From 091b8f1934a5ad71b2a15e8570b6934f7119e44d Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Wed, 21 Oct 2026 09:41:53 -0700 Subject: [PATCH 001/259] Report which packages and modules would run in a Node island Adds the report-only Node island policy, configuration and detector of the scope-B plan (milestone NI-2). Coverage now lists the npm packages a build would run in a Node island and why, gap islands first, without changing code generation. - project-config.ts reads the `scriptc` key of the entry's package.json with a schema; an unknown value in `scriptc.packages` or `scriptc.nodeIslands` is SC8004 instead of being ignored. Package shims and the WebAssembly scanner read through it. - node-islands/: origin (user, npm, shim, builtin; package instances), rules R1.1-R2.5 and the four classes, a syntactic pre-scan for R1/R2 markers, classification of refusals and runtime fences (reason ids at the refusal sites that need them), the policy (auto, explicit, off; forced node and native packages; marked user modules) and the report with island closure. - coverage: a "Node islands" section, `--explain-island=`, a `nodeIslands` field in the diagnostics envelope, and `--fail-on` `node-islands`, `eager-node-islands` and `island-gaps`. - CLI: `--node-islands`, `--node-island`, `--native`, `--node` (validated, report-only) and `--strict-user-js` (SC8101-SC8105 for R2 constructs in user JavaScript). Co-Authored-By: Claude Opus 5.5 --- .gitignore | 1 + packages/cli/src/bootstrap.ts | 23 +- packages/compiler/src/cli/command.ts | 85 +- packages/compiler/src/cli/usage.ts | 34 +- packages/compiler/src/compile-types.ts | 4 + packages/compiler/src/coverage/report.ts | 278 +++++- .../compiler/src/coverage/verdict-cache.ts | 11 +- .../compiler/src/diagnostics/diagnostic.ts | 67 ++ packages/compiler/src/diagnostics/envelope.ts | 53 ++ packages/compiler/src/frontend/analysis.ts | 26 +- .../lowering/builtins/module-resolution.ts | 2 + .../src/frontend/lowering/call-signatures.ts | 2 + .../frontend/lowering/cjs-inline-require.ts | 2 + .../lowering/expressions/identifiers.ts | 12 +- .../frontend/lowering/lower-node-module.ts | 2 + .../src/frontend/lowering/lower-stdlib.ts | 2 + .../compiler/src/frontend/lowering/lowerer.ts | 17 +- .../compiler/src/frontend/package-shims.ts | 33 +- packages/compiler/src/frontend/pipeline.ts | 107 ++- packages/compiler/src/index.ts | 3 + .../compiler/src/node-islands/classify.ts | 131 +++ .../compiler/src/node-islands/detect.test.ts | 165 ++++ packages/compiler/src/node-islands/detect.ts | 849 ++++++++++++++++++ packages/compiler/src/node-islands/origin.ts | 68 ++ packages/compiler/src/node-islands/policy.ts | 167 ++++ .../compiler/src/node-islands/report.test.ts | 201 +++++ packages/compiler/src/node-islands/report.ts | 355 ++++++++ packages/compiler/src/node-islands/rules.ts | 109 +++ packages/compiler/src/node-islands/scan.ts | 155 ++++ packages/compiler/src/node-islands/summary.ts | 110 +++ packages/compiler/src/project-config.test.ts | 126 +++ packages/compiler/src/project-config.ts | 421 +++++++++ packages/compiler/src/wasm/discover.ts | 39 +- .../node-islands-config/main.ts.json | 6 + .../node-islands-user-js.cjs | 22 + tests/coverage-fixtures/node-islands/main.ts | 16 + .../node_modules/ni-ctor/index.d.ts | 4 + .../node_modules/ni-ctor/index.js | 15 + .../node_modules/ni-ctor/package.json | 5 + .../node-islands/node_modules/ni-dep/index.js | 4 + .../node_modules/ni-dep/package.json | 5 + .../node_modules/ni-eval/index.d.ts | 1 + .../node_modules/ni-eval/index.js | 5 + .../node_modules/ni-eval/package.json | 5 + .../node_modules/ni-gap/index.d.ts | 1 + .../node-islands/node_modules/ni-gap/index.js | 8 + .../node_modules/ni-gap/package.json | 5 + .../node_modules/ni-minified/index.d.ts | 1 + .../node_modules/ni-minified/index.js | 1 + .../node_modules/ni-minified/package.json | 5 + .../node_modules/ni-typed/index.d.ts | 1 + .../node_modules/ni-typed/index.js | 4 + .../node_modules/ni-typed/package.json | 5 + .../node-islands/package.json | 5 + tests/diagnostics/node-islands-config/main.ts | 3 + .../node-islands-config/package.json | 14 + .../coverage-node-islands-explain.txt | 13 + .../coverage-node-islands-user-js.txt | 34 + .../__snapshots__/coverage-node-islands.txt | 39 + .../node-islands-config/main.ts.txt | 35 + tests/harness/coverage.test.ts | 87 ++ 61 files changed, 3928 insertions(+), 81 deletions(-) create mode 100644 packages/compiler/src/node-islands/classify.ts create mode 100644 packages/compiler/src/node-islands/detect.test.ts create mode 100644 packages/compiler/src/node-islands/detect.ts create mode 100644 packages/compiler/src/node-islands/origin.ts create mode 100644 packages/compiler/src/node-islands/policy.ts create mode 100644 packages/compiler/src/node-islands/report.test.ts create mode 100644 packages/compiler/src/node-islands/report.ts create mode 100644 packages/compiler/src/node-islands/rules.ts create mode 100644 packages/compiler/src/node-islands/scan.ts create mode 100644 packages/compiler/src/node-islands/summary.ts create mode 100644 packages/compiler/src/project-config.test.ts create mode 100644 packages/compiler/src/project-config.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/node-islands-config/main.ts.json create mode 100644 tests/coverage-fixtures/node-islands-user-js.cjs create mode 100644 tests/coverage-fixtures/node-islands/main.ts create mode 100644 tests/coverage-fixtures/node-islands/node_modules/ni-ctor/index.d.ts create mode 100644 tests/coverage-fixtures/node-islands/node_modules/ni-ctor/index.js create mode 100644 tests/coverage-fixtures/node-islands/node_modules/ni-ctor/package.json create mode 100644 tests/coverage-fixtures/node-islands/node_modules/ni-dep/index.js create mode 100644 tests/coverage-fixtures/node-islands/node_modules/ni-dep/package.json create mode 100644 tests/coverage-fixtures/node-islands/node_modules/ni-eval/index.d.ts create mode 100644 tests/coverage-fixtures/node-islands/node_modules/ni-eval/index.js create mode 100644 tests/coverage-fixtures/node-islands/node_modules/ni-eval/package.json create mode 100644 tests/coverage-fixtures/node-islands/node_modules/ni-gap/index.d.ts create mode 100644 tests/coverage-fixtures/node-islands/node_modules/ni-gap/index.js create mode 100644 tests/coverage-fixtures/node-islands/node_modules/ni-gap/package.json create mode 100644 tests/coverage-fixtures/node-islands/node_modules/ni-minified/index.d.ts create mode 100644 tests/coverage-fixtures/node-islands/node_modules/ni-minified/index.js create mode 100644 tests/coverage-fixtures/node-islands/node_modules/ni-minified/package.json create mode 100644 tests/coverage-fixtures/node-islands/node_modules/ni-typed/index.d.ts create mode 100644 tests/coverage-fixtures/node-islands/node_modules/ni-typed/index.js create mode 100644 tests/coverage-fixtures/node-islands/node_modules/ni-typed/package.json create mode 100644 tests/coverage-fixtures/node-islands/package.json create mode 100644 tests/diagnostics/node-islands-config/main.ts create mode 100644 tests/diagnostics/node-islands-config/package.json create mode 100644 tests/harness/__snapshots__/coverage-node-islands-explain.txt create mode 100644 tests/harness/__snapshots__/coverage-node-islands-user-js.txt create mode 100644 tests/harness/__snapshots__/coverage-node-islands.txt create mode 100644 tests/harness/__snapshots__/node-islands-config/main.ts.txt diff --git a/.gitignore b/.gitignore index fda9414aa..fa352c85e 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ node_modules/ !tests/corpus/*/node_modules/ !tests/fixtures/npm-static/node_modules/ !tests/coverage-fixtures/wasm/node_modules/ +!tests/coverage-fixtures/node-islands*/node_modules/ !tests/fixtures/npm-static/nested/inner/node_modules/ !tests/fixtures/npm-static/node_modules/*/node_modules/ !tests/fixtures/npm/store/*/node_modules/ diff --git a/packages/cli/src/bootstrap.ts b/packages/cli/src/bootstrap.ts index 1a319f98d..3fb61232f 100644 --- a/packages/cli/src/bootstrap.ts +++ b/packages/cli/src/bootstrap.ts @@ -70,7 +70,9 @@ async function tryFastPath(): Promise { values["profile-generate"] !== undefined || values["profile-use"] !== undefined || values.sparse || - (values["external-types"] ?? []).length > 0 + (values["external-types"] ?? []).length > 0 || + // The full CLI validates the Node island policy flags. + hasNodeIslandFlags(values) ) return null; const backend = values.backend; @@ -176,6 +178,21 @@ async function tryFastPath(): Promise { }); } +function hasNodeIslandFlags( + values: ReturnType< + typeof parseArgs<{ options: typeof CLI_OPTIONS; allowPositionals: true; allowNegative: true }> + >["values"], +): boolean { + return ( + values["node-islands"] !== undefined || + (values["node-island"] ?? []).length > 0 || + (values.native ?? []).length > 0 || + values.node !== undefined || + values["explain-island"] !== undefined || + values["strict-user-js"] + ); +} + /** An unchanged program's coverage verdict replays from the verdict cache * without loading the compiler graph. Anything else (a miss, a comment-only * edit, options the replay does not cover) defers to the full CLI. */ @@ -205,7 +222,9 @@ async function coverageFastPath( values["provenance-sources"] || values["emit-ir"] || (values["npm-static"] ?? []).length > 0 || - (values["external-types"] ?? []).length > 0 + (values["external-types"] ?? []).length > 0 || + // The replay covers the default Node island policy only. + hasNodeIslandFlags(values) ) return null; let startup: typeof import("@scriptc/compiler/startup-cache"); diff --git a/packages/compiler/src/cli/command.ts b/packages/compiler/src/cli/command.ts index 03160c6fa..128dacb26 100644 --- a/packages/compiler/src/cli/command.ts +++ b/packages/compiler/src/cli/command.ts @@ -4,12 +4,19 @@ import { parseArgs } from "node:util"; import { isExactExternalTypeSpecifier } from "../frontend/program.js"; import { renderDiagnostics } from "../diagnostics/render.js"; import { + COVERAGE_FAIL_ON, coverageEnvelope, coveragePasses, renderCoverage, renderExplainDynamic, + renderExplainIsland, type CoverageFailOn, } from "../coverage/report.js"; +import { + NODE_ISLANDS_MODES, + type NodeIslandOptions, + type NodeIslandsMode, +} from "../node-islands/policy.js"; import { TIER_MODES, type TierMode } from "../frontend/tier-analysis.js"; import { buildEnvelope } from "../diagnostics/envelope.js"; import { renderWarnings } from "../diagnostics/render.js"; @@ -105,6 +112,7 @@ async function main(args: string[], host: CliHost): Promise { values["emit-ir"] || values.tier !== undefined || values["explain-dynamic"] !== undefined || + hasNodeIslandFlags(values) || !values["keep-llvm"] ) { fail( @@ -162,6 +170,7 @@ async function main(args: string[], host: CliHost): Promise { values["emit-ir"] || values.tier !== undefined || values["explain-dynamic"] !== undefined || + hasNodeIslandFlags(values) || !values["keep-llvm"]; if (values.out === undefined || inputs.length === 0 || others) { fail( @@ -214,7 +223,8 @@ async function main(args: string[], host: CliHost): Promise { (values["npm-static"] ?? []).length > 0 || externalTypeArgs.length > 0 || values.tier !== undefined || - values["explain-dynamic"] !== undefined + values["explain-dynamic"] !== undefined || + hasNodeIslandFlags(values) ) { fail( "scriptc build --lib takes no --backend/--emit/--print/--optimization/--strip/--windows-subsystem/--detached-exit/--profile-generate/--profile-use/--npm-static/--ffi/--external-types/--tier/--explain-dynamic: the profile pins the emission and optimization, npm imports are judged automatically, outbound FFI belongs to executable builds, external type mappings belong to coverage, and library artifacts are static-tier only", @@ -284,8 +294,10 @@ async function main(args: string[], host: CliHost): Promise { fail(`--print=diagnostics is a build/coverage option\n\n${USAGE}`); } const failOnRaw = values["fail-on"]; - if (failOnRaw !== undefined && failOnRaw !== "blockers" && failOnRaw !== "divergences") { - fail(`unknown --fail-on value "${failOnRaw}" (supported: blockers, divergences)\n\n${USAGE}`); + if (failOnRaw !== undefined && !(COVERAGE_FAIL_ON as readonly string[]).includes(failOnRaw)) { + fail( + `unknown --fail-on value "${failOnRaw}" (supported: ${COVERAGE_FAIL_ON.join(", ")})\n\n${USAGE}`, + ); } if (failOnRaw !== undefined && command !== "coverage") { fail(`--fail-on is a coverage option (a build already fails on blockers)\n\n${USAGE}`); @@ -300,6 +312,48 @@ async function main(args: string[], host: CliHost): Promise { if (explainDynamic !== undefined && command !== "coverage") { fail(`--explain-dynamic is a coverage option\n\n${USAGE}`); } + const explainIsland = values["explain-island"]; + if (explainIsland !== undefined && command !== "coverage") { + fail(`--explain-island is a coverage option\n\n${USAGE}`); + } + if (explainIsland === "") fail(`--explain-island needs a package name\n\n${USAGE}`); + if (values["strict-user-js"] && command !== "coverage") { + fail(`--strict-user-js is a coverage option\n\n${USAGE}`); + } + // The Node island policy's command-line half. Report-only: build and run + // validate it, coverage reports the islands it would choose. + const islandMode = values["node-islands"]; + if (islandMode !== undefined && !(NODE_ISLANDS_MODES as readonly string[]).includes(islandMode)) { + fail( + `unknown --node-islands value "${islandMode}" (supported: ${NODE_ISLANDS_MODES.join(", ")})\n\n${USAGE}`, + ); + } + const listValues = (raw: string[] | undefined): string[] => + (raw ?? []) + .flatMap((v) => v.split(",")) + .map((v) => v.trim()) + .filter((v) => v !== ""); + const islandArgs = listValues(values["node-island"]); + const nativeArgs = listValues(values.native); + for (const name of nativeArgs) { + if (islandArgs.includes(name)) + fail(`--native=${name} and --node-island=${name} contradict each other\n\n${USAGE}`); + } + if (values.node === "") fail(`--node needs the path of a node executable\n\n${USAGE}`); + const nodeIslands: NodeIslandOptions | undefined = + islandMode === undefined && + islandArgs.length === 0 && + nativeArgs.length === 0 && + values.node === undefined && + !values["strict-user-js"] + ? undefined + : { + ...(islandMode !== undefined ? { mode: islandMode as NodeIslandsMode } : {}), + ...(islandArgs.length > 0 ? { islands: islandArgs } : {}), + ...(nativeArgs.length > 0 ? { native: nativeArgs } : {}), + ...(values.node !== undefined ? { node: resolve(values.node) } : {}), + ...(values["strict-user-js"] ? { strictUserJs: true } : {}), + }; if (printNativeLinkInfo && command !== "build") { fail(`--print=native-link-info is a build option\n\n${USAGE}`); } @@ -429,6 +483,7 @@ async function main(args: string[], host: CliHost): Promise { ...(tier !== undefined ? { tier } : {}), ...(explainDynamic !== undefined ? { explainDynamic: true } : {}), ...(wasmFiles.length > 0 ? { wasm: wasmFiles } : {}), + ...(nodeIslands !== undefined ? { nodeIslands } : {}), }); if (printDiagnostics) { // Keep stdout pure JSON for tooling. @@ -443,6 +498,17 @@ async function main(args: string[], host: CliHost): Promise { process.stdout.write( renderCoverage(coverage, { color, sourceTexts, root: process.cwd() }) + "\n", ); + if (explainIsland !== undefined) { + process.stdout.write( + "\n" + + renderExplainIsland(coverage.nodeIslands, explainIsland, { + color, + sourceTexts, + root: process.cwd(), + }) + + "\n", + ); + } if (explainDynamic !== undefined && coverage.tiers !== undefined) { process.stdout.write( "\n" + @@ -564,6 +630,19 @@ async function main(args: string[], host: CliHost): Promise { return 0; } +/** Whether any Node island flag is present (they belong to build, run and + * coverage). */ +function hasNodeIslandFlags(values: ReturnType["values"]): boolean { + return ( + values["node-islands"] !== undefined || + (values["node-island"] ?? []).length > 0 || + (values.native ?? []).length > 0 || + values.node !== undefined || + values["explain-island"] !== undefined || + values["strict-user-js"] + ); +} + /** Both installed and seed commands use this argument and diagnostic contract. */ export async function runCli(args: string[], host: CliHost): Promise { try { diff --git a/packages/compiler/src/cli/usage.ts b/packages/compiler/src/cli/usage.ts index aa7408d2a..bd40aa57c 100644 --- a/packages/compiler/src/cli/usage.ts +++ b/packages/compiler/src/cli/usage.ts @@ -31,10 +31,12 @@ Options: (native-link-info implies --emit=obj and never links; diagnostics prints the versioned JSON diagnostics envelope for build and coverage) - --fail-on + --fail-on coverage only: exit 1 when the entry path has blockers (a build would fail), or also when it has Node - divergences + divergences, any Node island (eager-node-islands is the + same until deferred evaluation lands), or a gap island + (a package scriptc should compile but cannot yet) --backend code generator (llvm) --optimization native optimization posture (default: release/-O2). dev @@ -100,6 +102,28 @@ Options: values and the bindings, fields, functions, classes and modules the dynamic tier would take over, with the refusal behind each; a name shows only that unit's chain + --node-islands + Node island policy (default: auto): npm packages outside + the native subset run in Node automatically; explicit + allows only marked islands; off allows none. REPORT-ONLY + in this version: coverage reports the islands a build + would choose; builds compile as before + --node-island + mark an npm package or one of your modules (a path or + glob) to run in a Node island (repeatable, comma lists; + report-only) + --native require an npm package to compile natively; outside the + native subset it is SC8003 (repeatable; report-only) + --node the node executable Node islands use (report-only) + --explain-island + coverage only: why a package would run in a Node island, + with the first reason per module, the native import + sites and the packages inside its closure + --strict-user-js + coverage only: report constructor functions, prototype + and shape mutation, sloppy-mode semantics and builtin + patching in your own .js/.cjs/.mjs modules as + SC8101–SC8105 blockers --wasm coverage only: report a WebAssembly module the program loads whose path its sources do not spell (repeatable; @@ -132,6 +156,12 @@ export const CLI_OPTIONS = { tier: { type: "string" }, "explain-dynamic": { type: "string" }, wasm: { type: "string", multiple: true }, + "node-islands": { type: "string" }, + "node-island": { type: "string", multiple: true }, + native: { type: "string", multiple: true }, + node: { type: "string" }, + "explain-island": { type: "string" }, + "strict-user-js": { type: "boolean", default: false }, lib: { type: "boolean", default: false }, profile: { type: "string" }, help: { type: "boolean", short: "h", default: false }, diff --git a/packages/compiler/src/compile-types.ts b/packages/compiler/src/compile-types.ts index 9ecd75974..39fea3acf 100644 --- a/packages/compiler/src/compile-types.ts +++ b/packages/compiler/src/compile-types.ts @@ -4,6 +4,7 @@ import type { NativeOptimization } from "./backend/optimization.js"; import type { ScrDiagnostic } from "./diagnostics/diagnostic.js"; import type { CoverageInput } from "./coverage/report.js"; import type { TierMode } from "./frontend/tier-analysis.js"; +import type { NodeIslandOptions } from "./node-islands/policy.js"; export type CompileOutputKind = "ir" | "llvm" | "asm" | "obj" | "exe"; @@ -183,6 +184,9 @@ export interface AnalyzeOptions { /** `--wasm `: WebAssembly module files the program loads that its * sources do not name (absolute paths); reported with the discovered ones. */ wasm?: readonly string[]; + /** The Node island policy's command-line half (report-only: coverage + * reports which packages and modules would run in a Node island). */ + nodeIslands?: NodeIslandOptions; } export interface AnalyzeResult { diff --git a/packages/compiler/src/coverage/report.ts b/packages/compiler/src/coverage/report.ts index 89733e255..8fc12a040 100644 --- a/packages/compiler/src/coverage/report.ts +++ b/packages/compiler/src/coverage/report.ts @@ -17,6 +17,7 @@ import { type DiagnosticsEnvelope, type LocatedDiagnostic, type SourcePosition, + type NodeIslandsEnvelope, type TierUnitPosition, type TiersEnvelope, } from "../diagnostics/envelope.js"; @@ -25,6 +26,14 @@ import type { LowerStats } from "../frontend/lowering/lowerer.js"; import type { ProvenanceSources } from "../frontend/provenance-registry.js"; import type { DemotionUnit, TierReport } from "../frontend/tier-analysis.js"; import type { WasmModuleReport } from "../wasm/discover.js"; +import { + describe as describeReason, + hasNodeIslandDecisions, + type NodeIslandEntry, + type NodeIslandReport, +} from "../node-islands/summary.js"; +import { classDescription } from "../node-islands/rules.js"; +import type { SrcLoc } from "../ir/ir.js"; export interface CoverageInput { file: string; @@ -61,6 +70,10 @@ export interface CoverageInput { /** The WebAssembly modules the build can see (wasm/discover.ts): their * size, validity and the proposals they use. */ wasmModules?: WasmModuleReport[]; + /** Node islands, report-only: the packages and user modules that would + * run in a Node island, and why. Present when there is something to + * report. */ + nodeIslands?: NodeIslandReport; /** True when tsc preflight failed — no coverage can be computed. */ preflightFailed: boolean; } @@ -144,6 +157,19 @@ export function renderCoverage(input: CoverageInput, opts: CoverageRenderOptions out.push(` ${c(RED, "not analyzable")}: ${config[0]!.message}`); return out.join("\n"); } + const projectConfig = input.diagnostics.filter((d) => d.code === "SC8004"); + if (projectConfig.length > 0) { + out.push( + ` ${c(RED, "not analyzable")}: the project's scriptc configuration has ${projectConfig.length} unknown setting${projectConfig.length === 1 ? "" : "s"}`, + ); + for (const d of projectConfig) { + const p = locator.position(d.loc.file, d.loc.start); + out.push(` ${c(DIM, "SC8004")} ${d.message}`); + out.push(` ${c(DIM, `at ${where({ file: d.loc.file, ...p })}`)}`); + if (d.hint !== undefined) out.push(` ${c(DIM, `hint: ${d.hint}`)}`); + } + return out.join("\n"); + } const tsc = input.diagnostics.filter((d) => d.code === "SC0001"); if (tsc.length > 0) { const world = tsc.filter((d) => d.typeWorld === true).length; @@ -221,6 +247,22 @@ export function renderCoverage(input: CoverageInput, opts: CoverageRenderOptions out.push(""); } + // Node islands (report-only): what would run in Node, gap islands + // first (DESIGN.md §1.3: a gap island is compiler work an island hides). + if (input.nodeIslands !== undefined && hasNodeIslandDecisions(input.nodeIslands)) { + renderNodeIslands( + input.nodeIslands, + out, + c, + (loc) => { + const p = locator.position(loc.file, loc.start); + return where({ file: loc.file, ...p }); + }, + opts.root, + ); + out.push(""); + } + // The WebAssembly modules the build can see (wasm/discover.ts). A build // translates the valid ones to native code (wasm/translate.ts) when the // program uses the WebAssembly API; the others fail to load at run time. @@ -450,7 +492,20 @@ function displayPath(file: string, root: string | undefined): string { /** What `coverage --fail-on` checks: reached blockers (they fail a build) * and, optionally, divergences. Unreached blockers never fail. */ -export type CoverageFailOn = "blockers" | "divergences"; +export type CoverageFailOn = + | "blockers" + | "divergences" + | "node-islands" + | "eager-node-islands" + | "island-gaps"; + +export const COVERAGE_FAIL_ON: readonly CoverageFailOn[] = [ + "blockers", + "divergences", + "node-islands", + "eager-node-islands", + "island-gaps", +]; /** Whether the analysis passes the selected gate. Preflight failures * always fail; `failOn` undefined means only preflight fails (the report's @@ -462,6 +517,16 @@ export function coveragePasses(input: CoverageInput, failOn?: CoverageFailOn): b // runtime fences build (the statement throws only if it executes). if (input.diagnostics.length > 0) return false; if (failOn === "divergences" && (input.divergences?.length ?? 0) > 0) return false; + // The Node island gates (report-only islands count: they are what a + // build would choose). Every island evaluates eagerly until deferred + // evaluation lands, so eager-node-islands equals node-islands for now. + // Would-be policy errors (SC8002, SC8003) fail every island gate. + const islands = input.nodeIslands; + if (islands === undefined) return true; + const anyIsland = failOn === "node-islands" || failOn === "eager-node-islands"; + if ((anyIsland || failOn === "island-gaps") && islands.violations.length > 0) return false; + if (anyIsland && (islands.islands.length > 0 || islands.userModules.length > 0)) return false; + if (failOn === "island-gaps" && islands.islands.some((i) => i.class === "gap")) return false; return true; } @@ -524,6 +589,9 @@ export function coverageEnvelope( }), ...(input.tiers !== undefined ? { tiers: tiersEnvelope(input.tiers, locator) } : {}), ...(input.wasmModules !== undefined ? { wasmModules: input.wasmModules } : {}), + ...(input.nodeIslands !== undefined + ? { nodeIslands: nodeIslandsEnvelope(input.nodeIslands, locator) } + : {}), groups, diagnostics: located, }; @@ -661,3 +729,211 @@ export function renderExplainDynamic( } return out.join("\n"); } + +/* ── Node islands (report-only) ───────────────────────────────────────── */ + +const ISLAND_REASONS_SHOWN = 1; + +function islandName(i: { package: string; version: string | null }): string { + return i.version === null ? i.package : `${i.package}@${i.version}`; +} + +function renderNodeIslands( + report: NodeIslandReport, + out: string[], + c: (code: string, s: string) => string, + at: (loc: SrcLoc) => string, + root: string | undefined, +): void { + const n = report.islands.length + report.userModules.length; + out.push( + ` ${c(BOLD, "Node islands")} ${c(DIM, `(would-be, report-only: the build is unchanged; --node-islands=${report.policy})`)}`, + ); + if (n === 0) out.push(` ${c(DIM, "none")}`); + const widest = Math.max(0, ...report.islands.map((i) => i.class.length)); + for (const island of report.islands) { + const tone = island.class === "gap" ? RED : YELLOW; + const decided = + island.decision === "auto" + ? "" + : c( + DIM, + ` (marked by ${island.decision === "cli" ? "--node-island" : "scriptc.packages"})`, + ); + out.push(` ${c(tone, island.class.padEnd(widest))} ${islandName(island)}${decided}`); + for (const r of island.reasons.slice(0, ISLAND_REASONS_SHOWN)) { + const where = r.loc === null ? "" : `${at(r.loc)}: `; + out.push(` ${c(DIM, capMessage(`${where}${describeReason(r)}`))}`); + } + const more = island.reasons.length - ISLAND_REASONS_SHOWN; + const details = [ + more > 0 + ? `+${more} more reason${more === 1 ? "" : "s"} in ${counted(island.modules, "module")}` + : "", + island.carries.length > 0 ? `carries ${island.carries.join(", ")}` : "", + ].filter((t) => t !== ""); + if (details.length > 0) out.push(` ${c(DIM, details.join("; "))}`); + } + for (const m of report.userModules) { + out.push( + ` ${c(YELLOW, "marked".padEnd(widest))} ${displayPath(m.file, root)} ${c(DIM, `(user module, marked by ${m.source === "cli" ? "--node-island" : "nodeIslands.modules"})`)}`, + ); + } + for (const v of report.violations) { + out.push(` ${c(RED, v.code)} ${capMessage(v.message)}`); + } + const shared = report.packages.filter((p) => p.status === "shared"); + if (shared.length > 0) { + out.push( + ` ${c(DIM, `reached from native code and from an island: ${shared.map((p) => p.package).join(", ")}`)}`, + ); + } + const native = report.packages.filter((p) => p.status === "native"); + if (native.length > 0) { + out.push( + ` ${c(DIM, `${counted(native.length, "package")} stay${native.length === 1 ? "s" : ""} native: ${native.map((p) => p.package).join(", ")}`)}`, + ); + } + if (report.unknownPackages.length > 0) { + out.push( + ` ${c(YELLOW, "note")} not imported by the program: ${report.unknownPackages.join(", ")}`, + ); + } + if (report.islands.length > 0) { + out.push( + ` ${c(DIM, "hint: scriptc coverage --explain-island= lists every reason")}`, + ); + } +} + +/** `scriptc coverage --explain-island=`: why a package would run + * in a Node island — every module's first reason, the native import sites + * (the boundary), the packages inside its closure, and what later + * milestones decide. */ +export function renderExplainIsland( + report: NodeIslandReport | undefined, + query: string, + opts: CoverageRenderOptions = {}, +): string { + const c = (code: string, s: string) => (opts.color ? code + s + RESET : s); + const locator = new SourceLocator(opts.sourceTexts); + const at = (loc: SrcLoc) => { + const p = locator.position(loc.file, loc.start); + return `${displayPath(loc.file, opts.root)}:${p.line}:${p.column}`; + }; + const out: string[] = []; + const matches = (report?.islands ?? []).filter( + (i) => i.package === query || islandName(i) === query, + ); + if (matches.length === 0) { + const pkg = (report?.packages ?? []).find((p) => p.package === query); + if (pkg === undefined) { + out.push(` '${query}' is not a Node island: no npm package of that name is in the program`); + } else if (pkg.status === "inside") { + out.push( + ` '${query}' is not a Node island of its own: only ${pkg.islands.join(", ")} import${pkg.islands.length === 1 ? "s" : ""} it, so it would run inside that island`, + ); + } else if (pkg.status === "shared") { + out.push( + ` '${query}' compiles natively and is also reached from the Node island${pkg.islands.length === 1 ? "" : "s"} ${pkg.islands.join(", ")}`, + ); + } else { + out.push(` '${query}' is not a Node island: it compiles natively`); + } + return out.join("\n"); + } + for (const island of matches) { + out.push( + ` ${c(BOLD, "Node island")} ${islandName(island)} ${c(DIM, "(would-be, report-only)")}`, + ); + if (island.path !== null) out.push(` path ${displayPath(island.path, opts.root)}`); + out.push(` class ${island.class}: ${classDescription(island.class)}`); + out.push( + ` decision ${island.decision === "auto" ? "automatic (npm code outside the native subset)" : island.decision === "cli" ? "marked with --node-island" : 'marked "node" in scriptc.packages'}`, + ); + out.push( + ` evaluation eager at its module position ${c(DIM, "(deferred evaluation is decided by a later milestone)")}`, + ); + if (island.reasons.length > 0) { + out.push(` reasons ${c(DIM, "(first per module; decisive class first)")}`); + const shown = new Set(); + for (const r of island.reasons) { + const key = r.loc === null ? "" : r.loc.file; + if (shown.has(key)) continue; + shown.add(key); + const where = r.loc === null ? "package" : at(r.loc); + out.push(` ${r.class.padEnd(12)} ${where}`); + out.push(` ${c(DIM, capMessage(describeReason(r)))}`); + } + const counts = new Map(); + for (const r of island.reasons) counts.set(r.class, (counts.get(r.class) ?? 0) + 1); + const summary = [...counts].map(([cls, k]) => `${k} ${cls}`).join(", "); + out.push(` all reasons ${island.reasons.length} (${summary})`); + } + if (island.importedFrom.length > 0) { + out.push(` boundary ${counted(island.importedFrom.length, "native import site")}:`); + for (const loc of island.importedFrom.slice(0, SITES_SHOWN)) out.push(` ${at(loc)}`); + if (island.importedFrom.length > SITES_SHOWN) + out.push(` ${c(DIM, `+${island.importedFrom.length - SITES_SHOWN} more`)}`); + out.push( + ` ${c(DIM, "copy and handle decisions per boundary site come with compiler-managed islands")}`, + ); + } else { + out.push( + ` boundary ${c(DIM, "no native import site (reached only from other islands)")}`, + ); + } + if (island.carries.length > 0) out.push(` carries ${island.carries.join(", ")}`); + } + return out.join("\n"); +} + +function nodeIslandsEnvelope( + report: NodeIslandReport, + locator: SourceLocator, +): NodeIslandsEnvelope { + const pos = (loc: SrcLoc): SourcePosition => ({ + file: loc.file, + ...locator.position(loc.file, loc.start), + }); + const entry = (i: NodeIslandEntry) => { + const first = i.reasons[0]; + return { + package: i.package, + version: i.version, + path: i.path, + class: i.class, + reason: i.reason, + diagnostic: i.diagnostic, + decision: i.decision, + evaluation: i.evaluation, + ...(first !== undefined && first.loc !== null ? { at: pos(first.loc) } : {}), + reasons: i.reasons.map((r) => ({ + class: r.class, + rule: r.rule, + reason: r.reason, + code: r.code, + message: r.message, + source: r.source, + ...(r.loc !== null ? { at: pos(r.loc) } : {}), + })), + carries: i.carries, + importedFrom: i.importedFrom.map(pos), + }; + }; + return { + mode: report.mode, + policy: report.policy, + islands: report.islands.map(entry), + userModules: report.userModules.map((m) => ({ file: m.file, decision: m.source })), + npmPackages: report.packages.map((p) => ({ + package: p.package, + version: p.version, + path: p.path, + status: p.status, + islands: p.islands, + })), + violations: report.violations.map((v) => ({ code: v.code, message: v.message, ...pos(v.loc) })), + unknownPackages: report.unknownPackages, + }; +} diff --git a/packages/compiler/src/coverage/verdict-cache.ts b/packages/compiler/src/coverage/verdict-cache.ts index 422bf5e4d..af8269189 100644 --- a/packages/compiler/src/coverage/verdict-cache.ts +++ b/packages/compiler/src/coverage/verdict-cache.ts @@ -15,13 +15,15 @@ import type { ScrDiagnostic } from "../diagnostics/diagnostic.js"; import type { LowerStats } from "../frontend/lowering/lowerer.js"; import type { NpmStaticStatus } from "./report.js"; import type { WasmModuleReport } from "../wasm/discover.js"; +import type { NodeIslandReport } from "../node-islands/summary.js"; +import { nodeIslandOptionsKey } from "../node-islands/policy.js"; import { FrontendInputTracker, frontendInputsStillMatch, type FrontendInputSnapshot, } from "../frontend/input-tracker.js"; -const SCHEMA = "scriptc.coverage-verdict.v2"; +const SCHEMA = "scriptc.coverage-verdict.v3"; /** Key-value storage for verdict entries (best effort: failures miss). */ export interface VerdictStore { @@ -40,6 +42,7 @@ export interface CachedCoverage { divergences?: ScrDiagnostic[]; npmStatic?: NpmStaticStatus[]; wasmModules?: WasmModuleReport[]; + nodeIslands?: NodeIslandReport; preflightFailed: boolean; } @@ -129,6 +132,10 @@ export function verdictKey( ...(opts.tier === "static-only" ? ["tier=static-only"] : []), // The module files' contents are probes; their names are options. ...(opts.wasm !== undefined && opts.wasm.length > 0 ? [`wasm=${opts.wasm.join("\n")}`] : []), + // The Node island policy's command-line half shapes the report. + ...(opts.nodeIslands !== undefined + ? [`node-islands=${nodeIslandOptionsKey(opts.nodeIslands)}`] + : []), ].join("\0"), ); } @@ -151,6 +158,7 @@ function cacheable(coverage: AnalyzeResult["coverage"]): CachedCoverage | null { if (coverage.divergences !== undefined) out.divergences = coverage.divergences; if (coverage.npmStatic !== undefined) out.npmStatic = coverage.npmStatic; if (coverage.wasmModules !== undefined) out.wasmModules = coverage.wasmModules; + if (coverage.nodeIslands !== undefined) out.nodeIslands = coverage.nodeIslands; return out; } @@ -168,6 +176,7 @@ function restore(cached: CachedCoverage, sources: CachedSource[]): AnalyzeResult if (cached.divergences !== undefined) coverage.divergences = cached.divergences; if (cached.npmStatic !== undefined) coverage.npmStatic = cached.npmStatic; if (cached.wasmModules !== undefined) coverage.wasmModules = cached.wasmModules; + if (cached.nodeIslands !== undefined) coverage.nodeIslands = cached.nodeIslands; return { coverage, sourceTexts }; } diff --git a/packages/compiler/src/diagnostics/diagnostic.ts b/packages/compiler/src/diagnostics/diagnostic.ts index e4d4006ca..b66efb351 100644 --- a/packages/compiler/src/diagnostics/diagnostic.ts +++ b/packages/compiler/src/diagnostics/diagnostic.ts @@ -62,6 +62,13 @@ * to a cast to an unrelated class (SC6004); SC6005 (Date strings * outside the native parser's grammar) is retired — the runtime * parses date strings with V8's grammar + * SC8xxx Node island policy: packages and modules outside the native + * subset that run (or, in report-only mode, would run) in a + * Node island — unknown project configuration (SC8004), a + * package required to be native (SC8003) or every island + * refused (SC8002) while outside the native subset, and the + * R2 object-model constructs in user JavaScript (SC8101–SC8105, + * behind --strict-user-js) * SC9xxx internal compiler errors (still source-anchored) */ import type { SrcLoc } from "../ir/ir.js"; @@ -89,6 +96,11 @@ export interface ScrDiagnostic { * the error may not reproduce under the project's tsc. Machine-readable * output reports these under the "environment" category. */ typeWorld?: boolean; + /** Why the construct is outside the native subset, as a Node island + * reason id (node-islands/rules.ts), at the refusal sites whose code + * alone does not say it (a computed require(), a native addon, `with`). + * Report-only: never part of the rendered message. */ + reason?: string; } /** SC3002–SC3004 — native-helper target, installation, and execution @@ -201,6 +213,60 @@ export function unrelatedClassCastDivergenceDiag( }; } +/* ── SC8xxx: Node island policy ───────────────────────────────────────── */ + +/** SC8004 — an unknown key or value in `scriptc.packages` or + * `scriptc.nodeIslands`. */ +export function projectConfigDiag( + path: string, + detail: string, + hint: string, + loc: SrcLoc, +): ScrDiagnostic { + return { + code: "SC8004", + message: `package.json '${path}' ${detail}`, + loc, + hint, + }; +} + +/** SC8002 — Node islands are off (or limited to marked islands) and an + * npm package is outside the native subset. */ +export function nodeIslandsOffDiag(pkg: string, why: string, loc: SrcLoc): ScrDiagnostic { + return { + code: "SC8002", + message: `npm package '${pkg}' is outside the native subset (${why}) and Node islands are off`, + loc, + hint: `allow Node islands (--node-islands=auto), mark it with --node-island=${pkg}, or replace the dependency`, + }; +} + +/** SC8003 — a package marked "native" is outside the native subset. */ +export function nativePackageDiag(pkg: string, why: string, loc: SrcLoc): ScrDiagnostic { + return { + code: "SC8003", + message: `npm package '${pkg}' is marked native but is outside the native subset: ${why}`, + loc, + hint: `remove the "native" marking to let it run in a Node island, or replace the construct the reason names`, + }; +} + +/** SC8101–SC8105 — an R2 object-model construct in the program's own + * JavaScript (R2.1 constructor functions … R2.5 builtin patching). */ +export function userJsObjectModelDiag( + code: "SC8101" | "SC8102" | "SC8103" | "SC8104" | "SC8105", + construct: string, + loc: SrcLoc, +): ScrDiagnostic { + return { + code, + message: `${construct} needs a mutable JavaScript object model, which native code does not have`, + loc, + hint: "rewrite it as a class or typed object, or mark this module as a Node island in scriptc.nodeIslands.modules", + }; +} + /* ── SC5xxx: native FFI ───────────────────────────────────────────────── */ /** SC5001 — the outbound native-FFI manifest is malformed or unreadable. */ @@ -766,6 +832,7 @@ export function nativeAddonDiag(specifier: string, loc: SrcLoc): ScrDiagnostic { loc, milestone: "later", hint: "expose the native operation as a plain C ABI function in an object or static archive, then bind a signature-only TypeScript declaration with --ffi; Node-API callbacks themselves require Node (https://scriptc.dev/ffi#replacing-a-node-api-addon)", + reason: "native-addon", }; } diff --git a/packages/compiler/src/diagnostics/envelope.ts b/packages/compiler/src/diagnostics/envelope.ts index c986fc5b1..42b424a7b 100644 --- a/packages/compiler/src/diagnostics/envelope.ts +++ b/packages/compiler/src/diagnostics/envelope.ts @@ -142,10 +142,60 @@ export interface DiagnosticsEnvelope { /** coverage only: the WebAssembly modules the build can see, with their * size, validity, proposals and the sources that found them. */ wasmModules?: WasmModuleReport[]; + /** coverage only, when there is something to report: the packages and + * user modules that would run in a Node island (report-only). */ + nodeIslands?: NodeIslandsEnvelope; groups: DiagnosticGroup[]; diagnostics: LocatedDiagnostic[]; } +/** One reason a package is outside the native subset. */ +export interface NodeIslandReasonEnvelope { + class: string; + /** R1.1–R2.5, or null for gap and packaging reasons. */ + rule: string | null; + reason: string; + code: string | null; + message: string; + source: string; + at?: SourcePosition; +} + +/** `scriptc coverage --print=diagnostics`: the Node island decisions. In + * this version they are would-be decisions (mode "would-be"): the build + * does not change. */ +export interface NodeIslandsEnvelope { + mode: "would-be"; + policy: "auto" | "explicit" | "off"; + /** Gap islands first, then by class and name. */ + islands: { + package: string; + version: string | null; + path: string | null; + class: string; + reason: string; + diagnostic: string | null; + decision: string; + evaluation: string; + at?: SourcePosition; + reasons: NodeIslandReasonEnvelope[]; + carries: string[]; + importedFrom: SourcePosition[]; + }[]; + userModules: { file: string; decision: string }[]; + /** Every npm package that is not an island: native, inside an island's + * closure, or shared between native code and an island. */ + npmPackages: { + package: string; + version: string | null; + path: string | null; + status: string; + islands: string[]; + }[]; + violations: (SourcePosition & { code: string; message: string })[]; + unknownPackages: string[]; +} + /** The divergence band: compiles, but the program can behave differently * from Node. Warnings, never build failures. */ export function isDivergenceCode(code: string): boolean { @@ -159,6 +209,7 @@ export function categoryOf(diag: ScrDiagnostic): DiagnosticCategory { if (code === "SC0003") return "invalid-source"; if (code === "SC0002" || code === "SC0004") return "environment"; if (/^SC[35]\d{3}$/.test(code)) return "environment"; + if (code === "SC8004" || code === "SC8005" || code === "SC8012") return "environment"; if (/^SC9\d{3}$/.test(code)) return "internal"; return "unsupported"; } @@ -179,6 +230,8 @@ export function hintOf(diag: ScrDiagnostic): string { return "restate the value's type inside the compilable set (number, string, boolean, arrays, Maps, Sets, RegExp, functions, classes, records, unions of those, and 'unknown')"; if (/^SC2\d{3}$/.test(code)) return "restate the type inside the compilable set (https://scriptc.dev/limitations describes the boundary)"; + if (/^SC8\d{3}$/.test(code)) + return "see the Node island policy: npm code outside the native subset runs in Node, user code must be marked (scriptc coverage --explain-island=)"; if (/^SC9\d{3}$/.test(code)) return "this is a compiler bug — please report it with the program that triggers it"; return "see https://scriptc.dev/limitations"; diff --git a/packages/compiler/src/frontend/analysis.ts b/packages/compiler/src/frontend/analysis.ts index 43d0aa2bb..5fbd96ba6 100644 --- a/packages/compiler/src/frontend/analysis.ts +++ b/packages/compiler/src/frontend/analysis.ts @@ -4,6 +4,10 @@ import type { AnalyzeOptions, AnalyzeResult } from "../compile-types.js"; import { loadFfiProfile, type FfiProfile } from "../ffi/ffi-manifest.js"; import { provenanceSources } from "./provenance-registry.js"; import type { FrontendFactory } from "./pipeline.js"; +import { readProjectConfig } from "../project-config.js"; +import { nodeIslandPolicy } from "../node-islands/policy.js"; +import { buildNodeIslandReport } from "../node-islands/report.js"; +import { hasNodeIslandFindings } from "../node-islands/summary.js"; /** Analysis without codegen: how much of the program compiles statically. * Unlike compile(), lowering diagnostics are data here, not failure. */ @@ -96,6 +100,23 @@ export function analyzeWithFrontend( ...(opts.wasm !== undefined && opts.wasm.length > 0 ? { wasmFiles: opts.wasm } : {}), }); const provenance = provenanceSources(); + // Node islands, report-only: which packages and modules would run in + // Node, from the detector's scan and the policy. Code generation does + // not depend on it. + const policy = nodeIslandPolicy(readProjectConfig(entryPath), opts.nodeIslands); + const islandReport = + fe.nodeIslandScan === undefined + ? null + : buildNodeIslandReport({ + entry: entryPath, + scan: fe.nodeIslandScan({ userJs: policy.strictUserJs }), + npm: fe.npmStatic, + diagnostics: [...lowered.diagnostics, ...(lowered.unreached?.diagnostics ?? [])], + fences: [...lowered.runtimeFences, ...(lowered.unreached?.runtimeFences ?? [])], + policy, + }); + const nodeIslands = + islandReport !== null && hasNodeIslandFindings(islandReport) ? islandReport : null; return { coverage: { file: entryPath, @@ -103,7 +124,9 @@ export function analyzeWithFrontend( // The import fences report as blockers alongside the statement-level // ones (use sites of the fenced bindings emit matching diagnostics, // which the report groups with these). - diagnostics: [...preflight, ...lowered.diagnostics], + // --strict-user-js: R2 constructs in user JavaScript are blockers + // (SC8101–SC8105), as scope B's builds will make them errors. + diagnostics: [...preflight, ...lowered.diagnostics, ...(nodeIslands?.userJs ?? [])], ...(lowered.runtimeFences.length > 0 ? { runtimeFences: lowered.runtimeFences } : {}), ...(lowered.divergences !== undefined ? { divergences: lowered.divergences } : {}), ...(lowered.unreached ? { unreached: lowered.unreached } : {}), @@ -115,6 +138,7 @@ export function analyzeWithFrontend( ...(lowered.provenanceElided ? { provenanceElided: lowered.provenanceElided } : {}), ...(lowered.tiers !== undefined ? { tiers: lowered.tiers } : {}), ...(lowered.wasmModules !== undefined ? { wasmModules: lowered.wasmModules } : {}), + ...(nodeIslands !== null ? { nodeIslands } : {}), preflightFailed: false, }, sourceTexts: fe.sourceTexts(), diff --git a/packages/compiler/src/frontend/lowering/builtins/module-resolution.ts b/packages/compiler/src/frontend/lowering/builtins/module-resolution.ts index 6b2e9e589..bbaf15353 100644 --- a/packages/compiler/src/frontend/lowering/builtins/module-resolution.ts +++ b/packages/compiler/src/frontend/lowering/builtins/module-resolution.ts @@ -146,6 +146,8 @@ export function lowerCreateRequireCall( "createRequire's require with this argument shape", call, 'the compiled module graph is fixed at build time — the one lowered form is require("")', + undefined, + "dynamic-require", ); } const spec = cr.spec; diff --git a/packages/compiler/src/frontend/lowering/call-signatures.ts b/packages/compiler/src/frontend/lowering/call-signatures.ts index e5ce784be..f57d9aedb 100644 --- a/packages/compiler/src/frontend/lowering/call-signatures.ts +++ b/packages/compiler/src/frontend/lowering/call-signatures.ts @@ -934,6 +934,8 @@ function appendArgumentsParameter( "SC1090", node, "parameterized 'arguments' outside an ES module (sloppy-mode parameter aliases)", + undefined, + "sloppy-arguments", ); } } diff --git a/packages/compiler/src/frontend/lowering/cjs-inline-require.ts b/packages/compiler/src/frontend/lowering/cjs-inline-require.ts index 2b28c6533..a4df8d910 100644 --- a/packages/compiler/src/frontend/lowering/cjs-inline-require.ts +++ b/packages/compiler/src/frontend/lowering/cjs-inline-require.ts @@ -211,6 +211,8 @@ export function lowerUncompiledRequireCall( "SC1090", call, 'require() with a computed specifier (the compiled module graph is fixed at build time: require("") lowers)', + undefined, + "dynamic-require", ); } if (canonicalBuiltinModule(spec) !== null) return null; diff --git a/packages/compiler/src/frontend/lowering/expressions/identifiers.ts b/packages/compiler/src/frontend/lowering/expressions/identifiers.ts index b5f99d682..bbf725fe9 100644 --- a/packages/compiler/src/frontend/lowering/expressions/identifiers.ts +++ b/packages/compiler/src/frontend/lowering/expressions/identifiers.ts @@ -786,7 +786,17 @@ export function lowerIdentifierExpr(lowerer: Lowerer, expr: ts.Identifier, loc: "finalization callbacks expose GC timing — genuinely dynamic; release resources explicitly instead", eval: "runtime code evaluation cannot be compiled ahead of time", }; - lowerer.noLowering(expr.text, expr, globalHints[expr.text], sym ?? undefined); + lowerer.noLowering( + expr.text, + expr, + globalHints[expr.text], + sym ?? undefined, + expr.text === "WeakRef" || expr.text === "FinalizationRegistry" + ? "weak-ref" + : expr.text === "eval" + ? "code-from-string" + : undefined, + ); } } // An ambient global nothing defines compiles to exactly what Node does diff --git a/packages/compiler/src/frontend/lowering/lower-node-module.ts b/packages/compiler/src/frontend/lowering/lower-node-module.ts index 37675777c..b383d2aff 100644 --- a/packages/compiler/src/frontend/lowering/lower-node-module.ts +++ b/packages/compiler/src/frontend/lowering/lower-node-module.ts @@ -586,6 +586,8 @@ export function fenceNodeModuleMutation( `${action} through require.cache`, target, "a compiled binary has a fixed module graph; cache lookup and Object.keys(require.cache) are read-only", + undefined, + "loader-hook", ); } if ( diff --git a/packages/compiler/src/frontend/lowering/lower-stdlib.ts b/packages/compiler/src/frontend/lowering/lower-stdlib.ts index e968af638..74b2a5709 100644 --- a/packages/compiler/src/frontend/lowering/lower-stdlib.ts +++ b/packages/compiler/src/frontend/lowering/lower-stdlib.ts @@ -2203,6 +2203,8 @@ export function lowerDynamicImportCall(lowerer: Lowerer, call: ts.CallExpression call, "dynamic import() of computed specifiers (the module graph resolves at " + "build time — the specifier must be a string literal)", + undefined, + "dynamic-import", ); } if (call.arguments.nodes.length !== 1) { diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 543149f83..4fd9afbc0 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -8067,8 +8067,11 @@ export class Lowerer { node: ts.Node, featureOverride?: string, hintOverride?: string, + reason?: string, ): never { - this.pushDiag(unsupportedDiag(code, locOf(node), featureOverride, hintOverride)); + const diag = unsupportedDiag(code, locOf(node), featureOverride, hintOverride); + if (reason !== undefined) diag.reason = reason; + this.pushDiag(diag); throw new PoisonError(); } @@ -8294,8 +8297,16 @@ export class Lowerer { * nothing lowers. Poisons the statement like every other rejection. * `sym`, when given, picks the wording: surface declared only by the * adopted @types/node is blamed at @types/node. */ - noLowering(surface: string, node: ts.Node, hint?: string, sym?: ts.Symbol | null): never { - this.pushDiag(noLoweringDiag(surface, locOf(node), hint, this.nodeTypesOnlySymbol(sym))); + noLowering( + surface: string, + node: ts.Node, + hint?: string, + sym?: ts.Symbol | null, + reason?: string, + ): never { + const diag = noLoweringDiag(surface, locOf(node), hint, this.nodeTypesOnlySymbol(sym)); + if (reason !== undefined) diag.reason = reason; + this.pushDiag(diag); throw new PoisonError(); } diff --git a/packages/compiler/src/frontend/package-shims.ts b/packages/compiler/src/frontend/package-shims.ts index 86a41d3a6..1c315a4cc 100644 --- a/packages/compiler/src/frontend/package-shims.ts +++ b/packages/compiler/src/frontend/package-shims.ts @@ -42,6 +42,7 @@ import { dirname, join, resolve } from "node:path"; import { packageShimRoot, tsgoPath } from "./dts-paths.js"; import { trackedDirectoryExists, trackedReadFile, trackedRealpath } from "./input-tracker.js"; +import { readProjectConfig } from "../project-config.js"; import { packageNameOfSpecifier } from "./workspace-registry.js"; import { BUILTIN_ALIAS_PACKAGES, @@ -150,36 +151,12 @@ export function packageShimEntries(): string[] { let unloadedPackages: ReadonlySet = new Set(); /** Reads the project's package-shim configuration: the `scriptc.packages` - * map of the entry's nearest package.json. Called once per program load. */ + * entries marked "unloaded" in the entry's nearest package.json + * (project-config.ts validates the rest). Called once per program load. */ export function configurePackageShims(entryPath: string): void { const packages = new Set(); - for (let dir = dirname(resolve(entryPath)); ;) { - const text = trackedReadFile(join(dir, "package.json")); - if (text !== null) { - let parsed: unknown = null; - try { - parsed = JSON.parse(text); - } catch { - parsed = null; - } - const config = - parsed !== null && typeof parsed === "object" - ? (parsed as Record)["scriptc"] - : undefined; - const map = - config !== null && typeof config === "object" - ? (config as Record)["packages"] - : undefined; - if (map !== null && typeof map === "object") { - for (const [name, kind] of Object.entries(map as Record)) { - if (kind === "unloaded") packages.add(name); - } - } - break; - } - const parent = dirname(dir); - if (parent === dir) break; - dir = parent; + for (const [name, setting] of readProjectConfig(entryPath).packages) { + if (setting.unloaded) packages.add(name); } unloadedPackages = packages; } diff --git a/packages/compiler/src/frontend/pipeline.ts b/packages/compiler/src/frontend/pipeline.ts index 193e8adc0..5ee2a8bea 100644 --- a/packages/compiler/src/frontend/pipeline.ts +++ b/packages/compiler/src/frontend/pipeline.ts @@ -46,6 +46,14 @@ import { CONTRACT_TYPES_MODULE } from "./contract-types.js"; import { THREADS_MODULE } from "./threads-import.js"; import { erasedTypeOnlyImport } from "./type-only-imports.js"; import { EXPERIMENTAL_MODULE } from "./experimental-import.js"; +import { readProjectConfig } from "../project-config.js"; +import { packageDirOf } from "../node-islands/origin.js"; +import { + scanFiles, + type NodeIslandScan, + type RefusalKind, + type RefusalRecord, +} from "../node-islands/scan.js"; /** Where a package-anchored preflight diagnostic sits, as * `:` — the SC2013 refusal that drops the package @@ -104,6 +112,10 @@ export interface Frontend { npmStatic: NpmStaticStatus[]; /** Each judged npm package's first import site, used to anchor refusals. */ npmImportSites: ReadonlyMap; + /** The Node island detector's input (report-only): the program's + * modules with their pre-scan markers, package import edges, and how + * each refused package was refused. Call before dispose. */ + nodeIslandScan?: (opts: { userJs: boolean }) => NodeIslandScan; /** Releases the frontend's resources (the spawned tsgo server). Call * exactly once, after the last lower(). */ dispose: () => void; @@ -384,6 +396,30 @@ function packagesNamedByDiag(message: string, optedIn: ReadonlySet): Set return hits; } +/** The modules of packages the drop-and-reload loop is about to remove, + * scanned on the program that still holds them. Report-only: a detector + * failure here never changes the build's outcome. */ +function scanDroppedPackages( + load: LoadResult, + packages: readonly string[], + into: { modules: NodeIslandScan["modules"]; edges: NodeIslandScan["edges"] }, +): void { + if (packages.length === 0) return; + try { + const wanted = new Set(packages); + const files = load.program.getImplementationSourceFiles().filter((sf) => { + if (sf.isDeclarationFile) return false; + const at = packageDirOf(sf.fileName); + return at !== null && wanted.has(at.name); + }); + const scanned = scanFiles(load.program, files, { userJs: false, dropped: true, edges: true }); + into.modules.push(...scanned.modules); + into.edges.push(...scanned.edges); + } catch { + /* report-only detection */ + } +} + export function runFrontend( entryPath: string, loadProgram: ProgramLoader, @@ -458,6 +494,16 @@ function loadFrontend( clearResolveCaches(); const statuses: NpmStaticStatus[] = []; const npmSites = new Map(); + // Node island detection (report-only): how each package was refused, and + // the modules of packages removed from the program. + const refusals: RefusalRecord[] = []; + const droppedScan: { modules: NodeIslandScan["modules"]; edges: NodeIslandScan["edges"] } = { + modules: [], + edges: [], + }; + const recordRefusal = (pkg: string, kind: RefusalKind, diag: ScrDiagnostic | null): void => { + refusals.push({ package: pkg, kind, diag }); + }; // Explicit library attempts bypass only the auto-selection heuristics. // The shared preflight/lowering refusal and dependency-closure checks remain. const judged = new Set(libraryNpmStatic); @@ -513,6 +559,7 @@ function loadFrontend( status: "refused", detail: `mapped as an external host module by --external-types (${specs.map((s) => JSON.stringify(s)).join(", ")})`, }); + recordRefusal(pkg, "external", null); return false; }); } @@ -546,19 +593,25 @@ function loadFrontend( const typecheckRefused = new Set(); while (effective.size > 0) { const reasons = new Map(npmStaticOffenders()); + const kinds = new Map(); + for (const pkg of reasons.keys()) kinds.set(pkg, { kind: "offender", diag: null }); // Bundler interop the rewrite could not finish refuses its package // only where the compiled program can load the file. if (npmStaticFileDegrades().size > 0) { const loadable = npmStaticLoadableFiles(load.program, load.moduleOrder); for (const [file, { pkg, reason }] of npmStaticFileDegrades()) { - if (!reasons.has(pkg) && (loadable === null || loadable.has(file))) + if (!reasons.has(pkg) && (loadable === null || loadable.has(file))) { reasons.set(pkg, reason); + kinds.set(pkg, { kind: "degrade", diag: null }); + } } } for (const d of preflight) { const pkg = npmStaticPackageOfPath(d.loc.file); - if (pkg !== null && !reasons.has(pkg)) + if (pkg !== null && !reasons.has(pkg)) { reasons.set(pkg, `${d.code} at ${packageDiagWhere(load, d.loc)}: ${d.message}`); + kinds.set(pkg, { kind: "preflight", diag: d }); + } } if (![...reasons.keys()].some((p) => effective.has(p))) { const named = new Map(); @@ -570,6 +623,7 @@ function loadFrontend( } for (const [pkg, count] of named) { typecheckRefused.add(pkg); + kinds.set(pkg, { kind: "typecheck", diag: null }); reasons.set( pkg, `its inferred export surface breaks ${count} import site${count === 1 ? "" : "s"} in program files (bundler-emitted surfaces type only as far as inference reaches)`, @@ -578,9 +632,12 @@ function loadFrontend( } const dropping = [...reasons.keys()].filter((p) => effective.has(p)); if (dropping.length === 0) break; + scanDroppedPackages(load, dropping, droppedScan); for (const p of dropping) { effective.delete(p); statuses.push({ package: p, status: "refused", detail: reasons.get(p)! }); + const kind = kinds.get(p); + recordRefusal(p, kind?.kind ?? "offender", kind?.diag ?? null); } load.dispose(); load = loadProgram(entryPath, { npmStatic: [...effective], externalTypes }); @@ -600,9 +657,12 @@ function loadFrontend( // graceful per-package degradation, never a failed gate the user cannot // act on (the note carries the why). if (effective.size > 0 && preflight.some((d) => d.code === "SC0001")) { + const lastResortDropped: string[] = []; const dropWithNote = (p: string): void => { effective.delete(p); typecheckRefused.add(p); + lastResortDropped.push(p); + recordRefusal(p, "typecheck", null); statuses.push({ package: p, status: "refused", @@ -624,11 +684,13 @@ function loadFrontend( probe.dispose(); if (probeDiags.some((d) => d.code === "SC0001")) dropWithNote(p); } + scanDroppedPackages(load, lastResortDropped.splice(0), droppedScan); load.dispose(); load = loadProgram(entryPath, { npmStatic: [...effective], externalTypes }); preflight = checkPreflight(load); if (preflight.some((d) => d.code === "SC0001") && effective.size > 0) { for (const p of [...effective]) dropWithNote(p); + scanDroppedPackages(load, lastResortDropped.splice(0), droppedScan); load.dispose(); load = loadProgram(entryPath, { npmStatic: [...effective], externalTypes }); preflight = checkPreflight(load); @@ -649,8 +711,12 @@ function loadFrontend( } const finalLoad = load; + // An unknown key or value in the project's scriptc configuration fails + // the build before anything else (SC8004). + const projectConfig = readProjectConfig(entryPath); + const configDiagnostics = projectConfig.diagnostics; return { - preflight, + preflight: configDiagnostics.length > 0 ? [...configDiagnostics, ...preflight] : preflight, entryText: () => finalLoad.entry.text, entryExports: () => entryFunctionExports(finalLoad.entry), // The contract scans the PROGRAM's source files, not the runtime @@ -677,14 +743,23 @@ function loadFrontend( // are in moduleOrder like any program module, so their bytes join the // library identity hashes (source_hash/build_id) — compiled code is // identity, whatever directory it came from. - sourceTexts: () => - new Map( + sourceTexts: () => { + const texts = new Map( [ finalLoad.entry, ...finalLoad.moduleOrder, ...finalLoad.program.getImplementationSourceFiles().filter((sf) => !sf.isDeclarationFile), ].map((sf) => [sf.fileName, sf.text]), - ), + ); + // SC8004 diagnostics point into the project's package.json. + if ( + configDiagnostics.length > 0 && + projectConfig.manifest !== null && + projectConfig.manifestText !== null + ) + texts.set(projectConfig.manifest, projectConfig.manifestText); + return texts; + }, lower: (opts) => lowerToIr(finalLoad.program, finalLoad.entry, finalLoad.moduleOrder, { ...opts, @@ -698,6 +773,26 @@ function loadFrontend( }), npmStatic: statuses, npmImportSites: npmSites, + nodeIslandScan: ({ userJs }) => { + const files = new Set([finalLoad.entry, ...finalLoad.moduleOrder]); + addDynamicImportGraph(finalLoad, files); + // Package edges matter only when the program has npm packages: one + // that loads, one that was refused, or one judged and dropped. + const npm = + statuses.length > 0 || + droppedScan.modules.length > 0 || + [...files].some((sf) => sf.fileName.includes("/node_modules/")); + const scanned = scanFiles(finalLoad.program, [...files], { + userJs, + dropped: false, + edges: npm, + }); + return { + modules: [...droppedScan.modules, ...scanned.modules], + edges: [...droppedScan.edges, ...scanned.edges], + refusals, + }; + }, dispose: finalLoad.dispose, }; } diff --git a/packages/compiler/src/index.ts b/packages/compiler/src/index.ts index e9b8514af..78a6a1e24 100644 --- a/packages/compiler/src/index.ts +++ b/packages/compiler/src/index.ts @@ -182,11 +182,14 @@ export { export { renderCoverage, renderExplainDynamic, + renderExplainIsland, coverageEnvelope, coveragePasses, type CoverageInput, type CoverageFailOn, } from "./coverage/report.js"; +export type { NodeIslandReport, NodeIslandEntry } from "./node-islands/summary.js"; +export type { NodeIslandOptions, NodeIslandsMode } from "./node-islands/policy.js"; export { TIER_MODES, type DemotedUnit, diff --git a/packages/compiler/src/node-islands/classify.ts b/packages/compiler/src/node-islands/classify.ts new file mode 100644 index 000000000..c41b9437c --- /dev/null +++ b/packages/compiler/src/node-islands/classify.ts @@ -0,0 +1,131 @@ +/* Diagnostic → Node island class (DESIGN.md §1.3). A refusal in a module + * of an npm package is a reason for that package to run in a Node island; + * its class says why: the runtime itself (R1), a mutable object model (R2), + * a shipping problem (packaging), or a construct inside the native subset + * that scriptc cannot compile yet (gap). The reason id on the diagnostic + * (ScrDiagnostic.reason) decides first; the code and message decide for + * refusal sites that do not carry one. */ +import type { ScrDiagnostic } from "../diagnostics/diagnostic.js"; +import type { NodeIslandMarker } from "./detect.js"; +import { classOfRule, ruleInfo, ruleOfReason } from "./rules.js"; +import type { RefusalRecord } from "./scan.js"; +import type { NodeIslandReason, NodeIslandReasonSource } from "./summary.js"; + +/** Message shapes of refusal sites that predate reason ids. */ +const MESSAGE_REASONS: { code: string; pattern: RegExp; reason: string }[] = [ + { code: "SC2010", pattern: /./, reason: "code-from-string" }, + { code: "SC1010", pattern: /'(?:node:)?vm'/, reason: "vm" }, + { code: "SC1090", pattern: /^dynamic import\(\) of computed/, reason: "dynamic-import" }, + { code: "SC1090", pattern: /require\(\) with a computed specifier/, reason: "dynamic-require" }, + { code: "SC1090", pattern: /'with' statement/, reason: "with" }, + { code: "SC1090", pattern: /sloppy-mode parameter aliases/, reason: "sloppy-arguments" }, + { code: "SC2020", pattern: /^'(?:eval|Function)'/, reason: "code-from-string" }, + { + code: "SC2020", + pattern: /createRequire's require with this argument shape/, + reason: "dynamic-require", + }, + { code: "SC2020", pattern: /native addon/, reason: "native-addon" }, + { + code: "SC2020", + pattern: /through require\.cache|require\.extensions|Module\._|module\.register/, + reason: "loader-hook", + }, + { + code: "SC2020", + pattern: /process\.binding|_linkedBinding|internalBinding|setFlagsFromString/, + reason: "engine-internal", + }, + { code: "SC2020", pattern: /\bWeakRef\b|\bFinalizationRegistry\b/, reason: "weak-ref" }, + { code: "SC1100", pattern: /\bWeakRef\b|\bFinalizationRegistry\b/, reason: "weak-ref" }, +]; + +function reasonIdOf(d: ScrDiagnostic): string | null { + if (d.reason !== undefined) return d.reason; + for (const entry of MESSAGE_REASONS) { + if (entry.code === d.code && entry.pattern.test(d.message)) return entry.reason; + } + return null; +} + +/** Codes that are not reasons of the package they appear in: a cascade + * marker repeats a root cause, an import of another refused package is + * that package's island boundary, and divergences compile. */ +export function isIslandReasonCode(code: string): boolean { + if (code === "SC2004" || code === "SC2013") return false; + if (/^SC6\d{3}$/.test(code)) return false; + return true; +} + +export function classifyDiagnostic( + d: ScrDiagnostic, + source: NodeIslandReasonSource, +): NodeIslandReason { + const id = reasonIdOf(d); + const rule = id === null ? null : ruleOfReason(id); + if (rule !== null && id !== null) { + return { + class: classOfRule(rule), + rule, + reason: id, + code: d.code, + message: d.message, + loc: d.loc, + source, + }; + } + return { + class: "gap", + rule: null, + reason: "gap", + code: d.code, + message: d.message, + loc: d.loc, + source, + }; +} + +export function classifyMarker(m: NodeIslandMarker): NodeIslandReason { + return { + class: classOfRule(m.rule), + rule: m.rule, + reason: m.reason, + code: null, + message: `${ruleInfo(m.rule).title}: ${m.construct}`, + loc: m.loc, + source: "pre-scan", + }; +} + +/** A refused package's status (pipeline.ts): the drop-and-reload record + * when there is one, else the declaration and shipped-JS eligibility bar, + * which is a packaging reason. */ +export function classifyRefusal( + detail: string, + record: RefusalRecord | null, +): NodeIslandReason | null { + if (record !== null && record.kind === "external") return null; + if (record !== null && record.kind === "preflight" && record.diag !== null) { + return classifyDiagnostic(record.diag, "package"); + } + if (record !== null && record.kind === "offender" && /require|createRequire/.test(detail)) { + return { + class: "runtime", + rule: "R1.2", + reason: "dynamic-require", + code: "SC2013", + message: detail, + loc: null, + source: "package", + }; + } + return { + class: "packaging", + rule: null, + reason: "packaging", + code: "SC2013", + message: detail, + loc: null, + source: "package", + }; +} diff --git a/packages/compiler/src/node-islands/detect.test.ts b/packages/compiler/src/node-islands/detect.test.ts new file mode 100644 index 000000000..2a21395da --- /dev/null +++ b/packages/compiler/src/node-islands/detect.test.ts @@ -0,0 +1,165 @@ +import { afterAll, describe, expect, test } from "vitest"; +import { closeSourceParser, parseSourceFile } from "../frontend/ts7/source-parser-node.js"; +import { scanModule } from "./detect.js"; + +afterAll(() => closeSourceParser()); + +let serial = 0; +/** The markers of one JavaScript module as `rule reason` strings. */ +function markers(source: string, ext = "cjs"): string[] { + const sf = parseSourceFile(`/virtual/m${serial++}.${ext}`, source, "js"); + return scanModule(sf).map((m) => `${m.rule} ${m.reason}`); +} + +describe("R1 runtime markers", () => { + test("R1.1 code from strings", () => { + expect(markers("eval(code);")).toEqual(["R1.1 code-from-string"]); + expect(markers("(0, eval)(code);")).toEqual(["R1.1 code-from-string"]); + expect(markers("const f = new Function('a', 'return a');")).toEqual(["R1.1 code-from-string"]); + expect(markers("const f = Function('a', body);")).toEqual(["R1.1 code-from-string"]); + expect(markers("const vm = require('node:vm');")).toEqual(["R1.1 vm"]); + expect(markers("import vm from 'vm';", "mjs")).toEqual(["R1.1 vm"]); + }); + + test("R1.1 exceptions: the global-object idiom and a capability probe in try", () => { + expect(markers("const g = Function('return this')();")).toEqual([]); + expect(markers("let ok; try { new Function(''); ok = true; } catch { ok = false; }")).toEqual( + [], + ); + }); + + test("R1.2 dynamic module loading", () => { + expect(markers("require(name);")).toEqual(["R1.2 dynamic-require"]); + expect(markers("import(`./${x}.js`);", "mjs")).toEqual(["R1.2 dynamic-import"]); + expect(markers("const r = createRequire(import.meta.url); r(spec);", "mjs")).toEqual([ + "R1.2 dynamic-require", + ]); + expect(markers("require('./a' + '.js'); require.resolve(name); import('./b.js');")).toEqual([]); + }); + + test("R1.3 native addons", () => { + expect(markers("require('./build/addon.node');")).toEqual(["R1.3 native-addon"]); + expect(markers("const b = require('bindings')('addon');")).toEqual(["R1.3 native-addon"]); + expect(markers("process.dlopen(module, path);")).toEqual(["R1.3 native-addon"]); + }); + + test("R1.4 loader and require hooks", () => { + expect(markers("require.extensions['.coffee'] = compile;")).toEqual(["R1.4 loader-hook"]); + expect(markers("delete require.cache[key];")).toEqual(["R1.4 loader-hook"]); + expect(markers("const Module = require('module'); Module._load = load;")).toEqual([ + "R1.4 loader-hook", + ]); + expect(markers("const m = require('node:module'); m.registerHooks({});")).toEqual([ + "R1.4 loader-hook", + ]); + expect(markers("require('require-in-the-middle');")).toEqual(["R1.4 loader-hook"]); + }); + + test("R1.5 engine internals", () => { + expect(markers("process.binding('fs');")).toEqual(["R1.5 engine-internal"]); + expect(markers("const v8 = require('v8'); v8.setFlagsFromString('--x');")).toEqual([ + "R1.5 engine-internal", + ]); + expect(markers("global.gc();")).toEqual(["R1.5 engine-internal"]); + }); + + test("R1.6 runtime-only globals", () => { + expect(markers("const r = new WeakRef(o);")).toEqual(["R1.6 weak-ref"]); + expect(markers("const f = new FinalizationRegistry(cb);")).toEqual(["R1.6 weak-ref"]); + expect(markers("if (typeof WeakRef !== 'undefined') {}")).toEqual([]); + expect(markers("const o = { WeakRef: 1 }; o.WeakRef;")).toEqual([]); + }); +}); + +describe("R2 object-model markers", () => { + test("R2.1 constructor functions", () => { + expect(markers("function F() {} const f = new F();")).toEqual(["R2.1 constructor-function"]); + expect(markers("function F() {} F.prototype.m = function () {};")).toEqual([ + "R2.1 constructor-function", + ]); + expect(markers("const util = require('util'); util.inherits(A, B);")).toEqual([ + "R2.1 constructor-function", + ]); + expect(markers("function Child() { Parent.call(this, 1); }")).toEqual([ + "R2.1 constructor-function", + ]); + expect(markers("class C {} const c = new C();")).toEqual([]); + expect( + markers("function wrap(fn) { return function () { return fn.apply(this, arguments); }; }"), + ).toEqual([]); + }); + + test("R2.2 prototype mutation", () => { + expect(markers("Object.setPrototypeOf(a, b);")).toEqual(["R2.2 prototype-write"]); + expect(markers("o.__proto__ = p;")).toEqual(["R2.2 prototype-write"]); + expect(markers("const o = { __proto__: base };")).toEqual(["R2.2 prototype-write"]); + // The transpiled-Error idiom and null-prototype dictionaries stay. + expect( + markers( + "class E extends Error { constructor() { super(); Object.setPrototypeOf(this, E.prototype); } }", + ), + ).toEqual([]); + expect(markers("const d = { __proto__: null };")).toEqual([]); + }); + + test("R2.3 shape mutation outside the checker's view", () => { + expect(markers("Object.defineProperty(o, 'k', { get() { return 1; } });")).toEqual([ + "R2.3 define-property", + ]); + expect(markers("class C {} C.prototype.extra = 1;")).toEqual(["R2.3 define-property"]); + // Module objects and interop helpers build module records. + expect(markers("Object.defineProperty(exports, '__esModule', { value: true });")).toEqual([]); + expect( + markers( + "var __createBinding = function (o, m, k) { Object.defineProperty(o, k, { enumerable: true, get: function () { return m[k]; } }); };", + ), + ).toEqual([]); + }); + + test("R2.4 sloppy-mode semantics", () => { + expect(markers("with (o) { x; }")).toEqual(["R2.4 with"]); + expect(markers("function f(a) { arguments[0] = 1; return a; }")).toEqual([ + "R2.4 sloppy-arguments", + ]); + expect(markers("function f(a) { a = 2; return arguments[0]; }")).toEqual([ + "R2.4 sloppy-arguments", + ]); + expect(markers("function f() { return arguments.callee; }")).toEqual(["R2.4 sloppy-arguments"]); + expect(markers("var n = 010;")).toEqual(["R2.4 sloppy-mode"]); + expect(markers("var x = 1; delete x;")).toEqual(["R2.4 sloppy-mode"]); + // Strict code: a prologue, an ES module, a class body. + expect(markers("'use strict'; function f(a) { a = 2; return arguments[0]; }")).toEqual([]); + expect(markers("export function f(a) { a = 2; return arguments[0]; }", "mjs")).toEqual([]); + expect(markers("class C { m(a) { a = 2; return arguments[0]; } }")).toEqual([]); + }); + + test("R2.5 builtin and global patching", () => { + expect(markers("Array.prototype.last = function () {};")).toEqual(["R2.5 builtin-write"]); + expect(markers("Promise = Bluebird;")).toEqual(["R2.5 builtin-write"]); + expect(markers("globalThis.fetch = f;")).toEqual(["R2.5 builtin-write"]); + expect(markers("const fs = require('fs'); fs.close = patched;")).toEqual([ + "R2.5 builtin-write", + ]); + expect(markers("const p = new Proxy(t, h);")).toEqual(["R2.5 proxy"]); + // Modeled process state and tuning knobs stay; so do redeclared names. + expect( + markers("process.exitCode = 1; process.env.X = 'y'; Error.stackTraceLimit = 50;"), + ).toEqual([]); + expect(markers("var Promise = require('bluebird'); Promise.config = {};")).toEqual([]); + }); +}); + +test("markers come back in source order with their locations", () => { + const source = "Object.setPrototypeOf(a, b);\neval(x);\n"; + const sf = parseSourceFile(`/virtual/order${serial++}.cjs`, source, "js"); + const found = scanModule(sf); + expect(found.map((m) => [m.rule, source.slice(m.loc.start, m.loc.end)])).toEqual([ + ["R2.2", "Object.setPrototypeOf(a, b)"], + ["R1.1", "eval(x)"], + ]); +}); + +test("computed writes keep the member they write through", () => { + expect(markers("process.env[key] = value;")).toEqual([]); + expect(markers("Array.prototype[name] = fn;")).toEqual(["R2.5 builtin-write"]); +}); diff --git a/packages/compiler/src/node-islands/detect.ts b/packages/compiler/src/node-islands/detect.ts new file mode 100644 index 000000000..f612d58e5 --- /dev/null +++ b/packages/compiler/src/node-islands/detect.ts @@ -0,0 +1,849 @@ +/* The pre-scan (DESIGN.md §1.4, phase 1): a syntactic walk over one + * JavaScript module that finds the R1 (runtime) and R2 (object-model) + * markers of rules.ts. It is a fast path and a source of good reasons; it + * never decides alone that a module is native, and the authoritative signal + * stays the lowering's refusals (classify.ts). + * + * Every check is local to the file: a name is a "function" when the file + * declares it as a function, a builtin global when the file does not + * declare it at all, and a builtin module object when the file binds it to + * require("") or imports it from one. Checker-dependent parts of + * R2.3 (writes the declared type does not cover, freeze followed by writes) + * and R2.4 (assignments to undeclared identifiers, `this` as the global + * object) are left to the lowering. */ +import type { SrcLoc } from "../ir/ir.js"; +import * as ts from "../frontend/ts7/adapter.js"; +import { SUPPORTED_BUILTIN_MODULES } from "../frontend/builtin-modules.js"; +import type { NodeIslandRule } from "./rules.js"; + +export interface NodeIslandMarker { + rule: NodeIslandRule; + /** The reason id (rules.ts). */ + reason: string; + /** The construct, as a short phrase for messages. */ + construct: string; + loc: SrcLoc; +} + +/** Markers past this count in one module add nothing to a report. */ +const MARKER_CAP = 64; + +const BUILTIN_GLOBALS = new Set([ + "Object", + "Array", + "String", + "Number", + "Boolean", + "Function", + "Symbol", + "BigInt", + "Promise", + "Error", + "TypeError", + "RangeError", + "SyntaxError", + "ReferenceError", + "EvalError", + "URIError", + "AggregateError", + "Map", + "Set", + "WeakMap", + "WeakSet", + "RegExp", + "Date", + "Math", + "JSON", + "Reflect", + "Intl", + "ArrayBuffer", + "SharedArrayBuffer", + "DataView", + "Uint8Array", + "Int8Array", + "Uint16Array", + "Int16Array", + "Uint32Array", + "Int32Array", + "Float32Array", + "Float64Array", + "BigInt64Array", + "BigUint64Array", + "Uint8ClampedArray", + "Buffer", + "process", + "console", + "globalThis", + "global", + "URL", + "URLSearchParams", + "TextEncoder", + "TextDecoder", + "AbortController", + "AbortSignal", + "EventTarget", + "Event", + "fetch", + "setTimeout", + "setInterval", + "setImmediate", + "clearTimeout", + "clearInterval", + "clearImmediate", + "queueMicrotask", + "structuredClone", +]); + +/** Writes to builtin members that the native subset models (process + * state, tuning knobs). */ +const ALLOWED_BUILTIN_WRITES = new Set([ + "process.exitCode", + "process.title", + "process.env", + "Error.stackTraceLimit", + "Buffer.poolSize", + "events.defaultMaxListeners", + "events.EventEmitter.defaultMaxListeners", + "EventEmitter.defaultMaxListeners", +]); + +const ADDON_LOADERS = new Set([ + "bindings", + "node-gyp-build", + "node-pre-gyp", + "@mapbox/node-pre-gyp", + "prebuild-install", + "node-gyp-build-optional-packages", +]); + +const LOADER_HOOK_PACKAGES = new Set(["import-in-the-middle", "require-in-the-middle"]); + +function builtinModuleName(spec: string): string | null { + const bare = spec.startsWith("node:") ? spec.slice(5) : spec; + if ((SUPPORTED_BUILTIN_MODULES as readonly string[]).includes(bare)) return bare; + if (bare === "vm" || bare === "v8" || bare === "module" || bare === "inspector") return bare; + return null; +} + +function literalText(node: ts.Node | undefined): string | null { + if (node === undefined) return null; + if (ts.isStringLiteral(node) || ts.isNoSubstitutionTemplateLiteral(node)) return node.text; + return null; +} + +/** A specifier that folds at build time: a literal, or a concatenation of + * literals. */ +function isFoldableSpecifier(node: ts.Node): boolean { + if (literalText(node) !== null) return true; + if (ts.isParenthesizedExpression(node)) return isFoldableSpecifier(node.expression); + if (ts.isBinaryExpression(node) && node.operatorToken.kind === ts.SyntaxKind.PlusToken) + return isFoldableSpecifier(node.left) && isFoldableSpecifier(node.right); + return false; +} + +function isAssignmentOperator(kind: ts.SyntaxKind): boolean { + return kind >= ts.SyntaxKind.FirstAssignment && kind <= ts.SyntaxKind.LastAssignment; +} + +function propertyName(node: ts.Node): string | null { + if (ts.isPropertyAccessExpression(node)) { + const name = node.name; + return ts.isIdentifier(name) ? name.text : null; + } + if (ts.isElementAccessExpression(node)) return literalText(node.argumentExpression); + return null; +} + +/** `a.b.c` as "a.b.c" (element accesses with literal keys included), or + * null when the chain has a computed key or does not start at a name. */ +function chainText(node: ts.Node): string | null { + if (ts.isIdentifier(node)) return node.text; + if (node.kind === ts.SyntaxKind.ThisKeyword) return "this"; + if (ts.isParenthesizedExpression(node)) return chainText(node.expression); + if (ts.isPropertyAccessExpression(node) || ts.isElementAccessExpression(node)) { + const base = chainText(node.expression); + const name = propertyName(node); + if (base === null || name === null) return null; + return `${base}.${name}`; + } + return null; +} + +/** Like chainText, with computed keys spelled `[…]`: `process.env[…]`. */ +function memberText(node: ts.Node): string | null { + const text = chainText(node); + if (text !== null) return text; + if (ts.isElementAccessExpression(node)) { + const base = memberText(node.expression); + return base === null ? null : `${base}[…]`; + } + if (ts.isPropertyAccessExpression(node)) { + const base = memberText(node.expression); + const name = propertyName(node); + return base === null || name === null ? null : `${base}.${name}`; + } + return null; +} + +/** The identifier a member chain starts at (`a` of `a.b[c].d`). */ +function chainRoot(node: ts.Node): ts.Identifier | null { + let cur = node; + for (;;) { + if (ts.isIdentifier(cur)) return cur; + if (ts.isPropertyAccessExpression(cur) || ts.isElementAccessExpression(cur)) { + cur = cur.expression; + continue; + } + if (ts.isParenthesizedExpression(cur)) { + cur = cur.expression; + continue; + } + return null; + } +} + +function hasUseStrict(statements: readonly ts.Node[]): boolean { + for (const stmt of statements) { + if (!ts.isExpressionStatement(stmt)) return false; + const text = literalText(stmt.expression); + if (text === null) return false; + if (text === "use strict") return true; + } + return false; +} + +/** ES module syntax at the top level (static import or export): the + * module is strict. The parser's module indicator is not used, since it + * also marks CommonJS files under forced module detection. */ +function hasEsmSyntax(sf: ts.SourceFile): boolean { + for (const stmt of sf.statements.nodes) { + if (ts.isImportDeclaration(stmt) || ts.isExportDeclaration(stmt)) return true; + if (ts.isExportAssignment(stmt)) return true; + const head = sf.text.slice(ts.tokenStartOfNode(stmt), ts.tokenStartOfNode(stmt) + 7); + if (head === "export ") return true; + } + return false; +} + +function isFunctionBoundary(node: ts.Node): boolean { + return ( + ts.isFunctionDeclaration(node) || + ts.isFunctionExpression(node) || + ts.isMethodDeclaration(node) || + ts.isConstructorDeclaration(node) || + ts.isGetAccessorDeclaration(node) || + ts.isSetAccessorDeclaration(node) + ); +} + +/** One module's pre-scan. */ +class ModuleScanner { + readonly markers: NodeIslandMarker[] = []; + /** Every name the file declares (any scope): a builtin global the file + * redeclares is not the builtin. */ + private readonly declared = new Set(); + /** Names declared as functions (declarations and function-valued + * variables). */ + private readonly functions = new Set(); + private readonly classes = new Set(); + /** Local name → the builtin module (or `module.member`) it is bound to. */ + private readonly builtinBindings = new Map(); + /** Local names bound to a createRequire(...) result. */ + private readonly createdRequires = new Set(); + private readonly strictness = new Map(); + private readonly moduleStrict: boolean; + + constructor(private readonly sf: ts.SourceFile) { + const name = sf.fileName; + this.moduleStrict = + name.endsWith(".mjs") || + name.endsWith(".mts") || + hasEsmSyntax(sf) || + hasUseStrict(sf.statements.nodes); + } + + scan(): NodeIslandMarker[] { + this.collectDeclarations(); + ts.walkPreorder(this.sf, (node) => { + if (this.markers.length >= MARKER_CAP) return "stop"; + this.visit(node); + return undefined; + }); + return this.markers; + } + + private add(rule: NodeIslandRule, reason: string, construct: string, node: ts.Node): void { + if (this.markers.length >= MARKER_CAP) return; + this.markers.push({ + rule, + reason, + construct, + loc: { file: this.sf.fileName, start: ts.tokenStartOfNode(node), end: node.end }, + }); + } + + private bindName(name: ts.Node | undefined, init: ts.Node | undefined): void { + if (name === undefined) return; + if (ts.isIdentifier(name)) { + this.declared.add(name.text); + if (init === undefined) return; + let value = init; + while (ts.isParenthesizedExpression(value)) value = value.expression; + if (ts.isFunctionExpression(value) || ts.isArrowFunction(value)) + this.functions.add(name.text); + else if (ts.isClassExpression(value)) this.classes.add(name.text); + const bound = this.builtinOf(value); + if (bound !== null) this.builtinBindings.set(name.text, bound); + if (ts.isCallExpression(value) && this.isCreateRequireCallee(value.expression)) + this.createdRequires.add(name.text); + return; + } + if (ts.isObjectBindingPattern(name)) { + const base = init === undefined ? null : this.builtinOf(init); + for (const element of name.elements.nodes) { + if (!ts.isBindingElement(element)) continue; + const local = element.name; + if (local !== undefined && ts.isIdentifier(local) && base !== null) { + const key = element.propertyName; + const member = key !== undefined && ts.isIdentifier(key) ? key.text : local.text; + this.builtinBindings.set(local.text, `${base}.${member}`); + } + this.bindName(local, undefined); + } + return; + } + if (ts.isArrayBindingPattern(name)) { + for (const element of name.elements.nodes) { + if (ts.isBindingElement(element)) this.bindName(element.name, undefined); + } + } + } + + /** `require("fs")`, `require("node:util").inherits` → "fs", "util.inherits". */ + private builtinOf(node: ts.Node): string | null { + let value = node; + while (ts.isParenthesizedExpression(value)) value = value.expression; + if (ts.isCallExpression(value) && this.isRequireCallee(value.expression)) { + const spec = literalText(value.arguments.nodes[0]); + return spec === null ? null : builtinModuleName(spec); + } + if (ts.isPropertyAccessExpression(value)) { + const base = this.builtinOf(value.expression); + const name = propertyName(value); + return base === null || name === null ? null : `${base}.${name}`; + } + if (ts.isIdentifier(value)) return this.builtinBindings.get(value.text) ?? null; + return null; + } + + private isRequireCallee(node: ts.Node): boolean { + return ts.isIdentifier(node) && node.text === "require"; + } + + private isCreateRequireCallee(node: ts.Node): boolean { + if (ts.isIdentifier(node)) { + return ( + node.text === "createRequire" || + this.builtinBindings.get(node.text) === "module.createRequire" + ); + } + return propertyName(node) === "createRequire"; + } + + private collectDeclarations(): void { + ts.walkPreorder(this.sf, (node) => { + if (ts.isFunctionDeclaration(node) && node.name !== undefined) { + this.declared.add(node.name.text); + this.functions.add(node.name.text); + } else if (ts.isClassDeclaration(node) && node.name !== undefined) { + this.declared.add(node.name.text); + this.classes.add(node.name.text); + } else if (ts.isVariableDeclaration(node)) { + this.bindName(node.name, node.initializer); + } else if (ts.isParameter(node)) { + this.bindName(node.name, undefined); + } else if (ts.isImportDeclaration(node)) { + const spec = literalText(node.moduleSpecifier); + const module = spec === null ? null : builtinModuleName(spec); + const clause = node.importClause; + if (clause !== undefined) { + if (clause.name !== undefined) { + this.declared.add(clause.name.text); + if (module !== null) this.builtinBindings.set(clause.name.text, module); + } + const bindings = clause.namedBindings; + if (bindings !== undefined && ts.isNamespaceImport(bindings)) { + this.declared.add(bindings.name.text); + if (module !== null) this.builtinBindings.set(bindings.name.text, module); + } else if (bindings !== undefined && ts.isNamedImports(bindings)) { + for (const element of bindings.elements.nodes) { + this.declared.add(element.name.text); + const imported = element.propertyName; + const member = + imported !== undefined && ts.isIdentifier(imported) + ? imported.text + : element.name.text; + if (module !== null) + this.builtinBindings.set(element.name.text, `${module}.${member}`); + } + } + } + } + return undefined; + }); + } + + /** Whether the code at `node` runs in strict mode. */ + private isStrict(node: ts.Node): boolean { + if (this.moduleStrict) return true; + let cur: ts.Node | undefined = node.parent; + const visited: ts.Node[] = []; + let strict = false; + while (cur !== undefined) { + const known = this.strictness.get(cur); + if (known !== undefined) { + strict = known; + break; + } + visited.push(cur); + if (ts.isClassDeclaration(cur) || ts.isClassExpression(cur)) { + strict = true; + break; + } + if (isFunctionBoundary(cur) || ts.isArrowFunction(cur)) { + const body = (cur as ts.FunctionLikeDeclaration).body; + if (body !== undefined && ts.isBlock(body) && hasUseStrict(body.statements.nodes)) { + strict = true; + break; + } + } + cur = cur.parent; + } + for (const n of visited) this.strictness.set(n, strict); + return strict; + } + + private isGlobal(name: string): boolean { + return BUILTIN_GLOBALS.has(name) && !this.declared.has(name); + } + + private visit(node: ts.Node): void { + if (ts.isCallExpression(node)) this.visitCall(node); + else if (ts.isNewExpression(node)) this.visitNew(node); + else if (ts.isBinaryExpression(node) && isAssignmentOperator(node.operatorToken.kind)) + this.visitWrite(node.left, node, "write"); + else if (ts.isDeleteExpression(node)) this.visitDelete(node); + else if (ts.isPrefixUnaryExpression(node) || ts.isPostfixUnaryExpression(node)) { + if ( + node.operator === ts.SyntaxKind.PlusPlusToken || + node.operator === ts.SyntaxKind.MinusMinusToken + ) + this.visitWrite(node.operand, node, "write"); + } else if (ts.isWithStatement(node)) { + this.add("R2.4", "with", "a 'with' statement", node); + } else if (ts.isImportDeclaration(node)) { + const spec = literalText(node.moduleSpecifier); + if (spec !== null) this.visitSpecifier(spec, node); + } else if (ts.isIdentifier(node)) { + this.visitIdentifier(node); + } else if (ts.isNumericLiteral(node)) { + const text = this.sf.text.slice(ts.tokenStartOfNode(node), node.end); + if (/^0[0-9]+$/.test(text) && !this.isStrict(node)) + this.add("R2.4", "sloppy-mode", "a legacy octal literal", node); + } else if (ts.isPropertyAccessExpression(node)) { + const text = chainText(node); + if ((text === "arguments.callee" || text === "arguments.caller") && !this.isStrict(node)) + this.add("R2.4", "sloppy-arguments", `'${text}'`, node); + } else if (ts.isObjectLiteralExpression(node)) { + for (const prop of node.properties.nodes) { + if (!ts.isPropertyAssignment(prop)) continue; + const name = prop.name; + const key = ts.isIdentifier(name) || ts.isStringLiteral(name) ? name.text : null; + if (key === "__proto__" && prop.initializer.kind !== ts.SyntaxKind.NullKeyword) + this.add("R2.2", "prototype-write", "an object literal with a '__proto__' value", prop); + } + } else if (isFunctionBoundary(node)) { + this.visitFunction(node as ts.FunctionLikeDeclaration); + } + } + + private visitSpecifier(spec: string, node: ts.Node): void { + const builtin = builtinModuleName(spec); + if (builtin === "vm") this.add("R1.1", "vm", "the 'vm' module", node); + else if (spec.endsWith(".node")) + this.add("R1.3", "native-addon", `the native addon '${spec}'`, node); + else if (ADDON_LOADERS.has(spec)) + this.add("R1.3", "native-addon", `the native addon loader '${spec}'`, node); + else if (LOADER_HOOK_PACKAGES.has(spec)) + this.add("R1.4", "loader-hook", `the loader hook package '${spec}'`, node); + } + + private visitCall(call: ts.CallExpression): void { + const callee = call.expression; + const args = call.arguments.nodes; + const first = args[0]; + // import(e) and require(e) + if (callee.kind === ts.SyntaxKind.ImportKeyword) { + if (first !== undefined && !isFoldableSpecifier(first)) + this.add("R1.2", "dynamic-import", "import() with a computed specifier", call); + else if (first !== undefined) this.visitSpecifier(literalText(first) ?? "", call); + return; + } + if ( + this.isRequireCallee(callee) || + (ts.isIdentifier(callee) && this.createdRequires.has(callee.text)) + ) { + if (first !== undefined && !isFoldableSpecifier(first)) + this.add("R1.2", "dynamic-require", "require() with a computed specifier", call); + else if (first !== undefined) this.visitSpecifier(literalText(first) ?? "", call); + return; + } + if (ts.isCallExpression(callee) && this.isCreateRequireCallee(callee.expression)) { + if (first !== undefined && !isFoldableSpecifier(first)) + this.add("R1.2", "dynamic-require", "createRequire(...)() with a computed specifier", call); + return; + } + // eval, Function + let target = callee; + while (ts.isParenthesizedExpression(target)) target = target.expression; + if (ts.isBinaryExpression(target) && target.operatorToken.kind === ts.SyntaxKind.CommaToken) + target = target.right; + const text = chainText(target); + if (text === null) return; + if ( + (text === "eval" && !this.declared.has("eval")) || + text === "globalThis.eval" || + text === "global.eval" || + text === "window.eval" + ) { + this.add("R1.1", "code-from-string", "eval()", call); + return; + } + if (text === "Function" && this.isGlobal("Function")) { + this.visitFunctionConstructor(call, args); + return; + } + const root = chainRoot(target); + const rootBinding = root === null ? undefined : this.builtinBindings.get(root.text); + const resolved = + rootBinding !== undefined && root !== null + ? rootBinding + text.slice(root.text.length) + : text; + // engine internals + if ( + (text === "process.binding" || text === "process._linkedBinding") && + this.isGlobal("process") + ) { + this.add("R1.5", "engine-internal", `'${text}()'`, call); + return; + } + if (text === "internalBinding" && !this.declared.has("internalBinding")) { + this.add("R1.5", "engine-internal", "'internalBinding()'", call); + return; + } + if (resolved === "v8.setFlagsFromString" || text.endsWith(".setFlagsFromString")) { + this.add("R1.5", "engine-internal", "'v8.setFlagsFromString()'", call); + return; + } + if ((text === "global.gc" || text === "globalThis.gc") && this.isGlobal(text.split(".")[0]!)) { + this.add("R1.5", "engine-internal", `'${text}()'`, call); + return; + } + if (text === "process.dlopen" && this.isGlobal("process")) { + this.add("R1.3", "native-addon", "'process.dlopen()'", call); + return; + } + // loader hooks + if (resolved === "module.register" || resolved === "module.registerHooks") { + this.add("R1.4", "loader-hook", `'${resolved}()'`, call); + return; + } + // prototype mutation + if ( + (text === "Object.setPrototypeOf" && this.isGlobal("Object")) || + (text === "Reflect.setPrototypeOf" && this.isGlobal("Reflect")) + ) { + // The transpiled-Error idiom `Object.setPrototypeOf(this, …)` stays. + if (first !== undefined && first.kind !== ts.SyntaxKind.ThisKeyword) + this.add("R2.2", "prototype-write", `'${text}()'`, call); + return; + } + // defineProperty outside the module object and interop helpers + if ( + ((text === "Object.defineProperty" || text === "Object.defineProperties") && + this.isGlobal("Object")) || + (text === "Reflect.defineProperty" && this.isGlobal("Reflect")) + ) { + if (first !== undefined && !this.isModuleObject(first) && !this.inInteropHelper(call)) + this.add("R2.3", "define-property", `'${text}()'`, call); + return; + } + if (text.endsWith(".__defineGetter__") || text.endsWith(".__defineSetter__")) { + this.add("R2.3", "define-property", `'${text.slice(text.lastIndexOf(".") + 1)}()'`, call); + return; + } + // constructor functions + if ( + args.length === 2 && + (resolved === "util.inherits" || + (text === "inherits" && !this.functions.has("inherits")) || + text.endsWith(".inherits")) + ) { + this.add("R2.1", "constructor-function", `'${text}()'`, call); + return; + } + if ( + ts.isPropertyAccessExpression(target) && + (propertyName(target) === "call" || propertyName(target) === "apply") && + first !== undefined && + first.kind === ts.SyntaxKind.ThisKeyword && + ts.isExpressionStatement(call.parent!) + ) { + const fn = target.expression; + const name = ts.isIdentifier(fn) ? fn.text : null; + if (name !== null && /^[A-Z]/.test(name) && !this.classes.has(name)) + this.add( + "R2.1", + "constructor-function", + `'${name}.${propertyName(target)}(this, …)'`, + call, + ); + } + } + + private visitFunctionConstructor(node: ts.Node, args: readonly ts.Node[]): void { + // The global-object idiom Function("return this")() folds to globalThis. + if (args.length === 1) { + const body = literalText(args[0]); + if (body !== null && body.trim() === "return this") return; + } + // A capability probe tested inside try (zod 4's allowsEval) keeps + // today's EvalError lowering. + for (let cur = node.parent; cur !== undefined; cur = cur.parent) { + if (isFunctionBoundary(cur) || ts.isArrowFunction(cur)) break; + if (ts.isBlock(cur) && cur.parent !== undefined && ts.isTryStatement(cur.parent)) { + if (cur.parent.tryBlock === cur) return; + } + } + this.add("R1.1", "code-from-string", "new Function()", node); + } + + private visitNew(node: ts.NewExpression): void { + const callee = node.expression; + if (!ts.isIdentifier(callee)) return; + const name = callee.text; + if (name === "Function" && this.isGlobal("Function")) { + this.visitFunctionConstructor(node, node.arguments?.nodes ?? []); + } else if (name === "Proxy" && !this.declared.has("Proxy")) { + this.add("R2.5", "proxy", "new Proxy()", node); + } else if (this.functions.has(name) && !this.classes.has(name)) { + this.add("R2.1", "constructor-function", `'new ${name}()' of a function`, node); + } + } + + private isModuleObject(node: ts.Node): boolean { + const text = chainText(node); + return text === "exports" || text === "module.exports" || text === "module"; + } + + /** Inside a module-interop helper (tsc's __createBinding/__exportStar, + * Babel's _interopRequireWildcard, esbuild's __export): their + * defineProperty calls build module objects the native subset models. */ + private inInteropHelper(node: ts.Node): boolean { + for (let cur = node.parent; cur !== undefined; cur = cur.parent) { + let name: string | null = null; + if (ts.isFunctionDeclaration(cur) && cur.name !== undefined) name = cur.name.text; + else if (ts.isVariableDeclaration(cur) && ts.isIdentifier(cur.name)) name = cur.name.text; + else if (ts.isBinaryExpression(cur) && isAssignmentOperator(cur.operatorToken.kind)) + name = chainText(cur.left); + if (name !== null && /(^|\.)_/.test(name)) return true; + } + return false; + } + + private visitWrite(target: ts.Node, node: ts.Node, what: "write" | "delete"): void { + let left = target; + while (ts.isParenthesizedExpression(left)) left = left.expression; + if (ts.isIdentifier(left)) { + if (this.isGlobal(left.text) && left.text !== "global" && left.text !== "globalThis") + this.add("R2.5", "builtin-write", `a ${what} of the global '${left.text}'`, node); + return; + } + if (!ts.isPropertyAccessExpression(left) && !ts.isElementAccessExpression(left)) return; + const text = chainText(left); + const root = chainRoot(left); + const base = left.expression; + const baseText = chainText(base); + // require.extensions / require.cache + if ( + text !== null && + (text.startsWith("require.extensions") || text.startsWith("require.cache")) + ) { + this.add( + "R1.4", + "loader-hook", + `a ${what} of '${text.startsWith("require.cache") ? "require.cache" : "require.extensions"}'`, + node, + ); + return; + } + if (baseText === "require.cache" || baseText === "require.extensions") { + this.add("R1.4", "loader-hook", `a ${what} of '${baseText}'`, node); + return; + } + // __proto__ writes + if (propertyName(left) === "__proto__") { + this.add("R2.2", "prototype-write", `a ${what} of '__proto__'`, node); + return; + } + if (root === null) return; + const binding = this.builtinBindings.get(root.text); + // Module internals: Module._load = …, Module.prototype.require = … + if (text !== null) { + const resolved = binding !== undefined ? binding + text.slice(root.text.length) : text; + if ( + /^(module|Module)\.(_load|_resolveFilename|_extensions|wrap|_compile|prototype\.require|prototype\._compile)$/.test( + resolved, + ) && + (binding !== undefined || !this.declared.has(root.text) || root.text === "Module") + ) { + this.add("R1.4", "loader-hook", `a ${what} of '${resolved}'`, node); + return; + } + // F.prototype… + const parts = text.split("."); + if (parts.length >= 2 && parts[1] === "prototype") { + const name = parts[0]!; + if (this.isGlobal(name)) { + this.add("R2.5", "builtin-write", `a ${what} of '${text}'`, node); + return; + } + if (binding === undefined && this.classes.has(name) && !this.functions.has(name)) { + this.add("R2.3", "define-property", `a ${what} of the class prototype '${text}'`, node); + return; + } + if (binding === undefined && name !== "this") { + this.add("R2.1", "constructor-function", `a ${what} of '${text}'`, node); + return; + } + } + } + // Builtin globals and builtin module objects. + const spelled = memberText(left) ?? `${root.text}[…]`; + if (binding !== undefined) { + const member = binding + spelled.slice(root.text.length); + if (!this.allowedWrite(member)) { + this.add( + "R2.5", + "builtin-write", + `a ${what} of the builtin module member '${member}'`, + node, + ); + } + return; + } + if (this.isGlobal(root.text)) { + const member = spelled; + if (!this.allowedWrite(member)) + this.add("R2.5", "builtin-write", `a ${what} of the builtin '${member}'`, node); + } + } + + private allowedWrite(member: string): boolean { + for (const allowed of ALLOWED_BUILTIN_WRITES) { + if ( + member === allowed || + member.startsWith(`${allowed}.`) || + member.startsWith(`${allowed}[`) + ) + return true; + } + return false; + } + + private visitDelete(node: ts.DeleteExpression): void { + let target = node.expression; + while (ts.isParenthesizedExpression(target)) target = target.expression; + if (ts.isIdentifier(target)) { + if (!this.isStrict(node)) + this.add("R2.4", "sloppy-mode", `'delete ${target.text}' of an identifier`, node); + return; + } + this.visitWrite(target, node, "delete"); + } + + private visitIdentifier(node: ts.Identifier): void { + const name = node.text; + if (name !== "WeakRef" && name !== "FinalizationRegistry") return; + if (this.declared.has(name)) return; + const parent = node.parent; + if (parent === undefined) return; + // Only value uses: not a property name, declaration name or typeof probe. + if (ts.isPropertyAccessExpression(parent) && parent.name === node) return; + if (ts.isTypeOfExpression(parent)) return; + if ((ts.isPropertyAssignment(parent) || ts.isMethodDeclaration(parent)) && parent.name === node) + return; + this.add("R1.6", "weak-ref", `'${name}'`, node); + } + + /** Observable `arguments` aliasing in a sloppy function: writes to + * arguments[i], or to a parameter while `arguments` is read. */ + private visitFunction(fn: ts.FunctionLikeDeclaration): void { + const body = fn.body; + if (body === undefined || !ts.isBlock(body)) return; + if (this.isStrict(body.statements.nodes[0] ?? body)) return; + if (hasUseStrict(body.statements.nodes)) return; + const params = new Set(); + for (const p of fn.parameters.nodes) { + if (ts.isIdentifier(p.name)) params.add(p.name.text); + } + const seen: ArgumentsUse = { reads: false, argumentsWrite: null, paramWrite: null }; + ts.walkPreorder(body, (node) => { + if ( + node !== body && + (isFunctionBoundary(node) || ts.isClassDeclaration(node) || ts.isClassExpression(node)) + ) + return "skip"; + if (ts.isIdentifier(node) && node.text === "arguments") seen.reads = true; + if (ts.isBinaryExpression(node) && isAssignmentOperator(node.operatorToken.kind)) { + const left = node.left; + if ( + ts.isElementAccessExpression(left) && + ts.isIdentifier(left.expression) && + left.expression.text === "arguments" + ) { + if (seen.argumentsWrite === null) seen.argumentsWrite = node; + } else if (ts.isIdentifier(left) && params.has(left.text)) { + if (seen.paramWrite === null) seen.paramWrite = node; + } + } + return undefined; + }); + if (seen.argumentsWrite !== null) + this.add( + "R2.4", + "sloppy-arguments", + "a write to 'arguments[i]' in sloppy mode", + seen.argumentsWrite, + ); + else if (seen.reads && seen.paramWrite !== null) + this.add( + "R2.4", + "sloppy-arguments", + "a parameter write while 'arguments' is read in sloppy mode", + seen.paramWrite, + ); + } +} + +interface ArgumentsUse { + reads: boolean; + argumentsWrite: ts.Node | null; + paramWrite: ts.Node | null; +} + +/** The R1/R2 markers of one JavaScript module, in source order. */ +export function scanModule(sf: ts.SourceFile): NodeIslandMarker[] { + const markers = new ModuleScanner(sf).scan(); + return markers.sort((a, b) => a.loc.start - b.loc.start); +} diff --git a/packages/compiler/src/node-islands/origin.ts b/packages/compiler/src/node-islands/origin.ts new file mode 100644 index 000000000..65beebba0 --- /dev/null +++ b/packages/compiler/src/node-islands/origin.ts @@ -0,0 +1,68 @@ +/* Where a source file comes from. User code (the program's own tree and + * workspace packages compiled from source) is strict; npm code (installed + * packages under node_modules) is lenient and is decided per package + * instance; shims are scriptc's own registry implementations; builtin + * covers declaration files of the type world. */ +import { join } from "node:path"; +import { isPackageShimFile } from "../frontend/package-shims.js"; +import { trackedReadFile } from "../frontend/input-tracker.js"; + +export type Origin = "user" | "npm" | "shim" | "builtin"; + +export function originOf(file: string): Origin { + const path = file.split("\\").join("/"); + if (isPackageShimFile(path)) return "shim"; + if (/\.d\.[cm]?ts$/.test(path)) return "builtin"; + return path.includes("/node_modules/") ? "npm" : "user"; +} + +/** One installed package: the decision unit for npm code. pnpm keeps + * versions apart in different directories, so the directory identifies the + * instance. */ +export interface PackageInstance { + name: string; + /** The package directory (…/node_modules/). */ + dir: string; + version: string | null; +} + +/** The package instance of a file under node_modules: the LAST + * node_modules segment (nested installs belong to the innermost package), + * scope-aware. Null outside node_modules. */ +export function packageDirOf(file: string): { name: string; dir: string } | null { + const path = file.split("\\").join("/"); + const parts = path.split("/"); + const i = parts.lastIndexOf("node_modules"); + if (i < 0 || i + 1 >= parts.length - 1) return null; + const first = parts[i + 1]!; + if (first.startsWith("@")) { + if (i + 2 >= parts.length - 1) return null; + const name = `${first}/${parts[i + 2]!}`; + return { name, dir: parts.slice(0, i + 3).join("/") }; + } + return { name: first, dir: parts.slice(0, i + 2).join("/") }; +} + +/** The `version` field of a package directory's package.json. */ +export function packageVersionOf(dir: string): string | null { + let version: string | null = null; + const text = trackedReadFile(join(dir, "package.json")); + if (text !== null) { + try { + const parsed: unknown = JSON.parse(text); + if (parsed !== null && typeof parsed === "object") { + const v = (parsed as Record)["version"]; + if (typeof v === "string") version = v; + } + } catch { + version = null; + } + } + return version; +} + +export function packageInstanceOf(file: string): PackageInstance | null { + const at = packageDirOf(file); + if (at === null) return null; + return { name: at.name, dir: at.dir, version: packageVersionOf(at.dir) }; +} diff --git a/packages/compiler/src/node-islands/policy.ts b/packages/compiler/src/node-islands/policy.ts new file mode 100644 index 000000000..72dbf3cd0 --- /dev/null +++ b/packages/compiler/src/node-islands/policy.ts @@ -0,0 +1,167 @@ +/* The Node island policy (DESIGN.md §1.5–§1.6): user code strict, npm + * lenient. npm code outside the native subset becomes a Node island + * automatically (`nodeIslands.auto`, `--node-islands=auto`); user modules + * become islands only when marked (`nodeIslands.modules`, + * `--node-island=`); `"native"` (`--native=`) makes one + * dependency strict; `--node-islands=off` makes the whole program strict. + * + * This version is report-only: the policy decides what WOULD run in Node, + * and coverage reports it, but code generation does not change. */ +import { isAbsolute, join, resolve, dirname } from "node:path"; +import type { ProjectConfig } from "../project-config.js"; + +export type NodeIslandsMode = "auto" | "explicit" | "off"; +export const NODE_ISLANDS_MODES: readonly NodeIslandsMode[] = ["auto", "explicit", "off"]; + +/** The command-line half of the policy (`build`, `run` and `coverage` + * accept these). */ +export interface NodeIslandOptions { + /** `--node-islands=auto|explicit|off`. */ + mode?: NodeIslandsMode; + /** `--node-island=`: packages and user modules forced into a + * Node island. Paths are absolute. */ + islands?: readonly string[]; + /** `--native=`: packages that must compile natively. */ + native?: readonly string[]; + /** `--node=`: the node executable recorded for islands. */ + node?: string; + /** `--strict-user-js`: report R2 constructs in user JavaScript as + * SC8101–SC8105. */ + strictUserJs?: boolean; +} + +export type DecisionSource = "config" | "cli"; + +export interface UserModulePattern { + /** An absolute path or glob. */ + pattern: string; + source: DecisionSource; +} + +export interface NodeIslandPolicy { + mode: NodeIslandsMode; + /** Where the mode came from (an explicit `"auto": false` reads as + * "explicit"). */ + modeSource: DecisionSource | "default"; + forcedNode: Map; + forcedNative: Map; + /** `"unloaded"` packages: never loaded, never islands. */ + unloaded: Set; + userModules: UserModulePattern[]; + node: string | null; + strictUserJs: boolean; +} + +/** Whether a `--node-island` value names a module rather than a package. */ +export function isModuleIslandArgument(value: string): boolean { + return ( + value.startsWith(".") || + value.startsWith("/") || + /\.(?:[cm]?[jt]s|[jt]sx)$/.test(value) || + value.includes("*") + ); +} + +export function nodeIslandPolicy( + config: ProjectConfig, + options: NodeIslandOptions = {}, +): NodeIslandPolicy { + const forcedNode = new Map(); + const forcedNative = new Map(); + const unloaded = new Set(); + for (const [name, setting] of config.packages) { + if (setting.unloaded) unloaded.add(name); + else if (setting.run === "node") forcedNode.set(name, "config"); + else if (setting.run === "native") forcedNative.set(name, "config"); + } + const userModules: UserModulePattern[] = []; + const base = config.manifest === null ? process.cwd() : dirname(config.manifest); + for (const pattern of config.nodeIslands.modules) { + userModules.push({ + pattern: isAbsolute(pattern) ? pattern : join(base, pattern), + source: "config", + }); + } + for (const value of options.islands ?? []) { + if (isModuleIslandArgument(value)) { + userModules.push({ pattern: resolve(value), source: "cli" }); + } else { + forcedNative.delete(value); + forcedNode.set(value, "cli"); + } + } + for (const name of options.native ?? []) { + forcedNode.delete(name); + forcedNative.set(name, "cli"); + } + let mode: NodeIslandsMode = "auto"; + let modeSource: DecisionSource | "default" = "default"; + if (options.mode !== undefined) { + mode = options.mode; + modeSource = "cli"; + } else if (!config.nodeIslands.auto) { + mode = "explicit"; + modeSource = "config"; + } + return { + mode, + modeSource, + forcedNode, + forcedNative, + unloaded, + userModules, + node: options.node ?? config.nodeIslands.node, + strictUserJs: options.strictUserJs === true, + }; +} + +/** Whether a user module is marked to run in a Node island. */ +export function isMarkedUserModule(policy: NodeIslandPolicy, file: string): DecisionSource | null { + const path = file.split("\\").join("/"); + for (const entry of policy.userModules) { + if (globMatch(entry.pattern.split("\\").join("/"), path)) return entry.source; + } + return null; +} + +/** Glob matching over `/`-separated paths: `**` spans directories, `*` and + * `?` stay inside one segment. */ +export function globMatch(pattern: string, path: string): boolean { + return matchSegments(pattern.split("/"), 0, path.split("/"), 0); +} + +function matchSegments(pat: string[], pi: number, segs: string[], si: number): boolean { + if (pi === pat.length) return si === segs.length; + const p = pat[pi]!; + if (p === "**") { + for (let k = si; k <= segs.length; k++) if (matchSegments(pat, pi + 1, segs, k)) return true; + return false; + } + if (si === segs.length) return false; + return matchSegment(p, 0, segs[si]!, 0) && matchSegments(pat, pi + 1, segs, si + 1); +} + +function matchSegment(p: string, pi: number, s: string, si: number): boolean { + if (pi === p.length) return si === s.length; + const ch = p.charAt(pi); + if (ch === "*") { + for (let k = si; k <= s.length; k++) if (matchSegment(p, pi + 1, s, k)) return true; + return false; + } + if (si === s.length) return false; + if (ch === "?" || ch === s.charAt(si)) return matchSegment(p, pi + 1, s, si + 1); + return false; +} + +/** The policy's identity for caches: two analyses with the same identity + * decide the same islands. */ +export function nodeIslandOptionsKey(options: NodeIslandOptions | undefined): string { + if (options === undefined) return ""; + return [ + options.mode ?? "", + (options.islands ?? []).join(","), + (options.native ?? []).join(","), + options.node ?? "", + options.strictUserJs === true ? "strict-user-js" : "", + ].join("|"); +} diff --git a/packages/compiler/src/node-islands/report.test.ts b/packages/compiler/src/node-islands/report.test.ts new file mode 100644 index 000000000..a11d9fb8b --- /dev/null +++ b/packages/compiler/src/node-islands/report.test.ts @@ -0,0 +1,201 @@ +import { describe, expect, test } from "vitest"; +import type { ScrDiagnostic } from "../diagnostics/diagnostic.js"; +import { emptyProjectConfig, parseProjectConfig } from "../project-config.js"; +import type { NodeIslandMarker } from "./detect.js"; +import { + globMatch, + isMarkedUserModule, + nodeIslandPolicy, + type NodeIslandOptions, +} from "./policy.js"; +import { buildNodeIslandReport, type NpmOutcome } from "./report.js"; +import type { NodeIslandScan, PackageEdge, ScannedModule } from "./scan.js"; + +const NM = "/app/node_modules"; + +function mod(pkg: string | null, file: string, markers: NodeIslandMarker[] = []): ScannedModule { + return { + file, + origin: pkg === null ? "user" : "npm", + packageDir: pkg === null ? null : `${NM}/${pkg}`, + packageName: pkg, + markers, + dropped: false, + }; +} + +function marker(file: string, rule: NodeIslandMarker["rule"], reason: string): NodeIslandMarker { + return { rule, reason, construct: reason, loc: { file, start: 0, end: 1 } }; +} + +function edge(from: string | null, to: string): PackageEdge { + return { + fromDir: from === null ? null : `${NM}/${from}`, + fromFile: from === null ? "/app/main.ts" : `${NM}/${from}/index.js`, + to, + toDir: `${NM}/${to}`, + shim: false, + loc: { file: from === null ? "/app/main.ts" : `${NM}/${from}/index.js`, start: 0, end: 1 }, + }; +} + +function gapFence(pkg: string): ScrDiagnostic { + return { + code: "SC1090", + message: "a builtin function alias as an escaping value", + loc: { file: `${NM}/${pkg}/index.js`, start: 5, end: 9 }, + }; +} + +/** A program: main.ts imports a (constructor functions), b (a gap fence) + * and c (clean); a imports d (clean, only from a) and c. */ +function program(): { scan: NodeIslandScan; fences: ScrDiagnostic[] } { + return { + scan: { + modules: [ + mod(null, "/app/main.ts"), + mod("a", `${NM}/a/index.js`, [marker(`${NM}/a/index.js`, "R2.1", "constructor-function")]), + mod("b", `${NM}/b/index.js`), + mod("c", `${NM}/c/index.js`), + mod("d", `${NM}/d/index.js`), + ], + edges: [edge(null, "a"), edge(null, "b"), edge(null, "c"), edge("a", "d"), edge("a", "c")], + refusals: [], + }, + fences: [gapFence("b")], + }; +} + +function report( + options: NodeIslandOptions = {}, + npm: NpmOutcome[] = [], + config = emptyProjectConfig(), +) { + const { scan, fences } = program(); + return buildNodeIslandReport({ + entry: "/app/main.ts", + scan, + npm, + diagnostics: [], + fences, + policy: nodeIslandPolicy(config, options), + }); +} + +describe("decisions", () => { + test("auto: packages with reasons are islands, gap islands first; closure and sharing", () => { + const r = report(); + expect(r.islands.map((i) => [i.package, i.class, i.decision])).toEqual([ + ["b", "gap", "auto"], + ["a", "object-model", "auto"], + ]); + expect(r.islands[0]!.reason).toBe("SC1090: a builtin function alias as an escaping value"); + expect(r.islands[1]!.carries).toEqual(["d"]); + expect(r.packages.map((p) => [p.package, p.status, p.islands])).toEqual([ + ["c", "shared", ["a"]], + ["d", "inside", ["a"]], + ]); + expect(r.violations).toEqual([]); + }); + + test("a refused package is a packaging island, classified by its refusal", () => { + const r = report({}, [ + { package: "c", status: "refused", detail: "auto: its shipped JS looks minified" }, + ]); + const c = r.islands.find((i) => i.package === "c")!; + expect([c.class, c.reason, c.diagnostic]).toEqual([ + "packaging", + "SC2013: auto: its shipped JS looks minified", + "SC2013", + ]); + }); + + test("forced native turns reasons into SC8003; forced node islands a clean package", () => { + const r = report({ native: ["a"], islands: ["c"] }); + expect(r.islands.map((i) => [i.package, i.class, i.decision])).toEqual([ + ["b", "gap", "auto"], + ["c", "marked", "cli"], + ]); + expect(r.violations.map((v) => v.code)).toEqual(["SC8003"]); + expect(r.violations[0]!.message).toContain("'a' is marked native"); + }); + + test("off: no islands, every package outside the native subset is SC8002", () => { + const r = report({ mode: "off" }); + expect(r.islands).toEqual([]); + expect(r.violations.map((v) => [v.code, v.message.split(" (")[0]])).toEqual([ + ["SC8002", "npm package 'a' is outside the native subset"], + ["SC8002", "npm package 'b' is outside the native subset"], + ]); + }); + + test('explicit (or "auto": false): only marked islands', () => { + const config = parseProjectConfig( + "/app/package.json", + JSON.stringify({ scriptc: { nodeIslands: { auto: false }, packages: { b: "node" } } }), + ); + const r = report({}, [], config); + expect(r.policy).toBe("explicit"); + expect(r.islands.map((i) => [i.package, i.decision])).toEqual([["b", "config"]]); + expect(r.violations.map((v) => v.code)).toEqual(["SC8002"]); + }); + + test("command-line names the program does not import are reported", () => { + expect(report({ native: ["nope"] }).unknownPackages).toEqual(["nope"]); + }); + + test("unloaded packages are never islands", () => { + const config = parseProjectConfig( + "/app/package.json", + JSON.stringify({ scriptc: { packages: { a: "unloaded" } } }), + ); + expect(report({}, [], config).islands.map((i) => i.package)).toEqual(["b"]); + }); +}); + +describe("user modules", () => { + test("marked by glob in the config or by path on the command line", () => { + const config = parseProjectConfig( + "/app/package.json", + JSON.stringify({ scriptc: { nodeIslands: { modules: ["src/plugins/**/*.ts"] } } }), + ); + const policy = nodeIslandPolicy(config, { islands: ["/app/src/legacy.js"] }); + expect(isMarkedUserModule(policy, "/app/src/plugins/a/loader.ts")).toBe("config"); + expect(isMarkedUserModule(policy, "/app/src/legacy.js")).toBe("cli"); + expect(isMarkedUserModule(policy, "/app/src/main.ts")).toBe(null); + }); + + test("SC81xx for R2 markers in user JavaScript, only with --strict-user-js", () => { + const file = "/app/legacy.js"; + const scan: NodeIslandScan = { + modules: [ + mod(null, file, [ + marker(file, "R2.1", "constructor-function"), + marker(file, "R2.5", "builtin-write"), + marker(file, "R1.1", "code-from-string"), + ]), + ], + edges: [], + refusals: [], + }; + const build = (strictUserJs: boolean) => + buildNodeIslandReport({ + entry: file, + scan, + npm: [], + diagnostics: [], + fences: [], + policy: nodeIslandPolicy(emptyProjectConfig(), { strictUserJs }), + }); + expect(build(false).userJs).toEqual([]); + expect(build(true).userJs.map((d) => d.code)).toEqual(["SC8101", "SC8105"]); + }); +}); + +test("globMatch", () => { + expect(globMatch("/a/**/*.ts", "/a/b/c/d.ts")).toBe(true); + expect(globMatch("/a/**/*.ts", "/a/d.ts")).toBe(true); + expect(globMatch("/a/*.ts", "/a/b/d.ts")).toBe(false); + expect(globMatch("/a/?.js", "/a/x.js")).toBe(true); + expect(globMatch("/a/x.js", "/a/x.js")).toBe(true); +}); diff --git a/packages/compiler/src/node-islands/report.ts b/packages/compiler/src/node-islands/report.ts new file mode 100644 index 000000000..a6898e855 --- /dev/null +++ b/packages/compiler/src/node-islands/report.ts @@ -0,0 +1,355 @@ +/* The Node island report: which packages and user modules would run in a + * Node island, and why (DESIGN.md §1.3–§1.7). Report-only: the decisions + * are computed from the detector and the policy, and nothing about the + * build changes. + * + * 1. Reasons per package instance: pre-scan markers in its modules, + * refusals and runtime fences the lowering produced in its modules, and + * the drop-and-reload refusal of a package that did not compile. + * 2. Decision per package: the policy (forced node or native, the mode) + * applied to its reasons. + * 3. Closure: a package imported only by island packages runs inside the + * island (it is Node's business); one reached from both sides is + * reported as shared (DESIGN.md §2.6 decides it later). */ +import { + nativePackageDiag, + nodeIslandsOffDiag, + userJsObjectModelDiag, + type ScrDiagnostic, +} from "../diagnostics/diagnostic.js"; +import type { SrcLoc } from "../ir/ir.js"; +import { + classifyDiagnostic, + classifyMarker, + classifyRefusal, + isIslandReasonCode, +} from "./classify.js"; +import { + describe, + type IslandDecision, + type NativePackage, + type NodeIslandEntry, + type NodeIslandReason, + type NodeIslandReasonSource, + type NodeIslandReport, + type UserModuleIsland, +} from "./summary.js"; +import { packageDirOf, packageVersionOf } from "./origin.js"; +import { isMarkedUserModule, type NodeIslandPolicy } from "./policy.js"; +import { classRank, reportRank, ruleInfo } from "./rules.js"; +import type { NodeIslandScan, RefusalRecord } from "./scan.js"; + +/** One dependency's native compilation outcome (coverage/report.ts's + * NpmStaticStatus, restated to keep this module free of coverage). */ +export interface NpmOutcome { + package: string; + status: "static" | "refused"; + detail?: string; +} + +export interface NodeIslandReportInput { + entry: string; + scan: NodeIslandScan; + npm: readonly NpmOutcome[]; + /** Lowering diagnostics of the analysis (reached and unreached), runtime + * fences separately. */ + diagnostics: readonly ScrDiagnostic[]; + fences: readonly ScrDiagnostic[]; + policy: NodeIslandPolicy; +} + +/** Reasons kept per package (the report renders the first per module). */ +const REASON_CAP = 200; + +interface PackageState { + key: string; + name: string; + dir: string | null; + reasons: NodeIslandReason[]; + importers: Set; + nativeSites: SrcLoc[]; + island: boolean; + decision: IslandDecision; + carriedBy: string | null; + violation: boolean; +} + +export function buildNodeIslandReport(input: NodeIslandReportInput): NodeIslandReport { + const policy = input.policy; + const states = new Map(); + const byName = new Map(); + const state = (name: string, dir: string | null): PackageState => { + const key = dir ?? `name:${name}`; + let s = states.get(key); + if (s === undefined) { + s = { + key, + name, + dir, + reasons: [], + importers: new Set(), + nativeSites: [], + island: false, + decision: "auto", + carriedBy: null, + violation: false, + }; + states.set(key, s); + const keys = byName.get(name) ?? []; + keys.push(key); + byName.set(name, keys); + } + return s; + }; + const addReason = (s: PackageState, r: NodeIslandReason): void => { + if (s.reasons.length < REASON_CAP) s.reasons.push(r); + }; + const ignored = (name: string): boolean => policy.unloaded.has(name); + + // Modules and their markers. + for (const m of input.scan.modules) { + if (m.origin !== "npm" || m.packageName === null) continue; + if (ignored(m.packageName)) continue; + const s = state(m.packageName, m.packageDir); + for (const marker of m.markers) addReason(s, classifyMarker(marker)); + } + // Import edges. + for (const e of input.scan.edges) { + if (e.shim || ignored(e.to)) continue; + const s = state(e.to, e.toDir); + if (e.fromDir === null) { + s.importers.add(""); + s.nativeSites.push(e.loc); + } else if (e.fromDir !== s.key) { + s.importers.add(e.fromDir); + } + } + // Lowering refusals and fences inside npm modules. + const addDiagnostics = (diags: readonly ScrDiagnostic[], source: NodeIslandReasonSource) => { + for (const d of diags) { + if (!isIslandReasonCode(d.code)) continue; + const at = packageDirOf(d.loc.file); + if (at === null || ignored(at.name)) continue; + addReason(state(at.name, at.dir), classifyDiagnostic(d, source)); + } + }; + addDiagnostics(input.diagnostics, "refusal"); + addDiagnostics(input.fences, "fence"); + // Packages that did not compile. + const records = new Map(); + for (const r of input.scan.refusals) if (!records.has(r.package)) records.set(r.package, r); + for (const outcome of input.npm) { + if (outcome.status !== "refused" || ignored(outcome.package)) continue; + const reason = classifyRefusal( + outcome.detail ?? "its static compilation was refused", + records.get(outcome.package) ?? null, + ); + if (reason === null) continue; + const keys = byName.get(outcome.package); + if (keys === undefined || keys.length === 0) { + addReason(state(outcome.package, null), reason); + continue; + } + for (const key of keys) addReason(states.get(key)!, reason); + } + + // Decisions. + const violations: ScrDiagnostic[] = []; + const fallbackLoc: SrcLoc = { file: input.entry, start: 0, end: 0 }; + for (const s of states.values()) { + sortReasons(s.reasons); + const forcedNode = policy.forcedNode.get(s.name); + const forcedNative = policy.forcedNative.get(s.name); + const outside = s.reasons.length > 0; + const loc = s.nativeSites[0] ?? fallbackLoc; + if (forcedNative !== undefined) { + if (outside) { + s.violation = true; + violations.push(nativePackageDiag(s.name, describe(s.reasons[0]!), loc)); + } + continue; + } + if (policy.mode === "off") { + if (outside || forcedNode !== undefined) { + s.violation = true; + violations.push( + nodeIslandsOffDiag( + s.name, + outside ? describe(s.reasons[0]!) : "it is marked to run in Node", + loc, + ), + ); + } + continue; + } + if (forcedNode !== undefined) { + s.island = true; + s.decision = forcedNode; + continue; + } + if (!outside) continue; + if (policy.mode === "explicit") { + s.violation = true; + violations.push(nodeIslandsOffDiag(s.name, describe(s.reasons[0]!), loc)); + continue; + } + s.island = true; + s.decision = "auto"; + } + + // Closure: packages imported only by islands (or by packages inside + // them) run inside the island. + for (let changed = true; changed;) { + changed = false; + for (const s of states.values()) { + if (s.island || s.carriedBy !== null || s.violation) continue; + if (s.importers.size === 0 || s.importers.has("")) continue; + let carrier: string | null = null; + let all = true; + for (const from of s.importers) { + const importer = states.get(from); + const owner = + importer === undefined ? null : importer.island ? importer.key : importer.carriedBy; + if (owner === null) { + all = false; + break; + } + carrier ??= owner; + } + if (all && carrier !== null) { + s.carriedBy = carrier; + changed = true; + } + } + } + + // Entries. + const islands: NodeIslandEntry[] = []; + const packages: NativePackage[] = []; + for (const s of states.values()) { + const version = s.dir === null ? null : packageVersionOf(s.dir); + if (s.island) { + const first = s.reasons[0]; + const modules = new Set(); + for (const r of s.reasons) if (r.loc !== null) modules.add(r.loc.file); + const carries: string[] = []; + for (const other of states.values()) { + if (other.carriedBy === s.key) carries.push(other.name); + } + carries.sort(); + islands.push({ + package: s.name, + version, + path: s.dir, + class: first === undefined ? "marked" : first.class, + reason: first === undefined ? markedReason(s.decision) : describe(first), + diagnostic: first === undefined ? null : first.code, + decision: s.decision, + reasons: s.reasons, + modules: modules.size, + carries, + importedFrom: s.nativeSites, + evaluation: "eager", + }); + continue; + } + if (s.violation) continue; + // A package that resolves to no installed JavaScript never loads (an + // optional dependency that is absent): nothing to compile or island. + if (s.dir === null && s.reasons.length === 0) continue; + const reachingIslands: string[] = []; + for (const from of s.importers) { + const importer = states.get(from); + if (importer === undefined) continue; + const owner = importer.island ? importer.key : importer.carriedBy; + if (owner !== null) { + const name = states.get(owner)!.name; + if (!reachingIslands.includes(name)) reachingIslands.push(name); + } + } + reachingIslands.sort(); + packages.push({ + package: s.name, + version, + path: s.dir, + status: s.carriedBy !== null ? "inside" : reachingIslands.length > 0 ? "shared" : "native", + islands: s.carriedBy !== null ? [states.get(s.carriedBy)!.name] : reachingIslands, + }); + } + islands.sort( + (a, b) => + reportRank(a.class) - reportRank(b.class) || + compareText(a.package, b.package) || + compareText(a.path ?? "", b.path ?? ""), + ); + packages.sort( + (a, b) => compareText(a.package, b.package) || compareText(a.path ?? "", b.path ?? ""), + ); + + // Marked user modules and SC81xx in user JavaScript. + const userModules: UserModuleIsland[] = []; + const userJs: ScrDiagnostic[] = []; + for (const m of input.scan.modules) { + if (m.origin !== "user") continue; + const marked = isMarkedUserModule(policy, m.file); + if (marked !== null) { + userModules.push({ file: m.file, source: marked }); + continue; + } + if (!policy.strictUserJs) continue; + for (const marker of m.markers) { + const code = ruleInfo(marker.rule).userJsCode; + if (code === null) continue; + userJs.push(userJsObjectModelDiag(code, capitalize(marker.construct), marker.loc)); + } + } + userModules.sort((a, b) => compareText(a.file, b.file)); + + const unknownPackages: string[] = []; + // Only command-line names: a project's configuration may list packages + // for other entries. + for (const forced of [policy.forcedNode, policy.forcedNative]) { + for (const [name, source] of forced) { + if (source === "cli" && !byName.has(name) && !unknownPackages.includes(name)) + unknownPackages.push(name); + } + } + unknownPackages.sort(); + + return { + mode: "would-be", + policy: policy.mode, + islands, + packages, + userModules, + violations, + userJs, + unknownPackages, + }; +} + +function compareText(a: string, b: string): number { + return a < b ? -1 : a > b ? 1 : 0; +} + +function capitalize(text: string): string { + return text.length === 0 ? text : text.charAt(0).toUpperCase() + text.slice(1); +} + +function markedReason(decision: IslandDecision): string { + return decision === "cli" ? "marked with --node-island" : 'marked "node" in scriptc.packages'; +} + +/** Decisive class first; within a class, refusals before pre-scan markers + * (the lowering is authoritative), then source order. */ +function sortReasons(reasons: NodeIslandReason[]): void { + const sourceRank = (r: NodeIslandReason): number => + r.source === "package" ? 0 : r.source === "refusal" ? 1 : r.source === "fence" ? 2 : 3; + reasons.sort( + (a, b) => + classRank(a.class) - classRank(b.class) || + sourceRank(a) - sourceRank(b) || + compareText(a.loc?.file ?? "", b.loc?.file ?? "") || + (a.loc?.start ?? 0) - (b.loc?.start ?? 0), + ); +} diff --git a/packages/compiler/src/node-islands/rules.ts b/packages/compiler/src/node-islands/rules.ts new file mode 100644 index 000000000..25f686314 --- /dev/null +++ b/packages/compiler/src/node-islands/rules.ts @@ -0,0 +1,109 @@ +/* The refusal rules of scope B (results/design-scope-b/DESIGN.md §1.2): + * the constructs that put a module outside the native subset, grouped in + * eleven rule families, and the four classes the detector reports. + * + * runtime (R1) needs the JavaScript runtime itself + * object-model (R2) needs a mutable object model + * gap inside the native subset, but scriptc cannot compile it yet + * packaging not compilable as shipped (no declarations, minified, ...) + * + * A reason id names one construct; refusal sites carry it on their + * diagnostic (ScrDiagnostic.reason) and the pre-scan (detect.ts) reports it + * with the rule. */ + +export type NodeIslandClass = "runtime" | "object-model" | "gap" | "packaging" | "marked"; + +export type NodeIslandRule = + | "R1.1" + | "R1.2" + | "R1.3" + | "R1.4" + | "R1.5" + | "R1.6" + | "R2.1" + | "R2.2" + | "R2.3" + | "R2.4" + | "R2.5"; + +export interface RuleInfo { + rule: NodeIslandRule; + title: string; + /** The SC81xx code the construct is in user JavaScript (R2 only). */ + userJsCode: "SC8101" | "SC8102" | "SC8103" | "SC8104" | "SC8105" | null; +} + +const RULES: RuleInfo[] = [ + { rule: "R1.1", title: "code from strings", userJsCode: null }, + { rule: "R1.2", title: "dynamic module loading", userJsCode: null }, + { rule: "R1.3", title: "native addons", userJsCode: null }, + { rule: "R1.4", title: "loader and require hooks", userJsCode: null }, + { rule: "R1.5", title: "engine internals", userJsCode: null }, + { rule: "R1.6", title: "runtime-only globals", userJsCode: null }, + { rule: "R2.1", title: "constructor functions", userJsCode: "SC8101" }, + { rule: "R2.2", title: "prototype mutation", userJsCode: "SC8102" }, + { rule: "R2.3", title: "shape mutation outside the checker's view", userJsCode: "SC8103" }, + { rule: "R2.4", title: "sloppy-mode semantics", userJsCode: "SC8104" }, + { rule: "R2.5", title: "builtin and global patching", userJsCode: "SC8105" }, +]; + +export function ruleInfo(rule: NodeIslandRule): RuleInfo { + for (const info of RULES) if (info.rule === rule) return info; + throw new Error(`unknown Node island rule ${rule}`); +} + +/** Reason id → rule. Ids without a rule (gap, packaging) are absent. */ +const REASON_RULES: Record = { + "code-from-string": "R1.1", + vm: "R1.1", + "dynamic-require": "R1.2", + "dynamic-import": "R1.2", + "unresolved-import": "R1.2", + "native-addon": "R1.3", + "loader-hook": "R1.4", + "engine-internal": "R1.5", + "weak-ref": "R1.6", + "constructor-function": "R2.1", + "prototype-write": "R2.2", + "define-property": "R2.3", + with: "R2.4", + "sloppy-arguments": "R2.4", + "sloppy-mode": "R2.4", + "builtin-write": "R2.5", + proxy: "R2.5", +}; + +export function ruleOfReason(reason: string): NodeIslandRule | null { + return REASON_RULES[reason] ?? null; +} + +export function classOfRule(rule: NodeIslandRule): NodeIslandClass { + return rule.startsWith("R1.") ? "runtime" : "object-model"; +} + +/** The decisive class first: a runtime need outranks an object-model need, + * which outranks shipping problems; a gap is a package's class only when + * nothing else keeps it out of the native subset (fixing the gap would make + * it native). */ +export function classRank(cls: NodeIslandClass): number { + if (cls === "runtime") return 0; + if (cls === "object-model") return 1; + if (cls === "packaging") return 2; + if (cls === "gap") return 3; + return 4; +} + +/** Report order: gap islands first (compiler work hidden behind an + * island), then the rest by rank. */ +export function reportRank(cls: NodeIslandClass): number { + if (cls === "gap") return 0; + return classRank(cls) + 1; +} + +export function classDescription(cls: NodeIslandClass): string { + if (cls === "runtime") return "needs the JavaScript runtime"; + if (cls === "object-model") return "needs a mutable object model"; + if (cls === "gap") return "inside the native subset, but scriptc cannot compile it yet"; + if (cls === "packaging") return "not compilable as shipped"; + return "marked to run in Node"; +} diff --git a/packages/compiler/src/node-islands/scan.ts b/packages/compiler/src/node-islands/scan.ts new file mode 100644 index 000000000..0ac082e73 --- /dev/null +++ b/packages/compiler/src/node-islands/scan.ts @@ -0,0 +1,155 @@ +/* The program-level half of the detector: which modules a program loads, + * the pre-scan markers in each, and the package import edges the island + * closure needs. The frontend calls it on its final program (and on the + * program that still held a package the drop-and-reload loop removed). */ +import type { ScrDiagnostic } from "../diagnostics/diagnostic.js"; +import type { SrcLoc } from "../ir/ir.js"; +import * as ts from "../frontend/ts7/adapter.js"; +import { canonicalBuiltinModule, npmBuiltinAliasOf } from "../frontend/builtin-modules.js"; +import { erasedTypeOnlyImport } from "../frontend/type-only-imports.js"; +import { isShimmedImport } from "../frontend/package-shims.js"; +import { resolveBareModule } from "../frontend/resolve.js"; +import { isJsSourceFileName } from "../frontend/tsc-codes.js"; +import { isRelativeSpecifier, packageNameOfSpecifier } from "../frontend/workspace-registry.js"; +import { moduleSourceCandidates } from "../frontend/module-source-candidates.js"; +import { scanModule, type NodeIslandMarker } from "./detect.js"; +import { originOf, packageDirOf, type Origin } from "./origin.js"; + +export interface ScannedModule { + file: string; + origin: Origin; + /** The npm package directory, for npm modules. */ + packageDir: string | null; + packageName: string | null; + markers: NodeIslandMarker[]; + /** True for a module of a package the drop-and-reload loop removed. */ + dropped: boolean; +} + +/** One import of an npm package. */ +export interface PackageEdge { + /** The importing package's directory; null for user code. */ + fromDir: string | null; + fromFile: string; + /** The imported package's name. */ + to: string; + /** Its directory when the import resolves to installed JavaScript. */ + toDir: string | null; + /** Served by a registry shim, a builtin alias, or marked unloaded. */ + shim: boolean; + loc: SrcLoc; +} + +/** How the drop-and-reload loop refused a package. */ +export type RefusalKind = "preflight" | "offender" | "degrade" | "typecheck" | "external"; + +export interface RefusalRecord { + package: string; + kind: RefusalKind; + /** The package-anchored preflight diagnostic, for kind "preflight". */ + diag: ScrDiagnostic | null; +} + +export interface NodeIslandScan { + modules: ScannedModule[]; + edges: PackageEdge[]; + refusals: RefusalRecord[]; +} + +export function emptyScan(): NodeIslandScan { + return { modules: [], edges: [], refusals: [] }; +} + +function locOfNode(node: ts.Node): SrcLoc { + const sf = ts.getSourceFileOfNode(node); + return { file: sf.fileName, start: ts.tokenStartOfNode(node), end: node.end }; +} + +/** The literal module specifiers of a file with their sites: top-level + * import and export declarations, and the require() and import() calls the + * program's shared module-source scan already collected (no second walk). */ +function specifiersOf(program: ts.Program, sf: ts.SourceFile): { spec: string; node: ts.Node }[] { + const out: { spec: string; node: ts.Node }[] = []; + for (const node of sf.statements.nodes) { + if ( + (ts.isImportDeclaration(node) || ts.isExportDeclaration(node)) && + node.moduleSpecifier !== undefined && + ts.isStringLiteral(node.moduleSpecifier) + ) { + // Type-only imports load nothing. + const typeOnly = ts.isImportDeclaration(node) ? erasedTypeOnlyImport(node) : node.isTypeOnly; + if (!typeOnly) out.push({ spec: node.moduleSpecifier.text, node }); + } + } + for (const call of moduleSourceCandidates(program, sf).calls) { + const arg = call.arguments.nodes[0]; + if ( + arg !== undefined && + ts.isStringLiteralLike(arg) && + (call.expression.kind === ts.SyntaxKind.ImportKeyword || + (ts.isIdentifier(call.expression) && call.expression.text === "require")) + ) + out.push({ spec: arg.text, node: call }); + } + return out; +} + +/** Scans `files`: markers for npm JavaScript (and for user JavaScript when + * `userJs`), and package edges for every file when `edges` (a program with + * no npm package has none to find). */ +export function scanFiles( + program: ts.Program, + files: readonly ts.SourceFile[], + opts: { userJs: boolean; dropped: boolean; edges: boolean }, +): { modules: ScannedModule[]; edges: PackageEdge[] } { + const modules: ScannedModule[] = []; + const edges: PackageEdge[] = []; + const seen = new Set(); + for (const sf of files) { + if (seen.has(sf.fileName)) continue; + seen.add(sf.fileName); + const origin = originOf(sf.fileName); + if (origin === "builtin" || origin === "shim") continue; + const at = origin === "npm" ? packageDirOf(sf.fileName) : null; + const js = isJsSourceFileName(sf.fileName); + const markers = js && (origin === "npm" || opts.userJs) ? scanModule(sf) : []; + modules.push({ + file: sf.fileName, + origin, + packageDir: at === null ? null : at.dir, + packageName: at === null ? null : at.name, + markers, + dropped: opts.dropped, + }); + if (!opts.edges) continue; + for (const { spec, node } of specifiersOf(program, sf)) { + if (isRelativeSpecifier(spec) || spec.startsWith("/") || spec.startsWith("#")) continue; + // scriptc's own packages lower at their use sites. + if (spec.startsWith("@scriptc/")) continue; + const alias = npmBuiltinAliasOf(spec); + if (alias === null && (spec.startsWith("node:") || canonicalBuiltinModule(spec) !== null)) + continue; + const name = packageNameOfSpecifier(spec); + const shim = alias !== null || isShimmedImport(sf.fileName, spec); + let toDir: string | null = null; + if (!shim) { + const resolved = resolveBareModule(sf.fileName, spec, "js-only"); + if (resolved !== null) { + const target = packageDirOf(resolved.typesFile); + // A workspace package compiled from source is user code. + if (target === null) continue; + toDir = target.dir; + } + } + edges.push({ + fromDir: at === null ? null : at.dir, + fromFile: sf.fileName, + to: name, + toDir, + shim, + loc: locOfNode(node), + }); + } + } + return { modules, edges }; +} diff --git a/packages/compiler/src/node-islands/summary.ts b/packages/compiler/src/node-islands/summary.ts new file mode 100644 index 000000000..8108d985c --- /dev/null +++ b/packages/compiler/src/node-islands/summary.ts @@ -0,0 +1,110 @@ +/* The Node island report's data model and the small helpers coverage + * rendering needs. Kept free of compiler imports: the coverage report (and + * the CLI's verdict-replay fast path behind it) loads this module. */ +import type { ScrDiagnostic } from "../diagnostics/diagnostic.js"; +import type { SrcLoc } from "../ir/ir.js"; +import type { DecisionSource, NodeIslandPolicy } from "./policy.js"; +import type { NodeIslandClass, NodeIslandRule } from "./rules.js"; + +export type NodeIslandReasonSource = "pre-scan" | "refusal" | "fence" | "package"; + +export interface NodeIslandReason { + class: NodeIslandClass; + rule: NodeIslandRule | null; + /** Reason id: a rules.ts id, "gap" or "packaging". */ + reason: string; + /** The SC code of the refusal, when the reason is a diagnostic. */ + code: string | null; + message: string; + loc: SrcLoc | null; + source: NodeIslandReasonSource; +} + +export type IslandDecision = "auto" | "config" | "cli"; + +export interface NodeIslandEntry { + package: string; + version: string | null; + /** The package directory (the instance), when it is installed. */ + path: string | null; + class: NodeIslandClass; + /** The first decisive reason, rendered. */ + reason: string; + /** The SC code of the first decisive reason, when it is a refusal. */ + diagnostic: string | null; + decision: IslandDecision; + /** Every reason, in report order (decisive class first, then source + * order). */ + reasons: NodeIslandReason[]; + /** Modules of the package with at least one reason. */ + modules: number; + /** Packages imported only through this island, which run inside it. */ + carries: string[]; + /** Where native code imports the package: the island boundary. */ + importedFrom: SrcLoc[]; + /** Report-only: deferral (NI-7) is not decided yet, so every island + * would evaluate eagerly at its module position. */ + evaluation: "eager"; +} + +export interface UserModuleIsland { + file: string; + source: DecisionSource; +} + +export interface NativePackage { + package: string; + version: string | null; + path: string | null; + /** "native": compiles natively; "inside": runs inside an island's + * closure; "shared": reached from native code and from an island. */ + status: "native" | "inside" | "shared"; + /** For inside and shared: the islands that reach it. */ + islands: string[]; +} + +export interface NodeIslandReport { + mode: "would-be"; + policy: NodeIslandPolicy["mode"]; + islands: NodeIslandEntry[]; + packages: NativePackage[]; + userModules: UserModuleIsland[]; + /** Would-be errors: SC8002 (islands off) and SC8003 (marked native). */ + violations: ScrDiagnostic[]; + /** SC8101–SC8105 for user JavaScript (only with --strict-user-js). */ + userJs: ScrDiagnostic[]; + /** --native / --node-island / config package names the program does + * not import. */ + unknownPackages: string[]; +} + +/** "R2.1 constructor functions: 'new Foo()' of a function" or + * "SC2012: ". */ +export function describe(r: NodeIslandReason): string { + if (r.source === "pre-scan" && r.rule !== null) return `${r.rule} ${r.message}`; + const rule = r.rule === null ? "" : `${r.rule} `; + return r.code === null ? `${rule}${r.message}` : `${rule}${r.code}: ${r.message}`; +} + +/** True when the report has decisions to show (islands, marked modules, + * policy errors or unknown names); SC81xx findings alone render as + * blockers. */ +export function hasNodeIslandDecisions(report: NodeIslandReport): boolean { + return ( + report.islands.length > 0 || + report.userModules.length > 0 || + report.violations.length > 0 || + report.unknownPackages.length > 0 + ); +} + +/** True when the report has anything to show. */ +export function hasNodeIslandFindings(report: NodeIslandReport): boolean { + return ( + report.islands.length > 0 || + report.userModules.length > 0 || + report.violations.length > 0 || + report.userJs.length > 0 || + report.unknownPackages.length > 0 + ); +} diff --git a/packages/compiler/src/project-config.test.ts b/packages/compiler/src/project-config.test.ts new file mode 100644 index 000000000..b9750f24e --- /dev/null +++ b/packages/compiler/src/project-config.test.ts @@ -0,0 +1,126 @@ +import { expect, test } from "vitest"; +import { parseProjectConfig } from "./project-config.js"; + +const manifest = "/project/package.json"; + +function config(scriptc: unknown) { + return parseProjectConfig(manifest, JSON.stringify({ name: "app", scriptc }, null, 2)); +} + +test("a package.json without a scriptc key has the default configuration", () => { + const c = parseProjectConfig(manifest, '{ "name": "app" }'); + expect(c.diagnostics).toEqual([]); + expect(c.packages.size).toBe(0); + expect(c.nodeIslands).toEqual({ + auto: true, + modules: [], + node: null, + nodeVersion: null, + packaging: "embedded", + speculativeStart: false, + }); + expect(parseProjectConfig(manifest, "{ not json").diagnostics).toEqual([]); +}); + +test("package settings: strings and objects", () => { + const c = config({ + packages: { + encoding: "unloaded", + "dd-trace": "node", + "hot-shots": "native", + semver: "auto", + "proper-lockfile": { run: "node", evaluate: "lazy", share: "duplicate" }, + }, + }); + expect(c.diagnostics).toEqual([]); + expect(c.packages.get("encoding")?.unloaded).toBe(true); + expect(c.packages.get("dd-trace")?.run).toBe("node"); + expect(c.packages.get("hot-shots")?.run).toBe("native"); + expect(c.packages.get("semver")?.run).toBe("auto"); + expect(c.packages.get("proper-lockfile")).toEqual({ + unloaded: false, + run: "node", + evaluate: "lazy", + share: "duplicate", + marshal: "copy", + schedule: "lockstep", + }); +}); + +test("nodeIslands settings", () => { + const c = config({ + nodeIslands: { + auto: false, + modules: ["src/plugins/*.ts"], + node: "/usr/local/bin/node", + nodeVersion: ">=24.13.1", + packaging: "beside", + speculativeStart: true, + }, + wasm: ["build/a.wasm", 3], + }); + expect(c.diagnostics).toEqual([]); + expect(c.nodeIslands).toEqual({ + auto: false, + modules: ["src/plugins/*.ts"], + node: "/usr/local/bin/node", + nodeVersion: ">=24.13.1", + packaging: "beside", + speculativeStart: true, + }); + // scriptc.wasm keeps its lenient reading. + expect(c.wasm).toEqual(["/project/build/a.wasm"]); +}); + +test("unknown keys and values are SC8004, located at the key", () => { + const text = JSON.stringify( + { + name: "app", + scriptc: { + packages: { + encoding: "unloded", + debug: { run: "node", evaluate: "later", color: true }, + ms: 3, + }, + nodeIslands: { auto: "yes", mode: "auto", modules: "src/x.ts", packaging: "zip" }, + }, + }, + null, + 2, + ); + const c = parseProjectConfig(manifest, text); + expect(c.diagnostics.map((d) => [d.code, d.message])).toEqual([ + ["SC8004", `package.json 'scriptc.packages.encoding' has the unknown value "unloded"`], + ["SC8004", `package.json 'scriptc.packages.debug.evaluate' has the unknown value "later"`], + ["SC8004", "package.json 'scriptc.packages.debug.color' is not a known package setting"], + ["SC8004", "package.json 'scriptc.packages.ms' must be a string or an object, not 3"], + ["SC8004", `package.json 'scriptc.nodeIslands.auto' must be true or false, not "yes"`], + ["SC8004", "package.json 'scriptc.nodeIslands.mode' is not a known Node island setting"], + [ + "SC8004", + `package.json 'scriptc.nodeIslands.modules' must be an array of module paths or globs, not "src/x.ts"`, + ], + ["SC8004", `package.json 'scriptc.nodeIslands.packaging' has the unknown value "zip"`], + ]); + // Locations point at the offending key inside the scriptc object. + const at = (i: number) => text.slice(c.diagnostics[i]!.loc.start).split(":")[0]; + expect(at(0)).toBe('"encoding"'); + expect(at(1)).toBe('"evaluate"'); + expect(at(5)).toBe('"mode"'); + for (const d of c.diagnostics) expect(d.loc.file).toBe(manifest); + // Invalid entries are not applied; valid siblings are. + expect(c.packages.has("encoding")).toBe(false); + expect(c.packages.has("debug")).toBe(false); + expect(c.nodeIslands.auto).toBe(true); +}); + +test("a non-object packages or nodeIslands value is SC8004", () => { + expect(config({ packages: ["a"] }).diagnostics.map((d) => d.message)).toEqual([ + "package.json 'scriptc.packages' must be an object mapping package names to settings, not an array", + ]); + expect(config({ nodeIslands: true }).diagnostics.map((d) => d.message)).toEqual([ + "package.json 'scriptc.nodeIslands' must be an object, not true", + ]); + // Other keys of the scriptc object belong to other readers. + expect(config({ somethingElse: 1 }).diagnostics).toEqual([]); +}); diff --git a/packages/compiler/src/project-config.ts b/packages/compiler/src/project-config.ts new file mode 100644 index 000000000..cc13a868d --- /dev/null +++ b/packages/compiler/src/project-config.ts @@ -0,0 +1,421 @@ +/* The project configuration: the `scriptc` key of the entry's nearest + * package.json. One reader for every consumer (package shims, the + * WebAssembly scanner, the Node island policy), with a schema: a value + * this compiler does not know in `scriptc.packages` or + * `scriptc.nodeIslands` is SC8004 instead of being ignored, because an + * ignored setting is a silent divergence from what the project asked for. + * + * "scriptc": { + * "packages": { + * "encoding": "unloaded", // never loaded (package-shims.ts) + * "dd-trace": "node", // run in a Node island + * "hot-shots": "native", // must compile natively (SC8003) + * "proper-lockfile": { "run": "node", "evaluate": "lazy" } + * }, + * "nodeIslands": { "auto": true, "modules": ["src/plugins/*.ts"] }, + * "wasm": ["build/module.wasm"] + * } + * + * Node islands are report-only in this version: the policy decides which + * packages and modules WOULD run in Node, and coverage reports it, but code + * generation does not change. Other keys of the `scriptc` object are left + * to their own readers. */ +import { dirname, join, resolve } from "node:path"; +import { projectConfigDiag, type ScrDiagnostic } from "./diagnostics/diagnostic.js"; +import { trackedReadFile } from "./frontend/input-tracker.js"; + +/** How a package runs: compiled natively, in a Node island, or decided by + * the detector. */ +export type PackageRun = "native" | "node" | "auto"; +export type PackageEvaluate = "auto" | "lazy" | "eager"; +export type PackageShare = "auto" | "shared" | "duplicate"; +export type PackageMarshal = "copy" | "handles"; +export type PackageSchedule = "lockstep" | "free"; + +/** One `scriptc.packages.` entry. `unloaded` packages never load; + * the other settings choose where the package runs. */ +export interface PackageSetting { + unloaded: boolean; + run: PackageRun; + evaluate: PackageEvaluate; + share: PackageShare; + marshal: PackageMarshal; + schedule: PackageSchedule; +} + +export interface NodeIslandsSetting { + /** Automatic Node islands for npm code outside the native subset. */ + auto: boolean; + /** User modules (paths or globs relative to the package.json) that run + * in Node. */ + modules: string[]; + /** The `node` executable recorded into the binary. */ + node: string | null; + /** A semver range checked at the helper handshake. */ + nodeVersion: string | null; + packaging: "embedded" | "beside"; + speculativeStart: boolean; +} + +export interface ProjectConfig { + /** The package.json the configuration came from, or null. */ + manifest: string | null; + /** Its text, for diagnostic code frames. */ + manifestText: string | null; + packages: Map; + nodeIslands: NodeIslandsSetting; + /** `scriptc.wasm`: module paths, resolved against the manifest. */ + wasm: string[]; + /** SC8004 for every unknown key or value. */ + diagnostics: ScrDiagnostic[]; +} + +const PACKAGE_STRINGS = ["unloaded", "node", "native", "auto"]; +const PACKAGE_OBJECT_KEYS: Record = { + run: ["native", "node", "auto"], + evaluate: ["auto", "lazy", "eager"], + share: ["auto", "shared", "duplicate"], + marshal: ["copy", "handles"], + schedule: ["lockstep", "free"], +}; +const NODE_ISLANDS_KEYS = [ + "auto", + "modules", + "node", + "nodeVersion", + "packaging", + "speculativeStart", +]; + +function defaultPackageSetting(): PackageSetting { + return { + unloaded: false, + run: "auto", + evaluate: "auto", + share: "auto", + marshal: "copy", + schedule: "lockstep", + }; +} + +function defaultNodeIslands(): NodeIslandsSetting { + return { + auto: true, + modules: [], + node: null, + nodeVersion: null, + packaging: "embedded", + speculativeStart: false, + }; +} + +/** The empty configuration of a project without a package.json. */ +export function emptyProjectConfig(): ProjectConfig { + return { + manifest: null, + manifestText: null, + packages: new Map(), + nodeIslands: defaultNodeIslands(), + wasm: [], + diagnostics: [], + }; +} + +function isRecord(value: unknown): value is Record { + return value !== null && typeof value === "object" && !Array.isArray(value); +} + +function quoted(values: string[]): string { + return values.map((v) => `"${v}"`).join(", "); +} + +/** A short rendering of a JSON value for a message. */ +function shown(value: unknown): string { + if (typeof value === "string") return `"${value}"`; + if (value === null) return "null"; + if (Array.isArray(value)) return "an array"; + if (typeof value === "object") return "an object"; + return String(value); +} + +/** Reads and validates one package.json text. Exported for tests. */ +export function parseProjectConfig(manifest: string, text: string): ProjectConfig { + const config = emptyProjectConfig(); + config.manifest = manifest; + config.manifestText = text; + let parsed: unknown = null; + try { + parsed = JSON.parse(text); + } catch { + // Node reports a malformed package.json itself; the configuration is + // simply absent here, as before. + return config; + } + if (!isRecord(parsed)) return config; + const root = parsed["scriptc"]; + if (!isRecord(root)) return config; + const locate = new JsonLocator(text); + const problem = (path: string[], detail: string, hint: string): void => { + config.diagnostics.push( + projectConfigDiag(`scriptc.${path.join(".")}`, detail, hint, { + file: manifest, + start: locate.offsetOf(["scriptc", ...path]), + end: locate.offsetOf(["scriptc", ...path]), + }), + ); + }; + + const packages = root["packages"]; + if (packages !== undefined) { + if (!isRecord(packages)) { + problem( + ["packages"], + `must be an object mapping package names to settings, not ${shown(packages)}`, + `write "packages": { "": "auto" }`, + ); + } else { + for (const name of Object.keys(packages)) { + const value = packages[name]; + const setting = defaultPackageSetting(); + if (typeof value === "string") { + if (!PACKAGE_STRINGS.includes(value)) { + problem( + ["packages", name], + `has the unknown value ${shown(value)}`, + `use one of ${quoted(PACKAGE_STRINGS)}, or an object with ${Object.keys(PACKAGE_OBJECT_KEYS).join(", ")}`, + ); + continue; + } + if (value === "unloaded") setting.unloaded = true; + else setting.run = value as PackageRun; + config.packages.set(name, setting); + continue; + } + if (!isRecord(value)) { + problem( + ["packages", name], + `must be a string or an object, not ${shown(value)}`, + `use one of ${quoted(PACKAGE_STRINGS)}, or an object with ${Object.keys(PACKAGE_OBJECT_KEYS).join(", ")}`, + ); + continue; + } + let valid = true; + for (const key of Object.keys(value)) { + const allowed = PACKAGE_OBJECT_KEYS[key]; + if (allowed === undefined) { + problem( + ["packages", name, key], + "is not a known package setting", + `the settings are ${Object.keys(PACKAGE_OBJECT_KEYS).join(", ")}`, + ); + valid = false; + continue; + } + const v = value[key]; + if (typeof v !== "string" || !allowed.includes(v)) { + problem( + ["packages", name, key], + `has the unknown value ${shown(v)}`, + `use one of ${quoted(allowed)}`, + ); + valid = false; + continue; + } + if (key === "run") setting.run = v as PackageRun; + else if (key === "evaluate") setting.evaluate = v as PackageEvaluate; + else if (key === "share") setting.share = v as PackageShare; + else if (key === "marshal") setting.marshal = v as PackageMarshal; + else setting.schedule = v as PackageSchedule; + } + if (valid) config.packages.set(name, setting); + } + } + } + + const islands = root["nodeIslands"]; + if (islands !== undefined) { + if (!isRecord(islands)) { + problem( + ["nodeIslands"], + `must be an object, not ${shown(islands)}`, + `write "nodeIslands": { "auto": true }`, + ); + } else { + const setting = config.nodeIslands; + for (const key of Object.keys(islands)) { + const v = islands[key]; + if (!NODE_ISLANDS_KEYS.includes(key)) { + problem( + ["nodeIslands", key], + "is not a known Node island setting", + `the settings are ${NODE_ISLANDS_KEYS.join(", ")}`, + ); + } else if (key === "auto" || key === "speculativeStart") { + if (typeof v !== "boolean") { + problem( + ["nodeIslands", key], + `must be true or false, not ${shown(v)}`, + "use a boolean", + ); + } else if (key === "auto") setting.auto = v; + else setting.speculativeStart = v; + } else if (key === "modules") { + const list: string[] = []; + let ok = Array.isArray(v); + if (Array.isArray(v)) { + for (const entry of v as unknown[]) { + if (typeof entry === "string" && entry !== "") list.push(entry); + else ok = false; + } + } + if (!ok) { + problem( + ["nodeIslands", key], + `must be an array of module paths or globs, not ${shown(v)}`, + `write "modules": ["src/plugins/loader.ts"]`, + ); + } else setting.modules = list; + } else if (key === "packaging") { + if (v !== "embedded" && v !== "beside") { + problem( + ["nodeIslands", key], + `has the unknown value ${shown(v)}`, + `use "embedded" or "beside"`, + ); + } else setting.packaging = v; + } else if (typeof v !== "string" || v === "") { + problem( + ["nodeIslands", key], + `must be a non-empty string, not ${shown(v)}`, + key === "node" + ? "give the path of the node executable" + : `write a range such as ">=24.13.1"`, + ); + } else if (key === "node") setting.node = v; + else setting.nodeVersion = v; + } + } + } + + // `scriptc.wasm` keeps its lenient reading: string entries of an array. + const wasm = root["wasm"]; + if (Array.isArray(wasm)) { + for (const entry of wasm as unknown[]) { + if (typeof entry === "string") config.wasm.push(resolve(dirname(manifest), entry)); + } + } + return config; +} + +let cachedManifest: string | null = null; +let cachedText: string | null = null; +let cachedConfig: ProjectConfig | null = null; + +/** The configuration of the entry's nearest package.json (the first one + * found walking up from the entry's directory, readable or not). */ +export function readProjectConfig(entryPath: string): ProjectConfig { + for (let dir = dirname(resolve(entryPath)); ;) { + const manifest = join(dir, "package.json"); + const text = trackedReadFile(manifest); + if (text !== null) { + if (cachedConfig !== null && cachedManifest === manifest && cachedText === text) + return cachedConfig; + const config = parseProjectConfig(manifest, text); + cachedManifest = manifest; + cachedText = text; + cachedConfig = config; + return config; + } + const parent = dirname(dir); + if (parent === dir) return emptyProjectConfig(); + dir = parent; + } +} + +/** Offsets of keys in a JSON text, for diagnostic locations. It follows + * object nesting so `["scriptc", "packages", "x"]` finds the key `"x"` + * inside `scriptc.packages`, not an earlier `"x"` elsewhere. */ +class JsonLocator { + constructor(private readonly text: string) {} + + /** The offset of the last key of `path` that could be found (0 when + * none). */ + offsetOf(path: string[]): number { + let start = 0; + let end = this.text.length; + let found = 0; + for (const key of path) { + const at = this.keyIn(key, start, end); + if (at < 0) break; + found = at; + // The key's value: from after the colon to the end of its object. + const colon = this.text.indexOf(":", at); + if (colon < 0) break; + start = colon + 1; + end = this.valueEnd(start, end); + } + return found; + } + + /** A direct key of the object starting at or after `start`. */ + private keyIn(key: string, start: number, end: number): number { + const text = this.text; + let depth = 0; + let i = start; + while (i < end) { + const ch = text.charCodeAt(i); + if (ch === 34 /* " */) { + const close = this.stringEnd(i); + if (depth === 1 && text.slice(i + 1, close) === key) { + let j = close + 1; + while (j < end && /\s/.test(text.charAt(j))) j++; + if (text.charAt(j) === ":") return i; + } + i = close + 1; + continue; + } + if (ch === 123 /* { */ || ch === 91 /* [ */) depth++; + else if (ch === 125 /* } */ || ch === 93 /* ] */) { + depth--; + if (depth <= 0) return -1; + } + i++; + } + return -1; + } + + private stringEnd(open: number): number { + const text = this.text; + let i = open + 1; + while (i < text.length) { + const ch = text.charCodeAt(i); + if (ch === 92 /* \ */) i += 2; + else if (ch === 34) return i; + else i++; + } + return text.length; + } + + /** The end of the JSON value that starts at or after `start`. */ + private valueEnd(start: number, end: number): number { + const text = this.text; + let i = start; + while (i < end && /\s/.test(text.charAt(i))) i++; + let depth = 0; + while (i < end) { + const ch = text.charCodeAt(i); + if (ch === 34) { + i = this.stringEnd(i) + 1; + if (depth === 0) return i; + continue; + } + if (ch === 123 || ch === 91) depth++; + else if (ch === 125 || ch === 93) { + depth--; + if (depth <= 0) return i + 1; + } else if (depth === 0 && ch === 44 /* , */) return i; + i++; + } + return end; + } +} diff --git a/packages/compiler/src/wasm/discover.ts b/packages/compiler/src/wasm/discover.ts index de38bf64f..3cdc3eb96 100644 --- a/packages/compiler/src/wasm/discover.ts +++ b/packages/compiler/src/wasm/discover.ts @@ -24,11 +24,8 @@ import { createHash } from "node:crypto"; import { readFileSync } from "node:fs"; import { dirname, isAbsolute, join, resolve } from "node:path"; import * as ts from "../frontend/ts7/adapter.js"; -import { - trackedAccessibleEntries, - trackedFileExists, - trackedReadFile, -} from "../frontend/input-tracker.js"; +import { trackedAccessibleEntries, trackedReadFile } from "../frontend/input-tracker.js"; +import { readProjectConfig } from "../project-config.js"; import { analyzeWasm, isWasmHeader, type WasmModuleSummary } from "./binary.js"; import { decodeBase64 } from "./base64.js"; @@ -282,24 +279,10 @@ class Discovery { // ── source 4: configuration ───────────────────────────────────────── scanConfig(): void { - const manifest = nearestPackageJson(dirname(this.input.entry)); - if (manifest !== null) { - const text = trackedReadFile(manifest); - if (text !== null) { - let listed: unknown; - try { - const parsed = JSON.parse(text) as { scriptc?: { wasm?: unknown } }; - listed = parsed.scriptc?.wasm; - } catch { - listed = undefined; - } - if (Array.isArray(listed)) { - for (const entry of listed) { - if (typeof entry === "string") { - this.addFile(resolve(dirname(manifest), entry), { kind: "config", file: manifest }); - } - } - } + const config = readProjectConfig(this.input.entry); + if (config.manifest !== null) { + for (const path of config.wasm) { + this.addFile(path, { kind: "config", file: config.manifest }); } } for (const path of this.input.configured) { @@ -396,16 +379,6 @@ function collectWasmFiles(dir: string, depth: number, out: string[]): void { } } -function nearestPackageJson(dir: string): string | null { - for (;;) { - const candidate = join(dir, "package.json"); - if (trackedFileExists(candidate)) return candidate; - const parent = dirname(dir); - if (parent === dir) return null; - dir = parent; - } -} - /** Every WebAssembly module the program's sources, packages and * configuration make visible to the build, in discovery order. */ export function discoverWasmModules(input: WasmDiscoveryInput): WasmModuleReport[] { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/node-islands-config/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/node-islands-config/main.ts.json new file mode 100644 index 000000000..6b86e7f9a --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/node-islands-config/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/diagnostics/node-islands-config/main.ts" + ], + "diags": [] +} diff --git a/tests/coverage-fixtures/node-islands-user-js.cjs b/tests/coverage-fixtures/node-islands-user-js.cjs new file mode 100644 index 000000000..c01f8c255 --- /dev/null +++ b/tests/coverage-fixtures/node-islands-user-js.cjs @@ -0,0 +1,22 @@ +// User JavaScript with one R2 construct per rule. With --strict-user-js, +// coverage reports each as the SC81xx error scope B makes it; without the +// flag the report is unchanged. +function Point(x) { + this.x = x; +} +Point.prototype.norm = function norm() { + return Math.abs(this.x); +}; +const base = { kind: "base" }; +const child = {}; +Object.setPrototypeOf(child, base); +const box = {}; +Object.defineProperty(box, "size", { value: 3, enumerable: false }); +function legacy(a) { + arguments[0] = 2; + return a; +} +Array.prototype.last = function last() { + return this[this.length - 1]; +}; +console.log(new Point(-2).norm(), child.kind, box.size, legacy(1)); diff --git a/tests/coverage-fixtures/node-islands/main.ts b/tests/coverage-fixtures/node-islands/main.ts new file mode 100644 index 000000000..ac6037d1a --- /dev/null +++ b/tests/coverage-fixtures/node-islands/main.ts @@ -0,0 +1,16 @@ +// Node islands, report-only: one npm package per island class, a package +// that runs inside an island's closure, one reached from both sides, and +// one that stays native. Coverage reports the islands a build would +// choose; the build itself is unchanged. +import { describe } from "ni-gap"; +import { compile } from "ni-eval"; +import { Counter } from "ni-ctor"; +import { shout } from "ni-minified"; +import { twice } from "ni-typed"; + +console.log(describe()); +console.log(compile("a + 1")(2)); +const counter = new Counter(); +counter.add(twice(2)); +console.log(counter.total()); +console.log(shout("hi")); diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-ctor/index.d.ts b/tests/coverage-fixtures/node-islands/node_modules/ni-ctor/index.d.ts new file mode 100644 index 000000000..2b70027a9 --- /dev/null +++ b/tests/coverage-fixtures/node-islands/node_modules/ni-ctor/index.d.ts @@ -0,0 +1,4 @@ +export declare class Counter { + add(n: number): void; + total(): number; +} diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-ctor/index.js b/tests/coverage-fixtures/node-islands/node_modules/ni-ctor/index.js new file mode 100644 index 000000000..39992107e --- /dev/null +++ b/tests/coverage-fixtures/node-islands/node_modules/ni-ctor/index.js @@ -0,0 +1,15 @@ +"use strict"; +// A constructor function with prototype methods needs a mutable object +// model (R2.1). Its helper package runs inside its island. +const { step } = require("ni-dep"); +const { twice } = require("ni-typed"); +function Counter() { + this.count = 0; +} +Counter.prototype.add = function add(n) { + this.count = step(this.count, twice(n)); +}; +Counter.prototype.total = function total() { + return this.count; +}; +exports.Counter = Counter; diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-ctor/package.json b/tests/coverage-fixtures/node-islands/node_modules/ni-ctor/package.json new file mode 100644 index 000000000..096b98d20 --- /dev/null +++ b/tests/coverage-fixtures/node-islands/node_modules/ni-ctor/package.json @@ -0,0 +1,5 @@ +{ + "name": "ni-ctor", + "version": "1.0.0", + "main": "index.js" +} diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-dep/index.js b/tests/coverage-fixtures/node-islands/node_modules/ni-dep/index.js new file mode 100644 index 000000000..71a0eec99 --- /dev/null +++ b/tests/coverage-fixtures/node-islands/node_modules/ni-dep/index.js @@ -0,0 +1,4 @@ +"use strict"; +exports.step = function step(a, b) { + return a + b; +}; diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-dep/package.json b/tests/coverage-fixtures/node-islands/node_modules/ni-dep/package.json new file mode 100644 index 000000000..24b33b1ef --- /dev/null +++ b/tests/coverage-fixtures/node-islands/node_modules/ni-dep/package.json @@ -0,0 +1,5 @@ +{ + "name": "ni-dep", + "version": "1.0.0", + "main": "index.js" +} diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-eval/index.d.ts b/tests/coverage-fixtures/node-islands/node_modules/ni-eval/index.d.ts new file mode 100644 index 000000000..4bdbf94f6 --- /dev/null +++ b/tests/coverage-fixtures/node-islands/node_modules/ni-eval/index.d.ts @@ -0,0 +1 @@ +export declare function compile(body: string): (a: number) => number; diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-eval/index.js b/tests/coverage-fixtures/node-islands/node_modules/ni-eval/index.js new file mode 100644 index 000000000..c549c058e --- /dev/null +++ b/tests/coverage-fixtures/node-islands/node_modules/ni-eval/index.js @@ -0,0 +1,5 @@ +"use strict"; +// Code from strings needs the JavaScript runtime (R1.1). +exports.compile = function compile(body) { + return new Function("a", "return " + body); +}; diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-eval/package.json b/tests/coverage-fixtures/node-islands/node_modules/ni-eval/package.json new file mode 100644 index 000000000..449239a05 --- /dev/null +++ b/tests/coverage-fixtures/node-islands/node_modules/ni-eval/package.json @@ -0,0 +1,5 @@ +{ + "name": "ni-eval", + "version": "1.0.0", + "main": "index.js" +} diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-gap/index.d.ts b/tests/coverage-fixtures/node-islands/node_modules/ni-gap/index.d.ts new file mode 100644 index 000000000..6e1b743c2 --- /dev/null +++ b/tests/coverage-fixtures/node-islands/node_modules/ni-gap/index.d.ts @@ -0,0 +1 @@ +export declare function describe(): string; diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-gap/index.js b/tests/coverage-fixtures/node-islands/node_modules/ni-gap/index.js new file mode 100644 index 000000000..2148e51fd --- /dev/null +++ b/tests/coverage-fixtures/node-islands/node_modules/ni-gap/index.js @@ -0,0 +1,8 @@ +"use strict"; +// A construct inside the native subset that scriptc does not compile yet: +// a builtin function alias used as an escaping value. +const { extname } = require("node:path"); +const ext = extname; +exports.describe = function describe() { + return typeof ext; +}; diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-gap/package.json b/tests/coverage-fixtures/node-islands/node_modules/ni-gap/package.json new file mode 100644 index 000000000..9804ad187 --- /dev/null +++ b/tests/coverage-fixtures/node-islands/node_modules/ni-gap/package.json @@ -0,0 +1,5 @@ +{ + "name": "ni-gap", + "version": "1.0.0", + "main": "index.js" +} diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-minified/index.d.ts b/tests/coverage-fixtures/node-islands/node_modules/ni-minified/index.d.ts new file mode 100644 index 000000000..ccebdab51 --- /dev/null +++ b/tests/coverage-fixtures/node-islands/node_modules/ni-minified/index.d.ts @@ -0,0 +1 @@ +export declare function shout(s: string): string; diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-minified/index.js b/tests/coverage-fixtures/node-islands/node_modules/ni-minified/index.js new file mode 100644 index 000000000..25c0e11ac --- /dev/null +++ b/tests/coverage-fixtures/node-islands/node_modules/ni-minified/index.js @@ -0,0 +1 @@ +"use strict";exports.shout=function shout(s){return s.toUpperCase()+"!"}; \ No newline at end of file diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-minified/package.json b/tests/coverage-fixtures/node-islands/node_modules/ni-minified/package.json new file mode 100644 index 000000000..cc819dfc8 --- /dev/null +++ b/tests/coverage-fixtures/node-islands/node_modules/ni-minified/package.json @@ -0,0 +1,5 @@ +{ + "name": "ni-minified", + "version": "1.0.0", + "main": "index.js" +} diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-typed/index.d.ts b/tests/coverage-fixtures/node-islands/node_modules/ni-typed/index.d.ts new file mode 100644 index 000000000..bb1a852b1 --- /dev/null +++ b/tests/coverage-fixtures/node-islands/node_modules/ni-typed/index.d.ts @@ -0,0 +1 @@ +export declare function twice(n: number): number; diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-typed/index.js b/tests/coverage-fixtures/node-islands/node_modules/ni-typed/index.js new file mode 100644 index 000000000..082402bfd --- /dev/null +++ b/tests/coverage-fixtures/node-islands/node_modules/ni-typed/index.js @@ -0,0 +1,4 @@ +"use strict"; +exports.twice = function twice(n) { + return n * 2; +}; diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-typed/package.json b/tests/coverage-fixtures/node-islands/node_modules/ni-typed/package.json new file mode 100644 index 000000000..c3048156c --- /dev/null +++ b/tests/coverage-fixtures/node-islands/node_modules/ni-typed/package.json @@ -0,0 +1,5 @@ +{ + "name": "ni-typed", + "version": "1.0.0", + "main": "index.js" +} diff --git a/tests/coverage-fixtures/node-islands/package.json b/tests/coverage-fixtures/node-islands/package.json new file mode 100644 index 000000000..f18eb6012 --- /dev/null +++ b/tests/coverage-fixtures/node-islands/package.json @@ -0,0 +1,5 @@ +{ + "name": "node-islands-coverage-fixture", + "private": true, + "type": "module" +} diff --git a/tests/diagnostics/node-islands-config/main.ts b/tests/diagnostics/node-islands-config/main.ts new file mode 100644 index 000000000..cc7b3735f --- /dev/null +++ b/tests/diagnostics/node-islands-config/main.ts @@ -0,0 +1,3 @@ +// An unknown value in scriptc.packages or scriptc.nodeIslands is SC8004: +// the configuration the project asked for is never silently ignored. +console.log("configured"); diff --git a/tests/diagnostics/node-islands-config/package.json b/tests/diagnostics/node-islands-config/package.json new file mode 100644 index 000000000..1a01afa30 --- /dev/null +++ b/tests/diagnostics/node-islands-config/package.json @@ -0,0 +1,14 @@ +{ + "private": true, + "type": "module", + "scriptc": { + "packages": { + "encoding": "unloded", + "debug": { "run": "island" } + }, + "nodeIslands": { + "auto": "yes", + "mode": "auto" + } + } +} diff --git a/tests/harness/__snapshots__/coverage-node-islands-explain.txt b/tests/harness/__snapshots__/coverage-node-islands-explain.txt new file mode 100644 index 000000000..f416b9781 --- /dev/null +++ b/tests/harness/__snapshots__/coverage-node-islands-explain.txt @@ -0,0 +1,13 @@ + Node island ni-ctor@1.0.0 (would-be, report-only) + path tests/coverage-fixtures/node-islands/node_modules/ni-ctor + class object-model: needs a mutable object model + decision automatic (npm code outside the native subset) + evaluation eager at its module position (deferred evaluation is decided by a later milestone) + reasons (first per module; decisive class first) + object-model tests/coverage-fixtures/node-islands/node_modules/ni-ctor/index.js:9:1 + R2.1 constructor functions: a write of 'Counter.prototype.add' + all reasons 2 (2 object-model) + boundary 1 native import site: + tests/coverage-fixtures/node-islands/main.ts:7:1 + copy and handle decisions per boundary site come with compiler-managed islands + carries ni-dep \ No newline at end of file diff --git a/tests/harness/__snapshots__/coverage-node-islands-user-js.txt b/tests/harness/__snapshots__/coverage-node-islands-user-js.txt new file mode 100644 index 000000000..61cb8bb33 --- /dev/null +++ b/tests/harness/__snapshots__/coverage-node-islands-user-js.txt @@ -0,0 +1,34 @@ +scriptc coverage tests/coverage-fixtures/node-islands-user-js.cjs + + statements analyzed 13 + compile statically 10 (76%) + in dynamic tier 10 (operate on values typed only at runtime; --explain-dynamic lists them) + (1 function not analyzed — signature blocked; their statements count as not static) + + deferred to runtime 2 sites (JS statements that throw their fence if executed) + ×1 SC1090 parameterized 'arguments' outside an ES module (sloppy-mode parameter aliases) + at tests/coverage-fixtures/node-islands-user-js.cjs:15:1 + hint: this form is valid TypeScript but does not compile yet — rewrite it with a supported equivalent of the construct the message names (https://scriptc.dev/limitations lists the boundary) + ×1 SC2004 uses of 'legacy' inherit the blocker on its declaration + at tests/coverage-fixtures/node-islands-user-js.cjs:22:57 + hint: the declaration of 'legacy' did not compile — fix the diagnostic reported there and these sites clear with it + + blockers: + ×1 SC8101 A write of 'Point.prototype.norm' needs a mutable JavaScript object model, which native code does not have + at tests/coverage-fixtures/node-islands-user-js.cjs:7:1 + hint: rewrite it as a class or typed object, or mark this module as a Node island in scriptc.nodeIslands.modules + ×1 SC8101 'new Point()' of a function needs a mutable JavaScript object model, which native code does not have + at tests/coverage-fixtures/node-islands-user-js.cjs:22:13 + hint: rewrite it as a class or typed object, or mark this module as a Node island in scriptc.nodeIslands.modules + ×1 SC8102 'Object.setPrototypeOf()' needs a mutable JavaScript object model, which native code does not have + at tests/coverage-fixtures/node-islands-user-js.cjs:12:1 + hint: rewrite it as a class or typed object, or mark this module as a Node island in scriptc.nodeIslands.modules + ×1 SC8103 'Object.defineProperty()' needs a mutable JavaScript object model, which native code does not have + at tests/coverage-fixtures/node-islands-user-js.cjs:14:1 + hint: rewrite it as a class or typed object, or mark this module as a Node island in scriptc.nodeIslands.modules + ×1 SC8104 A write to 'arguments[i]' in sloppy mode needs a mutable JavaScript object model, which native code does not have + at tests/coverage-fixtures/node-islands-user-js.cjs:16:3 + hint: rewrite it as a class or typed object, or mark this module as a Node island in scriptc.nodeIslands.modules + ×1 SC8105 A write of 'Array.prototype.last' needs a mutable JavaScript object model, which native code does not have + at tests/coverage-fixtures/node-islands-user-js.cjs:19:1 + hint: rewrite it as a class or typed object, or mark this module as a Node island in scriptc.nodeIslands.modules \ No newline at end of file diff --git a/tests/harness/__snapshots__/coverage-node-islands.txt b/tests/harness/__snapshots__/coverage-node-islands.txt new file mode 100644 index 000000000..e8876bb0d --- /dev/null +++ b/tests/harness/__snapshots__/coverage-node-islands.txt @@ -0,0 +1,39 @@ +scriptc coverage tests/coverage-fixtures/node-islands/main.ts + + statements analyzed 29 + compile statically 27 (93%) + in dynamic tier 17 (operate on values typed only at runtime; --explain-dynamic lists them) + + npm package compilation: + ni-minified refused (its shipped JS looks minified) + ni-gap static + ni-eval static + ni-ctor static + ni-typed static + ni-dep static + + Node islands (would-be, report-only: the build is unchanged; --node-islands=auto) + gap ni-gap@1.0.0 + tests/coverage-fixtures/node-islands/node_modules/ni-gap/index.js:7:17: SC1090: a builtin function alias as an escaping value (call 'ext' directly) is not supported yet + runtime ni-eval@1.0.0 + tests/coverage-fixtures/node-islands/node_modules/ni-eval/index.js:4:10: R1.1 code from strings: new Function() + object-model ni-ctor@1.0.0 + tests/coverage-fixtures/node-islands/node_modules/ni-ctor/index.js:9:1: R2.1 constructor functions: a write of 'Counter.prototype.add' + +1 more reason in 1 module; carries ni-dep + packaging ni-minified@1.0.0 + SC2013: its shipped JS looks minified + reached from native code and from an island: ni-typed + hint: scriptc coverage --explain-island= lists every reason + + deferred to runtime 1 site (JS statements that throw their fence if executed) + ×1 SC1090 a builtin function alias as an escaping value (call 'ext' directly) + at tests/coverage-fixtures/node-islands/node_modules/ni-gap/index.js:7:17 + hint: this form is valid TypeScript but does not compile yet — rewrite it with a supported equivalent of the construct the message names (https://scriptc.dev/limitations lists the boundary) + + blockers: + ×2 SC2013 cannot compile npm package 'ni-minified' statically: its implementation is not part of the compiled module graph + at tests/coverage-fixtures/node-islands/main.ts:8:1, tests/coverage-fixtures/node-islands/main.ts:16:13 + hint: use a dependency with supported source, or replace the unsupported operation; scriptc has no interpreter fallback + ×1 SC2013 cannot compile npm package 'ni-minified' statically: its shipped JS looks minified + at tests/coverage-fixtures/node-islands/main.ts:8:1 + hint: to compile it anyway, name it with --npm-static=ni-minified (or --npm-static=ni-minified... to include its dependencies) \ No newline at end of file diff --git a/tests/harness/__snapshots__/node-islands-config/main.ts.txt b/tests/harness/__snapshots__/node-islands-config/main.ts.txt new file mode 100644 index 000000000..03cc714aa --- /dev/null +++ b/tests/harness/__snapshots__/node-islands-config/main.ts.txt @@ -0,0 +1,35 @@ +node-islands-config/package.json:6:7 - error SC8004: package.json 'scriptc.packages.encoding' has the unknown value "unloded" + + 5 | "packages": { + 6 | "encoding": "unloded", + | ^ + 7 | "debug": { "run": "island" } + + hint: use one of "unloaded", "node", "native", "auto", or an object with run, evaluate, share, marshal, schedule + +node-islands-config/package.json:7:18 - error SC8004: package.json 'scriptc.packages.debug.run' has the unknown value "island" + + 6 | "encoding": "unloded", + 7 | "debug": { "run": "island" } + | ^ + 8 | }, + + hint: use one of "native", "node", "auto" + +node-islands-config/package.json:10:7 - error SC8004: package.json 'scriptc.nodeIslands.auto' must be true or false, not "yes" + + 9 | "nodeIslands": { + 10 | "auto": "yes", + | ^ + 11 | "mode": "auto" + + hint: use a boolean + +node-islands-config/package.json:11:7 - error SC8004: package.json 'scriptc.nodeIslands.mode' is not a known Node island setting + + 10 | "auto": "yes", + 11 | "mode": "auto" + | ^ + 12 | } + + hint: the settings are auto, modules, node, nodeVersion, packaging, speculativeStart \ No newline at end of file diff --git a/tests/harness/coverage.test.ts b/tests/harness/coverage.test.ts index cc91c0922..954294821 100644 --- a/tests/harness/coverage.test.ts +++ b/tests/harness/coverage.test.ts @@ -9,6 +9,7 @@ import { coveragePasses, renderCoverage, renderExplainDynamic, + renderExplainIsland, } from "@scriptc/compiler"; import { shardSelect, shardSuffix } from "./shard.js"; @@ -704,6 +705,92 @@ test("a cycle whose top level calls a builtin with a builtin function value is a expect(out).toContain("statements analyzed"); }); +test("Node islands (report-only): one package per class, gap islands first", async () => { + // ni-gap (a fence inside the native subset), ni-eval (new Function), + // ni-ctor (a constructor function, carrying ni-dep), ni-minified (not + // compilable as shipped), ni-typed (native, also reached from ni-ctor). + const entry = fixture("node-islands/main.ts"); + await expect(report(entry)).toMatchFileSnapshot("__snapshots__/coverage-node-islands.txt"); + const { coverage, sourceTexts } = analyze(entry); + const islands = coverage.nodeIslands!; + expect(islands.islands.map((i) => [i.package, i.class])).toEqual([ + ["ni-gap", "gap"], + ["ni-eval", "runtime"], + ["ni-ctor", "object-model"], + ["ni-minified", "packaging"], + ]); + expect(islands.packages.map((p) => [p.package, p.status, p.islands])).toEqual([ + ["ni-dep", "inside", ["ni-ctor"]], + ["ni-typed", "shared", ["ni-ctor"]], + ]); + await expect( + renderExplainIsland(coverage.nodeIslands, "ni-ctor", { sourceTexts, root: repoRoot }), + ).toMatchFileSnapshot("__snapshots__/coverage-node-islands-explain.txt"); + expect(renderExplainIsland(coverage.nodeIslands, "ni-dep", { root: repoRoot })).toContain( + "only ni-ctor imports it", + ); + // The machine-readable form carries the same decisions. + const envelope = coverageEnvelope(coverage, { compilerVersion: "test", sourceTexts }); + expect(envelope.nodeIslands?.mode).toBe("would-be"); + expect(envelope.nodeIslands?.islands.map((i) => [i.package, i.class, i.at?.line])).toEqual([ + ["ni-gap", "gap", 7], + ["ni-eval", "runtime", 4], + ["ni-ctor", "object-model", 9], + ["ni-minified", "packaging", undefined], + ]); + // The gates: the blocker gate is today's build (which refuses + // ni-minified with SC2013, and nothing else); the island gates fail on + // the would-be islands. + expect(coverage.diagnostics.every((d) => d.code === "SC2013")).toBe(true); + expect(coveragePasses(coverage, "island-gaps")).toBe(false); + expect(coveragePasses(coverage, "node-islands")).toBe(false); +}); + +test("Node island policy from the command line: native, forced, off", () => { + const entry = fixture("node-islands/main.ts"); + const forced = analyze(entry, { + nodeIslands: { native: ["ni-eval"], islands: ["ni-typed", "not-a-dependency"] }, + }).coverage.nodeIslands!; + expect(forced.islands.map((i) => [i.package, i.class, i.decision])).toEqual([ + ["ni-gap", "gap", "auto"], + ["ni-ctor", "object-model", "auto"], + ["ni-minified", "packaging", "auto"], + ["ni-typed", "marked", "cli"], + ]); + expect(forced.violations.map((v) => v.code)).toEqual(["SC8003"]); + expect(forced.unknownPackages).toEqual(["not-a-dependency"]); + const off = analyze(entry, { nodeIslands: { mode: "off" } }).coverage; + expect(off.nodeIslands!.islands).toEqual([]); + expect(off.nodeIslands!.violations.map((v) => v.code)).toEqual([ + "SC8002", + "SC8002", + "SC8002", + "SC8002", + ]); + expect(coveragePasses(off, "island-gaps")).toBe(false); +}); + +test("--strict-user-js reports R2 constructs in user JavaScript as SC8101–SC8105", async () => { + const entry = fixture("node-islands-user-js.cjs"); + // Without the flag the user module is not part of any island report. + expect(analyze(entry).coverage.nodeIslands).toBeUndefined(); + const { coverage } = analyze(entry, { nodeIslands: { strictUserJs: true } }); + expect(coverage.diagnostics.map((d) => d.code).filter((c) => c.startsWith("SC81"))).toEqual([ + "SC8101", + "SC8102", + "SC8103", + "SC8104", + "SC8105", + "SC8101", + ]); + await expect( + renderCoverage( + { ...coverage, file: coverage.file.replace(repoRoot + "/", "") }, + { root: repoRoot }, + ), + ).toMatchFileSnapshot("__snapshots__/coverage-node-islands-user-js.txt"); +}); + test(`every corpus program is 100% static (corpus and coverage agree${shardSuffix()})`, async () => { // The differential corpus compiles by definition; coverage must agree. From 84cf0ec19fd9288034678b8ce9aa5c09fcdba916 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 10:54:02 -0500 Subject: [PATCH 002/259] Inspect dynamic classes, functions and %o arguments as Node does - The inspector throws the 'not supported yet' Error for checked-dynamic values it does not render (a promise, a URL, a RegExp reached through `unknown`). Its calls were not marked as throwing, so `console.log("x", p)` printed "x " and the program went on; records and arrays with such a field printed `{ a: }` and `[ ]`. insp.dyn and insp.dynS are now may-throw library calls, so the Error propagates from the call that inspects the value, before anything is written. - A class reached through `unknown` prints `[class C]`, `[class C extends B]` or `[class (anonymous)]` instead of `[Function: C]`. Functions and classes reached as dynamic values print their enumerable own properties (`[Function: f] { x: 1 }`, `[class S extends A] { count: 3 }`), cycles through them as `[Circular *N]`, and `[Function]` past the depth limit. Class objects carry their base class's name. A compiled class's static fields are module globals that the class object does not carry, so inspecting a class that declares static fields through `unknown` throws the 'not supported yet' Error. - util.format's %o renders a checked-dynamic argument with showHidden: an array's `[length]` entry and an object's non-enumerable own properties, string- and symbol-keyed, in brackets. An array with more than 100 output entries keeps the last one out of the grid, as Node's groupArrayElements does. %o of a function, an Error, a typed array or a native handle other than Map, Set and Date throws the 'not supported yet' Error. ScrClassObj has two new fields, so RUNTIME_ABI_VERSION is now 27. --- packages/compiler/src/backend/llvm/classes.ts | 10 +- .../compiler/src/backend/llvm/emit-module.ts | 2 +- packages/compiler/src/backend/llvm/emitter.ts | 9 +- packages/compiler/src/backend/llvm/layouts.ts | 2 +- .../compiler/src/backend/llvm/lib-shared.ts | 1 + .../src/frontend/lowering/lower-classes.ts | 8 + .../src/frontend/lowering/lower-console.ts | 3 +- .../src/frontend/lowering/lower-inspect.ts | 32 ++- packages/compiler/src/ir/builtin-effects.ts | 7 + .../compiler/src/ir/builtin-signatures.ts | 4 + packages/compiler/src/ir/int32-slots.test.ts | 1 + packages/compiler/src/ir/int32-slots.ts | 1 + packages/compiler/src/ir/ir.ts | 4 + .../corpus/6343-inspect-class-values.ts.json | 6 + .../6344-inspect-function-properties.cjs.json | 6 + .../tests/corpus/6357-format-o-hidden.ts.json | 6 + .../corpus/6358-format-o-hidden-js.cjs.json | 6 + packages/runtime/src/scr_error.h | 6 + packages/runtime/src/scr_inspect.c | 187 +++++++++++++++--- packages/runtime/src/scr_inspect.h | 1 + packages/runtime/src/scr_object.c | 2 + tests/corpus/6343-inspect-class-values.ts | 31 +++ .../6344-inspect-function-properties.cjs | 34 ++++ tests/corpus/6357-format-o-hidden.ts | 19 ++ tests/corpus/6358-format-o-hidden-js.cjs | 9 + tests/fixtures/self-hosting/llvm-layouts.ts | 3 +- .../6343-inspect-class-values.ts.json | 1 + .../6344-inspect-function-properties.cjs.json | 1 + .../corpus-costs/6357-format-o-hidden.ts.json | 1 + .../6358-format-o-hidden-js.cjs.json | 1 + tests/harness/dyncheck.test.ts | 88 +++++++++ 31 files changed, 447 insertions(+), 45 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6343-inspect-class-values.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6344-inspect-function-properties.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6357-format-o-hidden.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6358-format-o-hidden-js.cjs.json create mode 100644 tests/corpus/6343-inspect-class-values.ts create mode 100644 tests/corpus/6344-inspect-function-properties.cjs create mode 100644 tests/corpus/6357-format-o-hidden.ts create mode 100644 tests/corpus/6358-format-o-hidden-js.cjs create mode 100644 tests/harness/corpus-costs/6343-inspect-class-values.ts.json create mode 100644 tests/harness/corpus-costs/6344-inspect-function-properties.cjs.json create mode 100644 tests/harness/corpus-costs/6357-format-o-hidden.ts.json create mode 100644 tests/harness/corpus-costs/6358-format-o-hidden-js.cjs.json diff --git a/packages/compiler/src/backend/llvm/classes.ts b/packages/compiler/src/backend/llvm/classes.ts index 3073bd1bd..8b20ec264 100644 --- a/packages/compiler/src/backend/llvm/classes.ts +++ b/packages/compiler/src/backend/llvm/classes.ts @@ -1363,18 +1363,18 @@ export function emitClassShapes( * statics plus their construct thunks — allocate, run the constructor over * a +1 `this`, and hand the remaining +1 out. No pending check is needed: * in-tier constructors are throw-free by construction. - * `classObjs` maps className → { nameSym } registered during body emission - * (the literal interned while the table was open). */ + * `classObjs` maps className → { nameSym, baseNameSym } registered during + * body emission (the literals interned while the table was open). */ export function emitClassObjDefs( host: ClassHost, metaMap: Map, - classObjs: Map, + classObjs: Map, fnByName: Map, llType: (t: IrType) => string, threadLocal = false, ): string[] { const out: string[] = []; - for (const [className, { nameSym }] of classObjs) { + for (const [className, { nameSym, baseNameSym }] of classObjs) { const meta = metaMap.get(className); if (!meta) throw new InternalCompilerError( @@ -1400,7 +1400,7 @@ export function emitClassObjDefs( const ctorArgs = params.map((p, i) => `${llType(p.type)} %a${i}`); const classObj = `@${mangleClassObj(className)} = internal ${threadLocal ? "thread_local " : ""}global %ScrClassObj ` + - `{ ${host.sizeType} -1, ${host.sizeType} ${intervalMeta.pre}, ${host.sizeType} ${intervalMeta.post}, ptr @${mangleCtorThunk(className)}, ptr ${nameSym}, ${host.sizeType} 0, ${host.sizeType} ${meta.def.jsLength ?? (meta.def.runtime ? 1 : 0)}, ptr null, ptr null } ; class ${className}`; + `{ ${host.sizeType} -1, ${host.sizeType} ${intervalMeta.pre}, ${host.sizeType} ${intervalMeta.post}, ptr @${mangleCtorThunk(className)}, ptr ${nameSym}, ${host.sizeType} 0, ${host.sizeType} ${meta.def.jsLength ?? (meta.def.runtime ? 1 : 0)}, ptr null, ptr null, ptr ${baseNameSym ?? "null"}, ${host.sizeType} ${meta.def.ownStaticFields ? 1 : 0} } ; class ${className}`; if (meta.def.runtime) { // A runtime-provided class: %C.construct allocates through the // runtime and returns the instance. diff --git a/packages/compiler/src/backend/llvm/emit-module.ts b/packages/compiler/src/backend/llvm/emit-module.ts index 3d9d41072..8da4bb140 100644 --- a/packages/compiler/src/backend/llvm/emit-module.ts +++ b/packages/compiler/src/backend/llvm/emit-module.ts @@ -483,7 +483,7 @@ export function emitModuleParts(emitter: LlEmitter): string[] { // class-object shape { rc, pre, post, ctor, name } — field reads on // builtin errors and classval loads GEP through these. `%ScrError = type { ${emitter.sizeType}, ptr, ptr, ptr, ptr, ptr, i8, i8, i8, i8, i8, ptr, ptr }`, - `%ScrClassObj = type { ${emitter.sizeType}, ${emitter.sizeType}, ${emitter.sizeType}, ptr, ptr, ${emitter.sizeType}, ${emitter.sizeType}, ptr, ptr }`, + `%ScrClassObj = type { ${emitter.sizeType}, ${emitter.sizeType}, ${emitter.sizeType}, ptr, ptr, ${emitter.sizeType}, ${emitter.sizeType}, ptr, ptr, ptr, ${emitter.sizeType} }`, // The runtime emitter prefix { rc, vt, reg, cls } — user subclasses // embed it (classes.ts), and bare-emitter GEPs address through it. `%ScrEmitter = type { ${emitter.sizeType}, ptr, ptr, ptr }`, diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index bfde59a30..0b4ce184a 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -1000,7 +1000,7 @@ export class LlEmitter { /** Class objects (classes as first-class values): className → the * interned .name literal ref — registered during body emission, the * statics and construct thunks assemble around the bodies. */ - readonly classObjs = new Map(); + readonly classObjs = new Map(); private readonly unionFieldReadGroups = new Map(); /** Preorder intervals of the runtime error classes under THIS module's * class-forest numbering (main() stamps scr_error_vts with them, exactly @@ -3638,7 +3638,12 @@ export class LlEmitter { classObjSym(className: string): string { if (!this.classObjs.has(className)) { const meta = this.classMetaOf(className); - this.classObjs.set(className, { nameSym: this.internLiteral(classJsName(meta.def)) }); + // util.inspect prints `[class C extends B]` with the base's name. + const baseName = meta.base ? classJsName(meta.base.def) : ""; + this.classObjs.set(className, { + nameSym: this.internLiteral(classJsName(meta.def)), + baseNameSym: baseName ? this.internLiteral(baseName) : null, + }); } return mangleClassObj(className); } diff --git a/packages/compiler/src/backend/llvm/layouts.ts b/packages/compiler/src/backend/llvm/layouts.ts index 8e1f0a4c1..5c426e910 100644 --- a/packages/compiler/src/backend/llvm/layouts.ts +++ b/packages/compiler/src/backend/llvm/layouts.ts @@ -17,7 +17,7 @@ export function emitLlvmLayouts( host: ClassHost, mod: IrModule, classes: Map, - classObjects: Map, + classObjects: Map, functions: Map, llType: (type: IrType) => string, nullable?: NullableRefFields, diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 9a65d9a24..be6595658 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -1029,6 +1029,7 @@ export const LIB_FN_SYMS: Record = { "dyn.generatorThis": "scr_gen_receiver", "insp.dyn": "scr_insp_dyn", "insp.dynS": "scr_insp_dyn_s", + "insp.dynHidden": "scr_insp_dyn_hidden", "fs.readFileSyncDyn": "scr_fs_read_file_sync_dyn", "fs.readFileEncoded": "scr_fs_read_file_encoded", "fs.readFdEncoded": "scr_fs_read_fd_encoded", diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index d8ccc15b7..3c294bb66 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -4395,6 +4395,14 @@ export function collectClassShapeInner( // INSTANTIATION prints its family's name — JS has one `Box`. jsName: jsNameOverride ?? decl.name?.text ?? "", ...(base ? { base: base.def.name } : {}), + ...(decl.members.nodes.some( + (member) => + ts.isPropertyDeclaration(member) && + !ts.isPrivateIdentifier(member.name) && + member.modifiers?.nodes.some((m) => m.kind === ts.SyntaxKind.StaticKeyword), + ) + ? { ownStaticFields: true as const } + : {}), jsLength: ctor?.parameters?.nodes.findIndex( (parameter) => parameter.initializer || parameter.dotDotDotToken, diff --git a/packages/compiler/src/frontend/lowering/lower-console.ts b/packages/compiler/src/frontend/lowering/lower-console.ts index eec308342..b45218bd0 100644 --- a/packages/compiler/src/frontend/lowering/lower-console.ts +++ b/packages/compiler/src/frontend/lowering/lower-console.ts @@ -249,7 +249,8 @@ export function lowerConsoleArg( // inspect at the rest-args depth 2 (formatWithOptions) — scalar // kinds byte-exactly, boxed functions as [Function: name] / // [Function (anonymous)], composites through the dyn walk - // (insp.dyn). Never throws — Node's console.log never does. + // (insp.dyn). A value the inspector does not render throws the + // 'not supported yet' Error before anything is written. if (lowered.type.kind === "dyn") { return { kind: "libCall", diff --git a/packages/compiler/src/frontend/lowering/lower-inspect.ts b/packages/compiler/src/frontend/lowering/lower-inspect.ts index 47f490c7b..71a7ea327 100644 --- a/packages/compiler/src/frontend/lowering/lower-inspect.ts +++ b/packages/compiler/src/frontend/lowering/lower-inspect.ts @@ -2607,10 +2607,21 @@ function formatSArg(lowerer: Lowerer, node: ts.Expression, depth: number, loc: S } /** %O (depth 2) / %o (showHidden, depth 4) — inspect with the spec's - * option deltas; %o fences over arrays (showHidden adds their hidden - * [length] entry, which has no lowering). */ + * option deltas. A checked-dynamic argument renders through the runtime's + * showHidden walk; static %o fences over arrays and nested dynamic values + * (showHidden adds an array's hidden [length] entry, which the static + * rendering has no lowering for). */ function formatOArg(lowerer: Lowerer, node: ts.Expression, depth: number, loc: SrcLoc): IrExpr { const value = lowerer.lowerExpr(node); + if (depth === 4 && value.type.kind === "dyn") { + return { + kind: "libCall", + fn: "insp.dynHidden", + args: [value, numLit(4, loc)], + type: STRING, + loc, + }; + } if (value.type.kind === "bytes") { lowerer.noLowering( `util.format %${depth === 4 ? "o" : "O"} of typed-array values`, @@ -2626,11 +2637,11 @@ function formatOArg(lowerer: Lowerer, node: ts.Expression, depth: number, loc: S node, reason, ); - if (depth === 4 && typeTreeHasArray(lowerer, value.type, new Set())) { + if (depth === 4 && typeTreeHasHidden(lowerer, value.type, new Set())) { lowerer.noLowering( "util.format %o over arrays", node, - "%o renders with showHidden (arrays gain a hidden [length] entry) — use %O for the default rendering", + "%o renders with showHidden (arrays gain a hidden [length] entry) — use %O for the default rendering, or pass the value as unknown", ); } return inspectExpr(lowerer, value.type, value, numLit(0, loc), numLit(depth, loc), loc); @@ -3031,35 +3042,36 @@ export function lowerFormatCall( } /** Arrays anywhere in the tree — the %o (showHidden) gate. */ -function typeTreeHasArray(lowerer: Lowerer, t: IrType, visiting: Set): boolean { +function typeTreeHasHidden(lowerer: Lowerer, t: IrType, visiting: Set): boolean { switch (t.kind) { case "array": + case "dyn": return true; case "record": { if (visiting.has(t.shapeId)) return false; visiting.add(t.shapeId); const shape = lowerer.shapes.get(t.shapeId); if (shape?.tuple) return true; - return (shape?.fields ?? []).some((f) => typeTreeHasArray(lowerer, f.type, visiting)); + return (shape?.fields ?? []).some((f) => typeTreeHasHidden(lowerer, f.type, visiting)); } case "map": return ( - typeTreeHasArray(lowerer, t.key, visiting) || typeTreeHasArray(lowerer, t.value, visiting) + typeTreeHasHidden(lowerer, t.key, visiting) || typeTreeHasHidden(lowerer, t.value, visiting) ); case "set": - return typeTreeHasArray(lowerer, t.elem, visiting); + return typeTreeHasHidden(lowerer, t.elem, visiting); case "union": { if (visiting.has(t.unionId)) return false; visiting.add(t.unionId); return (lowerer.unions.get(t.unionId)?.arms ?? []).some((a) => - typeTreeHasArray(lowerer, a, visiting), + typeTreeHasHidden(lowerer, a, visiting), ); } case "object": { if (visiting.has(t.className)) return false; visiting.add(t.className); return (lowerer.classes.get(t.className)?.def.fields ?? []).some((f) => - typeTreeHasArray(lowerer, f.type, visiting), + typeTreeHasHidden(lowerer, f.type, visiting), ); } case "bytes": diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index 16db45b6c..229fd8c28 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -174,6 +174,13 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "num.toStringRadix", "num.toStringRadixF64", "insp.jsonDyn", + // A checked-dynamic value the inspector does not render (a promise, a + // URL, a RegExp) throws the 'not supported yet' Error. + "insp.dyn", + "insp.dynS", + // %o's showHidden walk refuses the kinds whose hidden entries it cannot + // render. + "insp.dynHidden", // diagnostics_channel: publish runs subscribers synchronously (a throw // propagates — the documented divergence from triggerUncaughtException); // the subscribe/unsubscribe forms throw Node's ERR_INVALID_ARG_TYPE for diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index fcdbe8694..9f224c72a 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -4290,6 +4290,10 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "insp.errorCause": { argTypes: [null, F64, F64], result: STRING }, "insp.dyn": { argTypes: [DYN, F64, F64], result: STRING }, "insp.dynS": { argTypes: [DYN, F64], result: STRING }, + /** util.format's %o over a checked-dynamic value: inspect with + * showHidden. Kinds whose hidden entries have no rendering throw the + * 'not supported yet' Error. */ + "insp.dynHidden": { argTypes: [DYN, F64], result: STRING }, "insp.begin": { argTypes: [F64], result: VOID }, /** util.inspect's breakLength, compact (0 for false) and sorted for the * renders that follow; the call site restores 80, 3 and false afterwards. */ diff --git a/packages/compiler/src/ir/int32-slots.test.ts b/packages/compiler/src/ir/int32-slots.test.ts index be933ab38..f64e2de1f 100644 --- a/packages/compiler/src/ir/int32-slots.test.ts +++ b/packages/compiler/src/ir/int32-slots.test.ts @@ -281,6 +281,7 @@ test("dynamic stores disqualify the field names they can reach", () => { "dyn.typeof", "insp.dyn", "insp.dynS", + "insp.dynHidden", "dyn.objCreate", "dyn.getPrototype", "dyn.nameClassPrototype", diff --git a/packages/compiler/src/ir/int32-slots.ts b/packages/compiler/src/ir/int32-slots.ts index 21223862a..221692e3f 100644 --- a/packages/compiler/src/ir/int32-slots.ts +++ b/packages/compiler/src/ir/int32-slots.ts @@ -407,6 +407,7 @@ const DYN_READ_ONLY = new Set([ "fs.utimesSync", "insp.dyn", "insp.dynS", + "insp.dynHidden", // The dynamic-tier operators run their dyn twins (scr_js_value.c); the // conversions move a value between dyn and jsval, and js.toF64 is // dynCheck's number check. diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index 4a395feb2..5852eb8a6 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -1432,6 +1432,10 @@ export interface IrClassDef { jsName?: string; /** JavaScript constructor arity, ending before the first default or rest parameter. */ jsLength?: number; + /** The class declares public static fields. util.inspect prints them + * after the class tag; a class object reached through `unknown` does + * not carry them unless the runtime holds its static table. */ + ownStaticFields?: true; /** Zero-argument native helper returning the shared prototype data object. * Used when materializing an instance's own-property view. */ prototypeDataHelper?: string; diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6343-inspect-class-values.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6343-inspect-class-values.ts.json new file mode 100644 index 000000000..4fa8625ac --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6343-inspect-class-values.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6343-inspect-class-values.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6344-inspect-function-properties.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6344-inspect-function-properties.cjs.json new file mode 100644 index 000000000..003075140 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6344-inspect-function-properties.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6344-inspect-function-properties.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6357-format-o-hidden.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6357-format-o-hidden.ts.json new file mode 100644 index 000000000..cf0cd31d1 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6357-format-o-hidden.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6357-format-o-hidden.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6358-format-o-hidden-js.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6358-format-o-hidden-js.cjs.json new file mode 100644 index 000000000..73d4eefa6 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6358-format-o-hidden-js.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6358-format-o-hidden-js.cjs" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_error.h b/packages/runtime/src/scr_error.h index a7c921f23..17d217cdc 100644 --- a/packages/runtime/src/scr_error.h +++ b/packages/runtime/src/scr_error.h @@ -48,6 +48,12 @@ typedef struct ScrClassObj { size_t length; struct ScrBox *prototype_data; struct ScrBox *static_data; + /* The base class's name, which util.inspect prints as + * `[class C extends B]`; NULL without a named base. */ + const ScrStr *base_name; + /* Nonzero when the class declares public static fields, which the + * class object does not carry without static_data. */ + size_t own_static_fields; struct ScrBox *caps[]; } ScrClassObj; diff --git a/packages/runtime/src/scr_inspect.c b/packages/runtime/src/scr_inspect.c index a4d124ac3..214648802 100644 --- a/packages/runtime/src/scr_inspect.c +++ b/packages/runtime/src/scr_inspect.c @@ -324,6 +324,9 @@ typedef struct { static SCR_TL InspSeenEnt *g_seen; static SCR_TL size_t g_nseen; +/* util.format's %o (scr_insp_dyn_hidden): this render shows hidden own + * properties, like util.inspect's showHidden. */ +static SCR_TL bool g_show_hidden; static SCR_TL size_t g_seen_cap; /* Detection-numbered circular targets (persist across the call). */ static SCR_TL const void *g_circ[64]; @@ -1375,18 +1378,25 @@ static ScrStr *scr_insp_dyn_collection(ScrDyn *d, double recurse, double depth, return out; } -/* An own enumerable symbol-keyed property of `d` (borrowed), or NULL. */ +/* An own symbol-keyed property of `d` (borrowed) this render shows, or + * NULL: enumerable ones, and under showHidden the non-enumerable ones too. */ static ScrDynEntry *scr_insp_symbol_entry(ScrDyn *d, size_t i) { ScrDynEntry *ent = scr_dyn_own_symbol_entry(d, d->symbol_keys->v.arr.items[i]); - return ent && ent->enumerable ? ent : NULL; + return ent && (ent->enumerable || g_show_hidden) ? ent : NULL; } /* An ordinary object: `Name { key: value }` with its constructor name * `cls` (NULL for a plain object). Node's default view lists the own * enumerable string keys, then the own enumerable symbol keys. */ +/* An own entry this render shows: enumerable ones, and under showHidden + * the non-enumerable ones too (never the encoding's `%` markers). */ +static bool insp_obj_shows(const ScrDynEntry *ent) { + return ent->enumerable || (g_show_hidden && !(ent->key_len && ent->key[0] == '%')); +} + static ScrStr *scr_insp_obj(ScrDyn *d, double recurse, double depth, const char *cls) { size_t shown = 0; - for (size_t i = 0; i < d->v.obj.len; i++) shown += d->v.obj.entries[i].enumerable; + for (size_t i = 0; i < d->v.obj.len; i++) shown += insp_obj_shows(&d->v.obj.entries[i]); size_t nsymbols = d->symbol_keys ? d->symbol_keys->v.arr.len : 0; for (size_t i = 0; i < nsymbols; i++) shown += scr_insp_symbol_entry(d, i) != NULL; if (shown == 0) { @@ -1402,10 +1412,17 @@ static ScrStr *scr_insp_obj(ScrDyn *d, double recurse, double depth, const char scr_insp_begin(recurse + 1); for (size_t i = 0; i < d->v.obj.len; i++) { ScrDynEntry *ent = &d->v.obj.entries[i]; - if (!ent->enumerable) continue; + if (!insp_obj_shows(ent)) continue; ScrStr *val = scr_insp_dyn(ent->value, recurse + 1, depth); InspBuf eb = {0}; - insp_key_into(&eb, ent->key, ent->key_len); + if (ent->enumerable) { + insp_key_into(&eb, ent->key, ent->key_len); + } else { + /* formatProperty's hidden key: the key's rendering in brackets. */ + ib_char(&eb, '['); + insp_key_into(&eb, ent->key, ent->key_len); + ib_char(&eb, ']'); + } ib_cstr(&eb, ": "); ib_bytes(&eb, val->data, val->len); scr_str_release(val); @@ -1419,7 +1436,10 @@ static ScrStr *scr_insp_obj(ScrDyn *d, double recurse, double depth, const char ScrStr *key = scr_insp_dyn(d->symbol_keys->v.arr.items[i], recurse + 1, depth); ScrStr *val = scr_insp_dyn(ent->value, recurse + 1, depth); InspBuf eb = {0}; + /* A hidden symbol key is bracketed like a hidden string key. */ + if (!ent->enumerable) ib_char(&eb, '['); ib_bytes(&eb, key->data, key->len); + if (!ent->enumerable) ib_char(&eb, ']'); ib_cstr(&eb, ": "); ib_bytes(&eb, val->data, val->len); scr_str_release(key); @@ -1480,8 +1500,114 @@ ScrStr *scr_insp_typed_array(ScrBytes *b, double recurse, double depth) { return out; } +/* Node's function rendering: [Function: name] / [Function (anonymous)], + * and [class C extends B] / [class (anonymous)] for a class. The boxed + * name is the compiler's best-effort static spelling (SEMANTICS.md — + * reference-site naming). Enumerable own properties (a class's static + * fields, properties assigned to a function) follow in braces; past the + * depth limit such a function is [Function]. Borrows d; +1. */ +static ScrStr *scr_insp_dyn_func(ScrDyn *d, double recurse, double depth) { + const char *name = d->v.fn.name; + const ScrClassObj *cls = d->v.fn.class_obj; + ScrClosure *owner = scr_closure_identity(d->v.fn.clo); + ScrBox *props = owner->props ? owner->props : cls ? cls->static_data : NULL; + ScrDyn *table = props ? (ScrDyn *)scr_box_get_ref(props) : NULL; /* +1 */ + InspBuf out = {0}; + if (cls) { + ib_cstr(&out, "[class "); + ib_cstr(&out, name && name[0] ? name : "(anonymous)"); + const ScrDyn *base = table ? table->prototype : NULL; + if (cls->base_name && cls->base_name->len) { + ib_cstr(&out, " extends "); + ib_bytes(&out, cls->base_name->data, cls->base_name->len); + } else if (base && base->kind == SCR_DYN_FUNC && base->v.fn.name && base->v.fn.name[0]) { + ib_cstr(&out, " extends "); + ib_cstr(&out, base->v.fn.name); + } + ib_char(&out, ']'); + } else if (name && name[0]) { + ib_cstr(&out, "[Function: "); + ib_cstr(&out, name); + ib_char(&out, ']'); + } else { + ib_cstr(&out, "[Function (anonymous)]"); + } + ScrStr *tag = ib_take(&out); + if (cls && !props && cls->own_static_fields) { + /* Node prints the static fields after the tag; the class object + * does not hold them (the reflection fence's stance). */ + scr_str_release(tag); + static const char message[] = "util.inspect of a class with static fields through unknown is not supported yet"; + scr_throw_error_msg(SCR_ERR_ERROR, message, sizeof message - 1); + return scr_str_new("", 0); + } + size_t shown = 0; + if (table && table->kind == SCR_DYN_OBJ) { + for (size_t i = 0; i < table->v.obj.len; i++) shown += table->v.obj.entries[i].enumerable; + size_t nsymbols = table->symbol_keys ? table->symbol_keys->v.arr.len : 0; + for (size_t i = 0; i < nsymbols; i++) shown += scr_insp_symbol_entry(table, i) != NULL; + } + if (shown == 0) { + scr_dyn_release(table); + return tag; + } + if (recurse > depth) { + scr_dyn_release(table); + scr_str_release(tag); + return scr_str_new("[Function]", 10); + } + /* A function already on the traversal stack renders as [Circular *N], + * keyed by the closure every box of the function shares. */ + double circular = scr_insp_circ_check(owner); + if (circular > 0) { + scr_dyn_release(table); + scr_str_release(tag); + return scr_insp_circular(circular); + } + char *prefix = malloc(tag->len + 1); + if (!prefix) scr_trap("scriptc: out of memory\n"); + memcpy(prefix, tag->data, tag->len); + prefix[tag->len] = '\0'; + scr_str_release(tag); + size_t nseen = g_nseen; + g_pending_seen = owner; + ScrStr *rendered = scr_insp_obj(table, recurse, depth, prefix); + g_pending_seen = NULL; + if (g_nseen > nseen) g_nseen = nseen; + free(prefix); + scr_dyn_release(table); + return rendered; +} + +/* Under showHidden, the kinds whose hidden entries this inspector does not + * render (a function's length/name/prototype, an error's stack, a typed + * array's byte fields, a native handle's internals): the kind's name, NULL + * for the kinds it renders. */ +static const char *insp_hidden_refusal(const ScrDyn *d) { + switch (d->kind) { + case SCR_DYN_FUNC: return "function"; + case SCR_DYN_BYTES: return d->buffer ? "Buffer" : d->v.bytes->is_data_view ? "DataView" : "typed array"; + case SCR_DYN_OBJ: return scr_dyn_obj_get(d, "%error", 6) != NULL ? "Error" : NULL; + case SCR_DYN_HANDLE: + return d->v.handle.tag == SCR_DYNH_MAP || d->v.handle.tag == SCR_DYNH_SET || + d->v.handle.tag == SCR_DYNH_DATE + ? NULL + : scr_dyn_handle_cls(d); + default: return NULL; + } +} + ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) { if (d->kind == SCR_DYN_PROXY) return scr_insp_dyn(d->v.proxy.target, recurse, depth); + const char *refused = g_show_hidden ? insp_hidden_refusal(d) : NULL; + if (refused) { + InspBuf out = {0}; + ib_cstr(&out, "util.format %o of "); + ib_cstr(&out, refused); + ib_cstr(&out, " values is not supported yet"); + scr_throw_error(SCR_ERR_ERROR, ib_take(&out)); + return scr_str_new("", 0); + } switch (d->kind) { case SCR_DYN_NULL: return scr_str_new("null", 4); @@ -1499,14 +1625,14 @@ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) { return scr_insp_str(d->v.str); case SCR_DYN_ARR: { size_t len = d->v.arr.len; - if (len == 0) return scr_str_new("[]", 2); + if (len == 0 && !g_show_hidden) return scr_str_new("[]", 2); if (recurse > depth) return scr_str_new("[Array]", 7); scr_insp_begin(recurse + 1); /* Node's maxArrayLength (100) counts output entries; a run of holes * is one `` entry (formatSpecialArray). */ const unsigned char *presence = d->v.arr.presence; - size_t i = 0; - for (size_t shown = 0; i < len && shown < 100; shown++) { + size_t i = 0, shown = 0; + for (; i < len && shown < 100; shown++) { if (presence && !presence[i]) { size_t next = i + 1; while (next < len && !presence[next]) next++; @@ -1529,10 +1655,26 @@ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) { scr_insp_entry(m, d->v.arr.items[i]->kind == SCR_DYN_NUM); scr_str_release(m); } + if (g_show_hidden) { + /* The own non-enumerable `length`, after the items. Node's + * grouping reads value[k] for every output position k, this one + * included. */ + size_t at = shown + (more ? 1 : 0); + char line[48]; + int n = snprintf(line, sizeof line, "[length]: %zu", len); + ScrStr *s = scr_str_new(line, (size_t)n); + scr_insp_entry(s, at < len && (!presence || presence[at]) && + d->v.arr.items[at]->kind == SCR_DYN_NUM); + scr_str_release(s); + } ScrStr *base = scr_str_new("", 0); ScrStr *b0 = scr_str_new("[", 1); ScrStr *b1 = scr_str_new("]", 1); - ScrStr *out = scr_insp_end(base, b0, b1, recurse + 1, true, more); + /* groupArrayElements leaves the last entry out of the grid when + * there are more than maxArrayLength (100) entries: the "... N more + * items" tail, or under showHidden the `[length]` entry. */ + bool trailing = shown + (more ? 1 : 0) + (g_show_hidden ? 1 : 0) > 100; + ScrStr *out = scr_insp_end(base, b0, b1, recurse + 1, true, trailing); scr_str_release(base); scr_str_release(b0); scr_str_release(b1); @@ -1549,21 +1691,8 @@ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) { * the bare marker (where a plain object says [Object]). */ return scr_insp_obj(d, recurse, depth, scr_dyn_class_name(d)); } - case SCR_DYN_FUNC: { - /* Node's function rendering: [Function: name] / [Function - * (anonymous)]. The boxed name is the compiler's best-effort static - * spelling (SEMANTICS.md — reference-site naming). */ - const char *name = d->v.fn.name; - InspBuf out = {0}; - if (name && name[0]) { - ib_cstr(&out, "[Function: "); - ib_cstr(&out, name); - ib_char(&out, ']'); - } else { - ib_cstr(&out, "[Function (anonymous)]"); - } - return ib_take(&out); - } + case SCR_DYN_FUNC: + return scr_insp_dyn_func(d, recurse, depth); case SCR_DYN_HANDLE: { if (d->v.handle.tag == SCR_DYNH_ARRAY_BUFFER || d->v.handle.tag == SCR_DYNH_SHARED_ARRAY_BUFFER) { @@ -1734,6 +1863,16 @@ ScrStr *scr_insp_dyn_s(ScrDyn *d, double depth) { return scr_insp_dyn(d, 0, depth); } +/* util.format's %o over a dyn value: util.inspect with showHidden at the + * given depth. */ +ScrStr *scr_insp_dyn_hidden(ScrDyn *d, double depth) { + bool outer = g_show_hidden; + g_show_hidden = true; + ScrStr *out = scr_insp_dyn(d, 0, depth); + g_show_hidden = outer; + return out; +} + /* ── console.table cells ─────────────────────────────────────────────── */ size_t scr_insp_display_width(const char *data, size_t len) { return insp_width(data, len); } diff --git a/packages/runtime/src/scr_inspect.h b/packages/runtime/src/scr_inspect.h index 5ac3aa9dd..9bf18a23c 100644 --- a/packages/runtime/src/scr_inspect.h +++ b/packages/runtime/src/scr_inspect.h @@ -47,6 +47,7 @@ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth); ScrStr *scr_insp_typed_array(ScrBytes *b, double recurse, double depth); /* format's %s / rest-args twin: dyn strings pass verbatim. */ ScrStr *scr_insp_dyn_s(ScrDyn *d, double depth); +ScrStr *scr_insp_dyn_hidden(ScrDyn *d, double depth); /* %o: showHidden */ void scr_insp_begin(double recurse); /* util.inspect's breakLength, compact (0 for false) and sorted for the * renders that follow; the call site restores the defaults (80, 3, false) diff --git a/packages/runtime/src/scr_object.c b/packages/runtime/src/scr_object.c index 7cafbeca3..2f47a1c7b 100644 --- a/packages/runtime/src/scr_object.c +++ b/packages/runtime/src/scr_object.c @@ -33,6 +33,8 @@ ScrClassObj *scr_classobj_new(const ScrClassObj *template, size_t ncaps) { c->length = template->length; c->prototype_data = NULL; c->static_data = NULL; + c->base_name = template->base_name; + c->own_static_fields = template->own_static_fields; scr_obj_alloc_note(); return c; } diff --git a/tests/corpus/6343-inspect-class-values.ts b/tests/corpus/6343-inspect-class-values.ts new file mode 100644 index 000000000..5e9931c8c --- /dev/null +++ b/tests/corpus/6343-inspect-class-values.ts @@ -0,0 +1,31 @@ +// Classes reached through `unknown` print as Node prints them: +// `[class C]`, `[class C extends B]` with the runtime class's base, and +// `[class (anonymous)]`, at the top level and inside arrays and records. +import { inspect } from "node:util"; + +class A { + x = 1; +} +class B extends A { + y = 2; +} +class C extends B {} +class MyErr extends Error {} +const Anon = [class {}][0]!; +const Sub = class extends A {}; + +const a: unknown = A; +const b: unknown = B; +console.log(a, b); +console.log([a], { b }); +const values: unknown[] = [C, MyErr, Anon, Sub]; +console.log(values); +console.log(inspect({ deep: { values } }, { depth: 0 }), inspect(values, { depth: 0 })); +console.log(String(typeof values[0])); + +// A slot typed as the base holds a subclass at runtime. +const pick = (k: number): typeof A => (k === 0 ? A : k === 1 ? B : C); +for (let k = 0; k < 3; k++) { + const picked: unknown = pick(k); + console.log(k, picked); +} diff --git a/tests/corpus/6344-inspect-function-properties.cjs b/tests/corpus/6344-inspect-function-properties.cjs new file mode 100644 index 000000000..94db45a40 --- /dev/null +++ b/tests/corpus/6344-inspect-function-properties.cjs @@ -0,0 +1,34 @@ +'use strict'; +// Functions and classes reached as dynamic values print their enumerable +// own properties after the tag, as Node prints them: a class's static +// properties, properties assigned to a function, cycles through them, +// and `[Function]` past the depth limit. +const util = require('util'); + +function f() {} +f.x = 1; +f.label = 'f'; +function g() {} +g.self = g; +function plain() {} +class A {} +class S extends A { + static get hidden() { + return 1; + } +} +S.count = 3; +function show(value) { + console.log(value); +} +show(f); +show(g); +show(S); +show(A); +show(plain); +function shallow(value) { + console.log(util.inspect({ value }, { depth: 0 })); +} +shallow(f); +shallow(S); +shallow(A); diff --git a/tests/corpus/6357-format-o-hidden.ts b/tests/corpus/6357-format-o-hidden.ts new file mode 100644 index 000000000..9e48ed4ba --- /dev/null +++ b/tests/corpus/6357-format-o-hidden.ts @@ -0,0 +1,19 @@ +// util.format's %o over values reached through `unknown` renders with +// showHidden, as Node does: arrays show their hidden `[length]` (with +// Node's grouping), at every depth, inside Maps and records too. +import { format } from "node:util"; +const cases: [string, unknown][] = [ + ["ten", Array.from({ length: 10 }, (_, i) => i)], + ["wide", Array.from({ length: 120 }, (_, i) => i)], + ["hundred", Array.from({ length: 100 }, (_, i) => i)], + ["hundred-one", Array.from({ length: 101 }, (_, i) => i)], + ["hundred-strs", Array.from({ length: 100 }, (_, i) => "s" + i)], + ["seven", ["aaaaaaaaaaaaaaaaaaaa", "b", "c", "d", "e", "f", "g"]], + ["strs", Array.from({ length: 30 }, (_, i) => "s" + i)], + ["holes", [1, , 3]], + ["empty", []], + ["nested", { list: [[]], m: new Map([[1, [2]]]) }], + ["deep", [[[[[[1]]]]]]], + ["date", [new Date(0)]], +]; +for (const [k, v] of cases) console.log(k, format("%o", v)); diff --git a/tests/corpus/6358-format-o-hidden-js.cjs b/tests/corpus/6358-format-o-hidden-js.cjs new file mode 100644 index 000000000..df54b2714 --- /dev/null +++ b/tests/corpus/6358-format-o-hidden-js.cjs @@ -0,0 +1,9 @@ +'use strict'; +// %o shows an object's non-enumerable own properties as `[key]`, symbol +// keys included. +const util = require('util'); +const hidden = Object.defineProperty(JSON.parse('{"shown":1}'), 'secret', { value: [2], enumerable: false }); +Object.defineProperty(hidden, 'a-b', { value: 'x', enumerable: false }); +Object.defineProperty(hidden, Symbol('tag'), { value: 3, enumerable: false }); +console.log(util.format('%o and %O', hidden, hidden)); +console.log(util.format('%o', [hidden])); diff --git a/tests/fixtures/self-hosting/llvm-layouts.ts b/tests/fixtures/self-hosting/llvm-layouts.ts index 6ddf3ca3a..36d55bddf 100644 --- a/tests/fixtures/self-hosting/llvm-layouts.ts +++ b/tests/fixtures/self-hosting/llvm-layouts.ts @@ -119,7 +119,8 @@ try { }, ); virtualBorrows = new VirtualBorrows(mod, graph, functions, lifetimes.borrowed); - const classObjects = new Map(request.classObjects.map((name) => [name, { nameSym: `@name_${mangleClassObj(name)}` }])); + const classObjects: Map = new Map(); + for (const name of request.classObjects) classObjects.set(name, { nameSym: `@name_${mangleClassObj(name)}`, baseNameSym: null }); const typeName = (type: IrType): string => type.kind === "void" ? "void" : type.kind === "f64" || type.kind === "date" ? "double" : type.kind === "bool" ? "i1" : "ptr"; // Mirrors the emitter: whole-program int32 fields store the exact i32. const layouts = emitLlvmLayouts(host, mod, graph, classObjects, functions, typeName, undefined, analyzeInt32Slots(mod)); diff --git a/tests/harness/corpus-costs/6343-inspect-class-values.ts.json b/tests/harness/corpus-costs/6343-inspect-class-values.ts.json new file mode 100644 index 000000000..fa2590573 --- /dev/null +++ b/tests/harness/corpus-costs/6343-inspect-class-values.ts.json @@ -0,0 +1 @@ +{ "plain": 3700, "san": 4700 } diff --git a/tests/harness/corpus-costs/6344-inspect-function-properties.cjs.json b/tests/harness/corpus-costs/6344-inspect-function-properties.cjs.json new file mode 100644 index 000000000..71bf780f8 --- /dev/null +++ b/tests/harness/corpus-costs/6344-inspect-function-properties.cjs.json @@ -0,0 +1 @@ +{ "plain": 2700, "san": 3500 } diff --git a/tests/harness/corpus-costs/6357-format-o-hidden.ts.json b/tests/harness/corpus-costs/6357-format-o-hidden.ts.json new file mode 100644 index 000000000..f351a5044 --- /dev/null +++ b/tests/harness/corpus-costs/6357-format-o-hidden.ts.json @@ -0,0 +1 @@ +{ "plain": 2300, "san": 2100 } diff --git a/tests/harness/corpus-costs/6358-format-o-hidden-js.cjs.json b/tests/harness/corpus-costs/6358-format-o-hidden-js.cjs.json new file mode 100644 index 000000000..1f8ff72b2 --- /dev/null +++ b/tests/harness/corpus-costs/6358-format-o-hidden-js.cjs.json @@ -0,0 +1 @@ +{ "plain": 2100, "san": 2000 } diff --git a/tests/harness/dyncheck.test.ts b/tests/harness/dyncheck.test.ts index 6a2d4dc61..dab51a430 100644 --- a/tests/harness/dyncheck.test.ts +++ b/tests/harness/dyncheck.test.ts @@ -1278,4 +1278,92 @@ console.log("done", caught); expect(r.exitCode).toBe(0); expect(r.stdout).toBe("done 100\n"); }); + + test("an inspection refusal throws before console.log writes", async () => { + // A promise reached through `unknown` has no dynamic rendering; the + // refusal must stop the call, not print a partial line and continue. + const r = await compileAndRun( + "inspect-refusal-unwind", + `import { inspect } from "node:util"; +const p: unknown = Promise.resolve(3); +function attempt(label: string, f: () => void): void { + try { + f(); + console.log(label, "returned"); + } catch (e) { + console.log(label, (e as Error).message); + } +} +attempt("log", () => console.log("x", p)); +attempt("inspect", () => console.log(inspect(p).length)); +attempt("record", () => console.log({ a: p })); +attempt("array", () => console.log([p])); +console.log("before"); +console.log(p); +console.log("after"); +`, + ); + const refusal = "util.inspect of a promise value is not supported yet"; + expect(r.exitCode).toBe(1); + expect(r.stdout).toBe( + ["log", "inspect", "record", "array"].map((l) => `${l} ${refusal}\n`).join("") + "before\n", + ); + expect(r.stderr).toContain(`Uncaught Error: ${refusal}`); + }); + + test("inspecting a compiled class with static fields through unknown refuses", async () => { + // Node prints `[class S] { count: 3 }`; the class object does not + // carry compiled static fields, so the inspector refuses rather than + // print `[class S]`. A class without static fields still prints. + const r = await compileAndRun( + "inspect-class-statics", + `class Plain {} +class S extends Plain { + static count = 3; +} +const plain: unknown = Plain; +const s: unknown = S; +console.log(plain); +try { + console.log(s); +} catch (e) { + console.log((e as Error).message); +} +`, + ); + expect(r.exitCode).toBe(0); + expect(r.stdout).toBe( + "[class Plain]\nutil.inspect of a class with static fields through unknown is not supported yet\n", + ); + }); + + test("%o refuses the dynamic kinds whose hidden entries have no rendering", async () => { + // Node's showHidden adds a function's length/name/prototype, an + // error's stack and a typed array's byte fields; %o throws the 'not + // supported yet' Error for them instead of printing without them. + const r = await compileAndRun( + "format-o-hidden-refusals", + `import { format } from "node:util"; +function f(): void {} +const values: [string, unknown][] = [["fn", f], ["err", new Error("e")], ["u8", new Uint8Array(1)], ["arr", [1]]]; +for (const [label, value] of values) { + try { + console.log(label, format("%o", value)); + } catch (e) { + console.log(label, (e as Error).message); + } +} +`, + ); + expect(r.exitCode).toBe(0); + expect(r.stdout).toBe( + [ + "fn util.format %o of function values is not supported yet", + "err util.format %o of Error values is not supported yet", + "u8 util.format %o of typed array values is not supported yet", + "arr [ 1, [length]: 1 ]", + "", + ].join("\n"), + ); + }); }); From ba80dc254d2b6355bbdcef44ae1f76f577db63d1 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 13:56:21 -0500 Subject: [PATCH 003/259] Iterate classes with object-literal iterators and close them on early exits --- .../builtin-apis/synchronous-iteration.mdx | 2 +- .../language-features/async-iteration.mdx | 1 + .../lowering/class-dynamic-dispatch.ts | 10 +- .../src/frontend/lowering/dispatch-sites.ts | 1 + .../lowering/expressions/array-literals.ts | 8 + .../src/frontend/lowering/lower-classes.ts | 126 +++++++++++++-- .../src/frontend/lowering/lower-stmts.ts | 146 +++++++++++++++--- .../src/frontend/lowering/lower-stream.ts | 2 +- .../compiler/src/frontend/lowering/lowerer.ts | 10 +- .../6928-class-iterator-protocol.ts.json | 6 + .../6929-class-iterator-protocol.mjs.json | 6 + ...6935-class-async-iterator-protocol.ts.json | 6 + ...936-class-async-iterator-protocol.mjs.json | 6 + packages/runtime/src/scr_dyn_for_await.c | 8 +- tests/corpus/6928-class-iterator-protocol.ts | 93 +++++++++++ tests/corpus/6929-class-iterator-protocol.mjs | 78 ++++++++++ .../6935-class-async-iterator-protocol.ts | 60 +++++++ .../6936-class-async-iterator-protocol.mjs | 60 +++++++ .../6928-class-iterator-protocol.ts.json | 1 + .../6929-class-iterator-protocol.mjs.json | 1 + ...6935-class-async-iterator-protocol.ts.json | 1 + ...936-class-async-iterator-protocol.mjs.json | 1 + 22 files changed, 582 insertions(+), 51 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6928-class-iterator-protocol.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6929-class-iterator-protocol.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6935-class-async-iterator-protocol.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6936-class-async-iterator-protocol.mjs.json create mode 100644 tests/corpus/6928-class-iterator-protocol.ts create mode 100644 tests/corpus/6929-class-iterator-protocol.mjs create mode 100644 tests/corpus/6935-class-async-iterator-protocol.ts create mode 100644 tests/corpus/6936-class-async-iterator-protocol.mjs create mode 100644 tests/harness/corpus-costs/6928-class-iterator-protocol.ts.json create mode 100644 tests/harness/corpus-costs/6929-class-iterator-protocol.mjs.json create mode 100644 tests/harness/corpus-costs/6935-class-async-iterator-protocol.ts.json create mode 100644 tests/harness/corpus-costs/6936-class-async-iterator-protocol.mjs.json diff --git a/docs/content/limitations/builtin-apis/synchronous-iteration.mdx b/docs/content/limitations/builtin-apis/synchronous-iteration.mdx index 564f9af45..38cc9c475 100644 --- a/docs/content/limitations/builtin-apis/synchronous-iteration.mdx +++ b/docs/content/limitations/builtin-apis/synchronous-iteration.mdx @@ -1,4 +1,4 @@ - **Synchronous iteration:** Checked `for...of` follows live iterator methods, including compiled class methods and abrupt-completion cleanup. Mapper-less checked `Array.from` accepts those iterators and plain array-like objects. Sparse checked arrays and general borrowed iterator factories are unsupported. - Direct statically typed class loops also restrict iterator `return` and `throw` methods. + Direct statically typed class loops accept iterators that are class instances or object literals; a loop that exits early calls the iterator's zero-parameter `return()`, as Node's IteratorClose does. diff --git a/docs/content/limitations/language-features/async-iteration.mdx b/docs/content/limitations/language-features/async-iteration.mdx index 863c9be90..b15dca7fc 100644 --- a/docs/content/limitations/language-features/async-iteration.mdx +++ b/docs/content/limitations/language-features/async-iteration.mdx @@ -1,6 +1,7 @@ - **Async iteration:** Async `yield*` delegation, stored Web or Node iterator handles, and general structural async-iterator objects are unsupported. Typed async generators support lazy execution, `await`, direct `yield`, queued `.next()`/`.return()`/`.throw()` requests, and `for await`. `for await` also accepts Node `Readable` streams, Web `ReadableStream` values, and compiled class iterators whose zero-parameter `next()` returns a promise of a `{ value, done? }` record. + A class instance whose `[Symbol.asyncIterator]()` returns an object literal, or that has only `[Symbol.iterator]()`, iterates through the checked-dynamic async protocol, and an early exit awaits the iterator's `return()`. Abrupt completion runs cleanup, including literal `destroyOnReturn` and `preventCancel` options. The `node:timers/promises` `setInterval(delay, value)` iterator compiles without AbortSignal options. `Array.fromAsync` accepts arrays of values or of promises and typed async generators, with an optional mapping function; a `thisArg` and arrays that mix values and promises are unsupported. diff --git a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts index af3212ef0..86ad05386 100644 --- a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts +++ b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts @@ -2367,15 +2367,19 @@ export class ClassDynamicDispatch { } const iterator = expr.kind === "libCall" && - (expr.fn === "dyn.iterator" || expr.fn === "dyn.arrayFromIterator") + (expr.fn === "dyn.iterator" || + expr.fn === "dyn.arrayFromIterator" || + expr.fn === "dyn.asyncIteratorOpen") ? expr : null; + // `for await` opens a class instance's [Symbol.asyncIterator](). + const asyncOpen = iterator?.fn === "dyn.asyncIteratorOpen"; const invoke: Invoke | null = iterator ? { kind: "dynInvoke", recv: iterator.args[0]!, - method: "sym:iterator", - calleeName: "value[Symbol.iterator]", + method: asyncOpen ? "sym:asyncIterator" : "sym:iterator", + calleeName: asyncOpen ? "value[Symbol.asyncIterator]" : "value[Symbol.iterator]", args: [], type: DYN, loc: iterator.loc, diff --git a/packages/compiler/src/frontend/lowering/dispatch-sites.ts b/packages/compiler/src/frontend/lowering/dispatch-sites.ts index 2618dacf9..49d0bd243 100644 --- a/packages/compiler/src/frontend/lowering/dispatch-sites.ts +++ b/packages/compiler/src/frontend/lowering/dispatch-sites.ts @@ -59,6 +59,7 @@ const DISPATCH_LIB_CALLS = new Set([ "dyn.keySetComputed", "dyn.iterator", "dyn.arrayFromIterator", + "dyn.asyncIteratorOpen", "dyn.toString", "dyn.stringConstructor", "dyn.forInKeys", diff --git a/packages/compiler/src/frontend/lowering/expressions/array-literals.ts b/packages/compiler/src/frontend/lowering/expressions/array-literals.ts index 8f119504c..6153b87f2 100644 --- a/packages/compiler/src/frontend/lowering/expressions/array-literals.ts +++ b/packages/compiler/src/frontend/lowering/expressions/array-literals.ts @@ -425,6 +425,14 @@ export function lowerArrayLiteral( if (src.type.kind === "object") { const drained = lowerer.classIteratorDrainCall(src, locOf(el), type.elem); if (drained) src = drained; + // In JavaScript an iterable class whose inferred iterator shape has + // no static protocol spreads through the runtime's iterator walk. + else if ( + isJsSourceFile(ts.getSourceFileOfNode(el)) && + lowerer.classes.get(src.type.className) && + lowerer.findMethodOn(lowerer.classes.get(src.type.className)!, "sym:iterator") + ) + src = lowerer.coerceInto(el.expression, src, DYN); } // `[...s]` on a STRING spreads its code-point characters (the // string iterator's walk — astral chars whole) through the same diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index d8ccc15b7..9d994b76b 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -7923,31 +7923,83 @@ export function classMemberNameOf(lowerer: Lowerer, name: ts.PropertyName): stri export interface ClassIteratorInfo { /** The `[Symbol.iterator]()` call's receiver class + its declarer. */ className: string; - /** The iterator object's type (the method's return). */ - iterT: IrType & { kind: "object" }; + /** The iterator's type (the method's return): a class instance, or a + * record (an object literal) whose `next` field is a function. */ + iterT: IrType & ({ kind: "object" } | { kind: "record" }); /** next()'s result record type. */ resultT: IrType & { kind: "record" }; valueT: IrType; /** False: no done field — the protocol never terminates. */ hasDone: boolean; + /** The iterator declares a zero-parameter return(), which a consumer + * that stops before the end calls (IteratorClose). Only consumers that + * ask for `close` see such iterators. */ + hasReturn: boolean; } -export function classIteratorOf(lowerer: Lowerer, t: IrType): ClassIteratorInfo | null { +/** A return() result type that is always an object: IteratorClose after a + * break throws a TypeError for any other result, which these desugars do + * not model. */ +function objectResult(t: IrType): boolean { + return t.kind === "record" || t.kind === "object"; +} + +/** What a class iterable's consumer handles: `records` accepts an + * object-literal iterator; `close` accepts an iterator with return(), + * which the consumer calls when it stops early (or never stops early). */ +export interface ClassIteratorOptions { + records?: boolean; + close?: boolean; +} +export function classIteratorOf( + lowerer: Lowerer, + t: IrType, + options: ClassIteratorOptions = {}, +): ClassIteratorInfo | null { if (t.kind !== "object") return null; const info = lowerer.classes.get(t.className); if (!info) return null; const iter = findMethodOn(lowerer, info, "sym:iterator"); if (!iter || iter.sig.params.length !== 0 || iter.sig.abstract === true) return null; const iterT = iter.sig.ret; - if (iterT.kind !== "object") return null; - const itInfo = lowerer.classes.get(iterT.className); - if (!itInfo) return null; - // IteratorClose honesty: a declared return()/throw() would be called - // by JS on abrupt completion; these desugars never close. - if (findMethodOn(lowerer, itInfo, "return") || findMethodOn(lowerer, itInfo, "throw")) - return null; - const next = findMethodOn(lowerer, itInfo, "next"); - if (!next || next.sig.params.length !== 0 || next.sig.abstract === true) return null; - const resultT = next.sig.ret; + let resultT: IrType; + let hasReturn: boolean; + if (iterT.kind === "object") { + const itInfo = lowerer.classes.get(iterT.className); + if (!itInfo) return null; + // IteratorClose honesty: a declared return() would be called by JS on + // abrupt completion, so only a consumer that closes takes it; for-of + // never calls throw(), the other consumers refuse it. + const close = findMethodOn(lowerer, itInfo, "return"); + if ( + close && + (!options.close || + close.sig.abstract === true || + close.sig.params.length !== 0 || + !objectResult(close.sig.ret)) + ) + return null; + if (findMethodOn(lowerer, itInfo, "throw") && !options.close) return null; + const next = findMethodOn(lowerer, itInfo, "next"); + if (!next || next.sig.params.length !== 0 || next.sig.abstract === true) return null; + resultT = next.sig.ret; + hasReturn = !!close; + } else if (iterT.kind === "record" && options.records) { + const fields = lowerer.shapes.get(iterT.shapeId)?.fields; + const next = fields?.find((f) => f.name === "next")?.type; + if (!next || next.kind !== "func" || next.params.length !== 0 || next.rest) return null; + const close = fields?.find((f) => f.name === "return")?.type; + if ( + close && + (!options.close || + close.kind !== "func" || + close.params.length !== 0 || + close.rest || + !objectResult(close.ret)) + ) + return null; + resultT = next.ret; + hasReturn = close !== undefined; + } else return null; if (resultT.kind !== "record") return null; const shape = lowerer.shapes.get(resultT.shapeId); const value = shape?.fields.find((f) => f.name === "value"); @@ -7960,6 +8012,7 @@ export function classIteratorOf(lowerer: Lowerer, t: IrType): ClassIteratorInfo resultT, valueT: value.type, hasDone: done !== undefined, + hasReturn, }; } @@ -7971,7 +8024,43 @@ export function classIteratorNextCall( itRef: IrExpr, loc: SrcLoc, ): IrExpr { - return accessorCall(lowerer, cit.iterT.className, "next", itRef, [], cit.resultT, loc); + return classIteratorMethodCall(lowerer, cit, "next", itRef, loc); +} + +/** `it.next()` or `it.return()` of a class iterator: a (possibly virtual) + * method call of an iterator class, or the call of an object-literal + * iterator's function field. */ +export function classIteratorMethodCall( + lowerer: Lowerer, + cit: ClassIteratorInfo, + method: "next" | "return", + itRef: IrExpr, + loc: SrcLoc, +): IrExpr { + const iterT = cit.iterT; + if (iterT.kind === "object") { + const ret = + method === "next" + ? cit.resultT + : findMethodOn(lowerer, lowerer.classes.get(iterT.className)!, "return")!.sig.ret; + return accessorCall(lowerer, iterT.className, method, itRef, [], ret, loc); + } + const field = lowerer.shapes.get(iterT.shapeId)!.fields.find((f) => f.name === method)!; + const fnT = field.type as IrType & { kind: "func" }; + return { + kind: "callValue", + callee: { + kind: "recordGet", + obj: itRef, + shapeId: iterT.shapeId, + field: method, + type: fnT, + loc, + }, + args: [], + type: fnT.ret, + loc, + }; } /** `recv[Symbol.iterator]()` as an ordinary method call. */ @@ -7999,12 +8088,15 @@ export function classIteratorDrainCall( loc: SrcLoc, elemT?: IrType, ): IrExpr | null { - const cit = classIteratorOf(lowerer, src.type); + // A spread takes every value, so it never closes the iterator. + const cit = classIteratorOf(lowerer, src.type, { records: true, close: true }); if (!cit) return null; const outElem = elemT ?? cit.valueT; // Probe the element coercion purely: identical types, or an arm of a // union destination (the wrap coerceToExpected applies below). - if (!typeEquals(outElem, cit.valueT)) { + // A checked-dynamic value (`IteratorResult`'s value is `T | any`) + // converts to the destination element with a check. + if (!typeEquals(outElem, cit.valueT) && cit.valueT.kind !== "dyn") { if (outElem.kind !== "union" || lowerer.armTag(outElem.unionId, cit.valueT) < 0) return null; } const outT = arrayOf(outElem); @@ -8122,7 +8214,7 @@ export function classIteratorRestDrainCall( loc: SrcLoc, ): IrExpr { const outT = arrayOf(cit.valueT); - const key = `it:${cit.iterT.className}`; + const key = `it:${cit.iterT.kind === "object" ? cit.iterT.className : typeKey(cit.iterT)}`; let name = lowerer.iterDrainHelpers.get(key); if (!name) { name = keyedHelperName(lowerer, "%iter.drain", key); diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index 213abfec6..bee887e0f 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -9467,8 +9467,23 @@ export function lowerForOf(lowerer: Lowerer, stmt: ts.ForOfStatement): IrStmt { // iterator are awaited as the async-from-sync iterator awaits them, and // a value that is not iterable throws Node's TypeError. const headT = lowerer.mapTypeOf(lowerer.typeOf(stmt.expression)); + // A class instance whose [Symbol.asyncIterator]() (or + // [Symbol.iterator]()) returns an iterator object takes the same + // checked-dynamic protocol over the boxed instance. + const headClass = headT?.kind === "object" ? lowerer.classes.get(headT.className) : undefined; + const classAsync = + headClass !== undefined && lowerer.findMethodOn(headClass, "sym:asyncIterator") !== null; + // Without [Symbol.asyncIterator], the loop opens [Symbol.iterator]() and + // awaits its values, as the async-from-sync iterator does. + const classSync = + headClass !== undefined && + !classAsync && + lowerer.findMethodOn(headClass, "sym:iterator") !== null; + const classIterable = classAsync || classSync; const syncGenerator = - (headT?.kind === "generator" && headT.async !== true) || isJsSourceFile(stmt.getSourceFile()); + (headT?.kind === "generator" && headT.async !== true) || + classIterable || + isJsSourceFile(stmt.getSourceFile()); if (lowerer.ctx.isAsync && (syncGenerator || isUntypedIterable(lowerer, stmt.expression))) { const iterable = lowerer.lowerExpr(stmt.expression); if (iterable.type.kind === "generator" && iterable.type.async) @@ -9480,10 +9495,19 @@ export function lowerForOf(lowerer: Lowerer, stmt: ts.ForOfStatement): IrStmt { ); if (iterable.type.kind === "dyn") return lowerForOfDyn(lowerer, stmt, iterable, labels, true); if ( - (iterable.type.kind === "generator" || isJsSourceFile(stmt.getSourceFile())) && + (iterable.type.kind === "generator" || + classIterable || + isJsSourceFile(stmt.getSourceFile())) && lowerer.dynConvertible(iterable.type) ) - return lowerForOfDyn(lowerer, stmt, lowerer.coerceToExpected(iterable, DYN), labels, true); + return lowerForOfDyn( + lowerer, + stmt, + lowerer.coerceToExpected(iterable, DYN), + labels, + true, + classSync && iterable.type.kind === "object", + ); } // A NodeJS.ReadableStream iterates as the general Readable. requestGeneralStreamSurface(lowerer, stmt.expression); @@ -9732,17 +9756,30 @@ export function lowerForOf(lowerer: Lowerer, stmt: ts.ForOfStatement): IrStmt { ); // Class iterables ([Symbol.iterator]() + next() — classIteratorOf) // drive the same protocol with ordinary method calls. - const cit = lowerer.classIteratorOf(iterable.type); + const cit = lowerer.classIteratorOf(iterable.type, { records: true, close: true }); if (cit) return lowerForOfClassIterator(lowerer, stmt, iterable, cit, labels); // A declared [Symbol.iterator] whose shape classIteratorOf refused // (an `any`-typed iterator or result, a declared return()/throw()): // name the protocol, not the class. const info = lowerer.classes.get(iterable.type.className); + // In JavaScript the inferred shape is often a union of result + // objects: the loop runs the iterator protocol over the boxed value. + if ( + info && + isJsSourceFile(ts.getSourceFileOfNode(stmt)) && + lowerer.findMethodOn(info, "sym:iterator") + ) + return lowerForOfDyn( + lowerer, + stmt, + lowerer.coerceInto(stmt.expression, iterable, DYN), + labels, + ); if (info && lowerer.findMethodOn(info, "sym:iterator")) { lowerer.unsupported( "SC1090", stmt.expression, - `for-of over this [Symbol.iterator] shape (the method must take no parameters and return an object whose zero-parameter next() returns a { value, done? } record with a boolean done; iterator classes declaring return()/throw() stay out — IteratorClose has no lowering)`, + `for-of over this [Symbol.iterator] shape (the method must take no parameters and return an object whose zero-parameter next() returns a { value, done? } record with a boolean done, and whose return(), if any, takes no parameters and returns an object)`, ); } } @@ -10641,11 +10678,13 @@ function lowerForOfMatchAll( * } } * * A result record with NO done field never terminates — exactly JS - * (undefined is falsy forever; Node loops forever too). No - * IteratorClose: classIteratorOf already refused iterator classes - * declaring return()/throw(), so a break exits with nothing to close. - * `done: true` results bind nothing (the loop breaks before the value - * read), matching JS's ignore-the-final-value rule. */ + * (undefined is falsy forever; Node loops forever too). An iterator with + * return() is closed when the loop leaves after a value arrived (break, + * return, or a throw from the body), as IteratorClose does: a done flag + * set around each step guards the call in a finally, and after a throw + * from the body an error from return() is dropped. A throw from next() + * does not close. `done: true` results bind nothing (the loop breaks + * before the value read), matching JS's ignore-the-final-value rule. */ function lowerForOfClassIterator( lowerer: Lowerer, stmt: ts.ForOfStatement, @@ -10688,6 +10727,19 @@ function lowerForOfClassIterator( const recvRef: IrExpr = { kind: "varRef", localId: recv.id, type: iterable.type, loc }; const itRef = (): IrExpr => ({ kind: "varRef", localId: it.id, type: cit.iterT, loc }); const rRef = (): IrExpr => ({ kind: "varRef", localId: r.id, type: cit.resultT, loc }); + const done = cit.hasReturn ? lowerer.declareHiddenLocal("%cid", BOOL) : null; + if (done) done.mutable = true; + const setDone = (value: boolean): IrStmt[] => + done + ? [ + { + kind: "assign", + localId: done.id, + value: { kind: "boolLit", value, type: BOOL, loc }, + loc, + }, + ] + : []; const varTarget = exprTarget ?? (decl ? forOfVarTarget(lowerer, decl) : null); const x = varTarget ? lowerer.declareHiddenLocal("%vof", cit.valueT) @@ -10700,6 +10752,7 @@ function lowerForOfClassIterator( const xRef: IrExpr = { kind: "varRef", localId: x.id, type: cit.valueT, loc }; const blame: ts.Node = decl?.name ?? exprTargetNode ?? stmt.initializer; const head: IrStmt[] = [ + ...setDone(true), { kind: "varDecl", localId: r.id, @@ -10747,8 +10800,16 @@ function lowerForOfClassIterator( } satisfies IrStmt, ] : []), + ...setDone(false), ]; const body = lowerer.inCtl("loop", () => lowerer.lowerScopedBlock(stmt.statement), labels); + const loop: IrStmt = { + kind: "while", + cond: { kind: "boolLit", value: true, type: BOOL, loc }, + body: [...head, ...body], + ...(labels && { labels }), + loc, + }; return { kind: "block", body: [ @@ -10759,13 +10820,45 @@ function lowerForOfClassIterator( init: lowerer.classIteratorOpenCall(cit, recvRef, loc), loc, }, - { - kind: "while", - cond: { kind: "boolLit", value: true, type: BOOL, loc }, - body: [...head, ...body], - ...(labels && { labels }), - loc, - }, + ...(done + ? [ + { + kind: "varDecl", + localId: done.id, + init: { kind: "boolLit", value: true, type: BOOL, loc }, + loc, + } satisfies IrStmt, + { + kind: "tryCatch", + tryBody: [loop], + catchBody: null, + catchLocalId: null, + dropFinallyErrors: true, + finallyBody: [ + { + kind: "if", + cond: { + kind: "unary", + op: "!", + operand: { kind: "varRef", localId: done.id, type: BOOL, loc }, + type: BOOL, + loc, + }, + then: [ + { + kind: "exprStmt", + expr: lowerer.classIteratorReturnCall(cit, itRef(), loc), + loc, + }, + ], + else_: null, + loc, + }, + ], + loc, + } satisfies IrStmt, + ] + : [loop]), ], loc, }; @@ -10783,6 +10876,7 @@ function lowerForOfDyn( iterable: IrExpr, labels?: string[], asyncLoop = false, + syncOpen = false, ): IrStmt { const loc = locOf(stmt); const spell = notIterableSpelling(stmt.expression, asyncLoop ? "async iterable" : "iterable"); @@ -11010,7 +11104,7 @@ function lowerForOfDyn( localId: iterator.id, init: check({ kind: "libCall", - fn: asyncLoop ? "dyn.asyncIteratorOpen" : "dyn.iterator", + fn: asyncLoop && !syncOpen ? "dyn.asyncIteratorOpen" : "dyn.iterator", args: [iterable, { kind: "strLit", value: spell, type: STRING, loc }], type: DYN, loc, @@ -11022,13 +11116,15 @@ function lowerForOfDyn( { kind: "varDecl", localId: syncIterator.id, - init: { - kind: "libCall", - fn: "dyn.asyncIteratorWasSync", - args: [], - type: BOOL, - loc, - }, + init: syncOpen + ? { kind: "boolLit", value: true, type: BOOL, loc } + : { + kind: "libCall", + fn: "dyn.asyncIteratorWasSync", + args: [], + type: BOOL, + loc, + }, loc, } satisfies IrStmt, ] diff --git a/packages/compiler/src/frontend/lowering/lower-stream.ts b/packages/compiler/src/frontend/lowering/lower-stream.ts index 6540b3a99..90bdf917e 100644 --- a/packages/compiler/src/frontend/lowering/lower-stream.ts +++ b/packages/compiler/src/frontend/lowering/lower-stream.ts @@ -1954,7 +1954,7 @@ function classIteratorObject( iter: IrExpr, loc: SrcLoc, ): IrExpr { - const key = `streamFromIter:${cit.iterT.className}`; + const key = `streamFromIter:${cit.iterT.kind === "object" ? cit.iterT.className : typeKey(cit.iterT)}`; let name = lowerer.valueHelpers.get(key); if (!name) { name = keyedHelperName(lowerer, "%stream.fromIter", key); diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 747e396af..ea503e1f1 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -348,6 +348,7 @@ import { type ClassInfo, type ClassMethodSignature, type ClassIteratorInfo, + type ClassIteratorOptions, type GenericClassInfo, registerBuiltinErrorClasses, defineClassValueConstruct, @@ -359,6 +360,7 @@ import { builtinStreamInfoOf, analyzeClassDecoration, classIteratorDrainCall, + classIteratorMethodCall, classIteratorNextCall, classIteratorOf, classIteratorOpenCall, @@ -13049,8 +13051,12 @@ export class Lowerer { return accessorCall(this, className, member, obj, extraArgs, ret, loc); } - classIteratorOf(t: IrType): ClassIteratorInfo | null { - return classIteratorOf(this, t); + classIteratorOf(t: IrType, options?: ClassIteratorOptions): ClassIteratorInfo | null { + return classIteratorOf(this, t, options); + } + + classIteratorReturnCall(cit: ClassIteratorInfo, it: IrExpr, loc: SrcLoc): IrExpr { + return classIteratorMethodCall(this, cit, "return", it, loc); } classIteratorOpenCall(cit: ClassIteratorInfo, recv: IrExpr, loc: SrcLoc): IrExpr { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6928-class-iterator-protocol.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6928-class-iterator-protocol.ts.json new file mode 100644 index 000000000..2efd8521a --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6928-class-iterator-protocol.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6928-class-iterator-protocol.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6929-class-iterator-protocol.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6929-class-iterator-protocol.mjs.json new file mode 100644 index 000000000..49e5e4304 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6929-class-iterator-protocol.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6929-class-iterator-protocol.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6935-class-async-iterator-protocol.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6935-class-async-iterator-protocol.ts.json new file mode 100644 index 000000000..93775b96b --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6935-class-async-iterator-protocol.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6935-class-async-iterator-protocol.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6936-class-async-iterator-protocol.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6936-class-async-iterator-protocol.mjs.json new file mode 100644 index 000000000..378f7d18b --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6936-class-async-iterator-protocol.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6936-class-async-iterator-protocol.mjs" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_dyn_for_await.c b/packages/runtime/src/scr_dyn_for_await.c index 25183c4ee..2d39885c0 100644 --- a/packages/runtime/src/scr_dyn_for_await.c +++ b/packages/runtime/src/scr_dyn_for_await.c @@ -39,7 +39,11 @@ ScrDyn *scr_dyn_async_iterator_open(ScrDyn *value, ScrStr *spell) { } /* Whether the iterator the last scr_dyn_async_iterator_open returned is a - * synchronous one. Read immediately after the open. */ + * synchronous one. Read immediately after the open; the read clears it, so + * an iterator a class's [Symbol.asyncIterator]() returned (opened without + * the runtime) reads false. */ bool scr_dyn_async_iterator_was_sync(void) { - return scr_for_await_sync; + bool sync = scr_for_await_sync; + scr_for_await_sync = false; + return sync; } diff --git a/tests/corpus/6928-class-iterator-protocol.ts b/tests/corpus/6928-class-iterator-protocol.ts new file mode 100644 index 000000000..f097368de --- /dev/null +++ b/tests/corpus/6928-class-iterator-protocol.ts @@ -0,0 +1,93 @@ +// for-of and spread over classes whose [Symbol.iterator]() returns an iterator object, +// with return() called on early exits as Node's IteratorClose does. +class Bag { + readonly items: string[]; + constructor(items: string[]) { this.items = items; } + [Symbol.iterator]() { + let i = 0; + const items = this.items; + return { + next(): IteratorResult { + return i < items.length ? { value: items[i++]!, done: false } : { value: undefined, done: true }; + }, + return(): IteratorResult { + console.log("return at", i); + return { value: undefined, done: true }; + }, + }; + } +} +const bag = new Bag(["a", "b", "c", "d"]); +function firstLong(): string | undefined { + for (const s of bag) if (s >= "b") return s; + return undefined; +} +console.log(firstLong()); +try { + for (const s of bag) if (s === "c") throw new Error("stop at " + s); +} catch (e) { + console.log((e as Error).message); +} +outer: for (const n of [1, 2]) { + for (const s of bag) { + if (s === "b") continue outer; + console.log(n, s); + } +} +let all = ""; +for (const s of bag) all += s; +console.log(all); + +class Counter { + n = 0; + [Symbol.iterator](): CounterIterator { return new CounterIterator(3); } +} +class CounterIterator { + i = 0; + readonly limit: number; + constructor(limit: number) { this.limit = limit; } + next(): { value: number; done: boolean } { + return this.i < this.limit ? { value: this.i++, done: false } : { value: -1, done: true }; + } + return(): { value: number; done: boolean } { + console.log("class return", this.i); + return { value: -1, done: true }; + } +} +for (const v of new Counter()) { if (v === 1) break; console.log("v", v); } +console.log([...new Counter()].join()); + +class Fussy { + [Symbol.iterator]() { + let i = 0; + return { + next(): IteratorResult { return { value: i++, done: i > 5 }; }, + return(): IteratorResult { throw new Error("return failed"); }, + }; + } +} +try { + for (const v of new Fussy()) if (v === 1) break; +} catch (e) { + console.log("break:", (e as Error).message); +} +try { + for (const v of new Fussy()) if (v === 1) throw new Error("body failed"); +} catch (e) { + console.log("throw:", (e as Error).message); +} + +class Range { + readonly n: number; + constructor(n: number) { this.n = n; } + [Symbol.iterator]() { + let i = 0; + const n = this.n; + return { + next(): IteratorResult { return i < n ? { value: i++, done: false } : { value: undefined, done: true }; }, + }; + } +} +let total = 0; +for (const v of new Range(4)) total += v; +console.log(total, [...new Range(3)].join()); diff --git a/tests/corpus/6929-class-iterator-protocol.mjs b/tests/corpus/6929-class-iterator-protocol.mjs new file mode 100644 index 000000000..b5255ba35 --- /dev/null +++ b/tests/corpus/6929-class-iterator-protocol.mjs @@ -0,0 +1,78 @@ +// for-of and spread in JavaScript over classes whose [Symbol.iterator]() returns an +// iterator object, with return() called on early exits as Node's IteratorClose does. +class Bag { + + constructor(items) { this.items = items; } + [Symbol.iterator]() { + let i = 0; + const items = this.items; + return { + next() { + return i < items.length ? { value: items[i++], done: false } : { value: undefined, done: true }; + }, + return() { + console.log("return at", i); + return { value: undefined, done: true }; + }, + }; + } +} +const bag = new Bag(["a", "b", "c", "d"]); +function firstLong() { + for (const s of bag) if (s >= "b") return s; + return undefined; +} +console.log(firstLong()); +try { + for (const s of bag) if (s === "c") throw new Error("stop at " + s); +} catch (e) { + console.log(e.message); +} +outer: for (const n of [1, 2]) { + for (const s of bag) { + if (s === "b") continue outer; + console.log(n, s); + } +} +let all = ""; +for (const s of bag) all += s; +console.log(all); + +class Counter { + n = 0; + [Symbol.iterator]() { return new CounterIterator(3); } +} +class CounterIterator { + i = 0; + + constructor(limit) { this.limit = limit; } + next() { + return this.i < this.limit ? { value: this.i++, done: false } : { value: -1, done: true }; + } + return() { + console.log("class return", this.i); + return { value: -1, done: true }; + } +} +for (const v of new Counter()) { if (v === 1) break; console.log("v", v); } +console.log([...new Counter()].join()); + +class Fussy { + [Symbol.iterator]() { + let i = 0; + return { + next() { return { value: i++, done: i > 5 }; }, + return() { if (i >= 0) throw new Error("return failed"); return { value: undefined, done: true }; }, + }; + } +} +try { + for (const v of new Fussy()) if (v === 1) break; +} catch (e) { + console.log("break:", e.message); +} +try { + for (const v of new Fussy()) if (v === 1) throw new Error("body failed"); +} catch (e) { + console.log("throw:", e.message); +} diff --git a/tests/corpus/6935-class-async-iterator-protocol.ts b/tests/corpus/6935-class-async-iterator-protocol.ts new file mode 100644 index 000000000..9ec5a61a5 --- /dev/null +++ b/tests/corpus/6935-class-async-iterator-protocol.ts @@ -0,0 +1,60 @@ +// for await over classes whose [Symbol.asyncIterator]() or [Symbol.iterator]() +// returns an iterator object: early exits await return(), as in Node. +class Ticks { + readonly n: number; + constructor(n: number) { this.n = n; } + [Symbol.asyncIterator]() { + let i = 0; + const n = this.n; + return { + async next(): Promise> { + return i < n ? { value: i++, done: false } : { value: undefined, done: true }; + }, + async return(): Promise> { + console.log("closed at", i); + return { value: undefined, done: true }; + }, + }; + } +} +class Pages { + [Symbol.asyncIterator](): PageCursor { return new PageCursor(); } +} +class PageCursor { + page = 0; + async next(): Promise<{ value: string; done: boolean }> { + this.page++; + return this.page <= 3 ? { value: "page " + this.page, done: false } : { value: "", done: true }; + } +} +class Letters { + [Symbol.iterator]() { + const letters = ["x", "y", "z"]; + let i = 0; + return { + next(): IteratorResult { return i < letters.length ? { value: letters[i++]!, done: false } : { value: undefined, done: true }; }, + }; + } +} +async function main(): Promise { + let sum = 0; + for await (const v of new Ticks(4)) sum += v * 2; + console.log("sum", sum); + for await (const v of new Ticks(5)) { + if (v === 2) break; + console.log("early", v); + } + try { + for await (const v of new Ticks(5)) if (v === 1) throw new Error("body " + v); + } catch (e) { + console.log("caught", (e as Error).message); + } + async function find(): Promise { + for await (const v of new Ticks(9)) if (v > 2) return v; + return -1; + } + console.log("found", await find()); + for await (const p of new Pages()) console.log(p); + for await (const l of new Letters()) console.log("letter", l); +} +main(); diff --git a/tests/corpus/6936-class-async-iterator-protocol.mjs b/tests/corpus/6936-class-async-iterator-protocol.mjs new file mode 100644 index 000000000..cb7b1e68a --- /dev/null +++ b/tests/corpus/6936-class-async-iterator-protocol.mjs @@ -0,0 +1,60 @@ +// for await in JavaScript over classes whose [Symbol.asyncIterator]() or [Symbol.iterator]() +// returns an iterator object: early exits await return(), as in Node. +class Ticks { + + constructor(n) { this.n = n; } + [Symbol.asyncIterator]() { + let i = 0; + const n = this.n; + return { + async next() { + return i < n ? { value: i++, done: false } : { value: undefined, done: true }; + }, + async return() { + console.log("closed at", i); + return { value: undefined, done: true }; + }, + }; + } +} +class Pages { + [Symbol.asyncIterator]() { return new PageCursor(); } +} +class PageCursor { + page = 0; + async next() { + this.page++; + return this.page <= 3 ? { value: "page " + this.page, done: false } : { value: "", done: true }; + } +} +class Letters { + [Symbol.iterator]() { + const letters = ["x", "y", "z"]; + let i = 0; + return { + next() { return i < letters.length ? { value: letters[i++], done: false } : { value: undefined, done: true }; }, + }; + } +} +async function main() { + let sum = 0; + for await (const v of new Ticks(4)) sum += v * 2; + console.log("sum", sum); + for await (const v of new Ticks(5)) { + if (v === 2) break; + console.log("early", v); + } + try { + for await (const v of new Ticks(5)) if (v === 1) throw new Error("body " + v); + } catch (e) { + console.log("caught", e.message); + } + async function find() { + for await (const v of new Ticks(9)) if (v > 2) return v; + return -1; + } + console.log("found", await find()); + for await (const p of new Pages()) console.log(p); + for await (const l of new Letters()) console.log("letter", l); +} +main(); diff --git a/tests/harness/corpus-costs/6928-class-iterator-protocol.ts.json b/tests/harness/corpus-costs/6928-class-iterator-protocol.ts.json new file mode 100644 index 000000000..577adfbd9 --- /dev/null +++ b/tests/harness/corpus-costs/6928-class-iterator-protocol.ts.json @@ -0,0 +1 @@ +{ "plain": 3913, "san": 3785 } diff --git a/tests/harness/corpus-costs/6929-class-iterator-protocol.mjs.json b/tests/harness/corpus-costs/6929-class-iterator-protocol.mjs.json new file mode 100644 index 000000000..a653f7709 --- /dev/null +++ b/tests/harness/corpus-costs/6929-class-iterator-protocol.mjs.json @@ -0,0 +1 @@ +{ "plain": 3934, "san": 3488 } diff --git a/tests/harness/corpus-costs/6935-class-async-iterator-protocol.ts.json b/tests/harness/corpus-costs/6935-class-async-iterator-protocol.ts.json new file mode 100644 index 000000000..facd86f6d --- /dev/null +++ b/tests/harness/corpus-costs/6935-class-async-iterator-protocol.ts.json @@ -0,0 +1 @@ +{ "plain": 3179, "san": 2683 } diff --git a/tests/harness/corpus-costs/6936-class-async-iterator-protocol.mjs.json b/tests/harness/corpus-costs/6936-class-async-iterator-protocol.mjs.json new file mode 100644 index 000000000..cbe2cb7d2 --- /dev/null +++ b/tests/harness/corpus-costs/6936-class-async-iterator-protocol.mjs.json @@ -0,0 +1 @@ +{ "plain": 3547, "san": 2898 } From 3bbb88c43c8c5e0957047c6035c0a9ff42c66aba Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 16:51:25 -0500 Subject: [PATCH 004/259] Construct through arrays of class values that mix a class and its subclasses `const kinds = [Dog, Cat, Animal]; new kinds[0]()` now works as in Node: - TypeScript: the checker types the element as the common base (`typeof Animal`), and an element read keeps the `undefined` an index past the end reads. The construction now narrows the class value out of that union, and an index past the end throws Node's TypeError ("kinds[5] is not a constructor"). Before, it refused with SC2001. - JavaScript: such a literal is a checked-dynamic array stored in a slot of the base's class values, and the check accepted only the base's own class value, so storing it threw "expected class constructor". A class value of a subclass now checks into its base class's slot, as a subclass instance already checks into a base-class instance slot. Classes without subclasses keep the exact check. --- packages/compiler/src/backend/llvm/dyn.ts | 18 ++++ .../src/frontend/lowering/lower-classes.ts | 93 ++++++++++++++++++- .../corpus/6937-class-value-arrays.mjs.json | 6 ++ .../corpus/6938-class-value-arrays.ts.json | 6 ++ tests/corpus/6937-class-value-arrays.mjs | 30 ++++++ tests/corpus/6938-class-value-arrays.ts | 28 ++++++ .../6937-class-value-arrays.mjs.json | 1 + .../6938-class-value-arrays.ts.json | 1 + 8 files changed, 182 insertions(+), 1 deletion(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6937-class-value-arrays.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6938-class-value-arrays.ts.json create mode 100644 tests/corpus/6937-class-value-arrays.mjs create mode 100644 tests/corpus/6938-class-value-arrays.ts create mode 100644 tests/harness/corpus-costs/6937-class-value-arrays.mjs.json create mode 100644 tests/harness/corpus-costs/6938-class-value-arrays.ts.json diff --git a/packages/compiler/src/backend/llvm/dyn.ts b/packages/compiler/src/backend/llvm/dyn.ts index 5c9d8e60f..f0278bce6 100644 --- a/packages/compiler/src/backend/llvm/dyn.ts +++ b/packages/compiler/src/backend/llvm/dyn.ts @@ -1530,6 +1530,24 @@ export class LlDyn { const B = new BlockBuilder(); if (t.kind === "classval") { host.declare(`declare ptr @scr_dyn_class_check(ptr, ptr, ptr)`); + // A subclass's class value checks into the base class's slot. + const subclasses = host.classSubtypes(t.className).filter((name) => name !== t.className); + if (subclasses.length > 0) { + host.declare(`declare zeroext i1 @scr_dyn_class_is(ptr, ptr)`); + for (const className of subclasses) { + const subKey = host.cstr(typeKey({ kind: "classval", className })); + const matched = B.tmp(); + B.line(`${matched} = call zeroext i1 @scr_dyn_class_is(ptr %d, ptr ${subKey})`); + const yes = B.newLabel("sub.yes"); + const no = B.newLabel("sub.no"); + B.condBr(matched, yes, no); + B.startBlock(yes); + const sub = B.tmp(); + B.line(`${sub} = call ptr @scr_dyn_class_check(ptr %d, ptr ${subKey}, ptr %path)`); + B.terminate(`ret ptr ${sub}`); + B.startBlock(no); + } + } const checked = B.tmp(); B.line( `${checked} = call ptr @scr_dyn_class_check(ptr %d, ptr ${host.cstr(key)}, ptr %path)`, diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index d8ccc15b7..34631cf53 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -10769,8 +10769,99 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { "constructing through a class value of an uninstantiated generic type (annotate the slot with a concrete instantiation — e.g. 'new (v: number) => Box')", ); } - const callee = lowerer.lowerExpr(expr.expression); + let callee = lowerer.lowerExpr(expr.expression); if (callee.type.kind === "dyn") return lowerCheckedConstructor(lowerer, expr, callee); + // An array element read (`new T[0]()` over `[Dog, Animal]`, whose + // checker type is the common base) keeps the undefined an index past + // the end reads: the class value is narrowed out with a check, which + // throws a TypeError for undefined. + if (callee.type.kind === "union") { + const arms = lowerer.unions.get(callee.type.unionId)?.arms ?? []; + const classArms = arms.filter((arm) => arm.kind === "classval"); + if ( + classArms.length === 1 && + classArms[0]!.kind === "classval" && + classArms[0]!.className === calleeT.className && + arms.every((arm) => arm.kind === "classval" || arm.kind === "undefinedT") + ) { + const unionT = callee.type; + const helper = lowerer.narrowedArmHelper(unionT.unionId, calleeT, callee.loc); + if (helper) { + const loc = callee.loc; + const name = `%new.callee:${unionT.unionId}`; + if (!lowerer.liftedFns.some((fn) => fn.name === name)) { + const undefinedTag = lowerer.armTag(unionT.unionId, UNDEFINED_T); + const value: IrExpr = { kind: "varRef", localId: "value", type: unionT, loc }; + lowerer.liftedFns.push({ + name, + params: [ + { localId: "value", name: "value", type: unionT }, + { localId: "message", name: "message", type: STRING }, + ], + locals: [ + { id: "value", name: "value", type: unionT, mutable: false }, + { id: "message", name: "message", type: STRING, mutable: false }, + ], + returnType: calleeT, + body: [ + ...(undefinedTag >= 0 + ? [ + { + kind: "if", + cond: { + kind: "unionIsTag", + unionId: unionT.unionId, + tag: undefinedTag, + negated: false, + value, + type: BOOL, + loc, + }, + then: [ + { + kind: "throw", + value: { + kind: "libCall", + fn: "error.new", + args: [{ kind: "varRef", localId: "message", type: STRING, loc }], + type: { kind: "object", className: "%TypeError" }, + loc, + }, + loc, + }, + ], + else_: null, + loc, + } satisfies IrStmt, + ] + : []), + { + kind: "return", + value: lowerer.checkedNarrowCall(helper, value, calleeT, loc), + loc, + }, + ], + loc, + }); + } + callee = { + kind: "call", + callee: name, + args: [ + callee, + { + kind: "strLit", + value: `${expr.expression.getText()} is not a constructor`, + type: STRING, + loc, + }, + ], + type: calleeT, + loc, + }; + } + } + } if (callee.type.kind !== "classval") lowerer.badType(expr.expression, lowerer.typeOf(expr.expression)); lowerer.noteEdge(classValueConstructor(info.def).fn); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6937-class-value-arrays.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6937-class-value-arrays.mjs.json new file mode 100644 index 000000000..eefa82916 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6937-class-value-arrays.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6937-class-value-arrays.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6938-class-value-arrays.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6938-class-value-arrays.ts.json new file mode 100644 index 000000000..ff2a51546 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6938-class-value-arrays.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6938-class-value-arrays.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6937-class-value-arrays.mjs b/tests/corpus/6937-class-value-arrays.mjs new file mode 100644 index 000000000..a563d7514 --- /dev/null +++ b/tests/corpus/6937-class-value-arrays.mjs @@ -0,0 +1,30 @@ +// Arrays of class values that mix a base class and its subclasses: the +// elements construct, compare and name like the classes themselves. +class Animal { + speak() { + return "..."; + } +} +class Dog extends Animal { + speak() { + return "woof"; + } +} +class Cat extends Animal { + speak() { + return "meow"; + } +} +const kinds = [Dog, Cat, Animal]; +console.log(kinds.length, kinds.map((C) => C.name).join()); +console.log(new kinds[0]().speak(), new kinds[1]().speak(), new kinds[2]().speak()); +console.log(kinds[0] === Dog, kinds.indexOf(Cat), kinds.includes(Animal)); +const made = kinds.map((C) => new C()); +console.log(made.map((a) => a.speak()).join(), made[0] instanceof Animal, made[1] instanceof Dog); +try { + new kinds[5](); +} catch (e) { + console.log(e.name, e.message); +} +const byName = { dog: Dog, cat: Cat }; +console.log(new byName.dog().speak(), new byName["cat"]().speak()); diff --git a/tests/corpus/6938-class-value-arrays.ts b/tests/corpus/6938-class-value-arrays.ts new file mode 100644 index 000000000..672700cbf --- /dev/null +++ b/tests/corpus/6938-class-value-arrays.ts @@ -0,0 +1,28 @@ +// Arrays of class values that mix a base class and its subclasses, with the +// element type the checker infers (the base class): elements construct and +// dispatch to the subclass, and an index past the end throws Node's TypeError. +class Shape { + area(): number { + return 0; + } +} +class Square extends Shape { + area(): number { + return 4; + } +} +class Circle extends Shape { + area(): number { + return 3; + } +} +const shapes = [Square, Circle, Shape]; +console.log(shapes.length, new shapes[0]().area(), new shapes[1]().area(), new shapes[2]().area()); +let total = 0; +for (const S of shapes) total += new S().area(); +console.log(total, shapes[1] === Circle, shapes.map((S) => S.name).join()); +try { + new shapes[3](); +} catch (e) { + console.log((e as Error).name, (e as Error).message); +} diff --git a/tests/harness/corpus-costs/6937-class-value-arrays.mjs.json b/tests/harness/corpus-costs/6937-class-value-arrays.mjs.json new file mode 100644 index 000000000..7e905d65a --- /dev/null +++ b/tests/harness/corpus-costs/6937-class-value-arrays.mjs.json @@ -0,0 +1 @@ +{ "plain": 4211, "san": 6383 } diff --git a/tests/harness/corpus-costs/6938-class-value-arrays.ts.json b/tests/harness/corpus-costs/6938-class-value-arrays.ts.json new file mode 100644 index 000000000..76098ce8d --- /dev/null +++ b/tests/harness/corpus-costs/6938-class-value-arrays.ts.json @@ -0,0 +1 @@ +{ "plain": 2399, "san": 4080 } From aaca1f1e2b838e0ef15d91743b06bfd5803d6dc0 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 18:17:48 -0500 Subject: [PATCH 005/259] Count the arguments a function receives when it is called through a value `arguments.length` in a typed function folds to a constant. In a function declaration it was the declared parameter count even when the function is called through a value with more arguments: Node prints 4 for `[1].map(f)` with `function f(v) { return v + arguments.length; }`, the compiled program printed 2. A top-level function declaration that reads `arguments` and that the program uses as a value now gets a count slot. Its value is an adapter that stores the parameter count of the function type the value is passed as (3 for map, 4 for reduce, 2 for a sort comparator) and forwards; the function reads the slot on entry and clears it, so a direct call sees the declared count. Function expressions and declarations passed where the expected function type has optional or rest parameters (a replace callback) are called with a varying count and are refused with SC1090 instead of folding to a wrong count, as are methods, nested functions, and arrows inside a function used as a value. --- .../src/frontend/lowering/argument-counts.ts | 230 ++++++++++++++++++ .../lowering/expressions/identifiers.ts | 13 +- .../lowering/expressions/property-access.ts | 50 ++-- .../src/frontend/lowering/function-context.ts | 3 + .../src/frontend/lowering/lower-functions.ts | 2 + .../compiler/src/frontend/lowering/lowerer.ts | 3 + ...81-function-value-arguments-length.ts.json | 6 + .../function-value-arguments-length.ts.json | 6 + .../7381-function-value-arguments-length.ts | 27 ++ .../function-value-arguments-length.ts | 36 +++ .../function-value-arguments-length.ts.txt | 43 ++++ ...81-function-value-arguments-length.ts.json | 1 + 12 files changed, 398 insertions(+), 22 deletions(-) create mode 100644 packages/compiler/src/frontend/lowering/argument-counts.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7381-function-value-arguments-length.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/function-value-arguments-length.ts.json create mode 100644 tests/corpus/7381-function-value-arguments-length.ts create mode 100644 tests/diagnostics/function-value-arguments-length.ts create mode 100644 tests/harness/__snapshots__/function-value-arguments-length.ts.txt create mode 100644 tests/harness/corpus-costs/7381-function-value-arguments-length.ts.json diff --git a/packages/compiler/src/frontend/lowering/argument-counts.ts b/packages/compiler/src/frontend/lowering/argument-counts.ts new file mode 100644 index 000000000..ec1753160 --- /dev/null +++ b/packages/compiler/src/frontend/lowering/argument-counts.ts @@ -0,0 +1,230 @@ +import * as ts from "../ts7/adapter.js"; +import { bodyReadsArguments } from "../arguments-usage.js"; +import { isJsSourceFile, locOf } from "../program.js"; +import { BOOL, F64, type IrExpr, type IrStmt, type IrType } from "../../ir/ir.js"; +import { varRef } from "../../ir/build.js"; +import { typeKey } from "../type-mapper.js"; +import type { Lowerer } from "./lowerer.js"; +import { isThisParameter } from "./call-signatures.js"; +import { buildFunctionAdapter } from "./coercions/builders.js"; +import { keyedHelperName } from "./stable-names.js"; + +/** `arguments.length` in a top-level function declaration that the program + * also uses as a value. A direct call passes the declared parameters (tsc + * checks the arity), while a call through the value passes the parameter + * count of the function type the value was passed as (`[1].map(f)` calls f + * with 3). The value is an adapter that stores that count in a global slot + * before forwarding; the function reads the slot on entry and clears it, + * so a direct call (the cleared slot) sees the declared count. */ + +/** The count slot of `decl`, or null when its `arguments.length` folds to + * the declared count (or the declaration does not qualify). */ +export function argumentCountSlot(lowerer: Lowerer, decl: ts.FunctionDeclaration): string | null { + const cached = lowerer.argumentCountSlots.get(decl); + if (cached !== undefined) return cached; + let slot: string | null = null; + if ( + decl.body !== undefined && + decl.name !== undefined && + decl.asteriskToken === undefined && + !decl.typeParameters?.nodes.length && + lowerer.isTopLevelFnSymbol(decl.name) && + decl.modifiers?.nodes.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword) !== true && + !isJsSourceFile(ts.getSourceFileOfNode(decl)) && + fixedArity(decl) && + bodyReadsArguments(decl) && + usedAsValue(lowerer, decl) + ) { + const sig = lowerer.fnSigOf(decl.name); + if (sig) { + slot = `%g.argc.${sig.name}`; + lowerer.globalsList.push({ id: slot, name: "%argc", type: F64, mutable: true }); + } + } + lowerer.argumentCountSlots.set(decl, slot); + return slot; +} + +/** Reads `decl`'s count slot into a hidden local on entry and clears it; the + * local holds the declared count when the slot was clear. */ +export function declareArgumentCount( + lowerer: Lowerer, + decl: ts.FunctionDeclaration, + prologue: IrStmt[], +): void { + const slot = argumentCountSlot(lowerer, decl); + if (slot === null) return; + const loc = locOf(decl); + const local = lowerer.declareHiddenLocal("%argc", F64); + const stored = varRef(slot, F64, loc); + prologue.push( + { + kind: "varDecl", + localId: local.id, + init: { + kind: "ternary", + cond: { + kind: "bin", + op: "===", + left: stored, + right: { kind: "numLit", value: 0, type: F64, loc }, + type: BOOL, + loc, + }, + then: { kind: "numLit", value: declaredCount(decl), type: F64, loc }, + else_: stored, + type: F64, + loc, + }, + loc, + }, + { kind: "assign", localId: slot, value: { kind: "numLit", value: 0, type: F64, loc }, loc }, + ); + lowerer.ctx.argumentCount = local; +} + +/** `decl` as a value at `reference`: the plain closure when every call + * through the expected function type passes the declared count, otherwise + * an adapter that stores the expected type's count in the slot first. */ +export function argumentCountValue( + lowerer: Lowerer, + decl: ts.FunctionDeclaration, + reference: ts.Expression, + closure: IrExpr & { type: IrType & { kind: "func" } }, +): IrExpr { + const slot = argumentCountSlot(lowerer, decl); + if (slot === null) return closure; + const count = contextualCallCount(lowerer, reference); + if (count === null || count === "varies") { + lowerer.unsupported( + "SC1090", + reference, + count === null + ? "functions that read 'arguments.length' used as values where no function type is expected (the count each call passes is not known)" + : "functions that read 'arguments.length' used as values where the expected function type has optional or rest parameters (the count varies per call)", + ); + } + const declared = declaredCount(decl); + if (count <= declared) return closure; + const loc = locOf(reference); + const type = closure.type; + const key = `argc:${slot}:${count}:${typeKey(type)}`; + let name = lowerer.arrHofHelpers.get(key); + if (name === undefined) { + name = keyedHelperName(lowerer, "%argc.adapter", key); + lowerer.arrHofHelpers.set(key, name); + const params = type.params.map((t, i) => ({ localId: `p${i}.0`, name: `p${i}`, type: t })); + lowerer.liftedFns.push( + ...buildFunctionAdapter( + name, + type, + type, + params, + [], + [ + { + kind: "assign", + localId: slot, + value: { kind: "numLit", value: count, type: F64, loc }, + loc, + }, + { + kind: "return", + value: { + kind: "callValue", + callee: varRef("f.0", type, loc), + args: params.map((p) => varRef(p.localId, p.type, loc)), + type: type.ret, + loc, + }, + loc, + }, + ], + loc, + ), + ); + } + return { kind: "call", callee: name, args: [closure], type, loc }; +} + +/** The argument count every call through the function type `node` is + * expected as passes: that type's parameter count when it has one call + * signature with a fixed parameter list (a `this` parameter is type-only), + * "varies" when it has optional or rest parameters, null when there is no + * such type. */ +export function contextualCallCount( + lowerer: Lowerer, + node: ts.Expression, +): number | "varies" | null { + const contextual = lowerer.checker.getContextualType(node); + if (contextual === undefined) return null; + const signatures = lowerer.checker.getCallSignatures( + lowerer.checker.getNonNullableType(contextual), + ); + if (signatures.length !== 1) return null; + const declaration = signatures[0]!.declaration; + if (declaration === undefined) return null; + let count = 0; + for (const parameter of (declaration.parameters?.nodes ?? []) as ts.ParameterDeclaration[]) { + if (isThisParameter(parameter)) continue; + if (parameter.questionToken || parameter.initializer || parameter.dotDotDotToken) + return "varies"; + count++; + } + return count; +} + +/** Whether a program reference to the function declaration or method `fn` + * reads it as a value (`xs.map(f)`, `const g = f`, `xs.map(C.parse)`) rather + * than calling it. Export specifiers and default exports only name a + * function; the importing files' references resolve to it and are checked + * the same way. */ +export function usedAsValue( + lowerer: Lowerer, + fn: ts.FunctionDeclaration | ts.MethodDeclaration, +): boolean { + const name = fn.name; + if (!name || !(ts.isIdentifier(name) || ts.isPrivateIdentifier(name))) return false; + const method = ts.isMethodDeclaration(fn); + const symbolAt = (n: ts.Node): ts.Symbol | null | undefined => + method + ? lowerer.checker.getSymbolAtLocation(n) + : lowerer.resolveValueSymbol(n as ts.Identifier); + const symbol = symbolAt(name); + if (!symbol) return false; + let found = false; + for (const sf of lowerer.program.getSourceFiles()) { + if (sf.isDeclarationFile) continue; + ts.walkPreorder(sf, (n) => { + if (found) return "stop"; + if (ts.isTypeNode(n)) return "skip"; + if (n === name || !(ts.isIdentifier(n) || ts.isPrivateIdentifier(n))) return undefined; + if (n.text !== name.text || !n.parent) return undefined; + const parent = n.parent; + // A method is read through its member name (`C.parse`, `this.#m`). + const read = ts.isPropertyAccessExpression(parent) && parent.name === n ? parent : n; + if (method && read === n && !ts.isBindingElement(parent)) return undefined; + const use = read.parent; + if (use && ts.isCallExpression(use) && use.expression === read) return undefined; + if (ts.isExportSpecifier(parent) || ts.isExportAssignment(parent)) return undefined; + if (ts.isImportSpecifier(parent) || ts.isImportClause(parent)) return undefined; + if (symbolAt(n) === symbol) found = true; + return undefined; + }); + if (found) break; + } + return found; +} + +function fixedArity(fn: ts.FunctionLikeDeclaration): boolean { + return fn.parameters.nodes.every( + (p) => + p.questionToken === undefined && + p.initializer === undefined && + p.dotDotDotToken === undefined, + ); +} + +function declaredCount(fn: ts.FunctionLikeDeclaration): number { + return fn.parameters.nodes.filter((p) => !isThisParameter(p)).length; +} diff --git a/packages/compiler/src/frontend/lowering/expressions/identifiers.ts b/packages/compiler/src/frontend/lowering/expressions/identifiers.ts index 63175d50a..ff6f65f26 100644 --- a/packages/compiler/src/frontend/lowering/expressions/identifiers.ts +++ b/packages/compiler/src/frontend/lowering/expressions/identifiers.ts @@ -25,6 +25,7 @@ import { lowerNodeModuleIdentifier } from "../lower-node-module.js"; import { lowerCjsExportsObjectValue } from "../cjs-exports-object.js"; import { captureContextArguments } from "../function-context.js"; import { argumentsOwner, typedArgumentsCandidate } from "../typed-arguments.js"; +import { argumentCountValue } from "../argument-counts.js"; import { isCjsExportTableLiteral, isCjsJsFile, @@ -424,7 +425,17 @@ export function lowerIdentifierExpr(lowerer: Lowerer, expr: ts.Identifier, loc: // semantics); the rest marker carries the trailing dyn-array ABI. const funcType: IrType = funcTypeFromParamShapes(sig.params, sig.returnType); lowerer.requireExactArityValue(expr, expr, sig.params, funcType); - return { kind: "closure", fnName: sig.name, captures: [], type: funcType, loc }; + const closure = { + kind: "closure" as const, + fnName: sig.name, + captures: [], + type: funcType, + loc, + }; + const decl = lowerer.resolveValueSymbol(expr)?.valueDeclaration; + return decl && ts.isFunctionDeclaration(decl) && funcType.kind === "func" + ? argumentCountValue(lowerer, decl, expr, { ...closure, type: funcType }) + : closure; } { // A generic function as a VALUE: monomorphized by flow — the diff --git a/packages/compiler/src/frontend/lowering/expressions/property-access.ts b/packages/compiler/src/frontend/lowering/expressions/property-access.ts index 5df3c7fe0..5f1683ff7 100644 --- a/packages/compiler/src/frontend/lowering/expressions/property-access.ts +++ b/packages/compiler/src/frontend/lowering/expressions/property-access.ts @@ -6,6 +6,7 @@ import { lowerHistogramProperty } from "../builtins/performance.js"; import { staticFunctionNameRead } from "../static-function-names.js"; import { typedArgumentsArity } from "../typed-arguments.js"; import { isThisParameter } from "../call-signatures.js"; +import { argumentCountSlot, contextualCallCount, usedAsValue } from "../argument-counts.js"; import { checkedPrivateValue, localPrivateBrandClass, @@ -669,7 +670,31 @@ export function lowerPropertyAccessExpr( const declared = (fn as ts.FunctionLikeDeclaration).parameters.nodes.filter( (p) => !isThisParameter(p), ).length; - const count = Math.max(declared, contextualArgumentCount(lowerer, fn) ?? 0); + const contextual = contextualArgumentCount(lowerer, fn); + if (contextual === "varies") { + lowerer.unsupported( + "SC1090", + expr, + "'arguments.length' in function expressions passed where the expected function type has optional or rest parameters (the count varies per call)", + ); + } + // A top-level declaration also used as a value reads the count its + // caller stored (argument-counts.ts). + if (ts.isFunctionDeclaration(fn) && lowerer.ctx.argumentCount !== undefined) + return varRef(lowerer.ctx.argumentCount.id, F64, loc); + if ( + (ts.isFunctionDeclaration(fn) || ts.isMethodDeclaration(fn)) && + usedAsValue(lowerer, fn) + ) { + lowerer.unsupported( + "SC1090", + expr, + ts.isFunctionDeclaration(fn) && argumentCountSlot(lowerer, fn) !== null + ? "'arguments.length' in an arrow function inside a function that is also used as a value" + : "'arguments.length' in methods, nested, async and generator functions used as values (a caller of the value can pass more arguments than the function declares)", + ); + } + const count = Math.max(declared, contextual ?? 0); // Calls through the expression's own name pass the declared count, // calls through the wider slot pass more: no constant answers both. if (count > declared && referencesOwnName(lowerer, fn)) { @@ -4469,24 +4494,7 @@ function referencesOwnName(lowerer: Lowerer, fn: ts.Node): boolean { } /** The argument count every caller passes a function expression whose - * value flows into one fixed-arity function type, an array method's - * callback or an annotated slot: that type's parameter count. Null when - * there is no such type or its arity varies. */ -function contextualArgumentCount(lowerer: Lowerer, fn: ts.Node): number | null { - if (!ts.isFunctionExpression(fn)) return null; - const contextual = lowerer.checker.getContextualType(fn); - if (contextual === undefined) return null; - const signatures = lowerer.checker.getCallSignatures( - lowerer.checker.getNonNullableType(contextual), - ); - if (signatures.length !== 1) return null; - const declaration = signatures[0]!.declaration; - if (declaration === undefined) return null; - let count = 0; - for (const parameter of (declaration.parameters?.nodes ?? []) as ts.ParameterDeclaration[]) { - if (isThisParameter(parameter)) continue; - if (parameter.questionToken || parameter.initializer || parameter.dotDotDotToken) return null; - count++; - } - return count; + * value flows into a function type (argument-counts.ts contextualCallCount). */ +function contextualArgumentCount(lowerer: Lowerer, fn: ts.Node): number | "varies" | null { + return ts.isFunctionExpression(fn) ? contextualCallCount(lowerer, fn) : null; } diff --git a/packages/compiler/src/frontend/lowering/function-context.ts b/packages/compiler/src/frontend/lowering/function-context.ts index 92042b7d7..702574b63 100644 --- a/packages/compiler/src/frontend/lowering/function-context.ts +++ b/packages/compiler/src/frontend/lowering/function-context.ts @@ -46,6 +46,9 @@ export interface FnCtx { * rest param): the synthetic trailing dyn-array param `arguments` * reads resolve to. */ argumentsLocal?: IrLocal | null; + /** The count `arguments.length` reads in a top-level function declaration + * that is also used as a value (argument-counts.ts). */ + argumentCount?: IrLocal; /** Arrows inherit the nearest ordinary function's arguments binding. */ inheritsArguments?: boolean; /** A function lowered on demand on top of an unrelated caller's frames diff --git a/packages/compiler/src/frontend/lowering/lower-functions.ts b/packages/compiler/src/frontend/lowering/lower-functions.ts index c1cca9c64..c1682f7c8 100644 --- a/packages/compiler/src/frontend/lowering/lower-functions.ts +++ b/packages/compiler/src/frontend/lowering/lower-functions.ts @@ -1,5 +1,6 @@ import type { ScrDiagnostic } from "../../diagnostics/diagnostic.js"; import { declareTypedArguments } from "./typed-arguments.js"; +import { declareArgumentCount } from "./argument-counts.js"; import { dynUndefinedExpr, varRef } from "../../ir/build.js"; import { everyStmtList, transformStmtList } from "../../ir/traverse.js"; import { bindingNeverReassigned } from "./binding-analysis.js"; @@ -551,6 +552,7 @@ export function lowerFunction(lowerer: Lowerer, decl: ts.FunctionDeclaration): I (sig.params[sig.params.length - 1]!.mode === "dynRest" || sig.params[sig.params.length - 1]!.mode === "arguments"), ); + declareArgumentCount(lowerer, decl, prologue); const bodyBlock = blockBodyOf(decl); if (!bodyBlock) { lowerer.unsupported( diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 4add3193c..4b60d9e1b 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -2335,6 +2335,9 @@ export class Lowerer { * every name destructured from a present source optional. */ readonly runtimeOptionalPatternTypes = new Map(); readonly runtimeOptionalReduceTypes = new Map(); + /** Each function declaration's `arguments.length` count slot, or null + * (argument-counts.ts argumentCountSlot). */ + readonly argumentCountSlots = new Map(); /** Non-null assertions whose value is forwarded into a slot promoted to * hold undefined. `x!` has no runtime effect, so these keep the stored * undefined state instead of trapping before any dereference. */ diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7381-function-value-arguments-length.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7381-function-value-arguments-length.ts.json new file mode 100644 index 000000000..b9e5eacd1 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7381-function-value-arguments-length.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7381-function-value-arguments-length.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/function-value-arguments-length.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/function-value-arguments-length.ts.json new file mode 100644 index 000000000..6aa894918 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/function-value-arguments-length.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/diagnostics/function-value-arguments-length.ts" + ], + "diags": [] +} diff --git a/tests/corpus/7381-function-value-arguments-length.ts b/tests/corpus/7381-function-value-arguments-length.ts new file mode 100644 index 000000000..059ff1487 --- /dev/null +++ b/tests/corpus/7381-function-value-arguments-length.ts @@ -0,0 +1,27 @@ +// `arguments.length` in a function declaration counts the arguments its +// caller passes: a direct call passes the declared parameters, and a call +// through the function as a value passes the parameters of the function +// type it was passed as (3 for map and filter, 4 for reduce, 2 for sort). +function scaled(value: number): number { + return value * 10 + arguments.length; +} +function total(acc: number, value: number): number { + return acc + value + arguments.length; +} +function compare(a: number, b: number): number { + return arguments.length === 2 ? a - b : 0; +} +console.log([1, 2].map(scaled).join(), scaled(3)); +console.log([5, 6].filter(scaled).length, [1, 2].reduce(total, 0), total(1, 2)); +console.log([3, 1, 2].sort(compare).join()); + +function apply(f: (a: number, b: number, c: number) => number): number { + return f(1, 2, 3); +} +console.log(apply(scaled)); + +// A direct call inside a call through the value sees its own count. +function depth(n: number): number { + return n <= 0 ? arguments.length : depth(n - 1) + arguments.length; +} +console.log([2].map(depth).join(), depth(2)); diff --git a/tests/diagnostics/function-value-arguments-length.ts b/tests/diagnostics/function-value-arguments-length.ts new file mode 100644 index 000000000..ab0b53f82 --- /dev/null +++ b/tests/diagnostics/function-value-arguments-length.ts @@ -0,0 +1,36 @@ +// `arguments.length` has no single value when the calls pass varying +// counts: a function expression or declaration passed where the expected +// function type has optional or rest parameters. Methods and nested +// functions used as values, and arrows inside a function used as a value, +// keep the fence. +const replaced = "a-b".replace(/-/, function (match) { + return String(arguments.length) + match; +}); +function call(f: (a: number, b?: number) => number): number { + return f(1, 2); +} +const counted = call(function (a) { + return arguments.length + a; +}); +function offset(value: number): number { + return value + arguments.length; +} +const offsets = call(offset); +class Scale { + static by(value: number): number { + return value * arguments.length; + } +} +const scaled = [2].map(Scale.by); +function outer(): number[] { + function inner(value: number): number { + return value + arguments.length; + } + return [1].map(inner); +} +function deferred(value: number): number { + const read = (): number => arguments.length; + return value + read(); +} +const late = [1].map(deferred); +export { replaced, counted, offsets, scaled, outer, late }; diff --git a/tests/harness/__snapshots__/function-value-arguments-length.ts.txt b/tests/harness/__snapshots__/function-value-arguments-length.ts.txt new file mode 100644 index 000000000..adcb48d2a --- /dev/null +++ b/tests/harness/__snapshots__/function-value-arguments-length.ts.txt @@ -0,0 +1,43 @@ +function-value-arguments-length.ts:7:17 - error SC1090: 'arguments.length' in function expressions passed where the expected function type has optional or rest parameters (the count varies per call) are not supported yet + + 6 | const replaced = "a-b".replace(/-/, function (match) { + 7 | return String(arguments.length) + match; + | ^~~~~~~~~~~~~~~~ + 8 | }); + +function-value-arguments-length.ts:13:10 - error SC1090: 'arguments.length' in function expressions passed where the expected function type has optional or rest parameters (the count varies per call) are not supported yet + + 12 | const counted = call(function (a) { + 13 | return arguments.length + a; + | ^~~~~~~~~~~~~~~~ + 14 | }); + +function-value-arguments-length.ts:18:22 - error SC1090: functions that read 'arguments.length' used as values where the expected function type has optional or rest parameters (the count varies per call) are not supported yet + + 17 | } + 18 | const offsets = call(offset); + | ^~~~~~ + 19 | class Scale { + +function-value-arguments-length.ts:21:20 - error SC1090: 'arguments.length' in methods, nested, async and generator functions used as values (a caller of the value can pass more arguments than the function declares) are not supported yet + + 20 | static by(value: number): number { + 21 | return value * arguments.length; + | ^~~~~~~~~~~~~~~~ + 22 | } + +function-value-arguments-length.ts:32:30 - error SC1090: 'arguments.length' in an arrow function inside a function that is also used as a value is not supported yet + + 31 | function deferred(value: number): number { + 32 | const read = (): number => arguments.length; + | ^~~~~~~~~~~~~~~~ + 33 | return value + read(); + +function-value-arguments-length.ts:33:18 - error SC2004: uses of 'read' inherit the blocker on its declaration + + 32 | const read = (): number => arguments.length; + 33 | return value + read(); + | ^~~~ + 34 | } + + hint: the declaration of 'read' did not compile — fix the diagnostic reported there and these sites clear with it \ No newline at end of file diff --git a/tests/harness/corpus-costs/7381-function-value-arguments-length.ts.json b/tests/harness/corpus-costs/7381-function-value-arguments-length.ts.json new file mode 100644 index 000000000..b4659b9a0 --- /dev/null +++ b/tests/harness/corpus-costs/7381-function-value-arguments-length.ts.json @@ -0,0 +1 @@ +{ "plain": 3400, "san": 3300 } From a3b9cfb1466649db971d5562405a8a01f028c048 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 18:51:14 -0500 Subject: [PATCH 006/259] Find checker reply element ends in C and list dynamic imports from module references --- packages/compiler/native/ts7-json.test.c | 33 +++++ packages/compiler/native/ts7-process.c | 42 +++++++ packages/compiler/native/ts7-process.ffi.json | 3 +- packages/compiler/native/ts7-process.h | 4 + .../src/frontend/lowering/lower-modules.ts | 30 +++-- .../src/frontend/ts7/native-process.ts | 6 + .../src/frontend/ts7/semantic-json.ts | 26 +++- .../test/native-json-value-end.test.ts | 118 ++++++++++++++++++ 8 files changed, 243 insertions(+), 19 deletions(-) create mode 100644 packages/compiler/native/ts7-json.test.c create mode 100644 packages/compiler/test/native-json-value-end.test.ts diff --git a/packages/compiler/native/ts7-json.test.c b/packages/compiler/native/ts7-json.test.c new file mode 100644 index 000000000..b696d77c2 --- /dev/null +++ b/packages/compiler/native/ts7-json.test.c @@ -0,0 +1,33 @@ +/* Reads cases from standard input, each a little-endian u32 length, a u32 + * start and the bytes, and prints scriptc_ts7_json_value_end for each. */ +#include "ts7-process.h" +#include +#include +#ifdef _WIN32 +#include +#include +#endif + +static int read_u32(uint32_t *value) { + unsigned char bytes[4]; + if (fread(bytes, 1, 4, stdin) != 4) return 0; + *value = (uint32_t)bytes[0] | (uint32_t)bytes[1] << 8 | (uint32_t)bytes[2] << 16 | + (uint32_t)bytes[3] << 24; + return 1; +} + +int main(void) { +#ifdef _WIN32 + /* The cases are bytes: text mode would rewrite line endings. */ + _setmode(_fileno(stdin), _O_BINARY); +#endif + uint32_t length, start; + while (read_u32(&length)) { + if (!read_u32(&start)) return 1; + uint8_t *bytes = malloc(length == 0 ? 1 : length); + if (bytes == NULL || fread(bytes, 1, length, stdin) != length) return 1; + printf("%d\n", (int)scriptc_ts7_json_value_end(bytes, length, start)); + free(bytes); + } + return 0; +} diff --git a/packages/compiler/native/ts7-process.c b/packages/compiler/native/ts7-process.c index ea451345d..3333cf4e8 100644 --- a/packages/compiler/native/ts7-process.c +++ b/packages/compiler/native/ts7-process.c @@ -405,3 +405,45 @@ void scriptc_ts7_close(uint32_t handle) { void scriptc_ts7_close_all(void) { while (processes != NULL) scriptc_ts7_close(processes->id); } + +static int json_space(uint8_t byte) { + return byte == ' ' || byte == '\n' || byte == '\r' || byte == '\t'; +} + +int32_t scriptc_ts7_json_value_end(const uint8_t *bytes, size_t size, uint32_t start) { + if (size > INT32_MAX) return -1; + size_t depth = 0; + size_t index = start; + while (index < size) { + uint8_t byte = bytes[index]; + if (byte == '"') { + index++; + for (;;) { + if (index >= size) return -1; + const uint8_t *quote = memchr(bytes + index, '"', size - index); + if (quote == NULL) return -1; + const uint8_t *escape = memchr(bytes + index, '\\', (size_t)(quote - (bytes + index))); + if (escape == NULL) { + index = (size_t)(quote - bytes); + break; + } + index = (size_t)(escape - bytes) + 2; + } + index++; + if (depth == 0) return (int32_t)index; + continue; + } + if (byte == '{' || byte == '[') { + depth++; + } else if (byte == '}' || byte == ']') { + if (depth == 0) return (int32_t)index; + depth--; + if (depth == 0) return (int32_t)(index + 1); + } else if (depth == 0 && (byte == ',' || json_space(byte))) { + return (int32_t)index; + } + index++; + } + if (depth != 0) return -1; + return (int32_t)index; +} diff --git a/packages/compiler/native/ts7-process.ffi.json b/packages/compiler/native/ts7-process.ffi.json index 86f3cb4d2..9a9e39526 100644 --- a/packages/compiler/native/ts7-process.ffi.json +++ b/packages/compiler/native/ts7-process.ffi.json @@ -7,6 +7,7 @@ { "name": "ts7NativePid", "symbol": "scriptc_ts7_pid", "params": ["u32"], "returns": "u32" }, { "name": "ts7NativeClose", "symbol": "scriptc_ts7_close", "params": ["u32"], "returns": "void" }, { "name": "ts7NativeCloseAll", "symbol": "scriptc_ts7_close_all", "params": [], "returns": "void" }, - { "name": "ts7NativeError", "symbol": "scriptc_ts7_error", "params": ["mutable-bytes"], "returns": "i32" } + { "name": "ts7NativeError", "symbol": "scriptc_ts7_error", "params": ["mutable-bytes"], "returns": "i32" }, + { "name": "ts7NativeJsonValueEnd", "symbol": "scriptc_ts7_json_value_end", "params": ["bytes", "u32"], "returns": "i32" } ] } diff --git a/packages/compiler/native/ts7-process.h b/packages/compiler/native/ts7-process.h index 3d2a0ba05..5bc0d11c4 100644 --- a/packages/compiler/native/ts7-process.h +++ b/packages/compiler/native/ts7-process.h @@ -21,5 +21,9 @@ uint32_t scriptc_ts7_pid(uint32_t handle); void scriptc_ts7_close(uint32_t handle); void scriptc_ts7_close_all(void); int32_t scriptc_ts7_error(uint8_t *bytes, size_t size); +/* The index after the JSON value that starts at `start` in a checker reply, + * as jsonValueEnd in semantic-json.ts computes it, or -1 when the reply is + * malformed there. */ +int32_t scriptc_ts7_json_value_end(const uint8_t *bytes, size_t size, uint32_t start); #endif diff --git a/packages/compiler/src/frontend/lowering/lower-modules.ts b/packages/compiler/src/frontend/lowering/lower-modules.ts index 5238333ad..1301a152f 100644 --- a/packages/compiler/src/frontend/lowering/lower-modules.ts +++ b/packages/compiler/src/frontend/lowering/lower-modules.ts @@ -346,24 +346,28 @@ function dynamicImportProgramTargetOf( } /** Every distinct program module a file's `import("literal")` sites name - * (source order, deduped). */ + * (source order, deduped). The parser lists the specifier of every such call + * in the file's module references, in source order after the static imports, + * so the file's nodes need no walk. */ function dynamicProgramImportsOf(program: ts.Program, sf: ts.SourceFile): ts.SourceFile[] { const out: ts.SourceFile[] = []; const seen = new Set(); - ts.walkPreorder(sf, (node) => { + for (const specifier of sf.imports) { + const call = specifier.parent; if ( - ts.isCallExpression(node) && - node.expression.kind === ts.SyntaxKind.ImportKeyword && - node.arguments.nodes[0] !== undefined && - ts.isStringLiteralLike(node.arguments.nodes[0]) - ) { - const dep = dynamicImportProgramTargetOf(program, sf, node.arguments.nodes[0].text); - if (dep && !seen.has(dep)) { - seen.add(dep); - out.push(dep); - } + call === undefined || + !ts.isCallExpression(call) || + call.expression.kind !== ts.SyntaxKind.ImportKeyword || + call.arguments.nodes[0] !== specifier || + !ts.isStringLiteralLike(specifier) + ) + continue; + const dep = dynamicImportProgramTargetOf(program, sf, specifier.text); + if (dep && !seen.has(dep)) { + seen.add(dep); + out.push(dep); } - }); + } return out; } diff --git a/packages/compiler/src/frontend/ts7/native-process.ts b/packages/compiler/src/frontend/ts7/native-process.ts index 7bb523d74..b36189e64 100644 --- a/packages/compiler/src/frontend/ts7/native-process.ts +++ b/packages/compiler/src/frontend/ts7/native-process.ts @@ -1,5 +1,6 @@ import { Ts7Wire, type Ts7WireIo } from "./rpc-wire.js"; import { TS7_FILE_SYSTEM_CALLBACKS } from "./rpc-filesystem.js"; +import { useNativeJsonValueEnd } from "./semantic-json.js"; // Bound by native/ts7-process.ffi.json. This module is a native entry point; // the Node host continues to use rpc-process.ts's public spawn boundary. @@ -25,6 +26,11 @@ declare function ts7NativePid(handle: number): number; declare function ts7NativeClose(handle: number): void; declare function ts7NativeCloseAll(): void; declare function ts7NativeError(bytes: Uint8Array): number; +declare function ts7NativeJsonValueEnd(bytes: Uint8Array, start: number): number; + +// Reply decoding finds element ends with the C scanner. FFI functions can +// only be called, not passed as values, so an arrow function calls it. +useNativeJsonValueEnd((bytes, start) => ts7NativeJsonValueEnd(bytes, start)); // process.exit skips C atexit handlers. Its ordinary exit listener closes // servers too, while the C atexit sweep covers normal native termination. diff --git a/packages/compiler/src/frontend/ts7/semantic-json.ts b/packages/compiler/src/frontend/ts7/semantic-json.ts index 3a04c741f..1a4d93bd6 100644 --- a/packages/compiler/src/frontend/ts7/semantic-json.ts +++ b/packages/compiler/src/frontend/ts7/semantic-json.ts @@ -76,8 +76,8 @@ function malformedReply(): never { /** The index after the JSON value that starts at `start`: an object, an * array, a string or a bare literal. Strings are skipped with their escapes, - * so brackets inside them do not count. */ -function jsonValueEnd(bytes: Uint8Array, start: number): number { + * so brackets inside them do not count. Throws when the value is unclosed. */ +export function jsonValueEnd(bytes: Uint8Array, start: number): number { let depth = 0; let index = start; while (index < bytes.length) { @@ -103,6 +103,22 @@ function jsonValueEnd(bytes: Uint8Array, start: number): number { return index; } +/** The scanner the decoders find value ends with: jsonValueEnd, or the + * native compiler's scanner (useNativeJsonValueEnd). */ +let valueEnd: (bytes: Uint8Array, start: number) => number = jsonValueEnd; + +/** Has the decoders find value ends with `scan`, which returns what + * jsonValueEnd returns, or -1 where jsonValueEnd throws. The native compiler + * installs its C scanner (native/ts7-process.c), which skips the strings that + * make up most reply bytes with memchr. */ +export function useNativeJsonValueEnd(scan: (bytes: Uint8Array, start: number) => number): void { + valueEnd = (bytes, start) => { + const end = scan(bytes, start); + if (end < 0) malformedReply(); + return end; + }; +} + /** The id an object reply starts with (`{"id":N`), or -1 when it starts * otherwise. */ function leadingId(bytes: Uint8Array, start: number, end: number): number { @@ -158,7 +174,7 @@ export function decodeSemanticObject( ): R | null { const start = skipJsonSpace(bytes, 0); if (start === bytes.length) return null; - const end = jsonValueEnd(bytes, start); + const end = valueEnd(bytes, start); if (skipJsonSpace(bytes, end) !== bytes.length) malformedReply(); return replyElement(bytes, start, end, cached, build); } @@ -174,7 +190,7 @@ export function decodeSemanticObjects( let index = skipJsonSpace(bytes, 0); if (index === bytes.length) return null; if (bytes[index] !== OPEN_BRACKET) { - const end = jsonValueEnd(bytes, index); + const end = valueEnd(bytes, index); if ( skipJsonSpace(bytes, end) !== bytes.length || parseJsonSlice(bytes, index, end) !== null @@ -189,7 +205,7 @@ export function decodeSemanticObjects( return result; } for (;;) { - const end = jsonValueEnd(bytes, index); + const end = valueEnd(bytes, index); if (end === index) malformedReply(); result.push(replyElement(bytes, index, end, cached, build)); index = skipJsonSpace(bytes, end); diff --git a/packages/compiler/test/native-json-value-end.test.ts b/packages/compiler/test/native-json-value-end.test.ts new file mode 100644 index 000000000..9d9cc3950 --- /dev/null +++ b/packages/compiler/test/native-json-value-end.test.ts @@ -0,0 +1,118 @@ +import { execFileSync } from "node:child_process"; +import { mkdtempSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { jsonValueEnd } from "../src/frontend/ts7/semantic-json.js"; + +const sources = join(import.meta.dirname, "../native"); +const tempRoot = process.platform === "win32" ? tmpdir() : "/tmp"; + +/** jsonValueEnd's result, or -1 where it throws. */ +function expectedEnd(bytes: Uint8Array, start: number): number { + try { + return jsonValueEnd(bytes, start); + } catch { + return -1; + } +} + +/** A deterministic generator, so a failing case can be reproduced. */ +function random(seed: number): () => number { + let state = seed; + return () => { + state = (state * 1103515245 + 12345) % 2147483648; + return state / 2147483648; + }; +} + +const ALPHABET = ["{", "}", "[", "]", '"', "\\", ",", " ", "\n", "\t", "a", "1", "n", ":", "é"]; + +function cases(): { bytes: Uint8Array; start: number }[] { + const next = random(1); + const out: { bytes: Uint8Array; start: number }[] = []; + const texts = [ + "", + '""', + '"unclosed', + '"\\"', + '"\\\\"', + '"a\\"b"', + '"\\\\\\""', + "null", + "null,", + "123 ", + '{"id":1}', + '{"id":1,"name":"a}b"}', + '[{"id":1},null,{"id":2,"declarations":["1.2./a.ts","3.4./b \\"c\\".ts"]}]', + '{"id":1,"nested":{"list":[1,{"x":"]"}]}}, next', + "{", + "[[]", + "}", + "]", + ",", + " ", + ]; + for (const text of texts) { + const bytes = Buffer.from(text, "utf8"); + for (let start = 0; start <= bytes.length; start++) out.push({ bytes, start }); + } + for (let n = 0; n < 4000; n++) { + let text = ""; + const length = Math.floor(next() * 40); + for (let k = 0; k < length; k++) text += ALPHABET[Math.floor(next() * ALPHABET.length)]; + const bytes = Buffer.from(text, "utf8"); + out.push({ bytes, start: Math.floor(next() * (bytes.length + 1)) }); + } + const reply = JSON.stringify( + Array.from({ length: 200 }, (_, id) => + id % 7 === 0 + ? null + : { id, name: `name ${id} "q" \\ {[`, declarations: [`${id}.80./src/a ${id}.ts`] }, + ), + ); + const bytes = Buffer.from(reply, "utf8"); + for (let start = 0; start < bytes.length; start += 3) out.push({ bytes, start }); + return out; +} + +test("the native scanner finds the value ends jsonValueEnd finds", () => { + const dir = mkdtempSync(join(tempRoot, "scriptc-ts7-json-")); + try { + const harness = join(dir, "scan" + (process.platform === "win32" ? ".exe" : "")); + execFileSync("clang", [ + "-std=c11", + "-Wall", + "-Wextra", + "-Werror", + ...(process.env["SCRIPTC_SAN"] === "1" ? ["-fsanitize=address,undefined"] : []), + join(sources, "ts7-json.test.c"), + join(sources, "ts7-process.c"), + "-o", + harness, + ]); + const all = cases(); + const chunks: Buffer[] = []; + for (const { bytes, start } of all) { + const header = Buffer.alloc(8); + header.writeUInt32LE(bytes.length, 0); + header.writeUInt32LE(start, 4); + chunks.push(header, Buffer.from(bytes)); + } + const output = execFileSync(harness, { input: Buffer.concat(chunks), encoding: "utf8" }); + const actual = output.trim().split(/\r?\n/).map(Number); + expect(actual.length).toBe(all.length); + for (let k = 0; k < all.length; k++) { + const { bytes, start } = all[k]!; + const expected = expectedEnd(bytes, start); + if (actual[k] !== expected) + expect({ text: Buffer.from(bytes).toString("utf8"), start, end: actual[k] }).toEqual({ + text: Buffer.from(bytes).toString("utf8"), + start, + end: expected, + }); + } + } finally { + rmSync(dir, { recursive: true, force: true }); + } +}); From 6bbabd5fc9c680f5a0c4ae352f525672efd997cc Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 20:15:02 -0500 Subject: [PATCH 007/259] Convert dynamic values into nested unions in one pass Converting a dynamic value into a union (`JSON.parse(text) as T`, a cast from `any`) tries the arms in order and builds the first arm whose literal discriminator and whole structure match. The builder of that arm converts its members, and a member typed as another union matched its arm's structure again. Every value was matched once per union around it, so converting a tree of depth d cost about d times as much as a flat one. The arm a union matched now builds as a trusted conversion (scr_dyn_trust_enter). Inside it, a nested union picks an arm without matching the arm's structure, which the enclosing match already checked, when the value's arm is known: a plain object's arm by its literal, when the arms' literals are disjoint and no arm without a literal takes plain objects, or the only arm that takes plain objects (a record) or arrays (an array), as in an optional or nullable member. Other unions, and values that are not plain objects or arrays, match as before. Getters and proxy traps run outside the trusted conversion. Failed conversions throw the same TypeError with the same path. --- packages/compiler/src/backend/llvm/dyn.ts | 103 ++++++++++- .../7160-json-parse-deep-unions.ts.json | 6 + .../7161-dynamic-values-deep-unions.ts.json | 6 + packages/runtime/src/scr_dyn.h | 12 ++ packages/runtime/src/scr_json.c | 22 ++- tests/corpus/7160-json-parse-deep-unions.ts | 164 ++++++++++++++++++ .../corpus/7161-dynamic-values-deep-unions.ts | 73 ++++++++ .../7160-json-parse-deep-unions.ts.json | 1 + .../7161-dynamic-values-deep-unions.ts.json | 1 + tests/harness/dyncheck.test.ts | 98 +++++++++++ 10 files changed, 478 insertions(+), 8 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7160-json-parse-deep-unions.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7161-dynamic-values-deep-unions.ts.json create mode 100644 tests/corpus/7160-json-parse-deep-unions.ts create mode 100644 tests/corpus/7161-dynamic-values-deep-unions.ts create mode 100644 tests/harness/corpus-costs/7160-json-parse-deep-unions.ts.json create mode 100644 tests/harness/corpus-costs/7161-dynamic-values-deep-unions.ts.json diff --git a/packages/compiler/src/backend/llvm/dyn.ts b/packages/compiler/src/backend/llvm/dyn.ts index bb00e4563..40deb1d30 100644 --- a/packages/compiler/src/backend/llvm/dyn.ts +++ b/packages/compiler/src/backend/llvm/dyn.ts @@ -135,6 +135,18 @@ export const DYN_KIND = { SYMBOL: 15, } as const; +/** Union arm kinds whose matchers reject every plain dyn object + * (trustedArmByLiteral). */ +const NON_OBJECT_ARM_KINDS: ReadonlySet = new Set([ + "f64", + "string", + "bool", + "nullT", + "undefinedT", + "bigint", + "symbol", +]); + /** What the dyn helpers need beyond the walker host: interned immortal * unit instances (undefined-armed dynCheck targets build them). */ export interface DynHost extends WalkerHost { @@ -365,8 +377,56 @@ export class LlDyn { B.line(`call void @scr_dyn_build_add(ptr %d, ptr @${name}, ptr ${value})`); } + /** Whether a builder of `def` may pick a plain object's arm by its literal + * discriminator alone inside a trusted build (scr_dyn_trust_enter): the + * arms' literals are disjoint, and every arm without a literal has a kind + * no plain object matches. The value then matched exactly one arm with a + * literal, the arm whose literal it carries. */ + private trustedArmByLiteral(def: IrUnionDef): boolean { + const discriminant = def.discriminant; + if (!discriminant) return false; + const seen = new Set(); + for (const { values } of discriminant.cases) { + for (const value of values) { + const key = `${typeof value}:${String(value)}`; + if (seen.has(key)) return false; + seen.add(key); + } + } + return def.arms.every( + (arm, tag) => + discriminant.cases.some((candidate) => candidate.tag === tag) || + NON_OBJECT_ARM_KINDS.has(arm.kind), + ); + } + + /** Per arm of `def`, the dyn kind of the values a builder may convert into + * that arm without matching its structure inside a trusted build, or null. + * A value there already matched one of the union's arms, so the arm is + * known when it is the only arm that takes values of its kind: the arm + * whose literal a plain object carries (trustedArmByLiteral), or the one + * arm a plain object or an array can match at all. */ + private trustedArmKinds(def: IrUnionDef): (number | null)[] { + const byLiteral = this.trustedArmByLiteral(def); + const objectArms = def.arms.flatMap((arm, tag) => + NON_OBJECT_ARM_KINDS.has(arm.kind) ? [] : [tag], + ); + return def.arms.map((arm, tag) => { + if (def.discriminant?.cases.some((candidate) => candidate.tag === tag)) + return byLiteral ? DYN_KIND.OBJ : null; + if (objectArms.length !== 1 || objectArms[0] !== tag) return null; + if (arm.kind === "array") return DYN_KIND.ARR; + if (arm.kind === "record" && this.host.recordsById.get(arm.shapeId)?.tuple !== true) + return DYN_KIND.OBJ; + return null; + }); + } + /** Branch to a variant only after its literal discriminator and complete - * structure match. Use the same path for predicates and builders. */ + * structure match. Use the same path for predicates and builders. With a + * `trustedKind` (builders, trustedArmKinds), a value of that dyn kind + * inside a trusted build skips the structure match once its literal + * matched. */ private unionArmMatch( B: BlockBuilder, def: IrUnionDef, @@ -374,6 +434,7 @@ export class LlDyn { yes: string, no: string, preserveRefs = false, + trustedKind: number | null = null, ): void { const guard = def.discriminant?.cases.find((candidate) => candidate.tag === tag); if (guard && def.discriminant) { @@ -402,6 +463,19 @@ export class LlDyn { }); B.startBlock(structure); } + if (trustedKind !== null) { + this.host.declare(`declare zeroext i1 @scr_dyn_trusted_build()`); + const kind = this.kindOf(B, "%d"); + const sameKind = B.tmp(); + const trusted = B.tmp(); + const skip = B.tmp(); + B.line(`${sameKind} = icmp eq i32 ${kind}, ${trustedKind}`); + B.line(`${trusted} = call zeroext i1 @scr_dyn_trusted_build()`); + B.line(`${skip} = and i1 ${sameKind}, ${trusted}`); + const full = B.newLabel("du.full"); + B.condBr(skip, yes, full); + B.startBlock(full); + } const matches = B.tmp(); B.line( `${matches} = call zeroext i1 @${this.dynMatchHelper(def.arms[tag]!, preserveRefs)}(ptr %d)`, @@ -2357,11 +2431,22 @@ export class LlDyn { `llvm emitter bug: dynCheck of unknown union ${t.unionId}`, ); // Arms in CANONICAL order, first FULL match wins. The matched - // arm's builder can no longer fail. + // arm's builder can no longer fail, and it runs as a trusted build: + // a nested union inside it picks the arm trustedArmKinds names + // without matching the structure that this match already checked. + const trustedKinds = preserveRefs ? def.arms.map(() => null) : this.trustedArmKinds(def); + const trustedCall = (call: () => void): void => { + host.declare(`declare zeroext i1 @scr_dyn_trust_enter()`); + host.declare(`declare void @scr_dyn_trust_exit(i1 zeroext)`); + const previous = B.tmp(); + B.line(`${previous} = call zeroext i1 @scr_dyn_trust_enter()`); + call(); + B.line(`call void @scr_dyn_trust_exit(i1 zeroext ${previous})`); + }; def.arms.forEach((arm, i) => { const lHit = B.newLabel("dcu.h"); const lNext = B.newLabel("dcu.n"); - this.unionArmMatch(B, def, i, lHit, lNext, preserveRefs); + this.unionArmMatch(B, def, i, lHit, lNext, preserveRefs, trustedKinds[i]!); B.startBlock(lHit); if (arm.kind === "undefinedT" || arm.kind === "nullT") { // A matched unit arm builds nothing: THE interned immortal @@ -2388,14 +2473,22 @@ export class LlDyn { } else if (host.nullableUnions.has(t.unionId)) { // A nullable union is its (+1) reference payload. const x = B.tmp(); - B.line(`${x} = call ptr @${this.dynCheckHelper(arm, preserveRefs)}(ptr %d, ptr %path)`); + trustedCall(() => + B.line( + `${x} = call ptr @${this.dynCheckHelper(arm, preserveRefs)}(ptr %d, ptr %path)`, + ), + ); B.terminate(`ret ptr ${x}`); } else { const rc = vAdapters(host, arm); host.declare(`declare ptr @scr_union_new_ref(i32, ptr, ptr, ptr, ptr)`); const x = B.tmp(); const u = B.tmp(); - B.line(`${x} = call ptr @${this.dynCheckHelper(arm, preserveRefs)}(ptr %d, ptr %path)`); + trustedCall(() => + B.line( + `${x} = call ptr @${this.dynCheckHelper(arm, preserveRefs)}(ptr %d, ptr %path)`, + ), + ); B.line( `${u} = call ptr @scr_union_new_ref(i32 ${i}, ptr ${x}, ptr ${rc.retain}, ptr ${rc.release}, ptr ${traceArg(host, arm)})`, ); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7160-json-parse-deep-unions.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7160-json-parse-deep-unions.ts.json new file mode 100644 index 000000000..fb4ef3c1f --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7160-json-parse-deep-unions.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7160-json-parse-deep-unions.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7161-dynamic-values-deep-unions.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7161-dynamic-values-deep-unions.ts.json new file mode 100644 index 000000000..8ad1579da --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7161-dynamic-values-deep-unions.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7161-dynamic-values-deep-unions.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index 28c2accce..e9b4d33bc 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -1442,6 +1442,18 @@ void scr_dyn_build_note(const ScrDyn *d, const void *builder, void *value); void scr_dyn_build_rekey(const ScrDyn *d, const void *builder, void *value); ScrDyn *scr_dyn_visit_view(const ScrDyn *capsule); +/* A union's builder converts the arm whose literal discriminator and + * complete structure matched; every value inside that arm then matched its + * own type too. Between scr_dyn_trust_enter and scr_dyn_trust_exit (which + * restores the value enter returned), scr_dyn_trusted_build answers true, + * and the builder of a nested union whose arms' literals are disjoint picks + * a plain object's arm by its literal alone instead of matching the arm's + * structure again (dyn.ts unionArmMatch). Code a getter or proxy trap runs + * sees false. */ +bool scr_dyn_trust_enter(void); +void scr_dyn_trust_exit(bool previous); +bool scr_dyn_trusted_build(void); + /* ── native handles in the checked-dynamic tree (SCR_DYN_HANDLE) ──────────────────────── * Per-tag dispatch ops, registered by the handle's owning unit * (scr_http_dyn_install / scr_net_dyn_install — emitted main() calls diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 324233028..9fb5efd6d 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -9245,6 +9245,9 @@ static SCR_TL ScrDynVisitLog scr_dyn_viewed_log; /* The member value a matcher or builder read last and holds one * reference to until it calls scr_dyn_release_held. */ static SCR_TL const ScrDyn *scr_dyn_visit_held; +/* Set while a union's builder builds the arm it matched in full + * (scr_dyn_trust_enter). */ +static SCR_TL bool scr_dyn_trusted; /* Tables up to this many slots stay allocated for the next session. */ #define SCR_DYN_VISIT_KEEP 4096 @@ -9356,13 +9359,15 @@ typedef struct { ScrDynVisitLog built_log, viewed_log; bool track; const ScrDyn *held; + bool trusted; } ScrDynVisitState; static void scr_dyn_visit_suspend(ScrDynVisitState *saved) { - *saved = (ScrDynVisitState){scr_dyn_visit_depth, scr_dyn_matching, scr_dyn_built, - scr_dyn_viewed, scr_dyn_built_log, scr_dyn_viewed_log, - scr_dyn_build_track, scr_dyn_visit_held}; + *saved = (ScrDynVisitState){scr_dyn_visit_depth, scr_dyn_matching, scr_dyn_built, + scr_dyn_viewed, scr_dyn_built_log, scr_dyn_viewed_log, + scr_dyn_build_track, scr_dyn_visit_held, scr_dyn_trusted}; scr_dyn_visit_depth = 0; + scr_dyn_trusted = false; scr_dyn_matching = scr_dyn_built = scr_dyn_viewed = (ScrDynVisitSet){NULL, 0, 0}; scr_dyn_built_log = scr_dyn_viewed_log = (ScrDynVisitLog){NULL, 0, 0}; scr_dyn_visit_held = NULL; @@ -9382,6 +9387,7 @@ static void scr_dyn_visit_resume(const ScrDynVisitState *saved) { scr_dyn_viewed_log = saved->viewed_log; scr_dyn_build_track = saved->track; scr_dyn_visit_held = saved->held; + scr_dyn_trusted = saved->trusted; } /* Calls a getter for a member read, outside any visit session. */ @@ -9404,6 +9410,16 @@ static ScrDyn *scr_dyn_visit_proxy_get(const ScrDyn *d, ScrStr *name) { return result; } +bool scr_dyn_trust_enter(void) { + bool previous = scr_dyn_trusted; + scr_dyn_trusted = true; + return previous; +} + +void scr_dyn_trust_exit(bool previous) { scr_dyn_trusted = previous; } + +bool scr_dyn_trusted_build(void) { return scr_dyn_trusted; } + ScrDyn *scr_dyn_obj_read_held(const ScrDyn *d, const char *key, size_t key_len) { ScrDyn *value = scr_dyn_obj_read(d, key, key_len); scr_dyn_visit_held = value; diff --git a/tests/corpus/7160-json-parse-deep-unions.ts b/tests/corpus/7160-json-parse-deep-unions.ts new file mode 100644 index 000000000..bcbf5ea9d --- /dev/null +++ b/tests/corpus/7160-json-parse-deep-unions.ts @@ -0,0 +1,164 @@ +// JSON.parse into recursive discriminated unions: deep and wide trees, +// unions with primitive arms beside the records, unions whose records share +// a literal, and unions with a record arm that has no literal. + +type Expr = + | { kind: "num"; value: number } + | { kind: "str"; text: string } + | { kind: "add"; left: Expr; right: Expr } + | { kind: "neg"; operand: Expr } + | { kind: "call"; callee: string; args: Expr[] } + | { kind: "cond"; test: Expr; then: Expr; otherwise: Expr | null } + | { kind: "label"; inner: Expr; name?: string }; + +type Stmt = + | { kind: "expr"; expr: Expr } + | { kind: "ret"; value: Expr | undefined } + | { kind: "block"; body: Stmt[] }; + +interface Fn { + name: string; + body: Stmt[]; +} + +function evaluate(e: Expr): number { + switch (e.kind) { + case "num": + return e.value; + case "str": + return e.text.length; + case "add": + return evaluate(e.left) + evaluate(e.right); + case "neg": + return -evaluate(e.operand); + case "call": + return e.args.reduce((sum, arg) => sum + evaluate(arg), e.callee.length); + case "cond": + return evaluate(e.test) !== 0 + ? evaluate(e.then) + : e.otherwise === null + ? 0 + : evaluate(e.otherwise); + case "label": + return evaluate(e.inner) + (e.name?.length ?? 0); + } +} + +function depth(e: Expr): number { + switch (e.kind) { + case "num": + case "str": + return 1; + case "add": + return 1 + Math.max(depth(e.left), depth(e.right)); + case "neg": + return 1 + depth(e.operand); + case "call": + return 1 + e.args.reduce((max, arg) => Math.max(max, depth(arg)), 0); + case "cond": + return 1 + Math.max(depth(e.test), depth(e.then), e.otherwise ? depth(e.otherwise) : 0); + case "label": + return 1 + depth(e.inner); + } +} + +function chain(n: number): string { + let text = '{"kind":"num","value":1}'; + for (let i = 0; i < n; i++) { + text = + i % 3 === 0 + ? `{"kind":"neg","operand":${text}}` + : i % 3 === 1 + ? `{"kind":"add","left":${text},"right":{"kind":"str","text":"ab"}}` + : `{"kind":"label","inner":${text}${i % 2 === 0 ? ',"name":"x"' : ""}}`; + } + return text; +} + +function wide(n: number, level: number): string { + if (level === 0) return `{"kind":"num","value":${n}}`; + const args: string[] = []; + for (let i = 0; i < 3; i++) args.push(wide(n + i, level - 1)); + return `{"kind":"call","callee":"f${level}","args":[${args.join(",")}]}`; +} + +for (const n of [0, 1, 5, 60, 400]) { + const e = JSON.parse(chain(n)) as Expr; + console.log("chain", n, e.kind, depth(e), evaluate(e)); +} + +const tree = JSON.parse(wide(1, 6)) as Expr; +console.log("wide", depth(tree), evaluate(tree)); + +const cond = JSON.parse( + '{"kind":"cond","test":{"kind":"num","value":0},"then":{"kind":"num","value":5},"otherwise":null}', +) as Expr; +console.log("cond", evaluate(cond)); + +const fn = JSON.parse( + JSON.stringify({ + name: "main", + body: [ + { kind: "expr", expr: JSON.parse(chain(30)) }, + { kind: "block", body: [{ kind: "ret", value: JSON.parse(wide(2, 3)) }, { kind: "ret" }] }, + ], + }), +) as Fn; +let statements = 0; +const visit = (stmts: Stmt[]): void => { + for (const s of stmts) { + statements++; + if (s.kind === "block") visit(s.body); + else if (s.kind === "expr") console.log("stmt expr", evaluate(s.expr)); + else console.log("stmt ret", s.value === undefined ? "none" : evaluate(s.value)); + } +}; +visit(fn.body); +console.log("statements", statements); + +// Primitive arms beside the records. +type Value = number | string | null | { kind: "list"; items: Value[] } | { kind: "pair"; first: Value; second: Value }; +function show(v: Value): string { + if (v === null || typeof v === "number" || typeof v === "string") return JSON.stringify(v); + return v.kind === "list" ? `[${v.items.map(show).join(" ")}]` : `(${show(v.first)} . ${show(v.second)})`; +} +const values = JSON.parse( + '[1,"a",null,{"kind":"list","items":[2,{"kind":"pair","first":"b","second":{"kind":"list","items":[null,3]}}]}]', +) as Value[]; +console.log("values", values.map(show).join(" | ")); + +// Two records that share a literal: the arm follows the other fields. +type Shared = { kind: "a"; count: number } | { kind: "a"; name: string } | { kind: "b"; next: Shared[] }; +function describe(s: Shared): string { + if (s.kind === "b") return `b(${s.next.map(describe).join(",")})`; + return "count" in s ? `count=${s.count}` : `name=${s.name}`; +} +const shared = JSON.parse( + '{"kind":"b","next":[{"kind":"a","count":1},{"kind":"a","name":"n"},{"kind":"b","next":[{"kind":"a","name":"m"}]}]}', +) as Shared; +console.log("shared", describe(shared)); + +// A record arm without a literal beside records that have one. +type Loose = { kind: "leaf"; value: number } | { kind: "node"; children: Loose[] } | { weight: number; child: Loose }; +function total(l: Loose): number { + if ("weight" in l) return l.weight * total(l.child); + return l.kind === "leaf" ? l.value : l.children.reduce((sum, c) => sum + total(c), 0); +} +const loose = JSON.parse( + '{"kind":"node","children":[{"kind":"leaf","value":2},{"weight":3,"child":{"kind":"node","children":[{"kind":"leaf","value":4},{"weight":2,"child":{"kind":"leaf","value":5}}]}}]}', +) as Loose; +console.log("loose", total(loose)); + +// Optional and nullable members holding records and arrays of records. +type Box = { value: number; child?: Box; rest: Box[] | null }; +function weigh(b: Box): number { + let total = b.value; + if (b.child !== undefined) total += 2 * weigh(b.child); + for (const r of b.rest ?? []) total += weigh(r); + return total; +} +let boxText = '{"value":1,"rest":null}'; +for (let i = 2; i < 120; i++) + boxText = i % 2 === 0 ? `{"value":${i},"child":${boxText},"rest":null}` : `{"value":${i},"rest":[${boxText},{"value":1,"rest":[]}]}`; +const boxes = JSON.parse(boxText) as Box; +console.log("boxes", weigh(boxes) % 1000003); diff --git a/tests/corpus/7161-dynamic-values-deep-unions.ts b/tests/corpus/7161-dynamic-values-deep-unions.ts new file mode 100644 index 000000000..3e85b2689 --- /dev/null +++ b/tests/corpus/7161-dynamic-values-deep-unions.ts @@ -0,0 +1,73 @@ +// Dynamic values cast into recursive discriminated unions: trees built as +// untyped objects, trees that mix typed records into untyped ones, and casts +// of the same values twice. + +type Node = + | { kind: "leaf"; value: number } + | { kind: "pair"; left: Node; right: Node } + | { kind: "wrap"; inner: Node; tag: string } + | { kind: "many"; items: Node[] }; + +function sum(n: Node): number { + switch (n.kind) { + case "leaf": + return n.value; + case "pair": + return sum(n.left) + sum(n.right); + case "wrap": + return sum(n.inner) + n.tag.length; + case "many": + return n.items.reduce((total, item) => total + sum(item), 0); + } +} + +function height(n: Node): number { + switch (n.kind) { + case "leaf": + return 1; + case "pair": + return 1 + Math.max(height(n.left), height(n.right)); + case "wrap": + return 1 + height(n.inner); + case "many": + return 1 + n.items.reduce((max, item) => Math.max(max, height(item)), 0); + } +} + +function untyped(levels: number): any { + let node: any = { kind: "leaf", value: 1 }; + for (let i = 0; i < levels; i++) { + node = + i % 3 === 0 + ? { kind: "wrap", inner: node, tag: "t" } + : i % 3 === 1 + ? { kind: "pair", left: node, right: { kind: "leaf", value: i } } + : { kind: "many", items: [node, { kind: "leaf", value: 2 }] }; + } + return node; +} + +for (const levels of [0, 2, 10, 90, 300]) { + const value: unknown = untyped(levels); + const node = value as Node; + console.log("untyped", levels, node.kind, height(node), sum(node)); +} + +// Typed records inside an untyped tree. +const typedLeaf: Node = { kind: "leaf", value: 7 }; +const typedPair: Node = { kind: "pair", left: typedLeaf, right: { kind: "leaf", value: 3 } }; +const mixed: any = { kind: "many", items: [typedPair, untyped(20), { kind: "wrap", inner: typedLeaf, tag: "xy" }] }; +const fromMixed = mixed as Node; +console.log("mixed", height(fromMixed), sum(fromMixed)); + +// The same untyped value cast twice gives equal trees. +const again: any = untyped(40); +const first = again as Node; +const second = again as Node; +console.log("twice", sum(first) === sum(second), height(first), height(second)); + +// A tree that changes between casts. +const changing: any = { kind: "pair", left: { kind: "leaf", value: 1 }, right: untyped(5) }; +console.log("before", sum(changing as Node)); +changing.left = { kind: "wrap", inner: { kind: "leaf", value: 10 }, tag: "abc" }; +console.log("after", sum(changing as Node)); diff --git a/tests/harness/corpus-costs/7160-json-parse-deep-unions.ts.json b/tests/harness/corpus-costs/7160-json-parse-deep-unions.ts.json new file mode 100644 index 000000000..5d8e97d52 --- /dev/null +++ b/tests/harness/corpus-costs/7160-json-parse-deep-unions.ts.json @@ -0,0 +1 @@ +{ "plain": 11054, "san": 84858 } diff --git a/tests/harness/corpus-costs/7161-dynamic-values-deep-unions.ts.json b/tests/harness/corpus-costs/7161-dynamic-values-deep-unions.ts.json new file mode 100644 index 000000000..bf9a71561 --- /dev/null +++ b/tests/harness/corpus-costs/7161-dynamic-values-deep-unions.ts.json @@ -0,0 +1 @@ +{ "plain": 5843, "san": 57446 } diff --git a/tests/harness/dyncheck.test.ts b/tests/harness/dyncheck.test.ts index 6a2d4dc61..fca914792 100644 --- a/tests/harness/dyncheck.test.ts +++ b/tests/harness/dyncheck.test.ts @@ -427,6 +427,104 @@ console.log("unreachable", t.label); ); }); + test("nested unions: a failure inside a matched arm names the union that holds it", async () => { + // A union's builder converts the arm that matched; the unions nested in + // it pick their arms by literal or by the kind of value only one arm + // takes. A value that fails anywhere below fails its outermost union, + // whose arms the message names. + const r = await compileAndRun( + "deep-discriminated", + `type Expr = + | { kind: "num"; value: number } + | { kind: "str"; text: string } + | { kind: "add"; left: Expr; right: Expr } + | { kind: "call"; callee: string; args: Expr[] } + | { kind: "neg"; operand: Expr } + | { kind: "opt"; inner: Expr | undefined; label?: string }; +type Stmt = + | { kind: "expr"; expr: Expr } + | { kind: "ret"; value: Expr | null } + | { kind: "block"; body: Stmt[] }; +type Fn = { name: string; body: Stmt[] }; + +function attempt(label: string, text: string, as: "expr" | "stmt" | "fn" | "list"): void { + try { + if (as === "expr") { + const e = JSON.parse(text) as Expr; + console.log(label, "ok", e.kind); + } else if (as === "stmt") { + const s = JSON.parse(text) as Stmt; + console.log(label, "ok", s.kind); + } else if (as === "fn") { + const f = JSON.parse(text) as Fn; + console.log(label, "ok", f.name, f.body.length); + } else { + const l = JSON.parse(text) as Expr[]; + console.log(label, "ok", l.length); + } + } catch (e) { + console.log(label, "error", (e as Error).message); + } +} + +const deep = (leaf: string, depth: number): string => { + let s = leaf; + for (let i = 0; i < depth; i++) s = \`{"kind":"neg","operand":\${s}}\`; + return s; +}; +attempt("valid", deep('{"kind":"num","value":1}', 20), "expr"); +attempt("deep wrong field", deep('{"kind":"num","value":"x"}', 5), "expr"); +attempt("deep unknown kind", deep('{"kind":"nope","value":1}', 5), "expr"); +attempt("deep string node", deep('"text"', 5), "expr"); +attempt("deep missing field", deep('{"kind":"add","left":{"kind":"num","value":1}}', 4), "expr"); +attempt("deep array arg", deep('{"kind":"call","callee":"f","args":[{"kind":"num","value":1},{"kind":"str","text":2}]}', 3), "expr"); +attempt("optional inner", deep('{"kind":"opt","inner":{"kind":"num","value":true}}', 3), "expr"); +attempt("optional label", deep('{"kind":"opt","inner":{"kind":"num","value":1},"label":3}', 3), "expr"); +attempt("stmt deep", '{"kind":"block","body":[{"kind":"expr","expr":' + deep('{"kind":"num","value":null}', 3) + '}]}', "stmt"); +attempt("ret null", '{"kind":"ret","value":null}', "stmt"); +attempt("fn deep", '{"name":"f","body":[{"kind":"ret","value":' + deep('{"kind":"str","text":5}', 4) + '}]}', "fn"); +attempt("list element", '[{"kind":"num","value":1},' + deep('{"kind":"num"}', 2) + "]", "list"); +attempt("kind not string", deep('{"kind":3,"value":1}', 2), "expr"); +attempt("valid list", '[' + deep('{"kind":"num","value":1}', 3) + ',{"kind":"str","text":"t"}]', "list"); + +type Box = { value: number; child?: Box; rest: Box[] | null }; +function box(label: string, text: string): void { + try { + const b = JSON.parse(text) as Box; + console.log(label, "ok", b.value); + } catch (e) { + console.log(label, "error", (e as Error).message); + } +} +box("box valid", '{"value":1,"rest":null,"child":{"value":2,"rest":[{"value":3,"rest":null}]}}'); +box("box deep child", '{"value":1,"rest":null,"child":{"value":2,"rest":null,"child":{"value":"x","rest":null}}}'); +box("box deep rest", '{"value":1,"rest":[{"value":2,"rest":[{"value":3,"rest":[1]}]}]}'); +box("box child array", '{"value":1,"rest":null,"child":[]}'); +`, + ); + expect(r.exitCode).toBe(0); + expect(r.stdout.trimEnd().split("\n")).toEqual([ + "valid ok neg", + "deep wrong field error expected object | object | object | object | object | object at $, got object", + "deep unknown kind error expected object | object | object | object | object | object at $, got object", + "deep string node error expected object | object | object | object | object | object at $, got object", + "deep missing field error expected object | object | object | object | object | object at $, got object", + "deep array arg error expected object | object | object | object | object | object at $, got object", + "optional inner error expected object | object | object | object | object | object at $, got object", + "optional label error expected object | object | object | object | object | object at $, got object", + "stmt deep error expected object | object | object at $, got object", + "ret null ok ret", + "fn deep error expected object | object | object at $.body[0], got object", + "list element error expected object | object | object | object | object | object at $[1], got object", + "kind not string error expected object | object | object | object | object | object at $, got object", + "valid list ok 2", + "box valid ok 1", + "box deep child error expected number at $.child.child.value, got string", + "box deep rest error expected object at $.rest[0].rest[0].rest[0], got number", + "box child array error expected object | undefined at $.child, got array", + ]); + }); + test("array where a record is expected names the mismatch at the root", async () => { const r = await compileAndRun( "root-kind", From 4780e7ef22243c28fd0ac36a25e19fdd9e87e08a Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Thu, 22 Oct 2026 21:01:18 -0500 Subject: [PATCH 008/259] Compare optional string index reads as code units `s[i]` with an index the frontend cannot prove in bounds reads the character or undefined: temps for the string and the index, a range and integer test, and a string-or-undefined union. A lexer that tests `src[pos] === " "` or `c < "a"` on `const c = src[pos]` compared that union with a union-wrapped literal, or boxed it for a dynamic comparison, on every character. Tests of such a read against a literal of one UTF-16 code unit now compare `i === Math.floor(i) ? s.charCodeAt(i) : NaN` instead. Undefined, like NaN, equals no literal and fails every ordered comparison, and charCodeAt reads NaN out of range. A read of plain operands is evaluated in place; others keep the read's temps. An immutable local initialized from such a read, and used only in those tests, in tests for undefined and in a switch over one-unit cases, holds the code unit. Tests for undefined become NaN tests. Copies of the local, such as a switch's discriminant temp, follow it. The code-unit reads are charCodeAt reads, so a loop version can cover them. --- .../compiler/src/ir/char-unit-locals.test.ts | 70 +++ packages/compiler/src/ir/char-unit-locals.ts | 404 ++++++++++++++++-- .../7304-string-optional-char-reads.ts.json | 6 + .../corpus/7304-string-optional-char-reads.ts | 121 ++++++ .../7304-string-optional-char-reads.ts.json | 1 + 5 files changed, 567 insertions(+), 35 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7304-string-optional-char-reads.ts.json create mode 100644 tests/corpus/7304-string-optional-char-reads.ts create mode 100644 tests/harness/corpus-costs/7304-string-optional-char-reads.ts.json diff --git a/packages/compiler/src/ir/char-unit-locals.test.ts b/packages/compiler/src/ir/char-unit-locals.test.ts index ad16ecebd..378a7f0df 100644 --- a/packages/compiler/src/ir/char-unit-locals.test.ts +++ b/packages/compiler/src/ir/char-unit-locals.test.ts @@ -96,3 +96,73 @@ console.log(escapes("a b", 1), rebound(" x", 0), wide("ab", 0), against("a", "b expect(fn(after, name)).toBe(fn(before, name)); } }); + +/** The union and dynamic comparisons left in the function. */ +function unionTests(f: IrFunction): string[] { + const out: string[] = []; + everyStmtList(f.body, { + stmt: () => true, + expr: (e) => { + if (e.kind === "unionEq" || e.kind === "unionIsTag") out.push(e.kind); + if (e.kind === "libCall" && e.fn === "js.compare") out.push(e.fn); + if (e.kind === "strIntrinsic") out.push(e.method); + return true; + }, + }); + return out; +} + +test("optional character reads compare their code unit", async () => { + const mod = holdCharLocalsAsUnits( + await lower(` +function scan(src: string, pos: number): number { + let n = 0; + if (src[pos] === " ") n += 1; + if (src[pos] !== "x") n += 2; + if (src[pos] < "a" || "z" <= src[pos]) n += 4; + if (src[pos + 1] === "=") n += 8; + const c = src[pos]; + if (c === undefined) n += 16; + if (c !== undefined && c > "m") n += 32; + switch (c) { + case "q": + n += 64; + break; + case "r": + n += 128; + } + return n; +} +console.log(scan("a b", 1), scan("q", 0), scan("ab", 5), scan("r=", 0.5)); +`), + ); + const scan = fn(mod, "scan"); + // Only charCodeAt reads remain: no union tests, dynamic compares, charAt + // or length reads. + expect(new Set(unionTests(scan))).toEqual(new Set(["charCodeAt"])); + expect(scan.locals.find((l) => l.name === "c")!.type).toEqual({ kind: "f64" }); +}); + +test("optional character reads with other uses stay reads", async () => { + const before = await lower(` +function kept(src: string, pos: number): string { + const c = src[pos]; + if (c === " ") return "space"; + return c ?? "end"; +} +function longer(src: string, pos: number): boolean { + return src[pos] === "ab"; +} +function twice(src: string, pos: number): boolean { + return src[pos * 2] === undefined; +} +console.log(kept("a b", 1), kept("ab", 0), kept("", 3), longer("ab", 0), twice("ab", 1)); +`); + const after = holdCharLocalsAsUnits(before); + for (const name of ["kept", "longer", "twice"]) { + expect(fn(before, name)).toBeDefined(); + expect(unionTests(fn(after, name))).toEqual(unionTests(fn(before, name))); + } + // The local's own test still reads it as a union. + expect(unionTests(fn(after, "kept"))).toContain("unionEq"); +}); diff --git a/packages/compiler/src/ir/char-unit-locals.ts b/packages/compiler/src/ir/char-unit-locals.ts index 4008f4e1e..9917a148b 100644 --- a/packages/compiler/src/ir/char-unit-locals.ts +++ b/packages/compiler/src/ir/char-unit-locals.ts @@ -11,8 +11,11 @@ import { mapExprChildren, mapStmtChildren } from "./traverse.js"; type CharAt = IrExpr & { kind: "strIntrinsic" }; type UnitUse = IrExpr & { kind: "strEq" | "strCmp" }; +type CompareOp = "<" | "<=" | ">" | ">="; -/** Character locals held as their code unit. +const FLIPPED = { "<": ">", "<=": ">=", ">": "<", ">=": "<=" } as const; + +/** Character reads and locals held as their code unit. * * `const c = s[i]` (or `s.charAt(i)`) followed only by tests such as * `c === " "`, `c >= "a" && c <= "z"` or `switch (c) { case "x": ... }` @@ -28,7 +31,16 @@ type UnitUse = IrExpr & { kind: "strEq" | "strCmp" }; * * Only immutable unboxed string locals qualify, with one declaration whose * initializer is a one-argument charAt, and with no other mention of the - * local. */ + * local. + * + * `s[i]` with an index not proven in bounds reads the character or + * undefined (an optional read, see `optionalCharRead`). Its tests against + * one-unit literals compare `i === Math.floor(i) ? s.charCodeAt(i) : NaN` + * instead: undefined, like NaN, equals no literal and fails every ordered + * comparison, and charCodeAt answers NaN out of range. That holds both for + * the read in place and for an immutable local initialized from it and + * used only in such tests and in tests for undefined, which become NaN + * tests. */ export function holdCharLocalsAsUnits(mod: IrModule): IrModule { let changed = false; const functions = mod.functions.map((fn) => { @@ -39,11 +51,275 @@ export function holdCharLocalsAsUnits(mod: IrModule): IrModule { return changed ? { ...mod, functions } : mod; } +/** The read of `s[i]` for an index not proven in bounds: temps for the + * string and the index, then the string's charAt when the index is an + * integer in [0, length) and undefined otherwise. */ +interface OptionalCharRead { + /** The temps' declarations, and whether both operands are plain (local + * reads and literals), which the unit read may evaluate in place. */ + temps: [IrStmt & { kind: "varDecl" }, IrStmt & { kind: "varDecl" }]; + plain: boolean; + receiver: IrExpr; + index: IrExpr; + unionId: string; + stringTag: number; + undefinedTag: number; +} + +function optionalCharRead(e: IrExpr): OptionalCharRead | null { + if (e.kind !== "seqExpr" || e.stmts.length !== 2 || e.diverges) return null; + const [str, idx] = e.stmts; + if (str?.kind !== "varDecl" || idx?.kind !== "varDecl" || !str.init || !idx.init) return null; + const isStr = (x: IrExpr): boolean => x.kind === "varRef" && x.localId === str.localId; + const isIdx = (x: IrExpr): boolean => x.kind === "varRef" && x.localId === idx.localId; + const r = e.result; + if (r.kind !== "ternary") return null; + const c = r.cond; + if (c.kind !== "logical" || c.op !== "&&" || c.left.kind !== "logical" || c.left.op !== "&&") + return null; + const [low, high, whole] = [c.left.left, c.left.right, c.right]; + if ( + !( + low.kind === "bin" && + low.op === ">=" && + isIdx(low.left) && + low.right.kind === "numLit" && + low.right.value === 0 + ) || + !( + high.kind === "bin" && + high.op === "<" && + isIdx(high.left) && + high.right.kind === "strIntrinsic" && + high.right.method === "length" && + isStr(high.right.receiver) + ) || + !( + whole.kind === "bin" && + whole.op === "===" && + isIdx(whole.left) && + whole.right.kind === "libCall" && + whole.right.fn === "math.floor" && + whole.right.args.length === 1 && + isIdx(whole.right.args[0]!) + ) + ) + return null; + const [present, absent] = [r.then, r.else_]; + if (present.kind !== "unionWrap" || absent.kind !== "unionWrap") return null; + if (present.unionId !== absent.unionId) return null; + const read = present.value; + if ( + read.kind !== "strIntrinsic" || + read.method !== "charAt" || + !isStr(read.receiver) || + read.args.length !== 1 || + !isIdx(read.args[0]!) + ) + return null; + if (absent.value.kind !== "unitLit" || absent.value.unit !== "undefined") return null; + return { + temps: [str, idx], + plain: plainOperand(str.init) && plainOperand(idx.init), + receiver: str.init, + index: idx.init, + unionId: present.unionId, + stringTag: present.tag, + undefinedTag: absent.tag, + }; +} + +function plainOperand(e: IrExpr): boolean { + return e.kind === "varRef" || e.kind === "numLit" || e.kind === "strLit"; +} + +/** `i === Math.floor(i) ? s.charCodeAt(i) : NaN`: the code unit of an + * optional read, or NaN where it reads undefined. Plain operands are read + * in place; others keep the read's temps, so each is evaluated once. */ +function unitRead(read: OptionalCharRead, loc: IrExpr["loc"]): IrExpr { + if (!read.plain) { + const [str, idx] = read.temps; + const temp = (decl: IrStmt & { kind: "varDecl" }, type: IrExpr["type"]): IrExpr => ({ + kind: "varRef", + localId: decl.localId, + type, + loc, + }); + return { + kind: "seqExpr", + stmts: [{ ...str }, { ...idx }], + result: unitOf(temp(str, read.receiver.type), () => temp(idx, F64), loc), + type: F64, + loc, + }; + } + return unitOf({ ...read.receiver }, () => ({ ...read.index }), loc); +} + +function unitOf(receiver: IrExpr, index: () => IrExpr, loc: IrExpr["loc"]): IrExpr { + return { + kind: "ternary", + cond: { + kind: "bin", + op: "===", + left: index(), + right: { kind: "libCall", fn: "math.floor", args: [index()], type: F64, loc }, + type: BOOL, + loc, + }, + then: { + kind: "strIntrinsic", + method: "charCodeAt", + receiver, + args: [index()], + type: F64, + loc, + }, + else_: { kind: "numLit", value: NaN, type: F64, loc }, + type: F64, + loc, + }; +} + +/** A test of an operand that reads one character or undefined, against a + * literal of one code unit or for undefined, and the same test on the + * operand's code unit. `tagsOf` gives the operand's union tags. */ +interface UnitTest { + operand: IrExpr; + /** The test reads the unit twice. */ + twice?: boolean; + test: (unit: () => IrExpr) => IrExpr; +} + +function optionalUnitTest( + e: IrExpr, + tagsOf: (operand: IrExpr) => OptionalCharRead | null, +): UnitTest | null { + const loc = e.loc; + const compare = (op: "===" | "!==" | CompareOp, u: IrExpr, right: IrExpr): IrExpr => ({ + kind: "bin", + op, + left: u, + right, + type: BOOL, + loc, + }); + const num = (value: number): IrExpr => ({ kind: "numLit", value, type: F64, loc }); + if (e.kind === "unionEq" && !e.sameValue) { + for (const [operand, other] of [ + [e.left, e.right], + [e.right, e.left], + ] as const) { + const tags = tagsOf(operand); + if ( + tags && + tags.unionId === e.unionId && + other.kind === "unionWrap" && + other.tag === tags.stringTag && + other.value.kind === "strLit" && + other.value.value.length === 1 + ) { + const code = other.value.value.charCodeAt(0); + return { + operand, + test: (unit) => compare(e.negated ? "!==" : "===", unit(), num(code)), + }; + } + // `case undefined:` of a switch: undefined is a NaN unit. + if ( + tags && + tags.unionId === e.unionId && + other.kind === "unionWrap" && + other.tag === tags.undefinedTag && + other.value.kind === "unitLit" && + other.value.unit === "undefined" + ) + return { + operand, + twice: true, + test: (unit) => compare(e.negated ? "===" : "!==", unit(), unit()), + }; + } + return null; + } + if (e.kind === "libCall" && e.fn === "js.compare" && e.args.length === 3) { + const [a, b, opArg] = e.args as [IrExpr, IrExpr, IrExpr]; + if (opArg.kind !== "strLit" || !(opArg.value in FLIPPED)) return null; + const op = opArg.value as CompareOp; + const literalOf = (x: IrExpr): number | null => + x.kind === "libCall" && + x.fn === "js.fromStr" && + x.args.length === 1 && + x.args[0]!.kind === "strLit" && + x.args[0]!.value.length === 1 + ? x.args[0]!.value.charCodeAt(0) + : null; + const operandOf = (x: IrExpr): IrExpr | null => + x.kind === "libCall" && + x.fn === "js.fromDyn" && + x.args.length === 1 && + x.args[0]!.kind === "dynFrom" && + tagsOf(x.args[0]!.value) + ? x.args[0]!.value + : null; + // The comparison with the operand on the left. + const left = operandOf(a); + const right = operandOf(b); + const code = left ? literalOf(b) : right ? literalOf(a) : null; + const operand = left ?? right; + if (operand === null || code === null) return null; + const ordered = left ? op : FLIPPED[op]; + return { operand, test: (unit) => compare(ordered, unit(), num(code)) }; + } + if (e.kind === "unionIsTag") { + const tags = tagsOf(e.value); + if (!tags || tags.unionId !== e.unionId) return null; + if (e.tag !== tags.undefinedTag && e.tag !== tags.stringTag) return null; + // Undefined is a NaN unit; a character is any other. + const present = (e.tag === tags.stringTag) !== e.negated; + return { + operand: e.value, + twice: true, + test: (unit) => compare(present ? "===" : "!==", unit(), unit()), + }; + } + return null; +} + function rewriteFunction(fn: IrFunction): IrFunction { + const locals = new Map(fn.locals.map((l) => [l.id, l])); const candidates = new Set( - fn.locals.filter((l) => !l.mutable && !l.boxed && l.type.kind === "string").map((l) => l.id), + fn.locals + .filter( + (l) => !l.mutable && !l.boxed && (l.type.kind === "string" || l.type.kind === "union"), + ) + .map((l) => l.id), ); - if (candidates.size === 0) return fn; + // The optional reads candidate union locals are declared from, directly + // or as copies of another such local (a switch's discriminant temp). + const reads = new Map(); + const copyOf = new Map(); + const collect = (value: unknown): void => { + if (Array.isArray(value)) for (const item of value) collect(item); + else if (value !== null && typeof value === "object") { + const node = value as Record; + if (node.kind === "varDecl" && candidates.has(node.localId as string) && node.init) { + const id = node.localId as string; + const init = node.init as IrExpr; + const read = optionalCharRead(init); + if (read) reads.set(id, read); + else if (init.kind === "varRef" && reads.has(init.localId)) { + reads.set(id, reads.get(init.localId)!); + copyOf.set(id, init.localId); + } + } + for (const key in node) if (key !== "loc") collect(node[key]); + } + }; + collect(fn.body); + const localTags = (operand: IrExpr): OptionalCharRead | null => + operand.kind === "varRef" ? (reads.get(operand.localId) ?? null) : null; + // Every mention of a candidate, in any field, against the mentions the // rewrite understands. const mentions = new Map(); @@ -59,7 +335,7 @@ function rewriteFunction(fn: IrFunction): IrFunction { for (const item of value) count(item); } else if (value !== null && typeof value === "object") { const node = value as Record; - const id = understoodMention(node); + const id = understoodMention(node, locals, reads, localTags); if (id !== null && candidates.has(id)) { note(understood, id); if (node.kind === "varDecl") note(declarations, id); @@ -68,15 +344,26 @@ function rewriteFunction(fn: IrFunction): IrFunction { } }; count(fn.body); + // A copy is held only with its source, and the source's mention in the + // copy's initializer is understood only while the copy is held. const held = new Set(); for (const id of candidates) - if ( - declarations.get(id) === 1 && - (mentions.get(id) ?? 0) > 0 && - mentions.get(id) === understood.get(id) - ) - held.add(id); - if (held.size === 0) return fn; + if (declarations.get(id) === 1 && (mentions.get(id) ?? 0) > 0) held.add(id); + for (let settled = false; !settled;) { + settled = true; + for (const id of held) { + let copies = 0; + for (const [copy, source] of copyOf) if (source === id && held.has(copy)) copies++; + const source = copyOf.get(id); + if ( + mentions.get(id) !== (understood.get(id) ?? 0) + copies || + (source !== undefined && !held.has(source)) + ) { + held.delete(id); + settled = false; + } + } + } const unitRef = (id: string, loc: IrExpr["loc"]): IrExpr => ({ kind: "varRef", @@ -84,10 +371,19 @@ function rewriteFunction(fn: IrFunction): IrFunction { type: F64, loc, }); + // Operands of optional unit tests: held union locals and reads in place. + const operandTags = (operand: IrExpr): OptionalCharRead | null => + operand.kind === "varRef" + ? held.has(operand.localId) + ? localTags(operand) + : null + : optionalCharRead(operand); + let changed = false; const rewriteExpr = (e: IrExpr): IrExpr => { if (e.kind === "strEq" || e.kind === "strCmp") { const use = unitUse(e); if (use && held.has(use.id)) { + changed = true; const code: IrExpr = { kind: "numLit", value: use.code, type: F64, loc: e.loc }; const c = unitRef(use.id, e.loc); if (e.kind === "strEq") @@ -100,9 +396,7 @@ function rewriteFunction(fn: IrFunction): IrFunction { loc: e.loc, }; // The comparison with the local on the left. - const op = use.left - ? e.op - : ({ "<": ">", "<=": ">=", ">": "<", ">=": "<=" } as const)[e.op]; + const op = use.left ? e.op : FLIPPED[e.op]; if (op === ">" || op === ">=") return { kind: "bin", op, left: c, right: code, type: BOOL, loc: e.loc }; const negation: IrExpr = { @@ -116,21 +410,43 @@ function rewriteFunction(fn: IrFunction): IrFunction { return { kind: "unary", op: "!", operand: negation, type: BOOL, loc: e.loc }; } } + const optional = optionalUnitTest(e, operandTags); + if (optional) { + const operand = optional.operand; + if (operand.kind === "varRef") { + changed = true; + return optional.test(() => unitRef(operand.localId, e.loc)); + } + // A read that keeps its temps declares them once: one unit read. + const read = optionalCharRead(operand)!; + if (read.plain || !optional.twice) { + changed = true; + return optional.test(() => unitRead(read, operand.loc)); + } + } return mapExprChildren(e, rewriteExpr, rewriteStmt); }; const rewriteStmt = (s: IrStmt): IrStmt => { - if (s.kind === "varDecl" && held.has(s.localId) && s.init?.kind === "strIntrinsic") - return { - ...s, - init: { - ...s.init, - method: "charCodeAt", - receiver: rewriteExpr(s.init.receiver), - args: s.init.args.map(rewriteExpr), - type: F64, - }, - }; - if (s.kind === "switch" && s.disc.kind === "varRef" && held.has(s.disc.localId)) + if (s.kind === "varDecl" && held.has(s.localId) && s.init) { + changed = true; + const source = copyOf.get(s.localId); + if (source !== undefined) return { ...s, init: unitRef(source, s.init.loc) }; + const read = reads.get(s.localId); + if (read) return { ...s, init: unitRead(read, s.init.loc) }; + if (s.init.kind === "strIntrinsic") + return { + ...s, + init: { + ...s.init, + method: "charCodeAt", + receiver: rewriteExpr(s.init.receiver), + args: s.init.args.map(rewriteExpr), + type: F64, + }, + }; + } + if (s.kind === "switch" && s.disc.kind === "varRef" && held.has(s.disc.localId)) { + changed = true; return { ...s, disc: unitRef(s.disc.localId, s.disc.loc), @@ -143,11 +459,14 @@ function rewriteFunction(fn: IrFunction): IrFunction { body: c.body.map(rewriteStmt), })), }; + } return mapStmtChildren(s, rewriteExpr, rewriteStmt); }; + const body = fn.body.map(rewriteStmt); + if (!changed) return fn; return { ...fn, - body: fn.body.map(rewriteStmt), + body, locals: fn.locals.map((l) => (held.has(l.id) ? unitLocal(l) : l)), }; } @@ -157,22 +476,37 @@ function unitLocal(local: IrLocal): IrLocal { return { ...local, type: F64 }; } -/** The local a node mentions in a form the rewrite handles: the - * declaration from a one-argument charAt, a one-unit test, or a switch - * over one-unit cases. */ -function understoodMention(node: Record): string | null { +/** The local a node mentions in a form the rewrite handles: a string + * local's declaration from a one-argument charAt, one-unit test, or switch + * over one-unit cases; a union local's declaration from an optional read, + * or its test against a one-unit literal or for undefined. */ +function understoodMention( + node: Record, + locals: ReadonlyMap, + reads: ReadonlyMap, + localTags: (operand: IrExpr) => OptionalCharRead | null, +): string | null { const n = node as unknown as IrExpr | IrStmt; - if (n.kind === "varDecl") return n.init && isCharAt(n.init) ? n.localId : null; + if (n.kind === "varDecl") { + if (!n.init) return null; + const local = locals.get(n.localId); + if (local?.type.kind === "string") return isCharAt(n.init) ? n.localId : null; + const read = reads.get(n.localId); + return read && local?.type.kind === "union" && local.type.unionId === read.unionId + ? n.localId + : null; + } if (n.kind === "strEq" || n.kind === "strCmp") return unitUse(n)?.id ?? null; if (n.kind === "switch") { - if (n.disc.kind !== "varRef") return null; + if (n.disc.kind !== "varRef" || n.disc.type.kind !== "string") return null; if (!n.cases.some((c) => c.test !== null)) return null; const units = n.cases.every( (c) => c.test === null || (c.test.kind === "strLit" && c.test.value.length === 1), ); return units ? n.disc.localId : null; } - return null; + const optional = optionalUnitTest(n as IrExpr, localTags); + return optional?.operand.kind === "varRef" ? optional.operand.localId : null; } function isCharAt(e: IrExpr): e is CharAt { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7304-string-optional-char-reads.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7304-string-optional-char-reads.ts.json new file mode 100644 index 000000000..36ea6f8ec --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7304-string-optional-char-reads.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7304-string-optional-char-reads.ts" + ], + "diags": [] +} diff --git a/tests/corpus/7304-string-optional-char-reads.ts b/tests/corpus/7304-string-optional-char-reads.ts new file mode 100644 index 000000000..13222219d --- /dev/null +++ b/tests/corpus/7304-string-optional-char-reads.ts @@ -0,0 +1,121 @@ +// s[i] with an index not proven in bounds, tested against one-unit +// literals: equality, inequality and ordered comparisons on either side, +// peeks at i - 1 and i + 1, tests for undefined, switches, character +// locals with and without other uses, fractional, negative, -0, NaN and +// infinite indices, reads past the end, a two-unit literal, Object.is, a +// class-based lexer with its position in a field, and ASCII, Latin-1, BMP, +// surrogate pairs, lone surrogates and empty strings. + +class Lexer { + pos = 0; + src: string; + constructor(src: string) { + this.src = src; + } + skipSpaces(): void { + const src = this.src; + let pos = this.pos; + while (pos < src.length && (src[pos] === " " || src[pos] === "\t")) pos++; + this.pos = pos; + } + word(): string { + const src = this.src; + const start = this.pos; + let pos = start; + while (pos < src.length) { + const c = src[pos]; + if ((c < "a" || c > "z") && (c < "0" || c > "9")) break; + pos++; + } + this.pos = pos; + return src.slice(start, pos); + } + operator(): string { + const src = this.src; + const c = src[this.pos]; + switch (c) { + case "=": + this.pos += src[this.pos + 1] === "=" ? 2 : 1; + return src[this.pos - 1] === "=" && src[this.pos - 2] === "=" ? "==" : "="; + case "+": + case "-": + this.pos++; + return c; + case undefined: + return ""; + default: + this.pos++; + return "?"; + } + } + tokens(): string[] { + const out: string[] = []; + while (this.pos < this.src.length) { + this.skipSpaces(); + const w = this.word(); + if (w !== "") out.push(w); + else if (this.pos < this.src.length) out.push(this.operator()); + } + return out; + } +} + +function tests(src: string, pos: number): string { + const bits: number[] = []; + bits.push(src[pos] === " " ? 1 : 0, src[pos] !== "x" ? 1 : 0); + bits.push(src[pos] < "a" ? 1 : 0, src[pos] <= "a" ? 1 : 0); + bits.push(src[pos] > "a" ? 1 : 0, src[pos] >= "a" ? 1 : 0); + bits.push("m" < src[pos] ? 1 : 0, "m" >= src[pos] ? 1 : 0); + bits.push(src[pos + 1] === "b" ? 1 : 0, src[pos - 1] > "\0" ? 1 : 0); + bits.push(src[pos] === undefined ? 1 : 0, src[pos] !== undefined ? 1 : 0); + bits.push(src[pos * 2] === undefined ? 1 : 0, src[pos] === "ab" ? 1 : 0); + bits.push(Object.is(src[pos], "a") ? 1 : 0); + return bits.join(""); +} + +function local(src: string, pos: number): string { + const c = src[pos]; + let n = 0; + if (c === undefined) n += 1; + if (c !== undefined && c >= "a") n += 2; + if ("z" > c) n += 4; + switch (c) { + case "é": + n += 8; + break; + case "b": + n += 16; + break; + default: + n += 32; + } + return String(n); +} + +function kept(src: string, pos: number): string { + const c = src[pos]; + if (c === " ") return "space"; + return c ?? "end"; +} + +const samples = ["abc", "", " ", "a b\tc", "café", "日本 語", "😀x", "\uD800z", "ab=b"]; +const indices = [0, 1, 2, 3, -1, -0, 0.5, 1.5, NaN, Infinity, 10]; +for (const s of samples) { + const row: string[] = []; + for (const i of indices) row.push(`${tests(s, i)}:${local(s, i)}:${kept(s, i)}`); + console.log(JSON.stringify(s), row.join(" ")); +} + +const programs = [ + "let x = a + b - c", + " alpha==beta gamma = delta1 ", + "x=y==z+", + "", + "abc é def", + "\tq\t=\t9", +]; +for (const p of programs) console.log(JSON.stringify(p), JSON.stringify(new Lexer(p).tokens())); + +let text = ""; +for (let k = 0; k < 30; k++) text += (k % 4 === 0 ? "==" : "w" + k) + " "; +console.log(new Lexer(text).tokens().length, new Lexer(text).tokens().slice(0, 6).join(",")); diff --git a/tests/harness/corpus-costs/7304-string-optional-char-reads.ts.json b/tests/harness/corpus-costs/7304-string-optional-char-reads.ts.json new file mode 100644 index 000000000..207668232 --- /dev/null +++ b/tests/harness/corpus-costs/7304-string-optional-char-reads.ts.json @@ -0,0 +1 @@ +{ "plain": 2700, "san": 4200 } From 56f70c47b1ae251451c8f1bb42da5fd859c5493e Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Thu, 22 Oct 2026 20:06:30 -0700 Subject: [PATCH 009/259] Answer 'in' on native Node handles from their declared members `"closeAllConnections" in server` (the feature test servers use before calling it) was refused for an http.Server and the other native handles. A member Node's declarations give the class is on its prototype, so the test now answers true after evaluating the receiver. Undeclared names keep the refusal, since internal fields can still be present. Co-Authored-By: Claude Opus 5.5 --- .../lowering/expressions/relational.ts | 48 +++++++++++++++++++ .../server/cases/http-in-members/driver.mjs | 7 +++ .../server/cases/http-in-members/main.ts | 18 +++++++ 3 files changed, 73 insertions(+) create mode 100644 tests/fixtures/server/cases/http-in-members/driver.mjs create mode 100644 tests/fixtures/server/cases/http-in-members/main.ts diff --git a/packages/compiler/src/frontend/lowering/expressions/relational.ts b/packages/compiler/src/frontend/lowering/expressions/relational.ts index 0eb8ae653..edec5ba5f 100644 --- a/packages/compiler/src/frontend/lowering/expressions/relational.ts +++ b/packages/compiler/src/frontend/lowering/expressions/relational.ts @@ -1762,6 +1762,25 @@ export function lowerInExpression( }; } } + // A native Node handle (an http.Server, a socket, a child process...): + // a member Node's declarations give the class is on its prototype, so + // `"closeAllConnections" in server` answers true. Undeclared names can + // still be real (internal `_`-prefixed fields), so they keep the fence. + if ( + NATIVE_HANDLE_KINDS.has(recv.type.kind) && + nodeDeclaredMember(lowerer, lowerer.typeOf(expr.right), key) + ) { + const answer: IrExpr = { kind: "boolLit", value: true, type: BOOL, loc }; + return isSafeToDiscard(recv) + ? answer + : { + kind: "seqExpr", + stmts: [{ kind: "exprStmt", expr: recv, loc }], + result: answer, + type: BOOL, + loc, + }; + } if (recv.type.kind !== "record") { lowerer.unsupported( "SC1090", @@ -2059,3 +2078,32 @@ function dynInstanceOfRefusal(lowerer: Lowerer, expr: ts.BinaryExpression): stri const line = ts.getLineAndCharacterOfPosition(sf, diag.loc.start).line + 1; return `${diag.message} [${diag.code} at ${diag.loc.file}:${line}]`; } + +/** IR kinds of native Node handles whose members come from Node's own + * declarations. */ +const NATIVE_HANDLE_KINDS: ReadonlySet = new Set([ + "netServer", + "netSocket", + "httpReq", + "httpRes", + "httpClientReq", + "child", + "dgramSocket", + "fsWatcher", + "http2Session", + "http2Stream", +]); + +/** Whether every constituent of `t` declares a required member `key` in + * a declaration file (Node's @types/node). */ +function nodeDeclaredMember(lowerer: Lowerer, t: ts.Type, key: string): boolean { + const parts = t.isUnionType() ? ts.constituentTypes(t) : [t]; + return parts.every((part) => { + const prop = lowerer.checker.getPropertyOfType(part, key); + if (prop === undefined || (prop.flags & ts.SymbolFlags.Optional) !== 0) return false; + return ( + prop.declarations.length > 0 && + prop.declarations.every((d) => ts.getSourceFileOfNode(d).isDeclarationFile) + ); + }); +} diff --git a/tests/fixtures/server/cases/http-in-members/driver.mjs b/tests/fixtures/server/cases/http-in-members/driver.mjs new file mode 100644 index 000000000..9c989bb70 --- /dev/null +++ b/tests/fixtures/server/cases/http-in-members/driver.mjs @@ -0,0 +1,7 @@ +import http from "node:http"; +const port = Number(process.argv[2]); +http.get({ host: "127.0.0.1", port, path: "/" }, (res) => { + let body = ""; + res.on("data", (c) => (body += c)); + res.on("end", () => console.log(res.statusCode, body)); +}); diff --git a/tests/fixtures/server/cases/http-in-members/main.ts b/tests/fixtures/server/cases/http-in-members/main.ts new file mode 100644 index 000000000..80babfc13 --- /dev/null +++ b/tests/fixtures/server/cases/http-in-members/main.ts @@ -0,0 +1,18 @@ +// `in` tests on native Node handles answer from Node's declared members. +import { createServer } from "node:http"; +import type { AddressInfo } from "node:net"; + +const server = createServer((req, res) => { + console.log("request", "method" in req, "setHeader" in res, "writeHead" in res); + res.end("ok"); +}); +console.log("closeAllConnections" in server, "closeIdleConnections" in server, "listen" in server); +server.listen(0, "127.0.0.1", () => { + process.stderr.write(`PORT ${(server.address() as AddressInfo).port}\n`); +}); +server.on("request", () => { + setTimeout(() => { + if ("closeAllConnections" in server) server.closeAllConnections(); + server.close(() => console.log("closed")); + }, 10); +}); From 9c9fb6531a8857425049ffb700069ff008c3e730 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 03:07:29 -0500 Subject: [PATCH 010/259] Replay class objects with their base names, and restore the inspector after a refusal - The emitter journal that forked workers merge (#1919) records each class object entry whole, and the entries carry baseNameSym beside nameSym. The replay cast named only nameSym, which the native compiler refuses (SC1090), so the self-hosted LLVM emitter did not build. - An inspection refusal (the 'not supported yet' Error of insp.dyn) propagates out of the emitted inspect helpers before they close their frames and before util.inspect's layout options are restored. The open frames, their indentation and the custom layout then shaped every later console.log and util.inspect. A top-level render through helpers that can reach a checked-dynamic view, a generator or a class instance now runs in a lifted wrapper that takes insp.mark first and calls insp.unwind in a finally. A render under breakLength, compact or sorted restores the default layout in a finally the same way. - A non-enumerable accessor that %o shows, and any accessor of a checked-dynamic object, renders as [Getter], [Setter] or [Getter/Setter], as Node prints it, instead of its value slot. - Under %o, an array's non-enumerable own properties follow its named ones in brackets (`[ 1, 2, [length]: 2, foo: 'x', [hid]: 3 ]`), as Node prints them; corpus 6357 covers [length] ahead of named properties. --- packages/compiler/src/backend/llvm/emitter.ts | 2 +- .../compiler/src/backend/llvm/lib-shared.ts | 2 + .../src/frontend/lowering/lower-inspect.ts | 174 +++++++++++++++--- .../compiler/src/ir/builtin-signatures.ts | 5 + packages/runtime/src/scr_inspect.c | 73 ++++++-- packages/runtime/src/scr_inspect.h | 4 + tests/corpus/6357-format-o-hidden.ts | 18 +- tests/harness/dyncheck.test.ts | 66 +++++++ 8 files changed, 306 insertions(+), 38 deletions(-) diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 004277a24..7c6fd7a47 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -4859,7 +4859,7 @@ export class LlEmitter { return; } case "classObj": - addEntry(this.classObjs, key, value as { nameSym: string }); + addEntry(this.classObjs, key, value as { nameSym: string; baseNameSym: string | null }); return; case "retainWrapper": addEntry(this.nullableUnions.retainWrappers, key, value as string); diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index dfc5327e2..fc4b1337b 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -663,6 +663,8 @@ export const LIB_FN_SYMS: Record = { "insp.moreItems": "scr_insp_more_items", "insp.end": "scr_insp_end", "insp.nestedBegin": "scr_insp_nested_begin", + "insp.mark": "scr_insp_mark", + "insp.unwind": "scr_insp_unwind", "insp.nestedEnd": "scr_insp_nested_end", // Circular references over cycle-capable composites (Node's // seen/circular machinery — none of these throw; refWrap borrows its diff --git a/packages/compiler/src/frontend/lowering/lower-inspect.ts b/packages/compiler/src/frontend/lowering/lower-inspect.ts index cda4d2972..349fec120 100644 --- a/packages/compiler/src/frontend/lowering/lower-inspect.ts +++ b/packages/compiler/src/frontend/lowering/lower-inspect.ts @@ -900,6 +900,112 @@ export function inspectExpr( recurse: IrExpr, depth: IrExpr, loc: SrcLoc, +): IrExpr { + const render = inspectExprBody(lowerer, t, value, recurse, depth, loc); + // A top-level render through emitted helpers that can reach a refusal + // (the 'not supported yet' Error of insp.dyn) unwinds the inspector to + // its state before the render on every exit: the Error propagates out of + // the helpers before they close their frames. + if ( + render.kind !== "call" || + recurse.kind !== "numLit" || + recurse.value !== 0 || + !inspectMayRefuse(lowerer, t) + ) + return render; + return withInspectUnwind(lowerer, render, t, loc); +} + +/** A top-level helper render (`call helper(v, r, d)`) through a lifted + * wrapper that takes insp.mark first and runs insp.unwind however the + * render ends: `try { return helper(v, r, d); } finally { insp.unwind(); }`. + * A seqExpr cannot hold the try. */ +function withInspectUnwind( + lowerer: Lowerer, + render: IrExpr & { kind: "call" }, + t: IrType, + loc: SrcLoc, +): IrExpr { + const key = `unwind:${render.callee}`; + let name = lowerer.inspectHelpers.get(key); + if (name === undefined) { + name = keyedHelperName(lowerer, "%util.inspUnwound", key); + lowerer.inspectHelpers.set(key, name); + const params = [ + { localId: "v.0", name: "v", type: t }, + { localId: "r.0", name: "r", type: F64 }, + { localId: "d.0", name: "d", type: F64 }, + ]; + const call = (fn: "insp.mark" | "insp.unwind"): IrStmt => ({ + kind: "exprStmt", + expr: { kind: "libCall", fn, args: [], type: VOID, loc }, + loc, + }); + lowerer.liftedFns.push({ + name, + params, + returnType: STRING, + locals: params.map((p) => ({ id: p.localId, name: p.name, type: p.type, mutable: false })), + body: [ + call("insp.mark"), + { + kind: "tryCatch", + tryBody: [ + { + kind: "return", + value: { + kind: "call", + callee: render.callee, + args: params.map((p) => varRef(p.localId, p.type, loc)), + type: STRING, + loc, + }, + loc, + }, + ], + catchBody: null, + catchLocalId: null, + finallyBody: [call("insp.unwind")], + loc, + }, + ], + loc, + }); + } + return { ...render, callee: name }; +} + +/** Whether inspecting a `t` value can end in an inspection refusal: `t` + * or a type reachable from it is a checked-dynamic value, a generator, a + * Dirent row or a class instance, which can render through a + * checked-dynamic view. */ +function inspectMayRefuse(lowerer: Lowerer, t: IrType): boolean { + const seen = new Set(); + const walk = (u: IrType): boolean => { + if (u.kind === "dyn" || u.kind === "generator") return true; + if (u.kind === "record") { + const shape = lowerer.shapes.get(u.shapeId); + if (shape && isDirentShape(shape)) return true; + } + // A class instance can render through its checked-dynamic view, which + // a helper built earlier may only learn at the end of lowering + // (classInspectsAddedProperties). + if (u.kind === "object") return true; + const k = typeKey(u); + if (seen.has(k)) return false; + seen.add(k); + return typeConstituents(lowerer, u).some(walk); + }; + return walk(t); +} + +function inspectExprBody( + lowerer: Lowerer, + t: IrType, + value: IrExpr, + recurse: IrExpr, + depth: IrExpr, + loc: SrcLoc, ): IrExpr { // A Dirent row renders through its dyn view: Node's `Dirent { ... }` // with the Symbol(type) key. @@ -2350,40 +2456,55 @@ function parseInspectOptions( /** A render under non-default breakLength/compact/sorted: the value is evaluated * first, the layout applies to this render only, and the defaults return - * afterwards. */ + * however the render ends, an inspection refusal included. The render runs + * in a lifted function, `(v) => { insp.layout(...); try { return render(v); } + * finally { insp.layout(80, 3, false); } }`, since a seqExpr cannot hold the + * try; `tag` names the render for the function's key. */ function withInspectLayout( lowerer: Lowerer, options: InspectOptions, value: IrExpr, + tag: string, render: (value: IrExpr) => IrExpr, loc: SrcLoc, ): IrExpr { if (options.breakLength === 80 && options.compact === 3 && !options.sorted) return render(value); - const input = lowerer.declareHiddenLocal("%inspectInput", value.type); - const text = lowerer.declareHiddenLocal("%inspectText", STRING); - const layout = (breakLength: number, compact: number, sorted: boolean): IrStmt => ({ - kind: "exprStmt", - expr: { - kind: "libCall", - fn: "insp.layout", - args: [numLit(breakLength, loc), numLit(compact, loc), boolLit(sorted, loc)], - type: VOID, + const key = `layout:${tag}:${typeKey(value.type)}:${options.breakLength}:${options.compact}:${options.sorted}:${options.depth}`; + let name = lowerer.inspectHelpers.get(key); + if (name === undefined) { + name = keyedHelperName(lowerer, "%util.inspLayout", key); + lowerer.inspectHelpers.set(key, name); + const layout = (breakLength: number, compact: number, sorted: boolean): IrStmt => ({ + kind: "exprStmt", + expr: { + kind: "libCall", + fn: "insp.layout", + args: [numLit(breakLength, loc), numLit(compact, loc), boolLit(sorted, loc)], + type: VOID, + loc, + }, loc, - }, - loc, - }); - return { - kind: "seqExpr", - stmts: [ - { kind: "varDecl", localId: input.id, init: value, loc }, - layout(options.breakLength, options.compact, options.sorted), - { kind: "varDecl", localId: text.id, init: render(varRef(input.id, value.type, loc)), loc }, - layout(80, 3, false), - ], - result: varRef(text.id, STRING, loc), - type: STRING, - loc, - }; + }); + lowerer.liftedFns.push({ + name, + params: [{ localId: "v.0", name: "v", type: value.type }], + returnType: STRING, + locals: [{ id: "v.0", name: "v", type: value.type, mutable: false }], + body: [ + layout(options.breakLength, options.compact, options.sorted), + { + kind: "tryCatch", + tryBody: [{ kind: "return", value: render(varRef("v.0", value.type, loc)), loc }], + catchBody: null, + catchLocalId: null, + finallyBody: [layout(80, 3, false)], + loc, + }, + ], + loc, + }); + } + return { kind: "call", callee: name, args: [value], type: STRING, loc }; } /** `util.inspect(fn)` / `util.inspect(Cls)` over a DIRECT identifier @@ -2500,6 +2621,7 @@ export function lowerInspectValue( lowerer, options, value, + "typedArray", (input) => ({ kind: "libCall", fn: "insp.typedArray", @@ -2525,6 +2647,7 @@ export function lowerInspectValue( lowerer, options, value, + "dirDyn", (input) => ({ kind: "libCall", fn: "console.dirDyn", @@ -2539,6 +2662,7 @@ export function lowerInspectValue( lowerer, options, value, + "inspect", (input) => inspectExpr(lowerer, value.type, input, numLit(0, loc), numLit(depth, loc), loc), loc, ); diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index a316b5dd5..6dc8a6826 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -4414,6 +4414,11 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ * `prefix inner` re-indented at the caller's level (+1). */ "insp.nestedBegin": { argTypes: [], result: VOID }, "insp.nestedEnd": { argTypes: [STRING, STRING], result: STRING }, + /** Around a top-level render that an inspection refusal can end: mark + * records the inspector's frame and nesting depth, unwind (in the + * render's finally) closes what the render left open above it. */ + "insp.mark": { argTypes: [], result: VOID }, + "insp.unwind": { argTypes: [], result: VOID }, /** node:string_decoder's utf8 StringDecoder (scr_string.c): the decoder * value is a one-field record whose f64 PACKS the pending partial * sequence (count + up to 3 raw bytes — Node buffers at most 3 for diff --git a/packages/runtime/src/scr_inspect.c b/packages/runtime/src/scr_inspect.c index 9875a7077..e63c1cec1 100644 --- a/packages/runtime/src/scr_inspect.c +++ b/packages/runtime/src/scr_inspect.c @@ -646,6 +646,54 @@ ScrStr *scr_insp_nested_end(ScrStr *prefix, ScrStr *inner) { return ib_take(&out); } +/* The inspector's state at the start of a top-level render. A render that + * an inspection refusal ends leaves its compiled frames open: the Error + * propagates out of the emitted helpers before their scr_insp_end and + * scr_insp_nested_end calls. The emitted render takes a mark first and + * unwinds to it on every exit (lower-inspect.ts), so later renders start + * from the state the refused one found. */ +typedef struct { + size_t nframes; + size_t nsaved; + size_t nseen; + size_t indent; + double cur_depth; +} InspMark; + +static SCR_TL InspMark *g_marks; +static SCR_TL size_t g_nmarks; +static SCR_TL size_t g_marks_cap; + +void scr_insp_mark(void) { + if (g_nmarks == g_marks_cap) { + g_marks_cap = g_marks_cap ? g_marks_cap * 2 : 4; + g_marks = realloc(g_marks, g_marks_cap * sizeof(InspMark)); + if (!g_marks) insp_oom(); + } + g_marks[g_nmarks++] = (InspMark){g_nframes, g_nsaved, g_nseen, g_indent, g_cur_depth}; +} + +void scr_insp_unwind(void) { + InspMark m = g_marks[--g_nmarks]; + while (g_nframes > m.nframes) { + InspFrame *f = &g_frames[--g_nframes]; + for (size_t i = 0; i < f->len; i++) scr_str_release(f->items[i]); + free(f->items); + } + while (g_nsaved > m.nsaved) { + InspSaved *sv = &g_saved[--g_nsaved]; + free(g_seen); + g_seen = sv->seen; + g_seen_cap = sv->seen_cap; + memcpy(g_circ, sv->circ, sizeof g_circ); + g_ncirc = sv->ncirc; + } + if (g_nseen > m.nseen) g_nseen = m.nseen; + g_indent = m.indent; + g_cur_depth = m.cur_depth; + g_pending_seen = NULL; +} + /* ── string values (formatPrimitive's string half) ───────────────────── */ /* Byte offset of UTF-16 unit `units` — when the boundary splits an astral @@ -1422,7 +1470,7 @@ static ScrStr *scr_insp_obj(ScrDyn *d, double recurse, double depth, const char for (size_t i = 0; i < d->v.obj.len; i++) { ScrDynEntry *ent = &d->v.obj.entries[i]; if (!insp_obj_shows(ent)) continue; - ScrStr *val = scr_insp_dyn(ent->value, recurse + 1, depth); + ScrStr *val = ent->accessor ? insp_accessor_tag(ent) : scr_insp_dyn(ent->value, recurse + 1, depth); InspBuf eb = {0}; if (ent->enumerable) { insp_key_into(&eb, ent->key, ent->key_len); @@ -1443,7 +1491,7 @@ static ScrStr *scr_insp_obj(ScrDyn *d, double recurse, double depth, const char ScrDynEntry *ent = scr_insp_symbol_entry(d, i); if (!ent) continue; ScrStr *key = scr_insp_dyn(d->symbol_keys->v.arr.items[i], recurse + 1, depth); - ScrStr *val = scr_insp_dyn(ent->value, recurse + 1, depth); + ScrStr *val = ent->accessor ? insp_accessor_tag(ent) : scr_insp_dyn(ent->value, recurse + 1, depth); InspBuf eb = {0}; /* A hidden symbol key is bracketed like a hidden string key. */ if (!ent->enumerable) ib_char(&eb, '['); @@ -1635,10 +1683,11 @@ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) { case SCR_DYN_ARR: { size_t len = d->v.arr.len; /* Named and noncanonical numeric properties follow the elements as - * `key: value` entries (Node's array extras). */ + * `key: value` entries (Node's array extras); under showHidden the + * own `length` comes first, and non-enumerable properties show too. */ const ScrDyn *props = d->v.arr.properties; size_t nprops = 0; - for (size_t i = 0; props && i < props->v.obj.len; i++) nprops += props->v.obj.entries[i].enumerable; + for (size_t i = 0; props && i < props->v.obj.len; i++) nprops += insp_obj_shows(&props->v.obj.entries[i]); if (len == 0 && nprops == 0 && !g_show_hidden) return scr_str_new("[]", 2); if (recurse > depth) return scr_str_new("[Array]", 7); scr_insp_begin(recurse + 1); @@ -1672,9 +1721,9 @@ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) { scr_str_release(m); } if (g_show_hidden) { - /* The own non-enumerable `length`, after the items and before the - * other own properties. Node's grouping reads value[k] for every - * output position k, this one included. */ + /* The own non-enumerable `length`, after the items. Node's + * grouping reads value[k] for every output position k, this one + * included. */ char line[48]; int n = snprintf(line, sizeof line, "[length]: %zu", len); ScrStr *s = scr_str_new(line, (size_t)n); @@ -1685,10 +1734,13 @@ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) { } for (size_t k = 0; props && k < props->v.obj.len; k++) { const ScrDynEntry *ent = &props->v.obj.entries[k]; - if (!ent->enumerable) continue; + if (!insp_obj_shows(ent)) continue; ScrStr *val = ent->accessor ? insp_accessor_tag(ent) : scr_insp_dyn(ent->value, recurse + 1, depth); InspBuf eb = {0}; + /* formatProperty's hidden key: the key's rendering in brackets. */ + if (!ent->enumerable) ib_char(&eb, '['); insp_key_into(&eb, ent->key, ent->key_len); + if (!ent->enumerable) ib_char(&eb, ']'); ib_cstr(&eb, ": "); ib_bytes(&eb, val->data, val->len); scr_str_release(val); @@ -1702,9 +1754,8 @@ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) { entries++; } /* Node's grouping leaves out the last entry when there are more - * entries than maxArrayLength (the `... more items` entry when the - * array has no properties, or under showHidden the `[length]` - * entry). */ + * entries than maxArrayLength (100): the `... more items` entry, + * `[length]` under showHidden, or the last property. */ bool last_out = entries > 100; ScrStr *base = scr_str_new("", 0); ScrStr *b0 = scr_str_new("[", 1); diff --git a/packages/runtime/src/scr_inspect.h b/packages/runtime/src/scr_inspect.h index 9bf18a23c..f36335a3b 100644 --- a/packages/runtime/src/scr_inspect.h +++ b/packages/runtime/src/scr_inspect.h @@ -76,6 +76,10 @@ ScrStr *scr_insp_end(ScrStr *base, ScrStr *b0, ScrStr *b1, double recurse, * caller's level (+1; borrows both). */ void scr_insp_nested_begin(void); ScrStr *scr_insp_nested_end(ScrStr *prefix, ScrStr *inner); +/* Mark the inspector's state before a top-level render, and return to the + * mark when the render ends, normally or by an inspection refusal. */ +void scr_insp_mark(void); +void scr_insp_unwind(void); /* The buf.read* / buf.write* numeric families on u8 bytes, Node-exact: * boundsError's ladder (non-integer offset → 'It must be an integer', a diff --git a/tests/corpus/6357-format-o-hidden.ts b/tests/corpus/6357-format-o-hidden.ts index 9e48ed4ba..44ed1d772 100644 --- a/tests/corpus/6357-format-o-hidden.ts +++ b/tests/corpus/6357-format-o-hidden.ts @@ -1,6 +1,7 @@ // util.format's %o over values reached through `unknown` renders with // showHidden, as Node does: arrays show their hidden `[length]` (with -// Node's grouping), at every depth, inside Maps and records too. +// Node's grouping), at every depth, inside Maps and records too, ahead of +// an array's named properties. import { format } from "node:util"; const cases: [string, unknown][] = [ ["ten", Array.from({ length: 10 }, (_, i) => i)], @@ -17,3 +18,18 @@ const cases: [string, unknown][] = [ ["date", [new Date(0)]], ]; for (const [k, v] of cases) console.log(k, format("%o", v)); +// The hidden `[length]` comes before an array's named properties, and the +// grid's last-entry rule counts both. +type Bag = Record; +const named = [1, 2]; +(named as unknown as Bag).foo = "x"; +const tagged = Array.from({ length: 100 }, (_, i) => i); +(tagged as unknown as Bag).tag = "t"; +const bare: number[] = []; +(bare as unknown as Bag).k = 1; +for (const [k, v] of [ + ["named", named], + ["tagged", tagged], + ["bare", bare], +] as [string, unknown][]) + console.log(k, format("%o", v)); diff --git a/tests/harness/dyncheck.test.ts b/tests/harness/dyncheck.test.ts index dab51a430..21e67d085 100644 --- a/tests/harness/dyncheck.test.ts +++ b/tests/harness/dyncheck.test.ts @@ -1311,6 +1311,72 @@ console.log("after"); expect(r.stderr).toContain(`Uncaught Error: ${refusal}`); }); + test("accessors reached through unknown render as Node's accessor tags", async () => { + const r = await compileAndRun( + "inspect-accessor-tags", + `import { format } from "node:util"; +const o: unknown = JSON.parse('{"x":1}'); +Object.defineProperty(o, "g", { get: () => 2, enumerable: true }); +Object.defineProperty(o, "h", { get: () => 3, enumerable: false }); +Object.defineProperty(o, "gs", { get: () => 4, set: (_v: number) => {}, enumerable: false }); +Object.defineProperty(o, "s", { set: (_v: number) => {}, enumerable: true }); +console.log(o); +console.log(format("%o", o)); +`, + ); + expect(r.exitCode).toBe(0); + expect(r.stdout).toBe( + [ + "{ x: 1, g: [Getter], s: [Setter] }", + "{", + " x: 1,", + " g: [Getter],", + " [h]: [Getter],", + " [gs]: [Getter/Setter],", + " s: [Setter]", + "}", + "", + ].join("\n"), + ); + }); + + test("a refused inspection leaves later renders at the default layout", async () => { + // The refusal's Error skips the call site's layout restore and the + // render's own exits; later renders must not keep the custom layout, + // the indentation, showHidden or open frames of the abandoned one. + const r = await compileAndRun( + "inspect-refusal-state", + `import { format, inspect } from "node:util"; +const p: unknown = Promise.resolve(1); +const rec: unknown = { a: [1], b: p }; +try { + inspect({ a: [1, 2, 3, 4, 5, 6, 7, 8], b: p }, { breakLength: 20 }); +} catch {} +try { + format("%o", rec); +} catch {} +const long: unknown = JSON.parse(JSON.stringify(Array.from({ length: 12 }, (_, i) => "item" + i))); +console.log(long); +console.log(format("%O", [1])); +`, + ); + expect(r.exitCode).toBe(0); + expect(r.stdout).toBe( + [ + "[", + " 'item0', 'item1',", + " 'item2', 'item3',", + " 'item4', 'item5',", + " 'item6', 'item7',", + " 'item8', 'item9',", + " 'item10', 'item11'", + "]", + "[ 1 ]", + "", + ].join("\n"), + ); + }); + test("inspecting a compiled class with static fields through unknown refuses", async () => { // Node prints `[class S] { count: 3 }`; the class object does not // carry compiled static fields, so the inspector refuses rather than From e7bced94fd9082c9007d1af6f4cdefeb97f752f5 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 03:20:04 -0500 Subject: [PATCH 011/259] Let LLVM merge the comparisons of a three-way string comparator --- .../compiler/src/backend/llvm/emit-module.ts | 6 +-- .../src/backend/llvm/string-lifetimes.test.ts | 4 +- tests/harness/string-compare-emission.test.ts | 47 +++++++++++++++++++ 3 files changed, 53 insertions(+), 4 deletions(-) create mode 100644 tests/harness/string-compare-emission.test.ts diff --git a/packages/compiler/src/backend/llvm/emit-module.ts b/packages/compiler/src/backend/llvm/emit-module.ts index 16a1b1601..3c0e91e20 100644 --- a/packages/compiler/src/backend/llvm/emit-module.ts +++ b/packages/compiler/src/backend/llvm/emit-module.ts @@ -1601,8 +1601,8 @@ export function helperDefs(emitter: LlEmitter): string[] { // order; other differing words decide by their first differing byte, // and strings shorter than a word by their first byte. Otherwise a // proven-ASCII string on either side orders by bytes (scr_str_cmp), and - // other pairs call scr_str_cmp_u16_bytes, which only reads the two - // strings, so LLVM can merge repeated comparisons of one pair. Callers + // other pairs call scr_str_cmp_u16_bytes. Both only read the two strings, + // so LLVM can merge repeated comparisons of one pair. Callers // only test the sign of the result. if (emitter.decls.has(`declare i32 @scr_str_cmp_u16(ptr, ptr)`)) { const fn = "scr_str_cmp_u16"; @@ -1732,7 +1732,7 @@ export function helperDefs(emitter: LlEmitter): string[] { ` %anyascii = icmp slt i32 %cws, 0`, ` br i1 %anyascii, label %memorder, label %units`, `memorder:`, - ` %m = call i32 @scr_str_cmp(ptr %a, ptr %b)`, + ` %m = call i32 @scr_str_cmp(ptr %a, ptr %b) nounwind willreturn memory(argmem: read)`, ` ret i32 %m`, `units:`, ` %c = call i32 @scr_str_cmp_u16_bytes(ptr %a, ptr %b) nounwind willreturn memory(argmem: read)`, diff --git a/packages/compiler/src/backend/llvm/string-lifetimes.test.ts b/packages/compiler/src/backend/llvm/string-lifetimes.test.ts index f85addcf8..07ad31153 100644 --- a/packages/compiler/src/backend/llvm/string-lifetimes.test.ts +++ b/packages/compiler/src/backend/llvm/string-lifetimes.test.ts @@ -478,7 +478,9 @@ test("string comparisons decide identity, lengths and leading bytes before the r expect(units).toContain("%below = icmp ult i8 %bx, %by"); expect(units).toContain("%tailable = and i1 %samelen, %short"); expect(units).toContain("%anyascii = icmp slt i32 %cws, 0"); - expect(units).toContain("call i32 @scr_str_cmp(ptr %a, ptr %b)"); + expect(units).toContain( + "call i32 @scr_str_cmp(ptr %a, ptr %b) nounwind willreturn memory(argmem: read)", + ); expect(units).toContain( "call i32 @scr_str_cmp_u16_bytes(ptr %a, ptr %b) nounwind willreturn memory(argmem: read)", ); diff --git a/tests/harness/string-compare-emission.test.ts b/tests/harness/string-compare-emission.test.ts new file mode 100644 index 000000000..2654f56ba --- /dev/null +++ b/tests/harness/string-compare-emission.test.ts @@ -0,0 +1,47 @@ +/* String comparison emission: the runtime calls behind a relational string + * operator only read the two strings, so LLVM merges the comparisons of one + * pair. A three-way comparator (`a < b ? -1 : a > b ? 1 : 0`) then compares + * its strings once, as a comparator that tests one operator does. */ +import { createHash } from "node:crypto"; +import { mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile } from "@scriptc/compiler"; + +const repoRoot = join(import.meta.dirname, "../.."); +const cacheDir = join(repoRoot, "node_modules/.cache/scriptc-tests"); + +async function emittedAsm(name: string, source: string): Promise { + const key = createHash("sha256").update(source).digest("hex").slice(0, 16); + const outDir = join(cacheDir, `string-compare-${key}`); + mkdirSync(outDir, { recursive: true }); + const file = join(outDir, `${name}.ts`); + writeFileSync(file, source); + const result = await compile(file, { + outPath: join(outDir, name), + outDir, + backend: "llvm", + outputKind: "asm", + }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + return readFileSync(result.artifact.path, "utf8"); +} + +const program = (body: string): string => `function order(a: string, b: string): number { + return ${body}; +} +const words = process.argv.slice(2); +words.sort(order); +console.log(words.join(",")); +`; + +const compareCalls = (asm: string): number => + asm.match(/\bcall[a-z]*\s+(?:sc_str_cmp_u16|scr_str_cmp_u16_bytes|scr_str_cmp)\b/g)?.length ?? 0; + +test("a three-way string comparator compares its pair once", async () => { + const once = compareCalls(await emittedAsm("once", program("a < b ? -1 : 1"))); + const both = compareCalls(await emittedAsm("both", program("a < b ? -1 : a > b ? 1 : 0"))); + expect(once).toBeGreaterThan(0); + expect(both).toBe(once); +}); From 03807c0c3574d395c53905aa4b8983ef8ec11d09 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 04:11:54 -0500 Subject: [PATCH 012/259] Run private members and super calls over foreign receivers like Node A JavaScript class's prototype method called with a receiver that is not an instance of its class (`C.prototype.m.call(other)`, or an object that inherits the method) now behaves as in Node when it uses private members or calls super methods, instead of throwing "expected C" for the receiver. - Private fields keep their brand check: reading or writing `this.#x` throws "Cannot read private member #x from an object whose class did not declare it" (or the write message), and `#x in this` answers false. - `this.#m()` brand-checks the receiver through a new `call` use of the private brand helpers and throws "Receiver must be an instance of class C" (V8's wording: the class's own identifier, "anonymous" without one, and "Cannot read properties of undefined (reading 'C')" for a nullish receiver). It also applies to private method calls on other checked-dynamic values. - `super.m(...)` looks the method up on the base class's complete prototype object and calls it with the receiver, as `super` reads [[HomeObject]].[[Prototype]]. Methods that use `super` in other positions, static methods with private names, and classes whose base chain includes a function-local, generic, mixin, Date or runtime-provided class keep the native receiver check. The receiver-independent method lowering and the prototype reflection now mark their frames as `this` boundaries, so lowering one class's members on top of another method's frames (a super call reflecting the base) never reaches the caller's `this`. --- .../frontend/lowering/class-method-values.ts | 50 ++++++- .../src/frontend/lowering/class-prototypes.ts | 3 + .../src/frontend/lowering/lower-calls.ts | 44 ++++++ .../src/frontend/lowering/lower-classes.ts | 14 +- .../src/frontend/lowering/private-brands.ts | 50 ++++++- ...1-class-methods-foreign-receivers.mjs.json | 6 + .../7621-class-methods-foreign-receivers.mjs | 130 ++++++++++++++++++ ...1-class-methods-foreign-receivers.mjs.json | 1 + 8 files changed, 292 insertions(+), 6 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7621-class-methods-foreign-receivers.mjs.json create mode 100644 tests/corpus/7621-class-methods-foreign-receivers.mjs create mode 100644 tests/harness/corpus-costs/7621-class-methods-foreign-receivers.mjs.json diff --git a/packages/compiler/src/frontend/lowering/class-method-values.ts b/packages/compiler/src/frontend/lowering/class-method-values.ts index 6e8256513..af2ef51d5 100644 --- a/packages/compiler/src/frontend/lowering/class-method-values.ts +++ b/packages/compiler/src/frontend/lowering/class-method-values.ts @@ -378,9 +378,17 @@ function reflectedMethodValue( !isJsSourceFile(ts.getSourceFileOfNode(declaration)) || info.localClass !== undefined || lowerer.errorHierarchyClassOf(info.def.name); + // `super.m(...)` in a prototype method reads the base class's prototype, + // which lowerSuperMethodCall answers over the call-site receiver when the + // base has a prototype object. Other uses of `super` keep the native + // receiver. + const superCalls = !staticMethod && info.base !== null && prototypeChainViewable(info.base); ts.walkPreorder(member, (node) => { - if (ts.isPrivateIdentifier(node) || node.kind === ts.SyntaxKind.SuperKeyword) + if (node.kind === ts.SyntaxKind.SuperKeyword && !(superCalls && isSuperMethodCallee(node))) needsNativeReceiver = true; + // Private members on a static method's receiver (the class value) keep + // the native receiver; prototype methods brand-check theirs. + if (staticMethod && ts.isPrivateIdentifier(node)) needsNativeReceiver = true; }); if (needsNativeReceiver) return null; // The method reads itself as a value inside its own body: it is the @@ -403,7 +411,11 @@ function reflectedMethodValue( loc: locOf(member), }; } + // The method may be lowered on top of an unrelated caller's frames (a + // `super` call in another class's method reflects this class): its `this` + // is its own receiver, never an enclosing function's. const context = newFnCtx(false, null, null, DYN); + context.thisBoundary = true; const previousClass = lowerer.currentClass; lowerer.currentClass = info; lowerer.fnStack.push(context); @@ -441,6 +453,42 @@ function reflectedMethodValue( } } +/** Whether `base` and every class above it have a complete prototype object + * (reflectClassPrototype): module-level program classes that neither extend + * Date nor a runtime-provided class. */ +function prototypeChainViewable(base: ClassInfo): boolean { + for (let c: ClassInfo | null = base; c; c = c.base) + if ( + c.decl === null || + c.localClass !== undefined || + c.generic !== undefined || + c.genericInstance !== undefined || + c.mixinInstance !== undefined || + c.callableBase !== undefined || + c.extendsDate !== undefined || + c.def.runtime || + c.builtinEmitter || + c.builtinStream || + c.builtinError || + c.builtinEventTarget + ) + return false; + return true; +} + +/** `super` as the receiver of a called member: `super.m(...)`. */ +function isSuperMethodCallee(node: ts.Node): boolean { + const access = node.parent; + return ( + access !== undefined && + ts.isPropertyAccessExpression(access) && + access.expression === node && + access.parent !== undefined && + ts.isCallExpression(access.parent) && + access.parent.expression === access + ); +} + /** Complete adapters after all native class bodies and instantiations exist. */ export function finalizeClassMethodValues(lowerer: Lowerer, functions: IrFunction[]): void { const byName = new Map(functions.map((fn) => [fn.name, fn])); diff --git a/packages/compiler/src/frontend/lowering/class-prototypes.ts b/packages/compiler/src/frontend/lowering/class-prototypes.ts index cb2ab2280..116150465 100644 --- a/packages/compiler/src/frontend/lowering/class-prototypes.ts +++ b/packages/compiler/src/frontend/lowering/class-prototypes.ts @@ -400,7 +400,10 @@ export function reflectClassPrototype( writable, ]), ); + // The members lower on top of whatever frames requested the view (a + // `super` call in a subclass's method); their `this` is their own receiver. const context = newFnCtx(false, null, null, DYN); + context.thisBoundary = true; lowerer.fnStack.push(context); try { for (const member of info.decl.members.nodes) { diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 82f5a27c1..d80f342c2 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -1,3 +1,4 @@ +import { checkedPrivateMethodReceiver, privateNameClass } from "./private-brands.js"; import { keyedHelperName } from "./stable-names.js"; import { perKeyOrder } from "./key-order-witness.js"; import { isForwardedTupleSpread, lowerForwardingApply } from "./typed-arguments.js"; @@ -547,6 +548,17 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { ) { return lowerer.lowerSuperMethodCall(expr, expr.expression); } + // `value.#m(...)` on a checked-dynamic value (`this` in a JavaScript + // class's receiver-independent method): the private method of the + // brand-checked receiver. + if ( + ts.isPropertyAccessExpression(expr.expression) && + ts.isPrivateIdentifier(expr.expression.name) && + !expr.expression.questionDotToken + ) { + const privateCall = lowerCheckedPrivateMethodCall(lowerer, expr, expr.expression); + if (privateCall) return privateCall; + } const consoleMember = lowerer.consoleCallMember(expr); const consoleMethod = consoleMember === null ? lowerer.consoleMethodMember(expr) : null; @@ -11286,3 +11298,35 @@ function lowerShimIntrinsicCall( ); return { kind: "libCall", fn: intrinsic.fn, args, type: intrinsic.ret, loc }; } + +/** `value.#m(args)` where `value` lowers to a checked-dynamic value and the + * declaration-level class whose body declares `#m` declares it as a method: + * the method called on the brand-checked receiver + * (checkedPrivateMethodReceiver). Null for any other private member call. */ +function lowerCheckedPrivateMethodCall( + lowerer: Lowerer, + call: ts.CallExpression, + access: ts.PropertyAccessExpression, +): IrExpr | null { + if (!ts.isPrivateIdentifier(access.name)) return null; + const name = access.name.text; + const owner = privateNameClass(lowerer, access.name); + const found = owner ? lowerer.findMethodOn(owner, name) : null; + if (!owner || !found || found.declarer !== owner || found.sig.abstract === true) return null; + const probed = tryLowerExpression(lowerer, access.expression); + if (!probed || !checkedDynamicOperand(probed)) return null; + const value = checkedDynamicOperand(lowerer.lowerExpr(access.expression)); + if (!value) return null; + const loc = locOf(call); + const callee = `%${owner.def.name}.${name}`; + lowerer.noteEdge(callee); + const receiver = checkedPrivateMethodReceiver(lowerer, owner, name, value, loc); + const args = lowerer.completeArgs(call.arguments.nodes, found.sig.params, loc, call); + return { kind: "call", callee, args: [receiver, ...args], type: found.sig.ret, loc }; +} + +/** A checked-dynamic value, or the dynamic value under a checked extraction. */ +function checkedDynamicOperand(expr: IrExpr): IrExpr | null { + if (expr.type.kind === "dyn") return expr; + return expr.kind === "dynCheck" && expr.value.type.kind === "dyn" ? expr.value : null; +} diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index 29afbb4fe..db8f35f95 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -181,7 +181,7 @@ import { construction, constructionPrefix } from "./js-class-fields.js"; import { lowerObjectFactoryNew } from "./object-factory-new.js"; import { tryLowerExpression } from "./expressions/try-lower-expression.js"; import { lowerInstanceConstructorNew } from "./class-instance-constructor.js"; -import { classPrototypeData } from "./class-prototypes.js"; +import { classPrototypeData, reflectClassPrototype } from "./class-prototypes.js"; import { constructionEscape } from "./construction-escapes.js"; import { checkedClassConstruction, checkedClassConstructionPacked } from "./class-construction.js"; import { initializeRuntimeStatics, hasRuntimeStatics } from "./class-runtime-statics.js"; @@ -9384,8 +9384,16 @@ export function lowerSuperMethodCall( if (!thisLocal) lowerer.unsupported("SC1080", access); const loc = locOf(call); const thisRef: IrExpr = { kind: "varRef", localId: thisLocal.id, type: thisLocal.type, loc }; - if (lowerer.prototypeMethodAccesses.has(access.name.text)) { - const prototype = classPrototypeData(lowerer, cls.base, loc); + // A method whose `this` is the call-site receiver (a JavaScript class's + // receiver-independent method value, reflectedClassMethodValue) looks the + // method up on the base class's complete prototype, as `super` reads + // [[HomeObject]].[[Prototype]], and calls it with that receiver. + const dynamicThis = thisRef.type.kind === "dyn"; + if (dynamicThis || lowerer.prototypeMethodAccesses.has(access.name.text)) { + const prototype = + dynamicThis && cls.base.decl + ? reflectClassPrototype(lowerer, cls.base, loc, classValueRef(lowerer, cls.base, access)) + : classPrototypeData(lowerer, cls.base, loc); if (prototype) { const callee: IrExpr = { kind: "dynKeyGet", diff --git a/packages/compiler/src/frontend/lowering/private-brands.ts b/packages/compiler/src/frontend/lowering/private-brands.ts index c7881bce1..92bee4fdd 100644 --- a/packages/compiler/src/frontend/lowering/private-brands.ts +++ b/packages/compiler/src/frontend/lowering/private-brands.ts @@ -17,8 +17,9 @@ import type { Lowerer } from "./lowerer.js"; import type { ClassInfo } from "./lower-classes.js"; /** How a brand helper uses its receiver: `in` answers `#x in v`, `read` and - * `write` return the receiver as the declaring class for a field access. */ -type BrandUse = "in" | "read" | "write"; + * `write` return the receiver as the declaring class for a field access, and + * `call` for a private method call. */ +type BrandUse = "in" | "read" | "write" | "call"; const PREFIX = "%private."; @@ -214,6 +215,35 @@ export function checkedPrivateValue( return { kind: "call", callee: helper, args: [receiver], type: resultType, loc }; } +/** `value.#m(...)` on a checked-dynamic `value` in a declaration-level class + * `info` that declares the private method `#m`: the receiver as an instance + * of `info` when the value is one, else Node's TypeError ("Receiver must be + * an instance of class C"). */ +export function checkedPrivateMethodReceiver( + lowerer: Lowerer, + info: ClassInfo, + name: string, + receiver: IrExpr, + loc: SrcLoc, +): IrExpr { + const className = info.def.name; + const resultType: IrType = { kind: "object", className }; + const helper = `${PREFIX}call:${className}:${name}`; + if (!lowerer.valueHelpers.has(helper)) { + lowerer.liftedFns.push({ + name: helper, + params: [{ localId: "value.0", name: "value", type: DYN }], + returnType: resultType, + locals: [{ id: "value.0", name: "value", type: DYN, mutable: false }], + // finalizePrivateBrands fills the body. + body: [], + loc: helperLoc(loc), + }); + lowerer.valueHelpers.set(helper, helper); + } + return { kind: "call", callee: helper, args: [receiver], type: resultType, loc }; +} + /** A plain assignment, a destructuring target, or a for-in/of target writes * the field. Compound assignments and updates read it first, and Node * reports the failed read. */ @@ -358,6 +388,22 @@ export function finalizePrivateBrands(lowerer: Lowerer, functions: IrFunction[]) }, { kind: "return", value: { kind: "boolLit", value: false, type: BOOL, loc }, loc }, ); + } else if (use === "call") { + // V8 names the class by its own identifier (not a name inferred from + // a binding), "anonymous" without one, also for a nullish receiver. + const owner = lowerer.classes.get(className); + const identifier = owner?.decl?.name; + const shown = identifier !== undefined ? identifier.text : "anonymous"; + for (const unit of ["undefined", "null"] as const) { + body.push({ + kind: "if", + cond: { kind: "dynTest", test: unit, value, type: BOOL, loc }, + then: [typeError(strLit(`Cannot read properties of ${unit} (reading '${shown}')`, loc))], + else_: null, + loc, + }); + } + body.push(typeError(strLit(`Receiver must be an instance of class ${shown}`, loc))); } else { const verb = use === "read" ? "reading" : "setting"; const action = use === "read" ? "Cannot read properties" : "Cannot set properties"; diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7621-class-methods-foreign-receivers.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7621-class-methods-foreign-receivers.mjs.json new file mode 100644 index 000000000..8f50b09a3 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7621-class-methods-foreign-receivers.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7621-class-methods-foreign-receivers.mjs" + ], + "diags": [] +} diff --git a/tests/corpus/7621-class-methods-foreign-receivers.mjs b/tests/corpus/7621-class-methods-foreign-receivers.mjs new file mode 100644 index 000000000..beb046ea4 --- /dev/null +++ b/tests/corpus/7621-class-methods-foreign-receivers.mjs @@ -0,0 +1,130 @@ +// Prototype methods called with a receiver that is not an instance of +// their class (`C.prototype.m.call(other)`): `#private` members throw +// Node's TypeErrors for such a receiver, and `super.m()` looks the method up +// on the base class's prototype and calls it with the receiver. +function report(label, run) { + try { + console.log(label, run()); + } catch (error) { + console.log(label, error.constructor.name, error.message); + } +} + +class Counter { + #count = 0; + #step = 1; + constructor(name) { + this.name = name; + } + read() { + return this.#count; + } + bump() { + this.#count += this.#step; + return this.#count; + } + reset(value) { + this.#count = value; + return this.name; + } + #label() { + return `${this.name}#${this.#count}`; + } + label() { + return this.#label(); + } + owns(value) { + return #count in value; + } + ownsSelf() { + return #count in this; + } +} + +const counter = new Counter("c"); +console.log(counter.bump(), counter.bump(), counter.read(), counter.label()); +console.log(counter.owns(counter), counter.owns({}), counter.ownsSelf(), counter.reset(7), counter.read()); + +const plain = { name: "plain" }; +report("read", () => Counter.prototype.read.call(plain)); +report("bump", () => Counter.prototype.bump.call(plain)); +report("reset", () => Counter.prototype.reset.call(plain, 3)); +report("label", () => Counter.prototype.label.call(plain)); +report("ownsSelf", () => Counter.prototype.ownsSelf.call(plain)); +report("owns primitive", () => Counter.prototype.owns.call(counter, 5)); +report("label undefined", () => Counter.prototype.label.call(undefined)); +report("label null", () => Counter.prototype.label.call(null)); +report("label number", () => Counter.prototype.label.call(4)); +report("read other instance", () => Counter.prototype.read.call(new Counter("d"))); +report("label other instance", () => Counter.prototype.label.call(new Counter("e"))); + +const Anonymous = class { + #m() { + return 1; + } + call() { + return this.#m(); + } +}; +const Named = class Inner { + #m() { + return 2; + } + call() { + return this.#m(); + } +}; +report("anonymous", () => Anonymous.prototype.call.call({})); +report("named", () => Named.prototype.call.call({})); +console.log(new Anonymous().call(), new Named().call()); + +class Shape { + constructor(name) { + this.name = name; + } + describe() { + return `shape ${this.name}`; + } + area() { + return 0; + } +} +class Square extends Shape { + describe() { + return `square: ${super.describe()} area ${this.area()}`; + } + area() { + return this.size * this.size; + } + both() { + return [super.describe(), super.area()].join("|"); + } +} +class Tiny extends Square { + #tag = "t"; + describe() { + return `tiny<${super.describe()}>`; + } + tag() { + return `${this.#tag}:${super.both()}`; + } +} + +const square = new Square("s"); +square.size = 3; +console.log(square.describe(), square.both()); +const tiny = new Tiny("t"); +tiny.size = 1; +console.log(tiny.describe(), tiny.tag()); +const foreign = { + name: "f", + size: 2, + area() { + return 40; + }, +}; +report("square describe", () => Square.prototype.describe.call(foreign)); +report("square both", () => Square.prototype.both.call(foreign)); +report("tiny describe", () => Tiny.prototype.describe.call(foreign)); +report("tiny tag", () => Tiny.prototype.tag.call(foreign)); +report("square describe on tiny", () => Square.prototype.describe.call(tiny)); diff --git a/tests/harness/corpus-costs/7621-class-methods-foreign-receivers.mjs.json b/tests/harness/corpus-costs/7621-class-methods-foreign-receivers.mjs.json new file mode 100644 index 000000000..bb2ade1c2 --- /dev/null +++ b/tests/harness/corpus-costs/7621-class-methods-foreign-receivers.mjs.json @@ -0,0 +1 @@ +{ "plain": 6415, "san": 10107 } From d22250f8305a5a21c78e85eca17db51a82da02a5 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 08:05:50 -0500 Subject: [PATCH 013/259] Raise slow CI job time limits and prune closed pull request caches --- .github/workflows/ci.yml | 9 +++++--- .github/workflows/prune-caches.yml | 36 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 3 deletions(-) create mode 100644 .github/workflows/prune-caches.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f131747fa..fe601ed06 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -524,7 +524,9 @@ jobs: if: ${{ needs.validation_scope.outputs.full == 'true' && needs.lanes.outputs.linux == 'true' }} name: test (tsgo and tsc-ts give the same IR) runs-on: ubuntu-24.04 - timeout-minutes: 30 + # The two corpus compiles run back to back and take close to 30 minutes on a + # slow hosted runner, so a 30-minute limit cancels otherwise healthy runs. + timeout-minutes: 45 steps: - uses: actions/checkout@v4 - uses: pnpm/action-setup@v4 @@ -618,8 +620,9 @@ jobs: # Shard 1 additionally runs package/install and link-parity contracts # before its LLVM differential slice. The slice itself can take ~10 # minutes on a cold hosted runner, so 20 minutes cancels an otherwise - # healthy job before the differential completes. - timeout-minutes: 35 + # healthy job before the differential completes. Slow runners need more + # headroom than that, so the limit is 50 minutes. + timeout-minutes: 50 strategy: fail-fast: false matrix: diff --git a/.github/workflows/prune-caches.yml b/.github/workflows/prune-caches.yml new file mode 100644 index 000000000..008baaa43 --- /dev/null +++ b/.github/workflows/prune-caches.yml @@ -0,0 +1,36 @@ +name: Prune caches + +# Pull request caches are scoped to that pull request, so once it is closed no +# run can use them again. Deleting them keeps the repository under its cache +# size limit, so caches that main and open pull requests use are not evicted. +on: + pull_request: + types: [closed] + schedule: + - cron: "17 6 * * *" + workflow_dispatch: + +permissions: + actions: write + pull-requests: read + +jobs: + prune: + runs-on: ubuntu-24.04 + timeout-minutes: 10 + steps: + - name: Delete caches of closed pull requests + env: + GH_TOKEN: ${{ github.token }} + REPO: ${{ github.repository }} + run: | + open=" $(gh api --paginate "repos/$REPO/pulls?state=open&per_page=100" --jq '.[].number' | tr '\n' ' ') " + gh api --paginate "repos/$REPO/actions/caches?per_page=100" \ + --jq '.actions_caches[] | select(.ref | startswith("refs/pull/")) | "\(.id) \(.ref)"' | + while read -r id ref; do + number=$(echo "$ref" | cut -d/ -f3) + case "$open" in + *" $number "*) ;; + *) gh api --method DELETE "repos/$REPO/actions/caches/$id" >/dev/null && echo "deleted cache $id ($ref)" ;; + esac + done From 249773437aeb808798e53f96cc3f6052f9736a01 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Fri, 23 Oct 2026 07:21:37 -0700 Subject: [PATCH 014/259] Update the strict-user-js coverage snapshot for main's startup section Main now reports fenced sites in module top-level code under "runs at startup"; the use of 'legacy' on line 22 is one of them. Co-Authored-By: Claude Opus 5.5 --- .../__snapshots__/coverage-node-islands-user-js.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/harness/__snapshots__/coverage-node-islands-user-js.txt b/tests/harness/__snapshots__/coverage-node-islands-user-js.txt index 61cb8bb33..0898e19ba 100644 --- a/tests/harness/__snapshots__/coverage-node-islands-user-js.txt +++ b/tests/harness/__snapshots__/coverage-node-islands-user-js.txt @@ -5,14 +5,16 @@ scriptc coverage tests/coverage-fixtures/node-islands-user-js.cjs in dynamic tier 10 (operate on values typed only at runtime; --explain-dynamic lists them) (1 function not analyzed — signature blocked; their statements count as not static) - deferred to runtime 2 sites (JS statements that throw their fence if executed) - ×1 SC1090 parameterized 'arguments' outside an ES module (sloppy-mode parameter aliases) - at tests/coverage-fixtures/node-islands-user-js.cjs:15:1 - hint: this form is valid TypeScript but does not compile yet — rewrite it with a supported equivalent of the construct the message names (https://scriptc.dev/limitations lists the boundary) + runs at startup 1 site (JS statements in module top-level code, which runs when the module loads) ×1 SC2004 uses of 'legacy' inherit the blocker on its declaration at tests/coverage-fixtures/node-islands-user-js.cjs:22:57 hint: the declaration of 'legacy' did not compile — fix the diagnostic reported there and these sites clear with it + deferred to runtime 1 site (JS statements that throw their fence if executed) + ×1 SC1090 parameterized 'arguments' outside an ES module (sloppy-mode parameter aliases) + at tests/coverage-fixtures/node-islands-user-js.cjs:15:1 + hint: this form is valid TypeScript but does not compile yet — rewrite it with a supported equivalent of the construct the message names (https://scriptc.dev/limitations lists the boundary) + blockers: ×1 SC8101 A write of 'Point.prototype.norm' needs a mutable JavaScript object model, which native code does not have at tests/coverage-fixtures/node-islands-user-js.cjs:7:1 From c7c8f5d45ec6b1004a269f33df5688f1f8aec3c6 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 09:25:07 -0500 Subject: [PATCH 015/259] Run lone array callbacks as loops with their bodies inlined --- docs/content/docs/contracts.mdx | 2 +- docs/content/limitations/contract-types.mdx | 2 +- .../backend/llvm/appended-array-literals.ts | 35 +- .../src/backend/llvm/emit-statements.ts | 3 + packages/compiler/src/backend/llvm/emitter.ts | 9 +- .../src/backend/llvm/expr-primitives.ts | 57 ++- .../lowering/containers/array-callbacks.ts | 5 +- .../lowering/containers/array-pipelines.ts | 341 ++++++++++++++---- .../src/ir/callback-specialization.ts | 7 +- .../test/array-pipeline-fusion.test.ts | 46 ++- .../test/format-float-arguments.test.ts | 23 +- tests/diagnostics/contract-int32-escapes.ts | 3 +- .../contract-int32-arrays.ts.txt | 6 +- .../contract-int32-escapes.ts.txt | 2 +- 14 files changed, 450 insertions(+), 91 deletions(-) diff --git a/docs/content/docs/contracts.mdx b/docs/content/docs/contracts.mdx index 948fe7960..ad5953fa6 100644 --- a/docs/content/docs/contracts.mdx +++ b/docs/content/docs/contracts.mdx @@ -245,7 +245,7 @@ $ scriptc build scale.ts 1 error. ``` -A copy such as `slice()` or a spread is checked as if it were the same array as its source. The results of callbacks are not followed, so an array built by `map` or `Array.from` with a mapping function cannot be `Int32[]`; build it with a loop that stores `value | 0`. scriptc refuses an `Int32[]` slot whose array can come from code it cannot see, such as `JSON.parse`, dynamic values or the callers of a function used as a value, and an array that can reach one and escapes to such code, such as a call through a function value (SC7003). +A copy such as `slice()` or a spread is checked as if it were the same array as its source. The results of a callback are followed only when scriptc copies it into the loop that runs the array method: a callback written at a `map` or `filter` call whose captured variables are not reassigned, such as `xs.map((x) => (x * 2) | 0)`. Other callback results are not followed, so for example an array built by `Array.from` with a mapping function cannot be `Int32[]`; build it with a loop that stores `value | 0`. scriptc refuses an `Int32[]` slot whose array can come from code it cannot see, such as `JSON.parse`, dynamic values or the callers of a function used as a value, and an array that can reach one and escapes to such code, such as a call through a function value (SC7003). ## Immutable diff --git a/docs/content/limitations/contract-types.mdx b/docs/content/limitations/contract-types.mdx index 35d7a95c0..1fd24a81b 100644 --- a/docs/content/limitations/contract-types.mdx +++ b/docs/content/limitations/contract-types.mdx @@ -1,7 +1,7 @@ [Contract types](/docs/contracts) are checked only where they are written as the annotation of a parameter, variable, class instance field or function result, `Acyclic` only on classes, interfaces and object type aliases, and `ProgramLifetime` only in the `implements` clause of a class declaration; other aliases, interface members and nested type positions are reported. In programs that use worker threads, a surrounding `try`/`catch` does not discharge `NoThrow`. `Int32` refuses parameters of functions used as values and fields of classes whose instances are stored in `any` or `unknown` values. -`Int32[]` refuses arrays that can come from or escape to code scriptc cannot see, does not follow callback results (such as `map` results), and checks a copy made by `slice` or a spread as if it were its source array. +`Int32[]` refuses arrays that can come from or escape to code scriptc cannot see, follows callback results only for callbacks written at a `map` or `filter` call that scriptc runs inline, and checks a copy made by `slice` or a spread as if it were its source array. Element reads that find a value are int32s, but a scalar `Int32` slot still needs `a[i] | 0`, because a read can miss and produce `undefined`. `Immutable` refuses values stored in `any` or `unknown` or that another reference can still change. `ProgramLifetime` applies to root classes of executables only; instances the program drops are never reclaimed unless they belong to a released [lifetime region](/docs/experimental#lifetimeregion). diff --git a/packages/compiler/src/backend/llvm/appended-array-literals.ts b/packages/compiler/src/backend/llvm/appended-array-literals.ts index 3c09904e3..c65aded0c 100644 --- a/packages/compiler/src/backend/llvm/appended-array-literals.ts +++ b/packages/compiler/src/backend/llvm/appended-array-literals.ts @@ -9,7 +9,7 @@ * one directly or through a binding read from it. The choice never changes * behavior. */ -import type { IrExpr, IrModule } from "../../ir/ir.js"; +import type { IrExpr, IrModule, IrStmt } from "../../ir/ir.js"; import { eachNodeOfKinds, type IrNodeIndex, type IrNodeKind } from "../../ir/node-index.js"; const APPENDING_METHODS: ReadonlySet = new Set([ @@ -120,3 +120,36 @@ export function findAppendedArrayLiterals( } return result; } + +/** `const xs = []` directly followed by a capacity hint for `xs` (an + * `arraySetLength` with `reserve`) whose length reads only literals and + * other locals: the literal can be constructed with that capacity, and the + * hint then has nothing left to do. */ +export function reservedArrayLength( + stmts: readonly IrStmt[], + i: number, +): { literal: IrExpr; hint: IrStmt & { kind: "arraySetLength" } } | null { + const decl = stmts[i]; + const next = stmts[i + 1]; + if (decl?.kind !== "varDecl" || decl.init === null || !isEmptyLiteral(decl.init)) return null; + if (next?.kind !== "arraySetLength" || next.reserve !== true) return null; + if (next.arr.kind !== "varRef" || next.arr.localId !== decl.localId) return null; + return plainLength(next.length, decl.localId) ? { literal: decl.init, hint: next } : null; +} + +function plainLength(e: IrExpr, array: string): boolean { + switch (e.kind) { + case "numLit": + return true; + case "varRef": + return e.localId !== array; + case "bin": + return plainLength(e.left, array) && plainLength(e.right, array); + case "ternary": + return ( + plainLength(e.cond, array) && plainLength(e.then, array) && plainLength(e.else_, array) + ); + default: + return false; + } +} diff --git a/packages/compiler/src/backend/llvm/emit-statements.ts b/packages/compiler/src/backend/llvm/emit-statements.ts index c2846a9d4..cbf8fb27d 100644 --- a/packages/compiler/src/backend/llvm/emit-statements.ts +++ b/packages/compiler/src/backend/llvm/emit-statements.ts @@ -458,6 +458,9 @@ export function emitStmtBody(emitter: LlEmitter, s: IrStmt): void { emitter.publishedTypes?.containerGuarded(s.arr.type) !== true ) break; + // The literal it follows was constructed with this capacity + // (reservedArrayLength). + if (emitter.consumedReserves.delete(s)) break; const arr = emitBorrowedInput(emitter, s.arr); const length = emitter.emitExpr(s.length); if (s.arr.type.kind !== "array") diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 050c3fb90..b3508b5d0 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -176,7 +176,7 @@ import { ReferenceEffects } from "./reference-effects.js"; import { ReferenceWrites, type Writes } from "./reference-writes.js"; import { LlvmDebugInfo } from "./debug-info.js"; import { StackCallbacks } from "./stack-callbacks.js"; -import { findAppendedArrayLiterals } from "./appended-array-literals.js"; +import { findAppendedArrayLiterals, reservedArrayLength } from "./appended-array-literals.js"; import { AmbientReceiverReaders, findConstantCallbacks } from "./constant-callbacks.js"; import { findLentStringParameters, @@ -1235,6 +1235,11 @@ export class LlEmitter { /** Locals whose array literal emitStmts left for the `await Promise.all` * that reads them (deferredPromiseAllLocal). */ private readonly deferredPromiseAllEntries = new Map>(); + /** Empty array literals that a capacity hint follows directly + * (reservedArrayLength), with that hint. Constructing the literal with + * the hinted capacity consumes the hint, which then emits nothing. */ + readonly reservedArrayLengths = new Map(); + readonly consumedReserves = new Set(); /** The promise a `return` emitted past its finally regions already * produced for its adopting await (borrowed from the return's parked * slot); that await takes it instead of evaluating its operand. */ @@ -5514,6 +5519,8 @@ export class LlEmitter { if (this.B.isTerminated()) return; if (cursor) cursor.index = i; this.stmtCursor = cursor; + const reserve = reservedArrayLength(stmts, i); + if (reserve !== null) this.reservedArrayLengths.set(reserve.literal, reserve.hint); const deferred = this.deferredPromiseAllLocal(stmts, i); if (deferred !== null) { this.deferredPromiseAllEntries.set((stmts[i] as { localId: string }).localId, deferred); diff --git a/packages/compiler/src/backend/llvm/expr-primitives.ts b/packages/compiler/src/backend/llvm/expr-primitives.ts index 1eec6a965..9791de8e5 100644 --- a/packages/compiler/src/backend/llvm/expr-primitives.ts +++ b/packages/compiler/src/backend/llvm/expr-primitives.ts @@ -870,6 +870,34 @@ export function emitStringExpr( } } +/** scr_arr_reserve_len reserves dense storage only up to this many slots + * (SCR_ARR_DENSE_LIMIT, scr_array.c). */ +const RESERVE_LIMIT = 2 ** 20; + +/** Elements the inline slots of a small array construction + * (scr_arr_new_small, scr_arr_new_ops_small) hold at least + * (SCR_ARR_SMALL_SLOTS, scr_array.c). */ +const SMALL_ARRAY_SLOTS = 3; + +/** The capacity scr_arr_reserve_len would reserve for `length` on an empty + * array: the length truncated when it is at least 1 and at most + * RESERVE_LIMIT, else 0. */ +function reservedCapacity(host: LlvmEmitterContext, length: IrExpr): string { + const B = host.B; + const n = host.emitExpr(length); + const atLeastOne = B.tmp(), + withinLimit = B.tmp(), + reserves = B.tmp(), + slots = B.tmp(), + capacity = B.tmp(); + B.line(`${atLeastOne} = fcmp oge double ${n.name}, ${f64Lit(1)}`); + B.line(`${withinLimit} = fcmp ole double ${n.name}, ${f64Lit(RESERVE_LIMIT)}`); + B.line(`${reserves} = and i1 ${atLeastOne}, ${withinLimit}`); + B.line(`${slots} = select i1 ${reserves}, double ${n.name}, double ${f64Lit(0)}`); + B.line(`${capacity} = fptoui double ${slots} to ${host.sizeType}`); + return capacity; +} + export function emitContainerExpr( host: LlvmEmitterContext, e: ExprOf< @@ -941,7 +969,34 @@ export function emitContainerExpr( ? `${arr} = call ptr @scr_arr_new_small(i32 ${SCR_ELEM_I32})` : `${arr} = call ptr @scr_arr_new(i32 ${SCR_ELEM_I32}, ${host.sizeType} ${capacity})`, ); - } else B.line(`${arr} = ${arrNewCall(host.shapeHost, elem, String(capacity), small)}`); + } else { + const hint = host.reservedArrayLengths.get(e); + if (hint !== undefined) { + host.reservedArrayLengths.delete(e); + host.consumedReserves.add(hint); + const capacity = reservedCapacity(host, hint.length); + // The small construction's inline slots hold at least + // SMALL_ARRAY_SLOTS elements; larger capacities are sized. + const fits = B.tmp(), + smallArr = B.tmp(), + sizedArr = B.tmp(); + const smallLabel = B.newLabel("arr.cap.small"), + sizedLabel = B.newLabel("arr.cap.sized"), + joined = B.newLabel("arr.cap.j"); + B.line(`${fits} = icmp ule ${host.sizeType} ${capacity}, ${SMALL_ARRAY_SLOTS}`); + B.condBr(fits, smallLabel, sizedLabel); + B.startBlock(smallLabel); + B.line(`${smallArr} = ${arrNewCall(host.shapeHost, elem, "0", true)}`); + B.br(joined); + B.startBlock(sizedLabel); + B.line(`${sizedArr} = ${arrNewCall(host.shapeHost, elem, capacity)}`); + B.br(joined); + B.startBlock(joined); + B.line( + `${arr} = phi ptr [ ${smallArr}, %${smallLabel} ], [ ${sizedArr}, %${sizedLabel} ]`, + ); + } else B.line(`${arr} = ${arrNewCall(host.shapeHost, elem, String(capacity), small)}`); + } const out = host.own({ name: arr, type: e.type }); const acc: ArrayAccess = int32 ? "i32" : elemAccess(elem); let pending: LlValue[] = []; diff --git a/packages/compiler/src/frontend/lowering/containers/array-callbacks.ts b/packages/compiler/src/frontend/lowering/containers/array-callbacks.ts index 86f214bc1..7349566d9 100644 --- a/packages/compiler/src/frontend/lowering/containers/array-callbacks.ts +++ b/packages/compiler/src/frontend/lowering/containers/array-callbacks.ts @@ -827,15 +827,16 @@ function buildArrayHofFn( ); returnType = outT; body = [ + readLen, { kind: "varDecl", localId: "out.0", init: { kind: "arrayLit", elems: [], type: outT, loc }, loc, }, - readLen, // map's result has the receiver's length, holes where the receiver - // has them. Storage for it is reserved first and the length is set + // has them. Storage for it is reserved first (with the result's + // construction, which directly precedes it) and the length is set // after the loop, so a result without holes is filled by appends and // gets no state bytes. ...(method === "map" diff --git a/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts b/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts index 2f839a20b..cdcd0d93c 100644 --- a/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts +++ b/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts @@ -1,4 +1,6 @@ import { keyedHelperName } from "../stable-names.js"; +import { writtenLocals } from "../../../ir/callback-specialization.js"; +import { AmbientReceiverReaders } from "../../../ir/receiver-readers.js"; import { boolLit, countedFor, numLit, varRef } from "../../../ir/build.js"; import { BOOL, @@ -16,9 +18,12 @@ import { typeKey, } from "../../../ir/ir.js"; import { + everyExpr, everyExprChild, + everyStmt, everyStmtChild, everyStmtList, + transformExpr, transformStmtList, } from "../../../ir/traverse.js"; import { @@ -537,6 +542,65 @@ function matchChain(lowerer: Lowerer, e: IrExpr): Chain | null { }; } +/** The outermost array-HOF call of `e` on its own, over its receiver. */ +function loneChain(lowerer: Lowerer, e: IrExpr): Chain | null { + const top = stageOf(lowerer, e); + if (!top) return null; + const { stage, receiver } = top; + if (receiver.type.kind !== "array") return null; + const stages: Stage[] = []; + let terminal: Terminal; + if (TERMINALS.has(stage.info.method)) { + const init = + stage.info.method === "reduce" && stage.info.hasInit && e.kind === "call" ? e.args[2]! : null; + terminal = { kind: "call", stage, init }; + } else if (PRODUCERS.has(stage.info.method)) { + terminal = { kind: "collect" }; + stages.push(stage); + } else return null; + return { + source: receiver, + sourceType: receiver.type, + slice: null, + stages, + terminal, + type: e.type, + loc: e.loc, + }; +} + +/** The callbacks of `chain` in order, or null when its stages cannot run + * in one loop: element types that do not line up, an array argument past + * the first stage, reduce without a seed, or findIndex over holes. */ +function chainCallbacks(chain: Chain): Stage[] | null { + const { stages, terminal } = chain; + const terminalStage = terminal.kind === "call" ? terminal.stage : null; + const callbacks = terminalStage ? [...stages, terminalStage] : stages; + // Element types must line up stage to stage. + let elem = chain.sourceType.elem; + for (const stage of callbacks) { + if (!typeEquals(stage.info.elem, elem)) return null; + if (stage.info.method === "filter" && !typeEquals(stage.info.outElem, stage.info.elem)) + return null; + if ( + (stage.info.method === "map" || stage.info.method === "flatMap") && + !typeEquals(stage.info.outElem, stage.info.fnRet) + ) + return null; + elem = stage.info.outElem; + } + // Index arguments are reproduced; an array argument only names the source. + for (let k = 0; k < callbacks.length; k++) { + const stage = callbacks[k]!; + const lead = stage.info.method === "reduce" ? 1 : 0; + if (stage.info.arity > lead + 3) return null; + if (stage.info.arity === lead + 3 && (k !== 0 || chain.slice)) return null; + } + if (terminalStage?.info.method === "reduce" && !terminalStage.info.hasInit) return null; + if (terminalStage?.info.method === "findIndex" && holeCarrying(chain)) return null; + return callbacks; +} + /* ── the fusion pass ─────────────────────────────────────────────────── */ /** The values a fused loop hands from one stage to the next: a local of a @@ -550,6 +614,10 @@ interface Plan { writes: Set; /** Some callback may throw or loop; at most one does. */ risky: boolean; + /** How the loop inlines callbacks, when not by their effect summaries. */ + inline?: InlineTarget; + /** Stack frame name of the loop: the inlined callback's, for a lone call. */ + frame?: string; } /** Fuse chains of array-HOF helper calls into one loop. @@ -596,12 +664,22 @@ class PipelineFusion { readonly added: IrFunction[] = []; private readonly effects: CallbackEffects; private readonly helpers = new Map(); + /** Bindings each function, or a closure it creates, writes after their + * declaration. */ + private readonly written: Map>; + /** Bindings of the function being fused that inlined callbacks captured. */ + private inlinedCaptures = new Set(); + /** The helper calls each callback with an undefined receiver; a copied + * body runs under the receiver around the array call instead. */ + private readonly receivers: AmbientReceiverReaders; constructor( private readonly lowerer: Lowerer, functions: readonly IrFunction[], ) { this.effects = new CallbackEffects(functions, lowerer.globalsList); + this.written = writtenLocals({ functions }); + this.receivers = new AmbientReceiverReaders(new Map(functions.map((fn) => [fn.name, fn]))); } run(fn: IrFunction): void { @@ -612,6 +690,7 @@ class PipelineFusion { }); if (!candidate) return; const removed = new Set(); + this.inlinedCaptures = new Set(); let body = this.lists(fn.body, fn, removed); body = transformStmtList(body, { stmt: (s) => s, @@ -619,6 +698,7 @@ class PipelineFusion { }); fn.body = body; if (removed.size > 0) fn.locals = fn.locals.filter((l) => !removed.has(l.id)); + if (this.inlinedCaptures.size > 0) unboxUncaptured(fn, this.inlinedCaptures); } /* ── statement lists: fold single-use chain bindings ── */ @@ -733,40 +813,51 @@ class PipelineFusion { /* ── expressions ── */ private fuse(e: IrExpr, fn: IrFunction): IrExpr | null { - const plan = this.plan(e, fn); + const plan = this.plan(e, fn) ?? this.lonePlan(e, fn); return plan ? this.emit(plan) : null; } + /** One array-HOF call on its own (or the last call of a chain that does + * not fuse), when every callback is a closure literal whose body can be + * copied into the loop. A single stage reorders nothing, so the + * callbacks' effects need no model; their captured bindings must keep + * one value while the loop runs (stableTarget), since the loop reads + * them once, when it starts. The loop keeps the helper's order: the + * length read once, each element read when it is visited, holes + * skipped (and kept by map). */ + private lonePlan(e: IrExpr, fn: IrFunction): Plan | null { + const chain = loneChain(this.lowerer, e); + if (!chain) return null; + const callbacks = chainCallbacks(chain); + if (!callbacks) return null; + const inline = this.stableTarget(fn); + let frame: string | undefined; + for (const stage of callbacks) { + for (const arg of [stage.slow, stage.fast]) { + if (!arg) continue; + const target = inline(arg); + if (!target) return null; + frame ??= target.sourceName; + } + } + return { + chain, + callbacks, + writes: new Set(), + risky: true, + inline, + ...(frame === undefined ? {} : { frame }), + }; + } + /** Decide whether `e` is a fusable chain; null when it is not. */ private plan(e: IrExpr, fn: IrFunction): Plan | null { const chain = matchChain(this.lowerer, e); if (!chain) return null; + const callbacks = chainCallbacks(chain); + if (!callbacks) return null; const { stages, terminal } = chain; const terminalStage = terminal.kind === "call" ? terminal.stage : null; - const callbacks = terminalStage ? [...stages, terminalStage] : stages; - // Element types must line up stage to stage. - let elem = chain.sourceType.elem; - for (const stage of callbacks) { - if (!typeEquals(stage.info.elem, elem)) return null; - if (stage.info.method === "filter" && !typeEquals(stage.info.outElem, stage.info.elem)) - return null; - if ( - (stage.info.method === "map" || stage.info.method === "flatMap") && - !typeEquals(stage.info.outElem, stage.info.fnRet) - ) - return null; - elem = stage.info.outElem; - } - // Index arguments are reproduced; an array argument only names the source. - for (let k = 0; k < callbacks.length; k++) { - const stage = callbacks[k]!; - const lead = stage.info.method === "reduce" ? 1 : 0; - if (stage.info.arity > lead + 3) return null; - if (stage.info.arity === lead + 3 && (k !== 0 || chain.slice)) return null; - } - if (terminalStage?.info.method === "reduce" && !terminalStage.info.hasInit) return null; - const holes = holeCarrying(chain); - if (terminalStage?.info.method === "findIndex" && holes) return null; // Effects of each callback, in chain order. const scope = this.effects.scope(fn, true); const summaries: Effects[] = []; @@ -831,30 +922,62 @@ class PipelineFusion { * are passed in by value, read when the fused call starts; no callback * in the chain assigns a binding another one reads). */ private readonly inlineTarget: InlineTarget = (arg) => { + const fn = this.closureTarget(arg); + if (!fn) return null; + const captures = new Set((fn.captures ?? []).map((c) => c.localId)); + const effects = this.effects.ofFunction(fn); + if (!effects || intersects(effects.writes, captures)) return null; + return inlinableBody(fn, captures) ? fn : null; + }; + + /** inlineTarget for a callback created in `fn` whose captured bindings + * nothing assigns after their declaration: `fn`'s own locals and + * parameters, written neither by `fn` nor by any closure that shares + * them, and not by the callback body. The callback must not observe the + * ambient receiver (AmbientReceiverReaders). */ + private stableTarget(fn: IrFunction): InlineTarget { + const locals = new Map(fn.locals.map((l) => [l.id, l])); + const inherited = new Set((fn.captures ?? []).map((c) => c.localId)); + const written = this.written.get(fn.name); + return (arg) => { + const target = this.closureTarget(arg); + if (!target || !written || arg.kind !== "closure") return null; + if (!this.receivers.ignores(target)) return null; + for (const id of arg.captures) { + const local = locals.get(id); + if (!local || local.tdz || inherited.has(id) || written.has(id)) return null; + } + const captures = new Set((target.captures ?? []).map((c) => c.localId)); + const assigns = !everyStmtList(target.body, { + stmt: (st) => !((st.kind === "assign" || st.kind === "forOf") && captures.has(st.localId)), + expr: (ex) => + !((ex.kind === "assignExpr" || ex.kind === "incDec") && captures.has(ex.localId)), + }); + return !assigns && inlinableBody(target, captures) ? target : null; + }; + } + + /** The function behind a closure-literal callback the loop can inline. */ + private closureTarget(arg: IrExpr): IrFunction | null { if (arg.kind !== "closure" || arg.adapts) return null; const fn = this.effects.fn(arg.fnName); if (!fn || fn.async || fn.generator || fn.classCaptures?.length) return null; - const captures = new Set((fn.captures ?? []).map((c) => c.localId)); - if (captures.size !== arg.captures.length) return null; - const effects = this.effects.ofFunction(fn); - if (!effects || intersects(effects.writes, captures)) return null; - if (fn.locals.some((l) => l.tdz || (l.boxed && !captures.has(l.id)))) return null; - let size = 0; - const small = everyStmtList(fn.body, { - expr: (e) => ++size <= MAX_INLINE_NODES && e.kind !== "closure" && e.kind !== "selfRef", - stmt: (s) => ++size <= MAX_INLINE_NODES && s.kind !== "tryCatch", - }); - return small ? fn : null; - }; + if ((fn.captures ?? []).length !== arg.captures.length) return null; + return fn; + } private emit(plan: Plan): IrExpr | null { - const built = new FusedLoop(this.lowerer, plan.chain, this.inlineTarget).build(); + const built = new FusedLoop(this.lowerer, plan.chain, plan.inline ?? this.inlineTarget).build(); if (!built) return null; + for (const id of built.inlinedCaptures) this.inlinedCaptures.add(id); let name = this.helpers.get(built.key); if (!name) { - name = keyedHelperName(this.lowerer, "%arr.fused", built.key); + name = keyedHelperName(this.lowerer, plan.inline ? "%arr.loop" : "%arr.fused", built.key); this.helpers.set(built.key, name); - this.added.push({ ...built.fn, name }); + const helper: IrFunction = { ...built.fn, name }; + // A lone call's loop stands in the inlined callback's stack frame. + if (plan.frame !== undefined) helper.sourceName = plan.frame; + this.added.push(helper); } return { kind: "call", @@ -866,6 +989,48 @@ class PipelineFusion { } } +/** Whether a statement inside `e` (a sequence expression's) returns. */ +function returns(e: IrExpr): boolean { + return !everyExpr(e, { expr: () => true, stmt: (s) => s.kind !== "return" }); +} + +/** Drops the box of each binding in `inlined` that no closure or class + * created in `fn` captures any more: the callbacks that captured it were + * copied into loops, which receive its value. A dead-zone binding keeps the + * box that represents its uninitialized state, and bindings `fn` itself + * captures keep theirs. */ +function unboxUncaptured(fn: IrFunction, inlined: ReadonlySet): void { + const captured = new Set(); + everyStmtList(fn.body, { + expr: (e) => { + if (e.kind === "closure" || e.kind === "classRef") + for (const id of e.captures ?? []) captured.add(id); + return true; + }, + stmt: () => true, + }); + const inherited = new Set( + [...(fn.captures ?? []), ...(fn.classCaptures ?? [])].map((c) => c.localId), + ); + fn.locals = fn.locals.map((local): IrLocal => { + if (local.boxed !== true || local.tdz === true || !inlined.has(local.id)) return local; + if (captured.has(local.id) || inherited.has(local.id)) return local; + const { boxed: _boxed, ...plain } = local; + return plain; + }); +} + +/** A callback body the loop can copy: small, no nested closures, recursion + * or try statements, and no boxed locals besides its captures. */ +function inlinableBody(fn: IrFunction, captures: ReadonlySet): boolean { + if (fn.locals.some((l) => l.tdz || (l.boxed && !captures.has(l.id)))) return false; + let size = 0; + return everyStmtList(fn.body, { + expr: (e) => ++size <= MAX_INLINE_NODES && e.kind !== "closure" && e.kind !== "selfRef", + stmt: (s) => ++size <= MAX_INLINE_NODES && s.kind !== "tryCatch", + }); +} + function intersects(a: ReadonlySet, b: ReadonlySet): boolean { for (const id of a) if (b.has(id)) return true; return false; @@ -1080,8 +1245,23 @@ class FusedLoop { const id = this.local(l.name, l.type, true); renamed.set(l.id, id); } + const rename = (id: string): string => renamed.get(id) ?? id; + const renameExpr = (e: IrExpr): IrExpr => { + switch (e.kind) { + case "varRef": + case "incDec": + case "assignExpr": + return { ...e, localId: rename(e.localId) }; + default: + return e; + } + }; + const bind: IrStmt[] = fn.params.flatMap((p, index): IrStmt[] => + aliased.has(p.localId) + ? [] + : [{ kind: "varDecl", localId: rename(p.localId), init: args[index]!, loc }], + ); const labels = new Map(); - const exit = this.fresh("%fused.exit"); const label = (name: string): string => { let id = labels.get(name); if (!id) { @@ -1090,19 +1270,48 @@ class FusedLoop { } return id; }; + /** Locals and labels of a copied statement; returns are the caller's. */ + const renameStmt = (st: IrStmt): IrStmt => { + switch (st.kind) { + case "varDecl": + case "assign": + return { ...st, localId: rename(st.localId) }; + case "break": + case "continue": + return st.label ? { ...st, label: label(st.label) } : st; + case "while": + case "doWhile": + case "for": + case "block": + return st.labels ? { ...st, labels: st.labels.map(label) } : st; + default: + return st; + } + }; + // A body whose only return is its last statement (`(x) => x * k`, + // `{ const y = x * 2; return y > 4; }`) needs no exit block: its other + // statements run after the bindings, and the call's value is the + // returned expression. + const last = fn.body[fn.body.length - 1]; + const prefix = fn.body.slice(0, -1); + if ( + last !== undefined && + last.kind === "return" && + last.value !== null && + typeEquals(last.value.type, fn.returnType) && + !returns(last.value) && + prefix.every((st) => everyStmt(st, { expr: () => true, stmt: (x) => x.kind !== "return" })) + ) { + const copy = { expr: renameExpr, stmt: renameStmt }; + return { + pre: [...bind, ...transformStmtList(prefix, copy)], + value: transformExpr(last.value, copy), + }; + } + const exit = this.fresh("%fused.exit"); const result = fn.returnType.kind === "void" ? null : this.local("ret", fn.returnType, true); - const rename = (id: string): string => renamed.get(id) ?? id; const body = transformStmtList(fn.body, { - expr: (e) => { - switch (e.kind) { - case "varRef": - case "incDec": - case "assignExpr": - return { ...e, localId: rename(e.localId) }; - default: - return e; - } - }, + expr: renameExpr, stmt: (s): IrStmt => { switch (s.kind) { case "return": { @@ -1122,27 +1331,14 @@ class FusedLoop { loc: s.loc, }; } - case "varDecl": - case "assign": - return { ...s, localId: rename(s.localId) }; case "break": case "continue": return s.label && s.label !== exit ? { ...s, label: label(s.label) } : s; - case "while": - case "doWhile": - case "for": - case "block": - return s.labels ? { ...s, labels: s.labels.map(label) } : s; default: - return s; + return renameStmt(s); } }, }); - const bind: IrStmt[] = fn.params.flatMap((p, index): IrStmt[] => - aliased.has(p.localId) - ? [] - : [{ kind: "varDecl", localId: rename(p.localId), init: args[index]!, loc }], - ); const pre: IrStmt[] = []; if (result !== null) pre.push({ kind: "varDecl", localId: result, init: null, loc }); pre.push({ kind: "block", labels: [exit], body: [...bind, ...body], loc }); @@ -1155,7 +1351,13 @@ class FusedLoop { }; } - build(): { fn: Omit; args: IrExpr[]; key: string } | null { + build(): { + fn: Omit; + args: IrExpr[]; + key: string; + /** Bindings the callbacks copied into the loop captured at this site. */ + inlinedCaptures: string[]; + } | null { const { chain, loc } = this; const arrT = chain.sourceType; const a = this.param("a", chain.source, "src"); @@ -1640,7 +1842,10 @@ class FusedLoop { }; foldKnownUnions(fn); scalarizeRecordTemporaries(this.lowerer, fn); - return { fn, args: this.args, key: this.keyParts.join("|") }; + const inlinedCaptures = this.callees.flatMap((c) => + c.inline && c.arg.kind === "closure" ? c.arg.captures : [], + ); + return { fn, args: this.args, key: this.keyParts.join("|"), inlinedCaptures }; } } diff --git a/packages/compiler/src/ir/callback-specialization.ts b/packages/compiler/src/ir/callback-specialization.ts index 6038ccaa5..d67b557c4 100644 --- a/packages/compiler/src/ir/callback-specialization.ts +++ b/packages/compiler/src/ir/callback-specialization.ts @@ -16,7 +16,10 @@ const COPIED_NODE_FRACTION = 0.25; * closure it creates writes through its environment (and transitively the * closures those create). A parameter or capture absent from its function's * set holds the value it entered with for the whole call. */ -export function writtenLocals(mod: IrModule, nodes?: IrNodeIndex): Map> { +export function writtenLocals( + mod: { readonly functions: readonly IrFunction[] }, + nodes?: IrNodeIndex, +): Map> { return rebindings(mod, nodes).written; } @@ -31,7 +34,7 @@ const REBINDING_KINDS: readonly IrNodeKind[] = [ ]; function rebindings( - mod: IrModule, + mod: { readonly functions: readonly IrFunction[] }, nodes?: IrNodeIndex, ): { written: Map>; diff --git a/packages/compiler/test/array-pipeline-fusion.test.ts b/packages/compiler/test/array-pipeline-fusion.test.ts index 55cd0025e..0ff456a2c 100644 --- a/packages/compiler/test/array-pipeline-fusion.test.ts +++ b/packages/compiler/test/array-pipeline-fusion.test.ts @@ -108,5 +108,49 @@ const kept = rows.filter((r) => r.value > 3); console.log(kept.map((r) => r.id).length, kept.length); ${postlude}`); expect(init(mod).locals.some((l) => l.name === "kept")).toBe(true); - expect(helperCalls(init(mod))).toEqual(["%arr.filter", "%arr.fused"]); + expect(helperCalls(init(mod))).toEqual(["%arr.fused", "%arr.loop"]); +}); + +test("a lone call with a stable closure-literal callback runs as a loop", async () => { + const mod = await lowerSource(`${prelude} +const scale = 3; +const scaled = rows.map((r) => r.value * scale); +let total = 0; +rows.forEach((r) => { total += r.value; }); +const big = rows.filter((r) => r.value > scale); +const sum = scaled.reduce((acc, v) => acc + v, 0); +console.log(scaled.length, total, big.length, sum, rows.some((r) => r.id === scale)); +${postlude}`); + // forEach assigns \`total\`, a binding of \`run\`: it keeps its helper. + expect(helperCalls(init(mod))).toEqual([ + "%arr.forEach", + "%arr.loop", + "%arr.loop", + "%arr.loop", + "%arr.loop", + ]); + const loops = mod.functions.filter((f) => f.name.startsWith("%arr.loop.")); + expect(loops).toHaveLength(4); + // The callback bodies are copied into the loops: no closure value is + // created or called, and the captured \`scale\` is a plain parameter. + for (const fn of loops) { + expect(count(fn, "callValue")).toBe(0); + expect(count(fn, "closure")).toBe(0); + } + expect(count(init(mod), "closure")).toBe(1); + // No closure captures \`scale\` any more, so it needs no box. + expect(init(mod).locals.find((l) => l.name === "scale")?.boxed).toBeUndefined(); +}); + +test("a lone call keeps its helper when a capture can change while it runs", async () => { + const mod = await lowerSource(`${prelude} +let limit = 2; +const bump = (): void => { limit++; }; +const a = rows.filter((r) => { bump(); return r.id < limit; }); +let step = 1; +step = 2; +const b = rows.map((r) => r.id * step); +console.log(a.length, b.length, limit); +${postlude}`); + expect(helperCalls(init(mod))).toEqual(["%arr.filter", "%arr.map"]); }); diff --git a/packages/compiler/test/format-float-arguments.test.ts b/packages/compiler/test/format-float-arguments.test.ts index 6ce9c4bc0..795e238ef 100644 --- a/packages/compiler/test/format-float-arguments.test.ts +++ b/packages/compiler/test/format-float-arguments.test.ts @@ -3,6 +3,7 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { expect, test } from "vitest"; import { compile, deserializeModule, validateModule } from "../src/index.js"; +import { everyStmtList } from "../src/ir/traverse.js"; test("util.format %f lowers a boolean argument once", async () => { const dir = await mkdtemp(join(tmpdir(), "scriptc-format-float-")); @@ -22,14 +23,20 @@ test("util.format %f lowers a boolean argument once", async () => { throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); const mod = deserializeModule(await readFile(outPath, "utf8")); expect(validateModule(mod)).toEqual([]); - // One lifted helper per argument: the evaluated-for-effect statement - // reuses the lowered value instead of lowering the argument again. - const helpers = mod.functions - .map((f) => f.name) - .filter((name) => name.startsWith("%arr.")) - .map((name) => name.replace(/\.[0-9a-f]+$/, "")) - .sort(); - expect(helpers).toEqual(["%arr.every", "%arr.some"]); + // One lifted helper call per argument: the evaluated-for-effect + // statement reuses the lowered value instead of lowering the argument + // again. Each call runs its callback as a loop (array-pipelines.ts). + const helpers: string[] = []; + for (const fn of mod.functions) + everyStmtList(fn.body, { + expr: (e) => { + if (e.kind === "call" && e.callee.startsWith("%arr.")) + helpers.push(e.callee.replace(/\.[0-9a-f]+$/, "")); + return true; + }, + stmt: () => true, + }); + expect(helpers).toEqual(["%arr.loop", "%arr.loop"]); } finally { await rm(dir, { recursive: true, force: true }); } diff --git a/tests/diagnostics/contract-int32-escapes.ts b/tests/diagnostics/contract-int32-escapes.ts index fcbbcbfd9..57ed4ce39 100644 --- a/tests/diagnostics/contract-int32-escapes.ts +++ b/tests/diagnostics/contract-int32-escapes.ts @@ -14,4 +14,5 @@ class Box { const box = new Box(); const loose: any = box; loose.size = 0.5; -console.log([1.5, 2].map(double).join(","), box.size); +const pick: (x: number) => number = double; +console.log([1.5, 2].map(pick).join(","), box.size); diff --git a/tests/harness/__snapshots__/contract-int32-arrays.ts.txt b/tests/harness/__snapshots__/contract-int32-arrays.ts.txt index c326adbb5..56db22706 100644 --- a/tests/harness/__snapshots__/contract-int32-arrays.ts.txt +++ b/tests/harness/__snapshots__/contract-int32-arrays.ts.txt @@ -34,14 +34,14 @@ contract-int32-arrays.ts:16:13 - error SC7002: the element stored into 'counts' hint: make the int32 conversion explicit, for example 'Math.PI | 0', so Node stores the same value -contract-int32-arrays.ts:18:26 - error SC7002: the elements 'counts.map((x) => x * 2)' stores are not provably int32s (the array can reach 'doubled', declared Int32[]) +contract-int32-arrays.ts:18:44 - error SC7002: the element stored into 'counts.map((x) => x * 2)' is not provably an int32: 'x * 2' (the array can reach 'doubled', declared Int32[]) 17 | halveInto(counts, ids); 18 | const doubled: Int32[] = counts.map((x) => x * 2); - | ^~~~~~~~~~~~~~~~~~~~~~~~ + | ^~~~~ 19 | const parsed: Int32[] = JSON.parse("[1, 2]"); - hint: callback results are not followed; build the array with a loop that stores 'value | 0' + hint: make the int32 conversion explicit, for example '(x * 2) | 0', so Node stores the same value contract-int32-arrays.ts:19:15 - error SC7003: the Int32[] contract on 'parsed' cannot be checked: the array can come from dynamic (any or unknown) code (contract-int32-arrays.ts:19:25), whose element stores scriptc does not see diff --git a/tests/harness/__snapshots__/contract-int32-escapes.ts.txt b/tests/harness/__snapshots__/contract-int32-escapes.ts.txt index 920f4c4a4..1be04a0cf 100644 --- a/tests/harness/__snapshots__/contract-int32-escapes.ts.txt +++ b/tests/harness/__snapshots__/contract-int32-escapes.ts.txt @@ -21,6 +21,6 @@ contract-int32-escapes.ts:16:1 - error SC7002: the value stored into 'Box.size' 15 | const loose: any = box; 16 | loose.size = 0.5; | ^~~~~~~~~~~~~~~~ - 17 | console.log([1.5, 2].map(double).join(","), box.size); + 17 | const pick: (x: number) => number = double; hint: make the int32 conversion explicit, for example 'loose.size = 0.5 | 0', so Node computes the same value \ No newline at end of file From 52792d8c52919b16f703246c305247d7a5ed835f Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 09:54:58 -0500 Subject: [PATCH 016/259] Find weak collection entries through hashed indexes WeakMap and WeakSet kept each collection's entries in one list and found a key by walking it, and every collection's entries for a key in 1,024 shared buckets. Filling a collection and reading it back took quadratic time: 40,000 keys took 6.7 s against Node's 0.2 s, and 200,000 keys did not finish. Each thread now indexes its entries twice, in open-addressing tables with linear probing and backward-shift deletion: by collection, key and kind, for get, set, has and delete, and by key pointer, for a key's disposal, which ends the key's entries in every collection. A collection's entries and a key's entries are doubly linked, so an entry leaves both in constant time. The tables grow at half load and are freed when their last entry goes, so an exiting worker leaves none. 200,000 keys now take 0.24 s (Node 0.30 s). Closes #1702 Co-authored-by: ejc3 <1694850+ejc3@users.noreply.github.com> --- .../7742-weak-collections-many-keys.ts.json | 6 + packages/runtime/src/scr_json.c | 203 +++++++++++++++--- .../corpus/7742-weak-collections-many-keys.ts | 70 ++++++ .../7742-weak-collections-many-keys.ts.json | 1 + 4 files changed, 247 insertions(+), 33 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7742-weak-collections-many-keys.ts.json create mode 100644 tests/corpus/7742-weak-collections-many-keys.ts create mode 100644 tests/harness/corpus-costs/7742-weak-collections-many-keys.ts.json diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7742-weak-collections-many-keys.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7742-weak-collections-many-keys.ts.json new file mode 100644 index 000000000..e1a75c14e --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7742-weak-collections-many-keys.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7742-weak-collections-many-keys.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index da18a1c0b..4841da53d 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -15019,26 +15019,173 @@ typedef struct ScrWeakEntry { unsigned kind; ScrDyn *value; ScrWeakMap *owner; - struct ScrWeakEntry *next, *all_next; + /* The owner's entries, and every collection's entries for the same key + * pointer (whatever their kind): both doubly linked, so an entry leaves + * either list in constant time. */ + struct ScrWeakEntry *next, *prev, *key_next, *key_prev; } ScrWeakEntry; struct ScrWeakMap { size_t rc; ScrWeakEntry *entries; bool is_set; }; /* Weak observers borrow key identities. Values are traced strong edges; - * value-to-key cycles require explicit deletion or container disposal. */ -#define SCR_WEAK_BUCKETS 1024 -static SCR_TL ScrWeakEntry *scr_weak_entries[SCR_WEAK_BUCKETS]; -static size_t scr_weak_bucket(void *key) { - uintptr_t bits = (uintptr_t)key; - return ((bits >> 4) ^ (bits >> 14)) & (SCR_WEAK_BUCKETS - 1); + * value-to-key cycles require explicit deletion or container disposal. + * + * Two open-addressing indexes per thread find entries in expected constant + * time: scr_weak_index by (collection, key, kind), for get/set/has/delete, + * and scr_weak_keys by key pointer, the head of that key's entries, for a + * disposal, which ends the key's entries in every collection. Both use + * linear probing with backward-shift deletion, grow at half load, and are + * freed when their last entry goes. */ +static SCR_TL ScrWeakEntry **scr_weak_index; +static SCR_TL size_t scr_weak_index_mask, scr_weak_index_used; +typedef struct { void *key; ScrWeakEntry *head; } ScrWeakKeySlot; +static SCR_TL ScrWeakKeySlot *scr_weak_keys; +static SCR_TL size_t scr_weak_keys_mask, scr_weak_keys_used; + +static inline size_t scr_weak_mix(uintptr_t bits) { + bits ^= bits >> 33; + bits *= 0xff51afd7ed558ccdull; + bits ^= bits >> 29; + return (size_t)bits; +} +static inline size_t scr_weak_entry_hash(const ScrWeakMap *owner, const void *key, unsigned kind) { + return scr_weak_mix((uintptr_t)key ^ ((uintptr_t)owner * 0x9E3779B97F4A7C15ull) ^ ((uintptr_t)kind << 56)); +} +static inline size_t scr_weak_key_hash(const void *key) { return scr_weak_mix((uintptr_t)key); } + +static void scr_weak_index_put(ScrWeakEntry *entry) { + size_t j = scr_weak_entry_hash(entry->owner, entry->key, entry->kind) & scr_weak_index_mask; + while (scr_weak_index[j]) j = (j + 1) & scr_weak_index_mask; + scr_weak_index[j] = entry; +} +static void scr_weak_index_reserve(void) { + if (scr_weak_index && (scr_weak_index_used + 1) * 2 <= scr_weak_index_mask + 1) return; + ScrWeakEntry **old = scr_weak_index; + size_t n = old ? scr_weak_index_mask + 1 : 0, cap = n ? n * 2 : 64; + scr_weak_index = calloc(cap, sizeof *scr_weak_index); + if (!scr_weak_index) scr_json_oom(); + scr_weak_index_mask = cap - 1; + for (size_t i = 0; i < n; i++) + if (old[i]) scr_weak_index_put(old[i]); + free(old); +} +static ScrWeakEntry *scr_weak_find(ScrWeakMap *map, void *ptr, unsigned kind) { + if (!scr_weak_index) return NULL; + for (size_t j = scr_weak_entry_hash(map, ptr, kind) & scr_weak_index_mask;; j = (j + 1) & scr_weak_index_mask) { + ScrWeakEntry *entry = scr_weak_index[j]; + if (!entry) return NULL; + if (entry->owner == map && entry->key == ptr && entry->kind == kind) return entry; + } +} +static void scr_weak_index_delete(ScrWeakEntry *entry) { + size_t mask = scr_weak_index_mask; + size_t i = scr_weak_entry_hash(entry->owner, entry->key, entry->kind) & mask; + while (scr_weak_index[i] != entry) i = (i + 1) & mask; + if (--scr_weak_index_used == 0) { + /* Empty: give the table back, so a thread that exits leaves none. */ + free(scr_weak_index); + scr_weak_index = NULL; + return; + } + for (size_t k = i;;) { + scr_weak_index[i] = NULL; + for (;;) { + k = (k + 1) & mask; + ScrWeakEntry *e = scr_weak_index[k]; + if (!e) return; + size_t home = scr_weak_entry_hash(e->owner, e->key, e->kind) & mask; + /* e stays unless its home lies cyclically outside (i, k]. */ + if (i <= k ? (i < home && home <= k) : (i < home || home <= k)) continue; + scr_weak_index[i] = e; + i = k; + break; + } + } +} + +static ScrWeakKeySlot *scr_weak_key_slot(const void *key) { + if (!scr_weak_keys) return NULL; + for (size_t j = scr_weak_key_hash(key) & scr_weak_keys_mask;; j = (j + 1) & scr_weak_keys_mask) { + if (scr_weak_keys[j].key == key) return &scr_weak_keys[j]; + if (!scr_weak_keys[j].key) return NULL; + } +} +static ScrWeakKeySlot *scr_weak_key_slot_put(void *key) { + if (!scr_weak_keys || (scr_weak_keys_used + 1) * 2 > scr_weak_keys_mask + 1) { + ScrWeakKeySlot *old = scr_weak_keys; + size_t n = old ? scr_weak_keys_mask + 1 : 0, cap = n ? n * 2 : 64; + scr_weak_keys = calloc(cap, sizeof *scr_weak_keys); + if (!scr_weak_keys) scr_json_oom(); + scr_weak_keys_mask = cap - 1; + for (size_t i = 0; i < n; i++) { + if (!old[i].key) continue; + size_t j = scr_weak_key_hash(old[i].key) & scr_weak_keys_mask; + while (scr_weak_keys[j].key) j = (j + 1) & scr_weak_keys_mask; + scr_weak_keys[j] = old[i]; + } + free(old); + } + size_t j = scr_weak_key_hash(key) & scr_weak_keys_mask; + while (scr_weak_keys[j].key && scr_weak_keys[j].key != key) j = (j + 1) & scr_weak_keys_mask; + if (!scr_weak_keys[j].key) { + scr_weak_keys[j].key = key; + scr_weak_keys[j].head = NULL; + scr_weak_keys_used++; + } + return &scr_weak_keys[j]; +} +static void scr_weak_key_slot_delete(ScrWeakKeySlot *slot) { + size_t mask = scr_weak_keys_mask; + size_t i = (size_t)(slot - scr_weak_keys); + if (--scr_weak_keys_used == 0) { + free(scr_weak_keys); + scr_weak_keys = NULL; + return; + } + for (size_t k = i;;) { + scr_weak_keys[i].key = NULL; + scr_weak_keys[i].head = NULL; + for (;;) { + k = (k + 1) & mask; + if (!scr_weak_keys[k].key) return; + size_t home = scr_weak_key_hash(scr_weak_keys[k].key) & mask; + if (i <= k ? (i < home && home <= k) : (i < home || home <= k)) continue; + scr_weak_keys[i] = scr_weak_keys[k]; + i = k; + break; + } + } +} + +/* Indexes a new entry (its key, kind and owner set) under its key. */ +static void scr_weak_link(ScrWeakEntry *entry) { + scr_weak_index_reserve(); + scr_weak_index_put(entry); + scr_weak_index_used++; + ScrWeakKeySlot *slot = scr_weak_key_slot_put(entry->key); + entry->key_prev = NULL; + entry->key_next = slot->head; + if (slot->head) slot->head->key_prev = entry; + slot->head = entry; +} + +/* Takes an entry out of both indexes (it stays in its owner's list). */ +static void scr_weak_unlink(ScrWeakEntry *entry) { + scr_weak_index_delete(entry); + if (entry->key_next) entry->key_next->key_prev = entry->key_prev; + if (entry->key_prev) entry->key_prev->key_next = entry->key_next; + else { + ScrWeakKeySlot *slot = scr_weak_key_slot(entry->key); + if (entry->key_next) slot->head = entry->key_next; + else scr_weak_key_slot_delete(slot); + } } static void scr_weak_remove_impl(ScrWeakEntry *entry, bool collected) { - ScrWeakEntry **slot = &entry->owner->entries; - while (*slot != entry) slot = &(*slot)->next; - *slot = entry->next; - slot = &scr_weak_entries[scr_weak_bucket(entry->key)]; - while (*slot != entry) slot = &(*slot)->all_next; - *slot = entry->all_next; + ScrWeakMap *owner = entry->owner; + if (entry->next) entry->next->prev = entry->prev; + if (entry->prev) entry->prev->next = entry->next; + else owner->entries = entry->next; + scr_weak_unlink(entry); ScrDyn *value = entry->value; free(entry); /* Unlink before release: releasing a value can dispose another key. */ @@ -15062,10 +15209,9 @@ static void scr_weak_map_gcfree(void *ptr) { static void scr_weak_disposed(void *key) { for (;;) { - ScrWeakEntry *entry = scr_weak_entries[scr_weak_bucket(key)]; - while (entry && entry->key != key) entry = entry->all_next; - if (!entry) return; - scr_weak_remove(entry); + ScrWeakKeySlot *slot = scr_weak_key_slot(key); + if (!slot) return; + scr_weak_remove(slot->head); } } @@ -15122,12 +15268,6 @@ static int scr_weak_key(const ScrDyn *key, void **ptr, unsigned *kind) { } } -static ScrWeakEntry *scr_weak_find(ScrWeakMap *map, void *ptr, unsigned kind) { - for (ScrWeakEntry *entry = map->entries; entry; entry = entry->next) - if (entry->key == ptr && entry->kind == kind) return entry; - return NULL; -} - static bool scr_weak_set(ScrWeakMap *map, ScrDyn *key, ScrDyn *value) { void *ptr = NULL; unsigned kind = 0; @@ -15156,10 +15296,9 @@ static bool scr_weak_set(ScrWeakMap *map, ScrDyn *key, ScrDyn *value) { entry->value = scr_dyn_retain(value); entry->owner = map; entry->next = map->entries; + if (map->entries) map->entries->prev = entry; map->entries = entry; - size_t bucket = scr_weak_bucket(ptr); - entry->all_next = scr_weak_entries[bucket]; - scr_weak_entries[bucket] = entry; + scr_weak_link(entry); return true; } @@ -16371,16 +16510,14 @@ static bool scr_dyn_decl_rekey(ScrDyn *node, void *ptr) { bool moved = false; if (!scr_weak_observing) return false; for (;;) { - ScrWeakEntry **slot = &scr_weak_entries[scr_weak_bucket(node)]; - while (*slot && !((*slot)->key == (void *)node && (*slot)->kind == 0)) slot = &(*slot)->all_next; - ScrWeakEntry *entry = *slot; + ScrWeakKeySlot *slot = scr_weak_key_slot(node); + ScrWeakEntry *entry = slot ? slot->head : NULL; + while (entry && entry->kind != 0) entry = entry->key_next; if (!entry) return moved; - *slot = entry->all_next; + scr_weak_unlink(entry); entry->key = ptr; entry->kind = 32; - ScrWeakEntry **head = &scr_weak_entries[scr_weak_bucket(ptr)]; - entry->all_next = *head; - *head = entry; + scr_weak_link(entry); moved = true; } } diff --git a/tests/corpus/7742-weak-collections-many-keys.ts b/tests/corpus/7742-weak-collections-many-keys.ts new file mode 100644 index 000000000..2cb2b103e --- /dev/null +++ b/tests/corpus/7742-weak-collections-many-keys.ts @@ -0,0 +1,70 @@ +// Weak collections with many keys: entries found among tens of thousands +// in WeakMaps and WeakSets that share keys, deleted and replaced, and gone +// with their keys, so blocks a new key reuses are not found under it. +// Keys in reference cycles die by the cycle collector. +class Key { + readonly id: number; + peer: Key | null = null; + constructor(id: number) { + this.id = id; + } +} + +const n = 40000; +let keys: Key[] = []; +for (let i = 0; i < n; i++) keys.push(new Key(i)); +const values = new WeakMap(); +const labels = new WeakMap(); +const marked = new WeakSet(); +for (const k of keys) { + values.set(k, k.id * 2); + if (k.id % 3 === 0) labels.set(k, "k" + k.id); + if (k.id % 2 === 0) marked.add(k); +} +let sum = 0; +let labelled = 0; +let counted = 0; +for (const k of keys) { + sum += values.get(k) ?? 0; + if (labels.has(k)) labelled++; + if (marked.has(k)) counted++; +} +console.log("filled", sum, labelled, counted); + +// Deleting every fourth key from one collection leaves the others alone. +let deleted = 0; +for (const k of keys) if (k.id % 4 === 0 && values.delete(k)) deleted++; +let remaining = 0; +for (const k of keys) if (values.has(k)) remaining++; +console.log("deleted", deleted, remaining, values.delete(keys[0]!), marked.has(keys[0]!), labels.get(keys[3]!)); + +// Overwriting keeps one entry per key. +for (const k of keys) if (k.id % 5 === 0) values.set(k, -1); +let negative = 0; +for (const k of keys) if (values.get(k) === -1) negative++; +console.log("overwritten", negative); + +// Dropping the keys ends their entries; new keys are not found. +keys = []; +const fresh: Key[] = []; +for (let i = 0; i < n; i++) fresh.push(new Key(n + i)); +let stale = 0; +for (const k of fresh) if (values.has(k) || labels.has(k) || marked.has(k)) stale++; +console.log("fresh", fresh.length, stale); + +// Keys that reach each other die together through the cycle collector. +for (let round = 0; round < 3; round++) { + let ring: Key[] = []; + for (let i = 0; i < 1000; i++) ring.push(new Key(i)); + for (let i = 0; i < ring.length; i++) ring[i]!.peer = ring[(i + 1) % ring.length]!; + for (const k of ring) { + values.set(k, round); + marked.add(k); + } + ring = []; +} +const after: Key[] = []; +for (let i = 0; i < 3000; i++) after.push(new Key(i)); +let found = 0; +for (const k of after) if (values.has(k) || marked.has(k)) found++; +console.log("cycles", found); diff --git a/tests/harness/corpus-costs/7742-weak-collections-many-keys.ts.json b/tests/harness/corpus-costs/7742-weak-collections-many-keys.ts.json new file mode 100644 index 000000000..97e5fc450 --- /dev/null +++ b/tests/harness/corpus-costs/7742-weak-collections-many-keys.ts.json @@ -0,0 +1 @@ +{ "plain": 2500, "san": 6000 } From f32d0cd1847c13f1166ae925334c701b41a55fc5 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Fri, 23 Oct 2026 08:06:38 -0700 Subject: [PATCH 017/259] Make the packaging island fixture a webpack bundle Main now compiles minified npm packages (#1989), so ni-minified no longer refuses and the island report lost its packaging class. The fixture is now ni-bundled, whose build-transform markers still refuse it as shipped. Co-Authored-By: Claude Opus 5.5 --- tests/coverage-fixtures/node-islands/main.ts | 2 +- .../{ni-minified => ni-bundled}/index.d.ts | 0 .../node_modules/ni-bundled/index.js | 15 +++++++++++++ .../{ni-minified => ni-bundled}/package.json | 2 +- .../node_modules/ni-minified/index.js | 1 - .../__snapshots__/coverage-node-islands.txt | 22 +++++++++---------- tests/harness/coverage.test.ts | 10 ++++----- 7 files changed, 33 insertions(+), 19 deletions(-) rename tests/coverage-fixtures/node-islands/node_modules/{ni-minified => ni-bundled}/index.d.ts (100%) create mode 100644 tests/coverage-fixtures/node-islands/node_modules/ni-bundled/index.js rename tests/coverage-fixtures/node-islands/node_modules/{ni-minified => ni-bundled}/package.json (65%) delete mode 100644 tests/coverage-fixtures/node-islands/node_modules/ni-minified/index.js diff --git a/tests/coverage-fixtures/node-islands/main.ts b/tests/coverage-fixtures/node-islands/main.ts index ac6037d1a..597ba57cf 100644 --- a/tests/coverage-fixtures/node-islands/main.ts +++ b/tests/coverage-fixtures/node-islands/main.ts @@ -5,7 +5,7 @@ import { describe } from "ni-gap"; import { compile } from "ni-eval"; import { Counter } from "ni-ctor"; -import { shout } from "ni-minified"; +import { shout } from "ni-bundled"; import { twice } from "ni-typed"; console.log(describe()); diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-minified/index.d.ts b/tests/coverage-fixtures/node-islands/node_modules/ni-bundled/index.d.ts similarity index 100% rename from tests/coverage-fixtures/node-islands/node_modules/ni-minified/index.d.ts rename to tests/coverage-fixtures/node-islands/node_modules/ni-bundled/index.d.ts diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-bundled/index.js b/tests/coverage-fixtures/node-islands/node_modules/ni-bundled/index.js new file mode 100644 index 000000000..2e88085be --- /dev/null +++ b/tests/coverage-fixtures/node-islands/node_modules/ni-bundled/index.js @@ -0,0 +1,15 @@ +// A webpack bundle: its build-transform markers keep it out of the native +// subset as shipped (a packaging island). +var __webpack_modules__ = { + 1: function (module) { + module.exports.shout = function shout(s) { + return s.toUpperCase() + "!"; + }; + }, +}; +function __webpack_require__(id) { + var module = { exports: {} }; + __webpack_modules__[id](module); + return module.exports; +} +module.exports = __webpack_require__(1); diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-minified/package.json b/tests/coverage-fixtures/node-islands/node_modules/ni-bundled/package.json similarity index 65% rename from tests/coverage-fixtures/node-islands/node_modules/ni-minified/package.json rename to tests/coverage-fixtures/node-islands/node_modules/ni-bundled/package.json index cc819dfc8..fd9bab40d 100644 --- a/tests/coverage-fixtures/node-islands/node_modules/ni-minified/package.json +++ b/tests/coverage-fixtures/node-islands/node_modules/ni-bundled/package.json @@ -1,5 +1,5 @@ { - "name": "ni-minified", + "name": "ni-bundled", "version": "1.0.0", "main": "index.js" } diff --git a/tests/coverage-fixtures/node-islands/node_modules/ni-minified/index.js b/tests/coverage-fixtures/node-islands/node_modules/ni-minified/index.js deleted file mode 100644 index 25c0e11ac..000000000 --- a/tests/coverage-fixtures/node-islands/node_modules/ni-minified/index.js +++ /dev/null @@ -1 +0,0 @@ -"use strict";exports.shout=function shout(s){return s.toUpperCase()+"!"}; \ No newline at end of file diff --git a/tests/harness/__snapshots__/coverage-node-islands.txt b/tests/harness/__snapshots__/coverage-node-islands.txt index e8876bb0d..e94ad3560 100644 --- a/tests/harness/__snapshots__/coverage-node-islands.txt +++ b/tests/harness/__snapshots__/coverage-node-islands.txt @@ -5,12 +5,12 @@ scriptc coverage tests/coverage-fixtures/node-islands/main.ts in dynamic tier 17 (operate on values typed only at runtime; --explain-dynamic lists them) npm package compilation: - ni-minified refused (its shipped JS looks minified) - ni-gap static - ni-eval static - ni-ctor static - ni-typed static - ni-dep static + ni-bundled refused (its shipped JS carries build-transform markers (bundled/transpiled dist)) + ni-gap static + ni-eval static + ni-ctor static + ni-typed static + ni-dep static Node islands (would-be, report-only: the build is unchanged; --node-islands=auto) gap ni-gap@1.0.0 @@ -20,8 +20,8 @@ scriptc coverage tests/coverage-fixtures/node-islands/main.ts object-model ni-ctor@1.0.0 tests/coverage-fixtures/node-islands/node_modules/ni-ctor/index.js:9:1: R2.1 constructor functions: a write of 'Counter.prototype.add' +1 more reason in 1 module; carries ni-dep - packaging ni-minified@1.0.0 - SC2013: its shipped JS looks minified + packaging ni-bundled@1.0.0 + SC2013: its shipped JS carries build-transform markers (bundled/transpiled dist) reached from native code and from an island: ni-typed hint: scriptc coverage --explain-island= lists every reason @@ -31,9 +31,9 @@ scriptc coverage tests/coverage-fixtures/node-islands/main.ts hint: this form is valid TypeScript but does not compile yet — rewrite it with a supported equivalent of the construct the message names (https://scriptc.dev/limitations lists the boundary) blockers: - ×2 SC2013 cannot compile npm package 'ni-minified' statically: its implementation is not part of the compiled module graph + ×2 SC2013 cannot compile npm package 'ni-bundled' statically: its implementation is not part of the compiled module graph at tests/coverage-fixtures/node-islands/main.ts:8:1, tests/coverage-fixtures/node-islands/main.ts:16:13 hint: use a dependency with supported source, or replace the unsupported operation; scriptc has no interpreter fallback - ×1 SC2013 cannot compile npm package 'ni-minified' statically: its shipped JS looks minified + ×1 SC2013 cannot compile npm package 'ni-bundled' statically: its shipped JS carries build-transform markers (bundled/transpiled dist) at tests/coverage-fixtures/node-islands/main.ts:8:1 - hint: to compile it anyway, name it with --npm-static=ni-minified (or --npm-static=ni-minified... to include its dependencies) \ No newline at end of file + hint: to compile it anyway, name it with --npm-static=ni-bundled (or --npm-static=ni-bundled... to include its dependencies) \ No newline at end of file diff --git a/tests/harness/coverage.test.ts b/tests/harness/coverage.test.ts index 17c76034a..2c34a69e1 100644 --- a/tests/harness/coverage.test.ts +++ b/tests/harness/coverage.test.ts @@ -832,7 +832,7 @@ test("a cycle whose top level calls a builtin with a builtin function value is a test("Node islands (report-only): one package per class, gap islands first", async () => { // ni-gap (a fence inside the native subset), ni-eval (new Function), - // ni-ctor (a constructor function, carrying ni-dep), ni-minified (not + // ni-ctor (a constructor function, carrying ni-dep), ni-bundled (not // compilable as shipped), ni-typed (native, also reached from ni-ctor). const entry = fixture("node-islands/main.ts"); await expect(report(entry)).toMatchFileSnapshot("__snapshots__/coverage-node-islands.txt"); @@ -842,7 +842,7 @@ test("Node islands (report-only): one package per class, gap islands first", asy ["ni-gap", "gap"], ["ni-eval", "runtime"], ["ni-ctor", "object-model"], - ["ni-minified", "packaging"], + ["ni-bundled", "packaging"], ]); expect(islands.packages.map((p) => [p.package, p.status, p.islands])).toEqual([ ["ni-dep", "inside", ["ni-ctor"]], @@ -861,10 +861,10 @@ test("Node islands (report-only): one package per class, gap islands first", asy ["ni-gap", "gap", 7], ["ni-eval", "runtime", 4], ["ni-ctor", "object-model", 9], - ["ni-minified", "packaging", undefined], + ["ni-bundled", "packaging", undefined], ]); // The gates: the blocker gate is today's build (which refuses - // ni-minified with SC2013, and nothing else); the island gates fail on + // ni-bundled with SC2013, and nothing else); the island gates fail on // the would-be islands. expect(coverage.diagnostics.every((d) => d.code === "SC2013")).toBe(true); expect(coveragePasses(coverage, "island-gaps")).toBe(false); @@ -879,7 +879,7 @@ test("Node island policy from the command line: native, forced, off", () => { expect(forced.islands.map((i) => [i.package, i.class, i.decision])).toEqual([ ["ni-gap", "gap", "auto"], ["ni-ctor", "object-model", "auto"], - ["ni-minified", "packaging", "auto"], + ["ni-bundled", "packaging", "auto"], ["ni-typed", "marked", "cli"], ]); expect(forced.violations.map((v) => v.code)).toEqual(["SC8003"]); From e1358fb5635b9fe65a24c1854170366773437dd9 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 10:16:30 -0500 Subject: [PATCH 018/259] Read Math, JSON and Reflect as real objects in JavaScript In JavaScript sources, Math, JSON or Reflect read as a value lowered to an identity token, the string "[builtin Math]": typeof, String, `in`, descriptors and member calls through an alias all had string semantics. Each of these namespaces read as a value is now one object per program, built on first use, with Node 24's own properties in Node's order: function members are writable, configurable and non-enumerable with Node's `length`, the Math constants are read-only, and Symbol.toStringTag names the namespace. Members hold the same function values the spelled member read gives; a member without one throws its fence when called. Global reads, globalThis, destructuring and shorthand properties all produce the same object, and an object with a string Symbol.toStringTag coerces to "[object ]". Direct member calls keep their static lowerings, so replacing or deleting a function member would not reach them: such changes throw SC1090. New properties and attribute-only redefinitions behave as in Node. --- .../compiler/src/backend/llvm/expr-dynamic.ts | 4 + .../compiler/src/backend/llvm/lib-shared.ts | 2 + .../frontend/lowering/builtin-namespaces.ts | 285 ++++++++++++++++++ .../src/frontend/lowering/builtins/json.ts | 12 +- .../lowering/expressions/object-literals.ts | 7 +- .../lowering/expressions/property-access.ts | 12 + .../src/frontend/lowering/lower-stdlib.ts | 65 ++-- .../src/frontend/lowering/lower-stmts.ts | 4 +- .../compiler/src/frontend/lowering/lowerer.ts | 8 + .../src/frontend/lowering/surfaces.ts | 3 + .../compiler/src/ir/builtin-signatures.ts | 2 + packages/compiler/src/ir/ir.ts | 12 +- packages/compiler/src/ir/runtime-features.ts | 2 + .../test/namespace-member-fences.test.ts | 67 ++++ .../7186-namespace-object-values.js.json | 6 + .../7187-namespace-object-reflection.js.json | 6 + .../7188-namespace-object-extensions.js.json | 6 + packages/runtime/src/scr_dyn.h | 22 ++ packages/runtime/src/scr_dyn_invoke.c | 29 ++ packages/runtime/src/scr_js_object.c | 4 +- packages/runtime/src/scr_json.c | 90 +++++- packages/runtime/src/scr_symbol.c | 5 + tests/corpus/7186-namespace-object-values.js | 22 ++ .../7187-namespace-object-reflection.js | 23 ++ .../7188-namespace-object-extensions.js | 16 + .../7186-namespace-object-values.js.json | 1 + .../7187-namespace-object-reflection.js.json | 1 + .../7188-namespace-object-extensions.js.json | 1 + 28 files changed, 678 insertions(+), 39 deletions(-) create mode 100644 packages/compiler/src/frontend/lowering/builtin-namespaces.ts create mode 100644 packages/compiler/test/namespace-member-fences.test.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7186-namespace-object-values.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7187-namespace-object-reflection.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7188-namespace-object-extensions.js.json create mode 100644 tests/corpus/7186-namespace-object-values.js create mode 100644 tests/corpus/7187-namespace-object-reflection.js create mode 100644 tests/corpus/7188-namespace-object-extensions.js create mode 100644 tests/harness/corpus-costs/7186-namespace-object-values.js.json create mode 100644 tests/harness/corpus-costs/7187-namespace-object-reflection.js.json create mode 100644 tests/harness/corpus-costs/7188-namespace-object-extensions.js.json diff --git a/packages/compiler/src/backend/llvm/expr-dynamic.ts b/packages/compiler/src/backend/llvm/expr-dynamic.ts index 07a538184..fac708b82 100644 --- a/packages/compiler/src/backend/llvm/expr-dynamic.ts +++ b/packages/compiler/src/backend/llvm/expr-dynamic.ts @@ -115,6 +115,10 @@ export function emitDynamicExpr( const box = host.dyn.dynFuncBoxHelper(v.type); const t = B.tmp(); B.line(`${t} = call ptr @${box}(ptr ${v.name}, ptr ${name})`); + if (e.fnLength !== undefined) { + host.declare(`declare void @scr_dyn_function_set_length(ptr, i32)`); + B.line(`call void @scr_dyn_function_set_length(ptr ${t}, i32 ${e.fnLength})`); + } return host.own({ name: t, type: e.type }); } const conv = host.dyn.toDynHelper(v.type); diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index af32c6936..44db20d03 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -1027,6 +1027,8 @@ export const LIB_FN_SYMS: Record = { "dyn.nativeDateHandleIs": "scr_dyn_native_date_is", "dyn.globalConstructor": "scr_dyn_global_constructor", "dyn.builtinFunction": "scr_dyn_builtin_function", + "dyn.namespaceNew": "scr_dyn_namespace_new", + "dyn.namespaceDefine": "scr_dyn_namespace_define", "date.nativeNew": "scr_dyn_native_date_new", "date.nativeNewFields": "scr_dyn_native_date_new_fields", "date.nativeNewValue": "scr_dyn_native_date_new_value", diff --git a/packages/compiler/src/frontend/lowering/builtin-namespaces.ts b/packages/compiler/src/frontend/lowering/builtin-namespaces.ts new file mode 100644 index 000000000..bfe3c5e39 --- /dev/null +++ b/packages/compiler/src/frontend/lowering/builtin-namespaces.ts @@ -0,0 +1,285 @@ +/** The standard namespace objects (`Math`, `JSON`, `Reflect`) read as + * JavaScript values. Each is one object per program, built on first use, + * with Node's own properties in Node's order: the functions are writable, + * configurable and non-enumerable, the Math constants are read-only and + * non-configurable, and `Symbol.toStringTag` names the namespace. Function + * members hold the same function values the spelled `Math.abs` read gives; + * members without one hold a function that throws the named fence when + * called. Direct member calls (`Math.abs(x)`) keep their static lowerings. */ +import { + BOOL, + DYN, + F64, + STRING, + SYMBOL_T, + VOID, + type IrExpr, + type IrStmt, + type SrcLoc, + funcOf, +} from "../../ir/ir.js"; +import { helperLoc, varRef } from "../../ir/build.js"; +import { unsupportedDiag } from "../../diagnostics/diagnostic.js"; +import type { Lowerer } from "./lowerer.js"; +import { InternalCompilerError } from "../../errors.js"; +import { mathMemberValue } from "./lower-stdlib.js"; +import { jsonMemberValue } from "./builtins/json.js"; + +/** A function member with its `length`, or a constant (`length` -1). */ +interface NamespaceMember { + readonly key: string; + readonly length: number; +} + +/** Node 24's own string-keyed properties of the namespace `name`, in + * order, or null when `name` is not a namespace. */ +function namespaceMembers(name: string): readonly NamespaceMember[] | null { + switch (name) { + case "Math": + return [ + { key: "abs", length: 1 }, + { key: "acos", length: 1 }, + { key: "acosh", length: 1 }, + { key: "asin", length: 1 }, + { key: "asinh", length: 1 }, + { key: "atan", length: 1 }, + { key: "atanh", length: 1 }, + { key: "atan2", length: 2 }, + { key: "ceil", length: 1 }, + { key: "cbrt", length: 1 }, + { key: "expm1", length: 1 }, + { key: "clz32", length: 1 }, + { key: "cos", length: 1 }, + { key: "cosh", length: 1 }, + { key: "exp", length: 1 }, + { key: "floor", length: 1 }, + { key: "fround", length: 1 }, + { key: "hypot", length: 2 }, + { key: "imul", length: 2 }, + { key: "log", length: 1 }, + { key: "log1p", length: 1 }, + { key: "log2", length: 1 }, + { key: "log10", length: 1 }, + { key: "max", length: 2 }, + { key: "min", length: 2 }, + { key: "pow", length: 2 }, + { key: "random", length: 0 }, + { key: "round", length: 1 }, + { key: "sign", length: 1 }, + { key: "sin", length: 1 }, + { key: "sinh", length: 1 }, + { key: "sqrt", length: 1 }, + { key: "tan", length: 1 }, + { key: "tanh", length: 1 }, + { key: "trunc", length: 1 }, + { key: "E", length: -1 }, + { key: "LN10", length: -1 }, + { key: "LN2", length: -1 }, + { key: "LOG10E", length: -1 }, + { key: "LOG2E", length: -1 }, + { key: "PI", length: -1 }, + { key: "SQRT1_2", length: -1 }, + { key: "SQRT2", length: -1 }, + { key: "f16round", length: 1 }, + ]; + case "JSON": + return [ + { key: "parse", length: 2 }, + { key: "stringify", length: 3 }, + { key: "rawJSON", length: 1 }, + { key: "isRawJSON", length: 1 }, + ]; + case "Reflect": + return [ + { key: "defineProperty", length: 3 }, + { key: "deleteProperty", length: 2 }, + { key: "apply", length: 3 }, + { key: "construct", length: 2 }, + { key: "get", length: 2 }, + { key: "getOwnPropertyDescriptor", length: 2 }, + { key: "getPrototypeOf", length: 1 }, + { key: "has", length: 2 }, + { key: "isExtensible", length: 1 }, + { key: "ownKeys", length: 1 }, + { key: "preventExtensions", length: 1 }, + { key: "set", length: 3 }, + { key: "setPrototypeOf", length: 2 }, + ]; + default: + return null; + } +} + +/** Property attribute bits for dyn.namespaceDefine (the members are never + * enumerable). */ +const WRITABLE = 1; +const CONFIGURABLE = 4; + +/** The namespace object the stdlib global `canonical` reads as in + * JavaScript, or null when it is not a namespace. */ +export function builtinNamespaceValue( + lowerer: Lowerer, + canonical: string, + loc: SrcLoc, +): IrExpr | null { + const members = namespaceMembers(canonical); + if (members === null) return null; + const name = `%builtin.namespace.${canonical}`; + if (!lowerer.liftedFns.some((fn) => fn.name === name)) + defineNamespaceBuilder(lowerer, canonical, members, name, helperLoc(loc)); + lowerer.noteEdge(name); + return { kind: "call", callee: name, args: [], type: DYN, loc }; +} + +/** The lifted function that builds the namespace object once and answers + * the same object afterwards. */ +function defineNamespaceBuilder( + lowerer: Lowerer, + canonical: string, + members: readonly NamespaceMember[], + name: string, + loc: SrcLoc, +): void { + const storage = `%g.${name}`; + const ready = `${storage}%ready`; + lowerer.globalsList.push( + { id: storage, name: `${canonical} namespace`, type: DYN, mutable: true }, + { id: ready, name: "%ready", type: BOOL, mutable: true }, + ); + const object = varRef("namespace.0", DYN, loc); + const body: IrStmt[] = [ + { + kind: "if", + cond: varRef(ready, BOOL, loc), + then: [{ kind: "return", value: varRef(storage, DYN, loc), loc }], + else_: null, + loc, + }, + { + kind: "varDecl", + localId: "namespace.0", + init: { + kind: "libCall", + fn: "dyn.namespaceNew", + args: [ + { kind: "strLit", value: canonical, type: STRING, loc }, + { + kind: "dynFrom", + value: { + kind: "libCall", + fn: "sym.wellKnown", + args: [{ kind: "strLit", value: "toStringTag", type: STRING, loc }], + type: SYMBOL_T, + loc, + }, + type: DYN, + loc, + }, + ], + type: DYN, + loc, + }, + loc, + }, + ]; + for (const { key, length } of members) { + const value = + length < 0 + ? constantValue(lowerer, canonical, key, loc) + : functionValue(lowerer, canonical, key, loc); + const attributes = length < 0 ? 0 : WRITABLE | CONFIGURABLE; + body.push({ + kind: "exprStmt", + expr: { + kind: "libCall", + fn: "dyn.namespaceDefine", + args: [ + object, + { kind: "strLit", value: key, type: STRING, loc }, + value, + { kind: "numLit", value: attributes, type: F64, loc }, + { kind: "numLit", value: length, type: F64, loc }, + ], + type: VOID, + loc, + }, + loc, + }); + } + body.push( + { kind: "assign", localId: storage, value: object, loc }, + { + kind: "assign", + localId: ready, + value: { kind: "boolLit", value: true, type: BOOL, loc }, + loc, + }, + { kind: "return", value: varRef(storage, DYN, loc), loc }, + ); + lowerer.liftedFns.push({ + name, + params: [], + locals: [{ id: "namespace.0", name: "namespace", type: DYN, mutable: false }], + returnType: DYN, + body, + loc, + }); +} + +/** A Math constant, boxed. */ +function constantValue(lowerer: Lowerer, canonical: string, key: string, loc: SrcLoc): IrExpr { + const value = canonical === "Math" ? mathMemberValue(lowerer, key, loc) : null; + if (value === null) + throw new InternalCompilerError( + `builtin namespace '${canonical}.${key}' has no constant value`, + ); + return { kind: "dynFrom", value, type: DYN, loc }; +} + +/** A function member: its function value under its own name, or a function + * that throws the named fence when called. */ +function functionValue(lowerer: Lowerer, canonical: string, key: string, loc: SrcLoc): IrExpr { + const value = + canonical === "Math" + ? mathMemberValue(lowerer, key, loc) + : canonical === "JSON" + ? jsonMemberValue(lowerer, key, loc) + : null; + if (value !== null) + return value.type.kind === "dyn" + ? value + : { kind: "dynFrom", value, fnName: key, type: DYN, loc }; + return fencedMember(lowerer, `${canonical}.${key}`, key, loc); +} + +/** One function per member without a function value: calling it throws the + * SC1090 fence, while `typeof`, identity and the property's presence stay + * as in Node. */ +function fencedMember(lowerer: Lowerer, display: string, key: string, loc: SrcLoc): IrExpr { + const name = `%builtin.fence.${display}`; + if (!lowerer.liftedFns.some((fn) => fn.name === name)) { + const diag = unsupportedDiag( + "SC1090", + loc, + `'${display}' as a function value (call it directly)`, + ); + lowerer.runtimeFences.push(diag); + lowerer.liftedFns.push({ + name, + params: [], + locals: [], + returnType: DYN, + body: [ + { kind: "runtimeFence", code: diag.code, message: `${diag.message} [${diag.code}]`, loc }, + ], + loc, + }); + } + return { + kind: "dynFrom", + value: { kind: "closure", fnName: name, captures: [], type: funcOf([], DYN), loc }, + fnName: key, + type: DYN, + loc, + }; +} diff --git a/packages/compiler/src/frontend/lowering/builtins/json.ts b/packages/compiler/src/frontend/lowering/builtins/json.ts index 64f829865..c1cdac334 100644 --- a/packages/compiler/src/frontend/lowering/builtins/json.ts +++ b/packages/compiler/src/frontend/lowering/builtins/json.ts @@ -606,8 +606,15 @@ export function lowerJsonProperty( ): IrExpr | null { const member = lowerer.stdlibGlobalMember(expr, "JSON"); if (member === null) return null; + const value = jsonMemberValue(lowerer, member, locOf(expr)); + if (value !== null) return value; + lowerer.unsupported("SC1090", expr, `JSON methods as values (call '${member}' directly)`); +} + +/** The function value of the JSON member `member` (stringify and parse), + * or null for members without one. */ +export function jsonMemberValue(lowerer: Lowerer, member: string, loc: SrcLoc): IrExpr | null { if (member === "stringify") { - const loc = locOf(expr); const name = "%builtin.JSON.stringify"; if (!lowerer.builtinCallableValueFns.has(name)) { lowerer.builtinCallableValueFns.set(name, name); @@ -654,7 +661,6 @@ export function lowerJsonProperty( if (member === "parse") { // JSON.parse as a value: ToString of the text, then the reviver form // (a reviver that is not a function is ignored, as in Node). - const loc = locOf(expr); const name = "%builtin.JSON.parse"; if (!lowerer.builtinCallableValueFns.has(name)) { lowerer.builtinCallableValueFns.set(name, name); @@ -703,5 +709,5 @@ export function lowerJsonProperty( loc, }; } - lowerer.unsupported("SC1090", expr, `JSON methods as values (call '${member}' directly)`); + return null; } diff --git a/packages/compiler/src/frontend/lowering/expressions/object-literals.ts b/packages/compiler/src/frontend/lowering/expressions/object-literals.ts index 4cc0bee1a..1d6c887c1 100644 --- a/packages/compiler/src/frontend/lowering/expressions/object-literals.ts +++ b/packages/compiler/src/frontend/lowering/expressions/object-literals.ts @@ -38,6 +38,7 @@ import { planUnionRetag } from "../union-retag.js"; import { jsHoldsDynObject, runtimeOptionalStorageOperand } from "../lower-exprs.js"; import { builtinGlobalValue } from "./property-access.js"; import { holdsEvolvingArray } from "../lower-stmts.js"; +import { builtinNamespaceValue } from "../builtin-namespaces.js"; /** `{ a: 1, b: "x" }` → recordLit. The record type comes from the * contextual type when tsc has one (annotated declarations, arguments, @@ -3262,7 +3263,11 @@ function shorthandBuiltinValue( const symbol = lowerer.checker.getShorthandAssignmentValueSymbol(prop); if (!symbol || !lowerer.isStdlibSymbol(symbol)) return null; const js = isJsSourceFile(ts.getSourceFileOfNode(prop)); - return builtinGlobalValue(ts.symbolName(symbol), locOf(prop.name), js); + const name = ts.symbolName(symbol); + return ( + (js ? builtinNamespaceValue(lowerer, name, locOf(prop.name)) : null) ?? + builtinGlobalValue(name, locOf(prop.name), js) + ); } export function lowerShorthandValue( diff --git a/packages/compiler/src/frontend/lowering/expressions/property-access.ts b/packages/compiler/src/frontend/lowering/expressions/property-access.ts index 7b12297a8..5ec81f5ca 100644 --- a/packages/compiler/src/frontend/lowering/expressions/property-access.ts +++ b/packages/compiler/src/frontend/lowering/expressions/property-access.ts @@ -1,5 +1,6 @@ /* Property reads (`a.b`): lowerExprInner's property-access branch, intrinsic and union properties, field reads and targets, and match-group reads. */ import { keyedHelperName } from "../stable-names.js"; +import { builtinNamespaceValue } from "../builtin-namespaces.js"; import { staticallySelected } from "../static-typeof.js"; import * as ts from "../../ts7/adapter.js"; import { lowerHistogramProperty } from "../builtins/performance.js"; @@ -1105,11 +1106,18 @@ export function lowerPropertyAccessExpr( ) ) { const fnName = jsFuncNameOf(expr.expression); + // A builtin function value whose length is not its adapter's + // parameter count (`Math.max.length` is 2). + const fnLength = + probed.kind === "closure" + ? lowerer.builtinCallableValueLengths.get(probed.fnName) + : undefined; const boxed: IrExpr = { kind: "dynFrom", value: probed, type: DYN, ...(fnName !== null ? { fnName } : {}), + ...(fnLength !== undefined ? { fnLength } : {}), loc, }; const key: IrExpr = { @@ -4218,6 +4226,10 @@ export function builtinGlobalValueAt( loc: SrcLoc, js: boolean, ): IrExpr | null { + // A namespace object models its own properties, so member reads and + // reflection read it like any object. + const namespace = js ? builtinNamespaceValue(lowerer, canonical, loc) : null; + if (namespace !== null) return namespace; if (readsBuiltinGlobalMembers(expr)) return null; const value = builtinGlobalValue(canonical, loc, js); if (value === null) return null; diff --git a/packages/compiler/src/frontend/lowering/lower-stdlib.ts b/packages/compiler/src/frontend/lowering/lower-stdlib.ts index e671a0a08..097ccadbe 100644 --- a/packages/compiler/src/frontend/lowering/lower-stdlib.ts +++ b/packages/compiler/src/frontend/lowering/lower-stdlib.ts @@ -2553,35 +2553,8 @@ export function lowerMathProperty( const member = lowerer.stdlibGlobalMember(expr, "Math"); if (member === null) return null; const loc = locOf(expr); - const staticValue = own(STATIC_MATH_PROPS, member); - if (staticValue !== undefined) { - return { kind: "numLit", value: staticValue, type: F64, loc }; - } - const native = own(STATIC_MATH_FNS, member); - if (native && (member === "min" || member === "max" || member === "hypot")) - return lowerer.lowerNativeCallableValue( - { - fn: member === "min" ? "math.minArr" : member === "max" ? "math.maxArr" : "math.hypotArr", - params: [arrayOf(F64)], - result: F64, - valueParams: [{ mode: "rest", type: F64 }], - }, - `Math.${member}`, - loc, - ); - if (native && member !== "min" && member !== "max" && member !== "hypot") { - const params = Array.from({ length: native.arity }, () => F64); - return lowerer.lowerNativeCallableValue( - { - fn: native.fn, - params, - result: F64, - valueParams: params.map((type) => ({ mode: "required", type })), - }, - `Math.${member}`, - loc, - ); - } + const value = mathMemberValue(lowerer, member, loc); + if (value !== null) return value; const propType = own(STDLIB_SURFACE.math.props, member); if (propType !== undefined) { lowerer.refuseUnsupportedApi(`'Math.${member}'`, expr); @@ -2595,6 +2568,40 @@ export function lowerMathProperty( return null; // declared-but-untabled members fall through generically } +/** The value of the Math member `member`: a constant, or the interned + * native function value of a Math function. Null for other members. */ +export function mathMemberValue(lowerer: Lowerer, member: string, loc: SrcLoc): IrExpr | null { + const staticValue = own(STATIC_MATH_PROPS, member); + if (staticValue !== undefined) { + return { kind: "numLit", value: staticValue, type: F64, loc }; + } + const native = own(STATIC_MATH_FNS, member); + if (!native) return null; + if (member === "min" || member === "max" || member === "hypot") + return lowerer.lowerNativeCallableValue( + { + fn: member === "min" ? "math.minArr" : member === "max" ? "math.maxArr" : "math.hypotArr", + params: [arrayOf(F64)], + result: F64, + valueParams: [{ mode: "rest", type: F64 }], + valueLength: 2, + }, + `Math.${member}`, + loc, + ); + const params = Array.from({ length: native.arity }, () => F64); + return lowerer.lowerNativeCallableValue( + { + fn: native.fn, + params, + result: F64, + valueParams: params.map((type) => ({ mode: "required", type })), + }, + `Math.${member}`, + loc, + ); +} + export function npmPackageOf(lowerer: Lowerer, type: ts.Type): string | null { const pkg = lowerer.npmPackageOfSymbol(type.getAliasSymbol() ?? type.getSymbol()); if (pkg) return pkg; diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index 66ecea602..b83333397 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -26,6 +26,7 @@ import { InternalCompilerError } from "../../errors.js"; * explicit resource management, and blocked-binding poisoning. */ import * as ts from "../ts7/adapter.js"; import { lowerOptionalIndex } from "./undefined-index.js"; +import { builtinNamespaceValue } from "./builtin-namespaces.js"; import { processDataMemberValue, programReadsExitCode } from "./builtins/process.js"; import { requireInitFlagStmt } from "./require-initialization.js"; import { isJsonRequireDecl } from "./json-require.js"; @@ -4248,7 +4249,8 @@ function stdlibGlobalTokenDestructure( value = canonical === "crypto" ? { kind: "libCall", fn: "webcrypto.object", args: [], type: DYN, loc: locOf(el) } - : builtinGlobalValue(canonical, locOf(el), true); + : (builtinNamespaceValue(lowerer, canonical, locOf(el)) ?? + builtinGlobalValue(canonical, locOf(el), true)); } else if (globalName === "console" && !CONSOLE_CALL_MEMBERS.has(propName)) { token = `[builtin console.${propName}]`; } else if (TOKEN_OPAQUE_GLOBALS.has(globalName)) { diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 3c74cfbad..6c95f00a9 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -2969,6 +2969,9 @@ export class Lowerer { readonly builtinCallableValueFns = new Map(); /** Each builtin function-value adapter's Node name, for boxed values. */ readonly builtinCallableValueNames = new Map(); + /** Builtin function values whose `length` differs from their adapter's + * parameter count (BuiltinModuleFn.valueLength), by adapter name. */ + readonly builtinCallableValueLengths = new Map(); /** Optional-chain lowering state. While a chain body lowers, the guarded * receiver NODE reads as a chainRecv (typed by the narrowed arm) instead * of re-lowering, its checker type reads non-nullish (typeOf), and the @@ -9719,6 +9722,8 @@ export class Lowerer { // name Node's function carries (`[Function: randomUUID]`). const builtinName = expr.kind === "closure" ? this.builtinCallableValueNames.get(expr.fnName) : undefined; + const builtinLength = + expr.kind === "closure" ? this.builtinCallableValueLengths.get(expr.fnName) : undefined; return { kind: "dynFrom", value: expr, @@ -9726,6 +9731,7 @@ export class Lowerer { loc: expr.loc, ...(liveRef ? { liveRef: true as const } : {}), ...(builtinName !== undefined ? { fnName: builtinName } : {}), + ...(builtinLength !== undefined ? { fnLength: builtinLength } : {}), }; } return expr; @@ -13901,6 +13907,8 @@ export class Lowerer { fnName = keyedHelperName(this, `%builtin.value.${fn.valueFn ?? fn.fn}`, key); this.builtinCallableValueFns.set(key, fnName); this.builtinCallableValueNames.set(fnName, display.slice(display.lastIndexOf(".") + 1)); + if (fn.valueLength !== undefined) + this.builtinCallableValueLengths.set(fnName, fn.valueLength); const params = funcType.params.map((type, index) => ({ localId: `arg.${index}`, name: `arg${index}`, diff --git a/packages/compiler/src/frontend/lowering/surfaces.ts b/packages/compiler/src/frontend/lowering/surfaces.ts index 44564f2f1..a77ad2990 100644 --- a/packages/compiler/src/frontend/lowering/surfaces.ts +++ b/packages/compiler/src/frontend/lowering/surfaces.ts @@ -805,6 +805,9 @@ export interface BuiltinModuleFn { * direct-call row's `fn` (a direct call picks an arity-specific entry * point; the value accepts every arity through one). */ valueFn?: IrLibFn; + /** The function value's `length` when it is not the count of its + * required value parameters (`Math.max`'s 2 over its rest pack). */ + valueLength?: number; } export type BuiltinValueParam = diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 1be0f95cd..cd5b4eb20 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -289,6 +289,8 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ * timer APIs (it pulls in the event loop). The name is a compiler-chosen * literal. */ "dyn.builtinFunction": { argTypes: [STRING], result: DYN }, + "dyn.namespaceNew": { argTypes: [STRING, DYN], result: DYN }, + "dyn.namespaceDefine": { argTypes: [DYN, STRING, DYN, F64, F64], result: VOID }, "date.nativeNew": { argTypes: [DYN], result: DYN }, /** `new Date(year, monthIndex, ...)` in JavaScript: the argument array's * first seven values pass through ToNumber in order (later ones are diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index 878088d65..ec95926ac 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -3325,7 +3325,17 @@ export type IrExpr = * from a union) whose Web API contract exposes the reference again, such * as stream chunks and abort reasons; ordinary JSON-shaped values retain * the documented deep-copy boundary. */ - | { kind: "dynFrom"; value: IrExpr; fnName?: string; liveRef?: true; type: IrType; loc: SrcLoc } + | { + kind: "dynFrom"; + value: IrExpr; + fnName?: string; + /** A boxed function's `length` when it differs from its parameter + * count (builtin function values). */ + fnLength?: number; + liveRef?: true; + type: IrType; + loc: SrcLoc; + } /** CALLING a dyn value — `fn(a, b)` where fn is checked-dynamic (an * implicit-any JS binding, a dyn record member, a dynKeyGet result). * Arguments are ALREADY dyn-typed (typed values box through dynFrom at diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 4ad3dcc5c..1495d2e2b 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -309,6 +309,8 @@ const DYN_INVOKE_LIB_FNS: ReadonlySet = new Set([ "dyn.definePrototypeProps", "dyn.functionApply", "dyn.globalConstructor", + "dyn.namespaceDefine", + "dyn.namespaceNew", "dyn.objCreateWithProperties", "dyn.objectTag", "stream.dynNative", diff --git a/packages/compiler/test/namespace-member-fences.test.ts b/packages/compiler/test/namespace-member-fences.test.ts new file mode 100644 index 000000000..c040f35c7 --- /dev/null +++ b/packages/compiler/test/namespace-member-fences.test.ts @@ -0,0 +1,67 @@ +import { spawnSync } from "node:child_process"; +import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile } from "../src/index.js"; + +const sanitize = process.env["SCRIPTC_SAN"] === "1"; + +// Static member calls (`Math.abs(x)`) do not read the namespace objects, so +// a change to a function member's value fences (SC1090) instead of leaving +// those calls with the original. New properties and attribute-only changes +// behave as in Node (corpus 7188). +test("replacing or deleting a namespace member fences", async () => { + const dir = mkdtempSync(join(tmpdir(), "scriptc-namespace-fences-")); + try { + const entry = join(dir, "main.js"); + writeFileSync( + entry, + ` +const m = /** @type {any} */ (Math); +const j = /** @type {any} */ (JSON); +function attempt(label, run) { + try { console.log(label, run()); } catch (error) { console.log(label, error.code); } +} +attempt("alias", () => { m.abs = () => 0; return "replaced"; }); +attempt("direct", () => { Math.max = () => 0; return "replaced"; }); +attempt("define", () => Object.defineProperty(m, "min", { value: () => 0 }) === m); +attempt("same", () => Object.defineProperty(m, "min", { value: Math.min, enumerable: true }) === m); +attempt("reflect", () => Reflect.set(j, "parse", () => 0)); +attempt("assign", () => Object.assign(m, { floor: 1 }) === m); +attempt("delete", () => delete m.ceil); +attempt("added", () => { m.extra = 5; return m.extra; }); +console.log(Math.abs(-1), Math.max(1, 2), Math.min(1, 2), JSON.parse("[3]")[0], Math.floor(1.5), Math.ceil(1.5)); +console.log(Object.keys(Math).join(",")); +`, + ); + const result = await compile(entry, { + backend: "llvm", + sanitize, + outDir: dir, + outPath: join(dir, "program"), + }); + expect(result.ok, JSON.stringify(result.diagnostics)).toBe(true); + if (!result.ok) return; + const child = spawnSync(result.binaryPath, [], { encoding: "utf8" }); + expect(child.stderr).toBe(""); + expect(child.status).toBe(0); + expect(child.stdout).toBe( + [ + "alias SC1090", + "direct SC1090", + "define SC1090", + "same true", + "reflect SC1090", + "assign SC1090", + "delete SC1090", + "added 5", + "1 2 1 3 1 2", + "min,extra", + "", + ].join("\n"), + ); + } finally { + rmSync(dir, { recursive: true, force: true }); + } +}); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7186-namespace-object-values.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7186-namespace-object-values.js.json new file mode 100644 index 000000000..a130b4af6 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7186-namespace-object-values.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7186-namespace-object-values.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7187-namespace-object-reflection.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7187-namespace-object-reflection.js.json new file mode 100644 index 000000000..b2d9bc751 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7187-namespace-object-reflection.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7187-namespace-object-reflection.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7188-namespace-object-extensions.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7188-namespace-object-extensions.js.json new file mode 100644 index 000000000..96cbad8c2 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7188-namespace-object-extensions.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7188-namespace-object-extensions.js" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index 669f4aedb..a9f4dc2c6 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -319,6 +319,9 @@ typedef struct { * must not inspect the value: an earlier cycle member may already be freed. * Ordinary mutations need not maintain this collector-only decision. */ bool value_traced : 1; + /* A namespace object's function member (scr_dyn_namespace_define), which + * static member calls bypass: a change to its value fences instead. */ + bool fenced : 1; /* Ordinary object insertion sets all three attributes true. */ bool writable; bool enumerable; @@ -870,6 +873,19 @@ ScrDyn *scr_dyn_error_constructor(const char *name); /* A builtin global function (setTimeout, setImmediate, process.nextTick, ...) * as an interned dynamic function value: +1. */ ScrDyn *scr_dyn_builtin_function(const ScrStr *name); +/* A standard namespace object (Math, JSON, Reflect read as a JavaScript + * value): an ordinary object whose Symbol.toStringTag is `tag` (+1). + * `tag_key` is the Symbol.toStringTag key (borrowed), which the compiler + * passes so this unit needs no symbol entry points. */ +ScrDyn *scr_dyn_namespace_new(const ScrStr *tag, ScrDyn *tag_key); +/* Defines the own data property `key` of a namespace object. `attributes` + * has bits 1 writable, 2 enumerable, 4 configurable; a function value + * takes `length` as its length when it is not negative. */ +void scr_dyn_namespace_define(ScrDyn *object, const ScrStr *key, ScrDyn *value, double attributes, + double length); +/* Marks the own property `key` of `object` as a fenced namespace member + * (ScrDynEntry.fenced). */ +void scr_dyn_fence_member(ScrDyn *object, const ScrStr *key); /* A constant-key read of an Object.prototype member name: takes the * ordinary read's +1 result and answers the inherited member in place of * an undefined one (scr_dyn_invoke.c). */ @@ -905,6 +921,9 @@ ScrDyn *scr_dyn_iterator_result_get(const ScrDyn *result, const char *key, size_ void scr_dyn_install_iterator_symbol(ScrDyn *key); void scr_dyn_install_has_instance_symbol(ScrDyn *key); void scr_dyn_install_async_iterator_symbol(ScrDyn *key); +/* Registered by the symbol unit when Symbol.toStringTag is created; the + * core's Object.prototype.toString reads it. */ +void scr_dyn_install_to_string_tag_symbol(ScrDyn *key); void scr_dyn_install_async_dispose_symbol(ScrDyn *key); /* True when key is Symbol.asyncDispose (registered by the symbol unit when * the program names it); handle symbol_get ops outside that unit use it. */ @@ -1380,6 +1399,9 @@ ScrDyn *scr_dyn_new_func(ScrClosure *clo, ScrDynThunk thunk, uint32_t arity, con /* Gives a function box made with thunk its typed message entry (an * EventEmitter listener registered from it keeps the entry). */ void scr_dyn_func_set_message(ScrDyn *fn, ScrDynThunk thunk, ScrDynMessageListener listener); +/* Sets a freshly boxed function's `length` (a builtin function value whose + * length is not its adapter's parameter count). */ +void scr_dyn_function_set_length(ScrDyn *fn, uint32_t length); ScrDyn *scr_dyn_new_class(ScrClassObj *cls, const char *type_key); /* EventEmitter and the stream constructors as untyped constructor values, * and instanceof over untyped constructor functions diff --git a/packages/runtime/src/scr_dyn_invoke.c b/packages/runtime/src/scr_dyn_invoke.c index 364017e05..a55f748e5 100644 --- a/packages/runtime/src/scr_dyn_invoke.c +++ b/packages/runtime/src/scr_dyn_invoke.c @@ -2236,6 +2236,35 @@ ScrDyn *scr_dyn_builtin_function(const ScrStr *name) { return scr_dyn_retain(value); } +/* An own data property of a namespace object. Attribute bits: 1 writable, + * 2 enumerable, 4 configurable. */ +static void dyn_namespace_put(ScrDyn *object, ScrDyn *key, ScrDyn *value, unsigned attributes) { + ScrDyn *descriptor = scr_dyn_new_obj(); + scr_dyn_obj_set(descriptor, "value", 5, scr_dyn_retain(value)); + scr_dyn_obj_set(descriptor, "writable", 8, scr_dyn_new_bool((attributes & 1) != 0)); + scr_dyn_obj_set(descriptor, "enumerable", 10, scr_dyn_new_bool((attributes & 2) != 0)); + scr_dyn_obj_set(descriptor, "configurable", 12, scr_dyn_new_bool((attributes & 4) != 0)); + scr_dyn_release(scr_dyn_define_property(object, key, descriptor)); + scr_dyn_release(descriptor); +} + +ScrDyn *scr_dyn_namespace_new(const ScrStr *tag, ScrDyn *tag_key) { + ScrDyn *object = scr_dyn_new_obj(); + ScrDyn *value = scr_dyn_new_str((ScrStr *)tag); + dyn_namespace_put(object, tag_key, value, 4); + scr_dyn_release(value); + return object; +} + +void scr_dyn_namespace_define(ScrDyn *object, const ScrStr *key, ScrDyn *value, double attributes, + double length) { + if (length >= 0 && value->kind == SCR_DYN_FUNC) value->v.fn.arity = (uint32_t)length; + ScrDyn *name = scr_dyn_new_str((ScrStr *)key); + dyn_namespace_put(object, name, value, (unsigned)attributes); + scr_dyn_release(name); + if (length >= 0) scr_dyn_fence_member(object, key); +} + ScrDyn *scr_dyn_array_prototype(void) { static SCR_TL bool initialized; ScrDyn *prototype = scr_dyn_array_prototype_base(); diff --git a/packages/runtime/src/scr_js_object.c b/packages/runtime/src/scr_js_object.c index 63929ab57..29849fea1 100644 --- a/packages/runtime/src/scr_js_object.c +++ b/packages/runtime/src/scr_js_object.c @@ -268,7 +268,7 @@ static bool scr_js_error_synced_key(const ScrStr *key) { static bool scr_js_replace(ScrDyn *receiver, size_t slot, ScrDyn *value) { ScrDynEntry *found = &receiver->v.obj.entries[slot]; - if (found->accessor || !found->writable) return false; + if (found->accessor || !found->writable || found->fenced) return false; scr_dyn_region_store(receiver, value); ScrDyn *old = found->value; found->value = scr_dyn_retain(value); @@ -313,7 +313,7 @@ bool scr_js_store_probe(ScrDyn *receiver, const ScrStr *key, ScrDyn *value, ScrJ size_t slot = scr_js_shape_find(shape, key->data, key->len); if (slot != SIZE_MAX) { const ScrDynEntry *found = &receiver->v.obj.entries[slot]; - if (found->accessor || !found->writable) return false; + if (found->accessor || !found->writable || found->fenced) return false; scr_js_ic_add(ic, stale, (ScrJsIcEntry){shape, shape, NULL, NULL, slot}); return scr_js_replace(receiver, slot, value); } diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index da18a1c0b..a67740f40 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -52,6 +52,14 @@ static bool scr_dyn_error_prototype_fence(const ScrDyn *value) { SCR_TL const ScrHandleStreamHooks *scr_handle_stream_hooks = NULL; +/* Static member calls (`Math.abs(x)`) do not read the namespace objects, + * so replacing or deleting one of their function members would not reach + * those calls: the change throws instead. */ +static void scr_dyn_namespace_member_fence(void) { + static const char message[] = "Replacing or deleting a Math, JSON or Reflect member is not supported"; + scr_throw_error_msg_code(SCR_ERR_ERROR, message, sizeof message - 1, "SC1090"); +} + /* Constructor capsules expose identity and name/length, but do not model * per-class static property tables yet. Never report a fabricated empty view. */ static bool scr_dyn_class_reflection_fence(const ScrDyn *value) { @@ -87,6 +95,7 @@ static void scr_json_oom(void) { static SCR_TL ScrDyn *scr_iterator_symbol; static SCR_TL ScrDyn *scr_async_iterator_symbol; static SCR_TL ScrDyn *scr_to_primitive_symbol; +static SCR_TL ScrDyn *scr_to_string_tag_symbol; static bool scr_dyn_generator(const ScrDyn *value) { return value && value->kind == SCR_DYN_TYPED_REF && (value->v.typed_ref.type_key[0] == 'g' || value->v.typed_ref.type_key[0] == 'a') && @@ -183,6 +192,17 @@ void scr_dyn_install_to_primitive_symbol(ScrDyn *key) { scr_atexit(scr_to_primitive_symbol_cleanup); } +static void scr_to_string_tag_symbol_cleanup(void) { + scr_dyn_release(scr_to_string_tag_symbol); + scr_to_string_tag_symbol = NULL; +} + +void scr_dyn_install_to_string_tag_symbol(ScrDyn *key) { + if (scr_to_string_tag_symbol) return; + scr_to_string_tag_symbol = scr_dyn_retain(key); + scr_atexit(scr_to_string_tag_symbol_cleanup); +} + void scr_dyn_install_async_iterator_symbol(ScrDyn *key) { if (scr_async_iterator_symbol) return; scr_async_iterator_symbol = scr_dyn_retain(key); @@ -1728,6 +1748,11 @@ static void scr_dyn_obj_put(ScrDyn *obj, const char *key, size_t key_len, ScrDyn ScrDynEntry *existing = obj->v.obj.index ? scr_dyn_find_entry(obj, key, key_len) : scr_dyn_find_linear_entry(obj, key, key_len); if (existing) { + if (existing->fenced) { + scr_dyn_release(value); + scr_dyn_namespace_member_fence(); + return; + } if (existing->accessor || !existing->writable) { scr_dyn_release(value); static const char message[] = "Cannot assign to read only property"; @@ -1769,6 +1794,7 @@ static void scr_dyn_obj_put(ScrDyn *obj, const char *key, size_t key_len, ScrDyn e->getter = NULL; e->setter = NULL; e->accessor = false; + e->fenced = false; e->writable = true; e->enumerable = true; e->configurable = true; @@ -4426,6 +4452,15 @@ ScrDyn *scr_dyn_new_chunk(const ScrBytes *b) { /* A boxed static function value (the compiler's static→dyn converters). * Ownership of the closure MOVES in; sig/name are static literals. */ +void scr_dyn_function_set_length(ScrDyn *fn, uint32_t length) { + if (fn->kind == SCR_DYN_FUNC) fn->v.fn.arity = length; +} + +void scr_dyn_fence_member(ScrDyn *object, const ScrStr *key) { + ScrDynEntry *entry = scr_dyn_entry(object, key); + if (entry) entry->fenced = true; +} + ScrDyn *scr_dyn_new_func(ScrClosure *clo, ScrDynThunk thunk, uint32_t arity, const char *sig, const char *name) { if (clo->function_kind & 8) { ScrDyn *original = scr_box_get_ref(clo->caps[0]); @@ -5296,6 +5331,11 @@ void scr_dyn_obj_set_accessor(ScrDyn *obj, const char *key, size_t key_len, ScrD void scr_dyn_obj_set_field(ScrDyn *obj, const char *key, size_t key_len, ScrDyn *value) { ScrDynEntry *existing = obj->v.obj.index ? scr_dyn_find_entry(obj, key, key_len) : scr_dyn_find_linear_entry(obj, key, key_len); + if (existing && existing->fenced) { + scr_dyn_release(value); + scr_dyn_namespace_member_fence(); + return; + } if (existing && !existing->accessor) { scr_dyn_region_store(obj, value); ScrDyn *old = existing->value; @@ -7294,6 +7334,13 @@ ScrDyn *scr_dyn_define_property(ScrDyn *target, ScrDyn *key, ScrDyn *descriptor) scr_throw_error(SCR_ERR_TYPE, scr_jb_finish(&buffer)); return NULL; } + if (prior && prior->fenced && + (accessor || (value && !scr_dyn_property_same_value(prior->value, value)))) { + scr_dyn_descriptor_fields_drop(fields); + scr_str_release(name); + scr_dyn_namespace_member_fence(); + return NULL; + } if (prior) { if (accessor != prior->accessor) { ScrDyn *old_value = prior->value, *old_getter = prior->getter, *old_setter = prior->setter; @@ -7497,7 +7544,37 @@ void scr_dyn_throw(ScrDyn *d) { scr_dyn_trace_v, scr_dyn_is_object(d)); } +/* Object.prototype.toString's tag from a string-valued Symbol.toStringTag + * data property of an object or its prototypes ("[object Math]"), or NULL + * when there is none. */ +static ScrStr *scr_dyn_own_string_tag(const ScrDyn *d) { + /* The symbol unit installs the key when the program creates it; without + * it no object can carry the property. */ + const ScrDyn *key = scr_to_string_tag_symbol; + if (!key) return NULL; + ScrStr *out = NULL; + for (const ScrDyn *p = d; p; p = p->prototype) { + if (!p->symbol_properties) continue; + ScrDynEntry *entry = scr_dyn_own_symbol_entry(p, key); + if (!entry) continue; + if (!entry->accessor && entry->value && entry->value->kind == SCR_DYN_STR) { + ScrJsonBuf b; + scr_jb_init(&b); + scr_jb_puts(&b, "[object "); + scr_jb_write(&b, entry->value->v.str->data, entry->value->v.str->len); + scr_jb_putc(&b, ']'); + out = scr_jb_finish(&b); + } + break; + } + return out; +} + ScrStr *scr_dyn_object_tag(const ScrDyn *d) { + if (d->kind == SCR_DYN_OBJ) { + ScrStr *tag = scr_dyn_own_string_tag(d); + if (tag) return tag; + } if (d->kind == SCR_DYN_PROXY) { scr_dyn_proxy_unsupported("Symbol.toStringTag lookup"); return NULL; @@ -8739,7 +8816,9 @@ ScrStr *scr_dyn_string_coerce_js(const ScrDyn *d) { scr_error_release(error); return text; } - return scr_str_new("[object Object]", 15); + // Object.prototype.toString: "[object Object]", or the object's + // Symbol.toStringTag ("[object Math]"). + return scr_dyn_object_tag(d); } if (!m || m->kind != SCR_DYN_FUNC) { scr_dyn_release(m); continue; } /* OrdinaryToPrimitive performs a method call, not a bare function @@ -10477,6 +10556,7 @@ static void scr_dyn_obj_append_shared(ScrDyn *obj, char *key, size_t key_len, Sc e->getter = NULL; e->setter = NULL; e->accessor = false; + e->fenced = false; e->writable = true; e->enumerable = true; e->configurable = true; @@ -11271,6 +11351,10 @@ static void scr_json_delete_member(ScrDyn *object, const ScrStr *key) { for (size_t i = 0; i < object->v.obj.len; i++) { ScrDynEntry *entry = &object->v.obj.entries[i]; if (entry->key_len != key->len || memcmp(entry->key, key->data, key->len) != 0) continue; + if (entry->fenced) { + scr_dyn_namespace_member_fence(); + return; + } ScrDynEntry removed = *entry; memmove(entry, entry + 1, (object->v.obj.len - i - 1) * sizeof *entry); object->v.obj.len--; @@ -12866,7 +12950,9 @@ bool scr_dyn_reflect_define(ScrDyn *receiver, ScrDyn *raw_key, ScrDyn *value) { ScrDynEntry *entry = key->kind == SCR_DYN_SYMBOL ? (symbols ? scr_dyn_symbol_entry(symbols, key, true) : NULL) : receiver->kind == SCR_DYN_OBJ ? scr_dyn_entry(receiver, key->v.str) : receiver->kind == SCR_DYN_ARR && receiver->v.arr.properties ? scr_dyn_entry(receiver->v.arr.properties, key->v.str) : NULL; - if (!(entry && (entry->accessor || !entry->writable)) && !(receiver->non_extensible && !scr_dyn_has_own_computed(receiver, key))) { + if (entry && entry->fenced) { + scr_dyn_namespace_member_fence(); + } else if (!(entry && (entry->accessor || !entry->writable)) && !(receiver->non_extensible && !scr_dyn_has_own_computed(receiver, key))) { if (entry) { ScrDyn *old = entry->value; entry->value = scr_dyn_retain(value); diff --git a/packages/runtime/src/scr_symbol.c b/packages/runtime/src/scr_symbol.c index 647c31dc3..1f7f867dc 100644 --- a/packages/runtime/src/scr_symbol.c +++ b/packages/runtime/src/scr_symbol.c @@ -105,6 +105,11 @@ ScrSym *scr_sym_well_known(ScrStr *name) { scr_dyn_install_to_primitive_symbol(key); scr_dyn_release(key); } + if (name->len == 11 && !memcmp(name->data, "toStringTag", 11)) { + ScrDyn *key = scr_dyn_new_symbol(symbol); + scr_dyn_install_to_string_tag_symbol(key); + scr_dyn_release(key); + } return symbol; } diff --git a/tests/corpus/7186-namespace-object-values.js b/tests/corpus/7186-namespace-object-values.js new file mode 100644 index 000000000..c61d96e11 --- /dev/null +++ b/tests/corpus/7186-namespace-object-values.js @@ -0,0 +1,22 @@ +// Math, JSON and Reflect read as values are objects with Node's own +// properties: typeof, String, `in`, aliasing and member calls through +// the value behave as in Node, and every spelling is the same object. +function describe(value) { + return [typeof value, String(value), Object.prototype.toString.call(value)].join(" "); +} +console.log(describe(Math), "|", describe(JSON), "|", describe(Reflect)); + +const m = Math; +console.log(m.abs(-2), m.max(1, 5, 3), m.PI.toFixed(5), "trunc" in m, m === Math); +console.log(m === globalThis.Math, JSON === globalThis.JSON); +const { Math: fromGlobal } = globalThis; +console.log(fromGlobal === Math, fromGlobal.sqrt(81)); + +const known = new Set([Math, JSON, Reflect]); +console.log(known.has(Math), known.has(globalThis.JSON), known.size); + +const parse = JSON.parse; +console.log(parse("[1,2]").length, JSON.stringify({ a: [1] })); + +console.log(typeof Math === "object" && typeof Reflect === "object"); +console.log(Math.max.length, Math.min.length, Math.hypot.length, Math.abs.length); diff --git a/tests/corpus/7187-namespace-object-reflection.js b/tests/corpus/7187-namespace-object-reflection.js new file mode 100644 index 000000000..d62699dea --- /dev/null +++ b/tests/corpus/7187-namespace-object-reflection.js @@ -0,0 +1,23 @@ +// Reflection over the namespace objects answers Node's property +// attributes: members are own, non-enumerable properties, the Math +// constants are read-only, and Symbol.toStringTag names the namespace. +function show(object, key) { + const d = Object.getOwnPropertyDescriptor(object, key); + if (d === undefined) return `${String(key)}: none`; + const value = typeof d.value === "function" ? `fn/${d.value.length}/${d.value.name}` : String(d.value); + return `${String(key)}: ${value} ${d.writable} ${d.enumerable} ${d.configurable}`; +} +function inspect(object) { + return [ + Object.hasOwn(object, "parse"), + Object.hasOwn(object, "abs"), + Object.keys(object).length, + Object.getOwnPropertyNames(object).length, + ].join(" "); +} +console.log(show(Math, "abs"), "|", show(Math, "PI"), "|", show(Math, "max")); +console.log(show(Math, Symbol.toStringTag), "|", show(JSON, "stringify"), "|", show(Reflect, "apply")); +console.log(inspect(Math), "|", inspect(JSON), "|", inspect(Reflect)); +console.log(Object.getOwnPropertyNames(JSON).join(",")); +console.log(Object.getOwnPropertyNames(Math).slice(0, 5).join(","), Object.getOwnPropertyNames(Math).at(-1)); +console.log(Object.prototype.hasOwnProperty.call(Math, "random"), Object.keys(Reflect).length); diff --git a/tests/corpus/7188-namespace-object-extensions.js b/tests/corpus/7188-namespace-object-extensions.js new file mode 100644 index 000000000..0a33f7155 --- /dev/null +++ b/tests/corpus/7188-namespace-object-extensions.js @@ -0,0 +1,16 @@ +// Namespace objects take new properties and attribute-only redefinitions +// as in Node, and their members keep the values static calls use. +const m = Math; +m.tau = 2 * Math.PI; +console.log(m.tau.toFixed(4), Math.tau === m.tau, "tau" in Math, Object.keys(Math).join(",")); +Object.defineProperty(Math, "hypot", { enumerable: true }); +Object.defineProperty(Math, "trunc", { value: Math.trunc, writable: false }); +const d = Object.getOwnPropertyDescriptor(Math, "trunc"); +console.log(Object.keys(Math).join(","), d.writable, d.enumerable, d.configurable, Math.trunc(-1.5)); +console.log(Math.hypot(3, 4), m.hypot === Math.hypot, Object.getOwnPropertyDescriptor(m, "hypot").enumerable); +const j = JSON; +j.label = "json"; +console.log(j.label, Object.keys(JSON).join(","), Reflect.ownKeys(j).length); +const r = Reflect; +r.extra = [1, 2]; +console.log(Reflect.extra.length, Object.getOwnPropertyNames(Reflect).at(-1), "extra" in r); diff --git a/tests/harness/corpus-costs/7186-namespace-object-values.js.json b/tests/harness/corpus-costs/7186-namespace-object-values.js.json new file mode 100644 index 000000000..b9c097972 --- /dev/null +++ b/tests/harness/corpus-costs/7186-namespace-object-values.js.json @@ -0,0 +1 @@ +{ "plain": 3233, "san": 3781 } diff --git a/tests/harness/corpus-costs/7187-namespace-object-reflection.js.json b/tests/harness/corpus-costs/7187-namespace-object-reflection.js.json new file mode 100644 index 000000000..82f5d5ebf --- /dev/null +++ b/tests/harness/corpus-costs/7187-namespace-object-reflection.js.json @@ -0,0 +1 @@ +{ "plain": 3183, "san": 3882 } diff --git a/tests/harness/corpus-costs/7188-namespace-object-extensions.js.json b/tests/harness/corpus-costs/7188-namespace-object-extensions.js.json new file mode 100644 index 000000000..8d90b4234 --- /dev/null +++ b/tests/harness/corpus-costs/7188-namespace-object-extensions.js.json @@ -0,0 +1 @@ +{ "plain": 3075, "san": 3749 } From bbaa7d7ba40427eb7462551f0dc065280af1c68e Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 10:28:44 -0500 Subject: [PATCH 019/259] Pass callbacks through bindings in tests of the array-helper and closure paths --- .../test/callback-pending-emission.test.ts | 19 ++++++++++++------- .../test/runtime-optional-precision.test.ts | 4 +++- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/packages/compiler/test/callback-pending-emission.test.ts b/packages/compiler/test/callback-pending-emission.test.ts index 9dcbbf0a1..3b2ed3823 100644 --- a/packages/compiler/test/callback-pending-emission.test.ts +++ b/packages/compiler/test/callback-pending-emission.test.ts @@ -9,7 +9,9 @@ import { emitLlvmModule } from "../src/backend/llvm/emitter.js"; // A specialized array helper calls its known callback directly after // checking the closure's entry. A callback that cannot throw skips the // pending test on that path, and the fallback through the closure's own -// entry keeps it; a callback that can throw keeps it on both paths. +// entry keeps it; a callback that can throw keeps it on both paths. The +// callbacks are passed through bindings: a closure literal at the call +// would run as a loop with its body copied in (array-pipelines.ts). test("known callbacks outside the may-throw set test the pending flag only on the fallback", async () => { const dir = mkdtempSync(join(tmpdir(), "scriptc-callback-pending-")); try { @@ -18,13 +20,16 @@ test("known callbacks outside the may-throw set test the pending flag only on th writeFileSync( entry, `const values = [1, 2, 3, 4]; -console.log(values.every((v) => v > 0)); -console.log(values.map((v) => v * 2).join(",")); +const positive = (v: number): boolean => v > 0; +const double = (v: number): number => v * 2; +const stopAtThree = (v: number): boolean => { + if (v > 2) throw new Error("stop at " + v); + return true; +}; +console.log(values.every(positive)); +console.log(values.map(double).join(",")); try { - console.log(values.every((v) => { - if (v > 2) throw new Error("stop at " + v); - return true; - })); + console.log(values.every(stopAtThree)); } catch (error) { console.log("caught", (error as Error).message); } diff --git a/packages/compiler/test/runtime-optional-precision.test.ts b/packages/compiler/test/runtime-optional-precision.test.ts index 7840b0c62..b47cb828d 100644 --- a/packages/compiler/test/runtime-optional-precision.test.ts +++ b/packages/compiler/test/runtime-optional-precision.test.ts @@ -158,7 +158,9 @@ test("an unchanged captured parameter is borrowed and boxed only where a closure const module = await lower(`${ITEM} function heavier(item: Item, limits: number[]): boolean { if (limits.length === 0) return false; - return limits.some((limit) => weigh(item) > limit); + // A closure value: a closure literal at the call would run as a loop. + const over = (limit: number): boolean => weigh(item) > limit; + return limits.some(over); } function replaced(item: Item, other: Item): number { const read = () => item.weight; From 53115c7e50cc89220cd223daf18638e6f2a4ae21 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 11:15:27 -0500 Subject: [PATCH 020/259] Merge main and fix the Node island report --- .../compiler/src/diagnostics/diagnostic.ts | 15 ++++ .../compiler/src/node-islands/report.test.ts | 78 ++++++++++++++++ packages/compiler/src/node-islands/report.ts | 89 +++++++++++++------ packages/compiler/src/project-config.test.ts | 9 ++ packages/compiler/src/project-config.ts | 4 +- 5 files changed, 167 insertions(+), 28 deletions(-) diff --git a/packages/compiler/src/diagnostics/diagnostic.ts b/packages/compiler/src/diagnostics/diagnostic.ts index bc5cc4918..bb5efba31 100644 --- a/packages/compiler/src/diagnostics/diagnostic.ts +++ b/packages/compiler/src/diagnostics/diagnostic.ts @@ -249,6 +249,21 @@ export function nodeIslandsOffDiag(pkg: string, why: string, loc: SrcLoc): ScrDi }; } +/** SC8002 — a user module is marked to run in a Node island while + * Node islands are off. */ +export function nodeIslandsOffModuleDiag( + file: string, + source: "config" | "cli", + loc: SrcLoc, +): ScrDiagnostic { + return { + code: "SC8002", + message: `user module '${file}' is marked to run in Node (${source === "cli" ? "--node-island" : "scriptc.nodeIslands.modules"}) and Node islands are off`, + loc, + hint: "allow Node islands (--node-islands=auto or explicit), or remove the marking", + }; +} + /** SC8003 — a package marked "native" is outside the native subset. */ export function nativePackageDiag(pkg: string, why: string, loc: SrcLoc): ScrDiagnostic { return { diff --git a/packages/compiler/src/node-islands/report.test.ts b/packages/compiler/src/node-islands/report.test.ts index a11d9fb8b..d4221d31f 100644 --- a/packages/compiler/src/node-islands/report.test.ts +++ b/packages/compiler/src/node-islands/report.test.ts @@ -199,3 +199,81 @@ test("globMatch", () => { expect(globMatch("/a/?.js", "/a/x.js")).toBe(true); expect(globMatch("/a/x.js", "/a/x.js")).toBe(true); }); + +describe("reachability", () => { + const userEdge = (fromFile: string, to: string): PackageEdge => ({ + ...edge(null, to), + fromFile, + loc: { file: fromFile, start: 0, end: 1 }, + }); + const codeFromString = (pkg: string) => + mod(pkg, `${NM}/${pkg}/index.js`, [ + marker(`${NM}/${pkg}/index.js`, "R1.1", "code-from-string"), + ]); + const build = (scan: Omit, options: NodeIslandOptions = {}) => + buildNodeIslandReport({ + entry: "/app/main.ts", + scan: { ...scan, refusals: [] }, + npm: [], + diagnostics: [], + fences: [], + policy: nodeIslandPolicy(emptyProjectConfig(), options), + }); + + test("a marked user module owns the packages only it imports", () => { + const r = build( + { + modules: [ + mod(null, "/app/main.ts"), + mod(null, "/app/plugin.ts"), + mod("x", `${NM}/x/index.js`), + mod("y", `${NM}/y/index.js`), + ], + edges: [userEdge("/app/plugin.ts", "x"), userEdge("/app/plugin.ts", "y"), edge(null, "y")], + }, + { islands: ["/app/plugin.ts"] }, + ); + expect(r.packages.map((p) => [p.package, p.status, p.islands])).toEqual([ + ["x", "inside", ["/app/plugin.ts"]], + ["y", "shared", ["/app/plugin.ts"]], + ]); + }); + + test("an island imported by a native package lists that import site", () => { + const r = build({ + modules: [mod(null, "/app/main.ts"), mod("n", `${NM}/n/index.js`), codeFromString("i")], + edges: [edge(null, "n"), edge("n", "i")], + }); + expect(r.islands.map((i) => [i.package, i.importedFrom.map((l) => l.file)])).toEqual([ + ["i", [`${NM}/n/index.js`]], + ]); + }); + + test("the dependencies of a shared package are shared with the island", () => { + const r = build({ + modules: [ + mod(null, "/app/main.ts"), + codeFromString("a"), + mod("s", `${NM}/s/index.js`), + mod("d", `${NM}/d/index.js`), + ], + edges: [edge(null, "a"), edge(null, "s"), edge("a", "s"), edge("s", "d")], + }); + expect(r.packages.map((p) => [p.package, p.status, p.islands])).toEqual([ + ["d", "shared", ["a"]], + ["s", "shared", ["a"]], + ]); + }); + + test("with islands off, a marked user module is SC8002 and keeps the user JavaScript rules", () => { + const file = "/app/legacy.js"; + const r = build( + { modules: [mod(null, file, [marker(file, "R2.1", "constructor-function")])], edges: [] }, + { mode: "off", islands: [file], strictUserJs: true }, + ); + expect(r.userModules).toEqual([]); + expect(r.violations.map((v) => v.code)).toEqual(["SC8002"]); + expect(r.violations[0]!.message).toContain(`user module '${file}'`); + expect(r.userJs.map((d) => d.code)).toEqual(["SC8101"]); + }); +}); diff --git a/packages/compiler/src/node-islands/report.ts b/packages/compiler/src/node-islands/report.ts index a6898e855..c82d0f664 100644 --- a/packages/compiler/src/node-islands/report.ts +++ b/packages/compiler/src/node-islands/report.ts @@ -14,6 +14,7 @@ import { nativePackageDiag, nodeIslandsOffDiag, + nodeIslandsOffModuleDiag, userJsObjectModelDiag, type ScrDiagnostic, } from "../diagnostics/diagnostic.js"; @@ -67,7 +68,9 @@ interface PackageState { dir: string | null; reasons: NodeIslandReason[]; importers: Set; - nativeSites: SrcLoc[]; + /** Every import site, with its importer ("" native user code, + * "user:" a marked user module, else a package key). */ + sites: { from: string; loc: SrcLoc }[]; island: boolean; decision: IslandDecision; carriedBy: string | null; @@ -88,7 +91,7 @@ export function buildNodeIslandReport(input: NodeIslandReportInput): NodeIslandR dir, reasons: [], importers: new Set(), - nativeSites: [], + sites: [], island: false, decision: "auto", carriedBy: null, @@ -113,16 +116,22 @@ export function buildNodeIslandReport(input: NodeIslandReportInput): NodeIslandR const s = state(m.packageName, m.packageDir); for (const marker of m.markers) addReason(s, classifyMarker(marker)); } - // Import edges. + // Import edges. A marked user module is an island owner of its own + // (unless islands are off, where it is a violation and stays native). + const USER = "user:"; + const userIsland = (file: string): boolean => + policy.mode !== "off" && isMarkedUserModule(policy, file) !== null; + const imports = new Map>(); for (const e of input.scan.edges) { if (e.shim || ignored(e.to)) continue; const s = state(e.to, e.toDir); - if (e.fromDir === null) { - s.importers.add(""); - s.nativeSites.push(e.loc); - } else if (e.fromDir !== s.key) { - s.importers.add(e.fromDir); - } + const from = e.fromDir ?? (userIsland(e.fromFile) ? USER + e.fromFile : ""); + if (from === s.key) continue; + s.importers.add(from); + s.sites.push({ from, loc: e.loc }); + let out = imports.get(from); + if (out === undefined) imports.set(from, (out = new Set())); + out.add(s.key); } // Lowering refusals and fences inside npm modules. const addDiagnostics = (diags: readonly ScrDiagnostic[], source: NodeIslandReasonSource) => { @@ -161,7 +170,7 @@ export function buildNodeIslandReport(input: NodeIslandReportInput): NodeIslandR const forcedNode = policy.forcedNode.get(s.name); const forcedNative = policy.forcedNative.get(s.name); const outside = s.reasons.length > 0; - const loc = s.nativeSites[0] ?? fallbackLoc; + const loc = (s.sites.find((x) => x.from === "") ?? s.sites[0])?.loc ?? fallbackLoc; if (forcedNative !== undefined) { if (outside) { s.violation = true; @@ -197,6 +206,16 @@ export function buildNodeIslandReport(input: NodeIslandReportInput): NodeIslandR s.decision = "auto"; } + // The island that owns an importer: a marked user module, an island + // package, or the island a carried package runs inside; null for native. + const ownerOf = (from: string): string | null => { + if (from.startsWith(USER)) return from; + const importer = states.get(from); + return importer === undefined ? null : importer.island ? importer.key : importer.carriedBy; + }; + const ownerName = (owner: string): string => + owner.startsWith(USER) ? owner.slice(USER.length) : states.get(owner)!.name; + // Closure: packages imported only by islands (or by packages inside // them) run inside the island. for (let changed = true; changed;) { @@ -207,9 +226,7 @@ export function buildNodeIslandReport(input: NodeIslandReportInput): NodeIslandR let carrier: string | null = null; let all = true; for (const from of s.importers) { - const importer = states.get(from); - const owner = - importer === undefined ? null : importer.island ? importer.key : importer.carriedBy; + const owner = ownerOf(from); if (owner === null) { all = false; break; @@ -223,6 +240,31 @@ export function buildNodeIslandReport(input: NodeIslandReportInput): NodeIslandR } } + // Transitive reach: every non-island package an island loads, through + // carried and shared packages alike (an island package is a boundary). + const reach = new Map>(); + const owners = [...imports.keys()].filter( + (k) => k.startsWith(USER) || states.get(k)?.island === true, + ); + for (const owner of owners) { + const name = ownerName(owner); + const queue = [...(imports.get(owner) ?? new Set())]; + const seen = new Set(queue); + while (queue.length > 0) { + const key = queue.pop()!; + if (states.get(key)?.island === true) continue; + let names = reach.get(key); + if (names === undefined) reach.set(key, (names = new Set())); + names.add(name); + for (const next of imports.get(key) ?? new Set()) { + if (!seen.has(next)) { + seen.add(next); + queue.push(next); + } + } + } + } + // Entries. const islands: NodeIslandEntry[] = []; const packages: NativePackage[] = []; @@ -248,7 +290,7 @@ export function buildNodeIslandReport(input: NodeIslandReportInput): NodeIslandR reasons: s.reasons, modules: modules.size, carries, - importedFrom: s.nativeSites, + importedFrom: s.sites.filter((x) => ownerOf(x.from) === null).map((x) => x.loc), evaluation: "eager", }); continue; @@ -257,23 +299,13 @@ export function buildNodeIslandReport(input: NodeIslandReportInput): NodeIslandR // A package that resolves to no installed JavaScript never loads (an // optional dependency that is absent): nothing to compile or island. if (s.dir === null && s.reasons.length === 0) continue; - const reachingIslands: string[] = []; - for (const from of s.importers) { - const importer = states.get(from); - if (importer === undefined) continue; - const owner = importer.island ? importer.key : importer.carriedBy; - if (owner !== null) { - const name = states.get(owner)!.name; - if (!reachingIslands.includes(name)) reachingIslands.push(name); - } - } - reachingIslands.sort(); + const reachingIslands = [...(reach.get(s.key) ?? new Set())].sort(); packages.push({ package: s.name, version, path: s.dir, status: s.carriedBy !== null ? "inside" : reachingIslands.length > 0 ? "shared" : "native", - islands: s.carriedBy !== null ? [states.get(s.carriedBy)!.name] : reachingIslands, + islands: s.carriedBy !== null ? [ownerName(s.carriedBy)] : reachingIslands, }); } islands.sort( @@ -292,10 +324,13 @@ export function buildNodeIslandReport(input: NodeIslandReportInput): NodeIslandR for (const m of input.scan.modules) { if (m.origin !== "user") continue; const marked = isMarkedUserModule(policy, m.file); - if (marked !== null) { + if (marked !== null && policy.mode !== "off") { userModules.push({ file: m.file, source: marked }); continue; } + if (marked !== null) { + violations.push(nodeIslandsOffModuleDiag(m.file, marked, { file: m.file, start: 0, end: 0 })); + } if (!policy.strictUserJs) continue; for (const marker of m.markers) { const code = ruleInfo(marker.rule).userJsCode; diff --git a/packages/compiler/src/project-config.test.ts b/packages/compiler/src/project-config.test.ts index b9750f24e..ce475a4ae 100644 --- a/packages/compiler/src/project-config.test.ts +++ b/packages/compiler/src/project-config.test.ts @@ -124,3 +124,12 @@ test("a non-object packages or nodeIslands value is SC8004", () => { // Other keys of the scriptc object belong to other readers. expect(config({ somethingElse: 1 }).diagnostics).toEqual([]); }); + +test("package setting keys named like Object.prototype members are unknown settings", () => { + const c = config({ packages: { debug: { constructor: "node", toString: "node" } } }); + expect(c.diagnostics.map((d) => [d.code, d.message])).toEqual([ + ["SC8004", "package.json 'scriptc.packages.debug.constructor' is not a known package setting"], + ["SC8004", "package.json 'scriptc.packages.debug.toString' is not a known package setting"], + ]); + expect(c.packages.has("debug")).toBe(false); +}); diff --git a/packages/compiler/src/project-config.ts b/packages/compiler/src/project-config.ts index cc13a868d..bc68e6476 100644 --- a/packages/compiler/src/project-config.ts +++ b/packages/compiler/src/project-config.ts @@ -201,7 +201,9 @@ export function parseProjectConfig(manifest: string, text: string): ProjectConfi } let valid = true; for (const key of Object.keys(value)) { - const allowed = PACKAGE_OBJECT_KEYS[key]; + const allowed = Object.hasOwn(PACKAGE_OBJECT_KEYS, key) + ? PACKAGE_OBJECT_KEYS[key] + : undefined; if (allowed === undefined) { problem( ["packages", name, key], From d10ddff54807cee1b8baef43c7fc4c4004c88a3c Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 11:36:23 -0500 Subject: [PATCH 021/259] Compile createRequire probes for optional addons as deferred refusals Packages such as pi-tui look for their prebuilt Node-API addons at run time: a createRequire require call with a computed path, and the loader's resolve passed as a value, each inside a try block whose catch takes a fallback. Preflight refused these packages. Preflight now classifies each use of a createRequire loader. Inside the try block of a try statement in the same function, a call with a computed specifier or another argument shape, and resolve or resolve.paths read as a value, no longer refuse the package. Outside a try block they keep it refused, with a reason that names the computed specifier. The loader itself as a value, writes and optional calls stay refused. In JavaScript source, such a call evaluates its arguments and then throws a runtime fence, and the resolve value is a function that throws one when called, so `(options.resolve ?? require.resolve)(id)` still calls the option. Both are listed in coverage as deferred to runtime. TypeScript source keeps the compile-time refusals. Refs #1777 --- docs/content/limitations/native-addons.mdx | 6 ++ .../lowering/builtins/module-resolution.ts | 89 +++++++++++++++++-- .../lowering/expressions/property-access.ts | 22 +++++ packages/compiler/src/frontend/program.ts | 76 ++++++++++++---- tests/fixtures/npm-static/addon-probe-cli.ts | 5 ++ .../node_modules/addon-probe/index.d.ts | 2 + .../node_modules/addon-probe/index.js | 28 ++++++ .../node_modules/addon-probe/package.json | 7 ++ .../__snapshots__/create-require.ts.txt | 4 +- tests/harness/npm-static.test.ts | 59 ++++++++++++ 10 files changed, 275 insertions(+), 23 deletions(-) create mode 100644 tests/fixtures/npm-static/addon-probe-cli.ts create mode 100644 tests/fixtures/npm-static/node_modules/addon-probe/index.d.ts create mode 100644 tests/fixtures/npm-static/node_modules/addon-probe/index.js create mode 100644 tests/fixtures/npm-static/node_modules/addon-probe/package.json diff --git a/docs/content/limitations/native-addons.mdx b/docs/content/limitations/native-addons.mdx index 469d1cdd2..5fff3d7e8 100644 --- a/docs/content/limitations/native-addons.mdx +++ b/docs/content/limitations/native-addons.mdx @@ -2,5 +2,11 @@ Node-API (N-API) and V8 `.node` addons depend on Node.js itself, so compiled pro Direct `createRequire` calls to local addons are rejected at compile time. A package that requires an addon needs a JavaScript implementation that compiles, or a replacement through native FFI. +A package that looks for an optional addon at run time compiles with `--npm-static` when the lookup is inside a `try` block. +There, a `createRequire` require call with a computed specifier throws an error where it runs, and its `require.resolve` read as a value is a function that throws when called. +Coverage lists both as deferred to runtime. +The package's `catch` clause then runs as it does in Node.js when the addon is missing. +Outside a `try` block, the same uses keep the package refused. + Use [Native FFI](/docs/ffi#replacing-a-node-api-addon) to call a plain C ABI function linked from an object or static archive. The guide includes a replacement for a small Node-API helper. diff --git a/packages/compiler/src/frontend/lowering/builtins/module-resolution.ts b/packages/compiler/src/frontend/lowering/builtins/module-resolution.ts index 6b2e9e589..42ecfdd50 100644 --- a/packages/compiler/src/frontend/lowering/builtins/module-resolution.ts +++ b/packages/compiler/src/frontend/lowering/builtins/module-resolution.ts @@ -2,7 +2,7 @@ import { nodeThrowExpr, boolLit, strLit, varRef } from "../../../ir/build.js"; import { dirname, isAbsolute, resolve } from "node:path"; import * as ts from "../../ts7/adapter.js"; import { type Lowerer, PoisonError } from "../lowerer.js"; -import { canonicalBuiltinModule, isNodeEsmFile, locOf } from "../../program.js"; +import { canonicalBuiltinModule, isJsSourceFile, isNodeEsmFile, locOf } from "../../program.js"; import { isRelativeSpecifier } from "../../workspace-registry.js"; import { probeNodeRequireRefusal } from "../../npm.js"; import { isNpmStaticPackage } from "../../npm-static.js"; @@ -17,6 +17,7 @@ import { import { invalidJsonModuleDiag, nativeAddonDiag, + noLoweringDiag, unsupportedPackageImportDiag, } from "../../../diagnostics/diagnostic.js"; import { NODE_BUILTIN_MODULES_V24 } from "../surfaces.js"; @@ -24,12 +25,14 @@ import { BOOL, DYN, type IrExpr, + type IrStmt, type IrType, NULL_T, STRING, type SrcLoc, UNDEFINED_T, arrayOf, + funcOf, } from "../../../ir/ir.js"; import { lowerFfiMemoryModule } from "../native-ffi.js"; import { @@ -38,6 +41,7 @@ import { createRequireCalleeFileOf, } from "./module-bindings.js"; import { stripTypeCasts } from "./arguments.js"; +import { keyedHelperName } from "../stable-names.js"; /** node:module's two compiler-only calls. isBuiltin compares one evaluated * string against the pinned Node 24 list (bare builtins also accept their @@ -134,6 +138,61 @@ export function lowerNodeModuleCall( }; } +/** The fence a createRequire use with no build-time lowering throws in + * JavaScript source, where preflight admits it inside a try block + * (createRequireUse7 in program.ts). The diagnostic joins the runtime-fence + * ledger, so coverage lists the use as deferred to runtime. */ +function createRequireFence( + lowerer: Lowerer, + surface: string, + node: ts.Node, + hint: string, +): IrStmt & { kind: "runtimeFence" } { + const loc = locOf(node); + const d = noLoweringDiag(surface, loc, hint); + lowerer.runtimeFences.push(d); + const line = ts.getLineAndCharacterOfPosition(ts.getSourceFileOfNode(node), loc.start).line + 1; + return { + kind: "runtimeFence", + code: d.code, + message: `${d.message} [${d.code} at ${loc.file}:${line}]`, + loc, + }; +} + +/** A createRequire loader's `resolve` (or `resolve.paths`) read as a value + * in JavaScript source: a function that throws the fence when called, so + * `(options.resolve ?? require.resolve)(id)` still calls the option when + * one is given. */ +export function createRequireResolveFenceValue( + lowerer: Lowerer, + access: ts.PropertyAccessExpression, + loc: SrcLoc, +): IrExpr { + const surface = "createRequire's require.resolve as a value"; + const hint = + 'call it with a string literal (require.resolve("")), which resolves at build time'; + if (!isJsSourceFile(ts.getSourceFileOfNode(access))) lowerer.noLowering(surface, access, hint); + const name = keyedHelperName(lowerer, "%createRequire.fence", `${loc.file}:${loc.start}`); + if (!lowerer.liftedFns.some((fn) => fn.name === name)) { + lowerer.liftedFns.push({ + name, + params: [], + locals: [], + returnType: DYN, + body: [createRequireFence(lowerer, surface, access, hint)], + loc, + }); + } + return { + kind: "dynFrom", + value: { kind: "closure", fnName: name, captures: [], type: funcOf([], DYN), loc }, + fnName: access.name.text, + type: DYN, + loc, + }; +} + export function lowerCreateRequireCall( lowerer: Lowerer, call: ts.CallExpression, @@ -142,11 +201,31 @@ export function lowerCreateRequireCall( const cr = createRequireSpecOf(lowerer, call); if (cr === null) return null; if (cr.spec === null) { - lowerer.noLowering( - "createRequire's require with this argument shape", - call, - 'the compiled module graph is fixed at build time — the one lowered form is require("")', + const surface = "createRequire's require with a computed specifier or this argument shape"; + const hint = + 'the compiled module graph is fixed at build time — the one lowered form is require(""); native addons are not loaded'; + if (!isJsSourceFile(ts.getSourceFileOfNode(call))) lowerer.noLowering(surface, call, hint); + // Node evaluates the arguments, then the require throws. + const stmts: IrStmt[] = call.arguments.nodes.map((arg) => ({ + kind: "exprStmt", + expr: lowerer.lowerExpr(arg), + loc: locOf(arg), + })); + const type = lowerer.irTypeOf(call); + const slot = lowerer.declareHiddenLocal("%never", type); + slot.mutable = true; + stmts.push( + { kind: "varDecl", localId: slot.id, init: null, loc }, + createRequireFence(lowerer, surface, call, hint), ); + return { + kind: "seqExpr", + stmts, + result: varRef(slot.id, type, loc), + diverges: true, + type, + loc, + }; } const spec = cr.spec; if (spec === "node:ffi") { diff --git a/packages/compiler/src/frontend/lowering/expressions/property-access.ts b/packages/compiler/src/frontend/lowering/expressions/property-access.ts index 7b12297a8..539f27f80 100644 --- a/packages/compiler/src/frontend/lowering/expressions/property-access.ts +++ b/packages/compiler/src/frontend/lowering/expressions/property-access.ts @@ -144,6 +144,8 @@ import { nullishGenericBindingUnitOf } from "../binding-analysis.js"; import { blockedBindingUseDiag } from "../../../diagnostics/diagnostic.js"; import { npmStaticPackageOfPath } from "../../npm-static.js"; import { importMetaField, isImportMeta } from "../import-meta.js"; +import { createRequireCalleeFileOf } from "../builtins/module-bindings.js"; +import { createRequireResolveFenceValue } from "../builtins/module-resolution.js"; import { builtinPrototypeMethod, lowerArrayIsArrayValue, @@ -283,6 +285,21 @@ const DGRAM_METHOD_VALUES = new Set([ "unref", ]); +function isCreateRequireResolveValue(lowerer: Lowerer, expr: ts.PropertyAccessExpression): boolean { + let resolve: ts.Expression = expr; + if ( + expr.name.text === "paths" && + ts.isPropertyAccessExpression(expr.expression) && + !expr.expression.questionDotToken + ) + resolve = expr.expression; + return ( + ts.isPropertyAccessExpression(resolve) && + resolve.name.text === "resolve" && + createRequireCalleeFileOf(lowerer, resolve.expression) !== null + ); +} + export function lowerPropertyAccessExpr( lowerer: Lowerer, expr: ts.PropertyAccessExpression, @@ -1266,6 +1283,11 @@ export function lowerPropertyAccessExpr( return declared && declared.kind !== "void" ? lowerer.coerceToExpected(read, declared) : read; } } + // A createRequire loader's resolve read as a value (passed on, or + // picked by `??`): resolution happens at build time, so only calls + // with a literal specifier lower. + if (isCreateRequireResolveValue(lowerer, expr)) + return createRequireResolveFenceValue(lowerer, expr, loc); // The lib fence's PROPERTY chokepoint: a stdlib-declared member that // no lowering above claimed ([1,2].entries, Math.SQRT2, Promise.all, // re.exec as a value, ...) reports SC2020 here. diff --git a/packages/compiler/src/frontend/program.ts b/packages/compiler/src/frontend/program.ts index 6d8ffe4c0..54dd83714 100644 --- a/packages/compiler/src/frontend/program.ts +++ b/packages/compiler/src/frontend/program.ts @@ -2320,12 +2320,27 @@ export function isCreateRequireBinding7(program: ts.Program, callee: ts.Identifi ); } -/** Only literal calls and literal resolution queries can erase the loader - * value. In particular, assignments, exported aliases, shorthand properties, - * optional calls, and passing the loader to user code cannot pass this test. */ -function staticCreateRequireUse7(expr: ts.Expression): boolean { +/** How a use of a createRequire loader lowers: + * - "static": a literal call or a literal resolution query, which erases + * the loader value. + * - "deferred": a call with a computed specifier or another argument shape, + * or `resolve` / `resolve.paths` read as a value, inside the try block + * of a try statement in the same function. The call throws a runtime + * fence, and the resolve value is a function that throws one when called + * (module-resolution.ts), so the statement's catch clause handles them + * (packages that look for optional native addons). + * - "computed": the same shapes outside a try block. + * - "escaping": the loader itself as a value, writes, optional calls, and + * other members. */ +const COMPUTED_CREATE_REQUIRE_REASON = + "its createRequire result is used with a computed specifier, or its resolve as a value, outside a try block (static requires need literal specifiers)"; + +type CreateRequireUse7 = "static" | "deferred" | "computed" | "escaping"; + +function createRequireUse7(expr: ts.Expression): CreateRequireUse7 { let use: ts.Node = expr; while (ts.isParenthesizedExpression(use.parent)) use = use.parent; + let member = false; if ( ts.isPropertyAccessExpression(use.parent) && use.parent.expression === use && @@ -2333,6 +2348,7 @@ function staticCreateRequireUse7(expr: ts.Expression): boolean { !use.parent.questionDotToken ) { use = use.parent; + member = true; if ( ts.isPropertyAccessExpression(use.parent) && use.parent.expression === use && @@ -2342,15 +2358,42 @@ function staticCreateRequireUse7(expr: ts.Expression): boolean { use = use.parent; } const call = use.parent; + if (ts.isCallExpression(call) && call.expression === use) { + if (call.questionDotToken) return "escaping"; + if (call.arguments.nodes.length === 1 && ts.isStringLiteralLike(call.arguments.nodes[0]!)) + return "static"; + } else if (!member || isAssignmentTarget7(use)) { + return "escaping"; + } + return insideTryBlock7(use) ? "deferred" : "computed"; +} + +function isAssignmentTarget7(node: ts.Node): boolean { + const parent = node.parent; return ( - ts.isCallExpression(call) && - call.expression === use && - !call.questionDotToken && - call.arguments.nodes.length === 1 && - ts.isStringLiteralLike(call.arguments.nodes[0]!) + ts.isBinaryExpression(parent) && + parent.left === node && + parent.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && + parent.operatorToken.kind <= ts.SyntaxKind.LastAssignment ); } +/** True when `node` is inside the try block of a try statement in the same + * function (a catch clause or finally block does not count). A class field + * initializer runs when the class is instantiated, so it is a boundary too. */ +function insideTryBlock7(node: ts.Node): boolean { + for (let child = node, parent = node.parent; parent; child = parent, parent = parent.parent) { + if (ts.isTryStatement(parent) && parent.tryBlock === child) return true; + if ( + ts.isFunctionLike(parent) || + ts.isClassStaticBlockDeclaration(parent) || + ts.isPropertyDeclaration(parent) + ) + return false; + } + return false; +} + function stableCreateRequireBindingReason7( program: ts.Program, decl: ts.VariableDeclaration, @@ -2383,9 +2426,10 @@ function stableCreateRequireBindingReason7( : checker.getSymbolAtLocation(ref); if (target && (target.flags & ts.SymbolFlags.Alias) !== 0) target = checker.getAliasedSymbol(target); - if (target === symbol && !staticCreateRequireUse7(ref)) { - return "its createRequire binding is reassigned, escapes, or uses a computed specifier"; - } + if (target !== symbol) continue; + const use = createRequireUse7(ref); + if (use === "computed") return COMPUTED_CREATE_REQUIRE_REASON; + if (use === "escaping") return "its createRequire binding is reassigned or escapes"; } const preceding = stmt.declarationList.declarations.nodes.slice( 0, @@ -2448,10 +2492,10 @@ function npmStaticModuleImportReason7( checker.prefetchSymbolNodesExact(identifierOccurrences7(sf, specifier.name.text)); let reason: string | null = null; const checkUse = (expr: ts.Expression): void => { - if (!staticCreateRequireUse7(expr)) { - reason = - "its createRequire result escapes or is used with a computed specifier (static requires need literal specifiers)"; - } + const use = createRequireUse7(expr); + if (use === "computed") reason = COMPUTED_CREATE_REQUIRE_REASON; + else if (use === "escaping") + reason = "its createRequire result escapes (static requires need literal specifiers)"; }; ts.walkPreorder(sf, (node) => { if ( diff --git a/tests/fixtures/npm-static/addon-probe-cli.ts b/tests/fixtures/npm-static/addon-probe-cli.ts new file mode 100644 index 000000000..4515fb5bf --- /dev/null +++ b/tests/fixtures/npm-static/addon-probe-cli.ts @@ -0,0 +1,5 @@ +import { probe, resolveHelper } from "addon-probe"; +import { join } from "node:path"; + +console.log(join("a", "b"), [probe("clipboard"), probe("keys"), resolveHelper("addon-probe-helper")].join(",")); +console.log(resolveHelper("other", (id) => `custom:${id}`)); diff --git a/tests/fixtures/npm-static/node_modules/addon-probe/index.d.ts b/tests/fixtures/npm-static/node_modules/addon-probe/index.d.ts new file mode 100644 index 000000000..cfacc4764 --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/addon-probe/index.d.ts @@ -0,0 +1,2 @@ +export declare function probe(name: string): string; +export declare function resolveHelper(name: string, resolvePackage?: (id: string) => string): string; diff --git a/tests/fixtures/npm-static/node_modules/addon-probe/index.js b/tests/fixtures/npm-static/node_modules/addon-probe/index.js new file mode 100644 index 000000000..e65b1ad0e --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/addon-probe/index.js @@ -0,0 +1,28 @@ +import { createRequire } from "node:module"; +import { dirname, join } from "node:path"; +import { fileURLToPath } from "node:url"; + +const load = createRequire(import.meta.url); +const here = dirname(fileURLToPath(import.meta.url)); + +// Looks for a prebuilt addon in each packaging location, the way +// packages with optional native helpers do. +export function probe(name) { + for (const dir of ["prebuilds", "native"]) { + try { + const addon = load(join(here, dir, `${name}.node`)); + if (typeof addon?.run === "function") return "loaded"; + } catch { + // Try the next location. + } + } + return "absent"; +} + +export function resolveHelper(name, resolvePackage) { + try { + return (resolvePackage ?? load.resolve)(name); + } catch { + return "unresolved"; + } +} diff --git a/tests/fixtures/npm-static/node_modules/addon-probe/package.json b/tests/fixtures/npm-static/node_modules/addon-probe/package.json new file mode 100644 index 000000000..a2f7406f5 --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/addon-probe/package.json @@ -0,0 +1,7 @@ +{ + "name": "addon-probe", + "version": "1.0.0", + "type": "module", + "main": "index.js", + "types": "index.d.ts" +} diff --git a/tests/harness/__snapshots__/create-require.ts.txt b/tests/harness/__snapshots__/create-require.ts.txt index 219af92a4..a3c56a033 100644 --- a/tests/harness/__snapshots__/create-require.ts.txt +++ b/tests/harness/__snapshots__/create-require.ts.txt @@ -7,14 +7,14 @@ create-require.ts:13:13 - error SC2020: 'module.createRequire' is part of the st hint: the lowered shape is a const binding (or a proven stable top-level let/var) over createRequire(import.meta.url) (or __filename) whose require calls take STATIC string literals — builtins, project modules (including #imports), relative .json documents and natively compiled npm packages resolve at build time; dynamic specifiers cannot exist in a compiled binary's fixed module graph -create-require.ts:20:1 - error SC2020: 'createRequire's require with this argument shape' is part of the standard library types but has no scriptc lowering yet +create-require.ts:20:1 - error SC2020: 'createRequire's require with a computed specifier or this argument shape' is part of the standard library types but has no scriptc lowering yet 19 | const which = "left" + "-pad"; 20 | require(which); | ^~~~~~~~~~~~~~ 21 | - hint: the compiled module graph is fixed at build time — the one lowered form is require("") + hint: the compiled module graph is fixed at build time — the one lowered form is require(""); native addons are not loaded create-require.ts:23:1 - error SC2020: 'createRequire's require of './helper.js'' is part of the standard library types but has no scriptc lowering yet diff --git a/tests/harness/npm-static.test.ts b/tests/harness/npm-static.test.ts index 388da2138..026da8f4e 100644 --- a/tests/harness/npm-static.test.ts +++ b/tests/harness/npm-static.test.ts @@ -423,6 +423,40 @@ describe(`npm-static pilots${sanitize ? " (sanitized)" : ""}`, () => { }, ); + test.each(["llvm"] as const)( + "a package probing for optional addons through createRequire compiles with deferred refusals (%s)", + async (backend) => { + const entry = join(pilotRoot, "addon-probe-cli.ts"); + const { coverage } = analyze(entry, { npmStatic: "auto" }); + expect(coverage.npmStatic).toEqual([{ package: "addon-probe", status: "static" }]); + expect(coverage.diagnostics).toHaveLength(0); + expect( + (coverage.runtimeFences ?? []).filter((f) => f.code === "SC2020").map((f) => f.message), + ).toEqual([ + expect.stringContaining("'createRequire's require with a computed specifier"), + expect.stringContaining("'createRequire's require.resolve as a value'"), + ]); + const outDir = join(cacheDir, "addon-probe", sanitize ? "san" : "plain", backend); + const result = await compile(entry, { + backend, + npmStatic: "auto", + sanitize, + outDir, + outPath: join(outDir, "program"), + }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + const [nodeRes, nativeRes] = await Promise.all([ + runBinary(process.execPath, [entry]), + runBinary(result.binaryPath, []), + ]); + expect(nativeRes.stdout.toString()).toBe("a/b absent,absent,unresolved\ncustom:other\n"); + expect(nativeRes.stdout).toEqual(nodeRes.stdout); + expect(comparableStderr(nativeRes.stderr)).toEqual(nodeRes.stderr); + expect(nativeRes.exitCode).toBe(nodeRes.exitCode); + }, + ); + test.each([ [ "computed specifier", @@ -430,6 +464,31 @@ describe(`npm-static pilots${sanitize ? " (sanitized)" : ""}`, () => { "computed specifier", ], ["escaped require", 'const alias = load; const path = alias("node:path");', "escapes"], + [ + "computed specifier in a catch clause", + 'try { load("node:path"); } catch { load(String(1)); } const path = load("node:path");', + "outside a try block", + ], + [ + "computed specifier in a function inside a try block", + 'try { [1].map((n) => load(String(n))); } catch {} const path = load("node:path");', + "outside a try block", + ], + [ + "computed specifier in a class field inside a try block", + 'try { new (class { addon = load(String(1)); })(); } catch {} const path = load("node:path");', + "outside a try block", + ], + [ + "resolve value outside a try block", + 'const find = load.resolve; const path = load("node:path");', + "outside a try block", + ], + [ + "escaped require in a try block", + 'try { const alias = load; alias("node:path"); } catch {} const path = load("node:path");', + "escapes", + ], [ "reassigned require", 'let load = createLoader(import.meta.url); load = () => ({}); const path = load("node:path");', From ccd45c748f91d060ec0631c53df93f34bac383dc Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 12:21:50 -0500 Subject: [PATCH 022/259] Address the Node island report review findings --- packages/compiler/src/cli/command.ts | 15 +++- packages/compiler/src/diagnostics/envelope.ts | 5 +- packages/compiler/src/diagnostics/render.ts | 27 ++++++- packages/compiler/src/executable/prepare.ts | 6 +- packages/compiler/src/frontend/analysis.ts | 4 +- .../compiler/src/frontend/pipeline-native.ts | 4 +- packages/compiler/src/frontend/pipeline.ts | 78 ++++++++++++------- packages/compiler/src/index.ts | 9 ++- packages/compiler/src/native/compiler.ts | 3 +- .../node-islands-config/main.ts.json | 6 -- .../node-islands-config/main.ts | 4 + .../node-islands-config/package.json | 0 tests/diagnostics/node-islands-config/main.ts | 3 - .../node-islands-config/main.ts.txt | 35 --------- tests/harness/coverage.test.ts | 28 +++++++ 15 files changed, 141 insertions(+), 86 deletions(-) delete mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/node-islands-config/main.ts.json create mode 100644 tests/coverage-fixtures/node-islands-config/main.ts rename tests/{diagnostics => coverage-fixtures}/node-islands-config/package.json (100%) delete mode 100644 tests/diagnostics/node-islands-config/main.ts delete mode 100644 tests/harness/__snapshots__/node-islands-config/main.ts.txt diff --git a/packages/compiler/src/cli/command.ts b/packages/compiler/src/cli/command.ts index 2d15cbbb3..a660d339a 100644 --- a/packages/compiler/src/cli/command.ts +++ b/packages/compiler/src/cli/command.ts @@ -19,7 +19,7 @@ import { } from "../node-islands/policy.js"; import { TIER_MODES, type TierMode } from "../frontend/tier-analysis.js"; import { buildEnvelope } from "../diagnostics/envelope.js"; -import { renderWarnings } from "../diagnostics/render.js"; +import { renderConfigWarnings, renderWarnings } from "../diagnostics/render.js"; import { isPerformanceCode, renderPerformanceWarnings } from "../diagnostics/dynamic-tier.js"; import { isNativeOptimization } from "../backend/optimization.js"; import { setProvenanceSources } from "../frontend/provenance-registry.js"; @@ -609,14 +609,21 @@ async function main(args: string[], host: CliHost): Promise { // warning names likely-hot functions that use untyped values. `run` // keeps stderr for the program's own output. const color = process.stderr.isTTY ?? false; - const divergences = warnings.filter((d) => !isPerformanceCode(d.code)); + const config = warnings.filter((d) => d.code === "SC8004"); + const divergences = warnings.filter((d) => !isPerformanceCode(d.code) && d.code !== "SC8004"); const performance = warnings.filter((d) => isPerformanceCode(d.code)); - if (divergences.length > 0) + if (config.length > 0) + process.stderr.write( + renderConfigWarnings(config, result.sourceTexts ?? new Map(), { color }) + "\n", + ); + if (divergences.length > 0) { + if (config.length > 0) process.stderr.write("\n"); process.stderr.write( renderWarnings(divergences, result.sourceTexts ?? new Map(), { color }) + "\n", ); + } if (performance.length > 0) { - if (divergences.length > 0) process.stderr.write("\n"); + if (divergences.length > 0 || config.length > 0) process.stderr.write("\n"); process.stderr.write(renderPerformanceWarnings(performance) + "\n"); } } diff --git a/packages/compiler/src/diagnostics/envelope.ts b/packages/compiler/src/diagnostics/envelope.ts index ff08c3968..ad2e31507 100644 --- a/packages/compiler/src/diagnostics/envelope.ts +++ b/packages/compiler/src/diagnostics/envelope.ts @@ -334,7 +334,10 @@ export function locateDiagnostic( return { code: diag.code, category: categoryOf(diag), - severity: isDivergenceCode(diag.code) || isPerformanceCode(diag.code) ? "warning" : "error", + severity: + isDivergenceCode(diag.code) || isPerformanceCode(diag.code) || diag.code === "SC8004" + ? "warning" + : "error", scope, file: diag.loc.file, line: start.line, diff --git a/packages/compiler/src/diagnostics/render.ts b/packages/compiler/src/diagnostics/render.ts index e5a75c6bc..16fe3f0bf 100644 --- a/packages/compiler/src/diagnostics/render.ts +++ b/packages/compiler/src/diagnostics/render.ts @@ -102,14 +102,12 @@ export function renderDiagnostic( frame.push( c(DIM, ` ${" ".repeat(gutterWidth)} | `) + " ".repeat(caretCol) + - c(/^SC6\d{3}$/.test(diag.code) ? YELLOW : RED, "^" + "~".repeat(spanOnLine - 1)), + c(isWarningCode(diag.code) ? YELLOW : RED, "^" + "~".repeat(spanOnLine - 1)), ); emitLine(lineNum + 1); } - // The divergence band (SC6xxx) is the one warning severity: the program - // compiles, and the site can behave differently from Node. - const warning = /^SC6\d{3}$/.test(diag.code); + const warning = isWarningCode(diag.code); out.push( `${c(BOLD, `${diag.loc.file}:${lineNum}:${colNum}`)} - ${warning ? c(YELLOW, "warning") : c(RED, "error")} ${c(BOLD, diag.code)}: ${diag.message}`, ); @@ -154,6 +152,27 @@ export function renderDiagnostics( /** Divergence warnings after a successful build: the rendered sites plus a * one-line count, on stderr. */ +/** The warning severities: the divergence band (SC6xxx), where the program + * compiles and the site can behave differently from Node, and unknown + * settings in the project's scriptc configuration (SC8004), which builds do + * not use. */ +export function isWarningCode(code: string): boolean { + return /^SC6\d{3}$/.test(code) || code === "SC8004"; +} + +/** A build's SC8004 warnings: the unknown scriptc settings it ignored. */ +export function renderConfigWarnings( + diags: readonly ScrDiagnostic[], + sourceTextByFile: Map, + opts: RenderOptions = {}, +): string { + const n = diags.length; + return ( + renderDiagnostics([...diags], sourceTextByFile, opts) + + `\n\n${n} warning${n === 1 ? "" : "s"}: the build does not use ${n === 1 ? "this setting" : "these settings"}; scriptc coverage reports Node islands once they are valid.` + ); +} + export function renderWarnings( diags: readonly ScrDiagnostic[], sourceTextByFile: Map, diff --git a/packages/compiler/src/executable/prepare.ts b/packages/compiler/src/executable/prepare.ts index 1771f98f5..027bd6ca6 100644 --- a/packages/compiler/src/executable/prepare.ts +++ b/packages/compiler/src/executable/prepare.ts @@ -122,6 +122,10 @@ export function prepareExecutableModule( mod: lowered.module!, sourceTexts, stats: lowered.stats, - warnings: [...(lowered.divergences ?? []), ...(lowered.performance ?? [])], + warnings: [ + ...(fe.warnings ?? []), + ...(lowered.divergences ?? []), + ...(lowered.performance ?? []), + ], }; } diff --git a/packages/compiler/src/frontend/analysis.ts b/packages/compiler/src/frontend/analysis.ts index 403cb70b7..848306b66 100644 --- a/packages/compiler/src/frontend/analysis.ts +++ b/packages/compiler/src/frontend/analysis.ts @@ -38,7 +38,9 @@ export function analyzeWithFrontend( } ffi = loaded.profile; } - const fe = createFrontend(entryPath, opts.npmStatic, opts.externalTypes); + const fe = createFrontend(entryPath, opts.npmStatic, opts.externalTypes, undefined, { + nodeIslands: true, + }); try { const emptyStats = { statementsTotal: 0, diff --git a/packages/compiler/src/frontend/pipeline-native.ts b/packages/compiler/src/frontend/pipeline-native.ts index 511fd62f2..f2df52608 100644 --- a/packages/compiler/src/frontend/pipeline-native.ts +++ b/packages/compiler/src/frontend/pipeline-native.ts @@ -1,4 +1,4 @@ -import { runFrontend, type Frontend } from "./pipeline.js"; +import { runFrontend, type Frontend, type FrontendOptions } from "./pipeline.js"; import { loadProgram } from "./program.js"; import { FrontendServices, type ComptimeEvaluator } from "./services.js"; import { createNativeTs7Api } from "./ts7/native-api.js"; @@ -13,6 +13,7 @@ export function runNativeFrontend( externalTypes?: Readonly>, evaluateComptime?: ComptimeEvaluator, libraryNpmStatic: readonly string[] = [], + options: FrontendOptions = {}, ): Frontend { const services = new FrontendServices( (options) => createNativeTs7Api({ ...options, executable }), @@ -31,6 +32,7 @@ export function runNativeFrontend( npmStatic, externalTypes, libraryNpmStatic, + options, ); return { ...frontend, diff --git a/packages/compiler/src/frontend/pipeline.ts b/packages/compiler/src/frontend/pipeline.ts index 1021202cc..4e6a1c0f5 100644 --- a/packages/compiler/src/frontend/pipeline.ts +++ b/packages/compiler/src/frontend/pipeline.ts @@ -115,18 +115,30 @@ export interface Frontend { /** The Node island detector's input (report-only): the program's * modules with their pre-scan markers, package import edges, and how * each refused package was refused. Call before dispose. */ - nodeIslandScan?: (opts: { userJs: boolean }) => NodeIslandScan; + nodeIslandScan?: ((opts: { userJs: boolean }) => NodeIslandScan) | undefined; + /** Diagnostics that do not fail a build: unknown settings in the + * project's scriptc configuration (SC8004), which builds do not use. */ + warnings?: ScrDiagnostic[]; /** Releases the frontend's resources (the spawned tsgo server). Call * exactly once, after the last lower(). */ dispose: () => void; } /** Hosts own transport lifetimes; shared compiler stages own the frontend. */ +/** What a frontend computes beyond the build's own needs. */ +export interface FrontendOptions { + /** The Node island report (coverage): the project's scriptc settings and + * the detector's scan of the program and its npm packages. Builds do not + * read either. */ + nodeIslands?: boolean; +} + export type FrontendFactory = ( entryPath: string, npmStatic?: readonly string[] | "auto" | "lib", externalTypes?: Readonly>, libraryNpmStatic?: readonly string[], + options?: FrontendOptions, ) => Frontend; /** Adds the program modules a literal `import()` reaches to `scanned`, @@ -426,6 +438,7 @@ export function runFrontend( npmStatic?: readonly string[] | "auto" | "lib", externalTypes?: Readonly>, libraryNpmStatic: readonly string[] = [], + options: FrontendOptions = {}, ): Frontend { // A preflight or package probe may throw after its host has opened. Track // only live loads, releasing each immediately on normal fallback; this @@ -465,6 +478,7 @@ export function runFrontend( externalTypes, [...new Set(names)], transitive, + options, ); } catch (error) { for (const load of active) { @@ -486,6 +500,7 @@ function loadFrontend( externalTypes?: Readonly>, libraryNpmStatic: readonly string[] = [], transitive: Set = new Set(), + options: FrontendOptions = {}, ): Frontend { // Resolver package/workspace metadata is intentionally shared across the // several load attempts of ONE auto-detection fixpoint, but never across @@ -632,7 +647,7 @@ function loadFrontend( } const dropping = [...reasons.keys()].filter((p) => effective.has(p)); if (dropping.length === 0) break; - scanDroppedPackages(load, dropping, droppedScan); + if (options.nodeIslands === true) scanDroppedPackages(load, dropping, droppedScan); for (const p of dropping) { effective.delete(p); statuses.push({ package: p, status: "refused", detail: reasons.get(p)! }); @@ -684,13 +699,15 @@ function loadFrontend( probe.dispose(); if (probeDiags.some((d) => d.code === "SC0001")) dropWithNote(p); } - scanDroppedPackages(load, lastResortDropped.splice(0), droppedScan); + if (options.nodeIslands === true) + scanDroppedPackages(load, lastResortDropped.splice(0), droppedScan); load.dispose(); load = loadProgram(entryPath, { npmStatic: [...effective], externalTypes }); preflight = checkPreflight(load); if (preflight.some((d) => d.code === "SC0001") && effective.size > 0) { for (const p of [...effective]) dropWithNote(p); - scanDroppedPackages(load, lastResortDropped.splice(0), droppedScan); + if (options.nodeIslands === true) + scanDroppedPackages(load, lastResortDropped.splice(0), droppedScan); load.dispose(); load = loadProgram(entryPath, { npmStatic: [...effective], externalTypes }); preflight = checkPreflight(load); @@ -711,12 +728,16 @@ function loadFrontend( } const finalLoad = load; - // An unknown key or value in the project's scriptc configuration fails - // the build before anything else (SC8004). + // An unknown key or value in the project's scriptc configuration makes + // the Node island report unavailable (SC8004). The settings configure + // only that report: a build warns about them and goes on. const projectConfig = readProjectConfig(entryPath); const configDiagnostics = projectConfig.diagnostics; + const report = options.nodeIslands === true; return { - preflight: configDiagnostics.length > 0 ? [...configDiagnostics, ...preflight] : preflight, + preflight: + report && configDiagnostics.length > 0 ? [...configDiagnostics, ...preflight] : preflight, + ...(!report && configDiagnostics.length > 0 ? { warnings: configDiagnostics } : {}), entryText: () => finalLoad.entry.text, entryExports: () => entryFunctionExports(finalLoad.entry), // The contract scans the PROGRAM's source files, not the runtime @@ -779,26 +800,29 @@ function loadFrontend( }, npmStatic: statuses, npmImportSites: npmSites, - nodeIslandScan: ({ userJs }) => { - const files = new Set([finalLoad.entry, ...finalLoad.moduleOrder]); - addDynamicImportGraph(finalLoad, files); - // Package edges matter only when the program has npm packages: one - // that loads, one that was refused, or one judged and dropped. - const npm = - statuses.length > 0 || - droppedScan.modules.length > 0 || - [...files].some((sf) => sf.fileName.includes("/node_modules/")); - const scanned = scanFiles(finalLoad.program, [...files], { - userJs, - dropped: false, - edges: npm, - }); - return { - modules: [...droppedScan.modules, ...scanned.modules], - edges: [...droppedScan.edges, ...scanned.edges], - refusals, - }; - }, + nodeIslandScan: + options.nodeIslands !== true + ? undefined + : ({ userJs }) => { + const files = new Set([finalLoad.entry, ...finalLoad.moduleOrder]); + addDynamicImportGraph(finalLoad, files); + // Package edges matter only when the program has npm packages: one + // that loads, one that was refused, or one judged and dropped. + const npm = + statuses.length > 0 || + droppedScan.modules.length > 0 || + [...files].some((sf) => sf.fileName.includes("/node_modules/")); + const scanned = scanFiles(finalLoad.program, [...files], { + userJs, + dropped: false, + edges: npm, + }); + return { + modules: [...droppedScan.modules, ...scanned.modules], + edges: [...droppedScan.edges, ...scanned.edges], + refusals, + }; + }, dispose: finalLoad.dispose, }; } diff --git a/packages/compiler/src/index.ts b/packages/compiler/src/index.ts index 41f5cd619..14bdebf3c 100644 --- a/packages/compiler/src/index.ts +++ b/packages/compiler/src/index.ts @@ -412,8 +412,13 @@ export async function analyzeCached( return result; } -const nodeFrontend: FrontendFactory = (entry, npmStatic, externalTypes, libraryNpmStatic) => - runFrontend(entry, loadProgram, npmStatic, externalTypes, libraryNpmStatic); +const nodeFrontend: FrontendFactory = ( + entry, + npmStatic, + externalTypes, + libraryNpmStatic, + options, +) => runFrontend(entry, loadProgram, npmStatic, externalTypes, libraryNpmStatic, options); /** The checker's part of the executable cache key (`checkerCacheIdentity`), as the CLI's startup route computes it. */ function checkerField(): { checker?: string } { diff --git a/packages/compiler/src/native/compiler.ts b/packages/compiler/src/native/compiler.ts index a37d76f80..8f88356e9 100644 --- a/packages/compiler/src/native/compiler.ts +++ b/packages/compiler/src/native/compiler.ts @@ -108,7 +108,7 @@ export class NativeCompiler { private readonly cache: NativeCache | null = null, ) { const evaluator = toolchain.comptimeExecutable; - this.frontend = (entry, npmStatic, externalTypes, libraryNpmStatic) => + this.frontend = (entry, npmStatic, externalTypes, libraryNpmStatic, options) => runNativeFrontend( entry, toolchain.ts7Executable, @@ -119,6 +119,7 @@ export class NativeCompiler { : (source, timeout) => evaluateNativeComptime(source, timeout, toolchain.ts7Executable, evaluator), libraryNpmStatic, + options, ); } diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/node-islands-config/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/node-islands-config/main.ts.json deleted file mode 100644 index 6b86e7f9a..000000000 --- a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/node-islands-config/main.ts.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "order": [ - "/tests/diagnostics/node-islands-config/main.ts" - ], - "diags": [] -} diff --git a/tests/coverage-fixtures/node-islands-config/main.ts b/tests/coverage-fixtures/node-islands-config/main.ts new file mode 100644 index 000000000..5bacea88a --- /dev/null +++ b/tests/coverage-fixtures/node-islands-config/main.ts @@ -0,0 +1,4 @@ +// Unknown values in scriptc.packages or scriptc.nodeIslands are SC8004: a +// build warns about them and goes on (it does not use the settings), and +// coverage reports no Node islands until they are valid. +console.log("configured"); diff --git a/tests/diagnostics/node-islands-config/package.json b/tests/coverage-fixtures/node-islands-config/package.json similarity index 100% rename from tests/diagnostics/node-islands-config/package.json rename to tests/coverage-fixtures/node-islands-config/package.json diff --git a/tests/diagnostics/node-islands-config/main.ts b/tests/diagnostics/node-islands-config/main.ts deleted file mode 100644 index cc7b3735f..000000000 --- a/tests/diagnostics/node-islands-config/main.ts +++ /dev/null @@ -1,3 +0,0 @@ -// An unknown value in scriptc.packages or scriptc.nodeIslands is SC8004: -// the configuration the project asked for is never silently ignored. -console.log("configured"); diff --git a/tests/harness/__snapshots__/node-islands-config/main.ts.txt b/tests/harness/__snapshots__/node-islands-config/main.ts.txt deleted file mode 100644 index 03cc714aa..000000000 --- a/tests/harness/__snapshots__/node-islands-config/main.ts.txt +++ /dev/null @@ -1,35 +0,0 @@ -node-islands-config/package.json:6:7 - error SC8004: package.json 'scriptc.packages.encoding' has the unknown value "unloded" - - 5 | "packages": { - 6 | "encoding": "unloded", - | ^ - 7 | "debug": { "run": "island" } - - hint: use one of "unloaded", "node", "native", "auto", or an object with run, evaluate, share, marshal, schedule - -node-islands-config/package.json:7:18 - error SC8004: package.json 'scriptc.packages.debug.run' has the unknown value "island" - - 6 | "encoding": "unloded", - 7 | "debug": { "run": "island" } - | ^ - 8 | }, - - hint: use one of "native", "node", "auto" - -node-islands-config/package.json:10:7 - error SC8004: package.json 'scriptc.nodeIslands.auto' must be true or false, not "yes" - - 9 | "nodeIslands": { - 10 | "auto": "yes", - | ^ - 11 | "mode": "auto" - - hint: use a boolean - -node-islands-config/package.json:11:7 - error SC8004: package.json 'scriptc.nodeIslands.mode' is not a known Node island setting - - 10 | "auto": "yes", - 11 | "mode": "auto" - | ^ - 12 | } - - hint: the settings are auto, modules, node, nodeVersion, packaging, speculativeStart \ No newline at end of file diff --git a/tests/harness/coverage.test.ts b/tests/harness/coverage.test.ts index 2c34a69e1..8dd7173ad 100644 --- a/tests/harness/coverage.test.ts +++ b/tests/harness/coverage.test.ts @@ -5,6 +5,7 @@ import { join } from "node:path"; import { expect, test } from "vitest"; import { analyze, + compile, coverageEnvelope, coveragePasses, renderCoverage, @@ -871,6 +872,33 @@ test("Node islands (report-only): one package per class, gap islands first", asy expect(coveragePasses(coverage, "node-islands")).toBe(false); }); +test("unknown scriptc settings warn in a build and make the island report unavailable", async () => { + const entry = fixture("node-islands-config/main.ts"); + const outDir = mkdtempSync(join(tmpdir(), "scriptc-island-config-")); + try { + const built = await compile(entry, { + outputKind: "ir", + outPath: join(outDir, "main.ir.json"), + outDir, + }); + expect(built.ok).toBe(true); + if (!built.ok) return; + expect((built.warnings ?? []).map((d) => [d.code, d.message])).toEqual([ + ["SC8004", `package.json 'scriptc.packages.encoding' has the unknown value "unloded"`], + ["SC8004", `package.json 'scriptc.packages.debug.run' has the unknown value "island"`], + ["SC8004", `package.json 'scriptc.nodeIslands.auto' must be true or false, not "yes"`], + ["SC8004", "package.json 'scriptc.nodeIslands.mode' is not a known Node island setting"], + ]); + } finally { + rmSync(outDir, { recursive: true, force: true }); + } + const { coverage } = analyze(entry); + expect(coverage.nodeIslands).toBeUndefined(); + expect(renderCoverage({ ...coverage, file: "main.ts" }, { root: repoRoot })).toContain( + "not analyzable: the project's scriptc configuration has 4 unknown settings", + ); +}); + test("Node island policy from the command line: native, forced, off", () => { const entry = fixture("node-islands/main.ts"); const forced = analyze(entry, { From 26678e3c72385b44fe784ffea31c6a3f7fe2318c Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 13:20:59 -0500 Subject: [PATCH 023/259] Keep class methods native when element writes store data under their names --- benchmarks/runtime/README.md | 1 + .../workloads/keyed-option-writes.json | 6 ++ .../runtime/workloads/keyed-option-writes.ts | 76 ++++++++++++++++++ .../compiler/src/contracts/int32-elements.ts | 3 +- .../frontend/lowering/builtins/webassembly.ts | 5 +- .../lowering/class-method-mutations.ts | 53 +++++++++++-- .../lowering/containers/array-pipelines.ts | 4 +- .../lowering/containers/iterator-helpers.ts | 18 +++-- .../frontend/lowering/generic-functions.ts | 6 +- .../lowering/instantiation-path.test.ts | 12 ++- .../frontend/lowering/instantiation-path.ts | 6 +- .../compiler/src/frontend/lowering/lowerer.ts | 58 +++++++++----- .../lowering/site-dependencies.test.ts | 14 ++-- .../frontend/lowering/site-dependencies.ts | 15 +++- .../frontend/lowering/string-index-bounds.ts | 23 +++++- packages/compiler/src/frontend/npm-static.ts | 59 +++++++------- packages/compiler/src/frontend/services.ts | 9 ++- .../src/frontend/ts7/semantic-model.ts | 4 +- .../src/frontend/ts7/source-parser.ts | 4 +- .../compiler/test/keyed-method-writes.test.ts | 79 +++++++++++++++++++ 20 files changed, 361 insertions(+), 94 deletions(-) create mode 100644 benchmarks/runtime/workloads/keyed-option-writes.json create mode 100644 benchmarks/runtime/workloads/keyed-option-writes.ts create mode 100644 packages/compiler/test/keyed-method-writes.test.ts diff --git a/benchmarks/runtime/README.md b/benchmarks/runtime/README.md index 4f152e4bb..f7c21571a 100644 --- a/benchmarks/runtime/README.md +++ b/benchmarks/runtime/README.md @@ -16,6 +16,7 @@ Application-shaped workloads for measuring the speed of compiled executables. Ea | `functional-pipeline` | cpu | `filter`/`map`/`reduce`/`flatMap` chains, closures, small records | | `intern-table`, `intern-table-map`, `intern-table-1`, `intern-table-map-1` | cpu | worker threads interning the same type-like objects under string keys and records under number keys, then hits and misses: one shared `InternTable` per kind of key, or a module-level `Map` per thread (the `-map` entries), with 8 threads or 1 (the `-1` entries); under Node.js every thread has its own tables | | `json-records` | cpu | `JSON.stringify`, typed `JSON.parse`, Map aggregation | +| `keyed-option-writes` | cpu | class methods whose names are also keys of option records written through element accesses: `enabled[name] = true` over a union of literal names and `totals["count"] = n` | | `log-lines` | cpu | 200k immediate `console.log`/`process.stdout.write` lines into the runner's pipe | | `log-summary`, `inventory-report` | cpu | the multi-module applications from `benchmarks/builds`, on 300k-line inputs | | `number-maps` | cpu | number-keyed Map/Set: a dense-id table, sparse ids in many small maps, get/has/set mixes | diff --git a/benchmarks/runtime/workloads/keyed-option-writes.json b/benchmarks/runtime/workloads/keyed-option-writes.json new file mode 100644 index 000000000..802911e7d --- /dev/null +++ b/benchmarks/runtime/workloads/keyed-option-writes.json @@ -0,0 +1,6 @@ +{ + "entry": "workloads/keyed-option-writes.ts", + "args": [ + "4" + ] +} diff --git a/benchmarks/runtime/workloads/keyed-option-writes.ts b/benchmarks/runtime/workloads/keyed-option-writes.ts new file mode 100644 index 000000000..95cdbb86b --- /dev/null +++ b/benchmarks/runtime/workloads/keyed-option-writes.ts @@ -0,0 +1,76 @@ +// Class methods whose names are also keys of option records written through +// element accesses: `enabled[name] = true` over a union of literal names and +// `totals["count"] = n`. The writes store booleans and numbers into plain +// records, so the methods keep their native calls. +type Step = "scale" | "offset" | "clamp"; + +const enabled: Record = { scale: false, offset: false, clamp: false }; +function enable(name: Step): void { + enabled[name] = true; +} + +const totals: Record = {}; + +class Transform { + private readonly factor: number; + private readonly shift: number; + constructor(factor: number, shift: number) { + this.factor = factor; + this.shift = shift; + } + scale(x: number): number { + return enabled.scale ? x * this.factor : x; + } + offset(x: number): number { + return enabled.offset ? x + this.shift : x; + } + clamp(x: number): number { + if (!enabled.clamp) return x; + return x < 0 ? 0 : x > 1000 ? 1000 : x; + } +} + +class Counter { + private seen = 0; + private sum = 0; + add(value: number): void { + this.seen++; + this.sum += value; + } + count(): number { + return this.seen; + } + mean(): number { + return this.seen === 0 ? 0 : this.sum / this.seen; + } +} + +const scale = Number(process.argv[2] ?? "1"); +const steps: Step[] = ["scale", "offset", "clamp"]; +for (const step of steps) enable(step); + +const transforms: Transform[] = []; +for (let i = 0; i < 16; i++) transforms.push(new Transform(1 + (i % 5) * 0.25, (i % 7) - 3)); +const counters: Counter[] = []; +for (let i = 0; i < 8; i++) counters.push(new Counter()); + +let seed = 12345; +let checksum = 0; +const rounds = Math.floor(2_000_000 * scale); +for (let i = 0; i < rounds; i++) { + seed = (Math.imul(seed, 1103515245) + 12345) >>> 0; + const t = transforms[seed & 15]!; + const value = t.clamp(t.offset(t.scale((seed >>> 8) % 1200))); + const counter = counters[(seed >>> 4) & 7]!; + counter.add(value); + checksum += value; + if ((i & 65535) === 0) totals["count"] = counter.count(); +} + +let mean = 0; +let seen = 0; +for (const counter of counters) { + mean += counter.mean(); + seen += counter.count(); +} +console.log("seen", seen, "count", totals["count"], "mean", (mean / counters.length).toFixed(4), "checksum", checksum); diff --git a/packages/compiler/src/contracts/int32-elements.ts b/packages/compiler/src/contracts/int32-elements.ts index ca61a8e49..67446f2d1 100644 --- a/packages/compiler/src/contracts/int32-elements.ts +++ b/packages/compiler/src/contracts/int32-elements.ts @@ -709,7 +709,8 @@ export class Int32ElementContracts { const findChainsIn = (st: IrStmt): boolean => everyStmtChild(st, findChains, findChainsIn); for (const st of fn.body) findChainsIn(st); // Parameters whose callers are not all visible hold opaque arrays. - if (this.valueEscaped.has(fn.name) || this.runtimeVirtual(fn.name)) + const runtimeVirtual = this.runtimeVirtual; + if (this.valueEscaped.has(fn.name) || runtimeVirtual(fn.name)) for (const p of fn.params) if (this.holds(p.type)) { const why = this.valueEscaped.has(fn.name) diff --git a/packages/compiler/src/frontend/lowering/builtins/webassembly.ts b/packages/compiler/src/frontend/lowering/builtins/webassembly.ts index 8e5c3a048..f33ebe9fe 100644 --- a/packages/compiler/src/frontend/lowering/builtins/webassembly.ts +++ b/packages/compiler/src/frontend/lowering/builtins/webassembly.ts @@ -403,7 +403,10 @@ export function lowerWebAssemblyValueOf( recv: IrExpr, loc: IrExpr["loc"], ): IrExpr | null { - const ctx = { checker: lowerer.checker, isStdlibFile: lowerer.isStdlibFile }; + const ctx = { + checker: lowerer.checker, + isStdlibFile: (sf: ts.SourceFile) => lowerer.isStdlibFile(sf), + }; if (!isWebAssemblyType(lowerer.typeOf(receiver), ctx)) return null; lowerer.usesWebAssembly = true; return { kind: "libCall", fn: "wasm.valueOf", args: [recv], type: DYN, loc }; diff --git a/packages/compiler/src/frontend/lowering/class-method-mutations.ts b/packages/compiler/src/frontend/lowering/class-method-mutations.ts index fd23b6db8..d75f1d499 100644 --- a/packages/compiler/src/frontend/lowering/class-method-mutations.ts +++ b/packages/compiler/src/frontend/lowering/class-method-mutations.ts @@ -36,9 +36,20 @@ export function collectClassMethodMutations( const computedWrites: { key: ts.Expression | undefined; receiver: ts.Expression | undefined; + /** The written element access, when the write has one. */ + target?: ts.ElementAccessExpression; site: ts.Node; }[] = []; const propertyWrites: { target: ts.PropertyAccessExpression; site: ts.Node }[] = []; + /** Writes and deletes of a method name through an element access with a + * known key (`o["m"] = f`, `o[k] = f` with `k: "m" | "n"`), judged like + * the named writes in propertyWrites. */ + const keyedWrites: { + name: string; + receiver: ts.Expression; + target: ts.ElementAccessExpression; + site: ts.Node; + }[] = []; const reflection: ts.PropertyAccessExpression[] = []; const globals: ts.Identifier[] = []; const jsAssignments: (ts.PropertyAccessExpression | ts.ElementAccessExpression)[] = []; @@ -242,13 +253,32 @@ export function collectClassMethodMutations( sameBinding(receiver, keys.arguments.nodes[0]!) ); }; - const markKey = (key: ts.Expression, site: ts.Node, receiver?: ts.Expression): void => { + /** A write of the known key `name`: through an element access, a write + * to a method name is judged like a named write (keyedWrites). */ + const markKeyed = ( + name: string, + site: ts.Node, + receiver?: ts.Expression, + target?: ts.ElementAccessExpression, + ): void => { + if (receiver && target && methods.has(name) && name !== "prototype" && name !== "__proto__") { + receiverFields.add(name); + keyedWrites.push({ name, receiver, target, site }); + } else markName(name, site); + }; + const markKey = ( + key: ts.Expression, + site: ts.Node, + receiver?: ts.Expression, + target?: ts.ElementAccessExpression, + ): void => { const value = unwrap(key); - if (ts.isStringLiteralLike(value)) markName(value.text, site); - else if (ts.isNumericLiteral(value)) markName(String(Number(value.text)), site); + if (ts.isStringLiteralLike(value)) markKeyed(value.text, site, receiver, target); + else if (ts.isNumericLiteral(value)) + markKeyed(String(Number(value.text)), site, receiver, target); // The key keeps its assertions: `slots[at as number]` and `slots[at!]` // write a number key whatever the type of `at`. - else computedWrites.push({ key, receiver, site }); + else computedWrites.push(target ? { key, receiver, target, site } : { key, receiver, site }); }; const markFields = (value: ts.Expression, site: ts.Node, receiver?: ts.Expression): void => { value = unwrap(value); @@ -275,7 +305,7 @@ export function collectClassMethodMutations( propertyWrites.push({ target, site }); } else markName(name, site, arrow); } else if (ts.isElementAccessExpression(target)) - markKey(target.argumentExpression, site, target.expression); + markKey(target.argumentExpression, site, target.expression, target); else if (ts.isArrayLiteralExpression(target)) { for (const element of target.elements.nodes) { if (ts.isSpreadElement(element)) markTarget(element.expression, site); @@ -575,7 +605,7 @@ export function collectClassMethodMutations( if (!methodOwnerCanInhabit(target.expression, name)) continue; lowerer.prototypeMethodAccesses.set(name, site); } - for (const { key, receiver, site } of computedWrites) { + for (const { key, receiver, target, site } of computedWrites) { // A class method declared with a well-known symbol key is not a write; // any other write with one can replace that method. const symbolName = key ? wellKnownMethodName(unwrap(key)) : null; @@ -592,7 +622,7 @@ export function collectClassMethodMutations( const type = key ? lowerer.typeOf(key) : undefined; const names = type && (literalValues(type) ?? (key ? literalLoopKeys(unwrap(key)) : null)); if (names) { - for (const name of names) markName(String(name), site); + for (const name of names) markKeyed(String(name), site, receiver, target); continue; } if (key && receiver && preservesExistingMethod(key, receiver, site)) continue; @@ -614,6 +644,15 @@ export function collectClassMethodMutations( unknownKey = site; } } + lowerer.checker.prefetchClassCollection( + keyedWrites.flatMap((write) => [write.target, write.receiver]), + [], + ); + for (const { name, receiver, target, site } of keyedWrites) { + if (lowerer.prototypeMethodAccesses.has(name) || functionFree(lowerer.typeOf(target))) continue; + if (!methodOwnerCanInhabit(receiver, name)) continue; + lowerer.prototypeMethodAccesses.set(name, site); + } if (numericKey) { for (const name of [...methods, ...arrowFields]) { if (String(Number(name)) === name) markName(name, numericKey); diff --git a/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts b/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts index 2f839a20b..ff7da5fd7 100644 --- a/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts +++ b/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts @@ -1019,7 +1019,9 @@ class FusedLoop { private callee(arg: IrExpr & { type: FuncType }): Callee { const known = this.callees.find((c) => c.arg === arg); if (known) return known; - const target = this.inlineTarget(arg); + // Called as a plain function: the loop is not the target's receiver. + const inlineTarget = this.inlineTarget; + const target = inlineTarget(arg); let callee: Callee; if (target && arg.kind === "closure") { const captures = new Map(); diff --git a/packages/compiler/src/frontend/lowering/containers/iterator-helpers.ts b/packages/compiler/src/frontend/lowering/containers/iterator-helpers.ts index ba5d0684d..f6580c70e 100644 --- a/packages/compiler/src/frontend/lowering/containers/iterator-helpers.ts +++ b/packages/compiler/src/frontend/lowering/containers/iterator-helpers.ts @@ -1182,10 +1182,10 @@ function bindSource( /** Where chain code allocates its locals: a lifted helper function's own * frame, or hidden locals of the function being lowered (a fused for-of). */ -interface ChainFrame { - local(base: string, type: IrType, mutable: boolean): string; +abstract class ChainFrame { + abstract local(base: string, type: IrType, mutable: boolean): string; /** `id = id + 1` over a number local. */ - bump(id: string): IrStmt; + abstract bump(id: string): IrStmt; } /** `id = id + 1` over a number local. */ @@ -1206,11 +1206,13 @@ function bumpLocal(id: string, loc: SrcLoc): IrStmt { } /** Hidden locals of the function being lowered. */ -class HostFrame implements ChainFrame { +class HostFrame extends ChainFrame { constructor( private readonly lowerer: Lowerer, private readonly loc: SrcLoc, - ) {} + ) { + super(); + } local(base: string, type: IrType, mutable: boolean): string { const local = this.lowerer.declareHiddenLocal(`%${base}`, type); local.mutable = mutable; @@ -1223,11 +1225,13 @@ class HostFrame implements ChainFrame { /** The locals and parameters of a lifted helper function under * construction. */ -export class LiftedFrame implements ChainFrame { +export class LiftedFrame extends ChainFrame { readonly locals: IrLocal[] = []; readonly params: IrParam[] = []; private n = 0; - constructor(private readonly loc: SrcLoc) {} + constructor(private readonly loc: SrcLoc) { + super(); + } local(base: string, type: IrType, mutable: boolean): string { const id = `${base}.${this.n++}`; this.locals.push({ id, name: base, type, mutable }); diff --git a/packages/compiler/src/frontend/lowering/generic-functions.ts b/packages/compiler/src/frontend/lowering/generic-functions.ts index 222cb89f9..7896da578 100644 --- a/packages/compiler/src/frontend/lowering/generic-functions.ts +++ b/packages/compiler/src/frontend/lowering/generic-functions.ts @@ -645,8 +645,7 @@ function extendsParameter( info: GenericFnInfo, ): boolean { const params = new Set(); - const fn = info.decl as { parameters?: { nodes: readonly ts.ParameterDeclaration[] } }; - for (const param of fn.parameters?.nodes ?? []) { + for (const param of info.decl.parameters.nodes) { const symbol = ts.isIdentifier(param.name) ? lowerer.checker.getSymbolAtLocation(param.name) : undefined; @@ -672,8 +671,7 @@ function declaredInside(node: ts.Node, owner: ts.Node): boolean { * return gives anything else (or nothing). Nested functions and classes keep * their own returns. */ function returnedLocalClass(lowerer: Lowerer, info: GenericFnInfo): ts.ClassLikeDeclaration | null { - const fn = info.decl as ts.Node & { body?: ts.Node }; - const body = fn.body; + const body = info.decl.body; if (!body) return null; const classOf = (node: ts.Expression): ts.ClassLikeDeclaration | null => { let expr = node; diff --git a/packages/compiler/src/frontend/lowering/instantiation-path.test.ts b/packages/compiler/src/frontend/lowering/instantiation-path.test.ts index a31617106..267b402bc 100644 --- a/packages/compiler/src/frontend/lowering/instantiation-path.test.ts +++ b/packages/compiler/src/frontend/lowering/instantiation-path.test.ts @@ -1,19 +1,23 @@ import { expect, test } from "vitest"; +import type * as ts from "../ts7/adapter.js"; import { extendInstantiationPath, MAX_INSTANTIATION_RECURSION } from "./instantiation-path.js"; +/** A stand-in declaration: paths compare declarations by identity only. */ +const node = (): ts.Node => ({}) as ts.Node; + test("independent declarations and roots do not consume a recursive budget", () => { - const declaration = {}; + const declaration = node(); for (let i = 0; i < MAX_INSTANTIATION_RECURSION * 2; i++) expect(extendInstantiationPath(null, declaration)).not.toBeNull(); let path = extendInstantiationPath(null, declaration)!; for (let i = 0; i < MAX_INSTANTIATION_RECURSION * 2; i++) - path = extendInstantiationPath(path, {})!; + path = extendInstantiationPath(path, node())!; expect(extendInstantiationPath(path, declaration)).not.toBeNull(); }); test("bounds fresh recursive demands across intervening declarations", () => { - const first = {}; - const second = {}; + const first = node(); + const second = node(); let path = extendInstantiationPath(null, first)!; for (let i = 1; i < MAX_INSTANTIATION_RECURSION; i++) { path = extendInstantiationPath(path, second)!; diff --git a/packages/compiler/src/frontend/lowering/instantiation-path.ts b/packages/compiler/src/frontend/lowering/instantiation-path.ts index d79760988..b4a8375f6 100644 --- a/packages/compiler/src/frontend/lowering/instantiation-path.ts +++ b/packages/compiler/src/frontend/lowering/instantiation-path.ts @@ -1,7 +1,9 @@ +import type * as ts from "../ts7/adapter.js"; + /** Queued bodies preserve their demand ancestry. Independent concrete uses * do not consume a recursion budget; only fresh instances on one path do. */ export interface InstantiationPath { - declaration: object; + declaration: ts.Node; parent: InstantiationPath | null; } @@ -9,7 +11,7 @@ export const MAX_INSTANTIATION_RECURSION = 100; export function extendInstantiationPath( parent: InstantiationPath | null, - declaration: object, + declaration: ts.Node, ): InstantiationPath | null { let repetitions = 0; for (let path = parent; path; path = path.parent) { diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 3c74cfbad..ae2734ad4 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -3694,7 +3694,7 @@ export class Lowerer { positionOf: (node) => this.positions.of(node), shapes: this.shapes, unions: this.unions, - classNamer: this.classNamer, + classNamer: (decl) => this.classNamer(decl), resolveTypeParam: this.typeParamResolver, resolveTypeParamTs: this.typeParamTsResolver, isErasing: () => this.erasingDepth > 0, @@ -3775,8 +3775,8 @@ export class Lowerer { }, mixinIntersectionInstance: (widened) => mixinIntersectionInstanceType(this, widened), classImplementedProtocol: (type) => this.classImplementedProtocol(type), - isStdlibFile: this.isStdlibFile, - isNpmFile: this.isNpmFile, + isStdlibFile: (sf) => this.isStdlibFile(sf), + isNpmFile: (sf) => this.isNpmFile(sf), // The declaration-typed boundary's generated types (decl-projection.ts) // describe data, like an explicitly mapped external type surface. isExternalTypeFile: (sf) => @@ -8002,16 +8002,24 @@ export class Lowerer { lower: () => IrFunction | null; } >(); - const bodyRoots = (...roots: (ts.Node | undefined | null)[]): ts.Node[] => - roots.filter((root) => root !== undefined && root !== null); - const functionRoots = (decl: ts.FunctionLikeDeclaration): ts.Node[] => - bodyRoots(...decl.parameters.nodes.map((param) => param.initializer), decl.body); - const classCtorRoots = (info: ClassInfo): ts.Node[] => - bodyRoots( - ...(info.ctor?.parameters?.nodes ?? []).map((param) => param.initializer), - info.ctor?.body, - ...info.fieldOrder.map((field) => field.initializer), - ); + // Roots are collected with plain pushes: spread arguments into a rest + // parameter pass the nodes as dynamic values. + const addRoot = (roots: ts.Node[], root: ts.Node | undefined | null): void => { + if (root !== undefined && root !== null) roots.push(root); + }; + const functionRoots = (decl: ts.FunctionLikeDeclaration): ts.Node[] => { + const roots: ts.Node[] = []; + for (const param of decl.parameters.nodes) addRoot(roots, param.initializer); + addRoot(roots, decl.body); + return roots; + }; + const classCtorRoots = (info: ClassInfo): ts.Node[] => { + const roots: ts.Node[] = []; + for (const param of info.ctor?.parameters?.nodes ?? []) addRoot(roots, param.initializer); + addRoot(roots, info.ctor?.body); + for (const field of info.fieldOrder) addRoot(roots, field.initializer); + return roots; + }; const classMemberRoots = (info: ClassInfo): ts.Node[] => { const roots = classCtorRoots(info); for (const { member } of this.classMethodMembers(info)) roots.push(...functionRoots(member)); @@ -8188,7 +8196,8 @@ export class Lowerer { register(`%${cName}.set:${prop}`, [], () => this.throwingSetterFn(info, prop)); } }; - for (const name of collectionEdges) this.onEdge(name); + const onEdge = this.onEdge; + for (const name of collectionEdges) onEdge(name); // Generic instances queued by the bodies above lower here (an instance // body fires edges of its own and can queue further instances of // either kind — function instances and class instantiations drain to @@ -8323,7 +8332,8 @@ export class Lowerer { // profile-mapped exports are called from outside the graph, so they // seed the worklist beside the init bodies. Unknown names are inert // (the export-map resolution reports them as SC4002 later). - for (const root of extraRoots ?? []) this.onEdge?.(root); + const rootEdge = this.onEdge; + for (const root of extraRoots ?? []) rootEdge?.(root); const shuffle = lowerShuffle(); const drainUnits = (): void => { while (queue.length > 0) { @@ -8441,7 +8451,9 @@ export class Lowerer { /** Reachability hook (see emitReachable): fires when lowering resolves a * reference to a lowerable body. */ noteEdge(name: string): void { - if (this.onEdge) this.onEdge(name); + // Called as a plain function: the instance is not its receiver. + const onEdge = this.onEdge; + if (onEdge) onEdge(name); } /** A subclass constructor's super() edge: the base constructor runs, but @@ -11827,12 +11839,15 @@ export class Lowerer { /** Method-like members with their collected method-map names. Body * lowering omits abstract declarations; ABI analysis must include them - * because an abstract-typed call selects the same virtual slot. */ - *classMethodMembers( + * because an abstract-typed call selects the same virtual slot. An array, + * not a generator: a generator's yielded values are dynamic values, which + * would make every syntax node one. */ + classMethodMembers( info: ClassInfo, includeAbstract = false, - ): Generator<{ mName: string; member: ts.MethodDeclaration | ts.AccessorDeclaration }> { - if (!info.decl) return; // builtin error classes: runtime-provided bodies + ): { mName: string; member: ts.MethodDeclaration | ts.AccessorDeclaration }[] { + const members: { mName: string; member: ts.MethodDeclaration | ts.AccessorDeclaration }[] = []; + if (!info.decl) return members; // builtin error classes: runtime-provided bodies for (const member of info.decl.members.nodes) { const fnLike = ts.isMethodDeclaration(member) || ts.isGetAccessor(member) || ts.isSetAccessor(member) @@ -11856,8 +11871,9 @@ export class Lowerer { : `${ts.isGetAccessor(fnLike) ? "get" : "set"}:${baseName}`; const signature = info.methods.get(mName); if (!signature || (!fnLike.body && !(includeAbstract && signature.abstract))) continue; - yield { mName, member: fnLike }; + members.push({ mName, member: fnLike }); } + return members; } lowerClassCtor(info: ClassInfo): IrFunction { diff --git a/packages/compiler/src/frontend/lowering/site-dependencies.test.ts b/packages/compiler/src/frontend/lowering/site-dependencies.test.ts index ca5affcbe..0580a52ee 100644 --- a/packages/compiler/src/frontend/lowering/site-dependencies.test.ts +++ b/packages/compiler/src/frontend/lowering/site-dependencies.test.ts @@ -1,9 +1,13 @@ import { expect, test } from "vitest"; +import type * as ts from "../ts7/adapter.js"; import { SiteDependencies } from "./site-dependencies.js"; +/** A stand-in node fact: facts are compared by identity. */ +const node = (): ts.Node => ({}) as ts.Node; + test("a changed fact makes the sites that read it stale", () => { const dependencies = new SiteDependencies(3); - const a = {}; + const a = node(); const b = "key"; dependencies.begin(0); dependencies.read(a); @@ -20,8 +24,8 @@ test("a changed fact makes the sites that read it stale", () => { test("a visit that changes a fact makes every reader of its facts stale", () => { const dependencies = new SiteDependencies(3); - const shared = {}; - const own = {}; + const shared = node(); + const own = node(); dependencies.begin(0); dependencies.read(shared); dependencies.end(false); @@ -37,7 +41,7 @@ test("a visit that changes a fact makes every reader of its facts stale", () => test("reads outside a visit are not recorded", () => { const dependencies = new SiteDependencies(1); - const fact = {}; + const fact = node(); dependencies.read(fact); dependencies.changed(fact); expect(dependencies.isStale(0)).toBe(false); @@ -45,7 +49,7 @@ test("reads outside a visit are not recorded", () => { test("a site visited again is listed once per fact", () => { const dependencies = new SiteDependencies(3); - const fact = {}; + const fact = node(); for (const site of [0, 2, 1, 2, 0]) { dependencies.begin(site); dependencies.read(fact); diff --git a/packages/compiler/src/frontend/lowering/site-dependencies.ts b/packages/compiler/src/frontend/lowering/site-dependencies.ts index da8531e48..868531353 100644 --- a/packages/compiler/src/frontend/lowering/site-dependencies.ts +++ b/packages/compiler/src/frontend/lowering/site-dependencies.ts @@ -1,3 +1,5 @@ +import type * as ts from "../ts7/adapter.js"; + /** The facts each site of a fixed-point scan read on its last visit, so that * a pass visits again only the sites whose facts changed since. * @@ -13,14 +15,19 @@ * that with a pass over every site once a pass changes nothing, and resumes * when that pass changes a fact: a fact this tracking misses costs passes, * not a different result. */ +/** A fact a site reads: a symbol, a syntax node, or the name of a derived + * fact. A typed union keeps nodes and symbols native values; as `unknown` + * every syntax node would become a dynamic value. */ +export type SiteFact = ts.Node | ts.Symbol | string; + export class SiteDependencies { /** Each fact's entry: the visit that last read it, so that a visit lists a * fact once, followed by the sites that read it, ascending. */ - private readonly readers = new Map(); + private readonly readers = new Map(); private readonly stale: Uint8Array; private site = -1; private visit = 0; - private facts: unknown[] = []; + private facts: SiteFact[] = []; constructor(siteCount: number) { this.stale = new Uint8Array(siteCount); @@ -46,7 +53,7 @@ export class SiteDependencies { } /** The site being visited read `fact`. */ - read(fact: unknown): void { + read(fact: SiteFact): void { if (this.site < 0) return; const entry = this.readers.get(fact); if (entry === undefined) { @@ -72,7 +79,7 @@ export class SiteDependencies { } /** `fact` changed: every site that read it is visited again. */ - changed(fact: unknown): void { + changed(fact: SiteFact): void { const entry = this.readers.get(fact); if (entry !== undefined) for (let i = 1; i < entry.length; i++) this.stale[entry[i]!] = 1; } diff --git a/packages/compiler/src/frontend/lowering/string-index-bounds.ts b/packages/compiler/src/frontend/lowering/string-index-bounds.ts index af1b00ec6..6418aed76 100644 --- a/packages/compiler/src/frontend/lowering/string-index-bounds.ts +++ b/packages/compiler/src/frontend/lowering/string-index-bounds.ts @@ -182,11 +182,28 @@ export class StringIndexBounds { private readonly identifiers = new Map>(); constructor( - private readonly symbolAt: (node: ts.Node) => ts.Symbol | null, - private readonly declarationOf: (symbol: ts.Symbol) => ts.Node | undefined, - private readonly isString: (node: ts.Expression) => boolean, + private readonly lookupSymbol: (node: ts.Node) => ts.Symbol | null, + private readonly lookupDeclaration: (symbol: ts.Symbol) => ts.Node | undefined, + private readonly stringTyped: (node: ts.Expression) => boolean, ) {} + // The lookups are called as plain functions: the instance is not their + // receiver. + private symbolAt(node: ts.Node): ts.Symbol | null { + const lookup = this.lookupSymbol; + return lookup(node); + } + + private declarationOf(symbol: ts.Symbol): ts.Node | undefined { + const lookup = this.lookupDeclaration; + return lookup(symbol); + } + + private isString(node: ts.Expression): boolean { + const test = this.stringTyped; + return test(node); + } + /** True when `read` (an element access on a string receiver) is proven * to name an existing code unit. */ inBounds(read: ts.ElementAccessExpression): boolean { diff --git a/packages/compiler/src/frontend/npm-static.ts b/packages/compiler/src/frontend/npm-static.ts index eed02c95c..b00e14aa0 100644 --- a/packages/compiler/src/frontend/npm-static.ts +++ b/packages/compiler/src/frontend/npm-static.ts @@ -254,13 +254,18 @@ function aliasedPackageName(pkgDir: string): string | null { export function npmStaticTransformPkgJson(pkg: Record): void { delete pkg["types"]; delete pkg["typings"]; - const transform = (v: unknown): void => { - if (v === null || typeof v !== "object") return; - if (Array.isArray(v)) { - for (const item of v) transform(item); - return; - } - const obj = v as Record; + const transform = (v: unknown): unknown => { + if (v === null || typeof v !== "object") return v; + if (Array.isArray(v)) return v.map(transform); + // The result is a new object, built in key order; the first entry of a + // key wins. + const entries: [string, unknown][] = []; + const seen = new Set(); + const add = (key: string, value: unknown): void => { + if (seen.has(key)) return; + seen.add(key); + entries.push([key, value]); + }; // 0. The "node" condition HOISTS: Node's runtime resolution matches it // (yaml's `{ types, node: "./dist/index.js", default: "./browser/ // index.js" }` runs the node dist; the browser dist is a DIFFERENT @@ -270,24 +275,18 @@ export function npmStaticTransformPkgJson(pkg: Record): void { // under import+require (either matcher finds it there), an object's // entries splice inline — earlier real keys keep winning, exactly // Node's first-match-in-key-order rule. - if (obj["node"] !== undefined) { - const entries = Object.entries(obj); - for (const k of Object.keys(obj)) delete obj[k]; - for (const [k, val] of entries) { - if (k !== "node") { - if (!(k in obj)) obj[k] = val; - continue; - } - const inner: Record = - typeof val === "string" - ? { import: val, require: val } - : val !== null && typeof val === "object" && !Array.isArray(val) - ? (val as Record) - : {}; - for (const [ik, iv] of Object.entries(inner)) { - if (!(ik in obj)) obj[ik] = iv; - } + for (const [key, value] of Object.entries(v as Record)) { + if (key !== "node") { + add(key, value); + continue; } + const inner: Record = + typeof value === "string" + ? { import: value, require: value } + : value !== null && typeof value === "object" && !Array.isArray(value) + ? (value as Record) + : {}; + for (const [innerKey, innerValue] of Object.entries(inner)) add(innerKey, innerValue); } // 1. The types claims go AFTER the hoist: a node object's own // "types" key (uuid's `node: { types: "./dist/index.d.ts", default: @@ -295,15 +294,17 @@ export function npmStaticTransformPkgJson(pkg: Record): void { // in place tsgo follows it, maps the hidden declaration to its // same-stem JS (dist/index.js, the browser build) and disagrees with // this resolver's runtime answer. - delete obj["types"]; - delete obj["typings"]; - for (const value of Object.values(obj)) transform(value); + return Object.fromEntries( + entries + .filter(([key]) => key !== "types" && key !== "typings") + .map(([key, value]): [string, unknown] => [key, transform(value)]), + ); }; - if (pkg["exports"] !== undefined) transform(pkg["exports"]); + if (pkg["exports"] !== undefined) pkg["exports"] = transform(pkg["exports"]); // The "imports" field maps "#" specifiers with the same condition objects // (chalk 5's `"#supports-color": { node, default }`), so Node's "node" // target hoists there too. - if (pkg["imports"] !== undefined) transform(pkg["imports"]); + if (pkg["imports"] !== undefined) pkg["imports"] = transform(pkg["imports"]); } /** npmStaticTransformPkgJson over a package.json TEXT (the fs shadow's diff --git a/packages/compiler/src/frontend/services.ts b/packages/compiler/src/frontend/services.ts index 19728d6ce..14b366bfa 100644 --- a/packages/compiler/src/frontend/services.ts +++ b/packages/compiler/src/frontend/services.ts @@ -52,8 +52,10 @@ export class FrontendServices { } private sourceParser(): Ts7SourceParser { this.ensureOpen(); + // Called as a plain function: the instance is not its receiver. + const createApi = this.createApi; return (this.parser ??= new Ts7SourceParser( - (options) => this.createApi({ ...options, collectTiming: false }), + (options) => createApi({ ...options, collectTiming: false }), this.cwd, )); } @@ -62,9 +64,10 @@ export class FrontendServices { } evaluateComptime(source: string, timeoutMs: number): unknown { this.ensureOpen(); - if (this.comptimeEvaluator === undefined) + const evaluate = this.comptimeEvaluator; + if (evaluate === undefined) throw new Error("this compiler host does not provide compile-time evaluation"); - return this.comptimeEvaluator(source, timeoutMs); + return evaluate(source, timeoutMs); } createProgramHost(options?: Ts7HostOptions): Ts7Host { this.ensureOpen(); diff --git a/packages/compiler/src/frontend/ts7/semantic-model.ts b/packages/compiler/src/frontend/ts7/semantic-model.ts index d3d5fe61a..1a6560348 100644 --- a/packages/compiler/src/frontend/ts7/semantic-model.ts +++ b/packages/compiler/src/frontend/ts7/semantic-model.ts @@ -64,7 +64,9 @@ export interface SemanticQuery { export class SemanticProgram { constructor(private readonly sourceFile: (path: string) => AstNode | undefined) {} getSourceFile(path: string): AstNode | undefined { - return this.sourceFile(path); + // Called as a plain function: the instance is not its receiver. + const sourceFile = this.sourceFile; + return sourceFile(path); } } diff --git a/packages/compiler/src/frontend/ts7/source-parser.ts b/packages/compiler/src/frontend/ts7/source-parser.ts index f9029774c..bbb6cae7a 100644 --- a/packages/compiler/src/frontend/ts7/source-parser.ts +++ b/packages/compiler/src/frontend/ts7/source-parser.ts @@ -42,7 +42,9 @@ export class Ts7SourceParser { } private connect(): Ts7Api { - return this.createApi({ + // Called as a plain function: the instance is not its receiver. + const createApi = this.createApi; + return createApi({ cwd: this.cwd, fs: { readFile: (path) => this.files.get(tsgoPath(path)) ?? null, diff --git a/packages/compiler/test/keyed-method-writes.test.ts b/packages/compiler/test/keyed-method-writes.test.ts new file mode 100644 index 000000000..407530945 --- /dev/null +++ b/packages/compiler/test/keyed-method-writes.test.ts @@ -0,0 +1,79 @@ +import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile, deserializeModule } from "../src/index.js"; +import type { IrModule } from "../src/ir/ir.js"; +import { everyStmtList } from "../src/ir/traverse.js"; + +async function lowerSource(source: string): Promise { + const dir = await mkdtemp(join(tmpdir(), "scriptc-keyed-writes-")); + try { + const entry = join(dir, "main.ts"); + await writeFile(entry, source); + const outPath = join(dir, "main.ir.json"); + const result = await compile(entry, { outPath, outDir: dir, outputKind: "ir" }); + if (!result.ok) throw new Error(result.diagnostics.map((d) => d.message).join("\n")); + return deserializeModule(await readFile(outPath, "utf8")); + } finally { + await rm(dir, { recursive: true, force: true }); + } +} + +/** Calls in `run` that go through a dynamic value. */ +function dynamicCalls(mod: IrModule): number { + const fn = mod.functions.find((f) => f.name === "run"); + if (!fn) throw new Error("no run function"); + let n = 0; + everyStmtList(fn.body, { + expr: (e) => { + if (e.kind === "dynCall" || e.kind === "dynInvoke") n++; + return true; + }, + stmt: () => true, + }); + return n; +} + +const shape = ` +type Step = "scale" | "clamp"; +class Transform { + scale(x: number): number { + return x * 2; + } + clamp(x: number): number { + return x < 0 ? 0 : x; + } +} +`; + +test("element writes of data under method names keep the methods native", async () => { + const mod = await lowerSource(`${shape} +const enabled: Record = { scale: false, clamp: false }; +function enable(name: Step): void { + enabled[name] = true; +} +const totals: Record = {}; +function run(t: Transform): number { + enable("scale"); + totals["clamp"] = 1; + return t.clamp(t.scale(3)); +} +console.log(run(new Transform())); +`); + expect(dynamicCalls(mod)).toBe(0); +}); + +test("element writes through untyped receivers can still replace a method", async () => { + const mod = await lowerSource(`${shape} +function replace(target: object, name: Step): void { + (target as any)[name] = (x: number) => x + 100; +} +function run(t: Transform): number { + replace(t, "scale"); + return t.clamp(t.scale(3)); +} +console.log(run(new Transform())); +`); + expect(dynamicCalls(mod)).toBeGreaterThan(0); +}); From 7cdfe16c9b3849f3bd75efcb1e352ecae0561eac Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 14:24:38 -0500 Subject: [PATCH 024/259] Cap the Linux test step's memory and spread memory-heavy side files The Linux test shards run their suites in a transient systemd scope with MemoryMax=13G and no swap, below the runner's 16 GB. A process tree that grows past the cap loses its largest process to the kernel, and the job log names the failing test, where the runner itself ran out of memory and left no log. Hosts without systemd run the suites directly. The side-queue balancer also takes a table of memory-heavy files, with their measured peak. They run whole in the cost-balanced task, and each goes to the shard with the least memory-heavy work so far, after the time-balanced files. decl-boundary.test.ts, which peaks at about 1.8 GB alone and had no time measurement, so vitest's file sharding put it in shard 11, is the first entry. It now runs in shard 1 (plain) and 6 (san). --- .github/workflows/ci.yml | 7 +++++ scripts/ci-test-plan.mjs | 36 ++++++++++++++++++++++--- tests/harness/ci-test-plan.test.ts | 43 +++++++++++++++++++++++++++--- 3 files changed, 78 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b3bf0e770..5ab1d9331 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -216,9 +216,16 @@ jobs: # Start the corpus immediately beside a serial side queue. One shared # worker budget covers both processes; file and case shard axes stay # separate so every fixture still runs exactly once in each lane. + # The tests run in a transient scope capped below the runner's 16 GB: + # past 13 GB the kernel kills the scope's largest process, so the job + # log names the test instead of the runner itself running out of memory. - name: Tests (corpus and integration suites) run: | ulimit -c 0 + if [ -d /run/systemd/system ]; then + exec sudo --preserve-env systemd-run --scope --quiet -p MemoryMax=13G -p MemorySwapMax=0 \ + --uid="$(id -u)" --gid="$(id -g)" -- env PATH="$PATH" HOME="$HOME" node scripts/ci-test.mjs + fi node scripts/ci-test.mjs tests_macos: diff --git a/scripts/ci-test-plan.mjs b/scripts/ci-test-plan.mjs index 2b76b52d6..184f04d1c 100644 --- a/scripts/ci-test-plan.mjs +++ b/scripts/ci-test-plan.mjs @@ -42,22 +42,38 @@ export const testCosts = JSON.parse( readFileSync(new URL("./ci-test-costs.json", import.meta.url), "utf8"), ); +// Side-queue files whose process tree, run alone, peaks far above a plain +// vitest run (about 1 GB): megabytes at the peak, measured with CI's settings. +// They run beside the corpus task's three workers, so no two of them share a +// shard while there are shards without one. +export const memoryHeavyFiles = { + "tests/harness/decl-boundary.test.ts": 1838, +}; + // The shard (1-based) of each measured side-queue file and isolated suite: // longest first to the shard with the least work so far, counting about a // second per file for vitest to import it. Ties go to the highest shard, so the // longest files start from the last shard while the cost-balanced corpus and // three.js cases (tests/harness/shard.ts) place their longest from the first. -// An isolated suite without a measurement weighs as much as the median -// measured file. Files without a measurement are left to vitest's --shard, -// which splits them by count. +// An isolated suite or memory-heavy file without a measurement weighs as much +// as the median measured file. Memory-heavy files are placed after the others, +// each on the shard with the least memory-heavy work so far and, among those, +// the least work. Files without a +// measurement are left to vitest's --shard, which splits them by count. export function sideOwners(flavor, count) { const costs = testCosts[flavor]; const known = Object.values(costs).sort((a, b) => a - b); const median = known.length === 0 ? 0 : known[Math.floor(known.length / 2)]; const weight = (file) => (costs[file] ?? median) + 1000; - const files = [...new Set([...Object.keys(costs), ...isolatedFiles.map(([, file]) => file)])]; + const heavy = Object.keys(memoryHeavyFiles).sort( + (a, b) => memoryHeavyFiles[b] - memoryHeavyFiles[a] || (a < b ? -1 : a > b ? 1 : 0), + ); + const files = [ + ...new Set([...Object.keys(costs), ...isolatedFiles.map(([, file]) => file)]), + ].filter((file) => !(file in memoryHeavyFiles)); files.sort((a, b) => weight(b) - weight(a) || (a < b ? -1 : a > b ? 1 : 0)); const loads = new Array(count).fill(0); + const memory = new Array(count).fill(0); const owners = new Map(); for (const file of files) { let lightest = count - 1; @@ -66,6 +82,18 @@ export function sideOwners(flavor, count) { loads[lightest] += weight(file); owners.set(file, lightest + 1); } + for (const file of heavy) { + let lightest = count - 1; + for (let shard = count - 2; shard >= 0; shard--) + if ( + memory[shard] < memory[lightest] || + (memory[shard] === memory[lightest] && loads[shard] < loads[lightest]) + ) + lightest = shard; + memory[lightest] += memoryHeavyFiles[file]; + loads[lightest] += weight(file); + owners.set(file, lightest + 1); + } return owners; } diff --git a/tests/harness/ci-test-plan.test.ts b/tests/harness/ci-test-plan.test.ts index 34d61346f..9ff730ddf 100644 --- a/tests/harness/ci-test-plan.test.ts +++ b/tests/harness/ci-test-plan.test.ts @@ -11,6 +11,8 @@ import { caseShardedSideFiles, isolatedFiles, leakSuppressions, + memoryHeavyFiles, + sideOwners, testCosts, } from "../../scripts/ci-test-plan.mjs"; import { runCiTestPlan } from "../../scripts/ci-test.mjs"; @@ -40,20 +42,27 @@ test.for([1, 3, 5, 10, 20])( file, ).toHaveLength(everyShard ? count : 1); } - // Each measured file runs on exactly one shard, outside vitest's file shard. + // Each measured or memory-heavy file runs on exactly one shard, outside + // vitest's file shard. const isolated = new Set(isolatedFiles.map(([, file]) => file)); const balanced = plans.flatMap((plan) => plan.side .filter((task) => task.name === "cost-balanced tests") .flatMap((task) => task.args.slice(2)), ); - const measured = Object.keys(testCosts[flavor]).filter((file) => !isolated.has(file)); + const measured = [ + ...new Set([...Object.keys(testCosts[flavor]), ...Object.keys(memoryHeavyFiles)]), + ].filter((file) => !isolated.has(file)); expect(measured.length).toBeGreaterThan(0); expect(balanced.toSorted()).toEqual(measured.toSorted()); for (const plan of plans) { expect(plan.corpus.args).toEqual(["test", ...corpusFiles]); expect(plan.side[0]!.args).toContain(`--shard=${plan.corpus.env.SCRIPTC_TEST_SHARD}`); - for (const file of [...fileExclusions, ...Object.keys(testCosts[flavor])]) + for (const file of [ + ...fileExclusions, + ...Object.keys(testCosts[flavor]), + ...Object.keys(memoryHeavyFiles), + ]) expect(plan.side[0]!.args).toContain(`--exclude=${file}`); const cache = plan.side.find((task) => task.name === "native-cache correctness"); expect(Boolean(cache)).toBe(flavor === "plain"); @@ -103,6 +112,26 @@ test("the side queue balances measured files across the twenty Linux shards", () } }); +test("memory-heavy side files run whole in the cost-balanced task, on shards of their own", () => { + for (const flavor of ["plain", "san"] as const) { + const owners = sideOwners(flavor, 20); + const heavy = Object.keys(memoryHeavyFiles); + const shards = heavy.map((file) => owners.get(file)); + expect(shards.every((shard) => shard !== undefined)).toBe(true); + expect(new Set(shards).size).toBe(Math.min(heavy.length, 20)); + for (const file of heavy) { + const plan = ciTestPlan({ shard: `${owners.get(file)}/20`, flavor }); + const balanced = plan.side.find((task) => task.name === "cost-balanced tests")!; + expect(balanced.args).toContain(file); + // The file-sharded task leaves it out on every shard. + for (let shard = 1; shard <= 20; shard++) + expect(ciTestPlan({ shard: `${shard}/20`, flavor }).side[0]!.args).toContain( + `--exclude=${file}`, + ); + } + } +}); + test.for([1, 2, 4, 8])( "CI overlaps reserved lanes within a budget of %i workers", async (workers) => { @@ -265,7 +294,13 @@ test("pull requests run the full suite on Linux and the darwin suite on macOS", ); expect(coreStep).toBeGreaterThan(-1); expect(coreStep).toBeLessThan(linux.steps.length - 1); - expect(linux.steps.at(-1)!.run).toBe("ulimit -c 0\nnode scripts/ci-test.mjs\n"); + // Linux runs the suites in a memory-capped scope where systemd manages the + // runner, and directly elsewhere. + const linuxRun = linux.steps.at(-1)!.run as string; + expect(linuxRun.startsWith("ulimit -c 0\n")).toBe(true); + expect(linuxRun).toContain("systemd-run --scope --quiet -p MemoryMax=13G -p MemorySwapMax=0"); + expect(linuxRun).toMatch(/-- env PATH="\$PATH" HOME="\$HOME" node scripts\/ci-test\.mjs\n/); + expect(linuxRun.endsWith("fi\nnode scripts/ci-test.mjs\n")).toBe(true); expect(macos.steps.at(-1)!.run).toBe("node scripts/ci-test.mjs"); for (const job of [linux, macos]) expect(job.strategy.matrix.flavor).toEqual(["plain", "san"]); }); From b630efd450f066dabd3013e9d48b40a2b87ae0d1 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Fri, 23 Oct 2026 13:41:29 -0700 Subject: [PATCH 025/259] Report inferred shapes for untyped npm JavaScript (shape inference, stage 1) SCRIPTC_DEBUG_SHAPES=1 runs a whole-program allocation-site points-to analysis over opted-in npm packages' JavaScript and the user files that call into them, and prints which object and array literals a native record would represent exactly, the inferred class field types, the census of writes and reflection on untracked receivers, and the hot functions' parameter and return types. Report only: nothing reaches the lowering, and the analysis runs only when the variable is set. Design: results/design-shape-inference/DESIGN.md (scriptc-perf). Co-Authored-By: Claude Opus 5.5 --- packages/compiler/src/frontend/program.ts | 5 + .../src/frontend/shape-inference/analyze.ts | 2864 +++++++++++++++++ .../src/frontend/shape-inference/domain.ts | 153 + .../src/frontend/shape-inference/index.ts | 21 + .../src/frontend/shape-inference/report.ts | 374 +++ .../compiler/test/shape-inference.test.ts | 166 + 6 files changed, 3583 insertions(+) create mode 100644 packages/compiler/src/frontend/shape-inference/analyze.ts create mode 100644 packages/compiler/src/frontend/shape-inference/domain.ts create mode 100644 packages/compiler/src/frontend/shape-inference/index.ts create mode 100644 packages/compiler/src/frontend/shape-inference/report.ts create mode 100644 packages/compiler/test/shape-inference.test.ts diff --git a/packages/compiler/src/frontend/program.ts b/packages/compiler/src/frontend/program.ts index 6d8ffe4c0..a1f440648 100644 --- a/packages/compiler/src/frontend/program.ts +++ b/packages/compiler/src/frontend/program.ts @@ -140,6 +140,7 @@ import { } from "./type-only-imports.js"; import { moduleSourceCandidates } from "./module-source-candidates.js"; import { planDeclProjection, type DeclProjection } from "./decl-projection.js"; +import { reportShapes } from "./shape-inference/index.js"; import { inferredJsDiagnosticSuppressed } from "./inferred-js-diagnostics.js"; import { containsJsx, @@ -1260,6 +1261,10 @@ export function loadProgram( npmStaticPackages.length > 0, projector, ); + // Shape inference, stage S1: a report only (SCRIPTC_DEBUG_SHAPES). + const shapes = process.env["SCRIPTC_DEBUG_SHAPES"]; + if (shapes !== undefined && shapes !== "" && shapes !== "0" && npmStaticPackages.length > 0) + reportShapes(load.program, shapes); return { ...load, services, diff --git a/packages/compiler/src/frontend/shape-inference/analyze.ts b/packages/compiler/src/frontend/shape-inference/analyze.ts new file mode 100644 index 000000000..55e0e0107 --- /dev/null +++ b/packages/compiler/src/frontend/shape-inference/analyze.ts @@ -0,0 +1,2864 @@ +/* Shape inference (results/design-shape-inference/DESIGN.md), stage S1: + * a whole-program allocation-site points-to analysis over the JavaScript of + * opted-in npm packages and the user files that call into them. + * + * Stage S1 is report-only: the analysis runs when SCRIPTC_DEBUG_SHAPES is + * set and prints its plan (report.ts). Nothing it computes reaches the + * lowering yet, so every program compiles exactly as before. + * + * The analysis (DESIGN.md §4): + * - Andersen-style inclusion constraints, solved with a worklist. Locals + * and parameters are one value node per binding (flow-insensitive in S1); + * heap fields are one node per (atom, name); arrays one element node. + * - Calls resolve by the callee's atoms: functions, class constructors, + * methods by the receiver's class chain (inherited members, getters and + * setters, `this.constructor`), closures stored in fields, `bind`, and + * builtin summaries for the common library surface. + * - Escape: an atom escapes when it reaches code the analysis cannot see + * (a ⊤ callee, a builtin without a summary, a store into a ⊤ object). + * Escaped functions run with ⊤ arguments; everything reachable from an + * escaped atom escapes. + * - Census: writes and reflection whose receiver may be ⊤ apply to every + * escaped atom (§5.4); the report uses them to decide which allocation + * sites could become native records (§5.5). */ +import * as ts from "../ts7/adapter.js"; +import { isJsSourceFile } from "../program.js"; +import { npmStaticPackageOfPath } from "../npm-static.js"; +import { AtomTable, MODELED_GLOBALS, STRING_METHOD_RESULTS, type Atom } from "./domain.js"; + +type Node = ts.Node; + +export interface ValueNode { + readonly id: number; + readonly atoms: Set; + readonly succ: Set; + /** Constraints to run for each atom that arrives. */ + readonly onAtom: ((atom: Atom) => void)[]; + /** Every atom that arrives escapes. */ + escapeSink: string | null; +} + +export interface FunctionInfo { + readonly node: Node; + /** The analysis context: "" or a method's receiver (`C`). */ + readonly ctx: string; + /** The function whose clone the context is (bindings inside it are per context). */ + readonly root: Node | null; + /** Bodies are walked on first call: code that never runs adds no facts. */ + walked: boolean; + readonly label: string; + readonly params: number[]; + /** Index of a rest parameter, or -1. */ + readonly rest: number; + readonly thisNode: number; + readonly ret: number; + readonly isArrow: boolean; + readonly isAsync: boolean; + readonly isGenerator: boolean; + /** Reads `arguments` other than through `...arguments` forwarding. */ + usesArguments: boolean; + /** `f(...arguments)` forwarding: one node per argument position. */ + argPos: number[] | null; + /** The class whose member this function is (method, accessor, constructor). */ + readonly ownerClass: Node | null; + readonly inPackage: boolean; +} + +export interface LiteralSite { + readonly atom: Atom; + readonly node: Node; + readonly kind: "object" | "array"; + /** Static keys in creation order; null when a spread or computed key makes them unknown. */ + readonly keys: string[] | null; + readonly hasAccessor: boolean; + readonly hasProto: boolean; + readonly hasComputedKey: boolean; + readonly spreads: number[]; + readonly inPackage: boolean; +} + +export interface Op { + readonly kind: + | "read" + | "write" + | "computedRead" + | "computedWrite" + | "delete" + | "freeze" + | "seal" + | "defineProperty" + | "setPrototypeOf" + | "assign" + | "proxy" + | "lengthWrite"; + readonly recv: number; + readonly name: string | null; + readonly node: Node; +} + +export interface CallEdge { + readonly caller: FunctionInfo | null; + readonly callee: FunctionInfo; + readonly inLoop: boolean; +} + +export interface ShapeAnalysis { + readonly atoms: AtomTable; + readonly nodes: ValueNode[]; + readonly functions: Map; + readonly sites: LiteralSite[]; + readonly ops: Op[]; + readonly calls: CallEdge[]; + readonly escaped: Map; + readonly topWriteNames: Map; + readonly topComputedWrites: Node[]; + /** Fields per atom: name → node id. */ + readonly fields: Map>; + readonly elements: Map; + readonly top: Atom; + readonly files: readonly ts.SourceFile[]; + readonly packageFiles: number; + readonly checker: ts.TypeChecker; + readonly budgetExceeded: boolean; + readonly steps: number; + readonly topCause: ReadonlyMap; + readonly nodeLabel: ReadonlyMap; +} + +/** Array.prototype members: other names on an array are own properties. */ +const ARRAY_METHODS: ReadonlySet = new Set([ + "at", + "concat", + "copyWithin", + "entries", + "every", + "fill", + "filter", + "find", + "findIndex", + "findLast", + "findLastIndex", + "flat", + "flatMap", + "forEach", + "includes", + "indexOf", + "join", + "keys", + "lastIndexOf", + "map", + "pop", + "push", + "reduce", + "reduceRight", + "reverse", + "shift", + "slice", + "some", + "sort", + "splice", + "toLocaleString", + "toReversed", + "toSorted", + "toSpliced", + "toString", + "unshift", + "values", + "with", +]); +const MAX_STEPS = 20_000_000; + +function list(arr: { readonly nodes: readonly T[] } | undefined): readonly T[] { + return arr?.nodes ?? []; +} + +function isStatic(node: Node): boolean { + const mods = (node as { modifiers?: { nodes: readonly Node[] } }).modifiers; + return list(mods).some((m) => m.kind === ts.SyntaxKind.StaticKeyword); +} + +function unparen(node: ts.Expression): ts.Expression { + let n = node; + for (;;) { + if (ts.isParenthesizedExpression(n)) n = n.expression; + else if (ts.isNonNullExpression(n)) n = n.expression; + else if (ts.isAsExpression(n) || ts.isSatisfiesExpression(n)) n = n.expression; + else return n; + } +} + +function propertyNameText(name: Node): string | null { + if (ts.isIdentifier(name) || ts.isPrivateIdentifier(name)) return name.text; + if (ts.isStringLiteral(name) || ts.isNoSubstitutionTemplateLiteral(name)) return name.text; + if (ts.isNumericLiteral(name)) return String(Number(name.text)); + if (ts.isComputedPropertyName(name)) { + const e = unparen(name.expression); + if (ts.isStringLiteral(e) || ts.isNoSubstitutionTemplateLiteral(e)) return e.text; + if (ts.isNumericLiteral(e)) return String(Number(e.text)); + } + return null; +} + +function shortFile(fileName: string): string { + const norm = fileName.split("\\").join("/"); + const nm = norm.lastIndexOf("/node_modules/"); + if (nm >= 0) { + const rest = norm.slice(nm + "/node_modules/".length).split("/"); + const pkgLen = rest[0]?.startsWith("@") ? 2 : 1; + const pkg = rest.slice(0, pkgLen).join("/"); + return `${pkg}/${rest[rest.length - 1]}`; + } + return norm.slice(norm.lastIndexOf("/") + 1); +} + +export function locLabel(node: Node): string { + const sf = node.getSourceFile(); + const { line } = ts.getLineAndCharacterOfPosition(sf, node.getStart(sf)); + return `${shortFile(sf.fileName)}:${line + 1}`; +} + +/** Whether a source file belongs to an opted-in package's JavaScript. */ +export function isPackageJsFile(sf: ts.SourceFile): boolean { + return isJsSourceFile(sf) && npmStaticPackageOfPath(sf.fileName) !== null; +} + +function isLoop(node: Node): boolean { + return ( + ts.isForStatement(node) || + ts.isForOfStatement(node) || + ts.isForInStatement(node) || + ts.isWhileStatement(node) || + ts.isDoStatement(node) + ); +} + +const LOOP_CALLBACK_METHODS: ReadonlySet = new Set([ + "map", + "forEach", + "filter", + "some", + "every", + "find", + "findIndex", + "findLast", + "findLastIndex", + "reduce", + "reduceRight", + "flatMap", + "sort", +]); + +export function analyzeShapes(program: ts.Program, checker: ts.TypeChecker): ShapeAnalysis { + return new Analyzer(program, checker).run(); +} + +class Analyzer { + readonly atoms = new AtomTable(); + readonly nodes: ValueNode[] = []; + readonly functions = new Map(); + readonly sites: LiteralSite[] = []; + private readonly siteAtoms = new Set(); + readonly ops: Op[] = []; + readonly calls: CallEdge[] = []; + readonly escaped = new Map(); + readonly topWriteNames = new Map(); + readonly topComputedWrites: Node[] = []; + readonly fields = new Map>(); + readonly elements = new Map(); + readonly top: Atom; + private readonly bindings = new Map(); + private readonly exprMemo = new Map(); + /** Current analysis context and the function whose clone it is. */ + private ctx = ""; + private ctxRoot: Node | null = null; + private readonly classInfo = new Map(); + private readonly boundCalls = new Set(); + private readonly escapedFunctionCalls = new Set(); + private readonly worklist: [number, Atom][] = []; + private steps = 0; + private budgetExceeded = false; + private currentFn: FunctionInfo | null = null; + private loopDepth = 0; + private files: ts.SourceFile[] = []; + private packageFiles = 0; + private readonly prims = new Map(); + /** Per call site: the calling function and whether the site is in a loop + * (constraints fire during solving, after the walk has moved on). */ + private readonly siteCtx = new Map(); + private forceLoop = false; + + noteSite(site: Node): void { + if (!this.siteCtx.has(site)) + this.siteCtx.set(site, { caller: this.currentFn, inLoop: this.loopDepth > 0 }); + } + + edgeFor(site: Node, callee: FunctionInfo): void { + const ctx = this.siteCtx.get(site); + this.calls.push({ + caller: ctx?.caller ?? null, + callee, + inLoop: (ctx?.inLoop ?? false) || this.forceLoop, + }); + } + + constructor( + private readonly program: ts.Program, + private readonly checker: ts.TypeChecker, + ) { + this.top = this.atoms.intern("top", () => ({ kind: "top", label: "⊤" })); + } + + run(): ShapeAnalysis { + for (const sf of this.program.getSourceFiles()) { + if (sf.isDeclarationFile) continue; + const name = sf.fileName.split("\\").join("/"); + const inPackage = isPackageJsFile(sf); + if (!inPackage && name.includes("/node_modules/")) continue; + this.files.push(sf); + if (inPackage) this.packageFiles++; + } + for (const sf of this.files) this.checker.prefetchSourceFile(sf); + for (const sf of this.files) this.moduleBody(sf); + this.finish(); + return { + atoms: this.atoms, + nodes: this.nodes, + functions: this.functions, + sites: this.sites, + ops: this.ops, + calls: this.calls, + escaped: this.escaped, + topWriteNames: this.topWriteNames, + topComputedWrites: this.topComputedWrites, + fields: this.fields, + elements: this.elements, + top: this.top, + files: this.files, + packageFiles: this.packageFiles, + checker: this.checker, + budgetExceeded: this.budgetExceeded, + steps: this.steps, + topCause: this.topCause, + nodeLabel: this.nodeLabel, + }; + } + + // ---- value nodes ------------------------------------------------------- + + newNode(): number { + const id = this.nodes.length; + this.nodes.push({ id, atoms: new Set(), succ: new Set(), onAtom: [], escapeSink: null }); + return id; + } + + /** Debugging (SCRIPTC_DEBUG_SHAPES_WHY): where each node's ⊤ came from. */ + readonly topCause = new Map(); + readonly nodeLabel = new Map(); + private cause: number | null = null; + private readonly traceTop = process.env["SCRIPTC_DEBUG_SHAPES_WHY"] !== undefined; + + add(node: number, atom: Atom): void { + const n = this.nodes[node]!; + if (n.atoms.has(atom)) return; + n.atoms.add(atom); + if (this.traceTop && atom === this.top && !this.topCause.has(node)) + this.topCause.set( + node, + this.cause ?? + (new Error().stack ?? "") + .split("\n") + .slice(2, 4) + .map((l) => l.trim()) + .join(" < "), + ); + this.worklist.push([node, atom]); + } + + edge(from: number, to: number): void { + if (from === to) return; + const n = this.nodes[from]!; + if (n.succ.has(to)) return; + n.succ.add(to); + const saved = this.cause; + this.cause = from; + for (const a of n.atoms) this.add(to, a); + this.cause = saved; + } + + on(node: number, fn: (atom: Atom) => void): void { + const n = this.nodes[node]!; + n.onAtom.push(fn); + for (const a of [...n.atoms]) fn(a); + } + + sink(node: number, reason: string): void { + const n = this.nodes[node]!; + if (n.escapeSink !== null) return; + n.escapeSink = reason; + for (const a of [...n.atoms]) this.escape(a, reason); + } + + constNode(atom: Atom): number { + const n = this.newNode(); + this.add(n, atom); + return n; + } + + prim(name: string): Atom { + let a = this.prims.get(name); + if (a === undefined) { + a = this.atoms.intern(`prim:${name}`, () => ({ kind: "prim", label: name })); + this.prims.set(name, a); + } + return a; + } + + builtin(path: string, receiver?: Atom): Atom { + const key = receiver === undefined ? `builtin:${path}` : `builtin:${path}@${receiver.id}`; + return this.atoms.intern(key, () => ({ kind: "builtin", label: path, path, receiver })); + } + + solve(): void { + while (this.worklist.length > 0) { + if (++this.steps > MAX_STEPS) { + this.budgetExceeded = true; + return; + } + const [id, atom] = this.worklist.pop()!; + const n = this.nodes[id]!; + this.cause = id; + for (const s of n.succ) this.add(s, atom); + this.cause = null; + for (const f of n.onAtom) f(atom); + if (n.escapeSink !== null) this.escape(atom, n.escapeSink); + } + } + + // ---- heap ---------------------------------------------------------------- + + field(atom: Atom, name: string): number { + let m = this.fields.get(atom); + if (m === undefined) { + m = new Map(); + this.fields.set(atom, m); + } + let id = m.get(name); + if (id === undefined) { + id = this.newNode(); + m.set(name, id); + if (this.traceTop) this.nodeLabel.set(id, `${atom.label}.${name}`); + const reason = this.escaped.get(atom); + if (reason !== undefined) { + this.sink(id, reason); + if (this.topComputedWrites.length > 0 || this.topWriteNames.has(name)) + this.add(id, this.top); + } + } + return id; + } + + element(atom: Atom): number { + let id = this.elements.get(atom); + if (id === undefined) { + id = this.newNode(); + this.elements.set(atom, id); + const reason = this.escaped.get(atom); + if (reason !== undefined) { + this.sink(id, reason); + if (this.topComputedWrites.length > 0) this.add(id, this.top); + } + } + return id; + } + + escape(atom: Atom, reason: string): void { + if (atom.kind === "prim" || atom.kind === "top") return; + if (atom.kind === "builtin" && atom.receiver === undefined) return; + if (this.escaped.has(atom)) return; + this.escaped.set(atom, reason); + const via = `via ${atom.label}`; + const fm = this.fields.get(atom); + if (fm !== undefined) { + for (const [name, id] of fm) { + this.sink(id, via); + if (this.topComputedWrites.length > 0 || this.topWriteNames.has(name)) + this.add(id, this.top); + } + } + const el = this.elements.get(atom); + if (el !== undefined) { + this.sink(el, via); + if (this.topComputedWrites.length > 0) this.add(el, this.top); + } + if (atom.receiver !== undefined) this.escape(atom.receiver, via); + if (atom.kind === "function") { + const info = this.infoOfAtom(atom); + if (info !== undefined) this.escapeFunction(info, via); + } + if ((atom.kind === "instance" || atom.kind === "class") && atom.node !== undefined) { + // Unknown code may call any member with any arguments. + for (const member of this.classMembers(atom.node, atom.kind === "class")) { + const info = this.functionInfo(member, this.ownerOf(member), this.receiverCtx(atom)); + this.add(info.thisNode, atom); + this.escapeFunction(info, via); + } + } + if (atom.kind === "promise") this.sink(this.field(atom, "value"), via); + } + + /** A function unknown code may call: ⊤ arguments and receiver; its + * results escape. */ + escapeFunction(info: FunctionInfo, reason: string): void { + if (this.escapedFunctionCalls.has(info)) return; + this.escapedFunctionCalls.add(info); + this.activate(info); + for (const p of info.params) this.add(p, this.top); + if (!info.isArrow && info.ownerClass === null) this.add(info.thisNode, this.top); + this.sink(info.ret, reason); + } + + /** Property names that untyped code writes on receivers that may be ⊤ (census). */ + noteTopWrite(name: string | null, node: Node): void { + if (name === null) { + const first = this.topComputedWrites.length === 0; + this.topComputedWrites.push(node); + if (first) { + for (const atom of [...this.escaped.keys()]) { + for (const id of (this.fields.get(atom) ?? new Map()).values()) + this.add(id, this.top); + const el = this.elements.get(atom); + if (el !== undefined) this.add(el, this.top); + } + } + return; + } + if (this.topWriteNames.has(name)) return; + this.topWriteNames.set(name, node); + for (const atom of [...this.escaped.keys()]) { + const id = this.fields.get(atom)?.get(name); + if (id !== undefined) this.add(id, this.top); + } + } + + // ---- classes --------------------------------------------------------------- + + /** The base class declaration of `decl`, via the checker; null at a + * builtin base or none; undefined when unresolved. */ + baseClass(decl: Node): Node | null | undefined { + const heritage = list((decl as ts.ClassLikeDeclaration).heritageClauses).find( + (c) => c.token === ts.SyntaxKind.ExtendsKeyword, + )?.types?.nodes[0]; + if (heritage === undefined) return null; + const e = unparen(heritage.expression); + if (!ts.isIdentifier(e) && !ts.isPropertyAccessExpression(e)) return undefined; + let d = this.resolve(ts.isIdentifier(e) ? e : e.name); + // `var C = class C { … }` (bundler output) + if ( + d !== undefined && + ts.isVariableDeclaration(d) && + d.initializer !== undefined && + ts.isClassExpression(unparen(d.initializer)) + ) + d = unparen(d.initializer); + if (d !== undefined && ts.isClassLikeDeclaration(d)) return d; + if (d !== undefined && d.getSourceFile().isDeclarationFile) return null; + return undefined; + } + + classChain(decl: Node): Node[] { + const out: Node[] = []; + let cur: Node | null | undefined = decl; + while (cur && out.length < 64 && !out.includes(cur)) { + out.push(cur); + cur = this.baseClass(cur); + } + return out; + } + + /** Method, accessor and constructor declarations of a class chain. */ + classMembers(decl: Node, statics: boolean): Node[] { + const out: Node[] = []; + for (const c of this.classChain(decl)) { + for (const m of list((c as ts.ClassLikeDeclaration).members)) { + if (isStatic(m) !== statics) continue; + if ( + ts.isMethodDeclaration(m) || + ts.isGetAccessorDeclaration(m) || + ts.isSetAccessorDeclaration(m) + ) + out.push(m); + else if (ts.isPropertyDeclaration(m) && m.initializer !== undefined) { + const init = unparen(m.initializer); + if (ts.isArrowFunction(init) || ts.isFunctionExpression(init)) out.push(init); + } + } + } + return out; + } + + lookupMember( + decl: Node, + name: string, + statics: boolean, + ): { + kind: "method" | "getter" | "setter" | "both"; + get?: Node; + set?: Node; + method?: Node; + } | null { + for (const c of this.classChain(decl)) { + let get: Node | undefined; + let set: Node | undefined; + for (const m of list((c as ts.ClassLikeDeclaration).members)) { + if (isStatic(m) !== statics) continue; + const mn = (m as { name?: Node }).name; + if (mn === undefined || propertyNameText(mn) !== name) continue; + if (ts.isMethodDeclaration(m)) return { kind: "method", method: m }; + if (ts.isGetAccessorDeclaration(m)) get = m; + if (ts.isSetAccessorDeclaration(m)) set = m; + if (ts.isPropertyDeclaration(m)) return null; // an own field: data + } + if (get || set) + return { + kind: get && set ? "both" : get ? "getter" : "setter", + ...(get ? { get } : {}), + ...(set ? { set } : {}), + }; + } + return null; + } + + // ---- symbols ----------------------------------------------------------------- + + resolve(id: Node): Node | undefined { + let sym = this.checker.getSymbolAtLocation(id); + if (sym === undefined) return undefined; + if (sym.flags & ts.SymbolFlags.Alias) { + try { + sym = this.checker.getAliasedSymbol(sym); + } catch { + return undefined; + } + } + return sym.valueDeclaration ?? sym.declarations[0]; + } + + binding(decl: Node): number { + const key = this.ctxKey(decl); + let id = this.bindings.get(key); + if (id === undefined) { + id = this.newNode(); + this.bindings.set(key, id); + if (this.traceTop) + this.nodeLabel.set( + id, + `binding ${(decl as { name?: { text?: string } }).name?.text ?? "?"}@${locLabel(decl)}${this.ctx !== "" ? ` [${this.ctx}]` : ""}`, + ); + } + return id; + } + + /** Bindings and expressions inside the function being cloned belong to + * the clone's context; everything else to the default context. */ + ctxKey(node: Node): string { + const root = this.ctxRoot; + const inside = + root !== null && + node.getSourceFile() === root.getSourceFile() && + node.pos >= root.pos && + node.end <= root.end; + return `${inside ? this.ctx : ""}|${this.nodeKey(node)}`; + } + + receiverCtx(atom: Atom): string { + return atom.kind === "instance" || atom.kind === "class" ? `C${atom.id}` : ""; + } + + infoOfAtom(atom: Atom): FunctionInfo | undefined { + if (atom.node === undefined) return undefined; + return this.functions.get(`${atom.ctx ?? ""}|${this.nodeKey(atom.node)}`); + } + + // ---- functions --------------------------------------------------------------- + + functionInfo(node: Node, ownerClass: Node | null, ctxArg = ""): FunctionInfo { + // A nested closure walked inside a clone shares the clone's context. + const inherit = + ctxArg === "" && + this.ctxRoot !== null && + node.getSourceFile() === this.ctxRoot.getSourceFile() && + node.pos >= this.ctxRoot.pos && + node.end <= this.ctxRoot.end; + const ctx = ctxArg !== "" ? ctxArg : inherit ? this.ctx : ""; + const root = ctxArg !== "" ? node : inherit ? this.ctxRoot : null; + const fkey = `${ctx}|${this.nodeKey(node)}`; + const existing = this.functions.get(fkey); + if (existing !== undefined) return existing; + const savedCtx = this.ctx; + const savedRoot = this.ctxRoot; + this.ctx = ctx; + this.ctxRoot = root; + const fn = node as ts.FunctionLikeDeclaration; + const isArrow = ts.isArrowFunction(node); + const params: number[] = []; + let rest = -1; + for (const p of list(fn.parameters)) { + const id = this.binding(p); + if (p.dotDotDotToken !== undefined) rest = params.length; + params.push(id); + } + const mods = list((fn as { modifiers?: { nodes: readonly Node[] } }).modifiers); + const sf = node.getSourceFile(); + const nameNode = (fn as { name?: Node }).name; + const name = nameNode !== undefined ? (propertyNameText(nameNode) ?? "") : null; + const owner = ownerClass !== null ? this.className(ownerClass) : null; + const label = `${owner !== null ? `${owner}.` : ""}${name ?? (ts.isConstructorDeclaration(node) ? "constructor" : "")}@${locLabel(node)}`; + const info: FunctionInfo = { + node, + ctx, + root, + walked: false, + label: ctx === "" ? label : `${label} [${this.ctxLabel(ctx)}]`, + params, + rest, + thisNode: isArrow && this.currentFn !== null ? this.currentFn.thisNode : this.newNode(), + ret: this.newNode(), + isArrow, + isAsync: mods.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword), + isGenerator: (fn as { asteriskToken?: Node }).asteriskToken !== undefined, + usesArguments: false, + argPos: null, + ownerClass, + inPackage: isPackageJsFile(sf), + }; + this.functions.set(fkey, info); + this.ctx = savedCtx; + this.ctxRoot = savedRoot; + return info; + } + + /** Walks a function's body the first time it can run. */ + activate(info: FunctionInfo): void { + if (info.walked) return; + info.walked = true; + if (ts.isSourceFile(info.node) || ts.isClassLikeDeclaration(info.node)) return; + const fn = info.node as ts.FunctionLikeDeclaration; + const savedCtx = this.ctx; + const savedRoot = this.ctxRoot; + const saved = this.currentFn; + const savedLoop = this.loopDepth; + this.ctx = info.ctx; + this.ctxRoot = info.root; + this.currentFn = info; + this.loopDepth = 0; + for (const p of list(fn.parameters)) { + if (p.initializer !== undefined) this.edge(this.expr(p.initializer), this.binding(p)); + if (p.dotDotDotToken !== undefined) { + const arr = this.atoms.intern(`rest:${this.nodes.length}`, () => ({ + kind: "array", + label: `rest@${locLabel(p)}`, + node: p, + })); + this.add(this.binding(p), arr); + } + this.bindPattern(p.name, this.binding(p)); + } + const body = fn.body; + if (body !== undefined) { + if (ts.isBlock(body)) this.stmts(list(body.statements)); + else this.edge(this.expr(body as ts.Expression), info.ret); + } + this.currentFn = saved; + this.loopDepth = savedLoop; + this.ctx = savedCtx; + this.ctxRoot = savedRoot; + if (info.usesArguments) { + for (const p of info.params) this.add(p, this.top); + } + } + + /** The atom of a function node (memoized by its info). */ + fnAtom(node: Node, ownerClass: Node | null, ctx = ""): Atom { + const info = this.functionInfo(node, ownerClass, ctx); + return this.atoms.intern(`fn:${info.ret}`, () => ({ + kind: "function", + label: info.label, + node, + ctx: info.ctx, + })); + } + + ctxLabel(ctx: string): string { + if (ctx.startsWith("C")) return `this=${this.atoms.atoms[Number(ctx.slice(1))]?.label ?? ctx}`; + return ctx; + } + + className(decl: Node): string { + const own = (decl as ts.ClassLikeDeclaration).name?.text; + if (own !== undefined) return own; + const p = decl.parent; + if (p !== undefined && ts.isVariableDeclaration(p) && ts.isIdentifier(p.name)) + return p.name.text; + return ``; + } + + classAtoms(decl: Node): { cls: Atom; inst: Atom } { + const name = this.className(decl); + const cls = this.atoms.intern(`class:${this.nodeKey(decl)}`, () => ({ + kind: "class", + label: `class ${name}`, + node: decl, + })); + const inst = this.atoms.intern(`inst:${this.nodeKey(decl)}`, () => ({ + kind: "instance", + label: name, + node: decl, + })); + this.ensureClass(decl); + return { cls, inst }; + } + + private readonly nodeKeys = new Map(); + nodeKey(node: Node): number { + let k = this.nodeKeys.get(node); + if (k === undefined) { + k = this.nodeKeys.size; + this.nodeKeys.set(node, k); + } + return k; + } + + /** Registers a class: member functions, field initializers (as a pseudo + * function run at construction) and static initializers. */ + ensureClass(decl: Node): { initFn: FunctionInfo; staticInit: FunctionInfo } { + const existing = this.classInfo.get(decl); + if (existing !== undefined) return existing; + const c = decl as ts.ClassLikeDeclaration; + const label = this.className(decl); + const mk = (suffix: string): FunctionInfo => ({ + node: decl, + ctx: "", + root: null, + walked: true, + label: `${label}.${suffix}@${locLabel(decl)}`, + params: [], + rest: -1, + thisNode: this.newNode(), + ret: this.newNode(), + isArrow: false, + isAsync: false, + isGenerator: false, + usesArguments: false, + argPos: null, + ownerClass: decl, + inPackage: isPackageJsFile(decl.getSourceFile()), + }); + const entry = { initFn: mk(""), staticInit: mk("") }; + this.classInfo.set(decl, entry); + const cls = this.atoms.intern(`class:${this.nodeKey(decl)}`, () => ({ + kind: "class", + label: `class ${label}`, + node: decl, + })); + this.add(entry.staticInit.thisNode, cls); + const saved = this.currentFn; + for (const m of list(c.members)) { + const statics = isStatic(m); + if ( + ts.isMethodDeclaration(m) || + ts.isGetAccessorDeclaration(m) || + ts.isSetAccessorDeclaration(m) || + ts.isConstructorDeclaration(m) + ) { + continue; + } + if (ts.isPropertyDeclaration(m)) { + const name = propertyNameText(m.name); + const init = statics ? entry.staticInit : entry.initFn; + this.currentFn = init; + const value = + m.initializer !== undefined + ? this.exprIn(m.initializer, decl) + : this.constNode(this.prim("undefined")); + if (name !== null) this.storeConstraint(init.thisNode, name, value, m); + continue; + } + if (ts.isClassStaticBlockDeclaration(m)) { + this.currentFn = entry.staticInit; + this.stmts(list(m.body.statements)); + } + } + this.currentFn = saved; + return entry; + } + + /** An initializer expression: arrow functions in field initializers take + * the instance as `this` and belong to the class. */ + exprIn(e: ts.Expression, ownerClass: Node): number { + const u = unparen(e); + if (ts.isArrowFunction(u) || ts.isFunctionExpression(u)) { + const n = this.newNode(); + this.add(n, this.fnAtom(u, ts.isArrowFunction(u) ? null : ownerClass)); + return n; + } + return this.expr(e); + } + + /** `new C(args)` on a class atom: the instance, the field initializers of + * every class in the chain, and the constructor (or the implicit one). */ + construct( + decl: Node, + args: number[], + spread: boolean, + dst: number, + site: Node, + inst?: Atom, + ): void { + const atoms = this.classAtoms(decl); + const instance = inst ?? atoms.inst; + this.add(dst, instance); + this.callConstructorChain(decl, instance, args, spread, site); + } + + callConstructorChain( + decl: Node, + instance: Atom, + args: number[], + spread: boolean, + site: Node, + ): void { + const key = `ctor:${this.nodeKey(decl)}:${instance.id}:${this.nodeKey(site)}`; + if (this.boundCalls.has(key)) return; + this.boundCalls.add(key); + const entry = this.ensureClass(decl); + this.add(entry.initFn.thisNode, instance); + const ctor = list((decl as ts.ClassLikeDeclaration).members).find((m) => + ts.isConstructorDeclaration(m), + ); + if (ctor !== undefined) { + const info = this.functionInfo(ctor, decl, this.receiverCtx(instance)); + this.activate(info); + this.add(info.thisNode, instance); + this.bindArgs(info, args, spread); + this.edgeFor(site, info); + return; + } + const base = this.baseClass(decl); + if (base) this.callConstructorChain(base, instance, args, spread, site); + } + + bindArgs(info: FunctionInfo, args: number[], spread: boolean): void { + if (info.argPos !== null) { + for (let i = 0; i < info.argPos.length; i++) { + if (spread || i >= info.argPos.length - 1) { + for (const a of args.slice(i)) this.edge(a, info.argPos[i]!); + if (spread) this.add(info.argPos[i]!, this.top); + } else if (i < args.length) this.edge(args[i]!, info.argPos[i]!); + else this.add(info.argPos[i]!, this.prim("undefined")); + } + } + if (spread) { + for (const p of info.params) this.add(p, this.top); + for (const a of args) this.sink(a, `spread into ${info.label}`); + return; + } + for (let i = 0; i < info.params.length; i++) { + if (i === info.rest) { + const restAtoms = [...this.nodes[info.params[i]!]!.atoms]; + for (const ra of restAtoms) + for (let j = i; j < args.length; j++) this.edge(args[j]!, this.element(ra)); + break; + } + if (i < args.length) this.edge(args[i]!, info.params[i]!); + else this.add(info.params[i]!, this.prim("undefined")); + } + } + + /** Call of a function atom with a receiver node. */ + callFunction( + info: FunctionInfo, + thisNode: number | null, + args: number[], + spread: boolean, + dst: number, + site: Node, + ): void { + // `() => Object.create(null)` helpers: each call site gets its own + // dictionary, as if the helper were inlined. + if (this.isFactory(info.node)) { + const d = this.atoms.intern(`dict:${this.nodeKey(site)}`, () => ({ + kind: "dictionary", + label: `Object.create@${locLabel(site)}`, + node: site, + })); + this.add(dst, d); + return; + } + this.activate(info); + const fnNode = info.node; + const key = `call:${info.ctx}|${this.nodeKey(fnNode)}:${this.nodeKey(site)}:${thisNode ?? -1}:${dst}`; + if (this.boundCalls.has(key)) return; + this.boundCalls.add(key); + if (thisNode !== null && !info.isArrow) this.edge(thisNode, info.thisNode); + this.bindArgs(info, args, spread); + if (info.isAsync) { + const p = this.promiseAtom(fnNode, `async ${info.label}`); + this.awaitInto(info.ret, this.field(p, "value")); + this.add(dst, p); + } else if (info.isGenerator) { + this.add(dst, this.top); + } else this.edge(info.ret, dst); + this.edgeFor(site, info); + } + + private readonly factories = new Map(); + isFactory(node: Node): boolean { + let r = this.factories.get(node); + if (r === undefined) { + r = false; + const fn = node as ts.FunctionLikeDeclaration; + let e: Node | undefined = fn.body; + if (e !== undefined && ts.isBlock(e)) { + const st = e.statements.nodes; + e = st.length === 1 && ts.isReturnStatement(st[0]!) ? st[0]!.expression : undefined; + } + if (e !== undefined && !ts.isSourceFile(node)) { + const u = unparen(e as ts.Expression); + r = + ts.isCallExpression(u) && + u.expression.getText() === "Object.create" && + u.arguments.nodes.length === 1 && + u.arguments.nodes[0]!.kind === ts.SyntaxKind.NullKeyword; + } + this.factories.set(node, r); + } + return r; + } + + promiseAtom(site: Node, label: string): Atom { + return this.atoms.intern(`promise:${this.nodeKey(site)}`, () => ({ + kind: "promise", + label: `Promise@${label}`, + node: site, + })); + } + + /** dst ⊇ awaited(src). */ + awaitInto(src: number, dst: number): void { + this.on(src, (a) => { + if (a.kind === "promise") this.edge(this.field(a, "value"), dst); + else this.add(dst, a); + }); + } + + syntheticArray(site: Node, tag: string): Atom { + return this.atoms.intern(`arr:${tag}:${this.nodeKey(site)}`, () => ({ + kind: "array", + label: `${tag}[]@${locLabel(site)}`, + node: site, + })); + } + + // ---- statements ---------------------------------------------------------------- + + moduleBody(sf: ts.SourceFile): void { + const info: FunctionInfo = { + node: sf, + ctx: "", + root: null, + walked: true, + label: ``, + params: [], + rest: -1, + thisNode: this.constNode(this.prim("undefined")), + ret: this.newNode(), + isArrow: false, + isAsync: false, + isGenerator: false, + usesArguments: false, + argPos: null, + ownerClass: null, + inPackage: isPackageJsFile(sf), + }; + this.functions.set(`|${this.nodeKey(sf)}`, info); + this.currentFn = info; + this.stmts(list(sf.statements)); + this.currentFn = null; + } + + stmts(stmts: readonly Node[]): void { + for (const s of stmts) this.stmt(s); + } + + stmt(s: Node): void { + if (ts.isVariableStatement(s)) { + for (const d of list(s.declarationList.declarations)) this.varDecl(d); + return; + } + if (ts.isExpressionStatement(s)) { + this.expr(s.expression); + return; + } + if (ts.isReturnStatement(s)) { + if (s.expression !== undefined && this.currentFn !== null) + this.edge(this.expr(s.expression), this.currentFn.ret); + return; + } + if (ts.isFunctionDeclaration(s)) { + const b = this.binding(s); + const saved = this.currentFn; + this.currentFn = null; + this.add(b, this.fnAtom(s, null)); + this.currentFn = saved; + return; + } + if (ts.isClassDeclaration(s)) { + const b = this.binding(s); + this.add(b, this.classAtoms(s).cls); + return; + } + if (isLoop(s)) { + if (ts.isForOfStatement(s) || ts.isForInStatement(s)) { + const src = this.expr(s.expression); + const target = this.newNode(); + if (ts.isForInStatement(s)) this.add(target, this.prim("string")); + else this.iterateInto(src, target, s); + const init = s.initializer; + if (ts.isVariableDeclarationList(init)) { + for (const d of list(init.declarations)) { + this.edge(target, this.binding(d)); + this.bindPattern(d.name, this.binding(d)); + } + } else this.assignTo(init as ts.Expression, target); + } + this.loopDepth++; + if (ts.isForStatement(s)) { + if (s.initializer !== undefined) { + if (ts.isVariableDeclarationList(s.initializer)) + for (const d of list(s.initializer.declarations)) this.varDecl(d); + else this.expr(s.initializer as ts.Expression); + } + if (s.condition !== undefined) this.expr(s.condition); + if (s.incrementor !== undefined) this.expr(s.incrementor); + } + if (ts.isWhileStatement(s) || ts.isDoStatement(s)) this.expr(s.expression); + const body = (s as { statement?: Node }).statement; + if (body !== undefined) this.stmt(body); + this.loopDepth--; + return; + } + if (ts.isTryStatement(s)) { + this.stmts(list(s.tryBlock.statements)); + if (s.catchClause !== undefined) { + const v = s.catchClause.variableDeclaration; + if (v !== undefined) { + this.add(this.binding(v), this.top); + this.bindPattern(v.name, this.binding(v)); + } + this.stmts(list(s.catchClause.block.statements)); + } + if (s.finallyBlock !== undefined) this.stmts(list(s.finallyBlock.statements)); + return; + } + if (ts.isThrowStatement(s)) { + this.sink(this.expr(s.expression), `thrown at ${locLabel(s)}`); + return; + } + if ( + ts.isImportDeclaration(s) || + ts.isExportDeclaration(s) || + ts.isInterfaceDeclaration(s) || + ts.isTypeAliasDeclaration(s) + ) + return; + if (ts.isExportAssignment(s)) { + this.expr(s.expression); + return; + } + // Blocks, ifs, switches, labels: walk children, evaluating expressions. + ts.forEachChild(s, (child) => { + if (ts.isExpression(child)) this.expr(child); + else this.stmt(child); + return undefined; + }); + } + + varDecl(d: ts.VariableDeclaration): void { + const b = this.binding(d); + if (d.initializer !== undefined) this.edge(this.expr(d.initializer), b); + this.bindPattern(d.name, b); + } + + /** Destructuring: binding elements read from the source node. */ + bindPattern(name: Node, src: number): void { + if (ts.isIdentifier(name)) return; + if (ts.isObjectBindingPattern(name)) { + for (const el of list(name.elements)) { + const b = this.binding(el); + if (el.dotDotDotToken !== undefined) { + this.add(b, this.top); + continue; + } + const keyNode = el.propertyName ?? el.name; + const key = keyNode !== undefined ? propertyNameText(keyNode) : null; + if (key !== null) this.loadConstraint(src, key, b, el); + else this.add(b, this.top); + if (el.initializer !== undefined) this.edge(this.expr(el.initializer), b); + if (el.name !== undefined) this.bindPattern(el.name, b); + } + return; + } + if (ts.isArrayBindingPattern(name)) { + let i = 0; + for (const el of list(name.elements)) { + if (ts.isBindingElement(el)) { + const b = this.binding(el); + if (el.dotDotDotToken !== undefined) this.add(b, this.top); + else this.iterateInto(src, b, el, i); + if (el.initializer !== undefined) this.edge(this.expr(el.initializer), b); + if (el.name !== undefined) this.bindPattern(el.name, b); + } + i++; + } + } + } + + /** Element values of an iterable. */ + iterateInto(src: number, dst: number, site: Node, _index?: number): void { + this.on(src, (a) => { + if (a.kind === "array" || a.kind === "collection") this.edge(this.element(a), dst); + else if (a.kind === "prim" && a.label === "string") this.add(dst, this.prim("string")); + else if (a.kind === "prim" || a.kind === "object" || a.kind === "dictionary") { + /* not iterable (a TypeError): no value. Literals with a + Symbol.iterator member have a computed key; they are G sites. */ + } else { + this.add(dst, this.top); + if (a.kind !== "top") this.escape(a, `iterated at ${locLabel(site)}`); + } + }); + } + + // ---- expressions --------------------------------------------------------------- + + expr(e: ts.Expression): number { + const key = this.ctxKey(e); + const memo = this.exprMemo.get(key); + if (memo !== undefined) return memo; + const id = this.exprUncached(e); + this.exprMemo.set(key, id); + if (this.traceTop && !this.nodeLabel.has(id)) + this.nodeLabel.set( + id, + `expr ${e.getText().slice(0, 40).replace(/\s+/g, " ")}@${locLabel(e)}`, + ); + return id; + } + + private exprUncached(e: ts.Expression): number { + const u = unparen(e); + if (u !== e) return this.expr(u); + switch (e.kind) { + case ts.SyntaxKind.StringLiteral: + case ts.SyntaxKind.NoSubstitutionTemplateLiteral: + case ts.SyntaxKind.TemplateExpression: + if (ts.isTemplateExpression(e)) + for (const span of list(e.templateSpans)) this.expr(span.expression); + return this.constNode(this.prim("string")); + case ts.SyntaxKind.NumericLiteral: + return this.constNode(this.prim("number")); + case ts.SyntaxKind.BigIntLiteral: + return this.constNode(this.prim("bigint")); + case ts.SyntaxKind.TrueKeyword: + case ts.SyntaxKind.FalseKeyword: + return this.constNode(this.prim("boolean")); + case ts.SyntaxKind.NullKeyword: + return this.constNode(this.prim("null")); + case ts.SyntaxKind.RegularExpressionLiteral: + return this.constNode(this.builtin("RegExp.instance")); + case ts.SyntaxKind.ThisKeyword: + return this.currentFn !== null + ? this.currentFn.thisNode + : this.constNode(this.prim("undefined")); + case ts.SyntaxKind.SuperKeyword: + return this.constNode(this.top); + } + if (ts.isIdentifier(e)) return this.identifier(e); + if (ts.isObjectLiteralExpression(e)) return this.objectLiteral(e); + if (ts.isArrayLiteralExpression(e)) return this.arrayLiteral(e); + if (ts.isArrowFunction(e) || ts.isFunctionExpression(e)) { + const n = this.newNode(); + this.add(n, this.fnAtom(e, null)); + if (ts.isFunctionExpression(e) && e.name !== undefined) + this.add(this.binding(e), this.fnAtom(e, null)); + return n; + } + if (ts.isClassExpression(e)) { + const n = this.newNode(); + this.add(n, this.classAtoms(e).cls); + return n; + } + if (ts.isPropertyAccessExpression(e)) { + this.noteSite(e); + const recv = this.expr(e.expression); + const name = e.name.text; + const dst = this.newNode(); + this.loadConstraint(recv, name, dst, e); + this.ops.push({ kind: "read", recv, name, node: e }); + return dst; + } + if (ts.isElementAccessExpression(e)) { + const recv = this.expr(e.expression); + const key = unparen(e.argumentExpression); + const dst = this.newNode(); + const name = + ts.isStringLiteral(key) || ts.isNoSubstitutionTemplateLiteral(key) ? key.text : null; + if (name !== null) { + this.loadConstraint(recv, name, dst, e); + this.ops.push({ kind: "read", recv, name, node: e }); + } else { + this.expr(e.argumentExpression); + this.computedLoad(recv, dst, e); + this.ops.push({ kind: "computedRead", recv, name: null, node: e }); + } + return dst; + } + if (ts.isCallExpression(e)) return this.call(e); + if (ts.isNewExpression(e)) return this.newExpr(e); + if (ts.isBinaryExpression(e)) return this.binary(e); + if (ts.isConditionalExpression(e)) { + this.expr(e.condition); + const n = this.newNode(); + this.edge(this.expr(e.whenTrue), n); + this.edge(this.expr(e.whenFalse), n); + return n; + } + if (ts.isAwaitExpression(e)) { + const n = this.newNode(); + this.awaitInto(this.expr(e.expression), n); + return n; + } + if (ts.isTypeOfExpression(e)) { + this.expr(e.expression); + return this.constNode(this.prim("string")); + } + if (ts.isVoidExpression(e)) { + this.expr(e.expression); + return this.constNode(this.prim("undefined")); + } + if (ts.isDeleteExpression(e)) { + const target = unparen(e.expression); + if (ts.isPropertyAccessExpression(target) || ts.isElementAccessExpression(target)) { + const recv = this.expr(target.expression); + const name = ts.isPropertyAccessExpression(target) ? target.name.text : null; + this.ops.push({ kind: "delete", recv, name, node: e }); + } + return this.constNode(this.prim("boolean")); + } + if (ts.isPrefixUnaryExpression(e) || ts.isPostfixUnaryExpression(e)) { + const operand = e.operand; + this.expr(operand); + if ( + e.operator === ts.SyntaxKind.PlusPlusToken || + e.operator === ts.SyntaxKind.MinusMinusToken + ) + this.assignTo(operand, this.constNode(this.prim("number"))); + if (ts.isPrefixUnaryExpression(e) && e.operator === ts.SyntaxKind.ExclamationToken) + return this.constNode(this.prim("boolean")); + return this.constNode(this.prim("number")); + } + if (ts.isSpreadElement(e)) return this.expr(e.expression); + if (ts.isTaggedTemplateExpression(e)) { + this.expr(e.tag); + return this.constNode(this.top); + } + if (ts.isYieldExpression(e)) { + if (e.expression !== undefined) + this.sink(this.expr(e.expression), `yielded at ${locLabel(e)}`); + return this.constNode(this.top); + } + if (ts.isMetaProperty(e)) return this.constNode(this.top); + // Anything else: evaluate children, answer ⊤. + ts.forEachChild(e, (child) => { + if (ts.isExpression(child)) this.expr(child); + return undefined; + }); + return this.constNode(this.top); + } + + identifier(id: ts.Identifier): number { + if (id.text === "undefined") return this.constNode(this.prim("undefined")); + if (id.text === "arguments") { + const fn = this.enclosingNonArrow(); + if (fn !== null) { + const parent = id.parent; + const forwarding = parent !== undefined && ts.isSpreadElement(parent); + if (!forwarding) fn.usesArguments = true; + const arr = this.syntheticArray(id, "arguments"); + for (const p of fn.params) this.edge(p, this.element(arr)); + return this.constNode(arr); + } + } + const decl = this.resolve(id); + if (decl === undefined) return this.globalNode(id.text); + if (decl.getSourceFile().isDeclarationFile) return this.globalNode(id.text); + if (!this.files.includes(decl.getSourceFile())) return this.constNode(this.top); + if (ts.isFunctionDeclaration(decl)) { + const b = this.binding(decl); + const saved = this.currentFn; + this.currentFn = null; + this.add(b, this.fnAtom(decl, null)); + this.currentFn = saved; + return b; + } + if (ts.isClassDeclaration(decl) || ts.isClassExpression(decl)) { + const b = this.binding(decl); + this.add(b, this.classAtoms(decl).cls); + return b; + } + if (ts.isFunctionExpression(decl)) return this.binding(decl); + if ( + ts.isImportSpecifier(decl) || + ts.isImportClause(decl) || + ts.isNamespaceImport(decl) || + ts.isImportEqualsDeclaration(decl) + ) + return this.constNode(this.top); + if (ts.isSourceFile(decl) || ts.isModuleDeclaration(decl)) return this.namespaceNode(decl); + return this.narrowed(id, decl, this.binding(decl)); + } + + /** Flow narrowing at guarded references (S1 handles the guards hot code + * uses: `x instanceof C` and calls of predicate functions whose body is + * `… && x instanceof C`, in the true arm of an `if`, `?:` or `&&`). The + * narrowed value keeps the guard's class arms and ⊤. */ + narrowed(id: ts.Identifier, decl: Node, value: number): number { + let child: Node = id; + let p = id.parent; + while (p !== undefined && !ts.isFunctionLike(p) && !ts.isSourceFile(p)) { + let cond: ts.Expression | undefined; + if (ts.isIfStatement(p) && p.thenStatement === child) cond = p.expression; + else if (ts.isConditionalExpression(p) && p.whenTrue === child) cond = p.condition; + else if ( + ts.isBinaryExpression(p) && + p.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken && + p.right === child + ) + cond = p.left; + if (cond !== undefined) { + const cls = this.guardClass(cond, decl); + if (cls !== null) { + const out = this.newNode(); + this.on(value, (a) => { + if (a.kind === "top") this.add(out, a); + else if ( + cls === "Promise" + ? a.kind === "promise" + : a.kind === "instance" && + a.node !== undefined && + this.classChain(a.node).includes(cls) + ) + this.add(out, a); + }); + return out; + } + } + child = p; + p = p.parent; + } + return value; + } + + /** The class a condition proves `decl`'s value an instance of, if any. */ + guardClass(cond: ts.Expression, decl: Node): Node | "Promise" | null { + const e = unparen(cond); + if (ts.isBinaryExpression(e)) { + if (e.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) + return this.guardClass(e.left, decl) ?? this.guardClass(e.right, decl); + if (e.operatorToken.kind !== ts.SyntaxKind.InstanceOfKeyword) return null; + const l = unparen(e.left); + if (!ts.isIdentifier(l) || this.resolve(l) !== decl) return null; + return this.instanceofTarget(e.right); + } + if ( + ts.isCallExpression(e) && + ts.isIdentifier(unparen(e.expression)) && + e.arguments.nodes.length === 1 + ) { + const arg = unparen(e.arguments.nodes[0]!); + if (!ts.isIdentifier(arg) || this.resolve(arg) !== decl) return null; + const fnDecl = this.resolve(unparen(e.expression)); + let fn: Node | undefined = fnDecl; + if (fn !== undefined && ts.isVariableDeclaration(fn) && fn.initializer !== undefined) + fn = unparen(fn.initializer); + if ( + fn === undefined || + !(ts.isArrowFunction(fn) || ts.isFunctionDeclaration(fn) || ts.isFunctionExpression(fn)) + ) + return null; + const param = fn.parameters.nodes[0]; + if (param === undefined || !ts.isIdentifier(param.name)) return null; + let body: Node | undefined = fn.body; + if (body !== undefined && ts.isBlock(body)) { + const stmts = body.statements.nodes; + body = + stmts.length === 1 && ts.isReturnStatement(stmts[0]!) ? stmts[0]!.expression : undefined; + } + if (body === undefined) return null; + return this.predicateClass(body as ts.Expression, param); + } + return null; + } + + /** `… && p instanceof C` in a predicate body over parameter `p`. */ + predicateClass(e: ts.Expression, param: Node): Node | "Promise" | null { + const u = unparen(e); + if (!ts.isBinaryExpression(u)) return null; + if (u.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) + return this.predicateClass(u.right, param) ?? this.predicateClass(u.left, param); + if (u.operatorToken.kind !== ts.SyntaxKind.InstanceOfKeyword) return null; + const l = unparen(u.left); + if (!ts.isIdentifier(l) || this.resolve(l) !== param) return null; + return this.instanceofTarget(u.right); + } + + instanceofTarget(right: ts.Expression): Node | "Promise" | null { + const r = unparen(right); + if (!ts.isIdentifier(r)) return null; + const d = this.resolve(r); + if (d === undefined || d.getSourceFile().isDeclarationFile) + return r.text === "Promise" ? "Promise" : null; + return ts.isClassLikeDeclaration(d) ? d : null; + } + + private readonly namespaces = new Map(); + /** `import * as ns`: an object whose fields are the module's exports. */ + namespaceNode(mod: Node): number { + const existing = this.namespaces.get(mod); + if (existing !== undefined) return existing; + const n = this.newNode(); + this.namespaces.set(mod, n); + const atom = this.atoms.intern(`ns:${this.nodeKey(mod)}`, () => ({ + kind: "object", + label: `namespace ${shortFile((mod as ts.SourceFile).fileName ?? "")}`, + node: mod, + })); + this.add(n, atom); + const sym = this.checker.getSymbolAtLocation(mod); + if (sym !== undefined) { + for (const ex of this.checker.getExportsOfModule(sym)) { + let target = ex; + if (target.flags & ts.SymbolFlags.Alias) { + try { + target = this.checker.getAliasedSymbol(target); + } catch { + continue; + } + } + const d = target.valueDeclaration ?? target.declarations[0]; + if (d === undefined) continue; + const value = this.declValue(d); + if (value !== null) this.edge(value, this.field(atom, String(ex.escapedName))); + } + } + return n; + } + + declValue(d: Node): number | null { + if (d.getSourceFile().isDeclarationFile || !this.files.includes(d.getSourceFile())) return null; + if (ts.isFunctionDeclaration(d)) { + const b = this.binding(d); + const saved = this.currentFn; + this.currentFn = null; + this.add(b, this.fnAtom(d, null)); + this.currentFn = saved; + return b; + } + if (ts.isClassDeclaration(d)) { + const b = this.binding(d); + this.add(b, this.classAtoms(d).cls); + return b; + } + if (ts.isVariableDeclaration(d) || ts.isBindingElement(d) || ts.isParameter(d)) + return this.binding(d); + if (ts.isSourceFile(d)) return this.namespaceNode(d); + return null; + } + + globalNode(name: string): number { + if (MODELED_GLOBALS.has(name)) return this.constNode(this.builtin(name)); + if (name === "NaN" || name === "Infinity") return this.constNode(this.prim("number")); + return this.constNode(this.top); + } + + enclosingNonArrow(): FunctionInfo | null { + const fn = this.currentFn; + if (fn === null) return null; + if (!fn.isArrow) return fn; + // An arrow's `arguments` is its enclosing function's. + let p: Node | undefined = fn.node.parent; + while (p !== undefined) { + if (ts.isFunctionLike(p) && !ts.isArrowFunction(p)) + return ( + this.functions.get(this.ctxKey(p)) ?? this.functions.get(`|${this.nodeKey(p)}`) ?? null + ); + p = p.parent; + } + return null; + } + + objectLiteral(e: ts.ObjectLiteralExpression): number { + const keys: string[] = []; + let keysKnown = true; + let hasAccessor = false; + let hasProto = false; + let hasComputedKey = false; + const spreads: number[] = []; + const inPackage = isPackageJsFile(e.getSourceFile()); + const label = (): string => + `{${keys.slice(0, 6).join(",")}${keys.length > 6 ? ",…" : ""}${keysKnown ? "" : ",…"}}@${locLabel(e)}`; + // keys first, so the label is complete + for (const p of list(e.properties)) { + if (ts.isSpreadAssignment(p)) { + keysKnown = false; + continue; + } + const name = (p as { name?: Node }).name; + const key = name !== undefined ? propertyNameText(name) : null; + if (key === null) { + hasComputedKey = true; + keysKnown = false; + continue; + } + if (key === "__proto__" && ts.isPropertyAssignment(p) && !ts.isComputedPropertyName(p.name)) + hasProto = true; + if (!keys.includes(key)) keys.push(key); + } + const atom = this.atoms.intern(`obj:${this.nodeKey(e)}`, () => ({ + kind: "object", + label: label(), + node: e, + })); + const n = this.newNode(); + this.add(n, atom); + for (const p of list(e.properties)) { + if (ts.isSpreadAssignment(p)) { + const src = this.expr(p.expression); + spreads.push(src); + this.copyFields(src, atom, p); + continue; + } + if (ts.isGetAccessorDeclaration(p) || ts.isSetAccessorDeclaration(p)) { + hasAccessor = true; + const info = this.functionInfo(p, null); + this.activate(info); + this.add(info.thisNode, atom); + const key = propertyNameText(p.name); + if (key !== null && ts.isGetAccessorDeclaration(p)) + this.edge(info.ret, this.field(atom, key)); + continue; + } + const name = (p as { name?: Node }).name; + const key = name !== undefined ? propertyNameText(name) : null; + if (name !== undefined && ts.isComputedPropertyName(name)) this.expr(name.expression); + let value: number; + if (ts.isPropertyAssignment(p)) value = this.expr(p.initializer); + else if (ts.isShorthandPropertyAssignment(p)) { + const sym = this.checker.getShorthandAssignmentValueSymbol(p); + const d = sym?.valueDeclaration ?? sym?.declarations[0]; + const id = p.name as ts.Identifier; + value = d !== undefined ? (this.declValue(d) ?? this.identifier(id)) : this.identifier(id); + } else if (ts.isMethodDeclaration(p)) { + const fa = this.fnAtom(p, null); + this.add(this.infoOfAtom(fa)!.thisNode, atom); + value = this.constNode(fa); + } else continue; + if (key !== null) this.edge(value, this.field(atom, key)); + else this.edge(value, this.anyField(atom)); + } + if (!this.siteAtoms.has(atom) && this.siteAtoms.add(atom)) + this.sites.push({ + atom, + node: e, + kind: "object", + keys: keysKnown ? keys : null, + hasAccessor, + hasProto, + hasComputedKey, + spreads, + inPackage, + }); + return n; + } + + /** Values written under unknown keys. */ + anyField(atom: Atom): number { + return this.field(atom, "*"); + } + + copyFields(src: number, dstAtom: Atom, site: Node): void { + this.on(src, (a) => { + if (a.kind === "top") { + this.edge(this.constNode(this.top), this.anyField(dstAtom)); + return; + } + if (a.kind === "prim" || a.kind === "builtin") return; + if (a.kind === "array") { + this.edge(this.element(a), this.anyField(dstAtom)); + return; + } + // Copy every own field the source has, now and later. + const fm = this.fields.get(a); + const copied = new Set(); + const copy = (): void => { + for (const [name, id] of this.fields.get(a) ?? new Map()) { + if (copied.has(name)) continue; + copied.add(name); + this.edge(id, this.field(dstAtom, name)); + } + }; + copy(); + if (fm === undefined) this.fields.set(a, new Map()); + this.lateCopies.push(copy); + if (a.kind === "instance" || a.kind === "dictionary" || a.kind === "collection") + this.edge(this.constNode(this.top), this.anyField(dstAtom)); + void site; + }); + } + + /** Field copies re-run after solving rounds (fields created later). */ + private readonly lateCopies: (() => void)[] = []; + + arrayLiteral(e: ts.ArrayLiteralExpression): number { + const atom = this.atoms.intern(`arr:${this.nodeKey(e)}`, () => ({ + kind: "array", + label: `[]@${locLabel(e)}`, + node: e, + })); + const n = this.newNode(); + this.add(n, atom); + const el = this.element(atom); + let hasHole = false; + for (const item of list(e.elements)) { + if (ts.isOmittedExpression(item)) { + hasHole = true; + continue; + } + if (ts.isSpreadElement(item)) this.iterateInto(this.expr(item.expression), el, item); + else this.edge(this.expr(item), el); + } + if (!this.siteAtoms.has(atom) && this.siteAtoms.add(atom)) + this.sites.push({ + atom, + node: e, + kind: "array", + keys: null, + hasAccessor: false, + hasProto: hasHole, + hasComputedKey: false, + spreads: [], + inPackage: isPackageJsFile(e.getSourceFile()), + }); + return n; + } + + binary(e: ts.BinaryExpression): number { + const op = e.operatorToken.kind; + if (op === ts.SyntaxKind.EqualsToken) { + const value = this.expr(e.right); + this.assignTo(e.left, value); + return value; + } + if ( + op === ts.SyntaxKind.BarBarEqualsToken || + op === ts.SyntaxKind.QuestionQuestionEqualsToken || + op === ts.SyntaxKind.AmpersandAmpersandEqualsToken + ) { + const n = this.newNode(); + this.edge(this.expr(e.left), n); + const value = this.expr(e.right); + this.edge(value, n); + this.assignTo(e.left, value); + return n; + } + if (op >= ts.SyntaxKind.FirstCompoundAssignment && op <= ts.SyntaxKind.LastCompoundAssignment) { + this.expr(e.left); + this.expr(e.right); + const result = this.constNode( + op === ts.SyntaxKind.PlusEqualsToken ? this.top : this.prim("number"), + ); + if (op === ts.SyntaxKind.PlusEqualsToken) { + this.nodes[result]!.atoms.clear(); + this.add(result, this.prim("string")); + this.add(result, this.prim("number")); + } + this.assignTo(e.left, result); + return result; + } + if ( + op === ts.SyntaxKind.BarBarToken || + op === ts.SyntaxKind.QuestionQuestionToken || + op === ts.SyntaxKind.AmpersandAmpersandToken + ) { + const n = this.newNode(); + this.edge(this.expr(e.left), n); + this.edge(this.expr(e.right), n); + return n; + } + if (op === ts.SyntaxKind.CommaToken) { + this.expr(e.left); + return this.expr(e.right); + } + const l = this.expr(e.left); + const r = this.expr(e.right); + switch (op) { + case ts.SyntaxKind.EqualsEqualsEqualsToken: + case ts.SyntaxKind.ExclamationEqualsEqualsToken: + case ts.SyntaxKind.EqualsEqualsToken: + case ts.SyntaxKind.ExclamationEqualsToken: + case ts.SyntaxKind.LessThanToken: + case ts.SyntaxKind.LessThanEqualsToken: + case ts.SyntaxKind.GreaterThanToken: + case ts.SyntaxKind.GreaterThanEqualsToken: + case ts.SyntaxKind.InstanceOfKeyword: + case ts.SyntaxKind.InKeyword: + if (op === ts.SyntaxKind.InKeyword) + this.ops.push({ kind: "computedRead", recv: r, name: null, node: e }); + return this.constNode(this.prim("boolean")); + case ts.SyntaxKind.PlusToken: { + const n = this.newNode(); + const strOrNum = (a: Atom): void => { + this.add( + n, + a.kind === "prim" && a.label === "number" ? this.prim("number") : this.prim("string"), + ); + if ( + a.kind === "prim" && + (a.label === "boolean" || a.label === "null" || a.label === "undefined") + ) + this.add(n, this.prim("number")); + if (a.kind === "top") this.add(n, this.prim("number")); + }; + this.on(l, strOrNum); + this.on(r, strOrNum); + return n; + } + default: + return this.constNode(this.prim("number")); + } + } + + assignTo(target: ts.Expression, value: number): void { + const t = unparen(target); + if (ts.isIdentifier(t)) { + const decl = this.resolve(t); + if (decl === undefined || decl.getSourceFile().isDeclarationFile) { + this.sink(value, `global write at ${locLabel(t)}`); + return; + } + this.edge(value, this.binding(decl)); + return; + } + if (ts.isPropertyAccessExpression(t)) { + const recv = this.expr(t.expression); + this.storeConstraint(recv, t.name.text, value, t); + this.ops.push({ + kind: t.name.text === "length" ? "lengthWrite" : "write", + recv, + name: t.name.text, + node: t, + }); + return; + } + if (ts.isElementAccessExpression(t)) { + const recv = this.expr(t.expression); + const key = unparen(t.argumentExpression); + if (ts.isStringLiteral(key) || ts.isNoSubstitutionTemplateLiteral(key)) { + this.storeConstraint(recv, key.text, value, t); + this.ops.push({ kind: "write", recv, name: key.text, node: t }); + } else { + this.expr(t.argumentExpression); + this.computedStore(recv, value, t); + this.ops.push({ kind: "computedWrite", recv, name: null, node: t }); + } + return; + } + if (ts.isObjectLiteralExpression(t)) { + for (const p of list(t.properties)) { + if (ts.isPropertyAssignment(p)) { + const key = propertyNameText(p.name); + const n = this.newNode(); + if (key !== null) this.loadConstraint(value, key, n, p); + else this.add(n, this.top); + this.assignTo(p.initializer, n); + } else if (ts.isShorthandPropertyAssignment(p)) { + const n = this.newNode(); + const id = p.name as ts.Identifier; + this.loadConstraint(value, id.text, n, p); + this.assignTo(id, n); + } + } + return; + } + if (ts.isArrayLiteralExpression(t)) { + for (const el of list(t.elements)) { + if (ts.isOmittedExpression(el)) continue; + const n = this.newNode(); + this.iterateInto(value, n, el); + this.assignTo(ts.isSpreadElement(el) ? el.expression : el, n); + } + } + } + + // ---- loads and stores ------------------------------------------------------------ + + loadConstraint(recv: number, name: string, dst: number, site: Node): void { + this.on(recv, (a) => this.loadAtom(a, name, dst, site)); + } + + loadAtom(a: Atom, name: string, dst: number, site: Node): void { + switch (a.kind) { + case "top": + this.add(dst, this.top); + return; + case "prim": + if (name === "length" && a.label === "string") this.add(dst, this.prim("number")); + else if (a.label === "string" || a.label === "number" || a.label === "boolean") + this.add(dst, this.builtin(`${a.label}.${name}`, a)); + return; + case "instance": { + const decl = a.node!; + if (name === "constructor") { + this.add(dst, this.classAtoms(decl).cls); + return; + } + const member = this.lookupMember(decl, name, false); + if (member?.kind === "method") + this.add( + dst, + this.fnAtom(member.method!, this.ownerOf(member.method!), this.receiverCtx(a)), + ); + if (member !== null && member.get !== undefined) { + const g = this.functionInfo(member.get, this.ownerOf(member.get), this.receiverCtx(a)); + this.activate(g); + this.add(g.thisNode, a); + this.edge(g.ret, dst); + this.edgeFor(site, g); + return; + } + if (this.classChain(decl).some((c) => this.baseClass(c) === undefined)) + this.add(dst, this.top); + this.edge(this.field(a, name), dst); + return; + } + case "class": { + const decl = a.node!; + if (name === "prototype") { + this.add(dst, this.top); + return; + } + if (name === "name") { + this.add(dst, this.prim("string")); + return; + } + const member = this.lookupMember(decl, name, true); + if (member?.kind === "method") + this.add( + dst, + this.fnAtom(member.method!, this.ownerOf(member.method!), this.receiverCtx(a)), + ); + if (member?.get !== undefined) { + const g = this.functionInfo(member.get, this.ownerOf(member.get), this.receiverCtx(a)); + this.activate(g); + this.add(g.thisNode, a); + this.edge(g.ret, dst); + return; + } + // static fields of the class and its bases + for (const c of this.classChain(decl)) { + const cls = this.classAtoms(c).cls; + this.edge(this.field(cls, name), dst); + } + return; + } + case "function": + if (name === "call" || name === "apply" || name === "bind") + this.add(dst, this.builtin(`function.${name}`, a)); + else if (name === "prototype") this.add(dst, this.top); + else if (name === "name") this.add(dst, this.prim("string")); + else if (name === "length") this.add(dst, this.prim("number")); + else this.edge(this.field(a, name), dst); + return; + case "array": + if (name === "length") this.add(dst, this.prim("number")); + else if (/^\d+$/.test(name)) this.edge(this.element(a), dst); + else if (ARRAY_METHODS.has(name)) this.add(dst, this.builtin(`array.${name}`, a)); + else this.edge(this.field(a, name), dst); + return; + case "object": + this.edge(this.field(a, name), dst); + this.edge(this.anyField(a), dst); + if (name === "constructor" || name === "hasOwnProperty" || name === "toString") + this.add(dst, this.builtin(`object.${name}`, a)); + return; + case "dictionary": + this.edge(this.anyField(a), dst); + this.edge(this.field(a, name), dst); + return; + case "promise": + if (name === "then" || name === "catch" || name === "finally") + this.add(dst, this.builtin(`promise.${name}`, a)); + return; + case "collection": + if (name === "size") this.add(dst, this.prim("number")); + else this.add(dst, this.builtin(`collection.${name}`, a)); + return; + case "builtin": + this.loadBuiltin(a, name, dst); + return; + } + void site; + } + + ownerOf(member: Node): Node | null { + const p = member.parent; + return p !== undefined && ts.isClassLikeDeclaration(p) ? p : null; + } + + loadBuiltin(a: Atom, name: string, dst: number): void { + const path = a.path ?? ""; + if ( + path === "Number" && + (name === "MAX_SAFE_INTEGER" || + name === "MIN_SAFE_INTEGER" || + name === "EPSILON" || + name === "MAX_VALUE" || + name === "MIN_VALUE" || + name === "POSITIVE_INFINITY" || + name === "NEGATIVE_INFINITY" || + name === "NaN") + ) + this.add(dst, this.prim("number")); + else if (path === "Math" && /^[A-Z0-9_]+$/.test(name)) this.add(dst, this.prim("number")); + else if (path === "Symbol") this.add(dst, this.prim("symbol")); + else if (path === "Error.instance" || path === "error") { + if (name === "message" || name === "stack" || name === "name") + this.add(dst, this.prim("string")); + else this.add(dst, this.top); + } else if ( + a.receiver === undefined && + MODELED_GLOBALS.has(path.split(".")[0]!) && + path.split(".").length < 4 + ) + this.add(dst, this.builtin(`${path}.${name}`)); + else if (path === "RegExp.instance") this.add(dst, this.builtin(`regexp.${name}`, a)); + else this.add(dst, this.top); + } + + storeConstraint(recv: number, name: string, value: number, site: Node): void { + this.on(recv, (a) => { + switch (a.kind) { + case "top": + this.noteTopWrite(name, site); + this.sink(value, `stored into ⊤.${name} at ${locLabel(site)}`); + return; + case "instance": { + const member = this.lookupMember(a.node!, name, false); + if (member?.set !== undefined) { + const s = this.functionInfo(member.set, this.ownerOf(member.set), this.receiverCtx(a)); + this.activate(s); + this.add(s.thisNode, a); + if (s.params[0] !== undefined) this.edge(value, s.params[0]); + return; + } + this.edge(value, this.field(a, name)); + return; + } + case "class": + case "function": + case "object": + case "dictionary": + this.edge(value, this.field(a, name)); + return; + case "array": + if (/^\d+$/.test(name)) this.edge(value, this.element(a)); + return; + case "prim": + return; + default: + this.sink(value, `stored into ${a.label} at ${locLabel(site)}`); + } + }); + } + + computedLoad(recv: number, dst: number, site: Node): void { + this.on(recv, (a) => { + switch (a.kind) { + case "top": + this.add(dst, this.top); + return; + case "array": + case "collection": + this.edge(this.element(a), dst); + return; + case "prim": + if (a.label === "string") this.add(dst, this.prim("string")); + return; + case "object": + case "dictionary": + case "instance": + case "class": + case "function": { + // every field, now and later + const seen = new Set(); + const copy = (): void => { + for (const [name, id] of this.fields.get(a) ?? new Map()) { + if (seen.has(name)) continue; + seen.add(name); + this.edge(id, dst); + } + }; + copy(); + this.lateCopies.push(copy); + if (a.kind === "instance" || a.kind === "class") this.add(dst, this.top); + return; + } + default: + this.add(dst, this.top); + } + void site; + }); + } + + computedStore(recv: number, value: number, site: Node): void { + this.on(recv, (a) => { + switch (a.kind) { + case "top": + this.noteTopWrite(null, site); + this.sink(value, `stored into ⊤[k] at ${locLabel(site)}`); + return; + case "array": + this.edge(value, this.element(a)); + return; + case "prim": + return; + default: + this.edge(value, this.anyField(a)); + } + }); + } + + // ---- calls --------------------------------------------------------------------------- + + args(e: ts.CallExpression | ts.NewExpression): { args: number[]; spread: boolean } { + const out: number[] = []; + let spread = false; + for (const a of list(e.arguments)) { + if (ts.isSpreadElement(a)) { + const inner = unparen(a.expression); + if (ts.isIdentifier(inner) && inner.text === "arguments") { + // `f(...arguments)`: forward the enclosing function's parameters. + const fn = this.enclosingNonArrow(); + if (fn !== null && out.length === 0) { + if (fn.argPos === null) fn.argPos = [0, 1, 2, 3, 4, 5].map(() => this.newNode()); + out.push(...fn.argPos); + continue; + } + } + spread = true; + out.push(this.expr(a.expression)); + continue; + } + out.push(this.expr(a)); + } + return { args: out, spread }; + } + + call(e: ts.CallExpression): number { + this.noteSite(e); + const callee = unparen(e.expression); + const dst = this.newNode(); + if (callee.kind === ts.SyntaxKind.SuperKeyword) { + const { args, spread } = this.args(e); + const fn = this.enclosingNonArrow(); + const owner = fn?.ownerClass ?? null; + const base = owner !== null ? this.baseClass(owner) : undefined; + if (fn !== null && base) { + this.on(fn.thisNode, (inst) => { + if (inst.kind === "instance") this.callConstructorChain(base, inst, args, spread, e); + }); + } else if (base === undefined) + for (const a of args) this.sink(a, `super(...) at ${locLabel(e)}`); + return dst; + } + if (ts.isPropertyAccessExpression(callee) || ts.isElementAccessExpression(callee)) { + const recvExpr = unparen(callee.expression); + const { args, spread } = this.args(e); + if (recvExpr.kind === ts.SyntaxKind.SuperKeyword && ts.isPropertyAccessExpression(callee)) { + // super.m(...): the base class member with the current receiver. + const fn = this.enclosingNonArrow(); + const owner = fn?.ownerClass ?? null; + const base = owner !== null ? this.baseClass(owner) : undefined; + if (fn !== null && base) { + const member = this.lookupMember(base, callee.name.text, isStatic(fn.node)); + if (member?.method !== undefined) { + this.callFunction( + this.functionInfo(member.method, this.ownerOf(member.method), fn.ctx), + fn.thisNode, + args, + spread, + dst, + e, + ); + } + } + return dst; + } + const recv = this.expr(recvExpr); + let name: string | null = null; + if (ts.isPropertyAccessExpression(callee)) name = callee.name.text; + else { + const k = unparen(callee.argumentExpression); + if (ts.isStringLiteral(k) || ts.isNoSubstitutionTemplateLiteral(k)) name = k.text; + else this.expr(callee.argumentExpression); + } + if (name !== null) this.ops.push({ kind: "read", recv, name, node: callee }); + // Per receiver atom: the member it resolves to runs with that atom as `this`. + const member = name; + this.on(recv, (a) => { + const fnNode = this.newNode(); + const self = this.constNode(a); + if (member !== null) this.loadAtom(a, member, fnNode, callee); + else this.computedLoad(self, fnNode, callee); + this.invoke(fnNode, self, args, spread, dst, e); + }); + return dst; + } + const calleeNode = this.expr(callee); + const { args, spread } = this.args(e); + this.invoke(calleeNode, null, args, spread, dst, e); + return dst; + } + + invoke( + callee: number, + recv: number | null, + args: number[], + spread: boolean, + dst: number, + site: ts.CallExpression, + ): void { + const undefNode = recv === null ? this.constNode(this.prim("undefined")) : recv; + this.on(callee, (a) => { + switch (a.kind) { + case "function": + this.callFunction(this.infoOfAtom(a)!, undefNode, args, spread, dst, site); + return; + case "builtin": + this.callBuiltin(a, args, spread, dst, site, recv); + return; + case "class": + return; // calling a class throws + case "prim": + return; + default: + for (const x of args) this.sink(x, `argument of ⊤ call at ${locLabel(site)}`); + if (recv !== null && a.kind === "top") + this.sink(recv, `receiver of ⊤ call at ${locLabel(site)}`); + this.add(dst, this.top); + } + }); + } + + newExpr(e: ts.NewExpression): number { + this.noteSite(e); + const dst = this.newNode(); + const callee = this.expr(e.expression); + const { args, spread } = this.args(e); + this.on(callee, (a) => { + switch (a.kind) { + case "class": + this.construct(a.node!, args, spread, dst, e); + return; + case "function": { + // An ES5 constructor function: one instance atom per function. + const inst = this.atoms.intern(`fninst:${this.nodeKey(a.node!)}`, () => ({ + kind: "object", + label: `new ${a.label}`, + node: a.node, + })); + this.add(dst, inst); + const info = this.infoOfAtom(a); + if (info !== undefined) { + this.activate(info); + this.add(info.thisNode, inst); + this.bindArgs(info, args, spread); + this.edge(info.ret, dst); + } + return; + } + case "builtin": + this.constructBuiltin(a.path ?? "", args, dst, e); + return; + default: + for (const x of args) this.sink(x, `argument of ⊤ constructor at ${locLabel(e)}`); + this.add(dst, this.top); + } + }); + return dst; + } + + constructBuiltin(path: string, args: number[], dst: number, site: Node): void { + switch (path) { + case "Map": + case "Set": + case "WeakMap": + case "WeakSet": { + const c = this.atoms.intern(`coll:${this.nodeKey(site)}`, () => ({ + kind: "collection", + label: `${path}@${locLabel(site)}`, + node: site, + })); + this.add(dst, c); + if (args[0] !== undefined) this.iterateInto(args[0], this.element(c), site); + return; + } + case "Error": + case "TypeError": + case "RangeError": + case "SyntaxError": + this.add(dst, this.builtin("Error.instance")); + return; + case "Promise": { + const p = this.promiseAtom(site, locLabel(site)); + this.add(this.field(p, "value"), this.top); + this.add(dst, p); + if (args[0] !== undefined) { + const resolver = this.constNode(this.builtin("promise.resolver")); + this.on(args[0], (f) => { + if (f.kind === "function") + this.callFunction( + this.infoOfAtom(f)!, + null, + [resolver, resolver], + false, + this.newNode(), + site, + ); + }); + } + return; + } + case "Date": + this.add(dst, this.builtin("Date.instance")); + return; + case "RegExp": + this.add(dst, this.builtin("RegExp.instance")); + return; + case "Array": { + this.add(dst, this.syntheticArray(site, "Array")); + return; + } + default: + for (const x of args) this.sink(x, `argument of new ${path} at ${locLabel(site)}`); + this.add(dst, this.top); + } + } + + /** Builtin call summaries; anything unmodeled makes its arguments escape. */ + callBuiltin( + a: Atom, + args: number[], + spread: boolean, + dst: number, + site: ts.CallExpression, + recvNode: number | null, + ): void { + const path = a.path ?? ""; + const recv = a.receiver; + const arg = (i: number): number => args[i] ?? this.constNode(this.prim("undefined")); + const prim = (p: string): void => this.add(dst, this.prim(p)); + const callback = (i: number, cbArgs: number[], ret: number | null): void => { + if (args[i] === undefined) return; + this.on(args[i]!, (f) => { + if (f.kind === "function") { + const saved = this.forceLoop; + this.forceLoop = LOOP_CALLBACK_METHODS.has(path.slice(path.indexOf(".") + 1)); + this.callFunction(this.infoOfAtom(f)!, null, cbArgs, false, ret ?? this.newNode(), site); + this.forceLoop = saved; + } else if (f.kind === "top" || f.kind === "builtin") { + for (const x of cbArgs) this.sink(x, `argument of ⊤ callback at ${locLabel(site)}`); + if (ret !== null) this.add(ret, this.top); + } + }); + }; + const escapeAll = (): void => { + for (const x of args) this.sink(x, `argument of ${path} at ${locLabel(site)}`); + this.add(dst, this.top); + }; + // Methods of builtin receivers. + if (recv !== undefined) { + const method = path.slice(path.indexOf(".") + 1); + if (path.startsWith("array.")) { + const el = this.element(recv); + const num = this.constNode(this.prim("number")); + const recvN = this.constNode(recv); + switch (method) { + case "push": + case "unshift": + for (const x of args) { + if (spread) this.iterateInto(x, el, site); + else this.edge(x, el); + } + prim("number"); + return; + case "pop": + case "shift": + case "at": + this.edge(el, dst); + this.add(dst, this.prim("undefined")); + return; + case "find": + case "findLast": + callback(0, [el, num, recvN], null); + this.edge(el, dst); + this.add(dst, this.prim("undefined")); + return; + case "forEach": + callback(0, [el, num, recvN], null); + prim("undefined"); + return; + case "some": + case "every": + case "includes": + callback(0, [el, num, recvN], null); + prim("boolean"); + return; + case "findIndex": + case "findLastIndex": + case "indexOf": + case "lastIndexOf": + callback(0, [el, num, recvN], null); + prim("number"); + return; + case "join": + case "toString": + prim("string"); + return; + case "map": + case "flatMap": { + const out = this.syntheticArray(site, method); + const outEl = this.element(out); + if (method === "map") callback(0, [el, num, recvN], outEl); + else { + const r = this.newNode(); + callback(0, [el, num, recvN], r); + this.iterateInto(r, outEl, site); + } + this.add(dst, out); + return; + } + case "filter": + case "slice": + case "concat": + case "reverse": + case "sort": + case "splice": + case "toSorted": + case "toReversed": + case "flat": { + if (method === "filter") callback(0, [el, num, recvN], null); + if (method === "sort" || method === "toSorted") callback(0, [el, el], null); + if (method === "reverse" || method === "sort") { + this.add(dst, recv); + return; + } + const out = this.syntheticArray(site, method); + this.edge(el, this.element(out)); + if (method === "concat") + for (const x of args) this.iterateInto(x, this.element(out), site); + if (method === "splice") for (const x of args.slice(2)) this.edge(x, el); + this.add(dst, out); + return; + } + case "reduce": + case "reduceRight": { + const acc = this.newNode(); + if (args[1] !== undefined) this.edge(args[1], acc); + else this.edge(el, acc); + callback(0, [acc, el, num, recvN], acc); + this.edge(acc, dst); + return; + } + case "keys": + case "values": + case "entries": { + const out = this.syntheticArray(site, method); + if (method === "values") this.edge(el, this.element(out)); + else if (method === "keys") this.add(this.element(out), this.prim("number")); + else { + const pair = this.syntheticArray(site, "entry"); + this.add(this.element(pair), this.prim("number")); + this.edge(el, this.element(pair)); + this.add(this.element(out), pair); + } + this.add(dst, out); + return; + } + case "fill": + for (const x of args) this.edge(x, el); + this.add(dst, recv); + return; + } + escapeAll(); + this.escape(recv, `array.${method} at ${locLabel(site)}`); + return; + } + if (path.startsWith("string.") || path.startsWith("number.") || path.startsWith("boolean.")) { + const r = STRING_METHOD_RESULTS.get(method); + if (r === "array") { + const out = this.syntheticArray(site, method); + this.add(this.element(out), this.prim("string")); + this.add(this.element(out), this.prim("undefined")); + this.add(dst, out); + this.add(dst, this.prim("null")); + } else if (r !== undefined) prim(r); + else if (method === "replace" || method === "replaceAll") prim("string"); + else escapeAll(); + if (method === "replace" || method === "replaceAll") + callback(1, [this.constNode(this.prim("string"))], null); + return; + } + if (path.startsWith("regexp.")) { + if (method === "test") prim("boolean"); + else if (method === "exec") { + const out = this.syntheticArray(site, "exec"); + this.add(this.element(out), this.prim("string")); + this.add(dst, out); + prim("null"); + } else escapeAll(); + return; + } + if (path.startsWith("promise.")) { + const out = this.promiseAtom(site, locLabel(site)); + const value = this.field(recv, "value"); + const ret = this.newNode(); + if (method === "then") { + callback(0, [value], ret); + callback(1, [this.constNode(this.top)], ret); + } else if (method === "catch") { + callback(0, [this.constNode(this.top)], ret); + this.edge(value, ret); + } else { + callback(0, [], null); + this.edge(value, ret); + } + this.awaitInto(ret, this.field(out, "value")); + this.add(dst, out); + return; + } + if (path.startsWith("collection.")) { + const el = this.element(recv); + switch (method) { + case "add": + case "set": + for (const x of args) this.edge(x, el); + this.add(dst, recv); + return; + case "get": + this.edge(el, dst); + prim("undefined"); + return; + case "has": + case "delete": + prim("boolean"); + return; + case "clear": + prim("undefined"); + return; + case "forEach": + callback(0, [el, el], null); + prim("undefined"); + return; + case "keys": + case "values": + case "entries": { + const out = this.syntheticArray(site, method); + this.edge(el, this.element(out)); + if (method === "entries") { + const pair = this.syntheticArray(site, "entry"); + this.edge(el, this.element(pair)); + this.nodes[this.element(out)]!.atoms.clear(); + this.add(this.element(out), pair); + } + this.add(dst, out); + return; + } + } + escapeAll(); + return; + } + if (path.startsWith("function.")) { + if (recv.kind !== "function" || recv.node === undefined) { + escapeAll(); + return; + } + if (method === "bind") { + const info = this.infoOfAtom(recv); + if (info !== undefined && args[0] !== undefined && !info.isArrow) + this.edge(args[0], info.thisNode); + if (info !== undefined && args.length > 1) { + this.activate(info); + for (const p of info.params) this.add(p, this.top); + for (const x of args.slice(1)) this.sink(x, `bound argument at ${locLabel(site)}`); + } + this.add(dst, recv); + return; + } + if (method === "call") { + this.callFunction( + this.infoOfAtom(recv)!, + args[0] ?? this.constNode(this.prim("undefined")), + args.slice(1), + spread, + dst, + site, + ); + return; + } + // apply: arguments from an array + const info = this.infoOfAtom(recv); + if (info !== undefined) { + this.activate(info); + if (args[0] !== undefined && !info.isArrow) this.edge(args[0], info.thisNode); + for (const p of info.params) + if (args[1] !== undefined) this.iterateInto(args[1], p, site); + this.edge(info.ret, dst); + } + return; + } + if (path.startsWith("object.")) { + if (method === "hasOwnProperty") prim("boolean"); + else if (method === "toString") prim("string"); + else escapeAll(); + return; + } + escapeAll(); + return; + } + // `Object.prototype.m.call(o, …)`-style calls of builtin prototype methods. + if (/^(Object|Array|String|Function)\.prototype\.\w+\.(call|apply)$/.test(path)) { + const m = path.split(".")[2]!; + if (m === "hasOwnProperty" || m === "propertyIsEnumerable" || m === "isPrototypeOf") + prim("boolean"); + else if (m === "toString") prim("string"); + else escapeAll(); + return; + } + switch (path) { + case "Object.keys": + case "Object.getOwnPropertyNames": { + const out = this.syntheticArray(site, "keys"); + this.add(this.element(out), this.prim("string")); + this.add(dst, out); + return; + } + case "Object.values": + case "Object.entries": { + const out = this.syntheticArray(site, path === "Object.values" ? "values" : "entries"); + const vals = this.newNode(); + if (args[0] !== undefined) this.computedLoad(args[0], vals, site); + if (path === "Object.values") this.edge(vals, this.element(out)); + else { + const pair = this.syntheticArray(site, "entry"); + this.add(this.element(pair), this.prim("string")); + this.edge(vals, this.element(pair)); + this.add(this.element(out), pair); + } + this.add(dst, out); + return; + } + case "Object.freeze": + case "Object.seal": + case "Object.preventExtensions": + this.ops.push({ + kind: path === "Object.freeze" ? "freeze" : "seal", + recv: arg(0), + name: null, + node: site, + }); + this.edge(arg(0), dst); + return; + case "Object.isFrozen": + case "Object.isSealed": + case "Object.isExtensible": + case "Array.isArray": + case "Number.isInteger": + case "Number.isNaN": + case "Number.isFinite": + case "Number.isSafeInteger": + case "isNaN": + case "isFinite": + prim("boolean"); + return; + case "Object.assign": { + this.ops.push({ kind: "assign", recv: arg(0), name: null, node: site }); + this.on(arg(0), (t) => { + for (const s of args.slice(1)) this.copyFields(s, t, site); + if (t.kind === "top") + for (const s of args.slice(1)) + this.sink(s, `Object.assign into ⊤ at ${locLabel(site)}`); + }); + this.edge(arg(0), dst); + return; + } + case "Object.defineProperty": + case "Object.defineProperties": + case "Reflect.defineProperty": + this.ops.push({ kind: "defineProperty", recv: arg(0), name: null, node: site }); + this.sink(arg(2), `property descriptor at ${locLabel(site)}`); + this.sink(arg(1), `property descriptor at ${locLabel(site)}`); + this.edge(arg(0), dst); + return; + case "Object.setPrototypeOf": + case "Reflect.setPrototypeOf": + this.ops.push({ kind: "setPrototypeOf", recv: arg(0), name: null, node: site }); + this.sink(arg(1), `prototype at ${locLabel(site)}`); + this.edge(arg(0), dst); + return; + case "Object.create": { + const d = this.atoms.intern(`dict:${this.nodeKey(site)}`, () => ({ + kind: "dictionary", + label: `Object.create@${locLabel(site)}`, + node: site, + })); + this.add(dst, d); + return; + } + case "Object.fromEntries": { + const d = this.atoms.intern(`dict:${this.nodeKey(site)}`, () => ({ + kind: "dictionary", + label: `fromEntries@${locLabel(site)}`, + node: site, + })); + const pairs = this.newNode(); + if (args[0] !== undefined) this.iterateInto(args[0], pairs, site); + const vals = this.newNode(); + this.iterateInto(pairs, vals, site); + this.edge(vals, this.anyField(d)); + this.add(dst, d); + return; + } + case "Object.getPrototypeOf": + case "Reflect.getPrototypeOf": + this.add(dst, this.top); + return; + case "Object.is": + prim("boolean"); + return; + case "Array.from": + case "Array.of": { + const out = this.syntheticArray(site, path); + if (path === "Array.of") for (const x of args) this.edge(x, this.element(out)); + else if (args[1] !== undefined) { + const els = this.newNode(); + if (args[0] !== undefined) this.iterateInto(args[0], els, site); + callback(1, [els, this.constNode(this.prim("number"))], this.element(out)); + } else if (args[0] !== undefined) this.iterateInto(args[0], this.element(out), site); + this.add(dst, out); + return; + } + case "JSON.parse": + this.add(dst, this.top); + return; + case "JSON.stringify": + prim("string"); + prim("undefined"); + return; + case "String": + case "encodeURIComponent": + case "decodeURIComponent": + case "encodeURI": + case "decodeURI": + prim("string"); + return; + case "Number": + case "parseInt": + case "parseFloat": + case "Number.parseInt": + case "Number.parseFloat": + prim("number"); + return; + case "Boolean": + prim("boolean"); + return; + case "Symbol": + case "Symbol.for": + prim("symbol"); + return; + case "BigInt": + prim("bigint"); + return; + case "Promise.resolve": { + const p = this.promiseAtom(site, locLabel(site)); + if (args[0] !== undefined) this.awaitInto(args[0], this.field(p, "value")); + else this.add(this.field(p, "value"), this.prim("undefined")); + this.add(dst, p); + return; + } + case "Promise.reject": { + const p = this.promiseAtom(site, locLabel(site)); + this.add(dst, p); + if (args[0] !== undefined) this.sink(args[0], `rejection at ${locLabel(site)}`); + return; + } + case "Promise.all": + case "Promise.allSettled": + case "Promise.race": + case "Promise.any": { + const p = this.promiseAtom(site, locLabel(site)); + const items = this.newNode(); + if (args[0] !== undefined) this.iterateInto(args[0], items, site); + if (path === "Promise.all") { + const out = this.syntheticArray(site, "all"); + this.awaitInto(items, this.element(out)); + this.add(this.field(p, "value"), out); + } else if (path === "Promise.race" || path === "Promise.any") + this.awaitInto(items, this.field(p, "value")); + else this.add(this.field(p, "value"), this.top); + this.add(dst, p); + return; + } + case "promise.resolver": + for (const x of args) this.sink(x, `promise resolution at ${locLabel(site)}`); + return; + } + if (path.startsWith("console.")) { + prim("undefined"); + return; + } + if (path.startsWith("Math.")) { + prim("number"); + return; + } + if (path === "Date.now") { + prim("number"); + return; + } + if (path.startsWith("Date.instance") || path === "Error.instance") { + escapeAll(); + return; + } + void recvNode; + escapeAll(); + } + + /** Re-run deferred field copies until nothing new flows. */ + finish(): void { + for (;;) { + const before = this.steps; + for (const c of this.lateCopies) c(); + this.solve(); + if (this.steps === before || this.budgetExceeded) return; + } + } +} diff --git a/packages/compiler/src/frontend/shape-inference/domain.ts b/packages/compiler/src/frontend/shape-inference/domain.ts new file mode 100644 index 000000000..36978d4c9 --- /dev/null +++ b/packages/compiler/src/frontend/shape-inference/domain.ts @@ -0,0 +1,153 @@ +/* Shape inference (results/design-shape-inference/DESIGN.md), stage S1: + * the abstract domain of the allocation-site points-to analysis. + * + * An abstract value is a set of atoms. An atom names a set of runtime + * values: a primitive kind, an allocation site (object or array literal, or + * a value a builtin creates at one call site), the instances of one class, + * one class value, one function (closure site), a builtin object, or ⊤ — + * every value the analysis does not track. Value nodes hold atom sets and + * flow into each other along inclusion edges; the solver (analyze.ts) + * attaches load, store and call constraints that fire as atoms arrive. */ +import type * as ts from "../ts7/adapter.js"; + +export type AtomKind = + | "prim" + | "top" + | "object" + | "array" + | "instance" + | "class" + | "function" + | "builtin" + | "promise" + | "collection" + | "dictionary"; + +export interface Atom { + readonly id: number; + readonly kind: AtomKind; + /** Short display name, e.g. `string`, `ZodString`, `{status,value}@types.js:804`. */ + readonly label: string; + /** The syntax that creates the atom: the literal, class or function + * declaration, or the builtin call. Undefined for prims, ⊤ and builtins. */ + readonly node?: ts.Node | undefined; + /** builtin atoms: the dotted path (`Object.keys`, `array.push`). */ + readonly path?: string | undefined; + /** method atoms of builtin receivers: the receiver atom. */ + readonly receiver?: Atom | undefined; + /** function atoms: the analysis context of the function's clone (a + * method's receiver class), "" for the context-insensitive default. */ + readonly ctx?: string | undefined; +} + +export class AtomTable { + readonly atoms: Atom[] = []; + private readonly byKey = new Map(); + + intern(key: string, make: (id: number) => Omit): Atom { + let atom = this.byKey.get(key); + if (atom === undefined) { + const id = this.atoms.length; + atom = { id, ...make(id) }; + this.atoms.push(atom); + this.byKey.set(key, atom); + } + return atom; + } +} + +/** Object.prototype members: a read of one of these names on a plain + * object resolves on the prototype, never to an absent own key. */ +export const OBJECT_PROTOTYPE_MEMBERS: ReadonlySet = new Set([ + "constructor", + "hasOwnProperty", + "isPrototypeOf", + "propertyIsEnumerable", + "toLocaleString", + "toString", + "valueOf", + "__defineGetter__", + "__defineSetter__", + "__lookupGetter__", + "__lookupSetter__", + "__proto__", +]); + +/** Global names the analysis models as builtin objects. Any other global is ⊤. */ +export const MODELED_GLOBALS: ReadonlySet = new Set([ + "Object", + "Array", + "JSON", + "Math", + "Number", + "String", + "Boolean", + "Symbol", + "Promise", + "Map", + "Set", + "WeakMap", + "WeakSet", + "Error", + "TypeError", + "RangeError", + "SyntaxError", + "Date", + "RegExp", + "console", + "Reflect", + "parseInt", + "parseFloat", + "isNaN", + "isFinite", + "encodeURIComponent", + "decodeURIComponent", + "encodeURI", + "decodeURI", + "BigInt", +]); + +/** Results of string (and number) methods, by name. Anything else is ⊤. */ +type MethodResult = "string" | "number" | "boolean" | "array"; +export const STRING_METHOD_RESULTS: ReadonlyMap = new Map< + string, + MethodResult +>([ + ["at", "string"], + ["charAt", "string"], + ["charCodeAt", "number"], + ["codePointAt", "number"], + ["concat", "string"], + ["endsWith", "boolean"], + ["includes", "boolean"], + ["indexOf", "number"], + ["lastIndexOf", "number"], + ["localeCompare", "number"], + ["match", "array"], + ["matchAll", "array"], + ["normalize", "string"], + ["padEnd", "string"], + ["padStart", "string"], + ["repeat", "string"], + ["replace", "string"], + ["replaceAll", "string"], + ["search", "number"], + ["slice", "string"], + ["split", "array"], + ["startsWith", "boolean"], + ["substring", "string"], + ["substr", "string"], + ["toLowerCase", "string"], + ["toUpperCase", "string"], + ["toLocaleLowerCase", "string"], + ["toLocaleUpperCase", "string"], + ["toString", "string"], + ["trim", "string"], + ["trimEnd", "string"], + ["trimStart", "string"], + ["valueOf", "string"], + ["test", "boolean"], + ["toFixed", "string"], + ["toPrecision", "string"], + ["toExponential", "string"], +]); diff --git a/packages/compiler/src/frontend/shape-inference/index.ts b/packages/compiler/src/frontend/shape-inference/index.ts new file mode 100644 index 000000000..88c2100ee --- /dev/null +++ b/packages/compiler/src/frontend/shape-inference/index.ts @@ -0,0 +1,21 @@ +/* Shape inference for untyped npm JavaScript + * (results/design-shape-inference/DESIGN.md). Stage S1: report only. */ +import type * as ts from "../ts7/adapter.js"; +import { analyzeShapes } from "./analyze.js"; +import { buildShapeReport } from "./report.js"; + +export { analyzeShapes } from "./analyze.js"; +export { buildShapeReport } from "./report.js"; + +/** SCRIPTC_DEBUG_SHAPES: `1` reports package code in hot functions, + * `verbose` every package site, `all` user files too, any other value only + * files whose path contains it. Writes to stderr; changes nothing else. */ +export function reportShapes(program: ts.Program, filter: string): void { + const start = performance.now(); + const analysis = analyzeShapes(program, program.getTypeChecker()); + const report = buildShapeReport(analysis, filter); + const ms = (performance.now() - start).toFixed(0); + process.stderr.write( + `[shapes] ${ms} ms\n${report.lines.map((l) => `[shapes] ${l}`).join("\n")}\n`, + ); +} diff --git a/packages/compiler/src/frontend/shape-inference/report.ts b/packages/compiler/src/frontend/shape-inference/report.ts new file mode 100644 index 000000000..c18d9eb56 --- /dev/null +++ b/packages/compiler/src/frontend/shape-inference/report.ts @@ -0,0 +1,374 @@ +/* Shape inference stage S1: the plan the analysis would hand the lowering, + * as a report (DESIGN.md §4.5, §5.5). Nothing here changes compilation. + * + * Per allocation site of package code, the verdict: + * P local — a native record would be exact: no reflection, no added + * keys, no computed writes, and its objects never escape; + * P escaping — exact as a record behind identity-keeping capsules: it + * escapes, but the census leaves every later operation + * answerable (fields untyped code may write become dyn); + * G — keeps today's dynamic object, with the rule that decided. + * Plus class field types, the census, and the hot functions' value types. */ +import * as ts from "../ts7/adapter.js"; +import { OBJECT_PROTOTYPE_MEMBERS, type Atom } from "./domain.js"; +import { locLabel, type FunctionInfo, type LiteralSite, type ShapeAnalysis } from "./analyze.js"; + +export interface SiteVerdict { + readonly site: LiteralSite; + readonly label: string; + readonly verdict: "P-local" | "P-escaping" | "G"; + readonly reasons: string[]; + /** P-escaping: fields untyped code may write (they become dyn slots). */ + readonly writableByTop: string[]; + readonly freezable: boolean; + readonly brand: boolean; +} + +export interface ShapeReport { + readonly sites: SiteVerdict[]; + readonly hot: Set; + readonly lines: string[]; +} + +const MAX_ATOMS_SHOWN = 6; + +function fieldKeys(fields: ReadonlyMap | undefined): string[] { + return fields === undefined ? [] : [...fields.keys()]; +} + +function fieldEntries(fields: ReadonlyMap | undefined): [string, number][] { + return fields === undefined ? [] : [...fields.entries()]; +} + +export function describeValue(analysis: ShapeAnalysis, node: number): string { + const atoms = [...analysis.nodes[node]!.atoms]; + if (atoms.length === 0) return "∅"; + const labels = [...new Set(atoms.map((a) => a.label))]; + labels.sort((a, b) => (a === "⊤" ? 1 : b === "⊤" ? -1 : a.localeCompare(b))); + const shown = labels.slice(0, MAX_ATOMS_SHOWN).join(" | "); + if (labels.length <= MAX_ATOMS_SHOWN) return shown; + return `${shown} | +${labels.length - MAX_ATOMS_SHOWN}${labels.includes("⊤") ? " | ⊤" : ""}`; +} + +function atomsOf(analysis: ShapeAnalysis, node: number): Set { + return analysis.nodes[node]!.atoms; +} + +/** Functions reached from call sites in loops (or loop callbacks), and + * everything they call: the static hotness heuristic (DESIGN.md §8.1). */ +export function hotFunctions(analysis: ShapeAnalysis): Set { + const hot = new Set(); + const callees = new Map(); + const work: FunctionInfo[] = []; + for (const c of analysis.calls) { + let l = callees.get(c.caller); + if (l === undefined) callees.set(c.caller, (l = [])); + l.push(c.callee); + if (c.inLoop && !hot.has(c.callee)) { + hot.add(c.callee); + work.push(c.callee); + } + } + while (work.length > 0) { + const f = work.pop()!; + for (const g of callees.get(f) ?? []) { + if (!hot.has(g)) { + hot.add(g); + work.push(g); + } + } + } + return hot; +} + +export function buildShapeReport(analysis: ShapeAnalysis, filter: string): ShapeReport { + const lines: string[] = []; + const all = filter === "all" || filter === "verbose"; + const verbose = filter === "verbose"; + const fileFilter = filter !== "1" && !all ? filter : null; + const wanted = (n: ts.Node, inPackage: boolean): boolean => { + if (fileFilter !== null) return n.getSourceFile().fileName.includes(fileFilter); + return all || inPackage; + }; + + // Census facts: operations whose receiver may be ⊤ reach every escaped atom. + + // Index ops by the site atoms they can reach directly. + const byAtom = new Map(); + const topOps: typeof analysis.ops = []; + for (const o of analysis.ops) { + const atoms = atomsOf(analysis, o.recv); + for (const a of atoms) { + if (a.kind !== "object" && a.kind !== "array") continue; + let l = byAtom.get(a); + if (l === undefined) byAtom.set(a, (l = [])); + l.push(o); + } + if (atoms.has(analysis.top)) topOps.push(o); + } + + // Key-order groups: sites with the same key set and different orders need brands. + const orders = new Map>(); + for (const s of analysis.sites) { + if (s.kind !== "object" || s.keys === null) continue; + const set = [...s.keys].sort().join(","); + let o = orders.get(set); + if (o === undefined) orders.set(set, (o = new Set())); + o.add(s.keys.join(",")); + } + + const verdicts: SiteVerdict[] = []; + for (const s of analysis.sites) { + if (!s.inPackage && !all && fileFilter === null) continue; + const reasons: string[] = []; + const escapedWhy = analysis.escaped.get(s.atom); + const escapes = escapedWhy !== undefined; + if (s.hasAccessor) reasons.push("accessor in literal"); + if (s.hasProto) reasons.push(s.kind === "array" ? "hole in literal" : "__proto__ in literal"); + if (s.hasComputedKey) reasons.push("computed key in literal"); + for (const sp of s.spreads) + if (atomsOf(analysis, sp).has(analysis.top)) reasons.push("spread of ⊤"); + const direct = byAtom.get(s.atom) ?? []; + const ops = escapes ? [...direct, ...topOps] : direct; + const keys = new Set(s.keys ?? []); + const fieldsOf = analysis.fields.get(s.atom); + const knownKeys = + s.keys !== null ? keys : new Set([...fieldKeys(fieldsOf)].filter((k) => k !== "*")); + let freezable = false; + const seen = new Set(); + const note = (r: string): void => { + if (!seen.has(r)) { + seen.add(r); + reasons.push(r); + } + }; + for (const o of ops) { + const viaTop = !atomsOf(analysis, o.recv).has(s.atom); + const where = `${locLabel(o.node)}${viaTop ? " via ⊤" : ""}`; + switch (o.kind) { + case "delete": + case "defineProperty": + case "setPrototypeOf": + case "seal": + case "proxy": + note(`${o.kind} at ${where}`); + break; + case "assign": + note(`Object.assign target at ${where}`); + break; + case "freeze": + freezable = true; + break; + case "computedWrite": + if (!viaTop) + note(s.kind === "array" ? `index write at ${where}` : `computed write at ${where}`); + break; + case "lengthWrite": + if (s.kind === "array") note(`length write at ${where}`); + break; + case "write": + if (s.kind === "object" && !viaTop && o.name !== null && !knownKeys.has(o.name)) + note(`adds key '${o.name}' at ${where}`); + break; + case "read": + if ( + s.kind === "object" && + !underPromiseGuard(o.node) && + escapes && + o.name !== null && + !viaTop && + !knownKeys.has(o.name) && + !OBJECT_PROTOTYPE_MEMBERS.has(o.name) + ) + note(`reads absent key '${o.name}' at ${where} (escapes)`); + break; + default: + break; + } + } + let brand = false; + if (s.kind === "object" && s.keys !== null) { + const o = orders.get([...s.keys].sort().join(",")); + if (o !== undefined && o.size > 1) brand = true; + } + const writableByTop: string[] = []; + if (escapes) { + if (analysis.topComputedWrites.length > 0) writableByTop.push("*"); + else for (const k of knownKeys) if (analysis.topWriteNames.has(k)) writableByTop.push(k); + } + const verdict: SiteVerdict["verdict"] = + reasons.length > 0 ? "G" : escapes ? "P-escaping" : "P-local"; + const label = s.atom.label; + if (escapes) reasons.push(`escapes: ${escapedWhy}`); + verdicts.push({ site: s, label, verdict, reasons, writableByTop, freezable, brand }); + } + + const hot = hotFunctions(analysis); + const hotNodes = new Set([...hot].map((f) => f.node)); + + // ---- print ---- + const pkgFns = [...analysis.functions.values()].filter((f) => f.inPackage); + lines.push( + `analyzed ${analysis.files.length} files (${analysis.packageFiles} package JS), ${analysis.functions.size} functions (${pkgFns.length} in packages), ${analysis.atoms.atoms.length} atoms, ${analysis.nodes.length} value nodes, ${analysis.steps} steps${analysis.budgetExceeded ? " — BUDGET EXCEEDED, results incomplete" : ""}`, + ); + const topNames = [...analysis.topWriteNames.entries()].map( + ([n, node]) => `${n} (${locLabel(node)})`, + ); + lines.push( + `census: writes on ⊤ receivers: ${topNames.length === 0 ? "none" : topNames.slice(0, 20).join(", ")}${topNames.length > 20 ? ` +${topNames.length - 20}` : ""}`, + ); + lines.push( + `census: computed writes on ⊤ receivers: ${analysis.topComputedWrites.length === 0 ? "none" : analysis.topComputedWrites.slice(0, 8).map(locLabel).join(", ")}`, + ); + const topReflect = topOps.filter( + (o) => + o.kind !== "read" && + o.kind !== "computedRead" && + o.kind !== "write" && + o.kind !== "computedWrite", + ); + lines.push( + `census: reflection on ⊤ receivers: ${topReflect.length === 0 ? "none" : topReflect.map((o) => `${o.kind} (${locLabel(o.node)})`).join(", ")}`, + ); + const escapedPkg = [...analysis.escaped.keys()].filter( + (a) => + a.node !== undefined && + wanted(a.node, a.node.getSourceFile().fileName.includes("/node_modules/")), + ); + lines.push( + `escaped atoms: ${analysis.escaped.size} (${escapedPkg.length} shown below where relevant)`, + ); + const firstEscapes = [...analysis.escaped.entries()] + .filter(([, why]) => !why.startsWith("via ")) + .slice(0, 12); + for (const [atom, why] of firstEscapes) lines.push(` escape root: ${atom.label}: ${why}`); + + const counts = { "P-local": 0, "P-escaping": 0, G: 0 }; + const hotCounts = { "P-local": 0, "P-escaping": 0, G: 0 }; + const inHot = (n: ts.Node): boolean => { + let p: ts.Node | undefined = n.parent; + while (p !== undefined) { + if (hotNodes.has(p)) return true; + p = p.parent; + } + return false; + }; + for (const v of verdicts) { + counts[v.verdict]++; + if (inHot(v.site.node)) hotCounts[v.verdict]++; + } + lines.push( + `sites: ${verdicts.length} (P local ${counts["P-local"]}, P escaping ${counts["P-escaping"]}, G ${counts.G}); in hot functions: P local ${hotCounts["P-local"]}, P escaping ${hotCounts["P-escaping"]}, G ${hotCounts.G}`, + ); + for (const v of verdicts) { + if (!wanted(v.site.node, v.site.inPackage)) continue; + if (!verbose && !inHot(v.site.node)) continue; + const extra: string[] = []; + if (v.brand) extra.push("needs brand (key order)"); + if (v.freezable) extra.push("freezable"); + if (v.writableByTop.length > 0) extra.push(`⊤-writable: ${v.writableByTop.join(",")}`); + const fields = analysis.fields.get(v.site.atom); + const ftypes = + v.site.kind === "array" + ? `elem: ${analysis.elements.has(v.site.atom) ? describeValue(analysis, analysis.elements.get(v.site.atom)!) : "∅"}` + : fieldEntries(fields) + .filter(([k]) => k !== "*") + .map(([k, id]) => `${k}: ${describeValue(analysis, id)}`) + .join("; "); + lines.push( + `site ${v.label}${inHot(v.site.node) ? " [hot]" : ""}: ${v.verdict}${v.reasons.length > 0 ? ` — ${v.reasons.join("; ")}` : ""}${extra.length > 0 ? ` [${extra.join("; ")}]` : ""}`, + ); + if (ftypes.length > 0) lines.push(` ${ftypes}`); + } + + // Class fields. + for (const atom of analysis.atoms.atoms) { + if (atom.kind !== "instance" || atom.node === undefined) continue; + const inPackage = atom.node.getSourceFile().fileName.includes("/node_modules/"); + if (!wanted(atom.node, inPackage)) continue; + const fm = analysis.fields.get(atom); + if (fm === undefined || fm.size === 0) continue; + const esc = analysis.escaped.get(atom); + const parts = [...fm.entries()].map(([k, id]) => { + const w = + esc !== undefined && + !k.startsWith("#") && + (analysis.topComputedWrites.length > 0 || analysis.topWriteNames.has(k)) + ? " (⊤-writable)" + : ""; + return `${k}: ${describeValue(analysis, id)}${w}`; + }); + lines.push( + `class ${atom.label}${esc !== undefined ? ` (escapes: ${esc})` : ""}: ${parts.join("; ")}`, + ); + } + + // Hot functions. + const hotPkg = [...hot].filter((info) => wanted(info.node, info.inPackage)); + lines.push(`hot functions: ${hotPkg.length} (clones per receiver class counted separately)`); + for (const info of hotPkg) { + const n = info.node; + const params = info.params.map((p, i) => `p${i}=${describeValue(analysis, p)}`).join(", "); + const flags = [ + info.usesArguments ? "uses arguments" : "", + analysis.escaped.size > 0 && [...analysis.escaped.keys()].some((a) => a.node === n) + ? "escapes" + : "", + ].filter((x) => x !== ""); + lines.push( + `fn ${info.label}${flags.length > 0 ? ` [${flags.join(", ")}]` : ""}: this=${describeValue(analysis, info.thisNode)}${params.length > 0 ? `, ${params}` : ""}, ret=${describeValue(analysis, info.ret)}`, + ); + } + const why = process.env["SCRIPTC_DEBUG_SHAPES_WHY"]; + if (why !== undefined) { + for (const info of analysis.functions.values()) { + if (!info.label.startsWith(why)) continue; + for (const [what, node] of [ + ["ret", info.ret], + ...info.params.map((p, i) => [`p${i}`, p] as const), + ] as const) { + if (!analysis.nodes[node]!.atoms.has(analysis.top)) continue; + lines.push(`why ⊤ in ${info.label} ${what}:`); + let cur: number | string | undefined = node; + for (let i = 0; i < 40 && typeof cur === "number"; i++) { + lines.push(` ${analysis.nodeLabel.get(cur) ?? `node ${cur}`}`); + cur = analysis.topCause.get(cur); + } + if (typeof cur === "string") lines.push(` seed: ${cur}`); + } + } + } + return { sites: verdicts, hot, lines }; +} + +/** A read inside the true arm of a promise test (`isAsync(x)`, + * `x instanceof Promise`): flow-sensitive narrowing removes the record + * arms there. Stage S1's locals are flow-insensitive, so the report + * recognizes the guard syntactically. */ +function underPromiseGuard(node: ts.Node): boolean { + let child: ts.Node = node; + let p = node.parent; + while (p !== undefined && !ts.isFunctionLike(p)) { + let cond: ts.Expression | undefined; + if (ts.isIfStatement(p) && p.thenStatement === child) cond = p.expression; + if (ts.isConditionalExpression(p) && p.whenTrue === child) cond = p.condition; + if (cond !== undefined && isPromiseTest(cond)) return true; + child = p; + p = p.parent; + } + return false; +} + +function isPromiseTest(e: ts.Expression): boolean { + if (ts.isParenthesizedExpression(e)) return isPromiseTest(e.expression); + if (ts.isBinaryExpression(e)) { + if (e.operatorToken.kind === ts.SyntaxKind.InstanceOfKeyword) + return ts.isIdentifier(e.right) && e.right.text === "Promise"; + if (e.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) + return isPromiseTest(e.left) || isPromiseTest(e.right); + return false; + } + if (ts.isCallExpression(e) && ts.isIdentifier(e.expression)) + return /^is(Async|Promise|Thenable)$/.test(e.expression.text); + return false; +} diff --git a/packages/compiler/test/shape-inference.test.ts b/packages/compiler/test/shape-inference.test.ts new file mode 100644 index 000000000..3cd6e809d --- /dev/null +++ b/packages/compiler/test/shape-inference.test.ts @@ -0,0 +1,166 @@ +import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { afterEach, beforeEach, expect, test, vi } from "vitest"; +import { compile } from "../src/index.js"; + +// A package shaped like a validation library: schema classes with a virtual +// `_parse`, per-field context and result literals, a class holding the +// context, and an output object built with computed keys. +const packageSource = ` +export class Status { + constructor() { this.value = "valid"; } + dirty() { if (this.value === "valid") this.value = "dirty"; } +} +class LazyPath { + constructor(parent, data, key) { this.parent = parent; this.data = data; this.key = key; } + get path() { return [this.key]; } +} +export class Base { + constructor(def) { this._def = def; } + ctxOf(input) { return { common: input.parent.common, data: input.data, parent: input.parent }; } + parse(data) { + const root = { common: { issues: [] }, data, parent: null }; + const result = this._parse({ data, parent: root }); + return result.value; + } +} +export class Str extends Base { + _parse(input) { + const status = new Status(); + if (typeof input.data !== "string") status.dirty(); + return { status: status.value, value: input.data }; + } +} +export class Obj extends Base { + _parse(input) { + const ctx = this.ctxOf(input); + const pairs = []; + for (const key of Object.keys(this._def.shape)) { + const field = this._def.shape[key]; + pairs.push({ key, value: field._parse(new LazyPath(ctx, ctx.data[key], key)) }); + } + const out = {}; + for (const pair of pairs) out[pair.key] = pair.value.value; + return { status: "valid", value: out }; + } +} +export const str = () => new Str({ checks: [] }); +export const obj = (shape) => new Obj({ shape }); +export function leak(value) { globalThis.leaked = value; return value; } +export function reflect() { const o = { a: 1 }; delete o.a; return o; } +`; + +const packageTypes = ` +export declare class Base { parse(data: unknown): unknown; } +export declare class Str extends Base {} +export declare class Obj extends Base {} +export declare const str: () => Str; +export declare const obj: (shape: Record) => Obj; +export declare function leak(value: T): T; +export declare function reflect(): object; +`; + +const mainSource = ` +import { leak, obj, reflect, str } from "shapes-fixture"; +const schema = obj({ a: str(), b: str() }); +const input: unknown = JSON.parse('{"a":"x","b":"y"}'); +console.log(JSON.stringify(schema.parse(input))); +console.log(JSON.stringify(leak({ kept: 1 })), JSON.stringify(reflect())); +`; + +let dir: string; +let saved: string | undefined; +beforeEach(async () => { + dir = await mkdtemp(join(tmpdir(), "scriptc-shapes-")); + const pkg = join(dir, "node_modules", "shapes-fixture"); + await mkdir(pkg, { recursive: true }); + await writeFile( + join(pkg, "package.json"), + JSON.stringify({ + name: "shapes-fixture", + version: "1.0.0", + type: "module", + main: "index.js", + types: "index.d.ts", + }), + ); + await writeFile(join(pkg, "index.js"), packageSource); + await writeFile(join(pkg, "index.d.ts"), packageTypes); + await writeFile( + join(dir, "package.json"), + JSON.stringify({ type: "module", dependencies: { "shapes-fixture": "1.0.0" } }), + ); + await writeFile(join(dir, "main.ts"), mainSource); + saved = process.env["SCRIPTC_DEBUG_SHAPES"]; +}); +afterEach(async () => { + if (saved === undefined) delete process.env["SCRIPTC_DEBUG_SHAPES"]; + else process.env["SCRIPTC_DEBUG_SHAPES"] = saved; + vi.restoreAllMocks(); + await rm(dir, { recursive: true, force: true }); +}); + +async function report(): Promise { + process.env["SCRIPTC_DEBUG_SHAPES"] = "verbose"; + const lines: string[] = []; + vi.spyOn(process.stderr, "write").mockImplementation((chunk: string | Uint8Array) => { + const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8"); + for (const l of text.split("\n")) if (l.startsWith("[shapes] ")) lines.push(l.slice(9)); + return true; + }); + const entry = join(dir, "main.ts"); + await compile(entry, { + outDir: dir, + outPath: join(dir, "main.ir.json"), + outputKind: "ir", + npmStatic: ["shapes-fixture"], + }); + return lines; +} + +function site(lines: string[], label: RegExp): string { + const line = lines.find((l) => l.startsWith("site ") && label.test(l)); + if (line === undefined) throw new Error(`no site ${label}:\n${lines.join("\n")}`); + return line; +} + +test("S1 report: per-field temporaries are provable records, dynamic objects stay G", async () => { + const lines = await report(); + // result literals of both _parse implementations, the pair literal, the + // context and the root context never escape: native records would be exact + // the leaf schema's result: in a function called from a loop (hot) + expect(site(lines, /^site \{status,value\}@shapes-fixture\/index\.js:23 \[hot\]/)).toMatch( + /: P-local/, + ); + expect(site(lines, /^site \{status,value\}@shapes-fixture\/index\.js:36/)).toMatch(/: P-local/); + expect(site(lines, /^site \{key,value\}@/)).toMatch(/: P-local/); + expect(site(lines, /^site \{common,data,parent\}@shapes-fixture\/index\.js:12/)).toMatch( + /: P-local/, + ); + expect(site(lines, /^site \[\]@shapes-fixture\/index\.js:29/)).toMatch(/: P-local/); + // the output object is built with computed keys + expect(site(lines, /^site \{\}@shapes-fixture\/index\.js:34/)).toMatch(/: G — computed write/); + // a deleted key and a value stored into the global object + expect(site(lines, /^site \{a\}@/)).toMatch(/: G — delete at/); + expect(site(lines, /^site \{kept\}@main\.ts/)).toMatch(/: P-escaping — escapes: stored into ⊤/); + // receiver-typed dispatch: the field's validators are the schema classes + expect(lines.find((l) => l.startsWith("fn Str._parse@"))).toMatch(/p0=LazyPath/); + expect(lines.find((l) => l.startsWith("class LazyPath"))).toMatch( + /parent: \{common,data,parent\}@shapes-fixture\/index\.js:12;/, + ); + expect(lines.find((l) => l.startsWith("class Str"))).toMatch(/_def: \{checks\}@/); +}); + +test("S1 report is off by default and changes nothing", async () => { + delete process.env["SCRIPTC_DEBUG_SHAPES"]; + const writes = vi.spyOn(process.stderr, "write"); + const entry = join(dir, "main.ts"); + await compile(entry, { + outDir: dir, + outPath: join(dir, "main.ir.json"), + outputKind: "ir", + npmStatic: ["shapes-fixture"], + }); + expect(writes.mock.calls.some(([c]) => String(c).includes("[shapes]"))).toBe(false); +}); From e0d0e03eed999bcbc4564986632659937cecd030 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 15:47:49 -0500 Subject: [PATCH 026/259] Support Symbol.toStringTag class fields and getters --- .../symbol-fields.mdx | 1 + .../src/backend/llvm/expr-stream-bridges.ts | 71 +++++++++--- .../lowering/class-dynamic-dispatch.ts | 84 +++++++++++++- .../lowering/class-method-mutations.ts | 14 ++- .../frontend/lowering/class-to-primitive.ts | 103 ++++++++++++++++-- .../frontend/lowering/cycle-initialization.ts | 10 +- .../src/frontend/lowering/lower-calls.ts | 6 +- .../src/frontend/lowering/lower-classes.ts | 5 +- .../src/frontend/lowering/lower-inspect.ts | 87 ++++++++++++++- .../src/frontend/lowering/symbol-fields.ts | 49 +++++++++ .../src/ir/function-references.test.ts | 6 + .../compiler/src/ir/function-references.ts | 1 + packages/compiler/src/ir/ir.ts | 9 +- packages/compiler/src/ir/validate.ts | 25 ++++- ...751-class-well-known-symbol-fields.ts.json | 6 + packages/runtime/src/scr_dyn.h | 8 ++ packages/runtime/src/scr_inspect.c | 30 ++++- packages/runtime/src/scr_json.c | 71 +++++++++++- packages/runtime/src/scr_symbol.c | 5 + .../7751-class-well-known-symbol-fields.ts | 76 +++++++++++++ ...751-class-well-known-symbol-fields.ts.json | 1 + 21 files changed, 620 insertions(+), 48 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7751-class-well-known-symbol-fields.ts.json create mode 100644 tests/corpus/7751-class-well-known-symbol-fields.ts create mode 100644 tests/harness/corpus-costs/7751-class-well-known-symbol-fields.ts.json diff --git a/docs/content/limitations/types-and-class-definitions/symbol-fields.mdx b/docs/content/limitations/types-and-class-definitions/symbol-fields.mdx index baff4d190..45659b493 100644 --- a/docs/content/limitations/types-and-class-definitions/symbol-fields.mdx +++ b/docs/content/limitations/types-and-class-definitions/symbol-fields.mdx @@ -1,4 +1,5 @@ - **Symbol fields:** Instance fields require a stable module-level `Symbol()` or `Symbol.for()` binding with a literal description or constant string binding. + A `[Symbol.toStringTag]` field or getter with a string value sets the tag that `String()`, `Object.prototype.toString` and `util.inspect` print; fields keyed by other well-known symbols are unsupported. Reassigned keys, runtime-computed descriptions, distinct symbols with the same description in one class, and copying symbol fields with rest bindings or `Object.assign` are unsupported. JavaScript object spreads copy represented own symbol fields. Equal registry keys share a field across modules. diff --git a/packages/compiler/src/backend/llvm/expr-stream-bridges.ts b/packages/compiler/src/backend/llvm/expr-stream-bridges.ts index 70a8dcdee..f4532b21a 100644 --- a/packages/compiler/src/backend/llvm/expr-stream-bridges.ts +++ b/packages/compiler/src/backend/llvm/expr-stream-bridges.ts @@ -20,6 +20,7 @@ import { isRefCounted, shapeHasAccessorSlots, typeKey, + type IrClassDef, } from "../../ir/ir.js"; import { mangleFunction, mangleGlobal, mangleRecordStruct } from "../mangle.js"; import { BlockBuilder } from "./blocks.js"; @@ -277,9 +278,7 @@ export function streamTypedRefCommitAdapter( ); }); } - const symbols = new Map( - (meta.def.symbolFields ?? []).map((symbol) => [symbol.field, symbol.globalId]), - ); + const symbols = new Map((meta.def.symbolFields ?? []).map((symbol) => [symbol.field, symbol])); const fields = meta.def.fields.filter( (field) => (isClassOwnEnumerableFieldName(field.name) || symbols.has(field.name)) && @@ -299,13 +298,15 @@ export function streamTypedRefCommitAdapter( const inline = host.inlineUnions.classField(t.className, field.name); const fieldTy = int32 ? "i32" : llFieldType(field.type, inline); const checkTy = host.llType(field.type); - const symbolGlobal = symbols.get(field.name); - if (symbolGlobal) { + const symbolKey = symbols.get(field.name); + if (symbolKey) { host.declare(`declare ptr @scr_dyn_symbol_key_get(ptr, ptr, i1 zeroext)`); host.declare(`declare void @scr_dyn_release_v(ptr)`); + const keyLines = symbolKeyLines(host, symbolKey, `f${index}_keyraw`); lines.push( - ` %f${index}_keyraw = load ptr, ptr @${mangleGlobal(symbolGlobal)}`, + ...keyLines.load, ` %f${index}_key = call ptr @${host.dyn.toDynHelper(SYMBOL_T)}(ptr %f${index}_keyraw)`, + ...keyLines.release, ); if (field.type.kind === "symbol") { // A base constructor can mutate the instance before this @@ -333,7 +334,7 @@ export function streamTypedRefCommitAdapter( lines.push( ` %${raw} = call ptr @scr_dyn_obj_get(ptr %d, ptr ${host.cstr(field.name)}, ${host.sizeType} ${Buffer.byteLength(field.name, "utf8")})`, ); - if (meta.def.tracksOwnFields && !symbolGlobal) + if (meta.def.tracksOwnFields && !symbolKey) lines.push( ` %f${index}_present = icmp ne ptr %${raw}, null`, ` br i1 %f${index}_present, label %f${index}_read, label %${after}`, @@ -344,7 +345,7 @@ export function streamTypedRefCommitAdapter( ` %${undef} = call ptr @scr_dyn_undefined()`, ` %${input} = select i1 %${missing}, ptr %${undef}, ptr %${raw}`, ` %${next} = call ${field.type.kind === "bool" ? "zeroext " : ""}${checkTy} @${host.dyn.dynCheckHelper(field.type)}(ptr %${input}, ptr null)`, - ...(symbolGlobal ? [` call void @scr_dyn_release_v(ptr %${raw})`] : []), + ...(symbolKey ? [` call void @scr_dyn_release_v(ptr %${raw})`] : []), ...host.pendingTestLines(`%${pending}`), ` br i1 %${pending}, label %done, label %${store}`, `${store}:`, @@ -499,16 +500,18 @@ export function streamTypedRefCommitAdapter( ? `declare void @scr_dyn_symbol_key_placeholder(ptr, ptr)` : `declare void @scr_dyn_key_delete_computed(ptr, ptr, i1 zeroext)`, ); - [...symbols.values()].forEach((globalId, index) => + [...symbols.values()].forEach((symbol, index) => { + const keyLines = symbolKeyLines(host, symbol, `bag_symraw${index}`); lines.push( - ` %bag_symraw${index} = load ptr, ptr @${mangleGlobal(globalId)}`, + ...keyLines.load, ` %bag_sym${index} = call ptr @${host.dyn.toDynHelper(SYMBOL_T)}(ptr %bag_symraw${index})`, + ...keyLines.release, meta.def.tracksOwnFields ? ` call void @scr_dyn_symbol_key_placeholder(ptr %bag, ptr %bag_sym${index})` : ` call void @scr_dyn_key_delete_computed(ptr %bag, ptr %bag_sym${index}, i1 zeroext false)`, ` call void @scr_dyn_release_v(ptr %bag_sym${index})`, - ), - ); + ); + }); const { index } = classFieldIndex(meta, DYN_CLASS_PROPERTIES); lines.push( ` %bag_ptr = getelementptr inbounds %${classStructSym(t.className)}, ptr %target, i64 0, i32 ${index}`, @@ -705,6 +708,27 @@ export function liveDynUnionRefAdapter( return sym; } +/** The raw ScrSym of a class's symbol field key into `%name`: a module + * key is borrowed from its global, a well-known one comes from the + * runtime's registry (+1, released by the `release` lines once the key + * value holds it). */ +function symbolKeyLines( + host: LlvmEmitterContext, + symbol: NonNullable[number], + name: string, +): { load: string[]; release: string[] } { + if ("globalId" in symbol) + return { load: [` %${name} = load ptr, ptr @${mangleGlobal(symbol.globalId)}`], release: [] }; + host.declare("declare ptr @scr_sym_well_known(ptr)"); + host.declare("declare void @scr_sym_release(ptr)"); + return { + load: [ + ` %${name} = call ptr @scr_sym_well_known(ptr ${host.internLiteral(symbol.wellKnown)})`, + ], + release: [` call void @scr_sym_release(ptr %${name})`], + }; +} + export function streamTypedRefBoxValue( host: LlvmEmitterContext, B: BlockBuilder, @@ -929,8 +953,10 @@ export function streamTypedRefMaterializeAdapter( B.line(`${fieldValue} = sitofp i32 ${raw} to double`); } else if (inline) fieldValue = loadStructField(B, host.sizeType, fieldPtr, field.type, true); else B.line(`${fieldValue} = load ${llFieldType(field.type, false)}, ptr ${fieldPtr}`); - B.line(`${rawKey} = load ptr, ptr @${mangleGlobal(symbol.globalId)}`); + const keyLines = symbolKeyLines(host, symbol, rawKey.slice(1)); + for (const line of keyLines.load) B.line(line.trim()); const key = host.streamTypedRefBoxValue(B, SYMBOL_T, rawKey); + for (const line of keyLines.release) B.line(line.trim()); const afterSymbol = meta.def.tracksOwnFields || field.type.kind === "symbol" ? B.newLabel("symbol.after") @@ -1473,9 +1499,26 @@ function liveClassOps(host: LlvmEmitterContext, snapshot: string, meta: LlClassM // The constructor's name, as util.inspect prints before the fields. const jsName = meta.def.jsName ?? meta.def.name.replace(/^%/, ""); const className = jsName === "" ? "null" : host.internLiteral(jsName); + // Its Symbol.toStringTag getter's string, for Object.prototype.toString + // and util.inspect. + let stringTag = "null"; + if (meta.def.stringTagHelper) { + // The runtime lends the instance; the helper takes its own reference. + stringTag = `@${snapshot}_ctag`; + const retain = vAdapters(host.shapeHost, { kind: "object", className: meta.def.name }).retain; + host.resolveThunkDefs.push( + `define internal ptr ${stringTag}(ptr %p) ${FN_ATTRS} { ; Symbol.toStringTag of ${meta.def.name}`, + `entry:`, + ` %owned = call ptr ${retain}(ptr %p)`, + ` %tag = call ptr @${mangleFunction(meta.def.stringTagHelper)}(ptr %owned)`, + ` ret ptr %tag`, + `}`, + ``, + ); + } host.resolveThunkDefs.push( `@${names} = internal constant [${members.length} x ptr] [${literals.join(", ")}]`, - `@${ops} = internal constant { ptr, ${host.sizeType}, ptr, ptr } { ptr ${exact}, ${host.sizeType} ${members.length}, ptr @${names}, ptr ${className} }`, + `@${ops} = internal constant { ptr, ${host.sizeType}, ptr, ptr, ptr } { ptr ${exact}, ${host.sizeType} ${members.length}, ptr @${names}, ptr ${className}, ptr ${stringTag} }`, ``, ); } diff --git a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts index abf03811e..ad5f4a620 100644 --- a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts +++ b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts @@ -1,4 +1,5 @@ import { primitiveConstructorOr } from "./lower-exprs.js"; +import { TO_STRING_TAG_FIELD, wellKnownSymbolOfField } from "./symbol-fields.js"; import { InternalCompilerError } from "../../errors.js"; import { dynUndefinedExpr, helperLoc, nodeThrowExpr, varRef } from "../../ir/build.js"; import { constructedValue } from "./constructor-returns.js"; @@ -26,6 +27,7 @@ import { isUnitType, typeEquals, typeKey, + type IrClassDef, type IrExpr, type IrFunction, type IrParam, @@ -153,6 +155,41 @@ const STREAM_NUM_PROPERTIES = new Set([ const streamProperty = (name: string): boolean => STREAM_BOOL_PROPERTIES.has(name) || STREAM_NUM_PROPERTIES.has(name); +/** `(instance) => string`, the string a class's inherited + * Symbol.toStringTag getter answers, which the runtime reads for + * Object.prototype.toString and util.inspect of an instance seen as + * `unknown`. None for a class without a string getter, or whose own tag + * field shadows it. */ +function stringTagHelper(lowerer: Lowerer, info: ClassInfo, loc: SrcLoc): IrFunction | null { + if (info.fields.has(TO_STRING_TAG_FIELD)) return null; + const getter = findMethodOn(lowerer, info, "get:sym:toStringTag"); + if (getter?.sig.ret.kind !== "string") return null; + const type: IrType = { kind: "object", className: info.def.name }; + const owner = getter.declarer.def.name; + return { + name: `%class.stringTag:${info.def.name}`, + params: [{ localId: "this", name: "this", type }], + locals: [{ id: "this", name: "this", type, mutable: false }], + returnType: STRING, + body: [ + { + kind: "return", + value: accessorCall( + lowerer, + owner, + "get:sym:toStringTag", + lowerer.upcastTo(varRef("this", type, loc), owner), + [], + STRING, + loc, + ), + loc, + }, + ], + loc, + }; +} + function symbolMemberKey( lowerer: Lowerer, info: ClassInfo, @@ -1276,10 +1313,27 @@ export class ClassDynamicDispatch { const info = lowerer.classes.get(className); if (!info || info.builtinEmitter || info.builtinStream || info.builtinError) continue; if (info.symbolFields && info.def.symbolFields === undefined) { - info.def.symbolFields = [...info.symbolFields].flatMap(([symbol, field]) => { - const global = lowerer.globalsBySymbol.get(symbol); - return global?.type.kind === "symbol" ? [{ field, globalId: global.id }] : []; - }); + info.def.symbolFields = [...info.symbolFields].flatMap( + ([symbol, field]): NonNullable => { + const global = lowerer.globalsBySymbol.get(symbol); + if (global?.type.kind === "symbol") return [{ field, globalId: global.id }]; + const wellKnown = wellKnownSymbolOfField(field); + return wellKnown === null ? [] : [{ field, wellKnown }]; + }, + ); + } + const tagged = (current: ClassInfo): ClassInfo[] => [ + current, + ...current.subclasses.flatMap(tagged), + ]; + for (const current of tagged(info)) { + if (current.def.stringTagHelper !== undefined) continue; + const fn = stringTagHelper(lowerer, current, functions[0]!.loc); + if (!fn) continue; + current.def.stringTagHelper = fn.name; + this.generated.add(fn); + lowerer.liftedFns.push(fn); + changed = true; } if (this.prototypeHelper && !this.prototypeClasses.has(className)) { this.prototypeClasses.add(className); @@ -3554,10 +3608,29 @@ export class ClassDynamicDispatch { name, lowerer.coerceToExpected(varRef(global.id, global.type, loc), DYN), ); + } else if (wellKnownSymbolOfField(name) !== null) { + // A field keyed by a well-known symbol (Symbol.toStringTag). + symbols.set(name, { + kind: "dynFrom", + type: DYN, + loc, + value: { + kind: "libCall", + fn: "sym.wellKnown", + args: [ + { kind: "strLit", value: wellKnownSymbolOfField(name)!, type: STRING, loc }, + ], + type: SYMBOL_T, + loc, + }, + }); } } for (let owner: ClassInfo | null = info; owner; owner = owner.base) { - for (const name of [...owner.methods.keys()]) + for (const method of [...owner.methods.keys()]) { + // Accessors key by the property they define (`get [Symbol.toStringTag]`). + const name = + method.startsWith("get:") || method.startsWith("set:") ? method.slice(4) : method; if (name.startsWith("sym:")) { symbols.set(name, { kind: "dynFrom", @@ -3572,6 +3645,7 @@ export class ClassDynamicDispatch { }, }); } + } } const branches: IrStmt[] = []; if (!dispatch.write && !dispatch.reflect && !info.def.tracksOwnFields) { diff --git a/packages/compiler/src/frontend/lowering/class-method-mutations.ts b/packages/compiler/src/frontend/lowering/class-method-mutations.ts index 035c2c2a5..9a2632ed3 100644 --- a/packages/compiler/src/frontend/lowering/class-method-mutations.ts +++ b/packages/compiler/src/frontend/lowering/class-method-mutations.ts @@ -394,7 +394,19 @@ export function collectClassMethodMutations( (ts.isElementAccessExpression(base) && ts.isStringLiteralLike(base.argumentExpression) && base.argumentExpression.text === "prototype"); - if (prototype) { + // `Object.prototype.toString.call(value)` calls the builtin and + // keeps no reference to it, so it replaces nothing. + const builtinCall = + ts.isPropertyAccessExpression(node) && + ts.isPropertyAccessExpression(base) && + ts.isIdentifier(unwrap(base.expression)) && + lowerer.isStdlibGlobal(unwrap(base.expression) as ts.Identifier, "Object") && + ts.isPropertyAccessExpression(node.parent) && + node.parent.expression === node && + (node.parent.name.text === "call" || node.parent.name.text === "apply") && + ts.isCallExpression(node.parent.parent) && + node.parent.parent.expression === node.parent; + if (prototype && !builtinCall) { if (ts.isPropertyAccessExpression(node)) lowerer.noteMethodAccess(node.name.text, node); else if (ts.isStringLiteralLike(node.argumentExpression)) lowerer.noteMethodAccess(node.argumentExpression.text, node); diff --git a/packages/compiler/src/frontend/lowering/class-to-primitive.ts b/packages/compiler/src/frontend/lowering/class-to-primitive.ts index 0b107ab4e..a260116f8 100644 --- a/packages/compiler/src/frontend/lowering/class-to-primitive.ts +++ b/packages/compiler/src/frontend/lowering/class-to-primitive.ts @@ -13,6 +13,7 @@ import * as ts from "../ts7/adapter.js"; import type { Lowerer } from "./lowerer.js"; import { accessorCall, findMethodOn, type ClassInfo } from "./lower-classes.js"; import { isClassCallback } from "./class-callbacks.js"; +import { TO_STRING_TAG_FIELD } from "./symbol-fields.js"; import { isSafeToRepeat } from "./expressions/evaluation-safety.js"; import { DATE_TIME_FIELD, dateRootOf } from "./builtins/date-classes.js"; import { dateValueMethod } from "./builtins/dates.js"; @@ -29,7 +30,15 @@ type ConversionMethod = "sym:toPrimitive" | "valueOf" | "toString"; * Date`, or through Object.prototype.toString ("[object Object]"). */ type Plan = | { method: ConversionMethod; ret: IrType } - | { method: null; date?: "toString" | "valueOf" }; + | { method: null; date?: "toString" | "valueOf"; tag?: ToStringTag }; + +/** Where Object.prototype.toString finds a class's Symbol.toStringTag: a + * string field (`[Symbol.toStringTag] = "LRUCache"`) or a getter that + * returns a string, declared on `owner`. */ +interface ToStringTag { + owner: ClassInfo; + getter: boolean; +} const PRIMITIVE_KINDS = new Set(["f64", "string", "bool", "bigint", "undefinedT", "nullT"]); @@ -52,6 +61,17 @@ export function classToStringConversion( ); } +/** Object.prototype.toString of a program class instance: "[object " + + * its Symbol.toStringTag + "]" (an own tag field, else an inherited + * getter), or "[object Object]". The class's own conversion methods do not + * take part. Null as for classToStringConversion, and for Date subclasses. */ +export function classObjectTag(lowerer: Lowerer, value: IrExpr, node: ts.Node): IrExpr | null { + if (value.type.kind !== "object") return null; + const info = lowerer.classes.get(value.type.className); + if (!info || dateRootOf(info) !== null) return null; + return classConversion(lowerer, value, "tag", node, STRING, (tag) => tag); +} + /** ToNumber(ToPrimitive(value, "number")) of a program class instance * (`Number(x)`): `[Symbol.toPrimitive]("number")`, then `valueOf` and then * `toString`, and NaN for "[object Object]". Null as for @@ -122,7 +142,7 @@ function mayBeBigint(lowerer: Lowerer, type: IrType): boolean { function classConversion( lowerer: Lowerer, value: IrExpr, - hint: ConversionHint, + hint: ConversionHint | "tag", node: ts.Node, resultType: IrType, finish: (primitive: IrExpr) => IrExpr, @@ -131,7 +151,7 @@ function classConversion( const info = lowerer.classes.get(value.type.className); if (!info || !plainProgramClass(info)) return null; const classes = subtree(lowerer, info); - for (const cls of classes) refuseReplacedConversions(lowerer, cls, node); + if (hint !== "tag") for (const cls of classes) refuseReplacedConversions(lowerer, cls, node); const plans = new Map(classes.map((cls) => [cls, planOf(lowerer, cls, hint, node)])); // A class whose plan differs from its base's starts a group; the deepest // groups are tested first, so each instance takes its own class's plan. @@ -164,6 +184,41 @@ function classConversion( }; return finish(dateValueMethod(plan.date, time, loc)!); } + if (plan.method === null && plan.tag) { + // Object.prototype.toString: "[object " + the tag + "]". + const owner = plan.tag.owner.def.name; + const tag: IrExpr = plan.tag.getter + ? accessorCall( + lowerer, + owner, + "get:sym:toStringTag", + lowerer.upcastTo(object, owner), + [], + STRING, + loc, + ) + : { + kind: "fieldGet", + obj: lowerer.upcastTo(object, owner), + className: owner, + field: TO_STRING_TAG_FIELD, + type: STRING, + loc, + }; + return finish({ + kind: "strConcat", + left: { + kind: "strConcat", + left: { kind: "strLit", value: "[object ", type: STRING, loc }, + right: tag, + type: STRING, + loc, + }, + right: { kind: "strLit", value: "]", type: STRING, loc }, + type: STRING, + loc, + }); + } if (plan.method === null) return finish({ kind: "strLit", value: "[object Object]", type: STRING, loc }); const args: IrExpr[] = @@ -228,10 +283,28 @@ function depth(info: ClassInfo): number { } function samePlan(a: Plan, b: Plan): boolean { - return ( - a.method === b.method && - (a.method !== null || b.method !== null || a.date === (b as { date?: string }).date) - ); + if (a.method !== null || b.method !== null) return a.method === b.method; + return a.date === b.date && a.tag?.owner === b.tag?.owner && a.tag?.getter === b.tag?.getter; +} + +/** The class's Symbol.toStringTag, when it has one: the class at the top + * of the chain whose layout holds the tag field (an own property, which + * shadows any getter), or its getter. Other tag types would make + * Object.prototype.toString answer "Object" or the value depending on the + * run, and are refused. */ +function toStringTagOf(lowerer: Lowerer, info: ClassInfo, node: ts.Node): ToStringTag | null { + const type = info.fields.get(TO_STRING_TAG_FIELD); + if (type !== undefined) { + if (type.kind !== "string") refuse(lowerer, node, info, "a non-string Symbol.toStringTag"); + let owner = info; + while (owner.base?.fields.has(TO_STRING_TAG_FIELD)) owner = owner.base; + return { owner, getter: false }; + } + const getter = findMethodOn(lowerer, info, "get:sym:toStringTag"); + if (!getter) return null; + if (getter.sig.ret.kind !== "string") + refuse(lowerer, node, info, "a non-string Symbol.toStringTag"); + return { owner: getter.declarer, getter: true }; } /** A conversion method the class declares or inherits (a field of that @@ -246,7 +319,16 @@ function declared( return found ? { ret: found.sig.ret } : null; } -function planOf(lowerer: Lowerer, info: ClassInfo, hint: ConversionHint, node: ts.Node): Plan { +function planOf( + lowerer: Lowerer, + info: ClassInfo, + hint: ConversionHint | "tag", + node: ts.Node, +): Plan { + if (hint === "tag") { + const tag = toStringTagOf(lowerer, info, node); + return tag ? { method: null, tag } : { method: null }; + } const exotic = declared(lowerer, info, "sym:toPrimitive"); if (exotic) { if (!primitive(lowerer, exotic.ret)) @@ -271,7 +353,8 @@ function planOf(lowerer: Lowerer, info: ClassInfo, hint: ConversionHint, node: t refuse(lowerer, node, info, `a '${method}' method that can return an object`); return { method, ret: found.ret }; } - return { method: null }; + const tag = toStringTagOf(lowerer, info, node); + return tag ? { method: null, tag } : { method: null }; } function primitive(lowerer: Lowerer, type: IrType): boolean { @@ -292,8 +375,6 @@ function refuseReplacedConversions(lowerer: Lowerer, info: ClassInfo, node: ts.N if (lowerer.prototypeMethodAccesses.has(method)) refuse(lowerer, node, info, `a '${method}' the program reaches through a prototype`); } - if (findMethodOn(lowerer, info, "get:sym:toStringTag") || info.fields.has("sym:toStringTag")) - refuse(lowerer, node, info, "a Symbol.toStringTag"); } function refuse(lowerer: Lowerer, node: ts.Node, info: ClassInfo, what: string): never { diff --git a/packages/compiler/src/frontend/lowering/cycle-initialization.ts b/packages/compiler/src/frontend/lowering/cycle-initialization.ts index 4b1e74fcf..8c8ce06e6 100644 --- a/packages/compiler/src/frontend/lowering/cycle-initialization.ts +++ b/packages/compiler/src/frontend/lowering/cycle-initialization.ts @@ -707,11 +707,17 @@ function rewriteFunction( * unchecked. */ export function refuseUncheckedCycleReads( lowerer: Lowerer, - classes: readonly { baseValueGlobal?: string; symbolFields?: { globalId: string }[] }[], + classes: readonly { + baseValueGlobal?: string; + symbolFields?: readonly ({ globalId: string } | { wellKnown: string })[]; + }[], ): void { if (lowerer.cycleInitFlags.size === 0) return; for (const cls of classes) { - const ids = [cls.baseValueGlobal, ...(cls.symbolFields ?? []).map((f) => f.globalId)]; + const ids = [ + cls.baseValueGlobal, + ...(cls.symbolFields ?? []).map((f) => ("globalId" in f ? f.globalId : undefined)), + ]; for (const id of ids) { const flag = id === undefined ? undefined : lowerer.cycleInitFlags.get(id); if (flag === undefined) continue; diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 5366ca9d0..c9416df46 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -183,7 +183,7 @@ import { import { isSafeToDiscard } from "./expressions/evaluation-safety.js"; import { tryLowerExpression } from "./expressions/try-lower-expression.js"; import { lowerChildMethodValue, lowerChildPropertyCall } from "./handle-properties.js"; -import { classToNumberConversion } from "./class-to-primitive.js"; +import { classObjectTag, classToNumberConversion } from "./class-to-primitive.js"; import { hasRuntimeStatics } from "./class-runtime-statics.js"; import { structuralReadType } from "./class-unions.js"; import { @@ -3103,6 +3103,10 @@ function lowerObjectPrototypeCall( const immediate = immediateObjectTagReceiver(lowerer, receiverNode); const receiver = immediate?.effect ?? lowerer.lowerExpr(receiverNode); const tag = immediate?.tag ?? objectToStringTag(lowerer, receiver.type); + if (tag === null && immediate === null && call.arguments.nodes.length === 1) { + const classTag = classObjectTag(lowerer, receiver, receiverNode); + if (classTag) return classTag; + } // A generator object answers its tag through its checked capsule. if (tag === null && receiver.type.kind !== "dyn" && receiver.type.kind !== "generator") { lowerer.noLowering( diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index 9452cdf25..fb8c07a99 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -8156,7 +8156,10 @@ export function classMemberNameOf(lowerer: Lowerer, name: ts.PropertyName): stri member === "asyncIterator" || member === "dispose" || member === "asyncDispose" || - member === "toPrimitive" + member === "toPrimitive" || + // A toStringTag field keeps its symbol field name; its accessor and + // method forms take the method slot name. + (member === "toStringTag" && !ts.isPropertyDeclaration(name.parent)) ) { return `sym:${member}`; } diff --git a/packages/compiler/src/frontend/lowering/lower-inspect.ts b/packages/compiler/src/frontend/lowering/lower-inspect.ts index 5266d5c4e..ce9c35277 100644 --- a/packages/compiler/src/frontend/lowering/lower-inspect.ts +++ b/packages/compiler/src/frontend/lowering/lower-inspect.ts @@ -44,9 +44,9 @@ import { shapeKeyOrders, typeKey, } from "../../ir/ir.js"; -import type { ClassInfo } from "./lower-classes.js"; +import { accessorCall, findMethodOn, type ClassInfo } from "./lower-classes.js"; import { isSafeToDiscard, isSafeToRepeat } from "./expressions/evaluation-safety.js"; -import { symbolFieldDisplayName } from "./symbol-fields.js"; +import { symbolFieldDisplayName, TO_STRING_TAG_FIELD } from "./symbol-fields.js"; import { eventTargetRootOf } from "./lower-event-target.js"; import { dateRootOf } from "./builtins/date-classes.js"; import { lowerSystemErrorMap } from "./lower-system-errors.js"; @@ -1870,8 +1870,70 @@ function inspectHelper(lowerer: Lowerer, t: IrType, loc: SrcLoc): string { // observable way — Node's inspect omits them entirely (verified), // so a class whose only fields are private prints as `C {}`. const visible = info.def.fields.filter((f) => isClassOwnEnumerableFieldName(f.name)); + // A Symbol.toStringTag getter (an own tag field is listed instead) + // brackets the tag after the name, `Name [tag] {`, when it is a + // nonempty string other than the name. + const tagGetter = info.fields.has(TO_STRING_TAG_FIELD) + ? null + : findMethodOn(lowerer, info, "get:sym:toStringTag"); + let named: (plain: string, make: (head: IrExpr) => IrExpr) => IrExpr = (plain) => + strLit(plain, loc); + if (tagGetter?.sig.ret.kind === "string") { + const owner = tagGetter.declarer.def.name; + locals.push({ id: "tag.0", name: "tag", type: STRING, mutable: false }); + body.push({ + kind: "varDecl", + localId: "tag.0", + init: accessorCall( + lowerer, + owner, + "get:sym:toStringTag", + lowerer.upcastTo(v(), owner), + [], + STRING, + loc, + ), + loc, + }); + const tag = (): IrExpr => varRef("tag.0", STRING, loc); + const shown: IrExpr = { + kind: "logical", + op: "&&", + left: { + kind: "strEq", + negated: true, + left: tag(), + right: strLit("", loc), + type: BOOL, + loc, + }, + right: { + kind: "strEq", + negated: true, + left: tag(), + right: strLit(display, loc), + type: BOOL, + loc, + }, + type: BOOL, + loc, + }; + const head = concatAll( + [strLit(`${display === "" ? "Object" : display} [`, loc), tag(), strLit("]", loc)], + loc, + ); + named = (plain, make) => ({ + kind: "ternary", + cond: shown, + then: make(head), + else_: strLit(plain, loc), + type: STRING, + loc, + }); + } + const after = (text: string) => (head: IrExpr) => concatAll([head, strLit(text, loc)], loc); if (visible.length === 0) { - body = [ret(strLit(display === "" ? "{}" : `${display} {}`, loc))]; + body.push(ret(named(display === "" ? "{}" : `${display} {}`, after(" {}")))); break; } const get = (field: string, type: IrType): IrExpr => ({ @@ -1882,7 +1944,22 @@ function inspectHelper(lowerer: Lowerer, t: IrType, loc: SrcLoc): string { type, loc, }); - body = [depthGate(display === "" ? "[Object]" : `[${display}]`), ...begin()]; + body.push( + { + kind: "if", + cond: { kind: "bin", op: ">", left: r(), right: d(), type: BOOL, loc }, + then: [ + ret( + named(display === "" ? "[Object]" : `[${display}]`, (head) => + concatAll([strLit("[", loc), head, strLit("]", loc)], loc), + ), + ), + ], + else_: null, + loc, + }, + ...begin(), + ); // def.fields carries layout order: the base chain first, then own — // exactly the own-property insertion order of a constructor that // assigns in declaration order (SEMANTICS.md 36's stance). SYMBOL- @@ -1911,7 +1988,7 @@ function inspectHelper(lowerer: Lowerer, t: IrType, loc: SrcLoc): string { ret( end( strLit("", loc), - strLit(display === "" ? "{" : `${display} {`, loc), + named(display === "" ? "{" : `${display} {`, after(" {")), strLit("}", loc), false, boolLit(false, loc), diff --git a/packages/compiler/src/frontend/lowering/symbol-fields.ts b/packages/compiler/src/frontend/lowering/symbol-fields.ts index 56718615e..cdfb9e1b8 100644 --- a/packages/compiler/src/frontend/lowering/symbol-fields.ts +++ b/packages/compiler/src/frontend/lowering/symbol-fields.ts @@ -77,6 +77,8 @@ export function fenceSymbolFieldCopy( } export function classSymbolKeyOf(lowerer: Lowerer, key: ts.Expression): ClassSymbolKey | null { + const wellKnown = wellKnownSymbolKeyOf(lowerer, key); + if (wellKnown !== undefined) return wellKnown; if ( !ts.isIdentifier(key) && (!ts.isPropertyAccessExpression(key) || key.questionDotToken || !ts.isIdentifier(key.name)) @@ -90,6 +92,53 @@ export function classSymbolKeyOf(lowerer: Lowerer, key: ts.Expression): ClassSym return sym ? classSymbolKeyOfSymbol(lowerer, sym) : null; } +/** Well-known symbols a class field may be keyed by: those no protocol + * consults on an instance, or whose protocol the lowering reads from the + * field (Symbol.toStringTag, by the class string conversions). A field + * keyed by any other well-known symbol (Symbol.iterator, toPrimitive, + * hasInstance, ...) would be skipped by its protocol, so it keeps the + * computed-key refusal. */ +const FIELD_WELL_KNOWN_SYMBOLS: ReadonlySet = new Set(["toStringTag"]); + +/** The key of `Symbol.` on the standard global: undefined when the + * expression is not one, null when it is a well-known symbol a field may + * not be keyed by. The identity is the lib's declaration of the property, + * one symbol for every program reference. */ +function wellKnownSymbolKeyOf( + lowerer: Lowerer, + key: ts.Expression, +): ClassSymbolKey | null | undefined { + while (ts.isParenthesizedExpression(key)) key = key.expression; + if ( + !ts.isPropertyAccessExpression(key) || + key.questionDotToken || + !ts.isIdentifier(key.expression) || + !ts.isIdentifier(key.name) || + !lowerer.isStdlibGlobal(key.expression, "Symbol") + ) + return undefined; + const name = key.name.text; + const sym = lowerer.checker.getSymbolAtLocation(key.name); + if (!sym || !(lowerer.typeOf(key).flags & ts.TypeFlags.UniqueESSymbol)) return undefined; + if (!FIELD_WELL_KNOWN_SYMBOLS.has(name)) return null; + return { sym, identity: sym, fieldName: wellKnownSymbolFieldName(name) }; +} + +/** The layout name of a field keyed by the well-known `Symbol.`: a + * reserved symbol-field name, printed as Node spells the key. */ +export function wellKnownSymbolFieldName(name: string): string { + return `${FIELD_PREFIX}Symbol(Symbol.${name})`; +} + +/** The well-known symbol a field name is keyed by (`toStringTag`), or null. */ +export function wellKnownSymbolOfField(field: string): string | null { + const match = /^%symbol:Symbol\(Symbol\.(\w+)\)$/.exec(field); + return match === null ? null : match[1]!; +} + +/** The layout name of a `Symbol.toStringTag` field. */ +export const TO_STRING_TAG_FIELD = wellKnownSymbolFieldName("toStringTag"); + /** A literal Symbol()/Symbol.for() initialized once at module scope. The * whole-file proof also covers var declarations emitted by bundlers. Keys * cannot be used before initialization: a computed class field evaluates diff --git a/packages/compiler/src/ir/function-references.test.ts b/packages/compiler/src/ir/function-references.test.ts index 91e1d5f05..db872a525 100644 --- a/packages/compiler/src/ir/function-references.test.ts +++ b/packages/compiler/src/ir/function-references.test.ts @@ -157,10 +157,12 @@ const MODULE_FIELDS: Record>, Role> = { "classes[].errorNameAfter": "other", "classes[].prototypeDataHelper": "reference", "classes[].instancePrototypeHelper": "reference", + "classes[].stringTagHelper": "reference", "classes[].localCaptures[].name": "other", "classes[].localCaptures[].localId": "other", "classes[].symbolFields[].field": "other", "classes[].symbolFields[].globalId": "other", + "classes[].symbolFields[].wellKnown": "other", "classes[].fields[].name": "other", "classes[].methods[]": "method", "classes[].prototypeNames[]": "other", @@ -281,6 +283,10 @@ const REFERENCE_FIXTURES: Record IrModule> = { ...module(), classes: [{ name: "%m0.Cell", fields: [], instancePrototypeHelper: TARGET, loc }], }), + "classes[].stringTagHelper": () => ({ + ...module(), + classes: [{ name: "%m0.Cell", fields: [], stringTagHelper: TARGET, loc }], + }), "lib.exports[].fnName": () => ({ ...module(), lib: { diff --git a/packages/compiler/src/ir/function-references.ts b/packages/compiler/src/ir/function-references.ts index db474e9bb..6696a3c11 100644 --- a/packages/compiler/src/ir/function-references.ts +++ b/packages/compiler/src/ir/function-references.ts @@ -24,6 +24,7 @@ export function moduleFunctionReferences(mod: IrModule): string[] { for (const cls of mod.classes ?? []) { if (cls.prototypeDataHelper !== undefined) names.push(cls.prototypeDataHelper); if (cls.instancePrototypeHelper !== undefined) names.push(cls.instancePrototypeHelper); + if (cls.stringTagHelper !== undefined) names.push(cls.stringTagHelper); } return names; } diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index 0ec0043ce..4119ddcf3 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -1477,6 +1477,9 @@ export interface IrClassDef { prototypeDataHelper?: string; /** Native instance to its actual prototype, including factory captures and subclasses. */ instancePrototypeHelper?: string; + /** Native instance to the string its inherited Symbol.toStringTag getter + * answers, read by the runtime for an instance seen as `unknown`. */ + stringTagHelper?: string; /** Public JavaScript fields record their creation in the shared property * bag. Its descriptors preserve presence and insertion order independently * of native layout order; field values remain in their native slots. */ @@ -1486,8 +1489,10 @@ export interface IrClassDef { * class of the chain sets `name` during construction, and then an own * `name` follows every other own property. */ errorNameAfter?: string | null; - /** Stable module symbol identities for public instance layout fields. */ - symbolFields?: { field: string; globalId: string }[]; + /** Stable symbol identities for public instance layout fields: the + * module global holding the key, or the name of the well-known symbol + * (`toStringTag` for `Symbol.toStringTag`). */ + symbolFields?: ({ field: string } & ({ globalId: string } | { wellKnown: string }))[]; /** RUNTIME-PROVIDED class (the builtin Error hierarchy): the struct, RC * helpers, and vtable live in the runtime (ScrError / scr_error_*), so * backends emit no definitions for it — only the preorder-interval diff --git a/packages/compiler/src/ir/validate.ts b/packages/compiler/src/ir/validate.ts index c5b7e38f8..bd79d965b 100644 --- a/packages/compiler/src/ir/validate.ts +++ b/packages/compiler/src/ir/validate.ts @@ -501,10 +501,29 @@ export function validateModule(mod: IrModule): IrValidationError[] { }); } } - for (const symbol of cls.symbolFields ?? []) { - const global = mod.globals?.find((global) => global.id === symbol.globalId); + if (cls.stringTagHelper !== undefined) { + const helper = functionsByName.get(cls.stringTagHelper); + const receiver = helper?.params[0]?.type; if ( - global?.type.kind !== "symbol" || + !helper || + helper.params.length !== 1 || + receiver?.kind !== "object" || + receiver.className !== cls.name || + helper.returnType.kind !== "string" || + helper.captures !== undefined || + helper.classCaptures !== undefined + ) { + errors.push({ + message: `class ${cls.name}: string tag helper must be a noncapturing (instance) => string function`, + loc: cls.loc, + }); + } + } + for (const symbol of cls.symbolFields ?? []) { + const global = + "globalId" in symbol ? mod.globals?.find((global) => global.id === symbol.globalId) : null; + if ( + ("globalId" in symbol ? global?.type.kind !== "symbol" : symbol.wellKnown === "") || !cls.fields.some((field) => field.name === symbol.field) ) { errors.push({ message: `class ${cls.name}: invalid symbol field metadata`, loc: cls.loc }); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7751-class-well-known-symbol-fields.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7751-class-well-known-symbol-fields.ts.json new file mode 100644 index 000000000..2985bdf05 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7751-class-well-known-symbol-fields.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7751-class-well-known-symbol-fields.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index 9f7ddc527..21fed207e 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -398,6 +398,10 @@ typedef struct ScrDynTypedClassOps { size_t count; ScrStr *const *names; /* immortal member-name strings */ ScrStr *class_name; /* immortal constructor name; NULL for an anonymous class */ + /* The string an inherited Symbol.toStringTag getter answers for the + * instance (+1), or NULL with a pending exception from the getter; + * NULL when the class has no such getter. */ + ScrStr *(*string_tag)(void *instance); } ScrDynTypedClassOps; /* A compiled JavaScript class whose instances record their own properties @@ -915,6 +919,7 @@ void scr_dyn_install_iterator_symbol(ScrDyn *key); void scr_dyn_install_has_instance_symbol(ScrDyn *key); void scr_dyn_install_async_iterator_symbol(ScrDyn *key); void scr_dyn_install_async_dispose_symbol(ScrDyn *key); +void scr_dyn_install_to_string_tag_symbol(ScrDyn *key); /* True when key is Symbol.asyncDispose (registered by the symbol unit when * the program names it); handle symbol_get ops outside that unit use it. */ bool scr_dyn_is_async_dispose_symbol(const ScrDyn *key); @@ -1072,6 +1077,9 @@ ScrDyn *scr_record_source_apply(ScrDyn *snapshot, const void *rec); /* Attach the prototype member names of a class instance capsule * (idempotent), so `in` sees its methods and accessors. */ void scr_dyn_typed_ref_bind_class(ScrDyn *d, const ScrDynTypedClassOps *ops); +/* A class instance capsule's inherited Symbol.toStringTag string from its + * class's getter (+1); NULL when it has none or the getter threw. */ +ScrStr *scr_dyn_typed_ref_class_tag(const ScrDyn *d); /* Attach the bag and prototype hooks of a capsule of a bag-tracked class * instance (idempotent). */ void scr_dyn_typed_ref_bind_bag_class(ScrDyn *d, const ScrDynTypedBagClassOps *ops); diff --git a/packages/runtime/src/scr_inspect.c b/packages/runtime/src/scr_inspect.c index 1dce8d3c2..6777ef1ec 100644 --- a/packages/runtime/src/scr_inspect.c +++ b/packages/runtime/src/scr_inspect.c @@ -1207,6 +1207,19 @@ static bool insp_tag_names_class(const char *tag, const char *cls) { memcmp(tag + tag_len - cls_len, cls, cls_len) == 0; } +/* The Symbol.toStringTag a class instance inherits from its class's + * getter (+1), which Node brackets after the class name when it is a + * nonempty string other than the name. An own tag field is listed with + * the fields instead. */ +static ScrStr *insp_inherited_tag(const ScrDyn *instance, const ScrStr *name) { + ScrStr *tag = scr_dyn_typed_ref_class_tag(instance); + if (tag && (tag->len == 0 || (tag->len == name->len && memcmp(tag->data, name->data, name->len) == 0))) { + scr_str_release(tag); + return NULL; + } + return tag; +} + /* A native Set or Map held as a checked-dynamic value: `Set(n) { a, b }`, * `Map(n) { k => v }`, at most 100 entries like Node's maxArrayLength. */ /* Node's formatWeakCollection: the entries of a WeakMap or WeakSet are not @@ -1725,10 +1738,23 @@ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) { free(cls); } else if (name && materialized->kind == SCR_DYN_OBJ && scr_dyn_obj_get(materialized, "%error", 6) == NULL) { - char *cls = malloc(name->len + 1); + ScrStr *tag = insp_inherited_tag(d, name); + if (scr_exc_pending()) { + scr_dyn_release(materialized); + return scr_str_new("", 0); + } + size_t tag_len = tag ? tag->len + 3 : 0; + char *cls = malloc(name->len + tag_len + 1); if (!cls) scr_trap("scriptc: out of memory\n"); memcpy(cls, name->data, name->len); - cls[name->len] = '\0'; + if (tag) { + /* Node's `Name [tag]` prefix. */ + memcpy(cls + name->len, " [", 2); + memcpy(cls + name->len + 2, tag->data, tag->len); + cls[name->len + tag_len - 1] = ']'; + scr_str_release(tag); + } + cls[name->len + tag_len] = '\0'; size_t nseen = g_nseen; g_pending_seen = instance; out = scr_insp_obj(materialized, recurse, depth, cls); diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index a036e0dfd..fe890febd 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -202,6 +202,19 @@ void scr_dyn_install_has_instance_symbol(ScrDyn *key) { scr_atexit(scr_has_instance_symbol_cleanup); } +/* Symbol.toStringTag, installed when the program first evaluates it: no + * object holds the key before then. */ +static SCR_TL ScrDyn *scr_to_string_tag_symbol; +static void scr_to_string_tag_symbol_cleanup(void) { + scr_dyn_release(scr_to_string_tag_symbol); + scr_to_string_tag_symbol = NULL; +} +void scr_dyn_install_to_string_tag_symbol(ScrDyn *key) { + if (scr_to_string_tag_symbol) return; + scr_to_string_tag_symbol = scr_dyn_retain(key); + scr_atexit(scr_to_string_tag_symbol_cleanup); +} + void scr_dyn_install_iterator_symbol(ScrDyn *key) { if (scr_iterator_symbol) return; scr_iterator_symbol = scr_dyn_retain(key); @@ -3884,6 +3897,12 @@ static bool scr_dyn_name_in_strs(const ScrStr *key, ScrStr *const *names, size_t return false; } +ScrStr *scr_dyn_typed_ref_class_tag(const ScrDyn *d) { + if (!d || d->kind != SCR_DYN_TYPED_REF || d->prototype) return NULL; + const ScrDynTypedClassOps *ops = scr_typed_ref_class_ops(d); + return ops && ops->string_tag ? ops->string_tag(d->v.typed_ref.ptr) : NULL; +} + bool scr_dyn_typed_ref_class_has(const ScrDyn *d, const ScrStr *key) { if (!d || d->kind != SCR_DYN_TYPED_REF || d->prototype) return false; const ScrDynTypedClassOps *ops = scr_typed_ref_class_ops(d); @@ -7616,11 +7635,45 @@ void scr_dyn_throw(ScrDyn *d) { scr_dyn_trace_v, scr_dyn_is_object(d)); } +static ScrStr *scr_dyn_tag_string(const ScrStr *tag) { + ScrJsonBuf b; + scr_jb_init(&b); + scr_jb_puts(&b, "[object "); + scr_jb_write(&b, tag->data, tag->len); + scr_jb_putc(&b, ']'); + return scr_jb_finish(&b); +} + +/* Object.prototype.toString of an object whose own or inherited + * @@toStringTag is a string (+1), NULL otherwise or with a pending + * exception from its getter. */ +static ScrStr *scr_dyn_string_tag(const ScrDyn *d) { + ScrStr *getter_tag = scr_dyn_typed_ref_class_tag(d); + if (getter_tag) { + ScrStr *out = scr_dyn_tag_string(getter_tag); + scr_str_release(getter_tag); + return out; + } + if (scr_exc_pending() || !scr_to_string_tag_symbol) return NULL; + ScrDyn *tag = scr_dyn_symbol_key_get(d, scr_to_string_tag_symbol, true); + if (!tag) return NULL; + ScrStr *out = tag->kind == SCR_DYN_STR ? scr_dyn_tag_string(tag->v.str) : NULL; + scr_dyn_release(tag); + return out; +} + ScrStr *scr_dyn_object_tag(const ScrDyn *d) { if (d->kind == SCR_DYN_PROXY) { scr_dyn_proxy_unsupported("Symbol.toStringTag lookup"); return NULL; } + /* Object.prototype.toString answers a string @@toStringTag over the + * builtin tag of a plain object or a class instance. */ + if ((d->kind == SCR_DYN_OBJ || (d->kind == SCR_DYN_TYPED_REF && !scr_dyn_ref_is_error(d) && + !scr_dyn_generator(d)))) { + ScrStr *tag = scr_dyn_string_tag(d); + if (tag || scr_exc_pending()) return tag; + } if (d->kind == SCR_DYN_TYPED_REF) { if (scr_dyn_ref_is_error(d)) return scr_str_new("[object Error]", 14); if (scr_dyn_generator(d)) { @@ -8838,6 +8891,22 @@ ScrStr *scr_dyn_string_coerce_js(const ScrDyn *d) { return NULL; } if (d->kind == SCR_DYN_TYPED_REF) { + /* A class instance without its own conversion methods converts with + * Object.prototype.toString, which reads its toStringTag getter. */ + ScrStr *to_string_key = scr_str_new("toString", 8), *value_of_key = scr_str_new("valueOf", 7); + bool own_conversion = scr_dyn_typed_ref_class_has(d, to_string_key) || + scr_dyn_typed_ref_class_has(d, value_of_key); + scr_str_release(to_string_key); + scr_str_release(value_of_key); + if (!own_conversion) { + ScrStr *tag = scr_dyn_typed_ref_class_tag(d); + if (tag) { + ScrStr *out = scr_dyn_tag_string(tag); + scr_str_release(tag); + return out; + } + if (scr_exc_pending()) return NULL; + } ScrDyn *materialized = scr_dyn_typed_ref_string_view(d); ScrStr *out = scr_dyn_string_coerce_js(materialized); scr_dyn_release(materialized); @@ -8858,7 +8927,7 @@ ScrStr *scr_dyn_string_coerce_js(const ScrDyn *d) { scr_error_release(error); return text; } - return scr_str_new("[object Object]", 15); + return scr_dyn_object_tag(d); } if (!m || m->kind != SCR_DYN_FUNC) { scr_dyn_release(m); continue; } /* OrdinaryToPrimitive performs a method call, not a bare function diff --git a/packages/runtime/src/scr_symbol.c b/packages/runtime/src/scr_symbol.c index 647c31dc3..727e008b5 100644 --- a/packages/runtime/src/scr_symbol.c +++ b/packages/runtime/src/scr_symbol.c @@ -90,6 +90,11 @@ ScrSym *scr_sym_well_known(ScrStr *name) { scr_dyn_install_has_instance_symbol(key); scr_dyn_release(key); } + if (name->len == 11 && !memcmp(name->data, "toStringTag", 11)) { + ScrDyn *key = scr_dyn_new_symbol(symbol); + scr_dyn_install_to_string_tag_symbol(key); + scr_dyn_release(key); + } if (name->len == 13 && !memcmp(name->data, "asyncIterator", 13)) { ScrDyn *key = scr_dyn_new_symbol(symbol); scr_dyn_install_async_iterator_symbol(key); diff --git a/tests/corpus/7751-class-well-known-symbol-fields.ts b/tests/corpus/7751-class-well-known-symbol-fields.ts new file mode 100644 index 000000000..445af40d6 --- /dev/null +++ b/tests/corpus/7751-class-well-known-symbol-fields.ts @@ -0,0 +1,76 @@ +// Class fields keyed by well-known symbols, Symbol.toStringTag first (the +// lru-cache shape), beside toStringTag getters and module symbol keys. +// String conversion, Object.prototype.toString and util.inspect read the +// tag as Node does, through typed values and through `unknown`. + +const limit = Symbol("limit"); + +class Cache { + size = 0; + [limit] = 10; + [Symbol.toStringTag] = "LRUCache"; +} + +class Sub extends Cache { + extra = 1; +} + +class Retag extends Cache { + constructor() { + super(); + this[Symbol.toStringTag] = "Retagged"; + } +} + +class Tagged { + x = 1; + get [Symbol.toStringTag](): string { + return "Custom"; + } +} + +class TaggedSub extends Tagged { + y = 2; +} + +class Named { + get [Symbol.toStringTag](): string { + return "Named"; + } +} + +class Blank { + get [Symbol.toStringTag](): string { + return ""; + } +} + +class Plain { + n = 3; +} + +const c = new Cache(); +console.log(String(c), `${c}`, Object.prototype.toString.call(c), c[Symbol.toStringTag]); +console.log(c); +console.log(Object.keys(c), JSON.stringify(c)); +console.log(new Sub(), String(new Sub())); +const r: Cache = new Retag(); +console.log(String(r), r); +c[Symbol.toStringTag] = "Other"; +console.log(`${c}`, c); + +const t = new Tagged(); +console.log(String(t), `${t}`, t, [t], { deep: { deeper: { t } } }); +const ts: Tagged = new TaggedSub(); +console.log(String(ts), ts); +console.log(new Named(), new Blank(), String(new Blank())); +console.log(String(new Plain()), new Plain()); + +const values: unknown[] = [new Cache(), new Tagged(), new TaggedSub(), new Plain()]; +for (const v of values) { + console.log(Object.prototype.toString.call(v), String(v), (v as { [Symbol.toStringTag]?: unknown })[Symbol.toStringTag]); +} +console.log(values); + +const literal: unknown = { [Symbol.toStringTag]: "Literal", a: 1 }; +console.log(Object.prototype.toString.call(literal), String(literal), `${literal}`); diff --git a/tests/harness/corpus-costs/7751-class-well-known-symbol-fields.ts.json b/tests/harness/corpus-costs/7751-class-well-known-symbol-fields.ts.json new file mode 100644 index 000000000..5ed28c9dd --- /dev/null +++ b/tests/harness/corpus-costs/7751-class-well-known-symbol-fields.ts.json @@ -0,0 +1 @@ +{ "plain": 3800, "san": 4300 } From 4e87f45817348e105ca2bba225d65cb004526f56 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 16:16:09 -0500 Subject: [PATCH 027/259] Follow values through array properties, unknown keys, JSON callbacks, reflection and tagged templates Five gaps in the shape analysis let values escape or change unnoticed: - A store to a named property of an array was dropped, so a value read back from it and leaked did not escape. - Named loads on instances, classes and functions ignored values written under unknown keys. They now read that field once it exists, without creating it for atoms that have none. - JSON.parse never ran its reviver, and JSON.stringify never ran its replacer or the toJSON methods of the values it serializes. The reviver now runs with untracked values, the replacer with every serialized value (the holder as `this`), and toJSON on each value that has one. Their results are serialized in turn. - `new Proxy` and `Proxy.revocable` record a proxy operation on the target, and Reflect.deleteProperty records a delete, so those literals are G. - A tagged template now calls its tag with the strings array (with its `raw` array) and the substitutions, which were not evaluated before. --- .../src/frontend/shape-inference/analyze.ts | 184 +++++++++++++++++- .../src/frontend/shape-inference/domain.ts | 1 + .../compiler/test/shape-inference.test.ts | 83 +++++++- 3 files changed, 259 insertions(+), 9 deletions(-) diff --git a/packages/compiler/src/frontend/shape-inference/analyze.ts b/packages/compiler/src/frontend/shape-inference/analyze.ts index 55e0e0107..0a7b4d6d9 100644 --- a/packages/compiler/src/frontend/shape-inference/analyze.ts +++ b/packages/compiler/src/frontend/shape-inference/analyze.ts @@ -447,6 +447,10 @@ class Analyzer { id = this.newNode(); m.set(name, id); if (this.traceTop) this.nodeLabel.set(id, `${atom.label}.${name}`); + if (name === "*") { + for (const dst of this.unknownKeyReaders.get(atom) ?? []) this.edge(id, dst); + this.unknownKeyReaders.delete(atom); + } const reason = this.escaped.get(atom); if (reason !== undefined) { this.sink(id, reason); @@ -1367,10 +1371,7 @@ class Analyzer { return this.constNode(this.prim("number")); } if (ts.isSpreadElement(e)) return this.expr(e.expression); - if (ts.isTaggedTemplateExpression(e)) { - this.expr(e.tag); - return this.constNode(this.top); - } + if (ts.isTaggedTemplateExpression(e)) return this.taggedTemplate(e); if (ts.isYieldExpression(e)) { if (e.expression !== undefined) this.sink(this.expr(e.expression), `yielded at ${locLabel(e)}`); @@ -1695,6 +1696,25 @@ class Analyzer { return this.field(atom, "*"); } + /** Loads waiting for an atom's first write under an unknown key. */ + private readonly unknownKeyReaders = new Map(); + + /** dst ⊇ the values written to `atom` under unknown keys, now and later, + * without creating the field for atoms that have none. */ + unknownKeysInto(atom: Atom, dst: number): void { + const id = this.fields.get(atom)?.get("*"); + if (id !== undefined) { + this.edge(id, dst); + return; + } + let readers = this.unknownKeyReaders.get(atom); + if (readers === undefined) { + readers = []; + this.unknownKeyReaders.set(atom, readers); + } + readers.push(dst); + } + copyFields(src: number, dstAtom: Atom, site: Node): void { this.on(src, (a) => { if (a.kind === "top") { @@ -1728,6 +1748,60 @@ class Analyzer { /** Field copies re-run after solving rounds (fields created later). */ private readonly lateCopies: (() => void)[] = []; + /** node ⊇ the own field and element values of every value in it, now and + * later: the values JSON.stringify serializes. */ + childrenInto(node: number): void { + this.on(node, (a) => { + if ( + a.kind !== "object" && + a.kind !== "array" && + a.kind !== "instance" && + a.kind !== "dictionary" + ) + return; + const seen = new Set(); + const copy = (): void => { + for (const [name, id] of this.fields.get(a) ?? new Map()) { + if (seen.has(name) || name.startsWith("#")) continue; + seen.add(name); + this.edge(id, node); + } + const el = this.elements.get(a); + if (el !== undefined && !seen.has("[]")) { + seen.add("[]"); + this.edge(el, node); + } + }; + copy(); + this.lateCopies.push(copy); + }); + } + + /** JSON.stringify's call of `value.toJSON(key)` on a value that has one + * (a class member, or an own field once it exists); the result goes to `out`. */ + callToJSON( + value: Atom, + key: number, + out: number, + site: ts.CallExpression | ts.TaggedTemplateExpression, + ): void { + if (value.kind !== "object" && value.kind !== "instance" && value.kind !== "dictionary") return; + let called = false; + const call = (): void => { + if (called) return; + const has = + this.fields.get(value)?.has("toJSON") === true || + (value.kind === "instance" && this.lookupMember(value.node!, "toJSON", false) !== null); + if (!has) return; + called = true; + const fn = this.newNode(); + this.loadAtom(value, "toJSON", fn, site); + this.invoke(fn, this.constNode(value), [key], false, out, site); + }; + call(); + if (!called) this.lateCopies.push(call); + } + arrayLiteral(e: ts.ArrayLiteralExpression): number { const atom = this.atoms.intern(`arr:${this.nodeKey(e)}`, () => ({ kind: "array", @@ -1948,6 +2022,7 @@ class Analyzer { if (this.classChain(decl).some((c) => this.baseClass(c) === undefined)) this.add(dst, this.top); this.edge(this.field(a, name), dst); + this.unknownKeysInto(a, dst); return; } case "class": { @@ -1977,6 +2052,7 @@ class Analyzer { for (const c of this.classChain(decl)) { const cls = this.classAtoms(c).cls; this.edge(this.field(cls, name), dst); + this.unknownKeysInto(cls, dst); } return; } @@ -1986,7 +2062,10 @@ class Analyzer { else if (name === "prototype") this.add(dst, this.top); else if (name === "name") this.add(dst, this.prim("string")); else if (name === "length") this.add(dst, this.prim("number")); - else this.edge(this.field(a, name), dst); + else { + this.edge(this.field(a, name), dst); + this.unknownKeysInto(a, dst); + } return; case "array": if (name === "length") this.add(dst, this.prim("number")); @@ -2081,6 +2160,7 @@ class Analyzer { return; case "array": if (/^\d+$/.test(name)) this.edge(value, this.element(a)); + else if (name !== "length") this.edge(value, this.field(a, name)); return; case "prim": return; @@ -2149,6 +2229,37 @@ class Analyzer { // ---- calls --------------------------------------------------------------------------- + /** tag`…${x}…`: a call of the tag with the template's strings array (an + * array of strings with a `raw` array of strings) and each substitution. */ + taggedTemplate(e: ts.TaggedTemplateExpression): number { + this.noteSite(e); + const tag = unparen(e.tag); + const recv = + ts.isPropertyAccessExpression(tag) && tag.expression.kind !== ts.SyntaxKind.SuperKeyword + ? this.expr(tag.expression) + : null; + const callee = recv === null ? this.expr(tag) : null; + const strings = this.syntheticArray(e, "template"); + const raw = this.syntheticArray(e.template, "raw"); + this.add(this.element(strings), this.prim("string")); + this.add(this.element(raw), this.prim("string")); + this.add(this.field(strings, "raw"), raw); + const args = [this.constNode(strings)]; + if (ts.isTemplateExpression(e.template)) + for (const span of list(e.template.templateSpans)) args.push(this.expr(span.expression)); + const dst = this.newNode(); + if (recv !== null && ts.isPropertyAccessExpression(tag)) { + const name = tag.name.text; + this.ops.push({ kind: "read", recv, name, node: tag }); + this.on(recv, (a) => { + const fn = this.newNode(); + this.loadAtom(a, name, fn, tag); + this.invoke(fn, this.constNode(a), args, false, dst, e); + }); + } else this.invoke(callee!, null, args, false, dst, e); + return dst; + } + args(e: ts.CallExpression | ts.NewExpression): { args: number[]; spread: boolean } { const out: number[] = []; let spread = false; @@ -2245,7 +2356,7 @@ class Analyzer { args: number[], spread: boolean, dst: number, - site: ts.CallExpression, + site: ts.CallExpression | ts.TaggedTemplateExpression, ): void { const undefNode = recv === null ? this.constNode(this.prim("undefined")) : recv; this.on(callee, (a) => { @@ -2358,6 +2469,13 @@ class Analyzer { this.add(dst, this.syntheticArray(site, "Array")); return; } + case "Proxy": + // The handler's traps run on every operation with the target. + if (args[0] !== undefined) + this.ops.push({ kind: "proxy", recv: args[0], name: null, node: site }); + for (const x of args) this.sink(x, `argument of new Proxy at ${locLabel(site)}`); + this.add(dst, this.top); + return; default: for (const x of args) this.sink(x, `argument of new ${path} at ${locLabel(site)}`); this.add(dst, this.top); @@ -2370,7 +2488,7 @@ class Analyzer { args: number[], spread: boolean, dst: number, - site: ts.CallExpression, + site: ts.CallExpression | ts.TaggedTemplateExpression, recvNode: number | null, ): void { const path = a.path ?? ""; @@ -2768,12 +2886,62 @@ class Analyzer { return; } case "JSON.parse": + // A reviver runs on every parsed value with its key, the holder as `this`. + if (args[1] !== undefined) + this.on(args[1], (f) => { + if (f.kind === "function") + this.callFunction( + this.infoOfAtom(f)!, + this.constNode(this.top), + [this.constNode(this.prim("string")), this.constNode(this.top)], + false, + this.newNode(), + site, + ); + }); this.add(dst, this.top); return; - case "JSON.stringify": + case "JSON.stringify": { + // Every value it serializes: toJSON methods run on them, and a + // replacer function with each key and value, the holder as `this`. + // Their results are serialized in turn. + const serialized = this.newNode(); + this.childrenInto(serialized); + this.edge(arg(0), serialized); + const key = this.constNode(this.prim("string")); + this.on(serialized, (v) => this.callToJSON(v, key, serialized, site)); + if (args[1] !== undefined) + this.on(args[1], (f) => { + if (f.kind === "function") + this.callFunction( + this.infoOfAtom(f)!, + serialized, + [key, serialized], + false, + serialized, + site, + ); + else if (f.kind === "top") + this.sink(serialized, `JSON.stringify replacer at ${locLabel(site)}`); + }); prim("string"); prim("undefined"); return; + } + case "Reflect.deleteProperty": { + const key = ts.isCallExpression(site) ? unparen(list(site.arguments)[1]!) : undefined; + const name = + key !== undefined && (ts.isStringLiteral(key) || ts.isNoSubstitutionTemplateLiteral(key)) + ? key.text + : null; + this.ops.push({ kind: "delete", recv: arg(0), name, node: site }); + prim("boolean"); + return; + } + case "Proxy.revocable": + this.ops.push({ kind: "proxy", recv: arg(0), name: null, node: site }); + escapeAll(); + return; case "String": case "encodeURIComponent": case "decodeURIComponent": diff --git a/packages/compiler/src/frontend/shape-inference/domain.ts b/packages/compiler/src/frontend/shape-inference/domain.ts index 36978d4c9..d90a83cf2 100644 --- a/packages/compiler/src/frontend/shape-inference/domain.ts +++ b/packages/compiler/src/frontend/shape-inference/domain.ts @@ -105,6 +105,7 @@ export const MODELED_GLOBALS: ReadonlySet = new Set([ "encodeURI", "decodeURI", "BigInt", + "Proxy", ]); /** Results of string (and number) methods, by name. Anything else is ⊤. */ diff --git a/packages/compiler/test/shape-inference.test.ts b/packages/compiler/test/shape-inference.test.ts index 3cd6e809d..b4c898025 100644 --- a/packages/compiler/test/shape-inference.test.ts +++ b/packages/compiler/test/shape-inference.test.ts @@ -49,6 +49,36 @@ export const str = () => new Str({ checks: [] }); export const obj = (shape) => new Obj({ shape }); export function leak(value) { globalThis.leaked = value; return value; } export function reflect() { const o = { a: 1 }; delete o.a; return o; } +class Box {} +function tag(strings, ...values) { leak(values[0]); return strings.raw.length; } +export function arrayProp() { const list = []; list.meta = { listed: 1 }; return leak(list.meta); } +export function computedField(k) { + const box = new Box(); + box[k] = { boxed: 1 }; + Box[k] = { onClass: 1 }; + const fn = function () {}; + fn[k] = { onFunction: 1 }; + return [leak(box.held), leak(Box.held), leak(fn.held)]; +} +export function revive(text) { + const seen = { revived: 1 }; + return JSON.parse(text, function (k, v) { globalThis.revived = seen; return v; }); +} +class Doc { + constructor() { this.body = { doc: 1 }; } + toJSON() { return leak(this.body); } +} +export function stringified() { + const own = { owned: 1 }; + return [ + JSON.stringify({ inner: { replaced: 1 } }, (k, x) => leak(x)), + JSON.stringify(new Doc()), + JSON.stringify({ toJSON() { return leak(own); } }), + ]; +} +export function proxied() { return new Proxy({ proxied: 1 }, {}); } +export function reflectDelete() { const o = { gone: 1 }; Reflect.deleteProperty(o, "gone"); return o; } +export function tagged() { return tag\`a\${{ part: 1 }}b\`; } `; const packageTypes = ` @@ -59,14 +89,43 @@ export declare const str: () => Str; export declare const obj: (shape: Record) => Obj; export declare function leak(value: T): T; export declare function reflect(): object; +export declare function arrayProp(): unknown; +export declare function computedField(k: string): unknown; +export declare function revive(text: string): unknown; +export declare function stringified(): unknown; +export declare function proxied(): unknown; +export declare function reflectDelete(): unknown; +export declare function tagged(): unknown; `; const mainSource = ` -import { leak, obj, reflect, str } from "shapes-fixture"; +import { + arrayProp, + computedField, + leak, + obj, + proxied, + reflect, + reflectDelete, + revive, + str, + stringified, + tagged, +} from "shapes-fixture"; const schema = obj({ a: str(), b: str() }); const input: unknown = JSON.parse('{"a":"x","b":"y"}'); console.log(JSON.stringify(schema.parse(input))); console.log(JSON.stringify(leak({ kept: 1 })), JSON.stringify(reflect())); +const more = [ + arrayProp(), + computedField("held"), + revive("{}"), + stringified(), + proxied(), + reflectDelete(), + tagged(), +]; +console.log(more.length); `; let dir: string; @@ -152,6 +211,28 @@ test("S1 report: per-field temporaries are provable records, dynamic objects sta expect(lines.find((l) => l.startsWith("class Str"))).toMatch(/_def: \{checks\}@/); }); +test("S1 report follows values through array properties, unknown keys, callbacks and reflection", async () => { + const lines = await report(); + // a named property of an array, read back and leaked + expect(site(lines, /^site \{listed\}@/)).toMatch(/: P-escaping/); + // computed writes to an instance, a class and a function, read by name + expect(site(lines, /^site \{boxed\}@/)).toMatch(/: P-escaping/); + expect(site(lines, /^site \{onClass\}@/)).toMatch(/: P-escaping/); + expect(site(lines, /^site \{onFunction\}@/)).toMatch(/: P-escaping/); + // a JSON.parse reviver, a JSON.stringify replacer, and toJSON methods + expect(site(lines, /^site \{revived\}@/)).toMatch(/: P-escaping — escapes: stored into ⊤/); + expect(site(lines, /^site \{replaced\}@/)).toMatch(/: P-escaping/); + expect(site(lines, /^site \{doc\}@/)).toMatch(/: P-escaping/); + expect(site(lines, /^site \{owned\}@/)).toMatch(/: P-escaping/); + // a Proxy target and Reflect.deleteProperty + expect(site(lines, /^site \{proxied\}@/)).toMatch(/: G — proxy at/); + expect(site(lines, /^site \{gone\}@/)).toMatch(/: G — delete at/); + // a tagged template's substitution, passed to its tag + expect(site(lines, /^site \{part\}@/)).toMatch(/: P-escaping/); + // the existing verdicts hold + expect(site(lines, /^site \{kept\}@main\.ts/)).toMatch(/: P-escaping — escapes: stored into ⊤/); +}); + test("S1 report is off by default and changes nothing", async () => { delete process.env["SCRIPTC_DEBUG_SHAPES"]; const writes = vi.spyOn(process.stderr, "write"); From 068e77274d2efa9d14e43813a55d5586e044073f Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 17:26:47 -0500 Subject: [PATCH 028/259] Forward pointer-union wraps of call arguments to the callee's parameter proof A call argument that wraps a binding into a nullable-pointer union passes the binding's pointer itself. The call-lifetimes analysis now treats it like the bare binding, so a record or instance passed to a `T | undefined` parameter that is only projected keeps its frame storage and result slot. --- .../src/backend/llvm/call-lifetimes.test.ts | 46 +++++++ .../src/backend/llvm/call-lifetimes.ts | 20 ++- packages/compiler/src/backend/llvm/emitter.ts | 1 + ...-pointer-union-forwarded-arguments.ts.json | 6 + .../7660-pointer-union-forwarded-arguments.ts | 127 ++++++++++++++++++ 5 files changed, 196 insertions(+), 4 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7660-pointer-union-forwarded-arguments.ts.json create mode 100644 tests/corpus/7660-pointer-union-forwarded-arguments.ts diff --git a/packages/compiler/src/backend/llvm/call-lifetimes.test.ts b/packages/compiler/src/backend/llvm/call-lifetimes.test.ts index 90909a024..52b2a8775 100644 --- a/packages/compiler/src/backend/llvm/call-lifetimes.test.ts +++ b/packages/compiler/src/backend/llvm/call-lifetimes.test.ts @@ -760,3 +760,49 @@ test("a parameter stored as its last use takes the owned convention", () => { const passed = ctor([{ kind: "exprStmt", expr: call("use", [ref("item", cell)]), loc }]); expect(analyze(passed).borrowed.get("%Box.constructor")).toEqual(new Set([0, 1])); }); + +test("a wrap into a pointer union forwards the wrapped binding to the callee's parameter", () => { + const wrap = (id: string): IrExpr => ({ + kind: "unionWrap", + unionId: "optional", + tag: 0, + value: ref(id, record), + type: optional, + loc, + }); + const leaf = helper("leaf"); + const outer = helper("outer"); + outer.params[0]!.type = outer.locals[0]!.type = record; + outer.locals.push(local("cell", record)); + outer.body = [ + { + kind: "varDecl", + localId: "cell", + init: { kind: "recordLit", fields: [], type: record, loc }, + loc, + }, + { kind: "exprStmt", expr: call("leaf", [wrap("value")]), loc }, + ret(call("leaf", [wrap("cell")])), + ]; + const functions = new Map([leaf, outer].map((fn) => [fn.name, fn])); + const analyzeWith = (pointer: boolean) => + analyzeCallLifetimes( + functions, + undefined, + undefined, + undefined, + undefined, + undefined, + () => pointer, + ); + // A boxed union builds a new box around the payload: a whole-value use. + expect(analyzeWith(false).parameters.get("outer")).toBeUndefined(); + expect(analyzeWith(false).locals.get("outer")).toEqual(new Set()); + // A pointer union passes the payload pointer itself. + expect(analyzeWith(true).parameters.get("outer")).toEqual(new Set([0])); + expect(analyzeWith(true).locals.get("outer")).toEqual(new Set(["cell"])); + // A callee that keeps its parameter keeps the wrapped binding too. + leaf.body.push(ret(ref("value"))); + expect(analyzeWith(true).parameters.get("outer")).toBeUndefined(); + expect(analyzeWith(true).locals.get("outer")).toEqual(new Set()); +}); diff --git a/packages/compiler/src/backend/llvm/call-lifetimes.ts b/packages/compiler/src/backend/llvm/call-lifetimes.ts index db5bdb574..8055c7958 100644 --- a/packages/compiler/src/backend/llvm/call-lifetimes.ts +++ b/packages/compiler/src/backend/llvm/call-lifetimes.ts @@ -99,12 +99,18 @@ const NO_INLINE_FIELDS: InlineFieldTest = { record: () => false, classField: () * reads the record and keeps no reference to it. */ export type RecordDynCopyTest = (shapeId: string) => boolean; +/** Wraps into a nullable-pointer union whose value is the payload pointer + * itself (LlEmitter.borrowableNullableWrap): the wrapped binding reaches the + * callee's parameter unchanged. */ +export type PointerWrapTest = (wrap: IrExpr & { kind: "unionWrap" }) => boolean; + function collectUses( fn: IrFunction, nullableField: NullableFieldTest, registerReturn: boolean, inlineField: InlineFieldTest, recordDynCopy: RecordDynCopyTest, + pointerWrap: PointerWrapTest, ): Uses { const uses: Uses = { invalid: new Set(), @@ -200,12 +206,16 @@ function collectUses( return node.args.every(expr); case "call": node.args.forEach((arg, index) => { - if (arg.kind !== "varRef") { + const value = + arg.kind === "unionWrap" && arg.value.kind === "varRef" && pointerWrap(arg) + ? arg.value + : arg; + if (value.kind !== "varRef") { expr(arg); return; } - let forwards = uses.forwards.get(arg.localId); - if (!forwards) uses.forwards.set(arg.localId, (forwards = [])); + let forwards = uses.forwards.get(value.localId); + if (!forwards) uses.forwards.set(value.localId, (forwards = [])); forwards.push({ callee: node.callee, index }); }); return true; @@ -345,6 +355,7 @@ export function analyzeCallLifetimes( registerReturns: ReadonlySet = new Set(), inlineField: InlineFieldTest = NO_INLINE_FIELDS, recordDynCopy: RecordDynCopyTest = () => false, + pointerWrap: PointerWrapTest = () => false, ): CallLifetimes { const usesByFunction = new Map(); const lazyCaptures = new LazyCaptures(functions); @@ -361,7 +372,7 @@ export function analyzeCallLifetimes( }; for (const fn of functions.values()) { if (fn.generator !== undefined && fn.classCaptures === undefined) { - const uses = collectUses(fn, nullableField, false, inlineField, recordDynCopy); + const uses = collectUses(fn, nullableField, false, inlineField, recordDynCopy, pointerWrap); const locals = new Map(fn.locals.map((local) => [local.id, local])); const stable = new Set(); for (const param of fn.params) { @@ -386,6 +397,7 @@ export function analyzeCallLifetimes( registerReturns.has(fn.name), inlineField, recordDynCopy, + pointerWrap, ); usesByFunction.set(fn.name, uses); // Class-capturing bodies get only local facts (computed below from diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 8e6b88a3a..b2454b9fa 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -1774,6 +1774,7 @@ export class LlEmitter { const shape = this.recordsById.get(shapeId); return shape !== undefined && !recordDynKeepsIdentity(shape); }, + (wrap) => this.borrowableNullableWrap(wrap) === "ref", ); this.lentStringParameters = this.debug === null ? findLentStringParameters(this.fnByName, this.callLifetimes) : new Map(); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7660-pointer-union-forwarded-arguments.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7660-pointer-union-forwarded-arguments.ts.json new file mode 100644 index 000000000..8f317668f --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7660-pointer-union-forwarded-arguments.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7660-pointer-union-forwarded-arguments.ts" + ], + "diags": [] +} diff --git a/tests/corpus/7660-pointer-union-forwarded-arguments.ts b/tests/corpus/7660-pointer-union-forwarded-arguments.ts new file mode 100644 index 000000000..664f79fcb --- /dev/null +++ b/tests/corpus/7660-pointer-union-forwarded-arguments.ts @@ -0,0 +1,127 @@ +// Records and class instances passed to `T | undefined` and `T | null` +// parameters. The callee receives the object pointer itself, so a binding +// that the callee only reads keeps its frame storage; callees that keep, +// return or compare the argument still see one shared object. +interface Vec { + x: number; + y: number; +} +interface Tagged { + name: string; + at: Vec; +} +function vec(x: number, y: number): Vec { + return { x, y }; +} +function len(v: Vec | undefined): number { + return v === undefined ? -1 : Math.sqrt(v.x * v.x + v.y * v.y); +} +function sum(a: Vec | undefined, b: Vec): Vec { + return a === undefined ? b : { x: a.x + b.x, y: a.y + b.y }; +} +function label(t: Tagged | undefined): string { + return t === undefined ? "none" : t.name + "@" + t.at.x + "," + t.at.y; +} +function depth(v: Vec | undefined, n: number): number { + if (v === undefined || n === 0) return 0; + return v.x + depth(v, n - 1); +} + +const kept: (Vec | undefined)[] = []; +function keep(v: Vec | undefined): number { + kept.push(v); + return kept.length; +} +function same(a: Vec | undefined, b: Vec): boolean { + return a === b; +} +function orNull(v: Vec | undefined): Vec | undefined { + return v !== undefined && v.x < 0 ? undefined : v; +} + +class Cell { + value: number; + next: Cell | null; + constructor(value: number, next: Cell | null) { + this.value = value; + this.next = next; + } +} +function cellTotal(c: Cell | null): number { + let total = 0; + for (let at = c; at !== null; at = at.next) total += at.value; + return total; +} +function fail(v: Vec | undefined): number { + if (v !== undefined && v.x > 100) throw new Error("too far: " + v.x); + return v === undefined ? 0 : v.x; +} + +function projections(): void { + const a = vec(3, 4); + const b = sum(a, vec(1, 1)); + console.log("len", len(a), len(b), len(undefined)); + const c = sum(sum(a, b), a); + console.log("sum", c.x, c.y, sum(undefined, a).x); + console.log("depth", depth(a, 5), depth(undefined, 3)); + let total = 0; + for (let i = 0; i < 1000; i++) { + const p = vec(i, i + 1); + total += len(p) + len(sum(p, a)); + } + console.log("loop", total.toFixed(6)); +} + +function mutated(): void { + const p = vec(1, 2); + console.log("before", len(p)); + p.x = 6; + p.y = 8; + console.log("after", len(p)); +} + +function strings(): void { + const prefix = ["a", "b", "c"].join("-"); + const t: Tagged = { name: prefix + "!", at: vec(2, 5) }; + console.log("label", label(t), label(undefined)); + const u: Tagged = { name: label(t), at: t.at }; + console.log("nested", label(u)); +} + +function escapes(): void { + const a = vec(7, 8); + const count = keep(a); + const b = vec(9, 10); + console.log("kept", count, kept[0] === a, kept[0]!.x, keep(b), kept[1]!.y); + a.x = 70; + console.log("shared", kept[0]!.x); + const c = vec(1, 1); + console.log("same", same(c, c), same(c, vec(1, 1)), same(undefined, c)); + const d = vec(-1, 2); + const e = vec(4, 5); + console.log("returned", orNull(d), orNull(e) === e, orNull(e)!.y); +} + +function classes(): void { + const tail = new Cell(3, null); + const list = new Cell(1, new Cell(2, tail)); + console.log("cells", cellTotal(list), cellTotal(tail), cellTotal(null)); +} + +function throwing(): void { + const near = vec(5, 0); + const far = vec(500, 0); + try { + console.log("near", fail(near)); + console.log("far", fail(far)); + } catch (e) { + console.log("caught", (e as Error).message, near.x, far.x); + } +} + +projections(); +mutated(); +strings(); +escapes(); +classes(); +throwing(); From 8afec299b7816138e187c8f18e6d2c1a1f46e771 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 17:52:58 -0500 Subject: [PATCH 029/259] Kill corpus 6611's children after they start, and run the second module after the first close The children 6611 spawned ran `process.stdout.write('ok')` and were killed right after spawn. When a child exited before the SIGTERM took effect, Node reported `close 0` for it and closed it after the second child, so the expected output depended on process start-up timing. - The program re-runs itself as the child (`main.cjs child`), which writes `ready` and then waits. Each parent kills its child on the first stdout data, so both closes report `null` and `SIGTERM`. - definer.cjs runs on the first child's `close` instead of its `exit`, so the first close always prints before the second module's output. --- .../definer.cjs | 2 +- .../main.cjs | 33 +++++++++++-------- .../spawner.cjs | 2 +- 3 files changed, 22 insertions(+), 15 deletions(-) diff --git a/tests/corpus/6611-child-properties-across-modules/definer.cjs b/tests/corpus/6611-child-properties-across-modules/definer.cjs index 8b1c8f1a3..ea58bc046 100644 --- a/tests/corpus/6611-child-properties-across-modules/definer.cjs +++ b/tests/corpus/6611-child-properties-across-modules/definer.cjs @@ -21,5 +21,5 @@ module.exports = function run() { console.log(e instanceof TypeError, e.message.length, e.message.slice(0, 30), e.message.slice(-40)); } child.on("close", (code) => console.log("close", code, child.killedBy)); - child.kill("SIGTERM"); + child.stdout.once("data", () => child.kill("SIGTERM")); }; diff --git a/tests/corpus/6611-child-properties-across-modules/main.cjs b/tests/corpus/6611-child-properties-across-modules/main.cjs index a3f422c64..3dfb6756a 100644 --- a/tests/corpus/6611-child-properties-across-modules/main.cjs +++ b/tests/corpus/6611-child-properties-across-modules/main.cjs @@ -5,17 +5,24 @@ // and writes a getter-only property with a long name. const patched = require("./patcher.cjs"); const definer = require("./definer.cjs"); -const child = patched(); -console.log(child.label); -child.label = "x"; -console.log(child.stored, child.same); -try { - child.same = 1; -} catch (e) { - console.log(e instanceof TypeError, e.message); +if (process.argv.at(2) === "child") { + // The child reports that it started, then waits for the parent's SIGTERM. + // It exits after 30 seconds without one. + process.stdout.write("ready"); + setTimeout(() => {}, 30000); +} else { + const child = patched(); + console.log(child.label); + child.label = "x"; + console.log(child.stored, child.same); + try { + child.same = 1; + } catch (e) { + console.log(e instanceof TypeError, e.message); + } + child.on("close", (code) => { + console.log("close", code, child.killedBy); + }); + child.stdout.once("data", () => child.kill("SIGTERM")); + child.on("close", () => definer()); } -child.on("close", (code) => { - console.log("close", code, child.killedBy); -}); -child.kill("SIGTERM"); -child.on("exit", () => definer()); diff --git a/tests/corpus/6611-child-properties-across-modules/spawner.cjs b/tests/corpus/6611-child-properties-across-modules/spawner.cjs index d0c52d9b7..5701145a8 100644 --- a/tests/corpus/6611-child-properties-across-modules/spawner.cjs +++ b/tests/corpus/6611-child-properties-across-modules/spawner.cjs @@ -1,5 +1,5 @@ "use strict"; const { spawn } = require("child_process"); module.exports = function start() { - return spawn(process.execPath, ["-e", "process.stdout.write('ok')"]); + return spawn(process.execPath, [process.argv[1], "child"]); }; From 072543f5b98e5757b73a23b00127e8c7e2186417 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 18:01:19 -0500 Subject: [PATCH 030/259] Support X509Certificate fields and methods, TLS certificates and tls.Server contexts --- docs/content/docs/limitations.mdx | 8 + .../limitations/builtin-apis/crypto.mdx | 4 + docs/content/limitations/tls-certificates.mdx | 11 + docs/content/limitations/tls-sessions.mdx | 3 + .../src/generated/node-v24-compatibility.json | 126 +- .../generated/node-v24-internal.json | 232 ++- internal/compatibility/static-support.json | 8 + .../ambient/scriptc-node-fallback.d.ts | 108 +- .../src/backend/executable-features.ts | 1 + packages/compiler/src/backend/library-pack.ts | 1 + .../compiler/src/backend/llvm/lib-shared.ts | 22 + packages/compiler/src/backend/llvm/lib-tls.ts | 25 + .../src/backend/native-link-info-core.ts | 3 + .../compiler/src/backend/native/contracts.ts | 4 + .../compiler/src/backend/native/executable.ts | 3 + .../compiler/src/backend/native/library.ts | 3 +- .../src/backend/runtime-pack-targets.test.ts | 1 + .../compiler/src/backend/runtime-pack.test.ts | 1 + packages/compiler/src/backend/warm-cache.ts | 1 + .../src/executable/executable-cache.test.ts | 1 + .../src/executable/executable-cache.ts | 2 + .../src/frontend/lowering/builtins/x509.ts | 487 +++++ .../frontend/lowering/expressions/binary.ts | 2 + .../lowering/expressions/object-literals.ts | 8 + .../lowering/expressions/property-access.ts | 6 + .../src/frontend/lowering/lower-calls.ts | 3 + .../src/frontend/lowering/lower-classes.ts | 286 ++- .../src/frontend/lowering/lower-server.ts | 125 +- .../src/frontend/lowering/lower-stmts.ts | 2 + .../compiler/src/frontend/lowering/lowerer.ts | 3 + packages/compiler/src/frontend/type-mapper.ts | 74 +- packages/compiler/src/index.ts | 3 + packages/compiler/src/ir/builtin-effects.ts | 15 + .../compiler/src/ir/builtin-signatures.ts | 46 + packages/compiler/src/ir/runtime-features.ts | 32 + packages/compiler/src/library/ir-policy.ts | 3 + .../src/library/library-cache.test.ts | 13 + .../compiler/src/library/library-cache.ts | 3 + packages/compiler/src/native/cli.ts | 1 + packages/compiler/src/native/prepare.ts | 1 + .../compiler/src/native/sanitizer.test.ts | 1 + .../6936-x509-certificate-fields.ts.json | 6 + .../corpus/7090-x509-check-names.ts.json | 6 + .../corpus/7091-x509-certificate-keys.ts.json | 6 + .../corpus/7092-x509-legacy-object.ts.json | 6 + .../corpus/7093-x509-methods-js.mjs.json | 6 + .../corpus/7095-tls-peer-certificates.ts.json | 6 + .../7096-tls-peer-certificates.mjs.json | 6 + .../7097-tls-client-certificates.ts.json | 6 + ...7098-tls-client-certificates-paths.ts.json | 6 + .../7099-tls-client-certificates.mjs.json | 6 + .../7440-tls-server-add-context.ts.json | 6 + .../corpus/7441-tls-client-error.ts.json | 6 + .../corpus/7442-tls-server-contexts.mjs.json | 6 + .../corpus/7443-tls-final-flight.ts.json | 6 + .../corpus/7444-tls-final-flight.mjs.json | 6 + .../corpus/7454-tls-peer-embedded-pem.ts.json | 6 + .../corpus/7455-tls-als-contexts.mjs.json | 6 + .../tests/diagnostics/x509-fences.ts.json | 6 + .../tls-client-certificates.ts.json | 6 + .../node-types/tls-peer-certificates.ts.json | 6 + .../node-types/tls-server-contexts.ts.json | 6 + .../fixtures/node-types/x509-methods.ts.json | 6 + .../runtime-pack-common/library-matrix.mjs | 1 + .../runtime-pack-matrix.mjs | 3 + .../runtime-wasm32-wasi/scripts/build.mjs | 1 + packages/runtime/src/scr_crypto.h | 31 + packages/runtime/src/scr_lib.c | 21 +- packages/runtime/src/scr_net.c | 67 +- packages/runtime/src/scr_net.h | 18 + packages/runtime/src/scr_pki.c | 217 ++ packages/runtime/src/scr_tls.c | 966 ++++++++- packages/runtime/src/scr_tls.h | 19 + packages/runtime/src/scr_tls_x509.c | 119 ++ packages/runtime/src/scr_x509.c | 1820 +++++++++++++++++ tests/corpus/6936-x509-certificate-fields.ts | 189 ++ tests/corpus/7090-x509-check-names.ts | 141 ++ tests/corpus/7091-x509-certificate-keys.ts | 332 +++ tests/corpus/7092-x509-legacy-object.ts | 158 ++ tests/corpus/7093-x509-methods-js.mjs | 158 ++ tests/corpus/7095-tls-peer-certificates.ts | 188 ++ tests/corpus/7096-tls-peer-certificates.mjs | 35 + tests/corpus/7097-tls-client-certificates.ts | 84 + .../7098-tls-client-certificates-paths.ts | 161 ++ tests/corpus/7099-tls-client-certificates.mjs | 34 + tests/corpus/7440-tls-server-add-context.ts | 119 ++ tests/corpus/7441-tls-client-error.ts | 93 + tests/corpus/7442-tls-server-contexts.mjs | 51 + tests/corpus/7443-tls-final-flight.ts | 114 ++ tests/corpus/7444-tls-final-flight.mjs | 28 + tests/corpus/7454-tls-peer-embedded-pem.ts | 46 + tests/corpus/7455-tls-als-contexts.mjs | 48 + tests/diagnostics/x509-fences.ts | 21 + .../node-types/tls-client-certificates.ts | 32 + .../node-types/tls-peer-certificates.ts | 37 + .../node-types/tls-server-contexts.ts | 38 + tests/fixtures/node-types/x509-methods.ts | 20 + tests/fixtures/server/certs/README.md | 12 + tests/fixtures/server/certs/client-key.pem | 5 + tests/fixtures/server/certs/client.cnf | 7 + tests/fixtures/server/certs/client.pem | 11 + tests/fixtures/server/certs/embedded-key.pem | 5 + tests/fixtures/server/certs/embedded.cnf | 9 + tests/fixtures/server/certs/embedded.pem | 26 + tests/fixtures/tls/empty-ca.ts | 36 + .../tls-sni-callback-fences.ts.txt | 2 +- .../harness/__snapshots__/x509-fences.ts.txt | 48 + .../6936-x509-certificate-fields.ts.json | 1 + .../7090-x509-check-names.ts.json | 1 + .../7091-x509-certificate-keys.ts.json | 1 + .../7092-x509-legacy-object.ts.json | 1 + .../7093-x509-methods-js.mjs.json | 1 + .../7095-tls-peer-certificates.ts.json | 1 + .../7096-tls-peer-certificates.mjs.json | 1 + .../7097-tls-client-certificates.ts.json | 1 + ...7098-tls-client-certificates-paths.ts.json | 1 + .../7099-tls-client-certificates.mjs.json | 1 + .../7440-tls-server-add-context.ts.json | 1 + .../7441-tls-client-error.ts.json | 1 + .../7442-tls-server-contexts.mjs.json | 1 + .../7443-tls-final-flight.ts.json | 1 + .../7444-tls-final-flight.mjs.json | 1 + .../7454-tls-peer-embedded-pem.ts.json | 1 + .../7455-tls-als-contexts.mjs.json | 1 + tests/harness/errors.test.ts | 157 +- tests/harness/library-asyncfree.test.ts | 9 + tests/harness/library-mode.test.ts | 15 + tests/harness/project-config.test.ts | 7 + .../self-hosting-native-toolchain.test.ts | 1 + .../harness/self-hosting-runtime-pack.test.ts | 1 + tests/harness/tls-socket-leaks.test.ts | 10 +- tests/harness/tls-trust-store.test.ts | 42 + tests/library-mode/x509/lib.ts | 41 + tests/library-mode/x509/probe.c | 23 + tests/library-mode/x509/profile.json | 14 + 135 files changed, 7408 insertions(+), 314 deletions(-) create mode 100644 docs/content/limitations/tls-certificates.mdx create mode 100644 docs/content/limitations/tls-sessions.mdx create mode 100644 packages/compiler/src/frontend/lowering/builtins/x509.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6936-x509-certificate-fields.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7090-x509-check-names.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7091-x509-certificate-keys.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7092-x509-legacy-object.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7093-x509-methods-js.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7095-tls-peer-certificates.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7096-tls-peer-certificates.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7097-tls-client-certificates.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7098-tls-client-certificates-paths.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7099-tls-client-certificates.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7440-tls-server-add-context.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7441-tls-client-error.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7442-tls-server-contexts.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7443-tls-final-flight.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7444-tls-final-flight.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7454-tls-peer-embedded-pem.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7455-tls-als-contexts.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/x509-fences.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/tls-client-certificates.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/tls-peer-certificates.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/tls-server-contexts.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/x509-methods.ts.json create mode 100644 packages/runtime/src/scr_tls_x509.c create mode 100644 packages/runtime/src/scr_x509.c create mode 100644 tests/corpus/6936-x509-certificate-fields.ts create mode 100644 tests/corpus/7090-x509-check-names.ts create mode 100644 tests/corpus/7091-x509-certificate-keys.ts create mode 100644 tests/corpus/7092-x509-legacy-object.ts create mode 100644 tests/corpus/7093-x509-methods-js.mjs create mode 100644 tests/corpus/7095-tls-peer-certificates.ts create mode 100644 tests/corpus/7096-tls-peer-certificates.mjs create mode 100644 tests/corpus/7097-tls-client-certificates.ts create mode 100644 tests/corpus/7098-tls-client-certificates-paths.ts create mode 100644 tests/corpus/7099-tls-client-certificates.mjs create mode 100644 tests/corpus/7440-tls-server-add-context.ts create mode 100644 tests/corpus/7441-tls-client-error.ts create mode 100644 tests/corpus/7442-tls-server-contexts.mjs create mode 100644 tests/corpus/7443-tls-final-flight.ts create mode 100644 tests/corpus/7444-tls-final-flight.mjs create mode 100644 tests/corpus/7454-tls-peer-embedded-pem.ts create mode 100644 tests/corpus/7455-tls-als-contexts.mjs create mode 100644 tests/diagnostics/x509-fences.ts create mode 100644 tests/fixtures/node-types/tls-client-certificates.ts create mode 100644 tests/fixtures/node-types/tls-peer-certificates.ts create mode 100644 tests/fixtures/node-types/tls-server-contexts.ts create mode 100644 tests/fixtures/node-types/x509-methods.ts create mode 100644 tests/fixtures/server/certs/client-key.pem create mode 100644 tests/fixtures/server/certs/client.cnf create mode 100644 tests/fixtures/server/certs/client.pem create mode 100644 tests/fixtures/server/certs/embedded-key.pem create mode 100644 tests/fixtures/server/certs/embedded.cnf create mode 100644 tests/fixtures/server/certs/embedded.pem create mode 100644 tests/fixtures/tls/empty-ca.ts create mode 100644 tests/harness/__snapshots__/x509-fences.ts.txt create mode 100644 tests/harness/corpus-costs/6936-x509-certificate-fields.ts.json create mode 100644 tests/harness/corpus-costs/7090-x509-check-names.ts.json create mode 100644 tests/harness/corpus-costs/7091-x509-certificate-keys.ts.json create mode 100644 tests/harness/corpus-costs/7092-x509-legacy-object.ts.json create mode 100644 tests/harness/corpus-costs/7093-x509-methods-js.mjs.json create mode 100644 tests/harness/corpus-costs/7095-tls-peer-certificates.ts.json create mode 100644 tests/harness/corpus-costs/7096-tls-peer-certificates.mjs.json create mode 100644 tests/harness/corpus-costs/7097-tls-client-certificates.ts.json create mode 100644 tests/harness/corpus-costs/7098-tls-client-certificates-paths.ts.json create mode 100644 tests/harness/corpus-costs/7099-tls-client-certificates.mjs.json create mode 100644 tests/harness/corpus-costs/7440-tls-server-add-context.ts.json create mode 100644 tests/harness/corpus-costs/7441-tls-client-error.ts.json create mode 100644 tests/harness/corpus-costs/7442-tls-server-contexts.mjs.json create mode 100644 tests/harness/corpus-costs/7443-tls-final-flight.ts.json create mode 100644 tests/harness/corpus-costs/7444-tls-final-flight.mjs.json create mode 100644 tests/harness/corpus-costs/7454-tls-peer-embedded-pem.ts.json create mode 100644 tests/harness/corpus-costs/7455-tls-als-contexts.mjs.json create mode 100644 tests/harness/tls-trust-store.test.ts create mode 100644 tests/library-mode/x509/lib.ts create mode 100644 tests/library-mode/x509/probe.c create mode 100644 tests/library-mode/x509/profile.json diff --git a/docs/content/docs/limitations.mdx b/docs/content/docs/limitations.mdx index a86ed217e..cb6b93d0d 100644 --- a/docs/content/docs/limitations.mdx +++ b/docs/content/docs/limitations.mdx @@ -220,6 +220,14 @@ title: "Limitations" ../limitations/tls-ciphers.mdx +### TLS certificates + +../limitations/tls-certificates.mdx + +### TLS sessions + +../limitations/tls-sessions.mdx + ### Console and process streams ../limitations/console-and-process-streams.mdx diff --git a/docs/content/limitations/builtin-apis/crypto.mdx b/docs/content/limitations/builtin-apis/crypto.mdx index 329aa6809..cba219788 100644 --- a/docs/content/limitations/builtin-apis/crypto.mdx +++ b/docs/content/limitations/builtin-apis/crypto.mdx @@ -41,6 +41,10 @@ They support `type`, `asymmetricKeyType`, `asymmetricKeyDetails`, `export()`, `equals()`, and `instanceof KeyObject`. `crypto.sign`, `crypto.verify`, `createSign`, and `createVerify` support RSA PKCS#1 v1.5 and PSS padding and ECDSA with DER and IEEE P1363 encodings over SHA-1 and SHA-2 digests, and Ed25519 through `crypto.sign` and `crypto.verify` with a `null` or `undefined` algorithm. Ed25519 signing, verification, and private keys link when a string literal in the program names `ed25519` (in any case); without one they throw a coded SC2020 error, while Ed25519 public keys still import and export. + X509Certificate supports `publicKey`, `verify()`, `checkIssued()`, `checkPrivateKey()`, `checkHost()`, `checkEmail()`, `checkIP()`, `toLegacyObject()`, `toString()`, and `toJSON()`, and `String()`, template literals, and `+` give its PEM text as `toString()` does. + `publicKey`, `verify()`, and `checkPrivateKey()` are refused in wasm32-wasi builds, and an Ed25519 certificate's `verify()` needs the `ed25519` literal like the other Ed25519 operations. + Own-key walks over a certificate (`Object.keys()`, `Object.entries()`, spread, `for...in`, and `hasOwnProperty`) are refused, since Node keeps its fields as prototype getters. + `JSON.stringify()` and `console.log()` of a certificate, a certificate stored in an `unknown` or `any` slot, and its methods on a union-typed value are also refused. Sign and Verify values accumulate `update()` data and are not writable streams. Encrypted private keys (`passphrase`, `cipher`), the other key types (`rsa-pss`, `dsa`, `ed448`, `x448`, and the rest), and wasm32-wasi builds throw a coded SC2020 error or are refused. Comparing keys of different types with `equals()` answers false; Node also leaves an OpenSSL error queued, which a later key operation can report. diff --git a/docs/content/limitations/tls-certificates.mdx b/docs/content/limitations/tls-certificates.mdx new file mode 100644 index 000000000..bbe4ceaf9 --- /dev/null +++ b/docs/content/limitations/tls-certificates.mdx @@ -0,0 +1,11 @@ +`tlsSocket.getPeerCertificate()`, `getCertificate()`, `getPeerX509Certificate()`, and `getX509Certificate()` follow Node, including the `detailed` issuer chain, on sockets whose type is known. +On a TLS socket held in an `unknown` or `any` value, or in an untyped JavaScript parameter, they throw an error that names the call as not supported. +Client certificates follow Node: `tls.createServer`, `https.createServer`, and `new tls.TLSSocket` take `requestCert`, `rejectUnauthorized`, and `ca`, and `tls.connect` and `https.request` take `cert` and `key`. +A server's `authorized` and `authorizationError` report the client certificate's verification as Node does, and a server, client, or `tls.createSecureContext` given a `ca` also sends the chain it completes, as OpenSSL's automatic chain does. +`requestCert` beside a TLSSocket's `secureContext` or an `SNICallback`, client certificates on http2 secure servers, and a `cert` without a `key` (or the reverse) are refused. +`server.addContext()` and `server.setSecureContext()` follow Node on tls and https servers, including wildcard names, which match one label without regard to case. +A name with regular-expression groups or alternation, or one outside ASCII, is refused, as are both methods on a server that is not a tls or https server. +The `'tlsClientError'` event reports Node's error for a failed handshake: OpenSSL's code and reason, or `socket hang up` for a client that leaves. +OpenSSL's messages leave out the thread identifier Node prints before `error:` and the source location after the reason. +A failure whose OpenSSL reason the runtime does not know, such as a malformed client hello, is reported as an error with code `SC2020` that says so. +The X509Certificate those accessors return has the same refusals as any other certificate (see Crypto), so in JavaScript narrow it, for example with `if (cert)`, before reading its fields. diff --git a/docs/content/limitations/tls-sessions.mdx b/docs/content/limitations/tls-sessions.mdx new file mode 100644 index 000000000..8d34573a8 --- /dev/null +++ b/docs/content/limitations/tls-sessions.mdx @@ -0,0 +1,3 @@ +TLS servers send no session tickets, so a connection to them cannot be resumed. +A client's `'session'` event fires once per connection, when its handshake finishes and before `secureConnect`. +Node fires it for each ticket the server sends, after `secureConnect`, and OpenSSL servers send two. diff --git a/docs/src/generated/node-v24-compatibility.json b/docs/src/generated/node-v24-compatibility.json index 1039bc3d8..e463b872d 100644 --- a/docs/src/generated/node-v24-compatibility.json +++ b/docs/src/generated/node-v24-compatibility.json @@ -13822,9 +13822,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented by a dedicated static compiler/runtime path.", + "verification": "test-backed" } }, { @@ -13845,9 +13845,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented by a dedicated static compiler/runtime path.", + "verification": "test-backed" } }, { @@ -13868,9 +13868,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented by a dedicated static compiler/runtime path.", + "verification": "test-backed" } }, { @@ -13891,9 +13891,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented by a dedicated static compiler/runtime path.", + "verification": "test-backed" } }, { @@ -13914,9 +13914,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented by a dedicated static compiler/runtime path.", + "verification": "test-backed" } }, { @@ -13937,9 +13937,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented by a dedicated static compiler/runtime path.", + "verification": "test-backed" } }, { @@ -13960,9 +13960,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented by a dedicated static compiler/runtime path.", + "verification": "test-backed" } }, { @@ -13983,9 +13983,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented by a dedicated static compiler/runtime path.", + "verification": "test-backed" } }, { @@ -14006,9 +14006,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented by a dedicated static compiler/runtime path.", + "verification": "test-backed" } }, { @@ -14029,9 +14029,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented by a dedicated static compiler/runtime path.", + "verification": "test-backed" } }, { @@ -14236,9 +14236,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -23790,9 +23790,9 @@ "anchor": "err_tls_required_server_name", "nodeStability": null, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented by a dedicated static compiler/runtime path.", + "verification": "test-backed" } }, { @@ -67484,9 +67484,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented by a dedicated static compiler/runtime path.", + "verification": "test-backed" } }, { @@ -67599,9 +67599,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented by a dedicated static compiler/runtime path.", + "verification": "test-backed" } }, { @@ -67783,9 +67783,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented by a dedicated static compiler/runtime path.", + "verification": "test-backed" } }, { @@ -67921,9 +67921,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented by a dedicated static compiler/runtime path.", + "verification": "test-backed" } }, { @@ -68013,9 +68013,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented by a dedicated static compiler/runtime path.", + "verification": "test-backed" } }, { @@ -68059,9 +68059,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented by a dedicated static compiler/runtime path.", + "verification": "test-backed" } }, { @@ -68174,9 +68174,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented by a dedicated static compiler/runtime path.", + "verification": "test-backed" } }, { @@ -68312,9 +68312,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented by a dedicated static compiler/runtime path.", + "verification": "test-backed" } }, { @@ -68335,9 +68335,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index b3d91e453..1ee5cacd6 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -19394,6 +19394,8 @@ "tests": [ "tests/corpus/1358-crypto-random.ts", "tests/corpus/1534-crypto-hash-chain.ts", + "tests/corpus/1568-x509-fingerprint.ts", + "tests/corpus/1572-x509-validity-date-gettime.ts", "tests/corpus/2556-crypto-introspection.ts", "tests/corpus/2890-crypto-static-utility.ts", "tests/corpus/5250-cipher-aes-gcm.ts", @@ -19436,6 +19438,7 @@ "tests/corpus/6709-dh-generate.ts", "tests/corpus/6710-dh-encodings.cjs", "tests/corpus/6711-dh-handles.ts", + "tests/corpus/6936-x509-certificate-fields.ts", "tests/corpus/7055-cipher-streams.ts", "tests/corpus/7056-cipher-stream-errors.ts", "tests/corpus/7057-cipher-streams.mjs", @@ -19443,6 +19446,10 @@ "tests/corpus/7082-crypto-key-objects.ts", "tests/corpus/7083-crypto-sign-verify.ts", "tests/corpus/7084-crypto-key-pairs.cjs", + "tests/corpus/7090-x509-check-names.ts", + "tests/corpus/7091-x509-certificate-keys.ts", + "tests/corpus/7092-x509-legacy-object.ts", + "tests/corpus/7093-x509-methods-js.mjs", "tests/corpus/7122-webcrypto-node-crypto.ts", "tests/corpus/7123-webcrypto-node-crypto.cjs", "tests/corpus/7150-cipher-legacy-modes.ts", @@ -19461,6 +19468,7 @@ "tests/fixtures/node-types/dh.ts", "tests/fixtures/node-types/ecdh.ts", "tests/fixtures/node-types/keys.ts", + "tests/fixtures/node-types/x509-methods.ts", "tests/harness/npm-static.test.ts" ] }, @@ -23784,8 +23792,13 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:crypto" + "status": "partial", + "evidence": "compiler-dedicated:X509Certificate", + "tests": [ + "tests/corpus/1568-x509-fingerprint.ts", + "tests/corpus/1572-x509-validity-date-gettime.ts", + "tests/corpus/6936-x509-certificate-fields.ts" + ] }, "anchorSource": "exact" }, @@ -23807,8 +23820,15 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:crypto" + "status": "partial", + "evidence": "compiler-dedicated:x509.checkEmail", + "tests": [ + "tests/corpus/7090-x509-check-names.ts", + "tests/corpus/7091-x509-certificate-keys.ts", + "tests/corpus/7092-x509-legacy-object.ts", + "tests/corpus/7093-x509-methods-js.mjs", + "tests/fixtures/node-types/x509-methods.ts" + ] }, "anchorSource": "exact" }, @@ -23830,8 +23850,15 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:crypto" + "status": "partial", + "evidence": "compiler-dedicated:x509.checkHost", + "tests": [ + "tests/corpus/7090-x509-check-names.ts", + "tests/corpus/7091-x509-certificate-keys.ts", + "tests/corpus/7092-x509-legacy-object.ts", + "tests/corpus/7093-x509-methods-js.mjs", + "tests/fixtures/node-types/x509-methods.ts" + ] }, "anchorSource": "exact" }, @@ -23853,8 +23880,15 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:crypto" + "status": "partial", + "evidence": "compiler-dedicated:x509.checkIP", + "tests": [ + "tests/corpus/7090-x509-check-names.ts", + "tests/corpus/7091-x509-certificate-keys.ts", + "tests/corpus/7092-x509-legacy-object.ts", + "tests/corpus/7093-x509-methods-js.mjs", + "tests/fixtures/node-types/x509-methods.ts" + ] }, "anchorSource": "exact" }, @@ -23876,8 +23910,15 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:crypto" + "status": "partial", + "evidence": "compiler-dedicated:x509.checkIssued", + "tests": [ + "tests/corpus/7090-x509-check-names.ts", + "tests/corpus/7091-x509-certificate-keys.ts", + "tests/corpus/7092-x509-legacy-object.ts", + "tests/corpus/7093-x509-methods-js.mjs", + "tests/fixtures/node-types/x509-methods.ts" + ] }, "anchorSource": "exact" }, @@ -23899,8 +23940,15 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:crypto" + "status": "partial", + "evidence": "compiler-dedicated:x509.checkPrivateKey", + "tests": [ + "tests/corpus/7090-x509-check-names.ts", + "tests/corpus/7091-x509-certificate-keys.ts", + "tests/corpus/7092-x509-legacy-object.ts", + "tests/corpus/7093-x509-methods-js.mjs", + "tests/fixtures/node-types/x509-methods.ts" + ] }, "anchorSource": "exact" }, @@ -23922,8 +23970,15 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:crypto" + "status": "partial", + "evidence": "compiler-dedicated:x509.toJSON", + "tests": [ + "tests/corpus/7090-x509-check-names.ts", + "tests/corpus/7091-x509-certificate-keys.ts", + "tests/corpus/7092-x509-legacy-object.ts", + "tests/corpus/7093-x509-methods-js.mjs", + "tests/fixtures/node-types/x509-methods.ts" + ] }, "anchorSource": "exact" }, @@ -23945,8 +24000,15 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:crypto" + "status": "partial", + "evidence": "compiler-dedicated:x509.toLegacyObject", + "tests": [ + "tests/corpus/7090-x509-check-names.ts", + "tests/corpus/7091-x509-certificate-keys.ts", + "tests/corpus/7092-x509-legacy-object.ts", + "tests/corpus/7093-x509-methods-js.mjs", + "tests/fixtures/node-types/x509-methods.ts" + ] }, "anchorSource": "exact" }, @@ -23968,8 +24030,15 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:crypto" + "status": "partial", + "evidence": "compiler-dedicated:x509.toString", + "tests": [ + "tests/corpus/7090-x509-check-names.ts", + "tests/corpus/7091-x509-certificate-keys.ts", + "tests/corpus/7092-x509-legacy-object.ts", + "tests/corpus/7093-x509-methods-js.mjs", + "tests/fixtures/node-types/x509-methods.ts" + ] }, "anchorSource": "exact" }, @@ -23991,8 +24060,15 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:crypto" + "status": "partial", + "evidence": "compiler-dedicated:x509.verify", + "tests": [ + "tests/corpus/7090-x509-check-names.ts", + "tests/corpus/7091-x509-certificate-keys.ts", + "tests/corpus/7092-x509-legacy-object.ts", + "tests/corpus/7093-x509-methods-js.mjs", + "tests/fixtures/node-types/x509-methods.ts" + ] }, "anchorSource": "exact" }, @@ -24198,8 +24274,15 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:crypto" + "status": "partial", + "evidence": "compiler-feature:crypto.publicKey", + "tests": [ + "tests/corpus/7090-x509-check-names.ts", + "tests/corpus/7091-x509-certificate-keys.ts", + "tests/corpus/7092-x509-legacy-object.ts", + "tests/corpus/7093-x509-methods-js.mjs", + "tests/fixtures/node-types/x509-methods.ts" + ] }, "anchorSource": "ancestor" }, @@ -32679,6 +32762,7 @@ "tests": [ "tests/corpus/6702-ecdh-errors.js", "tests/corpus/6708-dh-errors.js", + "tests/corpus/7440-tls-server-add-context.ts", "tests/corpus/caught-system-error-fields.ts", "tests/corpus/error-stack-frames.ts", "tests/corpus/error-stack-limit.ts", @@ -39008,8 +39092,11 @@ "anchor": "err_tls_required_server_name", "nodeStability": null, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:errors" + "status": "partial", + "evidence": "compiler-dedicated:ERR_TLS_REQUIRED_SERVER_NAME", + "tests": [ + "tests/corpus/7440-tls-server-add-context.ts" + ] }, "anchorSource": "exact" }, @@ -95873,6 +95960,17 @@ "tests/corpus/6722-tls-min-max-version.ts", "tests/corpus/7087-tls-socket-wrap.ts", "tests/corpus/7088-tls-socket-connect-tunnel.ts", + "tests/corpus/7095-tls-peer-certificates.ts", + "tests/corpus/7096-tls-peer-certificates.mjs", + "tests/corpus/7097-tls-client-certificates.ts", + "tests/corpus/7098-tls-client-certificates-paths.ts", + "tests/corpus/7099-tls-client-certificates.mjs", + "tests/corpus/7440-tls-server-add-context.ts", + "tests/corpus/7441-tls-client-error.ts", + "tests/corpus/7442-tls-server-contexts.mjs", + "tests/fixtures/node-types/tls-client-certificates.ts", + "tests/fixtures/node-types/tls-peer-certificates.ts", + "tests/fixtures/node-types/tls-server-contexts.ts", "tests/fixtures/node-types/tls-socket-wrap.ts" ] }, @@ -96241,8 +96339,14 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:tls" + "status": "partial", + "evidence": "compiler-dedicated:server.addContext", + "tests": [ + "tests/corpus/7440-tls-server-add-context.ts", + "tests/corpus/7441-tls-client-error.ts", + "tests/corpus/7442-tls-server-contexts.mjs", + "tests/fixtures/node-types/tls-server-contexts.ts" + ] }, "anchorSource": "exact" }, @@ -96368,8 +96472,14 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:tls" + "status": "partial", + "evidence": "compiler-dedicated:server.setSecureContext", + "tests": [ + "tests/corpus/7440-tls-server-add-context.ts", + "tests/corpus/7441-tls-client-error.ts", + "tests/corpus/7442-tls-server-contexts.mjs", + "tests/fixtures/node-types/tls-server-contexts.ts" + ] }, "anchorSource": "exact" }, @@ -96552,8 +96662,14 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:tls" + "status": "partial", + "evidence": "compiler-dedicated:'tlsClientError'", + "tests": [ + "tests/corpus/7440-tls-server-add-context.ts", + "tests/corpus/7441-tls-client-error.ts", + "tests/corpus/7442-tls-server-contexts.mjs", + "tests/fixtures/node-types/tls-server-contexts.ts" + ] }, "anchorSource": "exact" }, @@ -96695,8 +96811,13 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:tls" + "status": "partial", + "evidence": "compiler-dedicated:tlsSocket.getCertificate", + "tests": [ + "tests/corpus/7095-tls-peer-certificates.ts", + "tests/corpus/7096-tls-peer-certificates.mjs", + "tests/fixtures/node-types/tls-peer-certificates.ts" + ] }, "anchorSource": "exact" }, @@ -96787,8 +96908,13 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:tls" + "status": "partial", + "evidence": "compiler-dedicated:tlsSocket.getPeerCertificate", + "tests": [ + "tests/corpus/7095-tls-peer-certificates.ts", + "tests/corpus/7096-tls-peer-certificates.mjs", + "tests/fixtures/node-types/tls-peer-certificates.ts" + ] }, "anchorSource": "exact" }, @@ -96856,8 +96982,13 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:tls" + "status": "partial", + "evidence": "compiler-dedicated:tlsSocket.getPeerX509Certificate", + "tests": [ + "tests/corpus/7095-tls-peer-certificates.ts", + "tests/corpus/7096-tls-peer-certificates.mjs", + "tests/fixtures/node-types/tls-peer-certificates.ts" + ] }, "anchorSource": "exact" }, @@ -96974,8 +97105,13 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:tls" + "status": "partial", + "evidence": "compiler-dedicated:tlsSocket.getX509Certificate", + "tests": [ + "tests/corpus/7095-tls-peer-certificates.ts", + "tests/corpus/7096-tls-peer-certificates.mjs", + "tests/fixtures/node-types/tls-peer-certificates.ts" + ] }, "anchorSource": "exact" }, @@ -97115,8 +97251,14 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:tls" + "status": "partial", + "evidence": "compiler-dedicated:tlsSocket.authorizationError", + "tests": [ + "tests/corpus/7097-tls-client-certificates.ts", + "tests/corpus/7098-tls-client-certificates-paths.ts", + "tests/corpus/7099-tls-client-certificates.mjs", + "tests/fixtures/node-types/tls-client-certificates.ts" + ] }, "anchorSource": "exact" }, @@ -97138,8 +97280,14 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:tls" + "status": "partial", + "evidence": "compiler-feature:tls.authorized", + "tests": [ + "tests/corpus/7097-tls-client-certificates.ts", + "tests/corpus/7098-tls-client-certificates-paths.ts", + "tests/corpus/7099-tls-client-certificates.mjs", + "tests/fixtures/node-types/tls-client-certificates.ts" + ] }, "anchorSource": "ancestor" }, diff --git a/internal/compatibility/static-support.json b/internal/compatibility/static-support.json index 92124f4f5..a098390f2 100644 --- a/internal/compatibility/static-support.json +++ b/internal/compatibility/static-support.json @@ -202,6 +202,8 @@ "stdlib.abort": ["tests/harness/fetch-conformance.test.ts"] }, "features": [ + { "chapter": "tls", "parent": "Class: `tls.TLSSocket`", "signatures": ["`authorized` Type: {boolean}"], "status": "partial", "evidence": ["tests/corpus/7097-tls-client-certificates.ts", "tests/corpus/7098-tls-client-certificates-paths.ts", "tests/corpus/7099-tls-client-certificates.mjs", "tests/fixtures/node-types/tls-client-certificates.ts"] }, + { "chapter": "crypto", "parent": "Class: `X509Certificate`", "signatures": ["`publicKey` Type: {KeyObject}"], "status": "partial", "evidence": ["tests/corpus/7090-x509-check-names.ts", "tests/corpus/7091-x509-certificate-keys.ts", "tests/corpus/7092-x509-legacy-object.ts", "tests/corpus/7093-x509-methods-js.mjs", "tests/fixtures/node-types/x509-methods.ts"] }, { "chapter": "webcrypto", "symbols": ["subtle.importKey", "subtle.generateKey", "subtle.exportKey", "subtle.encrypt", "subtle.decrypt", "subtle.wrapKey", "subtle.unwrapKey", "subtle.deriveBits", "subtle.deriveKey", "subtle.sign", "subtle.verify", "subtle.digest"], "status": "partial", "evidence": ["tests/corpus/7130-webcrypto-wrap-key.ts", "tests/corpus/7131-webcrypto-wrap-key-errors.mjs", "tests/corpus/7132-jose-pbes2/main.mjs", "tests/corpus/7128-webcrypto-derive.ts", "tests/corpus/7129-webcrypto-derive-errors.mjs", "tests/corpus/7126-webcrypto-aes.ts", "tests/corpus/7127-webcrypto-aes-errors.mjs", "tests/corpus/7124-webcrypto-secret-keys.ts", "tests/corpus/7125-webcrypto-key-errors.mjs", "tests/fixtures/node-types/webcrypto-keys.ts", "tests/corpus/6291-webcrypto-hmac-sign-verify.ts", "tests/corpus/6292-webcrypto-hmac-errors.ts", "tests/corpus/6293-webcrypto-digest.ts", "tests/corpus/6294-webcrypto-js-values.mjs", "tests/corpus/6295-jose-hs256/main.mjs", "tests/fixtures/node-types/webcrypto-hmac.ts", "tests/corpus/7081-webcrypto-ed25519.mjs", "tests/corpus/7085-webcrypto-ecdsa-rsa.ts", "tests/corpus/7086-webcrypto-ecdsa-rsa-errors.mjs"] }, { "chapter": "webcrypto", "signatures": ["Class: `SubtleCrypto`", "`subtle` Type: {SubtleCrypto}"], "status": "partial", "evidence": ["tests/corpus/6291-webcrypto-hmac-sign-verify.ts", "tests/corpus/6292-webcrypto-hmac-errors.ts", "tests/corpus/6293-webcrypto-digest.ts", "tests/corpus/6294-webcrypto-js-values.mjs", "tests/corpus/6295-jose-hs256/main.mjs"] }, { "chapter": "webcrypto", "signatures": ["Class: `CryptoKey`", "`cryptoKey.algorithm`", "`extractable` Type: {boolean}", "`type` Type: {string} One of `'secret'`, `'private'`, or `'public'`.", "`usages` Type: {string\\[]}"], "status": "partial", "evidence": ["tests/corpus/7124-webcrypto-secret-keys.ts", "tests/corpus/6291-webcrypto-hmac-sign-verify.ts", "tests/corpus/6294-webcrypto-js-values.mjs", "tests/corpus/6295-jose-hs256/main.mjs"] }, @@ -427,6 +429,11 @@ { "symbols": ["assert", "assert.ok", "assert.equal", "assert.notEqual", "assert.strictEqual", "assert.notStrictEqual", "assert.deepStrictEqual", "assert.notDeepStrictEqual", "assert.fail", "assert.match", "assert.doesNotMatch", "assert.throws", "assert.rejects", "assert.ifError"], "status": "partial", "evidence": ["tests/corpus/1600-assert-passing.ts", "tests/corpus/1604-assert-deep-structures.ts", "tests/corpus/1609-assert-async.ts", "tests/corpus/1721-assert-throws-regex-class.ts", "tests/corpus/2936-static-loose-equality.ts", "tests/corpus/5515-assert-deep-strict-typed-messages.ts"] }, { "chapter": "crypto", "symbols": ["Cipheriv", "cipher.update", "cipher.final", "cipher.setAAD", "cipher.getAuthTag", "cipher.setAutoPadding", "Decipheriv", "decipher.update", "decipher.final", "decipher.setAAD", "decipher.setAuthTag", "decipher.setAutoPadding"], "status": "partial", "evidence": ["tests/corpus/5250-cipher-aes-gcm.ts", "tests/corpus/5251-cipher-aes-cbc.ts", "tests/corpus/5252-cipher-aes-ctr.ts", "tests/corpus/5253-cipher-chacha20-poly1305.ts", "tests/corpus/5254-cipher-errors.js", "tests/corpus/5255-cipher-encodings.cjs", "tests/corpus/5256-cipher-deprecation.cjs", "tests/corpus/5257-cipher-vectors.ts", "tests/corpus/5258-cipher-handles.js", "tests/corpus/5259-cipher-chunked.ts", "tests/corpus/7055-cipher-streams.ts", "tests/corpus/7056-cipher-stream-errors.ts", "tests/corpus/7057-cipher-streams.mjs", "tests/fixtures/node-types/cipher.ts"] }, { "chapter": "crypto", "symbols": ["crypto.webcrypto", "subtle"], "status": "partial", "evidence": ["tests/corpus/7122-webcrypto-node-crypto.ts", "tests/corpus/7123-webcrypto-node-crypto.cjs"] }, + { "chapter": "tls", "symbols": ["server.addContext", "server.setSecureContext", "'tlsClientError'"], "status": "partial", "evidence": ["tests/corpus/7440-tls-server-add-context.ts", "tests/corpus/7441-tls-client-error.ts", "tests/corpus/7442-tls-server-contexts.mjs", "tests/fixtures/node-types/tls-server-contexts.ts"] }, + { "chapter": "errors", "symbols": ["ERR_TLS_REQUIRED_SERVER_NAME"], "status": "partial", "evidence": ["tests/corpus/7440-tls-server-add-context.ts"] }, + { "chapter": "tls", "symbols": ["tlsSocket.authorizationError"], "status": "partial", "evidence": ["tests/corpus/7097-tls-client-certificates.ts", "tests/corpus/7098-tls-client-certificates-paths.ts", "tests/corpus/7099-tls-client-certificates.mjs", "tests/fixtures/node-types/tls-client-certificates.ts"] }, + { "chapter": "tls", "symbols": ["tlsSocket.getPeerCertificate", "tlsSocket.getCertificate", "tlsSocket.getPeerX509Certificate", "tlsSocket.getX509Certificate"], "status": "partial", "evidence": ["tests/corpus/7095-tls-peer-certificates.ts", "tests/corpus/7096-tls-peer-certificates.mjs", "tests/fixtures/node-types/tls-peer-certificates.ts"] }, + { "chapter": "crypto", "symbols": ["x509.checkEmail", "x509.checkHost", "x509.checkIP", "x509.checkIssued", "x509.checkPrivateKey", "x509.toJSON", "x509.toLegacyObject", "x509.toString", "x509.verify"], "status": "partial", "evidence": ["tests/corpus/7090-x509-check-names.ts", "tests/corpus/7091-x509-certificate-keys.ts", "tests/corpus/7092-x509-legacy-object.ts", "tests/corpus/7093-x509-methods-js.mjs", "tests/fixtures/node-types/x509-methods.ts"] }, { "chapter": "crypto", "symbols": ["ECDH", "ecdh.computeSecret", "ecdh.generateKeys", "ecdh.getPrivateKey", "ecdh.getPublicKey", "ecdh.setPrivateKey", "ecdh.setPublicKey"], "status": "partial", "evidence": ["tests/corpus/6700-ecdh-shared-secret.ts", "tests/corpus/6701-ecdh-formats.ts", "tests/corpus/6702-ecdh-errors.js", "tests/corpus/6703-ecdh-private-keys.ts", "tests/corpus/6704-ecdh-set-public-key.cjs", "tests/corpus/6705-ecdh-handles.ts", "tests/fixtures/node-types/ecdh.ts"] }, { "chapter": "crypto", "symbols": ["DiffieHellman", "DiffieHellmanGroup", "diffieHellman.computeSecret", "diffieHellman.generateKeys", "diffieHellman.getGenerator", "diffieHellman.getPrime", "diffieHellman.getPrivateKey", "diffieHellman.getPublicKey", "diffieHellman.setPrivateKey", "diffieHellman.setPublicKey", "diffieHellman.verifyError"], "status": "partial", "evidence": ["tests/corpus/6706-dh-groups.ts", "tests/corpus/6707-dh-explicit-params.ts", "tests/corpus/6708-dh-errors.js", "tests/corpus/6709-dh-generate.ts", "tests/corpus/6710-dh-encodings.cjs", "tests/corpus/6711-dh-handles.ts", "tests/fixtures/node-types/dh.ts"] }, { "chapter": "errors", "symbols": ["ERR_CRYPTO_UNKNOWN_DH_GROUP", "ERR_CRYPTO_INVALID_KEYLEN", "ERR_CRYPTO_INVALID_STATE"], "status": "partial", "evidence": ["tests/corpus/6708-dh-errors.js"] }, @@ -437,6 +444,7 @@ { "symbols": ["crypto.createPrivateKey", "crypto.createPublicKey", "crypto.generateKeyPair", "crypto.generateKeyPairSync", "crypto.sign", "crypto.verify", "crypto.createSign", "crypto.createVerify", "Sign", "sign.update", "sign.sign", "Verify", "verify.update", "verify.verify", "asymmetricKeyType", "asymmetricKeyDetails"], "status": "partial", "evidence": ["tests/corpus/7080-crypto-ed25519.mjs", "tests/corpus/7082-crypto-key-objects.ts", "tests/corpus/7083-crypto-sign-verify.ts", "tests/corpus/7084-crypto-key-pairs.cjs", "tests/fixtures/node-types/keys.ts"] }, { "symbols": ["crypto.getRandomValues"], "status": "supported", "evidence": ["tests/corpus/6204-crypto-get-random-values.ts", "tests/corpus/6205-crypto-get-random-values.js"] }, { "symbols": ["crypto.timingSafeEqual"], "status": "supported", "evidence": ["tests/corpus/5444-crypto-timing-safe-equal.js", "tests/corpus/2890-crypto-static-utility.ts"] }, + { "symbols": ["X509Certificate"], "status": "partial", "evidence": ["tests/corpus/1568-x509-fingerprint.ts", "tests/corpus/1572-x509-validity-date-gettime.ts", "tests/corpus/6936-x509-certificate-fields.ts"] }, { "symbols": ["crypto.randomInt"], "status": "partial", "evidence": ["tests/corpus/5442-crypto-random-values.ts", "tests/corpus/2890-crypto-static-utility.ts"] }, { "symbols": ["crypto.hkdf", "crypto.hkdfSync", "crypto.scrypt", "crypto.scryptSync"], "status": "partial", "evidence": ["tests/corpus/node24-crypto-kdf.ts", "tests/corpus/node24-crypto-kdf-errors.ts", "tests/corpus/node24-crypto-kdf-options.ts", "tests/corpus/5438-crypto-kdf-digests.ts"] }, { "symbols": ["EventEmitter", "emitter.on", "emitter.addListener", "emitter.once", "emitter.prependListener", "emitter.prependOnceListener", "emitter.off", "emitter.removeListener", "emitter.removeAllListeners", "emitter.emit", "emitter.listenerCount", "emitter.listeners", "emitter.rawListeners", "emitter.eventNames", "emitter.setMaxListeners", "emitter.getMaxListeners", "events.once"], "status": "partial", "evidence": ["tests/corpus/1677-emitter-listeners.ts", "tests/corpus/2620-ee-override-once-order.ts"] }, diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 0be5bdca2..9cd0abdd3 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -3533,17 +3533,45 @@ declare module "crypto" { keylen: number, callback: (error: Error | null, derivedKey: ArrayBuffer) => void, ): void; - /* The lowered X509Certificate surface is the data-record slice: - * fingerprint (the SHA-1 of the DER, uppercase colon-separated) and - * the validFrom/validTo validity window (Node's ASN1_TIME_print - * strings — "Jul 1 00:00:00 2026 GMT"; the cert-expiry idiom composes - * them with new Date(...).getTime()). All compute at construction; - * unparseable input throws Node's ERR_OSSL_PEM_NO_START_LINE Error. */ + /* The lowered X509Certificate surface is the data-record slice: the + * fields below, all computed at construction (raw decodes the input, + * and the others read raw). validFrom/validTo are Node's + * ASN1_TIME_print strings ("Jul 1 00:00:00 2026 GMT"). Unparseable + * input throws Node's ERR_OSSL_PEM_NO_START_LINE Error. */ export class X509Certificate { constructor(buffer: Uint8Array | string); + readonly ca: boolean; readonly fingerprint: string; + readonly fingerprint256: string; + readonly fingerprint512: string; + readonly subject: string; + readonly subjectAltName: string | undefined; + readonly infoAccess: string | undefined; + readonly issuer: string; + readonly raw: Buffer; + readonly serialNumber: string; + readonly signatureAlgorithm: string | undefined; + readonly signatureAlgorithmOid: string; readonly validFrom: string; + readonly validFromDate: Date; readonly validTo: string; + readonly validToDate: Date; + /* the certificate's public key; every read answers the same KeyObject */ + readonly publicKey: KeyObject; + verify(publicKey: KeyObject): boolean; + checkPrivateKey(privateKey: KeyObject): boolean; + checkIssued(otherCert: X509Certificate): boolean; + checkHost(name: string, options?: X509CheckOptions): string | undefined; + checkEmail(email: string, options?: X509CheckOptions): string | undefined; + checkIP(ip: string): string | undefined; + toLegacyObject(): import("tls").PeerCertificate; + } + export interface X509CheckOptions { + subject?: "always" | "default" | "never"; + wildcards?: boolean; + partialWildcards?: boolean; + multiLabelWildcards?: boolean; + singleLabelSubdomains?: boolean; } /* The crypto introspection statics: getFips() answers 0 (a compiled * binary is never a FIPS build), the three name lists bake as fresh @@ -5439,6 +5467,11 @@ declare module "net" { /* The demux route: hand an accepted socket to another server. */ emit(event: "connection", socket: Socket): boolean; on(event: "connection" | "secureConnection", listener: (socket: Socket) => void): void; + /* tls and https servers: a handshake that failed */ + on( + event: "tlsClientError", + listener: (err: Error, tlsSocket: import("tls").TLSSocket) => void, + ): void; on(event: "close" | "listening", listener: () => void): void; on(event: "drop", listener: (data?: DropArgument) => void): void; on(event: "timeout", listener: (socket: Socket) => void): void; @@ -5458,6 +5491,11 @@ declare module "net" { ): void; /* addListener IS on (Node aliases them) — the suite spells both. */ addListener(event: "connection" | "secureConnection", listener: (socket: Socket) => void): void; + /* tls and https servers: a handshake that failed */ + addListener( + event: "tlsClientError", + listener: (err: Error, tlsSocket: import("tls").TLSSocket) => void, + ): void; addListener(event: "close" | "listening", listener: () => void): void; addListener(event: "drop", listener: (data?: DropArgument) => void): void; addListener(event: "timeout", listener: (socket: Socket) => void): void; @@ -5471,6 +5509,11 @@ declare module "net" { listener: (req: import("http").IncomingMessage, res: import("http").ServerResponse) => void, ): void; once(event: "connection" | "secureConnection", listener: (socket: Socket) => void): void; + /* tls and https servers: a handshake that failed */ + once( + event: "tlsClientError", + listener: (err: Error, tlsSocket: import("tls").TLSSocket) => void, + ): void; once(event: "close" | "listening", listener: () => void): void; once(event: "drop", listener: (data?: DropArgument) => void): void; once(event: "timeout", listener: (socket: Socket) => void): void; @@ -5924,8 +5967,15 @@ declare module "node:http" { * are PEM strings or Buffers. Handshake failures tear the socket down * without emitting an event, Node's default for 'tlsClientError' with no listener. */ declare module "tls" { - import { Server, Socket } from "net"; - export { Server }; + import { Server as NetServer, Socket } from "net"; + /** tls.Server: a net server whose connections handshake first. */ + export interface Server extends NetServer { + /* serve `context` to clients whose SNI name matches `hostname` ('*' + * matches within one label); the newest match wins */ + addContext(hostname: string, context: TlsOptions | SecureContext): void; + /* new connections serve a context made from `options` */ + setSecureContext(options: TlsOptions): void; + } export interface TlsOptions { /* Optional in the DECLARATION only (real Node programs build these * literals with every TLS knob): the lowering still requires both — @@ -5959,7 +6009,47 @@ declare module "tls" { getCipher(): CipherNameAndProtocol; /* whether the handshake resumed a cached session */ isSessionReused(): boolean; + /* the peer's certificate: {} before the handshake or without one, + * null once the socket is destroyed; detailed adds issuerCertificate */ + getPeerCertificate(detailed: true): DetailedPeerCertificate; + getPeerCertificate(detailed?: false): PeerCertificate; + getPeerCertificate(detailed?: boolean): PeerCertificate | DetailedPeerCertificate; + /* the certificate this socket serves, the same way */ + getCertificate(): PeerCertificate | object | null; + /* a new X509Certificate on each call, or undefined without one */ + getPeerX509Certificate(): import("crypto").X509Certificate | undefined; + getX509Certificate(): import("crypto").X509Certificate | undefined; } + /* A certificate as getPeerCertificate() and X509Certificate's + * toLegacyObject() answer it: subject and issuer map attribute short + * names to values, infoAccess its " - " keys to values. */ + export interface PeerCertificate { + subject: { [attribute: string]: string | string[] }; + issuer: { [attribute: string]: string | string[] }; + subjectaltname?: string; + infoAccess?: { [key: string]: string[] }; + ca: boolean; + modulus?: string; + exponent?: string; + pubkey?: Buffer; + bits?: number; + valid_from: string; + valid_to: string; + fingerprint: string; + fingerprint256: string; + fingerprint512: string; + ext_key_usage?: string[]; + serialNumber: string; + raw: Buffer; + asn1Curve?: string; + nistCurve?: string; + } + /* getPeerCertificate(true): each certificate links to its issuer; a + * self-issued root is its own issuerCertificate */ + export interface DetailedPeerCertificate extends PeerCertificate { + issuerCertificate: DetailedPeerCertificate; + } + /** new tls.TLSSocket(socket, options): the server-mode wrap of an open * socket (a server connection or an http CONNECT socket). The options * record reads at runtime; isServer, cert, key, secureContext, @@ -6014,6 +6104,8 @@ declare module "tls" { /** An opaque parsed cert/key pair — what an SNI callback answers with * (the value is a runtime handle; the members are runtime-internal). */ export interface SecureContext {} + /* @types/node's name for createSecureContext's options */ + export type SecureContextOptions = TlsOptions; export function createSecureContext(options: TlsOptions): SecureContext; /** The CA-store introspection surface (scr_tls_ca.c): per-type cached * PEM string arrays. The host bundle stands in for Node's compiled-in diff --git a/packages/compiler/src/backend/executable-features.ts b/packages/compiler/src/backend/executable-features.ts index a9076af22..48be5b564 100644 --- a/packages/compiler/src/backend/executable-features.ts +++ b/packages/compiler/src/backend/executable-features.ts @@ -61,6 +61,7 @@ export function executableLinkFeatures(mod: IrModule): NativeLinkFeatures { dh: features.dh, pki: features.pki, ed25519: features.ed25519, + x509: features.x509, webcrypto: features.webcrypto, perfLoop: features.perfLoop, }; diff --git a/packages/compiler/src/backend/library-pack.ts b/packages/compiler/src/backend/library-pack.ts index 79be316db..e7fa7a782 100644 --- a/packages/compiler/src/backend/library-pack.ts +++ b/packages/compiler/src/backend/library-pack.ts @@ -64,6 +64,7 @@ export async function compilePackedLibrary( dh: false, pki: false, ed25519: false, + x509: options.x509 ?? false, webcrypto: false, perfLoop: false, tlsCa: false, diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 9df33e63f..5383ca034 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -1082,6 +1082,28 @@ export const LIB_FN_SYMS: Record = { "crypto.verifyOneshot": "scr_crypto_verify_oneshot", "crypto.createSign": "scr_crypto_create_sign", "crypto.createVerify": "scr_crypto_create_verify", + "crypto.x509Raw": "scr_crypto_x509_raw", + "crypto.x509RawDer": "scr_crypto_x509_raw_der", + "crypto.x509RawStr": "scr_crypto_x509_raw_str", + "crypto.x509Subject": "scr_crypto_x509_subject", + "crypto.x509Issuer": "scr_crypto_x509_issuer", + "crypto.x509SubjectAltName": "scr_crypto_x509_subject_alt_name", + "crypto.x509InfoAccess": "scr_crypto_x509_info_access", + "crypto.x509SerialNumber": "scr_crypto_x509_serial_number", + "crypto.x509Fingerprint256": "scr_crypto_x509_fingerprint256", + "crypto.x509Fingerprint512": "scr_crypto_x509_fingerprint512", + "crypto.x509Ca": "scr_crypto_x509_ca", + "crypto.x509SignatureAlgorithm": "scr_crypto_x509_signature_algorithm", + "crypto.x509SignatureAlgorithmOid": "scr_crypto_x509_signature_algorithm_oid", + "crypto.x509CheckHost": "scr_crypto_x509_check_host", + "crypto.x509CheckEmail": "scr_crypto_x509_check_email", + "crypto.x509CheckIP": "scr_crypto_x509_check_ip", + "crypto.x509CheckIssued": "scr_crypto_x509_check_issued", + "crypto.x509LegacyObject": "scr_crypto_x509_legacy_object", + "crypto.x509Pem": "scr_crypto_x509_pem", + "crypto.x509PublicKey": "scr_crypto_x509_public_key", + "crypto.x509Verify": "scr_crypto_x509_verify", + "crypto.x509CheckPrivateKey": "scr_crypto_x509_check_private_key", "fs.writeFileModeSync": "scr_fs_write_file_mode", "fs.chownSync": "scr_fs_chown", "fs.lchownSync": "scr_fs_lchown", diff --git a/packages/compiler/src/backend/llvm/lib-tls.ts b/packages/compiler/src/backend/llvm/lib-tls.ts index 1d1cf659c..307aeb3dd 100644 --- a/packages/compiler/src/backend/llvm/lib-tls.ts +++ b/packages/compiler/src/backend/llvm/lib-tls.ts @@ -110,6 +110,31 @@ export function emitTlsLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlValu return finishRuntimeCall(host, e, "scr_tls_sock_get_cipher", a); case "tls.sockAlpnProtocol": return finishRuntimeCall(host, e, "scr_tls_sock_alpn_protocol", a); + case "tls.serverAddContext": + return finishRuntimeCall(host, e, "scr_tls_server_add_context", [...a, ptr()]); + case "tls.serverAddContextCtx": + return finishRuntimeCall(host, e, "scr_tls_server_add_context", [a[0]!, a[1]!, ptr(), a[2]!]); + case "tls.serverSetSecureContext": + return finishRuntimeCall(host, e, "scr_tls_server_set_secure_context", a); + case "tls.serverOnClientError": { + // (err, tlsSocket) listeners by arity: the adapter retains what the + // listener takes. + const cb = args[1]!; + const thunk = `scr_net_client_error_thunk${callbackType(cb).params.length}`; + return finishRuntimeCall(host, e, "scr_net_server_on_client_error", [ + a[0]!, + ...callbackAdapter(host, cb, thunk, ["ptr", "ptr", "ptr"]), + a[2]!, + ]); + } + case "tls.sockGetPeerCertificate": + return finishRuntimeCall(host, e, "scr_tls_sock_get_peer_certificate", a); + case "tls.sockGetCertificate": + return finishRuntimeCall(host, e, "scr_tls_sock_get_certificate", a); + case "tls.sockPeerCertDer": + return finishRuntimeCall(host, e, "scr_tls_sock_peer_cert_der", a); + case "tls.sockOwnCertDer": + return finishRuntimeCall(host, e, "scr_tls_sock_own_cert_der", a); case "tls.sockAuthError": { const result = callRuntime(host, "scr_tls_sock_auth_error", "ptr", a); return nullableReference(host, e.type, result, "string", "nullT"); diff --git a/packages/compiler/src/backend/native-link-info-core.ts b/packages/compiler/src/backend/native-link-info-core.ts index c073bb9a6..1235a3f3e 100644 --- a/packages/compiler/src/backend/native-link-info-core.ts +++ b/packages/compiler/src/backend/native-link-info-core.ts @@ -104,6 +104,9 @@ export interface NativeLinkFeatures { /** Ed25519 keys and signatures with pki: scr_ed25519.c (the vendored * libsodium Ed25519). */ ed25519: boolean; + /** X509Certificate fields beyond the validity window and fingerprint: + * scr_x509.c. */ + x509: boolean; /** perf_hooks event-loop metrics: scr_perf_loop.c. */ perfLoop: boolean; tlsCa: boolean; diff --git a/packages/compiler/src/backend/native/contracts.ts b/packages/compiler/src/backend/native/contracts.ts index 53e160984..ef84f4d10 100644 --- a/packages/compiler/src/backend/native/contracts.ts +++ b/packages/compiler/src/backend/native/contracts.ts @@ -269,6 +269,8 @@ export interface CcOptions { /** Ed25519 with pki: compiles scr_ed25519.c (the vendored libsodium * Ed25519). */ ed25519?: boolean; + /** X509Certificate fields: compiles scr_x509.c. */ + x509?: boolean; /** crypto.subtle importKey/sign/verify/digest: compiles scr_webcrypto.c. */ webcrypto?: boolean; /** perf_hooks event-loop metrics: compiles scr_perf_loop.c. */ @@ -354,6 +356,8 @@ export interface LibArchiveOptions { searchParams?: boolean; emitter?: boolean; zlib?: boolean; + /** X509Certificate fields: scr_x509.c. */ + x509?: boolean; copying?: boolean; textDecoderLegacy?: boolean; } diff --git a/packages/compiler/src/backend/native/executable.ts b/packages/compiler/src/backend/native/executable.ts index 1578a0c80..59957f664 100644 --- a/packages/compiler/src/backend/native/executable.ts +++ b/packages/compiler/src/backend/native/executable.ts @@ -309,6 +309,9 @@ const RUNTIME_UNITS: readonly RuntimeUnit[] = [ unit((u) => u.opts.webcrypto, "scr_webcrypto.c"), unit((u) => u.opts.webcrypto === true && u.opts.pki === true, "scr_webcrypto_pki.c"), unit((u) => u.opts.pki === true && u.opts.ed25519 === true, "scr_ed25519.c"), + unit((u) => u.opts.x509 === true, "scr_x509.c"), + // The TLS socket certificate accessors read scr_tls.c and build with scr_x509.c. + unit((u) => u.tls && u.opts.x509 === true, "scr_tls_x509.c"), // The crypto global's object extends scr_async_dyn.c's. unit((u) => u.opts.webcrypto && u.opts.dynAsync, "scr_webcrypto_object.c"), // The CA-store unit rides its own gate OR the tls one: scr_tls.c diff --git a/packages/compiler/src/backend/native/library.ts b/packages/compiler/src/backend/native/library.ts index f04e9926c..cca706896 100644 --- a/packages/compiler/src/backend/native/library.ts +++ b/packages/compiler/src/backend/native/library.ts @@ -73,7 +73,7 @@ import { CacheInputsChangedError } from "./session.js"; * async_free refusal already guarantees nothing references them — and * scr_library.c (sink, arena, reset registry, library funnel) joins. The gated * units a library may reach are the pure-data ones (regex + the vendored matcher, assert, - * inspect, symbol, searchParams, emitter+dyn_handle, zlib); every + * inspect, symbol, searchParams, emitter+dyn_handle, zlib, x509); every * loop-hooked or ambient unit was refused at SC4005 before emission. * External-symbol contract: undefined references only to the target's C/math * runtime and system APIs. Windows embedders additionally link advapi32, @@ -115,6 +115,7 @@ export async function compileLibArchive(opts: LibArchiveOptions): Promise ...(opts.dynInvoke && opts.dynBuffer ? ["scr_bytes_dyn.c"] : []), ...(opts.dynTier === true ? ["scr_js_value.c", "scr_js_object.c"] : []), ...(opts.zlib ? ["scr_zlib.c"] : []), + ...(opts.x509 ? ["scr_x509.c"] : []), ...(opts.copying ? ["scr_copying.c"] : []), ]; const cflags = [ diff --git a/packages/compiler/src/backend/runtime-pack-targets.test.ts b/packages/compiler/src/backend/runtime-pack-targets.test.ts index 9846e8d89..9312ecfd0 100644 --- a/packages/compiler/src/backend/runtime-pack-targets.test.ts +++ b/packages/compiler/src/backend/runtime-pack-targets.test.ts @@ -129,6 +129,7 @@ const features = { dh: false, pki: false, ed25519: false, + x509: false, webcrypto: false, perfLoop: false, }; diff --git a/packages/compiler/src/backend/runtime-pack.test.ts b/packages/compiler/src/backend/runtime-pack.test.ts index e2b24f8ca..13f74d4e1 100644 --- a/packages/compiler/src/backend/runtime-pack.test.ts +++ b/packages/compiler/src/backend/runtime-pack.test.ts @@ -65,6 +65,7 @@ const BASE: NativeLinkFeatures = { dh: false, pki: false, ed25519: false, + x509: false, webcrypto: false, perfLoop: false, }; diff --git a/packages/compiler/src/backend/warm-cache.ts b/packages/compiler/src/backend/warm-cache.ts index 02acb5462..c42ceb79e 100644 --- a/packages/compiler/src/backend/warm-cache.ts +++ b/packages/compiler/src/backend/warm-cache.ts @@ -71,6 +71,7 @@ export async function warmNativeCaches( dh: false, pki: false, ed25519: false, + x509: false, webcrypto: false, perfLoop: false, tlsCa: false, diff --git a/packages/compiler/src/executable/executable-cache.test.ts b/packages/compiler/src/executable/executable-cache.test.ts index e066c0412..4aaa86e0d 100644 --- a/packages/compiler/src/executable/executable-cache.test.ts +++ b/packages/compiler/src/executable/executable-cache.test.ts @@ -69,6 +69,7 @@ const native: EarlyExecutableNativeFeatures = { dh: false, pki: false, ed25519: false, + x509: false, webcrypto: false, perfLoop: false, }; diff --git a/packages/compiler/src/executable/executable-cache.ts b/packages/compiler/src/executable/executable-cache.ts index 96922ca13..10fcae7c5 100644 --- a/packages/compiler/src/executable/executable-cache.ts +++ b/packages/compiler/src/executable/executable-cache.ts @@ -102,6 +102,7 @@ export interface EarlyExecutableNativeFeatures { dh: boolean; pki: boolean; ed25519: boolean; + x509: boolean; perfLoop: boolean; tlsCa: boolean; webcrypto: boolean; @@ -247,6 +248,7 @@ const BOOLEAN_NATIVE_KEYS = [ "dh", "pki", "ed25519", + "x509", "webcrypto", "perfLoop", ] as const satisfies readonly (keyof EarlyExecutableNativeFeatures)[]; diff --git a/packages/compiler/src/frontend/lowering/builtins/x509.ts b/packages/compiler/src/frontend/lowering/builtins/x509.ts new file mode 100644 index 000000000..bc0092369 --- /dev/null +++ b/packages/compiler/src/frontend/lowering/builtins/x509.ts @@ -0,0 +1,487 @@ +import * as ts from "../../ts7/adapter.js"; +import { type Lowerer } from "../lowerer.js"; +import { locOf } from "../../program.js"; +import { + BOOL, + BYTES_U8, + DYN, + F64, + STRING, + UNDEFINED_T, + type IrExpr, + type IrFunction, + type IrLibFn, + type IrType, + type SrcLoc, +} from "../../../ir/ir.js"; +import { everyStmtList } from "../../../ir/traverse.js"; +import { unsupportedDiag } from "../../../diagnostics/diagnostic.js"; +import { X509_PUBLIC_KEY_FIELD } from "../../type-mapper.js"; +import { keyedHelperName } from "../stable-names.js"; +import { x509RecordCall } from "../lower-classes.js"; + +/* node:crypto's X509Certificate members beyond its fields: the methods + * and the publicKey getter. A certificate is the Dirent-style record + * (type-mapper.ts), and each member reads its raw DER. checkHost, + * checkEmail, checkIP, checkIssued, toLegacyObject and the PEM of + * toString/toJSON run in scr_x509.c; + * publicKey, verify and checkPrivateKey read keys in scr_pki.c. The first + * publicKey read stores the KeyObject in the record's hidden slot, so + * every read answers the same object, as in Node. */ + +/** Whether `t` is the X509Certificate record (its hidden publicKey slot + * marks the shape; no program can name that field). */ +export function isX509Type(lowerer: Lowerer, t: IrType | null | undefined): boolean { + return ( + t?.kind === "record" && + lowerer.shapes.get(t.shapeId)?.fields.some((f) => f.name === X509_PUBLIC_KEY_FIELD) === true + ); +} + +/** Whether `node` is an X509Certificate record. */ +function isX509Record(lowerer: Lowerer, node: ts.Expression): boolean { + const type = lowerer.typeOf(node); + const sym = type.getSymbol(); + if (!sym || ts.symbolName(sym) !== "X509Certificate" || !lowerer.isStdlibSymbol(sym)) + return false; + return isX509Type(lowerer, lowerer.mapTypeOf(type)); +} + +/** A certificate in an `unknown` or `any` slot would cross as a plain + * object of its fields, which Node's certificate is not: its fields are + * prototype getters, and toString() and toJSON() give its PEM. Every such + * conversion in the lowered program, including a certificate inside an + * array or record that converts, is refused where it happens. */ +export function refuseX509DynValues(lowerer: Lowerer, functions: readonly IrFunction[]): void { + // Certificates exist only where `new X509Certificate` built one. + if ( + !lowerer.valueHelpers.has("x509.record:bytes") && + !lowerer.valueHelpers.has("x509.record:str") && + !lowerer.valueHelpers.has("x509.record:der") + ) + return; + const seen = new Map(); + const holds = (t: IrType): boolean => { + switch (t.kind) { + case "record": { + const known = seen.get(t.shapeId); + if (known !== undefined) return known; + seen.set(t.shapeId, false); + const shape = lowerer.shapes.get(t.shapeId); + const result = + isX509Type(lowerer, t) || + (shape !== undefined && + (shape.fields.some((f) => holds(f.type)) || + (shape.indexValue !== undefined && holds(shape.indexValue)))); + seen.set(t.shapeId, result); + return result; + } + case "array": + case "set": + return holds(t.elem); + case "map": + return holds(t.key) || holds(t.value); + case "promise": + return holds(t.inner); + case "union": + return lowerer.unions.get(t.unionId)?.arms.some(holds) === true; + default: + return false; + } + }; + const visitor = { + expr: (e: IrExpr): boolean => { + if (e.kind === "dynFrom" && holds(e.value.type)) { + lowerer.pushDiag( + unsupportedDiag( + "SC1090", + e.loc, + "X509Certificate values in 'unknown' or 'any' slots (Node keeps a certificate's fields as prototype getters, and its toString() and toJSON() give the PEM; keep the X509Certificate type)", + ), + ); + } + return true; + }, + stmt: (): boolean => true, + }; + for (const fn of functions) everyStmtList(fn.body, visitor); +} + +/** String(x509), `${x509}` and x509 + "": the certificate's toString(), + * its PEM. */ +export function x509ToString(record: IrExpr, loc: SrcLoc): IrExpr { + return { kind: "libCall", fn: "crypto.x509Pem", args: [rawOf(record, loc)], type: STRING, loc }; +} + +/** Node keeps a certificate's fields as prototype getters, so own-key + * walks (Object.keys/values/entries, for-in, spread, hasOwnProperty) see + * none of them. Those walks over a certificate fence instead of listing + * the fields. */ +export function fenceX509KeyWalk( + lowerer: Lowerer, + t: IrType | null | undefined, + node: ts.Node, + what: string, +): void { + if (!isX509Type(lowerer, t)) return; + lowerer.unsupported( + "SC1090", + node, + `${what} over X509Certificate values (Node keeps their fields as prototype getters, so own-key walks see none; read the fields)`, + ); +} + +function rawOf(record: IrExpr, loc: SrcLoc): IrExpr { + if (record.type.kind !== "record") return record; + return { + kind: "recordGet", + obj: record, + shapeId: record.type.shapeId, + field: "raw", + type: BYTES_U8, + loc, + }; +} + +const dynUndefined = (loc: SrcLoc): IrExpr => ({ + kind: "dynFrom", + value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, + type: DYN, + loc, +}); + +/** The method's string answer as `string | undefined`: "" is undefined. + * A lifted helper takes the text once. */ +function optionalString(lowerer: Lowerer, text: IrExpr, type: IrType, loc: SrcLoc): IrExpr { + if (type.kind !== "union") return text; + const def = lowerer.unions.get(type.unionId); + const stringTag = def ? def.arms.findIndex((a) => a.kind === "string") : -1; + const undefinedTag = def ? def.arms.findIndex((a) => a.kind === "undefinedT") : -1; + if (stringTag < 0 || undefinedTag < 0) return text; + const key = `x509.optional:${type.unionId}`; + let helper = lowerer.valueHelpers.get(key); + if (!helper) { + helper = keyedHelperName(lowerer, "%x509.optional", key); + lowerer.valueHelpers.set(key, helper); + const s: IrExpr = { kind: "varRef", localId: "s.0", type: STRING, loc }; + lowerer.liftedFns.push({ + name: helper, + params: [{ localId: "s.0", name: "s", type: STRING }], + returnType: type, + locals: [{ id: "s.0", name: "s", type: STRING, mutable: false }], + body: [ + { + kind: "return", + value: { + kind: "ternary", + cond: { + kind: "strEq", + negated: false, + left: s, + right: { kind: "strLit", value: "", type: STRING, loc }, + type: BOOL, + loc, + }, + then: { + kind: "unionWrap", + unionId: type.unionId, + tag: undefinedTag, + value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, + type, + loc, + }, + else_: { + kind: "unionWrap", + unionId: type.unionId, + tag: stringTag, + value: s, + type, + loc, + }, + type, + loc, + }, + loc, + }, + ], + loc, + }); + } + return { kind: "call", callee: helper, args: [text], type, loc }; +} + +/** `x509.publicKey`: the cached KeyObject (a lifted helper fills the + * hidden slot on the first read). */ +export function lowerX509PublicKey( + lowerer: Lowerer, + access: ts.PropertyAccessExpression, +): IrExpr | null { + if (access.name.text !== "publicKey" || access.questionDotToken) return null; + if (!isX509Record(lowerer, access.expression)) return null; + const loc = locOf(access); + const record = lowerer.lowerExpr(access.expression); + if (record.type.kind !== "record") return null; + const shapeId = record.type.shapeId; + const key = `x509.publicKey:${shapeId}`; + let helper = lowerer.valueHelpers.get(key); + if (!helper) { + helper = keyedHelperName(lowerer, "%x509.publicKey", key); + lowerer.valueHelpers.set(key, helper); + const c: IrExpr = { kind: "varRef", localId: "c.0", type: record.type, loc }; + const slot: IrExpr = { + kind: "recordGet", + obj: c, + shapeId, + field: X509_PUBLIC_KEY_FIELD, + type: DYN, + loc, + }; + lowerer.liftedFns.push({ + name: helper, + params: [{ localId: "c.0", name: "c", type: record.type }], + returnType: DYN, + locals: [{ id: "c.0", name: "c", type: record.type, mutable: false }], + body: [ + { + kind: "if", + cond: { kind: "dynTest", test: "undefined", value: slot, type: BOOL, loc }, + then: [ + { + kind: "recordSet", + obj: c, + shapeId, + field: X509_PUBLIC_KEY_FIELD, + value: { + kind: "libCall", + fn: "crypto.x509PublicKey", + args: [rawOf(c, loc)], + type: DYN, + loc, + }, + loc, + }, + ], + else_: null, + loc, + }, + { kind: "return", value: slot, loc }, + ], + loc, + }); + } + return { kind: "call", callee: helper, args: [record], type: DYN, loc }; +} + +type X509Method = { fn: IrLibFn; min: number; max: number; form: string }; + +const METHODS: ReadonlyMap = new Map([ + ["verify", { fn: "crypto.x509Verify", min: 1, max: 1, form: "verify(publicKey)" }], + [ + "checkPrivateKey", + { fn: "crypto.x509CheckPrivateKey", min: 1, max: 1, form: "checkPrivateKey(privateKey)" }, + ], + ["checkIssued", { fn: "crypto.x509CheckIssued", min: 1, max: 1, form: "checkIssued(otherCert)" }], + ["checkHost", { fn: "crypto.x509CheckHost", min: 1, max: 2, form: "checkHost(name[, options])" }], + [ + "checkEmail", + { fn: "crypto.x509CheckEmail", min: 1, max: 2, form: "checkEmail(email[, options])" }, + ], + ["checkIP", { fn: "crypto.x509CheckIP", min: 1, max: 2, form: "checkIP(ip[, options])" }], + ["toLegacyObject", { fn: "crypto.x509LegacyObject", min: 0, max: 0, form: "toLegacyObject()" }], + ["toString", { fn: "crypto.x509Pem", min: 0, max: 0, form: "toString()" }], + ["toJSON", { fn: "crypto.x509Pem", min: 0, max: 0, form: "toJSON()" }], +]); + +/** The X509Certificate methods: verify, checkPrivateKey, checkIssued, + * checkHost, checkEmail, checkIP, toLegacyObject, toString and toJSON. */ +export function lowerX509Call(lowerer: Lowerer, call: ts.CallExpression): IrExpr | null { + if (call.questionDotToken || !ts.isPropertyAccessExpression(call.expression)) return null; + const access = call.expression; + if (access.questionDotToken) return null; + const method = METHODS.get(access.name.text); + if (!method) return null; + if (!isX509Record(lowerer, access.expression)) return null; + const loc = locOf(call); + const args = call.arguments.nodes; + if (args.length < method.min || args.length > method.max || args.some(ts.isSpreadElement)) { + lowerer.noLowering( + `X509Certificate.${access.name.text} with ${args.length} argument(s)`, + call, + `the supported form is ${method.form}`, + ); + } + const raw = rawOf(lowerer.lowerExpr(access.expression), loc); + if (method.fn === "crypto.x509LegacyObject") { + return { kind: "libCall", fn: method.fn, args: [raw], type: DYN, loc }; + } + if (method.fn === "crypto.x509Pem") + return { kind: "libCall", fn: method.fn, args: [raw], type: STRING, loc }; + if (method.fn === "crypto.x509CheckIssued") { + if (!isX509Record(lowerer, args[0]!)) { + // Node's validation of otherCert, after both operands evaluate. + return { + kind: "seqExpr", + stmts: [{ kind: "exprStmt", expr: raw, loc }], + result: { + kind: "libCall", + fn: "error.argTypeThrow", + args: [ + { kind: "strLit", value: "otherCert", type: STRING, loc }, + { kind: "strLit", value: "an instance of X509Certificate", type: STRING, loc }, + lowerer.lowerExprExpecting(args[0]!, DYN), + ], + type: BOOL, + loc, + }, + type: BOOL, + loc, + }; + } + const other = rawOf(lowerer.lowerExpr(args[0]!), loc); + return { kind: "libCall", fn: method.fn, args: [raw, other], type: BOOL, loc }; + } + const first = lowerer.lowerExprExpecting(args[0]!, DYN); + if (method.fn === "crypto.x509Verify" || method.fn === "crypto.x509CheckPrivateKey") { + return { kind: "libCall", fn: method.fn, args: [raw, first], type: BOOL, loc }; + } + const options = args.length > 1 ? lowerer.lowerExprExpecting(args[1]!, DYN) : dynUndefined(loc); + const text: IrExpr = { + kind: "libCall", + fn: method.fn, + args: [raw, first, options], + type: STRING, + loc, + }; + return optionalString(lowerer, text, lowerer.mapTypeOf(lowerer.typeOf(call)) ?? STRING, loc); +} + +/** The TLS socket certificate accessors. getPeerCertificate([detailed]) + * and getCertificate() answer Node's legacy object (scr_tls_x509.c): + * Node reads `detailed` only when it is true. getPeerX509Certificate() and + * getX509Certificate() build a new X509Certificate from the certificate's + * DER on each call, or answer undefined without one. Null for other + * members. */ +export function lowerTlsCertificateCall( + lowerer: Lowerer, + call: ts.CallExpression, + name: string, + receiver: () => IrExpr, +): IrExpr | null { + const loc = locOf(call); + const args = call.arguments.nodes; + if (name === "getPeerCertificate" || name === "getCertificate") { + const max = name === "getPeerCertificate" ? 1 : 0; + if (args.length > max || args.some(ts.isSpreadElement)) { + lowerer.noLowering( + `${name} with ${args.length} argument(s)`, + call, + name === "getPeerCertificate" + ? "the form is getPeerCertificate(detailed?)" + : "getCertificate() takes no arguments", + ); + } + const socket = receiver(); + const value: IrExpr = + name === "getCertificate" + ? { kind: "libCall", fn: "tls.sockGetCertificate", args: [socket], type: DYN, loc } + : { + kind: "libCall", + fn: "tls.sockGetPeerCertificate", + args: [ + socket, + args.length > 0 ? lowerer.lowerExprExpecting(args[0]!, DYN) : dynUndefined(loc), + ], + type: DYN, + loc, + }; + const declared = lowerer.mapTypeOf(lowerer.typeOf(call)); + return declared === null || declared.kind === "dyn" + ? value + : lowerer.coerceInto(call, value, declared); + } + if (name !== "getPeerX509Certificate" && name !== "getX509Certificate") return null; + if (args.length > 0) { + lowerer.noLowering( + `${name} with ${args.length} argument(s)`, + call, + `${name}() takes no arguments`, + ); + } + const type = lowerer.mapTypeOf(lowerer.typeOf(call)); + const def = type?.kind === "union" ? lowerer.unions.get(type.unionId) : undefined; + const recordTag = def ? def.arms.findIndex((arm) => isX509Type(lowerer, arm)) : -1; + const undefinedTag = def ? def.arms.findIndex((arm) => arm.kind === "undefinedT") : -1; + if (type?.kind !== "union" || !def || recordTag < 0 || undefinedTag < 0) { + lowerer.noLowering( + `tlsSocket.${name} with this result type`, + call, + "its type is X509Certificate | undefined", + ); + } + const record = def.arms[recordTag] as IrType & { kind: "record" }; + const der: IrExpr = { + kind: "libCall", + fn: name === "getPeerX509Certificate" ? "tls.sockPeerCertDer" : "tls.sockOwnCertDer", + args: [receiver()], + type: BYTES_U8, + loc, + }; + const key = `tls.x509:${type.unionId}`; + let helper = lowerer.valueHelpers.get(key); + if (!helper) { + helper = keyedHelperName(lowerer, "%tls.x509", key); + lowerer.valueHelpers.set(key, helper); + const d: IrExpr = { kind: "varRef", localId: "d.0", type: BYTES_U8, loc }; + lowerer.liftedFns.push({ + name: helper, + params: [{ localId: "d.0", name: "der", type: BYTES_U8 }], + returnType: type, + locals: [{ id: "d.0", name: "der", type: BYTES_U8, mutable: false }], + body: [ + { + kind: "return", + value: { + kind: "ternary", + cond: { + kind: "bin", + op: "===", + left: { + kind: "bytesIntrinsic", + method: "length", + receiver: d, + args: [], + type: F64, + loc, + }, + right: { kind: "numLit", value: 0, type: F64, loc }, + type: BOOL, + loc, + }, + then: { + kind: "unionWrap", + unionId: type.unionId, + tag: undefinedTag, + value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, + type, + loc, + }, + else_: { + kind: "unionWrap", + unionId: type.unionId, + tag: recordTag, + // The handshake's DER, read without PEM detection. + value: x509RecordCall(lowerer, d, record, loc, true), + type, + loc, + }, + type, + loc, + }, + loc, + }, + ], + loc, + }); + } + return { kind: "call", callee: helper, args: [der], type, loc }; +} diff --git a/packages/compiler/src/frontend/lowering/expressions/binary.ts b/packages/compiler/src/frontend/lowering/expressions/binary.ts index b26a3dd9f..ab5ddeab6 100644 --- a/packages/compiler/src/frontend/lowering/expressions/binary.ts +++ b/packages/compiler/src/frontend/lowering/expressions/binary.ts @@ -58,6 +58,7 @@ import { fenceNodeModuleMutation, lowerRequireCacheHas } from "../lower-node-mod import { errorToStringCall } from "../error-methods.js"; import { classToStringConversion, classUnionToString } from "../class-to-primitive.js"; import { isPerfEntryType, perfEntryTag } from "../builtins/performance.js"; +import { isX509Type, x509ToString } from "../builtins/x509.js"; import { guardNullProto, nullProtoRecordShape } from "../null-prototype.js"; import { numLit, varRef } from "../../../ir/build.js"; import { lowerUrlAssignment } from "../builtins/url.js"; @@ -798,6 +799,7 @@ export function ensureString(lowerer: Lowerer, e: IrExpr, node: ts.Node): IrExpr // other record is Object.prototype.toString's constant. const shape = lowerer.shapes.get(e.type.shapeId); if (isPerfEntryType(lowerer, e.type)) return perfEntryTag(lowerer, e, e.type, e.loc); + if (isX509Type(lowerer, e.type)) return x509ToString(e, e.loc); if (shape && !shape.tuple && !shape.fields.some((f) => f.name === "toString")) { // A null-prototype record (Object.groupBy) has no toString or // valueOf: ToPrimitive throws Node's TypeError. diff --git a/packages/compiler/src/frontend/lowering/expressions/object-literals.ts b/packages/compiler/src/frontend/lowering/expressions/object-literals.ts index 4cc0bee1a..d6f413dc1 100644 --- a/packages/compiler/src/frontend/lowering/expressions/object-literals.ts +++ b/packages/compiler/src/frontend/lowering/expressions/object-literals.ts @@ -28,6 +28,7 @@ import type { IndexMergeContributor } from "../containers/indexed-objects.js"; import type { KeyOrderSegment } from "../key-order-witness.js"; import { PERF_ENTRY_MARKER, + X509_PUBLIC_KEY_FIELD, isGenericCallableMemberType, jsOpenObjectType, } from "../../type-mapper.js"; @@ -501,6 +502,13 @@ function fenceAccessorSpreadSource( "object spread over performance entries (Node keeps their fields as prototype getters, so own-key walks see none; read the fields or call toJSON())", ); } + if (srcShape && srcShape.fields.some((f) => f.name === X509_PUBLIC_KEY_FIELD)) { + lowerer.unsupported( + "SC1090", + prop, + "object spread over X509Certificate values (Node keeps their fields as prototype getters, so own-key walks see none; read the fields)", + ); + } if (srcShape && shapeHasAccessorSlots(srcShape)) { lowerer.unsupported( "SC1090", diff --git a/packages/compiler/src/frontend/lowering/expressions/property-access.ts b/packages/compiler/src/frontend/lowering/expressions/property-access.ts index 8148e85f5..b542fa303 100644 --- a/packages/compiler/src/frontend/lowering/expressions/property-access.ts +++ b/packages/compiler/src/frontend/lowering/expressions/property-access.ts @@ -58,6 +58,7 @@ import { BYTES_ELEMENT_SIZE, } from "../../../ir/ir.js"; import { lowerNavigatorMember } from "../builtins/navigator.js"; +import { lowerX509PublicKey } from "../builtins/x509.js"; import { NODE_COMPAT_VERSION } from "../builtins/process.js"; import { inlineNamespaceRequireOf, @@ -347,6 +348,11 @@ export function lowerPropertyAccessExpr( const reading = lowerHistogramProperty(lowerer, expr); if (reading) return reading; } + // An X509Certificate's publicKey KeyObject. + { + const publicKey = lowerX509PublicKey(lowerer, expr); + if (publicKey) return publicKey; + } // `.length` of a forwarded fixed tuple (a typed `arguments`, a tuple // rest parameter, an alias of either): the signature's arity. if (expr.name.text === "length" && !expr.questionDotToken) { diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 8ac97fd32..87102377c 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -167,6 +167,7 @@ import { lowerPerfHooksCall, perfEntryTag, } from "./builtins/performance.js"; +import { fenceX509KeyWalk } from "./builtins/x509.js"; import { lowerProcStreamMethodCall, lowerProcessBuiltinModuleNamespace, @@ -2957,6 +2958,7 @@ function lowerObjectOwnCall( } else if (type.kind === "record") { const shape = lowerer.shapes.get(type.shapeId); fencePerfEntryKeyWalk(lowerer, type, receiverNode ?? call, `Object.prototype.${method}`); + fenceX509KeyWalk(lowerer, type, receiverNode ?? call, `Object.prototype.${method}`); if (!shape || shape.tuple || shapeHasAccessorSlots(shape)) { lowerer.noLowering( "Object.prototype." + method + " over this record shape", @@ -8921,6 +8923,7 @@ function lowerObjectStaticCall( // RESULTS, invoked in key order. The static field walk models neither // (accessor slots live outside declaredOrder), so the surface fences. fencePerfEntryKeyWalk(lowerer, argIr, call, `Object.${member}`); + fenceX509KeyWalk(lowerer, argIr, call, `Object.${member}`); if (shapeHasAccessorSlots(shape)) { lowerer.unsupported( "SC1090", diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index 3e49304d2..2283c7dfb 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -43,6 +43,7 @@ import type { FnCtx, Lowerer } from "./lowerer.js"; import { inlineNamespaceRequireOf, lowerWithInlineRequireInit } from "./cjs-inline-require.js"; import { BOOL, + BYTES_U8, canDynCheckTo, DATE_T, DYN, @@ -99,6 +100,7 @@ import { jsOpenObjectType, typeKey, withUnitArm, + X509_PUBLIC_KEY_FIELD, } from "../type-mapper.js"; import { canonicalBuiltinModule, @@ -10108,6 +10110,52 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { const agent = lowerHttpAgentNew(lowerer, expr); if (agent) return agent; } + // `new crypto.X509Certificate(data)` — the Dirent-style data record: + // the certificate's lowered members (fingerprint — the SHA-1 of the + // DER, uppercase colon-separated — plus the validFrom/validTo + // validity window in Node's ASN1_TIME_print shape) compute AT + // CONSTRUCTION, when Node parses too, so unparseable input throws + // Node's exact PEM error here (ERR_OSSL_PEM_NO_START_LINE) and the + // handle never exists. Both import forms (`crypto.X509Certificate` + // through the namespace, named `X509Certificate`); Buffer input only + // — the readFileSync idiom. mapType interns the matching record, so + // locals and the composed member reads all flow. The data argument + // feeds THREE field computations, so construction goes through an + // interned helper whose parameter evaluates it exactly once. + { + const callee = expr.expression; + const isX509 = + (ts.isPropertyAccessExpression(callee) && + callee.name.text === "X509Certificate" && + lowerer.builtinNamespaceModuleOf(callee.expression) === "crypto") || + (ts.isIdentifier(callee) && + (() => { + const bi = lowerer.builtinImportOf(callee); + return bi?.module === "crypto" && bi.member === "X509Certificate"; + })()); + if (isX509) { + const args: readonly ts.Expression[] = expr.arguments?.nodes ?? []; + if (args.length !== 1) { + lowerer.noLowering( + "X509Certificate with this argument shape", + expr, + "the supported form is new X509Certificate(readFileSync(path))", + ); + } + const data = lowerer.lowerExpr(args[0]!); + const isBytes = data.type.kind === "bytes" && data.type.elem === "u8"; + if (!isBytes && data.type.kind !== "string") { + lowerer.noLowering( + `X509Certificate over '${lowerer.fmt(data.type)}' data`, + args[0]!, + "pass the certificate Buffer or PEM string (an fs.readFileSync result)", + ); + } + const t = lowerer.mapTypeOf(lowerer.typeOf(expr)); + if (t?.kind !== "record") lowerer.badType(expr, lowerer.typeOf(expr)); + return x509RecordCall(lowerer, data, t, loc); + } + } if ( ts.isIdentifier(expr.expression) || (ts.isPropertyAccessExpression(expr.expression) && @@ -10888,99 +10936,6 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { ); } } - // `new crypto.X509Certificate(data)` — the Dirent-style data record: - // the certificate's lowered members (fingerprint — the SHA-1 of the - // DER, uppercase colon-separated — plus the validFrom/validTo - // validity window in Node's ASN1_TIME_print shape) compute AT - // CONSTRUCTION, when Node parses too, so unparseable input throws - // Node's exact PEM error here (ERR_OSSL_PEM_NO_START_LINE) and the - // handle never exists. Both import forms (`crypto.X509Certificate` - // through the namespace, named `X509Certificate`); Buffer input only - // — the readFileSync idiom. mapType interns the matching record, so - // locals and the composed member reads all flow. The data argument - // feeds THREE field computations, so construction goes through an - // interned helper whose parameter evaluates it exactly once. - { - const callee = expr.expression; - const isX509 = - (ts.isPropertyAccessExpression(callee) && - callee.name.text === "X509Certificate" && - lowerer.builtinNamespaceModuleOf(callee.expression) === "crypto") || - (ts.isIdentifier(callee) && - (() => { - const bi = lowerer.builtinImportOf(callee); - return bi?.module === "crypto" && bi.member === "X509Certificate"; - })()); - if (isX509) { - const args: readonly ts.Expression[] = expr.arguments?.nodes ?? []; - if (args.length !== 1) { - lowerer.noLowering( - "X509Certificate with this argument shape", - expr, - "the supported form is new X509Certificate(readFileSync(path))", - ); - } - const data = lowerer.lowerExpr(args[0]!); - const isBytes = data.type.kind === "bytes" && data.type.elem === "u8"; - if (!isBytes && data.type.kind !== "string") { - lowerer.noLowering( - `X509Certificate over '${lowerer.fmt(data.type)}' data`, - args[0]!, - "pass the certificate Buffer or PEM string (an fs.readFileSync result)", - ); - } - const t = lowerer.mapTypeOf(lowerer.typeOf(expr)); - if (t?.kind !== "record") lowerer.badType(expr, lowerer.typeOf(expr)); - const key = `x509.record:${isBytes ? "bytes" : "str"}`; - let helper = lowerer.valueHelpers.get(key); - if (!helper) { - helper = keyedHelperName(lowerer, "%x509.record", key); - lowerer.valueHelpers.set(key, helper); - const dataT = data.type; - const dRef: IrExpr = { kind: "varRef", localId: "d.0", type: dataT, loc }; - const field = ( - name: string, - fn: - | "crypto.x509Fingerprint" - | "crypto.x509FingerprintStr" - | "crypto.x509ValidFrom" - | "crypto.x509ValidFromStr" - | "crypto.x509ValidTo" - | "crypto.x509ValidToStr", - ): { name: string; value: IrExpr } => ({ - name, - value: { kind: "libCall", fn, args: [dRef], type: STRING, loc }, - }); - lowerer.liftedFns.push({ - name: helper, - params: [{ localId: "d.0", name: "d", type: dataT }], - returnType: t, - locals: [{ id: "d.0", name: "d", type: dataT, mutable: false }], - body: [ - { - kind: "return", - value: { - kind: "recordLit", - fields: [ - field( - "fingerprint", - isBytes ? "crypto.x509Fingerprint" : "crypto.x509FingerprintStr", - ), - field("validFrom", isBytes ? "crypto.x509ValidFrom" : "crypto.x509ValidFromStr"), - field("validTo", isBytes ? "crypto.x509ValidTo" : "crypto.x509ValidToStr"), - ], - type: t, - loc, - }, - loc, - }, - ], - loc, - }); - } - return { kind: "call", callee: helper, args: [data], type: t, loc }; - } - } // `new X(...)` through a class VALUE (a classval-typed binding, array // element, map read, param): the newValue dispatch through the class // object's construct thunk. Arguments complete against the STATIC @@ -11254,6 +11209,151 @@ function genericFieldFnNodeOf( return null; } +/** The lifted `new crypto.X509Certificate(d)` constructor: raw decodes the + * input once (Node's PEM error throws here), and every other field reads + * raw. subjectAltName, infoAccess and signatureAlgorithm hold undefined + * where the runtime answers "". */ +/** The X509Certificate record `t` built from `data`, a certificate Buffer + * (PEM or DER) or PEM string, through the interned constructor helper. + * `der` marks a Buffer known to hold a certificate's DER (a TLS socket's), + * which is read without looking for PEM armor inside it. */ +export function x509RecordCall( + lowerer: Lowerer, + data: IrExpr, + t: IrType & { kind: "record" }, + loc: SrcLoc, + der = false, +): IrExpr { + const isBytes = data.type.kind === "bytes" && data.type.elem === "u8"; + const key = `x509.record:${der ? "der" : isBytes ? "bytes" : "str"}`; + let helper = lowerer.valueHelpers.get(key); + if (!helper) { + helper = keyedHelperName(lowerer, "%x509.record", key); + lowerer.valueHelpers.set(key, helper); + lowerer.liftedFns.push(x509RecordHelper(lowerer, helper, data.type, t, isBytes, der, loc)); + } + return { kind: "call", callee: helper, args: [data], type: t, loc }; +} + +function x509RecordHelper( + lowerer: Lowerer, + name: string, + dataT: IrType, + t: IrType & { kind: "record" }, + isBytes: boolean, + der: boolean, + loc: SrcLoc, +): IrFunction { + const shape = lowerer.shapes.get(t.shapeId); + if (!shape) throw new InternalCompilerError("lowerer bug: X509Certificate shape unregistered"); + const raw: IrExpr = { kind: "varRef", localId: "raw.0", type: BYTES_U8, loc }; + const call = (fn: IrLibFn, type: IrType): IrExpr => ({ + kind: "libCall", + fn, + args: [raw], + type, + loc, + }); + const locals: IrLocal[] = [ + { id: "d.0", name: "d", type: dataT, mutable: false }, + { id: "raw.0", name: "raw", type: BYTES_U8, mutable: false }, + ]; + const decls: IrStmt[] = [ + { + kind: "varDecl", + localId: "raw.0", + init: { + kind: "libCall", + fn: der ? "crypto.x509RawDer" : isBytes ? "crypto.x509Raw" : "crypto.x509RawStr", + args: [{ kind: "varRef", localId: "d.0", type: dataT, loc }], + type: BYTES_U8, + loc, + }, + loc, + }, + ]; + const validTime = (fn: IrLibFn): IrExpr => ({ + kind: "libCall", + fn: "date.newString", + args: [call(fn, STRING)], + type: DATE_T, + loc, + }); + const values: Record IrExpr> = { + ca: () => call("crypto.x509Ca", BOOL), + fingerprint: () => call("crypto.x509Fingerprint", STRING), + fingerprint256: () => call("crypto.x509Fingerprint256", STRING), + fingerprint512: () => call("crypto.x509Fingerprint512", STRING), + subject: () => call("crypto.x509Subject", STRING), + subjectAltName: (type) => optionalText("san", "crypto.x509SubjectAltName", type), + infoAccess: (type) => optionalText("access", "crypto.x509InfoAccess", type), + issuer: () => call("crypto.x509Issuer", STRING), + raw: () => raw, + serialNumber: () => call("crypto.x509SerialNumber", STRING), + signatureAlgorithm: (type) => optionalText("sigalg", "crypto.x509SignatureAlgorithm", type), + signatureAlgorithmOid: () => call("crypto.x509SignatureAlgorithmOid", STRING), + validFrom: () => call("crypto.x509ValidFrom", STRING), + validFromDate: () => validTime("crypto.x509ValidFrom"), + validTo: () => call("crypto.x509ValidTo", STRING), + validToDate: () => validTime("crypto.x509ValidTo"), + [X509_PUBLIC_KEY_FIELD]: () => ({ + kind: "dynFrom", + value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, + type: DYN, + loc, + }), + }; + /** A string | undefined field: the runtime's text, or undefined for "". */ + function optionalText(local: string, fn: IrLibFn, type: IrType): IrExpr { + if (type.kind !== "union") + throw new InternalCompilerError("lowerer bug: X509Certificate optional field type"); + const def = lowerer.unions.get(type.unionId); + const stringTag = def ? def.arms.findIndex((a) => a.kind === "string") : -1; + const undefinedTag = def ? def.arms.findIndex((a) => a.kind === "undefinedT") : -1; + if (stringTag < 0 || undefinedTag < 0) + throw new InternalCompilerError("lowerer bug: X509Certificate optional field arms"); + const id = `${local}.0`; + locals.push({ id, name: local, type: STRING, mutable: false }); + decls.push({ kind: "varDecl", localId: id, init: call(fn, STRING), loc }); + const text: IrExpr = { kind: "varRef", localId: id, type: STRING, loc }; + return { + kind: "ternary", + cond: { + kind: "strEq", + negated: false, + left: text, + right: { kind: "strLit", value: "", type: STRING, loc }, + type: BOOL, + loc, + }, + then: { + kind: "unionWrap", + unionId: type.unionId, + tag: undefinedTag, + value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc }, + type, + loc, + }, + else_: { kind: "unionWrap", unionId: type.unionId, tag: stringTag, value: text, type, loc }, + type, + loc, + }; + } + const fields = shape.fields.map((f) => { + const value = values[f.name]; + if (!value) throw new InternalCompilerError(`lowerer bug: X509Certificate field ${f.name}`); + return { name: f.name, value: value(f.type) }; + }); + return { + name, + params: [{ localId: "d.0", name: "d", type: dataT }], + returnType: t, + locals, + body: [...decls, { kind: "return", value: { kind: "recordLit", fields, type: t, loc }, loc }], + loc, + }; +} + /** Whether a JavaScript class's own binding is the target of * `Object.defineProperty`/`defineProperties` in its file * (`Object.defineProperty(Definition, "name", { value })`): its constructor diff --git a/packages/compiler/src/frontend/lowering/lower-server.ts b/packages/compiler/src/frontend/lowering/lower-server.ts index cb79accea..4121d13b4 100644 --- a/packages/compiler/src/frontend/lowering/lower-server.ts +++ b/packages/compiler/src/frontend/lowering/lower-server.ts @@ -1,4 +1,5 @@ import { keyedHelperName } from "./stable-names.js"; +import { lowerTlsCertificateCall } from "./builtins/x509.js"; import { dynUndefinedExpr, nodeThrowExpr, @@ -1765,12 +1766,82 @@ function lowerNetServerMethodCall( ); return { kind: "libCall", fn: "net.serverCloseCb", args: [receiver, cb], type: VOID, loc }; } + if (name === "addContext" || name === "setSecureContext") { + // tls.Server's SNI table and default context (scr_tls.c): addContext + // takes a SecureContext or createSecureContext's options; the runtime + // throws Node's errors and the fence on a non-TLS server. + requireStatementPosition(lowerer, call, `server.${name}(...)`); + const want = name === "addContext" ? 2 : 1; + if (args.length !== want || args.some(ts.isSpreadElement)) { + lowerer.noLowering( + `${name} with ${args.length} arguments`, + call, + name === "addContext" + ? "the form is addContext(servername, context)" + : "the form is setSecureContext(options)", + ); + } + const receiver = coerceToHandle(lowerer, access.expression, NETSERVER_T); + if (name === "setSecureContext") { + const options = lowerer.lowerExprExpecting(args[0]!, DYN); + return { + kind: "libCall", + fn: "tls.serverSetSecureContext", + args: [receiver, options], + type: VOID, + loc, + }; + } + const servername = lowerer.lowerExprExpecting(args[0]!, DYN); + const context = lowerer.lowerExpr(args[1]!); + if (context.type.kind === "secureCtx") { + return { + kind: "libCall", + fn: "tls.serverAddContextCtx", + args: [receiver, servername, context], + type: VOID, + loc, + }; + } + return { + kind: "libCall", + fn: "tls.serverAddContext", + args: [receiver, servername, lowerer.coerceInto(args[1]!, context, DYN)], + type: VOID, + loc, + }; + } if ((name === "on" || name === "once" || name === "addListener") && args.length === 2) { requireStatementPosition(lowerer, call, `server.${name}(...)`); const once = boolLit(name === "once", loc); const evT = lowerer.typeOf(args[0]!); const event = evT.isStringLiteralType() ? evT.value : null; const receiver = coerceToHandle(lowerer, access.expression, NETSERVER_T); + if (event === "tlsClientError") { + // A failed handshake on a tls or https server: (err, tlsSocket). + const listener = args[1]!; + const { cb } = lowerCallbackArgShared( + lowerer, + listener, + "tlsClientError listeners", + 2, + (p, i) => + i === 0 ? p.kind === "object" && p.className === "%Error" : p.kind === "netSocket", + "use (err, tlsSocket), (err) or ()", + { + dynTuple: [ERROR_T, NETSOCKET_T], + checkAllParams: true, + adapt: (c) => voidizedCallback(lowerer, c, locOf(listener)), + }, + ); + return { + kind: "libCall", + fn: "tls.serverOnClientError", + args: [receiver, cb, once], + type: VOID, + loc, + }; + } if (event === "connection" || event === "secureConnection") { // 'secureConnection' rides the same list: a TLS server's // 'connection' listeners are DEFERRED to handshake completion @@ -2632,6 +2703,12 @@ function lowerNetSocketMethodCall( ? value : lowerer.coerceInto(call, value, declared); } + { + const certificate = lowerTlsCertificateCall(lowerer, call, name, () => + coerceToHandle(lowerer, access.expression, NETSOCKET_T), + ); + if (certificate) return certificate; + } if (name === "isSessionReused" && args.length === 0) { // TLSSocket.isSessionReused(): the client never offers a cached // session (no session resumption, a documented TLS divergence), so @@ -4941,19 +5018,12 @@ function lowerTlsServerOptions( } if (k !== "cert" && k !== "key") { const init = ts.isPropertyAssignment(prop) ? prop.initializer : null; - if ( - (k === "ca" || k === "rejectUnauthorized") && - (init === null || sideEffectFreeOptionValue(init)) - ) { - // Both are inert without requestCert (which fences): the server's - // `ca` verifies CLIENT certificates and rejectUnauthorized only - // gates that verification — Node-observably droppable, matching + if (k === "rejectUnauthorized" && (init === null || sideEffectFreeOptionValue(init))) { + // Without requestCert (a literal with requestCert or ca rides the + // runtime walk) rejectUnauthorized gates nothing — droppable, like // the runtime walk's split (effectful values keep the fence). continue; } - if (k === "requestCert" && (init === null || init.kind === ts.SyntaxKind.FalseKeyword)) { - continue; // Node's false default, spelled out - } fenceOrDropOptionKey( lowerer, prop, @@ -4964,8 +5034,6 @@ function lowerTlsServerOptions( { SNICallback: "SNICallback lowers on tls.createServer and http2.createSecureServer({ allowHTTP1: true, ... }) — serve one cert/key pair here", - requestCert: - "client-certificate handshakes are not modeled (SEMANTICS.md divergence 55) — requestCert: false is the lowered value", }, ); continue; // an undocumented key, dropped like Node drops it @@ -5063,12 +5131,19 @@ function tlsLiteralNeedsRuntimeWalk( ); } +/** The client-certificate options (requestCert, and ca, which also + * completes the server's own chain): the runtime walk implements them for + * tls.createServer and https.createServer, and the literal cert/key + * lowering does not. */ +const TLS_CLIENT_AUTH_OPTIONS: ReadonlySet = new Set(["requestCert", "ca"]); + /** tls.createServer options the runtime walk implements and the literal * cert/key lowering does not. */ const TLS_SERVER_RUNTIME_OPTIONS: ReadonlySet = new Set([ "ALPNProtocols", "minVersion", "maxVersion", + ...TLS_CLIENT_AUTH_OPTIONS, ]); function lowerTlsServerOptionsOrDyn( @@ -5092,7 +5167,7 @@ function lowerTlsServerOptionsOrDyn( lowerer.noLowering( `${what} with SNICallback and options the runtime walk reads`, sniOption, - "SNICallback lowers with cert and key; ALPNProtocols, minVersion, maxVersion and the validated options are not combined with it yet", + "SNICallback lowers with cert and key; ALPNProtocols, minVersion, maxVersion, requestCert, ca and the validated options are not combined with it yet", ); } } @@ -5124,14 +5199,14 @@ function lowerTlsServerOptionsOrDyn( * connect(options[, cb]) and connect(port[, host][, options][, cb]) with * a RUNTIME options record (the checked-dynamic JS lane's shape — a dyn * value, or a record that converts): the runtime walk implements - * port/host/socket/rejectUnauthorized/ca/servername/ALPNProtocols/minVersion/maxVersion/timeout and throws the catchable + * port/host/socket/rejectUnauthorized/ca/cert/key/servername/ALPNProtocols/minVersion/maxVersion/timeout and throws the catchable * fence for other documented members (the divergence-66 stance). The * callback (and 'secureConnect'/'connect' listeners) fires * post-handshake — Node's secureConnect timing. */ function lowerTlsConnectCall(lowerer: Lowerer, expr: ts.CallExpression, loc: SrcLoc): IrExpr { const args = expr.arguments.nodes; const FORMS_HINT = - "the supported forms are connect(options[, cb]) and connect(port[, host][, options][, cb]) — options implement port/host/socket/rejectUnauthorized/ca/servername/ALPNProtocols/minVersion/maxVersion/timeout"; + "the supported forms are connect(options[, cb]) and connect(port[, host][, options][, cb]) — options implement port/host/socket/rejectUnauthorized/ca/cert/key/servername/ALPNProtocols/minVersion/maxVersion/timeout"; if (args.length < 1 || args.length > 4 || args.some(ts.isSpreadElement)) { lowerer.noLowering(`tls.connect with ${args.length} arguments`, expr, FORMS_HINT); } @@ -5368,7 +5443,13 @@ function lowerTlsModuleCall( "the supported form is createSecureContext({ cert, key })", ); } - const opts = lowerTlsServerOptionsOrDyn(lowerer, args[0]!, "tls.createSecureContext"); + const opts = lowerTlsServerOptionsOrDyn( + lowerer, + args[0]!, + "tls.createSecureContext", + false, + TLS_CLIENT_AUTH_OPTIONS, + ); if (opts.dyn !== undefined) { return { kind: "libCall", @@ -5625,7 +5706,13 @@ function lowerHttpsModuleCall( "the supported form is createServer({ cert, key }, (req, res) => ...)", ); } - const opts = lowerTlsServerOptionsOrDyn(lowerer, args[0]!, "https.createServer", true); + const opts = lowerTlsServerOptionsOrDyn( + lowerer, + args[0]!, + "https.createServer", + true, + TLS_CLIENT_AUTH_OPTIONS, + ); if (args.length === 1) { // The handler-less form: 'request' listeners arrive later via // server.on("request", ...) — the createSecureServer emission's @@ -6281,7 +6368,9 @@ function runtimeRequestOptions( return ( (ts.isPropertyAssignment(prop) || ts.isShorthandPropertyAssignment(prop)) && (ts.isIdentifier(prop.name) || ts.isStringLiteral(prop.name)) && - prop.name.text === "socketPath" + (prop.name.text === "socketPath" || + // a client certificate: the runtime request walk reads cert and key + (secureish && (prop.name.text === "cert" || prop.name.text === "key"))) ); }); if (!needsRuntime) return null; diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index 82c0dbb3e..a19061fde 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -248,6 +248,7 @@ import { constituentTypes } from "../ts7/checker.js"; import { npmStaticPackageOfPath } from "../npm-static.js"; import { fenceNodeModuleMutation } from "./lower-node-module.js"; import { fencePerfEntryKeyWalk } from "./builtins/performance.js"; +import { fenceX509KeyWalk } from "./builtins/x509.js"; import { classGeneratorIterable } from "./class-iterables.js"; import { iterableUnionOf, lowerForOfIterable } from "./iterable-values.js"; @@ -11935,6 +11936,7 @@ function lowerForIn(lowerer: Lowerer, stmt: ts.ForInStatement): IrStmt { // them (accessor slots live outside declaredOrder), so the loop // fences rather than skip keys. fencePerfEntryKeyWalk(lowerer, receiver.type, stmt.expression, "for-in"); + fenceX509KeyWalk(lowerer, receiver.type, stmt.expression, "for-in"); if (shapeHasAccessorSlots(rShape)) { lowerer.unsupported( "SC1090", diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 35080e8f8..2dd44bf3e 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -63,6 +63,7 @@ import { discoverWasmModules, type WasmModuleReport } from "../../wasm/discover. import { encodeBase64 } from "../../wasm/base64.js"; import { resolveRequireRuntime } from "../runtime-resolve.js"; import { lowerKeyObjectCall } from "./builtins/key-object.js"; +import { lowerX509Call, refuseX509DynValues } from "./builtins/x509.js"; import { isEcdhType, lowerEcdhCall } from "./builtins/ecdh.js"; import { isDiffieHellmanType, lowerDiffieHellmanCall } from "./builtins/dh.js"; import { fenceWebCryptoMember, lowerWebCryptoCall } from "./builtins/webcrypto.js"; @@ -7825,6 +7826,7 @@ export class Lowerer { // every producer and consumer agrees. Programs with no unregistered // reference are untouched — byte-stability holds. checkRequireBindingAccesses(this, functions); + refuseX509DynValues(this, functions); const module: IrModule | null = this.diags.length > 0 ? null @@ -13237,6 +13239,7 @@ export class Lowerer { lowerStaticBlobCall(this, expr) ?? lowerWebCryptoCall(this, expr) ?? lowerKeyObjectCall(this, expr) ?? + lowerX509Call(this, expr) ?? lowerEcdhCall(this, expr) ?? lowerDiffieHellmanCall(this, expr) ?? lowerNetAddressCall(this, expr) ?? diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index fc159116f..8a9b59c9a 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -169,9 +169,10 @@ export const WEBCRYPTO_DYN_TYPES: ReadonlySet = new Set([ "AesDerivedKeyParams", ]); -/** node:crypto's key and signature option interfaces: the key functions, - * KeyObject.export and sign/verify take them as checked-dynamic arguments - * (scr_lib.c, scr_pki.c). */ +/** node:crypto's key, signature and X509Certificate check option + * interfaces: the key functions, KeyObject.export, sign/verify and the + * X509Certificate checks take them as checked-dynamic arguments + * (scr_lib.c, scr_pki.c, scr_x509.c). */ export const CRYPTO_KEY_OPTION_DYN_TYPES: ReadonlySet = new Set([ "AsymmetricKeyExportOptions", "ECKeyPairKeyObjectOptions", @@ -190,6 +191,7 @@ export const CRYPTO_KEY_OPTION_DYN_TYPES: ReadonlySet = new Set([ "SigningOptions", "VerifyKeyObjectInput", "VerifyPublicKeyInput", + "X509CheckOptions", ]); export const FETCH_AMBIENT_TYPES = [ @@ -4457,13 +4459,25 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { ), }; } - // crypto.X509Certificate — the Dirent-style data record: THREE visible - // fields (fingerprint and the validFrom/validTo validity window, all - // computed at construction by the new-expression lowering). Module- - // checked like SecureContext; @types/node declares the class inside - // `declare module "crypto"`, the shipped fallback mirrors it. - // JSON.stringify of one shows the three fields where Node's - // internal-slot object shows {} — the Dirent %dtype edge's cousin. + // X509Certificate.toLegacyObject()'s PeerCertificate (and tls's detailed + // form) is a plain checked-dynamic object. + if ( + psym !== undefined && + (ts.symbolName(psym) === "PeerCertificate" || + ts.symbolName(psym) === "DetailedPeerCertificate") && + psym.declarations.some( + (d) => ts.isInterfaceDeclaration(d) && ctx.isStdlibFile(ts.getSourceFileOfNode(d)), + ) + ) { + return DYN; + } + // crypto.X509Certificate — the Dirent-style data record: its fields are + // the certificate's lowered members, all computed at construction by the + // new-expression lowering (raw decodes the input once, and the others + // read raw). Module-checked like SecureContext; @types/node declares the + // class inside `declare module "crypto"`, the shipped fallback mirrors + // it. JSON.stringify of one shows the fields where Node's internal-slot + // object shows {} — the Dirent %dtype edge's cousin. if ( psym !== undefined && ts.symbolName(psym) === "X509Certificate" && @@ -4474,17 +4488,19 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { isDeclaredInAmbientModule(d, "crypto"), ) ) { + const optionalString = withUndefinedArm(STRING, ctx.unions); + if (!optionalString) return null; + const fields = X509_FIELDS.map(([name, type]) => ({ + name, + type: type === "string?" ? optionalString : type, + })); return { kind: "record", shapeId: ctx.shapes.intern( - [ - { name: "fingerprint", type: STRING }, - { name: "validFrom", type: STRING }, - { name: "validTo", type: STRING }, - ], + [...fields].sort((a, b) => (a.name < b.name ? -1 : 1)), false, undefined, - ["fingerprint", "validFrom", "validTo"], + fields.map((f) => f.name), ), }; } @@ -6693,6 +6709,32 @@ function boundVoidReturnType(p: ts.Type, resolveTypeParam?: TypeParamResolver): * result is exactly the nullable-callback shape mapType's union branch * admits, `(() => void) | undefined`) so the interned union is IDENTICAL * to what mapping the checker's own `T | undefined` produces. */ +/** The X509Certificate record's hidden slot for its publicKey KeyObject, + * filled on the first read (builtins/x509.ts). */ +export const X509_PUBLIC_KEY_FIELD = "%publicKey"; + +/** The X509Certificate record's fields in @types/node's declaration order + * ("string?" is string | undefined), then the hidden publicKey slot. */ +export const X509_FIELDS: readonly (readonly [string, IrType | "string?"])[] = [ + ["ca", BOOL], + ["fingerprint", STRING], + ["fingerprint256", STRING], + ["fingerprint512", STRING], + ["subject", STRING], + ["subjectAltName", "string?"], + ["infoAccess", "string?"], + ["issuer", STRING], + ["raw", { kind: "bytes", elem: "u8" }], + ["serialNumber", STRING], + ["signatureAlgorithm", "string?"], + ["signatureAlgorithmOid", STRING], + ["validFrom", STRING], + ["validFromDate", DATE_T], + ["validTo", STRING], + ["validToDate", DATE_T], + [X509_PUBLIC_KEY_FIELD, DYN], +]; + export function withUndefinedArm(t: IrType, unions: UnionRegistry): IrType | null { return withUnitArm(t, "undefinedT", unions); } diff --git a/packages/compiler/src/index.ts b/packages/compiler/src/index.ts index 58dc39c7b..8b88ead00 100644 --- a/packages/compiler/src/index.ts +++ b/packages/compiler/src/index.ts @@ -638,6 +638,7 @@ async function compileExecutableNative( dh: features.dh, pki: features.pki, ed25519: features.ed25519, + x509: features.x509, webcrypto: features.webcrypto, perfLoop: features.perfLoop, ...(onArtifactReady === undefined ? {} : { onArtifactReady }), @@ -1869,6 +1870,7 @@ function libraryNativeFeatures(mod: IrModule, backend: "llvm"): EarlyLibraryNati searchParams: features.searchParams, emitter: features.emitter, zlib: features.zlib, + x509: features.x509, copying: features.copying, textDecoderLegacy: features.legacyTextDecoder, dynInvoke: features.dynInvoke, @@ -1964,6 +1966,7 @@ async function compileLibraryNative( searchParams: features.searchParams, emitter: features.emitter, zlib: features.zlib, + x509: features.x509, copying: features.copying, textDecoderLegacy: features.textDecoderLegacy, dynInvoke: features.dynInvoke, diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index c8e7536ae..7682fe148 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -247,6 +247,11 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "tls.connectCb", "tls.wrapSocket", "tls.wrapSocketCtx", + // addContext's ERR_TLS_REQUIRED_SERVER_NAME and the context's errors, + // setSecureContext's validateObject. + "tls.serverAddContext", + "tls.serverAddContextCtx", + "tls.serverSetSecureContext", // The CA-store surface: an unknown getCACertificates type throws // Node's ERR_INVALID_ARG_VALUE TypeError; setDefaultCACertificates // throws Node's ERR_CRYPTO_OPERATION_FAILED on a certificate-free @@ -1037,6 +1042,16 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "crypto.diffieHellman", "crypto.createSign", "crypto.createVerify", + "crypto.x509Raw", + "crypto.x509RawDer", + "crypto.x509RawStr", + // Node's argument errors (name, options, pkey) and the key parse. + "crypto.x509CheckHost", + "crypto.x509CheckEmail", + "crypto.x509CheckIP", + "crypto.x509PublicKey", + "crypto.x509Verify", + "crypto.x509CheckPrivateKey", ]); /** libCall members that always throw. Their result type is the replaced diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index d563f2951..982550d72 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -1216,6 +1216,38 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "crypto.x509ValidFromStr": { argTypes: [STRING], result: STRING }, "crypto.x509ValidTo": { argTypes: [BYTES_U8], result: STRING }, "crypto.x509ValidToStr": { argTypes: [STRING], result: STRING }, + /** The certificate's DER as a fresh Buffer (the raw field), decoded + * once from the constructor's input; the same PEM error (may-throw). */ + "crypto.x509Raw": { argTypes: [BYTES_U8], result: BYTES_U8 }, + "crypto.x509RawDer": { argTypes: [BYTES_U8], result: BYTES_U8 }, + "crypto.x509RawStr": { argTypes: [STRING], result: BYTES_U8 }, + /** The remaining X509Certificate fields over that DER, in Node's + * renderings (scr_lib.c). subjectAltName, infoAccess and + * signatureAlgorithm answer "" where Node answers undefined. Borrowed; + * never throw. */ + "crypto.x509Subject": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509Issuer": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509SubjectAltName": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509InfoAccess": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509SerialNumber": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509Fingerprint256": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509Fingerprint512": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509Ca": { argTypes: [BYTES_U8], result: BOOL }, + "crypto.x509SignatureAlgorithm": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509SignatureAlgorithmOid": { argTypes: [BYTES_U8], result: STRING }, + /** X509Certificate methods over its raw DER. checkHost/checkEmail/checkIP + * answer the matching name or "" (undefined), checkIssued compares two + * certificates, x509Pem is toString's PEM (scr_x509.c); publicKey, + * verify and checkPrivateKey read keys (scr_pki.c). */ + "crypto.x509CheckHost": { argTypes: [BYTES_U8, DYN, DYN], result: STRING }, + "crypto.x509CheckEmail": { argTypes: [BYTES_U8, DYN, DYN], result: STRING }, + "crypto.x509CheckIP": { argTypes: [BYTES_U8, DYN, DYN], result: STRING }, + "crypto.x509CheckIssued": { argTypes: [BYTES_U8, BYTES_U8], result: BOOL }, + "crypto.x509LegacyObject": { argTypes: [BYTES_U8], result: DYN }, + "crypto.x509Pem": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509PublicKey": { argTypes: [BYTES_U8], result: DYN }, + "crypto.x509Verify": { argTypes: [BYTES_U8, DYN], result: BOOL }, + "crypto.x509CheckPrivateKey": { argTypes: [BYTES_U8, DYN], result: BOOL }, "fs.closeSync": { argTypes: [F64], result: VOID }, "stats.isFile": { argTypes: [STATS_T], result: BOOL }, "stats.isDirectory": { argTypes: [STATS_T], result: BOOL }, @@ -2218,6 +2250,13 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "tls.sockGetProtocol": { argTypes: [NETSOCKET_T], result: DYN }, "tls.sockGetCipher": { argTypes: [NETSOCKET_T], result: DYN }, "tls.sockAlpnProtocol": { argTypes: [NETSOCKET_T], result: DYN }, + /** getPeerCertificate(detailed) and getCertificate() (the legacy object, + * {} or null; scr_tls_x509.c), and the DER behind getPeerX509Certificate() + * and getX509Certificate() (a Buffer, empty without a certificate). */ + "tls.sockGetPeerCertificate": { argTypes: [NETSOCKET_T, DYN], result: DYN }, + "tls.sockGetCertificate": { argTypes: [NETSOCKET_T], result: DYN }, + "tls.sockPeerCertDer": { argTypes: [NETSOCKET_T], result: BYTES_U8 }, + "tls.sockOwnCertDer": { argTypes: [NETSOCKET_T], result: BYTES_U8 }, "tls.sockAuthError": { argTypes: [NETSOCKET_T], result: VOID }, "tls.sockOnSecureConnect": { argTypes: [NETSOCKET_T, { kind: "func", params: [], ret: VOID }, BOOL], @@ -2249,6 +2288,13 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ * walk — a validated { cert, key } bag builds the real context. * May-throw. */ "tls.createSecureContextDyn": { argTypes: [DYN], result: SECURECTX_T }, + /** server.addContext(servername, options | SecureContext), + * server.setSecureContext(options) and the 'tlsClientError' listener of + * a tls or https server (scr_tls.c). */ + "tls.serverAddContext": { argTypes: [NETSERVER_T, DYN, DYN], result: VOID }, + "tls.serverAddContextCtx": { argTypes: [NETSERVER_T, DYN, SECURECTX_T], result: VOID }, + "tls.serverSetSecureContext": { argTypes: [NETSERVER_T, DYN], result: VOID }, + "tls.serverOnClientError": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, /** tls.getCACertificates(type): validateString + the documented name * set, then the trailing compiler-rendered fence — ALWAYS THROWS (the * error.nodeThrow polymorphic-result carve-out). May-throw seed. */ diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 2ae19375f..cf1f30a4c 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -738,6 +738,9 @@ export const PKI_LIB_FNS: ReadonlySet = new Set([ "crypto.generateKeyPairSync", "crypto.signOneshot", "crypto.verifyOneshot", + "crypto.x509PublicKey", + "crypto.x509Verify", + "crypto.x509CheckPrivateKey", "crypto.diffieHellman", ]); @@ -1120,6 +1123,34 @@ const RUNTIME_FEATURE_RULES = { /** crypto.subtle importKey/sign/verify/digest and CryptoKey: * scr_webcrypto.c. */ webcrypto: rule({ prefixes: ["webcrypto."] }), + /** scr_x509.c: the X509Certificate fields beyond the validity window and + * fingerprint, which stay in scr_lib.c. */ + x509: rule({ + fns: [ + "crypto.x509Ca", + "crypto.x509Fingerprint256", + "crypto.x509Fingerprint512", + "crypto.x509InfoAccess", + "crypto.x509Issuer", + "crypto.x509Raw", + "crypto.x509RawDer", + "crypto.x509RawStr", + "crypto.x509SerialNumber", + "crypto.x509SignatureAlgorithm", + "crypto.x509SignatureAlgorithmOid", + "crypto.x509Subject", + "crypto.x509SubjectAltName", + "crypto.x509CheckHost", + "crypto.x509CheckEmail", + "crypto.x509CheckIP", + "crypto.x509CheckIssued", + "crypto.x509LegacyObject", + "crypto.x509Pem", + // getPeerCertificate and getCertificate build with scr_x509.c too. + "tls.sockGetPeerCertificate", + "tls.sockGetCertificate", + ], + }), zlib: rule({ prefixes: ["zlib."] }), }; @@ -1151,6 +1182,7 @@ function noRuntimeFeatures(): RuntimeFeatures { dynInvoke: false, dynTier: false, ecdh: false, + x509: false, dh: false, emitter: false, eventTarget: false, diff --git a/packages/compiler/src/library/ir-policy.ts b/packages/compiler/src/library/ir-policy.ts index ac5d5e47b..fde82f2b6 100644 --- a/packages/compiler/src/library/ir-policy.ts +++ b/packages/compiler/src/library/ir-policy.ts @@ -63,6 +63,9 @@ const LIB_MODE_REFUSED_PREFIXES: readonly [string, string][] = [ ["crypto.generateKeyPair", "asymmetric KeyObjects, generateKeyPair, sign and verify"], ["crypto.signOneshot", "asymmetric KeyObjects, generateKeyPair, sign and verify"], ["crypto.verifyOneshot", "asymmetric KeyObjects, generateKeyPair, sign and verify"], + ["crypto.x509PublicKey", "X509Certificate publicKey, verify and checkPrivateKey"], + ["crypto.x509Verify", "X509Certificate publicKey, verify and checkPrivateKey"], + ["crypto.x509CheckPrivateKey", "X509Certificate publicKey, verify and checkPrivateKey"], ["crypto.diffieHellman", "crypto.diffieHellman"], ["webcrypto.", "WebCrypto (crypto.subtle)"], ["fs.watch", "fs.watch"], diff --git a/packages/compiler/src/library/library-cache.test.ts b/packages/compiler/src/library/library-cache.test.ts index 846d90272..c19275733 100644 --- a/packages/compiler/src/library/library-cache.test.ts +++ b/packages/compiler/src/library/library-cache.test.ts @@ -85,6 +85,7 @@ test("early library cache restores generated artifacts and metadata", async () = searchParams: false, emitter: false, zlib: false, + x509: false, copying: false, textDecoderLegacy: false, dynInvoke: false, @@ -138,6 +139,7 @@ test("early library cache publishes after creating a fresh output directory", as searchParams: false, emitter: false, zlib: false, + x509: false, copying: false, textDecoderLegacy: false, dynInvoke: false, @@ -168,6 +170,7 @@ test("early library cache hits refresh every payload's LRU time", async () => { searchParams: false, emitter: false, zlib: false, + x509: false, copying: false, textDecoderLegacy: false, dynInvoke: false, @@ -213,6 +216,7 @@ test("early library cache misses on source edits and newly-resolved candidates", searchParams: false, emitter: false, zlib: false, + x509: false, copying: false, textDecoderLegacy: false, dynInvoke: false, @@ -242,6 +246,7 @@ test("early library cache misses on source edits and newly-resolved candidates", searchParams: false, emitter: false, zlib: false, + x509: false, copying: false, textDecoderLegacy: false, dynInvoke: false, @@ -291,6 +296,7 @@ test("semantic library cache restores and rebases IR after a comment-only edit", searchParams: false, emitter: false, zlib: false, + x509: false, copying: false, textDecoderLegacy: false, dynInvoke: false, @@ -354,6 +360,7 @@ test("semantic library cache refuses token and directive edits", async () => { searchParams: false, emitter: false, zlib: false, + x509: false, copying: false, textDecoderLegacy: false, dynInvoke: false, @@ -402,6 +409,7 @@ test("semantic LLVM cache accepts comment edits that shift source lines", async searchParams: false, emitter: false, zlib: false, + x509: false, copying: false, textDecoderLegacy: false, dynInvoke: false, @@ -440,6 +448,7 @@ test("semantic LLVM cache accepts line separator normalization", async () => { searchParams: false, emitter: false, zlib: false, + x509: false, copying: false, textDecoderLegacy: false, dynInvoke: false, @@ -501,6 +510,7 @@ test("semantic LLVM cache rebases comment edits in multi-source graphs", async ( searchParams: false, emitter: false, zlib: false, + x509: false, copying: false, textDecoderLegacy: false, dynInvoke: false, @@ -540,6 +550,7 @@ test("early library cache is separated by the host Node version", async () => { searchParams: false, emitter: false, zlib: false, + x509: false, copying: false, textDecoderLegacy: false, dynInvoke: false, @@ -571,6 +582,7 @@ test("early library cache rejects corrupted artifacts and metadata", async () => searchParams: false, emitter: false, zlib: false, + x509: false, copying: false, textDecoderLegacy: false, dynInvoke: false, @@ -605,6 +617,7 @@ test("disabled early library cache performs no reads or writes", async () => { searchParams: false, emitter: false, zlib: false, + x509: false, copying: false, textDecoderLegacy: false, dynInvoke: false, diff --git a/packages/compiler/src/library/library-cache.ts b/packages/compiler/src/library/library-cache.ts index 3e77ccced..7e61e95b8 100644 --- a/packages/compiler/src/library/library-cache.ts +++ b/packages/compiler/src/library/library-cache.ts @@ -54,6 +54,7 @@ interface EarlyLibraryCacheStamp { searchParams: boolean; emitter: boolean; zlib: boolean; + x509: boolean; copying: boolean; textDecoderLegacy: boolean; }; @@ -74,6 +75,7 @@ export interface EarlyLibraryNativeFeatures { searchParams: boolean; emitter: boolean; zlib: boolean; + x509: boolean; copying: boolean; textDecoderLegacy: boolean; /** Volatile exact-source build identity emitted from the tiny identity TU. */ @@ -132,6 +134,7 @@ const BOOLEAN_NATIVE_KEYS = [ "searchParams", "emitter", "zlib", + "x509", "copying", "textDecoderLegacy", ] as const satisfies readonly (keyof EarlyLibraryNativeFeatures)[]; diff --git a/packages/compiler/src/native/cli.ts b/packages/compiler/src/native/cli.ts index aa46944f5..b729b2557 100644 --- a/packages/compiler/src/native/cli.ts +++ b/packages/compiler/src/native/cli.ts @@ -147,6 +147,7 @@ async function main(): Promise { dh: false, pki: false, ed25519: false, + x509: false, webcrypto: false, perfLoop: false, tlsCa: false, diff --git a/packages/compiler/src/native/prepare.ts b/packages/compiler/src/native/prepare.ts index a238029dc..1530e8759 100644 --- a/packages/compiler/src/native/prepare.ts +++ b/packages/compiler/src/native/prepare.ts @@ -250,6 +250,7 @@ function validFeatures(value: unknown): value is NativeLinkFeatures { "dh", "pki", "ed25519", + "x509", "webcrypto", "perfLoop", ].every((name) => typeof features[name] === "boolean"); diff --git a/packages/compiler/src/native/sanitizer.test.ts b/packages/compiler/src/native/sanitizer.test.ts index 33a4c19b9..e039d6404 100644 --- a/packages/compiler/src/native/sanitizer.test.ts +++ b/packages/compiler/src/native/sanitizer.test.ts @@ -125,6 +125,7 @@ test.skipIf(process.platform !== "linux" && process.platform !== "darwin")( dh: false, pki: false, ed25519: false, + x509: false, webcrypto: false, perfLoop: false, nativeFetch: false, diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6936-x509-certificate-fields.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6936-x509-certificate-fields.ts.json new file mode 100644 index 000000000..2f7224882 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6936-x509-certificate-fields.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6936-x509-certificate-fields.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7090-x509-check-names.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7090-x509-check-names.ts.json new file mode 100644 index 000000000..e375f8d72 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7090-x509-check-names.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7090-x509-check-names.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7091-x509-certificate-keys.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7091-x509-certificate-keys.ts.json new file mode 100644 index 000000000..d4e9c4a6d --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7091-x509-certificate-keys.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7091-x509-certificate-keys.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7092-x509-legacy-object.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7092-x509-legacy-object.ts.json new file mode 100644 index 000000000..fd0b42f36 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7092-x509-legacy-object.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7092-x509-legacy-object.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7093-x509-methods-js.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7093-x509-methods-js.mjs.json new file mode 100644 index 000000000..deeeb0047 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7093-x509-methods-js.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7093-x509-methods-js.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7095-tls-peer-certificates.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7095-tls-peer-certificates.ts.json new file mode 100644 index 000000000..b6ebaa3e2 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7095-tls-peer-certificates.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7095-tls-peer-certificates.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7096-tls-peer-certificates.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7096-tls-peer-certificates.mjs.json new file mode 100644 index 000000000..2b85b584a --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7096-tls-peer-certificates.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7096-tls-peer-certificates.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7097-tls-client-certificates.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7097-tls-client-certificates.ts.json new file mode 100644 index 000000000..ecd6a35d7 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7097-tls-client-certificates.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7097-tls-client-certificates.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7098-tls-client-certificates-paths.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7098-tls-client-certificates-paths.ts.json new file mode 100644 index 000000000..8be352a07 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7098-tls-client-certificates-paths.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7098-tls-client-certificates-paths.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7099-tls-client-certificates.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7099-tls-client-certificates.mjs.json new file mode 100644 index 000000000..9dc6fbc9f --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7099-tls-client-certificates.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7099-tls-client-certificates.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7440-tls-server-add-context.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7440-tls-server-add-context.ts.json new file mode 100644 index 000000000..8acc4aade --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7440-tls-server-add-context.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7440-tls-server-add-context.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7441-tls-client-error.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7441-tls-client-error.ts.json new file mode 100644 index 000000000..ee5e78748 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7441-tls-client-error.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7441-tls-client-error.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7442-tls-server-contexts.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7442-tls-server-contexts.mjs.json new file mode 100644 index 000000000..22eda3ac8 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7442-tls-server-contexts.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7442-tls-server-contexts.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7443-tls-final-flight.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7443-tls-final-flight.ts.json new file mode 100644 index 000000000..2a8d134cc --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7443-tls-final-flight.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7443-tls-final-flight.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7444-tls-final-flight.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7444-tls-final-flight.mjs.json new file mode 100644 index 000000000..98f68721a --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7444-tls-final-flight.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7444-tls-final-flight.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7454-tls-peer-embedded-pem.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7454-tls-peer-embedded-pem.ts.json new file mode 100644 index 000000000..e4300cd15 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7454-tls-peer-embedded-pem.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7454-tls-peer-embedded-pem.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7455-tls-als-contexts.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7455-tls-als-contexts.mjs.json new file mode 100644 index 000000000..cd99090a6 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7455-tls-als-contexts.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7455-tls-als-contexts.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/x509-fences.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/x509-fences.ts.json new file mode 100644 index 000000000..e2b83a7c2 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/x509-fences.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/diagnostics/x509-fences.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/tls-client-certificates.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/tls-client-certificates.ts.json new file mode 100644 index 000000000..449e0f3ac --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/tls-client-certificates.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/node-types/tls-client-certificates.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/tls-peer-certificates.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/tls-peer-certificates.ts.json new file mode 100644 index 000000000..c5f8ed40a --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/tls-peer-certificates.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/node-types/tls-peer-certificates.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/tls-server-contexts.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/tls-server-contexts.ts.json new file mode 100644 index 000000000..73e294ea2 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/tls-server-contexts.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/node-types/tls-server-contexts.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/x509-methods.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/x509-methods.ts.json new file mode 100644 index 000000000..c42f8f9cc --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/node-types/x509-methods.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/node-types/x509-methods.ts" + ], + "diags": [] +} diff --git a/packages/runtime-pack-common/library-matrix.mjs b/packages/runtime-pack-common/library-matrix.mjs index d9878ec7c..1a621a375 100644 --- a/packages/runtime-pack-common/library-matrix.mjs +++ b/packages/runtime-pack-common/library-matrix.mjs @@ -13,6 +13,7 @@ export function withLibraryRuntimeFlavors(matrix) { "scr_events_emitter.c", "scr_dyn_handle.c", "scr_zlib.c", + "scr_x509.c", "scr_copying.c", "scr_dyn_invoke.c", "scr_bytes_dyn.c", diff --git a/packages/runtime-pack-common/runtime-pack-matrix.mjs b/packages/runtime-pack-common/runtime-pack-matrix.mjs index 0ab467236..2c02b55c3 100644 --- a/packages/runtime-pack-common/runtime-pack-matrix.mjs +++ b/packages/runtime-pack-common/runtime-pack-matrix.mjs @@ -163,6 +163,9 @@ export const OPTIONAL_RUNTIME_SOURCES = [ ["scr_webcrypto.c", "webcrypto"], ["scr_webcrypto_pki.c", all("webcrypto", "pki")], ["scr_ed25519.c", all("pki", "ed25519")], + ["scr_x509.c", "x509"], + // The TLS socket certificate accessors read scr_tls.c and build with scr_x509.c. + ["scr_tls_x509.c", all("tlsEffective", "x509")], // WebCrypto's AES ciphers run over the cipher feature's mbedTLS archive. ["scr_webcrypto_aes.c", all("cipher", "webcrypto")], ["scr_fetch.c", "nativeFetch"], diff --git a/packages/runtime-wasm32-wasi/scripts/build.mjs b/packages/runtime-wasm32-wasi/scripts/build.mjs index cbe744e4e..2a2766f4b 100644 --- a/packages/runtime-wasm32-wasi/scripts/build.mjs +++ b/packages/runtime-wasm32-wasi/scripts/build.mjs @@ -26,6 +26,7 @@ process.env.SCRIPTC_RUNTIME_PACK_CONFIG = JSON.stringify({ "scr_pki.c", "scr_webcrypto_pki.c", "scr_ed25519.c", + "scr_tls_x509.c", "scr_webcrypto_aes.c", "scr_wasm.c", "scr_fetch.c", diff --git a/packages/runtime/src/scr_crypto.h b/packages/runtime/src/scr_crypto.h index 03a9dd109..15180e880 100644 --- a/packages/runtime/src/scr_crypto.h +++ b/packages/runtime/src/scr_crypto.h @@ -305,5 +305,36 @@ ScrDyn *scr_crypto_create_sign(ScrDyn *algorithm); ScrDyn *scr_crypto_create_verify(ScrDyn *algorithm); bool scr_crypto_is_asymmetric_key(const ScrDyn *value); const char *scr_crypto_asymmetric_key_type(const ScrDyn *value); +/* X509Certificate fields (scr_x509.c): raw decodes the constructor's input (+1 Buffer, + * or NULL with Node's PEM error pending); the others read that DER + * (borrowed) and never throw. subjectAltName, infoAccess and + * signatureAlgorithm answer "" where Node answers undefined. */ +ScrBytes *scr_crypto_x509_raw(ScrBytes *data); +ScrBytes *scr_crypto_x509_raw_der(ScrBytes *der); +ScrBytes *scr_crypto_x509_raw_str(ScrStr *pem); +ScrStr *scr_crypto_x509_subject(ScrBytes *der); +ScrStr *scr_crypto_x509_issuer(ScrBytes *der); +ScrStr *scr_crypto_x509_subject_alt_name(ScrBytes *der); +ScrStr *scr_crypto_x509_info_access(ScrBytes *der); +ScrStr *scr_crypto_x509_serial_number(ScrBytes *der); +ScrStr *scr_crypto_x509_fingerprint256(ScrBytes *der); +ScrStr *scr_crypto_x509_fingerprint512(ScrBytes *der); +bool scr_crypto_x509_ca(ScrBytes *der); +ScrStr *scr_crypto_x509_signature_algorithm(ScrBytes *der); +ScrStr *scr_crypto_x509_signature_algorithm_oid(ScrBytes *der); +ScrStr *scr_crypto_x509_pem(ScrBytes *der); +/* X509Certificate methods over the DER (borrowed). checkHost, checkEmail + * and checkIP answer the matching name ("" for none, Node's undefined) or + * NULL with Node's argument error pending (scr_x509.c). publicKey, verify + * and checkPrivateKey read keys (scr_pki.c): publicKey is +1 or NULL, and + * the two checks answer false with the error pending when they throw. */ +ScrStr *scr_crypto_x509_check_host(ScrBytes *der, ScrDyn *name, ScrDyn *options); +ScrStr *scr_crypto_x509_check_email(ScrBytes *der, ScrDyn *email, ScrDyn *options); +ScrStr *scr_crypto_x509_check_ip(ScrBytes *der, ScrDyn *ip, ScrDyn *options); +bool scr_crypto_x509_check_issued(ScrBytes *der, ScrBytes *issuer_der); +ScrDyn *scr_crypto_x509_legacy_object(ScrBytes *der); +ScrDyn *scr_crypto_x509_public_key(ScrBytes *der); +bool scr_crypto_x509_verify(ScrBytes *der, ScrDyn *key); +bool scr_crypto_x509_check_private_key(ScrBytes *der, ScrDyn *key); #endif /* SCR_CRYPTO_H */ diff --git a/packages/runtime/src/scr_lib.c b/packages/runtime/src/scr_lib.c index 18d9c39e5..28e1bda07 100644 --- a/packages/runtime/src/scr_lib.c +++ b/packages/runtime/src/scr_lib.c @@ -10522,10 +10522,29 @@ static bool scr_x509_der(const uint8_t *in, size_t n, const uint8_t **der, size_ *der = NULL; *der_len = 0; *decoded = NULL; + /* One whole DER SEQUENCE is the certificate itself: these members read + * the DER the constructor already decoded, whose extensions can carry + * PEM armor as text. */ + if (n >= 2 && in[0] == 0x30) { + size_t len = in[1], head = 2; + if (len & 0x80) { + size_t k = len & 0x7f; + len = 0; + head = 2 + k; + for (size_t i = 0; i < k && k <= 4 && head <= n; i++) len = (len << 8) | in[2 + i]; + if (k == 0 || k > 4) head = n + 1; + } + if (head <= n && len == n - head) { + *der = in; + *der_len = n; + return true; + } + } /* PEM: base64-decode the armor's body. */ const uint8_t *b = NULL; + /* OpenSSL's PEM reader looks for the armor at the start of a line. */ for (size_t i = 0; i + sizeof begin - 1 <= n; i++) { - if (memcmp(in + i, begin, sizeof begin - 1) == 0) { + if ((i == 0 || in[i - 1] == '\n') && memcmp(in + i, begin, sizeof begin - 1) == 0) { b = in + i + sizeof begin - 1; break; } diff --git a/packages/runtime/src/scr_net.c b/packages/runtime/src/scr_net.c index 9ff9ba8b0..bd1233978 100644 --- a/packages/runtime/src/scr_net.c +++ b/packages/runtime/src/scr_net.c @@ -451,6 +451,9 @@ struct ScrNetServer { ScrStr *unix_path; /* listen(path): the bound socket file, removed at close */ size_t nconns; ScrNetLs conn_ls, err_ls, close_ls, listening_cbs, timeout_ls; + /* tls/https servers: 'tlsClientError' (err, tlsSocket), fired by the + * TLS unit for a handshake that fails */ + ScrNetLs client_error_ls; /* server.maxConnections (unset = undefined) and its 'drop' listeners */ bool max_conns_set; double max_conns; @@ -2134,6 +2137,53 @@ void scr_net_server_set_close_override(ScrNetServer *s, ScrClosure *ov /*moves*/ s->close_override = ov; } +void scr_net_server_on_client_error(ScrNetServer *s, ScrClosure *cb /*moves*/, void *fn, bool once) { + if (s->close_emitted) { + scr_closure_release(cb); + return; + } + scr_net_ls_add(&s->client_error_ls, cb, fn, once); +} + +typedef void (*ScrNetClientErrorFn)(ScrClosure *, ScrError *, ScrNetSocket *); + +/* Node emits 'tlsClientError' from the accepted connection's handshake, + * which has no AsyncLocalStorage store, not from the server's listen() + * context the connection's other events run in. */ +void scr_net_server_fire_client_error(ScrNetServer *s, ScrError *err /*borrowed*/, + ScrNetSocket *sock /*borrowed*/) { + if (s->client_error_ls.n == 0) return; + ScrNetL *snap; + size_t n = scr_net_ls_snapshot(&s->client_error_ls, &snap); + ScrAlsCtx *prev = scr_als_dispatch_enter(NULL); + scr_dyn_this_push(s, SCR_DYNH_NET_SERVER); + for (size_t i = 0; i < n; i++) { + if (!scr_exc_pending()) ((ScrNetClientErrorFn)snap[i].fn)(snap[i].cb, err, sock); + scr_closure_release(snap[i].cb); + } + scr_dyn_this_pop(); + scr_als_dispatch_leave(prev); + free(snap); +} + +/* The 'tlsClientError' listener adapters by arity; the arguments arrive + * borrowed and the listener takes them +1. */ +void scr_net_client_error_thunk0(ScrClosure *cb, ScrError *err, ScrNetSocket *sock) { + (void)err; + (void)sock; + ((void (*)(ScrClosure *))cb->fn)(cb); +} + +void scr_net_client_error_thunk1(ScrClosure *cb, ScrError *err, ScrNetSocket *sock) { + (void)sock; + ((void (*)(ScrClosure *, ScrError *))cb->fn)(cb, scr_error_retain(err)); +} + +void scr_net_client_error_thunk2(ScrClosure *cb, ScrError *err, ScrNetSocket *sock) { + ((void (*)(ScrClosure *, ScrError *, ScrNetSocket *))cb->fn)(cb, scr_error_retain(err), + scr_net_sock_retain(sock)); +} + void scr_net_server_on_error(ScrNetServer *s, ScrClosure *cb /*moves*/, ScrChildErrFn fn, bool once) { if (s->close_emitted) { @@ -5318,6 +5368,17 @@ void scr_net_sock_transport_error_code(ScrNetSocket *s, const char *msg, const c scr_net_sock_transport_error(s, msg); } +void scr_net_sock_transport_report(ScrNetSocket *s, const char *msg, const char *code) { + if (s->pending_err) return; + s->pending_err = scr_str_new(msg, strlen(msg)); + s->pending_code = code; +} + +void scr_net_sock_transport_ended(ScrNetSocket *s) { + s->rd_eof = true; + scr_net_fire0_this(&s->end_ls, s, SCR_DYNH_NET_SOCKET); +} + void scr_net_sock_transport_error(ScrNetSocket *s, const char *msg) { if (msg != NULL) { if (!s->pending_err) s->pending_err = scr_str_new(msg, strlen(msg)); @@ -5405,6 +5466,7 @@ static void scr_net_server_settle(ScrNetServer *srv) { scr_net_ls_drop(&srv->close_ls); scr_net_ls_drop(&srv->listening_cbs); scr_net_ls_drop(&srv->timeout_ls); + scr_net_ls_drop(&srv->client_error_ls); if (srv->proto_settle && srv->http_ctx) srv->proto_settle(srv->http_ctx); scr_net_server_unregister(srv); } @@ -5450,6 +5512,9 @@ static bool scr_net_sock_settle(ScrNetSocket *sock) { scr_net_fire_arg_this(&sock->close_ls, had_error, sock, SCR_DYNH_NET_SOCKET); scr_dyn_release(had_error); } + /* the transport settles first: a listener its last events add (a TLS + * server's 'tlsClientError') drops with the rest */ + if (sock->tops && sock->tops->settle) sock->tops->settle(sock->tctx); /* settle: listeners drop (cycle story) */ scr_net_ls_drop(&sock->data_ls); scr_net_ls_drop(&sock->end_ls); @@ -5462,7 +5527,6 @@ static bool scr_net_sock_settle(ScrNetSocket *sock) { scr_net_ls_drop(&sock->wcb_ls); scr_net_ls_drop(&sock->ready_ls); scr_net_ls_drop(&sock->lookup_ls); - if (sock->tops && sock->tops->settle) sock->tops->settle(sock->tctx); if (sock->pipe_dst) { scr_net_sock_release(sock->pipe_dst); sock->pipe_dst = NULL; @@ -5716,6 +5780,7 @@ static bool scr_net_sock_event(ScrNetSocket *s, unsigned events) { if (!scr_exc_pending() && s->fd >= 0) scr_net_sock_update_write(s); } else { s->t_want_write = false; + if (s->tops && s->tops->drain) s->tops->drain(s->tctx); scr_net_sock_flush(s); } } diff --git a/packages/runtime/src/scr_net.h b/packages/runtime/src/scr_net.h index 9e6dd1e0b..95490aaa5 100644 --- a/packages/runtime/src/scr_net.h +++ b/packages/runtime/src/scr_net.h @@ -186,6 +186,14 @@ void scr_net_server_close_direct(ScrNetServer *s, ScrClosure *cb /*moves, nullab * zero-arg wrapper); reassignment releases the old one. */ void scr_net_server_set_close_override(ScrNetServer *s, ScrClosure *ov /*moves*/); void scr_net_server_on_error(ScrNetServer *s, ScrClosure *cb /*moves*/, ScrChildErrFn fn, bool once); +/* tls/https servers' 'tlsClientError': registration (fn is one of the + * thunks below, by the listener's arity) and the TLS unit's fire. */ +void scr_net_server_on_client_error(ScrNetServer *s, ScrClosure *cb /*moves*/, void *fn, bool once); +void scr_net_server_fire_client_error(ScrNetServer *s, ScrError *err /*borrowed*/, + ScrNetSocket *sock /*borrowed*/); +void scr_net_client_error_thunk0(ScrClosure *cb, ScrError *err, ScrNetSocket *sock); +void scr_net_client_error_thunk1(ScrClosure *cb, ScrError *err, ScrNetSocket *sock); +void scr_net_client_error_thunk2(ScrClosure *cb, ScrError *err, ScrNetSocket *sock); void scr_net_server_on_close(ScrNetServer *s, ScrClosure *cb /*moves*/, bool once); /* server.on('listening', cb): the deferred 'listening' list listen(port, * cb) rides — fires once per successful bind; late registrations on an @@ -362,6 +370,9 @@ typedef struct ScrNetTransportOps { /* nullable: runs when the closed socket settles, after its own * listeners drop; the transport drops the listeners it holds */ void (*settle)(void *tctx); + /* nullable: the established socket's fd is writable; the transport + * writes what it holds back (TLS holds its final handshake flight) */ + void (*drain)(void *tctx); } ScrNetTransportOps; void scr_net_sock_set_transport(ScrNetSocket *s, const ScrNetTransportOps *ops, void *tctx); /* new tls.TLSSocket(socket) and tls.connect({ socket }): a fresh socket @@ -406,7 +417,14 @@ void scr_net_sock_replay(ScrNetSocket *s, const char *data, size_t len); /* Transport-level failure: msg (borrowed, Node's message shape) defers * 'error' + teardown to the sweep; NULL tears down without an 'error' * event, Node's default for an unhandled server-side handshake failure. */ +/* The peer ended the stream before the transport's handshake finished: + * 'end' fires now, ahead of the failure the transport reports next. */ +void scr_net_sock_transport_ended(ScrNetSocket *s); void scr_net_sock_transport_error(ScrNetSocket *s, const char *msg); +/* An error that leaves the socket open: 'error' fires from the sweep with + * `code` (static storage), and the socket ends when the peer closes, as + * Node's TLS socket reports a fatal alert after its handshake. */ +void scr_net_sock_transport_report(ScrNetSocket *s, const char *msg, const char *code); /* The same with the error's code given (static storage), for messages * whose text does not name it. */ void scr_net_sock_transport_error_code(ScrNetSocket *s, const char *msg, const char *code); diff --git a/packages/runtime/src/scr_pki.c b/packages/runtime/src/scr_pki.c index a1d5b98a6..72136afdb 100644 --- a/packages/runtime/src/scr_pki.c +++ b/packages/runtime/src/scr_pki.c @@ -2804,3 +2804,220 @@ bool scr_pki_verify(ScrPkiKey *key, const char *hash, bool pss, int salt, const SpSigKey k = {.key = key, .padding = pss ? 6 : 1, .salt = salt, .p1363 = true}; return sp_verify_hash(&k, md, digest, mbedtls_md_get_size(info), signature, signature_len); } + +/* ── X509Certificate members over keys ───────────────────────────────── */ + +/* The certificate's public key, +1; NULL with the error pending. */ +static SpKey *sp_x509_key(ScrBytes *der) { + ScrBytes *view = der; + SCR_BYTES_SNAPSHOT(view); + const unsigned char *spki; + size_t spki_len; + if (!sp_cert_spki(view->data, (size_t)scr_bytes_byte_len(view), &spki, &spki_len)) { + sp_unsupported_input(); + return NULL; + } + return sp_parse(spki, spki_len, false); +} + +/* x509.publicKey: the certificate's public key as a new KeyObject. */ +ScrDyn *scr_crypto_x509_public_key(ScrBytes *der) { + SpKey *k = sp_x509_key(der); + return k ? sp_key_box(k) : NULL; +} + +/* The pkey argument of verify (a public key) and checkPrivateKey (a + * private key), borrowed; NULL with Node's TypeError pending. */ +static SpKey *sp_x509_pkey(const ScrDyn *value, bool private_key) { + SpKey *k = sp_key_of(value); + size_t len; + if (!k && !scr_key_object_bytes(value, &len)) { + scr_dyn_arg_type_fail("pkey", "an instance of KeyObject", value); + return NULL; + } + if (!k || k->private_key != private_key) { + const char *cls = !k ? "SecretKeyObject" : k->private_key ? "PrivateKeyObject" : "PublicKeyObject"; + scr_pki_throw_fmt(SCR_ERR_TYPE, "ERR_INVALID_ARG_VALUE", "The argument 'pkey' is invalid. Received %s [KeyObject] {}", + cls); + return NULL; + } + return k; +} + +/* The digest of a signature algorithm OID's last arc (RSA and ECDSA). */ +static mbedtls_md_type_t sp_x509_rsa_md(unsigned char arc) { + switch (arc) { + case 5: return MBEDTLS_MD_SHA1; + case 11: return MBEDTLS_MD_SHA256; + case 12: return MBEDTLS_MD_SHA384; + case 13: return MBEDTLS_MD_SHA512; + case 14: return MBEDTLS_MD_SHA224; + default: return MBEDTLS_MD_NONE; + } +} + +/* A hash AlgorithmIdentifier inside RSASSA-PSS-params. */ +static mbedtls_md_type_t sp_x509_hash_alg(unsigned char *p, const unsigned char *end) { + size_t n; + if (mbedtls_asn1_get_tag(&p, end, &n, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) + return MBEDTLS_MD_NONE; + mbedtls_asn1_buf oid = {0}; + oid.tag = MBEDTLS_ASN1_OID; + if (mbedtls_asn1_get_tag(&p, end, &oid.len, MBEDTLS_ASN1_OID) != 0) return MBEDTLS_MD_NONE; + oid.p = p; + mbedtls_md_type_t md; + return mbedtls_oid_get_md_alg(&oid, &md) == 0 ? md : MBEDTLS_MD_NONE; +} + +/* x509.verify(publicKey): whether publicKey verifies the certificate's + * signature. An algorithm the key cannot verify answers false. */ +bool scr_crypto_x509_verify(ScrBytes *der, ScrDyn *key) { + SpKey *k = sp_x509_pkey(key, false); + if (!k) return false; + ScrBytes *view = der; + SCR_BYTES_SNAPSHOT(view); + unsigned char *p = view->data; + const unsigned char *end = p + (size_t)scr_bytes_byte_len(view); + size_t n; + if (mbedtls_asn1_get_tag(&p, end, &n, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) + return false; + end = p + n; + const unsigned char *tbs = p; + if (mbedtls_asn1_get_tag(&p, end, &n, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) + return false; + p += n; + size_t tbs_len = (size_t)(p - tbs); + const unsigned char *outer_alg = p; + if (mbedtls_asn1_get_tag(&p, end, &n, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) + return false; + const unsigned char *alg_end = p + n; + /* As in OpenSSL's X509_verify, the TBSCertificate's signature field must + * be the same AlgorithmIdentifier as the outer one. */ + { + unsigned char *q = (unsigned char *)tbs; + const unsigned char *tbs_end = tbs + tbs_len; + size_t len; + if (mbedtls_asn1_get_tag(&q, tbs_end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) + return false; + if (q < tbs_end && *q == (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0)) { + if (mbedtls_asn1_get_tag(&q, tbs_end, &len, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0) != 0) + return false; + q += len; + } + if (mbedtls_asn1_get_tag(&q, tbs_end, &len, MBEDTLS_ASN1_INTEGER) != 0) return false; + q += len; + const unsigned char *inner_alg = q; + if (mbedtls_asn1_get_tag(&q, tbs_end, &len, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) + return false; + size_t inner_len = (size_t)(q + len - inner_alg); + if (inner_len != (size_t)(alg_end - outer_alg) || memcmp(inner_alg, outer_alg, inner_len) != 0) return false; + } + size_t oid_len; + if (mbedtls_asn1_get_tag(&p, alg_end, &oid_len, MBEDTLS_ASN1_OID) != 0) return false; + const unsigned char *oid = p; + unsigned char *params = p + oid_len; + p = (unsigned char *)alg_end; + size_t sig_len; + if (mbedtls_asn1_get_tag(&p, end, &sig_len, MBEDTLS_ASN1_BIT_STRING) != 0 || sig_len < 1 || *p != 0) + return false; + const unsigned char *sig = p + 1; + sig_len -= 1; + static const unsigned char rsa_prefix[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01}; + static const unsigned char ecdsa_prefix[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04}; + static const unsigned char ed25519_oid[] = {0x2B, 0x65, 0x70}; + if (oid_len == sizeof ed25519_oid && memcmp(oid, ed25519_oid, oid_len) == 0) { + if (!sp_is_ed(k)) return false; + const ScrPkiEd25519 *ed = sp_ed(); + return ed != NULL && sp_ed_verify(ed, k->ed_pub, tbs, tbs_len, sig, sig_len); + } + if (sp_is_ed(k)) return false; + unsigned char hash[MBEDTLS_MD_MAX_SIZE]; + if (oid_len == sizeof rsa_prefix + 1 && memcmp(oid, rsa_prefix, sizeof rsa_prefix) == 0) { + if (!sp_is_rsa(k)) return false; + mbedtls_rsa_context *rsa = mbedtls_pk_rsa(k->pk); + if (oid[sizeof rsa_prefix] == 10) { /* RSASSA-PSS with its parameters */ + mbedtls_md_type_t md = MBEDTLS_MD_SHA1, mgf = MBEDTLS_MD_SHA1; + int salt = 20; + unsigned char *q = params; + size_t plen; + if (mbedtls_asn1_get_tag(&q, alg_end, &plen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) == 0) { + const unsigned char *pend = q + plen; + while (q < pend) { + unsigned char tag = *q; + size_t len; + if (mbedtls_asn1_get_tag(&q, pend, &len, tag) != 0) return false; + unsigned char *field = q; + q += len; + if (tag == (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0)) { + md = sp_x509_hash_alg(field, q); + } else if (tag == (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1)) { + /* MGF1 with its hash: SEQUENCE { id-mgf1, AlgorithmIdentifier } */ + size_t mlen, ilen; + unsigned char *m = field; + if (mbedtls_asn1_get_tag(&m, q, &mlen, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0 || + mbedtls_asn1_get_tag(&m, q, &ilen, MBEDTLS_ASN1_OID) != 0) + return false; + mgf = sp_x509_hash_alg(m + ilen, q); + } else if (tag == (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 2)) { + if (mbedtls_asn1_get_int(&field, q, &salt) != 0) return false; + } + } + } + if (md == MBEDTLS_MD_NONE || mgf == MBEDTLS_MD_NONE || sig_len != mbedtls_rsa_get_len(rsa)) + return false; + const mbedtls_md_info_t *info = mbedtls_md_info_from_type(md); + mbedtls_md(info, tbs, tbs_len, hash); + return mbedtls_rsa_rsassa_pss_verify_ext(rsa, md, mbedtls_md_get_size(info), hash, mgf, salt, + sig) == 0; + } + mbedtls_md_type_t md = sp_x509_rsa_md(oid[sizeof rsa_prefix]); + if (md == MBEDTLS_MD_NONE) return false; + const mbedtls_md_info_t *info = mbedtls_md_info_from_type(md); + mbedtls_md(info, tbs, tbs_len, hash); + /* PKCS#1 v1.5, whatever padding the key's last signature used */ + if (mbedtls_rsa_set_padding(rsa, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE) != 0) return false; + return mbedtls_pk_verify(&k->pk, md, hash, mbedtls_md_get_size(info), sig, sig_len) == 0; + } + if (oid_len >= sizeof ecdsa_prefix + 1 && memcmp(oid, ecdsa_prefix, sizeof ecdsa_prefix) == 0) { + if (!sp_is_ec(k)) return false; + mbedtls_md_type_t md = MBEDTLS_MD_NONE; + if (oid_len == 7 && oid[6] == 0x01) md = MBEDTLS_MD_SHA1; + else if (oid_len == 8 && oid[6] == 0x03) { + static const mbedtls_md_type_t sha2[] = {MBEDTLS_MD_NONE, MBEDTLS_MD_SHA224, MBEDTLS_MD_SHA256, + MBEDTLS_MD_SHA384, MBEDTLS_MD_SHA512}; + if (oid[7] >= 1 && oid[7] <= 4) md = sha2[oid[7]]; + } + if (md == MBEDTLS_MD_NONE) return false; + const mbedtls_md_info_t *info = mbedtls_md_info_from_type(md); + mbedtls_md(info, tbs, tbs_len, hash); + return mbedtls_pk_verify(&k->pk, md, hash, mbedtls_md_get_size(info), sig, sig_len) == 0; + } + return false; +} + +/* x509.checkPrivateKey(privateKey): whether privateKey is the private half + * of the certificate's public key. */ +bool scr_crypto_x509_check_private_key(ScrBytes *der, ScrDyn *key) { + SpKey *k = sp_x509_pkey(key, true); + if (!k) return false; + SpKey *cert = sp_x509_key(der); + if (!cert) return false; + bool same = false; + if (sp_is_ed(k) || sp_is_ed(cert)) { + same = sp_is_ed(k) && sp_is_ed(cert) && memcmp(k->ed_pub, cert->ed_pub, 32) == 0; + } else if (mbedtls_pk_get_type(&k->pk) == mbedtls_pk_get_type(&cert->pk)) { + SpKey *pub = sp_public_of(k); + if (pub) { + unsigned char *a = malloc(SP_DER_MAX), *b = malloc(SP_DER_MAX); + if (!a || !b) scr_trap("scriptc: out of memory\n"); + int na = sp_write_spki_der(pub, a, SP_DER_MAX); + int nb = sp_write_spki_der(cert, b, SP_DER_MAX); + same = na > 0 && na == nb && memcmp(a + SP_DER_MAX - na, b + SP_DER_MAX - nb, (size_t)na) == 0; + free(a); + free(b); + sp_key_release(pub); + } + } + sp_key_release(cert); + return same; +} diff --git a/packages/runtime/src/scr_tls.c b/packages/runtime/src/scr_tls.c index e7436ab69..2f448a417 100644 --- a/packages/runtime/src/scr_tls.c +++ b/packages/runtime/src/scr_tls.c @@ -64,10 +64,15 @@ * expired") through the socket's pending-error sweep — then 'close', * Node's order, exactly like ECONNREFUSED. * + * Client certificates: servers take requestCert, rejectUnauthorized and + * ca and report socket.authorized/authorizationError as Node does; + * clients send a cert and key when asked. A `ca` also completes the + * chain its owner sends, as OpenSSL's automatic chain does. + * * Bounds (SEMANTICS.md divergence 55): no session resumption or - * tickets, no renegotiation/post-handshake auth, no client - * certificates, and non-verify client handshake failures carry a generic - * message where Node prints an OpenSSL one. + * tickets, no renegotiation/post-handshake auth, and non-verify client + * handshake failures carry a generic message where Node prints an + * OpenSSL one. * * Certificate names: a client always checks the leaf against one name, * the servername when it is non-empty and the host otherwise. SNI carries @@ -82,6 +87,7 @@ #include #include #include +#include #include #include #ifdef _WIN32 @@ -202,6 +208,42 @@ static void scr_tls_bad_material(const char *what, int err) { _Exit(1); } +/* OpenSSL's automatic chain (ssl_add_cert_chain): a certificate option + * that holds only the leaf is sent with the issuers `store` holds, up to + * a self-issued one, as far as they are found. A chain given in the + * option is sent as it is. */ +static void scr_tls_auto_chain(mbedtls_x509_crt *own, const mbedtls_x509_crt *store) { + if (own->raw.len == 0 || own->next != NULL) return; + const mbedtls_x509_crt *at = own; + for (int depth = 0; depth < 8; depth++) { + if (at->issuer_raw.len == at->subject_raw.len && + memcmp(at->issuer_raw.p, at->subject_raw.p, at->subject_raw.len) == 0) + return; + const mbedtls_x509_crt *issuer = NULL; + for (const mbedtls_x509_crt *c = store; c != NULL && c->raw.len > 0 && issuer == NULL; c = c->next) { + if (c->subject_raw.len == at->issuer_raw.len && + memcmp(c->subject_raw.p, at->issuer_raw.p, c->subject_raw.len) == 0) + issuer = c; + } + if (issuer == NULL) return; + for (const mbedtls_x509_crt *c = own; c != NULL; c = c->next) { + if (c->raw.len == issuer->raw.len && memcmp(c->raw.p, issuer->raw.p, c->raw.len) == 0) return; + } + if (mbedtls_x509_crt_parse_der(own, issuer->raw.p, issuer->raw.len) != 0) return; + while (at->next != NULL) at = at->next; + } +} + +/* A copy of a certificate chain, completed from `store` as the automatic + * chain does, for a use that must leave the original as it is. */ +static void scr_tls_chained_copy(mbedtls_x509_crt *out, const mbedtls_x509_crt *chain, + const mbedtls_x509_crt *store) { + for (const mbedtls_x509_crt *c = chain; c != NULL && c->raw.len > 0; c = c->next) { + if (mbedtls_x509_crt_parse_der(out, c->raw.p, c->raw.len) != 0) scr_tls_bad_material("certificate", 0); + } + scr_tls_auto_chain(out, store); +} + /* ── SecureContext (tls.createSecureContext) ─────────────────────────── */ /* An opaque refcounted parsed cert/key pair — what an SNI callback @@ -210,6 +252,9 @@ struct ScrSecureCtx { size_t rc; mbedtls_x509_crt cert; mbedtls_pk_context pk; + /* the ca option: a socket created from this context (a TLSSocket's + * secureContext) sends the chain it completes */ + mbedtls_x509_crt ca; }; #ifdef SCR_RC_AUDIT @@ -224,6 +269,7 @@ ScrSecureCtx *scr_tls_create_secure_context(const char *cert, size_t cert_len, if (!c) scr_tls_oom(); c->rc = 1; mbedtls_x509_crt_init(&c->cert); + mbedtls_x509_crt_init(&c->ca); mbedtls_pk_init(&c->pk); int r = scr_tls_parse_crt(&c->cert, cert, cert_len); if (r != 0) scr_tls_bad_material("certificate", r); @@ -243,6 +289,7 @@ ScrSecureCtx *scr_secure_ctx_retain(ScrSecureCtx *c) { void scr_secure_ctx_release(ScrSecureCtx *c) { if (!c || --c->rc != 0) return; mbedtls_x509_crt_free(&c->cert); + mbedtls_x509_crt_free(&c->ca); mbedtls_pk_free(&c->pk); free(c); #ifdef SCR_RC_AUDIT @@ -372,6 +419,29 @@ typedef struct ScrTlsSrv { * certificate and key this config serves (+1; NULL when cert/key are the * config's own) */ ScrSecureCtx *ctx; + /* client certificates: requestCert asks for one and verifies it against + * `ca` (the default store without one); with rejectUnauthorized a client + * that sends none fails the handshake and one that fails verification + * is dropped before 'secureConnection', as in Node */ + bool request_cert; + bool reject_unauthorized; + bool has_ca; + mbedtls_x509_crt ca; + /* new tls.TLSSocket(socket, { isServer }): Node verifies client + * certificates only in tls.Server, so a standalone socket reports no + * verdict (authorized false, authorizationError null) and drops no + * client for one; rejectUnauthorized there only requires a certificate */ + bool standalone; + /* server.addContext(servername, context): lowercased name patterns + * ('*' matches within one label) with their contexts (+1), newest + * last; server.setSecureContext's replacement default (+1, NULL for the + * server's own). Both serve through scr_tls_f_cert. */ + struct ScrTlsNamedCtx { + char *pattern; + ScrSecureCtx *ctx; + } *contexts; + size_t ncontexts; + ScrSecureCtx *default_ctx; } ScrTlsSrv; /* The ALPN answers (static storage — mbedTLS keeps the pointers). Plain @@ -389,6 +459,7 @@ static ScrTlsSrv *scr_tls_srv_new(const char *cert, size_t cert_len, const char if (!s) scr_tls_oom(); s->rc = 1; mbedtls_x509_crt_init(&s->cert); + mbedtls_x509_crt_init(&s->ca); mbedtls_pk_init(&s->pk); mbedtls_ssl_config_init(&s->conf); int r = scr_tls_parse_crt(&s->cert, cert, cert_len); @@ -401,7 +472,8 @@ static ScrTlsSrv *scr_tls_srv_new(const char *cert, size_t cert_len, const char scr_tls_oom(); } mbedtls_ssl_conf_rng(&s->conf, mbedtls_ctr_drbg_random, &scr_tls_drbg); - mbedtls_ssl_conf_authmode(&s->conf, MBEDTLS_SSL_VERIFY_NONE); /* no client certs, Node's default */ + /* no client certificate unless requestCert asks (scr_tls_srv_client_auth) */ + mbedtls_ssl_conf_authmode(&s->conf, MBEDTLS_SSL_VERIFY_NONE); if (mbedtls_ssl_conf_own_cert(&s->conf, &s->cert, &s->pk) != 0) { scr_tls_bad_material("certificate/key pair", 0); } @@ -416,6 +488,7 @@ static ScrTlsSrv *scr_tls_srv_from_ctx(ScrSecureCtx *ctx /*borrowed*/) { if (!s) scr_tls_oom(); s->rc = 1; mbedtls_x509_crt_init(&s->cert); + mbedtls_x509_crt_init(&s->ca); mbedtls_pk_init(&s->pk); mbedtls_ssl_config_init(&s->conf); if (mbedtls_ssl_config_defaults(&s->conf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, @@ -425,7 +498,13 @@ static ScrTlsSrv *scr_tls_srv_from_ctx(ScrSecureCtx *ctx /*borrowed*/) { mbedtls_ssl_conf_rng(&s->conf, mbedtls_ctr_drbg_random, &scr_tls_drbg); mbedtls_ssl_conf_authmode(&s->conf, MBEDTLS_SSL_VERIFY_NONE); s->ctx = scr_secure_ctx_retain(ctx); - if (mbedtls_ssl_conf_own_cert(&s->conf, &ctx->cert, &ctx->pk) != 0) { + /* the context's ca completes the chain a socket created from it sends */ + const mbedtls_x509_crt *own = &ctx->cert; + if (ctx->ca.raw.len > 0) { + scr_tls_chained_copy(&s->cert, &ctx->cert, &ctx->ca); + own = &s->cert; + } + if (mbedtls_ssl_conf_own_cert(&s->conf, (mbedtls_x509_crt *)own, &ctx->pk) != 0) { scr_tls_bad_material("certificate/key pair", 0); } return s; @@ -443,14 +522,53 @@ static void scr_tls_srv_release(ScrTlsSrv *s) { scr_closure_release(s->sni_cb); mbedtls_ssl_config_free(&s->conf); mbedtls_x509_crt_free(&s->cert); + mbedtls_x509_crt_free(&s->ca); mbedtls_pk_free(&s->pk); scr_tls_alpn_free(s->alpn); scr_secure_ctx_release(s->ctx); + for (size_t i = 0; i < s->ncontexts; i++) { + free(s->contexts[i].pattern); + scr_secure_ctx_release(s->contexts[i].ctx); + } + free(s->contexts); + scr_secure_ctx_release(s->default_ctx); free(s); } static void scr_tls_srv_release_v(void *p) { scr_tls_srv_release((ScrTlsSrv *)p); } +/* The client-certificate options of a server: requestCert, rejectUnauthorized + * (Node's true default) and ca (+1, NULL for none). */ +typedef struct { + bool request; + bool reject; + ScrBytes *ca; +} ScrTlsClientAuth; + +static mbedtls_x509_crt *scr_tls_system_ca(void); + +/* Applies a server's client-certificate options. A `ca` also completes the + * server's own chain, as OpenSSL's automatic chain sends it. */ +static void scr_tls_srv_client_auth(ScrTlsSrv *s, const ScrTlsClientAuth *auth) { + if (auth == NULL) return; + /* An empty ca Buffer is an empty trust store, not the default one. */ + if (auth->ca != NULL) { + if (auth->ca->len > 0) { + int r = scr_tls_parse_crt(&s->ca, (const char *)auth->ca->data, auth->ca->len); + if (r != 0) scr_tls_bad_material("ca certificate", r); + if (s->ctx == NULL) scr_tls_auto_chain(&s->cert, &s->ca); + } + s->has_ca = true; + } + if (!auth->request) return; + s->request_cert = true; + s->reject_unauthorized = auth->reject; + /* OPTIONAL: the handshake records the verdict and goes on, as Node's + * verify callback does; scr_tls_handshake applies rejectUnauthorized */ + mbedtls_ssl_conf_authmode(&s->conf, MBEDTLS_SSL_VERIFY_OPTIONAL); + mbedtls_ssl_conf_ca_chain(&s->conf, s->has_ca ? &s->ca : scr_tls_system_ca(), NULL); +} + /* ── the client config (one per https.request, owned by its tctx) ────── */ typedef struct ScrTlsCli { @@ -463,6 +581,7 @@ typedef struct ScrTlsCli { * VERIFY_NONE socket (the https client's rejectUnauthorized:false) * never verified, so authorized answers false like Node's. */ bool verify_recorded; + bool reject; /* rejectUnauthorized: a verification failure fails the handshake */ /* The ALPNProtocols option's names, NULL-terminated, in the caller's * order (mbedtls_ssl_conf_alpn_protocols keeps the pointer); NULL when * none are offered. */ @@ -470,6 +589,11 @@ typedef struct ScrTlsCli { /* No TLS version is in the configured range: the handshake fails as * soon as it starts (Node's ERR_SSL_NO_PROTOCOLS_AVAILABLE). */ bool no_protocols; + /* the client certificate (cert and key options), sent when the server + * asks for one */ + bool has_own; + mbedtls_x509_crt own; + mbedtls_pk_context own_pk; } ScrTlsCli; /* The default trust anchors when no `ca` option is given: the host trust @@ -562,6 +686,8 @@ static ScrTlsCli *scr_tls_cli_new2(ScrStr *host, bool reject_unauthorized, const if (!c) scr_tls_oom(); mbedtls_ssl_config_init(&c->conf); mbedtls_x509_crt_init(&c->ca); + mbedtls_x509_crt_init(&c->own); + mbedtls_pk_init(&c->own_pk); if (mbedtls_ssl_config_defaults(&c->conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT) != 0) { @@ -569,6 +695,7 @@ static ScrTlsCli *scr_tls_cli_new2(ScrStr *host, bool reject_unauthorized, const } mbedtls_ssl_conf_rng(&c->conf, mbedtls_ctr_drbg_random, &scr_tls_drbg); c->verify_recorded = reject_unauthorized || verify_optional; + c->reject = reject_unauthorized; if (ca_len > 0) { int r = scr_tls_parse_crt(&c->ca, ca, ca_len); if (r != 0) scr_tls_bad_material("ca certificate", r); @@ -620,11 +747,27 @@ static void scr_tls_cli_free(ScrTlsCli *c) { mbedtls_ssl_config_free(&c->conf); scr_tls_alpn_free(c->alpn); mbedtls_x509_crt_free(&c->ca); + mbedtls_x509_crt_free(&c->own); + mbedtls_pk_free(&c->own_pk); free(c->hostname); free(c->verify_name); free(c); } +/* The cert and key options of a client: the certificate (with the issuers + * its `ca` holds, OpenSSL's automatic chain) is sent when the server asks + * for one. */ +static void scr_tls_cli_set_own(ScrTlsCli *c, const ScrBytes *cert, const ScrBytes *key) { + int r = scr_tls_parse_crt(&c->own, (const char *)cert->data, cert->len); + if (r != 0) scr_tls_bad_material("certificate", r); + r = scr_tls_parse_key(&c->own_pk, (const char *)key->data, key->len); + if (r != 0) scr_tls_bad_material("private key", r); + if (c->ca.raw.len > 0) scr_tls_auto_chain(&c->own, &c->ca); + if (mbedtls_ssl_conf_own_cert(&c->conf, &c->own, &c->own_pk) != 0) + scr_tls_bad_material("certificate/key pair", 0); + c->has_own = true; +} + /* ── the per-socket transport ────────────────────────────────────────── */ /* The SNI pre-parse states: NONE (no callback on the server — the @@ -665,8 +808,32 @@ typedef struct ScrTlsSock { /* the 'secure' event's listeners */ ScrNetLs secure_ls; bool settled; /* the socket closed: listeners added later never fire */ + /* a TLS 1.3 client sent no certificate to a server that requires one; + * the alert goes out once the handshake is over */ + bool cert_missing; + /* a fatal alert was reported without closing: reads end the stream */ + bool alert_reported; + /* a server socket: the accepting server (+1), which 'tlsClientError' + * fires on, and a hang-up waiting for the socket to close (Node emits + * ECONNRESET 'socket hang up' from the socket's 'close') */ + ScrNetServer *server; + bool hang_up_pending; + /* a client whose verification failed: like Node's, it closes without + * sending the alert, so later writes are dropped */ + bool quiet_failure; + /* the served context's chain completed from the server's ca */ + mbedtls_x509_crt served_chain; + /* what the handshake's last step and the established callbacks write: + * Node flushes it after the nextTick queue and before the immediates + * queued in those callbacks, so a destroy() there drops it. `holding` + * collects; held[held_off..held_len) waits for the fd. */ + bool holding; + unsigned char *held; + size_t held_len, held_off, held_cap; } ScrTlsSock; +static bool scr_tls_alert_error(ScrTlsSock *t, unsigned char alert); + /* checkServerIdentity for an IP literal: the address must be one of the * certificate's IP SANs (no DNS SAN or CN applies). */ static bool scr_tls_leaf_has_ip(const mbedtls_x509_crt *crt, const char *ip) { @@ -711,6 +878,9 @@ static int scr_tls_vrfy_cb(void *ctx, mbedtls_x509_crt *crt, int depth, uint32_t *flags |= name_flags & MBEDTLS_X509_BADCERT_CN_MISMATCH; } } + /* a rejecting client fails the handshake on any flag; Node's client + * then closes without sending an alert (its Finished is discarded) */ + if (*flags != 0 && t->cli != NULL && t->cli->reject) t->quiet_failure = true; bool self = crt->issuer_raw.len == crt->subject_raw.len && memcmp(crt->issuer_raw.p, crt->subject_raw.p, crt->subject_raw.len) == 0; if (*flags & MBEDTLS_X509_BADCERT_EXPIRED) t->vrfy_expired = true; @@ -725,8 +895,52 @@ static int scr_tls_vrfy_cb(void *ctx, mbedtls_x509_crt *crt, int depth, uint32_t /* The BIOs: nonblocking fd I/O in mbedTLS's own convention. A send that * would block arms the socket's write filter so the handshake resumes on * writability. */ +static void scr_tls_hold(ScrTlsSock *t, const unsigned char *buf, size_t len) { + if (t->held_len + len > t->held_cap) { + size_t cap = t->held_cap ? t->held_cap : 4096; + while (cap < t->held_len + len) cap *= 2; + unsigned char *grown = realloc(t->held, cap); + if (grown == NULL) scr_tls_oom(); + t->held = grown; + t->held_cap = cap; + } + memcpy(t->held + t->held_len, buf, len); + t->held_len += len; +} + +/* Writes what is held: 1 once it is all out, 0 when the fd would block + * (the write filter is armed for the rest), -1 when the connection is + * gone (the bytes are dropped). */ +static int scr_tls_flush_held(ScrTlsSock *t) { + int fd = scr_net_sock_fd(t->sock); + while (t->held_off < t->held_len) { + if (fd < 0) break; + ssize_t n = write(fd, t->held + t->held_off, t->held_len - t->held_off); + if (n > 0) { + t->held_off += (size_t)n; + continue; + } + if (n < 0 && errno == EINTR) continue; + if (n < 0 && (errno == EAGAIN || errno == EWOULDBLOCK)) { + scr_net_sock_transport_want_write(t->sock); + return 0; + } + break; + } + bool out = t->held_off == t->held_len; + t->held_off = t->held_len = 0; + return out ? 1 : -1; +} + static int scr_tls_bio_send(void *ctx, const unsigned char *buf, size_t len) { ScrTlsSock *t = (ScrTlsSock *)ctx; + if (t->quiet_failure) return (int)len; + if (t->holding) { + scr_tls_hold(t, buf, len); + return (int)len; + } + /* held bytes go first; mbedTLS retries this record once they are out */ + if (t->held_len > t->held_off && scr_tls_flush_held(t) == 0) return MBEDTLS_ERR_SSL_WANT_WRITE; int fd = scr_net_sock_fd(t->sock); if (fd < 0) return MBEDTLS_ERR_NET_CONN_RESET; ssize_t n = write(fd, buf, len); @@ -742,7 +956,7 @@ static int scr_tls_bio_send(void *ctx, const unsigned char *buf, size_t len) { /* Keeps the first bytes a wrapped socket's peer sends: a handshake that * fails on them reports what they looked like, as OpenSSL does. */ static void scr_tls_note_head(ScrTlsSock *t, const unsigned char *buf, size_t n) { - if (!t->wrapped || t->head_len == sizeof t->head) return; + if (t->srv == NULL || t->head_len == sizeof t->head) return; size_t take = sizeof t->head - t->head_len; if (take > n) take = n; memcpy(t->head + t->head_len, buf, take); @@ -770,6 +984,21 @@ static int scr_tls_bio_recv(void *ctx, unsigned char *buf, size_t len) { return MBEDTLS_ERR_NET_RECV_FAILED; } +/* Node reads what the kernel holds (one 64 KiB libuv read) before + * OpenSSL sees the records, so a failed handshake closes with nothing + * unread and the peer gets a FIN. Closing with the rest of, say, an HTTP + * request still queued would make the kernel send a reset instead. */ +static void scr_tls_drain_unread(ScrTlsSock *t) { + int fd = scr_net_sock_fd(t->sock); + if (fd < 0) return; + unsigned char sink[4096]; + for (size_t total = 0; total < 65536; ) { + ssize_t n = read(fd, sink, sizeof sink); + if (n <= 0) break; + total += (size_t)n; + } +} + /* ── the transport ops ───────────────────────────────────────────────── */ static void scr_tls_fire_session(ScrTlsSock *t); @@ -793,6 +1022,14 @@ static ssize_t scr_tls_xread(void *tctx, char *buf, size_t n) { errno = EAGAIN; return -1; } + if (t->alert_reported) return 0; /* the server closing after its alert */ + /* a TLS 1.3 server rejects a missing client certificate after the + * client finished its handshake */ + if (r == MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE && t->cli != NULL && + t->ssl.MBEDTLS_PRIVATE(in_msg) != NULL && scr_tls_alert_error(t, t->ssl.MBEDTLS_PRIVATE(in_msg)[1])) { + errno = EAGAIN; + return -1; + } errno = ECONNRESET; /* protocol-level death reads as a reset */ return -1; } @@ -1081,6 +1318,99 @@ void scr_tls_sni_answer(ScrClosure *self, bool has_err, ScrSecureCtx *ctx /*move * ECONNRESET, and bytes that are not a TLS record name what they were * (OpenSSL's reasons without the per-process prefix and source location, * SEMANTICS.md divergence 55). */ +/* The OpenSSL reason (without its per-process prefix and source location, + * SEMANTICS.md divergence 55) and Node's code for a server handshake that + * failed with mbedTLS error `r`; false when the peer closed or reset the + * connection instead. A failure mbedTLS reports without a reason OpenSSL + * would give answers a coded SC2020 refusal. */ +static bool scr_tls_server_reason(ScrTlsSock *t, int r, const char **msg, const char **code) { + if (r == MBEDTLS_ERR_SSL_CONN_EOF || r == MBEDTLS_ERR_NET_CONN_RESET) return false; + if (r == MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE) { + *msg = "error:0A0000C7:SSL routines:tls_process_client_certificate:peer did not return a certificate"; + *code = "ERR_SSL_PEER_DID_NOT_RETURN_A_CERTIFICATE"; + return true; + } + const unsigned char *h = t->head; + bool record = t->head_len >= 3 && h[0] >= 20 && h[0] <= 23 && h[1] == 3; + if (t->head_len >= 5 && !record) { + static const char *const http[] = { "GET ", "POST ", "HEAD ", "PATCH", "OPTIO", + "DELET", "TRACE", "PUT ", NULL }; + *msg = "error:0A00010B:SSL routines:tls_validate_record_header:wrong version number"; + *code = "ERR_SSL_WRONG_VERSION_NUMBER"; + for (size_t i = 0; http[i] != NULL; i++) { + if (memcmp(h, http[i], strlen(http[i])) == 0) { + *msg = "error:0A00009C:SSL routines:tls_validate_record_header:http request"; + *code = "ERR_SSL_HTTP_REQUEST"; + } + } + if (memcmp(h, "CONNE", 5) == 0) { + *msg = "error:0A00009B:SSL routines:tls_validate_record_header:https proxy request"; + *code = "ERR_SSL_HTTPS_PROXY_REQUEST"; + } + return true; + } + if (r == MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE && t->ssl.MBEDTLS_PRIVATE(in_msg) != NULL) { + /* an alert the client sent: OpenSSL's reason is 1000 + its number */ + static const struct { unsigned char alert; const char *msg, *code; } alerts[] = { + { 40, "error:0A000410:SSL routines:ssl3_read_bytes:ssl/tls alert handshake failure", + "ERR_SSL_SSL/TLS_ALERT_HANDSHAKE_FAILURE" }, + { 42, "error:0A000412:SSL routines:ssl3_read_bytes:sslv3 alert bad certificate", + "ERR_SSL_SSLV3_ALERT_BAD_CERTIFICATE" }, + { 45, "error:0A000415:SSL routines:ssl3_read_bytes:sslv3 alert certificate expired", + "ERR_SSL_SSLV3_ALERT_CERTIFICATE_EXPIRED" }, + { 46, "error:0A000416:SSL routines:ssl3_read_bytes:sslv3 alert certificate unknown", + "ERR_SSL_SSLV3_ALERT_CERTIFICATE_UNKNOWN" }, + { 48, "error:0A000418:SSL routines:ssl3_read_bytes:tlsv1 alert unknown ca", + "ERR_SSL_TLSV1_ALERT_UNKNOWN_CA" }, + { 49, "error:0A000419:SSL routines:ssl3_read_bytes:tlsv1 alert access denied", + "ERR_SSL_TLSV1_ALERT_ACCESS_DENIED" }, + { 51, "error:0A00041B:SSL routines:ssl3_read_bytes:tlsv1 alert decrypt error", + "ERR_SSL_TLSV1_ALERT_DECRYPT_ERROR" }, + { 70, "error:0A00042E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version", + "ERR_SSL_TLSV1_ALERT_PROTOCOL_VERSION" }, + { 80, "error:0A000438:SSL routines:ssl3_read_bytes:tlsv1 alert internal error", + "ERR_SSL_TLSV1_ALERT_INTERNAL_ERROR" }, + }; + unsigned char alert = t->ssl.MBEDTLS_PRIVATE(in_msg)[1]; + for (size_t i = 0; i < sizeof alerts / sizeof alerts[0]; i++) { + if (alerts[i].alert == alert) { + *msg = alerts[i].msg; + *code = alerts[i].code; + return true; + } + } + } + if (r == MBEDTLS_ERR_SSL_BAD_PROTOCOL_VERSION) { + *msg = "error:0A000102:SSL routines:tls_early_post_process_client_hello:unsupported protocol"; + *code = "ERR_SSL_UNSUPPORTED_PROTOCOL"; + return true; + } + if (r == MBEDTLS_ERR_SSL_NO_APPLICATION_PROTOCOL) { + *msg = "error:0A0000EB:SSL routines:tls_handle_alpn:no application protocol"; + *code = "ERR_SSL_NO_APPLICATION_PROTOCOL"; + return true; + } + static SCR_TL char refusal[128]; + snprintf(refusal, sizeof refusal, + "a TLS handshake failure (mbedTLS error -0x%04X) without the reason OpenSSL gives is not supported yet", + (unsigned)-r); + *msg = refusal; + *code = "SC2020"; + return true; +} + +/* 'tlsClientError' on the accepting server: Node's Error with `code`, and + * the socket. Without a listener the socket is only destroyed. */ +static void scr_tls_client_error(ScrTlsSock *t, const char *msg, const char *code) { + if (t->server == NULL) return; + ScrStr *m = scr_str_new(msg, strlen(msg)); + ScrError *e = scr_error_new(SCR_ERR_ERROR, m); + scr_str_release(m); + scr_error_set_code(e, code); + scr_net_server_fire_client_error(t->server, e, t->sock); + scr_error_release(e); +} + static void scr_tls_wrapped_failure(ScrTlsSock *t, int r) { if (r == MBEDTLS_ERR_SSL_CONN_EOF) { scr_net_sock_transport_eof(t->sock); @@ -1090,27 +1420,86 @@ static void scr_tls_wrapped_failure(ScrTlsSock *t, int r) { scr_net_sock_transport_error(t->sock, "read ECONNRESET"); return; } - const unsigned char *h = t->head; - bool record = t->head_len >= 3 && h[0] >= 20 && h[0] <= 23 && h[1] == 3; - if (t->head_len >= 5 && !record) { - static const char *const http[] = { "GET ", "POST ", "HEAD ", "PATCH", "OPTIO", - "DELET", "TRACE", "PUT ", NULL }; - const char *reason = "error:0A00010B:SSL routines:tls_validate_record_header:wrong version number"; - const char *code = "ERR_SSL_WRONG_VERSION_NUMBER"; - for (size_t i = 0; http[i] != NULL; i++) { - if (memcmp(h, http[i], strlen(http[i])) == 0) { - reason = "error:0A00009C:SSL routines:tls_validate_record_header:http request"; - code = "ERR_SSL_HTTP_REQUEST"; - } - } - if (memcmp(h, "CONNE", 5) == 0) { - reason = "error:0A00009B:SSL routines:tls_validate_record_header:https proxy request"; - code = "ERR_SSL_HTTPS_PROXY_REQUEST"; - } - scr_net_sock_transport_error_code(t->sock, reason, code); - return; + const char *msg, *code; + (void)scr_tls_server_reason(t, r, &msg, &code); + scr_net_sock_transport_error_code(t->sock, msg, code); +} + +/* A fatal alert a server sends a client without the certificate it + * requires: the client's error is OpenSSL's reason (without its + * per-process prefix and source location, SEMANTICS.md divergence 55) and + * Node's code. False for other alerts. */ +static bool scr_tls_alert_error(ScrTlsSock *t, unsigned char alert) { + if (alert == MBEDTLS_SSL_ALERT_MSG_CERT_REQUIRED) { + /* after the client's handshake: Node emits 'error' and the socket + * then ends when the server closes, with close(false) */ + scr_net_sock_transport_report(t->sock, + "error:0A00045C:SSL routines:ssl3_read_bytes:tlsv13 alert certificate required", + "ERR_SSL_TLSV13_ALERT_CERTIFICATE_REQUIRED"); + t->alert_reported = true; + return true; } - scr_net_sock_transport_error(t->sock, "server TLS handshake failed"); + if (alert == MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE) { + scr_net_sock_transport_error_code(t->sock, + "error:0A000410:SSL routines:ssl3_read_bytes:ssl/tls alert handshake failure", + "ERR_SSL_SSL/TLS_ALERT_HANDSHAKE_FAILURE"); + return true; + } + return false; +} + +/* A server that requires a client certificate (requestCert with + * rejectUnauthorized) runs its handshake a step at a time, so a client + * that sends none fails as soon as its empty Certificate is read, before + * the server's Finished in TLS 1.2, with OpenSSL's alert: certificate + * required in TLS 1.3, handshake failure in TLS 1.2. */ +static int scr_tls_handshake_requiring_cert(ScrTlsSock *t) { + while (!mbedtls_ssl_is_handshake_over(&t->ssl)) { + int r = mbedtls_ssl_handshake_step(&t->ssl); + if (r != 0) return r; + if (t->cert_missing) continue; + /* all ones until the client's Certificate is read */ + uint32_t verdict = mbedtls_ssl_get_verify_result(&t->ssl); + if (verdict == UINT32_MAX || !(verdict & MBEDTLS_X509_BADCERT_MISSING)) continue; + if (mbedtls_ssl_get_version_number(&t->ssl) != MBEDTLS_SSL_VERSION_TLS1_3) { + (void)mbedtls_ssl_send_alert_message(&t->ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_HANDSHAKE_FAILURE); + return MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE; + } + /* TLS 1.3: the client has finished and reads under the server's + * application keys, which mbedTLS writes with only once the handshake + * is over, so the alert waits for that */ + t->cert_missing = true; + } + if (t->cert_missing) { + (void)mbedtls_ssl_send_alert_message(&t->ssl, MBEDTLS_SSL_ALERT_LEVEL_FATAL, + MBEDTLS_SSL_ALERT_MSG_CERT_REQUIRED); + return MBEDTLS_ERR_SSL_NO_CLIENT_CERTIFICATE; + } + return 0; +} + +static ScrTlsSock *scr_tls_sock_of(ScrNetSocket *s); + +/* The immediate that ends the hold: queued as the handshake finishes, + * before the established callbacks run, so it comes ahead of any + * immediate they queue. A socket destroyed by then has no fd, and what + * was held is dropped. */ +static void scr_tls_release_hold(ScrClosure *self) { + ScrNetSocket *s = scr_box_get_ref(self->caps[0]); /* +1 */ + ScrTlsSock *t = scr_tls_sock_of(s); + if (t != NULL && t->holding) { + t->holding = false; + if (t->held_len > t->held_off) (void)scr_tls_flush_held(t); + } + scr_net_sock_release(s); +} + +static void scr_tls_hold_until_immediate(ScrTlsSock *t) { + ScrClosure *cb = scr_closure_new((void *)&scr_tls_release_hold, 1); + cb->caps[0] = scr_box_new_obj(&scr_net_sock_retain_v, &scr_net_sock_release_v, NULL); + scr_box_set_ref(cb->caps[0], scr_net_sock_retain(t->sock)); + (void)scr_set_immediate(cb); } static int scr_tls_handshake(void *tctx) { @@ -1129,8 +1518,27 @@ static int scr_tls_handshake(void *tctx) { } if (t->sni_state == SCR_SNI_WAIT) return 0; /* the callback is deciding */ scr_tls_current = t; - int r = mbedtls_ssl_handshake(&t->ssl); + t->holding = true; + int r = t->srv != NULL && t->srv->request_cert && t->srv->reject_unauthorized + ? scr_tls_handshake_requiring_cert(t) + : mbedtls_ssl_handshake(&t->ssl); scr_tls_current = NULL; + if (r == 0) { + scr_tls_hold_until_immediate(t); + } else { + /* a step that did not finish the handshake sends what it wrote now */ + t->holding = false; + if (t->held_len > t->held_off) (void)scr_tls_flush_held(t); + } + if (r == 0 && t->srv != NULL && t->srv->request_cert && t->srv->reject_unauthorized && + !t->srv->standalone && mbedtls_ssl_get_verify_result(&t->ssl) != 0) { + /* a client certificate that fails verification: Node's server + * destroys the socket before 'secureConnection', and its + * 'tlsClientError' is the hang-up */ + scr_net_sock_transport_error(t->sock, NULL); + t->hang_up_pending = true; + return -1; + } if (r == 0) return 1; if (r == MBEDTLS_ERR_SSL_WANT_READ || r == MBEDTLS_ERR_SSL_WANT_WRITE) return 0; if (t->srv != NULL && t->wrapped) { @@ -1138,21 +1546,38 @@ static int scr_tls_handshake(void *tctx) { return -1; } if (t->srv != NULL) { - /* Node's server default: 'tlsClientError' with no listener destroys - * the socket without an error event — exactly what portless (no - * listener) sees. */ + /* the socket is destroyed without an error event, and the server's + * 'tlsClientError' gets the failure: now, before the socket closes, + * for an OpenSSL reason; once it closes for a hang-up, as Node + * emits ECONNRESET from the socket's 'close' */ + const char *msg, *code; + bool reason = scr_tls_server_reason(t, r, &msg, &code); + /* Node's socket still has its handle when an OpenSSL reason is + * emitted, so remoteAddress answers; the address is cached before + * the fd closes */ + if (reason) scr_str_release(scr_net_sock_remote_address(t->sock)); + scr_tls_drain_unread(t); scr_net_sock_transport_error(t->sock, NULL); + if (reason) scr_tls_client_error(t, msg, code); + else t->hang_up_pending = true; return -1; } char msg[160]; if (r == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED) { scr_tls_verify_msg(t, msg, sizeof msg); - } else if (r == MBEDTLS_ERR_SSL_CONN_EOF || r == MBEDTLS_ERR_NET_CONN_RESET) { - /* The peer closed or reset the connection mid-handshake: Node's - * ECONNRESET for tls.connect and https.request alike. */ + } else if (r == MBEDTLS_ERR_SSL_CONN_EOF) { + /* The peer closed the connection mid-handshake: Node's socket ends, + * then fails with ECONNRESET, for tls.connect and https.request + * alike. */ + scr_net_sock_transport_ended(t->sock); + if (scr_exc_pending()) return -1; scr_net_sock_transport_error( t->sock, "Client network socket disconnected before secure TLS connection was established"); return -1; + } else if (r == MBEDTLS_ERR_NET_CONN_RESET) { + /* a reset is the read's own error, as in Node */ + scr_net_sock_transport_error(t->sock, "read ECONNRESET"); + return -1; } else if (r == MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE && t->ssl.MBEDTLS_PRIVATE(in_msg) != NULL && t->ssl.MBEDTLS_PRIVATE(in_msg)[1] == MBEDTLS_SSL_ALERT_MSG_NO_APPLICATION_PROTOCOL) { @@ -1167,6 +1592,9 @@ static int scr_tls_handshake(void *tctx) { t->ssl.MBEDTLS_PRIVATE(in_msg)[1] == MBEDTLS_SSL_ALERT_MSG_PROTOCOL_VERSION) { /* The server accepts none of the offered versions. */ snprintf(msg, sizeof msg, "error:0A00042E:SSL routines:ssl3_read_bytes:tlsv1 alert protocol version"); + } else if (r == MBEDTLS_ERR_SSL_FATAL_ALERT_MESSAGE && t->ssl.MBEDTLS_PRIVATE(in_msg) != NULL && + scr_tls_alert_error(t, t->ssl.MBEDTLS_PRIVATE(in_msg)[1])) { + return -1; } else { /* non-verify handshake failures: honest but not Node's exact openssl * string (SEMANTICS.md divergence 55) */ @@ -1215,6 +1643,9 @@ static void scr_tls_shutdown_write(void *tctx) { ScrTlsSock *t = (ScrTlsSock *)tctx; if (t->notify_sent) return; t->notify_sent = true; + /* end() sends what is held, then the close_notify, ahead of the FIN */ + t->holding = false; + if (t->held_len > t->held_off) (void)scr_tls_flush_held(t); (void)mbedtls_ssl_close_notify(&t->ssl); /* best effort; EAGAIN drops it */ } @@ -1227,9 +1658,18 @@ static void scr_tls_free(void *tctx) { scr_net_ls_drop(&t->secure_ls); free(t->hello); scr_secure_ctx_release(t->sni_ctx); + mbedtls_x509_crt_free(&t->served_chain); + if (t->server) scr_net_server_release(t->server); + free(t->held); free(t); } +/* The fd is writable again: the rest of what was held goes out. */ +static void scr_tls_drain(void *tctx) { + ScrTlsSock *t = (ScrTlsSock *)tctx; + if (!t->holding && t->held_len > t->held_off) (void)scr_tls_flush_held(t); +} + /* The 'secure' event: after a client's secureConnect listeners, as Node * emits it. */ static void scr_tls_after_established(void *tctx) { @@ -1247,6 +1687,10 @@ static void scr_tls_settle(void *tctx) { t->settled = true; scr_net_ls_drop(&t->secure_ls); scr_net_ls_drop(&t->session_ls); + if (t->hang_up_pending) { + t->hang_up_pending = false; + scr_tls_client_error(t, "socket hang up", "ECONNRESET"); + } } static const ScrNetTransportOps SCR_TLS_OPS = { @@ -1259,6 +1703,7 @@ static const ScrNetTransportOps SCR_TLS_OPS = { .free = scr_tls_free, .settle = scr_tls_settle, .after_established = scr_tls_after_established, + .drain = scr_tls_drain, }; /* ── the server surface ──────────────────────────────────────────────── */ @@ -1272,8 +1717,11 @@ static void scr_tls_srv_on_conn(void *ctx, ScrNetSocket *sock) { if (!t) scr_tls_oom(); mbedtls_ssl_init(&t->ssl); if (mbedtls_ssl_setup(&t->ssl, &srv->conf) != 0) scr_tls_oom(); + if (srv->request_cert) mbedtls_ssl_set_verify(&t->ssl, &scr_tls_vrfy_cb, t); t->sock = sock; t->srv = scr_tls_srv_retain(srv); + ScrNetServer *server = scr_net_sock_server(sock); + t->server = server != NULL ? scr_net_server_retain(server) : NULL; if (srv->sni_cb != NULL || srv->max_tls12) t->sni_state = SCR_SNI_COLLECT; /* pre-parse the hello */ mbedtls_ssl_set_bio(&t->ssl, t, scr_tls_bio_send, scr_tls_bio_recv, NULL); scr_net_sock_set_transport(sock, &SCR_TLS_OPS, t); @@ -1285,8 +1733,10 @@ static ScrNetServer *scr_tls_create_server_alpn(const char *cert, size_t cert_le ScrNetConnFn fn, char **alpn /*moves, nullable*/, int min_version, int max_version, ScrClosure *sni_cb /*moves, nullable*/, - void *sni_answer_fn) { + void *sni_answer_fn, + const ScrTlsClientAuth *auth /*nullable*/) { ScrTlsSrv *srv = scr_tls_srv_new(cert, cert_len, key, key_len, false); + scr_tls_srv_client_auth(srv, auth); if (sni_cb != NULL) { srv->sni_cb = sni_cb; /* moves; released with srv */ srv->sni_answer_fn = sni_answer_fn; @@ -1319,7 +1769,7 @@ ScrNetServer *scr_tls_create_server(const char *cert, size_t cert_len, const cha size_t key_len, ScrClosure *handler /*moves, nullable*/, ScrNetConnFn fn) { return scr_tls_create_server_alpn(cert, cert_len, key, key_len, handler, fn, NULL, 12, 13, NULL, - NULL); + NULL, NULL); } /* tls.createServer({ cert, key, SNICallback }): the pre-parse machinery @@ -1332,14 +1782,15 @@ ScrNetServer *scr_tls_create_server_sni(const char *cert, size_t cert_len, const ScrNetConnFn fn, ScrClosure *sni_cb /*moves, nullable*/, void *sni_answer_fn) { return scr_tls_create_server_alpn(cert, cert_len, key, key_len, handler, fn, NULL, 12, 13, sni_cb, - sni_answer_fn); + sni_answer_fn, NULL); } -ScrNetServer *scr_https_create_server(const char *cert, size_t cert_len, const char *key, - size_t key_len, ScrClosure *handler /*moves*/, - ScrHttpReqFn fn) { +static ScrNetServer *scr_https_create_server_auth(const char *cert, size_t cert_len, const char *key, + size_t key_len, ScrClosure *handler /*moves*/, + ScrHttpReqFn fn, const ScrTlsClientAuth *auth /*nullable*/) { ScrNetServer *s = scr_http_create_server(handler, fn); ScrTlsSrv *srv = scr_tls_srv_new(cert, cert_len, key, key_len, true /* ALPN http/1.1 */); + scr_tls_srv_client_auth(srv, auth); /* wrap the parser hook: TLS first, parser at establishment */ scr_net_server_get_native_conn(s, &srv->inner_conn, &srv->inner_ctx, &srv->inner_ctx_free); scr_net_server_set_native_conn(s, &scr_tls_srv_on_conn, srv, &scr_tls_srv_release_v); @@ -1347,6 +1798,12 @@ ScrNetServer *scr_https_create_server(const char *cert, size_t cert_len, const c return s; } +ScrNetServer *scr_https_create_server(const char *cert, size_t cert_len, const char *key, + size_t key_len, ScrClosure *handler /*moves*/, + ScrHttpReqFn fn) { + return scr_https_create_server_auth(cert, cert_len, key, key_len, handler, fn, NULL); +} + /* The SNI-callback form of the allowHTTP1 compatibility server: the same * handler-less https server, plus the pre-parse machinery (design note * atop the SNI section). A NULL sni_cb — the conditional spread's @@ -1505,12 +1962,22 @@ static int scr_tls_tunnel_bio_recv(void *ctx, unsigned char *buf, size_t len) { return scr_tls_tunnel_read((ScrTlsTunnel *)ctx, buf, len); } +/* A tunnel leg's handshake has finished. The tunnel runs no established + * callbacks before it writes the CONNECT request or the request itself, so + * the last flight goes out now instead of waiting for the immediate that + * ends a socket's hold (which does not see the tunnel's legs). */ +static void scr_tls_tunnel_end_hold(ScrTlsSock *t) { + t->holding = false; + if (t->held_len > t->held_off) (void)scr_tls_flush_held(t); +} + static int scr_tls_tunnel_handshake(void *tctx) { ScrTlsTunnel *tun = (ScrTlsTunnel *)tctx; ScrNetSocket *sock = tun->outer->sock; if (tun->stage == SCR_TUN_OUTER) { int r = scr_tls_handshake(tun->outer); if (r <= 0) return r; + scr_tls_tunnel_end_hold(tun->outer); tun->outer->established = true; tun->stage = SCR_TUN_SEND; } @@ -1579,6 +2046,7 @@ static int scr_tls_tunnel_handshake(void *tctx) { if (tun->stage == SCR_TUN_INNER) { int r = scr_tls_handshake(tun->inner); if (r <= 0) return r; + scr_tls_tunnel_end_hold(tun->inner); tun->stage = SCR_TUN_UP; } return 1; @@ -1625,12 +2093,16 @@ static void scr_tls_tunnel_free(void *tctx) { free(tun); } +/* The fd is writable again: the rest of what the outer leg held. */ +static void scr_tls_tunnel_drain(void *tctx) { scr_tls_drain(((ScrTlsTunnel *)tctx)->outer); } + static const ScrNetTransportOps SCR_TLS_TUNNEL_OPS = { .xread = scr_tls_tunnel_xread, .xwrite = scr_tls_tunnel_xwrite, .handshake = scr_tls_tunnel_handshake, .on_established = scr_tls_tunnel_on_established, .pending = scr_tls_tunnel_pending, + .drain = scr_tls_tunnel_drain, .shutdown_write = scr_tls_tunnel_shutdown_write, .free = scr_tls_tunnel_free, }; @@ -1822,10 +2294,11 @@ static ScrBytes *scr_tls_pem_dyn(const ScrDyn *v, const char *what, bool concat) /* https.request/get with a runtime options record: the http walk, then * the TLS options the literal https path lowers (rejectUnauthorized, ca, - * servername). Other tls.connect options fence when they carry a value. */ + * servername) and a client certificate (cert and key). Other tls.connect + * options fence when they carry a value. */ static const char *const SCR_HTTPS_REQ_FENCED_OPTIONS[] = { - "ALPNProtocols", "cert", "checkServerIdentity", "ciphers", "crl", "dhparam", "ecdhCurve", - "honorCipherOrder", "key", "maxVersion", "minVersion", "passphrase", "pfx", "secureContext", + "ALPNProtocols", "checkServerIdentity", "ciphers", "crl", "dhparam", "ecdhCurve", + "honorCipherOrder", "maxVersion", "minVersion", "passphrase", "pfx", "secureContext", "secureOptions", "secureProtocol", "session", "sessionIdContext", "sigalgs", NULL, }; @@ -1840,6 +2313,7 @@ ScrHttpClientReq *scr_https_request_dyn(const ScrDyn *opts /*borrowed*/, bool au const ScrDyn *rec = o.view != NULL ? o.view : opts; bool reject = true; ScrBytes *ca = NULL; + ScrBytes *own_cert = NULL, *own_key = NULL; ScrStr *servername = NULL; bool ok = true; if (rec != NULL && rec->kind == SCR_DYN_OBJ) { @@ -1848,7 +2322,7 @@ ScrHttpClientReq *scr_https_request_dyn(const ScrDyn *opts /*borrowed*/, bool au const ScrDyn *v = scr_dyn_obj_get(rec, key, strlen(key)); if (v != NULL && scr_tls_dyn_truthy(v)) { scr_http_req_opts_fence("https.request", key, - "rejectUnauthorized, ca, and servername are the supported TLS options"); + "rejectUnauthorized, ca, servername, cert, and key are the supported TLS options"); ok = false; } } @@ -1859,6 +2333,21 @@ ScrHttpClientReq *scr_https_request_dyn(const ScrDyn *opts /*borrowed*/, bool au ca = scr_tls_pem_dyn(c, "an https.request 'ca' option", true); if (ca == NULL) ok = false; } + const ScrDyn *oc = ok ? scr_dyn_obj_get(rec, "cert", 4) : NULL; + if (oc != NULL && oc->kind != SCR_DYN_UNDEF && oc->kind != SCR_DYN_NULL) { + own_cert = scr_tls_pem_dyn(oc, "an https.request 'cert' option", false); + if (own_cert == NULL) ok = false; + } + const ScrDyn *ok_ = ok ? scr_dyn_obj_get(rec, "key", 3) : NULL; + if (ok_ != NULL && ok_->kind != SCR_DYN_UNDEF && ok_->kind != SCR_DYN_NULL) { + own_key = scr_tls_pem_dyn(ok_, "an https.request 'key' option", false); + if (own_key == NULL) ok = false; + } + if (ok && (own_cert == NULL) != (own_key == NULL)) { + scr_http_req_opts_fence("https.request", own_cert != NULL ? "cert" : "key", + "a client certificate lowers with both cert and key"); + ok = false; + } const ScrDyn *sn = ok ? scr_dyn_obj_get(rec, "servername", 10) : NULL; if (sn != NULL && sn->kind != SCR_DYN_UNDEF && sn->kind != SCR_DYN_NULL) { if (sn->kind != SCR_DYN_STR) { @@ -1871,6 +2360,8 @@ ScrHttpClientReq *scr_https_request_dyn(const ScrDyn *opts /*borrowed*/, bool au } if (!ok) { if (ca) scr_bytes_release(ca); + scr_bytes_release(own_cert); + scr_bytes_release(own_key); scr_http_req_opts_free(&o); if (cb) scr_closure_release(cb); return NULL; @@ -1879,6 +2370,22 @@ ScrHttpClientReq *scr_https_request_dyn(const ScrDyn *opts /*borrowed*/, bool au size_t ca_len = ca ? ca->len : 0; ScrTlsCli *cli = scr_tls_cli_for(o.host, reject, ca_data, ca_len, servername); ScrStr *key = scr_tls_pool_key(o.host, reject, ca_data, ca_len, servername); + if (own_cert != NULL) { + /* Node's agent keys pooled sockets by the client certificate too */ + scr_tls_cli_set_own(cli, own_cert, own_key); + uint64_t h = 1469598103934665603ull; + for (size_t i = 0; i < own_cert->len; i++) h = (h ^ own_cert->data[i]) * 1099511628211ull; + for (size_t i = 0; i < own_key->len; i++) h = (h ^ own_key->data[i]) * 1099511628211ull; + char suffix[24]; + int n = snprintf(suffix, sizeof suffix, ":c%016llx", (unsigned long long)h); + ScrStr *tail = scr_str_new(suffix, (size_t)n); + ScrStr *keyed = scr_str_concat(key, tail); + scr_str_release(tail); + scr_str_release(key); + key = keyed; + scr_bytes_release(own_cert); + scr_bytes_release(own_key); + } scr_str_release(servername); ScrHttpClientReq *req = scr_http_req_opts_send(&o, auto_end, cb, fn, add_abort, &scr_tls_cli_wrap, cli, key); @@ -2014,9 +2521,22 @@ static bool scr_tls_opts_validate(const ScrDyn *opts) { /* `server_ok`: tls.createServer reads ALPNProtocols, minVersion and * maxVersion itself; the walk's other callers keep their fences. */ static bool scr_tls_srv_opts_walk_ex(const ScrDyn *opts, const char *api, ScrBytes **cert_out, - ScrBytes **key_out, bool server_ok) { + ScrBytes **key_out, bool server_ok, ScrTlsClientAuth *auth) { + if (opts != NULL && opts->kind == SCR_DYN_TYPED_REF) { + /* a typed record (an options binding): its fields, as a plain object */ + ScrDyn *plain = scr_dyn_typed_ref_materialize(opts); + if (plain == NULL) { + *cert_out = NULL; + *key_out = NULL; + return false; + } + bool ok = scr_tls_srv_opts_walk_ex(plain, api, cert_out, key_out, server_ok, auth); + scr_dyn_release(plain); + return ok; + } *cert_out = NULL; *key_out = NULL; + if (auth != NULL) *auth = (ScrTlsClientAuth){.request = false, .reject = true, .ca = NULL}; if (opts == NULL || opts->kind != SCR_DYN_OBJ) { scr_dyn_arg_type_fail("options", "of type object", opts ? opts : scr_dyn_undefined()); return false; @@ -2038,20 +2558,39 @@ static bool scr_tls_srv_opts_walk_ex(const ScrDyn *opts, const char *api, ScrByt continue; } if (strcmp(e->key, "ca") == 0) { - /* the server's `ca` verifies CLIENT certificates — inert without - * requestCert (which fences below), so Node-observably droppable */ + /* the server's `ca` verifies client certificates and completes the + * server's own chain (scr_tls_srv_client_auth); a walk without + * client certificates drops it */ + if (auth != NULL) { + char what[96]; + snprintf(what, sizeof what, "a %s 'ca' option", api); + scr_bytes_release(auth->ca); + /* An empty string is no ca, as Node reads it; an empty Buffer is + * an empty trust store. */ + if (v->kind == SCR_DYN_STR && v->v.str->len == 0) { + auth->ca = NULL; + } else { + auth->ca = scr_tls_pem_dyn(v, what, true); + if (auth->ca == NULL) ok = false; + } + } continue; } if (strcmp(e->key, "requestCert") == 0) { + if (auth != NULL) { + auth->request = scr_tls_dyn_truthy(v); + continue; + } if (scr_tls_dyn_truthy(v)) { scr_tls_opt_fence(api, "requestCert", - "client-certificate handshakes are not modeled (SEMANTICS.md divergence 55) — requestCert stays at Node's false default"); + "requestCert lowers on tls.createServer, https.createServer and new tls.TLSSocket"); ok = false; } continue; } if (strcmp(e->key, "rejectUnauthorized") == 0) { - continue; /* meaningful only with requestCert, which fences */ + if (auth != NULL) auth->reject = scr_tls_dyn_truthy(v); + continue; /* without client certificates it has no effect */ } if (server_ok && (strcmp(e->key, "ALPNProtocols") == 0 || strcmp(e->key, "minVersion") == 0 || strcmp(e->key, "maxVersion") == 0)) @@ -2085,13 +2624,17 @@ static bool scr_tls_srv_opts_walk_ex(const ScrDyn *opts, const char *api, ScrByt scr_bytes_release(*key_out); *cert_out = NULL; *key_out = NULL; + if (auth != NULL) { + scr_bytes_release(auth->ca); + auth->ca = NULL; + } } return ok; } bool scr_tls_srv_opts_walk(const ScrDyn *opts, const char *api, ScrBytes **cert_out, ScrBytes **key_out) { - return scr_tls_srv_opts_walk_ex(opts, api, cert_out, key_out, false); + return scr_tls_srv_opts_walk_ex(opts, api, cert_out, key_out, false, NULL); } /* createSecureContext over a RUNTIME options record: Node's typed @@ -2101,9 +2644,22 @@ bool scr_tls_srv_opts_walk(const ScrDyn *opts, const char *api, ScrBytes **cert_ * +1, or NULL with the exception pending. */ ScrSecureCtx *scr_tls_create_secure_context_dyn(const ScrDyn *opts /*borrowed*/) { ScrBytes *cert, *key; - if (!scr_tls_srv_opts_walk(opts, "tls.createSecureContext", &cert, &key)) return NULL; + /* requestCert and rejectUnauthorized are no context options: Node's + * createSecureContext ignores them */ + ScrTlsClientAuth auth; + if (!scr_tls_srv_opts_walk_ex(opts, "tls.createSecureContext", &cert, &key, false, &auth)) return NULL; ScrSecureCtx *c = scr_tls_create_secure_context((const char *)cert->data, cert->len, (const char *)key->data, key->len); + if (auth.ca != NULL) { + /* kept for sockets created from the context (a TLSSocket's + * secureContext); an SNI answer's chain comes from the server's + * context in OpenSSL, so the answer's ca is not used there */ + if (auth.ca->len > 0) { + int r = scr_tls_parse_crt(&c->ca, (const char *)auth.ca->data, auth.ca->len); + if (r != 0) scr_tls_bad_material("ca certificate", r); + } + scr_bytes_release(auth.ca); + } scr_bytes_release(cert); scr_bytes_release(key); return c; @@ -2142,7 +2698,8 @@ ScrNetServer *scr_tls_create_server_dyn(const ScrDyn *opts /*borrowed*/, return NULL; } ScrBytes *cert, *key; - if (!scr_tls_srv_opts_walk_ex(opts, "tls.createServer", &cert, &key, true)) { + ScrTlsClientAuth auth; + if (!scr_tls_srv_opts_walk_ex(opts, "tls.createServer", &cert, &key, true, &auth)) { scr_closure_release(handler); return NULL; } @@ -2153,12 +2710,14 @@ ScrNetServer *scr_tls_create_server_dyn(const ScrDyn *opts /*borrowed*/, if (protocols != NULL && !scr_tls_alpn_dyn(protocols, &alpn)) { scr_bytes_release(cert); scr_bytes_release(key); + scr_bytes_release(auth.ca); scr_closure_release(handler); return NULL; } ScrNetServer *s = scr_tls_create_server_alpn((const char *)cert->data, cert->len, (const char *)key->data, key->len, handler, fn, - alpn, min_version, max_version, NULL, NULL); + alpn, min_version, max_version, NULL, NULL, &auth); + scr_bytes_release(auth.ca); scr_bytes_release(cert); scr_bytes_release(key); return s; @@ -2189,18 +2748,146 @@ ScrNetServer *scr_https_create_server_dyn(const ScrDyn *opts /*borrowed*/, } } ScrBytes *cert, *key; - if (!scr_tls_srv_opts_walk(opts, "https.createServer", &cert, &key)) { + ScrTlsClientAuth auth; + if (!scr_tls_srv_opts_walk_ex(opts, "https.createServer", &cert, &key, false, &auth)) { scr_closure_release(handler); return NULL; } - ScrNetServer *s = scr_https_create_server((const char *)cert->data, cert->len, - (const char *)key->data, key->len, handler, fn); + ScrNetServer *s = scr_https_create_server_auth((const char *)cert->data, cert->len, + (const char *)key->data, key->len, handler, fn, &auth); + scr_bytes_release(auth.ca); if (has_timeout_buffer) scr_net_server_timeout_set(s, 4, timeout_buffer); scr_bytes_release(cert); scr_bytes_release(key); return s; } +/* ── server.addContext and server.setSecureContext ───────────────────── */ + +/* Node's addContext pattern: the name with '*' as [^.]* (any run within a + * label, empty too), matched without regard to case. */ +static bool scr_tls_name_match(const char *pattern, const unsigned char *name, size_t len) { + if (*pattern == '\0') return len == 0; + if (*pattern == '*') { + for (size_t k = 0;; k++) { + if (scr_tls_name_match(pattern + 1, name + k, len - k)) return true; + if (k == len || name[k] == '.') return false; + } + } + return len > 0 && (unsigned char)tolower(name[0]) == (unsigned char)*pattern && + scr_tls_name_match(pattern + 1, name + 1, len - 1); +} + +/* The certificate a server handshake serves when the server has contexts + * (mbedTLS's certificate callback, after the SNI name is read): the + * newest addContext entry whose pattern matches the name, else the + * setSecureContext default, else the server's own. An SNICallback answer + * (or a server with an SNICallback, whose contexts Node does not read) + * keeps its own path. OpenSSL completes the served chain from the store + * of the connection's context, the server's current default, and verifies + * client certificates against the served context's. */ +static int scr_tls_f_cert(mbedtls_ssl_context *ssl) { + ScrTlsSock *t = scr_tls_current; + if (t == NULL || t->srv == NULL || t->sni_ctx != NULL) return 0; + ScrTlsSrv *s = t->srv; + ScrSecureCtx *pick = NULL; + if (s->sni_cb == NULL) { + size_t len = 0; + const unsigned char *name = mbedtls_ssl_get_hs_sni(ssl, &len); + for (size_t i = s->ncontexts; name != NULL && i-- > 0;) { + if (scr_tls_name_match(s->contexts[i].pattern, name, len)) { + pick = s->contexts[i].ctx; + break; + } + } + } + if (pick == NULL) pick = s->default_ctx; + if (pick == NULL) return 0; + t->sni_ctx = scr_secure_ctx_retain(pick); + const mbedtls_x509_crt *store = s->default_ctx != NULL ? &s->default_ctx->ca : &s->ca; + mbedtls_x509_crt *own = &pick->cert; + if (store->raw.len > 0 && pick->cert.next == NULL) { + scr_tls_chained_copy(&t->served_chain, &pick->cert, store); + own = &t->served_chain; + } + if (s->request_cert) + mbedtls_ssl_set_hs_ca_chain(ssl, pick->ca.raw.len > 0 ? &pick->ca : scr_tls_system_ca(), NULL); + return mbedtls_ssl_set_hs_own_cert(ssl, own, &pick->pk); +} + +/* The TLS config of a tls or https server, or NULL with the fence thrown. */ +static ScrTlsSrv *scr_tls_srv_of_server(ScrNetServer *server, const char *what) { + ScrNetNativeConnFn fn = NULL; + void *ctx = NULL; + void (*ctx_free)(void *) = NULL; + scr_net_server_get_native_conn(server, &fn, &ctx, &ctx_free); + if (fn == &scr_tls_srv_on_conn && ctx != NULL) return (ScrTlsSrv *)ctx; + char msg[160]; + int n = snprintf(msg, sizeof msg, "%s on a server that is not a tls or https server is not supported yet", what); + scr_throw_error_msg_code(SCR_ERR_ERROR, msg, (size_t)(n < (int)sizeof msg ? n : (int)sizeof msg - 1), "SC2020"); + return NULL; +} + +/* server.addContext(servername, context): `context` is a SecureContext + * (borrowed, nullable) or the options createSecureContext reads. Node + * builds a RegExp from the name, so a name with regular-expression groups + * or alternation throws the fence. */ +void scr_tls_server_add_context(ScrNetServer *server, const ScrDyn *servername, + const ScrDyn *options /*nullable*/, ScrSecureCtx *ctx /*nullable*/) { + ScrTlsSrv *s = scr_tls_srv_of_server(server, "server.addContext"); + if (s == NULL) return; + if (!scr_tls_dyn_truthy(servername)) { + static const char msg[] = "\"servername\" is required parameter for Server.addContext"; + scr_throw_error_msg_code(SCR_ERR_ERROR, msg, sizeof msg - 1, "ERR_TLS_REQUIRED_SERVER_NAME"); + return; + } + if (servername->kind != SCR_DYN_STR) { + scr_tls_opt_fence("server.addContext", "servername", "the servername lowers as a string"); + return; + } + const ScrStr *name = servername->v.str; + for (size_t i = 0; i < name->len; i++) { + if (name->data[i] == '(' || name->data[i] == ')' || name->data[i] == '|') { + scr_tls_opt_fence("server.addContext", "servername", + "a servername with regular-expression groups or alternation has no lowering"); + return; + } + /* the RegExp's case folding beyond ASCII differs from tolower's */ + if ((unsigned char)name->data[i] >= 0x80) { + scr_tls_opt_fence("server.addContext", "servername", "a servername outside ASCII has no lowering"); + return; + } + } + ScrSecureCtx *c = ctx != NULL ? scr_secure_ctx_retain(ctx) : scr_tls_create_secure_context_dyn(options); + if (c == NULL) return; + char *pattern = malloc(name->len + 1); + struct ScrTlsNamedCtx *grown = realloc(s->contexts, (s->ncontexts + 1) * sizeof *s->contexts); + if (pattern == NULL || grown == NULL) scr_tls_oom(); + for (size_t i = 0; i < name->len; i++) pattern[i] = (char)tolower((unsigned char)name->data[i]); + pattern[name->len] = '\0'; + s->contexts = grown; + s->contexts[s->ncontexts].pattern = pattern; + s->contexts[s->ncontexts].ctx = c; + s->ncontexts++; + mbedtls_ssl_conf_cert_cb(&s->conf, &scr_tls_f_cert); +} + +/* server.setSecureContext(options): new connections serve a context made + * from `options`; open ones keep theirs. */ +void scr_tls_server_set_secure_context(ScrNetServer *server, const ScrDyn *options) { + ScrTlsSrv *s = scr_tls_srv_of_server(server, "server.setSecureContext"); + if (s == NULL) return; + if (options == NULL || (options->kind != SCR_DYN_OBJ && options->kind != SCR_DYN_TYPED_REF)) { + scr_dyn_arg_type_fail("options", "of type object", options != NULL ? options : scr_dyn_undefined()); + return; + } + ScrSecureCtx *c = scr_tls_create_secure_context_dyn(options); + if (c == NULL) return; + scr_secure_ctx_release(s->default_ctx); + s->default_ctx = c; + mbedtls_ssl_conf_cert_cb(&s->conf, &scr_tls_f_cert); +} + /* ── new tls.TLSSocket(socket, options) ───────────────────────────────── */ /* The server-mode wrap: a fresh TLS socket takes over raw's connection @@ -2226,7 +2913,7 @@ static bool scr_tls_wrap_socket_opts_check(const ScrDyn *record, const char *api if (strcmp(e->key, "requestCert") == 0) { if (!scr_tls_dyn_truthy(e->value)) continue; scr_tls_opt_fence(api, "requestCert", - "client-certificate handshakes are not modeled (SEMANTICS.md divergence 55) — requestCert stays at Node's false default"); + "requestCert lowers with cert and key options, not beside a secureContext"); return false; } if (strcmp(e->key, "SNICallback") == 0 || strcmp(e->key, "ALPNCallback") == 0) { @@ -2271,13 +2958,17 @@ ScrNetSocket *scr_tls_wrap_socket(ScrNetSocket *raw, const ScrDyn *opts /*borrow /* Node serves a secureContext as it is: the record's cert, key and * other context options are not read then. The socket's own options * still apply, so the ones without a lowering fence either way: - * requestCert asks for a client certificate this runtime cannot - * verify. */ + * requestCert lowers with cert and key, whose ca the walk reads. */ int min_version = 12, max_version = 13; ScrBytes *cert = NULL, *key = NULL; + ScrTlsClientAuth auth = {.request = false, .reject = false, .ca = NULL}; if (ctx == NULL) { if (!scr_tls_versions_dyn(record, &min_version, &max_version)) return NULL; - if (!scr_tls_srv_opts_walk_ex(record, api, &cert, &key, true)) return NULL; + if (!scr_tls_srv_opts_walk_ex(record, api, &cert, &key, true, &auth)) return NULL; + /* a standalone socket requires a certificate only for a truthy + * rejectUnauthorized; tls.Server's true default does not apply */ + const ScrDyn *reject = scr_dyn_obj_get(record, "rejectUnauthorized", 18); + auth.reject = reject != NULL && scr_tls_dyn_truthy(reject); } else if (!scr_tls_wrap_socket_opts_check(record, api)) { return NULL; } @@ -2286,6 +2977,7 @@ ScrNetSocket *scr_tls_wrap_socket(ScrNetSocket *raw, const ScrDyn *opts /*borrow if (protocols != NULL && protocols->kind != SCR_DYN_UNDEF && !scr_tls_alpn_dyn(protocols, &alpn)) { scr_bytes_release(cert); scr_bytes_release(key); + scr_bytes_release(auth.ca); return NULL; } ScrTlsSrv *srv = ctx != NULL ? scr_tls_srv_from_ctx(ctx) @@ -2293,6 +2985,9 @@ ScrNetSocket *scr_tls_wrap_socket(ScrNetSocket *raw, const ScrDyn *opts /*borrow (const char *)key->data, key->len, false); scr_bytes_release(cert); scr_bytes_release(key); + srv->standalone = true; + scr_tls_srv_client_auth(srv, ctx == NULL ? &auth : NULL); + scr_bytes_release(auth.ca); srv->alpn = alpn; /* moves */ if (alpn != NULL) mbedtls_ssl_conf_alpn_protocols(&srv->conf, (const char **)srv->alpn); if (!scr_tls_conf_versions(&srv->conf, min_version, max_version)) { @@ -2314,6 +3009,7 @@ ScrNetSocket *scr_tls_wrap_socket(ScrNetSocket *raw, const ScrDyn *opts /*borrow if (!ts) scr_tls_oom(); mbedtls_ssl_init(&ts->ssl); if (mbedtls_ssl_setup(&ts->ssl, &srv->conf) != 0) scr_tls_oom(); + if (srv->request_cert) mbedtls_ssl_set_verify(&ts->ssl, &scr_tls_vrfy_cb, ts); ts->sock = t; ts->srv = srv; /* moves */ ts->wrapped = true; @@ -2468,10 +3164,10 @@ static bool scr_tls_alpn_dyn(const ScrDyn *v, char ***out) { * throws (the server walk's stance). */ static const char *const SCR_TLS_CONNECT_FENCED_OPTIONS[] = { "allowHalfOpen", "autoSelectFamily", - "autoSelectFamilyAttemptTimeout", "cert", "certificateCompression", "checkServerIdentity", + "autoSelectFamilyAttemptTimeout", "certificateCompression", "checkServerIdentity", "ciphers", "clientCertEngine", "crl", "dhparam", "ecdhCurve", "enableTrace", "family", "fd", "hints", "highWaterMark", - "honorCipherOrder", "keepAlive", "keepAliveInitialDelay", "key", + "honorCipherOrder", "keepAlive", "keepAliveInitialDelay", "localAddress", "localPort", "lookup", "minDHSize", "noDelay", "onread", "passphrase", "path", "pfx", "privateKeyEngine", "privateKeyIdentifier", "pskCallback", "readable", "secureContext", "secureOptions", "secureProtocol", "session", @@ -2479,12 +3175,32 @@ static const char *const SCR_TLS_CONNECT_FENCED_OPTIONS[] = { "writable", NULL, }; +static ScrNetSocket *scr_tls_connect_plain(double port, ScrStr *host /*borrowed, nullable*/, + const ScrDyn *opts /*borrowed, nullable*/, + ScrClosure *cb /*moves, nullable*/); + ScrNetSocket *scr_tls_connect_dyn(double port, ScrStr *host /*borrowed, nullable*/, const ScrDyn *opts /*borrowed, nullable*/, ScrClosure *cb /*moves, nullable*/) { + if (opts == NULL || opts->kind != SCR_DYN_TYPED_REF) return scr_tls_connect_plain(port, host, opts, cb); + /* a typed record (an options binding): its fields, as a plain object */ + ScrDyn *plain = scr_dyn_typed_ref_materialize(opts); + if (plain == NULL) { + scr_closure_release(cb); + return NULL; + } + ScrNetSocket *s = scr_tls_connect_plain(port, host, plain, cb); + scr_dyn_release(plain); + return s; +} + +static ScrNetSocket *scr_tls_connect_plain(double port, ScrStr *host /*borrowed, nullable*/, + const ScrDyn *opts /*borrowed, nullable*/, + ScrClosure *cb /*moves, nullable*/) { scr_tls_rng_init(); bool reject = true; ScrBytes *ca = NULL; + ScrBytes *own_cert = NULL, *own_key = NULL; /* the client certificate */ const ScrStr *servername = NULL; const ScrStr *opt_host = NULL; char **alpn = NULL; @@ -2549,6 +3265,14 @@ ScrNetSocket *scr_tls_connect_dyn(double port, ScrStr *host /*borrowed, nullable if (ca == NULL) ok = false; continue; } + if (strcmp(e->key, "cert") == 0 || strcmp(e->key, "key") == 0) { + ScrBytes **slot = e->key[0] == 'c' ? &own_cert : &own_key; + scr_bytes_release(*slot); + *slot = scr_tls_pem_dyn(v, e->key[0] == 'c' ? "a tls.connect 'cert' option" : "a tls.connect 'key' option", + false); + if (*slot == NULL) ok = false; + continue; + } if (strcmp(e->key, "ALPNProtocols") == 0) { alpn_value = v; /* converted after the context options, as TLSSocket does */ continue; @@ -2607,6 +3331,11 @@ ScrNetSocket *scr_tls_connect_dyn(double port, ScrStr *host /*borrowed, nullable timeout_ms = timeout_value->v.num; } } + if (ok && (own_cert == NULL) != (own_key == NULL)) { + scr_tls_opt_fence("tls.connect", own_cert != NULL ? "cert" : "key", + "a client certificate lowers with both cert and key"); + ok = false; + } if (ok && port < 0 && wrap == NULL) { scr_dyn_arg_type_fail("options.port", "of type number", scr_dyn_undefined()); ok = false; @@ -2616,6 +3345,8 @@ ScrNetSocket *scr_tls_connect_dyn(double port, ScrStr *host /*borrowed, nullable if (!ok) { scr_tls_alpn_free(alpn); scr_bytes_release(ca); + scr_bytes_release(own_cert); + scr_bytes_release(own_key); scr_closure_release(cb); return NULL; } @@ -2639,6 +3370,8 @@ ScrNetSocket *scr_tls_connect_dyn(double port, ScrStr *host /*borrowed, nullable if (s == NULL) { scr_tls_alpn_free(alpn); scr_bytes_release(ca); + scr_bytes_release(own_cert); + scr_bytes_release(own_key); scr_closure_release(cb); scr_str_release(localhost_fallback); scr_str_release(socket_host); @@ -2656,6 +3389,9 @@ ScrNetSocket *scr_tls_connect_dyn(double port, ScrStr *host /*borrowed, nullable ca != NULL ? (const char *)ca->data : NULL, ca != NULL ? ca->len : 0, !reject); if (servername != NULL) scr_tls_cli_set_servername(cli, servername); + if (own_cert != NULL) scr_tls_cli_set_own(cli, own_cert, own_key); + scr_bytes_release(own_cert); + scr_bytes_release(own_key); if (alpn != NULL) { cli->alpn = alpn; /* moves */ mbedtls_ssl_conf_alpn_protocols(&cli->conf, (const char **)cli->alpn); @@ -2731,6 +3467,20 @@ static const char *scr_tls_auth_code(ScrTlsSock *t) { return "UNABLE_TO_VERIFY_LEAF_SIGNATURE"; } +/* A server's authorizationError for the client certificate. OpenSSL + * keeps the last error its verification met: the validity period is + * checked last, the purpose (clientAuth) before it, the chain first. A + * client that sent none is UNABLE_TO_GET_ISSUER_CERT, as Node reports it. */ +static const char *scr_tls_client_cert_code(ScrTlsSock *t) { + uint32_t vr = mbedtls_ssl_get_verify_result(&t->ssl); + if (vr & MBEDTLS_X509_BADCERT_MISSING) return "UNABLE_TO_GET_ISSUER_CERT"; + if (t->vrfy_expired) return "CERT_HAS_EXPIRED"; + if (vr & (MBEDTLS_X509_BADCERT_EXT_KEY_USAGE | MBEDTLS_X509_BADCERT_KEY_USAGE)) return "INVALID_PURPOSE"; + if (t->vrfy_leaf_self) return "DEPTH_ZERO_SELF_SIGNED_CERT"; + if (t->vrfy_chain_self) return "SELF_SIGNED_CERT_IN_CHAIN"; + return "UNABLE_TO_VERIFY_LEAF_SIGNATURE"; +} + static ScrTlsSock *scr_tls_sock_of(ScrNetSocket *s) { return (ScrTlsSock *)scr_net_sock_transport_ctx_for(s, &SCR_TLS_OPS); } @@ -2775,22 +3525,106 @@ static void scr_tls_fire_session(ScrTlsSock *t) { /* The STATIC-lane TLSSocket members (the lowered socket surface). */ +/* Whether the socket verified its peer: a client against its trust + * anchors, a server that requested a client certificate against its. */ +static bool scr_tls_sock_verifies(const ScrTlsSock *t) { + return t->established && ((t->cli != NULL && t->cli->verify_recorded) || + (t->srv != NULL && t->srv->request_cert && !t->srv->standalone)); +} + bool scr_tls_sock_authorized(ScrNetSocket *s) { ScrTlsSock *t = scr_tls_sock_of(s); - return t != NULL && t->established && t->cli != NULL && t->cli->verify_recorded && - mbedtls_ssl_get_verify_result(&t->ssl) == 0; + return t != NULL && scr_tls_sock_verifies(t) && mbedtls_ssl_get_verify_result(&t->ssl) == 0; } ScrStr *scr_tls_sock_auth_error(ScrNetSocket *s) { ScrTlsSock *t = scr_tls_sock_of(s); - if (t == NULL || !t->established || t->cli == NULL || !t->cli->verify_recorded || - mbedtls_ssl_get_verify_result(&t->ssl) == 0) { + if (t == NULL || !scr_tls_sock_verifies(t) || mbedtls_ssl_get_verify_result(&t->ssl) == 0) { return NULL; /* the null arm — authorized, or never verified */ } - const char *code = scr_tls_auth_code(t); + const char *code = t->srv != NULL ? scr_tls_client_cert_code(t) : scr_tls_auth_code(t); return scr_str_new(code, strlen(code)); } +/* ── certificates for the X509Certificate accessors ────────────────── + * + * getPeerCertificate, getCertificate and their X509Certificate forms read + * the DER below (scr_tls_x509.c builds the objects, so this unit needs no + * X.509 code). Node answers from the socket's handle, which a destroyed + * socket no longer has. */ + +bool scr_tls_sock_has_handle(ScrNetSocket *s) { + return scr_tls_sock_of(s) != NULL && !scr_net_sock_destroyed(s); +} + +/* The certificates the peer sent, leaf first (borrowed DER), up to `max`; + * none before the handshake. Answers the count. */ +size_t scr_tls_sock_peer_chain(ScrNetSocket *s, const uint8_t **der, size_t *len, size_t max) { + ScrTlsSock *t = scr_tls_sock_of(s); + if (t == NULL || !t->established) return 0; + size_t n = 0; + for (const mbedtls_x509_crt *c = mbedtls_ssl_get_peer_cert(&t->ssl); c != NULL && c->raw.len > 0 && n < max; + c = c->next) { + der[n] = c->raw.p; + len[n] = c->raw.len; + n++; + } + return n; +} + +/* The certificate the socket serves (borrowed DER), or NULL: a server's + * SNI answer, secureContext or own certificate. Clients send none. */ +const uint8_t *scr_tls_sock_own_cert(ScrNetSocket *s, size_t *len) { + ScrTlsSock *t = scr_tls_sock_of(s); + if (t != NULL && t->cli != NULL && t->cli->has_own) { + *len = t->cli->own.raw.len; + return t->cli->own.raw.p; + } + if (t == NULL || t->srv == NULL) return NULL; + const mbedtls_x509_crt *c = t->sni_ctx != NULL ? &t->sni_ctx->cert + : t->srv->ctx != NULL ? &t->srv->ctx->cert + : &t->srv->cert; + if (c->raw.len == 0) return NULL; + *len = c->raw.len; + return c->raw.p; +} + +/* Visits the trust anchors the socket verified its peer against (its + * `ca`, or the default store) until `visit` answers true. */ +void scr_tls_sock_each_trusted(ScrNetSocket *s, bool (*visit)(void *ctx, const uint8_t *der, size_t len), + void *ctx) { + ScrTlsSock *t = scr_tls_sock_of(s); + if (t == NULL || (t->cli == NULL && t->srv == NULL)) return; + const mbedtls_x509_crt *c = t->cli != NULL ? (t->cli->ca.raw.len > 0 ? &t->cli->ca : scr_tls_system_ca()) + : t->srv->has_ca ? &t->srv->ca + : scr_tls_system_ca(); + for (; c != NULL && c->raw.len > 0; c = c->next) + if (visit(ctx, c->raw.p, c->raw.len)) return; +} + +static ScrBytes *scr_tls_der_buffer(const uint8_t *der, size_t len) { + ScrBytes *b = scr_bytes_new(SCR_BYTES_U8, (double)len); + b->is_buffer = true; + if (len) memcpy(b->data, der, len); + return b; +} + +/* getPeerX509Certificate() and getX509Certificate(): the certificate's + * DER (+1 Buffer), empty when there is none (undefined in Node). */ +ScrBytes *scr_tls_sock_peer_cert_der(ScrNetSocket *s) { + const uint8_t *der; + size_t len; + if (!scr_tls_sock_has_handle(s) || scr_tls_sock_peer_chain(s, &der, &len, 1) == 0) + return scr_tls_der_buffer(NULL, 0); + return scr_tls_der_buffer(der, len); +} + +ScrBytes *scr_tls_sock_own_cert_der(ScrNetSocket *s) { + size_t len = 0; + const uint8_t *der = scr_tls_sock_has_handle(s) ? scr_tls_sock_own_cert(s, &len) : NULL; + return scr_tls_der_buffer(der, der ? len : 0); +} + /* tlsSocket.getProtocol(): the negotiated version ("TLSv1.2", * "TLSv1.3"); before the handshake the highest version on offer, as * OpenSSL answers, and null after close. +1. */ diff --git a/packages/runtime/src/scr_tls.h b/packages/runtime/src/scr_tls.h index cc8e3336e..94bf41d33 100644 --- a/packages/runtime/src/scr_tls.h +++ b/packages/runtime/src/scr_tls.h @@ -58,6 +58,19 @@ ScrNetSocket *scr_tls_connect_dyn(double port, ScrStr *host /*borrowed, nullable bool scr_tls_sock_authorized(ScrNetSocket *s); ScrStr *scr_tls_sock_auth_error(ScrNetSocket *s); /* +1 or NULL */ ScrDyn *scr_tls_sock_get_protocol(ScrNetSocket *s); /* +1: string or null */ +/* The certificates behind getPeerCertificate, getCertificate and their + * X509Certificate forms (scr_tls_x509.c reads them). */ +bool scr_tls_sock_has_handle(ScrNetSocket *s); +size_t scr_tls_sock_peer_chain(ScrNetSocket *s, const uint8_t **der, size_t *len, size_t max); +const uint8_t *scr_tls_sock_own_cert(ScrNetSocket *s, size_t *len); +void scr_tls_sock_each_trusted(ScrNetSocket *s, bool (*visit)(void *ctx, const uint8_t *der, size_t len), + void *ctx); +ScrBytes *scr_tls_sock_peer_cert_der(ScrNetSocket *s); /* +1 Buffer, empty for none */ +ScrBytes *scr_tls_sock_own_cert_der(ScrNetSocket *s); /* +1 Buffer, empty for none */ +/* scr_tls_x509.c: getPeerCertificate([detailed]) and getCertificate(), +1 + * (an object, {} or null). */ +ScrDyn *scr_tls_sock_get_peer_certificate(ScrNetSocket *s, const ScrDyn *detailed); +ScrDyn *scr_tls_sock_get_certificate(ScrNetSocket *s); ScrDyn *scr_tls_sock_get_cipher(ScrNetSocket *s); /* +1: object, undefined or null */ ScrDyn *scr_tls_sock_alpn_protocol(ScrNetSocket *s); /* +1: string, false or null */ void scr_tls_sock_on_secure_connect(ScrNetSocket *s, ScrClosure *cb /*moves*/, bool once); @@ -97,6 +110,12 @@ ScrSecureCtx *scr_tls_create_secure_context(const char *cert, size_t cert_len, c * validations first, then the pem walk (+1, or NULL with the exception * pending). Borrowed. */ ScrSecureCtx *scr_tls_create_secure_context_dyn(const ScrDyn *opts); +/* server.addContext(servername, context) (a SecureContext, or options when + * NULL) and server.setSecureContext(options) on a tls or https server; + * Node's errors pending on failure. */ +void scr_tls_server_add_context(ScrNetServer *server, const ScrDyn *servername, + const ScrDyn *options /*nullable*/, ScrSecureCtx *ctx /*nullable*/); +void scr_tls_server_set_secure_context(ScrNetServer *server, const ScrDyn *options); /* new tls.TLSSocket(socket, options) in server mode: a fresh TLS socket * takes over socket's connection and runs the server handshake, serving * ctx (options.secureContext; borrowed, nullable) or the options record's diff --git a/packages/runtime/src/scr_tls_x509.c b/packages/runtime/src/scr_tls_x509.c new file mode 100644 index 000000000..d1dfd819b --- /dev/null +++ b/packages/runtime/src/scr_tls_x509.c @@ -0,0 +1,119 @@ +/* tlsSocket.getPeerCertificate([detailed]) and getCertificate(): Node's + * legacy certificate objects, built by scr_x509.c's toLegacyObject over + * the certificates scr_tls.c keeps. Linked into programs that use both + * units, so neither unit depends on the other. */ +#include "scr_runtime.h" + +#include +#include + +/* The peer chain entries read; a longer chain is cut, as no real chain is + * this long. */ +enum { SCR_TLS_X509_MAX_CHAIN = 16 }; + +static ScrBytes *scr_tls_x509_bytes(const uint8_t *der, size_t len) { + ScrBytes *b = scr_bytes_new(SCR_BYTES_U8, (double)len); + if (len) memcpy(b->data, der, len); + return b; +} + +static bool scr_tls_x509_same(const ScrBytes *a, const ScrBytes *b) { + return a->len == b->len && memcmp(a->data, b->data, a->len) == 0; +} + +/* tlsSocket.getCertificate(): the certificate the socket serves, {} + * without one, null once the socket is destroyed. +1. */ +ScrDyn *scr_tls_sock_get_certificate(ScrNetSocket *s) { + if (!scr_tls_sock_has_handle(s)) return scr_dyn_new_null(); + size_t len = 0; + const uint8_t *der = scr_tls_sock_own_cert(s, &len); + if (der == NULL) return scr_dyn_new_obj(); + ScrBytes *cert = scr_tls_x509_bytes(der, len); + ScrDyn *result = scr_crypto_x509_legacy_object(cert); + scr_bytes_release(cert); + return result; +} + +typedef struct { + ScrBytes *subject; /* borrowed */ + ScrBytes *found; /* +1, NULL until found */ +} ScrTlsX509Lookup; + +/* SSL_CTX_get_issuer: the first trust anchor that issued the subject. */ +static bool scr_tls_x509_issuer_visit(void *ctx, const uint8_t *der, size_t len) { + ScrTlsX509Lookup *lookup = ctx; + ScrBytes *candidate = scr_tls_x509_bytes(der, len); + if (scr_crypto_x509_check_issued(lookup->subject, candidate)) { + lookup->found = candidate; + return true; + } + scr_bytes_release(candidate); + return false; +} + +/* Sets `chain`'s issuerCertificate to the legacy object of `issuer` + * (borrowed) and answers that object (borrowed; `chain` holds it). */ +static ScrDyn *scr_tls_x509_link(ScrDyn *chain, ScrBytes *issuer) { + ScrDyn *object = scr_crypto_x509_legacy_object(issuer); + scr_dyn_obj_set(chain, "issuerCertificate", 17, object); + return object; +} + +/* tlsSocket.getPeerCertificate([detailed]): the peer's certificate, {} + * before the handshake or without one, null once the socket is destroyed. + * With `detailed`, issuerCertificate links each certificate to its issuer + * as Node's GetPeerCert does: first from the certificates the peer sent, + * in their order of issue, then from the trust anchors; a self-issued + * last certificate is its own issuerCertificate. +1. */ +ScrDyn *scr_tls_sock_get_peer_certificate(ScrNetSocket *s, const ScrDyn *detailed_arg) { + /* Node reads the argument with IsTrue(): only true itself. */ + bool detailed = detailed_arg->kind == SCR_DYN_BOOL && detailed_arg->v.b; + if (!scr_tls_sock_has_handle(s)) return scr_dyn_new_null(); + const uint8_t *der[SCR_TLS_X509_MAX_CHAIN]; + size_t len[SCR_TLS_X509_MAX_CHAIN]; + size_t n = scr_tls_sock_peer_chain(s, der, len, SCR_TLS_X509_MAX_CHAIN); + if (n == 0) return scr_dyn_new_obj(); + ScrBytes *cert = scr_tls_x509_bytes(der[0], len[0]); + ScrDyn *result = scr_crypto_x509_legacy_object(cert); + if (!detailed) { + scr_bytes_release(cert); + return result; + } + ScrBytes *pool[SCR_TLS_X509_MAX_CHAIN]; + size_t pooled = 0; + for (size_t i = 1; i < n; i++) pool[pooled++] = scr_tls_x509_bytes(der[i], len[i]); + ScrDyn *chain = result; + /* AddIssuerChainToObject: take the issuer out of the peer's list, and + * stop when none issued the current certificate or the issuer taken was + * the list's last entry. */ + for (;;) { + size_t i; + for (i = 0; i < pooled; i++) { + if (!scr_crypto_x509_check_issued(cert, pool[i])) continue; + chain = scr_tls_x509_link(chain, pool[i]); + scr_bytes_release(cert); + cert = pool[i]; + memmove(pool + i, pool + i + 1, (pooled - i - 1) * sizeof pool[0]); + pooled--; + break; + } + if (i == pooled) break; + } + for (size_t i = 0; i < pooled; i++) scr_bytes_release(pool[i]); + /* GetLastIssuedCert: then the trust anchors, until a self-issued one + * (bounded, for anchors that issued each other). */ + for (size_t step = 0; step < SCR_TLS_X509_MAX_CHAIN && !scr_crypto_x509_check_issued(cert, cert); step++) { + ScrTlsX509Lookup lookup = {cert, NULL}; + scr_tls_sock_each_trusted(s, scr_tls_x509_issuer_visit, &lookup); + if (lookup.found == NULL) break; + chain = scr_tls_x509_link(chain, lookup.found); + bool same = scr_tls_x509_same(cert, lookup.found); + scr_bytes_release(cert); + cert = lookup.found; + if (same) break; + } + if (scr_crypto_x509_check_issued(cert, cert)) + scr_dyn_obj_set(chain, "issuerCertificate", 17, scr_dyn_retain(chain)); + scr_bytes_release(cert); + return result; +} diff --git a/packages/runtime/src/scr_x509.c b/packages/runtime/src/scr_x509.c new file mode 100644 index 000000000..7b853d68a --- /dev/null +++ b/packages/runtime/src/scr_x509.c @@ -0,0 +1,1820 @@ +/* X509Certificate fields (raw, subject, issuer, subjectAltName, + * infoAccess, serialNumber, fingerprint256, fingerprint512, ca, + * signatureAlgorithm, signatureAlgorithmOid), linked only into programs + * that read them (the x509 runtime feature). */ +#include "scr_runtime.h" + +#include +#include +#include + +/* Copies of scr_lib.c's PEM front half and DER header reader for the + * X509Certificate members it keeps, so that unit is unchanged for + * programs that do not read these fields. */ + +/* PEM armor → DER (or raw-DER passthrough), the shared front half of + * every X509Certificate member. On success `*der`/`*der_len` hold the + * certificate bytes and `*decoded` the malloc'd base64 buffer to free + * (NULL for raw-DER input); unparseable input throws Node's exact PEM + * error and answers false with the exception pending. */ +static bool scr_x509_der(const uint8_t *in, size_t n, const uint8_t **der, size_t *der_len, + uint8_t **decoded) { + static const char begin[] = "-----BEGIN CERTIFICATE-----"; + static const char end[] = "-----END CERTIFICATE-----"; + *der = NULL; + *der_len = 0; + *decoded = NULL; + /* PEM: base64-decode the armor's body. */ + const uint8_t *b = NULL; + /* OpenSSL's PEM reader looks for the armor at the start of a line. */ + for (size_t i = 0; i + sizeof begin - 1 <= n; i++) { + if ((i == 0 || in[i - 1] == '\n') && memcmp(in + i, begin, sizeof begin - 1) == 0) { + b = in + i + sizeof begin - 1; + break; + } + } + if (b != NULL) { + const uint8_t *stop = in + n; + for (const uint8_t *p = b; p + sizeof end - 1 <= in + n; p++) { + if (memcmp(p, end, sizeof end - 1) == 0) { + stop = p; + break; + } + } + uint8_t *out = malloc(((size_t)(stop - b) / 4 + 1) * 3 + 3); + if (!out) { + scr_trap("scriptc: out of memory\n"); + } + size_t o = 0; + unsigned acc = 0; + int have = 0; + for (const uint8_t *p = b; p < stop; p++) { + int v; + uint8_t c = *p; + if (c >= 'A' && c <= 'Z') v = c - 'A'; + else if (c >= 'a' && c <= 'z') v = c - 'a' + 26; + else if (c >= '0' && c <= '9') v = c - '0' + 52; + else if (c == '+') v = 62; + else if (c == '/') v = 63; + else continue; /* whitespace, '=' */ + acc = (acc << 6) | (unsigned)v; + if (++have == 4) { + out[o++] = (uint8_t)(acc >> 16); + out[o++] = (uint8_t)(acc >> 8); + out[o++] = (uint8_t)acc; + acc = 0; + have = 0; + } + } + if (have == 2) out[o++] = (uint8_t)(acc >> 4); + else if (have == 3) { + out[o++] = (uint8_t)(acc >> 10); + out[o++] = (uint8_t)(acc >> 2); + } + *decoded = out; + *der = out; + *der_len = o; + return true; + } + if (n > 0 && in[0] == 0x30) { + /* Raw DER: the certificate SEQUENCE, without bytes after it, as + * d2i_X509 reads it. */ + *der = in; + *der_len = n; + if (n >= 2) { + size_t len = in[1], head = 2; + if (len & 0x80) { + size_t k = len & 0x7f; + len = 0; + head = 2 + k; + for (size_t i = 0; i < k && k <= 4 && head <= n; i++) len = (len << 8) | in[2 + i]; + if (k == 0 || k > 4) head = n + 1; + } + if (head <= n && len <= n - head) *der_len = head + len; + } + return true; + } + scr_throw_error_msg_code(SCR_ERR_ERROR, + "error:0480006C:PEM routines::no start line", + 42, "ERR_OSSL_PEM_NO_START_LINE"); + return false; /* exception pending */ +} + +/* Reads one DER TL header at p (before end): tag to *tag, content length + * to *len, and answers the content pointer (NULL on malformed/overlong). */ +static const uint8_t *scr_der_tl(const uint8_t *p, const uint8_t *end, uint8_t *tag, size_t *len) { + if (p == NULL || end - p < 2) return NULL; + *tag = p[0]; + uint8_t l0 = p[1]; + const uint8_t *content = p + 2; + size_t l; + if (l0 < 0x80) { + l = l0; + } else { + size_t nb = l0 & 0x7f; + if (nb == 0 || nb > sizeof(size_t) || end - content < (ptrdiff_t)nb) return NULL; + l = 0; + for (size_t i = 0; i < nb; i++) l = (l << 8) | content[i]; + content += nb; + } + if ((size_t)(end - content) < l) return NULL; + *tag = p[0]; + *len = l; + return content; +} + +/* ── X509Certificate fields over the DER ───────────────────────────────── + * + * `raw` decodes the constructor's input once (scr_x509_der); every other + * field reads those DER bytes. The walks follow RFC 5280's Certificate ::= + * SEQUENCE { tbsCertificate, signatureAlgorithm, signatureValue } and + * render each value as Node does: names through X509_NAME_print_ex (one + * attribute per line, RFC 2253 escaping), alternative names and access + * descriptions through Node's PrintGeneralName, the serial number through + * BN_bn2hex. A field whose part of the certificate is missing or malformed + * answers Node's value for an absent part. */ + +typedef struct { + char *data; + size_t len, cap; +} ScrX509Buf; + +static void scr_x509_put(ScrX509Buf *b, const void *p, size_t n) { + if (b->len + n > b->cap) { + size_t cap = b->cap ? b->cap * 2 : 128; + while (cap < b->len + n) cap *= 2; + char *grown = realloc(b->data, cap); + if (!grown) scr_trap("scriptc: out of memory\n"); + b->data = grown; + b->cap = cap; + } + memcpy(b->data + b->len, p, n); + b->len += n; +} + +static void scr_x509_puts(ScrX509Buf *b, const char *s) { scr_x509_put(b, s, strlen(s)); } + +static void scr_x509_putc(ScrX509Buf *b, char c) { scr_x509_put(b, &c, 1); } + +static ScrStr *scr_x509_buf_str(ScrX509Buf *b) { + ScrStr *s = scr_str_new(b->data ? b->data : "", b->len); + free(b->data); + return s; +} + +/* The DER of a certificate field's input (raw or the bytes constructor + * input). */ +#define SCR_X509_DER(bytes) \ + ((const uint8_t *)(bytes)->data), ((bytes)->len * scr_bytes_elem_size((bytes)->elem)) + +typedef struct { + const uint8_t *tbs, *tbs_end; /* tbsCertificate contents */ + const uint8_t *sig_alg; /* outer signatureAlgorithm contents */ + size_t sig_alg_len; + const uint8_t *serial; /* serialNumber contents */ + size_t serial_len; + const uint8_t *issuer, *subject; /* Name contents */ + size_t issuer_len, subject_len; + const uint8_t *validity; /* Validity contents */ + size_t validity_len; + const uint8_t *exts; /* Extensions SEQUENCE contents, or NULL */ + size_t exts_len; + const uint8_t *spki; /* SubjectPublicKeyInfo contents, or NULL */ + size_t spki_len; + const uint8_t *spki_tlv; /* the whole SubjectPublicKeyInfo DER */ + size_t spki_tlv_len; +} ScrX509Parts; + +/* Splits the certificate into the parts the fields read; false when the + * outer structure does not parse. */ +static bool scr_x509_parts(const uint8_t *der, size_t n, ScrX509Parts *out) { + memset(out, 0, sizeof *out); + const uint8_t *end = der + n; + uint8_t tag; + size_t len; + const uint8_t *cert = scr_der_tl(der, end, &tag, &len); + if (!cert || tag != 0x30) return false; + const uint8_t *cert_end = cert + len; + const uint8_t *tbs = scr_der_tl(cert, cert_end, &tag, &len); + if (!tbs || tag != 0x30) return false; + out->tbs = tbs; + out->tbs_end = tbs + len; + const uint8_t *alg = scr_der_tl(tbs + len, cert_end, &tag, &len); + if (alg && tag == 0x30) { + out->sig_alg = alg; + out->sig_alg_len = len; + } + const uint8_t *p = tbs; + const uint8_t *c = scr_der_tl(p, out->tbs_end, &tag, &len); + if (c && tag == 0xA0) { /* [0] version */ + p = c + len; + c = scr_der_tl(p, out->tbs_end, &tag, &len); + } + if (!c || tag != 0x02) return true; + out->serial = c; + out->serial_len = len; + p = c + len; + /* signature AlgorithmIdentifier */ + c = scr_der_tl(p, out->tbs_end, &tag, &len); + if (!c) return true; + p = c + len; + c = scr_der_tl(p, out->tbs_end, &tag, &len); + if (!c || tag != 0x30) return true; + out->issuer = c; + out->issuer_len = len; + p = c + len; + c = scr_der_tl(p, out->tbs_end, &tag, &len); + if (!c || tag != 0x30) return true; + out->validity = c; + out->validity_len = len; + p = c + len; + c = scr_der_tl(p, out->tbs_end, &tag, &len); + if (!c || tag != 0x30) return true; + out->subject = c; + out->subject_len = len; + p = c + len; + c = scr_der_tl(p, out->tbs_end, &tag, &len); + if (c && tag == 0x30) { + out->spki = c; + out->spki_len = len; + out->spki_tlv = p; + out->spki_tlv_len = (size_t)(c + len - p); + } + /* subjectPublicKeyInfo, then the optional [1] [2] unique IDs and [3] + * extensions */ + while (p < out->tbs_end) { + c = scr_der_tl(p, out->tbs_end, &tag, &len); + if (!c) break; + if (tag == 0xA3) { + const uint8_t *seq = scr_der_tl(c, c + len, &tag, &len); + if (seq && tag == 0x30) { + out->exts = seq; + out->exts_len = len; + } + break; + } + p = c + len; + } + return true; +} + +/* Finds the extension with the DER-encoded OID `oid` (contents only): + * its extnValue contents, or NULL. */ +static const uint8_t *scr_x509_ext(const ScrX509Parts *parts, const uint8_t *oid, size_t oid_len, + size_t *value_len) { + if (!parts->exts) return NULL; + const uint8_t *p = parts->exts; + const uint8_t *end = parts->exts + parts->exts_len; + uint8_t tag; + size_t len; + while (p < end) { + const uint8_t *ext = scr_der_tl(p, end, &tag, &len); + if (!ext || tag != 0x30) return NULL; + const uint8_t *ext_end = ext + len; + p = ext_end; + const uint8_t *id = scr_der_tl(ext, ext_end, &tag, &len); + if (!id || tag != 0x06) continue; + bool match = len == oid_len && memcmp(id, oid, len) == 0; + const uint8_t *q = id + len; + const uint8_t *v = scr_der_tl(q, ext_end, &tag, &len); + if (v && tag == 0x01) { /* critical */ + q = v + len; + v = scr_der_tl(q, ext_end, &tag, &len); + } + if (match && v && tag == 0x04) { + *value_len = len; + return v; + } + } + return NULL; +} + +/* An OID's dotted text (OBJ_obj2txt with no_name). */ +static void scr_x509_oid_dotted(ScrX509Buf *b, const uint8_t *oid, size_t n) { + char tmp[24]; + uint64_t v = 0; + bool first = true; + for (size_t i = 0; i < n; i++) { + v = (v << 7) | (oid[i] & 0x7f); + if (oid[i] & 0x80) continue; + if (first) { + unsigned top = v < 40 ? 0 : v < 80 ? 1 : 2; + snprintf(tmp, sizeof tmp, "%u.%llu", top, (unsigned long long)(v - top * 40)); + first = false; + } else { + snprintf(tmp, sizeof tmp, ".%llu", (unsigned long long)v); + } + scr_x509_puts(b, tmp); + v = 0; + } +} + +typedef struct { + const char *oid; /* dotted */ + const char *name; +} ScrX509OidName; + +/* OpenSSL's short names for the attribute types names use (XN_FLAG_FN_SN). */ +static const ScrX509OidName scr_x509_attr_names[] = { + {"2.5.4.3", "CN"}, + {"2.5.4.4", "SN"}, + {"2.5.4.5", "serialNumber"}, + {"2.5.4.6", "C"}, + {"2.5.4.7", "L"}, + {"2.5.4.8", "ST"}, + {"2.5.4.9", "street"}, + {"2.5.4.10", "O"}, + {"2.5.4.11", "OU"}, + {"2.5.4.12", "title"}, + {"2.5.4.13", "description"}, + {"2.5.4.15", "businessCategory"}, + {"2.5.4.16", "postalAddress"}, + {"2.5.4.17", "postalCode"}, + {"2.5.4.18", "postOfficeBox"}, + {"2.5.4.20", "telephoneNumber"}, + {"2.5.4.41", "name"}, + {"2.5.4.42", "GN"}, + {"2.5.4.43", "initials"}, + {"2.5.4.44", "generationQualifier"}, + {"2.5.4.45", "x500UniqueIdentifier"}, + {"2.5.4.46", "dnQualifier"}, + {"2.5.4.65", "pseudonym"}, + {"2.5.4.72", "role"}, + {"2.5.4.97", "organizationIdentifier"}, + {"1.2.840.113549.1.9.1", "emailAddress"}, + {"1.2.840.113549.1.9.2", "unstructuredName"}, + {"0.9.2342.19200300.100.1.1", "UID"}, + {"0.9.2342.19200300.100.1.25", "DC"}, + {"1.3.6.1.4.1.311.60.2.1.1", "jurisdictionL"}, + {"1.3.6.1.4.1.311.60.2.1.2", "jurisdictionST"}, + {"1.3.6.1.4.1.311.60.2.1.3", "jurisdictionC"}, +}; + +/* OpenSSL's long names for the signature algorithms certificates use. */ +static const ScrX509OidName scr_x509_sig_names[] = { + {"1.2.840.113549.1.1.4", "md5WithRSAEncryption"}, + {"1.2.840.113549.1.1.5", "sha1WithRSAEncryption"}, + {"1.2.840.113549.1.1.10", "rsassaPss"}, + {"1.2.840.113549.1.1.11", "sha256WithRSAEncryption"}, + {"1.2.840.113549.1.1.12", "sha384WithRSAEncryption"}, + {"1.2.840.113549.1.1.13", "sha512WithRSAEncryption"}, + {"1.2.840.113549.1.1.14", "sha224WithRSAEncryption"}, + {"1.2.840.10045.4.1", "ecdsa-with-SHA1"}, + {"1.2.840.10045.4.3.1", "ecdsa-with-SHA224"}, + {"1.2.840.10045.4.3.2", "ecdsa-with-SHA256"}, + {"1.2.840.10045.4.3.3", "ecdsa-with-SHA384"}, + {"1.2.840.10045.4.3.4", "ecdsa-with-SHA512"}, + {"1.2.840.10040.4.3", "dsaWithSHA1"}, + {"2.16.840.1.101.3.4.3.1", "dsa_with_SHA224"}, + {"2.16.840.1.101.3.4.3.2", "dsa_with_SHA256"}, + {"1.3.101.112", "ED25519"}, + {"1.3.101.113", "ED448"}, +}; + +/* OpenSSL's long names for the access methods infoAccess prints. */ +static const ScrX509OidName scr_x509_access_names[] = { + {"1.3.6.1.5.5.7.48.1", "OCSP"}, + {"1.3.6.1.5.5.7.48.2", "CA Issuers"}, + {"1.3.6.1.5.5.7.48.3", "AD Time Stamping"}, + {"1.3.6.1.5.5.7.48.5", "CA Repository"}, +}; + +/* Appends the table name of an OID, or its dotted text; answers whether + * the table named it. */ +static bool scr_x509_oid_name(ScrX509Buf *b, const uint8_t *oid, size_t n, + const ScrX509OidName *table, size_t count) { + ScrX509Buf dotted = {0}; + scr_x509_oid_dotted(&dotted, oid, n); + for (size_t i = 0; i < count; i++) { + if (strlen(table[i].oid) == dotted.len && memcmp(table[i].oid, dotted.data, dotted.len) == 0) { + scr_x509_puts(b, table[i].name); + free(dotted.data); + return true; + } + } + scr_x509_put(b, dotted.data, dotted.len); + free(dotted.data); + return false; +} + +/* Appends one code point as UTF-8. */ +static void scr_x509_put_utf8(ScrX509Buf *b, uint32_t c) { + char u[4]; + size_t n; + if (c < 0x80) { + u[0] = (char)c; + n = 1; + } else if (c < 0x800) { + u[0] = (char)(0xC0 | (c >> 6)); + u[1] = (char)(0x80 | (c & 0x3F)); + n = 2; + } else if (c < 0x10000) { + u[0] = (char)(0xE0 | (c >> 12)); + u[1] = (char)(0x80 | ((c >> 6) & 0x3F)); + u[2] = (char)(0x80 | (c & 0x3F)); + n = 3; + } else { + u[0] = (char)(0xF0 | (c >> 18)); + u[1] = (char)(0x80 | ((c >> 12) & 0x3F)); + u[2] = (char)(0x80 | ((c >> 6) & 0x3F)); + u[3] = (char)(0x80 | (c & 0x3F)); + n = 4; + } + scr_x509_put(b, u, n); +} + +/* An attribute value as UTF-8 bytes (ASN1_STRFLGS_UTF8_CONVERT): a + * UTF8String as stored, BMPString and UniversalString decoded, every other + * type read as Latin-1. */ +static void scr_x509_value_utf8(ScrX509Buf *out, uint8_t tag, const uint8_t *v, size_t n) { + if (tag == 0x0C) { + scr_x509_put(out, v, n); + } else if (tag == 0x1E) { + for (size_t i = 0; i + 1 < n; i += 2) scr_x509_put_utf8(out, ((uint32_t)v[i] << 8) | v[i + 1]); + } else if (tag == 0x1C) { + for (size_t i = 0; i + 3 < n; i += 4) + scr_x509_put_utf8(out, ((uint32_t)v[i] << 24) | ((uint32_t)v[i + 1] << 16) | + ((uint32_t)v[i + 2] << 8) | v[i + 3]); + } else { + for (size_t i = 0; i < n; i++) scr_x509_put_utf8(out, v[i]); + } +} + +/* Appends a value with ASN1_STRFLGS_ESC_2253 escaping: the characters + * `"+,;<>\` get a backslash, as do a leading '#' or space and a trailing + * space; with `esc_ctrl`, control characters print as \XX. Bytes above + * 0x7f pass through. */ +static void scr_x509_put_escaped(ScrX509Buf *b, const uint8_t *s, size_t n, bool esc_ctrl) { + static const char hex[] = "0123456789ABCDEF"; + for (size_t i = 0; i < n; i++) { + uint8_t c = s[i]; + bool first = i == 0; + bool last = i + 1 == n; + if (c == '"' || c == '+' || c == ',' || c == ';' || c == '<' || c == '>' || c == '\\' || + (first && (c == '#' || c == ' ')) || (last && c == ' ')) { + scr_x509_putc(b, '\\'); + scr_x509_putc(b, (char)c); + } else if (esc_ctrl && (c < 0x20 || c == 0x7f)) { + char e[3] = {'\\', hex[c >> 4], hex[c & 0x0f]}; + scr_x509_put(b, e, 3); + } else { + scr_x509_putc(b, (char)c); + } + } +} + +/* Prints a Name. `multiline` is Node's subject/issuer form (attributes in + * order, one RDN per line, ESC_CTRL); otherwise the RFC 2253 form DirName + * alternative names use (RDNs reversed and comma-separated, unknown + * attribute types dumped as #hex of the value's DER). RDNs with several + * attributes join them with " + " or "+". */ +static void scr_x509_name_print(ScrX509Buf *b, const uint8_t *name, size_t n, bool multiline) { + const uint8_t *end = name + n; + const uint8_t *rdns[64]; + size_t rdn_lens[64]; + size_t count = 0; + uint8_t tag; + size_t len; + for (const uint8_t *p = name; p < end && count < 64;) { + const uint8_t *set = scr_der_tl(p, end, &tag, &len); + if (!set || tag != 0x31) break; + rdns[count] = set; + rdn_lens[count++] = len; + p = set + len; + } + for (size_t k = 0; k < count; k++) { + size_t r = multiline ? k : count - 1 - k; + if (k > 0) scr_x509_puts(b, multiline ? "\n" : ","); + const uint8_t *set_end = rdns[r] + rdn_lens[r]; + bool first_attr = true; + for (const uint8_t *q = rdns[r]; q < set_end;) { + const uint8_t *atv = scr_der_tl(q, set_end, &tag, &len); + if (!atv || tag != 0x30) break; + const uint8_t *atv_end = atv + len; + q = atv_end; + const uint8_t *oid = scr_der_tl(atv, atv_end, &tag, &len); + if (!oid || tag != 0x06) continue; + size_t oid_len = len; + const uint8_t *value_tl = oid + len; + uint8_t vtag; + size_t vlen; + const uint8_t *value = scr_der_tl(value_tl, atv_end, &vtag, &vlen); + if (!value) continue; + if (!first_attr) scr_x509_puts(b, multiline ? " + " : "+"); + first_attr = false; + bool known = scr_x509_oid_name(b, oid, oid_len, scr_x509_attr_names, + sizeof scr_x509_attr_names / sizeof scr_x509_attr_names[0]); + scr_x509_putc(b, '='); + if (!multiline && !known) { + static const char hex[] = "0123456789ABCDEF"; + scr_x509_putc(b, '#'); + for (const uint8_t *d = value_tl; d < value + vlen; d++) { + scr_x509_putc(b, hex[*d >> 4]); + scr_x509_putc(b, hex[*d & 0x0f]); + } + continue; + } + ScrX509Buf text = {0}; + scr_x509_value_utf8(&text, vtag, value, vlen); + scr_x509_put_escaped(b, (const uint8_t *)text.data, text.len, multiline); + free(text.data); + } + } +} + +/* Node's PrintAltName: a name with none of `"\,'` and only printable + * characters (in UTF-8 names, only non-control bytes) prints as is; + * otherwise it prints as a JSON string, `prefix:` inside the quotes, with + * `\\`, `\"` and \u00XX for commas, control characters and (outside + * UTF-8 names) bytes above 0x7e. */ +static void scr_x509_put_alt_name(ScrX509Buf *b, const uint8_t *s, size_t n, bool utf8, + const char *prefix) { + bool safe = true; + for (size_t i = 0; i < n && safe; i++) { + uint8_t c = s[i]; + if (c == '"' || c == '\\' || c == ',' || c == '\'') safe = false; + else if (utf8 ? (c < ' ' || c == 0x7f) : (c < ' ' || c > '~')) safe = false; + } + if (safe) { + if (prefix) { + scr_x509_puts(b, prefix); + scr_x509_putc(b, ':'); + } + scr_x509_put(b, s, n); + return; + } + static const char hex[] = "0123456789abcdef"; + scr_x509_putc(b, '"'); + if (prefix) { + scr_x509_puts(b, prefix); + scr_x509_putc(b, ':'); + } + for (size_t i = 0; i < n; i++) { + uint8_t c = s[i]; + if (c == '\\') { + scr_x509_puts(b, "\\\\"); + } else if (c == '"') { + scr_x509_puts(b, "\\\""); + } else if ((c >= ' ' && c != ',' && c <= '~') || (utf8 && (c & 0x80))) { + scr_x509_putc(b, (char)c); + } else { + char u[6] = {'\\', 'u', '0', '0', hex[c >> 4], hex[c & 0x0f]}; + scr_x509_put(b, u, 6); + } + } + scr_x509_putc(b, '"'); +} + +static const uint8_t SCR_X509_OID_UPN[] = {0x2B, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x14, 0x02, 0x03}; +static const uint8_t SCR_X509_OID_XMPP[] = {0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x08, 0x05}; +static const uint8_t SCR_X509_OID_SRV[] = {0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x08, 0x07}; +static const uint8_t SCR_X509_OID_NAI[] = {0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x08, 0x08}; +static const uint8_t SCR_X509_OID_SMTP_UTF8[] = {0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x08, 0x09}; + +/* Node's PrintGeneralName for one GeneralName element (tag and contents). */ +static void scr_x509_general_name(ScrX509Buf *b, uint8_t tag, const uint8_t *v, size_t n) { + switch (tag) { + case 0x81: /* rfc822Name */ + scr_x509_puts(b, "email:"); + scr_x509_put_alt_name(b, v, n, false, NULL); + return; + case 0x82: /* dNSName */ + scr_x509_puts(b, "DNS:"); + scr_x509_put_alt_name(b, v, n, false, NULL); + return; + case 0x86: /* uniformResourceIdentifier */ + scr_x509_puts(b, "URI:"); + scr_x509_put_alt_name(b, v, n, false, NULL); + return; + case 0x87: { /* iPAddress */ + char tmp[48]; + scr_x509_puts(b, "IP Address:"); + if (n == 4) { + snprintf(tmp, sizeof tmp, "%d.%d.%d.%d", v[0], v[1], v[2], v[3]); + scr_x509_puts(b, tmp); + } else if (n == 16) { + for (unsigned j = 0; j < 8; j++) { + snprintf(tmp, sizeof tmp, j == 0 ? "%X" : ":%X", (unsigned)((v[2 * j] << 8) | v[2 * j + 1])); + scr_x509_puts(b, tmp); + } + } else { + snprintf(tmp, sizeof tmp, "", n); + scr_x509_puts(b, tmp); + } + return; + } + case 0x88: /* registeredID */ + scr_x509_puts(b, "Registered ID:"); + scr_x509_oid_dotted(b, v, n); + return; + case 0xA4: { /* directoryName: [4] EXPLICIT Name */ + uint8_t ntag; + size_t nlen; + const uint8_t *name = scr_der_tl(v, v + n, &ntag, &nlen); + ScrX509Buf text = {0}; + if (name && ntag == 0x30) scr_x509_name_print(&text, name, nlen, false); + scr_x509_puts(b, "DirName:"); + scr_x509_put_alt_name(b, (const uint8_t *)(text.data ? text.data : ""), text.len, true, NULL); + free(text.data); + return; + } + case 0xA0: { /* otherName: type-id OID, [0] EXPLICIT value */ + uint8_t t; + size_t len; + const uint8_t *end = v + n; + const uint8_t *oid = scr_der_tl(v, end, &t, &len); + const char *prefix = NULL; + bool unicode = true; + if (oid && t == 0x06) { +#define SCR_X509_OID_IS(o) (len == sizeof(o) && memcmp(oid, (o), sizeof(o)) == 0) + if (SCR_X509_OID_IS(SCR_X509_OID_SMTP_UTF8)) prefix = "SmtpUTF8Mailbox"; + else if (SCR_X509_OID_IS(SCR_X509_OID_XMPP)) prefix = "XmppAddr"; + else if (SCR_X509_OID_IS(SCR_X509_OID_SRV)) { + prefix = "SRVName"; + unicode = false; + } else if (SCR_X509_OID_IS(SCR_X509_OID_UPN)) prefix = "UPN"; + else if (SCR_X509_OID_IS(SCR_X509_OID_NAI)) prefix = "NAIRealm"; +#undef SCR_X509_OID_IS + } + const uint8_t *value = NULL; + size_t value_len = 0; + uint8_t vtag = 0; + if (oid && prefix) { + const uint8_t *wrap = scr_der_tl(oid + len, end, &t, &len); + if (wrap && t == 0xA0) value = scr_der_tl(wrap, wrap + len, &vtag, &value_len); + } + if (!value || vtag != (unicode ? 0x0C : 0x16)) { + scr_x509_puts(b, "othername:"); + } else { + scr_x509_puts(b, "othername:"); + scr_x509_put_alt_name(b, value, value_len, unicode, prefix); + } + return; + } + case 0xA3: + scr_x509_puts(b, "X400Name:"); + return; + case 0xA5: + scr_x509_puts(b, "EdiPartyName:"); + return; + default: + return; + } +} + +/* The DER contents of the TBSCertificate parts, or an empty string when + * the certificate does not parse. */ +static ScrStr *scr_x509_name_field(ScrBytes *der, bool subject) { + ScrX509Parts parts; + ScrX509Buf b = {0}; + if (scr_x509_parts(SCR_X509_DER(der), &parts)) { + const uint8_t *name = subject ? parts.subject : parts.issuer; + if (name) scr_x509_name_print(&b, name, subject ? parts.subject_len : parts.issuer_len, true); + } + return scr_x509_buf_str(&b); +} + +/* new X509Certificate(data).raw: the certificate's DER as a fresh Buffer. + * Unparseable input throws Node's PEM error (exception pending, NULL). */ +static ScrBytes *scr_x509_raw(const uint8_t *in, size_t n) { + const uint8_t *der; + size_t der_len; + uint8_t *decoded; + if (!scr_x509_der(in, n, &der, &der_len, &decoded)) return NULL; + ScrBytes *out = scr_buffer_alloc_unsafe_slow((double)der_len); + memcpy(out->data, der, der_len); + free(decoded); + return out; +} + +ScrBytes *scr_crypto_x509_raw(ScrBytes *data) { + SCR_BYTES_SNAPSHOT(data); + return scr_x509_raw(SCR_X509_DER(data)); +} + +/* raw of a certificate whose DER a TLS handshake delivered: a copy, with + * no search for PEM armor that its extensions could carry. */ +ScrBytes *scr_crypto_x509_raw_der(ScrBytes *der) { + SCR_BYTES_SNAPSHOT(der); + size_t n = (size_t)scr_bytes_byte_len(der); + ScrBytes *out = scr_buffer_alloc_unsafe_slow((double)n); + memcpy(out->data, der->data, n); + return out; +} + +ScrBytes *scr_crypto_x509_raw_str(ScrStr *pem) { + return scr_x509_raw((const uint8_t *)pem->data, pem->len); +} + +ScrStr *scr_crypto_x509_subject(ScrBytes *der) { return scr_x509_name_field(der, true); } + +ScrStr *scr_crypto_x509_issuer(ScrBytes *der) { return scr_x509_name_field(der, false); } + +static const uint8_t SCR_X509_OID_SAN[] = {0x55, 0x1D, 0x11}; +static const uint8_t SCR_X509_OID_BASIC_CONSTRAINTS[] = {0x55, 0x1D, 0x13}; +static const uint8_t SCR_X509_OID_KEY_USAGE[] = {0x55, 0x1D, 0x0F}; +static const uint8_t SCR_X509_OID_AIA[] = {0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01}; + +/* subjectAltName: the GeneralNames joined with ", "; an empty string when + * the certificate has no subjectAltName extension (Node's undefined). */ +ScrStr *scr_crypto_x509_subject_alt_name(ScrBytes *der) { + ScrX509Parts parts; + ScrX509Buf b = {0}; + size_t n; + const uint8_t *ext = scr_x509_parts(SCR_X509_DER(der), &parts) + ? scr_x509_ext(&parts, SCR_X509_OID_SAN, sizeof SCR_X509_OID_SAN, &n) + : NULL; + uint8_t tag; + size_t len; + const uint8_t *names = ext ? scr_der_tl(ext, ext + n, &tag, &len) : NULL; + if (names && tag == 0x30) { + const uint8_t *end = names + len; + bool first = true; + for (const uint8_t *p = names; p < end;) { + const uint8_t *v = scr_der_tl(p, end, &tag, &len); + if (!v) break; + if (!first) scr_x509_puts(&b, ", "); + first = false; + scr_x509_general_name(&b, tag, v, len); + p = v + len; + } + } + return scr_x509_buf_str(&b); +} + +/* infoAccess: one " - " line per AccessDescription; + * an empty string when the extension is absent (Node's undefined). */ +ScrStr *scr_crypto_x509_info_access(ScrBytes *der) { + ScrX509Parts parts; + ScrX509Buf b = {0}; + size_t n; + const uint8_t *ext = scr_x509_parts(SCR_X509_DER(der), &parts) + ? scr_x509_ext(&parts, SCR_X509_OID_AIA, sizeof SCR_X509_OID_AIA, &n) + : NULL; + uint8_t tag; + size_t len; + const uint8_t *descs = ext ? scr_der_tl(ext, ext + n, &tag, &len) : NULL; + if (descs && tag == 0x30) { + const uint8_t *end = descs + len; + bool first = true; + for (const uint8_t *p = descs; p < end;) { + const uint8_t *desc = scr_der_tl(p, end, &tag, &len); + if (!desc || tag != 0x30) break; + const uint8_t *desc_end = desc + len; + p = desc_end; + const uint8_t *method = scr_der_tl(desc, desc_end, &tag, &len); + if (!method || tag != 0x06) continue; + if (!first) scr_x509_putc(&b, '\n'); + first = false; + scr_x509_oid_name(&b, method, len, scr_x509_access_names, + sizeof scr_x509_access_names / sizeof scr_x509_access_names[0]); + scr_x509_puts(&b, " - "); + const uint8_t *location = scr_der_tl(method + len, desc_end, &tag, &len); + if (location) scr_x509_general_name(&b, tag, location, len); + } + } + return scr_x509_buf_str(&b); +} + +/* serialNumber: BN_bn2hex of the INTEGER ("0" for zero, whole bytes in + * uppercase hex without leading zero bytes, '-' before a negative). */ +ScrStr *scr_crypto_x509_serial_number(ScrBytes *der) { + ScrX509Parts parts; + ScrX509Buf b = {0}; + if (scr_x509_parts(SCR_X509_DER(der), &parts) && parts.serial_len > 0) { + static const char hex[] = "0123456789ABCDEF"; + size_t n = parts.serial_len; + uint8_t *mag = malloc(n); + if (!mag) scr_trap("scriptc: out of memory\n"); + memcpy(mag, parts.serial, n); + bool neg = (mag[0] & 0x80) != 0; + if (neg) { /* two's complement magnitude */ + for (size_t i = 0; i < n; i++) mag[i] = (uint8_t)~mag[i]; + for (size_t i = n; i-- > 0;) { + if (++mag[i] != 0) break; + } + } + size_t i = 0; + while (i < n && mag[i] == 0) i++; + if (i == n) { + scr_x509_putc(&b, '0'); + } else { + if (neg) scr_x509_putc(&b, '-'); + for (; i < n; i++) { + scr_x509_putc(&b, hex[mag[i] >> 4]); + scr_x509_putc(&b, hex[mag[i] & 0x0f]); + } + } + free(mag); + } + return scr_x509_buf_str(&b); +} + +static ScrStr *scr_x509_fingerprint_alg(ScrBytes *der, const char *alg) { + unsigned char digest[64]; + size_t dn = scr_crypto_digest_raw(alg, SCR_X509_DER(der), digest); + static const char hex[] = "0123456789ABCDEF"; + char buf[192]; + size_t o = 0; + for (size_t i = 0; i < dn; i++) { + if (i > 0) buf[o++] = ':'; + buf[o++] = hex[digest[i] >> 4]; + buf[o++] = hex[digest[i] & 0x0f]; + } + return scr_str_new(buf, o); +} + +ScrStr *scr_crypto_x509_fingerprint256(ScrBytes *der) { + return scr_x509_fingerprint_alg(der, "sha256"); +} + +ScrStr *scr_crypto_x509_fingerprint512(ScrBytes *der) { + return scr_x509_fingerprint_alg(der, "sha512"); +} + +/* ca: X509_check_ca() == 1 — basicConstraints with cA TRUE, and a + * keyUsage extension, when present, that allows keyCertSign. */ +bool scr_crypto_x509_ca(ScrBytes *der) { + ScrX509Parts parts; + if (!scr_x509_parts(SCR_X509_DER(der), &parts)) return false; + uint8_t tag; + size_t len, n; + const uint8_t *ku = scr_x509_ext(&parts, SCR_X509_OID_KEY_USAGE, sizeof SCR_X509_OID_KEY_USAGE, &n); + if (ku) { + const uint8_t *bits = scr_der_tl(ku, ku + n, &tag, &len); + if (!bits || tag != 0x03 || len < 2 || (bits[1] & 0x04) == 0) return false; + } + const uint8_t *bc = scr_x509_ext(&parts, SCR_X509_OID_BASIC_CONSTRAINTS, + sizeof SCR_X509_OID_BASIC_CONSTRAINTS, &n); + if (!bc) return false; + const uint8_t *seq = scr_der_tl(bc, bc + n, &tag, &len); + if (!seq || tag != 0x30) return false; + const uint8_t *flag = scr_der_tl(seq, seq + len, &tag, &len); + return flag && tag == 0x01 && len == 1 && flag[0] != 0; +} + +/* The signature AlgorithmIdentifier's OID contents, or NULL. */ +static const uint8_t *scr_x509_sig_oid(ScrBytes *der, size_t *n) { + ScrX509Parts parts; + if (!scr_x509_parts(SCR_X509_DER(der), &parts) || !parts.sig_alg) return NULL; + uint8_t tag; + const uint8_t *oid = scr_der_tl(parts.sig_alg, parts.sig_alg + parts.sig_alg_len, &tag, n); + return oid && tag == 0x06 ? oid : NULL; +} + +/* signatureAlgorithm: OpenSSL's long name for the signature algorithm; an + * empty string for an algorithm OpenSSL does not name (Node's + * undefined). */ +ScrStr *scr_crypto_x509_signature_algorithm(ScrBytes *der) { + size_t n; + const uint8_t *oid = scr_x509_sig_oid(der, &n); + ScrX509Buf b = {0}; + if (oid && !scr_x509_oid_name(&b, oid, n, scr_x509_sig_names, + sizeof scr_x509_sig_names / sizeof scr_x509_sig_names[0])) + b.len = 0; + return scr_x509_buf_str(&b); +} + +/* signatureAlgorithmOid: the signature algorithm's dotted OID. */ +ScrStr *scr_crypto_x509_signature_algorithm_oid(ScrBytes *der) { + size_t n; + const uint8_t *oid = scr_x509_sig_oid(der, &n); + ScrX509Buf b = {0}; + if (oid) scr_x509_oid_dotted(&b, oid, n); + return scr_x509_buf_str(&b); +} + +/* toString() and toJSON(): PEM_write_bio_X509's armor over the DER, 64 + * base64 characters a line. */ +ScrStr *scr_crypto_x509_pem(ScrBytes *der) { + static const char digits[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + const uint8_t *d = (const uint8_t *)der->data; + size_t n = der->len * scr_bytes_elem_size(der->elem); + ScrX509Buf b = {0}; + scr_x509_puts(&b, "-----BEGIN CERTIFICATE-----\n"); + size_t col = 0; + for (size_t i = 0; i < n; i += 3) { + uint32_t v = (uint32_t)d[i] << 16; + if (i + 1 < n) v |= (uint32_t)d[i + 1] << 8; + if (i + 2 < n) v |= d[i + 2]; + char q[4] = {digits[(v >> 18) & 63], digits[(v >> 12) & 63], i + 1 < n ? digits[(v >> 6) & 63] : '=', + i + 2 < n ? digits[v & 63] : '='}; + for (int k = 0; k < 4; k++) { + scr_x509_putc(&b, q[k]); + if (++col == 64) { + scr_x509_putc(&b, '\n'); + col = 0; + } + } + } + if (col) scr_x509_putc(&b, '\n'); + scr_x509_puts(&b, "-----END CERTIFICATE-----\n"); + return scr_x509_buf_str(&b); +} + +/* ── checkHost, checkEmail and checkIP ───────────────────────────────── */ + +/* X509_CHECK_FLAG_* as Node's getFlags sets them. */ +enum { + SCR_X509_ALWAYS_CHECK_SUBJECT = 0x1, + SCR_X509_NO_WILDCARDS = 0x2, + SCR_X509_NO_PARTIAL_WILDCARDS = 0x4, + SCR_X509_MULTI_LABEL_WILDCARDS = 0x8, + SCR_X509_SINGLE_LABEL_SUBDOMAINS = 0x10, + SCR_X509_NEVER_CHECK_SUBJECT = 0x20, +}; + +/* Node's getFlags(options): validateObject, then the subject string and + * the four booleans, in Node's order. -1 with the error pending. */ +static int scr_x509_check_flags(const ScrDyn *options) { + if (options == NULL || options->kind == SCR_DYN_UNDEF) return 0; + if (options->kind == SCR_DYN_TYPED_REF) { + ScrDyn *value = scr_dyn_typed_ref_materialize((ScrDyn *)options); + if (!value) return -1; + int flags = scr_x509_check_flags(value); + scr_dyn_release(value); + return flags; + } + if (options->kind != SCR_DYN_OBJ) { + scr_dyn_arg_type_fail("options", "of type object", options); + return -1; + } + const ScrDyn *subject = scr_dyn_obj_get(options, "subject", 7); + static const char *const bool_names[] = {"wildcards", "partialWildcards", "multiLabelWildcards", + "singleLabelSubdomains"}; + static const bool bool_defaults[] = {true, true, false, false}; + bool values[4]; + if (subject != NULL && subject->kind != SCR_DYN_UNDEF && subject->kind != SCR_DYN_STR) { + scr_dyn_prop_type_fail("options.subject", "of type string", subject); + return -1; + } + for (size_t i = 0; i < 4; i++) { + const ScrDyn *v = scr_dyn_obj_get(options, bool_names[i], strlen(bool_names[i])); + if (v == NULL || v->kind == SCR_DYN_UNDEF) { + values[i] = bool_defaults[i]; + continue; + } + if (v->kind != SCR_DYN_BOOL) { + char name[48]; + snprintf(name, sizeof name, "options.%s", bool_names[i]); + scr_dyn_prop_type_fail(name, "of type boolean", v); + return -1; + } + values[i] = v->v.b; + } + int flags = 0; + if (subject != NULL && subject->kind == SCR_DYN_STR) { + const ScrStr *s = subject->v.str; + if (s->len == 6 && memcmp(s->data, "always", 6) == 0) flags |= SCR_X509_ALWAYS_CHECK_SUBJECT; + else if (s->len == 5 && memcmp(s->data, "never", 5) == 0) flags |= SCR_X509_NEVER_CHECK_SUBJECT; + else if (!(s->len == 7 && memcmp(s->data, "default", 7) == 0)) { + scr_dyn_arg_value_fail("options.subject", NULL, subject); + return -1; + } + } + if (!values[0]) flags |= SCR_X509_NO_WILDCARDS; + if (!values[1]) flags |= SCR_X509_NO_PARTIAL_WILDCARDS; + if (values[2]) flags |= SCR_X509_MULTI_LABEL_WILDCARDS; + if (values[3]) flags |= SCR_X509_SINGLE_LABEL_SUBDOMAINS; + return flags; +} + +static bool scr_x509_ieq(const uint8_t *a, const uint8_t *b, size_t n) { + for (size_t i = 0; i < n; i++) { + uint8_t x = a[i], y = b[i]; + if (x >= 'A' && x <= 'Z') x = (uint8_t)(x + 32); + if (y >= 'A' && y <= 'Z') y = (uint8_t)(y + 32); + if (x != y) return false; + } + return true; +} + +/* OpenSSL's equal_nocase after skip_prefix: a host that starts with '.' + * compares with the name's equal-length suffix when the characters + * skipped hold no NUL (and, under singleLabelSubdomains, no dot). */ +static bool scr_x509_host_equal(const uint8_t *pattern, size_t plen, const uint8_t *host, + size_t hlen, int flags) { + if (hlen > 1 && host[0] == '.') { + const uint8_t *p = pattern; + size_t n = plen; + while (n > hlen && *p) { + if ((flags & SCR_X509_SINGLE_LABEL_SUBDOMAINS) && *p == '.') break; + p++; + n--; + } + if (n == hlen) { + pattern = p; + plen = n; + } + } + return plen == hlen && memchr(pattern, 0, plen) == NULL && scr_x509_ieq(pattern, host, hlen); +} + +static bool scr_x509_label_char(uint8_t c) { + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); +} + +/* OpenSSL's valid_star: the '*' of a wildcard pattern, or NULL when the + * pattern is not a valid wildcard (the star outside the first label, in + * an IDNA label, partial when partial wildcards are off, or fewer than two + * labels after it). */ +static const uint8_t *scr_x509_valid_star(const uint8_t *p, size_t len, int flags) { + const uint8_t *star = NULL; + int dots = 0; + bool atstart = true, idna = false, first = true; + for (size_t i = 0; i < len; i++) { + if (p[i] == '*') { + bool atend = i == len - 1 || p[i + 1] == '.'; + if (star != NULL || !first || idna) return NULL; + if ((flags & SCR_X509_NO_PARTIAL_WILDCARDS) && (!atstart || !atend)) return NULL; + if (!atstart && !atend) return NULL; + star = &p[i]; + atstart = false; + } else if (p[i] == '.') { + if (atstart) return NULL; + idna = false; + dots++; + atstart = true; + first = false; + } else if (p[i] == '-' || scr_x509_label_char(p[i])) { + if (atstart && len - i >= 4 && scr_x509_ieq(&p[i], (const uint8_t *)"xn--", 4)) idna = true; + atstart = false; + } else { + return NULL; + } + } + if (star == NULL || dots < 2 || atstart) return NULL; + return star; +} + +/* OpenSSL's wildcard_match: prefix and suffix around the star match the + * host case-insensitively, the star covers at least one character, never + * a dot unless multi-label wildcards are on, and never an IDNA label. */ +static bool scr_x509_wildcard_match(const uint8_t *prefix, size_t prefix_len, + const uint8_t *suffix, size_t suffix_len, + const uint8_t *host, size_t hlen, int flags) { + if (hlen < prefix_len + suffix_len) return false; + if (!scr_x509_ieq(prefix, host, prefix_len)) return false; + const uint8_t *wild_start = host + prefix_len; + const uint8_t *wild_end = host + hlen - suffix_len; + if (!scr_x509_ieq(wild_end, suffix, suffix_len)) return false; + if (prefix_len == 0 && suffix_len > 0 && *suffix == '.') { + if (wild_start == wild_end) return false; + if (wild_end - wild_start > 4 && scr_x509_ieq(wild_start, (const uint8_t *)"xn--", 4)) + return false; + } + bool allow_multi = (flags & SCR_X509_MULTI_LABEL_WILDCARDS) != 0; + for (const uint8_t *p = wild_start; p != wild_end; p++) { + if (!scr_x509_label_char(*p) && *p != '-' && !(*p == '.' && allow_multi)) return false; + } + return true; +} + +static bool scr_x509_host_match(const uint8_t *pattern, size_t plen, const uint8_t *host, + size_t hlen, int flags) { + /* a host that starts with '.' matches a wildcard only as a suffix */ + if (!(flags & SCR_X509_NO_WILDCARDS) && !(hlen > 1 && host[0] == '.')) { + const uint8_t *star = scr_x509_valid_star(pattern, plen, flags); + if (star != NULL) + return scr_x509_wildcard_match(pattern, (size_t)(star - pattern), star + 1, + plen - (size_t)(star - pattern) - 1, host, hlen, flags); + } + return scr_x509_host_equal(pattern, plen, host, hlen, flags); +} + +/* OpenSSL's equal_email: the local part as is, the domain case- + * insensitively. */ +static bool scr_x509_email_match(const uint8_t *pattern, size_t plen, const uint8_t *email, + size_t elen) { + if (plen != elen || memchr(pattern, 0, plen) != NULL) return false; + size_t at = elen; + while (at > 0 && email[at - 1] != '@') at--; + if (at == 0) return scr_x509_ieq(pattern, email, elen); + return memcmp(pattern, email, at) == 0 && scr_x509_ieq(pattern + at, email + at, elen - at); +} + +enum { SCR_X509_GEN_EMAIL = 0x81, SCR_X509_GEN_DNS = 0x82, SCR_X509_GEN_IP = 0x87 }; + +/* do_x509_check over the subjectAltName entries of one type, then the + * subject's CN (hosts) or emailAddress (emails) entries when the flags + * allow. Writes the matching certificate name into *out. */ +static bool scr_x509_check(ScrBytes *der, uint8_t gen, const uint8_t *chk, size_t chk_len, + int flags, ScrX509Buf *out) { + ScrX509Parts parts; + if (!scr_x509_parts(SCR_X509_DER(der), &parts)) return false; + bool san_present = false; + size_t n; + const uint8_t *ext = scr_x509_ext(&parts, SCR_X509_OID_SAN, sizeof SCR_X509_OID_SAN, &n); + uint8_t tag; + size_t len; + const uint8_t *names = ext ? scr_der_tl(ext, ext + n, &tag, &len) : NULL; + if (names && tag == 0x30) { + const uint8_t *end = names + len; + for (const uint8_t *p = names; p < end;) { + const uint8_t *v = scr_der_tl(p, end, &tag, &len); + if (!v) break; + p = v + len; + if (tag != gen) continue; + san_present = true; + bool hit = gen == SCR_X509_GEN_IP ? len == chk_len && memcmp(v, chk, len) == 0 + : gen == SCR_X509_GEN_DNS ? scr_x509_host_match(v, len, chk, chk_len, flags) + : scr_x509_email_match(v, len, chk, chk_len); + if (hit) { + scr_x509_put(out, v, len); + return true; + } + } + } + if (gen == SCR_X509_GEN_IP || (flags & SCR_X509_NEVER_CHECK_SUBJECT) || + (san_present && !(flags & SCR_X509_ALWAYS_CHECK_SUBJECT)) || !parts.subject) + return false; + /* the subject's CN (2.5.4.3) or emailAddress (1.2.840.113549.1.9.1) */ + static const uint8_t cn[] = {0x55, 0x04, 0x03}; + static const uint8_t email[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x09, 0x01}; + const uint8_t *want = gen == SCR_X509_GEN_DNS ? cn : email; + size_t want_len = gen == SCR_X509_GEN_DNS ? sizeof cn : sizeof email; + const uint8_t *end = parts.subject + parts.subject_len; + for (const uint8_t *p = parts.subject; p < end;) { + const uint8_t *set = scr_der_tl(p, end, &tag, &len); + if (!set || tag != 0x31) break; + const uint8_t *set_end = set + len; + p = set_end; + for (const uint8_t *q = set; q < set_end;) { + const uint8_t *atv = scr_der_tl(q, set_end, &tag, &len); + if (!atv || tag != 0x30) break; + const uint8_t *atv_end = atv + len; + q = atv_end; + const uint8_t *oid = scr_der_tl(atv, atv_end, &tag, &len); + if (!oid || tag != 0x06 || len != want_len || memcmp(oid, want, len) != 0) continue; + uint8_t vtag; + size_t vlen; + const uint8_t *value = scr_der_tl(oid + len, atv_end, &vtag, &vlen); + if (!value) continue; + ScrX509Buf text = {0}; + scr_x509_value_utf8(&text, vtag, value, vlen); + bool hit = gen == SCR_X509_GEN_DNS + ? scr_x509_host_match((const uint8_t *)text.data, text.len, chk, chk_len, flags) + : scr_x509_email_match((const uint8_t *)text.data, text.len, chk, chk_len); + if (hit) scr_x509_put(out, text.data, text.len); + free(text.data); + if (hit) return true; + } + } + return false; +} + +/* x509.checkHost(name[, options]) and x509.checkEmail(email[, options]): + * the certificate name that matched (checkHost) or the argument + * (checkEmail), "" for none (Node's undefined), or NULL with the + * validation error pending. */ +static ScrStr *scr_x509_check_name(ScrBytes *der, const ScrDyn *value, const ScrDyn *options, + const char *arg, uint8_t gen) { + if (value->kind != SCR_DYN_STR) { + scr_dyn_arg_type_fail(arg, "of type string", value); + return NULL; + } + int flags = scr_x509_check_flags(options); + if (flags < 0) return NULL; + ScrX509Buf b = {0}; + const ScrStr *s = value->v.str; + bool hit = s->len > 0 && scr_x509_check(der, gen, (const uint8_t *)s->data, s->len, flags, &b); + if (hit && gen == SCR_X509_GEN_EMAIL) { + /* checkEmail answers its argument (X509_check_email reports no name) */ + free(b.data); + return scr_str_retain((ScrStr *)s); + } + return scr_x509_buf_str(&b); +} + +ScrStr *scr_crypto_x509_check_host(ScrBytes *der, ScrDyn *name, ScrDyn *options) { + return scr_x509_check_name(der, name, options, "name", SCR_X509_GEN_DNS); +} + +ScrStr *scr_crypto_x509_check_email(ScrBytes *der, ScrDyn *email, ScrDyn *options) { + return scr_x509_check_name(der, email, options, "email", SCR_X509_GEN_EMAIL); +} + +/* inet_pton's IPv4 form, which Node's checkIP parses: four decimal parts, + * each at most 255, without leading zeros. */ +static bool scr_x509_ipv4(const char *s, size_t n, uint8_t out[4]) { + size_t part = 0, i = 0; + while (part < 4) { + if (i >= n || s[i] < '0' || s[i] > '9') return false; + unsigned v = 0; + size_t digits = 0; + if (s[i] == '0' && i + 1 < n && s[i + 1] >= '0' && s[i + 1] <= '9') return false; + while (i < n && s[i] >= '0' && s[i] <= '9') { + v = v * 10 + (unsigned)(s[i++] - '0'); + if (++digits > 3 || v > 255) return false; + } + out[part++] = (uint8_t)v; + if (part < 4) { + if (i >= n || s[i] != '.') return false; + i++; + } + } + return i == n; +} + +/* inet_pton's IPv6 form: hex groups with at most one "::", and an IPv4 + * address in place of the last two groups. */ +static bool scr_x509_ipv6(const char *s, size_t n, uint8_t out[16]) { + uint8_t head[16], tail[16]; + size_t head_len = 0, tail_len = 0; + bool compressed = false; + size_t i = 0; + if (n >= 2 && s[0] == ':' && s[1] == ':') { + compressed = true; + i = 2; + if (i == n) { + memset(out, 0, 16); + return true; + } + } else if (n > 0 && s[0] == ':') { + return false; + } + while (i < n) { + uint8_t *dst = compressed ? tail : head; + size_t *dst_len = compressed ? &tail_len : &head_len; + /* an IPv4 tail */ + const char *dot = memchr(s + i, '.', n - i); + const char *colon = memchr(s + i, ':', n - i); + if (dot != NULL && colon == NULL) { + if (*dst_len + 4 > 16 || !scr_x509_ipv4(s + i, n - i, dst + *dst_len)) return false; + *dst_len += 4; + i = n; + break; + } + unsigned v = 0; + size_t digits = 0; + while (i < n && s[i] != ':') { + char c = s[i++]; + unsigned d = c >= '0' && c <= '9' ? (unsigned)(c - '0') + : c >= 'a' && c <= 'f' ? (unsigned)(c - 'a' + 10) + : c >= 'A' && c <= 'F' ? (unsigned)(c - 'A' + 10) + : 16; + if (d == 16 || ++digits > 4) return false; + v = (v << 4) | d; + } + if (digits == 0 || *dst_len + 2 > 16) return false; + dst[(*dst_len)++] = (uint8_t)(v >> 8); + dst[(*dst_len)++] = (uint8_t)v; + if (i == n) break; + i++; /* ':' */ + if (i < n && s[i] == ':') { + if (compressed) return false; + compressed = true; + i++; + if (i == n) break; + } else if (i == n) { + return false; + } + } + if (compressed) { + if (head_len + tail_len > 14) return false; + } else if (head_len != 16) { + return false; + } + memset(out, 0, 16); + memcpy(out, head, head_len); + memcpy(out + 16 - tail_len, tail, tail_len); + return true; +} + +/* x509.checkIP(ip[, options]): the argument itself when an iPAddress + * alternative name equals it, "" for none, NULL with the error pending. + * The options are validated like checkHost's and have no effect. */ +ScrStr *scr_crypto_x509_check_ip(ScrBytes *der, ScrDyn *ip, ScrDyn *options) { + if (ip->kind != SCR_DYN_STR) { + scr_dyn_arg_type_fail("ip", "of type string", ip); + return NULL; + } + if (scr_x509_check_flags(options) < 0) return NULL; + const ScrStr *s = ip->v.str; + uint8_t addr[16]; + size_t addr_len = 0; + if (memchr(s->data, ':', s->len) != NULL) { + if (scr_x509_ipv6(s->data, s->len, addr)) addr_len = 16; + } else if (scr_x509_ipv4(s->data, s->len, addr)) { + addr_len = 4; + } + if (addr_len == 0) { + static const char msg[] = "Invalid name"; + scr_throw_error_msg_code(SCR_ERR_TYPE, msg, sizeof msg - 1, "ERR_INVALID_ARG_VALUE"); + return NULL; + } + ScrX509Buf b = {0}; + if (scr_x509_check(der, SCR_X509_GEN_IP, addr, addr_len, 0, &b)) { + free(b.data); + return scr_str_retain((ScrStr *)s); + } + return scr_x509_buf_str(&b); +} + +/* ── checkIssued ──────────────────────────────────────────────────────── */ + +/* The string types OpenSSL canonicalizes before comparing names + * (ASN1_MASK_CANON). */ +static bool scr_x509_canon_type(uint8_t tag) { + return tag == 0x0C || tag == 0x1E || tag == 0x1C || tag == 0x13 || tag == 0x14 || tag == 0x16 || + tag == 0x1A; +} + +static bool scr_x509_space(uint8_t c) { + return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r'; +} + +/* asn1_string_canon: UTF-8, leading and trailing whitespace dropped, + * inner runs of whitespace as one space, ASCII in lower case. */ +static void scr_x509_canon(ScrX509Buf *out, uint8_t tag, const uint8_t *v, size_t n) { + ScrX509Buf text = {0}; + scr_x509_value_utf8(&text, tag, v, n); + const uint8_t *p = (const uint8_t *)text.data; + size_t len = text.len; + while (len > 0 && scr_x509_space(*p)) p++, len--; + while (len > 0 && scr_x509_space(p[len - 1])) len--; + for (size_t i = 0; i < len; i++) { + uint8_t c = p[i]; + if (scr_x509_space(c)) { + scr_x509_putc(out, ' '); + while (i + 1 < len && scr_x509_space(p[i + 1])) i++; + } else { + scr_x509_putc(out, (char)(c >= 'A' && c <= 'Z' ? c + 32 : c)); + } + } + free(text.data); +} + +/* One Name as comparable text: per RDN, each attribute's OID and its + * canonical value (or raw DER for non-string types), with separators that + * keep the RDN grouping. */ +static void scr_x509_name_canon(ScrX509Buf *out, const uint8_t *name, size_t n) { + const uint8_t *end = name + n; + uint8_t tag; + size_t len; + for (const uint8_t *p = name; p < end;) { + const uint8_t *set = scr_der_tl(p, end, &tag, &len); + if (!set || tag != 0x31) break; + const uint8_t *set_end = set + len; + p = set_end; + scr_x509_putc(out, '\x01'); + for (const uint8_t *q = set; q < set_end;) { + const uint8_t *atv = scr_der_tl(q, set_end, &tag, &len); + if (!atv || tag != 0x30) break; + const uint8_t *atv_end = atv + len; + q = atv_end; + const uint8_t *oid = scr_der_tl(atv, atv_end, &tag, &len); + if (!oid || tag != 0x06) continue; + scr_x509_putc(out, '\x02'); + scr_x509_put(out, oid, len); + uint8_t vtag; + size_t vlen; + const uint8_t *value_tl = oid + len; + const uint8_t *value = scr_der_tl(value_tl, atv_end, &vtag, &vlen); + if (!value) continue; + scr_x509_putc(out, '\x03'); + if (scr_x509_canon_type(vtag)) scr_x509_canon(out, vtag, value, vlen); + else scr_x509_put(out, value_tl, (size_t)(value + vlen - value_tl)); + } + } +} + +static bool scr_x509_name_eq(const uint8_t *a, size_t an, const uint8_t *b, size_t bn) { + ScrX509Buf x = {0}, y = {0}; + scr_x509_name_canon(&x, a, an); + scr_x509_name_canon(&y, b, bn); + bool eq = x.len == y.len && (x.len == 0 || memcmp(x.data, y.data, x.len) == 0); + free(x.data); + free(y.data); + return eq; +} + +static const uint8_t SCR_X509_OID_SKID[] = {0x55, 0x1D, 0x0E}; +static const uint8_t SCR_X509_OID_AKID[] = {0x55, 0x1D, 0x23}; + +/* The public key algorithm a signature algorithm needs: 1 RSA, 2 EC, + * 3 Ed25519, 4 Ed448, 0 unknown. */ +static int scr_x509_sig_key_kind(const uint8_t *oid, size_t n) { + static const uint8_t rsa_prefix[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01}; + static const uint8_t ecdsa_prefix[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04}; + if (n == sizeof rsa_prefix + 1 && memcmp(oid, rsa_prefix, sizeof rsa_prefix) == 0) { + uint8_t last = oid[sizeof rsa_prefix]; + return last == 4 || last == 5 || (last >= 10 && last <= 14) ? 1 : 0; + } + if (n >= sizeof ecdsa_prefix + 1 && memcmp(oid, ecdsa_prefix, sizeof ecdsa_prefix) == 0) + return 2; + if (n == 3 && oid[0] == 0x2B && oid[1] == 0x65 && oid[2] == 0x70) return 3; + if (n == 3 && oid[0] == 0x2B && oid[1] == 0x65 && oid[2] == 0x71) return 4; + return 0; +} + +/* The kind (as above) of a SubjectPublicKeyInfo's algorithm. */ +static int scr_x509_spki_kind(const ScrX509Parts *parts) { + if (!parts->spki) return 0; + uint8_t tag; + size_t len; + const uint8_t *alg = scr_der_tl(parts->spki, parts->spki + parts->spki_len, &tag, &len); + if (!alg || tag != 0x30) return 0; + const uint8_t *oid = scr_der_tl(alg, alg + len, &tag, &len); + if (!oid || tag != 0x06) return 0; + static const uint8_t rsa[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01}; + static const uint8_t pss[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0A}; + static const uint8_t ec[] = {0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01}; + if ((len == sizeof rsa && memcmp(oid, rsa, len) == 0) || + (len == sizeof pss && memcmp(oid, pss, len) == 0)) + return 1; + if (len == sizeof ec && memcmp(oid, ec, len) == 0) return 2; + if (len == 3 && oid[0] == 0x2B && oid[1] == 0x65 && oid[2] == 0x70) return 3; + if (len == 3 && oid[0] == 0x2B && oid[1] == 0x65 && oid[2] == 0x71) return 4; + return 0; +} + +/* X509_check_akid: the subject's authorityKeyIdentifier against the + * issuer's subjectKeyIdentifier, serial number and issuer name. */ +static bool scr_x509_akid_ok(const ScrX509Parts *issuer, const ScrX509Parts *subject) { + size_t n; + const uint8_t *akid = scr_x509_ext(subject, SCR_X509_OID_AKID, sizeof SCR_X509_OID_AKID, &n); + if (!akid) return true; + uint8_t tag; + size_t len; + const uint8_t *seq = scr_der_tl(akid, akid + n, &tag, &len); + if (!seq || tag != 0x30) return true; + const uint8_t *end = seq + len; + for (const uint8_t *p = seq; p < end;) { + const uint8_t *v = scr_der_tl(p, end, &tag, &len); + if (!v) break; + p = v + len; + if (tag == 0x80) { /* keyIdentifier */ + size_t sn; + const uint8_t *skid = scr_x509_ext(issuer, SCR_X509_OID_SKID, sizeof SCR_X509_OID_SKID, &sn); + uint8_t stag; + size_t slen; + const uint8_t *id = skid ? scr_der_tl(skid, skid + sn, &stag, &slen) : NULL; + if (id && stag == 0x04 && (slen != len || memcmp(id, v, len) != 0)) return false; + } else if (tag == 0x82) { /* authorityCertSerialNumber */ + if (issuer->serial && (issuer->serial_len != len || memcmp(issuer->serial, v, len) != 0)) + return false; + } else if (tag == 0xA1 && issuer->issuer) { /* authorityCertIssuer */ + bool found = false; + const uint8_t *names_end = v + len; + for (const uint8_t *q = v; q < names_end && !found;) { + uint8_t gtag; + size_t glen; + const uint8_t *g = scr_der_tl(q, names_end, >ag, &glen); + if (!g) break; + q = g + glen; + if (gtag != 0xA4) continue; + uint8_t ntag; + size_t nlen; + const uint8_t *name = scr_der_tl(g, g + glen, &ntag, &nlen); + if (name && ntag == 0x30 && scr_x509_name_eq(name, nlen, issuer->issuer, issuer->issuer_len)) + found = true; + } + if (!found) return false; + } + } + return true; +} + +/* x509.checkIssued(otherCert): X509_check_issued(otherCert, x509) — the + * names match, the authority key identifier fits, the signature algorithm + * suits the issuer's key, and the issuer's keyUsage, when present, allows + * certificate signing. */ +bool scr_crypto_x509_check_issued(ScrBytes *der, ScrBytes *issuer_der) { + ScrX509Parts subject, issuer; + if (!scr_x509_parts(SCR_X509_DER(der), &subject) || + !scr_x509_parts(SCR_X509_DER(issuer_der), &issuer)) + return false; + if (!subject.issuer || !issuer.subject || + !scr_x509_name_eq(issuer.subject, issuer.subject_len, subject.issuer, subject.issuer_len)) + return false; + if (!scr_x509_akid_ok(&issuer, &subject)) return false; + uint8_t tag; + size_t len; + const uint8_t *sig_oid = subject.sig_alg + ? scr_der_tl(subject.sig_alg, subject.sig_alg + subject.sig_alg_len, + &tag, &len) + : NULL; + if (!sig_oid || tag != 0x06) return false; + int need = scr_x509_sig_key_kind(sig_oid, len); + if (need == 0 || need != scr_x509_spki_kind(&issuer)) return false; + size_t n; + const uint8_t *ku = scr_x509_ext(&issuer, SCR_X509_OID_KEY_USAGE, sizeof SCR_X509_OID_KEY_USAGE, &n); + if (ku) { + const uint8_t *bits = scr_der_tl(ku, ku + n, &tag, &len); + if (!bits || tag != 0x03 || len < 2 || (bits[1] & 0x04) == 0) return false; + } + return true; +} + +/* ── toLegacyObject ───────────────────────────────────────────────────── */ + +static ScrDyn *scr_x509_dyn_text(const char *s, size_t n) { + ScrStr *str = scr_str_new(s, n); + ScrDyn *d = scr_dyn_new_str(str); + scr_str_release(str); + return d; +} + +/* A fresh Buffer holding n bytes. */ +static ScrDyn *scr_x509_dyn_buffer(const uint8_t *p, size_t n) { + ScrBytes *b = scr_buffer_alloc_unsafe_slow((double)n); + if (n) memcpy(b->data, p, n); + ScrDyn *d = scr_dyn_new_bytes(b); + scr_bytes_release(b); + return d; +} + +/* A Name as Node's legacy object: one property per attribute, keyed by + * OpenSSL's short name (the dotted OID otherwise), its value the UTF-8 + * text; a repeated key collects its values in an array. */ +static ScrDyn *scr_x509_name_object(const uint8_t *name, size_t n) { + ScrDyn *obj = scr_dyn_new_obj_null_proto(); + const uint8_t *end = name + n; + uint8_t tag; + size_t len; + for (const uint8_t *p = name; p < end;) { + const uint8_t *set = scr_der_tl(p, end, &tag, &len); + if (!set || tag != 0x31) break; + const uint8_t *set_end = set + len; + p = set_end; + for (const uint8_t *q = set; q < set_end;) { + const uint8_t *atv = scr_der_tl(q, set_end, &tag, &len); + if (!atv || tag != 0x30) break; + const uint8_t *atv_end = atv + len; + q = atv_end; + const uint8_t *oid = scr_der_tl(atv, atv_end, &tag, &len); + if (!oid || tag != 0x06) continue; + size_t oid_len = len; + uint8_t vtag; + size_t vlen; + const uint8_t *value = scr_der_tl(oid + len, atv_end, &vtag, &vlen); + if (!value) continue; + ScrX509Buf key = {0}, text = {0}; + scr_x509_oid_name(&key, oid, oid_len, scr_x509_attr_names, + sizeof scr_x509_attr_names / sizeof scr_x509_attr_names[0]); + scr_x509_value_utf8(&text, vtag, value, vlen); + ScrDyn *v = scr_x509_dyn_text(text.data ? text.data : "", text.len); + const ScrDyn *prior = scr_dyn_obj_get(obj, key.data, key.len); + if (prior == NULL) { + scr_dyn_obj_set(obj, key.data, key.len, v); + } else if (prior->kind == SCR_DYN_ARR) { + scr_dyn_arr_push((ScrDyn *)prior, v); + } else { + ScrDyn *arr = scr_dyn_new_arr(); + scr_dyn_arr_push(arr, scr_dyn_retain((ScrDyn *)prior)); + scr_dyn_arr_push(arr, v); + scr_dyn_obj_set(obj, key.data, key.len, arr); + } + free(key.data); + free(text.data); + } + } + return obj; +} + +/* The JSON string literal at s (a quoted alternative name), decoded. */ +static void scr_x509_json_unquote(ScrX509Buf *out, const char *s, size_t n) { + for (size_t i = 1; i < n; i++) { + char c = s[i]; + if (c == '"') return; + if (c != '\\' || i + 1 >= n) { + scr_x509_putc(out, c); + continue; + } + c = s[++i]; + if (c == 'u' && i + 4 < n) { + unsigned v = 0; + for (int k = 1; k <= 4; k++) { + char h = s[i + k]; + v = v * 16 + (unsigned)(h <= '9' ? h - '0' : (h | 0x20) - 'a' + 10); + } + scr_x509_put_utf8(out, v); + i += 4; + } else { + scr_x509_putc(out, c == 'n' ? '\n' : c == 't' ? '\t' : c); + } + } +} + +/* Node's legacy infoAccess: the infoAccess lines split at their first + * colon into " - " keys, each holding its values in an + * array (a quoted value is JSON-decoded). */ +static ScrDyn *scr_x509_info_access_object(ScrBytes *der) { + ScrStr *text = scr_crypto_x509_info_access(der); + if (text->len == 0) { + scr_str_release(text); + return scr_dyn_undefined(); + } + ScrDyn *obj = scr_dyn_new_obj_null_proto(); + const char *s = text->data; + size_t n = text->len; + for (size_t start = 0; start < n;) { + size_t eol = start; + while (eol < n && s[eol] != '\n') eol++; + size_t colon = start; + while (colon < eol && s[colon] != ':') colon++; + if (colon < eol) { + const char *val = s + colon + 1; + size_t val_len = eol - colon - 1; + ScrX509Buf v = {0}; + if (val_len > 0 && val[0] == '"') scr_x509_json_unquote(&v, val, val_len); + else scr_x509_put(&v, val, val_len); + ScrDyn *item = scr_x509_dyn_text(v.data ? v.data : "", v.len); + free(v.data); + const ScrDyn *prior = scr_dyn_obj_get(obj, s + start, colon - start); + if (prior != NULL && prior->kind == SCR_DYN_ARR) { + scr_dyn_arr_push((ScrDyn *)prior, item); + } else { + ScrDyn *arr = scr_dyn_new_arr(); + scr_dyn_arr_push(arr, item); + scr_dyn_obj_set(obj, s + start, colon - start, arr); + } + } + start = eol + 1; + } + scr_str_release(text); + return obj; +} + +/* Hex of a big-endian magnitude: BN_bn2hex (whole bytes, upper case, no + * leading zero bytes) or, with `lower_trim`, %llx-style text. */ +static void scr_x509_put_hex(ScrX509Buf *b, const uint8_t *p, size_t n, bool lower_trim) { + const char *hex = lower_trim ? "0123456789abcdef" : "0123456789ABCDEF"; + while (n > 0 && *p == 0) p++, n--; + if (n == 0) { + scr_x509_putc(b, '0'); + return; + } + for (size_t i = 0; i < n; i++) { + if (!(lower_trim && i == 0 && (p[i] >> 4) == 0)) scr_x509_putc(b, hex[p[i] >> 4]); + scr_x509_putc(b, hex[p[i] & 0x0f]); + } +} + +typedef struct { + const char *oid; + const char *name; + const char *nist; + int bits; +} ScrX509Curve; + +static const ScrX509Curve scr_x509_curves[] = { + {"1.2.840.10045.3.1.1", "prime192v1", "P-192", 192}, + {"1.3.132.0.33", "secp224r1", "P-224", 224}, + {"1.2.840.10045.3.1.7", "prime256v1", "P-256", 256}, + {"1.3.132.0.34", "secp384r1", "P-384", 384}, + {"1.3.132.0.35", "secp521r1", "P-521", 521}, + {"1.3.132.0.31", "secp192k1", NULL, 192}, + {"1.3.132.0.32", "secp224k1", NULL, 225}, + {"1.3.132.0.10", "secp256k1", NULL, 256}, + {"1.3.36.3.3.2.8.1.1.7", "brainpoolP256r1", NULL, 256}, + {"1.3.36.3.3.2.8.1.1.11", "brainpoolP384r1", NULL, 384}, + {"1.3.36.3.3.2.8.1.1.13", "brainpoolP512r1", NULL, 512}, +}; + +/* The public key members of the legacy object: modulus, exponent, + * pubkey, bits, asn1Curve and nistCurve (each undefined where the key + * type has none). */ +static void scr_x509_key_fields(const ScrX509Parts *parts, ScrDyn *slots[6]) { + for (int i = 0; i < 6; i++) slots[i] = scr_dyn_undefined(); + if (!parts->spki) return; + int kind = scr_x509_spki_kind(parts); + uint8_t tag; + size_t len; + const uint8_t *spki_end = parts->spki + parts->spki_len; + const uint8_t *alg = scr_der_tl(parts->spki, spki_end, &tag, &len); + if (!alg || tag != 0x30) return; + const uint8_t *alg_end = alg + len; + const uint8_t *oid = scr_der_tl(alg, alg_end, &tag, &len); + if (!oid) return; + const uint8_t *params = oid + len; + uint8_t ptag; + size_t plen; + const uint8_t *param = scr_der_tl(params, alg_end, &ptag, &plen); + const uint8_t *bits = scr_der_tl(alg_end, spki_end, &tag, &len); + if (!bits || tag != 0x03 || len < 1) return; + const uint8_t *key = bits + 1; + size_t key_len = len - 1; + static const uint8_t rsa_oid[] = {0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01}; + bool rsa = kind == 1 && (size_t)(params - oid) == sizeof rsa_oid && + memcmp(oid, rsa_oid, sizeof rsa_oid) == 0; + if (rsa) { + const uint8_t *seq = scr_der_tl(key, key + key_len, &tag, &len); + if (!seq || tag != 0x30) return; + const uint8_t *seq_end = seq + len; + size_t nlen, elen; + const uint8_t *nmod = scr_der_tl(seq, seq_end, &tag, &nlen); + if (!nmod || tag != 0x02) return; + const uint8_t *nexp = scr_der_tl(nmod + nlen, seq_end, &tag, &elen); + if (!nexp || tag != 0x02) return; + ScrX509Buf m = {0}, e = {0}; + scr_x509_put_hex(&m, nmod, nlen, false); + scr_x509_puts(&e, "0x"); + scr_x509_put_hex(&e, nexp, elen, true); + slots[0] = scr_x509_dyn_text(m.data, m.len); + slots[1] = scr_x509_dyn_text(e.data, e.len); + free(m.data); + free(e.data); + slots[2] = scr_x509_dyn_buffer(parts->spki_tlv, parts->spki_tlv_len); + size_t i = 0; + while (i < nlen && nmod[i] == 0) i++; + int nbits = 0; + if (i < nlen) { + nbits = (int)((nlen - i - 1) * 8); + for (uint8_t top = nmod[i]; top; top >>= 1) nbits++; + } + slots[3] = scr_dyn_new_num(nbits); + return; + } + if (kind == 2 && param && ptag == 0x06) { + ScrX509Buf dotted = {0}; + scr_x509_oid_dotted(&dotted, param, plen); + for (size_t c = 0; c < sizeof scr_x509_curves / sizeof scr_x509_curves[0]; c++) { + const ScrX509Curve *curve = &scr_x509_curves[c]; + if (strlen(curve->oid) != dotted.len || memcmp(curve->oid, dotted.data, dotted.len) != 0) + continue; + slots[2] = scr_x509_dyn_buffer(key, key_len); + slots[3] = scr_dyn_new_num(curve->bits); + slots[4] = scr_x509_dyn_text(curve->name, strlen(curve->name)); + if (curve->nist) slots[5] = scr_x509_dyn_text(curve->nist, strlen(curve->nist)); + break; + } + free(dotted.data); + } +} + +static const uint8_t SCR_X509_OID_EKU[] = {0x55, 0x1D, 0x25}; + +/* x509.toLegacyObject(): Node's X509ToObject, member order included. */ +ScrDyn *scr_crypto_x509_legacy_object(ScrBytes *der) { + ScrX509Parts parts; + ScrDyn *obj = scr_dyn_new_obj(); + bool ok = scr_x509_parts(SCR_X509_DER(der), &parts); + if (!ok) memset(&parts, 0, sizeof parts); + scr_dyn_obj_set(obj, "subject", 7, + parts.subject ? scr_x509_name_object(parts.subject, parts.subject_len) + : scr_dyn_new_obj_null_proto()); + scr_dyn_obj_set(obj, "issuer", 6, + parts.issuer ? scr_x509_name_object(parts.issuer, parts.issuer_len) + : scr_dyn_new_obj_null_proto()); + ScrStr *san = scr_crypto_x509_subject_alt_name(der); + scr_dyn_obj_set(obj, "subjectaltname", 14, san->len ? scr_dyn_new_str(san) : scr_dyn_undefined()); + scr_str_release(san); + scr_dyn_obj_set(obj, "infoAccess", 10, scr_x509_info_access_object(der)); + scr_dyn_obj_set(obj, "ca", 2, scr_dyn_new_bool(scr_crypto_x509_ca(der))); + ScrDyn *key[6]; + scr_x509_key_fields(&parts, key); + scr_dyn_obj_set(obj, "modulus", 7, key[0]); + scr_dyn_obj_set(obj, "exponent", 8, key[1]); + scr_dyn_obj_set(obj, "pubkey", 6, key[2]); + scr_dyn_obj_set(obj, "bits", 4, key[3]); + static const struct { + const char *key; + ScrStr *(*field)(ScrBytes *); + } texts[] = { + {"valid_from", scr_crypto_x509_valid_from}, + {"valid_to", scr_crypto_x509_valid_to}, + {"fingerprint", scr_crypto_x509_fingerprint}, + {"fingerprint256", scr_crypto_x509_fingerprint256}, + {"fingerprint512", scr_crypto_x509_fingerprint512}, + }; + for (size_t i = 0; i < sizeof texts / sizeof texts[0]; i++) { + ScrStr *s = texts[i].field(der); + scr_dyn_obj_set(obj, texts[i].key, strlen(texts[i].key), scr_dyn_new_str(s)); + scr_str_release(s); + } + size_t n; + const uint8_t *eku = ok ? scr_x509_ext(&parts, SCR_X509_OID_EKU, sizeof SCR_X509_OID_EKU, &n) : NULL; + uint8_t tag; + size_t len; + const uint8_t *purposes = eku ? scr_der_tl(eku, eku + n, &tag, &len) : NULL; + if (purposes && tag == 0x30) { + ScrDyn *arr = scr_dyn_new_arr(); + const uint8_t *end = purposes + len; + for (const uint8_t *p = purposes; p < end;) { + const uint8_t *oid = scr_der_tl(p, end, &tag, &len); + if (!oid) break; + p = oid + len; + if (tag != 0x06) continue; + ScrX509Buf dotted = {0}; + scr_x509_oid_dotted(&dotted, oid, len); + scr_dyn_arr_push(arr, scr_x509_dyn_text(dotted.data, dotted.len)); + free(dotted.data); + } + scr_dyn_obj_set(obj, "ext_key_usage", 13, arr); + } else { + scr_dyn_obj_set(obj, "ext_key_usage", 13, scr_dyn_undefined()); + } + ScrStr *serial = scr_crypto_x509_serial_number(der); + scr_dyn_obj_set(obj, "serialNumber", 12, scr_dyn_new_str(serial)); + scr_str_release(serial); + { + ScrBytes *view = der; + SCR_BYTES_SNAPSHOT(view); + scr_dyn_obj_set(obj, "raw", 3, scr_x509_dyn_buffer(SCR_X509_DER(view))); + } + scr_dyn_obj_set(obj, "asn1Curve", 9, key[4]); + scr_dyn_obj_set(obj, "nistCurve", 9, key[5]); + return obj; +} diff --git a/tests/corpus/6936-x509-certificate-fields.ts b/tests/corpus/6936-x509-certificate-fields.ts new file mode 100644 index 000000000..de4b78f9a --- /dev/null +++ b/tests/corpus/6936-x509-certificate-fields.ts @@ -0,0 +1,189 @@ +// X509Certificate fields match Node: subject and issuer (one attribute +// per line, RFC 2253 escaping), subjectAltName and infoAccess (undefined +// without the extension), serialNumber, the SHA-1/256/512 fingerprints, ca, +// the signature algorithm, the validity window as strings and Dates, and +// raw, over PEM Buffer, PEM string and DER input. +import * as crypto from "node:crypto"; + +// An RSA CA with a multi-attribute subject. +const CA = `-----BEGIN CERTIFICATE----- +MIIEITCCAwmgAwIBAgIIASNFZ4mrze8wDQYJKoZIhvcNAQELBQAwgZwxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNp +c2NvMRQwEgYDVQQKDAtFeGFtcGxlIE9yZzERMA8GA1UECwwIRGV2IFRlYW0xGDAW +BgNVBAMMD0V4YW1wbGUgUm9vdCBDQTEdMBsGCSqGSIb3DQEJARYOY2FAZXhhbXBs +ZS5jb20wIBcNMjYxMDIxMTYzMzUyWhgPMjEyNjA5MjcxNjMzNTJaMIGcMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j +aXNjbzEUMBIGA1UECgwLRXhhbXBsZSBPcmcxETAPBgNVBAsMCERldiBUZWFtMRgw +FgYDVQQDDA9FeGFtcGxlIFJvb3QgQ0ExHTAbBgkqhkiG9w0BCQEWDmNhQGV4YW1w +bGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0YGcCr0pxR8d +6qDdLuILcoT7vhtAjyHwfkoChnH6N3TLWzDUugnBp9NbDb7gDLqbRT4uTDoNb6zS +tEJZ4Q7/hhd0jDvoPmOy0Y3Kyj9uNsdf25GdbvwwEnlddELJCZprTZ4OhEg6w2s0 +Yy4SlviLzDXLmsggTypxeS+K8JHT9onMipi5L4GFu8n1QZbzXvSS4BkRgMXEyrtr +FOE9qSo2qkubFyd/WNKRTRIpTSc5/GGsqJ0FKDDJnN5adotcUucbJFn4noNnFUWh +M8mhBEj7ENDdJsD2EVFsI6H958jA2SbNNu4ngzAOs2AKNBYBfQK02ZQAdRNOSL3K +5FkfbII5LwIDAQABo2MwYTAdBgNVHQ4EFgQUP+yQyItpNYEls26Jfv+NnciGaK8w +HwYDVR0jBBgwFoAUP+yQyItpNYEls26Jfv+NnciGaK8wDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBABDw3Va/C+RFc/Hs +TJnHtQJtxFL0ZhnHUqg4DcDA3m+JDdIDNL8sNpLEbtn/pr0VeEWgG+MImWAQlrUW +IAZkLj9/Zg1wSO0oZ86ZyZJZmp54lUYXgG17CNl4g+F7VHt3bBwUJHTbWye/FKM6 +5OVZetCYKVj7Z+5BYuf7cumzvRqcn32fXidB/kjRX14SJ4JDPn2yFZWCr2ygIqWQ +SOuEmWbNAbYGaVZkQr2Ma8U28DWY2jb0f6nP8jLt49t9o6N/e6Fwd6I5t/mx9Mfj +0403omkxmr9vqN2kBamzVnun+2mDkRZcKPCr72Q4sfbvmDi/W5Nf1Iu2cQW8VfDO +SqpyT54= +-----END CERTIFICATE----- +`; + +// An EC leaf with alternative names, access descriptions and extended key usage, signed by CA. +const LEAF = `-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIPAPAN+s4AESIzRFVmd4iZMA0GCSqGSIb3DQEBDAUAMIGc +MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2Fu +IEZyYW5jaXNjbzEUMBIGA1UECgwLRXhhbXBsZSBPcmcxETAPBgNVBAsMCERldiBU +ZWFtMRgwFgYDVQQDDA9FeGFtcGxlIFJvb3QgQ0ExHTAbBgkqhkiG9w0BCQEWDmNh +QGV4YW1wbGUuY29tMB4XDTI2MTAyMTE2MzM1MloXDTM2MTAxODE2MzM1MlowJzER +MA8GA1UECgwITGVhZiBPcmcxEjAQBgNVBAMMCWxvY2FsaG9zdDBZMBMGByqGSM49 +AgEGCCqGSM49AwEHA0IABJVfVy9EH/VHQuRqpFFnXk0F00ncDht6APgVPDoybK8H +PlcM4T5H1yAOMHnlH29LK1jtMqU1aAOiiQRzPdCvqoujggE3MIIBMzAJBgNVHRME +AjAAMGgGA1UdEQRhMF+CCWxvY2FsaG9zdIINKi5leGFtcGxlLmNvbYcEfwAAAYcQ +AAAAAAAAAAAAAAAAAAAAAYERYWRtaW5AZXhhbXBsZS5jb22GGGh0dHBzOi8vZXhh +bXBsZS5jb20vcGF0aDBdBggrBgEFBQcBAQRRME8wIwYIKwYBBQUHMAGGF2h0dHA6 +Ly9vY3NwLmV4YW1wbGUuY29tMCgGCCsGAQUFBzAChhxodHRwOi8vY2EuZXhhbXBs +ZS5jb20vY2EuY3J0MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNV +HQ4EFgQUdKIx6ULFLPNP/kzwUFjSa5D19RswHwYDVR0jBBgwFoAUP+yQyItpNYEl +s26Jfv+NnciGaK8wDQYJKoZIhvcNAQEMBQADggEBABmQ8f2VsXNaMM9X1MEhi27D +LjwcOaaGEINNZq7xu/HL6UljMb1Odsuz66DkiH3Exd3MrWy6OlOpJJF0VzsqMsoD +0CRBxXF28o6Jil3vOGVwlYNmRidpkAkj4VyWDvv8FCS9VbsBtXaSHwu9wcCwePE0 +cGJRfTKoZ6KJ8vQ57DBEZ/ZszuhehOZYqrTmoUdjZ123kXdxQvK+ALn4SlIXHBhN +9unhd+8i00EmkXO/REw8paMcMVVGR+ioOEjyNHqZo6vkRqgpKggn1Yq8cTTDOMnS +P1o42EQZLlbuvx0kqInBqwqjDx4nZiPaifoDc9BF6iZPBvm8dhrEfghfB1tkNk0= +-----END CERTIFICATE----- +`; + +// Escaped subject characters, UTF-8 and a comma in a DNS name. +const ODD = `-----BEGIN CERTIFICATE----- +MIICXzCCAeWgAwIBAgIBATAKBggqhkjOPQQDAjBvMQ0wCwYDVQQDDARhLCBiMQ4w +DAYDVQQHDAUjbGVhZDESMBAGA1UECAwJICBzcGFjZSAgMSYwJAYDVQQKDB1RdW90 +ZSBxIGJhY2tcc2xhc2g7IHNlbWkgPGx0PjESMBAGA1UECwwJQ2Fmw6kg4oKsMB4X +DTI2MTAyMTE2MzM1MloXDTI3MTAyMTE2MzM1MlowbzENMAsGA1UEAwwEYSwgYjEO +MAwGA1UEBwwFI2xlYWQxEjAQBgNVBAgMCSAgc3BhY2UgIDEmMCQGA1UECgwdUXVv +dGUgcSBiYWNrXHNsYXNoOyBzZW1pIDxsdD4xEjAQBgNVBAsMCUNhZsOpIOKCrDB2 +MBAGByqGSM49AgEGBSuBBAAiA2IABMLLzwDsSeezCzScnC9xTIFl35dFAX+1Uagk +0y4Y72rOOgVFA13SMIbMfv2InIyg2vXOdqn0y7RqiaaqqnAYZB2RHHL0SD7t2MVL +K3BQajy7Oi6IeDDRGK1jM4D6nk/1AKNVMFMwMgYDVR0RBCswKYILYSxiLmV4YW1w +bGWCDXBsYWluLmV4YW1wbGWBBXhAeS56hwQKAAABMB0GA1UdDgQWBBSR4U6nIpTt +5rLoIZZxfxSyx9Uc9zAKBggqhkjOPQQDAgNoADBlAjEAlznFL0Nrt1jjZrT3/GN0 +yN/8gxO3SawyqoWrfP3uk1GScTh0PlrTEOrpSyuq3wl5AjBRntVI1ZoUM46pCwIw +0Vl3c3lns7OljcQFiR7o8yRhEW9ejdiR2W6PLBrjCly6U3I= +-----END CERTIFICATE----- +`; + +// A multi-valued RDN and serial number 0. +const MULTI = `-----BEGIN CERTIFICATE----- +MIICNzCCAaCgAwIBAgIBADANBgkqhkiG9w0BAQsFADA3MSgwCgYDVQQLDANyZG4w +DAYDVQQDDAVtdWx0aTAMBgNVBAoMBXRocmVlMQswCQYDVQQGEwJERTAeFw0yNjEw +MjExNjM0MDVaFw0yNjEwMzExNjM0MDVaMDcxKDAKBgNVBAsMA3JkbjAMBgNVBAMM +BW11bHRpMAwGA1UECgwFdGhyZWUxCzAJBgNVBAYTAkRFMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDdv64EOPdpcWdjVMAlEQvNzm3ZbQYXrhOwRF9yzQp25SuA +3uKvStZOt8hyTifAd30oDXIfgyYI39xKHEkHfARTV1E2Jwyiz86/pDHmFypPFJuI +v/vOjYLLeisiVi8TFfHgmoGqGvySR83fwiUnoOOWj9Bqt/5EVBQbBeWrU9qH6QID +AQABo1MwUTAdBgNVHQ4EFgQUZrGU0gkgqCkmegRtu6vQ3h7kpPUwHwYDVR0jBBgw +FoAUZrGU0gkgqCkmegRtu6vQ3h7kpPUwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG +9w0BAQsFAAOBgQAMzFkzJElc9VJYhGx7AngO8Yve22iCTOVLO3/be8w55klb/HJX +vfESQz+EJLYVaP5Q/uChoE0I27NytkeUSpJFwmjyqoQq2j6kJWGKONqhQSnXDrms +HMPA7iik/C5hOqpwzDZ98wNU/e86TrqZxzpFkwbnZx9MSfiGr690s5BfpA== +-----END CERTIFICATE----- +`; + +// An Ed25519 certificate with otherName, directoryName, registeredID and IPv6 names, a BMPString subject, a negative serial and keyUsage without keyCertSign. +const NAMES = `-----BEGIN CERTIFICATE----- +MIICSDCCAfqgAwIBAgIB+zAFBgMrZXAwLDEVMBMGA1UEAx4MAGIAbQBwACAA6U4t +MRMwEQYDVQQKHgoAcABsAGEAaQBuMB4XDTI2MTAyMTE2NDQzM1oXDTI2MTEyMDE2 +NDQzM1owLDEVMBMGA1UEAx4MAGIAbQBwACAA6U4tMRMwEQYDVQQKHgoAcABsAGEA +aQBuMCowBQYDK2VwAyEAP+2Vcp8nwu2AhFvSczYTxGs1jV/ckA76Jqvwj9QDGqij +ggE/MIIBOzCBtwYDVR0RBIGvMIGsoBsGCisGAQQBgjcUAgOgDQwLdXNlckBkb21h +aW6gEAYDKgMEoAkMB3Vua25vd26kRTBDMQswCQYDVQQGEwJVSzEZMBcGA1UECh4Q +AEQAaQByACwAIABPAHIAZzEZMBcGA1UEAx4QAGQAaQByACAAbgBhAG0AZYgEKgME +BYcQ/oAAAAAAAAAAAAAAAAEAAocQIAENuAAAAAAAAP8AAEKDKYYKaHR0cDovL3gv +cTAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIHgDBFBggrBgEFBQcBAQQ5MDcwIAYI +KwYBBQUHMAWGFGh0dHA6Ly9yZXBvLmV4YW1wbGUvMBMGBCoDBAWCC29kZC5leGFt +cGxlMB0GA1UdDgQWBBQYMJ0fQJ1Nx0PmatIfTJusAEA9WTAFBgMrZXADQQCixubE +nuunBZYYPXF52+joQSX/a5DFkOEDmzRTuH7IIpPFWPo37rmJOSdPA/PV8v9clzYF +LP3EjM4YOAatcbsO +-----END CERTIFICATE----- +`; + +// An RSA-PSS signature and a control character in the subject. +const PSS = `-----BEGIN CERTIFICATE----- +MIIDdTCCAiigAwIBAgICAIAwQgYJKoZIhvcNAQEKMDWgDzANBglghkgBZQMEAgEF +AKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEFAKIEAgIA3jAeMQwwCgYDVQQD +DANwc3MxDjAMBgNVBAoMBWN0bAF4MB4XDTI2MTAyMTE2NDQzM1oXDTI2MTEyMDE2 +NDQzM1owHjEMMAoGA1UEAwwDcHNzMQ4wDAYDVQQKDAVjdGwBeDCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAL2pno8Ybwihdv3hnMhWPPt85SXQmFAJpFoS +E+sT9H6FbwFCIyPkY+SWk8H7y8V+D+388tNvJZmGjX3uvWpK2Wx6anSB3/WMpkUR +2ExP4cpSxZNr9EFzC/cdqLvsxJcHMHkc/uJuFbtjsuiH1ygOe3nyhWSNiPwGdwHE +cKkBFkzW3j2C/4Jkgt4k+sMe3gy5litKtMi4zZB8ixCm5oGhveGhUZy0Kb01twgZ +RP4FEd32sSRqq3NCx4cB0kyreTuzmk6U7BkxcdPzaj6DifjRznTQmjMdoCNZQRCj +G3KBOMHHyvmV2B4lNGDuMlcSap/TpYq7n32AH5sDvELrUnPwVzsCAwEAAaNTMFEw +HQYDVR0OBBYEFC/QJvAQsbQ25sErc1To2G1VuNZ0MB8GA1UdIwQYMBaAFC/QJvAQ +sbQ25sErc1To2G1VuNZ0MA8GA1UdEwEB/wQFMAMBAf8wQgYJKoZIhvcNAQEKMDWg +DzANBglghkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEFAKIE +AgIA3gOCAQEAu3lP2Q3Bb5fWUQtgFr/82Oke1ZRW/GRbj03mZ30izADHC7yk0OYm +02f7B5sub04Jk6yuRVmEBjJHSPNwAo0RJWtwvD77KLhG8aObr7Z3+pkfFvpGzqeS +MQ4FtK2MPps3kA1a5D4XLwkwDJtHWZVuVyXpPgxkptfLzZgrieKrpNyOKR8Pz/PO +Wlwv6bF7SXvAV8Vrd7KDvTqwQ5iq9UFhP6GeMDWezYtzLdjlvje7MhmZ96zgSY6m +qumNWOPHmiN4eoOE4M69B+0fa3WyMzubW0nVGM/sDhtS0k5zHs6Y4RLn11HolhXH +LvbvDgqtl/m5i0uHxEld+Z1uhzJscqFQRg== +-----END CERTIFICATE----- +`; + +// A version 1 certificate without extensions. +const V1 = `-----BEGIN CERTIFICATE----- +MIIBSTCB7wIUI3kYI5NpR07YqZe6RwOx22je9IowCgYIKoZIzj0EAwIwJzERMA8G +A1UECgwITGVhZiBPcmcxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0yNjEwMjExNjMz +NTJaFw0yNjExMjAxNjMzNTJaMCcxETAPBgNVBAoMCExlYWYgT3JnMRIwEAYDVQQD +DAlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASVX1cvRB/1R0Lk +aqRRZ15NBdNJ3A4begD4FTw6MmyvBz5XDOE+R9cgDjB55R9vSytY7TKlNWgDookE +cz3Qr6qLMAoGCCqGSM49BAMCA0kAMEYCIQCFfFOw9qzzfSOQO1zRnT0sOXibjLWl +hHDyqecxhY7gtQIhAPMgqg+p1JXV5bgGpqgDfP3sE53luxMGlnAC39uhwBUh +-----END CERTIFICATE----- +`; + + +function show(label: string, cert: crypto.X509Certificate): void { + console.log(label, "subject", JSON.stringify(cert.subject)); + console.log(label, "issuer", JSON.stringify(cert.issuer)); + console.log(label, "subjectAltName", JSON.stringify(cert.subjectAltName), typeof cert.subjectAltName); + console.log(label, "infoAccess", JSON.stringify(cert.infoAccess), cert.infoAccess === undefined); + console.log(label, "serialNumber", cert.serialNumber); + console.log(label, "fingerprints", cert.fingerprint, cert.fingerprint256); + console.log(label, "fingerprint512", cert.fingerprint512); + console.log(label, "ca", cert.ca); + console.log(label, "signature", cert.signatureAlgorithm, cert.signatureAlgorithmOid); + console.log(label, "validity", cert.validFrom, "|", cert.validTo); + console.log(label, "dates", cert.validFromDate.toISOString(), cert.validToDate.getTime()); + console.log(label, "raw", cert.raw.length, Buffer.isBuffer(cert.raw), cert.raw.subarray(0, 4).toString("hex")); +} + +const pems: [string, string][] = [ + ["ca", CA], + ["leaf", LEAF], + ["odd", ODD], + ["multi", MULTI], + ["names", NAMES], + ["pss", PSS], + ["v1", V1], +]; +for (const [label, pem] of pems) show(label, new crypto.X509Certificate(Buffer.from(pem))); + +// A PEM string, and the DER bytes of raw. +const fromString = new crypto.X509Certificate(LEAF); +show("string", fromString); +const fromDer = new crypto.X509Certificate(fromString.raw); +console.log("der", fromDer.subject === fromString.subject, fromDer.fingerprint256 === fromString.fingerprint256); +console.log("der raw copy", fromDer.raw !== fromString.raw, fromDer.raw.equals(fromString.raw)); + +try { + new crypto.X509Certificate(Buffer.from("not a certificate")); +} catch (e) { + const err = e as NodeJS.ErrnoException; + console.log("garbage", err.name, err.code); +} diff --git a/tests/corpus/7090-x509-check-names.ts b/tests/corpus/7090-x509-check-names.ts new file mode 100644 index 000000000..31ec7244f --- /dev/null +++ b/tests/corpus/7090-x509-check-names.ts @@ -0,0 +1,141 @@ +// X509Certificate.checkHost, checkEmail and checkIP match Node: the +// subject alternative names of the asked kind first, then the subject's +// common name or emailAddress when the certificate has none (or as the +// subject option says), the wildcard rules and their options, case rules, +// IPv4 and IPv6 parsing, and an invalid subject option. +import { X509Certificate, type X509CheckOptions } from "node:crypto"; + +// DNS names with every wildcard form, an IP address and an email name. +const WILD = `-----BEGIN CERTIFICATE----- +MIIB/TCCAaOgAwIBAgIBCTAKBggqhkjOPQQDAjAXMRUwEwYDVQQDDAwqLmNuLmV4 +YW1wbGUwIBcNMjYxMDIyMTAwMTMxWhgPMjEyNjA5MjgxMDAxMzFaMBcxFTATBgNV +BAMMDCouY24uZXhhbXBsZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABGJ1KKs0 +givD5gd5LXXbPc37WfT64D0ePORDm7dB9mxEYJ6K8IQxBKzn5xQT+e/lZZ1raRBZ +q/E8aW4cW1iZLXSjgd0wgdowgbgGA1UdEQSBsDCBrYIOZiouZXhhbXBsZS5jb22C +Dypvby5leGFtcGxlLm5ldIIXKi54bi0tYmNoZXIta3ZhLmV4YW1wbGWCDXhuLS0q +LmV4YW1wbGWCBSouY29tgg9hLiouZXhhbXBsZS5vcmeCASqCDyouTWl4ZWQuRXhh +bXBsZYIMLmRvdC5leGFtcGxlgg9iKnouZXhhbXBsZS5lZHWHBMCoAQGBEU1peGVk +QEV4YW1wbGUuQ09NMB0GA1UdDgQWBBR8lJ0Uw8GcVD1cGUSprHt346HjDDAKBggq +hkjOPQQDAgNIADBFAiALkTbNe6bIavd8T9qKlAqzmEPQrFRZUVoOHSQPI/zV5QIh +AM0et8JtbWP+4ySiUPPqCXtlup00GfhcqGXy+lSl32vL +-----END CERTIFICATE----- +`; + +// No alternative names; the subject has a wildcard CN and an emailAddress. +const CN = `-----BEGIN CERTIFICATE----- +MIIBVDCB+gIBCjAKBggqhkjOPQQDAjA1MRcwFQYDVQQDDA5zZWNvbmQuZXhhbXBs +ZTEaMBgGCSqGSIb3DQEJARYLYUBiLmV4YW1wbGUwIBcNMjYxMDIyMTAwMTMxWhgP +MjEyNjA5MjgxMDAxMzFaMDUxFzAVBgNVBAMMDnNlY29uZC5leGFtcGxlMRowGAYJ +KoZIhvcNAQkBFgthQGIuZXhhbXBsZTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IA +BGJ1KKs0givD5gd5LXXbPc37WfT64D0ePORDm7dB9mxEYJ6K8IQxBKzn5xQT+e/l +ZZ1raRBZq/E8aW4cW1iZLXQwCgYIKoZIzj0EAwIDSQAwRgIhAIE0IFtuCNllBodV +go5WWgb8h1McrS/o31V5K0JrpF7QAiEAil8AEHuMiVtef/txZsEKPPojDKfPTYC8 +zplMuFd9gQA= +-----END CERTIFICATE----- +`; + +// A leaf with DNS, email, IPv4, IPv6 and URI names. +const LEAF = `-----BEGIN CERTIFICATE----- +MIIDqjCCApKgAwIBAgICCwswDQYJKoZIhvcNAQELBQAwPjELMAkGA1UEBhMCVVMx +FDASBgNVBAoMC0V4YW1wbGUgT3JnMRkwFwYDVQQDDBBFeGFtcGxlIFJTQSBSb290 +MCAXDTI2MTAyMjA5NDY0MVoYDzIxMjYwOTI4MDk0NjQxWjBfMQswCQYDVQQGEwJV +UzEUMBIGA1UECgwLRXhhbXBsZSBPcmcxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNv +bTEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBsZS5jb20wWTATBgcqhkjOPQIB +BggqhkjOPQMBBwNCAARidSirNIIrw+YHeS112z3N+1n0+uA9HjzkQ5u3QfZsRGCe +ivCEMQSs5+cUE/nv5WWda2kQWavxPGluHFtYmS10o4IBWDCCAVQwCQYDVR0TBAIw +ADALBgNVHQ8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHsG +A1UdEQR0MHKCDSouZXhhbXBsZS5jb22CC2V4YW1wbGUuY29tghV4bi0tYmNoZXIt +a3ZhLmV4YW1wbGWBD29wc0BleGFtcGxlLmNvbYcECgAAAYcQIAENuAAAAAAAAAAA +AAAAAYYUaHR0cHM6Ly9leGFtcGxlLmNvbS8wXgYIKwYBBQUHAQEEUjBQMCQGCCsG +AQUFBzABhhhodHRwOi8vb2NzcC5leGFtcGxlLmNvbS8wKAYIKwYBBQUHMAKGHGh0 +dHA6Ly9jYS5leGFtcGxlLmNvbS9jYS5jcnQwHQYDVR0OBBYEFHyUnRTDwZxUPVwZ +RKmse3fjoeMMMB8GA1UdIwQYMBaAFAgaWVveRbA7VKqcHzjMqBPzi1/LMA0GCSqG +SIb3DQEBCwUAA4IBAQAfMTcpidoH47PXOQVxRttfrG7K9BcntyXP4+5hUAoSfMr6 +Rxy7X/9ba7R0yCGlNsUCusObaBpbdvwX8v9TiTYKVL+C9rEVGrTHnh6kbgZaaCQc +L3oWbfRrYnEBYuSlFuadjVvX42aqzHV28E4ITgywCxwubu2hAbacbcUHpnRSqLDq +lV+VZSQA/6cPNct7PR6AkJU80D+5wVOk7RVi4rsfbw1wFDeksCHu+0EThs9zjzL+ +S7HTCjB6AOHpbu1Sx+0d5YEKSE7EPF+dSFATNbhjTHzYQySnHK+Lm8nON8wmY1rC +7opOhvUlid1jA1d2BKO2ZxlxLir4pyIehTC1ddG2 +-----END CERTIFICATE----- +`; + +// A self-signed certificate without alternative names. +const PLAIN = `-----BEGIN CERTIFICATE----- +MIIC8jCCAdoCAQcwDQYJKoZIhvcNAQELBQAwPjEaMBgGA1UEAwwRcGxhaW4uZXhh +bXBsZS5vcmcxIDAeBgkqhkiG9w0BCQEWEXBsYWluQGV4YW1wbGUub3JnMCAXDTI2 +MTAyMjA5NDY0MVoYDzIxMjYwOTI4MDk0NjQxWjA+MRowGAYDVQQDDBFwbGFpbi5l +eGFtcGxlLm9yZzEgMB4GCSqGSIb3DQEJARYRcGxhaW5AZXhhbXBsZS5vcmcwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCq01NcNAy9Ng04mVuAFvmZUvsm +rY7aOaMgtODmptulgZ2qw25E09RgGYCn1S+4IYDu9hH9X4s+28Ag7Khmj4nmeoXN +of5095wche8DR2AAUElqyr/Nmgm2kTLdIJX4wl0eWXHIlmSPdOUNovA6JjGKH99b +8W7a2TqY/TsSadpPSvvN2esr7Jr4KgW7MXPUOnwNbcBOVcQP9rtFrduAWz01q0HM +02LboclnUnk/e58BXAj8vgdVojljDcc0bhbdz/Hh1/5gaaNILjJNOd4AgwZaCT02 +KojGz4Nb6MSgFmON2iMgAZjY1fXXkJ7wsfVPytjW73e7uV/RFuqSHQZenxupAgMB +AAEwDQYJKoZIhvcNAQELBQADggEBAJX1DGuiSLoCKBDI3oCgAu7X86G01ovEgZJr +8JrmGHW5q7ujjo53t46h8XPm3LJ8UV9/MZ+Yry43xB2txXYv3b3g/i+7JdTWLgUD +INA5VWvVkEZfm0lBEpU1Agpy4lV5uUCKZTgP/3MY5hnJ0YhQIs4BOjbwueMRFshL +yyHVb73MMbpWaZ7+T368seafa+ekeuY6gQly/HacuszjoYd6KKV3n8eDewenClCF +HoOF1Y4I+CvmR+a6B3iBczJ+a4tceFIIWsZUIeqzvGHpM7G9YwlmbvGprfLgR8Nv +igUib/D9tU3hdL6VWN5nMjdXV/8Le4nDnBjVBjYDkVbsnmT91AQ= +-----END CERTIFICATE----- +`; + +const wild = new X509Certificate(WILD); +const cn = new X509Certificate(Buffer.from(CN)); +const leaf = new X509Certificate(LEAF); +const plain = new X509Certificate(PLAIN); + +const hosts = [ + "foo.example.com", "f.example.com", "fx.example.com", "a.b.example.com", "foo.example.net", + "oo.example.net", "x.xn--bcher-kva.example", "xn--abc.example", "example.com", + "a.b.example.org", "x", "a.mixed.example", "A.MIXED.EXAMPLE", "a.dot.example", ".dot.example", + "dot.example", "bz.example.edu", "baz.example.edu", "b.z.example.edu", "x.cn.example", + "second.example", "192.168.1.1", ".example.com", ".mixed.example", "a.b.mixed.example", +]; +const opts: [string, X509CheckOptions | undefined][] = [ + ["default", undefined], + ["nowild", { wildcards: false }], + ["nopartial", { partialWildcards: false }], + ["multi", { multiLabelWildcards: true }], + ["single", { singleLabelSubdomains: true }], + ["always", { subject: "always" }], + ["never", { subject: "never" }], +]; +for (const [label, o] of opts) { + console.log(label, hosts.map((h) => `${h}=${wild.checkHost(h, o)}`).join(" ")); + console.log(label, "cn", hosts.map((h) => `${h}=${cn.checkHost(h, o)}`).join(" ")); +} + +for (const h of ["www.example.com", "example.com", "EXAMPLE.COM", "xn--bcher-kva.example", "", "foo.example.com."]) { + console.log("leaf", JSON.stringify(h), leaf.checkHost(h), leaf.checkHost(h, { subject: "always" })); +} +console.log("plain", plain.checkHost("plain.example.org"), plain.checkHost("plain.example.org", { subject: "never" })); +const found: string | undefined = leaf.checkHost("api.example.com"); +console.log("typed", found === undefined ? "none" : found.toUpperCase()); + +for (const e of ["Mixed@example.com", "mixed@example.com", "Mixed@EXAMPLE.COM", "a@b.example", "a@B.EXAMPLE", "A@b.example"]) { + console.log("email", e, wild.checkEmail(e), cn.checkEmail(e), cn.checkEmail(e, { subject: "never" })); +} +for (const e of ["ops@example.com", "OPS@EXAMPLE.COM", "admin@example.com"]) console.log("email", e, leaf.checkEmail(e)); +console.log("email plain", plain.checkEmail("plain@example.org"), plain.checkEmail("plain@example.org", { subject: "always" })); + +const ips = [ + "192.168.1.1", "192.168.001.001", "192.168.1.1.", "1.2.3", "::", "::ffff:192.168.1.1", + "0:0:0:0:0:0:0:0", "1::2::3", "fe80::1%eth0", " 192.168.1.1", "192.168.1.256", + "10.0.0.1", "2001:db8::1", "2001:DB8:0:0:0:0:0:1", "2001:db8:0::0:1", "::ffff:10.0.0.1", "", +]; +for (const ip of ips) { + try { + console.log("ip", JSON.stringify(ip), wild.checkIP(ip), leaf.checkIP(ip)); + } catch (e) { + const err = e as NodeJS.ErrnoException; + console.log("ip", JSON.stringify(ip), err.name, err.code, err.message); + } +} + +try { + leaf.checkHost("www.example.com", { subject: "sometimes" as "always" }); +} catch (e) { + const err = e as NodeJS.ErrnoException; + console.log("subject", err.name, err.code, err.message); +} diff --git a/tests/corpus/7091-x509-certificate-keys.ts b/tests/corpus/7091-x509-certificate-keys.ts new file mode 100644 index 000000000..b9b89ae1e --- /dev/null +++ b/tests/corpus/7091-x509-certificate-keys.ts @@ -0,0 +1,332 @@ +// X509Certificate.publicKey, verify, checkIssued and checkPrivateKey match +// Node: the public key as a cached KeyObject, signature checks for RSA +// PKCS#1, RSA-PSS, ECDSA and Ed25519 signatures, issuer checks by name, +// key identifier and key type, private key matches, and the pkey errors. +import { + X509Certificate, + constants, + createPrivateKey, + createPublicKey, + createSecretKey, + generateKeyPairSync, + sign, + verify, + type KeyObject, +} from "node:crypto"; + +// An RSA root and the EC leaf it signed. +const ROOT = `-----BEGIN CERTIFICATE----- +MIIDPTCCAiWgAwIBAgIDChHOMA0GCSqGSIb3DQEBCwUAMD4xCzAJBgNVBAYTAlVT +MRQwEgYDVQQKDAtFeGFtcGxlIE9yZzEZMBcGA1UEAwwQRXhhbXBsZSBSU0EgUm9v +dDAgFw0yNjEwMjIwOTQ2NDFaGA8yMTI2MDkyODA5NDY0MVowPjELMAkGA1UEBhMC +VVMxFDASBgNVBAoMC0V4YW1wbGUgT3JnMRkwFwYDVQQDDBBFeGFtcGxlIFJTQSBS +b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwsfidupnXQcn8PUF +XaCKRYw8XKI1GUn29U5/IUGjAnJVaRmcB6BPTmblbKt4y7gLvU4h1Hxuypx8FZSZ +30eZOS1ixyrymDthG5zUHqzXk5zAGsNvZeXjN3YxTC9vX5CpQ9Uz2i+bLOi3PJsE +qyKVZ+GGT9fpIaALG11YrWmXTUko/a0AKGot0w8O/RaMpXQpkbeyTBF6f4pHNMqx +QGy+KlpC/+yIJ9psT6qyU33HF3Wa+DOy+0txAFEQNw9m1j7adOLnU0zBpkM/bnP2 +fSwxMkDB2Di2P5H6PkdqLT4zBf/BLdg7WqpxxSqqgVmaSXhEqUQ6xjf51yLR3wy/ +xBWhMQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd +BgNVHQ4EFgQUCBpZW95FsDtUqpwfOMyoE/OLX8swDQYJKoZIhvcNAQELBQADggEB +AChUtpNi8dPPxA4sf4EpZhEcYBN53X3WUcG3KJGtSf8JbPKru9lK9O+sZtJADbph +WoMPdWh8g+fEMk5D6l8Y5pDk/OR++oWNY7XCLFNyigmUGn+4SopJynBQiDk2dYPV +b6swDPPiV85TuAHVn79l766rtFdHdYwRe5HvfEkiXax7Egonlx7NR73xxm/XgvHQ +jhKbTZN9k/DEjkQuo5rt9ldVupUMM0iMhDMKX5oWEx9nvRwHPbjESS+Shy/FA4nA +2WHWO++4IU+imO40an1B/8SmFF+X9hj3UE6qaZLynVZRUiouBZibwZCcdCpibFM3 +kmB2s+NZXRvzhCjIxO97Ib4= +-----END CERTIFICATE----- +`; +const LEAF = `-----BEGIN CERTIFICATE----- +MIIDqjCCApKgAwIBAgICCwswDQYJKoZIhvcNAQELBQAwPjELMAkGA1UEBhMCVVMx +FDASBgNVBAoMC0V4YW1wbGUgT3JnMRkwFwYDVQQDDBBFeGFtcGxlIFJTQSBSb290 +MCAXDTI2MTAyMjA5NDY0MVoYDzIxMjYwOTI4MDk0NjQxWjBfMQswCQYDVQQGEwJV +UzEUMBIGA1UECgwLRXhhbXBsZSBPcmcxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNv +bTEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBsZS5jb20wWTATBgcqhkjOPQIB +BggqhkjOPQMBBwNCAARidSirNIIrw+YHeS112z3N+1n0+uA9HjzkQ5u3QfZsRGCe +ivCEMQSs5+cUE/nv5WWda2kQWavxPGluHFtYmS10o4IBWDCCAVQwCQYDVR0TBAIw +ADALBgNVHQ8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHsG +A1UdEQR0MHKCDSouZXhhbXBsZS5jb22CC2V4YW1wbGUuY29tghV4bi0tYmNoZXIt +a3ZhLmV4YW1wbGWBD29wc0BleGFtcGxlLmNvbYcECgAAAYcQIAENuAAAAAAAAAAA +AAAAAYYUaHR0cHM6Ly9leGFtcGxlLmNvbS8wXgYIKwYBBQUHAQEEUjBQMCQGCCsG +AQUFBzABhhhodHRwOi8vb2NzcC5leGFtcGxlLmNvbS8wKAYIKwYBBQUHMAKGHGh0 +dHA6Ly9jYS5leGFtcGxlLmNvbS9jYS5jcnQwHQYDVR0OBBYEFHyUnRTDwZxUPVwZ +RKmse3fjoeMMMB8GA1UdIwQYMBaAFAgaWVveRbA7VKqcHzjMqBPzi1/LMA0GCSqG +SIb3DQEBCwUAA4IBAQAfMTcpidoH47PXOQVxRttfrG7K9BcntyXP4+5hUAoSfMr6 +Rxy7X/9ba7R0yCGlNsUCusObaBpbdvwX8v9TiTYKVL+C9rEVGrTHnh6kbgZaaCQc +L3oWbfRrYnEBYuSlFuadjVvX42aqzHV28E4ITgywCxwubu2hAbacbcUHpnRSqLDq +lV+VZSQA/6cPNct7PR6AkJU80D+5wVOk7RVi4rsfbw1wFDeksCHu+0EThs9zjzL+ +S7HTCjB6AOHpbu1Sx+0d5YEKSE7EPF+dSFATNbhjTHzYQySnHK+Lm8nON8wmY1rC +7opOhvUlid1jA1d2BKO2ZxlxLir4pyIehTC1ddG2 +-----END CERTIFICATE----- +`; +// A self-signed RSA certificate and a self-signed Ed25519 certificate. +const PLAIN = `-----BEGIN CERTIFICATE----- +MIIC8jCCAdoCAQcwDQYJKoZIhvcNAQELBQAwPjEaMBgGA1UEAwwRcGxhaW4uZXhh +bXBsZS5vcmcxIDAeBgkqhkiG9w0BCQEWEXBsYWluQGV4YW1wbGUub3JnMCAXDTI2 +MTAyMjA5NDY0MVoYDzIxMjYwOTI4MDk0NjQxWjA+MRowGAYDVQQDDBFwbGFpbi5l +eGFtcGxlLm9yZzEgMB4GCSqGSIb3DQEJARYRcGxhaW5AZXhhbXBsZS5vcmcwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCq01NcNAy9Ng04mVuAFvmZUvsm +rY7aOaMgtODmptulgZ2qw25E09RgGYCn1S+4IYDu9hH9X4s+28Ag7Khmj4nmeoXN +of5095wche8DR2AAUElqyr/Nmgm2kTLdIJX4wl0eWXHIlmSPdOUNovA6JjGKH99b +8W7a2TqY/TsSadpPSvvN2esr7Jr4KgW7MXPUOnwNbcBOVcQP9rtFrduAWz01q0HM +02LboclnUnk/e58BXAj8vgdVojljDcc0bhbdz/Hh1/5gaaNILjJNOd4AgwZaCT02 +KojGz4Nb6MSgFmON2iMgAZjY1fXXkJ7wsfVPytjW73e7uV/RFuqSHQZenxupAgMB +AAEwDQYJKoZIhvcNAQELBQADggEBAJX1DGuiSLoCKBDI3oCgAu7X86G01ovEgZJr +8JrmGHW5q7ujjo53t46h8XPm3LJ8UV9/MZ+Yry43xB2txXYv3b3g/i+7JdTWLgUD +INA5VWvVkEZfm0lBEpU1Agpy4lV5uUCKZTgP/3MY5hnJ0YhQIs4BOjbwueMRFshL +yyHVb73MMbpWaZ7+T368seafa+ekeuY6gQly/HacuszjoYd6KKV3n8eDewenClCF +HoOF1Y4I+CvmR+a6B3iBczJ+a4tceFIIWsZUIeqzvGHpM7G9YwlmbvGprfLgR8Nv +igUib/D9tU3hdL6VWN5nMjdXV/8Le4nDnBjVBjYDkVbsnmT91AQ= +-----END CERTIFICATE----- +`; +const ED = `-----BEGIN CERTIFICATE----- +MIIBljCCAUigAwIBAgIUNFuRt3zKS19UAUMdLWewqHrGBigwBQYDK2VwMC8xFDAS +BgNVBAoMC0V4YW1wbGUgT3JnMRcwFQYDVQQDDA5lZC5leGFtcGxlLm5ldDAgFw0y +NjEwMjIxMDEwMTJaGA8yMTI2MDkyODEwMTAxMlowLzEUMBIGA1UECgwLRXhhbXBs +ZSBPcmcxFzAVBgNVBAMMDmVkLmV4YW1wbGUubmV0MCowBQYDK2VwAyEAOCSLKkel +kOH/5aqUwI3PNJVUUNyhgu2s19LFC254fNCjdDByMB0GA1UdDgQWBBR+50zUcqL8 +739jh6/rEYojULDmlTAfBgNVHSMEGDAWgBR+50zUcqL8739jh6/rEYojULDmlTAP +BgNVHRMBAf8EBTADAQH/MB8GA1UdEQQYMBaCDmVkLmV4YW1wbGUubmV0hwTAAAIH +MAUGAytlcANBAC/c0Bi0SVUnHCg/1pn7MaCgVivSHuoISi2SCq/0EnLefRdgsIir +0QxjVnxeuKN2Y1yfEO/R1W8Nwovo1l2M1gQ= +-----END CERTIFICATE----- +`; +// A second RSA root with its EC leaf, a self-signed RSA-PSS certificate +// and a self-signed v1 certificate with the second leaf's subject. +const ROOT2 = `-----BEGIN CERTIFICATE----- +MIIEITCCAwmgAwIBAgIIASNFZ4mrze8wDQYJKoZIhvcNAQELBQAwgZwxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNp +c2NvMRQwEgYDVQQKDAtFeGFtcGxlIE9yZzERMA8GA1UECwwIRGV2IFRlYW0xGDAW +BgNVBAMMD0V4YW1wbGUgUm9vdCBDQTEdMBsGCSqGSIb3DQEJARYOY2FAZXhhbXBs +ZS5jb20wIBcNMjYxMDIxMTYzMzUyWhgPMjEyNjA5MjcxNjMzNTJaMIGcMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j +aXNjbzEUMBIGA1UECgwLRXhhbXBsZSBPcmcxETAPBgNVBAsMCERldiBUZWFtMRgw +FgYDVQQDDA9FeGFtcGxlIFJvb3QgQ0ExHTAbBgkqhkiG9w0BCQEWDmNhQGV4YW1w +bGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0YGcCr0pxR8d +6qDdLuILcoT7vhtAjyHwfkoChnH6N3TLWzDUugnBp9NbDb7gDLqbRT4uTDoNb6zS +tEJZ4Q7/hhd0jDvoPmOy0Y3Kyj9uNsdf25GdbvwwEnlddELJCZprTZ4OhEg6w2s0 +Yy4SlviLzDXLmsggTypxeS+K8JHT9onMipi5L4GFu8n1QZbzXvSS4BkRgMXEyrtr +FOE9qSo2qkubFyd/WNKRTRIpTSc5/GGsqJ0FKDDJnN5adotcUucbJFn4noNnFUWh +M8mhBEj7ENDdJsD2EVFsI6H958jA2SbNNu4ngzAOs2AKNBYBfQK02ZQAdRNOSL3K +5FkfbII5LwIDAQABo2MwYTAdBgNVHQ4EFgQUP+yQyItpNYEls26Jfv+NnciGaK8w +HwYDVR0jBBgwFoAUP+yQyItpNYEls26Jfv+NnciGaK8wDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBABDw3Va/C+RFc/Hs +TJnHtQJtxFL0ZhnHUqg4DcDA3m+JDdIDNL8sNpLEbtn/pr0VeEWgG+MImWAQlrUW +IAZkLj9/Zg1wSO0oZ86ZyZJZmp54lUYXgG17CNl4g+F7VHt3bBwUJHTbWye/FKM6 +5OVZetCYKVj7Z+5BYuf7cumzvRqcn32fXidB/kjRX14SJ4JDPn2yFZWCr2ygIqWQ +SOuEmWbNAbYGaVZkQr2Ma8U28DWY2jb0f6nP8jLt49t9o6N/e6Fwd6I5t/mx9Mfj +0403omkxmr9vqN2kBamzVnun+2mDkRZcKPCr72Q4sfbvmDi/W5Nf1Iu2cQW8VfDO +SqpyT54= +-----END CERTIFICATE----- +`; +const LEAF2 = `-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIPAPAN+s4AESIzRFVmd4iZMA0GCSqGSIb3DQEBDAUAMIGc +MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2Fu +IEZyYW5jaXNjbzEUMBIGA1UECgwLRXhhbXBsZSBPcmcxETAPBgNVBAsMCERldiBU +ZWFtMRgwFgYDVQQDDA9FeGFtcGxlIFJvb3QgQ0ExHTAbBgkqhkiG9w0BCQEWDmNh +QGV4YW1wbGUuY29tMB4XDTI2MTAyMTE2MzM1MloXDTM2MTAxODE2MzM1MlowJzER +MA8GA1UECgwITGVhZiBPcmcxEjAQBgNVBAMMCWxvY2FsaG9zdDBZMBMGByqGSM49 +AgEGCCqGSM49AwEHA0IABJVfVy9EH/VHQuRqpFFnXk0F00ncDht6APgVPDoybK8H +PlcM4T5H1yAOMHnlH29LK1jtMqU1aAOiiQRzPdCvqoujggE3MIIBMzAJBgNVHRME +AjAAMGgGA1UdEQRhMF+CCWxvY2FsaG9zdIINKi5leGFtcGxlLmNvbYcEfwAAAYcQ +AAAAAAAAAAAAAAAAAAAAAYERYWRtaW5AZXhhbXBsZS5jb22GGGh0dHBzOi8vZXhh +bXBsZS5jb20vcGF0aDBdBggrBgEFBQcBAQRRME8wIwYIKwYBBQUHMAGGF2h0dHA6 +Ly9vY3NwLmV4YW1wbGUuY29tMCgGCCsGAQUFBzAChhxodHRwOi8vY2EuZXhhbXBs +ZS5jb20vY2EuY3J0MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNV +HQ4EFgQUdKIx6ULFLPNP/kzwUFjSa5D19RswHwYDVR0jBBgwFoAUP+yQyItpNYEl +s26Jfv+NnciGaK8wDQYJKoZIhvcNAQEMBQADggEBABmQ8f2VsXNaMM9X1MEhi27D +LjwcOaaGEINNZq7xu/HL6UljMb1Odsuz66DkiH3Exd3MrWy6OlOpJJF0VzsqMsoD +0CRBxXF28o6Jil3vOGVwlYNmRidpkAkj4VyWDvv8FCS9VbsBtXaSHwu9wcCwePE0 +cGJRfTKoZ6KJ8vQ57DBEZ/ZszuhehOZYqrTmoUdjZ123kXdxQvK+ALn4SlIXHBhN +9unhd+8i00EmkXO/REw8paMcMVVGR+ioOEjyNHqZo6vkRqgpKggn1Yq8cTTDOMnS +P1o42EQZLlbuvx0kqInBqwqjDx4nZiPaifoDc9BF6iZPBvm8dhrEfghfB1tkNk0= +-----END CERTIFICATE----- +`; +const PSS = `-----BEGIN CERTIFICATE----- +MIIDdTCCAiigAwIBAgICAIAwQgYJKoZIhvcNAQEKMDWgDzANBglghkgBZQMEAgEF +AKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEFAKIEAgIA3jAeMQwwCgYDVQQD +DANwc3MxDjAMBgNVBAoMBWN0bAF4MB4XDTI2MTAyMTE2NDQzM1oXDTI2MTEyMDE2 +NDQzM1owHjEMMAoGA1UEAwwDcHNzMQ4wDAYDVQQKDAVjdGwBeDCCASIwDQYJKoZI +hvcNAQEBBQADggEPADCCAQoCggEBAL2pno8Ybwihdv3hnMhWPPt85SXQmFAJpFoS +E+sT9H6FbwFCIyPkY+SWk8H7y8V+D+388tNvJZmGjX3uvWpK2Wx6anSB3/WMpkUR +2ExP4cpSxZNr9EFzC/cdqLvsxJcHMHkc/uJuFbtjsuiH1ygOe3nyhWSNiPwGdwHE +cKkBFkzW3j2C/4Jkgt4k+sMe3gy5litKtMi4zZB8ixCm5oGhveGhUZy0Kb01twgZ +RP4FEd32sSRqq3NCx4cB0kyreTuzmk6U7BkxcdPzaj6DifjRznTQmjMdoCNZQRCj +G3KBOMHHyvmV2B4lNGDuMlcSap/TpYq7n32AH5sDvELrUnPwVzsCAwEAAaNTMFEw +HQYDVR0OBBYEFC/QJvAQsbQ25sErc1To2G1VuNZ0MB8GA1UdIwQYMBaAFC/QJvAQ +sbQ25sErc1To2G1VuNZ0MA8GA1UdEwEB/wQFMAMBAf8wQgYJKoZIhvcNAQEKMDWg +DzANBglghkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEFAKIE +AgIA3gOCAQEAu3lP2Q3Bb5fWUQtgFr/82Oke1ZRW/GRbj03mZ30izADHC7yk0OYm +02f7B5sub04Jk6yuRVmEBjJHSPNwAo0RJWtwvD77KLhG8aObr7Z3+pkfFvpGzqeS +MQ4FtK2MPps3kA1a5D4XLwkwDJtHWZVuVyXpPgxkptfLzZgrieKrpNyOKR8Pz/PO +Wlwv6bF7SXvAV8Vrd7KDvTqwQ5iq9UFhP6GeMDWezYtzLdjlvje7MhmZ96zgSY6m +qumNWOPHmiN4eoOE4M69B+0fa3WyMzubW0nVGM/sDhtS0k5zHs6Y4RLn11HolhXH +LvbvDgqtl/m5i0uHxEld+Z1uhzJscqFQRg== +-----END CERTIFICATE----- +`; +const V1 = `-----BEGIN CERTIFICATE----- +MIIBSTCB7wIUI3kYI5NpR07YqZe6RwOx22je9IowCgYIKoZIzj0EAwIwJzERMA8G +A1UECgwITGVhZiBPcmcxEjAQBgNVBAMMCWxvY2FsaG9zdDAeFw0yNjEwMjExNjMz +NTJaFw0yNjExMjAxNjMzNTJaMCcxETAPBgNVBAoMCExlYWYgT3JnMRIwEAYDVQQD +DAlsb2NhbGhvc3QwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASVX1cvRB/1R0Lk +aqRRZ15NBdNJ3A4begD4FTw6MmyvBz5XDOE+R9cgDjB55R9vSytY7TKlNWgDookE +cz3Qr6qLMAoGCCqGSM49BAMCA0kAMEYCIQCFfFOw9qzzfSOQO1zRnT0sOXibjLWl +hHDyqecxhY7gtQIhAPMgqg+p1JXV5bgGpqgDfP3sE53luxMGlnAC39uhwBUh +-----END CERTIFICATE----- +`; + +const ROOT_KEY = `-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDCx+J26mddByfw +9QVdoIpFjDxcojUZSfb1Tn8hQaMCclVpGZwHoE9OZuVsq3jLuAu9TiHUfG7KnHwV +lJnfR5k5LWLHKvKYO2EbnNQerNeTnMAaw29l5eM3djFML29fkKlD1TPaL5ss6Lc8 +mwSrIpVn4YZP1+khoAsbXVitaZdNSSj9rQAoai3TDw79FoyldCmRt7JMEXp/ikc0 +yrFAbL4qWkL/7Ign2mxPqrJTfccXdZr4M7L7S3EAURA3D2bWPtp04udTTMGmQz9u +c/Z9LDEyQMHYOLY/kfo+R2otPjMF/8Et2DtaqnHFKqqBWZpJeESpRDrGN/nXItHf +DL/EFaExAgMBAAECggEADsvlabgryvbYs2bBlhe0eU0KZtURqI6kWoUwhiO40N5D +m7zMzA2DCMcrRYKPJhagmaxeSIh9WBnkGTWVLM+BFcVbXBrom+Ti3xieSohBxh5h +v4a6Jyj8BkINw6ZU1RMlsJf5HOmB5br19H4oMCHr7JzGubkCpkHEpjsEmgPL8Rxs +LYb9palDyTD1z5xVAQDAkvnCYQMX2DsiH8RuO4Ih0OoWMIsAGasS1dTQCkOzN9wF +cMg+hmJvQLN5xLYI+VPy/iZn+bmerCx8/NQBrbo+zibmnv7cDK1U9emVD70/Nd1d +B7ZEm+a4gReaxWVQGEkFMvs29u/TDWXYRnw0PGjUYwKBgQDrmKEx+ZiZwNNk/S3l +s8FgVrLFDr/+t5X33jaD5nVuSN6/AoR3qfh9piIyCrdNKdHicAcCnWP6skUFYLq3 +/tyMBATX3j+f3PHW3i2ZUAK26hgfp66F/3IyowePZbBDlGSmGsffVlc8on5fCk1Q +k3G0znktbrMCNxeeY9GSi1CHewKBgQDTpled6pZepZ54OGnKVJFo6DbQC0l4HQ6y +Rwv9BMtAz+AxWXda1oYK5bbJZrCmHyVP85VxkzRHOMxicv7M2kR9y2zZsJD7INqr +Nvt+lo2yGtIGv7kOdwWzvs4Pn7aCWSApzYBjuKrpP1xDzaMHhusAQtkk77YGCZCu +cCAQ/FjEQwKBgBq/1KWI8lOauiXAPULUWwNmNJv9Jb10+LkQ6N2m//RKn8fOMF4p +1UXm5AEMiG1hbywnjhQ07JIdRYrrxad4b3ASUL51xIGRI4BC76h1lilQgPavIjii +nUO0kPouEIpLwfW+Gq137yW6SWDfGZIpe4KM4uNOq1J4EN1x9eyOltEbAoGAP4bj +L5QVFE2T1jPglQlzJ9DjeuiYYcQfACXRFF3XABolCcr3xz0yuJygk60OAp7AnVHY +nmF3xJToy/gGQMiW3Ect4d1cdvQyjkePjzxzRW1Fcx8i1ZOmE4CG6yueJVvJCqMT +EVuBeUc6U2Oqtnyplsd509tbgE5oreMbzN1ha28CgYAHpG10ZQRDeqWFIo/ttk6Q +Q1Gf53eqZFCgh8GO1hBJ7+Fp+Ec5S9UPMBDjZb6GET7ifF8Zit/lR4gN2PuELwJA +YaXTIehCugH7Q3oTjNcQtls6tW+/+jEGjbjSHyZvwk8EFHc0J7PWRszB36s+qM+O +YPorNipExSeWti1506ljLQ== +-----END PRIVATE KEY----- +`; +const LEAF_KEY = `-----BEGIN EC PRIVATE KEY----- +MHcCAQEEINqbifA6kN/DSN0cMD2s7fXiNtPXZqipFrbCs/3mCGbtoAoGCCqGSM49 +AwEHoUQDQgAEYnUoqzSCK8PmB3ktdds9zftZ9PrgPR485EObt0H2bERgnorwhDEE +rOfnFBP57+VlnWtpEFmr8TxpbhxbWJktdA== +-----END EC PRIVATE KEY----- +`; +const PLAIN_KEY = `-----BEGIN PRIVATE KEY----- +MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCq01NcNAy9Ng04 +mVuAFvmZUvsmrY7aOaMgtODmptulgZ2qw25E09RgGYCn1S+4IYDu9hH9X4s+28Ag +7Khmj4nmeoXNof5095wche8DR2AAUElqyr/Nmgm2kTLdIJX4wl0eWXHIlmSPdOUN +ovA6JjGKH99b8W7a2TqY/TsSadpPSvvN2esr7Jr4KgW7MXPUOnwNbcBOVcQP9rtF +rduAWz01q0HM02LboclnUnk/e58BXAj8vgdVojljDcc0bhbdz/Hh1/5gaaNILjJN +Od4AgwZaCT02KojGz4Nb6MSgFmON2iMgAZjY1fXXkJ7wsfVPytjW73e7uV/RFuqS +HQZenxupAgMBAAECggEAAxY5ACZHoaanpAFvbBfeMEVV2PvTZEGc30MtejWDLBE0 +yGhqJm++e3MShlXdnCHs2sSTDCVNFphxdxbXryzCVOobX10hRDtSNJi9+izwwOiy +fu3FfAFf0g77IJBNbXaTqK/8lJ+VFxuJZQ7v8NkOVZzgVCC/fFBnFOskhV9ozLx6 +Uk+5Rg/UFenUhhHqrzwxCLKR3TAX8pBdidmbJF61ypxt6Cn3pOA/pB1gUBi76nau +w4kefdNj8AXzSjzOfVEg0quywfeoOq6ESdy3p4RQMt6NZ3wnCgzr/uuWjVQzJbJU +Mg2TVlrKzbiinel2ZqKV8lpymhFTlRaWNzK7PzD91QKBgQDaSDpdQIk2+CJMAVzU +LsI5tdZa0cMDbAZzxBmg1W6kwIrMzYVeMo7RPBarhCuQ/3gJFVvA7LdvXR87BbYa +UuDXbvO4Gv+2wqxxX961sWK85VqhwAqXhFbkS9KNJ0twmlmAcX9lvl0Zn4ciO3c+ +AMJT4JN4WR6wI/dt1TCHLa1wtQKBgQDIV9bgKinpUzhSy9byTH0CwghwudAPx2CA +9gJ6VcjyUKeBdgJ0PQMTwppyrPs0fz+NgJ6+LiTvp9BS9vrXmtnjbD1oAxFcC9uU +NL7BJSRY+wgmnPgbldA25xq1TRJmB8YMr1CO4gYKGSNM7I1HlNv4dvMcS295RhTG +cdDkl4T7pQKBgQCzJmygdIMplmWvs76Ydvf5nYAcceR4PoTdJqlSE1oH5e8FP/ih +4yTMHWENzCBllQbTjbAMmzvCLs+fBYT7/eGDbxCgnagaO5SESIbk4H2FQ0grUQ5g +ZMFcBc79Aq8r78JdZMmGm8KVcRTbx6qKPN1BMiRWte416o78meiGSbr7sQKBgQCJ +2AY8TkZwB5ZlQWMva3lIAIEWLoL9mEzJ7npd+dA9CUl3Rd8CY0hOvELQTDy7LiJo +FesjJ1S6oFgx/UUyO5VXaQ4HFrVHA9Gc832cHxYXMwG0r6P2NuoAHJq/y7uxAABA +kg93gARvxkQHlWrPqZiAKDe1bCHS62k38O+tmKMjEQKBgHF7a9tqZVoc8CqUL/I8 +FXRMRmdzC4RoWC2NDqMazW9qxXpFZmPux1q9ds6ikoG0v3pAxZmRH0eMTIujtLPn +chtAnvTvkg5Q+/xa429PFThJ2b04zsHCmnzfdMaIPvqhBqoPmyAmptjUeMB+yzQU +d3AigXwTBk4l4yPleDD4qUbO +-----END PRIVATE KEY----- +`; +const ED_KEY = `-----BEGIN PRIVATE KEY----- +MC4CAQAwBQYDK2VwBCIEID8VP7HLPAW9FXkVxo3eYbqZ8zkXsPFi3c2RwdDdwy/O +-----END PRIVATE KEY----- +`; + +const certs: [string, X509Certificate][] = [ + ["root", new X509Certificate(ROOT)], + ["leaf", new X509Certificate(Buffer.from(LEAF))], + ["plain", new X509Certificate(PLAIN)], + ["ed", new X509Certificate(ED)], + ["root2", new X509Certificate(ROOT2)], + ["leaf2", new X509Certificate(LEAF2)], + ["pss", new X509Certificate(PSS)], + ["v1", new X509Certificate(V1)], +]; + +function describe(key: KeyObject): string { + const details = key.asymmetricKeyDetails ?? {}; + const size = key.asymmetricKeyType === "ed25519" ? "32 bytes" : `${details.modulusLength ?? details.namedCurve}`; + return `${key.type} ${key.asymmetricKeyType} ${size}`; +} + +for (const [name, cert] of certs) { + const key = cert.publicKey; + const spki = key.export({ type: "spki", format: "der" }); + console.log(name, describe(key), key === cert.publicKey, spki.length, createPublicKey(cert.toString()).equals(key)); +} + +for (const [name, cert] of certs) { + const by: string[] = []; + const issued: string[] = []; + for (const [other, signer] of certs) { + if (cert.verify(signer.publicKey)) by.push(other); + if (cert.checkIssued(signer)) issued.push(other); + } + console.log(name, "verifies with", by.join(",") || "-", "issued by", issued.join(",") || "-"); +} + +const keys: [string, KeyObject][] = [ + ["root", createPrivateKey(ROOT_KEY)], + ["leaf", createPrivateKey(Buffer.from(LEAF_KEY))], + ["plain", createPrivateKey({ key: PLAIN_KEY, format: "pem" })], + ["ed", createPrivateKey(ED_KEY)], + ["fresh", generateKeyPairSync("ec", { namedCurve: "prime256v1" }).privateKey], +]; +for (const [name, cert] of certs) { + console.log(name, "private", keys.filter(([, key]) => cert.checkPrivateKey(key)).map(([k]) => k).join(",") || "-"); +} + +const leaf = certs[1]![1]; +function attempt(label: string, f: () => boolean): void { + try { + console.log(label, f()); + } catch (e) { + const err = e as NodeJS.ErrnoException; + console.log(label, err.name, err.code, err.message); + } +} +attempt("verify private", () => leaf.verify(keys[0]![1])); +attempt("verify secret", () => leaf.verify(createSecretKey(Buffer.alloc(16)))); +attempt("check public", () => leaf.checkPrivateKey(leaf.publicKey)); +attempt("check secret", () => leaf.checkPrivateKey(createSecretKey(Buffer.alloc(16)))); + +// A PSS signature check on the root's public key leaves no padding behind +// for the certificate checks that follow. +const root = certs[0]![1]; +const message = Buffer.from("pss"); +const pssSignature = sign("sha256", message, { key: keys[0]![1], padding: constants.RSA_PKCS1_PSS_PADDING }); +const pssValid = verify("sha256", message, { key: root.publicKey, padding: constants.RSA_PKCS1_PSS_PADDING }, pssSignature); +console.log("after pss", pssValid, root.verify(root.publicKey), leaf.verify(root.publicKey)); + +// An outer signatureAlgorithm that differs from the TBSCertificate's, here +// without its NULL parameters, does not verify. +function header(der: Buffer, at: number): [number, number] { + const first = der[at + 1]!; + if (first < 0x80) return [2, first]; + let length = 0; + for (let i = 0; i < (first & 0x7f); i++) length = length * 256 + der[at + 2 + i]!; + return [2 + (first & 0x7f), length]; +} +const rootDer = root.raw; +const [outerHeader] = header(rootDer, 0); +const [tbsHeader, tbsLength] = header(rootDer, outerHeader); +const algAt = outerHeader + tbsHeader + tbsLength; +const [algHeader, algLength] = header(rootDer, algAt); +const algorithm = rootDer.subarray(algAt, algAt + algHeader + algLength); +const oid = algorithm.subarray(2, 2 + 2 + algorithm[3]!); +const bare = Buffer.concat([Buffer.from([0x30, oid.length]), oid]); +const body = Buffer.concat([rootDer.subarray(outerHeader, algAt), bare, rootDer.subarray(algAt + algHeader + algLength)]); +const altered = new X509Certificate(Buffer.concat([Buffer.from([0x30, 0x82, body.length >> 8, body.length & 0xff]), body])); +console.log("outer algorithm", algorithm.toString("hex"), "->", bare.toString("hex"), altered.subject.split("\n").join("/"), altered.verify(root.publicKey)); diff --git a/tests/corpus/7092-x509-legacy-object.ts b/tests/corpus/7092-x509-legacy-object.ts new file mode 100644 index 000000000..6b423860a --- /dev/null +++ b/tests/corpus/7092-x509-legacy-object.ts @@ -0,0 +1,158 @@ +// X509Certificate.toLegacyObject and toString match Node: the +// legacy object's members in Node's order (subject and issuer objects +// with repeated attributes as arrays, alternative names, access +// descriptions by method, the RSA modulus, exponent and SPKI or the EC +// point and curve names, the validity window, fingerprints, extended key +// usages, serial number and raw bytes), its inspect output, and the PEM +// text of toString, String() and template literals. +import { X509Certificate } from "node:crypto"; + +// An EC leaf with every alternative name kind, and the RSA root that signed it. +const LEAF = `-----BEGIN CERTIFICATE----- +MIIDqjCCApKgAwIBAgICCwswDQYJKoZIhvcNAQELBQAwPjELMAkGA1UEBhMCVVMx +FDASBgNVBAoMC0V4YW1wbGUgT3JnMRkwFwYDVQQDDBBFeGFtcGxlIFJTQSBSb290 +MCAXDTI2MTAyMjA5NDY0MVoYDzIxMjYwOTI4MDk0NjQxWjBfMQswCQYDVQQGEwJV +UzEUMBIGA1UECgwLRXhhbXBsZSBPcmcxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNv +bTEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBsZS5jb20wWTATBgcqhkjOPQIB +BggqhkjOPQMBBwNCAARidSirNIIrw+YHeS112z3N+1n0+uA9HjzkQ5u3QfZsRGCe +ivCEMQSs5+cUE/nv5WWda2kQWavxPGluHFtYmS10o4IBWDCCAVQwCQYDVR0TBAIw +ADALBgNVHQ8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHsG +A1UdEQR0MHKCDSouZXhhbXBsZS5jb22CC2V4YW1wbGUuY29tghV4bi0tYmNoZXIt +a3ZhLmV4YW1wbGWBD29wc0BleGFtcGxlLmNvbYcECgAAAYcQIAENuAAAAAAAAAAA +AAAAAYYUaHR0cHM6Ly9leGFtcGxlLmNvbS8wXgYIKwYBBQUHAQEEUjBQMCQGCCsG +AQUFBzABhhhodHRwOi8vb2NzcC5leGFtcGxlLmNvbS8wKAYIKwYBBQUHMAKGHGh0 +dHA6Ly9jYS5leGFtcGxlLmNvbS9jYS5jcnQwHQYDVR0OBBYEFHyUnRTDwZxUPVwZ +RKmse3fjoeMMMB8GA1UdIwQYMBaAFAgaWVveRbA7VKqcHzjMqBPzi1/LMA0GCSqG +SIb3DQEBCwUAA4IBAQAfMTcpidoH47PXOQVxRttfrG7K9BcntyXP4+5hUAoSfMr6 +Rxy7X/9ba7R0yCGlNsUCusObaBpbdvwX8v9TiTYKVL+C9rEVGrTHnh6kbgZaaCQc +L3oWbfRrYnEBYuSlFuadjVvX42aqzHV28E4ITgywCxwubu2hAbacbcUHpnRSqLDq +lV+VZSQA/6cPNct7PR6AkJU80D+5wVOk7RVi4rsfbw1wFDeksCHu+0EThs9zjzL+ +S7HTCjB6AOHpbu1Sx+0d5YEKSE7EPF+dSFATNbhjTHzYQySnHK+Lm8nON8wmY1rC +7opOhvUlid1jA1d2BKO2ZxlxLir4pyIehTC1ddG2 +-----END CERTIFICATE----- +`; +const ROOT = `-----BEGIN CERTIFICATE----- +MIIDPTCCAiWgAwIBAgIDChHOMA0GCSqGSIb3DQEBCwUAMD4xCzAJBgNVBAYTAlVT +MRQwEgYDVQQKDAtFeGFtcGxlIE9yZzEZMBcGA1UEAwwQRXhhbXBsZSBSU0EgUm9v +dDAgFw0yNjEwMjIwOTQ2NDFaGA8yMTI2MDkyODA5NDY0MVowPjELMAkGA1UEBhMC +VVMxFDASBgNVBAoMC0V4YW1wbGUgT3JnMRkwFwYDVQQDDBBFeGFtcGxlIFJTQSBS +b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwsfidupnXQcn8PUF +XaCKRYw8XKI1GUn29U5/IUGjAnJVaRmcB6BPTmblbKt4y7gLvU4h1Hxuypx8FZSZ +30eZOS1ixyrymDthG5zUHqzXk5zAGsNvZeXjN3YxTC9vX5CpQ9Uz2i+bLOi3PJsE +qyKVZ+GGT9fpIaALG11YrWmXTUko/a0AKGot0w8O/RaMpXQpkbeyTBF6f4pHNMqx +QGy+KlpC/+yIJ9psT6qyU33HF3Wa+DOy+0txAFEQNw9m1j7adOLnU0zBpkM/bnP2 +fSwxMkDB2Di2P5H6PkdqLT4zBf/BLdg7WqpxxSqqgVmaSXhEqUQ6xjf51yLR3wy/ +xBWhMQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd +BgNVHQ4EFgQUCBpZW95FsDtUqpwfOMyoE/OLX8swDQYJKoZIhvcNAQELBQADggEB +AChUtpNi8dPPxA4sf4EpZhEcYBN53X3WUcG3KJGtSf8JbPKru9lK9O+sZtJADbph +WoMPdWh8g+fEMk5D6l8Y5pDk/OR++oWNY7XCLFNyigmUGn+4SopJynBQiDk2dYPV +b6swDPPiV85TuAHVn79l766rtFdHdYwRe5HvfEkiXax7Egonlx7NR73xxm/XgvHQ +jhKbTZN9k/DEjkQuo5rt9ldVupUMM0iMhDMKX5oWEx9nvRwHPbjESS+Shy/FA4nA +2WHWO++4IU+imO40an1B/8SmFF+X9hj3UE6qaZLynVZRUiouBZibwZCcdCpibFM3 +kmB2s+NZXRvzhCjIxO97Ib4= +-----END CERTIFICATE----- +`; +// An EC leaf with access descriptions and extended key usages. +const ACCESS = `-----BEGIN CERTIFICATE----- +MIIDuzCCAqOgAwIBAgIPAPAN+s4AESIzRFVmd4iZMA0GCSqGSIb3DQEBDAUAMIGc +MQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2Fu +IEZyYW5jaXNjbzEUMBIGA1UECgwLRXhhbXBsZSBPcmcxETAPBgNVBAsMCERldiBU +ZWFtMRgwFgYDVQQDDA9FeGFtcGxlIFJvb3QgQ0ExHTAbBgkqhkiG9w0BCQEWDmNh +QGV4YW1wbGUuY29tMB4XDTI2MTAyMTE2MzM1MloXDTM2MTAxODE2MzM1MlowJzER +MA8GA1UECgwITGVhZiBPcmcxEjAQBgNVBAMMCWxvY2FsaG9zdDBZMBMGByqGSM49 +AgEGCCqGSM49AwEHA0IABJVfVy9EH/VHQuRqpFFnXk0F00ncDht6APgVPDoybK8H +PlcM4T5H1yAOMHnlH29LK1jtMqU1aAOiiQRzPdCvqoujggE3MIIBMzAJBgNVHRME +AjAAMGgGA1UdEQRhMF+CCWxvY2FsaG9zdIINKi5leGFtcGxlLmNvbYcEfwAAAYcQ +AAAAAAAAAAAAAAAAAAAAAYERYWRtaW5AZXhhbXBsZS5jb22GGGh0dHBzOi8vZXhh +bXBsZS5jb20vcGF0aDBdBggrBgEFBQcBAQRRME8wIwYIKwYBBQUHMAGGF2h0dHA6 +Ly9vY3NwLmV4YW1wbGUuY29tMCgGCCsGAQUFBzAChhxodHRwOi8vY2EuZXhhbXBs +ZS5jb20vY2EuY3J0MB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNV +HQ4EFgQUdKIx6ULFLPNP/kzwUFjSa5D19RswHwYDVR0jBBgwFoAUP+yQyItpNYEl +s26Jfv+NnciGaK8wDQYJKoZIhvcNAQEMBQADggEBABmQ8f2VsXNaMM9X1MEhi27D +LjwcOaaGEINNZq7xu/HL6UljMb1Odsuz66DkiH3Exd3MrWy6OlOpJJF0VzsqMsoD +0CRBxXF28o6Jil3vOGVwlYNmRidpkAkj4VyWDvv8FCS9VbsBtXaSHwu9wcCwePE0 +cGJRfTKoZ6KJ8vQ57DBEZ/ZszuhehOZYqrTmoUdjZ123kXdxQvK+ALn4SlIXHBhN +9unhd+8i00EmkXO/REw8paMcMVVGR+ioOEjyNHqZo6vkRqgpKggn1Yq8cTTDOMnS +P1o42EQZLlbuvx0kqInBqwqjDx4nZiPaifoDc9BF6iZPBvm8dhrEfghfB1tkNk0= +-----END CERTIFICATE----- +`; +// A multi-valued RDN, an Ed25519 key and names that need escaping. +const MULTI = `-----BEGIN CERTIFICATE----- +MIICNzCCAaCgAwIBAgIBADANBgkqhkiG9w0BAQsFADA3MSgwCgYDVQQLDANyZG4w +DAYDVQQDDAVtdWx0aTAMBgNVBAoMBXRocmVlMQswCQYDVQQGEwJERTAeFw0yNjEw +MjExNjM0MDVaFw0yNjEwMzExNjM0MDVaMDcxKDAKBgNVBAsMA3JkbjAMBgNVBAMM +BW11bHRpMAwGA1UECgwFdGhyZWUxCzAJBgNVBAYTAkRFMIGfMA0GCSqGSIb3DQEB +AQUAA4GNADCBiQKBgQDdv64EOPdpcWdjVMAlEQvNzm3ZbQYXrhOwRF9yzQp25SuA +3uKvStZOt8hyTifAd30oDXIfgyYI39xKHEkHfARTV1E2Jwyiz86/pDHmFypPFJuI +v/vOjYLLeisiVi8TFfHgmoGqGvySR83fwiUnoOOWj9Bqt/5EVBQbBeWrU9qH6QID +AQABo1MwUTAdBgNVHQ4EFgQUZrGU0gkgqCkmegRtu6vQ3h7kpPUwHwYDVR0jBBgw +FoAUZrGU0gkgqCkmegRtu6vQ3h7kpPUwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG +9w0BAQsFAAOBgQAMzFkzJElc9VJYhGx7AngO8Yve22iCTOVLO3/be8w55klb/HJX +vfESQz+EJLYVaP5Q/uChoE0I27NytkeUSpJFwmjyqoQq2j6kJWGKONqhQSnXDrms +HMPA7iik/C5hOqpwzDZ98wNU/e86TrqZxzpFkwbnZx9MSfiGr690s5BfpA== +-----END CERTIFICATE----- +`; +const ED = `-----BEGIN CERTIFICATE----- +MIICSDCCAfqgAwIBAgIB+zAFBgMrZXAwLDEVMBMGA1UEAx4MAGIAbQBwACAA6U4t +MRMwEQYDVQQKHgoAcABsAGEAaQBuMB4XDTI2MTAyMTE2NDQzM1oXDTI2MTEyMDE2 +NDQzM1owLDEVMBMGA1UEAx4MAGIAbQBwACAA6U4tMRMwEQYDVQQKHgoAcABsAGEA +aQBuMCowBQYDK2VwAyEAP+2Vcp8nwu2AhFvSczYTxGs1jV/ckA76Jqvwj9QDGqij +ggE/MIIBOzCBtwYDVR0RBIGvMIGsoBsGCisGAQQBgjcUAgOgDQwLdXNlckBkb21h +aW6gEAYDKgMEoAkMB3Vua25vd26kRTBDMQswCQYDVQQGEwJVSzEZMBcGA1UECh4Q +AEQAaQByACwAIABPAHIAZzEZMBcGA1UEAx4QAGQAaQByACAAbgBhAG0AZYgEKgME +BYcQ/oAAAAAAAAAAAAAAAAEAAocQIAENuAAAAAAAAP8AAEKDKYYKaHR0cDovL3gv +cTAMBgNVHRMEBTADAQH/MAsGA1UdDwQEAwIHgDBFBggrBgEFBQcBAQQ5MDcwIAYI +KwYBBQUHMAWGFGh0dHA6Ly9yZXBvLmV4YW1wbGUvMBMGBCoDBAWCC29kZC5leGFt +cGxlMB0GA1UdDgQWBBQYMJ0fQJ1Nx0PmatIfTJusAEA9WTAFBgMrZXADQQCixubE +nuunBZYYPXF52+joQSX/a5DFkOEDmzRTuH7IIpPFWPo37rmJOSdPA/PV8v9clzYF +LP3EjM4YOAatcbsO +-----END CERTIFICATE----- +`; +const ODD = `-----BEGIN CERTIFICATE----- +MIICXzCCAeWgAwIBAgIBATAKBggqhkjOPQQDAjBvMQ0wCwYDVQQDDARhLCBiMQ4w +DAYDVQQHDAUjbGVhZDESMBAGA1UECAwJICBzcGFjZSAgMSYwJAYDVQQKDB1RdW90 +ZSBxIGJhY2tcc2xhc2g7IHNlbWkgPGx0PjESMBAGA1UECwwJQ2Fmw6kg4oKsMB4X +DTI2MTAyMTE2MzM1MloXDTI3MTAyMTE2MzM1MlowbzENMAsGA1UEAwwEYSwgYjEO +MAwGA1UEBwwFI2xlYWQxEjAQBgNVBAgMCSAgc3BhY2UgIDEmMCQGA1UECgwdUXVv +dGUgcSBiYWNrXHNsYXNoOyBzZW1pIDxsdD4xEjAQBgNVBAsMCUNhZsOpIOKCrDB2 +MBAGByqGSM49AgEGBSuBBAAiA2IABMLLzwDsSeezCzScnC9xTIFl35dFAX+1Uagk +0y4Y72rOOgVFA13SMIbMfv2InIyg2vXOdqn0y7RqiaaqqnAYZB2RHHL0SD7t2MVL +K3BQajy7Oi6IeDDRGK1jM4D6nk/1AKNVMFMwMgYDVR0RBCswKYILYSxiLmV4YW1w +bGWCDXBsYWluLmV4YW1wbGWBBXhAeS56hwQKAAABMB0GA1UdDgQWBBSR4U6nIpTt +5rLoIZZxfxSyx9Uc9zAKBggqhkjOPQQDAgNoADBlAjEAlznFL0Nrt1jjZrT3/GN0 +yN/8gxO3SawyqoWrfP3uk1GScTh0PlrTEOrpSyuq3wl5AjBRntVI1ZoUM46pCwIw +0Vl3c3lns7OljcQFiR7o8yRhEW9ejdiR2W6PLBrjCly6U3I= +-----END CERTIFICATE----- +`; + +const certs: [string, X509Certificate][] = [ + ["leaf", new X509Certificate(LEAF)], + ["root", new X509Certificate(Buffer.from(ROOT))], + ["access", new X509Certificate(ACCESS)], + ["multi", new X509Certificate(MULTI)], + ["ed", new X509Certificate(ED)], + ["odd", new X509Certificate(ODD)], +]; + +for (const [name, cert] of certs) { + const legacy = cert.toLegacyObject(); + const shown = JSON.stringify(legacy, (key: string, value: unknown) => { + if (value === undefined) return ""; + if (key === "raw" || key === "pubkey") return `<${(value as { data: number[] }).data.length} bytes>`; + return value; + }); + console.log(name, shown); + const absent = Object.keys(legacy).filter((key) => (legacy as unknown as Record)[key] === undefined); + console.log(name, "absent", absent.join(","), Buffer.isBuffer(legacy.raw), legacy.raw.equals(cert.raw), legacy.raw === cert.raw); + const spki: Buffer = cert.publicKey.export({ type: "spki", format: "der" }); + if (legacy.pubkey !== undefined) console.log(name, "pubkey", legacy.pubkey.equals(spki)); +} + +console.log(certs[0]![1].toLegacyObject()); +console.log(certs[3]![1].toLegacyObject()); + +for (const [name, cert] of certs) { + const pem = cert.toString(); + console.log(name, pem.length, pem === String(cert), `${cert}` === pem, new X509Certificate(pem).fingerprint256 === cert.fingerprint256); +} +console.log(certs[3]![1].toString()); diff --git a/tests/corpus/7093-x509-methods-js.mjs b/tests/corpus/7093-x509-methods-js.mjs new file mode 100644 index 000000000..a8144d071 --- /dev/null +++ b/tests/corpus/7093-x509-methods-js.mjs @@ -0,0 +1,158 @@ +// X509Certificate's methods from JavaScript match Node: publicKey, +// verify, checkIssued, checkPrivateKey, checkHost, checkEmail, checkIP, +// toLegacyObject, toString and toJSON, including the TypeErrors for +// arguments of the wrong type. +import { X509Certificate, createPrivateKey, createPublicKey, createSecretKey } from "node:crypto"; + +// An RSA root, the EC leaf it signed, and a self-signed RSA certificate. +const ROOT = `-----BEGIN CERTIFICATE----- +MIIDPTCCAiWgAwIBAgIDChHOMA0GCSqGSIb3DQEBCwUAMD4xCzAJBgNVBAYTAlVT +MRQwEgYDVQQKDAtFeGFtcGxlIE9yZzEZMBcGA1UEAwwQRXhhbXBsZSBSU0EgUm9v +dDAgFw0yNjEwMjIwOTQ2NDFaGA8yMTI2MDkyODA5NDY0MVowPjELMAkGA1UEBhMC +VVMxFDASBgNVBAoMC0V4YW1wbGUgT3JnMRkwFwYDVQQDDBBFeGFtcGxlIFJTQSBS +b290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwsfidupnXQcn8PUF +XaCKRYw8XKI1GUn29U5/IUGjAnJVaRmcB6BPTmblbKt4y7gLvU4h1Hxuypx8FZSZ +30eZOS1ixyrymDthG5zUHqzXk5zAGsNvZeXjN3YxTC9vX5CpQ9Uz2i+bLOi3PJsE +qyKVZ+GGT9fpIaALG11YrWmXTUko/a0AKGot0w8O/RaMpXQpkbeyTBF6f4pHNMqx +QGy+KlpC/+yIJ9psT6qyU33HF3Wa+DOy+0txAFEQNw9m1j7adOLnU0zBpkM/bnP2 +fSwxMkDB2Di2P5H6PkdqLT4zBf/BLdg7WqpxxSqqgVmaSXhEqUQ6xjf51yLR3wy/ +xBWhMQIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAd +BgNVHQ4EFgQUCBpZW95FsDtUqpwfOMyoE/OLX8swDQYJKoZIhvcNAQELBQADggEB +AChUtpNi8dPPxA4sf4EpZhEcYBN53X3WUcG3KJGtSf8JbPKru9lK9O+sZtJADbph +WoMPdWh8g+fEMk5D6l8Y5pDk/OR++oWNY7XCLFNyigmUGn+4SopJynBQiDk2dYPV +b6swDPPiV85TuAHVn79l766rtFdHdYwRe5HvfEkiXax7Egonlx7NR73xxm/XgvHQ +jhKbTZN9k/DEjkQuo5rt9ldVupUMM0iMhDMKX5oWEx9nvRwHPbjESS+Shy/FA4nA +2WHWO++4IU+imO40an1B/8SmFF+X9hj3UE6qaZLynVZRUiouBZibwZCcdCpibFM3 +kmB2s+NZXRvzhCjIxO97Ib4= +-----END CERTIFICATE----- +`; +const LEAF = `-----BEGIN CERTIFICATE----- +MIIDqjCCApKgAwIBAgICCwswDQYJKoZIhvcNAQELBQAwPjELMAkGA1UEBhMCVVMx +FDASBgNVBAoMC0V4YW1wbGUgT3JnMRkwFwYDVQQDDBBFeGFtcGxlIFJTQSBSb290 +MCAXDTI2MTAyMjA5NDY0MVoYDzIxMjYwOTI4MDk0NjQxWjBfMQswCQYDVQQGEwJV +UzEUMBIGA1UECgwLRXhhbXBsZSBPcmcxGDAWBgNVBAMMD3d3dy5leGFtcGxlLmNv +bTEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBsZS5jb20wWTATBgcqhkjOPQIB +BggqhkjOPQMBBwNCAARidSirNIIrw+YHeS112z3N+1n0+uA9HjzkQ5u3QfZsRGCe +ivCEMQSs5+cUE/nv5WWda2kQWavxPGluHFtYmS10o4IBWDCCAVQwCQYDVR0TBAIw +ADALBgNVHQ8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMHsG +A1UdEQR0MHKCDSouZXhhbXBsZS5jb22CC2V4YW1wbGUuY29tghV4bi0tYmNoZXIt +a3ZhLmV4YW1wbGWBD29wc0BleGFtcGxlLmNvbYcECgAAAYcQIAENuAAAAAAAAAAA +AAAAAYYUaHR0cHM6Ly9leGFtcGxlLmNvbS8wXgYIKwYBBQUHAQEEUjBQMCQGCCsG +AQUFBzABhhhodHRwOi8vb2NzcC5leGFtcGxlLmNvbS8wKAYIKwYBBQUHMAKGHGh0 +dHA6Ly9jYS5leGFtcGxlLmNvbS9jYS5jcnQwHQYDVR0OBBYEFHyUnRTDwZxUPVwZ +RKmse3fjoeMMMB8GA1UdIwQYMBaAFAgaWVveRbA7VKqcHzjMqBPzi1/LMA0GCSqG +SIb3DQEBCwUAA4IBAQAfMTcpidoH47PXOQVxRttfrG7K9BcntyXP4+5hUAoSfMr6 +Rxy7X/9ba7R0yCGlNsUCusObaBpbdvwX8v9TiTYKVL+C9rEVGrTHnh6kbgZaaCQc +L3oWbfRrYnEBYuSlFuadjVvX42aqzHV28E4ITgywCxwubu2hAbacbcUHpnRSqLDq +lV+VZSQA/6cPNct7PR6AkJU80D+5wVOk7RVi4rsfbw1wFDeksCHu+0EThs9zjzL+ +S7HTCjB6AOHpbu1Sx+0d5YEKSE7EPF+dSFATNbhjTHzYQySnHK+Lm8nON8wmY1rC +7opOhvUlid1jA1d2BKO2ZxlxLir4pyIehTC1ddG2 +-----END CERTIFICATE----- +`; +const PLAIN = `-----BEGIN CERTIFICATE----- +MIIC8jCCAdoCAQcwDQYJKoZIhvcNAQELBQAwPjEaMBgGA1UEAwwRcGxhaW4uZXhh +bXBsZS5vcmcxIDAeBgkqhkiG9w0BCQEWEXBsYWluQGV4YW1wbGUub3JnMCAXDTI2 +MTAyMjA5NDY0MVoYDzIxMjYwOTI4MDk0NjQxWjA+MRowGAYDVQQDDBFwbGFpbi5l +eGFtcGxlLm9yZzEgMB4GCSqGSIb3DQEJARYRcGxhaW5AZXhhbXBsZS5vcmcwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCq01NcNAy9Ng04mVuAFvmZUvsm +rY7aOaMgtODmptulgZ2qw25E09RgGYCn1S+4IYDu9hH9X4s+28Ag7Khmj4nmeoXN +of5095wche8DR2AAUElqyr/Nmgm2kTLdIJX4wl0eWXHIlmSPdOUNovA6JjGKH99b +8W7a2TqY/TsSadpPSvvN2esr7Jr4KgW7MXPUOnwNbcBOVcQP9rtFrduAWz01q0HM +02LboclnUnk/e58BXAj8vgdVojljDcc0bhbdz/Hh1/5gaaNILjJNOd4AgwZaCT02 +KojGz4Nb6MSgFmON2iMgAZjY1fXXkJ7wsfVPytjW73e7uV/RFuqSHQZenxupAgMB +AAEwDQYJKoZIhvcNAQELBQADggEBAJX1DGuiSLoCKBDI3oCgAu7X86G01ovEgZJr +8JrmGHW5q7ujjo53t46h8XPm3LJ8UV9/MZ+Yry43xB2txXYv3b3g/i+7JdTWLgUD +INA5VWvVkEZfm0lBEpU1Agpy4lV5uUCKZTgP/3MY5hnJ0YhQIs4BOjbwueMRFshL +yyHVb73MMbpWaZ7+T368seafa+ekeuY6gQly/HacuszjoYd6KKV3n8eDewenClCF +HoOF1Y4I+CvmR+a6B3iBczJ+a4tceFIIWsZUIeqzvGHpM7G9YwlmbvGprfLgR8Nv +igUib/D9tU3hdL6VWN5nMjdXV/8Le4nDnBjVBjYDkVbsnmT91AQ= +-----END CERTIFICATE----- +`; +const ROOT_KEY = `-----BEGIN PRIVATE KEY----- +MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDCx+J26mddByfw +9QVdoIpFjDxcojUZSfb1Tn8hQaMCclVpGZwHoE9OZuVsq3jLuAu9TiHUfG7KnHwV +lJnfR5k5LWLHKvKYO2EbnNQerNeTnMAaw29l5eM3djFML29fkKlD1TPaL5ss6Lc8 +mwSrIpVn4YZP1+khoAsbXVitaZdNSSj9rQAoai3TDw79FoyldCmRt7JMEXp/ikc0 +yrFAbL4qWkL/7Ign2mxPqrJTfccXdZr4M7L7S3EAURA3D2bWPtp04udTTMGmQz9u +c/Z9LDEyQMHYOLY/kfo+R2otPjMF/8Et2DtaqnHFKqqBWZpJeESpRDrGN/nXItHf +DL/EFaExAgMBAAECggEADsvlabgryvbYs2bBlhe0eU0KZtURqI6kWoUwhiO40N5D +m7zMzA2DCMcrRYKPJhagmaxeSIh9WBnkGTWVLM+BFcVbXBrom+Ti3xieSohBxh5h +v4a6Jyj8BkINw6ZU1RMlsJf5HOmB5br19H4oMCHr7JzGubkCpkHEpjsEmgPL8Rxs +LYb9palDyTD1z5xVAQDAkvnCYQMX2DsiH8RuO4Ih0OoWMIsAGasS1dTQCkOzN9wF +cMg+hmJvQLN5xLYI+VPy/iZn+bmerCx8/NQBrbo+zibmnv7cDK1U9emVD70/Nd1d +B7ZEm+a4gReaxWVQGEkFMvs29u/TDWXYRnw0PGjUYwKBgQDrmKEx+ZiZwNNk/S3l +s8FgVrLFDr/+t5X33jaD5nVuSN6/AoR3qfh9piIyCrdNKdHicAcCnWP6skUFYLq3 +/tyMBATX3j+f3PHW3i2ZUAK26hgfp66F/3IyowePZbBDlGSmGsffVlc8on5fCk1Q +k3G0znktbrMCNxeeY9GSi1CHewKBgQDTpled6pZepZ54OGnKVJFo6DbQC0l4HQ6y +Rwv9BMtAz+AxWXda1oYK5bbJZrCmHyVP85VxkzRHOMxicv7M2kR9y2zZsJD7INqr +Nvt+lo2yGtIGv7kOdwWzvs4Pn7aCWSApzYBjuKrpP1xDzaMHhusAQtkk77YGCZCu +cCAQ/FjEQwKBgBq/1KWI8lOauiXAPULUWwNmNJv9Jb10+LkQ6N2m//RKn8fOMF4p +1UXm5AEMiG1hbywnjhQ07JIdRYrrxad4b3ASUL51xIGRI4BC76h1lilQgPavIjii +nUO0kPouEIpLwfW+Gq137yW6SWDfGZIpe4KM4uNOq1J4EN1x9eyOltEbAoGAP4bj +L5QVFE2T1jPglQlzJ9DjeuiYYcQfACXRFF3XABolCcr3xz0yuJygk60OAp7AnVHY +nmF3xJToy/gGQMiW3Ect4d1cdvQyjkePjzxzRW1Fcx8i1ZOmE4CG6yueJVvJCqMT +EVuBeUc6U2Oqtnyplsd509tbgE5oreMbzN1ha28CgYAHpG10ZQRDeqWFIo/ttk6Q +Q1Gf53eqZFCgh8GO1hBJ7+Fp+Ec5S9UPMBDjZb6GET7ifF8Zit/lR4gN2PuELwJA +YaXTIehCugH7Q3oTjNcQtls6tW+/+jEGjbjSHyZvwk8EFHc0J7PWRszB36s+qM+O +YPorNipExSeWti1506ljLQ== +-----END PRIVATE KEY----- +`; +const LEAF_KEY = `-----BEGIN EC PRIVATE KEY----- +MHcCAQEEINqbifA6kN/DSN0cMD2s7fXiNtPXZqipFrbCs/3mCGbtoAoGCCqGSM49 +AwEHoUQDQgAEYnUoqzSCK8PmB3ktdds9zftZ9PrgPR485EObt0H2bERgnorwhDEE +rOfnFBP57+VlnWtpEFmr8TxpbhxbWJktdA== +-----END EC PRIVATE KEY----- +`; + +const ca = new X509Certificate(ROOT); +const leaf = new X509Certificate(Buffer.from(LEAF)); +const plain = new X509Certificate(PLAIN); +const caKey = createPrivateKey(ROOT_KEY); +const leafKey = createPrivateKey(LEAF_KEY); +function t(label, f) { + try { + const v = f(); + console.log(label, typeof v === "string" ? JSON.stringify(v) : v); + } catch (e) { + console.log(label, "THROW", e.name, e.code, e.message); + } +} +t("pub", () => [leaf.publicKey.asymmetricKeyType, ca.publicKey.asymmetricKeyType, ca.publicKey.asymmetricKeyDetails.modulusLength]); +t("pub same", () => leaf.publicKey === leaf.publicKey); +t("pub equals", () => leaf.publicKey.equals(createPublicKey(leafKey))); +t("verify ca", () => leaf.verify(ca.publicKey)); +t("verify self", () => leaf.verify(leaf.publicKey)); +t("verify ca self", () => ca.verify(ca.publicKey)); +t("verify private", () => leaf.verify(caKey)); +t("verify string", () => leaf.verify("x")); +t("verify secret", () => leaf.verify(createSecretKey(Buffer.alloc(16)))); +t("issued", () => [leaf.checkIssued(ca), ca.checkIssued(leaf), ca.checkIssued(ca), plain.checkIssued(plain), leaf.checkIssued(plain)]); +t("issued bad", () => leaf.checkIssued({})); +t("pk", () => [leaf.checkPrivateKey(leafKey), leaf.checkPrivateKey(caKey), ca.checkPrivateKey(caKey)]); +t("pk public", () => leaf.checkPrivateKey(leaf.publicKey)); +t("pk string", () => leaf.checkPrivateKey("x")); +for (const h of ["www.example.com", "foo.example.com", "a.b.example.com", "example.com", "EXAMPLE.COM", "xn--bcher-kva.example", "other.org", "10.0.0.1", "", "foo.example.com."]) t("host " + h, () => leaf.checkHost(h)); +t("host plain", () => plain.checkHost("plain.example.org")); +t("host plain never", () => plain.checkHost("plain.example.org", { subject: "never" })); +t("host leaf always", () => leaf.checkHost("www.example.com", { subject: "always" })); +t("host nowild", () => leaf.checkHost("foo.example.com", { wildcards: false })); +t("host partial", () => leaf.checkHost("foo.example.com", { partialWildcards: false })); +t("host multi", () => leaf.checkHost("a.b.example.com", { multiLabelWildcards: true })); +t("host single", () => leaf.checkHost("example.com", { singleLabelSubdomains: true })); +t("host num", () => leaf.checkHost(1)); +t("host opts bad", () => leaf.checkHost("x", { subject: "sometimes" })); +t("host opts type", () => leaf.checkHost("x", 5)); +t("host wild type", () => leaf.checkHost("x", { wildcards: "yes" })); +for (const e of ["ops@example.com", "OPS@EXAMPLE.COM", "admin@example.com", "nobody@example.com"]) t("email " + e, () => leaf.checkEmail(e)); +t("email plain", () => plain.checkEmail("plain@example.org")); +t("email plain never", () => plain.checkEmail("plain@example.org", { subject: "never" })); +t("email num", () => leaf.checkEmail(1)); +for (const ip of ["10.0.0.1", "2001:db8::1", "2001:DB8:0:0:0:0:0:1", "10.0.0.2", "::ffff:10.0.0.1", "bogus", ""]) t("ip " + ip, () => leaf.checkIP(ip)); +t("ip num", () => leaf.checkIP(1)); +t("ip opts", () => leaf.checkIP("10.0.0.1", {})); +for (const cert of [leaf, ca, plain]) { + const legacy = cert.toLegacyObject(); + console.log(Object.keys(legacy).join(","), legacy.subject.CN, legacy.bits, legacy.raw.length); +} +t("pem", () => [leaf.toString() === leaf.toJSON(), String(ca) === `${ca}`, ca.toString().split("\n").length]); +t("pem round trip", () => new X509Certificate(plain.toJSON()).fingerprint === plain.fingerprint); diff --git a/tests/corpus/7095-tls-peer-certificates.ts b/tests/corpus/7095-tls-peer-certificates.ts new file mode 100644 index 000000000..eee3c9ac8 --- /dev/null +++ b/tests/corpus/7095-tls-peer-certificates.ts @@ -0,0 +1,188 @@ +// tlsSocket.getPeerCertificate([detailed]), getCertificate(), +// getPeerX509Certificate() and getX509Certificate() match Node: the +// legacy certificate objects, {} before a handshake or without a +// certificate and null once the socket is destroyed; the detailed +// issuerCertificate chain from the certificates the peer sent and then +// the trust anchors, in any order, ending at a self-issued root that is its +// own issuer; and the certificates served by SNI answers, secureContext +// wraps and https servers. +import { X509Certificate } from "node:crypto"; +import { readFileSync } from "node:fs"; +import * as https from "node:https"; +import * as net from "node:net"; +import type { AddressInfo } from "node:net"; +import * as tls from "node:tls"; + +const d = "tests/fixtures/server/certs"; +const read = (f: string): Buffer => readFileSync(`${d}/${f}`); +const ca = read("ca.pem"), ca2 = read("ca2.pem"), cert = read("localhost.pem"), key = read("localhost-key.pem"); +const self = read("selfsigned.pem"), selfKey = read("selfsigned-key.pem"), alt = read("alt.pem"), altKey = read("alt-key.pem"); + +function describe(label: string, o: tls.PeerCertificate | tls.DetailedPeerCertificate | object | null): string { + if (o === null) return `${label} null`; + const keys = Object.keys(o); + if (keys.length === 0) return `${label} {}`; + const p = o as tls.DetailedPeerCertificate; + const issuer = p.issuerCertificate; + const link = issuer ? ` issuerCert:${issuer.subject.CN} self:${issuer === issuer.issuerCertificate} same:${issuer === p}` : ""; + return `${label} ${keys.join(",")} ${p.subject.CN} ${p.issuer.CN}${link}`; +} +function show(label: string, o: tls.PeerCertificate | tls.DetailedPeerCertificate | object | null): void { + console.log(describe(label, o)); +} +// A server's lines print once its client has the reply, so the output +// order does not depend on which side's callback runs first. +const serverLines: string[] = []; +function flushServer(): void { + for (const line of serverLines.splice(0)) console.log(line); +} +await new Promise((done) => { +const server = tls.createServer({ cert, key }, (s) => { + serverLines.push(describe("server peer", s.getPeerCertificate())); + serverLines.push(describe("server peer detailed", s.getPeerCertificate(true))); + serverLines.push(`server peerX509 ${s.getPeerX509Certificate()?.subject}`); + serverLines.push(describe("server own", s.getCertificate())); + serverLines.push(`server ownX509 ${s.getX509Certificate()?.subject}`); + s.end("hi"); +}); +server.listen(0, () => { + const c = tls.connect({ port: (server.address() as AddressInfo).port, ca, servername: "localhost" }, () => { + show("client peer", c.getPeerCertificate()); + const det = c.getPeerCertificate(true); + show("client peer detailed", det); + show("client issuer", det.issuerCertificate); + const x = c.getPeerX509Certificate(); + if (x) console.log("client peerX509", x.subject, x.issuer, x === c.getPeerX509Certificate(), x.checkIssued(new X509Certificate(ca)), x.checkHost("localhost")); + show("client own", c.getCertificate()); + console.log("client ownX509", c.getX509Certificate()?.subject); + console.log("peer raw eq", c.getPeerCertificate().raw.equals(x!.raw), c.getPeerCertificate() === c.getPeerCertificate()); + }); + c.on("data", () => {}); + c.on("end", () => { + flushServer(); + show("after end peer", c.getPeerCertificate()); + c.destroy(); + }); + c.on("close", () => { + show("after close peer", c.getPeerCertificate()); + console.log("after close X509", c.getPeerX509Certificate()?.subject, c.getCertificate()); + server.close(() => done()); + }); + show("before handshake", c.getPeerCertificate()); + console.log("before X509", c.getPeerX509Certificate()?.subject, c.getCertificate(), c.getX509Certificate()?.subject); +}); +}); + +function chain(o: tls.DetailedPeerCertificate | null): string { + if (o === null) return "null"; + if (Object.keys(o).length === 0) return "{}"; + const names: string[] = []; + let at: tls.DetailedPeerCertificate | undefined = o; + for (let i = 0; at !== undefined && i < 6; i++) { + names.push(at.subject.CN as string); + const next: tls.DetailedPeerCertificate | undefined = at.issuerCertificate; + if (next === at) { + names.push("(self)"); + break; + } + at = next; + } + return names.join(" -> "); +} +async function run(label: string, served: Buffer, servedKey: Buffer, trust: Buffer | null): Promise { + await new Promise((done) => { + const server = tls.createServer({ cert: served, key: servedKey }, (s) => s.end()); + server.listen(0, () => { + const port = (server.address() as AddressInfo).port; + const socket = + trust === null + ? tls.connect({ port, servername: "localhost", rejectUnauthorized: false }) + : tls.connect({ port, servername: "localhost", ca: trust, rejectUnauthorized: false }); + socket.on("secureConnect", () => { + console.log(label, socket.authorized, chain(socket.getPeerCertificate(true))); + console.log(label, "abbreviated", "issuerCertificate" in socket.getPeerCertificate(), "issuerCertificate" in socket.getPeerCertificate(false)); + socket.destroy(); + console.log(label, "destroyed", socket.getPeerCertificate(), socket.getPeerX509Certificate()?.subject, socket.getCertificate()); + server.close(() => done()); + }); + socket.on("error", (e) => console.log(label, "error", e.message)); + }); + }); +} +await run("leaf", cert, key, ca); +await run("sent chain", Buffer.concat([cert, ca]), key, ca); +await run("sent chain, default store", Buffer.concat([cert, ca]), key, null); +await run("out of order", Buffer.concat([cert, ca2, ca]), key, ca); +await run("self-signed", self, selfKey, null); +await run("wrong ca", cert, key, ca2); +await run("leaf, default store", cert, key, null); + +// SNI and secureContext: the certificate the server socket serves. +await new Promise((done) => { + const altCtx = tls.createSecureContext({ cert: alt, key: altKey }); + const server = tls.createServer({ cert, key, SNICallback: (name: string, cb: (err: Error | null, ctx?: tls.SecureContext) => void) => cb(null, name === "alt.localhost" ? altCtx : undefined) }, (s) => { + serverLines.push(`sni own ${(s.getCertificate() as tls.PeerCertificate).subject.CN} ${s.getX509Certificate()?.subject}`); + s.end("x"); + }); + server.listen(0, () => { + const port = (server.address() as AddressInfo).port; + const a = tls.connect({ port, ca, servername: "alt.localhost" }, () => { + console.log("sni peer", a.getPeerCertificate().subject.CN, a.getPeerX509Certificate()?.subjectAltName); + }); + a.resume(); + a.on("end", () => { + flushServer(); + a.destroy(); + const b = tls.connect({ port, ca, servername: "localhost" }, () => { + console.log("sni default peer", b.getPeerCertificate().subject.CN); + }); + b.resume(); + b.on("end", () => { + flushServer(); + b.destroy(); + server.close(() => done()); + }); + }); + }); +}); + +// new tls.TLSSocket over a net connection, with a secureContext. +await new Promise((done) => { + const context = tls.createSecureContext({ cert: alt, key: altKey }); + const server = net.createServer((raw) => { + const secure = new tls.TLSSocket(raw, { isServer: true, secureContext: context }); + console.log("wrap before", (secure.getCertificate() as tls.PeerCertificate).subject?.CN, secure.getX509Certificate()?.subject, JSON.stringify(secure.getPeerCertificate())); + secure.on("secure", () => { + serverLines.push(`wrap secure ${(secure.getCertificate() as tls.PeerCertificate).subject.CN} ${secure.getPeerX509Certificate()?.subject}`); + secure.end("x"); + }); + }); + server.listen(0, () => { + const c = tls.connect({ port: (server.address() as AddressInfo).port, ca, servername: "alt.localhost" }, () => { + console.log("wrap client", chain(c.getPeerCertificate(true))); + }); + c.resume(); + c.on("end", () => { + flushServer(); + c.destroy(); + server.close(() => done()); + }); + }); +}); + +// https: both sides of a request. +await new Promise((done) => { + const server = https.createServer({ cert, key }, (req, res) => { + const s = req.socket as tls.TLSSocket; + console.log("https server", (s.getCertificate() as tls.PeerCertificate).subject.CN, JSON.stringify(s.getPeerCertificate())); + res.end("ok"); + }); + server.listen(0, () => { + https.get({ port: (server.address() as AddressInfo).port, ca, host: "localhost", path: "/" }, (res) => { + const s = res.socket as tls.TLSSocket; + console.log("https client", chain(s.getPeerCertificate(true)), s.getPeerX509Certificate()?.issuer); + res.resume(); + res.on("end", () => server.close(() => done())); + }); + }); +}); diff --git a/tests/corpus/7096-tls-peer-certificates.mjs b/tests/corpus/7096-tls-peer-certificates.mjs new file mode 100644 index 000000000..ef1bfeb2a --- /dev/null +++ b/tests/corpus/7096-tls-peer-certificates.mjs @@ -0,0 +1,35 @@ +// tlsSocket.getPeerCertificate from JavaScript matches Node: only a +// detailed argument that is true itself adds the issuerCertificate chain, +// and the legacy object is a plain object with a Buffer raw and arrays for +// extended key usages. +import * as tls from "node:tls"; +import { readFileSync } from "node:fs"; + +const d = "tests/fixtures/server/certs"; +const ca = readFileSync(`${d}/ca.pem`); +const cert = readFileSync(`${d}/localhost.pem`); +const key = readFileSync(`${d}/localhost-key.pem`); + +const server = tls.createServer({ cert, key }, (s) => s.end("x")); +server.listen(0, () => { + const c = tls.connect({ port: server.address().port, ca, servername: "localhost" }, () => { + for (const arg of [true, false, 1, "yes", null, undefined, {}]) { + const peer = c.getPeerCertificate(arg); + console.log(String(arg), "issuerCertificate" in peer, peer.issuer.CN); + } + const legacy = c.getPeerCertificate(); + console.log(Object.keys(legacy).length, Buffer.isBuffer(legacy.raw), legacy.ext_key_usage, JSON.stringify(legacy.subject)); + const detailed = c.getPeerCertificate(true); + const root = detailed.issuerCertificate; + console.log(root.subject.CN, root.issuerCertificate === root, root.ca, Buffer.isBuffer(root.raw)); + const x509 = c.getPeerX509Certificate(); + if (x509) console.log(x509.subject, x509.checkHost("localhost"), x509.checkIssued(x509), legacy.raw.equals(x509.raw)); + console.log(c.getCertificate(), c.getX509Certificate() === undefined); + }); + c.resume(); + c.on("end", () => { + c.destroy(); + console.log(c.getPeerCertificate(), c.getPeerX509Certificate() === undefined, c.getCertificate()); + server.close(); + }); +}); diff --git a/tests/corpus/7097-tls-client-certificates.ts b/tests/corpus/7097-tls-client-certificates.ts new file mode 100644 index 000000000..b45560084 --- /dev/null +++ b/tests/corpus/7097-tls-client-certificates.ts @@ -0,0 +1,84 @@ +// Client certificates match Node: tls.createServer's requestCert, +// rejectUnauthorized and ca against clients that send no certificate, a +// valid one, one without the clientAuth purpose and a self-signed one +// (socket.authorized and authorizationError on the server, the peer +// certificate, the client's own certificate), the client's chain completed +// from its ca, and a server that requires a certificate rejecting a client +// without one in TLS 1.3 and TLS 1.2 (the client's events and codes). +import { readFileSync } from "node:fs"; +import type { AddressInfo } from "node:net"; +import * as tls from "node:tls"; + +const D = "tests/fixtures/server/certs"; +const r = (f: string): Buffer => readFileSync(`${D}/${f}`); +const ca = r("ca.pem"), ca2 = r("ca2.pem"), cert = r("localhost.pem"), key = r("localhost-key.pem"); +const client = r("client.pem"), clientKey = r("client-key.pem"); +const self = r("selfsigned.pem"), selfKey = r("selfsigned-key.pem"); + +type Handler = (s: tls.TLSSocket) => void; +const servers: [string, (h: Handler) => tls.Server][] = [ + ["request", (h) => tls.createServer({ cert, key, requestCert: true, rejectUnauthorized: false, ca }, h)], + ["reject", (h) => tls.createServer({ cert, key, requestCert: true, ca }, h)], + ["request-noca", (h) => tls.createServer({ cert, key, requestCert: true, rejectUnauthorized: false }, h)], + ["request-ca2", (h) => tls.createServer({ cert, key, requestCert: true, rejectUnauthorized: false, ca: ca2 }, h)], + // an empty Buffer is an empty trust store; an empty string is no ca + ["request-empty", (h) => tls.createServer({ cert, key, requestCert: true, rejectUnauthorized: false, ca: Buffer.alloc(0) }, h)], + ["request-emptystr", (h) => tls.createServer({ cert, key, requestCert: true, rejectUnauthorized: false, ca: "" }, h)], + ["plain", (h) => tls.createServer({ cert, key }, h)], +]; +const clients: [string, Buffer | null, Buffer | null][] = [ + ["none", null, null], + ["valid", client, clientKey], + ["serverEku", cert, key], + ["self", self, selfKey], +]; +async function run(label: string, make: (h: Handler) => tls.Server, name: string, clientCert: Buffer | null, clientKeyPem: Buffer | null): Promise { + await new Promise((done) => { + const events: string[] = []; + const server = make((s) => { + events.push(`server secureConnection authorized=${s.authorized} error=${s.authorizationError} peer=${(s.getPeerCertificate() as tls.PeerCertificate).subject?.CN} x509=${s.getPeerX509Certificate()?.subject}`); + s.end("ok"); + }); + server.listen(0, () => { + const port = (server.address() as AddressInfo).port; + const c = + clientCert === null || clientKeyPem === null + ? tls.connect({ port, ca, servername: "localhost" }) + : tls.connect({ port, ca, servername: "localhost", cert: clientCert, key: clientKeyPem }); + c.on("secureConnect", () => events.push(`client secureConnect own=${(c.getCertificate() as tls.PeerCertificate | null)?.subject?.CN}`)); + c.on("data", (d: Buffer) => events.push(`client data ${d}`)); + c.on("end", () => events.push("client end")); + c.on("error", (e: NodeJS.ErrnoException) => events.push(`client error ${e.code}`)); + c.on("close", () => { + setTimeout(() => { + console.log(label, name, "|", events.join(" ; ")); + server.close(() => done()); + }, 50); + }); + }); + }); +} +for (const [label, make] of servers) { + for (const [name, c, k] of clients) await run(label, make, name, c, k); +} + +// A server that requires a certificate, per protocol version: TLS 1.3 +// rejects after the client's handshake, TLS 1.2 during it. +for (const maxVersion of ["TLSv1.3", "TLSv1.2"] as const) { + await new Promise((done) => { + const server = tls.createServer({ cert, key, requestCert: true, ca, maxVersion }, (s) => s.end("ok")); + server.listen(0, () => { + const events: string[] = []; + const c = tls.connect({ port: (server.address() as AddressInfo).port, ca, servername: "localhost" }); + c.on("secureConnect", () => events.push("secureConnect")); + c.on("data", () => events.push("data")); + c.on("end", () => events.push("end")); + c.on("error", (e: NodeJS.ErrnoException) => events.push(`error ${e.code}`)); + c.on("close", (hadError: boolean) => { + events.push(`close ${hadError}`); + console.log(maxVersion, events.join(" ; ")); + server.close(() => done()); + }); + }); + }); +} diff --git a/tests/corpus/7098-tls-client-certificates-paths.ts b/tests/corpus/7098-tls-client-certificates-paths.ts new file mode 100644 index 000000000..b71e72b6f --- /dev/null +++ b/tests/corpus/7098-tls-client-certificates-paths.ts @@ -0,0 +1,161 @@ +// Client certificates on the other paths match Node: a server's (and a +// SecureContext's) ca completes the certificate chain it sends, as +// OpenSSL's automatic chain does; new tls.TLSSocket with requestCert and +// rejectUnauthorized, where Node reports no verdict; and https on both +// sides, including an agent that pools sockets per client certificate. +import { readFileSync } from "node:fs"; +import * as http from "node:http"; +import * as https from "node:https"; +import * as net from "node:net"; +import type { AddressInfo } from "node:net"; +import * as tls from "node:tls"; + +const D = "tests/fixtures/server/certs"; +const r = (f: string): Buffer => readFileSync(`${D}/${f}`); +const ca = r("ca.pem"), ca2 = r("ca2.pem"), cert = r("localhost.pem"), key = r("localhost-key.pem"); +const client = r("client.pem"), clientKey = r("client-key.pem"); + +// A server's ca completes the chain it sends. +for (const [label, make] of [ + ["no ca", () => tls.createServer({ cert, key }, (s) => s.end())], + ["ca", () => tls.createServer({ cert, key, ca }, (s) => s.end())], + ["other ca", () => tls.createServer({ cert, key, ca: ca2 }, (s) => s.end())], + // An SNI answer's own ca does not complete its chain. + ["sni ctx ca, server no ca", () => { + const context = tls.createSecureContext({ cert, key, ca }); + return tls.createServer({ cert, key, SNICallback: (name: string, cb: (err: Error | null, ctx?: tls.SecureContext) => void) => cb(null, context) }, (s) => s.end()); + }], +] as [string, () => tls.Server][]) { + await new Promise((done) => { + const server = make(); + server.listen(0, () => { + const c = tls.connect({ port: (server.address() as AddressInfo).port, ca: ca2, servername: "localhost", rejectUnauthorized: false }, () => { + const names: string[] = []; + let p: tls.DetailedPeerCertificate | undefined = c.getPeerCertificate(true); + for (let i = 0; p !== undefined && i < 4; i++) { + names.push(p.subject.CN as string); + if (p.issuerCertificate === p) break; + p = p.issuerCertificate; + } + console.log(label, c.authorizationError, names.join(" -> ")); + c.destroy(); + server.close(() => done()); + }); + }); + }); +} + +// A TLSSocket's secureContext sends the chain its ca completes. +for (const [label, context] of [ + ["wrap ctx ca", tls.createSecureContext({ cert, key, ca })], + ["wrap ctx", tls.createSecureContext({ cert, key })], +] as [string, tls.SecureContext][]) { + await new Promise((done) => { + const server = net.createServer((raw) => { + const s = new tls.TLSSocket(raw, { isServer: true, secureContext: context }); + s.on("secure", () => s.end()); + }); + server.listen(0, () => { + const c = tls.connect({ port: (server.address() as AddressInfo).port, ca: ca2, servername: "localhost", rejectUnauthorized: false }, () => { + const names: string[] = []; + let p: tls.DetailedPeerCertificate | undefined = c.getPeerCertificate(true); + for (let i = 0; p !== undefined && i < 4; i++) { + names.push(p.subject.CN as string); + if (p.issuerCertificate === p) break; + p = p.issuerCertificate; + } + console.log(label, c.authorizationError, names.join(" -> ")); + c.destroy(); + server.close(() => done()); + }); + }); + }); +} + +// new tls.TLSSocket with client certificates: Node reports no verdict there. +for (const [label, wrap] of [ + ["wrap request", (raw: net.Socket) => new tls.TLSSocket(raw, { isServer: true, cert, key, requestCert: true, ca })], + ["wrap reject", (raw: net.Socket) => new tls.TLSSocket(raw, { isServer: true, cert, key, requestCert: true, rejectUnauthorized: true, ca })], +] as [string, (raw: net.Socket) => tls.TLSSocket][]) { + for (const withCert of [false, true]) { + await new Promise((done) => { + const events: string[] = []; + const server = net.createServer((raw) => { + const s = wrap(raw); + s.on("secure", () => { + events.push(`wrap secure authorized=${s.authorized} error=${s.authorizationError} peer=${(s.getPeerCertificate() as tls.PeerCertificate).subject?.CN}`); + s.end("ok"); + }); + s.on("error", (e: NodeJS.ErrnoException) => events.push(`wrap error ${e.code}`)); + }); + server.listen(0, () => { + const port = (server.address() as AddressInfo).port; + const c = withCert + ? tls.connect({ port, ca, servername: "localhost", cert: client, key: clientKey }) + : tls.connect({ port, ca, servername: "localhost" }); + c.on("secureConnect", () => events.push("client secureConnect")); + c.on("data", (d: Buffer) => events.push(`client data ${d}`)); + c.on("error", (e: NodeJS.ErrnoException) => events.push(`client error ${e.code}`)); + c.on("close", () => { + setTimeout(() => { + console.log(label, withCert ? "cert" : "none", "|", events.join(" ; ")); + server.close(() => done()); + }, 50); + }); + }); + }); + } +} + +// https with client certificates, on both sides. +await new Promise((done) => { + const server = https.createServer({ cert, key, requestCert: true, rejectUnauthorized: false, ca }, (req, res) => { + const s = req.socket as tls.TLSSocket; + res.end(`${s.authorized} ${s.authorizationError} ${(s.getPeerCertificate() as tls.PeerCertificate).subject?.CN}`); + }); + server.listen(0, () => { + const port = (server.address() as AddressInfo).port; + https.get({ port, ca, host: "localhost", path: "/", cert: client, key: clientKey }, (res) => { + let body = ""; + res.on("data", (d: Buffer) => (body += d)); + res.on("end", () => { + console.log("https with cert", body); + https.get({ port, ca, host: "localhost", path: "/", agent: false }, (res2) => { + let body2 = ""; + res2.on("data", (d: Buffer) => (body2 += d)); + res2.on("end", () => { + console.log("https without cert", body2); + server.close(() => done()); + }); + }); + }); + }); + }); +}); + +// An agent pools sockets per client certificate. +let connections = 0; +const server = https.createServer({ cert, key, requestCert: true, rejectUnauthorized: false, ca }, (req, res) => { + const s = req.socket as tls.TLSSocket; + res.end(`${s.authorized} ${(s.getPeerCertificate() as tls.PeerCertificate).subject?.CN}`); +}); +server.on("secureConnection", () => connections++); +function get(port: number, withCert: boolean): Promise { + return new Promise((resolve) => { + const done = (res: http.IncomingMessage) => { + let body = ""; + res.on("data", (d: Buffer) => (body += d)); + res.on("end", () => resolve(body)); + }; + if (withCert) https.get({ port, ca, host: "localhost", path: "/", cert: client, key: clientKey }, done); + else https.get({ port, ca, host: "localhost", path: "/" }, done); + }); +} +server.listen(0, async () => { + // the agent keeps one socket per client certificate + const port = (server.address() as AddressInfo).port; + for (const withCert of [true, true, false, false, true]) console.log(withCert, await get(port, withCert)); + console.log("connections", connections); + server.close(); + https.globalAgent.destroy(); +}); diff --git a/tests/corpus/7099-tls-client-certificates.mjs b/tests/corpus/7099-tls-client-certificates.mjs new file mode 100644 index 000000000..0c9eeed2f --- /dev/null +++ b/tests/corpus/7099-tls-client-certificates.mjs @@ -0,0 +1,34 @@ +// Client certificates from JavaScript match Node: a server that requests +// one reads socket.authorized, authorizationError and the peer +// certificate's chain, and a client sends its cert and key. +import * as tls from "node:tls"; +import { readFileSync } from "node:fs"; + +const D = "tests/fixtures/server/certs"; +const ca = readFileSync(`${D}/ca.pem`); +const cert = readFileSync(`${D}/localhost.pem`); +const key = readFileSync(`${D}/localhost-key.pem`); +const clientCert = readFileSync(`${D}/client.pem`); +const clientKey = readFileSync(`${D}/client-key.pem`); + +const lines = []; +const server = tls.createServer({ cert, key, ca, requestCert: true, rejectUnauthorized: false }, (socket) => { + const peer = socket.getPeerCertificate(true); + lines.push(`server ${socket.authorized} ${socket.authorizationError} ${peer.subject?.CN} ${peer.issuerCertificate?.subject.CN} ${peer.ext_key_usage}`); + socket.end("hello"); +}); +server.listen(0, () => { + const port = server.address().port; + const first = tls.connect({ port, ca, servername: "localhost", cert: clientCert, key: clientKey }, () => { + lines.push(`client ${first.authorized} ${first.getCertificate().subject.CN} ${first.getX509Certificate()?.subject}`); + }); + first.resume(); + first.on("end", () => { + const second = tls.connect({ port, ca, servername: "localhost" }, () => lines.push(`anonymous ${second.authorized}`)); + second.resume(); + second.on("end", () => { + for (const line of lines) console.log(line); + server.close(); + }); + }); +}); diff --git a/tests/corpus/7440-tls-server-add-context.ts b/tests/corpus/7440-tls-server-add-context.ts new file mode 100644 index 000000000..3cb29ebb3 --- /dev/null +++ b/tests/corpus/7440-tls-server-add-context.ts @@ -0,0 +1,119 @@ +// tls.Server's addContext and setSecureContext match Node: SNI names +// matched against exact and wildcard patterns (a "*" covers one label, +// case-insensitively, the newest match winning), the default context when +// nothing matches or an SNICallback is set, setSecureContext replacing the +// default context, the argument errors, the chain each context sends +// (completed from the default context's ca), and the store that verifies +// client certificates after each change. +import { readFileSync } from "node:fs"; +import type { AddressInfo } from "node:net"; +import * as tls from "node:tls"; + +const D = "tests/fixtures/server/certs"; +const r = (f: string): Buffer => readFileSync(`${D}/${f}`); +const ca = r("ca.pem"), ca2 = r("ca2.pem"), cert = r("localhost.pem"), key = r("localhost-key.pem"); +const alt = r("alt.pem"), altKey = r("alt-key.pem"), self = r("selfsigned.pem"), selfKey = r("selfsigned-key.pem"); +const client = r("client.pem"), clientKey = r("client-key.pem"); + +const listen = (server: tls.Server): Promise => + new Promise((d) => server.listen(0, () => d((server.address() as AddressInfo).port))); + +function peer(port: number, servername: string): Promise { + return new Promise((res) => { + const c = tls.connect({ port, servername, rejectUnauthorized: false }, () => { + const p = c.getPeerCertificate(); + res(`${p.subject.CN}${p.subject.CN === "localhost" && p.issuer.CN === "localhost" ? "(self)" : ""}`); + c.destroy(); + }); + c.on("error", (e: NodeJS.ErrnoException) => res(`error ${e.code}`)); + }); +} + +function chain(c: tls.TLSSocket): string { + const names: string[] = []; + let p: tls.DetailedPeerCertificate | undefined = c.getPeerCertificate(true); + for (let i = 0; p !== undefined && i < 4; i++) { + names.push(p.subject.CN as string); + if (p.issuerCertificate === p) break; + p = p.issuerCertificate; + } + return names.join(" -> "); +} + +function look(port: number, servername: string): Promise { + return new Promise((res) => { + const c = tls.connect({ port, servername, ca: ca2, rejectUnauthorized: false }, () => { + const line = `${c.authorizationError} ${chain(c)}`; + c.destroy(); + res(line); + }); + }); +} + +function attempt(label: string, run: () => void): void { + try { + run(); + console.log(label, "ok"); + } catch (e) { + const err = e as NodeJS.ErrnoException; + console.log(label, err.name, err.code, err.message.split("\n")[0]); + } +} + +{ + const server = tls.createServer({ cert, key }); + server.addContext("alt.localhost", { cert: alt, key: altKey }); + server.addContext("*.wild.test", tls.createSecureContext({ cert: self, key: selfKey })); + server.addContext("a.b.wild.test", { cert: alt, key: altKey }); + const port = await listen(server); + const names = ["alt.localhost", "ALT.localhost", "x.wild.test", "a.b.wild.test", "c.b.wild.test", "wild.test", ".wild.test", "other", "alt.localhostx"]; + for (const name of names) console.log("sni", name, await peer(port, name)); + attempt("addContext empty", () => server.addContext("", { cert, key })); + attempt("addContext string ctx", () => server.addContext("x.test", "nope" as unknown as tls.SecureContextOptions)); + server.addContext("alt.localhost", { cert: self, key: selfKey }); + console.log("override", await peer(port, "alt.localhost")); + server.setSecureContext({ cert: alt, key: altKey }); + console.log("setSecureContext default", await peer(port, "nomatch"), await peer(port, "alt.localhost")); + attempt("setSecureContext string", () => server.setSecureContext("x" as unknown as tls.SecureContextOptions)); + server.close(); +} + +{ + const server = tls.createServer({ cert, key, SNICallback: (n: string, cb: (err: Error | null, ctx?: tls.SecureContext) => void) => cb(null, undefined) }); + server.addContext("alt.localhost", { cert: alt, key: altKey }); + console.log("with SNICallback", await peer(await listen(server), "alt.localhost")); + server.close(); +} + +{ + const server = tls.createServer({ cert, key, ca }); + server.addContext("alt.localhost", { cert: alt, key: altKey }); + const port = await listen(server); + console.log("server ca, sni", await look(port, "alt.localhost")); + server.setSecureContext({ cert, key }); + console.log("after set without ca, sni", await look(port, "alt.localhost")); + console.log("after set without ca, default", await look(port, "localhost")); + server.close(); +} + +{ + const lines: string[] = []; + const server = tls.createServer({ cert, key, ca, requestCert: true, rejectUnauthorized: false }, (s) => { + lines.push(`server ${s.authorized} ${s.authorizationError}`); + s.end(); + }); + const port = await listen(server); + const once = (servername: string): Promise => + new Promise((res) => { + const c = tls.connect({ port, servername, ca, cert: client, key: clientKey }); + c.on("data", () => {}); + c.on("close", () => res()); + }); + await once("localhost"); + server.setSecureContext({ cert, key, ca: ca2 }); + await once("localhost"); + server.addContext("alt.localhost", { cert: alt, key: altKey, ca }); + await once("alt.localhost"); + console.log(lines.join(" | ")); + server.close(); +} diff --git a/tests/corpus/7441-tls-client-error.ts b/tests/corpus/7441-tls-client-error.ts new file mode 100644 index 000000000..431ea9019 --- /dev/null +++ b/tests/corpus/7441-tls-client-error.ts @@ -0,0 +1,93 @@ +// tls.Server's 'tlsClientError' event matches Node: the error a failed +// handshake reports (OpenSSL's codes and messages for an HTTP or proxy +// request, a client that rejects the certificate, a missing required +// certificate, an unsupported version and no common ALPN protocol; a +// "socket hang up" ECONNRESET for a client that leaves), the socket it +// passes, what the client sees, and the same event on https.Server. +import * as https from "node:https"; +import * as net from "node:net"; +import type { AddressInfo } from "node:net"; +import { readFileSync } from "node:fs"; +import * as tls from "node:tls"; + +const D = "tests/fixtures/server/certs"; +const r = (f: string): Buffer => readFileSync(`${D}/${f}`); +const ca = r("ca.pem"), ca2 = r("ca2.pem"), cert = r("localhost.pem"), key = r("localhost-key.pem"); +const clean = (m: string): string => m.replace(/^[0-9A-F]+:/, "").split(":../")[0]!; + +type Drive = (port: number, client: string[], fin: () => void) => void; + +async function scenario(label: string, make: (h: (s: tls.TLSSocket) => void) => tls.Server, drive: Drive): Promise { + await new Promise((done) => { + const events: string[] = []; + const client: string[] = []; + const server = make((s) => { + events.push("secureConnection"); + s.end("ok"); + }); + server.on("tlsClientError", (err: Error, socket: tls.TLSSocket) => { + events.push(`tlsClientError ${err.name} ${(err as NodeJS.ErrnoException).code} [${clean(err.message)}] destroyed=${socket.destroyed} remote=${typeof socket.remoteAddress}`); + socket.on("close", () => events.push("server socket close")); + }); + server.listen(0, () => { + drive((server.address() as AddressInfo).port, client, () => + setTimeout(() => { + console.log(label, "|", events.join(" ; "), "| client:", client.join(" ; ")); + server.close(() => done()); + }, 100), + ); + }); + }); +} + +const raw = (bytes: Buffer | null, endFirst: boolean): Drive => (port, client, fin) => { + const s = net.connect(port, "127.0.0.1", () => { + if (bytes !== null) s.write(bytes); + if (endFirst) s.end(); + }); + s.on("data", (d: Buffer) => client.push(`data ${d.length}`)); + s.on("end", () => client.push("end")); + s.on("error", (e: NodeJS.ErrnoException) => client.push(`error ${e.code}`)); + s.on("close", (hadError: boolean) => { + client.push(`close ${hadError}`); + fin(); + }); +}; + +const tlsc = (trust: Buffer, maxVersion: "TLSv1.2" | "TLSv1.3", alpn: boolean): Drive => (port, client, fin) => { + const c = alpn + ? tls.connect({ port, servername: "localhost", ca: trust, maxVersion, ALPNProtocols: ["http/1.1"] }) + : tls.connect({ port, servername: "localhost", ca: trust, maxVersion }); + c.on("secureConnect", () => client.push("secureConnect")); + c.on("error", (e: NodeJS.ErrnoException) => client.push(`error ${e.code}`)); + c.on("data", () => {}); + c.on("close", (hadError: boolean) => { + client.push(`close ${hadError}`); + fin(); + }); +}; + +const plain = (h: (s: tls.TLSSocket) => void): tls.Server => tls.createServer({ cert, key }, h); +await scenario("close before hello", plain, raw(null, true)); +await scenario("http request", plain, raw(Buffer.from("GET / HTTP/1.1\r\nHost: x\r\n\r\n"), false)); +await scenario("connect request", plain, raw(Buffer.from("CONNECT x:443 HTTP/1.1\r\n\r\n"), false)); +await scenario("half hello", plain, raw(Buffer.from([0x16, 0x03, 0x01, 0x02, 0x00, 0x01]), true)); +await scenario("client rejects cert", plain, tlsc(ca2, "TLSv1.3", false)); +await scenario("no cert, required", (h) => tls.createServer({ cert, key, requestCert: true, ca }, h), tlsc(ca, "TLSv1.3", false)); +await scenario("version", (h) => tls.createServer({ cert, key, minVersion: "TLSv1.3" }, h), tlsc(ca, "TLSv1.2", false)); +await scenario("alpn", (h) => tls.createServer({ cert, key, ALPNProtocols: ["h2"] }, h), tlsc(ca, "TLSv1.3", true)); +await scenario("ok", plain, tlsc(ca, "TLSv1.3", false)); + +{ + const server = https.createServer({ cert, key }, (req, res) => res.end("ok")); + server.on("tlsClientError", (err: Error, socket: tls.TLSSocket) => console.log("https tlsClientError", (err as NodeJS.ErrnoException).code, socket.destroyed)); + await new Promise((d) => server.listen(0, () => d())); + await new Promise((res) => { + const s = net.connect((server.address() as AddressInfo).port, "127.0.0.1", () => s.write("GET / HTTP/1.1\r\nHost: x\r\n\r\n")); + s.on("data", () => {}); + s.on("error", (e: NodeJS.ErrnoException) => console.log("https client error", e.code)); + s.on("close", () => res()); + }); + await new Promise((d) => setTimeout(d, 50)); + server.close(); +} diff --git a/tests/corpus/7442-tls-server-contexts.mjs b/tests/corpus/7442-tls-server-contexts.mjs new file mode 100644 index 000000000..97f797129 --- /dev/null +++ b/tests/corpus/7442-tls-server-contexts.mjs @@ -0,0 +1,51 @@ +// tls.Server's addContext, setSecureContext and 'tlsClientError' from +// JavaScript match Node: a wildcard SNI context, the default context +// replaced, and the errors a plain-text client and one that leaves +// before its hello report. +import * as net from "node:net"; +import * as tls from "node:tls"; +import { readFileSync } from "node:fs"; + +const D = "tests/fixtures/server/certs"; +const cert = readFileSync(`${D}/localhost.pem`); +const key = readFileSync(`${D}/localhost-key.pem`); +const alt = readFileSync(`${D}/alt.pem`); +const altKey = readFileSync(`${D}/alt-key.pem`); + +const server = tls.createServer({ cert, key }, (socket) => socket.end()); +server.addContext("*.localhost", { cert: alt, key: altKey }); +server.on("tlsClientError", (err, socket) => { + const reason = err.message.replace(/^[0-9A-F]+:/, "").split(":../")[0]; + console.log("tlsClientError", err.code, reason, socket.destroyed); +}); + +function peer(port, servername) { + return new Promise((resolve) => { + const c = tls.connect({ port, servername, rejectUnauthorized: false }, () => { + resolve(c.getPeerCertificate().subject.CN); + c.end(); + }); + }); +} + +function raw(port, bytes) { + return new Promise((resolve) => { + const s = net.connect(port, "127.0.0.1", () => { + if (bytes) s.write(bytes); + else s.end(); + }); + s.on("data", () => {}); + s.on("error", (err) => console.log("client error", err.code)); + s.on("close", () => setTimeout(resolve, 50)); + }); +} + +server.listen(0, async () => { + const { port } = server.address(); + console.log("sni", await peer(port, "alt.localhost"), await peer(port, "localhost")); + server.setSecureContext({ cert: alt, key: altKey }); + console.log("after setSecureContext", await peer(port, "example.test")); + await raw(port, "GET / HTTP/1.1\r\nHost: x\r\n\r\n"); + await raw(port, null); + server.close(); +}); diff --git a/tests/corpus/7443-tls-final-flight.ts b/tests/corpus/7443-tls-final-flight.ts new file mode 100644 index 000000000..b4de4b4d4 --- /dev/null +++ b/tests/corpus/7443-tls-final-flight.ts @@ -0,0 +1,114 @@ +// The last handshake flight is flushed when Node flushes it: after the +// callbacks that see the handshake finish and their nextTick callbacks, +// before the immediates they queue. A destroy() in secureConnect or a tick +// drops a TLS 1.3 client's Finished (the server reports a hang-up), one in +// secureConnection drops a TLS 1.2 server's Finished (the client ends, then +// fails), and data written beside it is dropped too; end() and a destroy +// in an immediate let it go out. A client whose server closes or resets +// mid-handshake gets Node's events, from tls.connect and https.request. +import { readFileSync } from "node:fs"; +import * as https from "node:https"; +import * as net from "node:net"; +import type { AddressInfo } from "node:net"; +import * as tls from "node:tls"; + +const D = "tests/fixtures/server/certs"; +const cert = readFileSync(`${D}/localhost.pem`), key = readFileSync(`${D}/localhost-key.pem`); +type Version = "TLSv1.2" | "TLSv1.3"; +const hows = ["destroy", "tick", "immediate", "write+destroy", "end"]; + +function act(s: tls.TLSSocket, how: string): void { + if (how === "destroy") s.destroy(); + else if (how === "tick") process.nextTick(() => s.destroy()); + else if (how === "immediate") setImmediate(() => s.destroy()); + else if (how === "write+destroy") { + s.write("hi"); + s.destroy(); + } else s.end("bye"); +} + +const listen = (server: net.Server): Promise => + new Promise((d) => server.listen(0, "127.0.0.1", () => d((server.address() as AddressInfo).port))); + +// the client acts in secureConnect; the server reports what arrived +for (const v of ["TLSv1.2", "TLSv1.3"] as Version[]) { + for (const how of hows) { + const ev: string[] = []; + const server = tls.createServer({ cert, key, maxVersion: v }, (s) => { + ev.push("secureConnection"); + s.on("data", (d: Buffer) => ev.push(`data ${d}`)); + // A client that closes before it reads the server's TLS 1.3 session + // tickets resets the connection. Whether the tickets are read first + // depends on the platform's timing, so that reset is not printed. + s.on("error", (e: NodeJS.ErrnoException) => { + if (e.code !== "ECONNRESET") ev.push(`server socket error ${e.code}`); + }); + }); + server.on("tlsClientError", (e: Error) => ev.push(`tlsClientError ${(e as NodeJS.ErrnoException).code}`)); + const port = await listen(server); + await new Promise((res) => { + const c = tls.connect({ port, host: "127.0.0.1", rejectUnauthorized: false }, () => act(c, how)); + c.on("close", () => setTimeout(res, 100)); + }); + console.log("client", v, how, "|", ev.join(" ; ")); + server.close(); + } +} + +// the server acts in secureConnection; the client reports what arrived +for (const v of ["TLSv1.2", "TLSv1.3"] as Version[]) { + for (const how of hows) { + const ev: string[] = []; + const server = tls.createServer({ cert, key, maxVersion: v }, (s) => { + s.on("error", () => {}); + act(s, how); + }); + const port = await listen(server); + await new Promise((res) => { + const c = tls.connect({ port, host: "127.0.0.1", rejectUnauthorized: false }, () => ev.push("secureConnect")); + c.on("data", (d: Buffer) => ev.push(`data ${d}`)); + c.on("end", () => ev.push("end")); + c.on("error", (e: NodeJS.ErrnoException) => ev.push(`error ${e.code} ${e.message}`)); + c.on("close", (hadError: boolean) => { + ev.push(`close ${hadError}`); + setTimeout(res, 50); + }); + }); + console.log("server", v, how, "|", ev.join(" ; ")); + server.close(); + } +} + +// a peer that closes or resets after the client's hello +for (const how of ["fin", "rst"]) { + for (const via of ["tls.connect", "https.request"]) { + const ev: string[] = []; + const server = net.createServer((s) => { + s.once("data", () => { + if (how === "rst") s.resetAndDestroy(); + else s.end(); + }); + }); + const port = await listen(server); + await new Promise((res) => { + if (via === "tls.connect") { + const c = tls.connect({ port, host: "127.0.0.1", rejectUnauthorized: false }); + c.on("end", () => ev.push("end")); + c.on("error", (e: NodeJS.ErrnoException) => ev.push(`error ${e.code} ${e.message}`)); + c.on("close", (hadError: boolean) => { + ev.push(`close ${hadError}`); + res(); + }); + } else { + const req = https.request({ host: "127.0.0.1", port, path: "/", rejectUnauthorized: false, agent: false }); + req.on("error", (e: NodeJS.ErrnoException) => { + ev.push(`request error ${e.code} ${e.message}`); + res(); + }); + req.end(); + } + }); + console.log("peer", how, via, "|", ev.join(" ; ")); + server.close(); + } +} diff --git a/tests/corpus/7444-tls-final-flight.mjs b/tests/corpus/7444-tls-final-flight.mjs new file mode 100644 index 000000000..e21de782c --- /dev/null +++ b/tests/corpus/7444-tls-final-flight.mjs @@ -0,0 +1,28 @@ +// The last handshake flight from JavaScript: a TLS 1.3 client that +// destroys its socket in secureConnect or a tick never sends its Finished, +// so the server reports a hang-up; one that waits for an immediate, or +// ends the socket, completes the server's handshake. +import * as tls from "node:tls"; +import { readFileSync } from "node:fs"; + +const D = "tests/fixtures/server/certs"; +const cert = readFileSync(`${D}/localhost.pem`); +const key = readFileSync(`${D}/localhost-key.pem`); + +for (const how of ["destroy", "tick", "immediate", "end"]) { + const events = []; + const server = tls.createServer({ cert, key }, () => events.push("secureConnection")); + server.on("tlsClientError", (err) => events.push(`tlsClientError ${err.code}`)); + await new Promise((resolve) => server.listen(0, "127.0.0.1", resolve)); + await new Promise((resolve) => { + const client = tls.connect({ port: server.address().port, host: "127.0.0.1", rejectUnauthorized: false }, () => { + if (how === "destroy") client.destroy(); + else if (how === "tick") process.nextTick(() => client.destroy()); + else if (how === "immediate") setImmediate(() => client.destroy()); + else client.end(); + }); + client.on("close", () => setTimeout(resolve, 100)); + }); + console.log(how, events.join(" ; ")); + server.close(); +} diff --git a/tests/corpus/7454-tls-peer-embedded-pem.ts b/tests/corpus/7454-tls-peer-embedded-pem.ts new file mode 100644 index 000000000..1937320e9 --- /dev/null +++ b/tests/corpus/7454-tls-peer-embedded-pem.ts @@ -0,0 +1,46 @@ +// A peer certificate whose extension carries another certificate's PEM as +// text: getPeerX509Certificate() and getX509Certificate() give the +// certificate the handshake delivered, and its fields, not the embedded +// one. new X509Certificate() of the same DER reads the PEM inside it first, +// as Node's PEM-before-DER parse does. +import { X509Certificate } from "node:crypto"; +import { readFileSync } from "node:fs"; +import type { AddressInfo } from "node:net"; +import * as tls from "node:tls"; + +const D = "tests/fixtures/server/certs"; +const cert = readFileSync(`${D}/embedded.pem`), key = readFileSync(`${D}/embedded-key.pem`); +const pem = new X509Certificate(cert); + +function describe(label: string, x: X509Certificate | undefined): void { + if (!x) return console.log(label, "undefined"); + console.log(label, x.subject, x.serialNumber, x.fingerprint256 === pem.fingerprint256, x.fingerprint === pem.fingerprint, x.validTo, x.raw.length); +} + +// raw is the certificate SEQUENCE, without bytes after it, and PEM armor +// counts only at the start of a line +const trailing = new X509Certificate(Buffer.concat([pem.raw, Buffer.from([1, 2, 3])])); +console.log("trailing bytes", trailing.raw.length === pem.raw.length, trailing.fingerprint256 === pem.fingerprint256, trailing.fingerprint === pem.fingerprint, trailing.validFrom === pem.validFrom); +for (const [label, input] of [["after a line", Buffer.concat([Buffer.from("text\n"), cert])], ["inside a line", Buffer.concat([Buffer.from("text"), cert])]] as const) { + try { + console.log(label, new X509Certificate(input).subject); + } catch (e) { + console.log(label, (e as NodeJS.ErrnoException).code); + } +} + +const server = tls.createServer({ cert, key }, (s) => { + describe("server own", s.getX509Certificate()); + s.end(); +}); +server.listen(0, "127.0.0.1", () => { + const c = tls.connect({ port: (server.address() as AddressInfo).port, host: "127.0.0.1", rejectUnauthorized: false }, () => { + const peer = c.getPeerX509Certificate(); + describe("client peer", peer); + const legacy = c.getPeerCertificate(); + console.log("legacy", legacy.subject.CN, legacy.fingerprint256 === pem.fingerprint256); + if (peer) describe("rebuilt from raw", new X509Certificate(peer.raw)); + }); + c.resume(); + c.on("close", () => server.close()); +}); diff --git a/tests/corpus/7455-tls-als-contexts.mjs b/tests/corpus/7455-tls-als-contexts.mjs new file mode 100644 index 000000000..38783fdf9 --- /dev/null +++ b/tests/corpus/7455-tls-als-contexts.mjs @@ -0,0 +1,48 @@ +// The AsyncLocalStorage store in TLS server and client events: a server's +// connections run in its listen() context, except 'tlsClientError', which +// Node emits with no store; a client's events run in its connect() context. +import * as tls from "node:tls"; +import { AsyncLocalStorage } from "node:async_hooks"; +import { readFileSync } from "node:fs"; + +const D = "tests/fixtures/server/certs"; +const cert = readFileSync(`${D}/localhost.pem`); +const key = readFileSync(`${D}/localhost-key.pem`); +const als = new AsyncLocalStorage(); +const serverEvents = []; +const clientEvents = []; +const server = tls.createServer({ cert, key }, (socket) => { + serverEvents.push(`secureConnection ${als.getStore()}`); + socket.on("data", () => { + serverEvents.push(`data ${als.getStore()}`); + socket.end("pong"); + }); +}); +server.on("tlsClientError", (err) => serverEvents.push(`tlsClientError ${err.code} ${als.getStore()}`)); +await als.run("listen", () => new Promise((resolve) => server.listen(0, "127.0.0.1", () => { + serverEvents.push(`listening ${als.getStore()}`); + resolve(); +}))); +const { port } = server.address(); +await als.run("client", () => new Promise((resolve) => { + const client = tls.connect({ port, host: "127.0.0.1", rejectUnauthorized: false }, () => { + clientEvents.push(`secureConnect ${als.getStore()}`); + client.write("ping"); + }); + client.on("data", () => clientEvents.push(`data ${als.getStore()}`)); + client.on("close", () => { + clientEvents.push(`close ${als.getStore()}`); + resolve(); + }); +})); +await als.run("untrusted", () => new Promise((resolve) => { + const client = tls.connect({ port, host: "127.0.0.1" }); + client.on("error", (err) => { + clientEvents.push(`error ${err.code} ${als.getStore()}`); + setTimeout(resolve, 100); + }); +})); +server.close(() => { + console.log("server:", serverEvents.join(" ; ")); + console.log("client:", clientEvents.join(" ; ")); +}); diff --git a/tests/diagnostics/x509-fences.ts b/tests/diagnostics/x509-fences.ts new file mode 100644 index 000000000..416a88b59 --- /dev/null +++ b/tests/diagnostics/x509-fences.ts @@ -0,0 +1,21 @@ +// X509Certificate keeps its fields as prototype getters, so Node's own-key +// walks over a certificate see none of them. Those walks are refused by +// name instead of listing the fields. +import { X509Certificate } from "node:crypto"; +import { readFileSync } from "node:fs"; + +const cert = new X509Certificate(readFileSync("cert.pem")); +console.log(Object.keys(cert)); +console.log(Object.entries(cert)); +console.log({ ...cert }); +console.log(Object.prototype.hasOwnProperty.call(cert, "subject")); +for (const key in cert) console.log(key); + +// A certificate in an unknown or any slot would cross as a plain object of +// its fields, which Node's certificate is not. +const held: unknown = cert; +console.log(held); +function describe(value: unknown): string { + return typeof value; +} +console.log(describe([cert])); diff --git a/tests/fixtures/node-types/tls-client-certificates.ts b/tests/fixtures/node-types/tls-client-certificates.ts new file mode 100644 index 000000000..3268369f9 --- /dev/null +++ b/tests/fixtures/node-types/tls-client-certificates.ts @@ -0,0 +1,32 @@ +// Under @types/node: a mutual-TLS server that requires a client +// certificate signed by its CA, and a client that presents one. +import { readFileSync } from "node:fs"; +import type { AddressInfo } from "node:net"; +import * as tls from "node:tls"; + +const certs = "tests/fixtures/server/certs"; +const ca = readFileSync(`${certs}/ca.pem`); + +const cert = readFileSync(`${certs}/localhost.pem`); +const key = readFileSync(`${certs}/localhost-key.pem`); +let serverLine = ""; +const server = tls.createServer({ cert, key, ca, requestCert: true, rejectUnauthorized: true }, (socket: tls.TLSSocket) => { + const peer: tls.PeerCertificate = socket.getPeerCertificate(); + serverLine = `server ${socket.authorized} ${String(socket.authorizationError)} ${peer.subject.CN}`; + socket.end("welcome"); +}); +server.listen(0, "127.0.0.1", () => { + const port = (server.address() as AddressInfo).port; + const clientCert = readFileSync(`${certs}/client.pem`); + const clientKey = readFileSync(`${certs}/client-key.pem`); + const client = tls.connect({ port, host: "127.0.0.1", servername: "localhost", ca, cert: clientCert, key: clientKey }, () => { + console.log("client", client.authorized, client.getX509Certificate()?.subject); + }); + let body = ""; + client.on("data", (chunk: Buffer) => (body += chunk.toString())); + client.on("end", () => { + console.log(serverLine); + console.log("body", body); + server.close(); + }); +}); diff --git a/tests/fixtures/node-types/tls-peer-certificates.ts b/tests/fixtures/node-types/tls-peer-certificates.ts new file mode 100644 index 000000000..d082cfead --- /dev/null +++ b/tests/fixtures/node-types/tls-peer-certificates.ts @@ -0,0 +1,37 @@ +// Under @types/node: a TLS client reads the server's certificate as the +// legacy object, its detailed issuer chain and an X509Certificate, and the +// server reads the certificate it serves. +import { readFileSync } from "node:fs"; +import type { AddressInfo } from "node:net"; +import * as tls from "node:tls"; + +const certs = "tests/fixtures/server/certs"; +const ca = readFileSync(`${certs}/ca.pem`); +const cert = readFileSync(`${certs}/localhost.pem`); +const key = readFileSync(`${certs}/localhost-key.pem`); + +// The server's line prints once the client has its reply, so the output +// order does not depend on which side's callback runs first. +let serverLine = ""; +const server = tls.createServer({ cert, key }, (socket: tls.TLSSocket) => { + const own = socket.getCertificate() as tls.PeerCertificate; + serverLine = `server ${own.subject.CN} ${socket.getX509Certificate()?.subject} ${Object.keys(socket.getPeerCertificate()).length}`; + socket.end("done"); +}); +server.listen(0, "127.0.0.1", () => { + const port = (server.address() as AddressInfo).port; + const client = tls.connect({ port, host: "127.0.0.1", ca, servername: "localhost" }, () => { + const peer: tls.PeerCertificate = client.getPeerCertificate(); + const detailed: tls.DetailedPeerCertificate = client.getPeerCertificate(true); + console.log("client", peer.subject.CN, peer.subjectaltname, peer.bits, detailed.issuerCertificate.subject.CN); + console.log("root", detailed.issuerCertificate.issuerCertificate === detailed.issuerCertificate); + const x509 = client.getPeerX509Certificate(); + if (x509 !== undefined) console.log("x509", x509.subject, x509.checkIP("127.0.0.1"), x509.fingerprint256 === peer.fingerprint256); + }); + client.resume(); + client.on("end", () => { + console.log(serverLine); + client.destroy(); + server.close(); + }); +}); diff --git a/tests/fixtures/node-types/tls-server-contexts.ts b/tests/fixtures/node-types/tls-server-contexts.ts new file mode 100644 index 000000000..ff0425a56 --- /dev/null +++ b/tests/fixtures/node-types/tls-server-contexts.ts @@ -0,0 +1,38 @@ +// Under @types/node: a tls.Server that answers an SNI name from +// addContext, replaces its default context with setSecureContext, and +// reports a plain-text client through 'tlsClientError'. +import { readFileSync } from "node:fs"; +import * as net from "node:net"; +import type { AddressInfo } from "node:net"; +import * as tls from "node:tls"; + +const certs = "tests/fixtures/server/certs"; +const cert = readFileSync(`${certs}/localhost.pem`); +const key = readFileSync(`${certs}/localhost-key.pem`); +const alt = readFileSync(`${certs}/alt.pem`); +const altKey = readFileSync(`${certs}/alt-key.pem`); + +const server: tls.Server = tls.createServer({ cert, key }, (socket: tls.TLSSocket) => socket.end()); +server.addContext("*.localhost", tls.createSecureContext({ cert: alt, key: altKey })); +server.on("tlsClientError", (err: Error, socket: tls.TLSSocket) => { + console.log("tlsClientError", (err as NodeJS.ErrnoException).code, socket.destroyed); +}); + +function subject(port: number, servername: string): Promise { + return new Promise((resolve) => { + const client = tls.connect({ port, host: "127.0.0.1", servername, rejectUnauthorized: false }, () => { + resolve(String(client.getPeerCertificate().subject.CN)); + client.end(); + }); + }); +} + +server.listen(0, "127.0.0.1", async () => { + const port = (server.address() as AddressInfo).port; + console.log("sni", await subject(port, "alt.localhost"), await subject(port, "localhost")); + server.setSecureContext({ cert: alt, key: altKey }); + console.log("default", await subject(port, "localhost")); + const raw = net.connect(port, "127.0.0.1", () => raw.write("GET / HTTP/1.1\r\nHost: x\r\n\r\n")); + raw.on("data", () => {}); + raw.on("close", () => setTimeout(() => server.close(), 50)); +}); diff --git a/tests/fixtures/node-types/x509-methods.ts b/tests/fixtures/node-types/x509-methods.ts new file mode 100644 index 000000000..8736ec990 --- /dev/null +++ b/tests/fixtures/node-types/x509-methods.ts @@ -0,0 +1,20 @@ +// Under @types/node: X509Certificate's methods over the test certificates: +// the issuer, the signature, the host and IP names, the private key, the +// legacy object and the PEM text. +import { X509Certificate, createPrivateKey } from "node:crypto"; +import { readFileSync } from "node:fs"; +import type { PeerCertificate } from "node:tls"; + +const certs = "tests/fixtures/server/certs"; +const ca = new X509Certificate(readFileSync(`${certs}/ca.pem`)); +const leaf = new X509Certificate(readFileSync(`${certs}/localhost.pem`)); +const key = createPrivateKey(readFileSync(`${certs}/localhost-key.pem`)); + +console.log(leaf.checkIssued(ca), leaf.verify(ca.publicKey), ca.verify(leaf.publicKey)); +const host: string | undefined = leaf.checkHost("localhost"); +console.log(host, leaf.checkHost("example.com"), leaf.checkIP("127.0.0.1"), leaf.checkIP("::1")); +console.log(leaf.checkEmail("root@localhost", { subject: "always" }), leaf.checkPrivateKey(key)); +const legacy: PeerCertificate = leaf.toLegacyObject(); +console.log(legacy.subject.CN, legacy.subjectaltname, legacy.bits, legacy.exponent, legacy.raw.equals(leaf.raw)); +console.log(leaf.publicKey.asymmetricKeyType, leaf.publicKey === leaf.publicKey); +console.log(leaf.toString() === readFileSync(`${certs}/localhost.pem`, "latin1"), String(ca).split("\n")[0]); diff --git a/tests/fixtures/server/certs/README.md b/tests/fixtures/server/certs/README.md index dd383f028..2ab5c1839 100644 --- a/tests/fixtures/server/certs/README.md +++ b/tests/fixtures/server/certs/README.md @@ -13,3 +13,15 @@ Minted ONCE with the openssl recipe below (see san.cnf) and committed with a 100 (ca2 repeats the ca recipe with its own key and CN.) `alt.pem`/`alt-key.pem` (the SNI fixtures' second identity: CN=alt.localhost, SAN DNS:alt.localhost) repeats the leaf recipe against the same `ca.pem`, with an ext section whose subjectAltName is `DNS:alt.localhost`. + +`client.pem`/`client-key.pem` (CN=scriptc test client) is a client certificate for the mutual-TLS fixtures: a P-256 leaf signed by `ca.pem` whose extended key usage is clientAuth (`client.cnf`, section `ext`): + + openssl ecparam -genkey -name prime256v1 -noout -out client-key.pem + openssl req -new -key client-key.pem -out client.csr -subj "/CN=scriptc test client" -config client.cnf + openssl x509 -req -in client.csr -CA ca.pem -CAkey ca-key.pem -CAcreateserial -out client.pem -days 36500 -extfile client.cnf -extensions ext + +`embedded.pem`/`embedded-key.pem` (CN=embedded pem) is a localhost leaf signed by `ca.pem` whose Netscape comment extension holds `alt.pem` as PEM text on one line (`embedded.cnf`, section `ext`). It checks that a peer certificate's DER is read as DER: + + openssl ecparam -genkey -name prime256v1 -noout -out embedded-key.pem + openssl req -new -key embedded-key.pem -out embedded.csr -subj "/CN=embedded pem" -config embedded.cnf + openssl x509 -req -in embedded.csr -CA ca.pem -CAkey ca-key.pem -set_serial 4242 -out embedded.pem -days 36500 -extfile embedded.cnf -extensions ext diff --git a/tests/fixtures/server/certs/client-key.pem b/tests/fixtures/server/certs/client-key.pem new file mode 100644 index 000000000..90f95c680 --- /dev/null +++ b/tests/fixtures/server/certs/client-key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIE6TPp76NrDFeBw1tQSN7lygt9zixQ5xaGb0Xug5/aNVoAoGCCqGSM49 +AwEHoUQDQgAE9iN6ruUQ8IneIyb280iqEfRKAusDKrssfCJh7717mNISg8U7TKvG +XXxgsHD/8NKQjw1Z5SZye7FfNv0WetLRvg== +-----END EC PRIVATE KEY----- diff --git a/tests/fixtures/server/certs/client.cnf b/tests/fixtures/server/certs/client.cnf new file mode 100644 index 000000000..4b7151ef4 --- /dev/null +++ b/tests/fixtures/server/certs/client.cnf @@ -0,0 +1,7 @@ +[req] +distinguished_name = dn +[dn] +[ext] +basicConstraints = CA:FALSE +keyUsage = digitalSignature +extendedKeyUsage = clientAuth diff --git a/tests/fixtures/server/certs/client.pem b/tests/fixtures/server/certs/client.pem new file mode 100644 index 000000000..6458a0fe2 --- /dev/null +++ b/tests/fixtures/server/certs/client.pem @@ -0,0 +1,11 @@ +-----BEGIN CERTIFICATE----- +MIIBqzCCAVKgAwIBAgIUBVrP4y4NCL3DYzbSrpkMIwuBg2owCgYIKoZIzj0EAwIw +GzEZMBcGA1UEAwwQdHNuYXRpdmUgdGVzdCBDQTAgFw0yNjEwMjIxNTUxMTZaGA8y +MTI2MDkyODE1NTExNlowHjEcMBoGA1UEAwwTc2NyaXB0YyB0ZXN0IGNsaWVudDBZ +MBMGByqGSM49AgEGCCqGSM49AwEHA0IABPYjeq7lEPCJ3iMm9vNIqhH0SgLrAyq7 +LHwiYe+9e5jSEoPFO0yrxl18YLBw//DSkI8NWeUmcnuxXzb9FnrS0b6jbzBtMAkG +A1UdEwQCMAAwCwYDVR0PBAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMCMB0GA1Ud +DgQWBBS/BxjyTMQkc2IMuhvzyDUhflemADAfBgNVHSMEGDAWgBT7ISW3gYKaXUJu +ZYa2OrD6IBZbBTAKBggqhkjOPQQDAgNHADBEAiBy+DnJFvCUyNmxxeMaWW93n3vJ +XPzLMFQyyoe+hKhoYQIgIDT731Nwwcw/H0Mb+nsb7HMHYihYssPzK52XFAqKA9A= +-----END CERTIFICATE----- diff --git a/tests/fixtures/server/certs/embedded-key.pem b/tests/fixtures/server/certs/embedded-key.pem new file mode 100644 index 000000000..ddf76b1d3 --- /dev/null +++ b/tests/fixtures/server/certs/embedded-key.pem @@ -0,0 +1,5 @@ +-----BEGIN EC PRIVATE KEY----- +MHcCAQEEIMzj49L98KADiH/rd18MLx2kdJ8fMMd3Al4AWOE7Ma1VoAoGCCqGSM49 +AwEHoUQDQgAEIdpwV/6VqvmMJkIoZPPgnfNdn+e+NVxyLMMY5n90YMWRfy45AZwn +f/57ssBgq0FC1GDaLRe4dLL9YCSDq3pOzQ== +-----END EC PRIVATE KEY----- diff --git a/tests/fixtures/server/certs/embedded.cnf b/tests/fixtures/server/certs/embedded.cnf new file mode 100644 index 000000000..8d9556e43 --- /dev/null +++ b/tests/fixtures/server/certs/embedded.cnf @@ -0,0 +1,9 @@ +[req] +distinguished_name = dn +[dn] +[ext] +basicConstraints = CA:FALSE +keyUsage = digitalSignature, keyEncipherment +extendedKeyUsage = serverAuth +subjectAltName = DNS:localhost, IP:127.0.0.1, IP:::1 +nsComment = "-----BEGIN CERTIFICATE-----MIIBwzCCAWigAwIBAgIUSw5Q3SUK8/VNBnfXUCOkHzR4ShUwCgYIKoZIzj0EAwIwGzEZMBcGA1UEAwwQdHNuYXRpdmUgdGVzdCBDQTAgFw0yNjA3MTcwMDU2MjBaGA8yMTI2MDYyMzAwNTYyMFowGDEWMBQGA1UEAwwNYWx0LmxvY2FsaG9zdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABJyVZDQSTyauFgEwMTksal/hOBhIYpCAzEBCyQq6e23ETTb4NNwIL/NI0ILAr6QmhJaInY31QJq1NFHDkl4N5YujgYowgYcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwGAYDVR0RBBEwD4INYWx0LmxvY2FsaG9zdDAdBgNVHQ4EFgQU/Ho4zrglTx9pFwqI+09JFLH84LQwHwYDVR0jBBgwFoAU+yElt4GCml1CbmWGtjqw+iAWWwUwCgYIKoZIzj0EAwIDSQAwRgIhAOUMUtjnIJaYCnPV4YrDMrgIziihcbkq6ZqKBSwwbCMOAiEA0vfd3QpyrdTIKwuopJLg2gA6QPnRTXrZdYr0M3NmJ3Q=-----END CERTIFICATE-----" diff --git a/tests/fixtures/server/certs/embedded.pem b/tests/fixtures/server/certs/embedded.pem new file mode 100644 index 000000000..577ea39b8 --- /dev/null +++ b/tests/fixtures/server/certs/embedded.pem @@ -0,0 +1,26 @@ +-----BEGIN CERTIFICATE----- +MIIEbzCCBBagAwIBAgICEJIwCgYIKoZIzj0EAwIwGzEZMBcGA1UEAwwQdHNuYXRp +dmUgdGVzdCBDQTAgFw0yNjEwMjMxNjEwMzVaGA8yMTI2MDkyOTE2MTAzNVowFzEV +MBMGA1UEAwwMZW1iZWRkZWQgcGVtMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE +IdpwV/6VqvmMJkIoZPPgnfNdn+e+NVxyLMMY5n90YMWRfy45AZwnf/57ssBgq0FC +1GDaLRe4dLL9YCSDq3pOzaOCA0owggNGMAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWg +MBMGA1UdJQQMMAoGCCsGAQUFBwMBMCwGA1UdEQQlMCOCCWxvY2FsaG9zdIcEfwAA +AYcQAAAAAAAAAAAAAAAAAAAAATCCAqcGCWCGSAGG+EIBDQSCApgWggKULS0tLS1C +RUdJTiBDRVJUSUZJQ0FURS0tLS0tTUlJQnd6Q0NBV2lnQXdJQkFnSVVTdzVRM1NV +SzgvVk5CbmZYVUNPa0h6UjRTaFV3Q2dZSUtvWkl6ajBFQXdJd0d6RVpNQmNHQTFV +RUF3d1FkSE51WVhScGRtVWdkR1Z6ZENCRFFUQWdGdzB5TmpBM01UY3dNRFUyTWpC +YUdBOHlNVEkyTURZeU16QXdOVFl5TUZvd0dERVdNQlFHQTFVRUF3d05ZV3gwTG14 +dlkyRnNhRzl6ZERCWk1CTUdCeXFHU000OUFnRUdDQ3FHU000OUF3RUhBMElBQkp5 +VlpEUVNUeWF1RmdFd01Ua3NhbC9oT0JoSVlwQ0F6RUJDeVFxNmUyM0VUVGI0Tk53 +SUwvTkkwSUxBcjZRbWhKYUluWTMxUUpxMU5GSERrbDRONVl1amdZb3dnWWN3Q1FZ +RFZSMFRCQUl3QURBTEJnTlZIUThFQkFNQ0JhQXdFd1lEVlIwbEJBd3dDZ1lJS3dZ +QkJRVUhBd0V3R0FZRFZSMFJCQkV3RDRJTllXeDBMbXh2WTJGc2FHOXpkREFkQmdO +VkhRNEVGZ1FVL0hvNHpyZ2xUeDlwRndxSSswOUpGTEg4NExRd0h3WURWUjBqQkJn +d0ZvQVUreUVsdDRHQ21sMUNibVdHdGpxdytpQVdXd1V3Q2dZSUtvWkl6ajBFQXdJ +RFNRQXdSZ0loQU9VTVV0am5JSmFZQ25QVjRZckRNcmdJemlpaGNia3E2WnFLQlN3 +d2JDTU9BaUVBMHZmZDNRcHlyZFRJS3d1b3BKTGcyZ0E2UVBuUlRYclpkWXIwTTNO +bUozUT0tLS0tLUVORCBDRVJUSUZJQ0FURS0tLS0tMB0GA1UdDgQWBBQ+Y3aDuoRS +0FRNT2st7Lzlo7BtDjAfBgNVHSMEGDAWgBT7ISW3gYKaXUJuZYa2OrD6IBZbBTAK +BggqhkjOPQQDAgNHADBEAiB3zl81cDKI4GvoRBDneF53eeLR6ftnaD9Pf6hCHUUA +zwIgauFJwF7rLQ0krjZXxdOMZEOl7i1sBrlOfGiIyGSn84s= +-----END CERTIFICATE----- diff --git a/tests/fixtures/tls/empty-ca.ts b/tests/fixtures/tls/empty-ca.ts new file mode 100644 index 000000000..7d1d30928 --- /dev/null +++ b/tests/fixtures/tls/empty-ca.ts @@ -0,0 +1,36 @@ +// A server's ca option as a trust store for client certificates, run with +// NODE_EXTRA_CA_CERTS naming the test CA, so the default store trusts the +// client: an empty Buffer is an empty store, an empty string and no ca use +// the default store. +import { readFileSync } from "node:fs"; +import type { AddressInfo } from "node:net"; +import * as tls from "node:tls"; + +const D = "tests/fixtures/server/certs"; +const r = (f: string): Buffer => readFileSync(`${D}/${f}`); +const cert = r("localhost.pem"), key = r("localhost-key.pem"), ca = r("ca.pem"); +const cases: [string, Buffer | string | undefined][] = [ + ["empty Buffer", Buffer.alloc(0)], + ["empty string", ""], + ["no ca", undefined], + ["ca", ca], +]; +for (const [label, value] of cases) { + await new Promise((done) => { + const report = (s: tls.TLSSocket): void => { + console.log(label, s.authorized, s.authorizationError); + s.end(); + }; + const server = + value === undefined + ? tls.createServer({ cert, key, requestCert: true, rejectUnauthorized: false }, report) + : tls.createServer({ cert, key, requestCert: true, rejectUnauthorized: false, ca: value }, report); + server.listen(0, "127.0.0.1", () => { + const port = (server.address() as AddressInfo).port; + const c = tls.connect({ port, host: "127.0.0.1", ca, servername: "localhost", cert: r("client.pem"), key: r("client-key.pem") }); + c.on("error", () => {}); + c.resume(); + c.on("close", () => server.close(() => done())); + }); + }); +} diff --git a/tests/harness/__snapshots__/tls-sni-callback-fences.ts.txt b/tests/harness/__snapshots__/tls-sni-callback-fences.ts.txt index c45608bb9..80ace6df6 100644 --- a/tests/harness/__snapshots__/tls-sni-callback-fences.ts.txt +++ b/tests/harness/__snapshots__/tls-sni-callback-fences.ts.txt @@ -5,4 +5,4 @@ tls-sni-callback-fences.ts:13:54 - error SC2020: 'tls.createServer with SNICallb | ^~~~~~~~~~~~~~~~~~~~ 14 | - hint: SNICallback lowers with cert and key; ALPNProtocols, minVersion, maxVersion and the validated options are not combined with it yet \ No newline at end of file + hint: SNICallback lowers with cert and key; ALPNProtocols, minVersion, maxVersion, requestCert, ca and the validated options are not combined with it yet \ No newline at end of file diff --git a/tests/harness/__snapshots__/x509-fences.ts.txt b/tests/harness/__snapshots__/x509-fences.ts.txt new file mode 100644 index 000000000..2f5cc4e68 --- /dev/null +++ b/tests/harness/__snapshots__/x509-fences.ts.txt @@ -0,0 +1,48 @@ +x509-fences.ts:8:13 - error SC1090: Object.keys over X509Certificate values (Node keeps their fields as prototype getters, so own-key walks see none; read the fields) are not supported yet + + 7 | const cert = new X509Certificate(readFileSync("cert.pem")); + 8 | console.log(Object.keys(cert)); + | ^~~~~~~~~~~~~~~~~ + 9 | console.log(Object.entries(cert)); + +x509-fences.ts:9:13 - error SC1090: Object.entries over X509Certificate values (Node keeps their fields as prototype getters, so own-key walks see none; read the fields) are not supported yet + + 8 | console.log(Object.keys(cert)); + 9 | console.log(Object.entries(cert)); + | ^~~~~~~~~~~~~~~~~~~~ + 10 | console.log({ ...cert }); + +x509-fences.ts:10:15 - error SC1090: object spread over X509Certificate values (Node keeps their fields as prototype getters, so own-key walks see none; read the fields) are not supported yet + + 9 | console.log(Object.entries(cert)); + 10 | console.log({ ...cert }); + | ^~~~~~~ + 11 | console.log(Object.prototype.hasOwnProperty.call(cert, "subject")); + +x509-fences.ts:11:50 - error SC1090: Object.prototype.hasOwnProperty over X509Certificate values (Node keeps their fields as prototype getters, so own-key walks see none; read the fields) are not supported yet + + 10 | console.log({ ...cert }); + 11 | console.log(Object.prototype.hasOwnProperty.call(cert, "subject")); + | ^~~~ + 12 | for (const key in cert) console.log(key); + +x509-fences.ts:12:19 - error SC1090: for-in over X509Certificate values (Node keeps their fields as prototype getters, so own-key walks see none; read the fields) are not supported yet + + 11 | console.log(Object.prototype.hasOwnProperty.call(cert, "subject")); + 12 | for (const key in cert) console.log(key); + | ^~~~ + 13 | + +x509-fences.ts:16:23 - error SC1090: X509Certificate values in 'unknown' or 'any' slots (Node keeps a certificate's fields as prototype getters, and its toString() and toJSON() give the PEM; keep the X509Certificate type) are not supported yet + + 15 | // its fields, which Node's certificate is not. + 16 | const held: unknown = cert; + | ^~~~ + 17 | console.log(held); + +x509-fences.ts:21:23 - error SC1090: X509Certificate values in 'unknown' or 'any' slots (Node keeps a certificate's fields as prototype getters, and its toString() and toJSON() give the PEM; keep the X509Certificate type) are not supported yet + + 20 | } + 21 | console.log(describe([cert])); + | ^~~~ + 22 | \ No newline at end of file diff --git a/tests/harness/corpus-costs/6936-x509-certificate-fields.ts.json b/tests/harness/corpus-costs/6936-x509-certificate-fields.ts.json new file mode 100644 index 000000000..73e8107eb --- /dev/null +++ b/tests/harness/corpus-costs/6936-x509-certificate-fields.ts.json @@ -0,0 +1 @@ +{ "plain": 3042, "san": 5637 } diff --git a/tests/harness/corpus-costs/7090-x509-check-names.ts.json b/tests/harness/corpus-costs/7090-x509-check-names.ts.json new file mode 100644 index 000000000..3ee86dd28 --- /dev/null +++ b/tests/harness/corpus-costs/7090-x509-check-names.ts.json @@ -0,0 +1 @@ +{ "plain": 4003, "san": 5700 } diff --git a/tests/harness/corpus-costs/7091-x509-certificate-keys.ts.json b/tests/harness/corpus-costs/7091-x509-certificate-keys.ts.json new file mode 100644 index 000000000..a9b159564 --- /dev/null +++ b/tests/harness/corpus-costs/7091-x509-certificate-keys.ts.json @@ -0,0 +1 @@ +{ "plain": 4335, "san": 8298 } diff --git a/tests/harness/corpus-costs/7092-x509-legacy-object.ts.json b/tests/harness/corpus-costs/7092-x509-legacy-object.ts.json new file mode 100644 index 000000000..c7e0c4ee2 --- /dev/null +++ b/tests/harness/corpus-costs/7092-x509-legacy-object.ts.json @@ -0,0 +1 @@ +{ "plain": 3910, "san": 5665 } diff --git a/tests/harness/corpus-costs/7093-x509-methods-js.mjs.json b/tests/harness/corpus-costs/7093-x509-methods-js.mjs.json new file mode 100644 index 000000000..8f60594f1 --- /dev/null +++ b/tests/harness/corpus-costs/7093-x509-methods-js.mjs.json @@ -0,0 +1 @@ +{ "plain": 4421, "san": 5823 } diff --git a/tests/harness/corpus-costs/7095-tls-peer-certificates.ts.json b/tests/harness/corpus-costs/7095-tls-peer-certificates.ts.json new file mode 100644 index 000000000..68214a26c --- /dev/null +++ b/tests/harness/corpus-costs/7095-tls-peer-certificates.ts.json @@ -0,0 +1 @@ +{ "plain": 9277, "san": 14000 } diff --git a/tests/harness/corpus-costs/7096-tls-peer-certificates.mjs.json b/tests/harness/corpus-costs/7096-tls-peer-certificates.mjs.json new file mode 100644 index 000000000..ec7c1e0f4 --- /dev/null +++ b/tests/harness/corpus-costs/7096-tls-peer-certificates.mjs.json @@ -0,0 +1 @@ +{ "plain": 4576, "san": 8354 } diff --git a/tests/harness/corpus-costs/7097-tls-client-certificates.ts.json b/tests/harness/corpus-costs/7097-tls-client-certificates.ts.json new file mode 100644 index 000000000..2776a867c --- /dev/null +++ b/tests/harness/corpus-costs/7097-tls-client-certificates.ts.json @@ -0,0 +1 @@ +{ "plain": 8917, "san": 11888 } diff --git a/tests/harness/corpus-costs/7098-tls-client-certificates-paths.ts.json b/tests/harness/corpus-costs/7098-tls-client-certificates-paths.ts.json new file mode 100644 index 000000000..f55fef2c1 --- /dev/null +++ b/tests/harness/corpus-costs/7098-tls-client-certificates-paths.ts.json @@ -0,0 +1 @@ +{ "plain": 6188, "san": 10754 } diff --git a/tests/harness/corpus-costs/7099-tls-client-certificates.mjs.json b/tests/harness/corpus-costs/7099-tls-client-certificates.mjs.json new file mode 100644 index 000000000..02414f135 --- /dev/null +++ b/tests/harness/corpus-costs/7099-tls-client-certificates.mjs.json @@ -0,0 +1 @@ +{ "plain": 4389, "san": 5772 } diff --git a/tests/harness/corpus-costs/7440-tls-server-add-context.ts.json b/tests/harness/corpus-costs/7440-tls-server-add-context.ts.json new file mode 100644 index 000000000..f61acc3da --- /dev/null +++ b/tests/harness/corpus-costs/7440-tls-server-add-context.ts.json @@ -0,0 +1 @@ +{ "plain": 2787, "san": 2973 } diff --git a/tests/harness/corpus-costs/7441-tls-client-error.ts.json b/tests/harness/corpus-costs/7441-tls-client-error.ts.json new file mode 100644 index 000000000..a928ec1f1 --- /dev/null +++ b/tests/harness/corpus-costs/7441-tls-client-error.ts.json @@ -0,0 +1 @@ +{ "plain": 6387, "san": 6135 } diff --git a/tests/harness/corpus-costs/7442-tls-server-contexts.mjs.json b/tests/harness/corpus-costs/7442-tls-server-contexts.mjs.json new file mode 100644 index 000000000..8630193d3 --- /dev/null +++ b/tests/harness/corpus-costs/7442-tls-server-contexts.mjs.json @@ -0,0 +1 @@ +{ "plain": 2866, "san": 2854 } diff --git a/tests/harness/corpus-costs/7443-tls-final-flight.ts.json b/tests/harness/corpus-costs/7443-tls-final-flight.ts.json new file mode 100644 index 000000000..2eb48c40b --- /dev/null +++ b/tests/harness/corpus-costs/7443-tls-final-flight.ts.json @@ -0,0 +1 @@ +{ "plain": 8793, "san": 8889 } diff --git a/tests/harness/corpus-costs/7444-tls-final-flight.mjs.json b/tests/harness/corpus-costs/7444-tls-final-flight.mjs.json new file mode 100644 index 000000000..ddc1e1368 --- /dev/null +++ b/tests/harness/corpus-costs/7444-tls-final-flight.mjs.json @@ -0,0 +1 @@ +{ "plain": 3913, "san": 3715 } diff --git a/tests/harness/corpus-costs/7454-tls-peer-embedded-pem.ts.json b/tests/harness/corpus-costs/7454-tls-peer-embedded-pem.ts.json new file mode 100644 index 000000000..034b69448 --- /dev/null +++ b/tests/harness/corpus-costs/7454-tls-peer-embedded-pem.ts.json @@ -0,0 +1 @@ +{ "plain": 2535, "san": 3999 } diff --git a/tests/harness/corpus-costs/7455-tls-als-contexts.mjs.json b/tests/harness/corpus-costs/7455-tls-als-contexts.mjs.json new file mode 100644 index 000000000..53219fb76 --- /dev/null +++ b/tests/harness/corpus-costs/7455-tls-als-contexts.mjs.json @@ -0,0 +1 @@ +{ "plain": 3306, "san": 4617 } diff --git a/tests/harness/errors.test.ts b/tests/harness/errors.test.ts index f8068ac81..20231a94e 100644 --- a/tests/harness/errors.test.ts +++ b/tests/harness/errors.test.ts @@ -954,8 +954,8 @@ listener.listen(0, () => { }); // With a secureContext, the TLSSocket's own options still apply: a truthy -// requestCert, which asks for client certificates this runtime does not -// verify, and SNICallback throw the fence instead of being dropped. +// requestCert (which lowers with cert and key, whose ca the runtime reads) +// and SNICallback throw the fence instead of being dropped. describe("tls.TLSSocket socket options beside a secureContext", () => { test("requestCert and SNICallback throw the fence", async () => { const r = await compileAndRun( @@ -990,7 +990,7 @@ listener.listen(0, () => { ); expect(r.stderr).toBe(""); expect(r.stdout).toBe( - "requestCert new tls.TLSSocket option 'requestCert' has no static lowering — client-certificate handshakes are not modeled (SEMANTICS.md divergence 55) — requestCert stays at Node's false default\n" + + "requestCert new tls.TLSSocket option 'requestCert' has no static lowering — requestCert lowers with cert and key options, not beside a secureContext\n" + "SNICallback new tls.TLSSocket option 'SNICallback' has no static lowering — isServer, cert, key, secureContext, ALPNProtocols, minVersion and maxVersion are the implemented members\n" + "requestCert false no error\n" + "client closed\n", @@ -998,6 +998,93 @@ listener.listen(0, () => { }); }); +// A client certificate lowers as a cert and key pair; one without the +// other throws the fence before any connection is made. +describe("client certificates without both cert and key", () => { + test("tls.connect and https.request throw the fence", async () => { + const r = await compileAndRun( + "tls-client-certificate-fences", + `import { readFileSync } from "node:fs"; +import * as https from "node:https"; +import * as tls from "node:tls"; +const certs = "tests/fixtures/server/certs"; +const cert = readFileSync(\`\${certs}/client.pem\`); +const key = readFileSync(\`\${certs}/client-key.pem\`); +function report(label: string, run: () => void): void { + try { + run(); + console.log(label, "no error"); + } catch (error) { + console.log(label, (error as Error).message); + } +} +report("connect cert only", () => tls.connect({ port: 1, host: "127.0.0.1", cert })); +report("connect key only", () => tls.connect({ port: 1, host: "127.0.0.1", key })); +report("request key only", () => https.request({ host: "127.0.0.1", port: 1, path: "/", key })); +`, + ); + expect(r.stderr).toBe(""); + expect(r.stdout).toBe( + "connect cert only tls.connect option 'cert' has no static lowering — a client certificate lowers with both cert and key\n" + + "connect key only tls.connect option 'key' has no static lowering — a client certificate lowers with both cert and key\n" + + "request key only https.request option 'key' has no static lowering — a client certificate lowers with both cert and key\n", + ); + }); +}); + +// server.addContext and setSecureContext answer on tls and https servers; +// a plain net server, a servername Node's RegExp would read as groups or +// alternation, and one outside ASCII throw the fence. A handshake failure +// whose OpenSSL reason the runtime does not know reaches 'tlsClientError' +// as a coded SC2020 error. +describe("tls.Server contexts and client errors without a lowering", () => { + test("addContext and setSecureContext fences, and an unknown handshake failure", async () => { + const r = await compileAndRun( + "tls-server-context-fences", + `import { readFileSync } from "node:fs"; +import * as net from "node:net"; +import type { AddressInfo } from "node:net"; +import * as tls from "node:tls"; +const certs = "tests/fixtures/server/certs"; +const cert = readFileSync(\`\${certs}/localhost.pem\`); +const key = readFileSync(\`\${certs}/localhost-key.pem\`); +function report(label: string, run: () => void): void { + try { + run(); + console.log(label, "no error"); + } catch (error) { + console.log(label, (error as Error).message); + } +} +const plain = net.createServer() as unknown as tls.Server; +report("net addContext", () => plain.addContext("a.test", { cert, key })); +report("net setSecureContext", () => plain.setSecureContext({ cert, key })); +const server = tls.createServer({ cert, key }); +report("alternation", () => server.addContext("a.test|b.test", { cert, key })); +report("group", () => server.addContext("(a).test", { cert, key })); +report("non-ASCII", () => server.addContext("\u00e9.test", { cert, key })); +server.on("tlsClientError", (err: Error) => console.log("tlsClientError", (err as NodeJS.ErrnoException).code, err.message)); +server.listen(0, "127.0.0.1", () => { + const raw = net.connect((server.address() as AddressInfo).port, "127.0.0.1", () => { + raw.write(Buffer.from([0x16, 0x03, 0x01, 0x00, 0x04, 0x01, 0x00, 0x00, 0x00])); + }); + raw.on("data", () => {}); + raw.on("close", () => server.close()); +}); +`, + ); + expect(r.stderr).toBe(""); + expect(r.stdout).toBe( + "net addContext server.addContext on a server that is not a tls or https server is not supported yet\n" + + "net setSecureContext server.setSecureContext on a server that is not a tls or https server is not supported yet\n" + + "alternation server.addContext option 'servername' has no static lowering — a servername with regular-expression groups or alternation has no lowering\n" + + "group server.addContext option 'servername' has no static lowering — a servername with regular-expression groups or alternation has no lowering\n" + + "non-ASCII server.addContext option 'servername' has no static lowering — a servername outside ASCII has no lowering\n" + + "tlsClientError SC2020 a TLS handshake failure (mbedTLS error -0x7300) without the reason OpenSSL gives is not supported yet\n", + ); + }); +}); + // A curve Node lists in crypto.getCurves() but the runtime does not // implement throws a coded SC2020 error naming the curve when the name is // computed; literal names are refused at compile time (node-types-fenced). @@ -1989,6 +2076,70 @@ await attempt("subtle verify", () => crypto.subtle.verify(name, raw, new Uint8Ar }); }); +// An X509Certificate's Ed25519 key needs the same unit: without it the +// certificate's public key, issuer and names still read, while verify +// rejects with the coded SC2020 Error. 7091 pins the linked path. +describe("X509Certificate Ed25519 keys without the Ed25519 unit", () => { + test("verify refuses with SC2020 in a program that never names Ed25519", async () => { + const r = await compileAndRun( + "x509-ed25519-unit-not-linked", + `import { X509Certificate } from "node:crypto"; +const cert = new X509Certificate("-----BEGIN CERTIFICATE-----\\nMIIBljCCAUigAwIBAgIUNFuRt3zKS19UAUMdLWewqHrGBigwBQYDK2VwMC8xFDAS\\nBgNVBAoMC0V4YW1wbGUgT3JnMRcwFQYDVQQDDA5lZC5leGFtcGxlLm5ldDAgFw0y\\nNjEwMjIxMDEwMTJaGA8yMTI2MDkyODEwMTAxMlowLzEUMBIGA1UECgwLRXhhbXBs\\nZSBPcmcxFzAVBgNVBAMMDmVkLmV4YW1wbGUubmV0MCowBQYDK2VwAyEAOCSLKkel\\nkOH/5aqUwI3PNJVUUNyhgu2s19LFC254fNCjdDByMB0GA1UdDgQWBBR+50zUcqL8\\n739jh6/rEYojULDmlTAfBgNVHSMEGDAWgBR+50zUcqL8739jh6/rEYojULDmlTAP\\nBgNVHRMBAf8EBTADAQH/MB8GA1UdEQQYMBaCDmVkLmV4YW1wbGUubmV0hwTAAAIH\\nMAUGAytlcANBAC/c0Bi0SVUnHCg/1pn7MaCgVivSHuoISi2SCq/0EnLefRdgsIir\\n0QxjVnxeuKN2Y1yfEO/R1W8Nwovo1l2M1gQ=\\n-----END CERTIFICATE-----\\n"); +console.log(cert.publicKey.asymmetricKeyType?.length, cert.checkIssued(cert), cert.checkHost("ed.example.net")); +try { + console.log(cert.verify(cert.publicKey)); +} catch (e) { + const err = e as NodeJS.ErrnoException; + console.log(err.name, err.code, err.message); +} +`, + ); + expect(r.exitCode).toBe(0); + expect(r.stderr).toBe(""); + expect(r.stdout).toBe( + "7 true ed.example.net\n" + + "Error SC2020 Ed25519 keys are supported when a string literal in the program names 'ed25519'\n", + ); + }); +}); + +// A TLS socket held in an untyped JavaScript value has no lowering for its +// certificate accessors (they link the X.509 unit, which a dynamic call +// cannot ask for), so the call throws the fence; a socket whose type is +// known runs them (corpus 7095, 7096). +describe("tlsSocket.getPeerCertificate on a dynamic value (JS lane)", () => { + test("throws the fence", async () => { + const r = await compileAndRun( + "tls-peer-certificate-dynamic", + `import * as tls from "node:tls"; +import { readFileSync } from "node:fs"; +const certs = "tests/fixtures/server/certs"; +const server = tls.createServer({ cert: readFileSync(\`\${certs}/localhost.pem\`), key: readFileSync(\`\${certs}/localhost-key.pem\`) }, (s) => s.end()); +function peer(socket) { + try { + return socket.getPeerCertificate().subject.CN; + } catch (e) { + return e.message; + } +} +server.listen(0, () => { + const c = tls.connect({ port: server.address().port, ca: readFileSync(\`\${certs}/ca.pem\`), servername: "localhost" }, () => { + console.log(peer(c)); + c.destroy(); + server.close(); + }); +}); +`, + "mjs", + ); + expect(r.exitCode).toBe(0); + expect(r.stderr).toBe(""); + expect(r.stdout).toBe( + "'TLSSocket.prototype.getPeerCertificate' on a dynamic value is not supported yet\n", + ); + }); +}); + describe("inspecting error subclasses with properties created at run time (JS lane)", () => { test("an instance whose constructor created a property is a named fence", async () => { // Node prints `[Conditional [Error]: m] { extra: 'x' }`. The property diff --git a/tests/harness/library-asyncfree.test.ts b/tests/harness/library-asyncfree.test.ts index d924f26d1..9b569c584 100644 --- a/tests/harness/library-asyncfree.test.ts +++ b/tests/harness/library-asyncfree.test.ts @@ -106,6 +106,15 @@ describe("async_free detection over the IR", () => { ).toContain("asymmetric KeyObjects"); }); + test("X509Certificate's key members refuse", async () => { + expect( + await surfaceOf( + "x509-key", + `import { X509Certificate } from "node:crypto";\nimport { readFileSync } from "node:fs";\nconst cert = new X509Certificate(readFileSync("cert.pem"));\nconsole.log(cert.verify(cert.publicKey));\n`, + ), + ).toContain("X509Certificate publicKey, verify and checkPrivateKey"); + }); + test("process signal listeners refuse", async () => { expect( await surfaceOf( diff --git a/tests/harness/library-mode.test.ts b/tests/harness/library-mode.test.ts index db4fabb3e..47b77f0fd 100644 --- a/tests/harness/library-mode.test.ts +++ b/tests/harness/library-mode.test.ts @@ -299,6 +299,21 @@ wrap empty: len 2 bytes 60 62 expect(run.stdout).toBe(BUFFERS_EXPECTED); }); + /* ── X509Certificate fields: scr_x509.c rides the archive ────────────── */ + + test("X509Certificate fields in a library", async () => { + const { archive, outDir } = await buildLibrary("x509", emission); + const probe = buildProbe("x509", archive, outDir); + const run = runProbe(probe); + expect(run.signal).toBeNull(); + expect(run.status).toBe(0); + expect(run.stdout).toBe( + "C=US\nST=California\nL=San Francisco\nO=Example Org\nOU=Dev Team\nCN=Example Root CA\nemailAddress=ca@example.com" + + "|0123456789ABCDEF|Sep 27 16:33:52 2126 GMT|true|" + + "7C:5F:CA:18:57:BF:BD:FC:67:AC:BD:21:1C:67:E8:C3:73:48:35:4E:4D:95:A8:2B:83:FF:E0:5A:E7:0A:97:A9\n", + ); + }); + /* ── cstring: NUL-terminated text in, out, and through callbacks ─────── */ test("cstring parameters, results, and callback arguments", async () => { diff --git a/tests/harness/project-config.test.ts b/tests/harness/project-config.test.ts index fd2077a48..ea5ddd51f 100644 --- a/tests/harness/project-config.test.ts +++ b/tests/harness/project-config.test.ts @@ -100,6 +100,13 @@ for (const [name, title] of [ "eventLoopUtilization and monitorEventLoopDelay follow @types/node's types", ], ["timeout-type", "NodeJS.Timeout fields, ref/unref/hasRef and clearInterval under @types/node"], + ["x509-methods", "X509Certificate's methods and the legacy object under @types/node"], + ["tls-peer-certificates", "TLS socket certificate accessors under @types/node"], + ["tls-client-certificates", "mutual TLS with client certificates under @types/node"], + [ + "tls-server-contexts", + "tls.Server addContext, setSecureContext and tlsClientError under @types/node", + ], ] as const) { test(`node-types: ${title}`, async () => { const outDir = outDirFor(name); diff --git a/tests/harness/self-hosting-native-toolchain.test.ts b/tests/harness/self-hosting-native-toolchain.test.ts index c5476328e..90773c87f 100644 --- a/tests/harness/self-hosting-native-toolchain.test.ts +++ b/tests/harness/self-hosting-native-toolchain.test.ts @@ -52,6 +52,7 @@ const features: NativeLinkFeatures = { dh: false, pki: false, ed25519: false, + x509: false, webcrypto: false, perfLoop: false, }; diff --git a/tests/harness/self-hosting-runtime-pack.test.ts b/tests/harness/self-hosting-runtime-pack.test.ts index 64ddd0213..859f820da 100644 --- a/tests/harness/self-hosting-runtime-pack.test.ts +++ b/tests/harness/self-hosting-runtime-pack.test.ts @@ -53,6 +53,7 @@ const base: NativeLinkFeatures = { dh: false, pki: false, ed25519: false, + x509: false, webcrypto: false, perfLoop: false, }; diff --git a/tests/harness/tls-socket-leaks.test.ts b/tests/harness/tls-socket-leaks.test.ts index 64edfac25..d657b0950 100644 --- a/tests/harness/tls-socket-leaks.test.ts +++ b/tests/harness/tls-socket-leaks.test.ts @@ -3,7 +3,9 @@ * every socket that closes, including one whose handshake fails, must drop * them. The sanitized lanes otherwise run with detect_leaks=0, so this runs * the TLSSocket programs with LeakSanitizer explicitly on. 7094's - * handshakes all fail. Linux only (Apple's ASan has no LeakSanitizer); + * handshakes all fail; 7095's detailed certificates link roots to + * themselves; 7097 and 7098 hold client certificates and the chains a ca + * completes. Linux only (Apple's ASan has no LeakSanitizer); * runs in the SCRIPTC_SAN=1 lane. */ import { execFile } from "node:child_process"; import { createHash } from "node:crypto"; @@ -22,6 +24,12 @@ const programs = [ "tests/corpus/7087-tls-socket-wrap.ts", "tests/corpus/7088-tls-socket-connect-tunnel.ts", "tests/corpus/7094-tls-socket-failed-handshakes.ts", + "tests/corpus/7095-tls-peer-certificates.ts", + "tests/corpus/7097-tls-client-certificates.ts", + "tests/corpus/7098-tls-client-certificates-paths.ts", + "tests/corpus/7440-tls-server-add-context.ts", + "tests/corpus/7441-tls-client-error.ts", + "tests/corpus/7443-tls-final-flight.ts", ]; describe.skipIf(!sanitize || process.platform !== "linux")( diff --git a/tests/harness/tls-trust-store.test.ts b/tests/harness/tls-trust-store.test.ts new file mode 100644 index 000000000..714de9057 --- /dev/null +++ b/tests/harness/tls-trust-store.test.ts @@ -0,0 +1,42 @@ +// TLS trust stores that depend on the process's NODE_EXTRA_CA_CERTS: a +// server's ca option, where an empty Buffer is an empty store and an empty +// string is the default one. The corpus cannot set the environment, so the +// fixture runs here under Node and as a binary with the test CA added. +import { execFile } from "node:child_process"; +import { mkdirSync } from "node:fs"; +import { join } from "node:path"; +import { promisify } from "node:util"; +import { expect, test } from "vitest"; +import { compile } from "@scriptc/compiler"; + +const execFileAsync = promisify(execFile); +const repoRoot = join(import.meta.dirname, "../.."); +const cacheDir = join(repoRoot, "node_modules/.cache/scriptc-tests"); +const sanitize = process.env["SCRIPTC_SAN"] === "1"; + +test("a server's empty ca Buffer is an empty trust store, as in Node", async () => { + const entry = join(repoRoot, "tests/fixtures/tls/empty-ca.ts"); + const outDir = join(cacheDir, `tls-trust-store-${sanitize ? "san" : "plain"}`); + mkdirSync(outDir, { recursive: true }); + const result = await compile(entry, { + outPath: join(outDir, "empty-ca"), + outDir, + sanitize, + backend: "llvm", + }); + expect(result.ok, !result.ok ? JSON.stringify(result.diagnostics, null, 2) : "").toBe(true); + if (!result.ok) return; + const env = { + ...process.env, + NODE_EXTRA_CA_CERTS: join(repoRoot, "tests/fixtures/server/certs/ca.pem"), + }; + const [native, node] = await Promise.all([ + execFileAsync(result.binaryPath, [], { cwd: repoRoot, env }), + execFileAsync(process.execPath, ["--experimental-strip-types", "--no-warnings", entry], { + cwd: repoRoot, + env, + }), + ]); + expect(native.stdout).toBe(node.stdout); + expect(node.stdout).toContain("empty Buffer false SELF_SIGNED_CERT_IN_CHAIN"); +}, 120_000); diff --git a/tests/library-mode/x509/lib.ts b/tests/library-mode/x509/lib.ts new file mode 100644 index 000000000..9b023a727 --- /dev/null +++ b/tests/library-mode/x509/lib.ts @@ -0,0 +1,41 @@ +// X509Certificate fields in a library archive: the field code lives in +// scr_x509.c, which the archive carries when the program reads a field. +import * as crypto from "node:crypto"; + +const CA = `-----BEGIN CERTIFICATE----- +MIIEITCCAwmgAwIBAgIIASNFZ4mrze8wDQYJKoZIhvcNAQELBQAwgZwxCzAJBgNV +BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNp +c2NvMRQwEgYDVQQKDAtFeGFtcGxlIE9yZzERMA8GA1UECwwIRGV2IFRlYW0xGDAW +BgNVBAMMD0V4YW1wbGUgUm9vdCBDQTEdMBsGCSqGSIb3DQEJARYOY2FAZXhhbXBs +ZS5jb20wIBcNMjYxMDIxMTYzMzUyWhgPMjEyNjA5MjcxNjMzNTJaMIGcMQswCQYD +VQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5j +aXNjbzEUMBIGA1UECgwLRXhhbXBsZSBPcmcxETAPBgNVBAsMCERldiBUZWFtMRgw +FgYDVQQDDA9FeGFtcGxlIFJvb3QgQ0ExHTAbBgkqhkiG9w0BCQEWDmNhQGV4YW1w +bGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0YGcCr0pxR8d +6qDdLuILcoT7vhtAjyHwfkoChnH6N3TLWzDUugnBp9NbDb7gDLqbRT4uTDoNb6zS +tEJZ4Q7/hhd0jDvoPmOy0Y3Kyj9uNsdf25GdbvwwEnlddELJCZprTZ4OhEg6w2s0 +Yy4SlviLzDXLmsggTypxeS+K8JHT9onMipi5L4GFu8n1QZbzXvSS4BkRgMXEyrtr +FOE9qSo2qkubFyd/WNKRTRIpTSc5/GGsqJ0FKDDJnN5adotcUucbJFn4noNnFUWh +M8mhBEj7ENDdJsD2EVFsI6H958jA2SbNNu4ngzAOs2AKNBYBfQK02ZQAdRNOSL3K +5FkfbII5LwIDAQABo2MwYTAdBgNVHQ4EFgQUP+yQyItpNYEls26Jfv+NnciGaK8w +HwYDVR0jBBgwFoAUP+yQyItpNYEls26Jfv+NnciGaK8wDwYDVR0TAQH/BAUwAwEB +/zAOBgNVHQ8BAf8EBAMCAQYwDQYJKoZIhvcNAQELBQADggEBABDw3Va/C+RFc/Hs +TJnHtQJtxFL0ZhnHUqg4DcDA3m+JDdIDNL8sNpLEbtn/pr0VeEWgG+MImWAQlrUW +IAZkLj9/Zg1wSO0oZ86ZyZJZmp54lUYXgG17CNl4g+F7VHt3bBwUJHTbWye/FKM6 +5OVZetCYKVj7Z+5BYuf7cumzvRqcn32fXidB/kjRX14SJ4JDPn2yFZWCr2ygIqWQ +SOuEmWbNAbYGaVZkQr2Ma8U28DWY2jb0f6nP8jLt49t9o6N/e6Fwd6I5t/mx9Mfj +0403omkxmr9vqN2kBamzVnun+2mDkRZcKPCr72Q4sfbvmDi/W5Nf1Iu2cQW8VfDO +SqpyT54= +-----END CERTIFICATE----- +`; + +export function describe(): string { + const cert = new crypto.X509Certificate(CA); + return [ + cert.subject, + cert.serialNumber, + cert.validTo, + String(cert.ca), + cert.fingerprint256, + ].join("|"); +} diff --git a/tests/library-mode/x509/probe.c b/tests/library-mode/x509/probe.c new file mode 100644 index 000000000..d8065d039 --- /dev/null +++ b/tests/library-mode/x509/probe.c @@ -0,0 +1,23 @@ +/* X509Certificate fields read through a library export. */ +#include +#include + +extern void kx_init(void); +extern void kx_set_panic_sink(void (*fn)(void *, const uint8_t *, size_t, uint64_t), void *ctx); +extern void kx_collect(void); +extern void kx_describe(const uint8_t **out, size_t *out_len); + +static void sink(void *ctx, const uint8_t *msg, size_t len, uint64_t addr) { + (void)ctx; (void)addr; + printf("SINK %.*s\n", (int)len, msg); +} + +int main(void) { + kx_set_panic_sink(sink, NULL); + kx_init(); + const uint8_t *s; size_t n; + kx_describe(&s, &n); + printf("%.*s\n", (int)n, s); + kx_collect(); + return 0; +} diff --git a/tests/library-mode/x509/profile.json b/tests/library-mode/x509/profile.json new file mode 100644 index 000000000..fe9b4fb59 --- /dev/null +++ b/tests/library-mode/x509/profile.json @@ -0,0 +1,14 @@ +{ + "profile_format": 1, + "name": "conformance-x509", + "entry": "lib.ts", + "emission": "llvm", + "abi": { + "prefix": "kx_", + "init_symbol": "kx_init", + "sink_register_symbol": "kx_set_panic_sink", + "collect_symbol": "kx_collect", + "result_reset_symbol": null + }, + "exports": [{ "export": "describe", "symbol": "kx_describe", "params": [], "returns": "string" }] +} From a9da37b82ef7148f39c5ee67d05fed33b0ad3b38 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 18:11:49 -0500 Subject: [PATCH 031/259] zlib: Brotli compression and decompression over the vendored brotli 1.2.0 --- .../limitations/builtin-apis/compression.mdx | 3 +- .../src/generated/node-v24-compatibility.json | 112 +- .../generated/node-v24-internal.json | 110 +- internal/compatibility/src/generate.mjs | 9 +- internal/compatibility/static-support.json | 9 + .../ambient/scriptc-node-fallback.d.ts | 66 +- .../src/backend/executable-features.ts | 1 + .../compiler/src/backend/llvm/lib-shared.ts | 1 + .../src/backend/native-link-info-core.ts | 2 + .../compiler/src/backend/native/contracts.ts | 3 + .../compiler/src/backend/native/executable.ts | 38 + .../src/backend/native/runtime-inputs.ts | 4 +- .../compiler/src/backend/native/vendor.ts | 3 + .../compiler/src/backend/runtime-pack-core.ts | 4 +- .../compiler/src/backend/vendor-archives.ts | 91 + .../compiler/src/backend/vendor-inputs.ts | 4 +- .../src/executable/executable-cache.ts | 1 + .../frontend/lowering/builtins/compression.ts | 104 +- .../src/frontend/lowering/surfaces.ts | 29 +- packages/compiler/src/index.ts | 1 + .../compiler/src/ir/builtin-signatures.ts | 2 + packages/compiler/src/ir/ir.ts | 2 + packages/compiler/src/ir/runtime-features.ts | 4 + packages/compiler/src/library/ir-policy.ts | 1 + .../compiler/src/native/sanitizer.test.ts | 1 + packages/compiler/src/native/sanitizer.ts | 19 +- packages/compiler/surface-manifest.json | 40 +- .../test/native-codegen-lowering.test.ts | 10 +- .../corpus/7714-zlib-brotli-compress.cjs.json | 6 + .../7715-zlib-brotli-decompress.cjs.json | 6 + .../tests/corpus/7716-zlib-brotli.ts.json | 6 + .../runtime-pack-matrix.mjs | 2 + .../runtime-darwin-arm64/scripts/build.mjs | 30 +- .../runtime-pack-matrix.mjs | 2 + .../runtime-pack-common/scripts/build.mjs | 32 +- packages/runtime/src/scr_brotli.c | 317 + packages/runtime/src/scr_zlib.c | 62 +- packages/runtime/src/scr_zlib.h | 35 +- packages/runtime/src/scr_zlib_stream.c | 5 +- packages/runtime/vendor/README.md | 10 + packages/runtime/vendor/brotli/LICENSE | 19 + .../vendor/brotli/c/common/constants.c | 15 + .../vendor/brotli/c/common/constants.h | 198 + .../runtime/vendor/brotli/c/common/context.c | 156 + .../runtime/vendor/brotli/c/common/context.h | 112 + .../vendor/brotli/c/common/dictionary.c | 64 + .../vendor/brotli/c/common/dictionary.h | 63 + .../vendor/brotli/c/common/dictionary_inc.h | 5847 +++++++++++++++++ .../runtime/vendor/brotli/c/common/platform.c | 19 + .../runtime/vendor/brotli/c/common/platform.h | 680 ++ .../brotli/c/common/shared_dictionary.c | 517 ++ .../c/common/shared_dictionary_internal.h | 75 + .../vendor/brotli/c/common/static_init.h | 56 + .../vendor/brotli/c/common/transform.c | 293 + .../vendor/brotli/c/common/transform.h | 84 + .../runtime/vendor/brotli/c/common/version.h | 51 + .../runtime/vendor/brotli/c/dec/bit_reader.c | 77 + .../runtime/vendor/brotli/c/dec/bit_reader.h | 419 ++ packages/runtime/vendor/brotli/c/dec/decode.c | 2964 +++++++++ .../runtime/vendor/brotli/c/dec/huffman.c | 339 + .../runtime/vendor/brotli/c/dec/huffman.h | 120 + packages/runtime/vendor/brotli/c/dec/prefix.c | 67 + packages/runtime/vendor/brotli/c/dec/prefix.h | 43 + .../runtime/vendor/brotli/c/dec/prefix_inc.h | 707 ++ packages/runtime/vendor/brotli/c/dec/state.c | 186 + packages/runtime/vendor/brotli/c/dec/state.h | 396 ++ .../runtime/vendor/brotli/c/dec/static_init.c | 53 + .../runtime/vendor/brotli/c/dec/static_init.h | 30 + .../vendor/brotli/c/enc/backward_references.c | 231 + .../vendor/brotli/c/enc/backward_references.h | 36 + .../brotli/c/enc/backward_references_hq.c | 939 +++ .../brotli/c/enc/backward_references_hq.h | 92 + .../brotli/c/enc/backward_references_inc.h | 189 + .../runtime/vendor/brotli/c/enc/bit_cost.c | 60 + .../runtime/vendor/brotli/c/enc/bit_cost.h | 32 + .../vendor/brotli/c/enc/bit_cost_inc.h | 127 + .../vendor/brotli/c/enc/block_encoder_inc.h | 34 + .../vendor/brotli/c/enc/block_splitter.c | 214 + .../vendor/brotli/c/enc/block_splitter.h | 49 + .../vendor/brotli/c/enc/block_splitter_inc.h | 487 ++ .../vendor/brotli/c/enc/brotli_bit_stream.c | 1337 ++++ .../vendor/brotli/c/enc/brotli_bit_stream.h | 83 + .../runtime/vendor/brotli/c/enc/cluster.c | 55 + .../runtime/vendor/brotli/c/enc/cluster.h | 47 + .../runtime/vendor/brotli/c/enc/cluster_inc.h | 325 + .../runtime/vendor/brotli/c/enc/command.c | 28 + .../runtime/vendor/brotli/c/enc/command.h | 189 + .../vendor/brotli/c/enc/compound_dictionary.c | 205 + .../vendor/brotli/c/enc/compound_dictionary.h | 71 + .../vendor/brotli/c/enc/compress_fragment.c | 790 +++ .../vendor/brotli/c/enc/compress_fragment.h | 84 + .../brotli/c/enc/compress_fragment_two_pass.c | 647 ++ .../brotli/c/enc/compress_fragment_two_pass.h | 70 + .../vendor/brotli/c/enc/dictionary_hash.c | 145 + .../vendor/brotli/c/enc/dictionary_hash.h | 45 + .../vendor/brotli/c/enc/dictionary_hash_inc.h | 1829 ++++++ packages/runtime/vendor/brotli/c/enc/encode.c | 2021 ++++++ .../vendor/brotli/c/enc/encoder_dict.c | 642 ++ .../vendor/brotli/c/enc/encoder_dict.h | 155 + .../vendor/brotli/c/enc/entropy_encode.c | 501 ++ .../vendor/brotli/c/enc/entropy_encode.h | 121 + .../brotli/c/enc/entropy_encode_static.h | 548 ++ .../runtime/vendor/brotli/c/enc/fast_log.c | 105 + .../runtime/vendor/brotli/c/enc/fast_log.h | 66 + .../vendor/brotli/c/enc/find_match_length.h | 70 + packages/runtime/vendor/brotli/c/enc/hash.h | 735 +++ .../runtime/vendor/brotli/c/enc/hash_base.h | 38 + .../vendor/brotli/c/enc/hash_composite_inc.h | 140 + .../brotli/c/enc/hash_forgetful_chain_inc.h | 305 + .../brotli/c/enc/hash_longest_match64_inc.h | 279 + .../c/enc/hash_longest_match64_simd_inc.h | 304 + .../brotli/c/enc/hash_longest_match_inc.h | 277 + .../c/enc/hash_longest_match_quickly_inc.h | 270 + .../c/enc/hash_longest_match_simd_inc.h | 278 + .../vendor/brotli/c/enc/hash_rolling_inc.h | 212 + .../brotli/c/enc/hash_to_binary_tree_inc.h | 330 + .../runtime/vendor/brotli/c/enc/histogram.c | 101 + .../runtime/vendor/brotli/c/enc/histogram.h | 60 + .../vendor/brotli/c/enc/histogram_inc.h | 51 + .../vendor/brotli/c/enc/literal_cost.c | 178 + .../vendor/brotli/c/enc/literal_cost.h | 30 + .../vendor/brotli/c/enc/matching_tag_mask.h | 69 + packages/runtime/vendor/brotli/c/enc/memory.c | 189 + packages/runtime/vendor/brotli/c/enc/memory.h | 127 + .../runtime/vendor/brotli/c/enc/metablock.c | 675 ++ .../runtime/vendor/brotli/c/enc/metablock.h | 106 + .../vendor/brotli/c/enc/metablock_inc.h | 185 + packages/runtime/vendor/brotli/c/enc/params.h | 46 + packages/runtime/vendor/brotli/c/enc/prefix.h | 52 + .../runtime/vendor/brotli/c/enc/quality.h | 209 + .../runtime/vendor/brotli/c/enc/ringbuffer.h | 165 + packages/runtime/vendor/brotli/c/enc/state.h | 104 + .../runtime/vendor/brotli/c/enc/static_dict.c | 536 ++ .../runtime/vendor/brotli/c/enc/static_dict.h | 39 + .../vendor/brotli/c/enc/static_dict_lut.c | 224 + .../vendor/brotli/c/enc/static_dict_lut.h | 49 + .../vendor/brotli/c/enc/static_dict_lut_inc.h | 5830 ++++++++++++++++ .../runtime/vendor/brotli/c/enc/static_init.c | 59 + .../runtime/vendor/brotli/c/enc/static_init.h | 30 + .../runtime/vendor/brotli/c/enc/utf8_util.c | 85 + .../runtime/vendor/brotli/c/enc/utf8_util.h | 31 + .../runtime/vendor/brotli/c/enc/write_bits.h | 86 + .../vendor/brotli/c/include/brotli/decode.h | 409 ++ .../vendor/brotli/c/include/brotli/encode.h | 505 ++ .../vendor/brotli/c/include/brotli/port.h | 302 + .../c/include/brotli/shared_dictionary.h | 100 + .../vendor/brotli/c/include/brotli/types.h | 83 + tests/corpus/7714-zlib-brotli-compress.cjs | 91 + tests/corpus/7715-zlib-brotli-decompress.cjs | 96 + tests/corpus/7716-zlib-brotli.ts | 47 + tests/diagnostics/node-fallback-fence.ts | 6 +- tests/fixtures/node-types/fenced.ts | 5 +- .../__snapshots__/node-fallback-fence.ts.txt | 11 +- .../__snapshots__/node-types-fenced.txt | 153 +- .../7714-zlib-brotli-compress.cjs.json | 1 + .../7715-zlib-brotli-decompress.cjs.json | 1 + .../corpus-costs/7716-zlib-brotli.ts.json | 1 + tests/harness/library-mode.test.ts | 16 +- 158 files changed, 41519 insertions(+), 298 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7714-zlib-brotli-compress.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7715-zlib-brotli-decompress.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7716-zlib-brotli.ts.json create mode 100644 packages/runtime/src/scr_brotli.c create mode 100644 packages/runtime/vendor/brotli/LICENSE create mode 100644 packages/runtime/vendor/brotli/c/common/constants.c create mode 100644 packages/runtime/vendor/brotli/c/common/constants.h create mode 100644 packages/runtime/vendor/brotli/c/common/context.c create mode 100644 packages/runtime/vendor/brotli/c/common/context.h create mode 100644 packages/runtime/vendor/brotli/c/common/dictionary.c create mode 100644 packages/runtime/vendor/brotli/c/common/dictionary.h create mode 100644 packages/runtime/vendor/brotli/c/common/dictionary_inc.h create mode 100644 packages/runtime/vendor/brotli/c/common/platform.c create mode 100644 packages/runtime/vendor/brotli/c/common/platform.h create mode 100644 packages/runtime/vendor/brotli/c/common/shared_dictionary.c create mode 100644 packages/runtime/vendor/brotli/c/common/shared_dictionary_internal.h create mode 100644 packages/runtime/vendor/brotli/c/common/static_init.h create mode 100644 packages/runtime/vendor/brotli/c/common/transform.c create mode 100644 packages/runtime/vendor/brotli/c/common/transform.h create mode 100644 packages/runtime/vendor/brotli/c/common/version.h create mode 100644 packages/runtime/vendor/brotli/c/dec/bit_reader.c create mode 100644 packages/runtime/vendor/brotli/c/dec/bit_reader.h create mode 100644 packages/runtime/vendor/brotli/c/dec/decode.c create mode 100644 packages/runtime/vendor/brotli/c/dec/huffman.c create mode 100644 packages/runtime/vendor/brotli/c/dec/huffman.h create mode 100644 packages/runtime/vendor/brotli/c/dec/prefix.c create mode 100644 packages/runtime/vendor/brotli/c/dec/prefix.h create mode 100644 packages/runtime/vendor/brotli/c/dec/prefix_inc.h create mode 100644 packages/runtime/vendor/brotli/c/dec/state.c create mode 100644 packages/runtime/vendor/brotli/c/dec/state.h create mode 100644 packages/runtime/vendor/brotli/c/dec/static_init.c create mode 100644 packages/runtime/vendor/brotli/c/dec/static_init.h create mode 100644 packages/runtime/vendor/brotli/c/enc/backward_references.c create mode 100644 packages/runtime/vendor/brotli/c/enc/backward_references.h create mode 100644 packages/runtime/vendor/brotli/c/enc/backward_references_hq.c create mode 100644 packages/runtime/vendor/brotli/c/enc/backward_references_hq.h create mode 100644 packages/runtime/vendor/brotli/c/enc/backward_references_inc.h create mode 100644 packages/runtime/vendor/brotli/c/enc/bit_cost.c create mode 100644 packages/runtime/vendor/brotli/c/enc/bit_cost.h create mode 100644 packages/runtime/vendor/brotli/c/enc/bit_cost_inc.h create mode 100644 packages/runtime/vendor/brotli/c/enc/block_encoder_inc.h create mode 100644 packages/runtime/vendor/brotli/c/enc/block_splitter.c create mode 100644 packages/runtime/vendor/brotli/c/enc/block_splitter.h create mode 100644 packages/runtime/vendor/brotli/c/enc/block_splitter_inc.h create mode 100644 packages/runtime/vendor/brotli/c/enc/brotli_bit_stream.c create mode 100644 packages/runtime/vendor/brotli/c/enc/brotli_bit_stream.h create mode 100644 packages/runtime/vendor/brotli/c/enc/cluster.c create mode 100644 packages/runtime/vendor/brotli/c/enc/cluster.h create mode 100644 packages/runtime/vendor/brotli/c/enc/cluster_inc.h create mode 100644 packages/runtime/vendor/brotli/c/enc/command.c create mode 100644 packages/runtime/vendor/brotli/c/enc/command.h create mode 100644 packages/runtime/vendor/brotli/c/enc/compound_dictionary.c create mode 100644 packages/runtime/vendor/brotli/c/enc/compound_dictionary.h create mode 100644 packages/runtime/vendor/brotli/c/enc/compress_fragment.c create mode 100644 packages/runtime/vendor/brotli/c/enc/compress_fragment.h create mode 100644 packages/runtime/vendor/brotli/c/enc/compress_fragment_two_pass.c create mode 100644 packages/runtime/vendor/brotli/c/enc/compress_fragment_two_pass.h create mode 100644 packages/runtime/vendor/brotli/c/enc/dictionary_hash.c create mode 100644 packages/runtime/vendor/brotli/c/enc/dictionary_hash.h create mode 100644 packages/runtime/vendor/brotli/c/enc/dictionary_hash_inc.h create mode 100644 packages/runtime/vendor/brotli/c/enc/encode.c create mode 100644 packages/runtime/vendor/brotli/c/enc/encoder_dict.c create mode 100644 packages/runtime/vendor/brotli/c/enc/encoder_dict.h create mode 100644 packages/runtime/vendor/brotli/c/enc/entropy_encode.c create mode 100644 packages/runtime/vendor/brotli/c/enc/entropy_encode.h create mode 100644 packages/runtime/vendor/brotli/c/enc/entropy_encode_static.h create mode 100644 packages/runtime/vendor/brotli/c/enc/fast_log.c create mode 100644 packages/runtime/vendor/brotli/c/enc/fast_log.h create mode 100644 packages/runtime/vendor/brotli/c/enc/find_match_length.h create mode 100644 packages/runtime/vendor/brotli/c/enc/hash.h create mode 100644 packages/runtime/vendor/brotli/c/enc/hash_base.h create mode 100644 packages/runtime/vendor/brotli/c/enc/hash_composite_inc.h create mode 100644 packages/runtime/vendor/brotli/c/enc/hash_forgetful_chain_inc.h create mode 100644 packages/runtime/vendor/brotli/c/enc/hash_longest_match64_inc.h create mode 100644 packages/runtime/vendor/brotli/c/enc/hash_longest_match64_simd_inc.h create mode 100644 packages/runtime/vendor/brotli/c/enc/hash_longest_match_inc.h create mode 100644 packages/runtime/vendor/brotli/c/enc/hash_longest_match_quickly_inc.h create mode 100644 packages/runtime/vendor/brotli/c/enc/hash_longest_match_simd_inc.h create mode 100644 packages/runtime/vendor/brotli/c/enc/hash_rolling_inc.h create mode 100644 packages/runtime/vendor/brotli/c/enc/hash_to_binary_tree_inc.h create mode 100644 packages/runtime/vendor/brotli/c/enc/histogram.c create mode 100644 packages/runtime/vendor/brotli/c/enc/histogram.h create mode 100644 packages/runtime/vendor/brotli/c/enc/histogram_inc.h create mode 100644 packages/runtime/vendor/brotli/c/enc/literal_cost.c create mode 100644 packages/runtime/vendor/brotli/c/enc/literal_cost.h create mode 100644 packages/runtime/vendor/brotli/c/enc/matching_tag_mask.h create mode 100644 packages/runtime/vendor/brotli/c/enc/memory.c create mode 100644 packages/runtime/vendor/brotli/c/enc/memory.h create mode 100644 packages/runtime/vendor/brotli/c/enc/metablock.c create mode 100644 packages/runtime/vendor/brotli/c/enc/metablock.h create mode 100644 packages/runtime/vendor/brotli/c/enc/metablock_inc.h create mode 100644 packages/runtime/vendor/brotli/c/enc/params.h create mode 100644 packages/runtime/vendor/brotli/c/enc/prefix.h create mode 100644 packages/runtime/vendor/brotli/c/enc/quality.h create mode 100644 packages/runtime/vendor/brotli/c/enc/ringbuffer.h create mode 100644 packages/runtime/vendor/brotli/c/enc/state.h create mode 100644 packages/runtime/vendor/brotli/c/enc/static_dict.c create mode 100644 packages/runtime/vendor/brotli/c/enc/static_dict.h create mode 100644 packages/runtime/vendor/brotli/c/enc/static_dict_lut.c create mode 100644 packages/runtime/vendor/brotli/c/enc/static_dict_lut.h create mode 100644 packages/runtime/vendor/brotli/c/enc/static_dict_lut_inc.h create mode 100644 packages/runtime/vendor/brotli/c/enc/static_init.c create mode 100644 packages/runtime/vendor/brotli/c/enc/static_init.h create mode 100644 packages/runtime/vendor/brotli/c/enc/utf8_util.c create mode 100644 packages/runtime/vendor/brotli/c/enc/utf8_util.h create mode 100644 packages/runtime/vendor/brotli/c/enc/write_bits.h create mode 100644 packages/runtime/vendor/brotli/c/include/brotli/decode.h create mode 100644 packages/runtime/vendor/brotli/c/include/brotli/encode.h create mode 100644 packages/runtime/vendor/brotli/c/include/brotli/port.h create mode 100644 packages/runtime/vendor/brotli/c/include/brotli/shared_dictionary.h create mode 100644 packages/runtime/vendor/brotli/c/include/brotli/types.h create mode 100644 tests/corpus/7714-zlib-brotli-compress.cjs create mode 100644 tests/corpus/7715-zlib-brotli-decompress.cjs create mode 100644 tests/corpus/7716-zlib-brotli.ts create mode 100644 tests/harness/corpus-costs/7714-zlib-brotli-compress.cjs.json create mode 100644 tests/harness/corpus-costs/7715-zlib-brotli-decompress.cjs.json create mode 100644 tests/harness/corpus-costs/7716-zlib-brotli.ts.json diff --git a/docs/content/limitations/builtin-apis/compression.mdx b/docs/content/limitations/builtin-apis/compression.mdx index 36cec0bc4..83b0fd683 100644 --- a/docs/content/limitations/builtin-apis/compression.mdx +++ b/docs/content/limitations/builtin-apis/compression.mdx @@ -4,4 +4,5 @@ The `Deflate`, `Inflate`, `Gzip`, `Gunzip`, `DeflateRaw`, `InflateRaw`, and `Unzip` streams, from `createGzip()` and the other factories or `new zlib.Gzip()`, accept Node's options and support writes, piping, `pipeline`, async iteration, `flush`, `params`, `close`, `reset`, and `bytesWritten`. Each output chunk is its own Buffer rather than a slice of a shared chunk-size buffer. `zlib.constants` members and their module-level copies read as Node's values. - `util.inspect`, `instanceof zlib.Gzip`, and Brotli and Zstd compression are unsupported. + The Brotli one-shots `brotliCompress` and `brotliDecompress` and their `Sync` forms, and the `BrotliCompress` and `BrotliDecompress` streams, accept Node's options, including `params` and `dictionary`, and produce the same bytes as Node. + `util.inspect` and Zstd compression are unsupported. diff --git a/docs/src/generated/node-v24-compatibility.json b/docs/src/generated/node-v24-compatibility.json index 1039bc3d8..a082bf1c9 100644 --- a/docs/src/generated/node-v24-compatibility.json +++ b/docs/src/generated/node-v24-compatibility.json @@ -18268,9 +18268,9 @@ "anchor": "err_brotli_invalid_param", "nodeStability": null, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the documented scriptc module-loader subset.", + "verification": "test-backed" } }, { @@ -84302,9 +84302,9 @@ "inherited": true }, "static": { - "status": "refused", - "detail": "Explicitly rejected by a named compiler diagnostic.", - "verification": "explicit-refusal" + "status": "partial", + "detail": "BrotliCompress and BrotliDecompress are Transform streams over the brotli version Node bundles, with Node's parameters, dictionaries, flush, reset, error codes, and option validation; like Node's, they have no params().", + "verification": "test-backed" } }, { @@ -84325,9 +84325,9 @@ "inherited": true }, "static": { - "status": "refused", - "detail": "Explicitly rejected by a named compiler diagnostic.", - "verification": "explicit-refusal" + "status": "partial", + "detail": "BrotliCompress and BrotliDecompress are Transform streams over the brotli version Node bundles, with Node's parameters, dictionaries, flush, reset, error codes, and option validation; like Node's, they have no params().", + "verification": "test-backed" } }, { @@ -84349,7 +84349,7 @@ }, "static": { "status": "partial", - "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Brotli and Zstd streams remain unsupported.", + "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Zstd streams remain unsupported.", "verification": "test-backed" } }, @@ -84372,7 +84372,7 @@ }, "static": { "status": "partial", - "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Brotli and Zstd streams remain unsupported.", + "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Zstd streams remain unsupported.", "verification": "test-backed" } }, @@ -84395,7 +84395,7 @@ }, "static": { "status": "partial", - "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Brotli and Zstd streams remain unsupported.", + "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Zstd streams remain unsupported.", "verification": "test-backed" } }, @@ -84418,7 +84418,7 @@ }, "static": { "status": "partial", - "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Brotli and Zstd streams remain unsupported.", + "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Zstd streams remain unsupported.", "verification": "test-backed" } }, @@ -84441,7 +84441,7 @@ }, "static": { "status": "partial", - "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Brotli and Zstd streams remain unsupported.", + "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Zstd streams remain unsupported.", "verification": "test-backed" } }, @@ -84464,7 +84464,7 @@ }, "static": { "status": "partial", - "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Brotli and Zstd streams remain unsupported.", + "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Zstd streams remain unsupported.", "verification": "test-backed" } }, @@ -84487,7 +84487,7 @@ }, "static": { "status": "partial", - "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Brotli and Zstd streams remain unsupported.", + "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Zstd streams remain unsupported.", "verification": "test-backed" } }, @@ -84510,7 +84510,7 @@ }, "static": { "status": "partial", - "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Brotli and Zstd streams remain unsupported.", + "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Zstd streams remain unsupported.", "verification": "test-backed" } }, @@ -84533,7 +84533,7 @@ }, "static": { "status": "partial", - "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Brotli and Zstd streams remain unsupported.", + "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Zstd streams remain unsupported.", "verification": "test-backed" } }, @@ -84556,7 +84556,7 @@ }, "static": { "status": "partial", - "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Brotli and Zstd streams remain unsupported.", + "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Zstd streams remain unsupported.", "verification": "test-backed" } }, @@ -84579,7 +84579,7 @@ }, "static": { "status": "partial", - "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Brotli and Zstd streams remain unsupported.", + "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Zstd streams remain unsupported.", "verification": "test-backed" } }, @@ -84602,7 +84602,7 @@ }, "static": { "status": "partial", - "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Brotli and Zstd streams remain unsupported.", + "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Zstd streams remain unsupported.", "verification": "test-backed" } }, @@ -84625,7 +84625,7 @@ }, "static": { "status": "partial", - "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Brotli and Zstd streams remain unsupported.", + "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Zstd streams remain unsupported.", "verification": "test-backed" } }, @@ -84716,9 +84716,9 @@ "inherited": true }, "static": { - "status": "refused", - "detail": "Explicitly rejected by a named compiler diagnostic.", - "verification": "explicit-refusal" + "status": "partial", + "detail": "Implemented for the call shapes accepted by the compiler lowering.", + "verification": "test-backed" } }, { @@ -84739,9 +84739,9 @@ "inherited": true }, "static": { - "status": "refused", - "detail": "Explicitly rejected by a named compiler diagnostic.", - "verification": "explicit-refusal" + "status": "partial", + "detail": "Implemented for the call shapes accepted by the compiler lowering.", + "verification": "test-backed" } }, { @@ -84969,9 +84969,9 @@ "inherited": true }, "static": { - "status": "refused", - "detail": "Explicitly rejected by a named compiler diagnostic.", - "verification": "explicit-refusal" + "status": "partial", + "detail": "Implemented for the call shapes accepted by the compiler lowering.", + "verification": "test-backed" } }, { @@ -84992,9 +84992,9 @@ "inherited": true }, "static": { - "status": "refused", - "detail": "Explicitly rejected by a named compiler diagnostic.", - "verification": "explicit-refusal" + "status": "partial", + "detail": "Implemented for the call shapes accepted by the compiler lowering.", + "verification": "test-backed" } }, { @@ -85015,9 +85015,9 @@ "inherited": true }, "static": { - "status": "refused", - "detail": "Explicitly rejected by a named compiler diagnostic.", - "verification": "explicit-refusal" + "status": "partial", + "detail": "Implemented for the call shapes accepted by the compiler lowering.", + "verification": "test-backed" } }, { @@ -85038,9 +85038,9 @@ "inherited": true }, "static": { - "status": "refused", - "detail": "Explicitly rejected by a named compiler diagnostic.", - "verification": "explicit-refusal" + "status": "partial", + "detail": "Implemented for the call shapes accepted by the compiler lowering.", + "verification": "test-backed" } }, { @@ -85499,7 +85499,7 @@ }, "static": { "status": "partial", - "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Brotli and Zstd streams remain unsupported.", + "detail": "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Zstd streams remain unsupported.", "verification": "test-backed" } }, @@ -85521,9 +85521,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "BrotliCompress and BrotliDecompress are Transform streams over the brotli version Node bundles, with Node's parameters, dictionaries, flush, reset, error codes, and option validation; like Node's, they have no params().", + "verification": "test-backed" } }, { @@ -85567,9 +85567,9 @@ "inherited": true }, "static": { - "status": "refused", - "detail": "Explicitly rejected by a named compiler diagnostic.", - "verification": "explicit-refusal" + "status": "partial", + "detail": "Implemented for the call shapes accepted by the compiler lowering.", + "verification": "test-backed" } }, { @@ -85590,9 +85590,9 @@ "inherited": true }, "static": { - "status": "refused", - "detail": "Explicitly rejected by a named compiler diagnostic.", - "verification": "explicit-refusal" + "status": "partial", + "detail": "Implemented for the call shapes accepted by the compiler lowering.", + "verification": "test-backed" } }, { @@ -85613,9 +85613,9 @@ "inherited": true }, "static": { - "status": "refused", - "detail": "Explicitly rejected by a named compiler diagnostic.", - "verification": "explicit-refusal" + "status": "partial", + "detail": "Implemented for the call shapes accepted by the compiler lowering.", + "verification": "test-backed" } }, { @@ -85636,9 +85636,9 @@ "inherited": true }, "static": { - "status": "refused", - "detail": "Explicitly rejected by a named compiler diagnostic.", - "verification": "explicit-refusal" + "status": "partial", + "detail": "Implemented for the call shapes accepted by the compiler lowering.", + "verification": "test-backed" } }, { diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index b3d91e453..3c9ece8fa 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -32679,6 +32679,7 @@ "tests": [ "tests/corpus/6702-ecdh-errors.js", "tests/corpus/6708-dh-errors.js", + "tests/corpus/7714-zlib-brotli-compress.cjs", "tests/corpus/caught-system-error-fields.ts", "tests/corpus/error-stack-frames.ts", "tests/corpus/error-stack-limit.ts", @@ -33471,8 +33472,11 @@ "anchor": "err_brotli_invalid_param", "nodeStability": null, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:errors" + "status": "partial", + "evidence": "compiler-feature:errors.ERR_BROTLI_INVALID_PARAM", + "tests": [ + "tests/corpus/7714-zlib-brotli-compress.cjs" + ] }, "anchorSource": "exact" }, @@ -115756,7 +115760,10 @@ "tests/corpus/5377-zlib-stream-backpressure.cjs", "tests/corpus/5378-zlib-sync-options.cjs", "tests/corpus/5379-zlib-callback-options.ts", - "tests/corpus/5415-zlib-dynamic-inputs.cjs" + "tests/corpus/5415-zlib-dynamic-inputs.cjs", + "tests/corpus/7714-zlib-brotli-compress.cjs", + "tests/corpus/7715-zlib-brotli-decompress.cjs", + "tests/corpus/7716-zlib-brotli.ts" ] }, "anchorSource": "chapter" @@ -116239,8 +116246,11 @@ "inherited": true }, "static": { - "status": "refused", - "evidence": "surface-manifest:unsupported:node-builtin.zlib.BrotliCompress" + "status": "partial", + "evidence": "compiler-feature:zlib.zlib.BrotliCompress", + "tests": [ + "tests/corpus/7714-zlib-brotli-compress.cjs" + ] }, "anchorSource": "exact" }, @@ -116262,8 +116272,12 @@ "inherited": true }, "static": { - "status": "refused", - "evidence": "surface-manifest:unsupported:node-builtin.zlib.BrotliDecompress" + "status": "partial", + "evidence": "compiler-feature:zlib.zlib.BrotliDecompress", + "tests": [ + "tests/corpus/7715-zlib-brotli-decompress.cjs", + "tests/corpus/7716-zlib-brotli.ts" + ] }, "anchorSource": "exact" }, @@ -116781,8 +116795,11 @@ "inherited": true }, "static": { - "status": "refused", - "evidence": "surface-manifest:unsupported:node-builtin.zlib.createBrotliCompress" + "status": "partial", + "evidence": "surface-manifest:node-builtin.zlib.createBrotliCompress", + "tests": [ + "tests/corpus/7714-zlib-brotli-compress.cjs" + ] }, "anchorSource": "exact" }, @@ -116804,8 +116821,12 @@ "inherited": true }, "static": { - "status": "refused", - "evidence": "surface-manifest:unsupported:node-builtin.zlib.createBrotliDecompress" + "status": "partial", + "evidence": "surface-manifest:node-builtin.zlib.createBrotliDecompress", + "tests": [ + "tests/corpus/7715-zlib-brotli-decompress.cjs", + "tests/corpus/7716-zlib-brotli.ts" + ] }, "anchorSource": "exact" }, @@ -117111,8 +117132,11 @@ "inherited": true }, "static": { - "status": "refused", - "evidence": "surface-manifest:unsupported:node-builtin.zlib.brotliCompress" + "status": "partial", + "evidence": "surface-manifest:node-builtin.zlib.brotliCompress", + "tests": [ + "tests/corpus/7714-zlib-brotli-compress.cjs" + ] }, "anchorSource": "exact" }, @@ -117134,8 +117158,11 @@ "inherited": true }, "static": { - "status": "refused", - "evidence": "surface-manifest:unsupported:node-builtin.zlib.brotliCompressSync" + "status": "partial", + "evidence": "surface-manifest:node-builtin.zlib.brotliCompressSync", + "tests": [ + "tests/corpus/7714-zlib-brotli-compress.cjs" + ] }, "anchorSource": "exact" }, @@ -117157,8 +117184,12 @@ "inherited": true }, "static": { - "status": "refused", - "evidence": "surface-manifest:unsupported:node-builtin.zlib.brotliDecompress" + "status": "partial", + "evidence": "surface-manifest:node-builtin.zlib.brotliDecompress", + "tests": [ + "tests/corpus/7715-zlib-brotli-decompress.cjs", + "tests/corpus/7716-zlib-brotli.ts" + ] }, "anchorSource": "exact" }, @@ -117180,8 +117211,12 @@ "inherited": true }, "static": { - "status": "refused", - "evidence": "surface-manifest:unsupported:node-builtin.zlib.brotliDecompressSync" + "status": "partial", + "evidence": "surface-manifest:node-builtin.zlib.brotliDecompressSync", + "tests": [ + "tests/corpus/7715-zlib-brotli-decompress.cjs", + "tests/corpus/7716-zlib-brotli.ts" + ] }, "anchorSource": "exact" }, @@ -118198,8 +118233,11 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:zlib" + "status": "partial", + "evidence": "compiler-feature:zlib.BrotliOptions", + "tests": [ + "tests/corpus/7714-zlib-brotli-compress.cjs" + ] }, "anchorSource": "exact" }, @@ -118267,8 +118305,11 @@ "inherited": true }, "static": { - "status": "refused", - "evidence": "surface-manifest:unsupported:node-builtin.zlib.brotliCompress" + "status": "partial", + "evidence": "surface-manifest:node-builtin.zlib.brotliCompress", + "tests": [ + "tests/corpus/7714-zlib-brotli-compress.cjs" + ] }, "anchorSource": "ancestor" }, @@ -118290,8 +118331,11 @@ "inherited": true }, "static": { - "status": "refused", - "evidence": "surface-manifest:unsupported:node-builtin.zlib.brotliCompressSync" + "status": "partial", + "evidence": "surface-manifest:node-builtin.zlib.brotliCompressSync", + "tests": [ + "tests/corpus/7714-zlib-brotli-compress.cjs" + ] }, "anchorSource": "ancestor" }, @@ -118313,8 +118357,12 @@ "inherited": true }, "static": { - "status": "refused", - "evidence": "surface-manifest:unsupported:node-builtin.zlib.brotliDecompress" + "status": "partial", + "evidence": "surface-manifest:node-builtin.zlib.brotliDecompress", + "tests": [ + "tests/corpus/7715-zlib-brotli-decompress.cjs", + "tests/corpus/7716-zlib-brotli.ts" + ] }, "anchorSource": "ancestor" }, @@ -118336,8 +118384,12 @@ "inherited": true }, "static": { - "status": "refused", - "evidence": "surface-manifest:unsupported:node-builtin.zlib.brotliDecompressSync" + "status": "partial", + "evidence": "surface-manifest:node-builtin.zlib.brotliDecompressSync", + "tests": [ + "tests/corpus/7715-zlib-brotli-decompress.cjs", + "tests/corpus/7716-zlib-brotli.ts" + ] }, "anchorSource": "ancestor" }, diff --git a/internal/compatibility/src/generate.mjs b/internal/compatibility/src/generate.mjs index 662c0abd6..1b598fbd3 100644 --- a/internal/compatibility/src/generate.mjs +++ b/internal/compatibility/src/generate.mjs @@ -652,7 +652,14 @@ function publicDetail(tier) { source, ) ) { - return "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Brotli and Zstd streams remain unsupported."; + return "Deflate, Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, and Unzip are Transform streams with Node's output chunking, flush, params, reset, error codes, and option validation; Zstd streams remain unsupported."; + } + if ( + /^compiler-feature:zlib\.(?:zlib\.(?:BrotliCompress|BrotliDecompress)|BrotliOptions)$/.test( + source, + ) + ) { + return "BrotliCompress and BrotliDecompress are Transform streams over the brotli version Node bundles, with Node's parameters, dictionaries, flush, reset, error codes, and option validation; like Node's, they have no params()."; } if (source === "compiler-feature:zlib.zlib.constants") { return "Each zlib.constants member and its module-level copy reads as Node's value; the constants object itself is not a runtime value."; diff --git a/internal/compatibility/static-support.json b/internal/compatibility/static-support.json index 92124f4f5..89992231e 100644 --- a/internal/compatibility/static-support.json +++ b/internal/compatibility/static-support.json @@ -190,6 +190,12 @@ "node-builtin.util": ["tests/corpus/2440-console-inspect-args.ts", "tests/corpus/2912-promisify-fs-readfile.ts"], "node-builtin.worker_threads": ["tests/corpus/957-builtins-namespace.ts", "tests/corpus/native-worker-messages.ts", "tests/corpus/native-worker-references.ts"], "node-builtin.zlib": ["tests/corpus/1404-zlib-crypto-bytes.ts", "tests/corpus/2921-zlib-callbacks.ts", "tests/corpus/3115-zlib-static-compression-levels.ts", "tests/corpus/5370-zlib-stream-roundtrip.ts", "tests/corpus/5371-zlib-stream-chunking.cjs", "tests/corpus/5373-zlib-stream-options.cjs", "tests/corpus/5378-zlib-sync-options.cjs", "tests/corpus/5379-zlib-callback-options.ts", "tests/corpus/5415-zlib-dynamic-inputs.cjs"], + "node-builtin.zlib.brotliCompressSync": ["tests/corpus/7714-zlib-brotli-compress.cjs"], + "node-builtin.zlib.brotliCompress": ["tests/corpus/7714-zlib-brotli-compress.cjs"], + "node-builtin.zlib.createBrotliCompress": ["tests/corpus/7714-zlib-brotli-compress.cjs"], + "node-builtin.zlib.brotliDecompressSync": ["tests/corpus/7715-zlib-brotli-decompress.cjs", "tests/corpus/7716-zlib-brotli.ts"], + "node-builtin.zlib.brotliDecompress": ["tests/corpus/7715-zlib-brotli-decompress.cjs", "tests/corpus/7716-zlib-brotli.ts"], + "node-builtin.zlib.createBrotliDecompress": ["tests/corpus/7715-zlib-brotli-decompress.cjs", "tests/corpus/7716-zlib-brotli.ts"], "stdlib.fetch": ["tests/harness/fetch-conformance.test.ts"], "stdlib.map": ["tests/corpus/typed-collection-iterators.ts", "tests/corpus/typed-collection-iterator-references.ts", "tests/corpus/537-map-iter-drains.ts"], "stdlib.set": ["tests/corpus/typed-collection-iterators.ts", "tests/corpus/typed-collection-iterator-references.ts", "tests/corpus/checked-collection-iterators.ts"], @@ -404,6 +410,9 @@ { "chapter": "util", "signatures": ["`util.promisify(original)`"], "status": "partial", "evidence": ["tests/corpus/1473-promisify-execfile.ts", "tests/corpus/1573-promisify-execfile-env-spread.ts", "tests/corpus/2912-promisify-fs-readfile.ts", "tests/corpus/5625-promisify-exec.ts", "tests/corpus/5626-promisify-forms.ts", "tests/fixtures/node-types/promisify-fs.ts", "tests/corpus/5628-promisify-timers.ts", "tests/fixtures/node-types/promisify-timers.ts", "tests/corpus/5629-promisify-stream.ts", "tests/corpus/5630-promisify-zlib.ts", "tests/fixtures/node-types/promisify-zlib.ts", "tests/corpus/5631-promisify-crypto.ts", "tests/fixtures/node-types/promisify-crypto.ts", "tests/corpus/5632-promisify-dns.ts", "tests/fixtures/node-types/promisify-dns.ts", "tests/corpus/6428-promisify-callback-functions.ts", "tests/fixtures/node-types/promisify-callback-functions.ts", "tests/harness/project-config.test.ts"] }, { "chapter": "typescript", "symbols": ["type"], "status": "supported", "evidence": ["tests/corpus/2702-type-import-link-static/main.ts", "tests/corpus/2703-type-import-link-static-reexport/main.ts", "tests/corpus/2704-type-import-link-static-success/main.ts", "tests/corpus/2707-type-import-link-static-default-reexport/main.ts", "tests/harness/errors.test.ts"] }, { "chapter": "zlib", "signatures": ["Class: `zlib.Deflate`", "Class: `zlib.Inflate`", "Class: `zlib.Gzip`", "Class: `zlib.Gunzip`", "Class: `zlib.DeflateRaw`", "Class: `zlib.InflateRaw`", "Class: `zlib.Unzip`", "Class: `zlib.ZlibBase`", "`zlib.close([callback])`", "`zlib.flush([kind, ]callback)`", "`zlib.params(level, strategy, callback)`", "`zlib.reset()`", "`bytesWritten` Type: {number}", "Class: `Options`"], "status": "partial", "evidence": ["tests/corpus/5370-zlib-stream-roundtrip.ts", "tests/corpus/5371-zlib-stream-chunking.cjs", "tests/corpus/5372-zlib-stream-errors.cjs", "tests/corpus/5373-zlib-stream-options.cjs", "tests/corpus/5374-zlib-stream-flush-params.ts", "tests/corpus/5375-zlib-stream-promises.ts", "tests/corpus/5377-zlib-stream-backpressure.cjs"] }, + { "chapter": "zlib", "signatures": ["Class: `zlib.BrotliCompress`", "Class: `BrotliOptions`"], "status": "partial", "evidence": ["tests/corpus/7714-zlib-brotli-compress.cjs"] }, + { "chapter": "errors", "symbols": ["ERR_BROTLI_INVALID_PARAM"], "status": "partial", "evidence": ["tests/corpus/7714-zlib-brotli-compress.cjs"] }, + { "chapter": "zlib", "signatures": ["Class: `zlib.BrotliDecompress`"], "status": "partial", "evidence": ["tests/corpus/7715-zlib-brotli-decompress.cjs", "tests/corpus/7716-zlib-brotli.ts"] }, { "chapter": "zlib", "signatures": ["`zlib.constants`"], "status": "partial", "evidence": ["tests/corpus/5376-zlib-constants.cjs", "tests/corpus/5374-zlib-stream-flush-params.ts"] }, { "chapter": "dns", "symbols": ["dns.lookup", "dns.lookupService", "dns.getServers", "dns.getDefaultResultOrder", "dns.setDefaultResultOrder"], "status": "partial", "evidence": ["tests/corpus/5648-dns-lookup-forms.ts", "tests/corpus/5649-dns-service-servers.ts", "tests/corpus/5650-dns-lookup-errors-untyped.cjs"] }, { "chapter": "dns", "symbols": ["dnsPromises.lookup", "dnsPromises.lookupService", "dnsPromises.getDefaultResultOrder"], "status": "partial", "evidence": ["tests/corpus/dns-promises-lookup.ts", "tests/corpus/dns-promises-untyped.cjs"] }, diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 0be5bdca2..0e028f180 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -4854,9 +4854,9 @@ declare module "node:readline/promises" { * inputs with Node's default options; libz links only into zlib-using * binaries. Callback forms use the executable worker pool. Options stay * declared so reached uses receive a named SC2020 refusal. The Deflate, - * Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw and Unzip streams are - * runtime Transform streams; Brotli and Zstd remain outside the lowered - * surface. */ + * Inflate, Gzip, Gunzip, DeflateRaw, InflateRaw, Unzip, BrotliCompress + * and BrotliDecompress streams are runtime Transform streams; Zstd remains + * outside the lowered surface. */ declare module "zlib" { import { Transform } from "stream"; export interface ZlibOptions { @@ -4913,50 +4913,66 @@ declare module "zlib" { ): void; export function unzipSync(data: string | Uint8Array, options?: ZlibOptions): Buffer; export function crc32(data: string | Uint8Array, value?: number): number; - export function brotliCompressSync(data: string | Uint8Array): Buffer; - export function brotliDecompressSync(data: Uint8Array): Buffer; - /* Brotli needs a codec the static runtime does not vendor: these are - * declared so their uses receive the named refusal. */ + /* Brotli over the vendored brotli 1.2.0 (scr_brotli.c): `params` keys + * are the numeric BROTLI_PARAM_* and BROTLI_DECODER_PARAM_* constants. */ + export interface BrotliOptions { + [option: string]: unknown; + } export function brotliCompress(data: string | Uint8Array, callback: ZlibCallback): void; - export function brotliDecompress(data: Uint8Array, callback: ZlibCallback): void; - export function createBrotliCompress(options?: ZlibOptions): Transform; - export function createBrotliDecompress(options?: ZlibOptions): Transform; - export class BrotliCompress extends Transform { - constructor(options?: ZlibOptions); - } - export class BrotliDecompress extends Transform { - constructor(options?: ZlibOptions); - } + export function brotliCompress( + data: string | Uint8Array, + options: BrotliOptions, + callback: ZlibCallback, + ): void; + export function brotliCompressSync(data: string | Uint8Array, options?: BrotliOptions): Buffer; + export function brotliDecompress(data: string | Uint8Array, callback: ZlibCallback): void; + export function brotliDecompress( + data: string | Uint8Array, + options: BrotliOptions, + callback: ZlibCallback, + ): void; + export function brotliDecompressSync(data: string | Uint8Array, options?: BrotliOptions): Buffer; /* The stream classes: runtime Transform streams over the zlib engine * (scr_zlib_stream.c). createGzip(options) and new Gzip(options) build - * the same stream; options are validated at runtime with Node's rules. */ + * the same stream; options are validated at runtime with Node's rules. + * Brotli streams have no params(), as in Node. */ class ZlibBase extends Transform { readonly bytesWritten: number; flush(kind?: number, callback?: () => void): void; flush(callback: () => void): void; - params(level: number, strategy: number, callback?: () => void): void; close(callback?: () => void): void; reset(): void; } - export class Deflate extends ZlibBase { + class Zlib extends ZlibBase { + params(level: number, strategy: number, callback?: () => void): void; + } + export class BrotliCompress extends ZlibBase { + constructor(options?: BrotliOptions); + } + export class BrotliDecompress extends ZlibBase { + constructor(options?: BrotliOptions); + } + export function createBrotliCompress(options?: BrotliOptions): BrotliCompress; + export function createBrotliDecompress(options?: BrotliOptions): BrotliDecompress; + export class Deflate extends Zlib { constructor(options?: ZlibOptions); } - export class Inflate extends ZlibBase { + export class Inflate extends Zlib { constructor(options?: ZlibOptions); } - export class Gzip extends ZlibBase { + export class Gzip extends Zlib { constructor(options?: ZlibOptions); } - export class Gunzip extends ZlibBase { + export class Gunzip extends Zlib { constructor(options?: ZlibOptions); } - export class DeflateRaw extends ZlibBase { + export class DeflateRaw extends Zlib { constructor(options?: ZlibOptions); } - export class InflateRaw extends ZlibBase { + export class InflateRaw extends Zlib { constructor(options?: ZlibOptions); } - export class Unzip extends ZlibBase { + export class Unzip extends Zlib { constructor(options?: ZlibOptions); } export function createDeflate(options?: ZlibOptions): Deflate; diff --git a/packages/compiler/src/backend/executable-features.ts b/packages/compiler/src/backend/executable-features.ts index a9076af22..2afb887ea 100644 --- a/packages/compiler/src/backend/executable-features.ts +++ b/packages/compiler/src/backend/executable-features.ts @@ -20,6 +20,7 @@ export function executableLinkFeatures(mod: IrModule): NativeLinkFeatures { ...(features.warningReplace ? { warningReplace: true } : {}), ...(features.stdioExtended ? { stdioExtended: true } : {}), zlib: features.zlib, + ...(features.brotli ? { brotli: true } : {}), assert: features.assert, inspect: features.inspect, dynInvoke: features.dynInvoke, diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 9df33e63f..d5294ba1c 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -575,6 +575,7 @@ export const LIB_FN_SYMS: Record = { "zlib.deflateSync": "scr_zlib_deflate", "zlib.inflateSync": "scr_zlib_inflate", "zlib.crc32": "scr_zlib_crc32", + "zlib.brotliInstall": "scr_brotli_install", // The CA-store unit. get/set throw (an unknown type name, a // certificate-free set) and take the generic path's pending check. "tlsca.root": "scr_tls_ca_root", diff --git a/packages/compiler/src/backend/native-link-info-core.ts b/packages/compiler/src/backend/native-link-info-core.ts index c073bb9a6..1e9994422 100644 --- a/packages/compiler/src/backend/native-link-info-core.ts +++ b/packages/compiler/src/backend/native-link-info-core.ts @@ -35,6 +35,8 @@ export interface NativeLinkFeatures { * or stdio 'resize' events: links the SCR_STDIO_EXTENDED events unit. */ stdioExtended?: boolean; zlib: boolean; + /** node:zlib's Brotli forms: scr_brotli.c and the vendored brotli archive. */ + brotli?: boolean; assert: boolean; inspect: boolean; dynInvoke: boolean; diff --git a/packages/compiler/src/backend/native/contracts.ts b/packages/compiler/src/backend/native/contracts.ts index 53e160984..40bb2352b 100644 --- a/packages/compiler/src/backend/native/contracts.ts +++ b/packages/compiler/src/backend/native/contracts.ts @@ -85,6 +85,9 @@ export interface CcOptions { * compares round-trips and fixed-blob inflation, never raw deflate * output. */ zlib?: boolean; + /** The program uses node:zlib's Brotli forms (with zlib): compiles + * scr_brotli.c and links the vendored brotli archive. */ + brotli?: boolean; /** The program uses node:assert (index.ts detects assert.* libCalls on * the IR): compiles scr_assert.c — the zlib gating precedent, so * assert-free binaries keep their exact size class. scr_regex.c calls diff --git a/packages/compiler/src/backend/native/executable.ts b/packages/compiler/src/backend/native/executable.ts index 1578a0c80..ceb162bcc 100644 --- a/packages/compiler/src/backend/native/executable.ts +++ b/packages/compiler/src/backend/native/executable.ts @@ -82,15 +82,18 @@ import { currentVendorCacheBuildIdentity, vendorBuildCacheRoot, tlsArchivePath, + brotliArchivePath, lreObjectPaths, zlibObjectPaths, stageVendorInputs, ensureTlsArchive, + ensureBrotliArchive, ensureLreObjects, ensureZlibObjects, vendorEngineDir, vendorZlibDir, vendorTlsDir, + vendorBrotliDir, } from "./vendor.js"; import { execFileAsync, subprocessFailureDetail, CcCompileError } from "./process.js"; import { implicitLinkerFingerprint } from "./linker-fingerprint.js"; @@ -119,6 +122,7 @@ interface RuntimeUnitContext { lreObjects: readonly string[]; zlibObjects: readonly string[]; tlsArchive: string | null; + brotliArchive: string | null; } /** An optional runtime input: runtime sources compiled when `when` holds, @@ -222,6 +226,18 @@ const RUNTIME_UNITS: readonly RuntimeUnit[] = [ : [] : [], ), + // Brotli (scr_brotli.c) plugs into the zlib engine and links the + // vendored brotli archive. + unitArgs((u) => + u.brotliArchive + ? [ + "-I", + join(vendorBrotliDir(), "include"), + u.rt(join(u.rtDir, "scr_brotli.c")), + u.brotliArchive, + ] + : [], + ), unit((u) => u.opts.events, "scr_events.c", "scr_readline.c"), // readline's terminal mode: rl.terminal sets the regex unit it // measures with. @@ -398,6 +414,7 @@ export async function compileCInternal( const dh = opts.dh ?? false; const pki = opts.pki ?? false; const mbedtls = tls || cipher || ecdh || dh || pki; + const brotli = (opts.zlib ?? false) && opts.brotli === true; const driver = resolveCc(); const darwinDebugSymbols = needsDarwinDebugSymbols( targetPlatform(driver), @@ -637,6 +654,9 @@ export async function compileCInternal( let tlsArchive = mbedtls ? tlsArchivePath(sanitize, driver, vendorBuildIdentity, vendorCacheRoot) : null; + let brotliArchive = brotli + ? brotliArchivePath(sanitize, driver, vendorBuildIdentity, vendorCacheRoot) + : null; // ours would collide; see scr_regex.c) — the standalone objects are for // static builds only. @@ -674,6 +694,23 @@ export async function compileCInternal( : await stageVendorInputs(materialize, join(stageRoot, "tls")); tlsArchive = paths[0]!; } + if (brotli) { + const cachedArchive = brotliArchivePath( + sanitize, + driver, + vendorBuildIdentity, + materializeCacheRoot, + ); + protectCachedArtifact(cacheWarmPaths, cachedArchive); + const materialize = async (): Promise => [ + await ensureBrotliArchive(sanitize, driver, vendorBuildIdentity, materializeCacheRoot), + ]; + const paths = + stageRoot === undefined + ? await materialize() + : await stageVendorInputs(materialize, join(stageRoot, "brotli")); + brotliArchive = paths[0]!; + } if (regex) { for (const object of lreObjectPaths( sanitize, @@ -760,6 +797,7 @@ export async function compileCInternal( lreObjects, zlibObjects, tlsArchive, + brotliArchive, }), // A .ll program TU (the LLVM backend) deliberately carries no target // triple (byte-stable output; clang supplies the host/SCRIPTC_TARGET diff --git a/packages/compiler/src/backend/native/runtime-inputs.ts b/packages/compiler/src/backend/native/runtime-inputs.ts index 6fb51fd32..c7c5bc32b 100644 --- a/packages/compiler/src/backend/native/runtime-inputs.ts +++ b/packages/compiler/src/backend/native/runtime-inputs.ts @@ -3,7 +3,7 @@ import { createRequire } from "node:module"; import { readdir, readFile, realpath, stat } from "node:fs/promises"; import { basename, dirname, extname, join, relative, resolve } from "node:path"; import { fileURLToPath } from "node:url"; -import { MBEDTLS_VERSION, QJS_COMMIT, ZLIB_VERSION } from "../vendor-inputs.js"; +import { BROTLI_VERSION, MBEDTLS_VERSION, QJS_COMMIT, ZLIB_VERSION } from "../vendor-inputs.js"; import { stableTestMemo } from "./session.js"; const implementationPath = fileURLToPath(import.meta.url); @@ -134,6 +134,7 @@ async function runtimeFingerprintFresh(rtDir: string): Promise { .update(QJS_COMMIT) .update(MBEDTLS_VERSION) .update(ZLIB_VERSION) + .update(BROTLI_VERSION) .update("\0backend-recipe\0"); for (const path of NATIVE_RECIPE_IMPLEMENTATION_PATHS) { h.update(basename(path)) @@ -164,6 +165,7 @@ async function runtimeFingerprintInputGroups( { label: "quickjs-ng", dir: join(rtDir, "..", "vendor", "quickjs-ng") }, { label: "mbedtls", dir: join(rtDir, "..", "vendor", "mbedtls") }, { label: "zlib", dir: join(rtDir, "..", "vendor", "zlib") }, + { label: "brotli", dir: join(rtDir, "..", "vendor", "brotli", "c") }, { label: "curl", dir: join(rtDir, "..", "vendor", "curl") }, ].map(async (group) => { const names = (await nativeSourceFiles(group.dir, true)) diff --git a/packages/compiler/src/backend/native/vendor.ts b/packages/compiler/src/backend/native/vendor.ts index cf7b3a68d..b6084d5c4 100644 --- a/packages/compiler/src/backend/native/vendor.ts +++ b/packages/compiler/src/backend/native/vendor.ts @@ -6,6 +6,9 @@ import { resolvedToolIdentity } from "./tool-identity.js"; export const { vendorEngineDir, vendorTlsDir, + vendorBrotliDir, + brotliArchivePath, + ensureBrotliArchive, vendorBuildCacheRoot, vendorCacheTargetFlavor, vendorCacheBuildIdentity, diff --git a/packages/compiler/src/backend/runtime-pack-core.ts b/packages/compiler/src/backend/runtime-pack-core.ts index 75953be59..49165d8df 100644 --- a/packages/compiler/src/backend/runtime-pack-core.ts +++ b/packages/compiler/src/backend/runtime-pack-core.ts @@ -34,7 +34,7 @@ interface RuntimePackUnit { } interface RuntimePackArchive extends RuntimePackArtifact { - id: "quickjs" | "libregexp" | "zlib" | "mbedtls"; + id: "quickjs" | "libregexp" | "zlib" | "brotli" | "mbedtls"; predicate: RuntimePredicate; } @@ -93,6 +93,7 @@ export interface RuntimeFeatureSet extends NativeLinkFeatures { builtinValues: boolean; warningReplace: boolean; stdioExtended: boolean; + brotli: boolean; nativeFetch: boolean; netEffective: boolean; httpEffective: boolean; @@ -291,6 +292,7 @@ export function effectiveRuntimeFeatures( builtinValues: features.builtinValues === true, warningReplace: features.warningReplace === true, stdioExtended: features.stdioExtended === true, + brotli: features.brotli === true, nativeFetch, netEffective, httpEffective, diff --git a/packages/compiler/src/backend/vendor-archives.ts b/packages/compiler/src/backend/vendor-archives.ts index daa7e5eaa..dbcaf2d36 100644 --- a/packages/compiler/src/backend/vendor-archives.ts +++ b/packages/compiler/src/backend/vendor-archives.ts @@ -18,6 +18,7 @@ import { QJS_COMMIT, MBEDTLS_VERSION, ZLIB_VERSION, + BROTLI_VERSION, LRE_SOURCES, ZLIB_SOURCES, } from "./vendor-inputs.js"; @@ -25,6 +26,7 @@ export { QJS_COMMIT, MBEDTLS_VERSION, ZLIB_VERSION, + BROTLI_VERSION, LRE_SOURCES, ZLIB_SOURCES, } from "./vendor-inputs.js"; @@ -418,9 +420,98 @@ export function createVendorArchives(context: VendorArchiveContext) { return archive; } + function vendorBrotliDir(): string { + return join(runtimeSrcDir(), "..", "vendor", "brotli", "c"); + } + + function brotliArchivePath( + sanitize: boolean, + driver: CcDriver, + buildIdentity: string, + cacheRoot: string = vendorBuildCacheRoot(), + ): string { + const flavor = `${sanitize ? "asan" : "plain"}-${vendorCacheTargetFlavor(driver)}-${buildIdentity}`; + return join(cacheRoot, `brotli-${BROTLI_VERSION}-${flavor}`, "libbrotli.a"); + } + + /** The brotli archive for one flavor, compiled lazily on the first + * Brotli-using build and cached under + * /vendor/brotli----/libbrotli.a, + * with the mbedTLS archive's recipe: per-TU compiles of c/common, c/dec + * and c/enc against c/include, then one `ar rcs`. dec/ and enc/ share + * file names, so each object is named after its path (dec-static_init.o). */ + async function ensureBrotliArchive( + sanitize: boolean, + driver: CcDriver, + buildIdentity: string, + cacheRoot: string = vendorBuildCacheRoot(), + ): Promise { + const flavor = `${sanitize ? "asan" : "plain"}-${vendorCacheTargetFlavor(driver)}-${buildIdentity}`; + const compileArgv = isZigDriver(driver) ? driver.argv : ["clang"]; + const arArgv = isZigDriver(driver) ? [...driver.argv.slice(0, 1), "ar"] : ["ar"]; + const vendor = vendorBrotliDir(); + const archive = brotliArchivePath(sanitize, driver, buildIdentity, cacheRoot); + if (await validVendorArtifact(archive)) return archive; + + await mkdir(cacheRoot, { recursive: true }); + const buildDir = await mkdtemp(join(tmpdir(), `scriptc-vendor-brotli-${flavor}-`)); + try { + const sources = ( + await Promise.all( + ["common", "dec", "enc"].map(async (dir) => + (await readdir(join(vendor, dir))) + .filter((name) => !name.startsWith(".") && name.endsWith(".c")) + .map((name) => `${dir}/${name}`), + ), + ) + ) + .flat() + .sort(); + const object = (src: string): string => + join(buildDir, `${src.replaceAll("/", "-").replace(/\.c$/, "")}.o`); + const cflags = [ + "-std=c11", + ...driver.targetArgs, + ...(sanitize ? ["-O1", "-fsanitize=address"] : ["-Os"]), + "-I", + join(vendor, "include"), + ]; + const width = availableParallelism(); + for (let i = 0; i < sources.length; i += width) { + await Promise.all( + sources + .slice(i, i + width) + .map((src) => + execFileAsync(compileArgv[0] ?? "clang", [ + ...compileArgv.slice(1), + ...cflags, + "-c", + join(vendor, src), + "-o", + object(src), + ]), + ), + ); + } + await execFileAsync(arArgv[0] ?? "ar", [ + ...arArgv.slice(1), + "rcs", + join(buildDir, "libbrotli.a"), + ...sources.map(object), + ]); + await publishVendorArtifact(join(buildDir, "libbrotli.a"), archive); + } finally { + await rm(buildDir, { recursive: true, force: true }); + } + return archive; + } + return { vendorEngineDir, vendorTlsDir, + vendorBrotliDir, + brotliArchivePath, + ensureBrotliArchive, vendorBuildCacheRoot, vendorCacheTargetFlavor, vendorCacheBuildIdentity, diff --git a/packages/compiler/src/backend/vendor-inputs.ts b/packages/compiler/src/backend/vendor-inputs.ts index 3d2710fa0..a9d13e2f0 100644 --- a/packages/compiler/src/backend/vendor-inputs.ts +++ b/packages/compiler/src/backend/vendor-inputs.ts @@ -1,7 +1,9 @@ -/** The pinned QuickJS, mbedTLS, and zlib inputs used by native recipes. */ +/** The pinned QuickJS, mbedTLS, zlib, and brotli inputs used by native recipes. */ export const QJS_COMMIT = "3c8f3d68953955950074c41c6e4d999562ae82a7"; export const MBEDTLS_VERSION = "3.6.7"; export const ZLIB_VERSION = "1.3.1"; +/** The brotli release Node v24.22.0 bundles (packages/runtime/vendor/brotli). */ +export const BROTLI_VERSION = "1.2.0"; /** Exact translation-unit membership shared by cache builds and external * source-pack recipes. */ export const LRE_SOURCES = ["libregexp.c", "libunicode.c"] as const; diff --git a/packages/compiler/src/executable/executable-cache.ts b/packages/compiler/src/executable/executable-cache.ts index 96922ca13..cd3ef3feb 100644 --- a/packages/compiler/src/executable/executable-cache.ts +++ b/packages/compiler/src/executable/executable-cache.ts @@ -62,6 +62,7 @@ export interface EarlyExecutableNativeFeatures { warningReplace?: boolean; stdioExtended?: boolean; zlib: boolean; + brotli?: boolean; assert: boolean; inspect: boolean; dynInvoke: boolean; diff --git a/packages/compiler/src/frontend/lowering/builtins/compression.ts b/packages/compiler/src/frontend/lowering/builtins/compression.ts index 717e09933..1e4d7364c 100644 --- a/packages/compiler/src/frontend/lowering/builtins/compression.ts +++ b/packages/compiler/src/frontend/lowering/builtins/compression.ts @@ -13,6 +13,7 @@ import { funcOf, type IrExpr, type IrLibFn, + type IrStmt, type IrType, type SrcLoc, STRING, @@ -40,6 +41,36 @@ const ZLIB_CALLBACK_FNS: Readonly> = { unzip: "zlib.unzipCb", }; +/* Node's BROTLI_DECODE and BROTLI_ENCODE modes. */ +const BROTLI_DECODE = 8; +const BROTLI_ENCODE = 9; + +/** The Brotli one-shots: every form takes the options entries. */ +const BROTLI_SYNC_MEMBERS: ReadonlySet = new Set([ + "brotliCompressSync", + "brotliDecompressSync", +]); +const BROTLI_CALLBACK_MEMBERS: ReadonlySet = new Set([ + "brotliCompress", + "brotliDecompress", +]); + +/** A Brotli mode connects the codec (scr_brotli.c) to the zlib engine + * before any module initializer runs. */ +function noteBrotliMode(lowerer: Lowerer, mode: number, loc: SrcLoc): void { + if (mode !== BROTLI_DECODE && mode !== BROTLI_ENCODE) return; + const installs = (stmt: IrStmt): boolean => + stmt.kind === "exprStmt" && + stmt.expr.kind === "libCall" && + stmt.expr.fn === "zlib.brotliInstall"; + if (lowerer.mainPrelude.some(installs)) return; + lowerer.mainPrelude.push({ + kind: "exprStmt", + expr: { kind: "libCall", fn: "zlib.brotliInstall", args: [], type: VOID, loc }, + loc, + }); +} + const ZLIB_STREAM_CLASS = "%Transform"; const ZLIB_STREAM_T: IrType = { kind: "object", className: ZLIB_STREAM_CLASS }; @@ -115,6 +146,7 @@ export function lowerZlibStreamNew( } const options = args[0] !== undefined ? zlibOptionsValue(lowerer, args[0], what, loc) : dynUndefinedExpr(loc); + noteBrotliMode(lowerer, mode, loc); return { kind: "libCall", fn: "zlib.streamNew", @@ -154,8 +186,8 @@ function isZlibFallbackDecl(lowerer: Lowerer, d: ts.Node): boolean { return false; } -/** True when `access` names a member the zlib stream base class declares - * (bytesWritten, flush, params, close, reset). */ +/** True when `access` names a member the zlib stream base classes declare + * (bytesWritten, flush, close and reset on ZlibBase; params on Zlib). */ export function isZlibStreamMember(lowerer: Lowerer, access: ts.PropertyAccessExpression): boolean { const symbol = lowerer.checker.getSymbolAtLocation(access.name); if (!symbol) return false; @@ -163,7 +195,7 @@ export function isZlibStreamMember(lowerer: Lowerer, access: ts.PropertyAccessEx (d) => d.parent !== undefined && ts.isClassDeclaration(d.parent) && - d.parent.name?.text === "ZlibBase" && + (d.parent.name?.text === "ZlibBase" || d.parent.name?.text === "Zlib") && isZlibFallbackDecl(lowerer, d.parent), ); } @@ -281,12 +313,17 @@ const ZLIB_ONE_SHOT_MODES: Readonly> = { deflateRaw: 5, inflateRaw: 6, unzip: 7, + brotliDecompressSync: BROTLI_DECODE, + brotliCompressSync: BROTLI_ENCODE, + brotliDecompress: BROTLI_DECODE, + brotliCompress: BROTLI_ENCODE, }; /** True for a zlib callback one-shot util.promisify converts (deflate, - * inflate, deflateRaw, inflateRaw, gzip, gunzip and unzip). */ + * inflate, deflateRaw, inflateRaw, gzip, gunzip, unzip, brotliCompress and + * brotliDecompress). */ export function isPromisifiedZlibMember(member: string): boolean { - return ZLIB_CALLBACK_FNS[member] !== undefined; + return ZLIB_CALLBACK_FNS[member] !== undefined || BROTLI_CALLBACK_MEMBERS.has(member); } /** A call through `promisify(zlib.gzip)` and the other callback one-shots: @@ -311,6 +348,7 @@ export function lowerPromisifiedZlibCall( ); } const input = zlibInput(lowerer, expr.arguments.nodes[0]!, loc); + noteBrotliMode(lowerer, ZLIB_ONE_SHOT_MODES[member]!, loc); return { kind: "libCall", fn: input.dyn ? "zlib.promiseDyn" : "zlib.promise", @@ -334,6 +372,8 @@ const ZLIB_STREAM_FACTORIES: Readonly> = { createDeflateRaw: 5, createInflateRaw: 6, createUnzip: 7, + createBrotliDecompress: BROTLI_DECODE, + createBrotliCompress: BROTLI_ENCODE, }; export function lowerZlibModuleCall( @@ -356,6 +396,9 @@ export function lowerZlibModuleCall( loc, ); } + if (BROTLI_SYNC_MEMBERS.has(bi.member) || BROTLI_CALLBACK_MEMBERS.has(bi.member)) { + return lowerBrotliOneShot(lowerer, expr, bi.member, loc); + } const syncFn = ZLIB_SYNC_FNS[bi.member]; if (syncFn !== undefined) { if (expr.arguments.nodes.length === 0 || expr.arguments.nodes.length > 2) { @@ -502,6 +545,57 @@ export function lowerZlibModuleCall( throw new InternalCompilerError(`unhandled lowered zlib member ${bi.member}`); } +/** brotliCompressSync(data[, options]), brotliCompress(data[, options], + * callback) and the decompress pair: the options entries with Node's + * BROTLI_ENCODE or BROTLI_DECODE mode, an absent options value passing + * undefined. */ +function lowerBrotliOneShot( + lowerer: Lowerer, + expr: ts.CallExpression, + member: string, + loc: SrcLoc, +): IrExpr { + const args = expr.arguments.nodes; + const mode = ZLIB_ONE_SHOT_MODES[member]!; + const sync = BROTLI_SYNC_MEMBERS.has(member); + if (sync ? args.length === 0 || args.length > 2 : args.length !== 2 && args.length !== 3) { + lowerer.noLowering( + `zlib.${member} with ${args.length} arguments`, + expr, + sync + ? `${member}(data) and ${member}(data, options) are supported` + : `${member}(data, callback) and ${member}(data, options, callback) are supported`, + ); + } + const input = zlibInput(lowerer, args[0]!, loc); + const withOptions = sync ? args.length === 2 : args.length === 3; + const options = withOptions + ? zlibOptionsValue(lowerer, args[1]!, `zlib.${member}`, loc) + : dynUndefinedExpr(loc); + noteBrotliMode(lowerer, mode, loc); + if (sync) { + return { + kind: "libCall", + fn: input.dyn ? "zlib.syncOptsDyn" : "zlib.syncOpts", + args: [numLit(mode, loc), input.value, options], + type: BYTES_U8, + loc, + }; + } + return { + kind: "libCall", + fn: input.dyn ? "zlib.cbOptsDyn" : "zlib.cbOpts", + args: [ + numLit(mode, loc), + input.value, + options, + errorFirstBytesCallback(lowerer, args[withOptions ? 2 : 1]!, "zlib"), + ], + type: VOID, + loc, + }; +} + /** The class name of a zlib stream mode (Node's constructor name). */ export function zlibClassName(mode: number): string { for (const [name, m] of ZLIB_STREAM_MODES) if (m === mode) return name; diff --git a/packages/compiler/src/frontend/lowering/surfaces.ts b/packages/compiler/src/frontend/lowering/surfaces.ts index ebf09f9e6..e1cece88b 100644 --- a/packages/compiler/src/frontend/lowering/surfaces.ts +++ b/packages/compiler/src/frontend/lowering/surfaces.ts @@ -1635,6 +1635,12 @@ export const BUILTIN_MODULE_FNS: Record< unzip: { fn: "zlib.unzipCb", params: [], result: VOID }, unzipSync: { fn: "zlib.unzipSync", params: [BYTES_U8], result: BYTES_U8 }, crc32: { fn: "zlib.crc32", params: [], result: F64 }, + // Brotli (special-cased in lowerZlibModuleCall): every form takes the + // options entries with Node's BROTLI_ENCODE or BROTLI_DECODE mode. + brotliCompress: { fn: "zlib.cbOpts", params: [], result: VOID }, + brotliCompressSync: { fn: "zlib.syncOpts", params: [], result: BYTES_U8 }, + brotliDecompress: { fn: "zlib.cbOpts", params: [], result: VOID }, + brotliDecompressSync: { fn: "zlib.syncOpts", params: [], result: BYTES_U8 }, // The stream factories (special-cased in lowerZlibModuleCall): each // answers a runtime Transform stream over the zlib engine. createDeflate: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, @@ -1644,6 +1650,8 @@ export const BUILTIN_MODULE_FNS: Record< createDeflateRaw: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, createInflateRaw: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, createUnzip: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, + createBrotliCompress: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, + createBrotliDecompress: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, }, url: { fileURLToPath: { @@ -3048,17 +3056,6 @@ export function builtinModulesArrayLit(loc: { file: string; start: number; end: }; } -/** Member-specific hints for RECOGNIZED builtin modules whose member has - * no lowering. The default-options one-shot zlib/deflate-raw/gzip codecs - * lower for strings and Buffers; the remaining surface points at them. */ -const ZLIB_HINT = - "the deflate/inflate, raw, gzip/gunzip, and unzip sync/callback forms with Node's options, crc32, " + - "and the Deflate/Inflate/Gzip/Gunzip/DeflateRaw/InflateRaw/Unzip streams are the lowered zlib surface"; -/** Brotli has no codec in the static runtime (zlib is the only vendored - * compression library). */ -const BROTLI_HINT = - "Brotli needs a Brotli codec, which the static runtime does not vendor — " + ZLIB_HINT; - const ASSERT_MODULE_HINTS: Record = { ifError: "test explicitly instead: assert.strictEqual(err, null) / " + @@ -3120,16 +3117,6 @@ export const BUILTIN_MODULE_FENCE_HINTS: Record< "a compiled binary has no FIPS provider to enable, and Node itself throws on setFips(true) " + "in a non-FIPS build — getFips() answers 0 here", }, - zlib: { - brotliCompressSync: BROTLI_HINT, - brotliDecompressSync: BROTLI_HINT, - brotliCompress: BROTLI_HINT, - brotliDecompress: BROTLI_HINT, - createBrotliCompress: BROTLI_HINT, - createBrotliDecompress: BROTLI_HINT, - BrotliCompress: BROTLI_HINT, - BrotliDecompress: BROTLI_HINT, - }, http2: { connect: "HTTP/2 client sessions have no lowering — the lowered http2 surface is the SERVER side: " + diff --git a/packages/compiler/src/index.ts b/packages/compiler/src/index.ts index 58dc39c7b..4a2974f5b 100644 --- a/packages/compiler/src/index.ts +++ b/packages/compiler/src/index.ts @@ -595,6 +595,7 @@ async function compileExecutableNative( ...(features.warningReplace ? { warningReplace: true } : {}), ...(features.stdioExtended ? { stdioExtended: true } : {}), zlib: features.zlib, + ...(features.brotli ? { brotli: true } : {}), assert: features.assert, inspect: features.inspect, dynInvoke: features.dynInvoke, diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index d563f2951..8e278ef2c 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -3181,6 +3181,8 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ * the +1 %Transform stream. flush takes the kind value, params the level * and strategy values; the Cb forms move their () => void callback. The * receivers are borrowed. */ + /** Connects scr_brotli.c to the zlib engine (%main, before any module). */ + "zlib.brotliInstall": { argTypes: [], result: VOID }, "zlib.streamNew": { argTypes: [F64, DYN], result: VOID }, "zlib.streamBytesWritten": { argTypes: [null], result: F64 }, /** `stream instanceof zlib.Gzip`: the borrowed stream and the class's diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index 550333edd..db5ba735c 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -1673,6 +1673,8 @@ export const ZLIB_STREAM_MODES: ReadonlyMap = new Map([ ["DeflateRaw", 5], ["InflateRaw", 6], ["Unzip", 7], + ["BrotliDecompress", 8], + ["BrotliCompress", 9], ]); export interface IrRecordShape { diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 2ae19375f..118f0ef38 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -1121,6 +1121,9 @@ const RUNTIME_FEATURE_RULES = { * scr_webcrypto.c. */ webcrypto: rule({ prefixes: ["webcrypto."] }), zlib: rule({ prefixes: ["zlib."] }), + /** node:zlib's Brotli forms: zlib.brotliInstall, which %main calls when + * the program uses Brotli (scr_brotli.c). */ + brotli: rule({ fns: ["zlib.brotliInstall"] }), }; type RuntimeFeatureName = keyof typeof RUNTIME_FEATURE_RULES; @@ -1190,6 +1193,7 @@ function noRuntimeFeatures(): RuntimeFeatures { wasm: false, webcrypto: false, zlib: false, + brotli: false, }; } diff --git a/packages/compiler/src/library/ir-policy.ts b/packages/compiler/src/library/ir-policy.ts index ac5d5e47b..f08b85232 100644 --- a/packages/compiler/src/library/ir-policy.ts +++ b/packages/compiler/src/library/ir-policy.ts @@ -31,6 +31,7 @@ const LIB_MODE_REFUSED_PREFIXES: readonly [string, string][] = [ ["zlib.cbOpts", "the async node:zlib callback surface"], ["zlib.promise", "the async node:zlib callback surface (util.promisify)"], ["zlib.stream", "the node:zlib stream classes"], + ["zlib.brotliInstall", "node:zlib's Brotli forms"], ["process.stdoutWriteBytesCb", "process.stdout.write completion callbacks"], ["process.stderrWriteBytesCb", "process.stderr.write completion callbacks"], ["timers.", "the timers surface (setTimeout family)"], diff --git a/packages/compiler/src/native/sanitizer.test.ts b/packages/compiler/src/native/sanitizer.test.ts index 33a4c19b9..1415f2971 100644 --- a/packages/compiler/src/native/sanitizer.test.ts +++ b/packages/compiler/src/native/sanitizer.test.ts @@ -86,6 +86,7 @@ test.skipIf(process.platform !== "linux" && process.platform !== "darwin")( builtinValues: false, warningReplace: false, stdioExtended: false, + brotli: false, regex: true, copying: false, textDecoderLegacy: false, diff --git a/packages/compiler/src/native/sanitizer.ts b/packages/compiler/src/native/sanitizer.ts index 6c1ff1e35..cb3728ec0 100644 --- a/packages/compiler/src/native/sanitizer.ts +++ b/packages/compiler/src/native/sanitizer.ts @@ -94,6 +94,7 @@ export function buildSanitizedRuntime( const quickjs = join(vendor, "quickjs-ng"); const zlib = join(vendor, "zlib"); const mbedtls = join(vendor, "mbedtls"); + const brotli = join(vendor, "brotli", "c"); const cacheIdentity = contentDigest( JSON.stringify({ schema: 1, @@ -137,6 +138,8 @@ export function buildSanitizedRuntime( zlib, "-I", join(mbedtls, "include"), + "-I", + join(brotli, "include"), ...(toolchain.target.platform === "linux" ? ["-ffunction-sections", "-fdata-sections"] : []), ]; const runtimeObjects: string[] = []; @@ -173,9 +176,23 @@ export function buildSanitizedRuntime( .filter((file) => file.endsWith(".c") && !file.startsWith(".")) .sort(); args = ["-std=c11", "-I", join(mbedtls, "include"), "-I", directory]; + } else if (name === "brotli") { + directory = brotli; + sources = ["common", "dec", "enc"] + .flatMap((dir) => + readdirSync(join(brotli, dir)) + .filter((file) => file.endsWith(".c") && !file.startsWith(".")) + .map((file) => `${dir}/${file}`), + ) + .sort(); + args = ["-std=c11", "-I", join(brotli, "include")]; } else throw new NativeCodegenError("SC3003", `unsupported runtime vendor archive: ${name}`); const objects = sources.map((source) => - compile(join(directory, source), name + "-" + source.replace(/\.c$/, ".o"), args), + compile( + join(directory, source), + name + "-" + source.replaceAll("/", "-").replace(/\.c$/, ".o"), + args, + ), ); const output = join(stage, "libscriptc-" + name + ".a"); runNativeTool( diff --git a/packages/compiler/surface-manifest.json b/packages/compiler/surface-manifest.json index 75541b8e5..18301686a 100644 --- a/packages/compiler/surface-manifest.json +++ b/packages/compiler/surface-manifest.json @@ -2876,22 +2876,6 @@ "status": "static", "note": "recognized module (bare and node:-prefixed specifiers)" }, - { - "id": "node-builtin.zlib.BrotliCompress", - "kind": "node-builtin", - "name": "zlib.BrotliCompress", - "status": "unsupported", - "code": "SC2020", - "note": "Brotli needs a Brotli codec, which the static runtime does not vendor — the deflate/inflate, raw, gzip/gunzip, and unzip sync/callback forms with Node's options, crc32, and the Deflate/Inflate/Gzip/Gunzip/DeflateRaw/InflateRaw/Unzip streams are the lowered zlib surface" - }, - { - "id": "node-builtin.zlib.BrotliDecompress", - "kind": "node-builtin", - "name": "zlib.BrotliDecompress", - "status": "unsupported", - "code": "SC2020", - "note": "Brotli needs a Brotli codec, which the static runtime does not vendor — the deflate/inflate, raw, gzip/gunzip, and unzip sync/callback forms with Node's options, crc32, and the Deflate/Inflate/Gzip/Gunzip/DeflateRaw/InflateRaw/Unzip streams are the lowered zlib surface" - }, { "id": "node-builtin.zlib.DEFLATE", "kind": "node-builtin", @@ -3645,33 +3629,25 @@ "id": "node-builtin.zlib.brotliCompress", "kind": "node-builtin", "name": "zlib.brotliCompress", - "status": "unsupported", - "code": "SC2020", - "note": "Brotli needs a Brotli codec, which the static runtime does not vendor — the deflate/inflate, raw, gzip/gunzip, and unzip sync/callback forms with Node's options, crc32, and the Deflate/Inflate/Gzip/Gunzip/DeflateRaw/InflateRaw/Unzip streams are the lowered zlib surface" + "status": "static" }, { "id": "node-builtin.zlib.brotliCompressSync", "kind": "node-builtin", "name": "zlib.brotliCompressSync", - "status": "unsupported", - "code": "SC2020", - "note": "Brotli needs a Brotli codec, which the static runtime does not vendor — the deflate/inflate, raw, gzip/gunzip, and unzip sync/callback forms with Node's options, crc32, and the Deflate/Inflate/Gzip/Gunzip/DeflateRaw/InflateRaw/Unzip streams are the lowered zlib surface" + "status": "static" }, { "id": "node-builtin.zlib.brotliDecompress", "kind": "node-builtin", "name": "zlib.brotliDecompress", - "status": "unsupported", - "code": "SC2020", - "note": "Brotli needs a Brotli codec, which the static runtime does not vendor — the deflate/inflate, raw, gzip/gunzip, and unzip sync/callback forms with Node's options, crc32, and the Deflate/Inflate/Gzip/Gunzip/DeflateRaw/InflateRaw/Unzip streams are the lowered zlib surface" + "status": "static" }, { "id": "node-builtin.zlib.brotliDecompressSync", "kind": "node-builtin", "name": "zlib.brotliDecompressSync", - "status": "unsupported", - "code": "SC2020", - "note": "Brotli needs a Brotli codec, which the static runtime does not vendor — the deflate/inflate, raw, gzip/gunzip, and unzip sync/callback forms with Node's options, crc32, and the Deflate/Inflate/Gzip/Gunzip/DeflateRaw/InflateRaw/Unzip streams are the lowered zlib surface" + "status": "static" }, { "id": "node-builtin.zlib.crc32", @@ -3683,17 +3659,13 @@ "id": "node-builtin.zlib.createBrotliCompress", "kind": "node-builtin", "name": "zlib.createBrotliCompress", - "status": "unsupported", - "code": "SC2020", - "note": "Brotli needs a Brotli codec, which the static runtime does not vendor — the deflate/inflate, raw, gzip/gunzip, and unzip sync/callback forms with Node's options, crc32, and the Deflate/Inflate/Gzip/Gunzip/DeflateRaw/InflateRaw/Unzip streams are the lowered zlib surface" + "status": "static" }, { "id": "node-builtin.zlib.createBrotliDecompress", "kind": "node-builtin", "name": "zlib.createBrotliDecompress", - "status": "unsupported", - "code": "SC2020", - "note": "Brotli needs a Brotli codec, which the static runtime does not vendor — the deflate/inflate, raw, gzip/gunzip, and unzip sync/callback forms with Node's options, crc32, and the Deflate/Inflate/Gzip/Gunzip/DeflateRaw/InflateRaw/Unzip streams are the lowered zlib surface" + "status": "static" }, { "id": "node-builtin.zlib.createDeflate", diff --git a/packages/compiler/test/native-codegen-lowering.test.ts b/packages/compiler/test/native-codegen-lowering.test.ts index e9891e945..857393f21 100644 --- a/packages/compiler/test/native-codegen-lowering.test.ts +++ b/packages/compiler/test/native-codegen-lowering.test.ts @@ -51,14 +51,12 @@ test("decompression options lower for run-time validation", () => { expect(diags).toEqual([]); }); -test("Brotli keeps its SC2020 refusal", () => { +test("Brotli options lower for run-time validation", () => { const diags = diagnostics(` - import { brotliCompressSync } from "node:zlib"; - console.log(brotliCompressSync("payload").length); + import { brotliCompressSync, constants } from "node:zlib"; + console.log(brotliCompressSync("payload", { params: { [constants.BROTLI_PARAM_QUALITY]: 4 } }).length); `); - expect(diags).toHaveLength(1); - expect(diags[0]!.code).toBe("SC2020"); - expect(diags[0]!.message).toContain("brotliCompressSync"); + expect(diags).toEqual([]); }); test("union writes keep the refusal for incompatible field storage", () => { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7714-zlib-brotli-compress.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7714-zlib-brotli-compress.cjs.json new file mode 100644 index 000000000..fb8e2d1d9 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7714-zlib-brotli-compress.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7714-zlib-brotli-compress.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7715-zlib-brotli-decompress.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7715-zlib-brotli-decompress.cjs.json new file mode 100644 index 000000000..4a40657b1 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7715-zlib-brotli-decompress.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7715-zlib-brotli-decompress.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7716-zlib-brotli.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7716-zlib-brotli.ts.json new file mode 100644 index 000000000..b410a8230 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7716-zlib-brotli.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7716-zlib-brotli.ts" + ], + "diags": [] +} diff --git a/packages/runtime-darwin-arm64/runtime-pack-matrix.mjs b/packages/runtime-darwin-arm64/runtime-pack-matrix.mjs index 7b2d3e115..197adc516 100644 --- a/packages/runtime-darwin-arm64/runtime-pack-matrix.mjs +++ b/packages/runtime-darwin-arm64/runtime-pack-matrix.mjs @@ -14,6 +14,7 @@ import { */ const any = (...features) => ({ any: features }); +const all = (...features) => ({ all: features }); // ld64 dead-strips Mach-O symbol subsections without an ELF-style compile // flag. Keep this checked-in metadata alongside the matrix so pack build and @@ -43,6 +44,7 @@ export const RUNTIME_PACK_MATRIX = withLibraryRuntimeFlavors( { id: "quickjs", predicate: false }, { id: "libregexp", predicate: "regex" }, { id: "zlib", predicate: "zlibEffective" }, + { id: "brotli", predicate: all("zlib", "brotli") }, { id: "mbedtls", predicate: any("tlsEffective", "cipher", "ecdh", "dh", "pki") }, ], system_libraries: [{ name: "System", predicate: true }], diff --git a/packages/runtime-darwin-arm64/scripts/build.mjs b/packages/runtime-darwin-arm64/scripts/build.mjs index e492c36b4..b6b855c05 100644 --- a/packages/runtime-darwin-arm64/scripts/build.mjs +++ b/packages/runtime-darwin-arm64/scripts/build.mjs @@ -72,6 +72,7 @@ async function build() { const quickjs = join(vendorRoot, "quickjs-ng"); const zlib = join(vendorRoot, "zlib"); const mbedtls = join(vendorRoot, "mbedtls"); + const brotli = join(vendorRoot, "brotli", "c"); const QJS_SOURCES = ["dtoa.c", "libregexp.c", "libunicode.c", "quickjs.c"]; const LRE_SOURCES = ["libregexp.c", "libunicode.c"]; const ZLIB_SOURCES = [ @@ -112,20 +113,23 @@ async function build() { return parallelMap(items, width, task); } + // Archive members are named by basename, so a source in a subdirectory + // (brotli's dec/ and enc/ share file names) is named after its path. + const objectName = (source) => source.replaceAll("/", "-").replace(/\.c$/, ".o"); async function archive(id, sources, sourceRoot, flags) { const root = join(stagedOutputRoot, "vendor", id); const objectRoot = join(root, "objects"); await parallel(sources, async (source) => { await compile( join(sourceRoot, source), - join(objectRoot, source.replace(/\.c$/, ".o")), + join(objectRoot, objectName(source)), unalignedVendorSources.has(source) ? flags.filter((flag) => !codeAlignment.includes(flag)) : flags, ); }); const output = join(root, `libscriptc-${id}.a`); - const objects = sources.map((source) => join(objectRoot, source.replace(/\.c$/, ".o"))); + const objects = sources.map((source) => join(objectRoot, objectName(source))); await createDeterministicArchive(archiver, output, objects); await rm(objectRoot, { recursive: true, force: true }); return { @@ -181,6 +185,7 @@ async function build() { ...(unit.source === "scr_zlib.c" || unit.source === "scr_fetch.c" ? ["-I", zlib] : []), + ...(unit.source === "scr_brotli.c" ? ["-I", join(brotli, "include")] : []), ]; const unitFlags = [ ...commonFlags, @@ -268,6 +273,17 @@ async function build() { const mbedtlsSources = (await readdir(join(mbedtls, "library"))) .filter((name) => !name.startsWith(".") && name.endsWith(".c")) .sort(); + const brotliSources = ( + await Promise.all( + ["common", "dec", "enc"].map(async (dir) => + (await readdir(join(brotli, dir))) + .filter((name) => !name.startsWith(".") && name.endsWith(".c")) + .map((name) => `${dir}/${name}`), + ), + ) + ) + .flat() + .sort(); const archives = [ await archive("quickjs", QJS_SOURCES, quickjs, [ "-target", @@ -301,6 +317,15 @@ async function build() { "-I", zlib, ]), + await archive("brotli", brotliSources, brotli, [ + "-target", + RUNTIME_PACK_MATRIX.target.llvm_triple, + "-std=c11", + "-Os", + ...codeAlignment, + "-I", + join(brotli, "include"), + ]), await archive("mbedtls", mbedtlsSources, join(mbedtls, "library"), [ "-target", RUNTIME_PACK_MATRIX.target.llvm_triple, @@ -325,6 +350,7 @@ async function build() { ], [join(vendorRoot, "unicode", "LICENSE"), "artifacts/licenses/unicode.txt", "Unicode-3.0"], [join(zlib, "LICENSE"), "artifacts/licenses/zlib.txt", "Zlib"], + [join(vendorRoot, "brotli", "LICENSE"), "artifacts/licenses/brotli.txt", "MIT"], [join(mbedtls, "LICENSE"), "artifacts/licenses/mbedtls.txt", "Apache-2.0"], ]; await Promise.all( diff --git a/packages/runtime-pack-common/runtime-pack-matrix.mjs b/packages/runtime-pack-common/runtime-pack-matrix.mjs index 0ab467236..600637ba6 100644 --- a/packages/runtime-pack-common/runtime-pack-matrix.mjs +++ b/packages/runtime-pack-common/runtime-pack-matrix.mjs @@ -83,6 +83,7 @@ export const OPTIONAL_RUNTIME_SOURCES = [ // Blob and File box their reads as dyn promises through scr_async_dyn.c. ["scr_blob.c", "dynAsync"], ["scr_zlib.c", "zlib"], + ["scr_brotli.c", all("zlib", "brotli")], ["scr_events.c", "events"], ["scr_readline.c", "events"], ["scr_readline_tty.c", all("events", "regex")], @@ -227,6 +228,7 @@ export function createRuntimePackMatrix({ { id: "quickjs", predicate: false }, { id: "libregexp", predicate: "regex" }, { id: "zlib", predicate: "zlibEffective" }, + { id: "brotli", predicate: all("zlib", "brotli") }, { id: "mbedtls", predicate: any("tlsEffective", "cipher", "ecdh", "dh", "pki") }, ]; const matrix = withLibraryRuntimeFlavors( diff --git a/packages/runtime-pack-common/scripts/build.mjs b/packages/runtime-pack-common/scripts/build.mjs index e22f2a37c..d4794b7d1 100644 --- a/packages/runtime-pack-common/scripts/build.mjs +++ b/packages/runtime-pack-common/scripts/build.mjs @@ -85,6 +85,7 @@ async function build() { const quickjs = join(vendorRoot, "quickjs-ng"); const zlib = join(vendorRoot, "zlib"); const mbedtls = join(vendorRoot, "mbedtls"); + const brotli = join(vendorRoot, "brotli", "c"); const qjsSources = ["dtoa.c", "libregexp.c", "libunicode.c", "quickjs.c"]; const lreSources = ["libregexp.c", "libunicode.c"]; const zlibSources = [ @@ -131,6 +132,9 @@ async function build() { const width = Math.max(1, Math.min(8, availableParallelism())); return parallelMap(items, width, task); }; + // Archive members are named by basename, so a source in a subdirectory + // (brotli's dec/ and enc/ share file names) is named after its path. + const objectName = (source) => source.replaceAll("/", "-").replace(/\.c$/, ".o"); const archive = async (id, sources, sourceRoot, flags) => { process.stdout.write(`building ${packageManifest.name} ${id} archive\n`); const root = join(stagedOutputRoot, "vendor", id); @@ -138,7 +142,7 @@ async function build() { await parallel(sources, async (source) => compile( join(sourceRoot, source), - join(objectRoot, source.replace(/\.c$/, ".o")), + join(objectRoot, objectName(source)), unalignedVendorSources.has(source) ? flags.filter((flag) => !codeAlignment.includes(flag)) : flags, @@ -148,7 +152,7 @@ async function build() { await createDeterministicArchive( archiver, output, - sources.map((source) => join(objectRoot, source.replace(/\.c$/, ".o"))), + sources.map((source) => join(objectRoot, objectName(source))), archiverArgs, ); await rm(objectRoot, { recursive: true, force: true }); @@ -232,6 +236,7 @@ async function build() { ...(unit.source === "scr_zlib.c" || unit.source === "scr_fetch.c" ? ["-I", zlib] : []), + ...(unit.source === "scr_brotli.c" ? ["-I", join(brotli, "include")] : []), ]; // Worker variants link only into executables, whose own TLS block // holds every runtime thread-local: on ELF the initial-exec model @@ -334,6 +339,17 @@ async function build() { const mbedtlsSources = (await readdir(join(mbedtls, "library"))) .filter((name) => !name.startsWith(".") && name.endsWith(".c")) .sort(); + const brotliSources = ( + await Promise.all( + ["common", "dec", "enc"].map(async (dir) => + (await readdir(join(brotli, dir))) + .filter((name) => !name.startsWith(".") && name.endsWith(".c")) + .map((name) => `${dir}/${name}`), + ), + ) + ) + .flat() + .sort(); // Vendored QuickJS reads `clock_gettime` for its monotonic clock. WASI // exposes that declaration only when its process-clock emulation ABI is // selected, so vendor sources inherit the target's runtime defines too. @@ -388,6 +404,17 @@ async function build() { ]), ] : []), + ...(requestedArchives.has("brotli") + ? [ + await archive("brotli", brotliSources, brotli, [ + ...vendorTarget, + "-std=c11", + "-Os", + "-I", + join(brotli, "include"), + ]), + ] + : []), ...(requestedArchives.has("mbedtls") ? [ await archive("mbedtls", mbedtlsSources, join(mbedtls, "library"), [ @@ -417,6 +444,7 @@ async function build() { "BSD-3-Clause", ], [join(zlib, "LICENSE"), "artifacts/licenses/zlib.txt", "Zlib"], + [join(vendorRoot, "brotli", "LICENSE"), "artifacts/licenses/brotli.txt", "MIT"], [join(mbedtls, "LICENSE"), "artifacts/licenses/mbedtls.txt", "Apache-2.0"], ]; licensed.push([ diff --git a/packages/runtime/src/scr_brotli.c b/packages/runtime/src/scr_brotli.c new file mode 100644 index 000000000..617b0c60f --- /dev/null +++ b/packages/runtime/src/scr_brotli.c @@ -0,0 +1,317 @@ +/* node:zlib's Brotli codec over the vendored brotli 1.2.0 (the version Node + * v24.22.0 bundles, so compressed bytes match Node's). Node's + * BrotliEncoderContext and BrotliDecoderContext (src/node_zlib.cc) plug into + * scr_zlib.c's engine as a codec, so the one-shot, callback, promise and + * stream forms run exactly as their zlib counterparts do. The option ladder + * is lib/zlib.js's Brotli() followed by ZlibBase(). Linked only when the + * program uses Brotli; scr_brotli_install, which %main calls first, + * connects it to scr_zlib.c. */ +#include "scr_runtime.h" + +#include +#include +#include +#include +#include +#include + +enum { SCR_BROTLI_DECODE = 8, SCR_BROTLI_ENCODE = 9 }; +/* kMaxBrotliParam + 1: the largest BROTLI_PARAM_* value is + * BROTLI_PARAM_NDIRECT (8). An unset slot holds 0xFFFFFFFF, as Node's + * Uint32Array filled with -1 does. */ +#define SCR_BROTLI_PARAMS 9 +#define SCR_BROTLI_UNSET 0xFFFFFFFFu + +typedef struct { + bool encode; + BrotliEncoderState *enc; + BrotliEncoderPreparedDictionary *prepared; + BrotliDecoderState *dec; + /* The dictionary stays alive while the encoder's prepared dictionary or + * the decoder holds it. */ + unsigned char *dict; + size_t dict_len; + int flush; + bool enc_ok; + BrotliDecoderResult dec_result; + BrotliDecoderErrorCode dec_error; + char dec_code[64]; +} ScrBrotli; + +static void scr_brotli_oom(void) { + scr_trap("scriptc: out of memory\n"); +} + +static bool scr_brotli_fail(ScrZlibError *out, const char *message, const char *code, int err) { + out->message = message; + out->code = code; + out->err = err; + return true; +} + +static void scr_brotli_close(ScrBrotli *b) { + if (b->enc) BrotliEncoderDestroyInstance(b->enc); + if (b->prepared) BrotliEncoderDestroyPreparedDictionary(b->prepared); + if (b->dec) BrotliDecoderDestroyInstance(b->dec); + b->enc = NULL; + b->prepared = NULL; + b->dec = NULL; +} + +/* Init(dictionary): a fresh instance with the dictionary attached. As in + * Node, the decoder's last error survives a re-initialization. True with + * *out filled on failure. */ +static bool scr_brotli_init(ScrBrotli *b, ScrZlibError *out) { + scr_brotli_close(b); + if (b->encode) { + b->enc = BrotliEncoderCreateInstance(NULL, NULL, NULL); + b->enc_ok = false; + if (!b->enc) return scr_brotli_fail(out, "Could not initialize Brotli instance", "ERR_ZLIB_INITIALIZATION_FAILED", -1); + if (b->dict_len == 0) return false; + b->prepared = BrotliEncoderPrepareDictionary(BROTLI_SHARED_DICTIONARY_RAW, b->dict_len, b->dict, BROTLI_MAX_QUALITY, + NULL, NULL, NULL); + if (!b->prepared) return scr_brotli_fail(out, "Failed to prepare brotli dictionary", "ERR_ZLIB_DICTIONARY_LOAD_FAILED", -1); + if (!BrotliEncoderAttachPreparedDictionary(b->enc, b->prepared)) + return scr_brotli_fail(out, "Failed to attach brotli dictionary", "ERR_ZLIB_DICTIONARY_LOAD_FAILED", -1); + return false; + } + b->dec = BrotliDecoderCreateInstance(NULL, NULL, NULL); + if (!b->dec) return scr_brotli_fail(out, "Could not initialize Brotli instance", "ERR_ZLIB_INITIALIZATION_FAILED", -1); + if (b->dict_len != 0 && !BrotliDecoderAttachDictionary(b->dec, BROTLI_SHARED_DICTIONARY_RAW, b->dict_len, b->dict)) + return scr_brotli_fail(out, "Failed to attach brotli dictionary", "ERR_ZLIB_DICTIONARY_LOAD_FAILED", -1); + return false; +} + +static void scr_brotli_free(void *state) { + ScrBrotli *b = state; + if (!b) return; + scr_brotli_close(b); + free(b->dict); + free(b); +} + +/* DoThreadPoolWork: runs on a worker thread and touches only the state. */ +static void scr_brotli_work(void *state, int flush, const unsigned char *in, uint32_t in_len, unsigned char *out, + uint32_t out_len, uint32_t *avail_in, uint32_t *avail_out) { + ScrBrotli *b = state; + size_t in_left = in_len, out_left = out_len; + const uint8_t *next_in = in; + uint8_t *next_out = out; + b->flush = flush; + if (b->encode) { + b->enc_ok = BrotliEncoderCompressStream(b->enc, (BrotliEncoderOperation)flush, &in_left, &next_in, &out_left, + &next_out, NULL) != BROTLI_FALSE; + } else { + b->dec_result = BrotliDecoderDecompressStream(b->dec, &in_left, &next_in, &out_left, &next_out, NULL); + if (b->dec_result == BROTLI_DECODER_RESULT_ERROR) { + b->dec_error = BrotliDecoderGetErrorCode(b->dec); + snprintf(b->dec_code, sizeof b->dec_code, "ERR_%s", BrotliDecoderErrorString(b->dec_error)); + } + } + *avail_in = (uint32_t)in_left; + *avail_out = (uint32_t)out_left; +} + +/* GetErrorInfo. */ +static bool scr_brotli_error(const void *state, ScrZlibError *out) { + const ScrBrotli *b = state; + if (b->encode) { + if (!b->enc_ok) return scr_brotli_fail(out, "Compression failed", "ERR_BROTLI_COMPRESSION_FAILED", -1); + return false; + } + if (b->dec_error != BROTLI_DECODER_NO_ERROR) + return scr_brotli_fail(out, "Decompression failed", b->dec_code, (int)b->dec_error); + /* zlib's answer for a truncated stream; Brotli has no code of its own. */ + if (b->flush == BROTLI_OPERATION_FINISH && b->dec_result == BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT) + return scr_brotli_fail(out, "unexpected end of file", "Z_BUF_ERROR", -5); + return false; +} + +/* ResetStream is Init() without a dictionary: as in Node, the reset + * instance drops the dictionary and the parameters. */ +static bool scr_brotli_reset(void *state, ScrZlibError *out) { + ScrBrotli *b = state; + free(b->dict); + b->dict = NULL; + b->dict_len = 0; + return scr_brotli_init(b, out); +} + +static const ScrZlibCodec scr_brotli_codec = { + scr_brotli_work, + scr_brotli_error, + scr_brotli_reset, + scr_brotli_free, +}; + +/* ── lib/zlib.js Brotli() ──────────────────────────────────────────── */ + +static const ScrDyn *scr_brotli_opt(const ScrDyn *opts, const char *key) { + if (opts == NULL || opts->kind != SCR_DYN_OBJ) return NULL; + return scr_dyn_obj_get((ScrDyn *)opts, key, strlen(key)); +} + +/* Uint32Array element assignment: ToUint32 of a number or boolean. */ +static uint32_t scr_brotli_uint32(const ScrDyn *v) { + if (v->kind == SCR_DYN_BOOL) return v->v.b ? 1 : 0; + double d = v->v.num; + if (!isfinite(d)) return 0; + double m = fmod(trunc(d), 4294967296.0); + if (m < 0) m += 4294967296.0; + return (uint32_t)m; +} + +static void scr_brotli_invalid_param(const ScrStr *key) { + char message[160]; + int n = snprintf(message, sizeof message, "%.*s is not a valid Brotli parameter", (int)key->len, key->data); + scr_throw_error_msg_code(SCR_ERR_RANGE, message, (size_t)n, "ERR_BROTLI_INVALID_PARAM"); +} + +/* opts.params: each own key must name a parameter (0..8) once, and each + * value must be a number or boolean. */ +static bool scr_brotli_params(const ScrDyn *params, uint32_t values[SCR_BROTLI_PARAMS]) { + for (size_t i = 0; i < SCR_BROTLI_PARAMS; i++) values[i] = SCR_BROTLI_UNSET; + if (params == NULL || !scr_dyn_truthy(params)) return true; + ScrDyn *view = params->kind == SCR_DYN_TYPED_REF ? scr_dyn_typed_ref_materialize(params) : NULL; + if (scr_exc_pending()) return false; + const ScrDyn *p = view ? view : params; + if (p->kind == SCR_DYN_STR) { + /* Object.keys of a string names its indices; the first value is a + * one-character string, which the type check rejects. */ + ScrStr *first = scr_str_new(p->v.str->data, 1); + ScrDyn *value = scr_dyn_new_str(first); + scr_str_release(first); + scr_dyn_prop_type_fail("options.params[key]", "of type number", value); + scr_dyn_release(value); + scr_dyn_release(view); + return false; + } + if (p->kind != SCR_DYN_OBJ && p->kind != SCR_DYN_ARR) { + scr_dyn_release(view); + return true; + } + ScrDyn *keys = scr_dyn_own_keys(p); + bool ok = keys != NULL; + size_t count = ok && keys->kind == SCR_DYN_ARR ? keys->v.arr.len : 0; + for (size_t i = 0; ok && i < count; i++) { + const ScrDyn *key = keys->v.arr.items[i]; + if (key->kind != SCR_DYN_STR) continue; + double index = NAN; + if (!scr_dyn_number_coerce_js(key, &index)) { + ok = false; + break; + } + if (isnan(index) || index < 0 || index > SCR_BROTLI_PARAMS - 1 || trunc(index) != index || + values[(int)index] != SCR_BROTLI_UNSET) { + scr_brotli_invalid_param(key->v.str); + ok = false; + break; + } + ScrDyn *value = scr_dyn_obj_read(p, key->v.str->data, key->v.str->len); + if (!value) { + ok = false; + break; + } + if (value->kind != SCR_DYN_NUM && value->kind != SCR_DYN_BOOL) { + scr_dyn_prop_type_fail("options.params[key]", "of type number", value); + scr_dyn_release(value); + ok = false; + break; + } + values[(int)index] = scr_brotli_uint32(value); + scr_dyn_release(value); + } + scr_dyn_release(keys); + scr_dyn_release(view); + return ok; +} + +/* opts.dictionary: an ArrayBufferView, or an ArrayBuffer read as a Buffer. + * A copy (or NULL for none) in *dict. */ +static bool scr_brotli_dictionary(const ScrDyn *d, unsigned char **dict, size_t *dict_len) { + *dict = NULL; + *dict_len = 0; + if (d == NULL || d->kind == SCR_DYN_UNDEF) return true; + ScrBytes *bytes = NULL; + if (d->kind == SCR_DYN_BYTES) { + bytes = scr_bytes_raw_view(d->v.bytes); + } else if (scr_buffer_storage_is(d)) { + bytes = scr_array_buffer_view(SCR_BYTES_U8, (ScrDyn *)d, scr_dyn_undefined(), scr_dyn_undefined()); + if (!bytes) return false; + } else { + scr_dyn_prop_type_fail("options.dictionary", "an instance of Buffer, TypedArray, DataView, or ArrayBuffer", d); + return false; + } + if (bytes->len) { + *dict = malloc(bytes->len); + if (!*dict) scr_brotli_oom(); + memcpy(*dict, bytes->data, bytes->len); + *dict_len = bytes->len; + } + scr_bytes_release(bytes); + return true; +} + +static void scr_brotli_init_failed(void) { + static const char message[] = "Initialization failed"; + scr_throw_error_msg_code(SCR_ERR_ERROR, message, sizeof message - 1, "ERR_ZLIB_INITIALIZATION_FAILED"); +} + +static bool scr_brotli_options_object(int mode, const ScrDyn *opts, ScrZlibOptions *out) { + memset(out, 0, sizeof *out); + out->chunk_size = 16384; + out->flush = BROTLI_OPERATION_PROCESS; + out->finish_flush = BROTLI_OPERATION_FINISH; + out->max_output = 9007199254740991.0; + uint32_t params[SCR_BROTLI_PARAMS]; + if (!scr_brotli_params(scr_brotli_opt(opts, "params"), params)) return false; + unsigned char *dict; + size_t dict_len; + if (!scr_brotli_dictionary(scr_brotli_opt(opts, "dictionary"), &dict, &dict_len)) return false; + ScrBrotli *b = calloc(1, sizeof *b); + if (!b) scr_brotli_oom(); + b->encode = mode == SCR_BROTLI_ENCODE; + b->dict = dict; + b->dict_len = dict_len; + ScrZlibError err; + bool failed = scr_brotli_init(b, &err); + for (int i = 0; !failed && i < SCR_BROTLI_PARAMS; i++) { + if (params[i] == SCR_BROTLI_UNSET) continue; + failed = b->encode ? !BrotliEncoderSetParameter(b->enc, (BrotliEncoderParameter)i, params[i]) + : !BrotliDecoderSetParameter(b->dec, (BrotliDecoderParameter)i, params[i]); + } + if (failed) { + scr_brotli_free(b); + scr_brotli_init_failed(); + return false; + } + out->codec_state = b; + out->codec_state_free = scr_brotli_free; + /* ZlibBase's `if (opts)`: a falsy value reads no more options. */ + if (opts == NULL || !scr_dyn_truthy(opts)) return true; + return scr_zlib_base_options(opts, BROTLI_OPERATION_EMIT_METADATA, out); +} + +/* A typed options object is read through its materialized view. */ +static bool scr_brotli_options(int mode, const ScrDyn *opts, ScrZlibOptions *out) { + if (opts == NULL || opts->kind != SCR_DYN_TYPED_REF) return scr_brotli_options_object(mode, opts, out); + ScrDyn *view = scr_dyn_typed_ref_materialize(opts); + bool ok = false; + if (scr_exc_pending()) memset(out, 0, sizeof *out); + else ok = scr_brotli_options_object(mode, view, out); + scr_dyn_release(view); + return ok; +} + +/* Moves the prepared instance out of the options. */ +static ScrZlibEngine *scr_brotli_engine(int mode, ScrZlibOptions *o) { + ScrBrotli *b = o->codec_state; + o->codec_state = NULL; + return scr_zlib_engine_codec(mode, &scr_brotli_codec, b, o->reject_garbage); +} + +static const ScrZlibBrotliHooks scr_brotli_hooks = {scr_brotli_options, scr_brotli_engine}; + +void scr_brotli_install(void) { + scr_zlib_brotli_hooks = &scr_brotli_hooks; +} diff --git a/packages/runtime/src/scr_zlib.c b/packages/runtime/src/scr_zlib.c index ff09e7ea1..8756c3d17 100644 --- a/packages/runtime/src/scr_zlib.c +++ b/packages/runtime/src/scr_zlib.c @@ -133,6 +133,11 @@ bool scr_zlib_inflate_exact(const unsigned char *src, size_t src_len, * Modes are Node's node_zlib_mode numbers (DEFLATE 1 ... UNZIP 7). */ struct ScrZlibEngine { z_stream strm; + /* Another codec's engine (scr_zlib_engine_codec): its state answers the + * entries below, which skip the z_stream. */ + const ScrZlibCodec *codec; + void *codec_state; + uint32_t codec_avail_in, codec_avail_out; int mode; int level, window_bits, mem_level, strategy; int flush; @@ -172,6 +177,17 @@ ScrZlibEngine *scr_zlib_engine_new(int mode, int level, int window_bits, int mem return e; } +ScrZlibEngine *scr_zlib_engine_codec(int mode, const ScrZlibCodec *codec, void *state, + bool reject_garbage) { + ScrZlibEngine *e = calloc(1, sizeof *e); + if (!e) scr_zlib_oom(); + e->mode = mode; + e->codec = codec; + e->codec_state = state; + e->reject_garbage = reject_garbage; + return e; +} + static bool scr_zlib_engine_deflating(const ScrZlibEngine *e) { return e->mode == SCR_Z_DEFLATE || e->mode == SCR_Z_GZIP || e->mode == SCR_Z_DEFLATERAW; } @@ -229,6 +245,11 @@ static int scr_zlib_engine_reset_stream(ScrZlibEngine *e) { void scr_zlib_engine_work(ScrZlibEngine *e, int flush, const unsigned char *in, uint32_t in_len, unsigned char *out, uint32_t out_len) { + if (e->codec) { + e->codec->work(e->codec_state, flush, in, in_len, out, out_len, &e->codec_avail_in, + &e->codec_avail_out); + return; + } e->strm.avail_in = in_len; e->strm.next_in = (Bytef *)(uintptr_t)in; e->strm.avail_out = out_len; @@ -286,6 +307,11 @@ void scr_zlib_engine_work(ScrZlibEngine *e, int flush, const unsigned char *in, } void scr_zlib_engine_offsets(const ScrZlibEngine *e, uint32_t *avail_in, uint32_t *avail_out) { + if (e->codec) { + *avail_in = e->codec_avail_in; + *avail_out = e->codec_avail_out; + return; + } *avail_in = e->strm.avail_in; *avail_out = e->strm.avail_out; } @@ -313,6 +339,7 @@ static bool scr_zlib_engine_fail(const ScrZlibEngine *e, const char *message, Sc } bool scr_zlib_engine_error(const ScrZlibEngine *e, ScrZlibError *out) { + if (e->codec) return e->codec->error(e->codec_state, out); switch (e->err) { case Z_OK: case Z_BUF_ERROR: @@ -327,6 +354,7 @@ bool scr_zlib_engine_error(const ScrZlibEngine *e, ScrZlibError *out) { } bool scr_zlib_engine_reset(ScrZlibEngine *e, ScrZlibError *out) { + if (e->codec) return e->codec->reset(e->codec_state, out); switch (scr_zlib_engine_reset_stream(e)) { case 0: return false; case 1: return scr_zlib_engine_fail(e, "Failed to init stream before reset", out); @@ -338,6 +366,7 @@ bool scr_zlib_engine_reset(ScrZlibEngine *e, ScrZlibError *out) { /* SetParams: deflateParams for DEFLATE and DEFLATERAW only (Node's * switch leaves GZIP's level and strategy unchanged). */ bool scr_zlib_engine_params(ScrZlibEngine *e, int level, int strategy, ScrZlibError *out) { + if (e->codec) return false; /* Node's Brotli streams have no params() */ if (scr_zlib_engine_init(e) && e->err != Z_OK) return scr_zlib_engine_fail(e, "Failed to init stream before set parameters", out); e->err = Z_OK; @@ -350,6 +379,11 @@ bool scr_zlib_engine_params(ScrZlibEngine *e, int level, int strategy, ScrZlibEr void scr_zlib_engine_free(ScrZlibEngine *e) { if (!e) return; + if (e->codec) { + e->codec->free(e->codec_state); + free(e); + return; + } if (e->init_done) { if (scr_zlib_engine_deflating(e)) deflateEnd(&e->strm); else inflateEnd(&e->strm); @@ -418,6 +452,15 @@ static bool scr_zlib_is_null(const ScrDyn *v) { void scr_zlib_options_drop(ScrZlibOptions *o) { if (o->dict) scr_bytes_release(o->dict); o->dict = NULL; + if (o->codec_state) o->codec_state_free(o->codec_state); + o->codec_state = NULL; +} + +const ScrZlibBrotliHooks *scr_zlib_brotli_hooks = NULL; + +/* Node's BROTLI_DECODE and BROTLI_ENCODE modes. */ +static bool scr_zlib_brotli_mode(int mode) { + return mode == 8 || mode == 9; } static bool scr_zlib_options_parse_object(int mode, const ScrDyn *opts, ScrZlibOptions *out); @@ -426,6 +469,10 @@ static bool scr_zlib_options_parse_object(int mode, const ScrDyn *opts, ScrZlibO * slot by reference) is read through its materialized view, as a plain * object is. */ bool scr_zlib_options_parse(int mode, const ScrDyn *opts, ScrZlibOptions *out) { + if (scr_zlib_brotli_mode(mode)) { + if (!scr_zlib_brotli_hooks) scr_trap("scriptc: the Brotli codec is not linked\n"); + return scr_zlib_brotli_hooks->options(mode, opts, out); + } if (opts == NULL || opts->kind != SCR_DYN_TYPED_REF) return scr_zlib_options_parse_object(mode, opts, out); ScrDyn *view = scr_dyn_typed_ref_materialize(opts); bool ok = false; @@ -475,6 +522,10 @@ static bool scr_zlib_options_parse_object(int mode, const ScrDyn *opts, ScrZlibO } out->dict = scr_bytes_raw_view(d->v.bytes); } + return scr_zlib_base_options(o, 5, out); +} + +bool scr_zlib_base_options(const ScrDyn *o, double flush_max, ScrZlibOptions *out) { const ScrDyn *rg = scr_zlib_opt(o, "rejectGarbageAfterEnd"); out->reject_garbage = rg != NULL && rg->kind == SCR_DYN_BOOL && rg->v.b; const ScrDyn *cs = scr_zlib_opt(o, "chunkSize"); @@ -488,10 +539,10 @@ static bool scr_zlib_options_parse_object(int mode, const ScrDyn *opts, ScrZlibO } } if (!ok || - !scr_zlib_check_range(scr_zlib_opt(o, "flush"), "options.flush", true, 0, 5, Z_NO_FLUSH, - &out->flush) || - !scr_zlib_check_range(scr_zlib_opt(o, "finishFlush"), "options.finishFlush", true, 0, 5, - Z_FINISH, &out->finish_flush) || + !scr_zlib_check_range(scr_zlib_opt(o, "flush"), "options.flush", true, 0, flush_max, + out->flush, &out->flush) || + !scr_zlib_check_range(scr_zlib_opt(o, "finishFlush"), "options.finishFlush", true, 0, + flush_max, out->finish_flush, &out->finish_flush) || !scr_zlib_check_range(scr_zlib_opt(o, "maxOutputLength"), "options.maxOutputLength", true, 1, 9007199254740991.0, 9007199254740991.0, &out->max_output)) { scr_zlib_options_drop(out); @@ -513,7 +564,8 @@ static bool scr_zlib_options_parse_object(int mode, const ScrDyn *opts, ScrZlibO return true; } -ScrZlibEngine *scr_zlib_engine_from_options(int mode, const ScrZlibOptions *o) { +ScrZlibEngine *scr_zlib_engine_from_options(int mode, ScrZlibOptions *o) { + if (scr_zlib_brotli_mode(mode)) return scr_zlib_brotli_hooks->engine(mode, o); return scr_zlib_engine_new(mode, (int)o->level, (int)o->window_bits, (int)o->mem_level, (int)o->strategy, o->dict ? o->dict->data : NULL, o->dict ? o->dict->len : 0, o->reject_garbage); diff --git a/packages/runtime/src/scr_zlib.h b/packages/runtime/src/scr_zlib.h index 124e157ab..d34b81424 100644 --- a/packages/runtime/src/scr_zlib.h +++ b/packages/runtime/src/scr_zlib.h @@ -42,6 +42,19 @@ bool scr_zlib_engine_error(const ScrZlibEngine *e, ScrZlibError *out); bool scr_zlib_engine_reset(ScrZlibEngine *e, ScrZlibError *out); bool scr_zlib_engine_params(ScrZlibEngine *e, int level, int strategy, ScrZlibError *out); void scr_zlib_engine_free(ScrZlibEngine *e); +/* Another codec behind the same engine (Brotli, scr_brotli.c): the engine + * entries above call these on its state. work runs on a worker thread and + * reports the unused input and output; error and reset fill *out as the + * zlib entries do. free releases the state. */ +typedef struct { + void (*work)(void *state, int flush, const unsigned char *in, uint32_t in_len, unsigned char *out, + uint32_t out_len, uint32_t *avail_in, uint32_t *avail_out); + bool (*error)(const void *state, ScrZlibError *out); + bool (*reset)(void *state, ScrZlibError *out); + void (*free)(void *state); +} ScrZlibCodec; +ScrZlibEngine *scr_zlib_engine_codec(int mode, const ScrZlibCodec *codec, void *state /* moves */, + bool reject_garbage); /* Node's Zlib() and ZlibBase() option ladder, shared by the stream classes * and the one-shot forms with options: false with Node's error pending. * `dict` is a +1 view (or NULL) that scr_zlib_options_drop releases. @@ -52,12 +65,32 @@ typedef struct { ScrBytes *dict; bool reject_garbage, info; double chunk_size, flush, finish_flush, max_output; + /* Another codec's prepared state (a Brotli instance with its parameters + * set), which scr_zlib_engine_from_options moves into the engine and + * scr_zlib_options_drop frees otherwise. */ + void *codec_state; + void (*codec_state_free)(void *state); } ScrZlibOptions; bool scr_zlib_options_parse(int mode, const ScrDyn *opts, ScrZlibOptions *out); void scr_zlib_options_drop(ScrZlibOptions *o); +/* ZlibBase's reads over a truthy options object, after the codec's own: + * chunkSize, flush and finishFlush (within 0..flush_max), maxOutputLength, + * rejectGarbageAfterEnd and info. False with Node's error pending, *out + * dropped. */ +bool scr_zlib_base_options(const ScrDyn *opts, double flush_max, ScrZlibOptions *out); +/* Brotli's option ladder and engine (scr_brotli.c), installed when the + * program uses Brotli: scr_zlib_options_parse and + * scr_zlib_engine_from_options call them for Node's BROTLI_DECODE (8) and + * BROTLI_ENCODE (9) modes. */ +typedef struct { + bool (*options)(int mode, const ScrDyn *opts, ScrZlibOptions *out); + ScrZlibEngine *(*engine)(int mode, ScrZlibOptions *o); +} ScrZlibBrotliHooks; +extern const ScrZlibBrotliHooks *scr_zlib_brotli_hooks; +void scr_brotli_install(void); bool scr_zlib_check_range(const ScrDyn *v, const char *name, bool prop, double lower, double upper, double def, double *out); -ScrZlibEngine *scr_zlib_engine_from_options(int mode, const ScrZlibOptions *o); +ScrZlibEngine *scr_zlib_engine_from_options(int mode, ScrZlibOptions *o); ScrError *scr_zlib_error_new(const ScrZlibError *ze); /* +1 */ /* deflateSync(data, options) and the other one-shot forms with an options * value (undefined for none): Node's processChunkSync over the engine, diff --git a/packages/runtime/src/scr_zlib_stream.c b/packages/runtime/src/scr_zlib_stream.c index e2dcf27f5..8b932a63a 100644 --- a/packages/runtime/src/scr_zlib_stream.c +++ b/packages/runtime/src/scr_zlib_stream.c @@ -433,6 +433,8 @@ static const char *scr_zs_class_name(int mode) { case SCR_ZM_GUNZIP: return "Gunzip"; case SCR_ZM_DEFLATERAW: return "DeflateRaw"; case SCR_ZM_INFLATERAW: return "InflateRaw"; + case 8: return "BrotliDecompress"; + case 9: return "BrotliCompress"; default: return "Unzip"; } } @@ -478,7 +480,8 @@ ScrStream *scr_zlib_stream_new(double mode_d, ScrDyn *opts) { if (!zs->out_buf) scr_zlib_stream_oom(); zs->default_flush = (int)zo.flush; zs->finish_flush = (int)zo.finish_flush; - zs->full_flush = SCR_ZF_FULL; + /* Brotli's full flush is BROTLI_OPERATION_FLUSH (brotliDefaultOpts). */ + zs->full_flush = mode == 8 || mode == 9 ? 1 : SCR_ZF_FULL; zs->level = zo.level; zs->strategy = zo.strategy; zs->reject_garbage = zo.reject_garbage; diff --git a/packages/runtime/vendor/README.md b/packages/runtime/vendor/README.md index 7ab8cf6b0..5f75b683b 100644 --- a/packages/runtime/vendor/README.md +++ b/packages/runtime/vendor/README.md @@ -39,6 +39,16 @@ The CROSS-target arm of node:zlib (see packages/runtime/src/scr_zlib.c): host bu The objects build lazily on the first zlib-using cross compile into the per-user build cache's `vendor/zlib----/` directory — one flavor per driver/target and compiler environment/identity (the lre-objects pattern). Zlib-free binaries never compile any of this; compressed OUTPUT bytes are zlib-version-dependent, which is why the corpus only compares round-trips and fixed-blob inflation. +## brotli/ + +- Project: https://github.com/google/brotli +- Version: 1.2.0 (release tarball brotli-1.2.0.tar.gz, sha256 816c96e8e8f193b40151dad7e8ff37b1221d019dbcb9c35cd3fadbfe6477dfec), the version Node v24.22.0 bundles (`process.versions.brotli`) +- License: MIT (see brotli/LICENSE) + +The codec behind node:zlib's Brotli functions and streams (see packages/runtime/src/scr_brotli.c). Only `c/common`, `c/dec`, `c/enc` and `c/include` are vendored, in upstream's layout (LICENSE beside `c/`); the C++ lazy static initializer (`c/enc/static_init_lazy.cc`), the tools, tests, bindings and build machinery are not. No vendored file is modified, and the files match the copy Node bundles in `deps/brotli`. Because the version is Node's, compressed bytes match Node's for the same parameters, so the corpus compares compressed output as well as round trips. To update, re-fetch the release tarball, copy the same directories, and bump `BROTLI_VERSION` in vendor-inputs.ts. + +The `dec/` and `enc/` directories share file names (`static_init.c`, `state.h`, `prefix.h`), so archive members are named after their directory (`dec-static_init.o`). Brotli-free binaries compile and link none of it. + ## mbedtls/ - Project: https://github.com/Mbed-TLS/mbedtls diff --git a/packages/runtime/vendor/brotli/LICENSE b/packages/runtime/vendor/brotli/LICENSE new file mode 100644 index 000000000..33b7cdd2d --- /dev/null +++ b/packages/runtime/vendor/brotli/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2009, 2010, 2013-2016 by the Brotli Authors. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/packages/runtime/vendor/brotli/c/common/constants.c b/packages/runtime/vendor/brotli/c/common/constants.c new file mode 100644 index 000000000..ef5a2e2e0 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/common/constants.c @@ -0,0 +1,15 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#include "constants.h" + +const BROTLI_MODEL("small") +BrotliPrefixCodeRange _kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS] = { + {1, 2}, {5, 2}, {9, 2}, {13, 2}, {17, 3}, {25, 3}, + {33, 3}, {41, 3}, {49, 4}, {65, 4}, {81, 4}, {97, 4}, + {113, 5}, {145, 5}, {177, 5}, {209, 5}, {241, 6}, {305, 6}, + {369, 7}, {497, 8}, {753, 9}, {1265, 10}, {2289, 11}, {4337, 12}, + {8433, 13}, {16625, 24}}; diff --git a/packages/runtime/vendor/brotli/c/common/constants.h b/packages/runtime/vendor/brotli/c/common/constants.h new file mode 100644 index 000000000..85e9802c0 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/common/constants.h @@ -0,0 +1,198 @@ +/* Copyright 2016 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/** + * @file + * Common constants used in decoder and encoder API. + */ + +#ifndef BROTLI_COMMON_CONSTANTS_H_ +#define BROTLI_COMMON_CONSTANTS_H_ + +#include "platform.h" + +/* Specification: 7.3. Encoding of the context map */ +#define BROTLI_CONTEXT_MAP_MAX_RLE 16 + +/* Specification: 2. Compressed representation overview */ +#define BROTLI_MAX_NUMBER_OF_BLOCK_TYPES 256 + +/* Specification: 3.3. Alphabet sizes: insert-and-copy length */ +#define BROTLI_NUM_LITERAL_SYMBOLS 256 +#define BROTLI_NUM_COMMAND_SYMBOLS 704 +#define BROTLI_NUM_BLOCK_LEN_SYMBOLS 26 +#define BROTLI_MAX_CONTEXT_MAP_SYMBOLS (BROTLI_MAX_NUMBER_OF_BLOCK_TYPES + \ + BROTLI_CONTEXT_MAP_MAX_RLE) +#define BROTLI_MAX_BLOCK_TYPE_SYMBOLS (BROTLI_MAX_NUMBER_OF_BLOCK_TYPES + 2) + +/* Specification: 3.5. Complex prefix codes */ +#define BROTLI_REPEAT_PREVIOUS_CODE_LENGTH 16 +#define BROTLI_REPEAT_ZERO_CODE_LENGTH 17 +#define BROTLI_CODE_LENGTH_CODES (BROTLI_REPEAT_ZERO_CODE_LENGTH + 1) +/* "code length of 8 is repeated" */ +#define BROTLI_INITIAL_REPEATED_CODE_LENGTH 8 + +/* "Large Window Brotli" */ + +/** + * The theoretical maximum number of distance bits specified for large window + * brotli, for 64-bit encoders and decoders. Even when in practice 32-bit + * encoders and decoders only support up to 30 max distance bits, the value is + * set to 62 because it affects the large window brotli file format. + * Specifically, it affects the encoding of simple huffman tree for distances, + * see Specification RFC 7932 chapter 3.4. + */ +#define BROTLI_LARGE_MAX_DISTANCE_BITS 62U +#define BROTLI_LARGE_MIN_WBITS 10 +/** + * The maximum supported large brotli window bits by the encoder and decoder. + * Large window brotli allows up to 62 bits, however the current encoder and + * decoder, designed for 32-bit integers, only support up to 30 bits maximum. + */ +#define BROTLI_LARGE_MAX_WBITS 30 + +/* Specification: 4. Encoding of distances */ +#define BROTLI_NUM_DISTANCE_SHORT_CODES 16 +/** + * Maximal number of "postfix" bits. + * + * Number of "postfix" bits is stored as 2 bits in meta-block header. + */ +#define BROTLI_MAX_NPOSTFIX 3 +#define BROTLI_MAX_NDIRECT 120 +#define BROTLI_MAX_DISTANCE_BITS 24U +#define BROTLI_DISTANCE_ALPHABET_SIZE(NPOSTFIX, NDIRECT, MAXNBITS) ( \ + BROTLI_NUM_DISTANCE_SHORT_CODES + (NDIRECT) + \ + ((MAXNBITS) << ((NPOSTFIX) + 1))) +/* BROTLI_NUM_DISTANCE_SYMBOLS == 1128 */ +#define BROTLI_NUM_DISTANCE_SYMBOLS \ + BROTLI_DISTANCE_ALPHABET_SIZE( \ + BROTLI_MAX_NDIRECT, BROTLI_MAX_NPOSTFIX, BROTLI_LARGE_MAX_DISTANCE_BITS) + +/* ((1 << 26) - 4) is the maximal distance that can be expressed in RFC 7932 + brotli stream using NPOSTFIX = 0 and NDIRECT = 0. With other NPOSTFIX and + NDIRECT values distances up to ((1 << 29) + 88) could be expressed. */ +#define BROTLI_MAX_DISTANCE 0x3FFFFFC + +/* ((1 << 31) - 4) is the safe distance limit. Using this number as a limit + allows safe distance calculation without overflows, given the distance + alphabet size is limited to corresponding size + (see kLargeWindowDistanceCodeLimits). */ +#define BROTLI_MAX_ALLOWED_DISTANCE 0x7FFFFFFC + + +/* Specification: 4. Encoding of Literal Insertion Lengths and Copy Lengths */ +#define BROTLI_NUM_INS_COPY_CODES 24 + +/* 7.1. Context modes and context ID lookup for literals */ +/* "context IDs for literals are in the range of 0..63" */ +#define BROTLI_LITERAL_CONTEXT_BITS 6 + +/* 7.2. Context ID for distances */ +#define BROTLI_DISTANCE_CONTEXT_BITS 2 + +/* 9.1. Format of the Stream Header */ +/* Number of slack bytes for window size. Don't confuse + with BROTLI_NUM_DISTANCE_SHORT_CODES. */ +#define BROTLI_WINDOW_GAP 16 +#define BROTLI_MAX_BACKWARD_LIMIT(W) (((size_t)1 << (W)) - BROTLI_WINDOW_GAP) + +typedef struct BrotliDistanceCodeLimit { + uint32_t max_alphabet_size; + uint32_t max_distance; +} BrotliDistanceCodeLimit; + +/* This function calculates maximal size of distance alphabet, such that the + distances greater than the given values can not be represented. + + This limits are designed to support fast and safe 32-bit decoders. + "32-bit" means that signed integer values up to ((1 << 31) - 1) could be + safely expressed. + + Brotli distance alphabet symbols do not represent consecutive distance + ranges. Each distance alphabet symbol (excluding direct distances and short + codes), represent interleaved (for NPOSTFIX > 0) range of distances. + A "group" of consecutive (1 << NPOSTFIX) symbols represent non-interleaved + range. Two consecutive groups require the same amount of "extra bits". + + It is important that distance alphabet represents complete "groups". + To avoid complex logic on encoder side about interleaved ranges + it was decided to restrict both sides to complete distance code "groups". + */ +BROTLI_UNUSED_FUNCTION BrotliDistanceCodeLimit BrotliCalculateDistanceCodeLimit( + uint32_t max_distance, uint32_t npostfix, uint32_t ndirect) { + BrotliDistanceCodeLimit result; + /* Marking this function as unused, because not all files + including "constants.h" use it -> compiler warns about that. */ + BROTLI_UNUSED(&BrotliCalculateDistanceCodeLimit); + if (max_distance <= ndirect) { + /* This case never happens / exists only for the sake of completeness. */ + result.max_alphabet_size = max_distance + BROTLI_NUM_DISTANCE_SHORT_CODES; + result.max_distance = max_distance; + return result; + } else { + /* The first prohibited value. */ + uint32_t forbidden_distance = max_distance + 1; + /* Subtract "directly" encoded region. */ + uint32_t offset = forbidden_distance - ndirect - 1; + uint32_t ndistbits = 0; + uint32_t tmp; + uint32_t half; + uint32_t group; + /* Postfix for the last dcode in the group. */ + uint32_t postfix = (1u << npostfix) - 1; + uint32_t extra; + uint32_t start; + /* Remove postfix and "head-start". */ + offset = (offset >> npostfix) + 4; + /* Calculate the number of distance bits. */ + tmp = offset / 2; + /* Poor-man's log2floor, to avoid extra dependencies. */ + while (tmp != 0) {ndistbits++; tmp = tmp >> 1;} + /* One bit is covered with subrange addressing ("half"). */ + ndistbits--; + /* Find subrange. */ + half = (offset >> ndistbits) & 1; + /* Calculate the "group" part of dcode. */ + group = ((ndistbits - 1) << 1) | half; + /* Calculated "group" covers the prohibited distance value. */ + if (group == 0) { + /* This case is added for correctness; does not occur for limit > 128. */ + result.max_alphabet_size = ndirect + BROTLI_NUM_DISTANCE_SHORT_CODES; + result.max_distance = ndirect; + return result; + } + /* Decrement "group", so it is the last permitted "group". */ + group--; + /* After group was decremented, ndistbits and half must be recalculated. */ + ndistbits = (group >> 1) + 1; + /* The last available distance in the subrange has all extra bits set. */ + extra = (1u << ndistbits) - 1; + /* Calculate region start. NB: ndistbits >= 1. */ + start = (1u << (ndistbits + 1)) - 4; + /* Move to subregion. */ + start += (group & 1) << ndistbits; + /* Calculate the alphabet size. */ + result.max_alphabet_size = ((group << npostfix) | postfix) + ndirect + + BROTLI_NUM_DISTANCE_SHORT_CODES + 1; + /* Calculate the maximal distance representable by alphabet. */ + result.max_distance = ((start + extra) << npostfix) + postfix + ndirect + 1; + return result; + } +} + +/* Represents the range of values belonging to a prefix code: + [offset, offset + 2^nbits) */ +typedef struct { + uint16_t offset; + uint8_t nbits; +} BrotliPrefixCodeRange; + +/* "Soft-private", it is exported, but not "advertised" as API. */ +BROTLI_COMMON_API extern const BROTLI_MODEL("small") +BrotliPrefixCodeRange _kBrotliPrefixCodeRanges[BROTLI_NUM_BLOCK_LEN_SYMBOLS]; + +#endif /* BROTLI_COMMON_CONSTANTS_H_ */ diff --git a/packages/runtime/vendor/brotli/c/common/context.c b/packages/runtime/vendor/brotli/c/common/context.c new file mode 100644 index 000000000..d3c910cb1 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/common/context.c @@ -0,0 +1,156 @@ +#include "context.h" + +#include "platform.h" + +/* Common context lookup table for all context modes. */ +const BROTLI_MODEL("small") uint8_t _kBrotliContextLookupTable[2048] = { + /* CONTEXT_LSB6, last byte. */ + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + + /* CONTEXT_LSB6, second last byte, */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /* CONTEXT_MSB6, last byte. */ + 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, + 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, + 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, + 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, + 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, + 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, + 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27, + 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31, + 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35, + 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39, + 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43, + 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47, + 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51, 51, + 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55, 55, + 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59, 59, + 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63, 63, + + /* CONTEXT_MSB6, second last byte, */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + + /* CONTEXT_UTF8, last byte. */ + /* ASCII range. */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 0, 0, 4, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 8, 12, 16, 12, 12, 20, 12, 16, 24, 28, 12, 12, 32, 12, 36, 12, + 44, 44, 44, 44, 44, 44, 44, 44, 44, 44, 32, 32, 24, 40, 28, 12, + 12, 48, 52, 52, 52, 48, 52, 52, 52, 48, 52, 52, 52, 52, 52, 48, + 52, 52, 52, 52, 52, 48, 52, 52, 52, 52, 52, 24, 12, 28, 12, 12, + 12, 56, 60, 60, 60, 56, 60, 60, 60, 56, 60, 60, 60, 60, 60, 56, + 60, 60, 60, 60, 60, 56, 60, 60, 60, 60, 60, 24, 12, 28, 12, 0, + /* UTF8 continuation byte range. */ + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + /* UTF8 lead byte range. */ + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, 2, 3, + + /* CONTEXT_UTF8 second last byte. */ + /* ASCII range. */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, 1, + 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 1, 1, 1, 1, + 1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 0, + /* UTF8 continuation byte range. */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + /* UTF8 lead byte range. */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + + /* CONTEXT_SIGNED, last byte, same as the above values shifted by 3 bits. */ + 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, + 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 48, 56, + + /* CONTEXT_SIGNED, second last byte. */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, +}; diff --git a/packages/runtime/vendor/brotli/c/common/context.h b/packages/runtime/vendor/brotli/c/common/context.h new file mode 100644 index 000000000..45b57d8c3 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/common/context.h @@ -0,0 +1,112 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Lookup table to map the previous two bytes to a context id. + + There are four different context modeling modes defined here: + CONTEXT_LSB6: context id is the least significant 6 bits of the last byte, + CONTEXT_MSB6: context id is the most significant 6 bits of the last byte, + CONTEXT_UTF8: second-order context model tuned for UTF8-encoded text, + CONTEXT_SIGNED: second-order context model tuned for signed integers. + + If |p1| and |p2| are the previous two bytes, and |mode| is current context + mode, we calculate the context as: + + context = ContextLut(mode)[p1] | ContextLut(mode)[p2 + 256]. + + For CONTEXT_UTF8 mode, if the previous two bytes are ASCII characters + (i.e. < 128), this will be equivalent to + + context = 4 * context1(p1) + context2(p2), + + where context1 is based on the previous byte in the following way: + + 0 : non-ASCII control + 1 : \t, \n, \r + 2 : space + 3 : other punctuation + 4 : " ' + 5 : % + 6 : ( < [ { + 7 : ) > ] } + 8 : , ; : + 9 : . + 10 : = + 11 : number + 12 : upper-case vowel + 13 : upper-case consonant + 14 : lower-case vowel + 15 : lower-case consonant + + and context2 is based on the second last byte: + + 0 : control, space + 1 : punctuation + 2 : upper-case letter, number + 3 : lower-case letter + + If the last byte is ASCII, and the second last byte is not (in a valid UTF8 + stream it will be a continuation byte, value between 128 and 191), the + context is the same as if the second last byte was an ASCII control or space. + + If the last byte is a UTF8 lead byte (value >= 192), then the next byte will + be a continuation byte and the context id is 2 or 3 depending on the LSB of + the last byte and to a lesser extent on the second last byte if it is ASCII. + + If the last byte is a UTF8 continuation byte, the second last byte can be: + - continuation byte: the next byte is probably ASCII or lead byte (assuming + 4-byte UTF8 characters are rare) and the context id is 0 or 1. + - lead byte (192 - 207): next byte is ASCII or lead byte, context is 0 or 1 + - lead byte (208 - 255): next byte is continuation byte, context is 2 or 3 + + The possible value combinations of the previous two bytes, the range of + context ids and the type of the next byte is summarized in the table below: + + |--------\-----------------------------------------------------------------| + | \ Last byte | + | Second \---------------------------------------------------------------| + | last byte \ ASCII | cont. byte | lead byte | + | \ (0-127) | (128-191) | (192-) | + |=============|===================|=====================|==================| + | ASCII | next: ASCII/lead | not valid | next: cont. | + | (0-127) | context: 4 - 63 | | context: 2 - 3 | + |-------------|-------------------|---------------------|------------------| + | cont. byte | next: ASCII/lead | next: ASCII/lead | next: cont. | + | (128-191) | context: 4 - 63 | context: 0 - 1 | context: 2 - 3 | + |-------------|-------------------|---------------------|------------------| + | lead byte | not valid | next: ASCII/lead | not valid | + | (192-207) | | context: 0 - 1 | | + |-------------|-------------------|---------------------|------------------| + | lead byte | not valid | next: cont. | not valid | + | (208-) | | context: 2 - 3 | | + |-------------|-------------------|---------------------|------------------| +*/ + +#ifndef BROTLI_COMMON_CONTEXT_H_ +#define BROTLI_COMMON_CONTEXT_H_ + +#include "platform.h" + +typedef enum ContextType { + CONTEXT_LSB6 = 0, + CONTEXT_MSB6 = 1, + CONTEXT_UTF8 = 2, + CONTEXT_SIGNED = 3 +} ContextType; + +/* "Soft-private", it is exported, but not "advertised" as API. */ +/* Common context lookup table for all context modes. */ +BROTLI_COMMON_API extern const uint8_t _kBrotliContextLookupTable[2048]; + +typedef const uint8_t* ContextLut; + +/* typeof(MODE) == ContextType; returns ContextLut */ +#define BROTLI_CONTEXT_LUT(MODE) (&_kBrotliContextLookupTable[(MODE) << 9]) + +/* typeof(LUT) == ContextLut */ +#define BROTLI_CONTEXT(P1, P2, LUT) ((LUT)[P1] | ((LUT) + 256)[P2]) + +#endif /* BROTLI_COMMON_CONTEXT_H_ */ diff --git a/packages/runtime/vendor/brotli/c/common/dictionary.c b/packages/runtime/vendor/brotli/c/common/dictionary.c new file mode 100644 index 000000000..ef43af9bf --- /dev/null +++ b/packages/runtime/vendor/brotli/c/common/dictionary.c @@ -0,0 +1,64 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#include "dictionary.h" +#include "platform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#if !defined(BROTLI_EXTERNAL_DICTIONARY_DATA) +/* Embed kBrotliDictionaryData */ +#include "dictionary_inc.h" +static const BROTLI_MODEL("small") BrotliDictionary kBrotliDictionary = { +#else +static BROTLI_MODEL("small") BrotliDictionary kBrotliDictionary = { +#endif + /* size_bits_by_length */ + { + 0, 0, 0, 0, 10, 10, 11, 11, + 10, 10, 10, 10, 10, 9, 9, 8, + 7, 7, 8, 7, 7, 6, 6, 5, + 5, 0, 0, 0, 0, 0, 0, 0 + }, + + /* offsets_by_length */ + { + 0, 0, 0, 0, 0, 4096, 9216, 21504, + 35840, 44032, 53248, 63488, 74752, 87040, 93696, 100864, + 104704, 106752, 108928, 113536, 115968, 118528, 119872, 121280, + 122016, 122784, 122784, 122784, 122784, 122784, 122784, 122784 + }, + + /* data_size == sizeof(kBrotliDictionaryData) */ + 122784, + + /* data */ +#if defined(BROTLI_EXTERNAL_DICTIONARY_DATA) + NULL +#else + kBrotliDictionaryData +#endif +}; + +const BrotliDictionary* BrotliGetDictionary(void) { + return &kBrotliDictionary; +} + +void BrotliSetDictionaryData(const uint8_t* data) { +#if defined(BROTLI_EXTERNAL_DICTIONARY_DATA) + if (!!data && !kBrotliDictionary.data) { + kBrotliDictionary.data = data; + } +#else + BROTLI_UNUSED(data); // Appease -Werror=unused-parameter +#endif +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/common/dictionary.h b/packages/runtime/vendor/brotli/c/common/dictionary.h new file mode 100644 index 000000000..ed683b0ae --- /dev/null +++ b/packages/runtime/vendor/brotli/c/common/dictionary.h @@ -0,0 +1,63 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Collection of static dictionary words. */ + +#ifndef BROTLI_COMMON_DICTIONARY_H_ +#define BROTLI_COMMON_DICTIONARY_H_ + +#include "platform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +typedef struct BrotliDictionary { + /** + * Number of bits to encode index of dictionary word in a bucket. + * + * Specification: Appendix A. Static Dictionary Data + * + * Words in a dictionary are bucketed by length. + * @c 0 means that there are no words of a given length. + * Dictionary consists of words with length of [4..24] bytes. + * Values at [0..3] and [25..31] indices should not be addressed. + */ + uint8_t size_bits_by_length[32]; + + /* assert(offset[i + 1] == offset[i] + (bits[i] ? (i << bits[i]) : 0)) */ + uint32_t offsets_by_length[32]; + + /* assert(data_size == offsets_by_length[31]) */ + size_t data_size; + + /* Data array is not bound, and should obey to size_bits_by_length values. + Specified size matches default (RFC 7932) dictionary. Its size is + defined by data_size */ + const uint8_t* data; +} BrotliDictionary; + +BROTLI_COMMON_API const BrotliDictionary* BrotliGetDictionary(void); + +/** + * Sets dictionary data. + * + * When dictionary data is already set / present, this method is no-op. + * + * Dictionary data MUST be provided before BrotliGetDictionary is invoked. + * This method is used ONLY in multi-client environment (e.g. C + Java), + * to reduce storage by sharing single dictionary between implementations. + */ +BROTLI_COMMON_API void BrotliSetDictionaryData(const uint8_t* data); + +#define BROTLI_MIN_DICTIONARY_WORD_LENGTH 4 +#define BROTLI_MAX_DICTIONARY_WORD_LENGTH 24 + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_COMMON_DICTIONARY_H_ */ diff --git a/packages/runtime/vendor/brotli/c/common/dictionary_inc.h b/packages/runtime/vendor/brotli/c/common/dictionary_inc.h new file mode 100644 index 000000000..f40a93ecc --- /dev/null +++ b/packages/runtime/vendor/brotli/c/common/dictionary_inc.h @@ -0,0 +1,5847 @@ +static const BROTLI_MODEL("small") uint8_t kBrotliDictionaryData[] = { +116,105,109,101,100,111,119,110,108,105,102,101,108,101,102,116,98,97,99,107,99, +111,100,101,100,97,116,97,115,104,111,119,111,110,108,121,115,105,116,101,99,105 +,116,121,111,112,101,110,106,117,115,116,108,105,107,101,102,114,101,101,119,111 +,114,107,116,101,120,116,121,101,97,114,111,118,101,114,98,111,100,121,108,111, +118,101,102,111,114,109,98,111,111,107,112,108,97,121,108,105,118,101,108,105, +110,101,104,101,108,112,104,111,109,101,115,105,100,101,109,111,114,101,119,111, +114,100,108,111,110,103,116,104,101,109,118,105,101,119,102,105,110,100,112,97, +103,101,100,97,121,115,102,117,108,108,104,101,97,100,116,101,114,109,101,97,99, +104,97,114,101,97,102,114,111,109,116,114,117,101,109,97,114,107,97,98,108,101, +117,112,111,110,104,105,103,104,100,97,116,101,108,97,110,100,110,101,119,115, +101,118,101,110,110,101,120,116,99,97,115,101,98,111,116,104,112,111,115,116,117 +,115,101,100,109,97,100,101,104,97,110,100,104,101,114,101,119,104,97,116,110,97 +,109,101,76,105,110,107,98,108,111,103,115,105,122,101,98,97,115,101,104,101,108 +,100,109,97,107,101,109,97,105,110,117,115,101,114,39,41,32,43,104,111,108,100, +101,110,100,115,119,105,116,104,78,101,119,115,114,101,97,100,119,101,114,101, +115,105,103,110,116,97,107,101,104,97,118,101,103,97,109,101,115,101,101,110,99, +97,108,108,112,97,116,104,119,101,108,108,112,108,117,115,109,101,110,117,102, +105,108,109,112,97,114,116,106,111,105,110,116,104,105,115,108,105,115,116,103, +111,111,100,110,101,101,100,119,97,121,115,119,101,115,116,106,111,98,115,109, +105,110,100,97,108,115,111,108,111,103,111,114,105,99,104,117,115,101,115,108,97 +,115,116,116,101,97,109,97,114,109,121,102,111,111,100,107,105,110,103,119,105, +108,108,101,97,115,116,119,97,114,100,98,101,115,116,102,105,114,101,80,97,103, +101,107,110,111,119,97,119,97,121,46,112,110,103,109,111,118,101,116,104,97,110, +108,111,97,100,103,105,118,101,115,101,108,102,110,111,116,101,109,117,99,104, +102,101,101,100,109,97,110,121,114,111,99,107,105,99,111,110,111,110,99,101,108, +111,111,107,104,105,100,101,100,105,101,100,72,111,109,101,114,117,108,101,104, +111,115,116,97,106,97,120,105,110,102,111,99,108,117,98,108,97,119,115,108,101, +115,115,104,97,108,102,115,111,109,101,115,117,99,104,122,111,110,101,49,48,48, +37,111,110,101,115,99,97,114,101,84,105,109,101,114,97,99,101,98,108,117,101,102 +,111,117,114,119,101,101,107,102,97,99,101,104,111,112,101,103,97,118,101,104,97 +,114,100,108,111,115,116,119,104,101,110,112,97,114,107,107,101,112,116,112,97, +115,115,115,104,105,112,114,111,111,109,72,84,77,76,112,108,97,110,84,121,112, +101,100,111,110,101,115,97,118,101,107,101,101,112,102,108,97,103,108,105,110, +107,115,111,108,100,102,105,118,101,116,111,111,107,114,97,116,101,116,111,119, +110,106,117,109,112,116,104,117,115,100,97,114,107,99,97,114,100,102,105,108,101 +,102,101,97,114,115,116,97,121,107,105,108,108,116,104,97,116,102,97,108,108,97, +117,116,111,101,118,101,114,46,99,111,109,116,97,108,107,115,104,111,112,118,111 +,116,101,100,101,101,112,109,111,100,101,114,101,115,116,116,117,114,110,98,111, +114,110,98,97,110,100,102,101,108,108,114,111,115,101,117,114,108,40,115,107,105 +,110,114,111,108,101,99,111,109,101,97,99,116,115,97,103,101,115,109,101,101,116 +,103,111,108,100,46,106,112,103,105,116,101,109,118,97,114,121,102,101,108,116, +116,104,101,110,115,101,110,100,100,114,111,112,86,105,101,119,99,111,112,121,49 +,46,48,34,60,47,97,62,115,116,111,112,101,108,115,101,108,105,101,115,116,111, +117,114,112,97,99,107,46,103,105,102,112,97,115,116,99,115,115,63,103,114,97,121 +,109,101,97,110,38,103,116,59,114,105,100,101,115,104,111,116,108,97,116,101,115 +,97,105,100,114,111,97,100,118,97,114,32,102,101,101,108,106,111,104,110,114,105 +,99,107,112,111,114,116,102,97,115,116,39,85,65,45,100,101,97,100,60,47,98,62, +112,111,111,114,98,105,108,108,116,121,112,101,85,46,83,46,119,111,111,100,109, +117,115,116,50,112,120,59,73,110,102,111,114,97,110,107,119,105,100,101,119,97, +110,116,119,97,108,108,108,101,97,100,91,48,93,59,112,97,117,108,119,97,118,101, +115,117,114,101,36,40,39,35,119,97,105,116,109,97,115,115,97,114,109,115,103,111 +,101,115,103,97,105,110,108,97,110,103,112,97,105,100,33,45,45,32,108,111,99,107 +,117,110,105,116,114,111,111,116,119,97,108,107,102,105,114,109,119,105,102,101, +120,109,108,34,115,111,110,103,116,101,115,116,50,48,112,120,107,105,110,100,114 +,111,119,115,116,111,111,108,102,111,110,116,109,97,105,108,115,97,102,101,115, +116,97,114,109,97,112,115,99,111,114,101,114,97,105,110,102,108,111,119,98,97,98 +,121,115,112,97,110,115,97,121,115,52,112,120,59,54,112,120,59,97,114,116,115, +102,111,111,116,114,101,97,108,119,105,107,105,104,101,97,116,115,116,101,112, +116,114,105,112,111,114,103,47,108,97,107,101,119,101,97,107,116,111,108,100,70, +111,114,109,99,97,115,116,102,97,110,115,98,97,110,107,118,101,114,121,114,117, +110,115,106,117,108,121,116,97,115,107,49,112,120,59,103,111,97,108,103,114,101, +119,115,108,111,119,101,100,103,101,105,100,61,34,115,101,116,115,53,112,120,59, +46,106,115,63,52,48,112,120,105,102,32,40,115,111,111,110,115,101,97,116,110,111 +,110,101,116,117,98,101,122,101,114,111,115,101,110,116,114,101,101,100,102,97, +99,116,105,110,116,111,103,105,102,116,104,97,114,109,49,56,112,120,99,97,109, +101,104,105,108,108,98,111,108,100,122,111,111,109,118,111,105,100,101,97,115, +121,114,105,110,103,102,105,108,108,112,101,97,107,105,110,105,116,99,111,115, +116,51,112,120,59,106,97,99,107,116,97,103,115,98,105,116,115,114,111,108,108, +101,100,105,116,107,110,101,119,110,101,97,114,60,33,45,45,103,114,111,119,74,83 +,79,78,100,117,116,121,78,97,109,101,115,97,108,101,121,111,117,32,108,111,116, +115,112,97,105,110,106,97,122,122,99,111,108,100,101,121,101,115,102,105,115,104 +,119,119,119,46,114,105,115,107,116,97,98,115,112,114,101,118,49,48,112,120,114, +105,115,101,50,53,112,120,66,108,117,101,100,105,110,103,51,48,48,44,98,97,108, +108,102,111,114,100,101,97,114,110,119,105,108,100,98,111,120,46,102,97,105,114, +108,97,99,107,118,101,114,115,112,97,105,114,106,117,110,101,116,101,99,104,105, +102,40,33,112,105,99,107,101,118,105,108,36,40,34,35,119,97,114,109,108,111,114, +100,100,111,101,115,112,117,108,108,44,48,48,48,105,100,101,97,100,114,97,119, +104,117,103,101,115,112,111,116,102,117,110,100,98,117,114,110,104,114,101,102, +99,101,108,108,107,101,121,115,116,105,99,107,104,111,117,114,108,111,115,115, +102,117,101,108,49,50,112,120,115,117,105,116,100,101,97,108,82,83,83,34,97,103, +101,100,103,114,101,121,71,69,84,34,101,97,115,101,97,105,109,115,103,105,114, +108,97,105,100,115,56,112,120,59,110,97,118,121,103,114,105,100,116,105,112,115, +35,57,57,57,119,97,114,115,108,97,100,121,99,97,114,115,41,59,32,125,112,104,112 +,63,104,101,108,108,116,97,108,108,119,104,111,109,122,104,58,229,42,47,13,10,32 +,49,48,48,104,97,108,108,46,10,10,65,55,112,120,59,112,117,115,104,99,104,97,116 +,48,112,120,59,99,114,101,119,42,47,60,47,104,97,115,104,55,53,112,120,102,108, +97,116,114,97,114,101,32,38,38,32,116,101,108,108,99,97,109,112,111,110,116,111, +108,97,105,100,109,105,115,115,115,107,105,112,116,101,110,116,102,105,110,101, +109,97,108,101,103,101,116,115,112,108,111,116,52,48,48,44,13,10,13,10,99,111, +111,108,102,101,101,116,46,112,104,112,60,98,114,62,101,114,105,99,109,111,115, +116,103,117,105,100,98,101,108,108,100,101,115,99,104,97,105,114,109,97,116,104, +97,116,111,109,47,105,109,103,38,35,56,50,108,117,99,107,99,101,110,116,48,48,48 +,59,116,105,110,121,103,111,110,101,104,116,109,108,115,101,108,108,100,114,117, +103,70,82,69,69,110,111,100,101,110,105,99,107,63,105,100,61,108,111,115,101,110 +,117,108,108,118,97,115,116,119,105,110,100,82,83,83,32,119,101,97,114,114,101, +108,121,98,101,101,110,115,97,109,101,100,117,107,101,110,97,115,97,99,97,112, +101,119,105,115,104,103,117,108,102,84,50,51,58,104,105,116,115,115,108,111,116, +103,97,116,101,107,105,99,107,98,108,117,114,116,104,101,121,49,53,112,120,39,39 +,41,59,41,59,34,62,109,115,105,101,119,105,110,115,98,105,114,100,115,111,114, +116,98,101,116,97,115,101,101,107,84,49,56,58,111,114,100,115,116,114,101,101, +109,97,108,108,54,48,112,120,102,97,114,109,226,128,153,115,98,111,121,115,91,48 +,93,46,39,41,59,34,80,79,83,84,98,101,97,114,107,105,100,115,41,59,125,125,109, +97,114,121,116,101,110,100,40,85,75,41,113,117,97,100,122,104,58,230,45,115,105, +122,45,45,45,45,112,114,111,112,39,41,59,13,108,105,102,116,84,49,57,58,118,105, +99,101,97,110,100,121,100,101,98,116,62,82,83,83,112,111,111,108,110,101,99,107, +98,108,111,119,84,49,54,58,100,111,111,114,101,118,97,108,84,49,55,58,108,101, +116,115,102,97,105,108,111,114,97,108,112,111,108,108,110,111,118,97,99,111,108, +115,103,101,110,101,32,226,128,148,115,111,102,116,114,111,109,101,116,105,108, +108,114,111,115,115,60,104,51,62,112,111,117,114,102,97,100,101,112,105,110,107, +60,116,114,62,109,105,110,105,41,124,33,40,109,105,110,101,122,104,58,232,98,97, +114,115,104,101,97,114,48,48,41,59,109,105,108,107,32,45,45,62,105,114,111,110, +102,114,101,100,100,105,115,107,119,101,110,116,115,111,105,108,112,117,116,115, +47,106,115,47,104,111,108,121,84,50,50,58,73,83,66,78,84,50,48,58,97,100,97,109, +115,101,101,115,60,104,50,62,106,115,111,110,39,44,32,39,99,111,110,116,84,50,49 +,58,32,82,83,83,108,111,111,112,97,115,105,97,109,111,111,110,60,47,112,62,115, +111,117,108,76,73,78,69,102,111,114,116,99,97,114,116,84,49,52,58,60,104,49,62, +56,48,112,120,33,45,45,60,57,112,120,59,84,48,52,58,109,105,107,101,58,52,54,90, +110,105,99,101,105,110,99,104,89,111,114,107,114,105,99,101,122,104,58,228,39,41 +,41,59,112,117,114,101,109,97,103,101,112,97,114,97,116,111,110,101,98,111,110, +100,58,51,55,90,95,111,102,95,39,93,41,59,48,48,48,44,122,104,58,231,116,97,110, +107,121,97,114,100,98,111,119,108,98,117,115,104,58,53,54,90,74,97,118,97,51,48, +112,120,10,124,125,10,37,67,51,37,58,51,52,90,106,101,102,102,69,88,80,73,99,97, +115,104,118,105,115,97,103,111,108,102,115,110,111,119,122,104,58,233,113,117, +101,114,46,99,115,115,115,105,99,107,109,101,97,116,109,105,110,46,98,105,110, +100,100,101,108,108,104,105,114,101,112,105,99,115,114,101,110,116,58,51,54,90, +72,84,84,80,45,50,48,49,102,111,116,111,119,111,108,102,69,78,68,32,120,98,111, +120,58,53,52,90,66,79,68,89,100,105,99,107,59,10,125,10,101,120,105,116,58,51,53 +,90,118,97,114,115,98,101,97,116,39,125,41,59,100,105,101,116,57,57,57,59,97,110 +,110,101,125,125,60,47,91,105,93,46,76,97,110,103,107,109,194,178,119,105,114, +101,116,111,121,115,97,100,100,115,115,101,97,108,97,108,101,120,59,10,9,125,101 +,99,104,111,110,105,110,101,46,111,114,103,48,48,53,41,116,111,110,121,106,101, +119,115,115,97,110,100,108,101,103,115,114,111,111,102,48,48,48,41,32,50,48,48, +119,105,110,101,103,101,97,114,100,111,103,115,98,111,111,116,103,97,114,121,99, +117,116,115,116,121,108,101,116,101,109,112,116,105,111,110,46,120,109,108,99, +111,99,107,103,97,110,103,36,40,39,46,53,48,112,120,80,104,46,68,109,105,115,99, +97,108,97,110,108,111,97,110,100,101,115,107,109,105,108,101,114,121,97,110,117, +110,105,120,100,105,115,99,41,59,125,10,100,117,115,116,99,108,105,112,41,46,10, +10,55,48,112,120,45,50,48,48,68,86,68,115,55,93,62,60,116,97,112,101,100,101,109 +,111,105,43,43,41,119,97,103,101,101,117,114,111,112,104,105,108,111,112,116,115 +,104,111,108,101,70,65,81,115,97,115,105,110,45,50,54,84,108,97,98,115,112,101, +116,115,85,82,76,32,98,117,108,107,99,111,111,107,59,125,13,10,72,69,65,68,91,48 +,93,41,97,98,98,114,106,117,97,110,40,49,57,56,108,101,115,104,116,119,105,110, +60,47,105,62,115,111,110,121,103,117,121,115,102,117,99,107,112,105,112,101,124, +45,10,33,48,48,50,41,110,100,111,119,91,49,93,59,91,93,59,10,76,111,103,32,115, +97,108,116,13,10,9,9,98,97,110,103,116,114,105,109,98,97,116,104,41,123,13,10,48 +,48,112,120,10,125,41,59,107,111,58,236,102,101,101,115,97,100,62,13,115,58,47, +47,32,91,93,59,116,111,108,108,112,108,117,103,40,41,123,10,123,13,10,32,46,106, +115,39,50,48,48,112,100,117,97,108,98,111,97,116,46,74,80,71,41,59,10,125,113, +117,111,116,41,59,10,10,39,41,59,10,13,10,125,13,50,48,49,52,50,48,49,53,50,48, +49,54,50,48,49,55,50,48,49,56,50,48,49,57,50,48,50,48,50,48,50,49,50,48,50,50,50 +,48,50,51,50,48,50,52,50,48,50,53,50,48,50,54,50,48,50,55,50,48,50,56,50,48,50, +57,50,48,51,48,50,48,51,49,50,48,51,50,50,48,51,51,50,48,51,52,50,48,51,53,50,48 +,51,54,50,48,51,55,50,48,49,51,50,48,49,50,50,48,49,49,50,48,49,48,50,48,48,57, +50,48,48,56,50,48,48,55,50,48,48,54,50,48,48,53,50,48,48,52,50,48,48,51,50,48,48 +,50,50,48,48,49,50,48,48,48,49,57,57,57,49,57,57,56,49,57,57,55,49,57,57,54,49, +57,57,53,49,57,57,52,49,57,57,51,49,57,57,50,49,57,57,49,49,57,57,48,49,57,56,57 +,49,57,56,56,49,57,56,55,49,57,56,54,49,57,56,53,49,57,56,52,49,57,56,51,49,57, +56,50,49,57,56,49,49,57,56,48,49,57,55,57,49,57,55,56,49,57,55,55,49,57,55,54,49 +,57,55,53,49,57,55,52,49,57,55,51,49,57,55,50,49,57,55,49,49,57,55,48,49,57,54, +57,49,57,54,56,49,57,54,55,49,57,54,54,49,57,54,53,49,57,54,52,49,57,54,51,49,57 +,54,50,49,57,54,49,49,57,54,48,49,57,53,57,49,57,53,56,49,57,53,55,49,57,53,54, +49,57,53,53,49,57,53,52,49,57,53,51,49,57,53,50,49,57,53,49,49,57,53,48,49,48,48 +,48,49,48,50,52,49,51,57,52,48,48,48,48,57,57,57,57,99,111,109,111,109,195,161, +115,101,115,116,101,101,115,116,97,112,101,114,111,116,111,100,111,104,97,99,101 +,99,97,100,97,97,195,177,111,98,105,101,110,100,195,173,97,97,115,195,173,118, +105,100,97,99,97,115,111,111,116,114,111,102,111,114,111,115,111,108,111,111,116 +,114,97,99,117,97,108,100,105,106,111,115,105,100,111,103,114,97,110,116,105,112 +,111,116,101,109,97,100,101,98,101,97,108,103,111,113,117,195,169,101,115,116, +111,110,97,100,97,116,114,101,115,112,111,99,111,99,97,115,97,98,97,106,111,116, +111,100,97,115,105,110,111,97,103,117,97,112,117,101,115,117,110,111,115,97,110, +116,101,100,105,99,101,108,117,105,115,101,108,108,97,109,97,121,111,122,111,110 +,97,97,109,111,114,112,105,115,111,111,98,114,97,99,108,105,99,101,108,108,111, +100,105,111,115,104,111,114,97,99,97,115,105,208,183,208,176,208,189,208,176,208 +,190,208,188,209,128,208,176,209,128,209,131,209,130,208,176,208,189,208,181,208 +,191,208,190,208,190,209,130,208,184,208,183,208,189,208,190,208,180,208,190,209 +,130,208,190,208,182,208,181,208,190,208,189,208,184,209,133,208,157,208,176,208 +,181,208,181,208,177,209,139,208,188,209,139,208,146,209,139,209,129,208,190,208 +,178,209,139,208,178,208,190,208,157,208,190,208,190,208,177,208,159,208,190,208 +,187,208,184,208,189,208,184,208,160,208,164,208,157,208,181,208,156,209,139,209 +,130,209,139,208,158,208,189,208,184,208,188,208,180,208,176,208,151,208,176,208 +,148,208,176,208,157,209,131,208,158,208,177,209,130,208,181,208,152,208,183,208 +,181,208,185,208,189,209,131,208,188,208,188,208,162,209,139,209,131,208,182,217 +,129,217,138,216,163,217,134,217,133,216,167,217,133,216,185,217,131,217,132,216 +,163,217,136,216,177,216,175,217,138,216,167,217,129,217,137,217,135,217,136,217 +,132,217,133,217,132,217,131,216,167,217,136,217,132,217,135,216,168,216,179,216 +,167,217,132,216,165,217,134,217,135,217,138,216,163,217,138,217,130,216,175,217 +,135,217,132,216,171,217,133,216,168,217,135,217,132,217,136,217,132,217,138,216 +,168,217,132,216,167,217,138,216,168,217,131,216,180,217,138,216,167,217,133,216 +,163,217,133,217,134,216,170,216,168,217,138,217,132,217,134,216,173,216,168,217 +,135,217,133,217,133,216,180,217,136,216,180,102,105,114,115,116,118,105,100,101 +,111,108,105,103,104,116,119,111,114,108,100,109,101,100,105,97,119,104,105,116, +101,99,108,111,115,101,98,108,97,99,107,114,105,103,104,116,115,109,97,108,108, +98,111,111,107,115,112,108,97,99,101,109,117,115,105,99,102,105,101,108,100,111, +114,100,101,114,112,111,105,110,116,118,97,108,117,101,108,101,118,101,108,116, +97,98,108,101,98,111,97,114,100,104,111,117,115,101,103,114,111,117,112,119,111, +114,107,115,121,101,97,114,115,115,116,97,116,101,116,111,100,97,121,119,97,116, +101,114,115,116,97,114,116,115,116,121,108,101,100,101,97,116,104,112,111,119, +101,114,112,104,111,110,101,110,105,103,104,116,101,114,114,111,114,105,110,112, +117,116,97,98,111,117,116,116,101,114,109,115,116,105,116,108,101,116,111,111, +108,115,101,118,101,110,116,108,111,99,97,108,116,105,109,101,115,108,97,114,103 +,101,119,111,114,100,115,103,97,109,101,115,115,104,111,114,116,115,112,97,99, +101,102,111,99,117,115,99,108,101,97,114,109,111,100,101,108,98,108,111,99,107, +103,117,105,100,101,114,97,100,105,111,115,104,97,114,101,119,111,109,101,110,97 +,103,97,105,110,109,111,110,101,121,105,109,97,103,101,110,97,109,101,115,121, +111,117,110,103,108,105,110,101,115,108,97,116,101,114,99,111,108,111,114,103, +114,101,101,110,102,114,111,110,116,38,97,109,112,59,119,97,116,99,104,102,111, +114,99,101,112,114,105,99,101,114,117,108,101,115,98,101,103,105,110,97,102,116, +101,114,118,105,115,105,116,105,115,115,117,101,97,114,101,97,115,98,101,108,111 +,119,105,110,100,101,120,116,111,116,97,108,104,111,117,114,115,108,97,98,101, +108,112,114,105,110,116,112,114,101,115,115,98,117,105,108,116,108,105,110,107, +115,115,112,101,101,100,115,116,117,100,121,116,114,97,100,101,102,111,117,110, +100,115,101,110,115,101,117,110,100,101,114,115,104,111,119,110,102,111,114,109, +115,114,97,110,103,101,97,100,100,101,100,115,116,105,108,108,109,111,118,101, +100,116,97,107,101,110,97,98,111,118,101,102,108,97,115,104,102,105,120,101,100, +111,102,116,101,110,111,116,104,101,114,118,105,101,119,115,99,104,101,99,107, +108,101,103,97,108,114,105,118,101,114,105,116,101,109,115,113,117,105,99,107, +115,104,97,112,101,104,117,109,97,110,101,120,105,115,116,103,111,105,110,103, +109,111,118,105,101,116,104,105,114,100,98,97,115,105,99,112,101,97,99,101,115, +116,97,103,101,119,105,100,116,104,108,111,103,105,110,105,100,101,97,115,119, +114,111,116,101,112,97,103,101,115,117,115,101,114,115,100,114,105,118,101,115, +116,111,114,101,98,114,101,97,107,115,111,117,116,104,118,111,105,99,101,115,105 +,116,101,115,109,111,110,116,104,119,104,101,114,101,98,117,105,108,100,119,104, +105,99,104,101,97,114,116,104,102,111,114,117,109,116,104,114,101,101,115,112, +111,114,116,112,97,114,116,121,67,108,105,99,107,108,111,119,101,114,108,105,118 +,101,115,99,108,97,115,115,108,97,121,101,114,101,110,116,114,121,115,116,111, +114,121,117,115,97,103,101,115,111,117,110,100,99,111,117,114,116,121,111,117, +114,32,98,105,114,116,104,112,111,112,117,112,116,121,112,101,115,97,112,112,108 +,121,73,109,97,103,101,98,101,105,110,103,117,112,112,101,114,110,111,116,101, +115,101,118,101,114,121,115,104,111,119,115,109,101,97,110,115,101,120,116,114, +97,109,97,116,99,104,116,114,97,99,107,107,110,111,119,110,101,97,114,108,121,98 +,101,103,97,110,115,117,112,101,114,112,97,112,101,114,110,111,114,116,104,108, +101,97,114,110,103,105,118,101,110,110,97,109,101,100,101,110,100,101,100,84,101 +,114,109,115,112,97,114,116,115,71,114,111,117,112,98,114,97,110,100,117,115,105 +,110,103,119,111,109,97,110,102,97,108,115,101,114,101,97,100,121,97,117,100,105 +,111,116,97,107,101,115,119,104,105,108,101,46,99,111,109,47,108,105,118,101,100 +,99,97,115,101,115,100,97,105,108,121,99,104,105,108,100,103,114,101,97,116,106, +117,100,103,101,116,104,111,115,101,117,110,105,116,115,110,101,118,101,114,98, +114,111,97,100,99,111,97,115,116,99,111,118,101,114,97,112,112,108,101,102,105, +108,101,115,99,121,99,108,101,115,99,101,110,101,112,108,97,110,115,99,108,105, +99,107,119,114,105,116,101,113,117,101,101,110,112,105,101,99,101,101,109,97,105 +,108,102,114,97,109,101,111,108,100,101,114,112,104,111,116,111,108,105,109,105, +116,99,97,99,104,101,99,105,118,105,108,115,99,97,108,101,101,110,116,101,114, +116,104,101,109,101,116,104,101,114,101,116,111,117,99,104,98,111,117,110,100, +114,111,121,97,108,97,115,107,101,100,119,104,111,108,101,115,105,110,99,101,115 +,116,111,99,107,32,110,97,109,101,102,97,105,116,104,104,101,97,114,116,101,109, +112,116,121,111,102,102,101,114,115,99,111,112,101,111,119,110,101,100,109,105, +103,104,116,97,108,98,117,109,116,104,105,110,107,98,108,111,111,100,97,114,114, +97,121,109,97,106,111,114,116,114,117,115,116,99,97,110,111,110,117,110,105,111, +110,99,111,117,110,116,118,97,108,105,100,115,116,111,110,101,83,116,121,108,101 +,76,111,103,105,110,104,97,112,112,121,111,99,99,117,114,108,101,102,116,58,102, +114,101,115,104,113,117,105,116,101,102,105,108,109,115,103,114,97,100,101,110, +101,101,100,115,117,114,98,97,110,102,105,103,104,116,98,97,115,105,115,104,111, +118,101,114,97,117,116,111,59,114,111,117,116,101,46,104,116,109,108,109,105,120 +,101,100,102,105,110,97,108,89,111,117,114,32,115,108,105,100,101,116,111,112, +105,99,98,114,111,119,110,97,108,111,110,101,100,114,97,119,110,115,112,108,105, +116,114,101,97,99,104,82,105,103,104,116,100,97,116,101,115,109,97,114,99,104, +113,117,111,116,101,103,111,111,100,115,76,105,110,107,115,100,111,117,98,116,97 +,115,121,110,99,116,104,117,109,98,97,108,108,111,119,99,104,105,101,102,121,111 +,117,116,104,110,111,118,101,108,49,48,112,120,59,115,101,114,118,101,117,110, +116,105,108,104,97,110,100,115,67,104,101,99,107,83,112,97,99,101,113,117,101, +114,121,106,97,109,101,115,101,113,117,97,108,116,119,105,99,101,48,44,48,48,48, +83,116,97,114,116,112,97,110,101,108,115,111,110,103,115,114,111,117,110,100,101 +,105,103,104,116,115,104,105,102,116,119,111,114,116,104,112,111,115,116,115,108 +,101,97,100,115,119,101,101,107,115,97,118,111,105,100,116,104,101,115,101,109, +105,108,101,115,112,108,97,110,101,115,109,97,114,116,97,108,112,104,97,112,108, +97,110,116,109,97,114,107,115,114,97,116,101,115,112,108,97,121,115,99,108,97, +105,109,115,97,108,101,115,116,101,120,116,115,115,116,97,114,115,119,114,111, +110,103,60,47,104,51,62,116,104,105,110,103,46,111,114,103,47,109,117,108,116, +105,104,101,97,114,100,80,111,119,101,114,115,116,97,110,100,116,111,107,101,110 +,115,111,108,105,100,40,116,104,105,115,98,114,105,110,103,115,104,105,112,115, +115,116,97,102,102,116,114,105,101,100,99,97,108,108,115,102,117,108,108,121,102 +,97,99,116,115,97,103,101,110,116,84,104,105,115,32,47,47,45,45,62,97,100,109, +105,110,101,103,121,112,116,69,118,101,110,116,49,53,112,120,59,69,109,97,105, +108,116,114,117,101,34,99,114,111,115,115,115,112,101,110,116,98,108,111,103,115 +,98,111,120,34,62,110,111,116,101,100,108,101,97,118,101,99,104,105,110,97,115, +105,122,101,115,103,117,101,115,116,60,47,104,52,62,114,111,98,111,116,104,101, +97,118,121,116,114,117,101,44,115,101,118,101,110,103,114,97,110,100,99,114,105, +109,101,115,105,103,110,115,97,119,97,114,101,100,97,110,99,101,112,104,97,115, +101,62,60,33,45,45,101,110,95,85,83,38,35,51,57,59,50,48,48,112,120,95,110,97, +109,101,108,97,116,105,110,101,110,106,111,121,97,106,97,120,46,97,116,105,111, +110,115,109,105,116,104,85,46,83,46,32,104,111,108,100,115,112,101,116,101,114, +105,110,100,105,97,110,97,118,34,62,99,104,97,105,110,115,99,111,114,101,99,111, +109,101,115,100,111,105,110,103,112,114,105,111,114,83,104,97,114,101,49,57,57, +48,115,114,111,109,97,110,108,105,115,116,115,106,97,112,97,110,102,97,108,108, +115,116,114,105,97,108,111,119,110,101,114,97,103,114,101,101,60,47,104,50,62,97 +,98,117,115,101,97,108,101,114,116,111,112,101,114,97,34,45,47,47,87,99,97,114, +100,115,104,105,108,108,115,116,101,97,109,115,80,104,111,116,111,116,114,117, +116,104,99,108,101,97,110,46,112,104,112,63,115,97,105,110,116,109,101,116,97, +108,108,111,117,105,115,109,101,97,110,116,112,114,111,111,102,98,114,105,101, +102,114,111,119,34,62,103,101,110,114,101,116,114,117,99,107,108,111,111,107,115 +,86,97,108,117,101,70,114,97,109,101,46,110,101,116,47,45,45,62,10,60,116,114, +121,32,123,10,118,97,114,32,109,97,107,101,115,99,111,115,116,115,112,108,97,105 +,110,97,100,117,108,116,113,117,101,115,116,116,114,97,105,110,108,97,98,111,114 +,104,101,108,112,115,99,97,117,115,101,109,97,103,105,99,109,111,116,111,114,116 +,104,101,105,114,50,53,48,112,120,108,101,97,115,116,115,116,101,112,115,67,111, +117,110,116,99,111,117,108,100,103,108,97,115,115,115,105,100,101,115,102,117, +110,100,115,104,111,116,101,108,97,119,97,114,100,109,111,117,116,104,109,111, +118,101,115,112,97,114,105,115,103,105,118,101,115,100,117,116,99,104,116,101, +120,97,115,102,114,117,105,116,110,117,108,108,44,124,124,91,93,59,116,111,112, +34,62,10,60,33,45,45,80,79,83,84,34,111,99,101,97,110,60,98,114,47,62,102,108, +111,111,114,115,112,101,97,107,100,101,112,116,104,32,115,105,122,101,98,97,110, +107,115,99,97,116,99,104,99,104,97,114,116,50,48,112,120,59,97,108,105,103,110, +100,101,97,108,115,119,111,117,108,100,53,48,112,120,59,117,114,108,61,34,112,97 +,114,107,115,109,111,117,115,101,77,111,115,116,32,46,46,46,60,47,97,109,111,110 +,103,98,114,97,105,110,98,111,100,121,32,110,111,110,101,59,98,97,115,101,100,99 +,97,114,114,121,100,114,97,102,116,114,101,102,101,114,112,97,103,101,95,104,111 +,109,101,46,109,101,116,101,114,100,101,108,97,121,100,114,101,97,109,112,114, +111,118,101,106,111,105,110,116,60,47,116,114,62,100,114,117,103,115,60,33,45,45 +,32,97,112,114,105,108,105,100,101,97,108,97,108,108,101,110,101,120,97,99,116, +102,111,114,116,104,99,111,100,101,115,108,111,103,105,99,86,105,101,119,32,115, +101,101,109,115,98,108,97,110,107,112,111,114,116,115,32,40,50,48,48,115,97,118, +101,100,95,108,105,110,107,103,111,97,108,115,103,114,97,110,116,103,114,101,101 +,107,104,111,109,101,115,114,105,110,103,115,114,97,116,101,100,51,48,112,120,59 +,119,104,111,115,101,112,97,114,115,101,40,41,59,34,32,66,108,111,99,107,108,105 +,110,117,120,106,111,110,101,115,112,105,120,101,108,39,41,59,34,62,41,59,105, +102,40,45,108,101,102,116,100,97,118,105,100,104,111,114,115,101,70,111,99,117, +115,114,97,105,115,101,98,111,120,101,115,84,114,97,99,107,101,109,101,110,116, +60,47,101,109,62,98,97,114,34,62,46,115,114,99,61,116,111,119,101,114,97,108,116 +,61,34,99,97,98,108,101,104,101,110,114,121,50,52,112,120,59,115,101,116,117,112 +,105,116,97,108,121,115,104,97,114,112,109,105,110,111,114,116,97,115,116,101, +119,97,110,116,115,116,104,105,115,46,114,101,115,101,116,119,104,101,101,108, +103,105,114,108,115,47,99,115,115,47,49,48,48,37,59,99,108,117,98,115,115,116, +117,102,102,98,105,98,108,101,118,111,116,101,115,32,49,48,48,48,107,111,114,101 +,97,125,41,59,13,10,98,97,110,100,115,113,117,101,117,101,61,32,123,125,59,56,48 +,112,120,59,99,107,105,110,103,123,13,10,9,9,97,104,101,97,100,99,108,111,99,107 +,105,114,105,115,104,108,105,107,101,32,114,97,116,105,111,115,116,97,116,115,70 +,111,114,109,34,121,97,104,111,111,41,91,48,93,59,65,98,111,117,116,102,105,110, +100,115,60,47,104,49,62,100,101,98,117,103,116,97,115,107,115,85,82,76,32,61,99, +101,108,108,115,125,41,40,41,59,49,50,112,120,59,112,114,105,109,101,116,101,108 +,108,115,116,117,114,110,115,48,120,54,48,48,46,106,112,103,34,115,112,97,105, +110,98,101,97,99,104,116,97,120,101,115,109,105,99,114,111,97,110,103,101,108,45 +,45,62,60,47,103,105,102,116,115,115,116,101,118,101,45,108,105,110,107,98,111, +100,121,46,125,41,59,10,9,109,111,117,110,116,32,40,49,57,57,70,65,81,60,47,114, +111,103,101,114,102,114,97,110,107,67,108,97,115,115,50,56,112,120,59,102,101, +101,100,115,60,104,49,62,60,115,99,111,116,116,116,101,115,116,115,50,50,112,120 +,59,100,114,105,110,107,41,32,124,124,32,108,101,119,105,115,115,104,97,108,108, +35,48,51,57,59,32,102,111,114,32,108,111,118,101,100,119,97,115,116,101,48,48, +112,120,59,106,97,58,227,130,115,105,109,111,110,60,102,111,110,116,114,101,112, +108,121,109,101,101,116,115,117,110,116,101,114,99,104,101,97,112,116,105,103, +104,116,66,114,97,110,100,41,32,33,61,32,100,114,101,115,115,99,108,105,112,115, +114,111,111,109,115,111,110,107,101,121,109,111,98,105,108,109,97,105,110,46,78, +97,109,101,32,112,108,97,116,101,102,117,110,110,121,116,114,101,101,115,99,111, +109,47,34,49,46,106,112,103,119,109,111,100,101,112,97,114,97,109,83,84,65,82,84 +,108,101,102,116,32,105,100,100,101,110,44,32,50,48,49,41,59,10,125,10,102,111, +114,109,46,118,105,114,117,115,99,104,97,105,114,116,114,97,110,115,119,111,114, +115,116,80,97,103,101,115,105,116,105,111,110,112,97,116,99,104,60,33,45,45,10, +111,45,99,97,99,102,105,114,109,115,116,111,117,114,115,44,48,48,48,32,97,115, +105,97,110,105,43,43,41,123,97,100,111,98,101,39,41,91,48,93,105,100,61,49,48,98 +,111,116,104,59,109,101,110,117,32,46,50,46,109,105,46,112,110,103,34,107,101, +118,105,110,99,111,97,99,104,67,104,105,108,100,98,114,117,99,101,50,46,106,112, +103,85,82,76,41,43,46,106,112,103,124,115,117,105,116,101,115,108,105,99,101,104 +,97,114,114,121,49,50,48,34,32,115,119,101,101,116,116,114,62,13,10,110,97,109, +101,61,100,105,101,103,111,112,97,103,101,32,115,119,105,115,115,45,45,62,10,10, +35,102,102,102,59,34,62,76,111,103,46,99,111,109,34,116,114,101,97,116,115,104, +101,101,116,41,32,38,38,32,49,52,112,120,59,115,108,101,101,112,110,116,101,110, +116,102,105,108,101,100,106,97,58,227,131,105,100,61,34,99,78,97,109,101,34,119, +111,114,115,101,115,104,111,116,115,45,98,111,120,45,100,101,108,116,97,10,38, +108,116,59,98,101,97,114,115,58,52,56,90,60,100,97,116,97,45,114,117,114,97,108, +60,47,97,62,32,115,112,101,110,100,98,97,107,101,114,115,104,111,112,115,61,32, +34,34,59,112,104,112,34,62,99,116,105,111,110,49,51,112,120,59,98,114,105,97,110 +,104,101,108,108,111,115,105,122,101,61,111,61,37,50,70,32,106,111,105,110,109, +97,121,98,101,60,105,109,103,32,105,109,103,34,62,44,32,102,106,115,105,109,103, +34,32,34,41,91,48,93,77,84,111,112,66,84,121,112,101,34,110,101,119,108,121,68, +97,110,115,107,99,122,101,99,104,116,114,97,105,108,107,110,111,119,115,60,47, +104,53,62,102,97,113,34,62,122,104,45,99,110,49,48,41,59,10,45,49,34,41,59,116, +121,112,101,61,98,108,117,101,115,116,114,117,108,121,100,97,118,105,115,46,106, +115,39,59,62,13,10,60,33,115,116,101,101,108,32,121,111,117,32,104,50,62,13,10, +102,111,114,109,32,106,101,115,117,115,49,48,48,37,32,109,101,110,117,46,13,10,9 +,13,10,119,97,108,101,115,114,105,115,107,115,117,109,101,110,116,100,100,105, +110,103,98,45,108,105,107,116,101,97,99,104,103,105,102,34,32,118,101,103,97,115 +,100,97,110,115,107,101,101,115,116,105,115,104,113,105,112,115,117,111,109,105, +115,111,98,114,101,100,101,115,100,101,101,110,116,114,101,116,111,100,111,115, +112,117,101,100,101,97,195,177,111,115,101,115,116,195,161,116,105,101,110,101, +104,97,115,116,97,111,116,114,111,115,112,97,114,116,101,100,111,110,100,101,110 +,117,101,118,111,104,97,99,101,114,102,111,114,109,97,109,105,115,109,111,109, +101,106,111,114,109,117,110,100,111,97,113,117,195,173,100,195,173,97,115,115, +195,179,108,111,97,121,117,100,97,102,101,99,104,97,116,111,100,97,115,116,97, +110,116,111,109,101,110,111,115,100,97,116,111,115,111,116,114,97,115,115,105, +116,105,111,109,117,99,104,111,97,104,111,114,97,108,117,103,97,114,109,97,121, +111,114,101,115,116,111,115,104,111,114,97,115,116,101,110,101,114,97,110,116, +101,115,102,111,116,111,115,101,115,116,97,115,112,97,195,173,115,110,117,101, +118,97,115,97,108,117,100,102,111,114,111,115,109,101,100,105,111,113,117,105, +101,110,109,101,115,101,115,112,111,100,101,114,99,104,105,108,101,115,101,114, +195,161,118,101,99,101,115,100,101,99,105,114,106,111,115,195,169,101,115,116,97 +,114,118,101,110,116,97,103,114,117,112,111,104,101,99,104,111,101,108,108,111, +115,116,101,110,103,111,97,109,105,103,111,99,111,115,97,115,110,105,118,101,108 +,103,101,110,116,101,109,105,115,109,97,97,105,114,101,115,106,117,108,105,111, +116,101,109,97,115,104,97,99,105,97,102,97,118,111,114,106,117,110,105,111,108, +105,98,114,101,112,117,110,116,111,98,117,101,110,111,97,117,116,111,114,97,98, +114,105,108,98,117,101,110,97,116,101,120,116,111,109,97,114,122,111,115,97,98, +101,114,108,105,115,116,97,108,117,101,103,111,99,195,179,109,111,101,110,101, +114,111,106,117,101,103,111,112,101,114,195,186,104,97,98,101,114,101,115,116, +111,121,110,117,110,99,97,109,117,106,101,114,118,97,108,111,114,102,117,101,114 +,97,108,105,98,114,111,103,117,115,116,97,105,103,117,97,108,118,111,116,111,115 +,99,97,115,111,115,103,117,195,173,97,112,117,101,100,111,115,111,109,111,115,97 +,118,105,115,111,117,115,116,101,100,100,101,98,101,110,110,111,99,104,101,98, +117,115,99,97,102,97,108,116,97,101,117,114,111,115,115,101,114,105,101,100,105, +99,104,111,99,117,114,115,111,99,108,97,118,101,99,97,115,97,115,108,101,195,179 +,110,112,108,97,122,111,108,97,114,103,111,111,98,114,97,115,118,105,115,116,97, +97,112,111,121,111,106,117,110,116,111,116,114,97,116,97,118,105,115,116,111,99, +114,101,97,114,99,97,109,112,111,104,101,109,111,115,99,105,110,99,111,99,97,114 +,103,111,112,105,115,111,115,111,114,100,101,110,104,97,99,101,110,195,161,114, +101,97,100,105,115,99,111,112,101,100,114,111,99,101,114,99,97,112,117,101,100, +97,112,97,112,101,108,109,101,110,111,114,195,186,116,105,108,99,108,97,114,111, +106,111,114,103,101,99,97,108,108,101,112,111,110,101,114,116,97,114,100,101,110 +,97,100,105,101,109,97,114,99,97,115,105,103,117,101,101,108,108,97,115,115,105, +103,108,111,99,111,99,104,101,109,111,116,111,115,109,97,100,114,101,99,108,97, +115,101,114,101,115,116,111,110,105,195,177,111,113,117,101,100,97,112,97,115,97 +,114,98,97,110,99,111,104,105,106,111,115,118,105,97,106,101,112,97,98,108,111, +195,169,115,116,101,118,105,101,110,101,114,101,105,110,111,100,101,106,97,114, +102,111,110,100,111,99,97,110,97,108,110,111,114,116,101,108,101,116,114,97,99, +97,117,115,97,116,111,109,97,114,109,97,110,111,115,108,117,110,101,115,97,117, +116,111,115,118,105,108,108,97,118,101,110,100,111,112,101,115,97,114,116,105, +112,111,115,116,101,110,103,97,109,97,114,99,111,108,108,101,118,97,112,97,100, +114,101,117,110,105,100,111,118,97,109,111,115,122,111,110,97,115,97,109,98,111, +115,98,97,110,100,97,109,97,114,105,97,97,98,117,115,111,109,117,99,104,97,115, +117,98,105,114,114,105,111,106,97,118,105,118,105,114,103,114,97,100,111,99,104, +105,99,97,97,108,108,195,173,106,111,118,101,110,100,105,99,104,97,101,115,116, +97,110,116,97,108,101,115,115,97,108,105,114,115,117,101,108,111,112,101,115,111 +,115,102,105,110,101,115,108,108,97,109,97,98,117,115,99,111,195,169,115,116,97, +108,108,101,103,97,110,101,103,114,111,112,108,97,122,97,104,117,109,111,114,112 +,97,103,97,114,106,117,110,116,97,100,111,98,108,101,105,115,108,97,115,98,111, +108,115,97,98,97,195,177,111,104,97,98,108,97,108,117,99,104,97,195,129,114,101, +97,100,105,99,101,110,106,117,103,97,114,110,111,116,97,115,118,97,108,108,101, +97,108,108,195,161,99,97,114,103,97,100,111,108,111,114,97,98,97,106,111,101,115 +,116,195,169,103,117,115,116,111,109,101,110,116,101,109,97,114,105,111,102,105, +114,109,97,99,111,115,116,111,102,105,99,104,97,112,108,97,116,97,104,111,103,97 +,114,97,114,116,101,115,108,101,121,101,115,97,113,117,101,108,109,117,115,101, +111,98,97,115,101,115,112,111,99,111,115,109,105,116,97,100,99,105,101,108,111, +99,104,105,99,111,109,105,101,100,111,103,97,110,97,114,115,97,110,116,111,101, +116,97,112,97,100,101,98,101,115,112,108,97,121,97,114,101,100,101,115,115,105, +101,116,101,99,111,114,116,101,99,111,114,101,97,100,117,100,97,115,100,101,115, +101,111,118,105,101,106,111,100,101,115,101,97,97,103,117,97,115,38,113,117,111, +116,59,100,111,109,97,105,110,99,111,109,109,111,110,115,116,97,116,117,115,101, +118,101,110,116,115,109,97,115,116,101,114,115,121,115,116,101,109,97,99,116,105 +,111,110,98,97,110,110,101,114,114,101,109,111,118,101,115,99,114,111,108,108, +117,112,100,97,116,101,103,108,111,98,97,108,109,101,100,105,117,109,102,105,108 +,116,101,114,110,117,109,98,101,114,99,104,97,110,103,101,114,101,115,117,108, +116,112,117,98,108,105,99,115,99,114,101,101,110,99,104,111,111,115,101,110,111, +114,109,97,108,116,114,97,118,101,108,105,115,115,117,101,115,115,111,117,114,99 +,101,116,97,114,103,101,116,115,112,114,105,110,103,109,111,100,117,108,101,109, +111,98,105,108,101,115,119,105,116,99,104,112,104,111,116,111,115,98,111,114,100 +,101,114,114,101,103,105,111,110,105,116,115,101,108,102,115,111,99,105,97,108, +97,99,116,105,118,101,99,111,108,117,109,110,114,101,99,111,114,100,102,111,108, +108,111,119,116,105,116,108,101,62,101,105,116,104,101,114,108,101,110,103,116, +104,102,97,109,105,108,121,102,114,105,101,110,100,108,97,121,111,117,116,97,117 +,116,104,111,114,99,114,101,97,116,101,114,101,118,105,101,119,115,117,109,109, +101,114,115,101,114,118,101,114,112,108,97,121,101,100,112,108,97,121,101,114, +101,120,112,97,110,100,112,111,108,105,99,121,102,111,114,109,97,116,100,111,117 +,98,108,101,112,111,105,110,116,115,115,101,114,105,101,115,112,101,114,115,111, +110,108,105,118,105,110,103,100,101,115,105,103,110,109,111,110,116,104,115,102, +111,114,99,101,115,117,110,105,113,117,101,119,101,105,103,104,116,112,101,111, +112,108,101,101,110,101,114,103,121,110,97,116,117,114,101,115,101,97,114,99,104 +,102,105,103,117,114,101,104,97,118,105,110,103,99,117,115,116,111,109,111,102, +102,115,101,116,108,101,116,116,101,114,119,105,110,100,111,119,115,117,98,109, +105,116,114,101,110,100,101,114,103,114,111,117,112,115,117,112,108,111,97,100, +104,101,97,108,116,104,109,101,116,104,111,100,118,105,100,101,111,115,115,99, +104,111,111,108,102,117,116,117,114,101,115,104,97,100,111,119,100,101,98,97,116 +,101,118,97,108,117,101,115,79,98,106,101,99,116,111,116,104,101,114,115,114,105 +,103,104,116,115,108,101,97,103,117,101,99,104,114,111,109,101,115,105,109,112, +108,101,110,111,116,105,99,101,115,104,97,114,101,100,101,110,100,105,110,103, +115,101,97,115,111,110,114,101,112,111,114,116,111,110,108,105,110,101,115,113, +117,97,114,101,98,117,116,116,111,110,105,109,97,103,101,115,101,110,97,98,108, +101,109,111,118,105,110,103,108,97,116,101,115,116,119,105,110,116,101,114,70, +114,97,110,99,101,112,101,114,105,111,100,115,116,114,111,110,103,114,101,112, +101,97,116,76,111,110,100,111,110,100,101,116,97,105,108,102,111,114,109,101,100 +,100,101,109,97,110,100,115,101,99,117,114,101,112,97,115,115,101,100,116,111, +103,103,108,101,112,108,97,99,101,115,100,101,118,105,99,101,115,116,97,116,105, +99,99,105,116,105,101,115,115,116,114,101,97,109,121,101,108,108,111,119,97,116, +116,97,99,107,115,116,114,101,101,116,102,108,105,103,104,116,104,105,100,100, +101,110,105,110,102,111,34,62,111,112,101,110,101,100,117,115,101,102,117,108, +118,97,108,108,101,121,99,97,117,115,101,115,108,101,97,100,101,114,115,101,99, +114,101,116,115,101,99,111,110,100,100,97,109,97,103,101,115,112,111,114,116,115 +,101,120,99,101,112,116,114,97,116,105,110,103,115,105,103,110,101,100,116,104, +105,110,103,115,101,102,102,101,99,116,102,105,101,108,100,115,115,116,97,116, +101,115,111,102,102,105,99,101,118,105,115,117,97,108,101,100,105,116,111,114, +118,111,108,117,109,101,82,101,112,111,114,116,109,117,115,101,117,109,109,111, +118,105,101,115,112,97,114,101,110,116,97,99,99,101,115,115,109,111,115,116,108, +121,109,111,116,104,101,114,34,32,105,100,61,34,109,97,114,107,101,116,103,114, +111,117,110,100,99,104,97,110,99,101,115,117,114,118,101,121,98,101,102,111,114, +101,115,121,109,98,111,108,109,111,109,101,110,116,115,112,101,101,99,104,109, +111,116,105,111,110,105,110,115,105,100,101,109,97,116,116,101,114,67,101,110, +116,101,114,111,98,106,101,99,116,101,120,105,115,116,115,109,105,100,100,108, +101,69,117,114,111,112,101,103,114,111,119,116,104,108,101,103,97,99,121,109,97, +110,110,101,114,101,110,111,117,103,104,99,97,114,101,101,114,97,110,115,119,101 +,114,111,114,105,103,105,110,112,111,114,116,97,108,99,108,105,101,110,116,115, +101,108,101,99,116,114,97,110,100,111,109,99,108,111,115,101,100,116,111,112,105 +,99,115,99,111,109,105,110,103,102,97,116,104,101,114,111,112,116,105,111,110, +115,105,109,112,108,121,114,97,105,115,101,100,101,115,99,97,112,101,99,104,111, +115,101,110,99,104,117,114,99,104,100,101,102,105,110,101,114,101,97,115,111,110 +,99,111,114,110,101,114,111,117,116,112,117,116,109,101,109,111,114,121,105,102, +114,97,109,101,112,111,108,105,99,101,109,111,100,101,108,115,78,117,109,98,101, +114,100,117,114,105,110,103,111,102,102,101,114,115,115,116,121,108,101,115,107, +105,108,108,101,100,108,105,115,116,101,100,99,97,108,108,101,100,115,105,108, +118,101,114,109,97,114,103,105,110,100,101,108,101,116,101,98,101,116,116,101, +114,98,114,111,119,115,101,108,105,109,105,116,115,71,108,111,98,97,108,115,105, +110,103,108,101,119,105,100,103,101,116,99,101,110,116,101,114,98,117,100,103, +101,116,110,111,119,114,97,112,99,114,101,100,105,116,99,108,97,105,109,115,101, +110,103,105,110,101,115,97,102,101,116,121,99,104,111,105,99,101,115,112,105,114 +,105,116,45,115,116,121,108,101,115,112,114,101,97,100,109,97,107,105,110,103, +110,101,101,100,101,100,114,117,115,115,105,97,112,108,101,97,115,101,101,120, +116,101,110,116,83,99,114,105,112,116,98,114,111,107,101,110,97,108,108,111,119, +115,99,104,97,114,103,101,100,105,118,105,100,101,102,97,99,116,111,114,109,101, +109,98,101,114,45,98,97,115,101,100,116,104,101,111,114,121,99,111,110,102,105, +103,97,114,111,117,110,100,119,111,114,107,101,100,104,101,108,112,101,100,67, +104,117,114,99,104,105,109,112,97,99,116,115,104,111,117,108,100,97,108,119,97, +121,115,108,111,103,111,34,32,98,111,116,116,111,109,108,105,115,116,34,62,41, +123,118,97,114,32,112,114,101,102,105,120,111,114,97,110,103,101,72,101,97,100, +101,114,46,112,117,115,104,40,99,111,117,112,108,101,103,97,114,100,101,110,98, +114,105,100,103,101,108,97,117,110,99,104,82,101,118,105,101,119,116,97,107,105, +110,103,118,105,115,105,111,110,108,105,116,116,108,101,100,97,116,105,110,103, +66,117,116,116,111,110,98,101,97,117,116,121,116,104,101,109,101,115,102,111,114 +,103,111,116,83,101,97,114,99,104,97,110,99,104,111,114,97,108,109,111,115,116, +108,111,97,100,101,100,67,104,97,110,103,101,114,101,116,117,114,110,115,116,114 +,105,110,103,114,101,108,111,97,100,77,111,98,105,108,101,105,110,99,111,109,101 +,115,117,112,112,108,121,83,111,117,114,99,101,111,114,100,101,114,115,118,105, +101,119,101,100,38,110,98,115,112,59,99,111,117,114,115,101,65,98,111,117,116,32 +,105,115,108,97,110,100,60,104,116,109,108,32,99,111,111,107,105,101,110,97,109, +101,61,34,97,109,97,122,111,110,109,111,100,101,114,110,97,100,118,105,99,101, +105,110,60,47,97,62,58,32,84,104,101,32,100,105,97,108,111,103,104,111,117,115, +101,115,66,69,71,73,78,32,77,101,120,105,99,111,115,116,97,114,116,115,99,101, +110,116,114,101,104,101,105,103,104,116,97,100,100,105,110,103,73,115,108,97,110 +,100,97,115,115,101,116,115,69,109,112,105,114,101,83,99,104,111,111,108,101,102 +,102,111,114,116,100,105,114,101,99,116,110,101,97,114,108,121,109,97,110,117,97 +,108,83,101,108,101,99,116,46,10,10,79,110,101,106,111,105,110,101,100,109,101, +110,117,34,62,80,104,105,108,105,112,97,119,97,114,100,115,104,97,110,100,108, +101,105,109,112,111,114,116,79,102,102,105,99,101,114,101,103,97,114,100,115,107 +,105,108,108,115,110,97,116,105,111,110,83,112,111,114,116,115,100,101,103,114, +101,101,119,101,101,107,108,121,32,40,101,46,103,46,98,101,104,105,110,100,100, +111,99,116,111,114,108,111,103,103,101,100,117,110,105,116,101,100,60,47,98,62, +60,47,98,101,103,105,110,115,112,108,97,110,116,115,97,115,115,105,115,116,97, +114,116,105,115,116,105,115,115,117,101,100,51,48,48,112,120,124,99,97,110,97, +100,97,97,103,101,110,99,121,115,99,104,101,109,101,114,101,109,97,105,110,66, +114,97,122,105,108,115,97,109,112,108,101,108,111,103,111,34,62,98,101,121,111, +110,100,45,115,99,97,108,101,97,99,99,101,112,116,115,101,114,118,101,100,109,97 +,114,105,110,101,70,111,111,116,101,114,99,97,109,101,114,97,60,47,104,49,62,10, +95,102,111,114,109,34,108,101,97,118,101,115,115,116,114,101,115,115,34,32,47,62 +,13,10,46,103,105,102,34,32,111,110,108,111,97,100,108,111,97,100,101,114,79,120 +,102,111,114,100,115,105,115,116,101,114,115,117,114,118,105,118,108,105,115,116 +,101,110,102,101,109,97,108,101,68,101,115,105,103,110,115,105,122,101,61,34,97, +112,112,101,97,108,116,101,120,116,34,62,108,101,118,101,108,115,116,104,97,110, +107,115,104,105,103,104,101,114,102,111,114,99,101,100,97,110,105,109,97,108,97, +110,121,111,110,101,65,102,114,105,99,97,97,103,114,101,101,100,114,101,99,101, +110,116,80,101,111,112,108,101,60,98,114,32,47,62,119,111,110,100,101,114,112, +114,105,99,101,115,116,117,114,110,101,100,124,124,32,123,125,59,109,97,105,110, +34,62,105,110,108,105,110,101,115,117,110,100,97,121,119,114,97,112,34,62,102,97 +,105,108,101,100,99,101,110,115,117,115,109,105,110,117,116,101,98,101,97,99,111 +,110,113,117,111,116,101,115,49,53,48,112,120,124,101,115,116,97,116,101,114,101 +,109,111,116,101,101,109,97,105,108,34,108,105,110,107,101,100,114,105,103,104, +116,59,115,105,103,110,97,108,102,111,114,109,97,108,49,46,104,116,109,108,115, +105,103,110,117,112,112,114,105,110,99,101,102,108,111,97,116,58,46,112,110,103, +34,32,102,111,114,117,109,46,65,99,99,101,115,115,112,97,112,101,114,115,115,111 +,117,110,100,115,101,120,116,101,110,100,72,101,105,103,104,116,115,108,105,100, +101,114,85,84,70,45,56,34,38,97,109,112,59,32,66,101,102,111,114,101,46,32,87, +105,116,104,115,116,117,100,105,111,111,119,110,101,114,115,109,97,110,97,103, +101,112,114,111,102,105,116,106,81,117,101,114,121,97,110,110,117,97,108,112,97, +114,97,109,115,98,111,117,103,104,116,102,97,109,111,117,115,103,111,111,103,108 +,101,108,111,110,103,101,114,105,43,43,41,32,123,105,115,114,97,101,108,115,97, +121,105,110,103,100,101,99,105,100,101,104,111,109,101,34,62,104,101,97,100,101, +114,101,110,115,117,114,101,98,114,97,110,99,104,112,105,101,99,101,115,98,108, +111,99,107,59,115,116,97,116,101,100,116,111,112,34,62,60,114,97,99,105,110,103, +114,101,115,105,122,101,45,45,38,103,116,59,112,97,99,105,116,121,115,101,120, +117,97,108,98,117,114,101,97,117,46,106,112,103,34,32,49,48,44,48,48,48,111,98, +116,97,105,110,116,105,116,108,101,115,97,109,111,117,110,116,44,32,73,110,99,46 +,99,111,109,101,100,121,109,101,110,117,34,32,108,121,114,105,99,115,116,111,100 +,97,121,46,105,110,100,101,101,100,99,111,117,110,116,121,95,108,111,103,111,46, +70,97,109,105,108,121,108,111,111,107,101,100,77,97,114,107,101,116,108,115,101, +32,105,102,80,108,97,121,101,114,116,117,114,107,101,121,41,59,118,97,114,32,102 +,111,114,101,115,116,103,105,118,105,110,103,101,114,114,111,114,115,68,111,109, +97,105,110,125,101,108,115,101,123,105,110,115,101,114,116,66,108,111,103,60,47, +102,111,111,116,101,114,108,111,103,105,110,46,102,97,115,116,101,114,97,103,101 +,110,116,115,60,98,111,100,121,32,49,48,112,120,32,48,112,114,97,103,109,97,102, +114,105,100,97,121,106,117,110,105,111,114,100,111,108,108,97,114,112,108,97,99, +101,100,99,111,118,101,114,115,112,108,117,103,105,110,53,44,48,48,48,32,112,97, +103,101,34,62,98,111,115,116,111,110,46,116,101,115,116,40,97,118,97,116,97,114, +116,101,115,116,101,100,95,99,111,117,110,116,102,111,114,117,109,115,115,99,104 +,101,109,97,105,110,100,101,120,44,102,105,108,108,101,100,115,104,97,114,101, +115,114,101,97,100,101,114,97,108,101,114,116,40,97,112,112,101,97,114,83,117,98 +,109,105,116,108,105,110,101,34,62,98,111,100,121,34,62,10,42,32,84,104,101,84, +104,111,117,103,104,115,101,101,105,110,103,106,101,114,115,101,121,78,101,119, +115,60,47,118,101,114,105,102,121,101,120,112,101,114,116,105,110,106,117,114, +121,119,105,100,116,104,61,67,111,111,107,105,101,83,84,65,82,84,32,97,99,114, +111,115,115,95,105,109,97,103,101,116,104,114,101,97,100,110,97,116,105,118,101, +112,111,99,107,101,116,98,111,120,34,62,10,83,121,115,116,101,109,32,68,97,118, +105,100,99,97,110,99,101,114,116,97,98,108,101,115,112,114,111,118,101,100,65, +112,114,105,108,32,114,101,97,108,108,121,100,114,105,118,101,114,105,116,101, +109,34,62,109,111,114,101,34,62,98,111,97,114,100,115,99,111,108,111,114,115,99, +97,109,112,117,115,102,105,114,115,116,32,124,124,32,91,93,59,109,101,100,105,97 +,46,103,117,105,116,97,114,102,105,110,105,115,104,119,105,100,116,104,58,115, +104,111,119,101,100,79,116,104,101,114,32,46,112,104,112,34,32,97,115,115,117, +109,101,108,97,121,101,114,115,119,105,108,115,111,110,115,116,111,114,101,115, +114,101,108,105,101,102,115,119,101,100,101,110,67,117,115,116,111,109,101,97, +115,105,108,121,32,121,111,117,114,32,83,116,114,105,110,103,10,10,87,104,105, +108,116,97,121,108,111,114,99,108,101,97,114,58,114,101,115,111,114,116,102,114, +101,110,99,104,116,104,111,117,103,104,34,41,32,43,32,34,60,98,111,100,121,62,98 +,117,121,105,110,103,98,114,97,110,100,115,77,101,109,98,101,114,110,97,109,101, +34,62,111,112,112,105,110,103,115,101,99,116,111,114,53,112,120,59,34,62,118,115 +,112,97,99,101,112,111,115,116,101,114,109,97,106,111,114,32,99,111,102,102,101, +101,109,97,114,116,105,110,109,97,116,117,114,101,104,97,112,112,101,110,60,47, +110,97,118,62,107,97,110,115,97,115,108,105,110,107,34,62,73,109,97,103,101,115, +61,102,97,108,115,101,119,104,105,108,101,32,104,115,112,97,99,101,48,38,97,109, +112,59,32,10,10,73,110,32,32,112,111,119,101,114,80,111,108,115,107,105,45,99, +111,108,111,114,106,111,114,100,97,110,66,111,116,116,111,109,83,116,97,114,116, +32,45,99,111,117,110,116,50,46,104,116,109,108,110,101,119,115,34,62,48,49,46, +106,112,103,79,110,108,105,110,101,45,114,105,103,104,116,109,105,108,108,101, +114,115,101,110,105,111,114,73,83,66,78,32,48,48,44,48,48,48,32,103,117,105,100, +101,115,118,97,108,117,101,41,101,99,116,105,111,110,114,101,112,97,105,114,46, +120,109,108,34,32,32,114,105,103,104,116,115,46,104,116,109,108,45,98,108,111,99 +,107,114,101,103,69,120,112,58,104,111,118,101,114,119,105,116,104,105,110,118, +105,114,103,105,110,112,104,111,110,101,115,60,47,116,114,62,13,117,115,105,110, +103,32,10,9,118,97,114,32,62,39,41,59,10,9,60,47,116,100,62,10,60,47,116,114,62, +10,98,97,104,97,115,97,98,114,97,115,105,108,103,97,108,101,103,111,109,97,103, +121,97,114,112,111,108,115,107,105,115,114,112,115,107,105,216,177,216,175,217, +136,228,184,173,230,150,135,231,174,128,228,189,147,231,185,129,233,171,148,228, +191,161,230,129,175,228,184,173,229,155,189,230,136,145,228,187,172,228,184,128, +228,184,170,229,133,172,229,143,184,231,174,161,231,144,134,232,174,186,229,157, +155,229,143,175,228,187,165,230,156,141,229,138,161,230,151,182,233,151,180,228, +184,170,228,186,186,228,186,167,229,147,129,232,135,170,229,183,177,228,188,129, +228,184,154,230,159,165,231,156,139,229,183,165,228,189,156,232,129,148,231,179, +187,230,178,161,230,156,137,231,189,145,231,171,153,230,137,128,230,156,137,232, +175,132,232,174,186,228,184,173,229,191,131,230,150,135,231,171,160,231,148,168, +230,136,183,233,166,150,233,161,181,228,189,156,232,128,133,230,138,128,230,156, +175,233,151,174,233,162,152,231,155,184,229,133,179,228,184,139,232,189,189,230, +144,156,231,180,162,228,189,191,231,148,168,232,189,175,228,187,182,229,156,168, +231,186,191,228,184,187,233,162,152,232,181,132,230,150,153,232,167,134,233,162, +145,229,155,158,229,164,141,230,179,168,229,134,140,231,189,145,231,187,156,230, +148,182,232,151,143,229,134,133,229,174,185,230,142,168,232,141,144,229,184,130, +229,156,186,230,182,136,230,129,175,231,169,186,233,151,180,229,143,145,229,184, +131,228,187,128,228,185,136,229,165,189,229,143,139,231,148,159,230,180,187,229, +155,190,231,137,135,229,143,145,229,177,149,229,166,130,230,158,156,230,137,139, +230,156,186,230,150,176,233,151,187,230,156,128,230,150,176,230,150,185,229,188, +143,229,140,151,228,186,172,230,143,144,228,190,155,229,133,179,228,186,142,230, +155,180,229,164,154,232,191,153,228,184,170,231,179,187,231,187,159,231,159,165, +233,129,147,230,184,184,230,136,143,229,185,191,229,145,138,229,133,182,228,187, +150,229,143,145,232,161,168,229,174,137,229,133,168,231,172,172,228,184,128,228, +188,154,229,145,152,232,191,155,232,161,140,231,130,185,229,135,187,231,137,136, +230,157,131,231,148,181,229,173,144,228,184,150,231,149,140,232,174,190,232,174, +161,229,133,141,232,180,185,230,149,153,232,130,178,229,138,160,229,133,165,230, +180,187,229,138,168,228,187,150,228,187,172,229,149,134,229,147,129,229,141,154, +229,174,162,231,142,176,229,156,168,228,184,138,230,181,183,229,166,130,228,189, +149,229,183,178,231,187,143,231,149,153,232,168,128,232,175,166,231,187,134,231, +164,190,229,140,186,231,153,187,229,189,149,230,156,172,231,171,153,233,156,128, +232,166,129,228,187,183,230,160,188,230,148,175,230,140,129,229,155,189,233,153, +133,233,147,190,230,142,165,229,155,189,229,174,182,229,187,186,232,174,190,230, +156,139,229,143,139,233,152,133,232,175,187,230,179,149,229,190,139,228,189,141, +231,189,174,231,187,143,230,181,142,233,128,137,230,139,169,232,191,153,230,160, +183,229,189,147,229,137,141,229,136,134,231,177,187,230,142,146,232,161,140,229, +155,160,228,184,186,228,186,164,230,152,147,230,156,128,229,144,142,233,159,179, +228,185,144,228,184,141,232,131,189,233,128,154,232,191,135,232,161,140,228,184, +154,231,167,145,230,138,128,229,143,175,232,131,189,232,174,190,229,164,135,229, +144,136,228,189,156,229,164,167,229,174,182,231,164,190,228,188,154,231,160,148, +231,169,182,228,184,147,228,184,154,229,133,168,233,131,168,233,161,185,231,155, +174,232,191,153,233,135,140,232,191,152,230,152,175,229,188,128,229,167,139,230, +131,133,229,134,181,231,148,181,232,132,145,230,150,135,228,187,182,229,147,129, +231,137,140,229,184,174,229,138,169,230,150,135,229,140,150,232,181,132,230,186, +144,229,164,167,229,173,166,229,173,166,228,185,160,229,156,176,229,157,128,230, +181,143,232,167,136,230,138,149,232,181,132,229,183,165,231,168,139,232,166,129, +230,177,130,230,128,142,228,185,136,230,151,182,229,128,153,229,138,159,232,131, +189,228,184,187,232,166,129,231,155,174,229,137,141,232,181,132,232,174,175,229, +159,142,229,184,130,230,150,185,230,179,149,231,148,181,229,189,177,230,139,155, +232,129,152,229,163,176,230,152,142,228,187,187,228,189,149,229,129,165,229,186, +183,230,149,176,230,141,174,231,190,142,229,155,189,230,177,189,232,189,166,228, +187,139,231,187,141,228,189,134,230,152,175,228,186,164,230,181,129,231,148,159, +228,186,167,230,137,128,228,187,165,231,148,181,232,175,157,230,152,190,231,164, +186,228,184,128,228,186,155,229,141,149,228,189,141,228,186,186,229,145,152,229, +136,134,230,158,144,229,156,176,229,155,190,230,151,133,230,184,184,229,183,165, +229,133,183,229,173,166,231,148,159,231,179,187,229,136,151,231,189,145,229,143, +139,229,184,150,229,173,144,229,175,134,231,160,129,233,162,145,233,129,147,230, +142,167,229,136,182,229,156,176,229,140,186,229,159,186,230,156,172,229,133,168, +229,155,189,231,189,145,228,184,138,233,135,141,232,166,129,231,172,172,228,186, +140,229,150,156,230,172,162,232,191,155,229,133,165,229,143,139,230,131,133,232, +191,153,228,186,155,232,128,131,232,175,149,229,143,145,231,142,176,229,159,185, +232,174,173,228,187,165,228,184,138,230,148,191,229,186,156,230,136,144,228,184, +186,231,142,175,229,162,131,233,166,153,230,184,175,229,144,140,230,151,182,229, +168,177,228,185,144,229,143,145,233,128,129,228,184,128,229,174,154,229,188,128, +229,143,145,228,189,156,229,147,129,230,160,135,229,135,134,230,172,162,232,191, +142,232,167,163,229,134,179,229,156,176,230,150,185,228,184,128,228,184,139,228, +187,165,229,143,138,232,180,163,228,187,187,230,136,150,232,128,133,229,174,162, +230,136,183,228,187,163,232,161,168,231,167,175,229,136,134,229,165,179,228,186, +186,230,149,176,231,160,129,233,148,128,229,148,174,229,135,186,231,142,176,231, +166,187,231,186,191,229,186,148,231,148,168,229,136,151,232,161,168,228,184,141, +229,144,140,231,188,150,232,190,145,231,187,159,232,174,161,230,159,165,232,175, +162,228,184,141,232,166,129,230,156,137,229,133,179,230,156,186,230,158,132,229, +190,136,229,164,154,230,146,173,230,148,190,231,187,132,231,187,135,230,148,191, +231,173,150,231,155,180,230,142,165,232,131,189,229,138,155,230,157,165,230,186, +144,230,153,130,233,150,147,231,156,139,229,136,176,231,131,173,233,151,168,229, +133,179,233,148,174,228,184,147,229,140,186,233,157,158,229,184,184,232,139,177, +232,175,173,231,153,190,229,186,166,229,184,140,230,156,155,231,190,142,229,165, +179,230,175,148,232,190,131,231,159,165,232,175,134,232,167,132,229,174,154,229, +187,186,232,174,174,233,131,168,233,151,168,230,132,143,232,167,129,231,178,190, +229,189,169,230,151,165,230,156,172,230,143,144,233,171,152,229,143,145,232,168, +128,230,150,185,233,157,162,229,159,186,233,135,145,229,164,132,231,144,134,230, +157,131,233,153,144,229,189,177,231,137,135,233,147,182,232,161,140,232,191,152, +230,156,137,229,136,134,228,186,171,231,137,169,229,147,129,231,187,143,232,144, +165,230,183,187,229,138,160,228,184,147,229,174,182,232,191,153,231,167,141,232, +175,157,233,162,152,232,181,183,230,157,165,228,184,154,229,138,161,229,133,172, +229,145,138,232,174,176,229,189,149,231,174,128,228,187,139,232,180,168,233,135, +143,231,148,183,228,186,186,229,189,177,229,147,141,229,188,149,231,148,168,230, +138,165,229,145,138,233,131,168,229,136,134,229,191,171,233,128,159,229,146,168, +232,175,162,230,151,182,229,176,154,230,179,168,230,132,143,231,148,179,232,175, +183,229,173,166,230,160,161,229,186,148,232,175,165,229,142,134,229,143,178,229, +143,170,230,152,175,232,191,148,229,155,158,232,180,173,228,185,176,229,144,141, +231,167,176,228,184,186,228,186,134,230,136,144,229,138,159,232,175,180,230,152, +142,228,190,155,229,186,148,229,173,169,229,173,144,228,184,147,233,162,152,231, +168,139,229,186,143,228,184,128,232,136,172,230,156,131,229,147,161,229,143,170, +230,156,137,229,133,182,229,174,131,228,191,157,230,138,164,232,128,140,228,184, +148,228,187,138,229,164,169,231,170,151,229,143,163,229,138,168,230,128,129,231, +138,182,230,128,129,231,137,185,229,136,171,232,174,164,228,184,186,229,191,133, +233,161,187,230,155,180,230,150,176,229,176,143,232,175,180,230,136,145,229,128, +145,228,189,156,228,184,186,229,170,146,228,189,147,229,140,133,230,139,172,233, +130,163,228,185,136,228,184,128,230,160,183,229,155,189,229,134,133,230,152,175, +229,144,166,230,160,185,230,141,174,231,148,181,232,167,134,229,173,166,233,153, +162,229,133,183,230,156,137,232,191,135,231,168,139,231,148,177,228,186,142,228, +186,186,230,137,141,229,135,186,230,157,165,228,184,141,232,191,135,230,173,163, +229,156,168,230,152,142,230,152,159,230,149,133,228,186,139,229,133,179,231,179, +187,230,160,135,233,162,152,229,149,134,229,138,161,232,190,147,229,133,165,228, +184,128,231,155,180,229,159,186,231,161,128,230,149,153,229,173,166,228,186,134, +232,167,163,229,187,186,231,173,145,231,187,147,230,158,156,229,133,168,231,144, +131,233,128,154,231,159,165,232,174,161,229,136,146,229,175,185,228,186,142,232, +137,186,230,156,175,231,155,184,229,134,140,229,143,145,231,148,159,231,156,159, +231,154,132,229,187,186,231,171,139,231,173,137,231,186,167,231,177,187,229,158, +139,231,187,143,233,170,140,229,174,158,231,142,176,229,136,182,228,189,156,230, +157,165,232,135,170,230,160,135,231,173,190,228,187,165,228,184,139,229,142,159, +229,136,155,230,151,160,230,179,149,229,133,182,228,184,173,229,128,139,228,186, +186,228,184,128,229,136,135,230,140,135,229,141,151,229,133,179,233,151,173,233, +155,134,229,155,162,231,172,172,228,184,137,229,133,179,230,179,168,229,155,160, +230,173,164,231,133,167,231,137,135,230,183,177,229,156,179,229,149,134,228,184, +154,229,185,191,229,183,158,230,151,165,230,156,159,233,171,152,231,186,167,230, +156,128,232,191,145,231,187,188,229,144,136,232,161,168,231,164,186,228,184,147, +232,190,145,232,161,140,228,184,186,228,186,164,233,128,154,232,175,132,228,187, +183,232,167,137,229,190,151,231,178,190,229,141,142,229,174,182,229,186,173,229, +174,140,230,136,144,230,132,159,232,167,137,229,174,137,232,163,133,229,190,151, +229,136,176,233,130,174,228,187,182,229,136,182,229,186,166,233,163,159,229,147, +129,232,153,189,231,132,182,232,189,172,232,189,189,230,138,165,228,187,183,232, +174,176,232,128,133,230,150,185,230,161,136,232,161,140,230,148,191,228,186,186, +230,176,145,231,148,168,229,147,129,228,184,156,232,165,191,230,143,144,229,135, +186,233,133,146,229,186,151,231,132,182,229,144,142,228,187,152,230,172,190,231, +131,173,231,130,185,228,187,165,229,137,141,229,174,140,229,133,168,229,143,145, +229,184,150,232,174,190,231,189,174,233,162,134,229,175,188,229,183,165,228,184, +154,229,140,187,233,153,162,231,156,139,231,156,139,231,187,143,229,133,184,229, +142,159,229,155,160,229,185,179,229,143,176,229,144,132,231,167,141,229,162,158, +229,138,160,230,157,144,230,150,153,230,150,176,229,162,158,228,185,139,229,144, +142,232,129,140,228,184,154,230,149,136,230,158,156,228,187,138,229,185,180,232, +174,186,230,150,135,230,136,145,229,155,189,229,145,138,232,175,137,231,137,136, +228,184,187,228,191,174,230,148,185,229,143,130,228,184,142,230,137,147,229,141, +176,229,191,171,228,185,144,230,156,186,230,162,176,232,167,130,231,130,185,229, +173,152,229,156,168,231,178,190,231,165,158,232,142,183,229,190,151,229,136,169, +231,148,168,231,187,167,231,187,173,228,189,160,228,187,172,232,191,153,228,185, +136,230,168,161,229,188,143,232,175,173,232,168,128,232,131,189,229,164,159,233, +155,133,232,153,142,230,147,141,228,189,156,233,163,142,230,160,188,228,184,128, +232,181,183,231,167,145,229,173,166,228,189,147,232,130,178,231,159,173,228,191, +161,230,157,161,228,187,182,230,178,187,231,150,151,232,191,144,229,138,168,228, +186,167,228,184,154,228,188,154,232,174,174,229,175,188,232,136,170,229,133,136, +231,148,159,232,129,148,231,155,159,229,143,175,230,152,175,229,149,143,233,161, +140,231,187,147,230,158,132,228,189,156,231,148,168,232,176,131,230,159,165,232, +179,135,230,150,153,232,135,170,229,138,168,232,180,159,232,180,163,229,134,156, +228,184,154,232,174,191,233,151,174,229,174,158,230,150,189,230,142,165,229,143, +151,232,174,168,232,174,186,233,130,163,228,184,170,229,143,141,233,166,136,229, +138,160,229,188,186,229,165,179,230,128,167,232,140,131,229,155,180,230,156,141, +229,139,153,228,188,145,233,151,178,228,187,138,230,151,165,229,174,162,230,156, +141,232,167,128,231,156,139,229,143,130,229,138,160,231,154,132,232,175,157,228, +184,128,231,130,185,228,191,157,232,175,129,229,155,190,228,185,166,230,156,137, +230,149,136,230,181,139,232,175,149,231,167,187,229,138,168,230,137,141,232,131, +189,229,134,179,229,174,154,232,130,161,231,165,168,228,184,141,230,150,173,233, +156,128,230,177,130,228,184,141,229,190,151,229,138,158,230,179,149,228,185,139, +233,151,180,233,135,135,231,148,168,232,144,165,233,148,128,230,138,149,232,175, +137,231,155,174,230,160,135,231,136,177,230,131,133,230,145,132,229,189,177,230, +156,137,228,186,155,232,164,135,232,163,189,230,150,135,229,173,166,230,156,186, +228,188,154,230,149,176,229,173,151,232,163,133,228,191,174,232,180,173,231,137, +169,229,134,156,230,157,145,229,133,168,233,157,162,231,178,190,229,147,129,229, +133,182,229,174,158,228,186,139,230,131,133,230,176,180,229,185,179,230,143,144, +231,164,186,228,184,138,229,184,130,232,176,162,232,176,162,230,153,174,233,128, +154,230,149,153,229,184,136,228,184,138,228,188,160,231,177,187,229,136,171,230, +173,140,230,155,178,230,139,165,230,156,137,229,136,155,230,150,176,233,133,141, +228,187,182,229,143,170,232,166,129,230,151,182,228,187,163,232,179,135,232,168, +138,232,190,190,229,136,176,228,186,186,231,148,159,232,174,162,233,152,133,232, +128,129,229,184,136,229,177,149,231,164,186,229,191,131,231,144,134,232,180,180, +229,173,144,231,182,178,231,171,153,228,184,187,233,161,140,232,135,170,231,132, +182,231,186,167,229,136,171,231,174,128,229,141,149,230,148,185,233,157,169,233, +130,163,228,186,155,230,157,165,232,175,180,230,137,147,229,188,128,228,187,163, +231,160,129,229,136,160,233,153,164,232,175,129,229,136,184,232,138,130,231,155, +174,233,135,141,231,130,185,230,172,161,230,149,184,229,164,154,229,176,145,232, +167,132,229,136,146,232,181,132,233,135,145,230,137,190,229,136,176,228,187,165, +229,144,142,229,164,167,229,133,168,228,184,187,233,161,181,230,156,128,228,189, +179,229,155,158,231,173,148,229,164,169,228,184,139,228,191,157,233,154,156,231, +142,176,228,187,163,230,163,128,230,159,165,230,138,149,231,165,168,229,176,143, +230,151,182,230,178,146,230,156,137,230,173,163,229,184,184,231,148,154,232,135, +179,228,187,163,231,144,134,231,155,174,229,189,149,229,133,172,229,188,128,229, +164,141,229,136,182,233,135,145,232,158,141,229,185,184,231,166,143,231,137,136, +230,156,172,229,189,162,230,136,144,229,135,134,229,164,135,232,161,140,230,131, +133,229,155,158,229,136,176,230,128,157,230,131,179,230,128,142,230,160,183,229, +141,143,232,174,174,232,174,164,232,175,129,230,156,128,229,165,189,228,186,167, +231,148,159,230,140,137,231,133,167,230,156,141,232,163,133,229,185,191,228,184, +156,229,138,168,230,188,171,233,135,135,232,180,173,230,150,176,230,137,139,231, +187,132,229,155,190,233,157,162,230,157,191,229,143,130,232,128,131,230,148,191, +230,178,187,229,174,185,230,152,147,229,164,169,229,156,176,229,138,170,229,138, +155,228,186,186,228,187,172,229,141,135,231,186,167,233,128,159,229,186,166,228, +186,186,231,137,169,232,176,131,230,149,180,230,181,129,232,161,140,233,128,160, +230,136,144,230,150,135,229,173,151,233,159,169,229,155,189,232,180,184,230,152, +147,229,188,128,229,177,149,231,155,184,233,151,156,232,161,168,231,142,176,229, +189,177,232,167,134,229,166,130,230,173,164,231,190,142,229,174,185,229,164,167, +229,176,143,230,138,165,233,129,147,230,157,161,230,172,190,229,191,131,230,131, +133,232,174,184,229,164,154,230,179,149,232,167,132,229,174,182,229,177,133,228, +185,166,229,186,151,232,191,158,230,142,165,231,171,139,229,141,179,228,184,190, +230,138,165,230,138,128,229,183,167,229,165,165,232,191,144,231,153,187,229,133, +165,228,187,165,230,157,165,231,144,134,232,174,186,228,186,139,228,187,182,232, +135,170,231,148,177,228,184,173,229,141,142,229,138,158,229,133,172,229,166,136, +229,166,136,231,156,159,230,173,163,228,184,141,233,148,153,229,133,168,230,150, +135,229,144,136,229,144,140,228,187,183,229,128,188,229,136,171,228,186,186,231, +155,145,231,157,163,229,133,183,228,189,147,228,184,150,231,186,170,229,155,162, +233,152,159,229,136,155,228,184,154,230,137,191,230,139,133,229,162,158,233,149, +191,230,156,137,228,186,186,228,191,157,230,140,129,229,149,134,229,174,182,231, +187,180,228,191,174,229,143,176,230,185,190,229,183,166,229,143,179,232,130,161, +228,187,189,231,173,148,230,161,136,229,174,158,233,153,133,231,148,181,228,191, +161,231,187,143,231,144,134,231,148,159,229,145,189,229,174,163,228,188,160,228, +187,187,229,138,161,230,173,163,229,188,143,231,137,185,232,137,178,228,184,139, +230,157,165,229,141,143,228,188,154,229,143,170,232,131,189,229,189,147,231,132, +182,233,135,141,230,150,176,229,133,167,229,174,185,230,140,135,229,175,188,232, +191,144,232,161,140,230,151,165,229,191,151,232,179,163,229,174,182,232,182,133, +232,191,135,229,156,159,229,156,176,230,181,153,230,177,159,230,148,175,228,187, +152,230,142,168,229,135,186,231,171,153,233,149,191,230,157,173,229,183,158,230, +137,167,232,161,140,229,136,182,233,128,160,228,185,139,228,184,128,230,142,168, +229,185,191,231,142,176,229,156,186,230,143,143,232,191,176,229,143,152,229,140, +150,228,188,160,231,187,159,230,173,140,230,137,139,228,191,157,233,153,169,232, +175,190,231,168,139,229,140,187,231,150,151,231,187,143,232,191,135,232,191,135, +229,142,187,228,185,139,229,137,141,230,148,182,229,133,165,229,185,180,229,186, +166,230,157,130,229,191,151,231,190,142,228,184,189,230,156,128,233,171,152,231, +153,187,233,153,134,230,156,170,230,157,165,229,138,160,229,183,165,229,133,141, +232,180,163,230,149,153,231,168,139,231,137,136,229,157,151,232,186,171,228,189, +147,233,135,141,229,186,134,229,135,186,229,148,174,230,136,144,230,156,172,229, +189,162,229,188,143,229,156,159,232,177,134,229,135,186,229,131,185,228,184,156, +230,150,185,233,130,174,231,174,177,229,141,151,228,186,172,230,177,130,232,129, +140,229,143,150,229,190,151,232,129,140,228,189,141,231,155,184,228,191,161,233, +161,181,233,157,162,229,136,134,233,146,159,231,189,145,233,161,181,231,161,174, +229,174,154,229,155,190,228,190,139,231,189,145,229,157,128,231,167,175,230,158, +129,233,148,153,232,175,175,231,155,174,231,154,132,229,174,157,232,180,157,230, +156,186,229,133,179,233,163,142,233,153,169,230,142,136,230,157,131,231,151,133, +230,175,146,229,174,160,231,137,169,233,153,164,228,186,134,232,169,149,232,171, +150,231,150,190,231,151,133,229,143,138,230,151,182,230,177,130,232,180,173,231, +171,153,231,130,185,229,132,191,231,171,165,230,175,143,229,164,169,228,184,173, +229,164,174,232,174,164,232,175,134,230,175,143,228,184,170,229,164,169,230,180, +165,229,173,151,228,189,147,229,143,176,231,129,163,231,187,180,230,138,164,230, +156,172,233,161,181,228,184,170,230,128,167,229,174,152,230,150,185,229,184,184, +232,167,129,231,155,184,230,156,186,230,136,152,231,149,165,229,186,148,229,189, +147,229,190,139,229,184,136,230,150,185,228,190,191,230,160,161,229,155,173,232, +130,161,229,184,130,230,136,191,229,177,139,230,160,143,231,155,174,229,145,152, +229,183,165,229,175,188,232,135,180,231,170,129,231,132,182,233,129,147,229,133, +183,230,156,172,231,189,145,231,187,147,229,144,136,230,161,163,230,161,136,229, +138,179,229,138,168,229,143,166,229,164,150,231,190,142,229,133,131,229,188,149, +232,181,183,230,148,185,229,143,152,231,172,172,229,155,155,228,188,154,232,174, +161,232,170,170,230,152,142,233,154,144,231,167,129,229,174,157,229,174,157,232, +167,132,232,140,131,230,182,136,232,180,185,229,133,177,229,144,140,229,191,152, +232,174,176,228,189,147,231,179,187,229,184,166,230,157,165,229,144,141,229,173, +151,231,153,188,232,161,168,229,188,128,230,148,190,229,138,160,231,155,159,229, +143,151,229,136,176,228,186,140,230,137,139,229,164,167,233,135,143,230,136,144, +228,186,186,230,149,176,233,135,143,229,133,177,228,186,171,229,140,186,229,159, +159,229,165,179,229,173,169,229,142,159,229,136,153,230,137,128,229,156,168,231, +187,147,230,157,159,233,128,154,228,191,161,232,182,133,231,186,167,233,133,141, +231,189,174,229,189,147,230,151,182,228,188,152,231,167,128,230,128,167,230,132, +159,230,136,191,228,186,167,233,129,138,230,136,178,229,135,186,229,143,163,230, +143,144,228,186,164,229,176,177,228,184,154,228,191,157,229,129,165,231,168,139, +229,186,166,229,143,130,230,149,176,228,186,139,228,184,154,230,149,180,228,184, +170,229,177,177,228,184,156,230,131,133,230,132,159,231,137,185,230,174,138,229, +136,134,233,161,158,230,144,156,229,176,139,229,177,158,228,186,142,233,151,168, +230,136,183,232,180,162,229,138,161,229,163,176,233,159,179,229,143,138,229,133, +182,232,180,162,231,187,143,229,157,154,230,140,129,229,185,178,233,131,168,230, +136,144,231,171,139,229,136,169,231,155,138,232,128,131,232,153,145,230,136,144, +233,131,189,229,140,133,232,163,133,231,148,168,230,136,182,230,175,148,232,181, +155,230,150,135,230,152,142,230,139,155,229,149,134,229,174,140,230,149,180,231, +156,159,230,152,175,231,156,188,231,157,155,228,188,153,228,188,180,229,168,129, +230,156,155,233,162,134,229,159,159,229,141,171,231,148,159,228,188,152,230,131, +160,232,171,150,229,163,135,229,133,172,229,133,177,232,137,175,229,165,189,229, +133,133,229,136,134,231,172,166,229,144,136,233,153,132,228,187,182,231,137,185, +231,130,185,228,184,141,229,143,175,232,139,177,230,150,135,232,181,132,228,186, +167,230,160,185,230,156,172,230,152,142,230,152,190,229,175,134,231,162,188,229, +133,172,228,188,151,230,176,145,230,151,143,230,155,180,229,138,160,228,186,171, +229,143,151,229,144,140,229,173,166,229,144,175,229,138,168,233,128,130,229,144, +136,229,142,159,230,157,165,233,151,174,231,173,148,230,156,172,230,150,135,231, +190,142,233,163,159,231,187,191,232,137,178,231,168,179,229,174,154,231,187,136, +228,186,142,231,148,159,231,137,169,228,190,155,230,177,130,230,144,156,231,139, +144,229,138,155,233,135,143,228,184,165,233,135,141,230,176,184,232,191,156,229, +134,153,231,156,159,230,156,137,233,153,144,231,171,158,228,186,137,229,175,185, +232,177,161,232,180,185,231,148,168,228,184,141,229,165,189,231,187,157,229,175, +185,229,141,129,229,136,134,228,191,131,232,191,155,231,130,185,232,175,132,229, +189,177,233,159,179,228,188,152,229,138,191,228,184,141,229,176,145,230,172,163, +232,181,143,229,185,182,228,184,148,230,156,137,231,130,185,230,150,185,229,144, +145,229,133,168,230,150,176,228,191,161,231,148,168,232,174,190,230,150,189,229, +189,162,232,177,161,232,181,132,230,160,188,231,170,129,231,160,180,233,154,143, +231,157,128,233,135,141,229,164,167,228,186,142,230,152,175,230,175,149,228,184, +154,230,153,186,232,131,189,229,140,150,229,183,165,229,174,140,231,190,142,229, +149,134,229,159,142,231,187,159,228,184,128,229,135,186,231,137,136,230,137,147, +233,128,160,231,148,162,229,147,129,230,166,130,229,134,181,231,148,168,228,186, +142,228,191,157,231,149,153,229,155,160,231,180,160,228,184,173,229,156,139,229, +173,152,229,130,168,232,180,180,229,155,190,230,156,128,230,132,155,233,149,191, +230,156,159,229,143,163,228,187,183,231,144,134,232,180,162,229,159,186,229,156, +176,229,174,137,230,142,146,230,173,166,230,177,137,233,135,140,233,157,162,229, +136,155,229,187,186,229,164,169,231,169,186,233,166,150,229,133,136,229,174,140, +229,150,132,233,169,177,229,138,168,228,184,139,233,157,162,228,184,141,229,134, +141,232,175,154,228,191,161,230,132,143,228,185,137,233,152,179,229,133,137,232, +139,177,229,155,189,230,188,130,228,186,174,229,134,155,228,186,139,231,142,169, +229,174,182,231,190,164,228,188,151,229,134,156,230,176,145,229,141,179,229,143, +175,229,144,141,231,168,177,229,174,182,229,133,183,229,138,168,231,148,187,230, +131,179,229,136,176,230,179,168,230,152,142,229,176,143,229,173,166,230,128,167, +232,131,189,232,128,131,231,160,148,231,161,172,228,187,182,232,167,130,231,156, +139,230,184,133,230,165,154,230,144,158,231,172,145,233,166,150,233,160,129,233, +187,132,233,135,145,233,128,130,231,148,168,230,177,159,232,139,143,231,156,159, +229,174,158,228,184,187,231,174,161,233,152,182,230,174,181,232,168,187,229,134, +138,231,191,187,232,175,145,230,157,131,229,136,169,229,129,154,229,165,189,228, +188,188,228,185,142,233,128,154,232,174,175,230,150,189,229,183,165,231,139,128, +230,133,139,228,185,159,232,174,184,231,142,175,228,191,157,229,159,185,229,133, +187,230,166,130,229,191,181,229,164,167,229,158,139,230,156,186,231,165,168,231, +144,134,232,167,163,229,140,191,229,144,141,99,117,97,110,100,111,101,110,118, +105,97,114,109,97,100,114,105,100,98,117,115,99,97,114,105,110,105,99,105,111, +116,105,101,109,112,111,112,111,114,113,117,101,99,117,101,110,116,97,101,115, +116,97,100,111,112,117,101,100,101,110,106,117,101,103,111,115,99,111,110,116, +114,97,101,115,116,195,161,110,110,111,109,98,114,101,116,105,101,110,101,110, +112,101,114,102,105,108,109,97,110,101,114,97,97,109,105,103,111,115,99,105,117, +100,97,100,99,101,110,116,114,111,97,117,110,113,117,101,112,117,101,100,101,115 +,100,101,110,116,114,111,112,114,105,109,101,114,112,114,101,99,105,111,115,101, +103,195,186,110,98,117,101,110,111,115,118,111,108,118,101,114,112,117,110,116, +111,115,115,101,109,97,110,97,104,97,98,195,173,97,97,103,111,115,116,111,110, +117,101,118,111,115,117,110,105,100,111,115,99,97,114,108,111,115,101,113,117, +105,112,111,110,105,195,177,111,115,109,117,99,104,111,115,97,108,103,117,110,97 +,99,111,114,114,101,111,105,109,97,103,101,110,112,97,114,116,105,114,97,114,114 +,105,98,97,109,97,114,195,173,97,104,111,109,98,114,101,101,109,112,108,101,111, +118,101,114,100,97,100,99,97,109,98,105,111,109,117,99,104,97,115,102,117,101, +114,111,110,112,97,115,97,100,111,108,195,173,110,101,97,112,97,114,101,99,101, +110,117,101,118,97,115,99,117,114,115,111,115,101,115,116,97,98,97,113,117,105, +101,114,111,108,105,98,114,111,115,99,117,97,110,116,111,97,99,99,101,115,111, +109,105,103,117,101,108,118,97,114,105,111,115,99,117,97,116,114,111,116,105,101 +,110,101,115,103,114,117,112,111,115,115,101,114,195,161,110,101,117,114,111,112 +,97,109,101,100,105,111,115,102,114,101,110,116,101,97,99,101,114,99,97,100,101, +109,195,161,115,111,102,101,114,116,97,99,111,99,104,101,115,109,111,100,101,108 +,111,105,116,97,108,105,97,108,101,116,114,97,115,97,108,103,195,186,110,99,111, +109,112,114,97,99,117,97,108,101,115,101,120,105,115,116,101,99,117,101,114,112, +111,115,105,101,110,100,111,112,114,101,110,115,97,108,108,101,103,97,114,118, +105,97,106,101,115,100,105,110,101,114,111,109,117,114,99,105,97,112,111,100,114 +,195,161,112,117,101,115,116,111,100,105,97,114,105,111,112,117,101,98,108,111, +113,117,105,101,114,101,109,97,110,117,101,108,112,114,111,112,105,111,99,114, +105,115,105,115,99,105,101,114,116,111,115,101,103,117,114,111,109,117,101,114, +116,101,102,117,101,110,116,101,99,101,114,114,97,114,103,114,97,110,100,101,101 +,102,101,99,116,111,112,97,114,116,101,115,109,101,100,105,100,97,112,114,111, +112,105,97,111,102,114,101,99,101,116,105,101,114,114,97,101,45,109,97,105,108, +118,97,114,105,97,115,102,111,114,109,97,115,102,117,116,117,114,111,111,98,106, +101,116,111,115,101,103,117,105,114,114,105,101,115,103,111,110,111,114,109,97, +115,109,105,115,109,111,115,195,186,110,105,99,111,99,97,109,105,110,111,115,105 +,116,105,111,115,114,97,122,195,179,110,100,101,98,105,100,111,112,114,117,101, +98,97,116,111,108,101,100,111,116,101,110,195,173,97,106,101,115,195,186,115,101 +,115,112,101,114,111,99,111,99,105,110,97,111,114,105,103,101,110,116,105,101, +110,100,97,99,105,101,110,116,111,99,195,161,100,105,122,104,97,98,108,97,114, +115,101,114,195,173,97,108,97,116,105,110,97,102,117,101,114,122,97,101,115,116, +105,108,111,103,117,101,114,114,97,101,110,116,114,97,114,195,169,120,105,116, +111,108,195,179,112,101,122,97,103,101,110,100,97,118,195,173,100,101,111,101, +118,105,116,97,114,112,97,103,105,110,97,109,101,116,114,111,115,106,97,118,105, +101,114,112,97,100,114,101,115,102,195,161,99,105,108,99,97,98,101,122,97,195, +161,114,101,97,115,115,97,108,105,100,97,101,110,118,195,173,111,106,97,112,195, +179,110,97,98,117,115,111,115,98,105,101,110,101,115,116,101,120,116,111,115,108 +,108,101,118,97,114,112,117,101,100,97,110,102,117,101,114,116,101,99,111,109, +195,186,110,99,108,97,115,101,115,104,117,109,97,110,111,116,101,110,105,100,111 +,98,105,108,98,97,111,117,110,105,100,97,100,101,115,116,195,161,115,101,100,105 +,116,97,114,99,114,101,97,100,111,208,180,208,187,209,143,209,135,209,130,208, +190,208,186,208,176,208,186,208,184,208,187,208,184,209,141,209,130,208,190,208, +178,209,129,208,181,208,181,208,179,208,190,208,191,209,128,208,184,209,130,208, +176,208,186,208,181,209,137,208,181,209,131,208,182,208,181,208,154,208,176,208, +186,208,177,208,181,208,183,208,177,209,139,208,187,208,190,208,189,208,184,208, +146,209,129,208,181,208,191,208,190,208,180,208,173,209,130,208,190,209,130,208, +190,208,188,209,135,208,181,208,188,208,189,208,181,209,130,208,187,208,181,209, +130,209,128,208,176,208,183,208,190,208,189,208,176,208,179,208,180,208,181,208, +188,208,189,208,181,208,148,208,187,209,143,208,159,209,128,208,184,208,189,208, +176,209,129,208,189,208,184,209,133,209,130,208,181,208,188,208,186,209,130,208, +190,208,179,208,190,208,180,208,178,208,190,209,130,209,130,208,176,208,188,208, +161,208,168,208,144,208,188,208,176,209,143,208,167,209,130,208,190,208,178,208, +176,209,129,208,178,208,176,208,188,208,181,208,188,209,131,208,162,208,176,208, +186,208,180,208,178,208,176,208,189,208,176,208,188,209,141,209,130,208,184,209, +141,209,130,209,131,208,146,208,176,208,188,209,130,208,181,209,133,208,191,209, +128,208,190,209,130,209,131,209,130,208,189,208,176,208,180,208,180,208,189,209, +143,208,146,208,190,209,130,209,130,209,128,208,184,208,189,208,181,208,185,208, +146,208,176,209,129,208,189,208,184,208,188,209,129,208,176,208,188,209,130,208, +190,209,130,209,128,209,131,208,177,208,158,208,189,208,184,208,188,208,184,209, +128,208,189,208,181,208,181,208,158,208,158,208,158,208,187,208,184,209,134,209, +141,209,130,208,176,208,158,208,189,208,176,208,189,208,181,208,188,208,180,208, +190,208,188,208,188,208,190,208,185,208,180,208,178,208,181,208,190,208,189,208, +190,209,129,209,131,208,180,224,164,149,224,165,135,224,164,185,224,165,136,224, +164,149,224,165,128,224,164,184,224,165,135,224,164,149,224,164,190,224,164,149, +224,165,139,224,164,148,224,164,176,224,164,170,224,164,176,224,164,168,224,165, +135,224,164,143,224,164,149,224,164,149,224,164,191,224,164,173,224,165,128,224, +164,135,224,164,184,224,164,149,224,164,176,224,164,164,224,165,139,224,164,185, +224,165,139,224,164,134,224,164,170,224,164,185,224,165,128,224,164,175,224,164, +185,224,164,175,224,164,190,224,164,164,224,164,149,224,164,165,224,164,190,106, +97,103,114,97,110,224,164,134,224,164,156,224,164,156,224,165,139,224,164,133, +224,164,172,224,164,166,224,165,139,224,164,151,224,164,136,224,164,156,224,164, +190,224,164,151,224,164,143,224,164,185,224,164,174,224,164,135,224,164,168,224, +164,181,224,164,185,224,164,175,224,165,135,224,164,165,224,165,135,224,164,165, +224,165,128,224,164,152,224,164,176,224,164,156,224,164,172,224,164,166,224,165, +128,224,164,149,224,164,136,224,164,156,224,165,128,224,164,181,224,165,135,224, +164,168,224,164,136,224,164,168,224,164,143,224,164,185,224,164,176,224,164,137, +224,164,184,224,164,174,224,165,135,224,164,149,224,164,174,224,164,181,224,165, +139,224,164,178,224,165,135,224,164,184,224,164,172,224,164,174,224,164,136,224, +164,166,224,165,135,224,164,147,224,164,176,224,164,134,224,164,174,224,164,172, +224,164,184,224,164,173,224,164,176,224,164,172,224,164,168,224,164,154,224,164, +178,224,164,174,224,164,168,224,164,134,224,164,151,224,164,184,224,165,128,224, +164,178,224,165,128,216,185,217,132,217,137,216,165,217,132,217,137,217,135,216, +176,216,167,216,162,216,174,216,177,216,185,216,175,216,175,216,167,217,132,217, +137,217,135,216,176,217,135,216,181,217,136,216,177,216,186,217,138,216,177,217, +131,216,167,217,134,217,136,217,132,216,167,216,168,217,138,217,134,216,185,216, +177,216,182,216,176,217,132,217,131,217,135,217,134,216,167,217,138,217,136,217, +133,217,130,216,167,217,132,216,185,217,132,217,138,216,167,217,134,216,167,217, +132,217,131,217,134,216,173,216,170,217,137,217,130,216,168,217,132,217,136,216, +173,216,169,216,167,216,174,216,177,217,129,217,130,216,183,216,185,216,168,216, +175,216,177,217,131,217,134,216,165,216,176,216,167,217,131,217,133,216,167,216, +167,216,173,216,175,216,165,217,132,216,167,217,129,217,138,217,135,216,168,216, +185,216,182,217,131,217,138,217,129,216,168,216,173,216,171,217,136,217,133,217, +134,217,136,217,135,217,136,216,163,217,134,216,167,216,172,216,175,216,167,217, +132,217,135,216,167,216,179,217,132,217,133,216,185,217,134,216,175,217,132,217, +138,216,179,216,185,216,168,216,177,216,181,217,132,217,137,217,133,217,134,216, +176,216,168,217,135,216,167,216,163,217,134,217,135,217,133,216,171,217,132,217, +131,217,134,216,170,216,167,217,132,216,167,216,173,217,138,216,171,217,133,216, +181,216,177,216,180,216,177,216,173,216,173,217,136,217,132,217,136,217,129,217, +138,216,167,216,176,216,167,217,132,217,131,217,132,217,133,216,177,216,169,216, +167,217,134,216,170,216,167,217,132,217,129,216,163,216,168,217,136,216,174,216, +167,216,181,216,163,217,134,216,170,216,167,217,134,217,135,216,167,217,132,217, +138,216,185,216,182,217,136,217,136,217,130,216,175,216,167,216,168,217,134,216, +174,217,138,216,177,216,168,217,134,216,170,217,132,217,131,217,133,216,180,216, +167,216,161,217,136,217,135,217,138,216,167,216,168,217,136,217,130,216,181,216, +181,217,136,217,133,216,167,216,177,217,130,217,133,216,163,216,173,216,175,217, +134,216,173,217,134,216,185,216,175,217,133,216,177,216,163,217,138,216,167,216, +173,216,169,217,131,216,170,216,168,216,175,217,136,217,134,217,138,216,172,216, +168,217,133,217,134,217,135,216,170,216,173,216,170,216,172,217,135,216,169,216, +179,217,134,216,169,217,138,216,170,217,133,217,131,216,177,216,169,216,186,216, +178,216,169,217,134,217,129,216,179,216,168,217,138,216,170,217,132,217,132,217, +135,217,132,217,134,216,167,216,170,217,132,217,131,217,130,217,132,216,168,217, +132,217,133,216,167,216,185,217,134,217,135,216,163,217,136,217,132,216,180,217, +138,216,161,217,134,217,136,216,177,216,163,217,133,216,167,217,129,217,138,217, +131,216,168,217,131,217,132,216,176,216,167,216,170,216,177,216,170,216,168,216, +168,216,163,217,134,217,135,217,133,216,179,216,167,217,134,217,131,216,168,217, +138,216,185,217,129,217,130,216,175,216,173,216,179,217,134,217,132,217,135,217, +133,216,180,216,185,216,177,216,163,217,135,217,132,216,180,217,135,216,177,217, +130,216,183,216,177,216,183,217,132,216,168,112,114,111,102,105,108,101,115,101, +114,118,105,99,101,100,101,102,97,117,108,116,104,105,109,115,101,108,102,100, +101,116,97,105,108,115,99,111,110,116,101,110,116,115,117,112,112,111,114,116, +115,116,97,114,116,101,100,109,101,115,115,97,103,101,115,117,99,99,101,115,115, +102,97,115,104,105,111,110,60,116,105,116,108,101,62,99,111,117,110,116,114,121, +97,99,99,111,117,110,116,99,114,101,97,116,101,100,115,116,111,114,105,101,115, +114,101,115,117,108,116,115,114,117,110,110,105,110,103,112,114,111,99,101,115, +115,119,114,105,116,105,110,103,111,98,106,101,99,116,115,118,105,115,105,98,108 +,101,119,101,108,99,111,109,101,97,114,116,105,99,108,101,117,110,107,110,111, +119,110,110,101,116,119,111,114,107,99,111,109,112,97,110,121,100,121,110,97,109 +,105,99,98,114,111,119,115,101,114,112,114,105,118,97,99,121,112,114,111,98,108, +101,109,83,101,114,118,105,99,101,114,101,115,112,101,99,116,100,105,115,112,108 +,97,121,114,101,113,117,101,115,116,114,101,115,101,114,118,101,119,101,98,115, +105,116,101,104,105,115,116,111,114,121,102,114,105,101,110,100,115,111,112,116, +105,111,110,115,119,111,114,107,105,110,103,118,101,114,115,105,111,110,109,105, +108,108,105,111,110,99,104,97,110,110,101,108,119,105,110,100,111,119,46,97,100, +100,114,101,115,115,118,105,115,105,116,101,100,119,101,97,116,104,101,114,99, +111,114,114,101,99,116,112,114,111,100,117,99,116,101,100,105,114,101,99,116,102 +,111,114,119,97,114,100,121,111,117,32,99,97,110,114,101,109,111,118,101,100,115 +,117,98,106,101,99,116,99,111,110,116,114,111,108,97,114,99,104,105,118,101,99, +117,114,114,101,110,116,114,101,97,100,105,110,103,108,105,98,114,97,114,121,108 +,105,109,105,116,101,100,109,97,110,97,103,101,114,102,117,114,116,104,101,114, +115,117,109,109,97,114,121,109,97,99,104,105,110,101,109,105,110,117,116,101,115 +,112,114,105,118,97,116,101,99,111,110,116,101,120,116,112,114,111,103,114,97, +109,115,111,99,105,101,116,121,110,117,109,98,101,114,115,119,114,105,116,116, +101,110,101,110,97,98,108,101,100,116,114,105,103,103,101,114,115,111,117,114,99 +,101,115,108,111,97,100,105,110,103,101,108,101,109,101,110,116,112,97,114,116, +110,101,114,102,105,110,97,108,108,121,112,101,114,102,101,99,116,109,101,97,110 +,105,110,103,115,121,115,116,101,109,115,107,101,101,112,105,110,103,99,117,108, +116,117,114,101,38,113,117,111,116,59,44,106,111,117,114,110,97,108,112,114,111, +106,101,99,116,115,117,114,102,97,99,101,115,38,113,117,111,116,59,101,120,112, +105,114,101,115,114,101,118,105,101,119,115,98,97,108,97,110,99,101,69,110,103, +108,105,115,104,67,111,110,116,101,110,116,116,104,114,111,117,103,104,80,108, +101,97,115,101,32,111,112,105,110,105,111,110,99,111,110,116,97,99,116,97,118, +101,114,97,103,101,112,114,105,109,97,114,121,118,105,108,108,97,103,101,83,112, +97,110,105,115,104,103,97,108,108,101,114,121,100,101,99,108,105,110,101,109,101 +,101,116,105,110,103,109,105,115,115,105,111,110,112,111,112,117,108,97,114,113, +117,97,108,105,116,121,109,101,97,115,117,114,101,103,101,110,101,114,97,108,115 +,112,101,99,105,101,115,115,101,115,115,105,111,110,115,101,99,116,105,111,110, +119,114,105,116,101,114,115,99,111,117,110,116,101,114,105,110,105,116,105,97, +108,114,101,112,111,114,116,115,102,105,103,117,114,101,115,109,101,109,98,101, +114,115,104,111,108,100,105,110,103,100,105,115,112,117,116,101,101,97,114,108, +105,101,114,101,120,112,114,101,115,115,100,105,103,105,116,97,108,112,105,99, +116,117,114,101,65,110,111,116,104,101,114,109,97,114,114,105,101,100,116,114,97 +,102,102,105,99,108,101,97,100,105,110,103,99,104,97,110,103,101,100,99,101,110, +116,114,97,108,118,105,99,116,111,114,121,105,109,97,103,101,115,47,114,101,97, +115,111,110,115,115,116,117,100,105,101,115,102,101,97,116,117,114,101,108,105, +115,116,105,110,103,109,117,115,116,32,98,101,115,99,104,111,111,108,115,86,101, +114,115,105,111,110,117,115,117,97,108,108,121,101,112,105,115,111,100,101,112, +108,97,121,105,110,103,103,114,111,119,105,110,103,111,98,118,105,111,117,115, +111,118,101,114,108,97,121,112,114,101,115,101,110,116,97,99,116,105,111,110,115 +,60,47,117,108,62,13,10,119,114,97,112,112,101,114,97,108,114,101,97,100,121,99, +101,114,116,97,105,110,114,101,97,108,105,116,121,115,116,111,114,97,103,101,97, +110,111,116,104,101,114,100,101,115,107,116,111,112,111,102,102,101,114,101,100, +112,97,116,116,101,114,110,117,110,117,115,117,97,108,68,105,103,105,116,97,108, +99,97,112,105,116,97,108,87,101,98,115,105,116,101,102,97,105,108,117,114,101,99 +,111,110,110,101,99,116,114,101,100,117,99,101,100,65,110,100,114,111,105,100, +100,101,99,97,100,101,115,114,101,103,117,108,97,114,32,38,97,109,112,59,32,97, +110,105,109,97,108,115,114,101,108,101,97,115,101,65,117,116,111,109,97,116,103, +101,116,116,105,110,103,109,101,116,104,111,100,115,110,111,116,104,105,110,103, +80,111,112,117,108,97,114,99,97,112,116,105,111,110,108,101,116,116,101,114,115, +99,97,112,116,117,114,101,115,99,105,101,110,99,101,108,105,99,101,110,115,101, +99,104,97,110,103,101,115,69,110,103,108,97,110,100,61,49,38,97,109,112,59,72, +105,115,116,111,114,121,32,61,32,110,101,119,32,67,101,110,116,114,97,108,117, +112,100,97,116,101,100,83,112,101,99,105,97,108,78,101,116,119,111,114,107,114, +101,113,117,105,114,101,99,111,109,109,101,110,116,119,97,114,110,105,110,103,67 +,111,108,108,101,103,101,116,111,111,108,98,97,114,114,101,109,97,105,110,115,98 +,101,99,97,117,115,101,101,108,101,99,116,101,100,68,101,117,116,115,99,104,102, +105,110,97,110,99,101,119,111,114,107,101,114,115,113,117,105,99,107,108,121,98, +101,116,119,101,101,110,101,120,97,99,116,108,121,115,101,116,116,105,110,103, +100,105,115,101,97,115,101,83,111,99,105,101,116,121,119,101,97,112,111,110,115, +101,120,104,105,98,105,116,38,108,116,59,33,45,45,67,111,110,116,114,111,108,99, +108,97,115,115,101,115,99,111,118,101,114,101,100,111,117,116,108,105,110,101,97 +,116,116,97,99,107,115,100,101,118,105,99,101,115,40,119,105,110,100,111,119,112 +,117,114,112,111,115,101,116,105,116,108,101,61,34,77,111,98,105,108,101,32,107, +105,108,108,105,110,103,115,104,111,119,105,110,103,73,116,97,108,105,97,110,100 +,114,111,112,112,101,100,104,101,97,118,105,108,121,101,102,102,101,99,116,115, +45,49,39,93,41,59,10,99,111,110,102,105,114,109,67,117,114,114,101,110,116,97, +100,118,97,110,99,101,115,104,97,114,105,110,103,111,112,101,110,105,110,103,100 +,114,97,119,105,110,103,98,105,108,108,105,111,110,111,114,100,101,114,101,100, +71,101,114,109,97,110,121,114,101,108,97,116,101,100,60,47,102,111,114,109,62, +105,110,99,108,117,100,101,119,104,101,116,104,101,114,100,101,102,105,110,101, +100,83,99,105,101,110,99,101,99,97,116,97,108,111,103,65,114,116,105,99,108,101, +98,117,116,116,111,110,115,108,97,114,103,101,115,116,117,110,105,102,111,114, +109,106,111,117,114,110,101,121,115,105,100,101,98,97,114,67,104,105,99,97,103, +111,104,111,108,105,100,97,121,71,101,110,101,114,97,108,112,97,115,115,97,103, +101,44,38,113,117,111,116,59,97,110,105,109,97,116,101,102,101,101,108,105,110, +103,97,114,114,105,118,101,100,112,97,115,115,105,110,103,110,97,116,117,114,97, +108,114,111,117,103,104,108,121,46,10,10,84,104,101,32,98,117,116,32,110,111,116 +,100,101,110,115,105,116,121,66,114,105,116,97,105,110,67,104,105,110,101,115, +101,108,97,99,107,32,111,102,116,114,105,98,117,116,101,73,114,101,108,97,110, +100,34,32,100,97,116,97,45,102,97,99,116,111,114,115,114,101,99,101,105,118,101, +116,104,97,116,32,105,115,76,105,98,114,97,114,121,104,117,115,98,97,110,100,105 +,110,32,102,97,99,116,97,102,102,97,105,114,115,67,104,97,114,108,101,115,114,97 +,100,105,99,97,108,98,114,111,117,103,104,116,102,105,110,100,105,110,103,108,97 +,110,100,105,110,103,58,108,97,110,103,61,34,114,101,116,117,114,110,32,108,101, +97,100,101,114,115,112,108,97,110,110,101,100,112,114,101,109,105,117,109,112,97 +,99,107,97,103,101,65,109,101,114,105,99,97,69,100,105,116,105,111,110,93,38,113 +,117,111,116,59,77,101,115,115,97,103,101,110,101,101,100,32,116,111,118,97,108, +117,101,61,34,99,111,109,112,108,101,120,108,111,111,107,105,110,103,115,116,97, +116,105,111,110,98,101,108,105,101,118,101,115,109,97,108,108,101,114,45,109,111 +,98,105,108,101,114,101,99,111,114,100,115,119,97,110,116,32,116,111,107,105,110 +,100,32,111,102,70,105,114,101,102,111,120,121,111,117,32,97,114,101,115,105,109 +,105,108,97,114,115,116,117,100,105,101,100,109,97,120,105,109,117,109,104,101, +97,100,105,110,103,114,97,112,105,100,108,121,99,108,105,109,97,116,101,107,105, +110,103,100,111,109,101,109,101,114,103,101,100,97,109,111,117,110,116,115,102, +111,117,110,100,101,100,112,105,111,110,101,101,114,102,111,114,109,117,108,97, +100,121,110,97,115,116,121,104,111,119,32,116,111,32,83,117,112,112,111,114,116, +114,101,118,101,110,117,101,101,99,111,110,111,109,121,82,101,115,117,108,116, +115,98,114,111,116,104,101,114,115,111,108,100,105,101,114,108,97,114,103,101, +108,121,99,97,108,108,105,110,103,46,38,113,117,111,116,59,65,99,99,111,117,110, +116,69,100,119,97,114,100,32,115,101,103,109,101,110,116,82,111,98,101,114,116, +32,101,102,102,111,114,116,115,80,97,99,105,102,105,99,108,101,97,114,110,101, +100,117,112,32,119,105,116,104,104,101,105,103,104,116,58,119,101,32,104,97,118, +101,65,110,103,101,108,101,115,110,97,116,105,111,110,115,95,115,101,97,114,99, +104,97,112,112,108,105,101,100,97,99,113,117,105,114,101,109,97,115,115,105,118, +101,103,114,97,110,116,101,100,58,32,102,97,108,115,101,116,114,101,97,116,101, +100,98,105,103,103,101,115,116,98,101,110,101,102,105,116,100,114,105,118,105, +110,103,83,116,117,100,105,101,115,109,105,110,105,109,117,109,112,101,114,104, +97,112,115,109,111,114,110,105,110,103,115,101,108,108,105,110,103,105,115,32, +117,115,101,100,114,101,118,101,114,115,101,118,97,114,105,97,110,116,32,114,111 +,108,101,61,34,109,105,115,115,105,110,103,97,99,104,105,101,118,101,112,114,111 +,109,111,116,101,115,116,117,100,101,110,116,115,111,109,101,111,110,101,101,120 +,116,114,101,109,101,114,101,115,116,111,114,101,98,111,116,116,111,109,58,101, +118,111,108,118,101,100,97,108,108,32,116,104,101,115,105,116,101,109,97,112,101 +,110,103,108,105,115,104,119,97,121,32,116,111,32,32,65,117,103,117,115,116,115, +121,109,98,111,108,115,67,111,109,112,97,110,121,109,97,116,116,101,114,115,109, +117,115,105,99,97,108,97,103,97,105,110,115,116,115,101,114,118,105,110,103,125, +41,40,41,59,13,10,112,97,121,109,101,110,116,116,114,111,117,98,108,101,99,111, +110,99,101,112,116,99,111,109,112,97,114,101,112,97,114,101,110,116,115,112,108, +97,121,101,114,115,114,101,103,105,111,110,115,109,111,110,105,116,111,114,32,39 +,39,84,104,101,32,119,105,110,110,105,110,103,101,120,112,108,111,114,101,97,100 +,97,112,116,101,100,71,97,108,108,101,114,121,112,114,111,100,117,99,101,97,98, +105,108,105,116,121,101,110,104,97,110,99,101,99,97,114,101,101,114,115,41,46,32 +,84,104,101,32,99,111,108,108,101,99,116,83,101,97,114,99,104,32,97,110,99,105, +101,110,116,101,120,105,115,116,101,100,102,111,111,116,101,114,32,104,97,110, +100,108,101,114,112,114,105,110,116,101,100,99,111,110,115,111,108,101,69,97,115 +,116,101,114,110,101,120,112,111,114,116,115,119,105,110,100,111,119,115,67,104, +97,110,110,101,108,105,108,108,101,103,97,108,110,101,117,116,114,97,108,115,117 +,103,103,101,115,116,95,104,101,97,100,101,114,115,105,103,110,105,110,103,46, +104,116,109,108,34,62,115,101,116,116,108,101,100,119,101,115,116,101,114,110,99 +,97,117,115,105,110,103,45,119,101,98,107,105,116,99,108,97,105,109,101,100,74, +117,115,116,105,99,101,99,104,97,112,116,101,114,118,105,99,116,105,109,115,84, +104,111,109,97,115,32,109,111,122,105,108,108,97,112,114,111,109,105,115,101,112 +,97,114,116,105,101,115,101,100,105,116,105,111,110,111,117,116,115,105,100,101, +58,102,97,108,115,101,44,104,117,110,100,114,101,100,79,108,121,109,112,105,99, +95,98,117,116,116,111,110,97,117,116,104,111,114,115,114,101,97,99,104,101,100, +99,104,114,111,110,105,99,100,101,109,97,110,100,115,115,101,99,111,110,100,115, +112,114,111,116,101,99,116,97,100,111,112,116,101,100,112,114,101,112,97,114,101 +,110,101,105,116,104,101,114,103,114,101,97,116,108,121,103,114,101,97,116,101, +114,111,118,101,114,97,108,108,105,109,112,114,111,118,101,99,111,109,109,97,110 +,100,115,112,101,99,105,97,108,115,101,97,114,99,104,46,119,111,114,115,104,105, +112,102,117,110,100,105,110,103,116,104,111,117,103,104,116,104,105,103,104,101, +115,116,105,110,115,116,101,97,100,117,116,105,108,105,116,121,113,117,97,114, +116,101,114,67,117,108,116,117,114,101,116,101,115,116,105,110,103,99,108,101,97 +,114,108,121,101,120,112,111,115,101,100,66,114,111,119,115,101,114,108,105,98, +101,114,97,108,125,32,99,97,116,99,104,80,114,111,106,101,99,116,101,120,97,109, +112,108,101,104,105,100,101,40,41,59,70,108,111,114,105,100,97,97,110,115,119, +101,114,115,97,108,108,111,119,101,100,69,109,112,101,114,111,114,100,101,102, +101,110,115,101,115,101,114,105,111,117,115,102,114,101,101,100,111,109,83,101, +118,101,114,97,108,45,98,117,116,116,111,110,70,117,114,116,104,101,114,111,117, +116,32,111,102,32,33,61,32,110,117,108,108,116,114,97,105,110,101,100,68,101,110 +,109,97,114,107,118,111,105,100,40,48,41,47,97,108,108,46,106,115,112,114,101, +118,101,110,116,82,101,113,117,101,115,116,83,116,101,112,104,101,110,10,10,87, +104,101,110,32,111,98,115,101,114,118,101,60,47,104,50,62,13,10,77,111,100,101, +114,110,32,112,114,111,118,105,100,101,34,32,97,108,116,61,34,98,111,114,100,101 +,114,115,46,10,10,70,111,114,32,10,10,77,97,110,121,32,97,114,116,105,115,116, +115,112,111,119,101,114,101,100,112,101,114,102,111,114,109,102,105,99,116,105, +111,110,116,121,112,101,32,111,102,109,101,100,105,99,97,108,116,105,99,107,101, +116,115,111,112,112,111,115,101,100,67,111,117,110,99,105,108,119,105,116,110, +101,115,115,106,117,115,116,105,99,101,71,101,111,114,103,101,32,66,101,108,103, +105,117,109,46,46,46,60,47,97,62,116,119,105,116,116,101,114,110,111,116,97,98, +108,121,119,97,105,116,105,110,103,119,97,114,102,97,114,101,32,79,116,104,101, +114,32,114,97,110,107,105,110,103,112,104,114,97,115,101,115,109,101,110,116,105 +,111,110,115,117,114,118,105,118,101,115,99,104,111,108,97,114,60,47,112,62,13, +10,32,67,111,117,110,116,114,121,105,103,110,111,114,101,100,108,111,115,115,32, +111,102,106,117,115,116,32,97,115,71,101,111,114,103,105,97,115,116,114,97,110, +103,101,60,104,101,97,100,62,60,115,116,111,112,112,101,100,49,39,93,41,59,13,10 +,105,115,108,97,110,100,115,110,111,116,97,98,108,101,98,111,114,100,101,114,58, +108,105,115,116,32,111,102,99,97,114,114,105,101,100,49,48,48,44,48,48,48,60,47, +104,51,62,10,32,115,101,118,101,114,97,108,98,101,99,111,109,101,115,115,101,108 +,101,99,116,32,119,101,100,100,105,110,103,48,48,46,104,116,109,108,109,111,110, +97,114,99,104,111,102,102,32,116,104,101,116,101,97,99,104,101,114,104,105,103, +104,108,121,32,98,105,111,108,111,103,121,108,105,102,101,32,111,102,111,114,32, +101,118,101,110,114,105,115,101,32,111,102,38,114,97,113,117,111,59,112,108,117, +115,111,110,101,104,117,110,116,105,110,103,40,116,104,111,117,103,104,68,111, +117,103,108,97,115,106,111,105,110,105,110,103,99,105,114,99,108,101,115,70,111, +114,32,116,104,101,65,110,99,105,101,110,116,86,105,101,116,110,97,109,118,101, +104,105,99,108,101,115,117,99,104,32,97,115,99,114,121,115,116,97,108,118,97,108 +,117,101,32,61,87,105,110,100,111,119,115,101,110,106,111,121,101,100,97,32,115, +109,97,108,108,97,115,115,117,109,101,100,60,97,32,105,100,61,34,102,111,114,101 +,105,103,110,32,65,108,108,32,114,105,104,111,119,32,116,104,101,68,105,115,112, +108,97,121,114,101,116,105,114,101,100,104,111,119,101,118,101,114,104,105,100, +100,101,110,59,98,97,116,116,108,101,115,115,101,101,107,105,110,103,99,97,98, +105,110,101,116,119,97,115,32,110,111,116,108,111,111,107,32,97,116,99,111,110, +100,117,99,116,103,101,116,32,116,104,101,74,97,110,117,97,114,121,104,97,112, +112,101,110,115,116,117,114,110,105,110,103,97,58,104,111,118,101,114,79,110,108 +,105,110,101,32,70,114,101,110,99,104,32,108,97,99,107,105,110,103,116,121,112, +105,99,97,108,101,120,116,114,97,99,116,101,110,101,109,105,101,115,101,118,101, +110,32,105,102,103,101,110,101,114,97,116,100,101,99,105,100,101,100,97,114,101, +32,110,111,116,47,115,101,97,114,99,104,98,101,108,105,101,102,115,45,105,109,97 +,103,101,58,108,111,99,97,116,101,100,115,116,97,116,105,99,46,108,111,103,105, +110,34,62,99,111,110,118,101,114,116,118,105,111,108,101,110,116,101,110,116,101 +,114,101,100,102,105,114,115,116,34,62,99,105,114,99,117,105,116,70,105,110,108, +97,110,100,99,104,101,109,105,115,116,115,104,101,32,119,97,115,49,48,112,120,59 +,34,62,97,115,32,115,117,99,104,100,105,118,105,100,101,100,60,47,115,112,97,110 +,62,119,105,108,108,32,98,101,108,105,110,101,32,111,102,97,32,103,114,101,97, +116,109,121,115,116,101,114,121,47,105,110,100,101,120,46,102,97,108,108,105,110 +,103,100,117,101,32,116,111,32,114,97,105,108,119,97,121,99,111,108,108,101,103, +101,109,111,110,115,116,101,114,100,101,115,99,101,110,116,105,116,32,119,105, +116,104,110,117,99,108,101,97,114,74,101,119,105,115,104,32,112,114,111,116,101, +115,116,66,114,105,116,105,115,104,102,108,111,119,101,114,115,112,114,101,100, +105,99,116,114,101,102,111,114,109,115,98,117,116,116,111,110,32,119,104,111,32, +119,97,115,108,101,99,116,117,114,101,105,110,115,116,97,110,116,115,117,105,99, +105,100,101,103,101,110,101,114,105,99,112,101,114,105,111,100,115,109,97,114, +107,101,116,115,83,111,99,105,97,108,32,102,105,115,104,105,110,103,99,111,109, +98,105,110,101,103,114,97,112,104,105,99,119,105,110,110,101,114,115,60,98,114, +32,47,62,60,98,121,32,116,104,101,32,78,97,116,117,114,97,108,80,114,105,118,97, +99,121,99,111,111,107,105,101,115,111,117,116,99,111,109,101,114,101,115,111,108 +,118,101,83,119,101,100,105,115,104,98,114,105,101,102,108,121,80,101,114,115, +105,97,110,115,111,32,109,117,99,104,67,101,110,116,117,114,121,100,101,112,105, +99,116,115,99,111,108,117,109,110,115,104,111,117,115,105,110,103,115,99,114,105 +,112,116,115,110,101,120,116,32,116,111,98,101,97,114,105,110,103,109,97,112,112 +,105,110,103,114,101,118,105,115,101,100,106,81,117,101,114,121,40,45,119,105, +100,116,104,58,116,105,116,108,101,34,62,116,111,111,108,116,105,112,83,101,99, +116,105,111,110,100,101,115,105,103,110,115,84,117,114,107,105,115,104,121,111, +117,110,103,101,114,46,109,97,116,99,104,40,125,41,40,41,59,10,10,98,117,114,110 +,105,110,103,111,112,101,114,97,116,101,100,101,103,114,101,101,115,115,111,117, +114,99,101,61,82,105,99,104,97,114,100,99,108,111,115,101,108,121,112,108,97,115 +,116,105,99,101,110,116,114,105,101,115,60,47,116,114,62,13,10,99,111,108,111, +114,58,35,117,108,32,105,100,61,34,112,111,115,115,101,115,115,114,111,108,108, +105,110,103,112,104,121,115,105,99,115,102,97,105,108,105,110,103,101,120,101,99 +,117,116,101,99,111,110,116,101,115,116,108,105,110,107,32,116,111,68,101,102,97 +,117,108,116,60,98,114,32,47,62,10,58,32,116,114,117,101,44,99,104,97,114,116, +101,114,116,111,117,114,105,115,109,99,108,97,115,115,105,99,112,114,111,99,101, +101,100,101,120,112,108,97,105,110,60,47,104,49,62,13,10,111,110,108,105,110,101 +,46,63,120,109,108,32,118,101,104,101,108,112,105,110,103,100,105,97,109,111,110 +,100,117,115,101,32,116,104,101,97,105,114,108,105,110,101,101,110,100,32,45,45, +62,41,46,97,116,116,114,40,114,101,97,100,101,114,115,104,111,115,116,105,110, +103,35,102,102,102,102,102,102,114,101,97,108,105,122,101,86,105,110,99,101,110, +116,115,105,103,110,97,108,115,32,115,114,99,61,34,47,80,114,111,100,117,99,116, +100,101,115,112,105,116,101,100,105,118,101,114,115,101,116,101,108,108,105,110, +103,80,117,98,108,105,99,32,104,101,108,100,32,105,110,74,111,115,101,112,104,32 +,116,104,101,97,116,114,101,97,102,102,101,99,116,115,60,115,116,121,108,101,62, +97,32,108,97,114,103,101,100,111,101,115,110,39,116,108,97,116,101,114,44,32,69, +108,101,109,101,110,116,102,97,118,105,99,111,110,99,114,101,97,116,111,114,72, +117,110,103,97,114,121,65,105,114,112,111,114,116,115,101,101,32,116,104,101,115 +,111,32,116,104,97,116,77,105,99,104,97,101,108,83,121,115,116,101,109,115,80, +114,111,103,114,97,109,115,44,32,97,110,100,32,32,119,105,100,116,104,61,101,38, +113,117,111,116,59,116,114,97,100,105,110,103,108,101,102,116,34,62,10,112,101, +114,115,111,110,115,71,111,108,100,101,110,32,65,102,102,97,105,114,115,103,114, +97,109,109,97,114,102,111,114,109,105,110,103,100,101,115,116,114,111,121,105, +100,101,97,32,111,102,99,97,115,101,32,111,102,111,108,100,101,115,116,32,116, +104,105,115,32,105,115,46,115,114,99,32,61,32,99,97,114,116,111,111,110,114,101, +103,105,115,116,114,67,111,109,109,111,110,115,77,117,115,108,105,109,115,87,104 +,97,116,32,105,115,105,110,32,109,97,110,121,109,97,114,107,105,110,103,114,101, +118,101,97,108,115,73,110,100,101,101,100,44,101,113,117,97,108,108,121,47,115, +104,111,119,95,97,111,117,116,100,111,111,114,101,115,99,97,112,101,40,65,117, +115,116,114,105,97,103,101,110,101,116,105,99,115,121,115,116,101,109,44,73,110, +32,116,104,101,32,115,105,116,116,105,110,103,72,101,32,97,108,115,111,73,115, +108,97,110,100,115,65,99,97,100,101,109,121,10,9,9,60,33,45,45,68,97,110,105,101 +,108,32,98,105,110,100,105,110,103,98,108,111,99,107,34,62,105,109,112,111,115, +101,100,117,116,105,108,105,122,101,65,98,114,97,104,97,109,40,101,120,99,101, +112,116,123,119,105,100,116,104,58,112,117,116,116,105,110,103,41,46,104,116,109 +,108,40,124,124,32,91,93,59,10,68,65,84,65,91,32,42,107,105,116,99,104,101,110, +109,111,117,110,116,101,100,97,99,116,117,97,108,32,100,105,97,108,101,99,116, +109,97,105,110,108,121,32,95,98,108,97,110,107,39,105,110,115,116,97,108,108,101 +,120,112,101,114,116,115,105,102,40,116,121,112,101,73,116,32,97,108,115,111,38, +99,111,112,121,59,32,34,62,84,101,114,109,115,98,111,114,110,32,105,110,79,112, +116,105,111,110,115,101,97,115,116,101,114,110,116,97,108,107,105,110,103,99,111 +,110,99,101,114,110,103,97,105,110,101,100,32,111,110,103,111,105,110,103,106, +117,115,116,105,102,121,99,114,105,116,105,99,115,102,97,99,116,111,114,121,105, +116,115,32,111,119,110,97,115,115,97,117,108,116,105,110,118,105,116,101,100,108 +,97,115,116,105,110,103,104,105,115,32,111,119,110,104,114,101,102,61,34,47,34, +32,114,101,108,61,34,100,101,118,101,108,111,112,99,111,110,99,101,114,116,100, +105,97,103,114,97,109,100,111,108,108,97,114,115,99,108,117,115,116,101,114,112, +104,112,63,105,100,61,97,108,99,111,104,111,108,41,59,125,41,40,41,59,117,115, +105,110,103,32,97,62,60,115,112,97,110,62,118,101,115,115,101,108,115,114,101, +118,105,118,97,108,65,100,100,114,101,115,115,97,109,97,116,101,117,114,97,110, +100,114,111,105,100,97,108,108,101,103,101,100,105,108,108,110,101,115,115,119, +97,108,107,105,110,103,99,101,110,116,101,114,115,113,117,97,108,105,102,121,109 +,97,116,99,104,101,115,117,110,105,102,105,101,100,101,120,116,105,110,99,116,68 +,101,102,101,110,115,101,100,105,101,100,32,105,110,10,9,60,33,45,45,32,99,117, +115,116,111,109,115,108,105,110,107,105,110,103,76,105,116,116,108,101,32,66,111 +,111,107,32,111,102,101,118,101,110,105,110,103,109,105,110,46,106,115,63,97,114 +,101,32,116,104,101,107,111,110,116,97,107,116,116,111,100,97,121,39,115,46,104, +116,109,108,34,32,116,97,114,103,101,116,61,119,101,97,114,105,110,103,65,108, +108,32,82,105,103,59,10,125,41,40,41,59,114,97,105,115,105,110,103,32,65,108,115 +,111,44,32,99,114,117,99,105,97,108,97,98,111,117,116,34,62,100,101,99,108,97, +114,101,45,45,62,10,60,115,99,102,105,114,101,102,111,120,97,115,32,109,117,99, +104,97,112,112,108,105,101,115,105,110,100,101,120,44,32,115,44,32,98,117,116,32 +,116,121,112,101,32,61,32,10,13,10,60,33,45,45,116,111,119,97,114,100,115,82,101 +,99,111,114,100,115,80,114,105,118,97,116,101,70,111,114,101,105,103,110,80,114, +101,109,105,101,114,99,104,111,105,99,101,115,86,105,114,116,117,97,108,114,101, +116,117,114,110,115,67,111,109,109,101,110,116,80,111,119,101,114,101,100,105, +110,108,105,110,101,59,112,111,118,101,114,116,121,99,104,97,109,98,101,114,76, +105,118,105,110,103,32,118,111,108,117,109,101,115,65,110,116,104,111,110,121, +108,111,103,105,110,34,32,82,101,108,97,116,101,100,69,99,111,110,111,109,121, +114,101,97,99,104,101,115,99,117,116,116,105,110,103,103,114,97,118,105,116,121, +108,105,102,101,32,105,110,67,104,97,112,116,101,114,45,115,104,97,100,111,119, +78,111,116,97,98,108,101,60,47,116,100,62,13,10,32,114,101,116,117,114,110,115, +116,97,100,105,117,109,119,105,100,103,101,116,115,118,97,114,121,105,110,103, +116,114,97,118,101,108,115,104,101,108,100,32,98,121,119,104,111,32,97,114,101, +119,111,114,107,32,105,110,102,97,99,117,108,116,121,97,110,103,117,108,97,114, +119,104,111,32,104,97,100,97,105,114,112,111,114,116,116,111,119,110,32,111,102, +10,10,83,111,109,101,32,39,99,108,105,99,107,39,99,104,97,114,103,101,115,107, +101,121,119,111,114,100,105,116,32,119,105,108,108,99,105,116,121,32,111,102,40, +116,104,105,115,41,59,65,110,100,114,101,119,32,117,110,105,113,117,101,32,99, +104,101,99,107,101,100,111,114,32,109,111,114,101,51,48,48,112,120,59,32,114,101 +,116,117,114,110,59,114,115,105,111,110,61,34,112,108,117,103,105,110,115,119, +105,116,104,105,110,32,104,101,114,115,101,108,102,83,116,97,116,105,111,110,70, +101,100,101,114,97,108,118,101,110,116,117,114,101,112,117,98,108,105,115,104, +115,101,110,116,32,116,111,116,101,110,115,105,111,110,97,99,116,114,101,115,115 +,99,111,109,101,32,116,111,102,105,110,103,101,114,115,68,117,107,101,32,111,102 +,112,101,111,112,108,101,44,101,120,112,108,111,105,116,119,104,97,116,32,105, +115,104,97,114,109,111,110,121,97,32,109,97,106,111,114,34,58,34,104,116,116,112 +,105,110,32,104,105,115,32,109,101,110,117,34,62,10,109,111,110,116,104,108,121, +111,102,102,105,99,101,114,99,111,117,110,99,105,108,103,97,105,110,105,110,103, +101,118,101,110,32,105,110,83,117,109,109,97,114,121,100,97,116,101,32,111,102, +108,111,121,97,108,116,121,102,105,116,110,101,115,115,97,110,100,32,119,97,115, +101,109,112,101,114,111,114,115,117,112,114,101,109,101,83,101,99,111,110,100,32 +,104,101,97,114,105,110,103,82,117,115,115,105,97,110,108,111,110,103,101,115, +116,65,108,98,101,114,116,97,108,97,116,101,114,97,108,115,101,116,32,111,102,32 +,115,109,97,108,108,34,62,46,97,112,112,101,110,100,100,111,32,119,105,116,104, +102,101,100,101,114,97,108,98,97,110,107,32,111,102,98,101,110,101,97,116,104,68 +,101,115,112,105,116,101,67,97,112,105,116,97,108,103,114,111,117,110,100,115,41 +,44,32,97,110,100,32,112,101,114,99,101,110,116,105,116,32,102,114,111,109,99, +108,111,115,105,110,103,99,111,110,116,97,105,110,73,110,115,116,101,97,100,102, +105,102,116,101,101,110,97,115,32,119,101,108,108,46,121,97,104,111,111,46,114, +101,115,112,111,110,100,102,105,103,104,116,101,114,111,98,115,99,117,114,101, +114,101,102,108,101,99,116,111,114,103,97,110,105,99,61,32,77,97,116,104,46,101, +100,105,116,105,110,103,111,110,108,105,110,101,32,112,97,100,100,105,110,103,97 +,32,119,104,111,108,101,111,110,101,114,114,111,114,121,101,97,114,32,111,102, +101,110,100,32,111,102,32,98,97,114,114,105,101,114,119,104,101,110,32,105,116, +104,101,97,100,101,114,32,104,111,109,101,32,111,102,114,101,115,117,109,101,100 +,114,101,110,97,109,101,100,115,116,114,111,110,103,62,104,101,97,116,105,110, +103,114,101,116,97,105,110,115,99,108,111,117,100,102,114,119,97,121,32,111,102, +32,77,97,114,99,104,32,49,107,110,111,119,105,110,103,105,110,32,112,97,114,116, +66,101,116,119,101,101,110,108,101,115,115,111,110,115,99,108,111,115,101,115, +116,118,105,114,116,117,97,108,108,105,110,107,115,34,62,99,114,111,115,115,101, +100,69,78,68,32,45,45,62,102,97,109,111,117,115,32,97,119,97,114,100,101,100,76, +105,99,101,110,115,101,72,101,97,108,116,104,32,102,97,105,114,108,121,32,119, +101,97,108,116,104,121,109,105,110,105,109,97,108,65,102,114,105,99,97,110,99, +111,109,112,101,116,101,108,97,98,101,108,34,62,115,105,110,103,105,110,103,102, +97,114,109,101,114,115,66,114,97,115,105,108,41,100,105,115,99,117,115,115,114, +101,112,108,97,99,101,71,114,101,103,111,114,121,102,111,110,116,32,99,111,112, +117,114,115,117,101,100,97,112,112,101,97,114,115,109,97,107,101,32,117,112,114, +111,117,110,100,101,100,98,111,116,104,32,111,102,98,108,111,99,107,101,100,115, +97,119,32,116,104,101,111,102,102,105,99,101,115,99,111,108,111,117,114,115,105, +102,40,100,111,99,117,119,104,101,110,32,104,101,101,110,102,111,114,99,101,112, +117,115,104,40,102,117,65,117,103,117,115,116,32,85,84,70,45,56,34,62,70,97,110, +116,97,115,121,105,110,32,109,111,115,116,105,110,106,117,114,101,100,85,115,117 +,97,108,108,121,102,97,114,109,105,110,103,99,108,111,115,117,114,101,111,98,106 +,101,99,116,32,100,101,102,101,110,99,101,117,115,101,32,111,102,32,77,101,100, +105,99,97,108,60,98,111,100,121,62,10,101,118,105,100,101,110,116,98,101,32,117, +115,101,100,107,101,121,67,111,100,101,115,105,120,116,101,101,110,73,115,108,97 +,109,105,99,35,48,48,48,48,48,48,101,110,116,105,114,101,32,119,105,100,101,108, +121,32,97,99,116,105,118,101,32,40,116,121,112,101,111,102,111,110,101,32,99,97, +110,99,111,108,111,114,32,61,115,112,101,97,107,101,114,101,120,116,101,110,100, +115,80,104,121,115,105,99,115,116,101,114,114,97,105,110,60,116,98,111,100,121, +62,102,117,110,101,114,97,108,118,105,101,119,105,110,103,109,105,100,100,108, +101,32,99,114,105,99,107,101,116,112,114,111,112,104,101,116,115,104,105,102,116 +,101,100,100,111,99,116,111,114,115,82,117,115,115,101,108,108,32,116,97,114,103 +,101,116,99,111,109,112,97,99,116,97,108,103,101,98,114,97,115,111,99,105,97,108 +,45,98,117,108,107,32,111,102,109,97,110,32,97,110,100,60,47,116,100,62,10,32, +104,101,32,108,101,102,116,41,46,118,97,108,40,41,102,97,108,115,101,41,59,108, +111,103,105,99,97,108,98,97,110,107,105,110,103,104,111,109,101,32,116,111,110, +97,109,105,110,103,32,65,114,105,122,111,110,97,99,114,101,100,105,116,115,41,59 +,10,125,41,59,10,102,111,117,110,100,101,114,105,110,32,116,117,114,110,67,111, +108,108,105,110,115,98,101,102,111,114,101,32,66,117,116,32,116,104,101,99,104, +97,114,103,101,100,84,105,116,108,101,34,62,67,97,112,116,97,105,110,115,112,101 +,108,108,101,100,103,111,100,100,101,115,115,84,97,103,32,45,45,62,65,100,100, +105,110,103,58,98,117,116,32,119,97,115,82,101,99,101,110,116,32,112,97,116,105, +101,110,116,98,97,99,107,32,105,110,61,102,97,108,115,101,38,76,105,110,99,111, +108,110,119,101,32,107,110,111,119,67,111,117,110,116,101,114,74,117,100,97,105, +115,109,115,99,114,105,112,116,32,97,108,116,101,114,101,100,39,93,41,59,10,32, +32,104,97,115,32,116,104,101,117,110,99,108,101,97,114,69,118,101,110,116,39,44, +98,111,116,104,32,105,110,110,111,116,32,97,108,108,10,10,60,33,45,45,32,112,108 +,97,99,105,110,103,104,97,114,100,32,116,111,32,99,101,110,116,101,114,115,111, +114,116,32,111,102,99,108,105,101,110,116,115,115,116,114,101,101,116,115,66,101 +,114,110,97,114,100,97,115,115,101,114,116,115,116,101,110,100,32,116,111,102,97 +,110,116,97,115,121,100,111,119,110,32,105,110,104,97,114,98,111,117,114,70,114, +101,101,100,111,109,106,101,119,101,108,114,121,47,97,98,111,117,116,46,46,115, +101,97,114,99,104,108,101,103,101,110,100,115,105,115,32,109,97,100,101,109,111, +100,101,114,110,32,111,110,108,121,32,111,110,111,110,108,121,32,116,111,105,109 +,97,103,101,34,32,108,105,110,101,97,114,32,112,97,105,110,116,101,114,97,110, +100,32,110,111,116,114,97,114,101,108,121,32,97,99,114,111,110,121,109,100,101, +108,105,118,101,114,115,104,111,114,116,101,114,48,48,38,97,109,112,59,97,115,32 +,109,97,110,121,119,105,100,116,104,61,34,47,42,32,60,33,91,67,116,105,116,108, +101,32,61,111,102,32,116,104,101,32,108,111,119,101,115,116,32,112,105,99,107, +101,100,32,101,115,99,97,112,101,100,117,115,101,115,32,111,102,112,101,111,112, +108,101,115,32,80,117,98,108,105,99,77,97,116,116,104,101,119,116,97,99,116,105, +99,115,100,97,109,97,103,101,100,119,97,121,32,102,111,114,108,97,119,115,32,111 +,102,101,97,115,121,32,116,111,32,119,105,110,100,111,119,115,116,114,111,110, +103,32,32,115,105,109,112,108,101,125,99,97,116,99,104,40,115,101,118,101,110, +116,104,105,110,102,111,98,111,120,119,101,110,116,32,116,111,112,97,105,110,116 +,101,100,99,105,116,105,122,101,110,73,32,100,111,110,39,116,114,101,116,114,101 +,97,116,46,32,83,111,109,101,32,119,119,46,34,41,59,10,98,111,109,98,105,110,103 +,109,97,105,108,116,111,58,109,97,100,101,32,105,110,46,32,77,97,110,121,32,99, +97,114,114,105,101,115,124,124,123,125,59,119,105,119,111,114,107,32,111,102,115 +,121,110,111,110,121,109,100,101,102,101,97,116,115,102,97,118,111,114,101,100, +111,112,116,105,99,97,108,112,97,103,101,84,114,97,117,110,108,101,115,115,32, +115,101,110,100,105,110,103,108,101,102,116,34,62,60,99,111,109,83,99,111,114,65 +,108,108,32,116,104,101,106,81,117,101,114,121,46,116,111,117,114,105,115,116,67 +,108,97,115,115,105,99,102,97,108,115,101,34,32,87,105,108,104,101,108,109,115, +117,98,117,114,98,115,103,101,110,117,105,110,101,98,105,115,104,111,112,115,46, +115,112,108,105,116,40,103,108,111,98,97,108,32,102,111,108,108,111,119,115,98, +111,100,121,32,111,102,110,111,109,105,110,97,108,67,111,110,116,97,99,116,115, +101,99,117,108,97,114,108,101,102,116,32,116,111,99,104,105,101,102,108,121,45, +104,105,100,100,101,110,45,98,97,110,110,101,114,60,47,108,105,62,10,10,46,32,87 +,104,101,110,32,105,110,32,98,111,116,104,100,105,115,109,105,115,115,69,120,112 +,108,111,114,101,97,108,119,97,121,115,32,118,105,97,32,116,104,101,115,112,97, +195,177,111,108,119,101,108,102,97,114,101,114,117,108,105,110,103,32,97,114,114 +,97,110,103,101,99,97,112,116,97,105,110,104,105,115,32,115,111,110,114,117,108, +101,32,111,102,104,101,32,116,111,111,107,105,116,115,101,108,102,44,61,48,38,97 +,109,112,59,40,99,97,108,108,101,100,115,97,109,112,108,101,115,116,111,32,109, +97,107,101,99,111,109,47,112,97,103,77,97,114,116,105,110,32,75,101,110,110,101, +100,121,97,99,99,101,112,116,115,102,117,108,108,32,111,102,104,97,110,100,108, +101,100,66,101,115,105,100,101,115,47,47,45,45,62,60,47,97,98,108,101,32,116,111 +,116,97,114,103,101,116,115,101,115,115,101,110,99,101,104,105,109,32,116,111,32 +,105,116,115,32,98,121,32,99,111,109,109,111,110,46,109,105,110,101,114,97,108, +116,111,32,116,97,107,101,119,97,121,115,32,116,111,115,46,111,114,103,47,108,97 +,100,118,105,115,101,100,112,101,110,97,108,116,121,115,105,109,112,108,101,58, +105,102,32,116,104,101,121,76,101,116,116,101,114,115,97,32,115,104,111,114,116, +72,101,114,98,101,114,116,115,116,114,105,107,101,115,32,103,114,111,117,112,115 +,46,108,101,110,103,116,104,102,108,105,103,104,116,115,111,118,101,114,108,97, +112,115,108,111,119,108,121,32,108,101,115,115,101,114,32,115,111,99,105,97,108, +32,60,47,112,62,10,9,9,105,116,32,105,110,116,111,114,97,110,107,101,100,32,114, +97,116,101,32,111,102,117,108,62,13,10,32,32,97,116,116,101,109,112,116,112,97, +105,114,32,111,102,109,97,107,101,32,105,116,75,111,110,116,97,107,116,65,110, +116,111,110,105,111,104,97,118,105,110,103,32,114,97,116,105,110,103,115,32,97, +99,116,105,118,101,115,116,114,101,97,109,115,116,114,97,112,112,101,100,34,41, +46,99,115,115,40,104,111,115,116,105,108,101,108,101,97,100,32,116,111,108,105, +116,116,108,101,32,103,114,111,117,112,115,44,80,105,99,116,117,114,101,45,45,62 +,13,10,13,10,32,114,111,119,115,61,34,32,111,98,106,101,99,116,105,110,118,101, +114,115,101,60,102,111,111,116,101,114,67,117,115,116,111,109,86,62,60,92,47,115 +,99,114,115,111,108,118,105,110,103,67,104,97,109,98,101,114,115,108,97,118,101, +114,121,119,111,117,110,100,101,100,119,104,101,114,101,97,115,33,61,32,39,117, +110,100,102,111,114,32,97,108,108,112,97,114,116,108,121,32,45,114,105,103,104, +116,58,65,114,97,98,105,97,110,98,97,99,107,101,100,32,99,101,110,116,117,114, +121,117,110,105,116,32,111,102,109,111,98,105,108,101,45,69,117,114,111,112,101, +44,105,115,32,104,111,109,101,114,105,115,107,32,111,102,100,101,115,105,114,101 +,100,67,108,105,110,116,111,110,99,111,115,116,32,111,102,97,103,101,32,111,102, +32,98,101,99,111,109,101,32,110,111,110,101,32,111,102,112,38,113,117,111,116,59 +,77,105,100,100,108,101,32,101,97,100,39,41,91,48,67,114,105,116,105,99,115,115, +116,117,100,105,111,115,62,38,99,111,112,121,59,103,114,111,117,112,34,62,97,115 +,115,101,109,98,108,109,97,107,105,110,103,32,112,114,101,115,115,101,100,119, +105,100,103,101,116,46,112,115,58,34,32,63,32,114,101,98,117,105,108,116,98,121, +32,115,111,109,101,70,111,114,109,101,114,32,101,100,105,116,111,114,115,100,101 +,108,97,121,101,100,67,97,110,111,110,105,99,104,97,100,32,116,104,101,112,117, +115,104,105,110,103,99,108,97,115,115,61,34,98,117,116,32,97,114,101,112,97,114, +116,105,97,108,66,97,98,121,108,111,110,98,111,116,116,111,109,32,99,97,114,114, +105,101,114,67,111,109,109,97,110,100,105,116,115,32,117,115,101,65,115,32,119, +105,116,104,99,111,117,114,115,101,115,97,32,116,104,105,114,100,100,101,110,111 +,116,101,115,97,108,115,111,32,105,110,72,111,117,115,116,111,110,50,48,112,120, +59,34,62,97,99,99,117,115,101,100,100,111,117,98,108,101,32,103,111,97,108,32, +111,102,70,97,109,111,117,115,32,41,46,98,105,110,100,40,112,114,105,101,115,116 +,115,32,79,110,108,105,110,101,105,110,32,74,117,108,121,115,116,32,43,32,34,103 +,99,111,110,115,117,108,116,100,101,99,105,109,97,108,104,101,108,112,102,117, +108,114,101,118,105,118,101,100,105,115,32,118,101,114,121,114,39,43,39,105,112, +116,108,111,115,105,110,103,32,102,101,109,97,108,101,115,105,115,32,97,108,115, +111,115,116,114,105,110,103,115,100,97,121,115,32,111,102,97,114,114,105,118,97, +108,102,117,116,117,114,101,32,60,111,98,106,101,99,116,102,111,114,99,105,110, +103,83,116,114,105,110,103,40,34,32,47,62,10,9,9,104,101,114,101,32,105,115,101, +110,99,111,100,101,100,46,32,32,84,104,101,32,98,97,108,108,111,111,110,100,111, +110,101,32,98,121,47,99,111,109,109,111,110,98,103,99,111,108,111,114,108,97,119 +,32,111,102,32,73,110,100,105,97,110,97,97,118,111,105,100,101,100,98,117,116,32 +,116,104,101,50,112,120,32,51,112,120,106,113,117,101,114,121,46,97,102,116,101, +114,32,97,112,111,108,105,99,121,46,109,101,110,32,97,110,100,102,111,111,116, +101,114,45,61,32,116,114,117,101,59,102,111,114,32,117,115,101,115,99,114,101, +101,110,46,73,110,100,105,97,110,32,105,109,97,103,101,32,61,102,97,109,105,108, +121,44,104,116,116,112,58,47,47,32,38,110,98,115,112,59,100,114,105,118,101,114, +115,101,116,101,114,110,97,108,115,97,109,101,32,97,115,110,111,116,105,99,101, +100,118,105,101,119,101,114,115,125,41,40,41,59,10,32,105,115,32,109,111,114,101 +,115,101,97,115,111,110,115,102,111,114,109,101,114,32,116,104,101,32,110,101, +119,105,115,32,106,117,115,116,99,111,110,115,101,110,116,32,83,101,97,114,99, +104,119,97,115,32,116,104,101,119,104,121,32,116,104,101,115,104,105,112,112,101 +,100,98,114,62,60,98,114,62,119,105,100,116,104,58,32,104,101,105,103,104,116,61 +,109,97,100,101,32,111,102,99,117,105,115,105,110,101,105,115,32,116,104,97,116, +97,32,118,101,114,121,32,65,100,109,105,114,97,108,32,102,105,120,101,100,59,110 +,111,114,109,97,108,32,77,105,115,115,105,111,110,80,114,101,115,115,44,32,111, +110,116,97,114,105,111,99,104,97,114,115,101,116,116,114,121,32,116,111,32,105, +110,118,97,100,101,100,61,34,116,114,117,101,34,115,112,97,99,105,110,103,105, +115,32,109,111,115,116,97,32,109,111,114,101,32,116,111,116,97,108,108,121,102, +97,108,108,32,111,102,125,41,59,13,10,32,32,105,109,109,101,110,115,101,116,105, +109,101,32,105,110,115,101,116,32,111,117,116,115,97,116,105,115,102,121,116,111 +,32,102,105,110,100,100,111,119,110,32,116,111,108,111,116,32,111,102,32,80,108, +97,121,101,114,115,105,110,32,74,117,110,101,113,117,97,110,116,117,109,110,111, +116,32,116,104,101,116,105,109,101,32,116,111,100,105,115,116,97,110,116,70,105, +110,110,105,115,104,115,114,99,32,61,32,40,115,105,110,103,108,101,32,104,101, +108,112,32,111,102,71,101,114,109,97,110,32,108,97,119,32,97,110,100,108,97,98, +101,108,101,100,102,111,114,101,115,116,115,99,111,111,107,105,110,103,115,112, +97,99,101,34,62,104,101,97,100,101,114,45,119,101,108,108,32,97,115,83,116,97, +110,108,101,121,98,114,105,100,103,101,115,47,103,108,111,98,97,108,67,114,111, +97,116,105,97,32,65,98,111,117,116,32,91,48,93,59,10,32,32,105,116,44,32,97,110, +100,103,114,111,117,112,101,100,98,101,105,110,103,32,97,41,123,116,104,114,111, +119,104,101,32,109,97,100,101,108,105,103,104,116,101,114,101,116,104,105,99,97, +108,70,70,70,70,70,70,34,98,111,116,116,111,109,34,108,105,107,101,32,97,32,101, +109,112,108,111,121,115,108,105,118,101,32,105,110,97,115,32,115,101,101,110,112 +,114,105,110,116,101,114,109,111,115,116,32,111,102,117,98,45,108,105,110,107, +114,101,106,101,99,116,115,97,110,100,32,117,115,101,105,109,97,103,101,34,62, +115,117,99,99,101,101,100,102,101,101,100,105,110,103,78,117,99,108,101,97,114, +105,110,102,111,114,109,97,116,111,32,104,101,108,112,87,111,109,101,110,39,115, +78,101,105,116,104,101,114,77,101,120,105,99,97,110,112,114,111,116,101,105,110, +60,116,97,98,108,101,32,98,121,32,109,97,110,121,104,101,97,108,116,104,121,108, +97,119,115,117,105,116,100,101,118,105,115,101,100,46,112,117,115,104,40,123,115 +,101,108,108,101,114,115,115,105,109,112,108,121,32,84,104,114,111,117,103,104, +46,99,111,111,107,105,101,32,73,109,97,103,101,40,111,108,100,101,114,34,62,117, +115,46,106,115,34,62,32,83,105,110,99,101,32,117,110,105,118,101,114,115,108,97, +114,103,101,114,32,111,112,101,110,32,116,111,33,45,45,32,101,110,100,108,105, +101,115,32,105,110,39,93,41,59,13,10,32,32,109,97,114,107,101,116,119,104,111,32 +,105,115,32,40,34,68,79,77,67,111,109,97,110,97,103,101,100,111,110,101,32,102, +111,114,116,121,112,101,111,102,32,75,105,110,103,100,111,109,112,114,111,102, +105,116,115,112,114,111,112,111,115,101,116,111,32,115,104,111,119,99,101,110, +116,101,114,59,109,97,100,101,32,105,116,100,114,101,115,115,101,100,119,101,114 +,101,32,105,110,109,105,120,116,117,114,101,112,114,101,99,105,115,101,97,114, +105,115,105,110,103,115,114,99,32,61,32,39,109,97,107,101,32,97,32,115,101,99, +117,114,101,100,66,97,112,116,105,115,116,118,111,116,105,110,103,32,10,9,9,118, +97,114,32,77,97,114,99,104,32,50,103,114,101,119,32,117,112,67,108,105,109,97, +116,101,46,114,101,109,111,118,101,115,107,105,108,108,101,100,119,97,121,32,116 +,104,101,60,47,104,101,97,100,62,102,97,99,101,32,111,102,97,99,116,105,110,103, +32,114,105,103,104,116,34,62,116,111,32,119,111,114,107,114,101,100,117,99,101, +115,104,97,115,32,104,97,100,101,114,101,99,116,101,100,115,104,111,119,40,41,59 +,97,99,116,105,111,110,61,98,111,111,107,32,111,102,97,110,32,97,114,101,97,61, +61,32,34,104,116,116,60,104,101,97,100,101,114,10,60,104,116,109,108,62,99,111, +110,102,111,114,109,102,97,99,105,110,103,32,99,111,111,107,105,101,46,114,101, +108,121,32,111,110,104,111,115,116,101,100,32,46,99,117,115,116,111,109,104,101, +32,119,101,110,116,98,117,116,32,102,111,114,115,112,114,101,97,100,32,70,97,109 +,105,108,121,32,97,32,109,101,97,110,115,111,117,116,32,116,104,101,102,111,114, +117,109,115,46,102,111,111,116,97,103,101,34,62,77,111,98,105,108,67,108,101,109 +,101,110,116,115,34,32,105,100,61,34,97,115,32,104,105,103,104,105,110,116,101, +110,115,101,45,45,62,60,33,45,45,102,101,109,97,108,101,32,105,115,32,115,101, +101,110,105,109,112,108,105,101,100,115,101,116,32,116,104,101,97,32,115,116,97, +116,101,97,110,100,32,104,105,115,102,97,115,116,101,115,116,98,101,115,105,100, +101,115,98,117,116,116,111,110,95,98,111,117,110,100,101,100,34,62,60,105,109, +103,32,73,110,102,111,98,111,120,101,118,101,110,116,115,44,97,32,121,111,117, +110,103,97,110,100,32,97,114,101,78,97,116,105,118,101,32,99,104,101,97,112,101, +114,84,105,109,101,111,117,116,97,110,100,32,104,97,115,101,110,103,105,110,101, +115,119,111,110,32,116,104,101,40,109,111,115,116,108,121,114,105,103,104,116,58 +,32,102,105,110,100,32,97,32,45,98,111,116,116,111,109,80,114,105,110,99,101,32, +97,114,101,97,32,111,102,109,111,114,101,32,111,102,115,101,97,114,99,104,95,110 +,97,116,117,114,101,44,108,101,103,97,108,108,121,112,101,114,105,111,100,44,108 +,97,110,100,32,111,102,111,114,32,119,105,116,104,105,110,100,117,99,101,100,112 +,114,111,118,105,110,103,109,105,115,115,105,108,101,108,111,99,97,108,108,121, +65,103,97,105,110,115,116,116,104,101,32,119,97,121,107,38,113,117,111,116,59, +112,120,59,34,62,13,10,112,117,115,104,101,100,32,97,98,97,110,100,111,110,110, +117,109,101,114,97,108,67,101,114,116,97,105,110,73,110,32,116,104,105,115,109, +111,114,101,32,105,110,111,114,32,115,111,109,101,110,97,109,101,32,105,115,97, +110,100,44,32,105,110,99,114,111,119,110,101,100,73,83,66,78,32,48,45,99,114,101 +,97,116,101,115,79,99,116,111,98,101,114,109,97,121,32,110,111,116,99,101,110, +116,101,114,32,108,97,116,101,32,105,110,68,101,102,101,110,99,101,101,110,97,99 +,116,101,100,119,105,115,104,32,116,111,98,114,111,97,100,108,121,99,111,111,108 +,105,110,103,111,110,108,111,97,100,61,105,116,46,32,84,104,101,114,101,99,111, +118,101,114,77,101,109,98,101,114,115,104,101,105,103,104,116,32,97,115,115,117, +109,101,115,60,104,116,109,108,62,10,112,101,111,112,108,101,46,105,110,32,111, +110,101,32,61,119,105,110,100,111,119,102,111,111,116,101,114,95,97,32,103,111, +111,100,32,114,101,107,108,97,109,97,111,116,104,101,114,115,44,116,111,32,116, +104,105,115,95,99,111,111,107,105,101,112,97,110,101,108,34,62,76,111,110,100, +111,110,44,100,101,102,105,110,101,115,99,114,117,115,104,101,100,98,97,112,116, +105,115,109,99,111,97,115,116,97,108,115,116,97,116,117,115,32,116,105,116,108, +101,34,32,109,111,118,101,32,116,111,108,111,115,116,32,105,110,98,101,116,116, +101,114,32,105,109,112,108,105,101,115,114,105,118,97,108,114,121,115,101,114, +118,101,114,115,32,83,121,115,116,101,109,80,101,114,104,97,112,115,101,115,32, +97,110,100,32,99,111,110,116,101,110,100,102,108,111,119,105,110,103,108,97,115, +116,101,100,32,114,105,115,101,32,105,110,71,101,110,101,115,105,115,118,105,101 +,119,32,111,102,114,105,115,105,110,103,32,115,101,101,109,32,116,111,98,117,116 +,32,105,110,32,98,97,99,107,105,110,103,104,101,32,119,105,108,108,103,105,118, +101,110,32,97,103,105,118,105,110,103,32,99,105,116,105,101,115,46,102,108,111, +119,32,111,102,32,76,97,116,101,114,32,97,108,108,32,98,117,116,72,105,103,104, +119,97,121,111,110,108,121,32,98,121,115,105,103,110,32,111,102,104,101,32,100, +111,101,115,100,105,102,102,101,114,115,98,97,116,116,101,114,121,38,97,109,112, +59,108,97,115,105,110,103,108,101,115,116,104,114,101,97,116,115,105,110,116,101 +,103,101,114,116,97,107,101,32,111,110,114,101,102,117,115,101,100,99,97,108,108 +,101,100,32,61,85,83,38,97,109,112,83,101,101,32,116,104,101,110,97,116,105,118, +101,115,98,121,32,116,104,105,115,115,121,115,116,101,109,46,104,101,97,100,32, +111,102,58,104,111,118,101,114,44,108,101,115,98,105,97,110,115,117,114,110,97, +109,101,97,110,100,32,97,108,108,99,111,109,109,111,110,47,104,101,97,100,101, +114,95,95,112,97,114,97,109,115,72,97,114,118,97,114,100,47,112,105,120,101,108, +46,114,101,109,111,118,97,108,115,111,32,108,111,110,103,114,111,108,101,32,111, +102,106,111,105,110,116,108,121,115,107,121,115,99,114,97,85,110,105,99,111,100, +101,98,114,32,47,62,13,10,65,116,108,97,110,116,97,110,117,99,108,101,117,115,67 +,111,117,110,116,121,44,112,117,114,101,108,121,32,99,111,117,110,116,34,62,101, +97,115,105,108,121,32,98,117,105,108,100,32,97,111,110,99,108,105,99,107,97,32, +103,105,118,101,110,112,111,105,110,116,101,114,104,38,113,117,111,116,59,101, +118,101,110,116,115,32,101,108,115,101,32,123,10,100,105,116,105,111,110,115,110 +,111,119,32,116,104,101,44,32,119,105,116,104,32,109,97,110,32,119,104,111,111, +114,103,47,87,101,98,111,110,101,32,97,110,100,99,97,118,97,108,114,121,72,101, +32,100,105,101,100,115,101,97,116,116,108,101,48,48,44,48,48,48,32,123,119,105, +110,100,111,119,104,97,118,101,32,116,111,105,102,40,119,105,110,100,97,110,100, +32,105,116,115,115,111,108,101,108,121,32,109,38,113,117,111,116,59,114,101,110, +101,119,101,100,68,101,116,114,111,105,116,97,109,111,110,103,115,116,101,105, +116,104,101,114,32,116,104,101,109,32,105,110,83,101,110,97,116,111,114,85,115, +60,47,97,62,60,75,105,110,103,32,111,102,70,114,97,110,99,105,115,45,112,114,111 +,100,117,99,104,101,32,117,115,101,100,97,114,116,32,97,110,100,104,105,109,32, +97,110,100,117,115,101,100,32,98,121,115,99,111,114,105,110,103,97,116,32,104, +111,109,101,116,111,32,104,97,118,101,114,101,108,97,116,101,115,105,98,105,108, +105,116,121,102,97,99,116,105,111,110,66,117,102,102,97,108,111,108,105,110,107, +34,62,60,119,104,97,116,32,104,101,102,114,101,101,32,116,111,67,105,116,121,32, +111,102,99,111,109,101,32,105,110,115,101,99,116,111,114,115,99,111,117,110,116, +101,100,111,110,101,32,100,97,121,110,101,114,118,111,117,115,115,113,117,97,114 +,101,32,125,59,105,102,40,103,111,105,110,32,119,104,97,116,105,109,103,34,32,97 +,108,105,115,32,111,110,108,121,115,101,97,114,99,104,47,116,117,101,115,100,97, +121,108,111,111,115,101,108,121,83,111,108,111,109,111,110,115,101,120,117,97, +108,32,45,32,60,97,32,104,114,109,101,100,105,117,109,34,68,79,32,78,79,84,32,70 +,114,97,110,99,101,44,119,105,116,104,32,97,32,119,97,114,32,97,110,100,115,101, +99,111,110,100,32,116,97,107,101,32,97,32,62,13,10,13,10,13,10,109,97,114,107, +101,116,46,104,105,103,104,119,97,121,100,111,110,101,32,105,110,99,116,105,118, +105,116,121,34,108,97,115,116,34,62,111,98,108,105,103,101,100,114,105,115,101, +32,116,111,34,117,110,100,101,102,105,109,97,100,101,32,116,111,32,69,97,114,108 +,121,32,112,114,97,105,115,101,100,105,110,32,105,116,115,32,102,111,114,32,104, +105,115,97,116,104,108,101,116,101,74,117,112,105,116,101,114,89,97,104,111,111, +33,32,116,101,114,109,101,100,32,115,111,32,109,97,110,121,114,101,97,108,108, +121,32,115,46,32,84,104,101,32,97,32,119,111,109,97,110,63,118,97,108,117,101,61 +,100,105,114,101,99,116,32,114,105,103,104,116,34,32,98,105,99,121,99,108,101,97 +,99,105,110,103,61,34,100,97,121,32,97,110,100,115,116,97,116,105,110,103,82,97, +116,104,101,114,44,104,105,103,104,101,114,32,79,102,102,105,99,101,32,97,114, +101,32,110,111,119,116,105,109,101,115,44,32,119,104,101,110,32,97,32,112,97,121 +,32,102,111,114,111,110,32,116,104,105,115,45,108,105,110,107,34,62,59,98,111, +114,100,101,114,97,114,111,117,110,100,32,97,110,110,117,97,108,32,116,104,101, +32,78,101,119,112,117,116,32,116,104,101,46,99,111,109,34,32,116,97,107,105,110, +32,116,111,97,32,98,114,105,101,102,40,105,110,32,116,104,101,103,114,111,117, +112,115,46,59,32,119,105,100,116,104,101,110,122,121,109,101,115,115,105,109,112 +,108,101,32,105,110,32,108,97,116,101,123,114,101,116,117,114,110,116,104,101, +114,97,112,121,97,32,112,111,105,110,116,98,97,110,110,105,110,103,105,110,107, +115,34,62,10,40,41,59,34,32,114,101,97,32,112,108,97,99,101,92,117,48,48,51,67, +97,97,98,111,117,116,32,97,116,114,62,13,10,9,9,99,99,111,117,110,116,32,103,105 +,118,101,115,32,97,60,83,67,82,73,80,84,82,97,105,108,119,97,121,116,104,101,109 +,101,115,47,116,111,111,108,98,111,120,66,121,73,100,40,34,120,104,117,109,97, +110,115,44,119,97,116,99,104,101,115,105,110,32,115,111,109,101,32,105,102,32,40 +,119,105,99,111,109,105,110,103,32,102,111,114,109,97,116,115,32,85,110,100,101, +114,32,98,117,116,32,104,97,115,104,97,110,100,101,100,32,109,97,100,101,32,98, +121,116,104,97,110,32,105,110,102,101,97,114,32,111,102,100,101,110,111,116,101, +100,47,105,102,114,97,109,101,108,101,102,116,32,105,110,118,111,108,116,97,103, +101,105,110,32,101,97,99,104,97,38,113,117,111,116,59,98,97,115,101,32,111,102, +73,110,32,109,97,110,121,117,110,100,101,114,103,111,114,101,103,105,109,101,115 +,97,99,116,105,111,110,32,60,47,112,62,13,10,60,117,115,116,111,109,86,97,59,38, +103,116,59,60,47,105,109,112,111,114,116,115,111,114,32,116,104,97,116,109,111, +115,116,108,121,32,38,97,109,112,59,114,101,32,115,105,122,101,61,34,60,47,97,62 +,60,47,104,97,32,99,108,97,115,115,112,97,115,115,105,118,101,72,111,115,116,32, +61,32,87,104,101,116,104,101,114,102,101,114,116,105,108,101,86,97,114,105,111, +117,115,61,91,93,59,40,102,117,99,97,109,101,114,97,115,47,62,60,47,116,100,62, +97,99,116,115,32,97,115,73,110,32,115,111,109,101,62,13,10,13,10,60,33,111,114, +103,97,110,105,115,32,60,98,114,32,47,62,66,101,105,106,105,110,103,99,97,116,97 +,108,195,160,100,101,117,116,115,99,104,101,117,114,111,112,101,117,101,117,115, +107,97,114,97,103,97,101,105,108,103,101,115,118,101,110,115,107,97,101,115,112, +97,195,177,97,109,101,110,115,97,106,101,117,115,117,97,114,105,111,116,114,97, +98,97,106,111,109,195,169,120,105,99,111,112,195,161,103,105,110,97,115,105,101, +109,112,114,101,115,105,115,116,101,109,97,111,99,116,117,98,114,101,100,117,114 +,97,110,116,101,97,195,177,97,100,105,114,101,109,112,114,101,115,97,109,111,109 +,101,110,116,111,110,117,101,115,116,114,111,112,114,105,109,101,114,97,116,114, +97,118,195,169,115,103,114,97,99,105,97,115,110,117,101,115,116,114,97,112,114, +111,99,101,115,111,101,115,116,97,100,111,115,99,97,108,105,100,97,100,112,101, +114,115,111,110,97,110,195,186,109,101,114,111,97,99,117,101,114,100,111,109,195 +,186,115,105,99,97,109,105,101,109,98,114,111,111,102,101,114,116,97,115,97,108, +103,117,110,111,115,112,97,195,173,115,101,115,101,106,101,109,112,108,111,100, +101,114,101,99,104,111,97,100,101,109,195,161,115,112,114,105,118,97,100,111,97, +103,114,101,103,97,114,101,110,108,97,99,101,115,112,111,115,105,98,108,101,104, +111,116,101,108,101,115,115,101,118,105,108,108,97,112,114,105,109,101,114,111, +195,186,108,116,105,109,111,101,118,101,110,116,111,115,97,114,99,104,105,118, +111,99,117,108,116,117,114,97,109,117,106,101,114,101,115,101,110,116,114,97,100 +,97,97,110,117,110,99,105,111,101,109,98,97,114,103,111,109,101,114,99,97,100, +111,103,114,97,110,100,101,115,101,115,116,117,100,105,111,109,101,106,111,114, +101,115,102,101,98,114,101,114,111,100,105,115,101,195,177,111,116,117,114,105, +115,109,111,99,195,179,100,105,103,111,112,111,114,116,97,100,97,101,115,112,97, +99,105,111,102,97,109,105,108,105,97,97,110,116,111,110,105,111,112,101,114,109, +105,116,101,103,117,97,114,100,97,114,97,108,103,117,110,97,115,112,114,101,99, +105,111,115,97,108,103,117,105,101,110,115,101,110,116,105,100,111,118,105,115, +105,116,97,115,116,195,173,116,117,108,111,99,111,110,111,99,101,114,115,101,103 +,117,110,100,111,99,111,110,115,101,106,111,102,114,97,110,99,105,97,109,105,110 +,117,116,111,115,115,101,103,117,110,100,97,116,101,110,101,109,111,115,101,102, +101,99,116,111,115,109,195,161,108,97,103,97,115,101,115,105,195,179,110,114,101 +,118,105,115,116,97,103,114,97,110,97,100,97,99,111,109,112,114,97,114,105,110, +103,114,101,115,111,103,97,114,99,195,173,97,97,99,99,105,195,179,110,101,99,117 +,97,100,111,114,113,117,105,101,110,101,115,105,110,99,108,117,115,111,100,101, +98,101,114,195,161,109,97,116,101,114,105,97,104,111,109,98,114,101,115,109,117, +101,115,116,114,97,112,111,100,114,195,173,97,109,97,195,177,97,110,97,195,186, +108,116,105,109,97,101,115,116,97,109,111,115,111,102,105,99,105,97,108,116,97, +109,98,105,101,110,110,105,110,103,195,186,110,115,97,108,117,100,111,115,112, +111,100,101,109,111,115,109,101,106,111,114,97,114,112,111,115,105,116,105,111, +110,98,117,115,105,110,101,115,115,104,111,109,101,112,97,103,101,115,101,99,117 +,114,105,116,121,108,97,110,103,117,97,103,101,115,116,97,110,100,97,114,100,99, +97,109,112,97,105,103,110,102,101,97,116,117,114,101,115,99,97,116,101,103,111, +114,121,101,120,116,101,114,110,97,108,99,104,105,108,100,114,101,110,114,101, +115,101,114,118,101,100,114,101,115,101,97,114,99,104,101,120,99,104,97,110,103, +101,102,97,118,111,114,105,116,101,116,101,109,112,108,97,116,101,109,105,108, +105,116,97,114,121,105,110,100,117,115,116,114,121,115,101,114,118,105,99,101, +115,109,97,116,101,114,105,97,108,112,114,111,100,117,99,116,115,122,45,105,110, +100,101,120,58,99,111,109,109,101,110,116,115,115,111,102,116,119,97,114,101,99, +111,109,112,108,101,116,101,99,97,108,101,110,100,97,114,112,108,97,116,102,111, +114,109,97,114,116,105,99,108,101,115,114,101,113,117,105,114,101,100,109,111, +118,101,109,101,110,116,113,117,101,115,116,105,111,110,98,117,105,108,100,105, +110,103,112,111,108,105,116,105,99,115,112,111,115,115,105,98,108,101,114,101, +108,105,103,105,111,110,112,104,121,115,105,99,97,108,102,101,101,100,98,97,99, +107,114,101,103,105,115,116,101,114,112,105,99,116,117,114,101,115,100,105,115, +97,98,108,101,100,112,114,111,116,111,99,111,108,97,117,100,105,101,110,99,101, +115,101,116,116,105,110,103,115,97,99,116,105,118,105,116,121,101,108,101,109, +101,110,116,115,108,101,97,114,110,105,110,103,97,110,121,116,104,105,110,103,97 +,98,115,116,114,97,99,116,112,114,111,103,114,101,115,115,111,118,101,114,118, +105,101,119,109,97,103,97,122,105,110,101,101,99,111,110,111,109,105,99,116,114, +97,105,110,105,110,103,112,114,101,115,115,117,114,101,118,97,114,105,111,117, +115,32,60,115,116,114,111,110,103,62,112,114,111,112,101,114,116,121,115,104,111 +,112,112,105,110,103,116,111,103,101,116,104,101,114,97,100,118,97,110,99,101, +100,98,101,104,97,118,105,111,114,100,111,119,110,108,111,97,100,102,101,97,116, +117,114,101,100,102,111,111,116,98,97,108,108,115,101,108,101,99,116,101,100,76, +97,110,103,117,97,103,101,100,105,115,116,97,110,99,101,114,101,109,101,109,98, +101,114,116,114,97,99,107,105,110,103,112,97,115,115,119,111,114,100,109,111,100 +,105,102,105,101,100,115,116,117,100,101,110,116,115,100,105,114,101,99,116,108, +121,102,105,103,104,116,105,110,103,110,111,114,116,104,101,114,110,100,97,116, +97,98,97,115,101,102,101,115,116,105,118,97,108,98,114,101,97,107,105,110,103, +108,111,99,97,116,105,111,110,105,110,116,101,114,110,101,116,100,114,111,112, +100,111,119,110,112,114,97,99,116,105,99,101,101,118,105,100,101,110,99,101,102, +117,110,99,116,105,111,110,109,97,114,114,105,97,103,101,114,101,115,112,111,110 +,115,101,112,114,111,98,108,101,109,115,110,101,103,97,116,105,118,101,112,114, +111,103,114,97,109,115,97,110,97,108,121,115,105,115,114,101,108,101,97,115,101, +100,98,97,110,110,101,114,34,62,112,117,114,99,104,97,115,101,112,111,108,105,99 +,105,101,115,114,101,103,105,111,110,97,108,99,114,101,97,116,105,118,101,97,114 +,103,117,109,101,110,116,98,111,111,107,109,97,114,107,114,101,102,101,114,114, +101,114,99,104,101,109,105,99,97,108,100,105,118,105,115,105,111,110,99,97,108, +108,98,97,99,107,115,101,112,97,114,97,116,101,112,114,111,106,101,99,116,115,99 +,111,110,102,108,105,99,116,104,97,114,100,119,97,114,101,105,110,116,101,114, +101,115,116,100,101,108,105,118,101,114,121,109,111,117,110,116,97,105,110,111, +98,116,97,105,110,101,100,61,32,102,97,108,115,101,59,102,111,114,40,118,97,114, +32,97,99,99,101,112,116,101,100,99,97,112,97,99,105,116,121,99,111,109,112,117, +116,101,114,105,100,101,110,116,105,116,121,97,105,114,99,114,97,102,116,101,109 +,112,108,111,121,101,100,112,114,111,112,111,115,101,100,100,111,109,101,115,116 +,105,99,105,110,99,108,117,100,101,115,112,114,111,118,105,100,101,100,104,111, +115,112,105,116,97,108,118,101,114,116,105,99,97,108,99,111,108,108,97,112,115, +101,97,112,112,114,111,97,99,104,112,97,114,116,110,101,114,115,108,111,103,111, +34,62,60,97,100,97,117,103,104,116,101,114,97,117,116,104,111,114,34,32,99,117, +108,116,117,114,97,108,102,97,109,105,108,105,101,115,47,105,109,97,103,101,115, +47,97,115,115,101,109,98,108,121,112,111,119,101,114,102,117,108,116,101,97,99, +104,105,110,103,102,105,110,105,115,104,101,100,100,105,115,116,114,105,99,116, +99,114,105,116,105,99,97,108,99,103,105,45,98,105,110,47,112,117,114,112,111,115 +,101,115,114,101,113,117,105,114,101,115,101,108,101,99,116,105,111,110,98,101, +99,111,109,105,110,103,112,114,111,118,105,100,101,115,97,99,97,100,101,109,105, +99,101,120,101,114,99,105,115,101,97,99,116,117,97,108,108,121,109,101,100,105, +99,105,110,101,99,111,110,115,116,97,110,116,97,99,99,105,100,101,110,116,77,97, +103,97,122,105,110,101,100,111,99,117,109,101,110,116,115,116,97,114,116,105,110 +,103,98,111,116,116,111,109,34,62,111,98,115,101,114,118,101,100,58,32,38,113, +117,111,116,59,101,120,116,101,110,100,101,100,112,114,101,118,105,111,117,115, +83,111,102,116,119,97,114,101,99,117,115,116,111,109,101,114,100,101,99,105,115, +105,111,110,115,116,114,101,110,103,116,104,100,101,116,97,105,108,101,100,115, +108,105,103,104,116,108,121,112,108,97,110,110,105,110,103,116,101,120,116,97, +114,101,97,99,117,114,114,101,110,99,121,101,118,101,114,121,111,110,101,115,116 +,114,97,105,103,104,116,116,114,97,110,115,102,101,114,112,111,115,105,116,105, +118,101,112,114,111,100,117,99,101,100,104,101,114,105,116,97,103,101,115,104, +105,112,112,105,110,103,97,98,115,111,108,117,116,101,114,101,99,101,105,118,101 +,100,114,101,108,101,118,97,110,116,98,117,116,116,111,110,34,32,118,105,111,108 +,101,110,99,101,97,110,121,119,104,101,114,101,98,101,110,101,102,105,116,115, +108,97,117,110,99,104,101,100,114,101,99,101,110,116,108,121,97,108,108,105,97, +110,99,101,102,111,108,108,111,119,101,100,109,117,108,116,105,112,108,101,98, +117,108,108,101,116,105,110,105,110,99,108,117,100,101,100,111,99,99,117,114,114 +,101,100,105,110,116,101,114,110,97,108,36,40,116,104,105,115,41,46,114,101,112, +117,98,108,105,99,62,60,116,114,62,60,116,100,99,111,110,103,114,101,115,115,114 +,101,99,111,114,100,101,100,117,108,116,105,109,97,116,101,115,111,108,117,116, +105,111,110,60,117,108,32,105,100,61,34,100,105,115,99,111,118,101,114,72,111, +109,101,60,47,97,62,119,101,98,115,105,116,101,115,110,101,116,119,111,114,107, +115,97,108,116,104,111,117,103,104,101,110,116,105,114,101,108,121,109,101,109, +111,114,105,97,108,109,101,115,115,97,103,101,115,99,111,110,116,105,110,117,101 +,97,99,116,105,118,101,34,62,115,111,109,101,119,104,97,116,118,105,99,116,111, +114,105,97,87,101,115,116,101,114,110,32,32,116,105,116,108,101,61,34,76,111,99, +97,116,105,111,110,99,111,110,116,114,97,99,116,118,105,115,105,116,111,114,115, +68,111,119,110,108,111,97,100,119,105,116,104,111,117,116,32,114,105,103,104,116 +,34,62,10,109,101,97,115,117,114,101,115,119,105,100,116,104,32,61,32,118,97,114 +,105,97,98,108,101,105,110,118,111,108,118,101,100,118,105,114,103,105,110,105, +97,110,111,114,109,97,108,108,121,104,97,112,112,101,110,101,100,97,99,99,111, +117,110,116,115,115,116,97,110,100,105,110,103,110,97,116,105,111,110,97,108,82, +101,103,105,115,116,101,114,112,114,101,112,97,114,101,100,99,111,110,116,114, +111,108,115,97,99,99,117,114,97,116,101,98,105,114,116,104,100,97,121,115,116, +114,97,116,101,103,121,111,102,102,105,99,105,97,108,103,114,97,112,104,105,99, +115,99,114,105,109,105,110,97,108,112,111,115,115,105,98,108,121,99,111,110,115, +117,109,101,114,80,101,114,115,111,110,97,108,115,112,101,97,107,105,110,103,118 +,97,108,105,100,97,116,101,97,99,104,105,101,118,101,100,46,106,112,103,34,32,47 +,62,109,97,99,104,105,110,101,115,60,47,104,50,62,10,32,32,107,101,121,119,111, +114,100,115,102,114,105,101,110,100,108,121,98,114,111,116,104,101,114,115,99, +111,109,98,105,110,101,100,111,114,105,103,105,110,97,108,99,111,109,112,111,115 +,101,100,101,120,112,101,99,116,101,100,97,100,101,113,117,97,116,101,112,97,107 +,105,115,116,97,110,102,111,108,108,111,119,34,32,118,97,108,117,97,98,108,101, +60,47,108,97,98,101,108,62,114,101,108,97,116,105,118,101,98,114,105,110,103,105 +,110,103,105,110,99,114,101,97,115,101,103,111,118,101,114,110,111,114,112,108, +117,103,105,110,115,47,76,105,115,116,32,111,102,32,72,101,97,100,101,114,34,62, +34,32,110,97,109,101,61,34,32,40,38,113,117,111,116,59,103,114,97,100,117,97,116 +,101,60,47,104,101,97,100,62,10,99,111,109,109,101,114,99,101,109,97,108,97,121, +115,105,97,100,105,114,101,99,116,111,114,109,97,105,110,116,97,105,110,59,104, +101,105,103,104,116,58,115,99,104,101,100,117,108,101,99,104,97,110,103,105,110, +103,98,97,99,107,32,116,111,32,99,97,116,104,111,108,105,99,112,97,116,116,101, +114,110,115,99,111,108,111,114,58,32,35,103,114,101,97,116,101,115,116,115,117, +112,112,108,105,101,115,114,101,108,105,97,98,108,101,60,47,117,108,62,10,9,9,60 +,115,101,108,101,99,116,32,99,105,116,105,122,101,110,115,99,108,111,116,104,105 +,110,103,119,97,116,99,104,105,110,103,60,108,105,32,105,100,61,34,115,112,101, +99,105,102,105,99,99,97,114,114,121,105,110,103,115,101,110,116,101,110,99,101, +60,99,101,110,116,101,114,62,99,111,110,116,114,97,115,116,116,104,105,110,107, +105,110,103,99,97,116,99,104,40,101,41,115,111,117,116,104,101,114,110,77,105,99 +,104,97,101,108,32,109,101,114,99,104,97,110,116,99,97,114,111,117,115,101,108, +112,97,100,100,105,110,103,58,105,110,116,101,114,105,111,114,46,115,112,108,105 +,116,40,34,108,105,122,97,116,105,111,110,79,99,116,111,98,101,114,32,41,123,114 +,101,116,117,114,110,105,109,112,114,111,118,101,100,45,45,38,103,116,59,10,10, +99,111,118,101,114,97,103,101,99,104,97,105,114,109,97,110,46,112,110,103,34,32, +47,62,115,117,98,106,101,99,116,115,82,105,99,104,97,114,100,32,119,104,97,116, +101,118,101,114,112,114,111,98,97,98,108,121,114,101,99,111,118,101,114,121,98, +97,115,101,98,97,108,108,106,117,100,103,109,101,110,116,99,111,110,110,101,99, +116,46,46,99,115,115,34,32,47,62,32,119,101,98,115,105,116,101,114,101,112,111, +114,116,101,100,100,101,102,97,117,108,116,34,47,62,60,47,97,62,13,10,101,108, +101,99,116,114,105,99,115,99,111,116,108,97,110,100,99,114,101,97,116,105,111, +110,113,117,97,110,116,105,116,121,46,32,73,83,66,78,32,48,100,105,100,32,110, +111,116,32,105,110,115,116,97,110,99,101,45,115,101,97,114,99,104,45,34,32,108, +97,110,103,61,34,115,112,101,97,107,101,114,115,67,111,109,112,117,116,101,114, +99,111,110,116,97,105,110,115,97,114,99,104,105,118,101,115,109,105,110,105,115, +116,101,114,114,101,97,99,116,105,111,110,100,105,115,99,111,117,110,116,73,116, +97,108,105,97,110,111,99,114,105,116,101,114,105,97,115,116,114,111,110,103,108, +121,58,32,39,104,116,116,112,58,39,115,99,114,105,112,116,39,99,111,118,101,114, +105,110,103,111,102,102,101,114,105,110,103,97,112,112,101,97,114,101,100,66,114 +,105,116,105,115,104,32,105,100,101,110,116,105,102,121,70,97,99,101,98,111,111, +107,110,117,109,101,114,111,117,115,118,101,104,105,99,108,101,115,99,111,110,99 +,101,114,110,115,65,109,101,114,105,99,97,110,104,97,110,100,108,105,110,103,100 +,105,118,32,105,100,61,34,87,105,108,108,105,97,109,32,112,114,111,118,105,100, +101,114,95,99,111,110,116,101,110,116,97,99,99,117,114,97,99,121,115,101,99,116, +105,111,110,32,97,110,100,101,114,115,111,110,102,108,101,120,105,98,108,101,67, +97,116,101,103,111,114,121,108,97,119,114,101,110,99,101,60,115,99,114,105,112, +116,62,108,97,121,111,117,116,61,34,97,112,112,114,111,118,101,100,32,109,97,120 +,105,109,117,109,104,101,97,100,101,114,34,62,60,47,116,97,98,108,101,62,83,101, +114,118,105,99,101,115,104,97,109,105,108,116,111,110,99,117,114,114,101,110,116 +,32,99,97,110,97,100,105,97,110,99,104,97,110,110,101,108,115,47,116,104,101,109 +,101,115,47,47,97,114,116,105,99,108,101,111,112,116,105,111,110,97,108,112,111, +114,116,117,103,97,108,118,97,108,117,101,61,34,34,105,110,116,101,114,118,97, +108,119,105,114,101,108,101,115,115,101,110,116,105,116,108,101,100,97,103,101, +110,99,105,101,115,83,101,97,114,99,104,34,32,109,101,97,115,117,114,101,100,116 +,104,111,117,115,97,110,100,115,112,101,110,100,105,110,103,38,104,101,108,108, +105,112,59,110,101,119,32,68,97,116,101,34,32,115,105,122,101,61,34,112,97,103, +101,78,97,109,101,109,105,100,100,108,101,34,32,34,32,47,62,60,47,97,62,104,105, +100,100,101,110,34,62,115,101,113,117,101,110,99,101,112,101,114,115,111,110,97, +108,111,118,101,114,102,108,111,119,111,112,105,110,105,111,110,115,105,108,108, +105,110,111,105,115,108,105,110,107,115,34,62,10,9,60,116,105,116,108,101,62,118 +,101,114,115,105,111,110,115,115,97,116,117,114,100,97,121,116,101,114,109,105, +110,97,108,105,116,101,109,112,114,111,112,101,110,103,105,110,101,101,114,115, +101,99,116,105,111,110,115,100,101,115,105,103,110,101,114,112,114,111,112,111, +115,97,108,61,34,102,97,108,115,101,34,69,115,112,97,195,177,111,108,114,101,108 +,101,97,115,101,115,115,117,98,109,105,116,34,32,101,114,38,113,117,111,116,59, +97,100,100,105,116,105,111,110,115,121,109,112,116,111,109,115,111,114,105,101, +110,116,101,100,114,101,115,111,117,114,99,101,114,105,103,104,116,34,62,60,112, +108,101,97,115,117,114,101,115,116,97,116,105,111,110,115,104,105,115,116,111, +114,121,46,108,101,97,118,105,110,103,32,32,98,111,114,100,101,114,61,99,111,110 +,116,101,110,116,115,99,101,110,116,101,114,34,62,46,10,10,83,111,109,101,32,100 +,105,114,101,99,116,101,100,115,117,105,116,97,98,108,101,98,117,108,103,97,114, +105,97,46,115,104,111,119,40,41,59,100,101,115,105,103,110,101,100,71,101,110, +101,114,97,108,32,99,111,110,99,101,112,116,115,69,120,97,109,112,108,101,115, +119,105,108,108,105,97,109,115,79,114,105,103,105,110,97,108,34,62,60,115,112,97 +,110,62,115,101,97,114,99,104,34,62,111,112,101,114,97,116,111,114,114,101,113, +117,101,115,116,115,97,32,38,113,117,111,116,59,97,108,108,111,119,105,110,103, +68,111,99,117,109,101,110,116,114,101,118,105,115,105,111,110,46,32,10,10,84,104 +,101,32,121,111,117,114,115,101,108,102,67,111,110,116,97,99,116,32,109,105,99, +104,105,103,97,110,69,110,103,108,105,115,104,32,99,111,108,117,109,98,105,97, +112,114,105,111,114,105,116,121,112,114,105,110,116,105,110,103,100,114,105,110, +107,105,110,103,102,97,99,105,108,105,116,121,114,101,116,117,114,110,101,100,67 +,111,110,116,101,110,116,32,111,102,102,105,99,101,114,115,82,117,115,115,105,97 +,110,32,103,101,110,101,114,97,116,101,45,56,56,53,57,45,49,34,105,110,100,105, +99,97,116,101,102,97,109,105,108,105,97,114,32,113,117,97,108,105,116,121,109,97 +,114,103,105,110,58,48,32,99,111,110,116,101,110,116,118,105,101,119,112,111,114 +,116,99,111,110,116,97,99,116,115,45,116,105,116,108,101,34,62,112,111,114,116, +97,98,108,101,46,108,101,110,103,116,104,32,101,108,105,103,105,98,108,101,105, +110,118,111,108,118,101,115,97,116,108,97,110,116,105,99,111,110,108,111,97,100, +61,34,100,101,102,97,117,108,116,46,115,117,112,112,108,105,101,100,112,97,121, +109,101,110,116,115,103,108,111,115,115,97,114,121,10,10,65,102,116,101,114,32, +103,117,105,100,97,110,99,101,60,47,116,100,62,60,116,100,101,110,99,111,100,105 +,110,103,109,105,100,100,108,101,34,62,99,97,109,101,32,116,111,32,100,105,115, +112,108,97,121,115,115,99,111,116,116,105,115,104,106,111,110,97,116,104,97,110, +109,97,106,111,114,105,116,121,119,105,100,103,101,116,115,46,99,108,105,110,105 +,99,97,108,116,104,97,105,108,97,110,100,116,101,97,99,104,101,114,115,60,104, +101,97,100,62,10,9,97,102,102,101,99,116,101,100,115,117,112,112,111,114,116,115 +,112,111,105,110,116,101,114,59,116,111,83,116,114,105,110,103,60,47,115,109,97, +108,108,62,111,107,108,97,104,111,109,97,119,105,108,108,32,98,101,32,105,110, +118,101,115,116,111,114,48,34,32,97,108,116,61,34,104,111,108,105,100,97,121,115 +,82,101,115,111,117,114,99,101,108,105,99,101,110,115,101,100,32,40,119,104,105, +99,104,32,46,32,65,102,116,101,114,32,99,111,110,115,105,100,101,114,118,105,115 +,105,116,105,110,103,101,120,112,108,111,114,101,114,112,114,105,109,97,114,121, +32,115,101,97,114,99,104,34,32,97,110,100,114,111,105,100,34,113,117,105,99,107, +108,121,32,109,101,101,116,105,110,103,115,101,115,116,105,109,97,116,101,59,114 +,101,116,117,114,110,32,59,99,111,108,111,114,58,35,32,104,101,105,103,104,116, +61,97,112,112,114,111,118,97,108,44,32,38,113,117,111,116,59,32,99,104,101,99, +107,101,100,46,109,105,110,46,106,115,34,109,97,103,110,101,116,105,99,62,60,47, +97,62,60,47,104,102,111,114,101,99,97,115,116,46,32,87,104,105,108,101,32,116, +104,117,114,115,100,97,121,100,118,101,114,116,105,115,101,38,101,97,99,117,116, +101,59,104,97,115,67,108,97,115,115,101,118,97,108,117,97,116,101,111,114,100, +101,114,105,110,103,101,120,105,115,116,105,110,103,112,97,116,105,101,110,116, +115,32,79,110,108,105,110,101,32,99,111,108,111,114,97,100,111,79,112,116,105, +111,110,115,34,99,97,109,112,98,101,108,108,60,33,45,45,32,101,110,100,60,47,115 +,112,97,110,62,60,60,98,114,32,47,62,13,10,95,112,111,112,117,112,115,124,115,99 +,105,101,110,99,101,115,44,38,113,117,111,116,59,32,113,117,97,108,105,116,121, +32,87,105,110,100,111,119,115,32,97,115,115,105,103,110,101,100,104,101,105,103, +104,116,58,32,60,98,32,99,108,97,115,115,108,101,38,113,117,111,116,59,32,118,97 +,108,117,101,61,34,32,67,111,109,112,97,110,121,101,120,97,109,112,108,101,115, +60,105,102,114,97,109,101,32,98,101,108,105,101,118,101,115,112,114,101,115,101, +110,116,115,109,97,114,115,104,97,108,108,112,97,114,116,32,111,102,32,112,114, +111,112,101,114,108,121,41,46,10,10,84,104,101,32,116,97,120,111,110,111,109,121 +,109,117,99,104,32,111,102,32,60,47,115,112,97,110,62,10,34,32,100,97,116,97,45, +115,114,116,117,103,117,195,170,115,115,99,114,111,108,108,84,111,32,112,114,111 +,106,101,99,116,60,104,101,97,100,62,13,10,97,116,116,111,114,110,101,121,101, +109,112,104,97,115,105,115,115,112,111,110,115,111,114,115,102,97,110,99,121,98, +111,120,119,111,114,108,100,39,115,32,119,105,108,100,108,105,102,101,99,104,101 +,99,107,101,100,61,115,101,115,115,105,111,110,115,112,114,111,103,114,97,109, +109,112,120,59,102,111,110,116,45,32,80,114,111,106,101,99,116,106,111,117,114, +110,97,108,115,98,101,108,105,101,118,101,100,118,97,99,97,116,105,111,110,116, +104,111,109,112,115,111,110,108,105,103,104,116,105,110,103,97,110,100,32,116, +104,101,32,115,112,101,99,105,97,108,32,98,111,114,100,101,114,61,48,99,104,101, +99,107,105,110,103,60,47,116,98,111,100,121,62,60,98,117,116,116,111,110,32,67, +111,109,112,108,101,116,101,99,108,101,97,114,102,105,120,10,60,104,101,97,100, +62,10,97,114,116,105,99,108,101,32,60,115,101,99,116,105,111,110,102,105,110,100 +,105,110,103,115,114,111,108,101,32,105,110,32,112,111,112,117,108,97,114,32,32, +79,99,116,111,98,101,114,119,101,98,115,105,116,101,32,101,120,112,111,115,117, +114,101,117,115,101,100,32,116,111,32,32,99,104,97,110,103,101,115,111,112,101, +114,97,116,101,100,99,108,105,99,107,105,110,103,101,110,116,101,114,105,110,103 +,99,111,109,109,97,110,100,115,105,110,102,111,114,109,101,100,32,110,117,109,98 +,101,114,115,32,32,60,47,100,105,118,62,99,114,101,97,116,105,110,103,111,110,83 +,117,98,109,105,116,109,97,114,121,108,97,110,100,99,111,108,108,101,103,101,115 +,97,110,97,108,121,116,105,99,108,105,115,116,105,110,103,115,99,111,110,116,97, +99,116,46,108,111,103,103,101,100,73,110,97,100,118,105,115,111,114,121,115,105, +98,108,105,110,103,115,99,111,110,116,101,110,116,34,115,38,113,117,111,116,59, +41,115,46,32,84,104,105,115,32,112,97,99,107,97,103,101,115,99,104,101,99,107,98 +,111,120,115,117,103,103,101,115,116,115,112,114,101,103,110,97,110,116,116,111, +109,111,114,114,111,119,115,112,97,99,105,110,103,61,105,99,111,110,46,112,110, +103,106,97,112,97,110,101,115,101,99,111,100,101,98,97,115,101,98,117,116,116, +111,110,34,62,103,97,109,98,108,105,110,103,115,117,99,104,32,97,115,32,44,32, +119,104,105,108,101,32,60,47,115,112,97,110,62,32,109,105,115,115,111,117,114, +105,115,112,111,114,116,105,110,103,116,111,112,58,49,112,120,32,46,60,47,115, +112,97,110,62,116,101,110,115,105,111,110,115,119,105,100,116,104,61,34,50,108, +97,122,121,108,111,97,100,110,111,118,101,109,98,101,114,117,115,101,100,32,105, +110,32,104,101,105,103,104,116,61,34,99,114,105,112,116,34,62,10,38,110,98,115, +112,59,60,47,60,116,114,62,60,116,100,32,104,101,105,103,104,116,58,50,47,112, +114,111,100,117,99,116,99,111,117,110,116,114,121,32,105,110,99,108,117,100,101, +32,102,111,111,116,101,114,34,32,38,108,116,59,33,45,45,32,116,105,116,108,101, +34,62,60,47,106,113,117,101,114,121,46,60,47,102,111,114,109,62,10,40,231,174, +128,228,189,147,41,40,231,185,129,233,171,148,41,104,114,118,97,116,115,107,105, +105,116,97,108,105,97,110,111,114,111,109,195,162,110,196,131,116,195,188,114, +107,195,167,101,216,167,216,177,216,175,217,136,116,97,109,98,105,195,169,110, +110,111,116,105,99,105,97,115,109,101,110,115,97,106,101,115,112,101,114,115,111 +,110,97,115,100,101,114,101,99,104,111,115,110,97,99,105,111,110,97,108,115,101, +114,118,105,99,105,111,99,111,110,116,97,99,116,111,117,115,117,97,114,105,111, +115,112,114,111,103,114,97,109,97,103,111,98,105,101,114,110,111,101,109,112,114 +,101,115,97,115,97,110,117,110,99,105,111,115,118,97,108,101,110,99,105,97,99, +111,108,111,109,98,105,97,100,101,115,112,117,195,169,115,100,101,112,111,114, +116,101,115,112,114,111,121,101,99,116,111,112,114,111,100,117,99,116,111,112, +195,186,98,108,105,99,111,110,111,115,111,116,114,111,115,104,105,115,116,111, +114,105,97,112,114,101,115,101,110,116,101,109,105,108,108,111,110,101,115,109, +101,100,105,97,110,116,101,112,114,101,103,117,110,116,97,97,110,116,101,114,105 +,111,114,114,101,99,117,114,115,111,115,112,114,111,98,108,101,109,97,115,97,110 +,116,105,97,103,111,110,117,101,115,116,114,111,115,111,112,105,110,105,195,179, +110,105,109,112,114,105,109,105,114,109,105,101,110,116,114,97,115,97,109,195, +169,114,105,99,97,118,101,110,100,101,100,111,114,115,111,99,105,101,100,97,100, +114,101,115,112,101,99,116,111,114,101,97,108,105,122,97,114,114,101,103,105,115 +,116,114,111,112,97,108,97,98,114,97,115,105,110,116,101,114,195,169,115,101,110 +,116,111,110,99,101,115,101,115,112,101,99,105,97,108,109,105,101,109,98,114,111 +,115,114,101,97,108,105,100,97,100,99,195,179,114,100,111,98,97,122,97,114,97, +103,111,122,97,112,195,161,103,105,110,97,115,115,111,99,105,97,108,101,115,98, +108,111,113,117,101,97,114,103,101,115,116,105,195,179,110,97,108,113,117,105, +108,101,114,115,105,115,116,101,109,97,115,99,105,101,110,99,105,97,115,99,111, +109,112,108,101,116,111,118,101,114,115,105,195,179,110,99,111,109,112,108,101, +116,97,101,115,116,117,100,105,111,115,112,195,186,98,108,105,99,97,111,98,106, +101,116,105,118,111,97,108,105,99,97,110,116,101,98,117,115,99,97,100,111,114,99 +,97,110,116,105,100,97,100,101,110,116,114,97,100,97,115,97,99,99,105,111,110, +101,115,97,114,99,104,105,118,111,115,115,117,112,101,114,105,111,114,109,97,121 +,111,114,195,173,97,97,108,101,109,97,110,105,97,102,117,110,99,105,195,179,110, +195,186,108,116,105,109,111,115,104,97,99,105,101,110,100,111,97,113,117,101,108 +,108,111,115,101,100,105,99,105,195,179,110,102,101,114,110,97,110,100,111,97, +109,98,105,101,110,116,101,102,97,99,101,98,111,111,107,110,117,101,115,116,114, +97,115,99,108,105,101,110,116,101,115,112,114,111,99,101,115,111,115,98,97,115, +116,97,110,116,101,112,114,101,115,101,110,116,97,114,101,112,111,114,116,97,114 +,99,111,110,103,114,101,115,111,112,117,98,108,105,99,97,114,99,111,109,101,114, +99,105,111,99,111,110,116,114,97,116,111,106,195,179,118,101,110,101,115,100,105 +,115,116,114,105,116,111,116,195,169,99,110,105,99,97,99,111,110,106,117,110,116 +,111,101,110,101,114,103,195,173,97,116,114,97,98,97,106,97,114,97,115,116,117, +114,105,97,115,114,101,99,105,101,110,116,101,117,116,105,108,105,122,97,114,98, +111,108,101,116,195,173,110,115,97,108,118,97,100,111,114,99,111,114,114,101,99, +116,97,116,114,97,98,97,106,111,115,112,114,105,109,101,114,111,115,110,101,103, +111,99,105,111,115,108,105,98,101,114,116,97,100,100,101,116,97,108,108,101,115, +112,97,110,116,97,108,108,97,112,114,195,179,120,105,109,111,97,108,109,101,114, +195,173,97,97,110,105,109,97,108,101,115,113,117,105,195,169,110,101,115,99,111, +114,97,122,195,179,110,115,101,99,99,105,195,179,110,98,117,115,99,97,110,100, +111,111,112,99,105,111,110,101,115,101,120,116,101,114,105,111,114,99,111,110,99 +,101,112,116,111,116,111,100,97,118,195,173,97,103,97,108,101,114,195,173,97,101 +,115,99,114,105,98,105,114,109,101,100,105,99,105,110,97,108,105,99,101,110,99, +105,97,99,111,110,115,117,108,116,97,97,115,112,101,99,116,111,115,99,114,195, +173,116,105,99,97,100,195,179,108,97,114,101,115,106,117,115,116,105,99,105,97, +100,101,98,101,114,195,161,110,112,101,114,195,173,111,100,111,110,101,99,101, +115,105,116,97,109,97,110,116,101,110,101,114,112,101,113,117,101,195,177,111, +114,101,99,105,98,105,100,97,116,114,105,98,117,110,97,108,116,101,110,101,114, +105,102,101,99,97,110,99,105,195,179,110,99,97,110,97,114,105,97,115,100,101,115 +,99,97,114,103,97,100,105,118,101,114,115,111,115,109,97,108,108,111,114,99,97, +114,101,113,117,105,101,114,101,116,195,169,99,110,105,99,111,100,101,98,101,114 +,195,173,97,118,105,118,105,101,110,100,97,102,105,110,97,110,122,97,115,97,100, +101,108,97,110,116,101,102,117,110,99,105,111,110,97,99,111,110,115,101,106,111, +115,100,105,102,195,173,99,105,108,99,105,117,100,97,100,101,115,97,110,116,105, +103,117,97,115,97,118,97,110,122,97,100,97,116,195,169,114,109,105,110,111,117, +110,105,100,97,100,101,115,115,195,161,110,99,104,101,122,99,97,109,112,97,195, +177,97,115,111,102,116,111,110,105,99,114,101,118,105,115,116,97,115,99,111,110, +116,105,101,110,101,115,101,99,116,111,114,101,115,109,111,109,101,110,116,111, +115,102,97,99,117,108,116,97,100,99,114,195,169,100,105,116,111,100,105,118,101, +114,115,97,115,115,117,112,117,101,115,116,111,102,97,99,116,111,114,101,115,115 +,101,103,117,110,100,111,115,112,101,113,117,101,195,177,97,208,179,208,190,208, +180,208,176,208,181,209,129,208,187,208,184,208,181,209,129,209,130,209,140,208, +177,209,139,208,187,208,190,208,177,209,139,209,130,209,140,209,141,209,130,208, +190,208,188,208,149,209,129,208,187,208,184,209,130,208,190,208,179,208,190,208, +188,208,181,208,189,209,143,208,178,209,129,208,181,209,133,209,141,209,130,208, +190,208,185,208,180,208,176,208,182,208,181,208,177,209,139,208,187,208,184,208, +179,208,190,208,180,209,131,208,180,208,181,208,189,209,140,209,141,209,130,208, +190,209,130,208,177,209,139,208,187,208,176,209,129,208,181,208,177,209,143,208, +190,208,180,208,184,208,189,209,129,208,181,208,177,208,181,208,189,208,176,208, +180,208,190,209,129,208,176,208,185,209,130,209,132,208,190,209,130,208,190,208, +189,208,181,208,179,208,190,209,129,208,178,208,190,208,184,209,129,208,178,208, +190,208,185,208,184,208,179,209,128,209,139,209,130,208,190,208,182,208,181,208, +178,209,129,208,181,208,188,209,129,208,178,208,190,209,142,208,187,208,184,209, +136,209,140,209,141,209,130,208,184,209,133,208,191,208,190,208,186,208,176,208, +180,208,189,208,181,208,185,208,180,208,190,208,188,208,176,208,188,208,184,209, +128,208,176,208,187,208,184,208,177,208,190,209,130,208,181,208,188,209,131,209, +133,208,190,209,130,209,143,208,180,208,178,209,131,209,133,209,129,208,181,209, +130,208,184,208,187,209,142,208,180,208,184,208,180,208,181,208,187,208,190,208, +188,208,184,209,128,208,181,209,130,208,181,208,177,209,143,209,129,208,178,208, +190,208,181,208,178,208,184,208,180,208,181,209,135,208,181,208,179,208,190,209, +141,209,130,208,184,208,188,209,129,209,135,208,181,209,130,209,130,208,181,208, +188,209,139,209,134,208,181,208,189,209,139,209,129,209,130,208,176,208,187,208, +178,208,181,208,180,209,140,209,130,208,181,208,188,208,181,208,178,208,190,208, +180,209,139,209,130,208,181,208,177,208,181,208,178,209,139,209,136,208,181,208, +189,208,176,208,188,208,184,209,130,208,184,208,191,208,176,209,130,208,190,208, +188,209,131,208,191,209,128,208,176,208,178,208,187,208,184,209,134,208,176,208, +190,208,180,208,189,208,176,208,179,208,190,208,180,209,139,208,183,208,189,208, +176,209,142,208,188,208,190,208,179,209,131,208,180,209,128,209,131,208,179,208, +178,209,129,208,181,208,185,208,184,208,180,208,181,209,130,208,186,208,184,208, +189,208,190,208,190,208,180,208,189,208,190,208,180,208,181,208,187,208,176,208, +180,208,181,208,187,208,181,209,129,209,128,208,190,208,186,208,184,209,142,208, +189,209,143,208,178,208,181,209,129,209,140,208,149,209,129,209,130,209,140,209, +128,208,176,208,183,208,176,208,189,208,176,209,136,208,184,216,167,217,132,217, +132,217,135,216,167,217,132,216,170,217,138,216,172,217,133,217,138,216,185,216, +174,216,167,216,181,216,169,216,167,217,132,216,176,217,138,216,185,217,132,217, +138,217,135,216,172,216,175,217,138,216,175,216,167,217,132,216,162,217,134,216, +167,217,132,216,177,216,175,216,170,216,173,217,131,217,133,216,181,217,129,216, +173,216,169,217,131,216,167,217,134,216,170,216,167,217,132,217,132,217,138,217, +138,217,131,217,136,217,134,216,180,216,168,217,131,216,169,217,129,217,138,217, +135,216,167,216,168,217,134,216,167,216,170,216,173,217,136,216,167,216,161,216, +163,217,131,216,171,216,177,216,174,217,132,216,167,217,132,216,167,217,132,216, +173,216,168,216,175,217,132,217,138,217,132,216,175,216,177,217,136,216,179,216, +167,216,182,216,186,216,183,216,170,217,131,217,136,217,134,217,135,217,134,216, +167,217,131,216,179,216,167,216,173,216,169,217,134,216,167,216,175,217,138,216, +167,217,132,216,183,216,168,216,185,217,132,217,138,217,131,216,180,217,131,216, +177,216,167,217,138,217,133,217,131,217,134,217,133,217,134,217,135,216,167,216, +180,216,177,217,131,216,169,216,177,216,166,217,138,216,179,217,134,216,180,217, +138,216,183,217,133,216,167,216,176,216,167,216,167,217,132,217,129,217,134,216, +180,216,168,216,167,216,168,216,170,216,185,216,168,216,177,216,177,216,173,217, +133,216,169,217,131,216,167,217,129,216,169,217,138,217,130,217,136,217,132,217, +133,216,177,217,131,216,178,217,131,217,132,217,133,216,169,216,163,216,173,217, +133,216,175,217,130,217,132,216,168,217,138,217,138,216,185,217,134,217,138,216, +181,217,136,216,177,216,169,216,183,216,177,217,138,217,130,216,180,216,167,216, +177,217,131,216,172,217,136,216,167,217,132,216,163,216,174,216,177,217,137,217, +133,216,185,217,134,216,167,216,167,216,168,216,173,216,171,216,185,216,177,217, +136,216,182,216,168,216,180,217,131,217,132,217,133,216,179,216,172,217,132,216, +168,217,134,216,167,217,134,216,174,216,167,217,132,216,175,217,131,216,170,216, +167,216,168,217,131,217,132,217,138,216,169,216,168,216,175,217,136,217,134,216, +163,217,138,216,182,216,167,217,138,217,136,216,172,216,175,217,129,216,177,217, +138,217,130,217,131,216,170,216,168,216,170,216,163,217,129,216,182,217,132,217, +133,216,183,216,168,216,174,216,167,217,131,216,171,216,177,216,168,216,167,216, +177,217,131,216,167,217,129,216,182,217,132,216,167,216,173,217,132,217,137,217, +134,217,129,216,179,217,135,216,163,217,138,216,167,217,133,216,177,216,175,217, +136,216,175,216,163,217,134,217,135,216,167,216,175,217,138,217,134,216,167,216, +167,217,132,216,167,217,134,217,133,216,185,216,177,216,182,216,170,216,185,217, +132,217,133,216,175,216,167,216,174,217,132,217,133,217,133,217,131,217,134,0,0, +0,0,0,0,0,0,1,0,1,0,1,0,1,0,2,0,2,0,2,0,2,0,4,0,4,0,4,0,4,0,0,1,2,3,4,5,6,7,7,6, +5,4,3,2,1,0,8,9,10,11,12,13,14,15,15,14,13,12,11,10,9,8,16,17,18,19,20,21,22,23, +23,22,21,20,19,18,17,16,24,25,26,27,28,29,30,31,31,30,29,28,27,26,25,24,255,255, +255,255,0,0,0,0,0,0,0,0,255,255,255,255,1,0,0,0,2,0,0,0,2,0,0,0,1,0,0,0,1,0,0,0, +3,0,0,0,255,255,0,1,0,0,0,1,0,0,255,255,0,1,0,0,0,8,0,8,0,8,0,8,0,0,0,1,0,2,0,3, +0,4,0,5,0,6,0,7,114,101,115,111,117,114,99,101,115,99,111,117,110,116,114,105, +101,115,113,117,101,115,116,105,111,110,115,101,113,117,105,112,109,101,110,116, +99,111,109,109,117,110,105,116,121,97,118,97,105,108,97,98,108,101,104,105,103, +104,108,105,103,104,116,68,84,68,47,120,104,116,109,108,109,97,114,107,101,116, +105,110,103,107,110,111,119,108,101,100,103,101,115,111,109,101,116,104,105,110, +103,99,111,110,116,97,105,110,101,114,100,105,114,101,99,116,105,111,110,115,117 +,98,115,99,114,105,98,101,97,100,118,101,114,116,105,115,101,99,104,97,114,97,99 +,116,101,114,34,32,118,97,108,117,101,61,34,60,47,115,101,108,101,99,116,62,65, +117,115,116,114,97,108,105,97,34,32,99,108,97,115,115,61,34,115,105,116,117,97, +116,105,111,110,97,117,116,104,111,114,105,116,121,102,111,108,108,111,119,105, +110,103,112,114,105,109,97,114,105,108,121,111,112,101,114,97,116,105,111,110,99 +,104,97,108,108,101,110,103,101,100,101,118,101,108,111,112,101,100,97,110,111, +110,121,109,111,117,115,102,117,110,99,116,105,111,110,32,102,117,110,99,116,105 +,111,110,115,99,111,109,112,97,110,105,101,115,115,116,114,117,99,116,117,114, +101,97,103,114,101,101,109,101,110,116,34,32,116,105,116,108,101,61,34,112,111, +116,101,110,116,105,97,108,101,100,117,99,97,116,105,111,110,97,114,103,117,109, +101,110,116,115,115,101,99,111,110,100,97,114,121,99,111,112,121,114,105,103,104 +,116,108,97,110,103,117,97,103,101,115,101,120,99,108,117,115,105,118,101,99,111 +,110,100,105,116,105,111,110,60,47,102,111,114,109,62,13,10,115,116,97,116,101, +109,101,110,116,97,116,116,101,110,116,105,111,110,66,105,111,103,114,97,112,104 +,121,125,32,101,108,115,101,32,123,10,115,111,108,117,116,105,111,110,115,119, +104,101,110,32,116,104,101,32,65,110,97,108,121,116,105,99,115,116,101,109,112, +108,97,116,101,115,100,97,110,103,101,114,111,117,115,115,97,116,101,108,108,105 +,116,101,100,111,99,117,109,101,110,116,115,112,117,98,108,105,115,104,101,114, +105,109,112,111,114,116,97,110,116,112,114,111,116,111,116,121,112,101,105,110, +102,108,117,101,110,99,101,38,114,97,113,117,111,59,60,47,101,102,102,101,99,116 +,105,118,101,103,101,110,101,114,97,108,108,121,116,114,97,110,115,102,111,114, +109,98,101,97,117,116,105,102,117,108,116,114,97,110,115,112,111,114,116,111,114 +,103,97,110,105,122,101,100,112,117,98,108,105,115,104,101,100,112,114,111,109, +105,110,101,110,116,117,110,116,105,108,32,116,104,101,116,104,117,109,98,110,97 +,105,108,78,97,116,105,111,110,97,108,32,46,102,111,99,117,115,40,41,59,111,118, +101,114,32,116,104,101,32,109,105,103,114,97,116,105,111,110,97,110,110,111,117, +110,99,101,100,102,111,111,116,101,114,34,62,10,101,120,99,101,112,116,105,111, +110,108,101,115,115,32,116,104,97,110,101,120,112,101,110,115,105,118,101,102, +111,114,109,97,116,105,111,110,102,114,97,109,101,119,111,114,107,116,101,114, +114,105,116,111,114,121,110,100,105,99,97,116,105,111,110,99,117,114,114,101,110 +,116,108,121,99,108,97,115,115,78,97,109,101,99,114,105,116,105,99,105,115,109, +116,114,97,100,105,116,105,111,110,101,108,115,101,119,104,101,114,101,65,108, +101,120,97,110,100,101,114,97,112,112,111,105,110,116,101,100,109,97,116,101,114 +,105,97,108,115,98,114,111,97,100,99,97,115,116,109,101,110,116,105,111,110,101, +100,97,102,102,105,108,105,97,116,101,60,47,111,112,116,105,111,110,62,116,114, +101,97,116,109,101,110,116,100,105,102,102,101,114,101,110,116,47,100,101,102,97 +,117,108,116,46,80,114,101,115,105,100,101,110,116,111,110,99,108,105,99,107,61, +34,98,105,111,103,114,97,112,104,121,111,116,104,101,114,119,105,115,101,112,101 +,114,109,97,110,101,110,116,70,114,97,110,195,167,97,105,115,72,111,108,108,121, +119,111,111,100,101,120,112,97,110,115,105,111,110,115,116,97,110,100,97,114,100 +,115,60,47,115,116,121,108,101,62,10,114,101,100,117,99,116,105,111,110,68,101, +99,101,109,98,101,114,32,112,114,101,102,101,114,114,101,100,67,97,109,98,114, +105,100,103,101,111,112,112,111,110,101,110,116,115,66,117,115,105,110,101,115, +115,32,99,111,110,102,117,115,105,111,110,62,10,60,116,105,116,108,101,62,112, +114,101,115,101,110,116,101,100,101,120,112,108,97,105,110,101,100,100,111,101, +115,32,110,111,116,32,119,111,114,108,100,119,105,100,101,105,110,116,101,114, +102,97,99,101,112,111,115,105,116,105,111,110,115,110,101,119,115,112,97,112,101 +,114,60,47,116,97,98,108,101,62,10,109,111,117,110,116,97,105,110,115,108,105, +107,101,32,116,104,101,32,101,115,115,101,110,116,105,97,108,102,105,110,97,110, +99,105,97,108,115,101,108,101,99,116,105,111,110,97,99,116,105,111,110,61,34,47, +97,98,97,110,100,111,110,101,100,69,100,117,99,97,116,105,111,110,112,97,114,115 +,101,73,110,116,40,115,116,97,98,105,108,105,116,121,117,110,97,98,108,101,32, +116,111,60,47,116,105,116,108,101,62,10,114,101,108,97,116,105,111,110,115,78, +111,116,101,32,116,104,97,116,101,102,102,105,99,105,101,110,116,112,101,114,102 +,111,114,109,101,100,116,119,111,32,121,101,97,114,115,83,105,110,99,101,32,116, +104,101,116,104,101,114,101,102,111,114,101,119,114,97,112,112,101,114,34,62,97, +108,116,101,114,110,97,116,101,105,110,99,114,101,97,115,101,100,66,97,116,116, +108,101,32,111,102,112,101,114,99,101,105,118,101,100,116,114,121,105,110,103,32 +,116,111,110,101,99,101,115,115,97,114,121,112,111,114,116,114,97,121,101,100, +101,108,101,99,116,105,111,110,115,69,108,105,122,97,98,101,116,104,60,47,105, +102,114,97,109,101,62,100,105,115,99,111,118,101,114,121,105,110,115,117,114,97, +110,99,101,115,46,108,101,110,103,116,104,59,108,101,103,101,110,100,97,114,121, +71,101,111,103,114,97,112,104,121,99,97,110,100,105,100,97,116,101,99,111,114, +112,111,114,97,116,101,115,111,109,101,116,105,109,101,115,115,101,114,118,105, +99,101,115,46,105,110,104,101,114,105,116,101,100,60,47,115,116,114,111,110,103, +62,67,111,109,109,117,110,105,116,121,114,101,108,105,103,105,111,117,115,108, +111,99,97,116,105,111,110,115,67,111,109,109,105,116,116,101,101,98,117,105,108, +100,105,110,103,115,116,104,101,32,119,111,114,108,100,110,111,32,108,111,110, +103,101,114,98,101,103,105,110,110,105,110,103,114,101,102,101,114,101,110,99, +101,99,97,110,110,111,116,32,98,101,102,114,101,113,117,101,110,99,121,116,121, +112,105,99,97,108,108,121,105,110,116,111,32,116,104,101,32,114,101,108,97,116, +105,118,101,59,114,101,99,111,114,100,105,110,103,112,114,101,115,105,100,101, +110,116,105,110,105,116,105,97,108,108,121,116,101,99,104,110,105,113,117,101, +116,104,101,32,111,116,104,101,114,105,116,32,99,97,110,32,98,101,101,120,105, +115,116,101,110,99,101,117,110,100,101,114,108,105,110,101,116,104,105,115,32, +116,105,109,101,116,101,108,101,112,104,111,110,101,105,116,101,109,115,99,111, +112,101,112,114,97,99,116,105,99,101,115,97,100,118,97,110,116,97,103,101,41,59, +114,101,116,117,114,110,32,70,111,114,32,111,116,104,101,114,112,114,111,118,105 +,100,105,110,103,100,101,109,111,99,114,97,99,121,98,111,116,104,32,116,104,101, +32,101,120,116,101,110,115,105,118,101,115,117,102,102,101,114,105,110,103,115, +117,112,112,111,114,116,101,100,99,111,109,112,117,116,101,114,115,32,102,117, +110,99,116,105,111,110,112,114,97,99,116,105,99,97,108,115,97,105,100,32,116,104 +,97,116,105,116,32,109,97,121,32,98,101,69,110,103,108,105,115,104,60,47,102,114 +,111,109,32,116,104,101,32,115,99,104,101,100,117,108,101,100,100,111,119,110, +108,111,97,100,115,60,47,108,97,98,101,108,62,10,115,117,115,112,101,99,116,101, +100,109,97,114,103,105,110,58,32,48,115,112,105,114,105,116,117,97,108,60,47,104 +,101,97,100,62,10,10,109,105,99,114,111,115,111,102,116,103,114,97,100,117,97, +108,108,121,100,105,115,99,117,115,115,101,100,104,101,32,98,101,99,97,109,101, +101,120,101,99,117,116,105,118,101,106,113,117,101,114,121,46,106,115,104,111, +117,115,101,104,111,108,100,99,111,110,102,105,114,109,101,100,112,117,114,99, +104,97,115,101,100,108,105,116,101,114,97,108,108,121,100,101,115,116,114,111, +121,101,100,117,112,32,116,111,32,116,104,101,118,97,114,105,97,116,105,111,110, +114,101,109,97,105,110,105,110,103,105,116,32,105,115,32,110,111,116,99,101,110, +116,117,114,105,101,115,74,97,112,97,110,101,115,101,32,97,109,111,110,103,32, +116,104,101,99,111,109,112,108,101,116,101,100,97,108,103,111,114,105,116,104, +109,105,110,116,101,114,101,115,116,115,114,101,98,101,108,108,105,111,110,117, +110,100,101,102,105,110,101,100,101,110,99,111,117,114,97,103,101,114,101,115, +105,122,97,98,108,101,105,110,118,111,108,118,105,110,103,115,101,110,115,105, +116,105,118,101,117,110,105,118,101,114,115,97,108,112,114,111,118,105,115,105, +111,110,40,97,108,116,104,111,117,103,104,102,101,97,116,117,114,105,110,103,99, +111,110,100,117,99,116,101,100,41,44,32,119,104,105,99,104,32,99,111,110,116,105 +,110,117,101,100,45,104,101,97,100,101,114,34,62,70,101,98,114,117,97,114,121,32 +,110,117,109,101,114,111,117,115,32,111,118,101,114,102,108,111,119,58,99,111, +109,112,111,110,101,110,116,102,114,97,103,109,101,110,116,115,101,120,99,101, +108,108,101,110,116,99,111,108,115,112,97,110,61,34,116,101,99,104,110,105,99,97 +,108,110,101,97,114,32,116,104,101,32,65,100,118,97,110,99,101,100,32,115,111, +117,114,99,101,32,111,102,101,120,112,114,101,115,115,101,100,72,111,110,103,32, +75,111,110,103,32,70,97,99,101,98,111,111,107,109,117,108,116,105,112,108,101,32 +,109,101,99,104,97,110,105,115,109,101,108,101,118,97,116,105,111,110,111,102, +102,101,110,115,105,118,101,60,47,102,111,114,109,62,10,9,115,112,111,110,115, +111,114,101,100,100,111,99,117,109,101,110,116,46,111,114,32,38,113,117,111,116, +59,116,104,101,114,101,32,97,114,101,116,104,111,115,101,32,119,104,111,109,111, +118,101,109,101,110,116,115,112,114,111,99,101,115,115,101,115,100,105,102,102, +105,99,117,108,116,115,117,98,109,105,116,116,101,100,114,101,99,111,109,109,101 +,110,100,99,111,110,118,105,110,99,101,100,112,114,111,109,111,116,105,110,103, +34,32,119,105,100,116,104,61,34,46,114,101,112,108,97,99,101,40,99,108,97,115, +115,105,99,97,108,99,111,97,108,105,116,105,111,110,104,105,115,32,102,105,114, +115,116,100,101,99,105,115,105,111,110,115,97,115,115,105,115,116,97,110,116,105 +,110,100,105,99,97,116,101,100,101,118,111,108,117,116,105,111,110,45,119,114,97 +,112,112,101,114,34,101,110,111,117,103,104,32,116,111,97,108,111,110,103,32,116 +,104,101,100,101,108,105,118,101,114,101,100,45,45,62,13,10,60,33,45,45,65,109, +101,114,105,99,97,110,32,112,114,111,116,101,99,116,101,100,78,111,118,101,109, +98,101,114,32,60,47,115,116,121,108,101,62,60,102,117,114,110,105,116,117,114, +101,73,110,116,101,114,110,101,116,32,32,111,110,98,108,117,114,61,34,115,117, +115,112,101,110,100,101,100,114,101,99,105,112,105,101,110,116,98,97,115,101,100 +,32,111,110,32,77,111,114,101,111,118,101,114,44,97,98,111,108,105,115,104,101, +100,99,111,108,108,101,99,116,101,100,119,101,114,101,32,109,97,100,101,101,109, +111,116,105,111,110,97,108,101,109,101,114,103,101,110,99,121,110,97,114,114,97, +116,105,118,101,97,100,118,111,99,97,116,101,115,112,120,59,98,111,114,100,101, +114,99,111,109,109,105,116,116,101,100,100,105,114,61,34,108,116,114,34,101,109, +112,108,111,121,101,101,115,114,101,115,101,97,114,99,104,46,32,115,101,108,101, +99,116,101,100,115,117,99,99,101,115,115,111,114,99,117,115,116,111,109,101,114, +115,100,105,115,112,108,97,121,101,100,83,101,112,116,101,109,98,101,114,97,100, +100,67,108,97,115,115,40,70,97,99,101,98,111,111,107,32,115,117,103,103,101,115, +116,101,100,97,110,100,32,108,97,116,101,114,111,112,101,114,97,116,105,110,103, +101,108,97,98,111,114,97,116,101,83,111,109,101,116,105,109,101,115,73,110,115, +116,105,116,117,116,101,99,101,114,116,97,105,110,108,121,105,110,115,116,97,108 +,108,101,100,102,111,108,108,111,119,101,114,115,74,101,114,117,115,97,108,101, +109,116,104,101,121,32,104,97,118,101,99,111,109,112,117,116,105,110,103,103,101 +,110,101,114,97,116,101,100,112,114,111,118,105,110,99,101,115,103,117,97,114,97 +,110,116,101,101,97,114,98,105,116,114,97,114,121,114,101,99,111,103,110,105,122 +,101,119,97,110,116,101,100,32,116,111,112,120,59,119,105,100,116,104,58,116,104 +,101,111,114,121,32,111,102,98,101,104,97,118,105,111,117,114,87,104,105,108,101 +,32,116,104,101,101,115,116,105,109,97,116,101,100,98,101,103,97,110,32,116,111, +32,105,116,32,98,101,99,97,109,101,109,97,103,110,105,116,117,100,101,109,117, +115,116,32,104,97,118,101,109,111,114,101,32,116,104,97,110,68,105,114,101,99, +116,111,114,121,101,120,116,101,110,115,105,111,110,115,101,99,114,101,116,97, +114,121,110,97,116,117,114,97,108,108,121,111,99,99,117,114,114,105,110,103,118, +97,114,105,97,98,108,101,115,103,105,118,101,110,32,116,104,101,112,108,97,116, +102,111,114,109,46,60,47,108,97,98,101,108,62,60,102,97,105,108,101,100,32,116, +111,99,111,109,112,111,117,110,100,115,107,105,110,100,115,32,111,102,32,115,111 +,99,105,101,116,105,101,115,97,108,111,110,103,115,105,100,101,32,45,45,38,103, +116,59,10,10,115,111,117,116,104,119,101,115,116,116,104,101,32,114,105,103,104, +116,114,97,100,105,97,116,105,111,110,109,97,121,32,104,97,118,101,32,117,110, +101,115,99,97,112,101,40,115,112,111,107,101,110,32,105,110,34,32,104,114,101, +102,61,34,47,112,114,111,103,114,97,109,109,101,111,110,108,121,32,116,104,101, +32,99,111,109,101,32,102,114,111,109,100,105,114,101,99,116,111,114,121,98,117, +114,105,101,100,32,105,110,97,32,115,105,109,105,108,97,114,116,104,101,121,32, +119,101,114,101,60,47,102,111,110,116,62,60,47,78,111,114,119,101,103,105,97,110 +,115,112,101,99,105,102,105,101,100,112,114,111,100,117,99,105,110,103,112,97, +115,115,101,110,103,101,114,40,110,101,119,32,68,97,116,101,116,101,109,112,111, +114,97,114,121,102,105,99,116,105,111,110,97,108,65,102,116,101,114,32,116,104, +101,101,113,117,97,116,105,111,110,115,100,111,119,110,108,111,97,100,46,114,101 +,103,117,108,97,114,108,121,100,101,118,101,108,111,112,101,114,97,98,111,118, +101,32,116,104,101,108,105,110,107,101,100,32,116,111,112,104,101,110,111,109, +101,110,97,112,101,114,105,111,100,32,111,102,116,111,111,108,116,105,112,34,62, +115,117,98,115,116,97,110,99,101,97,117,116,111,109,97,116,105,99,97,115,112,101 +,99,116,32,111,102,65,109,111,110,103,32,116,104,101,99,111,110,110,101,99,116, +101,100,101,115,116,105,109,97,116,101,115,65,105,114,32,70,111,114,99,101,115, +121,115,116,101,109,32,111,102,111,98,106,101,99,116,105,118,101,105,109,109,101 +,100,105,97,116,101,109,97,107,105,110,103,32,105,116,112,97,105,110,116,105,110 +,103,115,99,111,110,113,117,101,114,101,100,97,114,101,32,115,116,105,108,108, +112,114,111,99,101,100,117,114,101,103,114,111,119,116,104,32,111,102,104,101,97 +,100,101,100,32,98,121,69,117,114,111,112,101,97,110,32,100,105,118,105,115,105, +111,110,115,109,111,108,101,99,117,108,101,115,102,114,97,110,99,104,105,115,101 +,105,110,116,101,110,116,105,111,110,97,116,116,114,97,99,116,101,100,99,104,105 +,108,100,104,111,111,100,97,108,115,111,32,117,115,101,100,100,101,100,105,99,97 +,116,101,100,115,105,110,103,97,112,111,114,101,100,101,103,114,101,101,32,111, +102,102,97,116,104,101,114,32,111,102,99,111,110,102,108,105,99,116,115,60,47,97 +,62,60,47,112,62,10,99,97,109,101,32,102,114,111,109,119,101,114,101,32,117,115, +101,100,110,111,116,101,32,116,104,97,116,114,101,99,101,105,118,105,110,103,69, +120,101,99,117,116,105,118,101,101,118,101,110,32,109,111,114,101,97,99,99,101, +115,115,32,116,111,99,111,109,109,97,110,100,101,114,80,111,108,105,116,105,99, +97,108,109,117,115,105,99,105,97,110,115,100,101,108,105,99,105,111,117,115,112, +114,105,115,111,110,101,114,115,97,100,118,101,110,116,32,111,102,85,84,70,45,56 +,34,32,47,62,60,33,91,67,68,65,84,65,91,34,62,67,111,110,116,97,99,116,83,111, +117,116,104,101,114,110,32,98,103,99,111,108,111,114,61,34,115,101,114,105,101, +115,32,111,102,46,32,73,116,32,119,97,115,32,105,110,32,69,117,114,111,112,101, +112,101,114,109,105,116,116,101,100,118,97,108,105,100,97,116,101,46,97,112,112, +101,97,114,105,110,103,111,102,102,105,99,105,97,108,115,115,101,114,105,111,117 +,115,108,121,45,108,97,110,103,117,97,103,101,105,110,105,116,105,97,116,101,100 +,101,120,116,101,110,100,105,110,103,108,111,110,103,45,116,101,114,109,105,110, +102,108,97,116,105,111,110,115,117,99,104,32,116,104,97,116,103,101,116,67,111, +111,107,105,101,109,97,114,107,101,100,32,98,121,60,47,98,117,116,116,111,110,62 +,105,109,112,108,101,109,101,110,116,98,117,116,32,105,116,32,105,115,105,110,99 +,114,101,97,115,101,115,100,111,119,110,32,116,104,101,32,114,101,113,117,105, +114,105,110,103,100,101,112,101,110,100,101,110,116,45,45,62,10,60,33,45,45,32, +105,110,116,101,114,118,105,101,119,87,105,116,104,32,116,104,101,32,99,111,112, +105,101,115,32,111,102,99,111,110,115,101,110,115,117,115,119,97,115,32,98,117, +105,108,116,86,101,110,101,122,117,101,108,97,40,102,111,114,109,101,114,108,121 +,116,104,101,32,115,116,97,116,101,112,101,114,115,111,110,110,101,108,115,116, +114,97,116,101,103,105,99,102,97,118,111,117,114,32,111,102,105,110,118,101,110, +116,105,111,110,87,105,107,105,112,101,100,105,97,99,111,110,116,105,110,101,110 +,116,118,105,114,116,117,97,108,108,121,119,104,105,99,104,32,119,97,115,112,114 +,105,110,99,105,112,108,101,67,111,109,112,108,101,116,101,32,105,100,101,110, +116,105,99,97,108,115,104,111,119,32,116,104,97,116,112,114,105,109,105,116,105, +118,101,97,119,97,121,32,102,114,111,109,109,111,108,101,99,117,108,97,114,112, +114,101,99,105,115,101,108,121,100,105,115,115,111,108,118,101,100,85,110,100, +101,114,32,116,104,101,118,101,114,115,105,111,110,61,34,62,38,110,98,115,112,59 +,60,47,73,116,32,105,115,32,116,104,101,32,84,104,105,115,32,105,115,32,119,105, +108,108,32,104,97,118,101,111,114,103,97,110,105,115,109,115,115,111,109,101,32, +116,105,109,101,70,114,105,101,100,114,105,99,104,119,97,115,32,102,105,114,115, +116,116,104,101,32,111,110,108,121,32,102,97,99,116,32,116,104,97,116,102,111, +114,109,32,105,100,61,34,112,114,101,99,101,100,105,110,103,84,101,99,104,110, +105,99,97,108,112,104,121,115,105,99,105,115,116,111,99,99,117,114,115,32,105, +110,110,97,118,105,103,97,116,111,114,115,101,99,116,105,111,110,34,62,115,112, +97,110,32,105,100,61,34,115,111,117,103,104,116,32,116,111,98,101,108,111,119,32 +,116,104,101,115,117,114,118,105,118,105,110,103,125,60,47,115,116,121,108,101, +62,104,105,115,32,100,101,97,116,104,97,115,32,105,110,32,116,104,101,99,97,117, +115,101,100,32,98,121,112,97,114,116,105,97,108,108,121,101,120,105,115,116,105, +110,103,32,117,115,105,110,103,32,116,104,101,119,97,115,32,103,105,118,101,110, +97,32,108,105,115,116,32,111,102,108,101,118,101,108,115,32,111,102,110,111,116, +105,111,110,32,111,102,79,102,102,105,99,105,97,108,32,100,105,115,109,105,115, +115,101,100,115,99,105,101,110,116,105,115,116,114,101,115,101,109,98,108,101, +115,100,117,112,108,105,99,97,116,101,101,120,112,108,111,115,105,118,101,114, +101,99,111,118,101,114,101,100,97,108,108,32,111,116,104,101,114,103,97,108,108, +101,114,105,101,115,123,112,97,100,100,105,110,103,58,112,101,111,112,108,101,32 +,111,102,114,101,103,105,111,110,32,111,102,97,100,100,114,101,115,115,101,115, +97,115,115,111,99,105,97,116,101,105,109,103,32,97,108,116,61,34,105,110,32,109, +111,100,101,114,110,115,104,111,117,108,100,32,98,101,109,101,116,104,111,100,32 +,111,102,114,101,112,111,114,116,105,110,103,116,105,109,101,115,116,97,109,112, +110,101,101,100,101,100,32,116,111,116,104,101,32,71,114,101,97,116,114,101,103, +97,114,100,105,110,103,115,101,101,109,101,100,32,116,111,118,105,101,119,101, +100,32,97,115,105,109,112,97,99,116,32,111,110,105,100,101,97,32,116,104,97,116, +116,104,101,32,87,111,114,108,100,104,101,105,103,104,116,32,111,102,101,120,112 +,97,110,100,105,110,103,84,104,101,115,101,32,97,114,101,99,117,114,114,101,110, +116,34,62,99,97,114,101,102,117,108,108,121,109,97,105,110,116,97,105,110,115,99 +,104,97,114,103,101,32,111,102,67,108,97,115,115,105,99,97,108,97,100,100,114, +101,115,115,101,100,112,114,101,100,105,99,116,101,100,111,119,110,101,114,115, +104,105,112,60,100,105,118,32,105,100,61,34,114,105,103,104,116,34,62,13,10,114, +101,115,105,100,101,110,99,101,108,101,97,118,101,32,116,104,101,99,111,110,116, +101,110,116,34,62,97,114,101,32,111,102,116,101,110,32,32,125,41,40,41,59,13,10, +112,114,111,98,97,98,108,121,32,80,114,111,102,101,115,115,111,114,45,98,117,116 +,116,111,110,34,32,114,101,115,112,111,110,100,101,100,115,97,121,115,32,116,104 +,97,116,104,97,100,32,116,111,32,98,101,112,108,97,99,101,100,32,105,110,72,117, +110,103,97,114,105,97,110,115,116,97,116,117,115,32,111,102,115,101,114,118,101, +115,32,97,115,85,110,105,118,101,114,115,97,108,101,120,101,99,117,116,105,111, +110,97,103,103,114,101,103,97,116,101,102,111,114,32,119,104,105,99,104,105,110, +102,101,99,116,105,111,110,97,103,114,101,101,100,32,116,111,104,111,119,101,118 +,101,114,44,32,112,111,112,117,108,97,114,34,62,112,108,97,99,101,100,32,111,110 +,99,111,110,115,116,114,117,99,116,101,108,101,99,116,111,114,97,108,115,121,109 +,98,111,108,32,111,102,105,110,99,108,117,100,105,110,103,114,101,116,117,114, +110,32,116,111,97,114,99,104,105,116,101,99,116,67,104,114,105,115,116,105,97, +110,112,114,101,118,105,111,117,115,32,108,105,118,105,110,103,32,105,110,101,97 +,115,105,101,114,32,116,111,112,114,111,102,101,115,115,111,114,10,38,108,116,59 +,33,45,45,32,101,102,102,101,99,116,32,111,102,97,110,97,108,121,116,105,99,115, +119,97,115,32,116,97,107,101,110,119,104,101,114,101,32,116,104,101,116,111,111, +107,32,111,118,101,114,98,101,108,105,101,102,32,105,110,65,102,114,105,107,97, +97,110,115,97,115,32,102,97,114,32,97,115,112,114,101,118,101,110,116,101,100, +119,111,114,107,32,119,105,116,104,97,32,115,112,101,99,105,97,108,60,102,105, +101,108,100,115,101,116,67,104,114,105,115,116,109,97,115,82,101,116,114,105,101 +,118,101,100,10,10,73,110,32,116,104,101,32,98,97,99,107,32,105,110,116,111,110, +111,114,116,104,101,97,115,116,109,97,103,97,122,105,110,101,115,62,60,115,116, +114,111,110,103,62,99,111,109,109,105,116,116,101,101,103,111,118,101,114,110, +105,110,103,103,114,111,117,112,115,32,111,102,115,116,111,114,101,100,32,105, +110,101,115,116,97,98,108,105,115,104,97,32,103,101,110,101,114,97,108,105,116, +115,32,102,105,114,115,116,116,104,101,105,114,32,111,119,110,112,111,112,117, +108,97,116,101,100,97,110,32,111,98,106,101,99,116,67,97,114,105,98,98,101,97, +110,97,108,108,111,119,32,116,104,101,100,105,115,116,114,105,99,116,115,119,105 +,115,99,111,110,115,105,110,108,111,99,97,116,105,111,110,46,59,32,119,105,100, +116,104,58,32,105,110,104,97,98,105,116,101,100,83,111,99,105,97,108,105,115,116 +,74,97,110,117,97,114,121,32,49,60,47,102,111,111,116,101,114,62,115,105,109,105 +,108,97,114,108,121,99,104,111,105,99,101,32,111,102,116,104,101,32,115,97,109, +101,32,115,112,101,99,105,102,105,99,32,98,117,115,105,110,101,115,115,32,84,104 +,101,32,102,105,114,115,116,46,108,101,110,103,116,104,59,32,100,101,115,105,114 +,101,32,116,111,100,101,97,108,32,119,105,116,104,115,105,110,99,101,32,116,104, +101,117,115,101,114,65,103,101,110,116,99,111,110,99,101,105,118,101,100,105,110 +,100,101,120,46,112,104,112,97,115,32,38,113,117,111,116,59,101,110,103,97,103, +101,32,105,110,114,101,99,101,110,116,108,121,44,102,101,119,32,121,101,97,114, +115,119,101,114,101,32,97,108,115,111,10,60,104,101,97,100,62,10,60,101,100,105, +116,101,100,32,98,121,97,114,101,32,107,110,111,119,110,99,105,116,105,101,115, +32,105,110,97,99,99,101,115,115,107,101,121,99,111,110,100,101,109,110,101,100, +97,108,115,111,32,104,97,118,101,115,101,114,118,105,99,101,115,44,102,97,109, +105,108,121,32,111,102,83,99,104,111,111,108,32,111,102,99,111,110,118,101,114, +116,101,100,110,97,116,117,114,101,32,111,102,32,108,97,110,103,117,97,103,101, +109,105,110,105,115,116,101,114,115,60,47,111,98,106,101,99,116,62,116,104,101, +114,101,32,105,115,32,97,32,112,111,112,117,108,97,114,115,101,113,117,101,110, +99,101,115,97,100,118,111,99,97,116,101,100,84,104,101,121,32,119,101,114,101,97 +,110,121,32,111,116,104,101,114,108,111,99,97,116,105,111,110,61,101,110,116,101 +,114,32,116,104,101,109,117,99,104,32,109,111,114,101,114,101,102,108,101,99,116 +,101,100,119,97,115,32,110,97,109,101,100,111,114,105,103,105,110,97,108,32,97, +32,116,121,112,105,99,97,108,119,104,101,110,32,116,104,101,121,101,110,103,105, +110,101,101,114,115,99,111,117,108,100,32,110,111,116,114,101,115,105,100,101, +110,116,115,119,101,100,110,101,115,100,97,121,116,104,101,32,116,104,105,114, +100,32,112,114,111,100,117,99,116,115,74,97,110,117,97,114,121,32,50,119,104,97, +116,32,116,104,101,121,97,32,99,101,114,116,97,105,110,114,101,97,99,116,105,111 +,110,115,112,114,111,99,101,115,115,111,114,97,102,116,101,114,32,104,105,115, +116,104,101,32,108,97,115,116,32,99,111,110,116,97,105,110,101,100,34,62,60,47, +100,105,118,62,10,60,47,97,62,60,47,116,100,62,100,101,112,101,110,100,32,111, +110,115,101,97,114,99,104,34,62,10,112,105,101,99,101,115,32,111,102,99,111,109, +112,101,116,105,110,103,82,101,102,101,114,101,110,99,101,116,101,110,110,101, +115,115,101,101,119,104,105,99,104,32,104,97,115,32,118,101,114,115,105,111,110, +61,60,47,115,112,97,110,62,32,60,60,47,104,101,97,100,101,114,62,103,105,118,101 +,115,32,116,104,101,104,105,115,116,111,114,105,97,110,118,97,108,117,101,61,34, +34,62,112,97,100,100,105,110,103,58,48,118,105,101,119,32,116,104,97,116,116,111 +,103,101,116,104,101,114,44,116,104,101,32,109,111,115,116,32,119,97,115,32,102, +111,117,110,100,115,117,98,115,101,116,32,111,102,97,116,116,97,99,107,32,111, +110,99,104,105,108,100,114,101,110,44,112,111,105,110,116,115,32,111,102,112,101 +,114,115,111,110,97,108,32,112,111,115,105,116,105,111,110,58,97,108,108,101,103 +,101,100,108,121,67,108,101,118,101,108,97,110,100,119,97,115,32,108,97,116,101, +114,97,110,100,32,97,102,116,101,114,97,114,101,32,103,105,118,101,110,119,97, +115,32,115,116,105,108,108,115,99,114,111,108,108,105,110,103,100,101,115,105, +103,110,32,111,102,109,97,107,101,115,32,116,104,101,109,117,99,104,32,108,101, +115,115,65,109,101,114,105,99,97,110,115,46,10,10,65,102,116,101,114,32,44,32,98 +,117,116,32,116,104,101,77,117,115,101,117,109,32,111,102,108,111,117,105,115, +105,97,110,97,40,102,114,111,109,32,116,104,101,109,105,110,110,101,115,111,116, +97,112,97,114,116,105,99,108,101,115,97,32,112,114,111,99,101,115,115,68,111,109 +,105,110,105,99,97,110,118,111,108,117,109,101,32,111,102,114,101,116,117,114, +110,105,110,103,100,101,102,101,110,115,105,118,101,48,48,112,120,124,114,105, +103,104,109,97,100,101,32,102,114,111,109,109,111,117,115,101,111,118,101,114,34 +,32,115,116,121,108,101,61,34,115,116,97,116,101,115,32,111,102,40,119,104,105, +99,104,32,105,115,99,111,110,116,105,110,117,101,115,70,114,97,110,99,105,115,99 +,111,98,117,105,108,100,105,110,103,32,119,105,116,104,111,117,116,32,97,119,105 +,116,104,32,115,111,109,101,119,104,111,32,119,111,117,108,100,97,32,102,111,114 +,109,32,111,102,97,32,112,97,114,116,32,111,102,98,101,102,111,114,101,32,105, +116,107,110,111,119,110,32,97,115,32,32,83,101,114,118,105,99,101,115,108,111,99 +,97,116,105,111,110,32,97,110,100,32,111,102,116,101,110,109,101,97,115,117,114, +105,110,103,97,110,100,32,105,116,32,105,115,112,97,112,101,114,98,97,99,107,118 +,97,108,117,101,115,32,111,102,13,10,60,116,105,116,108,101,62,61,32,119,105,110 +,100,111,119,46,100,101,116,101,114,109,105,110,101,101,114,38,113,117,111,116, +59,32,112,108,97,121,101,100,32,98,121,97,110,100,32,101,97,114,108,121,60,47,99 +,101,110,116,101,114,62,102,114,111,109,32,116,104,105,115,116,104,101,32,116, +104,114,101,101,112,111,119,101,114,32,97,110,100,111,102,32,38,113,117,111,116, +59,105,110,110,101,114,72,84,77,76,60,97,32,104,114,101,102,61,34,121,58,105,110 +,108,105,110,101,59,67,104,117,114,99,104,32,111,102,116,104,101,32,101,118,101, +110,116,118,101,114,121,32,104,105,103,104,111,102,102,105,99,105,97,108,32,45, +104,101,105,103,104,116,58,32,99,111,110,116,101,110,116,61,34,47,99,103,105,45, +98,105,110,47,116,111,32,99,114,101,97,116,101,97,102,114,105,107,97,97,110,115, +101,115,112,101,114,97,110,116,111,102,114,97,110,195,167,97,105,115,108,97,116, +118,105,101,197,161,117,108,105,101,116,117,118,105,197,179,196,140,101,197,161, +116,105,110,97,196,141,101,197,161,116,105,110,97,224,185,132,224,184,151,224, +184,162,230,151,165,230,156,172,232,170,158,231,174,128,228,189,147,229,173,151, +231,185,129,233,171,148,229,173,151,237,149,156,234,181,173,236,150,180,228,184, +186,228,187,128,228,185,136,232,174,161,231,174,151,230,156,186,231,172,148,232, +174,176,230,156,172,232,168,142,232,171,150,229,141,128,230,156,141,229,138,161, +229,153,168,228,186,146,232,129,148,231,189,145,230,136,191,229,156,176,228,186, +167,228,191,177,228,185,144,233,131,168,229,135,186,231,137,136,231,164,190,230, +142,146,232,161,140,230,166,156,233,131,168,232,144,189,230,160,188,232,191,155, +228,184,128,230,173,165,230,148,175,228,187,152,229,174,157,233,170,140,232,175, +129,231,160,129,229,167,148,229,145,152,228,188,154,230,149,176,230,141,174,229, +186,147,230,182,136,232,180,185,232,128,133,229,138,158,229,133,172,229,174,164, +232,174,168,232,174,186,229,140,186,230,183,177,229,156,179,229,184,130,230,146, +173,230,148,190,229,153,168,229,140,151,228,186,172,229,184,130,229,164,167,229, +173,166,231,148,159,232,182,138,230,157,165,232,182,138,231,174,161,231,144,134, +229,145,152,228,191,161,230,129,175,231,189,145,115,101,114,118,105,99,105,111, +115,97,114,116,195,173,99,117,108,111,97,114,103,101,110,116,105,110,97,98,97, +114,99,101,108,111,110,97,99,117,97,108,113,117,105,101,114,112,117,98,108,105, +99,97,100,111,112,114,111,100,117,99,116,111,115,112,111,108,195,173,116,105,99, +97,114,101,115,112,117,101,115,116,97,119,105,107,105,112,101,100,105,97,115,105 +,103,117,105,101,110,116,101,98,195,186,115,113,117,101,100,97,99,111,109,117, +110,105,100,97,100,115,101,103,117,114,105,100,97,100,112,114,105,110,99,105,112 +,97,108,112,114,101,103,117,110,116,97,115,99,111,110,116,101,110,105,100,111, +114,101,115,112,111,110,100,101,114,118,101,110,101,122,117,101,108,97,112,114, +111,98,108,101,109,97,115,100,105,99,105,101,109,98,114,101,114,101,108,97,99, +105,195,179,110,110,111,118,105,101,109,98,114,101,115,105,109,105,108,97,114, +101,115,112,114,111,121,101,99,116,111,115,112,114,111,103,114,97,109,97,115,105 +,110,115,116,105,116,117,116,111,97,99,116,105,118,105,100,97,100,101,110,99,117 +,101,110,116,114,97,101,99,111,110,111,109,195,173,97,105,109,195,161,103,101, +110,101,115,99,111,110,116,97,99,116,97,114,100,101,115,99,97,114,103,97,114,110 +,101,99,101,115,97,114,105,111,97,116,101,110,99,105,195,179,110,116,101,108,195 +,169,102,111,110,111,99,111,109,105,115,105,195,179,110,99,97,110,99,105,111,110 +,101,115,99,97,112,97,99,105,100,97,100,101,110,99,111,110,116,114,97,114,97,110 +,195,161,108,105,115,105,115,102,97,118,111,114,105,116,111,115,116,195,169,114, +109,105,110,111,115,112,114,111,118,105,110,99,105,97,101,116,105,113,117,101, +116,97,115,101,108,101,109,101,110,116,111,115,102,117,110,99,105,111,110,101, +115,114,101,115,117,108,116,97,100,111,99,97,114,195,161,99,116,101,114,112,114, +111,112,105,101,100,97,100,112,114,105,110,99,105,112,105,111,110,101,99,101,115 +,105,100,97,100,109,117,110,105,99,105,112,97,108,99,114,101,97,99,105,195,179, +110,100,101,115,99,97,114,103,97,115,112,114,101,115,101,110,99,105,97,99,111, +109,101,114,99,105,97,108,111,112,105,110,105,111,110,101,115,101,106,101,114,99 +,105,99,105,111,101,100,105,116,111,114,105,97,108,115,97,108,97,109,97,110,99, +97,103,111,110,122,195,161,108,101,122,100,111,99,117,109,101,110,116,111,112, +101,108,195,173,99,117,108,97,114,101,99,105,101,110,116,101,115,103,101,110,101 +,114,97,108,101,115,116,97,114,114,97,103,111,110,97,112,114,195,161,99,116,105, +99,97,110,111,118,101,100,97,100,101,115,112,114,111,112,117,101,115,116,97,112, +97,99,105,101,110,116,101,115,116,195,169,99,110,105,99,97,115,111,98,106,101, +116,105,118,111,115,99,111,110,116,97,99,116,111,115,224,164,174,224,165,135,224 +,164,130,224,164,178,224,164,191,224,164,143,224,164,185,224,165,136,224,164,130 +,224,164,151,224,164,175,224,164,190,224,164,184,224,164,190,224,164,165,224,164 +,143,224,164,181,224,164,130,224,164,176,224,164,185,224,165,135,224,164,149,224 +,165,139,224,164,136,224,164,149,224,165,129,224,164,155,224,164,176,224,164,185 +,224,164,190,224,164,172,224,164,190,224,164,166,224,164,149,224,164,185,224,164 +,190,224,164,184,224,164,173,224,165,128,224,164,185,224,165,129,224,164,143,224 +,164,176,224,164,185,224,165,128,224,164,174,224,165,136,224,164,130,224,164,166 +,224,164,191,224,164,168,224,164,172,224,164,190,224,164,164,100,105,112,108,111 +,100,111,99,115,224,164,184,224,164,174,224,164,175,224,164,176,224,165,130,224, +164,170,224,164,168,224,164,190,224,164,174,224,164,170,224,164,164,224,164,190, +224,164,171,224,164,191,224,164,176,224,164,148,224,164,184,224,164,164,224,164, +164,224,164,176,224,164,185,224,164,178,224,165,139,224,164,151,224,164,185,224, +165,129,224,164,134,224,164,172,224,164,190,224,164,176,224,164,166,224,165,135, +224,164,182,224,164,185,224,165,129,224,164,136,224,164,150,224,165,135,224,164, +178,224,164,175,224,164,166,224,164,191,224,164,149,224,164,190,224,164,174,224, +164,181,224,165,135,224,164,172,224,164,164,224,165,128,224,164,168,224,164,172, +224,165,128,224,164,154,224,164,174,224,165,140,224,164,164,224,164,184,224,164, +190,224,164,178,224,164,178,224,165,135,224,164,150,224,164,156,224,165,137,224, +164,172,224,164,174,224,164,166,224,164,166,224,164,164,224,164,165,224,164,190, +224,164,168,224,164,185,224,165,128,224,164,182,224,164,185,224,164,176,224,164, +133,224,164,178,224,164,151,224,164,149,224,164,173,224,165,128,224,164,168,224, +164,151,224,164,176,224,164,170,224,164,190,224,164,184,224,164,176,224,164,190, +224,164,164,224,164,149,224,164,191,224,164,143,224,164,137,224,164,184,224,165, +135,224,164,151,224,164,175,224,165,128,224,164,185,224,165,130,224,164,129,224, +164,134,224,164,151,224,165,135,224,164,159,224,165,128,224,164,174,224,164,150, +224,165,139,224,164,156,224,164,149,224,164,190,224,164,176,224,164,133,224,164, +173,224,165,128,224,164,151,224,164,175,224,165,135,224,164,164,224,165,129,224, +164,174,224,164,181,224,165,139,224,164,159,224,164,166,224,165,135,224,164,130, +224,164,133,224,164,151,224,164,176,224,164,144,224,164,184,224,165,135,224,164, +174,224,165,135,224,164,178,224,164,178,224,164,151,224,164,190,224,164,185,224, +164,190,224,164,178,224,164,138,224,164,170,224,164,176,224,164,154,224,164,190, +224,164,176,224,164,144,224,164,184,224,164,190,224,164,166,224,165,135,224,164, +176,224,164,156,224,164,191,224,164,184,224,164,166,224,164,191,224,164,178,224, +164,172,224,164,130,224,164,166,224,164,172,224,164,168,224,164,190,224,164,185, +224,165,130,224,164,130,224,164,178,224,164,190,224,164,150,224,164,156,224,165, +128,224,164,164,224,164,172,224,164,159,224,164,168,224,164,174,224,164,191,224, +164,178,224,164,135,224,164,184,224,165,135,224,164,134,224,164,168,224,165,135, +224,164,168,224,164,175,224,164,190,224,164,149,224,165,129,224,164,178,224,164, +178,224,165,137,224,164,151,224,164,173,224,164,190,224,164,151,224,164,176,224, +165,135,224,164,178,224,164,156,224,164,151,224,164,185,224,164,176,224,164,190, +224,164,174,224,164,178,224,164,151,224,165,135,224,164,170,224,165,135,224,164, +156,224,164,185,224,164,190,224,164,165,224,164,135,224,164,184,224,165,128,224, +164,184,224,164,185,224,165,128,224,164,149,224,164,178,224,164,190,224,164,160, +224,165,128,224,164,149,224,164,185,224,164,190,224,164,129,224,164,166,224,165, +130,224,164,176,224,164,164,224,164,185,224,164,164,224,164,184,224,164,190,224, +164,164,224,164,175,224,164,190,224,164,166,224,164,134,224,164,175,224,164,190, +224,164,170,224,164,190,224,164,149,224,164,149,224,165,140,224,164,168,224,164, +182,224,164,190,224,164,174,224,164,166,224,165,135,224,164,150,224,164,175,224, +164,185,224,165,128,224,164,176,224,164,190,224,164,175,224,164,150,224,165,129, +224,164,166,224,164,178,224,164,151,224,165,128,99,97,116,101,103,111,114,105, +101,115,101,120,112,101,114,105,101,110,99,101,60,47,116,105,116,108,101,62,13, +10,67,111,112,121,114,105,103,104,116,32,106,97,118,97,115,99,114,105,112,116,99 +,111,110,100,105,116,105,111,110,115,101,118,101,114,121,116,104,105,110,103,60, +112,32,99,108,97,115,115,61,34,116,101,99,104,110,111,108,111,103,121,98,97,99, +107,103,114,111,117,110,100,60,97,32,99,108,97,115,115,61,34,109,97,110,97,103, +101,109,101,110,116,38,99,111,112,121,59,32,50,48,49,106,97,118,97,83,99,114,105 +,112,116,99,104,97,114,97,99,116,101,114,115,98,114,101,97,100,99,114,117,109,98 +,116,104,101,109,115,101,108,118,101,115,104,111,114,105,122,111,110,116,97,108, +103,111,118,101,114,110,109,101,110,116,67,97,108,105,102,111,114,110,105,97,97, +99,116,105,118,105,116,105,101,115,100,105,115,99,111,118,101,114,101,100,78,97, +118,105,103,97,116,105,111,110,116,114,97,110,115,105,116,105,111,110,99,111,110 +,110,101,99,116,105,111,110,110,97,118,105,103,97,116,105,111,110,97,112,112,101 +,97,114,97,110,99,101,60,47,116,105,116,108,101,62,60,109,99,104,101,99,107,98, +111,120,34,32,116,101,99,104,110,105,113,117,101,115,112,114,111,116,101,99,116, +105,111,110,97,112,112,97,114,101,110,116,108,121,97,115,32,119,101,108,108,32, +97,115,117,110,116,39,44,32,39,85,65,45,114,101,115,111,108,117,116,105,111,110, +111,112,101,114,97,116,105,111,110,115,116,101,108,101,118,105,115,105,111,110, +116,114,97,110,115,108,97,116,101,100,87,97,115,104,105,110,103,116,111,110,110, +97,118,105,103,97,116,111,114,46,32,61,32,119,105,110,100,111,119,46,105,109,112 +,114,101,115,115,105,111,110,38,108,116,59,98,114,38,103,116,59,108,105,116,101, +114,97,116,117,114,101,112,111,112,117,108,97,116,105,111,110,98,103,99,111,108, +111,114,61,34,35,101,115,112,101,99,105,97,108,108,121,32,99,111,110,116,101,110 +,116,61,34,112,114,111,100,117,99,116,105,111,110,110,101,119,115,108,101,116, +116,101,114,112,114,111,112,101,114,116,105,101,115,100,101,102,105,110,105,116, +105,111,110,108,101,97,100,101,114,115,104,105,112,84,101,99,104,110,111,108,111 +,103,121,80,97,114,108,105,97,109,101,110,116,99,111,109,112,97,114,105,115,111, +110,117,108,32,99,108,97,115,115,61,34,46,105,110,100,101,120,79,102,40,34,99, +111,110,99,108,117,115,105,111,110,100,105,115,99,117,115,115,105,111,110,99,111 +,109,112,111,110,101,110,116,115,98,105,111,108,111,103,105,99,97,108,82,101,118 +,111,108,117,116,105,111,110,95,99,111,110,116,97,105,110,101,114,117,110,100, +101,114,115,116,111,111,100,110,111,115,99,114,105,112,116,62,60,112,101,114,109 +,105,115,115,105,111,110,101,97,99,104,32,111,116,104,101,114,97,116,109,111,115 +,112,104,101,114,101,32,111,110,102,111,99,117,115,61,34,60,102,111,114,109,32, +105,100,61,34,112,114,111,99,101,115,115,105,110,103,116,104,105,115,46,118,97, +108,117,101,103,101,110,101,114,97,116,105,111,110,67,111,110,102,101,114,101, +110,99,101,115,117,98,115,101,113,117,101,110,116,119,101,108,108,45,107,110,111 +,119,110,118,97,114,105,97,116,105,111,110,115,114,101,112,117,116,97,116,105, +111,110,112,104,101,110,111,109,101,110,111,110,100,105,115,99,105,112,108,105, +110,101,108,111,103,111,46,112,110,103,34,32,40,100,111,99,117,109,101,110,116, +44,98,111,117,110,100,97,114,105,101,115,101,120,112,114,101,115,115,105,111,110 +,115,101,116,116,108,101,109,101,110,116,66,97,99,107,103,114,111,117,110,100, +111,117,116,32,111,102,32,116,104,101,101,110,116,101,114,112,114,105,115,101,40 +,34,104,116,116,112,115,58,34,32,117,110,101,115,99,97,112,101,40,34,112,97,115, +115,119,111,114,100,34,32,100,101,109,111,99,114,97,116,105,99,60,97,32,104,114, +101,102,61,34,47,119,114,97,112,112,101,114,34,62,10,109,101,109,98,101,114,115, +104,105,112,108,105,110,103,117,105,115,116,105,99,112,120,59,112,97,100,100,105 +,110,103,112,104,105,108,111,115,111,112,104,121,97,115,115,105,115,116,97,110, +99,101,117,110,105,118,101,114,115,105,116,121,102,97,99,105,108,105,116,105,101 +,115,114,101,99,111,103,110,105,122,101,100,112,114,101,102,101,114,101,110,99, +101,105,102,32,40,116,121,112,101,111,102,109,97,105,110,116,97,105,110,101,100, +118,111,99,97,98,117,108,97,114,121,104,121,112,111,116,104,101,115,105,115,46, +115,117,98,109,105,116,40,41,59,38,97,109,112,59,110,98,115,112,59,97,110,110, +111,116,97,116,105,111,110,98,101,104,105,110,100,32,116,104,101,70,111,117,110, +100,97,116,105,111,110,112,117,98,108,105,115,104,101,114,34,97,115,115,117,109, +112,116,105,111,110,105,110,116,114,111,100,117,99,101,100,99,111,114,114,117, +112,116,105,111,110,115,99,105,101,110,116,105,115,116,115,101,120,112,108,105, +99,105,116,108,121,105,110,115,116,101,97,100,32,111,102,100,105,109,101,110,115 +,105,111,110,115,32,111,110,67,108,105,99,107,61,34,99,111,110,115,105,100,101, +114,101,100,100,101,112,97,114,116,109,101,110,116,111,99,99,117,112,97,116,105, +111,110,115,111,111,110,32,97,102,116,101,114,105,110,118,101,115,116,109,101, +110,116,112,114,111,110,111,117,110,99,101,100,105,100,101,110,116,105,102,105, +101,100,101,120,112,101,114,105,109,101,110,116,77,97,110,97,103,101,109,101,110 +,116,103,101,111,103,114,97,112,104,105,99,34,32,104,101,105,103,104,116,61,34, +108,105,110,107,32,114,101,108,61,34,46,114,101,112,108,97,99,101,40,47,100,101, +112,114,101,115,115,105,111,110,99,111,110,102,101,114,101,110,99,101,112,117, +110,105,115,104,109,101,110,116,101,108,105,109,105,110,97,116,101,100,114,101, +115,105,115,116,97,110,99,101,97,100,97,112,116,97,116,105,111,110,111,112,112, +111,115,105,116,105,111,110,119,101,108,108,32,107,110,111,119,110,115,117,112, +112,108,101,109,101,110,116,100,101,116,101,114,109,105,110,101,100,104,49,32,99 +,108,97,115,115,61,34,48,112,120,59,109,97,114,103,105,110,109,101,99,104,97,110 +,105,99,97,108,115,116,97,116,105,115,116,105,99,115,99,101,108,101,98,114,97, +116,101,100,71,111,118,101,114,110,109,101,110,116,10,10,68,117,114,105,110,103, +32,116,100,101,118,101,108,111,112,101,114,115,97,114,116,105,102,105,99,105,97, +108,101,113,117,105,118,97,108,101,110,116,111,114,105,103,105,110,97,116,101, +100,67,111,109,109,105,115,115,105,111,110,97,116,116,97,99,104,109,101,110,116, +60,115,112,97,110,32,105,100,61,34,116,104,101,114,101,32,119,101,114,101,78,101 +,100,101,114,108,97,110,100,115,98,101,121,111,110,100,32,116,104,101,114,101, +103,105,115,116,101,114,101,100,106,111,117,114,110,97,108,105,115,116,102,114, +101,113,117,101,110,116,108,121,97,108,108,32,111,102,32,116,104,101,108,97,110, +103,61,34,101,110,34,32,60,47,115,116,121,108,101,62,13,10,97,98,115,111,108,117 +,116,101,59,32,115,117,112,112,111,114,116,105,110,103,101,120,116,114,101,109, +101,108,121,32,109,97,105,110,115,116,114,101,97,109,60,47,115,116,114,111,110, +103,62,32,112,111,112,117,108,97,114,105,116,121,101,109,112,108,111,121,109,101 +,110,116,60,47,116,97,98,108,101,62,13,10,32,99,111,108,115,112,97,110,61,34,60, +47,102,111,114,109,62,10,32,32,99,111,110,118,101,114,115,105,111,110,97,98,111, +117,116,32,116,104,101,32,60,47,112,62,60,47,100,105,118,62,105,110,116,101,103, +114,97,116,101,100,34,32,108,97,110,103,61,34,101,110,80,111,114,116,117,103,117 +,101,115,101,115,117,98,115,116,105,116,117,116,101,105,110,100,105,118,105,100, +117,97,108,105,109,112,111,115,115,105,98,108,101,109,117,108,116,105,109,101, +100,105,97,97,108,109,111,115,116,32,97,108,108,112,120,32,115,111,108,105,100, +32,35,97,112,97,114,116,32,102,114,111,109,115,117,98,106,101,99,116,32,116,111, +105,110,32,69,110,103,108,105,115,104,99,114,105,116,105,99,105,122,101,100,101, +120,99,101,112,116,32,102,111,114,103,117,105,100,101,108,105,110,101,115,111, +114,105,103,105,110,97,108,108,121,114,101,109,97,114,107,97,98,108,101,116,104, +101,32,115,101,99,111,110,100,104,50,32,99,108,97,115,115,61,34,60,97,32,116,105 +,116,108,101,61,34,40,105,110,99,108,117,100,105,110,103,112,97,114,97,109,101, +116,101,114,115,112,114,111,104,105,98,105,116,101,100,61,32,34,104,116,116,112, +58,47,47,100,105,99,116,105,111,110,97,114,121,112,101,114,99,101,112,116,105, +111,110,114,101,118,111,108,117,116,105,111,110,102,111,117,110,100,97,116,105, +111,110,112,120,59,104,101,105,103,104,116,58,115,117,99,99,101,115,115,102,117, +108,115,117,112,112,111,114,116,101,114,115,109,105,108,108,101,110,110,105,117, +109,104,105,115,32,102,97,116,104,101,114,116,104,101,32,38,113,117,111,116,59, +110,111,45,114,101,112,101,97,116,59,99,111,109,109,101,114,99,105,97,108,105, +110,100,117,115,116,114,105,97,108,101,110,99,111,117,114,97,103,101,100,97,109, +111,117,110,116,32,111,102,32,117,110,111,102,102,105,99,105,97,108,101,102,102, +105,99,105,101,110,99,121,82,101,102,101,114,101,110,99,101,115,99,111,111,114, +100,105,110,97,116,101,100,105,115,99,108,97,105,109,101,114,101,120,112,101,100 +,105,116,105,111,110,100,101,118,101,108,111,112,105,110,103,99,97,108,99,117, +108,97,116,101,100,115,105,109,112,108,105,102,105,101,100,108,101,103,105,116, +105,109,97,116,101,115,117,98,115,116,114,105,110,103,40,48,34,32,99,108,97,115, +115,61,34,99,111,109,112,108,101,116,101,108,121,105,108,108,117,115,116,114,97, +116,101,102,105,118,101,32,121,101,97,114,115,105,110,115,116,114,117,109,101, +110,116,80,117,98,108,105,115,104,105,110,103,49,34,32,99,108,97,115,115,61,34, +112,115,121,99,104,111,108,111,103,121,99,111,110,102,105,100,101,110,99,101,110 +,117,109,98,101,114,32,111,102,32,97,98,115,101,110,99,101,32,111,102,102,111,99 +,117,115,101,100,32,111,110,106,111,105,110,101,100,32,116,104,101,115,116,114, +117,99,116,117,114,101,115,112,114,101,118,105,111,117,115,108,121,62,60,47,105, +102,114,97,109,101,62,111,110,99,101,32,97,103,97,105,110,98,117,116,32,114,97, +116,104,101,114,105,109,109,105,103,114,97,110,116,115,111,102,32,99,111,117,114 +,115,101,44,97,32,103,114,111,117,112,32,111,102,76,105,116,101,114,97,116,117, +114,101,85,110,108,105,107,101,32,116,104,101,60,47,97,62,38,110,98,115,112,59, +10,102,117,110,99,116,105,111,110,32,105,116,32,119,97,115,32,116,104,101,67,111 +,110,118,101,110,116,105,111,110,97,117,116,111,109,111,98,105,108,101,80,114, +111,116,101,115,116,97,110,116,97,103,103,114,101,115,115,105,118,101,97,102,116 +,101,114,32,116,104,101,32,83,105,109,105,108,97,114,108,121,44,34,32,47,62,60, +47,100,105,118,62,99,111,108,108,101,99,116,105,111,110,13,10,102,117,110,99,116 +,105,111,110,118,105,115,105,98,105,108,105,116,121,116,104,101,32,117,115,101, +32,111,102,118,111,108,117,110,116,101,101,114,115,97,116,116,114,97,99,116,105, +111,110,117,110,100,101,114,32,116,104,101,32,116,104,114,101,97,116,101,110,101 +,100,42,60,33,91,67,68,65,84,65,91,105,109,112,111,114,116,97,110,99,101,105,110 +,32,103,101,110,101,114,97,108,116,104,101,32,108,97,116,116,101,114,60,47,102, +111,114,109,62,10,60,47,46,105,110,100,101,120,79,102,40,39,105,32,61,32,48,59, +32,105,32,60,100,105,102,102,101,114,101,110,99,101,100,101,118,111,116,101,100, +32,116,111,116,114,97,100,105,116,105,111,110,115,115,101,97,114,99,104,32,102, +111,114,117,108,116,105,109,97,116,101,108,121,116,111,117,114,110,97,109,101, +110,116,97,116,116,114,105,98,117,116,101,115,115,111,45,99,97,108,108,101,100, +32,125,10,60,47,115,116,121,108,101,62,101,118,97,108,117,97,116,105,111,110,101 +,109,112,104,97,115,105,122,101,100,97,99,99,101,115,115,105,98,108,101,60,47, +115,101,99,116,105,111,110,62,115,117,99,99,101,115,115,105,111,110,97,108,111, +110,103,32,119,105,116,104,77,101,97,110,119,104,105,108,101,44,105,110,100,117, +115,116,114,105,101,115,60,47,97,62,60,98,114,32,47,62,104,97,115,32,98,101,99, +111,109,101,97,115,112,101,99,116,115,32,111,102,84,101,108,101,118,105,115,105, +111,110,115,117,102,102,105,99,105,101,110,116,98,97,115,107,101,116,98,97,108, +108,98,111,116,104,32,115,105,100,101,115,99,111,110,116,105,110,117,105,110,103 +,97,110,32,97,114,116,105,99,108,101,60,105,109,103,32,97,108,116,61,34,97,100, +118,101,110,116,117,114,101,115,104,105,115,32,109,111,116,104,101,114,109,97, +110,99,104,101,115,116,101,114,112,114,105,110,99,105,112,108,101,115,112,97,114 +,116,105,99,117,108,97,114,99,111,109,109,101,110,116,97,114,121,101,102,102,101 +,99,116,115,32,111,102,100,101,99,105,100,101,100,32,116,111,34,62,60,115,116, +114,111,110,103,62,112,117,98,108,105,115,104,101,114,115,74,111,117,114,110,97, +108,32,111,102,100,105,102,102,105,99,117,108,116,121,102,97,99,105,108,105,116, +97,116,101,97,99,99,101,112,116,97,98,108,101,115,116,121,108,101,46,99,115,115, +34,9,102,117,110,99,116,105,111,110,32,105,110,110,111,118,97,116,105,111,110,62 +,67,111,112,121,114,105,103,104,116,115,105,116,117,97,116,105,111,110,115,119, +111,117,108,100,32,104,97,118,101,98,117,115,105,110,101,115,115,101,115,68,105, +99,116,105,111,110,97,114,121,115,116,97,116,101,109,101,110,116,115,111,102,116 +,101,110,32,117,115,101,100,112,101,114,115,105,115,116,101,110,116,105,110,32, +74,97,110,117,97,114,121,99,111,109,112,114,105,115,105,110,103,60,47,116,105, +116,108,101,62,10,9,100,105,112,108,111,109,97,116,105,99,99,111,110,116,97,105, +110,105,110,103,112,101,114,102,111,114,109,105,110,103,101,120,116,101,110,115, +105,111,110,115,109,97,121,32,110,111,116,32,98,101,99,111,110,99,101,112,116,32 +,111,102,32,111,110,99,108,105,99,107,61,34,73,116,32,105,115,32,97,108,115,111, +102,105,110,97,110,99,105,97,108,32,109,97,107,105,110,103,32,116,104,101,76,117 +,120,101,109,98,111,117,114,103,97,100,100,105,116,105,111,110,97,108,97,114,101 +,32,99,97,108,108,101,100,101,110,103,97,103,101,100,32,105,110,34,115,99,114, +105,112,116,34,41,59,98,117,116,32,105,116,32,119,97,115,101,108,101,99,116,114, +111,110,105,99,111,110,115,117,98,109,105,116,61,34,10,60,33,45,45,32,69,110,100 +,32,101,108,101,99,116,114,105,99,97,108,111,102,102,105,99,105,97,108,108,121, +115,117,103,103,101,115,116,105,111,110,116,111,112,32,111,102,32,116,104,101, +117,110,108,105,107,101,32,116,104,101,65,117,115,116,114,97,108,105,97,110,79, +114,105,103,105,110,97,108,108,121,114,101,102,101,114,101,110,99,101,115,10,60, +47,104,101,97,100,62,13,10,114,101,99,111,103,110,105,115,101,100,105,110,105, +116,105,97,108,105,122,101,108,105,109,105,116,101,100,32,116,111,65,108,101,120 +,97,110,100,114,105,97,114,101,116,105,114,101,109,101,110,116,65,100,118,101, +110,116,117,114,101,115,102,111,117,114,32,121,101,97,114,115,10,10,38,108,116, +59,33,45,45,32,105,110,99,114,101,97,115,105,110,103,100,101,99,111,114,97,116, +105,111,110,104,51,32,99,108,97,115,115,61,34,111,114,105,103,105,110,115,32,111 +,102,111,98,108,105,103,97,116,105,111,110,114,101,103,117,108,97,116,105,111, +110,99,108,97,115,115,105,102,105,101,100,40,102,117,110,99,116,105,111,110,40, +97,100,118,97,110,116,97,103,101,115,98,101,105,110,103,32,116,104,101,32,104, +105,115,116,111,114,105,97,110,115,60,98,97,115,101,32,104,114,101,102,114,101, +112,101,97,116,101,100,108,121,119,105,108,108,105,110,103,32,116,111,99,111,109 +,112,97,114,97,98,108,101,100,101,115,105,103,110,97,116,101,100,110,111,109,105 +,110,97,116,105,111,110,102,117,110,99,116,105,111,110,97,108,105,110,115,105, +100,101,32,116,104,101,114,101,118,101,108,97,116,105,111,110,101,110,100,32,111 +,102,32,116,104,101,115,32,102,111,114,32,116,104,101,32,97,117,116,104,111,114, +105,122,101,100,114,101,102,117,115,101,100,32,116,111,116,97,107,101,32,112,108 +,97,99,101,97,117,116,111,110,111,109,111,117,115,99,111,109,112,114,111,109,105 +,115,101,112,111,108,105,116,105,99,97,108,32,114,101,115,116,97,117,114,97,110, +116,116,119,111,32,111,102,32,116,104,101,70,101,98,114,117,97,114,121,32,50,113 +,117,97,108,105,116,121,32,111,102,115,119,102,111,98,106,101,99,116,46,117,110, +100,101,114,115,116,97,110,100,110,101,97,114,108,121,32,97,108,108,119,114,105, +116,116,101,110,32,98,121,105,110,116,101,114,118,105,101,119,115,34,32,119,105, +100,116,104,61,34,49,119,105,116,104,100,114,97,119,97,108,102,108,111,97,116,58 +,108,101,102,116,105,115,32,117,115,117,97,108,108,121,99,97,110,100,105,100,97, +116,101,115,110,101,119,115,112,97,112,101,114,115,109,121,115,116,101,114,105, +111,117,115,68,101,112,97,114,116,109,101,110,116,98,101,115,116,32,107,110,111, +119,110,112,97,114,108,105,97,109,101,110,116,115,117,112,112,114,101,115,115, +101,100,99,111,110,118,101,110,105,101,110,116,114,101,109,101,109,98,101,114, +101,100,100,105,102,102,101,114,101,110,116,32,115,121,115,116,101,109,97,116, +105,99,104,97,115,32,108,101,100,32,116,111,112,114,111,112,97,103,97,110,100,97 +,99,111,110,116,114,111,108,108,101,100,105,110,102,108,117,101,110,99,101,115, +99,101,114,101,109,111,110,105,97,108,112,114,111,99,108,97,105,109,101,100,80, +114,111,116,101,99,116,105,111,110,108,105,32,99,108,97,115,115,61,34,83,99,105, +101,110,116,105,102,105,99,99,108,97,115,115,61,34,110,111,45,116,114,97,100,101 +,109,97,114,107,115,109,111,114,101,32,116,104,97,110,32,119,105,100,101,115,112 +,114,101,97,100,76,105,98,101,114,97,116,105,111,110,116,111,111,107,32,112,108, +97,99,101,100,97,121,32,111,102,32,116,104,101,97,115,32,108,111,110,103,32,97, +115,105,109,112,114,105,115,111,110,101,100,65,100,100,105,116,105,111,110,97, +108,10,60,104,101,97,100,62,10,60,109,76,97,98,111,114,97,116,111,114,121,78,111 +,118,101,109,98,101,114,32,50,101,120,99,101,112,116,105,111,110,115,73,110,100, +117,115,116,114,105,97,108,118,97,114,105,101,116,121,32,111,102,102,108,111,97, +116,58,32,108,101,102,68,117,114,105,110,103,32,116,104,101,97,115,115,101,115, +115,109,101,110,116,104,97,118,101,32,98,101,101,110,32,100,101,97,108,115,32, +119,105,116,104,83,116,97,116,105,115,116,105,99,115,111,99,99,117,114,114,101, +110,99,101,47,117,108,62,60,47,100,105,118,62,99,108,101,97,114,102,105,120,34, +62,116,104,101,32,112,117,98,108,105,99,109,97,110,121,32,121,101,97,114,115,119 +,104,105,99,104,32,119,101,114,101,111,118,101,114,32,116,105,109,101,44,115,121 +,110,111,110,121,109,111,117,115,99,111,110,116,101,110,116,34,62,10,112,114,101 +,115,117,109,97,98,108,121,104,105,115,32,102,97,109,105,108,121,117,115,101,114 +,65,103,101,110,116,46,117,110,101,120,112,101,99,116,101,100,105,110,99,108,117 +,100,105,110,103,32,99,104,97,108,108,101,110,103,101,100,97,32,109,105,110,111, +114,105,116,121,117,110,100,101,102,105,110,101,100,34,98,101,108,111,110,103, +115,32,116,111,116,97,107,101,110,32,102,114,111,109,105,110,32,79,99,116,111,98 +,101,114,112,111,115,105,116,105,111,110,58,32,115,97,105,100,32,116,111,32,98, +101,114,101,108,105,103,105,111,117,115,32,70,101,100,101,114,97,116,105,111,110 +,32,114,111,119,115,112,97,110,61,34,111,110,108,121,32,97,32,102,101,119,109, +101,97,110,116,32,116,104,97,116,108,101,100,32,116,111,32,116,104,101,45,45,62, +13,10,60,100,105,118,32,60,102,105,101,108,100,115,101,116,62,65,114,99,104,98, +105,115,104,111,112,32,99,108,97,115,115,61,34,110,111,98,101,105,110,103,32,117 +,115,101,100,97,112,112,114,111,97,99,104,101,115,112,114,105,118,105,108,101, +103,101,115,110,111,115,99,114,105,112,116,62,10,114,101,115,117,108,116,115,32, +105,110,109,97,121,32,98,101,32,116,104,101,69,97,115,116,101,114,32,101,103,103 +,109,101,99,104,97,110,105,115,109,115,114,101,97,115,111,110,97,98,108,101,80, +111,112,117,108,97,116,105,111,110,67,111,108,108,101,99,116,105,111,110,115,101 +,108,101,99,116,101,100,34,62,110,111,115,99,114,105,112,116,62,13,47,105,110, +100,101,120,46,112,104,112,97,114,114,105,118,97,108,32,111,102,45,106,115,115, +100,107,39,41,41,59,109,97,110,97,103,101,100,32,116,111,105,110,99,111,109,112, +108,101,116,101,99,97,115,117,97,108,116,105,101,115,99,111,109,112,108,101,116, +105,111,110,67,104,114,105,115,116,105,97,110,115,83,101,112,116,101,109,98,101, +114,32,97,114,105,116,104,109,101,116,105,99,112,114,111,99,101,100,117,114,101, +115,109,105,103,104,116,32,104,97,118,101,80,114,111,100,117,99,116,105,111,110, +105,116,32,97,112,112,101,97,114,115,80,104,105,108,111,115,111,112,104,121,102, +114,105,101,110,100,115,104,105,112,108,101,97,100,105,110,103,32,116,111,103, +105,118,105,110,103,32,116,104,101,116,111,119,97,114,100,32,116,104,101,103,117 +,97,114,97,110,116,101,101,100,100,111,99,117,109,101,110,116,101,100,99,111,108 +,111,114,58,35,48,48,48,118,105,100,101,111,32,103,97,109,101,99,111,109,109,105 +,115,115,105,111,110,114,101,102,108,101,99,116,105,110,103,99,104,97,110,103, +101,32,116,104,101,97,115,115,111,99,105,97,116,101,100,115,97,110,115,45,115, +101,114,105,102,111,110,107,101,121,112,114,101,115,115,59,32,112,97,100,100,105 +,110,103,58,72,101,32,119,97,115,32,116,104,101,117,110,100,101,114,108,121,105, +110,103,116,121,112,105,99,97,108,108,121,32,44,32,97,110,100,32,116,104,101,32, +115,114,99,69,108,101,109,101,110,116,115,117,99,99,101,115,115,105,118,101,115, +105,110,99,101,32,116,104,101,32,115,104,111,117,108,100,32,98,101,32,110,101, +116,119,111,114,107,105,110,103,97,99,99,111,117,110,116,105,110,103,117,115,101 +,32,111,102,32,116,104,101,108,111,119,101,114,32,116,104,97,110,115,104,111,119 +,115,32,116,104,97,116,60,47,115,112,97,110,62,10,9,9,99,111,109,112,108,97,105, +110,116,115,99,111,110,116,105,110,117,111,117,115,113,117,97,110,116,105,116, +105,101,115,97,115,116,114,111,110,111,109,101,114,104,101,32,100,105,100,32,110 +,111,116,100,117,101,32,116,111,32,105,116,115,97,112,112,108,105,101,100,32,116 +,111,97,110,32,97,118,101,114,97,103,101,101,102,102,111,114,116,115,32,116,111, +116,104,101,32,102,117,116,117,114,101,97,116,116,101,109,112,116,32,116,111,84, +104,101,114,101,102,111,114,101,44,99,97,112,97,98,105,108,105,116,121,82,101, +112,117,98,108,105,99,97,110,119,97,115,32,102,111,114,109,101,100,69,108,101,99 +,116,114,111,110,105,99,107,105,108,111,109,101,116,101,114,115,99,104,97,108, +108,101,110,103,101,115,112,117,98,108,105,115,104,105,110,103,116,104,101,32, +102,111,114,109,101,114,105,110,100,105,103,101,110,111,117,115,100,105,114,101, +99,116,105,111,110,115,115,117,98,115,105,100,105,97,114,121,99,111,110,115,112, +105,114,97,99,121,100,101,116,97,105,108,115,32,111,102,97,110,100,32,105,110,32 +,116,104,101,97,102,102,111,114,100,97,98,108,101,115,117,98,115,116,97,110,99, +101,115,114,101,97,115,111,110,32,102,111,114,99,111,110,118,101,110,116,105,111 +,110,105,116,101,109,116,121,112,101,61,34,97,98,115,111,108,117,116,101,108,121 +,115,117,112,112,111,115,101,100,108,121,114,101,109,97,105,110,101,100,32,97,97 +,116,116,114,97,99,116,105,118,101,116,114,97,118,101,108,108,105,110,103,115, +101,112,97,114,97,116,101,108,121,102,111,99,117,115,101,115,32,111,110,101,108, +101,109,101,110,116,97,114,121,97,112,112,108,105,99,97,98,108,101,102,111,117, +110,100,32,116,104,97,116,115,116,121,108,101,115,104,101,101,116,109,97,110,117 +,115,99,114,105,112,116,115,116,97,110,100,115,32,102,111,114,32,110,111,45,114, +101,112,101,97,116,40,115,111,109,101,116,105,109,101,115,67,111,109,109,101,114 +,99,105,97,108,105,110,32,65,109,101,114,105,99,97,117,110,100,101,114,116,97, +107,101,110,113,117,97,114,116,101,114,32,111,102,97,110,32,101,120,97,109,112, +108,101,112,101,114,115,111,110,97,108,108,121,105,110,100,101,120,46,112,104, +112,63,60,47,98,117,116,116,111,110,62,10,112,101,114,99,101,110,116,97,103,101, +98,101,115,116,45,107,110,111,119,110,99,114,101,97,116,105,110,103,32,97,34,32, +100,105,114,61,34,108,116,114,76,105,101,117,116,101,110,97,110,116,10,60,100, +105,118,32,105,100,61,34,116,104,101,121,32,119,111,117,108,100,97,98,105,108, +105,116,121,32,111,102,109,97,100,101,32,117,112,32,111,102,110,111,116,101,100, +32,116,104,97,116,99,108,101,97,114,32,116,104,97,116,97,114,103,117,101,32,116, +104,97,116,116,111,32,97,110,111,116,104,101,114,99,104,105,108,100,114,101,110, +39,115,112,117,114,112,111,115,101,32,111,102,102,111,114,109,117,108,97,116,101 +,100,98,97,115,101,100,32,117,112,111,110,116,104,101,32,114,101,103,105,111,110 +,115,117,98,106,101,99,116,32,111,102,112,97,115,115,101,110,103,101,114,115,112 +,111,115,115,101,115,115,105,111,110,46,10,10,73,110,32,116,104,101,32,66,101, +102,111,114,101,32,116,104,101,97,102,116,101,114,119,97,114,100,115,99,117,114, +114,101,110,116,108,121,32,97,99,114,111,115,115,32,116,104,101,115,99,105,101, +110,116,105,102,105,99,99,111,109,109,117,110,105,116,121,46,99,97,112,105,116, +97,108,105,115,109,105,110,32,71,101,114,109,97,110,121,114,105,103,104,116,45, +119,105,110,103,116,104,101,32,115,121,115,116,101,109,83,111,99,105,101,116,121 +,32,111,102,112,111,108,105,116,105,99,105,97,110,100,105,114,101,99,116,105,111 +,110,58,119,101,110,116,32,111,110,32,116,111,114,101,109,111,118,97,108,32,111, +102,32,78,101,119,32,89,111,114,107,32,97,112,97,114,116,109,101,110,116,115,105 +,110,100,105,99,97,116,105,111,110,100,117,114,105,110,103,32,116,104,101,117, +110,108,101,115,115,32,116,104,101,104,105,115,116,111,114,105,99,97,108,104,97, +100,32,98,101,101,110,32,97,100,101,102,105,110,105,116,105,118,101,105,110,103, +114,101,100,105,101,110,116,97,116,116,101,110,100,97,110,99,101,67,101,110,116, +101,114,32,102,111,114,112,114,111,109,105,110,101,110,99,101,114,101,97,100,121 +,83,116,97,116,101,115,116,114,97,116,101,103,105,101,115,98,117,116,32,105,110, +32,116,104,101,97,115,32,112,97,114,116,32,111,102,99,111,110,115,116,105,116, +117,116,101,99,108,97,105,109,32,116,104,97,116,108,97,98,111,114,97,116,111,114 +,121,99,111,109,112,97,116,105,98,108,101,102,97,105,108,117,114,101,32,111,102, +44,32,115,117,99,104,32,97,115,32,98,101,103,97,110,32,119,105,116,104,117,115, +105,110,103,32,116,104,101,32,116,111,32,112,114,111,118,105,100,101,102,101,97, +116,117,114,101,32,111,102,102,114,111,109,32,119,104,105,99,104,47,34,32,99,108 +,97,115,115,61,34,103,101,111,108,111,103,105,99,97,108,115,101,118,101,114,97, +108,32,111,102,100,101,108,105,98,101,114,97,116,101,105,109,112,111,114,116,97, +110,116,32,104,111,108,100,115,32,116,104,97,116,105,110,103,38,113,117,111,116, +59,32,118,97,108,105,103,110,61,116,111,112,116,104,101,32,71,101,114,109,97,110 +,111,117,116,115,105,100,101,32,111,102,110,101,103,111,116,105,97,116,101,100, +104,105,115,32,99,97,114,101,101,114,115,101,112,97,114,97,116,105,111,110,105, +100,61,34,115,101,97,114,99,104,119,97,115,32,99,97,108,108,101,100,116,104,101, +32,102,111,117,114,116,104,114,101,99,114,101,97,116,105,111,110,111,116,104,101 +,114,32,116,104,97,110,112,114,101,118,101,110,116,105,111,110,119,104,105,108, +101,32,116,104,101,32,101,100,117,99,97,116,105,111,110,44,99,111,110,110,101,99 +,116,105,110,103,97,99,99,117,114,97,116,101,108,121,119,101,114,101,32,98,117, +105,108,116,119,97,115,32,107,105,108,108,101,100,97,103,114,101,101,109,101,110 +,116,115,109,117,99,104,32,109,111,114,101,32,68,117,101,32,116,111,32,116,104, +101,119,105,100,116,104,58,32,49,48,48,115,111,109,101,32,111,116,104,101,114,75 +,105,110,103,100,111,109,32,111,102,116,104,101,32,101,110,116,105,114,101,102, +97,109,111,117,115,32,102,111,114,116,111,32,99,111,110,110,101,99,116,111,98, +106,101,99,116,105,118,101,115,116,104,101,32,70,114,101,110,99,104,112,101,111, +112,108,101,32,97,110,100,102,101,97,116,117,114,101,100,34,62,105,115,32,115,97 +,105,100,32,116,111,115,116,114,117,99,116,117,114,97,108,114,101,102,101,114, +101,110,100,117,109,109,111,115,116,32,111,102,116,101,110,97,32,115,101,112,97, +114,97,116,101,45,62,10,60,100,105,118,32,105,100,32,79,102,102,105,99,105,97, +108,32,119,111,114,108,100,119,105,100,101,46,97,114,105,97,45,108,97,98,101,108 +,116,104,101,32,112,108,97,110,101,116,97,110,100,32,105,116,32,119,97,115,100, +34,32,118,97,108,117,101,61,34,108,111,111,107,105,110,103,32,97,116,98,101,110, +101,102,105,99,105,97,108,97,114,101,32,105,110,32,116,104,101,109,111,110,105, +116,111,114,105,110,103,114,101,112,111,114,116,101,100,108,121,116,104,101,32, +109,111,100,101,114,110,119,111,114,107,105,110,103,32,111,110,97,108,108,111, +119,101,100,32,116,111,119,104,101,114,101,32,116,104,101,32,105,110,110,111,118 +,97,116,105,118,101,60,47,97,62,60,47,100,105,118,62,115,111,117,110,100,116,114 +,97,99,107,115,101,97,114,99,104,70,111,114,109,116,101,110,100,32,116,111,32,98 +,101,105,110,112,117,116,32,105,100,61,34,111,112,101,110,105,110,103,32,111,102 +,114,101,115,116,114,105,99,116,101,100,97,100,111,112,116,101,100,32,98,121,97, +100,100,114,101,115,115,105,110,103,116,104,101,111,108,111,103,105,97,110,109, +101,116,104,111,100,115,32,111,102,118,97,114,105,97,110,116,32,111,102,67,104, +114,105,115,116,105,97,110,32,118,101,114,121,32,108,97,114,103,101,97,117,116, +111,109,111,116,105,118,101,98,121,32,102,97,114,32,116,104,101,114,97,110,103, +101,32,102,114,111,109,112,117,114,115,117,105,116,32,111,102,102,111,108,108, +111,119,32,116,104,101,98,114,111,117,103,104,116,32,116,111,105,110,32,69,110, +103,108,97,110,100,97,103,114,101,101,32,116,104,97,116,97,99,99,117,115,101,100 +,32,111,102,99,111,109,101,115,32,102,114,111,109,112,114,101,118,101,110,116, +105,110,103,100,105,118,32,115,116,121,108,101,61,104,105,115,32,111,114,32,104, +101,114,116,114,101,109,101,110,100,111,117,115,102,114,101,101,100,111,109,32, +111,102,99,111,110,99,101,114,110,105,110,103,48,32,49,101,109,32,49,101,109,59, +66,97,115,107,101,116,98,97,108,108,47,115,116,121,108,101,46,99,115,115,97,110, +32,101,97,114,108,105,101,114,101,118,101,110,32,97,102,116,101,114,47,34,32,116 +,105,116,108,101,61,34,46,99,111,109,47,105,110,100,101,120,116,97,107,105,110, +103,32,116,104,101,112,105,116,116,115,98,117,114,103,104,99,111,110,116,101,110 +,116,34,62,13,60,115,99,114,105,112,116,62,40,102,116,117,114,110,101,100,32,111 +,117,116,104,97,118,105,110,103,32,116,104,101,60,47,115,112,97,110,62,13,10,32, +111,99,99,97,115,105,111,110,97,108,98,101,99,97,117,115,101,32,105,116,115,116, +97,114,116,101,100,32,116,111,112,104,121,115,105,99,97,108,108,121,62,60,47,100 +,105,118,62,10,32,32,99,114,101,97,116,101,100,32,98,121,67,117,114,114,101,110, +116,108,121,44,32,98,103,99,111,108,111,114,61,34,116,97,98,105,110,100,101,120, +61,34,100,105,115,97,115,116,114,111,117,115,65,110,97,108,121,116,105,99,115,32 +,97,108,115,111,32,104,97,115,32,97,62,60,100,105,118,32,105,100,61,34,60,47,115 +,116,121,108,101,62,10,60,99,97,108,108,101,100,32,102,111,114,115,105,110,103, +101,114,32,97,110,100,46,115,114,99,32,61,32,34,47,47,118,105,111,108,97,116,105 +,111,110,115,116,104,105,115,32,112,111,105,110,116,99,111,110,115,116,97,110, +116,108,121,105,115,32,108,111,99,97,116,101,100,114,101,99,111,114,100,105,110, +103,115,100,32,102,114,111,109,32,116,104,101,110,101,100,101,114,108,97,110,100 +,115,112,111,114,116,117,103,117,195,170,115,215,162,215,145,215,168,215,153,215 +,170,217,129,216,167,216,177,216,179,219,140,100,101,115,97,114,114,111,108,108, +111,99,111,109,101,110,116,97,114,105,111,101,100,117,99,97,99,105,195,179,110, +115,101,112,116,105,101,109,98,114,101,114,101,103,105,115,116,114,97,100,111, +100,105,114,101,99,99,105,195,179,110,117,98,105,99,97,99,105,195,179,110,112, +117,98,108,105,99,105,100,97,100,114,101,115,112,117,101,115,116,97,115,114,101, +115,117,108,116,97,100,111,115,105,109,112,111,114,116,97,110,116,101,114,101, +115,101,114,118,97,100,111,115,97,114,116,195,173,99,117,108,111,115,100,105,102 +,101,114,101,110,116,101,115,115,105,103,117,105,101,110,116,101,115,114,101,112 +,195,186,98,108,105,99,97,115,105,116,117,97,99,105,195,179,110,109,105,110,105, +115,116,101,114,105,111,112,114,105,118,97,99,105,100,97,100,100,105,114,101,99, +116,111,114,105,111,102,111,114,109,97,99,105,195,179,110,112,111,98,108,97,99, +105,195,179,110,112,114,101,115,105,100,101,110,116,101,99,111,110,116,101,110, +105,100,111,115,97,99,99,101,115,111,114,105,111,115,116,101,99,104,110,111,114, +97,116,105,112,101,114,115,111,110,97,108,101,115,99,97,116,101,103,111,114,195, +173,97,101,115,112,101,99,105,97,108,101,115,100,105,115,112,111,110,105,98,108, +101,97,99,116,117,97,108,105,100,97,100,114,101,102,101,114,101,110,99,105,97, +118,97,108,108,97,100,111,108,105,100,98,105,98,108,105,111,116,101,99,97,114, +101,108,97,99,105,111,110,101,115,99,97,108,101,110,100,97,114,105,111,112,111, +108,195,173,116,105,99,97,115,97,110,116,101,114,105,111,114,101,115,100,111,99, +117,109,101,110,116,111,115,110,97,116,117,114,97,108,101,122,97,109,97,116,101, +114,105,97,108,101,115,100,105,102,101,114,101,110,99,105,97,101,99,111,110,195, +179,109,105,99,97,116,114,97,110,115,112,111,114,116,101,114,111,100,114,195,173 +,103,117,101,122,112,97,114,116,105,99,105,112,97,114,101,110,99,117,101,110,116 +,114,97,110,100,105,115,99,117,115,105,195,179,110,101,115,116,114,117,99,116, +117,114,97,102,117,110,100,97,99,105,195,179,110,102,114,101,99,117,101,110,116, +101,115,112,101,114,109,97,110,101,110,116,101,116,111,116,97,108,109,101,110, +116,101,208,188,208,190,208,182,208,189,208,190,208,177,209,131,208,180,208,181, +209,130,208,188,208,190,208,182,208,181,209,130,208,178,209,128,208,181,208,188, +209,143,209,130,208,176,208,186,208,182,208,181,209,135,209,130,208,190,208,177, +209,139,208,177,208,190,208,187,208,181,208,181,208,190,209,135,208,181,208,189, +209,140,209,141,209,130,208,190,208,179,208,190,208,186,208,190,208,179,208,180, +208,176,208,191,208,190,209,129,208,187,208,181,208,178,209,129,208,181,208,179, +208,190,209,129,208,176,208,185,209,130,208,181,209,135,208,181,209,128,208,181, +208,183,208,188,208,190,208,179,209,131,209,130,209,129,208,176,208,185,209,130, +208,176,208,182,208,184,208,183,208,189,208,184,208,188,208,181,208,182,208,180, +209,131,208,177,209,131,208,180,209,131,209,130,208,159,208,190,208,184,209,129, +208,186,208,183,208,180,208,181,209,129,209,140,208,178,208,184,208,180,208,181, +208,190,209,129,208,178,209,143,208,183,208,184,208,189,209,131,208,182,208,189, +208,190,209,129,208,178,208,190,208,181,208,185,208,187,209,142,208,180,208,181, +208,185,208,191,208,190,209,128,208,189,208,190,208,188,208,189,208,190,208,179, +208,190,208,180,208,181,209,130,208,181,208,185,209,129,208,178,208,190,208,184, +209,133,208,191,209,128,208,176,208,178,208,176,209,130,208,176,208,186,208,190, +208,185,208,188,208,181,209,129,209,130,208,190,208,184,208,188,208,181,208,181, +209,130,208,182,208,184,208,183,208,189,209,140,208,190,208,180,208,189,208,190, +208,185,208,187,209,131,209,135,209,136,208,181,208,191,208,181,209,128,208,181, +208,180,209,135,208,176,209,129,209,130,208,184,209,135,208,176,209,129,209,130, +209,140,209,128,208,176,208,177,208,190,209,130,208,189,208,190,208,178,209,139, +209,133,208,191,209,128,208,176,208,178,208,190,209,129,208,190,208,177,208,190, +208,185,208,191,208,190,209,130,208,190,208,188,208,188,208,181,208,189,208,181, +208,181,209,135,208,184,209,129,208,187,208,181,208,189,208,190,208,178,209,139, +208,181,209,131,209,129,208,187,209,131,208,179,208,190,208,186,208,190,208,187, +208,190,208,189,208,176,208,183,208,176,208,180,209,130,208,176,208,186,208,190, +208,181,209,130,208,190,208,179,208,180,208,176,208,191,208,190,209,135,209,130, +208,184,208,159,208,190,209,129,208,187,208,181,209,130,208,176,208,186,208,184, +208,181,208,189,208,190,208,178,209,139,208,185,209,129,209,130,208,190,208,184, +209,130,209,130,208,176,208,186,208,184,209,133,209,129,209,128,208,176,208,183, +209,131,208,161,208,176,208,189,208,186,209,130,209,132,208,190,209,128,209,131, +208,188,208,154,208,190,208,179,208,180,208,176,208,186,208,189,208,184,208,179, +208,184,209,129,208,187,208,190,208,178,208,176,208,189,208,176,209,136,208,181, +208,185,208,189,208,176,208,185,209,130,208,184,209,129,208,178,208,190,208,184, +208,188,209,129,208,178,209,143,208,183,209,140,208,187,209,142,208,177,208,190, +208,185,209,135,208,176,209,129,209,130,208,190,209,129,209,128,208,181,208,180, +208,184,208,154,209,128,208,190,208,188,208,181,208,164,208,190,209,128,209,131, +208,188,209,128,209,139,208,189,208,186,208,181,209,129,209,130,208,176,208,187, +208,184,208,191,208,190,208,184,209,129,208,186,209,130,209,139,209,129,209,143, +209,135,208,188,208,181,209,129,209,143,209,134,209,134,208,181,208,189,209,130, +209,128,209,130,209,128,209,131,208,180,208,176,209,129,208,176,208,188,209,139, +209,133,209,128,209,139,208,189,208,186,208,176,208,157,208,190,208,178,209,139, +208,185,209,135,208,176,209,129,208,190,208,178,208,188,208,181,209,129,209,130, +208,176,209,132,208,184,208,187,209,140,208,188,208,188,208,176,209,128,209,130, +208,176,209,129,209,130,209,128,208,176,208,189,208,188,208,181,209,129,209,130, +208,181,209,130,208,181,208,186,209,129,209,130,208,189,208,176,209,136,208,184, +209,133,208,188,208,184,208,189,209,131,209,130,208,184,208,188,208,181,208,189, +208,184,208,184,208,188,208,181,209,142,209,130,208,189,208,190,208,188,208,181, +209,128,208,179,208,190,209,128,208,190,208,180,209,129,208,176,208,188,208,190, +208,188,209,141,209,130,208,190,208,188,209,131,208,186,208,190,208,189,209,134, +208,181,209,129,208,178,208,190,208,181,208,188,208,186,208,176,208,186,208,190, +208,185,208,144,209,128,209,133,208,184,208,178,217,133,217,134,216,170,216,175, +217,137,216,165,216,177,216,179,216,167,217,132,216,177,216,179,216,167,217,132, +216,169,216,167,217,132,216,185,216,167,217,133,217,131,216,170,216,168,217,135, +216,167,216,168,216,177,216,167,217,133,216,172,216,167,217,132,217,138,217,136, +217,133,216,167,217,132,216,181,217,136,216,177,216,172,216,175,217,138,216,175, +216,169,216,167,217,132,216,185,216,182,217,136,216,165,216,182,216,167,217,129, +216,169,216,167,217,132,217,130,216,179,217,133,216,167,217,132,216,185,216,167, +216,168,216,170,216,173,217,133,217,138,217,132,217,133,217,132,217,129,216,167, +216,170,217,133,217,132,216,170,217,130,217,137,216,170,216,185,216,175,217,138, +217,132,216,167,217,132,216,180,216,185,216,177,216,163,216,174,216,168,216,167, +216,177,216,170,216,183,217,136,217,138,216,177,216,185,217,132,217,138,217,131, +217,133,216,165,216,177,217,129,216,167,217,130,216,183,217,132,216,168,216,167, +216,170,216,167,217,132,217,132,216,186,216,169,216,170,216,177,216,170,217,138, +216,168,216,167,217,132,217,134,216,167,216,179,216,167,217,132,216,180,217,138, +216,174,217,133,217,134,216,170,216,175,217,138,216,167,217,132,216,185,216,177, +216,168,216,167,217,132,217,130,216,181,216,181,216,167,217,129,217,132,216,167, +217,133,216,185,217,132,217,138,217,135,216,167,216,170,216,173,216,175,217,138, +216,171,216,167,217,132,217,132,217,135,217,133,216,167,217,132,216,185,217,133, +217,132,217,133,217,131,216,170,216,168,216,169,217,138,217,133,217,131,217,134, +217,131,216,167,217,132,216,183,217,129,217,132,217,129,217,138,216,175,217,138, +217,136,216,165,216,175,216,167,216,177,216,169,216,170,216,167,216,177,217,138, +216,174,216,167,217,132,216,181,216,173,216,169,216,170,216,179,216,172,217,138, +217,132,216,167,217,132,217,136,217,130,216,170,216,185,217,134,216,175,217,133, +216,167,217,133,216,175,217,138,217,134,216,169,216,170,216,181,217,133,217,138, +217,133,216,163,216,177,216,180,217,138,217,129,216,167,217,132,216,176,217,138, +217,134,216,185,216,177,216,168,217,138,216,169,216,168,217,136,216,167,216,168, +216,169,216,163,217,132,216,185,216,167,216,168,216,167,217,132,216,179,217,129, +216,177,217,133,216,180,216,167,217,131,217,132,216,170,216,185,216,167,217,132, +217,137,216,167,217,132,216,163,217,136,217,132,216,167,217,132,216,179,217,134, +216,169,216,172,216,167,217,133,216,185,216,169,216,167,217,132,216,181,216,173, +217,129,216,167,217,132,216,175,217,138,217,134,217,131,217,132,217,133,216,167, +216,170,216,167,217,132,216,174,216,167,216,181,216,167,217,132,217,133,217,132, +217,129,216,163,216,185,216,182,216,167,216,161,217,131,216,170,216,167,216,168, +216,169,216,167,217,132,216,174,217,138,216,177,216,177,216,179,216,167,216,166, +217,132,216,167,217,132,217,130,217,132,216,168,216,167,217,132,216,163,216,175, +216,168,217,133,217,130,216,167,216,183,216,185,217,133,216,177,216,167,216,179, +217,132,217,133,217,134,216,183,217,130,216,169,216,167,217,132,217,131,216,170, +216,168,216,167,217,132,216,177,216,172,217,132,216,167,216,180,216,170,216,177, +217,131,216,167,217,132,217,130,216,175,217,133,217,138,216,185,216,183,217,138, +217,131,115,66,121,84,97,103,78,97,109,101,40,46,106,112,103,34,32,97,108,116,61 +,34,49,112,120,32,115,111,108,105,100,32,35,46,103,105,102,34,32,97,108,116,61, +34,116,114,97,110,115,112,97,114,101,110,116,105,110,102,111,114,109,97,116,105, +111,110,97,112,112,108,105,99,97,116,105,111,110,34,32,111,110,99,108,105,99,107 +,61,34,101,115,116,97,98,108,105,115,104,101,100,97,100,118,101,114,116,105,115, +105,110,103,46,112,110,103,34,32,97,108,116,61,34,101,110,118,105,114,111,110, +109,101,110,116,112,101,114,102,111,114,109,97,110,99,101,97,112,112,114,111,112 +,114,105,97,116,101,38,97,109,112,59,109,100,97,115,104,59,105,109,109,101,100, +105,97,116,101,108,121,60,47,115,116,114,111,110,103,62,60,47,114,97,116,104,101 +,114,32,116,104,97,110,116,101,109,112,101,114,97,116,117,114,101,100,101,118, +101,108,111,112,109,101,110,116,99,111,109,112,101,116,105,116,105,111,110,112, +108,97,99,101,104,111,108,100,101,114,118,105,115,105,98,105,108,105,116,121,58, +99,111,112,121,114,105,103,104,116,34,62,48,34,32,104,101,105,103,104,116,61,34, +101,118,101,110,32,116,104,111,117,103,104,114,101,112,108,97,99,101,109,101,110 +,116,100,101,115,116,105,110,97,116,105,111,110,67,111,114,112,111,114,97,116, +105,111,110,60,117,108,32,99,108,97,115,115,61,34,65,115,115,111,99,105,97,116, +105,111,110,105,110,100,105,118,105,100,117,97,108,115,112,101,114,115,112,101, +99,116,105,118,101,115,101,116,84,105,109,101,111,117,116,40,117,114,108,40,104, +116,116,112,58,47,47,109,97,116,104,101,109,97,116,105,99,115,109,97,114,103,105 +,110,45,116,111,112,58,101,118,101,110,116,117,97,108,108,121,32,100,101,115,99, +114,105,112,116,105,111,110,41,32,110,111,45,114,101,112,101,97,116,99,111,108, +108,101,99,116,105,111,110,115,46,74,80,71,124,116,104,117,109,98,124,112,97,114 +,116,105,99,105,112,97,116,101,47,104,101,97,100,62,60,98,111,100,121,102,108, +111,97,116,58,108,101,102,116,59,60,108,105,32,99,108,97,115,115,61,34,104,117, +110,100,114,101,100,115,32,111,102,10,10,72,111,119,101,118,101,114,44,32,99,111 +,109,112,111,115,105,116,105,111,110,99,108,101,97,114,58,98,111,116,104,59,99, +111,111,112,101,114,97,116,105,111,110,119,105,116,104,105,110,32,116,104,101,32 +,108,97,98,101,108,32,102,111,114,61,34,98,111,114,100,101,114,45,116,111,112,58 +,78,101,119,32,90,101,97,108,97,110,100,114,101,99,111,109,109,101,110,100,101, +100,112,104,111,116,111,103,114,97,112,104,121,105,110,116,101,114,101,115,116, +105,110,103,38,108,116,59,115,117,112,38,103,116,59,99,111,110,116,114,111,118, +101,114,115,121,78,101,116,104,101,114,108,97,110,100,115,97,108,116,101,114,110 +,97,116,105,118,101,109,97,120,108,101,110,103,116,104,61,34,115,119,105,116,122 +,101,114,108,97,110,100,68,101,118,101,108,111,112,109,101,110,116,101,115,115, +101,110,116,105,97,108,108,121,10,10,65,108,116,104,111,117,103,104,32,60,47,116 +,101,120,116,97,114,101,97,62,116,104,117,110,100,101,114,98,105,114,100,114,101 +,112,114,101,115,101,110,116,101,100,38,97,109,112,59,110,100,97,115,104,59,115, +112,101,99,117,108,97,116,105,111,110,99,111,109,109,117,110,105,116,105,101,115 +,108,101,103,105,115,108,97,116,105,111,110,101,108,101,99,116,114,111,110,105, +99,115,10,9,60,100,105,118,32,105,100,61,34,105,108,108,117,115,116,114,97,116, +101,100,101,110,103,105,110,101,101,114,105,110,103,116,101,114,114,105,116,111, +114,105,101,115,97,117,116,104,111,114,105,116,105,101,115,100,105,115,116,114, +105,98,117,116,101,100,54,34,32,104,101,105,103,104,116,61,34,115,97,110,115,45, +115,101,114,105,102,59,99,97,112,97,98,108,101,32,111,102,32,100,105,115,97,112, +112,101,97,114,101,100,105,110,116,101,114,97,99,116,105,118,101,108,111,111,107 +,105,110,103,32,102,111,114,105,116,32,119,111,117,108,100,32,98,101,65,102,103, +104,97,110,105,115,116,97,110,119,97,115,32,99,114,101,97,116,101,100,77,97,116, +104,46,102,108,111,111,114,40,115,117,114,114,111,117,110,100,105,110,103,99,97, +110,32,97,108,115,111,32,98,101,111,98,115,101,114,118,97,116,105,111,110,109,97 +,105,110,116,101,110,97,110,99,101,101,110,99,111,117,110,116,101,114,101,100,60 +,104,50,32,99,108,97,115,115,61,34,109,111,114,101,32,114,101,99,101,110,116,105 +,116,32,104,97,115,32,98,101,101,110,105,110,118,97,115,105,111,110,32,111,102, +41,46,103,101,116,84,105,109,101,40,41,102,117,110,100,97,109,101,110,116,97,108 +,68,101,115,112,105,116,101,32,116,104,101,34,62,60,100,105,118,32,105,100,61,34 +,105,110,115,112,105,114,97,116,105,111,110,101,120,97,109,105,110,97,116,105, +111,110,112,114,101,112,97,114,97,116,105,111,110,101,120,112,108,97,110,97,116, +105,111,110,60,105,110,112,117,116,32,105,100,61,34,60,47,97,62,60,47,115,112,97 +,110,62,118,101,114,115,105,111,110,115,32,111,102,105,110,115,116,114,117,109, +101,110,116,115,98,101,102,111,114,101,32,116,104,101,32,32,61,32,39,104,116,116 +,112,58,47,47,68,101,115,99,114,105,112,116,105,111,110,114,101,108,97,116,105, +118,101,108,121,32,46,115,117,98,115,116,114,105,110,103,40,101,97,99,104,32,111 +,102,32,116,104,101,101,120,112,101,114,105,109,101,110,116,115,105,110,102,108, +117,101,110,116,105,97,108,105,110,116,101,103,114,97,116,105,111,110,109,97,110 +,121,32,112,101,111,112,108,101,100,117,101,32,116,111,32,116,104,101,32,99,111, +109,98,105,110,97,116,105,111,110,100,111,32,110,111,116,32,104,97,118,101,77, +105,100,100,108,101,32,69,97,115,116,60,110,111,115,99,114,105,112,116,62,60,99, +111,112,121,114,105,103,104,116,34,32,112,101,114,104,97,112,115,32,116,104,101, +105,110,115,116,105,116,117,116,105,111,110,105,110,32,68,101,99,101,109,98,101, +114,97,114,114,97,110,103,101,109,101,110,116,109,111,115,116,32,102,97,109,111, +117,115,112,101,114,115,111,110,97,108,105,116,121,99,114,101,97,116,105,111,110 +,32,111,102,108,105,109,105,116,97,116,105,111,110,115,101,120,99,108,117,115, +105,118,101,108,121,115,111,118,101,114,101,105,103,110,116,121,45,99,111,110, +116,101,110,116,34,62,10,60,116,100,32,99,108,97,115,115,61,34,117,110,100,101, +114,103,114,111,117,110,100,112,97,114,97,108,108,101,108,32,116,111,100,111,99, +116,114,105,110,101,32,111,102,111,99,99,117,112,105,101,100,32,98,121,116,101, +114,109,105,110,111,108,111,103,121,82,101,110,97,105,115,115,97,110,99,101,97, +32,110,117,109,98,101,114,32,111,102,115,117,112,112,111,114,116,32,102,111,114, +101,120,112,108,111,114,97,116,105,111,110,114,101,99,111,103,110,105,116,105, +111,110,112,114,101,100,101,99,101,115,115,111,114,60,105,109,103,32,115,114,99, +61,34,47,60,104,49,32,99,108,97,115,115,61,34,112,117,98,108,105,99,97,116,105, +111,110,109,97,121,32,97,108,115,111,32,98,101,115,112,101,99,105,97,108,105,122 +,101,100,60,47,102,105,101,108,100,115,101,116,62,112,114,111,103,114,101,115, +115,105,118,101,109,105,108,108,105,111,110,115,32,111,102,115,116,97,116,101, +115,32,116,104,97,116,101,110,102,111,114,99,101,109,101,110,116,97,114,111,117, +110,100,32,116,104,101,32,111,110,101,32,97,110,111,116,104,101,114,46,112,97, +114,101,110,116,78,111,100,101,97,103,114,105,99,117,108,116,117,114,101,65,108, +116,101,114,110,97,116,105,118,101,114,101,115,101,97,114,99,104,101,114,115,116 +,111,119,97,114,100,115,32,116,104,101,77,111,115,116,32,111,102,32,116,104,101, +109,97,110,121,32,111,116,104,101,114,32,40,101,115,112,101,99,105,97,108,108, +121,60,116,100,32,119,105,100,116,104,61,34,59,119,105,100,116,104,58,49,48,48, +37,105,110,100,101,112,101,110,100,101,110,116,60,104,51,32,99,108,97,115,115,61 +,34,32,111,110,99,104,97,110,103,101,61,34,41,46,97,100,100,67,108,97,115,115,40 +,105,110,116,101,114,97,99,116,105,111,110,79,110,101,32,111,102,32,116,104,101, +32,100,97,117,103,104,116,101,114,32,111,102,97,99,99,101,115,115,111,114,105, +101,115,98,114,97,110,99,104,101,115,32,111,102,13,10,60,100,105,118,32,105,100, +61,34,116,104,101,32,108,97,114,103,101,115,116,100,101,99,108,97,114,97,116,105 +,111,110,114,101,103,117,108,97,116,105,111,110,115,73,110,102,111,114,109,97, +116,105,111,110,116,114,97,110,115,108,97,116,105,111,110,100,111,99,117,109,101 +,110,116,97,114,121,105,110,32,111,114,100,101,114,32,116,111,34,62,10,60,104, +101,97,100,62,10,60,34,32,104,101,105,103,104,116,61,34,49,97,99,114,111,115,115 +,32,116,104,101,32,111,114,105,101,110,116,97,116,105,111,110,41,59,60,47,115,99 +,114,105,112,116,62,105,109,112,108,101,109,101,110,116,101,100,99,97,110,32,98, +101,32,115,101,101,110,116,104,101,114,101,32,119,97,115,32,97,100,101,109,111, +110,115,116,114,97,116,101,99,111,110,116,97,105,110,101,114,34,62,99,111,110, +110,101,99,116,105,111,110,115,116,104,101,32,66,114,105,116,105,115,104,119,97, +115,32,119,114,105,116,116,101,110,33,105,109,112,111,114,116,97,110,116,59,112, +120,59,32,109,97,114,103,105,110,45,102,111,108,108,111,119,101,100,32,98,121,97 +,98,105,108,105,116,121,32,116,111,32,99,111,109,112,108,105,99,97,116,101,100, +100,117,114,105,110,103,32,116,104,101,32,105,109,109,105,103,114,97,116,105,111 +,110,97,108,115,111,32,99,97,108,108,101,100,60,104,52,32,99,108,97,115,115,61, +34,100,105,115,116,105,110,99,116,105,111,110,114,101,112,108,97,99,101,100,32, +98,121,103,111,118,101,114,110,109,101,110,116,115,108,111,99,97,116,105,111,110 +,32,111,102,105,110,32,78,111,118,101,109,98,101,114,119,104,101,116,104,101,114 +,32,116,104,101,60,47,112,62,10,60,47,100,105,118,62,97,99,113,117,105,115,105, +116,105,111,110,99,97,108,108,101,100,32,116,104,101,32,112,101,114,115,101,99, +117,116,105,111,110,100,101,115,105,103,110,97,116,105,111,110,123,102,111,110, +116,45,115,105,122,101,58,97,112,112,101,97,114,101,100,32,105,110,105,110,118, +101,115,116,105,103,97,116,101,101,120,112,101,114,105,101,110,99,101,100,109, +111,115,116,32,108,105,107,101,108,121,119,105,100,101,108,121,32,117,115,101, +100,100,105,115,99,117,115,115,105,111,110,115,112,114,101,115,101,110,99,101,32 +,111,102,32,40,100,111,99,117,109,101,110,116,46,101,120,116,101,110,115,105,118 +,101,108,121,73,116,32,104,97,115,32,98,101,101,110,105,116,32,100,111,101,115, +32,110,111,116,99,111,110,116,114,97,114,121,32,116,111,105,110,104,97,98,105, +116,97,110,116,115,105,109,112,114,111,118,101,109,101,110,116,115,99,104,111, +108,97,114,115,104,105,112,99,111,110,115,117,109,112,116,105,111,110,105,110, +115,116,114,117,99,116,105,111,110,102,111,114,32,101,120,97,109,112,108,101,111 +,110,101,32,111,114,32,109,111,114,101,112,120,59,32,112,97,100,100,105,110,103, +116,104,101,32,99,117,114,114,101,110,116,97,32,115,101,114,105,101,115,32,111, +102,97,114,101,32,117,115,117,97,108,108,121,114,111,108,101,32,105,110,32,116, +104,101,112,114,101,118,105,111,117,115,108,121,32,100,101,114,105,118,97,116, +105,118,101,115,101,118,105,100,101,110,99,101,32,111,102,101,120,112,101,114, +105,101,110,99,101,115,99,111,108,111,114,115,99,104,101,109,101,115,116,97,116, +101,100,32,116,104,97,116,99,101,114,116,105,102,105,99,97,116,101,60,47,97,62, +60,47,100,105,118,62,10,32,115,101,108,101,99,116,101,100,61,34,104,105,103,104, +32,115,99,104,111,111,108,114,101,115,112,111,110,115,101,32,116,111,99,111,109, +102,111,114,116,97,98,108,101,97,100,111,112,116,105,111,110,32,111,102,116,104, +114,101,101,32,121,101,97,114,115,116,104,101,32,99,111,117,110,116,114,121,105, +110,32,70,101,98,114,117,97,114,121,115,111,32,116,104,97,116,32,116,104,101,112 +,101,111,112,108,101,32,119,104,111,32,112,114,111,118,105,100,101,100,32,98,121 +,60,112,97,114,97,109,32,110,97,109,101,97,102,102,101,99,116,101,100,32,98,121, +105,110,32,116,101,114,109,115,32,111,102,97,112,112,111,105,110,116,109,101,110 +,116,73,83,79,45,56,56,53,57,45,49,34,119,97,115,32,98,111,114,110,32,105,110, +104,105,115,116,111,114,105,99,97,108,32,114,101,103,97,114,100,101,100,32,97, +115,109,101,97,115,117,114,101,109,101,110,116,105,115,32,98,97,115,101,100,32, +111,110,32,97,110,100,32,111,116,104,101,114,32,58,32,102,117,110,99,116,105,111 +,110,40,115,105,103,110,105,102,105,99,97,110,116,99,101,108,101,98,114,97,116, +105,111,110,116,114,97,110,115,109,105,116,116,101,100,47,106,115,47,106,113,117 +,101,114,121,46,105,115,32,107,110,111,119,110,32,97,115,116,104,101,111,114,101 +,116,105,99,97,108,32,116,97,98,105,110,100,101,120,61,34,105,116,32,99,111,117, +108,100,32,98,101,60,110,111,115,99,114,105,112,116,62,10,104,97,118,105,110,103 +,32,98,101,101,110,13,10,60,104,101,97,100,62,13,10,60,32,38,113,117,111,116,59, +84,104,101,32,99,111,109,112,105,108,97,116,105,111,110,104,101,32,104,97,100,32 +,98,101,101,110,112,114,111,100,117,99,101,100,32,98,121,112,104,105,108,111,115 +,111,112,104,101,114,99,111,110,115,116,114,117,99,116,101,100,105,110,116,101, +110,100,101,100,32,116,111,97,109,111,110,103,32,111,116,104,101,114,99,111,109, +112,97,114,101,100,32,116,111,116,111,32,115,97,121,32,116,104,97,116,69,110,103 +,105,110,101,101,114,105,110,103,97,32,100,105,102,102,101,114,101,110,116,114, +101,102,101,114,114,101,100,32,116,111,100,105,102,102,101,114,101,110,99,101, +115,98,101,108,105,101,102,32,116,104,97,116,112,104,111,116,111,103,114,97,112, +104,115,105,100,101,110,116,105,102,121,105,110,103,72,105,115,116,111,114,121, +32,111,102,32,82,101,112,117,98,108,105,99,32,111,102,110,101,99,101,115,115,97, +114,105,108,121,112,114,111,98,97,98,105,108,105,116,121,116,101,99,104,110,105, +99,97,108,108,121,108,101,97,118,105,110,103,32,116,104,101,115,112,101,99,116, +97,99,117,108,97,114,102,114,97,99,116,105,111,110,32,111,102,101,108,101,99,116 +,114,105,99,105,116,121,104,101,97,100,32,111,102,32,116,104,101,114,101,115,116 +,97,117,114,97,110,116,115,112,97,114,116,110,101,114,115,104,105,112,101,109, +112,104,97,115,105,115,32,111,110,109,111,115,116,32,114,101,99,101,110,116,115, +104,97,114,101,32,119,105,116,104,32,115,97,121,105,110,103,32,116,104,97,116, +102,105,108,108,101,100,32,119,105,116,104,100,101,115,105,103,110,101,100,32, +116,111,105,116,32,105,115,32,111,102,116,101,110,34,62,60,47,105,102,114,97,109 +,101,62,97,115,32,102,111,108,108,111,119,115,58,109,101,114,103,101,100,32,119, +105,116,104,116,104,114,111,117,103,104,32,116,104,101,99,111,109,109,101,114,99 +,105,97,108,32,112,111,105,110,116,101,100,32,111,117,116,111,112,112,111,114, +116,117,110,105,116,121,118,105,101,119,32,111,102,32,116,104,101,114,101,113, +117,105,114,101,109,101,110,116,100,105,118,105,115,105,111,110,32,111,102,112, +114,111,103,114,97,109,109,105,110,103,104,101,32,114,101,99,101,105,118,101,100 +,115,101,116,73,110,116,101,114,118,97,108,34,62,60,47,115,112,97,110,62,60,47, +105,110,32,78,101,119,32,89,111,114,107,97,100,100,105,116,105,111,110,97,108,32 +,99,111,109,112,114,101,115,115,105,111,110,10,10,60,100,105,118,32,105,100,61, +34,105,110,99,111,114,112,111,114,97,116,101,59,60,47,115,99,114,105,112,116,62, +60,97,116,116,97,99,104,69,118,101,110,116,98,101,99,97,109,101,32,116,104,101, +32,34,32,116,97,114,103,101,116,61,34,95,99,97,114,114,105,101,100,32,111,117, +116,83,111,109,101,32,111,102,32,116,104,101,115,99,105,101,110,99,101,32,97,110 +,100,116,104,101,32,116,105,109,101,32,111,102,67,111,110,116,97,105,110,101,114 +,34,62,109,97,105,110,116,97,105,110,105,110,103,67,104,114,105,115,116,111,112, +104,101,114,77,117,99,104,32,111,102,32,116,104,101,119,114,105,116,105,110,103, +115,32,111,102,34,32,104,101,105,103,104,116,61,34,50,115,105,122,101,32,111,102 +,32,116,104,101,118,101,114,115,105,111,110,32,111,102,32,109,105,120,116,117, +114,101,32,111,102,32,98,101,116,119,101,101,110,32,116,104,101,69,120,97,109, +112,108,101,115,32,111,102,101,100,117,99,97,116,105,111,110,97,108,99,111,109, +112,101,116,105,116,105,118,101,32,111,110,115,117,98,109,105,116,61,34,100,105, +114,101,99,116,111,114,32,111,102,100,105,115,116,105,110,99,116,105,118,101,47, +68,84,68,32,88,72,84,77,76,32,114,101,108,97,116,105,110,103,32,116,111,116,101, +110,100,101,110,99,121,32,116,111,112,114,111,118,105,110,99,101,32,111,102,119, +104,105,99,104,32,119,111,117,108,100,100,101,115,112,105,116,101,32,116,104,101 +,115,99,105,101,110,116,105,102,105,99,32,108,101,103,105,115,108,97,116,117,114 +,101,46,105,110,110,101,114,72,84,77,76,32,97,108,108,101,103,97,116,105,111,110 +,115,65,103,114,105,99,117,108,116,117,114,101,119,97,115,32,117,115,101,100,32, +105,110,97,112,112,114,111,97,99,104,32,116,111,105,110,116,101,108,108,105,103, +101,110,116,121,101,97,114,115,32,108,97,116,101,114,44,115,97,110,115,45,115, +101,114,105,102,100,101,116,101,114,109,105,110,105,110,103,80,101,114,102,111, +114,109,97,110,99,101,97,112,112,101,97,114,97,110,99,101,115,44,32,119,104,105, +99,104,32,105,115,32,102,111,117,110,100,97,116,105,111,110,115,97,98,98,114,101 +,118,105,97,116,101,100,104,105,103,104,101,114,32,116,104,97,110,115,32,102,114 +,111,109,32,116,104,101,32,105,110,100,105,118,105,100,117,97,108,32,99,111,109, +112,111,115,101,100,32,111,102,115,117,112,112,111,115,101,100,32,116,111,99,108 +,97,105,109,115,32,116,104,97,116,97,116,116,114,105,98,117,116,105,111,110,102, +111,110,116,45,115,105,122,101,58,49,101,108,101,109,101,110,116,115,32,111,102, +72,105,115,116,111,114,105,99,97,108,32,104,105,115,32,98,114,111,116,104,101, +114,97,116,32,116,104,101,32,116,105,109,101,97,110,110,105,118,101,114,115,97, +114,121,103,111,118,101,114,110,101,100,32,98,121,114,101,108,97,116,101,100,32, +116,111,32,117,108,116,105,109,97,116,101,108,121,32,105,110,110,111,118,97,116, +105,111,110,115,105,116,32,105,115,32,115,116,105,108,108,99,97,110,32,111,110, +108,121,32,98,101,100,101,102,105,110,105,116,105,111,110,115,116,111,71,77,84, +83,116,114,105,110,103,65,32,110,117,109,98,101,114,32,111,102,105,109,103,32,99 +,108,97,115,115,61,34,69,118,101,110,116,117,97,108,108,121,44,119,97,115,32,99, +104,97,110,103,101,100,111,99,99,117,114,114,101,100,32,105,110,110,101,105,103, +104,98,111,114,105,110,103,100,105,115,116,105,110,103,117,105,115,104,119,104, +101,110,32,104,101,32,119,97,115,105,110,116,114,111,100,117,99,105,110,103,116, +101,114,114,101,115,116,114,105,97,108,77,97,110,121,32,111,102,32,116,104,101, +97,114,103,117,101,115,32,116,104,97,116,97,110,32,65,109,101,114,105,99,97,110, +99,111,110,113,117,101,115,116,32,111,102,119,105,100,101,115,112,114,101,97,100 +,32,119,101,114,101,32,107,105,108,108,101,100,115,99,114,101,101,110,32,97,110, +100,32,73,110,32,111,114,100,101,114,32,116,111,101,120,112,101,99,116,101,100, +32,116,111,100,101,115,99,101,110,100,97,110,116,115,97,114,101,32,108,111,99,97 +,116,101,100,108,101,103,105,115,108,97,116,105,118,101,103,101,110,101,114,97, +116,105,111,110,115,32,98,97,99,107,103,114,111,117,110,100,109,111,115,116,32, +112,101,111,112,108,101,121,101,97,114,115,32,97,102,116,101,114,116,104,101,114 +,101,32,105,115,32,110,111,116,104,101,32,104,105,103,104,101,115,116,102,114, +101,113,117,101,110,116,108,121,32,116,104,101,121,32,100,111,32,110,111,116,97, +114,103,117,101,100,32,116,104,97,116,115,104,111,119,101,100,32,116,104,97,116, +112,114,101,100,111,109,105,110,97,110,116,116,104,101,111,108,111,103,105,99,97 +,108,98,121,32,116,104,101,32,116,105,109,101,99,111,110,115,105,100,101,114,105 +,110,103,115,104,111,114,116,45,108,105,118,101,100,60,47,115,112,97,110,62,60, +47,97,62,99,97,110,32,98,101,32,117,115,101,100,118,101,114,121,32,108,105,116, +116,108,101,111,110,101,32,111,102,32,116,104,101,32,104,97,100,32,97,108,114, +101,97,100,121,105,110,116,101,114,112,114,101,116,101,100,99,111,109,109,117, +110,105,99,97,116,101,102,101,97,116,117,114,101,115,32,111,102,103,111,118,101, +114,110,109,101,110,116,44,60,47,110,111,115,99,114,105,112,116,62,101,110,116, +101,114,101,100,32,116,104,101,34,32,104,101,105,103,104,116,61,34,51,73,110,100 +,101,112,101,110,100,101,110,116,112,111,112,117,108,97,116,105,111,110,115,108, +97,114,103,101,45,115,99,97,108,101,46,32,65,108,116,104,111,117,103,104,32,117, +115,101,100,32,105,110,32,116,104,101,100,101,115,116,114,117,99,116,105,111,110 +,112,111,115,115,105,98,105,108,105,116,121,115,116,97,114,116,105,110,103,32, +105,110,116,119,111,32,111,114,32,109,111,114,101,101,120,112,114,101,115,115, +105,111,110,115,115,117,98,111,114,100,105,110,97,116,101,108,97,114,103,101,114 +,32,116,104,97,110,104,105,115,116,111,114,121,32,97,110,100,60,47,111,112,116, +105,111,110,62,13,10,67,111,110,116,105,110,101,110,116,97,108,101,108,105,109, +105,110,97,116,105,110,103,119,105,108,108,32,110,111,116,32,98,101,112,114,97, +99,116,105,99,101,32,111,102,105,110,32,102,114,111,110,116,32,111,102,115,105, +116,101,32,111,102,32,116,104,101,101,110,115,117,114,101,32,116,104,97,116,116, +111,32,99,114,101,97,116,101,32,97,109,105,115,115,105,115,115,105,112,112,105, +112,111,116,101,110,116,105,97,108,108,121,111,117,116,115,116,97,110,100,105, +110,103,98,101,116,116,101,114,32,116,104,97,110,119,104,97,116,32,105,115,32, +110,111,119,115,105,116,117,97,116,101,100,32,105,110,109,101,116,97,32,110,97, +109,101,61,34,84,114,97,100,105,116,105,111,110,97,108,115,117,103,103,101,115, +116,105,111,110,115,84,114,97,110,115,108,97,116,105,111,110,116,104,101,32,102, +111,114,109,32,111,102,97,116,109,111,115,112,104,101,114,105,99,105,100,101,111 +,108,111,103,105,99,97,108,101,110,116,101,114,112,114,105,115,101,115,99,97,108 +,99,117,108,97,116,105,110,103,101,97,115,116,32,111,102,32,116,104,101,114,101, +109,110,97,110,116,115,32,111,102,112,108,117,103,105,110,115,112,97,103,101,47, +105,110,100,101,120,46,112,104,112,63,114,101,109,97,105,110,101,100,32,105,110, +116,114,97,110,115,102,111,114,109,101,100,72,101,32,119,97,115,32,97,108,115, +111,119,97,115,32,97,108,114,101,97,100,121,115,116,97,116,105,115,116,105,99,97 +,108,105,110,32,102,97,118,111,114,32,111,102,77,105,110,105,115,116,114,121,32, +111,102,109,111,118,101,109,101,110,116,32,111,102,102,111,114,109,117,108,97, +116,105,111,110,105,115,32,114,101,113,117,105,114,101,100,60,108,105,110,107,32 +,114,101,108,61,34,84,104,105,115,32,105,115,32,116,104,101,32,60,97,32,104,114, +101,102,61,34,47,112,111,112,117,108,97,114,105,122,101,100,105,110,118,111,108, +118,101,100,32,105,110,97,114,101,32,117,115,101,100,32,116,111,97,110,100,32, +115,101,118,101,114,97,108,109,97,100,101,32,98,121,32,116,104,101,115,101,101, +109,115,32,116,111,32,98,101,108,105,107,101,108,121,32,116,104,97,116,80,97,108 +,101,115,116,105,110,105,97,110,110,97,109,101,100,32,97,102,116,101,114,105,116 +,32,104,97,100,32,98,101,101,110,109,111,115,116,32,99,111,109,109,111,110,116, +111,32,114,101,102,101,114,32,116,111,98,117,116,32,116,104,105,115,32,105,115, +99,111,110,115,101,99,117,116,105,118,101,116,101,109,112,111,114,97,114,105,108 +,121,73,110,32,103,101,110,101,114,97,108,44,99,111,110,118,101,110,116,105,111, +110,115,116,97,107,101,115,32,112,108,97,99,101,115,117,98,100,105,118,105,115, +105,111,110,116,101,114,114,105,116,111,114,105,97,108,111,112,101,114,97,116, +105,111,110,97,108,112,101,114,109,97,110,101,110,116,108,121,119,97,115,32,108, +97,114,103,101,108,121,111,117,116,98,114,101,97,107,32,111,102,105,110,32,116, +104,101,32,112,97,115,116,102,111,108,108,111,119,105,110,103,32,97,32,120,109, +108,110,115,58,111,103,61,34,62,60,97,32,99,108,97,115,115,61,34,99,108,97,115, +115,61,34,116,101,120,116,67,111,110,118,101,114,115,105,111,110,32,109,97,121, +32,98,101,32,117,115,101,100,109,97,110,117,102,97,99,116,117,114,101,97,102,116 +,101,114,32,98,101,105,110,103,99,108,101,97,114,102,105,120,34,62,10,113,117, +101,115,116,105,111,110,32,111,102,119,97,115,32,101,108,101,99,116,101,100,116, +111,32,98,101,99,111,109,101,32,97,98,101,99,97,117,115,101,32,111,102,32,115, +111,109,101,32,112,101,111,112,108,101,105,110,115,112,105,114,101,100,32,98,121 +,115,117,99,99,101,115,115,102,117,108,32,97,32,116,105,109,101,32,119,104,101, +110,109,111,114,101,32,99,111,109,109,111,110,97,109,111,110,103,115,116,32,116, +104,101,97,110,32,111,102,102,105,99,105,97,108,119,105,100,116,104,58,49,48,48, +37,59,116,101,99,104,110,111,108,111,103,121,44,119,97,115,32,97,100,111,112,116 +,101,100,116,111,32,107,101,101,112,32,116,104,101,115,101,116,116,108,101,109, +101,110,116,115,108,105,118,101,32,98,105,114,116,104,115,105,110,100,101,120,46 +,104,116,109,108,34,67,111,110,110,101,99,116,105,99,117,116,97,115,115,105,103, +110,101,100,32,116,111,38,97,109,112,59,116,105,109,101,115,59,97,99,99,111,117, +110,116,32,102,111,114,97,108,105,103,110,61,114,105,103,104,116,116,104,101,32, +99,111,109,112,97,110,121,97,108,119,97,121,115,32,98,101,101,110,114,101,116, +117,114,110,101,100,32,116,111,105,110,118,111,108,118,101,109,101,110,116,66, +101,99,97,117,115,101,32,116,104,101,116,104,105,115,32,112,101,114,105,111,100, +34,32,110,97,109,101,61,34,113,34,32,99,111,110,102,105,110,101,100,32,116,111, +97,32,114,101,115,117,108,116,32,111,102,118,97,108,117,101,61,34,34,32,47,62, +105,115,32,97,99,116,117,97,108,108,121,69,110,118,105,114,111,110,109,101,110, +116,13,10,60,47,104,101,97,100,62,13,10,67,111,110,118,101,114,115,101,108,121, +44,62,10,60,100,105,118,32,105,100,61,34,48,34,32,119,105,100,116,104,61,34,49, +105,115,32,112,114,111,98,97,98,108,121,104,97,118,101,32,98,101,99,111,109,101, +99,111,110,116,114,111,108,108,105,110,103,116,104,101,32,112,114,111,98,108,101 +,109,99,105,116,105,122,101,110,115,32,111,102,112,111,108,105,116,105,99,105,97 +,110,115,114,101,97,99,104,101,100,32,116,104,101,97,115,32,101,97,114,108,121, +32,97,115,58,110,111,110,101,59,32,111,118,101,114,60,116,97,98,108,101,32,99, +101,108,108,118,97,108,105,100,105,116,121,32,111,102,100,105,114,101,99,116,108 +,121,32,116,111,111,110,109,111,117,115,101,100,111,119,110,119,104,101,114,101, +32,105,116,32,105,115,119,104,101,110,32,105,116,32,119,97,115,109,101,109,98, +101,114,115,32,111,102,32,114,101,108,97,116,105,111,110,32,116,111,97,99,99,111 +,109,109,111,100,97,116,101,97,108,111,110,103,32,119,105,116,104,32,73,110,32, +116,104,101,32,108,97,116,101,116,104,101,32,69,110,103,108,105,115,104,100,101, +108,105,99,105,111,117,115,34,62,116,104,105,115,32,105,115,32,110,111,116,116, +104,101,32,112,114,101,115,101,110,116,105,102,32,116,104,101,121,32,97,114,101, +97,110,100,32,102,105,110,97,108,108,121,97,32,109,97,116,116,101,114,32,111,102 +,13,10,9,60,47,100,105,118,62,13,10,13,10,60,47,115,99,114,105,112,116,62,102,97 +,115,116,101,114,32,116,104,97,110,109,97,106,111,114,105,116,121,32,111,102,97, +102,116,101,114,32,119,104,105,99,104,99,111,109,112,97,114,97,116,105,118,101, +116,111,32,109,97,105,110,116,97,105,110,105,109,112,114,111,118,101,32,116,104, +101,97,119,97,114,100,101,100,32,116,104,101,101,114,34,32,99,108,97,115,115,61, +34,102,114,97,109,101,98,111,114,100,101,114,114,101,115,116,111,114,97,116,105, +111,110,105,110,32,116,104,101,32,115,97,109,101,97,110,97,108,121,115,105,115, +32,111,102,116,104,101,105,114,32,102,105,114,115,116,68,117,114,105,110,103,32, +116,104,101,32,99,111,110,116,105,110,101,110,116,97,108,115,101,113,117,101,110 +,99,101,32,111,102,102,117,110,99,116,105,111,110,40,41,123,102,111,110,116,45, +115,105,122,101,58,32,119,111,114,107,32,111,110,32,116,104,101,60,47,115,99,114 +,105,112,116,62,10,60,98,101,103,105,110,115,32,119,105,116,104,106,97,118,97, +115,99,114,105,112,116,58,99,111,110,115,116,105,116,117,101,110,116,119,97,115, +32,102,111,117,110,100,101,100,101,113,117,105,108,105,98,114,105,117,109,97,115 +,115,117,109,101,32,116,104,97,116,105,115,32,103,105,118,101,110,32,98,121,110, +101,101,100,115,32,116,111,32,98,101,99,111,111,114,100,105,110,97,116,101,115, +116,104,101,32,118,97,114,105,111,117,115,97,114,101,32,112,97,114,116,32,111, +102,111,110,108,121,32,105,110,32,116,104,101,115,101,99,116,105,111,110,115,32, +111,102,105,115,32,97,32,99,111,109,109,111,110,116,104,101,111,114,105,101,115, +32,111,102,100,105,115,99,111,118,101,114,105,101,115,97,115,115,111,99,105,97, +116,105,111,110,101,100,103,101,32,111,102,32,116,104,101,115,116,114,101,110, +103,116,104,32,111,102,112,111,115,105,116,105,111,110,32,105,110,112,114,101, +115,101,110,116,45,100,97,121,117,110,105,118,101,114,115,97,108,108,121,116,111 +,32,102,111,114,109,32,116,104,101,98,117,116,32,105,110,115,116,101,97,100,99, +111,114,112,111,114,97,116,105,111,110,97,116,116,97,99,104,101,100,32,116,111, +105,115,32,99,111,109,109,111,110,108,121,114,101,97,115,111,110,115,32,102,111, +114,32,38,113,117,111,116,59,116,104,101,32,99,97,110,32,98,101,32,109,97,100, +101,119,97,115,32,97,98,108,101,32,116,111,119,104,105,99,104,32,109,101,97,110, +115,98,117,116,32,100,105,100,32,110,111,116,111,110,77,111,117,115,101,79,118, +101,114,97,115,32,112,111,115,115,105,98,108,101,111,112,101,114,97,116,101,100, +32,98,121,99,111,109,105,110,103,32,102,114,111,109,116,104,101,32,112,114,105, +109,97,114,121,97,100,100,105,116,105,111,110,32,111,102,102,111,114,32,115,101, +118,101,114,97,108,116,114,97,110,115,102,101,114,114,101,100,97,32,112,101,114, +105,111,100,32,111,102,97,114,101,32,97,98,108,101,32,116,111,104,111,119,101, +118,101,114,44,32,105,116,115,104,111,117,108,100,32,104,97,118,101,109,117,99, +104,32,108,97,114,103,101,114,10,9,60,47,115,99,114,105,112,116,62,97,100,111, +112,116,101,100,32,116,104,101,112,114,111,112,101,114,116,121,32,111,102,100, +105,114,101,99,116,101,100,32,98,121,101,102,102,101,99,116,105,118,101,108,121, +119,97,115,32,98,114,111,117,103,104,116,99,104,105,108,100,114,101,110,32,111, +102,80,114,111,103,114,97,109,109,105,110,103,108,111,110,103,101,114,32,116,104 +,97,110,109,97,110,117,115,99,114,105,112,116,115,119,97,114,32,97,103,97,105, +110,115,116,98,121,32,109,101,97,110,115,32,111,102,97,110,100,32,109,111,115, +116,32,111,102,115,105,109,105,108,97,114,32,116,111,32,112,114,111,112,114,105, +101,116,97,114,121,111,114,105,103,105,110,97,116,105,110,103,112,114,101,115, +116,105,103,105,111,117,115,103,114,97,109,109,97,116,105,99,97,108,101,120,112, +101,114,105,101,110,99,101,46,116,111,32,109,97,107,101,32,116,104,101,73,116,32 +,119,97,115,32,97,108,115,111,105,115,32,102,111,117,110,100,32,105,110,99,111, +109,112,101,116,105,116,111,114,115,105,110,32,116,104,101,32,85,46,83,46,114, +101,112,108,97,99,101,32,116,104,101,98,114,111,117,103,104,116,32,116,104,101, +99,97,108,99,117,108,97,116,105,111,110,102,97,108,108,32,111,102,32,116,104,101 +,116,104,101,32,103,101,110,101,114,97,108,112,114,97,99,116,105,99,97,108,108, +121,105,110,32,104,111,110,111,114,32,111,102,114,101,108,101,97,115,101,100,32, +105,110,114,101,115,105,100,101,110,116,105,97,108,97,110,100,32,115,111,109,101 +,32,111,102,107,105,110,103,32,111,102,32,116,104,101,114,101,97,99,116,105,111, +110,32,116,111,49,115,116,32,69,97,114,108,32,111,102,99,117,108,116,117,114,101 +,32,97,110,100,112,114,105,110,99,105,112,97,108,108,121,60,47,116,105,116,108, +101,62,10,32,32,116,104,101,121,32,99,97,110,32,98,101,98,97,99,107,32,116,111, +32,116,104,101,115,111,109,101,32,111,102,32,104,105,115,101,120,112,111,115,117 +,114,101,32,116,111,97,114,101,32,115,105,109,105,108,97,114,102,111,114,109,32, +111,102,32,116,104,101,97,100,100,70,97,118,111,114,105,116,101,99,105,116,105, +122,101,110,115,104,105,112,112,97,114,116,32,105,110,32,116,104,101,112,101,111 +,112,108,101,32,119,105,116,104,105,110,32,112,114,97,99,116,105,99,101,116,111, +32,99,111,110,116,105,110,117,101,38,97,109,112,59,109,105,110,117,115,59,97,112 +,112,114,111,118,101,100,32,98,121,32,116,104,101,32,102,105,114,115,116,32,97, +108,108,111,119,101,100,32,116,104,101,97,110,100,32,102,111,114,32,116,104,101, +102,117,110,99,116,105,111,110,105,110,103,112,108,97,121,105,110,103,32,116,104 +,101,115,111,108,117,116,105,111,110,32,116,111,104,101,105,103,104,116,61,34,48 +,34,32,105,110,32,104,105,115,32,98,111,111,107,109,111,114,101,32,116,104,97, +110,32,97,102,111,108,108,111,119,115,32,116,104,101,99,114,101,97,116,101,100, +32,116,104,101,112,114,101,115,101,110,99,101,32,105,110,38,110,98,115,112,59,60 +,47,116,100,62,110,97,116,105,111,110,97,108,105,115,116,116,104,101,32,105,100, +101,97,32,111,102,97,32,99,104,97,114,97,99,116,101,114,119,101,114,101,32,102, +111,114,99,101,100,32,99,108,97,115,115,61,34,98,116,110,100,97,121,115,32,111, +102,32,116,104,101,102,101,97,116,117,114,101,100,32,105,110,115,104,111,119,105 +,110,103,32,116,104,101,105,110,116,101,114,101,115,116,32,105,110,105,110,32, +112,108,97,99,101,32,111,102,116,117,114,110,32,111,102,32,116,104,101,116,104, +101,32,104,101,97,100,32,111,102,76,111,114,100,32,111,102,32,116,104,101,112, +111,108,105,116,105,99,97,108,108,121,104,97,115,32,105,116,115,32,111,119,110, +69,100,117,99,97,116,105,111,110,97,108,97,112,112,114,111,118,97,108,32,111,102 +,115,111,109,101,32,111,102,32,116,104,101,101,97,99,104,32,111,116,104,101,114, +44,98,101,104,97,118,105,111,114,32,111,102,97,110,100,32,98,101,99,97,117,115, +101,97,110,100,32,97,110,111,116,104,101,114,97,112,112,101,97,114,101,100,32, +111,110,114,101,99,111,114,100,101,100,32,105,110,98,108,97,99,107,38,113,117, +111,116,59,109,97,121,32,105,110,99,108,117,100,101,116,104,101,32,119,111,114, +108,100,39,115,99,97,110,32,108,101,97,100,32,116,111,114,101,102,101,114,115,32 +,116,111,32,97,98,111,114,100,101,114,61,34,48,34,32,103,111,118,101,114,110,109 +,101,110,116,32,119,105,110,110,105,110,103,32,116,104,101,114,101,115,117,108, +116,101,100,32,105,110,32,119,104,105,108,101,32,116,104,101,32,87,97,115,104, +105,110,103,116,111,110,44,116,104,101,32,115,117,98,106,101,99,116,99,105,116, +121,32,105,110,32,116,104,101,62,60,47,100,105,118,62,13,10,9,9,114,101,102,108, +101,99,116,32,116,104,101,116,111,32,99,111,109,112,108,101,116,101,98,101,99,97 +,109,101,32,109,111,114,101,114,97,100,105,111,97,99,116,105,118,101,114,101,106 +,101,99,116,101,100,32,98,121,119,105,116,104,111,117,116,32,97,110,121,104,105, +115,32,102,97,116,104,101,114,44,119,104,105,99,104,32,99,111,117,108,100,99,111 +,112,121,32,111,102,32,116,104,101,116,111,32,105,110,100,105,99,97,116,101,97, +32,112,111,108,105,116,105,99,97,108,97,99,99,111,117,110,116,115,32,111,102,99, +111,110,115,116,105,116,117,116,101,115,119,111,114,107,101,100,32,119,105,116, +104,101,114,60,47,97,62,60,47,108,105,62,111,102,32,104,105,115,32,108,105,102, +101,97,99,99,111,109,112,97,110,105,101,100,99,108,105,101,110,116,87,105,100, +116,104,112,114,101,118,101,110,116,32,116,104,101,76,101,103,105,115,108,97,116 +,105,118,101,100,105,102,102,101,114,101,110,116,108,121,116,111,103,101,116,104 +,101,114,32,105,110,104,97,115,32,115,101,118,101,114,97,108,102,111,114,32,97, +110,111,116,104,101,114,116,101,120,116,32,111,102,32,116,104,101,102,111,117, +110,100,101,100,32,116,104,101,101,32,119,105,116,104,32,116,104,101,32,105,115, +32,117,115,101,100,32,102,111,114,99,104,97,110,103,101,100,32,116,104,101,117, +115,117,97,108,108,121,32,116,104,101,112,108,97,99,101,32,119,104,101,114,101, +119,104,101,114,101,97,115,32,116,104,101,62,32,60,97,32,104,114,101,102,61,34, +34,62,60,97,32,104,114,101,102,61,34,116,104,101,109,115,101,108,118,101,115,44, +97,108,116,104,111,117,103,104,32,104,101,116,104,97,116,32,99,97,110,32,98,101, +116,114,97,100,105,116,105,111,110,97,108,114,111,108,101,32,111,102,32,116,104, +101,97,115,32,97,32,114,101,115,117,108,116,114,101,109,111,118,101,67,104,105, +108,100,100,101,115,105,103,110,101,100,32,98,121,119,101,115,116,32,111,102,32, +116,104,101,83,111,109,101,32,112,101,111,112,108,101,112,114,111,100,117,99,116 +,105,111,110,44,115,105,100,101,32,111,102,32,116,104,101,110,101,119,115,108, +101,116,116,101,114,115,117,115,101,100,32,98,121,32,116,104,101,100,111,119,110 +,32,116,111,32,116,104,101,97,99,99,101,112,116,101,100,32,98,121,108,105,118, +101,32,105,110,32,116,104,101,97,116,116,101,109,112,116,115,32,116,111,111,117, +116,115,105,100,101,32,116,104,101,102,114,101,113,117,101,110,99,105,101,115,72 +,111,119,101,118,101,114,44,32,105,110,112,114,111,103,114,97,109,109,101,114, +115,97,116,32,108,101,97,115,116,32,105,110,97,112,112,114,111,120,105,109,97, +116,101,97,108,116,104,111,117,103,104,32,105,116,119,97,115,32,112,97,114,116, +32,111,102,97,110,100,32,118,97,114,105,111,117,115,71,111,118,101,114,110,111, +114,32,111,102,116,104,101,32,97,114,116,105,99,108,101,116,117,114,110,101,100, +32,105,110,116,111,62,60,97,32,104,114,101,102,61,34,47,116,104,101,32,101,99, +111,110,111,109,121,105,115,32,116,104,101,32,109,111,115,116,109,111,115,116,32 +,119,105,100,101,108,121,119,111,117,108,100,32,108,97,116,101,114,97,110,100,32 +,112,101,114,104,97,112,115,114,105,115,101,32,116,111,32,116,104,101,111,99,99, +117,114,115,32,119,104,101,110,117,110,100,101,114,32,119,104,105,99,104,99,111, +110,100,105,116,105,111,110,115,46,116,104,101,32,119,101,115,116,101,114,110, +116,104,101,111,114,121,32,116,104,97,116,105,115,32,112,114,111,100,117,99,101, +100,116,104,101,32,99,105,116,121,32,111,102,105,110,32,119,104,105,99,104,32, +104,101,115,101,101,110,32,105,110,32,116,104,101,116,104,101,32,99,101,110,116, +114,97,108,98,117,105,108,100,105,110,103,32,111,102,109,97,110,121,32,111,102, +32,104,105,115,97,114,101,97,32,111,102,32,116,104,101,105,115,32,116,104,101,32 +,111,110,108,121,109,111,115,116,32,111,102,32,116,104,101,109,97,110,121,32,111 +,102,32,116,104,101,116,104,101,32,87,101,115,116,101,114,110,84,104,101,114,101 +,32,105,115,32,110,111,101,120,116,101,110,100,101,100,32,116,111,83,116,97,116, +105,115,116,105,99,97,108,99,111,108,115,112,97,110,61,50,32,124,115,104,111,114 +,116,32,115,116,111,114,121,112,111,115,115,105,98,108,101,32,116,111,116,111, +112,111,108,111,103,105,99,97,108,99,114,105,116,105,99,97,108,32,111,102,114, +101,112,111,114,116,101,100,32,116,111,97,32,67,104,114,105,115,116,105,97,110, +100,101,99,105,115,105,111,110,32,116,111,105,115,32,101,113,117,97,108,32,116, +111,112,114,111,98,108,101,109,115,32,111,102,84,104,105,115,32,99,97,110,32,98, +101,109,101,114,99,104,97,110,100,105,115,101,102,111,114,32,109,111,115,116,32, +111,102,110,111,32,101,118,105,100,101,110,99,101,101,100,105,116,105,111,110, +115,32,111,102,101,108,101,109,101,110,116,115,32,105,110,38,113,117,111,116,59, +46,32,84,104,101,99,111,109,47,105,109,97,103,101,115,47,119,104,105,99,104,32, +109,97,107,101,115,116,104,101,32,112,114,111,99,101,115,115,114,101,109,97,105, +110,115,32,116,104,101,108,105,116,101,114,97,116,117,114,101,44,105,115,32,97, +32,109,101,109,98,101,114,116,104,101,32,112,111,112,117,108,97,114,116,104,101, +32,97,110,99,105,101,110,116,112,114,111,98,108,101,109,115,32,105,110,116,105, +109,101,32,111,102,32,116,104,101,100,101,102,101,97,116,101,100,32,98,121,98, +111,100,121,32,111,102,32,116,104,101,97,32,102,101,119,32,121,101,97,114,115, +109,117,99,104,32,111,102,32,116,104,101,116,104,101,32,119,111,114,107,32,111, +102,67,97,108,105,102,111,114,110,105,97,44,115,101,114,118,101,100,32,97,115,32 +,97,103,111,118,101,114,110,109,101,110,116,46,99,111,110,99,101,112,116,115,32, +111,102,109,111,118,101,109,101,110,116,32,105,110,9,9,60,100,105,118,32,105,100 +,61,34,105,116,34,32,118,97,108,117,101,61,34,108,97,110,103,117,97,103,101,32, +111,102,97,115,32,116,104,101,121,32,97,114,101,112,114,111,100,117,99,101,100, +32,105,110,105,115,32,116,104,97,116,32,116,104,101,101,120,112,108,97,105,110, +32,116,104,101,100,105,118,62,60,47,100,105,118,62,10,72,111,119,101,118,101,114 +,32,116,104,101,108,101,97,100,32,116,111,32,116,104,101,9,60,97,32,104,114,101, +102,61,34,47,119,97,115,32,103,114,97,110,116,101,100,112,101,111,112,108,101,32 +,104,97,118,101,99,111,110,116,105,110,117,97,108,108,121,119,97,115,32,115,101, +101,110,32,97,115,97,110,100,32,114,101,108,97,116,101,100,116,104,101,32,114, +111,108,101,32,111,102,112,114,111,112,111,115,101,100,32,98,121,111,102,32,116, +104,101,32,98,101,115,116,101,97,99,104,32,111,116,104,101,114,46,67,111,110,115 +,116,97,110,116,105,110,101,112,101,111,112,108,101,32,102,114,111,109,100,105, +97,108,101,99,116,115,32,111,102,116,111,32,114,101,118,105,115,105,111,110,119, +97,115,32,114,101,110,97,109,101,100,97,32,115,111,117,114,99,101,32,111,102,116 +,104,101,32,105,110,105,116,105,97,108,108,97,117,110,99,104,101,100,32,105,110, +112,114,111,118,105,100,101,32,116,104,101,116,111,32,116,104,101,32,119,101,115 +,116,119,104,101,114,101,32,116,104,101,114,101,97,110,100,32,115,105,109,105, +108,97,114,98,101,116,119,101,101,110,32,116,119,111,105,115,32,97,108,115,111, +32,116,104,101,69,110,103,108,105,115,104,32,97,110,100,99,111,110,100,105,116, +105,111,110,115,44,116,104,97,116,32,105,116,32,119,97,115,101,110,116,105,116, +108,101,100,32,116,111,116,104,101,109,115,101,108,118,101,115,46,113,117,97,110 +,116,105,116,121,32,111,102,114,97,110,115,112,97,114,101,110,99,121,116,104,101 +,32,115,97,109,101,32,97,115,116,111,32,106,111,105,110,32,116,104,101,99,111, +117,110,116,114,121,32,97,110,100,116,104,105,115,32,105,115,32,116,104,101,84, +104,105,115,32,108,101,100,32,116,111,97,32,115,116,97,116,101,109,101,110,116, +99,111,110,116,114,97,115,116,32,116,111,108,97,115,116,73,110,100,101,120,79, +102,116,104,114,111,117,103,104,32,104,105,115,105,115,32,100,101,115,105,103, +110,101,100,116,104,101,32,116,101,114,109,32,105,115,105,115,32,112,114,111,118 +,105,100,101,100,112,114,111,116,101,99,116,32,116,104,101,110,103,60,47,97,62, +60,47,108,105,62,84,104,101,32,99,117,114,114,101,110,116,116,104,101,32,115,105 +,116,101,32,111,102,115,117,98,115,116,97,110,116,105,97,108,101,120,112,101,114 +,105,101,110,99,101,44,105,110,32,116,104,101,32,87,101,115,116,116,104,101,121, +32,115,104,111,117,108,100,115,108,111,118,101,110,196,141,105,110,97,99,111,109 +,101,110,116,97,114,105,111,115,117,110,105,118,101,114,115,105,100,97,100,99, +111,110,100,105,99,105,111,110,101,115,97,99,116,105,118,105,100,97,100,101,115, +101,120,112,101,114,105,101,110,99,105,97,116,101,99,110,111,108,111,103,195,173 +,97,112,114,111,100,117,99,99,105,195,179,110,112,117,110,116,117,97,99,105,195, +179,110,97,112,108,105,99,97,99,105,195,179,110,99,111,110,116,114,97,115,101, +195,177,97,99,97,116,101,103,111,114,195,173,97,115,114,101,103,105,115,116,114, +97,114,115,101,112,114,111,102,101,115,105,111,110,97,108,116,114,97,116,97,109, +105,101,110,116,111,114,101,103,195,173,115,116,114,97,116,101,115,101,99,114, +101,116,97,114,195,173,97,112,114,105,110,99,105,112,97,108,101,115,112,114,111, +116,101,99,99,105,195,179,110,105,109,112,111,114,116,97,110,116,101,115,105,109 +,112,111,114,116,97,110,99,105,97,112,111,115,105,98,105,108,105,100,97,100,105, +110,116,101,114,101,115,97,110,116,101,99,114,101,99,105,109,105,101,110,116,111 +,110,101,99,101,115,105,100,97,100,101,115,115,117,115,99,114,105,98,105,114,115 +,101,97,115,111,99,105,97,99,105,195,179,110,100,105,115,112,111,110,105,98,108, +101,115,101,118,97,108,117,97,99,105,195,179,110,101,115,116,117,100,105,97,110, +116,101,115,114,101,115,112,111,110,115,97,98,108,101,114,101,115,111,108,117,99 +,105,195,179,110,103,117,97,100,97,108,97,106,97,114,97,114,101,103,105,115,116, +114,97,100,111,115,111,112,111,114,116,117,110,105,100,97,100,99,111,109,101,114 +,99,105,97,108,101,115,102,111,116,111,103,114,97,102,195,173,97,97,117,116,111, +114,105,100,97,100,101,115,105,110,103,101,110,105,101,114,195,173,97,116,101, +108,101,118,105,115,105,195,179,110,99,111,109,112,101,116,101,110,99,105,97,111 +,112,101,114,97,99,105,111,110,101,115,101,115,116,97,98,108,101,99,105,100,111, +115,105,109,112,108,101,109,101,110,116,101,97,99,116,117,97,108,109,101,110,116 +,101,110,97,118,101,103,97,99,105,195,179,110,99,111,110,102,111,114,109,105,100 +,97,100,108,105,110,101,45,104,101,105,103,104,116,58,102,111,110,116,45,102,97, +109,105,108,121,58,34,32,58,32,34,104,116,116,112,58,47,47,97,112,112,108,105,99 +,97,116,105,111,110,115,108,105,110,107,34,32,104,114,101,102,61,34,115,112,101, +99,105,102,105,99,97,108,108,121,47,47,60,33,91,67,68,65,84,65,91,10,79,114,103, +97,110,105,122,97,116,105,111,110,100,105,115,116,114,105,98,117,116,105,111,110 +,48,112,120,59,32,104,101,105,103,104,116,58,114,101,108,97,116,105,111,110,115, +104,105,112,100,101,118,105,99,101,45,119,105,100,116,104,60,100,105,118,32,99, +108,97,115,115,61,34,60,108,97,98,101,108,32,102,111,114,61,34,114,101,103,105, +115,116,114,97,116,105,111,110,60,47,110,111,115,99,114,105,112,116,62,10,47,105 +,110,100,101,120,46,104,116,109,108,34,119,105,110,100,111,119,46,111,112,101, +110,40,32,33,105,109,112,111,114,116,97,110,116,59,97,112,112,108,105,99,97,116, +105,111,110,47,105,110,100,101,112,101,110,100,101,110,99,101,47,47,119,119,119, +46,103,111,111,103,108,101,111,114,103,97,110,105,122,97,116,105,111,110,97,117, +116,111,99,111,109,112,108,101,116,101,114,101,113,117,105,114,101,109,101,110, +116,115,99,111,110,115,101,114,118,97,116,105,118,101,60,102,111,114,109,32,110, +97,109,101,61,34,105,110,116,101,108,108,101,99,116,117,97,108,109,97,114,103, +105,110,45,108,101,102,116,58,49,56,116,104,32,99,101,110,116,117,114,121,97,110 +,32,105,109,112,111,114,116,97,110,116,105,110,115,116,105,116,117,116,105,111, +110,115,97,98,98,114,101,118,105,97,116,105,111,110,60,105,109,103,32,99,108,97, +115,115,61,34,111,114,103,97,110,105,115,97,116,105,111,110,99,105,118,105,108, +105,122,97,116,105,111,110,49,57,116,104,32,99,101,110,116,117,114,121,97,114,99 +,104,105,116,101,99,116,117,114,101,105,110,99,111,114,112,111,114,97,116,101, +100,50,48,116,104,32,99,101,110,116,117,114,121,45,99,111,110,116,97,105,110,101 +,114,34,62,109,111,115,116,32,110,111,116,97,98,108,121,47,62,60,47,97,62,60,47, +100,105,118,62,110,111,116,105,102,105,99,97,116,105,111,110,39,117,110,100,101, +102,105,110,101,100,39,41,70,117,114,116,104,101,114,109,111,114,101,44,98,101, +108,105,101,118,101,32,116,104,97,116,105,110,110,101,114,72,84,77,76,32,61,32, +112,114,105,111,114,32,116,111,32,116,104,101,100,114,97,109,97,116,105,99,97, +108,108,121,114,101,102,101,114,114,105,110,103,32,116,111,110,101,103,111,116, +105,97,116,105,111,110,115,104,101,97,100,113,117,97,114,116,101,114,115,83,111, +117,116,104,32,65,102,114,105,99,97,117,110,115,117,99,99,101,115,115,102,117, +108,80,101,110,110,115,121,108,118,97,110,105,97,65,115,32,97,32,114,101,115,117 +,108,116,44,60,104,116,109,108,32,108,97,110,103,61,34,38,108,116,59,47,115,117, +112,38,103,116,59,100,101,97,108,105,110,103,32,119,105,116,104,112,104,105,108, +97,100,101,108,112,104,105,97,104,105,115,116,111,114,105,99,97,108,108,121,41, +59,60,47,115,99,114,105,112,116,62,10,112,97,100,100,105,110,103,45,116,111,112, +58,101,120,112,101,114,105,109,101,110,116,97,108,103,101,116,65,116,116,114,105 +,98,117,116,101,105,110,115,116,114,117,99,116,105,111,110,115,116,101,99,104, +110,111,108,111,103,105,101,115,112,97,114,116,32,111,102,32,116,104,101,32,61, +102,117,110,99,116,105,111,110,40,41,123,115,117,98,115,99,114,105,112,116,105, +111,110,108,46,100,116,100,34,62,13,10,60,104,116,103,101,111,103,114,97,112,104 +,105,99,97,108,67,111,110,115,116,105,116,117,116,105,111,110,39,44,32,102,117, +110,99,116,105,111,110,40,115,117,112,112,111,114,116,101,100,32,98,121,97,103, +114,105,99,117,108,116,117,114,97,108,99,111,110,115,116,114,117,99,116,105,111, +110,112,117,98,108,105,99,97,116,105,111,110,115,102,111,110,116,45,115,105,122, +101,58,32,49,97,32,118,97,114,105,101,116,121,32,111,102,60,100,105,118,32,115, +116,121,108,101,61,34,69,110,99,121,99,108,111,112,101,100,105,97,105,102,114,97 +,109,101,32,115,114,99,61,34,100,101,109,111,110,115,116,114,97,116,101,100,97, +99,99,111,109,112,108,105,115,104,101,100,117,110,105,118,101,114,115,105,116, +105,101,115,68,101,109,111,103,114,97,112,104,105,99,115,41,59,60,47,115,99,114, +105,112,116,62,60,100,101,100,105,99,97,116,101,100,32,116,111,107,110,111,119, +108,101,100,103,101,32,111,102,115,97,116,105,115,102,97,99,116,105,111,110,112, +97,114,116,105,99,117,108,97,114,108,121,60,47,100,105,118,62,60,47,100,105,118, +62,69,110,103,108,105,115,104,32,40,85,83,41,97,112,112,101,110,100,67,104,105, +108,100,40,116,114,97,110,115,109,105,115,115,105,111,110,115,46,32,72,111,119, +101,118,101,114,44,32,105,110,116,101,108,108,105,103,101,110,99,101,34,32,116, +97,98,105,110,100,101,120,61,34,102,108,111,97,116,58,114,105,103,104,116,59,67, +111,109,109,111,110,119,101,97,108,116,104,114,97,110,103,105,110,103,32,102,114 +,111,109,105,110,32,119,104,105,99,104,32,116,104,101,97,116,32,108,101,97,115, +116,32,111,110,101,114,101,112,114,111,100,117,99,116,105,111,110,101,110,99,121 +,99,108,111,112,101,100,105,97,59,102,111,110,116,45,115,105,122,101,58,49,106, +117,114,105,115,100,105,99,116,105,111,110,97,116,32,116,104,97,116,32,116,105, +109,101,34,62,60,97,32,99,108,97,115,115,61,34,73,110,32,97,100,100,105,116,105, +111,110,44,100,101,115,99,114,105,112,116,105,111,110,43,99,111,110,118,101,114, +115,97,116,105,111,110,99,111,110,116,97,99,116,32,119,105,116,104,105,115,32, +103,101,110,101,114,97,108,108,121,114,34,32,99,111,110,116,101,110,116,61,34, +114,101,112,114,101,115,101,110,116,105,110,103,38,108,116,59,109,97,116,104,38, +103,116,59,112,114,101,115,101,110,116,97,116,105,111,110,111,99,99,97,115,105, +111,110,97,108,108,121,60,105,109,103,32,119,105,100,116,104,61,34,110,97,118, +105,103,97,116,105,111,110,34,62,99,111,109,112,101,110,115,97,116,105,111,110, +99,104,97,109,112,105,111,110,115,104,105,112,109,101,100,105,97,61,34,97,108, +108,34,32,118,105,111,108,97,116,105,111,110,32,111,102,114,101,102,101,114,101, +110,99,101,32,116,111,114,101,116,117,114,110,32,116,114,117,101,59,83,116,114, +105,99,116,47,47,69,78,34,32,116,114,97,110,115,97,99,116,105,111,110,115,105, +110,116,101,114,118,101,110,116,105,111,110,118,101,114,105,102,105,99,97,116, +105,111,110,73,110,102,111,114,109,97,116,105,111,110,32,100,105,102,102,105,99, +117,108,116,105,101,115,67,104,97,109,112,105,111,110,115,104,105,112,99,97,112, +97,98,105,108,105,116,105,101,115,60,33,91,101,110,100,105,102,93,45,45,62,125, +10,60,47,115,99,114,105,112,116,62,10,67,104,114,105,115,116,105,97,110,105,116, +121,102,111,114,32,101,120,97,109,112,108,101,44,80,114,111,102,101,115,115,105, +111,110,97,108,114,101,115,116,114,105,99,116,105,111,110,115,115,117,103,103, +101,115,116,32,116,104,97,116,119,97,115,32,114,101,108,101,97,115,101,100,40, +115,117,99,104,32,97,115,32,116,104,101,114,101,109,111,118,101,67,108,97,115, +115,40,117,110,101,109,112,108,111,121,109,101,110,116,116,104,101,32,65,109,101 +,114,105,99,97,110,115,116,114,117,99,116,117,114,101,32,111,102,47,105,110,100, +101,120,46,104,116,109,108,32,112,117,98,108,105,115,104,101,100,32,105,110,115, +112,97,110,32,99,108,97,115,115,61,34,34,62,60,97,32,104,114,101,102,61,34,47, +105,110,116,114,111,100,117,99,116,105,111,110,98,101,108,111,110,103,105,110, +103,32,116,111,99,108,97,105,109,101,100,32,116,104,97,116,99,111,110,115,101, +113,117,101,110,99,101,115,60,109,101,116,97,32,110,97,109,101,61,34,71,117,105, +100,101,32,116,111,32,116,104,101,111,118,101,114,119,104,101,108,109,105,110, +103,97,103,97,105,110,115,116,32,116,104,101,32,99,111,110,99,101,110,116,114,97 +,116,101,100,44,10,46,110,111,110,116,111,117,99,104,32,111,98,115,101,114,118, +97,116,105,111,110,115,60,47,97,62,10,60,47,100,105,118,62,10,102,32,40,100,111, +99,117,109,101,110,116,46,98,111,114,100,101,114,58,32,49,112,120,32,123,102,111 +,110,116,45,115,105,122,101,58,49,116,114,101,97,116,109,101,110,116,32,111,102, +48,34,32,104,101,105,103,104,116,61,34,49,109,111,100,105,102,105,99,97,116,105, +111,110,73,110,100,101,112,101,110,100,101,110,99,101,100,105,118,105,100,101, +100,32,105,110,116,111,103,114,101,97,116,101,114,32,116,104,97,110,97,99,104, +105,101,118,101,109,101,110,116,115,101,115,116,97,98,108,105,115,104,105,110, +103,74,97,118,97,83,99,114,105,112,116,34,32,110,101,118,101,114,116,104,101,108 +,101,115,115,115,105,103,110,105,102,105,99,97,110,99,101,66,114,111,97,100,99, +97,115,116,105,110,103,62,38,110,98,115,112,59,60,47,116,100,62,99,111,110,116, +97,105,110,101,114,34,62,10,115,117,99,104,32,97,115,32,116,104,101,32,105,110, +102,108,117,101,110,99,101,32,111,102,97,32,112,97,114,116,105,99,117,108,97,114 +,115,114,99,61,39,104,116,116,112,58,47,47,110,97,118,105,103,97,116,105,111,110 +,34,32,104,97,108,102,32,111,102,32,116,104,101,32,115,117,98,115,116,97,110,116 +,105,97,108,32,38,110,98,115,112,59,60,47,100,105,118,62,97,100,118,97,110,116, +97,103,101,32,111,102,100,105,115,99,111,118,101,114,121,32,111,102,102,117,110, +100,97,109,101,110,116,97,108,32,109,101,116,114,111,112,111,108,105,116,97,110, +116,104,101,32,111,112,112,111,115,105,116,101,34,32,120,109,108,58,108,97,110, +103,61,34,100,101,108,105,98,101,114,97,116,101,108,121,97,108,105,103,110,61,99 +,101,110,116,101,114,101,118,111,108,117,116,105,111,110,32,111,102,112,114,101, +115,101,114,118,97,116,105,111,110,105,109,112,114,111,118,101,109,101,110,116, +115,98,101,103,105,110,110,105,110,103,32,105,110,74,101,115,117,115,32,67,104, +114,105,115,116,80,117,98,108,105,99,97,116,105,111,110,115,100,105,115,97,103, +114,101,101,109,101,110,116,116,101,120,116,45,97,108,105,103,110,58,114,44,32, +102,117,110,99,116,105,111,110,40,41,115,105,109,105,108,97,114,105,116,105,101, +115,98,111,100,121,62,60,47,104,116,109,108,62,105,115,32,99,117,114,114,101,110 +,116,108,121,97,108,112,104,97,98,101,116,105,99,97,108,105,115,32,115,111,109, +101,116,105,109,101,115,116,121,112,101,61,34,105,109,97,103,101,47,109,97,110, +121,32,111,102,32,116,104,101,32,102,108,111,119,58,104,105,100,100,101,110,59, +97,118,97,105,108,97,98,108,101,32,105,110,100,101,115,99,114,105,98,101,32,116, +104,101,101,120,105,115,116,101,110,99,101,32,111,102,97,108,108,32,111,118,101, +114,32,116,104,101,116,104,101,32,73,110,116,101,114,110,101,116,9,60,117,108,32 +,99,108,97,115,115,61,34,105,110,115,116,97,108,108,97,116,105,111,110,110,101, +105,103,104,98,111,114,104,111,111,100,97,114,109,101,100,32,102,111,114,99,101, +115,114,101,100,117,99,105,110,103,32,116,104,101,99,111,110,116,105,110,117,101 +,115,32,116,111,78,111,110,101,116,104,101,108,101,115,115,44,116,101,109,112, +101,114,97,116,117,114,101,115,10,9,9,60,97,32,104,114,101,102,61,34,99,108,111, +115,101,32,116,111,32,116,104,101,101,120,97,109,112,108,101,115,32,111,102,32, +105,115,32,97,98,111,117,116,32,116,104,101,40,115,101,101,32,98,101,108,111,119 +,41,46,34,32,105,100,61,34,115,101,97,114,99,104,112,114,111,102,101,115,115,105 +,111,110,97,108,105,115,32,97,118,97,105,108,97,98,108,101,116,104,101,32,111, +102,102,105,99,105,97,108,9,9,60,47,115,99,114,105,112,116,62,10,10,9,9,60,100, +105,118,32,105,100,61,34,97,99,99,101,108,101,114,97,116,105,111,110,116,104,114 +,111,117,103,104,32,116,104,101,32,72,97,108,108,32,111,102,32,70,97,109,101,100 +,101,115,99,114,105,112,116,105,111,110,115,116,114,97,110,115,108,97,116,105, +111,110,115,105,110,116,101,114,102,101,114,101,110,99,101,32,116,121,112,101,61 +,39,116,101,120,116,47,114,101,99,101,110,116,32,121,101,97,114,115,105,110,32, +116,104,101,32,119,111,114,108,100,118,101,114,121,32,112,111,112,117,108,97,114 +,123,98,97,99,107,103,114,111,117,110,100,58,116,114,97,100,105,116,105,111,110, +97,108,32,115,111,109,101,32,111,102,32,116,104,101,32,99,111,110,110,101,99,116 +,101,100,32,116,111,101,120,112,108,111,105,116,97,116,105,111,110,101,109,101, +114,103,101,110,99,101,32,111,102,99,111,110,115,116,105,116,117,116,105,111,110 +,65,32,72,105,115,116,111,114,121,32,111,102,115,105,103,110,105,102,105,99,97, +110,116,32,109,97,110,117,102,97,99,116,117,114,101,100,101,120,112,101,99,116, +97,116,105,111,110,115,62,60,110,111,115,99,114,105,112,116,62,60,99,97,110,32, +98,101,32,102,111,117,110,100,98,101,99,97,117,115,101,32,116,104,101,32,104,97, +115,32,110,111,116,32,98,101,101,110,110,101,105,103,104,98,111,117,114,105,110, +103,119,105,116,104,111,117,116,32,116,104,101,32,97,100,100,101,100,32,116,111, +32,116,104,101,9,60,108,105,32,99,108,97,115,115,61,34,105,110,115,116,114,117, +109,101,110,116,97,108,83,111,118,105,101,116,32,85,110,105,111,110,97,99,107, +110,111,119,108,101,100,103,101,100,119,104,105,99,104,32,99,97,110,32,98,101, +110,97,109,101,32,102,111,114,32,116,104,101,97,116,116,101,110,116,105,111,110, +32,116,111,97,116,116,101,109,112,116,115,32,116,111,32,100,101,118,101,108,111, +112,109,101,110,116,115,73,110,32,102,97,99,116,44,32,116,104,101,60,108,105,32, +99,108,97,115,115,61,34,97,105,109,112,108,105,99,97,116,105,111,110,115,115,117 +,105,116,97,98,108,101,32,102,111,114,109,117,99,104,32,111,102,32,116,104,101, +32,99,111,108,111,110,105,122,97,116,105,111,110,112,114,101,115,105,100,101,110 +,116,105,97,108,99,97,110,99,101,108,66,117,98,98,108,101,32,73,110,102,111,114, +109,97,116,105,111,110,109,111,115,116,32,111,102,32,116,104,101,32,105,115,32, +100,101,115,99,114,105,98,101,100,114,101,115,116,32,111,102,32,116,104,101,32, +109,111,114,101,32,111,114,32,108,101,115,115,105,110,32,83,101,112,116,101,109, +98,101,114,73,110,116,101,108,108,105,103,101,110,99,101,115,114,99,61,34,104, +116,116,112,58,47,47,112,120,59,32,104,101,105,103,104,116,58,32,97,118,97,105, +108,97,98,108,101,32,116,111,109,97,110,117,102,97,99,116,117,114,101,114,104, +117,109,97,110,32,114,105,103,104,116,115,108,105,110,107,32,104,114,101,102,61, +34,47,97,118,97,105,108,97,98,105,108,105,116,121,112,114,111,112,111,114,116, +105,111,110,97,108,111,117,116,115,105,100,101,32,116,104,101,32,97,115,116,114, +111,110,111,109,105,99,97,108,104,117,109,97,110,32,98,101,105,110,103,115,110, +97,109,101,32,111,102,32,116,104,101,32,97,114,101,32,102,111,117,110,100,32,105 +,110,97,114,101,32,98,97,115,101,100,32,111,110,115,109,97,108,108,101,114,32, +116,104,97,110,97,32,112,101,114,115,111,110,32,119,104,111,101,120,112,97,110, +115,105,111,110,32,111,102,97,114,103,117,105,110,103,32,116,104,97,116,110,111, +119,32,107,110,111,119,110,32,97,115,73,110,32,116,104,101,32,101,97,114,108,121 +,105,110,116,101,114,109,101,100,105,97,116,101,100,101,114,105,118,101,100,32, +102,114,111,109,83,99,97,110,100,105,110,97,118,105,97,110,60,47,97,62,60,47,100 +,105,118,62,13,10,99,111,110,115,105,100,101,114,32,116,104,101,97,110,32,101, +115,116,105,109,97,116,101,100,116,104,101,32,78,97,116,105,111,110,97,108,60, +100,105,118,32,105,100,61,34,112,97,103,114,101,115,117,108,116,105,110,103,32, +105,110,99,111,109,109,105,115,115,105,111,110,101,100,97,110,97,108,111,103,111 +,117,115,32,116,111,97,114,101,32,114,101,113,117,105,114,101,100,47,117,108,62, +10,60,47,100,105,118,62,10,119,97,115,32,98,97,115,101,100,32,111,110,97,110,100 +,32,98,101,99,97,109,101,32,97,38,110,98,115,112,59,38,110,98,115,112,59,116,34, +32,118,97,108,117,101,61,34,34,32,119,97,115,32,99,97,112,116,117,114,101,100, +110,111,32,109,111,114,101,32,116,104,97,110,114,101,115,112,101,99,116,105,118, +101,108,121,99,111,110,116,105,110,117,101,32,116,111,32,62,13,10,60,104,101,97, +100,62,13,10,60,119,101,114,101,32,99,114,101,97,116,101,100,109,111,114,101,32, +103,101,110,101,114,97,108,105,110,102,111,114,109,97,116,105,111,110,32,117,115 +,101,100,32,102,111,114,32,116,104,101,105,110,100,101,112,101,110,100,101,110, +116,32,116,104,101,32,73,109,112,101,114,105,97,108,99,111,109,112,111,110,101, +110,116,32,111,102,116,111,32,116,104,101,32,110,111,114,116,104,105,110,99,108, +117,100,101,32,116,104,101,32,67,111,110,115,116,114,117,99,116,105,111,110,115, +105,100,101,32,111,102,32,116,104,101,32,119,111,117,108,100,32,110,111,116,32, +98,101,102,111,114,32,105,110,115,116,97,110,99,101,105,110,118,101,110,116,105, +111,110,32,111,102,109,111,114,101,32,99,111,109,112,108,101,120,99,111,108,108, +101,99,116,105,118,101,108,121,98,97,99,107,103,114,111,117,110,100,58,32,116, +101,120,116,45,97,108,105,103,110,58,32,105,116,115,32,111,114,105,103,105,110, +97,108,105,110,116,111,32,97,99,99,111,117,110,116,116,104,105,115,32,112,114, +111,99,101,115,115,97,110,32,101,120,116,101,110,115,105,118,101,104,111,119,101 +,118,101,114,44,32,116,104,101,116,104,101,121,32,97,114,101,32,110,111,116,114, +101,106,101,99,116,101,100,32,116,104,101,99,114,105,116,105,99,105,115,109,32, +111,102,100,117,114,105,110,103,32,119,104,105,99,104,112,114,111,98,97,98,108, +121,32,116,104,101,116,104,105,115,32,97,114,116,105,99,108,101,40,102,117,110, +99,116,105,111,110,40,41,123,73,116,32,115,104,111,117,108,100,32,98,101,97,110, +32,97,103,114,101,101,109,101,110,116,97,99,99,105,100,101,110,116,97,108,108, +121,100,105,102,102,101,114,115,32,102,114,111,109,65,114,99,104,105,116,101,99, +116,117,114,101,98,101,116,116,101,114,32,107,110,111,119,110,97,114,114,97,110, +103,101,109,101,110,116,115,105,110,102,108,117,101,110,99,101,32,111,110,97,116 +,116,101,110,100,101,100,32,116,104,101,105,100,101,110,116,105,99,97,108,32,116 +,111,115,111,117,116,104,32,111,102,32,116,104,101,112,97,115,115,32,116,104,114 +,111,117,103,104,120,109,108,34,32,116,105,116,108,101,61,34,119,101,105,103,104 +,116,58,98,111,108,100,59,99,114,101,97,116,105,110,103,32,116,104,101,100,105, +115,112,108,97,121,58,110,111,110,101,114,101,112,108,97,99,101,100,32,116,104, +101,60,105,109,103,32,115,114,99,61,34,47,105,104,116,116,112,115,58,47,47,119, +119,119,46,87,111,114,108,100,32,87,97,114,32,73,73,116,101,115,116,105,109,111, +110,105,97,108,115,102,111,117,110,100,32,105,110,32,116,104,101,114,101,113,117 +,105,114,101,100,32,116,111,32,97,110,100,32,116,104,97,116,32,116,104,101,98, +101,116,119,101,101,110,32,116,104,101,32,119,97,115,32,100,101,115,105,103,110, +101,100,99,111,110,115,105,115,116,115,32,111,102,32,99,111,110,115,105,100,101, +114,97,98,108,121,112,117,98,108,105,115,104,101,100,32,98,121,116,104,101,32, +108,97,110,103,117,97,103,101,67,111,110,115,101,114,118,97,116,105,111,110,99, +111,110,115,105,115,116,101,100,32,111,102,114,101,102,101,114,32,116,111,32,116 +,104,101,98,97,99,107,32,116,111,32,116,104,101,32,99,115,115,34,32,109,101,100, +105,97,61,34,80,101,111,112,108,101,32,102,114,111,109,32,97,118,97,105,108,97, +98,108,101,32,111,110,112,114,111,118,101,100,32,116,111,32,98,101,115,117,103, +103,101,115,116,105,111,110,115,34,119,97,115,32,107,110,111,119,110,32,97,115, +118,97,114,105,101,116,105,101,115,32,111,102,108,105,107,101,108,121,32,116,111 +,32,98,101,99,111,109,112,114,105,115,101,100,32,111,102,115,117,112,112,111,114 +,116,32,116,104,101,32,104,97,110,100,115,32,111,102,32,116,104,101,99,111,117, +112,108,101,100,32,119,105,116,104,99,111,110,110,101,99,116,32,97,110,100,32,98 +,111,114,100,101,114,58,110,111,110,101,59,112,101,114,102,111,114,109,97,110,99 +,101,115,98,101,102,111,114,101,32,98,101,105,110,103,108,97,116,101,114,32,98, +101,99,97,109,101,99,97,108,99,117,108,97,116,105,111,110,115,111,102,116,101, +110,32,99,97,108,108,101,100,114,101,115,105,100,101,110,116,115,32,111,102,109, +101,97,110,105,110,103,32,116,104,97,116,62,60,108,105,32,99,108,97,115,115,61, +34,101,118,105,100,101,110,99,101,32,102,111,114,101,120,112,108,97,110,97,116, +105,111,110,115,101,110,118,105,114,111,110,109,101,110,116,115,34,62,60,47,97, +62,60,47,100,105,118,62,119,104,105,99,104,32,97,108,108,111,119,115,73,110,116, +114,111,100,117,99,116,105,111,110,100,101,118,101,108,111,112,101,100,32,98,121 +,97,32,119,105,100,101,32,114,97,110,103,101,111,110,32,98,101,104,97,108,102,32 +,111,102,118,97,108,105,103,110,61,34,116,111,112,34,112,114,105,110,99,105,112, +108,101,32,111,102,97,116,32,116,104,101,32,116,105,109,101,44,60,47,110,111,115 +,99,114,105,112,116,62,13,115,97,105,100,32,116,111,32,104,97,118,101,105,110,32 +,116,104,101,32,102,105,114,115,116,119,104,105,108,101,32,111,116,104,101,114, +115,104,121,112,111,116,104,101,116,105,99,97,108,112,104,105,108,111,115,111, +112,104,101,114,115,112,111,119,101,114,32,111,102,32,116,104,101,99,111,110,116 +,97,105,110,101,100,32,105,110,112,101,114,102,111,114,109,101,100,32,98,121,105 +,110,97,98,105,108,105,116,121,32,116,111,119,101,114,101,32,119,114,105,116,116 +,101,110,115,112,97,110,32,115,116,121,108,101,61,34,105,110,112,117,116,32,110, +97,109,101,61,34,116,104,101,32,113,117,101,115,116,105,111,110,105,110,116,101, +110,100,101,100,32,102,111,114,114,101,106,101,99,116,105,111,110,32,111,102,105 +,109,112,108,105,101,115,32,116,104,97,116,105,110,118,101,110,116,101,100,32, +116,104,101,116,104,101,32,115,116,97,110,100,97,114,100,119,97,115,32,112,114, +111,98,97,98,108,121,108,105,110,107,32,98,101,116,119,101,101,110,112,114,111, +102,101,115,115,111,114,32,111,102,105,110,116,101,114,97,99,116,105,111,110,115 +,99,104,97,110,103,105,110,103,32,116,104,101,73,110,100,105,97,110,32,79,99,101 +,97,110,32,99,108,97,115,115,61,34,108,97,115,116,119,111,114,107,105,110,103,32 +,119,105,116,104,39,104,116,116,112,58,47,47,119,119,119,46,121,101,97,114,115, +32,98,101,102,111,114,101,84,104,105,115,32,119,97,115,32,116,104,101,114,101,99 +,114,101,97,116,105,111,110,97,108,101,110,116,101,114,105,110,103,32,116,104, +101,109,101,97,115,117,114,101,109,101,110,116,115,97,110,32,101,120,116,114,101 +,109,101,108,121,118,97,108,117,101,32,111,102,32,116,104,101,115,116,97,114,116 +,32,111,102,32,116,104,101,10,60,47,115,99,114,105,112,116,62,10,10,97,110,32, +101,102,102,111,114,116,32,116,111,105,110,99,114,101,97,115,101,32,116,104,101, +116,111,32,116,104,101,32,115,111,117,116,104,115,112,97,99,105,110,103,61,34,48 +,34,62,115,117,102,102,105,99,105,101,110,116,108,121,116,104,101,32,69,117,114, +111,112,101,97,110,99,111,110,118,101,114,116,101,100,32,116,111,99,108,101,97, +114,84,105,109,101,111,117,116,100,105,100,32,110,111,116,32,104,97,118,101,99, +111,110,115,101,113,117,101,110,116,108,121,102,111,114,32,116,104,101,32,110, +101,120,116,101,120,116,101,110,115,105,111,110,32,111,102,101,99,111,110,111, +109,105,99,32,97,110,100,97,108,116,104,111,117,103,104,32,116,104,101,97,114, +101,32,112,114,111,100,117,99,101,100,97,110,100,32,119,105,116,104,32,116,104, +101,105,110,115,117,102,102,105,99,105,101,110,116,103,105,118,101,110,32,98,121 +,32,116,104,101,115,116,97,116,105,110,103,32,116,104,97,116,101,120,112,101,110 +,100,105,116,117,114,101,115,60,47,115,112,97,110,62,60,47,97,62,10,116,104,111, +117,103,104,116,32,116,104,97,116,111,110,32,116,104,101,32,98,97,115,105,115,99 +,101,108,108,112,97,100,100,105,110,103,61,105,109,97,103,101,32,111,102,32,116, +104,101,114,101,116,117,114,110,105,110,103,32,116,111,105,110,102,111,114,109, +97,116,105,111,110,44,115,101,112,97,114,97,116,101,100,32,98,121,97,115,115,97, +115,115,105,110,97,116,101,100,115,34,32,99,111,110,116,101,110,116,61,34,97,117 +,116,104,111,114,105,116,121,32,111,102,110,111,114,116,104,119,101,115,116,101, +114,110,60,47,100,105,118,62,10,60,100,105,118,32,34,62,60,47,100,105,118,62,13, +10,32,32,99,111,110,115,117,108,116,97,116,105,111,110,99,111,109,109,117,110, +105,116,121,32,111,102,116,104,101,32,110,97,116,105,111,110,97,108,105,116,32, +115,104,111,117,108,100,32,98,101,112,97,114,116,105,99,105,112,97,110,116,115, +32,97,108,105,103,110,61,34,108,101,102,116,116,104,101,32,103,114,101,97,116, +101,115,116,115,101,108,101,99,116,105,111,110,32,111,102,115,117,112,101,114, +110,97,116,117,114,97,108,100,101,112,101,110,100,101,110,116,32,111,110,105,115 +,32,109,101,110,116,105,111,110,101,100,97,108,108,111,119,105,110,103,32,116, +104,101,119,97,115,32,105,110,118,101,110,116,101,100,97,99,99,111,109,112,97, +110,121,105,110,103,104,105,115,32,112,101,114,115,111,110,97,108,97,118,97,105, +108,97,98,108,101,32,97,116,115,116,117,100,121,32,111,102,32,116,104,101,111, +110,32,116,104,101,32,111,116,104,101,114,101,120,101,99,117,116,105,111,110,32, +111,102,72,117,109,97,110,32,82,105,103,104,116,115,116,101,114,109,115,32,111, +102,32,116,104,101,97,115,115,111,99,105,97,116,105,111,110,115,114,101,115,101, +97,114,99,104,32,97,110,100,115,117,99,99,101,101,100,101,100,32,98,121,100,101, +102,101,97,116,101,100,32,116,104,101,97,110,100,32,102,114,111,109,32,116,104, +101,98,117,116,32,116,104,101,121,32,97,114,101,99,111,109,109,97,110,100,101, +114,32,111,102,115,116,97,116,101,32,111,102,32,116,104,101,121,101,97,114,115, +32,111,102,32,97,103,101,116,104,101,32,115,116,117,100,121,32,111,102,60,117, +108,32,99,108,97,115,115,61,34,115,112,108,97,99,101,32,105,110,32,116,104,101, +119,104,101,114,101,32,104,101,32,119,97,115,60,108,105,32,99,108,97,115,115,61, +34,102,116,104,101,114,101,32,97,114,101,32,110,111,119,104,105,99,104,32,98,101 +,99,97,109,101,104,101,32,112,117,98,108,105,115,104,101,100,101,120,112,114,101 +,115,115,101,100,32,105,110,116,111,32,119,104,105,99,104,32,116,104,101,99,111, +109,109,105,115,115,105,111,110,101,114,102,111,110,116,45,119,101,105,103,104, +116,58,116,101,114,114,105,116,111,114,121,32,111,102,101,120,116,101,110,115, +105,111,110,115,34,62,82,111,109,97,110,32,69,109,112,105,114,101,101,113,117,97 +,108,32,116,111,32,116,104,101,73,110,32,99,111,110,116,114,97,115,116,44,104, +111,119,101,118,101,114,44,32,97,110,100,105,115,32,116,121,112,105,99,97,108, +108,121,97,110,100,32,104,105,115,32,119,105,102,101,40,97,108,115,111,32,99,97, +108,108,101,100,62,60,117,108,32,99,108,97,115,115,61,34,101,102,102,101,99,116, +105,118,101,108,121,32,101,118,111,108,118,101,100,32,105,110,116,111,115,101, +101,109,32,116,111,32,104,97,118,101,119,104,105,99,104,32,105,115,32,116,104, +101,116,104,101,114,101,32,119,97,115,32,110,111,97,110,32,101,120,99,101,108, +108,101,110,116,97,108,108,32,111,102,32,116,104,101,115,101,100,101,115,99,114, +105,98,101,100,32,98,121,73,110,32,112,114,97,99,116,105,99,101,44,98,114,111,97 +,100,99,97,115,116,105,110,103,99,104,97,114,103,101,100,32,119,105,116,104,114, +101,102,108,101,99,116,101,100,32,105,110,115,117,98,106,101,99,116,101,100,32, +116,111,109,105,108,105,116,97,114,121,32,97,110,100,116,111,32,116,104,101,32, +112,111,105,110,116,101,99,111,110,111,109,105,99,97,108,108,121,115,101,116,84, +97,114,103,101,116,105,110,103,97,114,101,32,97,99,116,117,97,108,108,121,118, +105,99,116,111,114,121,32,111,118,101,114,40,41,59,60,47,115,99,114,105,112,116, +62,99,111,110,116,105,110,117,111,117,115,108,121,114,101,113,117,105,114,101, +100,32,102,111,114,101,118,111,108,117,116,105,111,110,97,114,121,97,110,32,101, +102,102,101,99,116,105,118,101,110,111,114,116,104,32,111,102,32,116,104,101,44, +32,119,104,105,99,104,32,119,97,115,32,102,114,111,110,116,32,111,102,32,116,104 +,101,111,114,32,111,116,104,101,114,119,105,115,101,115,111,109,101,32,102,111, +114,109,32,111,102,104,97,100,32,110,111,116,32,98,101,101,110,103,101,110,101, +114,97,116,101,100,32,98,121,105,110,102,111,114,109,97,116,105,111,110,46,112, +101,114,109,105,116,116,101,100,32,116,111,105,110,99,108,117,100,101,115,32,116 +,104,101,100,101,118,101,108,111,112,109,101,110,116,44,101,110,116,101,114,101, +100,32,105,110,116,111,116,104,101,32,112,114,101,118,105,111,117,115,99,111,110 +,115,105,115,116,101,110,116,108,121,97,114,101,32,107,110,111,119,110,32,97,115 +,116,104,101,32,102,105,101,108,100,32,111,102,116,104,105,115,32,116,121,112, +101,32,111,102,103,105,118,101,110,32,116,111,32,116,104,101,116,104,101,32,116, +105,116,108,101,32,111,102,99,111,110,116,97,105,110,115,32,116,104,101,105,110, +115,116,97,110,99,101,115,32,111,102,105,110,32,116,104,101,32,110,111,114,116, +104,100,117,101,32,116,111,32,116,104,101,105,114,97,114,101,32,100,101,115,105, +103,110,101,100,99,111,114,112,111,114,97,116,105,111,110,115,119,97,115,32,116, +104,97,116,32,116,104,101,111,110,101,32,111,102,32,116,104,101,115,101,109,111, +114,101,32,112,111,112,117,108,97,114,115,117,99,99,101,101,100,101,100,32,105, +110,115,117,112,112,111,114,116,32,102,114,111,109,105,110,32,100,105,102,102, +101,114,101,110,116,100,111,109,105,110,97,116,101,100,32,98,121,100,101,115,105 +,103,110,101,100,32,102,111,114,111,119,110,101,114,115,104,105,112,32,111,102, +97,110,100,32,112,111,115,115,105,98,108,121,115,116,97,110,100,97,114,100,105, +122,101,100,114,101,115,112,111,110,115,101,84,101,120,116,119,97,115,32,105,110 +,116,101,110,100,101,100,114,101,99,101,105,118,101,100,32,116,104,101,97,115, +115,117,109,101,100,32,116,104,97,116,97,114,101,97,115,32,111,102,32,116,104, +101,112,114,105,109,97,114,105,108,121,32,105,110,116,104,101,32,98,97,115,105, +115,32,111,102,105,110,32,116,104,101,32,115,101,110,115,101,97,99,99,111,117, +110,116,115,32,102,111,114,100,101,115,116,114,111,121,101,100,32,98,121,97,116, +32,108,101,97,115,116,32,116,119,111,119,97,115,32,100,101,99,108,97,114,101,100 +,99,111,117,108,100,32,110,111,116,32,98,101,83,101,99,114,101,116,97,114,121,32 +,111,102,97,112,112,101,97,114,32,116,111,32,98,101,109,97,114,103,105,110,45, +116,111,112,58,49,47,94,92,115,43,124,92,115,43,36,47,103,101,41,123,116,104,114 +,111,119,32,101,125,59,116,104,101,32,115,116,97,114,116,32,111,102,116,119,111, +32,115,101,112,97,114,97,116,101,108,97,110,103,117,97,103,101,32,97,110,100,119 +,104,111,32,104,97,100,32,98,101,101,110,111,112,101,114,97,116,105,111,110,32, +111,102,100,101,97,116,104,32,111,102,32,116,104,101,114,101,97,108,32,110,117, +109,98,101,114,115,9,60,108,105,110,107,32,114,101,108,61,34,112,114,111,118,105 +,100,101,100,32,116,104,101,116,104,101,32,115,116,111,114,121,32,111,102,99,111 +,109,112,101,116,105,116,105,111,110,115,101,110,103,108,105,115,104,32,40,85,75 +,41,101,110,103,108,105,115,104,32,40,85,83,41,208,156,208,190,208,189,208,179, +208,190,208,187,208,161,209,128,208,191,209,129,208,186,208,184,209,129,209,128, +208,191,209,129,208,186,208,184,209,129,209,128,208,191,209,129,208,186,208,190, +217,132,216,185,216,177,216,168,217,138,216,169,230,173,163,233,171,148,228,184, +173,230,150,135,231,174,128,228,189,147,228,184,173,230,150,135,231,185,129,228, +189,147,228,184,173,230,150,135,230,156,137,233,153,144,229,133,172,229,143,184, +228,186,186,230,176,145,230,148,191,229,186,156,233,152,191,233,135,140,229,183, +180,229,183,180,231,164,190,228,188,154,228,184,187,228,185,137,230,147,141,228, +189,156,231,179,187,231,187,159,230,148,191,231,173,150,230,179,149,232,167,132, +105,110,102,111,114,109,97,99,105,195,179,110,104,101,114,114,97,109,105,101,110 +,116,97,115,101,108,101,99,116,114,195,179,110,105,99,111,100,101,115,99,114,105 +,112,99,105,195,179,110,99,108,97,115,105,102,105,99,97,100,111,115,99,111,110, +111,99,105,109,105,101,110,116,111,112,117,98,108,105,99,97,99,105,195,179,110, +114,101,108,97,99,105,111,110,97,100,97,115,105,110,102,111,114,109,195,161,116, +105,99,97,114,101,108,97,99,105,111,110,97,100,111,115,100,101,112,97,114,116,97 +,109,101,110,116,111,116,114,97,98,97,106,97,100,111,114,101,115,100,105,114,101 +,99,116,97,109,101,110,116,101,97,121,117,110,116,97,109,105,101,110,116,111,109 +,101,114,99,97,100,111,76,105,98,114,101,99,111,110,116,195,161,99,116,101,110, +111,115,104,97,98,105,116,97,99,105,111,110,101,115,99,117,109,112,108,105,109, +105,101,110,116,111,114,101,115,116,97,117,114,97,110,116,101,115,100,105,115, +112,111,115,105,99,105,195,179,110,99,111,110,115,101,99,117,101,110,99,105,97, +101,108,101,99,116,114,195,179,110,105,99,97,97,112,108,105,99,97,99,105,111,110 +,101,115,100,101,115,99,111,110,101,99,116,97,100,111,105,110,115,116,97,108,97, +99,105,195,179,110,114,101,97,108,105,122,97,99,105,195,179,110,117,116,105,108, +105,122,97,99,105,195,179,110,101,110,99,105,99,108,111,112,101,100,105,97,101, +110,102,101,114,109,101,100,97,100,101,115,105,110,115,116,114,117,109,101,110, +116,111,115,101,120,112,101,114,105,101,110,99,105,97,115,105,110,115,116,105, +116,117,99,105,195,179,110,112,97,114,116,105,99,117,108,97,114,101,115,115,117, +98,99,97,116,101,103,111,114,105,97,209,130,208,190,208,187,209,140,208,186,208, +190,208,160,208,190,209,129,209,129,208,184,208,184,209,128,208,176,208,177,208, +190,209,130,209,139,208,177,208,190,208,187,209,140,209,136,208,181,208,191,209, +128,208,190,209,129,209,130,208,190,208,188,208,190,208,182,208,181,209,130,208, +181,208,180,209,128,209,131,208,179,208,184,209,133,209,129,208,187,209,131,209, +135,208,176,208,181,209,129,208,181,208,185,209,135,208,176,209,129,208,178,209, +129,208,181,208,179,208,180,208,176,208,160,208,190,209,129,209,129,208,184,209, +143,208,156,208,190,209,129,208,186,208,178,208,181,208,180,209,128,209,131,208, +179,208,184,208,181,208,179,208,190,209,128,208,190,208,180,208,176,208,178,208, +190,208,191,209,128,208,190,209,129,208,180,208,176,208,189,208,189,209,139,209, +133,208,180,208,190,208,187,208,182,208,189,209,139,208,184,208,188,208,181,208, +189,208,189,208,190,208,156,208,190,209,129,208,186,208,178,209,139,209,128,209, +131,208,177,208,187,208,181,208,185,208,156,208,190,209,129,208,186,208,178,208, +176,209,129,209,130,209,128,208,176,208,189,209,139,208,189,208,184,209,135,208, +181,208,179,208,190,209,128,208,176,208,177,208,190,209,130,208,181,208,180,208, +190,208,187,208,182,208,181,208,189,209,131,209,129,208,187,209,131,208,179,208, +184,209,130,208,181,208,191,208,181,209,128,209,140,208,158,208,180,208,189,208, +176,208,186,208,190,208,191,208,190,209,130,208,190,208,188,209,131,209,128,208, +176,208,177,208,190,209,130,209,131,208,176,208,191,209,128,208,181,208,187,209, +143,208,178,208,190,208,190,208,177,209,137,208,181,208,190,208,180,208,189,208, +190,208,179,208,190,209,129,208,178,208,190,208,181,208,179,208,190,209,129,209, +130,208,176,209,130,209,140,208,184,208,180,209,128,209,131,208,179,208,190,208, +185,209,132,208,190,209,128,209,131,208,188,208,181,209,133,208,190,209,128,208, +190,209,136,208,190,208,191,209,128,208,190,209,130,208,184,208,178,209,129,209, +129,209,139,208,187,208,186,208,176,208,186,208,176,208,182,208,180,209,139,208, +185,208,178,208,187,208,176,209,129,209,130,208,184,208,179,209,128,209,131,208, +191,208,191,209,139,208,178,208,188,208,181,209,129,209,130,208,181,209,128,208, +176,208,177,208,190,209,130,208,176,209,129,208,186,208,176,208,183,208,176,208, +187,208,191,208,181,209,128,208,178,209,139,208,185,208,180,208,181,208,187,208, +176,209,130,209,140,208,180,208,181,208,189,209,140,208,179,208,184,208,191,208, +181,209,128,208,184,208,190,208,180,208,177,208,184,208,183,208,189,208,181,209, +129,208,190,209,129,208,189,208,190,208,178,208,181,208,188,208,190,208,188,208, +181,208,189,209,130,208,186,209,131,208,191,208,184,209,130,209,140,208,180,208, +190,208,187,208,182,208,189,208,176,209,128,208,176,208,188,208,186,208,176,209, +133,208,189,208,176,209,135,208,176,208,187,208,190,208,160,208,176,208,177,208, +190,209,130,208,176,208,162,208,190,208,187,209,140,208,186,208,190,209,129,208, +190,208,178,209,129,208,181,208,188,208,178,209,130,208,190,209,128,208,190,208, +185,208,189,208,176,209,135,208,176,208,187,208,176,209,129,208,191,208,184,209, +129,208,190,208,186,209,129,208,187,209,131,208,182,208,177,209,139,209,129,208, +184,209,129,209,130,208,181,208,188,208,191,208,181,209,135,208,176,209,130,208, +184,208,189,208,190,208,178,208,190,208,179,208,190,208,191,208,190,208,188,208, +190,209,137,208,184,209,129,208,176,208,185,209,130,208,190,208,178,208,191,208, +190,209,135,208,181,208,188,209,131,208,191,208,190,208,188,208,190,209,137,209, +140,208,180,208,190,208,187,208,182,208,189,208,190,209,129,209,129,209,139,208, +187,208,186,208,184,208,177,209,139,209,129,209,130,209,128,208,190,208,180,208, +176,208,189,208,189,209,139,208,181,208,188,208,189,208,190,208,179,208,184,208, +181,208,191,209,128,208,190,208,181,208,186,209,130,208,161,208,181,208,185,209, +135,208,176,209,129,208,188,208,190,208,180,208,181,208,187,208,184,209,130,208, +176,208,186,208,190,208,179,208,190,208,190,208,189,208,187,208,176,208,185,208, +189,208,179,208,190,209,128,208,190,208,180,208,181,208,178,208,181,209,128,209, +129,208,184,209,143,209,129,209,130,209,128,208,176,208,189,208,181,209,132,208, +184,208,187,209,140,208,188,209,139,209,131,209,128,208,190,208,178,208,189,209, +143,209,128,208,176,208,183,208,189,209,139,209,133,208,184,209,129,208,186,208, +176,209,130,209,140,208,189,208,181,208,180,208,181,208,187,209,142,209,143,208, +189,208,178,208,176,209,128,209,143,208,188,208,181,208,189,209,140,209,136,208, +181,208,188,208,189,208,190,208,179,208,184,209,133,208,180,208,176,208,189,208, +189,208,190,208,185,208,183,208,189,208,176,209,135,208,184,209,130,208,189,208, +181,208,187,209,140,208,183,209,143,209,132,208,190,209,128,209,131,208,188,208, +176,208,162,208,181,208,191,208,181,209,128,209,140,208,188,208,181,209,129,209, +143,209,134,208,176,208,183,208,176,209,137,208,184,209,130,209,139,208,155,209, +131,209,135,209,136,208,184,208,181,224,164,168,224,164,185,224,165,128,224,164, +130,224,164,149,224,164,176,224,164,168,224,165,135,224,164,133,224,164,170,224, +164,168,224,165,135,224,164,149,224,164,191,224,164,175,224,164,190,224,164,149, +224,164,176,224,165,135,224,164,130,224,164,133,224,164,168,224,165,141,224,164, +175,224,164,149,224,165,141,224,164,175,224,164,190,224,164,151,224,164,190,224, +164,135,224,164,161,224,164,172,224,164,190,224,164,176,224,165,135,224,164,149, +224,164,191,224,164,184,224,165,128,224,164,166,224,164,191,224,164,175,224,164, +190,224,164,170,224,164,185,224,164,178,224,165,135,224,164,184,224,164,191,224, +164,130,224,164,185,224,164,173,224,164,190,224,164,176,224,164,164,224,164,133, +224,164,170,224,164,168,224,165,128,224,164,181,224,164,190,224,164,178,224,165, +135,224,164,184,224,165,135,224,164,181,224,164,190,224,164,149,224,164,176,224, +164,164,224,165,135,224,164,174,224,165,135,224,164,176,224,165,135,224,164,185, +224,165,139,224,164,168,224,165,135,224,164,184,224,164,149,224,164,164,224,165, +135,224,164,172,224,164,185,224,165,129,224,164,164,224,164,184,224,164,190,224, +164,135,224,164,159,224,164,185,224,165,139,224,164,151,224,164,190,224,164,156, +224,164,190,224,164,168,224,165,135,224,164,174,224,164,191,224,164,168,224,164, +159,224,164,149,224,164,176,224,164,164,224,164,190,224,164,149,224,164,176,224, +164,168,224,164,190,224,164,137,224,164,168,224,164,149,224,165,135,224,164,175, +224,164,185,224,164,190,224,164,129,224,164,184,224,164,172,224,164,184,224,165, +135,224,164,173,224,164,190,224,164,183,224,164,190,224,164,134,224,164,170,224, +164,149,224,165,135,224,164,178,224,164,191,224,164,175,224,165,135,224,164,182, +224,165,129,224,164,176,224,165,130,224,164,135,224,164,184,224,164,149,224,165, +135,224,164,152,224,164,130,224,164,159,224,165,135,224,164,174,224,165,135,224, +164,176,224,165,128,224,164,184,224,164,149,224,164,164,224,164,190,224,164,174, +224,165,135,224,164,176,224,164,190,224,164,178,224,165,135,224,164,149,224,164, +176,224,164,133,224,164,167,224,164,191,224,164,149,224,164,133,224,164,170,224, +164,168,224,164,190,224,164,184,224,164,174,224,164,190,224,164,156,224,164,174, +224,165,129,224,164,157,224,165,135,224,164,149,224,164,190,224,164,176,224,164, +163,224,164,185,224,165,139,224,164,164,224,164,190,224,164,149,224,164,161,224, +164,188,224,165,128,224,164,175,224,164,185,224,164,190,224,164,130,224,164,185, +224,165,139,224,164,159,224,164,178,224,164,182,224,164,172,224,165,141,224,164, +166,224,164,178,224,164,191,224,164,175,224,164,190,224,164,156,224,165,128,224, +164,181,224,164,168,224,164,156,224,164,190,224,164,164,224,164,190,224,164,149, +224,165,136,224,164,184,224,165,135,224,164,134,224,164,170,224,164,149,224,164, +190,224,164,181,224,164,190,224,164,178,224,165,128,224,164,166,224,165,135,224, +164,168,224,165,135,224,164,170,224,165,130,224,164,176,224,165,128,224,164,170, +224,164,190,224,164,168,224,165,128,224,164,137,224,164,184,224,164,149,224,165, +135,224,164,185,224,165,139,224,164,151,224,165,128,224,164,172,224,165,136,224, +164,160,224,164,149,224,164,134,224,164,170,224,164,149,224,165,128,224,164,181, +224,164,176,224,165,141,224,164,183,224,164,151,224,164,190,224,164,130,224,164, +181,224,164,134,224,164,170,224,164,149,224,165,139,224,164,156,224,164,191,224, +164,178,224,164,190,224,164,156,224,164,190,224,164,168,224,164,190,224,164,184, +224,164,185,224,164,174,224,164,164,224,164,185,224,164,174,224,165,135,224,164, +130,224,164,137,224,164,168,224,164,149,224,165,128,224,164,175,224,164,190,224, +164,185,224,165,130,224,164,166,224,164,176,224,165,141,224,164,156,224,164,184, +224,165,130,224,164,154,224,165,128,224,164,170,224,164,184,224,164,130,224,164, +166,224,164,184,224,164,181,224,164,190,224,164,178,224,164,185,224,165,139,224, +164,168,224,164,190,224,164,185,224,165,139,224,164,164,224,165,128,224,164,156, +224,165,136,224,164,184,224,165,135,224,164,181,224,164,190,224,164,170,224,164, +184,224,164,156,224,164,168,224,164,164,224,164,190,224,164,168,224,165,135,224, +164,164,224,164,190,224,164,156,224,164,190,224,164,176,224,165,128,224,164,152, +224,164,190,224,164,175,224,164,178,224,164,156,224,164,191,224,164,178,224,165, +135,224,164,168,224,165,128,224,164,154,224,165,135,224,164,156,224,164,190,224, +164,130,224,164,154,224,164,170,224,164,164,224,165,141,224,164,176,224,164,151, +224,165,130,224,164,151,224,164,178,224,164,156,224,164,190,224,164,164,224,165, +135,224,164,172,224,164,190,224,164,185,224,164,176,224,164,134,224,164,170,224, +164,168,224,165,135,224,164,181,224,164,190,224,164,185,224,164,168,224,164,135, +224,164,184,224,164,149,224,164,190,224,164,184,224,165,129,224,164,172,224,164, +185,224,164,176,224,164,185,224,164,168,224,165,135,224,164,135,224,164,184,224, +164,184,224,165,135,224,164,184,224,164,185,224,164,191,224,164,164,224,164,172, +224,164,161,224,164,188,224,165,135,224,164,152,224,164,159,224,164,168,224,164, +190,224,164,164,224,164,178,224,164,190,224,164,182,224,164,170,224,164,190,224, +164,130,224,164,154,224,164,182,224,165,141,224,164,176,224,165,128,224,164,172, +224,164,161,224,164,188,224,165,128,224,164,185,224,165,139,224,164,164,224,165, +135,224,164,184,224,164,190,224,164,136,224,164,159,224,164,182,224,164,190,224, +164,175,224,164,166,224,164,184,224,164,149,224,164,164,224,165,128,224,164,156, +224,164,190,224,164,164,224,165,128,224,164,181,224,164,190,224,164,178,224,164, +190,224,164,185,224,164,156,224,164,190,224,164,176,224,164,170,224,164,159,224, +164,168,224,164,190,224,164,176,224,164,150,224,164,168,224,165,135,224,164,184, +224,164,161,224,164,188,224,164,149,224,164,174,224,164,191,224,164,178,224,164, +190,224,164,137,224,164,184,224,164,149,224,165,128,224,164,149,224,165,135,224, +164,181,224,164,178,224,164,178,224,164,151,224,164,164,224,164,190,224,164,150, +224,164,190,224,164,168,224,164,190,224,164,133,224,164,176,224,165,141,224,164, +165,224,164,156,224,164,185,224,164,190,224,164,130,224,164,166,224,165,135,224, +164,150,224,164,190,224,164,170,224,164,185,224,164,178,224,165,128,224,164,168, +224,164,191,224,164,175,224,164,174,224,164,172,224,164,191,224,164,168,224,164, +190,224,164,172,224,165,136,224,164,130,224,164,149,224,164,149,224,164,185,224, +165,128,224,164,130,224,164,149,224,164,185,224,164,168,224,164,190,224,164,166, +224,165,135,224,164,164,224,164,190,224,164,185,224,164,174,224,164,178,224,165, +135,224,164,149,224,164,190,224,164,171,224,165,128,224,164,156,224,164,172,224, +164,149,224,164,191,224,164,164,224,165,129,224,164,176,224,164,164,224,164,174, +224,164,190,224,164,130,224,164,151,224,164,181,224,164,185,224,165,128,224,164, +130,224,164,176,224,165,139,224,164,156,224,164,188,224,164,174,224,164,191,224, +164,178,224,165,128,224,164,134,224,164,176,224,165,139,224,164,170,224,164,184, +224,165,135,224,164,168,224,164,190,224,164,175,224,164,190,224,164,166,224,164, +181,224,164,178,224,165,135,224,164,168,224,165,135,224,164,150,224,164,190,224, +164,164,224,164,190,224,164,149,224,164,176,224,165,128,224,164,172,224,164,137, +224,164,168,224,164,149,224,164,190,224,164,156,224,164,181,224,164,190,224,164, +172,224,164,170,224,165,130,224,164,176,224,164,190,224,164,172,224,164,161,224, +164,188,224,164,190,224,164,184,224,165,140,224,164,166,224,164,190,224,164,182, +224,165,135,224,164,175,224,164,176,224,164,149,224,164,191,224,164,175,224,165, +135,224,164,149,224,164,185,224,164,190,224,164,130,224,164,133,224,164,149,224, +164,184,224,164,176,224,164,172,224,164,168,224,164,190,224,164,143,224,164,181, +224,164,185,224,164,190,224,164,130,224,164,184,224,165,141,224,164,165,224,164, +178,224,164,174,224,164,191,224,164,178,224,165,135,224,164,178,224,165,135,224, +164,150,224,164,149,224,164,181,224,164,191,224,164,183,224,164,175,224,164,149, +224,165,141,224,164,176,224,164,130,224,164,184,224,164,174,224,165,130,224,164, +185,224,164,165,224,164,190,224,164,168,224,164,190,216,170,216,179,216,170,216, +183,217,138,216,185,217,133,216,180,216,167,216,177,217,131,216,169,216,168,217, +136,216,167,216,179,216,183,216,169,216,167,217,132,216,181,217,129,216,173,216, +169,217,133,217,136,216,167,216,182,217,138,216,185,216,167,217,132,216,174,216, +167,216,181,216,169,216,167,217,132,217,133,216,178,217,138,216,175,216,167,217, +132,216,185,216,167,217,133,216,169,216,167,217,132,217,131,216,167,216,170,216, +168,216,167,217,132,216,177,216,175,217,136,216,175,216,168,216,177,217,134,216, +167,217,133,216,172,216,167,217,132,216,175,217,136,217,132,216,169,216,167,217, +132,216,185,216,167,217,132,217,133,216,167,217,132,217,133,217,136,217,130,216, +185,216,167,217,132,216,185,216,177,216,168,217,138,216,167,217,132,216,179,216, +177,217,138,216,185,216,167,217,132,216,172,217,136,216,167,217,132,216,167,217, +132,216,176,217,135,216,167,216,168,216,167,217,132,216,173,217,138,216,167,216, +169,216,167,217,132,216,173,217,130,217,136,217,130,216,167,217,132,217,131,216, +177,217,138,217,133,216,167,217,132,216,185,216,177,216,167,217,130,217,133,216, +173,217,129,217,136,216,184,216,169,216,167,217,132,216,171,216,167,217,134,217, +138,217,133,216,180,216,167,217,135,216,175,216,169,216,167,217,132,217,133,216, +177,216,163,216,169,216,167,217,132,217,130,216,177,216,162,217,134,216,167,217, +132,216,180,216,168,216,167,216,168,216,167,217,132,216,173,217,136,216,167,216, +177,216,167,217,132,216,172,216,175,217,138,216,175,216,167,217,132,216,163,216, +179,216,177,216,169,216,167,217,132,216,185,217,132,217,136,217,133,217,133,216, +172,217,133,217,136,216,185,216,169,216,167,217,132,216,177,216,173,217,133,217, +134,216,167,217,132,217,134,217,130,216,167,216,183,217,129,217,132,216,179,216, +183,217,138,217,134,216,167,217,132,217,131,217,136,217,138,216,170,216,167,217, +132,216,175,217,134,217,138,216,167,216,168,216,177,217,131,216,167,216,170,217, +135,216,167,217,132,216,177,217,138,216,167,216,182,216,170,216,173,217,138,216, +167,216,170,217,138,216,168,216,170,217,136,217,130,217,138,216,170,216,167,217, +132,216,163,217,136,217,132,217,137,216,167,217,132,216,168,216,177,217,138,216, +175,216,167,217,132,217,131,217,132,216,167,217,133,216,167,217,132,216,177,216, +167,216,168,216,183,216,167,217,132,216,180,216,174,216,181,217,138,216,179,217, +138,216,167,216,177,216,167,216,170,216,167,217,132,216,171,216,167,217,132,216, +171,216,167,217,132,216,181,217,132,216,167,216,169,216,167,217,132,216,173,216, +175,217,138,216,171,216,167,217,132,216,178,217,136,216,167,216,177,216,167,217, +132,216,174,217,132,217,138,216,172,216,167,217,132,216,172,217,133,217,138,216, +185,216,167,217,132,216,185,216,167,217,133,217,135,216,167,217,132,216,172,217, +133,216,167,217,132,216,167,217,132,216,179,216,167,216,185,216,169,217,133,216, +180,216,167,217,135,216,175,217,135,216,167,217,132,216,177,216,166,217,138,216, +179,216,167,217,132,216,175,216,174,217,136,217,132,216,167,217,132,217,129,217, +134,217,138,216,169,216,167,217,132,217,131,216,170,216,167,216,168,216,167,217, +132,216,175,217,136,216,177,217,138,216,167,217,132,216,175,216,177,217,136,216, +179,216,167,216,179,216,170,216,186,216,177,217,130,216,170,216,181,216,167,217, +133,217,138,217,133,216,167,217,132,216,168,217,134,216,167,216,170,216,167,217, +132,216,185,216,184,217,138,217,133,101,110,116,101,114,116,97,105,110,109,101, +110,116,117,110,100,101,114,115,116,97,110,100,105,110,103,32,61,32,102,117,110, +99,116,105,111,110,40,41,46,106,112,103,34,32,119,105,100,116,104,61,34,99,111, +110,102,105,103,117,114,97,116,105,111,110,46,112,110,103,34,32,119,105,100,116, +104,61,34,60,98,111,100,121,32,99,108,97,115,115,61,34,77,97,116,104,46,114,97, +110,100,111,109,40,41,99,111,110,116,101,109,112,111,114,97,114,121,32,85,110, +105,116,101,100,32,83,116,97,116,101,115,99,105,114,99,117,109,115,116,97,110,99 +,101,115,46,97,112,112,101,110,100,67,104,105,108,100,40,111,114,103,97,110,105, +122,97,116,105,111,110,115,60,115,112,97,110,32,99,108,97,115,115,61,34,34,62,60 +,105,109,103,32,115,114,99,61,34,47,100,105,115,116,105,110,103,117,105,115,104, +101,100,116,104,111,117,115,97,110,100,115,32,111,102,32,99,111,109,109,117,110, +105,99,97,116,105,111,110,99,108,101,97,114,34,62,60,47,100,105,118,62,105,110, +118,101,115,116,105,103,97,116,105,111,110,102,97,118,105,99,111,110,46,105,99, +111,34,32,109,97,114,103,105,110,45,114,105,103,104,116,58,98,97,115,101,100,32, +111,110,32,116,104,101,32,77,97,115,115,97,99,104,117,115,101,116,116,115,116,97 +,98,108,101,32,98,111,114,100,101,114,61,105,110,116,101,114,110,97,116,105,111, +110,97,108,97,108,115,111,32,107,110,111,119,110,32,97,115,112,114,111,110,117, +110,99,105,97,116,105,111,110,98,97,99,107,103,114,111,117,110,100,58,35,102,112 +,97,100,100,105,110,103,45,108,101,102,116,58,70,111,114,32,101,120,97,109,112, +108,101,44,32,109,105,115,99,101,108,108,97,110,101,111,117,115,38,108,116,59,47 +,109,97,116,104,38,103,116,59,112,115,121,99,104,111,108,111,103,105,99,97,108, +105,110,32,112,97,114,116,105,99,117,108,97,114,101,97,114,99,104,34,32,116,121, +112,101,61,34,102,111,114,109,32,109,101,116,104,111,100,61,34,97,115,32,111,112 +,112,111,115,101,100,32,116,111,83,117,112,114,101,109,101,32,67,111,117,114,116 +,111,99,99,97,115,105,111,110,97,108,108,121,32,65,100,100,105,116,105,111,110, +97,108,108,121,44,78,111,114,116,104,32,65,109,101,114,105,99,97,112,120,59,98, +97,99,107,103,114,111,117,110,100,111,112,112,111,114,116,117,110,105,116,105, +101,115,69,110,116,101,114,116,97,105,110,109,101,110,116,46,116,111,76,111,119, +101,114,67,97,115,101,40,109,97,110,117,102,97,99,116,117,114,105,110,103,112, +114,111,102,101,115,115,105,111,110,97,108,32,99,111,109,98,105,110,101,100,32, +119,105,116,104,70,111,114,32,105,110,115,116,97,110,99,101,44,99,111,110,115, +105,115,116,105,110,103,32,111,102,34,32,109,97,120,108,101,110,103,116,104,61, +34,114,101,116,117,114,110,32,102,97,108,115,101,59,99,111,110,115,99,105,111, +117,115,110,101,115,115,77,101,100,105,116,101,114,114,97,110,101,97,110,101,120 +,116,114,97,111,114,100,105,110,97,114,121,97,115,115,97,115,115,105,110,97,116, +105,111,110,115,117,98,115,101,113,117,101,110,116,108,121,32,98,117,116,116,111 +,110,32,116,121,112,101,61,34,116,104,101,32,110,117,109,98,101,114,32,111,102, +116,104,101,32,111,114,105,103,105,110,97,108,32,99,111,109,112,114,101,104,101, +110,115,105,118,101,114,101,102,101,114,115,32,116,111,32,116,104,101,60,47,117, +108,62,10,60,47,100,105,118,62,10,112,104,105,108,111,115,111,112,104,105,99,97, +108,108,111,99,97,116,105,111,110,46,104,114,101,102,119,97,115,32,112,117,98, +108,105,115,104,101,100,83,97,110,32,70,114,97,110,99,105,115,99,111,40,102,117, +110,99,116,105,111,110,40,41,123,10,60,100,105,118,32,105,100,61,34,109,97,105, +110,115,111,112,104,105,115,116,105,99,97,116,101,100,109,97,116,104,101,109,97, +116,105,99,97,108,32,47,104,101,97,100,62,13,10,60,98,111,100,121,115,117,103, +103,101,115,116,115,32,116,104,97,116,100,111,99,117,109,101,110,116,97,116,105, +111,110,99,111,110,99,101,110,116,114,97,116,105,111,110,114,101,108,97,116,105, +111,110,115,104,105,112,115,109,97,121,32,104,97,118,101,32,98,101,101,110,40, +102,111,114,32,101,120,97,109,112,108,101,44,84,104,105,115,32,97,114,116,105,99 +,108,101,32,105,110,32,115,111,109,101,32,99,97,115,101,115,112,97,114,116,115, +32,111,102,32,116,104,101,32,100,101,102,105,110,105,116,105,111,110,32,111,102, +71,114,101,97,116,32,66,114,105,116,97,105,110,32,99,101,108,108,112,97,100,100, +105,110,103,61,101,113,117,105,118,97,108,101,110,116,32,116,111,112,108,97,99, +101,104,111,108,100,101,114,61,34,59,32,102,111,110,116,45,115,105,122,101,58,32 +,106,117,115,116,105,102,105,99,97,116,105,111,110,98,101,108,105,101,118,101, +100,32,116,104,97,116,115,117,102,102,101,114,101,100,32,102,114,111,109,97,116, +116,101,109,112,116,101,100,32,116,111,32,108,101,97,100,101,114,32,111,102,32, +116,104,101,99,114,105,112,116,34,32,115,114,99,61,34,47,40,102,117,110,99,116, +105,111,110,40,41,32,123,97,114,101,32,97,118,97,105,108,97,98,108,101,10,9,60, +108,105,110,107,32,114,101,108,61,34,32,115,114,99,61,39,104,116,116,112,58,47, +47,105,110,116,101,114,101,115,116,101,100,32,105,110,99,111,110,118,101,110,116 +,105,111,110,97,108,32,34,32,97,108,116,61,34,34,32,47,62,60,47,97,114,101,32, +103,101,110,101,114,97,108,108,121,104,97,115,32,97,108,115,111,32,98,101,101, +110,109,111,115,116,32,112,111,112,117,108,97,114,32,99,111,114,114,101,115,112, +111,110,100,105,110,103,99,114,101,100,105,116,101,100,32,119,105,116,104,116, +121,108,101,61,34,98,111,114,100,101,114,58,60,47,97,62,60,47,115,112,97,110,62, +60,47,46,103,105,102,34,32,119,105,100,116,104,61,34,60,105,102,114,97,109,101, +32,115,114,99,61,34,116,97,98,108,101,32,99,108,97,115,115,61,34,105,110,108,105 +,110,101,45,98,108,111,99,107,59,97,99,99,111,114,100,105,110,103,32,116,111,32, +116,111,103,101,116,104,101,114,32,119,105,116,104,97,112,112,114,111,120,105, +109,97,116,101,108,121,112,97,114,108,105,97,109,101,110,116,97,114,121,109,111, +114,101,32,97,110,100,32,109,111,114,101,100,105,115,112,108,97,121,58,110,111, +110,101,59,116,114,97,100,105,116,105,111,110,97,108,108,121,112,114,101,100,111 +,109,105,110,97,110,116,108,121,38,110,98,115,112,59,124,38,110,98,115,112,59,38 +,110,98,115,112,59,60,47,115,112,97,110,62,32,99,101,108,108,115,112,97,99,105, +110,103,61,60,105,110,112,117,116,32,110,97,109,101,61,34,111,114,34,32,99,111, +110,116,101,110,116,61,34,99,111,110,116,114,111,118,101,114,115,105,97,108,112, +114,111,112,101,114,116,121,61,34,111,103,58,47,120,45,115,104,111,99,107,119,97 +,118,101,45,100,101,109,111,110,115,116,114,97,116,105,111,110,115,117,114,114, +111,117,110,100,101,100,32,98,121,78,101,118,101,114,116,104,101,108,101,115,115 +,44,119,97,115,32,116,104,101,32,102,105,114,115,116,99,111,110,115,105,100,101, +114,97,98,108,101,32,65,108,116,104,111,117,103,104,32,116,104,101,32,99,111,108 +,108,97,98,111,114,97,116,105,111,110,115,104,111,117,108,100,32,110,111,116,32, +98,101,112,114,111,112,111,114,116,105,111,110,32,111,102,60,115,112,97,110,32, +115,116,121,108,101,61,34,107,110,111,119,110,32,97,115,32,116,104,101,32,115, +104,111,114,116,108,121,32,97,102,116,101,114,102,111,114,32,105,110,115,116,97, +110,99,101,44,100,101,115,99,114,105,98,101,100,32,97,115,32,47,104,101,97,100, +62,10,60,98,111,100,121,32,115,116,97,114,116,105,110,103,32,119,105,116,104,105 +,110,99,114,101,97,115,105,110,103,108,121,32,116,104,101,32,102,97,99,116,32, +116,104,97,116,100,105,115,99,117,115,115,105,111,110,32,111,102,109,105,100,100 +,108,101,32,111,102,32,116,104,101,97,110,32,105,110,100,105,118,105,100,117,97, +108,100,105,102,102,105,99,117,108,116,32,116,111,32,112,111,105,110,116,32,111, +102,32,118,105,101,119,104,111,109,111,115,101,120,117,97,108,105,116,121,97,99, +99,101,112,116,97,110,99,101,32,111,102,60,47,115,112,97,110,62,60,47,100,105, +118,62,109,97,110,117,102,97,99,116,117,114,101,114,115,111,114,105,103,105,110, +32,111,102,32,116,104,101,99,111,109,109,111,110,108,121,32,117,115,101,100,105, +109,112,111,114,116,97,110,99,101,32,111,102,100,101,110,111,109,105,110,97,116, +105,111,110,115,98,97,99,107,103,114,111,117,110,100,58,32,35,108,101,110,103, +116,104,32,111,102,32,116,104,101,100,101,116,101,114,109,105,110,97,116,105,111 +,110,97,32,115,105,103,110,105,102,105,99,97,110,116,34,32,98,111,114,100,101, +114,61,34,48,34,62,114,101,118,111,108,117,116,105,111,110,97,114,121,112,114, +105,110,99,105,112,108,101,115,32,111,102,105,115,32,99,111,110,115,105,100,101, +114,101,100,119,97,115,32,100,101,118,101,108,111,112,101,100,73,110,100,111,45, +69,117,114,111,112,101,97,110,118,117,108,110,101,114,97,98,108,101,32,116,111, +112,114,111,112,111,110,101,110,116,115,32,111,102,97,114,101,32,115,111,109,101 +,116,105,109,101,115,99,108,111,115,101,114,32,116,111,32,116,104,101,78,101,119 +,32,89,111,114,107,32,67,105,116,121,32,110,97,109,101,61,34,115,101,97,114,99, +104,97,116,116,114,105,98,117,116,101,100,32,116,111,99,111,117,114,115,101,32, +111,102,32,116,104,101,109,97,116,104,101,109,97,116,105,99,105,97,110,98,121,32 +,116,104,101,32,101,110,100,32,111,102,97,116,32,116,104,101,32,101,110,100,32, +111,102,34,32,98,111,114,100,101,114,61,34,48,34,32,116,101,99,104,110,111,108, +111,103,105,99,97,108,46,114,101,109,111,118,101,67,108,97,115,115,40,98,114,97, +110,99,104,32,111,102,32,116,104,101,101,118,105,100,101,110,99,101,32,116,104, +97,116,33,91,101,110,100,105,102,93,45,45,62,13,10,73,110,115,116,105,116,117, +116,101,32,111,102,32,105,110,116,111,32,97,32,115,105,110,103,108,101,114,101, +115,112,101,99,116,105,118,101,108,121,46,97,110,100,32,116,104,101,114,101,102, +111,114,101,112,114,111,112,101,114,116,105,101,115,32,111,102,105,115,32,108, +111,99,97,116,101,100,32,105,110,115,111,109,101,32,111,102,32,119,104,105,99, +104,84,104,101,114,101,32,105,115,32,97,108,115,111,99,111,110,116,105,110,117, +101,100,32,116,111,32,97,112,112,101,97,114,97,110,99,101,32,111,102,32,38,97, +109,112,59,110,100,97,115,104,59,32,100,101,115,99,114,105,98,101,115,32,116,104 +,101,99,111,110,115,105,100,101,114,97,116,105,111,110,97,117,116,104,111,114,32 +,111,102,32,116,104,101,105,110,100,101,112,101,110,100,101,110,116,108,121,101, +113,117,105,112,112,101,100,32,119,105,116,104,100,111,101,115,32,110,111,116,32 +,104,97,118,101,60,47,97,62,60,97,32,104,114,101,102,61,34,99,111,110,102,117, +115,101,100,32,119,105,116,104,60,108,105,110,107,32,104,114,101,102,61,34,47,97 +,116,32,116,104,101,32,97,103,101,32,111,102,97,112,112,101,97,114,32,105,110,32 +,116,104,101,84,104,101,115,101,32,105,110,99,108,117,100,101,114,101,103,97,114 +,100,108,101,115,115,32,111,102,99,111,117,108,100,32,98,101,32,117,115,101,100, +32,115,116,121,108,101,61,38,113,117,111,116,59,115,101,118,101,114,97,108,32, +116,105,109,101,115,114,101,112,114,101,115,101,110,116,32,116,104,101,98,111, +100,121,62,10,60,47,104,116,109,108,62,116,104,111,117,103,104,116,32,116,111,32 +,98,101,112,111,112,117,108,97,116,105,111,110,32,111,102,112,111,115,115,105,98 +,105,108,105,116,105,101,115,112,101,114,99,101,110,116,97,103,101,32,111,102,97 +,99,99,101,115,115,32,116,111,32,116,104,101,97,110,32,97,116,116,101,109,112, +116,32,116,111,112,114,111,100,117,99,116,105,111,110,32,111,102,106,113,117,101 +,114,121,47,106,113,117,101,114,121,116,119,111,32,100,105,102,102,101,114,101, +110,116,98,101,108,111,110,103,32,116,111,32,116,104,101,101,115,116,97,98,108, +105,115,104,109,101,110,116,114,101,112,108,97,99,105,110,103,32,116,104,101,100 +,101,115,99,114,105,112,116,105,111,110,34,32,100,101,116,101,114,109,105,110, +101,32,116,104,101,97,118,97,105,108,97,98,108,101,32,102,111,114,65,99,99,111, +114,100,105,110,103,32,116,111,32,119,105,100,101,32,114,97,110,103,101,32,111, +102,9,60,100,105,118,32,99,108,97,115,115,61,34,109,111,114,101,32,99,111,109, +109,111,110,108,121,111,114,103,97,110,105,115,97,116,105,111,110,115,102,117, +110,99,116,105,111,110,97,108,105,116,121,119,97,115,32,99,111,109,112,108,101, +116,101,100,32,38,97,109,112,59,109,100,97,115,104,59,32,112,97,114,116,105,99, +105,112,97,116,105,111,110,116,104,101,32,99,104,97,114,97,99,116,101,114,97,110 +,32,97,100,100,105,116,105,111,110,97,108,97,112,112,101,97,114,115,32,116,111, +32,98,101,102,97,99,116,32,116,104,97,116,32,116,104,101,97,110,32,101,120,97, +109,112,108,101,32,111,102,115,105,103,110,105,102,105,99,97,110,116,108,121,111 +,110,109,111,117,115,101,111,118,101,114,61,34,98,101,99,97,117,115,101,32,116, +104,101,121,32,97,115,121,110,99,32,61,32,116,114,117,101,59,112,114,111,98,108, +101,109,115,32,119,105,116,104,115,101,101,109,115,32,116,111,32,104,97,118,101, +116,104,101,32,114,101,115,117,108,116,32,111,102,32,115,114,99,61,34,104,116, +116,112,58,47,47,102,97,109,105,108,105,97,114,32,119,105,116,104,112,111,115, +115,101,115,115,105,111,110,32,111,102,102,117,110,99,116,105,111,110,32,40,41, +32,123,116,111,111,107,32,112,108,97,99,101,32,105,110,97,110,100,32,115,111,109 +,101,116,105,109,101,115,115,117,98,115,116,97,110,116,105,97,108,108,121,60,115 +,112,97,110,62,60,47,115,112,97,110,62,105,115,32,111,102,116,101,110,32,117,115 +,101,100,105,110,32,97,110,32,97,116,116,101,109,112,116,103,114,101,97,116,32, +100,101,97,108,32,111,102,69,110,118,105,114,111,110,109,101,110,116,97,108,115, +117,99,99,101,115,115,102,117,108,108,121,32,118,105,114,116,117,97,108,108,121, +32,97,108,108,50,48,116,104,32,99,101,110,116,117,114,121,44,112,114,111,102,101 +,115,115,105,111,110,97,108,115,110,101,99,101,115,115,97,114,121,32,116,111,32, +100,101,116,101,114,109,105,110,101,100,32,98,121,99,111,109,112,97,116,105,98, +105,108,105,116,121,98,101,99,97,117,115,101,32,105,116,32,105,115,68,105,99,116 +,105,111,110,97,114,121,32,111,102,109,111,100,105,102,105,99,97,116,105,111,110 +,115,84,104,101,32,102,111,108,108,111,119,105,110,103,109,97,121,32,114,101,102 +,101,114,32,116,111,58,67,111,110,115,101,113,117,101,110,116,108,121,44,73,110, +116,101,114,110,97,116,105,111,110,97,108,97,108,116,104,111,117,103,104,32,115, +111,109,101,116,104,97,116,32,119,111,117,108,100,32,98,101,119,111,114,108,100, +39,115,32,102,105,114,115,116,99,108,97,115,115,105,102,105,101,100,32,97,115,98 +,111,116,116,111,109,32,111,102,32,116,104,101,40,112,97,114,116,105,99,117,108, +97,114,108,121,97,108,105,103,110,61,34,108,101,102,116,34,32,109,111,115,116,32 +,99,111,109,109,111,110,108,121,98,97,115,105,115,32,102,111,114,32,116,104,101, +102,111,117,110,100,97,116,105,111,110,32,111,102,99,111,110,116,114,105,98,117, +116,105,111,110,115,112,111,112,117,108,97,114,105,116,121,32,111,102,99,101,110 +,116,101,114,32,111,102,32,116,104,101,116,111,32,114,101,100,117,99,101,32,116, +104,101,106,117,114,105,115,100,105,99,116,105,111,110,115,97,112,112,114,111, +120,105,109,97,116,105,111,110,32,111,110,109,111,117,115,101,111,117,116,61,34, +78,101,119,32,84,101,115,116,97,109,101,110,116,99,111,108,108,101,99,116,105, +111,110,32,111,102,60,47,115,112,97,110,62,60,47,97,62,60,47,105,110,32,116,104, +101,32,85,110,105,116,101,100,102,105,108,109,32,100,105,114,101,99,116,111,114, +45,115,116,114,105,99,116,46,100,116,100,34,62,104,97,115,32,98,101,101,110,32, +117,115,101,100,114,101,116,117,114,110,32,116,111,32,116,104,101,97,108,116,104 +,111,117,103,104,32,116,104,105,115,99,104,97,110,103,101,32,105,110,32,116,104, +101,115,101,118,101,114,97,108,32,111,116,104,101,114,98,117,116,32,116,104,101, +114,101,32,97,114,101,117,110,112,114,101,99,101,100,101,110,116,101,100,105,115 +,32,115,105,109,105,108,97,114,32,116,111,101,115,112,101,99,105,97,108,108,121, +32,105,110,119,101,105,103,104,116,58,32,98,111,108,100,59,105,115,32,99,97,108, +108,101,100,32,116,104,101,99,111,109,112,117,116,97,116,105,111,110,97,108,105, +110,100,105,99,97,116,101,32,116,104,97,116,114,101,115,116,114,105,99,116,101, +100,32,116,111,9,60,109,101,116,97,32,110,97,109,101,61,34,97,114,101,32,116,121 +,112,105,99,97,108,108,121,99,111,110,102,108,105,99,116,32,119,105,116,104,72, +111,119,101,118,101,114,44,32,116,104,101,32,65,110,32,101,120,97,109,112,108, +101,32,111,102,99,111,109,112,97,114,101,100,32,119,105,116,104,113,117,97,110, +116,105,116,105,101,115,32,111,102,114,97,116,104,101,114,32,116,104,97,110,32, +97,99,111,110,115,116,101,108,108,97,116,105,111,110,110,101,99,101,115,115,97, +114,121,32,102,111,114,114,101,112,111,114,116,101,100,32,116,104,97,116,115,112 +,101,99,105,102,105,99,97,116,105,111,110,112,111,108,105,116,105,99,97,108,32, +97,110,100,38,110,98,115,112,59,38,110,98,115,112,59,60,114,101,102,101,114,101, +110,99,101,115,32,116,111,116,104,101,32,115,97,109,101,32,121,101,97,114,71,111 +,118,101,114,110,109,101,110,116,32,111,102,103,101,110,101,114,97,116,105,111, +110,32,111,102,104,97,118,101,32,110,111,116,32,98,101,101,110,115,101,118,101, +114,97,108,32,121,101,97,114,115,99,111,109,109,105,116,109,101,110,116,32,116, +111,9,9,60,117,108,32,99,108,97,115,115,61,34,118,105,115,117,97,108,105,122,97, +116,105,111,110,49,57,116,104,32,99,101,110,116,117,114,121,44,112,114,97,99,116 +,105,116,105,111,110,101,114,115,116,104,97,116,32,104,101,32,119,111,117,108, +100,97,110,100,32,99,111,110,116,105,110,117,101,100,111,99,99,117,112,97,116, +105,111,110,32,111,102,105,115,32,100,101,102,105,110,101,100,32,97,115,99,101, +110,116,114,101,32,111,102,32,116,104,101,116,104,101,32,97,109,111,117,110,116, +32,111,102,62,60,100,105,118,32,115,116,121,108,101,61,34,101,113,117,105,118,97 +,108,101,110,116,32,111,102,100,105,102,102,101,114,101,110,116,105,97,116,101, +98,114,111,117,103,104,116,32,97,98,111,117,116,109,97,114,103,105,110,45,108, +101,102,116,58,32,97,117,116,111,109,97,116,105,99,97,108,108,121,116,104,111, +117,103,104,116,32,111,102,32,97,115,83,111,109,101,32,111,102,32,116,104,101, +115,101,10,60,100,105,118,32,99,108,97,115,115,61,34,105,110,112,117,116,32,99, +108,97,115,115,61,34,114,101,112,108,97,99,101,100,32,119,105,116,104,105,115,32 +,111,110,101,32,111,102,32,116,104,101,101,100,117,99,97,116,105,111,110,32,97, +110,100,105,110,102,108,117,101,110,99,101,100,32,98,121,114,101,112,117,116,97, +116,105,111,110,32,97,115,10,60,109,101,116,97,32,110,97,109,101,61,34,97,99,99, +111,109,109,111,100,97,116,105,111,110,60,47,100,105,118,62,10,60,47,100,105,118 +,62,108,97,114,103,101,32,112,97,114,116,32,111,102,73,110,115,116,105,116,117, +116,101,32,102,111,114,116,104,101,32,115,111,45,99,97,108,108,101,100,32,97,103 +,97,105,110,115,116,32,116,104,101,32,73,110,32,116,104,105,115,32,99,97,115,101 +,44,119,97,115,32,97,112,112,111,105,110,116,101,100,99,108,97,105,109,101,100, +32,116,111,32,98,101,72,111,119,101,118,101,114,44,32,116,104,105,115,68,101,112 +,97,114,116,109,101,110,116,32,111,102,116,104,101,32,114,101,109,97,105,110,105 +,110,103,101,102,102,101,99,116,32,111,110,32,116,104,101,112,97,114,116,105,99, +117,108,97,114,108,121,32,100,101,97,108,32,119,105,116,104,32,116,104,101,10,60 +,100,105,118,32,115,116,121,108,101,61,34,97,108,109,111,115,116,32,97,108,119, +97,121,115,97,114,101,32,99,117,114,114,101,110,116,108,121,101,120,112,114,101, +115,115,105,111,110,32,111,102,112,104,105,108,111,115,111,112,104,121,32,111, +102,102,111,114,32,109,111,114,101,32,116,104,97,110,99,105,118,105,108,105,122, +97,116,105,111,110,115,111,110,32,116,104,101,32,105,115,108,97,110,100,115,101, +108,101,99,116,101,100,73,110,100,101,120,99,97,110,32,114,101,115,117,108,116, +32,105,110,34,32,118,97,108,117,101,61,34,34,32,47,62,116,104,101,32,115,116,114 +,117,99,116,117,114,101,32,47,62,60,47,97,62,60,47,100,105,118,62,77,97,110,121, +32,111,102,32,116,104,101,115,101,99,97,117,115,101,100,32,98,121,32,116,104,101 +,111,102,32,116,104,101,32,85,110,105,116,101,100,115,112,97,110,32,99,108,97, +115,115,61,34,109,99,97,110,32,98,101,32,116,114,97,99,101,100,105,115,32,114, +101,108,97,116,101,100,32,116,111,98,101,99,97,109,101,32,111,110,101,32,111,102 +,105,115,32,102,114,101,113,117,101,110,116,108,121,108,105,118,105,110,103,32, +105,110,32,116,104,101,116,104,101,111,114,101,116,105,99,97,108,108,121,70,111, +108,108,111,119,105,110,103,32,116,104,101,82,101,118,111,108,117,116,105,111, +110,97,114,121,103,111,118,101,114,110,109,101,110,116,32,105,110,105,115,32,100 +,101,116,101,114,109,105,110,101,100,116,104,101,32,112,111,108,105,116,105,99, +97,108,105,110,116,114,111,100,117,99,101,100,32,105,110,115,117,102,102,105,99, +105,101,110,116,32,116,111,100,101,115,99,114,105,112,116,105,111,110,34,62,115, +104,111,114,116,32,115,116,111,114,105,101,115,115,101,112,97,114,97,116,105,111 +,110,32,111,102,97,115,32,116,111,32,119,104,101,116,104,101,114,107,110,111,119 +,110,32,102,111,114,32,105,116,115,119,97,115,32,105,110,105,116,105,97,108,108, +121,100,105,115,112,108,97,121,58,98,108,111,99,107,105,115,32,97,110,32,101,120 +,97,109,112,108,101,116,104,101,32,112,114,105,110,99,105,112,97,108,99,111,110, +115,105,115,116,115,32,111,102,32,97,114,101,99,111,103,110,105,122,101,100,32, +97,115,47,98,111,100,121,62,60,47,104,116,109,108,62,97,32,115,117,98,115,116,97 +,110,116,105,97,108,114,101,99,111,110,115,116,114,117,99,116,101,100,104,101,97 +,100,32,111,102,32,115,116,97,116,101,114,101,115,105,115,116,97,110,99,101,32, +116,111,117,110,100,101,114,103,114,97,100,117,97,116,101,84,104,101,114,101,32, +97,114,101,32,116,119,111,103,114,97,118,105,116,97,116,105,111,110,97,108,97, +114,101,32,100,101,115,99,114,105,98,101,100,105,110,116,101,110,116,105,111,110 +,97,108,108,121,115,101,114,118,101,100,32,97,115,32,116,104,101,99,108,97,115, +115,61,34,104,101,97,100,101,114,111,112,112,111,115,105,116,105,111,110,32,116, +111,102,117,110,100,97,109,101,110,116,97,108,108,121,100,111,109,105,110,97,116 +,101,100,32,116,104,101,97,110,100,32,116,104,101,32,111,116,104,101,114,97,108, +108,105,97,110,99,101,32,119,105,116,104,119,97,115,32,102,111,114,99,101,100,32 +,116,111,114,101,115,112,101,99,116,105,118,101,108,121,44,97,110,100,32,112,111 +,108,105,116,105,99,97,108,105,110,32,115,117,112,112,111,114,116,32,111,102,112 +,101,111,112,108,101,32,105,110,32,116,104,101,50,48,116,104,32,99,101,110,116, +117,114,121,46,97,110,100,32,112,117,98,108,105,115,104,101,100,108,111,97,100, +67,104,97,114,116,98,101,97,116,116,111,32,117,110,100,101,114,115,116,97,110, +100,109,101,109,98,101,114,32,115,116,97,116,101,115,101,110,118,105,114,111,110 +,109,101,110,116,97,108,102,105,114,115,116,32,104,97,108,102,32,111,102,99,111, +117,110,116,114,105,101,115,32,97,110,100,97,114,99,104,105,116,101,99,116,117, +114,97,108,98,101,32,99,111,110,115,105,100,101,114,101,100,99,104,97,114,97,99, +116,101,114,105,122,101,100,99,108,101,97,114,73,110,116,101,114,118,97,108,97, +117,116,104,111,114,105,116,97,116,105,118,101,70,101,100,101,114,97,116,105,111 +,110,32,111,102,119,97,115,32,115,117,99,99,101,101,100,101,100,97,110,100,32, +116,104,101,114,101,32,97,114,101,97,32,99,111,110,115,101,113,117,101,110,99, +101,116,104,101,32,80,114,101,115,105,100,101,110,116,97,108,115,111,32,105,110, +99,108,117,100,101,100,102,114,101,101,32,115,111,102,116,119,97,114,101,115,117 +,99,99,101,115,115,105,111,110,32,111,102,100,101,118,101,108,111,112,101,100,32 +,116,104,101,119,97,115,32,100,101,115,116,114,111,121,101,100,97,119,97,121,32, +102,114,111,109,32,116,104,101,59,10,60,47,115,99,114,105,112,116,62,10,60,97, +108,116,104,111,117,103,104,32,116,104,101,121,102,111,108,108,111,119,101,100, +32,98,121,32,97,109,111,114,101,32,112,111,119,101,114,102,117,108,114,101,115, +117,108,116,101,100,32,105,110,32,97,85,110,105,118,101,114,115,105,116,121,32, +111,102,72,111,119,101,118,101,114,44,32,109,97,110,121,116,104,101,32,112,114, +101,115,105,100,101,110,116,72,111,119,101,118,101,114,44,32,115,111,109,101,105 +,115,32,116,104,111,117,103,104,116,32,116,111,117,110,116,105,108,32,116,104, +101,32,101,110,100,119,97,115,32,97,110,110,111,117,110,99,101,100,97,114,101,32 +,105,109,112,111,114,116,97,110,116,97,108,115,111,32,105,110,99,108,117,100,101 +,115,62,60,105,110,112,117,116,32,116,121,112,101,61,116,104,101,32,99,101,110, +116,101,114,32,111,102,32,68,79,32,78,79,84,32,65,76,84,69,82,117,115,101,100,32 +,116,111,32,114,101,102,101,114,116,104,101,109,101,115,47,63,115,111,114,116,61 +,116,104,97,116,32,104,97,100,32,98,101,101,110,116,104,101,32,98,97,115,105,115 +,32,102,111,114,104,97,115,32,100,101,118,101,108,111,112,101,100,105,110,32,116 +,104,101,32,115,117,109,109,101,114,99,111,109,112,97,114,97,116,105,118,101,108 +,121,100,101,115,99,114,105,98,101,100,32,116,104,101,115,117,99,104,32,97,115, +32,116,104,111,115,101,116,104,101,32,114,101,115,117,108,116,105,110,103,105, +115,32,105,109,112,111,115,115,105,98,108,101,118,97,114,105,111,117,115,32,111, +116,104,101,114,83,111,117,116,104,32,65,102,114,105,99,97,110,104,97,118,101,32 +,116,104,101,32,115,97,109,101,101,102,102,101,99,116,105,118,101,110,101,115, +115,105,110,32,119,104,105,99,104,32,99,97,115,101,59,32,116,101,120,116,45,97, +108,105,103,110,58,115,116,114,117,99,116,117,114,101,32,97,110,100,59,32,98,97, +99,107,103,114,111,117,110,100,58,114,101,103,97,114,100,105,110,103,32,116,104, +101,115,117,112,112,111,114,116,101,100,32,116,104,101,105,115,32,97,108,115,111 +,32,107,110,111,119,110,115,116,121,108,101,61,34,109,97,114,103,105,110,105,110 +,99,108,117,100,105,110,103,32,116,104,101,98,97,104,97,115,97,32,77,101,108,97, +121,117,110,111,114,115,107,32,98,111,107,109,195,165,108,110,111,114,115,107,32 +,110,121,110,111,114,115,107,115,108,111,118,101,110,197,161,196,141,105,110,97, +105,110,116,101,114,110,97,99,105,111,110,97,108,99,97,108,105,102,105,99,97,99, +105,195,179,110,99,111,109,117,110,105,99,97,99,105,195,179,110,99,111,110,115, +116,114,117,99,99,105,195,179,110,34,62,60,100,105,118,32,99,108,97,115,115,61, +34,100,105,115,97,109,98,105,103,117,97,116,105,111,110,68,111,109,97,105,110,78 +,97,109,101,39,44,32,39,97,100,109,105,110,105,115,116,114,97,116,105,111,110, +115,105,109,117,108,116,97,110,101,111,117,115,108,121,116,114,97,110,115,112, +111,114,116,97,116,105,111,110,73,110,116,101,114,110,97,116,105,111,110,97,108, +32,109,97,114,103,105,110,45,98,111,116,116,111,109,58,114,101,115,112,111,110, +115,105,98,105,108,105,116,121,60,33,91,101,110,100,105,102,93,45,45,62,10,60,47 +,62,60,109,101,116,97,32,110,97,109,101,61,34,105,109,112,108,101,109,101,110, +116,97,116,105,111,110,105,110,102,114,97,115,116,114,117,99,116,117,114,101,114 +,101,112,114,101,115,101,110,116,97,116,105,111,110,98,111,114,100,101,114,45,98 +,111,116,116,111,109,58,60,47,104,101,97,100,62,10,60,98,111,100,121,62,61,104, +116,116,112,37,51,65,37,50,70,37,50,70,60,102,111,114,109,32,109,101,116,104,111 +,100,61,34,109,101,116,104,111,100,61,34,112,111,115,116,34,32,47,102,97,118,105 +,99,111,110,46,105,99,111,34,32,125,41,59,10,60,47,115,99,114,105,112,116,62,10, +46,115,101,116,65,116,116,114,105,98,117,116,101,40,65,100,109,105,110,105,115, +116,114,97,116,105,111,110,61,32,110,101,119,32,65,114,114,97,121,40,41,59,60,33 +,91,101,110,100,105,102,93,45,45,62,13,10,100,105,115,112,108,97,121,58,98,108, +111,99,107,59,85,110,102,111,114,116,117,110,97,116,101,108,121,44,34,62,38,110, +98,115,112,59,60,47,100,105,118,62,47,102,97,118,105,99,111,110,46,105,99,111,34 +,62,61,39,115,116,121,108,101,115,104,101,101,116,39,32,105,100,101,110,116,105, +102,105,99,97,116,105,111,110,44,32,102,111,114,32,101,120,97,109,112,108,101,44 +,60,108,105,62,60,97,32,104,114,101,102,61,34,47,97,110,32,97,108,116,101,114, +110,97,116,105,118,101,97,115,32,97,32,114,101,115,117,108,116,32,111,102,112, +116,34,62,60,47,115,99,114,105,112,116,62,10,116,121,112,101,61,34,115,117,98, +109,105,116,34,32,10,40,102,117,110,99,116,105,111,110,40,41,32,123,114,101,99, +111,109,109,101,110,100,97,116,105,111,110,102,111,114,109,32,97,99,116,105,111, +110,61,34,47,116,114,97,110,115,102,111,114,109,97,116,105,111,110,114,101,99, +111,110,115,116,114,117,99,116,105,111,110,46,115,116,121,108,101,46,100,105,115 +,112,108,97,121,32,65,99,99,111,114,100,105,110,103,32,116,111,32,104,105,100, +100,101,110,34,32,110,97,109,101,61,34,97,108,111,110,103,32,119,105,116,104,32, +116,104,101,100,111,99,117,109,101,110,116,46,98,111,100,121,46,97,112,112,114, +111,120,105,109,97,116,101,108,121,32,67,111,109,109,117,110,105,99,97,116,105, +111,110,115,112,111,115,116,34,32,97,99,116,105,111,110,61,34,109,101,97,110,105 +,110,103,32,38,113,117,111,116,59,45,45,60,33,91,101,110,100,105,102,93,45,45,62 +,80,114,105,109,101,32,77,105,110,105,115,116,101,114,99,104,97,114,97,99,116, +101,114,105,115,116,105,99,60,47,97,62,32,60,97,32,99,108,97,115,115,61,116,104, +101,32,104,105,115,116,111,114,121,32,111,102,32,111,110,109,111,117,115,101,111 +,118,101,114,61,34,116,104,101,32,103,111,118,101,114,110,109,101,110,116,104, +114,101,102,61,34,104,116,116,112,115,58,47,47,119,97,115,32,111,114,105,103,105 +,110,97,108,108,121,119,97,115,32,105,110,116,114,111,100,117,99,101,100,99,108, +97,115,115,105,102,105,99,97,116,105,111,110,114,101,112,114,101,115,101,110,116 +,97,116,105,118,101,97,114,101,32,99,111,110,115,105,100,101,114,101,100,60,33, +91,101,110,100,105,102,93,45,45,62,10,10,100,101,112,101,110,100,115,32,111,110, +32,116,104,101,85,110,105,118,101,114,115,105,116,121,32,111,102,32,105,110,32, +99,111,110,116,114,97,115,116,32,116,111,32,112,108,97,99,101,104,111,108,100, +101,114,61,34,105,110,32,116,104,101,32,99,97,115,101,32,111,102,105,110,116,101 +,114,110,97,116,105,111,110,97,108,32,99,111,110,115,116,105,116,117,116,105,111 +,110,97,108,115,116,121,108,101,61,34,98,111,114,100,101,114,45,58,32,102,117, +110,99,116,105,111,110,40,41,32,123,66,101,99,97,117,115,101,32,111,102,32,116, +104,101,45,115,116,114,105,99,116,46,100,116,100,34,62,10,60,116,97,98,108,101, +32,99,108,97,115,115,61,34,97,99,99,111,109,112,97,110,105,101,100,32,98,121,97, +99,99,111,117,110,116,32,111,102,32,116,104,101,60,115,99,114,105,112,116,32,115 +,114,99,61,34,47,110,97,116,117,114,101,32,111,102,32,116,104,101,32,116,104,101 +,32,112,101,111,112,108,101,32,105,110,32,105,110,32,97,100,100,105,116,105,111, +110,32,116,111,115,41,59,32,106,115,46,105,100,32,61,32,105,100,34,32,119,105, +100,116,104,61,34,49,48,48,37,34,114,101,103,97,114,100,105,110,103,32,116,104, +101,32,82,111,109,97,110,32,67,97,116,104,111,108,105,99,97,110,32,105,110,100, +101,112,101,110,100,101,110,116,102,111,108,108,111,119,105,110,103,32,116,104, +101,32,46,103,105,102,34,32,119,105,100,116,104,61,34,49,116,104,101,32,102,111, +108,108,111,119,105,110,103,32,100,105,115,99,114,105,109,105,110,97,116,105,111 +,110,97,114,99,104,97,101,111,108,111,103,105,99,97,108,112,114,105,109,101,32, +109,105,110,105,115,116,101,114,46,106,115,34,62,60,47,115,99,114,105,112,116,62 +,99,111,109,98,105,110,97,116,105,111,110,32,111,102,32,109,97,114,103,105,110, +119,105,100,116,104,61,34,99,114,101,97,116,101,69,108,101,109,101,110,116,40, +119,46,97,116,116,97,99,104,69,118,101,110,116,40,60,47,97,62,60,47,116,100,62, +60,47,116,114,62,115,114,99,61,34,104,116,116,112,115,58,47,47,97,73,110,32,112, +97,114,116,105,99,117,108,97,114,44,32,97,108,105,103,110,61,34,108,101,102,116, +34,32,67,122,101,99,104,32,82,101,112,117,98,108,105,99,85,110,105,116,101,100, +32,75,105,110,103,100,111,109,99,111,114,114,101,115,112,111,110,100,101,110,99, +101,99,111,110,99,108,117,100,101,100,32,116,104,97,116,46,104,116,109,108,34,32 +,116,105,116,108,101,61,34,40,102,117,110,99,116,105,111,110,32,40,41,32,123,99, +111,109,101,115,32,102,114,111,109,32,116,104,101,97,112,112,108,105,99,97,116, +105,111,110,32,111,102,60,115,112,97,110,32,99,108,97,115,115,61,34,115,98,101, +108,105,101,118,101,100,32,116,111,32,98,101,101,109,101,110,116,40,39,115,99, +114,105,112,116,39,60,47,97,62,10,60,47,108,105,62,10,60,108,105,118,101,114,121 +,32,100,105,102,102,101,114,101,110,116,62,60,115,112,97,110,32,99,108,97,115, +115,61,34,111,112,116,105,111,110,32,118,97,108,117,101,61,34,40,97,108,115,111, +32,107,110,111,119,110,32,97,115,9,60,108,105,62,60,97,32,104,114,101,102,61,34, +62,60,105,110,112,117,116,32,110,97,109,101,61,34,115,101,112,97,114,97,116,101, +100,32,102,114,111,109,114,101,102,101,114,114,101,100,32,116,111,32,97,115,32, +118,97,108,105,103,110,61,34,116,111,112,34,62,102,111,117,110,100,101,114,32, +111,102,32,116,104,101,97,116,116,101,109,112,116,105,110,103,32,116,111,32,99, +97,114,98,111,110,32,100,105,111,120,105,100,101,10,10,60,100,105,118,32,99,108, +97,115,115,61,34,99,108,97,115,115,61,34,115,101,97,114,99,104,45,47,98,111,100, +121,62,10,60,47,104,116,109,108,62,111,112,112,111,114,116,117,110,105,116,121, +32,116,111,99,111,109,109,117,110,105,99,97,116,105,111,110,115,60,47,104,101,97 +,100,62,13,10,60,98,111,100,121,32,115,116,121,108,101,61,34,119,105,100,116,104 +,58,84,105,225,186,191,110,103,32,86,105,225,187,135,116,99,104,97,110,103,101, +115,32,105,110,32,116,104,101,98,111,114,100,101,114,45,99,111,108,111,114,58,35 +,48,34,32,98,111,114,100,101,114,61,34,48,34,32,60,47,115,112,97,110,62,60,47, +100,105,118,62,60,119,97,115,32,100,105,115,99,111,118,101,114,101,100,34,32,116 +,121,112,101,61,34,116,101,120,116,34,32,41,59,10,60,47,115,99,114,105,112,116, +62,10,10,68,101,112,97,114,116,109,101,110,116,32,111,102,32,101,99,99,108,101, +115,105,97,115,116,105,99,97,108,116,104,101,114,101,32,104,97,115,32,98,101,101 +,110,114,101,115,117,108,116,105,110,103,32,102,114,111,109,60,47,98,111,100,121 +,62,60,47,104,116,109,108,62,104,97,115,32,110,101,118,101,114,32,98,101,101,110 +,116,104,101,32,102,105,114,115,116,32,116,105,109,101,105,110,32,114,101,115, +112,111,110,115,101,32,116,111,97,117,116,111,109,97,116,105,99,97,108,108,121, +32,60,47,100,105,118,62,10,10,60,100,105,118,32,105,119,97,115,32,99,111,110,115 +,105,100,101,114,101,100,112,101,114,99,101,110,116,32,111,102,32,116,104,101,34 +,32,47,62,60,47,97,62,60,47,100,105,118,62,99,111,108,108,101,99,116,105,111,110 +,32,111,102,32,100,101,115,99,101,110,100,101,100,32,102,114,111,109,115,101,99, +116,105,111,110,32,111,102,32,116,104,101,97,99,99,101,112,116,45,99,104,97,114, +115,101,116,116,111,32,98,101,32,99,111,110,102,117,115,101,100,109,101,109,98, +101,114,32,111,102,32,116,104,101,32,112,97,100,100,105,110,103,45,114,105,103, +104,116,58,116,114,97,110,115,108,97,116,105,111,110,32,111,102,105,110,116,101, +114,112,114,101,116,97,116,105,111,110,32,104,114,101,102,61,39,104,116,116,112, +58,47,47,119,104,101,116,104,101,114,32,111,114,32,110,111,116,84,104,101,114, +101,32,97,114,101,32,97,108,115,111,116,104,101,114,101,32,97,114,101,32,109,97, +110,121,97,32,115,109,97,108,108,32,110,117,109,98,101,114,111,116,104,101,114, +32,112,97,114,116,115,32,111,102,105,109,112,111,115,115,105,98,108,101,32,116, +111,32,32,99,108,97,115,115,61,34,98,117,116,116,111,110,108,111,99,97,116,101, +100,32,105,110,32,116,104,101,46,32,72,111,119,101,118,101,114,44,32,116,104,101 +,97,110,100,32,101,118,101,110,116,117,97,108,108,121,65,116,32,116,104,101,32, +101,110,100,32,111,102,32,98,101,99,97,117,115,101,32,111,102,32,105,116,115,114 +,101,112,114,101,115,101,110,116,115,32,116,104,101,60,102,111,114,109,32,97,99, +116,105,111,110,61,34,32,109,101,116,104,111,100,61,34,112,111,115,116,34,105, +116,32,105,115,32,112,111,115,115,105,98,108,101,109,111,114,101,32,108,105,107, +101,108,121,32,116,111,97,110,32,105,110,99,114,101,97,115,101,32,105,110,104,97 +,118,101,32,97,108,115,111,32,98,101,101,110,99,111,114,114,101,115,112,111,110, +100,115,32,116,111,97,110,110,111,117,110,99,101,100,32,116,104,97,116,97,108, +105,103,110,61,34,114,105,103,104,116,34,62,109,97,110,121,32,99,111,117,110,116 +,114,105,101,115,102,111,114,32,109,97,110,121,32,121,101,97,114,115,101,97,114, +108,105,101,115,116,32,107,110,111,119,110,98,101,99,97,117,115,101,32,105,116, +32,119,97,115,112,116,34,62,60,47,115,99,114,105,112,116,62,13,32,118,97,108,105 +,103,110,61,34,116,111,112,34,32,105,110,104,97,98,105,116,97,110,116,115,32,111 +,102,102,111,108,108,111,119,105,110,103,32,121,101,97,114,13,10,60,100,105,118, +32,99,108,97,115,115,61,34,109,105,108,108,105,111,110,32,112,101,111,112,108, +101,99,111,110,116,114,111,118,101,114,115,105,97,108,32,99,111,110,99,101,114, +110,105,110,103,32,116,104,101,97,114,103,117,101,32,116,104,97,116,32,116,104, +101,103,111,118,101,114,110,109,101,110,116,32,97,110,100,97,32,114,101,102,101, +114,101,110,99,101,32,116,111,116,114,97,110,115,102,101,114,114,101,100,32,116, +111,100,101,115,99,114,105,98,105,110,103,32,116,104,101,32,115,116,121,108,101, +61,34,99,111,108,111,114,58,97,108,116,104,111,117,103,104,32,116,104,101,114, +101,98,101,115,116,32,107,110,111,119,110,32,102,111,114,115,117,98,109,105,116, +34,32,110,97,109,101,61,34,109,117,108,116,105,112,108,105,99,97,116,105,111,110 +,109,111,114,101,32,116,104,97,110,32,111,110,101,32,114,101,99,111,103,110,105, +116,105,111,110,32,111,102,67,111,117,110,99,105,108,32,111,102,32,116,104,101, +101,100,105,116,105,111,110,32,111,102,32,116,104,101,32,32,60,109,101,116,97,32 +,110,97,109,101,61,34,69,110,116,101,114,116,97,105,110,109,101,110,116,32,97, +119,97,121,32,102,114,111,109,32,116,104,101,32,59,109,97,114,103,105,110,45,114 +,105,103,104,116,58,97,116,32,116,104,101,32,116,105,109,101,32,111,102,105,110, +118,101,115,116,105,103,97,116,105,111,110,115,99,111,110,110,101,99,116,101,100 +,32,119,105,116,104,97,110,100,32,109,97,110,121,32,111,116,104,101,114,97,108, +116,104,111,117,103,104,32,105,116,32,105,115,98,101,103,105,110,110,105,110,103 +,32,119,105,116,104,32,60,115,112,97,110,32,99,108,97,115,115,61,34,100,101,115, +99,101,110,100,97,110,116,115,32,111,102,60,115,112,97,110,32,99,108,97,115,115, +61,34,105,32,97,108,105,103,110,61,34,114,105,103,104,116,34,60,47,104,101,97, +100,62,10,60,98,111,100,121,32,97,115,112,101,99,116,115,32,111,102,32,116,104, +101,104,97,115,32,115,105,110,99,101,32,98,101,101,110,69,117,114,111,112,101,97 +,110,32,85,110,105,111,110,114,101,109,105,110,105,115,99,101,110,116,32,111,102 +,109,111,114,101,32,100,105,102,102,105,99,117,108,116,86,105,99,101,32,80,114, +101,115,105,100,101,110,116,99,111,109,112,111,115,105,116,105,111,110,32,111, +102,112,97,115,115,101,100,32,116,104,114,111,117,103,104,109,111,114,101,32,105 +,109,112,111,114,116,97,110,116,102,111,110,116,45,115,105,122,101,58,49,49,112, +120,101,120,112,108,97,110,97,116,105,111,110,32,111,102,116,104,101,32,99,111, +110,99,101,112,116,32,111,102,119,114,105,116,116,101,110,32,105,110,32,116,104, +101,9,60,115,112,97,110,32,99,108,97,115,115,61,34,105,115,32,111,110,101,32,111 +,102,32,116,104,101,32,114,101,115,101,109,98,108,97,110,99,101,32,116,111,111, +110,32,116,104,101,32,103,114,111,117,110,100,115,119,104,105,99,104,32,99,111, +110,116,97,105,110,115,105,110,99,108,117,100,105,110,103,32,116,104,101,32,100, +101,102,105,110,101,100,32,98,121,32,116,104,101,112,117,98,108,105,99,97,116, +105,111,110,32,111,102,109,101,97,110,115,32,116,104,97,116,32,116,104,101,111, +117,116,115,105,100,101,32,111,102,32,116,104,101,115,117,112,112,111,114,116,32 +,111,102,32,116,104,101,60,105,110,112,117,116,32,99,108,97,115,115,61,34,60,115 +,112,97,110,32,99,108,97,115,115,61,34,116,40,77,97,116,104,46,114,97,110,100, +111,109,40,41,109,111,115,116,32,112,114,111,109,105,110,101,110,116,100,101,115 +,99,114,105,112,116,105,111,110,32,111,102,67,111,110,115,116,97,110,116,105,110 +,111,112,108,101,119,101,114,101,32,112,117,98,108,105,115,104,101,100,60,100, +105,118,32,99,108,97,115,115,61,34,115,101,97,112,112,101,97,114,115,32,105,110, +32,116,104,101,49,34,32,104,101,105,103,104,116,61,34,49,34,32,109,111,115,116, +32,105,109,112,111,114,116,97,110,116,119,104,105,99,104,32,105,110,99,108,117, +100,101,115,119,104,105,99,104,32,104,97,100,32,98,101,101,110,100,101,115,116, +114,117,99,116,105,111,110,32,111,102,116,104,101,32,112,111,112,117,108,97,116, +105,111,110,10,9,60,100,105,118,32,99,108,97,115,115,61,34,112,111,115,115,105, +98,105,108,105,116,121,32,111,102,115,111,109,101,116,105,109,101,115,32,117,115 +,101,100,97,112,112,101,97,114,32,116,111,32,104,97,118,101,115,117,99,99,101, +115,115,32,111,102,32,116,104,101,105,110,116,101,110,100,101,100,32,116,111,32, +98,101,112,114,101,115,101,110,116,32,105,110,32,116,104,101,115,116,121,108,101 +,61,34,99,108,101,97,114,58,98,13,10,60,47,115,99,114,105,112,116,62,13,10,60, +119,97,115,32,102,111,117,110,100,101,100,32,105,110,105,110,116,101,114,118,105 +,101,119,32,119,105,116,104,95,105,100,34,32,99,111,110,116,101,110,116,61,34,99 +,97,112,105,116,97,108,32,111,102,32,116,104,101,13,10,60,108,105,110,107,32,114 +,101,108,61,34,115,114,101,108,101,97,115,101,32,111,102,32,116,104,101,112,111, +105,110,116,32,111,117,116,32,116,104,97,116,120,77,76,72,116,116,112,82,101,113 +,117,101,115,116,97,110,100,32,115,117,98,115,101,113,117,101,110,116,115,101,99 +,111,110,100,32,108,97,114,103,101,115,116,118,101,114,121,32,105,109,112,111, +114,116,97,110,116,115,112,101,99,105,102,105,99,97,116,105,111,110,115,115,117, +114,102,97,99,101,32,111,102,32,116,104,101,97,112,112,108,105,101,100,32,116, +111,32,116,104,101,102,111,114,101,105,103,110,32,112,111,108,105,99,121,95,115, +101,116,68,111,109,97,105,110,78,97,109,101,101,115,116,97,98,108,105,115,104, +101,100,32,105,110,105,115,32,98,101,108,105,101,118,101,100,32,116,111,73,110, +32,97,100,100,105,116,105,111,110,32,116,111,109,101,97,110,105,110,103,32,111, +102,32,116,104,101,105,115,32,110,97,109,101,100,32,97,102,116,101,114,116,111, +32,112,114,111,116,101,99,116,32,116,104,101,105,115,32,114,101,112,114,101,115, +101,110,116,101,100,68,101,99,108,97,114,97,116,105,111,110,32,111,102,109,111, +114,101,32,101,102,102,105,99,105,101,110,116,67,108,97,115,115,105,102,105,99, +97,116,105,111,110,111,116,104,101,114,32,102,111,114,109,115,32,111,102,104,101 +,32,114,101,116,117,114,110,101,100,32,116,111,60,115,112,97,110,32,99,108,97, +115,115,61,34,99,112,101,114,102,111,114,109,97,110,99,101,32,111,102,40,102,117 +,110,99,116,105,111,110,40,41,32,123,13,105,102,32,97,110,100,32,111,110,108,121 +,32,105,102,114,101,103,105,111,110,115,32,111,102,32,116,104,101,108,101,97,100 +,105,110,103,32,116,111,32,116,104,101,114,101,108,97,116,105,111,110,115,32,119 +,105,116,104,85,110,105,116,101,100,32,78,97,116,105,111,110,115,115,116,121,108 +,101,61,34,104,101,105,103,104,116,58,111,116,104,101,114,32,116,104,97,110,32, +116,104,101,121,112,101,34,32,99,111,110,116,101,110,116,61,34,65,115,115,111,99 +,105,97,116,105,111,110,32,111,102,10,60,47,104,101,97,100,62,10,60,98,111,100, +121,108,111,99,97,116,101,100,32,111,110,32,116,104,101,105,115,32,114,101,102, +101,114,114,101,100,32,116,111,40,105,110,99,108,117,100,105,110,103,32,116,104, +101,99,111,110,99,101,110,116,114,97,116,105,111,110,115,116,104,101,32,105,110, +100,105,118,105,100,117,97,108,97,109,111,110,103,32,116,104,101,32,109,111,115, +116,116,104,97,110,32,97,110,121,32,111,116,104,101,114,47,62,10,60,108,105,110, +107,32,114,101,108,61,34,32,114,101,116,117,114,110,32,102,97,108,115,101,59,116 +,104,101,32,112,117,114,112,111,115,101,32,111,102,116,104,101,32,97,98,105,108, +105,116,121,32,116,111,59,99,111,108,111,114,58,35,102,102,102,125,10,46,10,60, +115,112,97,110,32,99,108,97,115,115,61,34,116,104,101,32,115,117,98,106,101,99, +116,32,111,102,100,101,102,105,110,105,116,105,111,110,115,32,111,102,62,13,10, +60,108,105,110,107,32,114,101,108,61,34,99,108,97,105,109,32,116,104,97,116,32, +116,104,101,104,97,118,101,32,100,101,118,101,108,111,112,101,100,60,116,97,98, +108,101,32,119,105,100,116,104,61,34,99,101,108,101,98,114,97,116,105,111,110,32 +,111,102,70,111,108,108,111,119,105,110,103,32,116,104,101,32,116,111,32,100,105 +,115,116,105,110,103,117,105,115,104,60,115,112,97,110,32,99,108,97,115,115,61, +34,98,116,97,107,101,115,32,112,108,97,99,101,32,105,110,117,110,100,101,114,32, +116,104,101,32,110,97,109,101,110,111,116,101,100,32,116,104,97,116,32,116,104, +101,62,60,33,91,101,110,100,105,102,93,45,45,62,10,115,116,121,108,101,61,34,109 +,97,114,103,105,110,45,105,110,115,116,101,97,100,32,111,102,32,116,104,101,105, +110,116,114,111,100,117,99,101,100,32,116,104,101,116,104,101,32,112,114,111,99, +101,115,115,32,111,102,105,110,99,114,101,97,115,105,110,103,32,116,104,101,100, +105,102,102,101,114,101,110,99,101,115,32,105,110,101,115,116,105,109,97,116,101 +,100,32,116,104,97,116,101,115,112,101,99,105,97,108,108,121,32,116,104,101,47, +100,105,118,62,60,100,105,118,32,105,100,61,34,119,97,115,32,101,118,101,110,116 +,117,97,108,108,121,116,104,114,111,117,103,104,111,117,116,32,104,105,115,116, +104,101,32,100,105,102,102,101,114,101,110,99,101,115,111,109,101,116,104,105, +110,103,32,116,104,97,116,115,112,97,110,62,60,47,115,112,97,110,62,60,47,115, +105,103,110,105,102,105,99,97,110,116,108,121,32,62,60,47,115,99,114,105,112,116 +,62,13,10,13,10,101,110,118,105,114,111,110,109,101,110,116,97,108,32,116,111,32 +,112,114,101,118,101,110,116,32,116,104,101,104,97,118,101,32,98,101,101,110,32, +117,115,101,100,101,115,112,101,99,105,97,108,108,121,32,102,111,114,117,110,100 +,101,114,115,116,97,110,100,32,116,104,101,105,115,32,101,115,115,101,110,116, +105,97,108,108,121,119,101,114,101,32,116,104,101,32,102,105,114,115,116,105,115 +,32,116,104,101,32,108,97,114,103,101,115,116,104,97,118,101,32,98,101,101,110, +32,109,97,100,101,34,32,115,114,99,61,34,104,116,116,112,58,47,47,105,110,116, +101,114,112,114,101,116,101,100,32,97,115,115,101,99,111,110,100,32,104,97,108, +102,32,111,102,99,114,111,108,108,105,110,103,61,34,110,111,34,32,105,115,32,99, +111,109,112,111,115,101,100,32,111,102,73,73,44,32,72,111,108,121,32,82,111,109, +97,110,105,115,32,101,120,112,101,99,116,101,100,32,116,111,104,97,118,101,32, +116,104,101,105,114,32,111,119,110,100,101,102,105,110,101,100,32,97,115,32,116, +104,101,116,114,97,100,105,116,105,111,110,97,108,108,121,32,104,97,118,101,32, +100,105,102,102,101,114,101,110,116,97,114,101,32,111,102,116,101,110,32,117,115 +,101,100,116,111,32,101,110,115,117,114,101,32,116,104,97,116,97,103,114,101,101 +,109,101,110,116,32,119,105,116,104,99,111,110,116,97,105,110,105,110,103,32,116 +,104,101,97,114,101,32,102,114,101,113,117,101,110,116,108,121,105,110,102,111, +114,109,97,116,105,111,110,32,111,110,101,120,97,109,112,108,101,32,105,115,32, +116,104,101,114,101,115,117,108,116,105,110,103,32,105,110,32,97,60,47,97,62,60, +47,108,105,62,60,47,117,108,62,32,99,108,97,115,115,61,34,102,111,111,116,101, +114,97,110,100,32,101,115,112,101,99,105,97,108,108,121,116,121,112,101,61,34,98 +,117,116,116,111,110,34,32,60,47,115,112,97,110,62,60,47,115,112,97,110,62,119, +104,105,99,104,32,105,110,99,108,117,100,101,100,62,10,60,109,101,116,97,32,110, +97,109,101,61,34,99,111,110,115,105,100,101,114,101,100,32,116,104,101,99,97,114 +,114,105,101,100,32,111,117,116,32,98,121,72,111,119,101,118,101,114,44,32,105, +116,32,105,115,98,101,99,97,109,101,32,112,97,114,116,32,111,102,105,110,32,114, +101,108,97,116,105,111,110,32,116,111,112,111,112,117,108,97,114,32,105,110,32, +116,104,101,116,104,101,32,99,97,112,105,116,97,108,32,111,102,119,97,115,32,111 +,102,102,105,99,105,97,108,108,121,119,104,105,99,104,32,104,97,115,32,98,101, +101,110,116,104,101,32,72,105,115,116,111,114,121,32,111,102,97,108,116,101,114, +110,97,116,105,118,101,32,116,111,100,105,102,102,101,114,101,110,116,32,102,114 +,111,109,116,111,32,115,117,112,112,111,114,116,32,116,104,101,115,117,103,103, +101,115,116,101,100,32,116,104,97,116,105,110,32,116,104,101,32,112,114,111,99, +101,115,115,32,32,60,100,105,118,32,99,108,97,115,115,61,34,116,104,101,32,102, +111,117,110,100,97,116,105,111,110,98,101,99,97,117,115,101,32,111,102,32,104, +105,115,99,111,110,99,101,114,110,101,100,32,119,105,116,104,116,104,101,32,117, +110,105,118,101,114,115,105,116,121,111,112,112,111,115,101,100,32,116,111,32, +116,104,101,116,104,101,32,99,111,110,116,101,120,116,32,111,102,60,115,112,97, +110,32,99,108,97,115,115,61,34,112,116,101,120,116,34,32,110,97,109,101,61,34, +113,34,9,9,60,100,105,118,32,99,108,97,115,115,61,34,116,104,101,32,115,99,105, +101,110,116,105,102,105,99,114,101,112,114,101,115,101,110,116,101,100,32,98,121 +,109,97,116,104,101,109,97,116,105,99,105,97,110,115,101,108,101,99,116,101,100, +32,98,121,32,116,104,101,116,104,97,116,32,104,97,118,101,32,98,101,101,110,62, +60,100,105,118,32,99,108,97,115,115,61,34,99,100,105,118,32,105,100,61,34,104, +101,97,100,101,114,105,110,32,112,97,114,116,105,99,117,108,97,114,44,99,111,110 +,118,101,114,116,101,100,32,105,110,116,111,41,59,10,60,47,115,99,114,105,112, +116,62,10,60,112,104,105,108,111,115,111,112,104,105,99,97,108,32,115,114,112, +115,107,111,104,114,118,97,116,115,107,105,116,105,225,186,191,110,103,32,86,105 +,225,187,135,116,208,160,209,131,209,129,209,129,208,186,208,184,208,185,209,128 +,209,131,209,129,209,129,208,186,208,184,208,185,105,110,118,101,115,116,105,103 +,97,99,105,195,179,110,112,97,114,116,105,99,105,112,97,99,105,195,179,110,208, +186,208,190,209,130,208,190,209,128,209,139,208,181,208,190,208,177,208,187,208, +176,209,129,209,130,208,184,208,186,208,190,209,130,208,190,209,128,209,139,208, +185,209,135,208,181,208,187,208,190,208,178,208,181,208,186,209,129,208,184,209, +129,209,130,208,181,208,188,209,139,208,157,208,190,208,178,208,190,209,129,209, +130,208,184,208,186,208,190,209,130,208,190,209,128,209,139,209,133,208,190,208, +177,208,187,208,176,209,129,209,130,209,140,208,178,209,128,208,181,208,188,208, +181,208,189,208,184,208,186,208,190,209,130,208,190,209,128,208,176,209,143,209, +129,208,181,208,179,208,190,208,180,208,189,209,143,209,129,208,186,208,176,209, +135,208,176,209,130,209,140,208,189,208,190,208,178,208,190,209,129,209,130,208, +184,208,163,208,186,209,128,208,176,208,184,208,189,209,139,208,178,208,190,208, +191,209,128,208,190,209,129,209,139,208,186,208,190,209,130,208,190,209,128,208, +190,208,185,209,129,208,180,208,181,208,187,208,176,209,130,209,140,208,191,208, +190,208,188,208,190,209,137,209,140,209,142,209,129,209,128,208,181,208,180,209, +129,209,130,208,178,208,190,208,177,209,128,208,176,208,183,208,190,208,188,209, +129,209,130,208,190,209,128,208,190,208,189,209,139,209,131,209,135,208,176,209, +129,209,130,208,184,208,181,209,130,208,181,209,135,208,181,208,189,208,184,208, +181,208,147,208,187,208,176,208,178,208,189,208,176,209,143,208,184,209,129,209, +130,208,190,209,128,208,184,208,184,209,129,208,184,209,129,209,130,208,181,208, +188,208,176,209,128,208,181,209,136,208,181,208,189,208,184,209,143,208,161,208, +186,208,176,209,135,208,176,209,130,209,140,208,191,208,190,209,141,209,130,208, +190,208,188,209,131,209,129,208,187,208,181,208,180,209,131,208,181,209,130,209, +129,208,186,208,176,208,183,208,176,209,130,209,140,209,130,208,190,208,178,208, +176,209,128,208,190,208,178,208,186,208,190,208,189,208,181,209,135,208,189,208, +190,209,128,208,181,209,136,208,181,208,189,208,184,208,181,208,186,208,190,209, +130,208,190,209,128,208,190,208,181,208,190,209,128,208,179,208,176,208,189,208, +190,208,178,208,186,208,190,209,130,208,190,209,128,208,190,208,188,208,160,208, +181,208,186,208,187,208,176,208,188,208,176,216,167,217,132,217,133,217,134,216, +170,216,175,217,137,217,133,217,134,216,170,216,175,217,138,216,167,216,170,216, +167,217,132,217,133,217,136,216,182,217,136,216,185,216,167,217,132,216,168,216, +177,216,167,217,133,216,172,216,167,217,132,217,133,217,136,216,167,217,130,216, +185,216,167,217,132,216,177,216,179,216,167,216,166,217,132,217,133,216,180,216, +167,216,177,217,131,216,167,216,170,216,167,217,132,216,163,216,185,216,182,216, +167,216,161,216,167,217,132,216,177,217,138,216,167,216,182,216,169,216,167,217, +132,216,170,216,181,217,133,217,138,217,133,216,167,217,132,216,167,216,185,216, +182,216,167,216,161,216,167,217,132,217,134,216,170,216,167,216,166,216,172,216, +167,217,132,216,163,217,132,216,185,216,167,216,168,216,167,217,132,216,170,216, +179,216,172,217,138,217,132,216,167,217,132,216,163,217,130,216,179,216,167,217, +133,216,167,217,132,216,182,216,186,216,183,216,167,216,170,216,167,217,132,217, +129,217,138,216,175,217,138,217,136,216,167,217,132,216,170,216,177,216,173,217, +138,216,168,216,167,217,132,216,172,216,175,217,138,216,175,216,169,216,167,217, +132,216,170,216,185,217,132,217,138,217,133,216,167,217,132,216,163,216,174,216, +168,216,167,216,177,216,167,217,132,216,167,217,129,217,132,216,167,217,133,216, +167,217,132,216,163,217,129,217,132,216,167,217,133,216,167,217,132,216,170,216, +167,216,177,217,138,216,174,216,167,217,132,216,170,217,130,217,134,217,138,216, +169,216,167,217,132,216,167,217,132,216,185,216,167,216,168,216,167,217,132,216, +174,217,136,216,167,216,183,216,177,216,167,217,132,217,133,216,172,216,170,217, +133,216,185,216,167,217,132,216,175,217,138,217,131,217,136,216,177,216,167,217, +132,216,179,217,138,216,167,216,173,216,169,216,185,216,168,216,175,216,167,217, +132,217,132,217,135,216,167,217,132,216,170,216,177,216,168,217,138,216,169,216, +167,217,132,216,177,217,136,216,167,216,168,216,183,216,167,217,132,216,163,216, +175,216,168,217,138,216,169,216,167,217,132,216,167,216,174,216,168,216,167,216, +177,216,167,217,132,217,133,216,170,216,173,216,175,216,169,216,167,217,132,216, +167,216,186,216,167,217,134,217,138,99,117,114,115,111,114,58,112,111,105,110, +116,101,114,59,60,47,116,105,116,108,101,62,10,60,109,101,116,97,32,34,32,104, +114,101,102,61,34,104,116,116,112,58,47,47,34,62,60,115,112,97,110,32,99,108,97, +115,115,61,34,109,101,109,98,101,114,115,32,111,102,32,116,104,101,32,119,105, +110,100,111,119,46,108,111,99,97,116,105,111,110,118,101,114,116,105,99,97,108, +45,97,108,105,103,110,58,47,97,62,32,124,32,60,97,32,104,114,101,102,61,34,60,33 +,100,111,99,116,121,112,101,32,104,116,109,108,62,109,101,100,105,97,61,34,115, +99,114,101,101,110,34,32,60,111,112,116,105,111,110,32,118,97,108,117,101,61,34, +102,97,118,105,99,111,110,46,105,99,111,34,32,47,62,10,9,9,60,100,105,118,32,99, +108,97,115,115,61,34,99,104,97,114,97,99,116,101,114,105,115,116,105,99,115,34, +32,109,101,116,104,111,100,61,34,103,101,116,34,32,47,98,111,100,121,62,10,60,47 +,104,116,109,108,62,10,115,104,111,114,116,99,117,116,32,105,99,111,110,34,32, +100,111,99,117,109,101,110,116,46,119,114,105,116,101,40,112,97,100,100,105,110, +103,45,98,111,116,116,111,109,58,114,101,112,114,101,115,101,110,116,97,116,105, +118,101,115,115,117,98,109,105,116,34,32,118,97,108,117,101,61,34,97,108,105,103 +,110,61,34,99,101,110,116,101,114,34,32,116,104,114,111,117,103,104,111,117,116, +32,116,104,101,32,115,99,105,101,110,99,101,32,102,105,99,116,105,111,110,10,32, +32,60,100,105,118,32,99,108,97,115,115,61,34,115,117,98,109,105,116,34,32,99,108 +,97,115,115,61,34,111,110,101,32,111,102,32,116,104,101,32,109,111,115,116,32, +118,97,108,105,103,110,61,34,116,111,112,34,62,60,119,97,115,32,101,115,116,97, +98,108,105,115,104,101,100,41,59,13,10,60,47,115,99,114,105,112,116,62,13,10,114 +,101,116,117,114,110,32,102,97,108,115,101,59,34,62,41,46,115,116,121,108,101,46 +,100,105,115,112,108,97,121,98,101,99,97,117,115,101,32,111,102,32,116,104,101, +32,100,111,99,117,109,101,110,116,46,99,111,111,107,105,101,60,102,111,114,109, +32,97,99,116,105,111,110,61,34,47,125,98,111,100,121,123,109,97,114,103,105,110, +58,48,59,69,110,99,121,99,108,111,112,101,100,105,97,32,111,102,118,101,114,115, +105,111,110,32,111,102,32,116,104,101,32,46,99,114,101,97,116,101,69,108,101,109 +,101,110,116,40,110,97,109,101,34,32,99,111,110,116,101,110,116,61,34,60,47,100, +105,118,62,10,60,47,100,105,118,62,10,10,97,100,109,105,110,105,115,116,114,97, +116,105,118,101,32,60,47,98,111,100,121,62,10,60,47,104,116,109,108,62,104,105, +115,116,111,114,121,32,111,102,32,116,104,101,32,34,62,60,105,110,112,117,116,32 +,116,121,112,101,61,34,112,111,114,116,105,111,110,32,111,102,32,116,104,101,32, +97,115,32,112,97,114,116,32,111,102,32,116,104,101,32,38,110,98,115,112,59,60,97 +,32,104,114,101,102,61,34,111,116,104,101,114,32,99,111,117,110,116,114,105,101, +115,34,62,10,60,100,105,118,32,99,108,97,115,115,61,34,60,47,115,112,97,110,62, +60,47,115,112,97,110,62,60,73,110,32,111,116,104,101,114,32,119,111,114,100,115, +44,100,105,115,112,108,97,121,58,32,98,108,111,99,107,59,99,111,110,116,114,111, +108,32,111,102,32,116,104,101,32,105,110,116,114,111,100,117,99,116,105,111,110, +32,111,102,47,62,10,60,109,101,116,97,32,110,97,109,101,61,34,97,115,32,119,101, +108,108,32,97,115,32,116,104,101,32,105,110,32,114,101,99,101,110,116,32,121,101 +,97,114,115,13,10,9,60,100,105,118,32,99,108,97,115,115,61,34,60,47,100,105,118, +62,10,9,60,47,100,105,118,62,10,105,110,115,112,105,114,101,100,32,98,121,32,116 +,104,101,116,104,101,32,101,110,100,32,111,102,32,116,104,101,32,99,111,109,112, +97,116,105,98,108,101,32,119,105,116,104,98,101,99,97,109,101,32,107,110,111,119 +,110,32,97,115,32,115,116,121,108,101,61,34,109,97,114,103,105,110,58,46,106,115 +,34,62,60,47,115,99,114,105,112,116,62,60,32,73,110,116,101,114,110,97,116,105, +111,110,97,108,32,116,104,101,114,101,32,104,97,118,101,32,98,101,101,110,71,101 +,114,109,97,110,32,108,97,110,103,117,97,103,101,32,115,116,121,108,101,61,34,99 +,111,108,111,114,58,35,67,111,109,109,117,110,105,115,116,32,80,97,114,116,121, +99,111,110,115,105,115,116,101,110,116,32,119,105,116,104,98,111,114,100,101,114 +,61,34,48,34,32,99,101,108,108,32,109,97,114,103,105,110,104,101,105,103,104,116 +,61,34,116,104,101,32,109,97,106,111,114,105,116,121,32,111,102,34,32,97,108,105 +,103,110,61,34,99,101,110,116,101,114,114,101,108,97,116,101,100,32,116,111,32, +116,104,101,32,109,97,110,121,32,100,105,102,102,101,114,101,110,116,32,79,114, +116,104,111,100,111,120,32,67,104,117,114,99,104,115,105,109,105,108,97,114,32, +116,111,32,116,104,101,32,47,62,10,60,108,105,110,107,32,114,101,108,61,34,115, +119,97,115,32,111,110,101,32,111,102,32,116,104,101,32,117,110,116,105,108,32, +104,105,115,32,100,101,97,116,104,125,41,40,41,59,10,60,47,115,99,114,105,112, +116,62,111,116,104,101,114,32,108,97,110,103,117,97,103,101,115,99,111,109,112, +97,114,101,100,32,116,111,32,116,104,101,112,111,114,116,105,111,110,115,32,111, +102,32,116,104,101,116,104,101,32,78,101,116,104,101,114,108,97,110,100,115,116, +104,101,32,109,111,115,116,32,99,111,109,109,111,110,98,97,99,107,103,114,111, +117,110,100,58,117,114,108,40,97,114,103,117,101,100,32,116,104,97,116,32,116, +104,101,115,99,114,111,108,108,105,110,103,61,34,110,111,34,32,105,110,99,108, +117,100,101,100,32,105,110,32,116,104,101,78,111,114,116,104,32,65,109,101,114, +105,99,97,110,32,116,104,101,32,110,97,109,101,32,111,102,32,116,104,101,105,110 +,116,101,114,112,114,101,116,97,116,105,111,110,115,116,104,101,32,116,114,97, +100,105,116,105,111,110,97,108,100,101,118,101,108,111,112,109,101,110,116,32, +111,102,32,102,114,101,113,117,101,110,116,108,121,32,117,115,101,100,97,32,99, +111,108,108,101,99,116,105,111,110,32,111,102,118,101,114,121,32,115,105,109,105 +,108,97,114,32,116,111,115,117,114,114,111,117,110,100,105,110,103,32,116,104, +101,101,120,97,109,112,108,101,32,111,102,32,116,104,105,115,97,108,105,103,110, +61,34,99,101,110,116,101,114,34,62,119,111,117,108,100,32,104,97,118,101,32,98, +101,101,110,105,109,97,103,101,95,99,97,112,116,105,111,110,32,61,97,116,116,97, +99,104,101,100,32,116,111,32,116,104,101,115,117,103,103,101,115,116,105,110,103 +,32,116,104,97,116,105,110,32,116,104,101,32,102,111,114,109,32,111,102,32,105, +110,118,111,108,118,101,100,32,105,110,32,116,104,101,105,115,32,100,101,114,105 +,118,101,100,32,102,114,111,109,110,97,109,101,100,32,97,102,116,101,114,32,116, +104,101,73,110,116,114,111,100,117,99,116,105,111,110,32,116,111,114,101,115,116 +,114,105,99,116,105,111,110,115,32,111,110,32,115,116,121,108,101,61,34,119,105, +100,116,104,58,32,99,97,110,32,98,101,32,117,115,101,100,32,116,111,32,116,104, +101,32,99,114,101,97,116,105,111,110,32,111,102,109,111,115,116,32,105,109,112, +111,114,116,97,110,116,32,105,110,102,111,114,109,97,116,105,111,110,32,97,110, +100,114,101,115,117,108,116,101,100,32,105,110,32,116,104,101,99,111,108,108,97, +112,115,101,32,111,102,32,116,104,101,84,104,105,115,32,109,101,97,110,115,32, +116,104,97,116,101,108,101,109,101,110,116,115,32,111,102,32,116,104,101,119,97, +115,32,114,101,112,108,97,99,101,100,32,98,121,97,110,97,108,121,115,105,115,32, +111,102,32,116,104,101,105,110,115,112,105,114,97,116,105,111,110,32,102,111,114 +,114,101,103,97,114,100,101,100,32,97,115,32,116,104,101,109,111,115,116,32,115, +117,99,99,101,115,115,102,117,108,107,110,111,119,110,32,97,115,32,38,113,117, +111,116,59,97,32,99,111,109,112,114,101,104,101,110,115,105,118,101,72,105,115, +116,111,114,121,32,111,102,32,116,104,101,32,119,101,114,101,32,99,111,110,115, +105,100,101,114,101,100,114,101,116,117,114,110,101,100,32,116,111,32,116,104, +101,97,114,101,32,114,101,102,101,114,114,101,100,32,116,111,85,110,115,111,117, +114,99,101,100,32,105,109,97,103,101,62,10,9,60,100,105,118,32,99,108,97,115,115 +,61,34,99,111,110,115,105,115,116,115,32,111,102,32,116,104,101,115,116,111,112, +80,114,111,112,97,103,97,116,105,111,110,105,110,116,101,114,101,115,116,32,105, +110,32,116,104,101,97,118,97,105,108,97,98,105,108,105,116,121,32,111,102,97,112 +,112,101,97,114,115,32,116,111,32,104,97,118,101,101,108,101,99,116,114,111,109, +97,103,110,101,116,105,99,101,110,97,98,108,101,83,101,114,118,105,99,101,115,40 +,102,117,110,99,116,105,111,110,32,111,102,32,116,104,101,73,116,32,105,115,32, +105,109,112,111,114,116,97,110,116,60,47,115,99,114,105,112,116,62,60,47,100,105 +,118,62,102,117,110,99,116,105,111,110,40,41,123,118,97,114,32,114,101,108,97, +116,105,118,101,32,116,111,32,116,104,101,97,115,32,97,32,114,101,115,117,108, +116,32,111,102,32,116,104,101,32,112,111,115,105,116,105,111,110,32,111,102,70, +111,114,32,101,120,97,109,112,108,101,44,32,105,110,32,109,101,116,104,111,100, +61,34,112,111,115,116,34,32,119,97,115,32,102,111,108,108,111,119,101,100,32,98, +121,38,97,109,112,59,109,100,97,115,104,59,32,116,104,101,116,104,101,32,97,112, +112,108,105,99,97,116,105,111,110,106,115,34,62,60,47,115,99,114,105,112,116,62, +13,10,117,108,62,60,47,100,105,118,62,60,47,100,105,118,62,97,102,116,101,114,32 +,116,104,101,32,100,101,97,116,104,119,105,116,104,32,114,101,115,112,101,99,116 +,32,116,111,115,116,121,108,101,61,34,112,97,100,100,105,110,103,58,105,115,32, +112,97,114,116,105,99,117,108,97,114,108,121,100,105,115,112,108,97,121,58,105, +110,108,105,110,101,59,32,116,121,112,101,61,34,115,117,98,109,105,116,34,32,105 +,115,32,100,105,118,105,100,101,100,32,105,110,116,111,228,184,173,230,150,135, +32,40,231,174,128,228,189,147,41,114,101,115,112,111,110,115,97,98,105,108,105, +100,97,100,97,100,109,105,110,105,115,116,114,97,99,105,195,179,110,105,110,116, +101,114,110,97,99,105,111,110,97,108,101,115,99,111,114,114,101,115,112,111,110, +100,105,101,110,116,101,224,164,137,224,164,170,224,164,175,224,165,139,224,164, +151,224,164,170,224,165,130,224,164,176,224,165,141,224,164,181,224,164,185,224, +164,174,224,164,190,224,164,176,224,165,135,224,164,178,224,165,139,224,164,151, +224,165,139,224,164,130,224,164,154,224,165,129,224,164,168,224,164,190,224,164, +181,224,164,178,224,165,135,224,164,149,224,164,191,224,164,168,224,164,184,224, +164,176,224,164,149,224,164,190,224,164,176,224,164,170,224,165,129,224,164,178, +224,164,191,224,164,184,224,164,150,224,165,139,224,164,156,224,165,135,224,164, +130,224,164,154,224,164,190,224,164,185,224,164,191,224,164,143,224,164,173,224, +165,135,224,164,156,224,165,135,224,164,130,224,164,182,224,164,190,224,164,174, +224,164,191,224,164,178,224,164,185,224,164,174,224,164,190,224,164,176,224,165, +128,224,164,156,224,164,190,224,164,151,224,164,176,224,164,163,224,164,172,224, +164,168,224,164,190,224,164,168,224,165,135,224,164,149,224,165,129,224,164,174, +224,164,190,224,164,176,224,164,172,224,165,141,224,164,178,224,165,137,224,164, +151,224,164,174,224,164,190,224,164,178,224,164,191,224,164,149,224,164,174,224, +164,185,224,164,191,224,164,178,224,164,190,224,164,170,224,165,131,224,164,183, +224,165,141,224,164,160,224,164,172,224,164,162,224,164,188,224,164,164,224,165, +135,224,164,173,224,164,190,224,164,156,224,164,170,224,164,190,224,164,149,224, +165,141,224,164,178,224,164,191,224,164,149,224,164,159,224,165,141,224,164,176, +224,165,135,224,164,168,224,164,150,224,164,191,224,164,178,224,164,190,224,164, +171,224,164,166,224,165,140,224,164,176,224,164,190,224,164,168,224,164,174,224, +164,190,224,164,174,224,164,178,224,165,135,224,164,174,224,164,164,224,164,166, +224,164,190,224,164,168,224,164,172,224,164,190,224,164,156,224,164,190,224,164, +176,224,164,181,224,164,191,224,164,149,224,164,190,224,164,184,224,164,149,224, +165,141,224,164,175,224,165,139,224,164,130,224,164,154,224,164,190,224,164,185, +224,164,164,224,165,135,224,164,170,224,164,185,224,165,129,224,164,129,224,164, +154,224,164,172,224,164,164,224,164,190,224,164,175,224,164,190,224,164,184,224, +164,130,224,164,181,224,164,190,224,164,166,224,164,166,224,165,135,224,164,150, +224,164,168,224,165,135,224,164,170,224,164,191,224,164,155,224,164,178,224,165, +135,224,164,181,224,164,191,224,164,182,224,165,135,224,164,183,224,164,176,224, +164,190,224,164,156,224,165,141,224,164,175,224,164,137,224,164,164,224,165,141, +224,164,164,224,164,176,224,164,174,224,165,129,224,164,130,224,164,172,224,164, +136,224,164,166,224,165,139,224,164,168,224,165,139,224,164,130,224,164,137,224, +164,170,224,164,149,224,164,176,224,164,163,224,164,170,224,164,162,224,164,188, +224,165,135,224,164,130,224,164,184,224,165,141,224,164,165,224,164,191,224,164, +164,224,164,171,224,164,191,224,164,178,224,165,141,224,164,174,224,164,174,224, +165,129,224,164,150,224,165,141,224,164,175,224,164,133,224,164,154,224,165,141, +224,164,155,224,164,190,224,164,155,224,165,130,224,164,159,224,164,164,224,165, +128,224,164,184,224,164,130,224,164,151,224,165,128,224,164,164,224,164,156,224, +164,190,224,164,143,224,164,151,224,164,190,224,164,181,224,164,191,224,164,173, +224,164,190,224,164,151,224,164,152,224,164,163,224,165,141,224,164,159,224,165, +135,224,164,166,224,165,130,224,164,184,224,164,176,224,165,135,224,164,166,224, +164,191,224,164,168,224,165,139,224,164,130,224,164,185,224,164,164,224,165,141, +224,164,175,224,164,190,224,164,184,224,165,135,224,164,149,224,165,141,224,164, +184,224,164,151,224,164,190,224,164,130,224,164,167,224,165,128,224,164,181,224, +164,191,224,164,182,224,165,141,224,164,181,224,164,176,224,164,190,224,164,164, +224,165,135,224,164,130,224,164,166,224,165,136,224,164,159,224,165,141,224,164, +184,224,164,168,224,164,149,224,165,141,224,164,182,224,164,190,224,164,184,224, +164,190,224,164,174,224,164,168,224,165,135,224,164,133,224,164,166,224,164,190, +224,164,178,224,164,164,224,164,172,224,164,191,224,164,156,224,164,178,224,165, +128,224,164,170,224,165,129,224,164,176,224,165,130,224,164,183,224,164,185,224, +164,191,224,164,130,224,164,166,224,165,128,224,164,174,224,164,191,224,164,164, +224,165,141,224,164,176,224,164,149,224,164,181,224,164,191,224,164,164,224,164, +190,224,164,176,224,165,129,224,164,170,224,164,175,224,165,135,224,164,184,224, +165,141,224,164,165,224,164,190,224,164,168,224,164,149,224,164,176,224,165,139, +224,164,161,224,164,188,224,164,174,224,165,129,224,164,149,224,165,141,224,164, +164,224,164,175,224,165,139,224,164,156,224,164,168,224,164,190,224,164,149,224, +165,131,224,164,170,224,164,175,224,164,190,224,164,170,224,165,139,224,164,184, +224,165,141,224,164,159,224,164,152,224,164,176,224,165,135,224,164,178,224,165, +130,224,164,149,224,164,190,224,164,176,224,165,141,224,164,175,224,164,181,224, +164,191,224,164,154,224,164,190,224,164,176,224,164,184,224,165,130,224,164,154, +224,164,168,224,164,190,224,164,174,224,165,130,224,164,178,224,165,141,224,164, +175,224,164,166,224,165,135,224,164,150,224,165,135,224,164,130,224,164,185,224, +164,174,224,165,135,224,164,182,224,164,190,224,164,184,224,165,141,224,164,149, +224,165,130,224,164,178,224,164,174,224,165,136,224,164,130,224,164,168,224,165, +135,224,164,164,224,165,136,224,164,175,224,164,190,224,164,176,224,164,156,224, +164,191,224,164,184,224,164,149,224,165,135,114,115,115,43,120,109,108,34,32,116 +,105,116,108,101,61,34,45,116,121,112,101,34,32,99,111,110,116,101,110,116,61,34 +,116,105,116,108,101,34,32,99,111,110,116,101,110,116,61,34,97,116,32,116,104, +101,32,115,97,109,101,32,116,105,109,101,46,106,115,34,62,60,47,115,99,114,105, +112,116,62,10,60,34,32,109,101,116,104,111,100,61,34,112,111,115,116,34,32,60,47 +,115,112,97,110,62,60,47,97,62,60,47,108,105,62,118,101,114,116,105,99,97,108,45 +,97,108,105,103,110,58,116,47,106,113,117,101,114,121,46,109,105,110,46,106,115, +34,62,46,99,108,105,99,107,40,102,117,110,99,116,105,111,110,40,32,115,116,121, +108,101,61,34,112,97,100,100,105,110,103,45,125,41,40,41,59,10,60,47,115,99,114, +105,112,116,62,10,60,47,115,112,97,110,62,60,97,32,104,114,101,102,61,34,60,97, +32,104,114,101,102,61,34,104,116,116,112,58,47,47,41,59,32,114,101,116,117,114, +110,32,102,97,108,115,101,59,116,101,120,116,45,100,101,99,111,114,97,116,105, +111,110,58,32,115,99,114,111,108,108,105,110,103,61,34,110,111,34,32,98,111,114, +100,101,114,45,99,111,108,108,97,112,115,101,58,97,115,115,111,99,105,97,116,101 +,100,32,119,105,116,104,32,66,97,104,97,115,97,32,73,110,100,111,110,101,115,105 +,97,69,110,103,108,105,115,104,32,108,97,110,103,117,97,103,101,60,116,101,120, +116,32,120,109,108,58,115,112,97,99,101,61,46,103,105,102,34,32,98,111,114,100, +101,114,61,34,48,34,60,47,98,111,100,121,62,10,60,47,104,116,109,108,62,10,111, +118,101,114,102,108,111,119,58,104,105,100,100,101,110,59,105,109,103,32,115,114 +,99,61,34,104,116,116,112,58,47,47,97,100,100,69,118,101,110,116,76,105,115,116, +101,110,101,114,114,101,115,112,111,110,115,105,98,108,101,32,102,111,114,32,115 +,46,106,115,34,62,60,47,115,99,114,105,112,116,62,10,47,102,97,118,105,99,111, +110,46,105,99,111,34,32,47,62,111,112,101,114,97,116,105,110,103,32,115,121,115, +116,101,109,34,32,115,116,121,108,101,61,34,119,105,100,116,104,58,49,116,97,114 +,103,101,116,61,34,95,98,108,97,110,107,34,62,83,116,97,116,101,32,85,110,105, +118,101,114,115,105,116,121,116,101,120,116,45,97,108,105,103,110,58,108,101,102 +,116,59,10,100,111,99,117,109,101,110,116,46,119,114,105,116,101,40,44,32,105, +110,99,108,117,100,105,110,103,32,116,104,101,32,97,114,111,117,110,100,32,116, +104,101,32,119,111,114,108,100,41,59,13,10,60,47,115,99,114,105,112,116,62,13,10 +,60,34,32,115,116,121,108,101,61,34,104,101,105,103,104,116,58,59,111,118,101, +114,102,108,111,119,58,104,105,100,100,101,110,109,111,114,101,32,105,110,102, +111,114,109,97,116,105,111,110,97,110,32,105,110,116,101,114,110,97,116,105,111, +110,97,108,97,32,109,101,109,98,101,114,32,111,102,32,116,104,101,32,111,110,101 +,32,111,102,32,116,104,101,32,102,105,114,115,116,99,97,110,32,98,101,32,102,111 +,117,110,100,32,105,110,32,60,47,100,105,118,62,10,9,9,60,47,100,105,118,62,10, +100,105,115,112,108,97,121,58,32,110,111,110,101,59,34,62,34,32,47,62,10,60,108, +105,110,107,32,114,101,108,61,34,10,32,32,40,102,117,110,99,116,105,111,110,40, +41,32,123,116,104,101,32,49,53,116,104,32,99,101,110,116,117,114,121,46,112,114, +101,118,101,110,116,68,101,102,97,117,108,116,40,108,97,114,103,101,32,110,117, +109,98,101,114,32,111,102,32,66,121,122,97,110,116,105,110,101,32,69,109,112,105 +,114,101,46,106,112,103,124,116,104,117,109,98,124,108,101,102,116,124,118,97, +115,116,32,109,97,106,111,114,105,116,121,32,111,102,109,97,106,111,114,105,116, +121,32,111,102,32,116,104,101,32,32,97,108,105,103,110,61,34,99,101,110,116,101, +114,34,62,85,110,105,118,101,114,115,105,116,121,32,80,114,101,115,115,100,111, +109,105,110,97,116,101,100,32,98,121,32,116,104,101,83,101,99,111,110,100,32,87, +111,114,108,100,32,87,97,114,100,105,115,116,114,105,98,117,116,105,111,110,32, +111,102,32,115,116,121,108,101,61,34,112,111,115,105,116,105,111,110,58,116,104, +101,32,114,101,115,116,32,111,102,32,116,104,101,32,99,104,97,114,97,99,116,101, +114,105,122,101,100,32,98,121,32,114,101,108,61,34,110,111,102,111,108,108,111, +119,34,62,100,101,114,105,118,101,115,32,102,114,111,109,32,116,104,101,114,97, +116,104,101,114,32,116,104,97,110,32,116,104,101,32,97,32,99,111,109,98,105,110, +97,116,105,111,110,32,111,102,115,116,121,108,101,61,34,119,105,100,116,104,58, +49,48,48,69,110,103,108,105,115,104,45,115,112,101,97,107,105,110,103,99,111,109 +,112,117,116,101,114,32,115,99,105,101,110,99,101,98,111,114,100,101,114,61,34, +48,34,32,97,108,116,61,34,116,104,101,32,101,120,105,115,116,101,110,99,101,32, +111,102,68,101,109,111,99,114,97,116,105,99,32,80,97,114,116,121,34,32,115,116, +121,108,101,61,34,109,97,114,103,105,110,45,70,111,114,32,116,104,105,115,32,114 +,101,97,115,111,110,44,46,106,115,34,62,60,47,115,99,114,105,112,116,62,10,9,115 +,66,121,84,97,103,78,97,109,101,40,115,41,91,48,93,106,115,34,62,60,47,115,99, +114,105,112,116,62,13,10,60,46,106,115,34,62,60,47,115,99,114,105,112,116,62,13, +10,108,105,110,107,32,114,101,108,61,34,105,99,111,110,34,32,39,32,97,108,116,61 +,39,39,32,99,108,97,115,115,61,39,102,111,114,109,97,116,105,111,110,32,111,102, +32,116,104,101,118,101,114,115,105,111,110,115,32,111,102,32,116,104,101,32,60, +47,97,62,60,47,100,105,118,62,60,47,100,105,118,62,47,112,97,103,101,62,10,32,32 +,60,112,97,103,101,62,10,60,100,105,118,32,99,108,97,115,115,61,34,99,111,110, +116,98,101,99,97,109,101,32,116,104,101,32,102,105,114,115,116,98,97,104,97,115, +97,32,73,110,100,111,110,101,115,105,97,101,110,103,108,105,115,104,32,40,115, +105,109,112,108,101,41,206,149,206,187,206,187,206,183,206,189,206,185,206,186, +206,172,209,133,209,128,208,178,208,176,209,130,209,129,208,186,208,184,208,186, +208,190,208,188,208,191,208,176,208,189,208,184,208,184,209,143,208,178,208,187, +209,143,208,181,209,130,209,129,209,143,208,148,208,190,208,177,208,176,208,178, +208,184,209,130,209,140,209,135,208,181,208,187,208,190,208,178,208,181,208,186, +208,176,209,128,208,176,208,183,208,178,208,184,209,130,208,184,209,143,208,152, +208,189,209,130,208,181,209,128,208,189,208,181,209,130,208,158,209,130,208,178, +208,181,209,130,208,184,209,130,209,140,208,189,208,176,208,191,209,128,208,184, +208,188,208,181,209,128,208,184,208,189,209,130,208,181,209,128,208,189,208,181, +209,130,208,186,208,190,209,130,208,190,209,128,208,190,208,179,208,190,209,129, +209,130,209,128,208,176,208,189,208,184,209,134,209,139,208,186,208,176,209,135, +208,181,209,129,209,130,208,178,208,181,209,131,209,129,208,187,208,190,208,178, +208,184,209,143,209,133,208,191,209,128,208,190,208,177,208,187,208,181,208,188, +209,139,208,191,208,190,208,187,209,131,209,135,208,184,209,130,209,140,209,143, +208,178,208,187,209,143,209,142,209,130,209,129,209,143,208,189,208,176,208,184, +208,177,208,190,208,187,208,181,208,181,208,186,208,190,208,188,208,191,208,176, +208,189,208,184,209,143,208,178,208,189,208,184,208,188,208,176,208,189,208,184, +208,181,209,129,209,128,208,181,208,180,209,129,209,130,208,178,208,176,216,167, +217,132,217,133,217,136,216,167,216,182,217,138,216,185,216,167,217,132,216,177, +216,166,217,138,216,179,217,138,216,169,216,167,217,132,216,167,217,134,216,170, +217,130,216,167,217,132,217,133,216,180,216,167,216,177,217,131,216,167,216,170, +217,131,216,167,217,132,216,179,217,138,216,167,216,177,216,167,216,170,216,167, +217,132,217,133,217,131,216,170,217,136,216,168,216,169,216,167,217,132,216,179, +216,185,217,136,216,175,217,138,216,169,216,167,216,173,216,181,216,167,216,166, +217,138,216,167,216,170,216,167,217,132,216,185,216,167,217,132,217,133,217,138, +216,169,216,167,217,132,216,181,217,136,216,170,217,138,216,167,216,170,216,167, +217,132,216,167,217,134,216,170,216,177,217,134,216,170,216,167,217,132,216,170, +216,181,216,167,217,133,217,138,217,133,216,167,217,132,216,165,216,179,217,132, +216,167,217,133,217,138,216,167,217,132,217,133,216,180,216,167,216,177,217,131, +216,169,216,167,217,132,217,133,216,177,216,166,217,138,216,167,216,170,114,111, +98,111,116,115,34,32,99,111,110,116,101,110,116,61,34,60,100,105,118,32,105,100, +61,34,102,111,111,116,101,114,34,62,116,104,101,32,85,110,105,116,101,100,32,83, +116,97,116,101,115,60,105,109,103,32,115,114,99,61,34,104,116,116,112,58,47,47, +46,106,112,103,124,114,105,103,104,116,124,116,104,117,109,98,124,46,106,115,34, +62,60,47,115,99,114,105,112,116,62,13,10,60,108,111,99,97,116,105,111,110,46,112 +,114,111,116,111,99,111,108,102,114,97,109,101,98,111,114,100,101,114,61,34,48, +34,32,115,34,32,47,62,10,60,109,101,116,97,32,110,97,109,101,61,34,60,47,97,62, +60,47,100,105,118,62,60,47,100,105,118,62,60,102,111,110,116,45,119,101,105,103, +104,116,58,98,111,108,100,59,38,113,117,111,116,59,32,97,110,100,32,38,113,117, +111,116,59,100,101,112,101,110,100,105,110,103,32,111,110,32,116,104,101,32,109, +97,114,103,105,110,58,48,59,112,97,100,100,105,110,103,58,34,32,114,101,108,61, +34,110,111,102,111,108,108,111,119,34,32,80,114,101,115,105,100,101,110,116,32, +111,102,32,116,104,101,32,116,119,101,110,116,105,101,116,104,32,99,101,110,116, +117,114,121,101,118,105,115,105,111,110,62,10,32,32,60,47,112,97,103,101,73,110, +116,101,114,110,101,116,32,69,120,112,108,111,114,101,114,97,46,97,115,121,110, +99,32,61,32,116,114,117,101,59,13,10,105,110,102,111,114,109,97,116,105,111,110, +32,97,98,111,117,116,60,100,105,118,32,105,100,61,34,104,101,97,100,101,114,34, +62,34,32,97,99,116,105,111,110,61,34,104,116,116,112,58,47,47,60,97,32,104,114, +101,102,61,34,104,116,116,112,115,58,47,47,60,100,105,118,32,105,100,61,34,99, +111,110,116,101,110,116,34,60,47,100,105,118,62,13,10,60,47,100,105,118,62,13,10 +,60,100,101,114,105,118,101,100,32,102,114,111,109,32,116,104,101,32,60,105,109, +103,32,115,114,99,61,39,104,116,116,112,58,47,47,97,99,99,111,114,100,105,110, +103,32,116,111,32,116,104,101,32,10,60,47,98,111,100,121,62,10,60,47,104,116,109 +,108,62,10,115,116,121,108,101,61,34,102,111,110,116,45,115,105,122,101,58,115, +99,114,105,112,116,32,108,97,110,103,117,97,103,101,61,34,65,114,105,97,108,44, +32,72,101,108,118,101,116,105,99,97,44,60,47,97,62,60,115,112,97,110,32,99,108, +97,115,115,61,34,60,47,115,99,114,105,112,116,62,60,115,99,114,105,112,116,32, +112,111,108,105,116,105,99,97,108,32,112,97,114,116,105,101,115,116,100,62,60,47 +,116,114,62,60,47,116,97,98,108,101,62,60,104,114,101,102,61,34,104,116,116,112, +58,47,47,119,119,119,46,105,110,116,101,114,112,114,101,116,97,116,105,111,110, +32,111,102,114,101,108,61,34,115,116,121,108,101,115,104,101,101,116,34,32,100, +111,99,117,109,101,110,116,46,119,114,105,116,101,40,39,60,99,104,97,114,115,101 +,116,61,34,117,116,102,45,56,34,62,10,98,101,103,105,110,110,105,110,103,32,111, +102,32,116,104,101,32,114,101,118,101,97,108,101,100,32,116,104,97,116,32,116, +104,101,116,101,108,101,118,105,115,105,111,110,32,115,101,114,105,101,115,34,32 +,114,101,108,61,34,110,111,102,111,108,108,111,119,34,62,32,116,97,114,103,101, +116,61,34,95,98,108,97,110,107,34,62,99,108,97,105,109,105,110,103,32,116,104,97 +,116,32,116,104,101,104,116,116,112,37,51,65,37,50,70,37,50,70,119,119,119,46, +109,97,110,105,102,101,115,116,97,116,105,111,110,115,32,111,102,80,114,105,109, +101,32,77,105,110,105,115,116,101,114,32,111,102,105,110,102,108,117,101,110,99, +101,100,32,98,121,32,116,104,101,99,108,97,115,115,61,34,99,108,101,97,114,102, +105,120,34,62,47,100,105,118,62,13,10,60,47,100,105,118,62,13,10,13,10,116,104, +114,101,101,45,100,105,109,101,110,115,105,111,110,97,108,67,104,117,114,99,104, +32,111,102,32,69,110,103,108,97,110,100,111,102,32,78,111,114,116,104,32,67,97, +114,111,108,105,110,97,115,113,117,97,114,101,32,107,105,108,111,109,101,116,114 +,101,115,46,97,100,100,69,118,101,110,116,76,105,115,116,101,110,101,114,100,105 +,115,116,105,110,99,116,32,102,114,111,109,32,116,104,101,99,111,109,109,111,110 +,108,121,32,107,110,111,119,110,32,97,115,80,104,111,110,101,116,105,99,32,65, +108,112,104,97,98,101,116,100,101,99,108,97,114,101,100,32,116,104,97,116,32,116 +,104,101,99,111,110,116,114,111,108,108,101,100,32,98,121,32,116,104,101,66,101, +110,106,97,109,105,110,32,70,114,97,110,107,108,105,110,114,111,108,101,45,112, +108,97,121,105,110,103,32,103,97,109,101,116,104,101,32,85,110,105,118,101,114, +115,105,116,121,32,111,102,105,110,32,87,101,115,116,101,114,110,32,69,117,114, +111,112,101,112,101,114,115,111,110,97,108,32,99,111,109,112,117,116,101,114,80, +114,111,106,101,99,116,32,71,117,116,101,110,98,101,114,103,114,101,103,97,114, +100,108,101,115,115,32,111,102,32,116,104,101,104,97,115,32,98,101,101,110,32, +112,114,111,112,111,115,101,100,116,111,103,101,116,104,101,114,32,119,105,116, +104,32,116,104,101,62,60,47,108,105,62,60,108,105,32,99,108,97,115,115,61,34,105 +,110,32,115,111,109,101,32,99,111,117,110,116,114,105,101,115,109,105,110,46,106 +,115,34,62,60,47,115,99,114,105,112,116,62,111,102,32,116,104,101,32,112,111,112 +,117,108,97,116,105,111,110,111,102,102,105,99,105,97,108,32,108,97,110,103,117, +97,103,101,60,105,109,103,32,115,114,99,61,34,105,109,97,103,101,115,47,105,100, +101,110,116,105,102,105,101,100,32,98,121,32,116,104,101,110,97,116,117,114,97, +108,32,114,101,115,111,117,114,99,101,115,99,108,97,115,115,105,102,105,99,97, +116,105,111,110,32,111,102,99,97,110,32,98,101,32,99,111,110,115,105,100,101,114 +,101,100,113,117,97,110,116,117,109,32,109,101,99,104,97,110,105,99,115,78,101, +118,101,114,116,104,101,108,101,115,115,44,32,116,104,101,109,105,108,108,105, +111,110,32,121,101,97,114,115,32,97,103,111,60,47,98,111,100,121,62,13,10,60,47, +104,116,109,108,62,13,206,149,206,187,206,187,206,183,206,189,206,185,206,186, +206,172,10,116,97,107,101,32,97,100,118,97,110,116,97,103,101,32,111,102,97,110, +100,44,32,97,99,99,111,114,100,105,110,103,32,116,111,97,116,116,114,105,98,117, +116,101,100,32,116,111,32,116,104,101,77,105,99,114,111,115,111,102,116,32,87, +105,110,100,111,119,115,116,104,101,32,102,105,114,115,116,32,99,101,110,116,117 +,114,121,117,110,100,101,114,32,116,104,101,32,99,111,110,116,114,111,108,100, +105,118,32,99,108,97,115,115,61,34,104,101,97,100,101,114,115,104,111,114,116, +108,121,32,97,102,116,101,114,32,116,104,101,110,111,116,97,98,108,101,32,101, +120,99,101,112,116,105,111,110,116,101,110,115,32,111,102,32,116,104,111,117,115 +,97,110,100,115,115,101,118,101,114,97,108,32,100,105,102,102,101,114,101,110, +116,97,114,111,117,110,100,32,116,104,101,32,119,111,114,108,100,46,114,101,97, +99,104,105,110,103,32,109,105,108,105,116,97,114,121,105,115,111,108,97,116,101, +100,32,102,114,111,109,32,116,104,101,111,112,112,111,115,105,116,105,111,110,32 +,116,111,32,116,104,101,116,104,101,32,79,108,100,32,84,101,115,116,97,109,101, +110,116,65,102,114,105,99,97,110,32,65,109,101,114,105,99,97,110,115,105,110,115 +,101,114,116,101,100,32,105,110,116,111,32,116,104,101,115,101,112,97,114,97,116 +,101,32,102,114,111,109,32,116,104,101,109,101,116,114,111,112,111,108,105,116, +97,110,32,97,114,101,97,109,97,107,101,115,32,105,116,32,112,111,115,115,105,98, +108,101,97,99,107,110,111,119,108,101,100,103,101,100,32,116,104,97,116,97,114, +103,117,97,98,108,121,32,116,104,101,32,109,111,115,116,116,121,112,101,61,34, +116,101,120,116,47,99,115,115,34,62,10,116,104,101,32,73,110,116,101,114,110,97, +116,105,111,110,97,108,65,99,99,111,114,100,105,110,103,32,116,111,32,116,104, +101,32,112,101,61,34,116,101,120,116,47,99,115,115,34,32,47,62,10,99,111,105,110 +,99,105,100,101,32,119,105,116,104,32,116,104,101,116,119,111,45,116,104,105,114 +,100,115,32,111,102,32,116,104,101,68,117,114,105,110,103,32,116,104,105,115,32, +116,105,109,101,44,100,117,114,105,110,103,32,116,104,101,32,112,101,114,105,111 +,100,97,110,110,111,117,110,99,101,100,32,116,104,97,116,32,104,101,116,104,101, +32,105,110,116,101,114,110,97,116,105,111,110,97,108,97,110,100,32,109,111,114, +101,32,114,101,99,101,110,116,108,121,98,101,108,105,101,118,101,100,32,116,104, +97,116,32,116,104,101,99,111,110,115,99,105,111,117,115,110,101,115,115,32,97, +110,100,102,111,114,109,101,114,108,121,32,107,110,111,119,110,32,97,115,115,117 +,114,114,111,117,110,100,101,100,32,98,121,32,116,104,101,102,105,114,115,116,32 +,97,112,112,101,97,114,101,100,32,105,110,111,99,99,97,115,105,111,110,97,108, +108,121,32,117,115,101,100,112,111,115,105,116,105,111,110,58,97,98,115,111,108, +117,116,101,59,34,32,116,97,114,103,101,116,61,34,95,98,108,97,110,107,34,32,112 +,111,115,105,116,105,111,110,58,114,101,108,97,116,105,118,101,59,116,101,120, +116,45,97,108,105,103,110,58,99,101,110,116,101,114,59,106,97,120,47,108,105,98, +115,47,106,113,117,101,114,121,47,49,46,98,97,99,107,103,114,111,117,110,100,45, +99,111,108,111,114,58,35,116,121,112,101,61,34,97,112,112,108,105,99,97,116,105, +111,110,47,97,110,103,117,97,103,101,34,32,99,111,110,116,101,110,116,61,34,60, +109,101,116,97,32,104,116,116,112,45,101,113,117,105,118,61,34,80,114,105,118,97 +,99,121,32,80,111,108,105,99,121,60,47,97,62,101,40,34,37,51,67,115,99,114,105, +112,116,32,115,114,99,61,39,34,32,116,97,114,103,101,116,61,34,95,98,108,97,110, +107,34,62,79,110,32,116,104,101,32,111,116,104,101,114,32,104,97,110,100,44,46, +106,112,103,124,116,104,117,109,98,124,114,105,103,104,116,124,50,60,47,100,105, +118,62,60,100,105,118,32,99,108,97,115,115,61,34,60,100,105,118,32,115,116,121, +108,101,61,34,102,108,111,97,116,58,110,105,110,101,116,101,101,110,116,104,32, +99,101,110,116,117,114,121,60,47,98,111,100,121,62,13,10,60,47,104,116,109,108, +62,13,10,60,105,109,103,32,115,114,99,61,34,104,116,116,112,58,47,47,115,59,116, +101,120,116,45,97,108,105,103,110,58,99,101,110,116,101,114,102,111,110,116,45, +119,101,105,103,104,116,58,32,98,111,108,100,59,32,65,99,99,111,114,100,105,110, +103,32,116,111,32,116,104,101,32,100,105,102,102,101,114,101,110,99,101,32,98, +101,116,119,101,101,110,34,32,102,114,97,109,101,98,111,114,100,101,114,61,34,48 +,34,32,34,32,115,116,121,108,101,61,34,112,111,115,105,116,105,111,110,58,108, +105,110,107,32,104,114,101,102,61,34,104,116,116,112,58,47,47,104,116,109,108,52 +,47,108,111,111,115,101,46,100,116,100,34,62,10,100,117,114,105,110,103,32,116, +104,105,115,32,112,101,114,105,111,100,60,47,116,100,62,60,47,116,114,62,60,47, +116,97,98,108,101,62,99,108,111,115,101,108,121,32,114,101,108,97,116,101,100,32 +,116,111,102,111,114,32,116,104,101,32,102,105,114,115,116,32,116,105,109,101,59 +,102,111,110,116,45,119,101,105,103,104,116,58,98,111,108,100,59,105,110,112,117 +,116,32,116,121,112,101,61,34,116,101,120,116,34,32,60,115,112,97,110,32,115,116 +,121,108,101,61,34,102,111,110,116,45,111,110,114,101,97,100,121,115,116,97,116, +101,99,104,97,110,103,101,9,60,100,105,118,32,99,108,97,115,115,61,34,99,108,101 +,97,114,100,111,99,117,109,101,110,116,46,108,111,99,97,116,105,111,110,46,32,70 +,111,114,32,101,120,97,109,112,108,101,44,32,116,104,101,32,97,32,119,105,100, +101,32,118,97,114,105,101,116,121,32,111,102,32,60,33,68,79,67,84,89,80,69,32, +104,116,109,108,62,13,10,60,38,110,98,115,112,59,38,110,98,115,112,59,38,110,98, +115,112,59,34,62,60,97,32,104,114,101,102,61,34,104,116,116,112,58,47,47,115,116 +,121,108,101,61,34,102,108,111,97,116,58,108,101,102,116,59,99,111,110,99,101, +114,110,101,100,32,119,105,116,104,32,116,104,101,61,104,116,116,112,37,51,65,37 +,50,70,37,50,70,119,119,119,46,105,110,32,112,111,112,117,108,97,114,32,99,117, +108,116,117,114,101,116,121,112,101,61,34,116,101,120,116,47,99,115,115,34,32,47 +,62,105,116,32,105,115,32,112,111,115,115,105,98,108,101,32,116,111,32,72,97,114 +,118,97,114,100,32,85,110,105,118,101,114,115,105,116,121,116,121,108,101,115, +104,101,101,116,34,32,104,114,101,102,61,34,47,116,104,101,32,109,97,105,110,32, +99,104,97,114,97,99,116,101,114,79,120,102,111,114,100,32,85,110,105,118,101,114 +,115,105,116,121,32,32,110,97,109,101,61,34,107,101,121,119,111,114,100,115,34, +32,99,115,116,121,108,101,61,34,116,101,120,116,45,97,108,105,103,110,58,116,104 +,101,32,85,110,105,116,101,100,32,75,105,110,103,100,111,109,102,101,100,101,114 +,97,108,32,103,111,118,101,114,110,109,101,110,116,60,100,105,118,32,115,116,121 +,108,101,61,34,109,97,114,103,105,110,32,100,101,112,101,110,100,105,110,103,32, +111,110,32,116,104,101,32,100,101,115,99,114,105,112,116,105,111,110,32,111,102, +32,116,104,101,60,100,105,118,32,99,108,97,115,115,61,34,104,101,97,100,101,114, +46,109,105,110,46,106,115,34,62,60,47,115,99,114,105,112,116,62,100,101,115,116, +114,117,99,116,105,111,110,32,111,102,32,116,104,101,115,108,105,103,104,116,108 +,121,32,100,105,102,102,101,114,101,110,116,105,110,32,97,99,99,111,114,100,97, +110,99,101,32,119,105,116,104,116,101,108,101,99,111,109,109,117,110,105,99,97, +116,105,111,110,115,105,110,100,105,99,97,116,101,115,32,116,104,97,116,32,116, +104,101,115,104,111,114,116,108,121,32,116,104,101,114,101,97,102,116,101,114, +101,115,112,101,99,105,97,108,108,121,32,105,110,32,116,104,101,32,69,117,114, +111,112,101,97,110,32,99,111,117,110,116,114,105,101,115,72,111,119,101,118,101, +114,44,32,116,104,101,114,101,32,97,114,101,115,114,99,61,34,104,116,116,112,58, +47,47,115,116,97,116,105,99,115,117,103,103,101,115,116,101,100,32,116,104,97, +116,32,116,104,101,34,32,115,114,99,61,34,104,116,116,112,58,47,47,119,119,119, +46,97,32,108,97,114,103,101,32,110,117,109,98,101,114,32,111,102,32,84,101,108, +101,99,111,109,109,117,110,105,99,97,116,105,111,110,115,34,32,114,101,108,61,34 +,110,111,102,111,108,108,111,119,34,32,116,72,111,108,121,32,82,111,109,97,110, +32,69,109,112,101,114,111,114,97,108,109,111,115,116,32,101,120,99,108,117,115, +105,118,101,108,121,34,32,98,111,114,100,101,114,61,34,48,34,32,97,108,116,61,34 +,83,101,99,114,101,116,97,114,121,32,111,102,32,83,116,97,116,101,99,117,108,109 +,105,110,97,116,105,110,103,32,105,110,32,116,104,101,67,73,65,32,87,111,114,108 +,100,32,70,97,99,116,98,111,111,107,116,104,101,32,109,111,115,116,32,105,109, +112,111,114,116,97,110,116,97,110,110,105,118,101,114,115,97,114,121,32,111,102, +32,116,104,101,115,116,121,108,101,61,34,98,97,99,107,103,114,111,117,110,100,45 +,60,108,105,62,60,101,109,62,60,97,32,104,114,101,102,61,34,47,116,104,101,32,65 +,116,108,97,110,116,105,99,32,79,99,101,97,110,115,116,114,105,99,116,108,121,32 +,115,112,101,97,107,105,110,103,44,115,104,111,114,116,108,121,32,98,101,102,111 +,114,101,32,116,104,101,100,105,102,102,101,114,101,110,116,32,116,121,112,101, +115,32,111,102,116,104,101,32,79,116,116,111,109,97,110,32,69,109,112,105,114, +101,62,60,105,109,103,32,115,114,99,61,34,104,116,116,112,58,47,47,65,110,32,73, +110,116,114,111,100,117,99,116,105,111,110,32,116,111,99,111,110,115,101,113,117 +,101,110,99,101,32,111,102,32,116,104,101,100,101,112,97,114,116,117,114,101,32, +102,114,111,109,32,116,104,101,67,111,110,102,101,100,101,114,97,116,101,32,83, +116,97,116,101,115,105,110,100,105,103,101,110,111,117,115,32,112,101,111,112, +108,101,115,80,114,111,99,101,101,100,105,110,103,115,32,111,102,32,116,104,101, +105,110,102,111,114,109,97,116,105,111,110,32,111,110,32,116,104,101,116,104,101 +,111,114,105,101,115,32,104,97,118,101,32,98,101,101,110,105,110,118,111,108,118 +,101,109,101,110,116,32,105,110,32,116,104,101,100,105,118,105,100,101,100,32, +105,110,116,111,32,116,104,114,101,101,97,100,106,97,99,101,110,116,32,99,111, +117,110,116,114,105,101,115,105,115,32,114,101,115,112,111,110,115,105,98,108, +101,32,102,111,114,100,105,115,115,111,108,117,116,105,111,110,32,111,102,32,116 +,104,101,99,111,108,108,97,98,111,114,97,116,105,111,110,32,119,105,116,104,119, +105,100,101,108,121,32,114,101,103,97,114,100,101,100,32,97,115,104,105,115,32, +99,111,110,116,101,109,112,111,114,97,114,105,101,115,102,111,117,110,100,105, +110,103,32,109,101,109,98,101,114,32,111,102,68,111,109,105,110,105,99,97,110,32 +,82,101,112,117,98,108,105,99,103,101,110,101,114,97,108,108,121,32,97,99,99,101 +,112,116,101,100,116,104,101,32,112,111,115,115,105,98,105,108,105,116,121,32, +111,102,97,114,101,32,97,108,115,111,32,97,118,97,105,108,97,98,108,101,117,110, +100,101,114,32,99,111,110,115,116,114,117,99,116,105,111,110,114,101,115,116,111 +,114,97,116,105,111,110,32,111,102,32,116,104,101,116,104,101,32,103,101,110,101 +,114,97,108,32,112,117,98,108,105,99,105,115,32,97,108,109,111,115,116,32,101, +110,116,105,114,101,108,121,112,97,115,115,101,115,32,116,104,114,111,117,103, +104,32,116,104,101,104,97,115,32,98,101,101,110,32,115,117,103,103,101,115,116, +101,100,99,111,109,112,117,116,101,114,32,97,110,100,32,118,105,100,101,111,71, +101,114,109,97,110,105,99,32,108,97,110,103,117,97,103,101,115,32,97,99,99,111, +114,100,105,110,103,32,116,111,32,116,104,101,32,100,105,102,102,101,114,101,110 +,116,32,102,114,111,109,32,116,104,101,115,104,111,114,116,108,121,32,97,102,116 +,101,114,119,97,114,100,115,104,114,101,102,61,34,104,116,116,112,115,58,47,47, +119,119,119,46,114,101,99,101,110,116,32,100,101,118,101,108,111,112,109,101,110 +,116,66,111,97,114,100,32,111,102,32,68,105,114,101,99,116,111,114,115,60,100, +105,118,32,99,108,97,115,115,61,34,115,101,97,114,99,104,124,32,60,97,32,104,114 +,101,102,61,34,104,116,116,112,58,47,47,73,110,32,112,97,114,116,105,99,117,108, +97,114,44,32,116,104,101,77,117,108,116,105,112,108,101,32,102,111,111,116,110, +111,116,101,115,111,114,32,111,116,104,101,114,32,115,117,98,115,116,97,110,99, +101,116,104,111,117,115,97,110,100,115,32,111,102,32,121,101,97,114,115,116,114, +97,110,115,108,97,116,105,111,110,32,111,102,32,116,104,101,60,47,100,105,118,62 +,13,10,60,47,100,105,118,62,13,10,13,10,60,97,32,104,114,101,102,61,34,105,110, +100,101,120,46,112,104,112,119,97,115,32,101,115,116,97,98,108,105,115,104,101, +100,32,105,110,109,105,110,46,106,115,34,62,60,47,115,99,114,105,112,116,62,10, +112,97,114,116,105,99,105,112,97,116,101,32,105,110,32,116,104,101,97,32,115,116 +,114,111,110,103,32,105,110,102,108,117,101,110,99,101,115,116,121,108,101,61,34 +,109,97,114,103,105,110,45,116,111,112,58,114,101,112,114,101,115,101,110,116, +101,100,32,98,121,32,116,104,101,103,114,97,100,117,97,116,101,100,32,102,114, +111,109,32,116,104,101,84,114,97,100,105,116,105,111,110,97,108,108,121,44,32, +116,104,101,69,108,101,109,101,110,116,40,34,115,99,114,105,112,116,34,41,59,72, +111,119,101,118,101,114,44,32,115,105,110,99,101,32,116,104,101,47,100,105,118, +62,10,60,47,100,105,118,62,10,60,100,105,118,32,108,101,102,116,59,32,109,97,114 +,103,105,110,45,108,101,102,116,58,112,114,111,116,101,99,116,105,111,110,32,97, +103,97,105,110,115,116,48,59,32,118,101,114,116,105,99,97,108,45,97,108,105,103, +110,58,85,110,102,111,114,116,117,110,97,116,101,108,121,44,32,116,104,101,116, +121,112,101,61,34,105,109,97,103,101,47,120,45,105,99,111,110,47,100,105,118,62, +10,60,100,105,118,32,99,108,97,115,115,61,34,32,99,108,97,115,115,61,34,99,108, +101,97,114,102,105,120,34,62,60,100,105,118,32,99,108,97,115,115,61,34,102,111, +111,116,101,114,9,9,60,47,100,105,118,62,10,9,9,60,47,100,105,118,62,10,116,104, +101,32,109,111,116,105,111,110,32,112,105,99,116,117,114,101,208,145,209,138,208 +,187,208,179,208,176,209,128,209,129,208,186,208,184,208,177,209,138,208,187,208 +,179,208,176,209,128,209,129,208,186,208,184,208,164,208,181,208,180,208,181,209 +,128,208,176,209,134,208,184,208,184,208,189,208,181,209,129,208,186,208,190,208 +,187,209,140,208,186,208,190,209,129,208,190,208,190,208,177,209,137,208,181,208 +,189,208,184,208,181,209,129,208,190,208,190,208,177,209,137,208,181,208,189,208 +,184,209,143,208,191,209,128,208,190,208,179,209,128,208,176,208,188,208,188,209 +,139,208,158,209,130,208,191,209,128,208,176,208,178,208,184,209,130,209,140,208 +,177,208,181,209,129,208,191,208,187,208,176,209,130,208,189,208,190,208,188,208 +,176,209,130,208,181,209,128,208,184,208,176,208,187,209,139,208,191,208,190,208 +,183,208,178,208,190,208,187,209,143,208,181,209,130,208,191,208,190,209,129,208 +,187,208,181,208,180,208,189,208,184,208,181,209,128,208,176,208,183,208,187,208 +,184,209,135,208,189,209,139,209,133,208,191,209,128,208,190,208,180,209,131,208 +,186,209,134,208,184,208,184,208,191,209,128,208,190,208,179,209,128,208,176,208 +,188,208,188,208,176,208,191,208,190,208,187,208,189,208,190,209,129,209,130,209 +,140,209,142,208,189,208,176,209,133,208,190,208,180,208,184,209,130,209,129,209 +,143,208,184,208,183,208,177,209,128,208,176,208,189,208,189,208,190,208,181,208 +,189,208,176,209,129,208,181,208,187,208,181,208,189,208,184,209,143,208,184,208 +,183,208,188,208,181,208,189,208,181,208,189,208,184,209,143,208,186,208,176,209 +,130,208,181,208,179,208,190,209,128,208,184,208,184,208,144,208,187,208,181,208 +,186,209,129,208,176,208,189,208,180,209,128,224,164,166,224,165,141,224,164,181 +,224,164,190,224,164,176,224,164,190,224,164,174,224,165,136,224,164,168,224,165 +,129,224,164,133,224,164,178,224,164,170,224,165,141,224,164,176,224,164,166,224 +,164,190,224,164,168,224,164,173,224,164,190,224,164,176,224,164,164,224,165,128 +,224,164,175,224,164,133,224,164,168,224,165,129,224,164,166,224,165,135,224,164 +,182,224,164,185,224,164,191,224,164,168,224,165,141,224,164,166,224,165,128,224 +,164,135,224,164,130,224,164,161,224,164,191,224,164,175,224,164,190,224,164,166 +,224,164,191,224,164,178,224,165,141,224,164,178,224,165,128,224,164,133,224,164 +,167,224,164,191,224,164,149,224,164,190,224,164,176,224,164,181,224,165,128,224 +,164,161,224,164,191,224,164,175,224,165,139,224,164,154,224,164,191,224,164,159 +,224,165,141,224,164,160,224,165,135,224,164,184,224,164,174,224,164,190,224,164 +,154,224,164,190,224,164,176,224,164,156,224,164,130,224,164,149,224,165,141,224 +,164,182,224,164,168,224,164,166,224,165,129,224,164,168,224,164,191,224,164,175 +,224,164,190,224,164,170,224,165,141,224,164,176,224,164,175,224,165,139,224,164 +,151,224,164,133,224,164,168,224,165,129,224,164,184,224,164,190,224,164,176,224 +,164,145,224,164,168,224,164,178,224,164,190,224,164,135,224,164,168,224,164,170 +,224,164,190,224,164,176,224,165,141,224,164,159,224,165,128,224,164,182,224,164 +,176,224,165,141,224,164,164,224,165,139,224,164,130,224,164,178,224,165,139,224 +,164,149,224,164,184,224,164,173,224,164,190,224,164,171,224,164,188,224,165,141 +,224,164,178,224,165,136,224,164,182,224,164,182,224,164,176,224,165,141,224,164 +,164,224,165,135,224,164,130,224,164,170,224,165,141,224,164,176,224,164,166,224 +,165,135,224,164,182,224,164,170,224,165,141,224,164,178,224,165,135,224,164,175 +,224,164,176,224,164,149,224,165,135,224,164,130,224,164,166,224,165,141,224,164 +,176,224,164,184,224,165,141,224,164,165,224,164,191,224,164,164,224,164,191,224 +,164,137,224,164,164,224,165,141,224,164,170,224,164,190,224,164,166,224,164,137 +,224,164,168,224,165,141,224,164,185,224,165,135,224,164,130,224,164,154,224,164 +,191,224,164,159,224,165,141,224,164,160,224,164,190,224,164,175,224,164,190,224 +,164,164,224,165,141,224,164,176,224,164,190,224,164,156,224,165,141,224,164,175 +,224,164,190,224,164,166,224,164,190,224,164,170,224,165,129,224,164,176,224,164 +,190,224,164,168,224,165,135,224,164,156,224,165,139,224,164,161,224,164,188,224 +,165,135,224,164,130,224,164,133,224,164,168,224,165,129,224,164,181,224,164,190 +,224,164,166,224,164,182,224,165,141,224,164,176,224,165,135,224,164,163,224,165 +,128,224,164,182,224,164,191,224,164,149,224,165,141,224,164,183,224,164,190,224 +,164,184,224,164,176,224,164,149,224,164,190,224,164,176,224,165,128,224,164,184 +,224,164,130,224,164,151,224,165,141,224,164,176,224,164,185,224,164,170,224,164 +,176,224,164,191,224,164,163,224,164,190,224,164,174,224,164,172,224,165,141,224 +,164,176,224,164,190,224,164,130,224,164,161,224,164,172,224,164,154,224,165,141 +,224,164,154,224,165,139,224,164,130,224,164,137,224,164,170,224,164,178,224,164 +,172,224,165,141,224,164,167,224,164,174,224,164,130,224,164,164,224,165,141,224 +,164,176,224,165,128,224,164,184,224,164,130,224,164,170,224,164,176,224,165,141 +,224,164,149,224,164,137,224,164,174,224,165,141,224,164,174,224,165,128,224,164 +,166,224,164,174,224,164,190,224,164,167,224,165,141,224,164,175,224,164,174,224 +,164,184,224,164,185,224,164,190,224,164,175,224,164,164,224,164,190,224,164,182 +,224,164,172,224,165,141,224,164,166,224,165,139,224,164,130,224,164,174,224,165 +,128,224,164,161,224,164,191,224,164,175,224,164,190,224,164,134,224,164,136,224 +,164,170,224,165,128,224,164,143,224,164,178,224,164,174,224,165,139,224,164,172 +,224,164,190,224,164,135,224,164,178,224,164,184,224,164,130,224,164,150,224,165 +,141,224,164,175,224,164,190,224,164,134,224,164,170,224,164,176,224,165,135,224 +,164,182,224,164,168,224,164,133,224,164,168,224,165,129,224,164,172,224,164,130 +,224,164,167,224,164,172,224,164,190,224,164,156,224,164,188,224,164,190,224,164 +,176,224,164,168,224,164,181,224,165,128,224,164,168,224,164,164,224,164,174,224 +,164,170,224,165,141,224,164,176,224,164,174,224,165,129,224,164,150,224,164,170 +,224,165,141,224,164,176,224,164,182,224,165,141,224,164,168,224,164,170,224,164 +,176,224,164,191,224,164,181,224,164,190,224,164,176,224,164,168,224,165,129,224 +,164,149,224,164,184,224,164,190,224,164,168,224,164,184,224,164,174,224,164,176 +,224,165,141,224,164,165,224,164,168,224,164,134,224,164,175,224,165,139,224,164 +,156,224,164,191,224,164,164,224,164,184,224,165,139,224,164,174,224,164,181,224 +,164,190,224,164,176,216,167,217,132,217,133,216,180,216,167,216,177,217,131,216 +,167,216,170,216,167,217,132,217,133,217,134,216,170,216,175,217,138,216,167,216 +,170,216,167,217,132,217,131,217,133,216,168,217,138,217,136,216,170,216,177,216 +,167,217,132,217,133,216,180,216,167,217,135,216,175,216,167,216,170,216,185,216 +,175,216,175,216,167,217,132,216,178,217,136,216,167,216,177,216,185,216,175,216 +,175,216,167,217,132,216,177,216,175,217,136,216,175,216,167,217,132,216,165,216 +,179,217,132,216,167,217,133,217,138,216,169,216,167,217,132,217,129,217,136,216 +,170,217,136,216,180,217,136,216,168,216,167,217,132,217,133,216,179,216,167,216 +,168,217,130,216,167,216,170,216,167,217,132,217,133,216,185,217,132,217,136,217 +,133,216,167,216,170,216,167,217,132,217,133,216,179,217,132,216,179,217,132,216 +,167,216,170,216,167,217,132,216,172,216,177,216,167,217,129,217,138,217,131,216 +,179,216,167,217,132,216,167,216,179,217,132,216,167,217,133,217,138,216,169,216 +,167,217,132,216,167,216,170,216,181,216,167,217,132,216,167,216,170,107,101,121 +,119,111,114,100,115,34,32,99,111,110,116,101,110,116,61,34,119,51,46,111,114, +103,47,49,57,57,57,47,120,104,116,109,108,34,62,60,97,32,116,97,114,103,101,116, +61,34,95,98,108,97,110,107,34,32,116,101,120,116,47,104,116,109,108,59,32,99,104 +,97,114,115,101,116,61,34,32,116,97,114,103,101,116,61,34,95,98,108,97,110,107, +34,62,60,116,97,98,108,101,32,99,101,108,108,112,97,100,100,105,110,103,61,34,97 +,117,116,111,99,111,109,112,108,101,116,101,61,34,111,102,102,34,32,116,101,120, +116,45,97,108,105,103,110,58,32,99,101,110,116,101,114,59,116,111,32,108,97,115, +116,32,118,101,114,115,105,111,110,32,98,121,32,98,97,99,107,103,114,111,117,110 +,100,45,99,111,108,111,114,58,32,35,34,32,104,114,101,102,61,34,104,116,116,112, +58,47,47,119,119,119,46,47,100,105,118,62,60,47,100,105,118,62,60,100,105,118,32 +,105,100,61,60,97,32,104,114,101,102,61,34,35,34,32,99,108,97,115,115,61,34,34, +62,60,105,109,103,32,115,114,99,61,34,104,116,116,112,58,47,47,99,114,105,112, +116,34,32,115,114,99,61,34,104,116,116,112,58,47,47,10,60,115,99,114,105,112,116 +,32,108,97,110,103,117,97,103,101,61,34,47,47,69,78,34,32,34,104,116,116,112,58, +47,47,119,119,119,46,119,101,110,99,111,100,101,85,82,73,67,111,109,112,111,110, +101,110,116,40,34,32,104,114,101,102,61,34,106,97,118,97,115,99,114,105,112,116, +58,60,100,105,118,32,99,108,97,115,115,61,34,99,111,110,116,101,110,116,100,111, +99,117,109,101,110,116,46,119,114,105,116,101,40,39,60,115,99,112,111,115,105, +116,105,111,110,58,32,97,98,115,111,108,117,116,101,59,115,99,114,105,112,116,32 +,115,114,99,61,34,104,116,116,112,58,47,47,32,115,116,121,108,101,61,34,109,97, +114,103,105,110,45,116,111,112,58,46,109,105,110,46,106,115,34,62,60,47,115,99, +114,105,112,116,62,10,60,47,100,105,118,62,10,60,100,105,118,32,99,108,97,115, +115,61,34,119,51,46,111,114,103,47,49,57,57,57,47,120,104,116,109,108,34,32,10, +13,10,60,47,98,111,100,121,62,13,10,60,47,104,116,109,108,62,100,105,115,116,105 +,110,99,116,105,111,110,32,98,101,116,119,101,101,110,47,34,32,116,97,114,103, +101,116,61,34,95,98,108,97,110,107,34,62,60,108,105,110,107,32,104,114,101,102, +61,34,104,116,116,112,58,47,47,101,110,99,111,100,105,110,103,61,34,117,116,102, +45,56,34,63,62,10,119,46,97,100,100,69,118,101,110,116,76,105,115,116,101,110, +101,114,63,97,99,116,105,111,110,61,34,104,116,116,112,58,47,47,119,119,119,46, +105,99,111,110,34,32,104,114,101,102,61,34,104,116,116,112,58,47,47,32,115,116, +121,108,101,61,34,98,97,99,107,103,114,111,117,110,100,58,116,121,112,101,61,34, +116,101,120,116,47,99,115,115,34,32,47,62,10,109,101,116,97,32,112,114,111,112, +101,114,116,121,61,34,111,103,58,116,60,105,110,112,117,116,32,116,121,112,101, +61,34,116,101,120,116,34,32,32,115,116,121,108,101,61,34,116,101,120,116,45,97, +108,105,103,110,58,116,104,101,32,100,101,118,101,108,111,112,109,101,110,116,32 +,111,102,32,116,121,108,101,115,104,101,101,116,34,32,116,121,112,101,61,34,116, +101,104,116,109,108,59,32,99,104,97,114,115,101,116,61,117,116,102,45,56,105,115 +,32,99,111,110,115,105,100,101,114,101,100,32,116,111,32,98,101,116,97,98,108, +101,32,119,105,100,116,104,61,34,49,48,48,37,34,32,73,110,32,97,100,100,105,116, +105,111,110,32,116,111,32,116,104,101,32,99,111,110,116,114,105,98,117,116,101, +100,32,116,111,32,116,104,101,32,100,105,102,102,101,114,101,110,99,101,115,32, +98,101,116,119,101,101,110,100,101,118,101,108,111,112,109,101,110,116,32,111, +102,32,116,104,101,32,73,116,32,105,115,32,105,109,112,111,114,116,97,110,116,32 +,116,111,32,60,47,115,99,114,105,112,116,62,10,10,60,115,99,114,105,112,116,32, +32,115,116,121,108,101,61,34,102,111,110,116,45,115,105,122,101,58,49,62,60,47, +115,112,97,110,62,60,115,112,97,110,32,105,100,61,103,98,76,105,98,114,97,114, +121,32,111,102,32,67,111,110,103,114,101,115,115,60,105,109,103,32,115,114,99,61 +,34,104,116,116,112,58,47,47,105,109,69,110,103,108,105,115,104,32,116,114,97, +110,115,108,97,116,105,111,110,65,99,97,100,101,109,121,32,111,102,32,83,99,105, +101,110,99,101,115,100,105,118,32,115,116,121,108,101,61,34,100,105,115,112,108, +97,121,58,99,111,110,115,116,114,117,99,116,105,111,110,32,111,102,32,116,104, +101,46,103,101,116,69,108,101,109,101,110,116,66,121,73,100,40,105,100,41,105, +110,32,99,111,110,106,117,110,99,116,105,111,110,32,119,105,116,104,69,108,101, +109,101,110,116,40,39,115,99,114,105,112,116,39,41,59,32,60,109,101,116,97,32, +112,114,111,112,101,114,116,121,61,34,111,103,58,208,145,209,138,208,187,208,179 +,208,176,209,128,209,129,208,186,208,184,10,32,116,121,112,101,61,34,116,101,120 +,116,34,32,110,97,109,101,61,34,62,80,114,105,118,97,99,121,32,80,111,108,105,99 +,121,60,47,97,62,97,100,109,105,110,105,115,116,101,114,101,100,32,98,121,32,116 +,104,101,101,110,97,98,108,101,83,105,110,103,108,101,82,101,113,117,101,115,116 +,115,116,121,108,101,61,38,113,117,111,116,59,109,97,114,103,105,110,58,60,47, +100,105,118,62,60,47,100,105,118,62,60,47,100,105,118,62,60,62,60,105,109,103,32 +,115,114,99,61,34,104,116,116,112,58,47,47,105,32,115,116,121,108,101,61,38,113, +117,111,116,59,102,108,111,97,116,58,114,101,102,101,114,114,101,100,32,116,111, +32,97,115,32,116,104,101,32,116,111,116,97,108,32,112,111,112,117,108,97,116,105 +,111,110,32,111,102,105,110,32,87,97,115,104,105,110,103,116,111,110,44,32,68,46 +,67,46,32,115,116,121,108,101,61,34,98,97,99,107,103,114,111,117,110,100,45,97, +109,111,110,103,32,111,116,104,101,114,32,116,104,105,110,103,115,44,111,114,103 +,97,110,105,122,97,116,105,111,110,32,111,102,32,116,104,101,112,97,114,116,105, +99,105,112,97,116,101,100,32,105,110,32,116,104,101,116,104,101,32,105,110,116, +114,111,100,117,99,116,105,111,110,32,111,102,105,100,101,110,116,105,102,105, +101,100,32,119,105,116,104,32,116,104,101,102,105,99,116,105,111,110,97,108,32, +99,104,97,114,97,99,116,101,114,32,79,120,102,111,114,100,32,85,110,105,118,101, +114,115,105,116,121,32,109,105,115,117,110,100,101,114,115,116,97,110,100,105, +110,103,32,111,102,84,104,101,114,101,32,97,114,101,44,32,104,111,119,101,118, +101,114,44,115,116,121,108,101,115,104,101,101,116,34,32,104,114,101,102,61,34, +47,67,111,108,117,109,98,105,97,32,85,110,105,118,101,114,115,105,116,121,101, +120,112,97,110,100,101,100,32,116,111,32,105,110,99,108,117,100,101,117,115,117, +97,108,108,121,32,114,101,102,101,114,114,101,100,32,116,111,105,110,100,105,99, +97,116,105,110,103,32,116,104,97,116,32,116,104,101,104,97,118,101,32,115,117, +103,103,101,115,116,101,100,32,116,104,97,116,97,102,102,105,108,105,97,116,101, +100,32,119,105,116,104,32,116,104,101,99,111,114,114,101,108,97,116,105,111,110, +32,98,101,116,119,101,101,110,110,117,109,98,101,114,32,111,102,32,100,105,102, +102,101,114,101,110,116,62,60,47,116,100,62,60,47,116,114,62,60,47,116,97,98,108 +,101,62,82,101,112,117,98,108,105,99,32,111,102,32,73,114,101,108,97,110,100,10, +60,47,115,99,114,105,112,116,62,10,60,115,99,114,105,112,116,32,117,110,100,101, +114,32,116,104,101,32,105,110,102,108,117,101,110,99,101,99,111,110,116,114,105, +98,117,116,105,111,110,32,116,111,32,116,104,101,79,102,102,105,99,105,97,108,32 +,119,101,98,115,105,116,101,32,111,102,104,101,97,100,113,117,97,114,116,101,114 +,115,32,111,102,32,116,104,101,99,101,110,116,101,114,101,100,32,97,114,111,117, +110,100,32,116,104,101,105,109,112,108,105,99,97,116,105,111,110,115,32,111,102, +32,116,104,101,104,97,118,101,32,98,101,101,110,32,100,101,118,101,108,111,112, +101,100,70,101,100,101,114,97,108,32,82,101,112,117,98,108,105,99,32,111,102,98, +101,99,97,109,101,32,105,110,99,114,101,97,115,105,110,103,108,121,99,111,110, +116,105,110,117,97,116,105,111,110,32,111,102,32,116,104,101,78,111,116,101,44, +32,104,111,119,101,118,101,114,44,32,116,104,97,116,115,105,109,105,108,97,114, +32,116,111,32,116,104,97,116,32,111,102,32,99,97,112,97,98,105,108,105,116,105, +101,115,32,111,102,32,116,104,101,97,99,99,111,114,100,97,110,99,101,32,119,105, +116,104,32,116,104,101,112,97,114,116,105,99,105,112,97,110,116,115,32,105,110, +32,116,104,101,102,117,114,116,104,101,114,32,100,101,118,101,108,111,112,109, +101,110,116,117,110,100,101,114,32,116,104,101,32,100,105,114,101,99,116,105,111 +,110,105,115,32,111,102,116,101,110,32,99,111,110,115,105,100,101,114,101,100, +104,105,115,32,121,111,117,110,103,101,114,32,98,114,111,116,104,101,114,60,47, +116,100,62,60,47,116,114,62,60,47,116,97,98,108,101,62,60,97,32,104,116,116,112, +45,101,113,117,105,118,61,34,88,45,85,65,45,112,104,121,115,105,99,97,108,32,112 +,114,111,112,101,114,116,105,101,115,111,102,32,66,114,105,116,105,115,104,32,67 +,111,108,117,109,98,105,97,104,97,115,32,98,101,101,110,32,99,114,105,116,105,99 +,105,122,101,100,40,119,105,116,104,32,116,104,101,32,101,120,99,101,112,116,105 +,111,110,113,117,101,115,116,105,111,110,115,32,97,98,111,117,116,32,116,104,101 +,112,97,115,115,105,110,103,32,116,104,114,111,117,103,104,32,116,104,101,48,34, +32,99,101,108,108,112,97,100,100,105,110,103,61,34,48,34,32,116,104,111,117,115, +97,110,100,115,32,111,102,32,112,101,111,112,108,101,114,101,100,105,114,101,99, +116,115,32,104,101,114,101,46,32,70,111,114,104,97,118,101,32,99,104,105,108,100 +,114,101,110,32,117,110,100,101,114,37,51,69,37,51,67,47,115,99,114,105,112,116, +37,51,69,34,41,41,59,60,97,32,104,114,101,102,61,34,104,116,116,112,58,47,47,119 +,119,119,46,60,108,105,62,60,97,32,104,114,101,102,61,34,104,116,116,112,58,47, +47,115,105,116,101,95,110,97,109,101,34,32,99,111,110,116,101,110,116,61,34,116, +101,120,116,45,100,101,99,111,114,97,116,105,111,110,58,110,111,110,101,115,116, +121,108,101,61,34,100,105,115,112,108,97,121,58,32,110,111,110,101,60,109,101, +116,97,32,104,116,116,112,45,101,113,117,105,118,61,34,88,45,110,101,119,32,68, +97,116,101,40,41,46,103,101,116,84,105,109,101,40,41,32,116,121,112,101,61,34, +105,109,97,103,101,47,120,45,105,99,111,110,34,60,47,115,112,97,110,62,60,115, +112,97,110,32,99,108,97,115,115,61,34,108,97,110,103,117,97,103,101,61,34,106,97 +,118,97,115,99,114,105,112,116,119,105,110,100,111,119,46,108,111,99,97,116,105, +111,110,46,104,114,101,102,60,97,32,104,114,101,102,61,34,106,97,118,97,115,99, +114,105,112,116,58,45,45,62,13,10,60,115,99,114,105,112,116,32,116,121,112,101, +61,34,116,60,97,32,104,114,101,102,61,39,104,116,116,112,58,47,47,119,119,119,46 +,104,111,114,116,99,117,116,32,105,99,111,110,34,32,104,114,101,102,61,34,60,47, +100,105,118,62,13,10,60,100,105,118,32,99,108,97,115,115,61,34,60,115,99,114,105 +,112,116,32,115,114,99,61,34,104,116,116,112,58,47,47,34,32,114,101,108,61,34, +115,116,121,108,101,115,104,101,101,116,34,32,116,60,47,100,105,118,62,10,60,115 +,99,114,105,112,116,32,116,121,112,101,61,47,97,62,32,60,97,32,104,114,101,102, +61,34,104,116,116,112,58,47,47,32,97,108,108,111,119,84,114,97,110,115,112,97, +114,101,110,99,121,61,34,88,45,85,65,45,67,111,109,112,97,116,105,98,108,101,34, +32,99,111,110,114,101,108,97,116,105,111,110,115,104,105,112,32,98,101,116,119, +101,101,110,10,60,47,115,99,114,105,112,116,62,13,10,60,115,99,114,105,112,116, +32,60,47,97,62,60,47,108,105,62,60,47,117,108,62,60,47,100,105,118,62,97,115,115 +,111,99,105,97,116,101,100,32,119,105,116,104,32,116,104,101,32,112,114,111,103, +114,97,109,109,105,110,103,32,108,97,110,103,117,97,103,101,60,47,97,62,60,97,32 +,104,114,101,102,61,34,104,116,116,112,58,47,47,60,47,97,62,60,47,108,105,62,60, +108,105,32,99,108,97,115,115,61,34,102,111,114,109,32,97,99,116,105,111,110,61, +34,104,116,116,112,58,47,47,60,100,105,118,32,115,116,121,108,101,61,34,100,105, +115,112,108,97,121,58,116,121,112,101,61,34,116,101,120,116,34,32,110,97,109,101 +,61,34,113,34,60,116,97,98,108,101,32,119,105,100,116,104,61,34,49,48,48,37,34, +32,98,97,99,107,103,114,111,117,110,100,45,112,111,115,105,116,105,111,110,58,34 +,32,98,111,114,100,101,114,61,34,48,34,32,119,105,100,116,104,61,34,114,101,108, +61,34,115,104,111,114,116,99,117,116,32,105,99,111,110,34,32,104,54,62,60,117, +108,62,60,108,105,62,60,97,32,104,114,101,102,61,34,32,32,60,109,101,116,97,32, +104,116,116,112,45,101,113,117,105,118,61,34,99,115,115,34,32,109,101,100,105,97 +,61,34,115,99,114,101,101,110,34,32,114,101,115,112,111,110,115,105,98,108,101, +32,102,111,114,32,116,104,101,32,34,32,116,121,112,101,61,34,97,112,112,108,105, +99,97,116,105,111,110,47,34,32,115,116,121,108,101,61,34,98,97,99,107,103,114, +111,117,110,100,45,104,116,109,108,59,32,99,104,97,114,115,101,116,61,117,116, +102,45,56,34,32,97,108,108,111,119,116,114,97,110,115,112,97,114,101,110,99,121, +61,34,115,116,121,108,101,115,104,101,101,116,34,32,116,121,112,101,61,34,116, +101,13,10,60,109,101,116,97,32,104,116,116,112,45,101,113,117,105,118,61,34,62, +60,47,115,112,97,110,62,60,115,112,97,110,32,99,108,97,115,115,61,34,48,34,32,99 +,101,108,108,115,112,97,99,105,110,103,61,34,48,34,62,59,10,60,47,115,99,114,105 +,112,116,62,10,60,115,99,114,105,112,116,32,115,111,109,101,116,105,109,101,115, +32,99,97,108,108,101,100,32,116,104,101,100,111,101,115,32,110,111,116,32,110, +101,99,101,115,115,97,114,105,108,121,70,111,114,32,109,111,114,101,32,105,110, +102,111,114,109,97,116,105,111,110,97,116,32,116,104,101,32,98,101,103,105,110, +110,105,110,103,32,111,102,32,60,33,68,79,67,84,89,80,69,32,104,116,109,108,62, +60,104,116,109,108,112,97,114,116,105,99,117,108,97,114,108,121,32,105,110,32, +116,104,101,32,116,121,112,101,61,34,104,105,100,100,101,110,34,32,110,97,109, +101,61,34,106,97,118,97,115,99,114,105,112,116,58,118,111,105,100,40,48,41,59,34 +,101,102,102,101,99,116,105,118,101,110,101,115,115,32,111,102,32,116,104,101,32 +,97,117,116,111,99,111,109,112,108,101,116,101,61,34,111,102,102,34,32,103,101, +110,101,114,97,108,108,121,32,99,111,110,115,105,100,101,114,101,100,62,60,105, +110,112,117,116,32,116,121,112,101,61,34,116,101,120,116,34,32,34,62,60,47,115, +99,114,105,112,116,62,13,10,60,115,99,114,105,112,116,116,104,114,111,117,103, +104,111,117,116,32,116,104,101,32,119,111,114,108,100,99,111,109,109,111,110,32, +109,105,115,99,111,110,99,101,112,116,105,111,110,97,115,115,111,99,105,97,116, +105,111,110,32,119,105,116,104,32,116,104,101,60,47,100,105,118,62,10,60,47,100, +105,118,62,10,60,100,105,118,32,99,100,117,114,105,110,103,32,104,105,115,32,108 +,105,102,101,116,105,109,101,44,99,111,114,114,101,115,112,111,110,100,105,110, +103,32,116,111,32,116,104,101,116,121,112,101,61,34,105,109,97,103,101,47,120,45 +,105,99,111,110,34,32,97,110,32,105,110,99,114,101,97,115,105,110,103,32,110,117 +,109,98,101,114,100,105,112,108,111,109,97,116,105,99,32,114,101,108,97,116,105, +111,110,115,97,114,101,32,111,102,116,101,110,32,99,111,110,115,105,100,101,114, +101,100,109,101,116,97,32,99,104,97,114,115,101,116,61,34,117,116,102,45,56,34, +32,60,105,110,112,117,116,32,116,121,112,101,61,34,116,101,120,116,34,32,101,120 +,97,109,112,108,101,115,32,105,110,99,108,117,100,101,32,116,104,101,34,62,60, +105,109,103,32,115,114,99,61,34,104,116,116,112,58,47,47,105,112,97,114,116,105, +99,105,112,97,116,105,111,110,32,105,110,32,116,104,101,116,104,101,32,101,115, +116,97,98,108,105,115,104,109,101,110,116,32,111,102,10,60,47,100,105,118,62,10, +60,100,105,118,32,99,108,97,115,115,61,34,38,97,109,112,59,110,98,115,112,59,38, +97,109,112,59,110,98,115,112,59,116,111,32,100,101,116,101,114,109,105,110,101, +32,119,104,101,116,104,101,114,113,117,105,116,101,32,100,105,102,102,101,114, +101,110,116,32,102,114,111,109,109,97,114,107,101,100,32,116,104,101,32,98,101, +103,105,110,110,105,110,103,100,105,115,116,97,110,99,101,32,98,101,116,119,101, +101,110,32,116,104,101,99,111,110,116,114,105,98,117,116,105,111,110,115,32,116, +111,32,116,104,101,99,111,110,102,108,105,99,116,32,98,101,116,119,101,101,110, +32,116,104,101,119,105,100,101,108,121,32,99,111,110,115,105,100,101,114,101,100 +,32,116,111,119,97,115,32,111,110,101,32,111,102,32,116,104,101,32,102,105,114, +115,116,119,105,116,104,32,118,97,114,121,105,110,103,32,100,101,103,114,101,101 +,115,104,97,118,101,32,115,112,101,99,117,108,97,116,101,100,32,116,104,97,116, +40,100,111,99,117,109,101,110,116,46,103,101,116,69,108,101,109,101,110,116,112, +97,114,116,105,99,105,112,97,116,105,110,103,32,105,110,32,116,104,101,111,114, +105,103,105,110,97,108,108,121,32,100,101,118,101,108,111,112,101,100,101,116,97 +,32,99,104,97,114,115,101,116,61,34,117,116,102,45,56,34,62,32,116,121,112,101, +61,34,116,101,120,116,47,99,115,115,34,32,47,62,10,105,110,116,101,114,99,104,97 +,110,103,101,97,98,108,121,32,119,105,116,104,109,111,114,101,32,99,108,111,115, +101,108,121,32,114,101,108,97,116,101,100,115,111,99,105,97,108,32,97,110,100,32 +,112,111,108,105,116,105,99,97,108,116,104,97,116,32,119,111,117,108,100,32,111, +116,104,101,114,119,105,115,101,112,101,114,112,101,110,100,105,99,117,108,97, +114,32,116,111,32,116,104,101,115,116,121,108,101,32,116,121,112,101,61,34,116, +101,120,116,47,99,115,115,116,121,112,101,61,34,115,117,98,109,105,116,34,32,110 +,97,109,101,61,34,102,97,109,105,108,105,101,115,32,114,101,115,105,100,105,110, +103,32,105,110,100,101,118,101,108,111,112,105,110,103,32,99,111,117,110,116,114 +,105,101,115,99,111,109,112,117,116,101,114,32,112,114,111,103,114,97,109,109, +105,110,103,101,99,111,110,111,109,105,99,32,100,101,118,101,108,111,112,109,101 +,110,116,100,101,116,101,114,109,105,110,97,116,105,111,110,32,111,102,32,116, +104,101,102,111,114,32,109,111,114,101,32,105,110,102,111,114,109,97,116,105,111 +,110,111,110,32,115,101,118,101,114,97,108,32,111,99,99,97,115,105,111,110,115, +112,111,114,116,117,103,117,195,170,115,32,40,69,117,114,111,112,101,117,41,208, +163,208,186,209,128,208,176,209,151,208,189,209,129,209,140,208,186,208,176,209, +131,208,186,209,128,208,176,209,151,208,189,209,129,209,140,208,186,208,176,208, +160,208,190,209,129,209,129,208,184,208,185,209,129,208,186,208,190,208,185,208, +188,208,176,209,130,208,181,209,128,208,184,208,176,208,187,208,190,208,178,208, +184,208,189,209,132,208,190,209,128,208,188,208,176,209,134,208,184,208,184,209, +131,208,191,209,128,208,176,208,178,208,187,208,181,208,189,208,184,209,143,208, +189,208,181,208,190,208,177,209,133,208,190,208,180,208,184,208,188,208,190,208, +184,208,189,209,132,208,190,209,128,208,188,208,176,209,134,208,184,209,143,208, +152,208,189,209,132,208,190,209,128,208,188,208,176,209,134,208,184,209,143,208, +160,208,181,209,129,208,191,209,131,208,177,208,187,208,184,208,186,208,184,208, +186,208,190,208,187,208,184,209,135,208,181,209,129,209,130,208,178,208,190,208, +184,208,189,209,132,208,190,209,128,208,188,208,176,209,134,208,184,209,142,209, +130,208,181,209,128,209,128,208,184,209,130,208,190,209,128,208,184,208,184,208, +180,208,190,209,129,209,130,208,176,209,130,208,190,209,135,208,189,208,190,216, +167,217,132,217,133,216,170,217,136,216,167,216,172,216,175,217,136,217,134,216, +167,217,132,216,167,216,180,216,170,216,177,216,167,217,131,216,167,216,170,216, +167,217,132,216,167,217,130,216,170,216,177,216,167,216,173,216,167,216,170,104, +116,109,108,59,32,99,104,97,114,115,101,116,61,85,84,70,45,56,34,32,115,101,116, +84,105,109,101,111,117,116,40,102,117,110,99,116,105,111,110,40,41,100,105,115, +112,108,97,121,58,105,110,108,105,110,101,45,98,108,111,99,107,59,60,105,110,112 +,117,116,32,116,121,112,101,61,34,115,117,98,109,105,116,34,32,116,121,112,101, +32,61,32,39,116,101,120,116,47,106,97,118,97,115,99,114,105,60,105,109,103,32, +115,114,99,61,34,104,116,116,112,58,47,47,119,119,119,46,34,32,34,104,116,116, +112,58,47,47,119,119,119,46,119,51,46,111,114,103,47,115,104,111,114,116,99,117, +116,32,105,99,111,110,34,32,104,114,101,102,61,34,34,32,97,117,116,111,99,111, +109,112,108,101,116,101,61,34,111,102,102,34,32,60,47,97,62,60,47,100,105,118,62 +,60,100,105,118,32,99,108,97,115,115,61,60,47,97,62,60,47,108,105,62,10,60,108, +105,32,99,108,97,115,115,61,34,99,115,115,34,32,116,121,112,101,61,34,116,101, +120,116,47,99,115,115,34,32,60,102,111,114,109,32,97,99,116,105,111,110,61,34, +104,116,116,112,58,47,47,120,116,47,99,115,115,34,32,104,114,101,102,61,34,104, +116,116,112,58,47,47,108,105,110,107,32,114,101,108,61,34,97,108,116,101,114,110 +,97,116,101,34,32,13,10,60,115,99,114,105,112,116,32,116,121,112,101,61,34,116, +101,120,116,47,32,111,110,99,108,105,99,107,61,34,106,97,118,97,115,99,114,105, +112,116,58,40,110,101,119,32,68,97,116,101,41,46,103,101,116,84,105,109,101,40, +41,125,104,101,105,103,104,116,61,34,49,34,32,119,105,100,116,104,61,34,49,34,32 +,80,101,111,112,108,101,39,115,32,82,101,112,117,98,108,105,99,32,111,102,32,32, +60,97,32,104,114,101,102,61,34,104,116,116,112,58,47,47,119,119,119,46,116,101, +120,116,45,100,101,99,111,114,97,116,105,111,110,58,117,110,100,101,114,116,104, +101,32,98,101,103,105,110,110,105,110,103,32,111,102,32,116,104,101,32,60,47,100 +,105,118,62,10,60,47,100,105,118,62,10,60,47,100,105,118,62,10,101,115,116,97,98 +,108,105,115,104,109,101,110,116,32,111,102,32,116,104,101,32,60,47,100,105,118, +62,60,47,100,105,118,62,60,47,100,105,118,62,60,47,100,35,118,105,101,119,112, +111,114,116,123,109,105,110,45,104,101,105,103,104,116,58,10,60,115,99,114,105, +112,116,32,115,114,99,61,34,104,116,116,112,58,47,47,111,112,116,105,111,110,62, +60,111,112,116,105,111,110,32,118,97,108,117,101,61,111,102,116,101,110,32,114, +101,102,101,114,114,101,100,32,116,111,32,97,115,32,47,111,112,116,105,111,110, +62,10,60,111,112,116,105,111,110,32,118,97,108,117,60,33,68,79,67,84,89,80,69,32 +,104,116,109,108,62,10,60,33,45,45,91,73,110,116,101,114,110,97,116,105,111,110, +97,108,32,65,105,114,112,111,114,116,62,10,60,97,32,104,114,101,102,61,34,104, +116,116,112,58,47,47,119,119,119,60,47,97,62,60,97,32,104,114,101,102,61,34,104, +116,116,112,58,47,47,119,224,184,160,224,184,178,224,184,169,224,184,178,224,185 +,132,224,184,151,224,184,162,225,131,165,225,131,144,225,131,160,225,131,151,225 +,131,163,225,131,154,225,131,152,230,173,163,233,171,148,228,184,173,230,150,135 +,32,40,231,185,129,233,171,148,41,224,164,168,224,164,191,224,164,176,224,165, +141,224,164,166,224,165,135,224,164,182,224,164,161,224,164,190,224,164,137,224, +164,168,224,164,178,224,165,139,224,164,161,224,164,149,224,165,141,224,164,183, +224,165,135,224,164,164,224,165,141,224,164,176,224,164,156,224,164,190,224,164, +168,224,164,149,224,164,190,224,164,176,224,165,128,224,164,184,224,164,130,224, +164,172,224,164,130,224,164,167,224,164,191,224,164,164,224,164,184,224,165,141, +224,164,165,224,164,190,224,164,170,224,164,168,224,164,190,224,164,184,224,165, +141,224,164,181,224,165,128,224,164,149,224,164,190,224,164,176,224,164,184,224, +164,130,224,164,184,224,165,141,224,164,149,224,164,176,224,164,163,224,164,184, +224,164,190,224,164,174,224,164,151,224,165,141,224,164,176,224,165,128,224,164, +154,224,164,191,224,164,159,224,165,141,224,164,160,224,165,139,224,164,130,224, +164,181,224,164,191,224,164,156,224,165,141,224,164,158,224,164,190,224,164,168, +224,164,133,224,164,174,224,165,135,224,164,176,224,164,191,224,164,149,224,164, +190,224,164,181,224,164,191,224,164,173,224,164,191,224,164,168,224,165,141,224, +164,168,224,164,151,224,164,190,224,164,161,224,164,191,224,164,175,224,164,190, +224,164,129,224,164,149,224,165,141,224,164,175,224,165,139,224,164,130,224,164, +149,224,164,191,224,164,184,224,165,129,224,164,176,224,164,149,224,165,141,224, +164,183,224,164,190,224,164,170,224,164,185,224,165,129,224,164,129,224,164,154, +224,164,164,224,165,128,224,164,170,224,165,141,224,164,176,224,164,172,224,164, +130,224,164,167,224,164,168,224,164,159,224,164,191,224,164,170,224,165,141,224, +164,170,224,164,163,224,165,128,224,164,149,224,165,141,224,164,176,224,164,191, +224,164,149,224,165,135,224,164,159,224,164,170,224,165,141,224,164,176,224,164, +190,224,164,176,224,164,130,224,164,173,224,164,170,224,165,141,224,164,176,224, +164,190,224,164,170,224,165,141,224,164,164,224,164,174,224,164,190,224,164,178, +224,164,191,224,164,149,224,165,139,224,164,130,224,164,176,224,164,171,224,164, +188,224,165,141,224,164,164,224,164,190,224,164,176,224,164,168,224,164,191,224, +164,176,224,165,141,224,164,174,224,164,190,224,164,163,224,164,178,224,164,191, +224,164,174,224,164,191,224,164,159,224,165,135,224,164,161,100,101,115,99,114, +105,112,116,105,111,110,34,32,99,111,110,116,101,110,116,61,34,100,111,99,117, +109,101,110,116,46,108,111,99,97,116,105,111,110,46,112,114,111,116,46,103,101, +116,69,108,101,109,101,110,116,115,66,121,84,97,103,78,97,109,101,40,60,33,68,79 +,67,84,89,80,69,32,104,116,109,108,62,10,60,104,116,109,108,32,60,109,101,116,97 +,32,99,104,97,114,115,101,116,61,34,117,116,102,45,56,34,62,58,117,114,108,34,32 +,99,111,110,116,101,110,116,61,34,104,116,116,112,58,47,47,46,99,115,115,34,32, +114,101,108,61,34,115,116,121,108,101,115,104,101,101,116,34,115,116,121,108,101 +,32,116,121,112,101,61,34,116,101,120,116,47,99,115,115,34,62,116,121,112,101,61 +,34,116,101,120,116,47,99,115,115,34,32,104,114,101,102,61,34,119,51,46,111,114, +103,47,49,57,57,57,47,120,104,116,109,108,34,32,120,109,108,116,121,112,101,61, +34,116,101,120,116,47,106,97,118,97,115,99,114,105,112,116,34,32,109,101,116,104 +,111,100,61,34,103,101,116,34,32,97,99,116,105,111,110,61,34,108,105,110,107,32, +114,101,108,61,34,115,116,121,108,101,115,104,101,101,116,34,32,32,61,32,100,111 +,99,117,109,101,110,116,46,103,101,116,69,108,101,109,101,110,116,116,121,112, +101,61,34,105,109,97,103,101,47,120,45,105,99,111,110,34,32,47,62,99,101,108,108 +,112,97,100,100,105,110,103,61,34,48,34,32,99,101,108,108,115,112,46,99,115,115, +34,32,116,121,112,101,61,34,116,101,120,116,47,99,115,115,34,32,60,47,97,62,60, +47,108,105,62,60,108,105,62,60,97,32,104,114,101,102,61,34,34,32,119,105,100,116 +,104,61,34,49,34,32,104,101,105,103,104,116,61,34,49,34,34,62,60,97,32,104,114, +101,102,61,34,104,116,116,112,58,47,47,119,119,119,46,115,116,121,108,101,61,34, +100,105,115,112,108,97,121,58,110,111,110,101,59,34,62,97,108,116,101,114,110,97 +,116,101,34,32,116,121,112,101,61,34,97,112,112,108,105,45,47,47,87,51,67,47,47, +68,84,68,32,88,72,84,77,76,32,49,46,48,32,101,108,108,115,112,97,99,105,110,103, +61,34,48,34,32,99,101,108,108,112,97,100,32,116,121,112,101,61,34,104,105,100, +100,101,110,34,32,118,97,108,117,101,61,34,47,97,62,38,110,98,115,112,59,60,115, +112,97,110,32,114,111,108,101,61,34,115,10,60,105,110,112,117,116,32,116,121,112 +,101,61,34,104,105,100,100,101,110,34,32,108,97,110,103,117,97,103,101,61,34,74, +97,118,97,83,99,114,105,112,116,34,32,32,100,111,99,117,109,101,110,116,46,103, +101,116,69,108,101,109,101,110,116,115,66,103,61,34,48,34,32,99,101,108,108,115, +112,97,99,105,110,103,61,34,48,34,32,121,112,101,61,34,116,101,120,116,47,99,115 +,115,34,32,109,101,100,105,97,61,34,116,121,112,101,61,39,116,101,120,116,47,106 +,97,118,97,115,99,114,105,112,116,39,119,105,116,104,32,116,104,101,32,101,120, +99,101,112,116,105,111,110,32,111,102,32,121,112,101,61,34,116,101,120,116,47,99 +,115,115,34,32,114,101,108,61,34,115,116,32,104,101,105,103,104,116,61,34,49,34, +32,119,105,100,116,104,61,34,49,34,32,61,39,43,101,110,99,111,100,101,85,82,73, +67,111,109,112,111,110,101,110,116,40,60,108,105,110,107,32,114,101,108,61,34,97 +,108,116,101,114,110,97,116,101,34,32,10,98,111,100,121,44,32,116,114,44,32,105, +110,112,117,116,44,32,116,101,120,116,109,101,116,97,32,110,97,109,101,61,34,114 +,111,98,111,116,115,34,32,99,111,110,109,101,116,104,111,100,61,34,112,111,115, +116,34,32,97,99,116,105,111,110,61,34,62,10,60,97,32,104,114,101,102,61,34,104, +116,116,112,58,47,47,119,119,119,46,99,115,115,34,32,114,101,108,61,34,115,116, +121,108,101,115,104,101,101,116,34,32,60,47,100,105,118,62,60,47,100,105,118,62, +60,100,105,118,32,99,108,97,115,115,108,97,110,103,117,97,103,101,61,34,106,97, +118,97,115,99,114,105,112,116,34,62,97,114,105,97,45,104,105,100,100,101,110,61, +34,116,114,117,101,34,62,194,183,60,114,105,112,116,34,32,116,121,112,101,61,34, +116,101,120,116,47,106,97,118,97,115,108,61,48,59,125,41,40,41,59,10,40,102,117, +110,99,116,105,111,110,40,41,123,98,97,99,107,103,114,111,117,110,100,45,105,109 +,97,103,101,58,32,117,114,108,40,47,97,62,60,47,108,105,62,60,108,105,62,60,97, +32,104,114,101,102,61,34,104,9,9,60,108,105,62,60,97,32,104,114,101,102,61,34, +104,116,116,112,58,47,47,97,116,111,114,34,32,97,114,105,97,45,104,105,100,100, +101,110,61,34,116,114,117,62,32,60,97,32,104,114,101,102,61,34,104,116,116,112, +58,47,47,119,119,119,46,108,97,110,103,117,97,103,101,61,34,106,97,118,97,115,99 +,114,105,112,116,34,32,47,111,112,116,105,111,110,62,10,60,111,112,116,105,111, +110,32,118,97,108,117,101,47,100,105,118,62,60,47,100,105,118,62,60,100,105,118, +32,99,108,97,115,115,61,114,97,116,111,114,34,32,97,114,105,97,45,104,105,100, +100,101,110,61,34,116,114,101,61,40,110,101,119,32,68,97,116,101,41,46,103,101, +116,84,105,109,101,40,41,112,111,114,116,117,103,117,195,170,115,32,40,100,111, +32,66,114,97,115,105,108,41,208,190,209,128,208,179,208,176,208,189,208,184,208, +183,208,176,209,134,208,184,208,184,208,178,208,190,208,183,208,188,208,190,208, +182,208,189,208,190,209,129,209,130,209,140,208,190,208,177,209,128,208,176,208, +183,208,190,208,178,208,176,208,189,208,184,209,143,209,128,208,181,208,179,208, +184,209,129,209,130,209,128,208,176,209,134,208,184,208,184,208,178,208,190,208, +183,208,188,208,190,208,182,208,189,208,190,209,129,209,130,208,184,208,190,208, +177,209,143,208,183,208,176,209,130,208,181,208,187,209,140,208,189,208,176,60, +33,68,79,67,84,89,80,69,32,104,116,109,108,32,80,85,66,76,73,67,32,34,110,116,45 +,84,121,112,101,34,32,99,111,110,116,101,110,116,61,34,116,101,120,116,47,60,109 +,101,116,97,32,104,116,116,112,45,101,113,117,105,118,61,34,67,111,110,116,101, +114,97,110,115,105,116,105,111,110,97,108,47,47,69,78,34,32,34,104,116,116,112, +58,60,104,116,109,108,32,120,109,108,110,115,61,34,104,116,116,112,58,47,47,119, +119,119,45,47,47,87,51,67,47,47,68,84,68,32,88,72,84,77,76,32,49,46,48,32,84,68, +84,68,47,120,104,116,109,108,49,45,116,114,97,110,115,105,116,105,111,110,97,108 +,47,47,119,119,119,46,119,51,46,111,114,103,47,84,82,47,120,104,116,109,108,49, +47,112,101,32,61,32,39,116,101,120,116,47,106,97,118,97,115,99,114,105,112,116, +39,59,60,109,101,116,97,32,110,97,109,101,61,34,100,101,115,99,114,105,112,116, +105,111,110,112,97,114,101,110,116,78,111,100,101,46,105,110,115,101,114,116,66, +101,102,111,114,101,60,105,110,112,117,116,32,116,121,112,101,61,34,104,105,100, +100,101,110,34,32,110,97,106,115,34,32,116,121,112,101,61,34,116,101,120,116,47, +106,97,118,97,115,99,114,105,40,100,111,99,117,109,101,110,116,41,46,114,101,97, +100,121,40,102,117,110,99,116,105,115,99,114,105,112,116,32,116,121,112,101,61, +34,116,101,120,116,47,106,97,118,97,115,105,109,97,103,101,34,32,99,111,110,116, +101,110,116,61,34,104,116,116,112,58,47,47,85,65,45,67,111,109,112,97,116,105,98 +,108,101,34,32,99,111,110,116,101,110,116,61,116,109,108,59,32,99,104,97,114,115 +,101,116,61,117,116,102,45,56,34,32,47,62,10,108,105,110,107,32,114,101,108,61, +34,115,104,111,114,116,99,117,116,32,105,99,111,110,60,108,105,110,107,32,114, +101,108,61,34,115,116,121,108,101,115,104,101,101,116,34,32,60,47,115,99,114,105 +,112,116,62,10,60,115,99,114,105,112,116,32,116,121,112,101,61,61,32,100,111,99, +117,109,101,110,116,46,99,114,101,97,116,101,69,108,101,109,101,110,60,97,32,116 +,97,114,103,101,116,61,34,95,98,108,97,110,107,34,32,104,114,101,102,61,32,100, +111,99,117,109,101,110,116,46,103,101,116,69,108,101,109,101,110,116,115,66,105, +110,112,117,116,32,116,121,112,101,61,34,116,101,120,116,34,32,110,97,109,101,61 +,97,46,116,121,112,101,32,61,32,39,116,101,120,116,47,106,97,118,97,115,99,114, +105,110,112,117,116,32,116,121,112,101,61,34,104,105,100,100,101,110,34,32,110, +97,109,101,104,116,109,108,59,32,99,104,97,114,115,101,116,61,117,116,102,45,56, +34,32,47,62,100,116,100,34,62,10,60,104,116,109,108,32,120,109,108,110,115,61,34 +,104,116,116,112,45,47,47,87,51,67,47,47,68,84,68,32,72,84,77,76,32,52,46,48,49, +32,84,101,110,116,115,66,121,84,97,103,78,97,109,101,40,39,115,99,114,105,112, +116,39,41,105,110,112,117,116,32,116,121,112,101,61,34,104,105,100,100,101,110, +34,32,110,97,109,60,115,99,114,105,112,116,32,116,121,112,101,61,34,116,101,120, +116,47,106,97,118,97,115,34,32,115,116,121,108,101,61,34,100,105,115,112,108,97, +121,58,110,111,110,101,59,34,62,100,111,99,117,109,101,110,116,46,103,101,116,69 +,108,101,109,101,110,116,66,121,73,100,40,61,100,111,99,117,109,101,110,116,46, +99,114,101,97,116,101,69,108,101,109,101,110,116,40,39,32,116,121,112,101,61,39, +116,101,120,116,47,106,97,118,97,115,99,114,105,112,116,39,105,110,112,117,116, +32,116,121,112,101,61,34,116,101,120,116,34,32,110,97,109,101,61,34,100,46,103, +101,116,69,108,101,109,101,110,116,115,66,121,84,97,103,78,97,109,101,40,115,110 +,105,99,97,108,34,32,104,114,101,102,61,34,104,116,116,112,58,47,47,119,119,119, +46,67,47,47,68,84,68,32,72,84,77,76,32,52,46,48,49,32,84,114,97,110,115,105,116, +60,115,116,121,108,101,32,116,121,112,101,61,34,116,101,120,116,47,99,115,115,34 +,62,10,10,60,115,116,121,108,101,32,116,121,112,101,61,34,116,101,120,116,47,99, +115,115,34,62,105,111,110,97,108,46,100,116,100,34,62,10,60,104,116,109,108,32, +120,109,108,110,115,61,104,116,116,112,45,101,113,117,105,118,61,34,67,111,110, +116,101,110,116,45,84,121,112,101,100,105,110,103,61,34,48,34,32,99,101,108,108, +115,112,97,99,105,110,103,61,34,48,34,104,116,109,108,59,32,99,104,97,114,115, +101,116,61,117,116,102,45,56,34,32,47,62,10,32,115,116,121,108,101,61,34,100,105 +,115,112,108,97,121,58,110,111,110,101,59,34,62,60,60,108,105,62,60,97,32,104, +114,101,102,61,34,104,116,116,112,58,47,47,119,119,119,46,32,116,121,112,101,61, +39,116,101,120,116,47,106,97,118,97,115,99,114,105,112,116,39,62,208,180,208,181 +,209,143,209,130,208,181,208,187,209,140,208,189,208,190,209,129,209,130,208,184 +,209,129,208,190,208,190,209,130,208,178,208,181,209,130,209,129,209,130,208,178 +,208,184,208,184,208,191,209,128,208,190,208,184,208,183,208,178,208,190,208,180 +,209,129,209,130,208,178,208,176,208,177,208,181,208,183,208,190,208,191,208,176 +,209,129,208,189,208,190,209,129,209,130,208,184,224,164,170,224,165,129,224,164 +,184,224,165,141,224,164,164,224,164,191,224,164,149,224,164,190,224,164,149,224 +,164,190,224,164,130,224,164,151,224,165,141,224,164,176,224,165,135,224,164,184 +,224,164,137,224,164,168,224,165,141,224,164,185,224,165,139,224,164,130,224,164 +,168,224,165,135,224,164,181,224,164,191,224,164,167,224,164,190,224,164,168,224 +,164,184,224,164,173,224,164,190,224,164,171,224,164,191,224,164,149,224,165,141 +,224,164,184,224,164,191,224,164,130,224,164,151,224,164,184,224,165,129,224,164 +,176,224,164,149,224,165,141,224,164,183,224,164,191,224,164,164,224,164,149,224 +,165,137,224,164,170,224,165,128,224,164,176,224,164,190,224,164,135,224,164,159 +,224,164,181,224,164,191,224,164,156,224,165,141,224,164,158,224,164,190,224,164 +,170,224,164,168,224,164,149,224,164,190,224,164,176,224,165,141,224,164,176,224 +,164,181,224,164,190,224,164,136,224,164,184,224,164,149,224,165,141,224,164,176 +,224,164,191,224,164,175,224,164,164,224,164,190 +}; diff --git a/packages/runtime/vendor/brotli/c/common/platform.c b/packages/runtime/vendor/brotli/c/common/platform.c new file mode 100644 index 000000000..1e047ced7 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/common/platform.c @@ -0,0 +1,19 @@ +/* Copyright 2016 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#include "platform.h" + +/* Default brotli_alloc_func */ +void* BrotliDefaultAllocFunc(void* opaque, size_t size) { + BROTLI_UNUSED(opaque); + return malloc(size); +} + +/* Default brotli_free_func */ +void BrotliDefaultFreeFunc(void* opaque, void* address) { + BROTLI_UNUSED(opaque); + free(address); +} diff --git a/packages/runtime/vendor/brotli/c/common/platform.h b/packages/runtime/vendor/brotli/c/common/platform.h new file mode 100644 index 000000000..b59f9b809 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/common/platform.h @@ -0,0 +1,680 @@ +/* Copyright 2016 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Macros for compiler / platform specific features and build options. + + Build options are: + * BROTLI_BUILD_32_BIT disables 64-bit optimizations + * BROTLI_BUILD_64_BIT forces to use 64-bit optimizations + * BROTLI_BUILD_BIG_ENDIAN forces to use big-endian optimizations + * BROTLI_BUILD_ENDIAN_NEUTRAL disables endian-aware optimizations + * BROTLI_BUILD_LITTLE_ENDIAN forces to use little-endian optimizations + * BROTLI_BUILD_NO_RBIT disables "rbit" optimization for ARM CPUs + * BROTLI_BUILD_NO_UNALIGNED_READ_FAST forces off the fast-unaligned-read + optimizations (mainly for testing purposes) + * BROTLI_DEBUG dumps file name and line number when decoder detects stream + or memory error + * BROTLI_ENABLE_LOG enables asserts and dumps various state information + * BROTLI_ENABLE_DUMP overrides default "dump" behaviour +*/ + +#ifndef BROTLI_COMMON_PLATFORM_H_ +#define BROTLI_COMMON_PLATFORM_H_ + +#include /* IWYU pragma: export memcmp, memcpy, memset */ +#include /* IWYU pragma: export exit, free, malloc */ +#include /* should include endian.h for us */ + +#include /* IWYU pragma: export */ +#include /* IWYU pragma: export */ + +#if BROTLI_MSVC_VERSION_CHECK(18, 0, 0) +#include +#endif + +#if defined(BROTLI_ENABLE_LOG) || defined(BROTLI_DEBUG) +#include +#include +#endif + +/* The following macros were borrowed from https://github.com/nemequ/hedley + * with permission of original author - Evan Nemerson */ + +/* >>> >>> >>> hedley macros */ + +/* Define "BROTLI_PREDICT_TRUE" and "BROTLI_PREDICT_FALSE" macros for capable + compilers. + +To apply compiler hint, enclose the branching condition into macros, like this: + + if (BROTLI_PREDICT_TRUE(zero == 0)) { + // main execution path + } else { + // compiler should place this code outside of main execution path + } + +OR: + + if (BROTLI_PREDICT_FALSE(something_rare_or_unexpected_happens)) { + // compiler should place this code outside of main execution path + } + +*/ +#if BROTLI_GNUC_HAS_BUILTIN(__builtin_expect, 3, 0, 0) || \ + BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \ + BROTLI_SUNPRO_VERSION_CHECK(5, 15, 0) || \ + BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \ + BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \ + BROTLI_TI_VERSION_CHECK(7, 3, 0) || \ + BROTLI_TINYC_VERSION_CHECK(0, 9, 27) +#define BROTLI_PREDICT_TRUE(x) (__builtin_expect(!!(x), 1)) +#define BROTLI_PREDICT_FALSE(x) (__builtin_expect(x, 0)) +#else +#define BROTLI_PREDICT_FALSE(x) (x) +#define BROTLI_PREDICT_TRUE(x) (x) +#endif + +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__cplusplus) +#define BROTLI_RESTRICT restrict +#elif BROTLI_GNUC_VERSION_CHECK(3, 1, 0) || \ + BROTLI_MSVC_VERSION_CHECK(14, 0, 0) || \ + BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \ + BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \ + BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \ + BROTLI_PGI_VERSION_CHECK(17, 10, 0) || \ + BROTLI_TI_VERSION_CHECK(8, 0, 0) || \ + BROTLI_IAR_VERSION_CHECK(8, 0, 0) || \ + (BROTLI_SUNPRO_VERSION_CHECK(5, 14, 0) && defined(__cplusplus)) +#define BROTLI_RESTRICT __restrict +#elif BROTLI_SUNPRO_VERSION_CHECK(5, 3, 0) && !defined(__cplusplus) +#define BROTLI_RESTRICT _Restrict +#else +#define BROTLI_RESTRICT +#endif + +#if (defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) || \ + (defined(__cplusplus) && (__cplusplus >= 199711L)) +#define BROTLI_MAYBE_INLINE inline +#elif defined(__GNUC_STDC_INLINE__) || defined(__GNUC_GNU_INLINE__) || \ + BROTLI_ARM_VERSION_CHECK(6, 2, 0) +#define BROTLI_MAYBE_INLINE __inline__ +#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0) || \ + BROTLI_ARM_VERSION_CHECK(4, 1, 0) || BROTLI_TI_VERSION_CHECK(8, 0, 0) +#define BROTLI_MAYBE_INLINE __inline +#else +#define BROTLI_MAYBE_INLINE +#endif + +#if BROTLI_GNUC_HAS_ATTRIBUTE(always_inline, 4, 0, 0) || \ + BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \ + BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \ + BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \ + BROTLI_TI_VERSION_CHECK(8, 0, 0) || \ + (BROTLI_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#define BROTLI_INLINE BROTLI_MAYBE_INLINE __attribute__((__always_inline__)) +#elif BROTLI_MSVC_VERSION_CHECK(12, 0, 0) +#define BROTLI_INLINE BROTLI_MAYBE_INLINE __forceinline +#elif BROTLI_TI_VERSION_CHECK(7, 0, 0) && defined(__cplusplus) +#define BROTLI_INLINE BROTLI_MAYBE_INLINE _Pragma("FUNC_ALWAYS_INLINE;") +#elif BROTLI_IAR_VERSION_CHECK(8, 0, 0) +#define BROTLI_INLINE BROTLI_MAYBE_INLINE _Pragma("inline=forced") +#else +#define BROTLI_INLINE BROTLI_MAYBE_INLINE +#endif + +#if BROTLI_GNUC_HAS_ATTRIBUTE(noinline, 4, 0, 0) || \ + BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \ + BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \ + BROTLI_IBM_VERSION_CHECK(10, 1, 0) || \ + BROTLI_TI_VERSION_CHECK(8, 0, 0) || \ + (BROTLI_TI_VERSION_CHECK(7, 3, 0) && defined(__TI_GNU_ATTRIBUTE_SUPPORT__)) +#define BROTLI_NOINLINE __attribute__((__noinline__)) +#elif BROTLI_MSVC_VERSION_CHECK(13, 10, 0) +#define BROTLI_NOINLINE __declspec(noinline) +#elif BROTLI_PGI_VERSION_CHECK(10, 2, 0) +#define BROTLI_NOINLINE _Pragma("noinline") +#elif BROTLI_TI_VERSION_CHECK(6, 0, 0) && defined(__cplusplus) +#define BROTLI_NOINLINE _Pragma("FUNC_CANNOT_INLINE;") +#elif BROTLI_IAR_VERSION_CHECK(8, 0, 0) +#define BROTLI_NOINLINE _Pragma("inline=never") +#else +#define BROTLI_NOINLINE +#endif + +/* <<< <<< <<< end of hedley macros. */ + +#if BROTLI_GNUC_HAS_ATTRIBUTE(unused, 2, 7, 0) || \ + BROTLI_INTEL_VERSION_CHECK(16, 0, 0) +#define BROTLI_UNUSED_FUNCTION static BROTLI_INLINE __attribute__ ((unused)) +#else +#define BROTLI_UNUSED_FUNCTION static BROTLI_INLINE +#endif + +#if BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0) +#define BROTLI_ALIGNED(N) __attribute__((aligned(N))) +#else +#define BROTLI_ALIGNED(N) +#endif + +#if (defined(__ARM_ARCH) && (__ARM_ARCH == 7)) || \ + (defined(M_ARM) && (M_ARM == 7)) +#define BROTLI_TARGET_ARMV7 +#endif /* ARMv7 */ + +#if (defined(__ARM_ARCH) && (__ARM_ARCH == 8)) || \ + defined(__aarch64__) || defined(__ARM64_ARCH_8__) +#define BROTLI_TARGET_ARMV8_ANY + +#if defined(__ARM_32BIT_STATE) +#define BROTLI_TARGET_ARMV8_32 +#elif defined(__ARM_64BIT_STATE) +#define BROTLI_TARGET_ARMV8_64 +#endif + +#endif /* ARMv8 */ + +#if defined(__ARM_NEON__) || defined(__ARM_NEON) +#define BROTLI_TARGET_NEON +#endif + +#if defined(__i386) || defined(_M_IX86) +#define BROTLI_TARGET_X86 +#endif + +#if defined(__x86_64__) || defined(_M_X64) +#define BROTLI_TARGET_X64 +#endif + +#if defined(__PPC64__) +#define BROTLI_TARGET_POWERPC64 +#endif + +#if defined(__riscv) && defined(__riscv_xlen) && __riscv_xlen == 64 +#define BROTLI_TARGET_RISCV64 +#endif + +#if defined(__loongarch_lp64) +#define BROTLI_TARGET_LOONGARCH64 +#endif + +/* This does not seem to be an indicator of z/Architecture (64-bit); neither + that allows to use unaligned loads. */ +#if defined(__s390x__) +#define BROTLI_TARGET_S390X +#endif + +#if defined(__mips64) +#define BROTLI_TARGET_MIPS64 +#endif + +#if defined(BROTLI_TARGET_X64) || defined(BROTLI_TARGET_ARMV8_64) || \ + defined(BROTLI_TARGET_POWERPC64) || defined(BROTLI_TARGET_RISCV64) || \ + defined(BROTLI_TARGET_LOONGARCH64) || defined(BROTLI_TARGET_MIPS64) +#define BROTLI_TARGET_64_BITS 1 +#else +#define BROTLI_TARGET_64_BITS 0 +#endif + +#if defined(BROTLI_BUILD_64_BIT) +#define BROTLI_64_BITS 1 +#elif defined(BROTLI_BUILD_32_BIT) +#define BROTLI_64_BITS 0 +#else +#define BROTLI_64_BITS BROTLI_TARGET_64_BITS +#endif + +#if (BROTLI_64_BITS) +#define brotli_reg_t uint64_t +#else +#define brotli_reg_t uint32_t +#endif + +#if defined(BROTLI_BUILD_BIG_ENDIAN) +#define BROTLI_BIG_ENDIAN 1 +#elif defined(BROTLI_BUILD_LITTLE_ENDIAN) +#define BROTLI_LITTLE_ENDIAN 1 +#elif defined(BROTLI_BUILD_ENDIAN_NEUTRAL) +/* Just break elif chain. */ +#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) +#define BROTLI_LITTLE_ENDIAN 1 +#elif defined(_WIN32) || defined(BROTLI_TARGET_X64) +/* Win32 & x64 can currently always be assumed to be little endian */ +#define BROTLI_LITTLE_ENDIAN 1 +#elif defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) +#define BROTLI_BIG_ENDIAN 1 +/* Likely target platform is iOS / OSX. */ +#elif defined(BYTE_ORDER) && (BYTE_ORDER == LITTLE_ENDIAN) +#define BROTLI_LITTLE_ENDIAN 1 +#elif defined(BYTE_ORDER) && (BYTE_ORDER == BIG_ENDIAN) +#define BROTLI_BIG_ENDIAN 1 +#endif + +#if !defined(BROTLI_LITTLE_ENDIAN) +#define BROTLI_LITTLE_ENDIAN 0 +#endif + +#if !defined(BROTLI_BIG_ENDIAN) +#define BROTLI_BIG_ENDIAN 0 +#endif + +#if defined(BROTLI_BUILD_NO_UNALIGNED_READ_FAST) +#define BROTLI_UNALIGNED_READ_FAST (!!0) +#elif defined(BROTLI_TARGET_X86) || defined(BROTLI_TARGET_X64) || \ + defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY) || \ + defined(BROTLI_TARGET_RISCV64) || defined(BROTLI_TARGET_LOONGARCH64) +/* These targets are known to generate efficient code for unaligned reads + * (e.g. a single instruction, not multiple 1-byte loads, shifted and or'd + * together). */ +#define BROTLI_UNALIGNED_READ_FAST (!!1) +#else +#define BROTLI_UNALIGNED_READ_FAST (!!0) +#endif + +/* Portable unaligned memory access: read / write values via memcpy. */ +#if !defined(BROTLI_USE_PACKED_FOR_UNALIGNED) +#if defined(__mips__) && (!defined(__mips_isa_rev) || __mips_isa_rev < 6) +#define BROTLI_USE_PACKED_FOR_UNALIGNED 1 +#else +#define BROTLI_USE_PACKED_FOR_UNALIGNED 0 +#endif +#endif /* defined(BROTLI_USE_PACKED_FOR_UNALIGNED) */ + +#if BROTLI_USE_PACKED_FOR_UNALIGNED + +typedef union BrotliPackedValue { + uint16_t u16; + uint32_t u32; + uint64_t u64; + size_t szt; +} __attribute__ ((packed)) BrotliPackedValue; + +static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) { + const BrotliPackedValue* address = (const BrotliPackedValue*)p; + return address->u16; +} +static BROTLI_INLINE uint32_t BrotliUnalignedRead32(const void* p) { + const BrotliPackedValue* address = (const BrotliPackedValue*)p; + return address->u32; +} +static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) { + const BrotliPackedValue* address = (const BrotliPackedValue*)p; + return address->u64; +} +static BROTLI_INLINE size_t BrotliUnalignedReadSizeT(const void* p) { + const BrotliPackedValue* address = (const BrotliPackedValue*)p; + return address->szt; +} +static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) { + BrotliPackedValue* address = (BrotliPackedValue*)p; + address->u64 = v; +} + +#else /* not BROTLI_USE_PACKED_FOR_UNALIGNED */ + +static BROTLI_INLINE uint16_t BrotliUnalignedRead16(const void* p) { + uint16_t t; + memcpy(&t, p, sizeof t); + return t; +} +static BROTLI_INLINE uint32_t BrotliUnalignedRead32(const void* p) { + uint32_t t; + memcpy(&t, p, sizeof t); + return t; +} +static BROTLI_INLINE uint64_t BrotliUnalignedRead64(const void* p) { + uint64_t t; + memcpy(&t, p, sizeof t); + return t; +} +static BROTLI_INLINE size_t BrotliUnalignedReadSizeT(const void* p) { + size_t t; + memcpy(&t, p, sizeof t); + return t; +} +static BROTLI_INLINE void BrotliUnalignedWrite64(void* p, uint64_t v) { + memcpy(p, &v, sizeof v); +} + +#endif /* BROTLI_USE_PACKED_FOR_UNALIGNED */ + +#if BROTLI_GNUC_HAS_BUILTIN(__builtin_bswap16, 4, 3, 0) +#define BROTLI_BSWAP16(V) ((uint16_t)__builtin_bswap16(V)) +#else +#define BROTLI_BSWAP16(V) ((uint16_t)( \ + (((V) & 0xFFU) << 8) | \ + (((V) >> 8) & 0xFFU))) +#endif + +#if BROTLI_GNUC_HAS_BUILTIN(__builtin_bswap32, 4, 3, 0) +#define BROTLI_BSWAP32(V) ((uint32_t)__builtin_bswap32(V)) +#else +#define BROTLI_BSWAP32(V) ((uint32_t)( \ + (((V) & 0xFFU) << 24) | (((V) & 0xFF00U) << 8) | \ + (((V) >> 8) & 0xFF00U) | (((V) >> 24) & 0xFFU))) +#endif + +#if BROTLI_GNUC_HAS_BUILTIN(__builtin_bswap64, 4, 3, 0) +#define BROTLI_BSWAP64(V) ((uint64_t)__builtin_bswap64(V)) +#else +#define BROTLI_BSWAP64(V) ((uint64_t)( \ + (((V) & 0xFFU) << 56) | (((V) & 0xFF00U) << 40) | \ + (((V) & 0xFF0000U) << 24) | (((V) & 0xFF000000U) << 8) | \ + (((V) >> 8) & 0xFF000000U) | (((V) >> 24) & 0xFF0000U) | \ + (((V) >> 40) & 0xFF00U) | (((V) >> 56) & 0xFFU))) +#endif + +#if BROTLI_LITTLE_ENDIAN +/* Straight endianness. Just read / write values. */ +#define BROTLI_UNALIGNED_LOAD16LE BrotliUnalignedRead16 +#define BROTLI_UNALIGNED_LOAD32LE BrotliUnalignedRead32 +#define BROTLI_UNALIGNED_LOAD64LE BrotliUnalignedRead64 +#define BROTLI_UNALIGNED_STORE64LE BrotliUnalignedWrite64 +#elif BROTLI_BIG_ENDIAN /* BROTLI_LITTLE_ENDIAN */ +static BROTLI_INLINE uint16_t BROTLI_UNALIGNED_LOAD16LE(const void* p) { + uint16_t value = BrotliUnalignedRead16(p); + return BROTLI_BSWAP16(value); +} +static BROTLI_INLINE uint32_t BROTLI_UNALIGNED_LOAD32LE(const void* p) { + uint32_t value = BrotliUnalignedRead32(p); + return BROTLI_BSWAP32(value); +} +static BROTLI_INLINE uint64_t BROTLI_UNALIGNED_LOAD64LE(const void* p) { + uint64_t value = BrotliUnalignedRead64(p); + return BROTLI_BSWAP64(value); +} +static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void* p, uint64_t v) { + uint64_t value = BROTLI_BSWAP64(v); + BrotliUnalignedWrite64(p, value); +} +#else /* BROTLI_LITTLE_ENDIAN */ +/* Read / store values byte-wise; hopefully compiler will understand. */ +static BROTLI_INLINE uint16_t BROTLI_UNALIGNED_LOAD16LE(const void* p) { + const uint8_t* in = (const uint8_t*)p; + return (uint16_t)(in[0] | (in[1] << 8)); +} +static BROTLI_INLINE uint32_t BROTLI_UNALIGNED_LOAD32LE(const void* p) { + const uint8_t* in = (const uint8_t*)p; + uint32_t value = (uint32_t)(in[0]); + value |= (uint32_t)(in[1]) << 8; + value |= (uint32_t)(in[2]) << 16; + value |= (uint32_t)(in[3]) << 24; + return value; +} +static BROTLI_INLINE uint64_t BROTLI_UNALIGNED_LOAD64LE(const void* p) { + const uint8_t* in = (const uint8_t*)p; + uint64_t value = (uint64_t)(in[0]); + value |= (uint64_t)(in[1]) << 8; + value |= (uint64_t)(in[2]) << 16; + value |= (uint64_t)(in[3]) << 24; + value |= (uint64_t)(in[4]) << 32; + value |= (uint64_t)(in[5]) << 40; + value |= (uint64_t)(in[6]) << 48; + value |= (uint64_t)(in[7]) << 56; + return value; +} +static BROTLI_INLINE void BROTLI_UNALIGNED_STORE64LE(void* p, uint64_t v) { + uint8_t* out = (uint8_t*)p; + out[0] = (uint8_t)v; + out[1] = (uint8_t)(v >> 8); + out[2] = (uint8_t)(v >> 16); + out[3] = (uint8_t)(v >> 24); + out[4] = (uint8_t)(v >> 32); + out[5] = (uint8_t)(v >> 40); + out[6] = (uint8_t)(v >> 48); + out[7] = (uint8_t)(v >> 56); +} +#endif /* BROTLI_LITTLE_ENDIAN */ + +static BROTLI_INLINE void* BROTLI_UNALIGNED_LOAD_PTR(const void* p) { + void* v; + memcpy(&v, p, sizeof(void*)); + return v; +} + +static BROTLI_INLINE void BROTLI_UNALIGNED_STORE_PTR(void* p, const void* v) { + memcpy(p, &v, sizeof(void*)); +} + +/* BROTLI_IS_CONSTANT macros returns true for compile-time constants. */ +#if BROTLI_GNUC_HAS_BUILTIN(__builtin_constant_p, 3, 0, 1) || \ + BROTLI_INTEL_VERSION_CHECK(16, 0, 0) +#define BROTLI_IS_CONSTANT(x) (!!__builtin_constant_p(x)) +#else +#define BROTLI_IS_CONSTANT(x) (!!0) +#endif + +#if defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY) +#define BROTLI_HAS_UBFX (!!1) +#else +#define BROTLI_HAS_UBFX (!!0) +#endif + +#if defined(BROTLI_ENABLE_LOG) +#define BROTLI_LOG(x) printf x +#else +#define BROTLI_LOG(x) +#endif + +#if defined(BROTLI_DEBUG) || defined(BROTLI_ENABLE_LOG) +#define BROTLI_ENABLE_DUMP_DEFAULT 1 +#define BROTLI_DCHECK(x) assert(x) +#else +#define BROTLI_ENABLE_DUMP_DEFAULT 0 +#define BROTLI_DCHECK(x) +#endif + +#if !defined(BROTLI_ENABLE_DUMP) +#define BROTLI_ENABLE_DUMP BROTLI_ENABLE_DUMP_DEFAULT +#endif + +#if BROTLI_ENABLE_DUMP +static BROTLI_INLINE void BrotliDump(const char* f, int l, const char* fn) { + fprintf(stderr, "%s:%d (%s)\n", f, l, fn); + fflush(stderr); +} +#define BROTLI_DUMP() BrotliDump(__FILE__, __LINE__, __FUNCTION__) +#else +#define BROTLI_DUMP() (void)(0) +#endif + +/* BrotliRBit assumes brotli_reg_t fits native CPU register type. */ +#if (BROTLI_64_BITS == BROTLI_TARGET_64_BITS) +/* TODO(eustas): add appropriate icc/sunpro/arm/ibm/ti checks. */ +#if (BROTLI_GNUC_VERSION_CHECK(3, 0, 0) || defined(__llvm__)) && \ + !defined(BROTLI_BUILD_NO_RBIT) +#if defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_ANY) +/* TODO(eustas): detect ARMv6T2 and enable this code for it. */ +static BROTLI_INLINE brotli_reg_t BrotliRBit(brotli_reg_t input) { + brotli_reg_t output; + __asm__("rbit %0, %1\n" : "=r"(output) : "r"(input)); + return output; +} +#define BROTLI_RBIT(x) BrotliRBit(x) +#endif /* armv7 / armv8 */ +#endif /* gcc || clang */ +#endif /* brotli_reg_t is native */ +#if !defined(BROTLI_RBIT) +static BROTLI_INLINE void BrotliRBit(void) { /* Should break build if used. */ } +#endif /* BROTLI_RBIT */ + +#define BROTLI_REPEAT_4(X) {X; X; X; X;} +#define BROTLI_REPEAT_5(X) {X; X; X; X; X;} +#define BROTLI_REPEAT_6(X) {X; X; X; X; X; X;} + +#define BROTLI_UNUSED(X) (void)(X) + +#define BROTLI_MIN_MAX(T) \ + static BROTLI_INLINE T brotli_min_ ## T (T a, T b) { return a < b ? a : b; } \ + static BROTLI_INLINE T brotli_max_ ## T (T a, T b) { return a > b ? a : b; } +BROTLI_MIN_MAX(double) BROTLI_MIN_MAX(float) BROTLI_MIN_MAX(int) +BROTLI_MIN_MAX(size_t) BROTLI_MIN_MAX(uint32_t) BROTLI_MIN_MAX(uint8_t) +#undef BROTLI_MIN_MAX +#define BROTLI_MIN(T, A, B) (brotli_min_ ## T((A), (B))) +#define BROTLI_MAX(T, A, B) (brotli_max_ ## T((A), (B))) + +#define BROTLI_SWAP(T, A, I, J) { \ + T __brotli_swap_tmp = (A)[(I)]; \ + (A)[(I)] = (A)[(J)]; \ + (A)[(J)] = __brotli_swap_tmp; \ +} + +#if BROTLI_64_BITS +#if BROTLI_GNUC_HAS_BUILTIN(__builtin_ctzll, 3, 4, 0) || \ + BROTLI_INTEL_VERSION_CHECK(16, 0, 0) +#define BROTLI_TZCNT64 __builtin_ctzll +#elif BROTLI_MSVC_VERSION_CHECK(18, 0, 0) +#if defined(BROTLI_TARGET_X64) && !defined(_M_ARM64EC) +#define BROTLI_TZCNT64 _tzcnt_u64 +#else /* BROTLI_TARGET_X64 */ +static BROTLI_INLINE uint32_t BrotliBsf64Msvc(uint64_t x) { + uint32_t lsb; + _BitScanForward64(&lsb, x); + return lsb; +} +#define BROTLI_TZCNT64 BrotliBsf64Msvc +#endif /* BROTLI_TARGET_X64 */ +#endif /* __builtin_ctzll */ +#endif /* BROTLI_64_BITS */ + +#if BROTLI_GNUC_HAS_BUILTIN(__builtin_clz, 3, 4, 0) || \ + BROTLI_INTEL_VERSION_CHECK(16, 0, 0) +#define BROTLI_BSR32(x) (31u ^ (uint32_t)__builtin_clz(x)) +#elif BROTLI_MSVC_VERSION_CHECK(18, 0, 0) +static BROTLI_INLINE uint32_t BrotliBsr32Msvc(uint32_t x) { + unsigned long msb; + _BitScanReverse(&msb, x); + return (uint32_t)msb; +} +#define BROTLI_BSR32 BrotliBsr32Msvc +#endif /* __builtin_clz */ + +/* Default brotli_alloc_func */ +BROTLI_COMMON_API void* BrotliDefaultAllocFunc(void* opaque, size_t size); + +/* Default brotli_free_func */ +BROTLI_COMMON_API void BrotliDefaultFreeFunc(void* opaque, void* address); + +/* Circular logical rotates. */ +static BROTLI_INLINE uint16_t BrotliRotateRight16(uint16_t const value, + size_t count) { + count &= 0x0F; /* for fickle pattern recognition */ + return (value >> count) | (uint16_t)(value << ((0U - count) & 0x0F)); +} +static BROTLI_INLINE uint32_t BrotliRotateRight32(uint32_t const value, + size_t count) { + count &= 0x1F; /* for fickle pattern recognition */ + return (value >> count) | (uint32_t)(value << ((0U - count) & 0x1F)); +} +static BROTLI_INLINE uint64_t BrotliRotateRight64(uint64_t const value, + size_t count) { + count &= 0x3F; /* for fickle pattern recognition */ + return (value >> count) | (uint64_t)(value << ((0U - count) & 0x3F)); +} + +BROTLI_UNUSED_FUNCTION void BrotliSuppressUnusedFunctions(void) { + BROTLI_UNUSED(&BrotliSuppressUnusedFunctions); + BROTLI_UNUSED(&BrotliUnalignedRead16); + BROTLI_UNUSED(&BrotliUnalignedRead32); + BROTLI_UNUSED(&BrotliUnalignedRead64); + BROTLI_UNUSED(&BrotliUnalignedReadSizeT); + BROTLI_UNUSED(&BrotliUnalignedWrite64); + BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD16LE); + BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD32LE); + BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD64LE); + BROTLI_UNUSED(&BROTLI_UNALIGNED_STORE64LE); + BROTLI_UNUSED(&BROTLI_UNALIGNED_LOAD_PTR); + BROTLI_UNUSED(&BROTLI_UNALIGNED_STORE_PTR); + BROTLI_UNUSED(&BrotliRBit); + BROTLI_UNUSED(&brotli_min_double); + BROTLI_UNUSED(&brotli_max_double); + BROTLI_UNUSED(&brotli_min_float); + BROTLI_UNUSED(&brotli_max_float); + BROTLI_UNUSED(&brotli_min_int); + BROTLI_UNUSED(&brotli_max_int); + BROTLI_UNUSED(&brotli_min_size_t); + BROTLI_UNUSED(&brotli_max_size_t); + BROTLI_UNUSED(&brotli_min_uint32_t); + BROTLI_UNUSED(&brotli_max_uint32_t); + BROTLI_UNUSED(&brotli_min_uint8_t); + BROTLI_UNUSED(&brotli_max_uint8_t); + BROTLI_UNUSED(&BrotliDefaultAllocFunc); + BROTLI_UNUSED(&BrotliDefaultFreeFunc); + BROTLI_UNUSED(&BrotliRotateRight16); + BROTLI_UNUSED(&BrotliRotateRight32); + BROTLI_UNUSED(&BrotliRotateRight64); +#if BROTLI_ENABLE_DUMP + BROTLI_UNUSED(&BrotliDump); +#endif + +#if defined(_MSC_VER) && (defined(_M_X64) || defined(_M_I86)) && \ + !defined(_M_ARM64EC) +/* _mm_prefetch() is not defined outside of x86/x64 */ +/* https://msdn.microsoft.com/fr-fr/library/84szxsww(v=vs.90).aspx */ +#include +#define PREFETCH_L1(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T0) +#define PREFETCH_L2(ptr) _mm_prefetch((const char*)(ptr), _MM_HINT_T1) +#elif BROTLI_GNUC_HAS_BUILTIN(__builtin_prefetch, 3, 1, 0) +#define PREFETCH_L1(ptr) \ + __builtin_prefetch((ptr), 0 /* rw==read */, 3 /* locality */) +#define PREFETCH_L2(ptr) \ + __builtin_prefetch((ptr), 0 /* rw==read */, 2 /* locality */) +#elif defined(__aarch64__) +#define PREFETCH_L1(ptr) \ + do { \ + __asm__ __volatile__("prfm pldl1keep, %0" ::"Q"(*(ptr))); \ + } while (0) +#define PREFETCH_L2(ptr) \ + do { \ + __asm__ __volatile__("prfm pldl2keep, %0" ::"Q"(*(ptr))); \ + } while (0) +#else +#define PREFETCH_L1(ptr) \ + do { \ + (void)(ptr); \ + } while (0) /* disabled */ +#define PREFETCH_L2(ptr) \ + do { \ + (void)(ptr); \ + } while (0) /* disabled */ +#endif + +/* The SIMD matchers are only faster at certain quality levels. */ +#if defined(_M_X64) && defined(BROTLI_TZCNT64) +#define BROTLI_MAX_SIMD_QUALITY 7 +#elif defined(BROTLI_TZCNT64) +#define BROTLI_MAX_SIMD_QUALITY 6 +#endif +} + +#if defined(_MSC_VER) +#define BROTLI_CRASH() __debugbreak(), (void)abort() +#elif BROTLI_GNUC_HAS_BUILTIN(__builtin_trap, 3, 0, 0) +#define BROTLI_CRASH() (void)__builtin_trap() +#else +#define BROTLI_CRASH() (void)abort() +#endif + +/* Make BROTLI_TEST=0 act same as undefined. */ +#if defined(BROTLI_TEST) && ((1-BROTLI_TEST-1) == 0) +#undef BROTLI_TEST +#endif + +#if BROTLI_GNUC_HAS_ATTRIBUTE(model, 3, 0, 3) +#define BROTLI_MODEL(M) __attribute__((model(M))) +#else +#define BROTLI_MODEL(M) /* M */ +#endif + +#if BROTLI_GNUC_HAS_ATTRIBUTE(cold, 4, 3, 0) +#define BROTLI_COLD __attribute__((cold)) +#else +#define BROTLI_COLD /* cold */ +#endif + +#endif /* BROTLI_COMMON_PLATFORM_H_ */ diff --git a/packages/runtime/vendor/brotli/c/common/shared_dictionary.c b/packages/runtime/vendor/brotli/c/common/shared_dictionary.c new file mode 100644 index 000000000..cef4e20fc --- /dev/null +++ b/packages/runtime/vendor/brotli/c/common/shared_dictionary.c @@ -0,0 +1,517 @@ +/* Copyright 2017 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Shared Dictionary definition and utilities. */ + +#include + +#include "dictionary.h" +#include "platform.h" +#include "shared_dictionary_internal.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#if defined(BROTLI_EXPERIMENTAL) + +#define BROTLI_NUM_ENCODED_LENGTHS (SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH \ + - SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH + 1) + +/* Max allowed by spec */ +#define BROTLI_MAX_SIZE_BITS 15u + +/* Returns BROTLI_TRUE on success, BROTLI_FALSE on failure. */ +static BROTLI_BOOL ReadBool(const uint8_t* encoded, size_t size, size_t* pos, + BROTLI_BOOL* result) { + uint8_t value; + size_t position = *pos; + if (position >= size) return BROTLI_FALSE; /* past file end */ + value = encoded[position++]; + if (value > 1) return BROTLI_FALSE; /* invalid bool */ + *result = TO_BROTLI_BOOL(value); + *pos = position; + return BROTLI_TRUE; /* success */ +} + +/* Returns BROTLI_TRUE on success, BROTLI_FALSE on failure. */ +static BROTLI_BOOL ReadUint8(const uint8_t* encoded, size_t size, size_t* pos, + uint8_t* result) { + size_t position = *pos; + if (position + sizeof(uint8_t) > size) return BROTLI_FALSE; + *result = encoded[position++]; + *pos = position; + return BROTLI_TRUE; +} + +/* Returns BROTLI_TRUE on success, BROTLI_FALSE on failure. */ +static BROTLI_BOOL ReadUint16(const uint8_t* encoded, size_t size, size_t* pos, + uint16_t* result) { + size_t position = *pos; + if (position + sizeof(uint16_t) > size) return BROTLI_FALSE; + *result = BROTLI_UNALIGNED_LOAD16LE(&encoded[position]); + position += 2; + *pos = position; + return BROTLI_TRUE; +} + +/* Reads a varint into a uint32_t, and returns error if it's too large */ +/* Returns BROTLI_TRUE on success, BROTLI_FALSE on failure. */ +static BROTLI_BOOL ReadVarint32(const uint8_t* encoded, size_t size, + size_t* pos, uint32_t* result) { + int num = 0; + uint8_t byte; + *result = 0; + for (;;) { + if (*pos >= size) return BROTLI_FALSE; + byte = encoded[(*pos)++]; + if (num == 4 && byte > 15) return BROTLI_FALSE; + *result |= (uint32_t)(byte & 127) << (num * 7); + if (byte < 128) return BROTLI_TRUE; + num++; + } +} + +/* Returns the total length of word list. */ +static size_t BrotliSizeBitsToOffsets(const uint8_t* size_bits_by_length, + uint32_t* offsets_by_length) { + uint32_t pos = 0; + uint32_t i; + for (i = 0; i <= SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH; i++) { + offsets_by_length[i] = pos; + if (size_bits_by_length[i] != 0) { + pos += i << size_bits_by_length[i]; + } + } + return pos; +} + +static BROTLI_BOOL ParseWordList(size_t size, const uint8_t* encoded, + size_t* pos, BrotliDictionary* out) { + size_t offset; + size_t i; + size_t position = *pos; + if (position + BROTLI_NUM_ENCODED_LENGTHS > size) { + return BROTLI_FALSE; + } + + memset(out->size_bits_by_length, 0, SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH); + memcpy(out->size_bits_by_length + SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH, + &encoded[position], BROTLI_NUM_ENCODED_LENGTHS); + for (i = SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH; + i <= SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH; i++) { + if (out->size_bits_by_length[i] > BROTLI_MAX_SIZE_BITS) { + return BROTLI_FALSE; + } + } + position += BROTLI_NUM_ENCODED_LENGTHS; + offset = BrotliSizeBitsToOffsets( + out->size_bits_by_length, out->offsets_by_length); + + out->data = &encoded[position]; + out->data_size = offset; + position += offset; + if (position > size) return BROTLI_FALSE; + *pos = position; + return BROTLI_TRUE; +} + +/* Computes the cutOffTransforms of a BrotliTransforms which already has the + transforms data correctly filled in. */ +static void ComputeCutoffTransforms(BrotliTransforms* transforms) { + uint32_t i; + for (i = 0; i < BROTLI_TRANSFORMS_MAX_CUT_OFF + 1; i++) { + transforms->cutOffTransforms[i] = -1; + } + for (i = 0; i < transforms->num_transforms; i++) { + const uint8_t* prefix = BROTLI_TRANSFORM_PREFIX(transforms, i); + uint8_t type = BROTLI_TRANSFORM_TYPE(transforms, i); + const uint8_t* suffix = BROTLI_TRANSFORM_SUFFIX(transforms, i); + if (type <= BROTLI_TRANSFORM_OMIT_LAST_9 && *prefix == 0 && *suffix == 0 && + transforms->cutOffTransforms[type] == -1) { + transforms->cutOffTransforms[type] = (int16_t)i; + } + } +} + +static BROTLI_BOOL ParsePrefixSuffixTable(size_t size, const uint8_t* encoded, + size_t* pos, BrotliTransforms* out, uint16_t* out_table, + size_t* out_table_size) { + size_t position = *pos; + size_t offset = 0; + size_t stringlet_count = 0; /* NUM_PREFIX_SUFFIX */ + size_t data_length = 0; + + /* PREFIX_SUFFIX_LENGTH */ + if (!ReadUint16(encoded, size, &position, &out->prefix_suffix_size)) { + return BROTLI_FALSE; + } + data_length = out->prefix_suffix_size; + + /* Must at least have space for null terminator. */ + if (data_length < 1) return BROTLI_FALSE; + out->prefix_suffix = &encoded[position]; + if (position + data_length >= size) return BROTLI_FALSE; + while (BROTLI_TRUE) { + /* STRING_LENGTH */ + size_t stringlet_len = encoded[position + offset]; + out_table[stringlet_count] = (uint16_t)offset; + stringlet_count++; + offset++; + if (stringlet_len == 0) { + if (offset == data_length) { + break; + } else { + return BROTLI_FALSE; + } + } + if (stringlet_count > 255) return BROTLI_FALSE; + offset += stringlet_len; + if (offset >= data_length) return BROTLI_FALSE; + } + + position += data_length; + *pos = position; + *out_table_size = (uint16_t)stringlet_count; + return BROTLI_TRUE; +} + +static BROTLI_BOOL ParseTransformsList(size_t size, const uint8_t* encoded, + size_t* pos, BrotliTransforms* out, uint16_t* prefix_suffix_table, + size_t* prefix_suffix_count) { + uint32_t i; + BROTLI_BOOL has_params = BROTLI_FALSE; + BROTLI_BOOL prefix_suffix_ok = BROTLI_FALSE; + size_t position = *pos; + size_t stringlet_cnt = 0; + if (position >= size) return BROTLI_FALSE; + + prefix_suffix_ok = ParsePrefixSuffixTable( + size, encoded, &position, out, prefix_suffix_table, &stringlet_cnt); + if (!prefix_suffix_ok) return BROTLI_FALSE; + out->prefix_suffix_map = prefix_suffix_table; + *prefix_suffix_count = stringlet_cnt; + + out->num_transforms = encoded[position++]; + out->transforms = &encoded[position]; + position += (size_t)out->num_transforms * 3; + if (position > size) return BROTLI_FALSE; + /* Check for errors and read extra parameters. */ + for (i = 0; i < out->num_transforms; i++) { + uint8_t prefix_id = BROTLI_TRANSFORM_PREFIX_ID(out, i); + uint8_t type = BROTLI_TRANSFORM_TYPE(out, i); + uint8_t suffix_id = BROTLI_TRANSFORM_SUFFIX_ID(out, i); + if (prefix_id >= stringlet_cnt) return BROTLI_FALSE; + if (type >= BROTLI_NUM_TRANSFORM_TYPES) return BROTLI_FALSE; + if (suffix_id >= stringlet_cnt) return BROTLI_FALSE; + if (type == BROTLI_TRANSFORM_SHIFT_FIRST || + type == BROTLI_TRANSFORM_SHIFT_ALL) { + has_params = BROTLI_TRUE; + } + } + if (has_params) { + out->params = &encoded[position]; + position += (size_t)out->num_transforms * 2; + if (position > size) return BROTLI_FALSE; + for (i = 0; i < out->num_transforms; i++) { + uint8_t type = BROTLI_TRANSFORM_TYPE(out, i); + if (type != BROTLI_TRANSFORM_SHIFT_FIRST && + type != BROTLI_TRANSFORM_SHIFT_ALL) { + if (out->params[i * 2] != 0 || out->params[i * 2 + 1] != 0) { + return BROTLI_FALSE; + } + } + } + } else { + out->params = NULL; + } + ComputeCutoffTransforms(out); + *pos = position; + return BROTLI_TRUE; +} + +static BROTLI_BOOL DryParseDictionary(const uint8_t* encoded, + size_t size, uint32_t* num_prefix, BROTLI_BOOL* is_custom_static_dict) { + size_t pos = 0; + uint32_t chunk_size = 0; + uint8_t num_word_lists; + uint8_t num_transform_lists; + *is_custom_static_dict = BROTLI_FALSE; + *num_prefix = 0; + + /* Skip magic header bytes. */ + pos += 2; + + /* LZ77_DICTIONARY_LENGTH */ + if (!ReadVarint32(encoded, size, &pos, &chunk_size)) return BROTLI_FALSE; + if (chunk_size != 0) { + /* This limitation is not specified but the 32-bit Brotli decoder for now */ + if (chunk_size > 1073741823) return BROTLI_FALSE; + *num_prefix = 1; + if (pos + chunk_size > size) return BROTLI_FALSE; + pos += chunk_size; + } + + if (!ReadUint8(encoded, size, &pos, &num_word_lists)) { + return BROTLI_FALSE; + } + if (!ReadUint8(encoded, size, &pos, &num_transform_lists)) { + return BROTLI_FALSE; + } + + if (num_word_lists > 0 || num_transform_lists > 0) { + *is_custom_static_dict = BROTLI_TRUE; + } + + return BROTLI_TRUE; +} + +static BROTLI_BOOL ParseDictionary(const uint8_t* encoded, size_t size, + BrotliSharedDictionary* dict) { + uint32_t i; + size_t pos = 0; + uint32_t chunk_size = 0; + size_t total_prefix_suffix_count = 0; + size_t transform_list_start[SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS]; + uint16_t temporary_prefix_suffix_table[256]; + + /* Skip magic header bytes. */ + pos += 2; + + /* LZ77_DICTIONARY_LENGTH */ + if (!ReadVarint32(encoded, size, &pos, &chunk_size)) return BROTLI_FALSE; + if (chunk_size != 0) { + if (pos + chunk_size > size) return BROTLI_FALSE; + dict->prefix_size[dict->num_prefix] = chunk_size; + dict->prefix[dict->num_prefix] = &encoded[pos]; + dict->num_prefix++; + /* LZ77_DICTIONARY_LENGTH bytes. */ + pos += chunk_size; + } + + /* NUM_WORD_LISTS */ + if (!ReadUint8(encoded, size, &pos, &dict->num_word_lists)) { + return BROTLI_FALSE; + } + if (dict->num_word_lists > SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS) { + return BROTLI_FALSE; + } + + if (dict->num_word_lists != 0) { + dict->words_instances = (BrotliDictionary*)dict->alloc_func( + dict->memory_manager_opaque, + dict->num_word_lists * sizeof(*dict->words_instances)); + if (!dict->words_instances) return BROTLI_FALSE; /* OOM */ + } + for (i = 0; i < dict->num_word_lists; i++) { + if (!ParseWordList(size, encoded, &pos, &dict->words_instances[i])) { + return BROTLI_FALSE; + } + } + + /* NUM_TRANSFORM_LISTS */ + if (!ReadUint8(encoded, size, &pos, &dict->num_transform_lists)) { + return BROTLI_FALSE; + } + if (dict->num_transform_lists > SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS) { + return BROTLI_FALSE; + } + + if (dict->num_transform_lists != 0) { + dict->transforms_instances = (BrotliTransforms*)dict->alloc_func( + dict->memory_manager_opaque, + dict->num_transform_lists * sizeof(*dict->transforms_instances)); + if (!dict->transforms_instances) return BROTLI_FALSE; /* OOM */ + } + for (i = 0; i < dict->num_transform_lists; i++) { + BROTLI_BOOL ok = BROTLI_FALSE; + size_t prefix_suffix_count = 0; + transform_list_start[i] = pos; + dict->transforms_instances[i].prefix_suffix_map = + temporary_prefix_suffix_table; + ok = ParseTransformsList( + size, encoded, &pos, &dict->transforms_instances[i], + temporary_prefix_suffix_table, &prefix_suffix_count); + if (!ok) return BROTLI_FALSE; + total_prefix_suffix_count += prefix_suffix_count; + } + if (total_prefix_suffix_count != 0) { + dict->prefix_suffix_maps = (uint16_t*)dict->alloc_func( + dict->memory_manager_opaque, + total_prefix_suffix_count * sizeof(*dict->prefix_suffix_maps)); + if (!dict->prefix_suffix_maps) return BROTLI_FALSE; /* OOM */ + } + total_prefix_suffix_count = 0; + for (i = 0; i < dict->num_transform_lists; i++) { + size_t prefix_suffix_count = 0; + size_t position = transform_list_start[i]; + uint16_t* prefix_suffix_map = + &dict->prefix_suffix_maps[total_prefix_suffix_count]; + BROTLI_BOOL ok = ParsePrefixSuffixTable( + size, encoded, &position, &dict->transforms_instances[i], + prefix_suffix_map, &prefix_suffix_count); + if (!ok) return BROTLI_FALSE; + dict->transforms_instances[i].prefix_suffix_map = prefix_suffix_map; + total_prefix_suffix_count += prefix_suffix_count; + } + + if (dict->num_word_lists != 0 || dict->num_transform_lists != 0) { + if (!ReadUint8(encoded, size, &pos, &dict->num_dictionaries)) { + return BROTLI_FALSE; + } + if (dict->num_dictionaries == 0 || + dict->num_dictionaries > SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS) { + return BROTLI_FALSE; + } + for (i = 0; i < dict->num_dictionaries; i++) { + uint8_t words_index; + uint8_t transforms_index; + if (!ReadUint8(encoded, size, &pos, &words_index)) { + return BROTLI_FALSE; + } + if (words_index > dict->num_word_lists) return BROTLI_FALSE; + if (!ReadUint8(encoded, size, &pos, &transforms_index)) { + return BROTLI_FALSE; + } + if (transforms_index > dict->num_transform_lists) return BROTLI_FALSE; + dict->words[i] = words_index == dict->num_word_lists ? + BrotliGetDictionary() : &dict->words_instances[words_index]; + dict->transforms[i] = transforms_index == dict->num_transform_lists ? + BrotliGetTransforms(): &dict->transforms_instances[transforms_index]; + } + /* CONTEXT_ENABLED */ + if (!ReadBool(encoded, size, &pos, &dict->context_based)) { + return BROTLI_FALSE; + } + + /* CONTEXT_MAP */ + if (dict->context_based) { + for (i = 0; i < SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS; i++) { + if (!ReadUint8(encoded, size, &pos, &dict->context_map[i])) { + return BROTLI_FALSE; + } + if (dict->context_map[i] >= dict->num_dictionaries) { + return BROTLI_FALSE; + } + } + } + } else { + dict->context_based = BROTLI_FALSE; + dict->num_dictionaries = 1; + dict->words[0] = BrotliGetDictionary(); + dict->transforms[0] = BrotliGetTransforms(); + } + + return BROTLI_TRUE; +} + +/* Decodes shared dictionary and verifies correctness. + Returns BROTLI_TRUE if dictionary is valid, BROTLI_FALSE otherwise. + The BrotliSharedDictionary must already have been initialized. If the + BrotliSharedDictionary already contains data, compound dictionaries + will be appended, but an error will be returned if it already has + custom words or transforms. + TODO(lode): link to RFC for shared brotli once published. */ +static BROTLI_BOOL DecodeSharedDictionary( + const uint8_t* encoded, size_t size, BrotliSharedDictionary* dict) { + uint32_t num_prefix = 0; + BROTLI_BOOL is_custom_static_dict = BROTLI_FALSE; + BROTLI_BOOL has_custom_static_dict = + dict->num_word_lists > 0 || dict->num_transform_lists > 0; + + /* Check magic header bytes. */ + if (size < 2) return BROTLI_FALSE; + if (encoded[0] != 0x91 || encoded[1] != 0) return BROTLI_FALSE; + + if (!DryParseDictionary(encoded, size, &num_prefix, &is_custom_static_dict)) { + return BROTLI_FALSE; + } + + if (num_prefix + dict->num_prefix > SHARED_BROTLI_MAX_COMPOUND_DICTS) { + return BROTLI_FALSE; + } + + /* Cannot combine different static dictionaries, only prefix dictionaries */ + if (has_custom_static_dict && is_custom_static_dict) return BROTLI_FALSE; + + return ParseDictionary(encoded, size, dict); +} + +#endif /* BROTLI_EXPERIMENTAL */ + +void BrotliSharedDictionaryDestroyInstance( + BrotliSharedDictionary* dict) { + if (!dict) { + return; + } else { + brotli_free_func free_func = dict->free_func; + void* opaque = dict->memory_manager_opaque; + /* Cleanup. */ + free_func(opaque, dict->words_instances); + free_func(opaque, dict->transforms_instances); + free_func(opaque, dict->prefix_suffix_maps); + /* Self-destruction. */ + free_func(opaque, dict); + } +} + +BROTLI_BOOL BrotliSharedDictionaryAttach( + BrotliSharedDictionary* dict, BrotliSharedDictionaryType type, + size_t data_size, const uint8_t data[BROTLI_ARRAY_PARAM(data_size)]) { + if (!dict) { + return BROTLI_FALSE; + } +#if defined(BROTLI_EXPERIMENTAL) + if (type == BROTLI_SHARED_DICTIONARY_SERIALIZED) { + return DecodeSharedDictionary(data, data_size, dict); + } +#endif /* BROTLI_EXPERIMENTAL */ + if (type == BROTLI_SHARED_DICTIONARY_RAW) { + if (dict->num_prefix >= SHARED_BROTLI_MAX_COMPOUND_DICTS) { + return BROTLI_FALSE; + } + dict->prefix_size[dict->num_prefix] = data_size; + dict->prefix[dict->num_prefix] = data; + dict->num_prefix++; + return BROTLI_TRUE; + } + return BROTLI_FALSE; +} + +BrotliSharedDictionary* BrotliSharedDictionaryCreateInstance( + brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) { + BrotliSharedDictionary* dict = 0; + if (!alloc_func && !free_func) { + dict = (BrotliSharedDictionary*)malloc(sizeof(BrotliSharedDictionary)); + } else if (alloc_func && free_func) { + dict = (BrotliSharedDictionary*)alloc_func( + opaque, sizeof(BrotliSharedDictionary)); + } + if (dict == 0) { + return 0; + } + + /* TODO(eustas): explicitly initialize all the fields? */ + memset(dict, 0, sizeof(BrotliSharedDictionary)); + + dict->context_based = BROTLI_FALSE; + dict->num_dictionaries = 1; + dict->num_word_lists = 0; + dict->num_transform_lists = 0; + + dict->words[0] = BrotliGetDictionary(); + dict->transforms[0] = BrotliGetTransforms(); + + dict->alloc_func = alloc_func ? alloc_func : BrotliDefaultAllocFunc; + dict->free_func = free_func ? free_func : BrotliDefaultFreeFunc; + dict->memory_manager_opaque = opaque; + + return dict; +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/common/shared_dictionary_internal.h b/packages/runtime/vendor/brotli/c/common/shared_dictionary_internal.h new file mode 100644 index 000000000..c6a90fa74 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/common/shared_dictionary_internal.h @@ -0,0 +1,75 @@ +/* Copyright 2017 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* (Transparent) Shared Dictionary definition. */ + +#ifndef BROTLI_COMMON_SHARED_DICTIONARY_INTERNAL_H_ +#define BROTLI_COMMON_SHARED_DICTIONARY_INTERNAL_H_ + +#include + +#include "dictionary.h" +#include "platform.h" +#include "transform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +struct BrotliSharedDictionaryStruct { + /* LZ77 prefixes (compound dictionary). */ + uint32_t num_prefix; /* max SHARED_BROTLI_MAX_COMPOUND_DICTS */ + size_t prefix_size[SHARED_BROTLI_MAX_COMPOUND_DICTS]; + const uint8_t* prefix[SHARED_BROTLI_MAX_COMPOUND_DICTS]; + + /* If set, the context map is used to select word and transform list from 64 + contexts, if not set, the context map is not used and only words[0] and + transforms[0] are to be used. */ + BROTLI_BOOL context_based; + + uint8_t context_map[SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS]; + + /* Amount of word_list+transform_list combinations. */ + uint8_t num_dictionaries; + + /* Must use num_dictionaries values. */ + const BrotliDictionary* words[SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS]; + + /* Must use num_dictionaries values. */ + const BrotliTransforms* transforms[SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS]; + + /* Amount of custom word lists. May be 0 if only Brotli's built-in is used */ + uint8_t num_word_lists; + + /* Contents of the custom words lists. Must be NULL if num_word_lists is 0. */ + BrotliDictionary* words_instances; + + /* Amount of custom transform lists. May be 0 if only Brotli's built-in is + used */ + uint8_t num_transform_lists; + + /* Contents of the custom transform lists. Must be NULL if num_transform_lists + is 0. */ + BrotliTransforms* transforms_instances; + + /* Concatenated prefix_suffix_maps of the custom transform lists. Must be NULL + if num_transform_lists is 0. */ + uint16_t* prefix_suffix_maps; + + /* Memory management */ + brotli_alloc_func alloc_func; + brotli_free_func free_func; + void* memory_manager_opaque; +}; + +typedef struct BrotliSharedDictionaryStruct BrotliSharedDictionaryInternal; +#define BrotliSharedDictionary BrotliSharedDictionaryInternal + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_COMMON_SHARED_DICTIONARY_INTERNAL_H_ */ diff --git a/packages/runtime/vendor/brotli/c/common/static_init.h b/packages/runtime/vendor/brotli/c/common/static_init.h new file mode 100644 index 000000000..12744de8f --- /dev/null +++ b/packages/runtime/vendor/brotli/c/common/static_init.h @@ -0,0 +1,56 @@ +/* Copyright 2025 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* + Central point for static initialization. + + In case of "lazy" mode `BrotliXxxLazyStaticInit` is not provided by the + library. Embedder is responsible for providing it. This function should call + `BrotliXxxLazyStaticInitInner` on the first invocation. This function should + not return until execution of `BrotliXxxLazyStaticInitInner` is finished. + In C or before C++11 it is possible to call `BrotliXxxLazyStaticInitInner` + on start-up path and then `BrotliEncoderLazyStaticInit` is could be no-op; + another option is to use available thread execution controls to meet the + requirements. For possible C++11 implementation see static_init_lazy.cc. +*/ + +#ifndef THIRD_PARTY_BROTLI_COMMON_STATIC_INIT_H_ +#define THIRD_PARTY_BROTLI_COMMON_STATIC_INIT_H_ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* Static data is "initialized" in compile time. */ +#define BROTLI_STATIC_INIT_NONE 0 +/* Static data is initialized before "main". */ +#define BROTLI_STATIC_INIT_EARLY 1 +/* Static data is initialized when first encoder is created. */ +#define BROTLI_STATIC_INIT_LAZY 2 + +#define BROTLI_STATIC_INIT_DEFAULT BROTLI_STATIC_INIT_NONE + +#if !defined(BROTLI_STATIC_INIT) +#define BROTLI_STATIC_INIT BROTLI_STATIC_INIT_DEFAULT +#endif + +#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE) && \ + (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_EARLY) && \ + (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_LAZY) +#error Invalid value for BROTLI_STATIC_INIT +#endif + +#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_EARLY) +#if defined(BROTLI_EXTERNAL_DICTIONARY_DATA) +#error BROTLI_STATIC_INIT_EARLY will fail with BROTLI_EXTERNAL_DICTIONARY_DATA +#endif +#endif /* BROTLI_STATIC_INIT */ + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif // THIRD_PARTY_BROTLI_COMMON_STATIC_INIT_H_ diff --git a/packages/runtime/vendor/brotli/c/common/transform.c b/packages/runtime/vendor/brotli/c/common/transform.c new file mode 100644 index 000000000..968b91238 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/common/transform.c @@ -0,0 +1,293 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#include "platform.h" +#include "transform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* RFC 7932 transforms string data */ +static const BROTLI_MODEL("small") char kPrefixSuffix[217] = + "\1 \2, \10 of the \4 of \2s \1.\5 and \4 " +/* 0x _0 _2 __5 _E _3 _6 _8 _E */ + "in \1\"\4 to \2\">\1\n\2. \1]\5 for \3 a \6 " +/* 2x _3_ _5 _A_ _D_ _F _2 _4 _A _E */ + "that \1\'\6 with \6 from \4 by \1(\6. T" +/* 4x _5_ _7 _E _5 _A _C */ + "he \4 on \4 as \4 is \4ing \2\n\t\1:\3ed " +/* 6x _3 _8 _D _2 _7_ _ _A _C */ + "\2=\"\4 at \3ly \1,\2=\'\5.com/\7. This \5" +/* 8x _0 _ _3 _8 _C _E _ _1 _7 _F */ + " not \3er \3al \4ful \4ive \5less \4es" +/* Ax _5 _9 _D _2 _7 _D */ + "t \4ize \2\xc2\xa0\4ous \5 the \2e "; /* \0 - implicit trailing zero. */ +/* Cx _2 _7___ ___ _A _F _5 _8 */ + +static const BROTLI_MODEL("small") uint16_t kPrefixSuffixMap[50] = { + 0x00, 0x02, 0x05, 0x0E, 0x13, 0x16, 0x18, 0x1E, 0x23, 0x25, + 0x2A, 0x2D, 0x2F, 0x32, 0x34, 0x3A, 0x3E, 0x45, 0x47, 0x4E, + 0x55, 0x5A, 0x5C, 0x63, 0x68, 0x6D, 0x72, 0x77, 0x7A, 0x7C, + 0x80, 0x83, 0x88, 0x8C, 0x8E, 0x91, 0x97, 0x9F, 0xA5, 0xA9, + 0xAD, 0xB2, 0xB7, 0xBD, 0xC2, 0xC7, 0xCA, 0xCF, 0xD5, 0xD8 +}; + +/* RFC 7932 transforms */ +static const BROTLI_MODEL("small") uint8_t kTransformsData[] = { + 49, BROTLI_TRANSFORM_IDENTITY, 49, + 49, BROTLI_TRANSFORM_IDENTITY, 0, + 0, BROTLI_TRANSFORM_IDENTITY, 0, + 49, BROTLI_TRANSFORM_OMIT_FIRST_1, 49, + 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 0, + 49, BROTLI_TRANSFORM_IDENTITY, 47, + 0, BROTLI_TRANSFORM_IDENTITY, 49, + 4, BROTLI_TRANSFORM_IDENTITY, 0, + 49, BROTLI_TRANSFORM_IDENTITY, 3, + 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 49, + 49, BROTLI_TRANSFORM_IDENTITY, 6, + 49, BROTLI_TRANSFORM_OMIT_FIRST_2, 49, + 49, BROTLI_TRANSFORM_OMIT_LAST_1, 49, + 1, BROTLI_TRANSFORM_IDENTITY, 0, + 49, BROTLI_TRANSFORM_IDENTITY, 1, + 0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 0, + 49, BROTLI_TRANSFORM_IDENTITY, 7, + 49, BROTLI_TRANSFORM_IDENTITY, 9, + 48, BROTLI_TRANSFORM_IDENTITY, 0, + 49, BROTLI_TRANSFORM_IDENTITY, 8, + 49, BROTLI_TRANSFORM_IDENTITY, 5, + 49, BROTLI_TRANSFORM_IDENTITY, 10, + 49, BROTLI_TRANSFORM_IDENTITY, 11, + 49, BROTLI_TRANSFORM_OMIT_LAST_3, 49, + 49, BROTLI_TRANSFORM_IDENTITY, 13, + 49, BROTLI_TRANSFORM_IDENTITY, 14, + 49, BROTLI_TRANSFORM_OMIT_FIRST_3, 49, + 49, BROTLI_TRANSFORM_OMIT_LAST_2, 49, + 49, BROTLI_TRANSFORM_IDENTITY, 15, + 49, BROTLI_TRANSFORM_IDENTITY, 16, + 0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 49, + 49, BROTLI_TRANSFORM_IDENTITY, 12, + 5, BROTLI_TRANSFORM_IDENTITY, 49, + 0, BROTLI_TRANSFORM_IDENTITY, 1, + 49, BROTLI_TRANSFORM_OMIT_FIRST_4, 49, + 49, BROTLI_TRANSFORM_IDENTITY, 18, + 49, BROTLI_TRANSFORM_IDENTITY, 17, + 49, BROTLI_TRANSFORM_IDENTITY, 19, + 49, BROTLI_TRANSFORM_IDENTITY, 20, + 49, BROTLI_TRANSFORM_OMIT_FIRST_5, 49, + 49, BROTLI_TRANSFORM_OMIT_FIRST_6, 49, + 47, BROTLI_TRANSFORM_IDENTITY, 49, + 49, BROTLI_TRANSFORM_OMIT_LAST_4, 49, + 49, BROTLI_TRANSFORM_IDENTITY, 22, + 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 49, + 49, BROTLI_TRANSFORM_IDENTITY, 23, + 49, BROTLI_TRANSFORM_IDENTITY, 24, + 49, BROTLI_TRANSFORM_IDENTITY, 25, + 49, BROTLI_TRANSFORM_OMIT_LAST_7, 49, + 49, BROTLI_TRANSFORM_OMIT_LAST_1, 26, + 49, BROTLI_TRANSFORM_IDENTITY, 27, + 49, BROTLI_TRANSFORM_IDENTITY, 28, + 0, BROTLI_TRANSFORM_IDENTITY, 12, + 49, BROTLI_TRANSFORM_IDENTITY, 29, + 49, BROTLI_TRANSFORM_OMIT_FIRST_9, 49, + 49, BROTLI_TRANSFORM_OMIT_FIRST_7, 49, + 49, BROTLI_TRANSFORM_OMIT_LAST_6, 49, + 49, BROTLI_TRANSFORM_IDENTITY, 21, + 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 1, + 49, BROTLI_TRANSFORM_OMIT_LAST_8, 49, + 49, BROTLI_TRANSFORM_IDENTITY, 31, + 49, BROTLI_TRANSFORM_IDENTITY, 32, + 47, BROTLI_TRANSFORM_IDENTITY, 3, + 49, BROTLI_TRANSFORM_OMIT_LAST_5, 49, + 49, BROTLI_TRANSFORM_OMIT_LAST_9, 49, + 0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 1, + 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 8, + 5, BROTLI_TRANSFORM_IDENTITY, 21, + 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 0, + 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 10, + 49, BROTLI_TRANSFORM_IDENTITY, 30, + 0, BROTLI_TRANSFORM_IDENTITY, 5, + 35, BROTLI_TRANSFORM_IDENTITY, 49, + 47, BROTLI_TRANSFORM_IDENTITY, 2, + 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 17, + 49, BROTLI_TRANSFORM_IDENTITY, 36, + 49, BROTLI_TRANSFORM_IDENTITY, 33, + 5, BROTLI_TRANSFORM_IDENTITY, 0, + 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 21, + 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 5, + 49, BROTLI_TRANSFORM_IDENTITY, 37, + 0, BROTLI_TRANSFORM_IDENTITY, 30, + 49, BROTLI_TRANSFORM_IDENTITY, 38, + 0, BROTLI_TRANSFORM_UPPERCASE_ALL, 0, + 49, BROTLI_TRANSFORM_IDENTITY, 39, + 0, BROTLI_TRANSFORM_UPPERCASE_ALL, 49, + 49, BROTLI_TRANSFORM_IDENTITY, 34, + 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 8, + 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 12, + 0, BROTLI_TRANSFORM_IDENTITY, 21, + 49, BROTLI_TRANSFORM_IDENTITY, 40, + 0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 12, + 49, BROTLI_TRANSFORM_IDENTITY, 41, + 49, BROTLI_TRANSFORM_IDENTITY, 42, + 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 17, + 49, BROTLI_TRANSFORM_IDENTITY, 43, + 0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 5, + 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 10, + 0, BROTLI_TRANSFORM_IDENTITY, 34, + 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 33, + 49, BROTLI_TRANSFORM_IDENTITY, 44, + 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 5, + 45, BROTLI_TRANSFORM_IDENTITY, 49, + 0, BROTLI_TRANSFORM_IDENTITY, 33, + 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 30, + 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 30, + 49, BROTLI_TRANSFORM_IDENTITY, 46, + 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 1, + 49, BROTLI_TRANSFORM_UPPERCASE_FIRST, 34, + 0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 33, + 0, BROTLI_TRANSFORM_UPPERCASE_ALL, 30, + 0, BROTLI_TRANSFORM_UPPERCASE_ALL, 1, + 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 33, + 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 21, + 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 12, + 0, BROTLI_TRANSFORM_UPPERCASE_ALL, 5, + 49, BROTLI_TRANSFORM_UPPERCASE_ALL, 34, + 0, BROTLI_TRANSFORM_UPPERCASE_ALL, 12, + 0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 30, + 0, BROTLI_TRANSFORM_UPPERCASE_ALL, 34, + 0, BROTLI_TRANSFORM_UPPERCASE_FIRST, 34, +}; + +static const BROTLI_MODEL("small") +BrotliTransforms kBrotliTransforms = { + sizeof(kPrefixSuffix), + (const uint8_t*)kPrefixSuffix, + kPrefixSuffixMap, + sizeof(kTransformsData) / (3 * sizeof(kTransformsData[0])), + kTransformsData, + NULL, /* no extra parameters */ + {0, 12, 27, 23, 42, 63, 56, 48, 59, 64} +}; + +const BrotliTransforms* BrotliGetTransforms(void) { + return &kBrotliTransforms; +} + +static int ToUpperCase(uint8_t* p) { + if (p[0] < 0xC0) { + if (p[0] >= 'a' && p[0] <= 'z') { + p[0] ^= 32; + } + return 1; + } + /* An overly simplified uppercasing model for UTF-8. */ + if (p[0] < 0xE0) { + p[1] ^= 32; + return 2; + } + /* An arbitrary transform for three byte characters. */ + p[2] ^= 5; + return 3; +} + +static int Shift(uint8_t* word, int word_len, uint16_t parameter) { + /* Limited sign extension: scalar < (1 << 24). */ + uint32_t scalar = + (parameter & 0x7FFFu) + (0x1000000u - (parameter & 0x8000u)); + if (word[0] < 0x80) { + /* 1-byte rune / 0sssssss / 7 bit scalar (ASCII). */ + scalar += (uint32_t)word[0]; + word[0] = (uint8_t)(scalar & 0x7Fu); + return 1; + } else if (word[0] < 0xC0) { + /* Continuation / 10AAAAAA. */ + return 1; + } else if (word[0] < 0xE0) { + /* 2-byte rune / 110sssss AAssssss / 11 bit scalar. */ + if (word_len < 2) return 1; + scalar += (uint32_t)((word[1] & 0x3Fu) | ((word[0] & 0x1Fu) << 6u)); + word[0] = (uint8_t)(0xC0 | ((scalar >> 6u) & 0x1F)); + word[1] = (uint8_t)((word[1] & 0xC0) | (scalar & 0x3F)); + return 2; + } else if (word[0] < 0xF0) { + /* 3-byte rune / 1110ssss AAssssss BBssssss / 16 bit scalar. */ + if (word_len < 3) return word_len; + scalar += (uint32_t)((word[2] & 0x3Fu) | ((word[1] & 0x3Fu) << 6u) | + ((word[0] & 0x0Fu) << 12u)); + word[0] = (uint8_t)(0xE0 | ((scalar >> 12u) & 0x0F)); + word[1] = (uint8_t)((word[1] & 0xC0) | ((scalar >> 6u) & 0x3F)); + word[2] = (uint8_t)((word[2] & 0xC0) | (scalar & 0x3F)); + return 3; + } else if (word[0] < 0xF8) { + /* 4-byte rune / 11110sss AAssssss BBssssss CCssssss / 21 bit scalar. */ + if (word_len < 4) return word_len; + scalar += (uint32_t)((word[3] & 0x3Fu) | ((word[2] & 0x3Fu) << 6u) | + ((word[1] & 0x3Fu) << 12u) | ((word[0] & 0x07u) << 18u)); + word[0] = (uint8_t)(0xF0 | ((scalar >> 18u) & 0x07)); + word[1] = (uint8_t)((word[1] & 0xC0) | ((scalar >> 12u) & 0x3F)); + word[2] = (uint8_t)((word[2] & 0xC0) | ((scalar >> 6u) & 0x3F)); + word[3] = (uint8_t)((word[3] & 0xC0) | (scalar & 0x3F)); + return 4; + } + return 1; +} + +int BrotliTransformDictionaryWord(uint8_t* dst, const uint8_t* word, int len, + const BrotliTransforms* transforms, int transform_idx) { + int idx = 0; + const uint8_t* prefix = BROTLI_TRANSFORM_PREFIX(transforms, transform_idx); + uint8_t type = BROTLI_TRANSFORM_TYPE(transforms, transform_idx); + const uint8_t* suffix = BROTLI_TRANSFORM_SUFFIX(transforms, transform_idx); + { + int prefix_len = *prefix++; + while (prefix_len--) { dst[idx++] = *prefix++; } + } + { + const int t = type; + int i = 0; + if (t <= BROTLI_TRANSFORM_OMIT_LAST_9) { + len -= t; + } else if (t >= BROTLI_TRANSFORM_OMIT_FIRST_1 + && t <= BROTLI_TRANSFORM_OMIT_FIRST_9) { + int skip = t - (BROTLI_TRANSFORM_OMIT_FIRST_1 - 1); + word += skip; + len -= skip; + } + while (i < len) { dst[idx++] = word[i++]; } + if (t == BROTLI_TRANSFORM_UPPERCASE_FIRST) { + ToUpperCase(&dst[idx - len]); + } else if (t == BROTLI_TRANSFORM_UPPERCASE_ALL) { + uint8_t* uppercase = &dst[idx - len]; + while (len > 0) { + int step = ToUpperCase(uppercase); + uppercase += step; + len -= step; + } + } else if (t == BROTLI_TRANSFORM_SHIFT_FIRST) { + uint16_t param = (uint16_t)(transforms->params[transform_idx * 2] + + (transforms->params[transform_idx * 2 + 1] << 8u)); + Shift(&dst[idx - len], len, param); + } else if (t == BROTLI_TRANSFORM_SHIFT_ALL) { + uint16_t param = (uint16_t)(transforms->params[transform_idx * 2] + + (transforms->params[transform_idx * 2 + 1] << 8u)); + uint8_t* shift = &dst[idx - len]; + while (len > 0) { + int step = Shift(shift, len, param); + shift += step; + len -= step; + } + } + } + { + int suffix_len = *suffix++; + while (suffix_len--) { dst[idx++] = *suffix++; } + return idx; + } +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/common/transform.h b/packages/runtime/vendor/brotli/c/common/transform.h new file mode 100644 index 000000000..c6176d834 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/common/transform.h @@ -0,0 +1,84 @@ +/* transforms is a part of ABI, but not API. + + It means that there are some functions that are supposed to be in "common" + library, but header itself is not placed into include/brotli. This way, + aforementioned functions will be available only to brotli internals. + */ + +#ifndef BROTLI_COMMON_TRANSFORM_H_ +#define BROTLI_COMMON_TRANSFORM_H_ + +#include "platform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +enum BrotliWordTransformType { + BROTLI_TRANSFORM_IDENTITY = 0, + BROTLI_TRANSFORM_OMIT_LAST_1 = 1, + BROTLI_TRANSFORM_OMIT_LAST_2 = 2, + BROTLI_TRANSFORM_OMIT_LAST_3 = 3, + BROTLI_TRANSFORM_OMIT_LAST_4 = 4, + BROTLI_TRANSFORM_OMIT_LAST_5 = 5, + BROTLI_TRANSFORM_OMIT_LAST_6 = 6, + BROTLI_TRANSFORM_OMIT_LAST_7 = 7, + BROTLI_TRANSFORM_OMIT_LAST_8 = 8, + BROTLI_TRANSFORM_OMIT_LAST_9 = 9, + BROTLI_TRANSFORM_UPPERCASE_FIRST = 10, + BROTLI_TRANSFORM_UPPERCASE_ALL = 11, + BROTLI_TRANSFORM_OMIT_FIRST_1 = 12, + BROTLI_TRANSFORM_OMIT_FIRST_2 = 13, + BROTLI_TRANSFORM_OMIT_FIRST_3 = 14, + BROTLI_TRANSFORM_OMIT_FIRST_4 = 15, + BROTLI_TRANSFORM_OMIT_FIRST_5 = 16, + BROTLI_TRANSFORM_OMIT_FIRST_6 = 17, + BROTLI_TRANSFORM_OMIT_FIRST_7 = 18, + BROTLI_TRANSFORM_OMIT_FIRST_8 = 19, + BROTLI_TRANSFORM_OMIT_FIRST_9 = 20, + BROTLI_TRANSFORM_SHIFT_FIRST = 21, + BROTLI_TRANSFORM_SHIFT_ALL = 22, + BROTLI_NUM_TRANSFORM_TYPES /* Counts transforms, not a transform itself. */ +}; + +#define BROTLI_TRANSFORMS_MAX_CUT_OFF BROTLI_TRANSFORM_OMIT_LAST_9 + +typedef struct BrotliTransforms { + uint16_t prefix_suffix_size; + /* Last character must be null, so prefix_suffix_size must be at least 1. */ + const uint8_t* prefix_suffix; + const uint16_t* prefix_suffix_map; + uint32_t num_transforms; + /* Each entry is a [prefix_id, transform, suffix_id] triplet. */ + const uint8_t* transforms; + /* Shift for BROTLI_TRANSFORM_SHIFT_FIRST and BROTLI_TRANSFORM_SHIFT_ALL, + must be NULL if and only if no such transforms are present. */ + const uint8_t* params; + /* Indices of transforms like ["", BROTLI_TRANSFORM_OMIT_LAST_#, ""]. + 0-th element corresponds to ["", BROTLI_TRANSFORM_IDENTITY, ""]. + -1, if cut-off transform does not exist. */ + int16_t cutOffTransforms[BROTLI_TRANSFORMS_MAX_CUT_OFF + 1]; +} BrotliTransforms; + +/* T is BrotliTransforms*; result is uint8_t. */ +#define BROTLI_TRANSFORM_PREFIX_ID(T, I) ((T)->transforms[((I) * 3) + 0]) +#define BROTLI_TRANSFORM_TYPE(T, I) ((T)->transforms[((I) * 3) + 1]) +#define BROTLI_TRANSFORM_SUFFIX_ID(T, I) ((T)->transforms[((I) * 3) + 2]) + +/* T is BrotliTransforms*; result is const uint8_t*. */ +#define BROTLI_TRANSFORM_PREFIX(T, I) (&(T)->prefix_suffix[ \ + (T)->prefix_suffix_map[BROTLI_TRANSFORM_PREFIX_ID(T, I)]]) +#define BROTLI_TRANSFORM_SUFFIX(T, I) (&(T)->prefix_suffix[ \ + (T)->prefix_suffix_map[BROTLI_TRANSFORM_SUFFIX_ID(T, I)]]) + +BROTLI_COMMON_API const BrotliTransforms* BrotliGetTransforms(void); + +BROTLI_COMMON_API int BrotliTransformDictionaryWord( + uint8_t* dst, const uint8_t* word, int len, + const BrotliTransforms* transforms, int transform_idx); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_COMMON_TRANSFORM_H_ */ diff --git a/packages/runtime/vendor/brotli/c/common/version.h b/packages/runtime/vendor/brotli/c/common/version.h new file mode 100644 index 000000000..0d6fcc50a --- /dev/null +++ b/packages/runtime/vendor/brotli/c/common/version.h @@ -0,0 +1,51 @@ +/* Copyright 2016 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Version definition. */ + +#ifndef BROTLI_COMMON_VERSION_H_ +#define BROTLI_COMMON_VERSION_H_ + +/* Compose 3 components into a single number. In a hexadecimal representation + B and C components occupy exactly 3 digits. */ +#define BROTLI_MAKE_HEX_VERSION(A, B, C) ((A << 24) | (B << 12) | C) + +/* Those macros should only be used when library is compiled together with + the client. If library is dynamically linked, use BrotliDecoderVersion and + BrotliEncoderVersion methods. */ + +#define BROTLI_VERSION_MAJOR 1 +#define BROTLI_VERSION_MINOR 2 +#define BROTLI_VERSION_PATCH 0 + +#define BROTLI_VERSION BROTLI_MAKE_HEX_VERSION( \ + BROTLI_VERSION_MAJOR, BROTLI_VERSION_MINOR, BROTLI_VERSION_PATCH) + +/* This macro is used by build system to produce Libtool-friendly soname. See + https://www.gnu.org/software/libtool/manual/html_node/Libtool-versioning.html + Version evolution rules: + - interfaces added (or change is compatible) -> current+1:0:age+1 + - interfaces removed (or changed is incompatible) -> current+1:0:0 + - interfaces not changed -> current:revision+1:age + */ + +#define BROTLI_ABI_CURRENT 3 +#define BROTLI_ABI_REVISION 0 +#define BROTLI_ABI_AGE 2 + +#if BROTLI_VERSION_MAJOR != (BROTLI_ABI_CURRENT - BROTLI_ABI_AGE) +#error ABI/API version inconsistency +#endif + +#if BROTLI_VERSION_MINOR != BROTLI_ABI_AGE +#error ABI/API version inconsistency +#endif + +#if BROTLI_VERSION_PATCH != BROTLI_ABI_REVISION +#error ABI/API version inconsistency +#endif + +#endif /* BROTLI_COMMON_VERSION_H_ */ diff --git a/packages/runtime/vendor/brotli/c/dec/bit_reader.c b/packages/runtime/vendor/brotli/c/dec/bit_reader.c new file mode 100644 index 000000000..fae034fd8 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/dec/bit_reader.c @@ -0,0 +1,77 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Bit reading helpers */ + +#include "bit_reader.h" + +#include "../common/platform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +const BROTLI_MODEL("small") +brotli_reg_t kBrotliBitMask[33] = { 0x00000000, + 0x00000001, 0x00000003, 0x00000007, 0x0000000F, + 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, + 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF, + 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, + 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF, + 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF, + 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF, + 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF +}; + +void BrotliInitBitReader(BrotliBitReader* const br) { + br->val_ = 0; + br->bit_pos_ = 0; +} + +BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* const br) { + size_t aligned_read_mask = (sizeof(br->val_) >> 1) - 1; + /* Fixing alignment after unaligned BrotliFillWindow would result accumulator + overflow. If unalignment is caused by BrotliSafeReadBits, then there is + enough space in accumulator to fix alignment. */ + if (BROTLI_UNALIGNED_READ_FAST) { + aligned_read_mask = 0; + } + if (BrotliGetAvailableBits(br) == 0) { + br->val_ = 0; + if (!BrotliPullByte(br)) { + return BROTLI_FALSE; + } + } + + while ((((size_t)br->next_in) & aligned_read_mask) != 0) { + if (!BrotliPullByte(br)) { + /* If we consumed all the input, we don't care about the alignment. */ + return BROTLI_TRUE; + } + } + return BROTLI_TRUE; +} + +BROTLI_BOOL BrotliSafeReadBits32Slow(BrotliBitReader* const br, + brotli_reg_t n_bits, brotli_reg_t* val) { + brotli_reg_t low_val; + brotli_reg_t high_val; + BrotliBitReaderState memento; + BROTLI_DCHECK(n_bits <= 32); + BROTLI_DCHECK(n_bits > 24); + BrotliBitReaderSaveState(br, &memento); + if (!BrotliSafeReadBits(br, 16, &low_val) || + !BrotliSafeReadBits(br, n_bits - 16, &high_val)) { + BrotliBitReaderRestoreState(br, &memento); + return BROTLI_FALSE; + } + *val = low_val | (high_val << 16); + return BROTLI_TRUE; +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/dec/bit_reader.h b/packages/runtime/vendor/brotli/c/dec/bit_reader.h new file mode 100644 index 000000000..ef6b047ae --- /dev/null +++ b/packages/runtime/vendor/brotli/c/dec/bit_reader.h @@ -0,0 +1,419 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Bit reading helpers */ + +#ifndef BROTLI_DEC_BIT_READER_H_ +#define BROTLI_DEC_BIT_READER_H_ + +#include "../common/constants.h" +#include "../common/platform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define BROTLI_SHORT_FILL_BIT_WINDOW_READ (sizeof(brotli_reg_t) >> 1) + +/* 162 bits + 7 bytes */ +#define BROTLI_FAST_INPUT_SLACK 28 + +BROTLI_INTERNAL extern const brotli_reg_t kBrotliBitMask[33]; + +static BROTLI_INLINE brotli_reg_t BitMask(brotli_reg_t n) { + if (BROTLI_IS_CONSTANT(n) || BROTLI_HAS_UBFX) { + /* Masking with this expression turns to a single + "Unsigned Bit Field Extract" UBFX instruction on ARM. */ + return ~(~((brotli_reg_t)0) << n); + } else { + return kBrotliBitMask[n]; + } +} + +typedef struct { + brotli_reg_t val_; /* pre-fetched bits */ + brotli_reg_t bit_pos_; /* current bit-reading position in val_ */ + const uint8_t* next_in; /* the byte we're reading from */ + const uint8_t* guard_in; /* position from which "fast-path" is prohibited */ + const uint8_t* last_in; /* == next_in + avail_in */ +} BrotliBitReader; + +typedef struct { + brotli_reg_t val_; + brotli_reg_t bit_pos_; + const uint8_t* next_in; + size_t avail_in; +} BrotliBitReaderState; + +/* Initializes the BrotliBitReader fields. */ +BROTLI_INTERNAL void BrotliInitBitReader(BrotliBitReader* br); + +/* Ensures that accumulator is not empty. + May consume up to sizeof(brotli_reg_t) - 1 bytes of input. + Returns BROTLI_FALSE if data is required but there is no input available. + For !BROTLI_UNALIGNED_READ_FAST this function also prepares bit reader for + aligned reading. */ +BROTLI_INTERNAL BROTLI_BOOL BrotliWarmupBitReader(BrotliBitReader* br); + +/* Fallback for BrotliSafeReadBits32. Extracted as noninlined method to unburden + the main code-path. Never called for RFC brotli streams, required only for + "large-window" mode and other extensions. */ +BROTLI_INTERNAL BROTLI_NOINLINE BROTLI_BOOL BrotliSafeReadBits32Slow( + BrotliBitReader* br, brotli_reg_t n_bits, brotli_reg_t* val); + +static BROTLI_INLINE size_t +BrotliBitReaderGetAvailIn(BrotliBitReader* const br) { + return (size_t)(br->last_in - br->next_in); +} + +static BROTLI_INLINE void BrotliBitReaderSaveState( + BrotliBitReader* const from, BrotliBitReaderState* to) { + to->val_ = from->val_; + to->bit_pos_ = from->bit_pos_; + to->next_in = from->next_in; + to->avail_in = BrotliBitReaderGetAvailIn(from); +} + +static BROTLI_INLINE void BrotliBitReaderSetInput( + BrotliBitReader* const br, const uint8_t* next_in, size_t avail_in) { + br->next_in = next_in; + br->last_in = (avail_in == 0) ? next_in : (next_in + avail_in); + if (avail_in + 1 > BROTLI_FAST_INPUT_SLACK) { + br->guard_in = next_in + (avail_in + 1 - BROTLI_FAST_INPUT_SLACK); + } else { + br->guard_in = next_in; + } +} + +static BROTLI_INLINE void BrotliBitReaderRestoreState( + BrotliBitReader* const to, BrotliBitReaderState* from) { + to->val_ = from->val_; + to->bit_pos_ = from->bit_pos_; + to->next_in = from->next_in; + BrotliBitReaderSetInput(to, from->next_in, from->avail_in); +} + +static BROTLI_INLINE brotli_reg_t BrotliGetAvailableBits( + const BrotliBitReader* br) { + return br->bit_pos_; +} + +/* Returns amount of unread bytes the bit reader still has buffered from the + BrotliInput, including whole bytes in br->val_. Result is capped with + maximal ring-buffer size (larger number won't be utilized anyway). */ +static BROTLI_INLINE size_t BrotliGetRemainingBytes(BrotliBitReader* br) { + static const size_t kCap = (size_t)1 << BROTLI_LARGE_MAX_WBITS; + size_t avail_in = BrotliBitReaderGetAvailIn(br); + if (avail_in > kCap) return kCap; + return avail_in + (BrotliGetAvailableBits(br) >> 3); +} + +/* Checks if there is at least |num| bytes left in the input ring-buffer + (excluding the bits remaining in br->val_). */ +static BROTLI_INLINE BROTLI_BOOL BrotliCheckInputAmount( + BrotliBitReader* const br) { + return TO_BROTLI_BOOL(br->next_in < br->guard_in); +} + +/* Load more bits into accumulator. */ +static BROTLI_INLINE brotli_reg_t BrotliBitReaderLoadBits(brotli_reg_t val, + brotli_reg_t new_bits, + brotli_reg_t count, + brotli_reg_t offset) { + BROTLI_DCHECK( + !((val >> offset) & ~new_bits & ~(~((brotli_reg_t)0) << count))); + (void)count; + return val | (new_bits << offset); +} + +/* Guarantees that there are at least |n_bits| + 1 bits in accumulator. + Precondition: accumulator contains at least 1 bit. + |n_bits| should be in the range [1..24] for regular build. For portable + non-64-bit little-endian build only 16 bits are safe to request. */ +static BROTLI_INLINE void BrotliFillBitWindow( + BrotliBitReader* const br, brotli_reg_t n_bits) { +#if (BROTLI_64_BITS) + if (BROTLI_UNALIGNED_READ_FAST && BROTLI_IS_CONSTANT(n_bits) && + (n_bits <= 8)) { + brotli_reg_t bit_pos = br->bit_pos_; + if (bit_pos <= 8) { + br->val_ = BrotliBitReaderLoadBits(br->val_, + BROTLI_UNALIGNED_LOAD64LE(br->next_in), 56, bit_pos); + br->bit_pos_ = bit_pos + 56; + br->next_in += 7; + } + } else if (BROTLI_UNALIGNED_READ_FAST && BROTLI_IS_CONSTANT(n_bits) && + (n_bits <= 16)) { + brotli_reg_t bit_pos = br->bit_pos_; + if (bit_pos <= 16) { + br->val_ = BrotliBitReaderLoadBits(br->val_, + BROTLI_UNALIGNED_LOAD64LE(br->next_in), 48, bit_pos); + br->bit_pos_ = bit_pos + 48; + br->next_in += 6; + } + } else { + brotli_reg_t bit_pos = br->bit_pos_; + if (bit_pos <= 32) { + br->val_ = BrotliBitReaderLoadBits(br->val_, + (uint64_t)BROTLI_UNALIGNED_LOAD32LE(br->next_in), 32, bit_pos); + br->bit_pos_ = bit_pos + 32; + br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ; + } + } +#else + if (BROTLI_UNALIGNED_READ_FAST && BROTLI_IS_CONSTANT(n_bits) && + (n_bits <= 8)) { + brotli_reg_t bit_pos = br->bit_pos_; + if (bit_pos <= 8) { + br->val_ = BrotliBitReaderLoadBits(br->val_, + BROTLI_UNALIGNED_LOAD32LE(br->next_in), 24, bit_pos); + br->bit_pos_ = bit_pos + 24; + br->next_in += 3; + } + } else { + brotli_reg_t bit_pos = br->bit_pos_; + if (bit_pos <= 16) { + br->val_ = BrotliBitReaderLoadBits(br->val_, + (uint32_t)BROTLI_UNALIGNED_LOAD16LE(br->next_in), 16, bit_pos); + br->bit_pos_ = bit_pos + 16; + br->next_in += BROTLI_SHORT_FILL_BIT_WINDOW_READ; + } + } +#endif +} + +/* Mostly like BrotliFillBitWindow, but guarantees only 16 bits and reads no + more than BROTLI_SHORT_FILL_BIT_WINDOW_READ bytes of input. */ +static BROTLI_INLINE void BrotliFillBitWindow16(BrotliBitReader* const br) { + BrotliFillBitWindow(br, 17); +} + +/* Tries to pull one byte of input to accumulator. + Returns BROTLI_FALSE if there is no input available. */ +static BROTLI_INLINE BROTLI_BOOL BrotliPullByte(BrotliBitReader* const br) { + if (br->next_in == br->last_in) { + return BROTLI_FALSE; + } + br->val_ = BrotliBitReaderLoadBits(br->val_, + (brotli_reg_t)*br->next_in, 8, br->bit_pos_); + br->bit_pos_ += 8; + ++br->next_in; + return BROTLI_TRUE; +} + +/* Returns currently available bits. + The number of valid bits could be calculated by BrotliGetAvailableBits. */ +static BROTLI_INLINE brotli_reg_t BrotliGetBitsUnmasked( + BrotliBitReader* const br) { + return br->val_; +} + +/* Like BrotliGetBits, but does not mask the result. + The result contains at least 16 valid bits. */ +static BROTLI_INLINE brotli_reg_t BrotliGet16BitsUnmasked( + BrotliBitReader* const br) { + BrotliFillBitWindow(br, 16); + return (brotli_reg_t)BrotliGetBitsUnmasked(br); +} + +/* Returns the specified number of bits from |br| without advancing bit + position. */ +static BROTLI_INLINE brotli_reg_t BrotliGetBits( + BrotliBitReader* const br, brotli_reg_t n_bits) { + BrotliFillBitWindow(br, n_bits); + return BrotliGetBitsUnmasked(br) & BitMask(n_bits); +} + +/* Tries to peek the specified amount of bits. Returns BROTLI_FALSE, if there + is not enough input. */ +static BROTLI_INLINE BROTLI_BOOL BrotliSafeGetBits( + BrotliBitReader* const br, brotli_reg_t n_bits, brotli_reg_t* val) { + while (BrotliGetAvailableBits(br) < n_bits) { + if (!BrotliPullByte(br)) { + return BROTLI_FALSE; + } + } + *val = BrotliGetBitsUnmasked(br) & BitMask(n_bits); + return BROTLI_TRUE; +} + +/* Advances the bit pos by |n_bits|. */ +static BROTLI_INLINE void BrotliDropBits( + BrotliBitReader* const br, brotli_reg_t n_bits) { + br->bit_pos_ -= n_bits; + br->val_ >>= n_bits; +} + +/* Make sure that there are no spectre bits in accumulator. + This is important for the cases when some bytes are skipped + (i.e. never placed into accumulator). */ +static BROTLI_INLINE void BrotliBitReaderNormalize(BrotliBitReader* br) { + /* Actually, it is enough to normalize when br->bit_pos_ == 0 */ + if (br->bit_pos_ < (sizeof(brotli_reg_t) << 3u)) { + br->val_ &= (((brotli_reg_t)1) << br->bit_pos_) - 1; + } +} + +static BROTLI_INLINE void BrotliBitReaderUnload(BrotliBitReader* br) { + brotli_reg_t unused_bytes = BrotliGetAvailableBits(br) >> 3; + brotli_reg_t unused_bits = unused_bytes << 3; + br->next_in = + (unused_bytes == 0) ? br->next_in : (br->next_in - unused_bytes); + br->bit_pos_ -= unused_bits; + BrotliBitReaderNormalize(br); +} + +/* Reads the specified number of bits from |br| and advances the bit pos. + Precondition: accumulator MUST contain at least |n_bits|. */ +static BROTLI_INLINE void BrotliTakeBits(BrotliBitReader* const br, + brotli_reg_t n_bits, + brotli_reg_t* val) { + *val = BrotliGetBitsUnmasked(br) & BitMask(n_bits); + BROTLI_LOG(("[BrotliTakeBits] %d %d %d val: %6x\n", + (int)BrotliBitReaderGetAvailIn(br), (int)br->bit_pos_, + (int)n_bits, (int)*val)); + BrotliDropBits(br, n_bits); +} + +/* Reads the specified number of bits from |br| and advances the bit pos. + Assumes that there is enough input to perform BrotliFillBitWindow. + Up to 24 bits are allowed to be requested from this method. */ +static BROTLI_INLINE brotli_reg_t BrotliReadBits24( + BrotliBitReader* const br, brotli_reg_t n_bits) { + BROTLI_DCHECK(n_bits <= 24); + if (BROTLI_64_BITS || (n_bits <= 16)) { + brotli_reg_t val; + BrotliFillBitWindow(br, n_bits); + BrotliTakeBits(br, n_bits, &val); + return val; + } else { + brotli_reg_t low_val; + brotli_reg_t high_val; + BrotliFillBitWindow(br, 16); + BrotliTakeBits(br, 16, &low_val); + BrotliFillBitWindow(br, 8); + BrotliTakeBits(br, n_bits - 16, &high_val); + return low_val | (high_val << 16); + } +} + +/* Same as BrotliReadBits24, but allows reading up to 32 bits. */ +static BROTLI_INLINE brotli_reg_t BrotliReadBits32( + BrotliBitReader* const br, brotli_reg_t n_bits) { + BROTLI_DCHECK(n_bits <= 32); + if (BROTLI_64_BITS || (n_bits <= 16)) { + brotli_reg_t val; + BrotliFillBitWindow(br, n_bits); + BrotliTakeBits(br, n_bits, &val); + return val; + } else { + brotli_reg_t low_val; + brotli_reg_t high_val; + BrotliFillBitWindow(br, 16); + BrotliTakeBits(br, 16, &low_val); + BrotliFillBitWindow(br, 16); + BrotliTakeBits(br, n_bits - 16, &high_val); + return low_val | (high_val << 16); + } +} + +/* Tries to read the specified amount of bits. Returns BROTLI_FALSE, if there + is not enough input. |n_bits| MUST be positive. + Up to 24 bits are allowed to be requested from this method. */ +static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits( + BrotliBitReader* const br, brotli_reg_t n_bits, brotli_reg_t* val) { + BROTLI_DCHECK(n_bits <= 24); + while (BrotliGetAvailableBits(br) < n_bits) { + if (!BrotliPullByte(br)) { + return BROTLI_FALSE; + } + } + BrotliTakeBits(br, n_bits, val); + return BROTLI_TRUE; +} + +/* Same as BrotliSafeReadBits, but allows reading up to 32 bits. */ +static BROTLI_INLINE BROTLI_BOOL BrotliSafeReadBits32( + BrotliBitReader* const br, brotli_reg_t n_bits, brotli_reg_t* val) { + BROTLI_DCHECK(n_bits <= 32); + if (BROTLI_64_BITS || (n_bits <= 24)) { + while (BrotliGetAvailableBits(br) < n_bits) { + if (!BrotliPullByte(br)) { + return BROTLI_FALSE; + } + } + BrotliTakeBits(br, n_bits, val); + return BROTLI_TRUE; + } else { + return BrotliSafeReadBits32Slow(br, n_bits, val); + } +} + +/* Advances the bit reader position to the next byte boundary and verifies + that any skipped bits are set to zero. */ +static BROTLI_INLINE BROTLI_BOOL BrotliJumpToByteBoundary(BrotliBitReader* br) { + brotli_reg_t pad_bits_count = BrotliGetAvailableBits(br) & 0x7; + brotli_reg_t pad_bits = 0; + if (pad_bits_count != 0) { + BrotliTakeBits(br, pad_bits_count, &pad_bits); + } + BrotliBitReaderNormalize(br); + return TO_BROTLI_BOOL(pad_bits == 0); +} + +static BROTLI_INLINE void BrotliDropBytes(BrotliBitReader* br, size_t num) { + /* Check detour is legal: accumulator must to be empty. */ + BROTLI_DCHECK(br->bit_pos_ == 0); + BROTLI_DCHECK(br->val_ == 0); + br->next_in += num; +} + +/* Copies remaining input bytes stored in the bit reader to the output. Value + |num| may not be larger than BrotliGetRemainingBytes. The bit reader must be + warmed up again after this. */ +static BROTLI_INLINE void BrotliCopyBytes(uint8_t* dest, + BrotliBitReader* br, size_t num) { + while (BrotliGetAvailableBits(br) >= 8 && num > 0) { + *dest = (uint8_t)BrotliGetBitsUnmasked(br); + BrotliDropBits(br, 8); + ++dest; + --num; + } + BrotliBitReaderNormalize(br); + if (num > 0) { + memcpy(dest, br->next_in, num); + BrotliDropBytes(br, num); + } +} + +BROTLI_UNUSED_FUNCTION void BrotliBitReaderSuppressUnusedFunctions(void) { + BROTLI_UNUSED(&BrotliBitReaderSuppressUnusedFunctions); + + BROTLI_UNUSED(&BrotliBitReaderGetAvailIn); + BROTLI_UNUSED(&BrotliBitReaderLoadBits); + BROTLI_UNUSED(&BrotliBitReaderRestoreState); + BROTLI_UNUSED(&BrotliBitReaderSaveState); + BROTLI_UNUSED(&BrotliBitReaderSetInput); + BROTLI_UNUSED(&BrotliBitReaderUnload); + BROTLI_UNUSED(&BrotliCheckInputAmount); + BROTLI_UNUSED(&BrotliCopyBytes); + BROTLI_UNUSED(&BrotliFillBitWindow16); + BROTLI_UNUSED(&BrotliGet16BitsUnmasked); + BROTLI_UNUSED(&BrotliGetBits); + BROTLI_UNUSED(&BrotliGetRemainingBytes); + BROTLI_UNUSED(&BrotliJumpToByteBoundary); + BROTLI_UNUSED(&BrotliReadBits24); + BROTLI_UNUSED(&BrotliReadBits32); + BROTLI_UNUSED(&BrotliSafeGetBits); + BROTLI_UNUSED(&BrotliSafeReadBits); + BROTLI_UNUSED(&BrotliSafeReadBits32); +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_DEC_BIT_READER_H_ */ diff --git a/packages/runtime/vendor/brotli/c/dec/decode.c b/packages/runtime/vendor/brotli/c/dec/decode.c new file mode 100644 index 000000000..e87e7f5ea --- /dev/null +++ b/packages/runtime/vendor/brotli/c/dec/decode.c @@ -0,0 +1,2964 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#include + +#include "../common/constants.h" +#include "../common/context.h" +#include "../common/dictionary.h" +#include "../common/platform.h" +#include "../common/shared_dictionary_internal.h" +#include "../common/transform.h" +#include "../common/version.h" +#include "bit_reader.h" +#include "huffman.h" +#include "prefix.h" +#include "state.h" +#include "static_init.h" + +#if defined(BROTLI_TARGET_NEON) +#include +#endif + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define BROTLI_FAILURE(CODE) (BROTLI_DUMP(), CODE) + +#define BROTLI_LOG_UINT(name) \ + BROTLI_LOG(("[%s] %s = %lu\n", __func__, #name, (unsigned long)(name))) +#define BROTLI_LOG_ARRAY_INDEX(array_name, idx) \ + BROTLI_LOG(("[%s] %s[%lu] = %lu\n", __func__, #array_name, \ + (unsigned long)(idx), (unsigned long)array_name[idx])) + +#define HUFFMAN_TABLE_BITS 8U +#define HUFFMAN_TABLE_MASK 0xFF + +/* We need the slack region for the following reasons: + - doing up to two 16-byte copies for fast backward copying + - inserting transformed dictionary word: + 255 prefix + 32 base + 255 suffix */ +static const brotli_reg_t kRingBufferWriteAheadSlack = 542; + +static const BROTLI_MODEL("small") +uint8_t kCodeLengthCodeOrder[BROTLI_CODE_LENGTH_CODES] = { + 1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15, +}; + +/* Static prefix code for the complex code length code lengths. */ +static const BROTLI_MODEL("small") +uint8_t kCodeLengthPrefixLength[16] = { + 2, 2, 2, 3, 2, 2, 2, 4, 2, 2, 2, 3, 2, 2, 2, 4, +}; + +static const BROTLI_MODEL("small") +uint8_t kCodeLengthPrefixValue[16] = { + 0, 4, 3, 2, 0, 4, 3, 1, 0, 4, 3, 2, 0, 4, 3, 5, +}; + +BROTLI_BOOL BrotliDecoderSetParameter( + BrotliDecoderState* state, BrotliDecoderParameter p, uint32_t value) { + if (state->state != BROTLI_STATE_UNINITED) return BROTLI_FALSE; + switch (p) { + case BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION: + state->canny_ringbuffer_allocation = !!value ? 0 : 1; + return BROTLI_TRUE; + + case BROTLI_DECODER_PARAM_LARGE_WINDOW: + state->large_window = TO_BROTLI_BOOL(!!value); + return BROTLI_TRUE; + + default: return BROTLI_FALSE; + } +} + +BrotliDecoderState* BrotliDecoderCreateInstance( + brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) { + BrotliDecoderState* state = 0; + if (!BrotliDecoderEnsureStaticInit()) { + BROTLI_DUMP(); + return 0; + } + if (!alloc_func && !free_func) { + state = (BrotliDecoderState*)malloc(sizeof(BrotliDecoderState)); + } else if (alloc_func && free_func) { + state = (BrotliDecoderState*)alloc_func(opaque, sizeof(BrotliDecoderState)); + } + if (state == 0) { + BROTLI_DUMP(); + return 0; + } + if (!BrotliDecoderStateInit(state, alloc_func, free_func, opaque)) { + BROTLI_DUMP(); + if (!alloc_func && !free_func) { + free(state); + } else if (alloc_func && free_func) { + free_func(opaque, state); + } + return 0; + } + return state; +} + +/* Deinitializes and frees BrotliDecoderState instance. */ +void BrotliDecoderDestroyInstance(BrotliDecoderState* state) { + if (!state) { + return; + } else { + brotli_free_func free_func = state->free_func; + void* opaque = state->memory_manager_opaque; + BrotliDecoderStateCleanup(state); + free_func(opaque, state); + } +} + +/* Saves error code and converts it to BrotliDecoderResult. */ +static BROTLI_NOINLINE BrotliDecoderResult SaveErrorCode( + BrotliDecoderState* s, BrotliDecoderErrorCode e, size_t consumed_input) { + s->error_code = (int)e; + s->used_input += consumed_input; + if ((s->buffer_length != 0) && (s->br.next_in == s->br.last_in)) { + /* If internal buffer is depleted at last, reset it. */ + s->buffer_length = 0; + } + switch (e) { + case BROTLI_DECODER_SUCCESS: + return BROTLI_DECODER_RESULT_SUCCESS; + + case BROTLI_DECODER_NEEDS_MORE_INPUT: + return BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT; + + case BROTLI_DECODER_NEEDS_MORE_OUTPUT: + return BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT; + + default: + return BROTLI_DECODER_RESULT_ERROR; + } +} + +/* Decodes WBITS by reading 1 - 7 bits, or 0x11 for "Large Window Brotli". + Precondition: bit-reader accumulator has at least 8 bits. */ +static BrotliDecoderErrorCode DecodeWindowBits(BrotliDecoderState* s, + BrotliBitReader* br) { + brotli_reg_t n; + BROTLI_BOOL large_window = s->large_window; + s->large_window = BROTLI_FALSE; + BrotliTakeBits(br, 1, &n); + if (n == 0) { + s->window_bits = 16; + return BROTLI_DECODER_SUCCESS; + } + BrotliTakeBits(br, 3, &n); + if (n != 0) { + s->window_bits = (17u + n) & 63u; + return BROTLI_DECODER_SUCCESS; + } + BrotliTakeBits(br, 3, &n); + if (n == 1) { + if (large_window) { + BrotliTakeBits(br, 1, &n); + if (n == 1) { + return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS); + } + s->large_window = BROTLI_TRUE; + return BROTLI_DECODER_SUCCESS; + } else { + return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS); + } + } + if (n != 0) { + s->window_bits = (8u + n) & 63u; + return BROTLI_DECODER_SUCCESS; + } + s->window_bits = 17; + return BROTLI_DECODER_SUCCESS; +} + +static BROTLI_INLINE void memmove16(uint8_t* dst, uint8_t* src) { +#if defined(BROTLI_TARGET_NEON) + vst1q_u8(dst, vld1q_u8(src)); +#else + uint32_t buffer[4]; + memcpy(buffer, src, 16); + memcpy(dst, buffer, 16); +#endif +} + +/* Decodes a number in the range [0..255], by reading 1 - 11 bits. */ +static BROTLI_NOINLINE BrotliDecoderErrorCode DecodeVarLenUint8( + BrotliDecoderState* s, BrotliBitReader* br, brotli_reg_t* value) { + brotli_reg_t bits; + switch (s->substate_decode_uint8) { + case BROTLI_STATE_DECODE_UINT8_NONE: + if (BROTLI_PREDICT_FALSE(!BrotliSafeReadBits(br, 1, &bits))) { + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + if (bits == 0) { + *value = 0; + return BROTLI_DECODER_SUCCESS; + } + /* Fall through. */ + + case BROTLI_STATE_DECODE_UINT8_SHORT: + if (BROTLI_PREDICT_FALSE(!BrotliSafeReadBits(br, 3, &bits))) { + s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_SHORT; + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + if (bits == 0) { + *value = 1; + s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_NONE; + return BROTLI_DECODER_SUCCESS; + } + /* Use output value as a temporary storage. It MUST be persisted. */ + *value = bits; + /* Fall through. */ + + case BROTLI_STATE_DECODE_UINT8_LONG: + if (BROTLI_PREDICT_FALSE(!BrotliSafeReadBits(br, *value, &bits))) { + s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_LONG; + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + *value = ((brotli_reg_t)1U << *value) + bits; + s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_NONE; + return BROTLI_DECODER_SUCCESS; + + default: + return + BROTLI_FAILURE(BROTLI_DECODER_ERROR_UNREACHABLE); /* COV_NF_LINE */ + } +} + +/* Decodes a metablock length and flags by reading 2 - 31 bits. */ +static BrotliDecoderErrorCode BROTLI_NOINLINE DecodeMetaBlockLength( + BrotliDecoderState* s, BrotliBitReader* br) { + brotli_reg_t bits; + int i; + for (;;) { + switch (s->substate_metablock_header) { + case BROTLI_STATE_METABLOCK_HEADER_NONE: + if (!BrotliSafeReadBits(br, 1, &bits)) { + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + s->is_last_metablock = bits ? 1 : 0; + s->meta_block_remaining_len = 0; + s->is_uncompressed = 0; + s->is_metadata = 0; + if (!s->is_last_metablock) { + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NIBBLES; + break; + } + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_EMPTY; + /* Fall through. */ + + case BROTLI_STATE_METABLOCK_HEADER_EMPTY: + if (!BrotliSafeReadBits(br, 1, &bits)) { + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + if (bits) { + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE; + return BROTLI_DECODER_SUCCESS; + } + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NIBBLES; + /* Fall through. */ + + case BROTLI_STATE_METABLOCK_HEADER_NIBBLES: + if (!BrotliSafeReadBits(br, 2, &bits)) { + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + s->size_nibbles = (uint8_t)(bits + 4); + s->loop_counter = 0; + if (bits == 3) { + s->is_metadata = 1; + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_RESERVED; + break; + } + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_SIZE; + /* Fall through. */ + + case BROTLI_STATE_METABLOCK_HEADER_SIZE: + i = s->loop_counter; + for (; i < (int)s->size_nibbles; ++i) { + if (!BrotliSafeReadBits(br, 4, &bits)) { + s->loop_counter = i; + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + if (i + 1 == (int)s->size_nibbles && s->size_nibbles > 4 && + bits == 0) { + return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_NIBBLE); + } + s->meta_block_remaining_len |= (int)(bits << (i * 4)); + } + s->substate_metablock_header = + BROTLI_STATE_METABLOCK_HEADER_UNCOMPRESSED; + /* Fall through. */ + + case BROTLI_STATE_METABLOCK_HEADER_UNCOMPRESSED: + if (!s->is_last_metablock) { + if (!BrotliSafeReadBits(br, 1, &bits)) { + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + s->is_uncompressed = bits ? 1 : 0; + } + ++s->meta_block_remaining_len; + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE; + return BROTLI_DECODER_SUCCESS; + + case BROTLI_STATE_METABLOCK_HEADER_RESERVED: + if (!BrotliSafeReadBits(br, 1, &bits)) { + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + if (bits != 0) { + return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_RESERVED); + } + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_BYTES; + /* Fall through. */ + + case BROTLI_STATE_METABLOCK_HEADER_BYTES: + if (!BrotliSafeReadBits(br, 2, &bits)) { + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + if (bits == 0) { + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE; + return BROTLI_DECODER_SUCCESS; + } + s->size_nibbles = (uint8_t)bits; + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_METADATA; + /* Fall through. */ + + case BROTLI_STATE_METABLOCK_HEADER_METADATA: + i = s->loop_counter; + for (; i < (int)s->size_nibbles; ++i) { + if (!BrotliSafeReadBits(br, 8, &bits)) { + s->loop_counter = i; + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + if (i + 1 == (int)s->size_nibbles && s->size_nibbles > 1 && + bits == 0) { + return BROTLI_FAILURE( + BROTLI_DECODER_ERROR_FORMAT_EXUBERANT_META_NIBBLE); + } + s->meta_block_remaining_len |= (int)(bits << (i * 8)); + } + ++s->meta_block_remaining_len; + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE; + return BROTLI_DECODER_SUCCESS; + + default: + return + BROTLI_FAILURE(BROTLI_DECODER_ERROR_UNREACHABLE); /* COV_NF_LINE */ + } + } +} + +/* Decodes the Huffman code. + This method doesn't read data from the bit reader, BUT drops the amount of + bits that correspond to the decoded symbol. + bits MUST contain at least 15 (BROTLI_HUFFMAN_MAX_CODE_LENGTH) valid bits. */ +static BROTLI_INLINE brotli_reg_t DecodeSymbol(brotli_reg_t bits, + const HuffmanCode* table, + BrotliBitReader* br) { + BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table); + BROTLI_HC_ADJUST_TABLE_INDEX(table, bits & HUFFMAN_TABLE_MASK); + if (BROTLI_HC_FAST_LOAD_BITS(table) > HUFFMAN_TABLE_BITS) { + brotli_reg_t nbits = BROTLI_HC_FAST_LOAD_BITS(table) - HUFFMAN_TABLE_BITS; + BrotliDropBits(br, HUFFMAN_TABLE_BITS); + BROTLI_HC_ADJUST_TABLE_INDEX(table, + BROTLI_HC_FAST_LOAD_VALUE(table) + + ((bits >> HUFFMAN_TABLE_BITS) & BitMask(nbits))); + } + BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(table)); + return BROTLI_HC_FAST_LOAD_VALUE(table); +} + +/* Reads and decodes the next Huffman code from bit-stream. + This method peeks 16 bits of input and drops 0 - 15 of them. */ +static BROTLI_INLINE brotli_reg_t ReadSymbol(const HuffmanCode* table, + BrotliBitReader* br) { + return DecodeSymbol(BrotliGet16BitsUnmasked(br), table, br); +} + +/* Same as DecodeSymbol, but it is known that there is less than 15 bits of + input are currently available. */ +static BROTLI_NOINLINE BROTLI_BOOL SafeDecodeSymbol( + const HuffmanCode* table, BrotliBitReader* br, brotli_reg_t* result) { + brotli_reg_t val; + brotli_reg_t available_bits = BrotliGetAvailableBits(br); + BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table); + if (available_bits == 0) { + if (BROTLI_HC_FAST_LOAD_BITS(table) == 0) { + *result = BROTLI_HC_FAST_LOAD_VALUE(table); + return BROTLI_TRUE; + } + return BROTLI_FALSE; /* No valid bits at all. */ + } + val = BrotliGetBitsUnmasked(br); + BROTLI_HC_ADJUST_TABLE_INDEX(table, val & HUFFMAN_TABLE_MASK); + if (BROTLI_HC_FAST_LOAD_BITS(table) <= HUFFMAN_TABLE_BITS) { + if (BROTLI_HC_FAST_LOAD_BITS(table) <= available_bits) { + BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(table)); + *result = BROTLI_HC_FAST_LOAD_VALUE(table); + return BROTLI_TRUE; + } else { + return BROTLI_FALSE; /* Not enough bits for the first level. */ + } + } + if (available_bits <= HUFFMAN_TABLE_BITS) { + return BROTLI_FALSE; /* Not enough bits to move to the second level. */ + } + + /* Speculatively drop HUFFMAN_TABLE_BITS. */ + val = (val & BitMask(BROTLI_HC_FAST_LOAD_BITS(table))) >> HUFFMAN_TABLE_BITS; + available_bits -= HUFFMAN_TABLE_BITS; + BROTLI_HC_ADJUST_TABLE_INDEX(table, BROTLI_HC_FAST_LOAD_VALUE(table) + val); + if (available_bits < BROTLI_HC_FAST_LOAD_BITS(table)) { + return BROTLI_FALSE; /* Not enough bits for the second level. */ + } + + BrotliDropBits(br, HUFFMAN_TABLE_BITS + BROTLI_HC_FAST_LOAD_BITS(table)); + *result = BROTLI_HC_FAST_LOAD_VALUE(table); + return BROTLI_TRUE; +} + +static BROTLI_INLINE BROTLI_BOOL SafeReadSymbol( + const HuffmanCode* table, BrotliBitReader* br, brotli_reg_t* result) { + brotli_reg_t val; + if (BROTLI_PREDICT_TRUE(BrotliSafeGetBits(br, 15, &val))) { + *result = DecodeSymbol(val, table, br); + return BROTLI_TRUE; + } + return SafeDecodeSymbol(table, br, result); +} + +/* Makes a look-up in first level Huffman table. Peeks 8 bits. */ +static BROTLI_INLINE void PreloadSymbol(int safe, + const HuffmanCode* table, + BrotliBitReader* br, + brotli_reg_t* bits, + brotli_reg_t* value) { + if (safe) { + return; + } + BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table); + BROTLI_HC_ADJUST_TABLE_INDEX(table, BrotliGetBits(br, HUFFMAN_TABLE_BITS)); + *bits = BROTLI_HC_FAST_LOAD_BITS(table); + *value = BROTLI_HC_FAST_LOAD_VALUE(table); +} + +/* Decodes the next Huffman code using data prepared by PreloadSymbol. + Reads 0 - 15 bits. Also peeks 8 following bits. */ +static BROTLI_INLINE brotli_reg_t ReadPreloadedSymbol(const HuffmanCode* table, + BrotliBitReader* br, + brotli_reg_t* bits, + brotli_reg_t* value) { + brotli_reg_t result = *value; + if (BROTLI_PREDICT_FALSE(*bits > HUFFMAN_TABLE_BITS)) { + brotli_reg_t val = BrotliGet16BitsUnmasked(br); + const HuffmanCode* ext = table + (val & HUFFMAN_TABLE_MASK) + *value; + brotli_reg_t mask = BitMask((*bits - HUFFMAN_TABLE_BITS)); + BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(ext); + BrotliDropBits(br, HUFFMAN_TABLE_BITS); + BROTLI_HC_ADJUST_TABLE_INDEX(ext, (val >> HUFFMAN_TABLE_BITS) & mask); + BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(ext)); + result = BROTLI_HC_FAST_LOAD_VALUE(ext); + } else { + BrotliDropBits(br, *bits); + } + PreloadSymbol(0, table, br, bits, value); + return result; +} + +/* Reads up to limit symbols from br and copies them into ringbuffer, + starting from pos. Caller must ensure that there is enough space + for the write. Returns the amount of symbols actually copied. */ +static BROTLI_INLINE int BrotliCopyPreloadedSymbolsToU8(const HuffmanCode* table, + BrotliBitReader* br, + brotli_reg_t* bits, + brotli_reg_t* value, + uint8_t* ringbuffer, + int pos, + const int limit) { + /* Calculate range where CheckInputAmount is always true. + Start with the number of bytes we can read. */ + int64_t new_lim = br->guard_in - br->next_in; + /* Convert to bits, since symbols use variable number of bits. */ + new_lim *= 8; + /* At most 15 bits per symbol, so this is safe. */ + new_lim /= 15; + const int kMaximalOverread = 4; + int pos_limit = limit; + int copies = 0; + if ((new_lim - kMaximalOverread) <= limit) { + // Safe cast, since new_lim is already < num_steps + pos_limit = (int)(new_lim - kMaximalOverread); + } + if (pos_limit < 0) { + pos_limit = 0; + } + copies = pos_limit; + pos_limit += pos; + /* Fast path, caller made sure it is safe to write, + we verified that is is safe to read. */ + for (; pos < pos_limit; pos++) { + BROTLI_DCHECK(BrotliCheckInputAmount(br)); + ringbuffer[pos] = (uint8_t)ReadPreloadedSymbol(table, br, bits, value); + BROTLI_LOG_ARRAY_INDEX(ringbuffer, pos); + } + /* Do the remainder, caller made sure it is safe to write, + we need to bverify that it is safe to read. */ + while (BrotliCheckInputAmount(br) && copies < limit) { + ringbuffer[pos] = (uint8_t)ReadPreloadedSymbol(table, br, bits, value); + BROTLI_LOG_ARRAY_INDEX(ringbuffer, pos); + pos++; + copies++; + } + return copies; +} + +static BROTLI_INLINE brotli_reg_t Log2Floor(brotli_reg_t x) { + brotli_reg_t result = 0; + while (x) { + x >>= 1; + ++result; + } + return result; +} + +/* Reads (s->symbol + 1) symbols. + Totally 1..4 symbols are read, 1..11 bits each. + The list of symbols MUST NOT contain duplicates. */ +static BrotliDecoderErrorCode ReadSimpleHuffmanSymbols( + brotli_reg_t alphabet_size_max, brotli_reg_t alphabet_size_limit, + BrotliDecoderState* s) { + /* max_bits == 1..11; symbol == 0..3; 1..44 bits will be read. */ + BrotliBitReader* br = &s->br; + BrotliMetablockHeaderArena* h = &s->arena.header; + brotli_reg_t max_bits = Log2Floor(alphabet_size_max - 1); + brotli_reg_t i = h->sub_loop_counter; + brotli_reg_t num_symbols = h->symbol; + while (i <= num_symbols) { + brotli_reg_t v; + if (BROTLI_PREDICT_FALSE(!BrotliSafeReadBits(br, max_bits, &v))) { + h->sub_loop_counter = i; + h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_READ; + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + if (v >= alphabet_size_limit) { + return + BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_ALPHABET); + } + h->symbols_lists_array[i] = (uint16_t)v; + BROTLI_LOG_UINT(h->symbols_lists_array[i]); + ++i; + } + + for (i = 0; i < num_symbols; ++i) { + brotli_reg_t k = i + 1; + for (; k <= num_symbols; ++k) { + if (h->symbols_lists_array[i] == h->symbols_lists_array[k]) { + return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_SIMPLE_HUFFMAN_SAME); + } + } + } + + return BROTLI_DECODER_SUCCESS; +} + +/* Process single decoded symbol code length: + A) reset the repeat variable + B) remember code length (if it is not 0) + C) extend corresponding index-chain + D) reduce the Huffman space + E) update the histogram */ +static BROTLI_INLINE void ProcessSingleCodeLength(brotli_reg_t code_len, + brotli_reg_t* symbol, brotli_reg_t* repeat, brotli_reg_t* space, + brotli_reg_t* prev_code_len, uint16_t* symbol_lists, + uint16_t* code_length_histo, int* next_symbol) { + *repeat = 0; + if (code_len != 0) { /* code_len == 1..15 */ + symbol_lists[next_symbol[code_len]] = (uint16_t)(*symbol); + next_symbol[code_len] = (int)(*symbol); + *prev_code_len = code_len; + *space -= 32768U >> code_len; + code_length_histo[code_len]++; + BROTLI_LOG(("[ReadHuffmanCode] code_length[%d] = %d\n", + (int)*symbol, (int)code_len)); + } + (*symbol)++; +} + +/* Process repeated symbol code length. + A) Check if it is the extension of previous repeat sequence; if the decoded + value is not BROTLI_REPEAT_PREVIOUS_CODE_LENGTH, then it is a new + symbol-skip + B) Update repeat variable + C) Check if operation is feasible (fits alphabet) + D) For each symbol do the same operations as in ProcessSingleCodeLength + + PRECONDITION: code_len == BROTLI_REPEAT_PREVIOUS_CODE_LENGTH or + code_len == BROTLI_REPEAT_ZERO_CODE_LENGTH */ +static BROTLI_INLINE void ProcessRepeatedCodeLength(brotli_reg_t code_len, + brotli_reg_t repeat_delta, brotli_reg_t alphabet_size, brotli_reg_t* symbol, + brotli_reg_t* repeat, brotli_reg_t* space, brotli_reg_t* prev_code_len, + brotli_reg_t* repeat_code_len, uint16_t* symbol_lists, + uint16_t* code_length_histo, int* next_symbol) { + brotli_reg_t old_repeat; + brotli_reg_t extra_bits = 3; /* for BROTLI_REPEAT_ZERO_CODE_LENGTH */ + brotli_reg_t new_len = 0; /* for BROTLI_REPEAT_ZERO_CODE_LENGTH */ + if (code_len == BROTLI_REPEAT_PREVIOUS_CODE_LENGTH) { + new_len = *prev_code_len; + extra_bits = 2; + } + if (*repeat_code_len != new_len) { + *repeat = 0; + *repeat_code_len = new_len; + } + old_repeat = *repeat; + if (*repeat > 0) { + *repeat -= 2; + *repeat <<= extra_bits; + } + *repeat += repeat_delta + 3U; + repeat_delta = *repeat - old_repeat; + if (*symbol + repeat_delta > alphabet_size) { + BROTLI_DUMP(); + *symbol = alphabet_size; + *space = 0xFFFFF; + return; + } + BROTLI_LOG(("[ReadHuffmanCode] code_length[%d..%d] = %d\n", + (int)*symbol, (int)(*symbol + repeat_delta - 1), (int)*repeat_code_len)); + if (*repeat_code_len != 0) { + brotli_reg_t last = *symbol + repeat_delta; + int next = next_symbol[*repeat_code_len]; + do { + symbol_lists[next] = (uint16_t)*symbol; + next = (int)*symbol; + } while (++(*symbol) != last); + next_symbol[*repeat_code_len] = next; + *space -= repeat_delta << (15 - *repeat_code_len); + code_length_histo[*repeat_code_len] = + (uint16_t)(code_length_histo[*repeat_code_len] + repeat_delta); + } else { + *symbol += repeat_delta; + } +} + +/* Reads and decodes symbol codelengths. */ +static BrotliDecoderErrorCode ReadSymbolCodeLengths( + brotli_reg_t alphabet_size, BrotliDecoderState* s) { + BrotliBitReader* br = &s->br; + BrotliMetablockHeaderArena* h = &s->arena.header; + brotli_reg_t symbol = h->symbol; + brotli_reg_t repeat = h->repeat; + brotli_reg_t space = h->space; + brotli_reg_t prev_code_len = h->prev_code_len; + brotli_reg_t repeat_code_len = h->repeat_code_len; + uint16_t* symbol_lists = h->symbol_lists; + uint16_t* code_length_histo = h->code_length_histo; + int* next_symbol = h->next_symbol; + if (!BrotliWarmupBitReader(br)) { + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + while (symbol < alphabet_size && space > 0) { + const HuffmanCode* p = h->table; + brotli_reg_t code_len; + BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(p); + if (!BrotliCheckInputAmount(br)) { + h->symbol = symbol; + h->repeat = repeat; + h->prev_code_len = prev_code_len; + h->repeat_code_len = repeat_code_len; + h->space = space; + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + BrotliFillBitWindow16(br); + BROTLI_HC_ADJUST_TABLE_INDEX(p, BrotliGetBitsUnmasked(br) & + BitMask(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH)); + BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p)); /* Use 1..5 bits. */ + code_len = BROTLI_HC_FAST_LOAD_VALUE(p); /* code_len == 0..17 */ + if (code_len < BROTLI_REPEAT_PREVIOUS_CODE_LENGTH) { + ProcessSingleCodeLength(code_len, &symbol, &repeat, &space, + &prev_code_len, symbol_lists, code_length_histo, next_symbol); + } else { /* code_len == 16..17, extra_bits == 2..3 */ + brotli_reg_t extra_bits = + (code_len == BROTLI_REPEAT_PREVIOUS_CODE_LENGTH) ? 2 : 3; + brotli_reg_t repeat_delta = + BrotliGetBitsUnmasked(br) & BitMask(extra_bits); + BrotliDropBits(br, extra_bits); + ProcessRepeatedCodeLength(code_len, repeat_delta, alphabet_size, + &symbol, &repeat, &space, &prev_code_len, &repeat_code_len, + symbol_lists, code_length_histo, next_symbol); + } + } + h->space = space; + return BROTLI_DECODER_SUCCESS; +} + +static BrotliDecoderErrorCode SafeReadSymbolCodeLengths( + brotli_reg_t alphabet_size, BrotliDecoderState* s) { + BrotliBitReader* br = &s->br; + BrotliMetablockHeaderArena* h = &s->arena.header; + BROTLI_BOOL get_byte = BROTLI_FALSE; + while (h->symbol < alphabet_size && h->space > 0) { + const HuffmanCode* p = h->table; + brotli_reg_t code_len; + brotli_reg_t available_bits; + brotli_reg_t bits = 0; + BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(p); + if (get_byte && !BrotliPullByte(br)) return BROTLI_DECODER_NEEDS_MORE_INPUT; + get_byte = BROTLI_FALSE; + available_bits = BrotliGetAvailableBits(br); + if (available_bits != 0) { + bits = (uint32_t)BrotliGetBitsUnmasked(br); + } + BROTLI_HC_ADJUST_TABLE_INDEX(p, + bits & BitMask(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH)); + if (BROTLI_HC_FAST_LOAD_BITS(p) > available_bits) { + get_byte = BROTLI_TRUE; + continue; + } + code_len = BROTLI_HC_FAST_LOAD_VALUE(p); /* code_len == 0..17 */ + if (code_len < BROTLI_REPEAT_PREVIOUS_CODE_LENGTH) { + BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p)); + ProcessSingleCodeLength(code_len, &h->symbol, &h->repeat, &h->space, + &h->prev_code_len, h->symbol_lists, h->code_length_histo, + h->next_symbol); + } else { /* code_len == 16..17, extra_bits == 2..3 */ + brotli_reg_t extra_bits = code_len - 14U; + brotli_reg_t repeat_delta = (bits >> BROTLI_HC_FAST_LOAD_BITS(p)) & + BitMask(extra_bits); + if (available_bits < BROTLI_HC_FAST_LOAD_BITS(p) + extra_bits) { + get_byte = BROTLI_TRUE; + continue; + } + BrotliDropBits(br, BROTLI_HC_FAST_LOAD_BITS(p) + extra_bits); + ProcessRepeatedCodeLength(code_len, repeat_delta, alphabet_size, + &h->symbol, &h->repeat, &h->space, &h->prev_code_len, + &h->repeat_code_len, h->symbol_lists, h->code_length_histo, + h->next_symbol); + } + } + return BROTLI_DECODER_SUCCESS; +} + +/* Reads and decodes 15..18 codes using static prefix code. + Each code is 2..4 bits long. In total 30..72 bits are used. */ +static BrotliDecoderErrorCode ReadCodeLengthCodeLengths(BrotliDecoderState* s) { + BrotliBitReader* br = &s->br; + BrotliMetablockHeaderArena* h = &s->arena.header; + brotli_reg_t num_codes = h->repeat; + brotli_reg_t space = h->space; + brotli_reg_t i = h->sub_loop_counter; + for (; i < BROTLI_CODE_LENGTH_CODES; ++i) { + const uint8_t code_len_idx = kCodeLengthCodeOrder[i]; + brotli_reg_t ix; + brotli_reg_t v; + if (BROTLI_PREDICT_FALSE(!BrotliSafeGetBits(br, 4, &ix))) { + brotli_reg_t available_bits = BrotliGetAvailableBits(br); + if (available_bits != 0) { + ix = BrotliGetBitsUnmasked(br) & 0xF; + } else { + ix = 0; + } + if (kCodeLengthPrefixLength[ix] > available_bits) { + h->sub_loop_counter = i; + h->repeat = num_codes; + h->space = space; + h->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX; + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + } + v = kCodeLengthPrefixValue[ix]; + BrotliDropBits(br, kCodeLengthPrefixLength[ix]); + h->code_length_code_lengths[code_len_idx] = (uint8_t)v; + BROTLI_LOG_ARRAY_INDEX(h->code_length_code_lengths, code_len_idx); + if (v != 0) { + space = space - (32U >> v); + ++num_codes; + ++h->code_length_histo[v]; + if (space - 1U >= 32U) { + /* space is 0 or wrapped around. */ + break; + } + } + } + if (!(num_codes == 1 || space == 0)) { + return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_CL_SPACE); + } + return BROTLI_DECODER_SUCCESS; +} + +/* Decodes the Huffman tables. + There are 2 scenarios: + A) Huffman code contains only few symbols (1..4). Those symbols are read + directly; their code lengths are defined by the number of symbols. + For this scenario 4 - 49 bits will be read. + + B) 2-phase decoding: + B.1) Small Huffman table is decoded; it is specified with code lengths + encoded with predefined entropy code. 32 - 74 bits are used. + B.2) Decoded table is used to decode code lengths of symbols in resulting + Huffman table. In worst case 3520 bits are read. */ +static BrotliDecoderErrorCode ReadHuffmanCode(brotli_reg_t alphabet_size_max, + brotli_reg_t alphabet_size_limit, + HuffmanCode* table, + brotli_reg_t* opt_table_size, + BrotliDecoderState* s) { + BrotliBitReader* br = &s->br; + BrotliMetablockHeaderArena* h = &s->arena.header; + /* State machine. */ + for (;;) { + switch (h->substate_huffman) { + case BROTLI_STATE_HUFFMAN_NONE: + if (!BrotliSafeReadBits(br, 2, &h->sub_loop_counter)) { + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + BROTLI_LOG_UINT(h->sub_loop_counter); + /* The value is used as follows: + 1 for simple code; + 0 for no skipping, 2 skips 2 code lengths, 3 skips 3 code lengths */ + if (h->sub_loop_counter != 1) { + h->space = 32; + h->repeat = 0; /* num_codes */ + memset(&h->code_length_histo[0], 0, sizeof(h->code_length_histo[0]) * + (BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH + 1)); + memset(&h->code_length_code_lengths[0], 0, + sizeof(h->code_length_code_lengths)); + h->substate_huffman = BROTLI_STATE_HUFFMAN_COMPLEX; + continue; + } + /* Fall through. */ + + case BROTLI_STATE_HUFFMAN_SIMPLE_SIZE: + /* Read symbols, codes & code lengths directly. */ + if (!BrotliSafeReadBits(br, 2, &h->symbol)) { /* num_symbols */ + h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_SIZE; + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + h->sub_loop_counter = 0; + /* Fall through. */ + + case BROTLI_STATE_HUFFMAN_SIMPLE_READ: { + BrotliDecoderErrorCode result = + ReadSimpleHuffmanSymbols(alphabet_size_max, alphabet_size_limit, s); + if (result != BROTLI_DECODER_SUCCESS) { + return result; + } + } + /* Fall through. */ + + case BROTLI_STATE_HUFFMAN_SIMPLE_BUILD: { + brotli_reg_t table_size; + if (h->symbol == 3) { + brotli_reg_t bits; + if (!BrotliSafeReadBits(br, 1, &bits)) { + h->substate_huffman = BROTLI_STATE_HUFFMAN_SIMPLE_BUILD; + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + h->symbol += bits; + } + BROTLI_LOG_UINT(h->symbol); + table_size = BrotliBuildSimpleHuffmanTable(table, HUFFMAN_TABLE_BITS, + h->symbols_lists_array, + (uint32_t)h->symbol); + if (opt_table_size) { + *opt_table_size = table_size; + } + h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE; + return BROTLI_DECODER_SUCCESS; + } + + /* Decode Huffman-coded code lengths. */ + case BROTLI_STATE_HUFFMAN_COMPLEX: { + brotli_reg_t i; + BrotliDecoderErrorCode result = ReadCodeLengthCodeLengths(s); + if (result != BROTLI_DECODER_SUCCESS) { + return result; + } + BrotliBuildCodeLengthsHuffmanTable(h->table, + h->code_length_code_lengths, + h->code_length_histo); + memset(&h->code_length_histo[0], 0, sizeof(h->code_length_histo)); + for (i = 0; i <= BROTLI_HUFFMAN_MAX_CODE_LENGTH; ++i) { + h->next_symbol[i] = (int)i - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1); + h->symbol_lists[h->next_symbol[i]] = 0xFFFF; + } + + h->symbol = 0; + h->prev_code_len = BROTLI_INITIAL_REPEATED_CODE_LENGTH; + h->repeat = 0; + h->repeat_code_len = 0; + h->space = 32768; + h->substate_huffman = BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS; + } + /* Fall through. */ + + case BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS: { + brotli_reg_t table_size; + BrotliDecoderErrorCode result = ReadSymbolCodeLengths( + alphabet_size_limit, s); + if (result == BROTLI_DECODER_NEEDS_MORE_INPUT) { + result = SafeReadSymbolCodeLengths(alphabet_size_limit, s); + } + if (result != BROTLI_DECODER_SUCCESS) { + return result; + } + + if (h->space != 0) { + BROTLI_LOG(("[ReadHuffmanCode] space = %d\n", (int)h->space)); + return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_HUFFMAN_SPACE); + } + table_size = BrotliBuildHuffmanTable( + table, HUFFMAN_TABLE_BITS, h->symbol_lists, h->code_length_histo); + if (opt_table_size) { + *opt_table_size = table_size; + } + h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE; + return BROTLI_DECODER_SUCCESS; + } + + default: + return + BROTLI_FAILURE(BROTLI_DECODER_ERROR_UNREACHABLE); /* COV_NF_LINE */ + } + } +} + +/* Decodes a block length by reading 3..39 bits. */ +static BROTLI_INLINE brotli_reg_t ReadBlockLength(const HuffmanCode* table, + BrotliBitReader* br) { + brotli_reg_t code; + brotli_reg_t nbits; + code = ReadSymbol(table, br); + nbits = _kBrotliPrefixCodeRanges[code].nbits; /* nbits == 2..24 */ + return _kBrotliPrefixCodeRanges[code].offset + BrotliReadBits24(br, nbits); +} + +/* WARNING: if state is not BROTLI_STATE_READ_BLOCK_LENGTH_NONE, then + reading can't be continued with ReadBlockLength. */ +static BROTLI_INLINE BROTLI_BOOL SafeReadBlockLength( + BrotliDecoderState* s, brotli_reg_t* result, const HuffmanCode* table, + BrotliBitReader* br) { + brotli_reg_t index; + if (s->substate_read_block_length == BROTLI_STATE_READ_BLOCK_LENGTH_NONE) { + if (!SafeReadSymbol(table, br, &index)) { + return BROTLI_FALSE; + } + } else { + index = s->block_length_index; + } + { + brotli_reg_t bits; + brotli_reg_t nbits = _kBrotliPrefixCodeRanges[index].nbits; + brotli_reg_t offset = _kBrotliPrefixCodeRanges[index].offset; + if (!BrotliSafeReadBits(br, nbits, &bits)) { + s->block_length_index = index; + s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX; + return BROTLI_FALSE; + } + *result = offset + bits; + s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE; + return BROTLI_TRUE; + } +} + +/* Transform: + 1) initialize list L with values 0, 1,... 255 + 2) For each input element X: + 2.1) let Y = L[X] + 2.2) remove X-th element from L + 2.3) prepend Y to L + 2.4) append Y to output + + In most cases max(Y) <= 7, so most of L remains intact. + To reduce the cost of initialization, we reuse L, remember the upper bound + of Y values, and reinitialize only first elements in L. + + Most of input values are 0 and 1. To reduce number of branches, we replace + inner for loop with do-while. */ +static BROTLI_NOINLINE void InverseMoveToFrontTransform( + uint8_t* v, brotli_reg_t v_len, BrotliDecoderState* state) { + /* Reinitialize elements that could have been changed. */ + brotli_reg_t i = 1; + brotli_reg_t upper_bound = state->mtf_upper_bound; + uint32_t* mtf = &state->mtf[1]; /* Make mtf[-1] addressable. */ + uint8_t* mtf_u8 = (uint8_t*)mtf; + /* Load endian-aware constant. */ + const uint8_t b0123[4] = {0, 1, 2, 3}; + uint32_t pattern; + memcpy(&pattern, &b0123, 4); + + /* Initialize list using 4 consequent values pattern. */ + mtf[0] = pattern; + do { + pattern += 0x04040404; /* Advance all 4 values by 4. */ + mtf[i] = pattern; + i++; + } while (i <= upper_bound); + + /* Transform the input. */ + upper_bound = 0; + for (i = 0; i < v_len; ++i) { + int index = v[i]; + uint8_t value = mtf_u8[index]; + upper_bound |= v[i]; + v[i] = value; + mtf_u8[-1] = value; + do { + index--; + mtf_u8[index + 1] = mtf_u8[index]; + } while (index >= 0); + } + /* Remember amount of elements to be reinitialized. */ + state->mtf_upper_bound = upper_bound >> 2; +} + +/* Decodes a series of Huffman table using ReadHuffmanCode function. */ +static BrotliDecoderErrorCode HuffmanTreeGroupDecode( + HuffmanTreeGroup* group, BrotliDecoderState* s) { + BrotliMetablockHeaderArena* h = &s->arena.header; + if (h->substate_tree_group != BROTLI_STATE_TREE_GROUP_LOOP) { + h->next = group->codes; + h->htree_index = 0; + h->substate_tree_group = BROTLI_STATE_TREE_GROUP_LOOP; + } + while (h->htree_index < group->num_htrees) { + brotli_reg_t table_size; + BrotliDecoderErrorCode result = ReadHuffmanCode(group->alphabet_size_max, + group->alphabet_size_limit, h->next, &table_size, s); + if (result != BROTLI_DECODER_SUCCESS) return result; + group->htrees[h->htree_index] = h->next; + h->next += table_size; + ++h->htree_index; + } + h->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE; + return BROTLI_DECODER_SUCCESS; +} + +/* Decodes a context map. + Decoding is done in 4 phases: + 1) Read auxiliary information (6..16 bits) and allocate memory. + In case of trivial context map, decoding is finished at this phase. + 2) Decode Huffman table using ReadHuffmanCode function. + This table will be used for reading context map items. + 3) Read context map items; "0" values could be run-length encoded. + 4) Optionally, apply InverseMoveToFront transform to the resulting map. */ +static BrotliDecoderErrorCode DecodeContextMap(brotli_reg_t context_map_size, + brotli_reg_t* num_htrees, + uint8_t** context_map_arg, + BrotliDecoderState* s) { + BrotliBitReader* br = &s->br; + BrotliDecoderErrorCode result = BROTLI_DECODER_SUCCESS; + BrotliMetablockHeaderArena* h = &s->arena.header; + + switch ((int)h->substate_context_map) { + case BROTLI_STATE_CONTEXT_MAP_NONE: + result = DecodeVarLenUint8(s, br, num_htrees); + if (result != BROTLI_DECODER_SUCCESS) { + return result; + } + (*num_htrees)++; + h->context_index = 0; + BROTLI_LOG_UINT(context_map_size); + BROTLI_LOG_UINT(*num_htrees); + *context_map_arg = + (uint8_t*)BROTLI_DECODER_ALLOC(s, (size_t)context_map_size); + if (*context_map_arg == 0) { + return BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MAP); + } + if (*num_htrees <= 1) { + memset(*context_map_arg, 0, (size_t)context_map_size); + return BROTLI_DECODER_SUCCESS; + } + h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_READ_PREFIX; + /* Fall through. */ + + case BROTLI_STATE_CONTEXT_MAP_READ_PREFIX: { + brotli_reg_t bits; + /* In next stage ReadHuffmanCode uses at least 4 bits, so it is safe + to peek 4 bits ahead. */ + if (!BrotliSafeGetBits(br, 5, &bits)) { + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + if ((bits & 1) != 0) { /* Use RLE for zeros. */ + h->max_run_length_prefix = (bits >> 1) + 1; + BrotliDropBits(br, 5); + } else { + h->max_run_length_prefix = 0; + BrotliDropBits(br, 1); + } + BROTLI_LOG_UINT(h->max_run_length_prefix); + h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_HUFFMAN; + } + /* Fall through. */ + + case BROTLI_STATE_CONTEXT_MAP_HUFFMAN: { + brotli_reg_t alphabet_size = *num_htrees + h->max_run_length_prefix; + result = ReadHuffmanCode(alphabet_size, alphabet_size, + h->context_map_table, NULL, s); + if (result != BROTLI_DECODER_SUCCESS) return result; + h->code = 0xFFFF; + h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_DECODE; + } + /* Fall through. */ + + case BROTLI_STATE_CONTEXT_MAP_DECODE: { + brotli_reg_t context_index = h->context_index; + brotli_reg_t max_run_length_prefix = h->max_run_length_prefix; + uint8_t* context_map = *context_map_arg; + brotli_reg_t code = h->code; + BROTLI_BOOL skip_preamble = (code != 0xFFFF); + while (context_index < context_map_size || skip_preamble) { + if (!skip_preamble) { + if (!SafeReadSymbol(h->context_map_table, br, &code)) { + h->code = 0xFFFF; + h->context_index = context_index; + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + BROTLI_LOG_UINT(code); + + if (code == 0) { + context_map[context_index++] = 0; + continue; + } + if (code > max_run_length_prefix) { + context_map[context_index++] = + (uint8_t)(code - max_run_length_prefix); + continue; + } + } else { + skip_preamble = BROTLI_FALSE; + } + /* RLE sub-stage. */ + { + brotli_reg_t reps; + if (!BrotliSafeReadBits(br, code, &reps)) { + h->code = code; + h->context_index = context_index; + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + reps += (brotli_reg_t)1U << code; + BROTLI_LOG_UINT(reps); + if (context_index + reps > context_map_size) { + return + BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_CONTEXT_MAP_REPEAT); + } + do { + context_map[context_index++] = 0; + } while (--reps); + } + } + } + /* Fall through. */ + + case BROTLI_STATE_CONTEXT_MAP_TRANSFORM: { + brotli_reg_t bits; + if (!BrotliSafeReadBits(br, 1, &bits)) { + h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_TRANSFORM; + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + if (bits != 0) { + InverseMoveToFrontTransform(*context_map_arg, context_map_size, s); + } + h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE; + return BROTLI_DECODER_SUCCESS; + } + + default: + return + BROTLI_FAILURE(BROTLI_DECODER_ERROR_UNREACHABLE); /* COV_NF_LINE */ + } +} + +/* Decodes a command or literal and updates block type ring-buffer. + Reads 3..54 bits. */ +static BROTLI_INLINE BROTLI_BOOL DecodeBlockTypeAndLength( + int safe, BrotliDecoderState* s, int tree_type) { + brotli_reg_t max_block_type = s->num_block_types[tree_type]; + const HuffmanCode* type_tree = &s->block_type_trees[ + tree_type * BROTLI_HUFFMAN_MAX_SIZE_258]; + const HuffmanCode* len_tree = &s->block_len_trees[ + tree_type * BROTLI_HUFFMAN_MAX_SIZE_26]; + BrotliBitReader* br = &s->br; + brotli_reg_t* ringbuffer = &s->block_type_rb[tree_type * 2]; + brotli_reg_t block_type; + if (max_block_type <= 1) { + return BROTLI_FALSE; + } + + /* Read 0..15 + 3..39 bits. */ + if (!safe) { + block_type = ReadSymbol(type_tree, br); + s->block_length[tree_type] = ReadBlockLength(len_tree, br); + } else { + BrotliBitReaderState memento; + BrotliBitReaderSaveState(br, &memento); + if (!SafeReadSymbol(type_tree, br, &block_type)) return BROTLI_FALSE; + if (!SafeReadBlockLength(s, &s->block_length[tree_type], len_tree, br)) { + s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE; + BrotliBitReaderRestoreState(br, &memento); + return BROTLI_FALSE; + } + } + + if (block_type == 1) { + block_type = ringbuffer[1] + 1; + } else if (block_type == 0) { + block_type = ringbuffer[0]; + } else { + block_type -= 2; + } + if (block_type >= max_block_type) { + block_type -= max_block_type; + } + ringbuffer[0] = ringbuffer[1]; + ringbuffer[1] = block_type; + return BROTLI_TRUE; +} + +static BROTLI_INLINE void DetectTrivialLiteralBlockTypes( + BrotliDecoderState* s) { + size_t i; + for (i = 0; i < 8; ++i) s->trivial_literal_contexts[i] = 0; + for (i = 0; i < s->num_block_types[0]; i++) { + size_t offset = i << BROTLI_LITERAL_CONTEXT_BITS; + size_t error = 0; + size_t sample = s->context_map[offset]; + size_t j; + for (j = 0; j < (1u << BROTLI_LITERAL_CONTEXT_BITS);) { + /* NOLINTNEXTLINE(bugprone-macro-repeated-side-effects) */ + BROTLI_REPEAT_4({ error |= s->context_map[offset + j++] ^ sample; }) + } + if (error == 0) { + s->trivial_literal_contexts[i >> 5] |= 1u << (i & 31); + } + } +} + +static BROTLI_INLINE void PrepareLiteralDecoding(BrotliDecoderState* s) { + uint8_t context_mode; + size_t trivial; + brotli_reg_t block_type = s->block_type_rb[1]; + brotli_reg_t context_offset = block_type << BROTLI_LITERAL_CONTEXT_BITS; + s->context_map_slice = s->context_map + context_offset; + trivial = s->trivial_literal_contexts[block_type >> 5]; + s->trivial_literal_context = (trivial >> (block_type & 31)) & 1; + s->literal_htree = s->literal_hgroup.htrees[s->context_map_slice[0]]; + context_mode = s->context_modes[block_type] & 3; + s->context_lookup = BROTLI_CONTEXT_LUT(context_mode); +} + +/* Decodes the block type and updates the state for literal context. + Reads 3..54 bits. */ +static BROTLI_INLINE BROTLI_BOOL DecodeLiteralBlockSwitchInternal( + int safe, BrotliDecoderState* s) { + if (!DecodeBlockTypeAndLength(safe, s, 0)) { + return BROTLI_FALSE; + } + PrepareLiteralDecoding(s); + return BROTLI_TRUE; +} + +static void BROTLI_NOINLINE DecodeLiteralBlockSwitch(BrotliDecoderState* s) { + DecodeLiteralBlockSwitchInternal(0, s); +} + +static BROTLI_BOOL BROTLI_NOINLINE SafeDecodeLiteralBlockSwitch( + BrotliDecoderState* s) { + return DecodeLiteralBlockSwitchInternal(1, s); +} + +/* Block switch for insert/copy length. + Reads 3..54 bits. */ +static BROTLI_INLINE BROTLI_BOOL DecodeCommandBlockSwitchInternal( + int safe, BrotliDecoderState* s) { + if (!DecodeBlockTypeAndLength(safe, s, 1)) { + return BROTLI_FALSE; + } + s->htree_command = s->insert_copy_hgroup.htrees[s->block_type_rb[3]]; + return BROTLI_TRUE; +} + +static void BROTLI_NOINLINE DecodeCommandBlockSwitch(BrotliDecoderState* s) { + DecodeCommandBlockSwitchInternal(0, s); +} + +static BROTLI_BOOL BROTLI_NOINLINE SafeDecodeCommandBlockSwitch( + BrotliDecoderState* s) { + return DecodeCommandBlockSwitchInternal(1, s); +} + +/* Block switch for distance codes. + Reads 3..54 bits. */ +static BROTLI_INLINE BROTLI_BOOL DecodeDistanceBlockSwitchInternal( + int safe, BrotliDecoderState* s) { + if (!DecodeBlockTypeAndLength(safe, s, 2)) { + return BROTLI_FALSE; + } + s->dist_context_map_slice = s->dist_context_map + + (s->block_type_rb[5] << BROTLI_DISTANCE_CONTEXT_BITS); + s->dist_htree_index = s->dist_context_map_slice[s->distance_context]; + return BROTLI_TRUE; +} + +static void BROTLI_NOINLINE DecodeDistanceBlockSwitch(BrotliDecoderState* s) { + DecodeDistanceBlockSwitchInternal(0, s); +} + +static BROTLI_BOOL BROTLI_NOINLINE SafeDecodeDistanceBlockSwitch( + BrotliDecoderState* s) { + return DecodeDistanceBlockSwitchInternal(1, s); +} + +static size_t UnwrittenBytes(const BrotliDecoderState* s, BROTLI_BOOL wrap) { + size_t pos = wrap && s->pos > s->ringbuffer_size ? + (size_t)s->ringbuffer_size : (size_t)(s->pos); + size_t partial_pos_rb = (s->rb_roundtrips * (size_t)s->ringbuffer_size) + pos; + return partial_pos_rb - s->partial_pos_out; +} + +/* Dumps output. + Returns BROTLI_DECODER_NEEDS_MORE_OUTPUT only if there is more output to push + and either ring-buffer is as big as window size, or |force| is true. */ +static BrotliDecoderErrorCode BROTLI_NOINLINE WriteRingBuffer( + BrotliDecoderState* s, size_t* available_out, uint8_t** next_out, + size_t* total_out, BROTLI_BOOL force) { + uint8_t* start = + s->ringbuffer + (s->partial_pos_out & (size_t)s->ringbuffer_mask); + size_t to_write = UnwrittenBytes(s, BROTLI_TRUE); + size_t num_written = *available_out; + if (num_written > to_write) { + num_written = to_write; + } + if (s->meta_block_remaining_len < 0) { + return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_1); + } + if (next_out && !*next_out) { + *next_out = start; + } else { + if (next_out) { + memcpy(*next_out, start, num_written); + *next_out += num_written; + } + } + *available_out -= num_written; + BROTLI_LOG_UINT(to_write); + BROTLI_LOG_UINT(num_written); + s->partial_pos_out += num_written; + if (total_out) { + *total_out = s->partial_pos_out; + } + if (num_written < to_write) { + if (s->ringbuffer_size == (1 << s->window_bits) || force) { + return BROTLI_DECODER_NEEDS_MORE_OUTPUT; + } else { + return BROTLI_DECODER_SUCCESS; + } + } + /* Wrap ring buffer only if it has reached its maximal size. */ + if (s->ringbuffer_size == (1 << s->window_bits) && + s->pos >= s->ringbuffer_size) { + s->pos -= s->ringbuffer_size; + s->rb_roundtrips++; + s->should_wrap_ringbuffer = (size_t)s->pos != 0 ? 1 : 0; + } + return BROTLI_DECODER_SUCCESS; +} + +static void BROTLI_NOINLINE WrapRingBuffer(BrotliDecoderState* s) { + if (s->should_wrap_ringbuffer) { + memcpy(s->ringbuffer, s->ringbuffer_end, (size_t)s->pos); + s->should_wrap_ringbuffer = 0; + } +} + +/* Allocates ring-buffer. + + s->ringbuffer_size MUST be updated by BrotliCalculateRingBufferSize before + this function is called. + + Last two bytes of ring-buffer are initialized to 0, so context calculation + could be done uniformly for the first two and all other positions. */ +static BROTLI_BOOL BROTLI_NOINLINE BrotliEnsureRingBuffer( + BrotliDecoderState* s) { + uint8_t* old_ringbuffer = s->ringbuffer; + if (s->ringbuffer_size == s->new_ringbuffer_size) { + return BROTLI_TRUE; + } + + s->ringbuffer = (uint8_t*)BROTLI_DECODER_ALLOC(s, + (size_t)(s->new_ringbuffer_size) + kRingBufferWriteAheadSlack); + if (s->ringbuffer == 0) { + /* Restore previous value. */ + s->ringbuffer = old_ringbuffer; + return BROTLI_FALSE; + } + s->ringbuffer[s->new_ringbuffer_size - 2] = 0; + s->ringbuffer[s->new_ringbuffer_size - 1] = 0; + + if (!!old_ringbuffer) { + memcpy(s->ringbuffer, old_ringbuffer, (size_t)s->pos); + BROTLI_DECODER_FREE(s, old_ringbuffer); + } + + s->ringbuffer_size = s->new_ringbuffer_size; + s->ringbuffer_mask = s->new_ringbuffer_size - 1; + s->ringbuffer_end = s->ringbuffer + s->ringbuffer_size; + + return BROTLI_TRUE; +} + +static BrotliDecoderErrorCode BROTLI_NOINLINE +SkipMetadataBlock(BrotliDecoderState* s) { + BrotliBitReader* br = &s->br; + int nbytes; + + if (s->meta_block_remaining_len == 0) { + return BROTLI_DECODER_SUCCESS; + } + + BROTLI_DCHECK((BrotliGetAvailableBits(br) & 7) == 0); + + /* Drain accumulator. */ + if (BrotliGetAvailableBits(br) >= 8) { + uint8_t buffer[8]; + nbytes = (int)(BrotliGetAvailableBits(br)) >> 3; + BROTLI_DCHECK(nbytes <= 8); + if (nbytes > s->meta_block_remaining_len) { + nbytes = s->meta_block_remaining_len; + } + BrotliCopyBytes(buffer, br, (size_t)nbytes); + if (s->metadata_chunk_func) { + s->metadata_chunk_func(s->metadata_callback_opaque, buffer, + (size_t)nbytes); + } + s->meta_block_remaining_len -= nbytes; + if (s->meta_block_remaining_len == 0) { + return BROTLI_DECODER_SUCCESS; + } + } + + /* Direct access to metadata is possible. */ + nbytes = (int)BrotliGetRemainingBytes(br); + if (nbytes > s->meta_block_remaining_len) { + nbytes = s->meta_block_remaining_len; + } + if (nbytes > 0) { + if (s->metadata_chunk_func) { + s->metadata_chunk_func(s->metadata_callback_opaque, br->next_in, + (size_t)nbytes); + } + BrotliDropBytes(br, (size_t)nbytes); + s->meta_block_remaining_len -= nbytes; + if (s->meta_block_remaining_len == 0) { + return BROTLI_DECODER_SUCCESS; + } + } + + BROTLI_DCHECK(BrotliGetRemainingBytes(br) == 0); + + return BROTLI_DECODER_NEEDS_MORE_INPUT; +} + +static BrotliDecoderErrorCode BROTLI_NOINLINE CopyUncompressedBlockToOutput( + size_t* available_out, uint8_t** next_out, size_t* total_out, + BrotliDecoderState* s) { + /* TODO(eustas): avoid allocation for single uncompressed block. */ + if (!BrotliEnsureRingBuffer(s)) { + return BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_1); + } + + /* State machine */ + for (;;) { + switch (s->substate_uncompressed) { + case BROTLI_STATE_UNCOMPRESSED_NONE: { + int nbytes = (int)BrotliGetRemainingBytes(&s->br); + if (nbytes > s->meta_block_remaining_len) { + nbytes = s->meta_block_remaining_len; + } + if (s->pos + nbytes > s->ringbuffer_size) { + nbytes = s->ringbuffer_size - s->pos; + } + /* Copy remaining bytes from s->br.buf_ to ring-buffer. */ + BrotliCopyBytes(&s->ringbuffer[s->pos], &s->br, (size_t)nbytes); + s->pos += nbytes; + s->meta_block_remaining_len -= nbytes; + if (s->pos < 1 << s->window_bits) { + if (s->meta_block_remaining_len == 0) { + return BROTLI_DECODER_SUCCESS; + } + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_WRITE; + } + /* Fall through. */ + + case BROTLI_STATE_UNCOMPRESSED_WRITE: { + BrotliDecoderErrorCode result; + result = WriteRingBuffer( + s, available_out, next_out, total_out, BROTLI_FALSE); + if (result != BROTLI_DECODER_SUCCESS) { + return result; + } + if (s->ringbuffer_size == 1 << s->window_bits) { + s->max_distance = s->max_backward_distance; + } + s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE; + break; + } + } + } + BROTLI_DCHECK(0); /* Unreachable */ +} + +static BROTLI_BOOL AttachCompoundDictionary( + BrotliDecoderState* state, const uint8_t* data, size_t size) { + BrotliDecoderCompoundDictionary* addon = state->compound_dictionary; + if (state->state != BROTLI_STATE_UNINITED) return BROTLI_FALSE; + if (!addon) { + addon = (BrotliDecoderCompoundDictionary*)BROTLI_DECODER_ALLOC( + state, sizeof(BrotliDecoderCompoundDictionary)); + if (!addon) return BROTLI_FALSE; + addon->num_chunks = 0; + addon->total_size = 0; + addon->br_length = 0; + addon->br_copied = 0; + addon->block_bits = -1; + addon->chunk_offsets[0] = 0; + state->compound_dictionary = addon; + } + if (addon->num_chunks == 15) return BROTLI_FALSE; + addon->chunks[addon->num_chunks] = data; + addon->num_chunks++; + addon->total_size += (int)size; + addon->chunk_offsets[addon->num_chunks] = addon->total_size; + return BROTLI_TRUE; +} + +static void EnsureCompoundDictionaryInitialized(BrotliDecoderState* state) { + BrotliDecoderCompoundDictionary* addon = state->compound_dictionary; + /* 256 = (1 << 8) slots in block map. */ + int block_bits = 8; + int cursor = 0; + int index = 0; + if (addon->block_bits != -1) return; + while (((addon->total_size - 1) >> block_bits) != 0) block_bits++; + block_bits -= 8; + addon->block_bits = block_bits; + while (cursor < addon->total_size) { + while (addon->chunk_offsets[index + 1] < cursor) index++; + addon->block_map[cursor >> block_bits] = (uint8_t)index; + cursor += 1 << block_bits; + } +} + +static BROTLI_BOOL InitializeCompoundDictionaryCopy(BrotliDecoderState* s, + int address, int length) { + BrotliDecoderCompoundDictionary* addon = s->compound_dictionary; + int index; + EnsureCompoundDictionaryInitialized(s); + index = addon->block_map[address >> addon->block_bits]; + while (address >= addon->chunk_offsets[index + 1]) index++; + if (addon->total_size < address + length) return BROTLI_FALSE; + /* Update the recent distances cache. */ + s->dist_rb[s->dist_rb_idx & 3] = s->distance_code; + ++s->dist_rb_idx; + s->meta_block_remaining_len -= length; + addon->br_index = index; + addon->br_offset = address - addon->chunk_offsets[index]; + addon->br_length = length; + addon->br_copied = 0; + return BROTLI_TRUE; +} + +static int GetCompoundDictionarySize(BrotliDecoderState* s) { + return s->compound_dictionary ? s->compound_dictionary->total_size : 0; +} + +static int CopyFromCompoundDictionary(BrotliDecoderState* s, int pos) { + BrotliDecoderCompoundDictionary* addon = s->compound_dictionary; + int orig_pos = pos; + while (addon->br_length != addon->br_copied) { + uint8_t* copy_dst = &s->ringbuffer[pos]; + const uint8_t* copy_src = + addon->chunks[addon->br_index] + addon->br_offset; + int space = s->ringbuffer_size - pos; + int rem_chunk_length = (addon->chunk_offsets[addon->br_index + 1] - + addon->chunk_offsets[addon->br_index]) - addon->br_offset; + int length = addon->br_length - addon->br_copied; + if (length > rem_chunk_length) length = rem_chunk_length; + if (length > space) length = space; + memcpy(copy_dst, copy_src, (size_t)length); + pos += length; + addon->br_offset += length; + addon->br_copied += length; + if (length == rem_chunk_length) { + addon->br_index++; + addon->br_offset = 0; + } + if (pos == s->ringbuffer_size) break; + } + return pos - orig_pos; +} + +BROTLI_BOOL BrotliDecoderAttachDictionary( + BrotliDecoderState* state, BrotliSharedDictionaryType type, + size_t data_size, const uint8_t data[BROTLI_ARRAY_PARAM(data_size)]) { + brotli_reg_t i; + brotli_reg_t num_prefix_before = state->dictionary->num_prefix; + if (state->state != BROTLI_STATE_UNINITED) return BROTLI_FALSE; + if (!BrotliSharedDictionaryAttach(state->dictionary, type, data_size, data)) { + return BROTLI_FALSE; + } + for (i = num_prefix_before; i < state->dictionary->num_prefix; i++) { + if (!AttachCompoundDictionary( + state, state->dictionary->prefix[i], + state->dictionary->prefix_size[i])) { + return BROTLI_FALSE; + } + } + return BROTLI_TRUE; +} + +/* Calculates the smallest feasible ring buffer. + + If we know the data size is small, do not allocate more ring buffer + size than needed to reduce memory usage. + + When this method is called, metablock size and flags MUST be decoded. */ +static void BROTLI_NOINLINE BrotliCalculateRingBufferSize( + BrotliDecoderState* s) { + int window_size = 1 << s->window_bits; + int new_ringbuffer_size = window_size; + /* We need at least 2 bytes of ring buffer size to get the last two + bytes for context from there */ + int min_size = s->ringbuffer_size ? s->ringbuffer_size : 1024; + int output_size; + + /* If maximum is already reached, no further extension is retired. */ + if (s->ringbuffer_size == window_size) { + return; + } + + /* Metadata blocks does not touch ring buffer. */ + if (s->is_metadata) { + return; + } + + if (!s->ringbuffer) { + output_size = 0; + } else { + output_size = s->pos; + } + output_size += s->meta_block_remaining_len; + min_size = min_size < output_size ? output_size : min_size; + + if (!!s->canny_ringbuffer_allocation) { + /* Reduce ring buffer size to save memory when server is unscrupulous. + In worst case memory usage might be 1.5x bigger for a short period of + ring buffer reallocation. */ + while ((new_ringbuffer_size >> 1) >= min_size) { + new_ringbuffer_size >>= 1; + } + } + + s->new_ringbuffer_size = new_ringbuffer_size; +} + +/* Reads 1..256 2-bit context modes. */ +static BrotliDecoderErrorCode ReadContextModes(BrotliDecoderState* s) { + BrotliBitReader* br = &s->br; + int i = s->loop_counter; + + while (i < (int)s->num_block_types[0]) { + brotli_reg_t bits; + if (!BrotliSafeReadBits(br, 2, &bits)) { + s->loop_counter = i; + return BROTLI_DECODER_NEEDS_MORE_INPUT; + } + s->context_modes[i] = (uint8_t)bits; + BROTLI_LOG_ARRAY_INDEX(s->context_modes, i); + i++; + } + return BROTLI_DECODER_SUCCESS; +} + +static BROTLI_INLINE void TakeDistanceFromRingBuffer(BrotliDecoderState* s) { + int offset = s->distance_code - 3; + if (s->distance_code <= 3) { + /* Compensate double distance-ring-buffer roll for dictionary items. */ + s->distance_context = 1 >> s->distance_code; + s->distance_code = s->dist_rb[(s->dist_rb_idx - offset) & 3]; + s->dist_rb_idx -= s->distance_context; + } else { + int index_delta = 3; + int delta; + int base = s->distance_code - 10; + if (s->distance_code < 10) { + base = s->distance_code - 4; + } else { + index_delta = 2; + } + /* Unpack one of six 4-bit values. */ + delta = ((0x605142 >> (4 * base)) & 0xF) - 3; + s->distance_code = s->dist_rb[(s->dist_rb_idx + index_delta) & 0x3] + delta; + if (s->distance_code <= 0) { + /* A huge distance will cause a BROTLI_FAILURE() soon. + This is a little faster than failing here. */ + s->distance_code = 0x7FFFFFFF; + } + } +} + +static BROTLI_INLINE BROTLI_BOOL SafeReadBits( + BrotliBitReader* const br, brotli_reg_t n_bits, brotli_reg_t* val) { + if (n_bits != 0) { + return BrotliSafeReadBits(br, n_bits, val); + } else { + *val = 0; + return BROTLI_TRUE; + } +} + +static BROTLI_INLINE BROTLI_BOOL SafeReadBits32( + BrotliBitReader* const br, brotli_reg_t n_bits, brotli_reg_t* val) { + if (n_bits != 0) { + return BrotliSafeReadBits32(br, n_bits, val); + } else { + *val = 0; + return BROTLI_TRUE; + } +} + +/* + RFC 7932 Section 4 with "..." shortenings and "[]" emendations. + + Each distance ... is represented with a pair ... + The distance code is encoded using a prefix code... The number of extra bits + can be 0..24... Two additional parameters: NPOSTFIX (0..3), and ... + NDIRECT (0..120) ... are encoded in the meta-block header... + + The first 16 distance symbols ... reference past distances... ring buffer ... + Next NDIRECT distance symbols ... represent distances from 1 to NDIRECT... + [For] distance symbols 16 + NDIRECT and greater ... the number of extra bits + ... is given by the following formula: + + [ xcode = dcode - NDIRECT - 16 ] + ndistbits = 1 + [ xcode ] >> (NPOSTFIX + 1) + + ... +*/ + +/* + RFC 7932 Section 9.2 with "..." shortenings and "[]" emendations. + + ... to get the actual value of the parameter NDIRECT, left-shift this + four-bit number by NPOSTFIX bits ... +*/ + +/* Remaining formulas from RFC 7932 Section 4 could be rewritten as following: + + alphabet_size = 16 + NDIRECT + (max_distbits << (NPOSTFIX + 1)) + + half = ((xcode >> NPOSTFIX) & 1) << ndistbits + postfix = xcode & ((1 << NPOSTFIX) - 1) + range_start = 2 * (1 << ndistbits - 1 - 1) + + distance = (range_start + half + extra) << NPOSTFIX + postfix + NDIRECT + 1 + + NB: ndistbits >= 1 -> range_start >= 0 + NB: range_start has factor 2, as the range is covered by 2 "halves" + NB: extra -1 offset in range_start formula covers the absence of + ndistbits = 0 case + NB: when NPOSTFIX = 0, NDIRECT is not greater than 15 + + In other words, xcode has the following binary structure - XXXHPPP: + - XXX represent the number of extra distance bits + - H selects upper / lower range of distances + - PPP represent "postfix" + + "Regular" distance encoding has NPOSTFIX = 0; omitting the postfix part + simplifies distance calculation. + + Using NPOSTFIX > 0 allows cheaper encoding of regular structures, e.g. where + most of distances have the same reminder of division by 2/4/8. For example, + the table of int32_t values that come from different sources; if it is likely + that 3 highest bytes of values from the same source are the same, then + copy distance often looks like 4x + y. + + Distance calculation could be rewritten to: + + ndistbits = NDISTBITS(NDIRECT, NPOSTFIX)[dcode] + distance = OFFSET(NDIRECT, NPOSTFIX)[dcode] + extra << NPOSTFIX + + NDISTBITS and OFFSET could be pre-calculated, as NDIRECT and NPOSTFIX could + change only once per meta-block. +*/ + +/* Calculates distance lookup table. + NB: it is possible to have all 64 tables precalculated. */ +static void CalculateDistanceLut(BrotliDecoderState* s) { + BrotliMetablockBodyArena* b = &s->arena.body; + brotli_reg_t npostfix = s->distance_postfix_bits; + brotli_reg_t ndirect = s->num_direct_distance_codes; + brotli_reg_t alphabet_size_limit = s->distance_hgroup.alphabet_size_limit; + brotli_reg_t postfix = (brotli_reg_t)1u << npostfix; + brotli_reg_t j; + brotli_reg_t bits = 1; + brotli_reg_t half = 0; + + /* Skip short codes. */ + brotli_reg_t i = BROTLI_NUM_DISTANCE_SHORT_CODES; + + /* Fill direct codes. */ + for (j = 0; j < ndirect; ++j) { + b->dist_extra_bits[i] = 0; + b->dist_offset[i] = j + 1; + ++i; + } + + /* Fill regular distance codes. */ + while (i < alphabet_size_limit) { + brotli_reg_t base = ndirect + ((((2 + half) << bits) - 4) << npostfix) + 1; + /* Always fill the complete group. */ + for (j = 0; j < postfix; ++j) { + b->dist_extra_bits[i] = (uint8_t)bits; + b->dist_offset[i] = base + j; + ++i; + } + bits = bits + half; + half = half ^ 1; + } +} + +/* Precondition: s->distance_code < 0. */ +static BROTLI_INLINE BROTLI_BOOL ReadDistanceInternal( + int safe, BrotliDecoderState* s, BrotliBitReader* br) { + BrotliMetablockBodyArena* b = &s->arena.body; + brotli_reg_t code; + brotli_reg_t bits; + BrotliBitReaderState memento; + HuffmanCode* distance_tree = s->distance_hgroup.htrees[s->dist_htree_index]; + if (!safe) { + code = ReadSymbol(distance_tree, br); + } else { + BrotliBitReaderSaveState(br, &memento); + if (!SafeReadSymbol(distance_tree, br, &code)) { + return BROTLI_FALSE; + } + } + --s->block_length[2]; + /* Convert the distance code to the actual distance by possibly + looking up past distances from the s->dist_rb. */ + s->distance_context = 0; + if ((code & ~0xFu) == 0) { + s->distance_code = (int)code; + TakeDistanceFromRingBuffer(s); + return BROTLI_TRUE; + } + if (!safe) { + bits = BrotliReadBits32(br, b->dist_extra_bits[code]); + } else { + if (!SafeReadBits32(br, b->dist_extra_bits[code], &bits)) { + ++s->block_length[2]; + BrotliBitReaderRestoreState(br, &memento); + return BROTLI_FALSE; + } + } + s->distance_code = + (int)(b->dist_offset[code] + (bits << s->distance_postfix_bits)); + return BROTLI_TRUE; +} + +static BROTLI_INLINE void ReadDistance( + BrotliDecoderState* s, BrotliBitReader* br) { + ReadDistanceInternal(0, s, br); +} + +static BROTLI_INLINE BROTLI_BOOL SafeReadDistance( + BrotliDecoderState* s, BrotliBitReader* br) { + return ReadDistanceInternal(1, s, br); +} + +static BROTLI_INLINE BROTLI_BOOL ReadCommandInternal( + int safe, BrotliDecoderState* s, BrotliBitReader* br, int* insert_length) { + brotli_reg_t cmd_code; + brotli_reg_t insert_len_extra = 0; + brotli_reg_t copy_length; + CmdLutElement v; + BrotliBitReaderState memento; + if (!safe) { + cmd_code = ReadSymbol(s->htree_command, br); + } else { + BrotliBitReaderSaveState(br, &memento); + if (!SafeReadSymbol(s->htree_command, br, &cmd_code)) { + return BROTLI_FALSE; + } + } + v = kCmdLut[cmd_code]; + s->distance_code = v.distance_code; + s->distance_context = v.context; + s->dist_htree_index = s->dist_context_map_slice[s->distance_context]; + *insert_length = v.insert_len_offset; + if (!safe) { + if (BROTLI_PREDICT_FALSE(v.insert_len_extra_bits != 0)) { + insert_len_extra = BrotliReadBits24(br, v.insert_len_extra_bits); + } + copy_length = BrotliReadBits24(br, v.copy_len_extra_bits); + } else { + if (!SafeReadBits(br, v.insert_len_extra_bits, &insert_len_extra) || + !SafeReadBits(br, v.copy_len_extra_bits, ©_length)) { + BrotliBitReaderRestoreState(br, &memento); + return BROTLI_FALSE; + } + } + s->copy_length = (int)copy_length + v.copy_len_offset; + --s->block_length[1]; + *insert_length += (int)insert_len_extra; + return BROTLI_TRUE; +} + +static BROTLI_INLINE void ReadCommand( + BrotliDecoderState* s, BrotliBitReader* br, int* insert_length) { + ReadCommandInternal(0, s, br, insert_length); +} + +static BROTLI_INLINE BROTLI_BOOL SafeReadCommand( + BrotliDecoderState* s, BrotliBitReader* br, int* insert_length) { + return ReadCommandInternal(1, s, br, insert_length); +} + +static BROTLI_INLINE BROTLI_BOOL CheckInputAmount( + int safe, BrotliBitReader* const br) { + if (safe) { + return BROTLI_TRUE; + } + return BrotliCheckInputAmount(br); +} + +#define BROTLI_SAFE(METHOD) \ + { \ + if (safe) { \ + if (!Safe##METHOD) { \ + result = BROTLI_DECODER_NEEDS_MORE_INPUT; \ + goto saveStateAndReturn; \ + } \ + } else { \ + METHOD; \ + } \ + } + +static BROTLI_INLINE BrotliDecoderErrorCode ProcessCommandsInternal( + int safe, BrotliDecoderState* s) { + int pos = s->pos; + int i = s->loop_counter; + BrotliDecoderErrorCode result = BROTLI_DECODER_SUCCESS; + BrotliBitReader* br = &s->br; + int compound_dictionary_size = GetCompoundDictionarySize(s); + + if (!CheckInputAmount(safe, br)) { + result = BROTLI_DECODER_NEEDS_MORE_INPUT; + goto saveStateAndReturn; + } + if (!safe) { + BROTLI_UNUSED(BrotliWarmupBitReader(br)); + } + + /* Jump into state machine. */ + if (s->state == BROTLI_STATE_COMMAND_BEGIN) { + goto CommandBegin; + } else if (s->state == BROTLI_STATE_COMMAND_INNER) { + goto CommandInner; + } else if (s->state == BROTLI_STATE_COMMAND_POST_DECODE_LITERALS) { + goto CommandPostDecodeLiterals; + } else if (s->state == BROTLI_STATE_COMMAND_POST_WRAP_COPY) { + goto CommandPostWrapCopy; + } else { + return BROTLI_FAILURE(BROTLI_DECODER_ERROR_UNREACHABLE); /* COV_NF_LINE */ + } + +CommandBegin: + if (safe) { + s->state = BROTLI_STATE_COMMAND_BEGIN; + } + if (!CheckInputAmount(safe, br)) { + s->state = BROTLI_STATE_COMMAND_BEGIN; + result = BROTLI_DECODER_NEEDS_MORE_INPUT; + goto saveStateAndReturn; + } + if (BROTLI_PREDICT_FALSE(s->block_length[1] == 0)) { + BROTLI_SAFE(DecodeCommandBlockSwitch(s)); + goto CommandBegin; + } + /* Read the insert/copy length in the command. */ + BROTLI_SAFE(ReadCommand(s, br, &i)); + BROTLI_LOG(("[ProcessCommandsInternal] pos = %d insert = %d copy = %d\n", + pos, i, s->copy_length)); + if (i == 0) { + goto CommandPostDecodeLiterals; + } + s->meta_block_remaining_len -= i; + +CommandInner: + if (safe) { + s->state = BROTLI_STATE_COMMAND_INNER; + } + /* Read the literals in the command. */ + if (s->trivial_literal_context) { + brotli_reg_t bits; + brotli_reg_t value; + PreloadSymbol(safe, s->literal_htree, br, &bits, &value); + if (!safe) { + // This is a hottest part of the decode, so we copy the loop below + // and optimize it by calculating the number of steps where all checks + // evaluate to false (ringbuffer size/block size/input size). + // Since all checks are loop invariant, we just need to find + // minimal number of iterations for a simple loop, and run + // the full version for the remainder. + int num_steps = i - 1; + if (num_steps > 0 && ((brotli_reg_t)(num_steps) > s->block_length[0])) { + // Safe cast, since block_length < steps + num_steps = (int)s->block_length[0]; + } + if (s->ringbuffer_size >= pos && + (s->ringbuffer_size - pos) <= num_steps) { + num_steps = s->ringbuffer_size - pos - 1; + } + if (num_steps < 0) { + num_steps = 0; + } + num_steps = BrotliCopyPreloadedSymbolsToU8(s->literal_htree, br, &bits, + &value, s->ringbuffer, pos, + num_steps); + pos += num_steps; + s->block_length[0] -= (brotli_reg_t)num_steps; + i -= num_steps; + do { + if (!CheckInputAmount(safe, br)) { + s->state = BROTLI_STATE_COMMAND_INNER; + result = BROTLI_DECODER_NEEDS_MORE_INPUT; + goto saveStateAndReturn; + } + if (BROTLI_PREDICT_FALSE(s->block_length[0] == 0)) { + goto NextLiteralBlock; + } + BrotliCopyPreloadedSymbolsToU8(s->literal_htree, br, &bits, &value, + s->ringbuffer, pos, 1); + --s->block_length[0]; + BROTLI_LOG_ARRAY_INDEX(s->ringbuffer, pos); + ++pos; + if (BROTLI_PREDICT_FALSE(pos == s->ringbuffer_size)) { + s->state = BROTLI_STATE_COMMAND_INNER_WRITE; + --i; + goto saveStateAndReturn; + } + } while (--i != 0); + } else { /* safe */ + do { + if (BROTLI_PREDICT_FALSE(s->block_length[0] == 0)) { + goto NextLiteralBlock; + } + brotli_reg_t literal; + if (!SafeReadSymbol(s->literal_htree, br, &literal)) { + result = BROTLI_DECODER_NEEDS_MORE_INPUT; + goto saveStateAndReturn; + } + s->ringbuffer[pos] = (uint8_t)literal; + --s->block_length[0]; + BROTLI_LOG_ARRAY_INDEX(s->ringbuffer, pos); + ++pos; + if (BROTLI_PREDICT_FALSE(pos == s->ringbuffer_size)) { + s->state = BROTLI_STATE_COMMAND_INNER_WRITE; + --i; + goto saveStateAndReturn; + } + } while (--i != 0); + } + } else { + uint8_t p1 = s->ringbuffer[(pos - 1) & s->ringbuffer_mask]; + uint8_t p2 = s->ringbuffer[(pos - 2) & s->ringbuffer_mask]; + do { + const HuffmanCode* hc; + uint8_t context; + if (!CheckInputAmount(safe, br)) { + s->state = BROTLI_STATE_COMMAND_INNER; + result = BROTLI_DECODER_NEEDS_MORE_INPUT; + goto saveStateAndReturn; + } + if (BROTLI_PREDICT_FALSE(s->block_length[0] == 0)) { + goto NextLiteralBlock; + } + context = BROTLI_CONTEXT(p1, p2, s->context_lookup); + BROTLI_LOG_UINT(context); + hc = s->literal_hgroup.htrees[s->context_map_slice[context]]; + p2 = p1; + if (!safe) { + p1 = (uint8_t)ReadSymbol(hc, br); + } else { + brotli_reg_t literal; + if (!SafeReadSymbol(hc, br, &literal)) { + result = BROTLI_DECODER_NEEDS_MORE_INPUT; + goto saveStateAndReturn; + } + p1 = (uint8_t)literal; + } + s->ringbuffer[pos] = p1; + --s->block_length[0]; + BROTLI_LOG_UINT(s->context_map_slice[context]); + BROTLI_LOG_ARRAY_INDEX(s->ringbuffer, pos & s->ringbuffer_mask); + ++pos; + if (BROTLI_PREDICT_FALSE(pos == s->ringbuffer_size)) { + s->state = BROTLI_STATE_COMMAND_INNER_WRITE; + --i; + goto saveStateAndReturn; + } + } while (--i != 0); + } + BROTLI_LOG_UINT(s->meta_block_remaining_len); + if (BROTLI_PREDICT_FALSE(s->meta_block_remaining_len <= 0)) { + s->state = BROTLI_STATE_METABLOCK_DONE; + goto saveStateAndReturn; + } + +CommandPostDecodeLiterals: + if (safe) { + s->state = BROTLI_STATE_COMMAND_POST_DECODE_LITERALS; + } + if (s->distance_code >= 0) { + /* Implicit distance case. */ + s->distance_context = s->distance_code ? 0 : 1; + --s->dist_rb_idx; + s->distance_code = s->dist_rb[s->dist_rb_idx & 3]; + } else { + /* Read distance code in the command, unless it was implicitly zero. */ + if (BROTLI_PREDICT_FALSE(s->block_length[2] == 0)) { + BROTLI_SAFE(DecodeDistanceBlockSwitch(s)); + } + BROTLI_SAFE(ReadDistance(s, br)); + } + BROTLI_LOG(("[ProcessCommandsInternal] pos = %d distance = %d\n", + pos, s->distance_code)); + if (s->max_distance != s->max_backward_distance) { + s->max_distance = + (pos < s->max_backward_distance) ? pos : s->max_backward_distance; + } + i = s->copy_length; + /* Apply copy of LZ77 back-reference, or static dictionary reference if + the distance is larger than the max LZ77 distance */ + if (s->distance_code > s->max_distance) { + /* The maximum allowed distance is BROTLI_MAX_ALLOWED_DISTANCE = 0x7FFFFFFC. + With this choice, no signed overflow can occur after decoding + a special distance code (e.g., after adding 3 to the last distance). */ + if (s->distance_code > BROTLI_MAX_ALLOWED_DISTANCE) { + BROTLI_LOG(("Invalid backward reference. pos: %d distance: %d " + "len: %d bytes left: %d\n", + pos, s->distance_code, i, s->meta_block_remaining_len)); + return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_DISTANCE); + } + if (s->distance_code - s->max_distance - 1 < compound_dictionary_size) { + int address = compound_dictionary_size - + (s->distance_code - s->max_distance); + if (!InitializeCompoundDictionaryCopy(s, address, i)) { + return BROTLI_FAILURE(BROTLI_DECODER_ERROR_COMPOUND_DICTIONARY); + } + pos += CopyFromCompoundDictionary(s, pos); + if (pos >= s->ringbuffer_size) { + s->state = BROTLI_STATE_COMMAND_POST_WRITE_1; + goto saveStateAndReturn; + } + } else if (i >= SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH && + i <= SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH) { + uint8_t p1 = s->ringbuffer[(pos - 1) & s->ringbuffer_mask]; + uint8_t p2 = s->ringbuffer[(pos - 2) & s->ringbuffer_mask]; + uint8_t dict_id = s->dictionary->context_based ? + s->dictionary->context_map[BROTLI_CONTEXT(p1, p2, s->context_lookup)] + : 0; + const BrotliDictionary* words = s->dictionary->words[dict_id]; + const BrotliTransforms* transforms = s->dictionary->transforms[dict_id]; + int offset = (int)words->offsets_by_length[i]; + brotli_reg_t shift = words->size_bits_by_length[i]; + int address = + s->distance_code - s->max_distance - 1 - compound_dictionary_size; + int mask = (int)BitMask(shift); + int word_idx = address & mask; + int transform_idx = address >> shift; + /* Compensate double distance-ring-buffer roll. */ + s->dist_rb_idx += s->distance_context; + offset += word_idx * i; + /* If the distance is out of bound, select a next static dictionary if + there exist multiple. */ + if ((transform_idx >= (int)transforms->num_transforms || + words->size_bits_by_length[i] == 0) && + s->dictionary->num_dictionaries > 1) { + uint8_t dict_id2; + int dist_remaining = address - + (int)(((1u << shift) & ~1u)) * (int)transforms->num_transforms; + for (dict_id2 = 0; dict_id2 < s->dictionary->num_dictionaries; + dict_id2++) { + const BrotliDictionary* words2 = s->dictionary->words[dict_id2]; + if (dict_id2 != dict_id && words2->size_bits_by_length[i] != 0) { + const BrotliTransforms* transforms2 = + s->dictionary->transforms[dict_id2]; + brotli_reg_t shift2 = words2->size_bits_by_length[i]; + int num = (int)((1u << shift2) & ~1u) * + (int)transforms2->num_transforms; + if (dist_remaining < num) { + dict_id = dict_id2; + words = words2; + transforms = transforms2; + address = dist_remaining; + shift = shift2; + mask = (int)BitMask(shift); + word_idx = address & mask; + transform_idx = address >> shift; + offset = (int)words->offsets_by_length[i] + word_idx * i; + break; + } + dist_remaining -= num; + } + } + } + if (BROTLI_PREDICT_FALSE(words->size_bits_by_length[i] == 0)) { + BROTLI_LOG(("Invalid backward reference. pos: %d distance: %d " + "len: %d bytes left: %d\n", + pos, s->distance_code, i, s->meta_block_remaining_len)); + return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_DICTIONARY); + } + if (BROTLI_PREDICT_FALSE(!words->data)) { + return BROTLI_FAILURE(BROTLI_DECODER_ERROR_DICTIONARY_NOT_SET); + } + if (transform_idx < (int)transforms->num_transforms) { + const uint8_t* word = &words->data[offset]; + int len = i; + if (transform_idx == transforms->cutOffTransforms[0]) { + memcpy(&s->ringbuffer[pos], word, (size_t)len); + BROTLI_LOG(("[ProcessCommandsInternal] dictionary word: [%.*s]\n", + len, word)); + } else { + len = BrotliTransformDictionaryWord(&s->ringbuffer[pos], word, len, + transforms, transform_idx); + BROTLI_LOG(("[ProcessCommandsInternal] dictionary word: [%.*s]," + " transform_idx = %d, transformed: [%.*s]\n", + i, word, transform_idx, len, &s->ringbuffer[pos])); + if (len == 0 && s->distance_code <= 120) { + BROTLI_LOG(("Invalid length-0 dictionary word after transform\n")); + return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_TRANSFORM); + } + } + pos += len; + s->meta_block_remaining_len -= len; + if (pos >= s->ringbuffer_size) { + s->state = BROTLI_STATE_COMMAND_POST_WRITE_1; + goto saveStateAndReturn; + } + } else { + BROTLI_LOG(("Invalid backward reference. pos: %d distance: %d " + "len: %d bytes left: %d\n", + pos, s->distance_code, i, s->meta_block_remaining_len)); + return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_TRANSFORM); + } + } else { + BROTLI_LOG(("Invalid backward reference. pos: %d distance: %d " + "len: %d bytes left: %d\n", + pos, s->distance_code, i, s->meta_block_remaining_len)); + return BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_DICTIONARY); + } + } else { + int src_start = (pos - s->distance_code) & s->ringbuffer_mask; + uint8_t* copy_dst = &s->ringbuffer[pos]; + uint8_t* copy_src = &s->ringbuffer[src_start]; + int dst_end = pos + i; + int src_end = src_start + i; + /* Update the recent distances cache. */ + s->dist_rb[s->dist_rb_idx & 3] = s->distance_code; + ++s->dist_rb_idx; + s->meta_block_remaining_len -= i; + /* There are 32+ bytes of slack in the ring-buffer allocation. + Also, we have 16 short codes, that make these 16 bytes irrelevant + in the ring-buffer. Let's copy over them as a first guess. */ + memmove16(copy_dst, copy_src); + if (src_end > pos && dst_end > src_start) { + /* Regions intersect. */ + goto CommandPostWrapCopy; + } + if (dst_end >= s->ringbuffer_size || src_end >= s->ringbuffer_size) { + /* At least one region wraps. */ + goto CommandPostWrapCopy; + } + pos += i; + if (i > 16) { + if (i > 32) { + memcpy(copy_dst + 16, copy_src + 16, (size_t)(i - 16)); + } else { + /* This branch covers about 45% cases. + Fixed size short copy allows more compiler optimizations. */ + memmove16(copy_dst + 16, copy_src + 16); + } + } + } + BROTLI_LOG_UINT(s->meta_block_remaining_len); + if (s->meta_block_remaining_len <= 0) { + /* Next metablock, if any. */ + s->state = BROTLI_STATE_METABLOCK_DONE; + goto saveStateAndReturn; + } else { + goto CommandBegin; + } +CommandPostWrapCopy: + { + int wrap_guard = s->ringbuffer_size - pos; + while (--i >= 0) { + s->ringbuffer[pos] = + s->ringbuffer[(pos - s->distance_code) & s->ringbuffer_mask]; + ++pos; + if (BROTLI_PREDICT_FALSE(--wrap_guard == 0)) { + s->state = BROTLI_STATE_COMMAND_POST_WRITE_2; + goto saveStateAndReturn; + } + } + } + if (s->meta_block_remaining_len <= 0) { + /* Next metablock, if any. */ + s->state = BROTLI_STATE_METABLOCK_DONE; + goto saveStateAndReturn; + } else { + goto CommandBegin; + } + +NextLiteralBlock: + BROTLI_SAFE(DecodeLiteralBlockSwitch(s)); + goto CommandInner; + +saveStateAndReturn: + s->pos = pos; + s->loop_counter = i; + return result; +} + +#undef BROTLI_SAFE + +static BROTLI_NOINLINE BrotliDecoderErrorCode ProcessCommands( + BrotliDecoderState* s) { + return ProcessCommandsInternal(0, s); +} + +static BROTLI_NOINLINE BrotliDecoderErrorCode SafeProcessCommands( + BrotliDecoderState* s) { + return ProcessCommandsInternal(1, s); +} + +BrotliDecoderResult BrotliDecoderDecompress( + size_t encoded_size, + const uint8_t encoded_buffer[BROTLI_ARRAY_PARAM(encoded_size)], + size_t* decoded_size, + uint8_t decoded_buffer[BROTLI_ARRAY_PARAM(*decoded_size)]) { + BrotliDecoderState s; + BrotliDecoderResult result; + size_t total_out = 0; + size_t available_in = encoded_size; + const uint8_t* next_in = encoded_buffer; + size_t available_out = *decoded_size; + uint8_t* next_out = decoded_buffer; + if (!BrotliDecoderStateInit(&s, 0, 0, 0)) { + return BROTLI_DECODER_RESULT_ERROR; + } + result = BrotliDecoderDecompressStream( + &s, &available_in, &next_in, &available_out, &next_out, &total_out); + *decoded_size = total_out; + BrotliDecoderStateCleanup(&s); + if (result != BROTLI_DECODER_RESULT_SUCCESS) { + result = BROTLI_DECODER_RESULT_ERROR; + } + return result; +} + +/* Invariant: input stream is never overconsumed: + - invalid input implies that the whole stream is invalid -> any amount of + input could be read and discarded + - when result is "needs more input", then at least one more byte is REQUIRED + to complete decoding; all input data MUST be consumed by decoder, so + client could swap the input buffer + - when result is "needs more output" decoder MUST ensure that it doesn't + hold more than 7 bits in bit reader; this saves client from swapping input + buffer ahead of time + - when result is "success" decoder MUST return all unused data back to input + buffer; this is possible because the invariant is held on enter */ +BrotliDecoderResult BrotliDecoderDecompressStream( + BrotliDecoderState* s, size_t* available_in, const uint8_t** next_in, + size_t* available_out, uint8_t** next_out, size_t* total_out) { + BrotliDecoderErrorCode result = BROTLI_DECODER_SUCCESS; + BrotliBitReader* br = &s->br; + size_t input_size = *available_in; +#define BROTLI_SAVE_ERROR_CODE(code) \ + SaveErrorCode(s, (code), input_size - *available_in) + /* Ensure that |total_out| is set, even if no data will ever be pushed out. */ + if (total_out) { + *total_out = s->partial_pos_out; + } + /* Do not try to process further in a case of unrecoverable error. */ + if ((int)s->error_code < 0) { + return BROTLI_DECODER_RESULT_ERROR; + } + if (*available_out && (!next_out || !*next_out)) { + return BROTLI_SAVE_ERROR_CODE( + BROTLI_FAILURE(BROTLI_DECODER_ERROR_INVALID_ARGUMENTS)); + } + if (!*available_out) next_out = 0; + if (s->buffer_length == 0) { /* Just connect bit reader to input stream. */ + BrotliBitReaderSetInput(br, *next_in, *available_in); + } else { + /* At least one byte of input is required. More than one byte of input may + be required to complete the transaction -> reading more data must be + done in a loop -> do it in a main loop. */ + result = BROTLI_DECODER_NEEDS_MORE_INPUT; + BrotliBitReaderSetInput(br, &s->buffer.u8[0], s->buffer_length); + } + /* State machine */ + for (;;) { + if (result != BROTLI_DECODER_SUCCESS) { + /* Error, needs more input/output. */ + if (result == BROTLI_DECODER_NEEDS_MORE_INPUT) { + if (s->ringbuffer != 0) { /* Pro-actively push output. */ + BrotliDecoderErrorCode intermediate_result = WriteRingBuffer(s, + available_out, next_out, total_out, BROTLI_TRUE); + /* WriteRingBuffer checks s->meta_block_remaining_len validity. */ + if ((int)intermediate_result < 0) { + result = intermediate_result; + break; + } + } + if (s->buffer_length != 0) { /* Used with internal buffer. */ + if (br->next_in == br->last_in) { + /* Successfully finished read transaction. + Accumulator contains less than 8 bits, because internal buffer + is expanded byte-by-byte until it is enough to complete read. */ + s->buffer_length = 0; + /* Switch to input stream and restart. */ + result = BROTLI_DECODER_SUCCESS; + BrotliBitReaderSetInput(br, *next_in, *available_in); + continue; + } else if (*available_in != 0) { + /* Not enough data in buffer, but can take one more byte from + input stream. */ + result = BROTLI_DECODER_SUCCESS; + BROTLI_DCHECK(s->buffer_length < 8); + s->buffer.u8[s->buffer_length] = **next_in; + s->buffer_length++; + BrotliBitReaderSetInput(br, &s->buffer.u8[0], s->buffer_length); + (*next_in)++; + (*available_in)--; + /* Retry with more data in buffer. */ + continue; + } + /* Can't finish reading and no more input. */ + break; + } else { /* Input stream doesn't contain enough input. */ + /* Copy tail to internal buffer and return. */ + *next_in = br->next_in; + *available_in = BrotliBitReaderGetAvailIn(br); + while (*available_in) { + s->buffer.u8[s->buffer_length] = **next_in; + s->buffer_length++; + (*next_in)++; + (*available_in)--; + } + break; + } + /* Unreachable. */ + } + + /* Fail or needs more output. */ + + if (s->buffer_length != 0) { + /* Just consumed the buffered input and produced some output. Otherwise + it would result in "needs more input". Reset internal buffer. */ + s->buffer_length = 0; + } else { + /* Using input stream in last iteration. When decoder switches to input + stream it has less than 8 bits in accumulator, so it is safe to + return unused accumulator bits there. */ + BrotliBitReaderUnload(br); + *available_in = BrotliBitReaderGetAvailIn(br); + *next_in = br->next_in; + } + break; + } + switch (s->state) { + case BROTLI_STATE_UNINITED: + /* Prepare to the first read. */ + if (!BrotliWarmupBitReader(br)) { + result = BROTLI_DECODER_NEEDS_MORE_INPUT; + break; + } + /* Decode window size. */ + result = DecodeWindowBits(s, br); /* Reads 1..8 bits. */ + if (result != BROTLI_DECODER_SUCCESS) { + break; + } + if (s->large_window) { + s->state = BROTLI_STATE_LARGE_WINDOW_BITS; + break; + } + s->state = BROTLI_STATE_INITIALIZE; + break; + + case BROTLI_STATE_LARGE_WINDOW_BITS: { + brotli_reg_t bits; + if (!BrotliSafeReadBits(br, 6, &bits)) { + result = BROTLI_DECODER_NEEDS_MORE_INPUT; + break; + } + s->window_bits = bits & 63u; + if (s->window_bits < BROTLI_LARGE_MIN_WBITS || + s->window_bits > BROTLI_LARGE_MAX_WBITS) { + result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_WINDOW_BITS); + break; + } + s->state = BROTLI_STATE_INITIALIZE; + } + /* Fall through. */ + + case BROTLI_STATE_INITIALIZE: + BROTLI_LOG_UINT(s->window_bits); + /* Maximum distance, see section 9.1. of the spec. */ + s->max_backward_distance = (1 << s->window_bits) - BROTLI_WINDOW_GAP; + + /* Allocate memory for both block_type_trees and block_len_trees. */ + s->block_type_trees = (HuffmanCode*)BROTLI_DECODER_ALLOC(s, + sizeof(HuffmanCode) * 3 * + (BROTLI_HUFFMAN_MAX_SIZE_258 + BROTLI_HUFFMAN_MAX_SIZE_26)); + if (s->block_type_trees == 0) { + result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_BLOCK_TYPE_TREES); + break; + } + s->block_len_trees = + s->block_type_trees + 3 * BROTLI_HUFFMAN_MAX_SIZE_258; + + s->state = BROTLI_STATE_METABLOCK_BEGIN; + /* Fall through. */ + + case BROTLI_STATE_METABLOCK_BEGIN: + BrotliDecoderStateMetablockBegin(s); + BROTLI_LOG_UINT(s->pos); + s->state = BROTLI_STATE_METABLOCK_HEADER; + /* Fall through. */ + + case BROTLI_STATE_METABLOCK_HEADER: + result = DecodeMetaBlockLength(s, br); /* Reads 2 - 31 bits. */ + if (result != BROTLI_DECODER_SUCCESS) { + break; + } + BROTLI_LOG_UINT(s->is_last_metablock); + BROTLI_LOG_UINT(s->meta_block_remaining_len); + BROTLI_LOG_UINT(s->is_metadata); + BROTLI_LOG_UINT(s->is_uncompressed); + if (s->is_metadata || s->is_uncompressed) { + if (!BrotliJumpToByteBoundary(br)) { + result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_PADDING_1); + break; + } + } + if (s->is_metadata) { + s->state = BROTLI_STATE_METADATA; + if (s->metadata_start_func) { + s->metadata_start_func(s->metadata_callback_opaque, + (size_t)s->meta_block_remaining_len); + } + break; + } + if (s->meta_block_remaining_len == 0) { + s->state = BROTLI_STATE_METABLOCK_DONE; + break; + } + BrotliCalculateRingBufferSize(s); + if (s->is_uncompressed) { + s->state = BROTLI_STATE_UNCOMPRESSED; + break; + } + s->state = BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER; + /* Fall through. */ + + case BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER: { + BrotliMetablockHeaderArena* h = &s->arena.header; + s->loop_counter = 0; + /* Initialize compressed metablock header arena. */ + h->sub_loop_counter = 0; + /* Make small negative indexes addressable. */ + h->symbol_lists = + &h->symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1]; + h->substate_huffman = BROTLI_STATE_HUFFMAN_NONE; + h->substate_tree_group = BROTLI_STATE_TREE_GROUP_NONE; + h->substate_context_map = BROTLI_STATE_CONTEXT_MAP_NONE; + s->state = BROTLI_STATE_HUFFMAN_CODE_0; + } + /* Fall through. */ + + case BROTLI_STATE_HUFFMAN_CODE_0: + if (s->loop_counter >= 3) { + s->state = BROTLI_STATE_METABLOCK_HEADER_2; + break; + } + /* Reads 1..11 bits. */ + result = DecodeVarLenUint8(s, br, &s->num_block_types[s->loop_counter]); + if (result != BROTLI_DECODER_SUCCESS) { + break; + } + s->num_block_types[s->loop_counter]++; + BROTLI_LOG_UINT(s->num_block_types[s->loop_counter]); + if (s->num_block_types[s->loop_counter] < 2) { + s->loop_counter++; + break; + } + s->state = BROTLI_STATE_HUFFMAN_CODE_1; + /* Fall through. */ + + case BROTLI_STATE_HUFFMAN_CODE_1: { + brotli_reg_t alphabet_size = s->num_block_types[s->loop_counter] + 2; + int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_SIZE_258; + result = ReadHuffmanCode(alphabet_size, alphabet_size, + &s->block_type_trees[tree_offset], NULL, s); + if (result != BROTLI_DECODER_SUCCESS) break; + s->state = BROTLI_STATE_HUFFMAN_CODE_2; + } + /* Fall through. */ + + case BROTLI_STATE_HUFFMAN_CODE_2: { + brotli_reg_t alphabet_size = BROTLI_NUM_BLOCK_LEN_SYMBOLS; + int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_SIZE_26; + result = ReadHuffmanCode(alphabet_size, alphabet_size, + &s->block_len_trees[tree_offset], NULL, s); + if (result != BROTLI_DECODER_SUCCESS) break; + s->state = BROTLI_STATE_HUFFMAN_CODE_3; + } + /* Fall through. */ + + case BROTLI_STATE_HUFFMAN_CODE_3: { + int tree_offset = s->loop_counter * BROTLI_HUFFMAN_MAX_SIZE_26; + if (!SafeReadBlockLength(s, &s->block_length[s->loop_counter], + &s->block_len_trees[tree_offset], br)) { + result = BROTLI_DECODER_NEEDS_MORE_INPUT; + break; + } + BROTLI_LOG_UINT(s->block_length[s->loop_counter]); + s->loop_counter++; + s->state = BROTLI_STATE_HUFFMAN_CODE_0; + break; + } + + case BROTLI_STATE_UNCOMPRESSED: { + result = CopyUncompressedBlockToOutput( + available_out, next_out, total_out, s); + if (result != BROTLI_DECODER_SUCCESS) { + break; + } + s->state = BROTLI_STATE_METABLOCK_DONE; + break; + } + + case BROTLI_STATE_METADATA: + result = SkipMetadataBlock(s); + if (result != BROTLI_DECODER_SUCCESS) { + break; + } + s->state = BROTLI_STATE_METABLOCK_DONE; + break; + + case BROTLI_STATE_METABLOCK_HEADER_2: { + brotli_reg_t bits; + if (!BrotliSafeReadBits(br, 6, &bits)) { + result = BROTLI_DECODER_NEEDS_MORE_INPUT; + break; + } + s->distance_postfix_bits = bits & BitMask(2); + bits >>= 2; + s->num_direct_distance_codes = bits << s->distance_postfix_bits; + BROTLI_LOG_UINT(s->num_direct_distance_codes); + BROTLI_LOG_UINT(s->distance_postfix_bits); + s->context_modes = + (uint8_t*)BROTLI_DECODER_ALLOC(s, (size_t)s->num_block_types[0]); + if (s->context_modes == 0) { + result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_CONTEXT_MODES); + break; + } + s->loop_counter = 0; + s->state = BROTLI_STATE_CONTEXT_MODES; + } + /* Fall through. */ + + case BROTLI_STATE_CONTEXT_MODES: + result = ReadContextModes(s); + if (result != BROTLI_DECODER_SUCCESS) { + break; + } + s->state = BROTLI_STATE_CONTEXT_MAP_1; + /* Fall through. */ + + case BROTLI_STATE_CONTEXT_MAP_1: + result = DecodeContextMap( + s->num_block_types[0] << BROTLI_LITERAL_CONTEXT_BITS, + &s->num_literal_htrees, &s->context_map, s); + if (result != BROTLI_DECODER_SUCCESS) { + break; + } + DetectTrivialLiteralBlockTypes(s); + s->state = BROTLI_STATE_CONTEXT_MAP_2; + /* Fall through. */ + + case BROTLI_STATE_CONTEXT_MAP_2: { + brotli_reg_t npostfix = s->distance_postfix_bits; + brotli_reg_t ndirect = s->num_direct_distance_codes; + brotli_reg_t distance_alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE( + npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS); + brotli_reg_t distance_alphabet_size_limit = distance_alphabet_size_max; + BROTLI_BOOL allocation_success = BROTLI_TRUE; + if (s->large_window) { + BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit( + BROTLI_MAX_ALLOWED_DISTANCE, (uint32_t)npostfix, + (uint32_t)ndirect); + distance_alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE( + npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS); + distance_alphabet_size_limit = limit.max_alphabet_size; + } + result = DecodeContextMap( + s->num_block_types[2] << BROTLI_DISTANCE_CONTEXT_BITS, + &s->num_dist_htrees, &s->dist_context_map, s); + if (result != BROTLI_DECODER_SUCCESS) { + break; + } + allocation_success &= BrotliDecoderHuffmanTreeGroupInit( + s, &s->literal_hgroup, BROTLI_NUM_LITERAL_SYMBOLS, + BROTLI_NUM_LITERAL_SYMBOLS, s->num_literal_htrees); + allocation_success &= BrotliDecoderHuffmanTreeGroupInit( + s, &s->insert_copy_hgroup, BROTLI_NUM_COMMAND_SYMBOLS, + BROTLI_NUM_COMMAND_SYMBOLS, s->num_block_types[1]); + allocation_success &= BrotliDecoderHuffmanTreeGroupInit( + s, &s->distance_hgroup, distance_alphabet_size_max, + distance_alphabet_size_limit, s->num_dist_htrees); + if (!allocation_success) { + return BROTLI_SAVE_ERROR_CODE( + BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_TREE_GROUPS)); + } + s->loop_counter = 0; + s->state = BROTLI_STATE_TREE_GROUP; + } + /* Fall through. */ + + case BROTLI_STATE_TREE_GROUP: { + HuffmanTreeGroup* hgroup = NULL; + switch (s->loop_counter) { + case 0: hgroup = &s->literal_hgroup; break; + case 1: hgroup = &s->insert_copy_hgroup; break; + case 2: hgroup = &s->distance_hgroup; break; + default: return BROTLI_SAVE_ERROR_CODE(BROTLI_FAILURE( + BROTLI_DECODER_ERROR_UNREACHABLE)); /* COV_NF_LINE */ + } + result = HuffmanTreeGroupDecode(hgroup, s); + if (result != BROTLI_DECODER_SUCCESS) break; + s->loop_counter++; + if (s->loop_counter < 3) { + break; + } + s->state = BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY; + } + /* Fall through. */ + + case BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY: + PrepareLiteralDecoding(s); + s->dist_context_map_slice = s->dist_context_map; + s->htree_command = s->insert_copy_hgroup.htrees[0]; + if (!BrotliEnsureRingBuffer(s)) { + result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_ALLOC_RING_BUFFER_2); + break; + } + CalculateDistanceLut(s); + s->state = BROTLI_STATE_COMMAND_BEGIN; + /* Fall through. */ + + case BROTLI_STATE_COMMAND_BEGIN: + /* Fall through. */ + case BROTLI_STATE_COMMAND_INNER: + /* Fall through. */ + case BROTLI_STATE_COMMAND_POST_DECODE_LITERALS: + /* Fall through. */ + case BROTLI_STATE_COMMAND_POST_WRAP_COPY: + result = ProcessCommands(s); + if (result == BROTLI_DECODER_NEEDS_MORE_INPUT) { + result = SafeProcessCommands(s); + } + break; + + case BROTLI_STATE_COMMAND_INNER_WRITE: + /* Fall through. */ + case BROTLI_STATE_COMMAND_POST_WRITE_1: + /* Fall through. */ + case BROTLI_STATE_COMMAND_POST_WRITE_2: + result = WriteRingBuffer( + s, available_out, next_out, total_out, BROTLI_FALSE); + if (result != BROTLI_DECODER_SUCCESS) { + break; + } + WrapRingBuffer(s); + if (s->ringbuffer_size == 1 << s->window_bits) { + s->max_distance = s->max_backward_distance; + } + if (s->state == BROTLI_STATE_COMMAND_POST_WRITE_1) { + BrotliDecoderCompoundDictionary* addon = s->compound_dictionary; + if (addon && (addon->br_length != addon->br_copied)) { + s->pos += CopyFromCompoundDictionary(s, s->pos); + if (s->pos >= s->ringbuffer_size) continue; + } + if (s->meta_block_remaining_len == 0) { + /* Next metablock, if any. */ + s->state = BROTLI_STATE_METABLOCK_DONE; + } else { + s->state = BROTLI_STATE_COMMAND_BEGIN; + } + break; + } else if (s->state == BROTLI_STATE_COMMAND_POST_WRITE_2) { + s->state = BROTLI_STATE_COMMAND_POST_WRAP_COPY; + } else { /* BROTLI_STATE_COMMAND_INNER_WRITE */ + if (s->loop_counter == 0) { + if (s->meta_block_remaining_len == 0) { + s->state = BROTLI_STATE_METABLOCK_DONE; + } else { + s->state = BROTLI_STATE_COMMAND_POST_DECODE_LITERALS; + } + break; + } + s->state = BROTLI_STATE_COMMAND_INNER; + } + break; + + case BROTLI_STATE_METABLOCK_DONE: + if (s->meta_block_remaining_len < 0) { + result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_BLOCK_LENGTH_2); + break; + } + BrotliDecoderStateCleanupAfterMetablock(s); + if (!s->is_last_metablock) { + s->state = BROTLI_STATE_METABLOCK_BEGIN; + break; + } + if (!BrotliJumpToByteBoundary(br)) { + result = BROTLI_FAILURE(BROTLI_DECODER_ERROR_FORMAT_PADDING_2); + break; + } + if (s->buffer_length == 0) { + BrotliBitReaderUnload(br); + *available_in = BrotliBitReaderGetAvailIn(br); + *next_in = br->next_in; + } + s->state = BROTLI_STATE_DONE; + /* Fall through. */ + + case BROTLI_STATE_DONE: + if (s->ringbuffer != 0) { + result = WriteRingBuffer( + s, available_out, next_out, total_out, BROTLI_TRUE); + if (result != BROTLI_DECODER_SUCCESS) { + break; + } + } + return BROTLI_SAVE_ERROR_CODE(result); + } + } + return BROTLI_SAVE_ERROR_CODE(result); +#undef BROTLI_SAVE_ERROR_CODE +} + +BROTLI_BOOL BrotliDecoderHasMoreOutput(const BrotliDecoderState* s) { + /* After unrecoverable error remaining output is considered nonsensical. */ + if ((int)s->error_code < 0) { + return BROTLI_FALSE; + } + return TO_BROTLI_BOOL( + s->ringbuffer != 0 && UnwrittenBytes(s, BROTLI_FALSE) != 0); +} + +const uint8_t* BrotliDecoderTakeOutput(BrotliDecoderState* s, size_t* size) { + uint8_t* result = 0; + size_t available_out = *size ? *size : 1u << 24; + size_t requested_out = available_out; + BrotliDecoderErrorCode status; + if ((s->ringbuffer == 0) || ((int)s->error_code < 0)) { + *size = 0; + return 0; + } + WrapRingBuffer(s); + status = WriteRingBuffer(s, &available_out, &result, 0, BROTLI_TRUE); + /* Either WriteRingBuffer returns those "success" codes... */ + if (status == BROTLI_DECODER_SUCCESS || + status == BROTLI_DECODER_NEEDS_MORE_OUTPUT) { + *size = requested_out - available_out; + } else { + /* ... or stream is broken. Normally this should be caught by + BrotliDecoderDecompressStream, this is just a safeguard. */ + if ((int)status < 0) SaveErrorCode(s, status, 0); + *size = 0; + result = 0; + } + return result; +} + +BROTLI_BOOL BrotliDecoderIsUsed(const BrotliDecoderState* s) { + return TO_BROTLI_BOOL(s->state != BROTLI_STATE_UNINITED || + BrotliGetAvailableBits(&s->br) != 0); +} + +BROTLI_BOOL BrotliDecoderIsFinished(const BrotliDecoderState* s) { + return TO_BROTLI_BOOL(s->state == BROTLI_STATE_DONE) && + !BrotliDecoderHasMoreOutput(s); +} + +BrotliDecoderErrorCode BrotliDecoderGetErrorCode(const BrotliDecoderState* s) { + return (BrotliDecoderErrorCode)s->error_code; +} + +const char* BrotliDecoderErrorString(BrotliDecoderErrorCode c) { + switch (c) { +#define BROTLI_ERROR_CODE_CASE_(PREFIX, NAME, CODE) \ + case BROTLI_DECODER ## PREFIX ## NAME: return #PREFIX #NAME; +#define BROTLI_NOTHING_ + BROTLI_DECODER_ERROR_CODES_LIST(BROTLI_ERROR_CODE_CASE_, BROTLI_NOTHING_) +#undef BROTLI_ERROR_CODE_CASE_ +#undef BROTLI_NOTHING_ + default: return "INVALID"; + } +} + +uint32_t BrotliDecoderVersion(void) { + return BROTLI_VERSION; +} + +void BrotliDecoderSetMetadataCallbacks( + BrotliDecoderState* state, + brotli_decoder_metadata_start_func start_func, + brotli_decoder_metadata_chunk_func chunk_func, void* opaque) { + state->metadata_start_func = start_func; + state->metadata_chunk_func = chunk_func; + state->metadata_callback_opaque = opaque; +} + +/* Escalate internal functions visibility; for testing purposes only. */ +#if defined(BROTLI_TEST) +BROTLI_BOOL BrotliSafeReadSymbolForTest( + const HuffmanCode*, BrotliBitReader*, brotli_reg_t*); +BROTLI_BOOL BrotliSafeReadSymbolForTest( + const HuffmanCode* table, BrotliBitReader* br, brotli_reg_t* result) { + return SafeReadSymbol(table, br, result); +} +void BrotliInverseMoveToFrontTransformForTest( + uint8_t*, brotli_reg_t, BrotliDecoderState*); +void BrotliInverseMoveToFrontTransformForTest( + uint8_t* v, brotli_reg_t l, BrotliDecoderState* s) { + InverseMoveToFrontTransform(v, l, s); +} +#endif + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/dec/huffman.c b/packages/runtime/vendor/brotli/c/dec/huffman.c new file mode 100644 index 000000000..06486cf81 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/dec/huffman.c @@ -0,0 +1,339 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Utilities for building Huffman decoding tables. */ + +#include "huffman.h" + +#include "../common/constants.h" +#include "../common/platform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define BROTLI_REVERSE_BITS_MAX 8 + +#if defined(BROTLI_RBIT) +#define BROTLI_REVERSE_BITS_BASE \ + ((sizeof(brotli_reg_t) << 3) - BROTLI_REVERSE_BITS_MAX) +#else +#define BROTLI_REVERSE_BITS_BASE 0 +static BROTLI_MODEL("small") +uint8_t kReverseBits[1 << BROTLI_REVERSE_BITS_MAX] = { + 0x00, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, + 0x10, 0x90, 0x50, 0xD0, 0x30, 0xB0, 0x70, 0xF0, + 0x08, 0x88, 0x48, 0xC8, 0x28, 0xA8, 0x68, 0xE8, + 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8, + 0x04, 0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, + 0x14, 0x94, 0x54, 0xD4, 0x34, 0xB4, 0x74, 0xF4, + 0x0C, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C, 0xEC, + 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC, + 0x02, 0x82, 0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, + 0x12, 0x92, 0x52, 0xD2, 0x32, 0xB2, 0x72, 0xF2, + 0x0A, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA, + 0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA, + 0x06, 0x86, 0x46, 0xC6, 0x26, 0xA6, 0x66, 0xE6, + 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6, 0x76, 0xF6, + 0x0E, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, + 0x1E, 0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE, + 0x01, 0x81, 0x41, 0xC1, 0x21, 0xA1, 0x61, 0xE1, + 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71, 0xF1, + 0x09, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, + 0x19, 0x99, 0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, + 0x05, 0x85, 0x45, 0xC5, 0x25, 0xA5, 0x65, 0xE5, + 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5, + 0x0D, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, + 0x1D, 0x9D, 0x5D, 0xDD, 0x3D, 0xBD, 0x7D, 0xFD, + 0x03, 0x83, 0x43, 0xC3, 0x23, 0xA3, 0x63, 0xE3, + 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3, + 0x0B, 0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, + 0x1B, 0x9B, 0x5B, 0xDB, 0x3B, 0xBB, 0x7B, 0xFB, + 0x07, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67, 0xE7, + 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7, + 0x0F, 0x8F, 0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, + 0x1F, 0x9F, 0x5F, 0xDF, 0x3F, 0xBF, 0x7F, 0xFF +}; +#endif /* BROTLI_RBIT */ + +#define BROTLI_REVERSE_BITS_LOWEST \ + ((brotli_reg_t)1 << (BROTLI_REVERSE_BITS_MAX - 1 + BROTLI_REVERSE_BITS_BASE)) + +/* Returns reverse(num >> BROTLI_REVERSE_BITS_BASE, BROTLI_REVERSE_BITS_MAX), + where reverse(value, len) is the bit-wise reversal of the len least + significant bits of value. */ +static BROTLI_INLINE brotli_reg_t BrotliReverseBits(brotli_reg_t num) { +#if defined(BROTLI_RBIT) + return BROTLI_RBIT(num); +#else + return kReverseBits[num]; +#endif +} + +/* Stores code in table[0], table[step], table[2*step], ..., table[end] */ +/* Assumes that end is an integer multiple of step */ +static BROTLI_INLINE void ReplicateValue(HuffmanCode* table, + int step, int end, + HuffmanCode code) { + do { + end -= step; + table[end] = code; + } while (end > 0); +} + +/* Returns the table width of the next 2nd level table. |count| is the histogram + of bit lengths for the remaining symbols, |len| is the code length of the + next processed symbol. */ +static BROTLI_INLINE int NextTableBitSize(const uint16_t* const count, + int len, int root_bits) { + int left = 1 << (len - root_bits); + while (len < BROTLI_HUFFMAN_MAX_CODE_LENGTH) { + left -= count[len]; + if (left <= 0) break; + ++len; + left <<= 1; + } + return len - root_bits; +} + +void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* table, + const uint8_t* const code_lengths, + uint16_t* count) { + HuffmanCode code; /* current table entry */ + int symbol; /* symbol index in original or sorted table */ + brotli_reg_t key; /* prefix code */ + brotli_reg_t key_step; /* prefix code addend */ + int step; /* step size to replicate values in current table */ + int table_size; /* size of current table */ + int sorted[BROTLI_CODE_LENGTH_CODES]; /* symbols sorted by code length */ + /* offsets in sorted table for each length */ + int offset[BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH + 1]; + int bits; + int bits_count; + BROTLI_DCHECK(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH <= + BROTLI_REVERSE_BITS_MAX); + BROTLI_DCHECK(BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH == 5); + + /* Generate offsets into sorted symbol table by code length. */ + symbol = -1; + bits = 1; + /* BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH == 5 */ + BROTLI_REPEAT_5({ + symbol += count[bits]; + offset[bits] = symbol; + bits++; + }); + /* Symbols with code length 0 are placed after all other symbols. */ + offset[0] = BROTLI_CODE_LENGTH_CODES - 1; + + /* Sort symbols by length, by symbol order within each length. */ + symbol = BROTLI_CODE_LENGTH_CODES; + do { + BROTLI_REPEAT_6({ + symbol--; + sorted[offset[code_lengths[symbol]]--] = symbol; + }); + } while (symbol != 0); + + table_size = 1 << BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH; + + /* Special case: all symbols but one have 0 code length. */ + if (offset[0] == 0) { + code = ConstructHuffmanCode(0, (uint16_t)sorted[0]); + for (key = 0; key < (brotli_reg_t)table_size; ++key) { + table[key] = code; + } + return; + } + + /* Fill in table. */ + key = 0; + key_step = BROTLI_REVERSE_BITS_LOWEST; + symbol = 0; + bits = 1; + step = 2; + do { + for (bits_count = count[bits]; bits_count != 0; --bits_count) { + code = ConstructHuffmanCode((uint8_t)bits, (uint16_t)sorted[symbol++]); + ReplicateValue(&table[BrotliReverseBits(key)], step, table_size, code); + key += key_step; + } + step <<= 1; + key_step >>= 1; + } while (++bits <= BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH); +} + +uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table, + int root_bits, + const uint16_t* const symbol_lists, + uint16_t* count) { + HuffmanCode code; /* current table entry */ + HuffmanCode* table; /* next available space in table */ + int len; /* current code length */ + int symbol; /* symbol index in original or sorted table */ + brotli_reg_t key; /* prefix code */ + brotli_reg_t key_step; /* prefix code addend */ + brotli_reg_t sub_key; /* 2nd level table prefix code */ + brotli_reg_t sub_key_step; /* 2nd level table prefix code addend */ + int step; /* step size to replicate values in current table */ + int table_bits; /* key length of current table */ + int table_size; /* size of current table */ + int total_size; /* sum of root table size and 2nd level table sizes */ + int max_length = -1; + int bits; + int bits_count; + + BROTLI_DCHECK(root_bits <= BROTLI_REVERSE_BITS_MAX); + BROTLI_DCHECK(BROTLI_HUFFMAN_MAX_CODE_LENGTH - root_bits <= + BROTLI_REVERSE_BITS_MAX); + + while (symbol_lists[max_length] == 0xFFFF) max_length--; + max_length += BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1; + + table = root_table; + table_bits = root_bits; + table_size = 1 << table_bits; + total_size = table_size; + + /* Fill in the root table. Reduce the table size to if possible, + and create the repetitions by memcpy. */ + if (table_bits > max_length) { + table_bits = max_length; + table_size = 1 << table_bits; + } + key = 0; + key_step = BROTLI_REVERSE_BITS_LOWEST; + bits = 1; + step = 2; + do { + symbol = bits - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1); + for (bits_count = count[bits]; bits_count != 0; --bits_count) { + symbol = symbol_lists[symbol]; + code = ConstructHuffmanCode((uint8_t)bits, (uint16_t)symbol); + ReplicateValue(&table[BrotliReverseBits(key)], step, table_size, code); + key += key_step; + } + step <<= 1; + key_step >>= 1; + } while (++bits <= table_bits); + + /* If root_bits != table_bits then replicate to fill the remaining slots. */ + while (total_size != table_size) { + memcpy(&table[table_size], &table[0], + (size_t)table_size * sizeof(table[0])); + table_size <<= 1; + } + + /* Fill in 2nd level tables and add pointers to root table. */ + key_step = BROTLI_REVERSE_BITS_LOWEST >> (root_bits - 1); + sub_key = (BROTLI_REVERSE_BITS_LOWEST << 1); + sub_key_step = BROTLI_REVERSE_BITS_LOWEST; + for (len = root_bits + 1, step = 2; len <= max_length; ++len) { + symbol = len - (BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1); + for (; count[len] != 0; --count[len]) { + if (sub_key == (BROTLI_REVERSE_BITS_LOWEST << 1U)) { + table += table_size; + table_bits = NextTableBitSize(count, len, root_bits); + table_size = 1 << table_bits; + total_size += table_size; + sub_key = BrotliReverseBits(key); + key += key_step; + root_table[sub_key] = ConstructHuffmanCode( + (uint8_t)(table_bits + root_bits), + (uint16_t)(((size_t)(table - root_table)) - sub_key)); + sub_key = 0; + } + symbol = symbol_lists[symbol]; + code = ConstructHuffmanCode((uint8_t)(len - root_bits), (uint16_t)symbol); + ReplicateValue( + &table[BrotliReverseBits(sub_key)], step, table_size, code); + sub_key += sub_key_step; + } + step <<= 1; + sub_key_step >>= 1; + } + return (uint32_t)total_size; +} + +uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table, + int root_bits, + uint16_t* val, + uint32_t num_symbols) { + uint32_t table_size = 1; + const uint32_t goal_size = 1U << root_bits; + switch (num_symbols) { + case 0: + table[0] = ConstructHuffmanCode(0, val[0]); + break; + case 1: + if (val[1] > val[0]) { + table[0] = ConstructHuffmanCode(1, val[0]); + table[1] = ConstructHuffmanCode(1, val[1]); + } else { + table[0] = ConstructHuffmanCode(1, val[1]); + table[1] = ConstructHuffmanCode(1, val[0]); + } + table_size = 2; + break; + case 2: + table[0] = ConstructHuffmanCode(1, val[0]); + table[2] = ConstructHuffmanCode(1, val[0]); + if (val[2] > val[1]) { + table[1] = ConstructHuffmanCode(2, val[1]); + table[3] = ConstructHuffmanCode(2, val[2]); + } else { + table[1] = ConstructHuffmanCode(2, val[2]); + table[3] = ConstructHuffmanCode(2, val[1]); + } + table_size = 4; + break; + case 3: { + int i, k; + for (i = 0; i < 3; ++i) { + for (k = i + 1; k < 4; ++k) { + if (val[k] < val[i]) { + uint16_t t = val[k]; + val[k] = val[i]; + val[i] = t; + } + } + } + table[0] = ConstructHuffmanCode(2, val[0]); + table[2] = ConstructHuffmanCode(2, val[1]); + table[1] = ConstructHuffmanCode(2, val[2]); + table[3] = ConstructHuffmanCode(2, val[3]); + table_size = 4; + break; + } + case 4: { + if (val[3] < val[2]) { + uint16_t t = val[3]; + val[3] = val[2]; + val[2] = t; + } + table[0] = ConstructHuffmanCode(1, val[0]); + table[1] = ConstructHuffmanCode(2, val[1]); + table[2] = ConstructHuffmanCode(1, val[0]); + table[3] = ConstructHuffmanCode(3, val[2]); + table[4] = ConstructHuffmanCode(1, val[0]); + table[5] = ConstructHuffmanCode(2, val[1]); + table[6] = ConstructHuffmanCode(1, val[0]); + table[7] = ConstructHuffmanCode(3, val[3]); + table_size = 8; + break; + } + } + while (table_size != goal_size) { + memcpy(&table[table_size], &table[0], + (size_t)table_size * sizeof(table[0])); + table_size <<= 1; + } + return goal_size; +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/dec/huffman.h b/packages/runtime/vendor/brotli/c/dec/huffman.h new file mode 100644 index 000000000..53daf600e --- /dev/null +++ b/packages/runtime/vendor/brotli/c/dec/huffman.h @@ -0,0 +1,120 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Utilities for building Huffman decoding tables. */ + +#ifndef BROTLI_DEC_HUFFMAN_H_ +#define BROTLI_DEC_HUFFMAN_H_ + +#include "../common/platform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define BROTLI_HUFFMAN_MAX_CODE_LENGTH 15 + +/* BROTLI_NUM_BLOCK_LEN_SYMBOLS == 26 */ +#define BROTLI_HUFFMAN_MAX_SIZE_26 396 +/* BROTLI_MAX_BLOCK_TYPE_SYMBOLS == 258 */ +#define BROTLI_HUFFMAN_MAX_SIZE_258 632 +/* BROTLI_MAX_CONTEXT_MAP_SYMBOLS == 272 */ +#define BROTLI_HUFFMAN_MAX_SIZE_272 646 + +#define BROTLI_HUFFMAN_MAX_CODE_LENGTH_CODE_LENGTH 5 + +#if ((defined(BROTLI_TARGET_ARMV7) || defined(BROTLI_TARGET_ARMV8_32)) && \ + BROTLI_GNUC_HAS_ATTRIBUTE(aligned, 2, 7, 0)) +#define BROTLI_HUFFMAN_CODE_FAST_LOAD +#endif + +#if !defined(BROTLI_HUFFMAN_CODE_FAST_LOAD) +/* Do not create this struct directly - use the ConstructHuffmanCode + * constructor below! */ +typedef struct { + uint8_t bits; /* number of bits used for this symbol */ + uint16_t value; /* symbol value or table offset */ +} HuffmanCode; + +static BROTLI_INLINE HuffmanCode ConstructHuffmanCode(const uint8_t bits, + const uint16_t value) { + HuffmanCode h; + h.bits = bits; + h.value = value; + return h; +} + +/* Please use the following macros to optimize HuffmanCode accesses in hot + * paths. + * + * For example, assuming |table| contains a HuffmanCode pointer: + * + * BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(table); + * BROTLI_HC_ADJUST_TABLE_INDEX(table, index_into_table); + * *bits = BROTLI_HC_GET_BITS(table); + * *value = BROTLI_HC_GET_VALUE(table); + * BROTLI_HC_ADJUST_TABLE_INDEX(table, offset); + * *bits2 = BROTLI_HC_GET_BITS(table); + * *value2 = BROTLI_HC_GET_VALUE(table); + * + */ + +#define BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(H) +#define BROTLI_HC_ADJUST_TABLE_INDEX(H, V) H += (V) + +/* These must be given a HuffmanCode pointer! */ +#define BROTLI_HC_FAST_LOAD_BITS(H) (H->bits) +#define BROTLI_HC_FAST_LOAD_VALUE(H) (H->value) + +#else /* BROTLI_HUFFMAN_CODE_FAST_LOAD */ + +typedef BROTLI_ALIGNED(4) uint32_t HuffmanCode; + +static BROTLI_INLINE HuffmanCode ConstructHuffmanCode(const uint8_t bits, + const uint16_t value) { + return (HuffmanCode) ((value & 0xFFFF) << 16) | (bits & 0xFF); +} + +#define BROTLI_HC_MARK_TABLE_FOR_FAST_LOAD(H) uint32_t __fastload_##H = (*H) +#define BROTLI_HC_ADJUST_TABLE_INDEX(H, V) H += (V); __fastload_##H = (*H) + +/* These must be given a HuffmanCode pointer! */ +#define BROTLI_HC_FAST_LOAD_BITS(H) ((__fastload_##H) & 0xFF) +#define BROTLI_HC_FAST_LOAD_VALUE(H) ((__fastload_##H) >> 16) +#endif /* BROTLI_HUFFMAN_CODE_FAST_LOAD */ + +/* Builds Huffman lookup table assuming code lengths are in symbol order. */ +BROTLI_INTERNAL void BrotliBuildCodeLengthsHuffmanTable(HuffmanCode* root_table, + const uint8_t* const code_lengths, uint16_t* count); + +/* Builds Huffman lookup table assuming code lengths are in symbol order. + Returns size of resulting table. */ +BROTLI_INTERNAL uint32_t BrotliBuildHuffmanTable(HuffmanCode* root_table, + int root_bits, const uint16_t* const symbol_lists, uint16_t* count); + +/* Builds a simple Huffman table. The |num_symbols| parameter is to be + interpreted as follows: 0 means 1 symbol, 1 means 2 symbols, + 2 means 3 symbols, 3 means 4 symbols with lengths [2, 2, 2, 2], + 4 means 4 symbols with lengths [1, 2, 3, 3]. */ +BROTLI_INTERNAL uint32_t BrotliBuildSimpleHuffmanTable(HuffmanCode* table, + int root_bits, uint16_t* symbols, uint32_t num_symbols); + +/* Contains a collection of Huffman trees with the same alphabet size. */ +/* alphabet_size_limit is needed due to simple codes, since + log2(alphabet_size_max) could be greater than log2(alphabet_size_limit). */ +typedef struct { + HuffmanCode** htrees; + HuffmanCode* codes; + uint16_t alphabet_size_max; + uint16_t alphabet_size_limit; + uint16_t num_htrees; +} HuffmanTreeGroup; + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_DEC_HUFFMAN_H_ */ diff --git a/packages/runtime/vendor/brotli/c/dec/prefix.c b/packages/runtime/vendor/brotli/c/dec/prefix.c new file mode 100644 index 000000000..ce3998f24 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/dec/prefix.c @@ -0,0 +1,67 @@ +/* Copyright 2025 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#include "prefix.h" + +#include "../common/platform.h" /* IWYU pragma: keep */ +#include "../common/static_init.h" + +#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE) +#include "../common/constants.h" +#endif + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_NONE) +/* Embed kCmdLut. */ +#include "prefix_inc.h" +#else +BROTLI_COLD BROTLI_BOOL BrotliDecoderInitCmdLut(CmdLutElement* items) { + static const uint8_t kInsertLengthExtraBits[24] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, + 0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0C, 0x0E, 0x18}; + static const uint8_t kCopyLengthExtraBits[24] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x02, 0x02, + 0x03, 0x03, 0x04, 0x04, 0x05, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x18}; + static const uint8_t kCellPos[11] = {0, 1, 0, 1, 8, 9, 2, 16, 10, 17, 18}; + + uint16_t insert_length_offsets[24]; + uint16_t copy_length_offsets[24]; + insert_length_offsets[0] = 0; + copy_length_offsets[0] = 2; + for (size_t i = 0; i < 23; ++i) { + insert_length_offsets[i + 1] = + insert_length_offsets[i] + (uint16_t)(1u << kInsertLengthExtraBits[i]); + copy_length_offsets[i + 1] = + copy_length_offsets[i] + (uint16_t)(1u << kCopyLengthExtraBits[i]); + } + + for (size_t symbol = 0; symbol < BROTLI_NUM_COMMAND_SYMBOLS; ++symbol) { + CmdLutElement* item = items + symbol; + const size_t cell_idx = symbol >> 6; + const size_t cell_pos = kCellPos[cell_idx]; + const size_t copy_code = ((cell_pos << 3) & 0x18) + (symbol & 0x7); + const uint16_t copy_len_offset = copy_length_offsets[copy_code]; + const size_t insert_code = (cell_pos & 0x18) + ((symbol >> 3) & 0x7); + item->copy_len_extra_bits = kCopyLengthExtraBits[copy_code]; + item->context = (copy_len_offset > 4) ? 3 : ((uint8_t)copy_len_offset - 2); + item->copy_len_offset = copy_len_offset; + item->distance_code = (cell_idx >= 2) ? -1 : 0; + item->insert_len_extra_bits = kInsertLengthExtraBits[insert_code]; + item->insert_len_offset = insert_length_offsets[insert_code]; + } + return BROTLI_TRUE; +} + +BROTLI_MODEL("small") +CmdLutElement kCmdLut[BROTLI_NUM_COMMAND_SYMBOLS]; +#endif /* BROTLI_STATIC_INIT */ + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/dec/prefix.h b/packages/runtime/vendor/brotli/c/dec/prefix.h new file mode 100644 index 000000000..f45b8be40 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/dec/prefix.h @@ -0,0 +1,43 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Lookup tables to map prefix codes to value ranges. This is used during + decoding of the block lengths, literal insertion lengths and copy lengths. */ + +#ifndef BROTLI_DEC_PREFIX_H_ +#define BROTLI_DEC_PREFIX_H_ + +#include "../common/constants.h" +#include "../common/platform.h" /* IWYU pragma: keep */ +#include "../common/static_init.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +typedef struct CmdLutElement { + uint8_t insert_len_extra_bits; + uint8_t copy_len_extra_bits; + int8_t distance_code; + uint8_t context; + uint16_t insert_len_offset; + uint16_t copy_len_offset; +} CmdLutElement; + +#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_NONE) +BROTLI_INTERNAL extern const BROTLI_MODEL("small") + CmdLutElement kCmdLut[BROTLI_NUM_COMMAND_SYMBOLS]; +#else +BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderInitCmdLut(CmdLutElement* items); +BROTLI_INTERNAL extern BROTLI_MODEL("small") + CmdLutElement kCmdLut[BROTLI_NUM_COMMAND_SYMBOLS]; +#endif + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_DEC_PREFIX_H_ */ diff --git a/packages/runtime/vendor/brotli/c/dec/prefix_inc.h b/packages/runtime/vendor/brotli/c/dec/prefix_inc.h new file mode 100644 index 000000000..91d81b846 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/dec/prefix_inc.h @@ -0,0 +1,707 @@ +const BROTLI_MODEL("small") +CmdLutElement kCmdLut[BROTLI_NUM_COMMAND_SYMBOLS] = { + { 0x00, 0x00, 0, 0x00, 0x0000, 0x0002 }, + { 0x00, 0x00, 0, 0x01, 0x0000, 0x0003 }, + { 0x00, 0x00, 0, 0x02, 0x0000, 0x0004 }, + { 0x00, 0x00, 0, 0x03, 0x0000, 0x0005 }, + { 0x00, 0x00, 0, 0x03, 0x0000, 0x0006 }, + { 0x00, 0x00, 0, 0x03, 0x0000, 0x0007 }, + { 0x00, 0x00, 0, 0x03, 0x0000, 0x0008 }, + { 0x00, 0x00, 0, 0x03, 0x0000, 0x0009 }, + { 0x00, 0x00, 0, 0x00, 0x0001, 0x0002 }, + { 0x00, 0x00, 0, 0x01, 0x0001, 0x0003 }, + { 0x00, 0x00, 0, 0x02, 0x0001, 0x0004 }, + { 0x00, 0x00, 0, 0x03, 0x0001, 0x0005 }, + { 0x00, 0x00, 0, 0x03, 0x0001, 0x0006 }, + { 0x00, 0x00, 0, 0x03, 0x0001, 0x0007 }, + { 0x00, 0x00, 0, 0x03, 0x0001, 0x0008 }, + { 0x00, 0x00, 0, 0x03, 0x0001, 0x0009 }, + { 0x00, 0x00, 0, 0x00, 0x0002, 0x0002 }, + { 0x00, 0x00, 0, 0x01, 0x0002, 0x0003 }, + { 0x00, 0x00, 0, 0x02, 0x0002, 0x0004 }, + { 0x00, 0x00, 0, 0x03, 0x0002, 0x0005 }, + { 0x00, 0x00, 0, 0x03, 0x0002, 0x0006 }, + { 0x00, 0x00, 0, 0x03, 0x0002, 0x0007 }, + { 0x00, 0x00, 0, 0x03, 0x0002, 0x0008 }, + { 0x00, 0x00, 0, 0x03, 0x0002, 0x0009 }, + { 0x00, 0x00, 0, 0x00, 0x0003, 0x0002 }, + { 0x00, 0x00, 0, 0x01, 0x0003, 0x0003 }, + { 0x00, 0x00, 0, 0x02, 0x0003, 0x0004 }, + { 0x00, 0x00, 0, 0x03, 0x0003, 0x0005 }, + { 0x00, 0x00, 0, 0x03, 0x0003, 0x0006 }, + { 0x00, 0x00, 0, 0x03, 0x0003, 0x0007 }, + { 0x00, 0x00, 0, 0x03, 0x0003, 0x0008 }, + { 0x00, 0x00, 0, 0x03, 0x0003, 0x0009 }, + { 0x00, 0x00, 0, 0x00, 0x0004, 0x0002 }, + { 0x00, 0x00, 0, 0x01, 0x0004, 0x0003 }, + { 0x00, 0x00, 0, 0x02, 0x0004, 0x0004 }, + { 0x00, 0x00, 0, 0x03, 0x0004, 0x0005 }, + { 0x00, 0x00, 0, 0x03, 0x0004, 0x0006 }, + { 0x00, 0x00, 0, 0x03, 0x0004, 0x0007 }, + { 0x00, 0x00, 0, 0x03, 0x0004, 0x0008 }, + { 0x00, 0x00, 0, 0x03, 0x0004, 0x0009 }, + { 0x00, 0x00, 0, 0x00, 0x0005, 0x0002 }, + { 0x00, 0x00, 0, 0x01, 0x0005, 0x0003 }, + { 0x00, 0x00, 0, 0x02, 0x0005, 0x0004 }, + { 0x00, 0x00, 0, 0x03, 0x0005, 0x0005 }, + { 0x00, 0x00, 0, 0x03, 0x0005, 0x0006 }, + { 0x00, 0x00, 0, 0x03, 0x0005, 0x0007 }, + { 0x00, 0x00, 0, 0x03, 0x0005, 0x0008 }, + { 0x00, 0x00, 0, 0x03, 0x0005, 0x0009 }, + { 0x01, 0x00, 0, 0x00, 0x0006, 0x0002 }, + { 0x01, 0x00, 0, 0x01, 0x0006, 0x0003 }, + { 0x01, 0x00, 0, 0x02, 0x0006, 0x0004 }, + { 0x01, 0x00, 0, 0x03, 0x0006, 0x0005 }, + { 0x01, 0x00, 0, 0x03, 0x0006, 0x0006 }, + { 0x01, 0x00, 0, 0x03, 0x0006, 0x0007 }, + { 0x01, 0x00, 0, 0x03, 0x0006, 0x0008 }, + { 0x01, 0x00, 0, 0x03, 0x0006, 0x0009 }, + { 0x01, 0x00, 0, 0x00, 0x0008, 0x0002 }, + { 0x01, 0x00, 0, 0x01, 0x0008, 0x0003 }, + { 0x01, 0x00, 0, 0x02, 0x0008, 0x0004 }, + { 0x01, 0x00, 0, 0x03, 0x0008, 0x0005 }, + { 0x01, 0x00, 0, 0x03, 0x0008, 0x0006 }, + { 0x01, 0x00, 0, 0x03, 0x0008, 0x0007 }, + { 0x01, 0x00, 0, 0x03, 0x0008, 0x0008 }, + { 0x01, 0x00, 0, 0x03, 0x0008, 0x0009 }, + { 0x00, 0x01, 0, 0x03, 0x0000, 0x000a }, + { 0x00, 0x01, 0, 0x03, 0x0000, 0x000c }, + { 0x00, 0x02, 0, 0x03, 0x0000, 0x000e }, + { 0x00, 0x02, 0, 0x03, 0x0000, 0x0012 }, + { 0x00, 0x03, 0, 0x03, 0x0000, 0x0016 }, + { 0x00, 0x03, 0, 0x03, 0x0000, 0x001e }, + { 0x00, 0x04, 0, 0x03, 0x0000, 0x0026 }, + { 0x00, 0x04, 0, 0x03, 0x0000, 0x0036 }, + { 0x00, 0x01, 0, 0x03, 0x0001, 0x000a }, + { 0x00, 0x01, 0, 0x03, 0x0001, 0x000c }, + { 0x00, 0x02, 0, 0x03, 0x0001, 0x000e }, + { 0x00, 0x02, 0, 0x03, 0x0001, 0x0012 }, + { 0x00, 0x03, 0, 0x03, 0x0001, 0x0016 }, + { 0x00, 0x03, 0, 0x03, 0x0001, 0x001e }, + { 0x00, 0x04, 0, 0x03, 0x0001, 0x0026 }, + { 0x00, 0x04, 0, 0x03, 0x0001, 0x0036 }, + { 0x00, 0x01, 0, 0x03, 0x0002, 0x000a }, + { 0x00, 0x01, 0, 0x03, 0x0002, 0x000c }, + { 0x00, 0x02, 0, 0x03, 0x0002, 0x000e }, + { 0x00, 0x02, 0, 0x03, 0x0002, 0x0012 }, + { 0x00, 0x03, 0, 0x03, 0x0002, 0x0016 }, + { 0x00, 0x03, 0, 0x03, 0x0002, 0x001e }, + { 0x00, 0x04, 0, 0x03, 0x0002, 0x0026 }, + { 0x00, 0x04, 0, 0x03, 0x0002, 0x0036 }, + { 0x00, 0x01, 0, 0x03, 0x0003, 0x000a }, + { 0x00, 0x01, 0, 0x03, 0x0003, 0x000c }, + { 0x00, 0x02, 0, 0x03, 0x0003, 0x000e }, + { 0x00, 0x02, 0, 0x03, 0x0003, 0x0012 }, + { 0x00, 0x03, 0, 0x03, 0x0003, 0x0016 }, + { 0x00, 0x03, 0, 0x03, 0x0003, 0x001e }, + { 0x00, 0x04, 0, 0x03, 0x0003, 0x0026 }, + { 0x00, 0x04, 0, 0x03, 0x0003, 0x0036 }, + { 0x00, 0x01, 0, 0x03, 0x0004, 0x000a }, + { 0x00, 0x01, 0, 0x03, 0x0004, 0x000c }, + { 0x00, 0x02, 0, 0x03, 0x0004, 0x000e }, + { 0x00, 0x02, 0, 0x03, 0x0004, 0x0012 }, + { 0x00, 0x03, 0, 0x03, 0x0004, 0x0016 }, + { 0x00, 0x03, 0, 0x03, 0x0004, 0x001e }, + { 0x00, 0x04, 0, 0x03, 0x0004, 0x0026 }, + { 0x00, 0x04, 0, 0x03, 0x0004, 0x0036 }, + { 0x00, 0x01, 0, 0x03, 0x0005, 0x000a }, + { 0x00, 0x01, 0, 0x03, 0x0005, 0x000c }, + { 0x00, 0x02, 0, 0x03, 0x0005, 0x000e }, + { 0x00, 0x02, 0, 0x03, 0x0005, 0x0012 }, + { 0x00, 0x03, 0, 0x03, 0x0005, 0x0016 }, + { 0x00, 0x03, 0, 0x03, 0x0005, 0x001e }, + { 0x00, 0x04, 0, 0x03, 0x0005, 0x0026 }, + { 0x00, 0x04, 0, 0x03, 0x0005, 0x0036 }, + { 0x01, 0x01, 0, 0x03, 0x0006, 0x000a }, + { 0x01, 0x01, 0, 0x03, 0x0006, 0x000c }, + { 0x01, 0x02, 0, 0x03, 0x0006, 0x000e }, + { 0x01, 0x02, 0, 0x03, 0x0006, 0x0012 }, + { 0x01, 0x03, 0, 0x03, 0x0006, 0x0016 }, + { 0x01, 0x03, 0, 0x03, 0x0006, 0x001e }, + { 0x01, 0x04, 0, 0x03, 0x0006, 0x0026 }, + { 0x01, 0x04, 0, 0x03, 0x0006, 0x0036 }, + { 0x01, 0x01, 0, 0x03, 0x0008, 0x000a }, + { 0x01, 0x01, 0, 0x03, 0x0008, 0x000c }, + { 0x01, 0x02, 0, 0x03, 0x0008, 0x000e }, + { 0x01, 0x02, 0, 0x03, 0x0008, 0x0012 }, + { 0x01, 0x03, 0, 0x03, 0x0008, 0x0016 }, + { 0x01, 0x03, 0, 0x03, 0x0008, 0x001e }, + { 0x01, 0x04, 0, 0x03, 0x0008, 0x0026 }, + { 0x01, 0x04, 0, 0x03, 0x0008, 0x0036 }, + { 0x00, 0x00, -1, 0x00, 0x0000, 0x0002 }, + { 0x00, 0x00, -1, 0x01, 0x0000, 0x0003 }, + { 0x00, 0x00, -1, 0x02, 0x0000, 0x0004 }, + { 0x00, 0x00, -1, 0x03, 0x0000, 0x0005 }, + { 0x00, 0x00, -1, 0x03, 0x0000, 0x0006 }, + { 0x00, 0x00, -1, 0x03, 0x0000, 0x0007 }, + { 0x00, 0x00, -1, 0x03, 0x0000, 0x0008 }, + { 0x00, 0x00, -1, 0x03, 0x0000, 0x0009 }, + { 0x00, 0x00, -1, 0x00, 0x0001, 0x0002 }, + { 0x00, 0x00, -1, 0x01, 0x0001, 0x0003 }, + { 0x00, 0x00, -1, 0x02, 0x0001, 0x0004 }, + { 0x00, 0x00, -1, 0x03, 0x0001, 0x0005 }, + { 0x00, 0x00, -1, 0x03, 0x0001, 0x0006 }, + { 0x00, 0x00, -1, 0x03, 0x0001, 0x0007 }, + { 0x00, 0x00, -1, 0x03, 0x0001, 0x0008 }, + { 0x00, 0x00, -1, 0x03, 0x0001, 0x0009 }, + { 0x00, 0x00, -1, 0x00, 0x0002, 0x0002 }, + { 0x00, 0x00, -1, 0x01, 0x0002, 0x0003 }, + { 0x00, 0x00, -1, 0x02, 0x0002, 0x0004 }, + { 0x00, 0x00, -1, 0x03, 0x0002, 0x0005 }, + { 0x00, 0x00, -1, 0x03, 0x0002, 0x0006 }, + { 0x00, 0x00, -1, 0x03, 0x0002, 0x0007 }, + { 0x00, 0x00, -1, 0x03, 0x0002, 0x0008 }, + { 0x00, 0x00, -1, 0x03, 0x0002, 0x0009 }, + { 0x00, 0x00, -1, 0x00, 0x0003, 0x0002 }, + { 0x00, 0x00, -1, 0x01, 0x0003, 0x0003 }, + { 0x00, 0x00, -1, 0x02, 0x0003, 0x0004 }, + { 0x00, 0x00, -1, 0x03, 0x0003, 0x0005 }, + { 0x00, 0x00, -1, 0x03, 0x0003, 0x0006 }, + { 0x00, 0x00, -1, 0x03, 0x0003, 0x0007 }, + { 0x00, 0x00, -1, 0x03, 0x0003, 0x0008 }, + { 0x00, 0x00, -1, 0x03, 0x0003, 0x0009 }, + { 0x00, 0x00, -1, 0x00, 0x0004, 0x0002 }, + { 0x00, 0x00, -1, 0x01, 0x0004, 0x0003 }, + { 0x00, 0x00, -1, 0x02, 0x0004, 0x0004 }, + { 0x00, 0x00, -1, 0x03, 0x0004, 0x0005 }, + { 0x00, 0x00, -1, 0x03, 0x0004, 0x0006 }, + { 0x00, 0x00, -1, 0x03, 0x0004, 0x0007 }, + { 0x00, 0x00, -1, 0x03, 0x0004, 0x0008 }, + { 0x00, 0x00, -1, 0x03, 0x0004, 0x0009 }, + { 0x00, 0x00, -1, 0x00, 0x0005, 0x0002 }, + { 0x00, 0x00, -1, 0x01, 0x0005, 0x0003 }, + { 0x00, 0x00, -1, 0x02, 0x0005, 0x0004 }, + { 0x00, 0x00, -1, 0x03, 0x0005, 0x0005 }, + { 0x00, 0x00, -1, 0x03, 0x0005, 0x0006 }, + { 0x00, 0x00, -1, 0x03, 0x0005, 0x0007 }, + { 0x00, 0x00, -1, 0x03, 0x0005, 0x0008 }, + { 0x00, 0x00, -1, 0x03, 0x0005, 0x0009 }, + { 0x01, 0x00, -1, 0x00, 0x0006, 0x0002 }, + { 0x01, 0x00, -1, 0x01, 0x0006, 0x0003 }, + { 0x01, 0x00, -1, 0x02, 0x0006, 0x0004 }, + { 0x01, 0x00, -1, 0x03, 0x0006, 0x0005 }, + { 0x01, 0x00, -1, 0x03, 0x0006, 0x0006 }, + { 0x01, 0x00, -1, 0x03, 0x0006, 0x0007 }, + { 0x01, 0x00, -1, 0x03, 0x0006, 0x0008 }, + { 0x01, 0x00, -1, 0x03, 0x0006, 0x0009 }, + { 0x01, 0x00, -1, 0x00, 0x0008, 0x0002 }, + { 0x01, 0x00, -1, 0x01, 0x0008, 0x0003 }, + { 0x01, 0x00, -1, 0x02, 0x0008, 0x0004 }, + { 0x01, 0x00, -1, 0x03, 0x0008, 0x0005 }, + { 0x01, 0x00, -1, 0x03, 0x0008, 0x0006 }, + { 0x01, 0x00, -1, 0x03, 0x0008, 0x0007 }, + { 0x01, 0x00, -1, 0x03, 0x0008, 0x0008 }, + { 0x01, 0x00, -1, 0x03, 0x0008, 0x0009 }, + { 0x00, 0x01, -1, 0x03, 0x0000, 0x000a }, + { 0x00, 0x01, -1, 0x03, 0x0000, 0x000c }, + { 0x00, 0x02, -1, 0x03, 0x0000, 0x000e }, + { 0x00, 0x02, -1, 0x03, 0x0000, 0x0012 }, + { 0x00, 0x03, -1, 0x03, 0x0000, 0x0016 }, + { 0x00, 0x03, -1, 0x03, 0x0000, 0x001e }, + { 0x00, 0x04, -1, 0x03, 0x0000, 0x0026 }, + { 0x00, 0x04, -1, 0x03, 0x0000, 0x0036 }, + { 0x00, 0x01, -1, 0x03, 0x0001, 0x000a }, + { 0x00, 0x01, -1, 0x03, 0x0001, 0x000c }, + { 0x00, 0x02, -1, 0x03, 0x0001, 0x000e }, + { 0x00, 0x02, -1, 0x03, 0x0001, 0x0012 }, + { 0x00, 0x03, -1, 0x03, 0x0001, 0x0016 }, + { 0x00, 0x03, -1, 0x03, 0x0001, 0x001e }, + { 0x00, 0x04, -1, 0x03, 0x0001, 0x0026 }, + { 0x00, 0x04, -1, 0x03, 0x0001, 0x0036 }, + { 0x00, 0x01, -1, 0x03, 0x0002, 0x000a }, + { 0x00, 0x01, -1, 0x03, 0x0002, 0x000c }, + { 0x00, 0x02, -1, 0x03, 0x0002, 0x000e }, + { 0x00, 0x02, -1, 0x03, 0x0002, 0x0012 }, + { 0x00, 0x03, -1, 0x03, 0x0002, 0x0016 }, + { 0x00, 0x03, -1, 0x03, 0x0002, 0x001e }, + { 0x00, 0x04, -1, 0x03, 0x0002, 0x0026 }, + { 0x00, 0x04, -1, 0x03, 0x0002, 0x0036 }, + { 0x00, 0x01, -1, 0x03, 0x0003, 0x000a }, + { 0x00, 0x01, -1, 0x03, 0x0003, 0x000c }, + { 0x00, 0x02, -1, 0x03, 0x0003, 0x000e }, + { 0x00, 0x02, -1, 0x03, 0x0003, 0x0012 }, + { 0x00, 0x03, -1, 0x03, 0x0003, 0x0016 }, + { 0x00, 0x03, -1, 0x03, 0x0003, 0x001e }, + { 0x00, 0x04, -1, 0x03, 0x0003, 0x0026 }, + { 0x00, 0x04, -1, 0x03, 0x0003, 0x0036 }, + { 0x00, 0x01, -1, 0x03, 0x0004, 0x000a }, + { 0x00, 0x01, -1, 0x03, 0x0004, 0x000c }, + { 0x00, 0x02, -1, 0x03, 0x0004, 0x000e }, + { 0x00, 0x02, -1, 0x03, 0x0004, 0x0012 }, + { 0x00, 0x03, -1, 0x03, 0x0004, 0x0016 }, + { 0x00, 0x03, -1, 0x03, 0x0004, 0x001e }, + { 0x00, 0x04, -1, 0x03, 0x0004, 0x0026 }, + { 0x00, 0x04, -1, 0x03, 0x0004, 0x0036 }, + { 0x00, 0x01, -1, 0x03, 0x0005, 0x000a }, + { 0x00, 0x01, -1, 0x03, 0x0005, 0x000c }, + { 0x00, 0x02, -1, 0x03, 0x0005, 0x000e }, + { 0x00, 0x02, -1, 0x03, 0x0005, 0x0012 }, + { 0x00, 0x03, -1, 0x03, 0x0005, 0x0016 }, + { 0x00, 0x03, -1, 0x03, 0x0005, 0x001e }, + { 0x00, 0x04, -1, 0x03, 0x0005, 0x0026 }, + { 0x00, 0x04, -1, 0x03, 0x0005, 0x0036 }, + { 0x01, 0x01, -1, 0x03, 0x0006, 0x000a }, + { 0x01, 0x01, -1, 0x03, 0x0006, 0x000c }, + { 0x01, 0x02, -1, 0x03, 0x0006, 0x000e }, + { 0x01, 0x02, -1, 0x03, 0x0006, 0x0012 }, + { 0x01, 0x03, -1, 0x03, 0x0006, 0x0016 }, + { 0x01, 0x03, -1, 0x03, 0x0006, 0x001e }, + { 0x01, 0x04, -1, 0x03, 0x0006, 0x0026 }, + { 0x01, 0x04, -1, 0x03, 0x0006, 0x0036 }, + { 0x01, 0x01, -1, 0x03, 0x0008, 0x000a }, + { 0x01, 0x01, -1, 0x03, 0x0008, 0x000c }, + { 0x01, 0x02, -1, 0x03, 0x0008, 0x000e }, + { 0x01, 0x02, -1, 0x03, 0x0008, 0x0012 }, + { 0x01, 0x03, -1, 0x03, 0x0008, 0x0016 }, + { 0x01, 0x03, -1, 0x03, 0x0008, 0x001e }, + { 0x01, 0x04, -1, 0x03, 0x0008, 0x0026 }, + { 0x01, 0x04, -1, 0x03, 0x0008, 0x0036 }, + { 0x02, 0x00, -1, 0x00, 0x000a, 0x0002 }, + { 0x02, 0x00, -1, 0x01, 0x000a, 0x0003 }, + { 0x02, 0x00, -1, 0x02, 0x000a, 0x0004 }, + { 0x02, 0x00, -1, 0x03, 0x000a, 0x0005 }, + { 0x02, 0x00, -1, 0x03, 0x000a, 0x0006 }, + { 0x02, 0x00, -1, 0x03, 0x000a, 0x0007 }, + { 0x02, 0x00, -1, 0x03, 0x000a, 0x0008 }, + { 0x02, 0x00, -1, 0x03, 0x000a, 0x0009 }, + { 0x02, 0x00, -1, 0x00, 0x000e, 0x0002 }, + { 0x02, 0x00, -1, 0x01, 0x000e, 0x0003 }, + { 0x02, 0x00, -1, 0x02, 0x000e, 0x0004 }, + { 0x02, 0x00, -1, 0x03, 0x000e, 0x0005 }, + { 0x02, 0x00, -1, 0x03, 0x000e, 0x0006 }, + { 0x02, 0x00, -1, 0x03, 0x000e, 0x0007 }, + { 0x02, 0x00, -1, 0x03, 0x000e, 0x0008 }, + { 0x02, 0x00, -1, 0x03, 0x000e, 0x0009 }, + { 0x03, 0x00, -1, 0x00, 0x0012, 0x0002 }, + { 0x03, 0x00, -1, 0x01, 0x0012, 0x0003 }, + { 0x03, 0x00, -1, 0x02, 0x0012, 0x0004 }, + { 0x03, 0x00, -1, 0x03, 0x0012, 0x0005 }, + { 0x03, 0x00, -1, 0x03, 0x0012, 0x0006 }, + { 0x03, 0x00, -1, 0x03, 0x0012, 0x0007 }, + { 0x03, 0x00, -1, 0x03, 0x0012, 0x0008 }, + { 0x03, 0x00, -1, 0x03, 0x0012, 0x0009 }, + { 0x03, 0x00, -1, 0x00, 0x001a, 0x0002 }, + { 0x03, 0x00, -1, 0x01, 0x001a, 0x0003 }, + { 0x03, 0x00, -1, 0x02, 0x001a, 0x0004 }, + { 0x03, 0x00, -1, 0x03, 0x001a, 0x0005 }, + { 0x03, 0x00, -1, 0x03, 0x001a, 0x0006 }, + { 0x03, 0x00, -1, 0x03, 0x001a, 0x0007 }, + { 0x03, 0x00, -1, 0x03, 0x001a, 0x0008 }, + { 0x03, 0x00, -1, 0x03, 0x001a, 0x0009 }, + { 0x04, 0x00, -1, 0x00, 0x0022, 0x0002 }, + { 0x04, 0x00, -1, 0x01, 0x0022, 0x0003 }, + { 0x04, 0x00, -1, 0x02, 0x0022, 0x0004 }, + { 0x04, 0x00, -1, 0x03, 0x0022, 0x0005 }, + { 0x04, 0x00, -1, 0x03, 0x0022, 0x0006 }, + { 0x04, 0x00, -1, 0x03, 0x0022, 0x0007 }, + { 0x04, 0x00, -1, 0x03, 0x0022, 0x0008 }, + { 0x04, 0x00, -1, 0x03, 0x0022, 0x0009 }, + { 0x04, 0x00, -1, 0x00, 0x0032, 0x0002 }, + { 0x04, 0x00, -1, 0x01, 0x0032, 0x0003 }, + { 0x04, 0x00, -1, 0x02, 0x0032, 0x0004 }, + { 0x04, 0x00, -1, 0x03, 0x0032, 0x0005 }, + { 0x04, 0x00, -1, 0x03, 0x0032, 0x0006 }, + { 0x04, 0x00, -1, 0x03, 0x0032, 0x0007 }, + { 0x04, 0x00, -1, 0x03, 0x0032, 0x0008 }, + { 0x04, 0x00, -1, 0x03, 0x0032, 0x0009 }, + { 0x05, 0x00, -1, 0x00, 0x0042, 0x0002 }, + { 0x05, 0x00, -1, 0x01, 0x0042, 0x0003 }, + { 0x05, 0x00, -1, 0x02, 0x0042, 0x0004 }, + { 0x05, 0x00, -1, 0x03, 0x0042, 0x0005 }, + { 0x05, 0x00, -1, 0x03, 0x0042, 0x0006 }, + { 0x05, 0x00, -1, 0x03, 0x0042, 0x0007 }, + { 0x05, 0x00, -1, 0x03, 0x0042, 0x0008 }, + { 0x05, 0x00, -1, 0x03, 0x0042, 0x0009 }, + { 0x05, 0x00, -1, 0x00, 0x0062, 0x0002 }, + { 0x05, 0x00, -1, 0x01, 0x0062, 0x0003 }, + { 0x05, 0x00, -1, 0x02, 0x0062, 0x0004 }, + { 0x05, 0x00, -1, 0x03, 0x0062, 0x0005 }, + { 0x05, 0x00, -1, 0x03, 0x0062, 0x0006 }, + { 0x05, 0x00, -1, 0x03, 0x0062, 0x0007 }, + { 0x05, 0x00, -1, 0x03, 0x0062, 0x0008 }, + { 0x05, 0x00, -1, 0x03, 0x0062, 0x0009 }, + { 0x02, 0x01, -1, 0x03, 0x000a, 0x000a }, + { 0x02, 0x01, -1, 0x03, 0x000a, 0x000c }, + { 0x02, 0x02, -1, 0x03, 0x000a, 0x000e }, + { 0x02, 0x02, -1, 0x03, 0x000a, 0x0012 }, + { 0x02, 0x03, -1, 0x03, 0x000a, 0x0016 }, + { 0x02, 0x03, -1, 0x03, 0x000a, 0x001e }, + { 0x02, 0x04, -1, 0x03, 0x000a, 0x0026 }, + { 0x02, 0x04, -1, 0x03, 0x000a, 0x0036 }, + { 0x02, 0x01, -1, 0x03, 0x000e, 0x000a }, + { 0x02, 0x01, -1, 0x03, 0x000e, 0x000c }, + { 0x02, 0x02, -1, 0x03, 0x000e, 0x000e }, + { 0x02, 0x02, -1, 0x03, 0x000e, 0x0012 }, + { 0x02, 0x03, -1, 0x03, 0x000e, 0x0016 }, + { 0x02, 0x03, -1, 0x03, 0x000e, 0x001e }, + { 0x02, 0x04, -1, 0x03, 0x000e, 0x0026 }, + { 0x02, 0x04, -1, 0x03, 0x000e, 0x0036 }, + { 0x03, 0x01, -1, 0x03, 0x0012, 0x000a }, + { 0x03, 0x01, -1, 0x03, 0x0012, 0x000c }, + { 0x03, 0x02, -1, 0x03, 0x0012, 0x000e }, + { 0x03, 0x02, -1, 0x03, 0x0012, 0x0012 }, + { 0x03, 0x03, -1, 0x03, 0x0012, 0x0016 }, + { 0x03, 0x03, -1, 0x03, 0x0012, 0x001e }, + { 0x03, 0x04, -1, 0x03, 0x0012, 0x0026 }, + { 0x03, 0x04, -1, 0x03, 0x0012, 0x0036 }, + { 0x03, 0x01, -1, 0x03, 0x001a, 0x000a }, + { 0x03, 0x01, -1, 0x03, 0x001a, 0x000c }, + { 0x03, 0x02, -1, 0x03, 0x001a, 0x000e }, + { 0x03, 0x02, -1, 0x03, 0x001a, 0x0012 }, + { 0x03, 0x03, -1, 0x03, 0x001a, 0x0016 }, + { 0x03, 0x03, -1, 0x03, 0x001a, 0x001e }, + { 0x03, 0x04, -1, 0x03, 0x001a, 0x0026 }, + { 0x03, 0x04, -1, 0x03, 0x001a, 0x0036 }, + { 0x04, 0x01, -1, 0x03, 0x0022, 0x000a }, + { 0x04, 0x01, -1, 0x03, 0x0022, 0x000c }, + { 0x04, 0x02, -1, 0x03, 0x0022, 0x000e }, + { 0x04, 0x02, -1, 0x03, 0x0022, 0x0012 }, + { 0x04, 0x03, -1, 0x03, 0x0022, 0x0016 }, + { 0x04, 0x03, -1, 0x03, 0x0022, 0x001e }, + { 0x04, 0x04, -1, 0x03, 0x0022, 0x0026 }, + { 0x04, 0x04, -1, 0x03, 0x0022, 0x0036 }, + { 0x04, 0x01, -1, 0x03, 0x0032, 0x000a }, + { 0x04, 0x01, -1, 0x03, 0x0032, 0x000c }, + { 0x04, 0x02, -1, 0x03, 0x0032, 0x000e }, + { 0x04, 0x02, -1, 0x03, 0x0032, 0x0012 }, + { 0x04, 0x03, -1, 0x03, 0x0032, 0x0016 }, + { 0x04, 0x03, -1, 0x03, 0x0032, 0x001e }, + { 0x04, 0x04, -1, 0x03, 0x0032, 0x0026 }, + { 0x04, 0x04, -1, 0x03, 0x0032, 0x0036 }, + { 0x05, 0x01, -1, 0x03, 0x0042, 0x000a }, + { 0x05, 0x01, -1, 0x03, 0x0042, 0x000c }, + { 0x05, 0x02, -1, 0x03, 0x0042, 0x000e }, + { 0x05, 0x02, -1, 0x03, 0x0042, 0x0012 }, + { 0x05, 0x03, -1, 0x03, 0x0042, 0x0016 }, + { 0x05, 0x03, -1, 0x03, 0x0042, 0x001e }, + { 0x05, 0x04, -1, 0x03, 0x0042, 0x0026 }, + { 0x05, 0x04, -1, 0x03, 0x0042, 0x0036 }, + { 0x05, 0x01, -1, 0x03, 0x0062, 0x000a }, + { 0x05, 0x01, -1, 0x03, 0x0062, 0x000c }, + { 0x05, 0x02, -1, 0x03, 0x0062, 0x000e }, + { 0x05, 0x02, -1, 0x03, 0x0062, 0x0012 }, + { 0x05, 0x03, -1, 0x03, 0x0062, 0x0016 }, + { 0x05, 0x03, -1, 0x03, 0x0062, 0x001e }, + { 0x05, 0x04, -1, 0x03, 0x0062, 0x0026 }, + { 0x05, 0x04, -1, 0x03, 0x0062, 0x0036 }, + { 0x00, 0x05, -1, 0x03, 0x0000, 0x0046 }, + { 0x00, 0x05, -1, 0x03, 0x0000, 0x0066 }, + { 0x00, 0x06, -1, 0x03, 0x0000, 0x0086 }, + { 0x00, 0x07, -1, 0x03, 0x0000, 0x00c6 }, + { 0x00, 0x08, -1, 0x03, 0x0000, 0x0146 }, + { 0x00, 0x09, -1, 0x03, 0x0000, 0x0246 }, + { 0x00, 0x0a, -1, 0x03, 0x0000, 0x0446 }, + { 0x00, 0x18, -1, 0x03, 0x0000, 0x0846 }, + { 0x00, 0x05, -1, 0x03, 0x0001, 0x0046 }, + { 0x00, 0x05, -1, 0x03, 0x0001, 0x0066 }, + { 0x00, 0x06, -1, 0x03, 0x0001, 0x0086 }, + { 0x00, 0x07, -1, 0x03, 0x0001, 0x00c6 }, + { 0x00, 0x08, -1, 0x03, 0x0001, 0x0146 }, + { 0x00, 0x09, -1, 0x03, 0x0001, 0x0246 }, + { 0x00, 0x0a, -1, 0x03, 0x0001, 0x0446 }, + { 0x00, 0x18, -1, 0x03, 0x0001, 0x0846 }, + { 0x00, 0x05, -1, 0x03, 0x0002, 0x0046 }, + { 0x00, 0x05, -1, 0x03, 0x0002, 0x0066 }, + { 0x00, 0x06, -1, 0x03, 0x0002, 0x0086 }, + { 0x00, 0x07, -1, 0x03, 0x0002, 0x00c6 }, + { 0x00, 0x08, -1, 0x03, 0x0002, 0x0146 }, + { 0x00, 0x09, -1, 0x03, 0x0002, 0x0246 }, + { 0x00, 0x0a, -1, 0x03, 0x0002, 0x0446 }, + { 0x00, 0x18, -1, 0x03, 0x0002, 0x0846 }, + { 0x00, 0x05, -1, 0x03, 0x0003, 0x0046 }, + { 0x00, 0x05, -1, 0x03, 0x0003, 0x0066 }, + { 0x00, 0x06, -1, 0x03, 0x0003, 0x0086 }, + { 0x00, 0x07, -1, 0x03, 0x0003, 0x00c6 }, + { 0x00, 0x08, -1, 0x03, 0x0003, 0x0146 }, + { 0x00, 0x09, -1, 0x03, 0x0003, 0x0246 }, + { 0x00, 0x0a, -1, 0x03, 0x0003, 0x0446 }, + { 0x00, 0x18, -1, 0x03, 0x0003, 0x0846 }, + { 0x00, 0x05, -1, 0x03, 0x0004, 0x0046 }, + { 0x00, 0x05, -1, 0x03, 0x0004, 0x0066 }, + { 0x00, 0x06, -1, 0x03, 0x0004, 0x0086 }, + { 0x00, 0x07, -1, 0x03, 0x0004, 0x00c6 }, + { 0x00, 0x08, -1, 0x03, 0x0004, 0x0146 }, + { 0x00, 0x09, -1, 0x03, 0x0004, 0x0246 }, + { 0x00, 0x0a, -1, 0x03, 0x0004, 0x0446 }, + { 0x00, 0x18, -1, 0x03, 0x0004, 0x0846 }, + { 0x00, 0x05, -1, 0x03, 0x0005, 0x0046 }, + { 0x00, 0x05, -1, 0x03, 0x0005, 0x0066 }, + { 0x00, 0x06, -1, 0x03, 0x0005, 0x0086 }, + { 0x00, 0x07, -1, 0x03, 0x0005, 0x00c6 }, + { 0x00, 0x08, -1, 0x03, 0x0005, 0x0146 }, + { 0x00, 0x09, -1, 0x03, 0x0005, 0x0246 }, + { 0x00, 0x0a, -1, 0x03, 0x0005, 0x0446 }, + { 0x00, 0x18, -1, 0x03, 0x0005, 0x0846 }, + { 0x01, 0x05, -1, 0x03, 0x0006, 0x0046 }, + { 0x01, 0x05, -1, 0x03, 0x0006, 0x0066 }, + { 0x01, 0x06, -1, 0x03, 0x0006, 0x0086 }, + { 0x01, 0x07, -1, 0x03, 0x0006, 0x00c6 }, + { 0x01, 0x08, -1, 0x03, 0x0006, 0x0146 }, + { 0x01, 0x09, -1, 0x03, 0x0006, 0x0246 }, + { 0x01, 0x0a, -1, 0x03, 0x0006, 0x0446 }, + { 0x01, 0x18, -1, 0x03, 0x0006, 0x0846 }, + { 0x01, 0x05, -1, 0x03, 0x0008, 0x0046 }, + { 0x01, 0x05, -1, 0x03, 0x0008, 0x0066 }, + { 0x01, 0x06, -1, 0x03, 0x0008, 0x0086 }, + { 0x01, 0x07, -1, 0x03, 0x0008, 0x00c6 }, + { 0x01, 0x08, -1, 0x03, 0x0008, 0x0146 }, + { 0x01, 0x09, -1, 0x03, 0x0008, 0x0246 }, + { 0x01, 0x0a, -1, 0x03, 0x0008, 0x0446 }, + { 0x01, 0x18, -1, 0x03, 0x0008, 0x0846 }, + { 0x06, 0x00, -1, 0x00, 0x0082, 0x0002 }, + { 0x06, 0x00, -1, 0x01, 0x0082, 0x0003 }, + { 0x06, 0x00, -1, 0x02, 0x0082, 0x0004 }, + { 0x06, 0x00, -1, 0x03, 0x0082, 0x0005 }, + { 0x06, 0x00, -1, 0x03, 0x0082, 0x0006 }, + { 0x06, 0x00, -1, 0x03, 0x0082, 0x0007 }, + { 0x06, 0x00, -1, 0x03, 0x0082, 0x0008 }, + { 0x06, 0x00, -1, 0x03, 0x0082, 0x0009 }, + { 0x07, 0x00, -1, 0x00, 0x00c2, 0x0002 }, + { 0x07, 0x00, -1, 0x01, 0x00c2, 0x0003 }, + { 0x07, 0x00, -1, 0x02, 0x00c2, 0x0004 }, + { 0x07, 0x00, -1, 0x03, 0x00c2, 0x0005 }, + { 0x07, 0x00, -1, 0x03, 0x00c2, 0x0006 }, + { 0x07, 0x00, -1, 0x03, 0x00c2, 0x0007 }, + { 0x07, 0x00, -1, 0x03, 0x00c2, 0x0008 }, + { 0x07, 0x00, -1, 0x03, 0x00c2, 0x0009 }, + { 0x08, 0x00, -1, 0x00, 0x0142, 0x0002 }, + { 0x08, 0x00, -1, 0x01, 0x0142, 0x0003 }, + { 0x08, 0x00, -1, 0x02, 0x0142, 0x0004 }, + { 0x08, 0x00, -1, 0x03, 0x0142, 0x0005 }, + { 0x08, 0x00, -1, 0x03, 0x0142, 0x0006 }, + { 0x08, 0x00, -1, 0x03, 0x0142, 0x0007 }, + { 0x08, 0x00, -1, 0x03, 0x0142, 0x0008 }, + { 0x08, 0x00, -1, 0x03, 0x0142, 0x0009 }, + { 0x09, 0x00, -1, 0x00, 0x0242, 0x0002 }, + { 0x09, 0x00, -1, 0x01, 0x0242, 0x0003 }, + { 0x09, 0x00, -1, 0x02, 0x0242, 0x0004 }, + { 0x09, 0x00, -1, 0x03, 0x0242, 0x0005 }, + { 0x09, 0x00, -1, 0x03, 0x0242, 0x0006 }, + { 0x09, 0x00, -1, 0x03, 0x0242, 0x0007 }, + { 0x09, 0x00, -1, 0x03, 0x0242, 0x0008 }, + { 0x09, 0x00, -1, 0x03, 0x0242, 0x0009 }, + { 0x0a, 0x00, -1, 0x00, 0x0442, 0x0002 }, + { 0x0a, 0x00, -1, 0x01, 0x0442, 0x0003 }, + { 0x0a, 0x00, -1, 0x02, 0x0442, 0x0004 }, + { 0x0a, 0x00, -1, 0x03, 0x0442, 0x0005 }, + { 0x0a, 0x00, -1, 0x03, 0x0442, 0x0006 }, + { 0x0a, 0x00, -1, 0x03, 0x0442, 0x0007 }, + { 0x0a, 0x00, -1, 0x03, 0x0442, 0x0008 }, + { 0x0a, 0x00, -1, 0x03, 0x0442, 0x0009 }, + { 0x0c, 0x00, -1, 0x00, 0x0842, 0x0002 }, + { 0x0c, 0x00, -1, 0x01, 0x0842, 0x0003 }, + { 0x0c, 0x00, -1, 0x02, 0x0842, 0x0004 }, + { 0x0c, 0x00, -1, 0x03, 0x0842, 0x0005 }, + { 0x0c, 0x00, -1, 0x03, 0x0842, 0x0006 }, + { 0x0c, 0x00, -1, 0x03, 0x0842, 0x0007 }, + { 0x0c, 0x00, -1, 0x03, 0x0842, 0x0008 }, + { 0x0c, 0x00, -1, 0x03, 0x0842, 0x0009 }, + { 0x0e, 0x00, -1, 0x00, 0x1842, 0x0002 }, + { 0x0e, 0x00, -1, 0x01, 0x1842, 0x0003 }, + { 0x0e, 0x00, -1, 0x02, 0x1842, 0x0004 }, + { 0x0e, 0x00, -1, 0x03, 0x1842, 0x0005 }, + { 0x0e, 0x00, -1, 0x03, 0x1842, 0x0006 }, + { 0x0e, 0x00, -1, 0x03, 0x1842, 0x0007 }, + { 0x0e, 0x00, -1, 0x03, 0x1842, 0x0008 }, + { 0x0e, 0x00, -1, 0x03, 0x1842, 0x0009 }, + { 0x18, 0x00, -1, 0x00, 0x5842, 0x0002 }, + { 0x18, 0x00, -1, 0x01, 0x5842, 0x0003 }, + { 0x18, 0x00, -1, 0x02, 0x5842, 0x0004 }, + { 0x18, 0x00, -1, 0x03, 0x5842, 0x0005 }, + { 0x18, 0x00, -1, 0x03, 0x5842, 0x0006 }, + { 0x18, 0x00, -1, 0x03, 0x5842, 0x0007 }, + { 0x18, 0x00, -1, 0x03, 0x5842, 0x0008 }, + { 0x18, 0x00, -1, 0x03, 0x5842, 0x0009 }, + { 0x02, 0x05, -1, 0x03, 0x000a, 0x0046 }, + { 0x02, 0x05, -1, 0x03, 0x000a, 0x0066 }, + { 0x02, 0x06, -1, 0x03, 0x000a, 0x0086 }, + { 0x02, 0x07, -1, 0x03, 0x000a, 0x00c6 }, + { 0x02, 0x08, -1, 0x03, 0x000a, 0x0146 }, + { 0x02, 0x09, -1, 0x03, 0x000a, 0x0246 }, + { 0x02, 0x0a, -1, 0x03, 0x000a, 0x0446 }, + { 0x02, 0x18, -1, 0x03, 0x000a, 0x0846 }, + { 0x02, 0x05, -1, 0x03, 0x000e, 0x0046 }, + { 0x02, 0x05, -1, 0x03, 0x000e, 0x0066 }, + { 0x02, 0x06, -1, 0x03, 0x000e, 0x0086 }, + { 0x02, 0x07, -1, 0x03, 0x000e, 0x00c6 }, + { 0x02, 0x08, -1, 0x03, 0x000e, 0x0146 }, + { 0x02, 0x09, -1, 0x03, 0x000e, 0x0246 }, + { 0x02, 0x0a, -1, 0x03, 0x000e, 0x0446 }, + { 0x02, 0x18, -1, 0x03, 0x000e, 0x0846 }, + { 0x03, 0x05, -1, 0x03, 0x0012, 0x0046 }, + { 0x03, 0x05, -1, 0x03, 0x0012, 0x0066 }, + { 0x03, 0x06, -1, 0x03, 0x0012, 0x0086 }, + { 0x03, 0x07, -1, 0x03, 0x0012, 0x00c6 }, + { 0x03, 0x08, -1, 0x03, 0x0012, 0x0146 }, + { 0x03, 0x09, -1, 0x03, 0x0012, 0x0246 }, + { 0x03, 0x0a, -1, 0x03, 0x0012, 0x0446 }, + { 0x03, 0x18, -1, 0x03, 0x0012, 0x0846 }, + { 0x03, 0x05, -1, 0x03, 0x001a, 0x0046 }, + { 0x03, 0x05, -1, 0x03, 0x001a, 0x0066 }, + { 0x03, 0x06, -1, 0x03, 0x001a, 0x0086 }, + { 0x03, 0x07, -1, 0x03, 0x001a, 0x00c6 }, + { 0x03, 0x08, -1, 0x03, 0x001a, 0x0146 }, + { 0x03, 0x09, -1, 0x03, 0x001a, 0x0246 }, + { 0x03, 0x0a, -1, 0x03, 0x001a, 0x0446 }, + { 0x03, 0x18, -1, 0x03, 0x001a, 0x0846 }, + { 0x04, 0x05, -1, 0x03, 0x0022, 0x0046 }, + { 0x04, 0x05, -1, 0x03, 0x0022, 0x0066 }, + { 0x04, 0x06, -1, 0x03, 0x0022, 0x0086 }, + { 0x04, 0x07, -1, 0x03, 0x0022, 0x00c6 }, + { 0x04, 0x08, -1, 0x03, 0x0022, 0x0146 }, + { 0x04, 0x09, -1, 0x03, 0x0022, 0x0246 }, + { 0x04, 0x0a, -1, 0x03, 0x0022, 0x0446 }, + { 0x04, 0x18, -1, 0x03, 0x0022, 0x0846 }, + { 0x04, 0x05, -1, 0x03, 0x0032, 0x0046 }, + { 0x04, 0x05, -1, 0x03, 0x0032, 0x0066 }, + { 0x04, 0x06, -1, 0x03, 0x0032, 0x0086 }, + { 0x04, 0x07, -1, 0x03, 0x0032, 0x00c6 }, + { 0x04, 0x08, -1, 0x03, 0x0032, 0x0146 }, + { 0x04, 0x09, -1, 0x03, 0x0032, 0x0246 }, + { 0x04, 0x0a, -1, 0x03, 0x0032, 0x0446 }, + { 0x04, 0x18, -1, 0x03, 0x0032, 0x0846 }, + { 0x05, 0x05, -1, 0x03, 0x0042, 0x0046 }, + { 0x05, 0x05, -1, 0x03, 0x0042, 0x0066 }, + { 0x05, 0x06, -1, 0x03, 0x0042, 0x0086 }, + { 0x05, 0x07, -1, 0x03, 0x0042, 0x00c6 }, + { 0x05, 0x08, -1, 0x03, 0x0042, 0x0146 }, + { 0x05, 0x09, -1, 0x03, 0x0042, 0x0246 }, + { 0x05, 0x0a, -1, 0x03, 0x0042, 0x0446 }, + { 0x05, 0x18, -1, 0x03, 0x0042, 0x0846 }, + { 0x05, 0x05, -1, 0x03, 0x0062, 0x0046 }, + { 0x05, 0x05, -1, 0x03, 0x0062, 0x0066 }, + { 0x05, 0x06, -1, 0x03, 0x0062, 0x0086 }, + { 0x05, 0x07, -1, 0x03, 0x0062, 0x00c6 }, + { 0x05, 0x08, -1, 0x03, 0x0062, 0x0146 }, + { 0x05, 0x09, -1, 0x03, 0x0062, 0x0246 }, + { 0x05, 0x0a, -1, 0x03, 0x0062, 0x0446 }, + { 0x05, 0x18, -1, 0x03, 0x0062, 0x0846 }, + { 0x06, 0x01, -1, 0x03, 0x0082, 0x000a }, + { 0x06, 0x01, -1, 0x03, 0x0082, 0x000c }, + { 0x06, 0x02, -1, 0x03, 0x0082, 0x000e }, + { 0x06, 0x02, -1, 0x03, 0x0082, 0x0012 }, + { 0x06, 0x03, -1, 0x03, 0x0082, 0x0016 }, + { 0x06, 0x03, -1, 0x03, 0x0082, 0x001e }, + { 0x06, 0x04, -1, 0x03, 0x0082, 0x0026 }, + { 0x06, 0x04, -1, 0x03, 0x0082, 0x0036 }, + { 0x07, 0x01, -1, 0x03, 0x00c2, 0x000a }, + { 0x07, 0x01, -1, 0x03, 0x00c2, 0x000c }, + { 0x07, 0x02, -1, 0x03, 0x00c2, 0x000e }, + { 0x07, 0x02, -1, 0x03, 0x00c2, 0x0012 }, + { 0x07, 0x03, -1, 0x03, 0x00c2, 0x0016 }, + { 0x07, 0x03, -1, 0x03, 0x00c2, 0x001e }, + { 0x07, 0x04, -1, 0x03, 0x00c2, 0x0026 }, + { 0x07, 0x04, -1, 0x03, 0x00c2, 0x0036 }, + { 0x08, 0x01, -1, 0x03, 0x0142, 0x000a }, + { 0x08, 0x01, -1, 0x03, 0x0142, 0x000c }, + { 0x08, 0x02, -1, 0x03, 0x0142, 0x000e }, + { 0x08, 0x02, -1, 0x03, 0x0142, 0x0012 }, + { 0x08, 0x03, -1, 0x03, 0x0142, 0x0016 }, + { 0x08, 0x03, -1, 0x03, 0x0142, 0x001e }, + { 0x08, 0x04, -1, 0x03, 0x0142, 0x0026 }, + { 0x08, 0x04, -1, 0x03, 0x0142, 0x0036 }, + { 0x09, 0x01, -1, 0x03, 0x0242, 0x000a }, + { 0x09, 0x01, -1, 0x03, 0x0242, 0x000c }, + { 0x09, 0x02, -1, 0x03, 0x0242, 0x000e }, + { 0x09, 0x02, -1, 0x03, 0x0242, 0x0012 }, + { 0x09, 0x03, -1, 0x03, 0x0242, 0x0016 }, + { 0x09, 0x03, -1, 0x03, 0x0242, 0x001e }, + { 0x09, 0x04, -1, 0x03, 0x0242, 0x0026 }, + { 0x09, 0x04, -1, 0x03, 0x0242, 0x0036 }, + { 0x0a, 0x01, -1, 0x03, 0x0442, 0x000a }, + { 0x0a, 0x01, -1, 0x03, 0x0442, 0x000c }, + { 0x0a, 0x02, -1, 0x03, 0x0442, 0x000e }, + { 0x0a, 0x02, -1, 0x03, 0x0442, 0x0012 }, + { 0x0a, 0x03, -1, 0x03, 0x0442, 0x0016 }, + { 0x0a, 0x03, -1, 0x03, 0x0442, 0x001e }, + { 0x0a, 0x04, -1, 0x03, 0x0442, 0x0026 }, + { 0x0a, 0x04, -1, 0x03, 0x0442, 0x0036 }, + { 0x0c, 0x01, -1, 0x03, 0x0842, 0x000a }, + { 0x0c, 0x01, -1, 0x03, 0x0842, 0x000c }, + { 0x0c, 0x02, -1, 0x03, 0x0842, 0x000e }, + { 0x0c, 0x02, -1, 0x03, 0x0842, 0x0012 }, + { 0x0c, 0x03, -1, 0x03, 0x0842, 0x0016 }, + { 0x0c, 0x03, -1, 0x03, 0x0842, 0x001e }, + { 0x0c, 0x04, -1, 0x03, 0x0842, 0x0026 }, + { 0x0c, 0x04, -1, 0x03, 0x0842, 0x0036 }, + { 0x0e, 0x01, -1, 0x03, 0x1842, 0x000a }, + { 0x0e, 0x01, -1, 0x03, 0x1842, 0x000c }, + { 0x0e, 0x02, -1, 0x03, 0x1842, 0x000e }, + { 0x0e, 0x02, -1, 0x03, 0x1842, 0x0012 }, + { 0x0e, 0x03, -1, 0x03, 0x1842, 0x0016 }, + { 0x0e, 0x03, -1, 0x03, 0x1842, 0x001e }, + { 0x0e, 0x04, -1, 0x03, 0x1842, 0x0026 }, + { 0x0e, 0x04, -1, 0x03, 0x1842, 0x0036 }, + { 0x18, 0x01, -1, 0x03, 0x5842, 0x000a }, + { 0x18, 0x01, -1, 0x03, 0x5842, 0x000c }, + { 0x18, 0x02, -1, 0x03, 0x5842, 0x000e }, + { 0x18, 0x02, -1, 0x03, 0x5842, 0x0012 }, + { 0x18, 0x03, -1, 0x03, 0x5842, 0x0016 }, + { 0x18, 0x03, -1, 0x03, 0x5842, 0x001e }, + { 0x18, 0x04, -1, 0x03, 0x5842, 0x0026 }, + { 0x18, 0x04, -1, 0x03, 0x5842, 0x0036 }, + { 0x06, 0x05, -1, 0x03, 0x0082, 0x0046 }, + { 0x06, 0x05, -1, 0x03, 0x0082, 0x0066 }, + { 0x06, 0x06, -1, 0x03, 0x0082, 0x0086 }, + { 0x06, 0x07, -1, 0x03, 0x0082, 0x00c6 }, + { 0x06, 0x08, -1, 0x03, 0x0082, 0x0146 }, + { 0x06, 0x09, -1, 0x03, 0x0082, 0x0246 }, + { 0x06, 0x0a, -1, 0x03, 0x0082, 0x0446 }, + { 0x06, 0x18, -1, 0x03, 0x0082, 0x0846 }, + { 0x07, 0x05, -1, 0x03, 0x00c2, 0x0046 }, + { 0x07, 0x05, -1, 0x03, 0x00c2, 0x0066 }, + { 0x07, 0x06, -1, 0x03, 0x00c2, 0x0086 }, + { 0x07, 0x07, -1, 0x03, 0x00c2, 0x00c6 }, + { 0x07, 0x08, -1, 0x03, 0x00c2, 0x0146 }, + { 0x07, 0x09, -1, 0x03, 0x00c2, 0x0246 }, + { 0x07, 0x0a, -1, 0x03, 0x00c2, 0x0446 }, + { 0x07, 0x18, -1, 0x03, 0x00c2, 0x0846 }, + { 0x08, 0x05, -1, 0x03, 0x0142, 0x0046 }, + { 0x08, 0x05, -1, 0x03, 0x0142, 0x0066 }, + { 0x08, 0x06, -1, 0x03, 0x0142, 0x0086 }, + { 0x08, 0x07, -1, 0x03, 0x0142, 0x00c6 }, + { 0x08, 0x08, -1, 0x03, 0x0142, 0x0146 }, + { 0x08, 0x09, -1, 0x03, 0x0142, 0x0246 }, + { 0x08, 0x0a, -1, 0x03, 0x0142, 0x0446 }, + { 0x08, 0x18, -1, 0x03, 0x0142, 0x0846 }, + { 0x09, 0x05, -1, 0x03, 0x0242, 0x0046 }, + { 0x09, 0x05, -1, 0x03, 0x0242, 0x0066 }, + { 0x09, 0x06, -1, 0x03, 0x0242, 0x0086 }, + { 0x09, 0x07, -1, 0x03, 0x0242, 0x00c6 }, + { 0x09, 0x08, -1, 0x03, 0x0242, 0x0146 }, + { 0x09, 0x09, -1, 0x03, 0x0242, 0x0246 }, + { 0x09, 0x0a, -1, 0x03, 0x0242, 0x0446 }, + { 0x09, 0x18, -1, 0x03, 0x0242, 0x0846 }, + { 0x0a, 0x05, -1, 0x03, 0x0442, 0x0046 }, + { 0x0a, 0x05, -1, 0x03, 0x0442, 0x0066 }, + { 0x0a, 0x06, -1, 0x03, 0x0442, 0x0086 }, + { 0x0a, 0x07, -1, 0x03, 0x0442, 0x00c6 }, + { 0x0a, 0x08, -1, 0x03, 0x0442, 0x0146 }, + { 0x0a, 0x09, -1, 0x03, 0x0442, 0x0246 }, + { 0x0a, 0x0a, -1, 0x03, 0x0442, 0x0446 }, + { 0x0a, 0x18, -1, 0x03, 0x0442, 0x0846 }, + { 0x0c, 0x05, -1, 0x03, 0x0842, 0x0046 }, + { 0x0c, 0x05, -1, 0x03, 0x0842, 0x0066 }, + { 0x0c, 0x06, -1, 0x03, 0x0842, 0x0086 }, + { 0x0c, 0x07, -1, 0x03, 0x0842, 0x00c6 }, + { 0x0c, 0x08, -1, 0x03, 0x0842, 0x0146 }, + { 0x0c, 0x09, -1, 0x03, 0x0842, 0x0246 }, + { 0x0c, 0x0a, -1, 0x03, 0x0842, 0x0446 }, + { 0x0c, 0x18, -1, 0x03, 0x0842, 0x0846 }, + { 0x0e, 0x05, -1, 0x03, 0x1842, 0x0046 }, + { 0x0e, 0x05, -1, 0x03, 0x1842, 0x0066 }, + { 0x0e, 0x06, -1, 0x03, 0x1842, 0x0086 }, + { 0x0e, 0x07, -1, 0x03, 0x1842, 0x00c6 }, + { 0x0e, 0x08, -1, 0x03, 0x1842, 0x0146 }, + { 0x0e, 0x09, -1, 0x03, 0x1842, 0x0246 }, + { 0x0e, 0x0a, -1, 0x03, 0x1842, 0x0446 }, + { 0x0e, 0x18, -1, 0x03, 0x1842, 0x0846 }, + { 0x18, 0x05, -1, 0x03, 0x5842, 0x0046 }, + { 0x18, 0x05, -1, 0x03, 0x5842, 0x0066 }, + { 0x18, 0x06, -1, 0x03, 0x5842, 0x0086 }, + { 0x18, 0x07, -1, 0x03, 0x5842, 0x00c6 }, + { 0x18, 0x08, -1, 0x03, 0x5842, 0x0146 }, + { 0x18, 0x09, -1, 0x03, 0x5842, 0x0246 }, + { 0x18, 0x0a, -1, 0x03, 0x5842, 0x0446 }, + { 0x18, 0x18, -1, 0x03, 0x5842, 0x0846 }, +}; diff --git a/packages/runtime/vendor/brotli/c/dec/state.c b/packages/runtime/vendor/brotli/c/dec/state.c new file mode 100644 index 000000000..dcf61b9eb --- /dev/null +++ b/packages/runtime/vendor/brotli/c/dec/state.c @@ -0,0 +1,186 @@ +/* Copyright 2015 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#include "state.h" + +#include "../common/dictionary.h" +#include "../common/platform.h" +#include "huffman.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#ifdef BROTLI_REPORTING +/* When BROTLI_REPORTING is defined extra reporting module have to be linked. */ +void BrotliDecoderOnStart(const BrotliDecoderState* s); +void BrotliDecoderOnFinish(const BrotliDecoderState* s); +#define BROTLI_DECODER_ON_START(s) BrotliDecoderOnStart(s); +#define BROTLI_DECODER_ON_FINISH(s) BrotliDecoderOnFinish(s); +#else +#if !defined(BROTLI_DECODER_ON_START) +#define BROTLI_DECODER_ON_START(s) (void)(s); +#endif +#if !defined(BROTLI_DECODER_ON_FINISH) +#define BROTLI_DECODER_ON_FINISH(s) (void)(s); +#endif +#endif + +BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s, + brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) { + BROTLI_DECODER_ON_START(s); + if (!alloc_func) { + s->alloc_func = BrotliDefaultAllocFunc; + s->free_func = BrotliDefaultFreeFunc; + s->memory_manager_opaque = 0; + } else { + s->alloc_func = alloc_func; + s->free_func = free_func; + s->memory_manager_opaque = opaque; + } + + s->error_code = 0; /* BROTLI_DECODER_NO_ERROR */ + + BrotliInitBitReader(&s->br); + s->state = BROTLI_STATE_UNINITED; + s->large_window = 0; + s->substate_metablock_header = BROTLI_STATE_METABLOCK_HEADER_NONE; + s->substate_uncompressed = BROTLI_STATE_UNCOMPRESSED_NONE; + s->substate_decode_uint8 = BROTLI_STATE_DECODE_UINT8_NONE; + s->substate_read_block_length = BROTLI_STATE_READ_BLOCK_LENGTH_NONE; + + s->buffer_length = 0; + s->loop_counter = 0; + s->pos = 0; + s->rb_roundtrips = 0; + s->partial_pos_out = 0; + s->used_input = 0; + + s->block_type_trees = NULL; + s->block_len_trees = NULL; + s->ringbuffer = NULL; + s->ringbuffer_size = 0; + s->new_ringbuffer_size = 0; + s->ringbuffer_mask = 0; + + s->context_map = NULL; + s->context_modes = NULL; + s->dist_context_map = NULL; + s->context_map_slice = NULL; + s->dist_context_map_slice = NULL; + + s->literal_hgroup.codes = NULL; + s->literal_hgroup.htrees = NULL; + s->insert_copy_hgroup.codes = NULL; + s->insert_copy_hgroup.htrees = NULL; + s->distance_hgroup.codes = NULL; + s->distance_hgroup.htrees = NULL; + + s->is_last_metablock = 0; + s->is_uncompressed = 0; + s->is_metadata = 0; + s->should_wrap_ringbuffer = 0; + s->canny_ringbuffer_allocation = 1; + + s->window_bits = 0; + s->max_distance = 0; + s->dist_rb[0] = 16; + s->dist_rb[1] = 15; + s->dist_rb[2] = 11; + s->dist_rb[3] = 4; + s->dist_rb_idx = 0; + s->block_type_trees = NULL; + s->block_len_trees = NULL; + + s->mtf_upper_bound = 63; + + s->compound_dictionary = NULL; + s->dictionary = + BrotliSharedDictionaryCreateInstance(alloc_func, free_func, opaque); + if (!s->dictionary) return BROTLI_FALSE; + + s->metadata_start_func = NULL; + s->metadata_chunk_func = NULL; + s->metadata_callback_opaque = 0; + + return BROTLI_TRUE; +} + +void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s) { + s->meta_block_remaining_len = 0; + s->block_length[0] = BROTLI_BLOCK_SIZE_CAP; + s->block_length[1] = BROTLI_BLOCK_SIZE_CAP; + s->block_length[2] = BROTLI_BLOCK_SIZE_CAP; + s->num_block_types[0] = 1; + s->num_block_types[1] = 1; + s->num_block_types[2] = 1; + s->block_type_rb[0] = 1; + s->block_type_rb[1] = 0; + s->block_type_rb[2] = 1; + s->block_type_rb[3] = 0; + s->block_type_rb[4] = 1; + s->block_type_rb[5] = 0; + s->context_map = NULL; + s->context_modes = NULL; + s->dist_context_map = NULL; + s->context_map_slice = NULL; + s->literal_htree = NULL; + s->dist_context_map_slice = NULL; + s->dist_htree_index = 0; + s->context_lookup = NULL; + s->literal_hgroup.codes = NULL; + s->literal_hgroup.htrees = NULL; + s->insert_copy_hgroup.codes = NULL; + s->insert_copy_hgroup.htrees = NULL; + s->distance_hgroup.codes = NULL; + s->distance_hgroup.htrees = NULL; +} + +void BrotliDecoderStateCleanupAfterMetablock(BrotliDecoderState* s) { + BROTLI_DECODER_FREE(s, s->context_modes); + BROTLI_DECODER_FREE(s, s->context_map); + BROTLI_DECODER_FREE(s, s->dist_context_map); + BROTLI_DECODER_FREE(s, s->literal_hgroup.htrees); + BROTLI_DECODER_FREE(s, s->insert_copy_hgroup.htrees); + BROTLI_DECODER_FREE(s, s->distance_hgroup.htrees); +} + +void BrotliDecoderStateCleanup(BrotliDecoderState* s) { + BrotliDecoderStateCleanupAfterMetablock(s); + + BROTLI_DECODER_ON_FINISH(s); + + BROTLI_DECODER_FREE(s, s->compound_dictionary); + BrotliSharedDictionaryDestroyInstance(s->dictionary); + s->dictionary = NULL; + BROTLI_DECODER_FREE(s, s->ringbuffer); + BROTLI_DECODER_FREE(s, s->block_type_trees); +} + +BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit(BrotliDecoderState* s, + HuffmanTreeGroup* group, brotli_reg_t alphabet_size_max, + brotli_reg_t alphabet_size_limit, brotli_reg_t ntrees) { + /* 376 = 256 (1-st level table) + 4 + 7 + 15 + 31 + 63 (2-nd level mix-tables) + This number is discovered "unlimited" "enough" calculator; it is actually + a wee bigger than required in several cases (especially for alphabets with + less than 16 symbols). */ + const size_t max_table_size = alphabet_size_limit + 376; + const size_t code_size = sizeof(HuffmanCode) * ntrees * max_table_size; + const size_t htree_size = sizeof(HuffmanCode*) * ntrees; + /* Pointer alignment is, hopefully, wider than sizeof(HuffmanCode). */ + HuffmanCode** p = (HuffmanCode**)BROTLI_DECODER_ALLOC(s, + code_size + htree_size); + group->alphabet_size_max = (uint16_t)alphabet_size_max; + group->alphabet_size_limit = (uint16_t)alphabet_size_limit; + group->num_htrees = (uint16_t)ntrees; + group->htrees = p; + group->codes = p ? (HuffmanCode*)(&p[ntrees]) : NULL; + return !!p; +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/dec/state.h b/packages/runtime/vendor/brotli/c/dec/state.h new file mode 100644 index 000000000..aa371fba2 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/dec/state.h @@ -0,0 +1,396 @@ +/* Copyright 2015 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Brotli state for partial streaming decoding. */ + +#ifndef BROTLI_DEC_STATE_H_ +#define BROTLI_DEC_STATE_H_ + +#include "../common/constants.h" +#include "../common/platform.h" +#include +#include +#include "bit_reader.h" +#include "huffman.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* Graphviz diagram that describes state transitions: + +digraph States { + graph [compound=true] + concentrate=true + node [shape="box"] + + UNINITED -> {LARGE_WINDOW_BITS -> INITIALIZE} + subgraph cluster_metablock_workflow { + style="rounded" + label=< METABLOCK CYCLE > + METABLOCK_BEGIN -> METABLOCK_HEADER + METABLOCK_HEADER:sw -> METADATA + METABLOCK_HEADER:s -> UNCOMPRESSED + METABLOCK_HEADER:se -> METABLOCK_DONE:ne + METADATA:s -> METABLOCK_DONE:w + UNCOMPRESSED:s -> METABLOCK_DONE:n + METABLOCK_DONE:e -> METABLOCK_BEGIN:e [constraint="false"] + } + INITIALIZE -> METABLOCK_BEGIN + METABLOCK_DONE -> DONE + + subgraph cluster_compressed_metablock { + style="rounded" + label=< COMPRESSED METABLOCK > + + subgraph cluster_command { + style="rounded" + label=< HOT LOOP > + + _METABLOCK_DONE_PORT_ [shape=point style=invis] + + { + // Set different shape for nodes returning from "compressed metablock". + node [shape=invhouse]; CMD_INNER CMD_POST_DECODE_LITERALS; + CMD_POST_WRAP_COPY; CMD_INNER_WRITE; CMD_POST_WRITE_1; + } + + CMD_BEGIN -> CMD_INNER -> CMD_POST_DECODE_LITERALS -> CMD_POST_WRAP_COPY + + // IO ("write") nodes are not in the hot loop! + CMD_INNER_WRITE [style=dashed] + CMD_INNER -> CMD_INNER_WRITE + CMD_POST_WRITE_1 [style=dashed] + CMD_POST_DECODE_LITERALS -> CMD_POST_WRITE_1 + CMD_POST_WRITE_2 [style=dashed] + CMD_POST_WRAP_COPY -> CMD_POST_WRITE_2 + + CMD_POST_WRITE_1 -> CMD_BEGIN:s [constraint="false"] + CMD_INNER_WRITE -> {CMD_INNER CMD_POST_DECODE_LITERALS} + [constraint="false"] + CMD_BEGIN:ne -> CMD_POST_DECODE_LITERALS [constraint="false"] + CMD_POST_WRAP_COPY -> CMD_BEGIN [constraint="false"] + CMD_POST_DECODE_LITERALS -> CMD_BEGIN:ne [constraint="false"] + CMD_POST_WRITE_2 -> CMD_POST_WRAP_COPY [constraint="false"] + {rank=same; CMD_BEGIN; CMD_INNER; CMD_POST_DECODE_LITERALS; + CMD_POST_WRAP_COPY} + {rank=same; CMD_INNER_WRITE; CMD_POST_WRITE_1; CMD_POST_WRITE_2} + + {CMD_INNER CMD_POST_DECODE_LITERALS CMD_POST_WRAP_COPY} -> + _METABLOCK_DONE_PORT_ [style=invis] + {CMD_INNER_WRITE CMD_POST_WRITE_1} -> _METABLOCK_DONE_PORT_ + [constraint="false" style=invis] + } + + BEFORE_COMPRESSED_METABLOCK_HEADER:s -> HUFFMAN_CODE_0:n + HUFFMAN_CODE_0 -> HUFFMAN_CODE_1 -> HUFFMAN_CODE_2 -> HUFFMAN_CODE_3 + HUFFMAN_CODE_0 -> METABLOCK_HEADER_2 -> CONTEXT_MODES -> CONTEXT_MAP_1 + CONTEXT_MAP_1 -> CONTEXT_MAP_2 -> TREE_GROUP + TREE_GROUP -> BEFORE_COMPRESSED_METABLOCK_BODY:e + BEFORE_COMPRESSED_METABLOCK_BODY:s -> CMD_BEGIN:n + + HUFFMAN_CODE_3:e -> HUFFMAN_CODE_0:ne [constraint="false"] + {rank=same; HUFFMAN_CODE_0; HUFFMAN_CODE_1; HUFFMAN_CODE_2; HUFFMAN_CODE_3} + {rank=same; METABLOCK_HEADER_2; CONTEXT_MODES; CONTEXT_MAP_1; CONTEXT_MAP_2; + TREE_GROUP} + } + METABLOCK_HEADER:e -> BEFORE_COMPRESSED_METABLOCK_HEADER:n + + _METABLOCK_DONE_PORT_ -> METABLOCK_DONE:se + [constraint="false" ltail=cluster_command] + + UNINITED [shape=Mdiamond]; + DONE [shape=Msquare]; +} + + + */ + +typedef enum { + BROTLI_STATE_UNINITED, + BROTLI_STATE_LARGE_WINDOW_BITS, + BROTLI_STATE_INITIALIZE, + BROTLI_STATE_METABLOCK_BEGIN, + BROTLI_STATE_METABLOCK_HEADER, + BROTLI_STATE_METABLOCK_HEADER_2, + BROTLI_STATE_CONTEXT_MODES, + BROTLI_STATE_COMMAND_BEGIN, + BROTLI_STATE_COMMAND_INNER, + BROTLI_STATE_COMMAND_POST_DECODE_LITERALS, + BROTLI_STATE_COMMAND_POST_WRAP_COPY, + BROTLI_STATE_UNCOMPRESSED, + BROTLI_STATE_METADATA, + BROTLI_STATE_COMMAND_INNER_WRITE, + BROTLI_STATE_METABLOCK_DONE, + BROTLI_STATE_COMMAND_POST_WRITE_1, + BROTLI_STATE_COMMAND_POST_WRITE_2, + BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_HEADER, + BROTLI_STATE_HUFFMAN_CODE_0, + BROTLI_STATE_HUFFMAN_CODE_1, + BROTLI_STATE_HUFFMAN_CODE_2, + BROTLI_STATE_HUFFMAN_CODE_3, + BROTLI_STATE_CONTEXT_MAP_1, + BROTLI_STATE_CONTEXT_MAP_2, + BROTLI_STATE_TREE_GROUP, + BROTLI_STATE_BEFORE_COMPRESSED_METABLOCK_BODY, + BROTLI_STATE_DONE +} BrotliRunningState; + +typedef enum { + BROTLI_STATE_METABLOCK_HEADER_NONE, + BROTLI_STATE_METABLOCK_HEADER_EMPTY, + BROTLI_STATE_METABLOCK_HEADER_NIBBLES, + BROTLI_STATE_METABLOCK_HEADER_SIZE, + BROTLI_STATE_METABLOCK_HEADER_UNCOMPRESSED, + BROTLI_STATE_METABLOCK_HEADER_RESERVED, + BROTLI_STATE_METABLOCK_HEADER_BYTES, + BROTLI_STATE_METABLOCK_HEADER_METADATA +} BrotliRunningMetablockHeaderState; + +typedef enum { + BROTLI_STATE_UNCOMPRESSED_NONE, + BROTLI_STATE_UNCOMPRESSED_WRITE +} BrotliRunningUncompressedState; + +typedef enum { + BROTLI_STATE_TREE_GROUP_NONE, + BROTLI_STATE_TREE_GROUP_LOOP +} BrotliRunningTreeGroupState; + +typedef enum { + BROTLI_STATE_CONTEXT_MAP_NONE, + BROTLI_STATE_CONTEXT_MAP_READ_PREFIX, + BROTLI_STATE_CONTEXT_MAP_HUFFMAN, + BROTLI_STATE_CONTEXT_MAP_DECODE, + BROTLI_STATE_CONTEXT_MAP_TRANSFORM +} BrotliRunningContextMapState; + +typedef enum { + BROTLI_STATE_HUFFMAN_NONE, + BROTLI_STATE_HUFFMAN_SIMPLE_SIZE, + BROTLI_STATE_HUFFMAN_SIMPLE_READ, + BROTLI_STATE_HUFFMAN_SIMPLE_BUILD, + BROTLI_STATE_HUFFMAN_COMPLEX, + BROTLI_STATE_HUFFMAN_LENGTH_SYMBOLS +} BrotliRunningHuffmanState; + +typedef enum { + BROTLI_STATE_DECODE_UINT8_NONE, + BROTLI_STATE_DECODE_UINT8_SHORT, + BROTLI_STATE_DECODE_UINT8_LONG +} BrotliRunningDecodeUint8State; + +typedef enum { + BROTLI_STATE_READ_BLOCK_LENGTH_NONE, + BROTLI_STATE_READ_BLOCK_LENGTH_SUFFIX +} BrotliRunningReadBlockLengthState; + +/* BrotliDecoderState addon, used for Compound Dictionary functionality. */ +typedef struct BrotliDecoderCompoundDictionary { + int num_chunks; + int total_size; + int br_index; + int br_offset; + int br_length; + int br_copied; + const uint8_t* chunks[16]; + int chunk_offsets[16]; + int block_bits; + uint8_t block_map[256]; +} BrotliDecoderCompoundDictionary; + +typedef struct BrotliMetablockHeaderArena { + BrotliRunningTreeGroupState substate_tree_group; + BrotliRunningContextMapState substate_context_map; + BrotliRunningHuffmanState substate_huffman; + + brotli_reg_t sub_loop_counter; + + brotli_reg_t repeat_code_len; + brotli_reg_t prev_code_len; + + /* For ReadHuffmanCode. */ + brotli_reg_t symbol; + brotli_reg_t repeat; + brotli_reg_t space; + + /* Huffman table for "histograms". */ + HuffmanCode table[32]; + /* List of heads of symbol chains. */ + uint16_t* symbol_lists; + /* Storage from symbol_lists. */ + uint16_t symbols_lists_array[BROTLI_HUFFMAN_MAX_CODE_LENGTH + 1 + + BROTLI_NUM_COMMAND_SYMBOLS]; + /* Tails of symbol chains. */ + int next_symbol[32]; + uint8_t code_length_code_lengths[BROTLI_CODE_LENGTH_CODES]; + /* Population counts for the code lengths. */ + uint16_t code_length_histo[16]; + /* TODO(eustas): +2 bytes padding */ + + /* For HuffmanTreeGroupDecode. */ + int htree_index; + HuffmanCode* next; + + /* For DecodeContextMap. */ + brotli_reg_t context_index; + brotli_reg_t max_run_length_prefix; + brotli_reg_t code; + HuffmanCode context_map_table[BROTLI_HUFFMAN_MAX_SIZE_272]; +} BrotliMetablockHeaderArena; + +typedef struct BrotliMetablockBodyArena { + uint8_t dist_extra_bits[544]; + brotli_reg_t dist_offset[544]; +} BrotliMetablockBodyArena; + +struct BrotliDecoderStateStruct { + BrotliRunningState state; + + /* This counter is reused for several disjoint loops. */ + int loop_counter; + + BrotliBitReader br; + + brotli_alloc_func alloc_func; + brotli_free_func free_func; + void* memory_manager_opaque; + + /* Temporary storage for remaining input. Brotli stream format is designed in + a way, that 64 bits are enough to make progress in decoding. */ + union { + uint64_t u64; + uint8_t u8[8]; + } buffer; + brotli_reg_t buffer_length; + + int pos; + int max_backward_distance; + int max_distance; + int ringbuffer_size; + int ringbuffer_mask; + int dist_rb_idx; + int dist_rb[4]; + int error_code; + int meta_block_remaining_len; + + uint8_t* ringbuffer; + uint8_t* ringbuffer_end; + HuffmanCode* htree_command; + const uint8_t* context_lookup; + uint8_t* context_map_slice; + uint8_t* dist_context_map_slice; + + /* This ring buffer holds a few past copy distances that will be used by + some special distance codes. */ + HuffmanTreeGroup literal_hgroup; + HuffmanTreeGroup insert_copy_hgroup; + HuffmanTreeGroup distance_hgroup; + HuffmanCode* block_type_trees; + HuffmanCode* block_len_trees; + /* This is true if the literal context map histogram type always matches the + block type. It is then not needed to keep the context (faster decoding). */ + int trivial_literal_context; + /* Distance context is actual after command is decoded and before distance is + computed. After distance computation it is used as a temporary variable. */ + int distance_context; + brotli_reg_t block_length[3]; + brotli_reg_t block_length_index; + brotli_reg_t num_block_types[3]; + brotli_reg_t block_type_rb[6]; + brotli_reg_t distance_postfix_bits; + brotli_reg_t num_direct_distance_codes; + brotli_reg_t num_dist_htrees; + uint8_t* dist_context_map; + HuffmanCode* literal_htree; + + /* For partial write operations. */ + size_t rb_roundtrips; /* how many times we went around the ring-buffer */ + size_t partial_pos_out; /* how much output to the user in total */ + + /* For InverseMoveToFrontTransform. */ + brotli_reg_t mtf_upper_bound; + uint32_t mtf[64 + 1]; + + int copy_length; + int distance_code; + + uint8_t dist_htree_index; + /* TODO(eustas): +3 bytes padding */ + + /* Less used attributes are at the end of this struct. */ + + brotli_decoder_metadata_start_func metadata_start_func; + brotli_decoder_metadata_chunk_func metadata_chunk_func; + void* metadata_callback_opaque; + + /* For reporting. */ + uint64_t used_input; /* how many bytes of input are consumed */ + + /* States inside function calls. */ + BrotliRunningMetablockHeaderState substate_metablock_header; + BrotliRunningUncompressedState substate_uncompressed; + BrotliRunningDecodeUint8State substate_decode_uint8; + BrotliRunningReadBlockLengthState substate_read_block_length; + + int new_ringbuffer_size; + /* TODO(eustas): +4 bytes padding */ + + unsigned int is_last_metablock : 1; + unsigned int is_uncompressed : 1; + unsigned int is_metadata : 1; + unsigned int should_wrap_ringbuffer : 1; + unsigned int canny_ringbuffer_allocation : 1; + unsigned int large_window : 1; + unsigned int window_bits : 6; + unsigned int size_nibbles : 8; + /* TODO(eustas): +12 bits padding */ + + brotli_reg_t num_literal_htrees; + uint8_t* context_map; + uint8_t* context_modes; + + BrotliSharedDictionary* dictionary; + BrotliDecoderCompoundDictionary* compound_dictionary; + + uint32_t trivial_literal_contexts[8]; /* 256 bits */ + + union { + BrotliMetablockHeaderArena header; + BrotliMetablockBodyArena body; + } arena; +}; + +typedef struct BrotliDecoderStateStruct BrotliDecoderStateInternal; +#define BrotliDecoderState BrotliDecoderStateInternal + +BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderStateInit(BrotliDecoderState* s, + brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque); +BROTLI_INTERNAL void BrotliDecoderStateCleanup(BrotliDecoderState* s); +BROTLI_INTERNAL void BrotliDecoderStateMetablockBegin(BrotliDecoderState* s); +BROTLI_INTERNAL void BrotliDecoderStateCleanupAfterMetablock( + BrotliDecoderState* s); +BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderHuffmanTreeGroupInit( + BrotliDecoderState* s, HuffmanTreeGroup* group, + brotli_reg_t alphabet_size_max, brotli_reg_t alphabet_size_limit, + brotli_reg_t ntrees); + +#define BROTLI_DECODER_ALLOC(S, L) S->alloc_func(S->memory_manager_opaque, L) + +#define BROTLI_DECODER_FREE(S, X) { \ + S->free_func(S->memory_manager_opaque, X); \ + X = NULL; \ +} + +/* Literal/Command/Distance block size maximum; same as maximum metablock size; + used as block size when there is no block switching. */ +#define BROTLI_BLOCK_SIZE_CAP (1U << 24) + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_DEC_STATE_H_ */ diff --git a/packages/runtime/vendor/brotli/c/dec/static_init.c b/packages/runtime/vendor/brotli/c/dec/static_init.c new file mode 100644 index 000000000..1345052c5 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/dec/static_init.c @@ -0,0 +1,53 @@ +/* Copyright 2025 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#include "static_init.h" + +#include "../common/platform.h" +#include "../common/static_init.h" + +#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE) +#include "../common/dictionary.h" +#include "prefix.h" +#endif + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE) +static BROTLI_BOOL DoBrotliDecoderStaticInit(void) { + BROTLI_BOOL ok = BrotliDecoderInitCmdLut(kCmdLut); + if (!ok) return BROTLI_FALSE; + return BROTLI_TRUE; +} +#endif /* BROTLI_STATIC_INIT_NONE */ + +#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_EARLY) +static BROTLI_BOOL kEarlyInitOk; +static __attribute__((constructor)) void BrotliDecoderStaticInitEarly(void) { + kEarlyInitOk = DoBrotliDecoderStaticInit(); +} +#elif (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_LAZY) +static BROTLI_BOOL kLazyInitOk; +void BrotliDecoderLazyStaticInitInner(void) { + kLazyInitOk = DoBrotliDecoderStaticInit(); +} +#endif /* BROTLI_STATIC_INIT_EARLY */ + +BROTLI_BOOL BrotliDecoderEnsureStaticInit(void) { +#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_NONE) + return BROTLI_TRUE; +#elif (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_EARLY) + return kEarlyInitOk; +#else + return kLazyInitOk; +#endif +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/dec/static_init.h b/packages/runtime/vendor/brotli/c/dec/static_init.h new file mode 100644 index 000000000..4ae063ef5 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/dec/static_init.h @@ -0,0 +1,30 @@ +/* Copyright 2025 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Central point for static initialization. */ + +#ifndef THIRD_PARTY_BROTLI_DEC_STATIC_INIT_H_ +#define THIRD_PARTY_BROTLI_DEC_STATIC_INIT_H_ + +#include "../common/platform.h" +#include "../common/static_init.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_LAZY) +BROTLI_INTERNAL void BrotliDecoderLazyStaticInitInner(void); +BROTLI_INTERNAL void BrotliDecoderLazyStaticInit(void); +#endif /* BROTLI_STATIC_INIT */ + +BROTLI_INTERNAL BROTLI_BOOL BrotliDecoderEnsureStaticInit(void); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif // THIRD_PARTY_BROTLI_DEC_STATIC_INIT_H_ diff --git a/packages/runtime/vendor/brotli/c/enc/backward_references.c b/packages/runtime/vendor/brotli/c/enc/backward_references.c new file mode 100644 index 000000000..5d1c0ed63 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/backward_references.c @@ -0,0 +1,231 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Function to find backward reference copies. */ + +#include "backward_references.h" + +#include "../common/constants.h" +#include "../common/context.h" +#include "../common/platform.h" +#include "command.h" +#include "compound_dictionary.h" +#include "encoder_dict.h" +#include "hash.h" +#include "params.h" +#include "quality.h" /* IWYU pragma: keep for inc */ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +static BROTLI_INLINE size_t ComputeDistanceCode(size_t distance, + size_t max_distance, + const int* dist_cache) { + if (distance <= max_distance) { + size_t distance_plus_3 = distance + 3; + size_t offset0 = distance_plus_3 - (size_t)dist_cache[0]; + size_t offset1 = distance_plus_3 - (size_t)dist_cache[1]; + if (distance == (size_t)dist_cache[0]) { + return 0; + } else if (distance == (size_t)dist_cache[1]) { + return 1; + } else if (offset0 < 7) { + return (0x9750468 >> (4 * offset0)) & 0xF; + } else if (offset1 < 7) { + return (0xFDB1ACE >> (4 * offset1)) & 0xF; + } else if (distance == (size_t)dist_cache[2]) { + return 2; + } else if (distance == (size_t)dist_cache[3]) { + return 3; + } + } + return distance + BROTLI_NUM_DISTANCE_SHORT_CODES - 1; +} + +#define EXPAND_CAT(a, b) CAT(a, b) +#define CAT(a, b) a ## b +#define FN(X) EXPAND_CAT(X, HASHER()) +#define EXPORT_FN(X) EXPAND_CAT(X, EXPAND_CAT(PREFIX(), HASHER())) + +#define PREFIX() N +#define ENABLE_COMPOUND_DICTIONARY 0 + +#define HASHER() H2 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER + +#define HASHER() H3 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER + +#define HASHER() H4 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER + +#define HASHER() H5 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER + +#define HASHER() H6 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER + +#define HASHER() H40 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER + +#define HASHER() H41 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER + +#define HASHER() H42 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER + +#define HASHER() H54 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER + +#define HASHER() H35 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER + +#define HASHER() H55 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER + +#define HASHER() H65 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER + +#if defined(BROTLI_MAX_SIMD_QUALITY) +#define HASHER() H58 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER + +#define HASHER() H68 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER +#endif + +#undef ENABLE_COMPOUND_DICTIONARY +#undef PREFIX +#define PREFIX() D +#define ENABLE_COMPOUND_DICTIONARY 1 + +#define HASHER() H5 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER +#define HASHER() H6 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER +#define HASHER() H40 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER +#define HASHER() H41 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER +#define HASHER() H42 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER +#define HASHER() H55 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER +#define HASHER() H65 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER +#if defined(BROTLI_MAX_SIMD_QUALITY) +#define HASHER() H58 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER +#define HASHER() H68 +/* NOLINTNEXTLINE(build/include) */ +#include "backward_references_inc.h" +#undef HASHER +#endif + +#undef ENABLE_COMPOUND_DICTIONARY +#undef PREFIX + +#undef EXPORT_FN +#undef FN +#undef CAT +#undef EXPAND_CAT + +void BrotliCreateBackwardReferences(size_t num_bytes, + size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, + ContextLut literal_context_lut, const BrotliEncoderParams* params, + Hasher* hasher, int* dist_cache, size_t* last_insert_len, + Command* commands, size_t* num_commands, size_t* num_literals) { + if (params->dictionary.compound.num_chunks != 0) { + switch (params->hasher.type) { +#define CASE_(N) \ + case N: \ + CreateBackwardReferencesDH ## N(num_bytes, \ + position, ringbuffer, ringbuffer_mask, \ + literal_context_lut, params, hasher, dist_cache, \ + last_insert_len, commands, num_commands, num_literals); \ + return; + CASE_(5) + CASE_(6) +#if defined(BROTLI_MAX_SIMD_QUALITY) + CASE_(58) + CASE_(68) +#endif + CASE_(40) + CASE_(41) + CASE_(42) + CASE_(55) + CASE_(65) +#undef CASE_ + default: + BROTLI_DCHECK(BROTLI_FALSE); + break; + } + } + + switch (params->hasher.type) { +#define CASE_(N) \ + case N: \ + CreateBackwardReferencesNH ## N(num_bytes, \ + position, ringbuffer, ringbuffer_mask, \ + literal_context_lut, params, hasher, dist_cache, \ + last_insert_len, commands, num_commands, num_literals); \ + return; + FOR_GENERIC_HASHERS(CASE_) +#undef CASE_ + default: + BROTLI_DCHECK(BROTLI_FALSE); + break; + } +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/backward_references.h b/packages/runtime/vendor/brotli/c/enc/backward_references.h new file mode 100644 index 000000000..17f0c8495 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/backward_references.h @@ -0,0 +1,36 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Function to find backward reference copies. */ + +#ifndef BROTLI_ENC_BACKWARD_REFERENCES_H_ +#define BROTLI_ENC_BACKWARD_REFERENCES_H_ + +#include "../common/context.h" +#include "../common/platform.h" +#include "command.h" +#include "hash.h" +#include "params.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* "commands" points to the next output command to write to, "*num_commands" is + initially the total amount of commands output by previous + CreateBackwardReferences calls, and must be incremented by the amount written + by this call. */ +BROTLI_INTERNAL void BrotliCreateBackwardReferences(size_t num_bytes, + size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, + ContextLut literal_context_lut, const BrotliEncoderParams* params, + Hasher* hasher, int* dist_cache, size_t* last_insert_len, + Command* commands, size_t* num_commands, size_t* num_literals); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_BACKWARD_REFERENCES_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/backward_references_hq.c b/packages/runtime/vendor/brotli/c/enc/backward_references_hq.c new file mode 100644 index 000000000..ab8b12187 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/backward_references_hq.c @@ -0,0 +1,939 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Function to find backward reference copies. */ + +#include "backward_references_hq.h" + +#include "../common/constants.h" +#include "../common/context.h" +#include "../common/platform.h" +#include "command.h" +#include "compound_dictionary.h" +#include "encoder_dict.h" +#include "fast_log.h" +#include "find_match_length.h" +#include "hash.h" +#include "literal_cost.h" +#include "memory.h" +#include "params.h" +#include "prefix.h" +#include "quality.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* BrotliCalculateDistanceCodeLimit(BROTLI_MAX_ALLOWED_DISTANCE, 3, 120). */ +#define BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE 544 + +static const float kInfinity = 1.7e38f; /* ~= 2 ^ 127 */ + +static const BROTLI_MODEL("small") uint32_t kDistanceCacheIndex[] = { + 0, 1, 2, 3, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, +}; +static const BROTLI_MODEL("small") int kDistanceCacheOffset[] = { + 0, 0, 0, 0, -1, 1, -2, 2, -3, 3, -1, 1, -2, 2, -3, 3 +}; + +void BrotliInitZopfliNodes(ZopfliNode* array, size_t length) { + ZopfliNode stub; + size_t i; + stub.length = 1; + stub.distance = 0; + stub.dcode_insert_length = 0; + stub.u.cost = kInfinity; + for (i = 0; i < length; ++i) array[i] = stub; +} + +static BROTLI_INLINE uint32_t ZopfliNodeCopyLength(const ZopfliNode* self) { + return self->length & 0x1FFFFFF; +} + +static BROTLI_INLINE uint32_t ZopfliNodeLengthCode(const ZopfliNode* self) { + const uint32_t modifier = self->length >> 25; + return ZopfliNodeCopyLength(self) + 9u - modifier; +} + +static BROTLI_INLINE uint32_t ZopfliNodeCopyDistance(const ZopfliNode* self) { + return self->distance; +} + +static BROTLI_INLINE uint32_t ZopfliNodeDistanceCode(const ZopfliNode* self) { + const uint32_t short_code = self->dcode_insert_length >> 27; + return short_code == 0 ? + ZopfliNodeCopyDistance(self) + BROTLI_NUM_DISTANCE_SHORT_CODES - 1 : + short_code - 1; +} + +static BROTLI_INLINE uint32_t ZopfliNodeCommandLength(const ZopfliNode* self) { + return ZopfliNodeCopyLength(self) + (self->dcode_insert_length & 0x7FFFFFF); +} + +/* Temporary data for ZopfliCostModelSetFromCommands. */ +typedef struct ZopfliCostModelArena { + uint32_t histogram_literal[BROTLI_NUM_LITERAL_SYMBOLS]; + uint32_t histogram_cmd[BROTLI_NUM_COMMAND_SYMBOLS]; + uint32_t histogram_dist[BROTLI_MAX_EFFECTIVE_DISTANCE_ALPHABET_SIZE]; + float cost_literal[BROTLI_NUM_LITERAL_SYMBOLS]; +} ZopfliCostModelArena; + +/* Histogram based cost model for zopflification. */ +typedef struct ZopfliCostModel { + /* The insert and copy length symbols. */ + float cost_cmd_[BROTLI_NUM_COMMAND_SYMBOLS]; + float* cost_dist_; + uint32_t distance_histogram_size; + /* Cumulative costs of literals per position in the stream. */ + float* literal_costs_; + float min_cost_cmd_; + size_t num_bytes_; + + /* Temporary data. */ + union { + size_t literal_histograms[3 * 256]; + ZopfliCostModelArena arena; + }; +} ZopfliCostModel; + +static void InitZopfliCostModel( + MemoryManager* m, ZopfliCostModel* self, const BrotliDistanceParams* dist, + size_t num_bytes) { + self->num_bytes_ = num_bytes; + self->literal_costs_ = BROTLI_ALLOC(m, float, num_bytes + 2); + self->cost_dist_ = BROTLI_ALLOC(m, float, dist->alphabet_size_limit); + self->distance_histogram_size = dist->alphabet_size_limit; + if (BROTLI_IS_OOM(m)) return; +} + +static void CleanupZopfliCostModel(MemoryManager* m, ZopfliCostModel* self) { + BROTLI_FREE(m, self->literal_costs_); + BROTLI_FREE(m, self->cost_dist_); +} + +static void SetCost(const uint32_t* histogram, size_t histogram_size, + BROTLI_BOOL literal_histogram, float* cost) { + size_t sum = 0; + size_t missing_symbol_sum; + float log2sum; + float missing_symbol_cost; + size_t i; + for (i = 0; i < histogram_size; i++) { + sum += histogram[i]; + } + log2sum = (float)FastLog2(sum); + missing_symbol_sum = sum; + if (!literal_histogram) { + for (i = 0; i < histogram_size; i++) { + if (histogram[i] == 0) missing_symbol_sum++; + } + } + missing_symbol_cost = (float)FastLog2(missing_symbol_sum) + 2; + for (i = 0; i < histogram_size; i++) { + if (histogram[i] == 0) { + cost[i] = missing_symbol_cost; + continue; + } + + /* Shannon bits for this symbol. */ + cost[i] = log2sum - (float)FastLog2(histogram[i]); + + /* Cannot be coded with less than 1 bit */ + if (cost[i] < 1) cost[i] = 1; + } +} + +static void ZopfliCostModelSetFromCommands(ZopfliCostModel* self, + size_t position, + const uint8_t* ringbuffer, + size_t ringbuffer_mask, + const Command* commands, + size_t num_commands, + size_t last_insert_len) { + ZopfliCostModelArena* arena = &self->arena; + size_t pos = position - last_insert_len; + float min_cost_cmd = kInfinity; + size_t i; + float* cost_cmd = self->cost_cmd_; + + memset(arena->histogram_literal, 0, sizeof(arena->histogram_literal)); + memset(arena->histogram_cmd, 0, sizeof(arena->histogram_cmd)); + memset(arena->histogram_dist, 0, sizeof(arena->histogram_dist)); + + for (i = 0; i < num_commands; i++) { + size_t inslength = commands[i].insert_len_; + size_t copylength = CommandCopyLen(&commands[i]); + size_t distcode = commands[i].dist_prefix_ & 0x3FF; + size_t cmdcode = commands[i].cmd_prefix_; + size_t j; + + arena->histogram_cmd[cmdcode]++; + if (cmdcode >= 128) arena->histogram_dist[distcode]++; + + for (j = 0; j < inslength; j++) { + arena->histogram_literal[ringbuffer[(pos + j) & ringbuffer_mask]]++; + } + + pos += inslength + copylength; + } + + SetCost(arena->histogram_literal, BROTLI_NUM_LITERAL_SYMBOLS, BROTLI_TRUE, + arena->cost_literal); + SetCost(arena->histogram_cmd, BROTLI_NUM_COMMAND_SYMBOLS, BROTLI_FALSE, + cost_cmd); + SetCost(arena->histogram_dist, self->distance_histogram_size, BROTLI_FALSE, + self->cost_dist_); + + for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) { + min_cost_cmd = BROTLI_MIN(float, min_cost_cmd, cost_cmd[i]); + } + self->min_cost_cmd_ = min_cost_cmd; + + { + float* literal_costs = self->literal_costs_; + float literal_carry = 0.0; + size_t num_bytes = self->num_bytes_; + literal_costs[0] = 0.0; + for (i = 0; i < num_bytes; ++i) { + literal_carry += + arena->cost_literal[ringbuffer[(position + i) & ringbuffer_mask]]; + literal_costs[i + 1] = literal_costs[i] + literal_carry; + literal_carry -= literal_costs[i + 1] - literal_costs[i]; + } + } +} + +static void ZopfliCostModelSetFromLiteralCosts(ZopfliCostModel* self, + size_t position, + const uint8_t* ringbuffer, + size_t ringbuffer_mask) { + float* literal_costs = self->literal_costs_; + float literal_carry = 0.0; + float* cost_dist = self->cost_dist_; + float* cost_cmd = self->cost_cmd_; + size_t num_bytes = self->num_bytes_; + size_t i; + BrotliEstimateBitCostsForLiterals(position, num_bytes, ringbuffer_mask, + ringbuffer, self->literal_histograms, + &literal_costs[1]); + literal_costs[0] = 0.0; + for (i = 0; i < num_bytes; ++i) { + literal_carry += literal_costs[i + 1]; + literal_costs[i + 1] = literal_costs[i] + literal_carry; + literal_carry -= literal_costs[i + 1] - literal_costs[i]; + } + for (i = 0; i < BROTLI_NUM_COMMAND_SYMBOLS; ++i) { + cost_cmd[i] = (float)FastLog2(11 + (uint32_t)i); + } + for (i = 0; i < self->distance_histogram_size; ++i) { + cost_dist[i] = (float)FastLog2(20 + (uint32_t)i); + } + self->min_cost_cmd_ = (float)FastLog2(11); +} + +static BROTLI_INLINE float ZopfliCostModelGetCommandCost( + const ZopfliCostModel* self, uint16_t cmdcode) { + return self->cost_cmd_[cmdcode]; +} + +static BROTLI_INLINE float ZopfliCostModelGetDistanceCost( + const ZopfliCostModel* self, size_t distcode) { + return self->cost_dist_[distcode]; +} + +static BROTLI_INLINE float ZopfliCostModelGetLiteralCosts( + const ZopfliCostModel* self, size_t from, size_t to) { + return self->literal_costs_[to] - self->literal_costs_[from]; +} + +static BROTLI_INLINE float ZopfliCostModelGetMinCostCmd( + const ZopfliCostModel* self) { + return self->min_cost_cmd_; +} + +/* REQUIRES: len >= 2, start_pos <= pos */ +/* REQUIRES: cost < kInfinity, nodes[start_pos].cost < kInfinity */ +/* Maintains the "ZopfliNode array invariant". */ +static BROTLI_INLINE void UpdateZopfliNode(ZopfliNode* nodes, size_t pos, + size_t start_pos, size_t len, size_t len_code, size_t dist, + size_t short_code, float cost) { + ZopfliNode* next = &nodes[pos + len]; + next->length = (uint32_t)(len | ((len + 9u - len_code) << 25)); + next->distance = (uint32_t)dist; + next->dcode_insert_length = (uint32_t)( + (short_code << 27) | (pos - start_pos)); + next->u.cost = cost; +} + +typedef struct PosData { + size_t pos; + int distance_cache[4]; + float costdiff; + float cost; +} PosData; + +/* Maintains the smallest 8 cost difference together with their positions */ +typedef struct StartPosQueue { + PosData q_[8]; + size_t idx_; +} StartPosQueue; + +static BROTLI_INLINE void InitStartPosQueue(StartPosQueue* self) { + self->idx_ = 0; +} + +static size_t StartPosQueueSize(const StartPosQueue* self) { + return BROTLI_MIN(size_t, self->idx_, 8); +} + +static void StartPosQueuePush(StartPosQueue* self, const PosData* posdata) { + size_t offset = ~(self->idx_++) & 7; + size_t len = StartPosQueueSize(self); + size_t i; + PosData* q = self->q_; + q[offset] = *posdata; + /* Restore the sorted order. In the list of |len| items at most |len - 1| + adjacent element comparisons / swaps are required. */ + for (i = 1; i < len; ++i) { + if (q[offset & 7].costdiff > q[(offset + 1) & 7].costdiff) { + BROTLI_SWAP(PosData, q, offset & 7, (offset + 1) & 7); + } + ++offset; + } +} + +static const PosData* StartPosQueueAt(const StartPosQueue* self, size_t k) { + return &self->q_[(k - self->idx_) & 7]; +} + +/* Returns the minimum possible copy length that can improve the cost of any */ +/* future position. */ +static size_t ComputeMinimumCopyLength(const float start_cost, + const ZopfliNode* nodes, + const size_t num_bytes, + const size_t pos) { + /* Compute the minimum possible cost of reaching any future position. */ + float min_cost = start_cost; + size_t len = 2; + size_t next_len_bucket = 4; + size_t next_len_offset = 10; + while (pos + len <= num_bytes && nodes[pos + len].u.cost <= min_cost) { + /* We already reached (pos + len) with no more cost than the minimum + possible cost of reaching anything from this pos, so there is no point in + looking for lengths <= len. */ + ++len; + if (len == next_len_offset) { + /* We reached the next copy length code bucket, so we add one more + extra bit to the minimum cost. */ + min_cost += 1.0f; + next_len_offset += next_len_bucket; + next_len_bucket *= 2; + } + } + return len; +} + +/* REQUIRES: nodes[pos].cost < kInfinity + REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */ +static uint32_t ComputeDistanceShortcut(const size_t block_start, + const size_t pos, + const size_t max_backward_limit, + const size_t gap, + const ZopfliNode* nodes) { + const size_t c_len = ZopfliNodeCopyLength(&nodes[pos]); + const size_t i_len = nodes[pos].dcode_insert_length & 0x7FFFFFF; + const size_t dist = ZopfliNodeCopyDistance(&nodes[pos]); + /* Since |block_start + pos| is the end position of the command, the copy part + starts from |block_start + pos - c_len|. Distances that are greater than + this or greater than |max_backward_limit| + |gap| are static dictionary + references, and do not update the last distances. + Also distance code 0 (last distance) does not update the last distances. */ + if (pos == 0) { + return 0; + } else if (dist + c_len <= block_start + pos + gap && + dist <= max_backward_limit + gap && + ZopfliNodeDistanceCode(&nodes[pos]) > 0) { + return (uint32_t)pos; + } else { + return nodes[pos - c_len - i_len].u.shortcut; + } +} + +/* Fills in dist_cache[0..3] with the last four distances (as defined by + Section 4. of the Spec) that would be used at (block_start + pos) if we + used the shortest path of commands from block_start, computed from + nodes[0..pos]. The last four distances at block_start are in + starting_dist_cache[0..3]. + REQUIRES: nodes[pos].cost < kInfinity + REQUIRES: nodes[0..pos] satisfies that "ZopfliNode array invariant". */ +static void ComputeDistanceCache(const size_t pos, + const int* starting_dist_cache, + const ZopfliNode* nodes, + int* dist_cache) { + int idx = 0; + size_t p = nodes[pos].u.shortcut; + while (idx < 4 && p > 0) { + const size_t i_len = nodes[p].dcode_insert_length & 0x7FFFFFF; + const size_t c_len = ZopfliNodeCopyLength(&nodes[p]); + const size_t dist = ZopfliNodeCopyDistance(&nodes[p]); + dist_cache[idx++] = (int)dist; + /* Because of prerequisite, p >= c_len + i_len >= 2. */ + p = nodes[p - c_len - i_len].u.shortcut; + } + for (; idx < 4; ++idx) { + dist_cache[idx] = *starting_dist_cache++; + } +} + +/* Maintains "ZopfliNode array invariant" and pushes node to the queue, if it + is eligible. */ +static void EvaluateNode( + const size_t block_start, const size_t pos, const size_t max_backward_limit, + const size_t gap, const int* starting_dist_cache, + const ZopfliCostModel* model, StartPosQueue* queue, ZopfliNode* nodes) { + /* Save cost, because ComputeDistanceCache invalidates it. */ + float node_cost = nodes[pos].u.cost; + nodes[pos].u.shortcut = ComputeDistanceShortcut( + block_start, pos, max_backward_limit, gap, nodes); + if (node_cost <= ZopfliCostModelGetLiteralCosts(model, 0, pos)) { + PosData posdata; + posdata.pos = pos; + posdata.cost = node_cost; + posdata.costdiff = node_cost - + ZopfliCostModelGetLiteralCosts(model, 0, pos); + ComputeDistanceCache( + pos, starting_dist_cache, nodes, posdata.distance_cache); + StartPosQueuePush(queue, &posdata); + } +} + +/* Returns longest copy length. */ +static size_t UpdateNodes( + const size_t num_bytes, const size_t block_start, const size_t pos, + const uint8_t* ringbuffer, const size_t ringbuffer_mask, + const BrotliEncoderParams* params, const size_t max_backward_limit, + const int* starting_dist_cache, const size_t num_matches, + const BackwardMatch* matches, const ZopfliCostModel* model, + StartPosQueue* queue, ZopfliNode* nodes) { + const size_t stream_offset = params->stream_offset; + const size_t cur_ix = block_start + pos; + const size_t cur_ix_masked = cur_ix & ringbuffer_mask; + const size_t max_distance = BROTLI_MIN(size_t, cur_ix, max_backward_limit); + const size_t dictionary_start = BROTLI_MIN(size_t, + cur_ix + stream_offset, max_backward_limit); + const size_t max_len = num_bytes - pos; + const size_t max_zopfli_len = MaxZopfliLen(params); + const size_t max_iters = MaxZopfliCandidates(params); + size_t min_len; + size_t result = 0; + size_t k; + const CompoundDictionary* addon = ¶ms->dictionary.compound; + size_t gap = addon->total_size; + + BROTLI_DCHECK(cur_ix_masked + max_len <= ringbuffer_mask); + + EvaluateNode(block_start + stream_offset, pos, max_backward_limit, gap, + starting_dist_cache, model, queue, nodes); + + { + const PosData* posdata = StartPosQueueAt(queue, 0); + float min_cost = (posdata->cost + ZopfliCostModelGetMinCostCmd(model) + + ZopfliCostModelGetLiteralCosts(model, posdata->pos, pos)); + min_len = ComputeMinimumCopyLength(min_cost, nodes, num_bytes, pos); + } + + /* Go over the command starting positions in order of increasing cost + difference. */ + for (k = 0; k < max_iters && k < StartPosQueueSize(queue); ++k) { + const PosData* posdata = StartPosQueueAt(queue, k); + const size_t start = posdata->pos; + const uint16_t inscode = GetInsertLengthCode(pos - start); + const float start_costdiff = posdata->costdiff; + const float base_cost = start_costdiff + (float)GetInsertExtra(inscode) + + ZopfliCostModelGetLiteralCosts(model, 0, pos); + + /* Look for last distance matches using the distance cache from this + starting position. */ + size_t best_len = min_len - 1; + size_t j = 0; + for (; j < BROTLI_NUM_DISTANCE_SHORT_CODES && best_len < max_len; ++j) { + const size_t idx = kDistanceCacheIndex[j]; + const size_t backward = + (size_t)(posdata->distance_cache[idx] + kDistanceCacheOffset[j]); + size_t prev_ix = cur_ix - backward; + size_t len = 0; + uint8_t continuation = ringbuffer[cur_ix_masked + best_len]; + if (cur_ix_masked + best_len > ringbuffer_mask) { + break; + } + if (BROTLI_PREDICT_FALSE(backward > dictionary_start + gap)) { + /* Word dictionary -> ignore. */ + continue; + } + if (backward <= max_distance) { + /* Regular backward reference. */ + if (prev_ix >= cur_ix) { + continue; + } + + prev_ix &= ringbuffer_mask; + if (prev_ix + best_len > ringbuffer_mask || + continuation != ringbuffer[prev_ix + best_len]) { + continue; + } + len = FindMatchLengthWithLimit(&ringbuffer[prev_ix], + &ringbuffer[cur_ix_masked], + max_len); + } else if (backward > dictionary_start) { + size_t d = 0; + size_t offset; + size_t limit; + const uint8_t* source; + offset = dictionary_start + 1 + addon->total_size - 1; + while (offset >= backward + addon->chunk_offsets[d + 1]) d++; + source = addon->chunk_source[d]; + offset = offset - addon->chunk_offsets[d] - backward; + limit = addon->chunk_offsets[d + 1] - addon->chunk_offsets[d] - offset; + limit = limit > max_len ? max_len : limit; + if (best_len >= limit || + continuation != source[offset + best_len]) { + continue; + } + len = FindMatchLengthWithLimit(&source[offset], + &ringbuffer[cur_ix_masked], + limit); + } else { + /* "Gray" area. It is addressable by decoder, but this encoder + instance does not have that data -> should not touch it. */ + continue; + } + { + const float dist_cost = base_cost + + ZopfliCostModelGetDistanceCost(model, j); + size_t l; + for (l = best_len + 1; l <= len; ++l) { + const uint16_t copycode = GetCopyLengthCode(l); + const uint16_t cmdcode = + CombineLengthCodes(inscode, copycode, j == 0); + const float cost = (cmdcode < 128 ? base_cost : dist_cost) + + (float)GetCopyExtra(copycode) + + ZopfliCostModelGetCommandCost(model, cmdcode); + if (cost < nodes[pos + l].u.cost) { + UpdateZopfliNode(nodes, pos, start, l, l, backward, j + 1, cost); + result = BROTLI_MAX(size_t, result, l); + } + best_len = l; + } + } + } + + /* At higher iterations look only for new last distance matches, since + looking only for new command start positions with the same distances + does not help much. */ + if (k >= 2) continue; + + { + /* Loop through all possible copy lengths at this position. */ + size_t len = min_len; + for (j = 0; j < num_matches; ++j) { + BackwardMatch match = matches[j]; + size_t dist = match.distance; + BROTLI_BOOL is_dictionary_match = + TO_BROTLI_BOOL(dist > dictionary_start + gap); + /* We already tried all possible last distance matches, so we can use + normal distance code here. */ + size_t dist_code = dist + BROTLI_NUM_DISTANCE_SHORT_CODES - 1; + uint16_t dist_symbol; + uint32_t distextra; + uint32_t distnumextra; + float dist_cost; + size_t max_match_len; + PrefixEncodeCopyDistance( + dist_code, params->dist.num_direct_distance_codes, + params->dist.distance_postfix_bits, &dist_symbol, &distextra); + distnumextra = dist_symbol >> 10; + dist_cost = base_cost + (float)distnumextra + + ZopfliCostModelGetDistanceCost(model, dist_symbol & 0x3FF); + + /* Try all copy lengths up until the maximum copy length corresponding + to this distance. If the distance refers to the static dictionary, or + the maximum length is long enough, try only one maximum length. */ + max_match_len = BackwardMatchLength(&match); + if (len < max_match_len && + (is_dictionary_match || max_match_len > max_zopfli_len)) { + len = max_match_len; + } + for (; len <= max_match_len; ++len) { + const size_t len_code = + is_dictionary_match ? BackwardMatchLengthCode(&match) : len; + const uint16_t copycode = GetCopyLengthCode(len_code); + const uint16_t cmdcode = CombineLengthCodes(inscode, copycode, 0); + const float cost = dist_cost + (float)GetCopyExtra(copycode) + + ZopfliCostModelGetCommandCost(model, cmdcode); + if (cost < nodes[pos + len].u.cost) { + UpdateZopfliNode(nodes, pos, start, len, len_code, dist, 0, cost); + result = BROTLI_MAX(size_t, result, len); + } + } + } + } + } + return result; +} + +static size_t ComputeShortestPathFromNodes(size_t num_bytes, + ZopfliNode* nodes) { + size_t index = num_bytes; + size_t num_commands = 0; + while ((nodes[index].dcode_insert_length & 0x7FFFFFF) == 0 && + nodes[index].length == 1) --index; + nodes[index].u.next = BROTLI_UINT32_MAX; + while (index != 0) { + size_t len = ZopfliNodeCommandLength(&nodes[index]); + index -= len; + nodes[index].u.next = (uint32_t)len; + num_commands++; + } + return num_commands; +} + +/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */ +void BrotliZopfliCreateCommands(const size_t num_bytes, + const size_t block_start, const ZopfliNode* nodes, int* dist_cache, + size_t* last_insert_len, const BrotliEncoderParams* params, + Command* commands, size_t* num_literals) { + const size_t stream_offset = params->stream_offset; + const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin); + size_t pos = 0; + uint32_t offset = nodes[0].u.next; + size_t i; + size_t gap = params->dictionary.compound.total_size; + for (i = 0; offset != BROTLI_UINT32_MAX; i++) { + const ZopfliNode* next = &nodes[pos + offset]; + size_t copy_length = ZopfliNodeCopyLength(next); + size_t insert_length = next->dcode_insert_length & 0x7FFFFFF; + pos += insert_length; + offset = next->u.next; + if (i == 0) { + insert_length += *last_insert_len; + *last_insert_len = 0; + } + { + size_t distance = ZopfliNodeCopyDistance(next); + size_t len_code = ZopfliNodeLengthCode(next); + size_t dictionary_start = BROTLI_MIN(size_t, + block_start + pos + stream_offset, max_backward_limit); + BROTLI_BOOL is_dictionary = + TO_BROTLI_BOOL(distance > dictionary_start + gap); + size_t dist_code = ZopfliNodeDistanceCode(next); + InitCommand(&commands[i], ¶ms->dist, insert_length, + copy_length, (int)len_code - (int)copy_length, dist_code); + + if (!is_dictionary && dist_code > 0) { + dist_cache[3] = dist_cache[2]; + dist_cache[2] = dist_cache[1]; + dist_cache[1] = dist_cache[0]; + dist_cache[0] = (int)distance; + } + } + + *num_literals += insert_length; + pos += copy_length; + } + *last_insert_len += num_bytes - pos; +} + +static size_t ZopfliIterate(size_t num_bytes, size_t position, + const uint8_t* ringbuffer, size_t ringbuffer_mask, + const BrotliEncoderParams* params, const size_t gap, const int* dist_cache, + const ZopfliCostModel* model, const uint32_t* num_matches, + const BackwardMatch* matches, ZopfliNode* nodes) { + const size_t stream_offset = params->stream_offset; + const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin); + const size_t max_zopfli_len = MaxZopfliLen(params); + StartPosQueue queue; + size_t cur_match_pos = 0; + size_t i; + nodes[0].length = 0; + nodes[0].u.cost = 0; + InitStartPosQueue(&queue); + for (i = 0; i + 3 < num_bytes; i++) { + size_t skip = UpdateNodes(num_bytes, position, i, ringbuffer, + ringbuffer_mask, params, max_backward_limit, dist_cache, + num_matches[i], &matches[cur_match_pos], model, &queue, nodes); + if (skip < BROTLI_LONG_COPY_QUICK_STEP) skip = 0; + cur_match_pos += num_matches[i]; + if (num_matches[i] == 1 && + BackwardMatchLength(&matches[cur_match_pos - 1]) > max_zopfli_len) { + skip = BROTLI_MAX(size_t, + BackwardMatchLength(&matches[cur_match_pos - 1]), skip); + } + if (skip > 1) { + skip--; + while (skip) { + i++; + if (i + 3 >= num_bytes) break; + EvaluateNode(position + stream_offset, i, max_backward_limit, gap, + dist_cache, model, &queue, nodes); + cur_match_pos += num_matches[i]; + skip--; + } + } + } + return ComputeShortestPathFromNodes(num_bytes, nodes); +} + +static void MergeMatches(BackwardMatch* dst, + BackwardMatch* src1, size_t len1, BackwardMatch* src2, size_t len2) { + while (len1 > 0 && len2 > 0) { + size_t l1 = BackwardMatchLength(src1); + size_t l2 = BackwardMatchLength(src2); + if (l1 < l2 || ((l1 == l2) && (src1->distance < src2->distance))) { + *dst++ = *src1++; + len1--; + } else { + *dst++ = *src2++; + len2--; + } + } + while (len1-- > 0) *dst++ = *src1++; + while (len2-- > 0) *dst++ = *src2++; +} + +/* REQUIRES: nodes != NULL and len(nodes) >= num_bytes + 1 */ +size_t BrotliZopfliComputeShortestPath(MemoryManager* m, size_t num_bytes, + size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, + ContextLut literal_context_lut, const BrotliEncoderParams* params, + const int* dist_cache, Hasher* hasher, ZopfliNode* nodes) { + const size_t stream_offset = params->stream_offset; + const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin); + const size_t max_zopfli_len = MaxZopfliLen(params); + StartPosQueue queue; + BackwardMatch* BROTLI_RESTRICT matches = + BROTLI_ALLOC(m, BackwardMatch, 2 * (MAX_NUM_MATCHES_H10 + 64)); + const size_t store_end = num_bytes >= StoreLookaheadH10() ? + position + num_bytes - StoreLookaheadH10() + 1 : position; + size_t i; + const CompoundDictionary* addon = ¶ms->dictionary.compound; + size_t gap = addon->total_size; + size_t lz_matches_offset = + (addon->num_chunks != 0) ? (MAX_NUM_MATCHES_H10 + 128) : 0; + ZopfliCostModel* model = BROTLI_ALLOC(m, ZopfliCostModel, 1); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(model) || BROTLI_IS_NULL(matches)) { + return 0; + } + nodes[0].length = 0; + nodes[0].u.cost = 0; + InitZopfliCostModel(m, model, ¶ms->dist, num_bytes); + if (BROTLI_IS_OOM(m)) return 0; + ZopfliCostModelSetFromLiteralCosts( + model, position, ringbuffer, ringbuffer_mask); + InitStartPosQueue(&queue); + for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; i++) { + const size_t pos = position + i; + const size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit); + const size_t dictionary_start = BROTLI_MIN(size_t, + pos + stream_offset, max_backward_limit); + size_t skip; + size_t num_matches; + int dict_id = 0; + if (params->dictionary.contextual.context_based) { + uint8_t p1 = pos >= 1 ? + ringbuffer[(size_t)(pos - 1) & ringbuffer_mask] : 0; + uint8_t p2 = pos >= 2 ? + ringbuffer[(size_t)(pos - 2) & ringbuffer_mask] : 0; + dict_id = params->dictionary.contextual.context_map[ + BROTLI_CONTEXT(p1, p2, literal_context_lut)]; + } + num_matches = FindAllMatchesH10(&hasher->privat._H10, + params->dictionary.contextual.dict[dict_id], + ringbuffer, ringbuffer_mask, pos, num_bytes - i, max_distance, + dictionary_start + gap, params, &matches[lz_matches_offset]); + if (addon->num_chunks != 0) { + size_t cd_matches = LookupAllCompoundDictionaryMatches(addon, + ringbuffer, ringbuffer_mask, pos, 3, num_bytes - i, + dictionary_start, params->dist.max_distance, + &matches[lz_matches_offset - 64], 64); + MergeMatches(matches, &matches[lz_matches_offset - 64], cd_matches, + &matches[lz_matches_offset], num_matches); + num_matches += cd_matches; + } + if (num_matches > 0 && + BackwardMatchLength(&matches[num_matches - 1]) > max_zopfli_len) { + matches[0] = matches[num_matches - 1]; + num_matches = 1; + } + skip = UpdateNodes(num_bytes, position, i, ringbuffer, ringbuffer_mask, + params, max_backward_limit, dist_cache, num_matches, matches, model, + &queue, nodes); + if (skip < BROTLI_LONG_COPY_QUICK_STEP) skip = 0; + if (num_matches == 1 && BackwardMatchLength(&matches[0]) > max_zopfli_len) { + skip = BROTLI_MAX(size_t, BackwardMatchLength(&matches[0]), skip); + } + if (skip > 1) { + /* Add the tail of the copy to the hasher. */ + StoreRangeH10(&hasher->privat._H10, + ringbuffer, ringbuffer_mask, pos + 1, BROTLI_MIN( + size_t, pos + skip, store_end)); + skip--; + while (skip) { + i++; + if (i + HashTypeLengthH10() - 1 >= num_bytes) break; + EvaluateNode(position + stream_offset, i, max_backward_limit, gap, + dist_cache, model, &queue, nodes); + skip--; + } + } + } + CleanupZopfliCostModel(m, model); + BROTLI_FREE(m, model); + BROTLI_FREE(m, matches); + return ComputeShortestPathFromNodes(num_bytes, nodes); +} + +void BrotliCreateZopfliBackwardReferences(MemoryManager* m, size_t num_bytes, + size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, + ContextLut literal_context_lut, const BrotliEncoderParams* params, + Hasher* hasher, int* dist_cache, size_t* last_insert_len, + Command* commands, size_t* num_commands, size_t* num_literals) { + ZopfliNode* nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return; + BrotliInitZopfliNodes(nodes, num_bytes + 1); + *num_commands += BrotliZopfliComputeShortestPath(m, num_bytes, + position, ringbuffer, ringbuffer_mask, literal_context_lut, params, + dist_cache, hasher, nodes); + if (BROTLI_IS_OOM(m)) return; + BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache, + last_insert_len, params, commands, num_literals); + BROTLI_FREE(m, nodes); +} + +void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, size_t num_bytes, + size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, + ContextLut literal_context_lut, const BrotliEncoderParams* params, + Hasher* hasher, int* dist_cache, size_t* last_insert_len, + Command* commands, size_t* num_commands, size_t* num_literals) { + const size_t stream_offset = params->stream_offset; + const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin); + uint32_t* num_matches = BROTLI_ALLOC(m, uint32_t, num_bytes); + size_t matches_size = 4 * num_bytes; + const size_t store_end = num_bytes >= StoreLookaheadH10() ? + position + num_bytes - StoreLookaheadH10() + 1 : position; + size_t cur_match_pos = 0; + size_t i; + size_t orig_num_literals; + size_t orig_last_insert_len; + int orig_dist_cache[4]; + size_t orig_num_commands; + ZopfliCostModel* model = BROTLI_ALLOC(m, ZopfliCostModel, 1); + ZopfliNode* nodes; + BackwardMatch* matches = BROTLI_ALLOC(m, BackwardMatch, matches_size); + const CompoundDictionary* addon = ¶ms->dictionary.compound; + size_t gap = addon->total_size; + size_t shadow_matches = + (addon->num_chunks != 0) ? (MAX_NUM_MATCHES_H10 + 128) : 0; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(model) || + BROTLI_IS_NULL(num_matches) || BROTLI_IS_NULL(matches)) { + return; + } + for (i = 0; i + HashTypeLengthH10() - 1 < num_bytes; ++i) { + const size_t pos = position + i; + size_t max_distance = BROTLI_MIN(size_t, pos, max_backward_limit); + size_t dictionary_start = BROTLI_MIN(size_t, + pos + stream_offset, max_backward_limit); + size_t max_length = num_bytes - i; + size_t num_found_matches; + size_t cur_match_end; + size_t j; + int dict_id = 0; + if (params->dictionary.contextual.context_based) { + uint8_t p1 = pos >= 1 ? + ringbuffer[(size_t)(pos - 1) & ringbuffer_mask] : 0; + uint8_t p2 = pos >= 2 ? + ringbuffer[(size_t)(pos - 2) & ringbuffer_mask] : 0; + dict_id = params->dictionary.contextual.context_map[ + BROTLI_CONTEXT(p1, p2, literal_context_lut)]; + } + /* Ensure that we have enough free slots. */ + BROTLI_ENSURE_CAPACITY(m, BackwardMatch, matches, matches_size, + cur_match_pos + MAX_NUM_MATCHES_H10 + shadow_matches); + if (BROTLI_IS_OOM(m)) return; + num_found_matches = FindAllMatchesH10(&hasher->privat._H10, + params->dictionary.contextual.dict[dict_id], + ringbuffer, ringbuffer_mask, pos, max_length, + max_distance, dictionary_start + gap, params, + &matches[cur_match_pos + shadow_matches]); + if (addon->num_chunks != 0) { + size_t cd_matches = LookupAllCompoundDictionaryMatches(addon, + ringbuffer, ringbuffer_mask, pos, 3, max_length, + dictionary_start, params->dist.max_distance, + &matches[cur_match_pos + shadow_matches - 64], 64); + MergeMatches(&matches[cur_match_pos], + &matches[cur_match_pos + shadow_matches - 64], cd_matches, + &matches[cur_match_pos + shadow_matches], num_found_matches); + num_found_matches += cd_matches; + } + cur_match_end = cur_match_pos + num_found_matches; + for (j = cur_match_pos; j + 1 < cur_match_end; ++j) { + BROTLI_DCHECK(BackwardMatchLength(&matches[j]) <= + BackwardMatchLength(&matches[j + 1])); + } + num_matches[i] = (uint32_t)num_found_matches; + if (num_found_matches > 0) { + const size_t match_len = BackwardMatchLength(&matches[cur_match_end - 1]); + if (match_len > MAX_ZOPFLI_LEN_QUALITY_11) { + const size_t skip = match_len - 1; + matches[cur_match_pos++] = matches[cur_match_end - 1]; + num_matches[i] = 1; + /* Add the tail of the copy to the hasher. */ + StoreRangeH10(&hasher->privat._H10, + ringbuffer, ringbuffer_mask, pos + 1, + BROTLI_MIN(size_t, pos + match_len, store_end)); + memset(&num_matches[i + 1], 0, skip * sizeof(num_matches[0])); + i += skip; + } else { + cur_match_pos = cur_match_end; + } + } + } + orig_num_literals = *num_literals; + orig_last_insert_len = *last_insert_len; + memcpy(orig_dist_cache, dist_cache, 4 * sizeof(dist_cache[0])); + orig_num_commands = *num_commands; + nodes = BROTLI_ALLOC(m, ZopfliNode, num_bytes + 1); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(nodes)) return; + InitZopfliCostModel(m, model, ¶ms->dist, num_bytes); + if (BROTLI_IS_OOM(m)) return; + for (i = 0; i < 2; i++) { + BrotliInitZopfliNodes(nodes, num_bytes + 1); + if (i == 0) { + ZopfliCostModelSetFromLiteralCosts( + model, position, ringbuffer, ringbuffer_mask); + } else { + ZopfliCostModelSetFromCommands(model, position, ringbuffer, + ringbuffer_mask, commands, *num_commands - orig_num_commands, + orig_last_insert_len); + } + *num_commands = orig_num_commands; + *num_literals = orig_num_literals; + *last_insert_len = orig_last_insert_len; + memcpy(dist_cache, orig_dist_cache, 4 * sizeof(dist_cache[0])); + *num_commands += ZopfliIterate(num_bytes, position, ringbuffer, + ringbuffer_mask, params, gap, dist_cache, model, num_matches, matches, + nodes); + BrotliZopfliCreateCommands(num_bytes, position, nodes, dist_cache, + last_insert_len, params, commands, num_literals); + } + CleanupZopfliCostModel(m, model); + BROTLI_FREE(m, model); + BROTLI_FREE(m, nodes); + BROTLI_FREE(m, matches); + BROTLI_FREE(m, num_matches); +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/backward_references_hq.h b/packages/runtime/vendor/brotli/c/enc/backward_references_hq.h new file mode 100644 index 000000000..4aa270674 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/backward_references_hq.h @@ -0,0 +1,92 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Function to find backward reference copies. */ + +#ifndef BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_ +#define BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_ + +#include "../common/context.h" +#include "../common/platform.h" +#include "command.h" +#include "hash.h" +#include "memory.h" +#include "params.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +BROTLI_INTERNAL void BrotliCreateZopfliBackwardReferences(MemoryManager* m, + size_t num_bytes, + size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, + ContextLut literal_context_lut, const BrotliEncoderParams* params, + Hasher* hasher, int* dist_cache, size_t* last_insert_len, + Command* commands, size_t* num_commands, size_t* num_literals); + +BROTLI_INTERNAL void BrotliCreateHqZopfliBackwardReferences(MemoryManager* m, + size_t num_bytes, + size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, + ContextLut literal_context_lut, const BrotliEncoderParams* params, + Hasher* hasher, int* dist_cache, size_t* last_insert_len, + Command* commands, size_t* num_commands, size_t* num_literals); + +typedef struct ZopfliNode { + /* Best length to get up to this byte (not including this byte itself) + highest 7 bit is used to reconstruct the length code. */ + uint32_t length; + /* Distance associated with the length. */ + uint32_t distance; + /* Number of literal inserts before this copy; highest 5 bits contain + distance short code + 1 (or zero if no short code). */ + uint32_t dcode_insert_length; + + /* This union holds information used by dynamic-programming. During forward + pass |cost| it used to store the goal function. When node is processed its + |cost| is invalidated in favor of |shortcut|. On path back-tracing pass + |next| is assigned the offset to next node on the path. */ + union { + /* Smallest cost to get to this byte from the beginning, as found so far. */ + float cost; + /* Offset to the next node on the path. Equals to command_length() of the + next node on the path. For last node equals to BROTLI_UINT32_MAX */ + uint32_t next; + /* Node position that provides next distance for distance cache. */ + uint32_t shortcut; + } u; +} ZopfliNode; + +BROTLI_INTERNAL void BrotliInitZopfliNodes(ZopfliNode* array, size_t length); + +/* Computes the shortest path of commands from position to at most + position + num_bytes. + + On return, path->size() is the number of commands found and path[i] is the + length of the i-th command (copy length plus insert length). + Note that the sum of the lengths of all commands can be less than num_bytes. + + On return, the nodes[0..num_bytes] array will have the following + "ZopfliNode array invariant": + For each i in [1..num_bytes], if nodes[i].cost < kInfinity, then + (1) nodes[i].copy_length() >= 2 + (2) nodes[i].command_length() <= i and + (3) nodes[i - nodes[i].command_length()].cost < kInfinity */ +BROTLI_INTERNAL size_t BrotliZopfliComputeShortestPath( + MemoryManager* m, size_t num_bytes, + size_t position, const uint8_t* ringbuffer, size_t ringbuffer_mask, + ContextLut literal_context_lut, const BrotliEncoderParams* params, + const int* dist_cache, Hasher* hasher, ZopfliNode* nodes); + +BROTLI_INTERNAL void BrotliZopfliCreateCommands( + const size_t num_bytes, const size_t block_start, const ZopfliNode* nodes, + int* dist_cache, size_t* last_insert_len, const BrotliEncoderParams* params, + Command* commands, size_t* num_literals); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_BACKWARD_REFERENCES_HQ_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/backward_references_inc.h b/packages/runtime/vendor/brotli/c/enc/backward_references_inc.h new file mode 100644 index 000000000..752c12e9f --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/backward_references_inc.h @@ -0,0 +1,189 @@ +/* NOLINT(build/header_guard) */ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* template parameters: EXPORT_FN, FN */ + +static BROTLI_NOINLINE void EXPORT_FN(CreateBackwardReferences)( + size_t num_bytes, size_t position, + const uint8_t* ringbuffer, size_t ringbuffer_mask, + ContextLut literal_context_lut, const BrotliEncoderParams* params, + Hasher* hasher, int* dist_cache, size_t* last_insert_len, + Command* commands, size_t* num_commands, size_t* num_literals) { + HASHER()* privat = &hasher->privat.FN(_); + /* Set maximum distance, see section 9.1. of the spec. */ + const size_t max_backward_limit = BROTLI_MAX_BACKWARD_LIMIT(params->lgwin); + const size_t position_offset = params->stream_offset; + + const Command* const orig_commands = commands; + size_t insert_length = *last_insert_len; + const size_t pos_end = position + num_bytes; + const size_t store_end = num_bytes >= FN(StoreLookahead)() ? + position + num_bytes - FN(StoreLookahead)() + 1 : position; + + /* For speed up heuristics for random data. */ + const size_t random_heuristics_window_size = + LiteralSpreeLengthForSparseSearch(params); + size_t apply_random_heuristics = position + random_heuristics_window_size; + const size_t gap = params->dictionary.compound.total_size; + + /* Minimum score to accept a backward reference. */ + const score_t kMinScore = BROTLI_SCORE_BASE + 100; + + FN(PrepareDistanceCache)(privat, dist_cache); + + while (position + FN(HashTypeLength)() < pos_end) { + size_t max_length = pos_end - position; + size_t max_distance = BROTLI_MIN(size_t, position, max_backward_limit); + size_t dictionary_start = BROTLI_MIN(size_t, + position + position_offset, max_backward_limit); + HasherSearchResult sr; + int dict_id = 0; + uint8_t p1 = 0; + uint8_t p2 = 0; + if (params->dictionary.contextual.context_based) { + p1 = position >= 1 ? + ringbuffer[(size_t)(position - 1) & ringbuffer_mask] : 0; + p2 = position >= 2 ? + ringbuffer[(size_t)(position - 2) & ringbuffer_mask] : 0; + dict_id = params->dictionary.contextual.context_map[ + BROTLI_CONTEXT(p1, p2, literal_context_lut)]; + } + sr.len = 0; + sr.len_code_delta = 0; + sr.distance = 0; + sr.score = kMinScore; + FN(FindLongestMatch)(privat, params->dictionary.contextual.dict[dict_id], + ringbuffer, ringbuffer_mask, dist_cache, position, max_length, + max_distance, dictionary_start + gap, params->dist.max_distance, &sr); + if (ENABLE_COMPOUND_DICTIONARY) { + LookupCompoundDictionaryMatch(¶ms->dictionary.compound, ringbuffer, + ringbuffer_mask, dist_cache, position, max_length, + dictionary_start, params->dist.max_distance, &sr); + } + if (sr.score > kMinScore) { + /* Found a match. Let's look for something even better ahead. */ + int delayed_backward_references_in_row = 0; + --max_length; + for (;; --max_length) { + const score_t cost_diff_lazy = 175; + HasherSearchResult sr2; + sr2.len = params->quality < MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH ? + BROTLI_MIN(size_t, sr.len - 1, max_length) : 0; + sr2.len_code_delta = 0; + sr2.distance = 0; + sr2.score = kMinScore; + max_distance = BROTLI_MIN(size_t, position + 1, max_backward_limit); + dictionary_start = BROTLI_MIN(size_t, + position + 1 + position_offset, max_backward_limit); + if (params->dictionary.contextual.context_based) { + p2 = p1; + p1 = ringbuffer[position & ringbuffer_mask]; + dict_id = params->dictionary.contextual.context_map[ + BROTLI_CONTEXT(p1, p2, literal_context_lut)]; + } + FN(FindLongestMatch)(privat, + params->dictionary.contextual.dict[dict_id], + ringbuffer, ringbuffer_mask, dist_cache, position + 1, max_length, + max_distance, dictionary_start + gap, params->dist.max_distance, + &sr2); + if (ENABLE_COMPOUND_DICTIONARY) { + LookupCompoundDictionaryMatch( + ¶ms->dictionary.compound, ringbuffer, + ringbuffer_mask, dist_cache, position + 1, max_length, + dictionary_start, params->dist.max_distance, &sr2); + } + if (sr2.score >= sr.score + cost_diff_lazy) { + /* Ok, let's just write one byte for now and start a match from the + next byte. */ + ++position; + ++insert_length; + sr = sr2; + if (++delayed_backward_references_in_row < 4 && + position + FN(HashTypeLength)() < pos_end) { + continue; + } + } + break; + } + apply_random_heuristics = + position + 2 * sr.len + random_heuristics_window_size; + dictionary_start = BROTLI_MIN(size_t, + position + position_offset, max_backward_limit); + { + /* The first 16 codes are special short-codes, + and the minimum offset is 1. */ + size_t distance_code = ComputeDistanceCode( + sr.distance, dictionary_start + gap, dist_cache); + if ((sr.distance <= (dictionary_start + gap)) && distance_code > 0) { + dist_cache[3] = dist_cache[2]; + dist_cache[2] = dist_cache[1]; + dist_cache[1] = dist_cache[0]; + dist_cache[0] = (int)sr.distance; + FN(PrepareDistanceCache)(privat, dist_cache); + } + InitCommand(commands++, ¶ms->dist, insert_length, + sr.len, sr.len_code_delta, distance_code); + } + *num_literals += insert_length; + insert_length = 0; + /* Put the hash keys into the table, if there are enough bytes left. + Depending on the hasher implementation, it can push all positions + in the given range or only a subset of them. + Avoid hash poisoning with RLE data. */ + { + size_t range_start = position + 2; + size_t range_end = BROTLI_MIN(size_t, position + sr.len, store_end); + if (sr.distance < (sr.len >> 2)) { + range_start = BROTLI_MIN(size_t, range_end, BROTLI_MAX(size_t, + range_start, position + sr.len - (sr.distance << 2))); + } + FN(StoreRange)(privat, ringbuffer, ringbuffer_mask, range_start, + range_end); + } + position += sr.len; + } else { + ++insert_length; + ++position; + /* If we have not seen matches for a long time, we can skip some + match lookups. Unsuccessful match lookups are very very expensive + and this kind of a heuristic speeds up compression quite + a lot. */ + if (position > apply_random_heuristics) { + /* Going through uncompressible data, jump. */ + if (position > + apply_random_heuristics + 4 * random_heuristics_window_size) { + /* It is quite a long time since we saw a copy, so we assume + that this data is not compressible, and store hashes less + often. Hashes of non compressible data are less likely to + turn out to be useful in the future, too, so we store less of + them to not to flood out the hash table of good compressible + data. */ + const size_t kMargin = + BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 4); + size_t pos_jump = + BROTLI_MIN(size_t, position + 16, pos_end - kMargin); + for (; position < pos_jump; position += 4) { + FN(Store)(privat, ringbuffer, ringbuffer_mask, position); + insert_length += 4; + } + } else { + const size_t kMargin = + BROTLI_MAX(size_t, FN(StoreLookahead)() - 1, 2); + size_t pos_jump = + BROTLI_MIN(size_t, position + 8, pos_end - kMargin); + for (; position < pos_jump; position += 2) { + FN(Store)(privat, ringbuffer, ringbuffer_mask, position); + insert_length += 2; + } + } + } + } + } + insert_length += pos_end - position; + *last_insert_len = insert_length; + *num_commands += (size_t)(commands - orig_commands); +} diff --git a/packages/runtime/vendor/brotli/c/enc/bit_cost.c b/packages/runtime/vendor/brotli/c/enc/bit_cost.c new file mode 100644 index 000000000..059f8d996 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/bit_cost.c @@ -0,0 +1,60 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Functions to estimate the bit cost of Huffman trees. */ + +#include "bit_cost.h" + +#include "../common/platform.h" +#include "fast_log.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +double BrotliBitsEntropy(const uint32_t* population, size_t size) { + size_t sum = 0; + double retval = 0; + const uint32_t* population_end = population + size; + size_t p; + if (size & 1) { + goto odd_number_of_elements_left; + } + while (population < population_end) { + p = *population++; + sum += p; + retval -= (double)p * FastLog2(p); + odd_number_of_elements_left: + p = *population++; + sum += p; + retval -= (double)p * FastLog2(p); + } + if (sum) retval += (double)sum * FastLog2(sum); + + if (retval < (double)sum) { + /* TODO(eustas): consider doing that per-symbol? */ + /* At least one bit per literal is needed. */ + retval = (double)sum; + } + + return retval; +} + +#define FN(X) X ## Literal +#include "bit_cost_inc.h" /* NOLINT(build/include) */ +#undef FN + +#define FN(X) X ## Command +#include "bit_cost_inc.h" /* NOLINT(build/include) */ +#undef FN + +#define FN(X) X ## Distance +#include "bit_cost_inc.h" /* NOLINT(build/include) */ +#undef FN + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/bit_cost.h b/packages/runtime/vendor/brotli/c/enc/bit_cost.h new file mode 100644 index 000000000..90313c4c3 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/bit_cost.h @@ -0,0 +1,32 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Functions to estimate the bit cost of Huffman trees. */ + +#ifndef BROTLI_ENC_BIT_COST_H_ +#define BROTLI_ENC_BIT_COST_H_ + +#include "../common/platform.h" +#include "histogram.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +BROTLI_INTERNAL double BrotliBitsEntropy( + const uint32_t* population, size_t size); +BROTLI_INTERNAL double BrotliPopulationCostLiteral( + const HistogramLiteral* histogram); +BROTLI_INTERNAL double BrotliPopulationCostCommand( + const HistogramCommand* histogram); +BROTLI_INTERNAL double BrotliPopulationCostDistance( + const HistogramDistance* histogram); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_BIT_COST_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/bit_cost_inc.h b/packages/runtime/vendor/brotli/c/enc/bit_cost_inc.h new file mode 100644 index 000000000..8e67f2503 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/bit_cost_inc.h @@ -0,0 +1,127 @@ +/* NOLINT(build/header_guard) */ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* template parameters: FN */ + +#define HistogramType FN(Histogram) + +double FN(BrotliPopulationCost)(const HistogramType* histogram) { + static const double kOneSymbolHistogramCost = 12; + static const double kTwoSymbolHistogramCost = 20; + static const double kThreeSymbolHistogramCost = 28; + static const double kFourSymbolHistogramCost = 37; + const size_t data_size = FN(HistogramDataSize)(); + int count = 0; + size_t s[5]; + double bits = 0.0; + size_t i; + if (histogram->total_count_ == 0) { + return kOneSymbolHistogramCost; + } + for (i = 0; i < data_size; ++i) { + if (histogram->data_[i] > 0) { + s[count] = i; + ++count; + if (count > 4) break; + } + } + if (count == 1) { + return kOneSymbolHistogramCost; + } + if (count == 2) { + return (kTwoSymbolHistogramCost + (double)histogram->total_count_); + } + if (count == 3) { + const uint32_t histo0 = histogram->data_[s[0]]; + const uint32_t histo1 = histogram->data_[s[1]]; + const uint32_t histo2 = histogram->data_[s[2]]; + const uint32_t histomax = + BROTLI_MAX(uint32_t, histo0, BROTLI_MAX(uint32_t, histo1, histo2)); + return (kThreeSymbolHistogramCost + + 2 * (histo0 + histo1 + histo2) - histomax); + } + if (count == 4) { + uint32_t histo[4]; + uint32_t h23; + uint32_t histomax; + for (i = 0; i < 4; ++i) { + histo[i] = histogram->data_[s[i]]; + } + /* Sort */ + for (i = 0; i < 4; ++i) { + size_t j; + for (j = i + 1; j < 4; ++j) { + if (histo[j] > histo[i]) { + BROTLI_SWAP(uint32_t, histo, j, i); + } + } + } + h23 = histo[2] + histo[3]; + histomax = BROTLI_MAX(uint32_t, h23, histo[0]); + return (kFourSymbolHistogramCost + + 3 * h23 + 2 * (histo[0] + histo[1]) - histomax); + } + + { + /* In this loop we compute the entropy of the histogram and simultaneously + build a simplified histogram of the code length codes where we use the + zero repeat code 17, but we don't use the non-zero repeat code 16. */ + size_t max_depth = 1; + uint32_t depth_histo[BROTLI_CODE_LENGTH_CODES] = { 0 }; + const double log2total = FastLog2(histogram->total_count_); + for (i = 0; i < data_size;) { + if (histogram->data_[i] > 0) { + /* Compute -log2(P(symbol)) = -log2(count(symbol)/total_count) = + = log2(total_count) - log2(count(symbol)) */ + double log2p = log2total - FastLog2(histogram->data_[i]); + /* Approximate the bit depth by round(-log2(P(symbol))) */ + size_t depth = (size_t)(log2p + 0.5); + bits += histogram->data_[i] * log2p; + if (depth > 15) { + depth = 15; + } + if (depth > max_depth) { + max_depth = depth; + } + ++depth_histo[depth]; + ++i; + } else { + /* Compute the run length of zeros and add the appropriate number of 0 + and 17 code length codes to the code length code histogram. */ + uint32_t reps = 1; + size_t k; + for (k = i + 1; k < data_size && histogram->data_[k] == 0; ++k) { + ++reps; + } + i += reps; + if (i == data_size) { + /* Don't add any cost for the last zero run, since these are encoded + only implicitly. */ + break; + } + if (reps < 3) { + depth_histo[0] += reps; + } else { + reps -= 2; + while (reps > 0) { + ++depth_histo[BROTLI_REPEAT_ZERO_CODE_LENGTH]; + /* Add the 3 extra bits for the 17 code length code. */ + bits += 3; + reps >>= 3; + } + } + } + } + /* Add the estimated encoding cost of the code length code histogram. */ + bits += (double)(18 + 2 * max_depth); + /* Add the entropy of the code length code histogram. */ + bits += BrotliBitsEntropy(depth_histo, BROTLI_CODE_LENGTH_CODES); + } + return bits; +} + +#undef HistogramType diff --git a/packages/runtime/vendor/brotli/c/enc/block_encoder_inc.h b/packages/runtime/vendor/brotli/c/enc/block_encoder_inc.h new file mode 100644 index 000000000..8cbd5eac6 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/block_encoder_inc.h @@ -0,0 +1,34 @@ +/* NOLINT(build/header_guard) */ +/* Copyright 2014 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* template parameters: FN */ + +#define HistogramType FN(Histogram) + +/* Creates entropy codes for all block types and stores them to the bit + stream. */ +static void FN(BuildAndStoreEntropyCodes)(MemoryManager* m, BlockEncoder* self, + const HistogramType* histograms, const size_t histograms_size, + const size_t alphabet_size, HuffmanTree* tree, + size_t* storage_ix, uint8_t* storage) { + const size_t table_size = histograms_size * self->histogram_length_; + self->depths_ = BROTLI_ALLOC(m, uint8_t, table_size); + self->bits_ = BROTLI_ALLOC(m, uint16_t, table_size); + if (BROTLI_IS_OOM(m)) return; + + { + size_t i; + for (i = 0; i < histograms_size; ++i) { + size_t ix = i * self->histogram_length_; + BuildAndStoreHuffmanTree(&histograms[i].data_[0], self->histogram_length_, + alphabet_size, tree, &self->depths_[ix], &self->bits_[ix], + storage_ix, storage); + } + } +} + +#undef HistogramType diff --git a/packages/runtime/vendor/brotli/c/enc/block_splitter.c b/packages/runtime/vendor/brotli/c/enc/block_splitter.c new file mode 100644 index 000000000..13e924f09 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/block_splitter.c @@ -0,0 +1,214 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Block split point selection utilities. */ + +#include "block_splitter.h" + +#include "../common/platform.h" +#include "bit_cost.h" +#include "cluster.h" +#include "command.h" +#include "fast_log.h" +#include "histogram.h" +#include "memory.h" +#include "quality.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +static const size_t kMaxLiteralHistograms = 100; +static const size_t kMaxCommandHistograms = 50; +static const double kLiteralBlockSwitchCost = 28.1; +static const double kCommandBlockSwitchCost = 13.5; +static const double kDistanceBlockSwitchCost = 14.6; +static const size_t kLiteralStrideLength = 70; +static const size_t kCommandStrideLength = 40; +static const size_t kDistanceStrideLength = 40; +static const size_t kSymbolsPerLiteralHistogram = 544; +static const size_t kSymbolsPerCommandHistogram = 530; +static const size_t kSymbolsPerDistanceHistogram = 544; +static const size_t kMinLengthForBlockSplitting = 128; +static const size_t kIterMulForRefining = 2; +static const size_t kMinItersForRefining = 100; + +static size_t CountLiterals(const Command* cmds, const size_t num_commands) { + /* Count how many we have. */ + size_t total_length = 0; + size_t i; + for (i = 0; i < num_commands; ++i) { + total_length += cmds[i].insert_len_; + } + return total_length; +} + +static void CopyLiteralsToByteArray(const Command* cmds, + const size_t num_commands, + const uint8_t* data, + const size_t offset, + const size_t mask, + uint8_t* literals) { + size_t pos = 0; + size_t from_pos = offset & mask; + size_t i; + for (i = 0; i < num_commands; ++i) { + size_t insert_len = cmds[i].insert_len_; + if (from_pos + insert_len > mask) { + size_t head_size = mask + 1 - from_pos; + memcpy(literals + pos, data + from_pos, head_size); + from_pos = 0; + pos += head_size; + insert_len -= head_size; + } + if (insert_len > 0) { + memcpy(literals + pos, data + from_pos, insert_len); + pos += insert_len; + } + from_pos = (from_pos + insert_len + CommandCopyLen(&cmds[i])) & mask; + } +} + +static BROTLI_INLINE uint32_t MyRand(uint32_t* seed) { + /* Initial seed should be 7. In this case, loop length is (1 << 29). */ + *seed *= 16807U; + return *seed; +} + +static BROTLI_INLINE double BitCost(size_t count) { + return count == 0 ? -2.0 : FastLog2(count); +} + +#define HISTOGRAMS_PER_BATCH 64 +#define CLUSTERS_PER_BATCH 16 + +#define FN(X) X ## Literal +#define DataType uint8_t +/* NOLINTNEXTLINE(build/include) */ +#include "block_splitter_inc.h" +#undef DataType +#undef FN + +#define FN(X) X ## Command +#define DataType uint16_t +/* NOLINTNEXTLINE(build/include) */ +#include "block_splitter_inc.h" +#undef FN + +#define FN(X) X ## Distance +/* NOLINTNEXTLINE(build/include) */ +#include "block_splitter_inc.h" +#undef DataType +#undef FN + +void BrotliInitBlockSplit(BlockSplit* self) { + self->num_types = 0; + self->num_blocks = 0; + self->types = 0; + self->lengths = 0; + self->types_alloc_size = 0; + self->lengths_alloc_size = 0; +} + +void BrotliDestroyBlockSplit(MemoryManager* m, BlockSplit* self) { + BROTLI_FREE(m, self->types); + BROTLI_FREE(m, self->lengths); +} + +/* Extracts literals, command distance and prefix codes, then applies + * SplitByteVector to create partitioning. */ +void BrotliSplitBlock(MemoryManager* m, + const Command* cmds, + const size_t num_commands, + const uint8_t* data, + const size_t pos, + const size_t mask, + const BrotliEncoderParams* params, + BlockSplit* literal_split, + BlockSplit* insert_and_copy_split, + BlockSplit* dist_split) { + { + size_t literals_count = CountLiterals(cmds, num_commands); + uint8_t* literals = BROTLI_ALLOC(m, uint8_t, literals_count); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literals)) return; + /* Create a continuous array of literals. */ + CopyLiteralsToByteArray(cmds, num_commands, data, pos, mask, literals); + /* Create the block split on the array of literals. + * Literal histograms can have alphabet size up to 256. + * Though, to accommodate context modeling, less than half of maximum size + * is allowed. */ + SplitByteVectorLiteral( + m, literals, literals_count, + kSymbolsPerLiteralHistogram, kMaxLiteralHistograms, + kLiteralStrideLength, kLiteralBlockSwitchCost, params, + literal_split); + if (BROTLI_IS_OOM(m)) return; + BROTLI_FREE(m, literals); + /* NB: this might be a good place for injecting extra splitting without + * increasing encoder complexity; however, output partition would be less + * optimal than one produced with forced splitting inside + * SplitByteVector (FindBlocks / ClusterBlocks). */ + } + + { + /* Compute prefix codes for commands. */ + uint16_t* insert_and_copy_codes = BROTLI_ALLOC(m, uint16_t, num_commands); + size_t i; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(insert_and_copy_codes)) return; + for (i = 0; i < num_commands; ++i) { + insert_and_copy_codes[i] = cmds[i].cmd_prefix_; + } + /* Create the block split on the array of command prefixes. */ + SplitByteVectorCommand( + m, insert_and_copy_codes, num_commands, + kSymbolsPerCommandHistogram, kMaxCommandHistograms, + kCommandStrideLength, kCommandBlockSwitchCost, params, + insert_and_copy_split); + if (BROTLI_IS_OOM(m)) return; + /* TODO(eustas): reuse for distances? */ + BROTLI_FREE(m, insert_and_copy_codes); + } + + { + /* Create a continuous array of distance prefixes. */ + uint16_t* distance_prefixes = BROTLI_ALLOC(m, uint16_t, num_commands); + size_t j = 0; + size_t i; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(distance_prefixes)) return; + for (i = 0; i < num_commands; ++i) { + const Command* cmd = &cmds[i]; + if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) { + distance_prefixes[j++] = cmd->dist_prefix_ & 0x3FF; + } + } + /* Create the block split on the array of distance prefixes. */ + SplitByteVectorDistance( + m, distance_prefixes, j, + kSymbolsPerDistanceHistogram, kMaxCommandHistograms, + kDistanceStrideLength, kDistanceBlockSwitchCost, params, + dist_split); + if (BROTLI_IS_OOM(m)) return; + BROTLI_FREE(m, distance_prefixes); + } +} + +#if defined(BROTLI_TEST) +size_t BrotliCountLiteralsForTest(const Command*, size_t); +size_t BrotliCountLiteralsForTest(const Command* cmds, size_t num_commands) { + return CountLiterals(cmds, num_commands); +} +void BrotliCopyLiteralsToByteArrayForTest( + const Command*, size_t, const uint8_t*, size_t, size_t, uint8_t*); +void BrotliCopyLiteralsToByteArrayForTest(const Command* cmds, + size_t num_commands, const uint8_t* data, size_t offset, size_t mask, + uint8_t* literals) { + CopyLiteralsToByteArray(cmds, num_commands, data, offset, mask, literals); +} +#endif + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/block_splitter.h b/packages/runtime/vendor/brotli/c/enc/block_splitter.h new file mode 100644 index 000000000..c927794eb --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/block_splitter.h @@ -0,0 +1,49 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Block split point selection utilities. */ + +#ifndef BROTLI_ENC_BLOCK_SPLITTER_H_ +#define BROTLI_ENC_BLOCK_SPLITTER_H_ + +#include "../common/platform.h" +#include "command.h" +#include "memory.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +typedef struct BlockSplit { + size_t num_types; /* Amount of distinct types */ + size_t num_blocks; /* Amount of values in types and length */ + uint8_t* types; + uint32_t* lengths; + + size_t types_alloc_size; + size_t lengths_alloc_size; +} BlockSplit; + +BROTLI_INTERNAL void BrotliInitBlockSplit(BlockSplit* self); +BROTLI_INTERNAL void BrotliDestroyBlockSplit(MemoryManager* m, + BlockSplit* self); + +BROTLI_INTERNAL void BrotliSplitBlock(MemoryManager* m, + const Command* cmds, + const size_t num_commands, + const uint8_t* data, + const size_t offset, + const size_t mask, + const BrotliEncoderParams* params, + BlockSplit* literal_split, + BlockSplit* insert_and_copy_split, + BlockSplit* dist_split); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_BLOCK_SPLITTER_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/block_splitter_inc.h b/packages/runtime/vendor/brotli/c/enc/block_splitter_inc.h new file mode 100644 index 000000000..5e34cb9c9 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/block_splitter_inc.h @@ -0,0 +1,487 @@ +/* NOLINT(build/header_guard) */ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* template parameters: FN, DataType */ + +#define HistogramType FN(Histogram) + +static void FN(InitialEntropyCodes)(const DataType* data, size_t length, + size_t stride, + size_t num_histograms, + HistogramType* histograms) { + uint32_t seed = 7; + size_t block_length = length / num_histograms; + size_t i; + FN(ClearHistograms)(histograms, num_histograms); + for (i = 0; i < num_histograms; ++i) { + size_t pos = length * i / num_histograms; + if (i != 0) { + pos += MyRand(&seed) % block_length; + } + if (pos + stride >= length) { + pos = length - stride - 1; + } + FN(HistogramAddVector)(&histograms[i], data + pos, stride); + } +} + +static void FN(RandomSample)(uint32_t* seed, + const DataType* data, + size_t length, + size_t stride, + HistogramType* sample) { + size_t pos = 0; + if (stride >= length) { + stride = length; + } else { + pos = MyRand(seed) % (length - stride + 1); + } + FN(HistogramAddVector)(sample, data + pos, stride); +} + +static void FN(RefineEntropyCodes)(const DataType* data, size_t length, + size_t stride, + size_t num_histograms, + HistogramType* histograms, + HistogramType* tmp) { + size_t iters = + kIterMulForRefining * length / stride + kMinItersForRefining; + uint32_t seed = 7; + size_t iter; + iters = ((iters + num_histograms - 1) / num_histograms) * num_histograms; + for (iter = 0; iter < iters; ++iter) { + FN(HistogramClear)(tmp); + FN(RandomSample)(&seed, data, length, stride, tmp); + FN(HistogramAddHistogram)(&histograms[iter % num_histograms], tmp); + } +} + +/* Assigns a block id from the range [0, num_histograms) to each data element + in data[0..length) and fills in block_id[0..length) with the assigned values. + Returns the number of blocks, i.e. one plus the number of block switches. */ +static size_t FN(FindBlocks)(const DataType* data, const size_t length, + const double block_switch_bitcost, + const size_t num_histograms, + const HistogramType* histograms, + double* insert_cost, + double* cost, + uint8_t* switch_signal, + uint8_t* block_id) { + const size_t alphabet_size = FN(HistogramDataSize)(); + const size_t bitmap_len = (num_histograms + 7) >> 3; + size_t num_blocks = 1; + size_t byte_ix; + size_t i; + size_t j; + BROTLI_DCHECK(num_histograms <= 256); + + /* Trivial case: single histogram -> single block type. */ + if (num_histograms <= 1) { + for (i = 0; i < length; ++i) { + block_id[i] = 0; + } + return 1; + } + + /* Fill bitcost for each symbol of all histograms. + * Non-existing symbol cost: 2 + log2(total_count). + * Regular symbol cost: -log2(symbol_count / total_count). */ + memset(insert_cost, 0, + sizeof(insert_cost[0]) * alphabet_size * num_histograms); + for (i = 0; i < num_histograms; ++i) { + insert_cost[i] = FastLog2((uint32_t)histograms[i].total_count_); + } + for (i = alphabet_size; i != 0;) { + /* Reverse order to use the 0-th row as a temporary storage. */ + --i; + for (j = 0; j < num_histograms; ++j) { + insert_cost[i * num_histograms + j] = + insert_cost[j] - BitCost(histograms[j].data_[i]); + } + } + + /* After each iteration of this loop, cost[k] will contain the difference + between the minimum cost of arriving at the current byte position using + entropy code k, and the minimum cost of arriving at the current byte + position. This difference is capped at the block switch cost, and if it + reaches block switch cost, it means that when we trace back from the last + position, we need to switch here. */ + memset(cost, 0, sizeof(cost[0]) * num_histograms); + memset(switch_signal, 0, sizeof(switch_signal[0]) * length * bitmap_len); + for (byte_ix = 0; byte_ix < length; ++byte_ix) { + size_t ix = byte_ix * bitmap_len; + size_t symbol = data[byte_ix]; + size_t insert_cost_ix = symbol * num_histograms; + double min_cost = 1e99; + double block_switch_cost = block_switch_bitcost; + static const size_t prologue_length = 2000; + static const double multiplier = 0.07 / 2000; + size_t k; + for (k = 0; k < num_histograms; ++k) { + /* We are coding the symbol with entropy code k. */ + cost[k] += insert_cost[insert_cost_ix + k]; + if (cost[k] < min_cost) { + min_cost = cost[k]; + block_id[byte_ix] = (uint8_t)k; + } + } + /* More blocks for the beginning. */ + if (byte_ix < prologue_length) { + block_switch_cost *= 0.77 + multiplier * (double)byte_ix; + } + for (k = 0; k < num_histograms; ++k) { + cost[k] -= min_cost; + if (cost[k] >= block_switch_cost) { + const uint8_t mask = (uint8_t)(1u << (k & 7)); + cost[k] = block_switch_cost; + BROTLI_DCHECK((k >> 3) < bitmap_len); + switch_signal[ix + (k >> 3)] |= mask; + } + } + } + + byte_ix = length - 1; + { /* Trace back from the last position and switch at the marked places. */ + size_t ix = byte_ix * bitmap_len; + uint8_t cur_id = block_id[byte_ix]; + while (byte_ix > 0) { + const uint8_t mask = (uint8_t)(1u << (cur_id & 7)); + BROTLI_DCHECK(((size_t)cur_id >> 3) < bitmap_len); + --byte_ix; + ix -= bitmap_len; + if (switch_signal[ix + (cur_id >> 3)] & mask) { + if (cur_id != block_id[byte_ix]) { + cur_id = block_id[byte_ix]; + ++num_blocks; + } + } + block_id[byte_ix] = cur_id; + } + } + return num_blocks; +} + +static size_t FN(RemapBlockIds)(uint8_t* block_ids, const size_t length, + uint16_t* new_id, const size_t num_histograms) { + static const uint16_t kInvalidId = 256; + uint16_t next_id = 0; + size_t i; + for (i = 0; i < num_histograms; ++i) { + new_id[i] = kInvalidId; + } + for (i = 0; i < length; ++i) { + BROTLI_DCHECK(block_ids[i] < num_histograms); + if (new_id[block_ids[i]] == kInvalidId) { + new_id[block_ids[i]] = next_id++; + } + } + for (i = 0; i < length; ++i) { + block_ids[i] = (uint8_t)new_id[block_ids[i]]; + BROTLI_DCHECK(block_ids[i] < num_histograms); + } + BROTLI_DCHECK(next_id <= num_histograms); + return next_id; +} + +static void FN(BuildBlockHistograms)(const DataType* data, const size_t length, + const uint8_t* block_ids, + const size_t num_histograms, + HistogramType* histograms) { + size_t i; + FN(ClearHistograms)(histograms, num_histograms); + for (i = 0; i < length; ++i) { + FN(HistogramAdd)(&histograms[block_ids[i]], data[i]); + } +} + +/* Given the initial partitioning build partitioning with limited number + * of histograms (and block types). */ +static void FN(ClusterBlocks)(MemoryManager* m, + const DataType* data, const size_t length, + const size_t num_blocks, + uint8_t* block_ids, + BlockSplit* split) { + uint32_t* histogram_symbols = BROTLI_ALLOC(m, uint32_t, num_blocks); + uint32_t* u32 = + BROTLI_ALLOC(m, uint32_t, num_blocks + 4 * HISTOGRAMS_PER_BATCH); + const size_t expected_num_clusters = CLUSTERS_PER_BATCH * + (num_blocks + HISTOGRAMS_PER_BATCH - 1) / HISTOGRAMS_PER_BATCH; + size_t all_histograms_size = 0; + size_t all_histograms_capacity = expected_num_clusters; + HistogramType* all_histograms = + BROTLI_ALLOC(m, HistogramType, all_histograms_capacity); + size_t cluster_size_size = 0; + size_t cluster_size_capacity = expected_num_clusters; + uint32_t* cluster_size = BROTLI_ALLOC(m, uint32_t, cluster_size_capacity); + size_t num_clusters = 0; + HistogramType* histograms = BROTLI_ALLOC(m, HistogramType, + BROTLI_MIN(size_t, num_blocks, HISTOGRAMS_PER_BATCH)); + size_t max_num_pairs = + HISTOGRAMS_PER_BATCH * HISTOGRAMS_PER_BATCH / 2; + size_t pairs_capacity = max_num_pairs + 1; + HistogramPair* pairs = BROTLI_ALLOC(m, HistogramPair, pairs_capacity); + size_t pos = 0; + uint32_t* clusters; + size_t num_final_clusters; + static const uint32_t kInvalidIndex = BROTLI_UINT32_MAX; + uint32_t* new_index; + size_t i; + uint32_t* BROTLI_RESTRICT const sizes = + u32 ? (u32 + 0 * HISTOGRAMS_PER_BATCH) : NULL; + uint32_t* BROTLI_RESTRICT const new_clusters = + u32 ? (u32 + 1 * HISTOGRAMS_PER_BATCH) : NULL; + uint32_t* BROTLI_RESTRICT const symbols = + u32 ? (u32 + 2 * HISTOGRAMS_PER_BATCH) : NULL; + uint32_t* BROTLI_RESTRICT const remap = + u32 ? (u32 + 3 * HISTOGRAMS_PER_BATCH) : NULL; + uint32_t* BROTLI_RESTRICT const block_lengths = + u32 ? (u32 + 4 * HISTOGRAMS_PER_BATCH) : NULL; + /* TODO(eustas): move to arena? */ + HistogramType* tmp = BROTLI_ALLOC(m, HistogramType, 2); + + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histogram_symbols) || + BROTLI_IS_NULL(u32) || BROTLI_IS_NULL(all_histograms) || + BROTLI_IS_NULL(cluster_size) || BROTLI_IS_NULL(histograms) || + BROTLI_IS_NULL(pairs) || BROTLI_IS_NULL(tmp)) { + return; + } + + memset(u32, 0, (num_blocks + 4 * HISTOGRAMS_PER_BATCH) * sizeof(uint32_t)); + + /* Calculate block lengths (convert repeating values -> series length). */ + { + size_t block_idx = 0; + for (i = 0; i < length; ++i) { + BROTLI_DCHECK(block_idx < num_blocks); + ++block_lengths[block_idx]; + if (i + 1 == length || block_ids[i] != block_ids[i + 1]) { + ++block_idx; + } + } + BROTLI_DCHECK(block_idx == num_blocks); + } + + /* Pre-cluster blocks (cluster batches). */ + for (i = 0; i < num_blocks; i += HISTOGRAMS_PER_BATCH) { + const size_t num_to_combine = + BROTLI_MIN(size_t, num_blocks - i, HISTOGRAMS_PER_BATCH); + size_t num_new_clusters; + size_t j; + for (j = 0; j < num_to_combine; ++j) { + size_t k; + size_t block_length = block_lengths[i + j]; + FN(HistogramClear)(&histograms[j]); + for (k = 0; k < block_length; ++k) { + FN(HistogramAdd)(&histograms[j], data[pos++]); + } + histograms[j].bit_cost_ = FN(BrotliPopulationCost)(&histograms[j]); + new_clusters[j] = (uint32_t)j; + symbols[j] = (uint32_t)j; + sizes[j] = 1; + } + num_new_clusters = FN(BrotliHistogramCombine)( + histograms, tmp, sizes, symbols, new_clusters, pairs, num_to_combine, + num_to_combine, HISTOGRAMS_PER_BATCH, max_num_pairs); + BROTLI_ENSURE_CAPACITY(m, HistogramType, all_histograms, + all_histograms_capacity, all_histograms_size + num_new_clusters); + BROTLI_ENSURE_CAPACITY(m, uint32_t, cluster_size, + cluster_size_capacity, cluster_size_size + num_new_clusters); + if (BROTLI_IS_OOM(m)) return; + for (j = 0; j < num_new_clusters; ++j) { + all_histograms[all_histograms_size++] = histograms[new_clusters[j]]; + cluster_size[cluster_size_size++] = sizes[new_clusters[j]]; + remap[new_clusters[j]] = (uint32_t)j; + } + for (j = 0; j < num_to_combine; ++j) { + histogram_symbols[i + j] = (uint32_t)num_clusters + remap[symbols[j]]; + } + num_clusters += num_new_clusters; + BROTLI_DCHECK(num_clusters == cluster_size_size); + BROTLI_DCHECK(num_clusters == all_histograms_size); + } + BROTLI_FREE(m, histograms); + + /* Final clustering. */ + max_num_pairs = + BROTLI_MIN(size_t, 64 * num_clusters, (num_clusters / 2) * num_clusters); + if (pairs_capacity < max_num_pairs + 1) { + BROTLI_FREE(m, pairs); + pairs = BROTLI_ALLOC(m, HistogramPair, max_num_pairs + 1); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(pairs)) return; + } + clusters = BROTLI_ALLOC(m, uint32_t, num_clusters); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(clusters)) return; + for (i = 0; i < num_clusters; ++i) { + clusters[i] = (uint32_t)i; + } + num_final_clusters = FN(BrotliHistogramCombine)( + all_histograms, tmp, cluster_size, histogram_symbols, clusters, pairs, + num_clusters, num_blocks, BROTLI_MAX_NUMBER_OF_BLOCK_TYPES, + max_num_pairs); + BROTLI_FREE(m, pairs); + BROTLI_FREE(m, cluster_size); + + /* Assign blocks to final histograms. */ + new_index = BROTLI_ALLOC(m, uint32_t, num_clusters); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return; + for (i = 0; i < num_clusters; ++i) new_index[i] = kInvalidIndex; + pos = 0; + { + uint32_t next_index = 0; + for (i = 0; i < num_blocks; ++i) { + size_t j; + uint32_t best_out; + double best_bits; + FN(HistogramClear)(tmp); + for (j = 0; j < block_lengths[i]; ++j) { + FN(HistogramAdd)(tmp, data[pos++]); + } + /* Among equally good histograms prefer last used. */ + /* TODO(eustas): should we give a block-switch discount here? */ + best_out = (i == 0) ? histogram_symbols[0] : histogram_symbols[i - 1]; + best_bits = FN(BrotliHistogramBitCostDistance)( + tmp, &all_histograms[best_out], tmp + 1); + for (j = 0; j < num_final_clusters; ++j) { + const double cur_bits = FN(BrotliHistogramBitCostDistance)( + tmp, &all_histograms[clusters[j]], tmp + 1); + if (cur_bits < best_bits) { + best_bits = cur_bits; + best_out = clusters[j]; + } + } + histogram_symbols[i] = best_out; + if (new_index[best_out] == kInvalidIndex) { + new_index[best_out] = next_index++; + } + } + } + BROTLI_FREE(m, tmp); + BROTLI_FREE(m, clusters); + BROTLI_FREE(m, all_histograms); + BROTLI_ENSURE_CAPACITY( + m, uint8_t, split->types, split->types_alloc_size, num_blocks); + BROTLI_ENSURE_CAPACITY( + m, uint32_t, split->lengths, split->lengths_alloc_size, num_blocks); + if (BROTLI_IS_OOM(m)) return; + + /* Rewrite final assignment to block-split. There might be less blocks + * than |num_blocks| due to clustering. */ + { + uint32_t cur_length = 0; + size_t block_idx = 0; + uint8_t max_type = 0; + for (i = 0; i < num_blocks; ++i) { + cur_length += block_lengths[i]; + if (i + 1 == num_blocks || + histogram_symbols[i] != histogram_symbols[i + 1]) { + const uint8_t id = (uint8_t)new_index[histogram_symbols[i]]; + split->types[block_idx] = id; + split->lengths[block_idx] = cur_length; + max_type = BROTLI_MAX(uint8_t, max_type, id); + cur_length = 0; + ++block_idx; + } + } + split->num_blocks = block_idx; + split->num_types = (size_t)max_type + 1; + } + BROTLI_FREE(m, new_index); + BROTLI_FREE(m, u32); + BROTLI_FREE(m, histogram_symbols); +} + +/* Create BlockSplit (partitioning) given the limits, estimates and "effort" + * parameters. + * + * NB: max_histograms is often less than number of histograms allowed by format; + * this is done intentionally, to save some "space" for context-aware + * clustering (here entropy is estimated for context-free symbols). */ +static void FN(SplitByteVector)(MemoryManager* m, + const DataType* data, const size_t length, + const size_t symbols_per_histogram, + const size_t max_histograms, + const size_t sampling_stride_length, + const double block_switch_cost, + const BrotliEncoderParams* params, + BlockSplit* split) { + const size_t data_size = FN(HistogramDataSize)(); + HistogramType* histograms; + HistogramType* tmp; + /* Calculate number of histograms; initial estimate is one histogram per + * specified amount of symbols; however, this value is capped. */ + size_t num_histograms = length / symbols_per_histogram + 1; + if (num_histograms > max_histograms) { + num_histograms = max_histograms; + } + + /* Corner case: no input. */ + if (length == 0) { + split->num_types = 1; + return; + } + + if (length < kMinLengthForBlockSplitting) { + BROTLI_ENSURE_CAPACITY(m, uint8_t, + split->types, split->types_alloc_size, split->num_blocks + 1); + BROTLI_ENSURE_CAPACITY(m, uint32_t, + split->lengths, split->lengths_alloc_size, split->num_blocks + 1); + if (BROTLI_IS_OOM(m)) return; + split->num_types = 1; + split->types[split->num_blocks] = 0; + split->lengths[split->num_blocks] = (uint32_t)length; + split->num_blocks++; + return; + } + histograms = BROTLI_ALLOC(m, HistogramType, num_histograms + 1); + tmp = histograms + num_histograms; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(histograms)) return; + /* Find good entropy codes. */ + FN(InitialEntropyCodes)(data, length, + sampling_stride_length, + num_histograms, histograms); + FN(RefineEntropyCodes)(data, length, + sampling_stride_length, + num_histograms, histograms, tmp); + { + /* Find a good path through literals with the good entropy codes. */ + uint8_t* block_ids = BROTLI_ALLOC(m, uint8_t, length); + size_t num_blocks = 0; + const size_t bitmaplen = (num_histograms + 7) >> 3; + double* insert_cost = BROTLI_ALLOC(m, double, data_size * num_histograms); + double* cost = BROTLI_ALLOC(m, double, num_histograms); + uint8_t* switch_signal = BROTLI_ALLOC(m, uint8_t, length * bitmaplen); + uint16_t* new_id = BROTLI_ALLOC(m, uint16_t, num_histograms); + const size_t iters = params->quality < HQ_ZOPFLIFICATION_QUALITY ? 3 : 10; + size_t i; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(block_ids) || + BROTLI_IS_NULL(insert_cost) || BROTLI_IS_NULL(cost) || + BROTLI_IS_NULL(switch_signal) || BROTLI_IS_NULL(new_id)) { + return; + } + for (i = 0; i < iters; ++i) { + num_blocks = FN(FindBlocks)(data, length, + block_switch_cost, + num_histograms, histograms, + insert_cost, cost, switch_signal, + block_ids); + num_histograms = FN(RemapBlockIds)(block_ids, length, + new_id, num_histograms); + FN(BuildBlockHistograms)(data, length, block_ids, + num_histograms, histograms); + } + BROTLI_FREE(m, insert_cost); + BROTLI_FREE(m, cost); + BROTLI_FREE(m, switch_signal); + BROTLI_FREE(m, new_id); + BROTLI_FREE(m, histograms); + FN(ClusterBlocks)(m, data, length, num_blocks, block_ids, split); + if (BROTLI_IS_OOM(m)) return; + BROTLI_FREE(m, block_ids); + } +} + +#undef HistogramType diff --git a/packages/runtime/vendor/brotli/c/enc/brotli_bit_stream.c b/packages/runtime/vendor/brotli/c/enc/brotli_bit_stream.c new file mode 100644 index 000000000..1e9e946fe --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/brotli_bit_stream.c @@ -0,0 +1,1337 @@ +/* Copyright 2014 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Brotli bit stream functions to support the low level format. There are no + compression algorithms here, just the right ordering of bits to match the + specs. */ + +#include "brotli_bit_stream.h" + +#include "../common/constants.h" +#include "../common/context.h" +#include "../common/platform.h" +#include "entropy_encode.h" +#include "entropy_encode_static.h" +#include "fast_log.h" +#include "histogram.h" +#include "memory.h" +#include "write_bits.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define MAX_HUFFMAN_TREE_SIZE (2 * BROTLI_NUM_COMMAND_SYMBOLS + 1) +/* The maximum size of Huffman dictionary for distances assuming that + NPOSTFIX = 0 and NDIRECT = 0. */ +#define MAX_SIMPLE_DISTANCE_ALPHABET_SIZE \ + BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_LARGE_MAX_DISTANCE_BITS) +/* MAX_SIMPLE_DISTANCE_ALPHABET_SIZE == 140 */ + +static BROTLI_INLINE uint32_t BlockLengthPrefixCode(uint32_t len) { + uint32_t code = (len >= 177) ? (len >= 753 ? 20 : 14) : (len >= 41 ? 7 : 0); + while (code < (BROTLI_NUM_BLOCK_LEN_SYMBOLS - 1) && + len >= _kBrotliPrefixCodeRanges[code + 1].offset) ++code; + return code; +} + +static BROTLI_INLINE void GetBlockLengthPrefixCode(uint32_t len, size_t* code, + uint32_t* n_extra, uint32_t* extra) { + *code = BlockLengthPrefixCode(len); + *n_extra = _kBrotliPrefixCodeRanges[*code].nbits; + *extra = len - _kBrotliPrefixCodeRanges[*code].offset; +} + +typedef struct BlockTypeCodeCalculator { + size_t last_type; + size_t second_last_type; +} BlockTypeCodeCalculator; + +static void InitBlockTypeCodeCalculator(BlockTypeCodeCalculator* self) { + self->last_type = 1; + self->second_last_type = 0; +} + +static BROTLI_INLINE size_t NextBlockTypeCode( + BlockTypeCodeCalculator* calculator, uint8_t type) { + size_t type_code = (type == calculator->last_type + 1) ? 1u : + (type == calculator->second_last_type) ? 0u : type + 2u; + calculator->second_last_type = calculator->last_type; + calculator->last_type = type; + return type_code; +} + +/* |nibblesbits| represents the 2 bits to encode MNIBBLES (0-3) + REQUIRES: length > 0 + REQUIRES: length <= (1 << 24) */ +static void BrotliEncodeMlen(size_t length, uint64_t* bits, + size_t* numbits, uint64_t* nibblesbits) { + size_t lg = (length == 1) ? 1 : Log2FloorNonZero((uint32_t)(length - 1)) + 1; + size_t mnibbles = (lg < 16 ? 16 : (lg + 3)) / 4; + BROTLI_DCHECK(length > 0); + BROTLI_DCHECK(length <= (1 << 24)); + BROTLI_DCHECK(lg <= 24); + *nibblesbits = mnibbles - 4; + *numbits = mnibbles * 4; + *bits = length - 1; +} + +static BROTLI_INLINE void StoreCommandExtra( + const Command* cmd, size_t* storage_ix, uint8_t* storage) { + uint32_t copylen_code = CommandCopyLenCode(cmd); + uint16_t inscode = GetInsertLengthCode(cmd->insert_len_); + uint16_t copycode = GetCopyLengthCode(copylen_code); + uint32_t insnumextra = GetInsertExtra(inscode); + uint64_t insextraval = cmd->insert_len_ - GetInsertBase(inscode); + uint64_t copyextraval = copylen_code - GetCopyBase(copycode); + uint64_t bits = (copyextraval << insnumextra) | insextraval; + BrotliWriteBits( + insnumextra + GetCopyExtra(copycode), bits, storage_ix, storage); +} + +/* Data structure that stores almost everything that is needed to encode each + block switch command. */ +typedef struct BlockSplitCode { + BlockTypeCodeCalculator type_code_calculator; + uint8_t type_depths[BROTLI_MAX_BLOCK_TYPE_SYMBOLS]; + uint16_t type_bits[BROTLI_MAX_BLOCK_TYPE_SYMBOLS]; + uint8_t length_depths[BROTLI_NUM_BLOCK_LEN_SYMBOLS]; + uint16_t length_bits[BROTLI_NUM_BLOCK_LEN_SYMBOLS]; +} BlockSplitCode; + +/* Stores a number between 0 and 255. */ +static void StoreVarLenUint8(size_t n, size_t* storage_ix, uint8_t* storage) { + if (n == 0) { + BrotliWriteBits(1, 0, storage_ix, storage); + } else { + size_t nbits = Log2FloorNonZero(n); + BrotliWriteBits(1, 1, storage_ix, storage); + BrotliWriteBits(3, nbits, storage_ix, storage); + BrotliWriteBits(nbits, n - ((size_t)1 << nbits), storage_ix, storage); + } +} + +/* Stores the compressed meta-block header. + REQUIRES: length > 0 + REQUIRES: length <= (1 << 24) */ +static void StoreCompressedMetaBlockHeader(BROTLI_BOOL is_final_block, + size_t length, + size_t* storage_ix, + uint8_t* storage) { + uint64_t lenbits; + size_t nlenbits; + uint64_t nibblesbits; + + /* Write ISLAST bit. */ + BrotliWriteBits(1, (uint64_t)is_final_block, storage_ix, storage); + /* Write ISEMPTY bit. */ + if (is_final_block) { + BrotliWriteBits(1, 0, storage_ix, storage); + } + + BrotliEncodeMlen(length, &lenbits, &nlenbits, &nibblesbits); + BrotliWriteBits(2, nibblesbits, storage_ix, storage); + BrotliWriteBits(nlenbits, lenbits, storage_ix, storage); + + if (!is_final_block) { + /* Write ISUNCOMPRESSED bit. */ + BrotliWriteBits(1, 0, storage_ix, storage); + } +} + +/* Stores the uncompressed meta-block header. + REQUIRES: length > 0 + REQUIRES: length <= (1 << 24) */ +static void BrotliStoreUncompressedMetaBlockHeader(size_t length, + size_t* storage_ix, + uint8_t* storage) { + uint64_t lenbits; + size_t nlenbits; + uint64_t nibblesbits; + + /* Write ISLAST bit. + Uncompressed block cannot be the last one, so set to 0. */ + BrotliWriteBits(1, 0, storage_ix, storage); + BrotliEncodeMlen(length, &lenbits, &nlenbits, &nibblesbits); + BrotliWriteBits(2, nibblesbits, storage_ix, storage); + BrotliWriteBits(nlenbits, lenbits, storage_ix, storage); + /* Write ISUNCOMPRESSED bit. */ + BrotliWriteBits(1, 1, storage_ix, storage); +} + +static void BrotliStoreHuffmanTreeOfHuffmanTreeToBitMask( + const int num_codes, const uint8_t* code_length_bitdepth, + size_t* storage_ix, uint8_t* storage) { + static const BROTLI_MODEL("small") + uint8_t kStorageOrder[BROTLI_CODE_LENGTH_CODES] = { + 1, 2, 3, 4, 0, 5, 17, 6, 16, 7, 8, 9, 10, 11, 12, 13, 14, 15 + }; + /* The bit lengths of the Huffman code over the code length alphabet + are compressed with the following static Huffman code: + Symbol Code + ------ ---- + 0 00 + 1 1110 + 2 110 + 3 01 + 4 10 + 5 1111 */ + static const BROTLI_MODEL("small") + uint8_t kHuffmanBitLengthHuffmanCodeSymbols[6] = { + 0, 7, 3, 2, 1, 15 + }; + static const BROTLI_MODEL("small") + uint8_t kHuffmanBitLengthHuffmanCodeBitLengths[6] = { + 2, 4, 3, 2, 2, 4 + }; + + size_t skip_some = 0; /* skips none. */ + + /* Throw away trailing zeros: */ + size_t codes_to_store = BROTLI_CODE_LENGTH_CODES; + if (num_codes > 1) { + for (; codes_to_store > 0; --codes_to_store) { + if (code_length_bitdepth[kStorageOrder[codes_to_store - 1]] != 0) { + break; + } + } + } + if (code_length_bitdepth[kStorageOrder[0]] == 0 && + code_length_bitdepth[kStorageOrder[1]] == 0) { + skip_some = 2; /* skips two. */ + if (code_length_bitdepth[kStorageOrder[2]] == 0) { + skip_some = 3; /* skips three. */ + } + } + BrotliWriteBits(2, skip_some, storage_ix, storage); + { + size_t i; + for (i = skip_some; i < codes_to_store; ++i) { + size_t l = code_length_bitdepth[kStorageOrder[i]]; + BrotliWriteBits(kHuffmanBitLengthHuffmanCodeBitLengths[l], + kHuffmanBitLengthHuffmanCodeSymbols[l], storage_ix, storage); + } + } +} + +static void BrotliStoreHuffmanTreeToBitMask( + const size_t huffman_tree_size, const uint8_t* huffman_tree, + const uint8_t* huffman_tree_extra_bits, const uint8_t* code_length_bitdepth, + const uint16_t* code_length_bitdepth_symbols, + size_t* BROTLI_RESTRICT storage_ix, uint8_t* BROTLI_RESTRICT storage) { + size_t i; + for (i = 0; i < huffman_tree_size; ++i) { + size_t ix = huffman_tree[i]; + BrotliWriteBits(code_length_bitdepth[ix], code_length_bitdepth_symbols[ix], + storage_ix, storage); + /* Extra bits */ + switch (ix) { + case BROTLI_REPEAT_PREVIOUS_CODE_LENGTH: + BrotliWriteBits(2, huffman_tree_extra_bits[i], storage_ix, storage); + break; + case BROTLI_REPEAT_ZERO_CODE_LENGTH: + BrotliWriteBits(3, huffman_tree_extra_bits[i], storage_ix, storage); + break; + } + } +} + +static void StoreSimpleHuffmanTree(const uint8_t* depths, + size_t symbols[4], + size_t num_symbols, + size_t max_bits, + size_t* storage_ix, uint8_t* storage) { + /* value of 1 indicates a simple Huffman code */ + BrotliWriteBits(2, 1, storage_ix, storage); + BrotliWriteBits(2, num_symbols - 1, storage_ix, storage); /* NSYM - 1 */ + + { + /* Sort */ + size_t i; + for (i = 0; i < num_symbols; i++) { + size_t j; + for (j = i + 1; j < num_symbols; j++) { + if (depths[symbols[j]] < depths[symbols[i]]) { + BROTLI_SWAP(size_t, symbols, j, i); + } + } + } + } + + if (num_symbols == 2) { + BrotliWriteBits(max_bits, symbols[0], storage_ix, storage); + BrotliWriteBits(max_bits, symbols[1], storage_ix, storage); + } else if (num_symbols == 3) { + BrotliWriteBits(max_bits, symbols[0], storage_ix, storage); + BrotliWriteBits(max_bits, symbols[1], storage_ix, storage); + BrotliWriteBits(max_bits, symbols[2], storage_ix, storage); + } else { + BrotliWriteBits(max_bits, symbols[0], storage_ix, storage); + BrotliWriteBits(max_bits, symbols[1], storage_ix, storage); + BrotliWriteBits(max_bits, symbols[2], storage_ix, storage); + BrotliWriteBits(max_bits, symbols[3], storage_ix, storage); + /* tree-select */ + BrotliWriteBits(1, depths[symbols[0]] == 1 ? 1 : 0, storage_ix, storage); + } +} + +/* num = alphabet size + depths = symbol depths */ +void BrotliStoreHuffmanTree(const uint8_t* depths, size_t num, + HuffmanTree* tree, + size_t* storage_ix, uint8_t* storage) { + /* Write the Huffman tree into the brotli-representation. + The command alphabet is the largest, so this allocation will fit all + alphabets. */ + /* TODO(eustas): fix me */ + uint8_t huffman_tree[BROTLI_NUM_COMMAND_SYMBOLS]; + uint8_t huffman_tree_extra_bits[BROTLI_NUM_COMMAND_SYMBOLS]; + size_t huffman_tree_size = 0; + uint8_t code_length_bitdepth[BROTLI_CODE_LENGTH_CODES] = { 0 }; + uint16_t code_length_bitdepth_symbols[BROTLI_CODE_LENGTH_CODES]; + uint32_t huffman_tree_histogram[BROTLI_CODE_LENGTH_CODES] = { 0 }; + size_t i; + int num_codes = 0; + size_t code = 0; + + BROTLI_DCHECK(num <= BROTLI_NUM_COMMAND_SYMBOLS); + + BrotliWriteHuffmanTree(depths, num, &huffman_tree_size, huffman_tree, + huffman_tree_extra_bits); + + /* Calculate the statistics of the Huffman tree in brotli-representation. */ + for (i = 0; i < huffman_tree_size; ++i) { + ++huffman_tree_histogram[huffman_tree[i]]; + } + + for (i = 0; i < BROTLI_CODE_LENGTH_CODES; ++i) { + if (huffman_tree_histogram[i]) { + if (num_codes == 0) { + code = i; + num_codes = 1; + } else if (num_codes == 1) { + num_codes = 2; + break; + } + } + } + + /* Calculate another Huffman tree to use for compressing both the + earlier Huffman tree with. */ + BrotliCreateHuffmanTree(huffman_tree_histogram, BROTLI_CODE_LENGTH_CODES, + 5, tree, code_length_bitdepth); + BrotliConvertBitDepthsToSymbols(code_length_bitdepth, + BROTLI_CODE_LENGTH_CODES, + code_length_bitdepth_symbols); + + /* Now, we have all the data, let's start storing it */ + BrotliStoreHuffmanTreeOfHuffmanTreeToBitMask(num_codes, code_length_bitdepth, + storage_ix, storage); + + if (num_codes == 1) { + code_length_bitdepth[code] = 0; + } + + /* Store the real Huffman tree now. */ + BrotliStoreHuffmanTreeToBitMask(huffman_tree_size, + huffman_tree, + huffman_tree_extra_bits, + code_length_bitdepth, + code_length_bitdepth_symbols, + storage_ix, storage); +} + +/* Builds a Huffman tree from histogram[0:length] into depth[0:length] and + bits[0:length] and stores the encoded tree to the bit stream. */ +static void BuildAndStoreHuffmanTree(const uint32_t* histogram, + const size_t histogram_length, + const size_t alphabet_size, + HuffmanTree* tree, + uint8_t* depth, + uint16_t* bits, + size_t* storage_ix, + uint8_t* storage) { + size_t count = 0; + size_t s4[4] = { 0 }; + size_t i; + size_t max_bits = 0; + for (i = 0; i < histogram_length; i++) { + if (histogram[i]) { + if (count < 4) { + s4[count] = i; + } else if (count > 4) { + break; + } + count++; + } + } + + { + size_t max_bits_counter = alphabet_size - 1; + while (max_bits_counter) { + max_bits_counter >>= 1; + ++max_bits; + } + } + + if (count <= 1) { + BrotliWriteBits(4, 1, storage_ix, storage); + BrotliWriteBits(max_bits, s4[0], storage_ix, storage); + depth[s4[0]] = 0; + bits[s4[0]] = 0; + return; + } + + memset(depth, 0, histogram_length * sizeof(depth[0])); + BrotliCreateHuffmanTree(histogram, histogram_length, 15, tree, depth); + BrotliConvertBitDepthsToSymbols(depth, histogram_length, bits); + + if (count <= 4) { + StoreSimpleHuffmanTree(depth, s4, count, max_bits, storage_ix, storage); + } else { + BrotliStoreHuffmanTree(depth, histogram_length, tree, storage_ix, storage); + } +} + +static BROTLI_INLINE BROTLI_BOOL SortHuffmanTree( + const HuffmanTree* v0, const HuffmanTree* v1) { + return TO_BROTLI_BOOL(v0->total_count_ < v1->total_count_); +} + +void BrotliBuildAndStoreHuffmanTreeFast(HuffmanTree* tree, + const uint32_t* histogram, + const size_t histogram_total, + const size_t max_bits, + uint8_t* depth, uint16_t* bits, + size_t* storage_ix, + uint8_t* storage) { + size_t count = 0; + size_t symbols[4] = { 0 }; + size_t length = 0; + size_t total = histogram_total; + while (total != 0) { + if (histogram[length]) { + if (count < 4) { + symbols[count] = length; + } + ++count; + total -= histogram[length]; + } + ++length; + } + + if (count <= 1) { + BrotliWriteBits(4, 1, storage_ix, storage); + BrotliWriteBits(max_bits, symbols[0], storage_ix, storage); + depth[symbols[0]] = 0; + bits[symbols[0]] = 0; + return; + } + + memset(depth, 0, length * sizeof(depth[0])); + { + uint32_t count_limit; + for (count_limit = 1; ; count_limit *= 2) { + HuffmanTree* node = tree; + size_t l; + for (l = length; l != 0;) { + --l; + if (histogram[l]) { + if (BROTLI_PREDICT_TRUE(histogram[l] >= count_limit)) { + InitHuffmanTree(node, histogram[l], -1, (int16_t)l); + } else { + InitHuffmanTree(node, count_limit, -1, (int16_t)l); + } + ++node; + } + } + { + const int n = (int)(node - tree); + HuffmanTree sentinel; + int i = 0; /* Points to the next leaf node. */ + int j = n + 1; /* Points to the next non-leaf node. */ + int k; + + SortHuffmanTreeItems(tree, (size_t)n, SortHuffmanTree); + /* The nodes are: + [0, n): the sorted leaf nodes that we start with. + [n]: we add a sentinel here. + [n + 1, 2n): new parent nodes are added here, starting from + (n+1). These are naturally in ascending order. + [2n]: we add a sentinel at the end as well. + There will be (2n+1) elements at the end. */ + InitHuffmanTree(&sentinel, BROTLI_UINT32_MAX, -1, -1); + *node++ = sentinel; + *node++ = sentinel; + + for (k = n - 1; k > 0; --k) { + int left, right; + if (tree[i].total_count_ <= tree[j].total_count_) { + left = i; + ++i; + } else { + left = j; + ++j; + } + if (tree[i].total_count_ <= tree[j].total_count_) { + right = i; + ++i; + } else { + right = j; + ++j; + } + /* The sentinel node becomes the parent node. */ + node[-1].total_count_ = + tree[left].total_count_ + tree[right].total_count_; + node[-1].index_left_ = (int16_t)left; + node[-1].index_right_or_value_ = (int16_t)right; + /* Add back the last sentinel node. */ + *node++ = sentinel; + } + if (BrotliSetDepth(2 * n - 1, tree, depth, 14)) { + /* We need to pack the Huffman tree in 14 bits. If this was not + successful, add fake entities to the lowest values and retry. */ + break; + } + } + } + } + BrotliConvertBitDepthsToSymbols(depth, length, bits); + if (count <= 4) { + size_t i; + /* value of 1 indicates a simple Huffman code */ + BrotliWriteBits(2, 1, storage_ix, storage); + BrotliWriteBits(2, count - 1, storage_ix, storage); /* NSYM - 1 */ + + /* Sort */ + for (i = 0; i < count; i++) { + size_t j; + for (j = i + 1; j < count; j++) { + if (depth[symbols[j]] < depth[symbols[i]]) { + BROTLI_SWAP(size_t, symbols, j, i); + } + } + } + + if (count == 2) { + BrotliWriteBits(max_bits, symbols[0], storage_ix, storage); + BrotliWriteBits(max_bits, symbols[1], storage_ix, storage); + } else if (count == 3) { + BrotliWriteBits(max_bits, symbols[0], storage_ix, storage); + BrotliWriteBits(max_bits, symbols[1], storage_ix, storage); + BrotliWriteBits(max_bits, symbols[2], storage_ix, storage); + } else { + BrotliWriteBits(max_bits, symbols[0], storage_ix, storage); + BrotliWriteBits(max_bits, symbols[1], storage_ix, storage); + BrotliWriteBits(max_bits, symbols[2], storage_ix, storage); + BrotliWriteBits(max_bits, symbols[3], storage_ix, storage); + /* tree-select */ + BrotliWriteBits(1, depth[symbols[0]] == 1 ? 1 : 0, storage_ix, storage); + } + } else { + uint8_t previous_value = 8; + size_t i; + /* Complex Huffman Tree */ + StoreStaticCodeLengthCode(storage_ix, storage); + + /* Actual RLE coding. */ + for (i = 0; i < length;) { + const uint8_t value = depth[i]; + size_t reps = 1; + size_t k; + for (k = i + 1; k < length && depth[k] == value; ++k) { + ++reps; + } + i += reps; + if (value == 0) { + BrotliWriteBits(kZeroRepsDepth[reps], kZeroRepsBits[reps], + storage_ix, storage); + } else { + if (previous_value != value) { + BrotliWriteBits(kCodeLengthDepth[value], kCodeLengthBits[value], + storage_ix, storage); + --reps; + } + if (reps < 3) { + while (reps != 0) { + reps--; + BrotliWriteBits(kCodeLengthDepth[value], kCodeLengthBits[value], + storage_ix, storage); + } + } else { + reps -= 3; + BrotliWriteBits(kNonZeroRepsDepth[reps], kNonZeroRepsBits[reps], + storage_ix, storage); + } + previous_value = value; + } + } + } +} + +static size_t IndexOf(const uint8_t* v, size_t v_size, uint8_t value) { + size_t i = 0; + for (; i < v_size; ++i) { + if (v[i] == value) return i; + } + return i; +} + +static void MoveToFront(uint8_t* v, size_t index) { + uint8_t value = v[index]; + size_t i; + for (i = index; i != 0; --i) { + v[i] = v[i - 1]; + } + v[0] = value; +} + +static void MoveToFrontTransform(const uint32_t* BROTLI_RESTRICT v_in, + const size_t v_size, + uint32_t* v_out) { + size_t i; + uint8_t mtf[256]; + uint32_t max_value; + if (v_size == 0) { + return; + } + max_value = v_in[0]; + for (i = 1; i < v_size; ++i) { + if (v_in[i] > max_value) max_value = v_in[i]; + } + BROTLI_DCHECK(max_value < 256u); + for (i = 0; i <= max_value; ++i) { + mtf[i] = (uint8_t)i; + } + { + size_t mtf_size = max_value + 1; + for (i = 0; i < v_size; ++i) { + size_t index = IndexOf(mtf, mtf_size, (uint8_t)v_in[i]); + BROTLI_DCHECK(index < mtf_size); + v_out[i] = (uint32_t)index; + MoveToFront(mtf, index); + } + } +} + +/* Finds runs of zeros in v[0..in_size) and replaces them with a prefix code of + the run length plus extra bits (lower 9 bits is the prefix code and the rest + are the extra bits). Non-zero values in v[] are shifted by + *max_length_prefix. Will not create prefix codes bigger than the initial + value of *max_run_length_prefix. The prefix code of run length L is simply + Log2Floor(L) and the number of extra bits is the same as the prefix code. */ +static void RunLengthCodeZeros(const size_t in_size, + uint32_t* BROTLI_RESTRICT v, size_t* BROTLI_RESTRICT out_size, + uint32_t* BROTLI_RESTRICT max_run_length_prefix) { + uint32_t max_reps = 0; + size_t i; + uint32_t max_prefix; + for (i = 0; i < in_size;) { + uint32_t reps = 0; + for (; i < in_size && v[i] != 0; ++i) ; + for (; i < in_size && v[i] == 0; ++i) { + ++reps; + } + max_reps = BROTLI_MAX(uint32_t, reps, max_reps); + } + max_prefix = max_reps > 0 ? Log2FloorNonZero(max_reps) : 0; + max_prefix = BROTLI_MIN(uint32_t, max_prefix, *max_run_length_prefix); + *max_run_length_prefix = max_prefix; + *out_size = 0; + for (i = 0; i < in_size;) { + BROTLI_DCHECK(*out_size <= i); + if (v[i] != 0) { + v[*out_size] = v[i] + *max_run_length_prefix; + ++i; + ++(*out_size); + } else { + uint32_t reps = 1; + size_t k; + for (k = i + 1; k < in_size && v[k] == 0; ++k) { + ++reps; + } + i += reps; + while (reps != 0) { + if (reps < (2u << max_prefix)) { + uint32_t run_length_prefix = Log2FloorNonZero(reps); + const uint32_t extra_bits = reps - (1u << run_length_prefix); + v[*out_size] = run_length_prefix + (extra_bits << 9); + ++(*out_size); + break; + } else { + const uint32_t extra_bits = (1u << max_prefix) - 1u; + v[*out_size] = max_prefix + (extra_bits << 9); + reps -= (2u << max_prefix) - 1u; + ++(*out_size); + } + } + } + } +} + +#define SYMBOL_BITS 9 + +typedef struct EncodeContextMapArena { + uint32_t histogram[BROTLI_MAX_CONTEXT_MAP_SYMBOLS]; + uint8_t depths[BROTLI_MAX_CONTEXT_MAP_SYMBOLS]; + uint16_t bits[BROTLI_MAX_CONTEXT_MAP_SYMBOLS]; +} EncodeContextMapArena; + +static void EncodeContextMap(MemoryManager* m, + EncodeContextMapArena* arena, + const uint32_t* context_map, + size_t context_map_size, + size_t num_clusters, + HuffmanTree* tree, + size_t* storage_ix, uint8_t* storage) { + size_t i; + uint32_t* rle_symbols; + uint32_t max_run_length_prefix = 6; + size_t num_rle_symbols = 0; + uint32_t* BROTLI_RESTRICT const histogram = arena->histogram; + static const uint32_t kSymbolMask = (1u << SYMBOL_BITS) - 1u; + uint8_t* BROTLI_RESTRICT const depths = arena->depths; + uint16_t* BROTLI_RESTRICT const bits = arena->bits; + + StoreVarLenUint8(num_clusters - 1, storage_ix, storage); + + if (num_clusters == 1) { + return; + } + + rle_symbols = BROTLI_ALLOC(m, uint32_t, context_map_size); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(rle_symbols)) return; + MoveToFrontTransform(context_map, context_map_size, rle_symbols); + RunLengthCodeZeros(context_map_size, rle_symbols, + &num_rle_symbols, &max_run_length_prefix); + memset(histogram, 0, sizeof(arena->histogram)); + for (i = 0; i < num_rle_symbols; ++i) { + ++histogram[rle_symbols[i] & kSymbolMask]; + } + { + BROTLI_BOOL use_rle = TO_BROTLI_BOOL(max_run_length_prefix > 0); + BrotliWriteBits(1, (uint64_t)use_rle, storage_ix, storage); + if (use_rle) { + BrotliWriteBits(4, max_run_length_prefix - 1, storage_ix, storage); + } + } + BuildAndStoreHuffmanTree(histogram, num_clusters + max_run_length_prefix, + num_clusters + max_run_length_prefix, + tree, depths, bits, storage_ix, storage); + for (i = 0; i < num_rle_symbols; ++i) { + const uint32_t rle_symbol = rle_symbols[i] & kSymbolMask; + const uint32_t extra_bits_val = rle_symbols[i] >> SYMBOL_BITS; + BrotliWriteBits(depths[rle_symbol], bits[rle_symbol], storage_ix, storage); + if (rle_symbol > 0 && rle_symbol <= max_run_length_prefix) { + BrotliWriteBits(rle_symbol, extra_bits_val, storage_ix, storage); + } + } + BrotliWriteBits(1, 1, storage_ix, storage); /* use move-to-front */ + BROTLI_FREE(m, rle_symbols); +} + +/* Stores the block switch command with index block_ix to the bit stream. */ +static BROTLI_INLINE void StoreBlockSwitch(BlockSplitCode* code, + const uint32_t block_len, + const uint8_t block_type, + BROTLI_BOOL is_first_block, + size_t* storage_ix, + uint8_t* storage) { + size_t typecode = NextBlockTypeCode(&code->type_code_calculator, block_type); + size_t lencode; + uint32_t len_nextra; + uint32_t len_extra; + if (!is_first_block) { + BrotliWriteBits(code->type_depths[typecode], code->type_bits[typecode], + storage_ix, storage); + } + GetBlockLengthPrefixCode(block_len, &lencode, &len_nextra, &len_extra); + + BrotliWriteBits(code->length_depths[lencode], code->length_bits[lencode], + storage_ix, storage); + BrotliWriteBits(len_nextra, len_extra, storage_ix, storage); +} + +/* Builds a BlockSplitCode data structure from the block split given by the + vector of block types and block lengths and stores it to the bit stream. */ +static void BuildAndStoreBlockSplitCode(const uint8_t* types, + const uint32_t* lengths, + const size_t num_blocks, + const size_t num_types, + HuffmanTree* tree, + BlockSplitCode* code, + size_t* storage_ix, + uint8_t* storage) { + uint32_t type_histo[BROTLI_MAX_BLOCK_TYPE_SYMBOLS]; + uint32_t length_histo[BROTLI_NUM_BLOCK_LEN_SYMBOLS]; + size_t i; + BlockTypeCodeCalculator type_code_calculator; + memset(type_histo, 0, (num_types + 2) * sizeof(type_histo[0])); + memset(length_histo, 0, sizeof(length_histo)); + InitBlockTypeCodeCalculator(&type_code_calculator); + for (i = 0; i < num_blocks; ++i) { + size_t type_code = NextBlockTypeCode(&type_code_calculator, types[i]); + if (i != 0) ++type_histo[type_code]; + ++length_histo[BlockLengthPrefixCode(lengths[i])]; + } + StoreVarLenUint8(num_types - 1, storage_ix, storage); + if (num_types > 1) { /* TODO(eustas): else? could StoreBlockSwitch occur? */ + BuildAndStoreHuffmanTree(&type_histo[0], num_types + 2, num_types + 2, tree, + &code->type_depths[0], &code->type_bits[0], + storage_ix, storage); + BuildAndStoreHuffmanTree(&length_histo[0], BROTLI_NUM_BLOCK_LEN_SYMBOLS, + BROTLI_NUM_BLOCK_LEN_SYMBOLS, + tree, &code->length_depths[0], + &code->length_bits[0], storage_ix, storage); + StoreBlockSwitch(code, lengths[0], types[0], 1, storage_ix, storage); + } +} + +/* Stores a context map where the histogram type is always the block type. */ +static void StoreTrivialContextMap(EncodeContextMapArena* arena, + size_t num_types, + size_t context_bits, + HuffmanTree* tree, + size_t* storage_ix, + uint8_t* storage) { + StoreVarLenUint8(num_types - 1, storage_ix, storage); + if (num_types > 1) { + size_t repeat_code = context_bits - 1u; + size_t repeat_bits = (1u << repeat_code) - 1u; + size_t alphabet_size = num_types + repeat_code; + uint32_t* BROTLI_RESTRICT const histogram = arena->histogram; + uint8_t* BROTLI_RESTRICT const depths = arena->depths; + uint16_t* BROTLI_RESTRICT const bits = arena->bits; + size_t i; + memset(histogram, 0, alphabet_size * sizeof(histogram[0])); + /* Write RLEMAX. */ + BrotliWriteBits(1, 1, storage_ix, storage); + BrotliWriteBits(4, repeat_code - 1, storage_ix, storage); + histogram[repeat_code] = (uint32_t)num_types; + histogram[0] = 1; + for (i = context_bits; i < alphabet_size; ++i) { + histogram[i] = 1; + } + BuildAndStoreHuffmanTree(histogram, alphabet_size, alphabet_size, + tree, depths, bits, storage_ix, storage); + for (i = 0; i < num_types; ++i) { + size_t code = (i == 0 ? 0 : i + context_bits - 1); + BrotliWriteBits(depths[code], bits[code], storage_ix, storage); + BrotliWriteBits( + depths[repeat_code], bits[repeat_code], storage_ix, storage); + BrotliWriteBits(repeat_code, repeat_bits, storage_ix, storage); + } + /* Write IMTF (inverse-move-to-front) bit. */ + BrotliWriteBits(1, 1, storage_ix, storage); + } +} + +/* Manages the encoding of one block category (literal, command or distance). */ +typedef struct BlockEncoder { + size_t histogram_length_; + size_t num_block_types_; + const uint8_t* block_types_; /* Not owned. */ + const uint32_t* block_lengths_; /* Not owned. */ + size_t num_blocks_; + BlockSplitCode block_split_code_; + size_t block_ix_; + size_t block_len_; + size_t entropy_ix_; + uint8_t* depths_; + uint16_t* bits_; +} BlockEncoder; + +static void InitBlockEncoder(BlockEncoder* self, size_t histogram_length, + size_t num_block_types, const uint8_t* block_types, + const uint32_t* block_lengths, const size_t num_blocks) { + self->histogram_length_ = histogram_length; + self->num_block_types_ = num_block_types; + self->block_types_ = block_types; + self->block_lengths_ = block_lengths; + self->num_blocks_ = num_blocks; + InitBlockTypeCodeCalculator(&self->block_split_code_.type_code_calculator); + self->block_ix_ = 0; + self->block_len_ = num_blocks == 0 ? 0 : block_lengths[0]; + self->entropy_ix_ = 0; + self->depths_ = 0; + self->bits_ = 0; +} + +static void CleanupBlockEncoder(MemoryManager* m, BlockEncoder* self) { + BROTLI_FREE(m, self->depths_); + BROTLI_FREE(m, self->bits_); +} + +/* Creates entropy codes of block lengths and block types and stores them + to the bit stream. */ +static void BuildAndStoreBlockSwitchEntropyCodes(BlockEncoder* self, + HuffmanTree* tree, size_t* storage_ix, uint8_t* storage) { + BuildAndStoreBlockSplitCode(self->block_types_, self->block_lengths_, + self->num_blocks_, self->num_block_types_, tree, &self->block_split_code_, + storage_ix, storage); +} + +/* Stores the next symbol with the entropy code of the current block type. + Updates the block type and block length at block boundaries. */ +static void StoreSymbol(BlockEncoder* self, size_t symbol, size_t* storage_ix, + uint8_t* storage) { + if (self->block_len_ == 0) { + size_t block_ix = ++self->block_ix_; + uint32_t block_len = self->block_lengths_[block_ix]; + uint8_t block_type = self->block_types_[block_ix]; + self->block_len_ = block_len; + self->entropy_ix_ = block_type * self->histogram_length_; + StoreBlockSwitch(&self->block_split_code_, block_len, block_type, 0, + storage_ix, storage); + } + --self->block_len_; + { + size_t ix = self->entropy_ix_ + symbol; + BrotliWriteBits(self->depths_[ix], self->bits_[ix], storage_ix, storage); + } +} + +/* Stores the next symbol with the entropy code of the current block type and + context value. + Updates the block type and block length at block boundaries. */ +static void StoreSymbolWithContext(BlockEncoder* self, size_t symbol, + size_t context, const uint32_t* context_map, size_t* storage_ix, + uint8_t* storage, const size_t context_bits) { + if (self->block_len_ == 0) { + size_t block_ix = ++self->block_ix_; + uint32_t block_len = self->block_lengths_[block_ix]; + uint8_t block_type = self->block_types_[block_ix]; + self->block_len_ = block_len; + self->entropy_ix_ = (size_t)block_type << context_bits; + StoreBlockSwitch(&self->block_split_code_, block_len, block_type, 0, + storage_ix, storage); + } + --self->block_len_; + { + size_t histo_ix = context_map[self->entropy_ix_ + context]; + size_t ix = histo_ix * self->histogram_length_ + symbol; + BrotliWriteBits(self->depths_[ix], self->bits_[ix], storage_ix, storage); + } +} + +#define FN(X) X ## Literal +/* NOLINTNEXTLINE(build/include) */ +#include "block_encoder_inc.h" +#undef FN + +#define FN(X) X ## Command +/* NOLINTNEXTLINE(build/include) */ +#include "block_encoder_inc.h" +#undef FN + +#define FN(X) X ## Distance +/* NOLINTNEXTLINE(build/include) */ +#include "block_encoder_inc.h" +#undef FN + +static void JumpToByteBoundary(size_t* storage_ix, uint8_t* storage) { + *storage_ix = (*storage_ix + 7u) & ~7u; + storage[*storage_ix >> 3] = 0; +} + +typedef struct StoreMetablockArena { + BlockEncoder literal_enc; + BlockEncoder command_enc; + BlockEncoder distance_enc; + EncodeContextMapArena context_map_arena; +} StoreMetablockArena; + +void BrotliStoreMetaBlock(MemoryManager* m, + const uint8_t* input, size_t start_pos, size_t length, size_t mask, + uint8_t prev_byte, uint8_t prev_byte2, BROTLI_BOOL is_last, + const BrotliEncoderParams* params, ContextType literal_context_mode, + const Command* commands, size_t n_commands, const MetaBlockSplit* mb, + size_t* storage_ix, uint8_t* storage) { + + size_t pos = start_pos; + size_t i; + uint32_t num_distance_symbols = params->dist.alphabet_size_max; + uint32_t num_effective_distance_symbols = params->dist.alphabet_size_limit; + HuffmanTree* tree; + ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode); + StoreMetablockArena* arena = NULL; + BlockEncoder* literal_enc = NULL; + BlockEncoder* command_enc = NULL; + BlockEncoder* distance_enc = NULL; + const BrotliDistanceParams* dist = ¶ms->dist; + BROTLI_DCHECK( + num_effective_distance_symbols <= BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS); + + StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage); + + tree = BROTLI_ALLOC(m, HuffmanTree, MAX_HUFFMAN_TREE_SIZE); + arena = BROTLI_ALLOC(m, StoreMetablockArena, 1); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tree) || BROTLI_IS_NULL(arena)) return; + literal_enc = &arena->literal_enc; + command_enc = &arena->command_enc; + distance_enc = &arena->distance_enc; + InitBlockEncoder(literal_enc, BROTLI_NUM_LITERAL_SYMBOLS, + mb->literal_split.num_types, mb->literal_split.types, + mb->literal_split.lengths, mb->literal_split.num_blocks); + InitBlockEncoder(command_enc, BROTLI_NUM_COMMAND_SYMBOLS, + mb->command_split.num_types, mb->command_split.types, + mb->command_split.lengths, mb->command_split.num_blocks); + InitBlockEncoder(distance_enc, num_effective_distance_symbols, + mb->distance_split.num_types, mb->distance_split.types, + mb->distance_split.lengths, mb->distance_split.num_blocks); + + BuildAndStoreBlockSwitchEntropyCodes(literal_enc, tree, storage_ix, storage); + BuildAndStoreBlockSwitchEntropyCodes(command_enc, tree, storage_ix, storage); + BuildAndStoreBlockSwitchEntropyCodes(distance_enc, tree, storage_ix, storage); + + BrotliWriteBits(2, dist->distance_postfix_bits, storage_ix, storage); + BrotliWriteBits( + 4, dist->num_direct_distance_codes >> dist->distance_postfix_bits, + storage_ix, storage); + for (i = 0; i < mb->literal_split.num_types; ++i) { + BrotliWriteBits(2, literal_context_mode, storage_ix, storage); + } + + if (mb->literal_context_map_size == 0) { + StoreTrivialContextMap( + &arena->context_map_arena, mb->literal_histograms_size, + BROTLI_LITERAL_CONTEXT_BITS, tree, storage_ix, storage); + } else { + EncodeContextMap(m, &arena->context_map_arena, + mb->literal_context_map, mb->literal_context_map_size, + mb->literal_histograms_size, tree, storage_ix, storage); + if (BROTLI_IS_OOM(m)) return; + } + + if (mb->distance_context_map_size == 0) { + StoreTrivialContextMap( + &arena->context_map_arena, mb->distance_histograms_size, + BROTLI_DISTANCE_CONTEXT_BITS, tree, storage_ix, storage); + } else { + EncodeContextMap(m, &arena->context_map_arena, + mb->distance_context_map, mb->distance_context_map_size, + mb->distance_histograms_size, tree, storage_ix, storage); + if (BROTLI_IS_OOM(m)) return; + } + + BuildAndStoreEntropyCodesLiteral(m, literal_enc, mb->literal_histograms, + mb->literal_histograms_size, BROTLI_NUM_LITERAL_SYMBOLS, tree, + storage_ix, storage); + if (BROTLI_IS_OOM(m)) return; + BuildAndStoreEntropyCodesCommand(m, command_enc, mb->command_histograms, + mb->command_histograms_size, BROTLI_NUM_COMMAND_SYMBOLS, tree, + storage_ix, storage); + if (BROTLI_IS_OOM(m)) return; + BuildAndStoreEntropyCodesDistance(m, distance_enc, mb->distance_histograms, + mb->distance_histograms_size, num_distance_symbols, tree, + storage_ix, storage); + if (BROTLI_IS_OOM(m)) return; + BROTLI_FREE(m, tree); + + for (i = 0; i < n_commands; ++i) { + const Command cmd = commands[i]; + size_t cmd_code = cmd.cmd_prefix_; + StoreSymbol(command_enc, cmd_code, storage_ix, storage); + StoreCommandExtra(&cmd, storage_ix, storage); + if (mb->literal_context_map_size == 0) { + size_t j; + for (j = cmd.insert_len_; j != 0; --j) { + StoreSymbol(literal_enc, input[pos & mask], storage_ix, storage); + ++pos; + } + } else { + size_t j; + for (j = cmd.insert_len_; j != 0; --j) { + size_t context = + BROTLI_CONTEXT(prev_byte, prev_byte2, literal_context_lut); + uint8_t literal = input[pos & mask]; + StoreSymbolWithContext(literal_enc, literal, context, + mb->literal_context_map, storage_ix, storage, + BROTLI_LITERAL_CONTEXT_BITS); + prev_byte2 = prev_byte; + prev_byte = literal; + ++pos; + } + } + pos += CommandCopyLen(&cmd); + if (CommandCopyLen(&cmd)) { + prev_byte2 = input[(pos - 2) & mask]; + prev_byte = input[(pos - 1) & mask]; + if (cmd.cmd_prefix_ >= 128) { + size_t dist_code = cmd.dist_prefix_ & 0x3FF; + uint32_t distnumextra = cmd.dist_prefix_ >> 10; + uint64_t distextra = cmd.dist_extra_; + if (mb->distance_context_map_size == 0) { + StoreSymbol(distance_enc, dist_code, storage_ix, storage); + } else { + size_t context = CommandDistanceContext(&cmd); + StoreSymbolWithContext(distance_enc, dist_code, context, + mb->distance_context_map, storage_ix, storage, + BROTLI_DISTANCE_CONTEXT_BITS); + } + BrotliWriteBits(distnumextra, distextra, storage_ix, storage); + } + } + } + CleanupBlockEncoder(m, distance_enc); + CleanupBlockEncoder(m, command_enc); + CleanupBlockEncoder(m, literal_enc); + BROTLI_FREE(m, arena); + if (is_last) { + JumpToByteBoundary(storage_ix, storage); + } +} + +static void BuildHistograms(const uint8_t* input, + size_t start_pos, + size_t mask, + const Command* commands, + size_t n_commands, + HistogramLiteral* lit_histo, + HistogramCommand* cmd_histo, + HistogramDistance* dist_histo) { + size_t pos = start_pos; + size_t i; + for (i = 0; i < n_commands; ++i) { + const Command cmd = commands[i]; + size_t j; + HistogramAddCommand(cmd_histo, cmd.cmd_prefix_); + for (j = cmd.insert_len_; j != 0; --j) { + HistogramAddLiteral(lit_histo, input[pos & mask]); + ++pos; + } + pos += CommandCopyLen(&cmd); + if (CommandCopyLen(&cmd) && cmd.cmd_prefix_ >= 128) { + HistogramAddDistance(dist_histo, cmd.dist_prefix_ & 0x3FF); + } + } +} + +static void StoreDataWithHuffmanCodes(const uint8_t* input, + size_t start_pos, + size_t mask, + const Command* commands, + size_t n_commands, + const uint8_t* lit_depth, + const uint16_t* lit_bits, + const uint8_t* cmd_depth, + const uint16_t* cmd_bits, + const uint8_t* dist_depth, + const uint16_t* dist_bits, + size_t* storage_ix, + uint8_t* storage) { + size_t pos = start_pos; + size_t i; + for (i = 0; i < n_commands; ++i) { + const Command cmd = commands[i]; + const size_t cmd_code = cmd.cmd_prefix_; + size_t j; + BrotliWriteBits( + cmd_depth[cmd_code], cmd_bits[cmd_code], storage_ix, storage); + StoreCommandExtra(&cmd, storage_ix, storage); + for (j = cmd.insert_len_; j != 0; --j) { + const uint8_t literal = input[pos & mask]; + BrotliWriteBits( + lit_depth[literal], lit_bits[literal], storage_ix, storage); + ++pos; + } + pos += CommandCopyLen(&cmd); + if (CommandCopyLen(&cmd) && cmd.cmd_prefix_ >= 128) { + const size_t dist_code = cmd.dist_prefix_ & 0x3FF; + const uint32_t distnumextra = cmd.dist_prefix_ >> 10; + const uint32_t distextra = cmd.dist_extra_; + BrotliWriteBits(dist_depth[dist_code], dist_bits[dist_code], + storage_ix, storage); + BrotliWriteBits(distnumextra, distextra, storage_ix, storage); + } + } +} + +/* TODO(eustas): pull alloc/dealloc to caller? */ +typedef struct MetablockArena { + HistogramLiteral lit_histo; + HistogramCommand cmd_histo; + HistogramDistance dist_histo; + /* TODO(eustas): merge bits and depth? */ + uint8_t lit_depth[BROTLI_NUM_LITERAL_SYMBOLS]; + uint16_t lit_bits[BROTLI_NUM_LITERAL_SYMBOLS]; + uint8_t cmd_depth[BROTLI_NUM_COMMAND_SYMBOLS]; + uint16_t cmd_bits[BROTLI_NUM_COMMAND_SYMBOLS]; + uint8_t dist_depth[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE]; + uint16_t dist_bits[MAX_SIMPLE_DISTANCE_ALPHABET_SIZE]; + HuffmanTree tree[MAX_HUFFMAN_TREE_SIZE]; +} MetablockArena; + +void BrotliStoreMetaBlockTrivial(MemoryManager* m, + const uint8_t* input, size_t start_pos, size_t length, size_t mask, + BROTLI_BOOL is_last, const BrotliEncoderParams* params, + const Command* commands, size_t n_commands, + size_t* storage_ix, uint8_t* storage) { + MetablockArena* arena = BROTLI_ALLOC(m, MetablockArena, 1); + uint32_t num_distance_symbols = params->dist.alphabet_size_max; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(arena)) return; + + StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage); + + HistogramClearLiteral(&arena->lit_histo); + HistogramClearCommand(&arena->cmd_histo); + HistogramClearDistance(&arena->dist_histo); + + BuildHistograms(input, start_pos, mask, commands, n_commands, + &arena->lit_histo, &arena->cmd_histo, &arena->dist_histo); + + BrotliWriteBits(13, 0, storage_ix, storage); + + BuildAndStoreHuffmanTree(arena->lit_histo.data_, BROTLI_NUM_LITERAL_SYMBOLS, + BROTLI_NUM_LITERAL_SYMBOLS, arena->tree, + arena->lit_depth, arena->lit_bits, + storage_ix, storage); + BuildAndStoreHuffmanTree(arena->cmd_histo.data_, BROTLI_NUM_COMMAND_SYMBOLS, + BROTLI_NUM_COMMAND_SYMBOLS, arena->tree, + arena->cmd_depth, arena->cmd_bits, + storage_ix, storage); + BuildAndStoreHuffmanTree(arena->dist_histo.data_, + MAX_SIMPLE_DISTANCE_ALPHABET_SIZE, + num_distance_symbols, arena->tree, + arena->dist_depth, arena->dist_bits, + storage_ix, storage); + StoreDataWithHuffmanCodes(input, start_pos, mask, commands, + n_commands, arena->lit_depth, arena->lit_bits, + arena->cmd_depth, arena->cmd_bits, + arena->dist_depth, arena->dist_bits, + storage_ix, storage); + BROTLI_FREE(m, arena); + if (is_last) { + JumpToByteBoundary(storage_ix, storage); + } +} + +void BrotliStoreMetaBlockFast(MemoryManager* m, + const uint8_t* input, size_t start_pos, size_t length, size_t mask, + BROTLI_BOOL is_last, const BrotliEncoderParams* params, + const Command* commands, size_t n_commands, + size_t* storage_ix, uint8_t* storage) { + MetablockArena* arena = BROTLI_ALLOC(m, MetablockArena, 1); + uint32_t num_distance_symbols = params->dist.alphabet_size_max; + uint32_t distance_alphabet_bits = + Log2FloorNonZero(num_distance_symbols - 1) + 1; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(arena)) return; + + StoreCompressedMetaBlockHeader(is_last, length, storage_ix, storage); + + BrotliWriteBits(13, 0, storage_ix, storage); + + if (n_commands <= 128) { + uint32_t histogram[BROTLI_NUM_LITERAL_SYMBOLS] = { 0 }; + size_t pos = start_pos; + size_t num_literals = 0; + size_t i; + for (i = 0; i < n_commands; ++i) { + const Command cmd = commands[i]; + size_t j; + for (j = cmd.insert_len_; j != 0; --j) { + ++histogram[input[pos & mask]]; + ++pos; + } + num_literals += cmd.insert_len_; + pos += CommandCopyLen(&cmd); + } + BrotliBuildAndStoreHuffmanTreeFast(arena->tree, histogram, num_literals, + /* max_bits = */ 8, + arena->lit_depth, arena->lit_bits, + storage_ix, storage); + StoreStaticCommandHuffmanTree(storage_ix, storage); + StoreStaticDistanceHuffmanTree(storage_ix, storage); + StoreDataWithHuffmanCodes(input, start_pos, mask, commands, + n_commands, arena->lit_depth, arena->lit_bits, + kStaticCommandCodeDepth, + kStaticCommandCodeBits, + kStaticDistanceCodeDepth, + kStaticDistanceCodeBits, + storage_ix, storage); + } else { + HistogramClearLiteral(&arena->lit_histo); + HistogramClearCommand(&arena->cmd_histo); + HistogramClearDistance(&arena->dist_histo); + BuildHistograms(input, start_pos, mask, commands, n_commands, + &arena->lit_histo, &arena->cmd_histo, &arena->dist_histo); + BrotliBuildAndStoreHuffmanTreeFast(arena->tree, arena->lit_histo.data_, + arena->lit_histo.total_count_, + /* max_bits = */ 8, + arena->lit_depth, arena->lit_bits, + storage_ix, storage); + BrotliBuildAndStoreHuffmanTreeFast(arena->tree, arena->cmd_histo.data_, + arena->cmd_histo.total_count_, + /* max_bits = */ 10, + arena->cmd_depth, arena->cmd_bits, + storage_ix, storage); + BrotliBuildAndStoreHuffmanTreeFast(arena->tree, arena->dist_histo.data_, + arena->dist_histo.total_count_, + /* max_bits = */ + distance_alphabet_bits, + arena->dist_depth, arena->dist_bits, + storage_ix, storage); + StoreDataWithHuffmanCodes(input, start_pos, mask, commands, + n_commands, arena->lit_depth, arena->lit_bits, + arena->cmd_depth, arena->cmd_bits, + arena->dist_depth, arena->dist_bits, + storage_ix, storage); + } + + BROTLI_FREE(m, arena); + + if (is_last) { + JumpToByteBoundary(storage_ix, storage); + } +} + +/* This is for storing uncompressed blocks (simple raw storage of + bytes-as-bytes). */ +void BrotliStoreUncompressedMetaBlock(BROTLI_BOOL is_final_block, + const uint8_t* BROTLI_RESTRICT input, + size_t position, size_t mask, + size_t len, + size_t* BROTLI_RESTRICT storage_ix, + uint8_t* BROTLI_RESTRICT storage) { + size_t masked_pos = position & mask; + BrotliStoreUncompressedMetaBlockHeader(len, storage_ix, storage); + JumpToByteBoundary(storage_ix, storage); + + if (masked_pos + len > mask + 1) { + size_t len1 = mask + 1 - masked_pos; + memcpy(&storage[*storage_ix >> 3], &input[masked_pos], len1); + *storage_ix += len1 << 3; + len -= len1; + masked_pos = 0; + } + memcpy(&storage[*storage_ix >> 3], &input[masked_pos], len); + *storage_ix += len << 3; + + /* We need to clear the next 4 bytes to continue to be + compatible with BrotliWriteBits. */ + BrotliWriteBitsPrepareStorage(*storage_ix, storage); + + /* Since the uncompressed block itself may not be the final block, add an + empty one after this. */ + if (is_final_block) { + BrotliWriteBits(1, 1, storage_ix, storage); /* islast */ + BrotliWriteBits(1, 1, storage_ix, storage); /* isempty */ + JumpToByteBoundary(storage_ix, storage); + } +} + +#if defined(BROTLI_TEST) +void BrotliGetBlockLengthPrefixCodeForTest(uint32_t len, size_t* code, + uint32_t* n_extra, uint32_t* extra); +void BrotliGetBlockLengthPrefixCodeForTest(uint32_t len, size_t* code, + uint32_t* n_extra, uint32_t* extra) { + GetBlockLengthPrefixCode(len, code, n_extra, extra); +} +#endif + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/brotli_bit_stream.h b/packages/runtime/vendor/brotli/c/enc/brotli_bit_stream.h new file mode 100644 index 000000000..7b72bdcee --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/brotli_bit_stream.h @@ -0,0 +1,83 @@ +/* Copyright 2014 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Functions to convert brotli-related data structures into the + brotli bit stream. The functions here operate under + assumption that there is enough space in the storage, i.e., there are + no out-of-range checks anywhere. + + These functions do bit addressing into a byte array. The byte array + is called "storage" and the index to the bit is called storage_ix + in function arguments. */ + +#ifndef BROTLI_ENC_BROTLI_BIT_STREAM_H_ +#define BROTLI_ENC_BROTLI_BIT_STREAM_H_ + +#include "../common/context.h" +#include "../common/platform.h" +#include "command.h" +#include "entropy_encode.h" +#include "memory.h" +#include "metablock.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* All Store functions here will use a storage_ix, which is always the bit + position for the current storage. */ + +BROTLI_INTERNAL void BrotliStoreHuffmanTree(const uint8_t* depths, size_t num, + HuffmanTree* tree, size_t* storage_ix, uint8_t* storage); + +BROTLI_INTERNAL void BrotliBuildAndStoreHuffmanTreeFast( + HuffmanTree* tree, const uint32_t* histogram, const size_t histogram_total, + const size_t max_bits, uint8_t* depth, uint16_t* bits, size_t* storage_ix, + uint8_t* storage); + +/* REQUIRES: length > 0 */ +/* REQUIRES: length <= (1 << 24) */ +BROTLI_INTERNAL void BrotliStoreMetaBlock(MemoryManager* m, + const uint8_t* input, size_t start_pos, size_t length, size_t mask, + uint8_t prev_byte, uint8_t prev_byte2, BROTLI_BOOL is_last, + const BrotliEncoderParams* params, ContextType literal_context_mode, + const Command* commands, size_t n_commands, const MetaBlockSplit* mb, + size_t* storage_ix, uint8_t* storage); + +/* Stores the meta-block without doing any block splitting, just collects + one histogram per block category and uses that for entropy coding. + REQUIRES: length > 0 + REQUIRES: length <= (1 << 24) */ +BROTLI_INTERNAL void BrotliStoreMetaBlockTrivial(MemoryManager* m, + const uint8_t* input, size_t start_pos, size_t length, size_t mask, + BROTLI_BOOL is_last, const BrotliEncoderParams* params, + const Command* commands, size_t n_commands, + size_t* storage_ix, uint8_t* storage); + +/* Same as above, but uses static prefix codes for histograms with a only a few + symbols, and uses static code length prefix codes for all other histograms. + REQUIRES: length > 0 + REQUIRES: length <= (1 << 24) */ +BROTLI_INTERNAL void BrotliStoreMetaBlockFast(MemoryManager* m, + const uint8_t* input, size_t start_pos, size_t length, size_t mask, + BROTLI_BOOL is_last, const BrotliEncoderParams* params, + const Command* commands, size_t n_commands, + size_t* storage_ix, uint8_t* storage); + +/* This is for storing uncompressed blocks (simple raw storage of + bytes-as-bytes). + REQUIRES: length > 0 + REQUIRES: length <= (1 << 24) */ +BROTLI_INTERNAL void BrotliStoreUncompressedMetaBlock( + BROTLI_BOOL is_final_block, const uint8_t* BROTLI_RESTRICT input, + size_t position, size_t mask, size_t len, + size_t* BROTLI_RESTRICT storage_ix, uint8_t* BROTLI_RESTRICT storage); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_BROTLI_BIT_STREAM_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/cluster.c b/packages/runtime/vendor/brotli/c/enc/cluster.c new file mode 100644 index 000000000..4bf94ab76 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/cluster.c @@ -0,0 +1,55 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Functions for clustering similar histograms together. */ + +#include "cluster.h" + +#include "../common/platform.h" +#include "bit_cost.h" /* BrotliPopulationCost */ +#include "fast_log.h" +#include "histogram.h" +#include "memory.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +static BROTLI_INLINE BROTLI_BOOL HistogramPairIsLess( + const HistogramPair* p1, const HistogramPair* p2) { + if (p1->cost_diff != p2->cost_diff) { + return TO_BROTLI_BOOL(p1->cost_diff > p2->cost_diff); + } + return TO_BROTLI_BOOL((p1->idx2 - p1->idx1) > (p2->idx2 - p2->idx1)); +} + +/* Returns entropy reduction of the context map when we combine two clusters. */ +static BROTLI_INLINE double ClusterCostDiff(size_t size_a, size_t size_b) { + size_t size_c = size_a + size_b; + return (double)size_a * FastLog2(size_a) + + (double)size_b * FastLog2(size_b) - + (double)size_c * FastLog2(size_c); +} + +#define CODE(X) X + +#define FN(X) X ## Literal +#include "cluster_inc.h" /* NOLINT(build/include) */ +#undef FN + +#define FN(X) X ## Command +#include "cluster_inc.h" /* NOLINT(build/include) */ +#undef FN + +#define FN(X) X ## Distance +#include "cluster_inc.h" /* NOLINT(build/include) */ +#undef FN + +#undef CODE + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/cluster.h b/packages/runtime/vendor/brotli/c/enc/cluster.h new file mode 100644 index 000000000..6519116c4 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/cluster.h @@ -0,0 +1,47 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Functions for clustering similar histograms together. */ + +#ifndef BROTLI_ENC_CLUSTER_H_ +#define BROTLI_ENC_CLUSTER_H_ + +#include "../common/platform.h" +#include "histogram.h" +#include "memory.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +typedef struct HistogramPair { + uint32_t idx1; + uint32_t idx2; + double cost_combo; + double cost_diff; +} HistogramPair; + +#define CODE(X) /* Declaration */; + +#define FN(X) X ## Literal +#include "cluster_inc.h" /* NOLINT(build/include) */ +#undef FN + +#define FN(X) X ## Command +#include "cluster_inc.h" /* NOLINT(build/include) */ +#undef FN + +#define FN(X) X ## Distance +#include "cluster_inc.h" /* NOLINT(build/include) */ +#undef FN + +#undef CODE + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_CLUSTER_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/cluster_inc.h b/packages/runtime/vendor/brotli/c/enc/cluster_inc.h new file mode 100644 index 000000000..d6215ef06 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/cluster_inc.h @@ -0,0 +1,325 @@ +/* NOLINT(build/header_guard) */ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* template parameters: FN, CODE */ + +#define HistogramType FN(Histogram) + +/* Computes the bit cost reduction by combining out[idx1] and out[idx2] and if + it is below a threshold, stores the pair (idx1, idx2) in the *pairs queue. */ +BROTLI_INTERNAL void FN(BrotliCompareAndPushToQueue)( + const HistogramType* out, HistogramType* tmp, const uint32_t* cluster_size, + uint32_t idx1, uint32_t idx2, size_t max_num_pairs, HistogramPair* pairs, + size_t* num_pairs) CODE({ + BROTLI_BOOL is_good_pair = BROTLI_FALSE; + HistogramPair p; + p.idx1 = p.idx2 = 0; + p.cost_diff = p.cost_combo = 0; + if (idx1 == idx2) { + return; + } + if (idx2 < idx1) { + uint32_t t = idx2; + idx2 = idx1; + idx1 = t; + } + p.idx1 = idx1; + p.idx2 = idx2; + p.cost_diff = 0.5 * ClusterCostDiff(cluster_size[idx1], cluster_size[idx2]); + p.cost_diff -= out[idx1].bit_cost_; + p.cost_diff -= out[idx2].bit_cost_; + + if (out[idx1].total_count_ == 0) { + p.cost_combo = out[idx2].bit_cost_; + is_good_pair = BROTLI_TRUE; + } else if (out[idx2].total_count_ == 0) { + p.cost_combo = out[idx1].bit_cost_; + is_good_pair = BROTLI_TRUE; + } else { + double threshold = *num_pairs == 0 ? 1e99 : + BROTLI_MAX(double, 0.0, pairs[0].cost_diff); + double cost_combo; + *tmp = out[idx1]; + FN(HistogramAddHistogram)(tmp, &out[idx2]); + cost_combo = FN(BrotliPopulationCost)(tmp); + if (cost_combo < threshold - p.cost_diff) { + p.cost_combo = cost_combo; + is_good_pair = BROTLI_TRUE; + } + } + if (is_good_pair) { + p.cost_diff += p.cost_combo; + if (*num_pairs > 0 && HistogramPairIsLess(&pairs[0], &p)) { + /* Replace the top of the queue if needed. */ + if (*num_pairs < max_num_pairs) { + pairs[*num_pairs] = pairs[0]; + ++(*num_pairs); + } + pairs[0] = p; + } else if (*num_pairs < max_num_pairs) { + pairs[*num_pairs] = p; + ++(*num_pairs); + } + } +}) + +BROTLI_INTERNAL size_t FN(BrotliHistogramCombine)(HistogramType* out, + HistogramType* tmp, + uint32_t* cluster_size, + uint32_t* symbols, + uint32_t* clusters, + HistogramPair* pairs, + size_t num_clusters, + size_t symbols_size, + size_t max_clusters, + size_t max_num_pairs) CODE({ + double cost_diff_threshold = 0.0; + size_t min_cluster_size = 1; + size_t num_pairs = 0; + + { + /* We maintain a vector of histogram pairs, with the property that the pair + with the maximum bit cost reduction is the first. */ + size_t idx1; + for (idx1 = 0; idx1 < num_clusters; ++idx1) { + size_t idx2; + for (idx2 = idx1 + 1; idx2 < num_clusters; ++idx2) { + FN(BrotliCompareAndPushToQueue)(out, tmp, cluster_size, clusters[idx1], + clusters[idx2], max_num_pairs, &pairs[0], &num_pairs); + } + } + } + + while (num_clusters > min_cluster_size) { + uint32_t best_idx1; + uint32_t best_idx2; + size_t i; + if (pairs[0].cost_diff >= cost_diff_threshold) { + cost_diff_threshold = 1e99; + min_cluster_size = max_clusters; + continue; + } + /* Take the best pair from the top of heap. */ + best_idx1 = pairs[0].idx1; + best_idx2 = pairs[0].idx2; + FN(HistogramAddHistogram)(&out[best_idx1], &out[best_idx2]); + out[best_idx1].bit_cost_ = pairs[0].cost_combo; + cluster_size[best_idx1] += cluster_size[best_idx2]; + for (i = 0; i < symbols_size; ++i) { + if (symbols[i] == best_idx2) { + symbols[i] = best_idx1; + } + } + for (i = 0; i < num_clusters; ++i) { + if (clusters[i] == best_idx2) { + memmove(&clusters[i], &clusters[i + 1], + (num_clusters - i - 1) * sizeof(clusters[0])); + break; + } + } + --num_clusters; + { + /* Remove pairs intersecting the just combined best pair. */ + size_t copy_to_idx = 0; + for (i = 0; i < num_pairs; ++i) { + HistogramPair* p = &pairs[i]; + if (p->idx1 == best_idx1 || p->idx2 == best_idx1 || + p->idx1 == best_idx2 || p->idx2 == best_idx2) { + /* Remove invalid pair from the queue. */ + continue; + } + if (HistogramPairIsLess(&pairs[0], p)) { + /* Replace the top of the queue if needed. */ + HistogramPair front = pairs[0]; + pairs[0] = *p; + pairs[copy_to_idx] = front; + } else { + pairs[copy_to_idx] = *p; + } + ++copy_to_idx; + } + num_pairs = copy_to_idx; + } + + /* Push new pairs formed with the combined histogram to the heap. */ + for (i = 0; i < num_clusters; ++i) { + FN(BrotliCompareAndPushToQueue)(out, tmp, cluster_size, best_idx1, + clusters[i], max_num_pairs, &pairs[0], &num_pairs); + } + } + return num_clusters; +}) + +/* What is the bit cost of moving histogram from cur_symbol to candidate. */ +BROTLI_INTERNAL double FN(BrotliHistogramBitCostDistance)( + const HistogramType* histogram, const HistogramType* candidate, + HistogramType* tmp) CODE({ + if (histogram->total_count_ == 0) { + return 0.0; + } else { + *tmp = *histogram; + FN(HistogramAddHistogram)(tmp, candidate); + return FN(BrotliPopulationCost)(tmp) - candidate->bit_cost_; + } +}) + +/* Find the best 'out' histogram for each of the 'in' histograms. + When called, clusters[0..num_clusters) contains the unique values from + symbols[0..in_size), but this property is not preserved in this function. + Note: we assume that out[]->bit_cost_ is already up-to-date. */ +BROTLI_INTERNAL void FN(BrotliHistogramRemap)(const HistogramType* in, + size_t in_size, const uint32_t* clusters, size_t num_clusters, + HistogramType* out, HistogramType* tmp, uint32_t* symbols) CODE({ + size_t i; + for (i = 0; i < in_size; ++i) { + uint32_t best_out = i == 0 ? symbols[0] : symbols[i - 1]; + double best_bits = + FN(BrotliHistogramBitCostDistance)(&in[i], &out[best_out], tmp); + size_t j; + for (j = 0; j < num_clusters; ++j) { + const double cur_bits = + FN(BrotliHistogramBitCostDistance)(&in[i], &out[clusters[j]], tmp); + if (cur_bits < best_bits) { + best_bits = cur_bits; + best_out = clusters[j]; + } + } + symbols[i] = best_out; + } + + /* Recompute each out based on raw and symbols. */ + for (i = 0; i < num_clusters; ++i) { + FN(HistogramClear)(&out[clusters[i]]); + } + for (i = 0; i < in_size; ++i) { + FN(HistogramAddHistogram)(&out[symbols[i]], &in[i]); + } +}) + +/* Reorders elements of the out[0..length) array and changes values in + symbols[0..length) array in the following way: + * when called, symbols[] contains indexes into out[], and has N unique + values (possibly N < length) + * on return, symbols'[i] = f(symbols[i]) and + out'[symbols'[i]] = out[symbols[i]], for each 0 <= i < length, + where f is a bijection between the range of symbols[] and [0..N), and + the first occurrences of values in symbols'[i] come in consecutive + increasing order. + Returns N, the number of unique values in symbols[]. */ +BROTLI_INTERNAL size_t FN(BrotliHistogramReindex)(MemoryManager* m, + HistogramType* out, uint32_t* symbols, size_t length) CODE({ + static const uint32_t kInvalidIndex = BROTLI_UINT32_MAX; + uint32_t* new_index = BROTLI_ALLOC(m, uint32_t, length); + uint32_t next_index; + HistogramType* tmp; + size_t i; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_index)) return 0; + for (i = 0; i < length; ++i) { + new_index[i] = kInvalidIndex; + } + next_index = 0; + for (i = 0; i < length; ++i) { + if (new_index[symbols[i]] == kInvalidIndex) { + new_index[symbols[i]] = next_index; + ++next_index; + } + } + /* TODO(eustas): by using idea of "cycle-sort" we can avoid allocation of + tmp and reduce the number of copying by the factor of 2. */ + tmp = BROTLI_ALLOC(m, HistogramType, next_index); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp)) return 0; + next_index = 0; + for (i = 0; i < length; ++i) { + if (new_index[symbols[i]] == next_index) { + tmp[next_index] = out[symbols[i]]; + ++next_index; + } + symbols[i] = new_index[symbols[i]]; + } + BROTLI_FREE(m, new_index); + for (i = 0; i < next_index; ++i) { + out[i] = tmp[i]; + } + BROTLI_FREE(m, tmp); + return next_index; +}) + +BROTLI_INTERNAL void FN(BrotliClusterHistograms)( + MemoryManager* m, const HistogramType* in, const size_t in_size, + size_t max_histograms, HistogramType* out, size_t* out_size, + uint32_t* histogram_symbols) CODE({ + uint32_t* cluster_size = BROTLI_ALLOC(m, uint32_t, in_size); + uint32_t* clusters = BROTLI_ALLOC(m, uint32_t, in_size); + size_t num_clusters = 0; + const size_t max_input_histograms = 64; + size_t pairs_capacity = max_input_histograms * max_input_histograms / 2; + /* For the first pass of clustering, we allow all pairs. */ + HistogramPair* pairs = BROTLI_ALLOC(m, HistogramPair, pairs_capacity + 1); + /* TODO(eustas): move to "persistent" arena? */ + HistogramType* tmp = BROTLI_ALLOC(m, HistogramType, 1); + size_t i; + + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(cluster_size) || + BROTLI_IS_NULL(clusters) || BROTLI_IS_NULL(pairs)|| BROTLI_IS_NULL(tmp)) { + return; + } + + for (i = 0; i < in_size; ++i) { + cluster_size[i] = 1; + } + + for (i = 0; i < in_size; ++i) { + out[i] = in[i]; + out[i].bit_cost_ = FN(BrotliPopulationCost)(&in[i]); + histogram_symbols[i] = (uint32_t)i; + } + + for (i = 0; i < in_size; i += max_input_histograms) { + size_t num_to_combine = + BROTLI_MIN(size_t, in_size - i, max_input_histograms); + size_t num_new_clusters; + size_t j; + for (j = 0; j < num_to_combine; ++j) { + clusters[num_clusters + j] = (uint32_t)(i + j); + } + num_new_clusters = + FN(BrotliHistogramCombine)(out, tmp, cluster_size, + &histogram_symbols[i], + &clusters[num_clusters], pairs, + num_to_combine, num_to_combine, + max_histograms, pairs_capacity); + num_clusters += num_new_clusters; + } + + { + /* For the second pass, we limit the total number of histogram pairs. + After this limit is reached, we only keep searching for the best pair. */ + size_t max_num_pairs = BROTLI_MIN(size_t, + 64 * num_clusters, (num_clusters / 2) * num_clusters); + BROTLI_ENSURE_CAPACITY( + m, HistogramPair, pairs, pairs_capacity, max_num_pairs + 1); + if (BROTLI_IS_OOM(m)) return; + + /* Collapse similar histograms. */ + num_clusters = FN(BrotliHistogramCombine)(out, tmp, cluster_size, + histogram_symbols, clusters, + pairs, num_clusters, in_size, + max_histograms, max_num_pairs); + } + BROTLI_FREE(m, pairs); + BROTLI_FREE(m, cluster_size); + /* Find the optimal map from original histograms to the final ones. */ + FN(BrotliHistogramRemap)(in, in_size, clusters, num_clusters, + out, tmp, histogram_symbols); + BROTLI_FREE(m, tmp); + BROTLI_FREE(m, clusters); + /* Convert the context map to a canonical form. */ + *out_size = FN(BrotliHistogramReindex)(m, out, histogram_symbols, in_size); + if (BROTLI_IS_OOM(m)) return; +}) + +#undef HistogramType diff --git a/packages/runtime/vendor/brotli/c/enc/command.c b/packages/runtime/vendor/brotli/c/enc/command.c new file mode 100644 index 000000000..699fa8098 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/command.c @@ -0,0 +1,28 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#include "command.h" + +#include "../common/platform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +const uint32_t kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES] = { + 0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26, + 34, 50, 66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594}; +const uint32_t kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES] = { + 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 12, 14, 24}; +const uint32_t kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES] = { + 2, 3, 4, 5, 6, 7, 8, 9, 10, 12, 14, 18, + 22, 30, 38, 54, 70, 102, 134, 198, 326, 582, 1094, 2118}; +const uint32_t kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES] = { + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 24}; + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/command.h b/packages/runtime/vendor/brotli/c/enc/command.h new file mode 100644 index 000000000..c1cb208e6 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/command.h @@ -0,0 +1,189 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* This class models a sequence of literals and a backward reference copy. */ + +#ifndef BROTLI_ENC_COMMAND_H_ +#define BROTLI_ENC_COMMAND_H_ + +#include "../common/constants.h" +#include "../common/platform.h" +#include "fast_log.h" +#include "params.h" +#include "prefix.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +BROTLI_INTERNAL extern const BROTLI_MODEL("small") +uint32_t kBrotliInsBase[BROTLI_NUM_INS_COPY_CODES]; +BROTLI_INTERNAL extern const BROTLI_MODEL("small") +uint32_t kBrotliInsExtra[BROTLI_NUM_INS_COPY_CODES]; +BROTLI_INTERNAL extern const BROTLI_MODEL("small") +uint32_t kBrotliCopyBase[BROTLI_NUM_INS_COPY_CODES]; +BROTLI_INTERNAL extern const BROTLI_MODEL("small") +uint32_t kBrotliCopyExtra[BROTLI_NUM_INS_COPY_CODES]; + +static BROTLI_INLINE uint16_t GetInsertLengthCode(size_t insertlen) { + if (insertlen < 6) { + return (uint16_t)insertlen; + } else if (insertlen < 130) { + uint32_t nbits = Log2FloorNonZero(insertlen - 2) - 1u; + return (uint16_t)((nbits << 1) + ((insertlen - 2) >> nbits) + 2); + } else if (insertlen < 2114) { + return (uint16_t)(Log2FloorNonZero(insertlen - 66) + 10); + } else if (insertlen < 6210) { + return 21u; + } else if (insertlen < 22594) { + return 22u; + } else { + return 23u; + } +} + +static BROTLI_INLINE uint16_t GetCopyLengthCode(size_t copylen) { + if (copylen < 10) { + return (uint16_t)(copylen - 2); + } else if (copylen < 134) { + uint32_t nbits = Log2FloorNonZero(copylen - 6) - 1u; + return (uint16_t)((nbits << 1) + ((copylen - 6) >> nbits) + 4); + } else if (copylen < 2118) { + return (uint16_t)(Log2FloorNonZero(copylen - 70) + 12); + } else { + return 23u; + } +} + +static BROTLI_INLINE uint16_t CombineLengthCodes( + uint16_t inscode, uint16_t copycode, BROTLI_BOOL use_last_distance) { + uint16_t bits64 = + (uint16_t)((copycode & 0x7u) | ((inscode & 0x7u) << 3u)); + if (use_last_distance && inscode < 8u && copycode < 16u) { + return (copycode < 8u) ? bits64 : (bits64 | 64u); + } else { + /* Specification: 5 Encoding of ... (last table) */ + /* offset = 2 * index, where index is in range [0..8] */ + uint32_t offset = 2u * ((copycode >> 3u) + 3u * (inscode >> 3u)); + /* All values in specification are K * 64, + where K = [2, 3, 6, 4, 5, 8, 7, 9, 10], + i + 1 = [1, 2, 3, 4, 5, 6, 7, 8, 9], + K - i - 1 = [1, 1, 3, 0, 0, 2, 0, 1, 2] = D. + All values in D require only 2 bits to encode. + Magic constant is shifted 6 bits left, to avoid final multiplication. */ + offset = (offset << 5u) + 0x40u + ((0x520D40u >> offset) & 0xC0u); + return (uint16_t)(offset | bits64); + } +} + +static BROTLI_INLINE void GetLengthCode(size_t insertlen, size_t copylen, + BROTLI_BOOL use_last_distance, + uint16_t* code) { + uint16_t inscode = GetInsertLengthCode(insertlen); + uint16_t copycode = GetCopyLengthCode(copylen); + *code = CombineLengthCodes(inscode, copycode, use_last_distance); +} + +static BROTLI_INLINE uint32_t GetInsertBase(uint16_t inscode) { + return kBrotliInsBase[inscode]; +} + +static BROTLI_INLINE uint32_t GetInsertExtra(uint16_t inscode) { + return kBrotliInsExtra[inscode]; +} + +static BROTLI_INLINE uint32_t GetCopyBase(uint16_t copycode) { + return kBrotliCopyBase[copycode]; +} + +static BROTLI_INLINE uint32_t GetCopyExtra(uint16_t copycode) { + return kBrotliCopyExtra[copycode]; +} + +typedef struct Command { + uint32_t insert_len_; + /* Stores copy_len in low 25 bits and copy_code - copy_len in high 7 bit. */ + uint32_t copy_len_; + /* Stores distance extra bits. */ + uint32_t dist_extra_; + uint16_t cmd_prefix_; + /* Stores distance code in low 10 bits + and number of extra bits in high 6 bits. */ + uint16_t dist_prefix_; +} Command; + +/* distance_code is e.g. 0 for same-as-last short code, or 16 for offset 1. */ +static BROTLI_INLINE void InitCommand(Command* self, + const BrotliDistanceParams* dist, size_t insertlen, + size_t copylen, int copylen_code_delta, size_t distance_code) { + /* Don't rely on signed int representation, use honest casts. */ + uint32_t delta = (uint8_t)((int8_t)copylen_code_delta); + self->insert_len_ = (uint32_t)insertlen; + self->copy_len_ = (uint32_t)(copylen | (delta << 25)); + /* The distance prefix and extra bits are stored in this Command as if + npostfix and ndirect were 0, they are only recomputed later after the + clustering if needed. */ + PrefixEncodeCopyDistance( + distance_code, dist->num_direct_distance_codes, + dist->distance_postfix_bits, &self->dist_prefix_, &self->dist_extra_); + GetLengthCode( + insertlen, (size_t)((int)copylen + copylen_code_delta), + TO_BROTLI_BOOL((self->dist_prefix_ & 0x3FF) == 0), &self->cmd_prefix_); +} + +static BROTLI_INLINE void InitInsertCommand(Command* self, size_t insertlen) { + self->insert_len_ = (uint32_t)insertlen; + self->copy_len_ = 4 << 25; + self->dist_extra_ = 0; + self->dist_prefix_ = BROTLI_NUM_DISTANCE_SHORT_CODES; + GetLengthCode(insertlen, 4, BROTLI_FALSE, &self->cmd_prefix_); +} + +static BROTLI_INLINE uint32_t CommandRestoreDistanceCode( + const Command* self, const BrotliDistanceParams* dist) { + if ((self->dist_prefix_ & 0x3FFu) < + BROTLI_NUM_DISTANCE_SHORT_CODES + dist->num_direct_distance_codes) { + return self->dist_prefix_ & 0x3FFu; + } else { + uint32_t dcode = self->dist_prefix_ & 0x3FFu; + uint32_t nbits = self->dist_prefix_ >> 10; + uint32_t extra = self->dist_extra_; + uint32_t postfix_mask = (1U << dist->distance_postfix_bits) - 1U; + uint32_t hcode = (dcode - dist->num_direct_distance_codes - + BROTLI_NUM_DISTANCE_SHORT_CODES) >> + dist->distance_postfix_bits; + uint32_t lcode = (dcode - dist->num_direct_distance_codes - + BROTLI_NUM_DISTANCE_SHORT_CODES) & postfix_mask; + uint32_t offset = ((2U + (hcode & 1U)) << nbits) - 4U; + return ((offset + extra) << dist->distance_postfix_bits) + lcode + + dist->num_direct_distance_codes + BROTLI_NUM_DISTANCE_SHORT_CODES; + } +} + +static BROTLI_INLINE uint32_t CommandDistanceContext(const Command* self) { + uint32_t r = self->cmd_prefix_ >> 6; + uint32_t c = self->cmd_prefix_ & 7; + if ((r == 0 || r == 2 || r == 4 || r == 7) && (c <= 2)) { + return c; + } + return 3; +} + +static BROTLI_INLINE uint32_t CommandCopyLen(const Command* self) { + return self->copy_len_ & 0x1FFFFFF; +} + +static BROTLI_INLINE uint32_t CommandCopyLenCode(const Command* self) { + uint32_t modifier = self->copy_len_ >> 25; + int32_t delta = (int8_t)((uint8_t)(modifier | ((modifier & 0x40) << 1))); + return (uint32_t)((int32_t)(self->copy_len_ & 0x1FFFFFF) + delta); +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_COMMAND_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/compound_dictionary.c b/packages/runtime/vendor/brotli/c/enc/compound_dictionary.c new file mode 100644 index 000000000..bf323a4b3 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/compound_dictionary.c @@ -0,0 +1,205 @@ +/* Copyright 2017 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#include "compound_dictionary.h" + +#include "../common/platform.h" +#include +#include "memory.h" + +static PreparedDictionary* CreatePreparedDictionaryWithParams(MemoryManager* m, + const uint8_t* source, size_t source_size, uint32_t bucket_bits, + uint32_t slot_bits, uint32_t hash_bits, uint16_t bucket_limit) { + /* Step 1: create "bloated" hasher. */ + uint32_t num_slots = 1u << slot_bits; + uint32_t num_buckets = 1u << bucket_bits; + uint32_t hash_shift = 64u - bucket_bits; + uint64_t hash_mask = (~((uint64_t)0U)) >> (64 - hash_bits); + uint32_t slot_mask = num_slots - 1; + size_t alloc_size = (sizeof(uint32_t) << slot_bits) + + (sizeof(uint32_t) << slot_bits) + + (sizeof(uint16_t) << bucket_bits) + + (sizeof(uint32_t) << bucket_bits) + + (sizeof(uint32_t) * source_size); + uint8_t* flat = NULL; + PreparedDictionary* result = NULL; + uint16_t* num = NULL; + uint32_t* bucket_heads = NULL; + uint32_t* next_bucket = NULL; + uint32_t* slot_offsets = NULL; + uint16_t* heads = NULL; + uint32_t* items = NULL; + uint8_t** source_ref = NULL; + uint32_t i; + uint32_t* slot_size = NULL; + uint32_t* slot_limit = NULL; + uint32_t total_items = 0; + if (slot_bits > 16) return NULL; + if (slot_bits > bucket_bits) return NULL; + if (bucket_bits - slot_bits >= 16) return NULL; + + flat = BROTLI_ALLOC(m, uint8_t, alloc_size); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(flat)) return NULL; + + slot_size = (uint32_t*)flat; + slot_limit = (uint32_t*)(&slot_size[num_slots]); + num = (uint16_t*)(&slot_limit[num_slots]); + bucket_heads = (uint32_t*)(&num[num_buckets]); + next_bucket = (uint32_t*)(&bucket_heads[num_buckets]); + memset(num, 0, num_buckets * sizeof(num[0])); + + /* TODO(eustas): apply custom "store" order. */ + for (i = 0; i + 7 < source_size; ++i) { + const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(&source[i]) & hash_mask) * + kPreparedDictionaryHashMul64Long; + const uint32_t key = (uint32_t)(h >> hash_shift); + uint16_t count = num[key]; + next_bucket[i] = (count == 0) ? ((uint32_t)(-1)) : bucket_heads[key]; + bucket_heads[key] = i; + count++; + if (count > bucket_limit) count = bucket_limit; + num[key] = count; + } + + /* Step 2: find slot limits. */ + for (i = 0; i < num_slots; ++i) { + BROTLI_BOOL overflow = BROTLI_FALSE; + slot_limit[i] = bucket_limit; + while (BROTLI_TRUE) { + uint32_t limit = slot_limit[i]; + size_t j; + uint32_t count = 0; + overflow = BROTLI_FALSE; + for (j = i; j < num_buckets; j += num_slots) { + uint32_t size = num[j]; + /* Last chain may span behind 64K limit; overflow happens only if + we are about to use 0xFFFF+ as item offset. */ + if (count >= 0xFFFF) { + overflow = BROTLI_TRUE; + break; + } + if (size > limit) size = limit; + count += size; + } + if (!overflow) { + slot_size[i] = count; + total_items += count; + break; + } + slot_limit[i]--; + } + } + + /* Step 3: transfer data to "slim" hasher. */ + alloc_size = sizeof(PreparedDictionary) + (sizeof(uint32_t) << slot_bits) + + (sizeof(uint16_t) << bucket_bits) + (sizeof(uint32_t) * total_items) + + sizeof(uint8_t*); + + result = (PreparedDictionary*)BROTLI_ALLOC(m, uint8_t, alloc_size); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(result)) { + BROTLI_FREE(m, flat); + return NULL; + } + slot_offsets = (uint32_t*)(&result[1]); + heads = (uint16_t*)(&slot_offsets[num_slots]); + items = (uint32_t*)(&heads[num_buckets]); + source_ref = (uint8_t**)(&items[total_items]); + + result->magic = kLeanPreparedDictionaryMagic; + result->num_items = total_items; + result->source_size = (uint32_t)source_size; + result->hash_bits = hash_bits; + result->bucket_bits = bucket_bits; + result->slot_bits = slot_bits; + BROTLI_UNALIGNED_STORE_PTR(source_ref, source); + + total_items = 0; + for (i = 0; i < num_slots; ++i) { + slot_offsets[i] = total_items; + total_items += slot_size[i]; + slot_size[i] = 0; + } + for (i = 0; i < num_buckets; ++i) { + uint32_t slot = i & slot_mask; + uint32_t count = num[i]; + uint32_t pos; + size_t j; + size_t cursor = slot_size[slot]; + if (count > slot_limit[slot]) count = slot_limit[slot]; + if (count == 0) { + heads[i] = 0xFFFF; + continue; + } + heads[i] = (uint16_t)cursor; + cursor += slot_offsets[slot]; + slot_size[slot] += count; + pos = bucket_heads[i]; + for (j = 0; j < count; j++) { + items[cursor++] = pos; + pos = next_bucket[pos]; + } + items[cursor - 1] |= 0x80000000; + } + + BROTLI_FREE(m, flat); + return result; +} + +PreparedDictionary* CreatePreparedDictionary(MemoryManager* m, + const uint8_t* source, size_t source_size) { + uint32_t bucket_bits = 17; + uint32_t slot_bits = 7; + uint32_t hash_bits = 40; + uint16_t bucket_limit = 32; + size_t volume = 16u << bucket_bits; + /* Tune parameters to fit dictionary size. */ + while (volume < source_size && bucket_bits < 22) { + bucket_bits++; + slot_bits++; + volume <<= 1; + } + return CreatePreparedDictionaryWithParams(m, + source, source_size, bucket_bits, slot_bits, hash_bits, bucket_limit); +} + +void DestroyPreparedDictionary(MemoryManager* m, + PreparedDictionary* dictionary) { + if (!dictionary) return; + BROTLI_FREE(m, dictionary); +} + +BROTLI_BOOL AttachPreparedDictionary( + CompoundDictionary* compound, const PreparedDictionary* dictionary) { + size_t length = 0; + size_t index = 0; + + if (compound->num_chunks == SHARED_BROTLI_MAX_COMPOUND_DICTS) { + return BROTLI_FALSE; + } + + if (!dictionary) return BROTLI_FALSE; + + length = dictionary->source_size; + index = compound->num_chunks; + compound->total_size += length; + compound->chunks[index] = dictionary; + compound->chunk_offsets[index + 1] = compound->total_size; + { + uint32_t* slot_offsets = (uint32_t*)(&dictionary[1]); + uint16_t* heads = (uint16_t*)(&slot_offsets[(size_t)1u << dictionary->slot_bits]); + uint32_t* items = (uint32_t*)(&heads[(size_t)1u << dictionary->bucket_bits]); + const void* tail = (void*)&items[dictionary->num_items]; + if (dictionary->magic == kPreparedDictionaryMagic) { + compound->chunk_source[index] = (const uint8_t*)tail; + } else { + /* dictionary->magic == kLeanPreparedDictionaryMagic */ + compound->chunk_source[index] = + (const uint8_t*)BROTLI_UNALIGNED_LOAD_PTR((const uint8_t**)tail); + } + } + compound->num_chunks++; + return BROTLI_TRUE; +} diff --git a/packages/runtime/vendor/brotli/c/enc/compound_dictionary.h b/packages/runtime/vendor/brotli/c/enc/compound_dictionary.h new file mode 100644 index 000000000..686f92fda --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/compound_dictionary.h @@ -0,0 +1,71 @@ +/* Copyright 2017 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#ifndef BROTLI_ENC_PREPARED_DICTIONARY_H_ +#define BROTLI_ENC_PREPARED_DICTIONARY_H_ + +#include "../common/platform.h" +#include +#include "memory.h" + +/* "Fat" prepared dictionary, could be cooked outside of C implementation, + * e.g. on Java side. LZ77 data is copied inside PreparedDictionary struct. */ +static const uint32_t kPreparedDictionaryMagic = 0xDEBCEDE0; + +static const uint32_t kSharedDictionaryMagic = 0xDEBCEDE1; + +static const uint32_t kManagedDictionaryMagic = 0xDEBCEDE2; + +/* "Lean" prepared dictionary. LZ77 data is referenced. It is the responsibility + * of caller of "prepare dictionary" to keep the LZ77 data while prepared + * dictionary is in use. */ +static const uint32_t kLeanPreparedDictionaryMagic = 0xDEBCEDE3; + +static const uint64_t kPreparedDictionaryHashMul64Long = + BROTLI_MAKE_UINT64_T(0x1FE35A7Bu, 0xD3579BD3u); + +typedef struct PreparedDictionary { + uint32_t magic; + uint32_t num_items; + uint32_t source_size; + uint32_t hash_bits; + uint32_t bucket_bits; + uint32_t slot_bits; + + /* --- Dynamic size members --- */ + + /* uint32_t slot_offsets[1 << slot_bits]; */ + /* uint16_t heads[1 << bucket_bits]; */ + /* uint32_t items[variable]; */ + + /* [maybe] uint8_t* source_ref, depending on magic. */ + /* [maybe] uint8_t source[source_size], depending on magic. */ +} PreparedDictionary; + +BROTLI_INTERNAL PreparedDictionary* CreatePreparedDictionary(MemoryManager* m, + const uint8_t* source, size_t source_size); + +BROTLI_INTERNAL void DestroyPreparedDictionary(MemoryManager* m, + PreparedDictionary* dictionary); + +typedef struct CompoundDictionary { + /* LZ77 prefix, compound dictionary */ + size_t num_chunks; + size_t total_size; + /* Client instances. */ + const PreparedDictionary* chunks[SHARED_BROTLI_MAX_COMPOUND_DICTS + 1]; + const uint8_t* chunk_source[SHARED_BROTLI_MAX_COMPOUND_DICTS + 1]; + size_t chunk_offsets[SHARED_BROTLI_MAX_COMPOUND_DICTS + 1]; + + size_t num_prepared_instances_; + /* Owned instances. */ + PreparedDictionary* prepared_instances_[SHARED_BROTLI_MAX_COMPOUND_DICTS + 1]; +} CompoundDictionary; + +BROTLI_INTERNAL BROTLI_BOOL AttachPreparedDictionary( + CompoundDictionary* compound, const PreparedDictionary* dictionary); + +#endif /* BROTLI_ENC_PREPARED_DICTIONARY */ diff --git a/packages/runtime/vendor/brotli/c/enc/compress_fragment.c b/packages/runtime/vendor/brotli/c/enc/compress_fragment.c new file mode 100644 index 000000000..14fec4fbf --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/compress_fragment.c @@ -0,0 +1,790 @@ +/* Copyright 2015 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Function for fast encoding of an input fragment, independently from the input + history. This function uses one-pass processing: when we find a backward + match, we immediately emit the corresponding command and literal codes to + the bit stream. + + Adapted from the CompressFragment() function in + https://github.com/google/snappy/blob/master/snappy.cc */ + +#include "compress_fragment.h" + +#include "../common/constants.h" +#include "../common/platform.h" +#include "brotli_bit_stream.h" +#include "entropy_encode.h" +#include "fast_log.h" +#include "find_match_length.h" +#include "hash_base.h" +#include "write_bits.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define MAX_DISTANCE (long)BROTLI_MAX_BACKWARD_LIMIT(18) + +static BROTLI_INLINE uint32_t Hash(const uint8_t* p, size_t shift) { + const uint64_t h = (BROTLI_UNALIGNED_LOAD64LE(p) << 24) * kHashMul32; + return (uint32_t)(h >> shift); +} + +static BROTLI_INLINE uint32_t HashBytesAtOffset( + uint64_t v, int offset, size_t shift) { + BROTLI_DCHECK(offset >= 0); + BROTLI_DCHECK(offset <= 3); + { + const uint64_t h = ((v >> (8 * offset)) << 24) * kHashMul32; + return (uint32_t)(h >> shift); + } +} + +static BROTLI_INLINE BROTLI_BOOL IsMatch(const uint8_t* p1, const uint8_t* p2) { + return TO_BROTLI_BOOL( + BrotliUnalignedRead32(p1) == BrotliUnalignedRead32(p2) && + p1[4] == p2[4]); +} + +/* Builds a literal prefix code into "depths" and "bits" based on the statistics + of the "input" string and stores it into the bit stream. + Note that the prefix code here is built from the pre-LZ77 input, therefore + we can only approximate the statistics of the actual literal stream. + Moreover, for long inputs we build a histogram from a sample of the input + and thus have to assign a non-zero depth for each literal. + Returns estimated compression ratio millibytes/char for encoding given input + with generated code. */ +static size_t BuildAndStoreLiteralPrefixCode(BrotliOnePassArena* s, + const uint8_t* input, + const size_t input_size, + uint8_t depths[256], + uint16_t bits[256], + size_t* storage_ix, + uint8_t* storage) { + uint32_t* BROTLI_RESTRICT const histogram = s->histogram; + size_t histogram_total; + size_t i; + memset(histogram, 0, sizeof(s->histogram)); + + if (input_size < (1 << 15)) { + for (i = 0; i < input_size; ++i) { + ++histogram[input[i]]; + } + histogram_total = input_size; + for (i = 0; i < 256; ++i) { + /* We weigh the first 11 samples with weight 3 to account for the + balancing effect of the LZ77 phase on the histogram. */ + const uint32_t adjust = 2 * BROTLI_MIN(uint32_t, histogram[i], 11u); + histogram[i] += adjust; + histogram_total += adjust; + } + } else { + static const size_t kSampleRate = 29; + for (i = 0; i < input_size; i += kSampleRate) { + ++histogram[input[i]]; + } + histogram_total = (input_size + kSampleRate - 1) / kSampleRate; + for (i = 0; i < 256; ++i) { + /* We add 1 to each population count to avoid 0 bit depths (since this is + only a sample and we don't know if the symbol appears or not), and we + weigh the first 11 samples with weight 3 to account for the balancing + effect of the LZ77 phase on the histogram (more frequent symbols are + more likely to be in backward references instead as literals). */ + const uint32_t adjust = 1 + 2 * BROTLI_MIN(uint32_t, histogram[i], 11u); + histogram[i] += adjust; + histogram_total += adjust; + } + } + BrotliBuildAndStoreHuffmanTreeFast(s->tree, histogram, histogram_total, + /* max_bits = */ 8, + depths, bits, storage_ix, storage); + { + size_t literal_ratio = 0; + for (i = 0; i < 256; ++i) { + if (histogram[i]) literal_ratio += histogram[i] * depths[i]; + } + /* Estimated encoding ratio, millibytes per symbol. */ + return (literal_ratio * 125) / histogram_total; + } +} + +/* Builds a command and distance prefix code (each 64 symbols) into "depth" and + "bits" based on "histogram" and stores it into the bit stream. */ +static void BuildAndStoreCommandPrefixCode(BrotliOnePassArena* s, + size_t* storage_ix, uint8_t* storage) { + const uint32_t* const histogram = s->cmd_histo; + uint8_t* const depth = s->cmd_depth; + uint16_t* const bits = s->cmd_bits; + uint8_t* BROTLI_RESTRICT const tmp_depth = s->tmp_depth; + uint16_t* BROTLI_RESTRICT const tmp_bits = s->tmp_bits; + /* TODO(eustas): do only once on initialization. */ + memset(tmp_depth, 0, BROTLI_NUM_COMMAND_SYMBOLS); + + BrotliCreateHuffmanTree(histogram, 64, 15, s->tree, depth); + BrotliCreateHuffmanTree(&histogram[64], 64, 14, s->tree, &depth[64]); + /* We have to jump through a few hoops here in order to compute + the command bits because the symbols are in a different order than in + the full alphabet. This looks complicated, but having the symbols + in this order in the command bits saves a few branches in the Emit* + functions. */ + memcpy(tmp_depth, depth, 24); + memcpy(tmp_depth + 24, depth + 40, 8); + memcpy(tmp_depth + 32, depth + 24, 8); + memcpy(tmp_depth + 40, depth + 48, 8); + memcpy(tmp_depth + 48, depth + 32, 8); + memcpy(tmp_depth + 56, depth + 56, 8); + BrotliConvertBitDepthsToSymbols(tmp_depth, 64, tmp_bits); + memcpy(bits, tmp_bits, 48); + memcpy(bits + 24, tmp_bits + 32, 16); + memcpy(bits + 32, tmp_bits + 48, 16); + memcpy(bits + 40, tmp_bits + 24, 16); + memcpy(bits + 48, tmp_bits + 40, 16); + memcpy(bits + 56, tmp_bits + 56, 16); + BrotliConvertBitDepthsToSymbols(&depth[64], 64, &bits[64]); + { + /* Create the bit length array for the full command alphabet. */ + size_t i; + memset(tmp_depth, 0, 64); /* only 64 first values were used */ + memcpy(tmp_depth, depth, 8); + memcpy(tmp_depth + 64, depth + 8, 8); + memcpy(tmp_depth + 128, depth + 16, 8); + memcpy(tmp_depth + 192, depth + 24, 8); + memcpy(tmp_depth + 384, depth + 32, 8); + for (i = 0; i < 8; ++i) { + tmp_depth[128 + 8 * i] = depth[40 + i]; + tmp_depth[256 + 8 * i] = depth[48 + i]; + tmp_depth[448 + 8 * i] = depth[56 + i]; + } + /* TODO(eustas): could/should full-length machinery be avoided? */ + BrotliStoreHuffmanTree( + tmp_depth, BROTLI_NUM_COMMAND_SYMBOLS, s->tree, storage_ix, storage); + } + BrotliStoreHuffmanTree(&depth[64], 64, s->tree, storage_ix, storage); +} + +/* REQUIRES: insertlen < 6210 */ +static BROTLI_INLINE void EmitInsertLen(size_t insertlen, + const uint8_t depth[128], + const uint16_t bits[128], + uint32_t histo[128], + size_t* storage_ix, + uint8_t* storage) { + if (insertlen < 6) { + const size_t code = insertlen + 40; + BrotliWriteBits(depth[code], bits[code], storage_ix, storage); + ++histo[code]; + } else if (insertlen < 130) { + const size_t tail = insertlen - 2; + const uint32_t nbits = Log2FloorNonZero(tail) - 1u; + const size_t prefix = tail >> nbits; + const size_t inscode = (nbits << 1) + prefix + 42; + BrotliWriteBits(depth[inscode], bits[inscode], storage_ix, storage); + BrotliWriteBits(nbits, tail - (prefix << nbits), storage_ix, storage); + ++histo[inscode]; + } else if (insertlen < 2114) { + const size_t tail = insertlen - 66; + const uint32_t nbits = Log2FloorNonZero(tail); + const size_t code = nbits + 50; + BrotliWriteBits(depth[code], bits[code], storage_ix, storage); + BrotliWriteBits(nbits, tail - ((size_t)1 << nbits), storage_ix, storage); + ++histo[code]; + } else { + BrotliWriteBits(depth[61], bits[61], storage_ix, storage); + BrotliWriteBits(12, insertlen - 2114, storage_ix, storage); + ++histo[61]; + } +} + +static BROTLI_INLINE void EmitLongInsertLen(size_t insertlen, + const uint8_t depth[128], + const uint16_t bits[128], + uint32_t histo[128], + size_t* storage_ix, + uint8_t* storage) { + if (insertlen < 22594) { + BrotliWriteBits(depth[62], bits[62], storage_ix, storage); + BrotliWriteBits(14, insertlen - 6210, storage_ix, storage); + ++histo[62]; + } else { + BrotliWriteBits(depth[63], bits[63], storage_ix, storage); + BrotliWriteBits(24, insertlen - 22594, storage_ix, storage); + ++histo[63]; + } +} + +static BROTLI_INLINE void EmitCopyLen(size_t copylen, + const uint8_t depth[128], + const uint16_t bits[128], + uint32_t histo[128], + size_t* storage_ix, + uint8_t* storage) { + if (copylen < 10) { + BrotliWriteBits( + depth[copylen + 14], bits[copylen + 14], storage_ix, storage); + ++histo[copylen + 14]; + } else if (copylen < 134) { + const size_t tail = copylen - 6; + const uint32_t nbits = Log2FloorNonZero(tail) - 1u; + const size_t prefix = tail >> nbits; + const size_t code = (nbits << 1) + prefix + 20; + BrotliWriteBits(depth[code], bits[code], storage_ix, storage); + BrotliWriteBits(nbits, tail - (prefix << nbits), storage_ix, storage); + ++histo[code]; + } else if (copylen < 2118) { + const size_t tail = copylen - 70; + const uint32_t nbits = Log2FloorNonZero(tail); + const size_t code = nbits + 28; + BrotliWriteBits(depth[code], bits[code], storage_ix, storage); + BrotliWriteBits(nbits, tail - ((size_t)1 << nbits), storage_ix, storage); + ++histo[code]; + } else { + BrotliWriteBits(depth[39], bits[39], storage_ix, storage); + BrotliWriteBits(24, copylen - 2118, storage_ix, storage); + ++histo[39]; + } +} + +static BROTLI_INLINE void EmitCopyLenLastDistance(size_t copylen, + const uint8_t depth[128], + const uint16_t bits[128], + uint32_t histo[128], + size_t* storage_ix, + uint8_t* storage) { + if (copylen < 12) { + BrotliWriteBits(depth[copylen - 4], bits[copylen - 4], storage_ix, storage); + ++histo[copylen - 4]; + } else if (copylen < 72) { + const size_t tail = copylen - 8; + const uint32_t nbits = Log2FloorNonZero(tail) - 1; + const size_t prefix = tail >> nbits; + const size_t code = (nbits << 1) + prefix + 4; + BrotliWriteBits(depth[code], bits[code], storage_ix, storage); + BrotliWriteBits(nbits, tail - (prefix << nbits), storage_ix, storage); + ++histo[code]; + } else if (copylen < 136) { + const size_t tail = copylen - 8; + const size_t code = (tail >> 5) + 30; + BrotliWriteBits(depth[code], bits[code], storage_ix, storage); + BrotliWriteBits(5, tail & 31, storage_ix, storage); + BrotliWriteBits(depth[64], bits[64], storage_ix, storage); + ++histo[code]; + ++histo[64]; + } else if (copylen < 2120) { + const size_t tail = copylen - 72; + const uint32_t nbits = Log2FloorNonZero(tail); + const size_t code = nbits + 28; + BrotliWriteBits(depth[code], bits[code], storage_ix, storage); + BrotliWriteBits(nbits, tail - ((size_t)1 << nbits), storage_ix, storage); + BrotliWriteBits(depth[64], bits[64], storage_ix, storage); + ++histo[code]; + ++histo[64]; + } else { + BrotliWriteBits(depth[39], bits[39], storage_ix, storage); + BrotliWriteBits(24, copylen - 2120, storage_ix, storage); + BrotliWriteBits(depth[64], bits[64], storage_ix, storage); + ++histo[39]; + ++histo[64]; + } +} + +static BROTLI_INLINE void EmitDistance(size_t distance, + const uint8_t depth[128], + const uint16_t bits[128], + uint32_t histo[128], + size_t* storage_ix, uint8_t* storage) { + const size_t d = distance + 3; + const uint32_t nbits = Log2FloorNonZero(d) - 1u; + const size_t prefix = (d >> nbits) & 1; + const size_t offset = (2 + prefix) << nbits; + const size_t distcode = 2 * (nbits - 1) + prefix + 80; + BrotliWriteBits(depth[distcode], bits[distcode], storage_ix, storage); + BrotliWriteBits(nbits, d - offset, storage_ix, storage); + ++histo[distcode]; +} + +static BROTLI_INLINE void EmitLiterals(const uint8_t* input, const size_t len, + const uint8_t depth[256], + const uint16_t bits[256], + size_t* storage_ix, uint8_t* storage) { + size_t j; + for (j = 0; j < len; j++) { + const uint8_t lit = input[j]; + BrotliWriteBits(depth[lit], bits[lit], storage_ix, storage); + } +} + +/* REQUIRES: len <= 1 << 24. */ +static void BrotliStoreMetaBlockHeader( + size_t len, BROTLI_BOOL is_uncompressed, size_t* storage_ix, + uint8_t* storage) { + size_t nibbles = 6; + /* ISLAST */ + BrotliWriteBits(1, 0, storage_ix, storage); + if (len <= (1U << 16)) { + nibbles = 4; + } else if (len <= (1U << 20)) { + nibbles = 5; + } + BrotliWriteBits(2, nibbles - 4, storage_ix, storage); + BrotliWriteBits(nibbles * 4, len - 1, storage_ix, storage); + /* ISUNCOMPRESSED */ + BrotliWriteBits(1, (uint64_t)is_uncompressed, storage_ix, storage); +} + +static void UpdateBits(size_t n_bits, uint32_t bits, size_t pos, + uint8_t* array) { + while (n_bits > 0) { + size_t byte_pos = pos >> 3; + size_t n_unchanged_bits = pos & 7; + size_t n_changed_bits = BROTLI_MIN(size_t, n_bits, 8 - n_unchanged_bits); + size_t total_bits = n_unchanged_bits + n_changed_bits; + uint32_t mask = + (~((1u << total_bits) - 1u)) | ((1u << n_unchanged_bits) - 1u); + uint32_t unchanged_bits = array[byte_pos] & mask; + uint32_t changed_bits = bits & ((1u << n_changed_bits) - 1u); + array[byte_pos] = + (uint8_t)((changed_bits << n_unchanged_bits) | unchanged_bits); + n_bits -= n_changed_bits; + bits >>= n_changed_bits; + pos += n_changed_bits; + } +} + +static void RewindBitPosition(const size_t new_storage_ix, + size_t* storage_ix, uint8_t* storage) { + const size_t bitpos = new_storage_ix & 7; + const size_t mask = (1u << bitpos) - 1; + storage[new_storage_ix >> 3] &= (uint8_t)mask; + *storage_ix = new_storage_ix; +} + +static BROTLI_BOOL ShouldMergeBlock(BrotliOnePassArena* s, + const uint8_t* data, size_t len, const uint8_t* depths) { + uint32_t* BROTLI_RESTRICT const histo = s->histogram; + static const size_t kSampleRate = 43; + size_t i; + memset(histo, 0, sizeof(s->histogram)); + for (i = 0; i < len; i += kSampleRate) { + ++histo[data[i]]; + } + { + const size_t total = (len + kSampleRate - 1) / kSampleRate; + double r = (FastLog2(total) + 0.5) * (double)total + 200; + for (i = 0; i < 256; ++i) { + r -= (double)histo[i] * (depths[i] + FastLog2(histo[i])); + } + return TO_BROTLI_BOOL(r >= 0.0); + } +} + +/* Acceptable loss for uncompressible speedup is 2% */ +#define MIN_RATIO 980 + +static BROTLI_INLINE BROTLI_BOOL ShouldUseUncompressedMode( + const uint8_t* metablock_start, const uint8_t* next_emit, + const size_t insertlen, const size_t literal_ratio) { + const size_t compressed = (size_t)(next_emit - metablock_start); + if (compressed * 50 > insertlen) { + return BROTLI_FALSE; + } else { + return TO_BROTLI_BOOL(literal_ratio > MIN_RATIO); + } +} + +static void EmitUncompressedMetaBlock(const uint8_t* begin, const uint8_t* end, + const size_t storage_ix_start, + size_t* storage_ix, uint8_t* storage) { + const size_t len = (size_t)(end - begin); + RewindBitPosition(storage_ix_start, storage_ix, storage); + BrotliStoreMetaBlockHeader(len, 1, storage_ix, storage); + *storage_ix = (*storage_ix + 7u) & ~7u; + memcpy(&storage[*storage_ix >> 3], begin, len); + *storage_ix += len << 3; + storage[*storage_ix >> 3] = 0; +} + +static BROTLI_MODEL("small") uint32_t kCmdHistoSeed[128] = { + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 0, 0, 0, 0, +}; + +static BROTLI_INLINE void BrotliCompressFragmentFastImpl( + BrotliOnePassArena* s, const uint8_t* input, size_t input_size, + BROTLI_BOOL is_last, int* table, size_t table_bits, + size_t* storage_ix, uint8_t* storage) { + uint8_t* BROTLI_RESTRICT const cmd_depth = s->cmd_depth; + uint16_t* BROTLI_RESTRICT const cmd_bits = s->cmd_bits; + uint32_t* BROTLI_RESTRICT const cmd_histo = s->cmd_histo; + uint8_t* BROTLI_RESTRICT const lit_depth = s->lit_depth; + uint16_t* BROTLI_RESTRICT const lit_bits = s->lit_bits; + const uint8_t* ip_end; + + /* "next_emit" is a pointer to the first byte that is not covered by a + previous copy. Bytes between "next_emit" and the start of the next copy or + the end of the input will be emitted as literal bytes. */ + const uint8_t* next_emit = input; + /* Save the start of the first block for position and distance computations. + */ + const uint8_t* base_ip = input; + + static const size_t kFirstBlockSize = 3 << 15; + static const size_t kMergeBlockSize = 1 << 16; + + const size_t kInputMarginBytes = BROTLI_WINDOW_GAP; + const size_t kMinMatchLen = 5; + + const uint8_t* metablock_start = input; + size_t block_size = BROTLI_MIN(size_t, input_size, kFirstBlockSize); + size_t total_block_size = block_size; + /* Save the bit position of the MLEN field of the meta-block header, so that + we can update it later if we decide to extend this meta-block. */ + size_t mlen_storage_ix = *storage_ix + 3; + + size_t literal_ratio; + + const uint8_t* ip; + int last_distance; + + const size_t shift = 64u - table_bits; + + BrotliStoreMetaBlockHeader(block_size, 0, storage_ix, storage); + /* No block splits, no contexts. */ + BrotliWriteBits(13, 0, storage_ix, storage); + + literal_ratio = BuildAndStoreLiteralPrefixCode( + s, input, block_size, s->lit_depth, s->lit_bits, storage_ix, storage); + + { + /* Store the pre-compressed command and distance prefix codes. */ + size_t i; + for (i = 0; i + 7 < s->cmd_code_numbits; i += 8) { + BrotliWriteBits(8, s->cmd_code[i >> 3], storage_ix, storage); + } + } + BrotliWriteBits(s->cmd_code_numbits & 7, + s->cmd_code[s->cmd_code_numbits >> 3], storage_ix, storage); + + emit_commands: + /* Initialize the command and distance histograms. We will gather + statistics of command and distance codes during the processing + of this block and use it to update the command and distance + prefix codes for the next block. */ + memcpy(s->cmd_histo, kCmdHistoSeed, sizeof(kCmdHistoSeed)); + + /* "ip" is the input pointer. */ + ip = input; + last_distance = -1; + ip_end = input + block_size; + + if (BROTLI_PREDICT_TRUE(block_size >= kInputMarginBytes)) { + /* For the last block, we need to keep a 16 bytes margin so that we can be + sure that all distances are at most window size - 16. + For all other blocks, we only need to keep a margin of 5 bytes so that + we don't go over the block size with a copy. */ + const size_t len_limit = BROTLI_MIN(size_t, block_size - kMinMatchLen, + input_size - kInputMarginBytes); + const uint8_t* ip_limit = input + len_limit; + + uint32_t next_hash; + for (next_hash = Hash(++ip, shift); ; ) { + /* Step 1: Scan forward in the input looking for a 5-byte-long match. + If we get close to exhausting the input then goto emit_remainder. + + Heuristic match skipping: If 32 bytes are scanned with no matches + found, start looking only at every other byte. If 32 more bytes are + scanned, look at every third byte, etc.. When a match is found, + immediately go back to looking at every byte. This is a small loss + (~5% performance, ~0.1% density) for compressible data due to more + bookkeeping, but for non-compressible data (such as JPEG) it's a huge + win since the compressor quickly "realizes" the data is incompressible + and doesn't bother looking for matches everywhere. + + The "skip" variable keeps track of how many bytes there are since the + last match; dividing it by 32 (i.e. right-shifting by five) gives the + number of bytes to move ahead for each iteration. */ + uint32_t skip = 32; + + const uint8_t* next_ip = ip; + const uint8_t* candidate; + BROTLI_DCHECK(next_emit < ip); +trawl: + do { + uint32_t hash = next_hash; + uint32_t bytes_between_hash_lookups = skip++ >> 5; + BROTLI_DCHECK(hash == Hash(next_ip, shift)); + ip = next_ip; + next_ip = ip + bytes_between_hash_lookups; + if (BROTLI_PREDICT_FALSE(next_ip > ip_limit)) { + goto emit_remainder; + } + next_hash = Hash(next_ip, shift); + candidate = ip - last_distance; + if (IsMatch(ip, candidate)) { + if (BROTLI_PREDICT_TRUE(candidate < ip)) { + table[hash] = (int)(ip - base_ip); + break; + } + } + candidate = base_ip + table[hash]; + BROTLI_DCHECK(candidate >= base_ip); + BROTLI_DCHECK(candidate < ip); + + table[hash] = (int)(ip - base_ip); + } while (BROTLI_PREDICT_TRUE(!IsMatch(ip, candidate))); + + /* Check copy distance. If candidate is not feasible, continue search. + Checking is done outside of hot loop to reduce overhead. */ + if (ip - candidate > MAX_DISTANCE) goto trawl; + + /* Step 2: Emit the found match together with the literal bytes from + "next_emit" to the bit stream, and then see if we can find a next match + immediately afterwards. Repeat until we find no match for the input + without emitting some literal bytes. */ + + { + /* We have a 5-byte match at ip, and we need to emit bytes in + [next_emit, ip). */ + const uint8_t* base = ip; + size_t matched = 5 + FindMatchLengthWithLimit( + candidate + 5, ip + 5, (size_t)(ip_end - ip) - 5); + int distance = (int)(base - candidate); /* > 0 */ + size_t insert = (size_t)(base - next_emit); + ip += matched; + BROTLI_LOG(("[CompressFragment] pos = %d insert = %lu copy = %d\n", + (int)(next_emit - base_ip), (unsigned long)insert, 2)); + BROTLI_DCHECK(0 == memcmp(base, candidate, matched)); + if (BROTLI_PREDICT_TRUE(insert < 6210)) { + EmitInsertLen(insert, cmd_depth, cmd_bits, cmd_histo, + storage_ix, storage); + } else if (ShouldUseUncompressedMode(metablock_start, next_emit, insert, + literal_ratio)) { + EmitUncompressedMetaBlock(metablock_start, base, mlen_storage_ix - 3, + storage_ix, storage); + input_size -= (size_t)(base - input); + input = base; + next_emit = input; + goto next_block; + } else { + EmitLongInsertLen(insert, cmd_depth, cmd_bits, cmd_histo, + storage_ix, storage); + } + EmitLiterals(next_emit, insert, lit_depth, lit_bits, + storage_ix, storage); + if (distance == last_distance) { + BrotliWriteBits(cmd_depth[64], cmd_bits[64], storage_ix, storage); + ++cmd_histo[64]; + } else { + EmitDistance((size_t)distance, cmd_depth, cmd_bits, + cmd_histo, storage_ix, storage); + last_distance = distance; + } + EmitCopyLenLastDistance(matched, cmd_depth, cmd_bits, cmd_histo, + storage_ix, storage); + BROTLI_LOG(("[CompressFragment] pos = %d distance = %d\n" + "[CompressFragment] pos = %d insert = %d copy = %d\n" + "[CompressFragment] pos = %d distance = %d\n", + (int)(base - base_ip), (int)distance, + (int)(base - base_ip) + 2, 0, (int)matched - 2, + (int)(base - base_ip) + 2, (int)distance)); + + next_emit = ip; + if (BROTLI_PREDICT_FALSE(ip >= ip_limit)) { + goto emit_remainder; + } + /* We could immediately start working at ip now, but to improve + compression we first update "table" with the hashes of some positions + within the last copy. */ + { + uint64_t input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 3); + uint32_t prev_hash = HashBytesAtOffset(input_bytes, 0, shift); + uint32_t cur_hash = HashBytesAtOffset(input_bytes, 3, shift); + table[prev_hash] = (int)(ip - base_ip - 3); + prev_hash = HashBytesAtOffset(input_bytes, 1, shift); + table[prev_hash] = (int)(ip - base_ip - 2); + prev_hash = HashBytesAtOffset(input_bytes, 2, shift); + table[prev_hash] = (int)(ip - base_ip - 1); + + candidate = base_ip + table[cur_hash]; + table[cur_hash] = (int)(ip - base_ip); + } + } + + while (IsMatch(ip, candidate)) { + /* We have a 5-byte match at ip, and no need to emit any literal bytes + prior to ip. */ + const uint8_t* base = ip; + size_t matched = 5 + FindMatchLengthWithLimit( + candidate + 5, ip + 5, (size_t)(ip_end - ip) - 5); + if (ip - candidate > MAX_DISTANCE) break; + ip += matched; + last_distance = (int)(base - candidate); /* > 0 */ + BROTLI_DCHECK(0 == memcmp(base, candidate, matched)); + EmitCopyLen(matched, cmd_depth, cmd_bits, cmd_histo, + storage_ix, storage); + EmitDistance((size_t)last_distance, cmd_depth, cmd_bits, + cmd_histo, storage_ix, storage); + BROTLI_LOG(("[CompressFragment] pos = %d insert = %d copy = %d\n" + "[CompressFragment] pos = %d distance = %d\n", + (int)(base - base_ip), 0, (int)matched, + (int)(base - base_ip), (int)last_distance)); + + next_emit = ip; + if (BROTLI_PREDICT_FALSE(ip >= ip_limit)) { + goto emit_remainder; + } + /* We could immediately start working at ip now, but to improve + compression we first update "table" with the hashes of some positions + within the last copy. */ + { + uint64_t input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 3); + uint32_t prev_hash = HashBytesAtOffset(input_bytes, 0, shift); + uint32_t cur_hash = HashBytesAtOffset(input_bytes, 3, shift); + table[prev_hash] = (int)(ip - base_ip - 3); + prev_hash = HashBytesAtOffset(input_bytes, 1, shift); + table[prev_hash] = (int)(ip - base_ip - 2); + prev_hash = HashBytesAtOffset(input_bytes, 2, shift); + table[prev_hash] = (int)(ip - base_ip - 1); + + candidate = base_ip + table[cur_hash]; + table[cur_hash] = (int)(ip - base_ip); + } + } + + next_hash = Hash(++ip, shift); + } + } + + emit_remainder: + BROTLI_DCHECK(next_emit <= ip_end); + input += block_size; + input_size -= block_size; + block_size = BROTLI_MIN(size_t, input_size, kMergeBlockSize); + + /* Decide if we want to continue this meta-block instead of emitting the + last insert-only command. */ + if (input_size > 0 && + total_block_size + block_size <= (1 << 20) && + ShouldMergeBlock(s, input, block_size, lit_depth)) { + BROTLI_DCHECK(total_block_size > (1 << 16)); + /* Update the size of the current meta-block and continue emitting commands. + We can do this because the current size and the new size both have 5 + nibbles. */ + total_block_size += block_size; + UpdateBits(20, (uint32_t)(total_block_size - 1), mlen_storage_ix, storage); + goto emit_commands; + } + + /* Emit the remaining bytes as literals. */ + if (next_emit < ip_end) { + const size_t insert = (size_t)(ip_end - next_emit); + BROTLI_LOG(("[CompressFragment] pos = %d insert = %lu copy = %d\n", + (int)(next_emit - base_ip), (unsigned long)insert, 2)); + if (BROTLI_PREDICT_TRUE(insert < 6210)) { + EmitInsertLen(insert, cmd_depth, cmd_bits, cmd_histo, + storage_ix, storage); + EmitLiterals(next_emit, insert, lit_depth, lit_bits, storage_ix, storage); + } else if (ShouldUseUncompressedMode(metablock_start, next_emit, insert, + literal_ratio)) { + EmitUncompressedMetaBlock(metablock_start, ip_end, mlen_storage_ix - 3, + storage_ix, storage); + } else { + EmitLongInsertLen(insert, cmd_depth, cmd_bits, cmd_histo, + storage_ix, storage); + EmitLiterals(next_emit, insert, lit_depth, lit_bits, + storage_ix, storage); + } + } + next_emit = ip_end; + +next_block: + /* If we have more data, write a new meta-block header and prefix codes and + then continue emitting commands. */ + if (input_size > 0) { + metablock_start = input; + block_size = BROTLI_MIN(size_t, input_size, kFirstBlockSize); + total_block_size = block_size; + /* Save the bit position of the MLEN field of the meta-block header, so that + we can update it later if we decide to extend this meta-block. */ + mlen_storage_ix = *storage_ix + 3; + BrotliStoreMetaBlockHeader(block_size, 0, storage_ix, storage); + /* No block splits, no contexts. */ + BrotliWriteBits(13, 0, storage_ix, storage); + literal_ratio = BuildAndStoreLiteralPrefixCode( + s, input, block_size, lit_depth, lit_bits, storage_ix, storage); + BuildAndStoreCommandPrefixCode(s, storage_ix, storage); + goto emit_commands; + } + + if (!is_last) { + /* If this is not the last block, update the command and distance prefix + codes for the next block and store the compressed forms. */ + s->cmd_code[0] = 0; + s->cmd_code_numbits = 0; + BuildAndStoreCommandPrefixCode(s, &s->cmd_code_numbits, s->cmd_code); + } +} + +#define FOR_TABLE_BITS_(X) X(9) X(11) X(13) X(15) + +#define BAKE_METHOD_PARAM_(B) \ +static BROTLI_NOINLINE void BrotliCompressFragmentFastImpl ## B( \ + BrotliOnePassArena* s, const uint8_t* input, size_t input_size, \ + BROTLI_BOOL is_last, int* table, size_t* storage_ix, uint8_t* storage) { \ + BrotliCompressFragmentFastImpl(s, input, input_size, is_last, table, B, \ + storage_ix, storage); \ +} +FOR_TABLE_BITS_(BAKE_METHOD_PARAM_) +#undef BAKE_METHOD_PARAM_ + +void BrotliCompressFragmentFast( + BrotliOnePassArena* s, const uint8_t* input, size_t input_size, + BROTLI_BOOL is_last, int* table, size_t table_size, + size_t* storage_ix, uint8_t* storage) { + const size_t initial_storage_ix = *storage_ix; + const size_t table_bits = Log2FloorNonZero(table_size); + + if (input_size == 0) { + BROTLI_DCHECK(is_last); + BrotliWriteBits(1, 1, storage_ix, storage); /* islast */ + BrotliWriteBits(1, 1, storage_ix, storage); /* isempty */ + *storage_ix = (*storage_ix + 7u) & ~7u; + return; + } + + switch (table_bits) { +#define CASE_(B) \ + case B: \ + BrotliCompressFragmentFastImpl ## B( \ + s, input, input_size, is_last, table, storage_ix, storage);\ + break; + FOR_TABLE_BITS_(CASE_) +#undef CASE_ + default: BROTLI_DCHECK(0); break; + } + + /* If output is larger than single uncompressed block, rewrite it. */ + if (*storage_ix - initial_storage_ix > 31 + (input_size << 3)) { + EmitUncompressedMetaBlock(input, input + input_size, initial_storage_ix, + storage_ix, storage); + } + + if (is_last) { + BrotliWriteBits(1, 1, storage_ix, storage); /* islast */ + BrotliWriteBits(1, 1, storage_ix, storage); /* isempty */ + *storage_ix = (*storage_ix + 7u) & ~7u; + } +} + +#undef FOR_TABLE_BITS_ + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/compress_fragment.h b/packages/runtime/vendor/brotli/c/enc/compress_fragment.h new file mode 100644 index 000000000..462f366b3 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/compress_fragment.h @@ -0,0 +1,84 @@ +/* Copyright 2015 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Function for fast encoding of an input fragment, independently from the input + history. This function uses one-pass processing: when we find a backward + match, we immediately emit the corresponding command and literal codes to + the bit stream. */ + +#ifndef BROTLI_ENC_COMPRESS_FRAGMENT_H_ +#define BROTLI_ENC_COMPRESS_FRAGMENT_H_ + +#include "../common/constants.h" +#include "../common/platform.h" +#include "entropy_encode.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +typedef struct BrotliOnePassArena { + uint8_t lit_depth[256]; + uint16_t lit_bits[256]; + + /* Command and distance prefix codes (each 64 symbols, stored back-to-back) + used for the next block. The command prefix code is over a smaller alphabet + with the following 64 symbols: + 0 - 15: insert length code 0, copy length code 0 - 15, same distance + 16 - 39: insert length code 0, copy length code 0 - 23 + 40 - 63: insert length code 0 - 23, copy length code 0 + Note that symbols 16 and 40 represent the same code in the full alphabet, + but we do not use either of them. */ + uint8_t cmd_depth[128]; + uint16_t cmd_bits[128]; + uint32_t cmd_histo[128]; + + /* The compressed form of the command and distance prefix codes for the next + block. */ + uint8_t cmd_code[512]; + size_t cmd_code_numbits; + + HuffmanTree tree[2 * BROTLI_NUM_LITERAL_SYMBOLS + 1]; + uint32_t histogram[256]; + uint8_t tmp_depth[BROTLI_NUM_COMMAND_SYMBOLS]; + uint16_t tmp_bits[64]; +} BrotliOnePassArena; + +/* Compresses "input" string to the "*storage" buffer as one or more complete + meta-blocks, and updates the "*storage_ix" bit position. + + If "is_last" is 1, emits an additional empty last meta-block. + + "cmd_depth" and "cmd_bits" contain the command and distance prefix codes + (see comment in encode.h) used for the encoding of this input fragment. + If "is_last" is 0, they are updated to reflect the statistics + of this input fragment, to be used for the encoding of the next fragment. + + "*cmd_code_numbits" is the number of bits of the compressed representation + of the command and distance prefix codes, and "cmd_code" is an array of + at least "(*cmd_code_numbits + 7) >> 3" size that contains the compressed + command and distance prefix codes. If "is_last" is 0, these are also + updated to represent the updated "cmd_depth" and "cmd_bits". + + REQUIRES: "input_size" is greater than zero, or "is_last" is 1. + REQUIRES: "input_size" is less or equal to maximal metablock size (1 << 24). + REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero. + REQUIRES: "table_size" is an odd (9, 11, 13, 15) power of two + OUTPUT: maximal copy distance <= |input_size| + OUTPUT: maximal copy distance <= BROTLI_MAX_BACKWARD_LIMIT(18) */ +BROTLI_INTERNAL void BrotliCompressFragmentFast(BrotliOnePassArena* s, + const uint8_t* input, + size_t input_size, + BROTLI_BOOL is_last, + int* table, size_t table_size, + size_t* storage_ix, + uint8_t* storage); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_COMPRESS_FRAGMENT_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/compress_fragment_two_pass.c b/packages/runtime/vendor/brotli/c/enc/compress_fragment_two_pass.c new file mode 100644 index 000000000..01e4794d8 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/compress_fragment_two_pass.c @@ -0,0 +1,647 @@ +/* Copyright 2015 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Function for fast encoding of an input fragment, independently from the input + history. This function uses two-pass processing: in the first pass we save + the found backward matches and literal bytes into a buffer, and in the + second pass we emit them into the bit stream using prefix codes built based + on the actual command and literal byte histograms. */ + +#include "compress_fragment_two_pass.h" + +#include "../common/constants.h" +#include "../common/platform.h" +#include "bit_cost.h" +#include "brotli_bit_stream.h" +#include "entropy_encode.h" +#include "fast_log.h" +#include "find_match_length.h" +#include "hash_base.h" +#include "write_bits.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define MAX_DISTANCE (long)BROTLI_MAX_BACKWARD_LIMIT(18) + +static BROTLI_INLINE uint32_t Hash(const uint8_t* p, + size_t shift, size_t length) { + const uint64_t h = + (BROTLI_UNALIGNED_LOAD64LE(p) << ((8 - length) * 8)) * kHashMul32; + return (uint32_t)(h >> shift); +} + +static BROTLI_INLINE uint32_t HashBytesAtOffset(uint64_t v, size_t offset, + size_t shift, size_t length) { + BROTLI_DCHECK(offset <= 8 - length); + { + const uint64_t h = ((v >> (8 * offset)) << ((8 - length) * 8)) * kHashMul32; + return (uint32_t)(h >> shift); + } +} + +static BROTLI_INLINE BROTLI_BOOL IsMatch(const uint8_t* p1, const uint8_t* p2, + size_t length) { + if (BrotliUnalignedRead32(p1) == BrotliUnalignedRead32(p2)) { + if (length == 4) return BROTLI_TRUE; + return TO_BROTLI_BOOL(p1[4] == p2[4] && p1[5] == p2[5]); + } + return BROTLI_FALSE; +} + +/* Builds a command and distance prefix code (each 64 symbols) into "depth" and + "bits" based on "histogram" and stores it into the bit stream. */ +static void BuildAndStoreCommandPrefixCode(BrotliTwoPassArena* s, + size_t* storage_ix, + uint8_t* storage) { + /* Tree size for building a tree over 64 symbols is 2 * 64 + 1. */ + /* TODO(eustas): initialize once. */ + memset(s->tmp_depth, 0, sizeof(s->tmp_depth)); + BrotliCreateHuffmanTree(s->cmd_histo, 64, 15, s->tmp_tree, s->cmd_depth); + BrotliCreateHuffmanTree(&s->cmd_histo[64], 64, 14, s->tmp_tree, + &s->cmd_depth[64]); + /* We have to jump through a few hoops here in order to compute + the command bits because the symbols are in a different order than in + the full alphabet. This looks complicated, but having the symbols + in this order in the command bits saves a few branches in the Emit* + functions. */ + memcpy(s->tmp_depth, s->cmd_depth + 24, 24); + memcpy(s->tmp_depth + 24, s->cmd_depth, 8); + memcpy(s->tmp_depth + 32, s->cmd_depth + 48, 8); + memcpy(s->tmp_depth + 40, s->cmd_depth + 8, 8); + memcpy(s->tmp_depth + 48, s->cmd_depth + 56, 8); + memcpy(s->tmp_depth + 56, s->cmd_depth + 16, 8); + BrotliConvertBitDepthsToSymbols(s->tmp_depth, 64, s->tmp_bits); + memcpy(s->cmd_bits, s->tmp_bits + 24, 16); + memcpy(s->cmd_bits + 8, s->tmp_bits + 40, 16); + memcpy(s->cmd_bits + 16, s->tmp_bits + 56, 16); + memcpy(s->cmd_bits + 24, s->tmp_bits, 48); + memcpy(s->cmd_bits + 48, s->tmp_bits + 32, 16); + memcpy(s->cmd_bits + 56, s->tmp_bits + 48, 16); + BrotliConvertBitDepthsToSymbols(&s->cmd_depth[64], 64, &s->cmd_bits[64]); + { + /* Create the bit length array for the full command alphabet. */ + size_t i; + memset(s->tmp_depth, 0, 64); /* only 64 first values were used */ + memcpy(s->tmp_depth, s->cmd_depth + 24, 8); + memcpy(s->tmp_depth + 64, s->cmd_depth + 32, 8); + memcpy(s->tmp_depth + 128, s->cmd_depth + 40, 8); + memcpy(s->tmp_depth + 192, s->cmd_depth + 48, 8); + memcpy(s->tmp_depth + 384, s->cmd_depth + 56, 8); + for (i = 0; i < 8; ++i) { + s->tmp_depth[128 + 8 * i] = s->cmd_depth[i]; + s->tmp_depth[256 + 8 * i] = s->cmd_depth[8 + i]; + s->tmp_depth[448 + 8 * i] = s->cmd_depth[16 + i]; + } + BrotliStoreHuffmanTree(s->tmp_depth, BROTLI_NUM_COMMAND_SYMBOLS, + s->tmp_tree, storage_ix, storage); + } + BrotliStoreHuffmanTree(&s->cmd_depth[64], 64, s->tmp_tree, storage_ix, + storage); +} + +static BROTLI_INLINE void EmitInsertLen( + uint32_t insertlen, uint32_t** commands) { + if (insertlen < 6) { + **commands = insertlen; + } else if (insertlen < 130) { + const uint32_t tail = insertlen - 2; + const uint32_t nbits = Log2FloorNonZero(tail) - 1u; + const uint32_t prefix = tail >> nbits; + const uint32_t inscode = (nbits << 1) + prefix + 2; + const uint32_t extra = tail - (prefix << nbits); + **commands = inscode | (extra << 8); + } else if (insertlen < 2114) { + const uint32_t tail = insertlen - 66; + const uint32_t nbits = Log2FloorNonZero(tail); + const uint32_t code = nbits + 10; + const uint32_t extra = tail - (1u << nbits); + **commands = code | (extra << 8); + } else if (insertlen < 6210) { + const uint32_t extra = insertlen - 2114; + **commands = 21 | (extra << 8); + } else if (insertlen < 22594) { + const uint32_t extra = insertlen - 6210; + **commands = 22 | (extra << 8); + } else { + const uint32_t extra = insertlen - 22594; + **commands = 23 | (extra << 8); + } + ++(*commands); +} + +static BROTLI_INLINE void EmitCopyLen(size_t copylen, uint32_t** commands) { + if (copylen < 10) { + **commands = (uint32_t)(copylen + 38); + } else if (copylen < 134) { + const size_t tail = copylen - 6; + const size_t nbits = Log2FloorNonZero(tail) - 1; + const size_t prefix = tail >> nbits; + const size_t code = (nbits << 1) + prefix + 44; + const size_t extra = tail - (prefix << nbits); + **commands = (uint32_t)(code | (extra << 8)); + } else if (copylen < 2118) { + const size_t tail = copylen - 70; + const size_t nbits = Log2FloorNonZero(tail); + const size_t code = nbits + 52; + const size_t extra = tail - ((size_t)1 << nbits); + **commands = (uint32_t)(code | (extra << 8)); + } else { + const size_t extra = copylen - 2118; + **commands = (uint32_t)(63 | (extra << 8)); + } + ++(*commands); +} + +static BROTLI_INLINE void EmitCopyLenLastDistance( + size_t copylen, uint32_t** commands) { + if (copylen < 12) { + **commands = (uint32_t)(copylen + 20); + ++(*commands); + } else if (copylen < 72) { + const size_t tail = copylen - 8; + const size_t nbits = Log2FloorNonZero(tail) - 1; + const size_t prefix = tail >> nbits; + const size_t code = (nbits << 1) + prefix + 28; + const size_t extra = tail - (prefix << nbits); + **commands = (uint32_t)(code | (extra << 8)); + ++(*commands); + } else if (copylen < 136) { + const size_t tail = copylen - 8; + const size_t code = (tail >> 5) + 54; + const size_t extra = tail & 31; + **commands = (uint32_t)(code | (extra << 8)); + ++(*commands); + **commands = 64; + ++(*commands); + } else if (copylen < 2120) { + const size_t tail = copylen - 72; + const size_t nbits = Log2FloorNonZero(tail); + const size_t code = nbits + 52; + const size_t extra = tail - ((size_t)1 << nbits); + **commands = (uint32_t)(code | (extra << 8)); + ++(*commands); + **commands = 64; + ++(*commands); + } else { + const size_t extra = copylen - 2120; + **commands = (uint32_t)(63 | (extra << 8)); + ++(*commands); + **commands = 64; + ++(*commands); + } +} + +static BROTLI_INLINE void EmitDistance(uint32_t distance, uint32_t** commands) { + uint32_t d = distance + 3; + uint32_t nbits = Log2FloorNonZero(d) - 1; + const uint32_t prefix = (d >> nbits) & 1; + const uint32_t offset = (2 + prefix) << nbits; + const uint32_t distcode = 2 * (nbits - 1) + prefix + 80; + uint32_t extra = d - offset; + **commands = distcode | (extra << 8); + ++(*commands); +} + +/* REQUIRES: len <= 1 << 24. */ +static void BrotliStoreMetaBlockHeader( + size_t len, BROTLI_BOOL is_uncompressed, size_t* storage_ix, + uint8_t* storage) { + size_t nibbles = 6; + /* ISLAST */ + BrotliWriteBits(1, 0, storage_ix, storage); + if (len <= (1U << 16)) { + nibbles = 4; + } else if (len <= (1U << 20)) { + nibbles = 5; + } + BrotliWriteBits(2, nibbles - 4, storage_ix, storage); + BrotliWriteBits(nibbles * 4, len - 1, storage_ix, storage); + /* ISUNCOMPRESSED */ + BrotliWriteBits(1, (uint64_t)is_uncompressed, storage_ix, storage); +} + +static BROTLI_INLINE void CreateCommands(const uint8_t* input, + size_t block_size, size_t input_size, const uint8_t* base_ip, int* table, + size_t table_bits, size_t min_match, + uint8_t** literals, uint32_t** commands) { + /* "ip" is the input pointer. */ + const uint8_t* ip = input; + const size_t shift = 64u - table_bits; + const uint8_t* ip_end = input + block_size; + /* "next_emit" is a pointer to the first byte that is not covered by a + previous copy. Bytes between "next_emit" and the start of the next copy or + the end of the input will be emitted as literal bytes. */ + const uint8_t* next_emit = input; + + int last_distance = -1; + const size_t kInputMarginBytes = BROTLI_WINDOW_GAP; + + if (BROTLI_PREDICT_TRUE(block_size >= kInputMarginBytes)) { + /* For the last block, we need to keep a 16 bytes margin so that we can be + sure that all distances are at most window size - 16. + For all other blocks, we only need to keep a margin of 5 bytes so that + we don't go over the block size with a copy. */ + const size_t len_limit = BROTLI_MIN(size_t, block_size - min_match, + input_size - kInputMarginBytes); + const uint8_t* ip_limit = input + len_limit; + + uint32_t next_hash; + for (next_hash = Hash(++ip, shift, min_match); ; ) { + /* Step 1: Scan forward in the input looking for a 6-byte-long match. + If we get close to exhausting the input then goto emit_remainder. + + Heuristic match skipping: If 32 bytes are scanned with no matches + found, start looking only at every other byte. If 32 more bytes are + scanned, look at every third byte, etc.. When a match is found, + immediately go back to looking at every byte. This is a small loss + (~5% performance, ~0.1% density) for compressible data due to more + bookkeeping, but for non-compressible data (such as JPEG) it's a huge + win since the compressor quickly "realizes" the data is incompressible + and doesn't bother looking for matches everywhere. + + The "skip" variable keeps track of how many bytes there are since the + last match; dividing it by 32 (ie. right-shifting by five) gives the + number of bytes to move ahead for each iteration. */ + uint32_t skip = 32; + + const uint8_t* next_ip = ip; + const uint8_t* candidate; + + BROTLI_DCHECK(next_emit < ip); +trawl: + do { + uint32_t hash = next_hash; + uint32_t bytes_between_hash_lookups = skip++ >> 5; + ip = next_ip; + BROTLI_DCHECK(hash == Hash(ip, shift, min_match)); + next_ip = ip + bytes_between_hash_lookups; + if (BROTLI_PREDICT_FALSE(next_ip > ip_limit)) { + goto emit_remainder; + } + next_hash = Hash(next_ip, shift, min_match); + candidate = ip - last_distance; + if (IsMatch(ip, candidate, min_match)) { + if (BROTLI_PREDICT_TRUE(candidate < ip)) { + table[hash] = (int)(ip - base_ip); + break; + } + } + candidate = base_ip + table[hash]; + BROTLI_DCHECK(candidate >= base_ip); + BROTLI_DCHECK(candidate < ip); + + table[hash] = (int)(ip - base_ip); + } while (BROTLI_PREDICT_TRUE(!IsMatch(ip, candidate, min_match))); + + /* Check copy distance. If candidate is not feasible, continue search. + Checking is done outside of hot loop to reduce overhead. */ + if (ip - candidate > MAX_DISTANCE) goto trawl; + + /* Step 2: Emit the found match together with the literal bytes from + "next_emit", and then see if we can find a next match immediately + afterwards. Repeat until we find no match for the input + without emitting some literal bytes. */ + + { + /* We have a 6-byte match at ip, and we need to emit bytes in + [next_emit, ip). */ + const uint8_t* base = ip; + size_t matched = min_match + FindMatchLengthWithLimit( + candidate + min_match, ip + min_match, + (size_t)(ip_end - ip) - min_match); + int distance = (int)(base - candidate); /* > 0 */ + int insert = (int)(base - next_emit); + ip += matched; + BROTLI_DCHECK(0 == memcmp(base, candidate, matched)); + EmitInsertLen((uint32_t)insert, commands); + BROTLI_LOG(("[CompressFragment] pos = %d insert = %d copy = %d\n", + (int)(next_emit - base_ip), insert, 2)); + memcpy(*literals, next_emit, (size_t)insert); + *literals += insert; + if (distance == last_distance) { + **commands = 64; + ++(*commands); + } else { + EmitDistance((uint32_t)distance, commands); + last_distance = distance; + } + EmitCopyLenLastDistance(matched, commands); + BROTLI_LOG(("[CompressFragment] pos = %d distance = %d\n" + "[CompressFragment] pos = %d insert = %d copy = %d\n" + "[CompressFragment] pos = %d distance = %d\n", + (int)(base - base_ip), (int)distance, + (int)(base - base_ip) + 2, 0, (int)matched - 2, + (int)(base - base_ip) + 2, (int)distance)); + + next_emit = ip; + if (BROTLI_PREDICT_FALSE(ip >= ip_limit)) { + goto emit_remainder; + } + { + /* We could immediately start working at ip now, but to improve + compression we first update "table" with the hashes of some + positions within the last copy. */ + uint64_t input_bytes; + uint32_t cur_hash; + uint32_t prev_hash; + if (min_match == 4) { + input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 3); + cur_hash = HashBytesAtOffset(input_bytes, 3, shift, min_match); + prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match); + table[prev_hash] = (int)(ip - base_ip - 3); + prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match); + table[prev_hash] = (int)(ip - base_ip - 2); + prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match); + table[prev_hash] = (int)(ip - base_ip - 1); + } else { + input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 5); + prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match); + table[prev_hash] = (int)(ip - base_ip - 5); + prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match); + table[prev_hash] = (int)(ip - base_ip - 4); + prev_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match); + table[prev_hash] = (int)(ip - base_ip - 3); + input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 2); + cur_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match); + prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match); + table[prev_hash] = (int)(ip - base_ip - 2); + prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match); + table[prev_hash] = (int)(ip - base_ip - 1); + } + + candidate = base_ip + table[cur_hash]; + table[cur_hash] = (int)(ip - base_ip); + } + } + + while (ip - candidate <= MAX_DISTANCE && + IsMatch(ip, candidate, min_match)) { + /* We have a 6-byte match at ip, and no need to emit any + literal bytes prior to ip. */ + const uint8_t* base = ip; + size_t matched = min_match + FindMatchLengthWithLimit( + candidate + min_match, ip + min_match, + (size_t)(ip_end - ip) - min_match); + ip += matched; + last_distance = (int)(base - candidate); /* > 0 */ + BROTLI_DCHECK(0 == memcmp(base, candidate, matched)); + EmitCopyLen(matched, commands); + EmitDistance((uint32_t)last_distance, commands); + BROTLI_LOG(("[CompressFragment] pos = %d insert = %d copy = %d\n" + "[CompressFragment] pos = %d distance = %d\n", + (int)(base - base_ip), 0, (int)matched, + (int)(base - base_ip), (int)last_distance)); + + next_emit = ip; + if (BROTLI_PREDICT_FALSE(ip >= ip_limit)) { + goto emit_remainder; + } + { + /* We could immediately start working at ip now, but to improve + compression we first update "table" with the hashes of some + positions within the last copy. */ + uint64_t input_bytes; + uint32_t cur_hash; + uint32_t prev_hash; + if (min_match == 4) { + input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 3); + cur_hash = HashBytesAtOffset(input_bytes, 3, shift, min_match); + prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match); + table[prev_hash] = (int)(ip - base_ip - 3); + prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match); + table[prev_hash] = (int)(ip - base_ip - 2); + prev_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match); + table[prev_hash] = (int)(ip - base_ip - 1); + } else { + input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 5); + prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match); + table[prev_hash] = (int)(ip - base_ip - 5); + prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match); + table[prev_hash] = (int)(ip - base_ip - 4); + prev_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match); + table[prev_hash] = (int)(ip - base_ip - 3); + input_bytes = BROTLI_UNALIGNED_LOAD64LE(ip - 2); + cur_hash = HashBytesAtOffset(input_bytes, 2, shift, min_match); + prev_hash = HashBytesAtOffset(input_bytes, 0, shift, min_match); + table[prev_hash] = (int)(ip - base_ip - 2); + prev_hash = HashBytesAtOffset(input_bytes, 1, shift, min_match); + table[prev_hash] = (int)(ip - base_ip - 1); + } + + candidate = base_ip + table[cur_hash]; + table[cur_hash] = (int)(ip - base_ip); + } + } + + next_hash = Hash(++ip, shift, min_match); + } + } + +emit_remainder: + BROTLI_DCHECK(next_emit <= ip_end); + /* Emit the remaining bytes as literals. */ + if (next_emit < ip_end) { + const uint32_t insert = (uint32_t)(ip_end - next_emit); + EmitInsertLen(insert, commands); + BROTLI_LOG(("[CompressFragment] pos = %d insert = %d copy = %d\n", + (int)(next_emit - base_ip), insert, 2)); + memcpy(*literals, next_emit, insert); + *literals += insert; + } +} + +static void StoreCommands(BrotliTwoPassArena* s, + const uint8_t* literals, const size_t num_literals, + const uint32_t* commands, const size_t num_commands, + size_t* storage_ix, uint8_t* storage) { + static const BROTLI_MODEL("small") uint32_t kNumExtraBits[128] = { + 0, 0, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, + 6, 7, 8, 9, 10, 12, 14, 24, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 2, 2, 3, 3, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 7, 8, 9, 10, 24, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, + 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, + 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23, 24, 24, + }; + static const BROTLI_MODEL("small") uint32_t kInsertOffset[24] = { + 0, 1, 2, 3, 4, 5, 6, 8, 10, 14, 18, 26, + 34, 50, 66, 98, 130, 194, 322, 578, 1090, 2114, 6210, 22594, + }; + + size_t i; + memset(s->lit_histo, 0, sizeof(s->lit_histo)); + /* TODO(eustas): is that necessary? */ + memset(s->cmd_depth, 0, sizeof(s->cmd_depth)); + /* TODO(eustas): is that necessary? */ + memset(s->cmd_bits, 0, sizeof(s->cmd_bits)); + memset(s->cmd_histo, 0, sizeof(s->cmd_histo)); + for (i = 0; i < num_literals; ++i) { + ++s->lit_histo[literals[i]]; + } + BrotliBuildAndStoreHuffmanTreeFast(s->tmp_tree, s->lit_histo, num_literals, + /* max_bits = */ 8, s->lit_depth, + s->lit_bits, storage_ix, storage); + + for (i = 0; i < num_commands; ++i) { + const uint32_t code = commands[i] & 0xFF; + BROTLI_DCHECK(code < 128); + ++s->cmd_histo[code]; + } + s->cmd_histo[1] += 1; + s->cmd_histo[2] += 1; + s->cmd_histo[64] += 1; + s->cmd_histo[84] += 1; + BuildAndStoreCommandPrefixCode(s, storage_ix, storage); + + for (i = 0; i < num_commands; ++i) { + const uint32_t cmd = commands[i]; + const uint32_t code = cmd & 0xFF; + const uint32_t extra = cmd >> 8; + BROTLI_DCHECK(code < 128); + BrotliWriteBits(s->cmd_depth[code], s->cmd_bits[code], storage_ix, storage); + BrotliWriteBits(kNumExtraBits[code], extra, storage_ix, storage); + if (code < 24) { + const uint32_t insert = kInsertOffset[code] + extra; + uint32_t j; + for (j = 0; j < insert; ++j) { + const uint8_t lit = *literals; + BrotliWriteBits(s->lit_depth[lit], s->lit_bits[lit], storage_ix, + storage); + ++literals; + } + } + } +} + +/* Acceptable loss for uncompressible speedup is 2% */ +#define MIN_RATIO 0.98 +#define SAMPLE_RATE 43 + +static BROTLI_BOOL ShouldCompress(BrotliTwoPassArena* s, + const uint8_t* input, size_t input_size, size_t num_literals) { + double corpus_size = (double)input_size; + if ((double)num_literals < MIN_RATIO * corpus_size) { + return BROTLI_TRUE; + } else { + const double max_total_bit_cost = corpus_size * 8 * MIN_RATIO / SAMPLE_RATE; + size_t i; + memset(s->lit_histo, 0, sizeof(s->lit_histo)); + for (i = 0; i < input_size; i += SAMPLE_RATE) { + ++s->lit_histo[input[i]]; + } + return TO_BROTLI_BOOL( + BrotliBitsEntropy(s->lit_histo, 256) < max_total_bit_cost); + } +} + +static void RewindBitPosition(const size_t new_storage_ix, + size_t* storage_ix, uint8_t* storage) { + const size_t bitpos = new_storage_ix & 7; + const size_t mask = (1u << bitpos) - 1; + storage[new_storage_ix >> 3] &= (uint8_t)mask; + *storage_ix = new_storage_ix; +} + +static void EmitUncompressedMetaBlock(const uint8_t* input, size_t input_size, + size_t* storage_ix, uint8_t* storage) { + BrotliStoreMetaBlockHeader(input_size, 1, storage_ix, storage); + *storage_ix = (*storage_ix + 7u) & ~7u; + memcpy(&storage[*storage_ix >> 3], input, input_size); + *storage_ix += input_size << 3; + storage[*storage_ix >> 3] = 0; +} + +static BROTLI_INLINE void BrotliCompressFragmentTwoPassImpl( + BrotliTwoPassArena* s, const uint8_t* input, size_t input_size, + BROTLI_BOOL is_last, uint32_t* command_buf, uint8_t* literal_buf, + int* table, size_t table_bits, size_t min_match, + size_t* storage_ix, uint8_t* storage) { + /* Save the start of the first block for position and distance computations. + */ + const uint8_t* base_ip = input; + BROTLI_UNUSED(is_last); + + while (input_size > 0) { + size_t block_size = + BROTLI_MIN(size_t, input_size, kCompressFragmentTwoPassBlockSize); + uint32_t* commands = command_buf; + uint8_t* literals = literal_buf; + size_t num_literals; + CreateCommands(input, block_size, input_size, base_ip, table, + table_bits, min_match, &literals, &commands); + num_literals = (size_t)(literals - literal_buf); + if (ShouldCompress(s, input, block_size, num_literals)) { + const size_t num_commands = (size_t)(commands - command_buf); + BrotliStoreMetaBlockHeader(block_size, 0, storage_ix, storage); + /* No block splits, no contexts. */ + BrotliWriteBits(13, 0, storage_ix, storage); + StoreCommands(s, literal_buf, num_literals, command_buf, num_commands, + storage_ix, storage); + } else { + /* Since we did not find many backward references and the entropy of + the data is close to 8 bits, we can simply emit an uncompressed block. + This makes compression speed of uncompressible data about 3x faster. */ + EmitUncompressedMetaBlock(input, block_size, storage_ix, storage); + } + input += block_size; + input_size -= block_size; + } +} + +#define FOR_TABLE_BITS_(X) \ + X(8) X(9) X(10) X(11) X(12) X(13) X(14) X(15) X(16) X(17) + +#define BAKE_METHOD_PARAM_(B) \ +static BROTLI_NOINLINE void BrotliCompressFragmentTwoPassImpl ## B( \ + BrotliTwoPassArena* s, const uint8_t* input, size_t input_size, \ + BROTLI_BOOL is_last, uint32_t* command_buf, uint8_t* literal_buf, \ + int* table, size_t* storage_ix, uint8_t* storage) { \ + size_t min_match = (B <= 15) ? 4 : 6; \ + BrotliCompressFragmentTwoPassImpl(s, input, input_size, is_last, command_buf,\ + literal_buf, table, B, min_match, storage_ix, storage); \ +} +FOR_TABLE_BITS_(BAKE_METHOD_PARAM_) +#undef BAKE_METHOD_PARAM_ + +void BrotliCompressFragmentTwoPass( + BrotliTwoPassArena* s, const uint8_t* input, size_t input_size, + BROTLI_BOOL is_last, uint32_t* command_buf, uint8_t* literal_buf, + int* table, size_t table_size, size_t* storage_ix, uint8_t* storage) { + const size_t initial_storage_ix = *storage_ix; + const size_t table_bits = Log2FloorNonZero(table_size); + switch (table_bits) { +#define CASE_(B) \ + case B: \ + BrotliCompressFragmentTwoPassImpl ## B( \ + s, input, input_size, is_last, command_buf, \ + literal_buf, table, storage_ix, storage); \ + break; + FOR_TABLE_BITS_(CASE_) +#undef CASE_ + default: BROTLI_DCHECK(0); break; + } + + /* If output is larger than single uncompressed block, rewrite it. */ + if (*storage_ix - initial_storage_ix > 31 + (input_size << 3)) { + RewindBitPosition(initial_storage_ix, storage_ix, storage); + EmitUncompressedMetaBlock(input, input_size, storage_ix, storage); + } + + if (is_last) { + BrotliWriteBits(1, 1, storage_ix, storage); /* islast */ + BrotliWriteBits(1, 1, storage_ix, storage); /* isempty */ + *storage_ix = (*storage_ix + 7u) & ~7u; + } +} + +#undef FOR_TABLE_BITS_ + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/compress_fragment_two_pass.h b/packages/runtime/vendor/brotli/c/enc/compress_fragment_two_pass.h new file mode 100644 index 000000000..e98b5e0e2 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/compress_fragment_two_pass.h @@ -0,0 +1,70 @@ +/* Copyright 2015 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Function for fast encoding of an input fragment, independently from the input + history. This function uses two-pass processing: in the first pass we save + the found backward matches and literal bytes into a buffer, and in the + second pass we emit them into the bit stream using prefix codes built based + on the actual command and literal byte histograms. */ + +#ifndef BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_ +#define BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_ + +#include "../common/constants.h" +#include "../common/platform.h" +#include "entropy_encode.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* TODO(eustas): turn to macro. */ +static const size_t kCompressFragmentTwoPassBlockSize = 1 << 17; + +typedef struct BrotliTwoPassArena { + uint32_t lit_histo[256]; + uint8_t lit_depth[256]; + uint16_t lit_bits[256]; + + uint32_t cmd_histo[128]; + uint8_t cmd_depth[128]; + uint16_t cmd_bits[128]; + + /* BuildAndStoreCommandPrefixCode */ + HuffmanTree tmp_tree[2 * BROTLI_NUM_LITERAL_SYMBOLS + 1]; + uint8_t tmp_depth[BROTLI_NUM_COMMAND_SYMBOLS]; + uint16_t tmp_bits[64]; +} BrotliTwoPassArena; + +/* Compresses "input" string to the "*storage" buffer as one or more complete + meta-blocks, and updates the "*storage_ix" bit position. + + If "is_last" is 1, emits an additional empty last meta-block. + + REQUIRES: "input_size" is greater than zero, or "is_last" is 1. + REQUIRES: "input_size" is less or equal to maximal metablock size (1 << 24). + REQUIRES: "command_buf" and "literal_buf" point to at least + kCompressFragmentTwoPassBlockSize long arrays. + REQUIRES: All elements in "table[0..table_size-1]" are initialized to zero. + REQUIRES: "table_size" is a power of two + OUTPUT: maximal copy distance <= |input_size| + OUTPUT: maximal copy distance <= BROTLI_MAX_BACKWARD_LIMIT(18) */ +BROTLI_INTERNAL void BrotliCompressFragmentTwoPass(BrotliTwoPassArena* s, + const uint8_t* input, + size_t input_size, + BROTLI_BOOL is_last, + uint32_t* command_buf, + uint8_t* literal_buf, + int* table, + size_t table_size, + size_t* storage_ix, + uint8_t* storage); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_COMPRESS_FRAGMENT_TWO_PASS_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/dictionary_hash.c b/packages/runtime/vendor/brotli/c/enc/dictionary_hash.c new file mode 100644 index 000000000..193f7a41c --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/dictionary_hash.c @@ -0,0 +1,145 @@ +/* Copyright 2015 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Hash table on the 4-byte prefixes of static dictionary words. */ + +#include "dictionary_hash.h" + +#include "../common/platform.h" /* IWYU pragma: keep */ +#include "../common/static_init.h" + +#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE) +#include "../common/dictionary.h" +#include "hash_base.h" +#endif + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE) +BROTLI_BOOL BROTLI_COLD BrotliEncoderInitDictionaryHash( + const BrotliDictionary* dict, uint16_t* words, uint8_t* lengths) { + size_t global_idx = 0; + size_t len; + size_t i; + static const uint8_t frozen_idx[1688] = {0, 0, 8, 164, 32, 56, 31, 191, 36, 4, +128, 81, 68, 132, 145, 129, 0, 0, 0, 28, 0, 8, 1, 1, 64, 3, 1, 0, 0, 0, 0, 0, 4, +64, 1, 2, 128, 0, 132, 49, 0, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 1, 0, 36, 152, +0, 0, 0, 0, 128, 8, 0, 0, 128, 0, 0, 8, 0, 0, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, +0, 0, 0, 1, 0, 64, 133, 0, 32, 0, 0, 128, 1, 0, 0, 0, 0, 4, 4, 4, 32, 16, 130, +0, 128, 8, 0, 0, 0, 0, 0, 64, 0, 64, 0, 160, 0, 148, 53, 0, 0, 0, 0, 0, 128, 0, +130, 0, 0, 0, 8, 0, 0, 0, 0, 0, 48, 0, 0, 0, 0, 0, 0, 32, 1, 32, 129, 0, 12, 0, +1, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 16, 32, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 8, +0, 0, 2, 0, 0, 0, 0, 0, 32, 0, 0, 0, 2, 66, 128, 0, 0, 16, 0, 0, 0, 0, 64, 1, 6, +128, 8, 0, 192, 24, 32, 0, 0, 8, 4, 128, 128, 2, 160, 0, 160, 0, 64, 0, 0, 2, 0, +0, 0, 0, 0, 0, 0, 0, 0, 32, 1, 0, 0, 64, 0, 0, 0, 0, 0, 0, 32, 0, 66, 0, 2, 0, +4, 0, 8, 0, 2, 0, 0, 33, 8, 0, 0, 0, 8, 0, 128, 162, 4, 128, 0, 2, 33, 0, 160, +0, 8, 0, 64, 0, 160, 0, 129, 4, 0, 0, 32, 0, 0, 32, 0, 2, 0, 0, 0, 0, 0, 0, 128, +0, 0, 0, 0, 0, 64, 10, 0, 0, 0, 0, 32, 64, 0, 0, 0, 0, 0, 16, 0, 16, 16, 0, 0, +80, 2, 0, 0, 0, 0, 8, 0, 0, 16, 0, 8, 0, 0, 0, 8, 64, 128, 0, 0, 0, 8, 208, 0, +0, 0, 0, 0, 0, 0, 32, 0, 0, 0, 0, 0, 0, 32, 0, 8, 0, 128, 0, 0, 0, 1, 0, 0, 0, +16, 8, 1, 136, 0, 0, 36, 0, 64, 9, 0, 1, 32, 8, 0, 64, 64, 131, 16, 224, 32, 4, +0, 4, 5, 160, 0, 131, 0, 4, 96, 0, 0, 184, 192, 0, 177, 205, 96, 0, 0, 0, 0, 2, +0, 32, 0, 0, 0, 0, 0, 0, 0, 0, 64, 0, 0, 128, 0, 0, 8, 0, 0, 0, 0, 1, 4, 0, 1, +0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 4, 0, 0, 64, 69, 0, 0, 8, 2, 66, 32, 64, 0, 0, 0, +0, 0, 1, 0, 128, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 12, 0, 16, 0, 0, 4, 128, 64, +0, 0, 0, 0, 0, 0, 0, 0, 224, 0, 8, 0, 0, 130, 16, 64, 128, 2, 64, 0, 0, 0, 128, +2, 192, 64, 0, 65, 0, 0, 0, 16, 0, 0, 0, 32, 4, 2, 2, 76, 0, 0, 0, 4, 72, 52, +131, 44, 76, 0, 0, 0, 0, 64, 1, 16, 148, 4, 0, 16, 10, 64, 0, 2, 0, 1, 0, 128, +64, 68, 0, 0, 0, 0, 0, 64, 144, 0, 8, 0, 2, 0, 0, 0, 0, 0, 0, 3, 64, 0, 0, 0, 0, +1, 128, 0, 0, 32, 66, 0, 0, 0, 40, 0, 18, 0, 0, 0, 0, 0, 33, 0, 0, 32, 0, 0, 32, +0, 128, 4, 64, 145, 140, 0, 0, 0, 128, 0, 2, 0, 0, 20, 0, 80, 38, 0, 0, 32, 0, +32, 64, 4, 4, 0, 4, 0, 0, 0, 129, 4, 0, 0, 144, 17, 32, 130, 16, 132, 24, 134, +0, 0, 64, 2, 5, 50, 8, 194, 33, 1, 68, 117, 1, 8, 32, 161, 54, 0, 130, 34, 0, 0, +0, 64, 128, 0, 0, 2, 0, 0, 0, 0, 32, 1, 0, 0, 0, 3, 14, 0, 0, 0, 0, 0, 16, 4, 0, +0, 0, 0, 0, 0, 0, 0, 96, 1, 24, 18, 0, 1, 128, 24, 0, 64, 0, 4, 0, 16, 128, 0, +64, 0, 0, 0, 64, 0, 8, 0, 0, 0, 0, 0, 66, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 16, 0, 64, 2, 0, 0, 0, 0, 6, 0, 8, 8, 2, 0, 64, 0, 0, 0, 0, 128, 2, +2, 12, 64, 0, 64, 0, 8, 0, 128, 32, 0, 0, 10, 0, 0, 32, 0, 128, 32, 33, 8, 136, +0, 96, 64, 0, 0, 0, 0, 0, 64, 4, 16, 4, 8, 0, 0, 0, 16, 0, 2, 0, 0, 1, 128, 0, +64, 16, 0, 0, 0, 0, 0, 0, 0, 0, 8, 0, 0, 2, 0, 16, 0, 4, 0, 8, 0, 0, 0, 0, 0, +20, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 136, 0, 0, 0, 0, 0, 8, 0, +0, 0, 0, 0, 2, 0, 0, 0, 64, 0, 0, 1, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 0, 0, +0, 0, 4, 0, 0, 0, 0, 65, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 2, 128, 0, 0, 0, 8, 2, 0, 0, 128, 0, 16, 2, 0, 0, 4, 0, 32, 0, 0, 1, +4, 64, 64, 0, 4, 0, 1, 0, 16, 0, 32, 68, 4, 4, 65, 10, 0, 20, 37, 18, 1, 148, 0, +32, 128, 3, 8, 0, 64, 0, 0, 0, 0, 0, 0, 4, 0, 16, 1, 128, 0, 0, 0, 128, 16, 0, +0, 0, 0, 1, 128, 0, 0, 128, 64, 128, 64, 0, 130, 0, 164, 8, 0, 0, 1, 64, 128, 0, +18, 0, 2, 150, 0, 8, 0, 0, 64, 0, 81, 0, 0, 16, 128, 2, 8, 36, 32, 129, 4, 144, +13, 0, 0, 3, 8, 1, 0, 2, 0, 0, 64, 0, 5, 0, 1, 34, 1, 32, 2, 16, 128, 128, 128, +0, 0, 0, 2, 0, 4, 18, 8, 12, 34, 32, 192, 6, 64, 224, 33, 0, 0, 137, 72, 64, 0, +24, 8, 128, 128, 0, 16, 0, 32, 128, 128, 132, 8, 0, 0, 16, 0, 64, 0, 0, 4, 0, 0, +16, 0, 4, 128, 64, 0, 0, 1, 0, 4, 64, 32, 144, 130, 2, 128, 0, 192, 0, 64, 82, +64, 1, 32, 128, 128, 2, 0, 84, 0, 32, 0, 44, 24, 72, 80, 32, 16, 0, 0, 44, 16, +96, 64, 1, 72, 131, 0, 0, 0, 16, 0, 0, 165, 0, 129, 2, 49, 48, 64, 64, 12, 64, +176, 64, 84, 8, 128, 20, 64, 213, 136, 104, 1, 41, 15, 83, 170, 0, 0, 41, 1, 64, +64, 0, 193, 64, 64, 8, 0, 128, 0, 0, 64, 8, 64, 8, 1, 16, 0, 8, 0, 0, 2, 1, 128, +28, 84, 141, 97, 0, 0, 68, 0, 0, 129, 8, 0, 16, 8, 32, 0, 64, 0, 0, 0, 24, 0, 0, +0, 192, 0, 8, 128, 0, 0, 0, 0, 0, 64, 0, 1, 0, 0, 0, 0, 40, 1, 128, 64, 0, 4, 2, +32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 32, 8, 0, 32, 0, 0, 0, 16, 17, 0, +2, 4, 0, 0, 33, 128, 2, 0, 0, 0, 0, 129, 0, 2, 0, 0, 0, 36, 0, 32, 2, 0, 0, 0, +0, 0, 0, 32, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0, 4, 32, 64, 0, 0, 0, 0, 0, 0, +32, 0, 0, 32, 128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 128, 16, 0, 0, 0, 0, 0, 0, 0, +1, 0, 136, 0, 0, 24, 192, 128, 3, 0, 17, 18, 2, 0, 66, 0, 4, 24, 0, 9, 208, 167, +0, 144, 20, 64, 0, 130, 64, 0, 2, 16, 136, 8, 74, 32, 0, 168, 0, 65, 32, 8, 12, +1, 3, 1, 64, 180, 3, 0, 64, 0, 8, 0, 0, 32, 65, 0, 4, 16, 4, 16, 68, 32, 64, 36, +32, 24, 33, 1, 128, 0, 0, 8, 0, 32, 64, 81, 0, 1, 10, 19, 8, 0, 0, 4, 5, 144, 0, +0, 8, 128, 0, 0, 4, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 8, 0, 0, 0, 0, 0, 80, 1, 0, 0, +33, 0, 32, 66, 4, 2, 0, 1, 43, 2, 0, 0, 4, 32, 16, 0, 64, 0, 3, 32, 0, 2, 64, +64, 116, 0, 65, 52, 64, 0, 17, 64, 192, 96, 8, 10, 8, 2, 4, 0, 17, 64, 0, 4, 0, +0, 4, 128, 0, 0, 9, 0, 0, 130, 2, 0, 192, 0, 48, 128, 64, 0, 96, 0, 64, 0, 1, +16, 32, 0, 1, 32, 6, 128, 2, 32, 0, 12, 0, 0, 48, 32, 8, 0, 0, 128, 0, 18, 0, +0, 28, 24, 41, 16, 5, 32, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 1, 0, 0, 0, 16, 0, 0, 0, 0, 64, 0, 0, 0, 0, 8, 0, 0, 0, 0, 16, 128, +0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 33, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, +0, 0, 0, 0, 0, 0, 0}; + + memset(lengths, 0, BROTLI_ENC_NUM_HASH_BUCKETS); + + for (len = BROTLI_MAX_DICTIONARY_WORD_LENGTH; + len >= BROTLI_MIN_DICTIONARY_WORD_LENGTH; --len) { + size_t length_lt_8 = len < 8 ? 1 : 0; + size_t n = 1u << dict->size_bits_by_length[len]; + const uint8_t* dict_words = dict->data + dict->offsets_by_length[len]; + for (i = 0; i < n; ++i) { + size_t j = n - 1 - i; + const uint8_t* word = dict_words + len * j; + const uint32_t key = Hash14(word); + size_t idx = (key << 1) + length_lt_8; + if ((lengths[idx] & 0x80) == 0) { + BROTLI_BOOL is_final = TO_BROTLI_BOOL(frozen_idx[global_idx / 8] & + (1u << (global_idx % 8))); + words[idx] = (uint16_t)j; + lengths[idx] = (uint8_t)(len + (is_final ? 0x80 : 0)); + } + global_idx++; + } + } + for (i = 0; i < BROTLI_ENC_NUM_HASH_BUCKETS; ++i) { + lengths[i] &= 0x7F; + } + + return BROTLI_TRUE; +} + +BROTLI_MODEL("small") +uint16_t kStaticDictionaryHashWords[BROTLI_ENC_NUM_HASH_BUCKETS]; +BROTLI_MODEL("small") +uint8_t kStaticDictionaryHashLengths[BROTLI_ENC_NUM_HASH_BUCKETS]; + +#else /* BROTLI_STATIC_INIT */ + +/* Embed kStaticDictionaryHashWords and kStaticDictionaryHashLengths. */ +#include "dictionary_hash_inc.h" + +#endif /* BROTLI_STATIC_INIT */ + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/dictionary_hash.h b/packages/runtime/vendor/brotli/c/enc/dictionary_hash.h new file mode 100644 index 000000000..dfddc017d --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/dictionary_hash.h @@ -0,0 +1,45 @@ +/* Copyright 2015 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Hash table on the 4-byte prefixes of static dictionary words. */ + +#ifndef BROTLI_ENC_DICTIONARY_HASH_H_ +#define BROTLI_ENC_DICTIONARY_HASH_H_ + +#include "../common/platform.h" +#include "../common/static_init.h" + +#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE) +#include "../common/dictionary.h" +#endif + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* Bucket is (Hash14 * 2 + length_lt_8); in other words we reserve 2 buckets + for each hash - one for shorter words and one for longer words. */ +#define BROTLI_ENC_NUM_HASH_BUCKETS 32768 + +#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE) +BROTLI_BOOL BROTLI_INTERNAL BrotliEncoderInitDictionaryHash( + const BrotliDictionary* dictionary, uint16_t* words, uint8_t* lengths); +BROTLI_INTERNAL extern BROTLI_MODEL("small") uint16_t + kStaticDictionaryHashWords[BROTLI_ENC_NUM_HASH_BUCKETS]; +BROTLI_INTERNAL extern BROTLI_MODEL("small") uint8_t + kStaticDictionaryHashLengths[BROTLI_ENC_NUM_HASH_BUCKETS]; +#else +BROTLI_INTERNAL extern const BROTLI_MODEL("small") uint16_t + kStaticDictionaryHashWords[BROTLI_ENC_NUM_HASH_BUCKETS]; +BROTLI_INTERNAL extern const BROTLI_MODEL("small") uint8_t + kStaticDictionaryHashLengths[BROTLI_ENC_NUM_HASH_BUCKETS]; +#endif + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_DICTIONARY_HASH_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/dictionary_hash_inc.h b/packages/runtime/vendor/brotli/c/enc/dictionary_hash_inc.h new file mode 100644 index 000000000..89e04f0f4 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/dictionary_hash_inc.h @@ -0,0 +1,1829 @@ +const BROTLI_MODEL("small") +uint16_t kStaticDictionaryHashWords[BROTLI_ENC_NUM_HASH_BUCKETS] = { +1002,0,0,0,0,0,0,0,0,683,0,0,0,0,0,0,0,1265,0,0,0,0,0,1431,0,0,0,0,0,0,40,0,0,0, +0,155,8,741,0,624,0,0,0,0,0,0,0,0,0,0,0,0,66,503,0,0,0,451,0,0,0,0,0,0,0,835,70, +0,0,539,0,0,0,0,0,0,0,0,0,113,0,0,0,0,718,0,0,0,0,0,0,520,0,1070,0,0,0,0,0,1515, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,78,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,610,0,0,750,0,0,0,307,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,964,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,999,0,0,0,0,0,0,0,0, +645,75,0,649,52,282,0,200,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1621,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,211,225,0,0,687,718,0,0,110,0,58,0,0,0,0,0,0,345,0,0,301,0,0, +0,203,0,0,1154,674,1949,0,0,0,0,0,0,0,0,0,259,0,0,0,0,0,0,0,1275,0,0,0,1231,254, +0,0,0,0,0,0,0,277,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,248,0,0,800,0,0,0,29, +116,100,490,0,0,0,0,0,1641,0,543,0,0,0,0,41,181,0,657,0,0,202,25,0,0,0,0,0,0,0, +0,0,0,423,0,0,0,113,0,0,0,927,963,0,976,0,206,0,0,0,0,0,0,0,0,0,2002,0,0,0,0,0, +0,0,0,0,0,0,696,0,1170,0,0,0,0,226,13,0,769,678,551,0,0,0,0,0,0,57,0,0,0,10,188, +0,0,0,624,0,0,0,0,0,0,0,0,0,1941,130,0,0,0,0,378,269,0,0,528,0,1146,0,0,0,1105, +0,1616,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,656,0,1940,0,0,0,0,0,173,0,0,0,0,0,0,0,0,0, +0,0,457,342,810,0,0,0,0,620,0,0,0,0,0,0,0,967,95,447,406,0,0,0,477,0,1268,944, +1941,0,0,0,629,0,0,0,0,0,375,0,0,0,1636,0,0,0,0,774,0,1,1034,0,0,0,0,0,824,0,0, +0,0,0,118,0,0,560,296,0,0,0,0,0,0,0,0,1009,894,0,0,0,0,0,0,0,0,0,0,0,0,0,1474, +366,0,0,0,0,0,0,0,0,0,79,1723,0,0,200,0,0,0,0,0,0,0,0,1759,372,0,16,0,943,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,258,0,0,900,1839,707,30,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,2004,0,0,10,115,0,50,0,0,0,0,0,0,0,0,0,0,520,1,0,738,98,482,0,0,0,0, +0,0,0,0,0,0,701,2,0,0,0,0,0,0,0,0,557,0,0,0,0,0,0,0,0,0,347,0,0,0,0,572,0,0,0,0, +0,0,0,0,0,832,0,0,797,809,0,0,0,0,0,0,0,0,0,0,0,528,0,0,0,861,0,0,294,0,0,0,109, +0,0,0,0,0,0,0,0,1187,290,266,0,0,0,0,49,50,748,0,0,466,399,0,0,0,0,0,0,0,378,0, +519,0,0,0,0,0,0,0,0,0,0,0,0,667,351,902,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,180, +0,0,869,0,0,0,0,0,0,0,260,0,0,0,0,0,0,0,0,0,0,523,36,0,0,587,510,809,29,260,0,0, +0,0,0,0,0,0,570,0,565,0,1464,0,0,0,0,0,0,10,0,0,787,399,380,200,0,0,0,0,516,0, +844,887,0,0,0,0,0,0,0,44,0,0,0,305,1655,0,0,0,0,0,0,0,0,0,0,0,0,0,0,786,10,0,0, +0,0,0,0,0,0,0,2031,0,0,0,0,0,684,0,0,0,0,0,1480,0,0,0,27,0,0,0,395,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,813,511,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,56,0,0,0,206, +496,0,0,0,0,0,909,0,891,0,0,0,0,0,0,0,0,0,687,0,0,0,1342,0,0,0,0,0,0,0,0,0,0, +160,41,0,0,0,0,0,0,0,0,0,0,0,1718,778,0,0,0,0,0,0,0,0,0,0,1610,0,0,0,0,0,115,0, +0,0,0,314,294,0,0,0,983,178,193,0,0,0,0,0,0,0,0,0,174,0,0,0,0,0,0,0,0,0,0,848, +1796,0,0,0,0,0,0,221,0,687,1660,0,0,0,0,262,0,0,179,0,0,0,0,0,66,0,773,0,352,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35,0,152,0,0,1197,0,0,0,0,0,0,0,0,0,0,0,0,560,0,0, +564,0,0,0,797,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,556,0,819,0,0,0,0,0,0,0,0,719,544, +637,5,0,0,0,0,0,0,0,0,0,0,0,101,0,1441,0,0,0,893,0,0,0,0,0,0,0,0,0,238,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,1296,0,0,969,1729,314,60,0,0,0,0,0,1144,0,1147,0,0,0,0,0, +0,0,0,0,0,437,1853,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,828,0,176,0,0,0,0,0,0,434,39,0, +0,0,0,0,159,0,0,0,902,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,270,0,0,0,0,801,556,0,0, +0,0,0,0,0,416,19,197,369,0,0,0,0,0,0,0,0,0,28,34,0,757,0,0,898,1553,0,721,0,0,0, +0,1012,0,0,0,0,1102,0,898,183,0,0,0,0,0,0,0,136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,247,277,0,0,0,435,0,0,0,0,0,1311,0,0,0,0, +0,0,211,437,0,0,0,28,0,0,750,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2012,0,702, +0,808,0,0,0,0,739,166,0,0,0,0,0,0,719,170,500,0,0,0,0,0,0,0,0,1500,327,0,0,450, +0,0,0,1318,0,0,0,1602,0,0,331,754,0,0,0,0,0,1368,0,0,557,0,0,0,799,850,0,0,0,0, +0,0,0,0,908,0,0,0,0,0,19,62,459,0,0,0,0,0,0,0,0,0,0,0,0,1802,0,0,0,0,0,0,0,0,0, +1397,0,0,0,0,120,238,0,0,0,0,0,0,0,0,0,0,0,1324,0,0,0,0,0,0,0,0,602,201,0,0,164, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,615,0,0,0,0,0,0,0,0,0,0,0,0,0,1243,0,0,0,0,968,0,0, +0,0,0,0,882,0,0,0,907,329,100,0,0,0,0,0,0,0,0,0,0,0,176,26,9,0,0,265,256,0,0,0, +0,0,0,0,0,0,643,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,610,0,0,0,0,973,2001,0, +0,0,0,0,0,522,0,0,0,0,0,0,0,0,0,0,0,553,0,0,0,0,0,0,1582,0,1578,0,0,0,0,0,0,0,0, +0,0,0,795,0,0,0,432,0,0,0,0,0,0,84,126,0,0,0,0,790,0,377,64,0,1529,0,0,0,0,530, +1857,539,1104,0,0,0,0,0,0,0,0,0,0,0,0,977,0,0,0,34,0,0,0,0,0,0,0,0,0,0,0,24,26, +0,0,918,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,183,379,0,0,0,0,0,0,0,792, +0,0,0,0,0,0,0,0,0,1920,0,0,0,0,0,0,0,0,0,771,0,0,0,1979,0,901,254,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,140,0,0,0,0,0,440,37,0, +508,0,0,0,513,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,533,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,752,920,0,1048,0,153,0, +0,391,0,0,1952,0,0,0,0,0,0,0,0,0,0,126,0,0,0,0,640,0,483,69,1616,0,0,0,0,0,734, +0,0,0,0,0,0,480,0,495,0,472,0,0,0,0,0,0,0,0,874,229,0,0,0,0,948,0,0,0,0,0,0,0,0, +1009,748,0,555,0,0,0,0,0,0,193,0,653,0,0,0,0,0,0,0,0,0,0,984,0,0,0,172,0,0,0,0, +0,0,0,0,83,1568,0,0,384,0,0,0,0,0,0,0,164,880,0,0,0,0,0,0,0,0,0,0,0,367,121,0,0, +828,0,0,0,0,0,0,0,1541,0,0,0,0,0,0,0,343,0,0,0,0,0,0,0,0,561,57,0,0,0,0,0,0,0, +926,0,0,0,0,827,0,194,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,0,0,0,0,0,0,0, +0,0,0,896,1249,0,0,0,0,0,1614,0,0,0,860,0,0,0,0,0,0,0,0,964,102,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,899,0,569,0,0,0,0,795,2045,0,0,0, +0,0,0,104,52,0,0,0,0,0,604,0,0,0,0,779,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,0,0,0,0, +494,0,677,0,0,0,0,0,0,0,508,0,0,0,0,0,0,0,0,0,1014,0,957,0,0,630,310,0,0,0,570, +0,0,449,0,64,537,0,0,0,0,0,0,0,244,0,0,0,0,0,0,0,0,0,0,0,0,0,0,702,1650,49,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,338,0,0,0,0,1279,0,0,0,0,0,0,0,896,0,0, +178,0,0,0,0,0,0,0,0,0,0,0,0,0,808,695,0,0,0,0,539,1117,0,0,0,0,0,0,0,0,257,0, +1003,0,0,0,1,448,0,516,0,0,960,0,125,4,0,1268,30,748,0,0,852,0,0,0,6,0,0,848, +236,1385,862,1811,0,0,0,0,698,803,0,0,0,0,0,0,0,610,992,0,0,878,0,1847,0,0,0,0, +0,0,0,383,0,1404,0,0,0,0,986,0,347,0,0,0,0,0,0,0,0,0,0,0,592,572,0,1411,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,606,0,0,0,0,0,0, +0,0,0,0,0,0,0,1829,0,0,0,0,0,0,0,0,0,0,0,0,700,748,0,0,0,0,0,0,365,0,0,127,0,0, +83,198,0,0,0,0,0,0,864,55,0,0,0,0,726,1752,0,0,0,0,0,0,0,0,0,0,0,0,0,1066,0,764, +0,0,0,0,683,0,550,309,0,0,874,1212,0,0,0,1364,0,986,381,723,0,0,0,1573,0,0,0,0, +0,1025,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1559,0,0,0,0,493,133,0,0,0,0,148, +119,0,0,0,0,0,0,537,14,541,0,635,126,0,0,0,495,0,0,0,0,861,998,1009,0,0,0,0,0,0, +0,359,368,0,0,0,0,304,1577,0,0,0,0,0,1107,0,0,0,0,0,929,0,0,0,1142,0,0,0,0,289, +175,0,432,0,219,0,0,0,0,0,785,0,0,595,0,0,0,0,0,0,0,0,0,0,0,0,0,80,0,0,0,0,0,0, +931,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1323,0,0,0,0,290,0,559,1751,127,0,0,0, +934,1167,0,963,0,260,0,0,0,573,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +580,1689,0,0,0,0,0,0,0,0,0,1164,0,0,982,1922,0,63,0,0,0,0,0,793,0,0,0,0,0,0,0,0, +0,0,0,0,0,67,790,0,0,0,0,0,0,0,0,0,0,391,443,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,271,0,0,0,0,0,0,0,0,0,0,0,1140,0,0,0,0,340,300,0,897,0,0,0,0,0,0, +0,0,0,0,890,0,0,0,0,818,321,53,0,0,0,0,0,0,0,0,0,468,0,243,0,870,0,0,0,1765,121, +0,0,0,180,518,0,822,419,634,0,0,0,0,0,0,0,0,0,898,0,0,0,0,454,36,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,806,0,0,0,0,0,0,0,0,0,0,0,0,1326,0,104,0,0,0,0,0,0,0, +0,0,260,0,0,0,0,0,0,0,0,0,0,0,0,542,45,0,0,263,1516,42,0,0,0,0,0,468,0,1005,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,288,87,0,0,0,0,0,0,0,0,502,988,133,0,0,0,0,0,0, +141,0,0,872,1842,0,0,0,0,0,0,0,0,261,619,0,0,0,0,189,246,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,678,0,0,0,0,0,0,0,0,0,0,0,0,285,35,0,517,0,0,0,0,0,0,0,0,0,0, +540,214,667,0,74,0,0,125,0,0,0,0,0,761,131,0,0,0,0,0,0,0,0,0,0,0,0,0,333,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1338,94,0,0,0,0,0,0,0,0,0,0,0,0,449,0,646,103, +86,641,2028,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,869,87,277,117,39,0,0,0,0,0,0,0,0,938, +297,0,0,0,0,558,464,0,0,0,0,0,0,0,0,0,0,731,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1608,0, +0,0,0,0,0,0,1429,0,0,733,1010,0,0,338,1656,0,0,0,1038,979,2010,0,0,0,0,0,0,0, +1005,0,0,121,0,0,0,219,20,0,0,0,0,0,0,872,1440,0,0,0,683,0,1070,0,0,522,0,0,0,0, +439,669,0,0,0,0,0,0,0,0,1245,0,0,0,0,0,1218,0,0,547,233,0,0,0,0,0,0,0,0,0,482,0, +0,0,0,0,0,0,886,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,795,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,371,0,0,0,0,0,0,0,0,0,0,0,0,0,622,0,625,0,0,0,339,29,0,0,338,0,0,0, +0,130,0,0,0,0,0,0,0,0,0,307,0,0,0,0,0,0,0,0,0,0,2044,0,0,0,0,0,0,0,0,308,770,0, +0,0,0,0,1266,0,0,0,0,0,0,0,0,0,400,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,690,739,0,0, +0,0,0,0,0,990,0,0,0,1831,0,0,0,0,0,0,0,0,0,0,0,0,0,613,0,0,0,0,0,0,0,0,0,0,0,0, +0,763,0,878,0,0,0,977,0,100,0,0,0,0,0,0,0,0,0,463,0,0,0,0,623,318,0,0,296,463, +137,0,0,454,0,0,0,1527,58,0,0,0,0,0,0,0,18,48,0,0,0,0,0,729,0,0,0,442,0,0,0,0, +40,449,0,853,0,0,0,0,0,0,227,0,0,0,0,0,0,1491,0,0,0,0,0,0,0,0,0,0,161,55,0,450, +0,1174,62,0,207,0,0,0,0,0,0,0,0,869,0,0,0,0,80,213,0,0,0,0,0,0,0,0,0,0,354,820, +0,0,747,0,0,0,954,0,0,1073,0,556,0,0,0,692,0,191,0,804,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,831,162,0,0,35,0,0,0,0,0,0,0,0,1235,0,0,0,0,0,1234,0,0, +0,0,0,0,0,0,0,0,96,0,0,0,0,0,0,0,149,0,0,0,902,204,0,0,833,0,287,366,0,0,0,0,0, +0,992,2020,0,0,0,0,0,0,0,0,0,0,0,356,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,784,0,0,567, +630,0,0,0,539,0,0,27,0,0,0,0,0,0,0,0,0,0,755,0,0,0,0,0,0,0,0,0,0,0,0,814,0,0,0, +0,0,0,0,0,0,0,0,0,0,987,0,0,255,761,194,0,1086,0,0,0,0,0,0,1016,0,0,1396,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,562,271,913,0,0,0,0,0,0,0,0,320,153,45,475,0,0, +0,0,0,0,0,713,0,327,0,0,0,0,0,0,604,552,3,359,0,0,0,0,853,80,0,0,0,0,0,0,0,2016, +6,887,0,0,0,0,975,0,961,0,0,0,0,0,916,1891,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,100,101,390,708,0,0,0,587,983,512,0,0,0,0,0,0,0,0,0,0,0,645,0,0,0,851,0,0,0, +0,0,498,140,217,0,0,0,1448,0,0,0,0,0,0,0,0,0,905,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +643,105,0,792,0,0,0,0,0,0,0,0,0,0,0,0,56,0,0,0,0,0,0,0,0,0,0,535,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1748,0,0,0,0,0,754,0,0,0,0,0,0,0,0,0,0,0,0,91,0,0,1565,0,91,792, +939,3,370,0,0,0,0,95,0,0,0,0,551,7,619,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1150,0, +0,0,0,0,0,0,0,0,0,0,0,0,671,0,0,0,0,0,888,368,149,0,0,105,1134,0,983,0,0,458,31, +0,643,0,0,0,312,0,740,0,0,0,1642,0,0,0,0,0,0,0,236,0,0,0,0,0,0,0,59,68,0,0,0,0, +0,867,795,0,0,0,0,970,1977,0,0,0,0,0,0,0,1148,0,775,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,970,0,0,0,0,0,0,0,0,0,665,71,0,0,0,0,827,0,0,0,0,0,0,0,0,0, +0,479,0,0,0,0,0,0,0,0,99,607,0,0,0,0,0,0,0,1960,0,0,0,793,0,0,871,41,0,0,241,94, +0,0,0,0,209,0,0,1497,0,0,0,0,0,0,0,0,0,98,0,0,0,463,0,0,0,0,291,0,0,0,0,0,0,0,0, +0,0,984,0,0,0,0,0,205,0,0,0,0,0,0,205,42,0,801,0,0,0,0,0,635,0,0,533,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,371,0,1282,0,0,0,825,0,0,0,0,0,0,0,0,0,357,879,467,0,317,0,0, +0,0,0,0,0,924,0,0,0,0,849,1795,0,0,0,0,895,1799,43,0,0,0,0,0,0,0,0,0,0,1820,0,0, +0,0,0,0,0,525,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,110,0,493,0,174,417,0,0, +0,0,0,583,733,0,0,0,0,0,0,481,215,0,0,0,0,477,0,0,0,0,0,0,0,0,308,0,0,0,0,0,0,0, +0,297,126,0,0,361,1551,0,0,0,0,0,0,871,1807,0,0,0,0,0,1307,0,685,0,0,0,0,0,0,0, +797,0,858,0,565,0,0,0,0,0,0,0,0,0,0,0,0,434,252,826,0,0,0,0,0,0,791,0,0,0,0,509, +231,178,601,0,0,0,0,0,0,0,0,43,1591,0,0,0,0,0,1683,0,0,0,0,45,0,0,0,0,0,0,0,0,0, +0,1120,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,556,494,0,398,0,0,0,1030,0,0,0,0,0,0, +168,0,0,0,0,0,0,0,0,0,0,973,0,642,0,0,0,0,0,0,0,0,0,1615,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,378,594,0,1093,0,679,112,0,0,0,0,1492,540,1374,714, +1486,0,0,0,0,825,1511,0,0,0,0,0,0,0,0,0,0,0,0,0,952,0,0,736,143,0,700,0,1540,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1557,0,0,0,860,990,0,0,0,807,0,0,0,0,0,131, +515,0,646,0,0,0,0,117,728,508,121,0,0,0,0,0,0,357,0,0,0,0,0,0,237,0,0,0,0,0,0,0, +0,0,1784,0,0,0,0,0,0,0,0,0,0,0,713,348,1536,0,738,0,0,0,0,0,0,0,434,0,0,0,0,0,0, +366,1877,39,0,0,0,0,0,0,580,0,0,0,0,0,0,0,0,0,0,0,0,0,0,873,0,0,0,0,171,0,625, +550,107,343,943,0,0,0,0,0,0,0,768,0,0,0,0,0,0,0,799,0,0,0,894,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1673,0,0,0,0,0,0,0,0,0,0,0,1052,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +272,0,441,0,0,3,9,0,0,0,1182,0,1346,0,0,0,0,0,0,0,0,682,0,0,1004,24,0,0,968,0,0, +0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,0,0,0,578, +474,0,0,0,0,0,0,0,0,0,0,0,0,0,0,113,530,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,556,0,0,0,0,0,0,16,1317,0,0,97,0,0,0,703,0,0,0,0,0,0,0,0,892,0,0,0,1571,0,0, +426,186,0,1101,0,0,0,0,0,0,0,0,937,585,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,644,291, +0,0,0,0,749,0,162,0,0,381,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,762,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,628,21,0,0,0,0,0,0,0,0,919,0,0,0,0,0,0,0,0,0, +633,0,0,0,0,332,0,0,0,0,0,0,0,0,0,1489,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,832,398,0,645,0,0,0,13,0,0,0,0,0,0,0,0,0,0,20,0,800,0,0,0,0,0,0,0,0,0, +0,0,0,0,1993,0,0,0,0,769,0,0,0,665,0,0,0,0,0,0,0,0,0,0,1426,0,0,0,0,60,0,0,0, +641,1874,0,644,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1757,0,0,0,0,0,937,0,1652,0,654,0, +0,0,0,0,0,0,527,0,0,0,0,0,0,0,0,0,0,0,0,0,226,0,0,0,0,0,1486,0,0,0,0,0,0,0,0,0, +0,0,325,0,0,0,0,0,0,0,1345,0,0,91,0,404,0,0,0,0,0,0,0,0,0,0,0,0,973,0,0,0,0,0,0, +0,1176,0,549,0,0,0,0,0,0,0,0,0,0,976,0,0,0,0,0,21,0,0,0,0,0,51,0,0,0,0,314,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,198,6,0,1093,0,0,0,0,0,0,0,0,0, +0,0,0,0,1776,0,0,0,0,0,1528,0,419,0,0,0,0,0,0,0,0,76,138,0,0,0,0,638,29,0,0,0,0, +0,0,0,1418,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1710,0,0,0,0,0, +0,0,0,0,0,0,0,532,23,0,0,0,0,0,0,0,862,0,0,946,592,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,70,0,0,0,0,0,0,0,0,0,812,0,0,0,76,0,0,988,0,442,0,0,0,896,0,0,0,0,0,0, +483,0,0,0,0,1709,0,0,0,0,0,0,119,0,0,0,117,0,309,0,0,0,0,0,596,976,0,0,0,0,0,0, +0,0,0,0,0,768,0,0,0,0,0,0,0,0,0,518,0,0,0,0,0,0,0,0,0,0,0,0,0,0,863,0,0,0,24, +145,1020,0,0,1984,0,0,0,0,0,0,0,658,0,0,0,0,0,0,0,0,0,0,106,1827,0,1010,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,582,87,0,0,0,0,0,0,0,267,0,0,0,703,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,496,0,0,0,0,1121,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,249,561,0,0,0,0,0, +0,0,760,0,0,154,0,0,0,255,0,419,323,0,0,0,0,0,368,0,0,0,0,0,0,0,0,0,0,522,0,0,0, +0,0,0,0,551,562,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,92,0,0,0,0, +0,0,0,284,525,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,958,0,0,594,0,0,0,0,0,0,6,479,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,61,0,0,0,0,0,0,0,820,1641,0,1556,0,0,0,0,0,0,0,302,0,0, +0,0,0,148,0,0,676,0,0,0,0,0,0,1674,0,0,0,0,0,0,178,0,0,0,0,0,0,0,94,389,0,0,0,0, +91,8,0,0,0,0,0,0,0,0,0,0,112,0,0,0,0,0,0,0,0,0,0,747,0,0,0,0,0,0,0,1746,0,0,0,0, +0,24,0,1352,158,1530,0,0,718,130,280,1401,0,0,0,0,0,1946,8,0,0,0,0,1607,0,0,0,0, +0,0,882,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,417,0,0,0,1597,633,433,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,234,0,0,0,0,0,0,0,0,680,1950,0,0,0,0,249,5,0,0,0, +0,0,0,0,0,0,1216,0,1773,0,0,0,0,0,0,0,0,0,0,0,0,0,0,509,180,0,0,0,0,0,0,0,1002, +0,0,0,0,0,0,0,0,0,0,0,0,0,931,0,0,0,0,0,0,0,0,747,943,0,1837,0,0,0,0,0,0,0,641, +0,0,0,0,280,0,0,0,5,0,0,0,0,0,72,545,0,0,0,0,0,0,0,0,0,742,0,0,254,151,872,0,0, +0,0,0,0,0,0,0,0,0,0,921,0,0,517,833,0,1680,0,0,436,251,584,0,0,0,0,0,0,0,0,0,0, +0,24,500,0,0,0,0,0,0,0,0,195,1775,514,389,0,0,0,0,0,0,0,743,0,0,0,0,0,0,292,0,0, +0,227,1283,774,1805,0,0,0,0,0,0,0,0,0,0,119,81,0,0,0,0,0,0,0,0,0,0,0,0,0,0,913, +1910,0,0,0,1826,490,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1162,700,30, +0,0,0,721,839,0,0,0,617,0,0,0,0,0,0,0,0,0,169,428,0,0,0,0,0,1648,637,1205,0,0,0, +1596,0,0,4,266,0,0,0,0,0,0,0,0,0,0,0,862,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0,0,0, +0,279,157,391,604,0,0,713,945,877,973,0,0,0,0,0,0,0,0,0,0,0,0,0,0,859,567,628, +1846,0,0,0,0,0,0,0,0,0,762,0,0,191,0,0,0,0,298,0,0,767,909,0,0,0,0,0,0,0,795,0, +0,301,0,0,1970,0,0,0,0,0,0,0,0,0,1236,0,0,0,0,0,0,644,369,15,0,160,71,0,0,0,0,0, +1447,0,0,0,0,0,0,0,0,735,1255,76,0,0,0,0,0,0,0,0,0,0,474,0,0,0,0,0,0,0,0,0,0, +841,0,0,0,0,0,0,0,0,0,0,836,0,0,0,0,0,1622,0,0,735,0,0,0,0,1601,804,1390,394,0, +0,0,0,0,0,96,0,289,0,0,35,688,0,0,0,667,0,513,0,0,0,0,0,0,0,2034,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,704,0,1524,0,1078,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,306, +0,0,0,0,0,0,0,431,0,1196,0,0,54,0,15,1448,0,1418,0,0,0,0,0,0,0,0,0,907,0,0,0,0, +0,0,194,1767,0,0,0,0,0,840,0,900,0,0,0,0,0,0,0,0,0,0,0,1436,0,0,0,0,642,1560,0, +0,0,0,0,0,94,386,0,0,0,0,0,0,0,0,0,0,830,416,0,0,20,731,0,0,0,0,0,0,0,0,697,0,0, +662,0,0,0,0,0,0,0,0,0,861,0,0,0,0,0,0,0,871,671,864,0,928,7,0,332,0,0,0,0,1055, +0,0,0,0,0,0,986,0,0,0,0,0,44,76,0,0,0,0,0,0,0,0,0,0,300,0,0,0,0,0,0,0,175,518, +831,1108,0,0,0,836,0,1852,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,843,1804,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,246,0,0,0,610,202,0,0,36,0,0,0,240,654,13,0,0,0,0,0,0,0, +0,391,0,403,0,0,0,0,0,0,0,0,0,0,75,0,366,815,0,0,631,0,0,0,0,0,0,0,0,345,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,952,0,0,0,0,0,0,0,0,0,0,0,673,35,662,0,287,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,5,34,0,0,0,0,0,0,0,0,151,0,427,0,0,382,0,0,0,329,0,0,279,0,0,0, +0,0,0,0,0,0,0,906,0,0,366,843,0,1443,0,1372,992,0,36,123,0,649,0,0,0,0,0,767,0, +1018,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,995,0,0,0,0,0,0,0,72,368,0,0,1345,0,0,0, +589,0,0,0,0,0,0,0,0,0,1988,0,0,220,541,0,0,0,686,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,32,196,0,0,0,0,0,0,0,0,0,0,0,0,0,381,0,0,0,0,0,0,0,0,0,1452,0, +0,0,616,0,0,0,0,0,0,0,0,0,1229,0,0,0,0,0,0,0,0,0,0,667,120,0,0,0,0,0,0,0,1146,0, +0,0,0,0,0,0,0,0,0,0,352,0,0,0,0,0,293,0,0,0,0,0,0,0,0,0,0,0,0,0,935,0,1050,0, +147,88,0,0,923,0,0,0,0,0,934,0,0,0,0,0,0,0,0,114,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,341,222,0,0,0,0,0,0,0,0,0,0,293,0,0,0,0,0,0,0,0,0,0,0,0, +637,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1159,0,0,0,847,0,0,0,0,0,0,683,0,867,944,0,0, +0,0,0,1809,0,0,0,0,0,0,0,0,0,0,395,170,0,0,0,0,0,0,0,0,0,0,618,535,0,1625,0,0,0, +0,0,0,0,0,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,778,0,0,0,0,0,46,0,2032,0,0,37, +1458,0,938,363,34,0,0,0,0,0,0,0,0,0,0,0,0,0,0,314,0,0,0,0,0,0,889,0,0,0,0,0,0,0, +0,0,0,0,462,0,0,0,0,525,0,0,23,0,0,0,0,0,0,0,0,0,0,0,676,0,0,0,0,0,0,0,0,0,0,0, +0,498,725,0,0,0,0,7,0,0,0,0,773,0,0,0,164,0,0,0,0,0,0,0,0,936,583,659,1462,0, +220,0,0,0,0,803,0,0,544,119,0,0,0,0,0,0,0,0,0,0,0,181,176,0,1192,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,1878,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,0,0,0,0,0,0, +944,0,0,0,0,0,0,0,273,0,0,0,0,0,855,0,0,0,0,5,127,0,0,0,0,0,0,0,0,752,230,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,162,0,654,48,156,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,240,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,197, +0,0,0,0,0,0,0,963,0,0,0,0,0,0,0,0,0,0,858,0,0,0,0,0,0,0,0,0,0,676,1978,0,0,102, +972,0,0,0,0,0,0,0,361,0,461,0,0,0,472,0,0,0,0,0,0,0,0,0,0,0,0,0,0,747,905,0,0,0, +155,0,0,0,0,0,0,0,0,0,0,319,163,0,0,0,0,0,0,0,0,0,848,0,0,36,631,0,0,0,0,0,1769, +0,0,0,0,0,144,0,0,0,0,0,0,0,0,0,0,369,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,555,247,0,0, +996,0,0,189,0,0,0,0,0,0,0,0,0,0,280,0,0,0,0,0,0,0,0,0,0,0,526,746,0,0,345,0,0,0, +1017,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,651,428,0,0,0,1162,230,327,546,792,0,0,0, +1203,0,0,0,0,0,0,0,0,0,672,189,0,0,0,0,0,0,99,0,0,0,298,0,0,0,0,0,0,555,397,0,0, +0,0,0,1157,0,0,0,0,0,0,0,0,0,0,398,1523,0,366,0,0,787,0,0,0,282,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,157,0,941,0,0,0,0,0,1336,0,0,116,0,0,0,0,0,0,787,0,0,0,0,0,0,0,0,0, +0,170,160,0,1815,0,0,0,0,0,866,0,0,0,0,0,0,0,0,0,689,0,0,0,0,820,0,498,108,0,0, +0,1119,0,0,0,244,609,1005,0,581,0,0,0,0,0,895,0,0,0,1898,0,0,0,0,0,926,0,0,0,0, +0,0,0,0,0,0,0,0,0,538,496,294,301,0,0,0,18,0,0,757,0,0,0,0,0,1263,0,820,0,722,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2028,0,0,0,0,124,1875,0,0,0,881,0,0,0,1348, +0,0,0,0,0,0,0,911,0,954,0,0,0,0,414,0,0,0,0,517,0,0,0,0,0,816,0,0,0,0,0,0,0,0, +713,0,0,0,0,0,0,0,33,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,593,150,0,0,0,0, +0,553,0,0,0,0,0,0,0,0,0,0,108,0,0,0,0,420,0,0,0,0,0,0,0,0,0,0,0,1777,0,0,55,493, +0,0,81,0,321,980,0,0,0,0,0,0,0,0,0,0,0,0,0,0,362,112,0,74,0,0,0,0,0,0,0,625,0,0, +0,0,0,0,377,16,0,0,61,281,0,0,0,0,0,0,0,0,0,0,0,0,0,0,224,1031,0,0,0,0,0,0,51,0, +0,0,0,0,0,0,211,309,15,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,789,173,0,439,9,648, +0,0,294,0,0,0,0,0,0,0,374,8,0,1099,0,0,0,0,0,0,0,575,0,0,0,518,0,0,0,702,0,0,0, +0,0,0,87,0,0,0,438,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,464,122,0,0,0,1802,0,0,0,0, +0,0,499,0,0,0,87,476,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,840,283,0,0,0,0,1620,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,609,1160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,600, +323,372,0,0,0,0,471,722,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0, +477,1304,0,1774,0,0,88,0,438,12,0,0,0,0,0,0,0,0,671,997,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,639,22,0,0,782,681,0,0,0,0,0,0,0,0,0,0,1013,664,0,942,0,1349,0,0,0,0,0,0,0, +0,0,0,0,0,356,0,0,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,215,289,0,1975, +109,450,0,0,0,0,0,0,0,0,0,0,705,0,0,664,0,0,0,0,0,0,0,1238,0,0,318,0,0,0,0,0,0, +0,0,0,0,0,0,0,960,1872,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,0,0,0,0,0,0,0,0,0,239, +777,0,26,0,0,0,0,0,0,0,0,0,0,0,0,375,414,0,17,0,0,0,1350,0,955,0,0,0,0,0,0,0,0, +887,960,0,0,0,0,0,0,0,0,0,0,708,710,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,919,0,0,0, +0,502,280,7,45,0,0,0,0,777,0,0,0,0,410,0,1110,0,0,0,0,0,0,414,341,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,787,0,0,0,436,0,0,0,0,0,0,0,1707,613,377,96,0,0,0,0,451, +0,0,0,0,0,0,0,0,0,0,0,0,0,680,0,483,916,0,0,0,0,0,0,937,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,739,0,0,0,0,0,0,0,0,82,0,0,663,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,128,0,0,0,0,0,0,0,0,1087,0,0,0,0,0,0,0,503,0,0,0,0,0,0,9,113,104,324,0,460,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,935,702,434,485,1014,949,423,0,900, +0,0,0,0,0,0,0,2018,574,0,0,0,0,0,0,0,0,0,0,0,0,1206,0,0,0,0,0,0,0,0,38,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1022,0,0,0,0,143,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,2029,0,0,0,0,0,0,0,0,0,0,0,0,523,0,0,0,0,0,0,625,0,0,425,37,0,0,0,1943,0,0,0, +0,0,765,0,0,0,0,0,0,0,0,0,0,551,0,0,0,0,0,0,0,0,0,0,0,0,168,0,0,1010,0,0,1994,0, +0,0,91,0,0,0,0,532,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1884,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,240,15,0,0,0,1227,0,1534,0,0,0,0,0,0,0,0,0,0,0,0,0,0,392,0, +0,0,0,0,0,0,0,0,0,0,0,655,562,395,0,0,0,501,1019,0,0,0,0,509,267,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1099,0,0,0,0,0,0,948,0,0,0,0,0,0,0, +462,114,0,0,258,404,0,1717,0,0,0,0,82,1061,0,724,0,0,0,0,0,1133,0,0,0,0,0,0, +1021,841,0,1021,0,0,0,0,0,0,0,0,0,0,488,373,37,0,0,0,0,564,0,0,0,0,0,513,0,0,0, +825,0,0,899,0,0,778,0,0,12,1417,0,1116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,114,545,0,5, +0,0,0,0,0,0,0,192,0,0,763,0,0,0,0,0,0,0,755,759,0,0,0,0,0,0,0,0,0,370,0,1237,0, +0,0,0,0,0,298,87,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31,0,0, +0,0,0,0,814,991,0,757,57,0,0,0,0,0,0,0,0,0,540,0,0,0,0,608,0,0,0,0,0,0,0,0,1014, +0,0,0,902,0,0,0,0,553,1668,0,0,0,0,0,0,0,0,0,559,60,0,0,0,0,0,511,0,0,675,0,0, +156,0,0,0,0,0,0,709,0,698,0,0,0,1745,0,0,0,0,0,0,0,0,0,714,0,0,0,0,0,0,0,0,206, +8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,776,0,0,0,0,0,0,0,0,0,1272,0,0, +0,0,0,1059,0,0,0,0,0,0,406,0,0,0,0,0,0,0,0,0,0,947,0,0,0,0,0,0,168,0,0,0,0,0,0, +870,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,554,0,0,0,0,784,908,0,0,0,0,0,0, +0,396,358,0,0,0,0,0,0,0,0,2,228,0,0,0,0,0,0,0,0,0,0,0,845,14,0,716,1820,594,0, +81,1428,0,161,0,782,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,0,0,998,0, +0,0,0,0,0,0,0,0,0,0,0,1043,0,1496,0,0,0,0,0,0,0,0,781,0,0,0,0,0,0,0,817,1114,0, +1814,958,0,0,0,0,812,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,139,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,236,643,0,0,0,0,0,0,0,0,0,1172,0,0,0,0,0,0,0,0,0,1338,0,0,0, +0,0,0,0,0,0,0,0,54,0,0,0,256,0,0,351,0,955,1885,0,469,0,0,0,1270,0,744,0,313,0, +0,0,0,0,0,0,0,402,969,0,0,0,0,0,0,50,0,0,0,0,572,0,0,0,0,847,0,0,0,0,0,0,0,248, +43,0,369,0,0,0,0,0,0,0,0,0,0,0,0,0,766,0,363,0,0,0,0,0,0,0,0,0,0,0,678,0,0,409, +258,82,249,0,0,0,0,0,0,0,0,0,0,0,0,32,393,0,788,0,0,0,1281,509,1968,0,0,0,0,39, +291,0,0,0,589,0,0,54,1059,0,0,0,0,0,0,824,0,0,0,0,0,0,0,0,0,0,1005,0,1598,0,0,0, +0,0,919,0,0,0,0,0,0,0,0,52,132,0,0,0,0,0,328,0,0,0,0,173,0,0,0,0,0,65,1411,0,0, +0,0,0,0,0,0,0,0,442,0,842,0,0,0,0,0,0,0,0,0,534,0,0,0,0,0,0,0,0,0,0,0,0,0,845, +210,0,0,0,0,0,0,0,0,892,0,0,223,0,0,0,0,529,0,0,0,807,0,137,218,0,1444,0,0,0,0, +0,332,661,0,0,0,0,0,0,0,76,1517,0,0,0,0,0,0,0,0,0,0,0,418,0,0,0,0,0,0,0,0,481, +379,0,0,0,0,0,149,18,0,0,0,0,0,0,0,0,742,304,142,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,799,925,195,51,0,0,0,0,688,0,0,0,0,697,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1169,751,0,0,0,452,929,0,221,0,1437,0,0,0,0,955,1251,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,0,132,0,0,0,0,0,865,0,0,0,0,0,0,0,767, +672,42,0,0,0,1050,0,0,0,0,0,0,0,0,368,44,0,0,0,0,0,0,0,570,29,0,0,0,0,0,0,227,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,522,0,0,0,0,0,0,0,1529,0,0,0,0,0,0,739,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1667,0,0,0,0,0,0,132,511,0,138,208,1020,0,0,23,565,0,344,0,0,0, +0,0,922,0,0,0,0,0,0,0,240,0,0,415,171,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,402,0,0,754,31,716,0,982,731,0,0,0,0,0,0,0,888,0,0,0,803,847,0,0,823, +0,0,0,0,0,0,785,0,0,2,0,0,0,0,0,0,0,532,0,0,681,0,0,314,0,384,684,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,649,447,0,1818,1007,0,321,0,66,360,0,0,0,385,0,0,0,0,0,0, +0,900,73,254,0,0,0,0,683,1959,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,86,0,0,725,0,0,0,0,0,196,0,0,0,0,0,831,0,0,0,0,723,0,0,0,0,0,994,627,0,0, +0,0,0,0,0,0,0,0,764,66,0,0,0,0,205,36,0,0,0,0,0,0,0,950,0,0,0,887,111,0,0,831, +388,165,0,0,0,0,0,155,0,0,0,0,0,0,0,0,0,0,0,0,0,0,780,755,0,0,0,0,898,146,0,0,0, +0,0,0,0,45,7,0,0,0,0,0,0,0,0,607,0,0,0,0,0,0,65,0,0,0,0,0,0,0,0,0,88,0,0,0,0,0, +621,600,0,367,0,0,0,0,0,0,0,561,0,559,0,585,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +287,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,672,157,0,0,0,0,714,0,0,0, +0,0,456,0,925,0,0,0,0,0,0,0,0,19,0,0,0,0,1473,0,0,0,0,0,0,0,0,0,0,113,0,0,0,0,0, +0,0,0,0,0,0,0,0,69,463,0,0,82,193,2,471,0,0,0,0,633,0,0,0,0,0,0,1148,129,1392, +542,803,0,0,0,0,0,0,0,0,0,0,0,0,438,0,0,0,0,0,0,875,0,0,0,0,0,237,0,0,0,0,0,0,0, +65,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,563,0,0,0,9,444,0,0,43,1260,0,0,0,0,0,0, +971,0,0,699,0,0,0,0,0,1116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,829,242,0, +0,593,0,0,0,0,0,0,0,0,201,36,224,0,0,0,0,0,0,1430,0,1806,0,523,0,0,212,1889,0,0, +0,827,0,0,0,0,0,2043,136,242,0,0,0,0,0,0,284,148,10,0,0,0,0,0,0,1249,0,0,0,807, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,94,0,0,0,494,0,0,0,0,0,0,0,0,1510,0,0,0,0,0, +0,0,0,0,0,505,1306,0,0,764,268,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,384,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1703,0,0,0,0,159,964,583,0,0,0, +0,0,0,515,0,0,854,0,0,0,0,0,0,0,0,0,0,0,0,1123,0,0,0,0,0,0,0,136,0,0,0,0,0,1782, +0,0,44,1287,0,0,0,0,0,732,0,0,0,0,313,679,0,0,316,0,0,0,0,595,0,0,0,0,0,0,753, +147,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,137,0,0,0,0,414,0,1762,0,0,0,0,0,0,0,0, +0,0,0,599,0,0,0,0,0,0,0,0,0,1749,0,0,0,1627,0,488,0,0,0,0,0,83,0,0,0,0,676,0,0, +1639,0,0,0,0,0,0,0,0,0,278,0,0,0,0,0,0,97,0,14,1085,0,0,0,0,0,0,781,388,0,849, +59,229,0,0,0,0,0,1115,0,0,0,0,108,0,0,0,0,700,0,0,0,0,0,0,0,0,0,1414,0,0,0,0,0, +0,0,0,0,0,0,0,0,660,737,1035,0,0,0,0,0,0,521,690,0,0,0,0,0,0,0,0,0,0,0,0,272,0, +0,0,0,0,0,0,0,0,0,1744,0,0,0,0,0,0,128,733,0,0,277,0,0,0,0,0,0,0,0,0,4,0,0,0,0, +0,0,0,0,0,0,0,0,0,936,1981,40,0,0,0,0,0,0,0,0,775,0,0,0,0,0,0,0,0,0,306,0,0,0,0, +0,0,0,979,0,0,0,0,0,611,0,0,0,0,0,178,0,0,0,1969,0,0,0,0,0,0,0,664,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,390,0,0,0,1510,0,0,0,0,0,0,0,0,0,0,0,493,0,0,37,0,0,0,0,724,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,1537,0,0,168,473,0,0,0,105,0,0,0,0, +627,438,0,0,0,0,0,0,0,0,0,0,11,1256,0,0,0,1626,0,779,0,0,0,0,25,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,308,0,0,0,0,0,741,0,671,0,0,0,0,649,150,0,0,99,521,0,0,3,339,0,0,0, +543,0,0,0,0,0,0,0,0,0,1358,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,234,155, +0,0,0,0,0,0,0,1628,0,766,0,0,0,0,0,0,0,0,0,0,0,0,0,829,0,0,0,1445,0,0,0,486,0,0, +0,0,2,1635,0,0,0,0,558,0,0,0,0,0,0,0,0,0,0,1461,0,0,0,0,0,599,0,0,0,0,0,0,0,0,0, +1376,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,93,0,0,0,0,0,0,447,0,0,66,1432,0,0,0,0, +0,0,307,0,413,609,0,0,0,930,0,0,0,0,21,939,0,0,0,0,0,962,4,651,0,0,0,0,15,579,0, +0,0,0,0,597,0,0,0,0,0,981,0,0,0,545,0,0,0,0,0,0,0,1558,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,800,17,0,0,17,0,907,0,0,0,110,0,0,0,53,458,0,1983,0,0,0,0,0,0,0,0,0,0,443,0, +0,0,0,0,0,0,0,0,0,0,924,1844,0,1232,0,0,0,0,70,519,0,993,0,0,0,0,0,0,14,530,0, +907,0,0,0,0,0,733,0,0,0,0,0,0,0,0,55,0,188,531,56,0,0,1693,0,0,0,0,0,0,0,0,441, +0,192,928,0,0,0,0,0,241,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1525,0,259,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,512,185,0,464,1603,0,0,0,0,0,0,0,0,0,0,0,1113, +284,720,0,0,722,0,0,0,0,0,13,0,0,0,0,0,0,0,4,289,43,0,0,0,0,0,0,1694,0,0,0,0, +193,0,0,0,0,409,0,0,0,0,0,0,0,0,0,0,0,0,308,0,0,1863,0,0,0,0,0,0,0,0,0,790,0,0, +745,1002,0,0,0,0,0,0,0,0,0,289,68,477,13,0,0,0,0,0,0,0,0,0,0,609,0,0,0,0,0,0,0, +0,0,0,0,367,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,528,0,0,0,0,0,0,0,0,0,694,58, +548,0,0,0,0,0,0,687,0,0,0,0,1749,0,0,0,0,0,0,0,0,1004,661,0,0,0,0,0,0,445,0,0,0, +74,0,0,0,0,213,0,0,0,0,0,0,0,0,0,0,0,0,0,834,0,0,189,1672,0,0,0,0,0,0,0,1548, +192,0,0,0,0,0,0,0,0,0,0,0,0,0,32,751,0,78,0,0,0,0,0,0,544,1602,105,473,0,0,0,0, +0,0,156,1949,0,1779,0,0,0,0,0,0,0,0,0,0,0,763,0,0,0,0,0,0,0,0,29,0,0,0,0,0,0,0, +0,0,0,883,0,0,0,0,0,0,0,488,0,617,0,0,50,0,694,1518,785,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,546,0,0,0,0,0,0,0,0,0,0,22,0,0,0,0,1016,0,0,0,577,0,0,0,0,0,0, +184,935,114,720,0,0,100,0,0,0,0,0,0,0,0,0,3,0,0,0,0,0,95,14,0,969,0,0,0,0,0,0,0, +727,0,1021,0,0,0,0,0,1190,0,0,0,0,0,0,0,0,0,0,0,0,0,153,0,0,0,0,0,0,0,0,0,798,0, +587,0,0,695,42,0,1929,141,957,0,465,7,908,0,0,450,148,0,0,0,1166,0,0,0,0,0,0,0, +0,0,0,0,0,253,0,1003,0,0,0,0,0,0,0,0,0,0,0,46,0,0,879,0,806,0,1868,0,0,0,0,0, +1846,0,0,0,730,0,0,0,0,0,0,0,965,0,0,0,0,506,0,0,0,10,0,0,0,22,0,0,0,0,0,0,0,0, +0,0,0,0,0,960,296,0,0,0,0,0,0,0,0,0,0,0,587,0,0,0,0,20,0,0,0,32,982,0,0,0,0,0,0, +0,0,0,0,941,0,0,0,0,435,0,0,0,0,0,0,71,419,0,0,0,0,0,0,688,740,94,345,0,0,679, +582,0,0,0,0,0,0,0,945,0,0,0,0,0,0,0,0,0,0,0,0,539,0,684,1993,0,0,0,659,0,583,0, +803,0,704,0,0,0,0,0,198,181,347,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,481,405,203,0,0,99,826,0,0,0,0,0,0,0,492,0,408,0,0,0,0,0,0,0,0,0,0,4,0,0, +0,0,665,349,137,0,0,0,0,612,1270,0,0,0,0,0,371,0,0,0,826,0,0,0,0,21,1535,858, +374,0,0,0,0,0,0,311,0,0,0,991,1968,0,0,0,0,494,1647,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,769,0,0,0,0,0,642,0,0,157,123,0,0,0,1435,0,0,0,0,0,0,0,0,0,0,79,0,0,0, +0,0,0,1425,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,106,393,486,1690,0,0,0,0, +0,0,0,0,0,0,0,0,756,184,0,0,0,1382,0,0,0,175,0,1493,0,1007,0,0,0,0,0,0,0,0,0,0, +0,219,0,0,0,0,515,99,0,851,0,0,0,0,0,1278,0,0,0,0,0,0,0,1000,982,0,762,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,910,1819,0,0,0,0,0,0,906,0,0,0,0,0,0,0,0,0,0,1730,0,0, +0,0,0,0,0,0,0,0,0,1185,0,0,0,0,0,0,0,0,40,0,0,0,147,0,0,0,0,0,0,0,0,0,0,0,0,0, +650,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,56,30,0,553,0,0,20,597,0,1614,0,0,0,0,0,327, +49,0,0,0,0,0,0,0,78,0,0,786,134,0,0,0,12,496,0,0,0,0,0,0,0,0,0,0,42,204,0,614,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,147,247,0,0,0,0,942,0,0,2023,0,0,0,0, +0,0,67,285,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1309,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,41,532,0,0,0,0,0,0,0, +1692,0,0,0,0,55,1704,0,0,0,0,988,0,0,0,223,0,0,0,0,0,0,0,57,1123,0,0,0,0,0,1764, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2015,0,0,0,1599,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,534,0,0,0,0,0,0,0,0,0,0,0, +0,0,504,621,1248,321,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1397,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,441,75,0,0,0,0,0,0,0,0,0,0,841,0,0,0,0,0,693,0,650,314,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,913,0,0,0,0,0,0,0,0,0,0,0,0,0,0,880,0,475,0, +0,1016,179,602,111,329,0,0,0,1864,0,0,0,0,846,1888,0,0,780,0,0,0,82,0,0,0,0,821, +0,0,0,0,0,0,0,0,0,0,0,956,112,0,0,0,261,455,0,0,0,0,0,0,337,385,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,184,1865,0,0,721,16,0,486,0,0,0,265,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,621,0,0,0,0,0,0,0,0,234,0,0,815,0,0,743, +1987,205,197,0,0,0,0,0,0,0,0,0,314,0,0,0,0,0,0,0,0,0,0,0,0,0,0,219,452,589,0, +176,333,0,0,0,0,0,0,0,1110,47,0,0,0,0,0,0,0,0,0,0,0,864,0,0,300,0,1237,0,0,0,0, +0,0,0,0,0,0,0,1685,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,135,395,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,631,0,0,0,0,0,0,835,0,0,0,606,459,0,979,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,612,0,0,0,0,0,0,0,0,158,372,0,854,0,0,0,0,0, +0,0,1492,0,0,0,833,0,0,0,0,0,0,0,1739,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +195,0,0,0,0,0,0,0,0,730,1997,0,0,0,0,0,0,0,0,61,0,0,0,0,0,0,0,266,751,0,0,0,0,0, +0,0,821,0,0,0,715,0,0,0,868,0,959,0,0,0,0,0,0,0,0,0,0,0,1053,0,0,0,950,0,1081,0, +1595,0,0,0,0,59,0,0,0,0,0,0,0,0,0,0,47,684,0,0,0,0,0,0,1606,0,777,0,1020,0,0,0, +1094,0,0,0,0,0,0,0,350,0,0,0,0,0,0,242,1812,0,0,0,967,0,0,0,473,286,0,0,0,0,0,0, +798,629,222,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,513,337,306,0,0,0,0,0,0,0,0,0, +146,0,0,1646,0,0,0,0,0,465,0,0,0,525,0,0,0,0,0,0,299,165,0,0,0,0,0,0,0,1064,0,0, +0,0,0,596,0,0,0,0,0,0,0,0,0,0,0,0,0,0,238,1741,0,1233,451,1824,0,0,0,0,733,495, +0,0,0,0,0,1204,0,0,0,559,341,0,224,21,0,0,0,0,0,0,0,0,97,1446,0,0,0,0,0,0,0,729, +0,0,565,727,0,1948,0,0,0,519,0,0,0,0,0,0,0,0,0,1193,0,0,0,0,0,0,790,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,323,2,201,0,0,59,0,0,34,0,896,961,0,1285,0,0,46,0,479,0,0, +0,0,549,0,663,0,0,0,0,0,783,65,682,0,0,0,0,0,11,0,0,0,0,0,522,0,0,0,52,0,0,0,0, +0,383,0,0,0,0,0,0,0,0,127,0,0,0,0,0,397,194,0,0,635,0,0,0,0,0,0,0,0,0,0,975,0,0, +0,0,0,0,0,0,0,0,116,0,51,0,0,858,0,1075,535,448,0,0,0,0,0,610,0,0,0,0,0,0,0,0,0, +0,191,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,267,673,319,94,92,0,551,0,0,218, +1406,69,256,0,0,952,1980,0,833,0,0,0,0,0,0,0,0,0,0,0,0,39,0,0,0,0,0,0,0,81,0,0, +0,352,634,0,0,0,0,0,618,0,0,0,0,0,0,73,339,0,0,0,0,0,0,0,0,0,0,0,0,0,0,169,759, +0,0,0,0,0,0,0,0,0,0,0,0,0,1075,0,0,0,0,0,0,482,649,0,0,0,0,0,0,0,0,386,336,0,0, +0,1035,0,0,0,0,0,0,0,0,0,0,0,924,0,73,0,0,0,0,0,1971,0,0,0,0,0,0,0,0,0,1344,0, +501,0,0,0,0,0,0,0,0,46,799,0,0,0,0,0,0,0,276,0,0,0,0,0,0,0,770,0,0,0,0,0,0,0,0, +0,0,0,0,0,158,0,0,0,0,0,1432,0,0,0,0,0,0,0,0,0,0,25,0,0,2001,0,0,0,0,0,0,0,0,0, +0,0,0,0,478,0,0,0,0,0,0,91,1461,211,602,0,0,0,0,0,0,0,0,0,1068,0,0,124,567,0,0, +0,1006,0,0,0,0,0,0,0,0,0,735,812,0,0,323,0,0,0,304,0,0,0,0,0,0,0,0,0,148,0,0,0, +0,0,0,0,0,0,523,0,0,144,730,0,0,981,0,0,111,0,0,132,0,0,0,0,0,0,890,0,0,0,0,0, +444,0,1787,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,2041,932,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,937,0,995,0,0,255,0,0,138,863,965,0,0,631,0,0,0,0,1394,16,652,0,0,0,0,0,0, +0,0,0,0,0,0,0,897,0,321,0,0,0,0,0,922,0,619,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,844,0,0,0,0,0,0,1659,0,1100,0,0,0,1173,0,1930,268,251,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,390,711,0,0,0,0,0,0,0,0,0,0,0,0,0,744,0,0,0,0,0,0,0,0,0,624,0,0,0, +1998,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1125,0,0,0,594,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,268,0,0,0,0,0,0,0,563,0,0,0,0,0,0,0,0,2,39,0,0,0,1332,0,0,0,0,0, +0,0,508,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,66,796,0,0,0,0,527,0,0,0,0,98,0,0,576,0, +0,0,0,0,122,0,276,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,645,0,0,0,0, +0,0,0,0,0,0,0,290,0,0,762,1292,0,0,0,1315,0,1955,0,0,0,0,0,0,0,0,0,0,210,131,0, +0,0,0,797,0,38,0,11,488,0,936,0,441,0,0,0,0,0,595,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +991,0,0,0,0,0,0,0,0,0,0,0,653,0,523,0,0,0,903,0,0,0,0,0,0,0,0,0,0,0,0,80,0,0,0, +0,0,0,0,0,0,432,0,0,314,0,0,0,0,232,1368,534,0,0,0,0,0,27,0,0,0,12,0,0,0,0,0,0, +0,0,0,264,736,0,1657,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1117,0,127,0,0,0,1208,0,1294, +0,0,0,0,364,0,0,0,0,0,125,1334,0,0,0,0,0,0,0,0,0,0,0,0,0,0,792,0,0,0,0,0,0,0, +849,699,0,0,0,0,0,968,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1446, +124,397,0,0,0,0,0,0,0,0,0,0,0,641,0,0,0,0,0,0,0,0,0,0,0,0,127,346,0,0,517,75,0, +0,0,0,0,0,0,0,83,0,0,0,0,0,0,1031,0,0,0,0,0,0,0,1470,0,954,0,0,345,304,410,0,0, +0,0,734,0,0,0,0,0,1822,0,0,0,1798,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,161, +1865,69,0,0,0,0,0,0,922,0,0,0,0,0,0,0,0,0,0,0,541,0,627,0,0,0,0,0,0,0,0,0,166,0, +0,0,0,0,0,0,0,0,849,0,0,0,0,0,0,0,717,0,0,0,0,0,0,0,0,0,0,0,0,0,0,600,0,0,0,0,0, +0,654,0,0,188,273,0,0,0,543,0,410,87,0,0,941,0,0,186,250,0,1785,0,0,0,0,0,1339, +462,961,0,780,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,529,0,0,0,0,0,0,474,1276,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,24,948,0,0,0,0,657,753,0,0,0,0,941,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,706,985,837,0,1861,0,0,0,0,0,0,0,0,0,0,0,0,0,0,292,933,0,0,0,0,0, +0,0,0,0,767,0,0,0,0,0,0,0,641,0,0,0,1233,114,0,883,0,274,2008,0,1794,285,0,0, +571,0,0,0,0,0,0,0,0,0,0,823,960,16,617,0,431,0,0,0,0,0,0,0,0,0,0,567,0,401,0,2, +781,424,33,0,2006,0,0,274,0,0,1882,0,794,0,0,0,1848,0,0,0,0,0,0,448,47,0,0,0, +1199,0,0,0,0,0,0,0,0,417,0,0,0,0,0,0,0,0,0,0,295,0,0,0,0,0,0,0,1019,0,0,0,0,0,0, +0,0,0,0,0,0,0,620,0,0,0,0,464,0,0,0,0,208,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,442,0,930,0,0,0,0,0,516,68,0,0,0,0,0,1128,104,0,0,0,0,0,0,0,0,787,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,491,0,0,0,0,0,0,711,0,0,9,0,101,441,0,0,0,0,0,0,0,0, +0,0,160,396,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,679,326,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,1128,0,0,0,0,0,737,0,1796,0,0,0,0,0,0,0,0,0,0,0,0,338,574,0,0, +0,0,0,1096,491,405,0,0,0,0,0,1081,0,0,0,0,0,0,0,0,0,0,0,0,0,1676,0,1207,0,0,0,0, +0,0,969,354,0,0,0,0,598,0,297,0,0,0,0,0,0,0,0,1772,751,0,37,0,0,1828,0,0,0,0,0, +0,0,0,0,257,191,582,0,0,0,0,0,0,790,0,0,0,0,0,47,0,0,0,0,0,0,0,449,306,1011,0,0, +0,0,0,299,0,0,0,0,0,0,837,0,0,0,0,0,0,10,329,0,0,0,0,0,1320,0,0,0,0,0,0,158,657, +0,1191,0,0,0,0,0,0,7,0,974,1939,0,1665,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,288, +66,0,0,0,0,494,175,0,1643,0,0,0,0,0,0,0,0,570,750,719,0,0,0,0,0,0,0,0,0,0,0,0,0, +13,0,0,1247,0,0,221,356,0,0,0,0,0,0,0,0,0,0,694,1809,0,0,0,0,0,0,0,411,0,44,31, +0,0,0,0,669,0,673,0,0,0,0,0,0,0,0,0,1303,704,299,0,0,0,275,0,0,216,1761,0,0,0,0, +0,0,0,0,0,0,0,1319,0,0,428,0,0,0,0,0,0,0,0,0,0,514,0,0,0,0,0,0,49,55,102,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,364,0,0,0,0,379,0,921,971,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1258,0,0,0,1058,0,0,0,0,0,656,0,0,0,0,0,144,0,0,0,0,0,0,0,0,0,0, +0,1373,10,605,0,0,0,0,0,0,0,838,0,1012,0,0,0,0,0,0,0,0,0,0,0,0,0,0,154,365,0,0, +0,0,0,0,0,0,0,340,0,0,0,0,0,810,0,0,0,0,0,0,495,0,0,0,0,0,0,0,0,0,261,0,535,248, +0,358,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,567,445,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,697,0,0,0,1336,0,0,0,0,0,0,0,0,917,174,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,972,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,351,0,0,0,0,0,0,0,0,0,0, +0,0,0,286,0,0,56,438,0,0,0,0,0,1950,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,738,0,0,0,0,0, +0,0,0,0,0,969,2047,0,0,0,0,0,0,0,818,0,0,0,0,0,0,0,866,0,0,0,0,0,0,0,1467,0,0,0, +0,0,0,0,0,0,0,0,0,0,972,0,355,0,0,0,116,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,267,189,104,0,0,0,0,1613,0,0,0,0,0,0,0,116,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,886,0,86,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,45,0,0,863,0,0,0,0,0, +0,0,1953,450,1773,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,381,0,0,0,0,0,0,0, +0,0,0,0,0,1142,0,1189,0,0,0,663,0,0,0,0,0,0,0,846,0,0,528,0,393,378,0,0,0,0,0,0, +325,899,680,1880,0,1770,0,0,0,0,0,648,0,0,0,0,0,0,185,167,0,2046,0,0,0,0,0,0, +249,1645,0,152,0,0,0,1733,0,0,0,0,0,1006,0,0,0,0,0,420,0,0,0,832,0,0,0,0,0,351, +0,0,0,0,6,40,0,0,60,0,0,0,0,1354,745,724,0,0,0,0,0,0,0,0,772,1951,275,108,639,0, +0,0,0,0,0,0,0,0,500,1758,0,0,0,0,0,0,0,0,0,0,0,1886,711,205,0,0,965,865,0,0,0, +534,0,0,0,0,691,0,0,0,237,443,0,878,0,0,0,0,0,1410,0,0,0,0,0,0,0,0,0,0,0,0,0, +995,0,0,0,0,0,0,0,0,0,0,0,0,0,578,0,0,0,0,881,0,0,0,0,0,0,0,0,822,0,923,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,924,0,0,0,665,0,0,0,0,0,1901,0,0,0,0,0,950,498,93, +0,0,0,1451,0,0,0,0,0,747,828,788,400,184,0,198,0,0,0,0,0,0,0,0,0,0,0,994,0,0,0, +0,0,0,0,0,615,320,0,0,0,978,843,905,0,0,0,0,0,0,0,0,850,974,0,0,0,0,6,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,509,0,0,0,0,0,273,0,0,0,0,0,0,0,0,0,0,0,0,0, +201,0,0,0,1041,0,0,0,1040,0,0,0,0,0,0,0,0,0,693,234,774,0,336,0,1399,22,0,805, +802,777,167,789,0,0,1705,0,0,0,0,0,0,0,0,0,0,0,10,13,11,0,0,204,264,0,0,56,0,0, +1917,0,470,0,0,0,0,0,0,0,0,0,0,0,1198,0,0,0,0,0,0,0,0,0,0,1015,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,715,0,0,1002,0,0,0,298,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,867,0,0,724,0,0,0,0,0,0,0,0,0,0,0,0,768,0,0,0,0,0,1066,0,0,0,0,67,0,174,948, +0,0,0,0,0,0,0,0,0,0,0,0,0,764,0,0,0,0,75,137,0,756,0,0,0,0,0,0,1008,842,643,0,0, +0,67,0,0,0,0,0,0,0,0,0,0,0,135,821,0,0,0,0,0,0,0,0,736,0,389,355,0,0,786,0,0,0, +0,0,0,2044,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1030,0,0,0,1083,0,0,0,0,0, +1226,0,0,0,0,356,319,8,389,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,474,0,0,0,427, +0,413,0,730,0,0,0,0,0,373,0,0,0,0,0,0,0,0,0,799,0,0,0,1793,0,0,0,322,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,290,2,0,0,0,0,0,0,0,0,0,0,672, +699,1860,0,0,0,737,0,0,0,1612,0,0,0,0,0,0,0,0,0,0,0,145,124,884,0,0,0,0,0,387,0, +0,0,0,0,0,0,0,0,0,0,679,0,550,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1305,0,0,0,0,0,0,0, +576,0,0,0,0,0,0,0,686,0,607,0,0,37,0,0,0,0,0,0,0,0,0,101,1726,0,0,0,0,0,958,0,0, +0,903,0,0,0,0,147,0,0,0,0,0,0,0,0,0,0,0,367,0,0,0,0,690,0,705,273,0,0,887,0,0,0, +0,0,0,0,0,0,0,0,90,0,0,0,0,0,0,0,908,0,0,0,0,0,0,0,1261,0,0,497,1235,0,429,0,0, +0,0,904,0,12,125,0,0,0,841,0,0,0,0,0,860,946,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,768,0,770,160,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,271,0,0,0,0,0,0,0,719,0,699,581,0,0,0,0,0,0,0,0,0,0,862,304,0,631,0,0,0,0,880, +1513,0,0,0,0,0,981,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,434,0,0,0,0,0,550,0,0,476,930, +824,553,0,0,452,0,151,0,0,0,0,0,0,772,0,292,135,0,0,0,0,0,0,0,504,0,0,1089,0,0, +0,0,0,0,0,0,0,0,0,783,0,0,0,0,0,0,206,393,0,0,0,0,0,0,0,0,232,912,0,0,0,0,0,977, +0,0,716,98,0,0,0,0,0,733,0,0,0,0,0,0,0,0,19,0,0,0,0,668,0,360,0,0,0,0,0,0,656,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,726,0,0,0,0,0,0,0,0,0,0,0,0,72,0,0,1269,0,0,463,0, +0,0,0,0,0,1454,0,1287,245,0,989,0,0,0,0,0,0,0,0,0,107,164,0,0,0,0,0,0,0,1061,0, +0,0,0,2,484,0,0,0,0,0,0,0,1127,0,0,0,0,0,0,0,460,0,0,0,0,0,932,0,0,0,0,0,0,0, +588,625,0,0,0,0,76,92,0,0,0,0,0,0,0,0,0,0,0,0,0,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +763,0,622,0,0,0,253,0,546,0,0,110,0,256,916,0,0,35,212,0,0,746,0,0,0,150,0,0, +1466,0,0,0,1299,0,0,0,0,0,0,0,0,0,1518,0,0,0,0,0,0,0,0,0,0,0,0,0,1229,0,0,0,816, +0,0,0,0,0,0,159,0,0,0,0,0,734,869,126,1716,0,0,0,0,0,0,202,232,0,0,0,0,212,0,0, +0,0,0,111,1003,0,0,0,0,0,0,0,0,0,0,0,1712,0,0,216,0,0,0,0,516,0,0,0,0,0,650,0,0, +0,0,57,99,0,0,0,0,300,574,0,0,0,0,1023,0,0,302,0,1871,0,728,252,0,0,461,0,0,0, +323,0,0,0,0,0,0,775,461,0,0,0,0,0,0,172,0,0,464,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,73,727,0,1023,0,0,0,0,0,0,0,0,0,0,577,0,0,0,0,0,0,0,0,1037,0,0,0,0,0,0, +0,0,280,677,0,0,0,0,0,0,0,0,0,0,0,799,0,0,0,0,159,0,446,1730,0,0,0,0,0,0,0,0,0, +395,0,0,0,0,145,0,0,0,0,0,0,0,20,0,0,426,608,0,0,0,0,0,977,0,250,0,0,0,0,0,100, +0,0,0,0,1982,0,0,0,0,0,476,0,0,0,0,0,0,594,76,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,447,0,0,0,0,526,0,0,14,1124,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,188,0,0,0,0,0,0,0,0,362,301,0,0,0,1743,0,178,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,872,0,831,0,0,208,202,0,0,0,0,0,0,0,1954,0, +0,0,0,516,872,0,0,313,224,0,0,24,0,11,546,0,0,0,1937,242,241,46,0,0,0,830,1273, +0,0,0,0,0,0,0,825,327,1006,0,0,0,0,0,1580,516,366,0,0,0,0,0,1736,0,0,0,0,0,0,0, +0,0,0,0,1935,0,826,0,0,0,0,139,331,0,0,0,0,0,0,0,0,0,0,0,288,0,916,0,0,0,0,0, +1888,0,0,0,0,0,0,0,1471,0,1570,0,394,0,0,0,0,0,0,0,1931,0,1719,0,658,228,0,0,0, +0,0,374,0,0,0,0,735,0,0,0,0,0,0,323,498,0,1063,0,0,0,0,155,0,0,0,0,0,0,0,0,906, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1139,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,108,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,616, +902,0,0,0,0,0,692,0,0,0,0,0,0,823,0,0,0,305,0,0,0,0,0,0,0,681,0,0,0,0,0,214, +1004,0,0,0,0,0,0,0,23,0,0,1703,0,0,0,0,0,0,0,0,0,1443,0,0,19,714,0,0,0,0,64,737, +0,0,345,1758,0,0,579,47,0,0,539,139,0,0,0,0,388,0,0,0,0,253,0,0,0,0,0,0,252,0, +745,0,0,0,0,0,0,0,0,0,0,0,504,107,0,871,0,0,0,229,0,0,0,0,0,903,0,0,71,0,0,549, +6,47,0,0,0,0,0,0,0,0,0,980,865,705,0,0,0,161,0,0,0,0,143,1331,0,0,0,1388,33,724, +0,0,0,19,0,0,0,395,0,0,0,0,0,846,210,0,0,0,122,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,695,937,497,0,0,0,0,0,718,0,0,0,0,0,0,0,1581,0, +0,0,0,0,0,161,49,0,0,0,0,0,0,0,0,0,597,0,0,0,1094,0,0,0,811,908,0,0,0,0,0,0,0,0, +0,0,1471,0,0,0,0,0,0,0,0,0,0,42,1935,0,0,0,2014,66,2007,0,0,586,0,0,0,0,0,0,0,0, +0,28,1077,0,0,0,1221,0,0,62,0,0,0,0,0,0,0,0,0,0,1766,0,0,0,0,0,0,0,0,0,0,0,0,25, +0,499,1388,0,0,97,10,0,0,0,0,0,481,0,0,0,0,0,0,0,0,0,0,37,134,155,486,0,1442,0, +0,0,0,0,591,0,0,0,0,0,0,310,1173,0,0,0,0,409,1156,0,0,0,482,0,0,263,926,0,0,0,0, +0,0,0,0,0,0,0,0,0,804,0,0,0,0,0,0,0,0,0,0,0,0,0,1265,0,415,0,348,0,0,0,1012,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,165,1803,0,0,0,0,0,0,0,408, +0,0,0,0,0,0,257,1321,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1138,0,0,0,249,0, +0,0,576,0,0,0,0,231,0,0,0,288,0,0,0,0,0,0,0,0,0,433,1487,569,1678,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,87,0,0,0,0,0,779,538,0,0,0,413,0,0,0, +0,0,0,0,0,0,0,495,0,0,0,0,0,191,54,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,530,567, +0,0,0,0,0,1484,0,0,0,0,0,0,815,609,0,0,0,0,0,484,0,0,0,0,0,0,0,0,0,0,900,0,0,0, +0,1335,0,1724,0,0,0,0,0,0,0,0,0,0,0,640,0,0,0,0,0,0,0,0,0,0,0,1831,0,0,0,0,0,0, +0,0,0,0,0,0,0,474,0,0,0,0,0,0,0,0,0,1103,0,1504,655,1034,0,0,0,0,0,305,0,0,0,0, +0,0,0,0,0,1236,0,0,429,217,0,0,0,0,739,278,0,0,0,0,0,0,0,708,0,0,0,0,0,1840,233, +0,0,0,0,0,0,0,0,2017,0,0,0,0,0,1488,0,0,0,1590,0,0,0,0,0,1800,28,0,0,0,0,0,0,0, +0,0,45,0,36,0,22,1442,378,0,0,0,0,0,0,1507,0,0,0,0,0,0,0,0,0,0,39,0,0,1054,725, +1955,0,2036,0,0,0,0,0,0,0,0,0,0,896,1871,0,0,0,0,0,0,0,0,0,0,805,0,0,0,0,2046,0, +0,0,0,17,712,0,617,55,320,271,0,0,0,0,0,0,0,0,0,445,0,184,103,0,0,0,0,0,0,0,0, +659,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,676,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +337,0,0,0,506,0,0,0,0,0,843,77,0,458,0,0,0,0,0,1420,382,109,142,330,0,0,0,0,0,0, +0,0,0,0,0,0,87,0,0,0,492,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1239,0,0,0,0,0,0, +211,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1049,0,321,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,1985,0,0,122,0,0,234,0,0,0,1098,0,0,0,0,0,0,549,253,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,522,131,0,0,149,0,0,0,0,0,0,0,0,0,0,0,0,0,0,507,0,0,0,0,811,630,0,0,0,343, +0,0,0,0,0,448,591,455,0,1381,0,0,0,0,0,0,0,575,0,0,0,0,0,1175,0,0,0,0,0,0,0,0,0, +653,0,0,0,1761,0,1198,0,0,0,0,297,1127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,678,0,0, +164,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,35,0,45,0,0,0,0,0,121,0,0,0,0,0,0, +0,0,125,0,0,0,1622,0,0,0,0,0,721,145,0,0,0,970,792,0,0,0,715,0,0,0,0,0,1999,0,0, +74,531,0,0,65,0,0,0,105,220,0,0,0,0,0,0,0,960,0,0,0,0,0,0,428,19,0,0,401,96,0,0, +0,0,0,1595,116,0,1021,0,0,0,0,0,750,1961,0,0,148,0,0,0,0,0,0,0,0,0,0,0,0,0,75,0, +0,1383,0,0,0,0,0,0,0,0,0,0,0,0,0,0,779,0,0,0,0,0,0,0,0,598,0,424,0,0,0,0,0,0,0, +1222,0,0,0,876,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,133,0,0,0,0,187,0,8,0,0,0,0,0, +0,0,429,0,685,0,0,0,0,0,0,0,0,0,0,0,132,472,0,0,0,0,0,0,0,0,0,938,0,0,874,0,0,0, +0,0,774,0,0,0,0,0,92,0,0,0,0,0,0,830,701,0,0,0,0,0,426,350,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,603,59,0,0,0,0,0,0,0,0,0,0,293,0,0,0,0,0,0,0,0,0,0,0,0,0,0,441,163,4,0, +0,0,0,0,0,0,0,0,806,0,0,0,0,0,0,233,0,0,0,0,1994,0,1739,0,0,393,0,47,1038,0,0,0, +309,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,363,0,0,0,175,0,0,0,0,0,0,0,666, +0,0,1675,0,1600,0,0,0,808,0,0,0,0,0,0,0,0,0,0,0,280,54,0,0,0,0,0,0,0,0,421,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,249,0,0,103,254,0,262,1,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,805,0,0,0,0,0,0,0,0,0,1630,0,0,0,0,0,0,0,0,0,0,0,0,0,671,972,989,0,0, +0,0,0,0,0,889,0,0,0,1382,0,0,0,0,0,0,0,775,0,0,0,0,0,0,0,0,0,0,388,202,0,0,0,0, +16,560,0,0,0,841,0,0,566,0,0,0,938,0,0,0,0,0,0,0,0,0,0,912,0,0,0,1361,0,0,0,0,0, +0,618,236,0,1854,0,0,318,190,0,1376,0,0,0,0,0,0,0,349,0,0,0,0,951,1972,0,0,0,0, +0,0,344,0,0,0,0,0,0,0,0,850,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,910,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,163,85,0,487,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,145,0,83,0,0,1013,0,0,0,1922,0,0,169,557,66,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,1193,82,0,352,454,57,0,0,1333,396,107,0,370,0,0,0,0,0,0,0,0,0,204,0,0,0, +0,0,1706,0,0,0,0,0,0,0,0,0,0,0,0,394,1204,0,0,0,0,0,1007,0,0,0,1696,0,1519,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,981,0,0,0,0,1072,0,0,0,712,0,1629,0,0,0,0,0,0,0,728,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1271,0,0,0,1608,16,0,0,0,0,485,0,0,0,0,0,0, +153,27,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1991,0,0,0,0,0,0,0,0,52,0,21,0, +0,0,0,0,0,0,0,0,819,0,0,0,0,0,917,0,0,0,0,784,0,0,0,0,135,0,0,0,0,0,454,0,0,0,0, +0,0,0,0,0,852,1719,0,0,0,0,0,852,0,0,0,0,0,952,0,0,0,0,568,0,0,0,0,0,448,0,0,0, +67,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1826,657,0,729,666,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +669,0,0,0,0,0,0,0,402,0,0,152,0,0,0,0,912,0,0,0,0,0,0,51,320,0,445,0,0,0,0,308, +0,0,0,0,0,386,0,0,239,0,0,130,83,0,143,0,348,0,0,0,0,0,0,0,958,0,0,0,0,0,210,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,430,0,0,0,0,0,0,0,0,0,0,0,0,7,213,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,801,0,0,0,0,0,0,0,0,0,936,0,108,0,0, +0,0,0,0,0,0,0,885,587,219,398,364,0,1165,0,0,342,241,303,0,0,0,0,0,0,0,0,0,0, +1454,0,0,0,0,0,0,0,0,0,0,254,562,0,786,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1294,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,493,216,0,0,0,0,219,341,0,0,0,0,0, +0,0,0,0,0,130,1734,154,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,701,604,0,0,879,0,195, +666,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1669,0,0,0,1791,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1228,0,0,0,0,0,623,0,0,0,0,0,0,0,798,0,0,0,0,0,0,0,0,0,0,0,0,84, +122,0,0,0,837,0,0,0,0,0,0,1013,0,0,577,0,0,0,460,932,0,0,0,0,0,0,0,0,0,0,0,31, +131,0,0,0,605,0,0,0,1246,0,0,0,0,68,278,165,307,781,0,0,0,0,0,0,33,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,1113,0,0,720,1953,203,0,0,0,0,0,0,0,425,326,0,0,0,0,0, +0,0,0,0,0,241,1316,0,0,0,0,0,416,0,0,0,1300,0,847,0,0,662,358,0,0,0,0,839,1823, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,654,1522,0,0,0,0,0,0,163,0,0,0,0,0,314,978,0,0,0, +601,0,0,0,0,0,946,434,0,0,0,402,411,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,1467, +410,0,0,0,0,0,0,0,0,0,0,0,0,0,0,483,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,677,0,0,0,0,0,0,0,0,0,0,0,0,70,0,0,0,0,1405,0,0,0,0,0,0,108,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,777,0,0,0,0,0,747,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,505,0,326,0,0,164,628,654,0,0,0, +37,32,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,668,152,0,0,0,0,0,0,0,0,0,0,0,581, +0,0,0,0,44,126,89,0,0,0,0,0,0,0,0,1531,0,0,0,0,0,0,0,0,203,1167,0,0,0,0,0,0,0,0, +531,1232,0,0,0,0,0,943,0,670,231,880,0,1617,0,0,0,1957,0,0,0,0,0,0,0,975,0,0,0, +0,0,0,0,0,0,0,0,242,0,0,0,0,0,0,0,0,0,421,0,0,14,834,0,0,0,0,0,0,0,0,0,0,0,0, +465,0,0,0,0,0,834,688,413,855,0,0,0,590,0,0,0,0,0,0,0,0,114,0,0,0,0,0,0,0,0,0,0, +0,45,169,0,0,0,0,0,0,0,0,0,0,0,198,0,0,565,585,0,0,0,0,0,0,0,0,0,0,0,0,0,691,0, +0,0,593,0,0,0,0,0,0,0,0,0,913,116,0,0,0,0,1360,0,0,0,802,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,673,308,0,709,1006,1895,0,228,0,0,0,1840,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,608,0,0,0,0,0,0,0,0,0,1573,0,2039,136,540,0,0,0,0,0,0,0, +897,0,0,938,1878,0,0,0,0,0,0,0,0,0,1469,0,999,0,299,0,0,0,0,0,0,0,578,0,0,0,0,0, +456,0,0,0,1679,163,693,0,0,0,0,0,0,48,755,0,0,0,0,0,0,0,0,0,0,0,0,338,0,0,0,0, +1091,0,0,0,0,695,0,0,1464,0,0,0,0,0,975,0,0,335,0,0,1979,0,0,0,0,269,1566,630, +396,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1815,634,0,0,0,966,0,0,0,0,0,0,0,9, +412,0,958,0,0,579,382,0,212,0,0,0,0,965,681,0,0,16,0,0,0,0,0,0,0,0,0,0,0,0,655, +0,0,0,0,67,0,0,0,0,0,0,751,0,0,0,0,423,231,0,0,1016,300,0,0,0,0,100,237,0,0,0, +1370,0,0,0,1208,0,0,0,0,0,1219,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,199,0,0,427,0,0, +0,0,949,665,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,712,0,0,0,0,0,1186,0,0,0,0,0,0,0,0,0,0,295,312,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +151,0,0,0,0,588,4,0,0,0,0,0,414,104,0,0,757,263,0,561,0,0,0,320,0,0,0,0,0,0,0,0, +0,0,0,225,0,0,0,0,37,817,0,974,0,0,0,0,0,0,0,0,0,0,0,0,0,2026,131,235,16,0,590, +1157,0,0,0,0,0,0,0,0,221,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,140,390,0,0,0,0, +0,0,0,1144,0,0,0,464,0,0,0,0,0,0,0,0,0,0,0,0,204,407,303,1218,0,0,0,0,5,325,0,0, +0,0,12,800,0,1783,0,0,0,0,0,0,0,0,0,0,504,621,0,0,0,0,0,0,0,0,0,920,0,376,0,0,0, +0,0,218,580,0,768,454,0,0,0,0,0,0,0,0,0,0,0,0,676,0,0,0,0,0,0,164,0,0,0,0,0,0,0, +0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,120,285,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,226,343, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,29,0,0,1812,0,0,8,0,0,0,21,1125,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,1327,0,0,0,0,575,1598,0,0,0,0,0,0,0,0,0,895,0,0,0,959,0,0, +0,0,0,1759,173,0,0,0,0,266,261,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,1427,0,0,300,1033,0,0,0,0,0,0,0,0,0,0,0,584,0,0,0,0,52,734, +0,0,217,239,0,1129,0,0,0,0,0,0,0,0,732,20,0,0,0,0,0,0,0,0,0,0,0,418,0,0,0,613,0, +0,0,0,0,0,0,0,0,632,0,0,85,984,0,0,0,0,909,694,7,1109,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,167,0,0,0,0,280,62,0,0,33,0,0,359,186,980,0,0,0,0,0,0,0,0,0,0,0,585,0,0,0, +211,0,0,336,145,0,1130,0,873,0,0,840,263,0,0,0,0,0,0,0,0,0,916,0,0,0,0,0,0,0,0, +0,0,155,0,0,0,461,97,0,0,0,0,0,1356,0,0,0,0,0,0,0,593,0,0,0,0,0,1392,0,0,0,0, +126,0,0,0,0,1179,0,0,0,0,0,162,0,0,0,0,0,765,0,187,0,1286,0,0,0,0,0,0,0,0,0,635, +0,0,23,215,0,0,0,1306,0,0,97,716,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,657,0, +0,0,0,0,0,0,0,299,0,0,0,0,0,0,134,0,0,0,0,0,0,0,0,0,0,0,658,1082,0,0,0,0,0,2002, +0,0,0,0,0,0,833,248,0,0,0,0,0,1654,0,0,531,0,0,0,0,0,0,634,0,0,0,0,0,0,0,0,0, +853,573,249,0,0,0,0,0,0,0,0,527,0,0,0,0,1419,0,0,0,0,0,0,20,49,0,0,0,992,0,0,0, +728,0,0,0,0,0,0,0,0,0,0,0,0,497,1579,0,0,0,0,62,268,0,0,0,0,0,0,0,1201,0,0,0,0, +0,0,0,0,0,0,0,0,495,193,0,0,0,0,106,0,0,859,0,0,23,0,0,0,0,0,0,0,813,925,0,0, +223,613,953,0,0,0,0,0,0,0,0,666,0,0,0,0,0,0,0,0,0,670,0,0,40,216,0,0,0,0,0,0, +259,0,0,0,440,1114,0,0,0,0,0,0,0,0,74,475,0,0,188,139,0,797,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,1572,0,0,0,0,39,0,0,0,0,0,0,0,0,0,0,0,0,1594,0,0,0,0,0,0,0,290,0,232, +0,0,887,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,521,14,0,0,0,0,0,741,0,0,0,992,0, +0,0,0,0,0,0,0,111,0,0,425,0,0,0,0,0,789,0,0,0,1593,0,1768,0,0,233,0,0,0,0,943,0, +0,0,0,0,0,0,955,225,245,0,0,0,0,0,0,241,0,0,0,0,1943,0,0,0,1284,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,709,0,0,0,0,0,0,554,0,0,0,0,0,0,0,0,1564,0,0,0, +443,0,0,0,0,0,0,280,0,0,0,0,0,0,0,0,729,0,0,0,348,0,0,0,0,0,0,0,758,848,298,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,829,1422,189,121,0,0,632,812,0,0,556,0,0,0,0,0,436,172, +530,844,232,984,0,0,0,0,0,0,0,0,0,0,147,0,0,0,0,0,0,0,0,537,0,0,0,0,0,859,0,0, +842,0,0,0,0,0,0,0,0,0,0,1291,0,0,0,0,0,0,0,0,0,0,0,1482,612,392,0,0,0,262,31,0, +0,0,0,0,0,0,0,0,0,753,549,0,0,0,0,0,0,696,0,0,0,0,0,0,0,834,0,0,0,0,0,771,0,0,0, +0,0,0,0,0,0,0,0,0,0,921,0,0,0,674,0,0,0,0,0,0,0,0,0,0,308,444,0,0,0,0,0,0,805, +180,0,0,278,271,0,0,214,505,0,1215,0,0,0,0,0,0,387,271,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,1645,42,92,0,459,0,0,330,1557,0,0,0,0,0,0,0,0,113,18,0,0,0, +1742,0,0,0,965,0,0,0,0,0,0,0,0,0,0,0,0,0,182,0,0,65,0,0,0,0,0,0,0,0,0,0,0,0,973, +0,0,0,0,0,328,0,0,588,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1786, +0,0,962,1985,0,0,0,308,508,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,588,0,0,0,0,0,0,614,793,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,290,0,0,0,0,0,0,0,0,0,0,1136,0,0,0,0,0,0,0,0,0,0,796,719,0,0, +326,210,0,0,0,701,758,472,0,0,0,1947,278,1079,0,0,0,0,0,0,497,41,0,0,634,46,961, +0,810,524,0,0,33,0,0,0,0,0,0,0,0,0,0,0,0,532,0,997,0,0,0,0,0,0,0,0,0,0,0,1301,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1298,0,671,0,0,0,306,0,0,0,0,0,0,0,0,0,0, +693,1823,0,0,0,759,0,0,0,0,0,1932,0,0,0,0,0,0,0,0,0,0,0,0,0,0,88,182,0,0,0,1964, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,521,0,0,0,0,0,0,424,857,0,0,0,0,671,328,0, +529,0,0,0,0,0,716,0,1509,80,67,0,0,0,0,59,141,0,0,0,0,0,0,783,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1498,0,0,0,0,343,430,803,1183,677, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1357,53,0,0,0,0,590,0,0,0,0,0,0,0,0,0,0, +0,0,0,329,0,0,0,0,0,0,0,469,0,0,0,0,0,0,0,0,0,0,460,0,0,1743,0,0,963,340,0,0,0, +0,0,1603,0,0,250,0,0,0,0,0,646,218,0,1794,0,0,0,571,0,455,0,0,0,1012,0,0,0,0,0, +0,0,0,0,0,0,0,597,161,0,349,0,524,0,0,0,0,0,0,0,0,0,0,0,0,322,432,0,0,0,0,0,0, +325,223,0,0,0,0,0,566,0,0,0,1394,481,436,0,48,457,610,756,618,0,0,0,755,0,1217, +0,0,0,0,0,197,0,0,0,0,0,0,0,0,0,0,0,0,0,0,544,492,107,414,0,0,0,0,0,0,0,0,0,0,0, +1007,0,0,0,0,5,0,0,1580,0,0,0,0,0,0,0,0,0,0,0,0,0,673,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,1843,0,0,0,0,0,0,0,0,0,165,0,0,0,0,0,0,809,885,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,498,0,0,0,306,9,0,0,0,0,0,0,0,437,721,146,0,0,0,0,0,0,0,0,0,0,0,177,0,0,0,0, +0,0,0,1377,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,200,0,959,0,0,0,1928,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1435,0,481,0,0,0,0,0,0,142,84,0,0,0,0,0, +1015,0,0,0,315,0,0,0,0,0,0,759,0,0,0,0,0,0,0,0,712,0,0,0,1722,0,0,0,0,0,0,0,0,0, +0,0,0,222,0,985,1414,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1273, +538,706,0,0,0,0,0,0,0,0,115,0,0,0,0,0,0,0,0,0,0,1781,0,0,0,0,0,431,97,665,42, +237,0,0,0,264,0,0,213,0,0,0,0,0,0,0,455,0,0,0,906,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +624,0,574,0,0,0,0,0,0,0,0,0,0,0,0,354,0,0,0,1558,0,0,0,0,0,0,0,0,0,0,0,0,0,0,68, +235,723,1813,0,0,0,957,0,830,0,0,0,0,0,0,0,0,0,0,0,0,23,0,0,496,0,0,0,0,0,0,0, +547,239,88,0,0,0,0,0,0,0,0,0,1310,0,0,0,0,0,0,0,0,80,1076,0,0,118,0,0,0,479,274, +0,0,0,0,0,0,0,0,0,0,0,497,0,0,669,261,0,0,0,0,13,0,0,0,0,0,0,791,250,642,0,0,0, +1429,939,949,0,0,0,0,0,0,0,0,0,0,0,0,0,818,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,982,330,0,0,0,0,545,0,0,0,0,0,0,947,0,1188,0,0,0,0,0,904,0,0,0,0,0,1372,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,693,377,0,0,0,0,0,0,0,0,0,0,0,0,0,0,695,0,0, +713,386,0,0,0,0,128,1575,0,0,0,0,0,0,424,893,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,904,0,0,0,0,0,552,322,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28,1808,49,0,0,0,0, +1832,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,421,0,0,442,415,0,0,289, +0,0,0,0,0,206,110,0,0,0,0,0,205,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +19,1539,0,0,0,0,0,1340,0,1194,0,0,0,0,0,0,0,0,549,0,0,0,0,0,0,0,0,1720,0,0,0,0, +0,0,0,0,0,319,0,0,0,0,112,1180,0,0,0,0,0,0,0,0,0,0,0,967,0,0,0,0,0,0,0,0,0,1940, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,735,0,0,0,0,0,0,0,0,0,897,132,0,0,0,0,0,0,0, +0,0,0,38,838,0,0,0,379,218,8,660,1017,0,0,0,0,0,0,111,387,647,877,0,0,53,790,0, +0,0,0,0,0,0,0,458,0,0,0,0,0,0,954,0,0,0,394,0,1367,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,882,0,0,0,0,0,0,0,1409,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,38,124,342,199,0,0,0,0, +0,0,0,0,0,0,724,628,0,0,0,0,804,266,0,0,0,0,0,208,0,79,0,0,0,0,0,0,0,0,741,0,0, +0,0,0,0,0,0,0,0,606,0,1494,821,1553,0,0,135,405,0,0,178,100,0,0,0,0,0,0,0,0,0,0, +0,0,0,481,0,0,0,1378,0,0,0,0,0,0,0,0,0,0,0,0,0,791,33,1227,857,0,467,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,447,0,0,0,0,0,0,86,128,0,0,0,0,0,0,587,0,0,0,692,1018,0, +195,0,0,0,0,0,0,0,1546,0,0,0,0,0,0,0,0,0,0,0,684,0,0,345,0,0,0,0,0,0,365,0,1683, +0,0,472,0,433,0,0,0,0,0,0,0,28,0,0,0,997,0,705,3,0,0,0,0,0,0,0,0,0,229,0,0,0,0, +102,0,0,0,0,866,1022,0,0,0,0,0,0,0,0,0,55,0,115,0,0,0,0,933,0,0,0,0,0,0,0,702,0, +0,0,0,0,0,0,1728,26,484,0,0,0,185,618,417,0,803,0,0,0,0,0,0,0,0,0,0,0,1262,0,0, +0,0,0,0,0,0,0,0,0,0,0,633,0,0,0,0,0,0,0,0,0,0,0,0,0,479,262,0,0,0,0,0,0,830,0,0, +0,0,26,70,0,0,0,0,0,0,0,0,217,0,640,51,0,0,360,1586,0,0,0,0,0,652,0,0,0,0,0,766, +0,0,0,0,298,737,0,0,0,0,0,0,0,0,0,0,655,222,906,0,0,1013,991,2009,0,0,0,0,503,0, +0,0,216,154,0,0,0,716,0,844,0,0,0,0,621,252,0,0,0,0,748,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,103,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,0,576,0,0,0,648,0,0,0,331,0,0,0, +0,0,0,0,0,0,0,0,0,632,0,0,0,518,107,0,0,0,0,0,0,0,0,851,0,0,0,0,504,0,0,0,0,0,0, +0,0,0,0,0,0,7,883,0,0,0,0,0,0,0,922,0,0,0,0,0,0,0,0,91,993,0,0,0,0,0,0,200,131, +10,0,0,0,0,0,0,0,0,0,0,0,0,0,365,1433,0,0,0,0,28,103,0,0,798,1013,0,0,0,0,0,0,0, +0,39,1925,0,853,0,0,271,519,0,0,0,0,338,0,0,300,470,419,0,0,0,0,0,0,836,0,0,0,0, +0,0,1937,0,0,0,0,0,393,0,0,357,0,0,0,0,0,703,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,387,0,0,0,0,0,0,75,708,453,1351,0,303,0,0,772,0,0,0,0,0,0,0,0,749,0,0, +0,0,0,0,0,0,0,0,0,0,0,1065,0,0,717,226,0,0,0,0,0,890,431,626,0,0,0,0,706,0,0,0, +51,698,0,0,0,0,0,0,0,0,0,0,0,828,0,0,17,0,0,0,0,1929,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,84,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,871,498,0,101,1793,0,0,0,0,0,0,435,0, +0,0,0,0,966,0,129,1644,0,0,0,0,0,0,0,0,0,0,0,0,0,997,502,0,0,0,0,0,0,0,0,0,0,0, +0,823,0,1927,0,0,0,0,98,1756,0,0,0,0,0,0,0,0,0,0,0,0,8,0,160,1046,0,492,0,0,0,0, +0,0,129,45,0,0,0,0,0,0,353,558,0,0,0,0,0,785,0,0,0,1145,189,0,0,0,26,353,0,0,0, +0,0,2024,0,0,0,606,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,32,855,0,0,0,0,0,0,0,0,0,0,0, +0,0,2011,0,0,5,4,0,0,461,764,0,0,0,1449,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1445,0,0, +0,1168,0,0,0,233,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,255,0,0,216,0,0,0,286,0,0,0, +3,0,0,0,723,536,0,0,0,0,0,285,0,0,0,560,0,0,0,0,0,690,0,0,0,0,0,1246,0,0,63,0, +33,0,0,0,0,0,520,1862,0,0,0,0,0,0,0,0,0,0,0,0,630,0,0,0,0,554,0,0,0,0,0,1001,0, +0,0,0,0,446,0,0,0,0,0,0,0,1313,0,0,837,636,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,278, +0,0,0,0,0,0,0,0,868,0,0,0,0,1010,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1231,0,304,0,506,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,26,0,93,1408,794, +843,704,0,285,114,485,898,145,0,19,2035,0,0,0,1933,0,0,0,0,0,0,0,1728,0,0,0,0,0, +0,0,0,746,0,0,0,0,0,0,0,995,1964,0,0,0,0,0,0,0,0,0,0,0,1550,0,874,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,1018,0,0,0,814,126,0,0,1264,0,0,814,955,0,0,0,0,0,0, +0,981,0,0,0,0,0,0,0,0,915,56,0,0,100,0,0,0,0,0,0,0,0,0,638,0,0,0,0,738,0,0,0,0, +0,0,0,0,0,758,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1112,0,0,214,0,0,0,133,0,196, +168,0,0,0,0,0,1152,0,1245,0,0,538,169,871,1816,0,0,413,133,0,0,0,978,0,0,43,93, +371,0,0,0,0,0,0,526,25,0,754,335,0,0,0,0,182,0,0,0,0,0,0,0,0,0,0,0,39,601,0,0,0, +0,0,0,0,181,370,0,0,1652,358,0,0,0,0,0,0,0,0,0,176,286,0,788,0,0,0,0,0,1223,780, +254,1003,896,0,0,0,1447,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,744,0,0,0,0,0,126,0, +41,788,0,0,0,629,0,0,0,0,0,0,0,0,0,0,0,293,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,420,37,1900,0,0,0,0,542,1570,957,0,0,0,0,0,0, +0,373,31,0,0,0,0,125,325,0,0,0,0,0,0,323,0,0,1547,0,0,0,0,0,0,0,0,0,0,0,0,0, +1216,0,0,0,0,0,0,198,1905,629,15,0,0,0,0,0,0,20,75,543,1353,0,0,0,533,0,0,6,0,0, +0,0,0,0,538,0,0,0,0,0,0,0,0,0,0,0,338,0,0,0,0,11,0,0,0,284,659,0,989,0,0,0,0,0, +0,0,0,0,848,0,0,507,0,0,0,0,0,0,0,0,188,991,884,0,0,0,0,60,959,0,0,0,0,0,1653,0, +0,922,337,0,638,0,0,500,0,0,0,0,0,0,0,0,0,0,0,166,0,0,0,0,0,0,0,0,0,0,0,0,418,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,760,0,0,0,0,0,0,1277,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,770,0,0,0,0,0,0,0,243,89,0,0,0,0,0,0,0,0,0,1396,0, +560,0,0,3,1658,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,586,0,0,1271,0,0,0,505,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,637,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1947, +41,445,0,0,0,0,0,0,0,0,57,189,0,0,371,0,0,0,0,552,0,883,0,923,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,875,0,0,0,1788,49,0,0,0,0,0, +0,0,0,0,0,0,661,0,0,1945,0,0,0,0,0,794,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,1135,0,0,0,745,0,0,0,0,0,0,0,84,0,0,0,0,0,0,0,410,0,976,0,0,0,0,0,703,0,0, +0,0,0,0,187,322,0,0,0,227,0,0,0,0,560,0,31,1395,0,0,0,0,0,466,0,0,0,0,643,167,0, +0,0,1428,0,412,0,0,0,0,0,0,0,0,0,1118,562,0,0,0,0,0,256,0,0,0,0,0,0,1771,0,0,0, +0,0,1190,132,0,66,0,0,0,0,0,0,0,0,0,0,317,0,0,0,63,0,0,0,0,0,0,0,1475,0,0,0,0,0, +0,0,288,0,0,0,0,608,0,0,0,0,0,0,0,0,1225,0,1189,0,0,0,0,0,0,0,1468,0,0,0,0,0, +689,120,0,0,0,0,0,0,0,1,0,329,0,0,0,0,226,0,0,0,0,0,1855,0,0,461,0,0,0,0,1346,0, +0,0,0,0,85,0,0,299,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1171,0,0, +0,980,0,0,0,0,0,0,0,0,637,279,0,0,0,0,0,293,0,0,0,0,528,17,0,0,0,0,5,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,48,0,0,0,0,0,0,0,601,0,0,0,0,0,0,779,0, +196,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1322,737,752,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,412,192,80,0,0,8,1470,0,0,0,0,0,0,0,0,0,873,0,0,0,0,0,835,0,0,0,0,256, +38,986,0,0,0,0,0,0,0,0,0,91,257,278,911,0,0,0,0,0,0,0,0,749,151,0,0,0,0,0,0,0,0, +0,0,0,0,989,0,0,990,0,0,90,194,0,0,0,0,0,425,0,0,0,0,0,774,0,0,0,0,0,0,0,0,0,0, +646,827,752,0,0,0,662,0,22,21,0,0,0,0,0,0,95,239,0,0,0,431,0,0,0,0,0,874,0,0, +265,65,0,0,0,1350,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1887,0,0,0,0,0,0,0,809, +0,696,0,1074,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,630,0,0,802,0,0,0,56,776,0, +970,0,0,797,0,0,0,0,0,400,0,0,1951,0,0,41,0,11,118,0,0,0,0,0,0,0,0,251,615,0,0, +0,1044,0,0,0,0,0,0,0,0,0,0,0,225,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,370,0,0,0,0, +104,48,209,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,930,0,0,0,0, +0,0,0,0,0,0,0,1286,0,759,0,120,385,0,0,0,429,0,0,0,0,0,0,0,0,820,0,0,0,0,0,0, +199,0,10,151,0,0,0,761,365,0,0,0,0,0,0,0,0,0,46,1086,0,0,0,0,11,1624,58,344,0,0, +1008,1868,0,0,0,888,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,711,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,440,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,914,1913,0,958,0,885,0,0,0,0,0,0,0,0,0,0,0, +0,0,847,276,0,302,65,0,0,0,510,0,1514,0,0,0,0,0,0,152,291,0,0,0,0,0,0,0,0,0,0,0, +0,282,589,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,463,42,0,0,0,0,0,372,0,0,0,0,0,0,0, +0,0,680,0,0,0,0,0,0,0,0,977,1997,0,0,0,810,0,0,0,0,0,0,0,0,0,1390,0,0,0,644,0,0, +867,982,0,0,0,0,0,0,0,540,0,123,0,0,0,1978,0,0,0,0,789,623,0,1723,0,1220,0,0,0, +0,0,0,0,480,0,0,0,0,0,0,0,0,0,0,0,888,0,0,0,0,0,0,0,0,0,0,0,0,299,1995,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,788,179,0,0,0,0,0,0,431,156,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1373,39,80,196,0,0,507,0,0,0,646,0,0,0,0, +0,1214,0,0,0,0,926,0,0,0,1,114,0,0,0,0,0,446,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,490,0,0,0,491,0,1584,0,0,507,250,0,0,0,158, +10,362,1,0,0,0,0,0,0,0,0,0,408,228,860,480,0,779,0,0,0,557,0,0,142,197,0,0,0,0, +0,0,0,0,0,0,0,1490,11,378,316,1057,0,0,18,579,299,1546,0,177,0,0,0,0,0,0,0,0,0, +411,0,0,0,0,727,439,0,0,0,0,0,1528,0,0,0,0,0,0,58,0,482,0,0,0,505,1952,0,0,0,0, +0,0,0,0,0,0,0,242,0,0,0,0,0,0,0,953,0,0,0,0,802,0,0,0,0,0,0,0,0,0,0,290,0,0,791, +52,0,0,0,0,0,0,0,0,0,0,0,112,0,0,0,0,0,1028,0,0,138,0,0,0,0,1811,0,0,0,0,0,0, +934,1821,0,0,0,0,371,38,0,0,0,1296,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,723,0,0,0,0,0, +0,0,0,0,0,0,0,0,1330,0,0,0,0,0,0,0,1255,296,109,0,0,0,0,0,660,0,0,0,0,270,591,0, +0,0,0,0,0,0,1090,81,0,0,0,0,391,0,0,0,0,249,322,0,0,0,0,0,0,0,1412,0,0,0,0,0,0, +0,0,0,0,526,632,0,0,0,0,0,0,235,144,0,0,0,0,0,940,0,0,0,52,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,309,196,0,0,0,0,0,1912,0,1290,0,686,0,0,625,0,0,0,0,0,0,0,0,0,0,0,412,0, +0,0,0,43,0,0,0,0,11,967,758,0,0,0,0,0,0,0,0,0,0,0,0,0,0,220,0,0,0,0,0,0,0,0,0,0, +873,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,890,0,0,2,0,0,0,0,0,0,0,0,1774, +393,263,0,0,0,0,0,0,818,456,0,0,251,178,393,97,0,0,0,0,0,674,168,0,0,0,0,0,0,0, +159,1639,0,0,0,0,0,0,0,0,59,934,0,191,0,0,0,0,346,165,0,877,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,128,0,0,0,0,0,0,1297,0,0,0,0,0,0,164,0,0,0,15,132,241,1073,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,228,324,53,0,0,910,0,0,0,0,0,0,0,0,734,705, +217,73,0,0,0,0,0,0,0,0,636,389,0,1409,0,0,0,0,0,893,0,0,0,0,21,0,0,0,0,0,0,0,0, +0,0,0,0,0,721,0,0,0,959,0,0,0,0,1433,0,0,0,0,0,0,0,0,0,0,0,0,174,189,0,0,0,0,0, +0,0,0,0,0,22,2,0,0,815,354,0,0,0,0,425,0,411,60,13,1611,0,0,0,0,0,0,0,0,0,0,0,0, +0,1478,596,0,0,398,0,50,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,192,1159,0,0,0,0,0, +592,223,0,0,0,0,0,0,0,245,64,0,0,0,0,278,0,604,0,0,1502,265,0,0,0,0,0,0,0,310, +1763,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,1356,0,0,0,0,0,0,0, +0,505,0,0,0,0,0,0,0,1000,0,0,966,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,839,0,0,0,0,0,0, +0,0,0,0,0,0,0,637,0,0,0,0,0,0,0,0,0,0,0,0,0,0,590,0,0,0,0,280,0,0,0,1386,0,0,0, +281,0,1064,0,0,0,0,0,917,0,0,15,555,0,0,1014,1883,0,0,0,965,0,0,117,33,0,0,0, +801,0,0,0,0,0,877,0,824,0,0,0,0,0,0,0,0,0,0,0,365,0,0,0,0,0,0,774,7,0,430,0,0, +231,360,0,0,0,0,0,0,0,0,822,740,0,0,929,1485,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,852,0,0,0,0,17,0,0,0,0,0,0,1001,0,0,0,0,35,831,0,0,384,457,0,0,0,1351,0,27, +0,0,984,0,264,552,0,401,0,0,0,710,0,1211,0,0,11,205,0,0,0,0,0,0,0,0,0,0,0,0,5, +579,0,717,0,0,1011,0,0,0,0,0,0,0,0,0,0,0,0,0,0,805,0,0,0,0,0,0,0,0,0,0,0,489,0, +0,0,1024,0,0,0,0,0,0,0,0,0,892,0,0,0,0,0,0,0,0,0,0,0,0,473,0,0,0,659,864,0,0,0, +0,0,0,152,819,0,51,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,229,0,0,0,0,674,0,0,0,0,0, +0,0,0,0,770,52,79,0,0,0,1666,0,409,0,0,0,0,0,0,0,195,0,688,0,0,0,0,0,0,0,0,0,0, +0,889,174,160,0,0,0,0,0,0,0,0,0,0,0,0,0,872,0,918,569,268,0,0,0,1224,0,1361,0,0, +0,0,0,0,0,0,0,374,0,0,0,0,0,731,0,0,0,0,190,0,0,0,0,0,0,0,202,506,444,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,835,0,17,1526,0,0,0,0,0,477,0,0, +994,1374,76,0,0,0,0,0,0,0,355,287,0,1389,0,0,0,0,0,0,455,384,0,0,0,264,0,0,0,0, +0,0,0,0,0,0,0,0,1001,0,0,0,0,0,0,0,0,0,0,0,0,28,0,0,0,851,175,359,0,0,0,0,0,0,0, +0,287,740,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,857,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +819,1402,0,0,0,0,0,0,174,224,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1649, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,655,573,0,0,0,0,0,0,0,0,128,351,0,0,0,0,0,0, +0,0,0,0,0,918,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,687,0,0,0,0,0,0,0,0,0,1525, +0,0,0,1009,0,0,0,0,0,0,0,340,0,0,0,0,0,0,0,0,0,0,861,0,176,0,0,0,0,0,0,0,0,0,96, +985,0,615,0,0,0,0,0,0,0,1919,0,0,0,0,0,1131,0,0,0,0,0,0,0,247,0,0,0,0,27,23,0,0, +0,0,0,0,0,0,38,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1015,0,0,0,0,0,1088,0,0, +0,0,0,1585,0,0,0,0,227,0,0,0,478,360,0,0,0,95,0,0,0,0,0,0,699,0,0,0,26,0,0,0,0, +1119,0,0,0,739,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,741,67,0,0,0,0,0,0,464,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42,0,96,0,0,0,26,342,0,0,0,0,0,0,203,0,0,449,0, +0,0,0,0,0,0,0,0,0,256,311,0,0,0,0,0,0,758,0,0,0,0,0,0,0,0,827,0,0,0,0,581,64,0, +1047,0,0,0,0,0,288,0,0,0,0,0,1375,0,0,0,0,0,0,0,0,0,0,0,1309,0,0,0,0,0,0,0,0, +376,12,0,0,0,0,0,154,0,1520,0,1753,95,502,0,0,0,0,0,0,0,269,291,1197,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0,0,0,1341,0,1017,0,0,0,0,0,0,0, +0,857,1810,533,0,0,1453,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,836,211,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,19,0,156,0,0,0,0,1009,0,0,0,0,0,0,0,0,0,0,0,0,0,820,0,0, +0,0,0,0,0,0,0,228,0,0,0,1131,0,1276,0,0,0,0,0,0,0,0,0,0,0,0,849,1792,0,0,389, +291,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,525,0,0, +0,453,0,0,0,0,666,0,0,0,422,0,355,0,0,0,0,165,0,260,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,865,0,0,0,0,0,0,0,1625,0,0,0,234,0,1383,0,0,0,0,0,0,0,0,306,0,0,0,802,1921, +0,0,0,0,0,0,180,0,0,0,0,1312,814,0,0,0,0,0,0,0,0,0,0,707,0,0,0,1493,11,61,733,0, +0,0,341,0,0,0,98,0,0,0,0,0,0,0,0,0,0,0,1014,0,0,0,0,0,0,0,142,102,0,0,30,0,0, +823,0,1045,0,0,0,1930,0,1512,0,0,0,0,0,0,0,87,0,1243,245,0,0,0,0,0,0,0,48,68,0, +0,0,0,0,0,0,0,126,77,625,938,0,0,351,0,0,0,174,1668,0,707,0,0,0,0,0,0,0,0,0,0,0, +403,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,282,0,0,0,0,0,0,8,44,0,0,363,115,0,0,0,0,0,0, +0,0,0,0,0,0,545,761,0,0,835,1254,0,0,0,0,930,1936,0,0,0,0,0,0,0,0,653,0,0,0,0,0, +344,0,0,1483,673,185,0,0,460,93,753,478,0,0,0,0,0,1020,0,0,0,0,0,0,0,103,0,0,0, +499,0,0,0,0,0,0,207,0,0,0,0,0,0,0,0,0,0,0,0,0,0,96,0,968,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,3,0,0,0,0,399,0,0,0,0,224,563,0,0,0,0,0,704,0,0,0,0,0,0,0,0,0,0,0, +1559,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,861,0,0,0,0,946,333,746,0,0,0,0,0, +0,0,910,0,0,0,0,0,0,0,0,0,0,0,0,0,652,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1393,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1514,0,0,0,0,201,0,510,717,0,0,528,0,0,0,0, +20,0,0,0,1251,0,0,0,1163,0,0,0,307,0,0,0,0,0,1091,0,0,0,0,0,0,0,0,0,0,0,429,0,0, +0,881,0,0,0,0,0,621,0,0,0,0,0,0,0,736,0,348,0,868,0,0,0,0,433,0,0,0,771,1495,0, +0,0,0,215,0,0,0,0,0,124,0,0,0,0,0,0,0,0,0,0,0,55,0,0,0,0,0,0,0,112,62,0,856,270, +0,572,0,0,0,0,939,0,0,0,0,0,0,0,352,0,0,0,0,0,0,0,0,0,647,0,0,0,0,10,0,0,0,0,0, +0,0,220,0,0,0,0,0,0,0,0,0,0,0,0,0,464,0,0,109,0,0,0,1746,0,0,0,515,0,0,0,566,0, +0,0,0,0,0,67,40,0,0,722,992,0,0,923,0,0,0,0,0,0,1145,0,0,0,0,0,0,0,0,0,0,0,568, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,247,0,0,0,0,645,0,0,328,0,0,0,0,0,0,0,0,0,0,0,0, +1363,0,0,0,0,0,1280,0,0,0,0,0,0,0,0,0,0,7,28,360,162,0,0,0,0,0,0,0,0,0,0,0,764, +0,0,833,862,0,856,0,0,0,0,0,0,736,92,0,0,948,1944,0,1479,63,590,0,0,0,1521,0,0, +0,709,0,0,61,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,483,0,0,0,0,1213, +0,0,0,0,29,1022,0,1712,0,466,0,0,0,0,0,0,0,0,0,0,0,0,0,731,0,0,0,0,0,0,171,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,241,0,0,0,0,0,0,0,0,0,0,0,964,2005,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,1100,0,0,0,954,0,0,0,0,0,0,0,0,0,1958,0,0,34,549,994,0,0,449, +137,850,0,0,670,146,0,0,0,0,518,159,0,0,0,0,0,0,0,0,151,0,0,1027,0,0,0,0,0,0,0, +0,0,0,983,0,0,0,0,993,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,141,501,0,0,0, +0,0,0,0,0,0,452,0,0,0,0,0,0,0,0,0,0,233,149,0,0,0,0,0,0,0,0,582,0,0,0,801,0,0,0, +0,0,0,70,0,0,369,0,36,0,0,0,0,0,0,0,204,721,430,241,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1817,16,1078,1021,0,0, +406,0,0,0,0,0,69,0,0,0,0,0,1830,0,0,0,824,0,0,0,0,0,0,0,0,0,826,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,816,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1000,717,1845,0,423,0,0, +0,0,0,0,0,0,510,0,0,1048,0,0,0,618,0,0,0,520,0,0,0,0,990,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,321,0,0,0,0,0,0,0,1135,0,0,921,0,0,0,24,397,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,856,0,0,0,139,282,981,0,288,0,0,0,1890,651,56,0,0,0,0,0,0,0, +0,261,0,0,0,0,0,0,0,0,0,0,0,617,1403,0,1205,0,0,563,0,0,0,0,0,0,0,0,333,0,0,0,0, +0,369,0,0,0,0,0,0,0,0,0,622,0,0,0,1407,0,0,0,0,0,0,0,0,0,0,0,0,624,160,0,363,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,619,0,174,292,0,0,656,616,0,0,0,685,0,0,0,0,0,0,0,0,0,0,0,0,0,647,0,0,0,631,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1267,0,0,0,1797,0,0,0,1684,0,0,469,0,531, +1230,73,0,0,0,0,0,0,0,0,0,268,0,0,0,0,0,102,558,109,65,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,595,0,0,0,0,0,374,1832,0,0,0,0,0,0,16,0,405,6,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,881,0,1495,0,0,0,0,0,0,0,0,0,142,0,0,0,0,0,0,0,0,0,0,21,466,23, +257,0,0,0,0,0,0,77,404,0,0,0,0,0,0,712,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,860, +1848,0,0,652,629,0,0,0,0,13,377,0,1842,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1501,0, +0,0,1906,0,0,0,0,0,0,0,0,0,0,0,0,0,491,234,171,0,0,0,0,631,1186,0,0,0,0,0,0,0,0, +0,0,0,0,931,0,170,0,0,0,0,0,0,0,0,0,0,1587,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +765,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,424,0,0,714,0,0,0,0,685,0,0,0,0,0, +0,285,0,0,0,0,0,0,429,0,0,0,0,0,0,0,0,0,0,71,18,0,0,0,0,0,0,0,0,0,0,116,828,0,0, +0,0,0,0,289,0,0,0,0,0,0,0,0,675,0,0,0,1424,0,0,0,0,0,647,0,0,0,1334,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,36,209,0,0,0,0,0,0,0,342,0,0,0,928,0,0,0,0,0,1838,118,856,654, +318,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,915,895,454,0,0,513,1425,0,0, +0,0,0,0,791,0,153,0,0,0,0,0,0,796,909,445,345,0,0,0,0,0,0,0,0,578,0,0,0,1387,0, +0,0,555,0,0,0,0,0,0,766,0,0,0,0,0,0,0,0,0,0,541,0,0,0,0,0,0,0,0,0,0,0,0,0,880,0, +0,0,0,0,1506,0,0,983,0,768,0,0,0,0,584,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,737, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,226,30,426,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +117,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,462,0,0,0,385,0,398,0,0,0,0,0,0, +0,0,0,347,0,0,0,0,125,1259,644,136,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,469,0,0,0,0,0, +1367,0,0,0,0,0,0,0,0,0,0,0,719,0,0,0,0,0,0,0,0,0,0,0,0,0,1423,0,0,0,0,0,0,0,0,0, +749,0,0,0,0,546,645,0,0,0,0,0,0,277,0,0,1275,0,0,0,0,0,0,0,453,536,555,0,0,987, +1107,0,0,90,0,0,0,0,0,0,0,0,860,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +257,0,1768,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1071,0,0,0,0,0,0,0,0,0,0,0,0,0,83, +0,835,0,0,0,0,0,0,0,2006,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,696,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,95,1718,0,0,0,0,0,0,0,26,0,550,0,0,0,0,0,901,0,0,0,0,0, +0,822,0,0,122,0,0,0,807,0,0,0,0,0,262,0,620,601,34,0,0,170,0,0,0,0,537,0,0,0,0, +0,0,0,0,0,332,0,0,208,1909,182,261,0,0,0,1721,0,0,0,0,0,933,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,1609,0,895,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,812,0,0,942,1916,0,0,0,0, +0,0,0,778,0,0,0,137,0,1314,0,0,0,0,0,0,0,1661,0,0,0,0,0,0,0,1591,0,0,0,0,0,0, +820,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,185,89,0,1160,230,6,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,63,29,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1740,0,0,177, +170,0,1961,0,0,0,0,0,0,0,0,0,0,0,0,91,0,17,44,0,0,0,0,0,0,0,0,0,270,0,296,0,0,0, +0,0,0,0,1523,0,0,0,0,0,0,0,0,0,0,757,7,0,0,0,0,0,0,0,0,0,0,530,588,0,0,0,0,0,0, +0,0,0,786,0,0,0,0,0,580,627,88,447,57,0,0,0,0,0,0,0,0,845,735,0,0,0,0,0,31,15,0, +460,521,12,424,0,0,0,1302,0,0,0,0,0,0,0,595,0,0,0,13,548,97,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,1472,452,1767,0,0,0,0,0,0,0,0,0,0,115,0,0,0,0,0,0,1543,0,1111,0,0,0,0, +1,0,359,488,0,267,0,0,0,1983,0,0,0,0,0,0,0,1155,0,1575,0,1438,31,0,0,377,101,0, +0,0,0,0,0,0,0,0,0,0,0,0,476,0,0,0,0,0,0,0,0,2023,0,0,0,0,0,1836,0,0,0,0,35,843, +0,0,0,0,0,0,0,554,0,0,0,536,625,207,0,1371,0,0,0,424,785,336,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,896,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27,750,0,0,0,0,238,0,0, +0,0,0,383,0,0,0,0,0,0,0,0,603,725,11,0,0,0,0,0,0,0,0,0,476,0,0,0,0,0,1552,0,0,0, +0,0,0,0,680,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,435,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +1431,0,0,13,112,0,0,356,0,0,0,0,0,0,0,0,0,0,1963,0,0,0,1244,18,0,0,0,0,0,0,867, +0,0,0,0,0,0,50,708,73,592,0,502,0,0,0,0,0,0,161,347,0,0,0,0,470,33,0,246,571,10, +0,465,614,0,237,0,0,0,0,0,24,18,0,506,0,0,0,0,0,0,33,309,0,0,0,0,0,0,0,0,0,0, +140,0,0,0,0,1056,0,0,0,1704,0,0,0,0,0,0,0,1036,0,0,0,0,0,0,0,0,0,1315,432,86, +264,524,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,107,0,0,0,0,0,123,927,0,0,957,1149,0,0, +0,0,0,778,0,502,196,0,0,0,0,1312,0,0,0,0,0,0,0,855,0,0,0,0,0,0,0,0,0,0,45,1400, +0,0,0,1003,0,0,0,0,0,1097,0,0,0,0,0,0,0,0,545,612,0,0,0,0,0,0,0,0,0,0,0,0,54,0, +0,0,0,172,0,0,0,1029,0,0,0,0,0,0,0,0,0,568,0,0,0,732,617,0,0,974,94,989,733,0,0, +0,0,0,0,1789,0,0,665,2015,0,0,0,0,0,0,806,287,0,0,0,0,0,1539,0,0,0,0,0,0,0,0,0, +0,182,1563,0,0,0,0,0,0,0,0,0,484,0,0,0,0,0,1623,0,0,0,0,0,0,0,0,878,1833,0,1569, +0,0,0,0,0,0,0,0,93,0,715,994,0,0,0,0,0,63,0,591,0,0,0,0,0,0,0,749,0,0,0,0,547, +366,0,0,0,1747,0,0,0,0,0,0,0,89,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1463,0,772, +893,0,0,0,48,0,0,941,0,0,690,1785,106,440,0,0,0,0,0,0,0,0,0,0,32,0,332,216,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,852,0, +0,416,564,0,918,0,1764,0,0,3,0,0,274,0,0,0,0,501,0,0,0,0,0,0,0,851,743,0,49,0, +879,0,0,47,0,0,0,0,0,0,865,0,1202,0,0,0,0,0,0,47,272,0,0,0,0,0,0,0,0,0,0,0,1455, +0,0,0,0,891,1911,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,761,0,0,0,0,0,0,0,0,0,407,0, +183,0,0,490,0,0,0,0,0,0,0,35,731,0,0,0,0,0,0,0,819,0,0,0,0,0,0,0,0,0,0,0,0,0, +575,0,0,0,0,45,818,0,0,77,222,0,0,0,0,849,1880,0,0,0,633,0,1308,0,0,0,0,0,0,0,0, +0,0,86,0,0,0,0,0,0,0,0,0,0,0,0,0,0,817,0,0,0,0,0,0,0,0,0,882,0,0,0,914,0,0,0,0, +0,0,0,0,0,0,865,0,0,426,399,58,0,0,0,0,0,0,538,102,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,876,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,139,566,0,63,12,0,0,0, +0,0,0,0,0,0,0,0,0,0,3,114,0,0,0,0,0,0,0,0,576,0,0,0,0,0,0,0,0,933,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,692,0,0,0,0,0,0,0,0,0,0,0,0,752,0,0,0,0, +0,0,0,0,375,0,1011,0,0,96,0,0,0,0,0,0,0,0,0,148,0,0,0,0,0,0,0,0,0,0,0,337,56, +666,0,246,394,0,0,0,0,0,0,0,0,437,0,0,0,506,0,0,0,0,1003,0,1163,0,328,0,0,0,0,0, +0,0,0,1000,0,0,0,0,0,744,101,0,0,0,0,0,726,0,0,176,0,146,9,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,839,0,0,0,0,0,0,223,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,246,1931,29,0,0,1771,0,0,0,0,0,846,6,157,0,0,0,0,0,0,0,0,0,875,0,0,477, +773,177,639,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1747,0,0,0,0,158,873,0,659,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,391,0,0,0,0,0,0,0,0,0,0,0,0,668,883,0,78,628,0,0,0, +0,0,0,0,0,0,0,0,0,1460,0,962,0,0,0,0,0,460,0,0,0,0,0,0,0,0,0,0,0,0,0,0,34,199,0, +0,0,388,474,0,271,0,333,608,0,0,0,0,0,0,49,0,988,0,707,617,0,0,0,0,0,0,0,756,0, +0,0,0,0,1583,0,0,0,0,0,0,0,0,0,0,285,0,0,0,0,0,0,0,0,0,0,0,0,0,0,344,0,0,0,0,0, +0,0,0,515,1709,0,0,0,0,0,0,0,0,404,0,0,0,0,500,0,0,0,0,0,0,0,0,0,68,216,0,0,0,0, +0,0,0,488,353,0,0,177,236,0,0,458,490,0,0,0,0,0,0,756,1504,0,757,0,1735,0,0,108, +598,0,0,0,0}; +const BROTLI_MODEL("small") +uint8_t kStaticDictionaryHashLengths[BROTLI_ENC_NUM_HASH_BUCKETS] = { +8,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,0,0,12,0,0,0,0,4,22,5,0, +4,0,0,0,0,0,0,0,0,0,0,0,0,14,6,0,0,0,5,0,0,0,0,0,0,0,7,13,0,0,4,0,0,0,0,0,0,0,0, +0,6,0,0,0,0,8,0,0,0,0,0,0,7,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,4,0,0,0,4, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,10,4,0,5,13,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,8,7,0,0,9,0,8,0,0,0,0,0,0,6,0, +0,9,0,0,0,11,0,0,6,8,7,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,7,0,0,0,6,8,0,0,0,0,0, +0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,9,0,0,0,8,4,13,7,0,0,0,0,0, +7,0,5,0,0,0,0,8,5,0,5,0,0,8,7,0,0,0,0,0,0,0,0,0,0,9,0,0,0,8,0,0,0,10,4,0,5,0,4, +0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,8,7,0,4,9,4,0,0,0,0,0,0, +9,0,0,0,8,5,0,0,0,6,0,0,0,0,0,0,0,0,0,7,18,0,0,0,0,4,9,0,0,4,0,6,0,0,0,6,0,6,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,5,8,7,0,0,0, +0,9,0,0,0,0,0,0,0,8,6,10,6,0,0,0,4,0,6,8,6,0,0,0,4,0,0,0,0,0,5,0,0,0,6,0,0,0,0, +10,0,12,7,0,0,0,0,0,4,0,0,0,0,0,5,0,0,8,7,0,0,0,0,0,0,0,0,9,5,0,0,0,0,0,0,0,0,0, +0,0,0,0,6,11,0,0,0,0,0,0,0,0,0,8,7,0,0,10,0,0,0,0,0,0,0,0,6,10,0,17,0,8,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,8,6,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +7,0,0,11,4,0,5,0,0,0,0,0,0,0,0,0,0,10,5,0,6,8,5,0,0,0,0,0,0,0,0,0,0,11,5,0,0,0, +0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,9,0,0,0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,8,7,0,0,0,0,0, +0,0,0,0,0,0,5,0,0,0,6,0,0,10,0,0,0,20,0,0,0,0,0,0,0,0,6,9,5,0,0,0,0,10,4,8,0,0, +4,13,0,0,0,0,0,0,0,9,0,9,0,0,0,0,0,0,0,0,0,0,0,0,4,8,6,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,12,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,12,5,0,0,10,4,10,7,13, +0,0,0,0,0,0,0,0,6,0,6,0,6,0,0,0,0,0,0,19,0,0,4,12,6,9,0,0,0,0,4,0,4,11,0,0,0,0, +0,0,0,12,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,4,0,0,0,0,0,0,0,0,0,6,0,0,0,0, +0,5,0,0,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,9,6,0,0,0,0,0,4,0,4,0,0,0,0,0,0,0,0,0,4,0,0,0, +6,0,0,0,0,0,0,0,0,0,0,13,6,0,0,0,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,0,6,0,0, +0,0,0,5,0,0,0,0,14,4,0,0,0,4,12,5,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,8,6,0, +0,0,0,0,0,12,0,9,6,0,0,0,0,13,0,0,5,0,0,0,0,0,4,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,13,0,9,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,5,0,0,0,6,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,8,7,8,4,0,0,0,0,0,0,0,0,0,0,0,7,0,7,0,0,0,4,0, +0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,6,8,4,0,0,0,0,0,6,0,7,0, +0,0,0,0,0,0,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,7,0,0,0,0,0,0,9,5,0,0, +0,0,0,7,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,9,4,0,0,0,0,0,0,0,4, +12,5,11,0,0,0,0,0,0,0,0,0,8,7,0,5,0,0,8,7,0,5,0,0,0,0,8,0,0,0,0,7,0,4,10,0,0,0, +0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +13,5,0,0,0,4,0,0,0,0,0,6,0,0,0,0,0,0,14,5,0,0,0,7,0,0,10,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,6,0,4,0,5,0,0,0,0,8,5,0,0,0,0,0,0,9,5,9,0,0,0,0,0,0,0,0,6,9,0, +0,4,0,0,0,7,0,0,0,6,0,0,10,4,0,0,0,0,0,6,0,0,10,0,0,0,8,5,0,0,0,0,0,0,0,0,10,0, +0,0,0,0,18,4,12,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,8,7,0,0,0, +0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,8,4,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0, +0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,8,0,0,0,0,0,0,6,0,0,0,4,10,5,0,0,0,0,0,0,0,0,0,0, +0,4,8,7,0,0,8,6,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0, +0,0,0,8,6,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,6,0,7,0,0,0,0,0,0, +0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,8,7,0,0,0,0,8,0,12,6,0,6,0,0,0,0,9,7,11,7,0,0,0, +0,0,0,0,0,0,0,0,0,11,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,10,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0, +0,0,0,6,0,0,0,7,0,4,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,14,0,0,0,0,0,8,4,0,4,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,20,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,12,5,0,7,0,5,0,0,10,0,0,7,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,6,0,4,9,7,0,0,0, +0,0,7,0,0,0,0,0,0,10,0,9,0,9,0,0,0,0,0,0,0,0,4,9,0,0,0,0,6,0,0,0,0,0,0,0,0,11,4, +0,6,0,0,0,0,0,0,8,0,8,0,0,0,0,0,0,0,0,0,0,4,0,0,0,5,0,0,0,0,0,0,0,0,13,6,0,0,11, +0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,6,18,0,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,0, +0,5,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,6,0,0,0,0,9,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,11, +4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,4,0,0,0,0,8, +6,0,0,0,0,0,0,9,6,0,0,0,0,0,4,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,0,0, +0,6,0,6,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,6,0,6,0,0,10,6,0,0,0,7,0,0,8,0,8,7,0, +0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,9,0,0,0,0,6,0,0,0,0,0,0,0,5,0,0,18,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0, +0,0,0,8,7,0,0,0,0,0,0,0,0,12,0,12,0,0,0,11,6,0,5,0,0,12,0,12,5,0,7,11,6,0,0,11, +0,0,0,12,0,0,4,12,7,8,6,0,0,0,0,8,5,0,0,0,0,0,0,0,4,11,0,0,6,0,7,0,0,0,0,0,0,0, +5,0,6,0,0,0,0,8,0,10,0,0,0,0,0,0,0,0,0,0,0,9,7,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0, +0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,0,0,10,0,0,5,0,0,12,6,0,0,0,0,0,0,10,6,0,0,0,0,8, +6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,5,0,0,0,0,11,0,10,6,0,0,8,6,0,0,0,6,0,7,10,6,0, +0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,10,7,0,0,0,0, +10,6,0,0,0,0,0,0,8,5,11,0,8,4,0,0,0,4,0,0,0,0,9,4,8,0,0,0,0,0,0,0,11,6,0,0,0,0, +10,7,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,7,0,0,0,0,9,6,0,5,0,7,0,0,0,0,0,7,0,0,11,0,0, +0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6, +0,0,0,0,13,0,8,6,13,0,0,0,11,7,0,7,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,6,0,0,9,6,0,6,0,0,0,0,0,5,0,0,0,0,0,0,0,0, +0,0,0,0,0,5,9,0,0,0,0,0,0,0,0,0,0,4,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,9,7,0,7,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0, +5,11,5,0,0,0,0,0,0,0,0,0,4,0,7,0,6,0,0,0,6,20,0,0,0,10,7,0,5,14,4,0,0,0,0,0,0,0, +0,0,6,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0, +0,0,6,0,4,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,11,6,15,0,0,0,0,0, +10,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,7,0,0,0,0,0,0,0,0,9,7,13,0,0,0,0,0, +0,7,0,0,8,6,0,0,0,0,0,0,0,0,9,4,0,0,0,0,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,5,0,0,0,0,0,0,0,0,0,0,0,0,8,5,0,4,0,0,0,0,0,0,0,0,0,0,12,6,8,0,12,0,0,7,0,0,0, +0,0,5,10,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7, +14,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,8,7,10,7,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,18,6, +14,7,0,0,0,0,0,0,0,0,11,6,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,11,7,0,0,10,7,0,0,0,6,8,6,0,0,0,0,0,0,0,6,0,0, +19,0,0,0,9,5,0,0,0,0,0,0,11,7,0,0,0,7,0,6,0,0,11,0,0,0,0,4,8,0,0,0,0,0,0,0,0,6, +0,0,0,0,0,6,0,0,8,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,7, +0,7,0,0,0,7,15,0,0,5,0,0,0,0,10,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,7,0,0, +0,0,0,0,0,0,9,6,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +11,7,0,0,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0, +0,0,5,0,4,0,0,0,4,0,4,0,0,0,0,0,0,0,0,0,6,0,0,0,0,11,6,0,0,8,5,14,0,0,4,0,0,0,7, +17,0,0,0,0,0,0,0,13,5,0,0,0,0,0,5,0,0,0,5,0,0,0,0,16,6,0,4,0,0,0,0,0,0,12,0,0,0, +0,0,0,6,0,0,0,0,0,0,0,0,0,0,12,5,0,5,0,6,10,0,12,0,0,0,0,0,0,0,0,7,0,0,0,0,8,4, +0,0,0,0,0,0,0,0,0,0,8,7,0,0,8,0,0,0,8,0,0,6,0,7,0,0,0,5,0,6,0,4,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,22,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0, +0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,18,0,0,0,9,4,0,0,8,0,9,7,0,0,0,0,0,0,8,6,0,0,0,0, +0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,9,7,0,0,0,6,0,0,14,0,0,0,0, +0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,7,10,4, +0,6,0,0,0,0,0,0,8,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,9,6,0,0,0,0,0,0, +0,0,11,6,12,7,0,0,0,0,0,0,0,6,0,5,0,0,0,0,0,0,9,6,11,6,0,0,0,0,9,5,0,0,0,0,0,0, +0,6,8,5,0,0,0,0,8,0,10,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9, +5,10,7,0,0,0,5,8,7,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,4,8,7,0,0,0,6,0,0, +0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,22, +0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,5,0,0,0,0,0,0,0, +0,0,0,0,0,17,0,0,6,0,6,12,4,19,6,0,0,0,0,16,0,0,0,0,7,15,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,4,10,4,0,0,8,7,0,7,0,0,9, +4,0,6,0,0,0,4,0,5,0,0,0,7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,7,10,0,0,0,0,0,11,7,0,0, +0,0,12,6,0,0,0,0,0,0,0,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8, +0,0,0,0,0,0,0,0,0,10,4,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,8,7,0,0, +0,0,0,0,0,6,0,0,0,4,0,0,11,4,0,0,12,7,0,0,0,0,9,0,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0, +4,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,0,0,9,4,0,6,0,0,0,0,0,4, +0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,6,0,0,0,5,0,0,0,0,0,0,0,0,0,7,9,6,0,7,0, +0,0,0,0,0,0,6,0,0,0,0,8,6,0,0,0,0,10,6,11,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,5, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,5,0,4,8,0,0,0,0,0,9,7,0,0,0,0,0,0, +13,5,0,0,0,0,8,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,8,5,0,0,11,7,0,0,0,0,0,0,8,6,0, +0,0,0,0,7,0,4,0,0,0,0,0,0,0,5,0,6,0,5,0,0,0,0,0,0,0,0,0,0,0,0,10,4,9,0,0,0,0,0, +0,4,0,0,0,0,10,5,10,7,0,0,0,0,0,0,0,0,16,7,0,0,0,0,0,7,0,0,0,0,11,0,0,0,0,0,0,0, +0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,5,0,4,0,0,0,7,0,0,0,0,0,0,13,0,0, +0,0,0,0,0,0,0,0,7,0,4,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,13,7,0,7,0,4,16,0,0,0,0,6,8,7,9,7,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0, +0,6,0,0,8,5,0,4,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,5,11,7,0,0,11, +0,0,0,0,0,9,5,0,4,0,0,0,0,9,7,8,6,0,0,0,0,0,0,10,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0, +0,7,0,0,0,0,0,0,0,0,0,0,0,4,10,6,0,7,0,0,0,0,0,0,0,5,0,0,0,0,0,0,10,7,10,0,0,0, +0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,7,0,6,8,7,12,4,0,0,0,0,0,0,0,5,14, +0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0, +6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,4,0,0,20,4,0,0,0,7,0,6,0,0,0,0,0,0,0,0,8,0, +0,6,15,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,12,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,5,0,0,0,0,0,0,8,6,0,0,18,0,0,0,10,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,9,6,0, +6,0,0,0,0,0,0,0,0,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,9,0,9,0,0,4, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,9,5,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,10,0,0,0,0,7,0,0,0,0,0,0,0,0,0,7,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,0,8,0,0,0,16,0,0,0,0,0,0,0, +0,0,0,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,8,0,0,0,11,0,0,0,0,0,0,0,0,0,0, +6,0,0,0,0,11,0,0,0,9,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,7,0,7,0,6, +0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6, +0,0,0,0,0,0,0,6,0,0,18,0,8,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,7,0,4,0,0,0, +0,0,0,0,0,0,0,8,0,0,0,0,0,16,0,0,0,0,0,16,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,18,0,0,0,0,0,0,0,0,0,9,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,4,0, +0,0,0,0,0,0,0,9,4,0,0,0,0,12,5,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,12,5,0,0,0,0,0,0,0,5,0,0,10,6,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,9,0,0,0,11,0,0,6,0,6,0,0, +0,7,0,0,0,0,0,0,8,0,0,0,0,6,0,0,0,0,0,0,19,0,0,0,12,0,9,0,0,0,0,0,10,7,0,0,0,0, +0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,16,7,12, +0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,12,6,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,10,5,0,0,0,0,0,0,0,4,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,7,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,4,0,0,0,0,0,0,0,4,0,0,9,0,0,0,8,0,12,4,0,0,0,0, +0,4,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,5,0, +0,0,0,0,0,13,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,0,0,0,0,8,6,0,6,0,0,0,0,0,0, +0,4,0,0,0,0,0,6,0,0,9,0,0,0,0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,0,0,10,6,0,0,0,0,8, +6,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,7,0,0,0,0,0,7,0,6, +10,7,0,0,10,5,11,6,0,0,0,0,0,7,16,0,0,0,0,6,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,5,0,0,0,7,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0, +0,0,0,0,0,8,7,0,0,0,0,11,6,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +8,7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,12,7,0,7,0,0,0, +0,0,0,0,6,0,0,0,0,9,0,0,0,23,0,0,0,0,0,10,5,0,0,0,0,0,0,0,0,0,4,0,0,11,7,10,0,0, +0,0,0,0,0,0,0,0,0,0,6,0,0,8,7,0,7,0,0,8,7,8,0,0,0,0,0,0,0,0,0,0,0,14,5,0,0,0,0, +0,0,0,0,18,6,8,7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,11,0,0,0,9,7,12,6,0,0,0,0,0,0,0,0, +0,0,12,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,7,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,6,8,7,0,0,0,6,10,0,0,0,9,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,6, +10,7,0,0,0,7,0,0,8,4,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,0, +0,0,0,8,7,8,6,0,0,11,7,10,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,4,8,7,0,0,0,0,0,0,0,0, +0,5,0,0,13,0,0,0,0,5,0,0,9,7,0,0,0,0,0,0,0,4,0,0,11,0,0,7,0,0,0,0,0,0,0,0,0,6,0, +0,0,0,0,0,12,7,19,0,8,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,10,6,8,0,0,0,0,0,0,0,0,0,0, +6,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,7,0,0,12,0,0,0,0,6,9,6, +14,0,0,0,0,0,0,6,0,5,0,0,8,7,0,0,0,6,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,4,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,5,0, +7,0,0,10,0,9,7,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,12,6,0,0,0,0,0,5,0,6,0,0,0,0, +0,0,0,0,0,0,0,6,0,0,0,0,9,7,0,0,0,0,0,0,11,6,0,0,0,0,0,0,0,0,0,0,11,7,0,0,13,7, +0,0,0,0,0,0,0,0,12,0,0,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,6,11,5,0,5,13,0,8,0, +0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,11,5, +9,6,0,0,0,4,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,10,0,0,0,8,5,0,0,9,0,0,0,8,7,9,0,0,0,0,0,0,0,0,7,0,6,0,0,0,0,0,0,0,0,0, +0,11,0,13,6,0,0,9,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0, +0,0,0,0,0,5,21,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24,5,0,0,0,0,0,0,0,0,10,0,8,0, +0,6,0,0,0,4,0,0,9,0,0,0,0,0,0,0,0,0,0,4,0,0,8,6,0,6,0,7,10,0,8,4,0,4,0,0,0,0,0, +5,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,6,12,0,0,7,0,0,0,5,0,0, +0,0,0,0,0,0,0,6,0,0,8,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +15,7,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,24,7,0,0,0,0,0,0,0,0,0, +7,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,6,0, +0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,4,12,0,0,7,0,0,0,0,0,5,0,0,0,0,0,0,0,0,15,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,8,0,0,0, +0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,9,0,9,6, +0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,8,4,0,7,0,0,0,0,0,0,0,0, +22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,4,0,7,0,0,21,7,0,7,9,6,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,8,0,0,6, +0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,23,0,0,0,0,7,0,0,0, +4,0,0,0,0,0,0,0,0,9,4,11,7,0,5,0,0,0,0,11,0,0,4,20,0,0,0,0,0,0,0,0,0,0,0,11,5,0, +7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +21,0,0,0,0,0,0,7,0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,11,6,0,0,0,0,0,0,0,0,9,6,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,5,0,4,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0, +0,0,0,10,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,8,7,0,0,11,7,0,0,0,0,0,0,0,4, +0,4,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,8,7,0, +0,0,0,0,0,0,0,0,6,0,0,21,6,0,0,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,14,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,8,0,0,7,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0, +0,0,0,8,7,0,0,11,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0,0,0,7,13,7,10,4,0, +0,0,6,0,0,0,0,0,0,0,0,0,5,10,0,0,0,0,0,0,5,0,0,0,7,0,0,0,0,0,0,8,4,0,0,0,0,0,6, +0,0,0,0,0,0,0,0,0,0,12,7,0,6,0,0,10,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,6,0, +0,0,0,0,7,0,0,8,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,10,5,0,6,0,0,0,0,0,4,0,0,0,0, +0,0,0,0,0,4,0,0,0,0,9,0,11,4,0,0,0,6,0,0,0,5,12,7,0,5,0,0,0,0,0,4,0,0,0,7,0,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,13,6,10,0,0,0,17,0,0,4,0,0,0,0,0,6,0,4,0,5,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,11,7,0,0,0,7,0,0,0,6,0,0,0,0,0,0, +0,6,0,4,0,0,0,0,8,0,0,0,0,5,0,0,0,0,0,4,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,9,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,12,0,0, +0,0,7,0,0,0,0,0,0,0,0,0,0,0,7,0,0,16,4,0,0,11,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +8,7,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,8,6,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10, +7,0,0,0,0,0,0,9,0,0,0,0,0,0,0,12,5,10,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0, +5,18,7,0,0,14,0,0,0,0,0,0,0,9,4,0,7,0,0,0,0,0,0,0,5,0,0,0,6,0,0,0,6,0,0,0,0,0,0, +8,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0,0,0,7,0,0,0,0,0,0,11,0,0,0, +10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,14,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +11,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,14,6,0,0,0,0,11,4,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,10,7,0,6,0,0,9,0,9,5,0,0,0,0,0, +0,0,0,10,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,8,5,0,0,0,0,0,0,0,0,0,0,11,4,0,6, +0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,12,4,0,6,8,6,0,0,0,0,0,0,0,0,0,0,8,0,0,5,0,0,0,0,0,0,0,7,0,0,13,0,0,0,0,0,0,0, +0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,12,7,0,6,0,0,0, +0,0,0,0,0,0,0,0,0,13,4,0,7,0,0,0,7,0,7,0,0,0,0,0,0,0,0,10,4,0,0,0,0,0,0,0,0,0,0, +9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,10,6,21,5,0,0,0,0,8,0,0,0,0,4,0, +7,0,0,0,0,0,0,11,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,4,0,0,0,0,0,0, +0,7,9,6,11,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,7,10,0,0,0,0,0,0,6,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,19,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,18,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,7,0,0,0,0,0,0,9,4,10,4,0,7,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,9,7,9,7,10,4,0,7,0,0,0,0,0,0,0,6,12,0, +0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0, +0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,8,0, +0,0,0,0,0,5,0,0,8,7,0,0,0,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0, +0,0,0,0,4,0,0,8,0,0,6,0,0,0,7,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,7,9,7,0,0,0,4,8,0,0,0,0,6,11,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,10,0,0,0,0,0,0,0,13,4,0,0, +12,6,0,6,0,0,0,0,8,7,0,7,0,0,0,0,0,6,0,0,0,0,0,0,12,6,0,4,0,0,0,0,0,0,0,0,0,0,9, +7,22,0,0,0,0,4,0,0,0,0,0,6,0,0,0,4,0,0,9,0,0,6,0,0,24,7,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,10,6,0,5,0,0,0,0,0,0,0,7,0,0,8,0,0,0,0,0,0,0,10,5,0,0,0,0,0,0,0,0,0,7,0, +7,0,0,0,0,0,0,13,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,0, +0,0,0,0,0,7,12,0,9,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,8,0,0,0,0,0,0,0,0,4,0,0,0,7,0, +0,0,0,8,7,0,0,0,0,0,0,0,0,0,4,18,0,0,0,0,0,10,0,0,5,0,0,11,0,0,0,0,0,0,5,0,6,0, +0,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0, +4,0,0,0,0,0,0,10,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0, +0,0,0,5,8,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,20,7,0,0,0,0,0,0,0,0,0,0,0,4,9,0,12, +6,8,0,14,7,0,5,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,0,0,10,0,0, +0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,9,6,0,7,12,0,0,0,0,4, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7, +0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,4,0,0,9,0, +12,6,0,5,0,0,0,6,0,4,0,6,0,0,0,0,0,0,0,0,10,7,0,0,0,0,0,0,8,0,0,0,0,4,0,0,0,0, +10,0,0,0,0,0,0,0,8,6,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,0,0,0,0,0,0,0,0,0,0,0, +6,0,0,12,6,20,5,0,0,0,0,0,0,0,0,0,0,0,0,9,5,0,5,0,0,0,6,13,7,0,0,0,0,15,6,0,0,0, +6,0,0,13,7,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,5,0,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0, +10,6,0,0,0,0,0,6,0,0,0,0,9,0,0,0,0,0,19,6,0,0,0,0,0,0,0,0,0,0,13,0,11,0,0,0,0,0, +0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,0,0,10,0,0,6,0,0,0,0,8,0,0, +0,9,0,15,4,0,6,0,0,0,0,0,6,12,0,0,0,0,0,0,0,14,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0, +0,0,0,0,0,8,7,0,0,0,0,0,6,10,0,0,0,0,0,0,0,0,7,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,10,5,0,0,0,0,8,0,0,0,0,4,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,6,12,0,0,0,10,7,0,5,0,6,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,6,0,4,0,0,0,0,0,7,0,0,0,0,0,0,0,4,9,6,0,0,0,7,0,0,0,0,0,0,0,0,8,6,0,0, +0,0,0,0,0,4,12,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,7,0, +0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,12,6,0,6,9,4,0,0,8,4,0,6, +0,0,0,0,0,4,0,0,0,0,0,0,0,6,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,8,0,0,6,13,4,0,5,8,0,0,0,0,0,0,0,8,0,0,0,10,5,0,0,9,0,0,0,0,0,0,6,0,0, +24,0,0,0,0,0,0,0,8,0,0,7,0,0,12,0,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0, +6,8,0,10,0,9,7,0,0,0,5,0,0,0,0,0,0,0,4,8,5,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,0,4,0,0,0,0,0,6,0,0,0,0,0,5,0,0,0,0,8,0,0, +0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,10,4,0,0,0,0,0,0,0,6,0,0,0,4,20,0,0,7, +10,6,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,0,0,0,9,6,0,0,0,0,0,0,0,4, +12,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,9,4,0,5,0,0, +0,0,0,0,0,6,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,6,9,0,0,0,0,7,0,0,0,0,0,6,0,5,0,0,0,0,0,0,0,0,9,0,0,0, +0,6,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,17,7,0,0,13,6,14,6,0,0,0,0, +8,0,0,0,0,0,0,7,12,7,8,7,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,4,0,0,0,0,0,4,0, +0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,12,4,0,0,10,7,0,0,0, +0,0,0,10,0,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,12,0,0,6, +0,0,0,0,0,0,0,0,8,7,12,0,0,0,0,0,0,6,0,6,0,4,0,0,18,6,0,0,0,6,0,0,0,0,0,6,10,6, +0,0,0,0,0,0,8,7,14,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19, +0,0,0,8,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,8,7,0,0,10,5,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0, +0,0,9,4,8,0,0,0,0,0,0,4,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,4,0,0,0,0, +0,6,0,0,9,7,0,0,0,0,0,5,0,0,0,0,8,7,0,0,14,0,0,0,0,6,0,0,0,0,0,0,9,6,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,5,0,7,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0, +0,0,0,6,0,0,0,6,0,4,0,0,0,0,0,4,0,0,0,0,12,0,0,7,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0, +0,12,0,16,6,0,0,0,0,0,0,11,7,0,4,8,7,0,0,0,0,0,6,0,0,0,0,16,0,0,0,0,6,0,0,0,0,0, +0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,10,7,0,0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0, +0,0,10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,13,4,0,0,10,0,0,0,0,0,0,0,0,0,19,0,0,0, +0,0,0,0,0,0,0,0,0,0,8,6,22,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0, +5,0,0,0,0,0,5,0,0,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +4,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,7,0,0,18,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,14,7,0,0,11,5,0,0,0,5,0,0,0,0,12,5,0,0,0,0,0,0,0,0,0,0,24,6,0,0, +0,7,0,4,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,7,0,4,0,0,0,0,8,7,0,0, +9,6,0,0,14,5,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,12,6,0,0,0,0,0,0,0,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,7,0,0,0,5,0,0, +0,0,12,7,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,6,0,0,13,7,0,0,0,0,0,0,14,0,11,4,0, +0,0,4,0,0,0,0,14,5,0,0,0,0,0,5,11,5,0,0,0,0,22,5,0,0,0,0,0,7,0,0,0,0,0,4,0,0,0, +4,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,17,0,10,0,0,0,8,0,0,0,19, +5,18,7,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,10,6,0,6,0,0,0,0,10,4,0,4,0, +0,0,0,0,0,14,7,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,8,0,9,6,12,0,0,6,0,0,0,0,0,0,0,0, +12,0,10,6,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,4,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,5,13,0,9,7,0,0,0,0,0,0,0,0,0,0,0,7,9,7,0,0,8,0,0,0,0,0, +22,0,0,0,0,0,0,0,23,6,14,0,0,0,0,0,0,7,0,0,0,0,11,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,10,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,8,5,0,0,0,0,0,0,0,0,0,7,11,6,21,0,0,0,0,0, +0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0, +0,0,0,0,0,0,0,4,9,7,0,0,0,0,0,0,12,0,0,0,0,7,0,0,0,0,0,0,0,0,10,4,0,0,0,0,0,0,9, +0,0,0,20,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,11,7,0,0,0,0,0,0,0,6,15,0,0, +0,0,0,0,0,0,0,0,0,0,0,12,4,0,5,0,0,0,0,0,0,11,7,17,6,0,0,0,0,0,0,15,6,0,7,0,0,0, +0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,6,0,5, +0,0,11,0,11,7,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0, +17,0,0,0,0,6,0,0,0,5,0,0,0,0,0,0,8,7,9,6,0,0,14,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0, +8,7,0,4,0,0,0,0,0,0,0,6,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0, +0,0,0,5,0,4,0,0,8,7,0,6,12,5,0,7,18,7,0,0,8,5,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0, +10,0,11,0,0,0,0,0,0,0,0,0,0,0,9,0,0,4,0,6,0,7,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0, +7,0,0,0,0,8,0,0,0,15,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,0,0,0, +0,0,6,0,0,0,0,23,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,5,0,0,0,0,0,0,8,6,0,0, +0,0,0,0,12,7,9,7,0,0,10,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,9,0,8,7,0,0,0, +6,0,6,0,4,0,5,0,0,0,0,0,5,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,7,10,5,0,0,11,6,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,4,9,7,0, +0,0,0,11,7,0,0,0,0,0,5,0,0,0,7,0,0,0,0,23,6,11,4,0,0,0,0,0,0,9,0,0,0,10,6,0,0,0, +0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,10,6,0,0,0,7,0,0, +0,0,0,0,0,0,0,0,20,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13, +6,11,7,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0,0,0,6,0,0,0,5,0,6,0,6,0,0,0,0,0,0,0,0,0,0, +0,6,0,0,0,0,8,7,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,4,10,0,8,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,10,6,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0, +0,0,0,0,0,0,10,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,11,6,0,4,0,0,14,5,0,7,0,0,0,0,0,6,16,0,0,0,0,0,0,0,10,0,0,7,15,0,0,0,11,7,0,0, +0,0,0,0,0,0,0,0,8,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,5,0,0,0, +0,8,0,0,6,0,0,0,0,0,0,9,5,0,0,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,6,0, +0,0,0,0,0,0,7,0,0,0,0,15,7,0,0,0,0,8,0,0,0,14,0,0,0,0,0,0,0,16,7,0,0,0,0,0,7,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,12,6,11,7, +9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13, +7,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,12,0,10,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,8,0,0,5,8,7,10,6,0,0,0,7,0,0,0,0,12,6, +0,0,9,0,0,0,12,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,4,10,0,0,0,10,5,0,0,0,0,0,0,9,6, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,6,0,0,9,5,0,4,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,9,0,0,5,0,0,8,7,8, +6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,10,0,9,4,0,0,0,0,0,0,0,6, +11,0,0,0,0,0,0,0,0,0,0,0,8,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,8,7,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0, +0,0,0,10,0,0,0,8,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0, +0,0,8,4,0,5,0,0,0,0,0,0,0,7,0,0,0,6,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,22,0,0,0,0,0,0,0,8,5,0,0,0, +0,0,0,0,7,0,0,0,6,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,5,0,6,0,7,0,0,0,0, +20,0,0,0,0,0,0,0,0,0,0,7,9,0,0,0,0,0,0,6,0,6,0,7,0,0,0,7,0,0,0,0,0,0,0,4,0,0,0, +0,0,0,14,7,0,0,0,5,0,0,22,4,10,0,0,0,0,0,0,4,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,11,5,13,0,0,0,0,0,0,0,0,0,8,0,0,7,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0,10,7,0, +0,0,0,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,0,7,14,6,0,0,0,0,9,5, +0,0,0,0,0,6,0,0,0,5,10,0,8,6,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,6,0,0,8,4,0,6,0, +0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7, +14,0,0,5,0,0,18,0,8,4,0,6,0,0,20,0,13,0,0,0,0,7,0,4,0,0,0,0,0,4,8,4,0,0,0,0,0,6, +0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,4,0,0,0,0,0,0,0,0,14,0,0,0,0,0,9,7,0,0,9,0,0,0,0, +0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,20,0,14,0,0,4,0,6,8,5,0,0,0,0,0,7,0,0,0,0,0,0, +0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,10,4,12,7,0,6,0,0,9,7,10,5, +0,0,8,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,17,0,0,0,0,0,0,0,18,0,0,0,14,7,0,0,0,0,0,4, +0,0,0,0,0,0,17,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13,4,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0, +0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,8,5,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,5,0,7,0,0,0,0,0, +7,0,0,0,0,0,0,0,0,0,7,0,6,0,0,0,0,0,0,0,0,8,5,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,5,0, +0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,23,0,0,7,0,0,0,0,0,0, +0,0,0,0,0,0,0,4,0,0,0,0,0,0,12,7,8,4,0,0,0,0,0,0,0,0,0,6,0,0,9,5,0,0,0,7,0,0,0, +0,0,0,0,0,0,4,10,0,0,7,0,0,0,5,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,5,0,0,18,7, +0,0,8,0,0,5,0,0,10,0,0,0,0,0,0,6,0,0,0,0,0,5,0,7,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0, +6,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,6,0,0,10,0,0,5,10,4,0,0,12,0,0,0,0, +6,22,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,5,0,0,0,0,0,7,0,5,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,6,0,7,0,0,0,6,0,6,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0,7,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0, +0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,16,6,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,12,7,0,0,0,0,9,0,0,0,0,6,0,0,11,0,0,0,0,0,13,0,9,6,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,4,0,0,10,7,0,0,0,7,0,6,0, +0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,11,0,15,0,22,7,0,4,0,6,0,0,0,0,0,7,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,4,0,7,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0, +18,0,0,0,0,0,0,0,0,0,14,0,0,4,0,0,0,0,8,7,9,0,0,0,0,0,9,0,0,0,14,0,0,0,0,0,0,0, +0,0,11,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,7,0,0,0,6,0,6,0,0,0,0,8,0,0,0,0, +0,11,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,9,4,0,0,0,0,0,4,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,8,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0, +0,0,0,0,0,0,8,6,0,0,9,5,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,5,0, +0,10,6,9,0,0,0,0,6,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0, +11,7,12,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,4,0,5,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0, +0,0,0,0,6,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,5,0,0,10,6, +0,0,0,4,0,7,13,0,0,4,0,0,11,4,0,6,0,0,0,0,0,6,8,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,5,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,5,0,0,0,0,12,6,0,0,0,0, +11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,11,5,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8, +7,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,4,0,0,0,6,17,0,9,0,10,6,0,6,12,0,0,4,0,0,0, +0,0,0,0,0,0,0,8,5,12,7,0,4,0,0,0,0,0,0,0,0,0,0,11,0,9,0,10,6,11,5,0,7,0,0,8,0,0, +7,0,4,0,0,0,7,0,0,0,0,0,0,8,6,0,0,0,6,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,6,0, +0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,11,0,0,0,0,6,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,10,0,0,0,0,0,8,6,0,0,0,0,0,6,12,0,0,0,0,0, +0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,6,0,0,16,0,11,5,0,0,0,0,0, +0,0,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,9,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,6,10, +7,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,6,0,0,0,0,0,0,9,5,0,0,0,0,8,0,9,0,0, +0,0,0,0,0,0,7,10,0,13,0,0,6,0,0,0,0,0,0,0,0,0,6,9,4,0,0,0,0,0,0,10,0,0,0,0,0,10, +0,0,0,0,0,0,0,10,6,11,0,0,0,0,0,9,0,0,0,0,0,0,4,0,0,0,0,0,0,10,5,0,0,0,0,0,6,0, +0,0,0,0,0,18,4,0,7,0,0,0,0,0,0,24,0,8,6,0,7,0,0,0,0,15,0,0,0,0,0,0,0,0,0,0,0,0, +0,8,5,0,0,0,0,10,7,0,6,0,0,0,0,0,0,0,0,8,5,10,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0, +6,0,0,8,7,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,4,0,5,15,0,0,0,0,7,0,7,0,0,0,0, +0,0,0,0,0,6,10,5,0,0,0,6,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,7,0,0,12,0,0,0,0,0,0,0,0, +0,0,5,0,0,0,0,0,0,14,4,18,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,11,0,10,4,9,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,7,0,0,0, +0,0,0,0,0,0,0,0,7,13,7,0,0,0,0,0,0,0,5,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0, +0,0,0,0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,8,0,10,6,0,4,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0, +0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,9,7,0,0,0,0,0,6, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,0,6,0,0,0, +0,0,0,0,5,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,6,0,0,0,5,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,11,0,0,0,0,6,0,0,0,0,0,0,0,6, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22,0,0, +6,0,0,0,0,0,0,0,6,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0, +0,0,0,0,0,0,0,6,0,6,0,0,0,5,0,0,0,0,0,0,0,5,0,0,10,0,11,5,0,0,0,0,0,0,14,7,9,7, +0,6,0,0,0,0,0,4,0,0,0,0,0,0,11,7,0,6,0,0,0,0,0,0,9,7,0,4,0,0,0,7,0,0,0,0,0,5,0, +0,0,0,0,5,0,0,0,7,0,0,0,0,0,5,0,0,0,0,17,5,0,0,8,0,0,0,0,6,9,4,0,0,0,0,0,0,0,0, +8,7,11,7,9,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,6,9,5,0,0,8,6,0,0,0,5,0, +0,0,0,9,0,0,0,9,6,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0, +0,0,0,0,4,0,0,0,0,10,0,0,0,0,0,0,0,0,4,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,4,0,0,0,5,0,0,0,0,0,7,0,0,0,0,0,7,13,5,0,0,0,7,0,0,0,0,0,7,9,6,11,7,0,7,0,0,0, +0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,8,5,0,0,0,5,9,4,0,0,0,0,0,0,0,0,8,4,0,0,0,0, +24,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0, +0,0,0,0,6,0,0,0,7,0,0,0,6,0,0,0,0,0,0,0,0,0,5,11,6,0,4,0,7,20,0,8,5,9,5,9,0,0,6, +0,0,0,0,0,0,0,0,0,0,0,7,23,5,0,0,8,4,0,0,10,0,0,6,0,5,0,0,0,0,0,0,0,0,0,0,0,7,0, +0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,9,0,0,0, +10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0, +6,0,0,0,0,14,0,18,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,9,6,0,4,0,0,0,0,0,0,8,4, +11,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,0,0,0,12,0,10,7,0,0,10,0,0,0,0, +0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,6,0,0,0,0,8, +6,10,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,4,0,6,0,4,0,0,0,0,0,5,0,0, +0,0,0,0,0,0,0,7,0,0,0,7,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,17,7,11,0,0,0,0,0,0,0,0,0,0,4,12,6,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,0,0,0, +0,5,12,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,6,0,6,0,0,20,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,4, +0,0,0,5,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,6,0,4,13,0,0,7,0,0,0,0,0,0, +0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,12,6,0,7,0,0,0,0,10,0,23,6,0,0, +0,4,0,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +10,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,11,0,9,7,0,0, +0,0,0,0,0,0,0,0,9,7,0,4,0,0,0,0,8,7,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4, +0,0,0,0,0,6,0,0,10,7,10,5,0,0,8,0,8,0,0,0,0,0,0,4,0,5,10,0,0,0,0,0,0,0,9,0,0,6, +0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,11,7,0,0,0,0,0,0,0,0,9,4,0,0,0,0,0,6,0,0,8, +7,0,0,0,0,0,5,0,0,0,0,0,0,0,0,10,0,0,0,0,5,0,4,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,24,7,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,6,0,0,9,0,0,0,0,0,0,7,0,6,13,0,8, +0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,6,0,0,0,0,8,5,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0, +4,0,0,0,0,0,4,0,0,0,0,0,0,0,6,8,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,4,0,4,0,0,0,5,0,7,0,0,10,0,10,7,0,0,12,5,0,0,9,0,0,0,10,0, +0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,5,0,0,0,0,0,0, +12,0,0,0,0,0,8,5,13,6,0,0,0,0,0,0,9,4,0,0,0,0,8,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0, +0,0,6,0,0,14,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,17,6,0,0,0,0,12,6,0,0,0,0,8,0,0,7,0, +7,0,4,9,0,0,6,0,0,0,6,0,0,0,0,0,0,8,7,0,0,0,0,0,0,11,0,0,4,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,18,7,0,4,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,6,0,0,0,0,0, +0,0,0,12,5,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,8,0,11,7,0,0,0,0,0,0,0,0,0,4,0,0,0,0, +11,0,0,0,0,0,0,0,21,0,0,6,10,0,0,0,0,0,9,0,10,0,0,0,0,0,11,0,0,0,0,6,0,0,0,0,0, +5,0,0,0,0,0,0,10,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,4,0,0,23,7,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,9,7,0,0,0,7, +0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,6,0,0, +11,6,0,0,0,0,0,0,0,6,0,0,0,0,10,7,0,0,9,4,0,0,11,0,8,5,0,0,0,7,8,5,22,0,0,0,9,6, +0,0,0,0,0,0,0,6,10,4,0,0,0,0,0,7,9,4,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,4,0, +0,0,0,11,6,0,0,0,0,0,0,0,0,0,0,0,7,0,6,0,0,0,0,0,7,0,0,0,0,0,0,0,6,0,6,0,4,0,0, +0,0,0,0,0,7,0,7,0,4,13,0,0,0,0,0,8,0,0,0,0,7,0,0,0,0,0,0,11,6,0,7,0,0,0,0,9,0,0, +0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,4,8,0,0,0,0,0,8,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,6,0,0,0,0,13,5,8,0,0, +0,0,0,0,0,14,0,0,6,0,0,0,0,0,0,0,0,0,7,0,0,17,6,0,0,0,0,13,4,0,0,9,6,0,0,10,5,0, +0,10,5,0,0,0,0,13,0,0,0,0,6,0,0,0,0,0,0,10,0,12,0,0,0,0,0,0,0,0,0,0,0,8,4,0,4,0, +0,0,4,0,0,0,0,0,4,0,0,12,0,0,5,9,4,0,0,0,0,0,0,0,0,0,5,8,5,0,0,0,7,0,0,0,0,8,7, +0,0,0,6,12,5,0,0,0,5,0,0,0,5,0,0,0,0,0,4,12,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,7,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0, +0,9,6,0,0,0,0,0,0,0,0,0,4,0,0,0,6,0,0,0,4,11,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0, +0,0,0,0,12,7,0,0,0,7,10,7,0,0,11,0,0,0,0,0,0,0,0,0,11,7,0,0,0,6,0,0,11,0,0,0,0, +0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,22,0,10,7,0,0,8,5,0,0,0,0,0,5,0,0,0,0,0,0, +0,0,0,0,9,6,8,7,0,6,0,0,0,0,0,5,0,0,0,0,0,0,8,7,0,0,0,0,9,7,0,0,0,6,0,0,8,7,0,0, +0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,4,0,5,0,0,0,4,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,6,0,0,0,0,0,0,0,4,0,0,0,0,0,0,9, +6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0,5,0,0,0,0,14,0,0,0, +9,0,0,0,0,0,0,0,0,0,9,7,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,12,0,0,0,0,0,12,7,0,0,0,5,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,10,7,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,6,0,0,0,0,0,0,9,6,0,0,0,0,0,6,0,0,0,0,0, +0,0,0,0,0,9,0,0,0,0,7,0,6,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0, +0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,6,0,7,12,6,0,0,0,0,0,5,0,0,0,0,0,0,0,0, +0,7,0,0,8,6,0,0,0,0,10,7,0,0,0,0,0,0,0,6,0,0,0,0,0,6,12,0,0,0,0,0,0,0,0,6,0,0,0, +0,0,6,0,0,0,6,0,0,0,0,0,6,16,0,0,0,0,0,0,0,0,0,9,0,17,0,14,7,8,0,0,0,0,0,0,6,0, +0,0,0,0,0,0,0,0,0,11,0,0,6,8,7,0,6,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,0,0,0, +9,0,0,0,0,7,0,0,0,0,11,5,0,4,9,6,8,0,0,0,0,0,0,0,0,0,10,0,11,7,0,0,0,0,0,0,0,0, +9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11, +0,0,0,12,0,0,0,0,0,10,5,0,4,0,0,0,0,0,7,10,6,11,6,0,0,0,0,0,0,0,0,0,0,0,0,17,0, +0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,8,0,0,4,0,0,0,6,0,0,0, +0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,4,0,0,0,0,9,6,0,0,0,4,0,0,0,0,0,4,10,7,0,7,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0, +0,0,0,0,0,0,6,0,0,0,6,0,6,0,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,18,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,13,0,0,0,0,0,10,0,0,0,0,0,0,0,0,4, +0,0,0,6,0,0,0,0,0,4,8,0,0,0,11,7,0,0,0,4,0,0,0,0,0,7,0,0,8,5,0,0,16,0,0,0,13,6, +0,0,0,0,0,0,0,6,0,0,0,0,20,0,11,6,0,0,8,7,0,0,0,0,0,6,17,0,8,0,0,0,0,0,8,7,0,0, +9,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0, +0,0,4,0,7,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,8, +0,8,0,0,0,0,0,0,0,11,0,8,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,6,0,0,9,0, +0,0,0,0,8,0,0,0,0,0,18,0,0,0,0,0,0,4,9,0,0,0,0,0,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,9,6,0,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,7,0,0,0,0,0,0,0,0, +0,4,0,0,0,0,0,0,14,0,0,0,0,7,0,6,0,0,8,0,20,7,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,8,0,0,0,14,0,0,0,0,0,0,0,8,0,0,7,0,6,0,0,0,7,0,0,0,0,0,0,0,0, +0,0,0,4,12,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,10,6,0, +5,16,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0, +0,0,0,5,8,4,0,0,0,0,0,0,0,4,0,0,0,7,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,12,7,0, +0,0,0,13,6,0,0,0,7,0,0,8,0,0,0,8,0,0,0,0,0,0,0,0,0,0,5,0,0,0,7,0,0,0,0,0,0,11,5, +0,6,0,0,8,5,0,7,0,0,0,0,0,0,0,7,0,0,0,0,8,6,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +14,0,10,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,19,0,0,4,0,0,0,7, +0,0,11,5,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,16,0,10,5,18,0,0,7,9,6,0,5,0,0,0,0,0, +0,0,0,0,5,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,5,0,0,0,7,0,6,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,6,0,0,0,4,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,6,0,0,0,7,23,0,0,0,0,5,0,0,0,0,0,0,8,5,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,14,0,20,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0, +11,0,0,0,0,7,0,0,0,0,15,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,7,0,0,0,0, +0,4,0,0,0,0,10,0,0,0,0,0,9,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,10,0,11,6,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,5,0,0,11,0,0,0,0,7,0,0,0,0,0,0,8,7,0, +4,0,0,0,0,11,0,0,0,0,0,11,0,0,5,0,0,8,7,0,4,0,7,0,0,0,0,0,0,0,6,0,0,0,0,0,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,10,5,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,6,0,5,0,0,0,0,0,0,0, +0,0,4,11,5,10,7,0,7,0,0,9,6,9,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,9,4,0,4, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,8,6,0,0,0,0,11,7,0,0,0,0,0,0,0,0,0,0,11,7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,8,5,0,0,8,0,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,4,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0, +10,7,0,0,0,6,0,0,0,0,0,0,8,0,0,6,0,0,0,6,10,0,0,0,0,0,0,0,0,0,0,0,8,5,0,0,0,6,0, +0,0,6,0,0,0,0,9,5,8,5,8,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0, +0,8,7,10,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,0,5,0,0,0,6,0,7,0,0, +10,5,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,11,0,0,0,0,0,13,4, +0,0,0,4,0,0,0,0,0,5,8,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,7,14,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,7,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,4,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,5,0,0,15,6,10,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,14,6,10,0,0,0,0,0,0,0,0,6,0, +0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,6,0,5,11,4,0,6,0,0,0,7,0,0,0,0, +0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,5,0,0,8,5,0,0,0,0,0,0,0,0,0,0, +0,0,10,0,0,0,0,0,9,6,9,4,0,0,0,4,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,8,5,0, +0,0,0,0,0,0,0,0,0,0,4,0,0,11,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,5,0,0,0,0,0,0, +0,0,0,7,12,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0, +4,9,6,0,4,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,6,0, +7,8,6,0,0,0,0,0,0,0,4,0,0,9,6,0,0,0,0,0,0,0,0,0,6,0,5,0,4,0,0,0,0,0,0,0,5,0,0,0, +0,0,5,0,0,0,7,12,7,0,0,0,0,0,0,18,4,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,6,0,0,0, +0,12,0,0,7,0,0,0,0,0,7,0,0,13,0,0,6,0,0,0,0,8,7,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,7,10,5,0,0,8,0,0,0,0,0,0,0,8,6,0,7,0,0,8,4,0,4,0,0,0,0,10,4,0,0,14,0, +0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,17,0,0,0,0,0,0,6,0,0,0,0,8,6,0,0,10,5,0,0,0,0,8, +6,0,0,0,6,0,0,0,7,0,0,0,0,0,6,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,12,0,0,0,0,6, +8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0, +0,0,0,6,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,4,24,0,0, +0,0,0,12,6,0,0,10,6,0,5,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,17,7,0,5,0,0,0, +0,0,0,0,0,0,0,0,0,0,6,11,5,9,0,8,7,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,10,7,0,0,0,0,0,0,0,7,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,5,8,7,0,0,0, +0,8,5,0,0,0,0,10,7,0,7,0,0,0,0,0,0,0,0,0,0,13,6,0,0,0,0,0,0,0,0,0,6,0,4,0,0,0,0, +0,6,12,0,8,7,0,0,0,0,0,0,0,0,0,0,16,0,10,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,22,0,0,0, +0,0,0,0,0,0,0,0,0,0,13,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,22,0,0,6,0,0,21,0,0,0,22,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +6,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,6,0,0,0,5,0,0,0,0,0,7,8,0,0,0,0,6,14,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,6,0,0,0,0,0,0, +0,0,0,0,0,6,0,0,0,0,8,5,0,0,11,7,0,6,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0, +6,0,0,0,5,0,0,0,0,0,0,0,0,0,4,0,0,8,7,0,0,0,0,8,5,11,7,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,4,0,0,0,0,8,5,0,0,10,0,0,4,13,7,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,5,0,0,13,6, +0,6,0,7,0,0,8,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,15,0,0,0,10,7,0,0,0,0,0, +7,0,0,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,19,0,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,6,0,5, +0,7,0,0,0,0,0,0,0,0,0,6,0,0,11,4,0,0,0,6,0,0,13,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,8,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,12,6,0,0,0,0, +0,7,0,0,0,0,0,0,11,7,0,0,0,0,0,6,0,0,10,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,5,11,6, +0,0,0,0,0,0,0,0,10,0,0,0,0,6,0,0,0,0,0,0,8,7,0,0,0,5,0,0,0,5,0,0,0,0,0,0,0,0,0, +0,0,0,8,7,0,0,0,0,9,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,0,0,0,10,0, +0,6,0,0,13,0,0,0,0,0,0,0,9,6,0,0,8,6,8,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,4,0, +0,9,7,0,0,0,0,0,0,11,0,0,0,10,7,0,0,0,0,0,0,0,0,9,6,0,0,12,4,0,4,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,6,0,0,0,0,21,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,5,0,0, +9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0, +16,0,0,4,0,0,0,0,0,7,0,0,0,6,0,6,0,0,11,0,0,0,0,5,0,0,0,0,0,0,0,4,8,5,0,0,0,0,0, +0,14,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0, +0,0,8,0,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0, +0,0,0,0,6,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,14,7,0,0,9,7,0,0,11,0,0,0,0,0,10, +4,11,5,13,6,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,5,0,0,0,0,0,4,0,0,9,0,0,0,0, +0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,6,12,5,0,0,0,6,14,0,0,0,0,0,0,0,0,0,0,4,9,4, +0,0,0,0,0,5,0,0,0,0,0,0,0,4,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,5,0,0, +0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,11,6,0,0,13,7,0,0,13,6,0,7,0,0,0,0,0,0,8,6,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,10,6,0,4,0,0,12,6,0,0,0,0,0,0,0,0,10,6, +0,0,0,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0,6,0, +0,0,0,0,7,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,6,0, +0,0,7,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0, +0,0,0,5,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0, +0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,8,7,0,0,8,5,0,0,0,4,9,5,0,0,0,7,10,6,0,0, +0,0,0,0,9,7,0,0,8,5,8,0,8,4,0,0,13,0,0,0,0,0,0,0,0,0,0,0,0,5,0,5,0,0,0,0,0,0,0, +0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,4,0,0,0,0,0,0,0,0,0, +0,11,7,0,0,0,7,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17,5,0,0,0,7,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,9,7,0,0,0,0,8,5,0,4,0,0,0,0,0,6,0,6,14, +6,0,0,0,0,9,6,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,6,0,0,0,0,14,7,9,7,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,16, +0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,14,0, +0,6,0,0,8,6,0,0,0,0,0,6,0,0,12,0,0,0,0,0,8,5,0,7,11,0,0,5,0,4,0,0,0,6,0,0,0,0,0, +0,0,0,0,0,0,0,9,6,0,4,0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,6,0,0,0,0,0,0,10,5,0,0,0,0, +0,4,0,0,0,7,11,6,0,4,8,5,9,5,0,0,0,5,0,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,8,5,14,7,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,16,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,9,6,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,9,0,0,0,12,5,0,0,0,0,0,0,0,4,10,5,0,0,0,0,0,0,0,0,0,0,0,6,0, +0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,4,0,0,0,6,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,10,4,0,0,0,0,0,5,0,0,0,4, +0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,8,0,10,7,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,10,7,0,0,0,0,0,0,0,0,15,0,0,0, +0,0,0,0,0,0,0,7,0,0,0,0,0,7,10,7,9,7,0,0,0,7,0,0,8,0,0,0,0,0,0,0,9,0,0,0,8,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,8,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,7,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,15,7,12,6,0,0,0,7,0,5,0,0,0,0,0,0,0,0,0,0,0,0,18,0,0,5,0,0,0,0, +0,0,0,6,9,5,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,9,7,0,0,14,0,0,0,11,7,0,0,0,0,0, +0,0,0,0,0,0,4,0,0,11,7,0,0,0,0,8,0,0,0,0,0,0,6,8,7,0,0,0,7,10,4,0,0,0,0,0,0,0,0, +0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,10,0,0,0,0,0,0, +6,0,6,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,11,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,7,0,0,10,7,0,0,0,0,9,7,0,0,0,0,0,0,13,7,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,12,0, +0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,9,6,0,0,11,0,0, +0,0,0,14,4,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,23,7,0,0, +0,0,0,6,0,7,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0,0,20, +7,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,8,0,0,0,0,0,0,0,0,0,11,5,0,0,0,0,0,0,0,0,0,0,10,4,0,0,0,5,8,5,10,4,0,0,0,0,0, +0,13,6,9,7,0,0,10,7,0,0,0,0,0,0,0,0,14,0,0,0,0,0,0,6,0,0,0,7,0,6,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,7,10,7,0,0, +0,0,0,0,0,0,0,0,12,4,0,0,0,0,8,7,0,0,0,0,0,7,0,6,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0, +0,0,0,0,6,0,6,9,6,0,0,12,5,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,6,0,0,0,0, +0,0,0,0,0,0,0,0,0,5,8,7,9,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,11, +4,0,0,0,0,0,0,8,0,0,0,10,7,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,0, +0,0,0,0,0,5,0,6,0,0,10,0,14,0,0,0,0,0,0,0,23,0,0,0,12,0,10,5,0,0,0,0,0,0,0,0,0, +5,0,0,0,0,8,0,0,0,0,6,8,0,0,0,0,0,0,0,0,0,22,0,8,0,0,0,0,6,0,0,0,0,0,0,0,5,0,0, +0,0,0,0,0,6,18,4,0,0,0,7,10,6,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0, +0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,7,10,0,0,0,0,0,0,6,0,0,0,0,11,5,0,0,0,0,0,0,0,0, +15,0,8,6,0,0,13,7,0,0,0,0,0,7,0,0,0,0,0,7,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,9,5,9, +0,0,6,8,6,0,0,0,0,10,0,0,0,18,5,0,0,0,5,0,7,0,0,0,0,8,6,0,0,0,0,9,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,14,0,23,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,6,0,0,0,5,0, +0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,8,5,0,0,0,0,0,0,0,0,9,0,0,0,0,4,0,0,0,0,0,0,0,0, +0,0,0,0,20,5,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,9,5,0,0,0,0,0,0,8,4,24,0,0,0,0,0,0, +0,0,0,0,0,0,0,9,7,0,0,0,0,10,5,0,0,8,5,0,0,0,0,0,0,0,0,12,7,0,6,0,0,10,6,0,0,0, +0,14,0,0,4,9,5,0,0,0,0,0,0,9,0,0,0,0,0,0,6,0,0,0,0,0,4,0,0,8,0,0,0,0,0,11,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,8,5,11,7,0,4,0,0,10,0,0,0,0, +0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,11,6,0,0,0,0,0,5,14,6,0,0,0,0,10,0,0, +0,13,4,0,0,0,0,0,0,0,0,0,0,0,6,0,0,10,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,7,12,0,10,6,0,0,0,0,0,0,10,0,0,0,0,0,10,0,9, +7,0,0,0,0,0,0,0,0,0,0,0,0,0,7,8,0,0,0,0,0,0,0,0,0,0,0,0,4,0,7,0,0,0,0,9,7,0,0,0, +0,0,0,0,0,0,0,0,0,24,0,11,7,0,7,0,0,0,0,0,0,8,6,0,0,0,0,0,0,8,7,0,0,0,0,0,5,0,0, +0,6,9,0,0,0,23,5,0,0,0,0,0,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,7,0,0,0, +0,0,0,0,0,0,0,0,0,0,6,0,0,18,4,0,0,11,7,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6, +0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,9,0,0,0,11,0,0,0,23,0,0, +0,10,4,0,0,0,0,0,7,0,0,0,7,0,0,0,0,0,4,0,0,0,0,0,7,0,0,19,0,11,0,0,0,0,0,12,7,0, +0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,5,0,0,0,0,0,5,0,0,0,0,0,5,0,0,0,0,0,0,0,6,0,0, +9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,4,0,0,0,0,10,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,4,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,22,0,8,7,10,4,11,0,13,5,8,7,9,0,8,7,0,0,0,7,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0, +0,8,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,4,0,0,0,4,11,0,0,6,0,0,8,5,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,8,5,0,0, +20,0,0,0,0,0,0,0,0,0,11,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,7,0,0,14,0,0,0,9,0,13,7,0,0,0,0,0,6,0,7,0,0,8,6,10,6,0,0,8,6,0,0,0,6,0, +0,12,6,9,0,0,0,0,0,0,5,9,0,12,4,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,8,5,0,0,0,0,0, +0,0,4,8,0,0,6,8,0,0,0,0,0,0,0,0,0,13,6,0,7,0,0,0,0,0,6,8,7,8,6,0,0,0,7,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,18,0,11,4,0,0,0,5,0,0,0,0,0,0,0,0,0,0, +0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,14, +6,0,0,0,0,12,7,8,0,0,0,0,0,0,0,8,7,0,0,0,0,10,4,0,0,0,0,0,0,10,0,0,6,0,0,0,0,0, +0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,15,6,9,7,0,0,0,0,0,0,15,6,11,7,0,0,0,7,0,0,21,0,0, +0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,17,6,0,0,10,5,0,5,0,0,0,0,0,0,0,0,0,7, +0,0,10,0,0,0,0,0,0,0,0,4,11,5,0,0,0,0,16,7,0,0,0,0,0,6,0,0,8,7,0,4,0,0,10,0,0,0, +0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,8,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0, +0,0,0,10,4,0,0,0,0,0,0,0,0,0,6,0,5,0,0,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0, +0,7,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,6,10,7,0,0,0,0,0,0,0,0,8,4,0,0,10,0,0,0,0,4,0,6,0,6,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,7,17,0,0,0,0,0, +0,0,0,0,0,0,10,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +6,0,0,0,5,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,5,0,4,0,0,0,0,0,6,0,0,0,0,0,0,10,5,0,0, +0,5,0,0,0,0,9,0,19,7,0,0,0,0,0,7,0,0,0,0,10,6,0,0,0,6,0,5,0,0,0,0,0,0,0,0,0,6,8, +0,0,0,0,0,11,0,0,0,0,0,0,6,0,0,0,0,0,7,9,0,15,0,0,0,0,0,0,0,0,0,0,4,0,0,0,5,0,0, +0,0,0,0,0,6,0,0,0,0,0,0,0,4,0,0,0,0,9,0,0,0,0,0,0,0,0,6,0,7,0,0,0,0,0,0,0,6,0,0, +0,0,0,6,10,0,0,0,0,0,0,0,23,0,14,0,0,0,0,7,0,0,0,0,0,7,0,0,9,0,0,0,0,7,0,0,0,0, +0,6,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,4,0,0,0, +0,0,0,0,0,9,5,0,0,0,0,0,4,0,0,0,0,9,5,0,0,0,0,22,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,22,0,0,0,0,0,0,0,10,0,0,0,0,0,0,5,0,4,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,6,11,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,14,7,0,0,12,7,0,0,0, +0,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,8,6,10,0,0,0,0,0,0,0,0,0,10,7,8,5,0,0,0,0,0,0, +0,0,8,4,0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,5,0,0,9,5,0,0,0,0,0,5,0,0,0,0,0,4,0,0,0, +0,0,0,0,0,0,0,12,4,11,0,0,0,9,0,11,7,0,0,0,0,0,0,10,6,0,0,0,6,0,0,0,0,15,5,0,0, +11,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,4,0,4,0,6,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,8,0,0,0,19,7,0,4,0,0,9,0,0,0,0,0,10,0, +0,6,0,0,13,0,12,6,0,0,0,0,0,0,0,0,10,7,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,13,7,10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,4,9,0,0,0,10,0,0,0,0,0,0,0, +0,5,0,0,0,0,0,0,10,0,23,6,0,0,0,6,8,0,0,0,0,0,0,0,0,0,17,7,0,0,0,0,11,6,22,5,0, +0,9,6,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,5,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,4,11,0,9,4,0,0, +0,7,0,7,0,0,0,0,0,0,12,4,0,0,0,0,0,0,0,0,0,0,0,0,11,4,0,0,0,0,0,0,0,0,0,0,0,0,0, +4,0,0,11,5,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,8,6,0,0,0,4,0,0,0,0, +0,0,0,0,0,7,0,0,0,4,0,0,10,4,0,0,0,0,0,0,0,7,0,7,0,0,0,6,0,0,0,0,8,6,0,6,0,6,0, +0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,0,0,0,0,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,6,22,6,12,0,0,6,0,0,0,6,0,0,0,0,0,7,0,0,0,0,11,0,0,0, +9,7,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,6,0,0,0,6,0,6,0,0,8,7,0,0,0,4,9,7,19,0,0,0,0,0,0,0,0,0,9,6,10,6,0,6,0,0,0, +4,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,6,16,7,10,6,0,0,23,6,11,7,0,4,0,0,0,0,0,0,0,0,0, +5,0,0,0,0,10,7,0,0,0,0,0,7,0,0,0,0,0,0,15,0,10,0,0,0,14,6,0,0,0,0,0,0,0,0,0,0,0, +5,0,0,0,0,0,0,0,5,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,5,0,0,11,5,0,0,0,0,0,0,0,0,0,0, +0,4,0,0,0,0,0,6,0,0,10,0,0,0,0,7,0,0,0,0,0,0,10,6,0,0,0,0,8,4,0,0,0,7,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,7,12,5,0,0,0,0, +0,6,0,0,0,0,9,6,0,0,0,0,0,0,0,6,9,0,0,0,0,6,0,0,0,0,8,7,0,0,0,0,0,0,0,6,0,0,0,0, +0,0,0,0,0,0,10,5,0,0,0,0,0,0,8,6,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,8,5,0,0,0,0,0,7,0,7,0,4,0,0,10,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,5,0,0,0,0,13, +7,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,7,0,0,13,0,0,0,0,0,0,0,0,7,10,5,0,0,0,0,0,0,9,7,0,0,8,6,9, +5,0,0,0,0,0,6,12,0,0,0,0,0,0,0,18,6,0,0,0,0,0,0,0,0,19,7,0,4,0,0,0,0,9,5,0,5,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,7,0,0,0,0,0,0,14,0,0,0,23,7,8,7,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,22,0,0,7,0,0,0,0,0,0,0,0,9,7,8,4,0, +0,0,0,0,0,0,0,8,5,0,6,0,0,0,0,0,6,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0, +8,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,12,5,0,0,0,0,0,0,0,0,0,0,8,6,0,0,11,7,0,0,0, +0,12,0,8,6,19,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,11,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,11,7,0,0,0,0,0,4,10,0,0,0,0,0,0,0,8,7,0,0,0,0,14,0,8,0,0,6,10,0,0, +0,0,0,0,0,12,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,6,0,0,0,0, +0,0,0,0,13,0,0,0,0,0,0,0,11,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0, +0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,5,0,0,0,6,0,0,0,5,0,7,0,0,0, +0,0,6,0,0,21,7,0,0,9,6,0,0,0,6,0,0,13,7,0,0,0,5,0,0,0,0,0,4,0,6,0,0,0,0,0,0,0,0, +0,0,0,4,0,0,0,0,0,0,11,5,0,6,0,0,10,5,0,0,0,0,0,0,0,0,9,6,0,0,8,7,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,9,0,0,0,0,0,0,6,0,0,0,0,15,4,0,0,12,7,0,0,0,6, +0,7,0,0,8,0,9,5,0,4,0,0,0,6,0,6,0,0,23,4,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,4,0,0,8, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,6,0,0,0,0,0,0,0,0,0, +7,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,12,6,0,0,0,0,0,0,10,7,0,7,0,0,0,0,0,0,0,0,0,0, +9,0,0,0,0,0,8,0,0,0,0,4,0,0,0,0,0,0,0,0,0,4,11,5,0,0,0,6,0,6,0,0,0,0,0,0,0,6,0, +4,0,0,0,0,0,0,0,0,0,0,0,5,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,8,7,0,0,0,6,0,6,0, +0,0,0,0,0,0,0,0,5,0,0,0,0,0,5,0,0,0,0,11,0,0,0,0,0,0,0,10,5,9,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,23,7,0,0,0,0,0,7,0,0,10,6,18,0,0,0, +0,0,0,0,8,7,0,6,0,0,0,0,0,0,8,5,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0, +0,0,0,0,0,6,0,0,0,4,12,7,0,0,0,0,0,0,0,0,10,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,13,5,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,0,0,0, +11,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0, +0,0,0,0,6,0,0,0,4,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,10,0,11,0,0,0,0,0,0,0,0,0, +17,5,0,4,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,4,0,0,0,0,8,7,0,0,0,0,0,0,0, +0,13,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0, +10,0,0,0,8,6,0,0,0,7,0,0,0,0,0,0,8,0,0,0,14,0,0,0,0,7,0,0,0,4,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,9,4,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,14,0, +10,0,0,0,16,5,0,0,0,0,0,0,8,0,0,4,0,0,0,0,0,0,0,0,0,0,9,6,0,0,0,0,0,0,10,0,0,0, +0,0,0,0,0,5,0,0,0,0,12,5,0,7,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,7,0, +0,0,0,0,0,0,0,12,6,0,0,0,0,0,7,0,6,0,6,12,6,0,0,0,0,0,0,0,4,8,7,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20,0,0,0,0,6,0,6,0,0,0,0,0,0,0,0,10,6,8,0,0, +6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +16,0,8,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,23,5,0,0,0,7,0,6,0, +0,0,0,0,0,0,0,0,0,0,0,10,6,0,0,9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,14,0,0,0,0,7,0,0,0,4,17,5,0,0,0,0,11,0,9,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,6,0,0,0,5,0,7,0,0,0,0,0,0,0,0,8,0,0,0, +12,6,0,0,0,0,0,0,13,0,0,0,0,7,9,0,0,0,0,0,0,0,0,0,0,5,0,0,0,7,10,7,12,0,0,0,9,0, +0,0,14,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,0,0,15,6,0,0,23,0,0,7,0,6,0,0,0,7,0,6, +0,0,0,0,0,0,0,6,0,6,9,0,0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,8,7,9,4,0,0,10,0,0,0,10, +6,0,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,23,0,0,6,0,0,0,0,0,0,9,4, +0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,9,6,0,0,0,0,8,6,0,0,0,0,0,0,0,0,12,0,0, +0,0,0,8,0,0,6,11,6,0,0,8,7,8,5,0,0,0,0,0,5,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,0, +10,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0, +7,0,0,0,0,9,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,8,0,0,0,0,6,12,5,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,10,0,10, +7,0,0,8,0,0,0,0,4,0,0,0,6,0,0,0,6,0,0,0,6,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,5,0, +0,0,4,0,0,0,0,0,4,0,0,0,0,0,0,0,6,0,6,0,5,0,0,0,0,8,0,0,0,10,7,0,0,0,0,10,0,0,0, +0,0,13,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,19,7,0,4,12,0,8,0,0,0,0,6,0,0,0,0, +0,0,0,6,0,0,0,0,0,0,0,0,0,4,0,0,0,0,18,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0,0,0,0, +0,14,0,0,4,0,0,0,6,0,0,0,6,0,0,0,7,0,0,0,0,0,0,10,4,0,0,9,7,0,0,11,0,0,0,0,0,0, +7,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,4,0,0,12,0,0,0, +0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,22,5,9,7,0,0,0,0,0,0,0,0,0, +0,0,6,0,0,9,6,0,5,0,0,0,0,0,0,10,5,0,0,8,6,0,6,10,5,0,0,0,6,0,0,0,6,0,0,20,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,6,0,0,0,0,17,4,0,7,0,6, +0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,14,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10, +0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0, +0,0,7,0,0,8,6,12,0,0,7,18,7,0,0,8,4,0,0,0,0,9,6,0,0,0,0,0,0,0,0,13,0,0,6,0,0,0, +0,0,0,0,0,0,0,10,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,0, +0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,8,5,0,0,0,0,0,0,0,0,12,0,0,0,8,0,0,0,0,0,0, +4,0,0,10,0,16,0,0,0,0,0,0,0,12,7,10,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,16,6,10,0,0,5,0,0,0,0,0,6,0,0,0,0, +0,7,0,0,0,7,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,5,8,7,0,7,0,0,0,0,0,0,0,0,8,0,0,6,0,0,0,6,0,0,0,4,0,0,0,0, +8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,7,0,0,8,0,0,0, +9,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,7,13,5,0,5,0,0,0,7,8,4,0,0,0,0,0,0,0, +0,12,0,0,0,0,0,0,0,0,0,0,0,8,6,0,6,0,0,11,0,0,0,0,0,0,0,0,6,0,0,0,0,0,4,0,0,0,0, +0,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,10,7,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,11,6,0,0,10,6,0,0, +0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6, +0,0,0,6,0,0,0,7,0,0,9,0,8,7,11,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,9,6,10,5,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,0,0,0,0,0,10,7,0,0,0,0,0,0,11,0,9,6,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,5,0,6,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,15,5,12,5, +0,0,0,0,0,0,12,7,0,0,0,0,0,0,8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,12,6,0, +0,0,0,24,4,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,4,10,4,0,0,0,0,10,7,0,0,0,0,0,0,0,0,0,0,0,0,9,0,11,0,0,0,0,0,0,0,0,0,0,6, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5, +0,0,8,0,0,0,0,7,0,0,0,0,0,0,10,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,10,7,0,0,0,0,0, +0,0,0,0,0,14,7,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,4,0,0,0,6,0,0,0,0,0,6,0,0,0,6,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,11,6,0,0,0,0,0,0,0,4,0,0,0,4,0,0,0,0,0,7,20,7,11,4,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19,7,9,6,0,0,12,7,0,0,0,0,0,0,10,0,12,0, +0,0,0,0,0,4,9,6,13,0,0,0,0,0,0,0,0,6,0,0,0,6,0,0,0,5,0,0,0,0,0,0,8,0,0,0,0,0,0, +0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,6,0,0,11,0,9,0,0,0,0,4,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,8,5,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,19,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0, +0,4,0,5,0,0,0,0,0,0,0,0,0,4,0,0,0,0,9,7,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0, +0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6, +0,0,0,0,8,7,0,0,0,0,0,0,12,0,0,6,0,0,0,0,0,0,0,6,8,4,0,0,10,7,0,0,10,0,0,0,0,0, +0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,7,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,4,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,7,0,0,0,0,0,0,0,5, +0,4,0,0,0,0,0,6,0,0,0,0,0,0,8,0,0,6,0,0,0,6,0,0,0,0,0,7,0,5,8,4,0,0,9,0,0,0,0,4, +0,0,0,0,0,0,0,0,0,5,0,0,15,6,8,6,0,0,0,6,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,6,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,9,6,0,0,0,0,0,0,0,7,0,0,0,4,0, +6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,9,5,0,6,12,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,6,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,8,7,0,6,0,0,0,0,0,0,0,0,0,0,0,0,11,0,12,7,0,0,0,0, +0,0,0,0,0,5,0,5,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,11,4,0,0,0,0,0,0,0,0,0,0,10, +7,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,7,8,7,9,6,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,5,12,0, +10,5,12,6,0,0,0,7,0,0,0,0,0,0,0,5,0,0,0,5,9,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7, +11,7,0,0,0,0,0,0,0,0,0,0,17,0,0,0,0,0,0,6,0,7,0,0,0,0,8,0,8,5,0,6,0,0,0,6,0,0,0, +0,0,0,0,6,0,6,0,6,9,0,0,5,17,0,0,0,0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,0,0,0,0,7,0,0, +0,0,0,7,0,0,0,0,16,5,0,0,0,0,0,0,0,4,0,0,0,5,11,5,0,7,0,0,0,4,8,7,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,7,0,0,0,0,12,0,0,0, +0,0,12,0,0,0,0,0,0,0,0,4,10,4,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,6,0,0,0,0,0,0,0,4,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,20,5,0,0, +10,0,0,0,0,0,0,0,0,0,0,6,0,0,0,6,12,0,0,0,0,0,0,6,0,0,0,0,0,0,9,4,10,7,0,4,0,0, +0,0,0,0,10,6,0,0,0,0,8,4,0,7,8,6,0,6,8,0,10,0,0,0,0,0,13,5,0,6,0,0,0,0,0,0,22,4, +0,0,0,0,0,0,0,0,0,0,9,0,0,0,0,6,0,0,0,6,0,0,0,0,0,0,0,6,0,0,0,0,0,0,0,0,0,6,10, +5,8,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,10,4,0,0,10,7,0,0,0,0,0,5,0, +5,8,0,0,0,0,6,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,10,7,0,0,0,4,0,0,0,0,0,6,0,0, +0,0,0,0,0,0,8,7,0,0,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,7,0,0,0,6,0,0,0,0,0,0,0,0,0, +4,0,0,0,4,10,0,0,6,13,7,8,0,0,0,0,0,0,7,0,0,12,7,0,0,0,0,0,0,10,5,0,0,0,0,0,6,0, +0,0,0,0,0,0,0,0,0,13,7,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,6,0,0,0,0,0,0,0,0,8,6,0,6, +0,0,0,0,0,0,0,0,12,0,8,4,0,0,0,0,0,4,0,4,0,0,0,0,0,0,0,5,0,0,0,0,12,5,0,0,0,7,0, +0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,10,0,0,0,20,0,0,5,0,0,10, +7,11,7,0,0,0,0,0,0,0,0,0,0,17,0,9,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,10,7,0,4,0,6,0,0,24,0,0,5,0,0,0,0,8,0,0, +0,0,0,0,0,10,5,0,4,0,6,0,0,8,0,0,0,0,0,0,4,0,6,0,0,0,0,0,0,9,5,0,0,0,0,0,0,0,0, +0,0,0,6,0,0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,4,0,7, +0,0,13,0,0,0,0,0,0,0,11,6,0,0,0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,4,0,0,0,0, +17,7,0,0,11,6,0,0,0,0,12,6,0,0,0,6,0,6,0,0,0,0,0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,4,0,0,0,0,0,0,0,0,0,5,0,0,0,6,0,0,0,0,0,0,0,0,0,0,10,0,0,4,8,6,0,0,0, +0,0,0,9,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,9,5,0,7,18,0,0,0,0,0,0,0,0,0,0,0,0,0,8,6,0,0,0,0,0,0,0,0,8,0,0,0, +0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6,0,0,0,0,0,0, +0,0,0,0,0,0,10,0,0,0,0,0,0,0,0,4,0,6,0,0,9,0,0,0,0,0,0,0,0,0,13,0,0,0,0,0,0,0,0, +0,0,0,8,7,10,0,8,5,0,0,0,0,0,0,0,0,9,0,0,0,10,0,0,0,0,6,0,7,0,4,0,0,0,0,0,0,0,0, +8,0,0,0,0,0,8,4,0,0,0,0,0,5,0,0,10,0,12,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +4,0,0,0,0,0,0,12,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,18,6,11,0,0, +7,0,0,0,0,0,6,10,5,0,0,0,0,0,0,0,0,0,5,0,0,9,5,12,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,6,0,0,0,0,13,6,0,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0, +0,0,0,8,4,0,6,12,0,0,0,0,0,0,0,0,0,0,0,0,6,0,6,0,0,0,0,0,5,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,11,4,0,0,0,6,14,0,11,0,9,6,0,0,0,0,0,0,22,0,12,0,8,6,0,0,0,0,0,0,0,6,0, +0,0,0,0,6,0,0,0,0,0,0,0,0,0,0,11,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7,0,0,0,0,0,0,0,0, +10,7,0,0,0,0,0,0,0,0,9,0,0,0,0,4,0,0,0,0,0,0,0,0,0,5,11,0,0,0,0,0,0,0,8,6,0,0,9, +7,0,0,12,4,0,0,0,0,0,0,12,6,0,6,0,7,0,0,8,5,0,0,0,0}; diff --git a/packages/runtime/vendor/brotli/c/enc/encode.c b/packages/runtime/vendor/brotli/c/enc/encode.c new file mode 100644 index 000000000..ba21aa2ec --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/encode.c @@ -0,0 +1,2021 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Implementation of Brotli compressor. */ + +#include + +#include "../common/constants.h" +#include "../common/context.h" +#include "../common/platform.h" +#include +#include "../common/version.h" +#include "backward_references_hq.h" +#include "backward_references.h" +#include "bit_cost.h" +#include "brotli_bit_stream.h" +#include "command.h" +#include "compound_dictionary.h" +#include "compress_fragment_two_pass.h" +#include "compress_fragment.h" +#include "dictionary_hash.h" +#include "encoder_dict.h" +#include "fast_log.h" +#include "hash.h" +#include "histogram.h" +#include "memory.h" +#include "metablock.h" +#include "params.h" +#include "quality.h" +#include "ringbuffer.h" +#include "state.h" +#include "static_init.h" +#include "utf8_util.h" +#include "write_bits.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define COPY_ARRAY(dst, src) memcpy(dst, src, sizeof(src)); + +static size_t InputBlockSize(BrotliEncoderState* s) { + return (size_t)1 << s->params.lgblock; +} + +static uint64_t UnprocessedInputSize(BrotliEncoderState* s) { + return s->input_pos_ - s->last_processed_pos_; +} + +static size_t RemainingInputBlockSize(BrotliEncoderState* s) { + const uint64_t delta = UnprocessedInputSize(s); + size_t block_size = InputBlockSize(s); + if (delta >= block_size) return 0; + return block_size - (size_t)delta; +} + +BROTLI_BOOL BrotliEncoderSetParameter( + BrotliEncoderState* state, BrotliEncoderParameter p, uint32_t value) { + /* Changing parameters on the fly is not implemented yet. */ + if (state->is_initialized_) return BROTLI_FALSE; + /* TODO(eustas): Validate/clamp parameters here. */ + switch (p) { + case BROTLI_PARAM_MODE: + state->params.mode = (BrotliEncoderMode)value; + return BROTLI_TRUE; + + case BROTLI_PARAM_QUALITY: + state->params.quality = (int)value; + return BROTLI_TRUE; + + case BROTLI_PARAM_LGWIN: + state->params.lgwin = (int)value; + return BROTLI_TRUE; + + case BROTLI_PARAM_LGBLOCK: + state->params.lgblock = (int)value; + return BROTLI_TRUE; + + case BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING: + if ((value != 0) && (value != 1)) return BROTLI_FALSE; + state->params.disable_literal_context_modeling = TO_BROTLI_BOOL(!!value); + return BROTLI_TRUE; + + case BROTLI_PARAM_SIZE_HINT: + state->params.size_hint = value; + return BROTLI_TRUE; + + case BROTLI_PARAM_LARGE_WINDOW: + state->params.large_window = TO_BROTLI_BOOL(!!value); + return BROTLI_TRUE; + + case BROTLI_PARAM_NPOSTFIX: + state->params.dist.distance_postfix_bits = value; + return BROTLI_TRUE; + + case BROTLI_PARAM_NDIRECT: + state->params.dist.num_direct_distance_codes = value; + return BROTLI_TRUE; + + case BROTLI_PARAM_STREAM_OFFSET: + if (value > (1u << 30)) return BROTLI_FALSE; + state->params.stream_offset = value; + return BROTLI_TRUE; + + default: return BROTLI_FALSE; + } +} + +/* Wraps 64-bit input position to 32-bit ring-buffer position preserving + "not-a-first-lap" feature. */ +static uint32_t WrapPosition(uint64_t position) { + uint32_t result = (uint32_t)position; + uint64_t gb = position >> 30; + if (gb > 2) { + /* Wrap every 2GiB; The first 3GB are continuous. */ + result = (result & ((1u << 30) - 1)) | ((uint32_t)((gb - 1) & 1) + 1) << 30; + } + return result; +} + +static uint8_t* GetBrotliStorage(BrotliEncoderState* s, size_t size) { + MemoryManager* m = &s->memory_manager_; + if (s->storage_size_ < size) { + BROTLI_FREE(m, s->storage_); + s->storage_ = BROTLI_ALLOC(m, uint8_t, size); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->storage_)) return NULL; + s->storage_size_ = size; + } + return s->storage_; +} + +static size_t HashTableSize(size_t max_table_size, size_t input_size) { + size_t htsize = 256; + while (htsize < max_table_size && htsize < input_size) { + htsize <<= 1; + } + return htsize; +} + +static int* GetHashTable(BrotliEncoderState* s, int quality, + size_t input_size, size_t* table_size) { + /* Use smaller hash table when input.size() is smaller, since we + fill the table, incurring O(hash table size) overhead for + compression, and if the input is short, we won't need that + many hash table entries anyway. */ + MemoryManager* m = &s->memory_manager_; + const size_t max_table_size = MaxHashTableSize(quality); + size_t htsize = HashTableSize(max_table_size, input_size); + int* table; + BROTLI_DCHECK(max_table_size >= 256); + if (quality == FAST_ONE_PASS_COMPRESSION_QUALITY) { + /* Only odd shifts are supported by fast-one-pass. */ + if ((htsize & 0xAAAAA) == 0) { + htsize <<= 1; + } + } + + if (htsize <= sizeof(s->small_table_) / sizeof(s->small_table_[0])) { + table = s->small_table_; + } else { + if (htsize > s->large_table_size_) { + s->large_table_size_ = htsize; + BROTLI_FREE(m, s->large_table_); + s->large_table_ = BROTLI_ALLOC(m, int, htsize); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->large_table_)) return 0; + } + table = s->large_table_; + } + + *table_size = htsize; + memset(table, 0, htsize * sizeof(*table)); + return table; +} + +static void EncodeWindowBits(int lgwin, BROTLI_BOOL large_window, + uint16_t* last_bytes, uint8_t* last_bytes_bits) { + if (large_window) { + *last_bytes = (uint16_t)(((lgwin & 0x3F) << 8) | 0x11); + *last_bytes_bits = 14; + } else { + if (lgwin == 16) { + *last_bytes = 0; + *last_bytes_bits = 1; + } else if (lgwin == 17) { + *last_bytes = 1; + *last_bytes_bits = 7; + } else if (lgwin > 17) { + *last_bytes = (uint16_t)(((lgwin - 17) << 1) | 0x01); + *last_bytes_bits = 4; + } else { + *last_bytes = (uint16_t)(((lgwin - 8) << 4) | 0x01); + *last_bytes_bits = 7; + } + } +} + +/* TODO(eustas): move to compress_fragment.c? */ +/* Initializes the command and distance prefix codes for the first block. */ +static void InitCommandPrefixCodes(BrotliOnePassArena* s) { + static const BROTLI_MODEL("small") uint8_t kDefaultCommandDepths[128] = { + 0, 4, 4, 5, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, + 0, 0, 0, 4, 4, 4, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, + 7, 7, 10, 10, 10, 10, 10, 10, 0, 4, 4, 5, 5, 5, 6, 6, + 7, 8, 8, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, + 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 6, 6, 6, 6, 6, 6, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, + 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 7, 7, 7, 8, 10, + 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + }; + static const BROTLI_MODEL("small") uint16_t kDefaultCommandBits[128] = { + 0, 0, 8, 9, 3, 35, 7, 71, + 39, 103, 23, 47, 175, 111, 239, 31, + 0, 0, 0, 4, 12, 2, 10, 6, + 13, 29, 11, 43, 27, 59, 87, 55, + 15, 79, 319, 831, 191, 703, 447, 959, + 0, 14, 1, 25, 5, 21, 19, 51, + 119, 159, 95, 223, 479, 991, 63, 575, + 127, 639, 383, 895, 255, 767, 511, 1023, + 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 27, 59, 7, 39, 23, 55, 30, 1, 17, 9, 25, 5, 0, 8, 4, 12, + 2, 10, 6, 21, 13, 29, 3, 19, 11, 15, 47, 31, 95, 63, 127, 255, + 767, 2815, 1791, 3839, 511, 2559, 1535, 3583, 1023, 3071, 2047, 4095, + }; + static const BROTLI_MODEL("small") uint8_t kDefaultCommandCode[] = { + 0xff, 0x77, 0xd5, 0xbf, 0xe7, 0xde, 0xea, 0x9e, 0x51, 0x5d, 0xde, 0xc6, + 0x70, 0x57, 0xbc, 0x58, 0x58, 0x58, 0xd8, 0xd8, 0x58, 0xd5, 0xcb, 0x8c, + 0xea, 0xe0, 0xc3, 0x87, 0x1f, 0x83, 0xc1, 0x60, 0x1c, 0x67, 0xb2, 0xaa, + 0x06, 0x83, 0xc1, 0x60, 0x30, 0x18, 0xcc, 0xa1, 0xce, 0x88, 0x54, 0x94, + 0x46, 0xe1, 0xb0, 0xd0, 0x4e, 0xb2, 0xf7, 0x04, 0x00, + }; + static const size_t kDefaultCommandCodeNumBits = 448; + COPY_ARRAY(s->cmd_depth, kDefaultCommandDepths); + COPY_ARRAY(s->cmd_bits, kDefaultCommandBits); + + /* Initialize the pre-compressed form of the command and distance prefix + codes. */ + COPY_ARRAY(s->cmd_code, kDefaultCommandCode); + s->cmd_code_numbits = kDefaultCommandCodeNumBits; +} + +/* TODO(eustas): avoid FP calculations. */ +static double EstimateEntropy(const uint32_t* population, size_t size) { + size_t total = 0; + double result = 0; + for (size_t i = 0; i < size; ++i) { + uint32_t p = population[i]; + total += p; + result += (double)p * FastLog2(p); + } + result = (double)total * FastLog2(total) - result; + return result; +} + +/* Decide about the context map based on the ability of the prediction + ability of the previous byte UTF8-prefix on the next byte. The + prediction ability is calculated as Shannon entropy. Here we need + Shannon entropy instead of 'BrotliBitsEntropy' since the prefix will be + encoded with the remaining 6 bits of the following byte, and + BrotliBitsEntropy will assume that symbol to be stored alone using Huffman + coding. */ +static void ChooseContextMap(int quality, + uint32_t* bigram_histo, + size_t* num_literal_contexts, + const uint32_t** literal_context_map) { + static const BROTLI_MODEL("small") + uint32_t kStaticContextMapContinuation[64] = { + 1, 1, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + static const BROTLI_MODEL("small") + uint32_t kStaticContextMapSimpleUTF8[64] = { + 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + }; + + uint32_t monogram_histo[3] = { 0 }; + uint32_t two_prefix_histo[6] = { 0 }; + size_t total; + size_t i; + double entropy[4]; + for (i = 0; i < 9; ++i) { + monogram_histo[i % 3] += bigram_histo[i]; + two_prefix_histo[i % 6] += bigram_histo[i]; + } + entropy[1] = EstimateEntropy(monogram_histo, 3); + entropy[2] = (EstimateEntropy(two_prefix_histo, 3) + + EstimateEntropy(two_prefix_histo + 3, 3)); + entropy[3] = 0; + for (i = 0; i < 3; ++i) { + entropy[3] += EstimateEntropy(bigram_histo + 3 * i, 3); + } + + total = monogram_histo[0] + monogram_histo[1] + monogram_histo[2]; + BROTLI_DCHECK(total != 0); + entropy[0] = 1.0 / (double)total; + entropy[1] *= entropy[0]; + entropy[2] *= entropy[0]; + entropy[3] *= entropy[0]; + + if (quality < MIN_QUALITY_FOR_HQ_CONTEXT_MODELING) { + /* 3 context models is a bit slower, don't use it at lower qualities. */ + entropy[3] = entropy[1] * 10; + } + /* If expected savings by symbol are less than 0.2 bits, skip the + context modeling -- in exchange for faster decoding speed. */ + if (entropy[1] - entropy[2] < 0.2 && + entropy[1] - entropy[3] < 0.2) { + *num_literal_contexts = 1; + } else if (entropy[2] - entropy[3] < 0.02) { + *num_literal_contexts = 2; + *literal_context_map = kStaticContextMapSimpleUTF8; + } else { + *num_literal_contexts = 3; + *literal_context_map = kStaticContextMapContinuation; + } +} + +/* Decide if we want to use a more complex static context map containing 13 + context values, based on the entropy reduction of histograms over the + first 5 bits of literals. */ +static BROTLI_BOOL ShouldUseComplexStaticContextMap(const uint8_t* input, + size_t start_pos, size_t length, size_t mask, int quality, size_t size_hint, + size_t* num_literal_contexts, const uint32_t** literal_context_map, + uint32_t* arena) { + static const BROTLI_MODEL("small") + uint32_t kStaticContextMapComplexUTF8[64] = { + 11, 11, 12, 12, /* 0 special */ + 0, 0, 0, 0, /* 4 lf */ + 1, 1, 9, 9, /* 8 space */ + 2, 2, 2, 2, /* !, first after space/lf and after something else. */ + 1, 1, 1, 1, /* " */ + 8, 3, 3, 3, /* % */ + 1, 1, 1, 1, /* ({[ */ + 2, 2, 2, 2, /* }]) */ + 8, 4, 4, 4, /* :; */ + 8, 7, 4, 4, /* . */ + 8, 0, 0, 0, /* > */ + 3, 3, 3, 3, /* [0..9] */ + 5, 5, 10, 5, /* [A-Z] */ + 5, 5, 10, 5, + 6, 6, 6, 6, /* [a-z] */ + 6, 6, 6, 6, + }; + BROTLI_UNUSED(quality); + /* Try the more complex static context map only for long data. */ + if (size_hint < (1 << 20)) { + return BROTLI_FALSE; + } else { + const size_t end_pos = start_pos + length; + /* To make entropy calculations faster, we collect histograms + over the 5 most significant bits of literals. One histogram + without context and 13 additional histograms for each context value. */ + uint32_t* BROTLI_RESTRICT const combined_histo = arena; + uint32_t* BROTLI_RESTRICT const context_histo = arena + 32; + uint32_t total = 0; + double entropy[3]; + size_t i; + ContextLut utf8_lut = BROTLI_CONTEXT_LUT(CONTEXT_UTF8); + memset(arena, 0, sizeof(arena[0]) * 32 * (BROTLI_MAX_STATIC_CONTEXTS + 1)); + for (; start_pos + 64 <= end_pos; start_pos += 4096) { + const size_t stride_end_pos = start_pos + 64; + uint8_t prev2 = input[start_pos & mask]; + uint8_t prev1 = input[(start_pos + 1) & mask]; + size_t pos; + /* To make the analysis of the data faster we only examine 64 byte long + strides at every 4kB intervals. */ + for (pos = start_pos + 2; pos < stride_end_pos; ++pos) { + const uint8_t literal = input[pos & mask]; + const uint8_t context = (uint8_t)kStaticContextMapComplexUTF8[ + BROTLI_CONTEXT(prev1, prev2, utf8_lut)]; + ++total; + ++combined_histo[literal >> 3]; + ++context_histo[(context << 5) + (literal >> 3)]; + prev2 = prev1; + prev1 = literal; + } + } + entropy[1] = EstimateEntropy(combined_histo, 32); + entropy[2] = 0; + for (i = 0; i < BROTLI_MAX_STATIC_CONTEXTS; ++i) { + entropy[2] += EstimateEntropy(context_histo + (i << 5), 32); + } + entropy[0] = 1.0 / (double)total; + entropy[1] *= entropy[0]; + entropy[2] *= entropy[0]; + /* The triggering heuristics below were tuned by compressing the individual + files of the silesia corpus. If we skip this kind of context modeling + for not very well compressible input (i.e. entropy using context modeling + is 60% of maximal entropy) or if expected savings by symbol are less + than 0.2 bits, then in every case when it triggers, the final compression + ratio is improved. Note however that this heuristics might be too strict + for some cases and could be tuned further. */ + if (entropy[2] > 3.0 || entropy[1] - entropy[2] < 0.2) { + return BROTLI_FALSE; + } else { + *num_literal_contexts = BROTLI_MAX_STATIC_CONTEXTS; + *literal_context_map = kStaticContextMapComplexUTF8; + return BROTLI_TRUE; + } + } +} + +static void DecideOverLiteralContextModeling(const uint8_t* input, + size_t start_pos, size_t length, size_t mask, int quality, size_t size_hint, + size_t* num_literal_contexts, const uint32_t** literal_context_map, + uint32_t* arena) { + if (quality < MIN_QUALITY_FOR_CONTEXT_MODELING || length < 64) { + return; + } else if (ShouldUseComplexStaticContextMap( + input, start_pos, length, mask, quality, size_hint, + num_literal_contexts, literal_context_map, arena)) { + /* Context map was already set, nothing else to do. */ + } else { + /* Gather bi-gram data of the UTF8 byte prefixes. To make the analysis of + UTF8 data faster we only examine 64 byte long strides at every 4kB + intervals. */ + const size_t end_pos = start_pos + length; + uint32_t* BROTLI_RESTRICT const bigram_prefix_histo = arena; + memset(bigram_prefix_histo, 0, sizeof(arena[0]) * 9); + for (; start_pos + 64 <= end_pos; start_pos += 4096) { + static const int lut[4] = { 0, 0, 1, 2 }; + const size_t stride_end_pos = start_pos + 64; + int prev = lut[input[start_pos & mask] >> 6] * 3; + size_t pos; + for (pos = start_pos + 1; pos < stride_end_pos; ++pos) { + const uint8_t literal = input[pos & mask]; + ++bigram_prefix_histo[prev + lut[literal >> 6]]; + prev = lut[literal >> 6] * 3; + } + } + ChooseContextMap(quality, &bigram_prefix_histo[0], num_literal_contexts, + literal_context_map); + } +} + +static BROTLI_BOOL ShouldCompress( + const uint8_t* data, const size_t mask, const uint64_t last_flush_pos, + const size_t bytes, const size_t num_literals, const size_t num_commands) { + /* TODO(eustas): find more precise minimal block overhead. */ + if (bytes <= 2) return BROTLI_FALSE; + if (num_commands < (bytes >> 8) + 2) { + if ((double)num_literals > 0.99 * (double)bytes) { + uint32_t literal_histo[256] = { 0 }; + static const uint32_t kSampleRate = 13; + static const double kInvSampleRate = 1.0 / 13.0; + static const double kMinEntropy = 7.92; + const double bit_cost_threshold = + (double)bytes * kMinEntropy * kInvSampleRate; + size_t t = (bytes + kSampleRate - 1) / kSampleRate; + uint32_t pos = (uint32_t)last_flush_pos; + size_t i; + for (i = 0; i < t; i++) { + ++literal_histo[data[pos & mask]]; + pos += kSampleRate; + } + if (BrotliBitsEntropy(literal_histo, 256) > bit_cost_threshold) { + return BROTLI_FALSE; + } + } + } + return BROTLI_TRUE; +} + +/* Chooses the literal context mode for a metablock */ +static ContextType ChooseContextMode(const BrotliEncoderParams* params, + const uint8_t* data, const size_t pos, const size_t mask, + const size_t length) { + /* We only do the computation for the option of something else than + CONTEXT_UTF8 for the highest qualities */ + if (params->quality >= MIN_QUALITY_FOR_HQ_BLOCK_SPLITTING && + !BrotliIsMostlyUTF8(data, pos, mask, length, kMinUTF8Ratio)) { + return CONTEXT_SIGNED; + } + return CONTEXT_UTF8; +} + +static void WriteMetaBlockInternal(MemoryManager* m, + const uint8_t* data, + const size_t mask, + const uint64_t last_flush_pos, + const size_t bytes, + const BROTLI_BOOL is_last, + ContextType literal_context_mode, + const BrotliEncoderParams* params, + const uint8_t prev_byte, + const uint8_t prev_byte2, + const size_t num_literals, + const size_t num_commands, + Command* commands, + const int* saved_dist_cache, + int* dist_cache, + size_t* storage_ix, + uint8_t* storage) { + const uint32_t wrapped_last_flush_pos = WrapPosition(last_flush_pos); + uint16_t last_bytes; + uint8_t last_bytes_bits; + ContextLut literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode); + BrotliEncoderParams block_params = *params; + + if (bytes == 0) { + /* Write the ISLAST and ISEMPTY bits. */ + BrotliWriteBits(2, 3, storage_ix, storage); + *storage_ix = (*storage_ix + 7u) & ~7u; + return; + } + + if (!ShouldCompress(data, mask, last_flush_pos, bytes, + num_literals, num_commands)) { + /* Restore the distance cache, as its last update by + CreateBackwardReferences is now unused. */ + memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0])); + BrotliStoreUncompressedMetaBlock(is_last, data, + wrapped_last_flush_pos, mask, bytes, + storage_ix, storage); + return; + } + + BROTLI_DCHECK(*storage_ix <= 14); + last_bytes = (uint16_t)((storage[1] << 8) | storage[0]); + last_bytes_bits = (uint8_t)(*storage_ix); + if (params->quality <= MAX_QUALITY_FOR_STATIC_ENTROPY_CODES) { + BrotliStoreMetaBlockFast(m, data, wrapped_last_flush_pos, + bytes, mask, is_last, params, + commands, num_commands, + storage_ix, storage); + if (BROTLI_IS_OOM(m)) return; + } else if (params->quality < MIN_QUALITY_FOR_BLOCK_SPLIT) { + BrotliStoreMetaBlockTrivial(m, data, wrapped_last_flush_pos, + bytes, mask, is_last, params, + commands, num_commands, + storage_ix, storage); + if (BROTLI_IS_OOM(m)) return; + } else { + MetaBlockSplit mb; + InitMetaBlockSplit(&mb); + if (params->quality < MIN_QUALITY_FOR_HQ_BLOCK_SPLITTING) { + size_t num_literal_contexts = 1; + const uint32_t* literal_context_map = NULL; + if (!params->disable_literal_context_modeling) { + /* TODO(eustas): pull to higher level and reuse. */ + uint32_t* arena = + BROTLI_ALLOC(m, uint32_t, 32 * (BROTLI_MAX_STATIC_CONTEXTS + 1)); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(arena)) return; + DecideOverLiteralContextModeling( + data, wrapped_last_flush_pos, bytes, mask, params->quality, + params->size_hint, &num_literal_contexts, + &literal_context_map, arena); + BROTLI_FREE(m, arena); + } + BrotliBuildMetaBlockGreedy(m, data, wrapped_last_flush_pos, mask, + prev_byte, prev_byte2, literal_context_lut, num_literal_contexts, + literal_context_map, commands, num_commands, &mb); + if (BROTLI_IS_OOM(m)) return; + } else { + BrotliBuildMetaBlock(m, data, wrapped_last_flush_pos, mask, &block_params, + prev_byte, prev_byte2, + commands, num_commands, + literal_context_mode, + &mb); + if (BROTLI_IS_OOM(m)) return; + } + if (params->quality >= MIN_QUALITY_FOR_OPTIMIZE_HISTOGRAMS) { + /* The number of distance symbols effectively used for distance + histograms. It might be less than distance alphabet size + for "Large Window Brotli" (32-bit). */ + BrotliOptimizeHistograms(block_params.dist.alphabet_size_limit, &mb); + } + BrotliStoreMetaBlock(m, data, wrapped_last_flush_pos, bytes, mask, + prev_byte, prev_byte2, + is_last, + &block_params, + literal_context_mode, + commands, num_commands, + &mb, + storage_ix, storage); + if (BROTLI_IS_OOM(m)) return; + DestroyMetaBlockSplit(m, &mb); + } + if (bytes + 4 < (*storage_ix >> 3)) { + /* Restore the distance cache and last byte. */ + memcpy(dist_cache, saved_dist_cache, 4 * sizeof(dist_cache[0])); + storage[0] = (uint8_t)last_bytes; + storage[1] = (uint8_t)(last_bytes >> 8); + *storage_ix = last_bytes_bits; + BrotliStoreUncompressedMetaBlock(is_last, data, + wrapped_last_flush_pos, mask, + bytes, storage_ix, storage); + } +} + +static void ChooseDistanceParams(BrotliEncoderParams* params) { + uint32_t distance_postfix_bits = 0; + uint32_t num_direct_distance_codes = 0; + + if (params->quality >= MIN_QUALITY_FOR_NONZERO_DISTANCE_PARAMS) { + uint32_t ndirect_msb; + if (params->mode == BROTLI_MODE_FONT) { + distance_postfix_bits = 1; + num_direct_distance_codes = 12; + } else { + distance_postfix_bits = params->dist.distance_postfix_bits; + num_direct_distance_codes = params->dist.num_direct_distance_codes; + } + ndirect_msb = (num_direct_distance_codes >> distance_postfix_bits) & 0x0F; + if (distance_postfix_bits > BROTLI_MAX_NPOSTFIX || + num_direct_distance_codes > BROTLI_MAX_NDIRECT || + (ndirect_msb << distance_postfix_bits) != num_direct_distance_codes) { + distance_postfix_bits = 0; + num_direct_distance_codes = 0; + } + } + + BrotliInitDistanceParams(¶ms->dist, distance_postfix_bits, + num_direct_distance_codes, params->large_window); +} + +static BROTLI_BOOL EnsureInitialized(BrotliEncoderState* s) { + MemoryManager* m = &s->memory_manager_; + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + if (s->is_initialized_) return BROTLI_TRUE; + + s->last_bytes_bits_ = 0; + s->last_bytes_ = 0; + s->flint_ = BROTLI_FLINT_DONE; + s->remaining_metadata_bytes_ = BROTLI_UINT32_MAX; + + SanitizeParams(&s->params); + s->params.lgblock = ComputeLgBlock(&s->params); + ChooseDistanceParams(&s->params); + + if (s->params.stream_offset != 0) { + s->flint_ = BROTLI_FLINT_NEEDS_2_BYTES; + /* Poison the distance cache. -16 +- 3 is still less than zero (invalid). */ + s->dist_cache_[0] = -16; + s->dist_cache_[1] = -16; + s->dist_cache_[2] = -16; + s->dist_cache_[3] = -16; + memcpy(s->saved_dist_cache_, s->dist_cache_, sizeof(s->saved_dist_cache_)); + } + + RingBufferSetup(&s->params, &s->ringbuffer_); + + /* Initialize last byte with stream header. */ + { + int lgwin = s->params.lgwin; + if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY || + s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) { + lgwin = BROTLI_MAX(int, lgwin, 18); + } + if (s->params.stream_offset == 0) { + EncodeWindowBits(lgwin, s->params.large_window, + &s->last_bytes_, &s->last_bytes_bits_); + } else { + /* Bigger values have the same effect, but could cause overflows. */ + s->params.stream_offset = BROTLI_MIN(size_t, + s->params.stream_offset, BROTLI_MAX_BACKWARD_LIMIT(lgwin)); + } + } + + if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY) { + s->one_pass_arena_ = BROTLI_ALLOC(m, BrotliOnePassArena, 1); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + InitCommandPrefixCodes(s->one_pass_arena_); + } else if (s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) { + s->two_pass_arena_ = BROTLI_ALLOC(m, BrotliTwoPassArena, 1); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + } + + s->is_initialized_ = BROTLI_TRUE; + return BROTLI_TRUE; +} + +static void BrotliEncoderInitParams(BrotliEncoderParams* params) { + params->mode = BROTLI_DEFAULT_MODE; + params->large_window = BROTLI_FALSE; + params->quality = BROTLI_DEFAULT_QUALITY; + params->lgwin = BROTLI_DEFAULT_WINDOW; + params->lgblock = 0; + params->stream_offset = 0; + params->size_hint = 0; + params->disable_literal_context_modeling = BROTLI_FALSE; + BrotliInitSharedEncoderDictionary(¶ms->dictionary); + params->dist.distance_postfix_bits = 0; + params->dist.num_direct_distance_codes = 0; + params->dist.alphabet_size_max = + BROTLI_DISTANCE_ALPHABET_SIZE(0, 0, BROTLI_MAX_DISTANCE_BITS); + params->dist.alphabet_size_limit = params->dist.alphabet_size_max; + params->dist.max_distance = BROTLI_MAX_DISTANCE; +} + +static void BrotliEncoderCleanupParams(MemoryManager* m, + BrotliEncoderParams* params) { + BrotliCleanupSharedEncoderDictionary(m, ¶ms->dictionary); +} + +#ifdef BROTLI_REPORTING +/* When BROTLI_REPORTING is defined extra reporting module have to be linked. */ +void BrotliEncoderOnStart(const BrotliEncoderState* s); +void BrotliEncoderOnFinish(const BrotliEncoderState* s); +#define BROTLI_ENCODER_ON_START(s) BrotliEncoderOnStart(s); +#define BROTLI_ENCODER_ON_FINISH(s) BrotliEncoderOnFinish(s); +#else +#if !defined(BROTLI_ENCODER_ON_START) +#define BROTLI_ENCODER_ON_START(s) (void)(s); +#endif +#if !defined(BROTLI_ENCODER_ON_FINISH) +#define BROTLI_ENCODER_ON_FINISH(s) (void)(s); +#endif +#endif + +static void BrotliEncoderInitState(BrotliEncoderState* s) { + BROTLI_ENCODER_ON_START(s); + BrotliEncoderInitParams(&s->params); + s->input_pos_ = 0; + s->num_commands_ = 0; + s->num_literals_ = 0; + s->last_insert_len_ = 0; + s->last_flush_pos_ = 0; + s->last_processed_pos_ = 0; + s->prev_byte_ = 0; + s->prev_byte2_ = 0; + s->storage_size_ = 0; + s->storage_ = 0; + HasherInit(&s->hasher_); + s->large_table_ = NULL; + s->large_table_size_ = 0; + s->one_pass_arena_ = NULL; + s->two_pass_arena_ = NULL; + s->command_buf_ = NULL; + s->literal_buf_ = NULL; + s->total_in_ = 0; + s->next_out_ = NULL; + s->available_out_ = 0; + s->total_out_ = 0; + s->stream_state_ = BROTLI_STREAM_PROCESSING; + s->is_last_block_emitted_ = BROTLI_FALSE; + s->is_initialized_ = BROTLI_FALSE; + + RingBufferInit(&s->ringbuffer_); + + s->commands_ = 0; + s->cmd_alloc_size_ = 0; + + /* Initialize distance cache. */ + s->dist_cache_[0] = 4; + s->dist_cache_[1] = 11; + s->dist_cache_[2] = 15; + s->dist_cache_[3] = 16; + /* Save the state of the distance cache in case we need to restore it for + emitting an uncompressed block. */ + memcpy(s->saved_dist_cache_, s->dist_cache_, sizeof(s->saved_dist_cache_)); +} + +BrotliEncoderState* BrotliEncoderCreateInstance( + brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) { + BROTLI_BOOL healthy = BrotliEncoderEnsureStaticInit(); + if (!healthy) { + return 0; + } + BrotliEncoderState* state = (BrotliEncoderState*)BrotliBootstrapAlloc( + sizeof(BrotliEncoderState), alloc_func, free_func, opaque); + if (state == NULL) { + /* BROTLI_DUMP(); */ + return 0; + } + BrotliInitMemoryManager( + &state->memory_manager_, alloc_func, free_func, opaque); + BrotliEncoderInitState(state); + return state; +} + +static void BrotliEncoderCleanupState(BrotliEncoderState* s) { + MemoryManager* m = &s->memory_manager_; + + BROTLI_ENCODER_ON_FINISH(s); + + if (BROTLI_IS_OOM(m)) { + BrotliWipeOutMemoryManager(m); + return; + } + + BROTLI_FREE(m, s->storage_); + BROTLI_FREE(m, s->commands_); + RingBufferFree(m, &s->ringbuffer_); + DestroyHasher(m, &s->hasher_); + BROTLI_FREE(m, s->large_table_); + BROTLI_FREE(m, s->one_pass_arena_); + BROTLI_FREE(m, s->two_pass_arena_); + BROTLI_FREE(m, s->command_buf_); + BROTLI_FREE(m, s->literal_buf_); + BrotliEncoderCleanupParams(m, &s->params); +} + +/* Deinitializes and frees BrotliEncoderState instance. */ +void BrotliEncoderDestroyInstance(BrotliEncoderState* state) { + if (!state) { + return; + } else { + BrotliEncoderCleanupState(state); + BrotliBootstrapFree(state, &state->memory_manager_); + } +} + +/* + Copies the given input data to the internal ring buffer of the compressor. + No processing of the data occurs at this time and this function can be + called multiple times before calling WriteBrotliData() to process the + accumulated input. At most input_block_size() bytes of input data can be + copied to the ring buffer, otherwise the next WriteBrotliData() will fail. + */ +static void CopyInputToRingBuffer(BrotliEncoderState* s, + const size_t input_size, + const uint8_t* input_buffer) { + RingBuffer* ringbuffer_ = &s->ringbuffer_; + MemoryManager* m = &s->memory_manager_; + RingBufferWrite(m, input_buffer, input_size, ringbuffer_); + if (BROTLI_IS_OOM(m)) return; + s->input_pos_ += input_size; + + /* TL;DR: If needed, initialize 7 more bytes in the ring buffer to make the + hashing not depend on uninitialized data. This makes compression + deterministic and it prevents uninitialized memory warnings in Valgrind. + Even without erasing, the output would be valid (but nondeterministic). + + Background information: The compressor stores short (at most 8 bytes) + substrings of the input already read in a hash table, and detects + repetitions by looking up such substrings in the hash table. If it + can find a substring, it checks whether the substring is really there + in the ring buffer (or it's just a hash collision). Should the hash + table become corrupt, this check makes sure that the output is + still valid, albeit the compression ratio would be bad. + + The compressor populates the hash table from the ring buffer as it's + reading new bytes from the input. However, at the last few indexes of + the ring buffer, there are not enough bytes to build full-length + substrings from. Since the hash table always contains full-length + substrings, we overwrite with zeros here to make sure that those + substrings will contain zeros at the end instead of uninitialized + data. + + Please note that erasing is not necessary (because the + memory region is already initialized since he ring buffer + has a `tail' that holds a copy of the beginning,) so we + skip erasing if we have already gone around at least once in + the ring buffer. + + Only clear during the first round of ring-buffer writes. On + subsequent rounds data in the ring-buffer would be affected. */ + if (ringbuffer_->pos_ <= ringbuffer_->mask_) { + /* This is the first time when the ring buffer is being written. + We clear 7 bytes just after the bytes that have been copied from + the input buffer. + + The ring-buffer has a "tail" that holds a copy of the beginning, + but only once the ring buffer has been fully written once, i.e., + pos <= mask. For the first time, we need to write values + in this tail (where index may be larger than mask), so that + we have exactly defined behavior and don't read uninitialized + memory. Due to performance reasons, hashing reads data using a + LOAD64, which can go 7 bytes beyond the bytes written in the + ring-buffer. */ + memset(ringbuffer_->buffer_ + ringbuffer_->pos_, 0, 7); + } +} + +/* Marks all input as processed. + Returns true if position wrapping occurs. */ +static BROTLI_BOOL UpdateLastProcessedPos(BrotliEncoderState* s) { + uint32_t wrapped_last_processed_pos = WrapPosition(s->last_processed_pos_); + uint32_t wrapped_input_pos = WrapPosition(s->input_pos_); + s->last_processed_pos_ = s->input_pos_; + return TO_BROTLI_BOOL(wrapped_input_pos < wrapped_last_processed_pos); +} + +static void ExtendLastCommand(BrotliEncoderState* s, uint32_t* bytes, + uint32_t* wrapped_last_processed_pos) { + Command* last_command = &s->commands_[s->num_commands_ - 1]; + const uint8_t* data = s->ringbuffer_.buffer_; + const uint32_t mask = s->ringbuffer_.mask_; + uint64_t max_backward_distance = + (((uint64_t)1) << s->params.lgwin) - BROTLI_WINDOW_GAP; + uint64_t last_copy_len = last_command->copy_len_ & 0x1FFFFFF; + uint64_t last_processed_pos = s->last_processed_pos_ - last_copy_len; + uint64_t max_distance = last_processed_pos < max_backward_distance ? + last_processed_pos : max_backward_distance; + uint64_t cmd_dist = (uint64_t)s->dist_cache_[0]; + uint32_t distance_code = CommandRestoreDistanceCode(last_command, + &s->params.dist); + const CompoundDictionary* dict = &s->params.dictionary.compound; + size_t compound_dictionary_size = dict->total_size; + if (distance_code < BROTLI_NUM_DISTANCE_SHORT_CODES || + distance_code - (BROTLI_NUM_DISTANCE_SHORT_CODES - 1) == cmd_dist) { + if (cmd_dist <= max_distance) { + while (*bytes != 0 && data[*wrapped_last_processed_pos & mask] == + data[(*wrapped_last_processed_pos - cmd_dist) & mask]) { + last_command->copy_len_++; + (*bytes)--; + (*wrapped_last_processed_pos)++; + } + } else { + if ((cmd_dist - max_distance - 1) < compound_dictionary_size && + last_copy_len < cmd_dist - max_distance) { + size_t address = + compound_dictionary_size - (size_t)(cmd_dist - max_distance) + + (size_t)last_copy_len; + size_t br_index = 0; + size_t br_offset; + const uint8_t* chunk; + size_t chunk_length; + while (address >= dict->chunk_offsets[br_index + 1]) br_index++; + br_offset = address - dict->chunk_offsets[br_index]; + chunk = dict->chunk_source[br_index]; + chunk_length = + dict->chunk_offsets[br_index + 1] - dict->chunk_offsets[br_index]; + while (*bytes != 0 && data[*wrapped_last_processed_pos & mask] == + chunk[br_offset]) { + last_command->copy_len_++; + (*bytes)--; + (*wrapped_last_processed_pos)++; + if (++br_offset == chunk_length) { + br_index++; + br_offset = 0; + if (br_index != dict->num_chunks) { + chunk = dict->chunk_source[br_index]; + chunk_length = dict->chunk_offsets[br_index + 1] - + dict->chunk_offsets[br_index]; + } else { + break; + } + } + } + } + } + /* The copy length is at most the metablock size, and thus expressible. */ + GetLengthCode(last_command->insert_len_, + (size_t)((int)(last_command->copy_len_ & 0x1FFFFFF) + + (int)(last_command->copy_len_ >> 25)), + TO_BROTLI_BOOL((last_command->dist_prefix_ & 0x3FF) == 0), + &last_command->cmd_prefix_); + } +} + +/* + Processes the accumulated input data and sets |*out_size| to the length of + the new output meta-block, or to zero if no new output meta-block has been + created (in this case the processed input data is buffered internally). + If |*out_size| is positive, |*output| points to the start of the output + data. If |is_last| or |force_flush| is BROTLI_TRUE, an output meta-block is + always created. However, until |is_last| is BROTLI_TRUE encoder may retain up + to 7 bits of the last byte of output. Byte-alignment could be enforced by + emitting an empty meta-data block. + Returns BROTLI_FALSE if the size of the input data is larger than + input_block_size(). + */ +static BROTLI_BOOL EncodeData( + BrotliEncoderState* s, const BROTLI_BOOL is_last, + const BROTLI_BOOL force_flush, size_t* out_size, uint8_t** output) { + const uint64_t delta = UnprocessedInputSize(s); + uint32_t bytes = (uint32_t)delta; + uint32_t wrapped_last_processed_pos = WrapPosition(s->last_processed_pos_); + uint8_t* data; + uint32_t mask; + MemoryManager* m = &s->memory_manager_; + ContextType literal_context_mode; + ContextLut literal_context_lut; + BROTLI_BOOL fast_compress = + s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY || + s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY; + + data = s->ringbuffer_.buffer_; + mask = s->ringbuffer_.mask_; + + if (delta == 0) { /* No new input; still might want to flush or finish. */ + if (!data) { /* No input has been processed so far. */ + if (is_last) { /* Emit complete finalized stream. */ + BROTLI_DCHECK(s->last_bytes_bits_ <= 14); + s->last_bytes_ |= (uint16_t)(3u << s->last_bytes_bits_); + s->last_bytes_bits_ = (uint8_t)(s->last_bytes_bits_ + 2u); + s->tiny_buf_.u8[0] = (uint8_t)s->last_bytes_; + s->tiny_buf_.u8[1] = (uint8_t)(s->last_bytes_ >> 8); + *output = s->tiny_buf_.u8; + *out_size = (s->last_bytes_bits_ + 7u) >> 3u; + return BROTLI_TRUE; + } else { /* No data, not last -> no-op. */ + *out_size = 0; + return BROTLI_TRUE; + } + } else { + /* Fast compress performs flush every block -> flush is no-op. */ + if (!is_last && (!force_flush || fast_compress)) { /* Another no-op. */ + *out_size = 0; + return BROTLI_TRUE; + } + } + } + BROTLI_DCHECK(data); + + if (s->params.quality > s->params.dictionary.max_quality) return BROTLI_FALSE; + /* Adding more blocks after "last" block is forbidden. */ + if (s->is_last_block_emitted_) return BROTLI_FALSE; + if (is_last) s->is_last_block_emitted_ = BROTLI_TRUE; + + if (delta > InputBlockSize(s)) { + return BROTLI_FALSE; + } + if (s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY && + !s->command_buf_) { + s->command_buf_ = + BROTLI_ALLOC(m, uint32_t, kCompressFragmentTwoPassBlockSize); + s->literal_buf_ = + BROTLI_ALLOC(m, uint8_t, kCompressFragmentTwoPassBlockSize); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->command_buf_) || + BROTLI_IS_NULL(s->literal_buf_)) { + return BROTLI_FALSE; + } + } + + if (fast_compress) { + uint8_t* storage; + size_t storage_ix = s->last_bytes_bits_; + size_t table_size; + int* table; + + storage = GetBrotliStorage(s, 2 * bytes + 503); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + storage[0] = (uint8_t)s->last_bytes_; + storage[1] = (uint8_t)(s->last_bytes_ >> 8); + table = GetHashTable(s, s->params.quality, bytes, &table_size); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY) { + BrotliCompressFragmentFast( + s->one_pass_arena_, &data[wrapped_last_processed_pos & mask], + bytes, is_last, + table, table_size, + &storage_ix, storage); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + } else { + BrotliCompressFragmentTwoPass( + s->two_pass_arena_, &data[wrapped_last_processed_pos & mask], + bytes, is_last, + s->command_buf_, s->literal_buf_, + table, table_size, + &storage_ix, storage); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + } + s->last_bytes_ = (uint16_t)(storage[storage_ix >> 3]); + s->last_bytes_bits_ = storage_ix & 7u; + UpdateLastProcessedPos(s); + *output = &storage[0]; + *out_size = storage_ix >> 3; + return BROTLI_TRUE; + } + + { + /* Theoretical max number of commands is 1 per 2 bytes. */ + size_t newsize = s->num_commands_ + bytes / 2 + 1; + if (newsize > s->cmd_alloc_size_) { + Command* new_commands; + /* Reserve a bit more memory to allow merging with a next block + without reallocation: that would impact speed. */ + newsize += (bytes / 4) + 16; + s->cmd_alloc_size_ = newsize; + new_commands = BROTLI_ALLOC(m, Command, newsize); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_commands)) return BROTLI_FALSE; + if (s->commands_) { + memcpy(new_commands, s->commands_, sizeof(Command) * s->num_commands_); + BROTLI_FREE(m, s->commands_); + } + s->commands_ = new_commands; + } + } + + InitOrStitchToPreviousBlock(m, &s->hasher_, data, mask, &s->params, + wrapped_last_processed_pos, bytes, is_last); + + literal_context_mode = ChooseContextMode( + &s->params, data, WrapPosition(s->last_flush_pos_), + mask, (size_t)(s->input_pos_ - s->last_flush_pos_)); + literal_context_lut = BROTLI_CONTEXT_LUT(literal_context_mode); + + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + + if (s->num_commands_ && s->last_insert_len_ == 0) { + ExtendLastCommand(s, &bytes, &wrapped_last_processed_pos); + } + + if (s->params.quality == ZOPFLIFICATION_QUALITY) { + BROTLI_DCHECK(s->params.hasher.type == 10); + BrotliCreateZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos, + data, mask, literal_context_lut, &s->params, + &s->hasher_, s->dist_cache_, + &s->last_insert_len_, &s->commands_[s->num_commands_], + &s->num_commands_, &s->num_literals_); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + } else if (s->params.quality == HQ_ZOPFLIFICATION_QUALITY) { + BROTLI_DCHECK(s->params.hasher.type == 10); + BrotliCreateHqZopfliBackwardReferences(m, bytes, wrapped_last_processed_pos, + data, mask, literal_context_lut, &s->params, + &s->hasher_, s->dist_cache_, + &s->last_insert_len_, &s->commands_[s->num_commands_], + &s->num_commands_, &s->num_literals_); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + } else { + BrotliCreateBackwardReferences(bytes, wrapped_last_processed_pos, + data, mask, literal_context_lut, &s->params, + &s->hasher_, s->dist_cache_, + &s->last_insert_len_, &s->commands_[s->num_commands_], + &s->num_commands_, &s->num_literals_); + } + + { + const size_t max_length = MaxMetablockSize(&s->params); + const size_t max_literals = max_length / 8; + const size_t max_commands = max_length / 8; + const size_t processed_bytes = (size_t)(s->input_pos_ - s->last_flush_pos_); + /* If maximal possible additional block doesn't fit metablock, flush now. */ + /* TODO(eustas): Postpone decision until next block arrives? */ + const BROTLI_BOOL next_input_fits_metablock = TO_BROTLI_BOOL( + processed_bytes + InputBlockSize(s) <= max_length); + /* If block splitting is not used, then flush as soon as there is some + amount of commands / literals produced. */ + const BROTLI_BOOL should_flush = TO_BROTLI_BOOL( + s->params.quality < MIN_QUALITY_FOR_BLOCK_SPLIT && + s->num_literals_ + s->num_commands_ >= MAX_NUM_DELAYED_SYMBOLS); + if (!is_last && !force_flush && !should_flush && + next_input_fits_metablock && + s->num_literals_ < max_literals && + s->num_commands_ < max_commands) { + /* Merge with next input block. Everything will happen later. */ + if (UpdateLastProcessedPos(s)) { + HasherReset(&s->hasher_); + } + *out_size = 0; + return BROTLI_TRUE; + } + } + + /* Create the last insert-only command. */ + if (s->last_insert_len_ > 0) { + InitInsertCommand(&s->commands_[s->num_commands_++], s->last_insert_len_); + s->num_literals_ += s->last_insert_len_; + s->last_insert_len_ = 0; + } + + if (!is_last && s->input_pos_ == s->last_flush_pos_) { + /* We have no new input data and we don't have to finish the stream, so + nothing to do. */ + *out_size = 0; + return BROTLI_TRUE; + } + BROTLI_DCHECK(s->input_pos_ >= s->last_flush_pos_); + BROTLI_DCHECK(s->input_pos_ > s->last_flush_pos_ || is_last); + BROTLI_DCHECK(s->input_pos_ - s->last_flush_pos_ <= 1u << 24); + { + const uint32_t metablock_size = + (uint32_t)(s->input_pos_ - s->last_flush_pos_); + uint8_t* storage = GetBrotliStorage(s, 2 * metablock_size + 503); + size_t storage_ix = s->last_bytes_bits_; + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + storage[0] = (uint8_t)s->last_bytes_; + storage[1] = (uint8_t)(s->last_bytes_ >> 8); + WriteMetaBlockInternal( + m, data, mask, s->last_flush_pos_, metablock_size, is_last, + literal_context_mode, &s->params, s->prev_byte_, s->prev_byte2_, + s->num_literals_, s->num_commands_, s->commands_, s->saved_dist_cache_, + s->dist_cache_, &storage_ix, storage); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + s->last_bytes_ = (uint16_t)(storage[storage_ix >> 3]); + s->last_bytes_bits_ = storage_ix & 7u; + s->last_flush_pos_ = s->input_pos_; + if (UpdateLastProcessedPos(s)) { + HasherReset(&s->hasher_); + } + if (s->last_flush_pos_ > 0) { + s->prev_byte_ = data[((uint32_t)s->last_flush_pos_ - 1) & mask]; + } + if (s->last_flush_pos_ > 1) { + s->prev_byte2_ = data[(uint32_t)(s->last_flush_pos_ - 2) & mask]; + } + s->num_commands_ = 0; + s->num_literals_ = 0; + /* Save the state of the distance cache in case we need to restore it for + emitting an uncompressed block. */ + memcpy(s->saved_dist_cache_, s->dist_cache_, sizeof(s->saved_dist_cache_)); + *output = &storage[0]; + *out_size = storage_ix >> 3; + return BROTLI_TRUE; + } +} + +/* Dumps remaining output bits and metadata header to |header|. + Returns number of produced bytes. + REQUIRED: |header| should be 8-byte aligned and at least 16 bytes long. + REQUIRED: |block_size| <= (1 << 24). */ +static size_t WriteMetadataHeader( + BrotliEncoderState* s, const size_t block_size, uint8_t* header) { + size_t storage_ix; + storage_ix = s->last_bytes_bits_; + header[0] = (uint8_t)s->last_bytes_; + header[1] = (uint8_t)(s->last_bytes_ >> 8); + s->last_bytes_ = 0; + s->last_bytes_bits_ = 0; + + BrotliWriteBits(1, 0, &storage_ix, header); + BrotliWriteBits(2, 3, &storage_ix, header); + BrotliWriteBits(1, 0, &storage_ix, header); + if (block_size == 0) { + BrotliWriteBits(2, 0, &storage_ix, header); + } else { + uint32_t nbits = (block_size == 1) ? 1 : + (Log2FloorNonZero((uint32_t)block_size - 1) + 1); + uint32_t nbytes = (nbits + 7) / 8; + BrotliWriteBits(2, nbytes, &storage_ix, header); + BrotliWriteBits(8 * nbytes, block_size - 1, &storage_ix, header); + } + return (storage_ix + 7u) >> 3; +} + +size_t BrotliEncoderMaxCompressedSize(size_t input_size) { + /* [window bits / empty metadata] + N * [uncompressed] + [last empty] */ + size_t num_large_blocks = input_size >> 14; + size_t overhead = 2 + (4 * num_large_blocks) + 3 + 1; + size_t result = input_size + overhead; + if (input_size == 0) return 2; + return (result < input_size) ? 0 : result; +} + +/* Wraps data to uncompressed brotli stream with minimal window size. + |output| should point at region with at least BrotliEncoderMaxCompressedSize + addressable bytes. + Returns the length of stream. */ +static size_t MakeUncompressedStream( + const uint8_t* input, size_t input_size, uint8_t* output) { + size_t size = input_size; + size_t result = 0; + size_t offset = 0; + if (input_size == 0) { + output[0] = 6; + return 1; + } + output[result++] = 0x21; /* window bits = 10, is_last = false */ + output[result++] = 0x03; /* empty metadata, padding */ + while (size > 0) { + uint32_t nibbles = 0; + uint32_t chunk_size; + uint32_t bits; + chunk_size = (size > (1u << 24)) ? (1u << 24) : (uint32_t)size; + if (chunk_size > (1u << 16)) nibbles = (chunk_size > (1u << 20)) ? 2 : 1; + bits = + (nibbles << 1) | ((chunk_size - 1) << 3) | (1u << (19 + 4 * nibbles)); + output[result++] = (uint8_t)bits; + output[result++] = (uint8_t)(bits >> 8); + output[result++] = (uint8_t)(bits >> 16); + if (nibbles == 2) output[result++] = (uint8_t)(bits >> 24); + memcpy(&output[result], &input[offset], chunk_size); + result += chunk_size; + offset += chunk_size; + size -= chunk_size; + } + output[result++] = 3; + return result; +} + +BROTLI_BOOL BrotliEncoderCompress( + int quality, int lgwin, BrotliEncoderMode mode, size_t input_size, + const uint8_t input_buffer[BROTLI_ARRAY_PARAM(input_size)], + size_t* encoded_size, + uint8_t encoded_buffer[BROTLI_ARRAY_PARAM(*encoded_size)]) { + BrotliEncoderState* s; + size_t out_size = *encoded_size; + const uint8_t* input_start = input_buffer; + uint8_t* output_start = encoded_buffer; + size_t max_out_size = BrotliEncoderMaxCompressedSize(input_size); + if (out_size == 0) { + /* Output buffer needs at least one byte. */ + return BROTLI_FALSE; + } + if (input_size == 0) { + /* Handle the special case of empty input. */ + *encoded_size = 1; + *encoded_buffer = 6; + return BROTLI_TRUE; + } + + s = BrotliEncoderCreateInstance(0, 0, 0); + if (!s) { + return BROTLI_FALSE; + } else { + size_t available_in = input_size; + const uint8_t* next_in = input_buffer; + size_t available_out = *encoded_size; + uint8_t* next_out = encoded_buffer; + size_t total_out = 0; + BROTLI_BOOL result = BROTLI_FALSE; + /* TODO(eustas): check that parameters are sane. */ + BrotliEncoderSetParameter(s, BROTLI_PARAM_QUALITY, (uint32_t)quality); + BrotliEncoderSetParameter(s, BROTLI_PARAM_LGWIN, (uint32_t)lgwin); + BrotliEncoderSetParameter(s, BROTLI_PARAM_MODE, (uint32_t)mode); + BrotliEncoderSetParameter(s, BROTLI_PARAM_SIZE_HINT, (uint32_t)input_size); + if (lgwin > BROTLI_MAX_WINDOW_BITS) { + BrotliEncoderSetParameter(s, BROTLI_PARAM_LARGE_WINDOW, BROTLI_TRUE); + } + result = BrotliEncoderCompressStream(s, BROTLI_OPERATION_FINISH, + &available_in, &next_in, &available_out, &next_out, &total_out); + if (!BrotliEncoderIsFinished(s)) result = 0; + *encoded_size = total_out; + BrotliEncoderDestroyInstance(s); + if (!result || (max_out_size && *encoded_size > max_out_size)) { + goto fallback; + } + return BROTLI_TRUE; + } +fallback: + *encoded_size = 0; + if (!max_out_size) return BROTLI_FALSE; + if (out_size >= max_out_size) { + *encoded_size = + MakeUncompressedStream(input_start, input_size, output_start); + return BROTLI_TRUE; + } + return BROTLI_FALSE; +} + +static void InjectBytePaddingBlock(BrotliEncoderState* s) { + uint32_t seal = s->last_bytes_; + size_t seal_bits = s->last_bytes_bits_; + uint8_t* destination; + s->last_bytes_ = 0; + s->last_bytes_bits_ = 0; + /* is_last = 0, data_nibbles = 11, reserved = 0, meta_nibbles = 00 */ + seal |= 0x6u << seal_bits; + seal_bits += 6; + /* If we have already created storage, then append to it. + Storage is valid until next block is being compressed. */ + if (s->next_out_) { + destination = s->next_out_ + s->available_out_; + } else { + destination = s->tiny_buf_.u8; + s->next_out_ = destination; + } + destination[0] = (uint8_t)seal; + if (seal_bits > 8) destination[1] = (uint8_t)(seal >> 8); + if (seal_bits > 16) destination[2] = (uint8_t)(seal >> 16); + s->available_out_ += (seal_bits + 7) >> 3; +} + +/* Fills the |total_out|, if it is not NULL. */ +static void SetTotalOut(BrotliEncoderState* s, size_t* total_out) { + if (total_out) { + /* Saturating conversion uint64_t -> size_t */ + size_t result = (size_t)-1; + if (s->total_out_ < result) { + result = (size_t)s->total_out_; + } + *total_out = result; + } +} + +/* Injects padding bits or pushes compressed data to output. + Returns false if nothing is done. */ +static BROTLI_BOOL InjectFlushOrPushOutput(BrotliEncoderState* s, + size_t* available_out, uint8_t** next_out, size_t* total_out) { + if (s->stream_state_ == BROTLI_STREAM_FLUSH_REQUESTED && + s->last_bytes_bits_ != 0) { + InjectBytePaddingBlock(s); + return BROTLI_TRUE; + } + + if (s->available_out_ != 0 && *available_out != 0) { + size_t copy_output_size = + BROTLI_MIN(size_t, s->available_out_, *available_out); + memcpy(*next_out, s->next_out_, copy_output_size); + *next_out += copy_output_size; + *available_out -= copy_output_size; + s->next_out_ += copy_output_size; + s->available_out_ -= copy_output_size; + s->total_out_ += copy_output_size; + SetTotalOut(s, total_out); + return BROTLI_TRUE; + } + + return BROTLI_FALSE; +} + +static void CheckFlushComplete(BrotliEncoderState* s) { + if (s->stream_state_ == BROTLI_STREAM_FLUSH_REQUESTED && + s->available_out_ == 0) { + s->stream_state_ = BROTLI_STREAM_PROCESSING; + s->next_out_ = 0; + } +} + +static BROTLI_BOOL BrotliEncoderCompressStreamFast( + BrotliEncoderState* s, BrotliEncoderOperation op, size_t* available_in, + const uint8_t** next_in, size_t* available_out, uint8_t** next_out, + size_t* total_out) { + const size_t block_size_limit = (size_t)1 << s->params.lgwin; + const size_t buf_size = BROTLI_MIN(size_t, kCompressFragmentTwoPassBlockSize, + BROTLI_MIN(size_t, *available_in, block_size_limit)); + uint32_t* tmp_command_buf = NULL; + uint32_t* command_buf = NULL; + uint8_t* tmp_literal_buf = NULL; + uint8_t* literal_buf = NULL; + MemoryManager* m = &s->memory_manager_; + if (s->params.quality != FAST_ONE_PASS_COMPRESSION_QUALITY && + s->params.quality != FAST_TWO_PASS_COMPRESSION_QUALITY) { + return BROTLI_FALSE; + } + if (s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) { + if (!s->command_buf_ && buf_size == kCompressFragmentTwoPassBlockSize) { + s->command_buf_ = + BROTLI_ALLOC(m, uint32_t, kCompressFragmentTwoPassBlockSize); + s->literal_buf_ = + BROTLI_ALLOC(m, uint8_t, kCompressFragmentTwoPassBlockSize); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(s->command_buf_) || + BROTLI_IS_NULL(s->literal_buf_)) { + return BROTLI_FALSE; + } + } + if (s->command_buf_) { + command_buf = s->command_buf_; + literal_buf = s->literal_buf_; + } else { + tmp_command_buf = BROTLI_ALLOC(m, uint32_t, buf_size); + tmp_literal_buf = BROTLI_ALLOC(m, uint8_t, buf_size); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp_command_buf) || + BROTLI_IS_NULL(tmp_literal_buf)) { + return BROTLI_FALSE; + } + command_buf = tmp_command_buf; + literal_buf = tmp_literal_buf; + } + } + + while (BROTLI_TRUE) { + if (InjectFlushOrPushOutput(s, available_out, next_out, total_out)) { + continue; + } + + /* Compress block only when internal output buffer is empty, stream is not + finished, there is no pending flush request, and there is either + additional input or pending operation. */ + if (s->available_out_ == 0 && + s->stream_state_ == BROTLI_STREAM_PROCESSING && + (*available_in != 0 || op != BROTLI_OPERATION_PROCESS)) { + size_t block_size = BROTLI_MIN(size_t, block_size_limit, *available_in); + BROTLI_BOOL is_last = + (*available_in == block_size) && (op == BROTLI_OPERATION_FINISH); + BROTLI_BOOL force_flush = + (*available_in == block_size) && (op == BROTLI_OPERATION_FLUSH); + size_t max_out_size = 2 * block_size + 503; + BROTLI_BOOL inplace = BROTLI_TRUE; + uint8_t* storage = NULL; + size_t storage_ix = s->last_bytes_bits_; + size_t table_size; + int* table; + + if (force_flush && block_size == 0) { + s->stream_state_ = BROTLI_STREAM_FLUSH_REQUESTED; + continue; + } + if (max_out_size <= *available_out) { + storage = *next_out; + } else { + inplace = BROTLI_FALSE; + storage = GetBrotliStorage(s, max_out_size); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + } + storage[0] = (uint8_t)s->last_bytes_; + storage[1] = (uint8_t)(s->last_bytes_ >> 8); + table = GetHashTable(s, s->params.quality, block_size, &table_size); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + + if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY) { + BrotliCompressFragmentFast(s->one_pass_arena_, *next_in, block_size, + is_last, table, table_size, &storage_ix, storage); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + } else { + BrotliCompressFragmentTwoPass(s->two_pass_arena_, *next_in, block_size, + is_last, command_buf, literal_buf, table, table_size, + &storage_ix, storage); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + } + if (block_size != 0) { + *next_in += block_size; + *available_in -= block_size; + s->total_in_ += block_size; + } + if (inplace) { + size_t out_bytes = storage_ix >> 3; + BROTLI_DCHECK(out_bytes <= *available_out); + BROTLI_DCHECK((storage_ix & 7) == 0 || out_bytes < *available_out); + *next_out += out_bytes; + *available_out -= out_bytes; + s->total_out_ += out_bytes; + SetTotalOut(s, total_out); + } else { + size_t out_bytes = storage_ix >> 3; + s->next_out_ = storage; + s->available_out_ = out_bytes; + } + s->last_bytes_ = (uint16_t)(storage[storage_ix >> 3]); + s->last_bytes_bits_ = storage_ix & 7u; + + if (force_flush) s->stream_state_ = BROTLI_STREAM_FLUSH_REQUESTED; + if (is_last) s->stream_state_ = BROTLI_STREAM_FINISHED; + continue; + } + break; + } + BROTLI_FREE(m, tmp_command_buf); + BROTLI_FREE(m, tmp_literal_buf); + CheckFlushComplete(s); + return BROTLI_TRUE; +} + +static BROTLI_BOOL ProcessMetadata( + BrotliEncoderState* s, size_t* available_in, const uint8_t** next_in, + size_t* available_out, uint8_t** next_out, size_t* total_out) { + if (*available_in > (1u << 24)) return BROTLI_FALSE; + /* Switch to metadata block workflow, if required. */ + if (s->stream_state_ == BROTLI_STREAM_PROCESSING) { + s->remaining_metadata_bytes_ = (uint32_t)*available_in; + s->stream_state_ = BROTLI_STREAM_METADATA_HEAD; + } + if (s->stream_state_ != BROTLI_STREAM_METADATA_HEAD && + s->stream_state_ != BROTLI_STREAM_METADATA_BODY) { + return BROTLI_FALSE; + } + + while (BROTLI_TRUE) { + if (InjectFlushOrPushOutput(s, available_out, next_out, total_out)) { + continue; + } + if (s->available_out_ != 0) break; + + if (s->input_pos_ != s->last_flush_pos_) { + BROTLI_BOOL result = EncodeData(s, BROTLI_FALSE, BROTLI_TRUE, + &s->available_out_, &s->next_out_); + if (!result) return BROTLI_FALSE; + continue; + } + + if (s->stream_state_ == BROTLI_STREAM_METADATA_HEAD) { + s->next_out_ = s->tiny_buf_.u8; + s->available_out_ = + WriteMetadataHeader(s, s->remaining_metadata_bytes_, s->next_out_); + s->stream_state_ = BROTLI_STREAM_METADATA_BODY; + continue; + } else { + /* Exit workflow only when there is no more input and no more output. + Otherwise client may continue producing empty metadata blocks. */ + if (s->remaining_metadata_bytes_ == 0) { + s->remaining_metadata_bytes_ = BROTLI_UINT32_MAX; + s->stream_state_ = BROTLI_STREAM_PROCESSING; + break; + } + if (*available_out) { + /* Directly copy input to output. */ + uint32_t copy = (uint32_t)BROTLI_MIN( + size_t, s->remaining_metadata_bytes_, *available_out); + memcpy(*next_out, *next_in, copy); + *next_in += copy; + *available_in -= copy; + s->total_in_ += copy; /* not actually data input, though */ + s->remaining_metadata_bytes_ -= copy; + *next_out += copy; + *available_out -= copy; + } else { + /* This guarantees progress in "TakeOutput" workflow. */ + uint32_t copy = BROTLI_MIN(uint32_t, s->remaining_metadata_bytes_, 16); + s->next_out_ = s->tiny_buf_.u8; + memcpy(s->next_out_, *next_in, copy); + *next_in += copy; + *available_in -= copy; + s->total_in_ += copy; /* not actually data input, though */ + s->remaining_metadata_bytes_ -= copy; + s->available_out_ = copy; + } + continue; + } + } + + return BROTLI_TRUE; +} + +static void UpdateSizeHint(BrotliEncoderState* s, size_t available_in) { + if (s->params.size_hint == 0) { + uint64_t delta = UnprocessedInputSize(s); + uint64_t tail = available_in; + uint32_t limit = 1u << 30; + uint32_t total; + if ((delta >= limit) || (tail >= limit) || ((delta + tail) >= limit)) { + total = limit; + } else { + total = (uint32_t)(delta + tail); + } + s->params.size_hint = total; + } +} + +BROTLI_BOOL BrotliEncoderCompressStream( + BrotliEncoderState* s, BrotliEncoderOperation op, size_t* available_in, + const uint8_t** next_in, size_t* available_out, uint8_t** next_out, + size_t* total_out) { + if (!EnsureInitialized(s)) return BROTLI_FALSE; + + /* Unfinished metadata block; check requirements. */ + if (s->remaining_metadata_bytes_ != BROTLI_UINT32_MAX) { + if (*available_in != s->remaining_metadata_bytes_) return BROTLI_FALSE; + if (op != BROTLI_OPERATION_EMIT_METADATA) return BROTLI_FALSE; + } + + if (op == BROTLI_OPERATION_EMIT_METADATA) { + UpdateSizeHint(s, 0); /* First data metablock might be emitted here. */ + return ProcessMetadata( + s, available_in, next_in, available_out, next_out, total_out); + } + + if (s->stream_state_ == BROTLI_STREAM_METADATA_HEAD || + s->stream_state_ == BROTLI_STREAM_METADATA_BODY) { + return BROTLI_FALSE; + } + + if (s->stream_state_ != BROTLI_STREAM_PROCESSING && *available_in != 0) { + return BROTLI_FALSE; + } + if (s->params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY || + s->params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) { + return BrotliEncoderCompressStreamFast(s, op, available_in, next_in, + available_out, next_out, total_out); + } + while (BROTLI_TRUE) { + size_t remaining_block_size = RemainingInputBlockSize(s); + /* Shorten input to flint size. */ + if (s->flint_ >= 0 && remaining_block_size > (size_t)s->flint_) { + remaining_block_size = (size_t)s->flint_; + } + + if (remaining_block_size != 0 && *available_in != 0) { + size_t copy_input_size = + BROTLI_MIN(size_t, remaining_block_size, *available_in); + CopyInputToRingBuffer(s, copy_input_size, *next_in); + *next_in += copy_input_size; + *available_in -= copy_input_size; + s->total_in_ += copy_input_size; + if (s->flint_ > 0) s->flint_ = (int8_t)(s->flint_ - (int)copy_input_size); + continue; + } + + if (InjectFlushOrPushOutput(s, available_out, next_out, total_out)) { + /* Exit the "emit flint" workflow. */ + if (s->flint_ == BROTLI_FLINT_WAITING_FOR_FLUSHING) { + CheckFlushComplete(s); + if (s->stream_state_ == BROTLI_STREAM_PROCESSING) { + s->flint_ = BROTLI_FLINT_DONE; + } + } + continue; + } + + /* Compress data only when internal output buffer is empty, stream is not + finished and there is no pending flush request. */ + if (s->available_out_ == 0 && + s->stream_state_ == BROTLI_STREAM_PROCESSING) { + if (remaining_block_size == 0 || op != BROTLI_OPERATION_PROCESS) { + BROTLI_BOOL is_last = TO_BROTLI_BOOL( + (*available_in == 0) && op == BROTLI_OPERATION_FINISH); + BROTLI_BOOL force_flush = TO_BROTLI_BOOL( + (*available_in == 0) && op == BROTLI_OPERATION_FLUSH); + BROTLI_BOOL result; + /* Force emitting (uncompressed) piece containing flint. */ + if (!is_last && s->flint_ == 0) { + s->flint_ = BROTLI_FLINT_WAITING_FOR_FLUSHING; + force_flush = BROTLI_TRUE; + } + UpdateSizeHint(s, *available_in); + result = EncodeData(s, is_last, force_flush, + &s->available_out_, &s->next_out_); + if (!result) return BROTLI_FALSE; + if (force_flush) s->stream_state_ = BROTLI_STREAM_FLUSH_REQUESTED; + if (is_last) s->stream_state_ = BROTLI_STREAM_FINISHED; + continue; + } + } + break; + } + CheckFlushComplete(s); + return BROTLI_TRUE; +} + +BROTLI_BOOL BrotliEncoderIsFinished(BrotliEncoderState* s) { + return TO_BROTLI_BOOL(s->stream_state_ == BROTLI_STREAM_FINISHED && + !BrotliEncoderHasMoreOutput(s)); +} + +BROTLI_BOOL BrotliEncoderHasMoreOutput(BrotliEncoderState* s) { + return TO_BROTLI_BOOL(s->available_out_ != 0); +} + +const uint8_t* BrotliEncoderTakeOutput(BrotliEncoderState* s, size_t* size) { + size_t consumed_size = s->available_out_; + uint8_t* result = s->next_out_; + if (*size) { + consumed_size = BROTLI_MIN(size_t, *size, s->available_out_); + } + if (consumed_size) { + s->next_out_ += consumed_size; + s->available_out_ -= consumed_size; + s->total_out_ += consumed_size; + CheckFlushComplete(s); + *size = consumed_size; + } else { + *size = 0; + result = 0; + } + return result; +} + +uint32_t BrotliEncoderVersion(void) { + return BROTLI_VERSION; +} + +BrotliEncoderPreparedDictionary* BrotliEncoderPrepareDictionary( + BrotliSharedDictionaryType type, size_t size, + const uint8_t data[BROTLI_ARRAY_PARAM(size)], int quality, + brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) { + ManagedDictionary* managed_dictionary = NULL; + BROTLI_BOOL type_is_known = BROTLI_FALSE; + type_is_known |= (type == BROTLI_SHARED_DICTIONARY_RAW); +#if defined(BROTLI_EXPERIMENTAL) + type_is_known |= (type == BROTLI_SHARED_DICTIONARY_SERIALIZED); +#endif /* BROTLI_EXPERIMENTAL */ + if (!type_is_known) { + return NULL; + } + managed_dictionary = + BrotliCreateManagedDictionary(alloc_func, free_func, opaque); + if (managed_dictionary == NULL) { + return NULL; + } + if (type == BROTLI_SHARED_DICTIONARY_RAW) { + managed_dictionary->dictionary = (uint32_t*)CreatePreparedDictionary( + &managed_dictionary->memory_manager_, data, size); + } +#if defined(BROTLI_EXPERIMENTAL) + if (type == BROTLI_SHARED_DICTIONARY_SERIALIZED) { + SharedEncoderDictionary* dict = (SharedEncoderDictionary*)BrotliAllocate( + &managed_dictionary->memory_manager_, sizeof(SharedEncoderDictionary)); + managed_dictionary->dictionary = (uint32_t*)dict; + if (dict != NULL) { + BROTLI_BOOL ok = BrotliInitCustomSharedEncoderDictionary( + &managed_dictionary->memory_manager_, data, size, quality, dict); + if (!ok) { + BrotliFree(&managed_dictionary->memory_manager_, dict); + managed_dictionary->dictionary = NULL; + } + } + } +#else /* BROTLI_EXPERIMENTAL */ + (void)quality; +#endif /* BROTLI_EXPERIMENTAL */ + if (managed_dictionary->dictionary == NULL) { + BrotliDestroyManagedDictionary(managed_dictionary); + return NULL; + } + return (BrotliEncoderPreparedDictionary*)managed_dictionary; +} + +void BROTLI_COLD BrotliEncoderDestroyPreparedDictionary( + BrotliEncoderPreparedDictionary* dictionary) { + ManagedDictionary* dict = (ManagedDictionary*)dictionary; + if (!dictionary) return; + /* First field of dictionary structs. */ + /* Only managed dictionaries are eligible for destruction by this method. */ + if (dict->magic != kManagedDictionaryMagic) { + return; + } + if (dict->dictionary == NULL) { + /* This should never ever happen. */ + } else if (*dict->dictionary == kLeanPreparedDictionaryMagic) { + DestroyPreparedDictionary( + &dict->memory_manager_, (PreparedDictionary*)dict->dictionary); + } else if (*dict->dictionary == kSharedDictionaryMagic) { + BrotliCleanupSharedEncoderDictionary(&dict->memory_manager_, + (SharedEncoderDictionary*)dict->dictionary); + BrotliFree(&dict->memory_manager_, dict->dictionary); + } else { + /* There is also kPreparedDictionaryMagic, but such instances should be + * constructed and destroyed by different means. */ + } + dict->dictionary = NULL; + BrotliDestroyManagedDictionary(dict); +} + +BROTLI_BOOL BROTLI_COLD BrotliEncoderAttachPreparedDictionary( + BrotliEncoderState* state, + const BrotliEncoderPreparedDictionary* dictionary) { + /* First field of dictionary structs */ + const BrotliEncoderPreparedDictionary* dict = dictionary; + uint32_t magic = *((const uint32_t*)dict); + SharedEncoderDictionary* current = NULL; + if (magic == kManagedDictionaryMagic) { + /* Unwrap managed dictionary. */ + ManagedDictionary* managed_dictionary = (ManagedDictionary*)dict; + magic = *managed_dictionary->dictionary; + dict = (BrotliEncoderPreparedDictionary*)managed_dictionary->dictionary; + } + current = &state->params.dictionary; + if (magic == kPreparedDictionaryMagic || + magic == kLeanPreparedDictionaryMagic) { + const PreparedDictionary* prepared = (const PreparedDictionary*)dict; + if (!AttachPreparedDictionary(¤t->compound, prepared)) { + return BROTLI_FALSE; + } + } else if (magic == kSharedDictionaryMagic) { + const SharedEncoderDictionary* attached = + (const SharedEncoderDictionary*)dict; + BROTLI_BOOL was_default = !current->contextual.context_based && + current->contextual.num_dictionaries == 1 && + current->contextual.dict[0]->hash_table_words == + kStaticDictionaryHashWords && + current->contextual.dict[0]->hash_table_lengths == + kStaticDictionaryHashLengths; + BROTLI_BOOL new_default = !attached->contextual.context_based && + attached->contextual.num_dictionaries == 1 && + attached->contextual.dict[0]->hash_table_words == + kStaticDictionaryHashWords && + attached->contextual.dict[0]->hash_table_lengths == + kStaticDictionaryHashLengths; + size_t i; + if (state->is_initialized_) return BROTLI_FALSE; + current->max_quality = + BROTLI_MIN(int, current->max_quality, attached->max_quality); + for (i = 0; i < attached->compound.num_chunks; i++) { + if (!AttachPreparedDictionary(¤t->compound, + attached->compound.chunks[i])) { + return BROTLI_FALSE; + } + } + if (!new_default) { + if (!was_default) return BROTLI_FALSE; + /* Copy by value, but then set num_instances_ to 0 because their memory + is managed by attached, not by current */ + current->contextual = attached->contextual; + current->contextual.num_instances_ = 0; + } + } else { + return BROTLI_FALSE; + } + return BROTLI_TRUE; +} + +size_t BROTLI_COLD BrotliEncoderEstimatePeakMemoryUsage(int quality, int lgwin, + size_t input_size) { + BrotliEncoderParams params; + size_t memory_manager_slots = BROTLI_ENCODER_MEMORY_MANAGER_SLOTS; + size_t memory_manager_size = memory_manager_slots * sizeof(void*); + BrotliEncoderInitParams(¶ms); + params.quality = quality; + params.lgwin = lgwin; + params.size_hint = input_size; + params.large_window = lgwin > BROTLI_MAX_WINDOW_BITS; + SanitizeParams(¶ms); + params.lgblock = ComputeLgBlock(¶ms); + ChooseHasher(¶ms, ¶ms.hasher); + if (params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY || + params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY) { + size_t state_size = sizeof(BrotliEncoderState); + size_t block_size = BROTLI_MIN(size_t, input_size, ((size_t)1ul << params.lgwin)); + size_t hash_table_size = + HashTableSize(MaxHashTableSize(params.quality), block_size); + size_t hash_size = + (hash_table_size < (1u << 10)) ? 0 : sizeof(int) * hash_table_size; + size_t cmdbuf_size = params.quality == FAST_TWO_PASS_COMPRESSION_QUALITY ? + 5 * BROTLI_MIN(size_t, block_size, 1ul << 17) : 0; + if (params.quality == FAST_ONE_PASS_COMPRESSION_QUALITY) { + state_size += sizeof(BrotliOnePassArena); + } else { + state_size += sizeof(BrotliTwoPassArena); + } + return hash_size + cmdbuf_size + state_size; + } else { + size_t short_ringbuffer_size = (size_t)1 << params.lgblock; + int ringbuffer_bits = ComputeRbBits(¶ms); + size_t ringbuffer_size = input_size < short_ringbuffer_size ? + input_size : ((size_t)1u << ringbuffer_bits) + short_ringbuffer_size; + size_t hash_size[4] = {0}; + size_t metablock_size = + BROTLI_MIN(size_t, input_size, MaxMetablockSize(¶ms)); + size_t inputblock_size = + BROTLI_MIN(size_t, input_size, (size_t)1 << params.lgblock); + size_t cmdbuf_size = metablock_size * 2 + inputblock_size * 6; + size_t outbuf_size = metablock_size * 2 + 503; + size_t histogram_size = 0; + HasherSize(¶ms, BROTLI_TRUE, input_size, hash_size); + if (params.quality < MIN_QUALITY_FOR_BLOCK_SPLIT) { + cmdbuf_size = BROTLI_MIN(size_t, cmdbuf_size, + MAX_NUM_DELAYED_SYMBOLS * sizeof(Command) + inputblock_size * 12); + } + if (params.quality >= MIN_QUALITY_FOR_HQ_BLOCK_SPLITTING) { + /* Only a very rough estimation, based on enwik8. */ + histogram_size = 200 << 20; + } else if (params.quality >= MIN_QUALITY_FOR_BLOCK_SPLIT) { + size_t literal_histograms = + BROTLI_MIN(size_t, metablock_size / 6144, 256); + size_t command_histograms = + BROTLI_MIN(size_t, metablock_size / 6144, 256); + size_t distance_histograms = + BROTLI_MIN(size_t, metablock_size / 6144, 256); + histogram_size = literal_histograms * sizeof(HistogramLiteral) + + command_histograms * sizeof(HistogramCommand) + + distance_histograms * sizeof(HistogramDistance); + } + return (memory_manager_size + ringbuffer_size + + hash_size[0] + hash_size[1] + hash_size[2] + hash_size[3] + + cmdbuf_size + + outbuf_size + + histogram_size); + } +} +size_t BROTLI_COLD BrotliEncoderGetPreparedDictionarySize( + const BrotliEncoderPreparedDictionary* prepared_dictionary) { + /* First field of dictionary structs */ + const BrotliEncoderPreparedDictionary* prepared = prepared_dictionary; + uint32_t magic = *((const uint32_t*)prepared); + size_t overhead = 0; + if (magic == kManagedDictionaryMagic) { + const ManagedDictionary* managed = (const ManagedDictionary*)prepared; + overhead = sizeof(ManagedDictionary); + magic = *managed->dictionary; + prepared = (const BrotliEncoderPreparedDictionary*)managed->dictionary; + } + + if (magic == kPreparedDictionaryMagic) { + const PreparedDictionary* dictionary = + (const PreparedDictionary*)prepared; + /* Keep in sync with step 3 of CreatePreparedDictionary */ + return sizeof(PreparedDictionary) + dictionary->source_size + + (sizeof(uint32_t) << dictionary->slot_bits) + + (sizeof(uint16_t) << dictionary->bucket_bits) + + (sizeof(uint32_t) * dictionary->num_items) + overhead; + } else if (magic == kLeanPreparedDictionaryMagic) { + const PreparedDictionary* dictionary = + (const PreparedDictionary*)prepared; + /* Keep in sync with step 3 of CreatePreparedDictionary */ + return sizeof(PreparedDictionary) + sizeof(uint8_t*) + + (sizeof(uint32_t) << dictionary->slot_bits) + + (sizeof(uint16_t) << dictionary->bucket_bits) + + (sizeof(uint32_t) * dictionary->num_items) + overhead; + } else if (magic == kSharedDictionaryMagic) { + const SharedEncoderDictionary* dictionary = + (const SharedEncoderDictionary*)prepared; + const CompoundDictionary* compound = &dictionary->compound; + const ContextualEncoderDictionary* contextual = &dictionary->contextual; + size_t result = sizeof(*dictionary); + size_t i; + size_t num_instances; + const BrotliEncoderDictionary* instances; + for (i = 0; i < compound->num_prepared_instances_; i++) { + size_t size = BrotliEncoderGetPreparedDictionarySize( + (const BrotliEncoderPreparedDictionary*) + compound->prepared_instances_[i]); + if (!size) return 0; /* error */ + result += size; + } + if (contextual->context_based) { + num_instances = contextual->num_instances_; + instances = contextual->instances_; + result += sizeof(*instances) * num_instances; + } else { + num_instances = 1; + instances = &contextual->instance_; + } + for (i = 0; i < num_instances; i++) { + const BrotliEncoderDictionary* dict = &instances[i]; + result += dict->trie.pool_capacity * sizeof(BrotliTrieNode); + if (dict->hash_table_data_words_) { + result += sizeof(kStaticDictionaryHashWords); + } + if (dict->hash_table_data_lengths_) { + result += sizeof(kStaticDictionaryHashLengths); + } + if (dict->buckets_data_) { + result += sizeof(*dict->buckets_data_) * dict->buckets_alloc_size_; + } + if (dict->dict_words_data_) { + result += sizeof(*dict->dict_words) * dict->dict_words_alloc_size_; + } + if (dict->words_instance_) { + result += sizeof(*dict->words_instance_); + /* data_size not added here: it is never allocated by the + SharedEncoderDictionary, instead it always points to the file + already loaded in memory. So if the caller wants to include + this memory as well, add the size of the loaded dictionary + file to this. */ + } + } + return result + overhead; + } + return 0; /* error */ +} + +#if defined(BROTLI_TEST) +size_t BrotliMakeUncompressedStreamForTest(const uint8_t*, size_t, uint8_t*); +size_t BrotliMakeUncompressedStreamForTest( + const uint8_t* input, size_t input_size, uint8_t* output) { + return MakeUncompressedStream(input, input_size, output); +} +#endif + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/encoder_dict.c b/packages/runtime/vendor/brotli/c/enc/encoder_dict.c new file mode 100644 index 000000000..f75ee5984 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/encoder_dict.c @@ -0,0 +1,642 @@ +/* Copyright 2017 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#include "encoder_dict.h" + +#include "../common/dictionary.h" +#include "../common/platform.h" +#include +#include "../common/shared_dictionary_internal.h" +#include "../common/transform.h" +#include +#include "compound_dictionary.h" +#include "dictionary_hash.h" +#include "hash_base.h" +#include "hash.h" +#include "memory.h" +#include "quality.h" +#include "static_dict_lut.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define NUM_HASH_BITS 15u +#define NUM_HASH_BUCKETS (1u << NUM_HASH_BITS) + +static void BrotliTrieInit(BrotliTrie* trie) { + trie->pool_capacity = 0; + trie->pool_size = 0; + trie->pool = 0; + + /* Set up the root node */ + trie->root.single = 0; + trie->root.len_ = 0; + trie->root.idx_ = 0; + trie->root.sub = 0; +} + +static void BrotliTrieFree(MemoryManager* m, BrotliTrie* trie) { + BrotliFree(m, trie->pool); +} + +/* Initializes to RFC 7932 static dictionary / transforms. */ +static void InitEncoderDictionary(BrotliEncoderDictionary* dict) { + dict->words = BrotliGetDictionary(); + dict->num_transforms = (uint32_t)BrotliGetTransforms()->num_transforms; + + dict->hash_table_words = kStaticDictionaryHashWords; + dict->hash_table_lengths = kStaticDictionaryHashLengths; + dict->buckets = kStaticDictionaryBuckets; + dict->dict_words = kStaticDictionaryWords; + + dict->cutoffTransformsCount = kCutoffTransformsCount; + dict->cutoffTransforms = kCutoffTransforms; + + dict->parent = 0; + + dict->hash_table_data_words_ = 0; + dict->hash_table_data_lengths_ = 0; + dict->buckets_alloc_size_ = 0; + dict->buckets_data_ = 0; + dict->dict_words_alloc_size_ = 0; + dict->dict_words_data_ = 0; + dict->words_instance_ = 0; + dict->has_words_heavy = BROTLI_FALSE; + BrotliTrieInit(&dict->trie); +} + +static void BrotliDestroyEncoderDictionary(MemoryManager* m, + BrotliEncoderDictionary* dict) { + BrotliFree(m, dict->hash_table_data_words_); + BrotliFree(m, dict->hash_table_data_lengths_); + BrotliFree(m, dict->buckets_data_); + BrotliFree(m, dict->dict_words_data_); + BrotliFree(m, dict->words_instance_); + BrotliTrieFree(m, &dict->trie); +} + +#if defined(BROTLI_EXPERIMENTAL) +/* Word length must be at least 4 bytes */ +static uint32_t Hash(const uint8_t* data, int bits) { + uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32; + /* The higher bits contain more mixture from the multiplication, + so we take our results from there. */ + return h >> (32 - bits); +} + +/* Theoretical max possible word size after transform */ +#define kTransformedBufferSize \ + (256 + 256 + SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH) + +/* To be safe buffer must have at least kTransformedBufferSize */ +static void TransformedDictionaryWord(uint32_t word_idx, int len, int transform, + const BrotliTransforms* transforms, + const BrotliEncoderDictionary* dict, + uint8_t* buffer, size_t* size) { + const uint8_t* dict_word = &dict->words->data[ + dict->words->offsets_by_length[len] + (uint32_t)len * word_idx]; + *size = (size_t)BrotliTransformDictionaryWord(buffer, dict_word, len, + transforms, transform); +} + +static DictWord MakeDictWord(uint8_t len, uint8_t transform, uint16_t idx) { + DictWord result; + result.len = len; + result.transform = transform; + result.idx = idx; + return result; +} + +static uint32_t BrotliTrieAlloc(MemoryManager* m, size_t num, BrotliTrie* trie, + BrotliTrieNode** keep) { + uint32_t result; + uint32_t keep_index = 0; + if (keep && *keep != &trie->root) { + /* Optional node to keep, since address may change after re-allocating */ + keep_index = (uint32_t)(*keep - trie->pool); + } + if (trie->pool_size == 0) { + /* Have a placeholder node in the front. We do not want the result to be 0, + it must be at least 1, 0 represents "null pointer" */ + trie->pool_size = 1; + } + BROTLI_ENSURE_CAPACITY(m, BrotliTrieNode, trie->pool, trie->pool_capacity, + trie->pool_size + num); + if (BROTLI_IS_OOM(m)) return 0; + /* Init the new nodes to empty */ + memset(trie->pool + trie->pool_size, 0, sizeof(*trie->pool) * num); + result = (uint32_t)trie->pool_size; + trie->pool_size += num; + if (keep && *keep != &trie->root) { + *keep = trie->pool + keep_index; + } + return result; +} + +/** + * len and idx: payload for last node + * word, size: the string + * index: position in the string + */ +static BROTLI_BOOL BrotliTrieNodeAdd(MemoryManager* m, uint8_t len, + uint32_t idx, const uint8_t* word, size_t size, int index, + BrotliTrieNode* node, BrotliTrie* trie) { + BrotliTrieNode* child = 0; + uint8_t c; + if ((size_t)index == size) { + if (!node->len_ || idx < node->idx_) { + node->len_ = len; + node->idx_ = idx; + } + return BROTLI_TRUE; + } + c = word[index]; + if (node->single && c != node->c) { + BrotliTrieNode old = trie->pool[node->sub]; + uint32_t new_nodes = BrotliTrieAlloc(m, 32, trie, &node); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + node->single = 0; + node->sub = new_nodes; + trie->pool[node->sub + (node->c >> 4)].sub = new_nodes + 16; + trie->pool[trie->pool[node->sub + (node->c >> 4)].sub + (node->c & 15)] = + old; + } + if (!node->sub) { + uint32_t new_node = BrotliTrieAlloc(m, 1, trie, &node); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + node->single = 1; + node->c = c; + node->sub = new_node; + } + if (node->single) { + child = &trie->pool[node->sub]; + } else { + if (!trie->pool[node->sub + (c >> 4)].sub) { + uint32_t new_nodes = BrotliTrieAlloc(m, 16, trie, &node); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + trie->pool[node->sub + (c >> 4)].sub = new_nodes; + } + child = &trie->pool[trie->pool[node->sub + (c >> 4)].sub + (c & 15)]; + } + return BrotliTrieNodeAdd(m, len, idx, word, size, index + 1, child, trie); +} + +static BROTLI_BOOL BrotliTrieAdd(MemoryManager* m, uint8_t len, uint32_t idx, + const uint8_t* word, size_t size, BrotliTrie* trie) { + return BrotliTrieNodeAdd(m, len, idx, word, size, 0, &trie->root, trie); +} + +const BrotliTrieNode* BrotliTrieSub(const BrotliTrie* trie, + const BrotliTrieNode* node, uint8_t c) { + BrotliTrieNode* temp_node; + if (node->single) { + if (node->c == c) return &trie->pool[node->sub]; + return 0; + } + if (!node->sub) return 0; + temp_node = &trie->pool[node->sub + (c >> 4)]; + if (!temp_node->sub) return 0; + return &trie->pool[temp_node->sub + (c & 15)]; +} + +static const BrotliTrieNode* BrotliTrieFind(const BrotliTrie* trie, + const uint8_t* word, size_t size) { + const BrotliTrieNode* node = &trie->root; + size_t i; + for (i = 0; i < size; i++) { + node = BrotliTrieSub(trie, node, word[i]); + if (!node) return 0; + } + return node; +} + +static BROTLI_BOOL BuildDictionaryLut(MemoryManager* m, + const BrotliTransforms* transforms, + BrotliEncoderDictionary* dict) { + uint32_t i; + DictWord* dict_words; + uint16_t* buckets; + DictWord** words_by_hash; + size_t* words_by_hash_size; + size_t* words_by_hash_capacity; + BrotliTrie dedup; + uint8_t word[kTransformedBufferSize]; + size_t word_size; + size_t total = 0; + uint8_t l; + uint16_t idx; + + BrotliTrieInit(&dedup); + + words_by_hash = (DictWord**)BrotliAllocate(m, + sizeof(*words_by_hash) * NUM_HASH_BUCKETS); + words_by_hash_size = (size_t*)BrotliAllocate(m, + sizeof(*words_by_hash_size) * NUM_HASH_BUCKETS); + words_by_hash_capacity = (size_t*)BrotliAllocate(m, + sizeof(*words_by_hash_capacity) * NUM_HASH_BUCKETS); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + memset(words_by_hash, 0, sizeof(*words_by_hash) * NUM_HASH_BUCKETS); + memset(words_by_hash_size, 0, sizeof(*words_by_hash_size) * NUM_HASH_BUCKETS); + memset(words_by_hash_capacity, 0, + sizeof(*words_by_hash_capacity) * NUM_HASH_BUCKETS); + + if (transforms->num_transforms > 0) { + for (l = SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH; + l <= SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH; ++l) { + uint16_t n = dict->words->size_bits_by_length[l] ? + (uint16_t)(1 << dict->words->size_bits_by_length[l]) : 0u; + for (idx = 0; idx < n; ++idx) { + uint32_t key; + /* First transform (usually identity) */ + TransformedDictionaryWord(idx, l, 0, transforms, dict, word, + &word_size); + /* Cannot hash words smaller than 4 bytes */ + if (word_size < 4) { + /* Break instead of continue, all next words of this length will have + same length after transform */ + break; + } + if (!BrotliTrieAdd(m, 0, idx, word, word_size, &dedup)) { + return BROTLI_FALSE; + } + key = Hash(word, NUM_HASH_BITS); + BROTLI_ENSURE_CAPACITY_APPEND(m, DictWord, words_by_hash[key], + words_by_hash_capacity[key], words_by_hash_size[key], + MakeDictWord(l, 0, idx)); + ++total; + } + } + } + + /* These LUT transforms only supported if no custom transforms. This is + ok, we will use the heavy trie instead. */ + if (transforms == BrotliGetTransforms()) { + for (l = SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH; + l <= SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH; ++l) { + uint16_t n = dict->words->size_bits_by_length[l] ? + (uint16_t)(1 << dict->words->size_bits_by_length[l]) : 0u; + for (idx = 0; idx < n; ++idx) { + int k; + BROTLI_BOOL is_ascii = BROTLI_TRUE; + size_t offset = dict->words->offsets_by_length[l] + (size_t)l * idx; + const uint8_t* data = &dict->words->data[offset]; + for (k = 0; k < l; ++k) { + if (data[k] >= 128) is_ascii = BROTLI_FALSE; + } + if (data[0] < 128) { + int transform = 9; /* {empty, uppercase first, empty} */ + uint32_t ix = idx + (uint32_t)transform * n; + const BrotliTrieNode* it; + TransformedDictionaryWord(idx, l, transform, transforms, + dict, word, &word_size); + it = BrotliTrieFind(&dedup, word, word_size); + if (!it || it->idx_ > ix) { + uint32_t key = Hash(word, NUM_HASH_BITS); + if (!BrotliTrieAdd(m, 0, ix, word, word_size, &dedup)) { + return BROTLI_FALSE; + } + BROTLI_ENSURE_CAPACITY_APPEND(m, DictWord, words_by_hash[key], + words_by_hash_capacity[key], words_by_hash_size[key], + MakeDictWord(l, BROTLI_TRANSFORM_UPPERCASE_FIRST, idx)); + ++total; + } + } + if (is_ascii) { + int transform = 44; /* {empty, uppercase all, empty} */ + uint32_t ix = idx + (uint32_t)transform * n; + const BrotliTrieNode* it; + TransformedDictionaryWord(idx, l, transform, transforms, + dict, word, &word_size); + it = BrotliTrieFind(&dedup, word, word_size); + if (!it || it->idx_ > ix) { + uint32_t key = Hash(word, NUM_HASH_BITS); + if (!BrotliTrieAdd(m, 0, ix, word, word_size, &dedup)) { + return BROTLI_FALSE; + } + BROTLI_ENSURE_CAPACITY_APPEND(m, DictWord, words_by_hash[key], + words_by_hash_capacity[key], words_by_hash_size[key], + MakeDictWord(l, BROTLI_TRANSFORM_UPPERCASE_ALL, idx)); + ++total; + } + } + } + } + } + + dict_words = (DictWord*)BrotliAllocate(m, + sizeof(*dict->dict_words) * (total + 1)); + buckets = (uint16_t*)BrotliAllocate(m, + sizeof(*dict->buckets) * NUM_HASH_BUCKETS); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + dict->dict_words_alloc_size_ = total + 1; + dict->dict_words = dict->dict_words_data_ = dict_words; + dict->buckets_alloc_size_ = NUM_HASH_BUCKETS; + dict->buckets = dict->buckets_data_ = buckets; + + /* Unused; makes offsets start from 1. */ + dict_words[0] = MakeDictWord(0, 0, 0); + total = 1; + for (i = 0; i < NUM_HASH_BUCKETS; ++i) { + size_t num_words = words_by_hash_size[i]; + if (num_words > 0) { + buckets[i] = (uint16_t)(total); + memcpy(&dict_words[total], &words_by_hash[i][0], + sizeof(dict_words[0]) * num_words); + total += num_words; + dict_words[total - 1].len |= 0x80; + } else { + buckets[i] = 0; + } + } + + for (i = 0; i < NUM_HASH_BUCKETS; ++i) { + BrotliFree(m, words_by_hash[i]); + } + BrotliFree(m, words_by_hash); + BrotliFree(m, words_by_hash_size); + BrotliFree(m, words_by_hash_capacity); + BrotliTrieFree(m, &dedup); + + return BROTLI_TRUE; +} + +static void BuildDictionaryHashTable(uint16_t* hash_table_words, + uint8_t* hash_table_lengths, const BrotliDictionary* dict) { + int j, len; + /* The order of the loops is such that in case of collision, words with + shorter length are preferred, and in case of same length, words with + smaller index. There is only a single word per bucket. */ + /* TODO(lode): consider adding optional user-supplied frequency_map to use + for preferred words instead, this can make the encoder better for + quality 9 and below without affecting the decoder */ + memset(hash_table_words, 0, sizeof(kStaticDictionaryHashWords)); + memset(hash_table_lengths, 0, sizeof(kStaticDictionaryHashLengths)); + for (len = SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH; + len >= SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH; --len) { + const size_t num_words = dict->size_bits_by_length[len] ? + (1u << dict->size_bits_by_length[len]) : 0; + for (j = (int)num_words - 1; j >= 0; --j) { + size_t offset = dict->offsets_by_length[len] + + (size_t)len * (size_t)j; + const uint8_t* word = &dict->data[offset]; + const uint32_t key = Hash(word, 14); + int idx = (int)(key << 1) + (len < 8 ? 1 : 0); + BROTLI_DCHECK(idx < (int)NUM_HASH_BUCKETS); + hash_table_words[idx] = (uint16_t)j; + hash_table_lengths[idx] = (uint8_t)len; + } + } +} + +static BROTLI_BOOL GenerateWordsHeavy(MemoryManager* m, + const BrotliTransforms* transforms, + BrotliEncoderDictionary* dict) { + int i, j, l; + for (j = (int)transforms->num_transforms - 1; j >= 0 ; --j) { + for (l = 0; l < 32; l++) { + int num = (int)((1u << dict->words->size_bits_by_length[l]) & ~1u); + for (i = 0; i < num; i++) { + uint8_t transformed[kTransformedBufferSize]; + size_t size; + TransformedDictionaryWord( + (uint32_t)i, l, j, transforms, dict, transformed, &size); + if (size < 4) continue; + if (!BrotliTrieAdd(m, (uint8_t)l, (uint32_t)(i + num * j), + transformed, size, &dict->trie)) { + return BROTLI_FALSE; + } + } + } + } + return BROTLI_TRUE; +} + +/* Computes cutoffTransformsCount (in count) and cutoffTransforms (in data) for + the custom transforms, where possible within the limits of the + cutoffTransforms encoding. The fast encoder uses this to do fast lookup for + transforms that remove the N last characters (OmitLast). */ +static void ComputeCutoffTransforms( + const BrotliTransforms* transforms, + uint32_t* count, uint64_t* data) { + int i; + /* The encoding in a 64-bit integer of transform N in the data is: (N << 2) + + ((cutoffTransforms >> (N * 6)) & 0x3F), so for example the identity + transform code must be 0-63, for N=1 the transform code must be 4-67, ..., + for N=9 it must be 36-99. + TODO(lode): consider a simple flexible uint8_t[10] instead of the uint64_t + for the cutoff transforms, so that shared dictionaries can have the + OmitLast transforms anywhere without loss. */ + *count = 0; + *data = 0; + for (i = 0; i < BROTLI_TRANSFORMS_MAX_CUT_OFF + 1; i++) { + int idx = transforms->cutOffTransforms[i]; + if (idx == -1) break; /* Not found */ + if (idx < (i << 2)) break; /* Too small for the encoding */ + if (idx >= (i << 2) + 64) break; /* Too large for the encoding */ + (*count)++; + *data |= (uint64_t)(((uint64_t)idx - + ((uint64_t)i << 2u)) << ((uint64_t)i * 6u)); + } +} + +static BROTLI_BOOL ComputeDictionary(MemoryManager* m, int quality, + const BrotliTransforms* transforms, + BrotliEncoderDictionary* current) { + int default_words = current->words == BrotliGetDictionary(); + int default_transforms = transforms == BrotliGetTransforms(); + + if (default_words && default_transforms) { + /* hashes are already set to Brotli defaults */ + return BROTLI_TRUE; + } + + current->hash_table_data_words_ = (uint16_t*)BrotliAllocate( + m, sizeof(kStaticDictionaryHashWords)); + current->hash_table_data_lengths_ = (uint8_t*)BrotliAllocate( + m, sizeof(kStaticDictionaryHashLengths)); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + current->hash_table_words = current->hash_table_data_words_; + current->hash_table_lengths = current->hash_table_data_lengths_; + + BuildDictionaryHashTable(current->hash_table_data_words_, + current->hash_table_data_lengths_, current->words); + + ComputeCutoffTransforms(transforms, + ¤t->cutoffTransformsCount, ¤t->cutoffTransforms); + + /* Only compute the data for slow encoder if the requested quality is high + enough to need it */ + if (quality >= ZOPFLIFICATION_QUALITY) { + if (!BuildDictionaryLut(m, transforms, current)) return BROTLI_FALSE; + + /* For the built-in Brotli transforms, there is a hard-coded function to + handle all transforms, but for custom transforms, we use the following + large hammer instead */ + current->has_words_heavy = !default_transforms; + if (current->has_words_heavy) { + if (!GenerateWordsHeavy(m, transforms, current)) return BROTLI_FALSE; + } + } + + return BROTLI_TRUE; +} +#endif /* BROTLI_EXPERIMENTAL */ + +void BrotliInitSharedEncoderDictionary(SharedEncoderDictionary* dict) { + dict->magic = kSharedDictionaryMagic; + + dict->compound.num_chunks = 0; + dict->compound.total_size = 0; + dict->compound.chunk_offsets[0] = 0; + dict->compound.num_prepared_instances_ = 0; + + dict->contextual.context_based = 0; + dict->contextual.num_dictionaries = 1; + dict->contextual.instances_ = 0; + dict->contextual.num_instances_ = 1; /* The instance_ field */ + dict->contextual.dict[0] = &dict->contextual.instance_; + InitEncoderDictionary(&dict->contextual.instance_); + dict->contextual.instance_.parent = &dict->contextual; + + dict->max_quality = BROTLI_MAX_QUALITY; +} + +#if defined(BROTLI_EXPERIMENTAL) +/* TODO(eustas): make sure that tooling will warn user if not all the cutoff + transforms are available (for low-quality encoder). */ +static BROTLI_BOOL InitCustomSharedEncoderDictionary( + MemoryManager* m, const BrotliSharedDictionary* decoded_dict, + int quality, SharedEncoderDictionary* dict) { + ContextualEncoderDictionary* contextual; + CompoundDictionary* compound; + BrotliEncoderDictionary* instances; + int i; + BrotliInitSharedEncoderDictionary(dict); + + contextual = &dict->contextual; + compound = &dict->compound; + + for (i = 0; i < (int)decoded_dict->num_prefix; i++) { + PreparedDictionary* prepared = CreatePreparedDictionary(m, + decoded_dict->prefix[i], decoded_dict->prefix_size[i]); + AttachPreparedDictionary(compound, prepared); + /* remember for cleanup */ + compound->prepared_instances_[ + compound->num_prepared_instances_++] = prepared; + } + + dict->max_quality = quality; + contextual->context_based = decoded_dict->context_based; + if (decoded_dict->context_based) { + memcpy(contextual->context_map, decoded_dict->context_map, + SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS); + } + + contextual->num_dictionaries = decoded_dict->num_dictionaries; + contextual->num_instances_ = decoded_dict->num_dictionaries; + if (contextual->num_instances_ == 1) { + instances = &contextual->instance_; + } else { + contextual->instances_ = (BrotliEncoderDictionary*) + BrotliAllocate(m, sizeof(*contextual->instances_) * + contextual->num_instances_); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + instances = contextual->instances_; + } + for (i = 0; i < (int)contextual->num_instances_; i++) { + BrotliEncoderDictionary* current = &instances[i]; + InitEncoderDictionary(current); + current->parent = &dict->contextual; + if (decoded_dict->words[i] == BrotliGetDictionary()) { + current->words = BrotliGetDictionary(); + } else { + current->words_instance_ = (BrotliDictionary*)BrotliAllocate( + m, sizeof(BrotliDictionary)); + if (BROTLI_IS_OOM(m)) return BROTLI_FALSE; + *current->words_instance_ = *decoded_dict->words[i]; + current->words = current->words_instance_; + } + current->num_transforms = + (uint32_t)decoded_dict->transforms[i]->num_transforms; + if (!ComputeDictionary( + m, quality, decoded_dict->transforms[i], current)) { + return BROTLI_FALSE; + } + + contextual->dict[i] = current; + } + + return BROTLI_TRUE; /* success */ +} + +BROTLI_BOOL BrotliInitCustomSharedEncoderDictionary( + MemoryManager* m, const uint8_t* encoded_dict, size_t size, + int quality, SharedEncoderDictionary* dict) { + BROTLI_BOOL success = BROTLI_FALSE; + BrotliSharedDictionary* decoded_dict = BrotliSharedDictionaryCreateInstance( + m->alloc_func, m->free_func, m->opaque); + if (!decoded_dict) { /* OOM */ + return BROTLI_FALSE; + } + success = BrotliSharedDictionaryAttach( + decoded_dict, BROTLI_SHARED_DICTIONARY_SERIALIZED, size, encoded_dict); + if (success) { + success = InitCustomSharedEncoderDictionary(m, + decoded_dict, quality, dict); + } + BrotliSharedDictionaryDestroyInstance(decoded_dict); + return success; +} +#endif /* BROTLI_EXPERIMENTAL */ + +void BrotliCleanupSharedEncoderDictionary(MemoryManager* m, + SharedEncoderDictionary* dict) { + size_t i; + for (i = 0; i < dict->compound.num_prepared_instances_; i++) { + DestroyPreparedDictionary(m, + (PreparedDictionary*)dict->compound.prepared_instances_[i]); + } + if (dict->contextual.num_instances_ == 1) { + BrotliDestroyEncoderDictionary(m, &dict->contextual.instance_); + } else if (dict->contextual.num_instances_ > 1) { + for (i = 0; i < dict->contextual.num_instances_; i++) { + BrotliDestroyEncoderDictionary(m, &dict->contextual.instances_[i]); + } + BrotliFree(m, dict->contextual.instances_); + } +} + +ManagedDictionary* BrotliCreateManagedDictionary( + brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) { + ManagedDictionary* result = (ManagedDictionary*)BrotliBootstrapAlloc( + sizeof(ManagedDictionary), alloc_func, free_func, opaque); + if (result == NULL) return NULL; + + result->magic = kManagedDictionaryMagic; + BrotliInitMemoryManager( + &result->memory_manager_, alloc_func, free_func, opaque); + result->dictionary = NULL; + + return result; +} + +void BrotliDestroyManagedDictionary(ManagedDictionary* dictionary) { + if (!dictionary) return; + BrotliBootstrapFree(dictionary, &dictionary->memory_manager_); +} + +/* Escalate internal functions visibility; for testing purposes only. */ +#if defined(BROTLI_TEST) +void BrotliInitEncoderDictionaryForTest(BrotliEncoderDictionary*); +void BrotliInitEncoderDictionaryForTest(BrotliEncoderDictionary* d) { + InitEncoderDictionary(d); +} +#endif + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/encoder_dict.h b/packages/runtime/vendor/brotli/c/enc/encoder_dict.h new file mode 100644 index 000000000..76f037977 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/encoder_dict.h @@ -0,0 +1,155 @@ +/* Copyright 2017 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#ifndef BROTLI_ENC_ENCODER_DICT_H_ +#define BROTLI_ENC_ENCODER_DICT_H_ + +#include "../common/dictionary.h" +#include +#include "../common/platform.h" +#include "compound_dictionary.h" +#include "memory.h" +#include "static_dict_lut.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* +Dictionary hierarchy for Encoder: +-SharedEncoderDictionary +--CompoundDictionary +---PreparedDictionary [up to 15x] + = prefix dictionary with precomputed hashes +--ContextualEncoderDictionary +---BrotliEncoderDictionary [up to 64x] + = for each context, precomputed static dictionary with words + transforms + +Dictionary hierarchy from common: similar, but without precomputed hashes +-BrotliSharedDictionary +--BrotliDictionary [up to 64x] +--BrotliTransforms [up to 64x] +--const uint8_t* prefix [up to 15x]: compound dictionaries +*/ + +typedef struct BrotliTrieNode { + uint8_t single; /* if 1, sub is a single node for c instead of 256 */ + uint8_t c; + uint8_t len_; /* untransformed length */ + uint32_t idx_; /* word index + num words * transform index */ + uint32_t sub; /* index of sub node(s) in the pool */ +} BrotliTrieNode; + +typedef struct BrotliTrie { + BrotliTrieNode* pool; + size_t pool_capacity; + size_t pool_size; + BrotliTrieNode root; +} BrotliTrie; + +#if defined(BROTLI_EXPERIMENTAL) +BROTLI_INTERNAL const BrotliTrieNode* BrotliTrieSub(const BrotliTrie* trie, + const BrotliTrieNode* node, uint8_t c); +#endif /* BROTLI_EXPERIMENTAL */ + +/* Dictionary data (words and transforms) for 1 possible context */ +typedef struct BrotliEncoderDictionary { + const BrotliDictionary* words; + uint32_t num_transforms; + + /* cut off for fast encoder */ + uint32_t cutoffTransformsCount; + uint64_t cutoffTransforms; + + /* from dictionary_hash.h, for fast encoder */ + const uint16_t* hash_table_words; + const uint8_t* hash_table_lengths; + + /* from static_dict_lut.h, for slow encoder */ + const uint16_t* buckets; + const DictWord* dict_words; + /* Heavy version, for use by slow encoder when there are custom transforms. + Contains every possible transformed dictionary word in a trie. It encodes + about as fast as the non-heavy encoder but consumes a lot of memory and + takes time to build. */ + BrotliTrie trie; + BROTLI_BOOL has_words_heavy; + + /* Reference to other dictionaries. */ + const struct ContextualEncoderDictionary* parent; + + /* Allocated memory, used only when not using the Brotli defaults */ + uint16_t* hash_table_data_words_; + uint8_t* hash_table_data_lengths_; + size_t buckets_alloc_size_; + uint16_t* buckets_data_; + size_t dict_words_alloc_size_; + DictWord* dict_words_data_; + BrotliDictionary* words_instance_; +} BrotliEncoderDictionary; + +/* Dictionary data for all 64 contexts */ +typedef struct ContextualEncoderDictionary { + BROTLI_BOOL context_based; + uint8_t num_dictionaries; + uint8_t context_map[SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS]; + const BrotliEncoderDictionary* dict[SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS]; + + /* If num_instances_ is 1, instance_ is used, else dynamic allocation with + instances_ is used. */ + size_t num_instances_; + BrotliEncoderDictionary instance_; + BrotliEncoderDictionary* instances_; +} ContextualEncoderDictionary; + +typedef struct SharedEncoderDictionary { + /* Magic value to distinguish this struct from PreparedDictionary for + certain external usages. */ + uint32_t magic; + + /* LZ77 prefix, compound dictionary */ + CompoundDictionary compound; + + /* Custom static dictionary (optionally context-based) */ + ContextualEncoderDictionary contextual; + + /* The maximum quality the dictionary was computed for */ + int max_quality; +} SharedEncoderDictionary; + +typedef struct ManagedDictionary { + uint32_t magic; + MemoryManager memory_manager_; + uint32_t* dictionary; +} ManagedDictionary; + +/* Initializes to the brotli built-in dictionary */ +BROTLI_INTERNAL void BrotliInitSharedEncoderDictionary( + SharedEncoderDictionary* dict); + +#if defined(BROTLI_EXPERIMENTAL) +/* Initializes to shared dictionary that will be parsed from + encoded_dict. Requires that you keep the encoded_dict buffer + around, parts of data will point to it. */ +BROTLI_INTERNAL BROTLI_BOOL BrotliInitCustomSharedEncoderDictionary( + MemoryManager* m, const uint8_t* encoded_dict, size_t size, + int quality, SharedEncoderDictionary* dict); +#endif /* BROTLI_EXPERIMENTAL */ + +BROTLI_INTERNAL void BrotliCleanupSharedEncoderDictionary( + MemoryManager* m, SharedEncoderDictionary* dict); + +BROTLI_INTERNAL ManagedDictionary* BrotliCreateManagedDictionary( + brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque); + +BROTLI_INTERNAL void BrotliDestroyManagedDictionary( + ManagedDictionary* dictionary); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_ENCODER_DICT_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/entropy_encode.c b/packages/runtime/vendor/brotli/c/enc/entropy_encode.c new file mode 100644 index 000000000..1b4eab97f --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/entropy_encode.c @@ -0,0 +1,501 @@ +/* Copyright 2010 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Entropy encoding (Huffman) utilities. */ + +#include "entropy_encode.h" + +#include "../common/constants.h" +#include "../common/platform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +const BROTLI_MODEL("small") size_t kBrotliShellGaps[] = {132, 57, 23, 10, 4, 1}; + +BROTLI_BOOL BrotliSetDepth( + int p0, HuffmanTree* pool, uint8_t* depth, int max_depth) { + int stack[16]; + int level = 0; + int p = p0; + BROTLI_DCHECK(max_depth <= 15); + stack[0] = -1; + while (BROTLI_TRUE) { + if (pool[p].index_left_ >= 0) { + level++; + if (level > max_depth) return BROTLI_FALSE; + stack[level] = pool[p].index_right_or_value_; + p = pool[p].index_left_; + continue; + } else { + depth[pool[p].index_right_or_value_] = (uint8_t)level; + } + while (level >= 0 && stack[level] == -1) level--; + if (level < 0) return BROTLI_TRUE; + p = stack[level]; + stack[level] = -1; + } +} + +/* Sort the root nodes, least popular first. */ +static BROTLI_INLINE BROTLI_BOOL SortHuffmanTree( + const HuffmanTree* v0, const HuffmanTree* v1) { + if (v0->total_count_ != v1->total_count_) { + return TO_BROTLI_BOOL(v0->total_count_ < v1->total_count_); + } + return TO_BROTLI_BOOL(v0->index_right_or_value_ > v1->index_right_or_value_); +} + +/* This function will create a Huffman tree. + + The catch here is that the tree cannot be arbitrarily deep. + Brotli specifies a maximum depth of 15 bits for "code trees" + and 7 bits for "code length code trees." + + count_limit is the value that is to be faked as the minimum value + and this minimum value is raised until the tree matches the + maximum length requirement. + + This algorithm is not of excellent performance for very long data blocks, + especially when population counts are longer than 2**tree_limit, but + we are not planning to use this with extremely long blocks. + + See http://en.wikipedia.org/wiki/Huffman_coding */ +void BrotliCreateHuffmanTree(const uint32_t* data, + const size_t length, + const int tree_limit, + HuffmanTree* tree, + uint8_t* depth) { + uint32_t count_limit; + HuffmanTree sentinel; + InitHuffmanTree(&sentinel, BROTLI_UINT32_MAX, -1, -1); + /* For block sizes below 64 kB, we never need to do a second iteration + of this loop. Probably all of our block sizes will be smaller than + that, so this loop is mostly of academic interest. If we actually + would need this, we would be better off with the Katajainen algorithm. */ + for (count_limit = 1; ; count_limit *= 2) { + size_t n = 0; + size_t i; + size_t j; + size_t k; + for (i = length; i != 0;) { + --i; + if (data[i]) { + const uint32_t count = BROTLI_MAX(uint32_t, data[i], count_limit); + InitHuffmanTree(&tree[n++], count, -1, (int16_t)i); + } + } + + if (n == 1) { + depth[tree[0].index_right_or_value_] = 1; /* Only one element. */ + break; + } + + SortHuffmanTreeItems(tree, n, SortHuffmanTree); + + /* The nodes are: + [0, n): the sorted leaf nodes that we start with. + [n]: we add a sentinel here. + [n + 1, 2n): new parent nodes are added here, starting from + (n+1). These are naturally in ascending order. + [2n]: we add a sentinel at the end as well. + There will be (2n+1) elements at the end. */ + tree[n] = sentinel; + tree[n + 1] = sentinel; + + i = 0; /* Points to the next leaf node. */ + j = n + 1; /* Points to the next non-leaf node. */ + for (k = n - 1; k != 0; --k) { + size_t left, right; + if (tree[i].total_count_ <= tree[j].total_count_) { + left = i; + ++i; + } else { + left = j; + ++j; + } + if (tree[i].total_count_ <= tree[j].total_count_) { + right = i; + ++i; + } else { + right = j; + ++j; + } + + { + /* The sentinel node becomes the parent node. */ + size_t j_end = 2 * n - k; + tree[j_end].total_count_ = + tree[left].total_count_ + tree[right].total_count_; + tree[j_end].index_left_ = (int16_t)left; + tree[j_end].index_right_or_value_ = (int16_t)right; + + /* Add back the last sentinel node. */ + tree[j_end + 1] = sentinel; + } + } + if (BrotliSetDepth((int)(2 * n - 1), &tree[0], depth, tree_limit)) { + /* We need to pack the Huffman tree in tree_limit bits. If this was not + successful, add fake entities to the lowest values and retry. */ + break; + } + } +} + +static void Reverse(uint8_t* v, size_t start, size_t end) { + --end; + while (start < end) { + uint8_t tmp = v[start]; + v[start] = v[end]; + v[end] = tmp; + ++start; + --end; + } +} + +static void BrotliWriteHuffmanTreeRepetitions( + const uint8_t previous_value, + const uint8_t value, + size_t repetitions, + size_t* tree_size, + uint8_t* tree, + uint8_t* extra_bits_data) { + BROTLI_DCHECK(repetitions > 0); + if (previous_value != value) { + tree[*tree_size] = value; + extra_bits_data[*tree_size] = 0; + ++(*tree_size); + --repetitions; + } + if (repetitions == 7) { + tree[*tree_size] = value; + extra_bits_data[*tree_size] = 0; + ++(*tree_size); + --repetitions; + } + if (repetitions < 3) { + size_t i; + for (i = 0; i < repetitions; ++i) { + tree[*tree_size] = value; + extra_bits_data[*tree_size] = 0; + ++(*tree_size); + } + } else { + size_t start = *tree_size; + repetitions -= 3; + while (BROTLI_TRUE) { + tree[*tree_size] = BROTLI_REPEAT_PREVIOUS_CODE_LENGTH; + extra_bits_data[*tree_size] = repetitions & 0x3; + ++(*tree_size); + repetitions >>= 2; + if (repetitions == 0) { + break; + } + --repetitions; + } + Reverse(tree, start, *tree_size); + Reverse(extra_bits_data, start, *tree_size); + } +} + +static void BrotliWriteHuffmanTreeRepetitionsZeros( + size_t repetitions, + size_t* tree_size, + uint8_t* tree, + uint8_t* extra_bits_data) { + if (repetitions == 11) { + tree[*tree_size] = 0; + extra_bits_data[*tree_size] = 0; + ++(*tree_size); + --repetitions; + } + if (repetitions < 3) { + size_t i; + for (i = 0; i < repetitions; ++i) { + tree[*tree_size] = 0; + extra_bits_data[*tree_size] = 0; + ++(*tree_size); + } + } else { + size_t start = *tree_size; + repetitions -= 3; + while (BROTLI_TRUE) { + tree[*tree_size] = BROTLI_REPEAT_ZERO_CODE_LENGTH; + extra_bits_data[*tree_size] = repetitions & 0x7; + ++(*tree_size); + repetitions >>= 3; + if (repetitions == 0) { + break; + } + --repetitions; + } + Reverse(tree, start, *tree_size); + Reverse(extra_bits_data, start, *tree_size); + } +} + +void BrotliOptimizeHuffmanCountsForRle(size_t length, uint32_t* counts, + uint8_t* good_for_rle) { + size_t nonzero_count = 0; + size_t stride; + size_t limit; + size_t sum; + const size_t streak_limit = 1240; + /* Let's make the Huffman code more compatible with RLE encoding. */ + size_t i; + for (i = 0; i < length; i++) { + if (counts[i]) { + ++nonzero_count; + } + } + if (nonzero_count < 16) { + return; + } + while (length != 0 && counts[length - 1] == 0) { + --length; + } + if (length == 0) { + return; /* All zeros. */ + } + /* Now counts[0..length - 1] does not have trailing zeros. */ + { + size_t nonzeros = 0; + uint32_t smallest_nonzero = 1 << 30; + for (i = 0; i < length; ++i) { + if (counts[i] != 0) { + ++nonzeros; + if (smallest_nonzero > counts[i]) { + smallest_nonzero = counts[i]; + } + } + } + if (nonzeros < 5) { + /* Small histogram will model it well. */ + return; + } + if (smallest_nonzero < 4) { + size_t zeros = length - nonzeros; + if (zeros < 6) { + for (i = 1; i < length - 1; ++i) { + if (counts[i - 1] != 0 && counts[i] == 0 && counts[i + 1] != 0) { + counts[i] = 1; + } + } + } + } + if (nonzeros < 28) { + return; + } + } + /* 2) Let's mark all population counts that already can be encoded + with an RLE code. */ + memset(good_for_rle, 0, length); + { + /* Let's not spoil any of the existing good RLE codes. + Mark any seq of 0's that is longer as 5 as a good_for_rle. + Mark any seq of non-0's that is longer as 7 as a good_for_rle. */ + uint32_t symbol = counts[0]; + size_t step = 0; + for (i = 0; i <= length; ++i) { + if (i == length || counts[i] != symbol) { + if ((symbol == 0 && step >= 5) || + (symbol != 0 && step >= 7)) { + size_t k; + for (k = 0; k < step; ++k) { + good_for_rle[i - k - 1] = 1; + } + } + step = 1; + if (i != length) { + symbol = counts[i]; + } + } else { + ++step; + } + } + } + /* 3) Let's replace those population counts that lead to more RLE codes. + Math here is in 24.8 fixed point representation. */ + stride = 0; + limit = 256 * (counts[0] + counts[1] + counts[2]) / 3 + 420; + sum = 0; + for (i = 0; i <= length; ++i) { + if (i == length || good_for_rle[i] || + (i != 0 && good_for_rle[i - 1]) || + (256 * counts[i] - limit + streak_limit) >= 2 * streak_limit) { + if (stride >= 4 || (stride >= 3 && sum == 0)) { + size_t k; + /* The stride must end, collapse what we have, if we have enough (4). */ + size_t count = (sum + stride / 2) / stride; + if (count == 0) { + count = 1; + } + if (sum == 0) { + /* Don't make an all zeros stride to be upgraded to ones. */ + count = 0; + } + for (k = 0; k < stride; ++k) { + /* We don't want to change value at counts[i], + that is already belonging to the next stride. Thus - 1. */ + counts[i - k - 1] = (uint32_t)count; + } + } + stride = 0; + sum = 0; + if (i < length - 2) { + /* All interesting strides have a count of at least 4, */ + /* at least when non-zeros. */ + limit = 256 * (counts[i] + counts[i + 1] + counts[i + 2]) / 3 + 420; + } else if (i < length) { + limit = 256 * counts[i]; + } else { + limit = 0; + } + } + ++stride; + if (i != length) { + sum += counts[i]; + if (stride >= 4) { + limit = (256 * sum + stride / 2) / stride; + } + if (stride == 4) { + limit += 120; + } + } + } +} + +static void DecideOverRleUse(const uint8_t* depth, const size_t length, + BROTLI_BOOL* use_rle_for_non_zero, + BROTLI_BOOL* use_rle_for_zero) { + size_t total_reps_zero = 0; + size_t total_reps_non_zero = 0; + size_t count_reps_zero = 1; + size_t count_reps_non_zero = 1; + size_t i; + for (i = 0; i < length;) { + const uint8_t value = depth[i]; + size_t reps = 1; + size_t k; + for (k = i + 1; k < length && depth[k] == value; ++k) { + ++reps; + } + if (reps >= 3 && value == 0) { + total_reps_zero += reps; + ++count_reps_zero; + } + if (reps >= 4 && value != 0) { + total_reps_non_zero += reps; + ++count_reps_non_zero; + } + i += reps; + } + *use_rle_for_non_zero = + TO_BROTLI_BOOL(total_reps_non_zero > count_reps_non_zero * 2); + *use_rle_for_zero = TO_BROTLI_BOOL(total_reps_zero > count_reps_zero * 2); +} + +void BrotliWriteHuffmanTree(const uint8_t* depth, + size_t length, + size_t* tree_size, + uint8_t* tree, + uint8_t* extra_bits_data) { + uint8_t previous_value = BROTLI_INITIAL_REPEATED_CODE_LENGTH; + size_t i; + BROTLI_BOOL use_rle_for_non_zero = BROTLI_FALSE; + BROTLI_BOOL use_rle_for_zero = BROTLI_FALSE; + + /* Throw away trailing zeros. */ + size_t new_length = length; + for (i = 0; i < length; ++i) { + if (depth[length - i - 1] == 0) { + --new_length; + } else { + break; + } + } + + /* First gather statistics on if it is a good idea to do RLE. */ + if (length > 50) { + /* Find RLE coding for longer codes. + Shorter codes seem not to benefit from RLE. */ + DecideOverRleUse(depth, new_length, + &use_rle_for_non_zero, &use_rle_for_zero); + } + + /* Actual RLE coding. */ + for (i = 0; i < new_length;) { + const uint8_t value = depth[i]; + size_t reps = 1; + if ((value != 0 && use_rle_for_non_zero) || + (value == 0 && use_rle_for_zero)) { + size_t k; + for (k = i + 1; k < new_length && depth[k] == value; ++k) { + ++reps; + } + } + if (value == 0) { + BrotliWriteHuffmanTreeRepetitionsZeros( + reps, tree_size, tree, extra_bits_data); + } else { + BrotliWriteHuffmanTreeRepetitions(previous_value, + value, reps, tree_size, + tree, extra_bits_data); + previous_value = value; + } + i += reps; + } +} + +static uint16_t BrotliReverseBits(size_t num_bits, uint16_t bits) { + static const size_t BROTLI_MODEL("small") kLut[16] = + { /* Pre-reversed 4-bit values. */ + 0x00, 0x08, 0x04, 0x0C, 0x02, 0x0A, 0x06, 0x0E, + 0x01, 0x09, 0x05, 0x0D, 0x03, 0x0B, 0x07, 0x0F + }; + size_t retval = kLut[bits & 0x0F]; + size_t i; + for (i = 4; i < num_bits; i += 4) { + retval <<= 4; + bits = (uint16_t)(bits >> 4); + retval |= kLut[bits & 0x0F]; + } + retval >>= ((0 - num_bits) & 0x03); + return (uint16_t)retval; +} + +/* 0..15 are values for bits */ +#define MAX_HUFFMAN_BITS 16 + +void BrotliConvertBitDepthsToSymbols(const uint8_t* depth, + size_t len, + uint16_t* bits) { + /* In Brotli, all bit depths are [1..15] + 0 bit depth means that the symbol does not exist. */ + uint16_t bl_count[MAX_HUFFMAN_BITS] = { 0 }; + uint16_t next_code[MAX_HUFFMAN_BITS]; + size_t i; + int code = 0; + for (i = 0; i < len; ++i) { + ++bl_count[depth[i]]; + } + bl_count[0] = 0; + next_code[0] = 0; + for (i = 1; i < MAX_HUFFMAN_BITS; ++i) { + code = (code + bl_count[i - 1]) << 1; + next_code[i] = (uint16_t)code; + } + for (i = 0; i < len; ++i) { + if (depth[i]) { + bits[i] = BrotliReverseBits(depth[i], next_code[depth[i]]++); + } + } +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/entropy_encode.h b/packages/runtime/vendor/brotli/c/enc/entropy_encode.h new file mode 100644 index 000000000..0470c16e0 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/entropy_encode.h @@ -0,0 +1,121 @@ +/* Copyright 2010 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Entropy encoding (Huffman) utilities. */ + +#ifndef BROTLI_ENC_ENTROPY_ENCODE_H_ +#define BROTLI_ENC_ENTROPY_ENCODE_H_ + +#include "../common/platform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* A node of a Huffman tree. */ +typedef struct HuffmanTree { + uint32_t total_count_; + int16_t index_left_; + int16_t index_right_or_value_; +} HuffmanTree; + +static BROTLI_INLINE void InitHuffmanTree(HuffmanTree* self, uint32_t count, + int16_t left, int16_t right) { + self->total_count_ = count; + self->index_left_ = left; + self->index_right_or_value_ = right; +} + +/* Returns 1 is assignment of depths succeeded, otherwise 0. */ +BROTLI_INTERNAL BROTLI_BOOL BrotliSetDepth( + int p, HuffmanTree* pool, uint8_t* depth, int max_depth); + +/* This function will create a Huffman tree. + + The (data,length) contains the population counts. + The tree_limit is the maximum bit depth of the Huffman codes. + + The depth contains the tree, i.e., how many bits are used for + the symbol. + + The actual Huffman tree is constructed in the tree[] array, which has to + be at least 2 * length + 1 long. + + See http://en.wikipedia.org/wiki/Huffman_coding */ +BROTLI_INTERNAL void BrotliCreateHuffmanTree(const uint32_t* data, + const size_t length, + const int tree_limit, + HuffmanTree* tree, + uint8_t* depth); + +/* Change the population counts in a way that the consequent + Huffman tree compression, especially its RLE-part will be more + likely to compress this data more efficiently. + + length contains the size of the histogram. + counts contains the population counts. + good_for_rle is a buffer of at least length size */ +BROTLI_INTERNAL void BrotliOptimizeHuffmanCountsForRle( + size_t length, uint32_t* counts, uint8_t* good_for_rle); + +/* Write a Huffman tree from bit depths into the bit-stream representation + of a Huffman tree. The generated Huffman tree is to be compressed once + more using a Huffman tree */ +BROTLI_INTERNAL void BrotliWriteHuffmanTree(const uint8_t* depth, + size_t length, + size_t* tree_size, + uint8_t* tree, + uint8_t* extra_bits_data); + +/* Get the actual bit values for a tree of bit depths. */ +BROTLI_INTERNAL void BrotliConvertBitDepthsToSymbols(const uint8_t* depth, + size_t len, + uint16_t* bits); + +BROTLI_INTERNAL extern BROTLI_MODEL("small") const size_t kBrotliShellGaps[6]; +/* Input size optimized Shell sort. */ +typedef BROTLI_BOOL (*HuffmanTreeComparator)( + const HuffmanTree*, const HuffmanTree*); +static BROTLI_INLINE void SortHuffmanTreeItems(HuffmanTree* items, + const size_t n, HuffmanTreeComparator comparator) { + if (n < 13) { + /* Insertion sort. */ + size_t i; + for (i = 1; i < n; ++i) { + HuffmanTree tmp = items[i]; + size_t k = i; + size_t j = i - 1; + while (comparator(&tmp, &items[j])) { + items[k] = items[j]; + k = j; + if (!j--) break; + } + items[k] = tmp; + } + return; + } else { + /* Shell sort. */ + int g = n < 57 ? 2 : 0; + for (; g < 6; ++g) { + size_t gap = kBrotliShellGaps[g]; + size_t i; + for (i = gap; i < n; ++i) { + size_t j = i; + HuffmanTree tmp = items[i]; + for (; j >= gap && comparator(&tmp, &items[j - gap]); j -= gap) { + items[j] = items[j - gap]; + } + items[j] = tmp; + } + } + } +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_ENTROPY_ENCODE_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/entropy_encode_static.h b/packages/runtime/vendor/brotli/c/enc/entropy_encode_static.h new file mode 100644 index 000000000..5056eaa13 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/entropy_encode_static.h @@ -0,0 +1,548 @@ +/* Copyright 2015 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Static entropy codes used for faster meta-block encoding. */ + +#ifndef BROTLI_ENC_ENTROPY_ENCODE_STATIC_H_ +#define BROTLI_ENC_ENTROPY_ENCODE_STATIC_H_ + +#include "../common/constants.h" +#include "../common/platform.h" +#include "write_bits.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +static const BROTLI_MODEL("small") uint8_t kCodeLengthDepth[18] = { + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 0, 4, 4, +}; + +static const BROTLI_MODEL("small") +uint8_t kStaticCommandCodeDepth[BROTLI_NUM_COMMAND_SYMBOLS] = { + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, + 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, +}; + +static const BROTLI_MODEL("small") +uint8_t kStaticDistanceCodeDepth[64] = { + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, +}; + +/* GENERATED CODE START */ +static const BROTLI_MODEL("small") +uint32_t kCodeLengthBits[18] = { + 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 15, 31, 0, 11, 7, +}; + +static BROTLI_INLINE void StoreStaticCodeLengthCode( + size_t* storage_ix, uint8_t* storage) { + BrotliWriteBits( + 40, BROTLI_MAKE_UINT64_T(0x0000FFu, 0x55555554u), storage_ix, storage); +} + +static const BROTLI_MODEL("small") +uint64_t kZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = { + 0x00000000, 0x00000000, 0x00000000, 0x00000007, 0x00000017, 0x00000027, + 0x00000037, 0x00000047, 0x00000057, 0x00000067, 0x00000077, 0x00000770, + 0x00000b87, 0x00001387, 0x00001b87, 0x00002387, 0x00002b87, 0x00003387, + 0x00003b87, 0x00000397, 0x00000b97, 0x00001397, 0x00001b97, 0x00002397, + 0x00002b97, 0x00003397, 0x00003b97, 0x000003a7, 0x00000ba7, 0x000013a7, + 0x00001ba7, 0x000023a7, 0x00002ba7, 0x000033a7, 0x00003ba7, 0x000003b7, + 0x00000bb7, 0x000013b7, 0x00001bb7, 0x000023b7, 0x00002bb7, 0x000033b7, + 0x00003bb7, 0x000003c7, 0x00000bc7, 0x000013c7, 0x00001bc7, 0x000023c7, + 0x00002bc7, 0x000033c7, 0x00003bc7, 0x000003d7, 0x00000bd7, 0x000013d7, + 0x00001bd7, 0x000023d7, 0x00002bd7, 0x000033d7, 0x00003bd7, 0x000003e7, + 0x00000be7, 0x000013e7, 0x00001be7, 0x000023e7, 0x00002be7, 0x000033e7, + 0x00003be7, 0x000003f7, 0x00000bf7, 0x000013f7, 0x00001bf7, 0x000023f7, + 0x00002bf7, 0x000033f7, 0x00003bf7, 0x0001c387, 0x0005c387, 0x0009c387, + 0x000dc387, 0x0011c387, 0x0015c387, 0x0019c387, 0x001dc387, 0x0001cb87, + 0x0005cb87, 0x0009cb87, 0x000dcb87, 0x0011cb87, 0x0015cb87, 0x0019cb87, + 0x001dcb87, 0x0001d387, 0x0005d387, 0x0009d387, 0x000dd387, 0x0011d387, + 0x0015d387, 0x0019d387, 0x001dd387, 0x0001db87, 0x0005db87, 0x0009db87, + 0x000ddb87, 0x0011db87, 0x0015db87, 0x0019db87, 0x001ddb87, 0x0001e387, + 0x0005e387, 0x0009e387, 0x000de387, 0x0011e387, 0x0015e387, 0x0019e387, + 0x001de387, 0x0001eb87, 0x0005eb87, 0x0009eb87, 0x000deb87, 0x0011eb87, + 0x0015eb87, 0x0019eb87, 0x001deb87, 0x0001f387, 0x0005f387, 0x0009f387, + 0x000df387, 0x0011f387, 0x0015f387, 0x0019f387, 0x001df387, 0x0001fb87, + 0x0005fb87, 0x0009fb87, 0x000dfb87, 0x0011fb87, 0x0015fb87, 0x0019fb87, + 0x001dfb87, 0x0001c397, 0x0005c397, 0x0009c397, 0x000dc397, 0x0011c397, + 0x0015c397, 0x0019c397, 0x001dc397, 0x0001cb97, 0x0005cb97, 0x0009cb97, + 0x000dcb97, 0x0011cb97, 0x0015cb97, 0x0019cb97, 0x001dcb97, 0x0001d397, + 0x0005d397, 0x0009d397, 0x000dd397, 0x0011d397, 0x0015d397, 0x0019d397, + 0x001dd397, 0x0001db97, 0x0005db97, 0x0009db97, 0x000ddb97, 0x0011db97, + 0x0015db97, 0x0019db97, 0x001ddb97, 0x0001e397, 0x0005e397, 0x0009e397, + 0x000de397, 0x0011e397, 0x0015e397, 0x0019e397, 0x001de397, 0x0001eb97, + 0x0005eb97, 0x0009eb97, 0x000deb97, 0x0011eb97, 0x0015eb97, 0x0019eb97, + 0x001deb97, 0x0001f397, 0x0005f397, 0x0009f397, 0x000df397, 0x0011f397, + 0x0015f397, 0x0019f397, 0x001df397, 0x0001fb97, 0x0005fb97, 0x0009fb97, + 0x000dfb97, 0x0011fb97, 0x0015fb97, 0x0019fb97, 0x001dfb97, 0x0001c3a7, + 0x0005c3a7, 0x0009c3a7, 0x000dc3a7, 0x0011c3a7, 0x0015c3a7, 0x0019c3a7, + 0x001dc3a7, 0x0001cba7, 0x0005cba7, 0x0009cba7, 0x000dcba7, 0x0011cba7, + 0x0015cba7, 0x0019cba7, 0x001dcba7, 0x0001d3a7, 0x0005d3a7, 0x0009d3a7, + 0x000dd3a7, 0x0011d3a7, 0x0015d3a7, 0x0019d3a7, 0x001dd3a7, 0x0001dba7, + 0x0005dba7, 0x0009dba7, 0x000ddba7, 0x0011dba7, 0x0015dba7, 0x0019dba7, + 0x001ddba7, 0x0001e3a7, 0x0005e3a7, 0x0009e3a7, 0x000de3a7, 0x0011e3a7, + 0x0015e3a7, 0x0019e3a7, 0x001de3a7, 0x0001eba7, 0x0005eba7, 0x0009eba7, + 0x000deba7, 0x0011eba7, 0x0015eba7, 0x0019eba7, 0x001deba7, 0x0001f3a7, + 0x0005f3a7, 0x0009f3a7, 0x000df3a7, 0x0011f3a7, 0x0015f3a7, 0x0019f3a7, + 0x001df3a7, 0x0001fba7, 0x0005fba7, 0x0009fba7, 0x000dfba7, 0x0011fba7, + 0x0015fba7, 0x0019fba7, 0x001dfba7, 0x0001c3b7, 0x0005c3b7, 0x0009c3b7, + 0x000dc3b7, 0x0011c3b7, 0x0015c3b7, 0x0019c3b7, 0x001dc3b7, 0x0001cbb7, + 0x0005cbb7, 0x0009cbb7, 0x000dcbb7, 0x0011cbb7, 0x0015cbb7, 0x0019cbb7, + 0x001dcbb7, 0x0001d3b7, 0x0005d3b7, 0x0009d3b7, 0x000dd3b7, 0x0011d3b7, + 0x0015d3b7, 0x0019d3b7, 0x001dd3b7, 0x0001dbb7, 0x0005dbb7, 0x0009dbb7, + 0x000ddbb7, 0x0011dbb7, 0x0015dbb7, 0x0019dbb7, 0x001ddbb7, 0x0001e3b7, + 0x0005e3b7, 0x0009e3b7, 0x000de3b7, 0x0011e3b7, 0x0015e3b7, 0x0019e3b7, + 0x001de3b7, 0x0001ebb7, 0x0005ebb7, 0x0009ebb7, 0x000debb7, 0x0011ebb7, + 0x0015ebb7, 0x0019ebb7, 0x001debb7, 0x0001f3b7, 0x0005f3b7, 0x0009f3b7, + 0x000df3b7, 0x0011f3b7, 0x0015f3b7, 0x0019f3b7, 0x001df3b7, 0x0001fbb7, + 0x0005fbb7, 0x0009fbb7, 0x000dfbb7, 0x0011fbb7, 0x0015fbb7, 0x0019fbb7, + 0x001dfbb7, 0x0001c3c7, 0x0005c3c7, 0x0009c3c7, 0x000dc3c7, 0x0011c3c7, + 0x0015c3c7, 0x0019c3c7, 0x001dc3c7, 0x0001cbc7, 0x0005cbc7, 0x0009cbc7, + 0x000dcbc7, 0x0011cbc7, 0x0015cbc7, 0x0019cbc7, 0x001dcbc7, 0x0001d3c7, + 0x0005d3c7, 0x0009d3c7, 0x000dd3c7, 0x0011d3c7, 0x0015d3c7, 0x0019d3c7, + 0x001dd3c7, 0x0001dbc7, 0x0005dbc7, 0x0009dbc7, 0x000ddbc7, 0x0011dbc7, + 0x0015dbc7, 0x0019dbc7, 0x001ddbc7, 0x0001e3c7, 0x0005e3c7, 0x0009e3c7, + 0x000de3c7, 0x0011e3c7, 0x0015e3c7, 0x0019e3c7, 0x001de3c7, 0x0001ebc7, + 0x0005ebc7, 0x0009ebc7, 0x000debc7, 0x0011ebc7, 0x0015ebc7, 0x0019ebc7, + 0x001debc7, 0x0001f3c7, 0x0005f3c7, 0x0009f3c7, 0x000df3c7, 0x0011f3c7, + 0x0015f3c7, 0x0019f3c7, 0x001df3c7, 0x0001fbc7, 0x0005fbc7, 0x0009fbc7, + 0x000dfbc7, 0x0011fbc7, 0x0015fbc7, 0x0019fbc7, 0x001dfbc7, 0x0001c3d7, + 0x0005c3d7, 0x0009c3d7, 0x000dc3d7, 0x0011c3d7, 0x0015c3d7, 0x0019c3d7, + 0x001dc3d7, 0x0001cbd7, 0x0005cbd7, 0x0009cbd7, 0x000dcbd7, 0x0011cbd7, + 0x0015cbd7, 0x0019cbd7, 0x001dcbd7, 0x0001d3d7, 0x0005d3d7, 0x0009d3d7, + 0x000dd3d7, 0x0011d3d7, 0x0015d3d7, 0x0019d3d7, 0x001dd3d7, 0x0001dbd7, + 0x0005dbd7, 0x0009dbd7, 0x000ddbd7, 0x0011dbd7, 0x0015dbd7, 0x0019dbd7, + 0x001ddbd7, 0x0001e3d7, 0x0005e3d7, 0x0009e3d7, 0x000de3d7, 0x0011e3d7, + 0x0015e3d7, 0x0019e3d7, 0x001de3d7, 0x0001ebd7, 0x0005ebd7, 0x0009ebd7, + 0x000debd7, 0x0011ebd7, 0x0015ebd7, 0x0019ebd7, 0x001debd7, 0x0001f3d7, + 0x0005f3d7, 0x0009f3d7, 0x000df3d7, 0x0011f3d7, 0x0015f3d7, 0x0019f3d7, + 0x001df3d7, 0x0001fbd7, 0x0005fbd7, 0x0009fbd7, 0x000dfbd7, 0x0011fbd7, + 0x0015fbd7, 0x0019fbd7, 0x001dfbd7, 0x0001c3e7, 0x0005c3e7, 0x0009c3e7, + 0x000dc3e7, 0x0011c3e7, 0x0015c3e7, 0x0019c3e7, 0x001dc3e7, 0x0001cbe7, + 0x0005cbe7, 0x0009cbe7, 0x000dcbe7, 0x0011cbe7, 0x0015cbe7, 0x0019cbe7, + 0x001dcbe7, 0x0001d3e7, 0x0005d3e7, 0x0009d3e7, 0x000dd3e7, 0x0011d3e7, + 0x0015d3e7, 0x0019d3e7, 0x001dd3e7, 0x0001dbe7, 0x0005dbe7, 0x0009dbe7, + 0x000ddbe7, 0x0011dbe7, 0x0015dbe7, 0x0019dbe7, 0x001ddbe7, 0x0001e3e7, + 0x0005e3e7, 0x0009e3e7, 0x000de3e7, 0x0011e3e7, 0x0015e3e7, 0x0019e3e7, + 0x001de3e7, 0x0001ebe7, 0x0005ebe7, 0x0009ebe7, 0x000debe7, 0x0011ebe7, + 0x0015ebe7, 0x0019ebe7, 0x001debe7, 0x0001f3e7, 0x0005f3e7, 0x0009f3e7, + 0x000df3e7, 0x0011f3e7, 0x0015f3e7, 0x0019f3e7, 0x001df3e7, 0x0001fbe7, + 0x0005fbe7, 0x0009fbe7, 0x000dfbe7, 0x0011fbe7, 0x0015fbe7, 0x0019fbe7, + 0x001dfbe7, 0x0001c3f7, 0x0005c3f7, 0x0009c3f7, 0x000dc3f7, 0x0011c3f7, + 0x0015c3f7, 0x0019c3f7, 0x001dc3f7, 0x0001cbf7, 0x0005cbf7, 0x0009cbf7, + 0x000dcbf7, 0x0011cbf7, 0x0015cbf7, 0x0019cbf7, 0x001dcbf7, 0x0001d3f7, + 0x0005d3f7, 0x0009d3f7, 0x000dd3f7, 0x0011d3f7, 0x0015d3f7, 0x0019d3f7, + 0x001dd3f7, 0x0001dbf7, 0x0005dbf7, 0x0009dbf7, 0x000ddbf7, 0x0011dbf7, + 0x0015dbf7, 0x0019dbf7, 0x001ddbf7, 0x0001e3f7, 0x0005e3f7, 0x0009e3f7, + 0x000de3f7, 0x0011e3f7, 0x0015e3f7, 0x0019e3f7, 0x001de3f7, 0x0001ebf7, + 0x0005ebf7, 0x0009ebf7, 0x000debf7, 0x0011ebf7, 0x0015ebf7, 0x0019ebf7, + 0x001debf7, 0x0001f3f7, 0x0005f3f7, 0x0009f3f7, 0x000df3f7, 0x0011f3f7, + 0x0015f3f7, 0x0019f3f7, 0x001df3f7, 0x0001fbf7, 0x0005fbf7, 0x0009fbf7, + 0x000dfbf7, 0x0011fbf7, 0x0015fbf7, 0x0019fbf7, 0x001dfbf7, 0x00e1c387, + 0x02e1c387, 0x04e1c387, 0x06e1c387, 0x08e1c387, 0x0ae1c387, 0x0ce1c387, + 0x0ee1c387, 0x00e5c387, 0x02e5c387, 0x04e5c387, 0x06e5c387, 0x08e5c387, + 0x0ae5c387, 0x0ce5c387, 0x0ee5c387, 0x00e9c387, 0x02e9c387, 0x04e9c387, + 0x06e9c387, 0x08e9c387, 0x0ae9c387, 0x0ce9c387, 0x0ee9c387, 0x00edc387, + 0x02edc387, 0x04edc387, 0x06edc387, 0x08edc387, 0x0aedc387, 0x0cedc387, + 0x0eedc387, 0x00f1c387, 0x02f1c387, 0x04f1c387, 0x06f1c387, 0x08f1c387, + 0x0af1c387, 0x0cf1c387, 0x0ef1c387, 0x00f5c387, 0x02f5c387, 0x04f5c387, + 0x06f5c387, 0x08f5c387, 0x0af5c387, 0x0cf5c387, 0x0ef5c387, 0x00f9c387, + 0x02f9c387, 0x04f9c387, 0x06f9c387, 0x08f9c387, 0x0af9c387, 0x0cf9c387, + 0x0ef9c387, 0x00fdc387, 0x02fdc387, 0x04fdc387, 0x06fdc387, 0x08fdc387, + 0x0afdc387, 0x0cfdc387, 0x0efdc387, 0x00e1cb87, 0x02e1cb87, 0x04e1cb87, + 0x06e1cb87, 0x08e1cb87, 0x0ae1cb87, 0x0ce1cb87, 0x0ee1cb87, 0x00e5cb87, + 0x02e5cb87, 0x04e5cb87, 0x06e5cb87, 0x08e5cb87, 0x0ae5cb87, 0x0ce5cb87, + 0x0ee5cb87, 0x00e9cb87, 0x02e9cb87, 0x04e9cb87, 0x06e9cb87, 0x08e9cb87, + 0x0ae9cb87, 0x0ce9cb87, 0x0ee9cb87, 0x00edcb87, 0x02edcb87, 0x04edcb87, + 0x06edcb87, 0x08edcb87, 0x0aedcb87, 0x0cedcb87, 0x0eedcb87, 0x00f1cb87, + 0x02f1cb87, 0x04f1cb87, 0x06f1cb87, 0x08f1cb87, 0x0af1cb87, 0x0cf1cb87, + 0x0ef1cb87, 0x00f5cb87, 0x02f5cb87, 0x04f5cb87, 0x06f5cb87, 0x08f5cb87, + 0x0af5cb87, 0x0cf5cb87, 0x0ef5cb87, 0x00f9cb87, 0x02f9cb87, 0x04f9cb87, + 0x06f9cb87, 0x08f9cb87, +}; + +static const BROTLI_MODEL("small") +uint32_t kZeroRepsDepth[BROTLI_NUM_COMMAND_SYMBOLS] = { + 0, 4, 8, 7, 7, 7, 7, 7, 7, 7, 7, 11, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, + 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, + 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, +}; + +static const BROTLI_MODEL("small") +uint64_t kNonZeroRepsBits[BROTLI_NUM_COMMAND_SYMBOLS] = { + 0x0000000b, 0x0000001b, 0x0000002b, 0x0000003b, 0x000002cb, 0x000006cb, + 0x00000acb, 0x00000ecb, 0x000002db, 0x000006db, 0x00000adb, 0x00000edb, + 0x000002eb, 0x000006eb, 0x00000aeb, 0x00000eeb, 0x000002fb, 0x000006fb, + 0x00000afb, 0x00000efb, 0x0000b2cb, 0x0001b2cb, 0x0002b2cb, 0x0003b2cb, + 0x0000b6cb, 0x0001b6cb, 0x0002b6cb, 0x0003b6cb, 0x0000bacb, 0x0001bacb, + 0x0002bacb, 0x0003bacb, 0x0000becb, 0x0001becb, 0x0002becb, 0x0003becb, + 0x0000b2db, 0x0001b2db, 0x0002b2db, 0x0003b2db, 0x0000b6db, 0x0001b6db, + 0x0002b6db, 0x0003b6db, 0x0000badb, 0x0001badb, 0x0002badb, 0x0003badb, + 0x0000bedb, 0x0001bedb, 0x0002bedb, 0x0003bedb, 0x0000b2eb, 0x0001b2eb, + 0x0002b2eb, 0x0003b2eb, 0x0000b6eb, 0x0001b6eb, 0x0002b6eb, 0x0003b6eb, + 0x0000baeb, 0x0001baeb, 0x0002baeb, 0x0003baeb, 0x0000beeb, 0x0001beeb, + 0x0002beeb, 0x0003beeb, 0x0000b2fb, 0x0001b2fb, 0x0002b2fb, 0x0003b2fb, + 0x0000b6fb, 0x0001b6fb, 0x0002b6fb, 0x0003b6fb, 0x0000bafb, 0x0001bafb, + 0x0002bafb, 0x0003bafb, 0x0000befb, 0x0001befb, 0x0002befb, 0x0003befb, + 0x002cb2cb, 0x006cb2cb, 0x00acb2cb, 0x00ecb2cb, 0x002db2cb, 0x006db2cb, + 0x00adb2cb, 0x00edb2cb, 0x002eb2cb, 0x006eb2cb, 0x00aeb2cb, 0x00eeb2cb, + 0x002fb2cb, 0x006fb2cb, 0x00afb2cb, 0x00efb2cb, 0x002cb6cb, 0x006cb6cb, + 0x00acb6cb, 0x00ecb6cb, 0x002db6cb, 0x006db6cb, 0x00adb6cb, 0x00edb6cb, + 0x002eb6cb, 0x006eb6cb, 0x00aeb6cb, 0x00eeb6cb, 0x002fb6cb, 0x006fb6cb, + 0x00afb6cb, 0x00efb6cb, 0x002cbacb, 0x006cbacb, 0x00acbacb, 0x00ecbacb, + 0x002dbacb, 0x006dbacb, 0x00adbacb, 0x00edbacb, 0x002ebacb, 0x006ebacb, + 0x00aebacb, 0x00eebacb, 0x002fbacb, 0x006fbacb, 0x00afbacb, 0x00efbacb, + 0x002cbecb, 0x006cbecb, 0x00acbecb, 0x00ecbecb, 0x002dbecb, 0x006dbecb, + 0x00adbecb, 0x00edbecb, 0x002ebecb, 0x006ebecb, 0x00aebecb, 0x00eebecb, + 0x002fbecb, 0x006fbecb, 0x00afbecb, 0x00efbecb, 0x002cb2db, 0x006cb2db, + 0x00acb2db, 0x00ecb2db, 0x002db2db, 0x006db2db, 0x00adb2db, 0x00edb2db, + 0x002eb2db, 0x006eb2db, 0x00aeb2db, 0x00eeb2db, 0x002fb2db, 0x006fb2db, + 0x00afb2db, 0x00efb2db, 0x002cb6db, 0x006cb6db, 0x00acb6db, 0x00ecb6db, + 0x002db6db, 0x006db6db, 0x00adb6db, 0x00edb6db, 0x002eb6db, 0x006eb6db, + 0x00aeb6db, 0x00eeb6db, 0x002fb6db, 0x006fb6db, 0x00afb6db, 0x00efb6db, + 0x002cbadb, 0x006cbadb, 0x00acbadb, 0x00ecbadb, 0x002dbadb, 0x006dbadb, + 0x00adbadb, 0x00edbadb, 0x002ebadb, 0x006ebadb, 0x00aebadb, 0x00eebadb, + 0x002fbadb, 0x006fbadb, 0x00afbadb, 0x00efbadb, 0x002cbedb, 0x006cbedb, + 0x00acbedb, 0x00ecbedb, 0x002dbedb, 0x006dbedb, 0x00adbedb, 0x00edbedb, + 0x002ebedb, 0x006ebedb, 0x00aebedb, 0x00eebedb, 0x002fbedb, 0x006fbedb, + 0x00afbedb, 0x00efbedb, 0x002cb2eb, 0x006cb2eb, 0x00acb2eb, 0x00ecb2eb, + 0x002db2eb, 0x006db2eb, 0x00adb2eb, 0x00edb2eb, 0x002eb2eb, 0x006eb2eb, + 0x00aeb2eb, 0x00eeb2eb, 0x002fb2eb, 0x006fb2eb, 0x00afb2eb, 0x00efb2eb, + 0x002cb6eb, 0x006cb6eb, 0x00acb6eb, 0x00ecb6eb, 0x002db6eb, 0x006db6eb, + 0x00adb6eb, 0x00edb6eb, 0x002eb6eb, 0x006eb6eb, 0x00aeb6eb, 0x00eeb6eb, + 0x002fb6eb, 0x006fb6eb, 0x00afb6eb, 0x00efb6eb, 0x002cbaeb, 0x006cbaeb, + 0x00acbaeb, 0x00ecbaeb, 0x002dbaeb, 0x006dbaeb, 0x00adbaeb, 0x00edbaeb, + 0x002ebaeb, 0x006ebaeb, 0x00aebaeb, 0x00eebaeb, 0x002fbaeb, 0x006fbaeb, + 0x00afbaeb, 0x00efbaeb, 0x002cbeeb, 0x006cbeeb, 0x00acbeeb, 0x00ecbeeb, + 0x002dbeeb, 0x006dbeeb, 0x00adbeeb, 0x00edbeeb, 0x002ebeeb, 0x006ebeeb, + 0x00aebeeb, 0x00eebeeb, 0x002fbeeb, 0x006fbeeb, 0x00afbeeb, 0x00efbeeb, + 0x002cb2fb, 0x006cb2fb, 0x00acb2fb, 0x00ecb2fb, 0x002db2fb, 0x006db2fb, + 0x00adb2fb, 0x00edb2fb, 0x002eb2fb, 0x006eb2fb, 0x00aeb2fb, 0x00eeb2fb, + 0x002fb2fb, 0x006fb2fb, 0x00afb2fb, 0x00efb2fb, 0x002cb6fb, 0x006cb6fb, + 0x00acb6fb, 0x00ecb6fb, 0x002db6fb, 0x006db6fb, 0x00adb6fb, 0x00edb6fb, + 0x002eb6fb, 0x006eb6fb, 0x00aeb6fb, 0x00eeb6fb, 0x002fb6fb, 0x006fb6fb, + 0x00afb6fb, 0x00efb6fb, 0x002cbafb, 0x006cbafb, 0x00acbafb, 0x00ecbafb, + 0x002dbafb, 0x006dbafb, 0x00adbafb, 0x00edbafb, 0x002ebafb, 0x006ebafb, + 0x00aebafb, 0x00eebafb, 0x002fbafb, 0x006fbafb, 0x00afbafb, 0x00efbafb, + 0x002cbefb, 0x006cbefb, 0x00acbefb, 0x00ecbefb, 0x002dbefb, 0x006dbefb, + 0x00adbefb, 0x00edbefb, 0x002ebefb, 0x006ebefb, 0x00aebefb, 0x00eebefb, + 0x002fbefb, 0x006fbefb, 0x00afbefb, 0x00efbefb, 0x0b2cb2cb, 0x1b2cb2cb, + 0x2b2cb2cb, 0x3b2cb2cb, 0x0b6cb2cb, 0x1b6cb2cb, 0x2b6cb2cb, 0x3b6cb2cb, + 0x0bacb2cb, 0x1bacb2cb, 0x2bacb2cb, 0x3bacb2cb, 0x0becb2cb, 0x1becb2cb, + 0x2becb2cb, 0x3becb2cb, 0x0b2db2cb, 0x1b2db2cb, 0x2b2db2cb, 0x3b2db2cb, + 0x0b6db2cb, 0x1b6db2cb, 0x2b6db2cb, 0x3b6db2cb, 0x0badb2cb, 0x1badb2cb, + 0x2badb2cb, 0x3badb2cb, 0x0bedb2cb, 0x1bedb2cb, 0x2bedb2cb, 0x3bedb2cb, + 0x0b2eb2cb, 0x1b2eb2cb, 0x2b2eb2cb, 0x3b2eb2cb, 0x0b6eb2cb, 0x1b6eb2cb, + 0x2b6eb2cb, 0x3b6eb2cb, 0x0baeb2cb, 0x1baeb2cb, 0x2baeb2cb, 0x3baeb2cb, + 0x0beeb2cb, 0x1beeb2cb, 0x2beeb2cb, 0x3beeb2cb, 0x0b2fb2cb, 0x1b2fb2cb, + 0x2b2fb2cb, 0x3b2fb2cb, 0x0b6fb2cb, 0x1b6fb2cb, 0x2b6fb2cb, 0x3b6fb2cb, + 0x0bafb2cb, 0x1bafb2cb, 0x2bafb2cb, 0x3bafb2cb, 0x0befb2cb, 0x1befb2cb, + 0x2befb2cb, 0x3befb2cb, 0x0b2cb6cb, 0x1b2cb6cb, 0x2b2cb6cb, 0x3b2cb6cb, + 0x0b6cb6cb, 0x1b6cb6cb, 0x2b6cb6cb, 0x3b6cb6cb, 0x0bacb6cb, 0x1bacb6cb, + 0x2bacb6cb, 0x3bacb6cb, 0x0becb6cb, 0x1becb6cb, 0x2becb6cb, 0x3becb6cb, + 0x0b2db6cb, 0x1b2db6cb, 0x2b2db6cb, 0x3b2db6cb, 0x0b6db6cb, 0x1b6db6cb, + 0x2b6db6cb, 0x3b6db6cb, 0x0badb6cb, 0x1badb6cb, 0x2badb6cb, 0x3badb6cb, + 0x0bedb6cb, 0x1bedb6cb, 0x2bedb6cb, 0x3bedb6cb, 0x0b2eb6cb, 0x1b2eb6cb, + 0x2b2eb6cb, 0x3b2eb6cb, 0x0b6eb6cb, 0x1b6eb6cb, 0x2b6eb6cb, 0x3b6eb6cb, + 0x0baeb6cb, 0x1baeb6cb, 0x2baeb6cb, 0x3baeb6cb, 0x0beeb6cb, 0x1beeb6cb, + 0x2beeb6cb, 0x3beeb6cb, 0x0b2fb6cb, 0x1b2fb6cb, 0x2b2fb6cb, 0x3b2fb6cb, + 0x0b6fb6cb, 0x1b6fb6cb, 0x2b6fb6cb, 0x3b6fb6cb, 0x0bafb6cb, 0x1bafb6cb, + 0x2bafb6cb, 0x3bafb6cb, 0x0befb6cb, 0x1befb6cb, 0x2befb6cb, 0x3befb6cb, + 0x0b2cbacb, 0x1b2cbacb, 0x2b2cbacb, 0x3b2cbacb, 0x0b6cbacb, 0x1b6cbacb, + 0x2b6cbacb, 0x3b6cbacb, 0x0bacbacb, 0x1bacbacb, 0x2bacbacb, 0x3bacbacb, + 0x0becbacb, 0x1becbacb, 0x2becbacb, 0x3becbacb, 0x0b2dbacb, 0x1b2dbacb, + 0x2b2dbacb, 0x3b2dbacb, 0x0b6dbacb, 0x1b6dbacb, 0x2b6dbacb, 0x3b6dbacb, + 0x0badbacb, 0x1badbacb, 0x2badbacb, 0x3badbacb, 0x0bedbacb, 0x1bedbacb, + 0x2bedbacb, 0x3bedbacb, 0x0b2ebacb, 0x1b2ebacb, 0x2b2ebacb, 0x3b2ebacb, + 0x0b6ebacb, 0x1b6ebacb, 0x2b6ebacb, 0x3b6ebacb, 0x0baebacb, 0x1baebacb, + 0x2baebacb, 0x3baebacb, 0x0beebacb, 0x1beebacb, 0x2beebacb, 0x3beebacb, + 0x0b2fbacb, 0x1b2fbacb, 0x2b2fbacb, 0x3b2fbacb, 0x0b6fbacb, 0x1b6fbacb, + 0x2b6fbacb, 0x3b6fbacb, 0x0bafbacb, 0x1bafbacb, 0x2bafbacb, 0x3bafbacb, + 0x0befbacb, 0x1befbacb, 0x2befbacb, 0x3befbacb, 0x0b2cbecb, 0x1b2cbecb, + 0x2b2cbecb, 0x3b2cbecb, 0x0b6cbecb, 0x1b6cbecb, 0x2b6cbecb, 0x3b6cbecb, + 0x0bacbecb, 0x1bacbecb, 0x2bacbecb, 0x3bacbecb, 0x0becbecb, 0x1becbecb, + 0x2becbecb, 0x3becbecb, 0x0b2dbecb, 0x1b2dbecb, 0x2b2dbecb, 0x3b2dbecb, + 0x0b6dbecb, 0x1b6dbecb, 0x2b6dbecb, 0x3b6dbecb, 0x0badbecb, 0x1badbecb, + 0x2badbecb, 0x3badbecb, 0x0bedbecb, 0x1bedbecb, 0x2bedbecb, 0x3bedbecb, + 0x0b2ebecb, 0x1b2ebecb, 0x2b2ebecb, 0x3b2ebecb, 0x0b6ebecb, 0x1b6ebecb, + 0x2b6ebecb, 0x3b6ebecb, 0x0baebecb, 0x1baebecb, 0x2baebecb, 0x3baebecb, + 0x0beebecb, 0x1beebecb, 0x2beebecb, 0x3beebecb, 0x0b2fbecb, 0x1b2fbecb, + 0x2b2fbecb, 0x3b2fbecb, 0x0b6fbecb, 0x1b6fbecb, 0x2b6fbecb, 0x3b6fbecb, + 0x0bafbecb, 0x1bafbecb, 0x2bafbecb, 0x3bafbecb, 0x0befbecb, 0x1befbecb, + 0x2befbecb, 0x3befbecb, 0x0b2cb2db, 0x1b2cb2db, 0x2b2cb2db, 0x3b2cb2db, + 0x0b6cb2db, 0x1b6cb2db, 0x2b6cb2db, 0x3b6cb2db, 0x0bacb2db, 0x1bacb2db, + 0x2bacb2db, 0x3bacb2db, 0x0becb2db, 0x1becb2db, 0x2becb2db, 0x3becb2db, + 0x0b2db2db, 0x1b2db2db, 0x2b2db2db, 0x3b2db2db, 0x0b6db2db, 0x1b6db2db, + 0x2b6db2db, 0x3b6db2db, 0x0badb2db, 0x1badb2db, 0x2badb2db, 0x3badb2db, + 0x0bedb2db, 0x1bedb2db, 0x2bedb2db, 0x3bedb2db, 0x0b2eb2db, 0x1b2eb2db, + 0x2b2eb2db, 0x3b2eb2db, 0x0b6eb2db, 0x1b6eb2db, 0x2b6eb2db, 0x3b6eb2db, + 0x0baeb2db, 0x1baeb2db, 0x2baeb2db, 0x3baeb2db, 0x0beeb2db, 0x1beeb2db, + 0x2beeb2db, 0x3beeb2db, 0x0b2fb2db, 0x1b2fb2db, 0x2b2fb2db, 0x3b2fb2db, + 0x0b6fb2db, 0x1b6fb2db, 0x2b6fb2db, 0x3b6fb2db, 0x0bafb2db, 0x1bafb2db, + 0x2bafb2db, 0x3bafb2db, 0x0befb2db, 0x1befb2db, 0x2befb2db, 0x3befb2db, + 0x0b2cb6db, 0x1b2cb6db, 0x2b2cb6db, 0x3b2cb6db, 0x0b6cb6db, 0x1b6cb6db, + 0x2b6cb6db, 0x3b6cb6db, 0x0bacb6db, 0x1bacb6db, 0x2bacb6db, 0x3bacb6db, + 0x0becb6db, 0x1becb6db, 0x2becb6db, 0x3becb6db, 0x0b2db6db, 0x1b2db6db, + 0x2b2db6db, 0x3b2db6db, 0x0b6db6db, 0x1b6db6db, 0x2b6db6db, 0x3b6db6db, + 0x0badb6db, 0x1badb6db, 0x2badb6db, 0x3badb6db, 0x0bedb6db, 0x1bedb6db, + 0x2bedb6db, 0x3bedb6db, 0x0b2eb6db, 0x1b2eb6db, 0x2b2eb6db, 0x3b2eb6db, + 0x0b6eb6db, 0x1b6eb6db, 0x2b6eb6db, 0x3b6eb6db, 0x0baeb6db, 0x1baeb6db, + 0x2baeb6db, 0x3baeb6db, +}; + +static const BROTLI_MODEL("small") +uint32_t kNonZeroRepsDepth[BROTLI_NUM_COMMAND_SYMBOLS] = { + 6, 6, 6, 6, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, + 12, 12, 12, 12, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, + 18, 18, 18, 18, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, + 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, +}; + +static const BROTLI_MODEL("small") +uint16_t kStaticCommandCodeBits[BROTLI_NUM_COMMAND_SYMBOLS] = { + 0, 256, 128, 384, 64, 320, 192, 448, + 32, 288, 160, 416, 96, 352, 224, 480, + 16, 272, 144, 400, 80, 336, 208, 464, + 48, 304, 176, 432, 112, 368, 240, 496, + 8, 264, 136, 392, 72, 328, 200, 456, + 40, 296, 168, 424, 104, 360, 232, 488, + 24, 280, 152, 408, 88, 344, 216, 472, + 56, 312, 184, 440, 120, 376, 248, 504, + 4, 260, 132, 388, 68, 324, 196, 452, + 36, 292, 164, 420, 100, 356, 228, 484, + 20, 276, 148, 404, 84, 340, 212, 468, + 52, 308, 180, 436, 116, 372, 244, 500, + 12, 268, 140, 396, 76, 332, 204, 460, + 44, 300, 172, 428, 108, 364, 236, 492, + 28, 284, 156, 412, 92, 348, 220, 476, + 60, 316, 188, 444, 124, 380, 252, 508, + 2, 258, 130, 386, 66, 322, 194, 450, + 34, 290, 162, 418, 98, 354, 226, 482, + 18, 274, 146, 402, 82, 338, 210, 466, + 50, 306, 178, 434, 114, 370, 242, 498, + 10, 266, 138, 394, 74, 330, 202, 458, + 42, 298, 170, 426, 106, 362, 234, 490, + 26, 282, 154, 410, 90, 346, 218, 474, + 58, 314, 186, 442, 122, 378, 250, 506, + 6, 262, 134, 390, 70, 326, 198, 454, + 38, 294, 166, 422, 102, 358, 230, 486, + 22, 278, 150, 406, 86, 342, 214, 470, + 54, 310, 182, 438, 118, 374, 246, 502, + 14, 270, 142, 398, 78, 334, 206, 462, + 46, 302, 174, 430, 110, 366, 238, 494, + 30, 286, 158, 414, 94, 350, 222, 478, + 62, 318, 190, 446, 126, 382, 254, 510, + 1, 257, 129, 385, 65, 321, 193, 449, + 33, 289, 161, 417, 97, 353, 225, 481, + 17, 273, 145, 401, 81, 337, 209, 465, + 49, 305, 177, 433, 113, 369, 241, 497, + 9, 265, 137, 393, 73, 329, 201, 457, + 41, 297, 169, 425, 105, 361, 233, 489, + 25, 281, 153, 409, 89, 345, 217, 473, + 57, 313, 185, 441, 121, 377, 249, 505, + 5, 261, 133, 389, 69, 325, 197, 453, + 37, 293, 165, 421, 101, 357, 229, 485, + 21, 277, 149, 405, 85, 341, 213, 469, + 53, 309, 181, 437, 117, 373, 245, 501, + 13, 269, 141, 397, 77, 333, 205, 461, + 45, 301, 173, 429, 109, 365, 237, 493, + 29, 285, 157, 413, 93, 349, 221, 477, + 61, 317, 189, 445, 125, 381, 253, 509, + 3, 259, 131, 387, 67, 323, 195, 451, + 35, 291, 163, 419, 99, 355, 227, 483, + 19, 275, 147, 403, 83, 339, 211, 467, + 51, 307, 179, 435, 115, 371, 243, 499, + 11, 267, 139, 395, 75, 331, 203, 459, + 43, 299, 171, 427, 107, 363, 235, 491, + 27, 283, 155, 411, 91, 347, 219, 475, + 59, 315, 187, 443, 123, 379, 251, 507, + 7, 1031, 519, 1543, 263, 1287, 775, 1799, + 135, 1159, 647, 1671, 391, 1415, 903, 1927, + 71, 1095, 583, 1607, 327, 1351, 839, 1863, + 199, 1223, 711, 1735, 455, 1479, 967, 1991, + 39, 1063, 551, 1575, 295, 1319, 807, 1831, + 167, 1191, 679, 1703, 423, 1447, 935, 1959, + 103, 1127, 615, 1639, 359, 1383, 871, 1895, + 231, 1255, 743, 1767, 487, 1511, 999, 2023, + 23, 1047, 535, 1559, 279, 1303, 791, 1815, + 151, 1175, 663, 1687, 407, 1431, 919, 1943, + 87, 1111, 599, 1623, 343, 1367, 855, 1879, + 215, 1239, 727, 1751, 471, 1495, 983, 2007, + 55, 1079, 567, 1591, 311, 1335, 823, 1847, + 183, 1207, 695, 1719, 439, 1463, 951, 1975, + 119, 1143, 631, 1655, 375, 1399, 887, 1911, + 247, 1271, 759, 1783, 503, 1527, 1015, 2039, + 15, 1039, 527, 1551, 271, 1295, 783, 1807, + 143, 1167, 655, 1679, 399, 1423, 911, 1935, + 79, 1103, 591, 1615, 335, 1359, 847, 1871, + 207, 1231, 719, 1743, 463, 1487, 975, 1999, + 47, 1071, 559, 1583, 303, 1327, 815, 1839, + 175, 1199, 687, 1711, 431, 1455, 943, 1967, + 111, 1135, 623, 1647, 367, 1391, 879, 1903, + 239, 1263, 751, 1775, 495, 1519, 1007, 2031, + 31, 1055, 543, 1567, 287, 1311, 799, 1823, + 159, 1183, 671, 1695, 415, 1439, 927, 1951, + 95, 1119, 607, 1631, 351, 1375, 863, 1887, + 223, 1247, 735, 1759, 479, 1503, 991, 2015, + 63, 1087, 575, 1599, 319, 1343, 831, 1855, + 191, 1215, 703, 1727, 447, 1471, 959, 1983, + 127, 1151, 639, 1663, 383, 1407, 895, 1919, + 255, 1279, 767, 1791, 511, 1535, 1023, 2047, +}; + +static BROTLI_INLINE void StoreStaticCommandHuffmanTree( + size_t* storage_ix, uint8_t* storage) { + BrotliWriteBits( + 56, BROTLI_MAKE_UINT64_T(0x926244U, 0x16307003U), storage_ix, storage); + BrotliWriteBits(3, 0x00000000U, storage_ix, storage); +} + +static const BROTLI_MODEL("small") uint16_t kStaticDistanceCodeBits[64] = { + 0, 32, 16, 48, 8, 40, 24, 56, 4, 36, 20, 52, 12, 44, 28, 60, + 2, 34, 18, 50, 10, 42, 26, 58, 6, 38, 22, 54, 14, 46, 30, 62, + 1, 33, 17, 49, 9, 41, 25, 57, 5, 37, 21, 53, 13, 45, 29, 61, + 3, 35, 19, 51, 11, 43, 27, 59, 7, 39, 23, 55, 15, 47, 31, 63, +}; + +static BROTLI_INLINE void StoreStaticDistanceHuffmanTree( + size_t* storage_ix, uint8_t* storage) { + BrotliWriteBits(28, 0x0369DC03u, storage_ix, storage); +} +/* GENERATED CODE END */ + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_ENTROPY_ENCODE_STATIC_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/fast_log.c b/packages/runtime/vendor/brotli/c/enc/fast_log.c new file mode 100644 index 000000000..7b7ac0295 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/fast_log.c @@ -0,0 +1,105 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#include "fast_log.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* ", ".join(["%.16ff" % x for x in [0.0]+[log2(x) for x in range(1, 256)]]) */ +const BROTLI_MODEL("small") double kBrotliLog2Table[BROTLI_LOG2_TABLE_SIZE] = { + 0.0000000000000000f, 0.0000000000000000f, 1.0000000000000000f, + 1.5849625007211563f, 2.0000000000000000f, 2.3219280948873622f, + 2.5849625007211561f, 2.8073549220576042f, 3.0000000000000000f, + 3.1699250014423126f, 3.3219280948873626f, 3.4594316186372978f, + 3.5849625007211565f, 3.7004397181410922f, 3.8073549220576037f, + 3.9068905956085187f, 4.0000000000000000f, 4.0874628412503400f, + 4.1699250014423122f, 4.2479275134435852f, 4.3219280948873626f, + 4.3923174227787607f, 4.4594316186372973f, 4.5235619560570131f, + 4.5849625007211570f, 4.6438561897747244f, 4.7004397181410926f, + 4.7548875021634691f, 4.8073549220576037f, 4.8579809951275728f, + 4.9068905956085187f, 4.9541963103868758f, 5.0000000000000000f, + 5.0443941193584534f, 5.0874628412503400f, 5.1292830169449664f, + 5.1699250014423122f, 5.2094533656289501f, 5.2479275134435852f, + 5.2854022188622487f, 5.3219280948873626f, 5.3575520046180838f, + 5.3923174227787607f, 5.4262647547020979f, 5.4594316186372973f, + 5.4918530963296748f, 5.5235619560570131f, 5.5545888516776376f, + 5.5849625007211570f, 5.6147098441152083f, 5.6438561897747244f, + 5.6724253419714961f, 5.7004397181410926f, 5.7279204545631996f, + 5.7548875021634691f, 5.7813597135246599f, 5.8073549220576046f, + 5.8328900141647422f, 5.8579809951275719f, 5.8826430493618416f, + 5.9068905956085187f, 5.9307373375628867f, 5.9541963103868758f, + 5.9772799234999168f, 6.0000000000000000f, 6.0223678130284544f, + 6.0443941193584534f, 6.0660891904577721f, 6.0874628412503400f, + 6.1085244567781700f, 6.1292830169449672f, 6.1497471195046822f, + 6.1699250014423122f, 6.1898245588800176f, 6.2094533656289510f, + 6.2288186904958804f, 6.2479275134435861f, 6.2667865406949019f, + 6.2854022188622487f, 6.3037807481771031f, 6.3219280948873617f, + 6.3398500028846252f, 6.3575520046180847f, 6.3750394313469254f, + 6.3923174227787598f, 6.4093909361377026f, 6.4262647547020979f, + 6.4429434958487288f, 6.4594316186372982f, 6.4757334309663976f, + 6.4918530963296748f, 6.5077946401986964f, 6.5235619560570131f, + 6.5391588111080319f, 6.5545888516776376f, 6.5698556083309478f, + 6.5849625007211561f, 6.5999128421871278f, 6.6147098441152092f, + 6.6293566200796095f, 6.6438561897747253f, 6.6582114827517955f, + 6.6724253419714952f, 6.6865005271832185f, 6.7004397181410917f, + 6.7142455176661224f, 6.7279204545631988f, 6.7414669864011465f, + 6.7548875021634691f, 6.7681843247769260f, 6.7813597135246599f, + 6.7944158663501062f, 6.8073549220576037f, 6.8201789624151887f, + 6.8328900141647422f, 6.8454900509443757f, 6.8579809951275719f, + 6.8703647195834048f, 6.8826430493618416f, 6.8948177633079437f, + 6.9068905956085187f, 6.9188632372745955f, 6.9307373375628867f, + 6.9425145053392399f, 6.9541963103868758f, 6.9657842846620879f, + 6.9772799234999168f, 6.9886846867721664f, 7.0000000000000000f, + 7.0112272554232540f, 7.0223678130284544f, 7.0334230015374501f, + 7.0443941193584534f, 7.0552824355011898f, 7.0660891904577721f, + 7.0768155970508317f, 7.0874628412503400f, 7.0980320829605272f, + 7.1085244567781700f, 7.1189410727235076f, 7.1292830169449664f, + 7.1395513523987937f, 7.1497471195046822f, 7.1598713367783891f, + 7.1699250014423130f, 7.1799090900149345f, 7.1898245588800176f, + 7.1996723448363644f, 7.2094533656289492f, 7.2191685204621621f, + 7.2288186904958804f, 7.2384047393250794f, 7.2479275134435861f, + 7.2573878426926521f, 7.2667865406949019f, 7.2761244052742384f, + 7.2854022188622487f, 7.2946207488916270f, 7.3037807481771031f, + 7.3128829552843557f, 7.3219280948873617f, 7.3309168781146177f, + 7.3398500028846243f, 7.3487281542310781f, 7.3575520046180847f, + 7.3663222142458151f, 7.3750394313469254f, 7.3837042924740528f, + 7.3923174227787607f, 7.4008794362821844f, 7.4093909361377026f, + 7.4178525148858991f, 7.4262647547020979f, 7.4346282276367255f, + 7.4429434958487288f, 7.4512111118323299f, 7.4594316186372973f, + 7.4676055500829976f, 7.4757334309663976f, 7.4838157772642564f, + 7.4918530963296748f, 7.4998458870832057f, 7.5077946401986964f, + 7.5156998382840436f, 7.5235619560570131f, 7.5313814605163119f, + 7.5391588111080319f, 7.5468944598876373f, 7.5545888516776376f, + 7.5622424242210728f, 7.5698556083309478f, 7.5774288280357487f, + 7.5849625007211561f, 7.5924570372680806f, 7.5999128421871278f, + 7.6073303137496113f, 7.6147098441152075f, 7.6220518194563764f, + 7.6293566200796095f, 7.6366246205436488f, 7.6438561897747244f, + 7.6510516911789290f, 7.6582114827517955f, 7.6653359171851765f, + 7.6724253419714952f, 7.6794800995054464f, 7.6865005271832185f, + 7.6934869574993252f, 7.7004397181410926f, 7.7073591320808825f, + 7.7142455176661224f, 7.7210991887071856f, 7.7279204545631996f, + 7.7347096202258392f, 7.7414669864011465f, 7.7481928495894596f, + 7.7548875021634691f, 7.7615512324444795f, 7.7681843247769260f, + 7.7747870596011737f, 7.7813597135246608f, 7.7879025593914317f, + 7.7944158663501062f, 7.8008998999203047f, 7.8073549220576037f, + 7.8137811912170374f, 7.8201789624151887f, 7.8265484872909159f, + 7.8328900141647422f, 7.8392037880969445f, 7.8454900509443757f, + 7.8517490414160571f, 7.8579809951275719f, 7.8641861446542798f, + 7.8703647195834048f, 7.8765169465650002f, 7.8826430493618425f, + 7.8887432488982601f, 7.8948177633079446f, 7.9008668079807496f, + 7.9068905956085187f, 7.9128893362299619f, 7.9188632372745955f, + 7.9248125036057813f, 7.9307373375628867f, 7.9366379390025719f, + 7.9425145053392399f, 7.9483672315846778f, 7.9541963103868758f, + 7.9600019320680806f, 7.9657842846620870f, 7.9715435539507720f, + 7.9772799234999168f, 7.9829935746943104f, 7.9886846867721664f, + 7.9943534368588578f +}; + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/fast_log.h b/packages/runtime/vendor/brotli/c/enc/fast_log.h new file mode 100644 index 000000000..a245443ff --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/fast_log.h @@ -0,0 +1,66 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Utilities for fast computation of logarithms. */ + +#ifndef BROTLI_ENC_FAST_LOG_H_ +#define BROTLI_ENC_FAST_LOG_H_ + +#include + +#include "../common/platform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +static BROTLI_INLINE uint32_t Log2FloorNonZero(size_t n) { +#if defined(BROTLI_BSR32) + return BROTLI_BSR32((uint32_t)n); +#else + uint32_t result = 0; + while (n >>= 1) result++; + return result; +#endif +} + +#define BROTLI_LOG2_TABLE_SIZE 256 + +/* A lookup table for small values of log2(int) to be used in entropy + computation. */ +BROTLI_INTERNAL extern const BROTLI_MODEL("small") +double kBrotliLog2Table[BROTLI_LOG2_TABLE_SIZE]; + +/* Visual Studio 2012 and Android API levels < 18 do not have the log2() + * function defined, so we use log() and a multiplication instead. */ +#if !defined(BROTLI_HAVE_LOG2) +#if ((defined(_MSC_VER) && _MSC_VER <= 1700) || \ + (defined(__ANDROID_API__) && __ANDROID_API__ < 18)) +#define BROTLI_HAVE_LOG2 0 +#else +#define BROTLI_HAVE_LOG2 1 +#endif +#endif + +#define LOG_2_INV 1.4426950408889634 + +/* Faster logarithm for small integers, with the property of log2(0) == 0. */ +static BROTLI_INLINE double FastLog2(size_t v) { + if (v < BROTLI_LOG2_TABLE_SIZE) { + return kBrotliLog2Table[v]; + } +#if !(BROTLI_HAVE_LOG2) + return log((double)v) * LOG_2_INV; +#else + return log2((double)v); +#endif +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_FAST_LOG_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/find_match_length.h b/packages/runtime/vendor/brotli/c/enc/find_match_length.h new file mode 100644 index 000000000..096be9331 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/find_match_length.h @@ -0,0 +1,70 @@ +/* Copyright 2010 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Function to find maximal matching prefixes of strings. */ + +#ifndef BROTLI_ENC_FIND_MATCH_LENGTH_H_ +#define BROTLI_ENC_FIND_MATCH_LENGTH_H_ + +#include "../common/platform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* Separate implementation for little-endian 64-bit targets, for speed. */ +#if defined(BROTLI_TZCNT64) && BROTLI_64_BITS && BROTLI_LITTLE_ENDIAN +static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1, + const uint8_t* s2, + size_t limit) { + const uint8_t *s1_orig = s1; + for (; limit >= 8; limit -= 8) { + uint64_t x = BROTLI_UNALIGNED_LOAD64LE(s2) ^ + BROTLI_UNALIGNED_LOAD64LE(s1); + s2 += 8; + if (x != 0) { + size_t matching_bits = (size_t)BROTLI_TZCNT64(x); + return (size_t)(s1 - s1_orig) + (matching_bits >> 3); + } + s1 += 8; + } + while (limit && *s1 == *s2) { + limit--; + ++s2; + ++s1; + } + return (size_t)(s1 - s1_orig); +} +#else +static BROTLI_INLINE size_t FindMatchLengthWithLimit(const uint8_t* s1, + const uint8_t* s2, + size_t limit) { + size_t matched = 0; + const uint8_t* s2_limit = s2 + limit; + const uint8_t* s2_ptr = s2; + /* Find out how long the match is. We loop over the data 32 bits at a + time until we find a 32-bit block that doesn't match; then we find + the first non-matching bit and use that to calculate the total + length of the match. */ + while (s2_ptr <= s2_limit - 4 && + BrotliUnalignedRead32(s2_ptr) == + BrotliUnalignedRead32(s1 + matched)) { + s2_ptr += 4; + matched += 4; + } + while ((s2_ptr < s2_limit) && (s1[matched] == *s2_ptr)) { + ++s2_ptr; + ++matched; + } + return matched; +} +#endif + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_FIND_MATCH_LENGTH_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/hash.h b/packages/runtime/vendor/brotli/c/enc/hash.h new file mode 100644 index 000000000..d86fa1895 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/hash.h @@ -0,0 +1,735 @@ +/* Copyright 2010 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* A (forgetful) hash table to the data seen by the compressor, to + help create backward references to previous data. */ + +#ifndef BROTLI_ENC_HASH_H_ +#define BROTLI_ENC_HASH_H_ + +#include "../common/constants.h" +#include "../common/dictionary.h" +#include "../common/platform.h" +#include "compound_dictionary.h" +#include "encoder_dict.h" +#include "fast_log.h" +#include "find_match_length.h" +#include "hash_base.h" +#include "matching_tag_mask.h" +#include "memory.h" +#include "params.h" +#include "quality.h" +#include "static_dict.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +typedef struct { + /** + * Dynamically allocated areas; regular hasher uses one or two allocations; + * "composite" hasher uses up to 4 allocations. + */ + void* extra[4]; + + /** + * False before the first invocation of HasherSetup (where "extra" memory) + * is allocated. + */ + BROTLI_BOOL is_setup_; + + size_t dict_num_lookups; + size_t dict_num_matches; + + BrotliHasherParams params; + + /** + * False if hasher needs to be "prepared" before use (before the first + * invocation of HasherSetup or after HasherReset). "preparation" is hasher + * data initialization (using input ringbuffer). + */ + BROTLI_BOOL is_prepared_; +} HasherCommon; + +#define score_t size_t + +static const uint32_t kCutoffTransformsCount = 10; +/* 0, 12, 27, 23, 42, 63, 56, 48, 59, 64 */ +/* 0+0, 4+8, 8+19, 12+11, 16+26, 20+43, 24+32, 28+20, 32+27, 36+28 */ +static const uint64_t kCutoffTransforms = + BROTLI_MAKE_UINT64_T(0x071B520A, 0xDA2D3200); + +typedef struct HasherSearchResult { + size_t len; + size_t distance; + score_t score; + int len_code_delta; /* == len_code - len */ +} HasherSearchResult; + +static BROTLI_INLINE void PrepareDistanceCache( + int* BROTLI_RESTRICT distance_cache, const int num_distances) { + if (num_distances > 4) { + int last_distance = distance_cache[0]; + distance_cache[4] = last_distance - 1; + distance_cache[5] = last_distance + 1; + distance_cache[6] = last_distance - 2; + distance_cache[7] = last_distance + 2; + distance_cache[8] = last_distance - 3; + distance_cache[9] = last_distance + 3; + if (num_distances > 10) { + int next_last_distance = distance_cache[1]; + distance_cache[10] = next_last_distance - 1; + distance_cache[11] = next_last_distance + 1; + distance_cache[12] = next_last_distance - 2; + distance_cache[13] = next_last_distance + 2; + distance_cache[14] = next_last_distance - 3; + distance_cache[15] = next_last_distance + 3; + } + } +} + +#define BROTLI_LITERAL_BYTE_SCORE 135 +#define BROTLI_DISTANCE_BIT_PENALTY 30 +/* Score must be positive after applying maximal penalty. */ +#define BROTLI_SCORE_BASE (BROTLI_DISTANCE_BIT_PENALTY * 8 * sizeof(size_t)) + +/* Usually, we always choose the longest backward reference. This function + allows for the exception of that rule. + + If we choose a backward reference that is further away, it will + usually be coded with more bits. We approximate this by assuming + log2(distance). If the distance can be expressed in terms of the + last four distances, we use some heuristic constants to estimate + the bits cost. For the first up to four literals we use the bit + cost of the literals from the literal cost model, after that we + use the average bit cost of the cost model. + + This function is used to sometimes discard a longer backward reference + when it is not much longer and the bit cost for encoding it is more + than the saved literals. + + backward_reference_offset MUST be positive. */ +static BROTLI_INLINE score_t BackwardReferenceScore( + size_t copy_length, size_t backward_reference_offset) { + return BROTLI_SCORE_BASE + BROTLI_LITERAL_BYTE_SCORE * (score_t)copy_length - + BROTLI_DISTANCE_BIT_PENALTY * Log2FloorNonZero(backward_reference_offset); +} + +static BROTLI_INLINE score_t BackwardReferenceScoreUsingLastDistance( + size_t copy_length) { + return BROTLI_LITERAL_BYTE_SCORE * (score_t)copy_length + + BROTLI_SCORE_BASE + 15; +} + +static BROTLI_INLINE score_t BackwardReferencePenaltyUsingLastDistance( + size_t distance_short_code) { + return (score_t)39 + ((0x1CA10 >> (distance_short_code & 0xE)) & 0xE); +} + +static BROTLI_INLINE BROTLI_BOOL TestStaticDictionaryItem( + const BrotliEncoderDictionary* dictionary, size_t len, size_t word_idx, + const uint8_t* data, size_t max_length, size_t max_backward, + size_t max_distance, HasherSearchResult* out) { + size_t offset; + size_t matchlen; + size_t backward; + score_t score; + offset = dictionary->words->offsets_by_length[len] + len * word_idx; + if (len > max_length) { + return BROTLI_FALSE; + } + + matchlen = + FindMatchLengthWithLimit(data, &dictionary->words->data[offset], len); + if (matchlen + dictionary->cutoffTransformsCount <= len || matchlen == 0) { + return BROTLI_FALSE; + } + { + size_t cut = len - matchlen; + size_t transform_id = (cut << 2) + + (size_t)((dictionary->cutoffTransforms >> (cut * 6)) & 0x3F); + backward = max_backward + 1 + word_idx + + (transform_id << dictionary->words->size_bits_by_length[len]); + } + if (backward > max_distance) { + return BROTLI_FALSE; + } + score = BackwardReferenceScore(matchlen, backward); + if (score < out->score) { + return BROTLI_FALSE; + } + out->len = matchlen; + out->len_code_delta = (int)len - (int)matchlen; + out->distance = backward; + out->score = score; + return BROTLI_TRUE; +} + +static BROTLI_INLINE void SearchInStaticDictionary( + const BrotliEncoderDictionary* dictionary, + HasherCommon* common, const uint8_t* data, size_t max_length, + size_t max_backward, size_t max_distance, + HasherSearchResult* out, BROTLI_BOOL shallow) { + size_t key; + size_t i; + if (common->dict_num_matches < (common->dict_num_lookups >> 7)) { + return; + } + key = Hash14(data) << 1; + for (i = 0; i < (shallow ? 1u : 2u); ++i, ++key) { + common->dict_num_lookups++; + if (dictionary->hash_table_lengths[key] != 0) { + BROTLI_BOOL item_matches = TestStaticDictionaryItem( + dictionary, dictionary->hash_table_lengths[key], + dictionary->hash_table_words[key], data, + max_length, max_backward, max_distance, out); + if (item_matches) { + common->dict_num_matches++; + } + } + } +} + +typedef struct BackwardMatch { + uint32_t distance; + uint32_t length_and_code; +} BackwardMatch; + +static BROTLI_INLINE void InitBackwardMatch(BackwardMatch* self, + size_t dist, size_t len) { + self->distance = (uint32_t)dist; + self->length_and_code = (uint32_t)(len << 5); +} + +static BROTLI_INLINE void InitDictionaryBackwardMatch(BackwardMatch* self, + size_t dist, size_t len, size_t len_code) { + self->distance = (uint32_t)dist; + self->length_and_code = + (uint32_t)((len << 5) | (len == len_code ? 0 : len_code)); +} + +static BROTLI_INLINE size_t BackwardMatchLength(const BackwardMatch* self) { + return self->length_and_code >> 5; +} + +static BROTLI_INLINE size_t BackwardMatchLengthCode(const BackwardMatch* self) { + size_t code = self->length_and_code & 31; + return code ? code : BackwardMatchLength(self); +} + +#define EXPAND_CAT(a, b) CAT(a, b) +#define CAT(a, b) a ## b +#define FN(X) EXPAND_CAT(X, HASHER()) + +#define HASHER() H10 +#define BUCKET_BITS 17 +#define MAX_TREE_SEARCH_DEPTH 64 +#define MAX_TREE_COMP_LENGTH 128 +#include "hash_to_binary_tree_inc.h" /* NOLINT(build/include) */ +#undef MAX_TREE_SEARCH_DEPTH +#undef MAX_TREE_COMP_LENGTH +#undef BUCKET_BITS +#undef HASHER +/* MAX_NUM_MATCHES == 64 + MAX_TREE_SEARCH_DEPTH */ +#define MAX_NUM_MATCHES_H10 128 + +/* For BUCKET_SWEEP_BITS == 0, enabling the dictionary lookup makes compression + a little faster (0.5% - 1%) and it compresses 0.15% better on small text + and HTML inputs. */ + +#define HASHER() H2 +#define BUCKET_BITS 16 +#define BUCKET_SWEEP_BITS 0 +#define HASH_LEN 5 +#define USE_DICTIONARY 1 +#include "hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */ +#undef BUCKET_SWEEP_BITS +#undef USE_DICTIONARY +#undef HASHER + +#define HASHER() H3 +#define BUCKET_SWEEP_BITS 1 +#define USE_DICTIONARY 0 +#include "hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */ +#undef USE_DICTIONARY +#undef BUCKET_SWEEP_BITS +#undef BUCKET_BITS +#undef HASHER + +#define HASHER() H4 +#define BUCKET_BITS 17 +#define BUCKET_SWEEP_BITS 2 +#define USE_DICTIONARY 1 +#include "hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */ +#undef USE_DICTIONARY +#undef HASH_LEN +#undef BUCKET_SWEEP_BITS +#undef BUCKET_BITS +#undef HASHER + +#define HASHER() H5 +#include "hash_longest_match_inc.h" /* NOLINT(build/include) */ +#undef HASHER + +#define HASHER() H6 +#include "hash_longest_match64_inc.h" /* NOLINT(build/include) */ +#undef HASHER + +#if defined(BROTLI_MAX_SIMD_QUALITY) +#define HASHER() H58 +#include "hash_longest_match_simd_inc.h" /* NOLINT(build/include) */ +#undef HASHER + +#define HASHER() H68 +#include "hash_longest_match64_simd_inc.h" /* NOLINT(build/include) */ +#undef HASHER +#endif + +#define BUCKET_BITS 15 + +#define NUM_LAST_DISTANCES_TO_CHECK 4 +#define NUM_BANKS 1 +#define BANK_BITS 16 +#define HASHER() H40 +#include "hash_forgetful_chain_inc.h" /* NOLINT(build/include) */ +#undef HASHER +#undef NUM_LAST_DISTANCES_TO_CHECK + +#define NUM_LAST_DISTANCES_TO_CHECK 10 +#define HASHER() H41 +#include "hash_forgetful_chain_inc.h" /* NOLINT(build/include) */ +#undef HASHER +#undef NUM_LAST_DISTANCES_TO_CHECK +#undef NUM_BANKS +#undef BANK_BITS + +#define NUM_LAST_DISTANCES_TO_CHECK 16 +#define NUM_BANKS 512 +#define BANK_BITS 9 +#define HASHER() H42 +#include "hash_forgetful_chain_inc.h" /* NOLINT(build/include) */ +#undef HASHER +#undef NUM_LAST_DISTANCES_TO_CHECK +#undef NUM_BANKS +#undef BANK_BITS + +#undef BUCKET_BITS + +#define HASHER() H54 +#define BUCKET_BITS 20 +#define BUCKET_SWEEP_BITS 2 +#define HASH_LEN 7 +#define USE_DICTIONARY 0 +#include "hash_longest_match_quickly_inc.h" /* NOLINT(build/include) */ +#undef USE_DICTIONARY +#undef HASH_LEN +#undef BUCKET_SWEEP_BITS +#undef BUCKET_BITS +#undef HASHER + +/* fast large window hashers */ + +#define HASHER() HROLLING_FAST +#define CHUNKLEN 32 +#define JUMP 4 +#define NUMBUCKETS 16777216 +#define MASK ((NUMBUCKETS * 64) - 1) +#include "hash_rolling_inc.h" /* NOLINT(build/include) */ +#undef JUMP +#undef HASHER + + +#define HASHER() HROLLING +#define JUMP 1 +#include "hash_rolling_inc.h" /* NOLINT(build/include) */ +#undef MASK +#undef NUMBUCKETS +#undef JUMP +#undef CHUNKLEN +#undef HASHER + +#define HASHER() H35 +#define HASHER_A H3 +#define HASHER_B HROLLING_FAST +#include "hash_composite_inc.h" /* NOLINT(build/include) */ +#undef HASHER_A +#undef HASHER_B +#undef HASHER + +#define HASHER() H55 +#define HASHER_A H54 +#define HASHER_B HROLLING_FAST +#include "hash_composite_inc.h" /* NOLINT(build/include) */ +#undef HASHER_A +#undef HASHER_B +#undef HASHER + +#define HASHER() H65 +#define HASHER_A H6 +#define HASHER_B HROLLING +#include "hash_composite_inc.h" /* NOLINT(build/include) */ +#undef HASHER_A +#undef HASHER_B +#undef HASHER + +#undef FN +#undef CAT +#undef EXPAND_CAT + +#if defined(BROTLI_MAX_SIMD_QUALITY) +#define FOR_SIMPLE_HASHERS(H) \ + H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54) H(58) H(68) +#else +#define FOR_SIMPLE_HASHERS(H) \ + H(2) H(3) H(4) H(5) H(6) H(40) H(41) H(42) H(54) +#endif +#define FOR_COMPOSITE_HASHERS(H) H(35) H(55) H(65) +#define FOR_GENERIC_HASHERS(H) FOR_SIMPLE_HASHERS(H) FOR_COMPOSITE_HASHERS(H) +#define FOR_ALL_HASHERS(H) FOR_GENERIC_HASHERS(H) H(10) + +typedef struct { + HasherCommon common; + + union { +#define MEMBER_(N) \ + H ## N _H ## N; + FOR_ALL_HASHERS(MEMBER_) +#undef MEMBER_ + } privat; +} Hasher; + +/* MUST be invoked before any other method. */ +static BROTLI_INLINE void HasherInit(Hasher* hasher) { + hasher->common.is_setup_ = BROTLI_FALSE; + hasher->common.extra[0] = NULL; + hasher->common.extra[1] = NULL; + hasher->common.extra[2] = NULL; + hasher->common.extra[3] = NULL; +} + +static BROTLI_INLINE void DestroyHasher(MemoryManager* m, Hasher* hasher) { + if (hasher->common.extra[0] != NULL) BROTLI_FREE(m, hasher->common.extra[0]); + if (hasher->common.extra[1] != NULL) BROTLI_FREE(m, hasher->common.extra[1]); + if (hasher->common.extra[2] != NULL) BROTLI_FREE(m, hasher->common.extra[2]); + if (hasher->common.extra[3] != NULL) BROTLI_FREE(m, hasher->common.extra[3]); +} + +static BROTLI_INLINE void HasherReset(Hasher* hasher) { + hasher->common.is_prepared_ = BROTLI_FALSE; +} + +static BROTLI_INLINE void HasherSize(const BrotliEncoderParams* params, + BROTLI_BOOL one_shot, const size_t input_size, size_t* alloc_size) { + switch (params->hasher.type) { +#define SIZE_(N) \ + case N: \ + HashMemAllocInBytesH ## N(params, one_shot, input_size, alloc_size); \ + break; + FOR_ALL_HASHERS(SIZE_) +#undef SIZE_ + default: + break; + } +} + +static BROTLI_INLINE void HasherSetup(MemoryManager* m, Hasher* hasher, + BrotliEncoderParams* params, const uint8_t* data, size_t position, + size_t input_size, BROTLI_BOOL is_last) { + BROTLI_BOOL one_shot = (position == 0 && is_last); + if (!hasher->common.is_setup_) { + size_t alloc_size[4] = {0}; + size_t i; + ChooseHasher(params, ¶ms->hasher); + hasher->common.params = params->hasher; + hasher->common.dict_num_lookups = 0; + hasher->common.dict_num_matches = 0; + HasherSize(params, one_shot, input_size, alloc_size); + for (i = 0; i < 4; ++i) { + if (alloc_size[i] == 0) continue; + hasher->common.extra[i] = BROTLI_ALLOC(m, uint8_t, alloc_size[i]); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(hasher->common.extra[i])) return; + } + switch (hasher->common.params.type) { +#define INITIALIZE_(N) \ + case N: \ + InitializeH ## N(&hasher->common, \ + &hasher->privat._H ## N, params); \ + break; + FOR_ALL_HASHERS(INITIALIZE_); +#undef INITIALIZE_ + default: + break; + } + HasherReset(hasher); + hasher->common.is_setup_ = BROTLI_TRUE; + } + + if (!hasher->common.is_prepared_) { + switch (hasher->common.params.type) { +#define PREPARE_(N) \ + case N: \ + PrepareH ## N( \ + &hasher->privat._H ## N, \ + one_shot, input_size, data); \ + break; + FOR_ALL_HASHERS(PREPARE_) +#undef PREPARE_ + default: break; + } + hasher->common.is_prepared_ = BROTLI_TRUE; + } +} + +static BROTLI_INLINE void InitOrStitchToPreviousBlock( + MemoryManager* m, Hasher* hasher, const uint8_t* data, size_t mask, + BrotliEncoderParams* params, size_t position, size_t input_size, + BROTLI_BOOL is_last) { + HasherSetup(m, hasher, params, data, position, input_size, is_last); + if (BROTLI_IS_OOM(m)) return; + switch (hasher->common.params.type) { +#define INIT_(N) \ + case N: \ + StitchToPreviousBlockH ## N( \ + &hasher->privat._H ## N, \ + input_size, position, data, mask); \ + break; + FOR_ALL_HASHERS(INIT_) +#undef INIT_ + default: break; + } +} + +/* NB: when seamless dictionary-ring-buffer copies are implemented, don't forget + to add proper guards for non-zero-BROTLI_PARAM_STREAM_OFFSET. */ +static BROTLI_INLINE void FindCompoundDictionaryMatch( + const PreparedDictionary* self, const uint8_t* BROTLI_RESTRICT data, + const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache, + const size_t cur_ix, const size_t max_length, const size_t distance_offset, + const size_t max_distance, HasherSearchResult* BROTLI_RESTRICT out) { + const uint32_t source_size = self->source_size; + const size_t boundary = distance_offset - source_size; + const uint32_t hash_bits = self->hash_bits; + const uint32_t bucket_bits = self->bucket_bits; + const uint32_t slot_bits = self->slot_bits; + + const uint32_t hash_shift = 64u - bucket_bits; + const uint32_t slot_mask = (~((uint32_t)0U)) >> (32 - slot_bits); + const uint64_t hash_mask = (~((uint64_t)0U)) >> (64 - hash_bits); + + const uint32_t* slot_offsets = (uint32_t*)(&self[1]); + const uint16_t* heads = (uint16_t*)(&slot_offsets[(size_t)1u << slot_bits]); + const uint32_t* items = (uint32_t*)(&heads[(size_t)1u << bucket_bits]); + const uint8_t* source = NULL; + + const size_t cur_ix_masked = cur_ix & ring_buffer_mask; + score_t best_score = out->score; + size_t best_len = out->len; + size_t i; + const uint64_t h = + (BROTLI_UNALIGNED_LOAD64LE(&data[cur_ix_masked]) & hash_mask) * + kPreparedDictionaryHashMul64Long; + const uint32_t key = (uint32_t)(h >> hash_shift); + const uint32_t slot = key & slot_mask; + const uint32_t head = heads[key]; + const uint32_t* BROTLI_RESTRICT chain = &items[slot_offsets[slot] + head]; + uint32_t item = (head == 0xFFFF) ? 1 : 0; + + const void* tail = (void*)&items[self->num_items]; + if (self->magic == kPreparedDictionaryMagic) { + source = (const uint8_t*)tail; + } else { + /* kLeanPreparedDictionaryMagic */ + source = (const uint8_t*)BROTLI_UNALIGNED_LOAD_PTR((const uint8_t**)tail); + } + + BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask); + + for (i = 0; i < 4; ++i) { + const size_t distance = (size_t)distance_cache[i]; + size_t offset; + size_t limit; + size_t len; + if (distance <= boundary || distance > distance_offset) continue; + offset = distance_offset - distance; + limit = source_size - offset; + limit = limit > max_length ? max_length : limit; + len = FindMatchLengthWithLimit(&source[offset], &data[cur_ix_masked], + limit); + if (len >= 2) { + score_t score = BackwardReferenceScoreUsingLastDistance(len); + if (best_score < score) { + if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i); + if (best_score < score) { + best_score = score; + if (len > best_len) best_len = len; + out->len = len; + out->len_code_delta = 0; + out->distance = distance; + out->score = best_score; + } + } + } + } + /* we require matches of len >4, so increase best_len to 3, so we can compare + * 4 bytes all the time. */ + if (best_len < 3) { + best_len = 3; + } + while (item == 0) { + size_t offset; + size_t distance; + size_t limit; + item = *chain; + chain++; + offset = item & 0x7FFFFFFF; + item &= 0x80000000; + distance = distance_offset - offset; + limit = source_size - offset; + limit = (limit > max_length) ? max_length : limit; + if (distance > max_distance) continue; + if (cur_ix_masked + best_len > ring_buffer_mask || best_len >= limit || + /* compare 4 bytes ending at best_len + 1 */ + BrotliUnalignedRead32(&data[cur_ix_masked + best_len - 3]) != + BrotliUnalignedRead32(&source[offset + best_len - 3])) { + continue; + } + { + const size_t len = FindMatchLengthWithLimit(&source[offset], + &data[cur_ix_masked], + limit); + if (len >= 4) { + score_t score = BackwardReferenceScore(len, distance); + if (best_score < score) { + best_score = score; + best_len = len; + out->len = best_len; + out->len_code_delta = 0; + out->distance = distance; + out->score = best_score; + } + } + } + } +} + +/* NB: when seamless dictionary-ring-buffer copies are implemented, don't forget + to add proper guards for non-zero-BROTLI_PARAM_STREAM_OFFSET. */ +static BROTLI_INLINE size_t FindAllCompoundDictionaryMatches( + const PreparedDictionary* self, const uint8_t* BROTLI_RESTRICT data, + const size_t ring_buffer_mask, const size_t cur_ix, const size_t min_length, + const size_t max_length, const size_t distance_offset, + const size_t max_distance, BackwardMatch* matches, size_t match_limit) { + const uint32_t source_size = self->source_size; + const uint32_t hash_bits = self->hash_bits; + const uint32_t bucket_bits = self->bucket_bits; + const uint32_t slot_bits = self->slot_bits; + + const uint32_t hash_shift = 64u - bucket_bits; + const uint32_t slot_mask = (~((uint32_t)0U)) >> (32 - slot_bits); + const uint64_t hash_mask = (~((uint64_t)0U)) >> (64 - hash_bits); + + const uint32_t* slot_offsets = (uint32_t*)(&self[1]); + const uint16_t* heads = (uint16_t*)(&slot_offsets[(size_t)1u << slot_bits]); + const uint32_t* items = (uint32_t*)(&heads[(size_t)1u << bucket_bits]); + const uint8_t* source = NULL; + + const size_t cur_ix_masked = cur_ix & ring_buffer_mask; + size_t best_len = min_length; + const uint64_t h = + (BROTLI_UNALIGNED_LOAD64LE(&data[cur_ix_masked]) & hash_mask) * + kPreparedDictionaryHashMul64Long; + const uint32_t key = (uint32_t)(h >> hash_shift); + const uint32_t slot = key & slot_mask; + const uint32_t head = heads[key]; + const uint32_t* BROTLI_RESTRICT chain = &items[slot_offsets[slot] + head]; + uint32_t item = (head == 0xFFFF) ? 1 : 0; + size_t found = 0; + + const void* tail = (void*)&items[self->num_items]; + if (self->magic == kPreparedDictionaryMagic) { + source = (const uint8_t*)tail; + } else { + /* kLeanPreparedDictionaryMagic */ + source = (const uint8_t*)BROTLI_UNALIGNED_LOAD_PTR((const uint8_t**)tail); + } + + BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask); + + while (item == 0) { + size_t offset; + size_t distance; + size_t limit; + size_t len; + item = *chain; + chain++; + offset = item & 0x7FFFFFFF; + item &= 0x80000000; + distance = distance_offset - offset; + limit = source_size - offset; + limit = (limit > max_length) ? max_length : limit; + if (distance > max_distance) continue; + if (cur_ix_masked + best_len > ring_buffer_mask || + best_len >= limit || + data[cur_ix_masked + best_len] != source[offset + best_len]) { + continue; + } + len = FindMatchLengthWithLimit( + &source[offset], &data[cur_ix_masked], limit); + if (len > best_len) { + best_len = len; + InitBackwardMatch(matches++, distance, len); + found++; + if (found == match_limit) break; + } + } + return found; +} + +static BROTLI_INLINE void LookupCompoundDictionaryMatch( + const CompoundDictionary* addon, const uint8_t* BROTLI_RESTRICT data, + const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache, + const size_t cur_ix, const size_t max_length, + const size_t max_ring_buffer_distance, const size_t max_distance, + HasherSearchResult* sr) { + size_t base_offset = max_ring_buffer_distance + 1 + addon->total_size - 1; + size_t d; + for (d = 0; d < addon->num_chunks; ++d) { + /* Only one prepared dictionary type is currently supported. */ + FindCompoundDictionaryMatch( + (const PreparedDictionary*)addon->chunks[d], data, ring_buffer_mask, + distance_cache, cur_ix, max_length, + base_offset - addon->chunk_offsets[d], max_distance, sr); + } +} + +static BROTLI_INLINE size_t LookupAllCompoundDictionaryMatches( + const CompoundDictionary* addon, const uint8_t* BROTLI_RESTRICT data, + const size_t ring_buffer_mask, const size_t cur_ix, size_t min_length, + const size_t max_length, const size_t max_ring_buffer_distance, + const size_t max_distance, BackwardMatch* matches, + size_t match_limit) { + size_t base_offset = max_ring_buffer_distance + 1 + addon->total_size - 1; + size_t d; + size_t total_found = 0; + for (d = 0; d < addon->num_chunks; ++d) { + /* Only one prepared dictionary type is currently supported. */ + total_found += FindAllCompoundDictionaryMatches( + (const PreparedDictionary*)addon->chunks[d], data, ring_buffer_mask, + cur_ix, min_length, max_length, base_offset - addon->chunk_offsets[d], + max_distance, matches + total_found, match_limit - total_found); + if (total_found == match_limit) break; + if (total_found > 0) { + min_length = BackwardMatchLength(&matches[total_found - 1]); + } + } + return total_found; +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_HASH_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/hash_base.h b/packages/runtime/vendor/brotli/c/enc/hash_base.h new file mode 100644 index 000000000..edf1ef020 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/hash_base.h @@ -0,0 +1,38 @@ +/* Copyright 2025 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Basic common hash functions / constants. */ + +#ifndef THIRD_PARTY_BROTLI_ENC_HASH_BASE_H_ +#define THIRD_PARTY_BROTLI_ENC_HASH_BASE_H_ + +#include "../common/platform.h" + +/* kHashMul32 multiplier has these properties: + * The multiplier must be odd. Otherwise we may lose the highest bit. + * No long streaks of ones or zeros. + * There is no effort to ensure that it is a prime, the oddity is enough + for this use. + * The number has been tuned heuristically against compression benchmarks. */ +static const uint32_t kHashMul32 = 0x1E35A7BD; +static const uint64_t kHashMul64 = + BROTLI_MAKE_UINT64_T(0x1FE35A7Bu, 0xD3579BD3u); + +static BROTLI_INLINE uint32_t Hash14(const uint8_t* data) { + uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32; + /* The higher bits contain more mixture from the multiplication, + so we take our results from there. */ + return h >> (32 - 14); +} + +static BROTLI_INLINE uint32_t Hash15(const uint8_t* data) { + uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32; + /* The higher bits contain more mixture from the multiplication, + so we take our results from there. */ + return h >> (32 - 15); +} + +#endif // THIRD_PARTY_BROTLI_ENC_HASH_BASE_H_ diff --git a/packages/runtime/vendor/brotli/c/enc/hash_composite_inc.h b/packages/runtime/vendor/brotli/c/enc/hash_composite_inc.h new file mode 100644 index 000000000..3923bc72c --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/hash_composite_inc.h @@ -0,0 +1,140 @@ +/* NOLINT(build/header_guard) */ +/* Copyright 2018 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* template parameters: FN, HASHER_A, HASHER_B */ + +/* Composite hasher: This hasher allows to combine two other hashers, HASHER_A + and HASHER_B. */ + +#define HashComposite HASHER() + +#define FN_A(X) EXPAND_CAT(X, HASHER_A) +#define FN_B(X) EXPAND_CAT(X, HASHER_B) + +static BROTLI_INLINE size_t FN(HashTypeLength)(void) { + size_t a = FN_A(HashTypeLength)(); + size_t b = FN_B(HashTypeLength)(); + return a > b ? a : b; +} + +static BROTLI_INLINE size_t FN(StoreLookahead)(void) { + size_t a = FN_A(StoreLookahead)(); + size_t b = FN_B(StoreLookahead)(); + return a > b ? a : b; +} + +typedef struct HashComposite { + HASHER_A ha; + HASHER_B hb; + HasherCommon ha_common; + HasherCommon hb_common; + + /* Shortcuts. */ + HasherCommon* common; + + BROTLI_BOOL fresh; + const BrotliEncoderParams* params; +} HashComposite; + +static void FN(Initialize)(HasherCommon* common, + HashComposite* BROTLI_RESTRICT self, const BrotliEncoderParams* params) { + self->common = common; + + self->ha_common = *self->common; + self->hb_common = *self->common; + self->fresh = BROTLI_TRUE; + self->params = params; + /* TODO(lode): Initialize of the hashers is deferred to Prepare (and params + remembered here) because we don't get the one_shot and input_size params + here that are needed to know the memory size of them. Instead provide + those params to all hashers FN(Initialize) */ +} + +static void FN(Prepare)( + HashComposite* BROTLI_RESTRICT self, BROTLI_BOOL one_shot, + size_t input_size, const uint8_t* BROTLI_RESTRICT data) { + if (self->fresh) { + self->fresh = BROTLI_FALSE; + self->ha_common.extra[0] = self->common->extra[0]; + self->ha_common.extra[1] = self->common->extra[1]; + self->ha_common.extra[2] = NULL; + self->ha_common.extra[3] = NULL; + self->hb_common.extra[0] = self->common->extra[2]; + self->hb_common.extra[1] = self->common->extra[3]; + self->hb_common.extra[2] = NULL; + self->hb_common.extra[3] = NULL; + + FN_A(Initialize)(&self->ha_common, &self->ha, self->params); + FN_B(Initialize)(&self->hb_common, &self->hb, self->params); + } + FN_A(Prepare)(&self->ha, one_shot, input_size, data); + FN_B(Prepare)(&self->hb, one_shot, input_size, data); +} + +static BROTLI_INLINE void FN(HashMemAllocInBytes)( + const BrotliEncoderParams* params, BROTLI_BOOL one_shot, + size_t input_size, size_t* alloc_size) { + size_t alloc_size_a[4] = {0}; + size_t alloc_size_b[4] = {0}; + FN_A(HashMemAllocInBytes)(params, one_shot, input_size, alloc_size_a); + FN_B(HashMemAllocInBytes)(params, one_shot, input_size, alloc_size_b); + /* Should never happen. */ + if (alloc_size_a[2] != 0 || alloc_size_a[3] != 0) exit(EXIT_FAILURE); + if (alloc_size_b[2] != 0 || alloc_size_b[3] != 0) exit(EXIT_FAILURE); + alloc_size[0] = alloc_size_a[0]; + alloc_size[1] = alloc_size_a[1]; + alloc_size[2] = alloc_size_b[0]; + alloc_size[3] = alloc_size_b[1]; +} + +static BROTLI_INLINE void FN(Store)(HashComposite* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) { + FN_A(Store)(&self->ha, data, mask, ix); + FN_B(Store)(&self->hb, data, mask, ix); +} + +static BROTLI_INLINE void FN(StoreRange)( + HashComposite* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data, + const size_t mask, const size_t ix_start, + const size_t ix_end) { + FN_A(StoreRange)(&self->ha, data, mask, ix_start, ix_end); + FN_B(StoreRange)(&self->hb, data, mask, ix_start, ix_end); +} + +static BROTLI_INLINE void FN(StitchToPreviousBlock)( + HashComposite* BROTLI_RESTRICT self, + size_t num_bytes, size_t position, const uint8_t* ringbuffer, + size_t ring_buffer_mask) { + FN_A(StitchToPreviousBlock)(&self->ha, num_bytes, position, + ringbuffer, ring_buffer_mask); + FN_B(StitchToPreviousBlock)(&self->hb, num_bytes, position, + ringbuffer, ring_buffer_mask); +} + +static BROTLI_INLINE void FN(PrepareDistanceCache)( + HashComposite* BROTLI_RESTRICT self, int* BROTLI_RESTRICT distance_cache) { + FN_A(PrepareDistanceCache)(&self->ha, distance_cache); + FN_B(PrepareDistanceCache)(&self->hb, distance_cache); +} + +static BROTLI_INLINE void FN(FindLongestMatch)( + HashComposite* BROTLI_RESTRICT self, + const BrotliEncoderDictionary* dictionary, + const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask, + const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix, + const size_t max_length, const size_t max_backward, + const size_t dictionary_distance, const size_t max_distance, + HasherSearchResult* BROTLI_RESTRICT out) { + FN_A(FindLongestMatch)(&self->ha, dictionary, data, ring_buffer_mask, + distance_cache, cur_ix, max_length, max_backward, dictionary_distance, + max_distance, out); + FN_B(FindLongestMatch)(&self->hb, dictionary, data, ring_buffer_mask, + distance_cache, cur_ix, max_length, max_backward, dictionary_distance, + max_distance, out); +} + +#undef HashComposite diff --git a/packages/runtime/vendor/brotli/c/enc/hash_forgetful_chain_inc.h b/packages/runtime/vendor/brotli/c/enc/hash_forgetful_chain_inc.h new file mode 100644 index 000000000..c44276fa4 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/hash_forgetful_chain_inc.h @@ -0,0 +1,305 @@ +/* NOLINT(build/header_guard) */ +/* Copyright 2016 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* template parameters: FN, BUCKET_BITS, NUM_BANKS, BANK_BITS, + NUM_LAST_DISTANCES_TO_CHECK */ + +/* A (forgetful) hash table to the data seen by the compressor, to + help create backward references to previous data. + + Hashes are stored in chains which are bucketed to groups. Group of chains + share a storage "bank". When more than "bank size" chain nodes are added, + oldest nodes are replaced; this way several chains may share a tail. */ + +#define HashForgetfulChain HASHER() + +#define BANK_SIZE (1 << BANK_BITS) + +/* Number of hash buckets. */ +#define BUCKET_SIZE (1 << BUCKET_BITS) + +#define CAPPED_CHAINS 0 + +static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; } +static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; } + +/* HashBytes is the function that chooses the bucket to place the address in.*/ +static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data) { + const uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32; + /* The higher bits contain more mixture from the multiplication, + so we take our results from there. */ + return h >> (32 - BUCKET_BITS); +} + +typedef struct FN(Slot) { + uint16_t delta; + uint16_t next; +} FN(Slot); + +typedef struct FN(Bank) { + FN(Slot) slots[BANK_SIZE]; +} FN(Bank); + +typedef struct HashForgetfulChain { + uint16_t free_slot_idx[NUM_BANKS]; /* Up to 1KiB. Move to dynamic? */ + size_t max_hops; + + /* Shortcuts. */ + void* extra[2]; + HasherCommon* common; + + /* --- Dynamic size members --- */ + + /* uint32_t addr[BUCKET_SIZE]; */ + + /* uint16_t head[BUCKET_SIZE]; */ + + /* Truncated hash used for quick rejection of "distance cache" candidates. */ + /* uint8_t tiny_hash[65536];*/ + + /* FN(Bank) banks[NUM_BANKS]; */ +} HashForgetfulChain; + +static uint32_t* FN(Addr)(void* extra) { + return (uint32_t*)extra; +} + +static uint16_t* FN(Head)(void* extra) { + return (uint16_t*)(&FN(Addr)(extra)[BUCKET_SIZE]); +} + +static uint8_t* FN(TinyHash)(void* extra) { + return (uint8_t*)(&FN(Head)(extra)[BUCKET_SIZE]); +} + +static FN(Bank)* FN(Banks)(void* extra) { + return (FN(Bank)*)(extra); +} + +static void FN(Initialize)( + HasherCommon* common, HashForgetfulChain* BROTLI_RESTRICT self, + const BrotliEncoderParams* params) { + self->common = common; + self->extra[0] = common->extra[0]; + self->extra[1] = common->extra[1]; + + self->max_hops = (params->quality > 6 ? 7u : 8u) << (params->quality - 4); +} + +static void FN(Prepare)( + HashForgetfulChain* BROTLI_RESTRICT self, BROTLI_BOOL one_shot, + size_t input_size, const uint8_t* BROTLI_RESTRICT data) { + uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra[0]); + uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra[0]); + uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra[0]); + /* Partial preparation is 100 times slower (per socket). */ + size_t partial_prepare_threshold = BUCKET_SIZE >> 6; + if (one_shot && input_size <= partial_prepare_threshold) { + size_t i; + for (i = 0; i < input_size; ++i) { + size_t bucket = FN(HashBytes)(&data[i]); + /* See InitEmpty comment. */ + addr[bucket] = 0xCCCCCCCC; + head[bucket] = 0xCCCC; + } + } else { + /* Fill |addr| array with 0xCCCCCCCC value. Because of wrapping, position + processed by hasher never reaches 3GB + 64M; this makes all new chains + to be terminated after the first node. */ + memset(addr, 0xCC, sizeof(uint32_t) * BUCKET_SIZE); + memset(head, 0, sizeof(uint16_t) * BUCKET_SIZE); + } + memset(tiny_hash, 0, sizeof(uint8_t) * 65536); + memset(self->free_slot_idx, 0, sizeof(self->free_slot_idx)); +} + +static BROTLI_INLINE void FN(HashMemAllocInBytes)( + const BrotliEncoderParams* params, BROTLI_BOOL one_shot, + size_t input_size, size_t* alloc_size) { + BROTLI_UNUSED(params); + BROTLI_UNUSED(one_shot); + BROTLI_UNUSED(input_size); + alloc_size[0] = sizeof(uint32_t) * BUCKET_SIZE + + sizeof(uint16_t) * BUCKET_SIZE + sizeof(uint8_t) * 65536; + alloc_size[1] = sizeof(FN(Bank)) * NUM_BANKS; +} + +/* Look at 4 bytes at &data[ix & mask]. Compute a hash from these, and prepend + node to corresponding chain; also update tiny_hash for current position. */ +static BROTLI_INLINE void FN(Store)(HashForgetfulChain* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) { + uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra[0]); + uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra[0]); + uint8_t* BROTLI_RESTRICT tiny_hash = FN(TinyHash)(self->extra[0]); + FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra[1]); + const size_t key = FN(HashBytes)(&data[ix & mask]); + const size_t bank = key & (NUM_BANKS - 1); + const size_t idx = self->free_slot_idx[bank]++ & (BANK_SIZE - 1); + size_t delta = ix - addr[key]; + tiny_hash[(uint16_t)ix] = (uint8_t)key; + if (delta > 0xFFFF) delta = CAPPED_CHAINS ? 0 : 0xFFFF; + banks[bank].slots[idx].delta = (uint16_t)delta; + banks[bank].slots[idx].next = head[key]; + addr[key] = (uint32_t)ix; + head[key] = (uint16_t)idx; +} + +static BROTLI_INLINE void FN(StoreRange)( + HashForgetfulChain* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, + const size_t ix_start, const size_t ix_end) { + size_t i; + for (i = ix_start; i < ix_end; ++i) { + FN(Store)(self, data, mask, i); + } +} + +static BROTLI_INLINE void FN(StitchToPreviousBlock)( + HashForgetfulChain* BROTLI_RESTRICT self, + size_t num_bytes, size_t position, const uint8_t* ringbuffer, + size_t ring_buffer_mask) { + if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) { + /* Prepare the hashes for three last bytes of the last write. + These could not be calculated before, since they require knowledge + of both the previous and the current block. */ + FN(Store)(self, ringbuffer, ring_buffer_mask, position - 3); + FN(Store)(self, ringbuffer, ring_buffer_mask, position - 2); + FN(Store)(self, ringbuffer, ring_buffer_mask, position - 1); + } +} + +static BROTLI_INLINE void FN(PrepareDistanceCache)( + HashForgetfulChain* BROTLI_RESTRICT self, + int* BROTLI_RESTRICT distance_cache) { + BROTLI_UNUSED(self); + PrepareDistanceCache(distance_cache, NUM_LAST_DISTANCES_TO_CHECK); +} + +/* Find a longest backward match of &data[cur_ix] up to the length of + max_length and stores the position cur_ix in the hash table. + + REQUIRES: FN(PrepareDistanceCache) must be invoked for current distance cache + values; if this method is invoked repeatedly with the same distance + cache values, it is enough to invoke FN(PrepareDistanceCache) once. + + Does not look for matches longer than max_length. + Does not look for matches further away than max_backward. + Writes the best match into |out|. + |out|->score is updated only if a better match is found. */ +static BROTLI_INLINE void FN(FindLongestMatch)( + HashForgetfulChain* BROTLI_RESTRICT self, + const BrotliEncoderDictionary* dictionary, + const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask, + const int* BROTLI_RESTRICT distance_cache, + const size_t cur_ix, const size_t max_length, const size_t max_backward, + const size_t dictionary_distance, const size_t max_distance, + HasherSearchResult* BROTLI_RESTRICT out) { + uint32_t* BROTLI_RESTRICT addr = FN(Addr)(self->extra[0]); + uint16_t* BROTLI_RESTRICT head = FN(Head)(self->extra[0]); + uint8_t* BROTLI_RESTRICT tiny_hashes = FN(TinyHash)(self->extra[0]); + FN(Bank)* BROTLI_RESTRICT banks = FN(Banks)(self->extra[1]); + const size_t cur_ix_masked = cur_ix & ring_buffer_mask; + /* Don't accept a short copy from far away. */ + score_t min_score = out->score; + score_t best_score = out->score; + size_t best_len = out->len; + size_t i; + const size_t key = FN(HashBytes)(&data[cur_ix_masked]); + const uint8_t tiny_hash = (uint8_t)(key); + out->len = 0; + out->len_code_delta = 0; + + BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask); + + /* Try last distance first. */ + for (i = 0; i < NUM_LAST_DISTANCES_TO_CHECK; ++i) { + const size_t backward = (size_t)distance_cache[i]; + size_t prev_ix = (cur_ix - backward); + /* For distance code 0 we want to consider 2-byte matches. */ + if (i > 0 && tiny_hashes[(uint16_t)prev_ix] != tiny_hash) continue; + if (prev_ix >= cur_ix || backward > max_backward) { + continue; + } + prev_ix &= ring_buffer_mask; + { + const size_t len = FindMatchLengthWithLimit(&data[prev_ix], + &data[cur_ix_masked], + max_length); + if (len >= 2) { + score_t score = BackwardReferenceScoreUsingLastDistance(len); + if (best_score < score) { + if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i); + if (best_score < score) { + best_score = score; + best_len = len; + out->len = best_len; + out->distance = backward; + out->score = best_score; + } + } + } + } + } + /* we require matches of len >4, so increase best_len to 3, so we can compare + * 4 bytes all the time. */ + if (best_len < 3) { + best_len = 3; + } + { + const size_t bank = key & (NUM_BANKS - 1); + size_t backward = 0; + size_t hops = self->max_hops; + size_t delta = cur_ix - addr[key]; + size_t slot = head[key]; + while (hops--) { + size_t prev_ix; + size_t last = slot; + backward += delta; + if (backward > max_backward || (CAPPED_CHAINS && !delta)) break; + prev_ix = (cur_ix - backward) & ring_buffer_mask; + slot = banks[bank].slots[last].next; + delta = banks[bank].slots[last].delta; + if (cur_ix_masked + best_len > ring_buffer_mask || + prev_ix + best_len > ring_buffer_mask || + /* compare 4 bytes ending at best_len + 1 */ + BrotliUnalignedRead32(&data[cur_ix_masked + best_len - 3]) != + BrotliUnalignedRead32(&data[prev_ix + best_len - 3])) { + continue; + } + { + const size_t len = FindMatchLengthWithLimit(&data[prev_ix], + &data[cur_ix_masked], + max_length); + if (len >= 4) { + /* Comparing for >= 3 does not change the semantics, but just saves + for a few unnecessary binary logarithms in backward reference + score, since we are not interested in such short matches. */ + score_t score = BackwardReferenceScore(len, backward); + if (best_score < score) { + best_score = score; + best_len = len; + out->len = best_len; + out->distance = backward; + out->score = best_score; + } + } + } + } + FN(Store)(self, data, ring_buffer_mask, cur_ix); + } + if (out->score == min_score) { + SearchInStaticDictionary(dictionary, + self->common, &data[cur_ix_masked], max_length, dictionary_distance, + max_distance, out, BROTLI_FALSE); + } +} + +#undef BANK_SIZE +#undef BUCKET_SIZE +#undef CAPPED_CHAINS + +#undef HashForgetfulChain diff --git a/packages/runtime/vendor/brotli/c/enc/hash_longest_match64_inc.h b/packages/runtime/vendor/brotli/c/enc/hash_longest_match64_inc.h new file mode 100644 index 000000000..bdbb30aa5 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/hash_longest_match64_inc.h @@ -0,0 +1,279 @@ +/* NOLINT(build/header_guard) */ +/* Copyright 2010 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* template parameters: FN */ + +/* A (forgetful) hash table to the data seen by the compressor, to + help create backward references to previous data. + + This is a hash map of fixed size (bucket_size_) to a ring buffer of + fixed size (block_size_). The ring buffer contains the last block_size_ + index positions of the given hash key in the compressed data. */ + +#define HashLongestMatch HASHER() + +static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; } +static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; } + +/* HashBytes is the function that chooses the bucket to place the address in. */ +static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data, + uint64_t hash_mul) { + const uint64_t h = BROTLI_UNALIGNED_LOAD64LE(data) * hash_mul; + /* The higher bits contain more mixture from the multiplication, + so we take our results from there. */ + return (size_t)(h >> (64 - 15)); +} + +typedef struct HashLongestMatch { + /* Number of hash buckets. */ + size_t bucket_size_; + /* Only block_size_ newest backward references are kept, + and the older are forgotten. */ + size_t block_size_; + /* Hash multiplier tuned to match length. */ + uint64_t hash_mul_; + /* Mask for accessing entries in a block (in a ring-buffer manner). */ + uint32_t block_mask_; + + int block_bits_; + int num_last_distances_to_check_; + + /* Shortcuts. */ + HasherCommon* common_; + + /* --- Dynamic size members --- */ + + /* Number of entries in a particular bucket. */ + uint16_t* num_; /* uint16_t[bucket_size]; */ + + /* Buckets containing block_size_ of backward references. */ + uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */ +} HashLongestMatch; + +static void FN(Initialize)( + HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self, + const BrotliEncoderParams* params) { + self->common_ = common; + + BROTLI_UNUSED(params); + self->hash_mul_ = kHashMul64 << (64 - 5 * 8); + BROTLI_DCHECK(common->params.bucket_bits == 15); + self->bucket_size_ = (size_t)1 << common->params.bucket_bits; + self->block_bits_ = common->params.block_bits; + self->block_size_ = (size_t)1 << common->params.block_bits; + self->block_mask_ = (uint32_t)(self->block_size_ - 1); + self->num_last_distances_to_check_ = + common->params.num_last_distances_to_check; + self->num_ = (uint16_t*)common->extra[0]; + self->buckets_ = (uint32_t*)common->extra[1]; +} + +static void FN(Prepare)( + HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot, + size_t input_size, const uint8_t* BROTLI_RESTRICT data) { + uint16_t* BROTLI_RESTRICT num = self->num_; + /* Partial preparation is 100 times slower (per socket). */ + size_t partial_prepare_threshold = self->bucket_size_ >> 6; + if (one_shot && input_size <= partial_prepare_threshold) { + size_t i; + for (i = 0; i < input_size; ++i) { + const size_t key = FN(HashBytes)(&data[i], self->hash_mul_); + num[key] = 0; + } + } else { + memset(num, 0, self->bucket_size_ * sizeof(num[0])); + } +} + +static BROTLI_INLINE void FN(HashMemAllocInBytes)( + const BrotliEncoderParams* params, BROTLI_BOOL one_shot, + size_t input_size, size_t* alloc_size) { + size_t bucket_size = (size_t)1 << params->hasher.bucket_bits; + size_t block_size = (size_t)1 << params->hasher.block_bits; + BROTLI_UNUSED(one_shot); + BROTLI_UNUSED(input_size); + alloc_size[0] = sizeof(uint16_t) * bucket_size; + alloc_size[1] = sizeof(uint32_t) * bucket_size * block_size; +} + +/* Look at 4 bytes at &data[ix & mask]. + Compute a hash from these, and store the value of ix at that position. */ +static BROTLI_INLINE void FN(Store)( + HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data, + const size_t mask, const size_t ix) { + uint16_t* BROTLI_RESTRICT num = self->num_; + uint32_t* BROTLI_RESTRICT buckets = self->buckets_; + const size_t key = FN(HashBytes)(&data[ix & mask], self->hash_mul_); + const size_t minor_ix = num[key] & self->block_mask_; + const size_t offset = minor_ix + (key << self->block_bits_); + ++num[key]; + buckets[offset] = (uint32_t)ix; +} + +static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, + const size_t ix_start, const size_t ix_end) { + size_t i; + for (i = ix_start; i < ix_end; ++i) { + FN(Store)(self, data, mask, i); + } +} + +static BROTLI_INLINE void FN(StitchToPreviousBlock)( + HashLongestMatch* BROTLI_RESTRICT self, + size_t num_bytes, size_t position, const uint8_t* ringbuffer, + size_t ringbuffer_mask) { + if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) { + /* Prepare the hashes for three last bytes of the last write. + These could not be calculated before, since they require knowledge + of both the previous and the current block. */ + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3); + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2); + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1); + } +} + +static BROTLI_INLINE void FN(PrepareDistanceCache)( + HashLongestMatch* BROTLI_RESTRICT self, + int* BROTLI_RESTRICT distance_cache) { + PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_); +} + +/* Find a longest backward match of &data[cur_ix] up to the length of + max_length and stores the position cur_ix in the hash table. + + REQUIRES: FN(PrepareDistanceCache) must be invoked for current distance cache + values; if this method is invoked repeatedly with the same distance + cache values, it is enough to invoke FN(PrepareDistanceCache) once. + + Does not look for matches longer than max_length. + Does not look for matches further away than max_backward. + Writes the best match into |out|. + |out|->score is updated only if a better match is found. */ +static BROTLI_INLINE void FN(FindLongestMatch)( + HashLongestMatch* BROTLI_RESTRICT self, + const BrotliEncoderDictionary* dictionary, + const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask, + const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix, + const size_t max_length, const size_t max_backward, + const size_t dictionary_distance, const size_t max_distance, + HasherSearchResult* BROTLI_RESTRICT out) { + uint16_t* BROTLI_RESTRICT num = self->num_; + uint32_t* BROTLI_RESTRICT buckets = self->buckets_; + const size_t cur_ix_masked = cur_ix & ring_buffer_mask; + /* Don't accept a short copy from far away. */ + score_t min_score = out->score; + score_t best_score = out->score; + size_t best_len = out->len; + size_t i; + /* Precalculate the hash key and prefetch the bucket. */ + const size_t key = FN(HashBytes)(&data[cur_ix_masked], self->hash_mul_); + uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_]; + PREFETCH_L1(bucket); + if (self->block_bits_ > 4) PREFETCH_L1(bucket + 16); + out->len = 0; + out->len_code_delta = 0; + + BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask); + + /* Try last distance first. */ + for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) { + const size_t backward = (size_t)distance_cache[i]; + size_t prev_ix = (size_t)(cur_ix - backward); + if (prev_ix >= cur_ix) { + continue; + } + if (BROTLI_PREDICT_FALSE(backward > max_backward)) { + continue; + } + prev_ix &= ring_buffer_mask; + + if (cur_ix_masked + best_len > ring_buffer_mask) { + break; + } + if (prev_ix + best_len > ring_buffer_mask || + data[cur_ix_masked + best_len] != data[prev_ix + best_len]) { + continue; + } + { + const size_t len = FindMatchLengthWithLimit(&data[prev_ix], + &data[cur_ix_masked], + max_length); + if (len >= 3 || (len == 2 && i < 2)) { + /* Comparing for >= 2 does not change the semantics, but just saves for + a few unnecessary binary logarithms in backward reference score, + since we are not interested in such short matches. */ + score_t score = BackwardReferenceScoreUsingLastDistance(len); + if (best_score < score) { + if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i); + if (best_score < score) { + best_score = score; + best_len = len; + out->len = best_len; + out->distance = backward; + out->score = best_score; + } + } + } + } + } + /* we require matches of len >4, so increase best_len to 3, so we can compare + * 4 bytes all the time. */ + if (best_len < 3) { + best_len = 3; + } + { + const size_t down = + (num[key] > self->block_size_) ? + (num[key] - self->block_size_) : 0u; + const uint32_t first4 = BrotliUnalignedRead32(data + cur_ix_masked); + const size_t max_length_m4 = max_length - 4; + i = num[key]; + for (; i > down;) { + size_t prev_ix = bucket[--i & self->block_mask_]; + uint32_t current4; + const size_t backward = cur_ix - prev_ix; + if (BROTLI_PREDICT_FALSE(backward > max_backward)) { + break; + } + prev_ix &= ring_buffer_mask; + if (cur_ix_masked + best_len > ring_buffer_mask) { + break; + } + if (prev_ix + best_len > ring_buffer_mask || + /* compare 4 bytes ending at best_len + 1 */ + BrotliUnalignedRead32(&data[cur_ix_masked + best_len - 3]) != + BrotliUnalignedRead32(&data[prev_ix + best_len - 3])) { + continue; + } + current4 = BrotliUnalignedRead32(data + prev_ix); + if (first4 != current4) continue; + { + const size_t len = FindMatchLengthWithLimit(&data[prev_ix + 4], + &data[cur_ix_masked + 4], + max_length_m4) + 4; + const score_t score = BackwardReferenceScore(len, backward); + if (best_score < score) { + best_score = score; + best_len = len; + out->len = best_len; + out->distance = backward; + out->score = best_score; + } + } + } + bucket[num[key] & self->block_mask_] = (uint32_t)cur_ix; + ++num[key]; + } + if (min_score == out->score) { + SearchInStaticDictionary(dictionary, + self->common_, &data[cur_ix_masked], max_length, dictionary_distance, + max_distance, out, BROTLI_FALSE); + } +} + +#undef HashLongestMatch diff --git a/packages/runtime/vendor/brotli/c/enc/hash_longest_match64_simd_inc.h b/packages/runtime/vendor/brotli/c/enc/hash_longest_match64_simd_inc.h new file mode 100644 index 000000000..12bd8cffd --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/hash_longest_match64_simd_inc.h @@ -0,0 +1,304 @@ +/* NOLINT(build/header_guard) */ +/* Copyright 2010 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* template parameters: FN */ + +/* A (forgetful) hash table to the data seen by the compressor, to + help create backward references to previous data. + + This is a hash map of fixed size (bucket_size_) to a ring buffer of + fixed size (block_size_). The ring buffer contains the last block_size_ + index positions of the given hash key in the compressed data. */ + +#define HashLongestMatch HASHER() + +#define TAG_HASH_BITS 8 +#define TAG_HASH_MASK ((1 << TAG_HASH_BITS) - 1) + +static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; } +static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; } + +/* HashBytes is the function that chooses the bucket to place the address in. */ +static BROTLI_INLINE size_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data, + uint64_t hash_mul) { + const uint64_t h = BROTLI_UNALIGNED_LOAD64LE(data) * hash_mul; + /* The higher bits contain more mixture from the multiplication, + so we take our results from there. */ + return (size_t)(h >> (64 - 15 - TAG_HASH_BITS)); +} + +typedef struct HashLongestMatch { + /* Number of hash buckets. */ + size_t bucket_size_; + /* Only block_size_ newest backward references are kept, + and the older are forgotten. */ + size_t block_size_; + /* Hash multiplier tuned to match length. */ + uint64_t hash_mul_; + /* Mask for accessing entries in a block (in a ring-buffer manner). */ + uint32_t block_mask_; + + int block_bits_; + int num_last_distances_to_check_; + + /* Shortcuts. */ + HasherCommon* common_; + + /* --- Dynamic size members --- */ + + /* Number of entries in a particular bucket. */ + uint16_t* num_; /* uint16_t[bucket_size]; */ + + uint8_t* tags_; + + /* Buckets containing block_size_ of backward references. */ + uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */ +} HashLongestMatch; + +static void FN(Initialize)( + HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self, + const BrotliEncoderParams* params) { + self->common_ = common; + + BROTLI_UNUSED(params); + self->hash_mul_ = kHashMul64 << (64 - 5 * 8); + BROTLI_DCHECK(common->params.bucket_bits == 15); + self->bucket_size_ = (size_t)1 << common->params.bucket_bits; + self->block_bits_ = common->params.block_bits; + self->block_size_ = (size_t)1 << common->params.block_bits; + self->block_mask_ = (uint32_t)(self->block_size_ - 1); + self->num_last_distances_to_check_ = + common->params.num_last_distances_to_check; + self->num_ = (uint16_t*)common->extra[0]; + self->tags_ = (uint8_t*)common->extra[1]; + self->buckets_ = (uint32_t*)common->extra[2]; +} + +static void FN(Prepare)( + HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot, + size_t input_size, const uint8_t* BROTLI_RESTRICT data) { + uint16_t* BROTLI_RESTRICT num = self->num_; + /* Partial preparation is 100 times slower (per socket). */ + size_t partial_prepare_threshold = self->bucket_size_ >> 6; + if (one_shot && input_size <= partial_prepare_threshold) { + size_t i; + for (i = 0; i < input_size; ++i) { + const size_t hash = FN(HashBytes)(&data[i], self->hash_mul_); + const size_t key = hash >> TAG_HASH_BITS; + num[key] = 65535; + } + } else { + /* Set all the bytes of num to 255, which makes each uint16_t 65535. */ + memset(num, 255, self->bucket_size_ * sizeof(num[0])); + } +} + +static BROTLI_INLINE void FN(HashMemAllocInBytes)( + const BrotliEncoderParams* params, BROTLI_BOOL one_shot, + size_t input_size, size_t* alloc_size) { + size_t bucket_size = (size_t)1 << params->hasher.bucket_bits; + size_t block_size = (size_t)1 << params->hasher.block_bits; + BROTLI_UNUSED(one_shot); + BROTLI_UNUSED(input_size); + alloc_size[0] = sizeof(uint16_t) * bucket_size; + alloc_size[1] = sizeof(uint8_t) * bucket_size * block_size; + alloc_size[2] = sizeof(uint32_t) * bucket_size * block_size; +} + +/* Look at 4 bytes at &data[ix & mask]. + Compute a hash from these, and store the value of ix at that position. */ +static BROTLI_INLINE void FN(Store)( + HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data, + const size_t mask, const size_t ix) { + uint16_t* BROTLI_RESTRICT num = self->num_; + uint8_t* BROTLI_RESTRICT tags = self->tags_; + uint32_t* BROTLI_RESTRICT buckets = self->buckets_; + const size_t hash = FN(HashBytes)(&data[ix & mask], self->hash_mul_); + const size_t key = hash >> TAG_HASH_BITS; + const uint8_t tag = hash & TAG_HASH_MASK; + const size_t minor_ix = num[key] & self->block_mask_; + const size_t offset = minor_ix + (key << self->block_bits_); + --num[key]; + buckets[offset] = (uint32_t)ix; + tags[offset] = tag; +} + +static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, + const size_t ix_start, const size_t ix_end) { + size_t i; + for (i = ix_start; i < ix_end; ++i) { + FN(Store)(self, data, mask, i); + } +} + +static BROTLI_INLINE void FN(StitchToPreviousBlock)( + HashLongestMatch* BROTLI_RESTRICT self, + size_t num_bytes, size_t position, const uint8_t* ringbuffer, + size_t ringbuffer_mask) { + if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) { + /* Prepare the hashes for three last bytes of the last write. + These could not be calculated before, since they require knowledge + of both the previous and the current block. */ + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3); + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2); + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1); + } +} + +static BROTLI_INLINE void FN(PrepareDistanceCache)( + HashLongestMatch* BROTLI_RESTRICT self, + int* BROTLI_RESTRICT distance_cache) { + PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_); +} + +/* Find a longest backward match of &data[cur_ix] up to the length of + max_length and stores the position cur_ix in the hash table. + + REQUIRES: FN(PrepareDistanceCache) must be invoked for current distance cache + values; if this method is invoked repeatedly with the same distance + cache values, it is enough to invoke FN(PrepareDistanceCache) once. + + Does not look for matches longer than max_length. + Does not look for matches further away than max_backward. + Writes the best match into |out|. + |out|->score is updated only if a better match is found. */ +static BROTLI_INLINE void FN(FindLongestMatch)( + HashLongestMatch* BROTLI_RESTRICT self, + const BrotliEncoderDictionary* dictionary, + const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask, + const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix, + const size_t max_length, const size_t max_backward, + const size_t dictionary_distance, const size_t max_distance, + HasherSearchResult* BROTLI_RESTRICT out) { + uint16_t* BROTLI_RESTRICT num = self->num_; + uint32_t* BROTLI_RESTRICT buckets = self->buckets_; + uint8_t* BROTLI_RESTRICT tags = self->tags_; + const size_t cur_ix_masked = cur_ix & ring_buffer_mask; + /* Don't accept a short copy from far away. */ + score_t min_score = out->score; + score_t best_score = out->score; + size_t best_len = out->len; + size_t i; + /* Precalculate the hash key and prefetch the bucket. */ + const size_t hash = FN(HashBytes)(&data[cur_ix_masked], self->hash_mul_); + const size_t key = hash >> TAG_HASH_BITS; + uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_]; + uint8_t* BROTLI_RESTRICT tag_bucket = &tags[key << self->block_bits_]; + PREFETCH_L1(bucket); + PREFETCH_L1(tag_bucket); + if (self->block_bits_ > 4) PREFETCH_L1(bucket + 16); + out->len = 0; + out->len_code_delta = 0; + + BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask); + + /* Try last distance first. */ + for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) { + const size_t backward = (size_t)distance_cache[i]; + size_t prev_ix = (size_t)(cur_ix - backward); + if (prev_ix >= cur_ix) { + continue; + } + if (BROTLI_PREDICT_FALSE(backward > max_backward)) { + continue; + } + prev_ix &= ring_buffer_mask; + + if (cur_ix_masked + best_len > ring_buffer_mask) { + break; + } + if (prev_ix + best_len > ring_buffer_mask || + data[cur_ix_masked + best_len] != data[prev_ix + best_len]) { + continue; + } + { + const size_t len = FindMatchLengthWithLimit(&data[prev_ix], + &data[cur_ix_masked], + max_length); + if (len >= 3 || (len == 2 && i < 2)) { + /* Comparing for >= 2 does not change the semantics, but just saves for + a few unnecessary binary logarithms in backward reference score, + since we are not interested in such short matches. */ + score_t score = BackwardReferenceScoreUsingLastDistance(len); + if (best_score < score) { + if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i); + if (best_score < score) { + best_score = score; + best_len = len; + out->len = best_len; + out->distance = backward; + out->score = best_score; + } + } + } + } + } + /* we require matches of len >4, so increase best_len to 3, so we can compare + * 4 bytes all the time. */ + if (best_len < 3) { + best_len = 3; + } + { + const uint8_t tag = hash & TAG_HASH_MASK; + const uint32_t first4 = BrotliUnalignedRead32(data + cur_ix_masked); + const size_t max_length_m4 = max_length - 4; + const size_t head = (num[key] + 1) & self->block_mask_; + uint64_t matches = + GetMatchingTagMask(self->block_size_ / 16, tag, tag_bucket, head); + /* Mask off any matches from uninitialized tags. */ + uint16_t n = 65535 - num[key]; + uint64_t block_has_unused_slots = self->block_size_ > n; + uint64_t mask = (block_has_unused_slots << (n & (64 - 1))) - 1; + matches &= mask; + for (; matches > 0; matches &= (matches - 1)) { + const size_t rb_index = + (head + (size_t)BROTLI_TZCNT64(matches)) & self->block_mask_; + size_t prev_ix = bucket[rb_index]; + uint32_t current4; + const size_t backward = cur_ix - prev_ix; + if (BROTLI_PREDICT_FALSE(backward > max_backward)) { + break; + } + prev_ix &= ring_buffer_mask; + if (cur_ix_masked + best_len > ring_buffer_mask) { + break; + } + if (prev_ix + best_len > ring_buffer_mask || + /* compare 4 bytes ending at best_len + 1 */ + BrotliUnalignedRead32(&data[cur_ix_masked + best_len - 3]) != + BrotliUnalignedRead32(&data[prev_ix + best_len - 3])) { + continue; + } + current4 = BrotliUnalignedRead32(data + prev_ix); + if (first4 != current4) continue; + { + const size_t len = FindMatchLengthWithLimit(&data[prev_ix + 4], + &data[cur_ix_masked + 4], + max_length_m4) + 4; + const score_t score = BackwardReferenceScore(len, backward); + if (best_score < score) { + best_score = score; + best_len = len; + out->len = best_len; + out->distance = backward; + out->score = best_score; + } + } + } + bucket[num[key] & self->block_mask_] = (uint32_t)cur_ix; + tag_bucket[num[key] & self->block_mask_] = tag; + --num[key]; + } + if (min_score == out->score) { + SearchInStaticDictionary(dictionary, + self->common_, &data[cur_ix_masked], max_length, dictionary_distance, + max_distance, out, BROTLI_FALSE); + } +} + +#undef HashLongestMatch diff --git a/packages/runtime/vendor/brotli/c/enc/hash_longest_match_inc.h b/packages/runtime/vendor/brotli/c/enc/hash_longest_match_inc.h new file mode 100644 index 000000000..58e88b3a6 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/hash_longest_match_inc.h @@ -0,0 +1,277 @@ +/* NOLINT(build/header_guard) */ +/* Copyright 2010 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* template parameters: FN */ + +/* A (forgetful) hash table to the data seen by the compressor, to + help create backward references to previous data. + + This is a hash map of fixed size (bucket_size_) to a ring buffer of + fixed size (block_size_). The ring buffer contains the last block_size_ + index positions of the given hash key in the compressed data. */ + +#define HashLongestMatch HASHER() + +static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; } +static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; } + +/* HashBytes is the function that chooses the bucket to place the address in. */ +static uint32_t FN(HashBytes)( + const uint8_t* BROTLI_RESTRICT data, const int shift) { + uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32; + /* The higher bits contain more mixture from the multiplication, + so we take our results from there. */ + return (uint32_t)(h >> shift); +} + +typedef struct HashLongestMatch { + /* Number of hash buckets. */ + size_t bucket_size_; + /* Only block_size_ newest backward references are kept, + and the older are forgotten. */ + size_t block_size_; + /* Left-shift for computing hash bucket index from hash value. */ + int hash_shift_; + /* Mask for accessing entries in a block (in a ring-buffer manner). */ + uint32_t block_mask_; + + int block_bits_; + int num_last_distances_to_check_; + + /* Shortcuts. */ + HasherCommon* common_; + + /* --- Dynamic size members --- */ + + /* Number of entries in a particular bucket. */ + uint16_t* num_; /* uint16_t[bucket_size]; */ + + /* Buckets containing block_size_ of backward references. */ + uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */ +} HashLongestMatch; + +static void FN(Initialize)( + HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self, + const BrotliEncoderParams* params) { + self->common_ = common; + + BROTLI_UNUSED(params); + self->hash_shift_ = 32 - common->params.bucket_bits; + self->bucket_size_ = (size_t)1 << common->params.bucket_bits; + self->block_size_ = (size_t)1 << common->params.block_bits; + self->block_mask_ = (uint32_t)(self->block_size_ - 1); + self->num_ = (uint16_t*)common->extra[0]; + self->buckets_ = (uint32_t*)common->extra[1]; + self->block_bits_ = common->params.block_bits; + self->num_last_distances_to_check_ = + common->params.num_last_distances_to_check; +} + +static void FN(Prepare)( + HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot, + size_t input_size, const uint8_t* BROTLI_RESTRICT data) { + uint16_t* BROTLI_RESTRICT num = self->num_; + /* Partial preparation is 100 times slower (per socket). */ + size_t partial_prepare_threshold = self->bucket_size_ >> 6; + if (one_shot && input_size <= partial_prepare_threshold) { + size_t i; + for (i = 0; i < input_size; ++i) { + const uint32_t key = FN(HashBytes)(&data[i], self->hash_shift_); + num[key] = 0; + } + } else { + memset(num, 0, self->bucket_size_ * sizeof(num[0])); + } +} + +static BROTLI_INLINE void FN(HashMemAllocInBytes)( + const BrotliEncoderParams* params, BROTLI_BOOL one_shot, + size_t input_size, size_t* alloc_size) { + size_t bucket_size = (size_t)1 << params->hasher.bucket_bits; + size_t block_size = (size_t)1 << params->hasher.block_bits; + BROTLI_UNUSED(one_shot); + BROTLI_UNUSED(input_size); + alloc_size[0] = sizeof(uint16_t) * bucket_size; + alloc_size[1] = sizeof(uint32_t) * bucket_size * block_size; +} + +/* Look at 4 bytes at &data[ix & mask]. + Compute a hash from these, and store the value of ix at that position. */ +static BROTLI_INLINE void FN(Store)( + HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data, + const size_t mask, const size_t ix) { + uint16_t* BROTLI_RESTRICT num = self->num_; + uint32_t* BROTLI_RESTRICT buckets = self->buckets_; + const uint32_t key = FN(HashBytes)(&data[ix & mask], self->hash_shift_); + const size_t minor_ix = num[key] & self->block_mask_; + const size_t offset = minor_ix + (key << self->block_bits_); + ++num[key]; + buckets[offset] = (uint32_t)ix; +} + +static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, + const size_t ix_start, const size_t ix_end) { + size_t i; + for (i = ix_start; i < ix_end; ++i) { + FN(Store)(self, data, mask, i); + } +} + +static BROTLI_INLINE void FN(StitchToPreviousBlock)( + HashLongestMatch* BROTLI_RESTRICT self, + size_t num_bytes, size_t position, const uint8_t* ringbuffer, + size_t ringbuffer_mask) { + if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) { + /* Prepare the hashes for three last bytes of the last write. + These could not be calculated before, since they require knowledge + of both the previous and the current block. */ + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3); + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2); + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1); + } +} + +static BROTLI_INLINE void FN(PrepareDistanceCache)( + HashLongestMatch* BROTLI_RESTRICT self, + int* BROTLI_RESTRICT distance_cache) { + PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_); +} + +/* Find a longest backward match of &data[cur_ix] up to the length of + max_length and stores the position cur_ix in the hash table. + + REQUIRES: FN(PrepareDistanceCache) must be invoked for current distance cache + values; if this method is invoked repeatedly with the same distance + cache values, it is enough to invoke FN(PrepareDistanceCache) once. + + Does not look for matches longer than max_length. + Does not look for matches further away than max_backward. + Writes the best match into |out|. + |out|->score is updated only if a better match is found. */ +static BROTLI_INLINE void FN(FindLongestMatch)( + HashLongestMatch* BROTLI_RESTRICT self, + const BrotliEncoderDictionary* dictionary, + const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask, + const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix, + const size_t max_length, const size_t max_backward, + const size_t dictionary_distance, const size_t max_distance, + HasherSearchResult* BROTLI_RESTRICT out) { + uint16_t* BROTLI_RESTRICT num = self->num_; + uint32_t* BROTLI_RESTRICT buckets = self->buckets_; + const size_t cur_ix_masked = cur_ix & ring_buffer_mask; + /* Don't accept a short copy from far away. */ + score_t min_score = out->score; + score_t best_score = out->score; + size_t best_len = out->len; + size_t i; + /* Precalculate the hash key and prefetch the bucket. */ + const uint32_t key = + FN(HashBytes)(&data[cur_ix_masked], self->hash_shift_); + uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_]; + PREFETCH_L1(bucket); + if (self->block_bits_ > 4) PREFETCH_L1(bucket + 16); + out->len = 0; + out->len_code_delta = 0; + + BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask); + + /* Try last distance first. */ + for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) { + const size_t backward = (size_t)distance_cache[i]; + size_t prev_ix = (size_t)(cur_ix - backward); + if (prev_ix >= cur_ix) { + continue; + } + if (BROTLI_PREDICT_FALSE(backward > max_backward)) { + continue; + } + prev_ix &= ring_buffer_mask; + + if (cur_ix_masked + best_len > ring_buffer_mask) { + break; + } + if (prev_ix + best_len > ring_buffer_mask || + data[cur_ix_masked + best_len] != data[prev_ix + best_len]) { + continue; + } + { + const size_t len = FindMatchLengthWithLimit(&data[prev_ix], + &data[cur_ix_masked], + max_length); + if (len >= 3 || (len == 2 && i < 2)) { + /* Comparing for >= 2 does not change the semantics, but just saves for + a few unnecessary binary logarithms in backward reference score, + since we are not interested in such short matches. */ + score_t score = BackwardReferenceScoreUsingLastDistance(len); + if (best_score < score) { + if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i); + if (best_score < score) { + best_score = score; + best_len = len; + out->len = best_len; + out->distance = backward; + out->score = best_score; + } + } + } + } + } + /* we require matches of len >4, so increase best_len to 3, so we can compare + * 4 bytes all the time. */ + if (best_len < 3) { + best_len = 3; + } + { + const size_t down = + (num[key] > self->block_size_) ? (num[key] - self->block_size_) : 0u; + for (i = num[key]; i > down;) { + size_t prev_ix = bucket[--i & self->block_mask_]; + const size_t backward = cur_ix - prev_ix; + if (BROTLI_PREDICT_FALSE(backward > max_backward)) { + break; + } + prev_ix &= ring_buffer_mask; + if (cur_ix_masked + best_len > ring_buffer_mask) { + break; + } + if (prev_ix + best_len > ring_buffer_mask || + /* compare 4 bytes ending at best_len + 1 */ + BrotliUnalignedRead32(&data[cur_ix_masked + best_len - 3]) != + BrotliUnalignedRead32(&data[prev_ix + best_len - 3])) { + continue; + } + { + const size_t len = FindMatchLengthWithLimit(&data[prev_ix], + &data[cur_ix_masked], + max_length); + if (len >= 4) { + /* Comparing for >= 3 does not change the semantics, but just saves + for a few unnecessary binary logarithms in backward reference + score, since we are not interested in such short matches. */ + score_t score = BackwardReferenceScore(len, backward); + if (best_score < score) { + best_score = score; + best_len = len; + out->len = best_len; + out->distance = backward; + out->score = best_score; + } + } + } + } + bucket[num[key] & self->block_mask_] = (uint32_t)cur_ix; + ++num[key]; + } + if (min_score == out->score) { + SearchInStaticDictionary(dictionary, + self->common_, &data[cur_ix_masked], max_length, dictionary_distance, + max_distance, out, BROTLI_FALSE); + } +} + +#undef HashLongestMatch diff --git a/packages/runtime/vendor/brotli/c/enc/hash_longest_match_quickly_inc.h b/packages/runtime/vendor/brotli/c/enc/hash_longest_match_quickly_inc.h new file mode 100644 index 000000000..57ed586fe --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/hash_longest_match_quickly_inc.h @@ -0,0 +1,270 @@ +/* NOLINT(build/header_guard) */ +/* Copyright 2010 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* template parameters: FN, BUCKET_BITS, BUCKET_SWEEP_BITS, HASH_LEN, + USE_DICTIONARY + */ + +#define HashLongestMatchQuickly HASHER() + +#define BUCKET_SIZE (1 << BUCKET_BITS) +#define BUCKET_MASK (BUCKET_SIZE - 1) +#define BUCKET_SWEEP (1 << BUCKET_SWEEP_BITS) +#define BUCKET_SWEEP_MASK ((BUCKET_SWEEP - 1) << 3) + +static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 8; } +static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 8; } + +/* HashBytes is the function that chooses the bucket to place + the address in. The HashLongestMatch and HashLongestMatchQuickly + classes have separate, different implementations of hashing. */ +static uint32_t FN(HashBytes)(const uint8_t* data) { + const uint64_t h = ((BROTLI_UNALIGNED_LOAD64LE(data) << (64 - 8 * HASH_LEN)) * + kHashMul64); + /* The higher bits contain more mixture from the multiplication, + so we take our results from there. */ + return (uint32_t)(h >> (64 - BUCKET_BITS)); +} + +/* A (forgetful) hash table to the data seen by the compressor, to + help create backward references to previous data. + + This is a hash map of fixed size (BUCKET_SIZE). */ +typedef struct HashLongestMatchQuickly { + /* Shortcuts. */ + HasherCommon* common; + + /* --- Dynamic size members --- */ + + uint32_t* buckets_; /* uint32_t[BUCKET_SIZE]; */ +} HashLongestMatchQuickly; + +static void FN(Initialize)( + HasherCommon* common, HashLongestMatchQuickly* BROTLI_RESTRICT self, + const BrotliEncoderParams* params) { + self->common = common; + + BROTLI_UNUSED(params); + self->buckets_ = (uint32_t*)common->extra[0]; +} + +static void FN(Prepare)( + HashLongestMatchQuickly* BROTLI_RESTRICT self, BROTLI_BOOL one_shot, + size_t input_size, const uint8_t* BROTLI_RESTRICT data) { + uint32_t* BROTLI_RESTRICT buckets = self->buckets_; + /* Partial preparation is 100 times slower (per socket). */ + size_t partial_prepare_threshold = BUCKET_SIZE >> 5; + if (one_shot && input_size <= partial_prepare_threshold) { + size_t i; + for (i = 0; i < input_size; ++i) { + const uint32_t key = FN(HashBytes)(&data[i]); + if (BUCKET_SWEEP == 1) { + buckets[key] = 0; + } else { + uint32_t j; + for (j = 0; j < BUCKET_SWEEP; ++j) { + buckets[(key + (j << 3)) & BUCKET_MASK] = 0; + } + } + } + } else { + /* It is not strictly necessary to fill this buffer here, but + not filling will make the results of the compression stochastic + (but correct). This is because random data would cause the + system to find accidentally good backward references here and there. */ + memset(buckets, 0, sizeof(uint32_t) * BUCKET_SIZE); + } +} + +static BROTLI_INLINE void FN(HashMemAllocInBytes)( + const BrotliEncoderParams* params, BROTLI_BOOL one_shot, + size_t input_size, size_t* alloc_size) { + BROTLI_UNUSED(params); + BROTLI_UNUSED(one_shot); + BROTLI_UNUSED(input_size); + alloc_size[0] = sizeof(uint32_t) * BUCKET_SIZE; +} + +/* Look at 5 bytes at &data[ix & mask]. + Compute a hash from these, and store the value somewhere within + [ix .. ix+3]. */ +static BROTLI_INLINE void FN(Store)( + HashLongestMatchQuickly* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) { + const uint32_t key = FN(HashBytes)(&data[ix & mask]); + if (BUCKET_SWEEP == 1) { + self->buckets_[key] = (uint32_t)ix; + } else { + /* Wiggle the value with the bucket sweep range. */ + const uint32_t off = ix & BUCKET_SWEEP_MASK; + self->buckets_[(key + off) & BUCKET_MASK] = (uint32_t)ix; + } +} + +static BROTLI_INLINE void FN(StoreRange)( + HashLongestMatchQuickly* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, + const size_t ix_start, const size_t ix_end) { + size_t i; + for (i = ix_start; i < ix_end; ++i) { + FN(Store)(self, data, mask, i); + } +} + +static BROTLI_INLINE void FN(StitchToPreviousBlock)( + HashLongestMatchQuickly* BROTLI_RESTRICT self, + size_t num_bytes, size_t position, + const uint8_t* ringbuffer, size_t ringbuffer_mask) { + if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) { + /* Prepare the hashes for three last bytes of the last write. + These could not be calculated before, since they require knowledge + of both the previous and the current block. */ + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3); + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2); + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1); + } +} + +static BROTLI_INLINE void FN(PrepareDistanceCache)( + HashLongestMatchQuickly* BROTLI_RESTRICT self, + int* BROTLI_RESTRICT distance_cache) { + BROTLI_UNUSED(self); + BROTLI_UNUSED(distance_cache); +} + +/* Find a longest backward match of &data[cur_ix & ring_buffer_mask] + up to the length of max_length and stores the position cur_ix in the + hash table. + + Does not look for matches longer than max_length. + Does not look for matches further away than max_backward. + Writes the best match into |out|. + |out|->score is updated only if a better match is found. */ +static BROTLI_INLINE void FN(FindLongestMatch)( + HashLongestMatchQuickly* BROTLI_RESTRICT self, + const BrotliEncoderDictionary* dictionary, + const uint8_t* BROTLI_RESTRICT data, + const size_t ring_buffer_mask, const int* BROTLI_RESTRICT distance_cache, + const size_t cur_ix, const size_t max_length, const size_t max_backward, + const size_t dictionary_distance, const size_t max_distance, + HasherSearchResult* BROTLI_RESTRICT out) { + uint32_t* BROTLI_RESTRICT buckets = self->buckets_; + const size_t best_len_in = out->len; + const size_t cur_ix_masked = cur_ix & ring_buffer_mask; + /* TODO: compare 4 bytes at once (and set the minimum best len to 4) */ + int compare_char = data[cur_ix_masked + best_len_in]; + size_t key = FN(HashBytes)(&data[cur_ix_masked]); + size_t key_out; + score_t min_score = out->score; + score_t best_score = out->score; + size_t best_len = best_len_in; + size_t cached_backward = (size_t)distance_cache[0]; + size_t prev_ix = cur_ix - cached_backward; + + BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask); + + out->len_code_delta = 0; + if (prev_ix < cur_ix) { + prev_ix &= (uint32_t)ring_buffer_mask; + if (compare_char == data[prev_ix + best_len]) { + const size_t len = FindMatchLengthWithLimit( + &data[prev_ix], &data[cur_ix_masked], max_length); + if (len >= 4) { + const score_t score = BackwardReferenceScoreUsingLastDistance(len); + if (best_score < score) { + out->len = len; + out->distance = cached_backward; + out->score = score; + if (BUCKET_SWEEP == 1) { + buckets[key] = (uint32_t)cur_ix; + return; + } else { + best_len = len; + best_score = score; + compare_char = data[cur_ix_masked + len]; + } + } + } + } + } + if (BUCKET_SWEEP == 1) { + size_t backward; + size_t len; + /* Only one to look for, don't bother to prepare for a loop. */ + prev_ix = buckets[key]; + buckets[key] = (uint32_t)cur_ix; + backward = cur_ix - prev_ix; + prev_ix &= (uint32_t)ring_buffer_mask; + if (compare_char != data[prev_ix + best_len_in]) { + return; + } + if (BROTLI_PREDICT_FALSE(backward == 0 || backward > max_backward)) { + return; + } + len = FindMatchLengthWithLimit(&data[prev_ix], + &data[cur_ix_masked], + max_length); + if (len >= 4) { + const score_t score = BackwardReferenceScore(len, backward); + if (best_score < score) { + out->len = len; + out->distance = backward; + out->score = score; + return; + } + } + } else { + size_t keys[BUCKET_SWEEP]; + size_t i; + for (i = 0; i < BUCKET_SWEEP; ++i) { + keys[i] = (key + (i << 3)) & BUCKET_MASK; + } + key_out = keys[(cur_ix & BUCKET_SWEEP_MASK) >> 3]; + for (i = 0; i < BUCKET_SWEEP; ++i) { + size_t len; + size_t backward; + prev_ix = buckets[keys[i]]; + backward = cur_ix - prev_ix; + prev_ix &= (uint32_t)ring_buffer_mask; + if (compare_char != data[prev_ix + best_len]) { + continue; + } + if (BROTLI_PREDICT_FALSE(backward == 0 || backward > max_backward)) { + continue; + } + len = FindMatchLengthWithLimit(&data[prev_ix], + &data[cur_ix_masked], + max_length); + if (len >= 4) { + const score_t score = BackwardReferenceScore(len, backward); + if (best_score < score) { + best_len = len; + out->len = len; + compare_char = data[cur_ix_masked + len]; + best_score = score; + out->score = score; + out->distance = backward; + } + } + } + } + if (USE_DICTIONARY && min_score == out->score) { + SearchInStaticDictionary(dictionary, + self->common, &data[cur_ix_masked], max_length, dictionary_distance, + max_distance, out, BROTLI_TRUE); + } + if (BUCKET_SWEEP != 1) { + buckets[key_out] = (uint32_t)cur_ix; + } +} + +#undef BUCKET_SWEEP_MASK +#undef BUCKET_SWEEP +#undef BUCKET_MASK +#undef BUCKET_SIZE + +#undef HashLongestMatchQuickly diff --git a/packages/runtime/vendor/brotli/c/enc/hash_longest_match_simd_inc.h b/packages/runtime/vendor/brotli/c/enc/hash_longest_match_simd_inc.h new file mode 100644 index 000000000..79b341ae5 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/hash_longest_match_simd_inc.h @@ -0,0 +1,278 @@ +/* NOLINT(build/header_guard) */ +/* Copyright 2010 Google Inc. All Rights Reserved. + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ +/* template parameters: FN */ +/* A (forgetful) hash table to the data seen by the compressor, to + help create backward references to previous data. + This is a hash map of fixed size (bucket_size_) to a ring buffer of + fixed size (block_size_). The ring buffer contains the last block_size_ + index positions of the given hash key in the compressed data. */ +#define HashLongestMatch HASHER() +#define TAG_HASH_BITS 8 +#define TAG_HASH_MASK ((1 << TAG_HASH_BITS) - 1) +static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; } +static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; } +/* HashBytes is the function that chooses the bucket to place the address in. */ +static uint32_t FN(HashBytes)( + const uint8_t* BROTLI_RESTRICT data, const int shift) { + uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32; + /* The higher bits contain more mixture from the multiplication, + so we take our results from there. */ + return (uint32_t)(h >> shift); +} +typedef struct HashLongestMatch { + /* Number of hash buckets. */ + size_t bucket_size_; + /* Only block_size_ newest backward references are kept, + and the older are forgotten. */ + size_t block_size_; + /* Left-shift for computing hash bucket index from hash value. */ + int hash_shift_; + /* Mask for accessing entries in a block (in a ring-buffer manner). */ + uint32_t block_mask_; + int block_bits_; + int num_last_distances_to_check_; + /* Shortcuts. */ + HasherCommon* common_; + /* --- Dynamic size members --- */ + /* Number of entries in a particular bucket. */ + uint16_t* num_; /* uint16_t[bucket_size]; */ + uint8_t* tags_; + /* Buckets containing block_size_ of backward references. */ + uint32_t* buckets_; /* uint32_t[bucket_size * block_size]; */ +} HashLongestMatch; +static void FN(Initialize)( + HasherCommon* common, HashLongestMatch* BROTLI_RESTRICT self, + const BrotliEncoderParams* params) { + self->common_ = common; + BROTLI_UNUSED(params); + self->hash_shift_ = 32 - common->params.bucket_bits - TAG_HASH_BITS; + self->bucket_size_ = (size_t)1 << common->params.bucket_bits; + self->block_size_ = (size_t)1 << common->params.block_bits; + self->block_mask_ = (uint32_t)(self->block_size_ - 1); + self->num_ = (uint16_t*)common->extra[0]; + self->tags_ = (uint8_t*)common->extra[1]; + self->buckets_ = (uint32_t*)common->extra[2]; + self->block_bits_ = common->params.block_bits; + self->num_last_distances_to_check_ = + common->params.num_last_distances_to_check; +} +static void FN(Prepare)( + HashLongestMatch* BROTLI_RESTRICT self, BROTLI_BOOL one_shot, + size_t input_size, const uint8_t* BROTLI_RESTRICT data) { + uint16_t* BROTLI_RESTRICT num = self->num_; + /* Partial preparation is 100 times slower (per socket). */ + size_t partial_prepare_threshold = self->bucket_size_ >> 6; + if (one_shot && input_size <= partial_prepare_threshold) { + size_t i; + for (i = 0; i < input_size; ++i) { + const uint32_t hash = FN(HashBytes)(&data[i], self->hash_shift_); + const uint32_t key = hash >> TAG_HASH_BITS; + num[key] = 65535; + } + } else { + /* Set all the bytes of num to 255, which makes each uint16_t 65535. */ + memset(num, 255, self->bucket_size_ * sizeof(num[0])); + } +} +static BROTLI_INLINE void FN(HashMemAllocInBytes)( + const BrotliEncoderParams* params, BROTLI_BOOL one_shot, + size_t input_size, size_t* alloc_size) { + size_t bucket_size = (size_t)1 << params->hasher.bucket_bits; + size_t block_size = (size_t)1 << params->hasher.block_bits; + BROTLI_UNUSED(one_shot); + BROTLI_UNUSED(input_size); + alloc_size[0] = sizeof(uint16_t) * bucket_size; + alloc_size[1] = sizeof(uint8_t) * bucket_size * block_size; + alloc_size[2] = sizeof(uint32_t) * bucket_size * block_size; +} +/* Look at 4 bytes at &data[ix & mask]. + Compute a hash from these, and store the value of ix at that position. */ +static BROTLI_INLINE void FN(Store)( + HashLongestMatch* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data, + const size_t mask, const size_t ix) { + uint16_t* BROTLI_RESTRICT num = self->num_; + uint8_t* BROTLI_RESTRICT tags = self->tags_; + uint32_t* BROTLI_RESTRICT buckets = self->buckets_; + const size_t hash = FN(HashBytes)(&data[ix & mask], self->hash_shift_); + const size_t key = hash >> TAG_HASH_BITS; + const uint8_t tag = hash & TAG_HASH_MASK; + const size_t minor_ix = num[key] & self->block_mask_; + const size_t offset = minor_ix + (key << self->block_bits_); + --num[key]; + buckets[offset] = (uint32_t)ix; + tags[offset] = tag; +} +static BROTLI_INLINE void FN(StoreRange)(HashLongestMatch* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, + const size_t ix_start, const size_t ix_end) { + size_t i; + for (i = ix_start; i < ix_end; ++i) { + FN(Store)(self, data, mask, i); + } +} +static BROTLI_INLINE void FN(StitchToPreviousBlock)( + HashLongestMatch* BROTLI_RESTRICT self, + size_t num_bytes, size_t position, const uint8_t* ringbuffer, + size_t ringbuffer_mask) { + if (num_bytes >= FN(HashTypeLength)() - 1 && position >= 3) { + /* Prepare the hashes for three last bytes of the last write. + These could not be calculated before, since they require knowledge + of both the previous and the current block. */ + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 3); + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 2); + FN(Store)(self, ringbuffer, ringbuffer_mask, position - 1); + } +} +static BROTLI_INLINE void FN(PrepareDistanceCache)( + HashLongestMatch* BROTLI_RESTRICT self, + int* BROTLI_RESTRICT distance_cache) { + PrepareDistanceCache(distance_cache, self->num_last_distances_to_check_); +} + +/* Find a longest backward match of &data[cur_ix] up to the length of + max_length and stores the position cur_ix in the hash table. + REQUIRES: FN(PrepareDistanceCache) must be invoked for current distance cache + values; if this method is invoked repeatedly with the same distance + cache values, it is enough to invoke FN(PrepareDistanceCache) once. + Does not look for matches longer than max_length. + Does not look for matches further away than max_backward. + Writes the best match into |out|. + |out|->score is updated only if a better match is found. */ +static BROTLI_INLINE void FN(FindLongestMatch)( + HashLongestMatch* BROTLI_RESTRICT self, + const BrotliEncoderDictionary* dictionary, + const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask, + const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix, + const size_t max_length, const size_t max_backward, + const size_t dictionary_distance, const size_t max_distance, + HasherSearchResult* BROTLI_RESTRICT out) { + uint16_t* BROTLI_RESTRICT num = self->num_; + uint32_t* BROTLI_RESTRICT buckets = self->buckets_; + uint8_t* BROTLI_RESTRICT tags = self->tags_; + const size_t cur_ix_masked = cur_ix & ring_buffer_mask; + /* Don't accept a short copy from far away. */ + score_t min_score = out->score; + score_t best_score = out->score; + size_t best_len = out->len; + size_t i; + /* Precalculate the hash key and prefetch the bucket. */ + const uint32_t hash = + FN(HashBytes)(&data[cur_ix_masked], self->hash_shift_); + const uint32_t key = hash >> TAG_HASH_BITS; + uint32_t* BROTLI_RESTRICT bucket = &buckets[key << self->block_bits_]; + uint8_t* BROTLI_RESTRICT tag_bucket = &tags[key << self->block_bits_]; + PREFETCH_L1(bucket); + PREFETCH_L1(tag_bucket); + if (self->block_bits_ > 4) PREFETCH_L1(bucket + 16); + out->len = 0; + out->len_code_delta = 0; + + BROTLI_DCHECK(cur_ix_masked + max_length <= ring_buffer_mask); + + /* Try last distance first. */ + for (i = 0; i < (size_t)self->num_last_distances_to_check_; ++i) { + const size_t backward = (size_t)distance_cache[i]; + size_t prev_ix = (size_t)(cur_ix - backward); + if (prev_ix >= cur_ix) { + continue; + } + if (BROTLI_PREDICT_FALSE(backward > max_backward)) { + continue; + } + prev_ix &= ring_buffer_mask; + + if (cur_ix_masked + best_len > ring_buffer_mask) { + break; + } + if (prev_ix + best_len > ring_buffer_mask || + data[cur_ix_masked + best_len] != data[prev_ix + best_len]) { + continue; + } + { + const size_t len = FindMatchLengthWithLimit(&data[prev_ix], + &data[cur_ix_masked], + max_length); + if (len >= 3 || (len == 2 && i < 2)) { + /* Comparing for >= 2 does not change the semantics, but just saves for + a few unnecessary binary logarithms in backward reference score, + since we are not interested in such short matches. */ + score_t score = BackwardReferenceScoreUsingLastDistance(len); + if (best_score < score) { + if (i != 0) score -= BackwardReferencePenaltyUsingLastDistance(i); + if (best_score < score) { + best_score = score; + best_len = len; + out->len = best_len; + out->distance = backward; + out->score = best_score; + } + } + } + } + } + /* we require matches of len >4, so increase best_len to 3, so we can compare + * 4 bytes all the time. */ + if (best_len < 3) { + best_len = 3; + } + { + const uint8_t tag = hash & TAG_HASH_MASK; + const size_t head = (num[key] + 1) & self->block_mask_; + uint64_t matches = + GetMatchingTagMask(self->block_size_ / 16, tag, tag_bucket, head); + /* Mask off any matches from uninitialized tags. */ + uint16_t n = 65535 - num[key]; + uint64_t block_has_unused_slots = self->block_size_ > n; + uint64_t mask = (block_has_unused_slots << (n & (64 - 1))) - 1; + matches &= mask; + for (; matches > 0; matches &= (matches - 1)) { + const size_t rb_index = + (head + (size_t)BROTLI_TZCNT64(matches)) & self->block_mask_; + size_t prev_ix = bucket[rb_index]; + const size_t backward = cur_ix - prev_ix; + if (BROTLI_PREDICT_FALSE(backward > max_backward)) { + break; + } + prev_ix &= ring_buffer_mask; + if (cur_ix_masked + best_len > ring_buffer_mask) { + break; + } + if (prev_ix + best_len > ring_buffer_mask || + /* compare 4 bytes ending at best_len + 1 */ + BrotliUnalignedRead32(&data[cur_ix_masked + best_len - 3]) != + BrotliUnalignedRead32(&data[prev_ix + best_len - 3])) { + continue; + } + { + const size_t len = FindMatchLengthWithLimit(&data[prev_ix], + &data[cur_ix_masked], + max_length); + if (len >= 4) { + /* Comparing for >= 3 does not change the semantics, but just saves + for a few unnecessary binary logarithms in backward reference + score, since we are not interested in such short matches. */ + score_t score = BackwardReferenceScore(len, backward); + if (best_score < score) { + best_score = score; + best_len = len; + out->len = best_len; + out->distance = backward; + out->score = best_score; + } + } + } + } + bucket[num[key] & self->block_mask_] = (uint32_t)cur_ix; + tag_bucket[num[key] & self->block_mask_] = tag; + --num[key]; + } + if (min_score == out->score) { + SearchInStaticDictionary(dictionary, + self->common_, &data[cur_ix_masked], max_length, dictionary_distance, + max_distance, out, BROTLI_FALSE); + } +} +#undef HashLongestMatch diff --git a/packages/runtime/vendor/brotli/c/enc/hash_rolling_inc.h b/packages/runtime/vendor/brotli/c/enc/hash_rolling_inc.h new file mode 100644 index 000000000..4c7a6b199 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/hash_rolling_inc.h @@ -0,0 +1,212 @@ +/* NOLINT(build/header_guard) */ +/* Copyright 2018 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* template parameters: FN, JUMP, NUMBUCKETS, MASK, CHUNKLEN */ +/* NUMBUCKETS / (MASK + 1) = probability of storing and using hash code. */ +/* JUMP = skip bytes for speedup */ + +/* Rolling hash for long distance long string matches. Stores one position + per bucket, bucket key is computed over a long region. */ + +#define HashRolling HASHER() + +static const uint32_t FN(kRollingHashMul32) = 69069; +static const uint32_t FN(kInvalidPos) = 0xffffffff; + +/* This hasher uses a longer forward length, but returning a higher value here + will hurt compression by the main hasher when combined with a composite + hasher. The hasher tests for forward itself instead. */ +static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; } +static BROTLI_INLINE size_t FN(StoreLookahead)(void) { return 4; } + +/* Computes a code from a single byte. A lookup table of 256 values could be + used, but simply adding 1 works about as good. */ +static uint32_t FN(HashByte)(uint8_t byte) { + return (uint32_t)byte + 1u; +} + +static uint32_t FN(HashRollingFunctionInitial)(uint32_t state, uint8_t add, + uint32_t factor) { + return (uint32_t)(factor * state + FN(HashByte)(add)); +} + +static uint32_t FN(HashRollingFunction)(uint32_t state, uint8_t add, + uint8_t rem, uint32_t factor, + uint32_t factor_remove) { + return (uint32_t)(factor * state + + FN(HashByte)(add) - factor_remove * FN(HashByte)(rem)); +} + +typedef struct HashRolling { + uint32_t state; + uint32_t* table; + size_t next_ix; + + uint32_t chunk_len; + uint32_t factor; + uint32_t factor_remove; +} HashRolling; + +static void FN(Initialize)( + HasherCommon* common, HashRolling* BROTLI_RESTRICT self, + const BrotliEncoderParams* params) { + size_t i; + self->state = 0; + self->next_ix = 0; + + self->factor = FN(kRollingHashMul32); + + /* Compute the factor of the oldest byte to remove: factor**steps modulo + 0xffffffff (the multiplications rely on 32-bit overflow) */ + self->factor_remove = 1; + for (i = 0; i < CHUNKLEN; i += JUMP) { + self->factor_remove *= self->factor; + } + + self->table = (uint32_t*)common->extra[0]; + for (i = 0; i < NUMBUCKETS; i++) { + self->table[i] = FN(kInvalidPos); + } + + BROTLI_UNUSED(params); +} + +static void FN(Prepare)(HashRolling* BROTLI_RESTRICT self, BROTLI_BOOL one_shot, + size_t input_size, const uint8_t* BROTLI_RESTRICT data) { + size_t i; + /* Too small size, cannot use this hasher. */ + if (input_size < CHUNKLEN) return; + self->state = 0; + for (i = 0; i < CHUNKLEN; i += JUMP) { + self->state = FN(HashRollingFunctionInitial)( + self->state, data[i], self->factor); + } + BROTLI_UNUSED(one_shot); +} + +static BROTLI_INLINE void FN(HashMemAllocInBytes)( + const BrotliEncoderParams* params, BROTLI_BOOL one_shot, + size_t input_size, size_t* alloc_size) { + BROTLI_UNUSED(params); + BROTLI_UNUSED(one_shot); + BROTLI_UNUSED(input_size); + alloc_size[0] = NUMBUCKETS * sizeof(uint32_t); +} + +static BROTLI_INLINE void FN(Store)(HashRolling* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, const size_t ix) { + BROTLI_UNUSED(self); + BROTLI_UNUSED(data); + BROTLI_UNUSED(mask); + BROTLI_UNUSED(ix); +} + +static BROTLI_INLINE void FN(StoreRange)(HashRolling* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, + const size_t ix_start, const size_t ix_end) { + BROTLI_UNUSED(self); + BROTLI_UNUSED(data); + BROTLI_UNUSED(mask); + BROTLI_UNUSED(ix_start); + BROTLI_UNUSED(ix_end); +} + +static BROTLI_INLINE void FN(StitchToPreviousBlock)( + HashRolling* BROTLI_RESTRICT self, + size_t num_bytes, size_t position, const uint8_t* ringbuffer, + size_t ring_buffer_mask) { + /* In this case we must re-initialize the hasher from scratch from the + current position. */ + size_t position_masked; + size_t available = num_bytes; + if ((position & (JUMP - 1)) != 0) { + size_t diff = JUMP - (position & (JUMP - 1)); + available = (diff > available) ? 0 : (available - diff); + position += diff; + } + position_masked = position & ring_buffer_mask; + /* wrapping around ringbuffer not handled. */ + if (available > ring_buffer_mask - position_masked) { + available = ring_buffer_mask - position_masked; + } + + FN(Prepare)(self, BROTLI_FALSE, available, + ringbuffer + (position & ring_buffer_mask)); + self->next_ix = position; + BROTLI_UNUSED(num_bytes); +} + +static BROTLI_INLINE void FN(PrepareDistanceCache)( + HashRolling* BROTLI_RESTRICT self, + int* BROTLI_RESTRICT distance_cache) { + BROTLI_UNUSED(self); + BROTLI_UNUSED(distance_cache); +} + +static BROTLI_INLINE void FN(FindLongestMatch)( + HashRolling* BROTLI_RESTRICT self, + const BrotliEncoderDictionary* dictionary, + const uint8_t* BROTLI_RESTRICT data, const size_t ring_buffer_mask, + const int* BROTLI_RESTRICT distance_cache, const size_t cur_ix, + const size_t max_length, const size_t max_backward, + const size_t dictionary_distance, const size_t max_distance, + HasherSearchResult* BROTLI_RESTRICT out) { + const size_t cur_ix_masked = cur_ix & ring_buffer_mask; + size_t pos; + + if ((cur_ix & (JUMP - 1)) != 0) return; + + /* Not enough lookahead */ + if (max_length < CHUNKLEN) return; + + for (pos = self->next_ix; pos <= cur_ix; pos += JUMP) { + uint32_t code = self->state & MASK; + + uint8_t rem = data[pos & ring_buffer_mask]; + uint8_t add = data[(pos + CHUNKLEN) & ring_buffer_mask]; + size_t found_ix = FN(kInvalidPos); + + self->state = FN(HashRollingFunction)( + self->state, add, rem, self->factor, self->factor_remove); + + if (code < NUMBUCKETS) { + found_ix = self->table[code]; + self->table[code] = (uint32_t)pos; + if (pos == cur_ix && found_ix != FN(kInvalidPos)) { + /* The cast to 32-bit makes backward distances up to 4GB work even + if cur_ix is above 4GB, despite using 32-bit values in the table. */ + size_t backward = (uint32_t)(cur_ix - found_ix); + if (backward <= max_backward) { + const size_t found_ix_masked = found_ix & ring_buffer_mask; + const size_t len = FindMatchLengthWithLimit(&data[found_ix_masked], + &data[cur_ix_masked], + max_length); + if (len >= 4 && len > out->len) { + score_t score = BackwardReferenceScore(len, backward); + if (score > out->score) { + out->len = len; + out->distance = backward; + out->score = score; + out->len_code_delta = 0; + } + } + } + } + } + } + + self->next_ix = cur_ix + JUMP; + + /* NOTE: this hasher does not search in the dictionary. It is used as + backup-hasher, the main hasher already searches in it. */ + BROTLI_UNUSED(dictionary); + BROTLI_UNUSED(distance_cache); + BROTLI_UNUSED(dictionary_distance); + BROTLI_UNUSED(max_distance); +} + +#undef HashRolling diff --git a/packages/runtime/vendor/brotli/c/enc/hash_to_binary_tree_inc.h b/packages/runtime/vendor/brotli/c/enc/hash_to_binary_tree_inc.h new file mode 100644 index 000000000..a639d2d4b --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/hash_to_binary_tree_inc.h @@ -0,0 +1,330 @@ +/* NOLINT(build/header_guard) */ +/* Copyright 2016 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* template parameters: FN, BUCKET_BITS, MAX_TREE_COMP_LENGTH, + MAX_TREE_SEARCH_DEPTH */ + +/* A (forgetful) hash table where each hash bucket contains a binary tree of + sequences whose first 4 bytes share the same hash code. + Each sequence is MAX_TREE_COMP_LENGTH long and is identified by its starting + position in the input data. The binary tree is sorted by the lexicographic + order of the sequences, and it is also a max-heap with respect to the + starting positions. */ + +#define HashToBinaryTree HASHER() + +#define BUCKET_SIZE (1 << BUCKET_BITS) + +static BROTLI_INLINE size_t FN(HashTypeLength)(void) { return 4; } +static BROTLI_INLINE size_t FN(StoreLookahead)(void) { + return MAX_TREE_COMP_LENGTH; +} + +static uint32_t FN(HashBytes)(const uint8_t* BROTLI_RESTRICT data) { + uint32_t h = BROTLI_UNALIGNED_LOAD32LE(data) * kHashMul32; + /* The higher bits contain more mixture from the multiplication, + so we take our results from there. */ + return h >> (32 - BUCKET_BITS); +} + +typedef struct HashToBinaryTree { + /* The window size minus 1 */ + size_t window_mask_; + + /* Hash table that maps the 4-byte hashes of the sequence to the last + position where this hash was found, which is the root of the binary + tree of sequences that share this hash bucket. */ + uint32_t* buckets_; /* uint32_t[BUCKET_SIZE]; */ + + /* A position used to mark a non-existent sequence, i.e. a tree is empty if + its root is at invalid_pos_ and a node is a leaf if both its children + are at invalid_pos_. */ + uint32_t invalid_pos_; + + /* --- Dynamic size members --- */ + + /* The union of the binary trees of each hash bucket. The root of the tree + corresponding to a hash is a sequence starting at buckets_[hash] and + the left and right children of a sequence starting at pos are + forest_[2 * pos] and forest_[2 * pos + 1]. */ + uint32_t* forest_; /* uint32_t[2 * num_nodes] */ +} HashToBinaryTree; + +static void FN(Initialize)( + HasherCommon* common, HashToBinaryTree* BROTLI_RESTRICT self, + const BrotliEncoderParams* params) { + self->buckets_ = (uint32_t*)common->extra[0]; + self->forest_ = (uint32_t*)common->extra[1]; + + self->window_mask_ = (1u << params->lgwin) - 1u; + self->invalid_pos_ = (uint32_t)(0 - self->window_mask_); +} + +static void FN(Prepare) + (HashToBinaryTree* BROTLI_RESTRICT self, BROTLI_BOOL one_shot, + size_t input_size, const uint8_t* BROTLI_RESTRICT data) { + uint32_t invalid_pos = self->invalid_pos_; + uint32_t i; + uint32_t* BROTLI_RESTRICT buckets = self->buckets_; + BROTLI_UNUSED(data); + BROTLI_UNUSED(one_shot); + BROTLI_UNUSED(input_size); + for (i = 0; i < BUCKET_SIZE; i++) { + buckets[i] = invalid_pos; + } +} + +static BROTLI_INLINE void FN(HashMemAllocInBytes)( + const BrotliEncoderParams* params, BROTLI_BOOL one_shot, + size_t input_size, size_t* alloc_size) { + size_t num_nodes = (size_t)1 << params->lgwin; + if (one_shot && input_size < num_nodes) { + num_nodes = input_size; + } + alloc_size[0] = sizeof(uint32_t) * BUCKET_SIZE; + alloc_size[1] = 2 * sizeof(uint32_t) * num_nodes; +} + +static BROTLI_INLINE size_t FN(LeftChildIndex)( + HashToBinaryTree* BROTLI_RESTRICT self, + const size_t pos) { + return 2 * (pos & self->window_mask_); +} + +static BROTLI_INLINE size_t FN(RightChildIndex)( + HashToBinaryTree* BROTLI_RESTRICT self, + const size_t pos) { + return 2 * (pos & self->window_mask_) + 1; +} + +/* Stores the hash of the next 4 bytes and in a single tree-traversal, the + hash bucket's binary tree is searched for matches and is re-rooted at the + current position. + + If less than MAX_TREE_COMP_LENGTH data is available, the hash bucket of the + current position is searched for matches, but the state of the hash table + is not changed, since we can not know the final sorting order of the + current (incomplete) sequence. + + This function must be called with increasing cur_ix positions. */ +static BROTLI_INLINE BackwardMatch* FN(StoreAndFindMatches)( + HashToBinaryTree* BROTLI_RESTRICT self, const uint8_t* BROTLI_RESTRICT data, + const size_t cur_ix, const size_t ring_buffer_mask, const size_t max_length, + const size_t max_backward, size_t* const BROTLI_RESTRICT best_len, + BackwardMatch* BROTLI_RESTRICT matches) { + const size_t cur_ix_masked = cur_ix & ring_buffer_mask; + const size_t max_comp_len = + BROTLI_MIN(size_t, max_length, MAX_TREE_COMP_LENGTH); + const BROTLI_BOOL should_reroot_tree = + TO_BROTLI_BOOL(max_length >= MAX_TREE_COMP_LENGTH); + const uint32_t key = FN(HashBytes)(&data[cur_ix_masked]); + uint32_t* BROTLI_RESTRICT buckets = self->buckets_; + uint32_t* BROTLI_RESTRICT forest = self->forest_; + size_t prev_ix = buckets[key]; + /* The forest index of the rightmost node of the left subtree of the new + root, updated as we traverse and re-root the tree of the hash bucket. */ + size_t node_left = FN(LeftChildIndex)(self, cur_ix); + /* The forest index of the leftmost node of the right subtree of the new + root, updated as we traverse and re-root the tree of the hash bucket. */ + size_t node_right = FN(RightChildIndex)(self, cur_ix); + /* The match length of the rightmost node of the left subtree of the new + root, updated as we traverse and re-root the tree of the hash bucket. */ + size_t best_len_left = 0; + /* The match length of the leftmost node of the right subtree of the new + root, updated as we traverse and re-root the tree of the hash bucket. */ + size_t best_len_right = 0; + size_t depth_remaining; + if (should_reroot_tree) { + buckets[key] = (uint32_t)cur_ix; + } + for (depth_remaining = MAX_TREE_SEARCH_DEPTH; ; --depth_remaining) { + const size_t backward = cur_ix - prev_ix; + const size_t prev_ix_masked = prev_ix & ring_buffer_mask; + if (backward == 0 || backward > max_backward || depth_remaining == 0) { + if (should_reroot_tree) { + forest[node_left] = self->invalid_pos_; + forest[node_right] = self->invalid_pos_; + } + break; + } + { + const size_t cur_len = BROTLI_MIN(size_t, best_len_left, best_len_right); + size_t len; + BROTLI_DCHECK(cur_len <= MAX_TREE_COMP_LENGTH); + len = cur_len + + FindMatchLengthWithLimit(&data[cur_ix_masked + cur_len], + &data[prev_ix_masked + cur_len], + max_length - cur_len); + BROTLI_DCHECK( + 0 == memcmp(&data[cur_ix_masked], &data[prev_ix_masked], len)); + if (matches && len > *best_len) { + *best_len = len; + InitBackwardMatch(matches++, backward, len); + } + if (len >= max_comp_len) { + if (should_reroot_tree) { + forest[node_left] = forest[FN(LeftChildIndex)(self, prev_ix)]; + forest[node_right] = forest[FN(RightChildIndex)(self, prev_ix)]; + } + break; + } + if (data[cur_ix_masked + len] > data[prev_ix_masked + len]) { + best_len_left = len; + if (should_reroot_tree) { + forest[node_left] = (uint32_t)prev_ix; + } + node_left = FN(RightChildIndex)(self, prev_ix); + prev_ix = forest[node_left]; + } else { + best_len_right = len; + if (should_reroot_tree) { + forest[node_right] = (uint32_t)prev_ix; + } + node_right = FN(LeftChildIndex)(self, prev_ix); + prev_ix = forest[node_right]; + } + } + } + return matches; +} + +/* Finds all backward matches of &data[cur_ix & ring_buffer_mask] up to the + length of max_length and stores the position cur_ix in the hash table. + + Sets *num_matches to the number of matches found, and stores the found + matches in matches[0] to matches[*num_matches - 1]. The matches will be + sorted by strictly increasing length and (non-strictly) increasing + distance. */ +static BROTLI_INLINE size_t FN(FindAllMatches)( + HashToBinaryTree* BROTLI_RESTRICT self, + const BrotliEncoderDictionary* dictionary, + const uint8_t* BROTLI_RESTRICT data, + const size_t ring_buffer_mask, const size_t cur_ix, + const size_t max_length, const size_t max_backward, + const size_t dictionary_distance, const BrotliEncoderParams* params, + BackwardMatch* matches) { + BackwardMatch* const orig_matches = matches; + const size_t cur_ix_masked = cur_ix & ring_buffer_mask; + size_t best_len = 1; + const size_t short_match_max_backward = + params->quality != HQ_ZOPFLIFICATION_QUALITY ? 16 : 64; + size_t stop = cur_ix - short_match_max_backward; + uint32_t dict_matches[BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN + 1]; + size_t i; + if (cur_ix < short_match_max_backward) { stop = 0; } + for (i = cur_ix - 1; i > stop && best_len <= 2; --i) { + size_t prev_ix = i; + const size_t backward = cur_ix - prev_ix; + if (BROTLI_PREDICT_FALSE(backward > max_backward)) { + break; + } + prev_ix &= ring_buffer_mask; + if (data[cur_ix_masked] != data[prev_ix] || + data[cur_ix_masked + 1] != data[prev_ix + 1]) { + continue; + } + { + const size_t len = + FindMatchLengthWithLimit(&data[prev_ix], &data[cur_ix_masked], + max_length); + if (len > best_len) { + best_len = len; + InitBackwardMatch(matches++, backward, len); + } + } + } + if (best_len < max_length) { + matches = FN(StoreAndFindMatches)(self, data, cur_ix, + ring_buffer_mask, max_length, max_backward, &best_len, matches); + } + for (i = 0; i <= BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN; ++i) { + dict_matches[i] = kInvalidMatch; + } + { + size_t minlen = BROTLI_MAX(size_t, 4, best_len + 1); + if (BrotliFindAllStaticDictionaryMatches(dictionary, + &data[cur_ix_masked], minlen, max_length, &dict_matches[0])) { + size_t maxlen = BROTLI_MIN( + size_t, BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN, max_length); + size_t l; + for (l = minlen; l <= maxlen; ++l) { + uint32_t dict_id = dict_matches[l]; + if (dict_id < kInvalidMatch) { + size_t distance = dictionary_distance + (dict_id >> 5) + 1; + if (distance <= params->dist.max_distance) { + InitDictionaryBackwardMatch(matches++, distance, l, dict_id & 31); + } + } + } + } + } + return (size_t)(matches - orig_matches); +} + +/* Stores the hash of the next 4 bytes and re-roots the binary tree at the + current sequence, without returning any matches. + REQUIRES: ix + MAX_TREE_COMP_LENGTH <= end-of-current-block */ +static BROTLI_INLINE void FN(Store)(HashToBinaryTree* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, + const size_t mask, const size_t ix) { + /* Maximum distance is window size - 16, see section 9.1. of the spec. */ + const size_t max_backward = self->window_mask_ - BROTLI_WINDOW_GAP + 1; + FN(StoreAndFindMatches)(self, data, ix, mask, MAX_TREE_COMP_LENGTH, + max_backward, NULL, NULL); +} + +static BROTLI_INLINE void FN(StoreRange)(HashToBinaryTree* BROTLI_RESTRICT self, + const uint8_t* BROTLI_RESTRICT data, const size_t mask, + const size_t ix_start, const size_t ix_end) { + size_t i = ix_start; + size_t j = ix_start; + if (ix_start + 63 <= ix_end) { + i = ix_end - 63; + } + if (ix_start + 512 <= i) { + for (; j < i; j += 8) { + FN(Store)(self, data, mask, j); + } + } + for (; i < ix_end; ++i) { + FN(Store)(self, data, mask, i); + } +} + +static BROTLI_INLINE void FN(StitchToPreviousBlock)( + HashToBinaryTree* BROTLI_RESTRICT self, + size_t num_bytes, size_t position, const uint8_t* ringbuffer, + size_t ringbuffer_mask) { + if (num_bytes >= FN(HashTypeLength)() - 1 && + position >= MAX_TREE_COMP_LENGTH) { + /* Store the last `MAX_TREE_COMP_LENGTH - 1` positions in the hasher. + These could not be calculated before, since they require knowledge + of both the previous and the current block. */ + const size_t i_start = position - MAX_TREE_COMP_LENGTH + 1; + const size_t i_end = BROTLI_MIN(size_t, position, i_start + num_bytes); + size_t i; + for (i = i_start; i < i_end; ++i) { + /* Maximum distance is window size - 16, see section 9.1. of the spec. + Furthermore, we have to make sure that we don't look further back + from the start of the next block than the window size, otherwise we + could access already overwritten areas of the ring-buffer. */ + const size_t max_backward = + self->window_mask_ - BROTLI_MAX(size_t, + BROTLI_WINDOW_GAP - 1, + position - i); + /* We know that i + MAX_TREE_COMP_LENGTH <= position + num_bytes, i.e. the + end of the current block and that we have at least + MAX_TREE_COMP_LENGTH tail in the ring-buffer. */ + FN(StoreAndFindMatches)(self, ringbuffer, i, ringbuffer_mask, + MAX_TREE_COMP_LENGTH, max_backward, NULL, NULL); + } + } +} + +#undef BUCKET_SIZE + +#undef HashToBinaryTree diff --git a/packages/runtime/vendor/brotli/c/enc/histogram.c b/packages/runtime/vendor/brotli/c/enc/histogram.c new file mode 100644 index 000000000..43e4b38e3 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/histogram.c @@ -0,0 +1,101 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Build per-context histograms of literals, commands and distance codes. */ + +#include "histogram.h" + +#include "../common/context.h" +#include "../common/platform.h" +#include "block_splitter.h" +#include "command.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +typedef struct BlockSplitIterator { + const BlockSplit* split_; /* Not owned. */ + size_t idx_; + size_t type_; + size_t length_; +} BlockSplitIterator; + +static void InitBlockSplitIterator(BlockSplitIterator* self, + const BlockSplit* split) { + self->split_ = split; + self->idx_ = 0; + self->type_ = 0; + self->length_ = split->lengths ? split->lengths[0] : 0; +} + +static void BlockSplitIteratorNext(BlockSplitIterator* self) { + if (self->length_ == 0) { + ++self->idx_; + self->type_ = self->split_->types[self->idx_]; + self->length_ = self->split_->lengths[self->idx_]; + } + --self->length_; +} + +void BrotliBuildHistogramsWithContext( + const Command* cmds, const size_t num_commands, + const BlockSplit* literal_split, const BlockSplit* insert_and_copy_split, + const BlockSplit* dist_split, const uint8_t* ringbuffer, size_t start_pos, + size_t mask, uint8_t prev_byte, uint8_t prev_byte2, + const ContextType* context_modes, HistogramLiteral* literal_histograms, + HistogramCommand* insert_and_copy_histograms, + HistogramDistance* copy_dist_histograms) { + size_t pos = start_pos; + BlockSplitIterator literal_it; + BlockSplitIterator insert_and_copy_it; + BlockSplitIterator dist_it; + size_t i; + + InitBlockSplitIterator(&literal_it, literal_split); + InitBlockSplitIterator(&insert_and_copy_it, insert_and_copy_split); + InitBlockSplitIterator(&dist_it, dist_split); + for (i = 0; i < num_commands; ++i) { + const Command* cmd = &cmds[i]; + size_t j; + BlockSplitIteratorNext(&insert_and_copy_it); + HistogramAddCommand(&insert_and_copy_histograms[insert_and_copy_it.type_], + cmd->cmd_prefix_); + /* TODO(eustas): unwrap iterator blocks. */ + for (j = cmd->insert_len_; j != 0; --j) { + size_t context; + BlockSplitIteratorNext(&literal_it); + context = literal_it.type_; + if (context_modes) { + ContextLut lut = BROTLI_CONTEXT_LUT(context_modes[context]); + context = (context << BROTLI_LITERAL_CONTEXT_BITS) + + BROTLI_CONTEXT(prev_byte, prev_byte2, lut); + } + HistogramAddLiteral(&literal_histograms[context], + ringbuffer[pos & mask]); + prev_byte2 = prev_byte; + prev_byte = ringbuffer[pos & mask]; + ++pos; + } + pos += CommandCopyLen(cmd); + if (CommandCopyLen(cmd)) { + prev_byte2 = ringbuffer[(pos - 2) & mask]; + prev_byte = ringbuffer[(pos - 1) & mask]; + if (cmd->cmd_prefix_ >= 128) { + size_t context; + BlockSplitIteratorNext(&dist_it); + context = (dist_it.type_ << BROTLI_DISTANCE_CONTEXT_BITS) + + CommandDistanceContext(cmd); + HistogramAddDistance(©_dist_histograms[context], + cmd->dist_prefix_ & 0x3FF); + } + } + } +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/histogram.h b/packages/runtime/vendor/brotli/c/enc/histogram.h new file mode 100644 index 000000000..a2accc331 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/histogram.h @@ -0,0 +1,60 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Models the histograms of literals, commands and distance codes. */ + +#ifndef BROTLI_ENC_HISTOGRAM_H_ +#define BROTLI_ENC_HISTOGRAM_H_ + +#include "../common/constants.h" +#include "../common/context.h" +#include "../common/platform.h" +#include "block_splitter.h" +#include "command.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* The distance symbols effectively used by "Large Window Brotli" (32-bit). */ +#define BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS 544 + +#define FN(X) X ## Literal +#define DATA_SIZE BROTLI_NUM_LITERAL_SYMBOLS +#define DataType uint8_t +#include "histogram_inc.h" /* NOLINT(build/include) */ +#undef DataType +#undef DATA_SIZE +#undef FN + +#define FN(X) X ## Command +#define DataType uint16_t +#define DATA_SIZE BROTLI_NUM_COMMAND_SYMBOLS +#include "histogram_inc.h" /* NOLINT(build/include) */ +#undef DATA_SIZE +#undef FN + +#define FN(X) X ## Distance +#define DATA_SIZE BROTLI_NUM_HISTOGRAM_DISTANCE_SYMBOLS +#include "histogram_inc.h" /* NOLINT(build/include) */ +#undef DataType +#undef DATA_SIZE +#undef FN + +BROTLI_INTERNAL void BrotliBuildHistogramsWithContext( + const Command* cmds, const size_t num_commands, + const BlockSplit* literal_split, const BlockSplit* insert_and_copy_split, + const BlockSplit* dist_split, const uint8_t* ringbuffer, size_t pos, + size_t mask, uint8_t prev_byte, uint8_t prev_byte2, + const ContextType* context_modes, HistogramLiteral* literal_histograms, + HistogramCommand* insert_and_copy_histograms, + HistogramDistance* copy_dist_histograms); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_HISTOGRAM_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/histogram_inc.h b/packages/runtime/vendor/brotli/c/enc/histogram_inc.h new file mode 100644 index 000000000..50eaf7468 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/histogram_inc.h @@ -0,0 +1,51 @@ +/* NOLINT(build/header_guard) */ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* template parameters: Histogram, DATA_SIZE, DataType */ + +/* A simple container for histograms of data in blocks. */ + +typedef struct FN(Histogram) { + uint32_t data_[DATA_SIZE]; + size_t total_count_; + double bit_cost_; +} FN(Histogram); + +static BROTLI_INLINE void FN(HistogramClear)(FN(Histogram)* self) { + memset(self->data_, 0, sizeof(self->data_)); + self->total_count_ = 0; + self->bit_cost_ = HUGE_VAL; +} + +static BROTLI_INLINE void FN(ClearHistograms)( + FN(Histogram)* array, size_t length) { + size_t i; + for (i = 0; i < length; ++i) FN(HistogramClear)(array + i); +} + +static BROTLI_INLINE void FN(HistogramAdd)(FN(Histogram)* self, size_t val) { + ++self->data_[val]; + ++self->total_count_; +} + +static BROTLI_INLINE void FN(HistogramAddVector)(FN(Histogram)* self, + const DataType* p, size_t n) { + self->total_count_ += n; + n += 1; + while (--n) ++self->data_[*p++]; +} + +static BROTLI_INLINE void FN(HistogramAddHistogram)(FN(Histogram)* self, + const FN(Histogram)* v) { + size_t i; + self->total_count_ += v->total_count_; + for (i = 0; i < DATA_SIZE; ++i) { + self->data_[i] += v->data_[i]; + } +} + +static BROTLI_INLINE size_t FN(HistogramDataSize)(void) { return DATA_SIZE; } diff --git a/packages/runtime/vendor/brotli/c/enc/literal_cost.c b/packages/runtime/vendor/brotli/c/enc/literal_cost.c new file mode 100644 index 000000000..c4e207d09 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/literal_cost.c @@ -0,0 +1,178 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Literal cost model to allow backward reference replacement to be efficient. +*/ + +#include "literal_cost.h" + +#include "../common/platform.h" +#include "fast_log.h" +#include "utf8_util.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +static size_t UTF8Position(size_t last, size_t c, size_t clamp) { + if (c < 128) { + return 0; /* Next one is the 'Byte 1' again. */ + } else if (c >= 192) { /* Next one is the 'Byte 2' of utf-8 encoding. */ + return BROTLI_MIN(size_t, 1, clamp); + } else { + /* Let's decide over the last byte if this ends the sequence. */ + if (last < 0xE0) { + return 0; /* Completed two or three byte coding. */ + } else { /* Next one is the 'Byte 3' of utf-8 encoding. */ + return BROTLI_MIN(size_t, 2, clamp); + } + } +} + +static size_t DecideMultiByteStatsLevel(size_t pos, size_t len, size_t mask, + const uint8_t* data) { + size_t counts[3] = { 0 }; + size_t max_utf8 = 1; /* should be 2, but 1 compresses better. */ + size_t last_c = 0; + size_t i; + for (i = 0; i < len; ++i) { + size_t c = data[(pos + i) & mask]; + ++counts[UTF8Position(last_c, c, 2)]; + last_c = c; + } + if (counts[2] < 500) { + max_utf8 = 1; + } + if (counts[1] + counts[2] < 25) { + max_utf8 = 0; + } + return max_utf8; +} + +static void EstimateBitCostsForLiteralsUTF8(size_t pos, size_t len, size_t mask, + const uint8_t* data, + size_t* histogram, float* cost) { + /* max_utf8 is 0 (normal ASCII single byte modeling), + 1 (for 2-byte UTF-8 modeling), or 2 (for 3-byte UTF-8 modeling). */ + const size_t max_utf8 = DecideMultiByteStatsLevel(pos, len, mask, data); + size_t window_half = 495; + size_t in_window = BROTLI_MIN(size_t, window_half, len); + size_t in_window_utf8[3] = { 0 }; + size_t i; + memset(histogram, 0, 3 * 256 * sizeof(histogram[0])); + + { /* Bootstrap histograms. */ + size_t last_c = 0; + size_t utf8_pos = 0; + for (i = 0; i < in_window; ++i) { + size_t c = data[(pos + i) & mask]; + ++histogram[256 * utf8_pos + c]; + ++in_window_utf8[utf8_pos]; + utf8_pos = UTF8Position(last_c, c, max_utf8); + last_c = c; + } + } + + /* Compute bit costs with sliding window. */ + for (i = 0; i < len; ++i) { + if (i >= window_half) { + /* Remove a byte in the past. */ + size_t c = + i < window_half + 1 ? 0 : data[(pos + i - window_half - 1) & mask]; + size_t last_c = + i < window_half + 2 ? 0 : data[(pos + i - window_half - 2) & mask]; + size_t utf8_pos2 = UTF8Position(last_c, c, max_utf8); + --histogram[256 * utf8_pos2 + data[(pos + i - window_half) & mask]]; + --in_window_utf8[utf8_pos2]; + } + if (i + window_half < len) { + /* Add a byte in the future. */ + size_t c = data[(pos + i + window_half - 1) & mask]; + size_t last_c = data[(pos + i + window_half - 2) & mask]; + size_t utf8_pos2 = UTF8Position(last_c, c, max_utf8); + ++histogram[256 * utf8_pos2 + data[(pos + i + window_half) & mask]]; + ++in_window_utf8[utf8_pos2]; + } + { + size_t c = i < 1 ? 0 : data[(pos + i - 1) & mask]; + size_t last_c = i < 2 ? 0 : data[(pos + i - 2) & mask]; + size_t utf8_pos = UTF8Position(last_c, c, max_utf8); + size_t masked_pos = (pos + i) & mask; + size_t histo = histogram[256 * utf8_pos + data[masked_pos]]; + static const size_t prologue_length = 2000; + static const double multiplier = 0.35 / 2000; + double lit_cost; + if (histo == 0) { + histo = 1; + } + lit_cost = FastLog2(in_window_utf8[utf8_pos]) - FastLog2(histo); + lit_cost += 0.02905; + if (lit_cost < 1.0) { + lit_cost *= 0.5; + lit_cost += 0.5; + } + /* Make the first bytes more expensive -- seems to help, not sure why. + Perhaps because the entropy source is changing its properties + rapidly in the beginning of the file, perhaps because the beginning + of the data is a statistical "anomaly". */ + if (i < prologue_length) { + lit_cost += 0.35 + multiplier * (double)i; + } + cost[i] = (float)lit_cost; + } + } +} + +void BrotliEstimateBitCostsForLiterals(size_t pos, size_t len, size_t mask, + const uint8_t* data, + size_t* histogram, float* cost) { + if (BrotliIsMostlyUTF8(data, pos, mask, len, kMinUTF8Ratio)) { + EstimateBitCostsForLiteralsUTF8(pos, len, mask, data, histogram, cost); + return; + } else { + size_t window_half = 2000; + size_t in_window = BROTLI_MIN(size_t, window_half, len); + size_t i; + memset(histogram, 0, 256 * sizeof(histogram[0])); + + /* Bootstrap histogram. */ + for (i = 0; i < in_window; ++i) { + ++histogram[data[(pos + i) & mask]]; + } + + /* Compute bit costs with sliding window. */ + for (i = 0; i < len; ++i) { + size_t histo; + if (i >= window_half) { + /* Remove a byte in the past. */ + --histogram[data[(pos + i - window_half) & mask]]; + --in_window; + } + if (i + window_half < len) { + /* Add a byte in the future. */ + ++histogram[data[(pos + i + window_half) & mask]]; + ++in_window; + } + histo = histogram[data[(pos + i) & mask]]; + if (histo == 0) { + histo = 1; + } + { + double lit_cost = FastLog2(in_window) - FastLog2(histo); + lit_cost += 0.029; + if (lit_cost < 1.0) { + lit_cost *= 0.5; + lit_cost += 0.5; + } + cost[i] = (float)lit_cost; + } + } + } +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/literal_cost.h b/packages/runtime/vendor/brotli/c/enc/literal_cost.h new file mode 100644 index 000000000..eb3f33836 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/literal_cost.h @@ -0,0 +1,30 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Literal cost model to allow backward reference replacement to be efficient. +*/ + +#ifndef BROTLI_ENC_LITERAL_COST_H_ +#define BROTLI_ENC_LITERAL_COST_H_ + +#include "../common/platform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* Estimates how many bits the literals in the interval [pos, pos + len) in the + ring-buffer (data, mask) will take entropy coded and writes these estimates + to the cost[0..len) array. */ +BROTLI_INTERNAL void BrotliEstimateBitCostsForLiterals( + size_t pos, size_t len, size_t mask, const uint8_t* data, size_t* histogram, + float* cost); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_LITERAL_COST_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/matching_tag_mask.h b/packages/runtime/vendor/brotli/c/enc/matching_tag_mask.h new file mode 100644 index 000000000..8a1be1d71 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/matching_tag_mask.h @@ -0,0 +1,69 @@ +#ifndef THIRD_PARTY_BROTLI_ENC_MATCHING_TAG_MASK_H_ +#define THIRD_PARTY_BROTLI_ENC_MATCHING_TAG_MASK_H_ + +#include "../common/platform.h" + +#if defined(__SSE2__) || defined(_M_AMD64) || \ + (defined(_M_IX86) && defined(_M_IX86_FP) && (_M_IX86_FP >= 2)) +#define SUPPORTS_SSE_2 +#endif + +#if defined(SUPPORTS_SSE_2) +#include +#endif + + +static BROTLI_INLINE uint64_t GetMatchingTagMask( + size_t chunk_count, const uint8_t tag, + const uint8_t* BROTLI_RESTRICT tag_bucket, const size_t head) { + uint64_t matches = 0; +#if defined(SUPPORTS_SSE_2) + const __m128i comparison_mask = _mm_set1_epi8((char)tag); + size_t i; + for (i = 0; i < chunk_count && i < 4; i++) { + const __m128i chunk = + _mm_loadu_si128((const __m128i*)(const void*)(tag_bucket + 16 * i)); + const __m128i equal_mask = _mm_cmpeq_epi8(chunk, comparison_mask); + matches |= (uint64_t)_mm_movemask_epi8(equal_mask) << 16 * i; + } +#else + const int chunk_size = sizeof(size_t); + const size_t shift_amount = ((chunk_size * 8) - chunk_size); + const size_t xFF = ~((size_t)0); + const size_t x01 = xFF / 0xFF; + const size_t x80 = x01 << 7; + const size_t splat_char = tag * x01; + int i = ((int)chunk_count * 16) - chunk_size; + BROTLI_DCHECK((sizeof(size_t) == 4) || (sizeof(size_t) == 8)); +#if BROTLI_LITTLE_ENDIAN + const size_t extractMagic = (xFF / 0x7F) >> chunk_size; + do { + size_t chunk = BrotliUnalignedReadSizeT(&tag_bucket[i]); + chunk ^= splat_char; + chunk = (((chunk | x80) - x01) | chunk) & x80; + matches <<= chunk_size; + matches |= (chunk * extractMagic) >> shift_amount; + i -= chunk_size; + } while (i >= 0); +#else + const size_t msb = xFF ^ (xFF >> 1); + const size_t extractMagic = (msb / 0x1FF) | msb; + do { + size_t chunk = BrotliUnalignedReadSizeT(&tag_bucket[i]); + chunk ^= splat_char; + chunk = (((chunk | x80) - x01) | chunk) & x80; + matches <<= chunk_size; + matches |= ((chunk >> 7) * extractMagic) >> shift_amount; + i -= chunk_size; + } while (i >= 0); +#endif + matches = ~matches; +#endif + if (chunk_count == 1) return BrotliRotateRight16((uint16_t)matches, head); + if (chunk_count == 2) return BrotliRotateRight32((uint32_t)matches, head); + return BrotliRotateRight64(matches, head); +} + +#undef SUPPORTS_SSE_2 + +#endif // THIRD_PARTY_BROTLI_ENC_MATCHING_TAG_MASK_H_ diff --git a/packages/runtime/vendor/brotli/c/enc/memory.c b/packages/runtime/vendor/brotli/c/enc/memory.c new file mode 100644 index 000000000..67f81ffde --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/memory.c @@ -0,0 +1,189 @@ +/* Copyright 2015 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Algorithms for distributing the literals and commands of a metablock between + block types and contexts. */ + +#include "memory.h" + +#include "../common/platform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define MAX_NEW_ALLOCATED (BROTLI_ENCODER_MEMORY_MANAGER_SLOTS >> 2) +#define MAX_NEW_FREED (BROTLI_ENCODER_MEMORY_MANAGER_SLOTS >> 2) +#define MAX_PERM_ALLOCATED (BROTLI_ENCODER_MEMORY_MANAGER_SLOTS >> 1) + +#define PERM_ALLOCATED_OFFSET 0 +#define NEW_ALLOCATED_OFFSET MAX_PERM_ALLOCATED +#define NEW_FREED_OFFSET (MAX_PERM_ALLOCATED + MAX_NEW_ALLOCATED) + +void BrotliInitMemoryManager( + MemoryManager* m, brotli_alloc_func alloc_func, brotli_free_func free_func, + void* opaque) { + if (!alloc_func) { + m->alloc_func = BrotliDefaultAllocFunc; + m->free_func = BrotliDefaultFreeFunc; + m->opaque = 0; + } else { + m->alloc_func = alloc_func; + m->free_func = free_func; + m->opaque = opaque; + } +#if !defined(BROTLI_ENCODER_EXIT_ON_OOM) + m->is_oom = BROTLI_FALSE; + m->perm_allocated = 0; + m->new_allocated = 0; + m->new_freed = 0; +#endif /* BROTLI_ENCODER_EXIT_ON_OOM */ +} + +#if defined(BROTLI_ENCODER_EXIT_ON_OOM) + +void* BrotliAllocate(MemoryManager* m, size_t n) { + void* result = m->alloc_func(m->opaque, n); + if (!result) exit(EXIT_FAILURE); + return result; +} + +void BrotliFree(MemoryManager* m, void* p) { + m->free_func(m->opaque, p); +} + +void BrotliWipeOutMemoryManager(MemoryManager* m) { + BROTLI_UNUSED(m); +} + +#else /* BROTLI_ENCODER_EXIT_ON_OOM */ + +static void SortPointers(void** items, const size_t n) { + /* Shell sort. */ + /* TODO(eustas): fine-tune for "many slots" case */ + static const size_t gaps[] = {23, 10, 4, 1}; + int g = 0; + for (; g < 4; ++g) { + size_t gap = gaps[g]; + size_t i; + for (i = gap; i < n; ++i) { + size_t j = i; + void* tmp = items[i]; + for (; j >= gap && tmp < items[j - gap]; j -= gap) { + items[j] = items[j - gap]; + } + items[j] = tmp; + } + } +} + +static size_t Annihilate(void** a, size_t a_len, void** b, size_t b_len) { + size_t a_read_index = 0; + size_t b_read_index = 0; + size_t a_write_index = 0; + size_t b_write_index = 0; + size_t annihilated = 0; + while (a_read_index < a_len && b_read_index < b_len) { + if (a[a_read_index] == b[b_read_index]) { + a_read_index++; + b_read_index++; + annihilated++; + } else if (a[a_read_index] < b[b_read_index]) { + a[a_write_index++] = a[a_read_index++]; + } else { + b[b_write_index++] = b[b_read_index++]; + } + } + while (a_read_index < a_len) a[a_write_index++] = a[a_read_index++]; + while (b_read_index < b_len) b[b_write_index++] = b[b_read_index++]; + return annihilated; +} + +static void CollectGarbagePointers(MemoryManager* m) { + size_t annihilated; + SortPointers(m->pointers + NEW_ALLOCATED_OFFSET, m->new_allocated); + SortPointers(m->pointers + NEW_FREED_OFFSET, m->new_freed); + annihilated = Annihilate( + m->pointers + NEW_ALLOCATED_OFFSET, m->new_allocated, + m->pointers + NEW_FREED_OFFSET, m->new_freed); + m->new_allocated -= annihilated; + m->new_freed -= annihilated; + + if (m->new_freed != 0) { + annihilated = Annihilate( + m->pointers + PERM_ALLOCATED_OFFSET, m->perm_allocated, + m->pointers + NEW_FREED_OFFSET, m->new_freed); + m->perm_allocated -= annihilated; + m->new_freed -= annihilated; + BROTLI_DCHECK(m->new_freed == 0); + } + + if (m->new_allocated != 0) { + BROTLI_DCHECK(m->perm_allocated + m->new_allocated <= MAX_PERM_ALLOCATED); + memcpy(m->pointers + PERM_ALLOCATED_OFFSET + m->perm_allocated, + m->pointers + NEW_ALLOCATED_OFFSET, + sizeof(void*) * m->new_allocated); + m->perm_allocated += m->new_allocated; + m->new_allocated = 0; + SortPointers(m->pointers + PERM_ALLOCATED_OFFSET, m->perm_allocated); + } +} + +void* BrotliAllocate(MemoryManager* m, size_t n) { + void* result = m->alloc_func(m->opaque, n); + if (!result) { + m->is_oom = BROTLI_TRUE; + return NULL; + } + if (m->new_allocated == MAX_NEW_ALLOCATED) CollectGarbagePointers(m); + m->pointers[NEW_ALLOCATED_OFFSET + (m->new_allocated++)] = result; + return result; +} + +void BrotliFree(MemoryManager* m, void* p) { + if (!p) return; + m->free_func(m->opaque, p); + if (m->new_freed == MAX_NEW_FREED) CollectGarbagePointers(m); + m->pointers[NEW_FREED_OFFSET + (m->new_freed++)] = p; +} + +void BrotliWipeOutMemoryManager(MemoryManager* m) { + size_t i; + CollectGarbagePointers(m); + /* Now all unfreed pointers are in perm-allocated list. */ + for (i = 0; i < m->perm_allocated; ++i) { + m->free_func(m->opaque, m->pointers[PERM_ALLOCATED_OFFSET + i]); + } + m->perm_allocated = 0; +} + +#endif /* BROTLI_ENCODER_EXIT_ON_OOM */ + +void* BrotliBootstrapAlloc(size_t size, + brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque) { + if (!alloc_func && !free_func) { + return malloc(size); + } else if (alloc_func && free_func) { + return alloc_func(opaque, size); + } + return NULL; +} + +void BrotliBootstrapFree(void* address, MemoryManager* m) { + if (!address) { + /* Should not happen! */ + return; + } else { + /* Copy values, as those would be freed. */ + brotli_free_func free_func = m->free_func; + void* opaque = m->opaque; + free_func(opaque, address); + } +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/memory.h b/packages/runtime/vendor/brotli/c/enc/memory.h new file mode 100644 index 000000000..d8374815b --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/memory.h @@ -0,0 +1,127 @@ +/* Copyright 2016 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Macros for memory management. */ + +#ifndef BROTLI_ENC_MEMORY_H_ +#define BROTLI_ENC_MEMORY_H_ + +#include "../common/platform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#if !defined(BROTLI_ENCODER_CLEANUP_ON_OOM) && \ + !defined(BROTLI_ENCODER_EXIT_ON_OOM) +#define BROTLI_ENCODER_EXIT_ON_OOM +#endif + +#if !defined(BROTLI_ENCODER_EXIT_ON_OOM) +#if defined(BROTLI_EXPERIMENTAL) +#define BROTLI_ENCODER_MEMORY_MANAGER_SLOTS (48*1024) +#else /* BROTLI_EXPERIMENTAL */ +#define BROTLI_ENCODER_MEMORY_MANAGER_SLOTS 256 +#endif /* BROTLI_EXPERIMENTAL */ +#else /* BROTLI_ENCODER_EXIT_ON_OOM */ +#define BROTLI_ENCODER_MEMORY_MANAGER_SLOTS 0 +#endif /* BROTLI_ENCODER_EXIT_ON_OOM */ + +typedef struct MemoryManager { + brotli_alloc_func alloc_func; + brotli_free_func free_func; + void* opaque; +#if !defined(BROTLI_ENCODER_EXIT_ON_OOM) + BROTLI_BOOL is_oom; + size_t perm_allocated; + size_t new_allocated; + size_t new_freed; + void* pointers[BROTLI_ENCODER_MEMORY_MANAGER_SLOTS]; +#endif /* BROTLI_ENCODER_EXIT_ON_OOM */ +} MemoryManager; + +BROTLI_INTERNAL void BrotliInitMemoryManager( + MemoryManager* m, brotli_alloc_func alloc_func, brotli_free_func free_func, + void* opaque); + +BROTLI_INTERNAL void* BrotliAllocate(MemoryManager* m, size_t n); +#define BROTLI_ALLOC(M, T, N) \ + ((N) > 0 ? ((T*)BrotliAllocate((M), (N) * sizeof(T))) : NULL) + +BROTLI_INTERNAL void BrotliFree(MemoryManager* m, void* p); +#define BROTLI_FREE(M, P) { \ + BrotliFree((M), (P)); \ + P = NULL; \ +} + +#if defined(BROTLI_ENCODER_EXIT_ON_OOM) +#define BROTLI_IS_OOM(M) (!!0) +#else /* BROTLI_ENCODER_EXIT_ON_OOM */ +#define BROTLI_IS_OOM(M) (!!(M)->is_oom) +#endif /* BROTLI_ENCODER_EXIT_ON_OOM */ + +/* +BROTLI_IS_NULL is a fake check, BROTLI_IS_OOM does the heavy lifting. +The only purpose of it is to explain static analyzers the state of things. +NB: use ONLY together with BROTLI_IS_OOM + AND ONLY for allocations in the current scope. + */ +#if defined(__clang_analyzer__) && !defined(BROTLI_ENCODER_EXIT_ON_OOM) +#define BROTLI_IS_NULL(A) ((A) == nullptr) +#else /* defined(__clang_analyzer__) */ +#define BROTLI_IS_NULL(A) (!!0) +#endif /* defined(__clang_analyzer__) */ + +BROTLI_INTERNAL void BrotliWipeOutMemoryManager(MemoryManager* m); + +/* +Dynamically grows array capacity to at least the requested size +M: MemoryManager +T: data type +A: array +C: capacity +R: requested size +*/ +#define BROTLI_ENSURE_CAPACITY(M, T, A, C, R) { \ + if (C < (R)) { \ + size_t _new_size = (C == 0) ? (R) : C; \ + T* new_array; \ + while (_new_size < (R)) _new_size *= 2; \ + new_array = BROTLI_ALLOC((M), T, _new_size); \ + if (!BROTLI_IS_OOM(M) && !BROTLI_IS_NULL(new_array) && C != 0) \ + memcpy(new_array, A, C * sizeof(T)); \ + BROTLI_FREE((M), A); \ + A = new_array; \ + C = _new_size; \ + } \ +} + +/* +Appends value and dynamically grows array capacity when needed +M: MemoryManager +T: data type +A: array +C: array capacity +S: array size +V: value to append +*/ +#define BROTLI_ENSURE_CAPACITY_APPEND(M, T, A, C, S, V) { \ + (S)++; \ + BROTLI_ENSURE_CAPACITY(M, T, A, C, S); \ + A[(S) - 1] = (V); \ +} + +/* "Bootstrap" allocations are not tracked by memory manager; should be used + only to allocate MemoryManager itself (or structure containing it). */ +BROTLI_INTERNAL void* BrotliBootstrapAlloc(size_t size, + brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque); +BROTLI_INTERNAL void BrotliBootstrapFree(void* address, MemoryManager* m); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_MEMORY_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/metablock.c b/packages/runtime/vendor/brotli/c/enc/metablock.c new file mode 100644 index 000000000..dfe8120c8 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/metablock.c @@ -0,0 +1,675 @@ +/* Copyright 2015 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Algorithms for distributing the literals and commands of a metablock between + block types and contexts. */ + +#include "metablock.h" + +#include "../common/constants.h" +#include "../common/context.h" +#include "../common/platform.h" +#include "bit_cost.h" +#include "block_splitter.h" +#include "cluster.h" +#include "command.h" +#include "entropy_encode.h" +#include "histogram.h" +#include "memory.h" +#include "params.h" +#include "prefix.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +void BrotliInitDistanceParams(BrotliDistanceParams* dist_params, + uint32_t npostfix, uint32_t ndirect, BROTLI_BOOL large_window) { + uint32_t alphabet_size_max; + uint32_t alphabet_size_limit; + uint32_t max_distance; + + dist_params->distance_postfix_bits = npostfix; + dist_params->num_direct_distance_codes = ndirect; + + alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE( + npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS); + alphabet_size_limit = alphabet_size_max; + max_distance = ndirect + (1U << (BROTLI_MAX_DISTANCE_BITS + npostfix + 2)) - + (1U << (npostfix + 2)); + + if (large_window) { + BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit( + BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect); + alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE( + npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS); + alphabet_size_limit = limit.max_alphabet_size; + max_distance = limit.max_distance; + } + + dist_params->alphabet_size_max = alphabet_size_max; + dist_params->alphabet_size_limit = alphabet_size_limit; + dist_params->max_distance = max_distance; +} + +static void RecomputeDistancePrefixes(Command* cmds, + size_t num_commands, + const BrotliDistanceParams* orig_params, + const BrotliDistanceParams* new_params) { + size_t i; + + if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits && + orig_params->num_direct_distance_codes == + new_params->num_direct_distance_codes) { + return; + } + + for (i = 0; i < num_commands; ++i) { + Command* cmd = &cmds[i]; + if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) { + PrefixEncodeCopyDistance(CommandRestoreDistanceCode(cmd, orig_params), + new_params->num_direct_distance_codes, + new_params->distance_postfix_bits, + &cmd->dist_prefix_, + &cmd->dist_extra_); + } + } +} + +static BROTLI_BOOL ComputeDistanceCost(const Command* cmds, + size_t num_commands, + const BrotliDistanceParams* orig_params, + const BrotliDistanceParams* new_params, + double* cost, + HistogramDistance* tmp) { + size_t i; + BROTLI_BOOL equal_params = BROTLI_FALSE; + uint16_t dist_prefix; + uint32_t dist_extra; + double extra_bits = 0.0; + HistogramClearDistance(tmp); + + if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits && + orig_params->num_direct_distance_codes == + new_params->num_direct_distance_codes) { + equal_params = BROTLI_TRUE; + } + + for (i = 0; i < num_commands; i++) { + const Command* cmd = &cmds[i]; + if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) { + if (equal_params) { + dist_prefix = cmd->dist_prefix_; + } else { + uint32_t distance = CommandRestoreDistanceCode(cmd, orig_params); + if (distance > new_params->max_distance) { + return BROTLI_FALSE; + } + PrefixEncodeCopyDistance(distance, + new_params->num_direct_distance_codes, + new_params->distance_postfix_bits, + &dist_prefix, + &dist_extra); + } + HistogramAddDistance(tmp, dist_prefix & 0x3FF); + extra_bits += dist_prefix >> 10; + } + } + + *cost = BrotliPopulationCostDistance(tmp) + extra_bits; + return BROTLI_TRUE; +} + +void BrotliBuildMetaBlock(MemoryManager* m, + const uint8_t* ringbuffer, + const size_t pos, + const size_t mask, + BrotliEncoderParams* params, + uint8_t prev_byte, + uint8_t prev_byte2, + Command* cmds, + size_t num_commands, + ContextType literal_context_mode, + MetaBlockSplit* mb) { + /* Histogram ids need to fit in one byte. */ + static const size_t kMaxNumberOfHistograms = 256; + HistogramDistance* distance_histograms; + HistogramLiteral* literal_histograms; + ContextType* literal_context_modes = NULL; + size_t literal_histograms_size; + size_t distance_histograms_size; + size_t i; + size_t literal_context_multiplier = 1; + uint32_t npostfix; + uint32_t ndirect_msb = 0; + BROTLI_BOOL check_orig = BROTLI_TRUE; + double best_dist_cost = 1e99; + BrotliDistanceParams orig_params = params->dist; + BrotliDistanceParams new_params = params->dist; + HistogramDistance* tmp = BROTLI_ALLOC(m, HistogramDistance, 1); + + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp)) return; + + for (npostfix = 0; npostfix <= BROTLI_MAX_NPOSTFIX; npostfix++) { + for (; ndirect_msb < 16; ndirect_msb++) { + uint32_t ndirect = ndirect_msb << npostfix; + BROTLI_BOOL skip; + double dist_cost; + BrotliInitDistanceParams(&new_params, npostfix, ndirect, + params->large_window); + if (npostfix == orig_params.distance_postfix_bits && + ndirect == orig_params.num_direct_distance_codes) { + check_orig = BROTLI_FALSE; + } + skip = !ComputeDistanceCost( + cmds, num_commands, &orig_params, &new_params, &dist_cost, tmp); + if (skip || (dist_cost > best_dist_cost)) { + break; + } + best_dist_cost = dist_cost; + params->dist = new_params; + } + if (ndirect_msb > 0) ndirect_msb--; + ndirect_msb /= 2; + } + if (check_orig) { + double dist_cost; + ComputeDistanceCost(cmds, num_commands, &orig_params, &orig_params, + &dist_cost, tmp); + if (dist_cost < best_dist_cost) { + /* NB: currently unused; uncomment when more param tuning is added. */ + /* best_dist_cost = dist_cost; */ + params->dist = orig_params; + } + } + BROTLI_FREE(m, tmp); + RecomputeDistancePrefixes(cmds, num_commands, &orig_params, ¶ms->dist); + + BrotliSplitBlock(m, cmds, num_commands, + ringbuffer, pos, mask, params, + &mb->literal_split, + &mb->command_split, + &mb->distance_split); + if (BROTLI_IS_OOM(m)) return; + + if (!params->disable_literal_context_modeling) { + literal_context_multiplier = 1 << BROTLI_LITERAL_CONTEXT_BITS; + literal_context_modes = + BROTLI_ALLOC(m, ContextType, mb->literal_split.num_types); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_context_modes)) return; + for (i = 0; i < mb->literal_split.num_types; ++i) { + literal_context_modes[i] = literal_context_mode; + } + } + + literal_histograms_size = + mb->literal_split.num_types * literal_context_multiplier; + literal_histograms = + BROTLI_ALLOC(m, HistogramLiteral, literal_histograms_size); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_histograms)) return; + ClearHistogramsLiteral(literal_histograms, literal_histograms_size); + + distance_histograms_size = + mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS; + distance_histograms = + BROTLI_ALLOC(m, HistogramDistance, distance_histograms_size); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(distance_histograms)) return; + ClearHistogramsDistance(distance_histograms, distance_histograms_size); + + BROTLI_DCHECK(mb->command_histograms == 0); + mb->command_histograms_size = mb->command_split.num_types; + mb->command_histograms = + BROTLI_ALLOC(m, HistogramCommand, mb->command_histograms_size); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->command_histograms)) return; + ClearHistogramsCommand(mb->command_histograms, mb->command_histograms_size); + + BrotliBuildHistogramsWithContext(cmds, num_commands, + &mb->literal_split, &mb->command_split, &mb->distance_split, + ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_modes, + literal_histograms, mb->command_histograms, distance_histograms); + BROTLI_FREE(m, literal_context_modes); + + BROTLI_DCHECK(mb->literal_context_map == 0); + mb->literal_context_map_size = + mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS; + mb->literal_context_map = + BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return; + + BROTLI_DCHECK(mb->literal_histograms == 0); + mb->literal_histograms_size = mb->literal_context_map_size; + mb->literal_histograms = + BROTLI_ALLOC(m, HistogramLiteral, mb->literal_histograms_size); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_histograms)) return; + + BrotliClusterHistogramsLiteral(m, literal_histograms, literal_histograms_size, + kMaxNumberOfHistograms, mb->literal_histograms, + &mb->literal_histograms_size, mb->literal_context_map); + if (BROTLI_IS_OOM(m)) return; + BROTLI_FREE(m, literal_histograms); + + if (params->disable_literal_context_modeling) { + /* Distribute assignment to all contexts. */ + for (i = mb->literal_split.num_types; i != 0;) { + size_t j = 0; + i--; + for (; j < (1 << BROTLI_LITERAL_CONTEXT_BITS); j++) { + mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] = + mb->literal_context_map[i]; + } + } + } + + BROTLI_DCHECK(mb->distance_context_map == 0); + mb->distance_context_map_size = + mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS; + mb->distance_context_map = + BROTLI_ALLOC(m, uint32_t, mb->distance_context_map_size); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_context_map)) return; + + BROTLI_DCHECK(mb->distance_histograms == 0); + mb->distance_histograms_size = mb->distance_context_map_size; + mb->distance_histograms = + BROTLI_ALLOC(m, HistogramDistance, mb->distance_histograms_size); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_histograms)) return; + + BrotliClusterHistogramsDistance(m, distance_histograms, + mb->distance_context_map_size, + kMaxNumberOfHistograms, + mb->distance_histograms, + &mb->distance_histograms_size, + mb->distance_context_map); + if (BROTLI_IS_OOM(m)) return; + BROTLI_FREE(m, distance_histograms); +} + +#define FN(X) X ## Literal +#include "metablock_inc.h" /* NOLINT(build/include) */ +#undef FN + +#define FN(X) X ## Command +#include "metablock_inc.h" /* NOLINT(build/include) */ +#undef FN + +#define FN(X) X ## Distance +#include "metablock_inc.h" /* NOLINT(build/include) */ +#undef FN + +/* Greedy block splitter for one block category (literal, command or distance). + Gathers histograms for all context buckets. */ +typedef struct ContextBlockSplitter { + /* Alphabet size of particular block category. */ + size_t alphabet_size_; + size_t num_contexts_; + size_t max_block_types_; + /* We collect at least this many symbols for each block. */ + size_t min_block_size_; + /* We merge histograms A and B if + entropy(A+B) < entropy(A) + entropy(B) + split_threshold_, + where A is the current histogram and B is the histogram of the last or the + second last block type. */ + double split_threshold_; + + size_t num_blocks_; + BlockSplit* split_; /* not owned */ + HistogramLiteral* histograms_; /* not owned */ + size_t* histograms_size_; /* not owned */ + + /* The number of symbols that we want to collect before deciding on whether + or not to merge the block with a previous one or emit a new block. */ + size_t target_block_size_; + /* The number of symbols in the current histogram. */ + size_t block_size_; + /* Offset of the current histogram. */ + size_t curr_histogram_ix_; + /* Offset of the histograms of the previous two block types. */ + size_t last_histogram_ix_[2]; + /* Entropy of the previous two block types. */ + double last_entropy_[2 * BROTLI_MAX_STATIC_CONTEXTS]; + /* The number of times we merged the current block with the last one. */ + size_t merge_last_count_; +} ContextBlockSplitter; + +static void InitContextBlockSplitter( + MemoryManager* m, ContextBlockSplitter* self, size_t alphabet_size, + size_t num_contexts, size_t min_block_size, double split_threshold, + size_t num_symbols, BlockSplit* split, HistogramLiteral** histograms, + size_t* histograms_size) { + size_t max_num_blocks = num_symbols / min_block_size + 1; + size_t max_num_types; + BROTLI_DCHECK(num_contexts <= BROTLI_MAX_STATIC_CONTEXTS); + + self->alphabet_size_ = alphabet_size; + self->num_contexts_ = num_contexts; + self->max_block_types_ = BROTLI_MAX_NUMBER_OF_BLOCK_TYPES / num_contexts; + self->min_block_size_ = min_block_size; + self->split_threshold_ = split_threshold; + self->num_blocks_ = 0; + self->split_ = split; + self->histograms_size_ = histograms_size; + self->target_block_size_ = min_block_size; + self->block_size_ = 0; + self->curr_histogram_ix_ = 0; + self->merge_last_count_ = 0; + + /* We have to allocate one more histogram than the maximum number of block + types for the current histogram when the meta-block is too big. */ + max_num_types = + BROTLI_MIN(size_t, max_num_blocks, self->max_block_types_ + 1); + BROTLI_ENSURE_CAPACITY(m, uint8_t, + split->types, split->types_alloc_size, max_num_blocks); + BROTLI_ENSURE_CAPACITY(m, uint32_t, + split->lengths, split->lengths_alloc_size, max_num_blocks); + if (BROTLI_IS_OOM(m)) return; + split->num_blocks = max_num_blocks; + if (BROTLI_IS_OOM(m)) return; + BROTLI_DCHECK(*histograms == 0); + *histograms_size = max_num_types * num_contexts; + *histograms = BROTLI_ALLOC(m, HistogramLiteral, *histograms_size); + self->histograms_ = *histograms; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return; + /* Clear only current histogram. */ + ClearHistogramsLiteral(&self->histograms_[0], num_contexts); + self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0; +} + +/* Does either of three things: + (1) emits the current block with a new block type; + (2) emits the current block with the type of the second last block; + (3) merges the current block with the last block. */ +static void ContextBlockSplitterFinishBlock( + ContextBlockSplitter* self, MemoryManager* m, BROTLI_BOOL is_final) { + BlockSplit* split = self->split_; + const size_t num_contexts = self->num_contexts_; + double* last_entropy = self->last_entropy_; + HistogramLiteral* histograms = self->histograms_; + + if (self->block_size_ < self->min_block_size_) { + self->block_size_ = self->min_block_size_; + } + if (self->num_blocks_ == 0) { + size_t i; + /* Create first block. */ + split->lengths[0] = (uint32_t)self->block_size_; + split->types[0] = 0; + + for (i = 0; i < num_contexts; ++i) { + last_entropy[i] = + BrotliBitsEntropy(histograms[i].data_, self->alphabet_size_); + last_entropy[num_contexts + i] = last_entropy[i]; + } + ++self->num_blocks_; + ++split->num_types; + self->curr_histogram_ix_ += num_contexts; + if (self->curr_histogram_ix_ < *self->histograms_size_) { + ClearHistogramsLiteral( + &self->histograms_[self->curr_histogram_ix_], self->num_contexts_); + } + self->block_size_ = 0; + } else if (self->block_size_ > 0) { + /* Try merging the set of histograms for the current block type with the + respective set of histograms for the last and second last block types. + Decide over the split based on the total reduction of entropy across + all contexts. */ + double entropy[BROTLI_MAX_STATIC_CONTEXTS]; + HistogramLiteral* combined_histo = + BROTLI_ALLOC(m, HistogramLiteral, 2 * num_contexts); + double combined_entropy[2 * BROTLI_MAX_STATIC_CONTEXTS]; + double diff[2] = { 0.0 }; + size_t i; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(combined_histo)) return; + for (i = 0; i < num_contexts; ++i) { + size_t curr_histo_ix = self->curr_histogram_ix_ + i; + size_t j; + entropy[i] = BrotliBitsEntropy(histograms[curr_histo_ix].data_, + self->alphabet_size_); + for (j = 0; j < 2; ++j) { + size_t jx = j * num_contexts + i; + size_t last_histogram_ix = self->last_histogram_ix_[j] + i; + combined_histo[jx] = histograms[curr_histo_ix]; + HistogramAddHistogramLiteral(&combined_histo[jx], + &histograms[last_histogram_ix]); + combined_entropy[jx] = BrotliBitsEntropy( + &combined_histo[jx].data_[0], self->alphabet_size_); + diff[j] += combined_entropy[jx] - entropy[i] - last_entropy[jx]; + } + } + + if (split->num_types < self->max_block_types_ && + diff[0] > self->split_threshold_ && + diff[1] > self->split_threshold_) { + /* Create new block. */ + split->lengths[self->num_blocks_] = (uint32_t)self->block_size_; + split->types[self->num_blocks_] = (uint8_t)split->num_types; + self->last_histogram_ix_[1] = self->last_histogram_ix_[0]; + self->last_histogram_ix_[0] = split->num_types * num_contexts; + for (i = 0; i < num_contexts; ++i) { + last_entropy[num_contexts + i] = last_entropy[i]; + last_entropy[i] = entropy[i]; + } + ++self->num_blocks_; + ++split->num_types; + self->curr_histogram_ix_ += num_contexts; + if (self->curr_histogram_ix_ < *self->histograms_size_) { + ClearHistogramsLiteral( + &self->histograms_[self->curr_histogram_ix_], self->num_contexts_); + } + self->block_size_ = 0; + self->merge_last_count_ = 0; + self->target_block_size_ = self->min_block_size_; + } else if (diff[1] < diff[0] - 20.0) { + /* Combine this block with second last block. */ + split->lengths[self->num_blocks_] = (uint32_t)self->block_size_; + split->types[self->num_blocks_] = split->types[self->num_blocks_ - 2]; + BROTLI_SWAP(size_t, self->last_histogram_ix_, 0, 1); + for (i = 0; i < num_contexts; ++i) { + histograms[self->last_histogram_ix_[0] + i] = + combined_histo[num_contexts + i]; + last_entropy[num_contexts + i] = last_entropy[i]; + last_entropy[i] = combined_entropy[num_contexts + i]; + HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]); + } + ++self->num_blocks_; + self->block_size_ = 0; + self->merge_last_count_ = 0; + self->target_block_size_ = self->min_block_size_; + } else { + /* Combine this block with last block. */ + split->lengths[self->num_blocks_ - 1] += (uint32_t)self->block_size_; + for (i = 0; i < num_contexts; ++i) { + histograms[self->last_histogram_ix_[0] + i] = combined_histo[i]; + last_entropy[i] = combined_entropy[i]; + if (split->num_types == 1) { + last_entropy[num_contexts + i] = last_entropy[i]; + } + HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]); + } + self->block_size_ = 0; + if (++self->merge_last_count_ > 1) { + self->target_block_size_ += self->min_block_size_; + } + } + BROTLI_FREE(m, combined_histo); + } + if (is_final) { + *self->histograms_size_ = split->num_types * num_contexts; + split->num_blocks = self->num_blocks_; + } +} + +/* Adds the next symbol to the current block type and context. When the + current block reaches the target size, decides on merging the block. */ +static void ContextBlockSplitterAddSymbol( + ContextBlockSplitter* self, MemoryManager* m, + size_t symbol, size_t context) { + HistogramAddLiteral(&self->histograms_[self->curr_histogram_ix_ + context], + symbol); + ++self->block_size_; + if (self->block_size_ == self->target_block_size_) { + ContextBlockSplitterFinishBlock(self, m, /* is_final = */ BROTLI_FALSE); + if (BROTLI_IS_OOM(m)) return; + } +} + +static void MapStaticContexts(MemoryManager* m, + size_t num_contexts, + const uint32_t* static_context_map, + MetaBlockSplit* mb) { + size_t i; + BROTLI_DCHECK(mb->literal_context_map == 0); + mb->literal_context_map_size = + mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS; + mb->literal_context_map = + BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return; + + for (i = 0; i < mb->literal_split.num_types; ++i) { + uint32_t offset = (uint32_t)(i * num_contexts); + size_t j; + for (j = 0; j < (1u << BROTLI_LITERAL_CONTEXT_BITS); ++j) { + mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] = + offset + static_context_map[j]; + } + } +} + +typedef struct GreedyMetablockArena { + union { + BlockSplitterLiteral plain; + ContextBlockSplitter ctx; + } lit_blocks; + BlockSplitterCommand cmd_blocks; + BlockSplitterDistance dist_blocks; +} GreedyMetablockArena; + +static BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal( + MemoryManager* m, GreedyMetablockArena* arena, const uint8_t* ringbuffer, + size_t pos, size_t mask, uint8_t prev_byte, uint8_t prev_byte2, + ContextLut literal_context_lut, const size_t num_contexts, + const uint32_t* static_context_map, const Command* commands, + size_t n_commands, MetaBlockSplit* mb) { + size_t num_literals = 0; + size_t i; + for (i = 0; i < n_commands; ++i) { + num_literals += commands[i].insert_len_; + } + + if (num_contexts == 1) { + InitBlockSplitterLiteral(m, &arena->lit_blocks.plain, 256, 512, 400.0, + num_literals, &mb->literal_split, &mb->literal_histograms, + &mb->literal_histograms_size); + } else { + InitContextBlockSplitter(m, &arena->lit_blocks.ctx, 256, num_contexts, 512, + 400.0, num_literals, &mb->literal_split, &mb->literal_histograms, + &mb->literal_histograms_size); + } + if (BROTLI_IS_OOM(m)) return; + InitBlockSplitterCommand(m, &arena->cmd_blocks, BROTLI_NUM_COMMAND_SYMBOLS, + 1024, 500.0, n_commands, &mb->command_split, &mb->command_histograms, + &mb->command_histograms_size); + if (BROTLI_IS_OOM(m)) return; + InitBlockSplitterDistance(m, &arena->dist_blocks, 64, 512, 100.0, n_commands, + &mb->distance_split, &mb->distance_histograms, + &mb->distance_histograms_size); + if (BROTLI_IS_OOM(m)) return; + + for (i = 0; i < n_commands; ++i) { + const Command cmd = commands[i]; + size_t j; + BlockSplitterAddSymbolCommand(&arena->cmd_blocks, cmd.cmd_prefix_); + for (j = cmd.insert_len_; j != 0; --j) { + uint8_t literal = ringbuffer[pos & mask]; + if (num_contexts == 1) { + BlockSplitterAddSymbolLiteral(&arena->lit_blocks.plain, literal); + } else { + size_t context = + BROTLI_CONTEXT(prev_byte, prev_byte2, literal_context_lut); + ContextBlockSplitterAddSymbol(&arena->lit_blocks.ctx, m, literal, + static_context_map[context]); + if (BROTLI_IS_OOM(m)) return; + } + prev_byte2 = prev_byte; + prev_byte = literal; + ++pos; + } + pos += CommandCopyLen(&cmd); + if (CommandCopyLen(&cmd)) { + prev_byte2 = ringbuffer[(pos - 2) & mask]; + prev_byte = ringbuffer[(pos - 1) & mask]; + if (cmd.cmd_prefix_ >= 128) { + BlockSplitterAddSymbolDistance( + &arena->dist_blocks, cmd.dist_prefix_ & 0x3FF); + } + } + } + + if (num_contexts == 1) { + BlockSplitterFinishBlockLiteral( + &arena->lit_blocks.plain, /* is_final = */ BROTLI_TRUE); + } else { + ContextBlockSplitterFinishBlock( + &arena->lit_blocks.ctx, m, /* is_final = */ BROTLI_TRUE); + if (BROTLI_IS_OOM(m)) return; + } + BlockSplitterFinishBlockCommand( + &arena->cmd_blocks, /* is_final = */ BROTLI_TRUE); + BlockSplitterFinishBlockDistance( + &arena->dist_blocks, /* is_final = */ BROTLI_TRUE); + + if (num_contexts > 1) { + MapStaticContexts(m, num_contexts, static_context_map, mb); + } +} + +void BrotliBuildMetaBlockGreedy(MemoryManager* m, + const uint8_t* ringbuffer, + size_t pos, + size_t mask, + uint8_t prev_byte, + uint8_t prev_byte2, + ContextLut literal_context_lut, + size_t num_contexts, + const uint32_t* static_context_map, + const Command* commands, + size_t n_commands, + MetaBlockSplit* mb) { + GreedyMetablockArena* arena = BROTLI_ALLOC(m, GreedyMetablockArena, 1); + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(arena)) return; + if (num_contexts == 1) { + BrotliBuildMetaBlockGreedyInternal(m, arena, ringbuffer, pos, mask, + prev_byte, prev_byte2, literal_context_lut, 1, NULL, commands, + n_commands, mb); + } else { + BrotliBuildMetaBlockGreedyInternal(m, arena, ringbuffer, pos, mask, + prev_byte, prev_byte2, literal_context_lut, num_contexts, + static_context_map, commands, n_commands, mb); + } + BROTLI_FREE(m, arena); +} + +void BrotliOptimizeHistograms(uint32_t num_distance_codes, + MetaBlockSplit* mb) { + uint8_t good_for_rle[BROTLI_NUM_COMMAND_SYMBOLS]; + size_t i; + for (i = 0; i < mb->literal_histograms_size; ++i) { + BrotliOptimizeHuffmanCountsForRle(256, mb->literal_histograms[i].data_, + good_for_rle); + } + for (i = 0; i < mb->command_histograms_size; ++i) { + BrotliOptimizeHuffmanCountsForRle(BROTLI_NUM_COMMAND_SYMBOLS, + mb->command_histograms[i].data_, + good_for_rle); + } + for (i = 0; i < mb->distance_histograms_size; ++i) { + BrotliOptimizeHuffmanCountsForRle(num_distance_codes, + mb->distance_histograms[i].data_, + good_for_rle); + } +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/metablock.h b/packages/runtime/vendor/brotli/c/enc/metablock.h new file mode 100644 index 000000000..e7d10526d --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/metablock.h @@ -0,0 +1,106 @@ +/* Copyright 2015 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Algorithms for distributing the literals and commands of a metablock between + block types and contexts. */ + +#ifndef BROTLI_ENC_METABLOCK_H_ +#define BROTLI_ENC_METABLOCK_H_ + +#include "../common/context.h" +#include "../common/platform.h" +#include "block_splitter.h" +#include "command.h" +#include "histogram.h" +#include "memory.h" +#include "params.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define BROTLI_MAX_STATIC_CONTEXTS 13 + +typedef struct MetaBlockSplit { + BlockSplit literal_split; + BlockSplit command_split; + BlockSplit distance_split; + uint32_t* literal_context_map; + size_t literal_context_map_size; + uint32_t* distance_context_map; + size_t distance_context_map_size; + HistogramLiteral* literal_histograms; + size_t literal_histograms_size; + HistogramCommand* command_histograms; + size_t command_histograms_size; + HistogramDistance* distance_histograms; + size_t distance_histograms_size; +} MetaBlockSplit; + +static BROTLI_INLINE void InitMetaBlockSplit(MetaBlockSplit* mb) { + BrotliInitBlockSplit(&mb->literal_split); + BrotliInitBlockSplit(&mb->command_split); + BrotliInitBlockSplit(&mb->distance_split); + mb->literal_context_map = 0; + mb->literal_context_map_size = 0; + mb->distance_context_map = 0; + mb->distance_context_map_size = 0; + mb->literal_histograms = 0; + mb->literal_histograms_size = 0; + mb->command_histograms = 0; + mb->command_histograms_size = 0; + mb->distance_histograms = 0; + mb->distance_histograms_size = 0; +} + +static BROTLI_INLINE void DestroyMetaBlockSplit( + MemoryManager* m, MetaBlockSplit* mb) { + BrotliDestroyBlockSplit(m, &mb->literal_split); + BrotliDestroyBlockSplit(m, &mb->command_split); + BrotliDestroyBlockSplit(m, &mb->distance_split); + BROTLI_FREE(m, mb->literal_context_map); + BROTLI_FREE(m, mb->distance_context_map); + BROTLI_FREE(m, mb->literal_histograms); + BROTLI_FREE(m, mb->command_histograms); + BROTLI_FREE(m, mb->distance_histograms); +} + +/* Uses the slow shortest-path block splitter and does context clustering. + The distance parameters are dynamically selected based on the commands + which get recomputed under the new distance parameters. The new distance + parameters are stored into *params. */ +BROTLI_INTERNAL void BrotliBuildMetaBlock(MemoryManager* m, + const uint8_t* ringbuffer, + const size_t pos, + const size_t mask, + BrotliEncoderParams* params, + uint8_t prev_byte, + uint8_t prev_byte2, + Command* cmds, + size_t num_commands, + ContextType literal_context_mode, + MetaBlockSplit* mb); + +/* Uses a fast greedy block splitter that tries to merge current block with the + last or the second last block and uses a static context clustering which + is the same for all block types. */ +BROTLI_INTERNAL void BrotliBuildMetaBlockGreedy( + MemoryManager* m, const uint8_t* ringbuffer, size_t pos, size_t mask, + uint8_t prev_byte, uint8_t prev_byte2, ContextLut literal_context_lut, + size_t num_contexts, const uint32_t* static_context_map, + const Command* commands, size_t n_commands, MetaBlockSplit* mb); + +BROTLI_INTERNAL void BrotliOptimizeHistograms(uint32_t num_distance_codes, + MetaBlockSplit* mb); + +BROTLI_INTERNAL void BrotliInitDistanceParams(BrotliDistanceParams* params, + uint32_t npostfix, uint32_t ndirect, BROTLI_BOOL large_window); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_METABLOCK_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/metablock_inc.h b/packages/runtime/vendor/brotli/c/enc/metablock_inc.h new file mode 100644 index 000000000..e7a7bc821 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/metablock_inc.h @@ -0,0 +1,185 @@ +/* NOLINT(build/header_guard) */ +/* Copyright 2015 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* template parameters: FN */ + +#define HistogramType FN(Histogram) + +/* Greedy block splitter for one block category (literal, command or distance). +*/ +typedef struct FN(BlockSplitter) { + /* Alphabet size of particular block category. */ + size_t alphabet_size_; + /* We collect at least this many symbols for each block. */ + size_t min_block_size_; + /* We merge histograms A and B if + entropy(A+B) < entropy(A) + entropy(B) + split_threshold_, + where A is the current histogram and B is the histogram of the last or the + second last block type. */ + double split_threshold_; + + size_t num_blocks_; + BlockSplit* split_; /* not owned */ + HistogramType* histograms_; /* not owned */ + size_t* histograms_size_; /* not owned */ + + /* Temporary storage for BlockSplitterFinishBlock. */ + HistogramType combined_histo[2]; + + /* The number of symbols that we want to collect before deciding on whether + or not to merge the block with a previous one or emit a new block. */ + size_t target_block_size_; + /* The number of symbols in the current histogram. */ + size_t block_size_; + /* Offset of the current histogram. */ + size_t curr_histogram_ix_; + /* Offset of the histograms of the previous two block types. */ + size_t last_histogram_ix_[2]; + /* Entropy of the previous two block types. */ + double last_entropy_[2]; + /* The number of times we merged the current block with the last one. */ + size_t merge_last_count_; +} FN(BlockSplitter); + +static void FN(InitBlockSplitter)( + MemoryManager* m, FN(BlockSplitter)* self, size_t alphabet_size, + size_t min_block_size, double split_threshold, size_t num_symbols, + BlockSplit* split, HistogramType** histograms, size_t* histograms_size) { + size_t max_num_blocks = num_symbols / min_block_size + 1; + /* We have to allocate one more histogram than the maximum number of block + types for the current histogram when the meta-block is too big. */ + size_t max_num_types = + BROTLI_MIN(size_t, max_num_blocks, BROTLI_MAX_NUMBER_OF_BLOCK_TYPES + 1); + self->alphabet_size_ = alphabet_size; + self->min_block_size_ = min_block_size; + self->split_threshold_ = split_threshold; + self->num_blocks_ = 0; + self->split_ = split; + self->histograms_size_ = histograms_size; + self->target_block_size_ = min_block_size; + self->block_size_ = 0; + self->curr_histogram_ix_ = 0; + self->merge_last_count_ = 0; + BROTLI_ENSURE_CAPACITY(m, uint8_t, + split->types, split->types_alloc_size, max_num_blocks); + BROTLI_ENSURE_CAPACITY(m, uint32_t, + split->lengths, split->lengths_alloc_size, max_num_blocks); + if (BROTLI_IS_OOM(m)) return; + self->split_->num_blocks = max_num_blocks; + BROTLI_DCHECK(*histograms == 0); + *histograms_size = max_num_types; + *histograms = BROTLI_ALLOC(m, HistogramType, *histograms_size); + self->histograms_ = *histograms; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return; + /* Clear only current histogram. */ + FN(HistogramClear)(&self->histograms_[0]); + self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0; +} + +/* Does either of three things: + (1) emits the current block with a new block type; + (2) emits the current block with the type of the second last block; + (3) merges the current block with the last block. */ +static void FN(BlockSplitterFinishBlock)( + FN(BlockSplitter)* self, BROTLI_BOOL is_final) { + BlockSplit* split = self->split_; + double* last_entropy = self->last_entropy_; + HistogramType* histograms = self->histograms_; + self->block_size_ = + BROTLI_MAX(size_t, self->block_size_, self->min_block_size_); + if (self->num_blocks_ == 0) { + /* Create first block. */ + split->lengths[0] = (uint32_t)self->block_size_; + split->types[0] = 0; + last_entropy[0] = + BrotliBitsEntropy(histograms[0].data_, self->alphabet_size_); + last_entropy[1] = last_entropy[0]; + ++self->num_blocks_; + ++split->num_types; + ++self->curr_histogram_ix_; + if (self->curr_histogram_ix_ < *self->histograms_size_) + FN(HistogramClear)(&histograms[self->curr_histogram_ix_]); + self->block_size_ = 0; + } else if (self->block_size_ > 0) { + double entropy = BrotliBitsEntropy( + histograms[self->curr_histogram_ix_].data_, self->alphabet_size_); + double combined_entropy[2]; + double diff[2]; + size_t j; + for (j = 0; j < 2; ++j) { + size_t last_histogram_ix = self->last_histogram_ix_[j]; + self->combined_histo[j] = histograms[self->curr_histogram_ix_]; + FN(HistogramAddHistogram)(&self->combined_histo[j], + &histograms[last_histogram_ix]); + combined_entropy[j] = BrotliBitsEntropy( + &self->combined_histo[j].data_[0], self->alphabet_size_); + diff[j] = combined_entropy[j] - entropy - last_entropy[j]; + } + + if (split->num_types < BROTLI_MAX_NUMBER_OF_BLOCK_TYPES && + diff[0] > self->split_threshold_ && + diff[1] > self->split_threshold_) { + /* Create new block. */ + split->lengths[self->num_blocks_] = (uint32_t)self->block_size_; + split->types[self->num_blocks_] = (uint8_t)split->num_types; + self->last_histogram_ix_[1] = self->last_histogram_ix_[0]; + self->last_histogram_ix_[0] = (uint8_t)split->num_types; + last_entropy[1] = last_entropy[0]; + last_entropy[0] = entropy; + ++self->num_blocks_; + ++split->num_types; + ++self->curr_histogram_ix_; + if (self->curr_histogram_ix_ < *self->histograms_size_) + FN(HistogramClear)(&histograms[self->curr_histogram_ix_]); + self->block_size_ = 0; + self->merge_last_count_ = 0; + self->target_block_size_ = self->min_block_size_; + } else if (diff[1] < diff[0] - 20.0) { + /* Combine this block with second last block. */ + split->lengths[self->num_blocks_] = (uint32_t)self->block_size_; + split->types[self->num_blocks_] = split->types[self->num_blocks_ - 2]; + BROTLI_SWAP(size_t, self->last_histogram_ix_, 0, 1); + histograms[self->last_histogram_ix_[0]] = self->combined_histo[1]; + last_entropy[1] = last_entropy[0]; + last_entropy[0] = combined_entropy[1]; + ++self->num_blocks_; + self->block_size_ = 0; + FN(HistogramClear)(&histograms[self->curr_histogram_ix_]); + self->merge_last_count_ = 0; + self->target_block_size_ = self->min_block_size_; + } else { + /* Combine this block with last block. */ + split->lengths[self->num_blocks_ - 1] += (uint32_t)self->block_size_; + histograms[self->last_histogram_ix_[0]] = self->combined_histo[0]; + last_entropy[0] = combined_entropy[0]; + if (split->num_types == 1) { + last_entropy[1] = last_entropy[0]; + } + self->block_size_ = 0; + FN(HistogramClear)(&histograms[self->curr_histogram_ix_]); + if (++self->merge_last_count_ > 1) { + self->target_block_size_ += self->min_block_size_; + } + } + } + if (is_final) { + *self->histograms_size_ = split->num_types; + split->num_blocks = self->num_blocks_; + } +} + +/* Adds the next symbol to the current histogram. When the current histogram + reaches the target size, decides on merging the block. */ +static void FN(BlockSplitterAddSymbol)(FN(BlockSplitter)* self, size_t symbol) { + FN(HistogramAdd)(&self->histograms_[self->curr_histogram_ix_], symbol); + ++self->block_size_; + if (self->block_size_ == self->target_block_size_) { + FN(BlockSplitterFinishBlock)(self, /* is_final = */ BROTLI_FALSE); + } +} + +#undef HistogramType diff --git a/packages/runtime/vendor/brotli/c/enc/params.h b/packages/runtime/vendor/brotli/c/enc/params.h new file mode 100644 index 000000000..fd1de0096 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/params.h @@ -0,0 +1,46 @@ +/* Copyright 2017 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Parameters for the Brotli encoder with chosen quality levels. */ + +#ifndef BROTLI_ENC_PARAMS_H_ +#define BROTLI_ENC_PARAMS_H_ + +#include +#include "encoder_dict.h" + +typedef struct BrotliHasherParams { + int type; + int bucket_bits; + int block_bits; + int num_last_distances_to_check; +} BrotliHasherParams; + +typedef struct BrotliDistanceParams { + uint32_t distance_postfix_bits; + uint32_t num_direct_distance_codes; + uint32_t alphabet_size_max; + uint32_t alphabet_size_limit; + size_t max_distance; +} BrotliDistanceParams; + +/* Encoding parameters */ +typedef struct BrotliEncoderParams { + BrotliEncoderMode mode; + int quality; + int lgwin; + int lgblock; + size_t stream_offset; + size_t size_hint; + BROTLI_BOOL disable_literal_context_modeling; + BROTLI_BOOL large_window; + BrotliHasherParams hasher; + BrotliDistanceParams dist; + /* TODO(eustas): rename to BrotliShared... */ + SharedEncoderDictionary dictionary; +} BrotliEncoderParams; + +#endif /* BROTLI_ENC_PARAMS_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/prefix.h b/packages/runtime/vendor/brotli/c/enc/prefix.h new file mode 100644 index 000000000..24c0afc17 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/prefix.h @@ -0,0 +1,52 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Functions for encoding of integers into prefix codes the amount of extra + bits, and the actual values of the extra bits. */ + +#ifndef BROTLI_ENC_PREFIX_H_ +#define BROTLI_ENC_PREFIX_H_ + +#include "../common/constants.h" +#include "../common/platform.h" +#include "fast_log.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* Here distance_code is an intermediate code, i.e. one of the special codes or + the actual distance increased by BROTLI_NUM_DISTANCE_SHORT_CODES - 1. */ +static BROTLI_INLINE void PrefixEncodeCopyDistance(size_t distance_code, + size_t num_direct_codes, + size_t postfix_bits, + uint16_t* code, + uint32_t* extra_bits) { + if (distance_code < BROTLI_NUM_DISTANCE_SHORT_CODES + num_direct_codes) { + *code = (uint16_t)distance_code; + *extra_bits = 0; + return; + } else { + size_t dist = ((size_t)1 << (postfix_bits + 2u)) + + (distance_code - BROTLI_NUM_DISTANCE_SHORT_CODES - num_direct_codes); + size_t bucket = Log2FloorNonZero(dist) - 1; + size_t postfix_mask = (1u << postfix_bits) - 1; + size_t postfix = dist & postfix_mask; + size_t prefix = (dist >> bucket) & 1; + size_t offset = (2 + prefix) << bucket; + size_t nbits = bucket - postfix_bits; + *code = (uint16_t)((nbits << 10) | + (BROTLI_NUM_DISTANCE_SHORT_CODES + num_direct_codes + + ((2 * (nbits - 1) + prefix) << postfix_bits) + postfix)); + *extra_bits = (uint32_t)((dist - offset) >> postfix_bits); + } +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_PREFIX_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/quality.h b/packages/runtime/vendor/brotli/c/enc/quality.h new file mode 100644 index 000000000..45d67bf40 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/quality.h @@ -0,0 +1,209 @@ +/* Copyright 2016 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Constants and formulas that affect speed-ratio trade-offs and thus define + quality levels. */ + +#ifndef BROTLI_ENC_QUALITY_H_ +#define BROTLI_ENC_QUALITY_H_ + +#include "../common/platform.h" +#include +#include "params.h" + +#define FAST_ONE_PASS_COMPRESSION_QUALITY 0 +#define FAST_TWO_PASS_COMPRESSION_QUALITY 1 +#define ZOPFLIFICATION_QUALITY 10 +#define HQ_ZOPFLIFICATION_QUALITY 11 + +#define MAX_QUALITY_FOR_STATIC_ENTROPY_CODES 2 +#define MIN_QUALITY_FOR_BLOCK_SPLIT 4 +#define MIN_QUALITY_FOR_NONZERO_DISTANCE_PARAMS 4 +#define MIN_QUALITY_FOR_OPTIMIZE_HISTOGRAMS 4 +#define MIN_QUALITY_FOR_EXTENSIVE_REFERENCE_SEARCH 5 +#define MIN_QUALITY_FOR_CONTEXT_MODELING 5 +#define MIN_QUALITY_FOR_HQ_CONTEXT_MODELING 7 +#define MIN_QUALITY_FOR_HQ_BLOCK_SPLITTING 10 + +/* For quality below MIN_QUALITY_FOR_BLOCK_SPLIT there is no block splitting, + so we buffer at most this much literals and commands. */ +#define MAX_NUM_DELAYED_SYMBOLS 0x2FFF + +/* Returns hash-table size for quality levels 0 and 1. */ +static BROTLI_INLINE size_t MaxHashTableSize(int quality) { + return quality == FAST_ONE_PASS_COMPRESSION_QUALITY ? 1 << 15 : 1 << 17; +} + +/* The maximum length for which the zopflification uses distinct distances. */ +#define MAX_ZOPFLI_LEN_QUALITY_10 150 +#define MAX_ZOPFLI_LEN_QUALITY_11 325 + +/* Do not thoroughly search when a long copy is found. */ +#define BROTLI_LONG_COPY_QUICK_STEP 16384 + +static BROTLI_INLINE size_t MaxZopfliLen(const BrotliEncoderParams* params) { + return params->quality <= 10 ? + MAX_ZOPFLI_LEN_QUALITY_10 : + MAX_ZOPFLI_LEN_QUALITY_11; +} + +/* Number of best candidates to evaluate to expand Zopfli chain. */ +static BROTLI_INLINE size_t MaxZopfliCandidates( + const BrotliEncoderParams* params) { + return params->quality <= 10 ? 1 : 5; +} + +static BROTLI_INLINE void SanitizeParams(BrotliEncoderParams* params) { + params->quality = BROTLI_MIN(int, BROTLI_MAX_QUALITY, + BROTLI_MAX(int, BROTLI_MIN_QUALITY, params->quality)); + if (params->quality <= MAX_QUALITY_FOR_STATIC_ENTROPY_CODES) { + params->large_window = BROTLI_FALSE; + } + if (params->lgwin < BROTLI_MIN_WINDOW_BITS) { + params->lgwin = BROTLI_MIN_WINDOW_BITS; + } else { + int max_lgwin = params->large_window ? BROTLI_LARGE_MAX_WINDOW_BITS : + BROTLI_MAX_WINDOW_BITS; + if (params->lgwin > max_lgwin) params->lgwin = max_lgwin; + } +} + +/* Returns optimized lg_block value. */ +static BROTLI_INLINE int ComputeLgBlock(const BrotliEncoderParams* params) { + int lgblock = params->lgblock; + if (params->quality == FAST_ONE_PASS_COMPRESSION_QUALITY || + params->quality == FAST_TWO_PASS_COMPRESSION_QUALITY) { + lgblock = params->lgwin; + } else if (params->quality < MIN_QUALITY_FOR_BLOCK_SPLIT) { + lgblock = 14; + } else if (lgblock == 0) { + lgblock = 16; + if (params->quality >= 9 && params->lgwin > lgblock) { + lgblock = BROTLI_MIN(int, 18, params->lgwin); + } + } else { + lgblock = BROTLI_MIN(int, BROTLI_MAX_INPUT_BLOCK_BITS, + BROTLI_MAX(int, BROTLI_MIN_INPUT_BLOCK_BITS, lgblock)); + } + return lgblock; +} + +/* Returns log2 of the size of main ring buffer area. + Allocate at least lgwin + 1 bits for the ring buffer so that the newly + added block fits there completely and we still get lgwin bits and at least + read_block_size_bits + 1 bits because the copy tail length needs to be + smaller than ring-buffer size. */ +static BROTLI_INLINE int ComputeRbBits(const BrotliEncoderParams* params) { + return 1 + BROTLI_MAX(int, params->lgwin, params->lgblock); +} + +static BROTLI_INLINE size_t MaxMetablockSize( + const BrotliEncoderParams* params) { + int bits = + BROTLI_MIN(int, ComputeRbBits(params), BROTLI_MAX_INPUT_BLOCK_BITS); + return (size_t)1 << bits; +} + +/* When searching for backward references and have not seen matches for a long + time, we can skip some match lookups. Unsuccessful match lookups are very + expensive and this kind of a heuristic speeds up compression quite a lot. + At first 8 byte strides are taken and every second byte is put to hasher. + After 4x more literals stride by 16 bytes, every put 4-th byte to hasher. + Applied only to qualities 2 to 9. */ +static BROTLI_INLINE size_t LiteralSpreeLengthForSparseSearch( + const BrotliEncoderParams* params) { + return params->quality < 9 ? 64 : 512; +} + +/* Quality to hasher mapping: + + - q02: h02 (longest_match_quickly), b16, l5 + + - q03: h03 (longest_match_quickly), b17, l5 + + - q04: h04 (longest_match_quickly), b17, l5 + - q04: h54 (longest_match_quickly), b20, l7 | for large files + + - q05: h58 (longest_match_simd ), b14, l4 + - q05: h68 (longest_match64_simd ), b15, l5 | for large files + - q05: h40 (forgetful_chain ), b15, l4 | for small window + + - q06: h58 (longest_match_simd ), b14, l4 + - q06: h68 (longest_match64_simd ), b15, l5 | for large files + - q06: h40 (forgetful_chain ), b15, l4 | for small window + + - q07: h58 (longest_match_simd ), b15, l4 + - q07: h68 (longest_match64_simd ), b15, l5 | for large files + - q07: h41 (forgetful_chain ), b15, l4 | for small window + + - q08: h05 (longest_match ), b15, l4 + - q08: h06 (longest_match64 ), b15, l5 | for large files + - q08: h41 (forgetful_chain ), b15, l4 | for small window + + - q09: h05 (longest_match ), b15, l4 + - q09: h06 (longest_match64 ), b15, l5 | for large files + - q09: h42 (forgetful_chain ), b15, l4 | for small window + + - q10: t10 (to_binary_tree ), b17, l128 + + - q11: t10 (to_binary_tree ), b17, l128 + + Where "q" is quality, "h" is hasher type, "b" is bucket bits, + "l" is source len. */ +static BROTLI_INLINE void ChooseHasher(const BrotliEncoderParams* params, + BrotliHasherParams* hparams) { + if (params->quality > 9) { + hparams->type = 10; + } else if (params->quality == 4 && params->size_hint >= (1 << 20)) { + hparams->type = 54; + } else if (params->quality < 5) { + hparams->type = params->quality; + } else if (params->lgwin <= 16) { + hparams->type = params->quality < 7 ? 40 : params->quality < 9 ? 41 : 42; + } else if (params->size_hint >= (1 << 20) && params->lgwin >= 19) { +#if defined(BROTLI_MAX_SIMD_QUALITY) + hparams->type = params->quality <= BROTLI_MAX_SIMD_QUALITY ? 68 : 6; +#else + hparams->type = 6; +#endif + hparams->block_bits = params->quality - 1; + hparams->bucket_bits = 15; + hparams->num_last_distances_to_check = + params->quality < 7 ? 4 : params->quality < 9 ? 10 : 16; + } else { + /* TODO(eustas): often previous setting (H6) is faster and denser; consider + adding an option to use it. */ +#if defined(BROTLI_MAX_SIMD_QUALITY) + hparams->type = params->quality <= BROTLI_MAX_SIMD_QUALITY ? 58 : 5; +#else + hparams->type = 5; +#endif + hparams->block_bits = params->quality - 1; + hparams->bucket_bits = params->quality < 7 ? 14 : 15; + hparams->num_last_distances_to_check = + params->quality < 7 ? 4 : params->quality < 9 ? 10 : 16; + } + + if (params->lgwin > 24) { + /* Different hashers for large window brotli: not for qualities <= 2, + these are too fast for large window. Not for qualities >= 10: their + hasher already works well with large window. So the changes are: + H3 --> H35: for quality 3. + H54 --> H55: for quality 4 with size hint > 1MB + H6/H68 --> H65: for qualities 5, 6, 7, 8, 9. */ + if (hparams->type == 3) { + hparams->type = 35; + } + if (hparams->type == 54) { + hparams->type = 55; + } + if (hparams->type == 6 || hparams->type == 68) { + hparams->type = 65; + } + } +} + +#endif /* BROTLI_ENC_QUALITY_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/ringbuffer.h b/packages/runtime/vendor/brotli/c/enc/ringbuffer.h new file mode 100644 index 000000000..5bb75ed7c --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/ringbuffer.h @@ -0,0 +1,165 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Sliding window over the input data. */ + +#ifndef BROTLI_ENC_RINGBUFFER_H_ +#define BROTLI_ENC_RINGBUFFER_H_ + +#include "../common/platform.h" +#include "memory.h" +#include "params.h" +#include "quality.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* A RingBuffer(window_bits, tail_bits) contains `1 << window_bits' bytes of + data in a circular manner: writing a byte writes it to: + `position() % (1 << window_bits)'. + For convenience, the RingBuffer array contains another copy of the + first `1 << tail_bits' bytes: + buffer_[i] == buffer_[i + (1 << window_bits)], if i < (1 << tail_bits), + and another copy of the last two bytes: + buffer_[-1] == buffer_[(1 << window_bits) - 1] and + buffer_[-2] == buffer_[(1 << window_bits) - 2]. */ +typedef struct RingBuffer { + /* Size of the ring-buffer is (1 << window_bits) + tail_size_. */ + const uint32_t size_; + const uint32_t mask_; + const uint32_t tail_size_; + const uint32_t total_size_; + + uint32_t cur_size_; + /* Position to write in the ring buffer. */ + uint32_t pos_; + /* The actual ring buffer containing the copy of the last two bytes, the data, + and the copy of the beginning as a tail. */ + uint8_t* data_; + /* The start of the ring-buffer. */ + uint8_t* buffer_; +} RingBuffer; + +static BROTLI_INLINE void RingBufferInit(RingBuffer* rb) { + rb->cur_size_ = 0; + rb->pos_ = 0; + rb->data_ = 0; + rb->buffer_ = 0; +} + +static BROTLI_INLINE void RingBufferSetup( + const BrotliEncoderParams* params, RingBuffer* rb) { + int window_bits = ComputeRbBits(params); + int tail_bits = params->lgblock; + *(uint32_t*)&rb->size_ = 1u << window_bits; + *(uint32_t*)&rb->mask_ = (1u << window_bits) - 1; + *(uint32_t*)&rb->tail_size_ = 1u << tail_bits; + *(uint32_t*)&rb->total_size_ = rb->size_ + rb->tail_size_; +} + +static BROTLI_INLINE void RingBufferFree(MemoryManager* m, RingBuffer* rb) { + BROTLI_FREE(m, rb->data_); +} + +/* Allocates or re-allocates data_ to the given length + plus some slack + region before and after. Fills the slack regions with zeros. */ +static BROTLI_INLINE void RingBufferInitBuffer( + MemoryManager* m, const uint32_t buflen, RingBuffer* rb) { + static const size_t kSlackForEightByteHashingEverywhere = 7; + uint8_t* new_data = BROTLI_ALLOC( + m, uint8_t, 2 + buflen + kSlackForEightByteHashingEverywhere); + size_t i; + if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(new_data)) return; + if (rb->data_) { + memcpy(new_data, rb->data_, + 2 + rb->cur_size_ + kSlackForEightByteHashingEverywhere); + BROTLI_FREE(m, rb->data_); + } + rb->data_ = new_data; + rb->cur_size_ = buflen; + rb->buffer_ = rb->data_ + 2; + rb->buffer_[-2] = rb->buffer_[-1] = 0; + for (i = 0; i < kSlackForEightByteHashingEverywhere; ++i) { + rb->buffer_[rb->cur_size_ + i] = 0; + } +} + +static BROTLI_INLINE void RingBufferWriteTail( + const uint8_t* bytes, size_t n, RingBuffer* rb) { + const size_t masked_pos = rb->pos_ & rb->mask_; + if (BROTLI_PREDICT_FALSE(masked_pos < rb->tail_size_)) { + /* Just fill the tail buffer with the beginning data. */ + const size_t p = rb->size_ + masked_pos; + memcpy(&rb->buffer_[p], bytes, + BROTLI_MIN(size_t, n, rb->tail_size_ - masked_pos)); + } +} + +/* Push bytes into the ring buffer. */ +static BROTLI_INLINE void RingBufferWrite( + MemoryManager* m, const uint8_t* bytes, size_t n, RingBuffer* rb) { + if (rb->pos_ == 0 && n < rb->tail_size_) { + /* Special case for the first write: to process the first block, we don't + need to allocate the whole ring-buffer and we don't need the tail + either. However, we do this memory usage optimization only if the + first write is less than the tail size, which is also the input block + size, otherwise it is likely that other blocks will follow and we + will need to reallocate to the full size anyway. */ + rb->pos_ = (uint32_t)n; + RingBufferInitBuffer(m, rb->pos_, rb); + if (BROTLI_IS_OOM(m)) return; + memcpy(rb->buffer_, bytes, n); + return; + } + if (rb->cur_size_ < rb->total_size_) { + /* Lazily allocate the full buffer. */ + RingBufferInitBuffer(m, rb->total_size_, rb); + if (BROTLI_IS_OOM(m)) return; + /* Initialize the last two bytes to zero, so that we don't have to worry + later when we copy the last two bytes to the first two positions. */ + rb->buffer_[rb->size_ - 2] = 0; + rb->buffer_[rb->size_ - 1] = 0; + /* Initialize tail; might be touched by "best_len++" optimization when + ring buffer is "full". */ + rb->buffer_[rb->size_] = 241; + } + { + const size_t masked_pos = rb->pos_ & rb->mask_; + /* The length of the writes is limited so that we do not need to worry + about a write */ + RingBufferWriteTail(bytes, n, rb); + if (BROTLI_PREDICT_TRUE(masked_pos + n <= rb->size_)) { + /* A single write fits. */ + memcpy(&rb->buffer_[masked_pos], bytes, n); + } else { + /* Split into two writes. + Copy into the end of the buffer, including the tail buffer. */ + memcpy(&rb->buffer_[masked_pos], bytes, + BROTLI_MIN(size_t, n, rb->total_size_ - masked_pos)); + /* Copy into the beginning of the buffer */ + memcpy(&rb->buffer_[0], bytes + (rb->size_ - masked_pos), + n - (rb->size_ - masked_pos)); + } + } + { + BROTLI_BOOL not_first_lap = (rb->pos_ & (1u << 31)) != 0; + uint32_t rb_pos_mask = (1u << 31) - 1; + rb->buffer_[-2] = rb->buffer_[rb->size_ - 2]; + rb->buffer_[-1] = rb->buffer_[rb->size_ - 1]; + rb->pos_ = (rb->pos_ & rb_pos_mask) + (uint32_t)(n & rb_pos_mask); + if (not_first_lap) { + /* Wrap, but preserve not-a-first-lap feature. */ + rb->pos_ |= 1u << 31; + } + } +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_RINGBUFFER_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/state.h b/packages/runtime/vendor/brotli/c/enc/state.h new file mode 100644 index 000000000..325f9f3dd --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/state.h @@ -0,0 +1,104 @@ +/* Copyright 2022 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Encoder state. */ + +#ifndef BROTLI_ENC_STATE_H_ +#define BROTLI_ENC_STATE_H_ + +#include "../common/constants.h" +#include "../common/platform.h" +#include "command.h" +#include "compress_fragment.h" +#include "compress_fragment_two_pass.h" +#include "hash.h" +#include "memory.h" +#include "params.h" +#include "ringbuffer.h" + +typedef enum BrotliEncoderStreamState { + /* Default state. */ + BROTLI_STREAM_PROCESSING = 0, + /* Intermediate state; after next block is emitted, byte-padding should be + performed before getting back to default state. */ + BROTLI_STREAM_FLUSH_REQUESTED = 1, + /* Last metablock was produced; no more input is acceptable. */ + BROTLI_STREAM_FINISHED = 2, + /* Flushing compressed block and writing meta-data block header. */ + BROTLI_STREAM_METADATA_HEAD = 3, + /* Writing metadata block body. */ + BROTLI_STREAM_METADATA_BODY = 4 +} BrotliEncoderStreamState; + +typedef enum BrotliEncoderFlintState { + BROTLI_FLINT_NEEDS_2_BYTES = 2, + BROTLI_FLINT_NEEDS_1_BYTE = 1, + BROTLI_FLINT_WAITING_FOR_PROCESSING = 0, + BROTLI_FLINT_WAITING_FOR_FLUSHING = -1, + BROTLI_FLINT_DONE = -2 +} BrotliEncoderFlintState; + +typedef struct BrotliEncoderStateStruct { + BrotliEncoderParams params; + + MemoryManager memory_manager_; + + uint64_t input_pos_; + RingBuffer ringbuffer_; + size_t cmd_alloc_size_; + Command* commands_; + size_t num_commands_; + size_t num_literals_; + size_t last_insert_len_; + uint64_t last_flush_pos_; + uint64_t last_processed_pos_; + int dist_cache_[BROTLI_NUM_DISTANCE_SHORT_CODES]; + int saved_dist_cache_[4]; + uint16_t last_bytes_; + uint8_t last_bytes_bits_; + /* "Flint" is a tiny uncompressed block emitted before the continuation + block to unwire literal context from previous data. Despite being int8_t, + field is actually BrotliEncoderFlintState enum. */ + int8_t flint_; + uint8_t prev_byte_; + uint8_t prev_byte2_; + size_t storage_size_; + uint8_t* storage_; + + Hasher hasher_; + + /* Hash table for FAST_ONE_PASS_COMPRESSION_QUALITY mode. */ + int small_table_[1 << 10]; /* 4KiB */ + int* large_table_; /* Allocated only when needed */ + size_t large_table_size_; + + BrotliOnePassArena* one_pass_arena_; + BrotliTwoPassArena* two_pass_arena_; + + /* Command and literal buffers for FAST_TWO_PASS_COMPRESSION_QUALITY. */ + uint32_t* command_buf_; + uint8_t* literal_buf_; + + uint64_t total_in_; + uint8_t* next_out_; + size_t available_out_; + uint64_t total_out_; + /* Temporary buffer for padding flush bits or metadata block header / body. */ + union { + uint64_t u64[2]; + uint8_t u8[16]; + } tiny_buf_; + uint32_t remaining_metadata_bytes_; + BrotliEncoderStreamState stream_state_; + + BROTLI_BOOL is_last_block_emitted_; + BROTLI_BOOL is_initialized_; +} BrotliEncoderStateStruct; + +typedef struct BrotliEncoderStateStruct BrotliEncoderStateInternal; +#define BrotliEncoderState BrotliEncoderStateInternal + +#endif // BROTLI_ENC_STATE_H_ diff --git a/packages/runtime/vendor/brotli/c/enc/static_dict.c b/packages/runtime/vendor/brotli/c/enc/static_dict.c new file mode 100644 index 000000000..854674600 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/static_dict.c @@ -0,0 +1,536 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#include "static_dict.h" + +#include "../common/dictionary.h" +#include "../common/platform.h" +#include "../common/transform.h" +#include "encoder_dict.h" +#include "find_match_length.h" +#include "hash_base.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +static BROTLI_INLINE void AddMatch(size_t distance, size_t len, size_t len_code, + uint32_t* matches) { + uint32_t match = (uint32_t)((distance << 5) + len_code); + matches[len] = BROTLI_MIN(uint32_t, matches[len], match); +} + +static BROTLI_INLINE size_t DictMatchLength(const BrotliDictionary* dictionary, + const uint8_t* data, + size_t id, + size_t len, + size_t maxlen) { + const size_t offset = dictionary->offsets_by_length[len] + len * id; + return FindMatchLengthWithLimit(&dictionary->data[offset], data, + BROTLI_MIN(size_t, len, maxlen)); +} + +static BROTLI_INLINE BROTLI_BOOL IsMatch(const BrotliDictionary* dictionary, + DictWord w, const uint8_t* data, size_t max_length) { + if (w.len > max_length) { + return BROTLI_FALSE; + } else { + const size_t offset = dictionary->offsets_by_length[w.len] + + (size_t)w.len * (size_t)w.idx; + const uint8_t* dict = &dictionary->data[offset]; + if (w.transform == 0) { + /* Match against base dictionary word. */ + return + TO_BROTLI_BOOL(FindMatchLengthWithLimit(dict, data, w.len) == w.len); + } else if (w.transform == 10) { + /* Match against uppercase first transform. + Note that there are only ASCII uppercase words in the lookup table. */ + return TO_BROTLI_BOOL(dict[0] >= 'a' && dict[0] <= 'z' && + (dict[0] ^ 32) == data[0] && + FindMatchLengthWithLimit(&dict[1], &data[1], w.len - 1u) == + w.len - 1u); + } else { + /* Match against uppercase all transform. + Note that there are only ASCII uppercase words in the lookup table. */ + size_t i; + for (i = 0; i < w.len; ++i) { + if (dict[i] >= 'a' && dict[i] <= 'z') { + if ((dict[i] ^ 32) != data[i]) return BROTLI_FALSE; + } else { + if (dict[i] != data[i]) return BROTLI_FALSE; + } + } + return BROTLI_TRUE; + } + } +} + +/* Finds matches for a single static dictionary */ +static BROTLI_BOOL BrotliFindAllStaticDictionaryMatchesFor( + const BrotliEncoderDictionary* dictionary, const uint8_t* data, + size_t min_length, size_t max_length, uint32_t* matches) { + BROTLI_BOOL has_found_match = BROTLI_FALSE; +#if defined(BROTLI_EXPERIMENTAL) + if (dictionary->has_words_heavy) { + const BrotliTrieNode* node = &dictionary->trie.root; + size_t l = 0; + while (node && l < max_length) { + uint8_t c; + if (l >= min_length && node->len_) { + AddMatch(node->idx_, l, node->len_, matches); + has_found_match = BROTLI_TRUE; + } + c = data[l++]; + node = BrotliTrieSub(&dictionary->trie, node, c); + } + return has_found_match; + } +#endif /* BROTLI_EXPERIMENTAL */ + { + size_t offset = dictionary->buckets[Hash15(data)]; + BROTLI_BOOL end = !offset; + while (!end) { + DictWord w = dictionary->dict_words[offset++]; + const size_t l = w.len & 0x1F; + const size_t n = (size_t)1 << dictionary->words->size_bits_by_length[l]; + const size_t id = w.idx; + end = !!(w.len & 0x80); + w.len = (uint8_t)l; + if (w.transform == 0) { + const size_t matchlen = + DictMatchLength(dictionary->words, data, id, l, max_length); + const uint8_t* s; + size_t minlen; + size_t maxlen; + size_t len; + /* Transform "" + BROTLI_TRANSFORM_IDENTITY + "" */ + if (matchlen == l) { + AddMatch(id, l, l, matches); + has_found_match = BROTLI_TRUE; + } + /* Transforms "" + BROTLI_TRANSFORM_OMIT_LAST_1 + "" and + "" + BROTLI_TRANSFORM_OMIT_LAST_1 + "ing " */ + if (matchlen >= l - 1) { + AddMatch(id + 12 * n, l - 1, l, matches); + if (l + 2 < max_length && + data[l - 1] == 'i' && data[l] == 'n' && data[l + 1] == 'g' && + data[l + 2] == ' ') { + AddMatch(id + 49 * n, l + 3, l, matches); + } + has_found_match = BROTLI_TRUE; + } + /* Transform "" + BROTLI_TRANSFORM_OMIT_LAST_# + "" (# = 2 .. 9) */ + minlen = min_length; + if (l > 9) minlen = BROTLI_MAX(size_t, minlen, l - 9); + maxlen = BROTLI_MIN(size_t, matchlen, l - 2); + for (len = minlen; len <= maxlen; ++len) { + size_t cut = l - len; + size_t transform_id = (cut << 2) + + (size_t)((dictionary->cutoffTransforms >> (cut * 6)) & 0x3F); + AddMatch(id + transform_id * n, len, l, matches); + has_found_match = BROTLI_TRUE; + } + if (matchlen < l || l + 6 >= max_length) { + continue; + } + s = &data[l]; + /* Transforms "" + BROTLI_TRANSFORM_IDENTITY + */ + if (s[0] == ' ') { + AddMatch(id + n, l + 1, l, matches); + if (s[1] == 'a') { + if (s[2] == ' ') { + AddMatch(id + 28 * n, l + 3, l, matches); + } else if (s[2] == 's') { + if (s[3] == ' ') AddMatch(id + 46 * n, l + 4, l, matches); + } else if (s[2] == 't') { + if (s[3] == ' ') AddMatch(id + 60 * n, l + 4, l, matches); + } else if (s[2] == 'n') { + if (s[3] == 'd' && s[4] == ' ') { + AddMatch(id + 10 * n, l + 5, l, matches); + } + } + } else if (s[1] == 'b') { + if (s[2] == 'y' && s[3] == ' ') { + AddMatch(id + 38 * n, l + 4, l, matches); + } + } else if (s[1] == 'i') { + if (s[2] == 'n') { + if (s[3] == ' ') AddMatch(id + 16 * n, l + 4, l, matches); + } else if (s[2] == 's') { + if (s[3] == ' ') AddMatch(id + 47 * n, l + 4, l, matches); + } + } else if (s[1] == 'f') { + if (s[2] == 'o') { + if (s[3] == 'r' && s[4] == ' ') { + AddMatch(id + 25 * n, l + 5, l, matches); + } + } else if (s[2] == 'r') { + if (s[3] == 'o' && s[4] == 'm' && s[5] == ' ') { + AddMatch(id + 37 * n, l + 6, l, matches); + } + } + } else if (s[1] == 'o') { + if (s[2] == 'f') { + if (s[3] == ' ') AddMatch(id + 8 * n, l + 4, l, matches); + } else if (s[2] == 'n') { + if (s[3] == ' ') AddMatch(id + 45 * n, l + 4, l, matches); + } + } else if (s[1] == 'n') { + if (s[2] == 'o' && s[3] == 't' && s[4] == ' ') { + AddMatch(id + 80 * n, l + 5, l, matches); + } + } else if (s[1] == 't') { + if (s[2] == 'h') { + if (s[3] == 'e') { + if (s[4] == ' ') AddMatch(id + 5 * n, l + 5, l, matches); + } else if (s[3] == 'a') { + if (s[4] == 't' && s[5] == ' ') { + AddMatch(id + 29 * n, l + 6, l, matches); + } + } + } else if (s[2] == 'o') { + if (s[3] == ' ') AddMatch(id + 17 * n, l + 4, l, matches); + } + } else if (s[1] == 'w') { + if (s[2] == 'i' && s[3] == 't' && s[4] == 'h' && s[5] == ' ') { + AddMatch(id + 35 * n, l + 6, l, matches); + } + } + } else if (s[0] == '"') { + AddMatch(id + 19 * n, l + 1, l, matches); + if (s[1] == '>') { + AddMatch(id + 21 * n, l + 2, l, matches); + } + } else if (s[0] == '.') { + AddMatch(id + 20 * n, l + 1, l, matches); + if (s[1] == ' ') { + AddMatch(id + 31 * n, l + 2, l, matches); + if (s[2] == 'T' && s[3] == 'h') { + if (s[4] == 'e') { + if (s[5] == ' ') AddMatch(id + 43 * n, l + 6, l, matches); + } else if (s[4] == 'i') { + if (s[5] == 's' && s[6] == ' ') { + AddMatch(id + 75 * n, l + 7, l, matches); + } + } + } + } + } else if (s[0] == ',') { + AddMatch(id + 76 * n, l + 1, l, matches); + if (s[1] == ' ') { + AddMatch(id + 14 * n, l + 2, l, matches); + } + } else if (s[0] == '\n') { + AddMatch(id + 22 * n, l + 1, l, matches); + if (s[1] == '\t') { + AddMatch(id + 50 * n, l + 2, l, matches); + } + } else if (s[0] == ']') { + AddMatch(id + 24 * n, l + 1, l, matches); + } else if (s[0] == '\'') { + AddMatch(id + 36 * n, l + 1, l, matches); + } else if (s[0] == ':') { + AddMatch(id + 51 * n, l + 1, l, matches); + } else if (s[0] == '(') { + AddMatch(id + 57 * n, l + 1, l, matches); + } else if (s[0] == '=') { + if (s[1] == '"') { + AddMatch(id + 70 * n, l + 2, l, matches); + } else if (s[1] == '\'') { + AddMatch(id + 86 * n, l + 2, l, matches); + } + } else if (s[0] == 'a') { + if (s[1] == 'l' && s[2] == ' ') { + AddMatch(id + 84 * n, l + 3, l, matches); + } + } else if (s[0] == 'e') { + if (s[1] == 'd') { + if (s[2] == ' ') AddMatch(id + 53 * n, l + 3, l, matches); + } else if (s[1] == 'r') { + if (s[2] == ' ') AddMatch(id + 82 * n, l + 3, l, matches); + } else if (s[1] == 's') { + if (s[2] == 't' && s[3] == ' ') { + AddMatch(id + 95 * n, l + 4, l, matches); + } + } + } else if (s[0] == 'f') { + if (s[1] == 'u' && s[2] == 'l' && s[3] == ' ') { + AddMatch(id + 90 * n, l + 4, l, matches); + } + } else if (s[0] == 'i') { + if (s[1] == 'v') { + if (s[2] == 'e' && s[3] == ' ') { + AddMatch(id + 92 * n, l + 4, l, matches); + } + } else if (s[1] == 'z') { + if (s[2] == 'e' && s[3] == ' ') { + AddMatch(id + 100 * n, l + 4, l, matches); + } + } + } else if (s[0] == 'l') { + if (s[1] == 'e') { + if (s[2] == 's' && s[3] == 's' && s[4] == ' ') { + AddMatch(id + 93 * n, l + 5, l, matches); + } + } else if (s[1] == 'y') { + if (s[2] == ' ') AddMatch(id + 61 * n, l + 3, l, matches); + } + } else if (s[0] == 'o') { + if (s[1] == 'u' && s[2] == 's' && s[3] == ' ') { + AddMatch(id + 106 * n, l + 4, l, matches); + } + } + } else { + /* Set is_all_caps=0 for BROTLI_TRANSFORM_UPPERCASE_FIRST and + is_all_caps=1 otherwise (BROTLI_TRANSFORM_UPPERCASE_ALL) + transform. */ + const BROTLI_BOOL is_all_caps = + TO_BROTLI_BOOL(w.transform != BROTLI_TRANSFORM_UPPERCASE_FIRST); + const uint8_t* s; + if (!IsMatch(dictionary->words, w, data, max_length)) { + continue; + } + /* Transform "" + kUppercase{First,All} + "" */ + AddMatch(id + (is_all_caps ? 44 : 9) * n, l, l, matches); + has_found_match = BROTLI_TRUE; + if (l + 1 >= max_length) { + continue; + } + /* Transforms "" + kUppercase{First,All} + */ + s = &data[l]; + if (s[0] == ' ') { + AddMatch(id + (is_all_caps ? 68 : 4) * n, l + 1, l, matches); + } else if (s[0] == '"') { + AddMatch(id + (is_all_caps ? 87 : 66) * n, l + 1, l, matches); + if (s[1] == '>') { + AddMatch(id + (is_all_caps ? 97 : 69) * n, l + 2, l, matches); + } + } else if (s[0] == '.') { + AddMatch(id + (is_all_caps ? 101 : 79) * n, l + 1, l, matches); + if (s[1] == ' ') { + AddMatch(id + (is_all_caps ? 114 : 88) * n, l + 2, l, matches); + } + } else if (s[0] == ',') { + AddMatch(id + (is_all_caps ? 112 : 99) * n, l + 1, l, matches); + if (s[1] == ' ') { + AddMatch(id + (is_all_caps ? 107 : 58) * n, l + 2, l, matches); + } + } else if (s[0] == '\'') { + AddMatch(id + (is_all_caps ? 94 : 74) * n, l + 1, l, matches); + } else if (s[0] == '(') { + AddMatch(id + (is_all_caps ? 113 : 78) * n, l + 1, l, matches); + } else if (s[0] == '=') { + if (s[1] == '"') { + AddMatch(id + (is_all_caps ? 105 : 104) * n, l + 2, l, matches); + } else if (s[1] == '\'') { + AddMatch(id + (is_all_caps ? 116 : 108) * n, l + 2, l, matches); + } + } + } + } + } + /* Transforms with prefixes " " and "." */ + if (max_length >= 5 && (data[0] == ' ' || data[0] == '.')) { + BROTLI_BOOL is_space = TO_BROTLI_BOOL(data[0] == ' '); + size_t offset = dictionary->buckets[Hash15(&data[1])]; + BROTLI_BOOL end = !offset; + while (!end) { + DictWord w = dictionary->dict_words[offset++]; + const size_t l = w.len & 0x1F; + const size_t n = (size_t)1 << dictionary->words->size_bits_by_length[l]; + const size_t id = w.idx; + end = !!(w.len & 0x80); + w.len = (uint8_t)l; + if (w.transform == 0) { + const uint8_t* s; + if (!IsMatch(dictionary->words, w, &data[1], max_length - 1)) { + continue; + } + /* Transforms " " + BROTLI_TRANSFORM_IDENTITY + "" and + "." + BROTLI_TRANSFORM_IDENTITY + "" */ + AddMatch(id + (is_space ? 6 : 32) * n, l + 1, l, matches); + has_found_match = BROTLI_TRUE; + if (l + 2 >= max_length) { + continue; + } + /* Transforms " " + BROTLI_TRANSFORM_IDENTITY + and + "." + BROTLI_TRANSFORM_IDENTITY + + */ + s = &data[l + 1]; + if (s[0] == ' ') { + AddMatch(id + (is_space ? 2 : 77) * n, l + 2, l, matches); + } else if (s[0] == '(') { + AddMatch(id + (is_space ? 89 : 67) * n, l + 2, l, matches); + } else if (is_space) { + if (s[0] == ',') { + AddMatch(id + 103 * n, l + 2, l, matches); + if (s[1] == ' ') { + AddMatch(id + 33 * n, l + 3, l, matches); + } + } else if (s[0] == '.') { + AddMatch(id + 71 * n, l + 2, l, matches); + if (s[1] == ' ') { + AddMatch(id + 52 * n, l + 3, l, matches); + } + } else if (s[0] == '=') { + if (s[1] == '"') { + AddMatch(id + 81 * n, l + 3, l, matches); + } else if (s[1] == '\'') { + AddMatch(id + 98 * n, l + 3, l, matches); + } + } + } + } else if (is_space) { + /* Set is_all_caps=0 for BROTLI_TRANSFORM_UPPERCASE_FIRST and + is_all_caps=1 otherwise (BROTLI_TRANSFORM_UPPERCASE_ALL) + transform. */ + const BROTLI_BOOL is_all_caps = + TO_BROTLI_BOOL(w.transform != BROTLI_TRANSFORM_UPPERCASE_FIRST); + const uint8_t* s; + if (!IsMatch(dictionary->words, w, &data[1], max_length - 1)) { + continue; + } + /* Transforms " " + kUppercase{First,All} + "" */ + AddMatch(id + (is_all_caps ? 85 : 30) * n, l + 1, l, matches); + has_found_match = BROTLI_TRUE; + if (l + 2 >= max_length) { + continue; + } + /* Transforms " " + kUppercase{First,All} + */ + s = &data[l + 1]; + if (s[0] == ' ') { + AddMatch(id + (is_all_caps ? 83 : 15) * n, l + 2, l, matches); + } else if (s[0] == ',') { + if (!is_all_caps) { + AddMatch(id + 109 * n, l + 2, l, matches); + } + if (s[1] == ' ') { + AddMatch(id + (is_all_caps ? 111 : 65) * n, l + 3, l, matches); + } + } else if (s[0] == '.') { + AddMatch(id + (is_all_caps ? 115 : 96) * n, l + 2, l, matches); + if (s[1] == ' ') { + AddMatch(id + (is_all_caps ? 117 : 91) * n, l + 3, l, matches); + } + } else if (s[0] == '=') { + if (s[1] == '"') { + AddMatch(id + (is_all_caps ? 110 : 118) * n, l + 3, l, matches); + } else if (s[1] == '\'') { + AddMatch(id + (is_all_caps ? 119 : 120) * n, l + 3, l, matches); + } + } + } + } + } + if (max_length >= 6) { + /* Transforms with prefixes "e ", "s ", ", " and "\xC2\xA0" */ + if ((data[1] == ' ' && + (data[0] == 'e' || data[0] == 's' || data[0] == ',')) || + (data[0] == 0xC2 && data[1] == 0xA0)) { + size_t offset = dictionary->buckets[Hash15(&data[2])]; + BROTLI_BOOL end = !offset; + while (!end) { + DictWord w = dictionary->dict_words[offset++]; + const size_t l = w.len & 0x1F; + const size_t n = (size_t)1 << dictionary->words->size_bits_by_length[l]; + const size_t id = w.idx; + end = !!(w.len & 0x80); + w.len = (uint8_t)l; + if (w.transform == 0 && + IsMatch(dictionary->words, w, &data[2], max_length - 2)) { + if (data[0] == 0xC2) { + AddMatch(id + 102 * n, l + 2, l, matches); + has_found_match = BROTLI_TRUE; + } else if (l + 2 < max_length && data[l + 2] == ' ') { + size_t t = data[0] == 'e' ? 18 : (data[0] == 's' ? 7 : 13); + AddMatch(id + t * n, l + 3, l, matches); + has_found_match = BROTLI_TRUE; + } + } + } + } + } + if (max_length >= 9) { + /* Transforms with prefixes " the " and ".com/" */ + if ((data[0] == ' ' && data[1] == 't' && data[2] == 'h' && + data[3] == 'e' && data[4] == ' ') || + (data[0] == '.' && data[1] == 'c' && data[2] == 'o' && + data[3] == 'm' && data[4] == '/')) { + size_t offset = dictionary->buckets[Hash15(&data[5])]; + BROTLI_BOOL end = !offset; + while (!end) { + DictWord w = dictionary->dict_words[offset++]; + const size_t l = w.len & 0x1F; + const size_t n = (size_t)1 << dictionary->words->size_bits_by_length[l]; + const size_t id = w.idx; + end = !!(w.len & 0x80); + w.len = (uint8_t)l; + if (w.transform == 0 && + IsMatch(dictionary->words, w, &data[5], max_length - 5)) { + AddMatch(id + (data[0] == ' ' ? 41 : 72) * n, l + 5, l, matches); + has_found_match = BROTLI_TRUE; + if (l + 5 < max_length) { + const uint8_t* s = &data[l + 5]; + if (data[0] == ' ') { + if (l + 8 < max_length && + s[0] == ' ' && s[1] == 'o' && s[2] == 'f' && s[3] == ' ') { + AddMatch(id + 62 * n, l + 9, l, matches); + if (l + 12 < max_length && + s[4] == 't' && s[5] == 'h' && s[6] == 'e' && s[7] == ' ') { + AddMatch(id + 73 * n, l + 13, l, matches); + } + } + } + } + } + } + } + } + return has_found_match; +} + +/* Finds matches for one or more dictionaries, if multiple are present + in the contextual dictionary */ +BROTLI_BOOL BrotliFindAllStaticDictionaryMatches( + const BrotliEncoderDictionary* dictionary, const uint8_t* data, + size_t min_length, size_t max_length, uint32_t* matches) { + BROTLI_BOOL has_found_match = + BrotliFindAllStaticDictionaryMatchesFor( + dictionary, data, min_length, max_length, matches); + + if (!!dictionary->parent && dictionary->parent->num_dictionaries > 1) { + uint32_t matches2[BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN + 1]; + int l; + const BrotliEncoderDictionary* dictionary2 = dictionary->parent->dict[0]; + if (dictionary2 == dictionary) { + dictionary2 = dictionary->parent->dict[1]; + } + + for (l = 0; l < BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN + 1; l++) { + matches2[l] = kInvalidMatch; + } + + has_found_match |= BrotliFindAllStaticDictionaryMatchesFor( + dictionary2, data, min_length, max_length, matches2); + + for (l = 0; l < BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN + 1; l++) { + if (matches2[l] != kInvalidMatch) { + uint32_t dist = (uint32_t)(matches2[l] >> 5); + uint32_t len_code = matches2[l] & 31; + uint32_t skipdist = (uint32_t)((uint32_t)(1 << dictionary->words-> + size_bits_by_length[len_code]) & ~1u) * + (uint32_t)dictionary->num_transforms; + /* TODO(lode): check for dist overflow */ + dist += skipdist; + AddMatch(dist, (size_t)l, len_code, matches); + } + } + } + return has_found_match; +} +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/static_dict.h b/packages/runtime/vendor/brotli/c/enc/static_dict.h new file mode 100644 index 000000000..bc69b1591 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/static_dict.h @@ -0,0 +1,39 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Class to model the static dictionary. */ + +#ifndef BROTLI_ENC_STATIC_DICT_H_ +#define BROTLI_ENC_STATIC_DICT_H_ + +#include "../common/platform.h" + +#include "encoder_dict.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN 37 +static const uint32_t kInvalidMatch = 0xFFFFFFF; + +/* Matches data against static dictionary words, and for each length l, + for which a match is found, updates matches[l] to be the minimum possible + (distance << 5) + len_code. + Returns 1 if matches have been found, otherwise 0. + Prerequisites: + matches array is at least BROTLI_MAX_STATIC_DICTIONARY_MATCH_LEN + 1 long + all elements are initialized to kInvalidMatch */ +BROTLI_INTERNAL BROTLI_BOOL BrotliFindAllStaticDictionaryMatches( + const BrotliEncoderDictionary* dictionary, + const uint8_t* data, size_t min_length, size_t max_length, + uint32_t* matches); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_STATIC_DICT_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/static_dict_lut.c b/packages/runtime/vendor/brotli/c/enc/static_dict_lut.c new file mode 100644 index 000000000..109366f60 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/static_dict_lut.c @@ -0,0 +1,224 @@ +/* Copyright 2025 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Lookup table for static dictionary and transforms. */ + +#include "static_dict_lut.h" + +#include "../common/platform.h" /* IWYU pragma: keep */ +#include "../common/static_init.h" + +#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE) +#include "../common/dictionary.h" +#include "../common/transform.h" +#include "hash_base.h" +#endif + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE) + +/* TODO(eustas): deal with largest bucket(s). Not it contains 163 items. */ +static BROTLI_BOOL BROTLI_COLD DoBrotliEncoderInitStaticDictionaryLut( + const BrotliDictionary* dict, uint16_t* buckets, DictWord* words, + void* arena) { + DictWord* slots = (DictWord*)arena; + uint16_t* heads = (uint16_t*)(slots + BROTLI_ENC_STATIC_DICT_LUT_NUM_ITEMS); + uint16_t* counts = heads + BROTLI_ENC_STATIC_DICT_LUT_NUM_BUCKETS; + uint16_t* prev = counts + BROTLI_ENC_STATIC_DICT_LUT_NUM_BUCKETS; + size_t next_slot = 0; + uint8_t transformed_word[24]; + uint8_t transformed_other_word[24]; + size_t l; + size_t pos; + size_t i; + + memset(counts, 0, BROTLI_ENC_STATIC_DICT_LUT_NUM_BUCKETS * sizeof(uint16_t)); + memset(heads, 0, BROTLI_ENC_STATIC_DICT_LUT_NUM_BUCKETS * sizeof(uint16_t)); + memset(prev, 0, BROTLI_ENC_STATIC_DICT_LUT_NUM_ITEMS * sizeof(uint16_t)); + + for (l = 4; l <= 24; ++l) { + size_t n = 1u << dict->size_bits_by_length[l]; + const uint8_t* dict_words = dict->data + dict->offsets_by_length[l]; + for (i = 0; i < n; ++i) { + const uint8_t* dict_word = dict_words + l * i; + uint32_t key = Hash15(dict_word); + slots[next_slot].len = (uint8_t)l; + slots[next_slot].transform = BROTLI_TRANSFORM_IDENTITY; + slots[next_slot].idx = (uint16_t)i; + prev[next_slot] = heads[key]; + heads[key] = (uint16_t)next_slot; + counts[key]++; + ++next_slot; + } + for (i = 0; i < n; ++i) { + uint32_t key; + uint32_t prefix; + BROTLI_BOOL found; + size_t curr; + const uint8_t* dict_word = dict_words + l * i; + if (dict_word[0] < 'a' || dict_word[0] > 'z') continue; + memcpy(transformed_word, dict_word, l); + transformed_word[0] = transformed_word[0] - 32; + key = Hash15(transformed_word); + prefix = BROTLI_UNALIGNED_LOAD32LE(transformed_word) & ~0x20202020u; + found = BROTLI_FALSE; + curr = heads[key]; + while (curr != 0) { + const uint8_t* other_word; + uint32_t other_prefix; + if (slots[curr].len != l) break; + other_word = dict_words + l * slots[curr].idx; + other_prefix = BROTLI_UNALIGNED_LOAD32LE(other_word) & ~0x20202020u; + if (prefix == other_prefix) { + if (memcmp(transformed_word, other_word, l) == 0) { + found = BROTLI_TRUE; + break; + } + } + curr = prev[curr]; + } + if (found) continue; + slots[next_slot].len = (uint8_t)l; + slots[next_slot].transform = BROTLI_TRANSFORM_UPPERCASE_FIRST; + slots[next_slot].idx = (uint16_t)i; + prev[next_slot] = heads[key]; + heads[key] = (uint16_t)next_slot; + counts[key]++; + ++next_slot; + } + for (i = 0; i < n; ++i) { + const uint8_t* dict_word = dict_words + l * i; + BROTLI_BOOL is_ascii = BROTLI_TRUE; + BROTLI_BOOL has_lower = BROTLI_FALSE; + size_t k; + uint32_t prefix; + uint32_t key; + size_t curr; + BROTLI_BOOL found; + for (k = 0; k < l; ++k) { + if (dict_word[k] >= 128) is_ascii = BROTLI_FALSE; + if (k > 0 && dict_word[k] >= 'a' && dict_word[k] <= 'z') + has_lower = BROTLI_TRUE; + } + if (!is_ascii || !has_lower) continue; + memcpy(transformed_word, dict_word, l); + prefix = BROTLI_UNALIGNED_LOAD32LE(transformed_word) & ~0x20202020u; + for (k = 0; k < l; ++k) { + if (transformed_word[k] >= 'a' && transformed_word[k] <= 'z') { + transformed_word[k] = transformed_word[k] - 32; + } + } + key = Hash15(transformed_word); + found = BROTLI_FALSE; + curr = heads[key]; + while (curr != 0) { + const uint8_t* other_word; + uint32_t other_prefix; + if (slots[curr].len != l) break; + other_word = dict_words + l * slots[curr].idx; + other_prefix = BROTLI_UNALIGNED_LOAD32LE(other_word) & ~0x20202020u; + if (prefix == other_prefix) { + if (slots[curr].transform == BROTLI_TRANSFORM_IDENTITY) { + if (memcmp(transformed_word, other_word, l) == 0) { + found = BROTLI_TRUE; + break; + } + } else if (slots[curr].transform == + BROTLI_TRANSFORM_UPPERCASE_FIRST) { + if ((transformed_word[0] == (other_word[0] - 32)) && + memcmp(transformed_word + 1, other_word + 1, l - 1) == 0) { + found = BROTLI_TRUE; + break; + } + } else { + for (k = 0; k < l; ++k) { + if (other_word[k] >= 'a' && other_word[k] <= 'z') { + transformed_other_word[k] = other_word[k] - 32; + } else { + transformed_other_word[k] = other_word[k]; + } + } + if (memcmp(transformed_word, transformed_other_word, l) == 0) { + found = BROTLI_TRUE; + break; + } + } + } + curr = prev[curr]; + } + if (found) { + continue; + } + slots[next_slot].len = (uint8_t)l; + slots[next_slot].transform = BROTLI_TRANSFORM_UPPERCASE_ALL; + slots[next_slot].idx = (uint16_t)i; + prev[next_slot] = heads[key]; + heads[key] = (uint16_t)next_slot; + counts[key]++; + ++next_slot; + } + } + + if (next_slot != 31704) return BROTLI_FALSE; + pos = 0; + /* Unused; makes offsets start from 1. */ + words[pos].len = 0; + words[pos].transform = 0; + words[pos].idx = 0; + pos++; + for (i = 0; i < BROTLI_ENC_STATIC_DICT_LUT_NUM_BUCKETS; ++i) { + size_t num_words = counts[i]; + size_t curr; + if (num_words == 0) { + buckets[i] = 0; + continue; + } + buckets[i] = (uint16_t)pos; + curr = heads[i]; + pos += num_words; + for (size_t k = 0; k < num_words; ++k) { + words[pos - 1 - k] = slots[curr]; + curr = prev[curr]; + } + words[pos - 1].len |= 0x80; + } + return BROTLI_TRUE; +} + +BROTLI_BOOL BrotliEncoderInitStaticDictionaryLut( + const BrotliDictionary* dict, uint16_t* buckets, DictWord* words) { + size_t arena_size = + BROTLI_ENC_STATIC_DICT_LUT_NUM_ITEMS * + (sizeof(uint16_t) + sizeof(DictWord)) + + BROTLI_ENC_STATIC_DICT_LUT_NUM_BUCKETS * 2 * sizeof(uint16_t); + void* arena = malloc(arena_size); + BROTLI_BOOL ok; + if (arena == NULL) { + return BROTLI_FALSE; + } + ok = DoBrotliEncoderInitStaticDictionaryLut(dict, buckets, words, arena); + free(arena); + return ok; +} + +BROTLI_MODEL("small") +uint16_t kStaticDictionaryBuckets[BROTLI_ENC_STATIC_DICT_LUT_NUM_BUCKETS]; +BROTLI_MODEL("small") +DictWord kStaticDictionaryWords[BROTLI_ENC_STATIC_DICT_LUT_NUM_ITEMS]; + +#else /* BROTLI_STATIC_INIT */ + +/* Embed kStaticDictionaryBuckets and kStaticDictionaryWords. */ +#include "static_dict_lut_inc.h" + +#endif /* BROTLI_STATIC_INIT */ + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/static_dict_lut.h b/packages/runtime/vendor/brotli/c/enc/static_dict_lut.h new file mode 100644 index 000000000..078f55424 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/static_dict_lut.h @@ -0,0 +1,49 @@ +/* Copyright 2015 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Lookup table for static dictionary and transforms. */ + +#ifndef BROTLI_ENC_STATIC_DICT_LUT_H_ +#define BROTLI_ENC_STATIC_DICT_LUT_H_ + +#include "../common/dictionary.h" +#include "../common/platform.h" +#include "../common/static_init.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +typedef struct DictWord { + /* Highest bit is used to indicate end of bucket. */ + uint8_t len; + uint8_t transform; + uint16_t idx; +} DictWord; + +/* Buckets are Hash15 results. */ +#define BROTLI_ENC_STATIC_DICT_LUT_NUM_BUCKETS 32768 +#define BROTLI_ENC_STATIC_DICT_LUT_NUM_ITEMS 31705 + +#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE) +BROTLI_INTERNAL BROTLI_BOOL BrotliEncoderInitStaticDictionaryLut( + const BrotliDictionary* dictionary, uint16_t* buckets, DictWord* words); +BROTLI_INTERNAL extern BROTLI_MODEL("small") uint16_t + kStaticDictionaryBuckets[BROTLI_ENC_STATIC_DICT_LUT_NUM_BUCKETS]; +BROTLI_INTERNAL extern BROTLI_MODEL("small") DictWord + kStaticDictionaryWords[BROTLI_ENC_STATIC_DICT_LUT_NUM_ITEMS]; +#else +BROTLI_INTERNAL extern const BROTLI_MODEL("small") uint16_t + kStaticDictionaryBuckets[BROTLI_ENC_STATIC_DICT_LUT_NUM_BUCKETS]; +BROTLI_INTERNAL extern const BROTLI_MODEL("small") DictWord + kStaticDictionaryWords[BROTLI_ENC_STATIC_DICT_LUT_NUM_ITEMS]; +#endif + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_STATIC_DICT_LUT_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/static_dict_lut_inc.h b/packages/runtime/vendor/brotli/c/enc/static_dict_lut_inc.h new file mode 100644 index 000000000..fea97f8d7 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/static_dict_lut_inc.h @@ -0,0 +1,5830 @@ +const BROTLI_MODEL("small") +uint16_t kStaticDictionaryBuckets[BROTLI_ENC_STATIC_DICT_LUT_NUM_BUCKETS] = { +1,0,0,0,0,0,0,0,0,3,6,0,0,0,0,0,20,0,0,0,21,0,22,0,0,0,0,0,0,0,0,23,0,0,25,0,29, +0,53,0,0,0,0,0,0,55,0,0,0,0,0,0,61,76,0,0,0,94,0,0,0,0,0,0,96,0,97,0,98,0,0,0,0, +0,0,0,99,101,106,108,0,0,0,0,0,110,0,111,112,0,113,118,124,0,0,0,0,0,125,128,0,0 +,0,0,129,0,0,131,0,0,0,0,0,0,132,0,0,135,0,0,0,137,0,0,0,0,0,138,139,0,0,0,0,0,0 +,0,142,143,144,0,0,0,0,0,145,0,0,0,146,149,151,152,0,0,153,0,0,0,0,0,0,0,0,0,0,0 +,0,0,0,0,154,0,0,0,0,0,0,155,0,0,0,0,160,182,0,0,0,0,0,0,183,0,0,0,188,189,0,0, +192,0,0,0,0,0,0,194,0,0,0,0,0,0,0,0,197,202,209,0,0,210,0,224,0,0,0,225,0,0,0,0, +0,0,0,0,0,0,231,0,0,0,232,0,240,0,0,242,0,0,0,0,0,0,0,0,0,0,0,244,0,0,0,246,0,0, +249,251,253,0,0,0,0,0,258,0,0,261,263,0,0,0,267,0,0,268,0,269,0,0,0,0,0,0,0,0,0, +271,0,0,0,0,0,0,272,0,273,0,277,0,278,286,0,0,0,0,287,0,289,290,291,0,0,0,295,0, +0,296,297,0,0,0,0,0,0,0,0,0,0,298,0,0,0,299,0,0,305,0,324,0,0,0,0,0,327,0,328, +329,0,0,0,0,336,0,0,340,0,341,342,343,0,0,346,0,348,0,0,0,0,0,0,349,351,0,0,355, +0,363,0,364,0,368,369,0,370,0,0,0,0,0,0,0,372,0,0,0,0,0,0,0,0,0,0,0,373,0,375,0, +0,0,0,376,377,0,0,394,395,396,0,0,398,0,0,0,0,400,0,0,408,0,0,0,0,420,0,0,0,0,0, +0,421,0,0,422,423,0,0,429,435,436,442,0,0,443,0,444,445,453,456,0,457,0,0,0,0,0, +458,0,0,0,459,0,0,0,460,0,462,463,465,0,0,0,0,0,0,466,469,0,0,0,0,0,0,470,0,0,0, +474,0,476,0,0,0,0,483,0,485,0,0,0,486,0,0,488,491,492,0,0,497,499,500,0,501,0,0, +0,505,0,0,506,0,0,0,507,0,0,0,509,0,0,0,0,511,512,519,0,0,0,0,0,0,529,530,0,0,0, +534,0,0,0,0,543,0,0,0,0,0,0,0,0,0,553,0,0,0,0,557,560,0,0,0,0,0,0,561,0,564,0,0, +0,0,0,0,565,566,0,575,0,619,0,620,0,0,623,624,0,0,0,625,0,0,626,627,0,0,628,0,0, +0,0,630,0,631,0,0,0,0,0,0,0,0,0,641,0,0,0,0,643,656,668,0,0,0,673,0,0,0,674,0,0, +0,0,0,0,0,0,682,0,687,0,690,0,693,699,700,0,0,0,0,0,0,704,705,0,0,0,0,707,710,0, +711,0,0,0,0,726,0,0,729,0,0,0,730,731,0,0,0,0,0,752,0,0,0,762,0,763,0,0,767,0,0, +0,770,774,0,0,775,0,0,0,0,0,0,0,0,0,0,776,0,0,0,777,783,0,0,0,785,788,0,0,0,0, +790,0,0,0,793,0,0,0,0,794,0,0,804,819,821,0,827,0,0,0,834,0,0,835,0,0,0,841,0, +844,0,850,851,859,0,860,0,0,0,0,0,0,0,874,0,876,0,877,890,0,0,0,0,0,0,0,0,893, +894,898,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,899,0,0,0,900,904,906,0,0,0,907,0,908,909, +0,910,0,0,0,0,911,0,0,0,0,0,916,0,0,0,922,925,0,930,0,934,0,0,0,0,0,943,0,0,944, +0,953,954,0,0,0,0,0,0,955,0,962,963,0,0,976,0,0,977,978,979,980,0,981,0,0,0,0, +984,0,0,985,0,0,987,989,991,0,0,0,0,0,0,0,0,0,992,0,0,0,993,0,0,0,0,0,0,996,0,0, +0,1000,0,0,0,0,0,1002,0,0,0,0,1005,1007,0,0,0,1009,0,0,0,1010,0,0,0,0,0,0,1011,0 +,1012,0,0,0,0,1014,1016,0,0,0,1020,0,1021,0,0,0,0,1022,0,0,0,1024,0,0,0,0,0,0, +1025,0,0,1026,1027,0,0,0,0,0,1031,0,1033,0,0,0,0,1034,0,0,0,1037,1040,0,0,0,1042 +,1043,0,0,1053,0,1054,0,0,1057,0,0,0,1058,0,0,1060,0,0,0,0,0,0,0,1061,0,0,1062,0 +,0,0,0,1063,0,0,0,0,1064,0,0,0,0,0,1065,0,0,0,0,1066,1067,0,0,0,1069,1070,1072,0 +,0,0,0,0,0,1073,0,1075,0,0,0,0,0,0,1080,1084,0,0,0,0,1088,0,0,0,0,0,0,1094,0, +1095,0,1107,0,0,0,1112,1114,0,1119,0,1122,0,0,1126,0,1129,0,1130,0,0,0,0,0,1132, +0,0,0,0,0,0,1144,0,0,1145,1146,0,1148,1149,0,0,1150,1151,0,0,0,0,1152,0,1153,0,0 +,0,0,0,1154,0,1163,0,0,0,1164,0,0,0,0,0,1165,0,1167,0,1170,0,0,0,0,0,1171,1172,0 +,0,0,0,0,0,0,0,1173,1175,1177,0,1186,0,0,0,0,0,0,0,0,0,0,1195,0,0,1221,0,0,1224, +0,0,1227,0,0,0,0,0,1228,1229,0,0,1230,0,0,0,0,0,0,0,0,0,1231,0,0,0,1233,0,0,1243 +,1244,1246,1248,0,0,0,0,1254,1255,1258,1259,0,0,0,1260,0,0,1261,0,0,0,1262,1264, +0,0,1265,0,0,0,0,0,0,0,0,0,0,0,0,1266,0,1267,0,0,0,0,1273,1274,1276,1289,0,0, +1291,1292,1293,0,0,1294,1295,1296,0,0,0,0,1302,0,1304,0,0,0,0,0,0,0,0,0,1311, +1312,0,1314,0,1316,1320,1321,0,0,0,0,0,0,0,1322,1323,1324,0,1335,0,1336,0,0,0,0, +1341,1342,0,1346,0,1357,0,0,0,1358,1360,0,0,0,0,0,0,1361,0,0,0,1362,1365,0,1366, +0,0,0,0,0,0,0,1379,0,0,0,0,0,0,0,0,0,0,0,0,1386,0,1388,0,0,0,0,0,0,0,0,0,0,0,0,0 +,0,1395,0,0,0,0,1403,0,1405,0,0,1407,0,0,0,0,0,1408,1409,0,1410,0,0,0,1412,1413, +1416,0,0,1429,1451,0,0,1454,0,0,0,0,0,0,0,1455,0,0,0,0,0,0,0,1456,0,0,0,0,1459, +1460,1461,1475,0,0,0,0,0,0,1477,0,1480,0,1481,0,0,1486,0,0,1495,0,0,0,1496,0,0, +1498,1499,1501,1520,1521,0,0,0,1526,0,0,0,0,1528,1529,0,1533,1536,0,0,0,1537, +1538,1549,0,1550,1558,1559,1572,0,1573,0,0,0,0,0,0,0,0,0,1575,0,0,0,0,0,1579,0, +1599,0,1603,0,1604,0,1605,0,0,0,0,0,1608,1610,0,0,0,0,1611,0,1615,0,1616,1618,0, +1619,0,0,1622,0,0,0,0,1634,0,0,0,1635,0,0,0,1641,0,0,0,0,0,0,0,0,0,1643,0,0,0, +1650,0,0,1652,0,0,0,0,0,1653,0,0,0,1654,0,0,0,0,1655,0,1662,0,0,1663,1664,0,0, +1668,0,0,1669,1670,0,1672,1673,0,0,0,0,0,1674,0,0,0,1675,1676,1680,0,1682,0,0, +1687,0,0,0,0,0,1704,0,0,1705,0,0,1721,0,0,0,0,1734,1735,0,0,0,0,1737,0,0,0,0, +1739,0,0,1740,0,0,0,0,0,0,0,0,0,0,1741,1743,0,0,0,0,1745,0,0,0,1749,0,0,0,1751,0 +,0,0,0,0,0,1760,0,0,0,0,1765,0,0,0,0,0,1784,0,1785,1787,0,0,0,0,1788,1789,0,0,0, +0,1790,1791,1793,0,1798,1799,0,0,0,0,1801,0,1803,1805,0,0,0,1806,1811,0,1812, +1814,0,1821,0,0,0,0,0,1822,1833,0,0,0,0,0,0,1848,0,0,0,0,0,0,1857,0,0,0,1859,0,0 +,0,0,1861,0,0,0,0,0,0,0,1866,0,1921,1925,0,0,0,1929,1930,0,0,0,0,0,0,0,0,0,1931, +0,0,0,0,1932,0,0,0,1934,0,0,0,0,0,0,0,0,1946,0,0,1948,0,0,0,0,1950,0,1957,0,1958 +,0,0,0,0,0,1965,1967,0,0,0,0,1968,0,1969,0,1971,1972,0,0,0,0,0,0,0,0,0,0,0,0,0,0 +,0,1973,0,0,0,0,1975,0,0,0,0,1976,1979,0,1982,0,0,0,0,1984,1988,0,0,0,0,1990, +2004,2008,0,0,0,2012,2013,0,0,0,0,0,0,0,0,0,0,2015,0,2016,2017,0,0,0,0,2021,0,0, +2025,0,0,0,0,0,2029,2036,2040,0,2042,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2043,0,0,0,0,0, +2045,0,0,0,0,0,0,0,2046,2047,0,2048,2049,0,2059,0,0,2063,0,2064,2065,0,0,2066,0, +0,0,0,0,0,2069,0,0,0,0,2070,0,2071,0,2072,0,0,0,0,2080,2082,2083,0,0,0,0,0,2085, +0,2086,2088,2089,2105,0,0,0,0,2107,0,0,2116,2117,0,2120,0,0,2122,0,0,0,0,0,2123, +0,0,2125,2127,2128,0,0,0,2130,0,0,0,2137,2139,2140,2141,0,0,0,0,0,0,0,0,0,2144, +2145,0,0,2146,2149,0,0,0,0,2150,0,0,2151,2158,0,2159,0,2160,0,0,0,0,0,0,2161, +2162,0,0,2194,2202,0,0,0,0,0,0,2205,2217,0,2220,0,2221,0,2222,2224,0,0,0,0,2237, +0,0,0,0,0,2238,0,2239,2241,0,0,2242,0,0,0,0,0,2243,0,0,0,0,0,0,2252,0,0,2253,0,0 +,0,2257,2258,0,0,0,2260,0,0,0,0,0,0,0,2262,0,2264,0,0,0,0,0,2269,2270,0,0,0,0,0, +0,0,0,0,2271,0,2273,0,0,0,0,2277,0,0,0,0,2278,0,0,0,0,2279,0,2280,0,2283,0,0,0,0 +,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2287,0,0,0,0,0,0,0,2289,2290,0,0,0,0,2291,0,2292,0, +0,0,2293,2295,2296,0,0,0,0,0,0,0,2298,0,0,0,0,0,2303,0,2305,0,0,2306,0,2307,0,0, +0,0,0,0,0,0,0,0,0,0,2313,2314,2315,2316,0,0,2318,0,2319,0,2322,0,0,2323,0,2324,0 +,2326,0,0,0,0,0,0,0,2335,0,2336,2338,2339,0,2340,0,0,0,2355,0,2375,0,2382,2386,0 +,2387,0,0,2394,0,0,0,0,2395,0,2397,0,0,0,0,0,2398,0,0,0,0,0,0,0,2399,2402,2404, +2408,2411,0,0,0,2413,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2415,0,0,2416,2417,2419,0,2420, +0,0,0,0,0,2425,0,0,0,2426,0,0,0,0,0,0,0,0,0,0,0,0,2427,2428,0,2429,0,0,2430,2434 +,0,2436,0,0,0,0,0,0,2441,2442,0,2445,0,0,2446,2457,0,2459,0,0,2462,0,2464,0,2477 +,0,2478,2486,0,0,0,2491,0,0,2493,0,0,2494,0,2495,0,2513,2523,0,0,0,0,2524,0,0,0, +0,0,0,2528,2529,2530,0,0,2531,0,2533,0,0,2534,2535,0,2536,2537,0,2538,0,2539, +2540,0,0,0,2545,2546,0,0,0,0,0,0,0,2548,0,0,2549,0,2550,2555,0,0,0,0,0,2557,0, +2560,0,0,0,0,0,0,0,0,0,0,0,2561,0,2576,0,0,0,0,0,0,0,0,0,2577,2578,0,0,0,2579,0, +0,0,0,0,0,0,2580,0,0,0,0,2581,0,0,0,0,2583,0,2584,0,2588,2590,0,0,0,2591,0,0,0,0 +,2593,2594,0,2595,0,2601,2602,0,0,2603,0,2605,0,0,0,2606,2607,2611,0,2615,0,0,0, +2617,0,0,0,0,0,0,0,0,0,0,0,0,0,2619,0,0,2620,0,0,0,2621,0,2623,0,2625,0,0,2628, +2629,0,0,2635,2636,2637,0,0,2639,0,0,0,2642,0,0,0,0,2643,0,2644,0,2649,0,0,0,0,0 +,0,2655,2656,0,0,2657,0,0,0,0,0,2658,0,0,0,0,0,2659,0,0,0,0,2664,2685,0,2687,0, +2688,0,0,2689,0,0,2694,0,2695,0,0,2698,0,2701,2706,0,0,0,2707,0,2709,2710,2711,0 +,0,0,2720,2730,2735,0,0,0,0,2738,2740,0,0,0,0,2747,0,0,0,0,0,0,2748,0,0,2749,0,0 +,0,0,0,2750,0,0,2752,2754,0,0,0,0,0,2758,0,0,0,0,2762,0,0,0,0,2763,0,0,0,0,0,0,0 +,2764,2767,0,0,0,0,2768,0,0,2770,0,0,0,0,0,0,0,2771,0,0,0,0,0,0,0,0,0,2772,0,0,0 +,0,0,2773,2776,0,0,2783,0,0,2784,0,2789,0,2790,0,0,0,2792,0,0,0,0,0,0,0,0,0,0, +2793,2795,0,0,0,0,0,0,2796,0,0,0,0,0,0,2797,2799,0,0,0,0,2803,0,0,0,0,2806,0, +2807,2808,2817,2819,0,0,0,0,0,2821,0,0,0,0,2822,2823,0,0,0,0,0,0,0,2824,0,0,2828 +,0,2834,0,0,0,0,0,0,2836,0,2838,0,0,2839,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,2841, +0,0,0,2842,0,0,0,0,0,2843,2844,0,0,0,0,2846,0,0,2847,0,2849,0,2853,0,0,0,0,0, +2857,0,0,0,0,2858,0,2859,0,0,2860,0,2862,2868,0,0,0,0,2875,0,2876,0,0,2877,2878, +2884,2889,2890,0,0,2891,0,0,2892,0,0,0,2906,2912,0,2913,0,0,0,0,0,0,0,0,2916,0, +2934,0,0,0,0,0,2935,0,0,0,0,2939,0,2940,0,0,0,0,0,0,0,2941,0,0,0,2946,0,2949,0,0 +,2950,2954,2955,0,0,0,2959,2961,0,0,2962,0,2963,0,0,0,0,0,0,2964,2965,2966,2967, +0,0,0,0,0,0,0,2969,0,0,0,0,0,2970,2975,0,2982,2983,2984,0,0,0,0,0,2989,0,0,2990, +0,0,0,0,0,0,0,2991,0,0,0,0,0,0,0,0,2998,0,3000,3001,0,0,3002,0,0,0,3003,0,0,3012 +,0,0,3022,0,0,3024,0,0,3025,3027,0,0,0,3030,0,0,0,0,3034,3035,0,0,3036,0,3039,0, +3049,0,0,3050,0,0,0,0,0,0,3051,0,3053,0,0,0,0,3057,0,3058,0,0,0,0,0,0,0,0,3063,0 +,0,3073,3074,3078,3079,0,3080,3086,0,0,0,0,0,0,0,0,3087,0,3092,0,3095,0,3099,0,0 +,0,3100,0,3101,3102,0,3122,0,0,0,3124,0,3125,0,0,0,0,0,0,3132,3134,0,0,3136,0,0, +0,0,0,0,0,3147,0,0,3149,0,0,0,0,0,3150,3151,3152,0,0,0,0,3158,0,0,3160,0,0,3161, +0,0,3162,0,3163,3166,3168,0,0,3169,3170,0,0,3171,0,0,0,0,0,0,0,3182,0,3184,0,0, +3188,0,0,3194,0,0,0,0,0,0,3204,0,0,0,0,3209,0,0,0,0,0,0,0,0,0,0,0,3216,3217,0,0, +0,0,0,0,0,3219,0,0,3220,3222,0,3223,0,0,0,0,3224,0,3225,3226,0,3228,3233,0,3239, +3241,3242,0,0,3251,3252,3253,3255,0,0,0,0,0,0,0,0,3260,0,0,3261,0,0,0,3267,0,0,0 +,0,0,0,0,0,3271,0,0,0,3278,0,3282,0,0,0,3284,0,0,0,3285,3286,0,0,0,0,0,0,0,3287, +3292,0,0,0,0,3294,3296,0,0,3299,3300,3301,0,3302,0,0,0,0,0,3304,3306,0,0,0,0,0,0 +,3308,0,0,0,0,0,0,0,0,0,3311,0,0,0,0,0,0,0,0,3312,3314,3315,0,3318,0,0,0,0,0,0,0 +,0,3319,0,0,0,0,0,3321,0,0,0,0,0,0,0,0,0,3322,0,0,3324,3325,0,0,3326,0,0,3328, +3329,3331,0,0,3335,0,0,3337,0,3338,0,0,0,0,3343,3347,0,0,0,3348,0,0,3351,0,0,0,0 +,0,0,3354,0,0,0,0,0,0,0,0,0,0,3355,0,0,3365,3366,3367,0,0,0,0,0,0,3368,3369,0, +3370,0,0,3373,0,0,3376,0,0,3377,0,3379,3387,0,0,0,0,0,3390,0,0,0,0,0,0,0,3402,0, +3403,3436,3437,3439,0,0,3441,0,0,0,3442,0,0,3449,0,0,0,3450,0,0,0,0,0,0,0,3451,0 +,0,3452,0,3453,3456,0,3457,0,0,3458,0,3459,0,0,0,0,0,0,0,0,0,3460,0,0,3469,3470, +0,0,3475,0,0,0,3480,3487,3489,0,3490,0,0,3491,3499,0,3500,0,0,3501,0,0,0,3502,0, +3514,0,0,0,3516,3517,0,0,0,3518,0,0,0,0,3520,3521,3522,0,0,3526,3530,0,0,0,0, +3531,0,0,0,0,3536,0,0,0,0,0,0,0,3539,3541,0,0,3542,3544,0,3547,3548,0,0,3550,0, +3553,0,0,0,0,0,0,0,3554,0,3555,0,3558,0,3559,0,0,0,0,0,0,0,0,3563,0,3581,0,0,0, +3599,0,0,0,3600,0,3601,0,3602,3603,0,0,3606,3608,0,3610,3611,0,0,0,0,0,0,0,0,0, +3612,3616,3619,0,0,0,0,0,0,0,0,0,0,0,0,0,3624,3628,0,3629,3634,3635,0,0,0,0,0,0, +3636,0,3637,0,0,3638,3651,0,0,0,0,0,0,3652,3653,0,0,0,0,3656,3657,0,0,0,0,0,3658 +,0,0,0,0,3659,0,3661,3663,3664,0,3665,0,3692,0,0,0,3694,3696,0,0,0,0,0,0,0,0,0,0 +,0,0,3698,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3700,0,0,3701,0,0,0,3708,3709,0,0,0,3711 +,3712,0,0,0,0,0,3723,0,3724,3725,0,0,3726,0,0,0,0,0,0,3728,3729,0,3734,3735,3737 +,0,0,0,3743,0,3745,0,0,3746,0,0,3747,3748,0,3757,0,3759,3766,3767,0,3768,0,0,0,0 +,3769,0,0,3771,0,3774,0,0,0,0,0,0,3775,0,0,0,0,0,0,3776,0,3777,3786,0,3788,3789, +0,0,0,0,0,0,0,0,0,3791,0,3811,0,0,0,0,0,3814,3815,3816,3820,0,0,0,0,0,0,0,3821,0 +,0,3825,0,0,0,0,3835,0,0,3848,3849,0,0,0,0,3850,3851,3853,0,0,0,0,3859,0,3860, +3862,0,0,0,0,0,3863,0,0,0,0,0,0,0,0,3873,0,3874,0,3875,3886,0,3887,0,0,0,0,3892, +3913,0,3914,0,0,0,3925,3931,0,0,0,0,3934,3941,3942,0,0,0,0,3943,0,0,0,3944,0,0,0 +,0,0,3945,0,3947,0,0,0,3956,3957,0,0,0,0,0,0,0,0,0,3958,0,3959,3965,0,0,0,0,3966 +,0,0,0,3967,0,0,0,3968,3974,0,0,0,0,0,3975,3977,3978,0,0,0,0,3980,0,3985,0,0,0,0 +,0,0,0,0,3986,4011,0,0,4017,0,0,0,0,0,0,0,0,0,0,0,4018,0,0,0,0,4019,0,4023,0,0,0 +,4027,4028,0,0,0,0,0,0,0,0,4031,4034,0,0,4035,4037,4039,4040,0,0,0,0,0,4059,0, +4060,4061,0,4062,4063,4066,0,0,4072,0,0,0,0,0,0,0,0,0,0,0,0,0,4088,0,0,0,0,0, +4091,0,0,0,0,4094,4095,0,0,4096,0,0,0,0,0,4098,4099,0,0,0,4101,0,4104,0,0,0,4105 +,4108,0,4113,0,0,4115,4116,0,4126,0,0,4127,0,0,0,0,0,0,0,4128,4132,4133,0,4134,0 +,0,0,4137,0,0,4141,0,0,0,0,4144,4146,4147,0,0,0,0,4148,0,0,4311,0,0,0,4314,4329, +0,4331,4332,0,4333,0,4334,0,0,0,4335,0,4336,0,0,0,4337,0,0,0,4342,4345,4346,4350 +,0,4351,4352,0,4354,4355,0,0,4364,0,0,0,0,4369,0,0,0,4373,0,4374,0,0,0,0,4377,0, +0,0,0,4378,0,0,0,4380,0,0,0,4381,4382,0,0,0,0,0,0,0,4384,0,0,0,0,4385,0,0,0,4386 +,0,0,0,4391,4398,0,0,0,0,4407,4409,0,0,0,0,4410,0,0,4411,0,4414,4415,4418,0,4427 +,4428,4430,0,4431,0,4448,0,0,0,0,0,4449,0,0,0,4451,4452,0,4453,4454,0,4456,0,0,0 +,0,0,0,0,4459,0,4463,0,0,0,0,0,4466,0,4467,0,4469,0,0,0,0,0,0,0,0,0,0,0,0,0,4470 +,4471,0,4473,0,0,4475,0,0,0,0,4477,4478,0,0,0,4479,4481,0,4482,0,4484,0,0,0,0,0, +0,0,4486,0,0,4488,0,0,4497,0,4508,0,0,4510,4511,0,4520,4523,0,4524,0,4525,0,4527 +,0,0,4528,0,0,0,0,4530,0,4531,0,0,4532,0,0,0,4533,0,0,0,0,0,4535,0,0,0,4536,0,0, +0,0,0,4541,4543,4544,4545,4547,0,4548,0,0,0,0,4550,4551,0,4553,0,0,0,0,4562,0,0, +4571,0,0,0,4574,0,0,0,4575,0,4576,0,4577,0,0,0,4581,0,0,0,0,0,4582,0,0,4586,0,0, +0,4588,0,0,4597,0,4598,0,0,0,0,4616,4617,0,4618,0,0,0,0,4619,0,4620,0,0,4621,0, +4624,0,0,0,0,0,4625,0,0,0,0,4657,0,4659,0,4667,0,0,0,4668,4670,0,4672,0,0,0,0,0, +4673,4676,0,0,0,0,4687,0,0,0,0,4697,0,0,0,0,4699,0,4701,0,0,0,0,4702,0,0,4706,0, +0,4713,0,0,0,4714,4715,4716,0,0,0,0,0,0,0,0,0,0,0,0,4717,0,0,4720,0,4721,4729, +4735,0,0,0,4737,0,0,0,4739,0,0,0,4740,0,0,0,4741,0,0,0,0,0,4742,0,4745,4746,4747 +,0,0,0,0,0,0,0,0,4748,0,0,0,4749,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,4751, +4786,0,4787,0,4788,4796,0,0,4797,4798,0,4799,4806,4807,0,0,0,0,4809,4810,0,0,0,0 +,0,0,4811,0,0,0,0,0,4812,0,4813,0,0,4815,0,4821,4822,0,0,0,0,4823,0,0,0,0,0,0,0, +0,0,0,4824,0,0,0,0,4826,0,0,0,4828,0,4829,0,0,0,4843,0,0,4847,0,4853,4855,4858,0 +,0,0,0,0,4859,0,4864,0,0,4879,0,0,0,0,4880,0,0,0,0,4881,0,4882,0,0,0,0,0,0,0,0,0 +,4883,0,0,0,0,4884,0,0,0,0,0,4886,4887,4888,4894,4896,0,4902,0,0,4905,0,0,4915,0 +,0,0,0,0,0,0,4916,4917,4919,4921,0,0,0,0,0,4926,0,0,0,0,4927,0,0,0,0,0,0,0,0, +4929,0,4930,4931,0,4938,0,4952,0,4953,4957,4960,4964,0,0,0,0,0,0,0,5019,5020, +5022,0,0,0,0,0,5023,0,0,0,5024,0,0,0,5025,0,0,0,0,5028,0,0,0,0,5029,5030,5031,0, +5033,0,0,0,0,0,0,0,0,0,5034,5035,0,5036,0,0,5037,0,0,0,0,5038,0,0,5039,0,0,0, +5041,5042,0,0,0,0,5044,5049,5054,0,5055,0,5057,0,0,0,5060,0,0,0,0,0,5063,0,5064, +5065,0,5067,0,0,0,5068,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5076,0,0,0,0,0,0, +0,5077,0,0,5078,5080,0,0,5083,0,0,0,0,0,0,0,0,5085,0,0,0,0,0,0,5098,5099,5101, +5105,5107,0,5108,0,5109,0,0,0,0,0,0,0,5110,0,0,0,0,0,5117,5118,0,5121,0,5122,0,0 +,5130,0,0,0,5137,0,0,0,5148,0,0,0,0,0,0,0,5151,5154,0,0,0,5155,0,0,5156,5159, +5161,0,0,0,0,5162,0,0,0,0,5163,5164,0,5166,0,0,0,0,0,0,0,0,0,0,5167,0,0,0,5172,0 +,0,0,0,0,0,5178,5179,0,0,5190,0,0,5191,5192,5194,0,0,5198,5201,0,0,0,0,0,5203,0, +5206,5209,0,0,0,0,0,0,5213,0,5214,5216,0,0,0,0,0,5217,0,0,0,0,0,0,0,0,5218,5219, +0,5231,0,0,5244,5249,0,5254,0,5255,0,0,5257,0,0,0,0,0,5258,0,5260,5270,0,5277,0, +0,0,0,0,0,5280,5281,5282,5283,0,0,0,0,0,5284,0,5285,0,0,0,0,0,5287,5288,0,0,0,0, +0,0,0,0,0,0,5289,5291,0,0,5294,0,0,5295,0,0,0,0,0,0,0,5304,0,0,5306,5307,5308,0, +5309,0,0,5310,0,0,0,0,5311,5312,0,5313,0,0,0,0,0,5316,0,0,0,5317,0,0,0,0,0,0,0,0 +,0,5325,0,0,0,0,0,0,5326,0,5327,5329,0,5332,0,0,0,0,5338,0,0,0,0,0,0,0,0,5340,0, +0,5341,0,0,0,5342,0,5343,5344,0,0,5345,0,0,0,0,0,0,5347,5348,0,0,0,0,0,0,0,0,0, +5349,0,5350,0,5354,0,0,0,0,5358,0,0,5359,0,0,5361,0,0,5365,0,5367,0,5373,0,0,0, +5379,0,0,0,5380,0,0,0,5382,0,5384,0,0,0,0,0,0,5385,0,0,0,0,5387,0,0,0,0,0,0,5388 +,5390,5393,0,0,0,0,0,0,0,0,0,0,0,5396,0,0,0,0,5397,5402,0,0,0,0,0,5403,0,0,0, +5404,5405,0,0,0,0,0,0,0,0,0,0,0,0,5406,0,0,0,0,5410,0,0,5411,0,5415,0,0,0,0,5416 +,5434,0,0,0,0,0,0,0,0,0,0,0,5438,0,5440,0,0,0,0,0,0,5441,5442,0,0,0,5443,5444, +5447,0,0,5448,5449,5451,0,0,0,5456,5457,0,0,0,5459,0,0,0,5461,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,5464,0,5466,0,0,5467,0,5470,0,0,5473,0,0,5474,0,0,5476,0,0,0,0,0,0,0,0 +,0,0,0,5477,0,0,0,0,0,0,0,5484,0,0,5485,5486,0,0,0,0,0,5488,0,0,0,0,0,0,0,5489,0 +,0,0,0,0,5507,0,0,0,5510,0,5511,0,0,5512,0,0,0,5513,0,5515,0,0,5516,5517,0,5518, +0,0,5522,0,0,0,0,0,5534,5535,0,0,5536,0,5538,0,0,5543,0,5544,0,0,5545,0,5547,0, +5557,0,0,5558,0,5560,5567,0,0,0,0,5568,0,0,0,5571,5573,0,5574,0,5575,0,0,0,0, +5577,0,0,5598,0,0,0,0,0,0,0,0,0,5600,5609,0,0,0,0,5610,0,0,5612,0,5624,0,5625,0, +0,0,5629,0,5641,0,5642,5643,0,0,0,0,0,0,5651,0,0,0,5652,5653,0,5661,5662,5678,0, +5679,0,0,0,0,5685,5686,0,0,0,0,0,5690,5692,0,5703,0,0,0,0,0,5706,0,0,0,0,5707,0, +0,0,0,0,0,5708,0,0,5709,0,5710,0,0,0,5712,0,5733,0,5734,5735,0,0,5744,5751,0,0,0 +,0,0,0,0,0,0,0,0,0,5752,0,5754,0,0,0,0,0,0,5757,5758,0,5760,5761,0,0,0,0,5763, +5764,5765,0,5766,0,5767,5768,0,5770,0,0,0,0,5776,5780,0,0,0,0,5782,0,0,0,0,5784, +0,0,5788,0,0,0,0,0,0,0,0,0,0,0,5797,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5799,0,0,5801, +0,0,0,5811,0,0,0,0,0,0,5816,0,0,5827,0,0,0,0,0,0,0,0,5830,5831,0,0,5832,0,0,5833 +,0,5835,5844,5845,0,5846,0,0,0,0,0,5850,0,0,0,0,0,5852,0,5855,5857,0,0,5859,0, +5861,0,0,5863,0,5865,0,0,0,5873,5875,0,0,0,5877,0,5879,0,0,0,5888,0,0,5889,5891, +0,5894,0,0,0,0,0,0,5895,0,5897,0,0,0,0,0,0,5907,0,5911,0,0,5912,0,5913,5922,5924 +,0,5927,5928,0,0,0,0,5929,5930,0,5933,0,0,0,0,5949,0,0,5951,0,0,0,0,0,0,0,0,5953 +,0,0,5954,0,5959,5960,5961,0,5964,0,0,0,5976,5978,5987,5990,0,0,0,0,0,5991,0, +5992,0,0,0,5994,5995,0,0,5996,0,0,6001,6003,0,0,0,0,6007,0,0,0,0,0,6008,0,0,6009 +,0,6010,0,0,0,6011,6015,0,6017,0,6019,0,6023,0,0,0,0,0,0,0,6025,0,0,0,0,0,0,0,0, +0,0,6026,0,6030,0,0,6032,0,0,0,6033,6038,6040,0,0,0,6041,6045,0,0,6046,0,0,6053, +0,0,6054,0,6055,0,0,0,0,0,0,6057,0,6063,0,0,0,6064,0,6066,6071,6072,0,0,0,0,0,0, +6075,6076,0,0,6077,0,0,0,0,0,0,0,0,0,6078,6079,0,0,0,0,0,0,0,0,6080,0,6083,0,0,0 +,0,0,6084,0,0,6088,0,6089,0,0,6093,6105,0,0,6107,0,6110,0,0,0,6111,6125,6126,0,0 +,0,6129,0,0,0,0,6130,0,0,0,6131,6134,0,0,0,0,0,0,6142,0,0,0,0,0,6144,0,0,6146, +6151,6153,0,6156,0,6163,0,6180,6181,0,0,0,0,0,6182,0,0,0,0,6184,6195,0,0,6206,0, +6208,0,0,6212,6213,6214,0,6215,0,0,0,6228,0,0,0,6234,0,0,0,0,0,0,6235,6240,0, +6242,6243,6244,0,6250,6255,0,0,0,0,0,6257,0,0,0,6258,6278,0,6284,0,0,0,6285,0,0, +0,0,0,0,0,0,6286,0,0,0,6320,0,0,6322,6332,0,0,0,0,0,0,0,0,6334,0,0,0,0,0,0,0, +6335,0,0,6337,0,6338,0,6339,6340,0,0,6356,6357,6369,0,0,0,6370,6371,6372,0,6373, +0,0,0,0,0,6376,0,0,0,0,0,6382,6383,6384,0,0,0,0,6386,0,6389,6397,6400,6411,0, +6414,0,0,0,0,0,0,0,6415,6416,0,0,0,0,0,0,6417,0,0,0,0,6418,0,0,0,0,0,0,0,6420,0, +6421,6423,6425,0,6429,6430,0,6433,6438,0,0,0,0,0,0,0,0,0,0,6439,6440,0,0,6441,0, +0,6444,0,0,0,0,6446,0,0,0,0,6447,6448,0,0,6450,0,0,0,6454,0,0,6455,0,6461,0,0,0, +0,0,0,6462,0,0,6463,0,6464,0,6465,6467,0,0,0,6468,0,6479,6480,0,0,0,0,0,0,0,6481 +,0,0,6485,6487,0,0,0,0,0,0,6493,0,0,0,0,0,0,0,0,6494,6495,6496,0,0,0,0,0,6498,0, +0,0,6507,6508,0,0,0,0,0,0,0,0,0,0,6511,6512,0,0,0,0,6513,0,0,0,6514,0,0,0,0,0, +6516,0,0,6517,6518,0,0,0,6519,6520,6521,0,6523,0,0,0,0,6524,6528,0,6530,0,0,6532 +,0,6578,0,0,0,6583,0,6584,0,0,0,6587,0,0,0,6590,0,6591,0,0,0,0,0,6592,0,0,0,0, +6593,6594,0,0,0,0,0,6599,6600,0,0,6601,6602,6604,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +6608,0,0,0,0,0,0,0,0,6610,6611,0,6615,0,6616,6618,6620,0,6637,0,0,0,0,6639,0,0,0 +,0,6641,0,6642,0,0,0,6647,0,6660,6663,0,6664,0,6666,6669,0,6675,6676,6677,0,0,0, +0,0,0,0,0,0,6678,0,0,0,6679,0,6680,0,0,0,0,0,0,0,6693,0,0,0,0,0,0,0,0,0,6704, +6705,6706,0,0,6711,6713,0,0,0,0,0,6716,0,0,0,6717,0,6719,6724,0,0,0,0,0,0,0,0, +6725,6726,0,0,0,0,0,6728,6729,6735,0,6737,6742,0,0,6743,6750,0,6751,0,0,6752, +6753,0,0,0,0,0,0,6754,0,0,0,0,0,6756,0,0,0,0,0,0,6763,0,0,6764,6765,0,0,0,6770,0 +,0,0,6776,6780,0,6781,0,0,0,6783,0,6784,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +6785,0,0,0,6792,0,0,0,6793,0,0,6802,0,0,0,0,0,6803,0,0,0,6804,0,0,0,6812,0,0, +6823,0,6824,6839,0,0,0,0,6852,0,0,6854,0,6856,6857,0,0,0,0,0,0,0,0,0,6867,0,6868 +,6870,6872,0,0,0,6873,6874,0,0,0,0,0,6875,0,0,6877,0,0,0,0,0,0,0,6878,0,0,0,6879 +,0,6880,0,0,0,0,0,0,0,0,0,0,6887,0,6888,6891,6893,0,6895,0,0,0,0,0,0,0,0,6899,0, +0,0,0,6901,0,0,0,0,6910,0,6911,0,0,6912,0,0,6913,6914,0,0,0,6915,0,0,0,6916,6919 +,0,0,0,0,0,0,6924,0,6925,0,0,0,6926,6927,6928,0,6929,0,6930,0,0,6931,6935,0,6936 +,0,0,0,0,6939,6940,6941,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,6942,6948,6949,0,0,0,0,0,0 +,0,6952,6954,6963,6965,6966,0,0,6967,6968,0,0,0,0,0,0,0,0,0,6969,0,0,6970,6979,0 +,0,6980,0,0,6983,0,0,0,0,0,6984,0,0,0,0,0,0,0,6988,6990,6992,0,0,0,0,0,0,0,6995, +0,0,0,7012,0,0,0,0,0,0,0,0,0,7019,0,0,0,0,0,0,0,0,7021,0,0,7022,7023,7028,0,7030 +,7033,0,0,0,0,0,0,7038,0,0,0,0,0,0,0,0,0,0,7039,0,0,0,0,0,7046,0,7047,0,0,0,0,0, +0,0,0,0,0,0,7048,7052,0,0,0,0,0,7054,0,7060,0,0,0,0,7061,0,7065,0,0,0,0,7067, +7069,0,7070,7071,7072,0,0,7078,0,7080,7081,0,7083,0,0,0,7084,7087,7088,0,0,7090, +0,7093,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7107,0,0,7108,0,0,0,0,0,0,0,0,7110,0,7114,0 +,0,0,0,0,0,0,7115,0,7116,0,0,0,0,0,7117,0,0,7118,0,0,7124,0,7125,0,0,7126,0,0,0, +0,7128,0,0,0,0,0,7129,0,7130,0,7132,7133,0,0,7134,0,0,7139,0,7148,7150,0,0,0,0, +7152,0,0,0,7153,7156,7157,0,0,0,0,0,7158,0,0,0,0,0,0,0,0,0,0,7163,7165,7169,0, +7171,0,0,0,0,0,0,0,0,0,7172,0,7173,7181,0,0,0,0,0,7182,7185,0,0,0,0,7187,0,7201, +7204,0,0,0,0,0,7206,7207,0,0,0,0,7211,7216,0,7218,0,0,0,0,7226,7228,7230,7232, +7233,7235,7237,0,0,0,0,7238,7241,0,7242,0,0,7247,0,0,0,7266,0,0,0,0,0,0,0,7289,0 +,0,7290,7291,0,0,7292,0,7297,0,0,0,0,0,0,0,0,0,0,7300,0,7301,0,0,0,0,0,0,0,0,0,0 +,0,0,7302,0,0,0,0,7305,0,0,0,0,7307,0,7308,0,7310,0,7335,0,0,0,0,0,0,0,7337,0, +7343,7347,0,0,0,0,0,7348,0,7349,7350,7352,7354,0,0,0,0,7357,0,7358,7366,0,7367, +7368,0,0,7373,0,0,0,7374,0,0,0,0,0,0,0,7376,0,0,0,7377,0,0,0,0,0,7378,0,7379, +7380,0,0,0,0,0,7383,0,0,7386,0,0,0,0,7398,0,0,0,7399,7400,0,7401,0,0,0,0,0,0,0, +7402,0,0,0,0,0,7405,0,0,0,0,0,7406,0,0,0,0,0,0,0,0,7421,7427,7429,0,0,0,7435,0,0 +,7436,0,0,0,7437,0,0,0,0,0,0,7438,7443,0,7446,0,7448,0,0,0,0,0,0,0,0,0,0,7456,0, +0,0,0,0,7457,0,0,7461,0,0,0,0,0,7462,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7463,7466,7472, +0,7476,0,0,7490,0,7491,0,0,7493,0,0,0,7498,7499,0,0,7508,0,0,0,0,0,7512,0,0,0, +7513,7514,7516,0,0,0,0,7518,0,0,7519,7521,7522,0,0,0,7526,0,0,7529,0,0,7531,0, +7536,0,7538,0,7539,0,0,7541,7542,7546,0,0,0,0,0,7547,0,7548,0,0,0,0,0,7550,0,0, +7552,7553,0,0,0,0,0,0,0,0,0,0,7554,7563,0,7573,0,0,0,0,0,0,7574,7576,0,7578,7581 +,7583,0,0,0,7584,0,7587,0,0,0,0,0,7589,0,0,0,7594,0,0,7595,0,0,7600,7602,7610,0, +0,0,0,0,7612,0,7613,7614,0,0,7615,0,0,7616,0,7620,0,7621,7622,0,7623,0,0,0,0, +7626,0,0,0,0,7627,7629,7631,0,0,7633,0,0,0,0,0,7639,0,7640,7642,0,0,7643,0,0,0,0 +,7644,0,0,0,0,0,0,0,7645,0,0,0,0,0,7661,7662,7663,7665,0,7666,0,7667,0,7684,7688 +,7690,0,7691,0,0,0,0,0,0,7692,0,0,7700,0,7707,0,7708,0,7709,0,7721,0,0,0,7722,0, +7724,0,0,0,0,0,0,7729,7731,0,7732,0,7733,7735,0,0,0,0,0,0,0,7739,0,0,7741,7745,0 +,7748,0,0,0,7751,0,0,0,7752,0,0,0,0,0,0,0,7753,0,0,7756,0,7757,0,7759,0,7760,0,0 +,0,0,7761,7768,0,0,7769,0,0,7770,0,0,7771,0,0,7772,0,0,7773,0,0,0,0,0,7778,7783, +0,0,0,0,0,7784,7785,0,7790,0,0,0,0,7792,0,7798,0,0,0,0,0,7799,0,7810,0,0,7813,0, +7814,0,7816,0,7818,7824,7825,7826,0,7828,7830,0,0,0,7840,0,7842,0,7843,0,0,0,0, +7844,0,0,0,0,0,0,0,7846,0,0,0,0,0,7856,7857,7858,7862,0,7865,0,0,7866,0,0,7913,0 +,0,0,0,7914,0,0,7915,7917,7918,7919,0,7920,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,7921, +7922,0,7924,0,0,7925,0,0,7927,0,7930,7935,0,0,7937,0,0,0,0,0,0,7939,0,7940,0,0,0 +,0,0,7941,0,0,0,0,7945,0,0,0,0,7949,0,0,0,0,0,0,0,0,7950,0,7953,0,0,0,0,0,0,0, +7968,0,0,0,0,7969,7972,7992,0,7993,0,0,0,0,0,0,0,0,0,0,0,7994,0,0,0,0,8007,8008, +0,0,0,0,0,0,0,0,0,0,0,0,8010,0,0,0,8012,0,0,0,0,0,0,0,0,8018,0,8028,8029,0,0, +8030,0,0,8032,8033,0,0,8034,8036,0,0,0,0,0,0,0,0,0,0,8037,0,0,0,8043,8052,8059, +8060,0,0,8061,0,0,0,8062,0,8063,0,8064,0,8066,8068,0,0,0,8080,8081,0,8089,0,0,0, +0,0,8092,0,0,0,0,0,0,8093,8110,0,0,0,0,0,0,0,8111,0,0,0,0,0,8112,8115,0,8117,0,0 +,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8120,8121,8122,8128,8129,8130,8131,0,0,8139,0,0, +8144,0,0,0,0,8145,8146,8153,0,0,0,0,0,0,0,0,8154,0,8157,8160,8162,0,8164,8165,0, +0,0,0,8166,8167,0,0,8179,0,0,0,8185,0,0,0,8186,0,0,8187,0,0,0,8188,0,0,0,0,0, +8204,0,0,0,0,8210,0,0,0,0,0,8213,0,8214,0,0,8215,0,0,0,0,0,0,8218,0,0,0,0,0,0,0, +0,0,8219,0,8221,0,0,8222,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8225,0,0,0,8233,0,0, +8242,0,0,0,0,0,0,0,0,0,0,0,8247,0,8248,8252,0,8256,8257,0,0,8261,0,8264,8265,0,0 +,0,0,8267,0,0,0,8269,0,0,0,0,0,0,0,0,0,8270,0,0,0,8278,0,8279,8283,0,0,8285,8286 +,8289,8292,0,0,0,0,8293,8295,8299,8300,8301,0,0,0,0,0,0,8304,8307,0,0,0,0,0,0,0, +8321,0,0,0,8322,8323,8325,8326,8327,0,0,8332,8338,0,0,8340,0,0,0,0,0,8350,0,0, +8351,0,8354,8355,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8360,8372,0,0,0,0,0,0,0,0,8377,0,0, +0,0,8380,0,0,0,8383,0,8384,0,0,0,0,8386,8392,0,0,8394,0,0,0,0,0,0,0,8396,8397,0, +8398,0,8399,0,0,0,0,0,8400,0,8401,8410,8411,0,8412,8413,8422,0,0,0,0,8423,0,0,0, +0,8424,0,0,8425,0,0,0,0,0,0,0,8441,8442,0,0,0,0,0,0,8443,0,0,8444,0,8447,0,0,0,0 +,8451,0,8458,0,8462,0,0,8468,0,8469,0,0,0,8470,0,8473,8479,8480,0,0,0,0,8481, +8483,0,0,0,0,0,0,0,0,0,8484,0,0,8490,0,0,0,0,0,0,8491,8493,8494,0,8528,0,0,0,0,0 +,0,0,8530,0,0,0,0,0,0,0,0,8534,8538,8540,0,0,8541,0,0,8545,0,8557,0,0,8569,8570, +0,0,8571,8574,8575,8579,0,8583,0,0,0,0,8591,0,0,0,0,0,0,0,0,8606,0,8607,0,0,0,0, +0,0,0,0,0,8608,0,0,8609,0,0,0,8610,0,0,0,8611,0,0,8613,8617,8621,0,0,8622,0,8623 +,0,8624,8625,0,0,0,0,0,0,0,0,0,8637,8638,8639,8650,0,0,0,0,8652,8654,8655,0,0,0, +0,0,0,0,0,0,0,8656,0,0,0,0,0,8657,0,0,0,0,0,0,0,0,0,8658,0,0,8659,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,8660,0,0,0,0,0,0,8661,8663,8664,0,0,0,0,8665,0,8669,0, +0,0,0,0,0,0,8671,8674,0,8684,0,8686,0,0,0,8689,0,0,0,8690,0,8706,0,0,0,0,0,0,0,0 +,0,0,0,8710,0,8711,8713,8714,8724,8727,8728,8733,8736,0,8737,8739,0,0,0,0,8742, +8743,8745,8754,0,0,0,0,8756,0,0,0,0,0,0,8757,8760,0,0,0,0,0,8762,8763,8764,0, +8766,8769,8770,8773,0,8774,0,8779,0,0,0,0,8780,0,0,8781,0,0,8783,0,0,0,0,0,0,0,0 +,0,0,0,0,0,0,0,0,0,0,0,0,0,0,8784,0,0,0,0,0,0,0,0,8785,0,0,0,0,8786,0,0,0,0,8788 +,8790,0,0,0,8803,0,8813,8814,0,0,0,0,0,8815,8816,0,0,0,0,8818,0,0,0,0,8822,8828, +8829,0,8831,0,0,0,0,8833,0,0,0,8834,0,0,0,8835,0,8836,0,0,0,8837,0,0,0,0,0,0, +8838,8839,0,0,0,0,0,0,0,0,0,0,0,8840,0,0,0,8841,0,8842,0,0,0,8846,0,0,0,0,0,0,0, +8847,0,8848,0,0,8864,0,0,8866,0,0,8870,8872,0,0,8873,8874,0,0,0,0,0,0,8875,0, +8876,0,0,0,0,8896,8900,0,0,0,0,8901,0,0,0,0,0,8904,0,8907,0,0,0,0,8911,8912,8913 +,0,0,0,8914,0,8915,0,0,0,0,0,0,0,0,0,0,0,0,8916,0,0,0,8929,0,0,0,0,0,0,0,0,0,0, +8930,0,8932,0,8943,0,0,0,8945,8947,0,0,0,0,8949,0,8950,0,8954,8957,0,0,8970,0,0, +0,0,8971,0,8996,0,0,0,0,8997,9000,0,0,0,0,9001,9002,0,9004,9009,9024,0,0,0,0,0,0 +,0,0,0,0,0,0,9027,9082,0,0,9083,9089,0,0,0,0,0,0,9090,0,0,0,9092,0,0,9093,0,9095 +,0,0,9096,9097,9101,9102,0,0,0,0,0,0,0,0,9112,0,0,0,0,0,0,9114,0,0,9120,0,9121, +9122,0,0,0,9123,9124,0,0,9125,0,0,9126,0,9127,0,0,9129,9131,0,0,0,9132,0,0,9136, +0,9144,0,0,9148,0,0,0,0,0,0,9149,0,9152,9163,0,0,9165,0,0,0,0,0,0,0,0,0,0,0,0,0, +9166,0,9169,0,0,0,0,0,0,0,9170,0,0,0,0,9172,0,9174,9175,9176,0,9177,0,0,0,0,0,0, +0,0,9186,0,9187,0,0,0,9188,9189,0,0,9190,0,0,0,0,9191,0,0,0,9193,0,0,0,0,9197, +9198,0,0,0,9208,9211,0,0,0,0,9216,9217,0,9220,0,0,0,0,9221,9222,9223,0,9224,9225 +,0,0,9227,0,9228,9229,0,0,9230,0,9232,0,9233,0,0,0,0,0,9234,9235,0,0,9237,0,0,0, +0,0,0,0,0,9238,9240,0,0,9241,0,0,0,0,9244,0,0,0,0,9247,0,0,0,0,0,0,0,0,0,0,9248, +0,0,0,9249,0,0,0,0,0,9250,0,0,0,0,9251,0,0,9252,9255,0,0,0,9256,0,0,0,0,0,0,0, +9257,0,0,9258,0,0,0,0,0,0,9259,0,0,0,0,0,9262,9263,0,0,9265,9266,0,0,0,0,0,0,0,0 +,9268,9271,0,0,0,0,0,0,0,0,0,9273,0,0,0,9276,9277,9279,0,0,0,0,0,0,0,9280,0,0, +9293,0,0,0,0,0,9297,9301,0,0,0,0,0,0,0,0,0,0,0,9308,9309,9313,9321,9322,0,9326, +9327,0,0,9477,0,9479,0,0,0,0,9482,0,0,0,9483,0,9484,0,0,0,0,0,0,0,0,0,9485,0,0, +9486,0,0,0,9489,0,0,0,0,9490,9491,0,0,0,0,9493,0,9495,9496,0,0,0,0,0,0,0,0,9500, +0,9502,0,0,0,0,0,9504,9507,0,9509,0,9511,0,0,9513,0,0,0,0,0,0,0,0,9515,0,0,0,0,0 +,0,9516,9517,0,0,0,0,9532,0,0,9533,0,0,9538,0,9539,9540,0,0,0,0,9541,0,0,0,9542, +0,0,0,0,0,0,0,0,9544,9545,0,9546,0,0,0,0,0,0,9547,9548,0,0,0,9550,0,9557,0,9558, +0,9561,0,9563,9570,0,9572,9574,9575,0,0,0,9577,9592,0,0,9596,0,0,0,9598,0,9600,0 +,9601,0,0,0,0,0,0,9608,0,9638,9639,0,0,0,0,0,0,0,9641,0,0,9643,9644,9645,9646,0, +0,0,9648,0,0,0,0,0,0,0,9650,9654,0,0,0,0,0,0,0,0,9655,0,0,0,0,0,9656,0,9657,0,0, +0,0,9658,0,0,9659,0,0,9664,0,0,9665,0,9667,9669,0,0,0,0,0,0,0,0,0,0,0,0,9671,0, +9673,9681,0,0,0,0,9682,9683,9684,0,0,0,0,9686,9698,0,0,9700,9701,9702,0,9703, +9717,0,0,0,0,9718,0,9726,0,0,0,0,9727,0,0,0,9728,0,9742,0,9744,0,0,0,9750,0,9754 +,9755,0,0,0,0,0,9756,0,9757,9768,0,9769,0,0,0,9770,9771,0,9773,0,9774,0,9775,0,0 +,0,9776,9777,9784,0,0,0,9786,0,9789,0,0,0,0,9793,9794,0,0,0,9808,0,0,0,0,0,9811, +0,0,0,0,0,0,0,0,0,0,0,0,9812,0,9820,0,9823,0,9828,0,0,0,0,9830,0,0,9833,9836,0,0 +,0,9840,0,0,0,9841,0,0,9842,0,9845,0,0,0,9847,9848,0,0,9855,0,0,0,0,0,0,9856, +9863,9865,0,0,0,0,0,0,0,0,9866,9867,9868,9873,9875,0,0,0,0,0,0,9880,0,9886,0,0,0 +,9887,0,0,9891,0,0,0,0,0,0,0,9906,9907,9908,0,0,0,9909,0,0,0,0,0,0,9910,0,0,0,0, +9913,0,0,0,0,9914,0,0,0,0,0,9922,0,0,0,0,9923,9925,0,0,0,0,0,0,9930,0,0,0,9931,0 +,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9932,0,9939,0,0,9940,9962,9966,0,9969,9970,0,0,9974 +,0,9979,9981,9982,0,0,0,9985,0,0,0,0,0,0,9987,0,0,0,0,0,0,0,9988,9993,0,0,9994,0 +,0,0,9997,0,10004,0,0,0,0,0,10007,10019,10020,10022,0,0,0,10031,0,0,0,0,0,10032, +0,0,10034,0,10036,0,0,0,0,10038,0,10039,10040,10041,10042,0,0,0,0,0,10043,0,0,0, +0,0,10045,10054,0,0,0,0,10055,0,0,10057,10058,0,0,0,0,0,0,10059,0,0,0,0,0,0,0, +10060,0,0,0,0,0,0,0,10063,0,10066,0,0,0,10070,0,10072,0,0,10076,10077,0,0,10084, +0,10087,10090,10091,0,0,0,10094,10097,0,0,0,0,0,0,10098,0,0,0,0,0,0,10103,0, +10104,0,10108,0,0,0,0,0,0,0,0,10120,0,0,0,10122,0,0,10125,0,0,0,0,10127,10128,0, +0,10134,0,10135,10136,0,10137,0,0,10147,0,10149,10150,0,0,10156,0,10158,10159, +10160,10168,0,0,10171,0,10173,0,0,0,10176,0,0,0,0,10177,0,0,0,0,10178,0,0,0,0, +10194,0,10202,0,0,10203,10204,0,10205,10206,0,10207,0,0,0,0,10209,0,0,0,0,0,0,0, +10213,0,0,0,0,0,0,10217,0,10229,0,10230,10231,0,0,10232,0,0,10237,10238,10244,0, +0,0,0,0,10250,0,10252,0,0,0,0,0,0,10255,0,0,10257,0,0,0,0,0,0,10258,0,10259,0,0, +0,0,0,0,0,0,10260,0,0,0,0,0,0,0,10284,10288,10289,0,0,0,10290,0,10296,0,0,0,0,0, +10297,0,0,0,0,0,0,10298,0,0,0,0,10299,10303,0,0,0,0,0,10306,0,0,0,10307,0,10308, +0,0,0,0,10311,0,0,0,0,0,0,0,10315,10317,0,0,0,10318,10319,0,10321,0,10326,0, +10328,0,0,0,0,10329,0,0,10331,0,10332,0,0,0,0,0,0,10334,0,0,10335,10338,0,0,0,0, +0,10339,10349,0,0,0,0,0,0,10351,0,10353,0,0,0,0,0,0,10362,0,10368,0,10369,0,0,0, +10372,10373,0,0,0,0,0,10374,0,0,0,10375,0,10376,0,0,10386,10388,10390,0,0,0,0,0, +0,0,10391,0,0,10392,10394,0,0,10396,0,10397,0,10403,0,0,0,0,0,0,0,0,10404,0, +10405,10410,0,0,10411,0,10412,0,0,0,0,0,0,0,10421,10422,10423,0,0,0,0,0,0,0,0,0, +10425,0,0,10427,0,0,10430,0,0,0,0,0,10432,0,10433,10434,0,0,0,0,10436,10437,0, +10438,0,10439,0,10444,10446,0,0,0,0,0,10448,0,0,0,0,0,10449,0,0,0,0,0,0,0,10451, +0,10453,0,0,0,10454,10457,0,0,10459,0,10469,0,0,0,0,0,10472,10481,0,0,0,0,0, +10482,10483,0,10492,0,0,0,0,0,0,0,0,0,0,10499,0,0,0,10502,0,0,10510,0,10521, +10524,0,0,10525,10526,10528,0,0,0,0,0,0,0,0,10530,0,0,0,0,10533,0,10534,0,0,0,0, +0,0,0,0,0,0,10535,10536,0,0,10544,0,10553,10556,0,10557,10559,0,0,0,0,0,10562, +10563,10564,0,10565,0,0,0,10566,0,10567,0,0,0,0,10575,0,0,10576,0,10578,0,0,0,0, +0,0,0,0,0,0,10585,10586,10587,10589,0,10590,0,0,10594,0,0,0,0,0,10598,0,0,10601, +0,0,0,10602,0,10603,0,10604,0,10605,0,0,10607,0,10626,0,10627,0,0,0,0,0,10629, +10630,10631,0,0,0,10646,0,0,0,10647,0,10650,0,10651,0,0,0,10652,10653,10655,0, +10658,0,0,10659,0,10667,0,0,0,0,10669,0,0,0,0,0,0,0,0,0,10670,0,0,0,10671,0,0,0, +0,10672,10673,0,10674,0,0,0,10676,0,0,0,0,0,0,10678,0,10682,0,0,10692,0,10697,0, +0,0,0,10698,0,0,0,10700,0,0,0,0,0,10703,0,10704,0,0,0,0,0,0,0,10705,0,10715, +10718,10720,0,0,10722,0,0,0,0,0,0,0,0,10723,0,0,0,0,10726,0,0,0,0,0,10727,10730, +10743,0,0,0,0,0,0,10744,0,0,10745,0,0,0,0,0,0,10748,0,0,0,0,10750,0,0,10752, +10753,0,0,0,10756,0,0,0,0,0,0,10758,0,0,0,10759,0,10769,0,0,10772,0,0,0,0,0,0, +10773,0,0,0,10777,0,0,10779,0,0,0,0,0,0,0,0,10780,10784,0,0,0,10789,0,0,0,10791, +0,0,0,0,0,0,0,0,0,10795,0,0,10796,0,10808,0,10809,0,0,0,10810,0,0,0,10812,0,0, +10814,0,0,0,0,0,0,0,0,0,10815,0,0,0,0,10816,10817,0,0,0,0,10819,0,10820,0,0,0,0, +10821,10822,10823,0,10826,10849,0,0,0,0,10850,0,0,10852,0,10853,0,0,10856,0,0, +10857,10858,10859,10860,0,0,0,0,0,0,10863,0,10866,10867,10872,10890,0,0,10891, +10892,0,0,0,0,0,10893,0,0,0,10896,10899,0,0,10900,10902,0,0,0,0,0,10903,0,0,0,0, +0,0,0,0,0,0,0,0,10905,0,10906,0,0,0,0,10908,10911,0,10912,0,0,10916,0,0,0,0,0, +10917,0,10918,0,0,0,10923,0,0,0,0,0,10924,0,0,10928,10929,0,0,10930,0,0,0,10932, +0,0,0,0,10939,0,0,10945,0,0,0,10947,0,0,10948,0,0,0,0,0,0,0,0,0,0,0,0,10958,0, +10960,10962,0,0,10964,0,0,0,10966,0,0,0,0,0,0,0,0,0,0,10967,0,0,0,10968,0,0,0, +10973,0,0,0,0,0,10975,0,0,0,10976,10978,0,0,10982,10984,10987,0,0,10988,0,10989, +0,0,10991,0,0,0,0,10992,0,0,0,10993,0,10995,0,0,0,10996,10997,0,0,0,10998,0, +10999,0,11001,0,0,0,0,0,0,11010,11012,0,11013,11016,11017,0,0,11019,11020,11021, +0,0,0,0,0,0,0,0,0,0,0,0,11022,0,0,11023,11029,0,0,0,0,11031,0,0,0,11034,0,0,0,0, +11055,0,0,0,0,0,11056,11060,0,0,0,0,0,0,11061,0,0,11064,11065,0,11066,0,11069,0, +11085,0,0,0,0,0,11086,0,0,0,11088,0,0,0,11094,0,0,0,11095,11096,0,0,0,0,0,0, +11097,11098,0,0,0,0,0,0,11099,0,0,11102,11108,0,0,0,11109,0,11114,11119,0,11131, +0,0,0,11142,0,0,11143,0,11146,0,11147,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11148,0, +11149,11152,11153,11154,0,11156,0,11157,0,0,0,11158,0,0,11159,11160,0,0,0,0,0,0, +0,0,0,0,0,0,11163,0,0,11164,11166,0,0,0,11172,11174,0,0,0,11176,0,0,0,0,0,11182, +11183,0,0,0,11184,11187,0,0,11188,11189,0,0,0,0,0,0,11194,0,0,0,0,0,0,0,11200, +11202,0,0,0,0,0,0,11203,0,11204,0,0,0,0,0,11205,0,0,0,11206,0,11207,0,0,11209,0, +11211,0,11214,0,0,11231,0,0,0,11293,11295,0,0,11296,11297,11302,0,0,0,11307,0,0, +0,0,11309,11310,0,11311,0,0,0,11313,0,11314,0,0,0,0,11334,0,11338,0,0,0,11339,0, +0,0,0,0,11340,0,11341,11342,0,11344,0,11345,0,0,0,11348,11349,0,0,11350,0,0,0, +11355,0,0,0,0,0,0,11356,0,11357,11370,0,0,11371,0,11374,11376,0,0,0,11377,0,0, +11378,11383,0,11386,11399,0,11400,11406,0,0,0,11408,0,0,11409,11412,0,0,0,0, +11417,0,0,0,11418,0,11421,0,11426,11429,0,0,0,0,0,11430,0,11437,0,11438,0,0,0,0, +0,11440,11453,0,0,0,0,0,0,11454,0,0,0,0,11455,0,0,11456,11460,11461,11463,0, +11469,0,11473,0,0,0,0,11474,0,0,0,11475,0,11476,11477,11480,0,0,0,0,11481,0,0, +11484,0,0,11487,0,0,0,0,0,0,0,0,0,0,11497,0,0,11502,0,11509,0,0,11510,11511, +11513,0,0,0,0,0,0,0,0,0,0,11515,0,0,0,0,11516,0,11520,11521,0,0,0,0,0,0,0,0,0,0, +0,11529,11530,11531,11534,0,0,11543,0,0,0,0,0,11547,0,11548,0,0,0,0,0,11552, +11556,0,11557,0,0,11559,0,11560,0,0,0,0,0,0,11561,0,0,11563,11564,0,11565,0,0,0, +0,11567,0,0,0,11569,0,11574,0,11575,0,0,0,11577,0,11578,0,0,0,11580,11581,0,0,0, +11582,11584,0,0,0,0,0,0,0,11587,0,11588,11591,0,11595,0,0,0,0,0,0,0,0,11596,0, +11597,0,0,0,0,11598,11601,0,0,0,11602,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,11603, +11604,0,11606,0,0,11608,0,0,0,0,11610,0,0,11611,0,0,0,0,11613,0,11622,0,0,0, +11623,0,0,0,0,11625,0,0,11626,11627,11628,11630,0,0,0,0,0,0,11639,0,0,11646,0, +11648,11649,0,11650,0,0,0,0,0,0,0,0,0,11651,0,0,11652,11653,11656,0,0,11677, +11679,0,0,0,0,11680,0,0,11681,0,11685,0,0,0,0,0,0,0,0,11688,0,0,0,11716,0,11719, +0,0,0,0,0,11721,0,0,11724,11743,0,0,0,0,0,0,0,0,11745,11748,11750,0,0,0,0,0, +11751,0,0,0,11752,11754,0,11755,0,0,0,0,0,0,0,11759,0,0,0,0,0,0,11760,0,0,0, +11761,0,0,0,0,0,0,11766,11767,0,11772,11773,0,11774,0,0,11775,0,11777,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,11778,11780,0,0,0,0,0,0,0,11783,0,11784,0,0,0,11785, +0,0,0,11786,0,0,0,0,11788,0,0,11789,11791,11792,0,0,0,0,11795,11834,11835,11836, +0,0,11837,0,0,0,11838,0,0,11846,11851,0,11852,0,11869,0,0,0,11871,0,0,0,11872, +11874,0,0,0,0,0,0,11875,0,11876,11877,0,0,0,0,0,0,0,0,0,0,11883,0,0,0,0,0,0,0, +11884,0,11885,0,11886,0,0,11887,0,11894,11895,11897,11909,11910,0,11912,11918,0, +0,11920,0,11922,11924,11927,11928,0,0,0,0,11929,0,11934,0,0,0,0,0,11941,11943, +11944,0,11945,0,0,0,0,11948,11949,0,0,0,0,11953,0,11954,0,11955,0,11956,0,0,0,0, +0,11957,0,0,11959,0,0,0,0,0,0,0,0,11961,0,0,0,0,0,11978,0,0,0,11979,11980,11986, +11987,0,11992,0,0,0,0,0,11993,0,0,0,11994,0,11999,12004,12005,12006,0,0,0,0,0, +12011,0,0,12012,12014,0,0,12015,0,0,12019,12028,0,0,12029,0,0,12032,12033,0,0,0, +0,12034,0,12041,12043,0,0,12044,0,0,0,0,0,0,0,12046,0,0,0,0,0,0,0,12054,12055,0, +12056,0,0,0,12060,12064,0,0,0,0,0,12065,12067,12068,0,0,0,0,0,0,0,0,12074,0,0,0, +12075,12076,0,0,0,12079,0,12081,12086,12087,0,0,12088,0,0,0,0,12089,0,12092,0,0, +0,0,12097,0,0,0,0,0,0,0,0,12098,0,0,0,0,0,0,0,0,0,0,0,0,0,12102,12103,12104, +12111,0,0,12114,12116,0,0,0,12118,0,0,0,12119,12120,12128,0,0,0,0,12130,0,0,0,0, +0,0,12131,0,0,0,12132,12134,0,0,0,0,12137,0,12139,0,12141,0,0,12142,0,0,0,12144, +0,0,0,0,0,12145,0,12148,0,12153,0,0,0,0,12154,12171,12173,0,0,0,12175,0,0,0,0, +12178,0,0,0,0,0,0,0,12183,0,0,0,0,0,0,0,0,12184,0,0,0,12186,0,0,0,0,0,12187, +12188,0,0,12189,0,12196,0,12197,0,0,12198,0,12201,0,0,0,0,12203,0,12209,0,0,0,0, +12210,12211,12212,12213,0,12217,12218,0,0,0,0,0,0,0,0,0,12222,0,0,0,0,0,0,0, +12223,0,0,12229,0,0,0,0,12233,0,0,0,0,12234,0,0,12236,12242,0,0,0,12243,0,0,0, +12244,12253,0,12254,12256,0,12257,0,0,12275,0,0,0,0,0,12277,0,0,0,0,0,12278,0, +12289,0,0,12290,0,12292,12293,0,0,12294,0,12295,0,0,12296,0,12297,0,12298,0,0,0, +0,12301,0,0,0,0,0,0,0,0,0,0,0,0,0,12309,0,12338,12340,0,0,0,0,12341,0,0,0,0,0,0, +0,0,12342,12343,0,12344,0,0,0,0,0,0,0,0,0,12345,0,0,0,0,0,0,0,0,12346,0,0,0,0, +12348,0,0,0,0,0,0,0,0,0,0,0,0,12350,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12351,0,12355, +12356,12357,0,0,12367,12370,12371,0,0,0,0,0,12372,12376,0,0,0,0,0,0,0,0,12379,0, +12382,0,12383,0,0,12384,0,0,0,0,12393,0,0,12394,0,0,0,0,12398,12403,0,0,12404,0, +0,0,0,0,0,0,0,0,0,0,0,0,12410,0,0,0,12411,0,0,0,12412,0,0,0,0,12420,0,12421,0,0, +0,0,0,12423,0,12425,12429,0,0,0,12431,12432,0,0,0,0,0,0,0,0,0,0,0,0,12434,0,0,0, +0,0,12435,12436,0,0,0,0,0,0,0,0,12437,0,0,0,0,0,12438,0,0,0,0,0,0,0,0,12445,0,0, +0,12450,12451,0,0,0,0,0,0,0,0,12452,12475,0,0,12493,12494,0,0,0,12495,0,0,0,0, +12496,12502,12509,0,0,0,0,12510,0,12512,12513,0,0,0,0,12514,0,0,0,12515,0,12520, +0,0,0,12524,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12527,0,0,0,12528,0,0,0,12529,0,0,0, +0,0,12530,0,12535,0,0,12536,0,12538,0,0,0,0,0,0,0,0,0,0,0,0,12540,0,12548,0,0,0, +0,0,12550,0,0,0,12551,12552,0,0,0,12554,0,0,0,0,0,0,0,0,12555,0,0,12562,0,12565, +0,12566,0,0,0,0,0,0,0,0,0,0,0,0,12569,0,0,0,12571,12574,0,0,0,0,0,0,0,12577,0,0, +0,0,0,0,0,12578,12579,12603,0,12608,0,0,12611,0,12612,0,12615,0,12625,0,0,0,0, +12627,12646,0,12648,0,0,12657,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12670,0,0,12671,0, +12673,12677,0,0,0,0,0,0,0,0,0,0,0,12679,0,12681,0,12682,12693,0,12694,0,12697,0, +12701,0,0,0,12703,12704,0,0,0,0,12707,12737,0,0,12739,0,0,12740,0,0,12742,12743, +0,0,0,0,0,0,0,0,0,12745,0,12746,12747,0,12748,0,0,12759,12767,0,0,0,0,12773,0, +12774,12778,0,0,0,0,0,0,0,12779,0,0,0,0,0,12780,12793,0,12824,0,12825,0,12836,0, +0,0,0,12839,0,12842,0,0,0,0,0,0,0,0,0,0,0,0,12843,12845,0,12846,0,0,0,0,12847,0, +0,12850,12852,12853,0,0,0,12854,0,0,0,12855,0,12856,0,12858,0,0,12859,0,12862,0, +12863,0,0,12866,0,12869,12872,12873,0,0,0,0,0,0,0,0,0,12875,0,12877,0,0,12878,0, +0,0,0,0,0,0,0,0,12884,12885,12888,0,12889,0,0,0,0,12893,0,0,0,12895,12896,12898, +0,0,0,0,0,0,0,12902,0,12909,12910,0,12926,0,12928,0,0,0,12929,0,12930,0,0,0,0, +12931,0,12932,12933,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,12934,0,12942,0,0,0,0,12944, +0,0,0,0,0,0,0,0,12946,0,0,12948,0,0,12949,0,0,0,0,12950,0,0,0,0,12951,0,12952,0, +12953,0,0,0,12954,12958,12959,0,0,0,0,0,12960,12964,0,0,0,0,0,12966,0,0,0,0,0,0, +0,0,12970,0,12971,0,0,0,0,0,0,12972,0,0,12982,0,0,0,12984,12985,0,12986,12996, +12997,13001,13002,0,0,0,0,13004,0,0,13005,0,0,13007,13009,0,13017,0,0,0,13020,0, +13021,0,0,0,0,0,0,0,0,0,0,13022,0,0,0,0,0,0,0,0,13024,13027,0,0,0,0,0,13028,0,0, +13029,0,0,0,0,0,0,0,13032,0,13037,0,0,0,0,0,0,13040,0,0,13041,0,0,0,13043,13044, +13046,0,0,0,0,13047,0,0,0,0,0,0,0,13049,13054,0,13056,0,0,13060,13061,0,0,0,0,0, +13067,0,0,13068,0,13071,0,0,0,0,0,13077,13078,0,0,0,0,0,13079,13080,13081,0, +13082,0,0,0,13085,0,0,0,0,0,0,0,13086,0,13087,13088,0,0,0,0,0,13094,0,13099,0, +13100,0,0,0,13101,0,13125,13126,13128,13129,0,0,13130,0,13131,0,0,0,0,0,0,13134, +0,0,0,0,0,0,0,0,0,0,0,13150,0,13168,0,0,0,0,0,0,0,0,0,13169,0,0,13170,0,0,0,0, +13174,0,0,0,13176,0,0,0,0,0,13177,0,13178,13183,13187,0,0,0,13189,0,0,13190,0,0, +13191,0,0,13206,0,0,0,13207,0,0,0,0,0,0,0,0,0,0,13212,0,0,13219,13232,0,0,0, +13241,0,13249,13253,0,0,0,0,0,13255,13259,0,13260,13261,0,13262,0,13272,0,0,0,0, +13276,0,0,0,0,13277,13299,0,0,13301,13302,0,0,13303,0,0,13305,0,13310,0,0,0, +13311,0,0,0,0,13325,0,13328,0,0,0,13329,0,0,0,0,0,0,13330,0,0,13331,0,13335,0,0, +13342,0,0,0,0,0,13343,0,13354,0,13362,0,13366,13367,13369,0,0,13371,13372,0, +13373,13374,0,13376,0,13380,13381,13386,0,13387,13388,0,13389,13391,13395,0,0,0, +0,0,13401,13409,0,13410,0,0,0,0,13420,0,0,0,0,0,13422,0,0,0,0,13423,0,0,0,0, +13425,0,0,0,0,0,13427,0,0,0,13428,0,0,13430,13438,0,13439,0,13445,0,13448,13449, +0,0,0,0,0,0,13451,0,13457,0,0,0,0,13458,13459,0,13460,0,0,0,0,13464,13465,13466, +13470,0,13471,13472,13474,13475,0,13476,0,0,13478,13479,0,13481,0,0,0,0,13487,0, +13490,0,13493,0,0,13494,0,0,13495,0,0,0,0,0,0,0,0,0,0,0,0,0,0,13496,13497,0, +13500,0,0,13516,13522,0,0,13525,13528,0,0,0,13530,13535,0,13537,13539,0,13540,0, +13543,0,13544,0,0,0,0,0,0,13545,0,0,0,0,0,0,13547,0,0,0,13549,13555,0,0,0,13556, +13557,0,0,0,0,0,0,0,13558,0,13563,0,0,0,0,13564,0,0,0,0,0,0,0,0,13566,0,0,0,0,0, +0,13569,0,0,13571,0,0,0,0,13573,0,0,0,0,0,0,13578,0,0,0,0,0,0,0,0,0,0,13581,0, +13586,0,13595,0,13600,0,0,0,0,0,0,0,0,13601,13603,0,13604,13605,13606,13607,0,0, +13617,13618,0,0,0,0,0,0,0,13623,0,13625,13627,0,0,0,0,0,0,0,0,13629,0,0,0,13634, +0,0,0,13638,0,0,0,0,0,0,0,0,13654,0,0,0,0,0,0,0,0,0,0,13656,0,13659,0,0,13660,0, +0,13662,0,0,0,13663,0,13664,0,0,0,0,0,13668,0,13669,13671,0,0,13672,0,0,0,0,0,0, +13675,13685,0,13686,0,0,0,13687,0,0,0,13692,13694,13697,0,0,0,13702,0,0,0,0,0, +13705,0,0,0,0,13707,0,0,0,13714,0,0,0,0,0,0,0,0,0,13715,0,13716,13717,0,0,13719, +13724,13730,13731,0,0,0,0,0,0,0,0,13732,0,0,0,0,0,0,0,13734,0,13736,0,0,13737, +13738,13747,0,13751,0,0,13752,0,0,0,13753,0,13757,0,0,13762,13763,0,13764,13765, +0,13766,0,0,13767,0,0,0,13768,0,0,0,0,0,0,0,13769,0,0,13772,0,13775,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,13776,13778,13787,0,0,0,13797,0,13798,0,13801,0,13804, +13806,0,0,0,0,13816,13817,0,0,0,0,0,0,0,0,0,0,0,0,0,13834,0,13836,0,0,13838,0,0, +13839,0,13840,0,0,0,0,13842,0,0,0,0,0,0,13843,0,0,0,0,0,0,0,0,0,13845,0,0,0,0,0, +13858,0,0,13860,0,0,13861,0,0,13862,13863,0,13868,0,13869,13870,0,0,0,0,0,0,0,0, +0,0,13872,0,0,0,0,13873,13878,0,0,0,0,0,0,0,0,0,0,13886,0,13888,13889,13890,0,0, +13891,13894,0,13897,13899,13900,13904,0,0,13906,0,0,0,13909,0,0,0,13910,0,0,0, +13911,0,0,0,0,0,13912,13917,0,0,0,0,13918,0,13919,0,0,13920,0,0,0,13921,0,0, +13922,0,0,0,0,0,0,0,13924,0,13927,0,0,0,0,0,13932,0,13933,0,13934,0,0,13935,0, +13944,0,0,0,13954,0,0,13955,0,0,0,0,13956,0,13957,0,13967,13969,0,0,0,0,0,0,0,0, +0,0,0,0,13970,13990,0,13991,13994,0,13995,0,0,0,0,13996,0,0,13999,0,0,0,14018,0, +14019,0,14021,0,0,0,0,0,0,14041,0,0,0,0,0,0,0,0,14043,0,0,0,0,14046,0,0,0,14048, +14049,0,0,0,0,0,0,0,0,0,0,14051,0,0,14052,14056,0,14063,0,14064,14066,0,0,14067, +0,0,0,0,0,0,0,0,0,14068,0,0,0,14072,0,14074,14075,0,14076,14079,14085,14086, +14087,14093,0,0,0,0,14095,0,0,0,0,0,0,14096,14097,0,0,0,0,0,0,0,14098,0,14102,0, +0,0,0,0,14103,0,0,0,14104,0,0,14105,0,0,0,14107,14108,0,0,14109,0,0,0,0,0,0,0,0, +14117,0,0,0,0,14118,0,0,0,0,14119,0,0,14120,0,0,14121,0,14122,14127,0,14128, +14136,0,0,14138,0,14140,0,0,0,14141,14142,0,0,0,0,14146,0,0,14149,0,14151,0,0,0, +14152,0,0,14153,0,0,0,0,0,0,0,0,0,14154,0,14156,14157,0,0,14159,0,14161,0,0,0,0, +14162,0,0,0,0,0,0,14163,0,0,14173,0,0,0,0,0,0,14174,0,0,14176,0,0,14178,0,0, +14179,14181,0,0,14182,14185,14187,0,14190,0,0,14197,0,0,0,0,0,0,0,0,0,0,0,0, +14198,0,0,0,0,0,0,14199,14200,0,0,0,14204,0,0,14208,0,0,0,0,0,0,0,0,0,0,0,14231, +0,0,0,0,0,0,0,0,0,14234,0,0,14235,0,0,0,14240,14241,0,0,0,14246,0,0,0,14247,0, +14250,0,0,14251,0,0,14254,0,0,14256,0,0,0,14260,0,14261,0,0,0,0,14262,14267, +14269,0,0,14277,0,0,14278,0,14279,14282,0,0,0,14283,0,0,0,14284,14285,0,0,0,0, +14286,0,0,0,14288,0,0,0,14289,0,14290,0,14293,14301,14302,14304,14305,0,14307,0, +14308,14309,0,0,0,0,0,0,0,0,0,0,0,14311,14312,0,0,14317,0,0,0,0,0,0,0,14318,0,0, +0,0,14320,0,0,0,0,14321,14322,0,0,0,0,0,14326,14329,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +14330,14331,0,0,0,0,14332,0,0,0,14333,0,0,14337,14340,0,14341,0,0,14342,0,14345, +14346,0,0,14347,0,14362,0,0,0,0,0,14364,14365,14371,0,14373,0,0,14374,0,14379,0, +14400,0,0,0,0,0,14401,0,0,14405,0,14406,0,14408,14409,0,0,0,14417,0,0,14424,0,0, +0,0,0,0,0,0,0,14430,0,0,0,14431,0,0,14435,0,14440,0,0,0,0,0,0,14442,0,0,14443,0, +0,0,0,0,14446,0,0,0,0,0,0,0,14454,0,14457,0,14460,0,0,14466,0,0,0,0,0,14467,0,0, +0,0,0,0,14469,0,14477,0,0,0,0,0,0,14478,14482,0,0,0,14483,0,0,0,14485,14486,0,0, +0,14487,14488,14489,14492,14493,14494,14495,14496,14497,0,14499,0,14501,0,0,0,0, +0,0,0,0,0,0,14502,0,14507,14512,14513,14514,0,0,0,0,0,0,0,0,0,0,0,14515,14526, +14530,0,14537,0,14544,0,14547,0,0,14548,14550,14551,0,0,14552,0,0,0,14553,0, +14554,0,0,0,0,14556,14564,0,0,14565,14566,0,0,0,0,0,0,14568,0,0,14569,0,0,0, +14571,14576,0,0,14577,14578,14579,0,0,14580,0,0,0,0,14582,0,0,0,0,0,0,0,0,0,0,0, +0,14583,0,0,0,0,0,14587,0,14588,0,0,14600,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,14601,0,0,14604,14605,14611,0,14613,0,0,0,0,14615,0,0,0,0,0,0,14627,0,14628,0, +0,0,0,14631,0,14633,14634,0,0,0,0,14635,0,0,0,0,0,0,0,0,14636,0,0,14639,14642,0, +0,0,0,14644,0,0,0,0,14645,14646,0,14653,0,0,14654,0,14658,0,14661,0,0,0,14665,0, +0,0,14668,0,0,0,0,0,0,0,0,0,14669,0,0,14670,0,0,0,14680,0,0,14681,0,0,0,0,0, +14682,14683,0,0,0,0,14686,0,0,0,0,14687,14697,0,0,0,0,14699,14705,14711,0,0,0,0, +0,0,0,0,0,0,14712,0,0,0,14713,0,0,0,0,14719,0,14720,14721,14726,0,0,0,14728, +14729,0,0,0,0,14731,0,0,0,0,0,0,0,14733,14736,14737,0,0,14740,14742,0,0,0,14744, +14753,0,0,0,0,14755,14758,14760,0,0,0,0,0,14761,14762,14765,14771,0,14772,0, +14773,14774,0,0,14775,0,0,14776,0,0,0,0,14777,0,14779,0,0,14782,0,0,14785,14786, +14788,0,0,0,0,0,14795,0,0,0,0,0,0,14798,0,14803,14804,14806,0,0,0,14809,0,0,0,0, +0,0,14810,0,0,0,0,14811,0,14812,0,0,0,0,0,14815,0,0,0,0,0,0,0,0,14816,0,14818,0, +0,0,0,0,0,14819,0,14820,0,14823,0,0,0,14824,0,0,14826,14827,0,0,0,0,0,0,0,0,0,0, +0,0,14830,0,0,0,0,0,14833,0,14845,0,0,0,0,0,14846,0,0,14847,14871,0,14873,0, +14876,0,14877,14878,14880,0,0,0,0,0,14881,0,14882,14894,0,0,0,0,14895,0,14907,0, +14908,0,0,0,0,0,0,0,14911,0,0,0,0,14920,0,0,14931,0,14932,14934,14935,0,0,14936, +0,14945,0,0,0,0,0,0,0,14947,0,0,14948,14949,14951,0,0,14952,0,0,0,14964,14973,0, +0,14990,0,0,0,0,14995,0,0,14998,15001,0,0,15002,15020,0,0,0,0,0,0,15021,0,15022, +0,0,0,0,15023,0,0,15025,15029,15033,0,0,0,15034,0,0,0,15035,0,0,0,0,0,15043, +15044,0,0,0,15045,15046,15048,15050,0,15065,0,0,0,0,15066,0,0,15075,15082,15084, +0,0,15085,15086,0,0,0,0,0,0,0,0,15088,0,0,0,15089,0,0,0,0,15094,0,15096,0,15097, +0,15100,0,0,15102,0,0,0,0,0,0,0,0,15105,0,0,15106,0,15109,15113,0,0,0,15115,0, +15118,0,0,0,0,0,0,15119,0,0,15120,0,0,0,0,0,15123,15129,0,0,0,15130,0,15131,0,0, +15134,0,15135,0,0,0,15137,15138,0,0,0,0,0,0,15139,0,0,0,0,0,15140,0,0,15154, +15162,0,15169,15170,0,15175,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15177,0,15178,15179,0, +0,0,0,0,15183,0,0,0,0,0,0,0,0,0,0,0,0,15185,15187,0,15194,15195,15196,0,0,0,0,0, +0,0,15204,0,0,0,0,15206,0,0,0,0,0,15207,0,0,0,0,0,0,0,0,0,15213,0,15214,0,0,0,0, +0,0,0,15232,0,0,0,0,15234,0,15238,15240,0,15248,0,0,0,0,15250,15251,0,0,0,0,0,0, +0,15252,0,0,0,15255,15262,15266,0,0,0,15267,0,0,0,15277,15279,0,0,0,15280,15281, +15282,0,0,0,0,0,15285,0,0,0,0,15289,0,0,15291,0,0,0,0,0,0,0,15296,15297,0,0, +15304,0,0,0,0,15306,0,0,0,0,0,0,15307,15308,0,15309,0,0,15311,0,0,15312,15313,0, +0,0,0,0,0,0,0,0,0,0,0,15314,15317,0,0,0,15318,15319,0,0,0,0,15320,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,15321,0,0,0,0,0,15324,0,15325,15326,0,15330,0,0,0,0,15334,0, +15335,0,15341,0,0,15342,0,0,15343,15344,0,0,0,0,15345,0,0,0,0,15347,0,0,15348, +15349,15350,0,15356,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15357,0,15358,0,0,0,0,0,0,0, +15359,15360,15364,0,15380,0,0,0,0,0,15392,0,0,15393,0,15395,0,0,0,0,0,0,0,0, +15396,0,0,15397,15398,0,0,0,0,0,0,0,0,0,15399,0,15400,0,0,0,15402,0,15405,15410, +0,0,0,0,15411,0,0,0,15412,0,15416,0,0,0,0,0,0,0,15428,0,15435,0,0,15438,0,0,0,0, +15439,0,0,0,15440,0,0,0,15441,15449,15451,0,0,0,0,0,0,0,15452,0,0,15455,0,0,0, +15456,0,0,15458,0,15460,15461,0,0,0,0,0,15462,15464,0,15465,0,0,15466,0,0,15467, +0,0,0,0,0,15468,0,0,0,0,15481,0,0,15484,0,15485,15486,0,0,0,15487,0,0,0,0,0, +15488,0,15492,15498,0,0,0,15499,0,0,0,15500,0,15501,0,0,15512,0,15522,0,0,0, +15524,0,15525,15526,0,0,15527,0,0,15545,15546,0,15548,15552,0,15553,0,0,0,15554, +0,15555,0,15557,15565,15573,15577,15578,0,15582,0,15583,0,0,0,0,0,0,0,0,0,0,0,0, +0,15586,0,0,0,0,0,0,0,0,0,0,0,0,0,0,15588,0,0,0,0,0,15589,0,0,0,0,0,0,0,15593, +15594,0,0,0,0,15595,0,0,0,0,0,0,15596,0,0,0,15597,0,0,0,0,15600,0,0,15601,0,0,0, +0,15602,15603,0,0,0,0,0,0,15604,0,15609,0,0,15612,0,0,15613,0,0,15615,15617, +15618,0,0,15620,0,15636,15637,0,0,15649,0,0,0,0,0,0,0,15650,0,0,15651,0,0,0, +15656,0,15658,0,0,0,15664,0,0,15665,0,0,15668,0,0,0,0,0,15669,0,0,15674,0,0, +15675,0,0,0,0,15676,0,0,0,0,0,0,0,0,0,0,0,15677,0,0,0,0,15678,0,0,0,0,0,15679,0, +0,15681,0,15686,0,0,0,0,15687,0,15688,0,0,15690,0,0,0,15697,0,15699,15700,0,0,0, +0,0,0,0,0,0,15701,0,15702,15703,0,15704,0,15705,0,15707,0,15709,0,15712,15716,0, +15717,0,15718,15720,0,0,0,0,0,15724,0,0,0,15725,0,15726,0,0,0,15740,0,15745, +15746,0,0,15747,0,15748,0,0,0,0,0,15749,0,0,0,15752,0,15753,0,0,0,0,0,0,15759,0, +0,0,15765,0,0,0,0,0,0,0,0,0,15767,0,0,0,15771,0,0,15784,0,0,0,0,15785,15790, +15791,0,0,15792,0,0,0,15807,0,15811,0,0,0,0,0,0,0,0,0,0,0,0,15818,0,0,0,15819,0, +0,0,0,15821,0,0,0,0,0,15822,15824,0,0,15827,0,0,15829,15831,0,15832,0,0,15833,0, +15835,15838,15839,15843,0,0,0,0,0,0,0,0,0,0,0,15844,0,0,0,0,15845,15851,15856,0, +0,0,0,0,0,0,15858,15860,0,15861,0,0,0,15864,0,0,0,0,15865,0,0,0,0,0,0,15866,0, +15872,0,0,15876,0,0,0,0,15877,15878,15883,15885,0,0,15888,0,0,0,0,0,15889,15890, +0,0,0,0,0,0,0,0,15892,0,0,0,0,0,0,0,15893,0,0,15894,0,0,0,15895,0,15896,15897,0, +15898,15901,15902,0,15911,15915,0,15916,0,15924,15935,0,15937,0,0,0,0,0,15950,0, +0,0,0,0,0,0,15958,0,0,0,15961,0,0,15966,0,15967,0,0,15977,0,0,15978,0,0,15981, +15982,15983,0,0,0,0,0,0,0,15986,0,0,0,15990,0,15991,15995,15998,0,15999,0,16000, +0,0,0,0,16008,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16009,16011,0,16013,0,0,0,0, +0,0,0,0,16014,0,0,16015,16023,16024,16025,0,0,16026,0,16030,0,16032,0,16033,0,0, +0,0,0,0,16035,16036,16037,0,0,0,0,0,16039,0,0,0,0,16041,0,0,0,0,0,16043,16044,0, +0,16047,0,0,0,16048,0,0,16049,16050,16052,0,0,0,0,0,16055,0,0,0,0,0,0,0,0,16056, +0,0,0,0,0,0,0,16058,16060,16061,0,0,16063,0,0,16064,0,0,0,16067,16068,0,0,16069, +16078,0,0,0,16079,0,0,0,16080,0,16081,0,0,0,16088,0,0,0,0,0,0,0,0,0,0,0,16089, +16093,0,16097,0,16103,0,16104,16105,0,0,16256,0,0,16259,0,0,0,0,0,0,0,16260, +16261,0,0,16262,0,0,16263,0,16268,0,0,0,0,0,0,0,16269,0,0,16270,16273,0,16274,0, +0,0,0,16275,16276,16277,16280,0,0,0,16281,16284,0,0,0,16286,0,16289,0,0,0,0,0,0, +0,0,0,16290,0,0,0,0,16291,0,0,0,0,0,0,0,16292,0,0,0,0,0,0,0,0,16293,16295,16297, +0,16302,0,16304,0,16305,0,16306,0,0,0,0,0,0,0,0,0,0,0,0,16307,16308,16312,0,0,0, +0,0,0,16313,16315,0,16318,0,0,0,16321,0,0,0,0,0,0,0,16326,16333,16336,0,0,0,0, +16337,16340,0,0,0,0,0,16345,0,0,16346,0,0,0,0,0,0,0,0,0,16347,0,0,16348,0,0,0,0, +16349,0,0,0,16350,0,16357,0,0,0,0,16359,16360,0,0,0,0,16362,16363,16364,16365,0, +0,16366,0,0,0,0,16367,16368,0,16369,16374,0,0,0,0,0,0,0,16376,0,0,0,0,16378, +16379,0,16380,0,0,0,16381,16383,0,0,0,0,0,16390,0,0,0,16399,0,16402,16404,16406, +16407,0,0,0,16409,16411,0,0,0,0,16412,0,16413,16415,16423,0,0,0,0,0,16424,0,0,0, +16428,16434,16435,16449,0,16450,16451,0,0,0,16453,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +16454,0,0,16456,16458,0,0,16459,0,0,16460,0,0,0,0,16462,0,16463,0,0,16466,0,0,0, +0,0,16479,0,0,16480,0,16481,16484,0,0,0,0,0,0,0,0,0,0,16485,0,0,0,0,0,0,16489,0, +0,0,0,0,16491,0,0,16498,0,0,16503,0,16505,0,0,0,0,0,0,0,0,16506,0,0,0,16508, +16509,0,0,0,0,0,0,0,0,16511,16513,0,0,0,16516,0,16517,0,16519,0,16529,0,0,16531, +0,0,0,0,0,0,16534,0,0,16541,16542,0,0,0,0,0,0,0,0,0,16543,16547,16548,0,0,0, +16551,0,16552,0,0,0,16553,0,0,16558,0,0,16562,16565,0,0,0,16570,0,0,0,16573, +16585,0,0,0,16586,16587,16595,0,16596,0,16598,0,0,0,16600,0,0,0,0,0,0,0,0,0,0,0, +0,0,16601,0,0,0,0,16603,0,0,0,0,0,0,0,16604,16612,0,0,0,0,16613,0,16618,0,0,0, +16640,0,0,16641,0,0,0,0,0,0,16645,0,0,0,0,16646,0,0,0,0,0,0,16651,0,0,0,0,16653, +16654,0,0,0,16655,0,0,16656,16667,0,0,0,0,16671,0,16672,0,0,0,16673,0,0,0,0,0, +16676,0,16686,0,0,0,0,16689,0,16690,0,16692,0,16693,0,16694,0,16696,0,0,0,16705, +0,0,0,0,0,0,16707,0,0,0,16709,0,0,0,0,16711,0,16712,16713,0,0,0,16715,0,0,0,0, +16716,0,0,0,0,0,0,0,0,0,16718,16724,0,0,16726,16727,0,0,0,0,0,0,0,16728,0,16729, +0,0,16730,0,0,0,0,0,16731,0,0,0,16732,0,0,0,0,16734,16738,0,0,0,0,0,0,0,0,16743, +0,0,16745,0,0,0,0,0,16749,0,16752,0,0,0,0,16756,0,0,16758,0,16759,0,0,0,0,0, +16760,0,0,0,0,0,0,0,16762,0,16769,0,16770,0,16772,0,0,0,16777,16780,0,0,0,0,0,0, +16781,0,0,16782,0,16784,0,0,16785,16787,16792,0,0,16794,0,0,0,16798,0,0,16809,0, +0,16814,16816,16817,0,16819,0,0,0,0,0,0,0,0,0,0,16820,0,0,16836,16839,0,0,16841, +16851,16857,0,0,16858,16859,0,0,16860,0,0,0,0,0,0,0,0,16862,0,16863,0,0,0,0,0,0, +0,16864,0,0,0,0,0,0,0,16876,0,16881,16882,0,16885,16886,0,16887,0,0,0,16889, +16891,0,0,0,0,0,16894,16895,0,0,0,0,0,0,0,0,0,0,0,16897,0,16898,0,0,0,0,0,16913, +0,0,16924,16925,16926,0,0,16927,0,0,0,16937,16938,0,0,0,16940,16941,0,0,0,16942, +16945,0,16946,16949,16950,0,0,0,16952,16955,0,0,0,16965,0,16969,0,0,16975,0,0, +16976,0,0,0,0,16978,0,0,16981,0,16983,16989,0,0,0,0,16990,0,0,16991,0,0,0,16993, +0,16994,16996,17000,0,0,0,0,0,17002,17004,0,17006,0,0,17007,0,0,0,0,17008,17013, +17014,0,0,0,0,0,0,0,0,0,17021,0,17031,0,0,0,0,0,17033,17036,0,17038,0,0,17039,0, +17045,0,0,17046,17047,0,0,0,0,17048,0,17049,17050,0,17051,17053,0,17054,0,17055, +0,0,0,0,0,17063,0,0,17064,0,0,0,0,0,0,0,17065,0,0,17068,0,0,0,0,0,17072,0,0,0,0, +0,0,17073,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17074,0,17080,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,17081,17083,17084,0,0,0,17085,0,0,0,0,17092,0,0,0,0,0,0,0, +0,0,17093,0,17095,17102,0,0,0,0,0,0,17103,0,0,17105,0,17107,0,0,0,0,17114,0,0,0, +0,0,17115,17125,17127,0,0,17128,0,0,0,17129,17130,0,17131,0,0,0,0,0,17132,17135, +17145,0,0,0,0,0,0,0,0,17146,0,17147,0,17148,0,0,0,0,0,0,17149,17150,0,17151, +17153,0,17155,0,0,0,0,17163,17171,0,17174,0,0,0,0,17179,0,0,17182,17185,0,0,0,0, +0,17186,0,0,17188,0,0,0,0,0,0,0,17189,17191,0,17194,0,0,0,0,0,0,0,0,0,17195, +17196,17203,17204,0,0,17205,17217,0,0,0,0,0,17218,0,0,0,0,17219,0,17220,0,17221, +0,0,17230,0,0,0,0,0,17236,0,17238,17239,0,0,0,17241,17244,0,0,17245,0,17248,0,0, +17251,0,17252,0,0,17264,0,17266,0,0,0,17268,0,0,0,0,17271,17272,0,17273,0,17295, +0,17302,0,17305,0,0,0,17306,0,0,0,0,0,0,0,17308,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +17309,0,17310,17313,0,0,0,0,17314,17315,0,17317,0,0,0,0,17318,0,0,0,0,0,0,0, +17320,0,0,0,0,0,0,17334,0,17344,17348,0,0,0,17350,17351,0,0,17353,0,0,17354,0,0, +0,0,0,0,0,0,0,17355,0,0,0,0,0,0,17356,17357,0,0,17359,0,0,0,17371,0,17372,0,0,0, +17393,0,0,0,0,17394,0,0,0,0,0,17395,0,0,17399,0,0,0,17401,17417,0,17418,0,17419, +0,0,0,0,0,17422,17423,0,0,0,0,0,17424,0,0,0,0,0,17428,17429,17433,0,0,0,17437,0, +0,17441,0,0,17442,0,0,17453,0,0,0,0,0,0,0,0,17454,17456,17462,0,0,17466,0,0, +17468,0,0,17469,0,0,0,0,17470,0,17475,0,0,0,0,0,17479,0,0,0,17483,17484,0,17485, +0,17486,0,17491,17492,0,0,17493,0,17494,17495,0,0,0,17496,0,0,0,17497,0,0,0, +17502,0,0,0,0,0,17503,0,17505,0,17507,0,0,0,17512,17513,17514,0,0,17515,0,0,0, +17519,0,0,0,17522,0,0,17523,0,0,0,0,0,0,0,0,0,17527,0,0,0,17528,0,0,0,17534,0,0, +0,0,17536,0,0,0,17539,0,17540,17543,17549,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17556, +0,0,17558,0,17559,0,0,17560,0,0,0,17563,0,0,0,0,0,0,17564,0,0,17565,17566,0, +17567,0,0,0,0,0,0,17569,17570,0,17575,0,0,0,0,0,0,0,0,0,0,0,17581,0,0,0,17582, +17583,0,17586,0,0,17587,0,0,0,0,0,0,0,17588,0,0,0,0,17596,17597,0,0,17598,17600, +0,0,0,0,0,0,17601,0,0,0,17604,0,0,17605,0,0,17607,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,17612,0,0,17618,0,17621,17622,0,0,0,0,17623,0,0,17624,0,0,17630,0,0, +17631,17633,17634,0,0,0,0,0,0,0,17635,0,0,17636,0,0,17637,0,17638,0,17640,0,0,0, +0,0,0,0,0,0,0,17641,0,0,0,0,0,0,0,0,0,0,17643,0,0,0,0,17645,0,0,0,0,0,0,0,0, +17646,17662,0,0,0,0,0,0,0,0,0,17663,17664,0,17665,17666,0,0,0,17669,17671,17673, +0,17679,0,0,0,0,0,0,0,17684,0,0,0,17686,0,17714,0,0,17720,17722,17726,0,0,17728, +0,0,17729,0,0,0,17732,0,17733,0,17734,0,0,0,17735,0,0,0,0,17737,0,0,0,0,17739,0, +0,0,17741,17742,0,0,0,0,17743,17744,17745,0,0,0,17749,0,17750,17751,17752,17754, +17761,17762,0,17763,0,17766,0,17772,0,0,0,0,0,17775,0,0,0,0,0,0,0,17776,0,0, +17777,0,0,17778,17779,0,17782,17783,0,0,0,0,0,0,0,0,0,0,17784,0,0,0,0,0,0,0, +17821,0,0,0,17822,0,0,0,17823,17825,0,0,0,0,0,17826,17831,17832,17833,0,0,17845, +0,0,0,17846,0,0,0,17848,17850,17854,0,17855,0,0,17859,0,0,0,0,0,0,17860,17861,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,17870,17871,0,0,0,0,0,0,17872,0,0,0,17879,0, +0,0,17881,17883,0,17884,0,17885,0,0,17886,0,0,17887,17891,17953,0,0,0,0,17954,0, +0,17955,0,17968,0,0,17972,0,0,0,0,0,17974,0,0,0,0,17976,17978,0,0,17983,0,0,0,0, +18003,0,0,0,0,0,18007,0,0,0,0,0,18009,0,0,0,0,0,0,0,18010,0,0,0,0,0,0,18012,0,0, +18014,0,0,0,18015,0,0,0,18016,0,18017,0,0,0,18030,0,0,0,0,0,0,0,18031,0,0,18036, +18037,18038,0,0,18049,18056,0,18057,18058,0,18059,0,0,0,0,0,0,0,0,18062,0,0,0,0, +18064,0,0,0,0,0,0,0,0,18067,0,0,0,18068,0,0,18075,0,0,18078,18093,18094,0,0,0,0, +0,0,0,0,18097,0,0,0,0,0,18098,18100,0,0,0,18108,0,18111,0,0,18112,0,18113,0,0, +18115,18116,0,18118,0,0,0,0,18121,0,0,0,0,18123,0,0,0,0,0,0,0,0,0,18124,0,0,0,0, +18125,18126,0,18127,0,0,18128,18135,0,0,0,0,0,0,0,0,0,18150,0,0,0,0,0,18151, +18152,0,0,18156,18164,0,18166,18171,0,0,0,0,0,0,0,0,0,18172,18183,0,18184,0,0,0, +0,18185,0,18187,0,0,0,0,0,18188,0,0,0,0,0,0,0,0,18189,0,0,18190,0,0,18191,18192, +0,0,18194,18195,18196,0,0,0,18197,0,18203,0,18204,0,0,0,0,18205,0,0,0,18207, +18208,0,0,18214,0,0,0,18215,18216,0,0,0,18220,0,0,18222,0,0,0,0,0,18223,0,18225, +18231,0,18234,0,18235,0,0,0,0,18240,0,0,18241,18242,0,0,0,0,0,18243,18251,0, +18253,0,18254,0,0,0,18266,0,0,0,0,0,0,18269,18270,18271,18273,18281,0,0,0,0,0,0, +0,0,0,0,0,0,18282,0,18283,0,18284,0,0,0,0,0,0,18285,0,18287,18289,0,0,18290,0,0, +0,0,18308,0,0,0,18310,0,0,0,0,0,0,0,0,0,0,0,0,18311,0,18312,18313,0,18315,0,0, +18316,18320,0,18331,0,18332,0,18336,0,0,0,0,18337,0,18340,0,0,0,0,0,0,0,0,0, +18341,0,18344,18345,0,18346,0,0,0,0,0,18348,0,18351,0,0,18356,0,0,0,0,0,0,18357, +0,0,0,0,0,18367,0,0,0,18368,0,18369,0,18370,18371,0,0,0,18437,18444,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,18445,18450,0,0,0,0,18451,0,18452,0,0,0,18453,0,0,0,0,0,18455,0, +0,0,18456,0,18457,0,18460,0,0,18461,0,0,0,0,0,0,0,0,18466,0,0,18467,0,0,0,0, +18473,0,0,0,18476,0,18477,0,0,0,18478,18479,18480,0,0,0,18485,0,0,0,18486,0,0,0, +0,0,0,18488,18490,0,0,0,0,0,0,18491,0,0,0,0,0,18495,0,0,18496,0,0,0,0,0,0,18505, +0,18521,0,18522,18523,0,0,0,18525,18526,0,0,0,0,0,18527,0,0,0,0,18532,18533,0, +18534,0,0,0,0,0,0,18535,18537,0,18538,0,0,0,0,0,0,18540,18541,18542,18543,0, +18546,0,0,0,0,18553,18556,0,0,18558,0,0,18569,18571,0,0,0,18572,0,18574,0,0,0,0, +18586,0,0,0,0,0,18588,0,0,18589,0,0,0,0,0,0,18590,0,18592,0,0,0,0,18594,0,0,0, +18596,0,0,18597,18598,0,0,18601,0,0,0,0,18602,0,0,0,18603,18604,0,18605,0,0,0,0, +18608,0,0,18611,0,0,0,0,0,0,0,0,0,18612,0,18616,0,0,18617,18619,0,0,0,18628,0,0, +0,18629,0,0,18630,0,0,0,0,0,0,0,18631,0,18632,0,0,18635,18637,0,0,0,0,0,0,18641, +18643,18648,0,18652,0,0,18653,0,18655,18656,0,0,0,18657,0,0,18666,18674,0,0,0,0, +18677,18684,18685,0,0,18686,0,0,18690,0,0,0,0,0,0,0,18695,18696,0,0,0,0,0,0,0,0, +0,0,18697,0,0,18700,0,0,0,0,0,0,18702,0,18708,0,0,18709,0,18710,0,0,18711,0, +18714,0,0,18718,0,0,0,0,0,0,18719,0,0,18722,0,18726,0,0,0,0,0,0,0,0,0,0,0,0,0, +18731,0,0,0,0,0,18739,18741,0,0,18742,0,18743,18744,18746,18748,0,18752,18753,0, +0,18754,18763,0,18765,0,0,0,18766,0,0,0,18769,0,0,0,0,0,18773,18778,18779,18781, +0,0,18784,18787,0,18788,0,18793,0,0,0,0,0,0,18795,0,0,18800,0,0,0,0,0,18801, +18804,0,0,0,0,0,0,0,18806,0,0,0,18811,18815,18816,0,0,0,0,18825,0,0,18827,18829, +0,0,18830,0,0,0,0,18831,0,0,18832,0,0,0,0,18833,0,18840,0,18841,0,18842,0,0,0,0, +18843,0,18844,0,0,0,0,0,0,18845,18846,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +18848,0,0,0,18853,18860,0,0,18862,18866,0,0,18867,18869,0,0,18874,18881,18891,0, +0,0,0,0,0,0,0,0,0,18892,0,0,0,0,0,0,0,0,18895,0,18896,0,0,0,18900,0,0,0,18901,0, +18902,18915,18916,0,0,0,0,0,0,0,0,18919,0,0,0,0,0,18920,0,0,0,18921,18929,0,0,0, +0,18930,0,0,0,0,0,0,18932,0,0,0,0,18934,18942,0,0,0,18951,18957,0,0,0,0,18958,0, +0,0,0,18959,18960,0,0,18961,0,0,18962,0,0,0,0,18963,18964,0,0,0,18965,0,18967,0, +0,0,0,0,0,0,0,0,18968,0,18969,0,18970,18973,18976,0,0,0,0,0,0,18977,0,0,0,18981, +0,0,0,18990,0,18998,0,0,0,0,0,18999,19003,0,0,19005,0,0,0,19006,0,0,0,0,0,0, +19008,19011,0,0,19018,0,0,19019,0,19024,0,19031,19032,0,19039,0,19041,19050,0,0, +0,19051,19055,19056,0,19059,19063,19064,0,0,19088,0,0,0,19093,19094,0,0,0,0, +19095,0,19096,0,0,0,19097,0,0,19098,0,19099,19100,0,0,19103,0,0,0,0,0,0,0,19111, +0,0,0,0,0,0,19112,0,0,0,19116,19117,0,19121,19122,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,19123,19124,0,0,0,0,0,0,0,19125,19126,0,19128,0,0,0,0,0,0,0,0,0,0, +19129,19130,19131,19132,0,0,19146,0,0,19147,19156,19158,0,0,0,0,0,0,0,0,19182, +19185,0,0,19187,0,0,0,19193,0,0,0,0,0,19194,0,19197,0,0,0,0,19198,0,0,0,0,0,0,0, +0,0,0,19202,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19203,0,19205,19210, +0,0,0,19213,0,19218,0,0,0,19223,19229,0,0,19230,0,0,19231,19232,19233,19239,0,0, +0,0,0,19240,0,19248,19249,0,0,0,0,19254,0,19256,19258,19259,0,0,19261,0,19266,0, +0,0,19272,0,19278,19281,19282,0,0,0,0,0,0,0,0,0,0,0,0,19283,0,0,19284,0,0,19285, +19287,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19288,19291,0,19292,0,0,0,0,19297,0,19298,0,0, +0,0,19302,19303,0,0,0,0,19304,19305,0,0,0,0,19314,0,0,19315,0,0,19321,0,0,0,0,0, +0,0,19322,0,19333,0,19334,19335,0,19336,19337,0,0,0,0,0,0,0,0,0,0,0,19346,0,0, +19353,0,19354,19362,0,19366,19367,0,0,19369,0,19375,0,19377,19380,19388,0,0,0,0, +0,19389,19390,0,0,0,0,19392,0,0,0,0,0,19402,0,0,0,0,0,0,0,0,19412,0,0,19413, +19422,0,19424,0,0,0,19425,0,0,0,19428,0,0,0,0,19431,0,0,0,0,0,19432,0,0,0,0,0, +19448,19459,0,0,19461,0,19462,19463,0,19467,19474,19482,0,0,0,0,19494,0,0,0,0, +19501,0,0,0,0,0,0,0,0,0,0,19502,19504,0,0,0,0,0,0,0,19505,0,0,0,0,19506,19507,0, +0,0,19508,0,0,19511,0,0,19514,0,19515,0,19516,0,19518,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,19530,0,19537,19538,0,19543,19546,0,19547,19551,0,0,0,0,0,0,19552, +19553,0,0,0,0,0,0,0,0,0,0,0,0,19555,0,0,19556,0,0,0,0,0,0,0,0,0,0,0,0,19560, +19561,0,0,19562,0,0,0,0,0,0,19565,19567,0,19568,0,0,0,19569,19570,0,19578,0,0,0, +0,19580,0,0,0,0,19581,19584,0,0,0,0,0,0,0,19585,19586,0,0,0,19587,19588,0,19589, +0,0,0,0,0,0,19592,19593,19599,0,19600,0,0,19604,0,0,19605,0,19606,19608,19610,0, +19613,19614,0,0,0,0,0,0,19616,19617,0,0,19618,0,0,19619,0,0,0,19620,19621,19631, +0,0,19632,19634,19636,0,19643,0,0,19644,19658,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,19659,0,0,0,0,0,0,0,0,0,0,0,19675,19677,0,0,0,0,19679,0,19683,0,19684,0,0, +0,0,0,0,19687,0,0,0,0,0,0,0,0,19688,19689,19692,0,0,0,0,0,0,0,19695,19697,0,0,0, +0,0,19698,19699,0,0,19700,0,19702,0,0,19703,0,0,0,0,0,0,19704,19708,0,19710,0, +19713,0,0,0,19715,0,0,0,0,19718,0,0,0,0,0,0,0,19720,0,19722,0,0,19725,0,0,0,0,0, +0,0,0,0,0,0,0,0,19730,0,0,0,0,0,19731,0,19734,19735,19739,0,0,19740,0,19741,0,0, +0,19746,0,0,19747,0,19771,0,0,0,0,0,0,0,0,19772,19775,0,0,0,0,0,0,19778,0,0,0,0, +0,19779,0,0,19780,19790,0,19791,0,0,19792,0,0,0,19793,0,0,19796,19797,0,0,0, +19799,0,0,0,19801,0,0,0,0,19803,0,19804,0,19805,0,0,19807,0,0,0,19808,0,0,0,0,0, +0,19809,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,19816,0,19821,0,19822,19830,19831,0,0, +0,19833,0,0,0,0,0,0,0,0,0,0,19838,0,0,0,0,19839,0,0,19843,0,0,0,0,19845,0,0,0,0, +19847,0,0,19848,0,19849,0,0,0,0,0,0,0,19851,0,0,0,19854,0,0,0,0,0,0,0,0,0,19864, +0,19865,0,19866,0,0,0,0,0,0,0,19868,0,0,19870,0,0,19871,0,0,19872,19873,19875,0, +19880,19882,19884,0,0,19885,19886,19888,0,0,0,0,0,0,0,0,0,0,0,0,19890,19892, +19893,0,0,19894,0,0,0,19895,0,19896,19902,0,0,19903,0,0,19905,0,0,0,19906,0, +19908,0,19909,19911,0,0,0,19913,19920,0,19938,19939,19940,0,0,0,0,0,0,0,19942,0, +19943,0,19945,0,0,0,19951,19952,19954,19960,0,19965,0,19971,0,0,0,0,0,19975,0, +19976,0,19990,0,0,19991,0,19993,0,19995,0,0,0,19998,19999,20001,0,20003,20005,0, +20011,20012,0,0,0,0,0,0,20014,0,20020,0,0,0,0,20021,0,0,0,0,0,20023,20024,0,0,0, +0,0,20025,0,0,20027,0,0,20029,0,0,20032,0,0,0,0,20044,20045,0,20048,20049,0,0, +20050,0,20052,0,0,20054,20057,0,0,0,0,0,0,0,0,0,20059,0,0,20061,0,20062,0,20064, +0,0,20066,0,0,20067,0,0,0,0,20069,0,0,0,0,0,0,20070,20071,0,0,0,0,0,0,0,0,0,0,0, +20072,0,0,20073,20074,0,0,0,0,0,20075,0,20078,0,0,0,0,20080,0,20081,0,0,0,0,0,0, +20095,0,20098,0,0,0,0,0,0,0,20107,0,0,0,0,0,0,0,0,20112,0,0,0,20113,20114,0,0,0, +20115,20123,20124,0,0,0,20131,20133,20134,0,0,0,0,20136,0,0,20137,20138,20150,0, +20152,0,0,0,20153,0,0,20154,0,0,0,20158,0,20163,0,0,20164,0,0,0,0,0,0,0,20166,0, +20168,0,20170,0,20175,0,0,20178,0,0,0,0,20223,0,0,0,0,20224,0,20226,0,0,20230,0, +20231,0,0,0,0,20232,0,0,20233,20234,0,20244,0,20247,0,0,0,0,0,0,20249,0,0,0, +20250,0,0,0,0,20251,0,20253,0,20254,0,0,0,0,20256,0,0,20264,0,0,0,0,20266,0,0,0, +20278,0,0,20279,20282,0,0,0,0,0,20283,0,20284,0,20285,0,20287,20290,0,0,0,0, +20292,0,0,0,0,20293,20297,0,0,0,0,0,0,20299,0,20300,20303,0,0,0,0,0,0,20307,0,0, +20308,0,20309,0,20310,0,0,0,0,0,0,20312,0,0,0,20314,0,0,0,0,20315,20316,0,20322, +0,0,0,0,0,0,20339,0,0,0,20342,0,0,0,0,20352,0,0,0,0,0,0,0,0,0,0,20362,0,0,20365, +0,20375,20377,0,0,0,0,0,0,0,0,0,0,0,20378,20379,0,20380,0,0,20381,0,20382,0, +20383,0,20388,0,0,0,0,0,0,0,0,0,0,0,0,0,0,20390,20392,20393,0,0,20395,0,0,0,0,0, +20396,0,0,0,0,0,0,0,0,20398,20415,0,0,0,20417,0,0,20420,0,0,20426,20428,0,20431, +0,0,20432,0,20433,20434,20435,0,0,0,0,20440,0,0,0,0,0,20442,0,20443,0,20446,0,0, +0,0,20448,0,20451,0,0,0,0,0,0,0,0,0,20452,20453,0,0,20454,0,0,0,0,0,0,20457,0, +20458,0,0,0,20465,0,0,0,0,0,20469,0,0,0,20473,0,20476,0,0,0,0,0,0,0,0,20477,0,0, +20485,0,0,20486,0,0,20487,0,20496,0,20497,0,0,20498,0,0,0,0,0,0,0,0,0,0,20499, +20500,0,20501,0,0,0,0,0,20520,20527,0,20529,0,0,0,0,20539,0,0,20540,0,0,0,20543, +0,0,0,20546,0,0,0,0,0,20548,0,0,20563,0,0,20564,0,20566,0,0,0,0,0,20589,0,0,0,0, +20590,0,0,20593,20594,0,0,0,0,20595,0,20597,20598,0,0,0,20618,20620,0,0,0,0, +20621,0,0,0,0,20627,0,0,0,0,0,20628,0,0,0,20629,0,20630,0,0,20639,0,0,0,0,0, +20707,0,0,20709,0,0,0,20713,20714,0,0,0,0,0,20724,20725,0,0,0,0,20726,20728, +20729,0,20733,0,20734,0,20735,20736,0,20737,0,0,20744,0,20745,0,20748,0,0,20749, +0,0,0,0,0,0,0,0,20750,0,0,0,0,20754,0,0,0,20761,0,0,20763,0,0,0,0,0,0,0,20766,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,20767,0,0,0,0,20768,0,20769,20777,0,0,0,0,0,0,20785,0, +0,0,20786,20795,20801,0,20802,0,20807,0,0,20808,0,0,20810,0,0,20811,0,20812,0,0, +0,0,0,20813,0,0,20818,20820,20821,0,0,0,20822,0,20823,0,0,0,20826,0,0,0,0,0,0,0, +20829,20830,20831,0,20832,20836,0,0,20839,0,0,20840,20842,0,20843,0,20844,0, +20854,0,0,0,20855,0,0,0,0,20856,0,0,0,20869,0,0,20871,0,0,0,0,0,0,0,20873,0,0,0, +0,0,20876,0,0,0,0,0,20880,0,0,20882,0,0,0,0,20883,20884,0,0,20890,0,0,0,0,0,0,0, +0,0,20891,0,0,0,0,0,20905,0,20906,20910,0,0,20912,20915,0,0,0,0,0,20916,0,20917, +0,20919,20920,20922,0,20927,0,20928,20929,20930,0,0,20935,0,0,20939,0,0,20941,0, +0,0,20943,0,0,0,20946,20947,0,0,0,0,0,20950,0,20954,0,0,20955,20964,0,0,20967,0, +0,0,0,0,20973,20975,0,0,0,20984,0,20987,20988,0,0,0,0,0,20989,0,0,0,20995,0, +20998,0,20999,0,0,0,0,21000,21001,0,0,0,0,21008,0,21010,0,21016,0,0,0,21017, +21018,0,0,0,0,0,21021,21026,21027,21028,0,0,21029,0,0,0,0,0,21030,0,0,0,0,0,0,0, +0,0,0,0,0,0,21031,21032,0,0,0,0,0,21037,0,0,21038,0,0,0,0,0,0,0,0,0,21039,0, +21041,0,21046,21047,0,0,0,21049,21053,0,0,21057,21064,21065,0,0,21066,21067,0,0, +0,21069,0,0,0,21071,21072,0,0,21073,0,21074,0,0,21078,0,0,0,0,21079,0,0,21080, +21081,0,0,21086,21087,0,21089,0,0,0,0,0,0,0,21091,0,21093,0,21094,0,0,0,0,0,0,0, +0,21095,0,0,0,0,0,21096,0,21098,0,0,0,0,0,0,0,21099,0,0,21100,21101,21102,0,0,0, +0,0,21103,0,21104,0,0,0,0,0,21105,21108,21109,0,0,21112,21113,0,0,0,0,0,0,21115, +21122,21123,0,0,0,0,0,21125,0,0,0,0,0,0,0,0,21129,21131,0,0,21134,0,0,0,21137, +21142,0,21143,0,0,21144,0,21145,21146,0,21152,21154,21155,21156,0,0,0,21160,0,0, +0,0,0,0,21161,0,21164,0,21166,0,0,0,0,21170,0,0,0,0,21171,0,0,21172,0,21174,0, +21175,0,0,0,0,0,21176,21179,21188,0,0,0,21189,0,0,21190,0,0,0,21192,0,0,21193,0, +0,0,21198,0,21212,0,0,21213,0,0,0,0,0,0,21215,21216,0,0,21223,21225,0,21226,0,0, +0,0,21227,21228,0,0,21229,0,0,0,0,21230,21236,0,0,0,0,0,0,0,0,0,0,0,0,0,21237,0, +0,21238,21239,0,0,0,0,21256,0,0,0,0,0,21257,0,0,0,0,0,0,0,21259,0,0,0,21263,0, +21272,0,21274,0,21282,0,0,0,0,0,0,0,0,21283,0,0,0,0,0,0,0,0,21294,0,0,21297,0,0, +0,0,21298,0,0,0,21299,0,21300,21302,0,21316,0,21318,21322,21323,0,21324,0,21326, +0,0,0,21327,21328,0,0,0,21352,0,0,21354,21361,0,0,0,0,0,0,0,0,0,0,0,0,0,21362,0, +0,0,21363,0,0,0,0,0,0,0,0,0,21366,0,0,21367,21372,21374,0,0,0,21375,21377,0, +21378,0,0,0,21380,0,0,0,0,0,0,0,0,0,0,21381,0,0,0,0,0,0,21382,0,21383,0,0,21384, +0,0,21385,0,0,0,0,21389,21390,0,0,0,0,0,0,0,0,0,0,0,0,0,21397,21398,0,0,0,0,0,0, +0,0,0,0,21399,0,21400,0,0,0,0,21402,0,0,0,21403,21404,0,21405,21406,0,0,0,21407, +0,0,0,0,0,0,0,0,0,0,0,0,21408,0,0,0,0,21409,0,21421,0,21422,0,0,0,21425,21428,0, +0,0,0,21429,0,0,0,0,0,21433,0,0,0,0,0,0,0,0,0,0,21434,0,21443,0,21444,21449,0, +21452,0,21453,21454,0,0,0,21457,0,0,21458,0,0,0,21460,21461,0,0,21464,0,0,0, +21473,21478,0,0,21479,0,0,21481,21483,0,0,0,0,0,0,0,0,21484,0,0,21485,21486,0,0, +21488,0,0,0,0,0,0,21523,0,0,21525,0,0,0,0,0,0,0,21526,0,0,0,0,0,0,21529,21530,0, +0,21531,0,0,21533,0,0,21539,21564,0,21567,0,0,0,0,0,0,0,0,21575,0,0,0,0,21577,0, +0,0,0,0,21591,0,0,21604,0,0,0,0,0,0,0,0,0,21605,0,21606,0,0,21617,21618,21619, +21620,0,0,0,0,0,0,0,0,0,0,0,0,0,21623,0,0,0,0,21631,0,21635,0,0,0,0,21639,21646, +21653,21662,0,0,21663,21664,0,21666,0,0,21667,0,21670,21672,21673,0,21674,21683, +0,0,0,0,0,21684,0,21694,0,0,0,0,21695,21700,0,21703,0,21704,0,0,21709,0,0,0, +21710,0,0,0,0,0,0,0,0,21711,0,0,0,21712,0,21717,0,21730,0,0,0,21731,21733,0,0,0, +0,21737,21741,21742,0,21747,0,0,0,21749,0,0,0,0,0,0,0,0,0,0,0,0,0,21750,0,0,0,0, +0,21752,0,0,0,0,21753,0,0,0,0,0,0,21755,21756,0,21757,0,0,0,0,0,0,21760,0,0, +21763,0,0,0,0,0,0,0,0,0,21764,0,0,21766,0,0,21767,0,0,0,0,0,0,0,0,0,21773,0, +21774,0,0,21775,0,0,0,0,21776,0,0,21777,0,0,0,0,0,0,0,0,0,21780,21787,21788, +21791,0,0,0,21797,0,0,0,0,0,21805,0,0,0,0,21806,0,21807,21809,0,21810,21811,0, +21817,21819,21820,0,21823,0,21824,0,0,21825,0,0,21826,21832,0,0,0,0,0,21833, +21848,21849,0,0,21867,21870,21871,21873,0,0,0,21874,0,0,0,0,0,0,0,0,0,21875,0, +21878,0,0,0,21879,0,21881,21886,0,0,0,0,21887,0,0,21888,21894,21895,21897,0, +21901,0,21904,0,0,21906,0,0,0,21909,21910,21911,0,0,21912,0,0,21913,21914,21915, +0,21919,0,0,0,0,0,0,0,21921,0,0,21922,21933,21939,0,0,0,0,0,0,0,0,0,0,0,21944,0, +0,0,0,0,21945,0,21947,0,0,0,0,0,0,0,0,0,0,21949,0,0,0,21950,0,0,0,0,0,0,0,0,0,0, +0,0,0,21951,0,21952,0,0,0,0,0,0,0,0,0,21954,21957,0,0,0,0,21958,0,21959,0,0,0,0, +0,0,21962,21963,0,0,0,0,0,0,0,0,21964,21965,0,0,21969,21970,0,0,0,21974,0,0, +21980,21981,0,21982,0,0,0,0,0,21985,0,21988,0,21992,0,21999,0,0,0,0,0,0,22001,0, +22002,0,0,0,0,0,0,22003,0,0,0,0,0,22004,0,0,0,22008,0,22009,22015,0,0,22016,0,0, +0,22017,22019,0,0,0,0,0,0,0,0,0,22020,0,0,0,0,0,0,0,0,0,0,22021,22037,0,22039,0, +0,0,22040,0,0,0,22048,22049,0,0,22053,22055,22056,22059,0,0,22060,22061,0,0, +22064,0,0,0,0,22066,0,0,0,0,0,0,0,22073,0,0,0,22074,22075,0,0,0,0,0,0,0,22076,0, +0,0,0,22077,22084,22099,0,0,0,0,0,0,0,22104,0,0,22107,0,22108,0,22109,0,22110,0, +0,0,0,0,0,0,22111,22119,0,22120,22122,0,0,0,0,22125,0,0,0,22128,22129,0,0,0,0,0, +0,22141,0,0,0,22142,0,0,22144,22146,0,22148,22149,22151,22154,0,0,0,22162,0,0,0, +0,22164,22177,0,0,0,0,22179,0,22182,22183,0,0,22184,22188,0,0,0,0,0,0,0,0,22190, +0,22194,22201,0,0,22208,0,22209,0,22212,0,0,22215,0,22223,22231,0,0,22232,0, +22234,0,0,22235,22236,0,22237,0,22240,0,0,0,0,0,22241,0,0,0,22242,22246,22247,0, +0,0,22259,22268,0,22269,0,0,0,0,0,0,0,22270,0,0,0,0,22271,0,22272,0,22277,0,0,0, +0,0,22278,22280,22283,22286,0,0,22287,22289,0,0,22290,0,22293,0,0,0,0,0,0,0,0,0, +0,22295,0,22301,22302,0,0,0,22305,0,22308,0,0,0,0,0,0,0,0,0,0,22315,0,0,0,22317, +0,22334,0,0,0,22335,0,0,0,0,0,22336,0,22338,22344,0,22347,22349,0,22350,0,0,0,0, +0,0,0,22357,0,0,0,0,0,22358,0,0,0,0,0,0,0,0,0,0,22359,22360,0,0,0,0,0,0,0,0, +22361,22366,0,0,22369,0,22370,22373,0,0,0,0,0,22375,0,22377,0,0,0,0,0,22378,0,0, +0,0,22381,0,0,0,0,22382,0,22383,0,0,0,0,0,0,0,0,0,22391,0,0,22392,22395,22396, +22402,0,0,0,0,0,0,0,0,0,0,0,0,0,22405,0,0,22406,0,0,22408,0,0,22409,22410,0,0,0, +0,0,0,22424,0,0,0,0,22426,0,0,0,22427,0,22428,0,22432,0,22435,22442,22443,0,0,0, +0,22444,0,0,0,0,0,22446,0,22454,0,22455,0,0,0,22465,0,22470,0,22471,0,0,0,0, +22472,22473,0,22487,0,0,0,22488,0,0,0,0,22489,0,0,22499,0,0,0,0,0,0,22514,0,0, +22515,0,0,0,0,0,0,0,22516,0,0,0,22517,22520,0,0,0,22534,0,0,22535,0,0,22536,0, +22540,22553,0,22555,0,0,0,0,22561,0,0,22562,0,0,0,0,0,0,0,0,0,0,0,22566,0,0,0,0, +22567,22568,0,0,22575,0,22579,0,22582,22583,22585,0,0,0,0,0,22586,0,0,22587,0,0, +22590,0,0,0,0,0,22591,0,22592,0,0,0,0,0,22593,0,22602,0,0,22604,0,0,22609,0,0, +22618,0,0,0,0,0,0,22619,0,22624,22625,0,0,22638,0,0,0,0,0,22639,0,0,22640,0,0,0, +0,0,0,0,22644,0,22645,22647,0,0,0,0,22652,22653,0,0,0,22654,0,22655,0,0,0,22656, +0,0,0,0,0,0,0,0,0,0,22673,22675,22676,0,0,22678,22679,0,22691,0,0,0,0,0,0,0, +22693,0,0,22696,0,22699,22707,22708,0,0,0,0,0,0,0,0,22718,0,22719,0,0,0,0,22723, +0,0,0,22724,22725,0,0,0,0,0,0,0,0,0,0,0,0,0,0,22726,22728,0,0,0,0,0,0,0,0,22729, +0,0,22731,0,0,0,0,22732,22735,22736,0,0,0,0,22739,0,22749,0,0,22751,0,0,0,0,0,0, +0,0,0,0,0,22758,0,0,0,0,0,22760,0,0,0,0,0,22764,22765,22766,0,22768,0,0,0,0,0, +22769,22770,0,0,0,0,0,0,22771,0,0,22772,22775,0,22776,22777,22780,0,0,22782, +22784,0,22787,0,22789,22796,0,0,0,0,0,22798,0,0,0,0,0,0,22802,0,22803,22804,0,0, +0,0,0,0,0,0,0,0,22805,0,0,22810,22811,22814,22816,0,22825,22826,0,22831,22833,0, +0,0,0,0,0,0,0,0,22834,0,22836,22838,0,22839,0,0,0,0,0,22840,0,22847,0,0,0,0,0, +22856,22857,0,22858,22859,0,0,22862,0,0,22864,0,0,0,0,22865,0,0,0,0,0,0,0,0,0,0, +0,22866,0,22867,22868,0,0,0,0,22869,0,22871,0,22872,0,22873,22881,22882,22884, +22885,0,0,0,0,0,0,0,22886,22887,0,22894,0,22895,0,0,0,22900,0,22901,0,0,0,0, +22904,0,0,0,0,22905,22907,0,0,0,22915,22917,0,0,22918,0,0,0,22920,0,0,0,22929, +22930,0,0,0,22941,22942,0,0,0,22943,0,0,0,22944,0,0,0,0,0,0,0,22946,0,22947,0,0, +22954,0,22956,0,0,22962,0,0,0,0,0,0,0,22963,0,0,22964,0,0,0,0,0,0,0,22965,0, +22968,0,0,0,22969,0,0,0,0,0,22970,0,22971,0,0,0,0,0,22978,0,0,22979,0,22987,0,0, +22989,0,0,0,0,0,0,22990,0,23005,0,0,0,0,0,0,0,23006,23007,23008,0,0,23023,23024, +23029,0,0,0,0,23030,0,0,0,0,0,23032,0,0,0,0,0,23035,0,0,0,0,23038,0,0,0,23048,0, +23049,23052,23053,23060,23061,0,23063,0,0,0,0,23067,23068,0,0,0,23069,23073,0,0, +0,23127,0,23128,0,0,0,0,0,23129,0,23138,23141,0,23149,0,0,23150,0,0,0,23152,0,0, +0,0,0,0,0,0,23154,0,0,0,0,23157,23159,23160,0,0,0,0,0,0,0,0,0,0,0,0,23180,0,0,0, +0,23181,0,0,23188,0,23189,0,0,0,0,0,0,0,0,0,0,0,0,23195,0,0,23196,23199,0,0,0,0, +0,0,0,0,0,23202,0,23204,0,23207,0,23209,23210,0,0,0,0,0,0,23227,23229,0,0,23230, +23234,23238,0,0,0,23245,23246,23248,0,0,0,0,23249,23254,0,0,0,23265,0,0,0,0,0,0, +0,23268,0,23276,0,0,0,0,23277,0,23297,0,23298,0,0,0,0,23299,0,23302,0,0,23303, +23312,0,0,23314,0,23320,0,0,0,0,23324,0,23325,0,23328,0,23334,0,0,0,23337,0,0,0, +0,23343,23344,23346,0,23348,0,0,0,0,0,0,0,0,23353,0,0,0,0,23355,0,23356,23358,0, +0,0,23359,23360,0,23361,0,23367,0,23369,0,0,23373,0,23378,23379,0,23382,23383,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,23387,0,0,0,0,0,0,23388,23390,0,0,23393,23398,0,0,0, +23399,0,0,0,23400,0,0,0,0,23401,0,0,0,23415,0,0,0,0,0,0,0,0,23416,0,23422,0, +23443,23444,0,0,0,0,23448,0,23454,0,0,0,0,0,0,23456,0,0,23458,23464,0,0,0,0,0,0, +23465,0,0,0,23470,23471,0,0,23472,0,0,0,23473,23496,0,0,0,0,0,0,0,0,23497,0, +23499,0,0,23502,0,0,23503,0,0,23513,0,0,23515,0,0,0,23517,0,0,0,0,23518,23519, +23521,23524,0,23525,23528,23539,0,0,0,0,0,23541,0,0,23544,0,0,23556,0,0,23557,0, +0,0,0,0,0,0,0,0,0,0,0,0,23559,0,23560,0,0,23561,0,0,23566,0,0,0,0,0,23568,23569, +23570,0,0,0,0,23571,0,23574,0,0,0,0,0,0,0,0,0,0,0,23575,0,23579,0,0,23581,0,0,0, +0,0,0,23587,0,0,0,0,0,0,0,23596,23598,0,0,0,0,23602,23606,0,0,23607,0,23608,0,0, +0,23614,23616,0,0,0,0,0,23618,0,0,23619,0,0,0,0,23621,23626,0,23627,0,0,0,0,0,0, +0,23629,0,23630,0,0,0,0,23634,0,23636,0,0,0,0,0,0,23638,0,0,0,0,23640,23667,0, +23669,0,0,0,23681,0,0,0,0,0,0,0,23682,0,23683,0,0,0,0,0,23684,0,0,0,23685,23689, +0,23693,23694,23700,0,23702,0,23709,0,0,0,0,0,0,0,23712,0,0,0,0,0,23714,0,0, +23715,0,0,0,0,23718,0,0,23720,0,0,0,0,23722,0,0,0,23726,23729,0,23741,23746,0, +23748,0,0,0,0,23749,0,0,0,0,0,23750,0,0,0,0,23751,0,23753,0,0,0,0,23757,23765,0, +0,0,23770,0,0,0,0,0,0,0,23771,0,23772,23781,0,0,23796,0,0,0,0,23798,0,23799,0,0, +0,23802,0,0,23806,0,23807,0,0,23808,0,23809,0,23819,0,0,0,23821,0,23827,0,0,0, +23829,0,0,0,0,0,0,0,23830,0,0,0,0,0,0,23832,23833,23834,23835,0,0,0,0,23837, +23838,0,0,0,0,0,23846,0,0,0,0,0,0,23847,0,0,0,0,0,23879,23881,0,0,23882,23883, +23895,0,23899,0,0,0,0,23901,0,0,0,0,0,0,23902,0,0,0,0,0,23903,23905,0,23906,0, +23907,23918,23919,23920,0,23922,0,23924,0,23927,0,23934,0,23937,23941,0,23942, +23946,0,0,0,0,0,23955,23956,23958,0,0,0,0,0,0,23959,0,23962,23965,0,23966,0,0,0, +0,23967,23968,0,0,23973,0,0,23974,0,0,0,0,23975,0,23976,0,0,0,0,0,0,0,0,0,0,0,0, +0,23977,0,0,0,0,0,0,0,0,23980,0,0,23984,0,23985,0,0,23987,0,0,23988,23990,23991, +0,0,0,0,0,0,23992,0,0,0,0,0,0,0,0,23994,0,0,0,23998,0,0,0,0,0,0,0,0,0,23999,0,0, +24003,0,24004,0,24006,0,0,0,24007,0,0,24008,0,0,0,0,0,0,0,24009,0,0,24010,0,0, +24011,0,0,24013,24014,0,0,24015,24016,24027,0,24028,24029,0,24030,0,0,0,0,0, +24033,24034,0,24035,0,0,24036,0,0,24044,0,24048,24049,24063,24067,0,24068,24070, +0,0,24071,24078,24087,0,24090,0,0,0,24095,0,24098,24101,24104,24106,0,24107,0,0, +0,24108,0,0,0,0,24110,24111,0,24113,0,0,24115,24120,0,0,0,0,0,0,24124,0,24125,0, +24126,0,24127,0,0,0,0,0,24135,0,0,24136,0,24137,24142,0,0,0,24146,0,0,24147, +24149,24154,0,24163,0,0,0,24165,24166,24167,0,0,0,0,0,0,0,0,0,0,24169,24170, +24175,0,0,0,24178,0,0,24179,0,0,24181,0,24184,24197,0,24201,24204,0,0,0,0,0,0, +24206,24212,24220,0,0,0,24224,0,0,0,0,0,0,0,0,24226,0,24234,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,24235,0,24236,0,0,0,0,0,24239,24240,24241,0,0,24248,0,0,24249,0, +24251,0,0,0,0,0,0,24253,0,24268,0,0,0,24269,0,24271,24272,0,0,0,0,24273,0,0, +24274,0,0,24279,0,0,0,0,0,0,0,24280,0,24293,24294,0,0,0,0,0,0,24296,0,0,24323,0, +0,0,24329,24330,24331,24339,0,24351,0,0,24369,24370,0,0,0,24371,0,0,0,0,24372, +24373,24374,0,0,0,0,0,24378,0,0,0,0,24379,0,24381,0,24383,24389,0,24390,0,0, +24394,24395,24400,0,0,0,24401,24402,0,24406,0,0,0,24411,0,0,0,24415,0,24416,0,0, +0,0,0,24417,0,24419,0,24422,0,24423,24428,0,24435,0,0,0,24439,0,0,0,24440,24442, +24446,0,0,0,24447,24448,24449,24452,0,0,0,0,24453,24457,0,0,24458,24459,24460,0, +24465,0,0,0,0,0,0,0,24470,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24471,0,24473, +24474,24475,24476,0,24478,0,0,0,0,24480,0,0,0,0,0,0,0,0,0,0,24481,0,0,0,0,0,0,0, +0,0,0,24482,24485,0,0,0,0,24486,0,0,0,24488,0,0,0,24494,0,0,0,0,24497,0,0,24498, +0,0,0,24499,24506,0,0,0,24507,0,0,24511,0,0,24513,24514,0,0,0,0,0,24517,0,24518, +0,24520,0,24521,24524,24525,0,0,0,0,0,24527,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24528,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,24537,24539,0,24540,0,0,0,24548,0,0,0,0,0,24549, +24550,0,0,0,24553,24554,0,24555,0,24556,0,24558,0,0,0,0,0,24560,0,0,0,24561,0,0, +0,0,0,24562,0,0,0,0,0,0,0,0,0,0,0,0,0,24567,0,0,0,0,0,24569,0,0,0,24574,0,24575, +0,0,0,0,0,0,0,0,0,0,0,24577,24581,0,24584,0,0,0,0,0,24585,0,0,0,0,0,24586,0,0, +24587,0,24588,0,0,0,0,0,0,0,0,0,0,24590,24591,0,0,0,0,24592,0,0,0,0,0,0,0,24594, +0,0,0,0,0,0,0,24596,24597,0,0,0,0,24602,24603,0,0,0,0,24604,0,0,24605,0,24610,0, +0,24611,0,0,0,0,24612,24615,24616,24624,0,0,0,24627,0,24638,24639,0,0,0,0,24640, +0,0,0,24655,24656,24657,0,0,0,0,0,0,0,0,24662,0,24663,24664,0,0,0,0,0,24665,0,0, +0,0,24667,0,0,0,0,0,0,24668,24669,0,24670,24674,0,0,0,24675,0,24678,0,0,24679,0, +0,0,24681,0,24683,0,0,0,0,24684,0,24685,0,0,24686,0,0,24688,24689,0,0,0,0,24690, +24691,0,0,0,0,0,0,0,24697,0,24698,0,0,0,0,0,0,0,0,24709,0,0,0,0,0,24710,0,24712, +0,0,0,0,0,0,24713,24714,0,24715,0,24716,24718,0,24719,0,0,0,0,24720,0,0,24725,0, +0,24738,0,24749,24750,0,0,0,24752,0,0,0,24753,0,0,0,24758,0,0,0,0,0,24762,0, +24763,0,0,0,0,0,0,0,24764,0,0,0,0,0,24765,24767,24768,0,24772,0,0,0,0,24773,0,0, +0,0,24777,0,0,0,0,0,24785,0,24786,24788,0,0,0,24789,0,0,0,0,24794,24798,0,24799, +24800,0,0,0,24803,0,24804,24806,0,24807,0,0,0,24810,0,0,0,0,0,0,24827,24828,0, +24835,0,0,0,0,0,0,24836,0,0,0,0,0,24839,0,24843,24844,0,0,0,0,0,0,0,0,0,0,24847, +0,0,24848,0,0,0,0,0,0,24849,0,24850,24851,0,0,0,24852,0,24853,0,0,0,0,0,0,0,0,0, +24854,0,24855,0,0,24868,0,0,0,24883,0,0,0,24884,0,24895,24897,0,0,0,0,0,24899,0, +0,0,0,0,24900,0,24913,0,0,0,0,0,0,24914,0,0,24917,24930,24931,0,0,0,24932,0,0, +24939,0,0,24942,0,0,0,0,0,0,0,0,0,24945,24950,0,24951,0,0,24953,0,0,0,24954,0, +24959,0,0,0,24961,0,0,24962,0,24964,24968,24970,24972,0,0,0,0,0,24976,0,0,0, +24977,0,24982,0,0,24983,0,0,24984,0,0,0,24993,0,0,0,24994,0,0,25001,0,0,0,25003, +0,0,25018,0,0,25023,0,0,0,25034,0,0,25035,25036,0,25037,0,0,0,0,0,0,0,25039,0,0, +0,0,0,25040,0,0,0,0,0,0,0,25042,0,0,25043,25045,0,0,0,0,0,0,25049,0,0,25051,0, +25052,25053,0,0,25054,0,0,0,25055,0,0,0,0,25057,25059,0,0,25060,25064,0,25065, +25069,25070,0,0,0,0,25072,0,25073,0,25090,0,0,25092,25093,25101,0,0,0,0,0,0, +25105,25108,0,0,25113,0,0,25115,25116,0,0,0,0,0,0,25117,0,0,0,25120,25121,0,0,0, +0,0,0,0,25125,0,0,0,25126,0,25130,25134,0,25139,0,25143,0,0,0,25151,0,25161,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,25163,0,0,0,0,0,0,0,25174,0,25175,0,25207,0,0, +0,25209,0,0,0,0,25213,0,25219,0,25223,0,25225,0,0,0,25227,0,0,0,25228,0,0,0, +25229,0,0,0,0,0,0,0,25231,25233,0,0,0,0,25237,25239,0,0,0,25243,0,0,0,25252,0, +25257,25258,0,0,0,0,25260,25265,0,25268,0,0,25273,25324,0,25325,0,25326,0,0,0,0, +0,0,0,0,25327,0,0,0,0,0,25328,0,0,0,0,0,0,25332,0,0,0,25333,0,0,0,25336,25337, +25338,0,0,25343,0,25350,0,0,0,0,0,0,0,25352,0,25354,0,25375,0,25379,0,0,0,0, +25384,0,0,0,0,0,0,0,0,0,25386,0,25388,0,25390,0,0,25399,0,0,25401,0,0,0,25402,0, +0,0,25407,0,0,0,0,0,0,0,0,0,0,0,25413,25415,0,0,25417,0,0,0,0,0,0,0,25419,0,0,0, +25421,0,0,0,25424,0,0,0,0,25433,0,0,0,0,0,0,0,0,0,25435,0,0,0,0,0,0,25436,0,0,0, +25437,0,0,25440,0,0,0,0,0,0,25442,0,0,25443,0,25446,0,0,25449,0,0,0,25450,0,0,0, +0,25452,0,25453,25454,25455,0,0,0,25456,0,25457,0,0,0,25459,0,25461,0,25468,0,0, +0,0,0,0,0,0,25469,0,0,0,0,0,25471,0,0,0,0,0,25474,0,0,0,0,0,0,0,0,25475,0,0,0,0, +25477,0,0,0,0,25483,0,0,0,0,0,25484,0,0,0,0,0,0,0,0,0,0,0,0,25485,0,25497,0,0, +25498,0,25504,0,25510,0,25512,0,0,25513,25514,0,0,0,0,0,0,25517,25518,25519,0, +25520,0,0,0,0,0,0,0,25521,0,25522,25527,25534,0,25536,0,25537,0,0,25548,25550,0, +0,25551,0,25552,0,0,0,0,0,25554,0,25555,0,25556,25557,25568,0,0,0,25570,25571,0, +0,0,0,0,0,25574,0,0,0,0,25579,0,0,0,25581,0,0,0,25582,0,0,0,0,0,0,0,0,0,25588,0, +0,0,0,25589,0,0,0,0,25590,0,25591,25592,25593,0,25594,0,0,0,25596,0,25597,25615, +0,0,0,0,0,25618,0,0,0,0,25619,25623,0,0,25629,0,0,25631,0,0,0,25635,25636,0,0, +25649,0,0,0,0,25654,0,0,0,25661,25663,0,0,25671,0,0,25678,25698,0,25699,25702, +25703,0,0,0,0,0,0,0,0,25704,0,0,0,0,0,25706,0,0,25710,0,25711,0,25712,0,25715, +25716,25717,0,0,25718,25728,25732,0,0,0,25734,0,0,0,0,0,0,0,0,0,25737,0,0,25739, +0,0,0,25740,0,25741,25745,0,25746,0,25748,25772,25778,0,0,0,0,0,25780,0,0,0,0, +25781,0,25782,25784,25785,0,0,0,25789,0,0,0,0,0,0,25797,25801,0,0,0,25808,25809, +0,0,25811,25814,25815,0,0,25817,0,0,0,0,0,0,0,0,25820,0,0,0,0,25832,25833,0,0,0, +25846,0,0,0,25847,25848,0,0,0,0,0,0,0,0,0,25849,25850,0,0,25851,0,0,25852,0, +25862,0,0,0,25863,25865,0,0,0,0,0,0,0,25867,25868,0,25869,25874,0,25875,0,25876, +25877,0,0,0,0,25878,25902,0,0,0,0,0,0,0,25903,25904,25905,0,0,0,25908,25909,0,0, +0,0,25910,0,0,0,0,0,0,0,25912,0,25913,0,0,0,0,0,0,0,0,25914,0,0,25916,0,0,0,0,0, +25917,25927,0,0,0,0,25928,0,0,25930,0,0,0,25933,0,0,25938,25942,0,0,0,0,0,0,0, +25945,0,25950,0,25956,0,0,25961,25962,0,0,25963,0,25964,25965,25966,0,0,0,0,0, +25967,0,0,0,0,25968,0,0,0,25969,25971,0,0,0,0,0,25973,25975,0,0,0,0,0,0,0,25978, +0,25981,0,0,0,25982,0,0,0,25984,0,0,0,0,0,0,0,25993,0,0,0,0,0,0,0,0,0,0,0,0,0, +26002,0,0,0,26005,0,0,0,26006,26007,0,0,26014,26015,26016,0,0,0,0,0,0,26017, +26018,26020,0,26022,26023,0,0,0,26024,26028,0,26029,26033,26034,26044,0,0,0,0,0, +26046,0,0,26047,0,0,26049,0,26050,0,26051,0,0,0,0,0,26053,0,0,0,0,26054,26059,0, +0,0,0,0,0,26060,0,26066,0,0,0,0,0,0,0,0,0,0,0,0,26067,0,26069,0,0,26071,0,0,0, +26073,0,26074,26077,0,0,0,0,26078,0,0,0,26079,0,26090,0,0,26094,0,0,0,0,0,0,0,0, +26095,0,0,0,0,0,0,0,0,0,0,0,26096,26101,0,26107,26122,0,26124,0,0,26125,0,0,0,0, +0,0,26136,26141,26155,0,0,0,0,0,0,0,0,0,26164,26166,0,0,0,26167,0,26170,26171,0, +0,26172,0,0,26174,0,0,0,0,0,0,0,0,0,0,0,0,0,26175,0,0,0,26176,26177,0,26321, +26322,0,26323,0,0,26324,0,0,0,0,0,0,0,26325,0,26331,0,0,0,0,0,0,26335,0,0,0, +26350,0,0,0,26379,0,0,26382,26383,26385,0,0,26392,26406,0,0,0,0,26411,0,0,0,0,0, +26412,0,0,26420,0,0,26423,0,26424,26426,26432,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +26435,0,26436,0,0,0,0,0,26441,0,26444,0,0,0,26446,0,0,0,0,26447,0,0,0,0,26449,0, +26450,26452,0,26453,26454,0,0,0,26455,0,0,0,26456,0,0,26458,0,0,26460,0,26463,0, +0,0,0,0,0,0,0,26464,26470,0,0,0,0,0,0,0,0,0,26473,0,0,26474,0,0,0,0,0,0,0,26475, +0,0,0,0,0,0,0,26477,0,26485,0,0,26486,0,26487,0,0,26488,26493,26494,0,0,26495,0, +26497,26504,26506,0,0,0,0,0,26507,0,0,0,0,0,26509,0,0,26510,0,0,0,0,0,0,0,0,0,0, +0,0,0,26512,0,26513,26515,0,0,0,26518,0,0,0,26519,0,26524,26526,0,0,0,26527,0, +26532,0,26533,26537,26558,0,0,0,26559,0,0,0,26571,0,0,26573,0,26588,0,26593,0,0, +0,0,0,0,26603,0,26604,0,0,0,0,0,0,0,0,0,0,26606,0,0,0,0,0,0,0,26607,26609,26611, +26614,0,0,0,26616,26620,0,26621,0,0,0,0,0,26627,0,26629,0,0,26630,0,0,26632, +26643,0,0,0,26644,0,0,0,0,0,0,0,0,0,26646,26647,0,0,0,26650,0,0,26656,0,0,0,0, +26663,26670,26671,0,0,0,26685,26686,26687,0,26689,0,0,0,0,26744,0,26745,0,26747, +26748,0,26749,26750,26751,0,0,0,0,26752,26755,0,0,0,26756,26769,0,0,0,26774,0,0, +0,0,0,26775,0,26777,26778,0,26786,0,0,0,26787,0,0,0,0,0,0,0,0,0,0,0,0,0,26788,0, +0,26789,0,0,0,0,0,26791,0,26792,26793,0,0,0,26794,0,26797,26798,0,0,0,26800,0,0, +26803,0,26804,0,0,0,0,0,0,0,0,0,26805,0,0,26808,0,0,26809,0,0,0,0,0,0,0,26812,0, +26825,0,0,0,0,0,0,0,26826,0,0,26827,26829,26834,0,0,0,0,26835,0,0,26849,0,26851, +0,0,0,0,0,0,0,0,0,26852,0,26853,26857,0,26858,0,26859,0,0,0,0,0,0,0,26876,0, +26878,26882,26883,0,0,0,0,26890,26894,0,0,0,0,26895,26896,0,0,0,0,0,26900,0,0,0, +0,0,0,0,26911,26913,26914,26915,26916,26919,0,0,0,26921,26922,0,0,26925,0,0,0, +26928,0,0,26929,26930,0,0,0,26931,0,26932,0,0,0,0,0,26933,0,0,0,0,0,0,26937,0,0, +26943,0,0,26944,0,0,0,26946,0,0,0,0,0,0,0,26956,0,26958,0,0,26963,0,0,0,0,0,0,0, +26965,0,26969,26970,26972,0,0,0,0,0,26973,0,26974,0,26978,0,26980,0,0,0,0,0,0, +26982,0,26986,26987,0,26990,0,0,0,0,27003,27006,0,0,27007,27010,27012,27013,0,0, +0,0,0,0,0,0,27014,27015,27018,0,27019,0,0,0,0,0,27025,0,0,0,27026,0,0,0,0,27029, +27030,27031,27034,0,0,27036,27037,0,0,0,27038,27042,0,0,0,27044,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,27045,0,0,0,0,0,0,0,27046,0,0,0,0,0,0,0,27047,27049,0,27050,0,0,0, +27051,27052,0,27055,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,27056,27058,27059,0, +27061,0,27064,0,0,0,0,0,27069,0,0,27070,0,0,0,0,0,0,0,27072,0,0,0,0,0,0,0,0, +27076,0,0,0,0,0,27078,0,27079,0,0,0,27081,0,0,0,0,0,0,27082,0,27083,27086,0,0,0, +0,27087,0,0,0,0,0,27088,27090,0,27094,0,0,27095,0,27099,27102,0,0,0,27103,0,0,0, +0,27105,0,0,0,27106,0,0,0,0,0,0,27107,0,0,0,0,27108,27117,0,0,0,0,27118,0,0, +27124,0,27126,0,0,27130,27131,0,0,0,0,0,0,27147,0,0,0,0,27148,27149,0,0,0,0, +27150,27151,0,27152,0,27159,0,0,0,27164,0,0,0,0,0,0,0,27175,0,27189,0,0,27191,0, +27193,0,27195,0,27198,0,0,0,0,0,27200,0,0,0,0,27202,0,0,0,0,27203,0,0,27204,0,0, +27206,0,27207,0,0,0,0,27209,0,0,0,27213,0,0,27216,27219,27220,27222,27223,0, +27224,0,27225,27226,0,0,27233,0,0,0,0,27235,0,27237,0,27238,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,27239,0,27242,27243,0,27250,0,0,0,27251,0,27253,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,27254,27255,27258,0,0,0,27259,0,0,0,0,0,0,27267,0,27276,27278, +0,0,0,0,0,0,0,0,0,27296,27297,27301,0,0,0,0,0,0,27302,0,0,0,0,0,0,27312,27313,0, +0,0,0,0,27318,0,27320,0,27329,0,27330,27331,0,27332,0,0,0,0,27340,0,0,0,27348,0, +0,0,0,0,0,27350,0,27351,0,0,0,0,27355,0,0,27358,27359,27361,0,0,0,27365,0,27367, +0,27376,27378,0,0,27379,0,0,0,0,0,0,27396,0,27397,27404,0,0,0,0,0,27408,0,0,0,0, +27453,0,0,0,27456,0,0,0,27458,0,0,0,0,0,0,0,27459,0,0,0,27460,0,0,27461,0,27465, +27467,0,0,27469,0,27470,0,27471,0,27477,27482,0,0,0,0,0,0,27484,0,0,0,0,0,0, +27485,0,0,0,0,0,27493,0,27494,27502,0,0,0,0,0,0,0,0,0,0,0,0,27511,27532,0,0,0, +27533,27545,0,0,0,27546,0,0,0,0,0,0,0,0,0,0,27547,0,0,27549,27550,0,27551,0,0,0, +0,0,0,0,27555,0,0,27571,0,27573,27574,27575,27577,0,27578,0,0,27579,27585,0,0,0, +0,0,27586,0,0,27588,27589,0,0,0,0,27596,0,0,27600,0,0,0,0,0,0,0,0,0,0,0,27608,0, +0,0,0,0,0,0,0,0,0,0,27610,0,0,0,27618,0,0,27620,0,0,0,27631,0,0,27632,27634,0, +27636,27638,0,0,0,27643,0,27644,27649,0,0,0,0,0,0,0,0,0,0,0,0,0,27651,27660,0, +27661,0,0,0,0,0,0,0,27662,0,0,27664,0,27665,0,0,0,27669,0,27671,0,0,0,27673, +27674,0,0,0,27682,0,0,0,27711,0,27712,27713,27719,27720,0,0,27728,0,27729,0,0,0, +0,0,0,0,0,0,27731,0,0,27732,0,27733,0,27738,0,0,0,27742,0,0,0,27743,27744,0,0,0, +0,0,0,27745,27746,0,0,0,27747,27748,27751,27752,0,0,0,27768,27770,0,0,0,27774, +27775,0,27776,27777,0,0,27781,0,27784,0,27786,0,0,27791,0,27792,27793,27804,0, +27812,27813,0,0,0,0,0,0,0,0,27814,0,27825,0,27827,0,0,0,0,27828,27861,27862,0,0, +0,27864,0,0,0,27865,27884,0,27889,0,0,0,0,0,27890,0,27891,0,0,0,27892,0,0,0,0,0, +27897,27898,0,0,27899,0,0,0,27901,27905,0,0,27920,0,0,27921,0,27922,0,0,0,27931, +27934,0,0,0,0,0,0,0,0,0,0,27941,0,27942,0,27945,0,27947,27954,0,0,0,0,27960, +27963,0,0,0,0,0,0,0,0,27964,27965,0,0,0,27967,0,27969,27975,0,27976,27977,0, +27981,0,27983,28051,28052,0,0,0,0,0,28056,0,0,0,0,0,0,28058,28059,0,0,28061,0,0, +0,0,0,0,0,28063,0,0,0,0,0,0,28066,0,0,0,0,0,0,28069,28070,28072,0,28073,0,0, +28074,0,0,0,0,28075,0,0,0,0,0,0,0,28078,0,0,0,0,28085,0,0,0,0,28086,0,0,0,0,0,0, +28088,0,0,0,0,0,0,0,0,28090,0,28097,28114,28115,0,0,0,0,0,0,0,28116,0,0,0,0,0, +28118,0,28129,0,28131,0,0,28135,0,0,0,28140,28141,0,0,0,28146,0,0,0,0,28152,0,0, +0,0,28155,28157,28161,0,0,0,0,28166,0,28167,0,0,0,0,0,0,0,0,0,0,0,28172,0,0,0,0, +0,0,28173,0,0,28175,0,0,0,0,0,0,0,0,0,28178,28188,0,28190,0,0,0,0,0,28191,0, +28193,28206,0,0,28207,28209,0,28211,0,28213,0,0,0,28215,28216,28217,0,28222,0, +28223,28225,0,0,0,28226,0,28227,28229,28232,0,0,0,0,0,0,0,0,0,28235,0,28241,0,0, +28242,0,0,0,0,28243,0,0,0,28245,0,0,0,28248,28250,0,28251,28252,0,0,0,0,0,0, +28253,0,0,28254,28255,0,0,28256,0,0,28258,0,0,0,0,0,28259,0,0,28260,0,0,28261,0, +0,0,0,28262,28263,0,0,28264,0,0,0,28266,0,28268,28269,0,28270,28272,28274,0, +28277,28278,0,0,0,28279,0,28280,28281,28283,0,28292,0,28294,0,28297,0,0,0,0, +28299,0,0,0,0,0,28300,0,0,0,0,0,0,0,28301,0,0,0,0,0,0,0,0,0,0,0,0,0,28302,28303, +0,0,0,0,28304,0,0,28305,0,28312,0,28313,28314,0,0,0,0,0,0,28315,0,0,0,28320, +28321,0,0,28328,0,0,0,28329,28338,0,28339,0,0,28344,0,0,0,0,0,0,0,0,28347,0,0,0, +0,0,0,0,0,28348,0,0,0,0,0,28411,0,28412,28413,0,28416,0,0,0,28420,0,0,0,0,0, +28421,0,0,0,0,28423,0,0,0,28424,0,0,28428,0,0,0,0,0,28429,0,0,0,28431,28434,0, +28458,0,0,0,0,0,0,0,0,0,0,0,28464,0,0,0,0,28465,0,28467,0,0,0,0,0,0,28471,0,0,0, +0,28474,0,28480,0,28481,0,0,28485,0,0,0,0,28486,28488,0,0,28489,0,0,0,0,28492,0, +0,0,28495,0,28497,0,28499,0,0,0,0,28500,0,0,28502,28503,0,0,0,28508,0,0,0,28510, +0,0,28512,28513,28514,28521,0,28526,0,28527,28528,0,0,0,0,28529,0,0,28532,0,0, +28537,28538,0,0,0,28539,0,28548,0,28553,28554,0,0,0,0,0,0,0,0,0,0,0,0,28560, +28563,0,0,28564,0,0,0,0,28565,0,0,0,0,0,0,0,28566,28568,0,0,0,0,0,0,28569,0,0,0, +28570,0,28572,28573,0,0,0,0,28575,0,0,0,0,28576,28581,28588,0,0,28589,0,0,0, +28590,28595,0,28598,0,0,28601,0,0,28605,0,0,0,0,28614,28615,28619,0,0,0,0,0,0, +28620,0,28626,0,0,28628,0,28631,0,28632,0,0,0,0,0,0,28635,0,0,0,28637,28638,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,28639,0,28643,0,0,28652,0,0,0,28662,0, +28670,28671,0,0,0,0,0,0,0,0,0,28672,28673,28675,28676,0,0,0,0,0,0,0,28691,0,0,0, +28695,0,0,0,28696,0,28697,28698,0,28705,0,28707,28708,28710,0,0,0,0,0,0,0,28711, +28728,0,0,0,28736,0,0,0,28737,0,0,0,0,0,0,0,0,0,28738,0,28739,0,28741,0,0,28742, +0,0,0,0,0,0,0,0,0,0,0,28745,0,0,0,0,0,0,28749,28750,28752,28754,28756,0,28757,0, +0,0,0,28759,28760,0,0,0,0,0,0,28762,0,0,0,28764,0,0,0,0,0,0,28766,0,28767,28768, +0,0,0,0,28769,28770,0,0,0,0,0,0,0,0,0,0,0,0,0,28771,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,28772,0,28773,0,28782,0,0,0,0,0,0,28784,0,28785,0,28786,0,0,0,28787,0,0,0, +28797,0,0,0,0,0,0,28799,0,0,28801,0,0,0,0,28802,0,28805,0,0,28806,0,0,28807,0,0, +0,0,0,0,0,28808,0,0,0,0,0,28810,28812,0,0,28816,28819,0,0,28821,0,28826,0,0,0, +28842,28852,0,0,28853,0,28854,28855,0,0,0,28857,0,0,0,28858,0,28867,28868,28869, +0,0,0,28874,28880,28882,28890,28892,0,0,0,0,0,0,0,28895,0,0,0,28898,28899,0,0,0, +28900,0,0,28904,0,28906,0,0,0,0,28907,0,0,0,0,0,0,28908,0,0,0,28910,0,28914,0,0, +0,0,0,0,0,28915,28916,28919,0,0,28920,0,28921,0,0,0,0,0,0,0,0,28924,0,0,0,0, +28926,28929,0,0,0,28930,0,28936,0,28939,0,0,0,0,28942,0,0,0,0,0,0,28956,0,0,0, +28966,0,0,0,0,28967,0,0,0,0,0,0,0,0,0,28968,0,28971,0,28975,28976,0,28982,28983, +0,0,28984,28989,28996,28997,28998,0,0,0,0,0,0,28999,0,0,0,0,0,29000,0,29001,0,0, +0,29009,0,0,29011,0,0,29021,0,0,0,0,29024,0,29025,0,0,0,0,0,29026,0,0,0,29036,0, +0,0,29037,0,0,0,0,29038,0,29045,0,29047,0,0,0,0,0,0,0,0,0,29051,0,0,0,29054, +29056,29062,0,29070,29082,0,0,0,29083,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29084,0,0, +0,0,29085,29088,0,0,0,0,0,0,0,29090,29097,0,0,0,29103,0,0,0,0,0,0,0,0,29105,0,0, +0,0,0,29107,0,29109,0,0,0,29115,0,0,29120,0,0,29138,29140,0,0,0,0,0,0,0,0,0, +29152,0,29160,29174,0,29176,0,0,29180,0,29181,0,0,0,0,0,0,0,0,29228,0,0,29229,0, +0,29230,0,0,0,0,0,0,0,0,0,0,29234,0,0,0,29241,0,29245,0,29248,0,29250,29256, +29280,0,29282,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29285,0,0,29286,29291,29292,0,0,0,0, +29294,0,29295,0,0,0,0,0,29296,29297,29298,29300,0,29302,0,0,29304,29307,0,29312, +0,0,0,29322,0,0,29323,0,0,29324,29326,29328,0,29335,0,0,0,0,0,0,0,29338,29339,0, +0,0,0,0,29341,29343,0,0,0,0,29344,0,0,0,0,0,29345,0,0,0,0,29346,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,29347,29348,29349,0,0,29354,0,0,29355,0,0,0,0,0,0,0,0,29357,0,0, +0,0,29364,0,29365,0,0,0,0,0,0,0,29366,0,0,29368,0,0,0,0,0,0,0,0,29378,0,29381,0, +0,0,0,0,0,0,0,29386,0,0,0,0,0,0,29389,0,0,0,29390,0,0,29391,29397,0,29398,29412, +29414,29418,29419,0,0,0,0,0,0,0,29420,0,0,0,0,0,0,0,29423,0,0,0,29435,0,0,0, +29437,0,0,29439,0,29441,0,0,0,0,29443,0,29446,29450,29452,0,0,0,0,0,29456,0,0,0, +0,0,29461,0,0,0,29464,0,0,0,0,0,0,0,0,29468,0,29473,0,0,0,29486,0,0,0,29490,0,0, +0,29491,29492,0,0,29497,0,0,0,29498,0,29499,0,29502,29505,0,29509,0,0,0,29510,0, +0,0,29512,0,0,0,29516,0,0,0,0,0,0,0,0,29518,0,29519,0,0,0,0,0,29520,29521,29529, +0,0,0,0,0,0,0,0,29530,0,0,29531,29538,0,29540,0,0,0,29542,0,29543,29544,29547,0, +0,29548,0,0,0,29549,0,0,0,29550,0,0,29552,0,0,0,0,29558,29561,0,29562,29564,0,0, +29565,0,0,29566,0,0,0,0,0,0,0,0,0,0,29578,29584,29586,29591,0,0,0,0,29593,29594, +0,0,29597,0,0,29613,0,29614,0,29615,0,0,0,0,29616,29617,0,0,29625,0,0,0,29632,0, +0,0,0,0,0,0,29633,0,0,0,0,0,29634,29635,29637,0,29638,0,29641,29643,0,0,0,0,0,0, +29644,0,29645,0,29649,0,0,0,29650,0,29653,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29656, +29659,0,0,29660,0,0,0,29661,0,0,0,0,0,29664,0,0,0,29671,29673,0,0,0,0,0,0,0, +29675,0,29677,29679,0,0,29684,0,0,0,0,0,29685,0,0,0,29687,0,0,0,29688,0,29689, +29690,29700,0,29701,0,0,0,29702,0,29706,0,0,0,0,0,0,0,29720,0,29721,0,29727,0, +29733,29734,0,29750,29761,0,29763,0,0,0,0,0,29764,0,0,29765,0,0,0,29771,0,0,0,0, +0,0,0,0,0,0,0,0,29772,0,0,0,29773,29774,29775,0,0,0,0,0,0,0,0,0,0,0,29822,0,0,0, +29824,0,29825,0,0,0,0,0,29827,0,0,0,0,0,0,0,0,29829,0,29832,29834,0,0,29835,0,0, +29837,29838,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,29843,0,0,0,0,29844,29845,0,0,0, +0,0,0,0,0,0,29849,0,0,29869,29872,29890,29905,0,0,0,0,0,29907,29921,0,29922,0,0, +29923,29926,29944,29946,0,0,0,0,0,0,0,29947,29948,0,0,0,29951,0,0,0,0,0,29953,0, +0,29956,0,29957,0,0,29962,0,0,0,0,29971,0,0,0,29972,0,0,0,0,0,29978,0,29979, +29992,30007,30008,30010,0,0,0,30013,0,0,0,0,30014,30016,0,0,0,0,0,0,0,0,0,0,0, +30017,0,0,0,0,0,30023,30031,0,0,30033,0,0,0,0,0,0,0,0,0,0,30034,0,30038,0,30039, +0,30040,0,0,0,0,0,0,30067,30068,0,0,0,30069,0,30072,0,0,0,30073,0,0,0,0,30075,0, +0,0,0,0,0,30079,0,0,30080,0,0,0,0,0,30082,0,0,0,0,0,0,0,0,0,0,0,30084,30090,0,0, +30091,0,0,0,0,30098,30118,0,30119,0,30121,30130,0,0,0,0,0,0,0,0,0,0,0,0,0,30131, +30132,30133,0,0,0,0,0,0,30135,0,0,0,0,0,0,0,0,0,0,0,30136,0,0,30137,30138,0,0,0, +30139,30146,0,0,0,0,0,30147,0,0,30148,30151,0,0,0,30168,0,30172,30173,0,0,0,0,0, +0,0,0,30180,30181,0,30192,0,0,0,0,0,0,0,30194,30196,0,0,30199,0,0,30202,0,0,0,0, +30203,0,0,0,0,0,0,0,0,0,0,30213,0,0,0,30216,0,0,30217,0,0,0,30218,0,0,0,0,30219, +0,30220,0,30222,30227,0,0,0,0,0,30231,0,0,30233,30235,0,0,0,0,30238,0,30240, +30243,30245,0,30250,30252,0,0,0,30269,0,0,30271,30272,0,0,0,30278,30280,0,0, +30282,0,30284,0,30294,0,0,0,0,30295,30296,0,0,0,0,0,30298,30299,30302,30304, +30306,0,0,0,0,0,0,30316,30317,0,0,0,30318,0,0,0,30319,0,30320,30322,30326,0,0,0, +0,0,30327,0,30332,30348,30349,0,0,30356,0,0,0,0,0,0,0,0,30357,0,30358,0,30359, +30360,0,0,30365,30366,30378,0,0,0,0,30379,0,0,30381,0,30385,0,30388,30397,0,0,0, +30401,0,0,0,0,30403,0,0,0,0,0,30404,0,0,30405,0,30406,30408,0,30409,0,30410,0,0, +0,30417,0,0,30418,30419,0,30420,0,30424,0,0,0,30427,30430,30432,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,30433,0,0,0,0,0,0,0,30436,0,30437,30438,0,30441,30442,0,0, +0,30445,0,0,0,0,30452,30456,30457,0,0,0,30458,0,30464,0,0,0,0,0,0,30467,0,30469, +0,0,0,0,0,30477,0,0,30484,0,0,0,0,0,30485,0,0,0,0,0,30486,30487,30497,30498,0,0, +0,0,0,0,0,0,0,0,30505,0,30508,0,0,0,30509,30510,0,30514,30516,0,0,0,0,0,0,0,0,0, +0,0,30523,0,30524,0,30525,0,0,0,0,30537,0,0,30538,0,0,0,0,0,30553,0,0,30555, +30556,30558,30559,30560,0,0,30561,0,30562,0,0,0,0,0,0,0,0,30563,30570,30571,0, +30586,30587,0,0,30590,0,0,30594,0,0,0,0,30611,30612,30623,30634,0,0,30636,30640, +30655,30656,0,30657,0,0,30658,30669,0,30670,0,30676,30678,0,0,0,0,0,0,0,30679,0, +0,0,0,0,0,0,0,0,0,0,30695,0,0,30698,0,0,0,0,30700,0,0,0,0,30701,0,30702,30703,0, +0,0,0,30707,0,0,0,30709,0,0,30710,30719,30729,0,0,0,0,0,0,0,0,0,30731,0,0,30733, +0,0,0,30734,0,0,0,0,0,30736,30737,0,0,0,30740,0,0,0,30743,0,30746,0,30747,30748, +0,0,30751,30752,30753,0,0,0,30754,0,0,30760,0,0,0,0,0,0,0,30763,0,30764,0,0, +30766,0,30769,30770,30771,30774,30777,0,0,30779,30780,30781,0,0,0,0,30790,0,0,0, +30792,0,0,0,0,30810,0,0,0,0,0,0,0,30812,30819,0,0,30823,30824,0,30825,0,30827,0, +0,0,0,0,0,30828,0,0,30830,0,0,0,30834,0,30835,0,30837,30838,0,30845,0,0,0,0,0, +30846,30847,0,0,30849,0,30851,0,0,0,0,0,30852,30858,0,0,30859,0,30865,0,0,30866, +0,0,30868,0,0,30869,0,0,0,30881,30883,0,0,0,0,0,30889,0,30891,0,0,0,0,30894,0, +30895,0,30897,0,30898,0,0,0,30904,30906,0,30909,0,0,0,0,0,0,30910,0,0,0,30915, +30933,30942,0,0,0,0,30943,0,0,30945,0,0,0,0,0,0,30946,0,0,30947,0,0,30955,30956, +0,0,30960,0,0,30961,30962,30966,0,0,30969,30974,0,0,0,30976,0,0,30977,0,30978, +30982,0,0,0,0,0,0,0,30994,30995,30998,0,31000,0,0,31001,0,0,31003,31005,0,0, +31006,31011,0,0,31014,0,31016,0,0,0,0,31018,0,0,31020,31023,31024,31025,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,31027,31028,31029,0,0,0,0,0,0,31032,0,0,0,0,0,0,0,0,0,0,0, +31036,31037,31038,0,0,0,31041,31043,31045,0,31047,0,0,0,31048,0,31049,0,0,0, +31053,31054,31055,0,0,31063,0,0,0,0,0,31066,0,31068,31071,0,0,0,31072,31073,0,0, +0,0,31075,0,0,31076,0,0,0,31077,31079,0,31080,0,0,0,0,0,0,0,0,0,0,31087,0,31142, +0,31144,0,0,31145,31146,31147,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31149,0,31151,31152,0, +0,0,0,0,0,0,31162,31171,31174,31175,0,0,0,31176,0,0,0,0,0,0,0,31179,0,0,0,31186, +0,0,0,31192,31195,0,0,31196,0,0,0,0,0,0,0,0,31198,0,0,0,0,0,31199,0,0,0,31205,0, +0,0,0,31211,31215,0,0,0,0,31231,0,31232,0,0,0,0,0,0,0,0,0,0,31233,31236,31253,0, +31254,0,0,0,0,0,0,31255,0,0,31257,0,0,0,0,0,0,0,0,0,31258,31259,0,0,31260,0, +31261,0,0,0,0,0,31262,31263,0,0,31264,0,31266,0,31267,0,0,0,0,0,31281,0,31282,0, +31284,0,0,31285,31287,31288,0,0,31290,0,0,0,31292,31295,0,31299,0,31300,0,0,0,0, +0,31302,0,0,0,0,31303,0,0,0,0,0,0,31304,0,0,0,0,0,31305,31308,31309,31315,0, +31317,0,0,0,0,0,31323,0,31324,0,0,0,0,0,31325,31327,0,0,31331,0,0,0,0,0,31333,0, +0,0,0,0,31336,0,0,31337,0,0,0,0,0,0,31338,0,0,0,0,0,0,0,0,0,0,0,0,31339,0,0,0,0, +0,0,0,31342,0,0,0,0,31345,0,0,0,0,0,0,0,0,31347,0,0,0,0,0,0,31348,0,0,31350, +31351,0,31352,0,0,31354,0,0,0,0,31355,0,0,31356,0,0,0,0,0,0,0,0,0,0,31363,0, +31372,0,0,31373,0,0,0,0,0,0,0,0,0,31376,0,31388,0,31389,0,31392,0,31401,0,31405, +31407,31408,0,31409,0,0,0,0,0,0,31413,31415,0,0,0,31416,31418,0,0,0,0,0,0,31422, +31423,0,0,31424,0,31425,31432,0,0,0,0,0,0,0,0,0,31433,0,0,0,0,0,0,0,0,31434,0,0, +0,0,0,0,31435,0,0,0,0,31438,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,31442,0,31444,0, +31448,0,0,31451,0,0,0,0,31452,0,31461,31465,0,0,31466,0,0,31467,0,0,31468,0,0,0, +31469,31473,0,31476,0,0,0,0,31489,31490,0,0,0,0,0,0,0,31492,31493,31494,0,0,0,0, +31501,31504,31505,0,0,0,0,0,0,0,0,0,31509,0,0,0,0,31510,0,0,31511,0,0,31513,0,0, +0,0,0,0,0,0,0,31514,0,31522,31536,31539,31540,0,31541,0,0,0,0,0,0,31546,31553, +31559,0,0,0,31560,31561,31562,0,0,31564,31567,0,31569,0,0,0,31570,0,0,0,0,31571, +0,0,0,0,0,0,31572,31574,31580,31581,0,0,31582,31584,31585,31586,31595,0,31596,0, +0,0,0,31597,0,31599,0,31600,31601,0,0,31603,31604,0,0,31608,31610,0,0,0,31611,0, +31615,0,0,0,0,31616,0,0,0,0,0,0,31617,0,0,0,0,0,31618,0,0,0,0,0,0,31621,0,0,0,0, +0,0,0,0,0,31622,31625,0,0,0,0,31627,0,31641,0,0,31642,0,0,31643,0,0,0,0,0,0,0,0, +0,31644,0,31646,0,0,0,0,31648,0,0,0,31652,0,0,0,31657,0,0,31676,0,0,0,0,0,0,0, +31689,31691,31692,0,31694,0,0,0,31696,0,31702,0,31703,0}; + +const BROTLI_MODEL("small") +DictWord kStaticDictionaryWords[BROTLI_ENC_STATIC_DICT_LUT_NUM_ITEMS] = { +{0,0,0},{8,0,1002},{136,0,1015},{4,0,683},{4,10,325},{138,10,125},{7,11,572},{9, +11,592},{11,11,680},{11,11,842},{11,11,924},{12,11,356},{12,11,550},{13,11,317}, +{13,11,370},{13,11,469},{13,11,471},{14,11,397},{18,11,69},{146,11,145},{134,0, +1265},{136,11,534},{134,0,1431},{11,0,138},{140,0,40},{4,0,155},{4,10,718},{7,0, +1689},{135,10,1216},{4,0,245},{5,0,151},{5,0,741},{6,0,1147},{7,0,498},{7,0,870} +,{7,0,1542},{12,0,213},{14,0,36},{14,0,391},{17,0,111},{18,0,6},{18,0,46},{18,0, +151},{19,0,36},{20,0,32},{20,0,56},{20,0,69},{20,0,102},{21,0,4},{22,0,8},{22,0, +10},{22,0,14},{150,0,31},{4,0,624},{135,0,1752},{5,10,124},{5,10,144},{6,10,548} +,{7,10,15},{7,10,153},{137,10,629},{6,0,503},{7,10,1531},{8,10,416},{9,0,586},{9 +,10,275},{10,10,100},{11,10,658},{11,10,979},{12,10,86},{13,0,468},{14,0,66},{14 +,10,207},{15,10,20},{15,10,25},{144,0,58},{5,0,603},{5,10,915},{6,10,1783},{7,0, +1212},{7,10,211},{7,10,1353},{9,0,565},{9,10,83},{10,10,376},{10,10,431},{11,10, +543},{12,10,664},{13,10,280},{13,10,428},{14,0,301},{14,10,128},{17,10,52},{145, +10,81},{4,0,492},{133,0,451},{135,0,835},{141,0,70},{132,0,539},{7,11,748},{139, +11,700},{7,11,1517},{11,11,597},{14,11,76},{14,11,335},{148,11,33},{6,0,113},{ +135,0,436},{4,10,338},{133,10,400},{136,0,718},{133,11,127},{133,11,418},{6,0, +1505},{6,11,198},{7,0,520},{11,10,892},{140,11,83},{4,10,221},{5,10,659},{5,10, +989},{7,10,697},{7,10,1211},{138,10,284},{135,0,1070},{5,11,276},{6,11,55},{135, +11,1369},{134,0,1515},{6,11,1752},{136,11,726},{138,10,507},{4,10,188},{7,10,805 +},{143,0,78},{5,10,884},{139,10,991},{133,11,764},{134,10,1653},{6,11,309},{7,11 +,331},{138,11,550},{135,11,1861},{132,11,348},{135,11,986},{135,11,1573},{12,0, +610},{13,0,431},{144,0,59},{9,11,799},{140,10,166},{134,0,1530},{132,0,750},{132 +,0,307},{133,0,964},{6,11,194},{7,11,133},{10,11,493},{10,11,570},{139,11,664},{ +5,11,24},{5,11,569},{6,11,3},{6,11,119},{6,11,143},{6,11,440},{7,11,295},{7,11, +599},{7,11,1686},{7,11,1854},{8,11,424},{9,11,43},{9,11,584},{9,11,760},{10,11, +148},{10,11,328},{11,11,159},{11,11,253},{11,11,506},{12,11,487},{12,11,531},{ +144,11,33},{136,10,760},{5,11,14},{5,11,892},{6,11,283},{7,11,234},{136,11,537}, +{135,11,1251},{4,11,126},{8,11,635},{147,11,34},{4,11,316},{135,11,1561},{6,0, +999},{6,0,1310},{137,11,861},{4,11,64},{5,11,352},{5,11,720},{6,11,368},{139,11, +359},{4,0,75},{5,0,180},{6,0,500},{7,0,58},{7,0,710},{8,10,770},{138,0,645},{133 +,0,649},{6,0,276},{7,0,282},{7,0,879},{7,0,924},{8,0,459},{9,0,599},{9,0,754},{ +11,0,574},{12,0,128},{12,0,494},{13,0,52},{13,0,301},{15,0,30},{143,0,132},{132, +0,200},{4,10,89},{5,10,489},{6,10,315},{7,10,553},{7,10,1745},{138,10,243},{135, +11,1050},{6,10,1658},{7,0,1621},{9,10,3},{10,10,154},{11,10,641},{13,10,85},{13, +10,201},{141,10,346},{6,11,175},{137,11,289},{5,11,432},{133,11,913},{6,0,225},{ +137,0,211},{7,0,718},{8,0,687},{139,0,374},{4,10,166},{133,10,505},{6,10,1670},{ +137,0,110},{8,0,58},{9,0,724},{11,0,809},{13,0,113},{145,0,72},{6,0,345},{7,0, +1247},{144,11,82},{5,11,931},{134,11,1698},{8,0,767},{8,0,803},{9,0,301},{137,0, +903},{139,0,203},{134,0,1154},{7,0,1949},{136,0,674},{134,0,259},{135,0,1275},{5 +,11,774},{6,11,1637},{6,11,1686},{134,11,1751},{134,0,1231},{7,10,445},{8,10,307 +},{8,10,704},{10,10,41},{10,10,439},{11,10,237},{11,10,622},{140,10,201},{136,0, +254},{6,11,260},{135,11,1484},{139,0,277},{135,10,1977},{4,10,189},{5,10,713},{6 +,11,573},{136,10,57},{138,10,371},{132,10,552},{134,11,344},{133,0,248},{6,11, +240},{9,0,800},{10,0,693},{11,0,482},{11,0,734},{139,0,789},{4,0,116},{4,11,292} +,{4,11,736},{5,0,95},{5,0,445},{5,11,871},{6,11,171},{6,11,1689},{7,0,1688},{7, +11,1324},{7,11,1944},{8,0,29},{9,0,272},{9,11,415},{9,11,580},{11,0,509},{11,0, +915},{14,11,230},{146,11,68},{7,0,490},{13,0,100},{143,0,75},{135,0,1641},{133,0 +,543},{7,11,209},{8,11,661},{10,11,42},{11,11,58},{12,11,58},{12,11,118},{141,11 +,32},{5,0,181},{6,11,63},{7,11,920},{136,0,41},{133,0,657},{133,11,793},{138,0, +709},{7,0,25},{8,0,202},{138,0,536},{5,11,665},{135,10,1788},{145,10,49},{9,0, +423},{140,0,89},{5,11,67},{6,11,62},{6,11,374},{135,11,1391},{8,0,113},{9,0,877} +,{9,11,790},{10,0,554},{11,0,83},{12,0,136},{12,11,47},{147,0,109},{138,10,661}, +{4,0,963},{7,10,1945},{10,0,927},{142,0,442},{133,0,976},{132,0,206},{4,11,391}, +{135,11,1169},{134,0,2002},{6,0,696},{134,0,1008},{134,0,1170},{132,11,271},{7,0 +,13},{8,0,226},{10,0,537},{11,0,570},{11,0,605},{11,0,799},{11,0,804},{12,0,85}, +{12,0,516},{12,0,623},{12,11,314},{13,0,112},{13,0,361},{14,0,77},{14,0,78},{17, +0,28},{147,0,110},{132,0,769},{134,0,1544},{4,0,551},{137,0,678},{5,10,84},{134, +10,163},{9,0,57},{9,0,459},{10,0,425},{11,0,119},{12,0,184},{12,0,371},{13,0,358 +},{145,0,51},{4,11,253},{5,0,188},{5,0,814},{5,10,410},{5,11,544},{7,11,300},{8, +0,10},{9,0,421},{9,0,729},{9,11,340},{10,0,609},{139,0,689},{134,0,624},{138,11, +321},{135,0,1941},{5,10,322},{8,10,186},{9,10,262},{10,10,187},{14,10,208},{146, +0,130},{5,11,53},{5,11,541},{6,11,94},{6,11,499},{7,11,230},{139,11,321},{133,10 +,227},{4,0,378},{4,11,920},{5,11,25},{5,11,790},{6,11,457},{135,11,853},{137,0, +269},{132,0,528},{134,0,1146},{7,10,1395},{8,10,486},{9,10,236},{9,10,878},{10, +10,218},{11,10,95},{19,10,17},{147,10,31},{7,10,2043},{8,10,672},{141,10,448},{ +134,0,1105},{134,0,1616},{134,11,1765},{140,11,163},{5,10,412},{133,11,822},{132 +,11,634},{6,0,656},{134,11,1730},{134,0,1940},{5,0,104},{6,0,173},{135,0,1631},{ +136,10,562},{6,11,36},{7,11,658},{8,11,454},{147,11,86},{5,0,457},{134,10,1771}, +{7,0,810},{8,0,138},{8,0,342},{9,0,84},{10,0,193},{11,0,883},{140,0,359},{7,10, +1190},{137,0,620},{137,10,132},{7,11,975},{137,11,789},{6,0,95},{6,0,1934},{136, +0,967},{141,11,335},{6,0,406},{10,0,409},{10,0,447},{11,0,44},{140,0,100},{4,10, +317},{135,10,1279},{132,0,477},{134,0,1268},{5,10,63},{5,10,509},{6,0,1941},{136 +,0,944},{132,0,629},{132,11,104},{4,0,246},{133,0,375},{4,10,288},{134,0,1636},{ +135,11,1614},{8,10,89},{8,10,620},{9,0,49},{10,0,774},{11,10,628},{12,10,322},{ +143,10,124},{4,0,282},{7,0,1034},{11,0,398},{11,0,634},{12,0,1},{12,0,79},{12,0, +544},{14,0,237},{17,0,10},{146,0,20},{132,0,824},{7,11,45},{9,11,542},{9,11,566} +,{138,11,728},{5,0,118},{5,0,499},{6,0,476},{6,0,665},{6,0,1176},{6,0,1196},{7,0 +,600},{7,0,888},{135,0,1096},{7,0,296},{7,0,596},{8,0,560},{8,0,586},{9,0,612},{ +11,0,304},{12,0,46},{13,0,89},{14,0,112},{145,0,122},{5,0,894},{6,0,1772},{9,0, +1009},{138,10,120},{5,11,533},{7,11,755},{138,11,780},{151,10,1},{6,0,1474},{7, +11,87},{142,11,288},{139,0,366},{137,10,461},{7,11,988},{7,11,1939},{9,11,64},{9 +,11,502},{12,11,7},{12,11,34},{13,11,12},{13,11,234},{147,11,77},{7,0,1599},{7,0 +,1723},{8,0,79},{8,0,106},{8,0,190},{8,0,302},{8,0,383},{8,0,713},{9,0,119},{9,0 +,233},{9,0,419},{9,0,471},{10,0,181},{10,0,406},{11,0,57},{11,0,85},{11,0,120},{ +11,0,177},{11,0,296},{11,0,382},{11,0,454},{11,0,758},{11,0,999},{12,0,27},{12,0 +,98},{12,0,131},{12,0,245},{12,0,312},{12,0,446},{12,0,454},{13,0,25},{13,0,98}, +{13,0,426},{13,0,508},{14,0,70},{14,0,163},{14,0,272},{14,0,277},{14,0,370},{15, +0,95},{15,0,138},{15,0,167},{17,0,38},{148,0,96},{135,10,1346},{10,0,200},{19,0, +2},{151,0,22},{135,11,141},{134,10,85},{134,0,1759},{138,0,372},{145,0,16},{4,11 +,619},{136,0,943},{139,11,88},{5,11,246},{8,11,189},{9,11,355},{9,11,512},{10,11 +,124},{10,11,453},{11,11,143},{11,11,416},{11,11,859},{141,11,341},{5,0,258},{ +134,0,719},{6,0,1798},{6,0,1839},{8,0,900},{10,0,874},{10,0,886},{12,0,698},{12, +0,732},{12,0,770},{16,0,106},{18,0,163},{18,0,170},{18,0,171},{152,0,20},{9,0, +707},{9,11,707},{11,0,326},{11,0,339},{11,11,326},{11,11,339},{12,0,423},{12,0, +502},{12,11,423},{12,11,502},{20,0,62},{148,11,62},{5,0,30},{7,0,495},{8,0,134}, +{9,0,788},{140,0,438},{133,11,678},{5,10,279},{6,10,235},{7,10,468},{8,10,446},{ +9,10,637},{10,10,717},{11,10,738},{140,10,514},{5,11,35},{6,11,287},{7,11,862},{ +7,11,1886},{138,11,179},{4,11,517},{7,0,1948},{135,0,2004},{5,10,17},{6,10,371}, +{137,10,528},{4,0,115},{5,0,669},{6,0,407},{8,0,311},{11,0,10},{141,0,5},{137,0, +381},{5,0,50},{6,0,439},{7,0,780},{135,0,1040},{136,11,667},{11,11,403},{146,11, +83},{5,0,1},{6,0,81},{138,0,520},{134,0,738},{5,0,482},{8,0,98},{9,0,172},{10,0, +360},{10,0,700},{10,0,822},{11,0,302},{11,0,778},{12,0,50},{12,0,127},{12,0,396} +,{13,0,62},{13,0,328},{14,0,122},{147,0,72},{9,11,157},{10,11,131},{140,11,72},{ +135,11,714},{135,11,539},{5,0,2},{6,0,512},{7,0,797},{7,0,1494},{8,0,253},{8,0, +589},{9,0,77},{10,0,1},{10,0,129},{10,0,225},{11,0,118},{11,0,226},{11,0,251},{ +11,0,430},{11,0,701},{11,0,974},{11,0,982},{12,0,64},{12,0,260},{12,0,488},{140, +0,690},{5,11,394},{7,11,367},{7,11,487},{7,11,857},{7,11,1713},{8,11,246},{9,11, +537},{10,11,165},{12,11,219},{140,11,561},{136,0,557},{5,10,779},{5,10,807},{6, +10,1655},{134,10,1676},{4,10,196},{5,10,558},{133,10,949},{11,11,827},{12,11,56} +,{14,11,34},{143,11,148},{137,0,347},{133,0,572},{134,0,832},{4,0,12},{7,0,504}, +{7,0,522},{7,0,809},{8,0,797},{141,0,88},{4,10,752},{133,11,449},{7,11,86},{8,11 +,103},{145,11,69},{7,11,2028},{138,11,641},{5,0,528},{6,11,1},{142,11,2},{134,0, +861},{4,10,227},{5,10,159},{5,10,409},{7,10,80},{10,0,294},{10,10,479},{12,10, +418},{14,10,50},{14,10,249},{142,10,295},{7,10,1470},{8,10,66},{8,10,137},{8,10, +761},{9,10,638},{11,10,80},{11,10,212},{11,10,368},{11,10,418},{12,10,8},{13,10, +15},{16,10,61},{17,10,59},{19,10,28},{148,10,84},{7,11,1148},{148,0,109},{6,11, +277},{7,11,1274},{7,11,1386},{7,11,1392},{12,11,129},{146,11,87},{6,11,187},{7, +11,39},{7,11,1203},{8,11,380},{8,11,542},{14,11,117},{149,11,28},{134,0,1187},{5 +,0,266},{9,0,290},{9,0,364},{10,0,293},{11,0,606},{142,0,45},{6,11,297},{7,11, +793},{139,11,938},{4,0,50},{6,0,594},{9,0,121},{10,0,49},{10,0,412},{139,0,834}, +{136,0,748},{7,11,464},{8,11,438},{11,11,105},{11,11,363},{12,11,231},{14,11,386 +},{15,11,102},{148,11,75},{132,0,466},{6,10,38},{7,10,1220},{8,10,185},{8,10,256 +},{9,10,22},{9,10,331},{10,10,738},{11,10,205},{11,10,540},{11,10,746},{13,0,399 +},{13,10,465},{14,0,337},{142,10,194},{9,0,378},{141,0,162},{137,0,519},{4,10, +159},{6,10,115},{7,10,252},{7,10,257},{7,10,1928},{8,10,69},{9,10,384},{10,10,91 +},{10,10,615},{12,10,375},{14,10,235},{18,10,117},{147,10,123},{5,10,911},{5,11, +604},{136,10,278},{132,0,667},{4,10,151},{7,10,1567},{8,0,351},{137,0,322},{134, +0,902},{133,10,990},{5,10,194},{7,10,1662},{9,10,90},{140,0,180},{4,0,869},{134, +0,1996},{134,0,813},{133,10,425},{137,11,761},{132,0,260},{133,10,971},{5,11,20} +,{6,11,298},{7,11,659},{7,11,1366},{137,11,219},{4,0,39},{5,0,36},{7,0,1843},{8, +0,407},{11,0,144},{140,0,523},{4,0,510},{10,0,587},{139,10,752},{7,0,29},{7,0,66 +},{7,0,1980},{10,0,487},{138,0,809},{9,10,662},{13,0,260},{14,0,82},{146,0,63},{ +5,10,72},{6,10,264},{7,10,21},{7,10,46},{7,10,2013},{8,10,215},{8,10,513},{10,10 +,266},{139,10,22},{134,0,570},{4,11,439},{6,0,565},{7,0,1667},{10,10,95},{11,10, +603},{12,11,242},{13,10,443},{14,10,160},{143,10,4},{134,0,1464},{134,10,431},{5 +,10,874},{6,10,1677},{9,0,372},{15,0,2},{15,10,0},{19,0,10},{147,0,18},{132,0, +787},{6,0,380},{7,10,939},{7,10,1172},{7,10,1671},{9,10,540},{10,10,696},{11,10, +265},{11,10,732},{11,10,928},{11,10,937},{12,0,399},{13,10,438},{149,0,19},{137, +0,200},{132,11,233},{132,0,516},{134,11,577},{132,0,844},{11,0,887},{14,0,365},{ +142,0,375},{132,11,482},{8,0,821},{140,0,44},{7,0,1655},{136,0,305},{5,10,682},{ +135,10,1887},{135,11,346},{132,10,696},{4,0,10},{7,0,917},{139,0,786},{5,11,795} +,{6,11,1741},{8,11,417},{137,11,782},{4,0,1016},{134,0,2031},{4,10,726},{5,0,684 +},{133,10,630},{6,0,1021},{134,0,1480},{8,10,802},{136,10,838},{134,0,27},{134,0 +,395},{135,11,622},{7,11,625},{135,11,1750},{4,11,203},{135,11,1936},{6,10,118}, +{7,10,215},{7,10,1521},{140,10,11},{132,0,813},{136,0,511},{7,10,615},{138,10, +251},{135,10,1044},{145,0,56},{133,10,225},{6,0,342},{6,0,496},{8,0,275},{137,0, +206},{4,0,909},{133,0,940},{132,0,891},{7,11,311},{9,11,308},{140,11,255},{4,10, +370},{5,10,756},{135,10,1326},{4,0,687},{134,0,1596},{134,0,1342},{6,10,1662},{7 +,10,48},{8,10,771},{10,10,116},{13,10,104},{14,10,105},{14,10,184},{15,10,168},{ +19,10,92},{148,10,68},{138,10,209},{4,11,400},{5,11,267},{135,11,232},{151,11,12 +},{6,0,41},{141,0,160},{141,11,314},{134,0,1718},{136,0,778},{142,11,261},{134,0 +,1610},{133,0,115},{132,0,294},{4,10,120},{142,0,314},{132,0,983},{5,0,193},{140 +,0,178},{138,10,429},{5,10,820},{135,10,931},{5,11,732},{6,0,994},{6,0,1051},{6, +0,1439},{135,0,174},{4,11,100},{7,11,679},{8,11,313},{138,10,199},{6,10,151},{6, +10,1675},{7,10,383},{151,10,10},{6,0,1796},{8,0,848},{8,0,867},{8,0,907},{10,0, +855},{140,0,703},{140,0,221},{4,0,122},{5,0,796},{5,0,952},{6,0,1660},{6,0,1671} +,{8,0,567},{9,0,687},{9,0,742},{10,0,686},{11,0,682},{11,0,909},{140,0,281},{5, +11,362},{5,11,443},{6,11,318},{7,11,1019},{139,11,623},{5,11,463},{136,11,296},{ +6,10,1624},{11,0,583},{12,10,422},{13,0,262},{142,10,360},{5,0,179},{7,0,1095},{ +135,0,1213},{4,10,43},{4,11,454},{5,10,344},{133,10,357},{4,0,66},{7,0,722},{135 +,0,904},{134,0,773},{5,10,888},{135,0,352},{5,11,48},{5,11,404},{6,11,557},{7,11 +,458},{8,11,597},{10,11,455},{10,11,606},{11,11,49},{11,11,548},{12,11,476},{13, +11,18},{141,11,450},{134,11,418},{132,10,711},{5,11,442},{135,11,1984},{141,0,35 +},{137,0,152},{134,0,1197},{135,11,1093},{137,11,203},{137,10,440},{10,0,592},{ +10,0,753},{12,0,317},{12,0,355},{12,0,465},{12,0,469},{12,0,560},{12,0,578},{141 +,0,243},{133,0,564},{134,0,797},{5,10,958},{133,10,987},{5,11,55},{7,11,376},{ +140,11,161},{133,11,450},{134,0,556},{134,0,819},{11,10,276},{142,10,293},{7,0, +544},{138,0,61},{4,10,65},{5,10,479},{5,10,1004},{7,10,1913},{8,0,719},{8,10,317 +},{9,10,302},{10,10,612},{141,10,22},{4,0,5},{4,10,261},{4,11,213},{5,0,498},{7, +10,510},{7,11,223},{8,0,637},{8,11,80},{137,0,521},{4,10,291},{5,0,927},{7,0,101 +},{7,11,381},{7,11,806},{7,11,820},{8,11,354},{8,11,437},{8,11,787},{9,10,515},{ +9,11,657},{10,11,58},{10,11,339},{10,11,749},{11,11,914},{12,10,152},{12,10,443} +,{12,11,162},{13,10,392},{13,11,75},{14,10,357},{14,11,106},{14,11,198},{14,11, +320},{14,11,413},{146,11,43},{6,0,1153},{7,0,1441},{136,11,747},{4,0,893},{5,0, +780},{133,0,893},{138,11,654},{133,11,692},{133,0,238},{134,11,191},{4,10,130},{ +135,10,843},{5,10,42},{5,10,879},{6,0,1296},{7,10,245},{7,10,324},{7,10,1532},{ +11,10,463},{11,10,472},{13,10,363},{144,10,52},{134,0,1729},{6,0,1999},{136,0, +969},{4,10,134},{133,10,372},{4,0,60},{7,0,941},{7,0,1800},{8,0,314},{9,0,700},{ +139,0,487},{134,0,1144},{6,11,162},{7,11,1960},{136,11,831},{132,11,706},{135,0, +1147},{138,11,426},{138,11,89},{7,0,1853},{138,0,437},{136,0,419},{135,10,1634}, +{133,0,828},{4,10,644},{5,0,806},{7,0,176},{7,0,178},{7,0,1240},{135,0,1976},{ +135,11,1877},{5,11,420},{135,11,1449},{4,0,51},{5,0,39},{6,0,4},{7,0,591},{7,0, +849},{7,0,951},{7,0,1613},{7,0,1760},{7,0,1988},{9,0,434},{10,0,754},{11,0,25},{ +139,0,37},{10,11,57},{138,11,277},{135,10,540},{132,11,204},{135,0,159},{139,11, +231},{133,0,902},{7,0,928},{7,11,366},{9,11,287},{12,11,199},{12,11,556},{140,11 +,577},{6,10,623},{136,10,789},{4,10,908},{5,10,359},{5,10,508},{6,10,1723},{7,10 +,343},{7,10,1996},{135,10,2026},{134,0,270},{4,10,341},{135,10,480},{5,11,356},{ +135,11,224},{11,11,588},{11,11,864},{11,11,968},{143,11,160},{132,0,556},{137,0, +801},{132,0,416},{142,0,372},{5,0,152},{5,0,197},{7,0,340},{7,0,867},{10,0,548}, +{10,0,581},{11,0,6},{12,0,3},{12,0,19},{14,0,110},{142,0,289},{139,0,369},{7,11, +630},{9,11,567},{11,11,150},{11,11,444},{141,11,119},{134,11,539},{7,10,1995},{8 +,10,299},{11,10,890},{140,10,674},{7,0,34},{7,0,190},{8,0,28},{8,0,141},{8,0,444 +},{8,0,811},{9,0,468},{11,0,334},{12,0,24},{12,0,386},{140,0,576},{133,0,757},{7 +,0,1553},{136,0,898},{133,0,721},{136,0,1012},{4,0,789},{5,0,647},{135,0,1102},{ +132,0,898},{4,10,238},{5,10,503},{6,10,179},{7,10,2003},{8,10,381},{8,10,473},{9 +,10,149},{10,0,183},{10,10,788},{15,10,45},{15,10,86},{20,10,110},{150,10,57},{4 +,10,121},{5,10,156},{5,10,349},{9,0,136},{10,10,605},{14,10,342},{147,0,107},{4, +11,235},{135,11,255},{4,11,194},{5,11,584},{6,11,384},{7,11,583},{10,11,761},{11 +,11,760},{139,11,851},{6,10,80},{6,10,1694},{7,10,173},{7,10,1974},{9,10,547},{ +10,10,730},{14,10,18},{150,10,39},{4,10,923},{134,10,1711},{5,0,277},{141,0,247} +,{132,0,435},{133,11,562},{134,0,1311},{5,11,191},{137,11,271},{132,10,595},{7, +11,1537},{14,11,96},{143,11,73},{5,0,437},{6,10,459},{7,0,502},{7,0,519},{7,0, +1122},{7,0,1751},{7,10,1753},{7,10,1805},{8,10,658},{9,10,1},{11,10,959},{13,10, +446},{142,0,211},{4,11,470},{5,11,473},{6,0,814},{6,11,153},{7,11,1503},{7,11, +1923},{10,11,701},{11,11,132},{11,11,168},{11,11,227},{11,11,320},{11,11,436},{ +11,11,525},{11,11,855},{12,11,41},{12,11,286},{13,11,103},{13,11,284},{14,11,255 +},{14,11,262},{15,11,117},{143,11,127},{5,0,265},{6,0,212},{135,0,28},{138,0,750 +},{133,11,327},{6,11,552},{7,11,1754},{137,11,604},{134,0,2012},{132,0,702},{5, +11,80},{6,11,405},{7,11,403},{7,11,1502},{7,11,1626},{8,11,456},{9,11,487},{9,11 +,853},{9,11,889},{10,11,309},{11,11,721},{11,11,994},{12,11,430},{141,11,165},{5 +,0,808},{135,0,2045},{5,0,166},{8,0,739},{140,0,511},{134,10,490},{4,11,453},{5, +11,887},{6,11,535},{8,11,6},{136,11,543},{4,0,119},{5,0,170},{5,0,447},{7,0,1708 +},{7,0,1889},{9,0,357},{9,0,719},{12,0,486},{140,0,596},{137,0,500},{7,10,250},{ +136,10,507},{132,10,158},{6,0,809},{134,0,1500},{4,10,140},{7,10,362},{8,10,209} +,{9,0,327},{9,10,10},{9,10,503},{9,10,614},{10,10,689},{11,0,350},{11,0,831},{11 +,10,327},{11,10,725},{12,10,252},{12,10,583},{13,0,352},{13,10,192},{14,10,269}, +{14,10,356},{148,10,50},{135,11,741},{4,0,450},{7,0,1158},{19,10,1},{19,10,26},{ +150,10,9},{6,0,597},{135,0,1318},{134,0,1602},{6,10,228},{7,10,1341},{9,10,408}, +{138,10,343},{7,0,1375},{7,0,1466},{138,0,331},{132,0,754},{132,10,557},{5,11, +101},{6,11,88},{6,11,543},{7,11,1677},{9,11,100},{10,11,677},{14,11,169},{14,11, +302},{14,11,313},{15,11,48},{143,11,84},{134,0,1368},{4,11,310},{9,11,795},{10, +11,733},{11,11,451},{12,11,249},{14,11,115},{14,11,286},{143,11,100},{132,10,548 +},{7,10,197},{8,10,142},{8,10,325},{9,10,150},{9,10,596},{10,0,557},{10,10,353}, +{11,10,74},{11,10,315},{12,10,662},{12,10,681},{14,10,423},{143,10,141},{133,11, +587},{5,0,850},{136,0,799},{10,0,908},{12,0,701},{12,0,757},{142,0,466},{4,0,62} +,{5,0,275},{6,10,399},{6,10,579},{7,10,692},{7,10,846},{7,10,1015},{7,10,1799},{ +8,10,403},{9,10,394},{10,10,133},{12,10,4},{12,10,297},{12,10,452},{16,10,81},{ +18,0,19},{18,10,25},{21,10,14},{22,10,12},{151,10,18},{7,10,1546},{11,10,299},{ +12,0,459},{142,10,407},{132,10,177},{132,11,498},{7,11,217},{8,11,140},{138,11, +610},{5,10,411},{135,10,653},{134,0,1802},{7,10,439},{10,10,727},{11,10,260},{ +139,10,684},{133,11,905},{11,11,580},{142,11,201},{134,0,1397},{5,10,208},{7,10, +753},{135,10,1528},{7,0,238},{7,0,2033},{8,0,120},{8,0,188},{8,0,659},{9,0,598}, +{10,0,466},{12,0,342},{12,0,588},{13,0,503},{14,0,246},{143,0,92},{135,11,1041}, +{4,11,456},{7,11,105},{7,11,358},{7,11,1637},{8,11,643},{139,11,483},{6,0,1318}, +{134,0,1324},{4,0,201},{5,10,242},{7,0,1744},{8,0,602},{11,0,247},{11,0,826},{ +145,0,65},{8,0,164},{146,0,62},{133,10,953},{139,10,802},{133,0,615},{7,11,1566} +,{8,11,269},{9,11,212},{9,11,718},{14,11,15},{14,11,132},{142,11,227},{133,10, +290},{132,10,380},{5,10,52},{7,10,277},{9,10,368},{139,10,791},{135,0,1243},{133 +,11,539},{11,11,919},{141,11,409},{136,0,968},{133,11,470},{134,0,882},{132,0, +907},{5,0,100},{10,0,329},{12,0,416},{149,0,29},{10,10,138},{139,10,476},{5,10, +725},{5,10,727},{6,11,91},{7,10,1811},{135,11,435},{4,11,16},{5,11,316},{5,11, +842},{6,11,370},{6,11,1778},{8,11,166},{11,11,812},{12,11,206},{12,11,351},{14, +11,418},{16,11,15},{16,11,34},{18,11,3},{19,11,3},{19,11,7},{20,11,4},{149,11,21 +},{132,0,176},{5,0,636},{5,0,998},{7,0,9},{7,0,1508},{8,0,26},{9,0,317},{9,0,358 +},{10,0,210},{10,0,292},{10,0,533},{11,0,555},{12,0,526},{12,0,607},{13,0,263},{ +13,0,459},{142,0,271},{4,10,38},{6,0,256},{7,10,307},{7,10,999},{7,10,1481},{7, +10,1732},{7,10,1738},{8,0,265},{9,10,414},{11,10,316},{12,10,52},{13,10,420},{ +147,10,100},{135,10,1296},{4,11,611},{133,11,606},{4,0,643},{142,11,21},{133,11, +715},{133,10,723},{6,0,610},{135,11,597},{10,0,127},{141,0,27},{6,0,1995},{6,0, +2001},{8,0,119},{136,0,973},{4,11,149},{138,11,368},{4,11,154},{5,10,109},{6,10, +1784},{7,10,1895},{7,11,1134},{8,11,105},{12,0,522},{12,10,296},{140,10,302},{4, +11,31},{6,11,429},{7,11,962},{9,11,458},{139,11,691},{4,11,312},{5,10,216},{7,10 +,1879},{9,10,141},{9,10,270},{9,10,679},{10,0,553},{10,10,159},{11,0,876},{11,10 +,197},{12,10,538},{12,10,559},{13,0,193},{13,0,423},{14,0,166},{14,10,144},{14, +10,167},{15,10,67},{147,0,84},{134,0,1582},{7,0,1578},{135,11,1578},{137,10,81}, +{132,11,236},{134,10,391},{134,0,795},{7,10,322},{136,10,249},{5,11,836},{5,11, +857},{6,11,1680},{7,11,59},{147,11,53},{135,0,432},{10,11,68},{139,11,494},{4,11 +,81},{139,11,867},{7,0,126},{136,0,84},{142,11,280},{5,11,282},{8,11,650},{9,11, +295},{9,11,907},{138,11,443},{136,0,790},{5,10,632},{138,10,526},{6,0,64},{12,0, +377},{13,0,309},{14,0,141},{14,0,429},{14,11,141},{142,11,429},{134,0,1529},{6,0 +,321},{7,0,1857},{7,10,948},{7,10,1042},{8,10,235},{8,10,461},{9,0,530},{9,10, +453},{10,10,354},{17,10,77},{147,0,99},{7,0,1104},{11,0,269},{11,0,539},{11,0, +627},{11,0,706},{11,0,975},{12,0,248},{12,0,434},{12,0,600},{12,0,622},{13,0,297 +},{13,0,485},{14,0,69},{14,0,409},{143,0,108},{4,10,362},{7,10,52},{7,10,303},{ +10,11,70},{12,11,26},{14,11,17},{14,11,178},{15,11,34},{149,11,12},{11,0,977},{ +141,0,507},{9,0,34},{139,0,484},{5,10,196},{6,10,486},{7,10,212},{8,10,309},{136 +,10,346},{6,0,1700},{7,0,26},{7,0,293},{7,0,382},{7,0,1026},{7,0,1087},{7,0,2027 +},{7,10,1912},{8,0,24},{8,0,114},{8,0,252},{8,0,727},{8,0,729},{9,0,30},{9,0,199 +},{9,0,231},{9,0,251},{9,0,334},{9,0,361},{9,0,712},{10,0,55},{10,0,60},{10,0, +232},{10,0,332},{10,0,384},{10,0,396},{10,0,504},{10,0,542},{10,0,652},{11,0,20} +,{11,0,48},{11,0,207},{11,0,291},{11,0,298},{11,0,342},{11,0,365},{11,0,394},{11 +,0,620},{11,0,705},{11,0,1017},{12,0,123},{12,0,340},{12,0,406},{12,0,643},{13,0 +,61},{13,0,269},{13,0,311},{13,0,319},{13,0,486},{14,0,234},{15,0,62},{15,0,85}, +{16,0,71},{18,0,119},{148,0,105},{4,11,71},{5,11,376},{7,11,119},{138,11,665},{4 +,10,686},{8,11,55},{10,0,918},{138,0,926},{138,10,625},{136,10,706},{132,11,479} +,{4,10,30},{133,10,43},{6,0,379},{7,0,270},{7,11,607},{8,0,176},{8,0,183},{8,11, +99},{9,0,432},{9,0,661},{12,0,247},{12,0,617},{18,0,125},{152,11,4},{5,0,792},{ +133,0,900},{4,11,612},{133,11,561},{4,10,220},{4,11,41},{5,11,74},{7,10,1535},{7 +,11,1627},{11,11,871},{140,11,619},{135,0,1920},{7,11,94},{11,11,329},{11,11,965 +},{12,11,241},{14,11,354},{15,11,22},{148,11,63},{9,11,209},{137,11,300},{134,0, +771},{135,0,1979},{4,0,901},{133,0,776},{142,0,254},{133,11,98},{9,11,16},{141, +11,386},{133,11,984},{4,11,182},{6,11,205},{135,11,220},{7,10,1725},{7,10,1774}, +{138,10,393},{5,10,263},{134,10,414},{4,11,42},{9,11,205},{9,11,786},{138,11,659 +},{14,0,140},{148,0,41},{6,10,178},{6,10,1750},{6,11,289},{7,11,1670},{8,0,440}, +{9,10,690},{10,0,359},{10,10,155},{10,10,373},{11,10,698},{12,11,57},{13,10,155} +,{20,10,93},{151,11,4},{4,0,37},{5,0,334},{7,0,1253},{151,11,25},{4,0,508},{4,11 +,635},{5,10,97},{137,10,393},{139,11,533},{4,0,640},{133,0,513},{134,10,1639},{ +132,11,371},{4,11,272},{7,11,836},{7,11,1651},{145,11,89},{5,11,825},{6,11,444}, +{6,11,1640},{136,11,308},{4,10,191},{7,10,934},{8,10,647},{145,10,97},{12,0,246} +,{15,0,162},{19,0,64},{20,0,8},{20,0,95},{22,0,24},{152,0,17},{4,0,533},{5,10, +165},{9,10,346},{138,10,655},{5,11,737},{139,10,885},{133,10,877},{8,10,128},{ +139,10,179},{137,11,307},{140,0,752},{133,0,920},{135,0,1048},{5,0,153},{6,0,580 +},{6,10,1663},{7,10,132},{7,10,1154},{7,10,1415},{7,10,1507},{12,10,493},{15,10, +105},{151,10,15},{5,10,459},{7,10,1073},{8,10,241},{136,10,334},{138,0,391},{135 +,0,1952},{133,11,525},{8,11,641},{11,11,388},{140,11,580},{142,0,126},{134,0,640 +},{132,0,483},{6,10,324},{6,10,520},{7,0,1616},{7,10,338},{7,10,1729},{8,10,228} +,{9,0,69},{139,10,750},{5,11,493},{134,11,528},{135,0,734},{4,11,174},{135,11, +911},{138,0,480},{9,0,495},{146,0,104},{135,10,705},{4,10,73},{6,10,612},{7,10, +927},{7,10,1330},{7,10,1822},{8,10,217},{9,0,472},{9,10,765},{9,10,766},{10,10, +408},{11,10,51},{11,10,793},{12,10,266},{15,10,158},{20,10,89},{150,10,32},{7,11 +,548},{137,11,58},{4,11,32},{5,11,215},{6,11,269},{7,11,1782},{7,11,1892},{10,11 +,16},{11,11,822},{11,11,954},{141,11,481},{132,0,874},{5,10,389},{8,10,636},{137 +,0,229},{7,11,1749},{136,11,477},{134,0,948},{5,11,308},{135,11,1088},{4,0,748}, +{139,0,1009},{136,10,21},{6,0,555},{135,0,485},{5,11,126},{8,11,297},{9,11,366}, +{9,11,445},{12,11,53},{12,11,374},{141,11,492},{7,11,1551},{139,11,361},{136,0, +193},{136,0,472},{8,0,653},{13,0,93},{147,0,14},{132,0,984},{132,11,175},{4,11, +685},{5,0,172},{134,0,1971},{149,11,8},{133,11,797},{5,10,189},{7,10,442},{7,10, +443},{8,10,281},{12,10,174},{13,0,83},{141,10,261},{134,0,1568},{133,11,565},{ +139,0,384},{133,0,260},{6,10,2},{7,0,758},{7,0,880},{7,0,1359},{7,10,1262},{7,10 +,1737},{8,10,22},{8,10,270},{8,10,612},{9,0,164},{9,0,167},{9,10,312},{9,10,436} +,{10,0,156},{10,0,588},{10,10,311},{10,10,623},{11,10,72},{11,10,330},{11,10,455 +},{12,0,101},{12,10,321},{12,10,504},{12,10,530},{12,10,543},{13,10,17},{13,10, +156},{13,10,334},{14,0,48},{15,0,70},{17,10,60},{148,10,64},{4,11,252},{7,11, +1068},{10,11,434},{11,11,228},{11,11,426},{13,11,231},{18,11,106},{148,11,87},{7 +,10,354},{10,10,410},{139,10,815},{6,0,367},{7,10,670},{7,10,1327},{8,10,411},{8 +,10,435},{9,10,653},{9,10,740},{10,10,385},{11,10,222},{11,10,324},{11,10,829},{ +140,10,611},{6,10,166},{7,0,1174},{135,10,374},{146,0,121},{132,0,828},{5,11,231 +},{138,11,509},{7,11,601},{9,11,277},{9,11,674},{10,11,178},{10,11,257},{10,11, +418},{11,11,531},{11,11,544},{11,11,585},{12,11,113},{12,11,475},{13,11,99},{142 +,11,428},{134,0,1541},{135,11,1779},{5,0,343},{134,10,398},{135,10,50},{135,11, +1683},{4,0,440},{7,0,57},{8,0,167},{8,0,375},{9,0,82},{9,0,561},{9,0,744},{9,11, +744},{138,0,620},{134,0,926},{6,10,517},{7,10,1159},{10,10,621},{139,10,192},{ +137,0,827},{8,0,194},{136,0,756},{10,10,223},{139,10,645},{7,10,64},{136,10,245} +,{4,11,399},{5,11,119},{5,11,494},{7,11,751},{137,11,556},{132,0,808},{135,0,22} +,{7,10,1763},{140,10,310},{5,0,639},{6,11,584},{7,0,1249},{139,0,896},{134,0, +1614},{135,0,860},{135,11,1121},{5,10,129},{6,10,61},{135,10,947},{4,0,102},{7,0 +,815},{7,0,1699},{139,0,964},{13,10,505},{141,10,506},{139,10,1000},{132,11,679} +,{132,0,899},{132,0,569},{5,11,694},{137,11,714},{136,0,795},{6,0,2045},{139,11, +7},{6,0,52},{9,0,104},{9,0,559},{12,0,308},{147,0,87},{4,0,301},{132,0,604},{133 +,10,637},{136,0,779},{5,11,143},{5,11,769},{6,11,1760},{7,11,682},{7,11,1992},{ +136,11,736},{137,10,590},{147,0,32},{137,11,527},{5,10,280},{135,10,1226},{134,0 +,494},{6,0,677},{6,0,682},{134,0,1044},{133,10,281},{135,10,1064},{5,11,860},{ +135,0,508},{6,11,422},{7,11,0},{7,11,1544},{9,11,577},{11,11,990},{12,11,141},{ +12,11,453},{13,11,47},{141,11,266},{134,0,1014},{5,11,515},{137,11,131},{134,0, +957},{132,11,646},{6,0,310},{7,0,1849},{8,0,72},{8,0,272},{8,0,431},{9,0,12},{9, +0,376},{10,0,563},{10,0,630},{10,0,796},{10,0,810},{11,0,367},{11,0,599},{11,0, +686},{140,0,672},{4,11,396},{7,0,570},{7,10,120},{7,11,728},{8,10,489},{9,10,319 +},{9,11,117},{10,10,820},{11,10,1004},{12,10,379},{12,10,679},{13,10,117},{13,10 +,412},{13,11,202},{14,10,25},{15,10,52},{15,10,161},{16,10,47},{20,11,51},{149, +10,2},{6,11,121},{6,11,124},{6,11,357},{7,11,1138},{7,11,1295},{8,11,162},{139, +11,655},{4,10,937},{5,10,801},{8,0,449},{136,11,449},{139,11,958},{6,0,181},{7,0 +,537},{8,0,64},{9,0,127},{10,0,496},{12,0,510},{141,0,384},{138,11,253},{4,0,244 +},{135,0,233},{133,11,237},{132,10,365},{6,0,1650},{10,0,702},{139,0,245},{5,10, +7},{139,10,774},{13,0,463},{13,11,463},{20,0,49},{148,11,49},{4,10,734},{5,10, +662},{134,10,430},{4,10,746},{135,10,1090},{5,10,360},{136,10,237},{137,0,338},{ +143,11,10},{7,11,571},{138,11,366},{134,0,1279},{9,11,513},{10,11,22},{10,11,39} +,{12,11,122},{140,11,187},{133,0,896},{146,0,178},{134,0,695},{137,0,808},{134, +11,587},{7,11,107},{7,11,838},{8,11,550},{138,11,401},{7,0,1117},{136,0,539},{4, +10,277},{5,10,608},{6,10,493},{7,10,457},{140,10,384},{133,11,768},{7,10,27},{7, +10,316},{140,0,257},{140,0,1003},{4,0,207},{5,0,586},{5,0,676},{5,10,552},{6,0, +448},{8,0,244},{11,0,1},{13,0,3},{16,0,54},{17,0,4},{146,0,13},{4,10,401},{137, +10,264},{5,0,516},{7,0,1883},{135,11,1883},{4,11,894},{140,0,960},{5,0,4},{5,0, +810},{6,0,13},{6,0,538},{6,0,1690},{6,0,1726},{7,0,499},{7,0,1819},{8,0,148},{8, +0,696},{8,0,791},{12,0,125},{143,0,9},{135,0,1268},{9,10,543},{10,10,524},{11,0, +30},{12,10,524},{14,0,315},{16,10,18},{20,10,26},{148,10,65},{4,10,205},{5,10, +623},{6,0,748},{7,10,104},{136,10,519},{11,0,542},{139,0,852},{140,0,6},{132,0, +848},{7,0,1385},{7,10,579},{9,10,41},{9,10,244},{9,10,669},{10,10,5},{11,0,582}, +{11,0,650},{11,0,901},{11,0,949},{11,10,861},{11,10,951},{11,10,980},{12,0,232}, +{12,0,236},{13,0,413},{13,0,501},{146,0,116},{4,0,945},{6,0,1811},{6,0,1845},{6, +0,1853},{6,0,1858},{8,0,862},{12,0,782},{12,0,788},{18,0,160},{148,0,117},{132, +10,717},{4,0,925},{5,0,803},{8,0,698},{138,0,828},{134,0,1416},{132,0,610},{139, +0,992},{6,0,878},{134,0,1477},{135,0,1847},{138,11,531},{137,11,539},{134,11,272 +},{133,0,383},{134,0,1404},{132,10,489},{4,11,9},{5,11,128},{7,11,368},{11,11, +480},{148,11,3},{136,0,986},{9,0,660},{138,0,347},{135,10,892},{136,11,682},{7,0 +,572},{9,0,592},{11,0,680},{12,0,356},{140,0,550},{7,0,1411},{138,11,527},{4,11, +2},{7,11,545},{135,11,894},{137,10,473},{7,10,819},{7,11,481},{9,10,26},{9,10, +392},{9,11,792},{10,10,152},{10,10,226},{11,0,64},{12,10,276},{12,10,426},{12,10 +,589},{13,10,460},{15,10,97},{19,10,48},{148,10,104},{135,10,51},{136,11,445},{ +136,11,646},{135,0,606},{132,10,674},{6,0,1829},{134,0,1830},{132,10,770},{5,10, +79},{7,10,1027},{7,10,1477},{139,10,52},{5,11,530},{142,11,113},{134,10,1666},{7 +,0,748},{139,0,700},{134,10,195},{133,10,789},{4,10,251},{4,10,688},{7,10,513},{ +7,10,1284},{9,0,87},{138,0,365},{136,11,111},{133,0,127},{6,0,198},{140,0,83},{ +133,11,556},{133,10,889},{4,10,160},{5,10,330},{7,10,1434},{136,10,174},{5,0,276 +},{6,0,55},{7,0,1369},{138,0,864},{8,11,16},{140,11,568},{6,0,1752},{136,0,726}, +{135,0,1066},{133,0,764},{6,11,186},{137,11,426},{11,0,683},{139,11,683},{6,0, +309},{7,0,331},{138,0,550},{133,10,374},{6,0,1212},{6,0,1852},{7,0,1062},{8,0, +874},{8,0,882},{138,0,936},{132,11,585},{134,0,1364},{5,10,731},{135,0,986},{6,0 +,723},{6,0,1408},{138,0,381},{135,0,1573},{134,0,1025},{4,10,626},{5,10,642},{6, +10,425},{10,10,202},{139,10,141},{4,11,93},{5,11,252},{6,11,229},{7,11,291},{9, +11,550},{139,11,644},{137,11,749},{137,11,162},{132,11,381},{135,0,1559},{6,0, +194},{7,0,133},{10,0,493},{10,0,570},{139,0,664},{5,0,24},{5,0,569},{6,0,3},{6,0 +,119},{6,0,143},{6,0,440},{7,0,295},{7,0,599},{7,0,1686},{7,0,1854},{8,0,424},{9 +,0,43},{9,0,584},{9,0,760},{10,0,148},{10,0,328},{11,0,159},{11,0,253},{11,0,506 +},{12,0,487},{140,0,531},{6,0,661},{134,0,1517},{136,10,835},{151,10,17},{5,0,14 +},{5,0,892},{6,0,283},{7,0,234},{136,0,537},{139,0,541},{4,0,126},{8,0,635},{147 +,0,34},{4,0,316},{4,0,495},{135,0,1561},{4,11,187},{5,11,184},{5,11,690},{7,11, +1869},{138,11,756},{139,11,783},{4,0,998},{137,0,861},{136,0,1009},{139,11,292}, +{5,11,21},{6,11,77},{6,11,157},{7,11,974},{7,11,1301},{7,11,1339},{7,11,1490},{7 +,11,1873},{137,11,628},{7,11,1283},{9,11,227},{9,11,499},{10,11,341},{11,11,325} +,{11,11,408},{14,11,180},{15,11,144},{18,11,47},{147,11,49},{4,0,64},{5,0,352},{ +5,0,720},{6,0,368},{139,0,359},{5,10,384},{8,10,455},{140,10,48},{5,10,264},{134 +,10,184},{7,0,1577},{10,0,304},{10,0,549},{12,0,365},{13,0,220},{13,0,240},{142, +0,33},{134,0,1107},{134,0,929},{135,0,1142},{6,0,175},{137,0,289},{5,0,432},{133 +,0,913},{5,10,633},{6,0,279},{7,0,219},{135,10,1323},{7,0,785},{7,10,359},{8,10, +243},{140,10,175},{139,0,595},{132,10,105},{8,11,398},{9,11,681},{139,11,632},{ +140,0,80},{5,0,931},{134,0,1698},{142,11,241},{134,11,20},{134,0,1323},{11,0,526 +},{11,0,939},{141,0,290},{5,0,774},{6,0,780},{6,0,1637},{6,0,1686},{6,0,1751},{8 +,0,559},{141,0,109},{141,0,127},{7,0,1167},{7,11,709},{11,0,934},{13,0,391},{145 +,0,76},{135,0,963},{6,0,260},{135,0,1484},{134,0,573},{4,10,758},{139,11,941},{ +135,10,1649},{145,11,36},{4,0,292},{137,0,580},{4,0,736},{5,0,871},{6,0,1689},{ +135,0,1944},{7,11,945},{11,11,713},{139,11,744},{134,0,1164},{135,11,937},{6,0, +1922},{7,11,1652},{9,0,982},{15,0,173},{15,0,178},{15,0,200},{18,0,189},{18,0, +207},{149,0,47},{7,0,1695},{139,10,128},{6,0,63},{135,0,920},{133,0,793},{143,11 +,134},{133,10,918},{5,0,67},{6,0,62},{6,0,374},{135,0,1391},{4,11,579},{5,11,226 +},{5,11,323},{7,11,960},{9,0,790},{140,0,47},{10,11,784},{141,11,191},{4,0,391}, +{135,0,1169},{137,0,443},{13,11,232},{146,11,35},{132,10,340},{132,0,271},{137, +11,313},{5,11,973},{137,11,659},{134,0,1140},{6,11,135},{135,11,1176},{4,0,253}, +{5,0,544},{7,0,300},{137,0,340},{5,10,985},{7,0,897},{7,10,509},{145,10,96},{138 +,11,735},{135,10,1919},{138,0,890},{5,0,818},{134,0,1122},{5,0,53},{5,0,541},{6, +0,94},{6,0,499},{7,0,230},{139,0,321},{4,0,920},{5,0,25},{5,0,790},{6,0,457},{7, +0,853},{8,0,788},{142,11,31},{132,10,247},{135,11,314},{132,0,468},{6,10,337},{7 +,0,243},{7,10,494},{8,10,27},{8,10,599},{138,10,153},{4,10,184},{5,10,390},{7,10 +,618},{7,10,1456},{139,10,710},{134,0,870},{134,0,1238},{134,0,1765},{10,0,853}, +{10,0,943},{14,0,437},{14,0,439},{14,0,443},{14,0,446},{14,0,452},{14,0,469},{14 +,0,471},{14,0,473},{16,0,93},{16,0,102},{16,0,110},{148,0,121},{4,0,605},{7,0, +518},{7,0,1282},{7,0,1918},{10,0,180},{139,0,218},{133,0,822},{4,0,634},{11,0, +916},{142,0,419},{6,11,281},{7,11,6},{8,11,282},{8,11,480},{8,11,499},{9,11,198} +,{10,11,143},{10,11,169},{10,11,211},{10,11,417},{10,11,574},{11,11,147},{11,11, +395},{12,11,75},{12,11,407},{12,11,608},{13,11,500},{142,11,251},{134,0,898},{6, +0,36},{7,0,658},{8,0,454},{150,11,48},{133,11,674},{135,11,1776},{4,11,419},{10, +10,227},{11,10,497},{11,10,709},{140,10,415},{6,10,360},{7,10,1664},{136,10,478} +,{137,0,806},{12,11,508},{14,11,102},{14,11,226},{144,11,57},{135,11,1123},{4,11 +,138},{7,11,1012},{7,11,1280},{137,11,76},{5,11,29},{140,11,638},{136,10,699},{ +134,0,1326},{132,0,104},{135,11,735},{132,10,739},{134,0,1331},{7,0,260},{135,11 +,260},{135,11,1063},{7,0,45},{9,0,542},{9,0,566},{9,10,869},{138,0,728},{4,10,67 +},{5,10,422},{7,10,1037},{7,10,1289},{7,10,1555},{9,10,741},{145,10,108},{139,0, +263},{134,0,1516},{14,0,146},{15,0,42},{16,0,23},{17,0,86},{146,0,17},{138,0,468 +},{136,0,1005},{4,11,17},{5,11,23},{7,11,995},{11,11,383},{11,11,437},{12,11,460 +},{140,11,532},{7,0,87},{142,0,288},{138,10,96},{135,11,626},{144,10,26},{7,0, +988},{7,0,1939},{9,0,64},{9,0,502},{12,0,22},{12,0,34},{13,0,12},{13,0,234},{147 +,0,77},{8,10,203},{11,10,823},{11,10,846},{12,10,482},{13,0,133},{13,10,277},{13 +,10,302},{13,10,464},{14,10,205},{142,10,221},{4,10,449},{133,10,718},{135,0,141 +},{6,0,1842},{136,0,872},{8,11,70},{12,11,171},{141,11,272},{4,10,355},{6,10,311 +},{9,10,256},{138,10,404},{132,0,619},{137,0,261},{10,10,758},{10,11,233},{139, +11,76},{5,0,246},{8,0,189},{9,0,355},{9,0,512},{10,0,124},{10,0,453},{11,0,143}, +{11,0,416},{11,0,859},{141,0,341},{134,11,442},{133,10,827},{5,10,64},{140,10, +581},{4,10,442},{7,10,1047},{7,10,1352},{135,10,1643},{134,11,1709},{5,0,678},{5 +,10,977},{6,0,305},{7,0,775},{135,0,1065},{11,11,69},{12,11,105},{12,11,117},{13 +,11,213},{14,11,13},{14,11,62},{14,11,177},{14,11,421},{15,11,19},{146,11,141},{ +137,11,309},{5,0,35},{7,0,862},{7,0,1886},{138,0,179},{136,0,285},{132,0,517},{7 +,11,976},{9,11,146},{10,11,206},{10,11,596},{13,11,218},{142,11,153},{132,10,254 +},{4,10,275},{6,0,214},{7,10,1219},{12,0,540},{140,10,376},{8,0,667},{11,0,403}, +{146,0,83},{10,11,648},{11,11,671},{12,0,74},{143,11,46},{135,0,125},{134,10, +1753},{133,0,761},{4,11,518},{6,0,912},{6,10,369},{6,10,502},{7,10,1036},{7,11, +1136},{8,10,348},{9,10,452},{10,10,26},{11,10,224},{11,10,387},{11,10,772},{12, +10,95},{12,10,629},{13,10,195},{13,10,207},{13,10,241},{14,10,260},{14,10,270},{ +143,10,140},{10,0,131},{140,0,72},{132,10,269},{5,10,480},{7,10,532},{7,10,1197} +,{7,10,1358},{8,10,291},{11,10,349},{142,10,396},{8,11,689},{137,11,863},{8,0, +333},{138,0,182},{4,11,18},{7,11,145},{7,11,444},{7,11,1278},{8,11,49},{8,11,400 +},{9,11,71},{9,11,250},{10,11,459},{12,11,160},{144,11,24},{14,11,35},{142,11, +191},{135,11,1864},{135,0,1338},{148,10,15},{14,0,94},{15,0,65},{16,0,4},{16,0, +77},{16,0,80},{145,0,5},{12,11,82},{143,11,36},{133,11,1010},{133,0,449},{133,0, +646},{7,0,86},{7,10,657},{136,0,103},{7,0,2028},{138,0,641},{136,10,533},{134,0, +1},{139,11,970},{5,11,87},{7,11,313},{7,11,1103},{10,11,112},{10,11,582},{11,11, +389},{11,11,813},{12,11,385},{13,11,286},{14,11,124},{146,11,108},{4,11,267},{ +134,0,869},{6,0,277},{7,0,1274},{7,0,1386},{146,0,87},{6,0,187},{7,0,39},{7,0, +1203},{8,0,380},{14,0,117},{149,0,28},{4,10,211},{4,10,332},{5,10,335},{6,10,238 +},{7,10,269},{7,10,811},{7,10,1797},{8,10,836},{9,10,507},{141,10,242},{4,0,785} +,{5,0,368},{6,0,297},{7,0,793},{139,0,938},{7,0,464},{8,0,558},{11,0,105},{12,0, +231},{14,0,386},{15,0,102},{148,0,75},{133,10,1009},{8,0,877},{140,0,731},{139, +11,289},{10,11,249},{139,11,209},{132,11,561},{134,0,1608},{132,11,760},{134,0, +1429},{9,11,154},{140,11,485},{5,10,228},{6,10,203},{7,10,156},{8,10,347},{137, +10,265},{7,0,1010},{11,0,733},{11,0,759},{13,0,34},{14,0,427},{146,0,45},{7,10, +1131},{135,10,1468},{136,11,255},{7,0,1656},{9,0,369},{10,0,338},{10,0,490},{11, +0,154},{11,0,545},{11,0,775},{13,0,77},{141,0,274},{133,11,621},{134,0,1038},{4, +11,368},{135,11,641},{6,0,2010},{8,0,979},{8,0,985},{10,0,951},{138,0,1011},{134 +,0,1005},{5,10,291},{5,10,318},{7,10,765},{9,10,389},{12,10,548},{147,0,121},{5, +0,20},{6,0,298},{7,0,659},{137,0,219},{7,0,1440},{11,0,854},{11,0,872},{11,0,921 +},{12,0,551},{13,0,472},{142,0,367},{5,0,490},{6,0,615},{6,0,620},{135,0,683},{6 +,0,1070},{134,0,1597},{139,0,522},{132,0,439},{136,0,669},{6,0,766},{6,0,1143},{ +6,0,1245},{10,10,525},{139,10,82},{9,11,92},{147,11,91},{6,0,668},{134,0,1218},{ +6,11,525},{9,11,876},{140,11,284},{132,0,233},{136,0,547},{132,10,422},{5,10,355 +},{145,10,0},{6,11,300},{135,11,1515},{4,0,482},{137,10,905},{4,0,886},{5,11,594 +},{135,0,346},{133,10,865},{5,10,914},{134,10,1625},{135,0,334},{5,0,795},{5,10, +234},{134,0,1741},{135,10,1383},{6,11,1641},{136,11,820},{135,0,371},{7,11,1313} +,{138,11,660},{135,10,1312},{135,0,622},{7,0,625},{135,0,1750},{135,0,339},{4,0, +203},{135,0,1936},{15,0,29},{15,11,29},{16,0,38},{144,11,38},{5,0,338},{135,0, +1256},{135,10,1493},{6,10,421},{7,10,61},{7,10,1540},{10,0,130},{138,10,501},{6, +11,389},{7,11,149},{9,11,142},{138,11,94},{137,10,341},{11,0,678},{12,0,307},{ +142,10,98},{6,11,8},{7,11,1881},{136,11,91},{135,0,2044},{6,0,770},{6,0,802},{6, +0,812},{6,10,102},{7,0,311},{7,10,72},{9,0,308},{12,0,255},{15,10,142},{147,10, +67},{151,10,30},{135,10,823},{135,0,1266},{135,11,1746},{135,10,1870},{4,0,400}, +{5,0,267},{135,0,232},{7,11,24},{11,11,542},{139,11,852},{135,11,1739},{4,11,503 +},{135,11,1661},{5,11,130},{7,11,1314},{9,11,610},{10,11,718},{11,11,601},{11,11 +,819},{11,11,946},{140,11,536},{10,11,149},{11,11,280},{142,11,336},{7,0,739},{7 +,11,1946},{8,10,48},{8,10,88},{8,10,582},{8,10,681},{9,10,373},{9,10,864},{11,0, +690},{11,10,157},{11,10,843},{148,10,27},{134,0,990},{4,10,88},{5,10,137},{5,10, +174},{5,10,777},{6,10,1664},{6,10,1725},{7,10,77},{7,10,426},{7,10,1317},{7,10, +1355},{8,10,126},{8,10,563},{9,10,523},{9,10,750},{10,10,310},{10,10,836},{11,10 +,42},{11,10,318},{11,10,731},{12,10,68},{12,10,92},{12,10,507},{12,10,692},{13, +10,81},{13,10,238},{13,10,374},{14,10,436},{18,10,138},{19,10,78},{19,10,111},{ +20,10,55},{20,10,77},{148,10,92},{141,10,418},{4,10,938},{135,0,1831},{6,0,776}, +{134,0,915},{138,10,351},{5,11,348},{6,10,1668},{6,11,522},{7,10,1499},{8,10,117 +},{9,10,314},{138,10,174},{135,10,707},{132,0,613},{133,10,403},{132,11,392},{5, +11,433},{9,11,633},{139,11,629},{133,0,763},{132,0,878},{132,0,977},{132,0,100}, +{4,10,44},{5,10,311},{6,0,463},{7,10,639},{7,10,762},{7,10,1827},{9,10,8},{9,10, +462},{148,10,83},{134,11,234},{4,10,346},{7,10,115},{9,10,180},{9,10,456},{138, +10,363},{5,0,362},{5,0,443},{6,0,318},{7,0,1019},{139,0,623},{5,0,463},{7,11,140 +},{7,11,1950},{8,0,296},{8,11,680},{11,11,817},{147,11,88},{7,11,1222},{138,11, +386},{142,0,137},{132,0,454},{6,11,5},{7,0,1914},{7,10,1051},{9,10,545},{11,11, +249},{12,11,313},{16,11,66},{145,11,26},{135,0,1527},{145,0,58},{148,11,59},{5,0 +,48},{5,0,404},{6,0,557},{7,0,458},{8,0,597},{10,0,455},{10,0,606},{11,0,49},{11 +,0,548},{12,0,476},{13,0,18},{141,0,450},{5,11,963},{134,11,1773},{133,0,729},{ +138,11,586},{5,0,442},{135,0,1984},{134,0,449},{144,0,40},{4,0,853},{7,11,180},{ +8,11,509},{136,11,792},{6,10,185},{7,10,1899},{9,10,875},{139,10,673},{134,11, +524},{4,10,327},{5,10,478},{7,10,1332},{8,10,753},{140,0,227},{5,10,1020},{5,10, +1022},{134,0,1491},{4,10,103},{133,10,401},{132,11,931},{4,10,499},{135,10,1421} +,{5,0,55},{7,0,376},{140,0,161},{133,0,450},{6,0,1174},{134,0,1562},{7,11,1837}, +{10,0,62},{141,0,400},{140,0,207},{135,0,869},{4,11,773},{5,11,618},{137,11,756} +,{132,10,96},{4,0,213},{7,0,223},{7,10,968},{136,0,80},{4,11,90},{5,11,337},{5, +11,545},{7,11,754},{9,11,186},{10,11,72},{10,11,782},{11,11,513},{11,11,577},{11 +,11,610},{11,11,889},{11,11,961},{12,11,354},{12,11,362},{12,11,461},{12,11,595} +,{13,11,79},{143,11,121},{7,0,381},{7,0,806},{7,0,820},{8,0,354},{8,0,437},{8,0, +787},{9,0,657},{10,0,58},{10,0,339},{10,0,749},{11,0,914},{12,0,162},{13,0,75},{ +14,0,106},{14,0,198},{14,0,320},{14,0,413},{146,0,43},{136,0,747},{136,0,954},{ +134,0,1073},{135,0,556},{7,11,151},{9,11,329},{139,11,254},{5,0,692},{134,0,1395 +},{6,10,563},{137,10,224},{134,0,191},{132,0,804},{9,11,187},{10,11,36},{17,11, +44},{146,11,64},{7,11,165},{7,11,919},{136,11,517},{4,11,506},{5,11,295},{7,11, +1680},{15,11,14},{144,11,5},{4,0,706},{6,0,162},{7,0,1960},{136,0,831},{135,11, +1376},{7,11,987},{9,11,688},{10,11,522},{11,11,788},{140,11,566},{150,0,35},{138 +,0,426},{135,0,1235},{135,11,1741},{7,11,389},{7,11,700},{7,11,940},{8,11,514},{ +9,11,116},{9,11,535},{10,11,118},{11,11,107},{11,11,148},{11,11,922},{12,11,254} +,{12,11,421},{142,11,238},{134,0,1234},{132,11,743},{4,10,910},{5,10,832},{135, +11,1335},{141,0,96},{135,11,185},{146,0,149},{4,0,204},{137,0,902},{4,11,784},{ +133,11,745},{136,0,833},{136,0,949},{5,11,81},{7,0,366},{7,11,146},{7,11,1342},{ +7,11,1446},{8,11,53},{8,11,561},{8,11,694},{8,11,754},{9,0,287},{9,11,97},{9,11, +115},{9,11,894},{10,11,462},{10,11,813},{11,11,230},{11,11,657},{11,11,699},{11, +11,748},{12,0,199},{12,0,556},{12,0,577},{12,11,119},{12,11,200},{12,11,283},{14 +,11,273},{145,11,15},{5,11,408},{137,11,747},{9,11,498},{140,11,181},{6,0,2020}, +{136,0,992},{5,0,356},{135,0,224},{134,0,784},{7,0,630},{8,10,528},{9,0,567},{9, +10,348},{11,0,150},{11,0,444},{141,0,119},{134,0,539},{4,10,20},{133,10,616},{ +142,0,27},{7,11,30},{8,11,86},{8,11,315},{8,11,700},{9,11,576},{9,11,858},{11,11 +,310},{11,11,888},{11,11,904},{12,11,361},{141,11,248},{138,11,839},{134,0,755}, +{134,0,1063},{7,10,1091},{135,10,1765},{134,11,428},{7,11,524},{8,11,169},{8,11, +234},{9,11,480},{138,11,646},{139,0,814},{7,11,1462},{139,11,659},{4,10,26},{5, +10,429},{6,10,245},{7,10,704},{7,10,1379},{135,10,1474},{7,11,1205},{138,11,637} +,{139,11,803},{132,10,621},{136,0,987},{4,11,266},{8,11,4},{9,11,39},{10,11,166} +,{11,11,918},{12,11,635},{20,11,10},{22,11,27},{150,11,43},{4,0,235},{135,0,255} +,{4,0,194},{5,0,584},{6,0,384},{7,0,583},{10,0,761},{11,0,760},{139,0,851},{133, +10,542},{134,0,1086},{133,10,868},{8,0,1016},{136,0,1018},{7,0,1396},{7,11,1396} +,{136,10,433},{135,10,1495},{138,10,215},{141,10,124},{7,11,157},{8,11,279},{9, +11,759},{16,11,31},{16,11,39},{16,11,75},{18,11,24},{20,11,42},{152,11,1},{5,0, +562},{134,11,604},{134,0,913},{5,0,191},{137,0,271},{4,0,470},{6,0,153},{7,0, +1503},{7,0,1923},{10,0,701},{11,0,132},{11,0,227},{11,0,320},{11,0,436},{11,0, +525},{11,0,855},{11,0,873},{12,0,41},{12,0,286},{13,0,103},{13,0,284},{14,0,255} +,{14,0,262},{15,0,117},{143,0,127},{7,0,475},{12,0,45},{147,10,112},{132,11,567} +,{137,11,859},{6,0,713},{6,0,969},{6,0,1290},{134,0,1551},{133,0,327},{6,0,552}, +{6,0,1292},{7,0,1754},{137,0,604},{4,0,223},{5,11,762},{6,0,359},{7,11,1880},{9, +11,680},{11,0,3},{11,11,798},{13,0,108},{14,0,89},{144,0,22},{5,0,80},{6,0,405}, +{7,0,403},{7,0,1502},{8,0,456},{9,0,487},{9,0,853},{9,0,889},{10,0,309},{11,0, +721},{11,0,994},{12,0,430},{141,0,165},{133,11,298},{132,10,647},{134,0,2016},{ +18,10,10},{146,11,10},{4,0,453},{5,0,887},{6,0,535},{8,0,6},{8,0,543},{136,0,826 +},{136,0,975},{10,0,961},{138,0,962},{138,10,220},{6,0,1891},{6,0,1893},{9,0,916 +},{9,0,965},{9,0,972},{12,0,801},{12,0,859},{12,0,883},{15,0,226},{149,0,51},{ +132,10,109},{135,11,267},{7,11,92},{7,11,182},{8,11,453},{9,11,204},{11,11,950}, +{12,11,94},{12,11,644},{16,11,20},{16,11,70},{16,11,90},{147,11,55},{134,10,1746 +},{6,11,71},{7,11,845},{7,11,1308},{8,11,160},{137,11,318},{5,0,101},{6,0,88},{7 +,0,263},{7,0,628},{7,0,1677},{7,11,237},{8,0,349},{8,11,664},{9,0,100},{9,11,42} +,{9,11,266},{9,11,380},{9,11,645},{10,0,677},{10,11,177},{10,11,276},{14,0,169}, +{14,0,302},{14,0,313},{15,0,48},{143,0,84},{138,11,69},{4,0,310},{7,0,708},{7,0, +996},{9,0,795},{10,0,390},{10,0,733},{11,0,451},{12,0,249},{14,0,115},{14,0,286} +,{143,0,100},{4,10,40},{5,0,587},{10,10,67},{11,10,117},{11,10,768},{139,10,935} +,{6,0,1942},{7,0,512},{136,0,983},{7,10,992},{8,10,301},{9,10,722},{12,10,63},{ +13,10,29},{14,10,161},{143,10,18},{136,11,76},{139,10,923},{134,0,645},{134,0, +851},{4,0,498},{132,11,293},{7,0,217},{8,0,140},{10,0,610},{14,11,352},{17,11,53 +},{18,11,146},{18,11,152},{19,11,11},{150,11,54},{134,0,1448},{138,11,841},{133, +0,905},{4,11,605},{7,11,518},{7,11,1282},{7,11,1918},{10,11,180},{139,11,218},{ +139,11,917},{135,10,825},{140,10,328},{4,0,456},{7,0,105},{7,0,358},{7,0,1637},{ +8,0,643},{139,0,483},{134,0,792},{6,11,96},{135,11,1426},{137,11,691},{4,11,651} +,{133,11,289},{7,11,688},{8,11,35},{9,11,511},{10,11,767},{147,11,118},{150,0,56 +},{5,0,243},{5,0,535},{6,10,204},{10,10,320},{10,10,583},{13,10,502},{14,10,72}, +{14,10,274},{14,10,312},{14,10,344},{15,10,159},{16,10,62},{16,10,69},{17,10,30} +,{18,10,42},{18,10,53},{18,10,84},{18,10,140},{19,10,68},{19,10,85},{20,10,5},{ +20,10,45},{20,10,101},{22,10,7},{150,10,20},{4,10,558},{6,10,390},{7,10,162},{7, +10,689},{9,10,360},{138,10,653},{146,11,23},{135,0,1748},{5,10,856},{6,10,1672}, +{6,10,1757},{134,10,1781},{4,11,704},{5,0,539},{5,0,754},{134,0,876},{135,11, +1078},{5,10,92},{10,10,736},{140,10,102},{5,10,590},{9,10,213},{145,0,91},{134,0 +,1565},{6,0,91},{135,0,435},{4,0,939},{140,0,792},{134,0,1399},{4,0,16},{4,11, +720},{5,0,316},{5,0,842},{5,11,306},{6,0,370},{6,0,1778},{8,0,166},{11,0,812},{ +12,0,206},{12,0,351},{14,0,418},{16,0,15},{16,0,34},{18,0,3},{19,0,3},{19,0,7},{ +20,0,4},{149,0,21},{144,0,95},{133,11,431},{132,11,234},{135,0,551},{4,0,999},{6 +,0,1966},{134,0,2042},{7,0,619},{10,0,547},{11,0,122},{12,0,601},{15,0,7},{148,0 +,20},{5,11,464},{6,11,236},{7,11,276},{7,11,696},{7,11,914},{7,11,1108},{7,11, +1448},{9,11,15},{9,11,564},{10,11,14},{12,11,565},{13,11,449},{14,11,53},{15,11, +13},{16,11,64},{145,11,41},{6,0,884},{6,0,1019},{134,0,1150},{6,11,1767},{12,11, +194},{145,11,107},{136,10,503},{133,11,840},{6,10,466},{135,0,671},{132,0,888},{ +4,0,149},{138,0,368},{4,0,154},{7,0,1134},{136,0,105},{135,0,983},{9,11,642},{11 +,11,236},{142,11,193},{4,0,31},{6,0,429},{7,0,962},{9,0,458},{139,0,691},{6,0, +643},{134,0,1102},{132,0,312},{4,11,68},{5,11,634},{6,11,386},{7,11,794},{8,11, +273},{9,11,563},{10,11,105},{10,11,171},{11,11,94},{139,11,354},{133,0,740},{135 +,0,1642},{4,11,95},{7,11,416},{8,11,211},{139,11,830},{132,0,236},{138,10,241},{ +7,11,731},{13,11,20},{143,11,11},{5,0,836},{5,0,857},{6,0,1680},{135,0,59},{10,0 +,68},{11,0,494},{152,11,6},{4,0,81},{139,0,867},{135,0,795},{133,11,689},{4,0, +1001},{5,0,282},{6,0,1932},{6,0,1977},{6,0,1987},{6,0,1992},{8,0,650},{8,0,919}, +{8,0,920},{8,0,923},{8,0,926},{8,0,927},{8,0,931},{8,0,939},{8,0,947},{8,0,956}, +{8,0,997},{9,0,907},{10,0,950},{10,0,953},{10,0,954},{10,0,956},{10,0,958},{10,0 +,959},{10,0,964},{10,0,970},{10,0,972},{10,0,973},{10,0,975},{10,0,976},{10,0, +980},{10,0,981},{10,0,984},{10,0,988},{10,0,990},{10,0,995},{10,0,999},{10,0, +1002},{10,0,1003},{10,0,1005},{10,0,1006},{10,0,1008},{10,0,1009},{10,0,1012},{ +10,0,1014},{10,0,1015},{10,0,1019},{10,0,1020},{10,0,1022},{12,0,959},{12,0,961} +,{12,0,962},{12,0,963},{12,0,964},{12,0,965},{12,0,967},{12,0,968},{12,0,969},{ +12,0,970},{12,0,971},{12,0,972},{12,0,973},{12,0,974},{12,0,975},{12,0,976},{12, +0,977},{12,0,979},{12,0,981},{12,0,982},{12,0,983},{12,0,984},{12,0,985},{12,0, +986},{12,0,987},{12,0,989},{12,0,990},{12,0,992},{12,0,993},{12,0,995},{12,0,998 +},{12,0,999},{12,0,1000},{12,0,1001},{12,0,1002},{12,0,1004},{12,0,1005},{12,0, +1006},{12,0,1007},{12,0,1008},{12,0,1009},{12,0,1010},{12,0,1011},{12,0,1012},{ +12,0,1014},{12,0,1015},{12,0,1016},{12,0,1017},{12,0,1018},{12,0,1019},{12,0, +1022},{12,0,1023},{14,0,475},{14,0,477},{14,0,478},{14,0,479},{14,0,480},{14,0, +482},{14,0,483},{14,0,484},{14,0,485},{14,0,486},{14,0,487},{14,0,488},{14,0,489 +},{14,0,490},{14,0,491},{14,0,492},{14,0,493},{14,0,494},{14,0,495},{14,0,496},{ +14,0,497},{14,0,498},{14,0,499},{14,0,500},{14,0,501},{14,0,502},{14,0,503},{14, +0,504},{14,0,506},{14,0,507},{14,0,508},{14,0,509},{14,0,510},{14,0,511},{16,0, +113},{16,0,114},{16,0,115},{16,0,117},{16,0,118},{16,0,119},{16,0,121},{16,0,122 +},{16,0,123},{16,0,124},{16,0,125},{16,0,126},{16,0,127},{18,0,242},{18,0,243},{ +18,0,244},{18,0,245},{18,0,248},{18,0,249},{18,0,250},{18,0,251},{18,0,252},{18, +0,253},{18,0,254},{18,0,255},{20,0,125},{20,0,126},{148,0,127},{7,11,1717},{7,11 +,1769},{138,11,546},{7,11,1127},{7,11,1572},{10,11,297},{10,11,422},{11,11,764}, +{11,11,810},{12,11,264},{13,11,102},{13,11,300},{13,11,484},{14,11,147},{14,11, +229},{17,11,71},{18,11,118},{147,11,120},{6,0,1148},{134,0,1586},{132,0,775},{ +135,10,954},{133,11,864},{133,11,928},{138,11,189},{135,10,1958},{6,10,549},{8, +10,34},{8,10,283},{9,10,165},{138,10,475},{5,10,652},{5,10,701},{135,10,449},{ +135,11,695},{4,10,655},{7,10,850},{17,10,75},{146,10,137},{140,11,682},{133,11, +523},{8,0,970},{136,10,670},{136,11,555},{7,11,76},{8,11,44},{9,11,884},{10,11, +580},{11,11,399},{11,11,894},{15,11,122},{18,11,144},{147,11,61},{6,10,159},{6, +10,364},{7,10,516},{7,10,1439},{137,10,518},{4,0,71},{5,0,376},{7,0,119},{138,0, +665},{141,10,151},{11,0,827},{14,0,34},{143,0,148},{133,11,518},{4,0,479},{135, +11,1787},{135,11,1852},{135,10,993},{7,0,607},{136,0,99},{134,0,1960},{132,0,793 +},{4,0,41},{5,0,74},{7,0,1627},{11,0,871},{140,0,619},{7,0,94},{11,0,329},{11,0, +965},{12,0,241},{14,0,354},{15,0,22},{148,0,63},{7,10,501},{9,10,111},{10,10,141 +},{11,10,332},{13,10,43},{13,10,429},{14,10,130},{14,10,415},{145,10,102},{9,0, +209},{137,0,300},{134,0,1497},{138,11,255},{4,11,934},{5,11,138},{136,11,610},{ +133,0,98},{6,0,1316},{10,11,804},{138,11,832},{8,11,96},{9,11,36},{10,11,607},{ +11,11,423},{11,11,442},{12,11,309},{14,11,199},{15,11,90},{145,11,110},{132,0, +463},{5,10,149},{136,10,233},{133,10,935},{4,11,652},{8,11,320},{9,11,13},{9,11, +398},{9,11,727},{10,11,75},{10,11,184},{10,11,230},{10,11,564},{10,11,569},{11, +11,973},{12,11,70},{12,11,189},{13,11,57},{13,11,257},{22,11,6},{150,11,16},{142 +,0,291},{12,10,582},{146,10,131},{136,10,801},{133,0,984},{145,11,116},{4,11,692 +},{133,11,321},{4,0,182},{6,0,205},{135,0,220},{4,0,42},{9,0,205},{9,0,786},{138 +,0,659},{6,0,801},{11,11,130},{140,11,609},{132,0,635},{5,11,345},{135,11,1016}, +{139,0,533},{132,0,371},{4,0,272},{135,0,836},{6,0,1282},{135,11,1100},{5,0,825} +,{134,0,1640},{135,11,1325},{133,11,673},{4,11,287},{133,11,1018},{135,0,357},{6 +,0,467},{137,0,879},{7,0,317},{135,0,569},{6,0,924},{134,0,1588},{5,10,406},{5, +11,34},{10,11,724},{12,11,444},{13,11,354},{18,11,32},{23,11,24},{23,11,31},{152 +,11,5},{6,0,1795},{6,0,1835},{6,0,1836},{6,0,1856},{8,0,844},{8,0,849},{8,0,854} +,{8,0,870},{8,0,887},{10,0,852},{138,0,942},{6,10,69},{135,10,117},{137,0,307},{ +4,0,944},{6,0,1799},{6,0,1825},{10,0,848},{10,0,875},{10,0,895},{10,0,899},{10,0 +,902},{140,0,773},{11,0,43},{13,0,72},{141,0,142},{135,10,1830},{134,11,382},{4, +10,432},{135,10,824},{132,11,329},{7,0,1820},{139,11,124},{133,10,826},{133,0, +525},{132,11,906},{7,11,1940},{136,11,366},{138,11,10},{4,11,123},{4,11,649},{5, +11,605},{7,11,1509},{136,11,36},{6,0,110},{135,0,1681},{133,0,493},{133,11,767}, +{4,0,174},{135,0,911},{138,11,786},{8,0,417},{137,0,782},{133,10,1000},{7,0,733} +,{137,0,583},{4,10,297},{6,10,529},{7,10,152},{7,10,713},{7,10,1845},{8,10,710}, +{8,10,717},{12,10,639},{140,10,685},{4,0,32},{5,0,215},{6,0,269},{7,0,1782},{7,0 +,1892},{10,0,16},{11,0,822},{11,0,954},{141,0,481},{4,11,273},{5,11,658},{133,11 +,995},{136,0,477},{134,11,72},{135,11,1345},{4,10,520},{5,0,308},{7,0,1088},{135 +,10,575},{133,11,589},{5,0,126},{8,0,297},{9,0,366},{140,0,374},{7,0,1551},{139, +0,361},{5,11,117},{6,11,514},{6,11,541},{7,11,1164},{7,11,1436},{8,11,220},{8,11 +,648},{10,11,688},{139,11,560},{133,11,686},{4,0,946},{6,0,1807},{8,0,871},{10,0 +,854},{10,0,870},{10,0,888},{10,0,897},{10,0,920},{12,0,722},{12,0,761},{12,0, +763},{12,0,764},{14,0,454},{14,0,465},{16,0,107},{18,0,167},{18,0,168},{146,0, +172},{132,0,175},{135,0,1307},{132,0,685},{135,11,1834},{133,0,797},{6,0,745},{6 +,0,858},{134,0,963},{133,0,565},{5,10,397},{6,10,154},{7,10,676},{7,11,196},{8, +10,443},{8,10,609},{9,10,24},{9,10,325},{10,10,35},{10,11,765},{11,10,535},{11, +10,672},{11,10,1018},{11,11,347},{11,11,552},{11,11,576},{11,11,790},{12,10,637} +,{12,11,263},{13,11,246},{13,11,270},{13,11,395},{14,11,74},{14,11,176},{14,11, +190},{14,11,398},{14,11,412},{15,11,32},{15,11,63},{16,10,30},{16,11,88},{147,11 +,105},{13,11,84},{141,11,122},{4,0,252},{7,0,1068},{10,0,434},{11,0,228},{11,0, +426},{13,0,231},{18,0,106},{148,0,87},{137,0,826},{4,11,589},{139,11,282},{5,11, +381},{135,11,1792},{132,0,791},{5,0,231},{5,10,981},{138,0,509},{7,0,601},{9,0, +277},{9,0,674},{10,0,178},{10,0,418},{10,0,571},{11,0,531},{12,0,113},{12,0,475} +,{13,0,99},{142,0,428},{4,10,56},{7,10,1791},{7,11,616},{8,10,607},{8,10,651},{ +10,11,413},{11,10,465},{11,10,835},{12,10,337},{141,10,480},{7,0,1591},{144,0,43 +},{9,10,158},{138,10,411},{135,0,1683},{8,0,289},{11,0,45},{12,0,278},{140,0,537 +},{6,11,120},{7,11,1188},{7,11,1710},{8,11,286},{9,11,667},{11,11,592},{139,11, +730},{136,10,617},{135,0,1120},{135,11,1146},{139,10,563},{4,10,369},{4,11,352}, +{135,11,687},{143,11,38},{4,0,399},{5,0,119},{5,0,494},{7,0,751},{9,0,556},{14, +11,179},{15,11,151},{150,11,11},{4,11,192},{5,11,49},{6,11,200},{6,11,293},{6,11 +,1696},{135,11,488},{4,0,398},{133,0,660},{6,10,622},{135,0,1030},{135,11,595},{ +141,0,168},{132,11,147},{7,0,973},{10,10,624},{142,10,279},{132,10,363},{132,0, +642},{133,11,934},{134,0,1615},{7,11,505},{135,11,523},{7,0,594},{7,0,851},{7,0, +1858},{9,0,411},{9,0,574},{9,0,666},{9,0,737},{10,0,346},{10,0,712},{11,0,246},{ +11,0,432},{11,0,517},{11,0,647},{11,0,679},{11,0,727},{12,0,304},{12,0,305},{12, +0,323},{12,0,483},{12,0,572},{12,0,593},{12,0,602},{13,0,95},{13,0,101},{13,0, +171},{13,0,315},{13,0,378},{13,0,425},{13,0,475},{14,0,63},{14,0,380},{14,0,384} +,{15,0,133},{18,0,112},{148,0,72},{135,0,1093},{132,0,679},{8,0,913},{10,0,903}, +{10,0,915},{10,11,438},{12,0,648},{12,0,649},{14,0,455},{144,0,112},{137,0,203}, +{134,10,292},{134,0,1492},{5,10,177},{6,10,616},{7,0,1374},{7,10,827},{8,0,540}, +{9,10,525},{138,10,656},{135,0,1486},{9,0,714},{138,10,31},{136,0,825},{134,0, +1511},{132,11,637},{134,0,952},{4,10,161},{133,10,631},{5,0,143},{5,0,769},{6,0, +1760},{7,0,682},{7,0,1992},{136,0,736},{132,0,700},{134,0,1540},{132,11,777},{9, +11,867},{138,11,837},{7,0,1557},{135,10,1684},{133,0,860},{6,0,422},{7,0,0},{7,0 +,1544},{9,0,605},{9,10,469},{9,10,709},{11,0,990},{12,0,235},{12,0,453},{12,10, +512},{13,0,47},{13,0,266},{14,10,65},{145,10,12},{10,10,229},{11,0,807},{11,10, +73},{139,10,376},{6,11,170},{7,11,1080},{8,11,395},{8,11,487},{11,11,125},{141, +11,147},{5,0,515},{137,0,131},{7,0,1605},{11,0,962},{146,0,139},{132,0,646},{4,0 +,396},{7,0,728},{9,0,117},{13,0,202},{148,0,51},{4,11,535},{6,0,121},{6,0,124},{ +6,0,357},{6,10,558},{7,0,1138},{7,0,1295},{7,10,651},{8,0,162},{8,0,508},{8,11, +618},{9,10,0},{10,10,34},{11,0,655},{139,10,1008},{135,11,1245},{138,0,357},{150 +,11,23},{133,0,237},{135,0,1784},{7,10,1832},{138,10,374},{132,0,713},{132,11,46 +},{5,11,811},{6,0,1536},{6,11,1679},{6,11,1714},{7,11,2032},{138,0,348},{11,11, +182},{142,11,195},{6,0,523},{7,0,738},{7,10,771},{7,10,1731},{9,10,405},{138,10, +421},{7,11,1458},{9,11,407},{139,11,15},{6,11,34},{7,11,69},{7,11,640},{7,11, +1089},{8,11,708},{8,11,721},{9,11,363},{9,11,643},{10,11,628},{148,11,98},{133,0 +,434},{135,0,1877},{7,0,571},{138,0,366},{5,10,881},{133,10,885},{9,0,513},{10,0 +,25},{10,0,39},{12,0,122},{140,0,187},{132,0,580},{5,10,142},{134,10,546},{132, +11,462},{137,0,873},{5,10,466},{11,10,571},{12,10,198},{13,10,283},{14,10,186},{ +15,10,21},{143,10,103},{4,10,185},{5,10,257},{5,10,839},{5,10,936},{7,0,171},{9, +10,399},{10,10,258},{10,10,395},{10,10,734},{11,10,1014},{12,10,23},{13,10,350}, +{14,10,150},{147,10,6},{134,0,625},{7,0,107},{7,0,838},{8,0,550},{138,0,401},{5, +11,73},{6,11,23},{134,11,338},{4,0,943},{6,0,1850},{12,0,713},{142,0,434},{7,10, +404},{7,10,1377},{7,10,1430},{7,10,2017},{8,10,149},{8,10,239},{8,10,512},{8,10, +793},{8,10,818},{9,10,474},{9,10,595},{10,10,122},{10,10,565},{10,10,649},{10,10 +,783},{11,0,588},{11,0,864},{11,0,936},{11,0,968},{11,10,239},{11,10,295},{11,10 +,447},{11,10,528},{11,10,639},{11,10,800},{12,0,73},{12,0,343},{12,0,394},{12,10 +,25},{12,10,157},{12,10,316},{12,10,390},{12,10,391},{12,10,395},{12,10,478},{12 +,10,503},{12,10,592},{12,10,680},{13,0,275},{13,10,50},{13,10,53},{13,10,132},{ +13,10,198},{13,10,322},{13,10,415},{13,10,511},{14,0,257},{14,10,71},{14,10,395} +,{15,0,160},{15,10,71},{15,10,136},{17,10,123},{18,10,93},{147,10,58},{133,0,768 +},{11,0,103},{142,0,0},{136,10,712},{132,0,799},{132,0,894},{7,11,725},{8,11,498 +},{139,11,268},{135,11,1798},{135,11,773},{141,11,360},{4,10,377},{152,10,13},{ +135,0,1673},{132,11,583},{134,0,1052},{133,11,220},{140,11,69},{132,11,544},{4, +10,180},{135,10,1906},{134,0,272},{4,0,441},{134,0,1421},{4,0,9},{5,0,128},{7,0, +368},{11,0,480},{148,0,3},{5,11,176},{6,11,437},{6,11,564},{11,11,181},{141,11, +183},{132,10,491},{7,0,1182},{141,11,67},{4,10,171},{6,0,1346},{138,10,234},{4, +10,586},{7,10,1186},{138,10,631},{136,0,682},{134,0,1004},{15,0,24},{143,11,24}, +{134,0,968},{4,0,2},{6,0,742},{6,0,793},{7,0,545},{7,0,894},{9,10,931},{10,10, +334},{148,10,71},{136,11,600},{133,10,765},{9,0,769},{140,0,185},{4,11,790},{5, +11,273},{134,11,394},{7,0,474},{137,0,578},{4,11,135},{6,11,127},{7,11,1185},{7, +11,1511},{8,11,613},{11,11,5},{12,11,133},{12,11,495},{12,11,586},{14,11,385},{ +15,11,118},{17,11,20},{146,11,98},{133,10,424},{5,0,530},{142,0,113},{6,11,230}, +{7,11,961},{7,11,1085},{136,11,462},{7,11,1954},{137,11,636},{136,10,714},{149, +11,6},{135,10,685},{9,10,420},{10,10,269},{10,10,285},{10,10,576},{11,10,397},{ +13,10,175},{145,10,90},{132,10,429},{5,0,556},{5,11,162},{136,11,68},{132,11,654 +},{4,11,156},{7,11,998},{7,11,1045},{7,11,1860},{9,11,48},{9,11,692},{11,11,419} +,{139,11,602},{6,0,1317},{7,11,1276},{8,0,16},{8,11,474},{9,0,825},{9,11,652},{ +140,0,568},{7,10,18},{7,10,699},{7,10,1966},{8,10,752},{9,10,273},{9,10,412},{9, +10,703},{10,10,71},{10,10,427},{10,10,508},{146,0,97},{7,11,1454},{10,0,703},{ +138,11,703},{4,10,53},{5,10,186},{135,10,752},{134,0,892},{134,0,1571},{8,10,575 +},{10,10,289},{139,10,319},{6,0,186},{137,0,426},{134,0,1101},{132,10,675},{132, +0,585},{6,0,1870},{137,0,937},{152,11,10},{9,11,197},{10,11,300},{12,11,473},{13 +,11,90},{141,11,405},{4,0,93},{5,0,252},{6,0,229},{7,0,291},{9,0,550},{139,0,644 +},{137,0,749},{6,10,209},{8,10,468},{9,0,162},{9,10,210},{11,10,36},{12,10,28},{ +12,10,630},{13,10,21},{13,10,349},{14,10,7},{145,10,13},{132,0,381},{132,11,606} +,{4,10,342},{135,10,1179},{7,11,1587},{7,11,1707},{10,11,528},{139,11,504},{12, +11,39},{13,11,265},{141,11,439},{4,10,928},{133,10,910},{7,10,1838},{7,11,1978}, +{136,11,676},{6,0,762},{6,0,796},{134,0,956},{4,10,318},{4,10,496},{7,10,856},{ +139,10,654},{137,11,242},{4,11,361},{133,11,315},{132,11,461},{132,11,472},{132, +0,857},{5,0,21},{6,0,77},{6,0,157},{7,0,974},{7,0,1301},{7,0,1339},{7,0,1490},{7 +,0,1873},{7,10,915},{8,10,247},{9,0,628},{147,10,0},{4,10,202},{5,10,382},{6,10, +454},{7,10,936},{7,10,1803},{8,10,758},{9,10,375},{9,10,895},{10,10,743},{10,10, +792},{11,10,978},{11,10,1012},{142,10,109},{7,11,617},{10,11,498},{11,11,501},{ +12,11,16},{140,11,150},{7,10,1150},{7,10,1425},{7,10,1453},{10,11,747},{140,10, +513},{133,11,155},{11,0,919},{141,0,409},{138,10,791},{10,0,633},{139,11,729},{7 +,11,163},{8,11,319},{9,11,402},{10,11,24},{10,11,681},{11,11,200},{11,11,567},{ +12,11,253},{12,11,410},{142,11,219},{5,11,475},{7,11,1780},{9,11,230},{11,11,297 +},{11,11,558},{14,11,322},{147,11,76},{6,10,445},{7,0,332},{137,10,909},{135,11, +1956},{136,11,274},{134,10,578},{135,0,1489},{135,11,1848},{5,11,944},{134,11, +1769},{132,11,144},{136,10,766},{4,0,832},{135,10,541},{8,0,398},{9,0,681},{139, +0,632},{136,0,645},{9,0,791},{10,0,93},{16,0,13},{17,0,23},{18,0,135},{19,0,12}, +{20,0,1},{20,0,12},{148,0,14},{6,11,247},{137,11,555},{134,0,20},{132,0,800},{ +135,0,1841},{139,10,983},{137,10,768},{132,10,584},{141,11,51},{4,11,620},{6,0, +1993},{138,11,280},{136,0,769},{7,11,1810},{11,0,290},{11,0,665},{11,11,866},{12 +,11,103},{13,11,495},{17,11,67},{147,11,74},{134,0,1426},{139,0,60},{4,10,326},{ +135,10,1770},{4,10,226},{7,0,1874},{137,0,641},{5,10,426},{6,0,644},{8,10,30},{9 +,10,2},{11,10,549},{147,10,122},{5,11,428},{138,11,442},{135,11,1871},{135,0, +1757},{147,10,117},{135,0,937},{135,0,1652},{6,0,654},{134,0,1476},{133,11,99},{ +135,0,527},{132,10,345},{4,10,385},{4,11,397},{7,10,265},{135,10,587},{4,0,579}, +{5,0,226},{5,0,323},{135,0,960},{134,0,1486},{8,11,502},{144,11,9},{4,10,347},{5 +,10,423},{5,10,996},{135,10,1329},{7,11,727},{146,11,73},{4,11,485},{7,10,1259}, +{7,11,353},{7,11,1523},{9,10,125},{139,10,65},{5,10,136},{6,0,325},{6,11,366},{7 +,11,1384},{7,11,1601},{136,10,644},{138,11,160},{6,0,1345},{137,11,282},{18,0,91 +},{147,0,70},{136,0,404},{4,11,157},{133,11,471},{133,0,973},{6,0,135},{135,0, +1176},{8,11,116},{11,11,551},{142,11,159},{4,0,549},{4,10,433},{133,10,719},{136 +,0,976},{5,11,160},{7,11,363},{7,11,589},{10,11,170},{141,11,55},{144,0,21},{144 +,0,51},{135,0,314},{135,10,1363},{4,11,108},{7,11,405},{10,11,491},{139,11,498}, +{146,0,4},{4,10,555},{8,10,536},{10,10,288},{139,10,1005},{135,11,1005},{6,0,281 +},{7,0,6},{8,0,282},{8,0,480},{8,0,499},{9,0,198},{10,0,143},{10,0,169},{10,0, +211},{10,0,417},{10,0,574},{11,0,147},{11,0,395},{12,0,75},{12,0,407},{12,0,608} +,{13,0,500},{142,0,251},{6,0,1093},{6,0,1405},{9,10,370},{138,10,90},{4,11,926}, +{133,11,983},{135,0,1776},{134,0,1528},{132,0,419},{132,11,538},{6,11,294},{7,11 +,1267},{136,11,624},{135,11,1772},{138,11,301},{4,10,257},{135,10,2031},{4,0,138 +},{7,0,1012},{7,0,1280},{7,10,1768},{137,0,76},{132,11,757},{5,0,29},{140,0,638} +,{7,11,655},{135,11,1844},{6,11,257},{7,0,1418},{135,11,1522},{8,11,469},{138,11 +,47},{142,11,278},{6,10,83},{6,10,1733},{135,10,1389},{11,11,204},{11,11,243},{ +140,11,293},{135,11,1875},{6,0,1710},{135,0,2038},{137,11,299},{4,0,17},{5,0,23} +,{7,0,995},{11,0,383},{11,0,437},{12,0,460},{140,0,532},{133,0,862},{137,10,696} +,{6,0,592},{138,0,946},{138,11,599},{7,10,1718},{9,10,95},{9,10,274},{10,10,279} +,{10,10,317},{10,10,420},{11,10,303},{11,10,808},{12,10,134},{12,10,367},{13,10, +149},{13,10,347},{14,10,349},{14,10,406},{18,10,22},{18,10,89},{18,10,122},{147, +10,47},{8,0,70},{12,0,171},{141,0,272},{133,10,26},{132,10,550},{137,0,812},{10, +0,233},{139,0,76},{134,0,988},{134,0,442},{136,10,822},{4,10,902},{5,10,809},{6, +10,122},{135,0,896},{5,11,150},{7,11,106},{8,11,603},{9,11,593},{9,11,634},{10, +11,44},{10,11,173},{11,11,462},{11,11,515},{13,11,216},{13,11,288},{142,11,400}, +{136,0,483},{135,10,262},{5,10,620},{134,0,1709},{4,10,34},{5,10,574},{7,10,279} +,{7,10,1624},{136,10,601},{137,10,170},{147,0,119},{12,11,108},{141,11,291},{11, +0,69},{12,0,105},{12,0,117},{13,0,213},{14,0,13},{14,0,62},{14,0,177},{14,0,421} +,{15,0,19},{146,0,141},{137,0,309},{11,11,278},{142,11,73},{7,0,608},{7,0,976},{ +9,0,146},{10,0,206},{10,0,596},{13,0,218},{142,0,153},{133,10,332},{6,10,261},{8 +,10,182},{139,10,943},{4,11,493},{144,11,55},{134,10,1721},{132,0,768},{4,10,933 +},{133,10,880},{7,11,555},{7,11,1316},{7,11,1412},{7,11,1839},{9,11,192},{9,11, +589},{11,11,241},{11,11,676},{11,11,811},{11,11,891},{12,11,140},{12,11,346},{12 +,11,479},{13,11,30},{13,11,49},{13,11,381},{14,11,188},{15,11,150},{16,11,76},{ +18,11,30},{148,11,52},{4,0,518},{135,0,1136},{6,11,568},{7,11,112},{7,11,1804},{ +8,11,362},{8,11,410},{8,11,830},{9,11,514},{11,11,649},{142,11,157},{135,11,673} +,{8,0,689},{137,0,863},{4,0,18},{4,11,625},{7,0,145},{7,0,444},{7,0,1278},{8,0, +49},{8,0,400},{9,0,71},{9,0,250},{10,0,459},{12,0,160},{144,0,24},{140,0,1020},{ +4,0,997},{6,0,1946},{6,0,1984},{134,0,1998},{6,11,16},{6,11,158},{7,11,43},{7,11 +,129},{7,11,181},{8,11,276},{8,11,377},{10,11,523},{11,11,816},{12,11,455},{13, +11,303},{142,11,135},{133,10,812},{134,0,658},{4,11,1},{7,11,1143},{7,11,1463},{ +8,11,61},{9,11,207},{9,11,390},{9,11,467},{139,11,836},{150,11,26},{140,0,106},{ +4,10,137},{6,0,1827},{7,10,1178},{7,10,1520},{7,11,1319},{10,0,931},{18,0,166},{ +148,0,114},{133,0,1010},{4,11,723},{5,11,895},{7,11,1031},{8,11,199},{8,11,340}, +{9,11,153},{9,11,215},{10,11,21},{10,11,59},{10,11,80},{10,11,224},{11,11,229},{ +11,11,652},{12,11,192},{13,11,146},{142,11,91},{132,11,295},{6,11,619},{7,11,898 +},{7,11,1092},{8,11,485},{18,11,28},{147,11,116},{137,11,51},{6,10,1661},{7,10, +1975},{7,10,2009},{135,10,2011},{5,11,309},{140,11,211},{5,0,87},{7,0,313},{7,0, +1103},{10,0,208},{10,0,582},{11,0,389},{11,0,813},{12,0,385},{13,0,286},{14,0, +124},{146,0,108},{5,11,125},{8,11,77},{138,11,15},{132,0,267},{133,0,703},{137, +11,155},{133,11,439},{11,11,164},{140,11,76},{5,10,89},{7,10,1915},{9,0,496},{9, +10,185},{9,10,235},{10,10,64},{10,10,270},{10,10,403},{10,10,469},{10,10,529},{ +10,10,590},{11,10,140},{11,10,860},{13,10,1},{13,10,422},{14,10,341},{14,10,364} +,{17,10,93},{18,10,113},{19,10,97},{147,10,113},{133,10,695},{135,0,1121},{5,10, +6},{6,10,183},{7,10,680},{7,10,978},{7,10,1013},{7,10,1055},{12,10,230},{13,10, +172},{146,10,29},{4,11,8},{7,11,1152},{7,11,1153},{7,11,1715},{9,11,374},{10,11, +478},{139,11,648},{135,11,1099},{6,10,29},{139,10,63},{4,0,561},{10,0,249},{139, +0,209},{132,0,760},{7,11,799},{138,11,511},{136,11,87},{9,0,154},{140,0,485},{ +136,0,255},{132,0,323},{140,0,419},{132,10,311},{134,10,1740},{4,0,368},{135,0, +641},{7,10,170},{8,10,90},{8,10,177},{8,10,415},{11,10,714},{142,10,281},{4,11, +69},{5,11,122},{9,11,656},{138,11,464},{5,11,849},{134,11,1633},{8,0,522},{142,0 +,328},{11,10,91},{13,10,129},{15,10,101},{145,10,125},{4,10,494},{6,10,74},{7,0, +562},{7,10,44},{8,0,551},{11,11,499},{12,10,17},{15,10,5},{148,10,11},{4,10,276} +,{133,10,296},{9,0,92},{147,0,91},{4,10,7},{5,10,90},{5,10,158},{6,10,542},{7,10 +,221},{7,10,1574},{9,10,490},{10,10,540},{11,10,443},{139,10,757},{6,0,525},{6,0 +,1976},{8,0,806},{9,0,876},{140,0,284},{5,11,859},{7,10,588},{7,11,1160},{8,11, +107},{9,10,175},{9,11,291},{9,11,439},{10,10,530},{10,11,663},{11,11,609},{140, +11,197},{7,11,168},{13,11,196},{141,11,237},{139,0,958},{133,0,594},{135,10,580} +,{7,10,88},{136,10,627},{5,10,872},{6,0,479},{6,0,562},{6,10,57},{7,0,1060},{7, +10,471},{9,10,447},{9,10,454},{141,0,6},{136,11,413},{145,11,19},{4,11,117},{6, +11,372},{7,11,1905},{142,11,323},{4,11,722},{139,11,471},{5,10,31},{6,10,614},{ +145,0,61},{8,10,330},{140,10,477},{7,10,1200},{138,10,460},{6,10,424},{135,10, +1866},{6,0,1641},{136,0,820},{6,0,1556},{134,0,1618},{9,11,5},{12,11,216},{12,11 +,294},{12,11,298},{12,11,400},{12,11,518},{13,11,229},{143,11,139},{15,11,155},{ +144,11,79},{4,0,302},{135,0,1766},{5,10,13},{134,10,142},{6,0,148},{7,0,1313},{7 +,10,116},{8,10,322},{8,10,755},{9,10,548},{10,10,714},{11,10,884},{141,10,324},{ +137,0,676},{9,11,88},{139,11,270},{5,11,12},{7,11,375},{137,11,438},{134,0,1674} +,{7,10,1472},{135,10,1554},{7,10,1071},{7,10,1541},{7,10,1767},{7,10,1806},{11,0 +,178},{11,10,162},{11,10,242},{12,10,605},{15,10,26},{144,10,44},{6,0,389},{7,0, +149},{9,0,142},{138,0,94},{140,11,71},{145,10,115},{6,0,8},{7,0,1881},{8,0,91},{ +11,11,966},{12,11,287},{13,11,342},{13,11,402},{15,11,110},{143,11,163},{4,11, +258},{136,11,639},{6,11,22},{7,11,903},{138,11,577},{133,11,681},{135,10,1111},{ +135,11,1286},{8,10,1},{9,0,112},{138,10,326},{5,10,488},{6,10,527},{7,10,489},{7 +,10,1636},{8,10,121},{8,10,144},{8,10,359},{9,10,193},{9,10,241},{9,10,336},{9, +10,882},{11,10,266},{11,10,372},{11,10,944},{12,10,401},{140,10,641},{4,11,664}, +{133,11,804},{6,0,747},{134,0,1015},{135,0,1746},{9,10,31},{10,10,244},{10,10, +699},{12,10,149},{141,10,497},{133,10,377},{135,0,24},{5,11,32},{6,0,1352},{145, +10,101},{7,0,1530},{10,0,158},{13,0,13},{13,0,137},{13,0,258},{14,0,111},{14,0, +225},{14,0,253},{14,0,304},{14,0,339},{14,0,417},{146,0,33},{4,0,503},{135,0, +1661},{5,0,130},{6,0,845},{7,0,1314},{9,0,610},{10,0,718},{11,0,601},{11,0,819}, +{11,0,946},{140,0,536},{10,0,149},{11,0,280},{142,0,336},{134,0,1401},{135,0, +1946},{8,0,663},{144,0,8},{134,0,1607},{135,10,2023},{4,11,289},{7,11,629},{7,11 +,1698},{7,11,1711},{140,11,215},{6,11,450},{136,11,109},{10,0,882},{10,0,883},{ +10,0,914},{138,0,928},{133,10,843},{136,11,705},{132,10,554},{133,10,536},{5,0, +417},{9,10,79},{11,10,625},{145,10,7},{7,11,1238},{142,11,37},{4,0,392},{135,0, +1597},{4,10,424},{5,0,433},{9,0,633},{139,0,629},{7,10,336},{136,10,785},{134,11 +,355},{6,0,234},{7,0,769},{9,0,18},{138,0,358},{4,10,896},{134,10,1777},{138,11, +323},{7,0,140},{7,0,1950},{8,0,680},{11,0,817},{147,0,88},{7,0,1222},{138,0,386} +,{139,11,908},{11,0,249},{12,0,313},{16,0,66},{145,0,26},{134,0,5},{7,10,750},{9 +,10,223},{11,10,27},{11,10,466},{12,10,624},{14,10,265},{146,10,61},{134,11,26}, +{134,0,1216},{5,0,963},{134,0,1773},{4,11,414},{5,11,467},{9,11,654},{10,11,451} +,{12,11,59},{141,11,375},{135,11,17},{4,10,603},{133,10,661},{4,10,11},{6,10,128 +},{7,10,231},{7,10,1533},{138,10,725},{135,11,955},{7,0,180},{8,0,509},{136,0, +792},{132,10,476},{132,0,1002},{133,11,538},{135,10,1807},{132,0,931},{7,0,943}, +{11,0,614},{140,0,747},{135,0,1837},{9,10,20},{10,10,324},{10,10,807},{139,10, +488},{134,0,641},{6,11,280},{10,11,502},{11,11,344},{140,11,38},{5,11,45},{7,11, +1161},{11,11,448},{11,11,880},{13,11,139},{13,11,407},{15,11,16},{17,11,95},{18, +11,66},{18,11,88},{18,11,123},{149,11,7},{9,0,280},{138,0,134},{22,0,22},{23,0,5 +},{151,0,29},{136,11,777},{4,0,90},{4,11,410},{5,0,545},{7,0,754},{7,11,521},{9, +0,186},{10,0,72},{10,0,782},{11,0,577},{11,0,610},{11,0,960},{12,0,354},{12,0, +362},{140,0,595},{135,11,1778},{5,10,112},{6,10,103},{134,10,150},{138,10,356},{ +132,0,742},{7,0,151},{9,0,329},{139,0,254},{8,0,853},{8,0,881},{8,0,911},{8,0, +912},{10,0,872},{12,0,741},{12,0,742},{152,0,18},{4,11,573},{136,11,655},{6,0, +921},{134,0,934},{9,0,187},{10,0,36},{11,0,1016},{17,0,44},{146,0,64},{7,0,833}, +{136,0,517},{4,0,506},{5,0,295},{135,0,1680},{4,10,708},{8,10,15},{9,10,50},{9, +10,386},{11,10,18},{11,10,529},{140,10,228},{4,10,563},{7,0,251},{7,0,1701},{7, +10,592},{7,10,637},{7,10,770},{8,0,436},{8,10,463},{9,10,60},{9,10,335},{9,10, +904},{10,10,73},{11,10,434},{12,10,585},{13,10,331},{18,10,110},{148,10,60},{132 +,10,502},{136,0,584},{6,10,347},{138,10,161},{7,0,987},{7,11,899},{9,0,688},{10, +0,522},{11,0,788},{12,0,137},{12,0,566},{14,0,9},{14,0,24},{14,0,64},{142,11,325 +},{4,0,214},{5,0,500},{5,10,102},{6,10,284},{7,10,1079},{7,10,1423},{7,10,1702}, +{8,10,470},{9,10,554},{9,10,723},{139,10,333},{7,10,246},{135,10,840},{6,10,10}, +{8,10,571},{9,10,739},{143,10,91},{133,10,626},{146,0,195},{134,0,1775},{7,0,389 +},{7,0,700},{7,0,940},{8,0,514},{9,0,116},{9,0,535},{10,0,118},{11,0,107},{11,0, +148},{11,0,922},{12,0,254},{12,0,421},{142,0,238},{5,10,18},{6,10,526},{13,10,24 +},{13,10,110},{19,10,5},{147,10,44},{132,0,743},{4,10,309},{5,10,462},{7,10,970} +,{7,10,1097},{139,0,292},{22,10,30},{150,10,33},{139,11,338},{135,11,1598},{7,0, +1283},{9,0,227},{11,0,325},{11,0,408},{14,0,180},{146,0,47},{4,0,953},{6,0,1805} +,{6,0,1814},{6,0,1862},{140,0,774},{6,11,611},{135,11,1733},{135,11,1464},{5,0, +81},{7,0,146},{7,0,1342},{8,0,53},{8,0,561},{8,0,694},{8,0,754},{9,0,115},{9,0, +179},{9,0,894},{10,0,462},{10,0,813},{11,0,230},{11,0,657},{11,0,699},{11,0,748} +,{12,0,119},{12,0,200},{12,0,283},{142,0,273},{5,0,408},{6,0,789},{6,0,877},{6,0 +,1253},{6,0,1413},{137,0,747},{134,10,1704},{135,11,663},{6,0,1910},{6,0,1915},{ +6,0,1923},{9,0,913},{9,0,928},{9,0,950},{9,0,954},{9,0,978},{9,0,993},{12,0,812} +,{12,0,819},{12,0,831},{12,0,833},{12,0,838},{12,0,909},{12,0,928},{12,0,931},{ +12,0,950},{15,0,186},{15,0,187},{15,0,195},{15,0,196},{15,0,209},{15,0,215},{15, +0,236},{15,0,241},{15,0,249},{15,0,253},{18,0,180},{18,0,221},{18,0,224},{18,0, +227},{18,0,229},{149,0,60},{7,0,1826},{135,0,1938},{5,10,86},{7,10,743},{9,10,85 +},{10,10,281},{10,10,432},{11,0,490},{12,10,251},{13,10,118},{14,10,378},{146,0, +143},{5,10,524},{133,10,744},{141,11,442},{10,10,107},{140,10,436},{135,11,503}, +{134,0,1162},{132,10,927},{7,0,30},{8,0,86},{8,0,315},{8,0,700},{9,0,576},{9,0, +858},{10,0,414},{11,0,310},{11,0,888},{11,0,904},{12,0,361},{12,10,670},{13,0, +248},{13,0,371},{14,0,142},{146,10,94},{134,0,721},{4,11,113},{5,11,163},{5,11, +735},{7,10,1149},{7,11,1009},{9,10,156},{9,11,9},{9,11,771},{12,11,90},{13,11, +138},{13,11,410},{143,11,128},{138,0,839},{133,10,778},{137,0,617},{133,10,502}, +{8,10,196},{10,10,283},{139,10,406},{6,0,428},{7,0,524},{8,0,169},{8,0,234},{9,0 +,480},{138,0,646},{133,10,855},{134,0,1648},{7,0,1205},{138,0,637},{4,11,935},{5 +,11,823},{135,0,1596},{5,11,269},{7,11,434},{7,11,891},{8,11,339},{9,11,702},{11 +,11,594},{11,11,718},{145,11,100},{7,11,878},{9,11,485},{141,11,264},{4,0,266},{ +6,11,1713},{8,0,4},{9,0,39},{10,0,166},{11,0,918},{12,0,635},{20,0,10},{22,0,27} +,{22,0,43},{150,0,52},{7,10,1400},{9,10,446},{138,10,45},{135,11,900},{132,0,862 +},{134,0,1554},{135,11,1033},{19,0,16},{147,11,16},{135,11,1208},{7,0,157},{136, +0,279},{6,0,604},{136,0,391},{13,10,455},{15,10,99},{15,10,129},{144,10,68},{135 +,10,172},{7,0,945},{11,0,713},{139,0,744},{4,0,973},{10,0,877},{10,0,937},{10,0, +938},{140,0,711},{139,0,1022},{132,10,568},{142,11,143},{4,0,567},{4,10,732},{ +137,0,859},{7,0,1846},{136,0,628},{136,10,733},{133,0,762},{4,10,428},{135,10, +1789},{7,10,2015},{10,0,784},{12,10,665},{141,0,191},{133,0,298},{7,0,633},{7,0, +905},{7,0,909},{7,0,1538},{9,0,767},{140,0,636},{138,10,806},{132,0,795},{139,0, +301},{135,0,1970},{5,11,625},{135,11,1617},{135,11,275},{7,11,37},{8,11,425},{8, +11,693},{9,11,720},{10,11,380},{10,11,638},{11,11,273},{11,11,307},{11,11,473},{ +12,11,61},{143,11,43},{135,11,198},{134,0,1236},{7,0,369},{12,0,644},{12,0,645}, +{144,0,90},{19,0,15},{149,0,27},{6,0,71},{6,10,1623},{6,10,1681},{7,0,845},{8,0, +160},{137,0,318},{134,0,1447},{134,0,1255},{138,0,735},{4,11,168},{136,0,76},{6, +10,1748},{8,10,715},{9,10,802},{10,10,46},{10,10,819},{13,10,308},{14,10,351},{ +14,10,363},{146,10,67},{135,11,91},{4,10,63},{5,10,347},{134,0,474},{133,10,749} +,{138,0,841},{133,10,366},{4,11,225},{134,0,836},{135,0,1622},{135,10,89},{140,0 +,735},{134,0,1601},{138,11,145},{6,0,1390},{137,0,804},{142,0,394},{6,11,15},{7, +11,70},{10,11,240},{147,11,93},{6,0,96},{135,0,1426},{4,0,651},{133,0,289},{7,10 +,977},{7,11,956},{7,11,1157},{7,11,1506},{7,11,1606},{7,11,1615},{7,11,1619},{7, +11,1736},{7,11,1775},{8,11,590},{9,11,324},{9,11,736},{9,11,774},{9,11,776},{9, +11,784},{10,11,567},{10,11,708},{11,11,518},{11,11,613},{11,11,695},{11,11,716}, +{11,11,739},{11,11,770},{11,11,771},{11,11,848},{11,11,857},{11,11,931},{11,11, +947},{12,11,326},{12,11,387},{12,11,484},{12,11,528},{12,11,552},{12,11,613},{13 +,11,189},{13,11,256},{13,11,340},{13,11,432},{13,11,436},{13,11,440},{13,11,454} +,{14,11,174},{14,11,220},{14,11,284},{14,11,390},{145,11,121},{7,0,688},{8,0,35} +,{9,0,511},{10,0,767},{147,0,118},{134,0,667},{4,0,513},{5,10,824},{133,10,941}, +{7,10,440},{8,10,230},{139,10,106},{134,0,2034},{135,11,1399},{143,11,66},{135, +11,1529},{4,11,145},{6,11,176},{7,11,395},{9,11,562},{144,11,28},{132,11,501},{ +132,0,704},{134,0,1524},{6,11,464},{135,0,1078},{6,11,509},{10,11,82},{20,11,91} +,{151,11,13},{4,0,720},{133,0,306},{133,0,431},{4,10,914},{5,10,800},{5,10,852}, +{135,0,1196},{135,11,1189},{10,0,54},{141,10,115},{7,10,564},{142,10,168},{4,10, +918},{5,0,464},{5,10,876},{6,0,236},{7,0,696},{7,0,914},{7,0,1108},{7,0,1448},{9 +,0,15},{9,0,564},{10,0,14},{12,0,565},{13,0,449},{14,0,53},{15,0,13},{16,0,64},{ +145,0,41},{6,0,1418},{134,10,1764},{4,10,92},{133,10,274},{134,0,907},{4,11,114} +,{8,10,501},{9,11,492},{13,11,462},{142,11,215},{4,11,77},{5,11,361},{6,11,139}, +{6,11,401},{6,11,404},{7,11,413},{7,11,715},{7,11,1716},{11,11,279},{12,11,179}, +{12,11,258},{13,11,244},{142,11,358},{6,0,1767},{12,0,194},{145,0,107},{134,11, +1717},{5,10,743},{142,11,329},{4,10,49},{7,10,280},{135,10,1633},{5,0,840},{7,11 +,1061},{8,11,82},{11,11,250},{12,11,420},{141,11,184},{135,11,724},{134,0,900},{ +136,10,47},{134,0,1436},{144,11,0},{5,10,272},{5,10,908},{5,10,942},{6,0,675},{7 +,0,1008},{7,0,1560},{8,10,197},{9,0,642},{9,10,47},{11,0,236},{11,10,538},{11,10 +,742},{142,0,193},{4,0,68},{5,0,628},{5,0,634},{6,0,386},{7,0,794},{8,0,273},{9, +0,563},{10,0,105},{10,0,171},{11,0,94},{139,0,354},{135,10,1911},{137,10,891},{4 +,0,95},{6,0,1297},{6,0,1604},{7,0,416},{139,0,830},{6,11,513},{135,11,1052},{7,0 +,731},{13,0,20},{143,0,11},{137,11,899},{10,0,850},{140,0,697},{4,0,662},{7,11, +1417},{12,11,382},{17,11,48},{152,11,12},{133,0,736},{132,0,861},{4,10,407},{132 +,10,560},{141,10,490},{6,11,545},{7,11,565},{7,11,1669},{10,11,114},{11,11,642}, +{140,11,618},{6,0,871},{134,0,1000},{5,0,864},{5,11,5},{10,0,648},{11,0,671},{ +143,0,46},{133,0,928},{4,10,475},{11,0,90},{11,10,35},{13,0,7},{13,10,71},{13,10 +,177},{142,10,422},{136,0,332},{135,11,192},{134,0,1055},{136,11,763},{11,0,986} +,{140,0,682},{7,0,76},{8,0,44},{9,0,884},{10,0,580},{11,0,399},{11,0,894},{143,0 +,122},{135,11,1237},{135,10,636},{6,10,222},{7,10,1620},{8,10,409},{9,10,693},{ +139,0,300},{4,11,87},{5,11,250},{10,11,601},{13,11,298},{13,11,353},{141,11,376} +,{5,0,518},{10,0,340},{11,0,175},{149,0,16},{140,0,771},{6,0,1108},{137,0,831},{ +132,0,836},{135,0,1852},{4,0,957},{6,0,1804},{8,0,842},{8,0,843},{8,0,851},{8,0, +855},{140,0,767},{135,11,814},{4,11,57},{7,11,1195},{7,11,1438},{7,11,1548},{7, +11,1835},{7,11,1904},{9,11,757},{10,11,604},{139,11,519},{133,10,882},{138,0,246 +},{4,0,934},{5,0,202},{7,11,1897},{8,0,610},{12,11,290},{13,11,80},{13,11,437},{ +145,11,74},{8,0,96},{9,0,36},{10,0,607},{10,0,804},{10,0,832},{11,0,423},{11,0, +442},{12,0,309},{14,0,199},{15,0,90},{145,0,110},{132,10,426},{6,10,58},{7,0,654 +},{7,10,745},{7,10,1969},{8,0,240},{8,10,675},{9,10,479},{9,10,731},{10,10,330}, +{10,10,593},{10,10,817},{11,10,32},{11,10,133},{11,10,221},{145,10,68},{9,0,13}, +{9,0,398},{9,0,727},{10,0,75},{10,0,184},{10,0,230},{10,0,564},{10,0,569},{11,0, +973},{12,0,70},{12,0,189},{13,0,57},{141,0,257},{4,11,209},{135,11,902},{7,0,391 +},{137,10,538},{134,0,403},{6,11,303},{7,11,335},{7,11,1437},{7,11,1668},{8,11, +553},{8,11,652},{8,11,656},{9,11,558},{11,11,743},{149,11,18},{132,11,559},{11,0 +,75},{142,0,267},{6,0,815},{141,11,2},{141,0,366},{137,0,631},{133,11,1017},{5,0 +,345},{135,0,1016},{133,11,709},{134,11,1745},{133,10,566},{6,10,48},{7,0,952},{ +9,10,139},{10,10,399},{11,10,469},{12,10,634},{141,10,223},{133,0,673},{7,11,8}, +{8,11,206},{137,0,850},{6,0,662},{149,0,35},{4,0,287},{133,0,1018},{6,10,114},{7 +,10,1224},{7,10,1556},{136,10,3},{8,10,576},{137,10,267},{4,0,884},{5,0,34},{10, +0,724},{12,0,444},{13,0,354},{18,0,32},{23,0,24},{23,0,31},{152,0,5},{133,10,933 +},{132,11,776},{138,0,151},{136,0,427},{134,0,382},{132,0,329},{9,0,846},{10,0, +827},{138,11,33},{7,11,1297},{9,0,279},{10,0,407},{14,0,84},{150,0,18},{136,11, +406},{132,0,906},{136,0,366},{134,0,843},{134,0,1443},{135,0,1372},{138,0,992},{ +4,0,123},{5,0,605},{7,0,1509},{136,0,36},{132,0,649},{8,11,175},{10,11,168},{138 +,11,573},{133,0,767},{134,0,1018},{135,11,1305},{12,10,30},{13,10,148},{14,10,87 +},{14,10,182},{16,10,42},{148,10,70},{134,11,607},{4,0,273},{5,0,658},{133,0,995 +},{6,0,72},{139,11,174},{7,10,56},{7,10,1989},{8,10,337},{8,10,738},{9,10,600},{ +10,0,483},{12,0,368},{13,10,447},{142,10,92},{5,11,784},{138,10,666},{135,0,1345 +},{139,11,882},{134,0,1293},{133,0,589},{134,0,1988},{5,0,117},{6,0,514},{6,0, +541},{7,0,1164},{7,0,1436},{8,0,220},{8,0,648},{10,0,688},{139,0,560},{136,0,379 +},{5,0,686},{7,10,866},{135,10,1163},{132,10,328},{9,11,14},{9,11,441},{10,11, +306},{139,11,9},{4,10,101},{135,10,1171},{5,10,833},{136,10,744},{5,11,161},{7, +11,839},{135,11,887},{7,0,196},{10,0,765},{11,0,347},{11,0,552},{11,0,790},{12,0 +,263},{13,0,246},{13,0,270},{13,0,395},{14,0,176},{14,0,190},{14,0,398},{14,0, +412},{15,0,32},{15,0,63},{16,0,88},{147,0,105},{6,10,9},{6,10,397},{7,10,53},{7, +10,1742},{10,10,632},{11,10,828},{140,10,146},{5,0,381},{135,0,1792},{134,0,1452 +},{135,11,429},{8,0,367},{10,0,760},{14,0,79},{20,0,17},{152,0,0},{7,0,616},{138 +,0,413},{11,10,417},{12,10,223},{140,10,265},{7,11,1611},{13,11,14},{15,11,44},{ +19,11,13},{148,11,76},{135,0,1229},{6,0,120},{7,0,1188},{7,0,1710},{8,0,286},{9, +0,667},{11,0,592},{139,0,730},{135,11,1814},{135,0,1146},{4,10,186},{5,10,157},{ +8,10,168},{138,10,6},{4,0,352},{135,0,687},{4,0,192},{5,0,49},{6,0,200},{6,0,293 +},{6,0,1696},{135,0,1151},{133,10,875},{5,10,773},{5,10,991},{6,10,1635},{134,10 +,1788},{7,10,111},{136,10,581},{6,0,935},{134,0,1151},{134,0,1050},{132,0,650},{ +132,0,147},{11,0,194},{11,11,194},{12,0,62},{12,0,88},{12,11,62},{140,11,88},{6, +0,339},{135,0,923},{134,10,1747},{7,11,643},{136,11,236},{133,0,934},{7,10,1364} +,{7,10,1907},{141,10,158},{132,10,659},{4,10,404},{135,10,675},{7,11,581},{9,11, +644},{137,11,699},{13,0,211},{14,0,133},{14,0,204},{15,0,64},{15,0,69},{15,0,114 +},{16,0,10},{19,0,23},{19,0,35},{19,0,39},{19,0,51},{19,0,71},{19,0,75},{152,0, +15},{133,10,391},{5,11,54},{135,11,1513},{5,10,540},{6,10,1697},{7,0,222},{136,0 +,341},{134,10,78},{132,11,744},{136,0,293},{137,11,701},{7,11,930},{10,11,402},{ +10,11,476},{13,11,452},{18,11,55},{147,11,104},{132,0,637},{133,10,460},{8,11,50 +},{137,11,624},{132,11,572},{134,0,1159},{4,10,199},{139,10,34},{134,0,847},{134 +,10,388},{6,11,43},{7,11,38},{8,11,248},{9,11,504},{138,11,513},{4,10,511},{6,10 +,608},{9,0,683},{9,10,333},{10,10,602},{11,10,441},{11,10,723},{11,10,976},{140, +10,357},{9,0,867},{138,0,837},{6,0,944},{135,11,326},{135,0,1809},{5,10,938},{7, +11,783},{136,10,707},{133,11,766},{133,11,363},{6,0,170},{7,0,1080},{8,0,395},{8 +,0,487},{141,0,147},{6,11,258},{140,11,409},{4,0,535},{5,11,249},{8,0,618},{148, +11,82},{6,0,1379},{149,11,15},{135,0,1625},{150,0,23},{5,11,393},{6,11,378},{7, +11,1981},{9,11,32},{9,11,591},{10,11,685},{10,11,741},{142,11,382},{133,11,788}, +{7,11,1968},{10,11,19},{139,11,911},{7,11,1401},{135,11,1476},{4,11,61},{5,11,58 +},{5,11,171},{5,11,635},{5,11,683},{5,11,700},{6,11,291},{6,11,566},{7,11,1650}, +{11,11,523},{12,11,273},{12,11,303},{15,11,39},{143,11,111},{6,10,469},{7,10, +1709},{138,10,515},{4,0,778},{134,11,589},{132,0,46},{5,0,811},{6,0,1679},{6,0, +1714},{135,0,2032},{7,0,1458},{9,0,407},{11,0,15},{12,0,651},{149,0,37},{4,10, +500},{135,0,938},{6,0,34},{7,0,69},{7,0,1089},{7,0,1281},{8,0,708},{8,0,721},{9, +0,363},{148,0,98},{10,11,231},{147,11,124},{7,11,726},{152,11,9},{5,10,68},{134, +10,383},{136,11,583},{4,11,917},{133,11,1005},{11,10,216},{139,10,340},{135,11, +1675},{8,0,441},{10,0,314},{143,0,3},{132,11,919},{4,10,337},{6,10,353},{7,10, +1934},{8,10,488},{137,10,429},{7,0,889},{7,10,1795},{8,10,259},{9,10,135},{9,10, +177},{9,10,860},{10,10,825},{11,10,115},{11,10,370},{11,10,405},{11,10,604},{12, +10,10},{12,10,667},{12,10,669},{13,10,76},{14,10,310},{15,10,76},{15,10,147},{ +148,10,23},{4,10,15},{4,11,255},{5,10,22},{5,11,302},{6,10,244},{6,11,132},{7,10 +,40},{7,10,200},{7,10,906},{7,10,1199},{7,11,128},{7,11,283},{7,11,1299},{9,10, +616},{10,10,716},{10,11,52},{10,11,514},{11,10,635},{11,10,801},{11,11,925},{12, +10,458},{13,11,92},{142,11,309},{132,0,462},{137,11,173},{135,10,1735},{5,10,598 +},{7,10,791},{8,0,525},{8,10,108},{137,10,123},{5,0,73},{6,0,23},{134,0,338},{ +132,0,676},{132,10,683},{7,0,725},{8,0,498},{139,0,268},{12,0,21},{151,0,7},{135 +,0,773},{4,10,155},{135,10,1689},{4,0,164},{5,0,730},{5,10,151},{5,10,741},{6,11 +,210},{7,10,498},{7,10,870},{7,10,1542},{12,10,213},{14,10,36},{14,10,391},{17, +10,111},{18,10,6},{18,10,46},{18,10,151},{19,10,36},{20,10,32},{20,10,56},{20,10 +,69},{20,10,102},{21,10,4},{22,10,8},{22,10,10},{22,10,14},{150,10,31},{4,10,624 +},{135,10,1752},{4,0,583},{6,11,588},{9,0,936},{15,0,214},{18,0,199},{152,0,26}, +{4,11,284},{6,11,223},{7,0,1462},{139,0,659},{133,0,220},{139,0,803},{132,0,544} +,{4,10,492},{133,10,451},{16,0,98},{148,0,119},{4,11,218},{7,11,526},{143,11,137 +},{135,10,835},{4,11,270},{5,11,192},{6,11,332},{7,11,1322},{13,10,70},{13,11,9} +,{14,11,104},{142,11,311},{132,10,539},{140,11,661},{5,0,176},{6,0,437},{6,0,564 +},{11,0,181},{141,0,183},{135,0,1192},{6,10,113},{135,10,436},{136,10,718},{135, +10,520},{135,0,1878},{140,11,196},{7,11,379},{8,11,481},{137,11,377},{5,11,1003} +,{6,11,149},{137,11,746},{8,11,262},{9,11,627},{10,11,18},{11,11,214},{11,11,404 +},{11,11,457},{11,11,780},{11,11,849},{11,11,913},{13,11,330},{13,11,401},{142, +11,200},{149,0,26},{136,11,304},{132,11,142},{135,0,944},{4,0,790},{5,0,273},{ +134,0,394},{134,0,855},{4,0,135},{6,0,127},{7,0,1185},{7,0,1511},{8,0,613},{11,0 +,5},{12,0,336},{12,0,495},{12,0,586},{12,0,660},{12,0,668},{14,0,385},{15,0,118} +,{17,0,20},{146,0,98},{6,0,230},{9,0,752},{12,10,610},{13,10,431},{16,10,59},{ +146,0,109},{7,0,1954},{135,11,925},{4,11,471},{5,11,51},{6,11,602},{8,11,484},{ +10,11,195},{140,11,159},{132,10,307},{136,11,688},{132,11,697},{7,11,812},{7,11, +1261},{7,11,1360},{9,11,632},{140,11,352},{5,0,162},{5,10,964},{136,0,68},{4,0, +654},{136,11,212},{4,0,156},{7,0,998},{7,0,1045},{7,0,1860},{9,0,48},{9,0,692},{ +11,0,419},{139,0,602},{133,11,221},{4,11,373},{5,11,283},{6,11,480},{135,11,609} +,{142,11,216},{132,0,240},{6,11,192},{9,11,793},{145,11,55},{4,10,75},{5,10,180} +,{6,10,500},{7,10,58},{7,10,710},{138,10,645},{4,11,132},{5,10,649},{5,11,69},{ +135,11,1242},{6,10,276},{7,10,282},{7,10,879},{7,10,924},{8,10,459},{9,10,599},{ +9,10,754},{11,10,574},{12,10,128},{12,10,494},{13,10,52},{13,10,301},{15,10,30}, +{143,10,132},{132,10,200},{4,11,111},{135,11,302},{9,0,197},{10,0,300},{12,0,473 +},{13,0,90},{141,0,405},{132,11,767},{6,11,42},{7,11,1416},{7,11,1590},{7,11, +2005},{8,11,131},{8,11,466},{9,11,672},{13,11,252},{148,11,103},{8,0,958},{8,0, +999},{10,0,963},{138,0,1001},{135,10,1621},{135,0,858},{4,0,606},{137,11,444},{6 +,11,44},{136,11,368},{139,11,172},{4,11,570},{133,11,120},{139,11,624},{6,10,225 +},{7,0,1978},{8,0,676},{137,10,211},{7,0,972},{8,10,687},{139,0,102},{6,11,227}, +{135,11,1589},{8,10,58},{9,10,724},{11,10,809},{13,10,113},{145,10,72},{4,0,361} +,{133,0,315},{132,0,461},{6,10,345},{135,10,1247},{132,0,472},{8,10,767},{8,10, +803},{9,10,301},{137,10,903},{135,11,1333},{135,11,477},{7,10,1949},{136,10,674} +,{6,0,905},{138,0,747},{133,0,155},{134,10,259},{7,0,163},{8,0,319},{9,0,402},{ +10,0,24},{10,0,681},{11,0,200},{12,0,253},{12,0,410},{142,0,219},{5,0,475},{6,11 +,1667},{7,0,1780},{7,11,2036},{9,0,230},{10,11,600},{11,0,297},{11,0,558},{14,0, +322},{147,0,76},{136,10,254},{6,0,848},{135,0,1956},{6,11,511},{140,11,132},{5, +11,568},{6,11,138},{135,11,1293},{6,0,631},{137,0,838},{149,0,36},{4,11,565},{8, +11,23},{136,11,827},{5,0,944},{134,0,1769},{4,0,144},{4,11,922},{5,11,1023},{6,0 +,842},{134,0,1400},{133,10,248},{9,10,800},{10,10,693},{11,10,482},{11,10,734},{ +139,10,789},{7,11,1002},{139,11,145},{4,10,116},{5,10,95},{5,10,445},{7,10,1688} +,{8,10,29},{9,10,272},{11,10,509},{139,10,915},{14,0,369},{146,0,72},{135,10, +1641},{132,11,740},{133,10,543},{140,11,116},{5,10,181},{6,0,247},{8,10,41},{137 +,0,555},{133,10,657},{136,0,996},{138,10,709},{7,0,189},{8,10,202},{138,10,536}, +{136,11,402},{4,11,716},{141,11,31},{10,0,280},{138,0,797},{9,10,423},{140,10,89 +},{8,10,113},{9,10,877},{10,10,554},{11,10,83},{12,10,136},{147,10,109},{133,10, +976},{4,10,206},{135,0,746},{136,0,526},{139,0,345},{136,0,1017},{8,11,152},{9, +11,53},{9,11,268},{9,11,901},{10,11,518},{10,11,829},{11,11,188},{13,11,74},{14, +11,46},{15,11,17},{15,11,33},{17,11,40},{18,11,36},{19,11,20},{22,11,1},{152,11, +2},{133,11,736},{136,11,532},{5,0,428},{138,0,651},{135,11,681},{135,0,1162},{7, +0,327},{8,10,226},{10,10,537},{11,10,570},{11,10,605},{11,10,799},{11,10,804},{ +12,10,85},{12,10,516},{12,10,623},{12,11,677},{13,0,230},{13,10,361},{14,10,77}, +{14,10,78},{17,0,113},{147,10,110},{4,0,792},{4,10,769},{7,0,1717},{138,0,546},{ +4,11,684},{136,11,384},{132,10,551},{134,0,1203},{9,10,57},{9,10,459},{10,10,425 +},{11,10,119},{12,10,184},{12,10,371},{13,10,358},{145,10,51},{5,0,672},{5,10, +814},{8,10,10},{9,10,421},{9,10,729},{10,10,609},{139,10,689},{138,0,189},{134, +10,624},{7,11,110},{7,11,188},{8,11,290},{8,11,591},{9,11,382},{9,11,649},{11,11 +,71},{11,11,155},{11,11,313},{12,11,5},{13,11,325},{142,11,287},{133,0,99},{6,0, +1053},{135,0,298},{7,11,360},{7,11,425},{9,11,66},{9,11,278},{138,11,644},{4,0, +397},{136,0,555},{137,10,269},{132,10,528},{4,11,900},{133,11,861},{5,11,254},{6 +,0,1157},{7,11,985},{136,11,73},{7,11,1959},{136,11,683},{12,0,398},{20,0,39},{ +21,0,11},{150,0,41},{4,0,485},{7,0,353},{135,0,1523},{6,0,366},{7,0,1384},{135,0 +,1601},{138,0,787},{137,0,282},{5,10,104},{6,10,173},{135,10,1631},{139,11,146}, +{4,0,157},{133,0,471},{134,0,941},{132,11,725},{7,0,1336},{8,10,138},{8,10,342}, +{9,10,84},{10,10,193},{11,10,883},{140,10,359},{134,11,196},{136,0,116},{133,11, +831},{134,0,787},{134,10,95},{6,10,406},{10,10,409},{10,10,447},{11,10,44},{140, +10,100},{5,0,160},{7,0,363},{7,0,589},{10,0,170},{141,0,55},{134,0,1815},{132,0, +866},{4,11,321},{6,0,889},{6,0,1067},{6,0,1183},{134,11,569},{5,11,848},{134,11, +66},{4,11,36},{6,10,1636},{7,11,1387},{10,11,205},{11,11,755},{141,11,271},{132, +0,689},{4,10,282},{7,10,1034},{9,0,820},{11,10,398},{11,10,634},{12,10,1},{12,10 +,79},{12,10,544},{14,10,237},{17,10,10},{146,10,20},{4,0,108},{7,0,804},{139,0, +498},{132,11,887},{6,0,1119},{135,11,620},{6,11,165},{138,11,388},{5,0,244},{5, +10,499},{6,10,476},{7,10,600},{7,10,888},{135,10,1096},{140,0,609},{135,0,1005}, +{4,0,412},{133,0,581},{4,11,719},{135,11,155},{7,10,296},{7,10,596},{8,10,560},{ +8,10,586},{9,10,612},{11,10,304},{12,10,46},{13,10,89},{14,10,112},{145,10,122}, +{4,0,895},{133,0,772},{142,11,307},{135,0,1898},{4,0,926},{133,0,983},{4,11,353} +,{6,11,146},{6,11,1789},{7,11,288},{7,11,990},{7,11,1348},{9,11,665},{9,11,898}, +{11,11,893},{142,11,212},{132,0,538},{133,11,532},{6,0,294},{7,0,1267},{8,0,624} +,{141,0,496},{4,11,45},{7,0,1325},{135,11,1257},{138,0,301},{7,10,1599},{7,10, +1723},{8,10,79},{8,10,106},{8,10,190},{8,10,302},{8,10,383},{8,10,713},{9,0,298} +,{9,10,119},{9,10,233},{9,10,419},{9,10,471},{10,10,181},{10,10,406},{11,10,57}, +{11,10,85},{11,10,120},{11,10,177},{11,10,296},{11,10,382},{11,10,454},{11,10, +758},{11,10,999},{12,0,291},{12,10,27},{12,10,131},{12,10,245},{12,10,312},{12, +10,446},{12,10,454},{13,0,276},{13,10,98},{13,10,426},{13,10,508},{14,0,6},{14, +10,163},{14,10,272},{14,10,277},{14,10,370},{15,10,95},{15,10,138},{15,10,167},{ +17,0,18},{17,10,38},{20,10,96},{149,0,32},{132,0,757},{134,0,1263},{4,0,820},{ +134,10,1759},{133,0,722},{136,11,816},{138,10,372},{145,10,16},{134,0,1039},{4,0 +,991},{134,0,2028},{133,10,258},{7,0,1875},{139,0,124},{6,11,559},{6,11,1691},{ +135,11,586},{5,0,324},{7,0,881},{8,10,134},{9,10,788},{140,10,438},{7,11,1823},{ +139,11,693},{6,0,1348},{134,0,1545},{134,0,911},{132,0,954},{7,10,1948},{7,10, +2004},{8,0,329},{136,0,414},{5,0,517},{6,10,439},{7,10,780},{135,10,1040},{132,0 +,816},{5,10,1},{6,10,81},{138,10,520},{5,10,482},{8,10,98},{9,0,713},{10,0,222}, +{10,10,700},{10,10,822},{11,10,302},{11,10,778},{12,10,50},{12,10,127},{12,10, +396},{13,10,62},{13,10,328},{14,10,122},{147,10,72},{137,0,33},{5,10,2},{7,10, +1494},{136,10,589},{6,10,512},{7,10,797},{8,10,253},{9,10,77},{10,10,1},{10,10, +129},{10,10,225},{10,11,108},{11,10,118},{11,10,226},{11,10,251},{11,10,430},{11 +,10,701},{11,10,974},{11,10,982},{11,11,116},{12,10,64},{12,10,260},{12,10,488}, +{140,10,690},{134,11,456},{133,11,925},{5,0,150},{7,0,106},{7,0,774},{8,0,603},{ +9,0,593},{9,0,634},{10,0,44},{10,0,173},{11,0,462},{11,0,515},{13,0,216},{13,0, +288},{142,0,400},{137,10,347},{5,0,748},{134,0,553},{12,0,108},{141,0,291},{4,10 +,12},{7,0,420},{7,10,522},{7,10,809},{8,10,797},{141,10,88},{6,11,193},{7,11,240 +},{7,11,1682},{10,11,51},{10,11,640},{11,11,410},{13,11,82},{14,11,247},{14,11, +331},{142,11,377},{133,10,528},{135,0,1777},{4,0,493},{144,0,55},{136,11,633},{ +139,0,81},{6,0,980},{136,0,321},{148,10,109},{5,10,266},{9,10,290},{9,10,364},{ +10,10,293},{11,10,606},{142,10,45},{6,0,568},{7,0,112},{7,0,1804},{8,0,362},{8,0 +,410},{8,0,830},{9,0,514},{11,0,649},{142,0,157},{4,0,74},{6,0,510},{6,10,594},{ +9,10,121},{10,10,49},{10,10,412},{139,10,834},{134,0,838},{136,10,748},{132,10, +466},{132,0,625},{135,11,1443},{4,11,237},{135,11,514},{9,10,378},{141,10,162},{ +6,0,16},{6,0,158},{7,0,43},{7,0,129},{7,0,181},{8,0,276},{8,0,377},{10,0,523},{ +11,0,816},{12,0,455},{13,0,303},{142,0,135},{135,0,281},{4,0,1},{7,0,1143},{7,0, +1463},{8,0,61},{9,0,207},{9,0,390},{9,0,467},{139,0,836},{6,11,392},{7,11,65},{ +135,11,2019},{132,10,667},{4,0,723},{5,0,895},{7,0,1031},{8,0,199},{8,0,340},{9, +0,153},{9,0,215},{10,0,21},{10,0,59},{10,0,80},{10,0,224},{10,0,838},{11,0,229}, +{11,0,652},{12,0,192},{13,0,146},{142,0,91},{132,0,295},{137,0,51},{9,11,222},{ +10,11,43},{139,11,900},{5,0,309},{140,0,211},{5,0,125},{8,0,77},{138,0,15},{136, +11,604},{138,0,789},{4,10,39},{5,0,173},{7,10,1843},{8,10,407},{11,10,144},{140, +10,523},{138,11,265},{133,0,439},{132,10,510},{7,0,648},{7,0,874},{7,10,1980},{ +10,10,487},{10,10,809},{11,0,164},{12,0,76},{146,0,9},{12,0,111},{13,10,260},{14 +,0,294},{18,10,63},{147,0,45},{133,11,549},{134,10,570},{4,0,8},{7,0,1152},{7,0, +1153},{7,0,1715},{9,0,374},{10,0,478},{139,0,648},{135,0,1099},{5,0,575},{6,0, +354},{135,0,701},{7,11,36},{8,11,201},{136,11,605},{4,10,787},{136,11,156},{6,0, +518},{149,11,13},{140,11,224},{134,0,702},{132,10,516},{5,11,724},{10,11,305},{ +11,11,151},{12,11,33},{12,11,121},{12,11,381},{17,11,3},{17,11,27},{17,11,78},{ +18,11,18},{19,11,54},{149,11,5},{4,11,523},{5,11,638},{8,0,87},{11,10,887},{14, +10,365},{142,10,375},{138,0,438},{136,10,821},{135,11,1908},{6,11,242},{7,11,227 +},{7,11,1581},{8,11,104},{9,11,113},{9,11,220},{9,11,427},{10,11,74},{10,11,239} +,{11,11,579},{11,11,1023},{13,11,4},{13,11,204},{13,11,316},{18,11,95},{148,11, +86},{4,0,69},{5,0,122},{5,0,849},{6,0,1633},{9,0,656},{138,0,464},{4,10,10},{7,0 +,1802},{139,10,786},{135,11,861},{139,0,499},{7,0,476},{7,0,1592},{138,0,87},{ +133,10,684},{4,0,840},{134,10,27},{142,0,283},{6,0,1620},{7,11,1328},{136,11,494 +},{5,0,859},{7,0,1160},{8,0,107},{9,0,291},{9,0,439},{10,0,663},{11,0,609},{140, +0,197},{7,11,1306},{8,11,505},{9,11,482},{10,11,126},{11,11,225},{12,11,347},{12 +,11,449},{13,11,19},{142,11,218},{5,11,268},{10,11,764},{12,11,120},{13,11,39},{ +145,11,127},{145,10,56},{7,11,1672},{10,11,472},{11,11,189},{143,11,51},{6,10, +342},{6,10,496},{8,10,275},{137,10,206},{133,0,600},{4,0,117},{6,0,372},{7,0, +1905},{142,0,323},{4,10,909},{5,10,940},{135,11,1471},{132,10,891},{4,0,722},{ +139,0,471},{4,11,384},{135,11,1022},{132,10,687},{9,0,5},{12,0,216},{12,0,294},{ +12,0,298},{12,0,400},{12,0,518},{13,0,229},{143,0,139},{135,11,1703},{7,11,1602} +,{10,11,698},{12,11,212},{141,11,307},{6,10,41},{141,10,160},{135,11,1077},{9,11 +,159},{11,11,28},{140,11,603},{4,0,514},{7,0,1304},{138,0,477},{134,0,1774},{9,0 +,88},{139,0,270},{5,0,12},{6,10,1718},{7,0,375},{137,0,438},{132,11,515},{136,10 +,778},{8,11,632},{8,11,697},{137,11,854},{6,0,362},{6,0,997},{146,0,51},{7,0,816 +},{7,0,1241},{9,0,283},{9,0,520},{10,0,213},{10,0,307},{10,0,463},{10,0,671},{10 +,0,746},{11,0,401},{11,0,794},{12,0,517},{18,0,107},{147,0,115},{133,10,115},{ +150,11,28},{4,11,136},{133,11,551},{142,10,314},{132,0,258},{6,0,22},{7,0,903},{ +7,0,1963},{8,0,639},{138,0,577},{5,0,681},{5,10,193},{8,0,782},{12,10,178},{13,0 +,130},{145,0,84},{9,11,17},{138,11,291},{7,11,1287},{9,11,44},{10,11,552},{10,11 +,642},{11,11,839},{12,11,274},{12,11,275},{12,11,372},{13,11,91},{142,11,125},{ +135,10,174},{4,0,664},{5,0,804},{139,0,1013},{134,0,942},{6,0,1349},{6,0,1353},{ +6,0,1450},{7,11,1518},{139,11,694},{4,10,122},{5,10,796},{5,10,952},{6,10,1660}, +{6,10,1671},{8,10,567},{9,10,687},{9,10,742},{10,10,686},{11,0,356},{11,10,682}, +{140,10,281},{5,0,32},{6,11,147},{7,11,886},{9,11,753},{138,11,268},{5,10,179},{ +7,10,1095},{135,10,1213},{4,10,66},{7,10,722},{135,10,904},{135,10,352},{9,11, +245},{138,11,137},{4,0,289},{5,11,414},{7,0,629},{7,0,1698},{7,0,1711},{140,0, +215},{6,0,1975},{135,11,1762},{6,0,450},{136,0,109},{141,10,35},{134,11,599},{ +136,0,705},{133,0,664},{134,11,1749},{11,11,402},{12,11,109},{12,11,431},{13,11, +179},{13,11,206},{14,11,175},{14,11,217},{16,11,3},{148,11,53},{135,0,1238},{134 +,11,1627},{132,11,488},{10,10,592},{10,10,753},{12,10,317},{12,10,355},{12,10, +465},{12,10,469},{12,10,560},{12,10,578},{141,0,318},{133,10,564},{132,11,83},{ +140,11,676},{6,0,1872},{6,0,1906},{6,0,1907},{9,0,934},{9,0,956},{9,0,960},{9,0, +996},{12,0,794},{12,0,876},{12,0,880},{12,0,918},{15,0,230},{18,0,234},{18,0,238 +},{21,0,38},{149,0,62},{134,10,556},{134,11,278},{137,0,103},{7,10,544},{8,10, +719},{138,10,61},{4,10,5},{5,10,498},{8,10,637},{137,10,521},{7,0,777},{12,0,229 +},{12,0,239},{12,11,229},{12,11,239},{15,0,12},{143,11,12},{6,0,26},{7,11,388},{ +7,11,644},{139,11,781},{7,11,229},{8,11,59},{9,11,190},{9,11,257},{10,11,378},{ +140,11,191},{133,10,927},{135,10,1441},{4,10,893},{5,10,780},{133,10,893},{4,0, +414},{5,0,467},{9,0,654},{10,0,451},{12,0,59},{141,0,375},{142,0,173},{135,0,17} +,{5,10,238},{135,0,1350},{135,0,955},{4,0,960},{10,0,887},{12,0,753},{18,0,161}, +{18,0,162},{152,0,19},{136,11,344},{6,10,1729},{137,11,288},{132,11,660},{4,0, +217},{4,10,60},{5,0,710},{7,0,760},{7,0,1926},{7,10,1800},{8,10,314},{9,0,428},{ +9,0,708},{9,10,700},{10,0,254},{10,0,296},{10,0,720},{11,0,109},{11,0,255},{11, +10,487},{12,0,165},{12,0,315},{13,0,107},{13,0,203},{14,0,54},{14,0,99},{14,0, +114},{14,0,388},{16,0,85},{17,0,9},{17,0,33},{20,0,25},{20,0,28},{20,0,29},{21,0 +,9},{21,0,10},{21,0,34},{150,0,17},{7,11,1035},{138,11,737},{7,11,690},{9,11,217 +},{9,11,587},{140,11,521},{6,0,919},{7,11,706},{7,11,1058},{138,11,538},{7,10, +1853},{138,10,437},{136,10,419},{6,0,280},{10,0,502},{11,0,344},{140,0,38},{5,0, +45},{7,0,1161},{11,0,448},{11,0,880},{13,0,139},{13,0,407},{15,0,16},{17,0,95},{ +18,0,66},{18,0,88},{18,0,123},{149,0,7},{11,11,92},{11,11,196},{11,11,409},{11, +11,450},{11,11,666},{11,11,777},{12,11,262},{13,11,385},{13,11,393},{15,11,115}, +{16,11,45},{145,11,82},{136,0,777},{134,11,1744},{4,0,410},{5,10,828},{135,0,521 +},{134,0,673},{7,0,1110},{7,0,1778},{7,10,176},{135,10,178},{5,10,806},{7,10, +1976},{7,11,268},{136,11,569},{4,11,733},{9,11,194},{10,11,92},{11,11,198},{12, +11,84},{12,11,87},{13,11,128},{144,11,74},{4,10,51},{5,0,341},{6,10,4},{7,0,1129 +},{7,10,591},{7,10,849},{7,10,951},{7,10,1613},{7,10,1760},{7,10,1988},{9,10,434 +},{10,10,754},{11,0,414},{11,10,25},{139,10,37},{133,10,902},{135,10,928},{135,0 +,787},{132,0,436},{134,10,270},{7,0,1587},{135,0,1707},{6,0,377},{7,0,1025},{9,0 +,613},{145,0,104},{7,11,982},{7,11,1361},{10,11,32},{143,11,56},{139,0,96},{132, +0,451},{132,10,416},{142,10,372},{5,10,152},{5,10,197},{7,10,340},{7,10,867},{7, +11,306},{10,10,548},{10,10,581},{11,10,6},{12,10,3},{12,10,19},{14,10,110},{142, +10,289},{134,0,680},{134,11,609},{7,0,483},{7,10,190},{8,10,28},{8,10,141},{8,10 +,444},{8,10,811},{9,10,468},{11,10,334},{12,10,24},{12,10,386},{140,10,576},{5, +10,757},{138,0,916},{5,10,721},{135,10,1553},{133,11,178},{134,0,937},{132,10, +898},{133,0,739},{147,0,82},{135,0,663},{146,0,128},{5,10,277},{141,10,247},{134 +,0,1087},{132,10,435},{6,11,381},{7,11,645},{7,11,694},{136,11,546},{7,0,503},{ +135,0,1885},{6,0,1965},{8,0,925},{138,0,955},{4,0,113},{5,0,163},{5,0,735},{7,0, +1009},{9,0,9},{9,0,771},{12,0,90},{13,0,138},{13,0,410},{143,0,128},{4,0,324},{ +138,0,104},{5,10,265},{6,10,212},{135,0,460},{133,11,105},{7,11,261},{7,11,1107} +,{7,11,1115},{7,11,1354},{7,11,1588},{7,11,1705},{7,11,1902},{9,11,465},{10,11, +248},{10,11,349},{10,11,647},{11,11,527},{11,11,660},{11,11,669},{12,11,529},{ +141,11,305},{5,11,438},{9,11,694},{12,11,627},{141,11,210},{152,11,11},{4,0,935} +,{133,0,823},{132,10,702},{5,0,269},{5,10,808},{7,0,434},{7,0,891},{7,10,2045},{ +8,0,339},{9,0,702},{11,0,594},{11,0,718},{145,0,100},{7,0,1014},{9,0,485},{141,0 +,264},{134,0,1713},{7,0,1810},{11,0,866},{12,0,103},{12,11,233},{141,0,495},{4,0 +,423},{10,0,949},{138,0,1013},{135,0,900},{8,11,25},{138,11,826},{5,10,166},{8, +10,739},{140,10,511},{134,0,2018},{7,11,1270},{139,11,612},{4,10,119},{5,10,170} +,{5,10,447},{7,10,1708},{7,10,1889},{9,10,357},{9,10,719},{12,10,486},{140,10, +596},{12,0,574},{140,11,574},{132,11,308},{6,0,964},{6,0,1206},{134,0,1302},{4, +10,450},{135,10,1158},{135,11,150},{136,11,649},{14,0,213},{148,0,38},{9,11,45}, +{9,11,311},{141,11,42},{134,11,521},{7,10,1375},{7,10,1466},{138,10,331},{132,10 +,754},{5,11,339},{7,11,1442},{14,11,3},{15,11,41},{147,11,66},{136,11,378},{134, +0,1022},{5,10,850},{136,10,799},{142,0,143},{135,0,2029},{134,11,1628},{8,0,523} +,{150,0,34},{5,0,625},{135,0,1617},{7,0,275},{7,10,238},{7,10,2033},{8,10,120},{ +8,10,188},{8,10,659},{9,10,598},{10,10,466},{12,10,342},{12,10,588},{13,10,503}, +{14,10,246},{143,10,92},{7,0,37},{8,0,425},{8,0,693},{9,0,720},{10,0,380},{10,0, +638},{11,0,273},{11,0,473},{12,0,61},{143,0,43},{135,11,829},{135,0,1943},{132,0 +,765},{5,11,486},{135,11,1349},{7,11,1635},{8,11,17},{10,11,217},{138,11,295},{4 +,10,201},{7,10,1744},{8,10,602},{11,10,247},{11,10,826},{145,10,65},{138,11,558} +,{11,0,551},{142,0,159},{8,10,164},{146,10,62},{139,11,176},{132,0,168},{136,0, +1010},{134,0,1994},{135,0,91},{138,0,532},{135,10,1243},{135,0,1884},{132,10,907 +},{5,10,100},{10,10,329},{12,10,416},{149,10,29},{134,11,447},{132,10,176},{5,10 +,636},{5,10,998},{7,10,9},{7,10,1508},{8,10,26},{9,10,317},{9,10,358},{10,10,210 +},{10,10,292},{10,10,533},{11,10,555},{12,10,526},{12,10,607},{13,10,263},{13,10 +,459},{142,10,271},{4,11,609},{135,11,756},{6,0,15},{7,0,70},{10,0,240},{147,0, +93},{4,11,930},{133,11,947},{134,0,1227},{134,0,1534},{133,11,939},{133,11,962}, +{5,11,651},{8,11,170},{9,11,61},{9,11,63},{10,11,23},{10,11,37},{10,11,834},{11, +11,4},{11,11,187},{11,11,281},{11,11,503},{11,11,677},{12,11,96},{12,11,130},{12 +,11,244},{14,11,5},{14,11,40},{14,11,162},{14,11,202},{146,11,133},{4,11,406},{5 +,11,579},{12,11,492},{150,11,15},{139,0,392},{6,10,610},{10,10,127},{141,10,27}, +{7,0,655},{7,0,1844},{136,10,119},{4,0,145},{6,0,176},{7,0,395},{137,0,562},{132 +,0,501},{140,11,145},{136,0,1019},{134,0,509},{139,0,267},{6,11,17},{7,11,16},{7 +,11,1001},{7,11,1982},{9,11,886},{10,11,489},{10,11,800},{11,11,782},{12,11,320} +,{13,11,467},{14,11,145},{14,11,387},{143,11,119},{145,11,17},{5,11,458},{134,0, +1099},{7,11,1983},{8,11,0},{8,11,171},{9,11,120},{9,11,732},{10,11,473},{11,11, +656},{11,11,998},{18,11,0},{18,11,2},{147,11,21},{12,11,427},{146,11,38},{10,0, +948},{138,0,968},{7,10,126},{136,10,84},{136,10,790},{4,0,114},{9,0,492},{13,0, +462},{142,0,215},{6,10,64},{12,10,377},{141,10,309},{4,0,77},{5,0,361},{6,0,139} +,{6,0,401},{6,0,404},{7,0,413},{7,0,715},{7,0,1716},{11,0,279},{12,0,179},{12,0, +258},{13,0,244},{142,0,358},{134,0,1717},{7,0,772},{7,0,1061},{7,0,1647},{7,10, +1104},{8,0,82},{11,0,250},{11,0,607},{11,10,269},{11,10,539},{11,10,627},{11,10, +706},{11,10,975},{12,0,311},{12,0,420},{12,10,248},{12,10,434},{12,10,600},{12, +10,622},{13,0,184},{13,0,367},{13,10,297},{13,10,485},{14,10,69},{14,10,409},{ +143,10,108},{135,0,724},{4,11,512},{4,11,519},{133,11,342},{134,0,1133},{145,11, +29},{11,10,977},{141,10,507},{6,0,841},{6,0,1042},{6,0,1194},{10,0,993},{140,0, +1021},{6,11,31},{7,11,491},{7,11,530},{8,11,592},{9,10,34},{11,10,484},{11,11,53 +},{11,11,779},{12,11,167},{12,11,411},{14,11,14},{14,11,136},{15,11,72},{16,11, +17},{144,11,72},{4,0,1021},{5,11,907},{134,0,2037},{6,10,1700},{7,0,373},{7,10, +293},{7,10,382},{7,10,1026},{7,10,1087},{7,10,2027},{8,0,335},{8,0,596},{8,10, +252},{8,10,727},{8,10,729},{9,0,488},{9,10,30},{9,10,199},{9,10,231},{9,10,251}, +{9,10,334},{9,10,361},{9,10,712},{10,10,55},{10,10,60},{10,10,232},{10,10,332},{ +10,10,384},{10,10,396},{10,10,504},{10,10,542},{10,10,652},{11,10,20},{11,10,48} +,{11,10,207},{11,10,291},{11,10,298},{11,10,342},{11,10,365},{11,10,394},{11,10, +620},{11,10,705},{11,10,1017},{12,10,123},{12,10,340},{12,10,406},{12,10,643},{ +13,10,61},{13,10,269},{13,10,311},{13,10,319},{13,10,486},{14,10,234},{15,10,62} +,{15,10,85},{16,10,71},{18,10,119},{148,10,105},{150,0,37},{4,11,208},{5,11,106} +,{6,11,531},{8,11,408},{9,11,188},{138,11,572},{132,0,564},{6,0,513},{135,0,1052 +},{132,0,825},{9,0,899},{140,11,441},{134,0,778},{133,11,379},{7,0,1417},{12,0, +382},{17,0,48},{152,0,12},{132,11,241},{6,10,379},{7,0,1116},{7,10,270},{8,10, +176},{8,10,183},{9,10,432},{9,10,661},{12,10,247},{12,10,617},{146,10,125},{5,10 +,792},{133,10,900},{6,0,545},{7,0,565},{7,0,1669},{10,0,114},{11,0,642},{140,0, +618},{133,0,5},{138,11,7},{132,11,259},{135,0,192},{134,0,701},{136,0,763},{135, +10,1979},{4,10,901},{133,10,776},{10,0,755},{147,0,29},{133,0,759},{4,11,173},{5 +,11,312},{5,11,512},{135,11,1285},{7,11,1603},{7,11,1691},{9,11,464},{11,11,195} +,{12,11,279},{12,11,448},{14,11,11},{147,11,102},{7,0,370},{7,0,1007},{7,0,1177} +,{135,0,1565},{135,0,1237},{4,0,87},{5,0,250},{141,0,298},{4,11,452},{5,11,583}, +{5,11,817},{6,11,433},{7,11,593},{7,11,720},{7,11,1378},{8,11,161},{9,11,284},{ +10,11,313},{139,11,886},{4,11,547},{135,11,1409},{136,11,722},{4,10,37},{5,10, +334},{135,10,1253},{132,10,508},{12,0,107},{146,0,31},{8,11,420},{139,11,193},{ +135,0,814},{135,11,409},{140,0,991},{4,0,57},{7,0,1195},{7,0,1438},{7,0,1548},{7 +,0,1835},{7,0,1904},{9,0,757},{10,0,604},{139,0,519},{132,0,540},{138,11,308},{ +132,10,533},{136,0,608},{144,11,65},{4,0,1014},{134,0,2029},{4,0,209},{5,11,1002 +},{7,0,902},{136,11,745},{134,0,2030},{6,0,303},{7,0,335},{7,0,1437},{7,0,1668}, +{8,0,553},{8,0,652},{8,0,656},{9,0,558},{11,0,743},{149,0,18},{5,11,575},{6,11, +354},{135,11,701},{4,11,239},{6,11,477},{7,11,1607},{11,11,68},{139,11,617},{132 +,0,559},{8,0,527},{18,0,60},{147,0,24},{133,10,920},{138,0,511},{133,0,1017},{ +133,0,675},{138,10,391},{7,10,1952},{139,0,156},{138,11,369},{132,11,367},{133,0 +,709},{6,0,698},{134,0,887},{142,10,126},{134,0,1745},{132,10,483},{13,11,299},{ +142,11,75},{133,0,714},{7,0,8},{136,0,206},{138,10,480},{4,11,694},{9,10,495},{ +146,10,104},{7,11,1248},{11,11,621},{139,11,702},{140,11,687},{132,0,776},{139, +10,1009},{135,0,1272},{134,0,1059},{8,10,653},{13,10,93},{147,10,14},{135,11,213 +},{136,0,406},{133,10,172},{132,0,947},{8,0,175},{10,0,168},{138,0,573},{132,0, +870},{6,0,1567},{151,11,28},{134,11,472},{5,10,260},{136,11,132},{4,11,751},{11, +11,390},{140,11,32},{4,11,409},{133,11,78},{6,11,473},{12,0,554},{145,11,105},{ +133,0,784},{8,0,908},{136,11,306},{139,0,882},{6,0,358},{7,0,1393},{7,11,1759},{ +8,0,396},{8,11,396},{10,0,263},{10,11,263},{14,0,154},{14,11,154},{16,0,48},{16, +11,48},{17,0,8},{145,11,8},{13,11,163},{13,11,180},{18,11,78},{148,11,35},{14,0, +32},{18,0,85},{20,0,2},{152,0,16},{7,0,228},{8,10,167},{8,10,375},{9,10,82},{9, +10,561},{10,0,770},{138,10,620},{132,0,845},{9,0,14},{9,0,441},{10,0,306},{139,0 +,9},{8,10,194},{8,10,756},{11,0,966},{12,0,287},{13,0,342},{13,0,402},{15,0,110} +,{143,0,163},{134,0,1578},{4,0,967},{6,0,1820},{6,0,1847},{140,0,716},{136,0,594 +},{7,0,1428},{7,0,1640},{7,0,1867},{7,11,883},{9,0,169},{9,0,182},{9,0,367},{9,0 +,478},{9,0,506},{9,0,551},{9,0,557},{9,0,648},{9,0,697},{9,0,705},{9,0,725},{9,0 +,787},{9,0,794},{10,0,198},{10,0,214},{10,0,267},{10,0,275},{10,0,456},{10,0,551 +},{10,0,561},{10,0,613},{10,0,627},{10,0,668},{10,0,675},{10,0,691},{10,0,695},{ +10,0,707},{10,0,715},{11,0,183},{11,0,201},{11,0,244},{11,0,262},{11,0,352},{11, +0,439},{11,0,493},{11,0,572},{11,0,591},{11,0,608},{11,0,611},{11,0,646},{11,0, +674},{11,0,711},{11,0,751},{11,0,761},{11,0,776},{11,0,785},{11,0,850},{11,0,853 +},{11,0,862},{11,0,865},{11,0,868},{11,0,875},{11,0,898},{11,0,902},{11,0,903},{ +11,0,910},{11,0,932},{11,0,942},{11,0,957},{11,0,967},{11,0,972},{12,0,148},{12, +0,195},{12,0,220},{12,0,237},{12,0,318},{12,0,339},{12,0,393},{12,0,445},{12,0, +450},{12,0,474},{12,0,505},{12,0,509},{12,0,533},{12,0,591},{12,0,594},{12,0,597 +},{12,0,621},{12,0,633},{12,0,642},{13,0,59},{13,0,60},{13,0,145},{13,0,239},{13 +,0,250},{13,0,329},{13,0,344},{13,0,365},{13,0,372},{13,0,387},{13,0,403},{13,0, +414},{13,0,456},{13,0,470},{13,0,478},{13,0,483},{13,0,489},{14,0,55},{14,0,57}, +{14,0,81},{14,0,90},{14,0,148},{14,0,239},{14,0,266},{14,0,321},{14,0,326},{14,0 +,327},{14,0,330},{14,0,347},{14,0,355},{14,0,401},{14,0,404},{14,0,411},{14,0, +414},{14,0,416},{14,0,420},{15,0,61},{15,0,74},{15,0,87},{15,0,88},{15,0,94},{15 +,0,96},{15,0,116},{15,0,149},{15,0,154},{16,0,50},{16,0,63},{16,0,73},{17,0,2},{ +17,0,66},{17,0,92},{17,0,103},{17,0,112},{17,0,120},{18,0,50},{18,0,54},{18,0,82 +},{18,0,86},{18,0,90},{18,0,111},{18,0,115},{18,0,156},{19,0,40},{19,0,79},{20,0 +,78},{149,0,22},{5,0,161},{135,0,839},{4,0,782},{13,11,293},{142,11,56},{133,11, +617},{139,11,50},{135,10,22},{145,0,64},{5,10,639},{7,10,1249},{139,10,896},{138 +,0,998},{135,11,2042},{4,11,546},{142,11,233},{6,0,1043},{134,0,1574},{134,0, +1496},{4,10,102},{7,10,815},{7,10,1699},{139,10,964},{12,0,781},{142,0,461},{4, +11,313},{133,11,577},{6,0,639},{6,0,1114},{137,0,817},{8,11,184},{141,11,433},{7 +,0,1814},{135,11,935},{10,0,997},{140,0,958},{4,0,812},{137,11,625},{132,10,899} +,{136,10,795},{5,11,886},{6,11,46},{6,11,1790},{7,11,14},{7,11,732},{7,11,1654}, +{8,11,95},{8,11,327},{8,11,616},{10,11,598},{10,11,769},{11,11,134},{11,11,747}, +{12,11,378},{142,11,97},{136,0,139},{6,10,52},{9,10,104},{9,10,559},{12,10,308}, +{147,10,87},{133,11,1021},{132,10,604},{132,10,301},{136,10,779},{7,0,643},{136, +0,236},{132,11,153},{134,0,1172},{147,10,32},{133,11,798},{4,11,587},{134,0,1338 +},{6,11,598},{7,11,42},{8,11,695},{10,11,212},{11,11,158},{14,11,196},{145,11,85 +},{135,10,508},{5,11,957},{5,11,1008},{135,11,249},{4,11,129},{135,11,465},{5,0, +54},{7,11,470},{7,11,1057},{7,11,1201},{9,11,755},{11,11,906},{140,11,527},{7,11 +,908},{146,11,7},{5,11,148},{136,11,450},{144,11,1},{4,0,256},{135,0,1488},{6,10 +,310},{7,10,1849},{8,10,72},{8,10,272},{8,10,431},{9,0,351},{9,10,12},{10,10,563 +},{10,10,630},{10,10,796},{10,10,810},{11,10,367},{11,10,599},{11,10,686},{140, +10,672},{6,0,1885},{6,0,1898},{6,0,1899},{140,0,955},{4,0,714},{133,0,469},{6,0, +1270},{134,0,1456},{132,0,744},{6,0,313},{7,10,537},{8,10,64},{9,10,127},{10,10, +496},{12,10,510},{141,10,384},{4,10,244},{4,11,217},{5,11,710},{7,10,233},{7,11, +1926},{9,11,428},{9,11,708},{10,11,254},{10,11,296},{10,11,720},{11,11,109},{11, +11,255},{12,11,165},{12,11,315},{13,11,107},{13,11,203},{14,11,54},{14,11,99},{ +14,11,114},{14,11,388},{16,11,85},{17,11,9},{17,11,33},{20,11,25},{20,11,28},{20 +,11,29},{21,11,9},{21,11,10},{21,11,34},{150,11,17},{138,0,402},{7,0,969},{146,0 +,55},{8,0,50},{137,0,624},{134,0,1355},{132,0,572},{134,10,1650},{10,10,702},{ +139,10,245},{10,0,847},{142,0,445},{6,0,43},{7,0,38},{8,0,248},{138,0,513},{133, +0,369},{137,10,338},{133,0,766},{133,0,363},{133,10,896},{8,11,392},{11,11,54},{ +13,11,173},{13,11,294},{148,11,7},{134,0,678},{7,11,1230},{136,11,531},{6,0,258} +,{140,0,409},{5,0,249},{148,0,82},{7,10,1117},{136,10,539},{5,0,393},{6,0,378},{ +7,0,1981},{9,0,32},{9,0,591},{10,0,685},{10,0,741},{142,0,382},{133,0,788},{134, +0,1281},{134,0,1295},{7,0,1968},{141,0,509},{4,0,61},{5,0,58},{5,0,171},{5,0,683 +},{6,0,291},{6,0,566},{7,0,1650},{11,0,523},{12,0,273},{12,0,303},{15,0,39},{143 +,0,111},{6,0,706},{134,0,1283},{134,0,589},{135,11,1433},{133,11,435},{5,10,4},{ +5,10,810},{6,10,13},{6,10,538},{6,10,1690},{6,10,1726},{7,0,1059},{7,10,1819},{8 +,10,148},{8,10,696},{8,10,791},{12,10,125},{13,0,54},{143,10,9},{135,10,1268},{5 +,11,85},{6,11,419},{7,11,134},{7,11,305},{7,11,361},{7,11,1337},{8,11,71},{140, +11,519},{137,0,824},{140,11,688},{5,11,691},{7,10,1385},{7,11,345},{9,11,94},{11 +,10,582},{11,10,650},{11,10,901},{11,10,949},{12,10,232},{12,10,236},{12,11,169} +,{13,10,413},{13,10,501},{146,10,116},{4,0,917},{133,0,1005},{5,11,183},{6,11, +582},{7,0,1598},{9,11,344},{10,11,679},{140,11,435},{4,10,925},{5,10,803},{8,10, +698},{138,10,828},{132,0,919},{135,11,511},{139,10,992},{4,0,255},{5,0,302},{6,0 +,132},{7,0,128},{7,0,283},{7,0,1299},{10,0,52},{10,0,514},{11,0,925},{13,0,92},{ +142,0,309},{134,0,1369},{135,10,1847},{134,0,328},{7,11,1993},{136,11,684},{133, +10,383},{137,0,173},{134,11,583},{134,0,1411},{5,11,704},{8,11,357},{10,11,745}, +{14,11,426},{17,11,94},{19,0,65},{147,11,57},{9,10,660},{138,10,347},{4,11,179}, +{5,11,198},{133,11,697},{7,11,347},{7,11,971},{8,11,181},{138,11,711},{141,0,442 +},{7,10,572},{9,10,592},{11,0,842},{11,0,924},{11,10,680},{12,10,356},{12,10,550 +},{13,0,317},{13,0,370},{13,0,469},{13,0,471},{14,0,397},{18,0,69},{146,0,145},{ +14,11,19},{14,11,28},{144,11,29},{136,0,534},{4,11,243},{5,11,203},{7,11,19},{7, +11,71},{7,11,113},{10,11,405},{11,11,357},{142,11,240},{6,0,210},{10,0,845},{138 +,0,862},{7,11,1351},{9,11,581},{10,11,639},{11,11,453},{140,11,584},{7,11,1450}, +{139,11,99},{10,0,892},{12,0,719},{144,0,105},{4,0,284},{6,0,223},{134,11,492},{ +5,11,134},{6,11,408},{6,11,495},{135,11,1593},{136,0,529},{137,0,807},{4,0,218}, +{7,0,526},{143,0,137},{6,0,1444},{142,11,4},{132,11,665},{4,0,270},{4,11,248},{5 +,0,192},{6,0,332},{7,0,1322},{7,11,137},{137,11,349},{140,0,661},{7,0,1517},{7, +10,748},{11,0,597},{11,10,700},{14,0,76},{14,0,335},{148,0,33},{5,11,371},{135, +11,563},{146,11,57},{133,10,127},{133,0,418},{4,11,374},{7,11,547},{7,11,1700},{ +7,11,1833},{139,11,858},{6,10,198},{140,10,83},{7,11,1812},{13,11,259},{13,11, +356},{14,11,242},{147,11,114},{5,10,276},{6,10,55},{7,0,379},{7,10,1369},{8,0, +481},{137,0,377},{138,11,286},{5,0,1003},{6,0,149},{6,10,1752},{136,10,726},{6, +11,1647},{7,11,1552},{7,11,2010},{8,0,262},{9,0,627},{9,11,494},{9,11,509},{10,0 +,18},{11,0,214},{11,0,404},{11,0,457},{11,0,780},{11,0,913},{13,0,401},{142,0, +200},{135,0,742},{136,0,304},{132,0,142},{133,10,764},{6,10,309},{7,10,331},{138 +,10,550},{135,10,1062},{6,11,123},{7,10,986},{7,11,214},{9,11,728},{10,11,157},{ +11,11,346},{11,11,662},{143,11,106},{135,10,1573},{7,0,925},{137,0,799},{4,0,471 +},{5,0,51},{6,0,602},{8,0,484},{138,0,195},{136,0,688},{132,0,697},{6,0,1169},{6 +,0,1241},{6,10,194},{7,10,133},{10,10,493},{10,10,570},{139,10,664},{140,0,751}, +{5,10,24},{5,10,569},{6,10,3},{6,10,119},{6,10,143},{6,10,440},{7,0,929},{7,10, +599},{7,10,1686},{7,10,1854},{8,10,424},{9,10,43},{9,10,584},{9,10,760},{10,0, +452},{10,10,328},{11,0,878},{11,10,159},{11,10,253},{12,10,487},{12,10,531},{144 +,0,33},{4,11,707},{13,11,106},{18,11,49},{147,11,41},{5,0,221},{5,11,588},{134, +11,393},{134,0,1437},{6,11,211},{7,11,1690},{11,11,486},{140,11,369},{5,10,14},{ +5,10,892},{6,10,283},{7,10,234},{136,10,537},{4,0,988},{136,0,955},{135,0,1251}, +{4,10,126},{8,10,635},{147,10,34},{4,10,316},{135,10,1561},{137,10,861},{4,10,64 +},{5,10,352},{5,10,720},{6,10,368},{139,10,359},{134,0,192},{4,0,132},{5,0,69},{ +135,0,1242},{7,10,1577},{10,10,304},{10,10,549},{12,10,365},{13,10,220},{13,10, +240},{142,10,33},{4,0,111},{6,11,219},{135,0,865},{5,11,582},{6,11,1646},{7,11, +99},{7,11,1962},{7,11,1986},{8,11,515},{8,11,773},{9,11,23},{9,11,491},{12,11, +620},{14,11,52},{145,11,50},{132,0,767},{7,11,568},{148,11,21},{5,11,851},{6,0, +42},{7,0,1416},{7,0,2005},{8,0,131},{8,0,466},{9,0,672},{13,0,252},{148,0,103},{ +135,0,1050},{6,10,175},{137,10,289},{5,10,432},{133,10,913},{6,0,44},{136,0,368} +,{135,11,784},{132,0,570},{133,0,120},{139,10,595},{140,0,29},{6,0,227},{135,0, +1589},{4,11,98},{7,11,1365},{9,11,422},{9,11,670},{10,11,775},{11,11,210},{13,11 +,26},{13,11,457},{141,11,476},{140,10,80},{5,10,931},{134,10,1698},{133,0,522},{ +134,0,1120},{135,0,1529},{12,0,739},{14,0,448},{142,0,467},{11,10,526},{11,10, +939},{141,10,290},{5,10,774},{6,10,1637},{6,10,1686},{134,10,1751},{6,0,1667},{ +135,0,2036},{7,10,1167},{11,10,934},{13,10,391},{145,10,76},{137,11,147},{6,10, +260},{7,10,1484},{11,11,821},{12,11,110},{12,11,153},{18,11,41},{150,11,19},{6,0 +,511},{6,10,573},{140,0,132},{5,0,568},{6,0,138},{135,0,1293},{132,0,1020},{8,0, +258},{9,0,208},{137,0,359},{4,0,565},{8,0,23},{136,0,827},{134,0,344},{4,0,922}, +{5,0,1023},{13,11,477},{14,11,120},{148,11,61},{134,0,240},{5,11,209},{6,11,30}, +{11,11,56},{139,11,305},{4,10,292},{4,10,736},{5,10,871},{6,0,171},{6,10,1689},{ +7,0,1002},{7,0,1324},{7,10,1944},{9,0,415},{9,10,580},{14,0,230},{146,0,68},{9, +11,635},{139,11,559},{4,11,150},{5,11,303},{134,11,327},{6,10,63},{135,10,920},{ +133,10,793},{8,11,192},{10,11,78},{10,11,555},{11,11,308},{13,11,359},{147,11,95 +},{135,11,786},{135,11,1712},{136,0,402},{6,0,754},{6,11,1638},{7,11,79},{7,11, +496},{9,11,138},{10,11,336},{11,11,12},{12,11,412},{12,11,440},{142,11,305},{4,0 +,716},{141,0,31},{133,0,982},{5,10,67},{6,10,62},{6,10,374},{7,10,1391},{8,0,691 +},{136,0,731},{9,10,790},{140,10,47},{139,11,556},{151,11,1},{7,11,204},{7,11, +415},{8,11,42},{10,11,85},{11,11,33},{11,11,564},{12,11,571},{149,11,1},{7,11, +610},{7,11,1501},{136,0,888},{4,10,391},{135,10,1169},{5,0,847},{9,0,840},{138,0 +,803},{137,0,823},{134,0,785},{8,0,152},{9,0,53},{9,0,268},{9,0,901},{10,0,518}, +{10,0,829},{11,0,188},{13,0,74},{14,0,46},{15,0,17},{15,0,33},{17,0,40},{18,0,36 +},{19,0,20},{22,0,1},{152,0,2},{4,11,3},{5,11,247},{5,11,644},{7,11,744},{7,11, +1207},{7,11,1225},{7,11,1909},{146,11,147},{136,0,532},{135,0,681},{132,10,271}, +{140,0,314},{140,0,677},{4,0,684},{136,0,384},{5,11,285},{9,11,67},{13,11,473},{ +143,11,82},{4,10,253},{5,10,544},{7,10,300},{137,10,340},{7,0,110},{7,0,447},{8, +0,290},{8,0,591},{9,0,382},{9,0,649},{11,0,71},{11,0,155},{11,0,313},{12,0,5},{ +13,0,325},{142,0,287},{134,0,1818},{136,0,1007},{138,0,321},{7,0,360},{7,0,425}, +{9,0,66},{9,0,278},{138,0,644},{133,10,818},{5,0,385},{5,10,541},{6,10,94},{6,10 +,499},{7,10,230},{139,10,321},{4,10,920},{5,10,25},{5,10,790},{6,10,457},{7,10, +853},{136,10,788},{4,0,900},{133,0,861},{5,0,254},{7,0,985},{136,0,73},{7,0,1959 +},{136,0,683},{134,10,1765},{133,10,822},{132,10,634},{4,11,29},{6,11,532},{7,11 +,1628},{7,11,1648},{9,11,303},{9,11,350},{10,11,433},{11,11,97},{11,11,557},{11, +11,745},{12,11,289},{12,11,335},{12,11,348},{12,11,606},{13,11,116},{13,11,233}, +{13,11,466},{14,11,181},{14,11,209},{14,11,232},{14,11,236},{14,11,300},{16,11, +41},{148,11,97},{6,10,36},{7,10,658},{8,10,454},{147,0,86},{135,11,1692},{132,0, +725},{5,11,501},{7,11,1704},{9,11,553},{11,11,520},{12,11,557},{141,11,249},{134 +,0,196},{133,0,831},{136,0,723},{7,0,1897},{13,0,80},{13,0,437},{145,0,74},{4,0, +992},{6,0,627},{136,0,994},{135,11,1294},{132,10,104},{5,0,848},{6,0,66},{136,0, +764},{4,0,36},{7,0,1387},{10,0,205},{139,0,755},{6,0,1046},{134,0,1485},{134,0, +950},{132,0,887},{14,0,450},{148,0,111},{7,0,620},{7,0,831},{9,10,542},{9,10,566 +},{138,10,728},{6,0,165},{138,0,388},{139,10,263},{4,0,719},{135,0,155},{138,10, +468},{6,11,453},{144,11,36},{134,11,129},{5,0,533},{7,0,755},{138,0,780},{134,0, +1465},{4,0,353},{6,0,146},{6,0,1789},{7,0,427},{7,0,990},{7,0,1348},{9,0,665},{9 +,0,898},{11,0,893},{142,0,212},{7,10,87},{142,10,288},{4,0,45},{135,0,1257},{7, +10,988},{7,10,1939},{9,10,64},{9,10,502},{12,0,7},{12,10,34},{13,10,12},{13,10, +234},{147,10,77},{4,0,607},{5,11,60},{6,11,504},{7,11,614},{7,11,1155},{140,11,0 +},{135,10,141},{8,11,198},{11,11,29},{140,11,534},{140,0,65},{136,0,816},{132,10 +,619},{139,0,88},{5,10,246},{8,10,189},{9,10,355},{9,10,512},{10,10,124},{10,10, +453},{11,10,143},{11,10,416},{11,10,859},{141,10,341},{4,11,379},{135,11,1397},{ +4,0,600},{137,0,621},{133,0,367},{134,0,561},{6,0,559},{134,0,1691},{6,0,585},{ +134,11,585},{135,11,1228},{4,11,118},{5,10,678},{6,11,274},{6,11,361},{7,11,75}, +{141,11,441},{135,11,1818},{137,11,841},{5,0,573},{6,0,287},{7,10,862},{7,10, +1886},{138,10,179},{132,10,517},{140,11,693},{5,11,314},{6,11,221},{7,11,419},{ +10,11,650},{11,11,396},{12,11,156},{13,11,369},{14,11,333},{145,11,47},{140,10, +540},{136,10,667},{11,10,403},{146,10,83},{5,10,761},{134,0,672},{9,0,157},{10, +10,131},{140,10,72},{6,11,460},{135,0,714},{134,0,456},{133,0,925},{5,11,682},{ +135,11,1887},{136,11,510},{136,11,475},{133,11,1016},{7,11,602},{8,11,179},{9,0, +19},{10,11,781},{140,11,126},{6,11,329},{138,11,111},{6,0,822},{134,0,1473},{144 +,11,86},{11,0,113},{139,11,113},{5,11,821},{134,11,1687},{133,10,449},{7,0,463}, +{8,10,103},{145,0,69},{7,10,2028},{138,10,641},{6,0,193},{7,0,240},{7,0,1682},{ +10,0,51},{10,0,640},{11,0,410},{13,0,82},{14,0,247},{14,0,331},{142,0,377},{6,0, +471},{11,0,411},{142,0,2},{5,11,71},{7,11,1407},{9,11,388},{9,11,704},{10,11,261 +},{10,11,619},{11,11,547},{11,11,619},{143,11,157},{136,0,633},{135,0,1148},{6,0 +,554},{7,0,1392},{7,10,1274},{7,10,1386},{7,11,2008},{9,11,337},{10,11,517},{12, +0,129},{146,10,87},{6,10,187},{7,0,803},{7,10,1203},{8,0,542},{8,10,380},{14,10, +117},{149,10,28},{6,10,297},{7,10,793},{139,10,938},{7,10,464},{8,0,438},{11,0, +363},{11,10,105},{12,10,231},{14,10,386},{15,10,102},{148,10,75},{5,11,16},{6,11 +,86},{6,11,603},{7,11,292},{7,11,561},{8,11,257},{8,11,382},{9,11,721},{9,11,778 +},{11,11,581},{140,11,466},{4,11,486},{5,11,491},{134,0,717},{132,0,875},{132,11 +,72},{6,11,265},{135,11,847},{4,0,237},{135,0,514},{6,0,392},{7,0,65},{135,0, +2019},{140,11,261},{135,11,922},{137,11,404},{7,10,1010},{11,10,733},{11,10,759} +,{12,0,563},{13,10,34},{14,0,101},{18,0,129},{146,10,45},{7,10,1656},{9,10,369}, +{10,10,338},{10,10,490},{11,10,154},{11,10,545},{11,10,775},{13,10,77},{141,10, +274},{4,0,444},{10,0,146},{140,0,9},{139,11,163},{7,0,1260},{135,0,1790},{9,0, +222},{10,0,43},{139,0,900},{137,11,234},{138,0,971},{137,0,761},{134,0,699},{136 +,11,434},{5,10,20},{6,0,1116},{6,10,298},{6,11,197},{7,0,1366},{7,10,659},{8,11, +205},{137,10,219},{132,11,490},{11,11,820},{150,11,51},{7,10,1440},{11,10,854},{ +11,10,872},{11,10,921},{12,10,551},{13,10,472},{142,10,367},{140,11,13},{132,0, +829},{4,10,439},{140,0,242},{136,10,669},{6,0,593},{6,11,452},{7,11,312},{138,11 +,219},{4,11,333},{9,11,176},{12,11,353},{141,11,187},{7,0,36},{8,0,201},{136,0, +605},{140,0,224},{132,10,233},{134,0,1430},{134,0,1806},{4,0,523},{133,0,638},{6 +,0,1889},{9,0,958},{9,0,971},{9,0,976},{12,0,796},{12,0,799},{12,0,808},{12,0, +835},{12,0,836},{12,0,914},{12,0,946},{15,0,216},{15,0,232},{18,0,183},{18,0,187 +},{18,0,194},{18,0,212},{18,0,232},{149,0,49},{132,10,482},{6,0,827},{134,0,1434 +},{135,10,346},{134,0,2043},{6,0,242},{7,0,227},{7,0,1581},{8,0,104},{9,0,113},{ +9,0,220},{9,0,427},{10,0,136},{10,0,239},{11,0,579},{11,0,1023},{13,0,4},{13,0, +204},{13,0,316},{148,0,86},{134,11,1685},{7,0,148},{8,0,284},{141,0,63},{142,0, +10},{135,11,584},{134,0,1249},{7,0,861},{135,10,334},{5,10,795},{6,10,1741},{137 +,11,70},{132,0,807},{7,11,135},{8,11,7},{8,11,62},{9,11,243},{10,11,658},{10,11, +697},{11,11,456},{139,11,756},{9,11,395},{138,11,79},{137,11,108},{147,0,94},{ +136,0,494},{135,11,631},{135,10,622},{7,0,1510},{135,10,1750},{4,10,203},{135,10 +,1936},{7,11,406},{7,11,459},{8,11,606},{139,11,726},{7,0,1306},{8,0,505},{9,0, +482},{10,0,126},{11,0,225},{12,0,347},{12,0,449},{13,0,19},{14,0,218},{142,0,435 +},{5,0,268},{10,0,764},{12,0,120},{13,0,39},{145,0,127},{142,11,68},{11,10,678}, +{140,10,307},{12,11,268},{12,11,640},{142,11,119},{135,10,2044},{133,11,612},{4, +11,372},{7,11,482},{8,11,158},{9,11,602},{9,11,615},{10,11,245},{10,11,678},{10, +11,744},{11,11,248},{139,11,806},{7,10,311},{9,10,308},{140,10,255},{4,0,384},{ +135,0,1022},{5,11,854},{135,11,1991},{135,10,1266},{4,10,400},{5,10,267},{135,10 +,232},{135,0,1703},{9,0,159},{11,0,661},{140,0,603},{4,0,964},{9,11,106},{9,11, +163},{9,11,296},{10,11,167},{10,11,172},{10,11,777},{11,11,16},{14,0,438},{14,0, +444},{14,0,456},{22,0,60},{150,0,63},{136,0,583},{132,0,515},{8,0,632},{8,0,697} +,{137,0,854},{5,11,195},{135,11,1685},{6,0,1123},{134,0,1365},{134,11,328},{7,11 +,1997},{8,11,730},{139,11,1006},{4,0,136},{133,0,551},{134,0,1782},{7,0,1287},{9 +,0,44},{10,0,552},{10,0,642},{11,0,839},{12,0,274},{12,0,275},{12,0,372},{13,0, +91},{142,0,125},{5,11,751},{11,11,797},{140,11,203},{133,0,732},{4,10,100},{7,0, +679},{7,11,821},{136,0,313},{10,0,361},{142,0,316},{134,0,595},{6,0,147},{7,0, +886},{9,0,753},{138,0,268},{5,10,362},{5,10,443},{6,10,318},{7,10,1019},{139,10, +623},{5,10,463},{136,10,296},{4,10,454},{5,11,950},{5,11,994},{134,11,351},{138, +0,137},{5,10,48},{5,10,404},{6,10,557},{7,10,458},{8,10,597},{10,10,455},{10,10, +606},{11,10,49},{11,10,548},{12,10,476},{13,10,18},{141,10,450},{133,0,414},{135 +,0,1762},{5,11,421},{135,11,47},{5,10,442},{135,10,1984},{134,0,599},{134,0,1749 +},{134,0,1627},{4,0,488},{132,11,350},{137,11,751},{132,0,83},{140,0,676},{133, +11,967},{5,10,55},{7,0,1639},{140,10,161},{4,11,473},{7,11,623},{8,11,808},{9,11 +,871},{9,11,893},{11,11,38},{11,11,431},{12,11,112},{12,11,217},{12,11,243},{12, +11,562},{12,11,683},{13,11,141},{13,11,197},{13,11,227},{13,11,406},{13,11,487}, +{14,11,156},{14,11,203},{14,11,224},{14,11,256},{18,11,58},{150,11,0},{133,10, +450},{7,11,736},{139,11,264},{134,0,278},{4,11,222},{7,11,286},{136,11,629},{135 +,10,869},{140,0,97},{144,0,14},{134,0,1085},{4,10,213},{7,10,223},{136,10,80},{7 +,0,388},{7,0,644},{139,0,781},{132,0,849},{7,0,229},{8,0,59},{9,0,190},{10,0,378 +},{140,0,191},{7,10,381},{7,10,806},{7,10,820},{8,10,354},{8,10,437},{8,10,787}, +{9,10,657},{10,10,58},{10,10,339},{10,10,749},{11,10,914},{12,10,162},{13,10,75} +,{14,10,106},{14,10,198},{14,10,320},{14,10,413},{146,10,43},{141,11,306},{136, +10,747},{134,0,1115},{8,11,146},{16,0,94},{144,0,108},{6,0,700},{6,0,817},{134,0 +,1002},{133,10,692},{4,11,465},{135,11,1663},{134,10,191},{6,0,1414},{135,11,913 +},{132,0,660},{7,0,1035},{138,0,737},{6,10,162},{7,10,1960},{136,10,831},{132,10 +,706},{7,0,690},{9,0,217},{9,0,587},{140,0,521},{138,10,426},{135,10,1235},{6,11 +,82},{7,11,138},{7,11,517},{9,11,673},{139,11,238},{138,0,272},{5,11,495},{7,11, +834},{9,11,733},{139,11,378},{134,0,1744},{132,0,1011},{7,11,828},{142,11,116},{ +4,0,733},{5,11,559},{9,0,194},{10,0,92},{11,0,198},{12,0,84},{141,0,128},{6,11, +21},{6,11,1737},{7,11,1444},{8,11,224},{10,0,57},{138,0,277},{4,10,204},{137,10, +902},{136,10,833},{7,10,366},{9,10,287},{11,0,348},{12,0,99},{12,10,199},{12,10, +556},{12,10,577},{18,0,1},{18,0,11},{147,0,4},{6,0,1981},{136,0,936},{21,0,33},{ +150,0,40},{5,11,519},{138,11,204},{5,10,356},{135,10,224},{134,0,775},{135,0,306 +},{7,10,630},{9,10,567},{11,10,150},{11,10,444},{141,10,119},{5,0,979},{134,10, +539},{133,0,611},{4,11,402},{135,11,1679},{5,0,178},{7,11,2},{8,11,323},{136,11, +479},{5,11,59},{135,11,672},{4,0,1010},{6,0,1969},{138,11,237},{133,11,412},{146 +,11,34},{7,11,1740},{146,11,48},{134,0,664},{139,10,814},{4,11,85},{135,11,549}, +{133,11,94},{133,11,457},{132,0,390},{134,0,1510},{4,10,235},{135,10,255},{4,10, +194},{5,10,584},{6,10,384},{6,11,11},{7,10,583},{7,11,187},{10,10,761},{11,10, +760},{139,10,851},{4,11,522},{139,11,802},{135,0,493},{10,11,776},{13,11,345},{ +142,11,425},{146,0,37},{4,11,52},{135,11,661},{134,0,724},{134,0,829},{133,11, +520},{133,10,562},{4,11,281},{5,11,38},{7,11,194},{7,11,668},{7,11,1893},{137,11 +,397},{5,10,191},{137,10,271},{7,0,1537},{14,0,96},{143,0,73},{4,10,470},{5,0, +473},{6,10,153},{7,10,1503},{7,10,1923},{10,10,701},{11,0,168},{11,10,132},{11, +10,227},{11,10,320},{11,10,436},{11,10,525},{11,10,855},{12,10,41},{12,10,286},{ +13,10,103},{13,10,284},{14,10,255},{14,10,262},{15,10,117},{143,10,127},{133,0, +105},{5,0,438},{9,0,694},{12,0,627},{141,0,210},{133,10,327},{6,10,552},{7,10, +1754},{137,10,604},{134,0,1256},{152,0,11},{5,11,448},{11,11,98},{139,11,524},{5 +,10,80},{6,10,405},{7,0,1626},{7,10,403},{7,10,1502},{8,10,456},{9,10,487},{9,10 +,853},{9,10,889},{10,10,309},{11,10,721},{11,10,994},{12,10,430},{13,10,165},{14 +,11,16},{146,11,44},{132,0,779},{8,0,25},{138,0,826},{4,10,453},{5,10,887},{6,10 +,535},{8,10,6},{8,10,543},{136,10,826},{137,11,461},{140,11,632},{132,0,308},{ +135,0,741},{132,0,671},{7,0,150},{8,0,649},{136,0,1020},{6,11,336},{8,11,552},{9 +,0,99},{9,11,285},{10,11,99},{139,11,568},{134,0,521},{5,0,339},{14,0,3},{15,0, +41},{15,0,166},{147,0,66},{6,11,423},{7,11,665},{7,11,1210},{9,11,218},{141,11, +222},{5,10,101},{5,11,256},{6,0,543},{6,10,88},{7,10,1677},{9,10,100},{10,10,677 +},{14,10,169},{14,10,302},{14,10,313},{15,10,48},{143,10,84},{4,10,310},{7,10, +708},{7,10,996},{9,10,795},{10,10,390},{10,10,733},{11,10,451},{12,10,249},{14, +10,115},{14,10,286},{143,10,100},{133,10,587},{13,11,417},{14,11,129},{143,11,15 +},{134,0,1358},{136,11,554},{132,10,498},{7,10,217},{8,10,140},{138,10,610},{135 +,11,989},{135,11,634},{6,0,155},{140,0,234},{135,11,462},{132,11,618},{134,0, +1628},{132,0,766},{4,11,339},{5,10,905},{135,11,259},{135,0,829},{4,11,759},{141 +,11,169},{4,10,456},{7,0,1445},{7,10,358},{7,10,1637},{8,10,643},{139,10,483},{5 +,0,486},{135,0,1349},{5,11,688},{135,11,712},{7,0,1635},{8,0,17},{10,0,217},{10, +0,295},{12,0,2},{140,11,2},{138,0,558},{150,10,56},{4,11,278},{5,11,465},{135,11 +,1367},{136,11,482},{133,10,535},{6,0,1362},{6,0,1461},{10,11,274},{10,11,625},{ +139,11,530},{5,0,599},{5,11,336},{6,11,341},{6,11,478},{6,11,1763},{136,11,386}, +{7,10,1748},{137,11,151},{134,0,1376},{133,10,539},{135,11,73},{135,11,1971},{ +139,11,283},{9,0,93},{139,0,474},{6,10,91},{135,10,435},{5,11,396},{6,0,447},{ +134,11,501},{4,10,16},{5,10,316},{5,10,842},{6,10,370},{6,10,1778},{8,10,166},{ +11,10,812},{12,10,206},{12,10,351},{14,10,418},{16,10,15},{16,10,34},{18,10,3},{ +19,10,3},{19,10,7},{20,10,4},{149,10,21},{7,0,577},{7,0,1432},{9,0,475},{9,0,505 +},{9,0,526},{9,0,609},{9,0,689},{9,0,726},{9,0,735},{9,0,738},{10,0,556},{10,0, +674},{10,0,684},{11,0,89},{11,0,202},{11,0,272},{11,0,380},{11,0,415},{11,0,505} +,{11,0,537},{11,0,550},{11,0,562},{11,0,640},{11,0,667},{11,0,688},{11,0,847},{ +11,0,927},{11,0,930},{11,0,940},{12,0,144},{12,0,325},{12,0,329},{12,0,389},{12, +0,403},{12,0,451},{12,0,515},{12,0,604},{12,0,616},{12,0,626},{13,0,66},{13,0, +131},{13,0,167},{13,0,236},{13,0,368},{13,0,411},{13,0,434},{13,0,453},{13,0,461 +},{13,0,474},{14,0,59},{14,0,60},{14,0,139},{14,0,152},{14,0,276},{14,0,353},{14 +,0,402},{15,0,28},{15,0,81},{15,0,123},{15,0,152},{18,0,136},{148,0,88},{4,11, +929},{133,11,799},{136,11,46},{142,0,307},{4,0,609},{7,0,756},{9,0,544},{11,0, +413},{144,0,25},{7,10,619},{10,0,687},{10,10,547},{11,10,122},{140,10,601},{4,0, +930},{133,0,947},{133,0,939},{142,0,21},{4,11,892},{133,11,770},{133,0,962},{5,0 +,651},{8,0,170},{9,0,61},{9,0,63},{10,0,23},{10,0,37},{10,0,834},{11,0,4},{11,0, +187},{11,0,281},{11,0,503},{11,0,677},{12,0,96},{12,0,130},{12,0,244},{14,0,5},{ +14,0,40},{14,0,162},{14,0,202},{146,0,133},{4,0,406},{5,0,579},{12,0,492},{150,0 +,15},{135,11,158},{135,0,597},{132,0,981},{132,10,888},{4,10,149},{138,10,368},{ +132,0,545},{4,10,154},{7,10,1134},{136,10,105},{135,11,2001},{134,0,1558},{4,10, +31},{6,10,429},{7,10,962},{9,10,458},{139,10,691},{132,10,312},{135,10,1642},{6, +0,17},{6,0,1304},{7,0,16},{7,0,1001},{9,0,886},{10,0,489},{10,0,800},{11,0,782}, +{12,0,320},{13,0,467},{14,0,145},{14,0,387},{143,0,119},{135,0,1982},{7,11,1461} +,{12,11,91},{145,0,17},{4,10,236},{132,11,602},{138,0,907},{136,0,110},{5,10,836 +},{5,10,857},{6,10,1680},{7,0,272},{147,0,53},{5,0,458},{7,11,1218},{136,11,303} +,{7,0,1983},{8,0,0},{8,0,171},{9,0,120},{9,0,732},{10,0,473},{10,10,68},{11,0, +656},{11,0,998},{11,10,494},{18,0,0},{18,0,2},{147,0,21},{137,11,662},{4,11,13}, +{5,11,567},{7,11,1498},{9,11,124},{11,11,521},{140,11,405},{4,10,81},{139,10,867 +},{135,11,1006},{7,11,800},{7,11,1783},{138,11,12},{5,10,282},{8,10,650},{9,0, +295},{9,10,907},{138,0,443},{132,11,735},{4,10,775},{4,11,170},{135,11,323},{6,0 +,1844},{10,0,924},{11,11,844},{12,11,104},{140,11,625},{5,11,304},{7,11,1403},{ +140,11,498},{134,0,1232},{4,0,519},{10,0,70},{12,0,26},{14,0,17},{14,0,178},{15, +0,34},{149,0,12},{132,0,993},{4,11,148},{133,11,742},{6,0,31},{7,0,491},{7,0,530 +},{8,0,592},{11,0,53},{11,0,779},{12,0,167},{12,0,411},{14,0,14},{14,0,136},{15, +0,72},{16,0,17},{144,0,72},{133,0,907},{134,0,733},{133,11,111},{4,10,71},{5,10, +376},{7,10,119},{138,10,665},{136,0,55},{8,0,430},{136,11,430},{4,0,208},{5,0, +106},{6,0,531},{8,0,408},{9,0,188},{138,0,572},{11,10,827},{12,0,56},{14,10,34}, +{143,10,148},{134,0,1693},{133,11,444},{132,10,479},{140,0,441},{9,0,449},{10,0, +192},{138,0,740},{134,0,928},{4,0,241},{7,10,607},{136,10,99},{8,11,123},{15,11, +6},{144,11,7},{6,11,285},{8,11,654},{11,11,749},{12,11,190},{12,11,327},{13,11, +120},{13,11,121},{13,11,327},{15,11,47},{146,11,40},{4,10,41},{5,10,74},{7,10, +1627},{11,10,871},{140,10,619},{7,0,1525},{11,10,329},{11,10,965},{12,10,241},{ +14,10,354},{15,10,22},{148,10,63},{132,0,259},{135,11,183},{9,10,209},{137,10, +300},{5,11,937},{135,11,100},{133,10,98},{4,0,173},{5,0,312},{5,0,512},{135,0, +1285},{141,0,185},{7,0,1603},{7,0,1691},{9,0,464},{11,0,195},{12,0,279},{12,0, +448},{14,0,11},{147,0,102},{135,0,1113},{133,10,984},{4,0,452},{5,0,583},{135,0, +720},{4,0,547},{5,0,817},{6,0,433},{7,0,593},{7,0,1378},{8,0,161},{9,0,284},{10, +0,313},{139,0,886},{4,10,182},{6,10,205},{7,10,220},{136,0,722},{150,0,13},{4,10 +,42},{9,10,205},{9,10,786},{138,10,659},{6,0,289},{7,0,1670},{12,0,57},{151,0,4} +,{132,10,635},{14,0,43},{146,0,21},{139,10,533},{135,0,1694},{8,0,420},{139,0, +193},{135,0,409},{132,10,371},{4,10,272},{135,10,836},{5,10,825},{134,10,1640},{ +5,11,251},{5,11,956},{8,11,268},{9,11,214},{146,11,142},{138,0,308},{6,0,1863},{ +141,11,37},{137,10,879},{7,10,317},{135,10,569},{132,11,294},{134,0,790},{5,0, +1002},{136,0,745},{5,11,346},{5,11,711},{136,11,390},{135,0,289},{5,0,504},{9,10 +,307},{139,0,68},{4,0,239},{6,0,477},{7,0,1607},{139,0,617},{149,0,13},{133,0, +609},{133,11,624},{5,11,783},{7,11,1998},{135,11,2047},{133,10,525},{132,0,367}, +{132,11,594},{5,10,493},{134,0,528},{4,10,174},{135,10,911},{8,10,417},{137,10, +782},{132,0,694},{7,0,548},{137,0,58},{4,10,32},{5,10,215},{6,10,269},{7,10,1782 +},{7,10,1892},{10,10,16},{11,10,822},{11,10,954},{141,10,481},{140,0,687},{7,0, +1749},{136,10,477},{132,11,569},{133,10,308},{135,10,1088},{4,0,661},{138,0,1004 +},{5,11,37},{6,11,39},{6,11,451},{7,11,218},{7,11,667},{7,11,1166},{7,11,1687},{ +8,11,662},{144,11,2},{5,10,126},{8,10,297},{9,0,445},{9,10,366},{12,0,53},{12,10 +,374},{141,0,492},{7,10,1551},{139,10,361},{148,0,74},{134,11,508},{135,0,213},{ +132,10,175},{132,10,685},{6,0,760},{6,0,834},{134,0,1248},{7,11,453},{7,11,635}, +{7,11,796},{8,11,331},{9,11,328},{9,11,330},{9,11,865},{10,11,119},{10,11,235},{ +11,11,111},{11,11,129},{11,11,240},{12,11,31},{12,11,66},{12,11,222},{12,11,269} +,{12,11,599},{12,11,689},{13,11,186},{13,11,364},{142,11,345},{7,0,1672},{139,0, +189},{133,10,797},{133,10,565},{6,0,1548},{6,11,98},{7,11,585},{135,11,702},{9,0 +,968},{15,0,192},{149,0,56},{4,10,252},{6,11,37},{7,10,1068},{7,11,299},{7,11, +1666},{8,11,195},{8,11,316},{9,11,178},{9,11,276},{9,11,339},{9,11,536},{10,10, +434},{10,11,102},{10,11,362},{10,11,785},{11,10,228},{11,10,426},{11,11,55},{11, +11,149},{11,11,773},{13,10,231},{13,11,416},{13,11,419},{14,11,38},{14,11,41},{ +14,11,210},{18,10,106},{148,10,87},{4,0,751},{11,0,390},{140,0,32},{4,0,409},{ +133,0,78},{11,11,458},{12,11,15},{140,11,432},{5,10,231},{7,0,1602},{7,10,601},{ +9,10,277},{9,10,674},{10,0,257},{10,0,698},{10,10,178},{10,10,418},{10,10,509},{ +11,0,544},{11,0,585},{11,10,531},{12,0,212},{12,10,113},{12,10,475},{13,0,307},{ +13,10,99},{142,10,428},{6,0,473},{145,0,105},{5,11,645},{6,0,1949},{143,0,156},{ +7,10,1591},{144,10,43},{135,0,1779},{135,10,1683},{4,11,290},{135,11,1356},{134, +0,763},{6,11,70},{7,11,1292},{10,11,762},{139,11,288},{142,0,29},{140,11,428},{7 +,0,883},{7,11,131},{7,11,422},{8,11,210},{140,11,573},{134,0,488},{4,10,399},{5, +10,119},{5,10,494},{7,10,751},{137,10,556},{133,0,617},{132,11,936},{139,0,50},{ +7,0,1518},{139,0,694},{137,0,785},{4,0,546},{135,0,2042},{7,11,716},{13,11,97},{ +141,11,251},{132,11,653},{145,0,22},{134,0,1016},{4,0,313},{133,0,577},{136,11, +657},{8,0,184},{141,0,433},{135,0,935},{6,0,720},{9,0,114},{146,11,80},{7,10,594 +},{7,10,851},{7,10,1858},{9,10,411},{9,10,574},{9,10,666},{9,10,737},{10,10,346} +,{10,10,712},{11,10,246},{11,10,432},{11,10,517},{11,10,647},{11,10,679},{11,10, +727},{12,0,186},{12,0,292},{12,10,304},{12,10,305},{12,10,323},{12,10,483},{12, +10,572},{12,10,593},{12,10,602},{13,10,95},{13,10,101},{13,10,171},{13,10,315},{ +13,10,378},{13,10,425},{13,10,475},{14,0,100},{14,10,63},{14,10,380},{14,10,384} +,{15,10,133},{18,0,70},{18,10,112},{148,10,72},{135,10,1093},{135,11,1836},{132, +10,679},{137,10,203},{11,0,402},{12,0,109},{12,0,431},{13,0,179},{13,0,206},{14, +0,217},{16,0,3},{148,0,53},{7,11,1368},{8,11,232},{8,11,361},{10,11,682},{138,11 +,742},{137,10,714},{5,0,886},{6,0,46},{6,0,1790},{7,0,14},{7,0,732},{7,0,1654},{ +8,0,95},{8,0,327},{8,0,616},{9,0,892},{9,11,534},{10,0,598},{10,0,769},{11,0,134 +},{11,0,747},{12,0,378},{142,0,97},{4,0,969},{136,10,825},{137,11,27},{6,0,727}, +{142,11,12},{133,0,1021},{134,0,1190},{134,11,1657},{5,10,143},{5,10,769},{6,10, +1760},{7,10,682},{7,10,1992},{136,10,736},{132,0,153},{135,11,127},{133,0,798},{ +132,0,587},{6,0,598},{7,0,42},{8,0,695},{10,0,212},{11,0,158},{14,0,196},{145,0, +85},{133,10,860},{6,0,1929},{134,0,1933},{5,0,957},{5,0,1008},{6,10,422},{7,10,0 +},{7,10,1544},{8,11,364},{9,0,577},{11,10,990},{12,0,141},{12,10,453},{13,10,47} +,{141,10,266},{134,0,1319},{4,0,129},{135,0,465},{7,0,470},{7,0,1057},{7,0,1201} +,{9,0,755},{11,0,906},{140,0,527},{7,0,908},{146,0,7},{5,0,148},{136,0,450},{5, +10,515},{137,10,131},{7,10,1605},{11,10,962},{146,10,139},{132,10,646},{134,0, +1166},{4,10,396},{7,10,728},{9,10,117},{13,10,202},{148,10,51},{6,10,121},{6,10, +124},{6,10,357},{7,10,1138},{7,10,1295},{8,10,162},{139,10,655},{14,0,374},{142, +11,374},{138,0,253},{139,0,1003},{5,11,909},{9,11,849},{138,11,805},{133,10,237} +,{7,11,525},{7,11,1579},{8,11,497},{136,11,573},{137,0,46},{132,0,879},{134,0, +806},{135,0,1868},{6,0,1837},{134,0,1846},{6,0,730},{134,0,881},{7,0,965},{7,0, +1460},{7,0,1604},{7,11,193},{7,11,397},{7,11,1105},{8,11,124},{8,11,619},{9,11, +305},{10,11,264},{11,11,40},{12,11,349},{13,11,134},{13,11,295},{14,11,155},{15, +11,120},{146,11,105},{136,0,506},{143,0,10},{4,11,262},{7,10,571},{7,10,1877},{7 +,11,342},{10,10,366},{141,11,23},{133,11,641},{9,10,513},{10,0,22},{10,10,39},{ +12,10,122},{140,10,187},{135,11,1431},{150,11,49},{4,11,99},{6,11,250},{6,11,346 +},{8,11,127},{138,11,81},{6,0,2014},{8,0,928},{10,0,960},{10,0,979},{140,0,996}, +{134,0,296},{132,11,915},{5,11,75},{9,11,517},{10,11,470},{12,11,155},{141,11, +224},{137,10,873},{4,0,854},{140,11,18},{134,0,587},{7,10,107},{7,10,838},{8,10, +550},{138,10,401},{11,0,636},{11,10,588},{11,10,864},{11,10,968},{15,0,145},{15, +10,160},{17,0,34},{19,0,50},{151,0,20},{135,11,216},{7,0,982},{10,0,32},{143,0, +56},{133,10,768},{133,11,954},{6,11,304},{7,11,1114},{8,11,418},{10,11,345},{11, +11,341},{11,11,675},{141,11,40},{9,11,410},{139,11,425},{136,0,941},{4,10,894},{ +133,0,435},{5,0,85},{6,0,419},{7,0,134},{7,0,305},{7,0,361},{7,0,1337},{8,0,71}, +{140,0,519},{140,0,688},{135,0,740},{5,0,691},{7,0,345},{9,0,94},{140,0,169},{5, +0,183},{6,0,582},{10,0,679},{140,0,435},{134,11,14},{6,0,945},{135,0,511},{134, +11,1708},{5,11,113},{6,11,243},{7,11,1865},{11,11,161},{16,11,37},{145,11,99},{ +132,11,274},{137,0,539},{6,10,272},{7,0,1993},{136,0,684},{6,0,659},{134,0,982}, +{4,10,9},{5,10,128},{7,10,368},{11,10,480},{148,10,3},{134,0,583},{132,0,803},{ +133,0,704},{4,0,179},{5,0,198},{133,0,697},{7,0,347},{7,0,971},{7,11,166},{8,0, +181},{138,0,711},{136,10,682},{4,10,2},{7,10,545},{7,10,894},{136,11,521},{135,0 +,481},{132,0,243},{5,0,203},{7,0,19},{7,0,71},{7,0,113},{10,0,405},{11,0,357},{ +142,0,240},{5,11,725},{5,11,727},{135,11,1811},{6,0,826},{137,11,304},{7,0,1450} +,{139,0,99},{133,11,654},{134,0,492},{5,0,134},{6,0,408},{6,0,495},{6,11,273},{7 +,0,1593},{10,11,188},{13,11,377},{146,11,77},{9,10,769},{140,10,185},{135,11,410 +},{142,0,4},{4,0,665},{134,11,1785},{4,0,248},{7,0,137},{137,0,349},{5,10,530},{ +142,10,113},{7,0,1270},{139,0,612},{132,11,780},{5,0,371},{135,0,563},{135,0,826 +},{6,0,1535},{23,0,21},{151,0,23},{4,0,374},{7,0,547},{7,0,1700},{7,0,1833},{139 +,0,858},{133,10,556},{7,11,612},{8,11,545},{8,11,568},{8,11,642},{9,11,717},{10, +11,541},{10,11,763},{11,11,449},{12,11,489},{13,11,153},{13,11,296},{14,11,138}, +{14,11,392},{15,11,50},{16,11,6},{16,11,12},{148,11,9},{9,0,311},{141,0,42},{8, +10,16},{140,10,568},{6,0,1968},{6,0,2027},{138,0,991},{6,0,1647},{7,0,1552},{7,0 +,2010},{9,0,494},{137,0,509},{133,11,948},{6,10,186},{137,10,426},{134,0,769},{ +134,0,642},{132,10,585},{6,0,123},{7,0,214},{9,0,728},{10,0,157},{11,0,346},{11, +0,662},{143,0,106},{142,11,381},{135,0,1435},{4,11,532},{5,11,706},{135,11,662}, +{5,11,837},{134,11,1651},{4,10,93},{5,10,252},{6,10,229},{7,10,291},{9,10,550},{ +139,10,644},{148,0,79},{137,10,749},{134,0,1425},{137,10,162},{4,11,362},{7,11, +52},{7,11,303},{140,11,166},{132,10,381},{4,11,330},{7,11,933},{7,11,2012},{136, +11,292},{135,11,767},{4,0,707},{5,0,588},{6,0,393},{13,0,106},{18,0,49},{147,0, +41},{6,0,211},{7,0,1690},{11,0,486},{140,0,369},{137,11,883},{4,11,703},{135,11, +207},{4,0,187},{5,0,184},{5,0,690},{7,0,1869},{10,0,756},{139,0,783},{132,11,571 +},{134,0,1382},{5,0,175},{6,10,77},{6,10,157},{7,10,974},{7,10,1301},{7,10,1339} +,{7,10,1490},{7,10,1873},{137,10,628},{134,0,1493},{5,11,873},{133,11,960},{134, +0,1007},{12,11,93},{12,11,501},{13,11,362},{14,11,151},{15,11,40},{15,11,59},{16 +,11,46},{17,11,25},{18,11,14},{18,11,134},{19,11,25},{19,11,69},{20,11,16},{20, +11,19},{20,11,66},{21,11,23},{21,11,25},{150,11,42},{11,10,919},{141,10,409},{ +134,0,219},{5,0,582},{6,0,1646},{7,0,99},{7,0,1962},{7,0,1986},{8,0,515},{8,0, +773},{9,0,23},{9,0,491},{12,0,620},{142,0,93},{133,0,851},{5,11,33},{134,11,470} +,{135,11,1291},{134,0,1278},{135,11,1882},{135,10,1489},{132,0,1000},{138,0,982} +,{8,0,762},{8,0,812},{137,0,910},{6,11,47},{7,11,90},{7,11,664},{7,11,830},{7,11 +,1380},{7,11,2025},{8,11,448},{136,11,828},{4,0,98},{4,0,940},{6,0,1819},{6,0, +1834},{6,0,1841},{7,0,1365},{8,0,859},{8,0,897},{8,0,918},{8,10,398},{9,0,422},{ +9,0,670},{9,10,681},{10,0,775},{10,0,894},{10,0,909},{10,0,910},{10,0,935},{11,0 +,210},{11,10,632},{12,0,750},{12,0,755},{13,0,26},{13,0,457},{13,0,476},{16,0, +100},{16,0,109},{18,0,173},{146,0,175},{9,11,417},{137,11,493},{136,10,645},{138 +,0,906},{134,0,1730},{134,10,20},{133,11,1019},{134,0,1185},{8,10,769},{138,0,40 +},{6,11,208},{137,0,147},{140,0,650},{5,0,209},{6,0,30},{11,0,56},{139,0,305},{ +132,0,553},{138,11,344},{6,11,68},{7,11,398},{7,11,448},{7,11,1629},{7,11,1813}, +{8,11,387},{8,11,442},{9,11,710},{10,11,282},{138,11,722},{5,0,597},{14,0,20},{ +142,11,20},{135,0,1614},{135,10,1757},{4,0,150},{5,0,303},{6,0,327},{135,10,937} +,{7,10,1652},{16,0,49},{144,11,49},{8,0,192},{10,0,78},{141,0,359},{135,0,786},{ +143,0,134},{6,0,1638},{7,0,79},{7,0,496},{9,0,138},{10,0,336},{11,0,12},{12,0, +412},{12,0,440},{142,0,305},{136,11,491},{4,10,579},{5,10,226},{5,10,323},{135, +10,960},{7,0,204},{7,0,415},{8,0,42},{10,0,85},{139,0,564},{132,0,614},{4,11,403 +},{5,11,441},{7,11,450},{11,11,101},{12,11,193},{141,11,430},{135,11,1927},{135, +11,1330},{4,0,3},{5,0,247},{5,0,644},{7,0,744},{7,0,1207},{7,0,1225},{7,0,1909}, +{146,0,147},{136,0,942},{4,0,1019},{134,0,2023},{5,10,973},{133,11,679},{5,0,285 +},{9,0,67},{13,0,473},{143,0,82},{7,11,328},{137,11,326},{151,0,8},{6,10,135},{ +135,10,1176},{135,11,1128},{134,0,1309},{135,11,1796},{135,10,314},{4,11,574},{7 +,11,350},{7,11,1024},{8,11,338},{9,11,677},{10,11,808},{139,11,508},{7,11,818},{ +17,11,14},{17,11,45},{18,11,75},{148,11,18},{146,10,4},{135,11,1081},{4,0,29},{6 +,0,532},{7,0,1628},{7,0,1648},{9,0,350},{10,0,433},{11,0,97},{11,0,557},{11,0, +745},{12,0,289},{12,0,335},{12,0,348},{12,0,606},{13,0,116},{13,0,233},{13,0,466 +},{14,0,181},{14,0,209},{14,0,232},{14,0,236},{14,0,300},{16,0,41},{148,0,97},{6 +,10,281},{7,0,318},{8,10,282},{8,10,480},{8,10,499},{9,10,198},{10,10,143},{10, +10,169},{10,10,211},{10,10,417},{10,10,574},{11,10,147},{11,10,395},{12,10,75},{ +12,10,407},{12,10,608},{13,10,500},{142,10,251},{135,11,1676},{135,11,2037},{135 +,0,1692},{5,0,501},{7,0,1704},{9,0,553},{11,0,520},{12,0,557},{141,0,249},{6,0, +1527},{14,0,324},{14,11,324},{15,0,55},{15,0,80},{15,11,55},{143,11,80},{135,10, +1776},{8,0,988},{137,11,297},{132,10,419},{142,0,223},{139,11,234},{7,0,1123},{ +12,0,508},{14,0,102},{14,0,226},{144,0,57},{4,10,138},{7,10,1012},{7,10,1280},{ +137,10,76},{5,10,29},{7,0,1764},{140,10,638},{134,0,2015},{134,0,1599},{138,11, +56},{6,11,306},{7,11,1140},{7,11,1340},{8,11,133},{138,11,449},{139,11,1011},{6, +10,1710},{135,10,2038},{7,11,1763},{140,11,310},{4,10,17},{5,10,23},{6,0,129},{7 +,10,995},{11,10,383},{11,10,437},{12,10,460},{140,10,532},{5,11,329},{136,11,260 +},{133,10,862},{132,0,534},{6,0,811},{135,0,626},{132,11,657},{4,0,25},{5,0,60}, +{6,0,504},{7,0,614},{7,0,1155},{12,0,0},{152,11,7},{7,0,1248},{11,0,621},{139,0, +702},{137,0,321},{8,10,70},{12,10,171},{141,10,272},{10,10,233},{139,10,76},{4,0 +,379},{6,10,442},{135,0,1397},{5,11,66},{7,11,1896},{136,11,288},{134,11,1643},{ +134,10,1709},{4,11,21},{5,11,91},{5,11,570},{5,11,648},{5,11,750},{5,11,781},{6, +11,54},{6,11,112},{6,11,402},{6,11,1732},{7,11,315},{7,11,749},{7,11,1347},{7,11 +,1900},{9,11,78},{9,11,508},{10,11,611},{11,11,510},{11,11,728},{13,11,36},{14, +11,39},{16,11,83},{17,11,124},{148,11,30},{4,0,118},{6,0,274},{6,0,361},{7,0,75} +,{141,0,441},{10,11,322},{10,11,719},{139,11,407},{147,10,119},{12,11,549},{14, +11,67},{147,11,60},{11,10,69},{12,10,105},{12,10,117},{13,10,213},{14,10,13},{14 +,10,62},{14,10,177},{14,10,421},{15,10,19},{146,10,141},{9,0,841},{137,10,309},{ +7,10,608},{7,10,976},{8,11,125},{8,11,369},{8,11,524},{9,10,146},{10,10,206},{10 +,10,596},{10,11,486},{11,11,13},{11,11,381},{11,11,736},{11,11,766},{11,11,845}, +{13,10,218},{13,11,114},{13,11,292},{14,10,153},{142,11,47},{7,11,759},{140,0, +693},{5,0,314},{6,0,221},{7,0,419},{10,0,650},{11,0,396},{12,0,156},{13,0,369},{ +14,0,333},{145,0,47},{6,11,1684},{6,11,1731},{7,11,356},{7,11,1932},{8,11,54},{8 +,11,221},{9,11,225},{9,11,356},{10,11,77},{10,11,446},{10,11,731},{12,11,404},{ +141,11,491},{132,11,375},{4,10,518},{135,10,1136},{4,0,913},{4,11,411},{11,11, +643},{140,11,115},{4,11,80},{133,11,44},{8,10,689},{137,10,863},{138,0,880},{4, +10,18},{7,10,145},{7,10,444},{7,10,1278},{8,10,49},{8,10,400},{9,10,71},{9,10, +250},{10,10,459},{12,10,160},{144,10,24},{136,0,475},{5,0,1016},{5,11,299},{135, +11,1083},{7,0,602},{8,0,179},{10,0,781},{140,0,126},{6,0,329},{138,0,111},{135,0 +,1864},{4,11,219},{7,11,1761},{137,11,86},{6,0,1888},{6,0,1892},{6,0,1901},{6,0, +1904},{9,0,953},{9,0,985},{9,0,991},{9,0,1001},{12,0,818},{12,0,846},{12,0,847}, +{12,0,861},{12,0,862},{12,0,873},{12,0,875},{12,0,877},{12,0,879},{12,0,881},{12 +,0,884},{12,0,903},{12,0,915},{12,0,926},{12,0,939},{15,0,182},{15,0,219},{15,0, +255},{18,0,191},{18,0,209},{18,0,211},{149,0,41},{5,11,328},{135,11,918},{137,0, +780},{12,0,82},{143,0,36},{133,10,1010},{5,0,821},{134,0,1687},{133,11,514},{132 +,0,956},{134,0,1180},{5,10,87},{7,10,313},{7,10,1103},{10,0,112},{10,10,582},{11 +,10,389},{11,10,813},{12,10,385},{13,10,286},{14,10,124},{146,10,108},{5,0,71},{ +7,0,1407},{9,0,704},{10,0,261},{10,0,619},{11,0,547},{11,0,619},{143,0,157},{4,0 +,531},{5,0,455},{5,11,301},{6,11,571},{14,11,49},{146,11,102},{132,10,267},{6,0, +385},{7,0,2008},{9,0,337},{138,0,517},{133,11,726},{133,11,364},{4,11,76},{7,11, +1550},{9,11,306},{9,11,430},{9,11,663},{10,11,683},{11,11,427},{11,11,753},{12, +11,334},{12,11,442},{14,11,258},{14,11,366},{143,11,131},{6,0,1865},{6,0,1879},{ +6,0,1881},{6,0,1894},{6,0,1908},{9,0,915},{9,0,926},{9,0,940},{9,0,943},{9,0,966 +},{9,0,980},{9,0,989},{9,0,1005},{9,0,1010},{12,0,813},{12,0,817},{12,0,840},{12 +,0,843},{12,0,855},{12,0,864},{12,0,871},{12,0,872},{12,0,899},{12,0,905},{12,0, +924},{15,0,171},{15,0,181},{15,0,224},{15,0,235},{15,0,251},{146,0,184},{137,11, +52},{5,0,16},{6,0,86},{6,0,603},{7,0,292},{7,0,561},{8,0,257},{8,0,382},{9,0,721 +},{9,0,778},{11,0,581},{140,0,466},{4,0,486},{5,0,491},{135,10,1121},{4,0,72},{6 +,0,265},{135,0,1300},{135,11,1183},{10,10,249},{139,10,209},{132,10,561},{137,11 +,519},{4,10,760},{4,11,656},{135,11,779},{9,10,154},{140,10,485},{135,11,1793},{ +135,11,144},{136,10,255},{133,0,621},{4,10,368},{135,10,641},{135,11,1373},{7,11 +,554},{7,11,605},{141,11,10},{137,0,234},{5,0,815},{6,0,1688},{134,0,1755},{5,11 +,838},{5,11,841},{134,11,1649},{7,0,1987},{7,0,2040},{136,0,743},{133,11,1012},{ +6,0,197},{136,0,205},{6,0,314},{134,11,314},{144,11,53},{6,11,251},{7,11,365},{7 +,11,1357},{7,11,1497},{8,11,154},{141,11,281},{133,11,340},{6,0,452},{7,0,312},{ +138,0,219},{138,0,589},{4,0,333},{9,0,176},{12,0,353},{141,0,187},{9,10,92},{147 +,10,91},{134,0,1110},{11,0,47},{139,11,495},{6,10,525},{8,10,806},{9,10,876},{ +140,10,284},{8,11,261},{9,11,144},{9,11,466},{10,11,370},{12,11,470},{13,11,144} +,{142,11,348},{137,11,897},{6,11,248},{8,0,863},{8,0,864},{8,0,868},{8,0,884},{9 +,11,546},{10,0,866},{10,0,868},{10,0,873},{10,0,911},{10,0,912},{10,0,944},{10, +11,535},{11,11,681},{12,0,727},{141,11,135},{6,0,300},{135,0,1515},{134,0,1237}, +{139,10,958},{133,10,594},{140,11,250},{134,0,1685},{134,11,567},{7,0,135},{8,0, +7},{8,0,62},{9,0,243},{10,0,658},{10,0,697},{11,0,456},{139,0,756},{9,0,395},{ +138,0,79},{6,10,1641},{136,10,820},{4,10,302},{135,10,1766},{134,11,174},{135,10 +,1313},{135,0,631},{134,10,1674},{134,11,395},{138,0,835},{7,0,406},{7,0,459},{8 +,0,606},{139,0,726},{134,11,617},{134,0,979},{6,10,389},{7,10,149},{9,10,142},{ +138,10,94},{5,11,878},{133,11,972},{6,10,8},{7,10,1881},{8,10,91},{136,11,511},{ +133,0,612},{132,11,351},{4,0,372},{7,0,482},{8,0,158},{9,0,602},{9,0,615},{10,0, +245},{10,0,678},{10,0,744},{11,0,248},{139,0,806},{5,0,854},{135,0,1991},{132,11 +,286},{135,11,344},{7,11,438},{7,11,627},{7,11,1516},{8,11,40},{9,11,56},{9,11, +294},{10,11,30},{10,11,259},{11,11,969},{146,11,148},{135,0,1492},{5,11,259},{7, +11,414},{7,11,854},{142,11,107},{135,10,1746},{6,0,833},{134,0,998},{135,10,24}, +{6,0,750},{135,0,1739},{4,10,503},{135,10,1661},{5,10,130},{7,10,1314},{9,10,610 +},{10,10,718},{11,10,601},{11,10,819},{11,10,946},{140,10,536},{10,10,149},{11, +10,280},{142,10,336},{132,11,738},{135,10,1946},{5,0,195},{135,0,1685},{7,0,1997 +},{8,0,730},{139,0,1006},{151,11,17},{133,11,866},{14,0,463},{14,0,470},{150,0, +61},{4,10,392},{5,0,751},{7,10,1597},{8,0,266},{139,0,578},{5,10,433},{9,10,633} +,{139,10,629},{135,0,821},{6,0,715},{134,0,1325},{133,11,116},{4,11,457},{134,0, +868},{134,0,959},{6,10,234},{138,11,199},{7,0,1053},{7,10,1950},{8,10,680},{11, +10,817},{147,10,88},{7,10,1222},{138,10,386},{5,0,950},{5,0,994},{6,0,351},{134, +0,1124},{134,0,1081},{6,10,5},{7,0,1595},{11,10,249},{12,10,313},{16,10,66},{145 +,10,26},{148,0,59},{5,11,527},{6,11,189},{135,11,859},{5,10,963},{6,10,1773},{11 +,11,104},{11,11,554},{15,11,60},{143,11,125},{135,0,47},{137,0,684},{134,11,116} +,{134,0,1606},{134,0,777},{7,0,1020},{8,10,509},{136,10,792},{135,0,1094},{132,0 +,350},{133,11,487},{4,11,86},{5,11,667},{5,11,753},{6,11,316},{6,11,455},{135,11 +,946},{7,0,1812},{13,0,259},{13,0,356},{14,0,242},{147,0,114},{132,10,931},{133, +0,967},{4,0,473},{7,0,623},{8,0,808},{9,0,871},{9,0,893},{11,0,38},{11,0,431},{ +12,0,112},{12,0,217},{12,0,243},{12,0,562},{12,0,663},{12,0,683},{13,0,141},{13, +0,197},{13,0,227},{13,0,406},{13,0,487},{14,0,156},{14,0,203},{14,0,224},{14,0, +256},{18,0,58},{150,0,0},{138,0,286},{7,10,943},{139,10,614},{135,10,1837},{150, +11,45},{132,0,798},{4,0,222},{7,0,286},{136,0,629},{4,11,79},{7,11,1773},{10,11, +450},{11,11,589},{13,11,332},{13,11,493},{14,11,183},{14,11,334},{14,11,362},{14 +,11,368},{14,11,376},{14,11,379},{19,11,90},{19,11,103},{19,11,127},{148,11,90}, +{4,10,90},{5,0,337},{5,10,545},{7,10,754},{9,10,186},{10,10,72},{10,10,782},{11, +0,513},{11,0,889},{11,0,961},{11,10,577},{11,10,610},{12,0,461},{12,10,354},{12, +10,362},{12,10,595},{13,0,79},{143,0,121},{141,0,306},{136,0,146},{7,0,1646},{9, +10,329},{11,10,254},{141,11,124},{4,0,465},{135,0,1663},{132,0,525},{133,11,663} +,{9,10,187},{10,0,299},{11,10,1016},{17,10,44},{146,0,74},{4,10,506},{7,0,165},{ +7,0,919},{136,10,517},{5,10,295},{135,10,1680},{133,11,846},{134,0,1064},{5,11, +378},{7,11,1402},{7,11,1414},{8,11,465},{9,11,286},{10,11,185},{10,11,562},{10, +11,635},{11,11,31},{11,11,393},{12,11,456},{13,11,312},{18,11,65},{18,11,96},{ +147,11,89},{132,0,596},{7,10,987},{9,10,688},{10,10,522},{11,10,788},{140,10,566 +},{4,11,648},{6,0,82},{6,10,1775},{7,0,138},{7,0,517},{7,0,1741},{139,0,238},{7, +0,1233},{7,10,700},{7,10,940},{8,10,514},{9,10,116},{9,10,535},{10,10,118},{11, +10,107},{11,10,148},{11,10,922},{12,10,254},{12,10,421},{142,10,238},{4,0,962},{ +6,0,1824},{8,0,894},{12,0,708},{12,0,725},{14,0,451},{20,0,94},{22,0,59},{150,0, +62},{5,11,945},{6,11,1656},{6,11,1787},{7,11,167},{8,11,824},{9,11,391},{10,11, +375},{139,11,185},{5,0,495},{7,0,834},{9,0,733},{139,0,378},{4,10,743},{135,11, +1273},{6,0,1204},{7,11,1645},{8,11,352},{137,11,249},{139,10,292},{133,0,559},{ +132,11,152},{7,10,1283},{9,0,499},{9,10,227},{10,0,341},{11,10,325},{11,10,408}, +{14,10,180},{15,0,144},{18,10,47},{147,0,49},{6,0,21},{6,0,1737},{7,0,1444},{136 +,0,224},{133,11,1006},{5,10,81},{7,0,1446},{7,10,146},{7,10,1342},{8,10,53},{8, +10,561},{8,10,694},{8,10,754},{9,0,97},{9,10,115},{9,10,894},{10,10,462},{10,10, +813},{11,10,230},{11,10,657},{11,10,699},{11,10,748},{12,10,119},{12,10,200},{12 +,10,283},{14,10,273},{145,0,15},{5,10,408},{137,10,747},{135,11,431},{135,11,832 +},{6,0,729},{134,0,953},{4,0,727},{5,11,351},{7,11,264},{8,0,565},{136,11,565},{ +134,0,1948},{5,0,519},{5,11,40},{7,11,598},{7,11,1638},{8,11,78},{9,11,166},{9, +11,640},{9,11,685},{9,11,773},{11,11,215},{13,11,65},{14,11,172},{14,11,317},{ +145,11,6},{8,11,60},{9,11,343},{139,11,769},{137,11,455},{134,0,1193},{140,0,790 +},{7,11,1951},{8,11,765},{8,11,772},{140,11,671},{7,11,108},{8,11,219},{8,11,388 +},{9,11,639},{9,11,775},{11,11,275},{140,11,464},{132,11,468},{7,10,30},{8,10,86 +},{8,10,315},{8,10,700},{9,10,576},{9,10,858},{11,10,310},{11,10,888},{11,10,904 +},{12,10,361},{141,10,248},{5,11,15},{6,11,56},{7,11,1758},{8,11,500},{9,11,730} +,{11,11,331},{13,11,150},{142,11,282},{4,0,402},{7,0,2},{8,0,323},{136,0,479},{ +138,10,839},{11,0,580},{142,0,201},{5,0,59},{135,0,672},{137,10,617},{146,0,34}, +{134,11,1886},{4,0,961},{136,0,896},{5,11,205},{6,0,1285},{6,11,438},{137,11,711 +},{134,10,428},{7,10,524},{8,10,169},{8,10,234},{9,10,480},{138,10,646},{148,0, +46},{141,0,479},{133,11,534},{6,0,2019},{134,10,1648},{4,0,85},{7,0,549},{7,10, +1205},{138,10,637},{4,0,663},{5,0,94},{7,11,235},{7,11,1475},{15,11,68},{146,11, +120},{6,11,443},{9,11,237},{9,11,571},{9,11,695},{10,11,139},{11,11,715},{12,11, +417},{141,11,421},{132,0,783},{4,0,682},{8,0,65},{9,10,39},{10,10,166},{11,10, +918},{12,10,635},{20,10,10},{22,10,27},{22,10,43},{150,10,52},{6,0,11},{135,0, +187},{132,0,522},{4,0,52},{135,0,661},{4,0,383},{133,0,520},{135,11,546},{11,0, +343},{142,0,127},{4,11,578},{7,10,157},{7,11,624},{7,11,916},{8,10,279},{10,11, +256},{11,11,87},{139,11,703},{134,10,604},{4,0,281},{5,0,38},{7,0,194},{7,0,668} +,{7,0,1893},{137,0,397},{7,10,945},{11,10,713},{139,10,744},{139,10,1022},{9,0, +635},{139,0,559},{5,11,923},{7,11,490},{12,11,553},{13,11,100},{14,11,118},{143, +11,75},{132,0,975},{132,10,567},{137,10,859},{7,10,1846},{7,11,1846},{8,10,628}, +{136,11,628},{148,0,116},{138,11,750},{14,0,51},{14,11,51},{15,11,7},{148,11,20} +,{132,0,858},{134,0,1075},{4,11,924},{133,10,762},{136,0,535},{133,0,448},{10,10 +,784},{141,10,191},{133,10,298},{7,0,610},{135,0,1501},{7,10,633},{7,10,905},{7, +10,909},{7,10,1538},{9,10,767},{140,10,636},{4,11,265},{7,11,807},{135,11,950},{ +5,11,93},{12,11,267},{144,11,26},{136,0,191},{139,10,301},{135,10,1970},{135,0, +267},{4,0,319},{5,0,699},{138,0,673},{6,0,336},{7,0,92},{7,0,182},{8,0,453},{8,0 +,552},{9,0,204},{9,0,285},{10,0,99},{11,0,568},{11,0,950},{12,0,94},{12,10,644}, +{16,0,20},{16,0,70},{16,10,90},{147,0,55},{6,0,551},{7,0,1308},{7,10,845},{7,11, +994},{8,10,160},{137,10,318},{19,11,1},{19,11,26},{150,11,9},{7,0,1406},{9,0,218 +},{141,0,222},{5,0,256},{138,0,69},{5,11,233},{5,11,320},{6,11,140},{7,11,330},{ +136,11,295},{6,0,1980},{136,0,952},{4,0,833},{137,11,678},{133,11,978},{4,11,905 +},{6,11,1701},{137,11,843},{138,10,735},{136,10,76},{17,0,39},{148,0,36},{18,0, +81},{146,11,81},{14,0,352},{17,0,53},{18,0,146},{18,0,152},{19,0,11},{150,0,54}, +{135,0,634},{138,10,841},{132,0,618},{4,0,339},{4,11,275},{7,0,259},{12,11,376}, +{145,0,73},{132,11,509},{7,11,273},{139,11,377},{4,0,759},{9,10,804},{141,0,169} +,{6,10,96},{135,10,1426},{4,10,651},{133,10,289},{7,0,1075},{8,10,35},{9,10,511} +,{10,10,767},{147,10,118},{6,0,649},{6,0,670},{136,0,482},{5,0,336},{6,0,341},{6 +,0,478},{6,0,1763},{136,0,386},{5,11,802},{7,11,2021},{8,11,805},{14,11,94},{15, +11,65},{16,11,4},{16,11,77},{16,11,80},{145,11,5},{5,11,167},{5,11,899},{6,0, +1035},{6,11,410},{137,11,777},{134,11,1705},{5,0,924},{133,0,969},{132,10,704},{ +135,0,73},{135,11,10},{135,10,1078},{5,11,11},{6,11,117},{6,11,485},{7,11,1133}, +{9,11,582},{9,11,594},{11,11,21},{11,11,818},{12,11,535},{141,11,86},{135,0,1971 +},{4,11,264},{7,11,1067},{8,11,204},{8,11,385},{139,11,953},{6,0,1458},{135,0, +1344},{5,0,396},{134,0,501},{4,10,720},{133,10,306},{4,0,929},{5,0,799},{5,10, +431},{8,0,46},{136,0,740},{7,11,646},{7,11,1730},{11,11,446},{141,11,178},{5,10, +464},{6,10,236},{7,0,276},{7,10,696},{7,10,914},{7,10,1108},{7,10,1448},{9,10,15 +},{9,10,564},{10,10,14},{12,10,565},{13,10,449},{14,10,53},{15,10,13},{16,10,64} +,{145,10,41},{4,0,892},{133,0,770},{6,10,1767},{12,10,194},{145,10,107},{135,0, +158},{5,10,840},{138,11,608},{134,0,1432},{138,11,250},{8,11,794},{9,11,400},{10 +,11,298},{142,11,228},{151,0,25},{7,11,1131},{135,11,1468},{135,0,2001},{9,10, +642},{11,10,236},{142,10,193},{4,10,68},{5,10,634},{6,10,386},{7,10,794},{8,10, +273},{9,10,563},{10,10,105},{10,10,171},{11,10,94},{139,10,354},{136,11,724},{ +132,0,478},{11,11,512},{13,11,205},{19,11,30},{22,11,36},{151,11,19},{7,0,1461}, +{140,0,91},{6,11,190},{7,11,768},{135,11,1170},{4,0,602},{4,10,95},{7,10,416},{8 +,0,211},{139,10,830},{7,10,731},{13,10,20},{143,10,11},{6,0,1068},{135,0,1872},{ +4,0,13},{5,0,567},{7,0,1498},{7,11,1023},{9,0,124},{11,0,521},{140,0,405},{135,0 +,1006},{132,0,735},{138,0,812},{4,0,170},{135,0,323},{6,11,137},{9,11,75},{9,11, +253},{10,11,194},{138,11,444},{5,0,304},{5,10,864},{7,0,1403},{10,10,648},{11,10 +,671},{143,10,46},{135,11,1180},{133,10,928},{4,0,148},{133,0,742},{11,10,986},{ +140,10,682},{133,0,523},{135,11,1743},{7,0,730},{8,10,44},{9,10,884},{10,10,580} +,{11,10,399},{11,10,894},{15,10,122},{18,0,144},{147,0,61},{5,11,760},{7,11,542} +,{8,11,135},{136,11,496},{136,0,981},{133,0,111},{10,0,132},{11,0,191},{11,0,358 +},{139,0,460},{7,11,319},{7,11,355},{7,11,763},{10,11,389},{145,11,43},{134,0, +890},{134,0,1420},{136,11,557},{133,10,518},{133,0,444},{135,0,1787},{135,10, +1852},{8,0,123},{15,0,6},{144,0,7},{6,0,2041},{10,11,38},{139,11,784},{136,0,932 +},{5,0,937},{135,0,100},{4,11,58},{5,11,286},{6,0,995},{6,11,319},{7,11,402},{7, +11,1254},{7,11,1903},{8,11,356},{140,11,408},{4,11,389},{9,11,181},{9,11,255},{ +10,11,8},{10,11,29},{10,11,816},{11,11,311},{11,11,561},{12,11,67},{141,11,181}, +{138,0,255},{4,10,934},{5,0,138},{136,10,610},{4,0,965},{10,0,863},{138,0,898},{ +10,10,804},{138,10,832},{8,10,96},{9,10,36},{10,10,607},{11,10,423},{11,10,442}, +{12,0,631},{12,10,309},{14,10,199},{15,10,90},{145,10,110},{134,0,1394},{4,0,652 +},{8,0,320},{9,10,13},{9,10,398},{9,10,727},{10,10,75},{10,10,184},{10,10,230},{ +10,10,564},{10,10,569},{11,10,973},{12,10,70},{12,10,189},{13,10,57},{13,10,257} +,{22,0,6},{150,0,16},{6,0,897},{134,0,1333},{4,0,692},{133,0,321},{133,11,373},{ +135,0,922},{5,0,619},{133,0,698},{137,10,631},{5,10,345},{135,10,1016},{9,0,957} +,{9,0,1018},{12,0,828},{12,0,844},{12,0,897},{12,0,901},{12,0,943},{15,0,180},{ +18,0,197},{18,0,200},{18,0,213},{18,0,214},{146,0,226},{5,0,917},{134,0,1659},{ +135,0,1100},{134,0,1173},{134,0,1930},{5,0,251},{5,0,956},{8,0,268},{9,0,214},{ +146,0,142},{133,10,673},{137,10,850},{4,10,287},{133,10,1018},{132,11,672},{5,0, +346},{5,0,711},{8,0,390},{11,11,752},{139,11,885},{5,10,34},{10,10,724},{12,10, +444},{13,10,354},{18,10,32},{23,10,24},{23,10,31},{152,10,5},{4,11,710},{134,11, +606},{134,0,744},{134,10,382},{133,11,145},{4,10,329},{7,11,884},{140,11,124},{4 +,11,467},{5,11,405},{134,11,544},{9,10,846},{138,10,827},{133,0,624},{9,11,372}, +{15,11,2},{19,11,10},{147,11,18},{4,11,387},{135,11,1288},{5,0,783},{7,0,1998},{ +135,0,2047},{132,10,906},{136,10,366},{135,11,550},{4,10,123},{4,10,649},{5,10, +605},{7,10,1509},{136,10,36},{134,0,1125},{132,0,594},{133,10,767},{135,11,1227} +,{136,11,467},{4,11,576},{135,11,1263},{4,0,268},{7,0,1534},{135,11,1534},{4,10, +273},{5,10,658},{5,10,995},{5,11,919},{134,11,1673},{133,0,563},{134,10,72},{135 +,10,1345},{4,11,82},{5,11,333},{5,11,904},{6,11,207},{7,11,325},{7,11,1726},{8, +11,101},{10,11,778},{139,11,220},{5,0,37},{5,10,589},{6,0,39},{6,0,451},{7,0,218 +},{7,0,667},{7,0,1166},{7,0,1687},{8,0,662},{144,0,2},{134,0,1332},{133,11,903}, +{134,0,508},{5,10,117},{6,10,514},{6,10,541},{7,10,1164},{7,10,1436},{8,10,220}, +{8,10,648},{10,10,688},{11,10,560},{140,11,147},{6,11,555},{135,11,485},{133,10, +686},{7,0,453},{7,0,635},{7,0,796},{8,0,331},{9,0,330},{9,0,865},{10,0,119},{10, +0,235},{11,0,111},{11,0,129},{11,0,240},{12,0,31},{12,0,66},{12,0,222},{12,0,269 +},{12,0,599},{12,0,684},{12,0,689},{12,0,691},{142,0,345},{135,0,1834},{4,11,705 +},{7,11,615},{138,11,251},{136,11,345},{137,0,527},{6,0,98},{7,0,702},{135,0,991 +},{7,10,196},{10,10,765},{11,0,576},{11,10,347},{11,10,552},{11,10,790},{12,10, +263},{13,10,246},{13,10,270},{13,10,395},{14,0,74},{14,10,176},{14,10,190},{14, +10,398},{14,10,412},{15,10,32},{15,10,63},{16,10,88},{147,10,105},{134,11,90},{ +13,0,84},{141,0,122},{6,0,37},{7,0,299},{7,0,1666},{8,0,195},{8,0,316},{9,0,178} +,{9,0,276},{9,0,339},{9,0,536},{10,0,102},{10,0,362},{10,0,785},{11,0,55},{11,0, +149},{11,0,773},{13,0,416},{13,0,419},{14,0,38},{14,0,41},{142,0,210},{5,10,381} +,{135,10,1792},{7,11,813},{12,11,497},{141,11,56},{7,10,616},{138,10,413},{133,0 +,645},{6,11,125},{135,11,1277},{132,0,290},{6,0,70},{7,0,1292},{10,0,762},{139,0 +,288},{6,10,120},{7,10,1188},{7,10,1710},{8,10,286},{9,10,667},{11,10,592},{139, +10,730},{135,11,1784},{7,0,1315},{135,11,1315},{134,0,1955},{135,10,1146},{7,0, +131},{7,0,422},{8,0,210},{140,0,573},{4,10,352},{135,10,687},{139,0,797},{143,0, +38},{14,0,179},{15,0,151},{150,0,11},{4,10,192},{5,10,49},{6,10,200},{6,10,293}, +{6,10,1696},{135,0,488},{132,0,936},{135,11,703},{6,11,160},{7,11,1106},{9,11, +770},{10,11,618},{11,11,112},{140,11,413},{5,0,453},{134,0,441},{135,0,595},{132 +,10,650},{132,10,147},{6,0,991},{6,0,1182},{12,11,271},{145,11,109},{133,10,934} +,{140,11,221},{132,0,653},{7,0,505},{135,0,523},{134,0,903},{135,11,479},{7,11, +304},{9,11,646},{9,11,862},{10,11,262},{11,11,696},{12,11,208},{15,11,79},{147, +11,108},{146,0,80},{135,11,981},{142,0,432},{132,0,314},{137,11,152},{7,0,1368}, +{8,0,232},{8,0,361},{10,0,682},{138,0,742},{135,11,1586},{4,11,434},{9,0,534},{ +11,11,663},{12,11,210},{13,11,166},{13,11,310},{14,11,373},{147,11,43},{7,11, +1091},{135,11,1765},{6,11,550},{135,11,652},{137,0,27},{142,0,12},{4,10,637},{5, +11,553},{7,11,766},{138,11,824},{7,11,737},{8,11,298},{136,11,452},{7,0,736},{ +139,0,264},{134,0,1657},{133,11,292},{138,11,135},{6,0,844},{134,0,1117},{135,0, +127},{9,10,867},{138,10,837},{6,0,1184},{134,0,1208},{134,0,1294},{136,0,364},{6 +,0,1415},{6,10,170},{7,0,1334},{7,11,393},{8,10,395},{8,10,487},{10,11,603},{11, +0,125},{11,11,206},{141,10,147},{137,11,748},{4,11,912},{137,11,232},{4,10,535}, +{136,10,618},{137,0,792},{7,11,1973},{136,11,716},{135,11,98},{5,0,909},{9,0,849 +},{138,0,805},{4,0,630},{132,0,699},{5,11,733},{14,11,103},{150,10,23},{12,11, +158},{18,11,8},{19,11,62},{20,11,6},{22,11,4},{23,11,2},{151,11,9},{132,0,968},{ +132,10,778},{132,10,46},{5,10,811},{6,10,1679},{6,10,1714},{135,10,2032},{6,0, +1446},{7,10,1458},{9,10,407},{139,10,15},{6,10,34},{7,0,206},{7,0,397},{7,0,621} +,{7,0,640},{7,10,1089},{8,0,124},{8,0,619},{8,10,708},{8,10,721},{9,0,305},{9,0, +643},{9,10,363},{10,0,264},{10,0,628},{11,0,40},{12,0,349},{13,0,134},{13,0,295} +,{14,0,155},{15,0,120},{18,0,105},{148,10,98},{4,0,262},{5,0,641},{135,0,342},{ +137,11,72},{4,0,99},{6,0,250},{6,0,346},{8,0,127},{138,0,81},{132,0,915},{5,0,75 +},{9,0,517},{10,0,470},{12,0,155},{141,0,224},{132,10,462},{11,11,600},{11,11, +670},{141,11,245},{142,0,83},{5,10,73},{6,10,23},{134,10,338},{6,0,1031},{139,11 +,923},{7,11,164},{7,11,1571},{9,11,107},{140,11,225},{134,0,1470},{133,0,954},{6 +,0,304},{8,0,418},{10,0,345},{11,0,341},{139,0,675},{9,0,410},{139,0,425},{4,11, +27},{5,11,484},{5,11,510},{6,11,434},{7,11,1000},{7,11,1098},{8,11,2},{136,11, +200},{134,0,734},{140,11,257},{7,10,725},{8,10,498},{139,10,268},{134,0,1822},{ +135,0,1798},{135,10,773},{132,11,460},{4,11,932},{133,11,891},{134,0,14},{132,10 +,583},{7,10,1462},{8,11,625},{139,10,659},{5,0,113},{5,10,220},{6,0,243},{6,0, +1708},{7,0,1865},{11,0,161},{16,0,37},{145,0,99},{134,11,76},{5,11,461},{135,11, +1925},{140,0,69},{8,11,92},{137,11,221},{139,10,803},{132,10,544},{4,0,274},{134 +,0,922},{132,0,541},{5,0,627},{6,10,437},{6,10,564},{11,10,181},{141,10,183},{ +135,10,1192},{4,11,763},{135,0,166},{133,11,253},{134,0,849},{9,11,73},{10,11, +110},{14,11,185},{145,11,119},{5,11,212},{12,11,35},{141,11,382},{133,0,717},{ +137,0,304},{136,0,600},{133,0,654},{6,0,273},{10,0,188},{13,0,377},{146,0,77},{4 +,10,790},{5,10,273},{134,10,394},{132,0,543},{135,0,410},{11,0,98},{11,0,524},{ +141,0,87},{132,0,941},{135,11,1175},{4,0,250},{6,10,127},{7,0,1612},{7,10,1511}, +{8,10,613},{11,0,186},{12,0,133},{12,10,495},{12,10,586},{12,10,660},{12,10,668} +,{14,10,385},{15,10,118},{17,10,20},{146,10,98},{5,11,816},{134,0,1785},{134,0, +1339},{6,10,230},{7,0,961},{7,0,1085},{7,0,1727},{7,11,1727},{136,0,462},{7,10, +1954},{137,0,636},{132,0,780},{5,11,869},{5,11,968},{6,11,1626},{8,11,734},{136, +11,784},{4,11,542},{6,11,1716},{6,11,1727},{7,11,1082},{7,11,1545},{8,11,56},{8, +11,118},{8,11,412},{8,11,564},{9,11,888},{9,11,908},{10,11,50},{10,11,423},{11, +11,685},{11,11,697},{11,11,933},{12,11,299},{13,11,126},{13,11,136},{13,11,170}, +{141,11,190},{134,11,226},{4,11,232},{9,11,202},{10,11,474},{140,11,433},{137,11 +,500},{5,0,529},{136,10,68},{132,10,654},{4,10,156},{7,10,998},{7,10,1045},{7,10 +,1860},{9,10,48},{9,10,692},{11,10,419},{139,10,602},{6,11,108},{7,0,1276},{7,11 +,1003},{7,11,1181},{8,0,474},{8,11,343},{137,0,652},{7,11,1264},{7,11,1678},{11, +11,945},{12,11,341},{12,11,471},{140,11,569},{134,11,1712},{5,0,948},{12,0,468}, +{19,0,96},{148,0,24},{4,11,133},{7,11,711},{7,11,1298},{7,11,1585},{135,11,1929} +,{6,0,753},{140,0,657},{139,0,941},{6,11,99},{7,11,1808},{145,11,57},{6,11,574}, +{7,11,428},{7,11,1250},{10,11,669},{11,11,485},{11,11,840},{12,11,300},{142,11, +250},{4,0,532},{5,0,706},{135,0,662},{5,0,837},{6,0,1651},{139,0,985},{7,0,1861} +,{9,10,197},{10,10,300},{12,10,473},{13,10,90},{141,10,405},{137,11,252},{6,11, +323},{135,11,1564},{4,0,330},{4,0,863},{7,0,933},{7,0,2012},{7,11,461},{8,0,292} +,{8,11,775},{138,11,435},{132,10,606},{4,11,655},{7,11,850},{17,11,75},{146,11, +137},{135,0,767},{7,10,1978},{136,10,676},{132,0,641},{135,11,1559},{134,0,1233} +,{137,0,242},{4,10,361},{5,10,315},{145,0,114},{137,0,883},{132,10,461},{138,0, +274},{134,0,2008},{134,0,1794},{4,0,703},{135,0,207},{4,10,472},{140,0,285},{132 +,0,571},{5,0,873},{5,0,960},{8,0,823},{8,11,577},{137,0,881},{7,0,617},{10,0,498 +},{11,0,501},{12,0,16},{140,0,150},{138,10,747},{132,0,431},{133,10,155},{7,10, +163},{8,10,319},{9,10,402},{10,10,24},{10,10,681},{11,0,283},{11,0,567},{11,10, +200},{12,10,253},{12,10,410},{142,10,219},{4,11,413},{5,11,677},{8,11,432},{140, +11,280},{5,10,475},{7,10,1780},{9,0,401},{11,10,297},{11,10,558},{14,10,322},{ +147,10,76},{6,0,781},{9,0,134},{10,0,2},{10,0,27},{10,0,333},{11,0,722},{143,0,1 +},{5,0,33},{6,0,470},{139,0,424},{135,0,2006},{7,10,1956},{140,0,783},{136,0,274 +},{135,0,1882},{132,0,794},{135,0,1848},{5,10,944},{134,10,1769},{6,0,47},{7,0, +90},{7,0,664},{7,0,830},{7,0,1380},{7,0,2025},{8,0,448},{136,0,828},{132,10,144} +,{134,0,1199},{4,11,395},{139,11,762},{135,11,1504},{9,0,417},{137,0,493},{9,11, +174},{10,11,164},{11,11,440},{11,11,841},{143,11,98},{134,11,426},{139,11,1002}, +{134,0,295},{134,0,816},{6,10,247},{137,10,555},{133,0,1019},{4,0,620},{5,11,476 +},{10,10,280},{138,10,797},{139,0,464},{5,11,76},{6,11,458},{6,11,497},{7,11,764 +},{7,11,868},{9,11,658},{10,11,594},{11,11,173},{11,11,566},{12,11,20},{12,11, +338},{141,11,200},{134,0,208},{4,11,526},{7,11,1029},{135,11,1054},{132,11,636}, +{6,11,233},{7,11,660},{7,11,1124},{17,11,31},{19,11,22},{151,11,14},{5,10,428},{ +138,0,442},{10,0,930},{140,0,778},{6,0,68},{7,0,448},{7,0,1629},{7,0,1769},{7,0, +1813},{7,10,1717},{8,0,442},{8,0,516},{9,0,710},{10,0,282},{10,0,722},{138,10, +546},{134,0,1128},{11,0,844},{12,0,104},{140,0,625},{4,11,432},{135,11,824},{138 +,10,189},{133,0,787},{133,10,99},{4,11,279},{7,11,301},{137,11,362},{4,10,397},{ +8,0,491},{136,10,555},{4,11,178},{133,11,399},{134,0,711},{144,0,9},{4,0,403},{5 +,0,441},{7,0,450},{10,0,840},{11,0,101},{12,0,193},{141,0,430},{135,11,1246},{12 +,10,398},{20,10,39},{21,10,11},{150,10,41},{4,10,485},{7,10,353},{135,10,1523},{ +6,10,366},{7,10,1384},{7,10,1601},{135,11,1912},{7,0,396},{7,11,396},{138,0,160} +,{137,10,282},{134,11,1692},{4,10,157},{5,10,471},{6,11,202},{10,11,448},{11,11, +208},{12,11,360},{17,11,117},{17,11,118},{18,11,27},{148,11,67},{133,0,679},{137 +,0,326},{136,10,116},{7,11,872},{10,11,516},{139,11,167},{132,11,224},{5,11,546} +,{7,11,35},{8,11,11},{8,11,12},{9,11,315},{9,11,533},{10,11,802},{11,11,166},{12 +,11,525},{142,11,243},{7,0,1128},{135,11,1920},{5,11,241},{8,11,242},{9,11,451}, +{10,11,667},{11,11,598},{140,11,429},{5,10,160},{6,0,737},{7,10,363},{7,10,589}, +{10,10,170},{141,10,55},{135,0,1796},{142,11,254},{4,0,574},{7,0,350},{7,0,1024} +,{8,0,338},{9,0,677},{138,0,808},{134,0,1096},{137,11,516},{4,10,108},{4,11,366} +,{7,0,405},{10,0,491},{139,10,498},{11,11,337},{142,11,303},{134,11,1736},{7,0, +1081},{140,11,364},{7,10,1005},{140,10,609},{4,10,895},{5,10,772},{135,0,1676},{ +135,0,2037},{6,0,1207},{11,11,916},{142,11,419},{14,11,140},{148,11,41},{6,11, +331},{136,11,623},{4,10,926},{5,10,983},{9,0,944},{9,0,969},{9,0,1022},{12,0,913 +},{12,0,936},{15,0,177},{143,0,193},{5,0,354},{135,11,506},{8,0,598},{9,0,664},{ +138,0,441},{4,11,640},{133,11,513},{137,0,297},{132,10,538},{6,10,294},{7,10, +1267},{136,10,624},{7,0,1772},{7,11,1888},{8,11,289},{11,11,45},{12,11,278},{140 +,11,537},{135,10,1325},{138,0,751},{141,0,37},{134,0,1828},{132,10,757},{132,11, +394},{6,0,257},{135,0,1522},{4,0,582},{7,11,1931},{137,0,191},{7,11,574},{7,11, +1719},{137,11,145},{132,11,658},{4,11,369},{138,0,790},{9,11,781},{10,11,144},{ +11,11,385},{13,11,161},{13,11,228},{13,11,268},{148,11,107},{8,0,469},{8,11,374} +,{138,0,47},{6,0,306},{7,0,1140},{7,0,1340},{8,0,133},{138,0,449},{139,0,1011},{ +7,10,1875},{139,10,124},{4,11,344},{6,11,498},{139,11,323},{137,0,299},{132,0, +837},{133,11,906},{5,0,329},{8,0,260},{138,0,10},{134,0,1320},{4,0,657},{146,0, +158},{135,0,1191},{152,0,7},{6,0,1939},{8,0,974},{138,0,996},{135,0,1665},{11,11 +,126},{139,11,287},{143,0,8},{14,11,149},{14,11,399},{143,11,57},{5,0,66},{7,0, +1896},{136,0,288},{5,10,150},{7,0,175},{8,10,603},{9,10,593},{9,10,634},{10,0, +494},{10,10,173},{11,10,462},{11,10,515},{13,10,216},{13,10,288},{142,10,400},{ +134,0,1643},{136,11,21},{4,0,21},{5,0,91},{5,0,648},{5,0,750},{5,0,781},{6,0,54} +,{6,0,112},{6,0,402},{6,0,1732},{7,0,315},{7,0,749},{7,0,1427},{7,0,1900},{9,0, +78},{9,0,508},{10,0,611},{10,0,811},{11,0,510},{11,0,728},{13,0,36},{14,0,39},{ +16,0,83},{17,0,124},{148,0,30},{4,0,668},{136,0,570},{10,0,322},{10,0,719},{139, +0,407},{135,11,1381},{136,11,193},{12,10,108},{141,10,291},{132,11,616},{136,11, +692},{8,0,125},{8,0,369},{8,0,524},{10,0,486},{11,0,13},{11,0,381},{11,0,736},{ +11,0,766},{11,0,845},{13,0,114},{13,0,292},{142,0,47},{134,0,1247},{6,0,1684},{6 +,0,1731},{7,0,356},{8,0,54},{8,0,221},{9,0,225},{9,0,356},{10,0,77},{10,0,446},{ +10,0,731},{12,0,404},{141,0,491},{135,10,1777},{4,10,493},{4,11,305},{144,10,55} +,{4,0,951},{6,0,1809},{6,0,1849},{8,0,846},{8,0,866},{8,0,899},{10,0,896},{12,0, +694},{142,0,468},{5,11,214},{7,11,603},{8,11,611},{9,11,686},{10,11,88},{11,11, +459},{11,11,496},{12,11,463},{12,11,590},{13,11,0},{142,11,214},{132,0,411},{4,0 +,80},{133,0,44},{140,11,74},{143,0,31},{6,10,568},{7,0,669},{7,10,1804},{8,10, +362},{8,10,410},{8,10,830},{9,10,514},{11,10,649},{142,10,157},{6,11,1703},{135, +0,673},{132,10,625},{134,0,1303},{5,0,299},{135,0,1083},{138,0,704},{6,0,275},{6 +,10,158},{7,0,408},{7,10,129},{7,10,181},{8,10,276},{8,10,377},{10,10,523},{11, +10,816},{12,10,455},{13,10,303},{142,10,135},{4,0,219},{7,0,367},{7,0,1713},{7,0 +,1761},{9,0,86},{9,0,537},{10,0,165},{12,0,219},{140,0,561},{4,10,1},{4,11,737}, +{6,11,317},{7,10,1143},{7,10,1463},{8,0,216},{9,10,207},{9,10,390},{9,10,467},{ +10,11,98},{11,10,836},{11,11,294},{12,11,60},{12,11,437},{13,11,64},{13,11,380}, +{142,11,430},{6,11,1758},{8,11,520},{9,11,345},{9,11,403},{142,11,350},{5,11,47} +,{10,11,242},{138,11,579},{5,11,139},{7,11,1168},{138,11,539},{135,0,1319},{4,10 +,295},{4,10,723},{5,10,895},{7,10,1031},{8,10,199},{8,10,340},{9,10,153},{9,10, +215},{10,10,21},{10,10,59},{10,10,80},{10,10,224},{10,10,838},{11,10,229},{11,10 +,652},{12,10,192},{13,10,146},{142,10,91},{140,0,428},{137,10,51},{133,0,514},{5 +,10,309},{140,10,211},{5,10,125},{6,0,1010},{8,10,77},{138,10,15},{4,0,55},{5,0, +301},{6,0,571},{142,0,49},{146,0,102},{136,11,370},{4,11,107},{7,11,613},{8,11, +358},{8,11,439},{8,11,504},{9,11,501},{10,11,383},{139,11,477},{132,11,229},{133 +,0,364},{133,10,439},{4,11,903},{135,11,1816},{11,0,379},{140,10,76},{4,0,76},{4 +,0,971},{7,0,1550},{9,0,306},{9,0,430},{9,0,663},{10,0,683},{10,0,921},{11,0,427 +},{11,0,753},{12,0,334},{12,0,442},{14,0,258},{14,0,366},{143,0,131},{137,0,52}, +{4,11,47},{6,11,373},{7,11,452},{7,11,543},{7,11,1714},{7,11,1856},{9,11,6},{11, +11,257},{139,11,391},{4,10,8},{7,10,1152},{7,10,1153},{7,10,1715},{9,10,374},{10 +,10,478},{139,10,648},{4,11,785},{133,11,368},{135,10,1099},{135,11,860},{5,11, +980},{134,11,1754},{134,0,1258},{6,0,1058},{6,0,1359},{7,11,536},{7,11,1331},{ +136,11,143},{4,0,656},{135,0,779},{136,10,87},{5,11,19},{6,11,533},{146,11,126}, +{7,0,144},{138,10,438},{5,11,395},{5,11,951},{134,11,1776},{135,0,1373},{7,0,554 +},{7,0,605},{141,0,10},{4,10,69},{5,10,122},{9,10,656},{138,10,464},{5,10,849},{ +134,10,1633},{5,0,838},{5,0,841},{134,0,1649},{133,0,1012},{139,10,499},{7,10, +476},{7,10,1592},{138,10,87},{6,0,251},{7,0,365},{7,0,1357},{7,0,1497},{8,0,154} +,{141,0,281},{132,11,441},{132,11,695},{7,11,497},{9,11,387},{147,11,81},{133,0, +340},{14,10,283},{142,11,283},{134,0,810},{135,11,1894},{139,0,495},{5,11,284},{ +6,11,49},{6,11,350},{7,11,1},{7,11,377},{7,11,1693},{8,11,18},{8,11,678},{9,11, +161},{9,11,585},{9,11,671},{9,11,839},{11,11,912},{141,11,427},{5,10,859},{7,10, +1160},{8,10,107},{9,10,291},{9,10,439},{10,10,663},{11,10,609},{140,10,197},{8,0 +,261},{9,0,144},{9,0,466},{10,0,370},{12,0,470},{13,0,144},{142,0,348},{137,0, +897},{6,0,248},{9,0,546},{10,0,535},{11,0,681},{141,0,135},{4,0,358},{135,0,1496 +},{134,0,567},{136,0,445},{4,10,117},{6,10,372},{7,10,1905},{142,10,323},{4,10, +722},{139,10,471},{6,0,697},{134,0,996},{7,11,2007},{9,11,101},{9,11,450},{10,11 +,66},{10,11,842},{11,11,536},{140,11,587},{132,0,577},{134,0,1336},{9,10,5},{12, +10,216},{12,10,294},{12,10,298},{12,10,400},{12,10,518},{13,10,229},{143,10,139} +,{6,0,174},{138,0,917},{134,10,1774},{5,10,12},{7,10,375},{9,10,88},{9,10,438},{ +11,10,270},{139,11,62},{134,11,1766},{6,11,0},{7,10,816},{7,10,1241},{7,11,84},{ +9,10,283},{9,10,520},{10,10,213},{10,10,307},{10,10,463},{10,10,671},{10,10,746} +,{11,10,401},{11,10,794},{11,11,895},{12,10,517},{17,11,11},{18,10,107},{147,10, +115},{5,0,878},{133,0,972},{6,11,1665},{7,11,256},{7,11,1388},{138,11,499},{4,10 +,258},{136,10,639},{4,11,22},{5,11,10},{6,10,22},{7,10,903},{7,10,1963},{7,11, +848},{8,11,97},{138,10,577},{5,10,681},{136,10,782},{133,11,481},{132,0,351},{4, +10,664},{5,10,804},{139,10,1013},{6,11,134},{7,11,437},{7,11,959},{9,11,37},{14, +11,285},{14,11,371},{144,11,60},{7,11,486},{8,11,155},{11,11,93},{140,11,164},{ +132,0,286},{7,0,438},{7,0,627},{7,0,1516},{8,0,40},{9,0,56},{9,0,294},{10,0,30}, +{11,0,969},{11,0,995},{146,0,148},{5,11,591},{135,11,337},{134,0,1950},{133,10, +32},{138,11,500},{5,11,380},{5,11,650},{136,11,310},{4,11,364},{7,11,1156},{7,11 +,1187},{137,11,409},{4,0,738},{134,11,482},{4,11,781},{6,11,487},{7,11,926},{8, +11,263},{139,11,500},{135,11,418},{4,10,289},{6,0,2047},{7,10,629},{7,10,1698},{ +7,10,1711},{10,0,969},{140,10,215},{6,10,450},{136,10,109},{134,0,818},{136,10, +705},{133,0,866},{4,11,94},{135,11,1265},{132,11,417},{134,0,1467},{135,10,1238} +,{4,0,972},{6,0,1851},{134,0,1857},{134,0,355},{133,0,116},{132,0,457},{135,11, +1411},{4,11,408},{4,11,741},{135,11,500},{134,10,26},{142,11,137},{5,0,527},{6,0 +,189},{7,0,859},{136,0,267},{11,0,104},{11,0,554},{15,0,60},{143,0,125},{134,0, +1613},{4,10,414},{5,10,467},{9,10,654},{10,10,451},{12,10,59},{141,10,375},{135, +10,17},{134,0,116},{135,11,541},{135,10,955},{6,11,73},{135,11,177},{133,11,576} +,{134,0,886},{133,0,487},{4,0,86},{5,0,667},{5,0,753},{6,0,316},{6,0,455},{135,0 +,946},{142,11,231},{150,0,45},{134,0,863},{134,0,1953},{6,10,280},{10,10,502},{ +11,10,344},{140,10,38},{4,0,79},{7,0,1773},{10,0,450},{11,0,589},{13,0,332},{13, +0,493},{14,0,183},{14,0,334},{14,0,362},{14,0,368},{14,0,376},{14,0,379},{19,0, +90},{19,0,103},{19,0,127},{148,0,90},{5,10,45},{7,10,1161},{11,10,448},{11,10, +880},{13,10,139},{13,10,407},{15,10,16},{17,10,95},{18,10,66},{18,10,88},{18,10, +123},{149,10,7},{136,10,777},{4,10,410},{135,10,521},{135,10,1778},{135,11,538}, +{142,0,381},{133,11,413},{134,0,1142},{6,0,1189},{136,11,495},{5,0,663},{6,0, +1962},{134,0,2003},{7,11,54},{8,11,312},{10,11,191},{10,11,614},{140,11,567},{ +132,10,436},{133,0,846},{7,10,1587},{7,10,1707},{10,0,528},{139,0,504},{5,0,378} +,{8,0,465},{9,0,286},{10,0,185},{10,0,562},{10,0,635},{11,0,31},{11,0,393},{13,0 +,312},{18,0,65},{18,0,96},{147,0,89},{6,11,468},{7,0,899},{7,11,567},{7,11,1478} +,{8,11,530},{14,0,325},{142,11,290},{7,0,1880},{9,0,680},{139,0,798},{134,0,1770 +},{132,0,648},{150,11,35},{5,0,945},{6,0,1656},{6,0,1787},{7,0,167},{8,0,824},{9 +,0,391},{10,0,375},{139,0,185},{6,11,484},{135,11,822},{134,0,2046},{7,0,1645},{ +8,0,352},{137,0,249},{132,0,152},{6,0,611},{135,0,1733},{6,11,1724},{135,11,2022 +},{133,0,1006},{141,11,96},{5,0,420},{135,0,1449},{146,11,149},{135,0,832},{135, +10,663},{133,0,351},{5,0,40},{7,0,598},{7,0,1638},{8,0,78},{9,0,166},{9,0,640},{ +9,0,685},{9,0,773},{11,0,215},{13,0,65},{14,0,172},{14,0,317},{145,0,6},{8,0,60} +,{9,0,343},{139,0,769},{134,0,1354},{132,0,724},{137,0,745},{132,11,474},{7,0, +1951},{8,0,765},{8,0,772},{140,0,671},{7,0,108},{8,0,219},{8,0,388},{9,0,775},{ +11,0,275},{140,0,464},{137,0,639},{135,10,503},{133,11,366},{5,0,15},{5,11,305}, +{6,0,56},{7,0,1758},{8,0,500},{9,0,730},{9,11,560},{11,0,331},{13,0,150},{13,11, +208},{142,0,282},{4,10,113},{5,10,163},{5,10,735},{7,10,1009},{9,10,9},{9,10,771 +},{12,10,90},{13,10,138},{13,10,410},{143,10,128},{4,10,324},{138,10,104},{135, +11,466},{142,11,27},{134,0,1886},{4,11,480},{5,0,205},{6,0,438},{6,11,167},{6,11 +,302},{6,11,1642},{7,11,130},{7,11,656},{7,11,837},{7,11,1547},{7,11,1657},{8,11 +,429},{9,0,711},{9,11,228},{10,11,643},{13,11,289},{13,11,343},{147,11,101},{134 +,0,865},{6,0,2025},{136,0,965},{7,11,278},{10,11,739},{11,11,708},{141,11,348},{ +133,0,534},{135,11,1922},{137,0,691},{4,10,935},{133,10,823},{6,0,443},{9,0,237} +,{9,0,571},{9,0,695},{10,0,139},{11,0,715},{12,0,417},{141,0,421},{5,10,269},{7, +10,434},{7,10,891},{8,10,339},{9,10,702},{11,10,594},{11,10,718},{145,10,100},{6 +,0,1555},{7,0,878},{9,10,485},{141,10,264},{134,10,1713},{7,10,1810},{11,10,866} +,{12,10,103},{141,10,495},{135,10,900},{6,0,1410},{9,11,316},{139,11,256},{4,0, +995},{135,0,1033},{132,0,578},{10,0,881},{12,0,740},{12,0,743},{140,0,759},{132, +0,822},{133,0,923},{142,10,143},{135,11,1696},{6,11,363},{7,11,1955},{136,11,725 +},{132,0,924},{133,0,665},{135,10,2029},{135,0,1901},{4,0,265},{6,0,1092},{6,0, +1417},{7,0,807},{135,0,950},{5,0,93},{12,0,267},{141,0,498},{135,0,1451},{5,11, +813},{135,11,2046},{5,10,625},{135,10,1617},{135,0,747},{6,0,788},{137,0,828},{5 +,11,712},{7,0,184},{7,11,1855},{8,10,425},{8,10,693},{9,10,720},{10,10,380},{10, +10,638},{11,0,307},{11,0,400},{11,10,473},{11,11,17},{12,10,61},{13,11,321},{15, +0,130},{144,11,67},{135,0,198},{6,11,320},{7,11,781},{7,11,1921},{9,11,55},{10, +11,186},{10,11,273},{10,11,664},{10,11,801},{11,11,996},{11,11,997},{13,11,157}, +{142,11,170},{136,11,271},{135,0,994},{7,11,103},{7,11,863},{11,11,184},{14,11, +299},{145,11,62},{11,10,551},{142,10,159},{5,0,233},{5,0,320},{6,0,140},{8,0,295 +},{8,0,615},{136,11,615},{133,0,978},{4,0,905},{6,0,1701},{137,0,843},{132,10, +168},{4,0,974},{8,0,850},{12,0,709},{12,0,768},{140,0,786},{135,10,91},{152,0,6} +,{138,10,532},{135,10,1884},{132,0,509},{6,0,1307},{135,0,273},{5,11,77},{7,11, +1455},{10,11,843},{19,11,73},{150,11,5},{132,11,458},{135,11,1420},{6,11,109},{ +138,11,382},{6,0,201},{6,11,330},{7,10,70},{7,11,1084},{10,10,240},{11,11,142},{ +147,10,93},{7,0,1041},{140,11,328},{133,11,354},{134,0,1040},{133,0,693},{134,0, +774},{139,0,234},{132,0,336},{7,0,1399},{139,10,392},{20,0,22},{148,11,22},{5,0, +802},{7,0,2021},{136,0,805},{5,0,167},{5,0,899},{6,0,410},{137,0,777},{137,0,789 +},{134,0,1705},{7,10,655},{135,10,1844},{4,10,145},{6,10,176},{7,10,395},{137,10 +,562},{132,10,501},{135,0,10},{5,0,11},{6,0,117},{6,0,485},{6,10,509},{7,0,1133} +,{9,0,582},{9,0,594},{10,0,82},{11,0,21},{11,0,818},{12,0,535},{13,0,86},{20,0, +91},{151,0,13},{4,0,264},{7,0,1067},{8,0,204},{8,0,385},{139,0,953},{139,11,737} +,{138,0,56},{134,0,1917},{133,0,470},{10,11,657},{14,11,297},{142,11,361},{135, +11,412},{7,0,1198},{7,11,1198},{8,11,556},{14,11,123},{14,11,192},{143,11,27},{7 +,11,1985},{14,11,146},{15,11,42},{16,11,23},{17,11,86},{146,11,17},{8,11,122},{ +139,0,1015},{4,10,114},{9,10,492},{13,10,462},{142,10,215},{4,10,77},{5,10,361}, +{6,10,139},{6,10,401},{6,10,404},{7,10,413},{7,10,715},{7,10,1716},{11,10,279},{ +12,10,179},{12,10,258},{13,10,244},{142,10,358},{134,10,1717},{7,10,1061},{8,10, +82},{11,10,250},{12,10,420},{141,10,184},{133,0,715},{135,10,724},{9,0,919},{9,0 +,922},{9,0,927},{9,0,933},{9,0,962},{9,0,1000},{9,0,1002},{9,0,1021},{12,0,890}, +{12,0,907},{12,0,930},{15,0,207},{15,0,228},{15,0,238},{149,0,61},{8,0,794},{9,0 +,400},{10,0,298},{142,0,228},{5,11,430},{5,11,932},{6,11,131},{7,11,417},{9,11, +522},{11,11,314},{141,11,390},{132,0,867},{4,11,507},{136,0,724},{137,11,261},{4 +,11,343},{133,11,511},{6,0,190},{7,0,768},{135,0,1170},{6,10,513},{135,10,1052}, +{7,11,455},{138,11,591},{134,0,1066},{137,10,899},{14,0,67},{147,0,60},{4,0,948} +,{18,0,174},{146,0,176},{135,0,1023},{7,10,1417},{12,10,382},{17,10,48},{152,10, +12},{134,11,575},{132,0,764},{6,10,545},{7,10,565},{7,10,1669},{10,10,114},{11, +10,642},{140,10,618},{6,0,137},{9,0,75},{9,0,253},{10,0,194},{138,0,444},{4,0, +756},{133,10,5},{7,10,192},{136,0,1008},{132,0,842},{8,10,763},{11,0,643},{140,0 +,115},{139,0,67},{133,10,759},{4,0,821},{5,0,760},{7,0,542},{7,11,580},{8,0,135} +,{136,0,496},{7,10,370},{7,10,1007},{7,10,1177},{135,10,1565},{135,10,1237},{140 +,0,736},{7,0,319},{7,0,355},{7,0,763},{10,0,389},{145,0,43},{8,11,333},{138,11, +182},{4,10,87},{5,10,250},{141,10,298},{138,0,786},{134,0,2044},{8,11,330},{140, +11,477},{135,11,1338},{132,11,125},{134,0,1030},{134,0,1083},{132,11,721},{135, +10,814},{7,11,776},{8,11,145},{147,11,56},{134,0,1226},{4,10,57},{7,10,1195},{7, +10,1438},{7,10,1548},{7,10,1835},{7,10,1904},{9,10,757},{10,10,604},{139,10,519} +,{7,11,792},{8,11,147},{10,11,821},{139,11,1021},{137,11,797},{4,0,58},{5,0,286} +,{6,0,319},{7,0,402},{7,0,1254},{7,0,1903},{8,0,356},{140,0,408},{4,0,389},{4,0, +815},{9,0,181},{9,0,255},{10,0,8},{10,0,29},{10,0,816},{11,0,311},{11,0,561},{12 +,0,67},{141,0,181},{7,11,1472},{135,11,1554},{7,11,1071},{7,11,1541},{7,11,1767} +,{7,11,1806},{7,11,1999},{9,11,248},{10,11,400},{11,11,162},{11,11,178},{11,11, +242},{12,11,605},{15,11,26},{144,11,44},{5,11,168},{5,11,930},{8,11,74},{9,11, +623},{12,11,500},{12,11,579},{13,11,41},{143,11,93},{6,11,220},{7,11,1101},{141, +11,105},{4,10,209},{5,0,474},{7,0,507},{7,10,902},{135,11,507},{132,0,427},{6,0, +413},{7,10,335},{7,10,1437},{7,10,1668},{8,10,553},{8,10,652},{8,10,656},{9,10, +558},{11,10,743},{149,10,18},{132,0,730},{6,11,19},{7,11,1413},{139,11,428},{133 +,0,373},{132,10,559},{7,11,96},{8,11,401},{137,11,896},{5,10,1017},{7,0,799},{7, +0,1972},{138,10,511},{135,0,1793},{7,11,1961},{7,11,1965},{8,11,702},{136,11,750 +},{8,11,150},{8,11,737},{140,11,366},{132,0,322},{133,10,709},{8,11,800},{9,11, +148},{9,11,872},{9,11,890},{11,11,309},{11,11,1001},{13,11,267},{141,11,323},{ +134,10,1745},{7,0,290},{136,10,206},{7,0,1651},{145,0,89},{139,0,2},{132,0,672}, +{6,0,1860},{8,0,905},{10,0,844},{10,0,846},{10,0,858},{12,0,699},{12,0,746},{140 +,0,772},{135,11,424},{133,11,547},{133,0,737},{5,11,490},{6,11,615},{6,11,620},{ +135,11,683},{6,0,746},{134,0,1612},{132,10,776},{9,11,385},{149,11,17},{133,0, +145},{135,10,1272},{7,0,884},{140,0,124},{4,0,387},{135,0,1288},{5,11,133},{136, +10,406},{136,11,187},{6,0,679},{8,11,8},{138,11,0},{135,0,550},{135,11,798},{136 +,11,685},{7,11,1086},{145,11,46},{8,10,175},{10,10,168},{138,10,573},{135,0,1305 +},{4,0,576},{135,0,1263},{6,0,686},{134,0,1563},{134,0,607},{5,0,919},{134,0, +1673},{148,0,37},{8,11,774},{10,11,670},{140,11,51},{133,10,784},{139,10,882},{4 +,0,82},{5,0,333},{5,0,904},{6,0,207},{7,0,325},{7,0,1726},{8,0,101},{10,0,778},{ +139,0,220},{135,11,371},{132,0,958},{133,0,903},{4,11,127},{5,11,350},{6,11,356} +,{8,11,426},{9,11,572},{10,11,247},{139,11,312},{140,0,147},{6,11,59},{7,11,885} +,{9,11,603},{141,11,397},{9,10,14},{9,10,441},{10,0,367},{139,10,9},{11,10,966}, +{12,10,287},{13,10,342},{13,10,402},{15,10,110},{143,10,163},{134,0,690},{132,0, +705},{7,10,1428},{7,10,1640},{7,10,1867},{9,0,651},{9,10,169},{9,10,182},{9,10, +367},{9,10,478},{9,10,506},{9,10,551},{9,10,557},{9,10,648},{9,10,697},{9,10,705 +},{9,10,725},{9,10,787},{9,10,794},{10,10,198},{10,10,214},{10,10,267},{10,10, +275},{10,10,456},{10,10,551},{10,10,561},{10,10,613},{10,10,627},{10,10,668},{10 +,10,675},{10,10,691},{10,10,695},{10,10,707},{10,10,715},{11,0,971},{11,10,183}, +{11,10,201},{11,10,262},{11,10,352},{11,10,439},{11,10,493},{11,10,572},{11,10, +591},{11,10,608},{11,10,611},{11,10,646},{11,10,674},{11,10,711},{11,10,751},{11 +,10,761},{11,10,776},{11,10,785},{11,10,850},{11,10,853},{11,10,862},{11,10,865} +,{11,10,868},{11,10,875},{11,10,898},{11,10,902},{11,10,903},{11,10,910},{11,10, +932},{11,10,942},{11,10,957},{11,10,967},{11,10,972},{12,10,148},{12,10,195},{12 +,10,220},{12,10,237},{12,10,318},{12,10,339},{12,10,393},{12,10,445},{12,10,450} +,{12,10,474},{12,10,505},{12,10,509},{12,10,533},{12,10,591},{12,10,594},{12,10, +597},{12,10,621},{12,10,633},{12,10,642},{13,0,273},{13,10,59},{13,10,60},{13,10 +,145},{13,10,239},{13,10,250},{13,10,329},{13,10,344},{13,10,365},{13,10,372},{ +13,10,387},{13,10,403},{13,10,414},{13,10,456},{13,10,470},{13,10,478},{13,10, +483},{13,10,489},{14,10,55},{14,10,57},{14,10,81},{14,10,90},{14,10,148},{14,10, +239},{14,10,266},{14,10,321},{14,10,326},{14,10,327},{14,10,330},{14,10,347},{14 +,10,355},{14,10,401},{14,10,404},{14,10,411},{14,10,414},{14,10,416},{14,10,420} +,{15,10,61},{15,10,74},{15,10,87},{15,10,88},{15,10,94},{15,10,96},{15,10,116},{ +15,10,149},{15,10,154},{16,10,50},{16,10,63},{16,10,73},{17,10,2},{17,10,66},{17 +,10,92},{17,10,103},{17,10,112},{17,10,120},{18,10,50},{18,10,54},{18,10,82},{18 +,10,86},{18,10,90},{18,10,111},{18,10,115},{18,10,156},{19,10,40},{19,10,79},{20 +,10,78},{149,10,22},{5,10,161},{7,0,887},{135,10,839},{142,11,98},{134,0,90},{ +138,11,356},{135,11,441},{6,11,111},{7,11,4},{8,11,163},{8,11,776},{138,11,566}, +{134,0,908},{134,0,1261},{7,0,813},{12,0,497},{141,0,56},{134,0,1235},{135,0,429 +},{135,11,1994},{138,0,904},{6,0,125},{7,0,1277},{137,0,772},{151,0,12},{4,0,841 +},{5,0,386},{133,11,386},{5,11,297},{135,11,1038},{6,0,860},{6,0,1069},{135,11, +309},{136,0,946},{135,10,1814},{141,11,418},{136,11,363},{10,0,768},{139,0,787}, +{22,11,30},{150,11,33},{6,0,160},{7,0,1106},{9,0,770},{11,0,112},{140,0,413},{11 +,11,216},{139,11,340},{136,10,139},{135,11,1390},{135,11,808},{132,11,280},{7,10 +,643},{8,10,236},{12,0,271},{145,0,109},{140,11,54},{4,11,421},{133,11,548},{11, +0,719},{12,0,36},{141,0,337},{7,0,581},{9,0,644},{137,0,699},{11,11,511},{13,11, +394},{14,11,298},{14,11,318},{146,11,103},{7,0,304},{9,0,646},{9,0,862},{11,0, +696},{12,0,208},{15,0,79},{147,0,108},{4,0,631},{7,0,1126},{135,0,1536},{135,11, +1527},{8,0,880},{10,0,869},{138,0,913},{5,10,54},{6,11,254},{7,0,1513},{9,11,109 +},{138,11,103},{135,0,981},{133,11,729},{132,10,744},{132,0,434},{134,0,550},{6, +11,1630},{7,0,930},{10,0,476},{10,10,402},{13,0,452},{18,10,55},{147,0,104},{5,0 +,553},{138,0,824},{136,0,452},{8,0,151},{137,10,624},{132,10,572},{132,0,772},{ +133,11,671},{133,0,292},{138,0,135},{132,11,889},{140,11,207},{6,10,43},{7,10,38 +},{8,10,248},{9,0,504},{138,10,513},{6,0,1089},{135,11,1910},{4,11,627},{133,11, +775},{135,0,783},{133,10,766},{133,10,363},{7,0,387},{135,11,387},{7,0,393},{7, +11,202},{10,0,603},{11,0,206},{11,11,362},{11,11,948},{140,11,388},{6,11,507},{7 +,11,451},{8,11,389},{12,11,490},{13,11,16},{13,11,215},{13,11,351},{18,11,132},{ +147,11,125},{4,0,912},{7,11,841},{137,0,232},{6,10,258},{140,10,409},{5,10,249}, +{148,10,82},{136,11,566},{6,0,977},{135,11,1214},{7,0,1973},{136,0,716},{135,0, +98},{133,0,733},{5,11,912},{134,11,1695},{5,10,393},{6,10,378},{7,10,1981},{9,10 +,32},{9,10,591},{10,10,685},{10,10,741},{142,10,382},{133,10,788},{7,10,1968},{ +10,0,19},{11,0,911},{141,10,509},{5,0,668},{5,11,236},{6,11,572},{8,11,492},{11, +11,618},{144,11,56},{135,11,1789},{4,0,360},{5,0,635},{5,0,700},{5,10,58},{5,10, +171},{5,10,683},{6,10,291},{6,10,566},{7,10,1650},{11,10,523},{12,10,273},{12,10 +,303},{15,10,39},{143,10,111},{133,0,901},{134,10,589},{5,11,190},{136,11,318},{ +140,0,656},{7,0,726},{152,0,9},{4,10,917},{133,10,1005},{135,10,1598},{134,11, +491},{4,10,919},{133,11,434},{137,0,72},{6,0,1269},{6,0,1566},{134,0,1621},{4,10 +,255},{5,10,302},{6,10,132},{7,10,128},{7,10,283},{7,10,1299},{9,0,463},{10,0, +595},{10,10,52},{10,10,514},{11,10,925},{13,10,92},{142,10,309},{135,0,1454},{ +134,0,1287},{9,10,173},{11,0,600},{141,0,245},{136,0,989},{7,0,164},{7,0,1571},{ +9,0,107},{140,0,225},{6,0,1061},{141,10,442},{4,0,27},{5,0,484},{5,0,510},{6,0, +434},{7,0,1000},{7,0,1098},{136,0,2},{7,11,85},{7,11,247},{8,11,585},{10,11,163} +,{138,11,316},{11,11,103},{142,11,0},{134,0,1127},{4,0,460},{134,0,852},{134,10, +210},{4,0,932},{133,0,891},{6,0,588},{147,11,83},{4,10,284},{6,10,223},{136,0, +625},{134,0,76},{8,0,92},{137,0,221},{4,11,124},{10,11,457},{11,11,121},{11,11, +169},{11,11,422},{11,11,870},{12,11,214},{13,11,389},{14,11,187},{143,11,77},{9, +11,618},{138,11,482},{4,10,218},{7,10,526},{143,10,137},{4,10,270},{5,10,192},{6 +,10,332},{7,10,1322},{13,0,9},{14,0,104},{142,0,311},{140,10,661},{135,11,1193}, +{6,11,107},{7,11,638},{7,11,1632},{137,11,396},{132,0,763},{4,0,622},{5,11,370}, +{134,11,1756},{133,0,253},{135,0,546},{5,11,204},{9,0,73},{10,0,110},{14,0,185}, +{145,0,119},{7,0,624},{7,0,916},{10,0,256},{139,0,87},{7,10,379},{8,10,481},{137 +,10,377},{5,0,212},{5,11,970},{6,11,1706},{12,0,35},{141,0,382},{5,10,1003},{6, +10,149},{137,0,746},{8,10,262},{9,10,627},{10,0,150},{11,0,849},{11,10,214},{11, +10,404},{11,10,457},{11,10,780},{11,10,913},{13,0,330},{13,10,401},{142,10,200}, +{134,0,1466},{135,11,3},{4,11,35},{5,11,121},{5,11,483},{5,11,685},{6,0,1299},{6 +,11,489},{7,11,1204},{136,11,394},{135,10,742},{4,10,142},{136,10,304},{4,11,921 +},{133,11,1007},{134,0,1518},{6,0,1229},{135,0,1175},{133,0,816},{4,10,471},{4, +11,712},{5,10,51},{6,10,602},{7,10,925},{8,10,484},{10,10,195},{140,0,159},{134, +11,1629},{5,0,869},{5,0,968},{6,0,1626},{8,0,734},{136,0,784},{4,0,542},{6,0, +1716},{6,0,1727},{7,0,1082},{7,0,1545},{8,0,56},{8,0,118},{8,0,412},{8,0,564},{8 +,10,688},{9,0,888},{9,0,908},{10,0,50},{10,0,423},{11,0,685},{11,0,697},{11,0, +933},{12,0,299},{13,0,126},{13,0,136},{13,0,170},{141,0,190},{132,10,697},{4,0, +232},{9,0,202},{10,0,474},{140,0,433},{136,0,212},{6,0,108},{7,0,1003},{7,0,1181 +},{8,0,111},{136,0,343},{5,10,221},{135,11,1255},{133,11,485},{134,0,1712},{142, +0,216},{4,11,285},{5,0,643},{5,11,317},{6,0,516},{6,11,301},{7,11,7},{8,11,153}, +{10,11,766},{11,11,468},{12,11,467},{141,11,143},{4,0,133},{7,0,711},{7,0,1298}, +{135,0,1585},{134,0,650},{135,11,512},{6,0,99},{7,0,1808},{145,0,57},{6,0,246},{ +6,0,574},{7,0,428},{9,0,793},{10,0,669},{11,0,485},{11,0,840},{12,0,300},{14,0, +250},{145,0,55},{4,10,132},{5,10,69},{135,10,1242},{136,0,1023},{4,10,111},{135, +0,302},{135,0,1871},{132,0,728},{4,10,767},{137,0,252},{6,0,461},{7,0,1590},{7, +10,1416},{7,10,2005},{8,10,131},{8,10,466},{9,10,672},{13,10,252},{148,10,103},{ +6,0,323},{135,0,1564},{7,0,461},{136,0,775},{6,10,44},{136,10,368},{139,0,172},{ +132,0,464},{4,10,570},{133,10,120},{137,11,269},{6,10,227},{135,10,1589},{6,11, +1719},{6,11,1735},{7,11,2016},{7,11,2020},{8,11,837},{137,11,852},{7,0,727},{146 +,0,73},{132,0,1023},{135,11,852},{135,10,1529},{136,0,577},{138,11,568},{134,0, +1037},{8,11,67},{138,11,419},{4,0,413},{5,0,677},{8,0,432},{140,0,280},{6,10, +1667},{7,10,2036},{7,11,967},{10,0,600},{141,11,11},{6,10,511},{140,10,132},{5, +10,568},{6,0,799},{6,10,138},{135,10,1293},{4,10,565},{8,0,159},{136,10,827},{7, +0,646},{7,0,1730},{11,0,446},{141,0,178},{4,10,922},{133,10,1023},{135,11,11},{ +132,0,395},{7,10,1002},{139,0,145},{9,0,174},{10,0,164},{11,0,440},{11,0,514},{ +11,0,841},{15,0,98},{149,0,20},{134,0,426},{10,0,608},{139,0,1002},{7,11,320},{8 +,11,51},{12,11,481},{12,11,570},{148,11,106},{4,11,445},{9,0,977},{137,0,983},{ +138,0,250},{139,0,100},{6,0,1982},{136,10,402},{133,11,239},{4,10,716},{141,10, +31},{5,0,476},{7,11,83},{7,11,1990},{8,11,130},{139,11,720},{8,10,691},{136,10, +731},{5,11,123},{6,11,530},{7,11,348},{135,11,1419},{5,0,76},{6,0,458},{6,0,497} +,{7,0,868},{9,0,658},{10,0,594},{11,0,173},{11,0,566},{12,0,20},{12,0,338},{141, +0,200},{9,11,139},{10,11,399},{11,11,469},{12,11,634},{141,11,223},{9,10,840},{ +138,10,803},{133,10,847},{11,11,223},{140,11,168},{132,11,210},{8,0,447},{9,10, +53},{9,10,268},{9,10,901},{10,10,518},{10,10,829},{11,10,188},{13,10,74},{14,10, +46},{15,10,17},{15,10,33},{17,10,40},{18,10,36},{19,10,20},{22,10,1},{152,10,2}, +{4,0,526},{7,0,1029},{135,0,1054},{19,11,59},{150,11,2},{4,0,636},{6,0,1875},{6, +0,1920},{8,10,532},{9,0,999},{12,0,807},{12,0,825},{15,0,179},{15,0,190},{146,0, +182},{6,0,1699},{7,0,660},{7,0,1124},{17,0,31},{19,0,22},{151,0,14},{135,10,681} +,{132,11,430},{140,10,677},{4,10,684},{136,10,384},{132,11,756},{133,11,213},{7, +0,188},{7,10,110},{8,10,290},{8,10,591},{9,10,382},{9,10,649},{11,10,71},{11,10, +155},{11,10,313},{12,10,5},{13,10,325},{142,10,287},{7,10,360},{7,10,425},{9,10, +66},{9,10,278},{138,10,644},{142,11,164},{4,0,279},{7,0,301},{137,0,362},{134,11 +,586},{135,0,1743},{4,0,178},{133,0,399},{4,10,900},{133,10,861},{5,10,254},{7, +10,985},{136,10,73},{133,11,108},{7,10,1959},{136,10,683},{133,11,219},{4,11,193 +},{5,11,916},{7,11,364},{10,11,398},{10,11,726},{11,11,317},{11,11,626},{12,11, +142},{12,11,288},{12,11,678},{13,11,313},{15,11,113},{18,11,114},{21,11,30},{150 +,11,53},{6,11,241},{7,11,907},{8,11,832},{9,11,342},{10,11,729},{11,11,284},{11, +11,445},{11,11,651},{11,11,863},{13,11,398},{146,11,99},{132,0,872},{134,0,831}, +{134,0,1692},{6,0,202},{6,0,1006},{9,0,832},{9,11,734},{10,0,636},{11,0,208},{12 +,0,360},{17,0,118},{18,0,27},{148,0,67},{132,10,725},{7,11,993},{138,11,666},{ +134,0,1954},{134,10,196},{7,0,872},{10,0,516},{139,0,167},{133,10,831},{4,11,562 +},{9,11,254},{139,11,879},{137,0,313},{4,0,224},{132,11,786},{8,10,723},{11,0,24 +},{140,0,170},{5,0,546},{7,0,35},{8,0,11},{8,0,12},{9,0,315},{9,0,533},{10,0,802 +},{11,0,166},{12,0,525},{142,0,243},{7,0,1937},{13,10,80},{13,10,437},{145,10,74 +},{5,0,241},{8,0,242},{9,0,451},{10,0,667},{11,0,598},{140,0,429},{150,0,46},{6, +0,1273},{137,0,830},{5,10,848},{6,10,66},{136,10,764},{6,0,825},{134,0,993},{4,0 +,1006},{4,10,36},{7,10,1387},{10,0,327},{11,10,755},{141,0,271},{134,0,1023},{ +135,0,1580},{4,0,366},{137,0,516},{132,10,887},{6,0,1736},{135,0,1891},{6,11,216 +},{7,11,901},{7,11,1343},{136,11,493},{6,10,165},{138,10,388},{7,11,341},{139,11 +,219},{4,10,719},{135,10,155},{134,0,1935},{132,0,826},{6,0,331},{6,0,1605},{8,0 +,623},{11,0,139},{139,0,171},{135,11,1734},{10,11,115},{11,11,420},{12,11,154},{ +13,11,404},{14,11,346},{15,11,54},{143,11,112},{4,10,353},{6,10,146},{6,10,1789} +,{7,0,288},{7,10,990},{7,10,1348},{9,10,665},{9,10,898},{11,10,893},{142,10,212} +,{6,0,916},{134,0,1592},{4,10,45},{7,0,1888},{135,10,1257},{5,11,1011},{136,11, +701},{139,11,596},{4,11,54},{5,11,666},{7,11,1039},{7,11,1130},{9,11,195},{138, +11,302},{134,0,1471},{134,0,1570},{132,0,394},{140,10,65},{136,10,816},{135,0, +1931},{7,0,574},{135,0,1719},{134,11,467},{132,0,658},{6,11,1669},{9,0,781},{10, +0,144},{11,0,385},{13,0,161},{13,0,228},{13,0,268},{148,0,107},{136,0,374},{135, +0,735},{4,0,344},{6,0,498},{139,0,323},{6,10,559},{6,10,1691},{7,0,586},{135,0, +1063},{137,0,155},{133,0,906},{7,11,122},{9,11,259},{10,11,84},{11,11,470},{12, +11,541},{141,11,379},{134,0,1139},{10,0,108},{139,0,116},{134,10,456},{133,10, +925},{5,11,82},{5,11,131},{7,11,1755},{8,11,31},{9,11,168},{9,11,764},{139,11, +869},{134,11,605},{5,11,278},{137,11,68},{4,11,163},{5,11,201},{5,11,307},{5,11, +310},{6,11,335},{7,11,284},{136,11,165},{135,11,1660},{6,11,33},{135,11,1244},{4 +,0,616},{136,11,483},{4,11,199},{8,0,857},{8,0,902},{8,0,910},{10,0,879},{11,11, +34},{140,0,726},{136,0,692},{6,10,193},{7,10,240},{7,10,1682},{10,10,51},{10,10, +640},{11,10,410},{13,10,82},{14,10,247},{14,10,331},{142,10,377},{6,0,823},{134, +0,983},{139,10,411},{132,0,305},{136,10,633},{138,11,203},{134,0,681},{6,11,326} +,{7,11,677},{137,11,425},{5,0,214},{7,0,603},{8,0,611},{9,0,686},{10,0,88},{11,0 +,459},{11,0,496},{12,0,463},{12,0,590},{141,0,0},{136,0,1004},{142,0,23},{134,0, +1703},{147,11,8},{145,11,56},{135,0,1443},{4,10,237},{135,10,514},{6,0,714},{145 +,0,19},{5,11,358},{7,11,473},{7,11,1184},{10,11,662},{13,11,212},{13,11,304},{13 +,11,333},{145,11,98},{4,0,737},{10,0,98},{11,0,294},{12,0,60},{12,0,437},{13,0, +64},{13,0,380},{142,0,430},{6,10,392},{7,10,65},{135,10,2019},{6,0,1758},{8,0, +520},{9,0,345},{9,0,403},{142,0,350},{5,0,47},{10,0,242},{138,0,579},{5,0,139},{ +7,0,1168},{138,0,539},{134,0,1459},{13,0,388},{141,11,388},{134,0,253},{7,10, +1260},{135,10,1790},{9,10,222},{10,0,252},{139,10,900},{140,0,745},{133,11,946}, +{4,0,107},{7,0,613},{8,0,439},{8,0,504},{9,0,501},{10,0,383},{139,0,477},{135,11 +,1485},{132,0,871},{7,11,411},{7,11,590},{8,11,631},{9,11,323},{10,11,355},{11, +11,491},{12,11,143},{12,11,402},{13,11,73},{14,11,408},{15,11,107},{146,11,71},{ +132,0,229},{132,0,903},{140,0,71},{133,0,549},{4,0,47},{6,0,373},{7,0,452},{7,0, +543},{7,0,1828},{7,0,1856},{9,0,6},{11,0,257},{139,0,391},{7,11,1467},{8,11,328} +,{10,11,544},{11,11,955},{13,11,320},{145,11,83},{5,0,980},{134,0,1754},{136,0, +865},{5,0,705},{137,0,606},{7,0,161},{8,10,201},{136,10,605},{143,11,35},{5,11, +835},{6,11,483},{140,10,224},{7,0,536},{7,0,1331},{136,0,143},{134,0,1388},{5,0, +724},{10,0,305},{11,0,151},{12,0,33},{12,0,121},{12,0,381},{17,0,3},{17,0,27},{ +17,0,78},{18,0,18},{19,0,54},{149,0,5},{4,10,523},{133,10,638},{5,0,19},{134,0, +533},{5,0,395},{5,0,951},{134,0,1776},{135,0,1908},{132,0,846},{6,10,242},{7,10, +227},{7,10,1581},{8,10,104},{9,10,113},{9,10,220},{9,10,427},{10,0,74},{10,10, +239},{11,0,663},{11,10,579},{11,10,1023},{12,0,210},{13,0,166},{13,0,310},{13,10 +,4},{13,10,204},{13,10,316},{14,0,373},{18,0,95},{19,0,43},{148,10,86},{9,11,716 +},{11,11,108},{13,11,123},{14,11,252},{19,11,38},{21,11,3},{151,11,11},{8,0,372} +,{9,0,122},{138,0,175},{132,11,677},{7,11,1374},{136,11,540},{135,10,861},{132,0 +,695},{7,0,497},{9,0,387},{147,0,81},{136,0,937},{134,0,718},{7,0,1328},{136,10, +494},{132,11,331},{5,11,747},{134,0,1581},{5,0,284},{6,0,49},{6,0,350},{7,0,1},{ +7,0,377},{7,0,1693},{8,0,18},{8,0,678},{9,0,161},{9,0,585},{9,0,671},{9,0,839},{ +11,0,912},{141,0,427},{7,10,1306},{8,10,505},{9,10,482},{10,10,126},{11,10,225}, +{12,10,347},{12,10,449},{13,10,19},{14,10,218},{142,10,435},{10,10,764},{12,10, +120},{13,10,39},{145,10,127},{4,0,597},{133,10,268},{134,0,1094},{4,0,1008},{134 +,0,1973},{132,0,811},{139,0,908},{135,0,1471},{133,11,326},{4,10,384},{135,10, +1022},{4,11,691},{7,0,1935},{7,11,1935},{8,0,324},{8,11,324},{9,11,35},{10,11, +680},{11,11,364},{12,0,42},{12,11,42},{13,11,357},{146,11,16},{135,0,2014},{6,11 +,32},{7,0,2007},{7,11,385},{7,11,757},{7,11,1916},{8,11,37},{8,11,94},{8,11,711} +,{9,0,101},{9,0,450},{9,11,541},{10,0,66},{10,0,842},{10,11,162},{10,11,795},{11 +,0,536},{11,11,989},{11,11,1010},{12,0,587},{12,11,14},{142,11,308},{139,0,586}, +{135,10,1703},{7,0,1077},{9,10,159},{11,0,28},{140,10,603},{6,0,1221},{136,10, +583},{6,11,152},{6,11,349},{6,11,1682},{7,11,1252},{8,11,112},{9,11,435},{9,11, +668},{10,11,290},{10,11,319},{10,11,815},{11,11,180},{11,11,837},{12,11,240},{13 +,11,152},{13,11,219},{142,11,158},{139,0,62},{132,10,515},{8,10,632},{8,10,697}, +{137,10,854},{134,0,1766},{132,11,581},{6,11,126},{7,11,573},{8,11,397},{142,11, +44},{150,0,28},{4,10,136},{5,10,551},{11,0,670},{150,0,25},{6,0,1665},{7,0,256}, +{7,0,1388},{138,0,499},{4,0,22},{5,0,10},{7,0,1576},{136,0,97},{134,10,1782},{5, +0,481},{7,10,1287},{9,10,44},{10,10,552},{10,10,642},{11,10,839},{12,10,274},{12 +,10,275},{12,10,372},{13,10,91},{142,10,125},{133,11,926},{7,11,1232},{137,11, +531},{6,0,134},{7,0,437},{7,0,1824},{9,0,37},{14,0,285},{142,0,371},{7,0,486},{8 +,0,155},{11,0,93},{140,0,164},{6,0,1391},{134,0,1442},{133,11,670},{133,0,591},{ +6,10,147},{7,10,886},{7,11,1957},{9,10,753},{138,10,268},{5,0,380},{5,0,650},{7, +0,1173},{136,0,310},{4,0,364},{7,0,1156},{7,0,1187},{137,0,409},{135,11,1621},{ +134,0,482},{133,11,506},{4,0,781},{6,0,487},{7,0,926},{8,0,263},{139,0,500},{138 +,10,137},{135,11,242},{139,11,96},{133,10,414},{135,10,1762},{134,0,804},{5,11, +834},{7,11,1202},{8,11,14},{9,11,481},{137,11,880},{134,10,599},{4,0,94},{135,0, +1265},{4,0,415},{132,0,417},{5,0,348},{6,0,522},{6,10,1749},{7,11,1526},{138,11, +465},{134,10,1627},{132,0,1012},{132,10,488},{4,11,357},{6,11,172},{7,11,143},{ +137,11,413},{4,10,83},{4,11,590},{146,11,76},{140,10,676},{7,11,287},{8,11,355}, +{9,11,293},{137,11,743},{134,10,278},{5,11,169},{6,0,1803},{7,11,333},{8,11,45}, +{18,0,165},{152,0,21},{12,10,97},{140,11,97},{4,0,408},{4,0,741},{135,0,500},{ +132,11,198},{7,10,388},{7,10,644},{139,10,781},{4,11,24},{5,11,140},{5,11,185},{ +7,11,1500},{11,11,565},{139,11,838},{6,0,1321},{7,10,229},{8,10,59},{9,0,257},{9 +,10,190},{10,10,378},{140,10,191},{4,11,334},{133,11,593},{135,11,1885},{134,0, +1138},{4,0,249},{6,0,73},{135,0,177},{133,0,576},{142,0,231},{137,0,288},{132,10 +,660},{7,10,1035},{138,10,737},{135,0,1487},{6,0,989},{7,10,690},{9,0,433},{9,10 +,587},{140,10,521},{7,0,1264},{7,0,1678},{11,0,945},{12,0,341},{12,0,471},{140,0 +,569},{132,11,709},{133,11,897},{5,11,224},{13,11,174},{146,11,52},{135,11,1840} +,{134,10,1744},{4,10,733},{9,10,194},{10,10,92},{11,10,198},{12,0,87},{12,10,84} +,{13,10,128},{144,0,74},{140,0,779},{135,0,538},{4,11,608},{133,11,497},{133,0, +413},{7,11,1375},{7,11,1466},{138,11,331},{136,0,495},{6,11,540},{136,11,136},{7 +,0,54},{8,0,312},{10,0,191},{10,0,614},{140,0,567},{5,11,999},{6,0,468},{7,0,567 +},{7,0,1478},{8,0,530},{142,0,290},{4,11,299},{7,10,306},{135,11,1004},{142,11, +296},{134,0,1484},{133,10,979},{6,0,609},{9,0,815},{12,11,137},{14,11,9},{14,11, +24},{142,11,64},{133,11,456},{6,0,484},{135,0,822},{133,10,178},{136,11,180},{ +132,11,755},{137,0,900},{135,0,1335},{6,0,1724},{135,0,2022},{135,11,1139},{4,10 +,390},{133,0,640},{6,0,1831},{138,11,633},{135,11,566},{4,11,890},{5,11,805},{5, +11,819},{5,11,961},{6,11,396},{6,11,1631},{6,11,1678},{7,11,1967},{7,11,2041},{9 +,11,630},{11,11,8},{11,11,1019},{12,11,176},{13,11,225},{14,11,292},{149,11,24}, +{132,0,474},{134,0,1103},{135,0,1504},{134,0,1576},{6,0,961},{6,0,1034},{140,0, +655},{11,11,514},{149,11,20},{5,0,305},{135,11,1815},{7,11,1505},{10,11,190},{10 +,11,634},{11,11,792},{12,11,358},{140,11,447},{5,11,0},{6,11,536},{7,11,604},{13 +,11,445},{145,11,126},{5,10,105},{135,0,1236},{4,0,480},{6,0,217},{6,0,302},{6,0 +,1642},{6,11,232},{6,11,412},{7,0,130},{7,0,837},{7,0,1321},{7,0,1547},{7,0,1657 +},{7,11,1074},{8,0,429},{8,11,9},{8,11,157},{8,11,786},{9,0,228},{9,11,196},{9, +11,352},{9,11,457},{10,11,337},{11,11,232},{11,11,877},{12,11,480},{12,11,546},{ +13,0,289},{13,0,343},{147,0,101},{5,10,438},{7,11,958},{9,10,694},{12,10,627},{ +13,10,210},{141,11,38},{4,11,382},{136,11,579},{7,0,278},{10,0,739},{11,0,708},{ +141,0,348},{4,11,212},{135,11,1206},{135,11,1898},{6,0,708},{6,0,1344},{152,10, +11},{137,11,768},{134,0,1840},{140,0,233},{8,10,25},{138,10,826},{5,11,655},{134 +,0,2017},{6,0,1488},{139,11,290},{132,10,308},{134,0,1590},{134,0,1800},{134,0, +1259},{6,11,231},{7,11,95},{8,11,423},{144,0,28},{133,11,300},{135,10,150},{136, +10,649},{7,11,1874},{137,11,641},{6,11,237},{7,11,611},{8,11,100},{9,11,416},{11 +,11,335},{12,11,173},{146,11,101},{137,0,45},{134,10,521},{14,11,26},{17,0,36},{ +146,11,150},{5,10,339},{7,0,1442},{14,0,22},{15,10,41},{15,10,166},{147,10,66},{ +6,11,581},{7,11,1119},{136,0,378},{134,0,1507},{147,11,117},{139,0,39},{134,0, +1054},{6,0,363},{7,0,1955},{136,0,725},{134,0,2036},{133,11,199},{6,0,1871},{9,0 +,935},{9,0,961},{9,0,1004},{9,0,1016},{12,0,805},{12,0,852},{12,0,853},{12,0,869 +},{12,0,882},{12,0,896},{12,0,906},{12,0,917},{12,0,940},{15,0,170},{15,0,176},{ +15,0,188},{15,0,201},{15,0,205},{15,0,212},{15,0,234},{15,0,244},{18,0,181},{18, +0,193},{18,0,196},{18,0,201},{18,0,202},{18,0,210},{18,0,217},{18,0,235},{18,0, +236},{18,0,237},{21,0,54},{21,0,55},{21,0,58},{21,0,59},{152,0,22},{134,10,1628} +,{137,0,805},{5,0,813},{135,0,2046},{142,11,42},{5,0,712},{6,0,1240},{11,0,17},{ +13,0,321},{144,0,67},{132,0,617},{135,10,829},{6,0,320},{7,0,781},{7,0,1921},{9, +0,55},{10,0,186},{10,0,273},{10,0,664},{10,0,801},{11,0,996},{11,0,997},{13,0, +157},{142,0,170},{136,0,271},{5,10,486},{135,10,1349},{18,11,91},{147,11,70},{7, +10,1635},{8,10,17},{10,0,445},{138,10,295},{136,11,404},{7,0,103},{7,0,863},{11, +0,184},{145,0,62},{138,10,558},{137,0,659},{6,11,312},{6,11,1715},{10,11,584},{ +11,11,546},{11,11,692},{12,11,259},{12,11,295},{13,11,46},{141,11,154},{134,0, +676},{132,11,588},{4,11,231},{5,11,61},{6,11,104},{7,11,729},{7,11,964},{7,11, +1658},{140,11,414},{6,11,263},{138,11,757},{11,0,337},{142,0,303},{135,11,1363}, +{132,11,320},{140,0,506},{134,10,447},{5,0,77},{7,0,1455},{10,0,843},{147,0,73}, +{7,10,577},{7,10,1432},{9,10,475},{9,10,505},{9,10,526},{9,10,609},{9,10,689},{9 +,10,726},{9,10,735},{9,10,738},{10,10,556},{10,10,674},{10,10,684},{11,10,89},{ +11,10,202},{11,10,272},{11,10,380},{11,10,415},{11,10,505},{11,10,537},{11,10, +550},{11,10,562},{11,10,640},{11,10,667},{11,10,688},{11,10,847},{11,10,927},{11 +,10,930},{11,10,940},{12,10,144},{12,10,325},{12,10,329},{12,10,389},{12,10,403} +,{12,10,451},{12,10,515},{12,10,604},{12,10,616},{12,10,626},{13,10,66},{13,10, +131},{13,10,167},{13,10,236},{13,10,368},{13,10,411},{13,10,434},{13,10,453},{13 +,10,461},{13,10,474},{14,10,59},{14,10,60},{14,10,139},{14,10,152},{14,10,276},{ +14,10,353},{14,10,402},{15,10,28},{15,10,81},{15,10,123},{15,10,152},{18,10,136} +,{148,10,88},{132,0,458},{135,0,1420},{4,10,609},{4,11,405},{6,0,109},{7,10,756} +,{7,11,817},{9,10,544},{10,0,382},{11,10,413},{14,10,307},{14,11,58},{16,10,25}, +{17,11,37},{146,11,124},{5,11,974},{6,0,330},{7,0,1084},{139,0,142},{4,10,930},{ +133,10,947},{5,10,939},{142,11,394},{16,0,91},{145,0,87},{5,10,962},{5,11,235},{ +7,11,1239},{11,11,131},{140,11,370},{5,10,651},{8,10,170},{9,10,61},{9,10,63},{ +10,10,23},{10,10,37},{10,10,834},{11,0,492},{11,10,4},{11,10,281},{11,10,503},{ +11,10,677},{12,10,96},{12,10,130},{12,10,244},{14,10,5},{14,10,40},{14,10,162},{ +14,10,202},{146,10,133},{4,10,406},{5,10,579},{12,10,492},{150,10,15},{9,11,137} +,{138,11,221},{134,0,1239},{11,0,211},{140,0,145},{7,11,390},{138,11,140},{135, +11,1418},{135,11,1144},{134,0,1049},{6,10,17},{7,0,321},{7,10,1001},{7,10,1982}, +{9,10,886},{10,10,489},{10,10,800},{11,10,782},{12,10,320},{13,10,467},{14,10, +145},{14,10,387},{143,10,119},{145,10,17},{5,11,407},{11,11,489},{19,11,37},{20, +11,73},{150,11,38},{133,10,458},{135,0,1985},{7,10,1983},{8,10,0},{8,10,171},{9, +10,120},{9,10,732},{10,10,473},{11,10,656},{11,10,998},{18,10,0},{18,10,2},{147, +10,21},{5,11,325},{7,11,1483},{8,11,5},{8,11,227},{9,11,105},{10,11,585},{140,11 +,614},{136,0,122},{132,0,234},{135,11,1196},{6,0,976},{6,0,1098},{134,0,1441},{7 +,0,253},{136,0,549},{6,11,621},{13,11,504},{144,11,19},{132,10,519},{5,0,430},{5 +,0,932},{6,0,131},{7,0,417},{9,0,522},{11,0,314},{141,0,390},{14,0,149},{14,0, +399},{143,0,57},{5,10,907},{6,10,31},{6,11,218},{7,10,491},{7,10,530},{8,10,592} +,{11,10,53},{11,10,779},{12,10,167},{12,10,411},{14,10,14},{14,10,136},{15,10,72 +},{16,10,17},{144,10,72},{140,11,330},{7,11,454},{7,11,782},{136,11,768},{132,0, +507},{10,11,676},{140,11,462},{4,10,208},{5,10,106},{6,0,630},{6,10,531},{8,10, +408},{9,0,811},{9,10,188},{138,10,572},{4,0,343},{5,0,511},{134,10,1693},{134,11 +,164},{132,0,448},{7,0,455},{138,0,591},{135,0,1381},{12,10,441},{150,11,50},{9, +10,449},{10,10,192},{138,10,740},{4,10,241},{134,0,575},{134,0,1175},{134,0,653} +,{134,0,1761},{134,0,1198},{132,10,259},{6,11,343},{7,11,195},{9,11,226},{10,11, +197},{10,11,575},{11,11,502},{139,11,899},{7,0,1127},{7,0,1572},{10,0,297},{10,0 +,422},{11,0,764},{11,0,810},{12,0,264},{13,0,102},{13,0,300},{13,0,484},{14,0, +147},{14,0,229},{17,0,71},{18,0,118},{147,0,120},{135,11,666},{132,0,678},{4,10, +173},{5,10,312},{5,10,512},{135,10,1285},{7,10,1603},{7,10,1691},{9,10,464},{11, +10,195},{12,10,279},{12,10,448},{14,10,11},{147,10,102},{16,0,99},{146,0,164},{7 +,11,1125},{9,11,143},{11,11,61},{14,11,405},{150,11,21},{137,11,260},{4,10,452}, +{5,10,583},{5,10,817},{6,10,433},{7,10,593},{7,10,720},{7,10,1378},{8,10,161},{9 +,10,284},{10,10,313},{139,10,886},{132,10,547},{136,10,722},{14,0,35},{142,0,191 +},{141,0,45},{138,0,121},{132,0,125},{134,0,1622},{133,11,959},{8,10,420},{139, +10,193},{132,0,721},{135,10,409},{136,0,145},{7,0,792},{8,0,147},{8,11,173},{10, +0,821},{11,0,970},{139,0,1021},{134,11,266},{132,0,715},{7,0,1999},{138,10,308}, +{133,0,531},{5,0,168},{5,0,930},{8,0,74},{9,0,623},{12,0,500},{140,0,579},{144,0 +,65},{138,11,246},{6,0,220},{7,0,1101},{13,0,105},{142,11,314},{5,10,1002},{136, +10,745},{134,0,960},{20,0,0},{148,11,0},{4,0,1005},{4,10,239},{6,10,477},{7,10, +1607},{11,10,68},{139,10,617},{6,0,19},{7,0,1413},{139,0,428},{149,10,13},{7,0, +96},{8,0,401},{8,0,703},{8,11,300},{137,0,896},{134,0,1595},{145,0,116},{136,0, +1021},{7,0,1961},{7,0,1965},{7,0,2030},{8,0,150},{8,0,702},{8,0,737},{8,0,750},{ +140,0,366},{11,11,75},{142,11,267},{132,10,367},{5,11,427},{5,11,734},{7,11,478} +,{8,0,800},{8,11,52},{9,0,148},{9,0,872},{9,0,890},{11,0,309},{11,0,1001},{13,0, +267},{141,0,323},{7,11,239},{11,11,217},{142,11,165},{132,11,323},{140,11,419},{ +13,0,299},{142,0,75},{6,11,87},{6,11,1734},{7,11,20},{7,11,1056},{8,11,732},{9, +11,406},{9,11,911},{138,11,694},{134,0,1383},{132,10,694},{133,11,613},{137,0, +779},{4,0,598},{140,10,687},{6,0,970},{135,0,424},{133,0,547},{7,11,32},{7,11, +984},{8,11,85},{8,11,709},{9,11,579},{9,11,847},{9,11,856},{10,11,799},{11,11, +258},{11,11,1007},{12,11,331},{12,11,615},{13,11,188},{13,11,435},{14,11,8},{15, +11,165},{16,11,27},{148,11,40},{6,0,1222},{134,0,1385},{132,0,876},{138,11,151}, +{135,10,213},{4,11,167},{135,11,82},{133,0,133},{6,11,24},{7,11,74},{7,11,678},{ +137,11,258},{5,11,62},{6,11,534},{7,11,684},{7,11,1043},{7,11,1072},{8,11,280},{ +8,11,541},{8,11,686},{10,11,519},{11,11,252},{140,11,282},{136,0,187},{8,0,8},{ +10,0,0},{10,0,818},{139,0,988},{132,11,359},{7,10,1672},{11,0,429},{143,0,51},{ +136,0,685},{5,11,211},{7,11,88},{136,11,627},{134,0,472},{136,0,132},{6,11,145}, +{141,11,336},{4,10,751},{11,10,390},{140,10,32},{4,10,409},{4,11,263},{5,10,78}, +{6,0,938},{134,0,1060},{137,0,874},{4,11,916},{6,10,473},{7,10,1602},{8,0,774},{ +10,0,670},{10,10,698},{12,0,51},{12,10,212},{13,10,307},{145,10,105},{146,0,92}, +{143,10,156},{132,0,830},{137,0,701},{4,11,599},{6,11,1634},{7,11,5},{7,11,55},{ +7,11,67},{7,11,97},{7,11,691},{7,11,979},{7,11,1697},{8,11,207},{8,11,214},{8,11 +,231},{8,11,294},{8,11,336},{8,11,428},{8,11,451},{8,11,460},{8,11,471},{8,11, +622},{8,11,626},{8,11,679},{8,11,759},{8,11,829},{9,11,11},{9,11,246},{9,11,484} +,{9,11,573},{9,11,706},{9,11,762},{9,11,798},{9,11,855},{9,11,870},{9,11,912},{ +10,11,303},{10,11,335},{10,11,424},{10,11,461},{10,11,543},{10,11,759},{10,11, +814},{11,11,59},{11,11,199},{11,11,235},{11,11,475},{11,11,590},{11,11,929},{11, +11,963},{12,11,114},{12,11,182},{12,11,226},{12,11,332},{12,11,439},{12,11,575}, +{12,11,598},{13,11,8},{13,11,125},{13,11,194},{13,11,287},{14,11,197},{14,11,383 +},{15,11,53},{17,11,63},{19,11,46},{19,11,98},{19,11,106},{148,11,85},{4,0,127}, +{5,0,350},{6,0,356},{8,0,426},{9,0,572},{10,0,247},{139,0,312},{134,0,1215},{6,0 +,59},{7,11,1853},{9,0,603},{10,11,437},{141,0,397},{134,0,1762},{147,11,126},{ +135,10,883},{13,0,293},{142,0,56},{133,10,617},{139,10,50},{5,11,187},{7,10,1518 +},{139,10,694},{135,0,441},{6,0,111},{7,0,4},{8,0,163},{8,0,776},{138,0,566},{ +132,0,806},{4,11,215},{9,11,38},{10,11,3},{11,11,23},{11,11,127},{139,11,796},{4 +,10,546},{7,10,2042},{142,0,233},{135,0,1994},{134,0,1739},{135,11,1530},{136,0, +393},{5,0,297},{7,0,1038},{14,0,359},{19,0,52},{148,0,47},{135,0,309},{4,10,313} +,{133,10,577},{8,10,184},{141,10,433},{135,10,935},{12,10,186},{12,10,292},{14, +10,100},{146,10,70},{136,0,363},{11,10,402},{12,10,109},{12,10,431},{13,10,179}, +{13,10,206},{14,0,175},{14,10,217},{16,10,3},{148,10,53},{5,10,886},{6,10,46},{6 +,10,1790},{7,10,14},{7,10,732},{7,10,1654},{8,10,95},{8,10,327},{8,10,616},{9,10 +,892},{10,10,598},{10,10,769},{11,10,134},{11,10,747},{12,10,378},{142,10,97},{ +136,0,666},{135,0,1675},{6,0,655},{134,0,1600},{135,0,808},{133,10,1021},{4,11, +28},{5,11,440},{7,11,248},{11,11,833},{140,11,344},{134,11,1654},{132,0,280},{ +140,0,54},{4,0,421},{133,0,548},{132,10,153},{6,11,339},{135,11,923},{133,11,853 +},{133,10,798},{132,10,587},{6,11,249},{7,11,1234},{139,11,573},{6,10,598},{7,10 +,42},{8,10,695},{10,10,212},{11,10,158},{14,10,196},{145,10,85},{5,10,957},{5,10 +,1008},{135,0,249},{4,10,129},{135,10,465},{6,0,254},{7,0,842},{7,0,1659},{7,10, +908},{7,10,1201},{9,0,109},{9,10,755},{10,0,103},{11,10,906},{12,10,527},{146,10 +,7},{5,0,262},{136,10,450},{144,0,1},{10,11,201},{142,11,319},{7,11,49},{7,11, +392},{8,11,20},{8,11,172},{8,11,690},{9,11,383},{9,11,845},{10,11,48},{11,11,293 +},{11,11,832},{11,11,920},{141,11,221},{5,11,858},{133,11,992},{134,0,805},{139, +10,1003},{6,0,1630},{134,11,307},{7,11,1512},{135,11,1794},{6,11,268},{137,11,62 +},{135,10,1868},{133,0,671},{4,0,989},{8,0,972},{136,0,998},{132,11,423},{132,0, +889},{135,0,1382},{135,0,1910},{7,10,965},{7,10,1460},{135,10,1604},{4,0,627},{5 +,0,775},{138,11,106},{134,11,348},{7,0,202},{11,0,362},{11,0,948},{140,0,388},{ +138,11,771},{6,11,613},{136,11,223},{6,0,560},{7,0,451},{8,0,389},{12,0,490},{13 +,0,16},{13,0,215},{13,0,351},{18,0,132},{147,0,125},{135,0,841},{136,0,566},{136 +,0,938},{132,11,670},{5,0,912},{6,0,1695},{140,11,55},{9,11,40},{139,11,136},{7, +0,1361},{7,10,982},{10,10,32},{143,10,56},{11,11,259},{140,11,270},{5,0,236},{6, +0,572},{8,0,492},{11,0,618},{144,0,56},{8,11,572},{9,11,310},{9,11,682},{137,11, +698},{134,0,1854},{5,0,190},{136,0,318},{133,10,435},{135,0,1376},{4,11,296},{6, +11,352},{7,11,401},{7,11,1410},{7,11,1594},{7,11,1674},{8,11,63},{8,11,660},{137 +,11,74},{5,10,85},{6,10,419},{7,0,349},{7,10,305},{7,10,361},{7,10,1337},{8,10, +71},{140,10,519},{4,11,139},{4,11,388},{140,11,188},{6,0,1972},{6,0,2013},{8,0, +951},{10,0,947},{10,0,974},{10,0,1018},{142,0,476},{140,10,688},{135,10,740},{5, +10,691},{7,10,345},{9,10,94},{140,10,169},{5,10,183},{6,10,582},{9,0,344},{10,10 +,679},{140,10,435},{135,10,511},{132,0,850},{8,11,441},{10,11,314},{143,11,3},{7 +,10,1993},{136,10,684},{4,11,747},{6,10,583},{6,11,290},{7,11,649},{7,11,1479},{ +135,11,1583},{133,11,232},{133,10,704},{134,0,910},{4,10,179},{5,10,198},{133,10 +,697},{7,10,347},{7,10,971},{8,10,181},{138,10,711},{136,11,525},{14,0,19},{14,0 +,28},{144,0,29},{7,0,85},{7,0,247},{8,0,585},{138,0,163},{4,0,487},{7,11,472},{7 +,11,1801},{10,11,748},{141,11,458},{4,10,243},{5,10,203},{7,10,19},{7,10,71},{7, +10,113},{10,10,405},{11,10,357},{142,10,240},{7,10,1450},{139,10,99},{132,11,425 +},{138,0,145},{147,0,83},{6,10,492},{137,11,247},{4,0,1013},{134,0,2033},{5,10, +134},{6,10,408},{6,10,495},{135,10,1593},{135,0,1922},{134,11,1768},{4,0,124},{ +10,0,457},{11,0,121},{11,0,169},{11,0,870},{11,0,874},{12,0,214},{14,0,187},{143 +,0,77},{5,0,557},{135,0,1457},{139,0,66},{5,11,943},{6,11,1779},{142,10,4},{4,10 +,248},{4,10,665},{7,10,137},{137,10,349},{5,11,245},{6,11,576},{7,0,1193},{7,11, +582},{136,11,225},{144,0,82},{7,10,1270},{139,10,612},{5,0,454},{10,0,352},{138, +11,352},{5,10,371},{7,10,563},{146,0,57},{135,0,1333},{6,0,107},{6,11,610},{7,0, +638},{7,0,1632},{137,0,396},{5,0,370},{134,0,1756},{4,10,374},{7,10,547},{7,10, +1700},{7,10,1833},{139,10,858},{133,0,204},{6,0,1305},{9,10,311},{141,10,42},{5, +0,970},{134,0,1706},{6,10,1647},{7,10,1552},{7,10,2010},{9,10,494},{137,10,509}, +{13,11,455},{15,11,99},{15,11,129},{144,11,68},{135,0,3},{4,0,35},{5,0,121},{5,0 +,483},{5,0,685},{6,0,489},{6,0,782},{6,0,1032},{7,0,1204},{136,0,394},{4,0,921}, +{133,0,1007},{8,11,360},{138,11,63},{135,0,1696},{134,0,1519},{132,11,443},{135, +11,944},{6,10,123},{7,10,214},{9,10,728},{10,10,157},{11,10,346},{11,10,662},{ +143,10,106},{137,0,981},{135,10,1435},{134,0,1072},{132,0,712},{134,0,1629},{134 +,0,728},{4,11,298},{137,11,483},{5,11,164},{6,0,1177},{6,0,1271},{7,11,121},{142 +,11,189},{4,10,707},{5,10,588},{6,10,393},{7,0,1608},{13,10,106},{18,10,49},{147 +,10,41},{23,0,16},{151,11,16},{6,10,211},{7,10,1690},{11,10,486},{140,10,369},{ +133,0,485},{19,11,15},{149,11,27},{4,11,172},{9,11,611},{10,11,436},{12,11,673}, +{141,11,255},{5,11,844},{10,11,484},{11,11,754},{12,11,457},{14,11,171},{14,11, +389},{146,11,153},{4,0,285},{5,0,27},{5,0,317},{6,0,301},{7,0,7},{8,0,153},{10,0 +,766},{11,0,468},{12,0,467},{141,0,143},{134,0,1462},{9,11,263},{10,11,147},{138 +,11,492},{133,11,537},{6,0,1945},{6,0,1986},{6,0,1991},{134,0,2038},{134,10,219} +,{137,11,842},{5,10,582},{6,10,1646},{7,10,99},{7,10,1962},{7,10,1986},{8,10,515 +},{8,10,773},{9,10,23},{9,10,491},{12,10,620},{14,0,52},{14,10,93},{145,0,50},{ +138,11,97},{5,10,851},{20,0,21},{148,0,44},{136,0,819},{139,0,917},{5,11,230},{5 +,11,392},{6,11,420},{8,10,762},{8,10,812},{9,10,910},{9,11,568},{140,11,612},{ +135,0,784},{15,0,135},{143,11,135},{10,0,454},{140,0,324},{4,11,0},{5,11,41},{7, +11,1459},{7,11,1469},{7,11,1618},{7,11,1859},{9,11,549},{139,11,905},{4,10,98},{ +7,10,1365},{9,10,422},{9,10,670},{10,10,775},{11,10,210},{13,10,26},{13,10,457}, +{141,10,476},{6,0,1719},{6,0,1735},{7,0,2016},{7,0,2020},{8,0,837},{137,0,852},{ +133,11,696},{135,0,852},{132,0,952},{134,10,1730},{132,11,771},{138,0,568},{137, +0,448},{139,0,146},{8,0,67},{138,0,419},{133,11,921},{137,10,147},{134,0,1826},{ +10,0,657},{14,0,297},{142,0,361},{6,0,666},{6,0,767},{134,0,1542},{139,0,729},{6 +,11,180},{7,11,1137},{8,11,751},{139,11,805},{4,11,183},{7,11,271},{11,11,824},{ +11,11,952},{13,11,278},{13,11,339},{13,11,482},{14,11,424},{148,11,99},{4,0,669} +,{5,11,477},{5,11,596},{6,11,505},{7,11,1221},{11,11,907},{12,11,209},{141,11, +214},{135,11,1215},{5,0,402},{6,10,30},{11,10,56},{139,10,305},{7,11,564},{142, +11,168},{139,0,152},{7,0,912},{135,10,1614},{4,10,150},{5,10,303},{134,10,327},{ +7,0,320},{8,0,51},{9,0,868},{10,0,833},{12,0,481},{12,0,570},{148,0,106},{132,0, +445},{7,11,274},{11,11,263},{11,11,479},{11,11,507},{140,11,277},{6,11,1645},{8, +10,192},{10,0,555},{10,10,78},{11,0,308},{13,10,359},{147,0,95},{135,10,786},{6, +11,92},{6,11,188},{7,11,1269},{7,11,1524},{7,11,1876},{10,11,228},{139,11,1020}, +{4,11,459},{133,11,966},{6,10,1638},{7,10,79},{7,10,496},{9,10,138},{10,10,336}, +{11,0,386},{12,10,412},{12,10,440},{142,10,305},{133,0,239},{7,0,83},{7,0,1990}, +{8,0,130},{139,0,720},{138,11,709},{4,0,143},{5,0,550},{133,0,752},{5,0,123},{6, +0,530},{7,0,348},{135,0,1419},{135,0,2024},{6,11,18},{7,11,179},{7,11,721},{7,11 +,932},{8,11,548},{8,11,757},{9,11,54},{9,11,65},{9,11,532},{9,11,844},{10,11,113 +},{10,11,117},{10,11,236},{10,11,315},{10,11,430},{10,11,798},{11,11,153},{11,11 +,351},{11,11,375},{12,11,78},{12,11,151},{12,11,392},{14,11,248},{143,11,23},{7, +10,204},{7,10,415},{8,10,42},{10,10,85},{139,10,564},{134,0,958},{133,11,965},{ +132,0,210},{135,11,1429},{138,11,480},{134,11,182},{139,11,345},{10,11,65},{10, +11,488},{138,11,497},{4,10,3},{5,10,247},{5,10,644},{7,10,744},{7,10,1207},{7,10 +,1225},{7,10,1909},{146,10,147},{132,0,430},{5,10,285},{9,10,67},{13,10,473},{ +143,10,82},{144,11,16},{7,11,1162},{9,11,588},{10,11,260},{151,10,8},{133,0,213} +,{138,0,7},{135,0,801},{134,11,1786},{135,11,308},{6,0,936},{134,0,1289},{133,0, +108},{132,0,885},{133,0,219},{139,0,587},{4,0,193},{5,0,916},{6,0,1041},{7,0,364 +},{10,0,398},{10,0,726},{11,0,317},{11,0,626},{12,0,142},{12,0,288},{12,0,678},{ +13,0,313},{15,0,113},{146,0,114},{135,0,1165},{6,0,241},{9,0,342},{10,0,729},{11 +,0,284},{11,0,445},{11,0,651},{11,0,863},{13,0,398},{146,0,99},{7,0,907},{136,0, +832},{4,10,29},{6,10,532},{7,10,1628},{7,10,1648},{9,0,303},{9,10,350},{10,10, +433},{11,10,97},{11,10,557},{11,10,745},{12,10,289},{12,10,335},{12,10,348},{12, +10,606},{13,10,116},{13,10,233},{13,10,466},{14,10,181},{14,10,209},{14,10,232}, +{14,10,236},{14,10,300},{16,10,41},{148,10,97},{7,10,1692},{7,11,423},{136,11, +588},{6,0,931},{134,0,1454},{5,10,501},{7,10,1704},{9,10,553},{11,10,520},{12,10 +,557},{141,10,249},{136,11,287},{4,0,562},{9,0,254},{139,0,879},{132,0,786},{14, +11,32},{18,11,85},{20,11,2},{152,11,16},{135,0,1294},{7,11,723},{135,11,1135},{6 +,0,216},{6,11,403},{7,0,901},{7,0,1343},{136,0,493},{7,11,719},{8,11,809},{136, +11,834},{5,11,210},{6,11,213},{7,11,60},{10,11,364},{139,11,135},{5,11,607},{7,0 +,341},{8,11,326},{8,11,490},{139,0,219},{4,11,701},{5,11,472},{5,11,639},{7,11, +1249},{9,11,758},{139,11,896},{135,11,380},{135,11,1947},{139,0,130},{135,0,1734 +},{10,0,115},{11,0,420},{12,0,154},{13,0,404},{14,0,346},{143,0,54},{134,10,129} +,{4,11,386},{7,11,41},{8,11,405},{9,11,497},{11,11,110},{11,11,360},{15,11,37},{ +144,11,84},{141,11,282},{5,11,46},{7,11,1452},{7,11,1480},{8,11,634},{140,11,472 +},{4,11,524},{136,11,810},{10,11,238},{141,11,33},{133,0,604},{5,0,1011},{136,0, +701},{8,0,856},{8,0,858},{8,0,879},{12,0,702},{142,0,447},{4,0,54},{5,0,666},{7, +0,1039},{7,0,1130},{9,0,195},{138,0,302},{4,10,25},{5,10,60},{6,10,504},{7,10, +614},{7,10,1155},{140,10,0},{7,10,1248},{11,10,621},{139,10,702},{133,11,997},{ +137,10,321},{134,0,1669},{134,0,1791},{4,10,379},{135,10,1397},{138,11,372},{5, +11,782},{5,11,829},{134,11,1738},{135,0,1228},{4,10,118},{6,10,274},{6,10,361},{ +7,10,75},{141,10,441},{132,0,623},{9,11,279},{10,11,407},{14,11,84},{150,11,18}, +{137,10,841},{135,0,798},{140,10,693},{5,10,314},{6,10,221},{7,10,419},{10,10, +650},{11,10,396},{12,10,156},{13,10,369},{14,10,333},{145,10,47},{135,11,1372},{ +7,0,122},{9,0,259},{10,0,84},{11,0,470},{12,0,541},{141,0,379},{134,0,837},{4,11 +,78},{5,11,96},{5,11,182},{7,11,1724},{7,11,1825},{8,0,1013},{10,11,394},{10,11, +471},{11,11,532},{14,11,340},{145,11,88},{134,0,577},{135,11,1964},{132,10,913}, +{134,0,460},{8,0,891},{10,0,901},{10,0,919},{10,0,932},{12,0,715},{12,0,728},{12 +,0,777},{14,0,457},{144,0,103},{5,0,82},{5,0,131},{7,0,1755},{8,0,31},{9,0,168}, +{9,0,764},{139,0,869},{136,10,475},{5,10,1016},{6,0,605},{9,11,601},{9,11,619},{ +10,11,505},{10,11,732},{11,11,355},{140,11,139},{7,10,602},{8,10,179},{10,10,781 +},{140,10,126},{134,0,1246},{6,10,329},{138,10,111},{6,11,215},{7,11,1028},{7,11 +,1473},{7,11,1721},{9,11,424},{138,11,779},{5,0,278},{137,0,68},{6,0,932},{6,0, +1084},{144,0,86},{4,0,163},{5,0,201},{5,0,307},{5,0,310},{6,0,335},{7,0,284},{7, +0,1660},{136,0,165},{136,0,781},{134,0,707},{6,0,33},{135,0,1244},{5,10,821},{6, +10,1687},{6,11,67},{7,11,258},{7,11,1630},{9,11,354},{9,11,675},{10,11,830},{14, +11,80},{145,11,80},{6,11,141},{7,11,225},{9,11,59},{9,11,607},{10,11,312},{11,11 +,687},{12,11,555},{13,11,373},{13,11,494},{148,11,58},{134,0,1113},{5,10,71},{7, +10,1407},{9,0,388},{9,10,704},{10,10,261},{10,10,619},{11,10,547},{11,10,619},{ +143,10,157},{7,0,1953},{136,0,720},{138,0,203},{7,10,2008},{9,10,337},{138,10, +517},{6,0,326},{7,0,677},{137,0,425},{139,11,81},{7,0,1316},{7,0,1412},{7,0,1839 +},{9,0,589},{11,0,241},{11,0,676},{11,0,811},{11,0,891},{12,0,140},{12,0,346},{ +12,0,479},{13,0,140},{13,0,381},{14,0,188},{18,0,30},{148,0,108},{5,0,416},{6,10 +,86},{6,10,603},{7,10,292},{7,10,561},{8,10,257},{8,10,382},{9,10,721},{9,10,778 +},{11,10,581},{140,10,466},{4,10,486},{133,10,491},{134,0,1300},{132,10,72},{6, +10,265},{7,0,847},{7,11,430},{139,11,46},{5,11,602},{6,11,106},{7,11,1786},{7,11 +,1821},{7,11,2018},{9,11,418},{137,11,763},{5,0,358},{7,0,535},{7,0,1184},{10,0, +662},{13,0,212},{13,0,304},{13,0,333},{145,0,98},{5,11,65},{6,11,416},{7,11,1720 +},{7,11,1924},{8,11,677},{10,11,109},{11,11,14},{11,11,70},{11,11,569},{11,11, +735},{15,11,153},{148,11,80},{6,0,1823},{8,0,839},{8,0,852},{8,0,903},{10,0,940} +,{12,0,707},{140,0,775},{135,11,1229},{6,0,1522},{140,0,654},{136,11,595},{139,0 +,163},{141,0,314},{132,0,978},{4,0,601},{6,0,2035},{137,10,234},{5,10,815},{6,10 +,1688},{134,10,1755},{133,0,946},{136,0,434},{6,10,197},{136,10,205},{7,0,411},{ +7,0,590},{8,0,631},{9,0,323},{10,0,355},{11,0,491},{12,0,143},{12,0,402},{13,0, +73},{14,0,408},{15,0,107},{146,0,71},{7,0,1467},{8,0,328},{10,0,544},{11,0,955}, +{12,0,13},{13,0,320},{145,0,83},{142,0,410},{11,0,511},{13,0,394},{14,0,298},{14 +,0,318},{146,0,103},{6,10,452},{7,10,312},{138,10,219},{138,10,589},{4,10,333},{ +9,10,176},{12,10,353},{141,10,187},{135,11,329},{132,11,469},{5,0,835},{134,0, +483},{134,11,1743},{5,11,929},{6,11,340},{8,11,376},{136,11,807},{134,10,1685},{ +132,0,677},{5,11,218},{7,11,1610},{138,11,83},{5,11,571},{135,11,1842},{132,11, +455},{137,0,70},{135,0,1405},{7,10,135},{8,10,7},{8,10,62},{9,10,243},{10,10,658 +},{10,10,697},{11,10,456},{139,10,756},{9,10,395},{138,10,79},{137,0,108},{6,11, +161},{7,11,372},{137,11,597},{132,11,349},{132,0,777},{132,0,331},{135,10,631},{ +133,0,747},{6,11,432},{6,11,608},{139,11,322},{138,10,835},{5,11,468},{7,11,1809 +},{10,11,325},{11,11,856},{12,11,345},{143,11,104},{133,11,223},{7,10,406},{7,10 +,459},{8,10,606},{139,10,726},{132,11,566},{142,0,68},{4,11,59},{135,11,1394},{6 +,11,436},{139,11,481},{4,11,48},{5,11,271},{135,11,953},{139,11,170},{5,11,610}, +{136,11,457},{133,11,755},{135,11,1217},{133,10,612},{132,11,197},{132,0,505},{4 +,10,372},{7,10,482},{8,10,158},{9,10,602},{9,10,615},{10,10,245},{10,10,678},{10 +,10,744},{11,10,248},{139,10,806},{133,0,326},{5,10,854},{135,10,1991},{4,0,691} +,{146,0,16},{6,0,628},{9,0,35},{10,0,680},{10,0,793},{11,0,364},{13,0,357},{143, +0,164},{138,0,654},{6,0,32},{7,0,385},{7,0,757},{7,0,1916},{8,0,37},{8,0,94},{8, +0,711},{9,0,541},{10,0,162},{10,0,795},{11,0,989},{11,0,1010},{12,0,14},{142,0, +308},{133,11,217},{6,0,152},{6,0,349},{6,0,1682},{7,0,1252},{8,0,112},{9,0,435}, +{9,0,668},{10,0,290},{10,0,319},{10,0,815},{11,0,180},{11,0,837},{12,0,240},{13, +0,152},{13,0,219},{142,0,158},{4,0,581},{134,0,726},{5,10,195},{135,10,1685},{6, +0,126},{7,0,573},{8,0,397},{142,0,44},{138,0,89},{7,10,1997},{8,10,730},{139,10, +1006},{134,0,1531},{134,0,1167},{5,0,926},{5,10,751},{140,0,203},{4,11,165},{7, +11,1398},{135,11,1829},{7,0,1232},{137,0,531},{135,10,821},{134,0,943},{133,0, +670},{4,0,880},{139,0,231},{134,0,1617},{135,0,1957},{5,11,9},{7,11,297},{7,11, +966},{140,11,306},{6,0,975},{134,0,985},{5,10,950},{5,10,994},{134,10,351},{12, +11,21},{151,11,7},{5,11,146},{6,11,411},{138,11,721},{7,0,242},{135,0,1942},{6, +11,177},{135,11,467},{5,0,421},{7,10,47},{137,10,684},{5,0,834},{7,0,1202},{8,0, +14},{9,0,481},{137,0,880},{138,0,465},{4,10,350},{6,0,688},{137,0,834},{132,0, +855},{4,0,357},{6,0,172},{7,0,143},{137,0,413},{133,11,200},{132,0,590},{7,10, +1812},{13,10,259},{13,10,356},{14,10,242},{147,10,114},{133,10,967},{4,10,473},{ +7,10,623},{8,10,808},{9,10,871},{9,10,893},{11,0,114},{11,10,431},{12,10,112},{ +12,10,217},{12,10,243},{12,10,562},{12,10,663},{12,10,683},{13,10,141},{13,10, +197},{13,10,227},{13,10,406},{13,10,487},{14,10,156},{14,10,203},{14,10,224},{14 +,10,256},{18,10,58},{150,10,0},{138,10,286},{4,10,222},{7,10,286},{136,10,629},{ +5,0,169},{7,0,333},{136,0,45},{134,11,481},{132,0,198},{4,0,24},{4,11,84},{5,0, +140},{5,0,185},{7,0,1500},{7,11,1482},{10,11,76},{10,11,142},{11,0,565},{139,0, +838},{133,0,585},{141,10,306},{133,11,1015},{4,11,315},{5,11,507},{135,11,1370}, +{136,10,146},{6,0,691},{134,0,1503},{4,0,334},{133,0,593},{4,10,465},{135,10, +1663},{142,11,173},{135,0,913},{6,11,1722},{140,0,116},{134,0,1360},{132,0,802}, +{8,11,222},{8,11,476},{9,11,238},{11,11,516},{11,11,575},{15,11,109},{146,11,100 +},{6,0,308},{7,10,138},{7,10,517},{9,0,673},{139,10,238},{132,0,709},{6,0,1876}, +{6,0,1895},{9,0,994},{9,0,1006},{12,0,829},{12,0,888},{12,0,891},{146,0,185},{ +148,10,94},{4,0,228},{133,0,897},{5,10,495},{7,0,1840},{7,10,834},{9,10,733},{ +139,10,378},{133,10,559},{6,10,21},{6,10,1737},{7,10,1444},{136,10,224},{4,0,608 +},{133,0,497},{6,11,40},{135,11,1781},{134,0,1573},{135,0,2039},{6,0,540},{136,0 +,136},{4,0,897},{5,0,786},{133,10,519},{6,0,1878},{6,0,1884},{9,0,938},{9,0,948} +,{9,0,955},{9,0,973},{9,0,1012},{12,0,895},{12,0,927},{143,0,254},{134,0,1469},{ +133,0,999},{4,0,299},{135,0,1004},{4,0,745},{133,0,578},{136,11,574},{133,0,456} +,{134,0,1457},{4,10,402},{135,0,1679},{7,0,693},{8,0,180},{8,10,323},{8,10,479}, +{140,0,163},{11,10,580},{142,10,201},{5,10,59},{135,10,672},{132,11,354},{146,10 +,34},{4,0,755},{135,11,1558},{7,0,1740},{146,0,48},{4,10,85},{135,10,549},{139,0 +,338},{133,10,94},{134,0,1091},{135,11,469},{5,11,830},{12,0,695},{12,0,704},{14 +,11,338},{20,0,113},{148,11,81},{135,0,1464},{6,10,11},{135,10,187},{135,0,975}, +{4,10,522},{141,0,335},{134,0,1979},{5,11,496},{135,11,203},{4,10,52},{135,10, +661},{7,0,1566},{8,0,269},{9,0,212},{9,0,718},{14,0,15},{14,0,132},{142,0,227},{ +4,0,890},{4,10,383},{5,0,805},{5,0,819},{5,0,961},{5,10,520},{6,0,396},{6,0,1631 +},{6,0,1678},{7,0,1967},{7,0,2041},{9,0,630},{11,0,8},{11,0,1019},{12,0,176},{13 +,0,225},{14,0,292},{149,0,24},{134,11,547},{135,11,1748},{5,11,88},{137,11,239}, +{146,11,128},{7,11,650},{135,11,1310},{4,10,281},{5,10,38},{7,10,194},{7,10,668} +,{7,10,1893},{137,10,397},{135,0,1815},{9,10,635},{139,10,559},{7,0,1505},{10,0, +190},{10,0,634},{11,0,792},{12,0,358},{140,0,447},{5,0,0},{6,0,536},{7,0,604},{ +13,0,445},{145,0,126},{7,11,1076},{9,11,80},{11,11,78},{11,11,421},{11,11,534},{ +140,11,545},{8,0,966},{10,0,1023},{14,11,369},{146,11,72},{135,11,1641},{6,0,232 +},{6,0,412},{7,0,1074},{8,0,9},{8,0,157},{8,0,786},{9,0,196},{9,0,352},{9,0,457} +,{10,0,337},{11,0,232},{11,0,877},{12,0,480},{140,0,546},{135,0,958},{4,0,382},{ +136,0,579},{4,0,212},{135,0,1206},{4,11,497},{5,11,657},{135,11,1584},{132,0,681 +},{8,0,971},{138,0,965},{5,10,448},{136,10,535},{14,0,16},{146,0,44},{11,0,584}, +{11,0,616},{11,11,584},{11,11,616},{14,0,275},{142,11,275},{136,11,13},{7,10,610 +},{135,10,1501},{7,11,642},{8,11,250},{11,11,123},{11,11,137},{13,11,48},{142,11 +,95},{133,0,655},{17,0,67},{147,0,74},{134,0,751},{134,0,1967},{6,0,231},{136,0, +423},{5,0,300},{138,0,1016},{4,10,319},{5,10,699},{138,10,673},{6,0,237},{6,10, +336},{7,0,611},{8,0,100},{8,10,552},{9,0,416},{9,10,285},{10,10,99},{11,0,335},{ +11,10,568},{12,0,173},{146,0,101},{134,0,1370},{7,10,1406},{9,10,218},{141,10, +222},{133,10,256},{135,0,1208},{14,11,213},{148,11,38},{6,0,1219},{135,11,1642}, +{13,0,417},{14,0,129},{143,0,15},{10,11,545},{140,11,301},{17,10,39},{148,10,36} +,{133,0,199},{4,11,904},{133,11,794},{12,0,427},{146,0,38},{134,0,949},{7,10,634 +},{136,0,665},{132,10,618},{135,10,259},{132,10,339},{133,11,761},{141,10,169},{ +132,10,759},{5,0,688},{7,0,539},{135,0,712},{7,11,386},{138,11,713},{134,0,1186} +,{6,11,7},{6,11,35},{7,11,147},{7,11,1069},{7,11,1568},{7,11,1575},{7,11,1917},{ +8,11,43},{8,11,208},{9,11,128},{9,11,866},{10,11,20},{11,11,981},{147,11,33},{7, +11,893},{8,10,482},{141,11,424},{6,0,312},{6,0,1715},{10,0,584},{11,0,546},{11,0 +,692},{12,0,259},{12,0,295},{13,0,46},{141,0,154},{5,10,336},{6,10,341},{6,10, +478},{6,10,1763},{136,10,386},{137,0,151},{132,0,588},{152,0,4},{6,11,322},{9,11 +,552},{11,11,274},{13,11,209},{13,11,499},{14,11,85},{15,11,126},{145,11,70},{ +135,10,73},{4,0,231},{5,0,61},{6,0,104},{7,0,729},{7,0,964},{7,0,1658},{140,0, +414},{6,0,263},{138,0,757},{135,10,1971},{4,0,612},{133,0,561},{132,0,320},{135, +10,1344},{8,11,83},{8,11,817},{9,11,28},{9,11,29},{9,11,885},{10,11,387},{11,11, +633},{11,11,740},{13,11,235},{13,11,254},{15,11,143},{143,11,146},{5,10,396},{ +134,10,501},{140,11,49},{132,0,225},{4,10,929},{5,10,799},{8,10,46},{136,10,740} +,{4,0,405},{7,0,817},{14,0,58},{17,0,37},{146,0,124},{133,0,974},{4,11,412},{133 +,11,581},{4,10,892},{133,10,770},{4,0,996},{134,0,2026},{4,0,527},{5,0,235},{7,0 +,1239},{11,0,131},{140,0,370},{7,11,421},{9,0,16},{141,0,386},{7,0,956},{7,0, +1157},{7,0,1506},{7,0,1606},{7,0,1615},{7,0,1619},{7,0,1736},{7,0,1775},{8,0,590 +},{9,0,324},{9,0,736},{9,0,774},{9,0,776},{9,0,784},{10,0,567},{10,0,708},{11,0, +518},{11,0,613},{11,0,695},{11,0,716},{11,0,739},{11,0,770},{11,0,771},{11,0,848 +},{11,0,857},{11,0,931},{11,0,947},{12,0,326},{12,0,387},{12,0,484},{12,0,528},{ +12,0,552},{12,0,613},{13,0,189},{13,0,256},{13,0,340},{13,0,432},{13,0,436},{13, +0,440},{13,0,454},{14,0,174},{14,0,220},{14,0,284},{14,0,390},{145,0,121},{135, +10,158},{9,0,137},{138,0,221},{4,11,110},{10,11,415},{10,11,597},{142,11,206},{ +141,11,496},{135,11,205},{151,10,25},{135,11,778},{7,10,2001},{7,11,1656},{9,11, +369},{10,11,338},{10,11,490},{11,11,154},{11,11,545},{11,11,775},{13,11,77},{141 +,11,274},{4,11,444},{10,11,146},{140,11,9},{7,0,390},{138,0,140},{135,0,1144},{ +134,0,464},{7,10,1461},{140,10,91},{132,10,602},{4,11,283},{135,11,1194},{5,0, +407},{11,0,204},{11,0,243},{11,0,489},{12,0,293},{19,0,37},{20,0,73},{150,0,38}, +{7,0,1218},{136,0,303},{4,10,13},{5,0,325},{5,10,567},{7,10,1498},{8,0,5},{8,0, +227},{9,0,105},{9,10,124},{10,0,585},{11,10,521},{12,0,614},{140,10,405},{135,10 +,1006},{6,11,1720},{7,0,800},{138,0,12},{135,0,1783},{132,10,735},{138,10,812},{ +4,10,170},{135,10,323},{6,0,621},{13,0,504},{144,0,89},{5,10,304},{135,10,1403}, +{137,11,216},{6,0,920},{6,0,1104},{9,11,183},{139,11,286},{4,0,376},{133,10,742} +,{134,0,218},{8,0,641},{11,0,388},{140,0,580},{7,0,454},{7,0,782},{8,0,768},{140 +,0,686},{137,11,33},{133,10,111},{144,0,0},{10,0,676},{140,0,462},{6,0,164},{136 +,11,735},{133,10,444},{150,0,50},{7,11,1862},{12,11,491},{12,11,520},{13,11,383} +,{14,11,244},{146,11,12},{5,11,132},{9,11,486},{9,11,715},{10,11,458},{11,11,373 +},{11,11,668},{11,11,795},{11,11,897},{12,11,272},{12,11,424},{12,11,539},{12,11 +,558},{14,11,245},{14,11,263},{14,11,264},{14,11,393},{142,11,403},{8,10,123},{ +15,10,6},{144,10,7},{6,0,285},{8,0,654},{11,0,749},{12,0,190},{12,0,327},{13,0, +120},{13,0,121},{13,0,327},{15,0,47},{146,0,40},{5,11,8},{6,11,89},{6,11,400},{7 +,11,1569},{7,11,1623},{7,11,1850},{8,11,218},{8,11,422},{9,11,570},{138,11,626}, +{6,11,387},{7,11,882},{141,11,111},{6,0,343},{6,11,224},{7,0,195},{7,11,877},{9, +0,226},{9,11,647},{10,0,197},{10,0,575},{11,0,502},{139,0,899},{5,10,937},{135, +10,100},{135,11,790},{150,0,29},{147,0,8},{134,0,1812},{149,0,8},{135,11,394},{7 +,0,1125},{9,0,143},{11,0,61},{14,0,405},{150,0,21},{10,11,755},{147,11,29},{9,11 +,378},{141,11,162},{135,10,922},{5,10,619},{133,10,698},{134,0,1327},{6,0,1598}, +{137,0,575},{9,11,569},{12,11,12},{12,11,81},{12,11,319},{13,11,69},{14,11,259}, +{16,11,87},{17,11,1},{17,11,21},{17,11,24},{18,11,15},{18,11,56},{18,11,59},{18, +11,127},{18,11,154},{19,11,19},{148,11,31},{6,0,895},{135,11,1231},{5,0,959},{7, +11,124},{136,11,38},{5,11,261},{7,11,78},{7,11,199},{8,11,815},{9,11,126},{138, +11,342},{5,10,917},{134,10,1659},{5,11,595},{7,0,1759},{135,11,1863},{136,0,173} +,{134,0,266},{142,0,261},{132,11,628},{5,10,251},{5,10,956},{8,10,268},{9,10,214 +},{146,10,142},{7,11,266},{136,11,804},{135,11,208},{6,11,79},{7,11,1021},{135, +11,1519},{11,11,704},{141,11,396},{5,10,346},{5,10,711},{136,10,390},{136,11,741 +},{134,11,376},{134,0,1427},{6,0,1033},{6,0,1217},{136,0,300},{133,10,624},{6,11 +,100},{7,11,244},{7,11,632},{7,11,1609},{8,11,178},{8,11,638},{141,11,58},{5,10, +783},{6,0,584},{7,10,1998},{135,10,2047},{5,0,427},{5,0,734},{7,0,478},{136,0,52 +},{7,0,239},{11,0,217},{142,0,165},{134,0,1129},{6,0,168},{6,0,1734},{7,0,20},{7 +,0,1056},{8,0,732},{9,0,406},{9,0,911},{138,0,694},{132,10,594},{133,11,791},{7, +11,686},{8,11,33},{8,11,238},{10,11,616},{11,11,467},{11,11,881},{13,11,217},{13 +,11,253},{142,11,268},{137,11,476},{134,0,418},{133,0,613},{132,0,632},{132,11, +447},{7,0,32},{7,0,984},{8,0,85},{8,0,709},{9,0,579},{9,0,847},{9,0,856},{10,0, +799},{11,0,258},{11,0,1007},{12,0,331},{12,0,615},{13,0,188},{13,0,435},{14,0,8} +,{15,0,165},{16,0,27},{16,11,35},{148,0,40},{4,11,128},{5,11,415},{6,11,462},{7, +11,294},{7,11,578},{10,11,710},{139,11,86},{5,0,694},{136,0,909},{5,10,37},{6,10 +,39},{6,10,451},{7,0,1109},{7,10,218},{7,10,1166},{7,10,1687},{8,10,662},{11,0,7 +},{144,10,2},{136,11,587},{6,11,427},{7,11,1018},{138,11,692},{4,11,195},{6,10, +508},{135,11,802},{4,0,167},{135,0,82},{5,0,62},{6,0,24},{6,0,534},{7,0,74},{7,0 +,678},{7,0,684},{7,0,1043},{7,0,1072},{8,0,280},{8,0,541},{8,0,686},{9,0,258},{ +10,0,519},{11,0,252},{140,0,282},{138,0,33},{4,0,359},{133,11,738},{7,0,980},{7, +10,635},{7,10,796},{8,10,331},{9,0,328},{9,10,330},{9,10,865},{10,10,119},{10,10 +,235},{11,10,111},{11,10,129},{11,10,240},{12,10,31},{12,10,66},{12,10,222},{12, +10,269},{12,10,599},{12,10,684},{12,10,689},{12,10,691},{13,0,186},{13,0,364},{ +142,10,345},{137,10,527},{6,0,596},{7,0,585},{135,10,702},{134,11,1683},{133,0, +211},{6,0,145},{141,0,336},{134,0,1130},{6,10,37},{7,0,873},{7,10,1666},{8,10, +195},{8,10,316},{9,10,178},{9,10,276},{9,10,339},{9,10,536},{10,10,102},{10,10, +362},{10,10,785},{11,10,55},{11,10,149},{11,10,773},{13,10,416},{13,10,419},{14, +10,38},{14,10,41},{142,10,210},{8,0,840},{136,0,841},{132,0,263},{5,11,3},{8,11, +578},{9,11,118},{10,11,705},{12,11,383},{141,11,279},{132,0,916},{133,11,229},{ +133,10,645},{8,11,102},{10,11,578},{10,11,672},{12,11,496},{13,11,408},{14,11, +121},{15,0,155},{16,0,79},{145,11,106},{4,0,599},{5,0,592},{6,0,1634},{7,0,5},{7 +,0,55},{7,0,67},{7,0,97},{7,0,691},{7,0,979},{7,0,1600},{7,0,1697},{8,0,207},{8, +0,214},{8,0,231},{8,0,294},{8,0,336},{8,0,428},{8,0,471},{8,0,622},{8,0,626},{8, +0,679},{8,0,759},{8,0,829},{9,0,11},{9,0,246},{9,0,484},{9,0,573},{9,0,706},{9,0 +,762},{9,0,798},{9,0,855},{9,0,870},{9,0,912},{10,0,303},{10,0,335},{10,0,424},{ +10,0,461},{10,0,543},{10,0,759},{10,0,814},{11,0,59},{11,0,199},{11,0,235},{11,0 +,590},{11,0,631},{11,0,929},{11,0,963},{11,0,987},{12,0,114},{12,0,182},{12,0, +226},{12,0,332},{12,0,439},{12,0,575},{12,0,598},{12,0,675},{13,0,8},{13,0,125}, +{13,0,194},{13,0,287},{14,0,197},{14,0,383},{15,0,53},{17,0,63},{19,0,46},{19,0, +98},{19,0,106},{148,0,85},{4,10,290},{135,0,1356},{6,10,70},{7,10,1292},{10,10, +762},{139,10,288},{150,11,55},{4,0,593},{8,11,115},{8,11,350},{9,11,489},{10,11, +128},{11,11,306},{12,11,373},{14,11,30},{17,11,79},{147,11,80},{135,11,1235},{ +134,0,1392},{4,11,230},{133,11,702},{147,0,126},{7,10,131},{7,10,422},{8,10,210} +,{140,10,573},{134,0,1179},{139,11,435},{139,10,797},{134,11,1728},{4,0,162},{18 +,11,26},{19,11,42},{20,11,43},{21,11,0},{23,11,27},{152,11,14},{132,10,936},{5, +10,453},{6,0,765},{134,10,441},{133,0,187},{135,0,1286},{6,0,635},{6,0,904},{6,0 +,1210},{134,0,1489},{4,0,215},{8,0,890},{9,0,38},{10,0,923},{11,0,23},{11,0,127} +,{139,0,796},{6,0,1165},{134,0,1306},{7,0,716},{13,0,97},{141,0,251},{132,10,653 +},{136,0,657},{146,10,80},{5,11,622},{7,11,1032},{11,11,26},{11,11,213},{11,11, +707},{12,11,380},{13,11,226},{141,11,355},{5,11,70},{6,0,299},{6,11,334},{9,11, +171},{11,11,637},{12,11,202},{14,11,222},{145,11,42},{142,0,134},{4,11,23},{5,11 +,313},{5,11,1014},{6,11,50},{6,11,51},{7,11,142},{7,11,384},{9,11,783},{139,11, +741},{4,11,141},{7,11,559},{8,11,640},{9,11,460},{12,11,183},{141,11,488},{136, +11,614},{7,10,1368},{8,10,232},{8,10,361},{10,10,682},{138,10,742},{137,10,534}, +{6,0,1082},{140,0,658},{137,10,27},{135,0,2002},{142,10,12},{4,0,28},{5,0,440},{ +7,0,248},{11,0,833},{140,0,344},{7,10,736},{139,10,264},{134,10,1657},{134,0, +1654},{138,0,531},{5,11,222},{9,11,140},{138,11,534},{6,0,634},{6,0,798},{134,0, +840},{138,11,503},{135,10,127},{133,0,853},{5,11,154},{7,11,1491},{10,11,379},{ +138,11,485},{6,0,249},{7,0,1234},{139,0,573},{133,11,716},{7,11,1570},{140,11, +542},{136,10,364},{138,0,527},{4,11,91},{5,11,388},{5,11,845},{6,11,206},{6,11, +252},{6,11,365},{7,11,136},{7,11,531},{8,11,264},{136,11,621},{134,0,1419},{135, +11,1441},{7,0,49},{7,0,392},{8,0,20},{8,0,172},{8,0,690},{9,0,383},{9,0,845},{10 +,0,48},{11,0,293},{11,0,832},{11,0,920},{11,0,984},{141,0,221},{5,0,858},{133,0, +992},{5,0,728},{137,10,792},{5,10,909},{9,10,849},{138,10,805},{7,0,525},{7,0, +1579},{8,0,497},{136,0,573},{6,0,268},{137,0,62},{135,11,576},{134,0,1201},{5,11 +,771},{5,11,863},{5,11,898},{6,11,1632},{6,11,1644},{134,11,1780},{133,11,331},{ +7,0,193},{7,0,1105},{7,10,397},{8,10,124},{8,10,619},{9,10,305},{10,0,495},{11, +10,40},{12,10,349},{13,10,134},{13,10,295},{14,10,155},{15,10,120},{146,10,105}, +{138,0,106},{5,11,107},{6,0,859},{7,11,201},{136,11,518},{6,11,446},{135,11,1817 +},{4,10,262},{7,10,342},{141,0,23},{133,10,641},{137,11,851},{6,0,925},{137,0, +813},{132,11,504},{6,0,613},{136,0,223},{4,10,99},{6,10,250},{6,10,346},{8,10, +127},{138,10,81},{136,0,953},{132,10,915},{139,11,892},{5,10,75},{9,10,517},{10, +10,470},{12,10,155},{141,10,224},{4,0,666},{7,0,1017},{7,11,996},{138,11,390},{5 +,11,883},{133,11,975},{14,10,83},{142,11,83},{4,0,670},{5,11,922},{134,11,1707}, +{135,0,216},{7,11,787},{9,0,40},{139,0,136},{5,10,954},{5,11,993},{7,11,515},{ +137,11,91},{139,0,259},{6,10,304},{7,0,1114},{8,10,418},{9,0,310},{9,0,682},{10, +0,440},{11,10,341},{11,10,675},{141,0,40},{9,10,410},{11,10,425},{142,0,296},{10 +,11,377},{12,11,363},{13,11,68},{13,11,94},{14,11,108},{142,11,306},{7,0,1401},{ +135,0,1476},{4,0,296},{6,0,475},{7,0,401},{7,0,1410},{7,0,1594},{7,0,1674},{8,0, +63},{8,0,660},{137,0,74},{4,0,139},{4,0,388},{140,0,188},{132,0,797},{132,11,766 +},{5,11,103},{7,11,921},{8,11,580},{8,11,593},{8,11,630},{138,11,28},{4,11,911}, +{5,11,867},{133,11,1013},{134,10,14},{134,0,1572},{134,10,1708},{5,10,113},{6,10 +,243},{7,10,1865},{11,10,161},{16,10,37},{17,10,99},{149,0,39},{7,11,1563},{141, +11,182},{5,11,135},{6,11,519},{7,11,1722},{10,11,271},{11,11,261},{145,11,54},{ +132,10,274},{134,0,1594},{4,11,300},{5,11,436},{135,11,484},{4,0,747},{6,0,290}, +{7,0,649},{7,0,1479},{135,0,1583},{133,11,535},{147,11,82},{133,0,232},{137,0, +887},{135,10,166},{136,0,521},{4,0,14},{7,0,472},{7,0,1801},{10,0,748},{141,0, +458},{134,0,741},{134,0,992},{9,10,304},{144,0,111},{4,0,425},{5,11,387},{7,11, +557},{12,11,547},{142,11,86},{135,11,1747},{5,10,654},{135,11,1489},{4,11,6},{5, +11,708},{7,0,789},{136,11,75},{6,10,273},{10,10,188},{13,10,377},{146,10,77},{4, +11,303},{6,0,1593},{7,11,619},{10,11,547},{10,11,687},{11,11,122},{140,11,601},{ +134,0,1768},{135,10,410},{138,11,772},{11,0,233},{139,10,524},{5,0,943},{134,0, +1779},{134,10,1785},{136,11,529},{132,0,955},{5,0,245},{6,0,576},{7,0,582},{136, +0,225},{132,10,780},{142,0,241},{134,0,1943},{4,11,106},{7,11,310},{7,11,1785},{ +10,11,690},{139,11,717},{134,0,1284},{5,11,890},{133,11,988},{6,11,626},{142,11, +431},{10,11,706},{145,11,32},{137,11,332},{132,11,698},{135,0,709},{5,10,948},{ +138,11,17},{136,0,554},{134,0,1564},{139,10,941},{132,0,443},{134,0,909},{134,11 +,84},{142,0,280},{4,10,532},{5,10,706},{135,10,662},{132,0,729},{5,10,837},{6,10 +,1651},{139,10,985},{135,10,1861},{4,0,348},{152,11,3},{5,11,986},{6,11,130},{7, +11,1582},{8,11,458},{10,11,101},{10,11,318},{138,11,823},{134,0,758},{4,0,298},{ +137,0,848},{4,10,330},{7,10,933},{7,10,2012},{136,10,292},{7,11,1644},{137,11, +129},{6,0,1422},{7,10,767},{137,0,829},{5,0,164},{7,0,121},{142,0,189},{7,0,812} +,{7,0,1261},{7,0,1360},{9,0,632},{140,0,352},{135,11,1788},{139,0,556},{135,11, +997},{145,10,114},{4,0,172},{9,0,611},{9,10,883},{10,0,436},{12,0,673},{141,0, +255},{10,10,274},{139,0,530},{133,0,844},{134,0,984},{4,10,703},{7,10,207},{13,0 +,232},{146,0,35},{132,10,571},{9,0,263},{10,0,147},{138,0,492},{7,11,1756},{137, +11,98},{5,10,873},{5,10,960},{8,10,823},{137,10,881},{133,0,537},{132,0,859},{7, +11,1046},{139,11,160},{137,0,842},{139,10,283},{5,10,33},{6,10,470},{139,10,424} +,{6,11,45},{7,11,433},{8,11,129},{9,11,21},{10,11,392},{11,11,79},{12,11,499},{ +13,11,199},{141,11,451},{135,0,1291},{135,10,1882},{7,11,558},{136,11,353},{134, +0,1482},{5,0,230},{5,0,392},{6,0,420},{9,0,568},{140,0,612},{6,0,262},{7,10,90}, +{7,10,664},{7,10,830},{7,10,1380},{7,10,2025},{8,10,448},{8,10,828},{8,11,81},{9 +,11,189},{9,11,201},{11,11,478},{11,11,712},{141,11,338},{142,0,31},{5,11,353},{ +151,11,26},{132,0,753},{4,0,0},{5,0,41},{7,0,1459},{7,0,1469},{7,0,1859},{9,0, +549},{139,0,905},{9,10,417},{137,10,493},{135,11,1113},{133,0,696},{141,11,448}, +{134,10,295},{132,0,834},{4,0,771},{5,10,1019},{6,11,25},{7,11,855},{7,11,1258}, +{144,11,32},{134,0,1076},{133,0,921},{133,0,674},{4,11,4},{7,11,1118},{7,11,1320 +},{7,11,1706},{8,11,277},{9,11,622},{10,11,9},{11,11,724},{12,11,350},{12,11,397 +},{13,11,28},{13,11,159},{15,11,89},{18,11,5},{19,11,9},{20,11,34},{150,11,47},{ +134,10,208},{6,0,444},{136,0,308},{6,0,180},{7,0,1137},{8,0,751},{139,0,805},{4, +0,183},{7,0,271},{11,0,824},{11,0,952},{13,0,278},{13,0,339},{13,0,482},{14,0, +424},{148,0,99},{7,11,317},{135,11,569},{4,0,19},{5,0,477},{5,0,596},{6,0,505},{ +7,0,1221},{11,0,907},{12,0,209},{141,0,214},{135,0,1215},{6,0,271},{7,0,398},{7, +10,448},{7,10,1629},{7,10,1813},{8,0,387},{8,10,442},{9,10,710},{10,0,344},{10, +10,282},{138,10,722},{11,10,844},{12,10,104},{140,10,625},{134,11,255},{133,10, +787},{134,0,1645},{11,11,956},{151,11,3},{6,0,92},{6,0,188},{7,0,209},{7,0,1269} +,{7,0,1524},{7,0,1876},{8,0,661},{10,0,42},{10,0,228},{11,0,58},{11,0,1020},{12, +0,58},{12,0,118},{141,0,32},{4,0,459},{133,0,966},{4,11,536},{7,11,1141},{10,11, +723},{139,11,371},{140,0,330},{134,0,1557},{7,11,285},{135,11,876},{136,10,491}, +{135,11,560},{6,0,18},{7,0,179},{7,0,932},{8,0,548},{8,0,757},{9,0,54},{9,0,65}, +{9,0,532},{9,0,844},{10,0,113},{10,0,117},{10,0,315},{10,0,560},{10,0,622},{10,0 +,798},{11,0,153},{11,0,351},{11,0,375},{12,0,78},{12,0,151},{12,0,392},{12,0,666 +},{14,0,248},{143,0,23},{4,11,690},{134,0,1742},{4,10,403},{5,10,441},{7,10,450} +,{10,10,840},{11,10,101},{12,10,193},{141,10,430},{133,0,965},{134,0,182},{10,0, +65},{10,0,488},{138,0,497},{135,11,1346},{6,0,973},{6,0,1158},{10,11,200},{19,11 +,2},{151,11,22},{4,11,190},{133,11,554},{133,10,679},{7,0,328},{137,10,326},{133 +,11,1001},{9,0,588},{138,0,260},{133,11,446},{135,10,1128},{135,10,1796},{147,11 +,119},{134,0,1786},{6,0,1328},{6,0,1985},{8,0,962},{138,0,1017},{135,0,308},{4, +10,574},{7,10,350},{7,10,1024},{8,10,338},{9,10,677},{10,10,808},{139,0,508},{ +138,11,752},{135,10,1081},{137,11,96},{7,10,1676},{135,10,2037},{136,0,588},{132 +,11,304},{133,0,614},{140,0,793},{136,0,287},{137,10,297},{141,10,37},{6,11,53}, +{6,11,199},{7,11,1408},{8,11,32},{8,11,93},{9,11,437},{10,11,397},{10,11,629},{ +11,11,593},{11,11,763},{13,11,326},{145,11,35},{134,11,105},{9,11,320},{10,11, +506},{138,11,794},{5,11,114},{5,11,255},{141,11,285},{140,0,290},{7,11,2035},{8, +11,19},{9,11,89},{138,11,831},{134,0,1136},{6,10,306},{7,0,719},{7,10,1140},{7, +10,1340},{8,0,796},{8,0,809},{8,0,834},{8,10,133},{138,10,449},{139,10,1011},{5, +0,210},{6,0,213},{7,0,60},{10,0,364},{139,0,135},{5,0,607},{8,0,326},{136,0,490} +,{138,11,176},{132,0,701},{5,0,472},{7,0,380},{137,0,758},{135,0,1947},{6,0,1079 +},{138,0,278},{138,11,391},{5,10,329},{8,10,260},{139,11,156},{4,0,386},{7,0,41} +,{8,0,405},{8,0,728},{9,0,497},{11,0,110},{11,0,360},{15,0,37},{144,0,84},{5,0, +46},{7,0,1452},{7,0,1480},{8,0,634},{140,0,472},{136,0,961},{4,0,524},{136,0,810 +},{10,0,238},{141,0,33},{132,10,657},{152,10,7},{133,0,532},{5,0,997},{135,10, +1665},{7,11,594},{7,11,851},{7,11,1858},{9,11,411},{9,11,574},{9,11,666},{9,11, +737},{10,11,346},{10,11,712},{11,11,246},{11,11,432},{11,11,517},{11,11,647},{11 +,11,679},{11,11,727},{12,11,304},{12,11,305},{12,11,323},{12,11,483},{12,11,572} +,{12,11,593},{12,11,602},{13,11,95},{13,11,101},{13,11,171},{13,11,315},{13,11, +378},{13,11,425},{13,11,475},{14,11,63},{14,11,380},{14,11,384},{15,11,133},{18, +11,112},{148,11,72},{5,11,955},{136,11,814},{134,0,1301},{5,10,66},{7,10,1896},{ +136,10,288},{133,11,56},{134,10,1643},{6,0,1298},{148,11,100},{5,0,782},{5,0,829 +},{6,0,671},{6,0,1156},{6,0,1738},{137,11,621},{4,0,306},{5,0,570},{5,10,91},{5, +10,648},{5,10,750},{5,10,781},{6,10,54},{6,10,112},{6,10,402},{6,10,1732},{7,0, +1347},{7,10,315},{7,10,749},{7,10,1900},{9,10,78},{9,10,508},{10,10,611},{10,10, +811},{11,10,510},{11,10,728},{13,10,36},{14,10,39},{16,10,83},{17,10,124},{148, +10,30},{8,10,570},{9,11,477},{141,11,78},{4,11,639},{10,10,322},{10,10,719},{10, +11,4},{11,10,407},{11,11,638},{12,11,177},{148,11,57},{7,0,1823},{139,0,693},{5, +11,758},{7,0,759},{8,10,125},{8,10,369},{8,10,524},{10,10,486},{11,10,13},{11,10 +,381},{11,10,736},{11,10,766},{11,10,845},{13,10,114},{13,10,292},{142,10,47},{6 +,10,1684},{6,10,1731},{7,0,1932},{7,10,356},{8,10,54},{8,10,221},{9,10,225},{9, +10,356},{10,10,77},{10,10,446},{10,10,731},{12,10,404},{141,10,491},{135,11,552} +,{135,11,1112},{4,0,78},{5,0,96},{5,0,182},{6,0,1257},{7,0,1724},{7,0,1825},{10, +0,394},{10,0,471},{11,0,532},{14,0,340},{145,0,88},{139,11,328},{135,0,1964},{ +132,10,411},{4,10,80},{5,10,44},{137,11,133},{5,11,110},{6,11,169},{6,11,1702},{ +7,11,400},{8,11,538},{9,11,184},{9,11,524},{140,11,218},{4,0,521},{5,10,299},{7, +10,1083},{140,11,554},{6,11,133},{9,11,353},{12,11,628},{146,11,79},{6,0,215},{7 +,0,584},{7,0,1028},{7,0,1473},{7,0,1721},{9,0,424},{138,0,779},{7,0,857},{7,0, +1209},{7,10,1713},{9,10,537},{10,10,165},{12,10,219},{140,10,561},{4,10,219},{6, +11,93},{7,10,1761},{7,11,1422},{7,11,1851},{8,11,673},{9,10,86},{9,11,529},{140, +11,43},{137,11,371},{136,0,671},{5,0,328},{135,0,918},{132,0,529},{9,11,25},{10, +11,467},{138,11,559},{4,11,335},{135,11,942},{134,0,716},{134,0,1509},{6,0,67},{ +7,0,258},{7,0,1630},{9,0,354},{9,0,675},{10,0,830},{12,10,428},{14,0,80},{145,0, +80},{134,0,1112},{6,0,141},{7,0,225},{9,0,59},{9,0,607},{10,0,312},{11,0,687},{ +12,0,555},{13,0,373},{13,0,494},{148,0,58},{133,10,514},{8,11,39},{10,11,773},{ +11,11,84},{12,11,205},{142,11,1},{5,11,601},{5,11,870},{136,0,783},{136,11,594}, +{4,10,55},{5,10,301},{6,10,571},{14,10,49},{146,10,102},{132,11,181},{134,11, +1652},{133,10,364},{4,11,97},{5,11,147},{6,11,286},{7,11,1362},{141,11,176},{4, +10,76},{7,10,1550},{9,10,306},{9,10,430},{9,10,663},{10,10,683},{11,10,427},{11, +10,753},{12,10,334},{12,10,442},{14,10,258},{14,10,366},{143,10,131},{137,10,52} +,{6,0,955},{134,0,1498},{6,11,375},{7,11,169},{7,11,254},{136,11,780},{7,0,430}, +{11,0,46},{14,0,343},{142,11,343},{135,0,1183},{5,0,602},{7,0,2018},{7,11,1447}, +{9,0,418},{137,0,803},{7,11,1044},{136,0,677},{139,11,285},{4,10,656},{135,10, +779},{135,10,144},{5,11,629},{135,11,1549},{135,10,1373},{138,11,209},{7,10,554} +,{7,10,605},{141,10,10},{5,10,838},{5,10,841},{134,10,1649},{133,10,1012},{6,0, +1357},{134,0,1380},{144,0,53},{6,0,590},{7,10,365},{7,10,1357},{7,10,1497},{8,10 +,154},{141,10,281},{133,10,340},{132,11,420},{135,0,329},{147,11,32},{4,0,469},{ +10,11,429},{139,10,495},{8,10,261},{9,10,144},{9,10,466},{10,10,370},{12,10,470} +,{13,10,144},{142,10,348},{142,0,460},{4,11,325},{9,10,897},{138,11,125},{6,0, +1743},{6,10,248},{9,10,546},{10,10,535},{11,10,681},{141,10,135},{4,0,990},{5,0, +929},{6,0,340},{8,0,376},{8,0,807},{8,0,963},{8,0,980},{138,0,1007},{134,0,1603} +,{140,0,250},{4,11,714},{133,11,469},{134,10,567},{136,10,445},{5,0,218},{7,0, +1610},{8,0,646},{10,0,83},{11,11,138},{140,11,40},{7,0,1512},{135,0,1794},{135, +11,1216},{4,11,718},{11,0,0},{144,0,78},{133,0,571},{132,0,455},{134,0,1012},{5, +11,124},{5,11,144},{6,11,548},{7,11,15},{7,11,153},{137,11,629},{142,11,10},{6, +11,75},{7,11,1531},{8,11,416},{9,11,240},{9,11,275},{10,11,100},{11,11,658},{11, +11,979},{12,11,86},{13,11,468},{14,11,66},{14,11,207},{15,11,20},{15,11,25},{144 +,11,58},{132,10,577},{5,11,141},{5,11,915},{6,11,1783},{7,11,211},{7,11,698},{7, +11,1353},{9,11,83},{9,11,281},{10,11,376},{10,11,431},{11,11,543},{12,11,664},{ +13,11,280},{13,11,428},{14,11,61},{14,11,128},{17,11,52},{145,11,81},{6,0,161},{ +7,0,372},{137,0,597},{132,0,349},{10,11,702},{139,11,245},{134,0,524},{134,10, +174},{6,0,432},{9,0,751},{139,0,322},{147,11,94},{4,11,338},{133,11,400},{5,0, +468},{10,0,325},{11,0,856},{12,0,345},{143,0,104},{133,0,223},{132,0,566},{4,11, +221},{5,11,659},{5,11,989},{7,11,697},{7,11,1211},{138,11,284},{135,11,1070},{4, +0,59},{135,0,1394},{5,10,878},{5,10,972},{6,0,436},{139,0,481},{4,0,48},{5,0,271 +},{135,0,953},{5,0,610},{136,0,457},{4,0,773},{5,0,618},{137,0,756},{133,0,755}, +{135,0,1217},{138,11,507},{132,10,351},{132,0,197},{143,11,78},{4,11,188},{7,11, +805},{11,11,276},{142,11,293},{5,11,884},{139,11,991},{132,10,286},{7,10,438},{7 +,10,627},{7,10,1516},{8,10,40},{9,10,56},{9,10,294},{10,0,259},{10,0,428},{11,10 +,969},{11,10,995},{146,10,148},{4,0,356},{5,0,217},{5,0,492},{5,0,656},{8,0,544} +,{136,11,544},{5,0,259},{6,0,1230},{7,0,414},{7,0,854},{142,0,107},{132,0,1007}, +{15,0,14},{144,0,5},{4,10,738},{134,0,1580},{132,11,596},{132,0,673},{133,10,866 +},{6,0,1843},{135,11,1847},{4,0,165},{7,0,1398},{135,0,1829},{135,11,1634},{147, +11,65},{6,0,885},{6,0,1009},{137,0,809},{133,10,116},{132,10,457},{136,11,770},{ +9,0,498},{10,11,361},{12,0,181},{142,11,316},{134,11,595},{5,0,9},{7,0,297},{7,0 +,966},{140,0,306},{4,11,89},{5,11,489},{6,11,315},{7,11,553},{7,11,1745},{138,11 +,243},{134,0,1487},{132,0,437},{5,0,146},{6,0,411},{138,0,721},{5,10,527},{6,10, +189},{135,10,859},{11,10,104},{11,10,554},{15,10,60},{143,10,125},{6,11,1658},{9 +,11,3},{10,11,154},{11,11,641},{13,11,85},{13,11,201},{141,11,346},{6,0,177},{ +135,0,467},{134,0,1377},{134,10,116},{136,11,645},{4,11,166},{5,11,505},{6,11, +1670},{137,11,110},{133,10,487},{4,10,86},{5,10,667},{5,10,753},{6,10,316},{6,10 +,455},{135,10,946},{133,0,200},{132,0,959},{6,0,1928},{134,0,1957},{139,11,203}, +{150,10,45},{4,10,79},{7,10,1773},{10,10,450},{11,10,589},{13,10,332},{13,10,493 +},{14,10,183},{14,10,334},{14,10,362},{14,10,368},{14,10,376},{14,10,379},{19,10 +,90},{19,10,103},{19,10,127},{148,10,90},{6,0,1435},{135,11,1275},{134,0,481},{7 +,11,445},{8,11,307},{8,11,704},{10,11,41},{10,11,439},{11,11,237},{11,11,622},{ +140,11,201},{135,11,869},{4,0,84},{7,0,1482},{10,0,76},{138,0,142},{11,11,277},{ +144,11,14},{135,11,1977},{4,11,189},{5,11,713},{136,11,57},{133,0,1015},{138,11, +371},{4,0,315},{5,0,507},{135,0,1370},{4,11,552},{142,10,381},{9,0,759},{16,0,31 +},{16,0,39},{16,0,75},{18,0,24},{20,0,42},{152,0,1},{134,0,712},{134,0,1722},{ +133,10,663},{133,10,846},{8,0,222},{8,0,476},{9,0,238},{11,0,516},{11,0,575},{15 +,0,109},{146,0,100},{5,10,378},{7,0,1402},{7,0,1414},{8,10,465},{9,10,286},{10, +10,185},{10,10,562},{10,10,635},{11,10,31},{11,10,393},{12,0,456},{13,10,312},{ +18,10,65},{18,10,96},{147,10,89},{4,0,986},{6,0,1958},{6,0,2032},{8,0,934},{138, +0,985},{7,10,1880},{9,10,680},{139,10,798},{134,10,1770},{145,11,49},{132,11,614 +},{132,10,648},{5,10,945},{6,10,1656},{6,10,1787},{7,10,167},{8,10,824},{9,10, +391},{10,10,375},{139,10,185},{138,11,661},{7,0,1273},{135,11,1945},{7,0,706},{7 +,0,1058},{138,0,538},{7,10,1645},{8,10,352},{137,10,249},{132,10,152},{11,0,92}, +{11,0,196},{11,0,409},{11,0,450},{11,0,666},{11,0,777},{12,0,262},{13,0,385},{13 +,0,393},{15,0,115},{16,0,45},{145,0,82},{133,10,1006},{6,0,40},{135,0,1781},{9, +11,614},{139,11,327},{5,10,420},{135,10,1449},{135,0,431},{7,10,832},{138,0,97}, +{6,0,423},{7,0,665},{135,0,1210},{7,0,237},{8,0,664},{9,0,42},{9,0,266},{9,0,380 +},{9,0,645},{10,0,177},{138,0,276},{5,10,351},{135,0,264},{5,10,40},{7,10,598},{ +7,10,1638},{8,0,213},{9,10,166},{9,10,640},{9,10,685},{9,10,773},{11,10,215},{13 +,10,65},{14,10,172},{14,10,317},{145,10,6},{5,11,84},{134,11,163},{8,10,60},{9, +10,343},{139,10,769},{137,0,455},{133,11,410},{8,0,906},{12,0,700},{12,0,706},{ +140,0,729},{21,11,33},{150,11,40},{7,10,1951},{8,10,765},{8,10,772},{140,10,671} +,{7,10,108},{8,10,219},{8,10,388},{9,10,639},{9,10,775},{11,10,275},{140,10,464} +,{5,11,322},{7,11,1941},{8,11,186},{9,11,262},{10,11,187},{14,11,208},{146,11, +130},{139,0,624},{5,11,227},{8,0,574},{140,11,29},{7,11,1546},{11,11,299},{142, +11,407},{5,10,15},{6,10,56},{7,10,1758},{8,10,500},{9,10,730},{11,10,331},{13,10 +,150},{142,10,282},{7,11,1395},{8,11,486},{9,11,236},{9,11,878},{10,11,218},{11, +11,95},{19,11,17},{147,11,31},{135,11,2043},{4,0,354},{146,11,4},{140,11,80},{ +135,0,1558},{134,10,1886},{5,10,205},{6,10,438},{137,10,711},{133,11,522},{133, +10,534},{7,0,235},{7,0,1475},{15,0,68},{146,0,120},{137,10,691},{4,0,942},{6,0, +1813},{8,0,917},{10,0,884},{12,0,696},{12,0,717},{12,0,723},{12,0,738},{12,0,749 +},{12,0,780},{16,0,97},{146,0,169},{6,10,443},{8,11,562},{9,10,237},{9,10,571},{ +9,10,695},{10,10,139},{11,10,715},{12,10,417},{141,10,421},{135,0,957},{133,0, +830},{134,11,1771},{146,0,23},{5,0,496},{6,0,694},{7,0,203},{7,11,1190},{137,11, +620},{137,11,132},{6,0,547},{134,0,1549},{8,11,258},{9,11,208},{137,11,359},{4,0 +,864},{5,0,88},{137,0,239},{135,11,493},{4,11,317},{135,11,1279},{132,11,477},{4 +,10,578},{5,11,63},{133,11,509},{7,0,650},{135,0,1310},{7,0,1076},{9,0,80},{11,0 +,78},{11,0,421},{11,0,534},{140,0,545},{132,11,288},{5,10,923},{12,0,553},{142,0 +,118},{7,0,274},{11,0,479},{139,0,507},{8,11,89},{8,11,620},{9,11,49},{10,11,774 +},{11,11,628},{12,11,322},{143,11,124},{4,0,497},{135,0,1584},{4,10,924},{7,0, +261},{7,0,1115},{7,0,1354},{7,0,1404},{7,0,1588},{7,0,1705},{7,0,1902},{9,0,465} +,{10,0,248},{10,0,349},{10,0,647},{11,0,527},{11,0,660},{11,0,669},{12,0,529},{ +141,0,305},{133,10,665},{136,0,13},{6,0,791},{138,11,120},{7,0,642},{8,0,250},{ +11,0,123},{11,0,137},{13,0,48},{142,0,95},{4,10,265},{7,10,807},{135,10,950},{5, +10,93},{140,10,267},{135,0,1429},{4,0,949},{10,0,885},{10,0,891},{10,0,900},{10, +0,939},{12,0,760},{142,0,449},{139,11,366},{132,0,818},{134,11,85},{135,10,994}, +{5,10,233},{5,10,320},{6,10,140},{7,0,330},{136,10,295},{4,0,1004},{8,0,982},{ +136,0,993},{133,10,978},{4,10,905},{6,10,1701},{137,10,843},{10,0,545},{140,0, +301},{6,0,947},{134,0,1062},{134,0,1188},{4,0,904},{5,0,794},{152,10,6},{134,0, +1372},{135,11,608},{5,11,279},{6,11,235},{7,11,468},{8,11,446},{9,11,637},{10,11 +,717},{11,11,738},{140,11,514},{132,10,509},{5,11,17},{6,11,371},{137,11,528},{ +132,0,693},{4,11,115},{5,11,669},{6,11,407},{8,11,311},{11,11,10},{141,11,5},{7, +10,273},{9,11,381},{139,0,377},{135,0,695},{7,0,386},{138,0,713},{135,10,1041},{ +134,0,1291},{6,0,7},{6,0,35},{7,0,147},{7,0,1069},{7,0,1568},{7,0,1575},{7,0, +1917},{8,0,43},{8,0,208},{9,0,128},{9,0,866},{10,0,20},{11,0,981},{147,0,33},{7, +0,893},{141,0,424},{139,10,234},{150,11,56},{5,11,779},{5,11,807},{6,11,1655},{ +134,11,1676},{5,10,802},{7,10,2021},{136,10,805},{4,11,196},{5,10,167},{5,10,899 +},{5,11,558},{5,11,949},{6,10,410},{137,10,777},{137,10,789},{134,10,1705},{8,0, +904},{140,0,787},{6,0,322},{9,0,552},{11,0,274},{13,0,209},{13,0,499},{14,0,85}, +{15,0,126},{145,0,70},{135,10,10},{5,10,11},{6,10,117},{6,10,485},{7,10,1133},{9 +,10,582},{9,10,594},{11,10,21},{11,10,818},{12,10,535},{141,10,86},{4,10,264},{7 +,10,1067},{8,10,204},{8,10,385},{139,10,953},{132,11,752},{138,10,56},{133,10, +470},{6,0,1808},{8,0,83},{8,0,742},{8,0,817},{9,0,28},{9,0,29},{9,0,885},{10,0, +387},{11,0,633},{11,0,740},{13,0,235},{13,0,254},{15,0,143},{143,0,146},{140,0, +49},{134,0,1832},{4,11,227},{5,11,159},{5,11,409},{7,11,80},{10,11,294},{10,11, +479},{12,11,418},{14,11,50},{14,11,249},{142,11,295},{7,11,1470},{8,11,66},{8,11 +,137},{8,11,761},{9,11,638},{11,11,80},{11,11,212},{11,11,368},{11,11,418},{12, +11,8},{13,11,15},{16,11,61},{17,11,59},{19,11,28},{148,11,84},{139,10,1015},{138 +,11,468},{135,0,421},{6,0,415},{7,0,1049},{137,0,442},{6,11,38},{7,11,1220},{8, +11,185},{8,11,256},{9,11,22},{9,11,331},{10,11,738},{11,11,205},{11,11,540},{11, +11,746},{13,11,399},{13,11,465},{14,11,88},{142,11,194},{139,0,289},{133,10,715} +,{4,0,110},{10,0,415},{10,0,597},{142,0,206},{4,11,159},{6,11,115},{7,11,252},{7 +,11,257},{7,11,1928},{8,11,69},{9,11,384},{10,11,91},{10,11,615},{12,11,375},{14 +,11,235},{18,11,117},{147,11,123},{5,11,911},{136,11,278},{7,0,205},{7,0,2000},{ +8,10,794},{9,10,400},{10,10,298},{142,10,228},{135,11,1774},{4,11,151},{7,11, +1567},{8,11,351},{137,11,322},{136,10,724},{133,11,990},{7,0,1539},{7,11,1539},{ +11,0,512},{13,0,205},{19,0,30},{22,0,36},{151,0,19},{5,11,194},{7,11,1662},{9,11 +,90},{140,11,180},{6,10,190},{7,10,768},{135,10,1170},{134,0,1340},{4,0,283},{ +135,0,1194},{133,11,425},{133,11,971},{12,0,549},{14,10,67},{147,10,60},{135,10, +1023},{134,0,1720},{138,11,587},{5,11,72},{6,11,264},{7,11,21},{7,11,46},{7,11, +2013},{8,11,215},{8,11,513},{10,11,266},{139,11,22},{5,0,319},{135,0,534},{6,10, +137},{9,10,75},{9,10,253},{10,10,194},{138,10,444},{6,11,239},{7,0,1180},{7,11, +118},{10,11,95},{11,11,603},{13,11,443},{14,11,160},{15,11,4},{148,0,112},{134, +11,431},{5,11,874},{6,11,1677},{11,10,643},{12,10,115},{143,11,0},{134,0,967},{6 +,11,65},{7,11,939},{7,11,1172},{7,11,1671},{9,11,540},{10,11,696},{11,11,265},{ +11,11,732},{11,11,928},{11,11,937},{12,11,399},{13,11,438},{149,11,19},{137,11, +200},{135,0,1940},{5,10,760},{7,10,542},{8,10,135},{136,10,496},{140,11,44},{7, +11,1655},{136,11,305},{7,10,319},{7,10,355},{7,10,763},{10,10,389},{145,10,43},{ +136,0,735},{138,10,786},{137,11,19},{132,11,696},{5,0,132},{9,0,486},{9,0,715},{ +10,0,458},{11,0,373},{11,0,668},{11,0,795},{11,0,897},{12,0,272},{12,0,424},{12, +0,539},{12,0,558},{14,0,245},{14,0,263},{14,0,264},{14,0,393},{142,0,403},{10,0, +38},{139,0,784},{132,0,838},{4,11,302},{135,11,1766},{133,0,379},{4,11,726},{5,0 +,8},{5,11,630},{6,0,89},{6,0,400},{7,0,1569},{7,0,1623},{7,0,1850},{8,0,218},{8, +0,422},{9,0,570},{138,0,626},{4,0,1017},{138,0,660},{6,0,387},{7,0,882},{141,0, +111},{6,0,224},{7,0,877},{137,0,647},{4,10,58},{5,10,286},{6,10,319},{7,10,402}, +{7,10,1254},{7,10,1903},{8,10,356},{140,10,408},{135,0,790},{4,10,389},{9,0,510} +,{9,10,181},{10,0,53},{10,10,29},{10,10,816},{11,10,311},{11,10,561},{12,10,67}, +{141,10,181},{142,0,458},{6,11,118},{7,11,215},{7,11,1521},{140,11,11},{134,0, +954},{135,0,394},{134,0,1367},{5,10,373},{133,11,225},{132,0,882},{7,0,1409},{ +135,10,1972},{135,10,1793},{4,11,370},{5,11,756},{135,11,1326},{150,11,13},{7,11 +,354},{10,11,410},{139,11,815},{6,11,1662},{7,11,48},{8,11,771},{10,11,116},{13, +11,104},{14,11,105},{14,11,184},{15,11,168},{19,11,92},{148,11,68},{7,0,124},{ +136,0,38},{5,0,261},{7,0,78},{7,0,199},{8,0,815},{9,0,126},{10,0,342},{140,0,647 +},{4,0,628},{140,0,724},{7,0,266},{7,10,1651},{8,0,804},{145,10,89},{135,0,208}, +{134,0,1178},{6,0,79},{135,0,1519},{132,10,672},{133,10,737},{136,0,741},{132,11 +,120},{4,0,710},{6,0,376},{134,0,606},{134,0,1347},{134,0,1494},{6,0,850},{6,0, +1553},{137,0,821},{5,10,145},{134,11,593},{7,0,1311},{140,0,135},{4,0,467},{5,0, +405},{134,0,544},{5,11,820},{135,11,931},{6,0,100},{7,0,244},{7,0,632},{7,0,1609 +},{8,0,178},{8,0,638},{141,0,58},{4,10,387},{135,10,1288},{6,11,151},{6,11,1675} +,{7,11,383},{151,11,10},{132,0,481},{135,10,550},{134,0,1378},{6,11,1624},{11,11 +,11},{12,11,422},{13,11,262},{142,11,360},{133,0,791},{4,11,43},{5,11,344},{133, +11,357},{7,0,1227},{140,0,978},{7,0,686},{8,0,33},{8,0,238},{10,0,616},{11,0,467 +},{11,0,881},{13,0,217},{13,0,253},{142,0,268},{137,0,857},{7,11,148},{8,0,467}, +{8,0,1006},{8,11,284},{141,11,63},{4,10,576},{135,10,1263},{133,11,888},{5,10, +919},{134,10,1673},{20,10,37},{148,11,37},{132,0,447},{132,11,711},{4,0,128},{5, +0,415},{6,0,462},{7,0,294},{7,0,578},{10,0,710},{139,0,86},{4,10,82},{5,10,333}, +{5,10,904},{6,10,207},{7,10,325},{7,10,1726},{8,10,101},{10,10,778},{139,10,220} +,{136,0,587},{137,11,440},{133,10,903},{6,0,427},{7,0,1018},{138,0,692},{4,0,195 +},{135,0,802},{140,10,147},{134,0,1546},{134,0,684},{132,10,705},{136,0,345},{11 +,11,678},{140,11,307},{133,0,365},{134,0,1683},{4,11,65},{5,11,479},{5,11,1004}, +{7,11,1913},{8,11,317},{9,11,302},{10,11,612},{141,11,22},{138,0,472},{4,11,261} +,{135,11,510},{134,10,90},{142,0,433},{151,0,28},{4,11,291},{7,11,101},{9,11,515 +},{12,11,152},{12,11,443},{13,11,392},{142,11,357},{140,0,997},{5,0,3},{8,0,578} +,{9,0,118},{10,0,705},{141,0,279},{135,11,1266},{7,10,813},{12,10,497},{141,10, +56},{133,0,229},{6,10,125},{135,10,1277},{8,0,102},{10,0,578},{10,0,672},{12,0, +496},{13,0,408},{14,0,121},{17,0,106},{151,10,12},{6,0,866},{134,0,1080},{136,0, +1022},{4,11,130},{135,11,843},{5,11,42},{5,11,879},{7,11,245},{7,11,324},{7,11, +1532},{11,11,463},{11,11,472},{13,11,363},{144,11,52},{150,0,55},{4,11,134},{5, +11,372},{8,0,115},{8,0,350},{9,0,489},{10,0,128},{11,0,306},{12,0,373},{14,0,30} +,{17,0,79},{147,0,80},{134,0,657},{134,0,933},{135,11,1147},{4,0,230},{133,0,702 +},{134,0,1728},{4,0,484},{18,0,26},{19,0,42},{20,0,43},{21,0,0},{23,0,27},{152,0 +,14},{7,0,185},{135,0,703},{6,0,417},{7,10,1106},{9,10,770},{10,0,618},{11,10, +112},{140,10,413},{134,0,803},{132,11,644},{134,0,1262},{7,11,540},{12,10,271},{ +145,10,109},{135,11,123},{132,0,633},{134,11,623},{4,11,908},{5,11,359},{5,11, +508},{6,11,1723},{7,11,343},{7,11,1996},{135,11,2026},{135,0,479},{7,10,304},{9, +10,646},{9,10,862},{10,0,262},{11,10,696},{12,10,208},{15,10,79},{147,10,108},{4 +,11,341},{135,11,480},{134,0,830},{5,0,70},{5,0,622},{6,0,334},{7,0,1032},{9,0, +171},{11,0,26},{11,0,213},{11,0,637},{11,0,707},{12,0,202},{12,0,380},{13,0,226} +,{13,0,355},{14,0,222},{145,0,42},{135,10,981},{143,0,217},{137,11,114},{4,0,23} +,{4,0,141},{5,0,313},{5,0,1014},{6,0,50},{6,0,51},{7,0,142},{7,0,384},{7,0,559}, +{8,0,640},{9,0,460},{9,0,783},{11,0,741},{12,0,183},{141,0,488},{141,0,360},{7,0 +,1586},{7,11,1995},{8,11,299},{11,11,890},{140,11,674},{132,10,434},{6,10,550},{ +135,0,652},{5,10,553},{7,0,766},{138,10,824},{7,0,737},{8,0,298},{136,10,452},{4 +,11,238},{5,11,503},{6,11,179},{7,11,2003},{8,11,381},{8,11,473},{9,11,149},{10, +11,183},{15,11,45},{143,11,86},{133,10,292},{5,0,222},{9,0,655},{138,0,534},{138 +,10,135},{4,11,121},{5,11,156},{5,11,349},{9,11,136},{10,11,605},{14,11,342},{ +147,11,107},{137,0,906},{6,0,1013},{134,0,1250},{6,0,1956},{6,0,2009},{8,0,991}, +{144,0,120},{135,11,1192},{138,0,503},{5,0,154},{7,0,1491},{10,0,379},{138,0,485 +},{6,0,1867},{6,0,1914},{6,0,1925},{9,0,917},{9,0,925},{9,0,932},{9,0,951},{9,0, +1007},{9,0,1013},{12,0,806},{12,0,810},{12,0,814},{12,0,816},{12,0,824},{12,0, +832},{12,0,837},{12,0,863},{12,0,868},{12,0,870},{12,0,889},{12,0,892},{12,0,900 +},{12,0,902},{12,0,908},{12,0,933},{12,0,942},{12,0,949},{12,0,954},{15,0,175},{ +15,0,203},{15,0,213},{15,0,218},{15,0,225},{15,0,231},{15,0,239},{15,0,248},{15, +0,252},{18,0,190},{18,0,204},{18,0,215},{18,0,216},{18,0,222},{18,0,225},{18,0, +230},{18,0,239},{18,0,241},{21,0,42},{21,0,43},{21,0,44},{21,0,45},{21,0,46},{21 +,0,53},{24,0,27},{152,0,31},{133,0,716},{135,0,844},{4,0,91},{5,0,388},{5,0,845} +,{6,0,206},{6,0,252},{6,0,365},{7,0,136},{7,0,531},{136,0,621},{7,10,393},{10,10 +,603},{139,10,206},{6,11,80},{6,11,1694},{7,11,173},{7,11,1974},{9,11,547},{10, +11,730},{14,11,18},{150,11,39},{137,0,748},{4,11,923},{134,11,1711},{4,10,912},{ +137,10,232},{7,10,98},{7,10,1973},{136,10,716},{5,10,733},{142,0,103},{132,11, +595},{5,11,240},{6,11,459},{7,11,12},{7,11,114},{7,11,502},{7,11,1751},{7,11, +1753},{7,11,1805},{8,11,658},{9,11,1},{11,11,959},{12,0,158},{13,11,446},{14,11, +211},{18,0,8},{19,0,62},{20,0,6},{22,0,4},{23,0,2},{151,0,9},{135,0,576},{5,0, +771},{5,0,863},{5,0,898},{6,0,648},{6,0,1632},{6,0,1644},{134,0,1780},{133,0,331 +},{7,11,633},{7,11,905},{7,11,909},{7,11,1538},{9,11,767},{140,11,636},{140,0, +632},{5,0,107},{7,0,201},{136,0,518},{6,0,446},{6,11,490},{135,0,1817},{9,0,851} +,{141,0,510},{7,11,250},{8,11,506},{136,11,507},{4,0,504},{137,10,72},{132,11, +158},{4,11,140},{7,11,362},{8,11,209},{9,11,10},{9,11,160},{9,11,503},{10,11,689 +},{11,11,350},{11,11,553},{11,11,725},{12,11,252},{12,11,583},{13,11,192},{13,11 +,352},{14,11,269},{14,11,356},{148,11,50},{6,11,597},{135,11,1318},{135,10,1454} +,{5,0,883},{5,0,975},{8,0,392},{148,0,7},{6,11,228},{7,11,1341},{9,11,408},{138, +11,343},{11,10,600},{11,11,348},{12,11,99},{13,10,245},{18,11,1},{18,11,11},{147 +,11,4},{134,11,296},{5,0,922},{134,0,1707},{132,11,557},{4,11,548},{7,10,164},{7 +,10,1571},{9,10,107},{140,10,225},{7,11,197},{8,11,142},{8,11,325},{9,11,150},{9 +,11,596},{10,11,350},{10,11,353},{11,11,74},{11,11,315},{14,11,423},{143,11,141} +,{5,0,993},{7,0,515},{137,0,91},{4,0,131},{5,10,484},{5,10,510},{6,10,434},{7,10 +,1000},{7,10,1098},{8,0,200},{136,10,2},{152,0,10},{4,11,62},{5,11,83},{6,11,399 +},{6,11,579},{7,11,692},{7,11,846},{7,11,1015},{7,11,1799},{8,11,403},{9,11,394} +,{10,11,133},{12,11,4},{12,11,297},{12,11,452},{16,11,81},{18,11,19},{18,11,25}, +{21,11,14},{22,11,12},{151,11,18},{140,11,459},{132,11,177},{7,0,1433},{9,0,365} +,{137,11,365},{132,10,460},{5,0,103},{5,11,411},{6,0,2004},{7,0,921},{7,11,653}, +{8,0,580},{8,0,593},{8,0,630},{138,0,28},{4,10,932},{133,10,891},{4,0,911},{5,0, +867},{5,0,1013},{7,0,2034},{8,0,798},{136,0,813},{7,11,439},{10,11,727},{11,11, +260},{139,11,684},{136,10,625},{5,11,208},{7,11,753},{135,11,1528},{5,0,461},{6, +10,76},{7,0,1925},{12,0,39},{13,0,265},{141,0,439},{6,0,853},{8,10,92},{137,10, +221},{5,0,135},{6,0,519},{7,0,1722},{10,0,271},{11,0,261},{145,0,54},{139,11,814 +},{14,0,338},{148,0,81},{4,0,300},{133,0,436},{5,0,419},{5,0,687},{7,0,864},{7, +11,864},{137,0,470},{5,11,242},{137,0,836},{134,0,1937},{4,10,763},{133,11,953}, +{132,10,622},{132,0,393},{133,10,253},{7,10,546},{8,0,357},{10,0,745},{14,0,426} +,{17,0,94},{147,0,57},{5,11,615},{146,11,37},{9,10,73},{10,10,110},{14,10,185},{ +145,10,119},{7,10,624},{7,10,916},{10,10,256},{11,0,703},{139,10,87},{133,11,290 +},{5,10,212},{12,10,35},{141,10,382},{132,11,380},{5,11,52},{7,11,277},{9,11,368 +},{139,11,791},{133,0,387},{10,11,138},{139,11,476},{4,0,6},{5,0,708},{136,0,75} +,{7,0,1351},{9,0,581},{10,0,639},{11,0,453},{140,0,584},{132,0,303},{138,0,772}, +{135,10,1175},{4,0,749},{5,10,816},{6,11,256},{7,11,307},{7,11,999},{7,11,1481}, +{7,11,1732},{7,11,1738},{8,11,265},{9,11,414},{11,11,316},{12,11,52},{13,11,420} +,{147,11,100},{135,11,1296},{5,10,869},{5,10,968},{6,0,1065},{6,10,1626},{8,10, +734},{136,10,784},{4,10,542},{6,10,1716},{6,10,1727},{7,10,1082},{7,10,1545},{8, +10,56},{8,10,118},{8,10,412},{8,10,564},{9,10,888},{9,10,908},{10,10,50},{10,10, +423},{11,10,685},{11,10,697},{11,10,933},{12,10,299},{13,10,126},{13,10,136},{13 +,10,170},{141,10,190},{134,0,226},{4,0,106},{5,11,723},{7,0,310},{139,0,717},{4, +10,232},{5,0,890},{5,0,988},{9,10,202},{10,10,474},{140,10,433},{6,0,626},{142,0 +,431},{10,0,706},{150,0,44},{6,10,108},{7,10,1003},{7,10,1181},{8,10,111},{8,10, +343},{141,0,51},{132,0,698},{5,11,109},{6,11,1784},{7,11,1895},{12,11,296},{140, +11,302},{134,0,828},{134,10,1712},{138,0,17},{4,10,133},{5,11,216},{7,0,1929},{7 +,10,711},{7,10,1298},{7,10,1585},{7,11,1879},{9,11,141},{9,11,270},{9,11,679},{ +10,11,159},{10,11,553},{11,11,197},{11,11,438},{12,11,538},{12,11,559},{13,11, +193},{13,11,423},{14,11,144},{14,11,166},{14,11,167},{15,11,67},{147,11,84},{141 +,11,127},{7,11,1872},{137,11,81},{6,10,99},{7,10,1808},{145,10,57},{134,11,391}, +{5,0,689},{6,0,84},{6,10,574},{7,0,1250},{7,10,428},{10,10,669},{11,10,485},{11, +10,840},{12,10,300},{142,10,250},{7,11,322},{136,11,249},{7,11,432},{135,11,1649 +},{135,10,1871},{137,10,252},{6,11,155},{140,11,234},{7,0,871},{19,0,27},{147,11 +,27},{140,0,498},{5,0,986},{6,0,130},{138,0,823},{6,0,1793},{6,10,323},{7,0,1582 +},{7,10,1564},{8,0,458},{10,0,101},{10,0,318},{10,0,945},{12,0,734},{16,0,104},{ +146,0,177},{5,11,632},{138,11,526},{7,10,461},{8,10,775},{138,0,435},{6,11,144}, +{7,11,948},{7,11,1042},{7,11,1857},{8,11,235},{8,11,461},{9,11,453},{9,11,530},{ +10,11,354},{17,11,77},{19,11,99},{148,11,79},{138,0,966},{7,0,1644},{137,0,129}, +{135,0,997},{136,0,502},{5,11,196},{6,11,486},{7,11,212},{8,11,309},{136,11,346} +,{7,10,727},{146,10,73},{132,0,823},{132,11,686},{135,0,1927},{4,0,762},{7,0, +1756},{137,0,98},{136,10,577},{4,11,30},{5,11,43},{24,0,8},{152,11,8},{7,0,1046} +,{139,0,160},{4,10,413},{5,10,677},{7,0,492},{7,11,492},{8,10,432},{140,10,280}, +{6,0,45},{7,0,433},{8,0,129},{9,0,21},{10,0,392},{11,0,79},{12,0,499},{13,0,199} +,{141,0,451},{7,0,558},{136,0,353},{4,11,220},{7,11,1535},{9,11,93},{139,11,474} +,{7,10,646},{7,10,1730},{11,10,446},{141,10,178},{133,0,785},{134,0,1145},{8,0, +81},{9,0,189},{9,0,201},{11,0,478},{11,0,712},{141,0,338},{5,0,353},{151,0,26},{ +4,10,395},{139,0,762},{134,0,2024},{4,0,611},{133,0,606},{9,10,174},{10,10,164}, +{11,10,440},{11,10,841},{143,10,98},{134,10,426},{10,10,608},{139,10,1002},{138, +10,250},{6,0,25},{7,0,855},{7,0,1258},{144,0,32},{7,11,1725},{138,11,393},{5,11, +263},{134,11,414},{5,10,476},{134,0,2011},{4,0,4},{6,11,178},{6,11,1750},{7,0, +1118},{7,0,1320},{7,0,1706},{8,0,277},{8,11,251},{9,0,622},{9,11,690},{10,0,9},{ +10,11,155},{10,11,196},{10,11,373},{11,0,724},{11,11,698},{12,0,350},{12,0,397}, +{13,0,28},{13,0,159},{13,11,155},{15,0,89},{18,0,5},{19,0,9},{20,0,34},{20,11,93 +},{150,0,47},{5,11,97},{137,11,393},{5,10,76},{6,10,458},{6,10,497},{7,0,764},{7 +,10,868},{9,10,658},{10,10,594},{11,0,461},{11,10,566},{12,0,172},{12,10,338},{ +141,10,200},{134,0,1449},{138,11,40},{134,11,1639},{134,0,1445},{4,10,526},{6,0, +1168},{7,10,1029},{135,10,1054},{4,11,191},{7,11,934},{8,11,647},{145,11,97},{ +132,10,636},{6,0,233},{7,10,660},{7,10,1124},{17,10,31},{19,10,22},{151,10,14},{ +6,10,1699},{136,11,110},{12,11,246},{15,11,162},{19,11,64},{20,11,8},{20,11,95}, +{22,11,24},{152,11,17},{5,11,165},{9,11,346},{138,11,655},{5,11,319},{135,11,534 +},{134,0,255},{8,11,128},{9,0,216},{139,11,179},{9,0,183},{139,0,286},{11,0,956} +,{151,0,3},{4,0,536},{7,0,1141},{10,0,723},{139,0,371},{4,10,279},{7,10,301},{ +137,10,362},{5,11,57},{6,11,101},{6,11,1663},{7,0,285},{7,11,132},{7,11,1048},{7 +,11,1154},{7,11,1415},{7,11,1507},{12,11,493},{15,11,105},{151,11,15},{5,11,459} +,{7,10,1743},{7,11,1073},{8,11,241},{136,11,334},{4,10,178},{133,10,399},{135,0, +560},{132,0,690},{135,0,1246},{18,0,157},{147,0,63},{10,0,599},{11,0,33},{12,0, +571},{149,0,1},{6,11,324},{6,11,520},{7,11,338},{7,11,1616},{7,11,1729},{8,11, +228},{9,11,69},{139,11,750},{7,0,1862},{12,0,491},{12,0,520},{13,0,383},{142,0, +244},{135,11,734},{134,10,1692},{6,10,202},{7,11,705},{10,0,448},{11,0,630},{12, +10,360},{17,0,117},{17,10,118},{18,10,27},{148,10,67},{4,11,73},{6,11,612},{7,11 +,927},{7,11,1822},{8,11,217},{9,11,472},{9,11,765},{9,11,766},{10,11,408},{11,11 +,51},{11,11,793},{12,11,266},{15,11,158},{20,11,89},{150,11,32},{4,0,190},{133,0 +,554},{133,0,1001},{5,11,389},{8,11,636},{137,11,229},{5,0,446},{7,10,872},{10, +10,516},{139,10,167},{137,10,313},{132,10,224},{134,0,1313},{5,10,546},{7,10,35} +,{8,10,11},{8,10,12},{9,10,315},{9,10,533},{10,10,802},{11,10,166},{12,10,525},{ +142,10,243},{6,0,636},{137,0,837},{5,10,241},{8,10,242},{9,10,451},{10,10,667},{ +11,10,598},{140,10,429},{22,10,46},{150,11,46},{136,11,472},{11,0,278},{142,0,73 +},{141,11,185},{132,0,868},{134,0,972},{4,10,366},{137,10,516},{138,0,1010},{5, +11,189},{6,10,1736},{7,11,442},{7,11,443},{8,11,281},{12,11,174},{13,11,83},{141 +,11,261},{139,11,384},{6,11,2},{7,11,191},{7,11,446},{7,11,758},{7,11,1262},{7, +11,1737},{8,11,22},{8,11,270},{8,11,612},{9,11,4},{9,11,167},{9,11,312},{9,11, +436},{10,11,156},{10,11,216},{10,11,311},{10,11,623},{11,11,72},{11,11,330},{11, +11,455},{12,11,101},{12,11,321},{12,11,504},{12,11,530},{12,11,543},{13,11,17},{ +13,11,156},{13,11,334},{14,11,48},{15,11,70},{17,11,60},{148,11,64},{6,10,331},{ +136,10,623},{135,0,1231},{132,0,304},{6,11,60},{7,11,670},{7,11,1327},{8,11,411} +,{8,11,435},{9,11,653},{9,11,740},{10,11,385},{11,11,222},{11,11,324},{11,11,829 +},{140,11,611},{6,11,166},{7,0,506},{7,11,374},{135,11,1174},{14,11,43},{146,11, +21},{135,11,1694},{135,10,1888},{5,11,206},{134,11,398},{135,11,50},{150,0,26},{ +6,0,53},{6,0,199},{7,0,1408},{8,0,32},{8,0,93},{10,0,397},{10,0,629},{11,0,593}, +{11,0,763},{13,0,326},{145,0,35},{134,0,105},{132,10,394},{4,0,843},{138,0,794}, +{11,0,704},{141,0,396},{5,0,114},{5,0,255},{141,0,285},{6,0,619},{7,0,898},{7,0, +1092},{7,10,1931},{8,0,485},{18,0,28},{147,0,116},{7,10,574},{7,10,1719},{137,0, +145},{7,0,2035},{8,0,19},{9,0,89},{138,0,831},{132,10,658},{6,11,517},{7,11,1159 +},{10,11,621},{139,11,192},{7,0,1933},{7,11,1933},{9,10,781},{10,10,144},{11,10, +385},{13,10,161},{13,10,228},{13,10,268},{148,10,107},{136,10,374},{10,11,223},{ +139,11,645},{135,0,1728},{7,11,64},{7,11,289},{136,11,245},{4,10,344},{6,10,498} +,{139,10,323},{136,0,746},{135,10,1063},{137,10,155},{4,0,987},{6,0,1964},{6,0, +1974},{6,0,1990},{136,0,995},{133,11,609},{133,10,906},{134,0,1550},{134,0,874}, +{5,11,129},{6,11,61},{135,11,947},{4,0,1018},{6,0,1938},{6,0,2021},{134,0,2039}, +{132,0,814},{11,0,126},{139,0,287},{134,0,1264},{5,0,955},{136,0,814},{141,11, +506},{132,11,314},{6,0,981},{139,11,1000},{5,0,56},{8,0,892},{8,0,915},{140,0, +776},{148,0,100},{10,0,4},{10,0,13},{11,0,638},{148,0,57},{148,11,74},{4,10,616} +,{133,0,738},{133,11,637},{136,10,692},{133,0,758},{132,10,305},{137,11,590},{5, +11,280},{135,11,1226},{134,11,494},{135,0,1112},{133,11,281},{5,10,214},{7,10, +603},{8,10,611},{9,10,686},{10,10,88},{11,10,459},{11,10,496},{12,10,463},{12,10 +,590},{13,0,44},{142,0,214},{139,0,328},{135,11,1064},{137,0,133},{7,0,168},{13, +0,196},{141,0,237},{134,10,1703},{134,0,1152},{135,0,1245},{5,0,110},{6,0,169},{ +6,0,1702},{7,0,400},{8,0,538},{9,0,184},{9,0,524},{140,0,218},{6,0,1816},{10,0, +871},{12,0,769},{140,0,785},{132,11,630},{7,11,33},{7,11,120},{8,11,489},{9,11, +319},{10,11,820},{11,11,1004},{12,11,379},{13,11,117},{13,11,412},{14,11,25},{15 +,11,52},{15,11,161},{16,11,47},{149,11,2},{6,0,133},{8,0,413},{9,0,353},{139,0, +993},{145,10,19},{4,11,937},{133,11,801},{134,0,978},{6,0,93},{6,0,1508},{7,0, +1422},{7,0,1851},{8,0,673},{9,0,529},{140,0,43},{4,10,737},{6,0,317},{10,0,512}, +{11,10,294},{12,10,60},{12,10,437},{13,10,64},{13,10,380},{142,10,430},{7,11, +1591},{9,0,371},{144,11,43},{6,10,1758},{8,10,520},{9,10,345},{9,10,403},{142,10 +,350},{5,0,526},{10,10,242},{138,10,579},{9,0,25},{10,0,467},{138,0,559},{5,10, +139},{7,10,1168},{138,10,539},{4,0,335},{135,0,942},{140,0,754},{132,11,365},{11 +,0,182},{142,0,195},{142,11,29},{5,11,7},{139,11,774},{4,11,746},{135,11,1090},{ +8,0,39},{10,0,773},{11,0,84},{12,0,205},{142,0,1},{5,0,601},{5,0,870},{5,11,360} +,{136,11,237},{132,0,181},{136,0,370},{134,0,1652},{4,10,107},{7,10,613},{8,0, +358},{8,10,439},{8,10,504},{9,10,501},{10,10,383},{139,10,477},{132,10,229},{137 +,11,785},{4,0,97},{5,0,147},{6,0,286},{7,0,1362},{141,0,176},{4,10,903},{6,0,537 +},{7,0,788},{135,0,1816},{140,10,71},{6,0,743},{134,0,1223},{6,0,375},{7,0,169}, +{7,0,254},{7,11,1493},{136,0,780},{4,10,47},{6,10,373},{7,0,1714},{7,10,452},{7, +10,543},{7,10,1856},{9,10,6},{11,10,257},{139,10,391},{6,0,896},{136,0,1003},{ +135,0,1447},{137,11,341},{5,10,980},{134,10,1754},{145,11,22},{4,11,277},{5,11, +608},{6,11,493},{7,11,457},{140,11,384},{7,10,536},{7,10,1331},{136,10,143},{140 +,0,744},{7,11,27},{135,11,316},{5,10,19},{6,10,533},{146,0,126},{4,0,788},{5,11, +552},{5,11,586},{5,11,676},{6,11,448},{8,11,244},{11,0,41},{11,11,1},{11,11,41}, +{13,11,3},{16,11,54},{17,11,4},{146,11,13},{4,0,985},{4,11,401},{6,0,1801},{137, +11,264},{5,10,395},{5,10,951},{134,10,1776},{5,0,629},{135,0,1549},{11,10,663},{ +12,10,210},{13,10,166},{13,10,310},{14,10,373},{147,10,43},{9,11,543},{10,11,524 +},{11,11,30},{12,11,524},{14,11,315},{16,11,18},{20,11,26},{148,11,65},{4,11,205 +},{5,11,623},{7,11,104},{136,11,519},{5,0,293},{134,0,601},{7,11,579},{9,11,41}, +{9,11,244},{9,11,669},{10,11,5},{11,11,861},{11,11,951},{139,11,980},{132,11,717 +},{132,10,695},{7,10,497},{9,10,387},{147,10,81},{132,0,420},{142,0,37},{6,0, +1134},{6,0,1900},{12,0,830},{12,0,878},{12,0,894},{15,0,221},{143,0,245},{132,11 +,489},{7,0,1570},{140,0,542},{8,0,933},{136,0,957},{5,10,284},{6,0,1371},{6,10, +49},{6,10,350},{7,0,31},{7,10,377},{7,10,1693},{8,0,373},{8,10,678},{9,10,161},{ +9,10,585},{9,10,671},{9,10,839},{11,10,912},{141,10,427},{135,11,892},{4,0,325}, +{138,0,125},{139,11,47},{132,10,597},{138,0,323},{6,0,1547},{7,11,1605},{9,11, +473},{11,11,962},{146,11,139},{139,10,908},{7,11,819},{9,11,26},{9,11,392},{10, +11,152},{10,11,226},{11,11,19},{12,11,276},{12,11,426},{12,11,589},{13,11,460},{ +15,11,97},{19,11,48},{148,11,104},{135,11,51},{4,0,718},{135,0,1216},{6,0,1896}, +{6,0,1905},{6,0,1912},{7,11,761},{7,11,1051},{9,0,947},{9,0,974},{9,11,545},{12, +0,809},{12,0,850},{12,0,858},{12,0,874},{12,0,887},{12,0,904},{12,0,929},{12,0, +948},{12,0,952},{15,0,198},{15,0,206},{15,0,220},{15,0,227},{15,0,247},{18,0,188 +},{21,0,48},{21,0,50},{24,0,25},{152,0,29},{5,0,124},{5,0,144},{6,0,548},{7,0,15 +},{7,0,153},{137,0,629},{135,11,606},{135,10,2014},{7,10,2007},{9,10,101},{9,10, +450},{9,11,46},{10,10,66},{10,10,842},{11,10,536},{140,10,587},{6,0,75},{7,0, +1531},{8,0,416},{9,0,240},{9,0,275},{10,0,100},{11,0,658},{11,0,979},{12,0,86},{ +14,0,207},{15,0,20},{143,0,25},{5,0,141},{5,0,915},{6,0,1783},{7,0,211},{7,0,698 +},{7,0,1353},{9,0,83},{9,0,281},{10,0,376},{10,0,431},{11,0,543},{12,0,664},{13, +0,280},{13,0,428},{14,0,61},{14,0,128},{17,0,52},{145,0,81},{132,11,674},{135,0, +533},{149,0,6},{132,11,770},{133,0,538},{5,11,79},{7,11,1027},{7,11,1477},{139, +11,52},{139,10,62},{4,0,338},{133,0,400},{5,11,789},{134,11,195},{4,11,251},{4, +11,688},{7,11,513},{7,11,1284},{9,11,87},{138,11,365},{134,10,1766},{6,0,0},{7,0 +,84},{11,0,895},{145,0,11},{139,0,892},{4,0,221},{5,0,659},{7,0,697},{7,0,1211}, +{138,0,284},{133,0,989},{133,11,889},{4,11,160},{5,11,330},{7,11,1434},{136,11, +174},{6,10,1665},{7,10,256},{7,10,1388},{10,10,499},{139,10,670},{4,10,22},{5,10 +,10},{7,0,848},{136,10,97},{138,0,507},{133,10,481},{4,0,188},{135,0,805},{5,0, +884},{6,0,732},{139,0,991},{135,11,968},{11,11,636},{15,11,145},{17,11,34},{19, +11,50},{151,11,20},{6,10,134},{7,0,959},{7,10,437},{9,10,37},{14,10,285},{14,10, +371},{144,0,60},{7,10,486},{8,10,155},{11,10,93},{140,10,164},{134,0,1653},{5,10 +,591},{135,0,337},{5,11,374},{6,0,1989},{8,0,922},{136,0,978},{132,0,638},{138,0 +,500},{133,11,731},{5,10,380},{5,10,650},{136,10,310},{138,11,381},{4,10,364},{7 +,10,1156},{7,10,1187},{137,10,409},{137,11,224},{140,0,166},{134,10,482},{4,11, +626},{5,11,642},{6,11,425},{10,11,202},{139,11,141},{4,10,781},{6,10,487},{7,10, +926},{8,10,263},{139,10,500},{135,0,418},{4,10,94},{135,10,1265},{136,0,760},{ +132,10,417},{136,11,835},{5,10,348},{134,10,522},{6,0,1277},{134,0,1538},{139,11 +,541},{135,11,1597},{5,11,384},{8,11,455},{140,11,48},{136,0,770},{5,11,264},{ +134,11,184},{4,0,89},{5,0,489},{6,0,315},{7,0,553},{7,0,1745},{138,0,243},{4,10, +408},{4,10,741},{135,10,500},{134,0,1396},{133,0,560},{6,0,1658},{9,0,3},{10,0, +154},{11,0,641},{13,0,85},{13,0,201},{141,0,346},{135,11,1595},{5,11,633},{6,11, +28},{7,11,219},{135,11,1323},{9,11,769},{140,11,185},{135,11,785},{7,11,359},{8, +11,243},{140,11,175},{138,0,586},{6,10,73},{135,0,1271},{132,11,105},{4,0,166},{ +5,0,505},{134,0,1670},{133,10,576},{4,11,324},{138,11,104},{142,10,231},{6,0,637 +},{7,10,1264},{7,10,1678},{11,10,945},{12,10,341},{12,10,471},{12,10,569},{23,11 +,21},{151,11,23},{8,11,559},{141,11,109},{134,0,1947},{7,0,445},{8,0,307},{8,0, +704},{10,0,41},{10,0,439},{11,0,237},{11,0,622},{140,0,201},{135,11,963},{135,0, +1977},{4,0,189},{5,0,713},{136,0,57},{138,0,371},{135,10,538},{132,0,552},{5,10, +413},{134,0,883},{4,11,758},{134,0,923},{138,11,215},{136,10,495},{7,10,54},{8, +10,312},{10,10,191},{10,10,614},{140,10,567},{7,11,351},{139,11,128},{6,10,468}, +{7,0,875},{7,10,1478},{8,10,530},{142,10,290},{135,0,1788},{5,11,918},{145,0,49} +,{12,11,398},{20,11,39},{21,11,11},{150,11,41},{6,10,484},{7,10,822},{138,0,661} +,{135,0,1945},{134,0,794},{137,10,900},{135,10,1335},{6,10,1724},{135,10,2022},{ +132,11,340},{134,0,1135},{4,0,784},{133,0,745},{5,0,84},{134,0,163},{133,0,410}, +{4,0,976},{5,11,985},{7,11,509},{7,11,529},{145,11,96},{132,10,474},{134,0,703}, +{135,11,1919},{5,0,322},{8,0,186},{9,0,262},{10,0,187},{142,0,208},{135,10,1504} +,{133,0,227},{5,10,305},{9,0,560},{141,0,208},{132,11,247},{7,0,1395},{8,0,486}, +{9,0,236},{9,0,878},{10,0,218},{11,0,95},{19,0,17},{147,0,31},{7,0,2043},{8,0, +672},{141,0,448},{4,11,184},{5,11,390},{6,11,337},{7,11,23},{7,11,494},{7,11,618 +},{7,11,1456},{8,11,27},{8,11,599},{10,11,153},{139,11,710},{135,0,466},{135,10, +1236},{4,10,480},{6,0,167},{6,10,302},{6,10,1642},{7,0,186},{7,0,656},{7,10,837} +,{7,10,1547},{7,10,1657},{8,10,429},{9,10,228},{10,0,643},{13,10,289},{13,10,343 +},{147,10,101},{134,0,1428},{134,0,1440},{5,0,412},{7,10,278},{10,10,739},{11,10 +,708},{141,10,348},{134,0,1118},{136,0,562},{148,11,46},{9,0,316},{139,0,256},{ +134,0,1771},{135,0,1190},{137,0,132},{10,11,227},{11,11,497},{11,11,709},{140,11 +,415},{143,0,66},{6,11,360},{7,11,1664},{136,11,478},{144,10,28},{4,0,317},{135, +0,1279},{5,0,63},{133,0,509},{136,11,699},{145,10,36},{134,0,1475},{11,11,343},{ +142,11,127},{132,11,739},{132,0,288},{135,11,1757},{8,0,89},{8,0,620},{9,0,608}, +{11,0,628},{12,0,322},{143,0,124},{134,0,1225},{4,11,67},{5,11,422},{6,10,363},{ +7,0,1189},{7,10,1955},{7,11,1037},{7,11,1289},{7,11,1555},{8,10,725},{9,11,741}, +{145,11,108},{134,0,1468},{6,0,689},{134,0,1451},{138,0,120},{151,0,1},{137,10, +805},{142,0,329},{5,10,813},{135,10,2046},{135,0,226},{138,11,96},{5,10,712},{7, +0,1855},{11,10,17},{13,10,321},{144,10,67},{6,10,320},{7,10,781},{7,10,1921},{9, +0,461},{9,10,55},{10,10,186},{10,10,273},{10,10,664},{10,10,801},{11,10,996},{11 +,10,997},{13,10,157},{142,10,170},{8,10,271},{8,11,203},{11,11,823},{11,11,846}, +{12,11,482},{13,11,133},{13,11,277},{13,11,302},{13,11,464},{14,11,205},{142,11, +221},{135,0,1346},{4,11,449},{133,11,718},{134,0,85},{7,10,103},{7,10,863},{11, +10,184},{14,0,299},{145,10,62},{4,11,355},{6,11,311},{9,11,256},{138,11,404},{ +137,10,659},{138,11,758},{133,11,827},{5,11,64},{140,11,581},{134,0,1171},{4,11, +442},{7,11,1047},{7,11,1352},{135,11,1643},{132,0,980},{5,11,977},{6,11,288},{7, +11,528},{135,11,1065},{5,0,279},{6,0,235},{7,0,468},{8,0,446},{9,0,637},{10,0, +717},{11,0,738},{140,0,514},{132,0,293},{11,10,337},{142,10,303},{136,11,285},{4 +,11,254},{5,0,17},{6,0,371},{9,0,528},{140,0,364},{5,10,77},{7,10,1455},{10,10, +843},{147,10,73},{150,0,5},{132,10,458},{6,11,12},{7,11,1219},{145,11,73},{135, +10,1420},{6,10,109},{138,10,382},{135,11,125},{6,10,330},{7,10,1084},{139,10,142 +},{6,11,369},{6,11,502},{7,11,1036},{8,11,348},{9,11,452},{10,11,26},{11,11,224} +,{11,11,387},{11,11,772},{12,11,95},{12,11,629},{13,11,195},{13,11,207},{13,11, +241},{14,11,260},{14,11,270},{143,11,140},{132,11,269},{5,11,480},{7,11,532},{7, +11,1197},{7,11,1358},{8,11,291},{11,11,349},{142,11,396},{150,0,48},{10,0,601},{ +13,0,353},{141,0,376},{5,0,779},{5,0,807},{6,0,1655},{134,0,1676},{142,11,223},{ +4,0,196},{5,0,558},{133,0,949},{148,11,15},{135,11,1764},{134,0,1322},{132,0,752 +},{139,0,737},{135,11,657},{136,11,533},{135,0,412},{4,0,227},{5,0,159},{5,0,409 +},{7,0,80},{8,0,556},{10,0,479},{12,0,418},{14,0,50},{14,0,123},{14,0,192},{14,0 +,249},{14,0,295},{143,0,27},{7,0,1470},{8,0,66},{8,0,137},{8,0,761},{9,0,638},{ +11,0,80},{11,0,212},{11,0,368},{11,0,418},{12,0,8},{13,0,15},{16,0,61},{17,0,59} +,{19,0,28},{148,0,84},{135,10,1985},{4,11,211},{4,11,332},{5,11,335},{6,11,238}, +{7,11,269},{7,11,811},{7,11,1797},{8,10,122},{8,11,836},{9,11,507},{141,11,242}, +{6,0,683},{134,0,1252},{4,0,873},{132,10,234},{134,0,835},{6,0,38},{7,0,1220},{8 +,0,185},{8,0,256},{9,0,22},{9,0,331},{10,0,738},{11,0,205},{11,0,540},{11,0,746} +,{13,0,465},{14,0,88},{142,0,194},{138,0,986},{5,11,1009},{12,11,582},{146,11, +131},{4,0,159},{6,0,115},{7,0,252},{7,0,257},{7,0,1928},{8,0,69},{9,0,384},{10,0 +,91},{10,0,615},{12,0,375},{14,0,235},{18,0,117},{147,0,123},{133,0,911},{136,0, +278},{5,10,430},{5,10,932},{6,10,131},{7,10,417},{9,10,522},{11,10,314},{141,10, +390},{14,10,149},{14,10,399},{143,10,57},{4,0,151},{7,0,1567},{136,0,749},{5,11, +228},{6,11,203},{7,11,156},{8,11,347},{137,11,265},{132,10,507},{10,0,989},{140, +0,956},{133,0,990},{5,0,194},{6,0,927},{7,0,1662},{9,0,90},{140,0,564},{4,10,343 +},{133,10,511},{133,0,425},{7,10,455},{138,10,591},{4,0,774},{7,11,476},{7,11, +1592},{138,11,87},{5,0,971},{135,10,1381},{5,11,318},{147,11,121},{5,11,291},{7, +11,765},{9,11,389},{140,11,548},{134,10,575},{4,0,827},{12,0,646},{12,0,705},{12 +,0,712},{140,0,714},{139,0,752},{137,0,662},{5,0,72},{6,0,264},{7,0,21},{7,0,46} +,{7,0,2013},{8,0,215},{8,0,513},{10,0,266},{139,0,22},{139,11,522},{6,0,239},{7, +0,118},{10,0,95},{11,0,603},{13,0,443},{14,0,160},{143,0,4},{6,0,431},{134,0,669 +},{7,10,1127},{7,10,1572},{10,10,297},{10,10,422},{11,10,764},{11,10,810},{12,10 +,264},{13,10,102},{13,10,300},{13,10,484},{14,10,147},{14,10,229},{17,10,71},{18 +,10,118},{147,10,120},{5,0,874},{6,0,1677},{10,11,525},{11,11,82},{143,0,0},{6,0 +,65},{7,0,939},{7,0,1172},{7,0,1671},{9,0,540},{10,0,696},{11,0,265},{11,0,732}, +{11,0,928},{11,0,937},{141,0,438},{134,0,1350},{136,11,547},{132,11,422},{5,11, +355},{145,11,0},{137,11,905},{5,0,682},{135,0,1887},{132,0,809},{4,0,696},{133, +11,865},{6,0,1074},{6,0,1472},{14,10,35},{142,10,191},{5,11,914},{134,11,1625},{ +133,11,234},{135,11,1383},{137,11,780},{132,10,125},{4,0,726},{133,0,630},{8,0, +802},{136,0,838},{132,10,721},{6,0,1337},{7,0,776},{8,10,145},{147,0,56},{132,0, +970},{7,10,792},{8,10,147},{10,10,821},{139,10,1021},{139,10,970},{8,0,940},{137 +,0,797},{135,11,1312},{7,10,1999},{7,11,816},{7,11,1241},{9,0,248},{9,11,283},{9 +,11,520},{10,0,400},{10,11,213},{10,11,307},{10,11,463},{10,11,671},{10,11,746}, +{11,11,401},{11,11,794},{12,11,517},{18,11,107},{147,11,115},{6,0,1951},{134,0, +2040},{135,11,339},{5,10,168},{5,10,930},{8,10,74},{9,10,623},{12,10,500},{12,10 +,579},{13,0,41},{143,0,93},{6,0,118},{7,0,215},{7,0,1521},{140,0,11},{6,10,220}, +{7,10,1101},{141,10,105},{6,11,421},{7,11,61},{7,11,1540},{10,11,11},{138,11,501 +},{7,0,615},{138,0,251},{140,11,631},{135,0,1044},{6,10,19},{7,10,1413},{139,10, +428},{133,0,225},{7,10,96},{8,10,401},{8,10,703},{137,10,896},{145,10,116},{6,11 +,102},{7,11,72},{15,11,142},{147,11,67},{7,10,1961},{7,10,1965},{8,10,702},{136, +10,750},{7,10,2030},{8,10,150},{8,10,737},{12,10,366},{151,11,30},{4,0,370},{5,0 +,756},{7,0,1326},{135,11,823},{8,10,800},{9,10,148},{9,10,872},{9,10,890},{11,10 +,309},{11,10,1001},{13,10,267},{141,10,323},{6,0,1662},{7,0,48},{8,0,771},{10,0, +116},{13,0,104},{14,0,105},{14,0,184},{15,0,168},{19,0,92},{148,0,68},{7,11,1870 +},{138,0,209},{7,11,68},{8,11,48},{8,11,88},{8,11,582},{8,11,681},{9,11,373},{9, +11,864},{11,11,157},{11,11,336},{11,11,843},{148,11,27},{134,0,930},{4,11,88},{5 +,11,137},{5,11,174},{5,11,777},{6,11,1664},{6,11,1725},{7,11,77},{7,11,426},{7, +11,1317},{7,11,1355},{8,11,126},{8,11,563},{9,11,523},{9,11,750},{10,11,310},{10 +,11,836},{11,11,42},{11,11,318},{11,11,731},{12,11,68},{12,11,92},{12,11,507},{ +12,11,692},{13,11,81},{13,11,238},{13,11,374},{18,11,138},{19,11,78},{19,11,111} +,{20,11,55},{20,11,77},{148,11,92},{4,11,938},{135,11,1831},{5,10,547},{7,10,424 +},{8,11,617},{138,11,351},{6,0,1286},{6,11,1668},{7,11,1499},{8,11,117},{9,11, +314},{138,11,174},{6,0,759},{6,0,894},{7,11,707},{139,11,563},{4,0,120},{135,0, +1894},{9,0,385},{149,0,17},{138,0,429},{133,11,403},{5,0,820},{135,0,931},{5,10, +133},{138,0,199},{6,0,151},{6,0,1675},{7,0,383},{151,0,10},{6,0,761},{136,10,187 +},{8,0,365},{10,10,0},{10,10,818},{139,10,988},{4,11,44},{5,11,311},{6,11,156},{ +7,11,639},{7,11,762},{7,11,1827},{9,11,8},{9,11,462},{148,11,83},{4,11,346},{7, +11,115},{9,11,180},{9,11,456},{138,11,363},{136,10,685},{7,0,1086},{145,0,46},{6 +,0,1624},{11,0,11},{12,0,422},{13,0,444},{142,0,360},{6,0,1020},{6,0,1260},{134, +0,1589},{4,0,43},{5,0,344},{5,0,357},{14,0,472},{150,0,58},{6,0,1864},{6,0,1866} +,{6,0,1868},{6,0,1869},{6,0,1874},{6,0,1877},{6,0,1903},{6,0,1911},{9,0,920},{9, +0,921},{9,0,924},{9,0,946},{9,0,959},{9,0,963},{9,0,970},{9,0,997},{9,0,1008},{9 +,0,1017},{12,0,795},{12,0,797},{12,0,798},{12,0,800},{12,0,803},{12,0,811},{12,0 +,820},{12,0,821},{12,0,839},{12,0,841},{12,0,848},{12,0,911},{12,0,921},{12,0, +922},{12,0,925},{12,0,937},{12,0,944},{12,0,945},{12,0,953},{15,0,184},{15,0,191 +},{15,0,199},{15,0,237},{15,0,240},{15,0,243},{15,0,246},{18,0,203},{21,0,40},{ +21,0,52},{21,0,57},{24,0,23},{24,0,28},{152,0,30},{134,0,725},{145,11,58},{133,0 +,888},{137,10,874},{4,0,711},{8,10,774},{10,10,670},{140,10,51},{144,11,40},{6, +11,185},{7,11,1899},{139,11,673},{137,10,701},{137,0,440},{4,11,327},{5,11,478}, +{7,11,1332},{8,11,753},{140,11,227},{4,10,127},{5,10,350},{6,10,356},{8,10,426}, +{9,10,572},{10,10,247},{139,10,312},{5,11,1020},{133,11,1022},{4,11,103},{133,11 +,401},{6,0,1913},{6,0,1926},{6,0,1959},{9,0,914},{9,0,939},{9,0,952},{9,0,979},{ +9,0,990},{9,0,998},{9,0,1003},{9,0,1023},{12,0,827},{12,0,834},{12,0,845},{12,0, +912},{12,0,935},{12,0,951},{15,0,172},{15,0,174},{18,0,198},{149,0,63},{4,11,499 +},{5,0,958},{5,0,987},{135,11,1421},{6,10,59},{6,10,1762},{7,0,885},{9,10,603},{ +141,10,397},{10,11,62},{141,11,164},{4,0,847},{135,0,326},{11,0,276},{142,0,293} +,{4,0,65},{4,11,96},{5,0,479},{5,0,1004},{7,0,1913},{8,0,317},{9,0,302},{10,0, +612},{141,0,22},{4,0,261},{135,0,510},{135,0,1514},{6,10,111},{7,10,4},{8,10,163 +},{8,10,776},{138,10,566},{4,0,291},{9,0,515},{12,0,152},{12,0,443},{13,0,392},{ +142,0,357},{7,11,399},{135,11,1492},{4,0,589},{139,0,282},{6,11,563},{135,10, +1994},{5,10,297},{135,10,1038},{4,0,130},{7,0,843},{135,0,1562},{5,0,42},{5,0, +879},{7,0,245},{7,0,324},{7,0,1532},{11,0,463},{11,0,472},{13,0,363},{144,0,52}, +{4,0,134},{133,0,372},{133,0,680},{136,10,363},{6,0,1997},{8,0,935},{136,0,977}, +{4,0,810},{135,0,1634},{135,10,1675},{4,11,910},{5,11,832},{135,0,1390},{7,10, +808},{8,11,266},{139,11,578},{132,0,644},{4,0,982},{138,0,867},{132,10,280},{135 +,0,540},{140,10,54},{135,0,123},{134,0,1978},{4,10,421},{133,10,548},{6,0,623},{ +136,0,789},{4,0,908},{5,0,359},{5,0,508},{6,0,1723},{7,0,343},{7,0,1996},{135,0, +2026},{134,0,1220},{4,0,341},{135,0,480},{6,10,254},{9,10,109},{138,10,103},{134 +,0,888},{8,11,528},{137,11,348},{4,11,20},{5,11,616},{7,0,1995},{8,0,299},{11,0, +890},{140,0,674},{135,11,1094},{134,10,1630},{4,0,238},{5,0,503},{6,0,179},{7,0, +2003},{8,0,381},{8,0,473},{9,0,149},{10,0,788},{15,0,45},{15,0,86},{20,0,110},{ +150,0,57},{133,10,671},{4,11,26},{5,11,429},{6,11,245},{7,11,704},{7,11,1379},{ +135,11,1474},{4,0,121},{5,0,156},{5,0,349},{9,0,431},{10,0,605},{142,0,342},{7, +11,943},{139,11,614},{132,10,889},{132,11,621},{7,10,1382},{7,10,1910},{135,11, +1382},{132,10,627},{133,10,775},{133,11,542},{133,11,868},{136,11,433},{6,0,1373 +},{7,0,1011},{11,10,362},{11,10,948},{140,10,388},{6,0,80},{7,0,173},{7,11,1495} +,{9,0,547},{10,0,730},{14,0,18},{150,0,39},{6,0,1694},{135,0,1974},{140,0,196},{ +4,0,923},{6,0,507},{6,0,1711},{7,10,451},{8,10,389},{12,10,490},{13,10,16},{13, +10,215},{13,10,351},{18,10,132},{147,10,125},{6,0,646},{134,0,1047},{135,10,841} +,{136,10,566},{6,0,1611},{135,0,1214},{139,0,926},{132,11,525},{132,0,595},{5,0, +240},{6,0,459},{7,0,12},{7,0,114},{7,0,949},{7,0,1753},{7,0,1805},{8,0,658},{9,0 +,1},{11,0,959},{141,0,446},{5,10,912},{134,10,1695},{132,0,446},{7,11,62},{12,11 +,45},{147,11,112},{5,10,236},{6,10,572},{8,10,492},{11,10,618},{144,10,56},{5,10 +,190},{136,10,318},{135,10,1376},{4,11,223},{6,11,359},{11,11,3},{13,11,108},{14 +,11,89},{144,11,22},{132,11,647},{134,0,490},{134,0,491},{134,0,1584},{135,11, +685},{138,11,220},{7,0,250},{136,0,507},{132,0,158},{4,0,140},{7,0,362},{8,0,209 +},{9,0,10},{9,0,160},{9,0,503},{9,0,614},{10,0,689},{11,0,327},{11,0,553},{11,0, +725},{11,0,767},{12,0,252},{12,0,583},{13,0,192},{14,0,269},{14,0,356},{148,0,50 +},{19,0,1},{19,0,26},{150,0,9},{132,11,109},{6,0,228},{7,0,1341},{9,0,408},{138, +0,343},{4,0,373},{5,0,283},{6,0,480},{7,0,609},{10,0,860},{138,0,878},{6,0,779}, +{134,0,1209},{4,0,557},{7,11,263},{7,11,628},{136,11,349},{132,0,548},{7,0,197}, +{8,0,142},{8,0,325},{9,0,150},{9,0,596},{10,0,350},{10,0,353},{11,0,74},{11,0, +315},{12,0,662},{12,0,681},{14,0,423},{143,0,141},{4,11,40},{10,11,67},{11,11, +117},{11,11,768},{139,11,935},{7,11,992},{8,11,301},{9,11,722},{12,11,63},{13,11 +,29},{14,11,161},{143,11,18},{6,0,1490},{138,11,532},{5,0,580},{7,0,378},{7,0, +674},{7,0,1424},{15,0,83},{15,11,83},{16,0,11},{144,11,11},{6,0,1057},{6,0,1335} +,{7,10,85},{7,10,247},{8,10,585},{10,0,316},{138,10,163},{4,0,169},{5,0,83},{6,0 +,399},{6,0,579},{6,0,1513},{7,0,692},{7,0,846},{7,0,1015},{7,0,1799},{8,0,403},{ +9,0,394},{10,0,133},{12,0,4},{12,0,297},{12,0,452},{16,0,81},{18,0,25},{21,0,14} +,{22,0,12},{151,0,18},{134,0,1106},{7,0,1546},{11,0,299},{142,0,407},{134,0,1192 +},{132,0,177},{5,0,411},{135,0,653},{7,0,439},{10,0,727},{11,0,260},{139,0,684}, +{138,10,145},{147,10,83},{5,0,208},{7,0,753},{135,0,1528},{137,11,617},{135,10, +1922},{135,11,825},{4,10,124},{10,10,457},{11,0,422},{11,10,121},{11,10,169},{11 +,10,870},{12,10,214},{13,0,389},{14,10,187},{143,10,77},{11,0,615},{11,11,615},{ +15,0,58},{143,11,58},{9,0,618},{138,0,482},{6,0,1952},{6,0,1970},{142,0,505},{7, +10,1193},{135,11,1838},{133,0,242},{135,10,1333},{6,10,107},{7,10,638},{7,10, +1632},{137,10,396},{133,0,953},{5,10,370},{134,10,1756},{5,11,28},{6,11,204},{10 +,11,320},{10,11,583},{13,11,502},{14,11,72},{14,11,274},{14,11,312},{14,11,344}, +{15,11,159},{16,11,62},{16,11,69},{17,11,30},{18,11,42},{18,11,53},{18,11,84},{ +18,11,140},{19,11,68},{19,11,85},{20,11,5},{20,11,45},{20,11,101},{22,11,7},{150 +,11,20},{4,11,558},{6,11,390},{7,11,162},{7,11,689},{9,11,360},{138,11,653},{11, +0,802},{141,0,67},{133,10,204},{133,0,290},{5,10,970},{134,10,1706},{132,0,380}, +{5,0,52},{7,0,277},{9,0,368},{139,0,791},{5,11,856},{6,11,1672},{6,11,1757},{6, +11,1781},{7,11,1150},{7,11,1425},{7,11,1453},{140,11,513},{5,11,92},{7,10,3},{10 +,11,736},{140,11,102},{4,0,112},{5,0,653},{5,10,483},{5,10,685},{6,10,489},{7,10 +,1204},{136,10,394},{132,10,921},{5,10,1007},{134,0,1028},{5,11,590},{9,11,213}, +{145,11,91},{135,10,1696},{10,0,138},{139,0,476},{5,0,725},{5,0,727},{135,0,1811 +},{4,0,979},{6,0,1821},{6,0,1838},{8,0,876},{8,0,883},{8,0,889},{8,0,893},{8,0, +895},{10,0,934},{12,0,720},{14,0,459},{148,0,123},{135,11,551},{4,0,38},{6,0,435 +},{7,0,307},{7,0,999},{7,0,1481},{7,0,1732},{7,0,1738},{8,0,371},{9,0,414},{11,0 +,316},{12,0,52},{13,0,420},{147,0,100},{135,0,1296},{132,10,712},{134,10,1629},{ +133,0,723},{134,0,651},{136,11,191},{9,11,791},{10,11,93},{11,11,301},{16,11,13} +,{17,11,23},{18,11,135},{19,11,12},{20,11,1},{20,11,12},{148,11,14},{136,11,503} +,{6,11,466},{135,11,671},{6,0,1200},{134,0,1330},{135,0,1255},{134,0,986},{5,0, +109},{6,0,1784},{7,0,1895},{12,0,296},{140,0,302},{135,11,983},{133,10,485},{134 +,0,660},{134,0,800},{4,10,285},{5,0,216},{5,0,294},{5,10,317},{6,0,591},{6,10, +301},{7,0,1879},{7,10,7},{8,10,153},{9,0,141},{9,0,270},{9,0,679},{10,0,159},{10 +,10,766},{11,0,197},{11,0,438},{11,10,468},{12,0,538},{12,0,559},{12,10,467},{13 +,10,143},{14,0,144},{14,0,167},{143,0,67},{136,0,945},{134,0,1090},{137,0,81},{ +12,11,468},{19,11,96},{148,11,24},{134,0,391},{138,11,241},{7,0,322},{136,0,249} +,{134,0,1412},{135,11,795},{5,0,632},{138,0,526},{136,10,819},{6,0,144},{7,0,948 +},{7,0,1042},{7,11,954},{8,0,235},{8,0,461},{9,0,453},{9,0,796},{10,0,354},{145, +0,77},{139,10,917},{6,0,940},{134,0,1228},{4,0,362},{7,0,52},{135,0,303},{6,11, +549},{8,11,34},{8,11,283},{9,11,165},{138,11,475},{7,11,370},{7,11,1007},{7,11, +1177},{135,11,1565},{5,11,652},{5,11,701},{135,11,449},{5,0,196},{6,0,486},{7,0, +212},{8,0,309},{136,0,346},{6,10,1719},{6,10,1735},{7,10,2016},{7,10,2020},{8,10 +,837},{137,10,852},{6,11,159},{6,11,364},{7,11,516},{7,11,1439},{137,11,518},{ +135,0,1912},{135,0,1290},{132,0,686},{141,11,151},{138,0,625},{136,0,706},{138, +10,568},{139,0,412},{4,0,30},{133,0,43},{8,10,67},{138,10,419},{7,0,967},{141,0, +11},{12,0,758},{14,0,441},{142,0,462},{10,10,657},{14,10,297},{142,10,361},{139, +10,729},{4,0,220},{135,0,1535},{7,11,501},{9,11,111},{10,11,141},{11,11,332},{13 +,11,43},{13,11,429},{14,11,130},{14,11,415},{145,11,102},{4,0,950},{6,0,1859},{7 +,0,11},{8,0,873},{12,0,710},{12,0,718},{12,0,748},{12,0,765},{148,0,124},{5,11, +149},{5,11,935},{136,11,233},{142,11,291},{134,0,1579},{7,0,890},{8,10,51},{9,10 +,868},{10,10,833},{12,10,481},{12,10,570},{148,10,106},{141,0,2},{132,10,445},{ +136,11,801},{135,0,1774},{7,0,1725},{138,0,393},{5,0,263},{134,0,414},{132,11, +322},{133,10,239},{7,0,456},{7,10,1990},{8,10,130},{139,10,720},{137,0,818},{5, +10,123},{6,10,530},{7,10,348},{135,10,1419},{135,10,2024},{6,0,178},{6,0,1750},{ +8,0,251},{9,0,690},{10,0,155},{10,0,196},{10,0,373},{11,0,698},{13,0,155},{148,0 +,93},{5,0,97},{137,0,393},{134,0,674},{11,0,223},{140,0,168},{132,10,210},{139, +11,464},{6,0,1639},{146,0,159},{139,11,2},{7,0,934},{8,0,647},{17,0,97},{19,0,59 +},{150,0,2},{132,0,191},{4,10,430},{5,0,165},{7,11,357},{9,0,346},{10,0,655},{ +139,0,885},{133,0,877},{5,10,213},{133,11,406},{8,0,128},{139,0,179},{6,11,69},{ +135,11,117},{135,0,1297},{11,11,43},{13,11,72},{141,11,142},{135,11,1830},{142,0 +,164},{5,0,57},{6,0,101},{6,0,586},{6,0,1663},{7,0,132},{7,0,1154},{7,0,1415},{7 +,0,1507},{12,0,493},{15,0,105},{151,0,15},{5,0,459},{7,0,1073},{8,0,241},{136,0, +334},{133,11,826},{133,10,108},{5,10,219},{10,11,132},{11,11,191},{11,11,358},{ +139,11,460},{6,0,324},{6,0,520},{7,0,338},{7,0,1729},{8,0,228},{139,0,750},{4,10 +,193},{5,10,916},{7,10,364},{10,10,398},{10,10,726},{11,10,317},{11,10,626},{12, +10,142},{12,10,288},{12,10,678},{13,10,313},{15,10,113},{18,10,114},{21,0,30},{ +150,0,53},{6,11,110},{135,11,1681},{135,0,910},{6,10,241},{7,10,907},{8,10,832}, +{9,10,342},{10,10,729},{11,10,284},{11,10,445},{11,10,651},{11,10,863},{13,10, +398},{146,10,99},{5,11,1000},{7,0,705},{7,11,733},{9,0,734},{137,11,583},{4,0,73 +},{6,0,612},{7,0,927},{7,0,1822},{8,0,217},{9,0,765},{9,0,766},{10,0,408},{11,0, +51},{11,0,793},{12,0,266},{15,0,158},{20,0,89},{150,0,32},{4,11,297},{6,11,529}, +{7,0,1330},{7,11,152},{7,11,713},{7,11,1845},{8,11,710},{8,11,717},{140,11,639}, +{5,0,389},{136,0,636},{134,0,1409},{4,10,562},{9,10,254},{139,10,879},{134,0,893 +},{132,10,786},{4,11,520},{135,11,575},{136,0,21},{140,0,721},{136,0,959},{7,11, +1428},{7,11,1640},{9,11,169},{9,11,182},{9,11,367},{9,11,478},{9,11,506},{9,11, +551},{9,11,648},{9,11,651},{9,11,697},{9,11,705},{9,11,725},{9,11,787},{9,11,794 +},{10,11,198},{10,11,214},{10,11,267},{10,11,275},{10,11,456},{10,11,551},{10,11 +,561},{10,11,613},{10,11,627},{10,11,668},{10,11,675},{10,11,691},{10,11,695},{ +10,11,707},{10,11,715},{11,11,183},{11,11,201},{11,11,244},{11,11,262},{11,11, +352},{11,11,439},{11,11,493},{11,11,572},{11,11,591},{11,11,608},{11,11,611},{11 +,11,646},{11,11,674},{11,11,711},{11,11,751},{11,11,761},{11,11,776},{11,11,785} +,{11,11,850},{11,11,853},{11,11,862},{11,11,865},{11,11,868},{11,11,898},{11,11, +902},{11,11,903},{11,11,910},{11,11,932},{11,11,942},{11,11,957},{11,11,967},{11 +,11,972},{12,11,148},{12,11,195},{12,11,220},{12,11,237},{12,11,318},{12,11,339} +,{12,11,393},{12,11,445},{12,11,450},{12,11,474},{12,11,509},{12,11,533},{12,11, +591},{12,11,594},{12,11,597},{12,11,621},{12,11,633},{12,11,642},{13,11,59},{13, +11,60},{13,11,145},{13,11,239},{13,11,250},{13,11,273},{13,11,329},{13,11,344},{ +13,11,365},{13,11,372},{13,11,387},{13,11,403},{13,11,414},{13,11,456},{13,11, +478},{13,11,483},{13,11,489},{14,11,55},{14,11,57},{14,11,81},{14,11,90},{14,11, +148},{14,11,239},{14,11,266},{14,11,321},{14,11,326},{14,11,327},{14,11,330},{14 +,11,347},{14,11,355},{14,11,401},{14,11,411},{14,11,414},{14,11,416},{14,11,420} +,{15,11,61},{15,11,74},{15,11,87},{15,11,88},{15,11,94},{15,11,96},{15,11,116},{ +15,11,149},{15,11,154},{16,11,50},{16,11,63},{16,11,73},{17,11,2},{17,11,66},{17 +,11,92},{17,11,103},{17,11,112},{18,11,50},{18,11,54},{18,11,82},{18,11,86},{18, +11,90},{18,11,111},{18,11,115},{18,11,156},{19,11,40},{19,11,79},{20,11,78},{149 +,11,22},{137,11,170},{134,0,1433},{135,11,1307},{139,11,411},{5,0,189},{7,0,442} +,{7,0,443},{8,0,281},{12,0,174},{141,0,261},{6,10,216},{7,10,901},{7,10,1343},{ +136,10,493},{5,11,397},{6,11,154},{7,10,341},{7,11,676},{8,11,443},{8,11,609},{9 +,11,24},{9,11,325},{10,11,35},{11,10,219},{11,11,535},{11,11,672},{11,11,1018},{ +12,11,637},{144,11,30},{6,0,2},{7,0,191},{7,0,446},{7,0,1262},{7,0,1737},{8,0,22 +},{8,0,270},{8,0,612},{9,0,4},{9,0,312},{9,0,436},{9,0,626},{10,0,216},{10,0,311 +},{10,0,521},{10,0,623},{11,0,72},{11,0,330},{11,0,455},{12,0,321},{12,0,504},{ +12,0,530},{12,0,543},{13,0,17},{13,0,156},{13,0,334},{14,0,131},{17,0,60},{148,0 +,64},{7,0,354},{10,0,410},{139,0,815},{139,10,130},{7,10,1734},{137,11,631},{10, +10,115},{11,10,420},{12,0,425},{13,10,404},{14,10,346},{15,0,112},{143,10,54},{6 +,0,60},{6,0,166},{7,0,374},{7,0,670},{7,0,1327},{8,0,411},{8,0,435},{9,0,653},{9 +,0,740},{10,0,385},{11,0,222},{11,0,324},{11,0,829},{140,0,611},{7,0,1611},{13,0 +,14},{15,0,44},{19,0,13},{148,0,76},{133,11,981},{4,11,56},{7,11,1791},{8,11,607 +},{8,11,651},{11,11,465},{11,11,835},{12,11,337},{141,11,480},{5,10,1011},{6,0, +1478},{136,10,701},{139,0,596},{5,0,206},{134,0,398},{4,10,54},{5,10,666},{7,10, +1039},{7,10,1130},{9,10,195},{138,10,302},{7,0,50},{9,11,158},{138,11,411},{135, +11,1120},{6,0,517},{6,10,1669},{7,0,1159},{10,0,621},{139,0,192},{4,0,592},{6,0, +600},{135,0,1653},{10,0,223},{139,0,645},{136,11,139},{7,0,64},{136,0,245},{142, +0,278},{6,11,622},{135,11,1030},{136,0,604},{134,0,1502},{138,0,265},{141,11,168 +},{7,0,1763},{140,0,310},{7,10,798},{139,11,719},{7,11,160},{10,11,624},{142,11, +279},{132,11,363},{7,10,122},{9,10,259},{10,10,84},{11,10,470},{12,10,541},{141, +10,379},{5,0,129},{6,0,61},{135,0,947},{134,0,1356},{135,11,1191},{13,0,505},{ +141,0,506},{5,10,82},{5,10,131},{7,10,1755},{8,10,31},{9,10,168},{9,10,764},{11, +0,1000},{139,10,869},{134,0,966},{134,10,605},{134,11,292},{5,11,177},{6,11,616} +,{7,11,827},{9,11,525},{138,11,656},{135,11,1486},{138,11,31},{5,10,278},{137,10 +,68},{4,10,163},{5,10,201},{5,10,307},{5,10,310},{6,10,335},{7,10,284},{136,10, +165},{6,0,839},{135,10,1660},{136,10,781},{6,10,33},{135,10,1244},{133,0,637},{4 +,11,161},{133,11,631},{137,0,590},{7,10,1953},{136,10,720},{5,0,280},{7,0,1226}, +{138,10,203},{134,0,1386},{5,0,281},{6,0,1026},{6,10,326},{7,10,677},{137,10,425 +},{7,11,1557},{135,11,1684},{135,0,1064},{9,11,469},{9,11,709},{12,11,512},{14, +11,65},{145,11,12},{134,0,917},{10,11,229},{11,11,73},{11,11,376},{139,11,433},{ +7,0,555},{7,10,1316},{7,10,1412},{7,10,1839},{9,0,192},{9,10,589},{11,10,241},{ +11,10,676},{11,10,811},{11,10,891},{12,10,140},{12,10,346},{12,10,479},{13,0,30} +,{13,0,49},{13,10,381},{14,10,188},{15,0,150},{16,0,76},{18,10,30},{148,0,52},{ +149,0,15},{6,0,1882},{6,0,1883},{6,0,1897},{9,0,945},{9,0,1014},{9,0,1020},{12,0 +,823},{12,0,842},{12,0,866},{12,0,934},{15,0,242},{146,0,208},{6,0,965},{134,0, +1499},{7,0,33},{7,0,120},{8,0,489},{9,0,319},{10,0,820},{11,0,1004},{12,0,379},{ +12,0,679},{13,0,117},{13,0,412},{14,0,25},{15,0,52},{15,0,161},{16,0,47},{149,0, +2},{6,11,558},{7,11,651},{8,11,421},{9,11,0},{138,11,34},{4,0,937},{5,0,801},{5, +10,358},{7,0,473},{7,10,1184},{10,10,662},{13,10,212},{13,10,304},{13,10,333},{ +145,10,98},{132,0,877},{6,0,693},{134,0,824},{132,0,365},{7,11,1832},{138,11,374 +},{5,0,7},{139,0,774},{4,0,734},{5,0,662},{134,0,430},{4,0,746},{135,0,1090},{5, +0,360},{8,0,237},{10,0,231},{147,0,124},{138,11,348},{6,11,6},{7,11,81},{7,11, +771},{7,11,1731},{9,11,405},{138,11,421},{6,0,740},{137,0,822},{133,10,946},{7,0 +,1485},{136,0,929},{7,10,411},{8,10,631},{9,10,323},{10,10,355},{11,10,491},{12, +10,143},{12,10,402},{13,10,73},{14,10,408},{15,10,107},{146,10,71},{135,10,590}, +{5,11,881},{133,11,885},{150,11,25},{4,0,852},{5,11,142},{134,11,546},{7,10,1467 +},{8,10,328},{10,10,544},{11,10,955},{13,10,320},{145,10,83},{9,0,17},{10,0,291} +,{11,10,511},{13,10,394},{14,10,298},{14,10,318},{146,10,103},{5,11,466},{11,11, +571},{12,11,198},{13,11,283},{14,11,186},{15,11,21},{143,11,103},{134,0,1001},{4 +,11,185},{5,11,257},{5,11,839},{5,11,936},{7,11,171},{9,11,399},{10,11,258},{10, +11,395},{10,11,734},{11,11,1014},{12,11,23},{13,11,350},{14,11,150},{147,11,6},{ +143,0,35},{132,0,831},{5,10,835},{134,10,483},{4,0,277},{5,0,608},{6,0,493},{7,0 +,457},{7,11,404},{7,11,1377},{7,11,1430},{7,11,2017},{8,11,149},{8,11,239},{8,11 +,512},{8,11,793},{8,11,818},{9,11,474},{9,11,595},{10,11,122},{10,11,565},{10,11 +,649},{10,11,783},{11,11,239},{11,11,295},{11,11,447},{11,11,528},{11,11,639},{ +11,11,800},{11,11,936},{12,0,384},{12,11,25},{12,11,73},{12,11,77},{12,11,157},{ +12,11,316},{12,11,390},{12,11,391},{12,11,394},{12,11,395},{12,11,478},{12,11, +503},{12,11,592},{12,11,680},{13,11,50},{13,11,53},{13,11,132},{13,11,198},{13, +11,275},{13,11,322},{13,11,415},{14,11,71},{14,11,257},{14,11,395},{15,11,71},{ +15,11,136},{17,11,123},{18,11,93},{147,11,58},{134,0,1351},{7,0,27},{135,0,316}, +{136,11,712},{136,0,984},{133,0,552},{137,0,264},{132,0,401},{6,0,710},{6,0,1111 +},{134,0,1343},{134,0,1211},{9,0,543},{10,0,524},{11,0,108},{11,0,653},{12,0,524 +},{13,0,123},{14,0,252},{16,0,18},{19,0,38},{20,0,26},{20,0,65},{21,0,3},{151,0, +11},{4,0,205},{5,0,623},{7,0,104},{8,0,519},{137,0,716},{132,10,677},{4,11,377}, +{152,11,13},{135,11,1673},{7,0,579},{9,0,41},{9,0,244},{9,0,669},{10,0,5},{11,0, +861},{11,0,951},{139,0,980},{132,0,717},{136,0,1011},{132,0,805},{4,11,180},{135 +,11,1906},{132,10,777},{132,10,331},{132,0,489},{4,11,491},{5,10,747},{134,0, +1024},{135,11,1182},{4,11,171},{138,11,234},{4,11,586},{7,11,1186},{138,11,631}, +{135,0,892},{135,11,336},{9,11,931},{10,11,334},{148,11,71},{137,0,473},{6,0,864 +},{11,11,926},{140,0,659},{7,0,819},{9,0,26},{9,0,392},{10,0,152},{10,0,226},{11 +,0,19},{12,0,276},{12,0,426},{12,0,589},{13,0,460},{15,0,97},{19,0,48},{148,0, +104},{135,0,51},{133,10,326},{4,10,691},{146,10,16},{9,0,130},{10,10,680},{10,10 +,793},{11,0,765},{141,10,357},{133,11,765},{6,10,32},{7,10,385},{7,10,757},{7,10 +,1916},{8,0,229},{8,10,94},{8,10,711},{9,10,541},{10,10,162},{10,10,795},{11,10, +989},{11,10,1010},{12,10,14},{142,10,308},{7,11,474},{137,11,578},{132,0,674},{ +132,0,770},{5,0,79},{7,0,1027},{7,0,1477},{139,0,52},{133,11,424},{134,0,1666},{ +6,0,409},{6,10,349},{6,10,1682},{7,10,1252},{8,10,112},{8,11,714},{9,10,435},{9, +10,668},{10,10,290},{10,10,319},{10,10,815},{11,10,180},{11,10,837},{12,10,240}, +{13,10,152},{13,10,219},{142,10,158},{5,0,789},{134,0,195},{4,0,251},{4,0,688},{ +7,0,513},{135,0,1284},{132,10,581},{9,11,420},{10,11,269},{10,11,285},{10,11,576 +},{11,11,397},{13,11,175},{145,11,90},{6,10,126},{7,10,573},{8,10,397},{142,10, +44},{132,11,429},{133,0,889},{4,0,160},{5,0,330},{7,0,1434},{136,0,174},{7,11,18 +},{7,11,699},{7,11,1966},{8,11,752},{9,11,273},{9,11,412},{9,11,703},{10,11,71}, +{10,11,427},{10,11,508},{146,11,97},{6,0,872},{134,0,899},{133,10,926},{134,0, +1126},{134,0,918},{4,11,53},{5,11,186},{135,11,752},{7,0,268},{136,0,569},{134,0 +,1224},{6,0,1361},{7,10,1232},{137,10,531},{8,11,575},{10,11,289},{139,11,319},{ +133,10,670},{132,11,675},{133,0,374},{135,10,1957},{133,0,731},{11,0,190},{11,11 +,190},{15,0,49},{143,11,49},{4,0,626},{5,0,506},{5,0,642},{6,0,425},{10,0,202},{ +139,0,141},{137,0,444},{7,10,242},{135,10,1942},{6,11,209},{8,11,468},{9,11,210} +,{11,11,36},{12,11,28},{12,11,630},{13,11,21},{13,11,349},{14,11,7},{145,11,13}, +{4,11,342},{135,11,1179},{5,10,834},{7,10,1202},{8,10,14},{9,10,481},{137,10,880 +},{4,11,928},{133,11,910},{4,11,318},{4,11,496},{7,11,856},{139,11,654},{136,0, +835},{7,0,1526},{138,10,465},{151,0,17},{135,0,477},{4,10,357},{6,10,172},{7,10, +143},{137,10,413},{6,0,1374},{138,0,994},{4,10,590},{146,0,76},{7,0,287},{8,0, +355},{9,0,293},{137,0,743},{134,0,1389},{7,11,915},{8,11,247},{147,11,0},{4,11, +202},{5,11,382},{6,11,454},{7,11,936},{7,11,1803},{8,11,758},{9,11,375},{9,11, +895},{10,11,743},{10,11,792},{11,11,978},{11,11,1012},{142,11,109},{5,0,384},{8, +0,455},{140,0,48},{132,11,390},{5,10,169},{7,10,333},{136,10,45},{5,0,264},{134, +0,184},{138,11,791},{133,11,717},{132,10,198},{6,11,445},{7,11,332},{137,11,909} +,{136,0,1001},{4,10,24},{5,10,140},{5,10,185},{7,10,1500},{11,10,565},{139,10, +838},{134,11,578},{5,0,633},{6,0,28},{135,0,1323},{132,0,851},{136,11,267},{7,0, +359},{8,0,243},{140,0,175},{4,10,334},{133,10,593},{141,11,87},{136,11,766},{10, +0,287},{10,11,287},{12,0,138},{140,11,138},{4,0,105},{132,0,740},{140,10,116},{ +134,0,857},{135,11,1841},{6,0,1402},{137,0,819},{132,11,584},{132,10,709},{133, +10,897},{5,0,224},{13,0,174},{146,0,52},{135,10,1840},{4,10,608},{133,10,497},{ +139,11,60},{4,0,758},{135,0,1649},{4,11,226},{4,11,326},{135,11,1770},{5,11,426} +,{8,11,30},{9,11,2},{11,11,549},{147,11,122},{135,10,2039},{6,10,540},{136,10, +136},{4,0,573},{4,10,897},{5,10,786},{136,0,655},{7,0,351},{139,0,128},{133,10, +999},{4,10,299},{135,10,1004},{133,0,918},{132,11,345},{4,11,385},{7,11,265},{ +135,11,587},{133,10,456},{136,10,180},{6,0,687},{134,0,1537},{4,11,347},{5,11, +423},{5,11,996},{135,11,1329},{132,10,755},{7,11,1259},{9,11,125},{11,11,65},{ +140,11,285},{5,11,136},{6,11,136},{136,11,644},{134,0,1525},{4,0,1009},{135,0, +1139},{139,10,338},{132,0,340},{135,10,1464},{8,0,847},{10,0,861},{10,0,876},{10 +,0,889},{10,0,922},{10,0,929},{10,0,933},{12,0,784},{140,0,791},{139,0,176},{9, +11,134},{10,11,2},{10,11,27},{10,11,333},{11,11,722},{143,11,1},{4,11,433},{133, +11,719},{5,0,985},{7,0,509},{7,0,529},{145,0,96},{132,0,615},{4,10,890},{5,10, +805},{5,10,819},{5,10,961},{6,10,396},{6,10,1631},{6,10,1678},{7,10,1967},{7,10, +2041},{9,10,630},{11,10,8},{11,10,1019},{12,10,176},{13,10,225},{14,10,292},{149 +,10,24},{135,0,1919},{134,0,1131},{144,11,21},{144,11,51},{135,10,1815},{4,0,247 +},{7,10,1505},{10,10,190},{10,10,634},{11,10,792},{12,10,358},{140,10,447},{5,10 +,0},{6,10,536},{7,10,604},{13,10,445},{145,10,126},{4,0,184},{5,0,390},{6,0,337} +,{7,0,23},{7,0,494},{7,0,618},{7,0,1456},{8,0,27},{8,0,599},{10,0,153},{139,0, +710},{6,10,232},{6,10,412},{7,10,1074},{8,10,9},{8,10,157},{8,10,786},{9,10,196} +,{9,10,352},{9,10,457},{10,10,337},{11,10,232},{11,10,877},{12,10,480},{140,10, +546},{7,10,958},{141,0,38},{4,10,382},{136,10,579},{4,10,212},{135,10,1206},{4, +11,555},{8,11,536},{138,11,288},{11,11,139},{139,11,171},{9,11,370},{138,11,90}, +{132,0,1015},{134,0,1088},{5,10,655},{135,11,977},{134,0,1585},{17,10,67},{147, +10,74},{10,0,227},{11,0,497},{11,0,709},{140,0,415},{6,0,360},{7,0,1664},{136,0, +478},{6,10,231},{7,0,95},{136,10,423},{140,11,65},{4,11,257},{135,11,2031},{135, +11,1768},{133,10,300},{139,11,211},{136,0,699},{6,10,237},{7,10,611},{8,10,100}, +{9,10,416},{11,10,335},{12,10,173},{146,10,101},{14,0,26},{146,0,150},{6,0,581}, +{135,0,1119},{135,10,1208},{132,0,739},{6,11,83},{6,11,1733},{135,11,1389},{137, +0,869},{4,0,67},{5,0,422},{7,0,1037},{7,0,1289},{7,0,1555},{9,0,741},{145,0,108} +,{133,10,199},{12,10,427},{146,10,38},{136,0,464},{142,0,42},{8,11,501},{9,11, +696},{138,0,96},{134,11,592},{4,0,512},{4,0,966},{5,0,342},{6,0,1855},{8,0,869}, +{8,0,875},{8,0,901},{144,0,26},{8,0,203},{11,0,823},{11,0,846},{12,0,482},{13,0, +277},{13,0,302},{13,0,464},{14,0,205},{142,0,221},{4,0,449},{133,0,718},{7,11, +1718},{9,11,95},{9,11,274},{10,11,279},{10,11,317},{10,11,420},{11,11,303},{11, +11,808},{12,11,134},{12,11,367},{13,11,149},{13,11,347},{14,11,349},{14,11,406}, +{18,11,22},{18,11,89},{18,11,122},{147,11,47},{133,11,26},{4,0,355},{6,0,311},{9 +,0,256},{138,0,404},{132,11,550},{6,10,312},{6,10,1715},{10,0,758},{10,10,584},{ +11,10,546},{11,10,692},{12,10,259},{12,10,295},{13,10,46},{141,10,154},{136,11, +822},{4,11,902},{5,0,827},{5,11,809},{6,11,122},{135,11,896},{5,0,64},{140,0,581 +},{4,0,442},{6,0,739},{7,0,1047},{7,0,1352},{7,0,1643},{7,11,1911},{9,11,449},{ +10,11,192},{138,11,740},{135,11,262},{132,10,588},{133,11,620},{4,11,34},{5,0, +977},{5,11,574},{6,0,288},{7,0,528},{7,11,279},{7,11,1624},{136,11,601},{4,10, +231},{5,10,61},{6,0,1375},{6,10,104},{7,10,729},{7,10,964},{7,10,1658},{140,10, +414},{6,10,263},{138,10,757},{132,10,320},{4,0,254},{5,11,332},{7,0,1309},{135, +11,1309},{6,11,261},{8,11,182},{139,11,943},{132,10,225},{6,0,12},{135,0,1219},{ +4,0,275},{6,11,1721},{12,0,376},{141,11,490},{4,11,933},{133,11,880},{4,10,405}, +{6,0,951},{6,0,1109},{6,0,1181},{7,0,154},{7,10,817},{14,10,58},{17,10,37},{146, +10,124},{5,10,974},{134,0,1520},{134,0,1753},{6,0,369},{6,0,502},{7,0,1036},{8,0 +,348},{9,0,452},{10,0,26},{11,0,224},{11,0,387},{11,0,772},{12,0,95},{12,0,629}, +{13,0,195},{13,0,207},{13,0,241},{14,0,260},{14,0,270},{143,0,140},{132,0,269},{ +5,0,480},{7,0,532},{7,0,1197},{7,0,1358},{8,0,291},{11,0,349},{142,0,396},{5,10, +235},{7,10,1239},{11,10,131},{140,10,370},{7,10,956},{7,10,1157},{7,10,1506},{7, +10,1606},{7,10,1615},{7,10,1619},{7,10,1736},{7,10,1775},{8,10,590},{9,10,324},{ +9,10,736},{9,10,774},{9,10,776},{9,10,784},{10,10,567},{10,10,708},{11,10,518},{ +11,10,613},{11,10,695},{11,10,716},{11,10,739},{11,10,770},{11,10,771},{11,10, +848},{11,10,857},{11,10,931},{11,10,947},{12,10,326},{12,10,387},{12,10,484},{12 +,10,528},{12,10,552},{12,10,613},{13,10,189},{13,10,256},{13,10,340},{13,10,432} +,{13,10,436},{13,10,440},{13,10,454},{14,10,174},{14,10,220},{14,10,284},{14,10, +390},{145,10,121},{8,11,598},{9,11,664},{138,11,441},{9,10,137},{138,10,221},{ +133,11,812},{148,0,15},{134,0,1341},{4,11,137},{6,0,1017},{7,11,1178},{135,11, +1520},{7,10,390},{138,10,140},{7,11,1260},{135,11,1790},{137,11,191},{135,10, +1144},{6,0,1810},{7,0,657},{8,0,886},{10,0,857},{14,0,440},{144,0,96},{6,11,1661 +},{7,11,1975},{7,11,2009},{7,11,2011},{136,0,533},{6,0,1453},{134,10,464},{132, +11,715},{5,10,407},{11,10,204},{11,10,243},{11,10,489},{12,10,293},{19,10,37},{ +20,10,73},{150,10,38},{133,11,703},{4,0,211},{5,10,325},{7,0,1483},{8,10,5},{8, +10,227},{9,10,105},{10,10,585},{140,10,614},{4,0,332},{5,0,335},{6,0,238},{7,0, +269},{7,0,811},{7,0,1797},{8,0,836},{9,0,507},{141,0,242},{5,11,89},{7,11,1915}, +{9,11,185},{9,11,235},{9,11,496},{10,11,64},{10,11,270},{10,11,403},{10,11,469}, +{10,11,529},{10,11,590},{11,11,140},{11,11,860},{13,11,1},{13,11,422},{14,11,341 +},{14,11,364},{17,11,93},{18,11,113},{19,11,97},{147,11,113},{133,11,695},{5,11, +6},{6,10,621},{6,11,183},{7,11,680},{7,11,978},{7,11,1013},{7,11,1055},{12,11, +230},{13,10,504},{13,11,172},{16,0,19},{146,11,29},{136,0,156},{133,0,1009},{6, +11,29},{139,11,63},{134,0,820},{134,10,218},{7,10,454},{7,10,782},{8,10,768},{ +140,10,686},{5,0,228},{6,0,203},{7,0,156},{8,0,347},{9,0,265},{15,11,8},{18,0,39 +},{18,11,39},{20,0,54},{20,11,54},{21,0,31},{21,11,31},{22,0,3},{22,11,3},{23,0, +0},{151,11,0},{7,0,1131},{135,0,1468},{144,10,0},{134,0,1276},{10,10,676},{140, +10,462},{132,11,311},{134,11,1740},{7,11,170},{8,11,90},{8,11,177},{8,11,415},{ +11,11,714},{142,11,281},{134,10,164},{6,0,1792},{138,0,849},{150,10,50},{5,0,291 +},{5,0,318},{7,0,765},{8,11,522},{9,0,389},{12,0,548},{142,11,328},{11,11,91},{ +13,11,129},{15,11,101},{145,11,125},{4,11,494},{6,11,74},{7,11,44},{7,11,407},{8 +,11,551},{12,11,17},{15,11,5},{148,11,11},{4,11,276},{133,11,296},{6,10,343},{7, +10,195},{7,11,1777},{9,10,226},{10,10,197},{10,10,575},{11,10,502},{139,10,899}, +{10,0,525},{139,0,82},{4,11,7},{5,11,90},{5,11,158},{6,11,542},{7,11,221},{7,11, +1574},{9,11,490},{10,11,540},{11,11,443},{11,11,757},{142,0,453},{135,0,666},{22 +,10,29},{150,11,29},{4,0,422},{147,10,8},{5,0,355},{145,0,0},{6,0,1873},{7,11, +588},{9,0,918},{9,11,175},{138,11,530},{143,11,31},{7,10,1125},{9,10,143},{11,0, +165},{14,10,405},{150,10,21},{9,0,260},{137,0,905},{5,11,872},{6,11,57},{6,11, +479},{6,11,562},{7,11,471},{7,11,1060},{9,11,447},{9,11,454},{141,11,6},{138,11, +704},{133,0,865},{5,0,914},{134,0,1625},{133,0,234},{5,11,31},{6,11,614},{7,0, +1383},{145,11,61},{7,11,1200},{138,11,460},{6,11,424},{135,11,1866},{136,0,306}, +{5,10,959},{12,11,30},{13,11,148},{14,11,87},{14,11,182},{16,11,42},{18,11,92},{ +148,11,70},{6,0,1919},{6,0,1921},{9,0,923},{9,0,930},{9,0,941},{9,0,949},{9,0, +987},{9,0,988},{9,0,992},{12,0,802},{12,0,815},{12,0,856},{12,0,885},{12,0,893}, +{12,0,898},{12,0,919},{12,0,920},{12,0,941},{12,0,947},{15,0,183},{15,0,185},{15 +,0,189},{15,0,197},{15,0,202},{15,0,233},{15,11,156},{18,0,218},{18,0,219},{146, +0,233},{135,10,1759},{136,10,173},{5,11,13},{6,11,142},{13,0,163},{13,0,180},{18 +,0,78},{148,0,35},{134,10,266},{6,11,97},{7,11,116},{8,11,322},{8,11,755},{9,11, +548},{10,11,714},{11,11,884},{141,11,324},{135,0,1312},{9,0,814},{137,11,676},{ +133,0,707},{135,0,1493},{6,0,421},{7,0,61},{7,0,1540},{10,0,11},{138,0,501},{7, +11,866},{7,11,1163},{12,0,733},{140,0,766},{137,0,341},{142,0,98},{145,11,115},{ +135,11,1111},{136,10,300},{136,0,1014},{8,11,1},{9,11,112},{138,11,326},{132,11, +730},{5,11,488},{6,11,527},{7,11,489},{7,11,1636},{8,11,121},{8,11,144},{8,11, +359},{9,11,193},{9,11,241},{9,11,336},{9,11,882},{11,11,266},{11,11,372},{11,11, +944},{12,11,401},{140,11,641},{6,0,971},{134,0,1121},{6,0,102},{7,0,72},{15,0, +142},{147,0,67},{151,0,30},{135,0,823},{134,0,1045},{5,10,427},{5,10,734},{7,10, +478},{136,10,52},{7,0,1930},{11,10,217},{142,10,165},{6,0,1512},{135,0,1870},{9, +11,31},{10,11,244},{10,11,699},{12,11,149},{141,11,497},{133,11,377},{145,11,101 +},{10,11,158},{13,11,13},{13,11,137},{13,11,258},{14,11,111},{14,11,225},{14,11, +253},{14,11,304},{14,11,339},{14,11,417},{146,11,33},{6,0,87},{6,10,1734},{7,10, +20},{7,10,1056},{8,10,732},{9,10,406},{9,10,911},{138,10,694},{134,0,1243},{137, +0,245},{7,0,68},{8,0,48},{8,0,88},{8,0,582},{8,0,681},{9,0,373},{9,0,864},{11,0, +157},{11,0,336},{11,0,843},{148,0,27},{8,11,663},{144,11,8},{133,10,613},{4,0,88 +},{5,0,137},{5,0,174},{5,0,777},{6,0,1664},{6,0,1725},{7,0,77},{7,0,426},{7,0, +1317},{7,0,1355},{8,0,126},{8,0,563},{9,0,523},{9,0,750},{10,0,310},{10,0,836},{ +11,0,42},{11,0,318},{11,0,731},{12,0,68},{12,0,92},{12,0,507},{12,0,692},{13,0, +81},{13,0,238},{13,0,374},{14,0,436},{18,0,138},{19,0,78},{19,0,111},{20,0,55},{ +20,0,77},{148,0,92},{141,0,418},{4,0,938},{137,0,625},{138,0,351},{5,11,843},{7, +10,32},{7,10,984},{8,10,85},{8,10,709},{9,10,579},{9,10,847},{9,10,856},{10,10, +799},{11,10,258},{11,10,1007},{12,10,331},{12,10,615},{13,10,188},{13,10,435},{ +14,10,8},{15,10,165},{16,10,27},{148,10,40},{6,0,1668},{7,0,1499},{8,0,117},{9,0 +,314},{138,0,174},{135,0,707},{132,11,554},{133,11,536},{5,0,403},{5,11,207},{9, +11,79},{11,11,625},{145,11,7},{132,11,424},{136,11,785},{4,10,167},{135,10,82},{ +9,0,7},{9,11,7},{23,0,6},{151,11,6},{5,10,62},{6,0,282},{6,10,534},{7,10,74},{7, +10,678},{7,10,684},{7,10,1043},{7,10,1072},{8,10,280},{8,10,541},{8,10,686},{9, +10,258},{10,10,519},{11,10,252},{140,10,282},{138,10,33},{132,10,359},{4,0,44},{ +5,0,311},{6,0,156},{7,0,639},{7,0,762},{7,0,1827},{9,0,8},{9,0,462},{148,0,83},{ +7,11,769},{9,11,18},{138,11,358},{4,0,346},{4,11,896},{6,11,1777},{7,0,115},{9,0 +,180},{9,0,456},{138,0,363},{133,10,211},{7,0,761},{7,0,1051},{137,0,545},{6,10, +145},{141,10,336},{7,11,750},{9,11,223},{11,11,27},{11,11,466},{12,11,624},{14, +11,265},{146,11,61},{6,0,752},{6,0,768},{6,0,1195},{6,0,1254},{6,0,1619},{137,0, +835},{6,0,1936},{8,0,930},{136,0,960},{132,10,263},{132,11,249},{4,10,916},{140, +0,653},{4,11,603},{133,11,661},{4,11,11},{6,11,128},{7,11,231},{7,11,1533},{8,0, +344},{138,11,725},{134,0,1483},{134,0,875},{6,0,185},{7,0,1899},{9,0,875},{139,0 +,673},{15,10,155},{144,10,79},{4,10,599},{6,10,1634},{7,0,93},{7,0,210},{7,0, +1223},{7,10,67},{7,10,691},{7,10,979},{7,10,1697},{8,0,451},{8,0,460},{8,10,207} +,{8,10,214},{8,10,231},{8,10,294},{8,10,336},{8,10,428},{8,10,471},{8,10,622},{8 +,10,626},{8,10,679},{8,10,759},{8,10,829},{9,10,11},{9,10,246},{9,10,484},{9,10, +573},{9,10,706},{9,10,762},{9,10,798},{9,10,855},{9,10,870},{9,10,912},{10,10, +303},{10,10,335},{10,10,424},{10,10,461},{10,10,543},{10,10,759},{10,10,814},{11 +,0,353},{11,0,475},{11,10,59},{11,10,235},{11,10,590},{11,10,929},{11,10,963},{ +11,10,987},{12,10,114},{12,10,182},{12,10,226},{12,10,332},{12,10,439},{12,10, +575},{12,10,598},{12,10,675},{13,10,8},{13,10,125},{13,10,194},{13,10,287},{14, +10,197},{14,10,383},{15,10,53},{17,10,63},{19,10,46},{19,10,98},{19,10,106},{148 +,10,85},{132,11,476},{4,0,327},{5,0,478},{7,0,1332},{136,0,753},{5,0,1020},{133, +0,1022},{135,11,1807},{4,0,103},{133,0,401},{4,0,499},{135,0,1421},{10,0,207},{ +13,0,164},{147,10,126},{9,11,20},{10,11,324},{139,11,488},{132,0,96},{9,11,280}, +{138,11,134},{135,0,968},{133,10,187},{135,10,1286},{5,11,112},{6,11,103},{134, +11,150},{4,10,215},{8,0,914},{9,10,38},{10,0,3},{11,10,23},{11,10,127},{139,10, +796},{135,0,399},{6,0,563},{137,0,224},{6,0,704},{134,0,1214},{4,11,708},{8,11, +15},{9,11,50},{9,11,386},{11,11,18},{11,11,529},{140,11,228},{4,11,563},{7,11, +109},{7,11,592},{7,11,637},{7,11,770},{7,11,1701},{8,11,436},{8,11,463},{9,11,60 +},{9,11,335},{9,11,904},{10,11,73},{11,11,434},{12,11,585},{13,11,331},{18,11, +110},{148,11,60},{134,0,1559},{132,11,502},{6,11,347},{138,11,161},{4,11,33},{5, +11,102},{5,11,500},{6,11,284},{7,11,1079},{7,11,1423},{7,11,1702},{8,11,470},{9, +11,554},{9,11,723},{139,11,333},{7,11,246},{135,11,840},{6,11,10},{8,11,571},{9, +11,739},{143,11,91},{5,11,626},{8,0,861},{10,0,905},{12,0,730},{140,0,789},{134, +0,946},{5,0,746},{12,0,333},{12,11,333},{14,0,332},{142,11,332},{5,11,18},{6,11, +526},{13,11,24},{13,11,110},{19,11,5},{147,11,44},{4,0,910},{5,0,832},{135,10, +2002},{10,11,768},{139,11,787},{4,11,309},{5,11,462},{7,11,970},{135,11,1097},{4 +,10,28},{5,10,440},{7,10,248},{11,10,833},{140,10,344},{134,10,1654},{6,0,632},{ +6,0,652},{6,0,1272},{6,0,1384},{134,0,1560},{134,11,1704},{5,10,853},{134,0,1393 +},{6,10,249},{7,10,1234},{139,10,573},{5,11,86},{7,11,743},{9,11,85},{10,11,281} +,{10,11,432},{11,11,490},{12,11,251},{13,11,118},{14,11,378},{146,11,143},{5,11, +524},{133,11,744},{134,0,1514},{10,0,201},{142,0,319},{7,0,717},{7,10,392},{8,10 +,20},{8,10,172},{8,10,690},{9,10,383},{9,10,845},{10,0,510},{11,10,293},{11,10, +832},{11,10,920},{11,10,984},{141,10,221},{134,0,1381},{5,10,858},{133,10,992},{ +8,0,528},{137,0,348},{10,11,107},{140,11,436},{4,0,20},{133,0,616},{134,0,1251}, +{132,11,927},{10,11,123},{12,11,670},{13,11,371},{14,11,142},{146,11,94},{134,0, +1163},{7,11,1149},{137,11,156},{134,0,307},{133,11,778},{7,0,1091},{135,0,1765}, +{5,11,502},{6,10,268},{137,10,62},{8,11,196},{10,11,283},{139,11,406},{4,0,26},{ +5,0,429},{6,0,245},{7,0,704},{7,0,1379},{135,0,1474},{133,11,855},{132,0,881},{4 +,0,621},{135,11,1596},{7,11,1400},{9,11,446},{138,11,45},{6,0,736},{138,10,106}, +{133,0,542},{134,0,348},{133,0,868},{136,0,433},{135,0,1495},{138,0,771},{6,10, +613},{136,10,223},{138,0,215},{141,0,124},{136,11,391},{135,11,172},{132,10,670} +,{140,0,55},{9,10,40},{139,10,136},{7,0,62},{147,0,112},{132,0,856},{132,11,568} +,{11,10,259},{140,0,270},{8,0,572},{137,0,698},{4,11,732},{9,10,310},{137,10,682 +},{142,10,296},{134,0,939},{136,11,733},{135,11,1435},{7,10,1401},{135,10,1476}, +{4,10,296},{6,0,352},{7,10,401},{7,10,1410},{7,10,1594},{7,10,1674},{8,10,63},{8 +,10,660},{137,10,74},{4,11,428},{133,11,668},{4,10,139},{4,10,388},{140,10,188}, +{7,11,2015},{140,11,665},{132,0,647},{146,0,10},{138,0,220},{142,0,464},{132,0, +109},{134,0,1746},{4,10,747},{6,0,515},{6,11,1623},{6,11,1681},{7,10,649},{7,10, +1479},{135,10,1583},{133,10,232},{135,0,566},{137,10,887},{4,0,40},{10,0,67},{11 +,0,117},{11,0,768},{139,0,935},{132,0,801},{7,0,992},{8,0,301},{9,0,722},{12,0, +63},{13,0,29},{14,0,161},{143,0,18},{139,0,923},{6,11,1748},{8,11,715},{9,11,802 +},{10,11,46},{10,11,819},{13,11,308},{14,11,351},{14,11,363},{146,11,67},{137,11 +,745},{4,10,14},{7,0,1145},{7,10,1801},{10,10,748},{141,10,458},{4,11,63},{5,11, +347},{134,11,474},{135,0,568},{4,10,425},{7,11,577},{7,11,1432},{9,11,475},{9,11 +,505},{9,11,526},{9,11,609},{9,11,689},{9,11,726},{9,11,735},{9,11,738},{10,11, +556},{10,11,674},{10,11,684},{11,11,89},{11,11,202},{11,11,272},{11,11,380},{11, +11,415},{11,11,505},{11,11,537},{11,11,550},{11,11,562},{11,11,640},{11,11,667}, +{11,11,688},{11,11,847},{11,11,927},{11,11,930},{11,11,940},{12,11,144},{12,11, +325},{12,11,329},{12,11,389},{12,11,403},{12,11,451},{12,11,515},{12,11,604},{12 +,11,616},{12,11,626},{13,11,66},{13,11,131},{13,11,167},{13,11,236},{13,11,368}, +{13,11,411},{13,11,434},{13,11,453},{13,11,461},{13,11,474},{14,11,59},{14,11,60 +},{14,11,139},{14,11,152},{14,11,276},{14,11,353},{14,11,402},{15,11,28},{15,11, +81},{15,11,123},{15,11,152},{18,11,136},{148,11,88},{137,0,247},{135,11,1622},{9 +,11,544},{11,11,413},{144,11,25},{4,0,645},{6,10,1768},{7,0,825},{135,11,89},{ +140,0,328},{5,10,943},{134,10,1779},{134,0,1363},{5,10,245},{6,10,576},{7,10,582 +},{136,10,225},{134,0,1280},{5,11,824},{133,11,941},{7,11,440},{8,11,230},{139, +11,106},{5,0,28},{6,0,204},{10,0,320},{10,0,583},{13,0,502},{14,0,72},{14,0,274} +,{14,0,312},{14,0,344},{15,0,159},{16,0,62},{16,0,69},{17,0,30},{18,0,42},{18,0, +53},{18,0,84},{18,0,140},{19,0,68},{19,0,85},{20,0,5},{20,0,45},{20,0,101},{22,0 +,7},{150,0,20},{4,0,558},{6,0,390},{7,0,162},{7,0,689},{9,0,360},{138,0,653},{ +134,0,764},{6,0,862},{137,0,833},{5,0,856},{6,0,1672},{6,0,1757},{134,0,1781},{5 +,0,92},{10,0,736},{140,0,102},{6,0,1927},{6,0,1944},{8,0,924},{8,0,948},{10,0, +967},{138,0,978},{134,0,1479},{5,0,590},{8,0,360},{9,0,213},{138,0,63},{134,0, +1521},{6,0,709},{134,0,891},{132,10,443},{13,0,477},{14,0,120},{148,0,61},{4,11, +914},{5,11,800},{133,11,852},{10,11,54},{141,11,115},{4,11,918},{133,11,876},{ +139,11,152},{4,11,92},{133,11,274},{135,11,1901},{9,11,800},{10,11,693},{11,11, +482},{11,11,734},{139,11,789},{4,10,298},{137,0,483},{6,0,1213},{141,11,498},{ +135,11,1451},{133,11,743},{4,0,1022},{10,0,1000},{12,0,957},{12,0,980},{12,0, +1013},{14,0,481},{144,0,116},{4,11,49},{7,11,280},{7,11,1633},{8,0,503},{145,0, +29},{135,0,1712},{134,0,466},{136,11,47},{5,10,164},{7,10,121},{142,10,189},{7, +10,812},{7,10,1261},{7,10,1360},{9,10,632},{140,10,352},{139,10,556},{132,0,731} +,{5,11,272},{5,11,908},{5,11,942},{7,11,1008},{7,11,1560},{8,11,197},{9,11,47},{ +11,11,538},{139,11,742},{4,10,172},{9,10,611},{10,10,436},{12,10,673},{141,10, +255},{133,10,844},{10,0,484},{11,0,754},{12,0,457},{14,0,171},{14,0,389},{146,0, +153},{9,10,263},{10,10,147},{138,10,492},{137,11,891},{138,0,241},{133,10,537},{ +6,0,2005},{136,0,964},{137,10,842},{151,11,8},{4,11,407},{132,11,560},{135,11, +1884},{6,0,1100},{134,0,1242},{135,0,954},{5,10,230},{5,10,392},{6,10,420},{9,10 +,568},{140,10,612},{4,11,475},{11,11,35},{11,11,90},{13,11,7},{13,11,71},{13,11, +177},{142,11,422},{136,11,332},{135,0,1958},{6,0,549},{8,0,34},{8,0,283},{9,0, +165},{138,0,475},{10,0,952},{12,0,966},{140,0,994},{5,0,652},{5,0,701},{135,0, +449},{4,0,655},{7,0,850},{17,0,75},{146,0,137},{4,0,146},{5,10,41},{7,0,1618},{7 +,10,1459},{7,10,1469},{7,10,1859},{8,0,670},{9,10,549},{139,10,905},{133,10,696} +,{6,0,159},{6,0,364},{7,0,516},{137,0,518},{135,0,1439},{6,11,222},{7,11,636},{7 +,11,1620},{8,11,409},{9,11,693},{139,11,77},{13,0,151},{141,11,45},{4,10,771},{4 +,11,336},{134,0,1027},{139,11,392},{10,11,121},{11,11,175},{149,11,16},{8,0,950} +,{138,0,983},{133,10,921},{135,0,993},{6,10,180},{7,10,1137},{8,10,751},{139,10, +805},{7,0,501},{9,0,111},{10,0,141},{11,0,332},{13,0,43},{13,0,429},{14,0,130},{ +14,0,415},{145,0,102},{4,10,183},{5,11,882},{7,10,271},{11,10,824},{11,10,952},{ +13,10,278},{13,10,339},{13,10,482},{14,10,424},{148,10,99},{4,10,19},{5,10,477}, +{5,10,596},{6,10,505},{7,10,1221},{11,10,907},{12,10,209},{141,10,214},{135,10, +1215},{133,0,452},{132,11,426},{5,0,149},{136,0,233},{133,0,935},{6,11,58},{7,11 +,654},{7,11,745},{7,11,1969},{8,11,240},{8,11,675},{9,11,479},{9,11,731},{10,11, +330},{10,11,593},{10,11,817},{11,11,32},{11,11,133},{11,11,221},{145,11,68},{7, +11,102},{9,11,538},{12,0,582},{146,0,131},{136,0,801},{134,10,1645},{132,0,70},{ +6,10,92},{6,10,188},{7,10,1269},{7,10,1524},{7,10,1876},{10,10,228},{139,10,1020 +},{4,10,459},{133,10,966},{138,0,369},{12,10,330},{144,0,36},{141,11,366},{6,10, +18},{7,0,721},{7,10,932},{8,10,757},{9,10,54},{9,10,65},{9,10,844},{10,0,236},{ +10,10,113},{10,10,315},{10,10,798},{11,10,153},{12,0,204},{12,10,151},{12,10,392 +},{12,10,666},{142,10,248},{7,0,241},{8,10,548},{9,10,532},{10,0,430},{10,10,117 +},{11,10,351},{11,10,375},{143,10,23},{134,10,1742},{133,10,965},{133,11,566},{6 +,11,48},{135,11,63},{134,10,182},{10,10,65},{10,10,488},{138,10,497},{6,11,114}, +{7,11,1224},{7,11,1556},{136,11,3},{134,0,1817},{8,11,576},{137,11,267},{6,0, +1078},{144,0,16},{9,10,588},{138,10,260},{138,0,1021},{5,0,406},{134,0,2022},{ +133,11,933},{6,0,69},{135,0,117},{7,0,1830},{136,11,427},{4,0,432},{135,0,824},{ +134,10,1786},{133,0,826},{139,11,67},{133,11,759},{135,10,308},{137,0,816},{133, +0,1000},{4,0,297},{6,0,529},{7,0,152},{7,0,713},{7,0,1845},{8,0,710},{8,0,717},{ +12,0,639},{140,0,685},{7,0,423},{136,10,588},{136,10,287},{136,0,510},{134,0, +1048},{6,0,618},{7,11,56},{7,11,1989},{8,11,337},{8,11,738},{9,11,600},{10,11, +483},{12,11,37},{13,11,447},{142,11,92},{4,0,520},{135,0,575},{8,0,990},{138,0, +977},{135,11,774},{9,11,347},{11,11,24},{140,11,170},{136,11,379},{140,10,290},{ +132,11,328},{4,0,321},{134,0,569},{4,11,101},{135,11,1171},{5,11,833},{7,0,723}, +{7,0,1135},{136,11,744},{7,10,719},{8,10,809},{136,10,834},{8,0,921},{136,10,796 +},{5,10,210},{6,10,213},{7,10,60},{10,10,364},{139,10,135},{5,0,397},{5,10,607}, +{6,0,154},{7,0,676},{8,0,443},{8,0,609},{8,10,326},{8,10,490},{9,0,24},{9,0,325} +,{10,0,35},{11,0,535},{11,0,672},{11,0,1018},{12,0,637},{144,0,30},{4,10,701},{5 +,10,472},{6,11,9},{6,11,397},{7,11,53},{7,11,1742},{9,10,758},{10,11,632},{11,11 +,828},{140,11,146},{135,10,380},{135,10,1947},{148,11,109},{10,10,278},{138,11, +278},{134,0,856},{4,10,386},{7,0,139},{8,10,405},{8,10,728},{9,10,497},{11,10, +110},{11,10,360},{15,10,37},{144,10,84},{141,0,282},{133,0,981},{5,0,288},{7,10, +1452},{7,10,1480},{8,10,634},{140,10,472},{7,0,1890},{8,11,367},{10,11,760},{14, +11,79},{20,11,17},{152,11,0},{4,10,524},{136,10,810},{4,0,56},{7,0,1791},{8,0, +607},{8,0,651},{11,0,465},{11,0,835},{12,0,337},{141,0,480},{10,10,238},{141,10, +33},{11,11,417},{12,11,223},{140,11,265},{9,0,158},{10,0,411},{140,0,261},{133, +10,532},{133,10,997},{12,11,186},{12,11,292},{14,11,100},{146,11,70},{6,0,1403}, +{136,0,617},{134,0,1205},{139,0,563},{4,0,242},{134,0,333},{4,11,186},{5,11,157} +,{8,11,168},{138,11,6},{132,0,369},{133,11,875},{5,10,782},{5,10,829},{134,10, +1738},{134,0,622},{135,11,1272},{6,0,1407},{7,11,111},{136,11,581},{7,10,1823},{ +139,10,693},{7,0,160},{10,0,624},{142,0,279},{132,0,363},{10,11,589},{12,11,111} +,{13,11,260},{14,11,82},{18,11,63},{147,11,45},{7,11,1364},{7,11,1907},{141,11, +158},{4,11,404},{4,11,659},{135,11,675},{13,11,211},{14,11,133},{14,11,204},{15, +11,64},{15,11,69},{15,11,114},{16,11,10},{19,11,23},{19,11,35},{19,11,39},{19,11 +,51},{19,11,71},{19,11,75},{152,11,15},{4,10,78},{5,10,96},{5,10,182},{7,10,1724 +},{7,10,1825},{10,10,394},{10,10,471},{11,10,532},{14,10,340},{145,10,88},{135, +10,1964},{133,11,391},{11,11,887},{14,11,365},{142,11,375},{5,11,540},{6,11,1697 +},{7,11,222},{136,11,341},{134,11,78},{9,0,601},{9,0,619},{10,0,505},{10,0,732}, +{11,0,355},{140,0,139},{134,0,292},{139,0,174},{5,0,177},{6,0,616},{7,0,827},{9, +0,525},{138,0,656},{6,10,215},{7,10,1028},{7,10,1473},{7,10,1721},{9,10,424},{10 +,0,31},{138,10,779},{135,10,584},{136,11,293},{134,0,685},{135,11,1868},{133,11, +460},{6,10,67},{7,0,647},{7,10,1630},{9,10,354},{9,10,675},{10,10,830},{14,10,80 +},{145,10,80},{4,0,161},{133,0,631},{6,10,141},{7,10,225},{9,10,59},{9,10,607},{ +10,10,312},{11,10,687},{12,10,555},{13,10,373},{13,10,494},{148,10,58},{7,11,965 +},{7,11,1460},{135,11,1604},{136,10,783},{134,11,388},{4,11,511},{6,0,722},{6,0, +1267},{9,11,333},{9,11,379},{10,11,602},{11,11,441},{11,11,723},{11,11,976},{140 +,11,357},{134,0,1797},{135,0,1684},{5,11,938},{8,11,707},{9,0,469},{9,0,709},{12 +,0,512},{14,0,65},{145,0,12},{7,0,1230},{136,0,531},{10,0,229},{11,0,73},{11,0, +376},{139,0,433},{12,0,268},{12,0,640},{142,0,119},{7,10,430},{139,10,46},{6,0, +558},{7,0,651},{8,0,421},{9,0,0},{10,0,34},{139,0,1008},{5,10,602},{6,0,106},{7, +0,1786},{7,0,1821},{7,10,2018},{9,0,102},{9,0,763},{137,10,418},{5,0,65},{6,0, +416},{7,0,1720},{7,0,1924},{8,10,677},{10,0,109},{11,0,14},{11,0,70},{11,0,569}, +{11,0,735},{15,0,153},{148,0,80},{135,11,1625},{137,11,772},{136,0,595},{6,11, +469},{7,11,1709},{138,11,515},{7,0,1832},{138,0,374},{9,0,106},{9,0,163},{9,0, +296},{10,0,167},{10,0,172},{10,0,777},{139,0,16},{6,0,6},{7,0,81},{7,0,771},{7,0 +,1731},{9,0,405},{138,0,421},{4,11,500},{135,11,938},{5,11,68},{134,11,383},{5,0 +,881},{133,0,885},{6,0,854},{6,0,1132},{6,0,1495},{6,0,1526},{6,0,1533},{134,0, +1577},{4,11,337},{6,11,353},{7,11,1934},{8,11,488},{137,11,429},{7,11,236},{7,11 +,1795},{8,11,259},{9,11,135},{9,11,177},{10,11,825},{11,11,115},{11,11,370},{11, +11,405},{11,11,604},{12,11,10},{12,11,667},{12,11,669},{13,11,76},{14,11,310},{ +15,11,76},{15,11,147},{148,11,23},{5,0,142},{134,0,546},{4,11,15},{5,11,22},{6, +11,244},{7,11,40},{7,11,200},{7,11,906},{7,11,1199},{9,11,616},{10,11,716},{11, +11,635},{11,11,801},{140,11,458},{5,0,466},{7,10,329},{11,0,571},{12,0,198},{13, +0,283},{14,0,186},{15,0,21},{143,0,103},{4,0,185},{5,0,257},{5,0,839},{5,0,936}, +{7,11,1735},{9,0,399},{10,0,258},{10,0,395},{10,0,734},{11,0,1014},{12,0,23},{13 +,0,350},{14,0,150},{147,0,6},{12,11,36},{141,11,337},{5,11,598},{7,11,791},{8,11 +,108},{137,11,123},{132,10,469},{7,0,404},{7,0,1377},{7,0,1430},{7,0,2017},{8,0, +149},{8,0,239},{8,0,512},{8,0,793},{8,0,818},{9,0,474},{9,0,595},{10,0,122},{10, +0,565},{10,0,649},{10,0,783},{11,0,239},{11,0,295},{11,0,447},{11,0,528},{11,0, +639},{11,0,800},{12,0,25},{12,0,77},{12,0,157},{12,0,256},{12,0,316},{12,0,390}, +{12,0,391},{12,0,395},{12,0,478},{12,0,503},{12,0,592},{12,0,680},{13,0,50},{13, +0,53},{13,0,132},{13,0,198},{13,0,322},{13,0,415},{13,0,511},{14,0,71},{14,0,395 +},{15,0,71},{15,0,136},{17,0,123},{18,0,93},{147,0,58},{136,0,712},{134,10,1743} +,{5,10,929},{6,10,340},{8,10,376},{136,10,807},{6,0,1848},{8,0,860},{10,0,856},{ +10,0,859},{10,0,925},{10,0,941},{140,0,762},{6,0,629},{6,0,906},{9,0,810},{140,0 +,652},{5,10,218},{7,10,1610},{138,10,83},{7,10,1512},{135,10,1794},{4,0,377},{4, +11,155},{7,11,1689},{11,10,0},{16,10,78},{152,0,13},{4,11,164},{5,11,151},{5,11, +730},{5,11,741},{7,11,498},{7,11,870},{7,11,1542},{12,11,213},{14,11,36},{14,11, +391},{17,11,111},{18,11,6},{18,11,46},{18,11,151},{19,11,36},{20,11,32},{20,11, +56},{20,11,69},{20,11,102},{21,11,4},{22,11,8},{22,11,10},{22,11,14},{150,11,31} +,{5,10,571},{135,0,1842},{4,10,455},{4,11,624},{135,11,1752},{134,0,1501},{4,11, +492},{5,11,451},{6,10,161},{7,10,372},{137,10,597},{132,10,349},{4,0,180},{135,0 +,1906},{135,11,835},{141,11,70},{132,0,491},{137,10,751},{6,10,432},{139,10,322} +,{4,0,171},{138,0,234},{6,11,113},{135,11,436},{4,0,586},{7,0,1186},{138,0,631}, +{5,10,468},{10,10,325},{11,10,856},{12,10,345},{143,10,104},{5,10,223},{10,11, +592},{10,11,753},{12,11,317},{12,11,355},{12,11,465},{12,11,469},{12,11,560},{12 +,11,578},{141,11,243},{132,10,566},{135,11,520},{4,10,59},{135,10,1394},{6,10, +436},{139,10,481},{4,10,48},{5,10,271},{7,10,953},{7,11,1878},{9,0,931},{10,0, +334},{148,0,71},{5,10,610},{8,10,457},{139,0,170},{133,10,755},{6,0,1587},{135, +10,1217},{4,10,197},{149,11,26},{133,11,585},{137,11,521},{133,0,765},{133,10, +217},{139,11,586},{133,0,424},{9,11,752},{12,11,610},{13,11,431},{16,11,59},{146 +,11,109},{136,0,714},{4,11,307},{135,0,685},{9,0,420},{10,0,269},{10,0,285},{10, +0,576},{11,0,397},{13,0,175},{145,0,90},{132,0,429},{133,11,964},{9,11,463},{138 +,11,595},{7,0,18},{7,0,699},{7,0,1966},{8,0,752},{9,0,273},{9,0,412},{9,0,703},{ +10,0,71},{10,0,427},{138,0,508},{4,10,165},{7,10,1398},{135,10,1829},{4,0,53},{5 +,0,186},{7,0,752},{7,0,828},{142,0,116},{8,0,575},{10,0,289},{139,0,319},{132,0, +675},{134,0,1424},{4,11,75},{5,11,180},{6,11,500},{7,11,58},{7,11,710},{138,11, +645},{133,11,649},{6,11,276},{7,11,282},{7,11,879},{7,11,924},{8,11,459},{9,11, +599},{9,11,754},{11,11,574},{12,11,128},{12,11,494},{13,11,52},{13,11,301},{15, +11,30},{143,11,132},{6,0,647},{134,0,1095},{5,10,9},{7,10,297},{7,10,966},{140, +10,306},{132,11,200},{134,0,1334},{5,10,146},{6,10,411},{138,10,721},{6,0,209},{ +6,0,1141},{6,0,1288},{8,0,468},{9,0,210},{11,0,36},{12,0,28},{12,0,630},{13,0,21 +},{13,0,349},{14,0,7},{145,0,13},{6,10,177},{135,10,467},{4,0,342},{135,0,1179}, +{10,11,454},{140,11,324},{4,0,928},{133,0,910},{6,11,225},{7,0,1838},{137,11,211 +},{16,0,101},{20,0,115},{20,0,118},{148,0,122},{4,0,496},{135,0,856},{4,0,318},{ +7,11,718},{11,0,654},{139,11,102},{8,11,58},{9,11,724},{11,11,809},{13,11,113},{ +145,11,72},{5,10,200},{6,11,345},{135,11,1247},{8,11,767},{8,11,803},{9,11,301}, +{137,11,903},{7,0,915},{7,11,1949},{8,0,247},{8,11,674},{147,0,0},{4,0,202},{5,0 +,382},{6,0,454},{7,0,936},{7,0,1803},{8,0,758},{9,0,375},{9,0,895},{10,0,743},{ +10,0,792},{11,0,978},{11,0,1012},{142,0,109},{7,0,1150},{7,0,1425},{7,0,1453},{ +140,0,513},{134,11,259},{138,0,791},{11,0,821},{12,0,110},{12,0,153},{18,0,41},{ +150,0,19},{134,10,481},{132,0,796},{6,0,445},{8,11,254},{137,0,909},{10,0,776},{ +13,0,345},{142,0,425},{4,10,84},{7,10,1482},{10,10,76},{138,10,142},{135,11,742} +,{5,10,1015},{134,0,578},{4,10,315},{5,10,507},{6,0,1387},{135,10,1370},{4,0,438 +},{133,0,555},{136,0,766},{133,11,248},{134,10,1722},{4,11,116},{5,11,95},{5,11, +445},{7,11,1688},{8,11,29},{9,11,272},{11,11,509},{139,11,915},{135,0,541},{133, +11,543},{8,10,222},{8,10,476},{9,10,238},{11,10,516},{11,10,575},{15,10,109},{ +146,10,100},{6,0,880},{134,0,1191},{5,11,181},{136,11,41},{134,0,1506},{132,11, +681},{7,11,25},{8,11,202},{138,11,536},{139,0,983},{137,0,768},{132,0,584},{9,11 +,423},{140,11,89},{8,11,113},{9,11,877},{10,11,554},{11,11,83},{12,11,136},{147, +11,109},{7,10,706},{7,10,1058},{138,10,538},{133,11,976},{4,11,206},{135,11,746} +,{136,11,526},{140,0,737},{11,10,92},{11,10,196},{11,10,409},{11,10,450},{11,10, +666},{11,10,777},{12,10,262},{13,10,385},{13,10,393},{15,10,115},{16,10,45},{145 +,10,82},{4,0,226},{4,0,326},{4,11,319},{5,11,699},{7,0,1770},{138,11,673},{6,10, +40},{135,10,1781},{5,0,426},{8,0,30},{9,0,2},{11,0,549},{147,0,122},{6,0,1161},{ +134,0,1329},{138,10,97},{6,10,423},{7,10,665},{135,10,1210},{7,11,13},{8,11,226} +,{10,11,537},{11,11,570},{11,11,605},{11,11,799},{11,11,804},{12,11,85},{12,11, +516},{12,11,623},{13,11,112},{13,11,361},{14,11,77},{14,11,78},{17,11,28},{147, +11,110},{132,11,769},{132,11,551},{132,11,728},{147,0,117},{9,11,57},{9,11,459}, +{10,11,425},{11,11,119},{12,11,184},{12,11,371},{13,11,358},{145,11,51},{5,11, +188},{5,11,814},{8,11,10},{9,11,421},{9,11,729},{10,11,609},{139,11,689},{134,11 +,624},{135,11,298},{135,0,462},{4,0,345},{139,10,624},{136,10,574},{4,0,385},{7, +0,265},{135,0,587},{4,11,528},{134,0,808},{133,0,398},{132,10,354},{4,0,347},{5, +0,423},{5,0,996},{135,0,1329},{135,10,1558},{7,0,1259},{9,0,125},{139,0,65},{5,0 +,136},{6,0,136},{136,0,644},{5,11,104},{6,11,173},{135,11,1631},{135,0,469},{133 +,10,830},{4,0,278},{5,0,465},{135,0,1367},{7,11,810},{8,11,138},{8,11,342},{9,11 +,84},{10,11,193},{11,11,883},{140,11,359},{5,10,496},{135,10,203},{4,0,433},{133 +,0,719},{6,10,547},{134,11,95},{5,10,88},{137,10,239},{6,11,406},{10,11,409},{10 +,11,447},{11,11,44},{140,11,100},{134,0,1423},{7,10,650},{135,10,1310},{134,0, +749},{135,11,1243},{135,0,1363},{6,0,381},{7,0,645},{7,0,694},{7,10,1076},{8,0, +546},{9,10,80},{11,10,78},{11,10,421},{11,10,534},{140,10,545},{134,11,1636},{ +135,11,1344},{7,10,274},{11,10,479},{11,10,507},{140,0,277},{4,11,282},{6,0,705} +,{6,0,783},{6,0,1275},{6,0,1481},{7,11,1034},{11,11,398},{11,11,634},{12,11,1},{ +12,11,79},{12,11,544},{14,11,237},{17,11,10},{146,11,20},{134,0,453},{4,0,555},{ +4,10,497},{7,10,1584},{8,0,536},{10,0,288},{139,0,1005},{5,11,118},{5,11,499},{6 +,11,476},{7,11,600},{7,11,888},{135,11,1096},{138,0,987},{7,0,1107},{7,10,261},{ +7,10,1115},{7,10,1354},{7,10,1588},{7,10,1705},{7,10,1902},{9,10,465},{10,10,248 +},{10,10,349},{10,10,647},{11,10,527},{11,10,660},{11,10,669},{12,10,529},{141, +10,305},{7,11,296},{7,11,596},{8,11,560},{8,11,586},{9,11,612},{11,11,100},{11, +11,304},{12,11,46},{13,11,89},{14,11,112},{145,11,122},{9,0,370},{138,0,90},{136 +,10,13},{132,0,860},{7,10,642},{8,10,250},{11,10,123},{11,10,137},{13,10,48},{ +142,10,95},{135,10,1429},{137,11,321},{132,0,257},{135,0,2031},{7,0,1768},{7,11, +1599},{7,11,1723},{8,11,79},{8,11,106},{8,11,190},{8,11,302},{8,11,383},{9,11, +119},{9,11,233},{9,11,298},{9,11,419},{9,11,471},{10,11,181},{10,11,406},{11,11, +57},{11,11,85},{11,11,120},{11,11,177},{11,11,296},{11,11,382},{11,11,454},{11, +11,758},{11,11,999},{12,11,27},{12,11,98},{12,11,131},{12,11,245},{12,11,312},{ +12,11,446},{12,11,454},{13,11,25},{13,11,98},{13,11,426},{13,11,508},{14,11,6},{ +14,11,163},{14,11,272},{14,11,277},{14,11,370},{15,11,95},{15,11,138},{15,11,167 +},{17,11,18},{17,11,38},{20,11,96},{149,11,32},{5,11,722},{134,11,1759},{145,11, +16},{6,0,1071},{134,0,1561},{10,10,545},{140,10,301},{6,0,83},{6,0,1733},{135,0, +1389},{4,0,835},{135,0,1818},{133,11,258},{4,10,904},{133,10,794},{134,0,2006},{ +5,11,30},{7,11,495},{8,11,134},{9,11,788},{140,11,438},{135,11,2004},{137,0,696} +,{5,11,50},{6,11,439},{7,11,780},{135,11,1040},{7,11,772},{7,11,1104},{7,11,1647 +},{11,11,269},{11,11,539},{11,11,607},{11,11,627},{11,11,706},{11,11,975},{12,11 +,248},{12,11,311},{12,11,434},{12,11,600},{12,11,622},{13,11,297},{13,11,367},{ +13,11,485},{14,11,69},{14,11,409},{143,11,108},{5,11,1},{6,11,81},{138,11,520},{ +7,0,1718},{9,0,95},{9,0,274},{10,0,279},{10,0,317},{10,0,420},{11,0,303},{11,0, +808},{12,0,134},{12,0,367},{13,0,149},{13,0,347},{14,0,349},{14,0,406},{18,0,22} +,{18,0,89},{18,0,122},{147,0,47},{5,11,482},{8,11,98},{9,11,172},{10,11,222},{10 +,11,700},{10,11,822},{11,11,302},{11,11,778},{12,11,50},{12,11,127},{12,11,396}, +{13,11,62},{13,11,328},{14,11,122},{147,11,72},{7,10,386},{138,10,713},{6,10,7}, +{6,10,35},{7,10,147},{7,10,1069},{7,10,1568},{7,10,1575},{7,10,1917},{8,10,43},{ +8,10,208},{9,10,128},{9,10,866},{10,10,20},{11,10,981},{147,10,33},{133,0,26},{ +132,0,550},{5,11,2},{7,11,1494},{136,11,589},{6,11,512},{7,11,797},{8,11,253},{9 +,11,77},{10,11,1},{10,11,129},{10,11,225},{11,11,118},{11,11,226},{11,11,251},{ +11,11,430},{11,11,701},{11,11,974},{11,11,982},{12,11,64},{12,11,260},{12,11,488 +},{140,11,690},{7,10,893},{141,10,424},{134,0,901},{136,0,822},{4,0,902},{5,0, +809},{134,0,122},{6,0,807},{134,0,1366},{5,11,748},{6,11,553},{135,0,262},{133,0 +,620},{4,0,34},{5,0,574},{7,0,279},{7,0,1624},{136,0,601},{6,10,322},{9,0,170},{ +9,10,552},{11,10,274},{13,10,209},{13,10,499},{14,10,85},{15,10,126},{145,10,70} +,{132,0,537},{4,11,12},{7,11,420},{7,11,522},{7,11,809},{8,11,797},{141,11,88},{ +133,0,332},{8,10,83},{8,10,742},{8,10,817},{9,10,28},{9,10,29},{9,10,885},{10,10 +,387},{11,10,633},{11,10,740},{13,10,235},{13,10,254},{15,10,143},{143,10,146},{ +6,0,1909},{9,0,964},{12,0,822},{12,0,854},{12,0,865},{12,0,910},{12,0,938},{15,0 +,169},{15,0,208},{15,0,211},{18,0,205},{18,0,206},{18,0,220},{18,0,223},{152,0, +24},{140,10,49},{5,11,528},{135,11,1580},{6,0,261},{8,0,182},{139,0,943},{134,0, +1721},{4,0,933},{133,0,880},{136,11,321},{5,11,266},{9,11,290},{9,11,364},{10,11 +,293},{11,11,606},{142,11,45},{4,11,50},{6,0,1609},{6,11,510},{6,11,594},{9,11, +121},{10,11,49},{10,11,412},{139,11,834},{7,0,895},{136,11,748},{132,11,466},{4, +10,110},{10,10,415},{10,10,597},{142,10,206},{133,0,812},{135,11,281},{6,0,1890} +,{6,0,1902},{6,0,1916},{7,10,205},{7,10,2000},{9,0,929},{9,0,942},{9,0,975},{9,0 +,984},{9,0,986},{9,0,1011},{9,0,1019},{12,0,804},{12,0,851},{12,0,867},{12,0,916 +},{12,0,923},{15,0,194},{15,0,204},{15,0,210},{15,0,222},{15,0,223},{15,0,229},{ +15,0,250},{18,0,179},{18,0,186},{146,0,192},{132,11,667},{135,0,778},{4,0,137},{ +7,0,1178},{135,0,1520},{134,0,1314},{4,11,242},{134,11,333},{6,0,1661},{7,0,1975 +},{7,0,2009},{135,0,2011},{134,0,1591},{4,10,283},{135,10,1194},{11,0,820},{150, +0,51},{4,11,39},{5,11,36},{7,11,1843},{8,11,407},{11,11,144},{140,11,523},{134, +10,1720},{4,11,510},{7,11,29},{7,11,66},{7,11,1980},{10,11,487},{10,11,809},{146 +,11,9},{5,0,89},{7,0,1915},{9,0,185},{9,0,235},{10,0,64},{10,0,270},{10,0,403},{ +10,0,469},{10,0,529},{10,0,590},{11,0,140},{11,0,860},{13,0,1},{13,0,422},{14,0, +341},{14,0,364},{17,0,93},{18,0,113},{19,0,97},{147,0,113},{133,0,695},{6,0,987} +,{134,0,1160},{5,0,6},{6,0,183},{7,0,680},{7,0,978},{7,0,1013},{7,0,1055},{12,0, +230},{13,0,172},{146,0,29},{134,11,570},{132,11,787},{134,11,518},{6,0,29},{139, +0,63},{132,11,516},{136,11,821},{132,0,311},{134,0,1740},{7,0,170},{8,0,90},{8,0 +,177},{8,0,415},{8,10,735},{11,0,714},{142,0,281},{134,0,1961},{135,11,1405},{4, +11,10},{7,11,917},{139,11,786},{5,10,132},{9,10,486},{9,10,715},{10,10,458},{11, +10,373},{11,10,668},{11,10,795},{11,10,897},{12,10,272},{12,10,424},{12,10,539}, +{12,10,558},{14,10,245},{14,10,263},{14,10,264},{14,10,393},{142,10,403},{11,0, +91},{13,0,129},{15,0,101},{145,0,125},{135,0,1132},{4,0,494},{6,0,74},{7,0,44},{ +7,0,407},{12,0,17},{15,0,5},{148,0,11},{133,10,379},{5,0,270},{5,11,684},{6,10, +89},{6,10,400},{7,10,1569},{7,10,1623},{7,10,1850},{8,10,218},{8,10,422},{9,10, +570},{138,10,626},{4,0,276},{133,0,296},{6,0,1523},{134,11,27},{6,10,387},{7,10, +882},{141,10,111},{6,10,224},{7,10,877},{137,10,647},{135,10,790},{4,0,7},{5,0, +90},{5,0,158},{6,0,542},{7,0,221},{7,0,1574},{9,0,490},{10,0,540},{11,0,443},{ +139,0,757},{7,0,588},{9,0,175},{138,0,530},{135,10,394},{142,11,23},{134,0,786}, +{135,0,580},{7,0,88},{136,0,627},{5,0,872},{6,0,57},{7,0,471},{9,0,447},{137,0, +454},{6,11,342},{6,11,496},{8,11,275},{137,11,206},{4,11,909},{133,11,940},{4,11 +,891},{134,0,735},{7,10,1409},{8,0,845},{136,0,916},{5,0,31},{134,0,614},{11,0, +458},{12,0,15},{140,0,432},{8,0,330},{140,0,477},{4,0,530},{4,11,687},{5,0,521}, +{7,0,1200},{138,0,460},{6,0,424},{135,0,1866},{9,0,569},{12,0,12},{12,0,81},{12, +0,319},{13,0,69},{14,0,259},{16,0,87},{17,0,1},{17,0,21},{17,0,24},{18,0,15},{18 +,0,56},{18,0,59},{18,0,127},{18,0,154},{19,0,19},{148,0,31},{7,0,1302},{136,10, +38},{134,11,253},{5,10,261},{7,10,78},{7,10,199},{8,10,815},{9,10,126},{138,10, +342},{5,0,595},{135,0,1863},{6,11,41},{141,11,160},{5,0,13},{134,0,142},{6,0,97} +,{7,0,116},{7,11,1304},{8,0,322},{8,0,755},{9,0,548},{10,0,714},{10,11,477},{11, +0,884},{141,0,324},{132,10,628},{134,11,1718},{7,10,266},{136,10,804},{135,10, +208},{6,10,79},{7,0,1021},{135,10,1519},{7,0,1472},{135,0,1554},{6,11,362},{146, +11,51},{7,0,1071},{7,0,1541},{7,0,1767},{7,0,1806},{11,0,162},{11,0,242},{11,0, +452},{12,0,605},{15,0,26},{144,0,44},{136,10,741},{133,11,115},{145,0,115},{134, +10,376},{6,0,1406},{134,0,1543},{5,11,193},{12,11,178},{13,11,130},{145,11,84},{ +135,0,1111},{5,11,705},{8,0,1},{9,0,650},{9,11,606},{138,0,326},{5,0,488},{6,0, +527},{7,0,489},{7,0,1636},{8,0,121},{8,0,144},{8,0,359},{9,0,193},{9,0,241},{9,0 +,336},{9,0,882},{11,0,266},{11,0,372},{11,0,944},{12,0,401},{140,0,641},{135,11, +174},{6,0,267},{7,10,244},{7,10,632},{7,10,1609},{8,10,178},{8,10,638},{141,10, +58},{134,0,1983},{134,0,1155},{134,0,1575},{134,0,1438},{9,0,31},{10,0,244},{10, +0,699},{12,0,149},{141,0,497},{133,0,377},{4,11,122},{5,11,796},{5,11,952},{6,11 +,1660},{6,11,1671},{8,11,567},{9,11,687},{9,11,742},{10,11,686},{11,11,356},{11, +11,682},{140,11,281},{145,0,101},{11,11,0},{144,11,78},{5,10,791},{5,11,179},{7, +11,1095},{135,11,1213},{8,11,372},{9,11,122},{138,11,175},{7,10,686},{8,10,33},{ +8,10,238},{10,10,616},{11,10,467},{11,10,881},{13,10,217},{13,10,253},{142,10, +268},{4,11,66},{7,11,722},{7,11,904},{137,0,476},{7,11,352},{137,11,684},{135,0, +2023},{135,0,1836},{132,10,447},{5,0,843},{144,0,35},{137,11,779},{141,11,35},{4 +,10,128},{5,10,415},{6,10,462},{7,10,294},{7,10,578},{10,10,710},{139,10,86},{ +132,0,554},{133,0,536},{136,10,587},{5,0,207},{9,0,79},{11,0,625},{145,0,7},{6, +10,427},{7,0,1371},{138,10,692},{4,0,424},{4,10,195},{135,10,802},{5,11,564},{ +136,0,785},{135,0,336},{4,0,896},{6,0,1777},{134,11,556},{137,11,103},{134,10, +1683},{7,11,544},{8,11,719},{138,11,61},{138,10,472},{4,11,5},{5,11,498},{136,11 +,637},{7,0,750},{9,0,223},{11,0,27},{11,0,466},{12,0,624},{14,0,265},{146,0,61}, +{12,0,238},{12,11,238},{18,0,155},{146,11,155},{151,10,28},{133,11,927},{5,10,3} +,{8,10,578},{9,10,118},{10,10,705},{12,0,383},{141,10,279},{4,11,893},{5,11,780} +,{133,11,893},{4,0,603},{133,0,661},{4,0,11},{5,10,229},{5,11,238},{6,0,128},{7, +0,231},{7,0,1533},{7,11,1350},{138,0,725},{8,10,102},{10,10,578},{10,10,672},{12 +,10,496},{13,10,408},{14,10,121},{145,10,106},{132,0,476},{134,0,1552},{134,11, +1729},{8,10,115},{8,10,350},{9,10,489},{10,10,128},{11,10,306},{12,10,373},{14, +10,30},{17,10,79},{19,10,80},{150,10,55},{135,0,1807},{4,0,680},{4,11,60},{7,11, +760},{7,11,1800},{8,11,314},{9,11,700},{139,11,487},{4,10,230},{5,10,702},{148, +11,94},{132,11,228},{139,0,435},{9,0,20},{10,0,324},{10,0,807},{139,0,488},{6,10 +,1728},{136,11,419},{4,10,484},{18,10,26},{19,10,42},{20,10,43},{21,10,0},{23,10 +,27},{152,10,14},{135,0,1431},{133,11,828},{5,0,112},{6,0,103},{6,0,150},{7,0, +1303},{7,11,176},{7,11,178},{7,11,1110},{9,0,292},{10,0,481},{10,11,481},{20,0, +13},{148,11,13},{138,0,356},{4,11,51},{5,11,39},{6,11,4},{7,11,591},{7,11,849},{ +7,11,951},{7,11,1129},{7,11,1613},{7,11,1760},{7,11,1988},{9,11,434},{10,11,754} +,{11,11,25},{11,11,37},{139,11,414},{6,0,1963},{134,0,2000},{132,10,633},{5,11, +902},{134,0,1244},{135,11,928},{140,0,18},{138,0,204},{135,11,1173},{134,0,867}, +{4,0,708},{8,0,15},{9,0,50},{9,0,386},{11,0,18},{11,0,529},{140,0,228},{134,11, +270},{4,0,563},{7,0,109},{7,0,592},{7,0,637},{7,0,770},{8,0,463},{9,0,60},{9,0, +335},{9,0,904},{10,0,73},{11,0,434},{12,0,585},{13,0,331},{18,0,110},{148,0,60}, +{132,0,502},{14,11,359},{19,11,52},{148,11,47},{6,11,377},{7,11,1025},{9,11,613} +,{145,11,104},{5,10,70},{5,10,622},{6,0,347},{6,10,334},{7,10,1032},{9,10,171},{ +10,0,161},{11,10,26},{11,10,213},{11,10,637},{11,10,707},{12,10,202},{12,10,380} +,{13,10,226},{13,10,355},{14,10,222},{145,10,42},{132,11,416},{4,0,33},{5,0,102} +,{6,0,284},{7,0,1079},{7,0,1423},{7,0,1702},{8,0,470},{9,0,554},{9,0,723},{11,0, +333},{142,11,372},{5,11,152},{5,11,197},{7,11,340},{7,11,867},{10,11,548},{10,11 +,581},{11,11,6},{12,11,3},{12,11,19},{14,11,110},{142,11,289},{7,0,246},{135,0, +840},{6,0,10},{8,0,571},{9,0,739},{143,0,91},{4,10,23},{4,10,141},{5,10,313},{5, +10,1014},{6,0,465},{6,10,50},{7,0,1465},{7,10,142},{7,10,559},{8,10,640},{9,10, +460},{9,10,783},{11,10,741},{12,10,183},{141,10,488},{133,0,626},{136,0,614},{ +138,0,237},{7,11,34},{7,11,190},{8,11,28},{8,11,141},{8,11,444},{8,11,811},{9,11 +,468},{11,11,334},{12,11,24},{12,11,386},{140,11,576},{133,11,757},{5,0,18},{6,0 +,526},{13,0,24},{13,0,110},{19,0,5},{147,0,44},{6,0,506},{134,11,506},{135,11, +1553},{4,0,309},{5,0,462},{7,0,970},{7,0,1097},{7,11,1385},{11,11,582},{11,11, +650},{11,11,901},{11,11,949},{12,11,232},{12,11,236},{13,11,413},{13,11,501},{18 +,11,116},{22,0,30},{150,0,33},{5,10,222},{9,0,140},{138,10,534},{6,0,1056},{137, +10,906},{134,0,1704},{138,10,503},{134,0,1036},{5,10,154},{7,10,1491},{10,10,379 +},{138,10,485},{4,11,383},{133,10,716},{134,0,1315},{5,0,86},{7,0,743},{9,0,85}, +{10,0,281},{10,0,432},{11,0,825},{12,0,251},{13,0,118},{142,0,378},{4,10,91},{5, +10,388},{5,10,845},{6,10,206},{6,10,252},{6,10,365},{7,10,136},{7,10,531},{8,0, +264},{136,10,621},{5,0,524},{133,0,744},{5,11,277},{141,11,247},{132,11,435},{10 +,0,107},{140,0,436},{132,0,927},{10,0,123},{12,0,670},{146,0,94},{7,0,1149},{9,0 +,156},{138,0,957},{5,11,265},{6,11,212},{135,11,28},{133,0,778},{133,0,502},{8,0 +,196},{10,0,283},{139,0,406},{135,10,576},{136,11,535},{134,0,1312},{5,10,771},{ +5,10,863},{5,10,898},{6,10,1632},{6,10,1644},{134,10,1780},{5,0,855},{5,10,331}, +{135,11,1487},{132,11,702},{5,11,808},{135,11,2045},{7,0,1400},{9,0,446},{138,0, +45},{140,10,632},{132,0,1003},{5,11,166},{8,11,739},{140,11,511},{5,10,107},{7, +10,201},{136,10,518},{6,10,446},{135,10,1817},{134,0,1532},{134,0,1097},{4,11, +119},{5,11,170},{5,11,447},{7,11,1708},{7,11,1889},{9,11,357},{9,11,719},{12,11, +486},{140,11,596},{9,10,851},{141,10,510},{4,10,504},{7,0,612},{8,0,545},{8,0, +568},{8,0,642},{9,0,717},{10,0,541},{10,0,763},{11,0,449},{12,0,489},{13,0,153}, +{13,0,296},{14,0,138},{14,0,392},{15,0,50},{16,0,6},{16,0,12},{148,0,9},{4,11, +450},{135,11,1158},{5,10,883},{5,10,975},{8,10,392},{11,0,54},{13,0,173},{13,0, +294},{148,10,7},{13,0,455},{15,0,99},{15,0,129},{144,0,68},{135,0,172},{132,11, +754},{5,10,922},{134,10,1707},{134,0,1029},{17,11,39},{148,11,36},{4,0,568},{5, +10,993},{7,10,515},{137,10,91},{132,0,732},{10,0,617},{138,11,617},{134,0,974},{ +7,0,989},{10,0,377},{12,0,363},{13,0,68},{13,0,94},{14,0,108},{142,0,306},{136,0 +,733},{132,0,428},{7,0,1789},{135,11,1062},{7,0,2015},{140,0,665},{135,10,1433}, +{5,0,287},{7,10,921},{8,10,580},{8,10,593},{8,10,630},{138,10,28},{138,0,806},{4 +,10,911},{5,10,867},{5,10,1013},{7,10,2034},{8,10,798},{136,10,813},{134,0,1539} +,{8,11,523},{150,11,34},{135,11,740},{7,11,238},{7,11,2033},{8,11,120},{8,11,188 +},{8,11,659},{9,11,598},{10,11,466},{12,11,342},{12,11,588},{13,11,503},{14,11, +246},{143,11,92},{7,0,1563},{141,0,182},{5,10,135},{6,10,519},{7,10,1722},{10,10 +,271},{11,10,261},{145,10,54},{14,10,338},{148,10,81},{4,10,300},{5,10,436},{135 +,0,484},{145,11,114},{6,0,1623},{134,0,1681},{133,11,640},{4,11,201},{7,11,1744} +,{8,11,602},{11,11,247},{11,11,826},{145,11,65},{8,11,164},{146,11,62},{6,0,1833 +},{6,0,1861},{136,0,878},{134,0,1569},{8,10,357},{10,10,745},{14,10,426},{17,10, +94},{147,10,57},{12,0,93},{12,0,501},{13,0,362},{14,0,151},{15,0,40},{15,0,59},{ +16,0,46},{17,0,25},{18,0,14},{18,0,134},{19,0,25},{19,0,69},{20,0,16},{20,0,19}, +{20,0,66},{21,0,23},{21,0,25},{150,0,42},{6,0,1748},{8,0,715},{9,0,802},{10,0,46 +},{10,0,819},{13,0,308},{14,0,351},{14,0,363},{146,0,67},{132,0,994},{4,0,63},{ +133,0,347},{132,0,591},{133,0,749},{7,11,1577},{10,11,304},{10,11,549},{11,11, +424},{12,11,365},{13,11,220},{13,11,240},{142,11,33},{133,0,366},{5,10,387},{7,0 +,557},{12,0,547},{142,0,86},{135,0,1747},{132,11,907},{5,11,100},{10,11,329},{12 +,11,416},{149,11,29},{4,10,6},{5,10,708},{136,10,75},{7,10,1351},{9,10,581},{10, +10,639},{11,10,453},{140,10,584},{4,10,303},{135,0,89},{138,10,772},{132,11,176} +,{5,11,636},{5,11,998},{8,11,26},{137,11,358},{7,11,9},{7,11,1508},{9,11,317},{ +10,11,210},{10,11,292},{10,11,533},{11,11,555},{12,11,526},{12,11,607},{13,11, +263},{13,11,459},{142,11,271},{134,0,1463},{6,0,772},{6,0,1137},{139,11,595},{7, +0,977},{139,11,66},{138,0,893},{20,0,48},{148,11,48},{5,0,824},{133,0,941},{134, +11,295},{4,10,106},{7,0,1543},{7,0,1785},{10,0,690},{139,10,717},{7,0,440},{8,0, +230},{139,0,106},{5,10,890},{133,10,988},{6,10,626},{142,10,431},{10,11,127},{ +141,11,27},{10,10,706},{17,0,32},{150,10,44},{132,0,216},{137,0,332},{4,10,698}, +{136,11,119},{139,11,267},{138,10,17},{11,11,526},{11,11,939},{141,11,290},{7,11 +,1167},{11,11,934},{13,11,391},{145,11,76},{139,11,39},{134,10,84},{4,0,914},{5, +0,800},{133,0,852},{10,0,416},{141,0,115},{7,0,564},{142,0,168},{4,0,918},{133,0 +,876},{134,0,1764},{152,0,3},{4,0,92},{5,0,274},{7,11,126},{136,11,84},{140,10, +498},{136,11,790},{5,10,986},{6,10,130},{7,10,1582},{8,0,501},{8,10,458},{10,10, +101},{10,10,318},{138,10,823},{6,11,64},{12,11,377},{141,11,309},{5,0,743},{138, +0,851},{4,0,49},{7,0,280},{135,0,1633},{134,0,879},{136,0,47},{7,10,1644},{137, +10,129},{132,0,865},{134,0,1202},{9,11,34},{139,11,484},{135,10,997},{5,0,272},{ +5,0,908},{5,0,942},{8,0,197},{9,0,47},{11,0,538},{139,0,742},{6,11,1700},{7,11, +26},{7,11,293},{7,11,382},{7,11,1026},{7,11,1087},{7,11,2027},{8,11,24},{8,11, +114},{8,11,252},{8,11,727},{8,11,729},{9,11,30},{9,11,199},{9,11,231},{9,11,251} +,{9,11,334},{9,11,361},{9,11,488},{9,11,712},{10,11,55},{10,11,60},{10,11,232},{ +10,11,332},{10,11,384},{10,11,396},{10,11,504},{10,11,542},{10,11,652},{11,11,20 +},{11,11,48},{11,11,207},{11,11,291},{11,11,298},{11,11,342},{11,11,365},{11,11, +394},{11,11,620},{11,11,705},{11,11,1017},{12,11,123},{12,11,340},{12,11,406},{ +12,11,643},{13,11,61},{13,11,269},{13,11,311},{13,11,319},{13,11,486},{14,11,234 +},{15,11,62},{15,11,85},{16,11,71},{18,11,119},{148,11,105},{6,0,1455},{150,11, +37},{135,10,1927},{135,0,1911},{137,0,891},{7,10,1756},{137,10,98},{7,10,1046},{ +139,10,160},{132,0,761},{6,11,379},{7,11,270},{7,11,1116},{8,11,176},{8,11,183}, +{9,11,432},{9,11,661},{12,11,247},{12,11,617},{146,11,125},{6,10,45},{7,10,433}, +{8,10,129},{9,10,21},{10,10,392},{11,10,79},{12,10,499},{13,10,199},{141,10,451} +,{4,0,407},{5,11,792},{133,11,900},{132,0,560},{135,0,183},{7,10,558},{8,10,353} +,{141,0,490},{4,0,475},{5,10,785},{6,0,731},{11,0,35},{13,0,71},{13,0,177},{142, +0,422},{8,10,81},{9,10,189},{9,10,201},{11,10,478},{11,10,712},{141,10,338},{4,0 +,418},{4,0,819},{133,10,353},{151,10,26},{4,11,901},{133,11,776},{132,0,575},{7, +0,818},{16,0,92},{17,0,14},{17,0,45},{18,0,75},{148,0,18},{6,0,222},{7,0,636},{7 +,0,1620},{8,0,409},{9,0,693},{139,0,77},{6,10,25},{7,10,855},{7,10,1258},{144,10 +,32},{6,0,1880},{6,0,1887},{6,0,1918},{6,0,1924},{9,0,967},{9,0,995},{9,0,1015}, +{12,0,826},{12,0,849},{12,0,857},{12,0,860},{12,0,886},{12,0,932},{18,0,228},{18 +,0,231},{146,0,240},{134,0,633},{134,0,1308},{4,11,37},{5,11,334},{135,11,1253}, +{4,10,4},{7,10,1118},{7,10,1320},{7,10,1706},{8,10,277},{9,10,622},{10,0,86},{11 +,10,724},{12,10,350},{12,10,397},{13,10,28},{13,10,159},{15,10,89},{18,10,5},{19 +,10,9},{20,10,34},{150,10,47},{132,11,508},{137,11,448},{12,11,107},{146,11,31}, +{132,0,817},{134,0,663},{133,0,882},{134,0,914},{132,11,540},{132,11,533},{136, +11,608},{8,0,885},{138,0,865},{132,0,426},{6,0,58},{7,0,745},{7,0,1969},{8,0,399 +},{8,0,675},{9,0,479},{9,0,731},{10,0,330},{10,0,593},{10,0,817},{11,0,32},{11,0 +,133},{11,0,221},{145,0,68},{134,10,255},{7,0,102},{137,0,538},{137,10,216},{7, +11,253},{136,11,549},{135,11,912},{9,10,183},{139,10,286},{11,10,956},{151,10,3} +,{8,11,527},{18,11,60},{147,11,24},{4,10,536},{7,10,1141},{10,10,723},{139,10, +371},{133,11,920},{7,0,876},{135,10,285},{135,10,560},{132,10,690},{142,11,126}, +{11,10,33},{12,10,571},{149,10,1},{133,0,566},{4,11,483},{9,0,139},{10,0,399},{ +11,0,469},{12,0,634},{141,0,223},{6,0,48},{135,0,63},{7,10,1862},{12,10,491},{12 +,10,520},{13,10,383},{14,10,244},{146,0,12},{135,11,1665},{132,11,448},{9,11,495 +},{146,11,104},{6,0,114},{7,0,1224},{7,0,1556},{136,0,3},{4,10,190},{133,10,554} +,{5,10,1001},{8,0,576},{137,0,267},{133,10,446},{133,0,933},{139,11,1009},{8,11, +653},{13,11,93},{147,11,14},{6,0,692},{6,0,821},{134,0,1077},{5,11,172},{135,11, +801},{138,0,752},{4,0,375},{134,0,638},{134,0,1011},{140,11,540},{5,11,260},{137 +,0,96},{139,11,587},{135,10,1231},{4,10,304},{12,0,30},{13,0,148},{14,0,87},{14, +0,182},{16,0,42},{148,0,70},{6,0,1398},{7,0,56},{7,0,1989},{8,0,337},{8,0,738},{ +9,0,600},{12,0,37},{13,0,447},{142,0,92},{138,0,666},{5,0,394},{7,0,487},{136,0, +246},{6,10,53},{6,10,199},{7,10,1408},{8,10,32},{8,10,93},{9,0,437},{10,10,397}, +{10,10,629},{11,10,593},{11,10,763},{13,10,326},{145,10,35},{134,10,105},{9,0, +320},{10,0,506},{138,10,794},{7,11,57},{8,11,167},{8,11,375},{9,11,82},{9,11,561 +},{10,11,620},{10,11,770},{11,10,704},{141,10,396},{5,10,114},{5,10,255},{6,0, +1003},{141,10,285},{7,0,866},{135,0,1163},{133,11,531},{132,0,328},{7,10,2035},{ +8,10,19},{9,10,89},{138,10,831},{8,11,194},{136,11,756},{136,0,1000},{5,11,453}, +{134,11,441},{4,0,101},{5,0,833},{7,0,1171},{136,0,744},{133,0,726},{136,10,746} +,{138,0,176},{6,0,9},{6,0,397},{7,0,53},{7,0,1742},{10,0,632},{11,0,828},{140,0, +146},{135,11,22},{145,11,64},{132,0,839},{11,0,417},{12,0,223},{140,0,265},{4,11 +,102},{7,11,815},{7,11,1699},{139,11,964},{5,10,955},{136,10,814},{6,0,1931},{6, +0,2007},{18,0,246},{146,0,247},{8,0,198},{11,0,29},{140,0,534},{135,0,1771},{6,0 +,846},{7,11,1010},{11,11,733},{11,11,759},{12,11,563},{13,11,34},{14,11,101},{18 +,11,45},{146,11,129},{4,0,186},{5,0,157},{8,0,168},{138,0,6},{132,11,899},{133, +10,56},{148,10,100},{133,0,875},{5,0,773},{5,0,991},{6,0,1635},{134,0,1788},{6,0 +,1274},{9,0,477},{141,0,78},{4,0,639},{6,11,52},{7,0,111},{8,0,581},{9,11,104},{ +9,11,559},{10,10,4},{10,10,13},{11,10,638},{12,0,177},{12,11,308},{19,11,87},{ +148,10,57},{132,11,604},{4,11,301},{133,10,738},{133,10,758},{134,0,1747},{7,11, +1440},{11,11,854},{11,11,872},{11,11,921},{12,11,551},{13,11,472},{142,11,367},{ +7,0,1364},{7,0,1907},{141,0,158},{134,0,873},{4,0,404},{4,0,659},{7,0,552},{135, +0,675},{135,10,1112},{139,10,328},{7,11,508},{137,10,133},{133,0,391},{5,10,110} +,{6,10,169},{6,10,1702},{7,10,400},{8,10,538},{9,10,184},{9,10,524},{140,10,218} +,{6,11,310},{7,11,1849},{8,11,72},{8,11,272},{8,11,431},{9,11,12},{9,11,351},{10 +,11,563},{10,11,630},{10,11,810},{11,11,367},{11,11,599},{11,11,686},{140,11,672 +},{5,0,540},{6,0,1697},{136,0,668},{132,0,883},{134,0,78},{6,10,133},{9,10,353}, +{11,10,993},{12,0,628},{146,0,79},{6,11,181},{7,11,537},{8,11,64},{9,11,127},{10 +,11,496},{12,11,510},{141,11,384},{6,10,93},{7,10,1422},{7,10,1851},{8,10,673},{ +9,10,529},{140,10,43},{137,10,371},{134,0,1460},{134,0,962},{4,11,244},{135,11, +233},{9,10,25},{10,10,467},{138,10,559},{4,10,335},{135,10,942},{133,0,460},{135 +,11,334},{134,11,1650},{4,0,199},{139,0,34},{5,10,601},{8,10,39},{10,10,773},{11 +,10,84},{12,10,205},{142,10,1},{133,10,870},{134,0,388},{14,0,474},{148,0,120},{ +133,11,369},{139,0,271},{4,0,511},{4,10,181},{9,0,333},{9,0,379},{10,0,602},{11, +0,441},{11,0,723},{11,0,976},{140,0,357},{134,0,608},{134,10,1652},{9,11,338},{ +150,0,49},{140,0,988},{134,0,617},{5,0,938},{136,0,707},{132,10,97},{5,10,147},{ +6,10,286},{7,10,1362},{141,10,176},{6,0,756},{134,0,1149},{133,11,896},{6,10,375 +},{7,10,169},{7,10,254},{136,10,780},{134,0,1583},{135,10,1447},{139,0,285},{7, +11,1117},{8,11,393},{136,11,539},{135,0,344},{6,0,469},{7,0,1709},{138,0,515},{5 +,10,629},{135,10,1549},{5,11,4},{5,11,810},{6,11,13},{6,11,538},{6,11,1690},{6, +11,1726},{7,11,499},{7,11,1819},{8,11,148},{8,11,696},{8,11,791},{12,11,125},{13 +,11,54},{143,11,9},{135,11,1268},{137,0,404},{132,0,500},{5,0,68},{134,0,383},{ +11,0,216},{139,0,340},{4,11,925},{5,11,803},{8,11,698},{138,11,828},{4,0,337},{6 +,0,353},{7,0,1934},{8,0,488},{137,0,429},{7,0,236},{7,0,1795},{8,0,259},{9,0,135 +},{9,0,177},{9,0,860},{10,0,825},{11,0,115},{11,0,370},{11,0,405},{11,0,604},{12 +,0,10},{12,0,667},{12,0,669},{13,0,76},{14,0,310},{15,0,76},{15,0,147},{148,0,23 +},{4,0,15},{4,0,490},{5,0,22},{6,0,244},{7,0,40},{7,0,200},{7,0,906},{7,0,1199}, +{9,0,616},{10,0,716},{11,0,635},{11,0,801},{140,0,458},{4,10,420},{140,0,756},{ +134,0,1504},{5,11,383},{134,0,757},{6,0,1266},{135,0,1735},{5,0,598},{7,0,791},{ +7,10,1570},{8,0,108},{9,0,123},{140,10,542},{142,11,410},{9,11,660},{138,11,347} +}; diff --git a/packages/runtime/vendor/brotli/c/enc/static_init.c b/packages/runtime/vendor/brotli/c/enc/static_init.c new file mode 100644 index 000000000..c0dff3a3a --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/static_init.c @@ -0,0 +1,59 @@ +/* Copyright 2025 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +#include "static_init.h" + +#include "../common/platform.h" +#include "../common/static_init.h" + +#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE) +#include "../common/dictionary.h" +#include "dictionary_hash.h" +#include "static_dict_lut.h" +#endif + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#if (BROTLI_STATIC_INIT != BROTLI_STATIC_INIT_NONE) +static BROTLI_BOOL DoBrotliEncoderStaticInit(void) { + const BrotliDictionary* dict = BrotliGetDictionary(); + BROTLI_BOOL ok = BrotliEncoderInitStaticDictionaryLut( + dict, kStaticDictionaryBuckets, kStaticDictionaryWords); + if (!ok) return BROTLI_FALSE; + ok = BrotliEncoderInitDictionaryHash(dict, kStaticDictionaryHashWords, + kStaticDictionaryHashLengths); + if (!ok) return BROTLI_FALSE; + return BROTLI_TRUE; +} +#endif /* BROTLI_STATIC_INIT_NONE */ + +#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_EARLY) +static BROTLI_BOOL kEarlyInitOk; +static __attribute__((constructor)) void BrotliEncoderStaticInitEarly(void) { + kEarlyInitOk = DoBrotliEncoderStaticInit(); +} +#elif (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_LAZY) +static BROTLI_BOOL kLazyInitOk; +void BrotliEncoderLazyStaticInitInner(void) { + kLazyInitOk = DoBrotliEncoderStaticInit(); +} +#endif /* BROTLI_STATIC_INIT_EARLY */ + +BROTLI_BOOL BrotliEncoderEnsureStaticInit(void) { +#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_NONE) + return BROTLI_TRUE; +#elif (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_EARLY) + return kEarlyInitOk; +#else + return kLazyInitOk; +#endif +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/static_init.h b/packages/runtime/vendor/brotli/c/enc/static_init.h new file mode 100644 index 000000000..e5cb23916 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/static_init.h @@ -0,0 +1,30 @@ +/* Copyright 2025 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Central point for static initialization. */ + +#ifndef THIRD_PARTY_BROTLI_ENC_STATIC_INIT_H_ +#define THIRD_PARTY_BROTLI_ENC_STATIC_INIT_H_ + +#include "../common/platform.h" +#include "../common/static_init.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#if (BROTLI_STATIC_INIT == BROTLI_STATIC_INIT_LAZY) +BROTLI_INTERNAL void BrotliEncoderLazyStaticInitInner(void); +BROTLI_INTERNAL void BrotliEncoderLazyStaticInit(void); +#endif /* BROTLI_STATIC_INIT */ + +BROTLI_INTERNAL BROTLI_BOOL BrotliEncoderEnsureStaticInit(void); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif // THIRD_PARTY_BROTLI_ENC_STATIC_INIT_H_ diff --git a/packages/runtime/vendor/brotli/c/enc/utf8_util.c b/packages/runtime/vendor/brotli/c/enc/utf8_util.c new file mode 100644 index 000000000..d46c3644e --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/utf8_util.c @@ -0,0 +1,85 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Heuristics for deciding about the UTF8-ness of strings. */ + +#include "utf8_util.h" + +#include "../common/platform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +static size_t BrotliParseAsUTF8( + int* symbol, const uint8_t* input, size_t size) { + /* ASCII */ + if ((input[0] & 0x80) == 0) { + *symbol = input[0]; + if (*symbol > 0) { + return 1; + } + } + /* 2-byte UTF8 */ + if (size > 1u && + (input[0] & 0xE0) == 0xC0 && + (input[1] & 0xC0) == 0x80) { + *symbol = (((input[0] & 0x1F) << 6) | + (input[1] & 0x3F)); + if (*symbol > 0x7F) { + return 2; + } + } + /* 3-byte UFT8 */ + if (size > 2u && + (input[0] & 0xF0) == 0xE0 && + (input[1] & 0xC0) == 0x80 && + (input[2] & 0xC0) == 0x80) { + *symbol = (((input[0] & 0x0F) << 12) | + ((input[1] & 0x3F) << 6) | + (input[2] & 0x3F)); + if (*symbol > 0x7FF) { + return 3; + } + } + /* 4-byte UFT8 */ + if (size > 3u && + (input[0] & 0xF8) == 0xF0 && + (input[1] & 0xC0) == 0x80 && + (input[2] & 0xC0) == 0x80 && + (input[3] & 0xC0) == 0x80) { + *symbol = (((input[0] & 0x07) << 18) | + ((input[1] & 0x3F) << 12) | + ((input[2] & 0x3F) << 6) | + (input[3] & 0x3F)); + if (*symbol > 0xFFFF && *symbol <= 0x10FFFF) { + return 4; + } + } + /* Not UTF8, emit a special symbol above the UTF8-code space */ + *symbol = 0x110000 | input[0]; + return 1; +} + +/* Returns 1 if at least min_fraction of the data is UTF8-encoded.*/ +BROTLI_BOOL BrotliIsMostlyUTF8( + const uint8_t* data, const size_t pos, const size_t mask, + const size_t length, const double min_fraction) { + size_t size_utf8 = 0; + size_t i = 0; + while (i < length) { + int symbol; + size_t bytes_read = + BrotliParseAsUTF8(&symbol, &data[(pos + i) & mask], length - i); + i += bytes_read; + if (symbol < 0x110000) size_utf8 += bytes_read; + } + return TO_BROTLI_BOOL((double)size_utf8 > min_fraction * (double)length); +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif diff --git a/packages/runtime/vendor/brotli/c/enc/utf8_util.h b/packages/runtime/vendor/brotli/c/enc/utf8_util.h new file mode 100644 index 000000000..cae3dba7a --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/utf8_util.h @@ -0,0 +1,31 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Heuristics for deciding about the UTF8-ness of strings. */ + +#ifndef BROTLI_ENC_UTF8_UTIL_H_ +#define BROTLI_ENC_UTF8_UTIL_H_ + +#include "../common/platform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +static const double kMinUTF8Ratio = 0.75; + +/* Returns 1 if at least min_fraction of the bytes between pos and + pos + length in the (data, mask) ring-buffer is UTF8-encoded, otherwise + returns 0. */ +BROTLI_INTERNAL BROTLI_BOOL BrotliIsMostlyUTF8( + const uint8_t* data, const size_t pos, const size_t mask, + const size_t length, const double min_fraction); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_UTF8_UTIL_H_ */ diff --git a/packages/runtime/vendor/brotli/c/enc/write_bits.h b/packages/runtime/vendor/brotli/c/enc/write_bits.h new file mode 100644 index 000000000..0cdc3372b --- /dev/null +++ b/packages/runtime/vendor/brotli/c/enc/write_bits.h @@ -0,0 +1,86 @@ +/* Copyright 2010 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Write bits into a byte array. */ + +#ifndef BROTLI_ENC_WRITE_BITS_H_ +#define BROTLI_ENC_WRITE_BITS_H_ + +#include "../common/platform.h" + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/* This function writes bits into bytes in increasing addresses, and within + a byte least-significant-bit first. + + The function can write up to 56 bits in one go with WriteBits + Example: let's assume that 3 bits (Rs below) have been written already: + + BYTE-0 BYTE+1 BYTE+2 + + 0000 0RRR 0000 0000 0000 0000 + + Now, we could write 5 or less bits in MSB by just shifting by 3 + and OR'ing to BYTE-0. + + For n bits, we take the last 5 bits, OR that with high bits in BYTE-0, + and locate the rest in BYTE+1, BYTE+2, etc. */ +static BROTLI_INLINE void BrotliWriteBits(size_t n_bits, + uint64_t bits, + size_t* BROTLI_RESTRICT pos, + uint8_t* BROTLI_RESTRICT array) { + BROTLI_LOG(("WriteBits %2d 0x%08x%08x %10d\n", (int)n_bits, + (uint32_t)(bits >> 32), (uint32_t)(bits & 0xFFFFFFFF), + (int)*pos)); + BROTLI_DCHECK((bits >> n_bits) == 0); + BROTLI_DCHECK(n_bits <= 56); +#if defined(BROTLI_LITTLE_ENDIAN) + /* This branch of the code can write up to 56 bits at a time, + 7 bits are lost by being perhaps already in *p and at least + 1 bit is needed to initialize the bit-stream ahead (i.e. if 7 + bits are in *p and we write 57 bits, then the next write will + access a byte that was never initialized). */ + { + uint8_t* p = &array[*pos >> 3]; + uint64_t v = (uint64_t)(*p); /* Zero-extend 8 to 64 bits. */ + v |= bits << (*pos & 7); + BROTLI_UNALIGNED_STORE64LE(p, v); /* Set some bits. */ + *pos += n_bits; + } +#else + /* implicit & 0xFF is assumed for uint8_t arithmetics */ + { + uint8_t* array_pos = &array[*pos >> 3]; + const size_t bits_reserved_in_first_byte = (*pos & 7); + size_t bits_left_to_write; + bits <<= bits_reserved_in_first_byte; + *array_pos++ |= (uint8_t)bits; + for (bits_left_to_write = n_bits + bits_reserved_in_first_byte; + bits_left_to_write >= 9; + bits_left_to_write -= 8) { + bits >>= 8; + *array_pos++ = (uint8_t)bits; + } + *array_pos = 0; + *pos += n_bits; + } +#endif +} + +static BROTLI_INLINE void BrotliWriteBitsPrepareStorage( + size_t pos, uint8_t* array) { + BROTLI_LOG(("WriteBitsPrepareStorage %10d\n", (int)pos)); + BROTLI_DCHECK((pos & 7) == 0); + array[pos >> 3] = 0; +} + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_WRITE_BITS_H_ */ diff --git a/packages/runtime/vendor/brotli/c/include/brotli/decode.h b/packages/runtime/vendor/brotli/c/include/brotli/decode.h new file mode 100644 index 000000000..8d436db73 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/include/brotli/decode.h @@ -0,0 +1,409 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/** + * @file + * API for Brotli decompression. + */ + +#ifndef BROTLI_DEC_DECODE_H_ +#define BROTLI_DEC_DECODE_H_ + +#include +#include +#include /* IWYU pragma: export */ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/** + * Opaque structure that holds decoder state. + * + * Allocated and initialized with ::BrotliDecoderCreateInstance. + * Cleaned up and deallocated with ::BrotliDecoderDestroyInstance. + */ +typedef struct BrotliDecoderStateStruct BrotliDecoderState; + +/** + * Result type for ::BrotliDecoderDecompress and + * ::BrotliDecoderDecompressStream functions. + */ +typedef enum { + /** Decoding error, e.g. corrupted input or memory allocation problem. */ + BROTLI_DECODER_RESULT_ERROR = 0, + /** Decoding successfully completed. */ + BROTLI_DECODER_RESULT_SUCCESS = 1, + /** Partially done; should be called again with more input. */ + BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT = 2, + /** Partially done; should be called again with more output. */ + BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT = 3 +} BrotliDecoderResult; + +/** + * Template that evaluates items of ::BrotliDecoderErrorCode. + * + * Example: @code {.cpp} + * // Log Brotli error code. + * switch (brotliDecoderErrorCode) { + * #define CASE_(PREFIX, NAME, CODE) \ + * case BROTLI_DECODER ## PREFIX ## NAME: \ + * LOG(INFO) << "error code:" << #NAME; \ + * break; + * #define NEWLINE_ + * BROTLI_DECODER_ERROR_CODES_LIST(CASE_, NEWLINE_) + * #undef CASE_ + * #undef NEWLINE_ + * default: LOG(FATAL) << "unknown brotli error code"; + * } + * @endcode + */ +#define BROTLI_DECODER_ERROR_CODES_LIST(BROTLI_ERROR_CODE, SEPARATOR) \ + BROTLI_ERROR_CODE(_, NO_ERROR, 0) SEPARATOR \ + /* Same as BrotliDecoderResult values */ \ + BROTLI_ERROR_CODE(_, SUCCESS, 1) SEPARATOR \ + BROTLI_ERROR_CODE(_, NEEDS_MORE_INPUT, 2) SEPARATOR \ + BROTLI_ERROR_CODE(_, NEEDS_MORE_OUTPUT, 3) SEPARATOR \ + \ + /* Errors caused by invalid input */ \ + BROTLI_ERROR_CODE(_ERROR_FORMAT_, EXUBERANT_NIBBLE, -1) SEPARATOR \ + BROTLI_ERROR_CODE(_ERROR_FORMAT_, RESERVED, -2) SEPARATOR \ + BROTLI_ERROR_CODE(_ERROR_FORMAT_, EXUBERANT_META_NIBBLE, -3) SEPARATOR \ + BROTLI_ERROR_CODE(_ERROR_FORMAT_, SIMPLE_HUFFMAN_ALPHABET, -4) SEPARATOR \ + BROTLI_ERROR_CODE(_ERROR_FORMAT_, SIMPLE_HUFFMAN_SAME, -5) SEPARATOR \ + BROTLI_ERROR_CODE(_ERROR_FORMAT_, CL_SPACE, -6) SEPARATOR \ + BROTLI_ERROR_CODE(_ERROR_FORMAT_, HUFFMAN_SPACE, -7) SEPARATOR \ + BROTLI_ERROR_CODE(_ERROR_FORMAT_, CONTEXT_MAP_REPEAT, -8) SEPARATOR \ + BROTLI_ERROR_CODE(_ERROR_FORMAT_, BLOCK_LENGTH_1, -9) SEPARATOR \ + BROTLI_ERROR_CODE(_ERROR_FORMAT_, BLOCK_LENGTH_2, -10) SEPARATOR \ + BROTLI_ERROR_CODE(_ERROR_FORMAT_, TRANSFORM, -11) SEPARATOR \ + BROTLI_ERROR_CODE(_ERROR_FORMAT_, DICTIONARY, -12) SEPARATOR \ + BROTLI_ERROR_CODE(_ERROR_FORMAT_, WINDOW_BITS, -13) SEPARATOR \ + BROTLI_ERROR_CODE(_ERROR_FORMAT_, PADDING_1, -14) SEPARATOR \ + BROTLI_ERROR_CODE(_ERROR_FORMAT_, PADDING_2, -15) SEPARATOR \ + BROTLI_ERROR_CODE(_ERROR_FORMAT_, DISTANCE, -16) SEPARATOR \ + \ + /* -17 code is reserved */ \ + \ + BROTLI_ERROR_CODE(_ERROR_, COMPOUND_DICTIONARY, -18) SEPARATOR \ + BROTLI_ERROR_CODE(_ERROR_, DICTIONARY_NOT_SET, -19) SEPARATOR \ + BROTLI_ERROR_CODE(_ERROR_, INVALID_ARGUMENTS, -20) SEPARATOR \ + \ + /* Memory allocation problems */ \ + BROTLI_ERROR_CODE(_ERROR_ALLOC_, CONTEXT_MODES, -21) SEPARATOR \ + /* Literal, insert and distance trees together */ \ + BROTLI_ERROR_CODE(_ERROR_ALLOC_, TREE_GROUPS, -22) SEPARATOR \ + /* -23..-24 codes are reserved for distinct tree groups */ \ + BROTLI_ERROR_CODE(_ERROR_ALLOC_, CONTEXT_MAP, -25) SEPARATOR \ + BROTLI_ERROR_CODE(_ERROR_ALLOC_, RING_BUFFER_1, -26) SEPARATOR \ + BROTLI_ERROR_CODE(_ERROR_ALLOC_, RING_BUFFER_2, -27) SEPARATOR \ + /* -28..-29 codes are reserved for dynamic ring-buffer allocation */ \ + BROTLI_ERROR_CODE(_ERROR_ALLOC_, BLOCK_TYPE_TREES, -30) SEPARATOR \ + \ + /* "Impossible" states */ \ + BROTLI_ERROR_CODE(_ERROR_, UNREACHABLE, -31) + +/** + * Error code for detailed logging / production debugging. + * + * See ::BrotliDecoderGetErrorCode and ::BROTLI_LAST_ERROR_CODE. + */ +typedef enum { +#define BROTLI_COMMA_ , +#define BROTLI_ERROR_CODE_ENUM_ITEM_(PREFIX, NAME, CODE) \ + BROTLI_DECODER ## PREFIX ## NAME = CODE + BROTLI_DECODER_ERROR_CODES_LIST(BROTLI_ERROR_CODE_ENUM_ITEM_, BROTLI_COMMA_) +} BrotliDecoderErrorCode; +#undef BROTLI_ERROR_CODE_ENUM_ITEM_ +#undef BROTLI_COMMA_ + +/** + * The value of the last error code, negative integer. + * + * All other error code values are in the range from ::BROTLI_LAST_ERROR_CODE + * to @c -1. There are also 4 other possible non-error codes @c 0 .. @c 3 in + * ::BrotliDecoderErrorCode enumeration. + */ +#define BROTLI_LAST_ERROR_CODE BROTLI_DECODER_ERROR_UNREACHABLE + +/** Options to be used with ::BrotliDecoderSetParameter. */ +typedef enum BrotliDecoderParameter { + /** + * Disable "canny" ring buffer allocation strategy. + * + * Ring buffer is allocated according to window size, despite the real size of + * the content. + */ + BROTLI_DECODER_PARAM_DISABLE_RING_BUFFER_REALLOCATION = 0, + /** + * Flag that determines if "Large Window Brotli" is used. + */ + BROTLI_DECODER_PARAM_LARGE_WINDOW = 1 +} BrotliDecoderParameter; + +/** + * Sets the specified parameter to the given decoder instance. + * + * @param state decoder instance + * @param param parameter to set + * @param value new parameter value + * @returns ::BROTLI_FALSE if parameter is unrecognized, or value is invalid + * @returns ::BROTLI_TRUE if value is accepted + */ +BROTLI_DEC_API BROTLI_BOOL BrotliDecoderSetParameter( + BrotliDecoderState* state, BrotliDecoderParameter param, uint32_t value); + +/** + * Adds LZ77 prefix dictionary, adds or replaces built-in static dictionary and + * transforms. + * + * Attached dictionary ownership is not transferred. + * Data provided to this method should be kept accessible until + * decoding is finished and decoder instance is destroyed. + * + * @note Dictionaries can NOT be attached after actual decoding is started. + * + * @param state decoder instance + * @param type dictionary data format + * @param data_size length of memory region pointed by @p data + * @param data dictionary data in format corresponding to @p type + * @returns ::BROTLI_FALSE if dictionary is corrupted, + * or dictionary count limit is reached + * @returns ::BROTLI_TRUE if dictionary is accepted / attached + */ +BROTLI_DEC_API BROTLI_BOOL BrotliDecoderAttachDictionary( + BrotliDecoderState* state, BrotliSharedDictionaryType type, + size_t data_size, const uint8_t data[BROTLI_ARRAY_PARAM(data_size)]); + +/** + * Creates an instance of ::BrotliDecoderState and initializes it. + * + * The instance can be used once for decoding and should then be destroyed with + * ::BrotliDecoderDestroyInstance, it cannot be reused for a new decoding + * session. + * + * @p alloc_func and @p free_func @b MUST be both zero or both non-zero. In the + * case they are both zero, default memory allocators are used. @p opaque is + * passed to @p alloc_func and @p free_func when they are called. @p free_func + * has to return without doing anything when asked to free a NULL pointer. + * + * @param alloc_func custom memory allocation function + * @param free_func custom memory free function + * @param opaque custom memory manager handle + * @returns @c 0 if instance can not be allocated or initialized + * @returns pointer to initialized ::BrotliDecoderState otherwise + */ +BROTLI_DEC_API BrotliDecoderState* BrotliDecoderCreateInstance( + brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque); + +/** + * Deinitializes and frees ::BrotliDecoderState instance. + * + * @param state decoder instance to be cleaned up and deallocated + */ +BROTLI_DEC_API void BrotliDecoderDestroyInstance(BrotliDecoderState* state); + +/** + * Performs one-shot memory-to-memory decompression. + * + * Decompresses the data in @p encoded_buffer into @p decoded_buffer, and sets + * @p *decoded_size to the decompressed length. + * + * @param encoded_size size of @p encoded_buffer + * @param encoded_buffer compressed data buffer with at least @p encoded_size + * addressable bytes + * @param[in, out] decoded_size @b in: size of @p decoded_buffer; \n + * @b out: length of decompressed data written to + * @p decoded_buffer + * @param decoded_buffer decompressed data destination buffer + * @returns ::BROTLI_DECODER_RESULT_ERROR if input is corrupted, memory + * allocation failed, or @p decoded_buffer is not large enough; + * @returns ::BROTLI_DECODER_RESULT_SUCCESS otherwise + */ +BROTLI_DEC_API BrotliDecoderResult BrotliDecoderDecompress( + size_t encoded_size, + const uint8_t encoded_buffer[BROTLI_ARRAY_PARAM(encoded_size)], + size_t* decoded_size, + uint8_t decoded_buffer[BROTLI_ARRAY_PARAM(*decoded_size)]); + +/** + * Decompresses the input stream to the output stream. + * + * The values @p *available_in and @p *available_out must specify the number of + * bytes addressable at @p *next_in and @p *next_out respectively. + * When @p *available_out is @c 0, @p next_out is allowed to be @c NULL. + * + * After each call, @p *available_in will be decremented by the amount of input + * bytes consumed, and the @p *next_in pointer will be incremented by that + * amount. Similarly, @p *available_out will be decremented by the amount of + * output bytes written, and the @p *next_out pointer will be incremented by + * that amount. + * + * @p total_out, if it is not a null-pointer, will be set to the number + * of bytes decompressed since the last @p state initialization. + * + * @note Input is never overconsumed, so @p next_in and @p available_in could be + * passed to the next consumer after decoding is complete. + * + * @param state decoder instance + * @param[in, out] available_in @b in: amount of available input; \n + * @b out: amount of unused input + * @param[in, out] next_in pointer to the next compressed byte + * @param[in, out] available_out @b in: length of output buffer; \n + * @b out: remaining size of output buffer + * @param[in, out] next_out output buffer cursor; + * can be @c NULL if @p available_out is @c 0 + * @param[out] total_out number of bytes decompressed so far; can be @c NULL + * @returns ::BROTLI_DECODER_RESULT_ERROR if input is corrupted, memory + * allocation failed, arguments were invalid, etc.; + * use ::BrotliDecoderGetErrorCode to get detailed error code + * @returns ::BROTLI_DECODER_RESULT_NEEDS_MORE_INPUT decoding is blocked until + * more input data is provided + * @returns ::BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT decoding is blocked until + * more output space is provided + * @returns ::BROTLI_DECODER_RESULT_SUCCESS decoding is finished, no more + * input might be consumed and no more output will be produced + */ +BROTLI_DEC_API BrotliDecoderResult BrotliDecoderDecompressStream( + BrotliDecoderState* state, size_t* available_in, const uint8_t** next_in, + size_t* available_out, uint8_t** next_out, size_t* total_out); + +/** + * Checks if decoder has more output. + * + * @param state decoder instance + * @returns ::BROTLI_TRUE, if decoder has some unconsumed output + * @returns ::BROTLI_FALSE otherwise + */ +BROTLI_DEC_API BROTLI_BOOL BrotliDecoderHasMoreOutput( + const BrotliDecoderState* state); + +/** + * Acquires pointer to internal output buffer. + * + * This method is used to make language bindings easier and more efficient: + * -# push data to ::BrotliDecoderDecompressStream, + * until ::BROTLI_DECODER_RESULT_NEEDS_MORE_OUTPUT is reported + * -# use ::BrotliDecoderTakeOutput to peek bytes and copy to language-specific + * entity + * + * Also this could be useful if there is an output stream that is able to + * consume all the provided data (e.g. when data is saved to file system). + * + * @attention After every call to ::BrotliDecoderTakeOutput @p *size bytes of + * output are considered consumed for all consecutive calls to the + * instance methods; returned pointer becomes invalidated as well. + * + * @note Decoder output is not guaranteed to be contiguous. This means that + * after the size-unrestricted call to ::BrotliDecoderTakeOutput, + * immediate next call to ::BrotliDecoderTakeOutput may return more data. + * + * @param state decoder instance + * @param[in, out] size @b in: number of bytes caller is ready to take, @c 0 if + * any amount could be handled; \n + * @b out: amount of data pointed by returned pointer and + * considered consumed; \n + * out value is never greater than in value, unless it is @c 0 + * @returns pointer to output data + */ +BROTLI_DEC_API const uint8_t* BrotliDecoderTakeOutput( + BrotliDecoderState* state, size_t* size); + +/** + * Checks if instance has already consumed input. + * + * Instance that returns ::BROTLI_FALSE is considered "fresh" and could be + * reused. + * + * @param state decoder instance + * @returns ::BROTLI_TRUE if decoder has already used some input bytes + * @returns ::BROTLI_FALSE otherwise + */ +BROTLI_DEC_API BROTLI_BOOL BrotliDecoderIsUsed(const BrotliDecoderState* state); + +/** + * Checks if decoder instance reached the final state. + * + * @param state decoder instance + * @returns ::BROTLI_TRUE if decoder is in a state where it reached the end of + * the input and produced all of the output + * @returns ::BROTLI_FALSE otherwise + */ +BROTLI_DEC_API BROTLI_BOOL BrotliDecoderIsFinished( + const BrotliDecoderState* state); + +/** + * Acquires a detailed error code. + * + * Should be used only after ::BrotliDecoderDecompressStream returns + * ::BROTLI_DECODER_RESULT_ERROR. + * + * See also ::BrotliDecoderErrorString + * + * @param state decoder instance + * @returns last saved error code + */ +BROTLI_DEC_API BrotliDecoderErrorCode BrotliDecoderGetErrorCode( + const BrotliDecoderState* state); + +/** + * Converts error code to a c-string. + */ +BROTLI_DEC_API const char* BrotliDecoderErrorString(BrotliDecoderErrorCode c); + +/** + * Gets a decoder library version. + * + * Look at BROTLI_MAKE_HEX_VERSION for more information. + */ +BROTLI_DEC_API uint32_t BrotliDecoderVersion(void); + +/** + * Callback to fire on metadata block start. + * + * After this callback is fired, if @p size is not @c 0, it is followed by + * ::brotli_decoder_metadata_chunk_func as more metadata block contents become + * accessible. + * + * @param opaque callback handle + * @param size size of metadata block + */ +typedef void (*brotli_decoder_metadata_start_func)(void* opaque, size_t size); + +/** + * Callback to fire on metadata block chunk becomes available. + * + * This function can be invoked multiple times per metadata block; block should + * be considered finished when sum of @p size matches the announced metadata + * block size. Chunks contents pointed by @p data are transient and shouln not + * be accessed after leaving the callback. + * + * @param opaque callback handle + * @param data pointer to metadata contents + * @param size size of metadata block chunk, at least @c 1 + */ +typedef void (*brotli_decoder_metadata_chunk_func)(void* opaque, + const uint8_t* data, + size_t size); + +/** + * Sets callback for receiving metadata blocks. + * + * @param state decoder instance + * @param start_func callback on metadata block start + * @param chunk_func callback on metadata block chunk + * @param opaque callback handle + */ +BROTLI_DEC_API void BrotliDecoderSetMetadataCallbacks( + BrotliDecoderState* state, + brotli_decoder_metadata_start_func start_func, + brotli_decoder_metadata_chunk_func chunk_func, void* opaque); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_DEC_DECODE_H_ */ diff --git a/packages/runtime/vendor/brotli/c/include/brotli/encode.h b/packages/runtime/vendor/brotli/c/include/brotli/encode.h new file mode 100644 index 000000000..ac26ea8e6 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/include/brotli/encode.h @@ -0,0 +1,505 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/** + * @file + * API for Brotli compression. + */ + +#ifndef BROTLI_ENC_ENCODE_H_ +#define BROTLI_ENC_ENCODE_H_ + +#include +#include +#include /* IWYU pragma: export */ + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +/** Minimal value for ::BROTLI_PARAM_LGWIN parameter. */ +#define BROTLI_MIN_WINDOW_BITS 10 +/** + * Maximal value for ::BROTLI_PARAM_LGWIN parameter. + * + * @note equal to @c BROTLI_MAX_DISTANCE_BITS constant. + */ +#define BROTLI_MAX_WINDOW_BITS 24 +/** + * Maximal value for ::BROTLI_PARAM_LGWIN parameter + * in "Large Window Brotli" (32-bit). + */ +#define BROTLI_LARGE_MAX_WINDOW_BITS 30 +/** Minimal value for ::BROTLI_PARAM_LGBLOCK parameter. */ +#define BROTLI_MIN_INPUT_BLOCK_BITS 16 +/** Maximal value for ::BROTLI_PARAM_LGBLOCK parameter. */ +#define BROTLI_MAX_INPUT_BLOCK_BITS 24 +/** Minimal value for ::BROTLI_PARAM_QUALITY parameter. */ +#define BROTLI_MIN_QUALITY 0 +/** Maximal value for ::BROTLI_PARAM_QUALITY parameter. */ +#define BROTLI_MAX_QUALITY 11 + +/** Options for ::BROTLI_PARAM_MODE parameter. */ +typedef enum BrotliEncoderMode { + /** + * Default compression mode. + * + * In this mode compressor does not know anything in advance about the + * properties of the input. + */ + BROTLI_MODE_GENERIC = 0, + /** Compression mode for UTF-8 formatted text input. */ + BROTLI_MODE_TEXT = 1, + /** Compression mode used in WOFF 2.0. */ + BROTLI_MODE_FONT = 2 +} BrotliEncoderMode; + +/** Default value for ::BROTLI_PARAM_QUALITY parameter. */ +#define BROTLI_DEFAULT_QUALITY 11 +/** Default value for ::BROTLI_PARAM_LGWIN parameter. */ +#define BROTLI_DEFAULT_WINDOW 22 +/** Default value for ::BROTLI_PARAM_MODE parameter. */ +#define BROTLI_DEFAULT_MODE BROTLI_MODE_GENERIC + +/** Operations that can be performed by streaming encoder. */ +typedef enum BrotliEncoderOperation { + /** + * Process input. + * + * Encoder may postpone producing output, until it has processed enough input. + */ + BROTLI_OPERATION_PROCESS = 0, + /** + * Produce output for all processed input. + * + * Actual flush is performed when input stream is depleted and there is enough + * space in output stream. This means that client should repeat + * ::BROTLI_OPERATION_FLUSH operation until @p available_in becomes @c 0, and + * ::BrotliEncoderHasMoreOutput returns ::BROTLI_FALSE. If output is acquired + * via ::BrotliEncoderTakeOutput, then operation should be repeated after + * output buffer is drained. + * + * @warning Until flush is complete, client @b SHOULD @b NOT swap, + * reduce or extend input stream. + * + * When flush is complete, output data will be sufficient for decoder to + * reproduce all the given input. + */ + BROTLI_OPERATION_FLUSH = 1, + /** + * Finalize the stream. + * + * Actual finalization is performed when input stream is depleted and there is + * enough space in output stream. This means that client should repeat + * ::BROTLI_OPERATION_FINISH operation until @p available_in becomes @c 0, and + * ::BrotliEncoderHasMoreOutput returns ::BROTLI_FALSE. If output is acquired + * via ::BrotliEncoderTakeOutput, then operation should be repeated after + * output buffer is drained. + * + * @warning Until finalization is complete, client @b SHOULD @b NOT swap, + * reduce or extend input stream. + * + * Helper function ::BrotliEncoderIsFinished checks if stream is finalized and + * output fully dumped. + * + * Adding more input data to finalized stream is impossible. + */ + BROTLI_OPERATION_FINISH = 2, + /** + * Emit metadata block to stream. + * + * Metadata is opaque to Brotli: neither encoder, nor decoder processes this + * data or relies on it. It may be used to pass some extra information from + * encoder client to decoder client without interfering with main data stream. + * + * @note Encoder may emit empty metadata blocks internally, to pad encoded + * stream to byte boundary. + * + * @warning Until emitting metadata is complete client @b SHOULD @b NOT swap, + * reduce or extend input stream. + * + * @warning The whole content of input buffer is considered to be the content + * of metadata block. Do @b NOT @e append metadata to input stream, + * before it is depleted with other operations. + * + * Stream is soft-flushed before metadata block is emitted. Metadata block + * @b MUST be no longer than than 16MiB. + */ + BROTLI_OPERATION_EMIT_METADATA = 3 +} BrotliEncoderOperation; + +/** Options to be used with ::BrotliEncoderSetParameter. */ +typedef enum BrotliEncoderParameter { + /** + * Tune encoder for specific input. + * + * ::BrotliEncoderMode enumerates all available values. + */ + BROTLI_PARAM_MODE = 0, + /** + * The main compression speed-density lever. + * + * The higher the quality, the slower the compression. Range is + * from ::BROTLI_MIN_QUALITY to ::BROTLI_MAX_QUALITY. + */ + BROTLI_PARAM_QUALITY = 1, + /** + * Recommended sliding LZ77 window size. + * + * Encoder may reduce this value, e.g. if input is much smaller than + * window size. + * + * Window size is `(1 << value) - 16`. + * + * Range is from ::BROTLI_MIN_WINDOW_BITS to ::BROTLI_MAX_WINDOW_BITS. + */ + BROTLI_PARAM_LGWIN = 2, + /** + * Recommended input block size. + * + * Encoder may reduce this value, e.g. if input is much smaller than input + * block size. + * + * Range is from ::BROTLI_MIN_INPUT_BLOCK_BITS to + * ::BROTLI_MAX_INPUT_BLOCK_BITS. + * + * @note Bigger input block size allows better compression, but consumes more + * memory. \n The rough formula of memory used for temporary input + * storage is `3 << lgBlock`. + */ + BROTLI_PARAM_LGBLOCK = 3, + /** + * Flag that affects usage of "literal context modeling" format feature. + * + * This flag is a "decoding-speed vs compression ratio" trade-off. + */ + BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING = 4, + /** + * Estimated total input size for all ::BrotliEncoderCompressStream calls. + * + * The default value is 0, which means that the total input size is unknown. + */ + BROTLI_PARAM_SIZE_HINT = 5, + /** + * Flag that determines if "Large Window Brotli" is used. + */ + BROTLI_PARAM_LARGE_WINDOW = 6, + /** + * Recommended number of postfix bits (NPOSTFIX). + * + * Encoder may change this value. + * + * Range is from 0 to ::BROTLI_MAX_NPOSTFIX. + */ + BROTLI_PARAM_NPOSTFIX = 7, + /** + * Recommended number of direct distance codes (NDIRECT). + * + * Encoder may change this value. + * + * Range is from 0 to (15 << NPOSTFIX) in steps of (1 << NPOSTFIX). + */ + BROTLI_PARAM_NDIRECT = 8, + /** + * Number of bytes of input stream already processed by a different instance. + * + * @note It is important to configure all the encoder instances with same + * parameters (except this one) in order to allow all the encoded parts + * obey the same restrictions implied by header. + * + * If offset is not 0, then stream header is omitted. + * In any case output start is byte aligned, so for proper streams stitching + * "predecessor" stream must be flushed. + * + * Range is not artificially limited, but all the values greater or equal to + * maximal window size have the same effect. Values greater than 2**30 are not + * allowed. + */ + BROTLI_PARAM_STREAM_OFFSET = 9 +} BrotliEncoderParameter; + +/** + * Opaque structure that holds encoder state. + * + * Allocated and initialized with ::BrotliEncoderCreateInstance. + * Cleaned up and deallocated with ::BrotliEncoderDestroyInstance. + */ +typedef struct BrotliEncoderStateStruct BrotliEncoderState; + +/** + * Sets the specified parameter to the given encoder instance. + * + * @param state encoder instance + * @param param parameter to set + * @param value new parameter value + * @returns ::BROTLI_FALSE if parameter is unrecognized, or value is invalid + * @returns ::BROTLI_FALSE if value of parameter can not be changed at current + * encoder state (e.g. when encoding is started, window size might be + * already encoded and therefore it is impossible to change it) + * @returns ::BROTLI_TRUE if value is accepted + * @warning invalid values might be accepted in case they would not break + * encoding process. + */ +BROTLI_ENC_API BROTLI_BOOL BrotliEncoderSetParameter( + BrotliEncoderState* state, BrotliEncoderParameter param, uint32_t value); + +/** + * Creates an instance of ::BrotliEncoderState and initializes it. + * + * @p alloc_func and @p free_func @b MUST be both zero or both non-zero. In the + * case they are both zero, default memory allocators are used. @p opaque is + * passed to @p alloc_func and @p free_func when they are called. @p free_func + * has to return without doing anything when asked to free a NULL pointer. + * + * @param alloc_func custom memory allocation function + * @param free_func custom memory free function + * @param opaque custom memory manager handle + * @returns @c 0 if instance can not be allocated or initialized + * @returns pointer to initialized ::BrotliEncoderState otherwise + */ +BROTLI_ENC_API BrotliEncoderState* BrotliEncoderCreateInstance( + brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque); + +/** + * Deinitializes and frees ::BrotliEncoderState instance. + * + * @param state decoder instance to be cleaned up and deallocated + */ +BROTLI_ENC_API void BrotliEncoderDestroyInstance(BrotliEncoderState* state); + +/* Opaque type for pointer to different possible internal structures containing + dictionary prepared for the encoder */ +typedef struct BrotliEncoderPreparedDictionaryStruct + BrotliEncoderPreparedDictionary; + +/** + * Prepares a shared dictionary from the given file format for the encoder. + * + * @p alloc_func and @p free_func @b MUST be both zero or both non-zero. In the + * case they are both zero, default memory allocators are used. @p opaque is + * passed to @p alloc_func and @p free_func when they are called. @p free_func + * has to return without doing anything when asked to free a NULL pointer. + * + * @warning Created instance is "lean"; it does not contain copy of @p data, + * rather it contains only pointer to it; therefore, + * @p data @b MUST outlive the created instance. + * + * @param type type of dictionary stored in data + * @param data_size size of @p data buffer + * @param data pointer to the dictionary data + * @param quality the maximum Brotli quality to prepare the dictionary for, + * use BROTLI_MAX_QUALITY by default + * @param alloc_func custom memory allocation function + * @param free_func custom memory free function + * @param opaque custom memory manager handle + */ +BROTLI_ENC_API BrotliEncoderPreparedDictionary* +BrotliEncoderPrepareDictionary(BrotliSharedDictionaryType type, + size_t data_size, const uint8_t data[BROTLI_ARRAY_PARAM(data_size)], + int quality, + brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque); + +BROTLI_ENC_API void BrotliEncoderDestroyPreparedDictionary( + BrotliEncoderPreparedDictionary* dictionary); + +/** + * Attaches a prepared dictionary of any type to the encoder. Can be used + * multiple times to attach multiple dictionaries. The dictionary type was + * determined by BrotliEncoderPrepareDictionary. Multiple raw prefix + * dictionaries and/or max 1 serialized dictionary with custom words can be + * attached. + * + * @returns ::BROTLI_FALSE in case of error + * @returns ::BROTLI_TRUE otherwise + */ +BROTLI_ENC_API BROTLI_BOOL BrotliEncoderAttachPreparedDictionary( + BrotliEncoderState* state, + const BrotliEncoderPreparedDictionary* dictionary); + +/** + * Calculates the output size bound for the given @p input_size. + * + * @warning Result is only valid if quality is at least @c 2 and, in + * case ::BrotliEncoderCompressStream was used, no flushes + * (::BROTLI_OPERATION_FLUSH) were performed. + * + * @param input_size size of projected input + * @returns @c 0 if result does not fit @c size_t + */ +BROTLI_ENC_API size_t BrotliEncoderMaxCompressedSize(size_t input_size); + +/** + * Performs one-shot memory-to-memory compression. + * + * Compresses the data in @p input_buffer into @p encoded_buffer, and sets + * @p *encoded_size to the compressed length. + * + * @note If ::BrotliEncoderMaxCompressedSize(@p input_size) returns non-zero + * value, then output is guaranteed to be no longer than that. + * + * @note If @p lgwin is greater than ::BROTLI_MAX_WINDOW_BITS then resulting + * stream might be incompatible with RFC 7932; to decode such streams, + * decoder should be configured with + * ::BROTLI_DECODER_PARAM_LARGE_WINDOW = @c 1 + * + * @param quality quality parameter value, e.g. ::BROTLI_DEFAULT_QUALITY + * @param lgwin lgwin parameter value, e.g. ::BROTLI_DEFAULT_WINDOW + * @param mode mode parameter value, e.g. ::BROTLI_DEFAULT_MODE + * @param input_size size of @p input_buffer + * @param input_buffer input data buffer with at least @p input_size + * addressable bytes + * @param[in, out] encoded_size @b in: size of @p encoded_buffer; \n + * @b out: length of compressed data written to + * @p encoded_buffer, or @c 0 if compression fails + * @param encoded_buffer compressed data destination buffer + * @returns ::BROTLI_FALSE in case of compression error + * @returns ::BROTLI_FALSE if output buffer is too small + * @returns ::BROTLI_TRUE otherwise + */ +BROTLI_ENC_API BROTLI_BOOL BrotliEncoderCompress( + int quality, int lgwin, BrotliEncoderMode mode, size_t input_size, + const uint8_t input_buffer[BROTLI_ARRAY_PARAM(input_size)], + size_t* encoded_size, + uint8_t encoded_buffer[BROTLI_ARRAY_PARAM(*encoded_size)]); + +/** + * Compresses input stream to output stream. + * + * The values @p *available_in and @p *available_out must specify the number of + * bytes addressable at @p *next_in and @p *next_out respectively. + * When @p *available_out is @c 0, @p next_out is allowed to be @c NULL. + * + * After each call, @p *available_in will be decremented by the amount of input + * bytes consumed, and the @p *next_in pointer will be incremented by that + * amount. Similarly, @p *available_out will be decremented by the amount of + * output bytes written, and the @p *next_out pointer will be incremented by + * that amount. + * + * @p total_out, if it is not a null-pointer, will be set to the number + * of bytes compressed since the last @p state initialization. + * + * + * + * Internally workflow consists of 3 tasks: + * -# (optionally) copy input data to internal buffer + * -# actually compress data and (optionally) store it to internal buffer + * -# (optionally) copy compressed bytes from internal buffer to output stream + * + * Whenever all 3 tasks can't move forward anymore, or error occurs, this + * method returns the control flow to caller. + * + * @p op is used to perform flush, finish the stream, or inject metadata block. + * See ::BrotliEncoderOperation for more information. + * + * Flushing the stream means forcing encoding of all input passed to encoder and + * completing the current output block, so it could be fully decoded by stream + * decoder. To perform flush set @p op to ::BROTLI_OPERATION_FLUSH. + * Under some circumstances (e.g. lack of output stream capacity) this operation + * would require several calls to ::BrotliEncoderCompressStream. The method must + * be called again until both input stream is depleted and encoder has no more + * output (see ::BrotliEncoderHasMoreOutput) after the method is called. + * + * Finishing the stream means encoding of all input passed to encoder and + * adding specific "final" marks, so stream decoder could determine that stream + * is complete. To perform finish set @p op to ::BROTLI_OPERATION_FINISH. + * Under some circumstances (e.g. lack of output stream capacity) this operation + * would require several calls to ::BrotliEncoderCompressStream. The method must + * be called again until both input stream is depleted and encoder has no more + * output (see ::BrotliEncoderHasMoreOutput) after the method is called. + * + * @warning When flushing and finishing, @p op should not change until operation + * is complete; input stream should not be swapped, reduced or + * extended as well. + * + * @param state encoder instance + * @param op requested operation + * @param[in, out] available_in @b in: amount of available input; \n + * @b out: amount of unused input + * @param[in, out] next_in pointer to the next input byte + * @param[in, out] available_out @b in: length of output buffer; \n + * @b out: remaining size of output buffer + * @param[in, out] next_out compressed output buffer cursor; + * can be @c NULL if @p available_out is @c 0 + * @param[out] total_out number of bytes produced so far; can be @c NULL + * @returns ::BROTLI_FALSE if there was an error + * @returns ::BROTLI_TRUE otherwise + */ +BROTLI_ENC_API BROTLI_BOOL BrotliEncoderCompressStream( + BrotliEncoderState* state, BrotliEncoderOperation op, size_t* available_in, + const uint8_t** next_in, size_t* available_out, uint8_t** next_out, + size_t* total_out); + +/** + * Checks if encoder instance reached the final state. + * + * @param state encoder instance + * @returns ::BROTLI_TRUE if encoder is in a state where it reached the end of + * the input and produced all of the output + * @returns ::BROTLI_FALSE otherwise + */ +BROTLI_ENC_API BROTLI_BOOL BrotliEncoderIsFinished(BrotliEncoderState* state); + +/** + * Checks if encoder has more output. + * + * @param state encoder instance + * @returns ::BROTLI_TRUE, if encoder has some unconsumed output + * @returns ::BROTLI_FALSE otherwise + */ +BROTLI_ENC_API BROTLI_BOOL BrotliEncoderHasMoreOutput( + BrotliEncoderState* state); + +/** + * Acquires pointer to internal output buffer. + * + * This method is used to make language bindings easier and more efficient: + * -# push data to ::BrotliEncoderCompressStream, + * until ::BrotliEncoderHasMoreOutput returns BROTLI_TRUE + * -# use ::BrotliEncoderTakeOutput to peek bytes and copy to language-specific + * entity + * + * Also this could be useful if there is an output stream that is able to + * consume all the provided data (e.g. when data is saved to file system). + * + * @attention After every call to ::BrotliEncoderTakeOutput @p *size bytes of + * output are considered consumed for all consecutive calls to the + * instance methods; returned pointer becomes invalidated as well. + * + * @note Encoder output is not guaranteed to be contiguous. This means that + * after the size-unrestricted call to ::BrotliEncoderTakeOutput, + * immediate next call to ::BrotliEncoderTakeOutput may return more data. + * + * @param state encoder instance + * @param[in, out] size @b in: number of bytes caller is ready to take, @c 0 if + * any amount could be handled; \n + * @b out: amount of data pointed by returned pointer and + * considered consumed; \n + * out value is never greater than in value, unless it is @c 0 + * @returns pointer to output data + */ +BROTLI_ENC_API const uint8_t* BrotliEncoderTakeOutput( + BrotliEncoderState* state, size_t* size); + +/* Returns the estimated peak memory usage (in bytes) of the BrotliCompress() + function, not counting the memory needed for the input and output. */ +BROTLI_ENC_EXTRA_API size_t BrotliEncoderEstimatePeakMemoryUsage( + int quality, int lgwin, size_t input_size); +/* Returns 0 if dictionary is not valid; otherwise returns allocation size. */ +BROTLI_ENC_EXTRA_API size_t BrotliEncoderGetPreparedDictionarySize( + const BrotliEncoderPreparedDictionary* dictionary); + +/** + * Gets an encoder library version. + * + * Look at BROTLI_MAKE_HEX_VERSION for more information. + */ +BROTLI_ENC_API uint32_t BrotliEncoderVersion(void); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_ENC_ENCODE_H_ */ diff --git a/packages/runtime/vendor/brotli/c/include/brotli/port.h b/packages/runtime/vendor/brotli/c/include/brotli/port.h new file mode 100644 index 000000000..11cefd791 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/include/brotli/port.h @@ -0,0 +1,302 @@ +/* Copyright 2016 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* Macros for compiler / platform specific API declarations. */ + +#ifndef BROTLI_COMMON_PORT_H_ +#define BROTLI_COMMON_PORT_H_ + +/* The following macros were borrowed from https://github.com/nemequ/hedley + * with permission of original author - Evan Nemerson */ + +/* >>> >>> >>> hedley macros */ + +#define BROTLI_MAKE_VERSION(major, minor, revision) \ + (((major) * 1000000) + ((minor) * 1000) + (revision)) + +#if defined(__GNUC__) && defined(__GNUC_PATCHLEVEL__) +#define BROTLI_GNUC_VERSION \ + BROTLI_MAKE_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#elif defined(__GNUC__) +#define BROTLI_GNUC_VERSION BROTLI_MAKE_VERSION(__GNUC__, __GNUC_MINOR__, 0) +#endif + +#if defined(BROTLI_GNUC_VERSION) +#define BROTLI_GNUC_VERSION_CHECK(major, minor, patch) \ + (BROTLI_GNUC_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch)) +#else +#define BROTLI_GNUC_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 140000000) +#define BROTLI_MSVC_VERSION \ + BROTLI_MAKE_VERSION((_MSC_FULL_VER / 10000000), \ + (_MSC_FULL_VER % 10000000) / 100000, \ + (_MSC_FULL_VER % 100000) / 100) +#elif defined(_MSC_FULL_VER) +#define BROTLI_MSVC_VERSION \ + BROTLI_MAKE_VERSION((_MSC_FULL_VER / 1000000), \ + (_MSC_FULL_VER % 1000000) / 10000, \ + (_MSC_FULL_VER % 10000) / 10) +#elif defined(_MSC_VER) +#define BROTLI_MSVC_VERSION \ + BROTLI_MAKE_VERSION(_MSC_VER / 100, _MSC_VER % 100, 0) +#endif + +#if !defined(_MSC_VER) +#define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) (0) +#elif defined(_MSC_VER) && (_MSC_VER >= 1400) +#define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) \ + (_MSC_FULL_VER >= ((major * 10000000) + (minor * 100000) + (patch))) +#elif defined(_MSC_VER) && (_MSC_VER >= 1200) +#define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) \ + (_MSC_FULL_VER >= ((major * 1000000) + (minor * 10000) + (patch))) +#else +#define BROTLI_MSVC_VERSION_CHECK(major, minor, patch) \ + (_MSC_VER >= ((major * 100) + (minor))) +#endif + +#if defined(__INTEL_COMPILER) && defined(__INTEL_COMPILER_UPDATE) +#define BROTLI_INTEL_VERSION \ + BROTLI_MAKE_VERSION(__INTEL_COMPILER / 100, \ + __INTEL_COMPILER % 100, \ + __INTEL_COMPILER_UPDATE) +#elif defined(__INTEL_COMPILER) +#define BROTLI_INTEL_VERSION \ + BROTLI_MAKE_VERSION(__INTEL_COMPILER / 100, __INTEL_COMPILER % 100, 0) +#endif + +#if defined(BROTLI_INTEL_VERSION) +#define BROTLI_INTEL_VERSION_CHECK(major, minor, patch) \ + (BROTLI_INTEL_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch)) +#else +#define BROTLI_INTEL_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(__PGI) && \ + defined(__PGIC__) && defined(__PGIC_MINOR__) && defined(__PGIC_PATCHLEVEL__) +#define BROTLI_PGI_VERSION \ + BROTLI_MAKE_VERSION(__PGIC__, __PGIC_MINOR__, __PGIC_PATCHLEVEL__) +#endif + +#if defined(BROTLI_PGI_VERSION) +#define BROTLI_PGI_VERSION_CHECK(major, minor, patch) \ + (BROTLI_PGI_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch)) +#else +#define BROTLI_PGI_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(__SUNPRO_C) && (__SUNPRO_C > 0x1000) +#define BROTLI_SUNPRO_VERSION \ + BROTLI_MAKE_VERSION( \ + (((__SUNPRO_C >> 16) & 0xf) * 10) + ((__SUNPRO_C >> 12) & 0xf), \ + (((__SUNPRO_C >> 8) & 0xf) * 10) + ((__SUNPRO_C >> 4) & 0xf), \ + (__SUNPRO_C & 0xf) * 10) +#elif defined(__SUNPRO_C) +#define BROTLI_SUNPRO_VERSION \ + BROTLI_MAKE_VERSION((__SUNPRO_C >> 8) & 0xf, \ + (__SUNPRO_C >> 4) & 0xf, \ + (__SUNPRO_C) & 0xf) +#elif defined(__SUNPRO_CC) && (__SUNPRO_CC > 0x1000) +#define BROTLI_SUNPRO_VERSION \ + BROTLI_MAKE_VERSION( \ + (((__SUNPRO_CC >> 16) & 0xf) * 10) + ((__SUNPRO_CC >> 12) & 0xf), \ + (((__SUNPRO_CC >> 8) & 0xf) * 10) + ((__SUNPRO_CC >> 4) & 0xf), \ + (__SUNPRO_CC & 0xf) * 10) +#elif defined(__SUNPRO_CC) +#define BROTLI_SUNPRO_VERSION \ + BROTLI_MAKE_VERSION((__SUNPRO_CC >> 8) & 0xf, \ + (__SUNPRO_CC >> 4) & 0xf, \ + (__SUNPRO_CC) & 0xf) +#endif + +#if defined(BROTLI_SUNPRO_VERSION) +#define BROTLI_SUNPRO_VERSION_CHECK(major, minor, patch) \ + (BROTLI_SUNPRO_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch)) +#else +#define BROTLI_SUNPRO_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(__CC_ARM) && defined(__ARMCOMPILER_VERSION) +#define BROTLI_ARM_VERSION \ + BROTLI_MAKE_VERSION((__ARMCOMPILER_VERSION / 1000000), \ + (__ARMCOMPILER_VERSION % 1000000) / 10000, \ + (__ARMCOMPILER_VERSION % 10000) / 100) +#elif defined(__CC_ARM) && defined(__ARMCC_VERSION) +#define BROTLI_ARM_VERSION \ + BROTLI_MAKE_VERSION((__ARMCC_VERSION / 1000000), \ + (__ARMCC_VERSION % 1000000) / 10000, \ + (__ARMCC_VERSION % 10000) / 100) +#endif + +#if defined(BROTLI_ARM_VERSION) +#define BROTLI_ARM_VERSION_CHECK(major, minor, patch) \ + (BROTLI_ARM_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch)) +#else +#define BROTLI_ARM_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(__ibmxl__) +#define BROTLI_IBM_VERSION \ + BROTLI_MAKE_VERSION(__ibmxl_version__, \ + __ibmxl_release__, \ + __ibmxl_modification__) +#elif defined(__xlC__) && defined(__xlC_ver__) +#define BROTLI_IBM_VERSION \ + BROTLI_MAKE_VERSION(__xlC__ >> 8, __xlC__ & 0xff, (__xlC_ver__ >> 8) & 0xff) +#elif defined(__xlC__) +#define BROTLI_IBM_VERSION BROTLI_MAKE_VERSION(__xlC__ >> 8, __xlC__ & 0xff, 0) +#endif + +#if defined(BROTLI_IBM_VERSION) +#define BROTLI_IBM_VERSION_CHECK(major, minor, patch) \ + (BROTLI_IBM_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch)) +#else +#define BROTLI_IBM_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(__TI_COMPILER_VERSION__) +#define BROTLI_TI_VERSION \ + BROTLI_MAKE_VERSION((__TI_COMPILER_VERSION__ / 1000000), \ + (__TI_COMPILER_VERSION__ % 1000000) / 1000, \ + (__TI_COMPILER_VERSION__ % 1000)) +#endif + +#if defined(BROTLI_TI_VERSION) +#define BROTLI_TI_VERSION_CHECK(major, minor, patch) \ + (BROTLI_TI_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch)) +#else +#define BROTLI_TI_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(__IAR_SYSTEMS_ICC__) +#if __VER__ > 1000 +#define BROTLI_IAR_VERSION \ + BROTLI_MAKE_VERSION((__VER__ / 1000000), \ + (__VER__ / 1000) % 1000, \ + (__VER__ % 1000)) +#else +#define BROTLI_IAR_VERSION BROTLI_MAKE_VERSION(VER / 100, __VER__ % 100, 0) +#endif +#endif + +#if defined(BROTLI_IAR_VERSION) +#define BROTLI_IAR_VERSION_CHECK(major, minor, patch) \ + (BROTLI_IAR_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch)) +#else +#define BROTLI_IAR_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(__TINYC__) +#define BROTLI_TINYC_VERSION \ + BROTLI_MAKE_VERSION(__TINYC__ / 1000, (__TINYC__ / 100) % 10, __TINYC__ % 100) +#endif + +#if defined(BROTLI_TINYC_VERSION) +#define BROTLI_TINYC_VERSION_CHECK(major, minor, patch) \ + (BROTLI_TINYC_VERSION >= BROTLI_MAKE_VERSION(major, minor, patch)) +#else +#define BROTLI_TINYC_VERSION_CHECK(major, minor, patch) (0) +#endif + +#if defined(__has_attribute) +#define BROTLI_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) \ + __has_attribute(attribute) +#else +#define BROTLI_GNUC_HAS_ATTRIBUTE(attribute, major, minor, patch) \ + BROTLI_GNUC_VERSION_CHECK(major, minor, patch) +#endif + +#if defined(__has_builtin) +#define BROTLI_GNUC_HAS_BUILTIN(builtin, major, minor, patch) \ + __has_builtin(builtin) +#else +#define BROTLI_GNUC_HAS_BUILTIN(builtin, major, minor, patch) \ + BROTLI_GNUC_VERSION_CHECK(major, minor, patch) +#endif + +#if defined(__has_feature) +#define BROTLI_HAS_FEATURE(feature) __has_feature(feature) +#else +#define BROTLI_HAS_FEATURE(feature) (0) +#endif + +#if defined(_WIN32) || defined(__CYGWIN__) +#define BROTLI_PUBLIC +#elif BROTLI_GNUC_VERSION_CHECK(3, 3, 0) || \ + BROTLI_TI_VERSION_CHECK(8, 0, 0) || \ + BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \ + BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \ + BROTLI_IBM_VERSION_CHECK(13, 1, 0) || \ + BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + (BROTLI_TI_VERSION_CHECK(7, 3, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__) && defined(__TI_EABI__)) +#define BROTLI_PUBLIC __attribute__ ((visibility ("default"))) +#else +#define BROTLI_PUBLIC +#endif + +#if defined(_WIN32) || defined(__CYGWIN__) +#define BROTLI_INTERNAL +#elif BROTLI_GNUC_VERSION_CHECK(3, 3, 0) || \ + BROTLI_TI_VERSION_CHECK(8, 0, 0) || \ + BROTLI_INTEL_VERSION_CHECK(16, 0, 0) || \ + BROTLI_ARM_VERSION_CHECK(4, 1, 0) || \ + BROTLI_IBM_VERSION_CHECK(13, 1, 0) || \ + BROTLI_SUNPRO_VERSION_CHECK(5, 11, 0) || \ + (BROTLI_TI_VERSION_CHECK(7, 3, 0) && \ + defined(__TI_GNU_ATTRIBUTE_SUPPORT__) && defined(__TI_EABI__)) +#define BROTLI_INTERNAL __attribute__ ((visibility ("hidden"))) +#else +#define BROTLI_INTERNAL +#endif + +#if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) && \ + !defined(__STDC_NO_VLA__) && !defined(__cplusplus) && \ + !defined(__PGI) && !defined(__PGIC__) && !defined(__TINYC__) && \ + !defined(__clang__) +#define BROTLI_ARRAY_PARAM(name) (name) +#else +#define BROTLI_ARRAY_PARAM(name) +#endif + +/* <<< <<< <<< end of hedley macros. */ + +#if defined(BROTLI_SHARED_COMPILATION) +#if defined(_WIN32) +#if defined(BROTLICOMMON_SHARED_COMPILATION) +#define BROTLI_COMMON_API __declspec(dllexport) +#else /* !BROTLICOMMON_SHARED_COMPILATION */ +#define BROTLI_COMMON_API __declspec(dllimport) +#endif /* BROTLICOMMON_SHARED_COMPILATION */ +#if defined(BROTLIDEC_SHARED_COMPILATION) +#define BROTLI_DEC_API __declspec(dllexport) +#else /* !BROTLIDEC_SHARED_COMPILATION */ +#define BROTLI_DEC_API __declspec(dllimport) +#endif /* BROTLIDEC_SHARED_COMPILATION */ +#if defined(BROTLIENC_SHARED_COMPILATION) +#define BROTLI_ENC_API __declspec(dllexport) +#else /* !BROTLIENC_SHARED_COMPILATION */ +#define BROTLI_ENC_API __declspec(dllimport) +#endif /* BROTLIENC_SHARED_COMPILATION */ +#else /* !_WIN32 */ +#define BROTLI_COMMON_API BROTLI_PUBLIC +#define BROTLI_DEC_API BROTLI_PUBLIC +#define BROTLI_ENC_API BROTLI_PUBLIC +#endif /* _WIN32 */ +#else /* BROTLI_SHARED_COMPILATION */ +#define BROTLI_COMMON_API +#define BROTLI_DEC_API +#define BROTLI_ENC_API +#endif + +#if defined(BROTLI_BUILD_ENC_EXTRA_API) +#define BROTLI_ENC_EXTRA_API BROTLI_ENC_API +#else +#define BROTLI_ENC_EXTRA_API BROTLI_INTERNAL +#endif + +#endif /* BROTLI_COMMON_PORT_H_ */ diff --git a/packages/runtime/vendor/brotli/c/include/brotli/shared_dictionary.h b/packages/runtime/vendor/brotli/c/include/brotli/shared_dictionary.h new file mode 100644 index 000000000..2970c2dcc --- /dev/null +++ b/packages/runtime/vendor/brotli/c/include/brotli/shared_dictionary.h @@ -0,0 +1,100 @@ +/* Copyright 2017 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/* (Opaque) Shared Dictionary definition and utilities. */ + +#ifndef BROTLI_COMMON_SHARED_DICTIONARY_H_ +#define BROTLI_COMMON_SHARED_DICTIONARY_H_ + +#include +#include + +#if defined(__cplusplus) || defined(c_plusplus) +extern "C" { +#endif + +#define SHARED_BROTLI_MIN_DICTIONARY_WORD_LENGTH 4 +#define SHARED_BROTLI_MAX_DICTIONARY_WORD_LENGTH 31 +#define SHARED_BROTLI_NUM_DICTIONARY_CONTEXTS 64 +#define SHARED_BROTLI_MAX_COMPOUND_DICTS 15 + +/** + * Opaque structure that holds shared dictionary data. + * + * Allocated and initialized with ::BrotliSharedDictionaryCreateInstance. + * Cleaned up and deallocated with ::BrotliSharedDictionaryDestroyInstance. + */ +typedef struct BrotliSharedDictionaryStruct BrotliSharedDictionary; + +/** + * Input data type for ::BrotliSharedDictionaryAttach. + */ +typedef enum BrotliSharedDictionaryType { + /** Raw LZ77 prefix dictionary. */ + BROTLI_SHARED_DICTIONARY_RAW = 0, + /** Serialized shared dictionary. + * + * DO NOT USE: methods accepting this value will fail. + */ + BROTLI_SHARED_DICTIONARY_SERIALIZED = 1 +} BrotliSharedDictionaryType; + +/** + * Creates an instance of ::BrotliSharedDictionary. + * + * Fresh instance has default word dictionary and transforms + * and no LZ77 prefix dictionary. + * + * @p alloc_func and @p free_func @b MUST be both zero or both non-zero. In the + * case they are both zero, default memory allocators are used. @p opaque is + * passed to @p alloc_func and @p free_func when they are called. @p free_func + * has to return without doing anything when asked to free a NULL pointer. + * + * @param alloc_func custom memory allocation function + * @param free_func custom memory free function + * @param opaque custom memory manager handle + * @returns @c 0 if instance can not be allocated or initialized + * @returns pointer to initialized ::BrotliSharedDictionary otherwise + */ +BROTLI_COMMON_API BrotliSharedDictionary* BrotliSharedDictionaryCreateInstance( + brotli_alloc_func alloc_func, brotli_free_func free_func, void* opaque); + +/** + * Deinitializes and frees ::BrotliSharedDictionary instance. + * + * @param dict shared dictionary instance to be cleaned up and deallocated + */ +BROTLI_COMMON_API void BrotliSharedDictionaryDestroyInstance( + BrotliSharedDictionary* dict); + +/** + * Attaches dictionary to a given instance of ::BrotliSharedDictionary. + * + * Dictionary to be attached is represented in a serialized format as a region + * of memory. + * + * Provided data it partially referenced by a resulting (compound) dictionary, + * and should be kept untouched, while at least one compound dictionary uses it. + * This way memory overhead is kept minimal by the cost of additional resource + * management. + * + * @param dict dictionary to extend + * @param type type of dictionary to attach + * @param data_size size of @p data + * @param data serialized dictionary of type @p type, with at least @p data_size + * addressable bytes + * @returns ::BROTLI_TRUE if provided dictionary is successfully attached + * @returns ::BROTLI_FALSE otherwise + */ +BROTLI_COMMON_API BROTLI_BOOL BrotliSharedDictionaryAttach( + BrotliSharedDictionary* dict, BrotliSharedDictionaryType type, + size_t data_size, const uint8_t data[BROTLI_ARRAY_PARAM(data_size)]); + +#if defined(__cplusplus) || defined(c_plusplus) +} /* extern "C" */ +#endif + +#endif /* BROTLI_COMMON_SHARED_DICTIONARY_H_ */ diff --git a/packages/runtime/vendor/brotli/c/include/brotli/types.h b/packages/runtime/vendor/brotli/c/include/brotli/types.h new file mode 100644 index 000000000..2dc61ff40 --- /dev/null +++ b/packages/runtime/vendor/brotli/c/include/brotli/types.h @@ -0,0 +1,83 @@ +/* Copyright 2013 Google Inc. All Rights Reserved. + + Distributed under MIT license. + See file LICENSE for detail or copy at https://opensource.org/licenses/MIT +*/ + +/** + * @file + * Common types used in decoder and encoder API. + */ + +#ifndef BROTLI_COMMON_TYPES_H_ +#define BROTLI_COMMON_TYPES_H_ + +#include /* IWYU pragma: export */ + +#if defined(_MSC_VER) && (_MSC_VER < 1600) +typedef __int8 int8_t; +typedef unsigned __int8 uint8_t; +typedef __int16 int16_t; +typedef unsigned __int16 uint16_t; +typedef __int32 int32_t; +typedef unsigned __int32 uint32_t; +typedef unsigned __int64 uint64_t; +typedef __int64 int64_t; +#else +#include /* IWYU pragma: export */ +#endif /* defined(_MSC_VER) && (_MSC_VER < 1600) */ + +/** + * A portable @c bool replacement. + * + * ::BROTLI_BOOL is a "documentation" type: actually it is @c int, but in API it + * denotes a type, whose only values are ::BROTLI_TRUE and ::BROTLI_FALSE. + * + * ::BROTLI_BOOL values passed to Brotli should either be ::BROTLI_TRUE or + * ::BROTLI_FALSE, or be a result of ::TO_BROTLI_BOOL macros. + * + * ::BROTLI_BOOL values returned by Brotli should not be tested for equality + * with @c true, @c false, ::BROTLI_TRUE, ::BROTLI_FALSE, but rather should be + * evaluated, for example: @code{.cpp} + * if (SomeBrotliFunction(encoder, BROTLI_TRUE) && + * !OtherBrotliFunction(decoder, BROTLI_FALSE)) { + * bool x = !!YetAnotherBrotliFunction(encoder, TO_BROLTI_BOOL(2 * 2 == 4)); + * DoSomething(x); + * } + * @endcode + */ +#define BROTLI_BOOL int +/** Portable @c true replacement. */ +#define BROTLI_TRUE 1 +/** Portable @c false replacement. */ +#define BROTLI_FALSE 0 +/** @c bool to ::BROTLI_BOOL conversion macros. */ +#define TO_BROTLI_BOOL(X) (!!(X) ? BROTLI_TRUE : BROTLI_FALSE) + +#define BROTLI_MAKE_UINT64_T(high, low) ((((uint64_t)(high)) << 32) | low) + +#define BROTLI_UINT32_MAX (~((uint32_t)0)) +#define BROTLI_SIZE_MAX (~((size_t)0)) + +/** + * Allocating function pointer type. + * + * @param opaque custom memory manager handle provided by client + * @param size requested memory region size; can not be @c 0 + * @returns @c 0 in the case of failure + * @returns a valid pointer to a memory region of at least @p size bytes + * long otherwise + */ +typedef void* (*brotli_alloc_func)(void* opaque, size_t size); + +/** + * Deallocating function pointer type. + * + * This function @b SHOULD do nothing if @p address is @c 0. + * + * @param opaque custom memory manager handle provided by client + * @param address memory region pointer returned by ::brotli_alloc_func, or @c 0 + */ +typedef void (*brotli_free_func)(void* opaque, void* address); + +#endif /* BROTLI_COMMON_TYPES_H_ */ diff --git a/tests/corpus/7714-zlib-brotli-compress.cjs b/tests/corpus/7714-zlib-brotli-compress.cjs new file mode 100644 index 000000000..9f12f35f8 --- /dev/null +++ b/tests/corpus/7714-zlib-brotli-compress.cjs @@ -0,0 +1,91 @@ +// zlib's Brotli compression over the vendored brotli 1.2.0, the version +// Node bundles: compressed bytes match Node's for the same parameters, and +// the options, errors, callback, promisified and stream forms follow Node. +const zlib = require("node:zlib"); +const { promisify } = require("node:util"); + +const text = Buffer.from("hello hello hello brotli ".repeat(20)); +const hex = (b) => b.toString("hex"); +const tryIt = (label, run) => { + try { + const r = run(); + console.log(label, "ok", Buffer.isBuffer(r) ? hex(r) : r); + } catch (e) { + console.log(label, e.name, e.code, e.errno, e.message); + } +}; + +console.log(hex(zlib.brotliCompressSync("")), hex(zlib.brotliCompressSync("a"))); +for (const quality of [0, 1, 4, 5, 9, 11]) { + const out = zlib.brotliCompressSync(text, { params: { [zlib.constants.BROTLI_PARAM_QUALITY]: quality } }); + console.log("quality", quality, out.length, hex(out)); +} +console.log("text mode", hex(zlib.brotliCompressSync(text, { params: { [zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT } }))); +console.log("font mode", hex(zlib.brotliCompressSync(text, { params: { [zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_FONT } }))); +console.log( + "window", + hex(zlib.brotliCompressSync(text, { + params: { [zlib.constants.BROTLI_PARAM_LGWIN]: 10, [zlib.constants.BROTLI_PARAM_SIZE_HINT]: text.length }, + })), +); +console.log("dictionary", hex(zlib.brotliCompressSync("hello world", { dictionary: Buffer.from("hello world") }))); +console.log("arraybuffer dictionary", hex(zlib.brotliCompressSync("hello world", { dictionary: new Uint8Array([104, 101, 108, 108, 111]).buffer }))); +console.log("finishFlush", hex(zlib.brotliCompressSync("hello", { finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH }))); +tryIt("boolean param", () => zlib.brotliCompressSync("x", { params: { [zlib.constants.BROTLI_PARAM_DISABLE_LITERAL_CONTEXT_MODELING]: true } })); +tryIt("fractional quality", () => zlib.brotliCompressSync("hello hello hello", { params: { 1: 4.7 } })); +tryIt("negative quality", () => zlib.brotliCompressSync("hello hello hello", { params: { 1: -1 } })); +tryIt("quality above 11", () => zlib.brotliCompressSync("hello hello hello", { params: { 1: 12 } })); +tryIt("unknown param", () => zlib.brotliCompressSync("x", { params: { 9999: 1 } })); +tryIt("param 9", () => zlib.brotliCompressSync("x", { params: { 9: 0 } })); +tryIt("repeated param", () => zlib.brotliCompressSync("x", { params: { 1: 5, "01": 4 } })); +tryIt("fractional param key", () => zlib.brotliCompressSync("x", { params: { "1.5": 5 } })); +tryIt("negative param key", () => zlib.brotliCompressSync("x", { params: { "-1": 5 } })); +tryIt("string param value", () => zlib.brotliCompressSync("x", { params: { 1: "5" } })); +tryIt("string dictionary", () => zlib.brotliCompressSync("x", { dictionary: "abc" })); +tryIt("chunkSize", () => zlib.brotliCompressSync(text, { chunkSize: 10 })); +tryIt("flush", () => zlib.brotliCompressSync(text, { flush: 4 })); +tryIt("finishFlush range", () => zlib.brotliCompressSync(text, { finishFlush: 99 })); +tryIt("rejectGarbageAfterEnd", () => zlib.brotliCompressSync(text, { rejectGarbageAfterEnd: 1 })); +tryIt("maxOutputLength", () => zlib.brotliCompressSync(text, { maxOutputLength: 8 })); +tryIt("number input", () => zlib.brotliCompressSync(JSON.parse("5"))); + +zlib.brotliCompress(text, (err, out) => { + console.log("callback", err, hex(out)); + zlib.brotliCompress("abc", { params: { [zlib.constants.BROTLI_PARAM_QUALITY]: 2 } }, (err2, out2) => { + console.log("callback options", err2, hex(out2)); + promised(); + }); +}); + +function promised() { + const compress = promisify(zlib.brotliCompress); + compress("promised").then((out) => { + console.log("promisified", hex(out)); + streams(); + }); +} + +function streams() { + const chunks = []; + const stream = zlib.createBrotliCompress({ params: { [zlib.constants.BROTLI_PARAM_QUALITY]: 5 } }); + console.log(stream instanceof zlib.BrotliCompress, stream instanceof zlib.Gzip); + stream.on("data", (chunk) => chunks.push(chunk)); + stream.on("end", () => { + console.log("stream", hex(Buffer.concat(chunks)), stream.bytesWritten); + const second = new zlib.BrotliCompress(); + const parts = []; + second.on("data", (chunk) => parts.push(chunk)); + second.on("end", () => { + console.log("class", hex(Buffer.concat(parts))); + try { zlib.createBrotliCompress({ params: { 99: 1 } }); } catch (e) { console.log(e.code, e.message); } + try { zlib.createBrotliCompress({ flush: 9 }); } catch (e) { console.log(e.code, e.message); } + }); + second.reset(); + second.end("reset first"); + }); + stream.write(text.subarray(0, 100)); + stream.flush(() => { + console.log("flushed", chunks.length > 0); + stream.end(text.subarray(100)); + }); +} diff --git a/tests/corpus/7715-zlib-brotli-decompress.cjs b/tests/corpus/7715-zlib-brotli-decompress.cjs new file mode 100644 index 000000000..c2f826f75 --- /dev/null +++ b/tests/corpus/7715-zlib-brotli-decompress.cjs @@ -0,0 +1,96 @@ +// zlib's Brotli decompression: fixed blobs Node produced, Brotli's own +// error codes (ERR_ + the decoder's error name) and zlib's for truncated +// input, trailing data, maxOutputLength, dictionaries, the decoder +// parameters, and the callback, promisified and stream forms. +const zlib = require("node:zlib"); +const { promisify } = require("node:util"); +const { pipeline, Readable, Writable } = require("node:stream"); + +const hello = Buffer.from("1b1600f88d946ede44558696206c6f350b32b54006543b", "hex"); +const repeated = Buffer.from("1b8713f825f0e2b14020680100", "hex"); +const withDictionary = Buffer.from("1b0a00f8250002980820", "hex"); +const tryIt = (label, run) => { + try { + const r = run(); + console.log(label, "ok", Buffer.isBuffer(r) ? r.length + " " + r.toString().slice(0, 24) : r); + } catch (e) { + console.log(label, e.name, e.code, e.errno, e.message); + } +}; + +tryIt("hello", () => zlib.brotliDecompressSync(hello)); +tryIt("repeated", () => zlib.brotliDecompressSync(repeated)); +tryIt("string input", () => zlib.brotliDecompressSync("abc")); +tryIt("arraybuffer input", () => zlib.brotliDecompressSync(hello.buffer.slice(hello.byteOffset, hello.byteOffset + hello.length))); +for (const hex of ["ff", "ffffffff", "ce", "0b008061", "3b00", "06", "2f", "1bffff00ffffffffffff"]) { + tryIt(hex, () => zlib.brotliDecompressSync(Buffer.from(hex, "hex"))); +} +tryIt("truncated", () => zlib.brotliDecompressSync(hello.subarray(0, 10))); +tryIt("trailing data", () => zlib.brotliDecompressSync(Buffer.concat([hello, Buffer.from("junk")]))); +tryIt("trailing data rejected", () => zlib.brotliDecompressSync(Buffer.concat([hello, Buffer.from("junk")]), { rejectGarbageAfterEnd: true })); +tryIt("maxOutputLength", () => zlib.brotliDecompressSync(repeated, { maxOutputLength: 100 })); +tryIt("small chunks", () => zlib.brotliDecompressSync(repeated, { chunkSize: 64 })); +tryIt("partial with flush", () => zlib.brotliDecompressSync(hello.subarray(0, 8), { finishFlush: zlib.constants.BROTLI_OPERATION_FLUSH })); +tryIt("dictionary", () => zlib.brotliDecompressSync(withDictionary, { dictionary: Buffer.from("hello world") })); +tryIt("missing dictionary", () => zlib.brotliDecompressSync(withDictionary)); +tryIt("large window", () => zlib.brotliDecompressSync(hello, { params: { [zlib.constants.BROTLI_DECODER_PARAM_LARGE_WINDOW]: 1 } })); +tryIt("encoder param", () => zlib.brotliDecompressSync(hello, { params: { [zlib.constants.BROTLI_PARAM_LGWIN]: 10 } })); +tryIt("round trip", () => zlib.brotliDecompressSync(zlib.brotliCompressSync("round trip ".repeat(100))).toString() === "round trip ".repeat(100)); + +zlib.brotliDecompress(hello, (err, out) => { + console.log("callback", err, out.toString()); + zlib.brotliDecompress(Buffer.from([1, 2, 3]), (err2) => { + console.log("callback error", err2.code, err2.errno, err2.message); + promised(); + }); +}); + +function promised() { + const decompress = promisify(zlib.brotliDecompress); + decompress(repeated, { maxOutputLength: 10 }).catch((err) => { + console.log("promisified", err.code, err.message); + streams(); + }); +} + +function streams() { + const out = []; + const stream = zlib.createBrotliDecompress(); + console.log(stream instanceof zlib.BrotliDecompress, stream instanceof zlib.BrotliCompress); + stream.on("data", (chunk) => out.push(chunk)); + stream.on("end", () => { + console.log("stream", Buffer.concat(out).toString(), stream.bytesWritten); + const bad = new zlib.BrotliDecompress(); + bad.on("error", (err) => { + console.log("stream error", err.code, err.errno, err.message); + piped(); + }); + bad.write(Buffer.from("ffff", "hex")); + bad.end(); + }); + stream.write(hello.subarray(0, 5)); + stream.end(hello.subarray(5)); +} + +function piped() { + const sink = []; + pipeline( + Readable.from([Buffer.from("one "), Buffer.from("two "), Buffer.from("three")]), + zlib.createBrotliCompress(), + zlib.createBrotliDecompress(), + new Writable({ + write(chunk, _encoding, callback) { + sink.push(chunk); + callback(); + }, + }), + (err) => { + console.log("pipeline", err, Buffer.concat(sink).toString()); + try { + new zlib.BrotliDecompress({ params: { 3: 1 } }); + } catch (e) { + console.log(e.code, e.message); + } + }, + ); +} diff --git a/tests/corpus/7716-zlib-brotli.ts b/tests/corpus/7716-zlib-brotli.ts new file mode 100644 index 000000000..812cf6fae --- /dev/null +++ b/tests/corpus/7716-zlib-brotli.ts @@ -0,0 +1,47 @@ +// zlib's Brotli forms through their TypeScript types: typed options, +// dictionaries, maxOutputLength, the callback and promisified forms, and the +// BrotliCompress and BrotliDecompress classes. +import * as zlib from "node:zlib"; +import { promisify } from "node:util"; + +const input: string = "typed brotli ".repeat(64); +const compressed: Buffer = zlib.brotliCompressSync(input, { + params: { [zlib.constants.BROTLI_PARAM_QUALITY]: 4, [zlib.constants.BROTLI_PARAM_MODE]: zlib.constants.BROTLI_MODE_TEXT }, +}); +console.log(compressed.toString("base64")); +console.log(zlib.brotliDecompressSync(compressed).toString() === input); +const dict: Buffer = Buffer.from("typed brotli"); +const withDict = zlib.brotliCompressSync(input, { dictionary: dict }); +console.log(withDict.length, zlib.brotliDecompressSync(withDict, { dictionary: dict }).length); +try { + zlib.brotliDecompressSync(compressed, { maxOutputLength: 16 }); +} catch (e) { + const err = e as NodeJS.ErrnoException; + console.log(err.code, err.message); +} +zlib.brotliCompress(Buffer.from("abc"), (err, out) => { + console.log(err, out.toString("hex")); + zlib.brotliDecompress(out, { finishFlush: zlib.constants.BROTLI_OPERATION_FINISH }, (err2, back) => { + console.log(err2, back.toString()); + main(); + }); +}); +const compressAsync = promisify(zlib.brotliCompress); +const decompressAsync = promisify(zlib.brotliDecompress); +async function main(): Promise { + const packed = await compressAsync("promised"); + console.log((await decompressAsync(packed)).toString()); + try { + await decompressAsync(Buffer.from([0xff])); + } catch (e) { + console.log((e as NodeJS.ErrnoException).code); + } + const stream: zlib.BrotliCompress = new zlib.BrotliCompress(); + const parts: Buffer[] = []; + stream.on("data", (c: Buffer) => parts.push(c)); + stream.on("end", () => console.log("stream", Buffer.concat(parts).equals(zlib.brotliCompressSync("streamed")), stream.bytesWritten)); + stream.end("streamed"); + const dec = zlib.createBrotliDecompress(); + dec.reset(); + console.log(dec instanceof zlib.BrotliDecompress); +} diff --git a/tests/diagnostics/node-fallback-fence.ts b/tests/diagnostics/node-fallback-fence.ts index 86034f1ac..b044e22d3 100644 --- a/tests/diagnostics/node-fallback-fence.ts +++ b/tests/diagnostics/node-fallback-fence.ts @@ -30,9 +30,9 @@ const raw = readFileSync("/etc/hosts").toString(tty ? "hex" : "latin1"); // runt const intervalWithSignal = promiseInterval(1, "tick", {}); // AbortSignal options stay fenced const sleepWithSignal = promiseSleep(1, "tick", { signal: AbortSignal.timeout(5) }); // resolve values and AbortSignal options lower // The computed encoding is now part of the static Buffer surface. The -// one-shot zlib/raw/gzip codecs take Node's options, validated at run -// time; Brotli remains an explicit member fence. +// one-shot zlib/raw/gzip and Brotli codecs take Node's options, validated +// at run time. import { brotliCompressSync, deflateSync } from "node:zlib"; const packed = deflateSync("data", { level: 9, strategy: 1 }); // options lower -const brotli = brotliCompressSync(Buffer.from("data")); // outside the lowered family: fenced +const brotli = brotliCompressSync(Buffer.from("data")); // Brotli lowers too // The remaining imports continue the declared-but-not-lowered surface. diff --git a/tests/fixtures/node-types/fenced.ts b/tests/fixtures/node-types/fenced.ts index 0ddf0ea3f..0d90e8cac 100644 --- a/tests/fixtures/node-types/fenced.ts +++ b/tests/fixtures/node-types/fenced.ts @@ -45,9 +45,8 @@ console.log(win32.sep); const u = new URL("https://example.com/x?a=1"); console.log(URL.createObjectURL(new Blob(["data"]))); u.searchParams.get("a"); -/* The one-shot zlib/raw/gzip codecs take Node's options (the deflateSync - * call lowers), while Brotli remains a member-qualified fence with the - * lowered family named. */ +/* The one-shot zlib/raw/gzip and Brotli codecs take Node's options (the + * deflateSync and brotliCompressSync calls lower). */ import { brotliCompressSync, deflateSync } from "zlib"; deflateSync("data", { level: 9, strategy: 1 }); brotliCompressSync(Buffer.from("data")); diff --git a/tests/harness/__snapshots__/node-fallback-fence.ts.txt b/tests/harness/__snapshots__/node-fallback-fence.ts.txt index 9670ca7d0..6cd12532e 100644 --- a/tests/harness/__snapshots__/node-fallback-fence.ts.txt +++ b/tests/harness/__snapshots__/node-fallback-fence.ts.txt @@ -14,13 +14,4 @@ node-fallback-fence.ts:30:28 - error SC2020: 'timers/promises.setInterval with 3 | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 31 | const sleepWithSignal = promiseSleep(1, "tick", { signal: AbortSignal.timeout(5) }); // resolve values and AbortSignal options lower - hint: the lowered form is setInterval(delay, value) with an explicit yielded value; AbortSignal options are not supported yet - -node-fallback-fence.ts:37:16 - error SC2020: 'zlib.brotliCompressSync' is part of the standard library types but has no scriptc lowering yet - - 36 | const packed = deflateSync("data", { level: 9, strategy: 1 }); // options lower - 37 | const brotli = brotliCompressSync(Buffer.from("data")); // outside the lowered family: fenced - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 38 | // The remaining imports continue the declared-but-not-lowered surface. - - hint: Brotli needs a Brotli codec, which the static runtime does not vendor — the deflate/inflate, raw, gzip/gunzip, and unzip sync/callback forms with Node's options, crc32, and the Deflate/Inflate/Gzip/Gunzip/DeflateRaw/InflateRaw/Unzip streams are the lowered zlib surface \ No newline at end of file + hint: the lowered form is setInterval(delay, value) with an explicit yielded value; AbortSignal options are not supported yet \ No newline at end of file diff --git a/tests/harness/__snapshots__/node-types-fenced.txt b/tests/harness/__snapshots__/node-types-fenced.txt index d0aa4a140..32eb08fba 100644 --- a/tests/harness/__snapshots__/node-types-fenced.txt +++ b/tests/harness/__snapshots__/node-types-fenced.txt @@ -79,173 +79,164 @@ fenced.ts:46:13 - error SC2020: 'URL.createObjectURL' is typed by @types/node bu hint: protocol, origin, username, password, pathname, href, host, hostname, port, search, hash, searchParams, toString(), and toJSON() are the supported URL members -fenced.ts:53:1 - error SC2020: 'zlib.brotliCompressSync' is typed by @types/node but has no scriptc lowering yet +fenced.ts:61:71 - error SC2020: 'a createSecureServer SNICallback of 'undefined' values' is part of the standard library types but has no scriptc lowering yet - 52 | deflateSync("data", { level: 9, strategy: 1 }); - 53 | brotliCompressSync(Buffer.from("data")); - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 54 | /* The http2 compatibility slice's @types/node-world fences (divergence - - hint: Brotli needs a Brotli codec, which the static runtime does not vendor — the deflate/inflate, raw, gzip/gunzip, and unzip sync/callback forms with Node's options, crc32, and the Deflate/Inflate/Gzip/Gunzip/DeflateRaw/InflateRaw/Unzip streams are the lowered zlib surface - -fenced.ts:62:71 - error SC2020: 'a createSecureServer SNICallback of 'undefined' values' is part of the standard library types but has no scriptc lowering yet - - 61 | import * as http2 from "node:http2"; - 62 | http2.createSecureServer({ allowHTTP1: true, cert: "pem", key: "pem", SNICallback: undefined }); + 60 | import * as http2 from "node:http2"; + 61 | http2.createSecureServer({ allowHTTP1: true, cert: "pem", key: "pem", SNICallback: undefined }); | ^~~~~~~~~~~~~~~~~~~~~~ - 63 | http2.createSecureServer({ + 62 | http2.createSecureServer({ hint: SNICallback lowers as a direct option or the conditional spread ...(x ? { SNICallback: x } : {}) — the callback is (servername, cb) => void with cb: (err: Error | null, ctx?: tls.SecureContext) => void -fenced.ts:67:3 - error SC2020: 'createSecureServer options with a conditional spread' is part of the standard library types but has no scriptc lowering yet +fenced.ts:66:3 - error SC2020: 'createSecureServer options with a conditional spread' is part of the standard library types but has no scriptc lowering yet - 66 | key: "pem", - 67 | ...(1 ? { SNICallback: undefined } : {}), + 65 | key: "pem", + 66 | ...(1 ? { SNICallback: undefined } : {}), | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 68 | }); + 67 | }); hint: the lowered conditional spread is exactly ...(x ? { SNICallback: x } : {}) — the included value must BE the condition -fenced.ts:69:71 - error SC2020: 'createSecureServer option 'streamResetBurst' with a non-literal value' is part of the standard library types but has no scriptc lowering yet +fenced.ts:68:71 - error SC2020: 'createSecureServer option 'streamResetBurst' with a non-literal value' is part of the standard library types but has no scriptc lowering yet - 68 | }); - 69 | http2.createSecureServer({ allowHTTP1: true, cert: "pem", key: "pem", streamResetBurst: 1 + 0 }); + 67 | }); + 68 | http2.createSecureServer({ allowHTTP1: true, cert: "pem", key: "pem", streamResetBurst: 1 + 0 }); | ^~~~~~~~~~~~~~~~~~~~~~~ - 70 | http2.connect("https://localhost"); + 69 | http2.connect("https://localhost"); hint: h2 session-tuning options are accepted with literal values but are not applied yet -fenced.ts:76:1 - error SC2020: 'crypto.publicEncrypt' is typed by @types/node but has no scriptc lowering yet +fenced.ts:75:1 - error SC2020: 'crypto.publicEncrypt' is typed by @types/node but has no scriptc lowering yet - 75 | import { createCipheriv, publicEncrypt, secureHeapUsed, setFips } from "node:crypto"; - 76 | publicEncrypt("key", Buffer.alloc(1)); + 74 | import { createCipheriv, publicEncrypt, secureHeapUsed, setFips } from "node:crypto"; + 75 | publicEncrypt("key", Buffer.alloc(1)); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 77 | createCipheriv("aes-128-ocb", Buffer.alloc(16), Buffer.alloc(12), { authTagLength: 16 }); + 76 | createCipheriv("aes-128-ocb", Buffer.alloc(16), Buffer.alloc(12), { authTagLength: 16 }); hint: RSA encryption has no lowering — the asymmetric crypto surface is RSA and EC KeyObjects (generateKeyPair, createPrivateKey, createPublicKey), sign, verify, createSign, createVerify, createECDH, and createDiffieHellman -fenced.ts:77:16 - error SC2020: 'crypto.createCipheriv with cipher 'aes-128-ocb'' is part of the standard library types but has no scriptc lowering yet +fenced.ts:76:16 - error SC2020: 'crypto.createCipheriv with cipher 'aes-128-ocb'' is part of the standard library types but has no scriptc lowering yet - 76 | publicEncrypt("key", Buffer.alloc(1)); - 77 | createCipheriv("aes-128-ocb", Buffer.alloc(16), Buffer.alloc(12), { authTagLength: 16 }); + 75 | publicEncrypt("key", Buffer.alloc(1)); + 76 | createCipheriv("aes-128-ocb", Buffer.alloc(16), Buffer.alloc(12), { authTagLength: 16 }); | ^~~~~~~~~~~~~ - 78 | secureHeapUsed(); + 77 | secureHeapUsed(); hint: the supported ciphers are aes-128, aes-192 and aes-256 in cbc, ctr, gcm, ccm, ecb, cfb, cfb8, cfb1 and ofb modes and their wrap, wrap-pad, wrap-inv and wrap-pad-inv key wraps, des-ede3 in cbc, ecb, cfb, cfb8, cfb1 and ofb modes, des-ede in cbc, ecb, cfb and ofb modes, chacha20, and chacha20-poly1305 -fenced.ts:78:1 - error SC2020: 'crypto.secureHeapUsed' is typed by @types/node but has no scriptc lowering yet +fenced.ts:77:1 - error SC2020: 'crypto.secureHeapUsed' is typed by @types/node but has no scriptc lowering yet - 77 | createCipheriv("aes-128-ocb", Buffer.alloc(16), Buffer.alloc(12), { authTagLength: 16 }); - 78 | secureHeapUsed(); + 76 | createCipheriv("aes-128-ocb", Buffer.alloc(16), Buffer.alloc(12), { authTagLength: 16 }); + 77 | secureHeapUsed(); | ^~~~~~~~~~~~~~~~ - 79 | setFips(false); + 78 | setFips(false); hint: the type checker sees everything @types/node declares, but only the supported surface compiles (https://scriptc.dev/limitations) -fenced.ts:79:1 - error SC2020: 'crypto.setFips' is typed by @types/node but has no scriptc lowering yet +fenced.ts:78:1 - error SC2020: 'crypto.setFips' is typed by @types/node but has no scriptc lowering yet - 78 | secureHeapUsed(); - 79 | setFips(false); + 77 | secureHeapUsed(); + 78 | setFips(false); | ^~~~~~~~~~~~~~ - 80 | fetch("https://example.invalid/", { + 79 | fetch("https://example.invalid/", { hint: a compiled binary has no FIPS provider to enable, and Node itself throws on setFips(true) in a non-FIPS build — getFips() answers 0 here -fenced.ts:81:3 - error SC2020: 'RequestInit option 'integrity' in a static build' is typed by @types/node but has no scriptc lowering yet +fenced.ts:80:3 - error SC2020: 'RequestInit option 'integrity' in a static build' is typed by @types/node but has no scriptc lowering yet - 80 | fetch("https://example.invalid/", { - 81 | integrity: "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", + 79 | fetch("https://example.invalid/", { + 80 | integrity: "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=", | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 82 | }); + 81 | }); hint: the compiler does not preserve this RequestInit member's conversion or transport behavior -fenced.ts:85:3 - error SC2020: 'ReadableStream.tee' is typed by @types/node but has no scriptc lowering yet +fenced.ts:84:3 - error SC2020: 'ReadableStream.tee' is typed by @types/node but has no scriptc lowering yet - 84 | const body = (await fetch(url)).body!; - 85 | body.tee(); + 83 | const body = (await fetch(url)).body!; + 84 | body.tee(); | ^~~~~~~~ - 86 | const tee = body.tee; + 85 | const tee = body.tee; hint: this operation is outside the native readable-stream implementation -fenced.ts:86:15 - error SC2020: 'ReadableStream.tee' is typed by @types/node but has no scriptc lowering yet +fenced.ts:85:15 - error SC2020: 'ReadableStream.tee' is typed by @types/node but has no scriptc lowering yet - 85 | body.tee(); - 86 | const tee = body.tee; + 84 | body.tee(); + 85 | const tee = body.tee; | ^~~~~~~~ - 87 | body["tee"](); + 86 | body["tee"](); hint: this operation is outside the native readable-stream implementation -fenced.ts:87:3 - error SC2020: 'ReadableStream.tee' is typed by @types/node but has no scriptc lowering yet +fenced.ts:86:3 - error SC2020: 'ReadableStream.tee' is typed by @types/node but has no scriptc lowering yet - 86 | const tee = body.tee; - 87 | body["tee"](); + 85 | const tee = body.tee; + 86 | body["tee"](); | ^~~~~~~~~~~ - 88 | const bracketTee = body["tee"]; + 87 | const bracketTee = body["tee"]; hint: this operation is outside the native readable-stream implementation -fenced.ts:88:22 - error SC2020: 'ReadableStream.tee' is typed by @types/node but has no scriptc lowering yet +fenced.ts:87:22 - error SC2020: 'ReadableStream.tee' is typed by @types/node but has no scriptc lowering yet - 87 | body["tee"](); - 88 | const bracketTee = body["tee"]; + 86 | body["tee"](); + 87 | const bracketTee = body["tee"]; | ^~~~~~~~~~~ - 89 | } + 88 | } hint: this operation is outside the native readable-stream implementation -fenced.ts:94:23 - error SC2020: 'util.callbackify into a callback whose error parameter excludes null' is part of the standard library types but has no scriptc lowering yet +fenced.ts:93:23 - error SC2020: 'util.callbackify into a callback whose error parameter excludes null' is part of the standard library types but has no scriptc lowering yet - 93 | import { callbackify } from "node:util"; - 94 | const callbackified = callbackify(async (n: number) => n); + 92 | import { callbackify } from "node:util"; + 93 | const callbackified = callbackify(async (n: number) => n); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 95 | void callbackified; + 94 | void callbackified; hint: Node calls back with a null error on success; type the binding's callback as (err: NodeJS.ErrnoException | null, ...) => void -fenced.ts:100:12 - error SC2020: 'crypto.createECDH with curve 'sect163k1'' is part of the standard library types but has no scriptc lowering yet +fenced.ts:99:12 - error SC2020: 'crypto.createECDH with curve 'sect163k1'' is part of the standard library types but has no scriptc lowering yet - 99 | import { createECDH } from "node:crypto"; - 100 | createECDH("sect163k1"); + 98 | import { createECDH } from "node:crypto"; + 99 | createECDH("sect163k1"); | ^~~~~~~~~~~ - 101 | createECDH("prime256v1").computeSecret(Buffer.alloc(65), "hex"); + 100 | createECDH("prime256v1").computeSecret(Buffer.alloc(65), "hex"); hint: the supported curves are prime192v1, secp224r1, prime256v1, secp384r1, secp521r1, secp192k1, secp224k1, secp256k1, brainpoolP256r1, brainpoolP384r1, and brainpoolP512r1 -fenced.ts:101:1 - error SC2020: 'ECDH.computeSecret(key, encoding) with a Buffer or view key' is part of the standard library types but has no scriptc lowering yet +fenced.ts:100:1 - error SC2020: 'ECDH.computeSecret(key, encoding) with a Buffer or view key' is part of the standard library types but has no scriptc lowering yet - 100 | createECDH("sect163k1"); - 101 | createECDH("prime256v1").computeSecret(Buffer.alloc(65), "hex"); + 99 | createECDH("sect163k1"); + 100 | createECDH("prime256v1").computeSecret(Buffer.alloc(65), "hex"); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 102 | /* DiffieHellman's Object.prototype members. */ + 101 | /* DiffieHellman's Object.prototype members. */ hint: Node reads the second argument as the key's input encoding and answers a Buffer; pass the output encoding third: computeSecret(key, undefined, encoding) -fenced.ts:104:1 - error SC2020: 'DiffieHellman.toString' is part of the standard library types but has no scriptc lowering yet +fenced.ts:103:1 - error SC2020: 'DiffieHellman.toString' is part of the standard library types but has no scriptc lowering yet - 103 | import { createDiffieHellman } from "node:crypto"; - 104 | createDiffieHellman(Buffer.from([23])).toString(); + 102 | import { createDiffieHellman } from "node:crypto"; + 103 | createDiffieHellman(Buffer.from([23])).toString(); | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 105 | /* WebCrypto beyond the secret-key slice: @types/node declares the whole + 104 | /* WebCrypto beyond the secret-key slice: @types/node declares the whole hint: generateKeys(), computeSecret(), getPrime(), getGenerator(), getPublicKey(), getPrivateKey(), setPublicKey(), setPrivateKey() and verifyError are supported -fenced.ts:109:9 - error SC2020: 'crypto.subtle.getPublicKey' is part of the standard library types but has no scriptc lowering yet +fenced.ts:108:9 - error SC2020: 'crypto.subtle.getPublicKey' is part of the standard library types but has no scriptc lowering yet - 108 | async function publicKeyWithWebCrypto(key: import("node:crypto").webcrypto.CryptoKey): Promise { - 109 | await crypto.subtle.getPublicKey(key, ["verify"]); + 107 | async function publicKeyWithWebCrypto(key: import("node:crypto").webcrypto.CryptoKey): Promise { + 108 | await crypto.subtle.getPublicKey(key, ["verify"]); | ^~~~~~~~~~~~~~~~~~~~~~~~~~ - 110 | } + 109 | } hint: the native WebCrypto surface is crypto.subtle's importKey, generateKey and exportKey for HMAC and AES keys (importKey also for PBKDF2 and HKDF keys), encrypt and decrypt with AES-GCM, AES-CBC or AES-CTR, wrapKey and unwrapKey of secret keys with AES-KW or those ciphers, deriveBits and deriveKey with PBKDF2 or HKDF, sign and verify with HMAC, generateKey, importKey, exportKey, sign and verify for ECDSA, Ed25519, RSASSA-PKCS1-v1_5 and RSA-PSS, and digest with SHA-1, SHA-256, SHA-384 or SHA-512, each called directly on crypto.subtle -fenced.ts:114:15 - error SC2020: 'navigator.hardwareConcurrency' is typed by @types/node but has no scriptc lowering yet +fenced.ts:113:15 - error SC2020: 'navigator.hardwareConcurrency' is typed by @types/node but has no scriptc lowering yet - 113 | * compile; the other members fence by name. */ - 114 | const cores = navigator.hardwareConcurrency; + 112 | * compile; the other members fence by name. */ + 113 | const cores = navigator.hardwareConcurrency; | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 115 | void cores; + 114 | void cores; hint: of Node's navigator global only typeof navigator and navigator.userAgent compile \ No newline at end of file diff --git a/tests/harness/corpus-costs/7714-zlib-brotli-compress.cjs.json b/tests/harness/corpus-costs/7714-zlib-brotli-compress.cjs.json new file mode 100644 index 000000000..7c5c28b59 --- /dev/null +++ b/tests/harness/corpus-costs/7714-zlib-brotli-compress.cjs.json @@ -0,0 +1 @@ +{ "plain": 5362, "san": 120966 } diff --git a/tests/harness/corpus-costs/7715-zlib-brotli-decompress.cjs.json b/tests/harness/corpus-costs/7715-zlib-brotli-decompress.cjs.json new file mode 100644 index 000000000..de8ec5e7a --- /dev/null +++ b/tests/harness/corpus-costs/7715-zlib-brotli-decompress.cjs.json @@ -0,0 +1 @@ +{ "plain": 4974, "san": 112620 } diff --git a/tests/harness/corpus-costs/7716-zlib-brotli.ts.json b/tests/harness/corpus-costs/7716-zlib-brotli.ts.json new file mode 100644 index 000000000..a4b393de1 --- /dev/null +++ b/tests/harness/corpus-costs/7716-zlib-brotli.ts.json @@ -0,0 +1 @@ +{ "plain": 3930, "san": 108068 } diff --git a/tests/harness/library-mode.test.ts b/tests/harness/library-mode.test.ts index db4fabb3e..7eecd3c93 100644 --- a/tests/harness/library-mode.test.ts +++ b/tests/harness/library-mode.test.ts @@ -1060,13 +1060,13 @@ describe.each(EMISSIONS)("K14: determinism fences, %s emission", (emission) => { test("a manifest-id-keyed teachings entry attaches to that surface's own refusal", async () => { const diags = await refusal( - `import { brotliCompressSync } from "node:zlib";\nexport function f(): number { return brotliCompressSync("data").length; }\n`, + `import { createRequire } from "node:module";\nexport function f(): number { return createRequire("/x") === undefined ? 0 : 1; }\n`, { exports: [{ export: "f", symbol: "kx_f", params: [], returns: "f64" }], determinism: { teachings: { - "node-builtin.zlib.brotliCompressSync": - "compression runs in the host; request it as an effect", + "node-builtin.module.createRequire": + "module state is the host's; request it as an effect", }, }, }, @@ -1075,20 +1075,20 @@ describe.each(EMISSIONS)("K14: determinism fences, %s emission", (emission) => { // The surface's own code, not a fence code: the id key attaches text // to the refusal that already fires. expect(diags[0]!.code).toBe("SC2020"); - expect(diags[0]!.message).toContain("zlib.brotliCompressSync"); + expect(diags[0]!.message).toContain("module.createRequire"); expect(diags[0]!.note).toBe( - "from the 'refusal-fixture' profile: compression runs in the host; request it as an effect", + "from the 'refusal-fixture' profile: module state is the host's; request it as an effect", ); }); test("fencing a surface the static tier refuses anyway changes only the message", async () => { const diags = await refusal( - `import { brotliCompressSync } from "node:zlib";\nexport function f(): number { return brotliCompressSync("data").length; }\n`, + `import { createRequire } from "node:module";\nexport function f(): number { return createRequire("/x") === undefined ? 0 : 1; }\n`, { exports: [{ export: "f", symbol: "kx_f", params: [], returns: "f64" }], determinism: { fences: [ - { id: "node-builtin.zlib.brotliCompressSync", teaching: "compression is host work" }, + { id: "node-builtin.module.createRequire", teaching: "module state is host work" }, ], }, }, @@ -1097,6 +1097,6 @@ describe.each(EMISSIONS)("K14: determinism fences, %s emission", (emission) => { // The existing refusal's code survives — the fence never re-codes a // surface that already refuses; its teaching rides as the note. expect(diags[0]!.code).toBe("SC2020"); - expect(diags[0]!.note).toBe("from the 'refusal-fixture' profile: compression is host work"); + expect(diags[0]!.note).toBe("from the 'refusal-fixture' profile: module state is host work"); }); }); From 0dfea3c6420a8f3558fc55e34ce4a8e00844e5b6 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Fri, 23 Oct 2026 15:15:33 -0700 Subject: [PATCH 032/259] Reject class capsules of other classes without materializing them A dynMatch helper for a class target tested the capsule's class key and, when it did not match, materialized the capsule's view and matched that. A materialized view is a plain object, which never matches a class target, so the answer was always false: the helper now answers false directly. Checked casts from unknown to unions of classes no longer build a view per non-matching arm (1,000 casts x 2,000 rounds: 255 ms -> 67 ms). Co-Authored-By: Claude Opus 5.5 --- packages/compiler/src/backend/llvm/dyn.ts | 5 +- .../7991-unknown-class-union-casts.ts.json | 6 ++ .../corpus/7991-unknown-class-union-casts.ts | 70 +++++++++++++++++++ .../7991-unknown-class-union-casts.ts.json | 1 + 4 files changed, 81 insertions(+), 1 deletion(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7991-unknown-class-union-casts.ts.json create mode 100644 tests/corpus/7991-unknown-class-union-casts.ts create mode 100644 tests/harness/corpus-costs/7991-unknown-class-union-casts.ts.json diff --git a/packages/compiler/src/backend/llvm/dyn.ts b/packages/compiler/src/backend/llvm/dyn.ts index 136798796..0e220d349 100644 --- a/packages/compiler/src/backend/llvm/dyn.ts +++ b/packages/compiler/src/backend/llvm/dyn.ts @@ -979,7 +979,10 @@ export class LlDyn { const lPlain = B.newLabel("dm.tr.plain"); B.condBr(capsule, lCapsule, lPlain); B.startBlock(lCapsule); - if (preserveRefs) { + // A class target matches only capsules of that class (tested above): + // a materialized view is a plain object, which never carries a class + // brand, so materializing one cannot change the answer. + if (preserveRefs || (t.kind === "object" && t.className !== "%Error")) { B.terminate(`ret i1 false`); } else { const materialized = B.tmp(); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7991-unknown-class-union-casts.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7991-unknown-class-union-casts.ts.json new file mode 100644 index 000000000..68185e837 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7991-unknown-class-union-casts.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7991-unknown-class-union-casts.ts" + ], + "diags": [] +} diff --git a/tests/corpus/7991-unknown-class-union-casts.ts b/tests/corpus/7991-unknown-class-union-casts.ts new file mode 100644 index 000000000..6560abbc2 --- /dev/null +++ b/tests/corpus/7991-unknown-class-union-casts.ts @@ -0,0 +1,70 @@ +// Checked casts from `unknown` to unions of classes: each instance selects +// its own arm, whatever the order of the arms, including subclasses, arrays +// of instances, instances inside records, and values of no listed class. +class Circle { + readonly r: number; + constructor(r: number) { + this.r = r; + } + area(): number { + return Math.round(Math.PI * this.r * this.r); + } +} +class Square { + readonly side: number; + constructor(side: number) { + this.side = side; + } + area(): number { + return this.side * this.side; + } +} +class Rect { + readonly w: number; + readonly h: number; + constructor(w: number, h: number) { + this.w = w; + this.h = h; + } + area(): number { + return this.w * this.h; + } +} +class Tile extends Square { + label(): string { + return `tile ${this.side}`; + } +} + +type Shape = Circle | Square | Rect; + +function describe(value: unknown): string { + try { + const shape = value as Shape; + const kind = shape instanceof Circle ? "circle" : shape instanceof Rect ? "rect" : "square"; + return `${kind} ${shape.area()}`; + } catch (error) { + return `rejected: ${(error as Error).name}`; + } +} + +const values: unknown[] = [new Circle(2), new Square(3), new Rect(2, 5), new Tile(4), { side: 3 }, 7, null]; +for (const value of values) console.log(describe(value)); + +const reversed = values.slice(0, 4).reverse() as Shape[]; +console.log(reversed.map((s) => s.area()).join(",")); + +const boxed: unknown = { first: new Rect(1, 2), second: new Circle(1) }; +const pair = boxed as { first: Shape; second: Shape }; +console.log(pair.first.area(), pair.second.area(), pair.first instanceof Rect); + +const tiles: unknown = [new Tile(1), new Tile(2)]; +const asSquares = tiles as Square[]; +console.log(asSquares.map((t) => t.area()).join(" "), asSquares[0] instanceof Tile); + +let total = 0; +for (let i = 0; i < 1000; i++) { + const v: unknown = i % 3 === 0 ? new Circle(1) : i % 3 === 1 ? new Square(2) : new Rect(1, 3); + total += (v as Shape).area(); +} +console.log(total); diff --git a/tests/harness/corpus-costs/7991-unknown-class-union-casts.ts.json b/tests/harness/corpus-costs/7991-unknown-class-union-casts.ts.json new file mode 100644 index 000000000..263ca9783 --- /dev/null +++ b/tests/harness/corpus-costs/7991-unknown-class-union-casts.ts.json @@ -0,0 +1 @@ +{ "plain": 4400 } From 1b5c90549a8cf3f38de568cfb43bdd220544fdbb Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Fri, 23 Oct 2026 17:44:00 -0700 Subject: [PATCH 033/259] Answer Error.prototype for Object.getPrototypeOf of an Error An Error's view had no prototype or a holder of its default name and message, so Object.getPrototypeOf(new Error()) was Object.prototype or a fresh object. A view of an error built as an Error, whose prototype is still the one its view starts with, now answers Error.prototype. Co-Authored-By: Claude Opus 5.5 --- .../8115-error-prototype-identity.js.json | 6 +++ packages/runtime/src/scr_json.c | 23 ++++++++++ tests/corpus/8115-error-prototype-identity.js | 46 +++++++++++++++++++ 3 files changed, 75 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8115-error-prototype-identity.js.json create mode 100644 tests/corpus/8115-error-prototype-identity.js diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8115-error-prototype-identity.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8115-error-prototype-identity.js.json new file mode 100644 index 000000000..f4a6f13f0 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8115-error-prototype-identity.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8115-error-prototype-identity.js" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 40fd73508..b318114a3 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -2189,8 +2189,11 @@ ScrDyn *scr_dyn_obj_create(ScrDyn *prototype) { return object; } +static bool scr_dyn_error_view_on_error_prototype(const ScrDyn *object); + ScrDyn *scr_dyn_get_prototype(ScrDyn *object) { if (object == scr_builtin_object_prototype) return scr_dyn_new_null(); + if (object->kind == SCR_DYN_OBJ && scr_dyn_error_view_on_error_prototype(object)) return scr_dyn_error_prototype(); if (scr_dyn_class_reflection_fence(object)) return NULL; if (object->kind == SCR_DYN_TYPED_REF && strncmp(object->v.typed_ref.type_key, "object:", 7)) { ScrDyn *view = scr_dyn_typed_ref_materialize(object); @@ -8841,6 +8844,26 @@ static void scr_error_dyn_add_stack(ScrDyn *d) { entry->enumerable = false; } +/* Whether `object` is the view of an error built as an Error (not a + * subclass or another error kind) whose prototype is still the one its view + * starts with: none, or the holder of its default `name` and `message` + * (scr_error_dyn_fields). Such an error's prototype is Error.prototype. */ +static bool scr_dyn_error_view_on_error_prototype(const ScrDyn *object) { + const ScrDyn *holder = object->prototype; + if (object->null_proto) return false; + if (holder) { + if (holder->kind != SCR_DYN_OBJ || holder->prototype || holder->null_proto || holder->v.obj.len > 2) return false; + for (size_t i = 0; i < holder->v.obj.len; i++) { + const ScrDynEntry *entry = &holder->v.obj.entries[i]; + bool known = (entry->key_len == 4 && memcmp(entry->key, "name", 4) == 0) || + (entry->key_len == 7 && memcmp(entry->key, "message", 7) == 0); + if (!known || entry->enumerable || entry->accessor) return false; + } + } + size_t hit = scr_errdyn_find(object, false); + return hit != SIZE_MAX && scr_errdyn_cache[hit].err->vt == &scr_error_vts[SCR_ERR_ERROR]; +} + ScrDyn *scr_error_dyn_fields(const ScrError *e) { ScrDyn *d = scr_dyn_new_obj(); scr_dyn_obj_set(d, "%error", 6, scr_dyn_new_bool(true)); /* the checked-dynamic tree's error marker */ diff --git a/tests/corpus/8115-error-prototype-identity.js b/tests/corpus/8115-error-prototype-identity.js new file mode 100644 index 000000000..1eda2c2c0 --- /dev/null +++ b/tests/corpus/8115-error-prototype-identity.js @@ -0,0 +1,46 @@ +"use strict"; +// Object.getPrototypeOf of an Error is Error.prototype, whose own prototype +// is Object.prototype: with or without a message, after its name is +// reassigned, and when it was thrown and caught. + +const describe = (label, value) => { + const proto = Object.getPrototypeOf(value); + console.log(label, proto === Error.prototype, proto === Object.prototype, Object.getPrototypeOf(proto) === Object.prototype); +}; + +describe("message", new Error("boom")); +describe("empty", new Error()); +const renamed = new Error("x"); +renamed.name = "Custom"; +describe("renamed", renamed); +const coded = new Error("y"); +coded.code = "E_CODE"; +describe("coded", coded); +try { + throw new Error("thrown"); +} catch (error) { + describe("caught", error); +} + +// Walks up the chain, as error serializers and type sniffers do. +/** @param {unknown} value */ +function chainLength(value) { + let length = 0; + for (let current = Object.getPrototypeOf(value); current !== null; current = Object.getPrototypeOf(current)) length++; + return length; +} +console.log(chainLength(new Error("a")), chainLength({}), chainLength([])); + +/** @param {unknown} value */ +function kind(value) { + if (typeof value !== "object" || value === null) return typeof value; + const proto = Object.getPrototypeOf(value); + if (proto === Object.prototype || proto === null) return "plain"; + if (proto === Error.prototype) return "error"; + if (proto === Array.prototype) return "array"; + return "other"; +} +const values = [new Error("e"), {}, Object.create(null), [], JSON.parse('{"a":1}'), "s"]; +console.log(values.map(kind).join(",")); +const proto = Object.getPrototypeOf(new Error("m")); +console.log(proto.name, JSON.stringify(proto.message), Object.prototype.hasOwnProperty.call(proto, "name")); From c0d6c34f78df6c6a852a703c9c1f6b505ec589e3 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 20:02:25 -0500 Subject: [PATCH 034/259] Compare integer values without converting them to doubles Two kinds of number compares still went through doubles when the integers were already at hand. Integer typed-array elements and `charCodeAt` results are integers or NaN (past the end). A compare of two such values, or of one and an exact integer, all within int32 (or all within uint32), now compares their 32-bit views, which hold ToUint32 of the value, as signed (or unsigned) integers, and folds in an ordered test of each double: NaN makes `<`, `<=`, `>`, `>=` and `===` false and `!==` true, as before. A sum, difference or product of two operands that always equal their doubles, such as `2 * i + 1` of a speculated counter, has a double that is its integer rounded once, even past 2^53. Rounding is monotonic, and the neighbors of a safe integer are doubles, so such a value compares with an exact safe integer as its integer does: the compare uses the i64s. A product by a power of two never rounds, so its wide view always equals its double. --- .../compiler/src/backend/llvm/expr-context.ts | 3 + .../src/backend/llvm/expr-primitives.ts | 76 ++++++++- .../src/backend/llvm/integer-values.ts | 49 +++++- .../test/integer-view-compares.test.ts | 16 +- .../corpus/7983-integer-compares.ts.json | 6 + tests/corpus/7983-integer-compares.ts | 150 ++++++++++++++++++ .../7983-integer-compares.ts.json | 1 + 7 files changed, 287 insertions(+), 14 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7983-integer-compares.ts.json create mode 100644 tests/corpus/7983-integer-compares.ts create mode 100644 tests/harness/corpus-costs/7983-integer-compares.ts.json diff --git a/packages/compiler/src/backend/llvm/expr-context.ts b/packages/compiler/src/backend/llvm/expr-context.ts index c6dc506f4..ac5262571 100644 --- a/packages/compiler/src/backend/llvm/expr-context.ts +++ b/packages/compiler/src/backend/llvm/expr-context.ts @@ -30,6 +30,9 @@ export interface WideInteger { name: string; below: number; bound: number; + /** The double is the integer rounded once: the result of one operation on + * operands that always equal their doubles. */ + single?: true; } export type ExprOf = Extract; diff --git a/packages/compiler/src/backend/llvm/expr-primitives.ts b/packages/compiler/src/backend/llvm/expr-primitives.ts index 04af0fcef..370056ec4 100644 --- a/packages/compiler/src/backend/llvm/expr-primitives.ts +++ b/packages/compiler/src/backend/llvm/expr-primitives.ts @@ -13,13 +13,14 @@ import { emitStringInputs } from "./string-lifetimes.js"; import { emitStringParts, numberPart, stringParts } from "./string-construction.js"; import { emitBorrowedInputs } from "./borrowed-inputs.js"; import { - alwaysExactInteger, + exactCompareOperands, exactInteger, int32Number, integerNumber, narrowInteger, wideArithmetic, widenInteger, + type LlInteger, } from "./integer-values.js"; import { bitwiseIdentityOperand, @@ -45,7 +46,7 @@ import { slotWidth, type ArrayAccess, } from "./dense-array-access.js"; -import { emitWrappingSum, markWrappingOperands } from "./wrapping-sums.js"; +import { emitWrappingSum, integerOrNaNRange, markWrappingOperands } from "./wrapping-sums.js"; /** The signed integer predicates of the number compares. */ const INTEGER_COMPARES: Record = { @@ -57,6 +58,63 @@ const INTEGER_COMPARES: Record = { "!==": "ne", }; +const UNSIGNED_COMPARES: Record = { + "<": "ult", + "<=": "ule", + ">": "ugt", + ">=": "uge", + "===": "eq", + "!==": "ne", +}; + +/** A number compare of operands that are each an exact integer or an + * integer-or-NaN value (integerOrNaNRange: integer typed-array elements, + * `charCodeAt` results, sums of those), all within int32 or all within + * uint32: their 32-bit views compared, and NaN comparing false (unequal for + * `!==`). The 32-bit view is the value's ToUint32, which holds its bits + * whenever it is not NaN. Null when an operand has no such view. */ +function emitIntegerOrNaNCompare( + host: LlvmEmitterContext, + e: ExprOf<"bin">, + l: LlValue, + li: LlInteger | null, + r: LlValue, + ri: LlInteger | null, +): string | null { + const lr = li?.range ?? integerOrNaNRange(host, e.left), + rr = ri?.range ?? integerOrNaNRange(host, e.right); + if (!lr || !rr) return null; + const signed = withinInt32(lr) && withinInt32(rr); + if (!signed && !(withinUint32(lr) && withinUint32(rr))) return null; + const bits = (value: LlValue, integer: LlInteger | null): string | undefined => + integer ? narrowInteger(host, integer) : value.uint32; + const left = bits(l, li), + right = bits(r, ri); + if (left === undefined || right === undefined) return null; + const B = host.B; + const compare = B.tmp(); + B.line( + `${compare} = icmp ${(signed ? INTEGER_COMPARES : UNSIGNED_COMPARES)[e.op]} i32 ${left}, ${right}`, + ); + let result = compare; + for (const [value, integer] of [ + [l, li], + [r, ri], + ] as const) { + if (integer) continue; + const ordered = B.tmp(), + combined = B.tmp(); + B.line(`${ordered} = fcmp ord double ${value.name}, 0.0`); + if (e.op === "!==") { + const unordered = B.tmp(); + B.line(`${unordered} = xor i1 ${ordered}, true`); + B.line(`${combined} = or i1 ${result}, ${unordered}`); + } else B.line(`${combined} = and i1 ${result}, ${ordered}`); + result = combined; + } + return result; +} + export function emitLiteralExpr( host: LlvmEmitterContext, e: ExprOf<"numLit" | "boolLit" | "strLit" | "moduleNsRef" | "unitLit" | "varRef">, @@ -360,14 +418,16 @@ export function emitOperatorExpr( return value; } } else { - // An operand with only a wide view, such as `i + 1` of a speculated - // counter: compare the integers when both always equal the doubles. - const left = alwaysExactInteger(host, l, li), - right = left === null ? null : alwaysExactInteger(host, r, ri); - if (left !== null && right !== null) { - B.line(`${t} = icmp ${INTEGER_COMPARES[e.op]} i64 ${left}, ${right}`); + // An operand with only a wide view, such as `i + 1` or `2 * i + 1` + // of a speculated counter: compare the integers when that gives the + // doubles' result. + const operands = exactCompareOperands(host, l, li, r, ri); + if (operands) { + B.line(`${t} = icmp ${INTEGER_COMPARES[e.op]} i64 ${operands[0]}, ${operands[1]}`); return { name: t, type: e.type }; } + const nanCoded = emitIntegerOrNaNCompare(host, e, l, li, r, ri); + if (nanCoded) return { name: nanCoded, type: e.type }; B.line(`${t} = fcmp ${cmp[e.op]} double ${l.name}, ${r.name}`); } } else if (bit[e.op] !== undefined) { diff --git a/packages/compiler/src/backend/llvm/integer-values.ts b/packages/compiler/src/backend/llvm/integer-values.ts index 90954f4c6..497eb5b0d 100644 --- a/packages/compiler/src/backend/llvm/integer-values.ts +++ b/packages/compiler/src/backend/llvm/integer-values.ts @@ -111,13 +111,17 @@ export function wideArithmetic( rv = view(r, ri); if (!lv || !rv) return null; let below: number, bound: number; + let single = false; if (op === "*") { if (lv.below !== Infinity || rv.below !== Infinity) return null; - below = EXACT_DOUBLES; bound = productBound(lv.bound, rv.bound); + // Scaling by a power of two never rounds a double that stays finite. + below = powerOfTwo(li) || powerOfTwo(ri) ? Infinity : EXACT_DOUBLES; + single = true; } else if (lv.below === Infinity && rv.below === Infinity) { below = EXACT_DOUBLES; bound = sumBound(lv.bound, rv.bound); + single = true; } else if (lv.below === Infinity || rv.below === Infinity) { const [exact, wide] = lv.below === Infinity ? [lv, rv] : [rv, lv]; below = Math.min(wide.below - exact.bound, EXACT_DOUBLES); @@ -132,7 +136,48 @@ export function wideArithmetic( host.B.line( `${name} = ${op === "+" ? "add" : op === "-" ? "sub" : "mul"} nsw i64 ${left}, ${right}`, ); - return { name, below, bound }; + return single ? { name, below, bound, single } : { name, below, bound }; +} + +/** Whether an exact integer is the constant 2^k or -2^k. */ +function powerOfTwo(integer: LlInteger | null): boolean { + if (integer === null || integer.range.min !== integer.range.max) return false; + const value = Math.abs(integer.range.min); + return value >= 1 && value <= 2 ** 52 && Number.isInteger(Math.log2(value)); +} + +/** The i64 operands of a number compare that gives the doubles' result: + * both equal their doubles wherever they can be, or one is an exact integer + * of magnitude at most 2^53 - 1 and the other's double is its integer + * rounded once. Rounding is monotonic, and b - 1, b and b + 1 are doubles + * for a safe integer b, so an integer rounded once compares with b as the + * integer does. Null for any other pair. */ +export function exactCompareOperands( + host: LlvmEmitterContext, + l: LlValue, + li: LlInteger | null, + r: LlValue, + ri: LlInteger | null, +): [string, string] | null { + const describe = (value: LlValue, integer: LlInteger | null) => { + if (integer) return { exact: true, single: true, bound: magnitude(integer.range) }; + const wide = value.wideInteger; + if (!wide) return null; + return { exact: wide.bound <= wide.below, single: wide.single === true, bound: wide.bound }; + }; + const a = describe(l, li), + b = describe(r, ri); + if (!a || !b) return null; + const safe = (d: { exact: boolean; bound: number }): boolean => + d.exact && d.bound <= Number.MAX_SAFE_INTEGER; + const ok = + (a.exact && b.exact) || + (safe(a) && (b.exact || b.single)) || + (safe(b) && (a.exact || a.single)); + if (!ok) return null; + const operand = (value: LlValue, integer: LlInteger | null): string => + integer ? widenInteger(host, integer) : value.wideInteger!.name; + return [operand(l, li), operand(r, ri)]; } /** An i64 index for a consumer that compares it, unsigned, with a length or diff --git a/packages/compiler/test/integer-view-compares.test.ts b/packages/compiler/test/integer-view-compares.test.ts index e988d48bd..4e814368d 100644 --- a/packages/compiler/test/integer-view-compares.test.ts +++ b/packages/compiler/test/integer-view-compares.test.ts @@ -22,7 +22,7 @@ siftDown(a, 0, Number(process.argv[2] ?? "5")); console.log(Array.from(a).join()); `; -test("integer sums of speculated locals compare and index as integers", async () => { +test("integer values compare and index as integers", async () => { const dir = await mkdtemp(join(tmpdir(), "scriptc-integer-views-")); try { const entry = join(dir, "sift.ts"); @@ -43,9 +43,17 @@ test("integer sums of speculated locals compare and index as integers", async () expect(uses("icmp slt").length).toBeGreaterThan(0); // and `a[child + 1]` bounds the integer index without a double round trip. expect(uses("icmp ult").length).toBeGreaterThan(0); - // `2 * root + 1 < end` may pass 2^53, so it keeps the double compare. - expect(body).toMatch(/fmul double 0x4000000000000000, %t\d+\n\s+%t\d+ = mul nsw i64 2/); - expect(body).toContain("fcmp olt double"); + // `2 * root + 1` may pass 2^53, but its double is its integer rounded + // once (doubling is exact) and `end` is a safe integer, so the integers + // compare as the doubles do. + const doubled = /(%t\d+) = mul nsw i64 2, %t\d+\n/.exec(body)![1]!; + const plusOne = new RegExp(`(%t\\d+) = add nsw i64 \\${doubled}, 1\\n`).exec(body)![1]!; + expect(body).toMatch(new RegExp(`= icmp slt i64 \\${plusOne}, %t\\d+\\n`)); + // `a[child]! < a[child + 1]!` compares the elements' int32 bits, and is + // false when either read is out of range (NaN). + const ordered = String.raw`\s+%t\d+ = fcmp ord double %t\d+, 0\.0\n\s+%t\d+ = and i1 %t\d+, %t\d+\n`; + expect(body).toMatch(new RegExp(String.raw`icmp slt i32 %t\d+, %t\d+\n(${ordered}){2}`)); + expect(body).toMatch(new RegExp(String.raw`icmp sge i32 %t\d+, %t\d+\n(${ordered}){2}`)); } finally { await rm(dir, { recursive: true, force: true }); } diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7983-integer-compares.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7983-integer-compares.ts.json new file mode 100644 index 000000000..f7c61e778 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7983-integer-compares.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7983-integer-compares.ts" + ], + "diags": [] +} diff --git a/tests/corpus/7983-integer-compares.ts b/tests/corpus/7983-integer-compares.ts new file mode 100644 index 000000000..1114df8a8 --- /dev/null +++ b/tests/corpus/7983-integer-compares.ts @@ -0,0 +1,150 @@ +// Compares of integer values that are not doubles in the generated code: +// typed-array elements and char codes, which read as NaN past the end, and +// sums such as `2 * i + 1` whose double is the integer rounded once, near and +// past 2^53. + +function countPairs(a: Int32Array): string { + // `j` runs one past the end, where `a[j]` is NaN and every order compare + // is false. + let lt = 0; + let ge = 0; + let eq = 0; + let ne = 0; + for (let i = 0; i < a.length; i++) { + for (let j = 0; j <= a.length; j++) { + if (a[i]! < a[j]!) lt++; + if (a[i]! >= a[j]!) ge++; + if (a[i]! === a[j]!) eq++; + if (a[i]! !== a[j]!) ne++; + } + } + return `${lt} ${ge} ${eq} ${ne}`; +} + +function pastTheEnd(a: Int32Array, b: Uint8Array, c: Uint32Array): string { + const n = a.length; + const out: boolean[] = []; + out.push(a[n]! < a[0]!, a[n]! > a[0]!, a[n]! <= a[n]!, a[n]! === a[0]!, a[0]! !== a[n]!); + out.push(a[n]! < 0, a[n]! >= -1, a[-1]! < a[0]!, b[n]! <= b[0]!, b[0]! !== b[n]!); + out.push(c[n]! < c[0]!, c[n]! >= c[n]!, c[0]! === c[0]!, c[n]! !== c[0]!); + out.push(a[0]! < b[n]!, b[0]! >= a[n]!, a[0]! < c[n]!); + return out.map((v) => (v ? 1 : 0)).join(""); +} + +function unsigned(c: Uint32Array): string { + // Elements above 2^31 compare as unsigned values. + let below = 0; + let above = 0; + let same = 0; + for (let i = 0; i < c.length; i++) { + for (let j = 0; j < c.length; j++) { + if (c[i]! < c[j]!) below++; + if (c[i]! > c[j]!) above++; + if (c[i]! === c[j]!) same++; + } + } + return `${below} ${above} ${same}`; +} + +function mixed(a: Int32Array, b: Uint8Array, c: Uint32Array, d: Int16Array): string { + let count = 0; + for (let i = 0; i < a.length; i++) { + if (a[i]! < b[i]!) count += 1; + if (a[i]! < c[i]!) count += 10; + if (c[i]! > d[i]!) count += 100; + if (b[i]! >= d[i]!) count += 1000; + if (a[i]! === c[i]!) count += 10000; + } + return String(count); +} + +function charCodes(s: string): string { + // `s.charCodeAt(s.length)` is NaN. + let rising = 0; + let falls = 0; + let equal = 0; + let differ = 0; + for (let i = 0; i < s.length; i++) { + if (s.charCodeAt(i) < s.charCodeAt(i + 1)) rising++; + if (s.charCodeAt(i) >= s.charCodeAt(i + 1)) falls++; + if (s.charCodeAt(i) === s.charCodeAt(i + 1)) equal++; + if (s.charCodeAt(i) !== s.charCodeAt(i + 1)) differ++; + } + return `${rising} ${falls} ${equal} ${differ}`; +} + +function heapChildren(start: number, end: number, steps: number): string { + // `2 * i + 1` passes 2^53 for `i` at or above 2^52, where its double + // rounds; `end` stays a safe integer. + const out: string[] = []; + for (let i = start; i < start + steps; i++) { + const child = 2 * i + 1; + out.push( + [2 * i + 1 < end, 2 * i + 1 <= end, 2 * i + 1 > end, 2 * i + 1 === end, 2 * i + 1 !== end] + .map((v) => (v ? 1 : 0)) + .join("") + ` ${child}`, + ); + } + return out.join(" "); +} + +function countNear(start: number, end: number, steps: number): string { + // The same compares in a loop over integer locals only, stopping early if + // `i` reaches `end`. + let lt = 0; + let le = 0; + let gt = 0; + let eq = 0; + let ne = 0; + for (let i = start; i < start + steps && i !== end; i++) { + if (2 * i + 1 < end) lt++; + if (2 * i + 1 <= end) le++; + if (2 * i + 1 > end) gt++; + if (2 * i + 1 === end) eq++; + if (2 * i + 1 !== end) ne++; + } + return `${lt} ${le} ${gt} ${eq} ${ne}`; +} + +function descend(root: number, end: number): number { + // A sift-down's index walk: doubles `root` until `2 * root + 1` reaches `end`. + let steps = 0; + while (2 * root + 1 < end) { + root = 2 * root + 1; + steps++; + } + return steps * 1000 + (root % 1000); +} + +function scaled(i: number, end: number): string { + // Products by a power of two never round: 4 * i and 1024 * i compare exactly. + return [4 * i < end, 4 * i === end, 1024 * i - 1 < end, 3 * i + 1 < end, 2 * i - 1 > -end] + .map((v) => (v ? 1 : 0)) + .join(""); +} + +const a = new Int32Array([5, -3, 2147483647, -2147483648, 5, 0]); +const b = new Uint8Array([0, 255, 7, 128, 5, 0]); +const c = new Uint32Array([4294967295, 2147483648, 2147483647, 0, 1, 4294967295]); +const d = new Int16Array([-32768, 32767, -1, 1, 5, 0]); +console.log(countPairs(a)); +console.log(countPairs(new Int32Array(0))); +console.log(pastTheEnd(a, b, c)); +console.log(unsigned(c)); +console.log(mixed(a, b, c, d)); +console.log(charCodes("abcddcbaÿ￿\u0000")); +console.log(charCodes("")); +const p52 = 2 ** 52; +const safe = Number.MAX_SAFE_INTEGER; +console.log(heapChildren(p52 - 2, safe, 5)); +console.log(heapChildren(p52 - 2, safe - 1, 5)); +console.log(heapChildren(p52 + 100, safe, 3)); +console.log(heapChildren(-p52 - 2, -safe, 5)); +console.log(heapChildren(0, 4, 4)); +console.log(countNear(p52 - 3, safe, 6), countNear(p52 - 3, safe - 2, 6), countNear(p52, safe, 4)); +console.log(countNear(-p52 - 3, -safe, 6), countNear(-p52 + 1, -safe + 4, 4), countNear(0, 7, 6)); +console.log(descend(0, safe), descend(1, safe), descend(p52 - 1, safe), descend(p52, safe)); +console.log(descend(3, 100), descend(0, 1), descend(5, 0)); +for (const i of [0, 1, p52 / 2 - 1, p52 / 2, p52 / 1024, p52 / 2 + 1, p52, -p52]) { + console.log(scaled(i, safe), scaled(i, safe - 1), scaled(i, 2 ** 51), scaled(i, 4)); +} diff --git a/tests/harness/corpus-costs/7983-integer-compares.ts.json b/tests/harness/corpus-costs/7983-integer-compares.ts.json new file mode 100644 index 000000000..8bfb69ce2 --- /dev/null +++ b/tests/harness/corpus-costs/7983-integer-compares.ts.json @@ -0,0 +1 @@ +{ "plain": 2000, "san": 2100 } From 17f1351b6fb0b2dff23ef8d9fc5d5a07b4700477 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 20:12:40 -0500 Subject: [PATCH 035/259] Fix the CI failures --- packages/compiler/src/native/executable-cache.test.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/compiler/src/native/executable-cache.test.ts b/packages/compiler/src/native/executable-cache.test.ts index 3199ef97f..91762f046 100644 --- a/packages/compiler/src/native/executable-cache.test.ts +++ b/packages/compiler/src/native/executable-cache.test.ts @@ -40,6 +40,11 @@ function fixture(debug = false) { const library = join(sdk, "libSystem.tbd"); writeFileSync(runtime, "runtime"); writeFileSync(library, "system library"); + // A directory's identity is its stat. Where the file system stamps times + // at the kernel tick, a file added within the tick of the last write + // leaves the directory's times unchanged; an old time makes every later + // change to the SDK directory visible. + utimesSync(sdk, 0, 0); const cache = new NativeCache(join(root, "cache")); const key = contentDigest("llvm and options"); const open = () => new NativeExecutableCache(cache, key, "clang", debug, [runtime]); From 7bce848e4d69c044e7d5595a2f59f19b8e33eb84 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 20:13:09 -0500 Subject: [PATCH 036/259] Freeze class instances held in untyped values Object.freeze, Object.seal and Object.preventExtensions of a class instance held in an untyped value threw SC2020 at run time. Node changes the instance itself: writes through its typed references then throw the read-only TypeError in strict mode code, adding properties through any reference fails, and Object.isFrozen, isSealed and isExtensible report the state through either reference. - In a program that freezes, seals or prevents extensions of an untyped value that is not a fresh literal, every class hierarchy that can be held there gets the integrity word that static Object.freeze already uses, and with it the existing write checks. - The runtime applies the operation to the instance's checked view and commits the view. The commit of such a hierarchy stores the view's integrity state in the word (scr_dyn_class_view_integrity) and makes the instance's property bag not extensible with it. A hierarchy without the word still throws SC2020. - These commits replace and remove the bag's field entries whatever their attributes, so a sealed or frozen view does not leave stale field values in the bag. - The analysis behind records and arrays now starts from these calls only, rather than from every untyped freeze the lowering emits, such as the frozen strings array of a tagged template. - Programs without such calls compile as before. The runtime ABI moves to v38. Corpus 7407 covers freeze, seal and preventExtensions through unknown of classes and subclasses, writes through typed and untyped references and through methods, properties added before and after the operation, and the integrity queries, and matches Node. Refs #1374 Co-authored-by: blurname <50226652+blurname@users.noreply.github.com> --- .../builtin-apis/object-freezing.mdx | 3 +- packages/cli/test/native-link-info.test.ts | 4 +- packages/compiler/src/backend/llvm/emitter.ts | 10 +- .../src/backend/llvm/expr-stream-bridges.ts | 28 +++- packages/compiler/src/backend/runtime-abi.ts | 4 +- .../src/backend/runtime-pack-targets.test.ts | 2 +- .../compiler/src/backend/runtime-pack.test.ts | 2 +- .../src/frontend/lowering/class-attributes.ts | 24 ++- .../lowering/expressions/property-access.ts | 2 + .../src/frontend/lowering/frozen-records.ts | 20 ++- .../src/frontend/lowering/lower-calls.ts | 7 +- .../compiler/src/frontend/lowering/lowerer.ts | 7 +- packages/compiler/src/ir/ir.ts | 5 + packages/compiler/src/ir/validate.ts | 2 + .../compiler/test/class-attributes.test.ts | 30 ++++ .../test/native-codegen-integration.test.ts | 4 +- .../7407-frozen-class-instances.ts.json | 6 + .../runtime-darwin-arm64/scripts/build.mjs | 2 +- .../runtime-pack-common/scripts/build.mjs | 2 +- packages/runtime/src/scr_console.c | 2 +- packages/runtime/src/scr_core.h | 2 +- packages/runtime/src/scr_dyn.h | 9 ++ packages/runtime/src/scr_json.c | 96 +++++++++--- tests/corpus/7407-frozen-class-instances.ts | 143 ++++++++++++++++++ .../7407-frozen-class-instances.ts.json | 1 + .../self-hosting-native-toolchain.test.ts | 2 +- 26 files changed, 372 insertions(+), 47 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7407-frozen-class-instances.ts.json create mode 100644 tests/corpus/7407-frozen-class-instances.ts create mode 100644 tests/harness/corpus-costs/7407-frozen-class-instances.ts.json diff --git a/docs/content/limitations/builtin-apis/object-freezing.mdx b/docs/content/limitations/builtin-apis/object-freezing.mdx index 99b78ded5..030b03b4b 100644 --- a/docs/content/limitations/builtin-apis/object-freezing.mdx +++ b/docs/content/limitations/builtin-apis/object-freezing.mdx @@ -4,7 +4,8 @@ Class instances support `Object.freeze`, `Object.seal`, `Object.preventExtensions`, `Object.isFrozen`, `Object.isSealed`, and `Object.isExtensible` when the static type of the argument names the class. A write to a read-only field throws Node's `TypeError` in strict mode code and leaves the field unchanged in sloppy mode code. `Object.defineProperty` with a string-literal key changes the value, `writable`, `enumerable`, and `configurable` attributes of a declared field; an object-literal accessor descriptor (`get` or `set`) for a declared field is refused at compile time with `SC2020`, and another accessor descriptor for a declared field throws `SC2020` when the call runs. - Freezing, sealing, or preventing extensions of a class instance held in an untyped value throws `SC2020`. + `Object.freeze`, `Object.seal`, and `Object.preventExtensions` of a class instance held in an untyped value change the instance itself, so writes through its typed references are checked the same way. + The `TypeError` for a write to a read-only property that was added to a class instance through an untyped value names `#` where Node names the class. Functions support `Object.freeze`, `Object.seal`, `Object.preventExtensions`, `Object.isFrozen`, `Object.isSealed`, and `Object.isExtensible`; the operations apply to the function's own properties (`name`, `length`, `prototype`, and the ones a program assigns). Class constructors are not supported. A write to a read-only property of a checked dictionary or a function throws a `TypeError` whose message omits Node's `'x' of object '#'` (or `of function '…'`) suffix. diff --git a/packages/cli/test/native-link-info.test.ts b/packages/cli/test/native-link-info.test.ts index 8ac579449..f85b6908f 100644 --- a/packages/cli/test/native-link-info.test.ts +++ b/packages/cli/test/native-link-info.test.ts @@ -72,7 +72,7 @@ describe.runIf(supported)("macOS arm64 native link info", () => { minimum_os: "14.0", }, program: { object, entry_symbol: "main" }, - runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + runtime_abi: { version: 38, marker: "scr_runtime_abi_v38" }, runtime_pack: { kind: "precompiled", package: "@scriptc/runtime-darwin-arm64", @@ -165,6 +165,6 @@ describe.runIf(supported)("macOS arm64 native link info", () => { () => null, (failure: { stderr?: string }) => failure, ); - expect(error?.stderr).toContain("scr_runtime_abi_v37"); + expect(error?.stderr).toContain("scr_runtime_abi_v38"); }); }); diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 8106a6478..3bf1c34d7 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -1387,6 +1387,10 @@ export class LlEmitter { * commit back into their objects. Library builds keep their commits: * their values cross a native boundary. */ readonly liveViewsReadOnly: boolean; + /** The program freezes, seals or prevents extensions of untyped values + * (IrModule.untypedIntegrity): the commits of class views store the + * view's integrity state in the instance's integrity word. */ + readonly untypedIntegrity: boolean; /** Functions whose direct calls use i32 parameters or results. */ readonly int32Abis: ReadonlyMap; /** Pure number functions with speculative integer clones. */ @@ -1599,8 +1603,12 @@ export class LlEmitter { initializerBindings: this.initializerBindings, nodes: this.nodeIndex, }); + this.untypedIntegrity = mod.untypedIntegrity === true; this.liveViewsReadOnly = - mod.lib === undefined && !dynamicStores.all && dynamicStores.names.size === 0; + mod.lib === undefined && + !this.untypedIntegrity && + !dynamicStores.all && + dynamicStores.names.size === 0; this.int32Abis = this.debug === null ? findInt32Abis(mod, this.int32Slots) : new Map(); this.immortalGlobals = new Set(mod.contracts?.immortalGlobals ?? []); this.programLifetime = new Set(mod.contracts?.programLifetime ?? []); diff --git a/packages/compiler/src/backend/llvm/expr-stream-bridges.ts b/packages/compiler/src/backend/llvm/expr-stream-bridges.ts index 1acc75cec..757e4349f 100644 --- a/packages/compiler/src/backend/llvm/expr-stream-bridges.ts +++ b/packages/compiler/src/backend/llvm/expr-stream-bridges.ts @@ -437,10 +437,14 @@ export function streamTypedRefCommitAdapter( host.declare(`declare ptr @scr_str_new(ptr, ${host.sizeType})`); host.declare(`declare void @scr_str_release(ptr)`); host.declare(`declare void @scr_dyn_key_delete(ptr, ptr, i1 zeroext)`); + // The view of a sealed or frozen instance holds its fields as + // non-configurable entries, which the bag copies. + const withAttributes = meta.def.fields.some((field) => field.name === CLASS_ATTRIBUTES); + const placeholderSet = withAttributes ? "scr_dyn_obj_set_field" : "scr_dyn_obj_set"; if (meta.def.tracksOwnFields) { host.declare(`declare ptr @scr_dyn_retain_v(ptr)`); - host.declare(`declare void @scr_dyn_obj_set(ptr, ptr, ${host.sizeType}, ptr)`); - } + host.declare(`declare void @${placeholderSet}(ptr, ptr, ${host.sizeType}, ptr)`); + } else if (withAttributes) host.declare(`declare void @scr_dyn_obj_delete_field(ptr, ptr)`); lines.push( ` %bag = call ptr @scr_dyn_new_obj()`, ` %bag_copy = call ptr @scr_dyn_copy_property_descriptors(ptr %bag, ptr %d)`, @@ -477,14 +481,16 @@ export function streamTypedRefCommitAdapter( `bag_field${index}_present:`, ` %bag_undefined${index} = call ptr @scr_dyn_undefined()`, ` %bag_placeholder${index} = call ptr @scr_dyn_retain_v(ptr %bag_undefined${index})`, - ` call void @scr_dyn_obj_set(ptr %bag, ptr ${host.cstr(field.name)}, ${host.sizeType} ${Buffer.byteLength(field.name, "utf8")}, ptr %bag_placeholder${index})`, + ` call void @${placeholderSet}(ptr %bag, ptr ${host.cstr(field.name)}, ${host.sizeType} ${Buffer.byteLength(field.name, "utf8")}, ptr %bag_placeholder${index})`, ` br label %bag_field${index}_after`, `bag_field${index}_after:`, ); else lines.push( ` %bag_key${index} = call ptr @scr_str_new(ptr ${host.cstr(field.name)}, ${host.sizeType} ${Buffer.byteLength(field.name, "utf8")})`, - ` call void @scr_dyn_key_delete(ptr %bag, ptr %bag_key${index}, i1 zeroext false)`, + withAttributes + ? ` call void @scr_dyn_obj_delete_field(ptr %bag, ptr %bag_key${index})` + : ` call void @scr_dyn_key_delete(ptr %bag, ptr %bag_key${index}, i1 zeroext false)`, ` call void @scr_str_release(ptr %bag_key${index})`, ); }); @@ -516,6 +522,20 @@ export function streamTypedRefCommitAdapter( host.declare(`declare void @scr_error_commit_dyn(ptr, ptr)`); lines.push(` call void @scr_error_commit_dyn(ptr %target, ptr %d)`); } + // Untyped Object.freeze, seal and preventExtensions apply to the view; + // the instance's integrity word records them. + if (host.untypedIntegrity && meta.def.fields.some((field) => field.name === CLASS_ATTRIBUTES)) { + const bag = meta.def.fields.some((field) => field.name === DYN_CLASS_PROPERTIES) + ? "%bag" + : "null"; + host.declare(`declare double @scr_dyn_class_view_integrity(ptr, double, ptr)`); + lines.push( + ` %word_ptr = getelementptr inbounds %${classStructSym(t.className)}, ptr %target, i64 0, i32 ${classFieldIndex(meta, CLASS_ATTRIBUTES).index}`, + ` %word = load double, ptr %word_ptr`, + ` %word_next = call double @scr_dyn_class_view_integrity(ptr %d, double %word, ptr ${bag})`, + ` store double %word_next, ptr %word_ptr`, + ); + } lines.push(` br label %done`, `done:`, ` ret void`, `}`, ``); host.resolveThunkDefs.push(...lines); return `@${commit}`; diff --git a/packages/compiler/src/backend/runtime-abi.ts b/packages/compiler/src/backend/runtime-abi.ts index 11bde6c2b..612cd2b2e 100644 --- a/packages/compiler/src/backend/runtime-abi.ts +++ b/packages/compiler/src/backend/runtime-abi.ts @@ -2,8 +2,8 @@ * of the link contract: a program object keeps this symbol undefined and the * matching runtime defines it, so incompatible manual links fail before the * program can start. */ -export const RUNTIME_ABI_VERSION = 37 as const; -export const RUNTIME_ABI_MARKER = "scr_runtime_abi_v37" as const; +export const RUNTIME_ABI_VERSION = 38 as const; +export const RUNTIME_ABI_MARKER = "scr_runtime_abi_v38" as const; /** Object consumption is useful today, but the complete scr_* surface may * still change before 1.0. The versioned marker prevents accidental mixing; diff --git a/packages/compiler/src/backend/runtime-pack-targets.test.ts b/packages/compiler/src/backend/runtime-pack-targets.test.ts index 9846e8d89..5227f6062 100644 --- a/packages/compiler/src/backend/runtime-pack-targets.test.ts +++ b/packages/compiler/src/backend/runtime-pack-targets.test.ts @@ -52,7 +52,7 @@ async function fixture(target: NativeTargetSpec, workers = false) { object_format: target.objectFormat, minimum_os: target.minimumOs, }, - runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + runtime_abi: { version: 38, marker: "scr_runtime_abi_v38" }, compiler: { command: "fixture", identity: "fixture", target: target.llvmTriple }, macros: { executable: [], excluded: ["SCR_LIB"], sanitizer: "external-toolchain-required" }, flavors: { diff --git a/packages/compiler/src/backend/runtime-pack.test.ts b/packages/compiler/src/backend/runtime-pack.test.ts index e2b24f8ca..e401d5ed2 100644 --- a/packages/compiler/src/backend/runtime-pack.test.ts +++ b/packages/compiler/src/backend/runtime-pack.test.ts @@ -128,7 +128,7 @@ async function fixture(target: NativeTargetSpec = MACOS_ARM64_TARGET) { object_format: target.objectFormat, minimum_os: target.minimumOs, }, - runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + runtime_abi: { version: 38, marker: "scr_runtime_abi_v38" }, compiler: { command: "clang", identity: "fixture clang", diff --git a/packages/compiler/src/frontend/lowering/class-attributes.ts b/packages/compiler/src/frontend/lowering/class-attributes.ts index 4e7bbe801..de7cc8ca7 100644 --- a/packages/compiler/src/frontend/lowering/class-attributes.ts +++ b/packages/compiler/src/frontend/lowering/class-attributes.ts @@ -39,8 +39,14 @@ import { runtimeRooted } from "./class-descriptors.js"; type ClassObjectType = Extract; function attributeClass(lowerer: Lowerer, target: IrExpr): ClassInfo | null { - if (!isDynTypedRefType(target.type)) return null; - const info = lowerer.classes.get(target.type.className); + return isDynTypedRefType(target.type) + ? attributeClassNamed(lowerer, target.type.className) + : null; +} + +/** The compiled class `className`, when its instances can carry attributes. */ +function attributeClassNamed(lowerer: Lowerer, className: string): ClassInfo | null { + const info = lowerer.classes.get(className); if (!info || runtimeRooted(info) || info.decl == null) return null; return info; } @@ -62,6 +68,20 @@ function addHiddenField(info: ClassInfo, name: string): void { add(root); } +/** In a program that freezes, seals or prevents extensions of untyped + * values, gives every hierarchy whose instances can be held there the + * integrity word. The runtime applies the operation to the instance's + * checked view, whose commit stores the view's integrity state in the word + * (backend streamTypedRefCommitAdapter), and the write checks below read + * it. */ +export function addUntypedIntegrityWords(lowerer: Lowerer): void { + if (!lowerer.untypedIntegrity) return; + for (const [className, info] of lowerer.classes) { + if (isDynTypedRefType({ kind: "object", className }) && attributeClassNamed(lowerer, className)) + addHiddenField(info, CLASS_ATTRIBUTES); + } +} + function hiddenFieldGet(receiver: IrExpr, className: string, field: string, loc: SrcLoc): IrExpr { return { kind: "fieldGet", obj: receiver, className, field, type: F64, loc }; } diff --git a/packages/compiler/src/frontend/lowering/expressions/property-access.ts b/packages/compiler/src/frontend/lowering/expressions/property-access.ts index 1a4883e5a..4ef003f81 100644 --- a/packages/compiler/src/frontend/lowering/expressions/property-access.ts +++ b/packages/compiler/src/frontend/lowering/expressions/property-access.ts @@ -499,6 +499,8 @@ export function lowerPropertyAccessExpr( }; } if (lowerer.stdlibGlobalMember(expr, "Object") === "freeze") { + // Object.freeze as a value can freeze any untyped value it is passed. + lowerer.untypedIntegrity = true; const name = "%builtin.Object.freeze"; if (!lowerer.liftedFns.some((fn) => fn.name === name)) lowerer.liftedFns.push({ diff --git a/packages/compiler/src/frontend/lowering/frozen-records.ts b/packages/compiler/src/frontend/lowering/frozen-records.ts index 30eb9e455..fc770a0cb 100644 --- a/packages/compiler/src/frontend/lowering/frozen-records.ts +++ b/packages/compiler/src/frontend/lowering/frozen-records.ts @@ -24,7 +24,8 @@ import { isStrictCode } from "./strict-mode.js"; * (scr_array.h SCR_ARR_FROZEN), which the backend's array write guards test * for the array types the module lists (IrModule.freezableArrays). A type is * freezable when a static Object.freeze names it, or, in a program that - * freezes untyped values, when a value of it or of a type reaching it can be + * freezes, seals or prevents extensions of untyped values + * (noteUntypedIntegrity), when a value of it or of a type reaching it can be * held as a live untyped reference. */ type RecordType = Extract; @@ -59,6 +60,17 @@ export function lowerNativeFreeze( }; } +/** Records that the program freezes, seals or prevents extensions of the + * untyped value `node` lowers to. Unless it is a fresh object or array + * literal, the value can be any record, array or class instance the program + * holds as an untyped reference, so those types become freezable. */ +export function noteUntypedIntegrity(lowerer: Lowerer, node: ts.Expression): void { + let inner = node; + while (ts.isParenthesizedExpression(inner) || ts.isAsExpression(inner)) inner = inner.expression; + if (!ts.isObjectLiteralExpression(inner) && !ts.isArrayLiteralExpression(inner)) + lowerer.untypedIntegrity = true; +} + function isRecordWrite(s: IrStmt): s is RecordWrite { return s.kind === "recordSet" || s.kind === "recordKeySet" || s.kind === "recordKeyDelete"; } @@ -109,7 +121,6 @@ function freezableTypes( const shapes = new Set(); const arrays = new Set(); const live: IrType[] = []; - let dynFreeze = false; for (const fn of functions) everyStmtList(fn.body, { expr: (e) => { @@ -119,13 +130,12 @@ function freezableTypes( } else if (e.kind === "libCall" && e.fn === "array.freeze") { const target = e.args[0]; if (target && target.type.kind === "array") arrays.add(typeKey(target.type)); - } else if (e.kind === "libCall" && e.fn === "dyn.freeze") dynFreeze = true; - else if (e.kind === "dynFrom") live.push(e.value.type); + } else if (e.kind === "dynFrom") live.push(e.value.type); return true; }, stmt: () => true, }); - if (!dynFreeze) return { shapes, arrays }; + if (!lowerer.untypedIntegrity) return { shapes, arrays }; // An untyped reference to a class instance, or to a record or array // boxed live, reaches the values its fields and elements hold as further // live references. Class instances also cross into untyped code through diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 8ac97fd32..0db330077 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -249,7 +249,7 @@ import { import { fenceSymbolFieldCopy } from "./symbol-fields.js"; import { lowerClassDataDescriptor, lowerClassDescriptorRead } from "./class-descriptors.js"; import { lowerClassFieldDefine, lowerClassIntegrity } from "./class-attributes.js"; -import { freezableRecordType, lowerNativeFreeze } from "./frozen-records.js"; +import { freezableRecordType, lowerNativeFreeze, noteUntypedIntegrity } from "./frozen-records.js"; import { classStaticDataFor } from "./class-static-data.js"; import { lowerUrlFactory } from "./lower-url.js"; import { nullishValueUnitOf } from "./binding-analysis.js"; @@ -8544,6 +8544,7 @@ function lowerObjectStaticCall( isSealed: "dyn.isSealed", } as const; const fn = operation[member as keyof typeof operation]; + if (!member.startsWith("is")) noteUntypedIntegrity(lowerer, call.arguments.nodes[0]!); return { kind: "libCall", fn, @@ -8610,8 +8611,10 @@ function lowerObjectStaticCall( (ts.isObjectLiteralExpression(inner) || ts.isArrayLiteralExpression(inner)) ? lowerer.lowerExprExpecting(argNode, DYN) : lowerer.lowerExpr(argNode); - if (value.type.kind === "dyn") + if (value.type.kind === "dyn") { + noteUntypedIntegrity(lowerer, argNode); return { kind: "libCall", fn: "dyn.freeze", args: [value], type: DYN, loc: locOf(call) }; + } if (ts.isObjectLiteralExpression(inner) || ts.isArrayLiteralExpression(inner)) { return value; // fresh — freeze is identity here, honestly } diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 3582e8e8a..f14f20265 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -151,7 +151,7 @@ import type { FsPathPlan } from "./builtins/fs-paths.js"; import { defaultAfterUndefined, lowerStaticallyUndefinedArgument } from "./optional-arguments.js"; import { type ProtocolDispatch } from "./class-protocol-dispatch.js"; import { ClassDynamicDispatch, trackClassFieldCreation } from "./class-dynamic-dispatch.js"; -import { guardClassAttributeWrites } from "./class-attributes.js"; +import { addUntypedIntegrityWords, guardClassAttributeWrites } from "./class-attributes.js"; import { guardFrozenWrites, markSloppyRecordWrites } from "./frozen-records.js"; import { applyHandleProperties } from "./handle-properties.js"; import { installBufferValue } from "./containers/bytes.js"; @@ -3296,6 +3296,9 @@ export class Lowerer { readonly recordFieldDeletes = new Set(); /** typeKeys of the array types the program may freeze (IrModule.freezableArrays). */ readonly freezableArrays = new Set(); + /** Whether the program freezes, seals or prevents extensions of untyped + * values other than fresh literals (noteUntypedIntegrity). */ + untypedIntegrity = false; readonly liftedFns: IrFunction[] = []; /** The first lifted function of each name (liftedFnNamed), for the * liftedFns indexed so far. liftedFns only grows. */ @@ -7767,6 +7770,7 @@ export class Lowerer { finalizeClassMethodValues(this, functions); finalizePrivateBrands(this, functions); trackClassFieldCreation(this, functions); + addUntypedIntegrityWords(this); guardClassAttributeWrites(this, functions); guardFrozenWrites(this, functions); applyHandleProperties(this, functions); @@ -7881,6 +7885,7 @@ export class Lowerer { ...(this.freezableArrays.size > 0 ? { freezableArrays: [...this.freezableArrays].sort() } : {}), + ...(this.untypedIntegrity ? { untypedIntegrity: true as const } : {}), ...(isNodeEsmFile(this.entry, this.program) ? {} : { commonJsEntry: true }), ...(this.ffiImports.length > 0 ? { ffiImports: [...this.ffiImports] } : {}), }; diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index 5916a5166..636634dab 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -1073,6 +1073,11 @@ export interface IrModule { * (frontend frozen-records.ts): their writes test the array's frozen bit * (SCR_ARR_FROZEN) and throw Node's TypeError when it is set. */ freezableArrays?: string[]; + /** The program freezes, seals or prevents extensions of untyped values + * (frontend frozen-records.ts noteUntypedIntegrity). Class hierarchies + * that can be held there carry an integrity word, which the runtime sets + * through the commit of the instance's checked view. */ + untypedIntegrity?: true; /** The entry module is CommonJS under Node's classification. Node runs a * CommonJS main synchronously and drains process.nextTick callbacks * before promise jobs at the first checkpoint; an ES-module main's diff --git a/packages/compiler/src/ir/validate.ts b/packages/compiler/src/ir/validate.ts index a694e8d2c..8152775d1 100644 --- a/packages/compiler/src/ir/validate.ts +++ b/packages/compiler/src/ir/validate.ts @@ -123,6 +123,8 @@ export function validateModule(mod: IrModule): IrValidationError[] { errors.push({ message: "worker execution mode must be a boolean", loc: moduleLoc }); if (mod.declBoundary !== undefined && mod.declBoundary !== true) errors.push({ message: "declBoundary must be true when present", loc: moduleLoc }); + if (mod.untypedIntegrity !== undefined && mod.untypedIntegrity !== true) + errors.push({ message: "untypedIntegrity must be true when present", loc: moduleLoc }); if (mod.lifetimeRegions !== undefined && mod.lifetimeRegions !== true) errors.push({ message: "lifetimeRegions must be true when present", loc: moduleLoc }); if (mod.workers && mod.lib !== undefined) diff --git a/packages/compiler/test/class-attributes.test.ts b/packages/compiler/test/class-attributes.test.ts index 1a6fea654..a0e6efa62 100644 --- a/packages/compiler/test/class-attributes.test.ts +++ b/packages/compiler/test/class-attributes.test.ts @@ -82,3 +82,33 @@ b.x = 2; expect(throwing.length).toBeGreaterThan(0); expect(throwing.every((name) => name.includes("constructor"))).toBe(true); }); + +test("an untyped freeze gives every class hierarchy attribute state", async () => { + const mod = await lowerModule(` +export {}; +class Point { x = 1; } +class Labeled extends Point { label = "a"; } +function freezeUnknown(value: unknown): unknown { return Object.freeze(value); } +function move(p: Point): void { p.x = 2; } +freezeUnknown(new Labeled()); +move(new Point()); +`); + expect(mod.untypedIntegrity).toBe(true); + expect(fieldsOf(mod, "Point")).toContain("%attributes"); + expect(fieldsOf(mod, "Labeled")).toContain("%attributes"); + expect(functionsCalling(mod, "class.throwReadOnly")).toContain("move"); +}); + +test("untyped freezes of fresh literals and tagged templates leave classes unchanged", async () => { + const mod = await lowerModule( + ` +class Point { constructor() { this.x = 1; } } +const tag = (strings) => strings.length; +const frozen = Object.freeze({ a: 1 }); +console.log(tag\`a\${1}b\`, frozen.a, new Point().x); +`, + "main.js", + ); + expect(mod.untypedIntegrity).toBeUndefined(); + expect(fieldsOf(mod, "Point")).not.toContain("%attributes"); +}); diff --git a/packages/compiler/test/native-codegen-integration.test.ts b/packages/compiler/test/native-codegen-integration.test.ts index cecebb49c..2a0f8371e 100644 --- a/packages/compiler/test/native-codegen-integration.test.ts +++ b/packages/compiler/test/native-codegen-integration.test.ts @@ -378,7 +378,7 @@ done: expect(await symbols(helperObject, ["-u"])).toEqual(await symbols(clangObject, ["-u"])); expect(await symbols(helperObject, ["-gU"])).toEqual(await symbols(clangObject, ["-gU"])); expect(await symbols(helperObject, ["-gU"])).toEqual(["0000000000000000 T _main"]); - expect(await symbols(helperObject, ["-u"])).toContain("_scr_runtime_abi_v37"); + expect(await symbols(helperObject, ["-u"])).toContain("_scr_runtime_abi_v38"); const clangExe = join(dir, "clang-program"); const linkDriver = join(dir, "clang-driver.c"); @@ -712,7 +712,7 @@ done: .split("\n"); expect(undefinedSymbols).toContain("_sf_scale"); expect(undefinedSymbols).toContain("_sf_callback_mix"); - expect(undefinedSymbols).toContain("_scr_runtime_abi_v37"); + expect(undefinedSymbols).toContain("_scr_runtime_abi_v38"); }); test("helper and clang object paths retain the same outbound FFI C ABI", async () => { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7407-frozen-class-instances.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7407-frozen-class-instances.ts.json new file mode 100644 index 000000000..da868130c --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7407-frozen-class-instances.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7407-frozen-class-instances.ts" + ], + "diags": [] +} diff --git a/packages/runtime-darwin-arm64/scripts/build.mjs b/packages/runtime-darwin-arm64/scripts/build.mjs index e492c36b4..951883c07 100644 --- a/packages/runtime-darwin-arm64/scripts/build.mjs +++ b/packages/runtime-darwin-arm64/scripts/build.mjs @@ -340,7 +340,7 @@ async function build() { package: packageManifest.name, version: packageManifest.version, target: RUNTIME_PACK_MATRIX.target, - runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + runtime_abi: { version: 38, marker: "scr_runtime_abi_v38" }, compiler: { command: compiler, identity: compilerVersion, diff --git a/packages/runtime-pack-common/scripts/build.mjs b/packages/runtime-pack-common/scripts/build.mjs index e22f2a37c..988c899cf 100644 --- a/packages/runtime-pack-common/scripts/build.mjs +++ b/packages/runtime-pack-common/scripts/build.mjs @@ -437,7 +437,7 @@ async function build() { package: packageManifest.name, version: packageManifest.version, target: matrix.target, - runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + runtime_abi: { version: 38, marker: "scr_runtime_abi_v38" }, compiler: { command: compiler, identity: compilerVersion, diff --git a/packages/runtime/src/scr_console.c b/packages/runtime/src/scr_console.c index 086340014..819121c3f 100644 --- a/packages/runtime/src/scr_console.c +++ b/packages/runtime/src/scr_console.c @@ -148,7 +148,7 @@ static void scr_enable_utf8_console_output(void) { } #endif -void scr_runtime_abi_v37(void) {} +void scr_runtime_abi_v38(void) {} void scr_init(void) { #ifdef SCR_WORKERS diff --git a/packages/runtime/src/scr_core.h b/packages/runtime/src/scr_core.h index 3707b8d50..20c591cbb 100644 --- a/packages/runtime/src/scr_core.h +++ b/packages/runtime/src/scr_core.h @@ -81,7 +81,7 @@ void scr_init(void); /* Program objects emitted by the bundled LLVM helper reference this symbol. * Its versioned spelling makes a mismatched manual runtime link fail before * the program can start. */ -void scr_runtime_abi_v37(void); +void scr_runtime_abi_v38(void); void scr_runtime_workers_v8(void); /* ── the trap funnel (scr_console.c; scr_library.c under -DSCR_LIB) ────── diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index 5b1598a8b..bf3b8d426 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -1182,6 +1182,12 @@ void scr_dyn_obj_set_field(ScrDyn *obj, const char *key, size_t key_len, ScrDyn ScrDyn *scr_dyn_define_property(ScrDyn *target, ScrDyn *key, ScrDyn *descriptor); void scr_dyn_class_field_attributes(ScrDyn *view, ScrStr *name, double bits); void scr_dyn_class_view_attributes(ScrDyn *view, double bits); +/* The integrity state of a class instance's checked view as CLASS_* bits, + * added to `bits`. The commits of hierarchies with an integrity word store + * it in the word, in programs that freeze, seal or prevent extensions of + * untyped values. `bag`, the instance's new property bag or NULL, stops + * being extensible with the view. */ +double scr_dyn_class_view_integrity(const ScrDyn *view, double bits, ScrDyn *bag); ScrDyn *scr_class_define_field(ScrDyn *current, double field_bits, double object_bits, ScrStr *name, ScrDyn *descriptor); double scr_class_defined_bits(ScrDyn *holder, ScrStr *name); @@ -1211,6 +1217,9 @@ void scr_dyn_key_set(ScrDyn *recv, ScrStr *key, ScrDyn *value); void scr_dyn_arr_named_put(ScrDyn *arr, const char *key, size_t key_len, ScrDyn *value); void scr_dyn_key_set_computed(ScrDyn *recv, ScrDyn *key, ScrDyn *value); void scr_dyn_key_delete(ScrDyn *recv, const ScrStr *key, bool strict); +/* Removes the own property `key` of an ordinary object whatever its + * attributes, as scr_dyn_obj_set_field replaces values. */ +void scr_dyn_obj_delete_field(ScrDyn *obj, const ScrStr *key); /* This thread's global object box (borrowed). Every spelling of the global * object answers it; its symbol-keyed properties are the global object's * (scr_node_builtin.c). */ diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 40fd73508..2f8e4b6f8 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -2389,9 +2389,74 @@ void scr_record_throw_frozen(ScrStr *key, ScrStr *owner, double operation) { scr_throw_error(SCR_ERR_TYPE, scr_jb_finish(&buffer)); } -/* A class instance's integrity state lives in its native layout, which only - * statically typed calls can reach (the compiler adds the state to the - * hierarchies they name). Through an untyped value the operation throws. */ +/* ── class instance attributes ─────────────────────────────────────────── + * A hierarchy passed to Object.freeze, Object.seal, Object.preventExtensions + * or Object.defineProperty keeps an integrity state per instance and an + * attribute word per redefined field (CLASS_* and FIELD_* bits in the + * compiler's ir.ts). The checked view of an instance carries them, so + * reflection over the view answers as Node does. */ +enum { + SCR_CLASS_NOT_EXTENSIBLE = 1, + SCR_CLASS_SEALED = 2, + SCR_CLASS_FROZEN = 4, + SCR_FIELD_NOT_WRITABLE = 1, + SCR_FIELD_NOT_ENUMERABLE = 2, + SCR_FIELD_NOT_CONFIGURABLE = 4, +}; + +/* Set by scr_dyn_class_view_integrity, which only the commits of + * hierarchies with an integrity word call. */ +static SCR_TL bool scr_class_integrity_committed; + +double scr_dyn_class_view_integrity(const ScrDyn *view, double bits, ScrDyn *bag) { + scr_class_integrity_committed = true; + unsigned state = (unsigned)bits; + if (view->kind != SCR_DYN_OBJ || !view->non_extensible) return state; + state |= SCR_CLASS_NOT_EXTENSIBLE; + if (bag && bag->kind == SCR_DYN_OBJ) bag->non_extensible = true; + bool sealed = true, frozen = true; + for (size_t i = 0; i < view->v.obj.len; i++) { + const ScrDynEntry *entry = &view->v.obj.entries[i]; + if (entry->configurable) sealed = false; + if (!entry->accessor && entry->writable) frozen = false; + } + if (sealed) state |= SCR_CLASS_SEALED; + if (sealed && frozen) state |= SCR_CLASS_FROZEN; + return state; +} + +/* Object.freeze, Object.seal or Object.preventExtensions (`operation`) of + * the class instance a capsule refers to. In a program that applies them to + * untyped values, every hierarchy that can be held there keeps an + * integrity word (class-attributes.ts), and its commit stores the + * integrity state of the instance's checked view in the word + * (scr_dyn_class_view_integrity). The operation applies to the view, and + * the commit records it. A first commit of the unchanged view finds out + * whether the hierarchy has the word. Answers false for other values and + * for instances whose hierarchy has no word, whose state stays as it was, + * and true when the operation applied or threw. */ +static bool scr_dyn_class_integrity(ScrDyn *object, ScrDyn *(*operation)(ScrDyn *)) { + if (object->kind != SCR_DYN_TYPED_REF || !object->v.typed_ref.commit || + object->v.typed_ref.type_key_len < 7 || memcmp(object->v.typed_ref.type_key, "object:", 7) != 0) + return false; + ScrDyn *view = scr_dyn_typed_ref_materialize(object); + bool word = false; + if (!scr_exc_pending()) { + scr_class_integrity_committed = false; + scr_dyn_typed_ref_commit(object); + word = scr_class_integrity_committed; + } + if (word && !scr_exc_pending()) { + scr_dyn_release(operation(view)); + if (!scr_exc_pending()) scr_dyn_typed_ref_commit(object); + } + scr_dyn_release(view); + return word || scr_exc_pending(); +} + +/* A class instance's integrity state lives in its native layout. Through an + * untyped value whose hierarchy has no integrity word, the operation + * throws. */ static bool scr_dyn_class_integrity_fence(const ScrDyn *object, const char *operation) { if (object->kind != SCR_DYN_TYPED_REF) return false; ScrJsonBuf buffer; @@ -2456,6 +2521,8 @@ ScrDyn *scr_dyn_prevent_extensions(ScrDyn *object) { scr_map_prevent_extensions(collection); return scr_dyn_retain(object); } + if (scr_dyn_class_integrity(object, scr_dyn_prevent_extensions)) + return scr_exc_pending() ? NULL : scr_dyn_retain(object); if (scr_dyn_class_integrity_fence(object, "Object.preventExtensions")) return NULL; ScrDyn *table = scr_dyn_fn_integrity_table(object); if (table) { @@ -2494,6 +2561,8 @@ ScrDyn *scr_dyn_seal(ScrDyn *object) { scr_map_prevent_extensions(collection); return scr_dyn_retain(object); } + if (scr_dyn_class_integrity(object, scr_dyn_seal)) + return scr_exc_pending() ? NULL : scr_dyn_retain(object); if (scr_dyn_class_integrity_fence(object, "Object.seal")) return NULL; if (object->symbol_properties) scr_dyn_release(scr_dyn_seal(object->symbol_properties)); ScrDyn *table = scr_dyn_fn_integrity_table(object); @@ -12118,6 +12187,10 @@ static void scr_json_delete_member(ScrDyn *object, const ScrStr *key) { } } +void scr_dyn_obj_delete_field(ScrDyn *obj, const ScrStr *key) { + if (obj->kind == SCR_DYN_OBJ) scr_json_delete_member(obj, key); +} + /* Ordinary native objects carry removable own data properties. Dense * arrays, typed references and handles keep their explicit boundary; * deleting from a materialized snapshot would lose the mutation. */ @@ -16724,6 +16797,8 @@ ScrDyn *scr_dyn_freeze(ScrDyn *value) { if (scr_dyn_class_reflection_fence(value) || scr_dyn_error_prototype_fence(value)) return NULL; ScrDyn *native = scr_dyn_freeze_native(value); if (native) return native; + if (scr_dyn_class_integrity(value, scr_dyn_freeze_data)) + return scr_exc_pending() ? NULL : scr_dyn_retain(value); if (scr_dyn_class_integrity_fence(value, "Object.freeze")) return NULL; ScrDyn *table = scr_dyn_fn_integrity_table(value); if (!table) return scr_dyn_freeze_data(value); @@ -16829,21 +16904,6 @@ ScrDyn *scr_caught_to_dyn(const ScrCaught *c) { } } -/* ── class instance attributes ─────────────────────────────────────────── - * A hierarchy passed to Object.freeze, Object.seal, Object.preventExtensions - * or Object.defineProperty keeps an integrity state per instance and an - * attribute word per redefined field (CLASS_* and FIELD_* bits in the - * compiler's ir.ts). The checked view of an instance carries them, so - * reflection over the view answers as Node does. */ -enum { - SCR_CLASS_NOT_EXTENSIBLE = 1, - SCR_CLASS_SEALED = 2, - SCR_CLASS_FROZEN = 4, - SCR_FIELD_NOT_WRITABLE = 1, - SCR_FIELD_NOT_ENUMERABLE = 2, - SCR_FIELD_NOT_CONFIGURABLE = 4, -}; - void scr_dyn_class_field_attributes(ScrDyn *view, ScrStr *name, double bits) { unsigned b = (unsigned)bits; if (b == 0 || view->kind != SCR_DYN_OBJ) return; diff --git a/tests/corpus/7407-frozen-class-instances.ts b/tests/corpus/7407-frozen-class-instances.ts new file mode 100644 index 000000000..0732b8c35 --- /dev/null +++ b/tests/corpus/7407-frozen-class-instances.ts @@ -0,0 +1,143 @@ +// Object.freeze, Object.seal and Object.preventExtensions of class instances +// held in untyped values. The operation changes the instance itself: writes +// through its typed references, through untyped references and through its +// methods then throw Node's TypeError (this module is strict mode code), and +// Object.isFrozen, isSealed and isExtensible report the state through either +// reference. +export {}; + +function report(e: unknown): void { + console.log((e as Error).name + ": " + (e as Error).message); +} + +function freezeUnknown(value: unknown): unknown { + return Object.freeze(value); +} + +function sealUnknown(value: unknown): unknown { + return Object.seal(value); +} + +function preventUnknown(value: unknown): unknown { + return Object.preventExtensions(value); +} + +function integrity(value: unknown): string { + return [Object.isFrozen(value), Object.isSealed(value), Object.isExtensible(value)].join(" "); +} + +function writeAny(value: any, key: string, next: unknown): void { + value[key] = next; +} + +function deleteAny(value: any, key: string): void { + delete value[key]; +} + +class Point { + x: number; + y: number; + constructor(x: number, y: number) { + this.x = x; + this.y = y; + } + move(dx: number): void { + this.x += dx; + } +} + +class Labeled extends Point { + label: string; + constructor(x: number, y: number, label: string) { + super(x, y); + this.label = label; + } + rename(label: string): void { + this.label = label; + } +} + +class Counter { + count = 0; + tags: string[] = []; + bump(): number { + return ++this.count; + } +} + +function frozen(): void { + const p = new Point(1, 2); + console.log(integrity(p)); + const same = freezeUnknown(p); + console.log(same === p, integrity(p), Object.isFrozen(p)); + try { p.x = 5; } catch (e) { report(e); } + try { p.move(1); } catch (e) { report(e); } + try { writeAny(p, "y", 9); } catch (e) { report(e); } + try { writeAny(p, "z", 1); } catch (e) { report(e); } + console.log(p.x, p.y, JSON.stringify(p)); + + const l = new Labeled(3, 4, "a"); + const base: Point = l; + freezeUnknown(base); + console.log(integrity(l), integrity(base)); + try { l.rename("b"); } catch (e) { report(e); } + try { base.x = 0; } catch (e) { report(e); } + try { writeAny(l, "label", "c"); } catch (e) { report(e); } + console.log(l.x, l.label, l instanceof Labeled); + freezeUnknown(l); + console.log(integrity(l)); +} + +function sealed(): void { + const c = new Counter(); + sealUnknown(c); + console.log(integrity(c)); + console.log(c.bump(), c.bump()); + c.tags.push("kept"); + try { writeAny(c, "extra", 1); } catch (e) { report(e); } + writeAny(c, "count", 10); + console.log(c.count, c.tags.join(), JSON.stringify(c)); + freezeUnknown(c); + console.log(integrity(c)); + try { c.bump(); } catch (e) { report(e); } + c.tags.push("still"); + console.log(c.count, c.tags.join()); +} + +function notExtensible(): void { + const l = new Labeled(0, 0, "n"); + preventUnknown(l); + console.log(integrity(l)); + l.move(2); + l.rename("m"); + try { writeAny(l, "extra", true); } catch (e) { report(e); } + console.log(l.x, l.label, Object.keys(l).join()); + sealUnknown(l); + console.log(integrity(l)); + writeAny(l, "y", 7); + console.log(l.y); +} + +function untouched(): void { + const p = new Point(5, 6); + const q = new Point(7, 8); + freezeUnknown(q); + p.x = 50; + writeAny(p, "y", 60); + console.log(p.x, p.y, integrity(p), integrity(q)); +} + +function added(): void { + const p = new Point(1, 1); + writeAny(p, "extra", 1); + freezeUnknown(p); + console.log(integrity(p), Object.keys(p).join()); + try { deleteAny(p, "extra"); } catch (e) { report(e); } + console.log((p as any).extra, JSON.stringify(p)); +} + +frozen(); +sealed(); +notExtensible(); +untouched(); +added(); diff --git a/tests/harness/corpus-costs/7407-frozen-class-instances.ts.json b/tests/harness/corpus-costs/7407-frozen-class-instances.ts.json new file mode 100644 index 000000000..34061c3eb --- /dev/null +++ b/tests/harness/corpus-costs/7407-frozen-class-instances.ts.json @@ -0,0 +1 @@ +{ "plain": 3923, "san": 3742 } diff --git a/tests/harness/self-hosting-native-toolchain.test.ts b/tests/harness/self-hosting-native-toolchain.test.ts index c5476328e..030408deb 100644 --- a/tests/harness/self-hosting-native-toolchain.test.ts +++ b/tests/harness/self-hosting-native-toolchain.test.ts @@ -109,7 +109,7 @@ for (const backend of ["llvm"] as const) { object_format: target.objectFormat, minimum_os: target.minimumOs, }, - runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + runtime_abi: { version: 38, marker: "scr_runtime_abi_v38" }, compiler: { command: "fixture", identity: "fixture", target: target.llvmTriple }, macros: { executable: [], excluded: [], sanitizer: "external-toolchain-required" }, flavors: { From 7784800c8e6d83b962e6164b8e5ba48bc69ea54f Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 20:51:00 -0500 Subject: [PATCH 037/259] Prepare v0.4.4 release --- CHANGELOG.md | 27 +++++++++++++++++-- packages/cli-darwin-arm64/package.json | 2 +- packages/cli-darwin-x64/package.json | 2 +- packages/cli-linux-arm64-gnu/package.json | 2 +- packages/cli-linux-arm64-musl/package.json | 2 +- packages/cli-linux-x64-gnu/package.json | 2 +- packages/cli-linux-x64-musl/package.json | 2 +- packages/cli-win32-x64-msvc/package.json | 2 +- packages/cli/package.json | 2 +- packages/compiler/package.json | 2 +- packages/compiler/surface-manifest.json | 2 +- packages/experimental/package.json | 2 +- packages/llvm-darwin-arm64/package.json | 2 +- packages/llvm-darwin-x64/package.json | 2 +- packages/llvm-linux-arm64-gnu/package.json | 2 +- packages/llvm-linux-arm64-musl/package.json | 2 +- packages/llvm-linux-x64-gnu/package.json | 2 +- packages/llvm-linux-x64-musl/package.json | 2 +- packages/llvm-win32-x64-msvc/package.json | 2 +- packages/runtime-android-arm64/package.json | 2 +- packages/runtime-darwin-arm64/package.json | 2 +- packages/runtime-darwin-x64/package.json | 2 +- packages/runtime-ios-arm64/package.json | 2 +- .../runtime-ios-simulator-arm64/package.json | 2 +- packages/runtime-linux-arm64-gnu/package.json | 2 +- .../runtime-linux-arm64-musl/package.json | 2 +- packages/runtime-linux-x64-gnu/package.json | 2 +- packages/runtime-linux-x64-musl/package.json | 2 +- packages/runtime-wasm32-wasi/package.json | 2 +- packages/runtime-win32-x64-msvc/package.json | 2 +- packages/runtime/package.json | 2 +- packages/threads/package.json | 2 +- packages/types/package.json | 2 +- 33 files changed, 57 insertions(+), 34 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 96f13fa26..612df47b5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,31 @@ All notable changes to scriptc will be documented in this file. +## 0.4.4 + +### Highlights + +- **Fixes for 0.4.3:** + - Unchanged rebuilds hit the frontend cache again. An unchanged rebuild of a 23-module program takes 93 ms instead of 1.26 s, and of tsc-ts (dev) 1.6 s instead of 58.2 s. + - The native compiler builds programs with several typed-array accesses at one masked index in a loop again, including tsc-ts's release build, which failed with SC3004. + - `x!` returned from a function, used as an arrow function's result, or passed as an argument keeps null or undefined when the destination type holds it, as JavaScript does. `x!` operands of `+`, `+=` and other conversions that hold undefined or null convert as Node does. + - Effect 4 programs whose generators yield clients built by other generators run again. + - The cache for untyped property access in programs that declare classes is reverted, fixing a crash in Effect 4 observability programs. +- **Faster:** + - Number compares and typed-array indexes use the exact integer of sums like `i + 1`: a heap sift-down over an `Int32Array` runs 17.5% faster. + - glibc's per-thread heaps use huge pages: the VS Code type-check runs 3.4% faster. + - Mid-size executables (over 1 MiB of LLVM text) build in at least eight partitions: the LLVM backend phase takes 34 to 74% less time for three.js programs of 1.4 to 7.8 MB. + - JavaScript class instances are boxed at their exact class, and stores into nested string-keyed dictionaries keep class method calls direct. + - `--target-cpu` selects an x86-64 microarchitecture level. +- **Node.js parity:** + - X25519 keys and `crypto.diffieHellman`; `existsSync` and `fs.promises` accept `file:` URLs; `Buffer.from` ranges over ArrayBuffers, the deprecated `Buffer()` constructor and `Buffer` as a value. + - Dates are objects with identity; `Promise.all` over different entry types settles on Node's turns; completion callbacks run in their call's AsyncLocalStorage context. + - TypedArray methods run on typed arrays held as untyped values, and unions of typed-array classes compile. Borrowed `TypedArray.prototype.set` calls compile and throw Node's TypeError for other targets. + - Split CommonJS `require` bindings, `__`-prefixed exports, string-key destructuring of `any` values, and record key order for values JavaScript built. +- **npm packages:** zod 4 and `@hono/zod-validator` values are projected at the declaration boundary. + + + ## 0.4.3 ### Highlights @@ -26,8 +51,6 @@ All notable changes to scriptc will be documented in this file. - **npm packages:** zod 3 compiles natively and zod 4's core runs, minified packages such as marked compile, chalk 5 and hot-shots 8 build from built-in shims, and `@hono/node-server` 2.x is built in. User code types npm package declarations at a checked, identity-preserving boundary. - **Builds:** the cached build is reused after whitespace and comment edits, function bodies are emitted on forked workers, and the LLVM emitter reads its analyses from one recorded walk of each module. - - ## 0.4.2 ### Highlights diff --git a/packages/cli-darwin-arm64/package.json b/packages/cli-darwin-arm64/package.json index eee0ec3c8..bac01cc44 100644 --- a/packages/cli-darwin-arm64/package.json +++ b/packages/cli-darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/cli-darwin-arm64", - "version": "0.4.3", + "version": "0.4.4", "description": "Native scriptc compiler for darwin-arm64", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/cli-darwin-x64/package.json b/packages/cli-darwin-x64/package.json index b527a3cd7..6c2fb3123 100644 --- a/packages/cli-darwin-x64/package.json +++ b/packages/cli-darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/cli-darwin-x64", - "version": "0.4.3", + "version": "0.4.4", "description": "Native scriptc compiler for darwin-x64", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/cli-linux-arm64-gnu/package.json b/packages/cli-linux-arm64-gnu/package.json index 512a7cd13..289d8d6bd 100644 --- a/packages/cli-linux-arm64-gnu/package.json +++ b/packages/cli-linux-arm64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/cli-linux-arm64-gnu", - "version": "0.4.3", + "version": "0.4.4", "description": "Native scriptc compiler for linux-arm64-gnu", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/cli-linux-arm64-musl/package.json b/packages/cli-linux-arm64-musl/package.json index 8d0fdfb0f..3a601ca33 100644 --- a/packages/cli-linux-arm64-musl/package.json +++ b/packages/cli-linux-arm64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/cli-linux-arm64-musl", - "version": "0.4.3", + "version": "0.4.4", "description": "Native scriptc compiler for linux-arm64-musl", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/cli-linux-x64-gnu/package.json b/packages/cli-linux-x64-gnu/package.json index b71205614..8f6b1aa5e 100644 --- a/packages/cli-linux-x64-gnu/package.json +++ b/packages/cli-linux-x64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/cli-linux-x64-gnu", - "version": "0.4.3", + "version": "0.4.4", "description": "Native scriptc compiler for linux-x64-gnu", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/cli-linux-x64-musl/package.json b/packages/cli-linux-x64-musl/package.json index eaeb6f15a..ff0d1d686 100644 --- a/packages/cli-linux-x64-musl/package.json +++ b/packages/cli-linux-x64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/cli-linux-x64-musl", - "version": "0.4.3", + "version": "0.4.4", "description": "Native scriptc compiler for linux-x64-musl", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/cli-win32-x64-msvc/package.json b/packages/cli-win32-x64-msvc/package.json index 3e3b8259f..e94ba31df 100644 --- a/packages/cli-win32-x64-msvc/package.json +++ b/packages/cli-win32-x64-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/cli-win32-x64-msvc", - "version": "0.4.3", + "version": "0.4.4", "description": "Native scriptc compiler for win32-x64-msvc", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/cli/package.json b/packages/cli/package.json index 264a7f5f1..26cf10f07 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -1,6 +1,6 @@ { "name": "scriptc", - "version": "0.4.3", + "version": "0.4.4", "description": "Compile ordinary TypeScript and JavaScript to small, fast native executables and WebAssembly modules that run without Node.js", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/compiler/package.json b/packages/compiler/package.json index 60f6bd0f0..570c0a1a5 100644 --- a/packages/compiler/package.json +++ b/packages/compiler/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/compiler", - "version": "0.4.3", + "version": "0.4.4", "description": "The scriptc compiler — TypeScript/JavaScript frontend, typed IR, LLVM backend", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/compiler/surface-manifest.json b/packages/compiler/surface-manifest.json index 75541b8e5..ea084affe 100644 --- a/packages/compiler/surface-manifest.json +++ b/packages/compiler/surface-manifest.json @@ -1,6 +1,6 @@ { "schemaVersion": 2, - "compilerVersion": "0.4.3", + "compilerVersion": "0.4.4", "coverage": [ "Entries are projected mechanically from the compiler's own decision tables: the diagnostics registry, the unsupported-syntax dispatch tables, the stdlib and node-builtin lowering tables, and the supported-builtin-module list. Nothing is hand-maintained; the manifest regenerates byte-identically from the source tree at this version.", "Absence from this manifest means 'not projected', never 'unsupported'. Surfaces lowered through dedicated code paths rather than tables are not yet projected: console, JSON, Promise/async and the timer surface, the net/http/tls/https/dgram/dns/assert/test/stream/readline module member surfaces, template literals, the regex slice, global functions (parseInt, parseFloat, isNaN, isFinite), and the process surface outside its ambient slice.", diff --git a/packages/experimental/package.json b/packages/experimental/package.json index b3e8a6fb1..583a2bc58 100644 --- a/packages/experimental/package.json +++ b/packages/experimental/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/experimental", - "version": "0.4.3", + "version": "0.4.4", "description": "Experimental scriptc APIs, with Node.js implementations: lifetime regions for ProgramLifetime objects, intern tables shared between threads, and per-thread slots on shared objects", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/llvm-darwin-arm64/package.json b/packages/llvm-darwin-arm64/package.json index ac99f1661..76d5fdb72 100644 --- a/packages/llvm-darwin-arm64/package.json +++ b/packages/llvm-darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/llvm-darwin-arm64", - "version": "0.4.3", + "version": "0.4.4", "description": "Pinned LLVM code-generation helper for scriptc on macOS arm64", "license": "Apache-2.0 WITH LLVM-exception", "homepage": "https://scriptc.dev", diff --git a/packages/llvm-darwin-x64/package.json b/packages/llvm-darwin-x64/package.json index ca632dcd4..fbb755f4a 100644 --- a/packages/llvm-darwin-x64/package.json +++ b/packages/llvm-darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/llvm-darwin-x64", - "version": "0.4.3", + "version": "0.4.4", "description": "Pinned LLVM code-generation helper for scriptc on macOS x64", "license": "Apache-2.0 WITH LLVM-exception", "homepage": "https://scriptc.dev", diff --git a/packages/llvm-linux-arm64-gnu/package.json b/packages/llvm-linux-arm64-gnu/package.json index 566b38e40..81fdc7d5b 100644 --- a/packages/llvm-linux-arm64-gnu/package.json +++ b/packages/llvm-linux-arm64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/llvm-linux-arm64-gnu", - "version": "0.4.3", + "version": "0.4.4", "description": "Pinned LLVM code-generation helper for scriptc on Linux arm64", "license": "Apache-2.0 WITH LLVM-exception", "homepage": "https://scriptc.dev", diff --git a/packages/llvm-linux-arm64-musl/package.json b/packages/llvm-linux-arm64-musl/package.json index a9288c2ca..8b3b2f185 100644 --- a/packages/llvm-linux-arm64-musl/package.json +++ b/packages/llvm-linux-arm64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/llvm-linux-arm64-musl", - "version": "0.4.3", + "version": "0.4.4", "description": "Statically linked LLVM code-generation helper for scriptc on Linux arm64 musl", "license": "Apache-2.0 WITH LLVM-exception", "homepage": "https://scriptc.dev", diff --git a/packages/llvm-linux-x64-gnu/package.json b/packages/llvm-linux-x64-gnu/package.json index c55f51847..79b7eba3f 100644 --- a/packages/llvm-linux-x64-gnu/package.json +++ b/packages/llvm-linux-x64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/llvm-linux-x64-gnu", - "version": "0.4.3", + "version": "0.4.4", "description": "Pinned LLVM code-generation helper for scriptc on Linux x64", "license": "Apache-2.0 WITH LLVM-exception", "homepage": "https://scriptc.dev", diff --git a/packages/llvm-linux-x64-musl/package.json b/packages/llvm-linux-x64-musl/package.json index b257085bf..5bffa5bef 100644 --- a/packages/llvm-linux-x64-musl/package.json +++ b/packages/llvm-linux-x64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/llvm-linux-x64-musl", - "version": "0.4.3", + "version": "0.4.4", "description": "Statically linked LLVM code-generation helper for scriptc on Linux x64 musl", "license": "Apache-2.0 WITH LLVM-exception", "homepage": "https://scriptc.dev", diff --git a/packages/llvm-win32-x64-msvc/package.json b/packages/llvm-win32-x64-msvc/package.json index 0f3f99331..14c747a4a 100644 --- a/packages/llvm-win32-x64-msvc/package.json +++ b/packages/llvm-win32-x64-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/llvm-win32-x64-msvc", - "version": "0.4.3", + "version": "0.4.4", "description": "Pinned LLVM code-generation helper for scriptc on Windows x64", "license": "Apache-2.0 WITH LLVM-exception", "homepage": "https://scriptc.dev", diff --git a/packages/runtime-android-arm64/package.json b/packages/runtime-android-arm64/package.json index 392ef1717..1dfa1b177 100644 --- a/packages/runtime-android-arm64/package.json +++ b/packages/runtime-android-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/runtime-android-arm64", - "version": "0.4.3", + "version": "0.4.4", "description": "Precompiled scriptc library runtime pack for Android arm64", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/runtime-darwin-arm64/package.json b/packages/runtime-darwin-arm64/package.json index 354526024..32463357f 100644 --- a/packages/runtime-darwin-arm64/package.json +++ b/packages/runtime-darwin-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/runtime-darwin-arm64", - "version": "0.4.3", + "version": "0.4.4", "description": "Precompiled scriptc runtime pack for macOS arm64", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/runtime-darwin-x64/package.json b/packages/runtime-darwin-x64/package.json index 58aa358b2..c0577b04c 100644 --- a/packages/runtime-darwin-x64/package.json +++ b/packages/runtime-darwin-x64/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/runtime-darwin-x64", - "version": "0.4.3", + "version": "0.4.4", "description": "Precompiled scriptc runtime pack for macOS x64", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/runtime-ios-arm64/package.json b/packages/runtime-ios-arm64/package.json index 6193c5258..9c2134280 100644 --- a/packages/runtime-ios-arm64/package.json +++ b/packages/runtime-ios-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/runtime-ios-arm64", - "version": "0.4.3", + "version": "0.4.4", "description": "Precompiled scriptc library runtime pack for iOS arm64", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/runtime-ios-simulator-arm64/package.json b/packages/runtime-ios-simulator-arm64/package.json index 7d01c45d3..6b7563a6a 100644 --- a/packages/runtime-ios-simulator-arm64/package.json +++ b/packages/runtime-ios-simulator-arm64/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/runtime-ios-simulator-arm64", - "version": "0.4.3", + "version": "0.4.4", "description": "Precompiled scriptc library runtime pack for iOS simulator arm64", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/runtime-linux-arm64-gnu/package.json b/packages/runtime-linux-arm64-gnu/package.json index 419080c3a..f0ae56929 100644 --- a/packages/runtime-linux-arm64-gnu/package.json +++ b/packages/runtime-linux-arm64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/runtime-linux-arm64-gnu", - "version": "0.4.3", + "version": "0.4.4", "description": "Precompiled scriptc runtime pack for Linux arm64 glibc", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/runtime-linux-arm64-musl/package.json b/packages/runtime-linux-arm64-musl/package.json index 2bae09884..79fa8e7dd 100644 --- a/packages/runtime-linux-arm64-musl/package.json +++ b/packages/runtime-linux-arm64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/runtime-linux-arm64-musl", - "version": "0.4.3", + "version": "0.4.4", "description": "Precompiled scriptc runtime pack for Linux arm64 musl", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/runtime-linux-x64-gnu/package.json b/packages/runtime-linux-x64-gnu/package.json index 6749ddeea..45af8d2b7 100644 --- a/packages/runtime-linux-x64-gnu/package.json +++ b/packages/runtime-linux-x64-gnu/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/runtime-linux-x64-gnu", - "version": "0.4.3", + "version": "0.4.4", "description": "Precompiled scriptc runtime pack for Linux x64 glibc", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/runtime-linux-x64-musl/package.json b/packages/runtime-linux-x64-musl/package.json index 9b4803406..fe9d11bcd 100644 --- a/packages/runtime-linux-x64-musl/package.json +++ b/packages/runtime-linux-x64-musl/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/runtime-linux-x64-musl", - "version": "0.4.3", + "version": "0.4.4", "description": "Precompiled scriptc runtime pack for Linux x64 musl", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/runtime-wasm32-wasi/package.json b/packages/runtime-wasm32-wasi/package.json index 63a95601d..ac2f4a5e9 100644 --- a/packages/runtime-wasm32-wasi/package.json +++ b/packages/runtime-wasm32-wasi/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/runtime-wasm32-wasi", - "version": "0.4.3", + "version": "0.4.4", "description": "Precompiled scriptc runtime pack for WASI Preview 1", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/runtime-win32-x64-msvc/package.json b/packages/runtime-win32-x64-msvc/package.json index 01bec7c31..9a5731da2 100644 --- a/packages/runtime-win32-x64-msvc/package.json +++ b/packages/runtime-win32-x64-msvc/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/runtime-win32-x64-msvc", - "version": "0.4.3", + "version": "0.4.4", "description": "Precompiled scriptc runtime pack for Windows x64 MSVC", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/runtime/package.json b/packages/runtime/package.json index d367ad6bf..1d58b00e5 100644 --- a/packages/runtime/package.json +++ b/packages/runtime/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/runtime", - "version": "0.4.3", + "version": "0.4.4", "description": "scriptc native runtime sources and vendored dependencies", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/threads/package.json b/packages/threads/package.json index a37a3ba82..c29967cc6 100644 --- a/packages/threads/package.json +++ b/packages/threads/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/threads", - "version": "0.4.3", + "version": "0.4.4", "description": "Zero-copy publication of immutable object graphs to worker threads (scriptc), with a deep-freezing Node.js implementation", "license": "Apache-2.0", "homepage": "https://scriptc.dev", diff --git a/packages/types/package.json b/packages/types/package.json index 906c68dec..db88b4b2f 100644 --- a/packages/types/package.json +++ b/packages/types/package.json @@ -1,6 +1,6 @@ { "name": "@scriptc/types", - "version": "0.4.3", + "version": "0.4.4", "description": "Contract types for scriptc: type-only annotations (Int32, NoThrow, Immutable) that scriptc checks and optimizes, with no runtime semantics", "license": "Apache-2.0", "homepage": "https://scriptc.dev", From 995f3458279e9f08a6efe78fd99a8c19e697e612 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Fri, 23 Oct 2026 19:15:31 -0700 Subject: [PATCH 038/259] Record corpus 8115's CI cost Co-Authored-By: Claude Opus 5.5 --- tests/harness/corpus-costs/8115-error-prototype-identity.js.json | 1 + 1 file changed, 1 insertion(+) create mode 100644 tests/harness/corpus-costs/8115-error-prototype-identity.js.json diff --git a/tests/harness/corpus-costs/8115-error-prototype-identity.js.json b/tests/harness/corpus-costs/8115-error-prototype-identity.js.json new file mode 100644 index 000000000..57bb2b280 --- /dev/null +++ b/tests/harness/corpus-costs/8115-error-prototype-identity.js.json @@ -0,0 +1 @@ +{ "plain": 5600, "san": 5100 } From 61647a8e40d2455cd859146d88745b7cad8a3fce Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 21:20:57 -0500 Subject: [PATCH 039/259] Read typed-array elements through non-null assertions as undefined where Node does `t[i]!` on a typed array always took the numeric element read, which is NaN for an index outside the array. Node reads undefined there, so `t[n]! === t[n]!` was false instead of true, `${t[n]!}` was "NaN", and `typeof t[n]!` was "number". `t[i]!` now takes the numeric read only where its use converts the value to a number. Where the use tells undefined from NaN (an equality, a template span, `+` with a string, a comparison with a string, `!`, `typeof`, an array literal element, or an argument whose parameter admits undefined, such as `Object.is` and `String`), it reads undefined for an invalid index, like `t[i]`. Returns and plain bindings keep the numeric read. Corpus 7394. --- .../lowering/expressions/element-access.ts | 14 +++-- .../src/frontend/lowering/lower-exprs.ts | 25 +++++++- .../7394-non-null-typed-array-reads.ts.json | 6 ++ .../corpus/7394-non-null-typed-array-reads.ts | 59 +++++++++++++++++++ .../7394-non-null-typed-array-reads.ts.json | 1 + 5 files changed, 98 insertions(+), 7 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7394-non-null-typed-array-reads.ts.json create mode 100644 tests/corpus/7394-non-null-typed-array-reads.ts create mode 100644 tests/harness/corpus-costs/7394-non-null-typed-array-reads.ts.json diff --git a/packages/compiler/src/frontend/lowering/expressions/element-access.ts b/packages/compiler/src/frontend/lowering/expressions/element-access.ts index 0f22a9622..9ac6a04b6 100644 --- a/packages/compiler/src/frontend/lowering/expressions/element-access.ts +++ b/packages/compiler/src/frontend/lowering/expressions/element-access.ts @@ -45,6 +45,7 @@ import { lowerDynMemberAssignment, lowerOptionalArrayIndexRead, lowerOptionalNumber, + assertedReadObservesUndefined, recordKeyResultOk, representedClassFieldTarget, runtimeOptionalElementKey, @@ -381,13 +382,18 @@ export function lowerElementAccess(lowerer: Lowerer, expr: ts.ElementAccessExpre if (index.type.kind !== "f64") { lowerer.unsupported("SC1090", expr.argumentExpression, "indexing with non-number keys"); } - // `t[i]!` asserts presence: the numeric element read (NaN when - // invalid). Every other read answers undefined for an invalid index, - // like Node. + // `t[i]!` performs no runtime check, but its static type is a number: + // it takes the numeric element read (NaN when invalid), except where + // the value reaches a use that tells undefined from NaN (an equality, a + // string conversion, `typeof`, an array element), which reads undefined + // for an invalid index like `t[i]`. Every other read answers undefined + // for an invalid index, like Node. // A read whose every consumer treats undefined like NaN (see // nan-coded-reads.ts) is the same plain numeric read. if ( - (ts.isNonNullExpression(expr.parent) && expr.parent.expression === expr) || + (ts.isNonNullExpression(expr.parent) && + expr.parent.expression === expr && + !assertedReadObservesUndefined(lowerer, expr.parent)) || lowerer.nanCodedReads?.isNumericRead(expr) === true ) { return { diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index f2b601619..033f482d1 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -1024,13 +1024,14 @@ function assertionOperand( ) ) return null; - // Array and typed-array element reads keep their own handling of a - // missing element. + // Array element reads keep their own handling of a missing element. A + // typed-array read is optional here only where its use tells undefined + // from NaN (assertedReadObservesUndefined). let operand: ts.Expression = expr.expression; while (ts.isParenthesizedExpression(operand)) operand = operand.expression; if (ts.isElementAccessExpression(operand)) { const kind = lowerer.mapTypeOf(lowerer.typeOf(operand.expression))?.kind; - if (kind === "array" || kind === "bytes") return null; + if (kind === "array") return null; } const use = convertingUseOf(lowerer, expr); if (use === null) return null; @@ -1047,6 +1048,7 @@ function convertingUseOf(lowerer: Lowerer, expr: ts.NonNullExpression): "number" while (ts.isParenthesizedExpression(outer.parent)) outer = outer.parent; const parent = outer.parent; if (ts.isTemplateSpan(parent)) return parent.expression === outer ? "value" : null; + if (ts.isTypeOfExpression(parent)) return "value"; if (ts.isPrefixUnaryExpression(parent)) { if (parent.operator === ts.SyntaxKind.ExclamationToken) return "value"; return parent.operator === ts.SyntaxKind.MinusToken || @@ -1143,6 +1145,23 @@ const NUMERIC_COMPOUNDS = new Set([ ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken, ]); +/** Whether the use of `t[i]!` tells undefined from NaN: a converting use + * that takes the value itself (see convertingUseOf), or a destination that + * holds a missing element (see assertedElementKeepsUndefined) other than a + * return, whose slot has the function's number type. */ +export function assertedReadObservesUndefined( + lowerer: Lowerer, + node: ts.NonNullExpression, +): boolean { + if (convertingUseOf(lowerer, node) === "value") return true; + let outer: ts.Expression = node; + while (ts.isParenthesizedExpression(outer.parent)) outer = outer.parent; + const parent = outer.parent; + if (ts.isReturnStatement(parent) || (ts.isArrowFunction(parent) && parent.body === outer)) + return false; + return assertedElementKeepsUndefined(lowerer, node); +} + export function runtimeOptionalAssertionErases( lowerer: Lowerer, expr: ts.Expression, diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7394-non-null-typed-array-reads.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7394-non-null-typed-array-reads.ts.json new file mode 100644 index 000000000..5fbae0c10 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7394-non-null-typed-array-reads.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7394-non-null-typed-array-reads.ts" + ], + "diags": [] +} diff --git a/tests/corpus/7394-non-null-typed-array-reads.ts b/tests/corpus/7394-non-null-typed-array-reads.ts new file mode 100644 index 000000000..6f1ec9808 --- /dev/null +++ b/tests/corpus/7394-non-null-typed-array-reads.ts @@ -0,0 +1,59 @@ +// Non-null assertions on typed-array element reads. `!` performs no +// runtime check: an index outside the array reads undefined, as in Node, +// wherever the use tells undefined from NaN (equality, string conversion, +// typeof, Object.is, an array element), and NaN where it converts the value +// to a number. + +const int32 = new Int32Array([1, -2, 3]); +const float64 = new Float64Array([1.5, NaN, -0]); +const uint8 = new Uint8Array([7, 255]); + +function show(v: unknown): string { + return Object.is(v, -0) ? "-0" : String(v); +} + +function line(label: string, parts: unknown[]): void { + console.log(label.padEnd(12), parts.map(show).join(" ")); +} + +for (const k of [0, 1, 2, 3, -1, 1.5]) { + line(`int32 ${k}`, [ + int32[k]! === int32[k]!, + int32[k]! !== int32[0]!, + int32[k]! === undefined, + int32[k]! == null, + Object.is(int32[k]!, undefined), + typeof int32[k]!, + `${int32[k]!}`, + "v=" + int32[k]!, + String(int32[k]!), + int32[k]! + 1, + int32[k]! < 2, + [int32[k]!].length, + ]); + line(`float64 ${k}`, [ + float64[k]! === float64[k]!, + float64[k]! === undefined, + Object.is(float64[k]!, NaN), + typeof float64[k]!, + `${float64[k]!}`, + float64[k]! * 2, + -float64[k]!, + ]); + line(`uint8 ${k}`, [ + uint8[k]! === uint8[k]!, + uint8[k]! == undefined, + typeof uint8[k]!, + `${uint8[k]!}`, + uint8[k]! | 0, + uint8[k]! > 100, + ]); +} + +const optional: number | undefined = uint8[5]!; +const listed = [int32[9]!, float64[0]!]; +line("slots", [optional, listed[0], listed[1], listed.length]); + +let total = 0; +for (let i = 0; i <= int32.length; i++) total += int32[i]!; +line("sum", [total]); diff --git a/tests/harness/corpus-costs/7394-non-null-typed-array-reads.ts.json b/tests/harness/corpus-costs/7394-non-null-typed-array-reads.ts.json new file mode 100644 index 000000000..ad10beaaa --- /dev/null +++ b/tests/harness/corpus-costs/7394-non-null-typed-array-reads.ts.json @@ -0,0 +1 @@ +{ "plain": 4300, "san": 3900 } From 01e88d0b4862fb9d3b5c86e1e0b7a5f372e774b8 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 21:30:21 -0500 Subject: [PATCH 040/259] Support named properties and Symbol.species on typed arrays held as untyped values --- packages/cli/test/native-link-info.test.ts | 4 +- packages/compiler/src/backend/runtime-abi.ts | 4 +- .../src/backend/runtime-pack-targets.test.ts | 2 +- .../compiler/src/backend/runtime-pack.test.ts | 2 +- .../src/frontend/lowering/lower-calls.ts | 5 +- .../compiler/test/llvm-runtime-abi.test.ts | 7 +- .../test/native-codegen-integration.test.ts | 4 +- .../7753-typed-array-named-properties.js.json | 6 + .../runtime-darwin-arm64/scripts/build.mjs | 2 +- .../runtime-pack-common/scripts/build.mjs | 2 +- packages/runtime/src/scr_bytes.c | 13 +- packages/runtime/src/scr_bytes.h | 8 + packages/runtime/src/scr_console.c | 2 +- packages/runtime/src/scr_core.h | 2 +- packages/runtime/src/scr_dyn.h | 6 + packages/runtime/src/scr_dyn_invoke.c | 14 + packages/runtime/src/scr_inspect.c | 79 ++- packages/runtime/src/scr_json.c | 497 ++++++++++++++++-- packages/runtime/src/scr_symbol.c | 10 + .../7752-typed-array-dynamic-methods.js | 12 + .../7753-typed-array-named-properties.js | 143 +++++ .../7753-typed-array-named-properties.js.json | 1 + .../typed-array-property-refusals.test.ts | 64 +++ 23 files changed, 836 insertions(+), 53 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7753-typed-array-named-properties.js.json create mode 100644 tests/corpus/7753-typed-array-named-properties.js create mode 100644 tests/harness/corpus-costs/7753-typed-array-named-properties.js.json create mode 100644 tests/harness/typed-array-property-refusals.test.ts diff --git a/packages/cli/test/native-link-info.test.ts b/packages/cli/test/native-link-info.test.ts index 8ac579449..187dbc0d5 100644 --- a/packages/cli/test/native-link-info.test.ts +++ b/packages/cli/test/native-link-info.test.ts @@ -72,7 +72,7 @@ describe.runIf(supported)("macOS arm64 native link info", () => { minimum_os: "14.0", }, program: { object, entry_symbol: "main" }, - runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + runtime_abi: { version: 40, marker: "scr_runtime_abi_v40" }, runtime_pack: { kind: "precompiled", package: "@scriptc/runtime-darwin-arm64", @@ -165,6 +165,6 @@ describe.runIf(supported)("macOS arm64 native link info", () => { () => null, (failure: { stderr?: string }) => failure, ); - expect(error?.stderr).toContain("scr_runtime_abi_v37"); + expect(error?.stderr).toContain("scr_runtime_abi_v40"); }); }); diff --git a/packages/compiler/src/backend/runtime-abi.ts b/packages/compiler/src/backend/runtime-abi.ts index 11bde6c2b..229d8ec33 100644 --- a/packages/compiler/src/backend/runtime-abi.ts +++ b/packages/compiler/src/backend/runtime-abi.ts @@ -2,8 +2,8 @@ * of the link contract: a program object keeps this symbol undefined and the * matching runtime defines it, so incompatible manual links fail before the * program can start. */ -export const RUNTIME_ABI_VERSION = 37 as const; -export const RUNTIME_ABI_MARKER = "scr_runtime_abi_v37" as const; +export const RUNTIME_ABI_VERSION = 40 as const; +export const RUNTIME_ABI_MARKER = "scr_runtime_abi_v40" as const; /** Object consumption is useful today, but the complete scr_* surface may * still change before 1.0. The versioned marker prevents accidental mixing; diff --git a/packages/compiler/src/backend/runtime-pack-targets.test.ts b/packages/compiler/src/backend/runtime-pack-targets.test.ts index 9846e8d89..6e7a09fb3 100644 --- a/packages/compiler/src/backend/runtime-pack-targets.test.ts +++ b/packages/compiler/src/backend/runtime-pack-targets.test.ts @@ -52,7 +52,7 @@ async function fixture(target: NativeTargetSpec, workers = false) { object_format: target.objectFormat, minimum_os: target.minimumOs, }, - runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + runtime_abi: { version: 40, marker: "scr_runtime_abi_v40" }, compiler: { command: "fixture", identity: "fixture", target: target.llvmTriple }, macros: { executable: [], excluded: ["SCR_LIB"], sanitizer: "external-toolchain-required" }, flavors: { diff --git a/packages/compiler/src/backend/runtime-pack.test.ts b/packages/compiler/src/backend/runtime-pack.test.ts index e2b24f8ca..b2f5995fb 100644 --- a/packages/compiler/src/backend/runtime-pack.test.ts +++ b/packages/compiler/src/backend/runtime-pack.test.ts @@ -128,7 +128,7 @@ async function fixture(target: NativeTargetSpec = MACOS_ARM64_TARGET) { object_format: target.objectFormat, minimum_os: target.minimumOs, }, - runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + runtime_abi: { version: 40, marker: "scr_runtime_abi_v40" }, compiler: { command: "clang", identity: "fixture clang", diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 073ebed91..9eaf9535b 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -1087,7 +1087,10 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { if (!argNode || (ts.isIdentifier(argNode) && argNode.text === "undefined")) { return { kind: "libCall", fn: "sym.newAnon", args: [], type: SYMBOL_T, loc }; } - const desc = lowerer.lowerExpr(argNode); + let desc = lowerer.lowerExpr(argNode); + // A number or boolean description is its ToString. + if (desc.type.kind === "f64" || desc.type.kind === "bool") + desc = lowerer.ensureString(desc, argNode); if (desc.type.kind !== "string") { lowerer.noLowering( `Symbol with a '${lowerer.fmt(desc.type)}' description`, diff --git a/packages/compiler/test/llvm-runtime-abi.test.ts b/packages/compiler/test/llvm-runtime-abi.test.ts index 6cfd862b7..a457feb72 100644 --- a/packages/compiler/test/llvm-runtime-abi.test.ts +++ b/packages/compiler/test/llvm-runtime-abi.test.ts @@ -355,12 +355,13 @@ describe("LLVM backend declares match scr_runtime.h prototypes", () => { #include "scr_runtime.h" /* LLVM emits: %ScrBytes = type { i64, i64, i32, ptr, ptr, i8, i8, i8, i8, ptr }. - * Keep every ABI fact used by its field-index GEPs explicit here. */ + * Keep every ABI fact used by its field-index GEPs explicit here. The C + * struct continues with fields only the runtime reads. */ _Static_assert(sizeof(size_t) == 8, "LLVM ScrBytes expects 64-bit size_t"); _Static_assert(sizeof(void *) == 8, "LLVM ScrBytes expects 64-bit pointers"); _Static_assert(sizeof(ScrBytesElem) == 4, "LLVM ScrBytes elem field is i32"); _Static_assert(_Alignof(ScrBytes) == 8, "LLVM ScrBytes alignment changed"); -_Static_assert(sizeof(ScrBytes) == 56, "LLVM ScrBytes size changed"); +_Static_assert(sizeof(ScrBytes) == 64, "ScrBytes size changed"); _Static_assert(offsetof(ScrBytes, rc) == 0, "LLVM ScrBytes.rc offset changed"); _Static_assert(offsetof(ScrBytes, len) == 8, "LLVM ScrBytes.len offset changed"); _Static_assert(offsetof(ScrBytes, elem) == 16, "LLVM ScrBytes.elem offset changed"); @@ -370,7 +371,9 @@ _Static_assert(offsetof(ScrBytes, is_buffer) == 40, "LLVM ScrBytes.is_buffer off _Static_assert(offsetof(ScrBytes, is_data_view) == 41, "LLVM ScrBytes.is_data_view offset changed"); _Static_assert(offsetof(ScrBytes, external) == 42, "LLVM ScrBytes.external offset changed"); _Static_assert(offsetof(ScrBytes, untransferable) == 43, "LLVM ScrBytes.untransferable offset changed"); +_Static_assert(offsetof(ScrBytes, properties_traced) == 44, "ScrBytes.properties_traced must stay in padding"); _Static_assert(offsetof(ScrBytes, shared) == 48, "LLVM ScrBytes.shared offset changed"); +_Static_assert(offsetof(ScrBytes, properties) == 56, "ScrBytes.properties must follow the LLVM prefix"); `, ); const driver = resolveCc(); diff --git a/packages/compiler/test/native-codegen-integration.test.ts b/packages/compiler/test/native-codegen-integration.test.ts index cecebb49c..d35cbfefd 100644 --- a/packages/compiler/test/native-codegen-integration.test.ts +++ b/packages/compiler/test/native-codegen-integration.test.ts @@ -378,7 +378,7 @@ done: expect(await symbols(helperObject, ["-u"])).toEqual(await symbols(clangObject, ["-u"])); expect(await symbols(helperObject, ["-gU"])).toEqual(await symbols(clangObject, ["-gU"])); expect(await symbols(helperObject, ["-gU"])).toEqual(["0000000000000000 T _main"]); - expect(await symbols(helperObject, ["-u"])).toContain("_scr_runtime_abi_v37"); + expect(await symbols(helperObject, ["-u"])).toContain("_scr_runtime_abi_v40"); const clangExe = join(dir, "clang-program"); const linkDriver = join(dir, "clang-driver.c"); @@ -712,7 +712,7 @@ done: .split("\n"); expect(undefinedSymbols).toContain("_sf_scale"); expect(undefinedSymbols).toContain("_sf_callback_mix"); - expect(undefinedSymbols).toContain("_scr_runtime_abi_v37"); + expect(undefinedSymbols).toContain("_scr_runtime_abi_v40"); }); test("helper and clang object paths retain the same outbound FFI C ABI", async () => { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7753-typed-array-named-properties.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7753-typed-array-named-properties.js.json new file mode 100644 index 000000000..74a4316d9 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7753-typed-array-named-properties.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7753-typed-array-named-properties.js" + ], + "diags": [] +} diff --git a/packages/runtime-darwin-arm64/scripts/build.mjs b/packages/runtime-darwin-arm64/scripts/build.mjs index e492c36b4..27cafe022 100644 --- a/packages/runtime-darwin-arm64/scripts/build.mjs +++ b/packages/runtime-darwin-arm64/scripts/build.mjs @@ -340,7 +340,7 @@ async function build() { package: packageManifest.name, version: packageManifest.version, target: RUNTIME_PACK_MATRIX.target, - runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + runtime_abi: { version: 40, marker: "scr_runtime_abi_v40" }, compiler: { command: compiler, identity: compilerVersion, diff --git a/packages/runtime-pack-common/scripts/build.mjs b/packages/runtime-pack-common/scripts/build.mjs index e22f2a37c..318880a54 100644 --- a/packages/runtime-pack-common/scripts/build.mjs +++ b/packages/runtime-pack-common/scripts/build.mjs @@ -437,7 +437,7 @@ async function build() { package: packageManifest.name, version: packageManifest.version, target: matrix.target, - runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + runtime_abi: { version: 40, marker: "scr_runtime_abi_v40" }, compiler: { command: compiler, identity: compilerVersion, diff --git a/packages/runtime/src/scr_bytes.c b/packages/runtime/src/scr_bytes.c index 3926bf83e..e761641c2 100644 --- a/packages/runtime/src/scr_bytes.c +++ b/packages/runtime/src/scr_bytes.c @@ -190,6 +190,8 @@ ScrBytes *scr_bytes_take_data(uint8_t *data, size_t len) { b->external = false; b->untransferable = false; b->shared = NULL; + b->properties = NULL; + b->properties_traced = false; #ifdef SCR_RC_AUDIT scr_live_bytes++; #endif @@ -304,6 +306,7 @@ void scr_bytes_release(ScrBytes *b) { if (!b || b->rc == SIZE_MAX) return; /* NULL: an uninitialized `let` local */ if (--b->rc == 0) { scr_weak_dispose_inline(b); + if (b->properties) scr_dyn_release(b->properties); if (b->backing) { scr_bytes_release(b->backing); /* a view: data points into the owner */ } else if (b->shared) { @@ -740,6 +743,8 @@ ScrBytes *scr_bytes_subarray(ScrBytes *b, double start, double end) { v->external = false; v->untransferable = false; v->shared = owner->shared; + v->properties = NULL; + v->properties_traced = false; #ifdef SCR_RC_AUDIT scr_live_bytes++; #endif @@ -866,7 +871,9 @@ ScrBytes *scr_bytes_from_dyn(ScrBytesElem elem, const ScrDyn *value, bool from) if (value->kind == SCR_DYN_BYTES) return scr_bytes_convert(elem, value->v.bytes); if (!from && scr_buffer_storage_is(value)) return scr_array_buffer_view(elem, value, scr_dyn_undefined(), scr_dyn_undefined()); if (!from && (value->kind == SCR_DYN_NUM || value->kind == SCR_DYN_BOOL || - value->kind == SCR_DYN_STR || value->kind == SCR_DYN_NULL || value->kind == SCR_DYN_UNDEF)) { + value->kind == SCR_DYN_STR || value->kind == SCR_DYN_NULL || value->kind == SCR_DYN_UNDEF || + value->kind == SCR_DYN_SYMBOL || value->kind == SCR_DYN_BIGINT)) { + /* ToIndex: a Symbol or BigInt length throws ToNumber's TypeError. */ double number; if (!scr_dyn_number_coerce_js(value, &number)) return NULL; return scr_bytes_new(elem, number); @@ -992,6 +999,8 @@ ScrBytes *scr_dataview_new(ScrBytes *src, double byte_off, bool has_len, double v->external = false; v->untransferable = false; v->shared = owner->shared; + v->properties = NULL; + v->properties_traced = false; #ifdef SCR_RC_AUDIT scr_live_bytes++; #endif @@ -2883,6 +2892,8 @@ static ScrBytes *scr_pool_take(size_t len) { v->external = false; v->untransferable = false; v->shared = NULL; + v->properties = NULL; + v->properties_traced = false; #ifdef SCR_RC_AUDIT scr_live_bytes++; #endif diff --git a/packages/runtime/src/scr_bytes.h b/packages/runtime/src/scr_bytes.h index 7c0a935cc..64e3e299a 100644 --- a/packages/runtime/src/scr_bytes.h +++ b/packages/runtime/src/scr_bytes.h @@ -65,7 +65,15 @@ typedef struct ScrBytes { bool is_data_view; /* DataView is distinct from a numeric typed array. */ bool external; /* Root aliases foreign memory; releasing it never frees data. */ bool untransferable; /* A Buffer pool slab: its ArrayBuffer cannot be transferred. */ + /* The cycle collector's last trace of `properties` from the one checked + * value that held this view (see scr_dyn_trace_v). In padding, so the + * offsets compiled code uses hold. */ + bool properties_traced; ScrSharedBytes *shared; /* Neutral backing, borrowed by views from their local owner. */ + /* Named properties a program adds to the view (`ta.foo = 1`, + * Object.defineProperty): a checked object, NULL until the first one. + * Runtime-only and last, so compiled code's field indices hold. */ + struct ScrDyn *properties; } ScrBytes; /* Copies out of and into shared storage, made of relaxed atomic accesses diff --git a/packages/runtime/src/scr_console.c b/packages/runtime/src/scr_console.c index 086340014..06cc7ccd7 100644 --- a/packages/runtime/src/scr_console.c +++ b/packages/runtime/src/scr_console.c @@ -148,7 +148,7 @@ static void scr_enable_utf8_console_output(void) { } #endif -void scr_runtime_abi_v37(void) {} +void scr_runtime_abi_v40(void) {} void scr_init(void) { #ifdef SCR_WORKERS diff --git a/packages/runtime/src/scr_core.h b/packages/runtime/src/scr_core.h index 3707b8d50..bdb9942fe 100644 --- a/packages/runtime/src/scr_core.h +++ b/packages/runtime/src/scr_core.h @@ -81,7 +81,7 @@ void scr_init(void); /* Program objects emitted by the bundled LLVM helper reference this symbol. * Its versioned spelling makes a mismatched manual runtime link fail before * the program can start. */ -void scr_runtime_abi_v37(void); +void scr_runtime_abi_v40(void); void scr_runtime_workers_v8(void); /* ── the trap funnel (scr_console.c; scr_library.c under -DSCR_LIB) ────── diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index bd76c12e2..b4955220a 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -917,6 +917,9 @@ void scr_dyn_install_iterator_symbol(ScrDyn *key); void scr_dyn_install_has_instance_symbol(ScrDyn *key); void scr_dyn_install_async_iterator_symbol(ScrDyn *key); void scr_dyn_install_async_dispose_symbol(ScrDyn *key); +void scr_dyn_install_species_symbol(ScrDyn *key); +/* Records each well-known symbol the symbol unit creates. */ +void scr_dyn_install_well_known_symbol(ScrDyn *key); /* True when key is Symbol.asyncDispose (registered by the symbol unit when * the program names it); handle symbol_get ops outside that unit use it. */ bool scr_dyn_is_async_dispose_symbol(const ScrDyn *key); @@ -1003,6 +1006,9 @@ ScrDyn *scr_bytes_construct(const ScrDyn *callee, const ScrDyn *args, const ScrS extern SCR_TL bool (*scr_dyn_global_construct_fn)(const ScrDyn *callee, const ScrDyn *args, ScrDyn **result); ScrDyn *scr_dyn_bytes_key_get(const ScrDyn *value, const ScrStr *key); +/* A typed array's, Buffer's or DataView's own named property (+1), or NULL + * without an exception when it has none. */ +ScrDyn *scr_bytes_named_get(const ScrDyn *view, const char *key, size_t key_len); /* The Buffer-flavored twin (stream chunks): string coercion/toString * decode utf8 instead of joining elements. */ ScrDyn *scr_dyn_new_buffer(const ScrBytes *b); diff --git a/packages/runtime/src/scr_dyn_invoke.c b/packages/runtime/src/scr_dyn_invoke.c index b76fe38d2..96035cccc 100644 --- a/packages/runtime/src/scr_dyn_invoke.c +++ b/packages/runtime/src/scr_dyn_invoke.c @@ -1602,6 +1602,20 @@ static ScrDyn *scr_dyn_invoke_impl( if (recv->kind == SCR_DYN_BYTES) { ScrBytes *bytes = recv->v.bytes; + /* An own property of the view shadows the prototype's method. */ + ScrDyn *member = bytes->properties ? scr_bytes_named_get(recv, method, strlen(method)) : NULL; + if (!member && scr_exc_pending()) return NULL; + if (member) { + ScrDyn *result = NULL; + if (!scr_dyn_is_callable(member)) dyn_throw_not_fn(what); + else { + scr_dyn_this_push_dyn(recv); + result = scr_dyn_call(member, args, argc, what); + scr_dyn_this_pop(); + } + scr_dyn_release(member); + return result; + } if (bytes->is_data_view) { static const char *const kinds[] = { "Uint8", "Int8", "Uint16", "Int16", "Uint32", "Int32", "Float32", "Float64", "BigUint64", "BigInt64", "Float16" }; const bool get = !strncmp(method, "get", 3); diff --git a/packages/runtime/src/scr_inspect.c b/packages/runtime/src/scr_inspect.c index 011a1f582..ce85c00ff 100644 --- a/packages/runtime/src/scr_inspect.c +++ b/packages/runtime/src/scr_inspect.c @@ -743,6 +743,52 @@ ScrStr *scr_insp_regex(ScrRegex *re) { return ib_take(&out); } +/* Named properties of a typed array, Buffer or DataView (its + * ScrBytes.properties table): slot k is the k-th string-keyed entry, then + * the k-th symbol key. */ +static size_t insp_view_property_slots(const ScrDyn *props) { + if (!props) return 0; + return props->v.obj.len + (props->symbol_keys ? props->symbol_keys->v.arr.len : 0); +} + +static ScrStr *insp_accessor_tag(const ScrDynEntry *ent); +static void insp_key_into(InspBuf *b, const char *key, size_t len); + +/* Slot k's `key: value` entry when it is enumerable, else NULL. */ +static ScrStr *insp_view_property(ScrDyn *props, size_t k, double recurse, double depth) { + const ScrDynEntry *ent; + ScrStr *key = NULL; + if (k < props->v.obj.len) { + ent = &props->v.obj.entries[k]; + } else { + ScrDyn *symbol = props->symbol_keys->v.arr.items[k - props->v.obj.len]; + ent = scr_dyn_own_symbol_entry(props, symbol); + if (ent && ent->enumerable) key = scr_insp_dyn(symbol, recurse, depth); + } + if (!ent || !ent->enumerable) return NULL; + ScrStr *val = ent->accessor ? insp_accessor_tag(ent) : scr_insp_dyn(ent->value, recurse, depth); + InspBuf eb = {0}; + if (key) ib_bytes(&eb, key->data, key->len); + else insp_key_into(&eb, ent->key, ent->key_len); + ib_cstr(&eb, ": "); + ib_bytes(&eb, val->data, val->len); + scr_str_release(key); + scr_str_release(val); + return ib_take(&eb); +} + +static size_t insp_view_property_count(ScrDyn *props) { + size_t count = 0; + for (size_t k = 0; k < insp_view_property_slots(props); k++) { + if (k < props->v.obj.len) count += props->v.obj.entries[k].enumerable; + else { + const ScrDynEntry *ent = scr_dyn_own_symbol_entry(props, props->symbol_keys->v.arr.items[k - props->v.obj.len]); + count += ent && ent->enumerable; + } + } + return count; +} + /* Buffer: the custom-inspect hex form ``, capped at * INSPECT_MAX_BYTES (50); renders fully at any depth (custom inspection * runs before the depth check in Node). u8 element kind only (the @@ -765,6 +811,17 @@ ScrStr *scr_insp_buffer(ScrBytes *b) { remaining > 1 ? "s" : ""); ib_bytes(&out, more, (size_t)n); } + /* Named properties follow as `, key: value`, rendered as the members of + * an object at depth 0 (Buffer's custom inspect). */ + bool first = true; + for (size_t k = 0; k < insp_view_property_slots(b->properties); k++) { + ScrStr *entry = insp_view_property(b->properties, k, 1, 2); + if (!entry) continue; + if (!first || b->len) ib_cstr(&out, ", "); + first = false; + ib_bytes(&out, entry->data, entry->len); + scr_str_release(entry); + } ib_char(&out, '>'); return ib_take(&out); } @@ -848,6 +905,12 @@ static ScrStr *scr_insp_data_view(const ScrBytes *b, double recurse, double dept entry = ib_take(&eb); scr_insp_entry(entry, false); scr_str_release(entry); + for (size_t k = 0; k < insp_view_property_slots(b->properties); k++) { + entry = insp_view_property(b->properties, k, recurse + 1, depth); + if (!entry) continue; + scr_insp_entry(entry, false); + scr_str_release(entry); + } ScrStr *base = scr_str_new("", 0); ScrStr *b0 = scr_str_new("DataView {", 10); ScrStr *b1 = scr_str_new("}", 1); @@ -1455,7 +1518,10 @@ static ScrStr *scr_insp_obj(ScrDyn *d, double recurse, double depth, const char ScrStr *scr_insp_typed_array(ScrBytes *b, double recurse, double depth) { char prefix[48]; int pn = snprintf(prefix, sizeof prefix, "%s(%zu) [", scr_bytes_elem_name(b->elem), b->len); - if (b->len == 0) { + /* Named properties follow the elements as `key: value` entries. */ + ScrDyn *props = b->properties; + size_t nprops = insp_view_property_count(props); + if (b->len == 0 && nprops == 0) { InspBuf out = {0}; ib_bytes(&out, prefix, (size_t)pn); ib_char(&out, ']'); @@ -1479,10 +1545,19 @@ ScrStr *scr_insp_typed_array(ScrBytes *b, double recurse, double depth) { scr_insp_entry(m, true); scr_str_release(m); } + size_t entries = shown + (more ? 1 : 0); + for (size_t k = 0; nprops && k < insp_view_property_slots(props); k++) { + ScrStr *entry = insp_view_property(props, k, recurse + 1, depth); + if (!entry) continue; + /* Node's grouping pads by the element at the entry's output position. */ + scr_insp_entry(entry, entries < b->len); + scr_str_release(entry); + entries++; + } ScrStr *base = scr_str_new("", 0); ScrStr *b0 = scr_str_new(prefix, (size_t)pn); ScrStr *b1 = scr_str_new("]", 1); - ScrStr *out = scr_insp_end(base, b0, b1, recurse + 1, true, more); + ScrStr *out = scr_insp_end(base, b0, b1, recurse + 1, true, nprops ? entries > 100 : more); scr_str_release(base); scr_str_release(b0); scr_str_release(b1); diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 4af8c63b5..928d43490 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -202,6 +202,33 @@ void scr_dyn_install_has_instance_symbol(ScrDyn *key) { scr_atexit(scr_has_instance_symbol_cleanup); } +/* Symbol.species, installed when the program first evaluates it: no + * constructor names a species before then. */ +static SCR_TL ScrDyn *scr_species_symbol; +static void scr_species_symbol_cleanup(void) { + scr_dyn_release(scr_species_symbol); + scr_species_symbol = NULL; +} +void scr_dyn_install_species_symbol(ScrDyn *key) { + if (scr_species_symbol) return; + scr_species_symbol = scr_dyn_retain(key); + scr_atexit(scr_species_symbol_cleanup); +} + +/* The well-known symbols the program has created. They live until exit, + * so their identities are compared without a reference. */ +static SCR_TL const ScrSym *scr_well_known_symbols[24]; +static SCR_TL size_t scr_well_known_count; +void scr_dyn_install_well_known_symbol(ScrDyn *key) { + if (scr_well_known_count < sizeof scr_well_known_symbols / sizeof scr_well_known_symbols[0]) + scr_well_known_symbols[scr_well_known_count++] = key->v.symbol.value; +} +static bool scr_dyn_well_known_symbol(const ScrDyn *key) { + for (size_t i = 0; i < scr_well_known_count; i++) + if (scr_well_known_symbols[i] == key->v.symbol.value) return true; + return false; +} + void scr_dyn_install_iterator_symbol(ScrDyn *key) { if (scr_iterator_symbol) return; scr_iterator_symbol = scr_dyn_retain(key); @@ -880,6 +907,17 @@ void scr_dyn_trace_v(void *ptr, ScrTraceVisit visit, void *ctx) { } break; case SCR_DYN_FUNC: visit(d->v.fn.clo, ctx); break; + case SCR_DYN_BYTES: { + /* A view's named properties belong to its ScrBytes. Only a view this + * value alone holds owns that edge; a shared view's table stays out of + * trial deletion. Teardown reads the snapshot, not the count. */ + ScrBytes *bytes = d->v.bytes; + if (bytes->properties) { + bytes->properties_traced = bytes->rc == 1; + if (bytes->properties_traced) visit(bytes->properties, ctx); + } + break; + } case SCR_DYN_PROXY: visit(d->v.proxy.target, ctx); visit(d->v.proxy.handler, ctx); @@ -1144,6 +1182,8 @@ static void scr_dyn_dispose(ScrDyn *d, bool collected) { scr_str_release(d->v.str); break; case SCR_DYN_BYTES: + /* The collector frees a traced table itself. */ + if (collected && d->v.bytes->properties && d->v.bytes->properties_traced) d->v.bytes->properties = NULL; scr_bytes_release(d->v.bytes); break; case SCR_DYN_ARR: @@ -2417,10 +2457,27 @@ static bool scr_dyn_typed_ref_view_answer(ScrDyn *object, bool (*query)(const Sc return true; } +static ScrDyn *scr_bytes_properties(const ScrDyn *v); static bool scr_dyn_is_extensible_view(const ScrDyn *view) { + if (view->kind == SCR_DYN_BYTES) return !view->v.bytes->properties || !view->v.bytes->properties->non_extensible; return (view->kind == SCR_DYN_OBJ || view->kind == SCR_DYN_ARR) && !view->non_extensible; } +/* A view's integrity state lives on its named-property table. A typed array + * with elements cannot be frozen, and cannot be sealed while extensible: as + * in V8, the named properties are sealed or frozen and the view made + * non-extensible before the TypeError. */ +static bool scr_bytes_integrity_fence(const ScrDyn *view, const char *verb) { + if (view->v.bytes->is_data_view || view->v.bytes->len == 0) return false; + ScrJsonBuf message; + scr_jb_init(&message); + scr_jb_puts(&message, "Cannot "); + scr_jb_puts(&message, verb); + scr_jb_puts(&message, " array buffer views with elements"); + scr_throw_error(SCR_ERR_TYPE, scr_jb_finish(&message)); + return true; +} + /* A plain function's own properties (name, length, prototype, and the ones * a program adds) live in its property table, which carries the function's * integrity state too: freezing or sealing the function freezes or seals @@ -2467,6 +2524,7 @@ ScrDyn *scr_dyn_prevent_extensions(ScrDyn *object) { if (object->kind == SCR_DYN_ARR && object->v.arr.properties) object->v.arr.properties->non_extensible = true; } + if (object->kind == SCR_DYN_BYTES) scr_bytes_properties(object)->non_extensible = true; return scr_dyn_retain(object); } @@ -2495,6 +2553,12 @@ ScrDyn *scr_dyn_seal(ScrDyn *object) { return scr_dyn_retain(object); } if (scr_dyn_class_integrity_fence(object, "Object.seal")) return NULL; + if (object->kind == SCR_DYN_BYTES) { + bool extensible = scr_dyn_is_extensible_view(object); + scr_dyn_release(scr_dyn_seal(scr_bytes_properties(object))); + if (extensible && scr_bytes_integrity_fence(object, "seal")) return NULL; + return scr_dyn_retain(object); + } if (object->symbol_properties) scr_dyn_release(scr_dyn_seal(object->symbol_properties)); ScrDyn *table = scr_dyn_fn_integrity_table(object); if (table) { @@ -2530,6 +2594,8 @@ bool scr_dyn_is_sealed(const ScrDyn *object) { if (object->kind == SCR_DYN_ARR) return object->non_extensible && (object->v.arr.len == 0 || object->v.arr.sealed) && (!object->v.arr.properties || scr_dyn_is_sealed(object->v.arr.properties)); + /* V8 answers from a typed array's named properties alone. */ + if (object->kind == SCR_DYN_BYTES) return object->v.bytes->properties && scr_dyn_is_sealed(object->v.bytes->properties); if (object->kind != SCR_DYN_OBJ) return true; if (!object->non_extensible) return false; for (size_t i = 0; i < object->v.obj.len; i++) if (object->v.obj.entries[i].configurable) return false; @@ -2736,6 +2802,65 @@ static bool scr_dyn_data_view_proto_name(const ScrStr *key) { return scr_dyn_name_in(key, names, sizeof names / sizeof names[0]); } +/* A canonical numeric string ("1", "-0", "1.5", "Infinity"): typed arrays + * answer those keys as element indices, never as named properties. */ +static bool scr_bytes_numeric_key(const ScrStr *key, double *index) { + if (key->len == 2 && memcmp(key->data, "-0", 2) == 0) { *index = -0.0; return true; } + *index = scr_string_to_number(key); + char spelling[32]; + size_t length = scr_f64_to_str(*index, spelling); + return length == key->len && memcmp(spelling, key->data, length) == 0; +} + +/* Whether the view has an own named property `key`. */ +static bool scr_bytes_has_named(const ScrDyn *v, const ScrStr *key) { + const ScrDyn *properties = v->v.bytes->properties; + return properties && scr_dyn_obj_get(properties, key->data, key->len); +} + +/* The view's own named property `key` read with the view as a getter's + * `this` (+1), or NULL without an exception when the view has none. Only + * reads the table, so callers do not link the typed array methods. */ +ScrDyn *scr_bytes_named_get(const ScrDyn *view, const char *key, size_t key_len) { + const ScrDyn *properties = view->v.bytes->properties; + if (!properties || !scr_dyn_obj_get(properties, key, key_len)) return NULL; + return scr_dyn_obj_read_receiver(properties, key, key_len, view); +} + +/* The view's named-property table, created on first use. Borrowed. The + * table belongs to the ScrBytes, which several checked values can wrap. */ +static ScrDyn *scr_bytes_properties(const ScrDyn *v) { + ScrBytes *bytes = v->v.bytes; + if (!bytes->properties) bytes->properties = scr_dyn_new_obj_null_proto(); + return bytes->properties; +} + +/* Accessors without a setter on the view's prototype chain: writing one + * that the view does not own throws V8's strict-mode TypeError. */ +static bool scr_bytes_getter_name(const ScrDyn *v, const ScrStr *key) { + static const char *const names[] = { "byteLength", "byteOffset", "buffer", "length", "parent", "offset" }; + size_t count = v->v.bytes->is_data_view ? 3 : v->buffer ? 6 : 4; + return scr_dyn_name_in(key, names, count); +} + +/* Keys that the runtime's conversions, iteration and printing of a view + * read from its prototype without consulting its own properties. */ +static bool scr_bytes_protocol_name(const ScrStr *key) { + static const char *const names[] = { "toString", "valueOf", "toLocaleString", "toJSON", "join" }; + return scr_dyn_name_in(key, names, sizeof names / sizeof names[0]); +} + +static void scr_bytes_protocol_fence(const char *key, size_t key_len) { + ScrJsonBuf message; + scr_jb_init(&message); + scr_jb_puts(&message, "defining "); + scr_jb_write(&message, key, key_len); + scr_jb_puts(&message, " on a typed array, Buffer or DataView is not supported yet"); + ScrStr *text = scr_jb_finish(&message); + scr_throw_error_msg_code(SCR_ERR_ERROR, text->data, text->len, "SC2020"); + scr_str_release(text); +} + /* `in` on a typed array, Buffer or DataView. On a typed array, a canonical * numeric key (one that ToString(ToNumber(key)) reproduces, or "-0") * answers by bounds alone: an integral index, not -0, below the length. @@ -2743,6 +2868,7 @@ static bool scr_dyn_data_view_proto_name(const ScrStr *key) { * Buffer, or Object.prototype. A DataView has no indexed elements: its keys * name members of DataView.prototype or Object.prototype. */ static bool scr_dyn_bytes_in(const ScrDyn *v, const ScrStr *key) { + if (scr_bytes_has_named(v, key)) return true; if (v->v.bytes->is_data_view) return scr_dyn_data_view_proto_name(key) || scr_dyn_object_proto_name(key); if (key->len == 2 && memcmp(key->data, "-0", 2) == 0) return false; double index = scr_string_to_number(key); @@ -2858,6 +2984,19 @@ ScrDyn *scr_dyn_own_descriptor(const ScrDyn *value, const ScrStr *key) { scr_dyn_obj_set(out, "configurable", 12, scr_dyn_new_bool(false)); return out; } + if (value->kind == SCR_DYN_BYTES && scr_bytes_has_named(value, key)) + return scr_dyn_own_descriptor(value->v.bytes->properties, key); + if (value->kind == SCR_DYN_BYTES && !value->v.bytes->is_data_view) { + if (!scr_dyn_canonical_own_index(key, value->v.bytes->len)) return scr_dyn_retain(scr_dyn_undefined()); + size_t index = 0; + for (size_t i = 0; i < key->len; i++) index = index * 10 + (size_t)(key->data[i] - '0'); + ScrDyn *out = scr_dyn_new_obj(); + scr_dyn_obj_set(out, "value", 5, scr_dyn_new_num(scr_bytes_get(value->v.bytes, (double)index))); + scr_dyn_obj_set(out, "writable", 8, scr_dyn_new_bool(true)); + scr_dyn_obj_set(out, "enumerable", 10, scr_dyn_new_bool(true)); + scr_dyn_obj_set(out, "configurable", 12, scr_dyn_new_bool(true)); + return out; + } if (value->kind == SCR_DYN_ARR) { if (value->v.arr.properties && scr_dyn_obj_get(value->v.arr.properties, key->data, key->len)) @@ -4847,6 +4986,55 @@ static double *dyn_bytes_values(const ScrBytes *b, size_t n) { return values; } +/* SpeciesConstructor of a typed array: NULL (and no exception) for the + * default constructor of its kind, else the species constructor (+1). + * Only a `constructor` the program set on the view can differ. */ +static ScrDyn *scr_bytes_species(ScrDyn *recv, bool *failed) { + *failed = false; + ScrStr *name = scr_str_new("constructor", 11); + bool own = scr_bytes_has_named(recv, name); + ScrDyn *constructor = own ? scr_dyn_obj_read_receiver(recv->v.bytes->properties, name->data, name->len, recv) : NULL; + scr_str_release(name); + if (!own) return NULL; + if (!constructor) { *failed = true; return NULL; } + if (constructor->kind == SCR_DYN_UNDEF) { scr_dyn_release(constructor); return NULL; } + if (constructor->kind != SCR_DYN_OBJ && constructor->kind != SCR_DYN_FUNC) { + scr_dyn_release(constructor); + static const char message[] = "object.constructor is not an object"; + scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); + *failed = true; + return NULL; + } + ScrDyn *species = scr_species_symbol ? scr_dyn_symbol_key_get(constructor, scr_species_symbol, true) : NULL; + scr_dyn_release(constructor); + if (scr_exc_pending()) { scr_dyn_release(species); *failed = true; return NULL; } + if (!species || species->kind == SCR_DYN_UNDEF || species->kind == SCR_DYN_NULL || + scr_bytes_ctor_elem(species) == (int)recv->v.bytes->elem) { + scr_dyn_release(species); + return NULL; + } + if (!scr_dyn_is_callable(species)) { + scr_dyn_release(species); + static const char message[] = "object.constructor[Symbol.species] is not a constructor"; + scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); + *failed = true; + return NULL; + } + return species; +} + +/* TypedArraySpeciesCreate(recv, [n]): a new array of the receiver's kind + * (and Buffer flavor), or the species constructor's checked result. */ +static ScrDyn *scr_bytes_species_create(ScrDyn *recv, size_t n) { + bool failed; + ScrDyn *species = scr_bytes_species(recv, &failed); + if (failed) return NULL; + if (!species) return dyn_bytes_wrap(recv, scr_bytes_new(recv->v.bytes->elem, (double)n)); + ScrDyn *result = scr_bytes_static_create(species, n); + scr_dyn_release(species); + return result; +} + ScrDyn *scr_dyn_bytes_method(ScrDyn *recv, const char *method, ScrDyn *const *args, size_t argc, bool *handled) { ScrBytes *bytes = recv->v.bytes; size_t len = bytes->len; @@ -4866,11 +5054,41 @@ ScrDyn *scr_dyn_bytes_method(ScrDyn *recv, const char *method, ScrDyn *const *ar if (scr_exc_pending()) return NULL; double endD = scr_dyn_bytes_index_arg(args, argc, 1, (double)blen); if (scr_exc_pending()) return NULL; - ScrBytes *out = recv->buffer || scr_dyn_bytes_named(method, "subarray") - ? scr_bytes_subarray(bytes, startD, endD) : scr_bytes_slice(bytes, startD, endD); - ScrDyn *d = recv->buffer ? scr_dyn_new_buffer(out) : scr_dyn_new_bytes(out); + const bool subarray = recv->buffer || scr_dyn_bytes_named(method, "subarray"); + bool failed; + ScrDyn *species = recv->buffer ? NULL : scr_bytes_species(recv, &failed); + if (!recv->buffer && failed) return NULL; + ScrBytes *out = subarray ? scr_bytes_subarray(bytes, startD, endD) : scr_bytes_slice(bytes, startD, endD); + if (!species) { + ScrDyn *d = recv->buffer ? scr_dyn_new_buffer(out) : scr_dyn_new_bytes(out); + scr_bytes_release(out); + return d; + } + ScrDyn *result; + if (subarray) { + /* The species constructor views the same buffer. */ + ScrDyn *ctor_args = scr_dyn_new_arr(); + scr_dyn_arr_push(ctor_args, scr_array_buffer_from_bytes(bytes)); + scr_dyn_arr_push(ctor_args, scr_dyn_new_num(scr_bytes_byte_offset(out))); + scr_dyn_arr_push(ctor_args, scr_dyn_new_num((double)out->len)); + ScrStr *what = scr_str_new("TypedArray species", 18); + result = scr_dyn_construct(species, ctor_args, what); + scr_str_release(what); + scr_dyn_release(ctor_args); + if (result && (result->kind != SCR_DYN_BYTES || result->v.bytes->is_data_view)) { + scr_dyn_release(result); + result = NULL; + static const char message[] = "this is not a typed array."; + scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); + } + } else { + result = scr_bytes_static_create(species, out->len); + for (size_t i = 0; result && i < out->len; i++) + scr_bytes_set(result->v.bytes, (double)i, scr_bytes_get(out, (double)i)); + } + scr_dyn_release(species); scr_bytes_release(out); - return d; + return result; } if (scr_dyn_bytes_named(method, "set")) { double offset = scr_dyn_bytes_index_arg(args, argc, 1, 0); @@ -4908,6 +5126,22 @@ ScrDyn *scr_dyn_bytes_method(ScrDyn *recv, const char *method, ScrDyn *const *ar scr_str_release(joined); return out; } + if (scr_dyn_bytes_named(method, "toLocaleString")) { + /* Each element's Number.prototype.toLocaleString, joined by ",". */ + ScrJsonBuf b; + scr_jb_init(&b); + for (size_t i = 0; i < len; i++) { + if (i > 0) scr_jb_putc(&b, ','); + if (i >= bytes->len) continue; + ScrStr *text = scr_intl_num_format_en_us(scr_bytes_get(bytes, (double)i)); + scr_jb_write(&b, text->data, text->len); + scr_str_release(text); + } + ScrStr *joined = scr_jb_finish(&b); + ScrDyn *out = scr_dyn_new_str(joined); + scr_str_release(joined); + return out; + } if (scr_dyn_bytes_named(method, "keys") || scr_dyn_bytes_named(method, "values") || scr_dyn_bytes_named(method, "entries")) return scr_dyn_native_handle_iterator(recv, scr_dyn_bytes_named(method, "keys") ? 1 : scr_dyn_bytes_named(method, "entries") ? 2 : 0); if (scr_dyn_bytes_named(method, "indexOf") || scr_dyn_bytes_named(method, "lastIndexOf") || scr_dyn_bytes_named(method, "includes")) { @@ -4946,7 +5180,8 @@ ScrDyn *scr_dyn_bytes_method(ScrDyn *recv, const char *method, ScrDyn *const *ar if (!scr_dyn_bytes_cb_check(args, argc)) return NULL; ScrDyn *cb = args[0], *this_arg = argc > 1 ? args[1] : scr_dyn_undefined(); const bool backward = scr_dyn_bytes_named(method, "findLast") || scr_dyn_bytes_named(method, "findLastIndex"); - ScrBytes *mapped = scr_dyn_bytes_named(method, "map") ? scr_bytes_new(bytes->elem, (double)len) : NULL; + ScrDyn *mapped = NULL; + if (scr_dyn_bytes_named(method, "map") && !(mapped = scr_bytes_species_create(recv, len))) return NULL; double *kept = scr_dyn_bytes_named(method, "filter") ? malloc((len ? len : 1) * sizeof *kept) : NULL; size_t nkept = 0; for (size_t step = 0; step < len; step++) { @@ -4957,7 +5192,7 @@ ScrDyn *scr_dyn_bytes_method(ScrDyn *recv, const char *method, ScrDyn *const *ar scr_dyn_release(index); if (!r) { scr_dyn_release(item); - if (mapped) scr_bytes_release(mapped); + scr_dyn_release(mapped); free(kept); return NULL; } @@ -4966,8 +5201,8 @@ ScrDyn *scr_dyn_bytes_method(ScrDyn *recv, const char *method, ScrDyn *const *ar bool converted = scr_dyn_number_coerce_js(r, &v); scr_dyn_release(r); scr_dyn_release(item); - if (!converted) { scr_bytes_release(mapped); return NULL; } - if (k < mapped->len) scr_bytes_set(mapped, (double)k, v); + if (!converted) { scr_dyn_release(mapped); return NULL; } + if (k < mapped->v.bytes->len) scr_bytes_set(mapped->v.bytes, (double)k, v); continue; } bool truthy = scr_dyn_truthy(r); @@ -4988,12 +5223,12 @@ ScrDyn *scr_dyn_bytes_method(ScrDyn *recv, const char *method, ScrDyn *const *ar } scr_dyn_release(item); } - if (mapped) return dyn_bytes_wrap(recv, mapped); + if (mapped) return mapped; if (kept) { - ScrBytes *out = scr_bytes_new(bytes->elem, (double)nkept); - for (size_t i = 0; i < nkept; i++) scr_bytes_set(out, (double)i, kept[i]); + ScrDyn *out = scr_bytes_species_create(recv, nkept); + for (size_t i = 0; out && i < nkept; i++) scr_bytes_set(out->v.bytes, (double)i, kept[i]); free(kept); - return dyn_bytes_wrap(recv, out); + return out; } if (scr_dyn_bytes_named(method, "some")) return scr_dyn_new_bool(false); if (scr_dyn_bytes_named(method, "every")) return scr_dyn_new_bool(true); @@ -5120,6 +5355,8 @@ static ScrDyn *scr_dyn_bytes_method_value(const ScrStr *name, size_t arity) { /* Shared view metadata and indexed reads for both compiler backends. */ ScrDyn *scr_dyn_bytes_key_get(const ScrDyn *value, const ScrStr *key) { ScrBytes *bytes = value->v.bytes; + /* Own named properties first; a getter sees the view as `this`. */ + if (scr_bytes_has_named(value, key)) return scr_bytes_named_get(value, key->data, key->len); if (key->len == 10 && memcmp(key->data, "byteLength", 10) == 0) return scr_dyn_new_num(scr_bytes_byte_len(bytes)); if (key->len == 10 && memcmp(key->data, "byteOffset", 10) == 0) return scr_dyn_new_num(scr_bytes_byte_offset(bytes)); if (key->len == 6 && memcmp(key->data, "buffer", 6) == 0) return scr_array_buffer_from_bytes(bytes); @@ -6385,6 +6622,10 @@ static ScrDyn *scr_dyn_symbol_receiver(const ScrDyn *value) { if (value->kind == SCR_DYN_FUNC) return scr_dyn_fn_properties(value); if (value->kind == SCR_DYN_OBJ || value->kind == SCR_DYN_ARR || value->kind == SCR_DYN_HANDLE) return scr_dyn_retain((ScrDyn *)value); + /* A view keeps its symbol properties on its named-property table, which + * writes create first (scr_bytes_symbol_write). */ + if (value->kind == SCR_DYN_BYTES) + return value->v.bytes->properties ? scr_dyn_retain(value->v.bytes->properties) : NULL; if (value->kind == SCR_DYN_PROXY) { static const char message[] = "Symbol properties on this native value have no lowering"; scr_throw_error_msg_code(SCR_ERR_ERROR, message, sizeof message - 1, "SC2020"); @@ -7798,8 +8039,46 @@ void scr_dyn_symbol_key_placeholder(ScrDyn *value, ScrDyn *key) { entry->value = scr_dyn_retain(scr_dyn_undefined()); } +/* Symbol keys that the runtime reads from a view's prototype without + * consulting its own properties: the well-known symbols and + * util.inspect.custom. */ +static bool scr_bytes_protocol_symbol(const ScrDyn *key) { + if (scr_dyn_well_known_symbol(key)) return true; + ScrStr *description = key->v.symbol.description(key->v.symbol.value); + bool custom = description && description->len == 26 && !memcmp(description->data, "nodejs.util.inspect.custom", 26); + scr_str_release(description); + return custom; +} + +/* Before a symbol-keyed write or definition on a view: false with an + * exception pending for a key the view cannot own, else true with the + * view's table created. Symbol.toStringTag is an accessor without a setter + * on %TypedArray%.prototype, so assigning it throws V8's TypeError. */ +static bool scr_bytes_symbol_write(ScrDyn *value, const ScrDyn *key, bool assign) { + ScrDyn *receiver = scr_dyn_symbol_receiver(value); + bool own = receiver && scr_dyn_symbol_entry(receiver, key, true); + scr_dyn_release(receiver); + if (own) return true; + ScrStr *description = key->v.symbol.description(key->v.symbol.value); + bool tag = assign && !value->v.bytes->is_data_view && scr_dyn_well_known_symbol(key) && description && + description->len == 18 && !memcmp(description->data, "Symbol.toStringTag", 18); + if (tag) { + static const char message[] = "Cannot set property Symbol(Symbol.toStringTag) of [object Object] which has only a getter"; + scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); + } else if (scr_bytes_protocol_symbol(key)) { + ScrStr *name = key->v.symbol.render(key->v.symbol.value); + scr_bytes_protocol_fence(name->data, name->len); + scr_str_release(name); + } + scr_str_release(description); + if (scr_exc_pending()) return false; + scr_bytes_properties(value); + return true; +} + void scr_dyn_symbol_key_set(ScrDyn *value, ScrDyn *key, ScrDyn *stored) { if (scr_dyn_error_prototype_fence(value)) return; + if (value->kind == SCR_DYN_BYTES && !scr_bytes_symbol_write(value, key, true)) return; ScrDyn *receiver = scr_dyn_symbol_receiver(value); if (!receiver) { if (!scr_exc_pending()) { @@ -7822,6 +8101,18 @@ void scr_dyn_symbol_key_set(ScrDyn *value, ScrDyn *key, ScrDyn *stored) { scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); } else { bool present = scr_dyn_symbol_entry(receiver, key, true) != NULL; + if (!present && receiver->non_extensible) { + ScrStr *rendered = key->v.symbol.render(key->v.symbol.value); + ScrJsonBuf message; + scr_jb_init(&message); + scr_jb_puts(&message, "Cannot add property "); + scr_jb_write(&message, rendered->data, rendered->len); + scr_jb_puts(&message, ", object is not extensible"); + scr_str_release(rendered); + scr_throw_error(SCR_ERR_TYPE, scr_jb_finish(&message)); + scr_dyn_release(receiver); + return; + } scr_dyn_symbol_table(receiver); ScrStr *name = scr_dyn_symbol_storage_key(key); scr_dyn_key_set(receiver->symbol_properties, name, stored); @@ -7832,6 +8123,7 @@ void scr_dyn_symbol_key_set(ScrDyn *value, ScrDyn *key, ScrDyn *stored) { } static ScrDyn *scr_dyn_define_symbol(ScrDyn *target, ScrDyn *key, ScrDyn *descriptor) { + if (target->kind == SCR_DYN_BYTES && !scr_bytes_symbol_write(target, key, false)) return NULL; ScrDyn *receiver = scr_dyn_symbol_receiver(target); if (!receiver) { if (!scr_exc_pending()) { @@ -8026,6 +8318,53 @@ ScrDyn *scr_dyn_define_property(ScrDyn *target, ScrDyn *key, ScrDyn *descriptor) scr_dyn_release(defined); return scr_dyn_retain(target); } + if (target->kind == SCR_DYN_BYTES) { + ScrStr *name = scr_dyn_property_key(key); + if (!name) return NULL; + double index; + bool numeric = !target->v.bytes->is_data_view && scr_bytes_numeric_key(name, &index); + if (numeric) { + /* [[DefineOwnProperty]] of an element: a valid index and a data + * descriptor that keeps it writable, enumerable and configurable. */ + bool valid = !signbit(index) && trunc(index) == index && index < (double)target->v.bytes->len; + const ScrDyn *configurable = scr_dyn_obj_get(descriptor, "configurable", 12); + const ScrDyn *enumerable = scr_dyn_obj_get(descriptor, "enumerable", 10); + const ScrDyn *writable = scr_dyn_obj_get(descriptor, "writable", 8); + bool accessor = scr_dyn_obj_get(descriptor, "get", 3) || scr_dyn_obj_get(descriptor, "set", 3); + if (!valid) { + scr_str_release(name); + static const char message[] = "Invalid typed array index"; + scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); + return NULL; + } + if (accessor || (configurable && !scr_dyn_truthy(configurable)) || + (enumerable && !scr_dyn_truthy(enumerable)) || (writable && !scr_dyn_truthy(writable))) { + ScrJsonBuf message; + scr_jb_init(&message); + scr_jb_puts(&message, "Cannot redefine property: "); + scr_jb_write(&message, name->data, name->len); + scr_str_release(name); + scr_throw_error(SCR_ERR_TYPE, scr_jb_finish(&message)); + return NULL; + } + scr_str_release(name); + const ScrDyn *value = scr_dyn_obj_get(descriptor, "value", 5); + double number; + if (value) { + if (!scr_dyn_number_coerce_js(value, &number)) return NULL; + scr_bytes_set(target->v.bytes, index, number); + } + return scr_dyn_retain(target); + } + bool fenced = scr_bytes_protocol_name(name) && !scr_bytes_has_named(target, name); + if (fenced) scr_bytes_protocol_fence(name->data, name->len); + scr_str_release(name); + if (fenced) return NULL; + ScrDyn *defined = scr_dyn_define_property(scr_bytes_properties(target), key, descriptor); + if (!defined) return NULL; + scr_dyn_release(defined); + return scr_dyn_retain(target); + } if (target->kind != SCR_DYN_OBJ) { static const char msg[] = "Object.defineProperty called on non-object"; scr_throw_error_msg(SCR_ERR_TYPE, msg, sizeof msg - 1); @@ -8173,7 +8512,7 @@ ScrDyn *scr_dyn_get_own_property_descriptor(ScrDyn *target, ScrDyn *key) { scr_throw_error_msg(SCR_ERR_TYPE, msg, sizeof msg - 1); return NULL; } - if (target->kind != SCR_DYN_OBJ && target->kind != SCR_DYN_PROXY && target->kind != SCR_DYN_FUNC && target->kind != SCR_DYN_ARR && target->kind != SCR_DYN_STR && target->kind != SCR_DYN_BOOL && target->kind != SCR_DYN_NUM && target->kind != SCR_DYN_TYPED_REF) { + if (target->kind != SCR_DYN_OBJ && target->kind != SCR_DYN_PROXY && target->kind != SCR_DYN_FUNC && target->kind != SCR_DYN_ARR && target->kind != SCR_DYN_STR && target->kind != SCR_DYN_BOOL && target->kind != SCR_DYN_NUM && target->kind != SCR_DYN_TYPED_REF && target->kind != SCR_DYN_BYTES) { static const char msg[] = "Object.getOwnPropertyDescriptor on this value is not supported yet"; scr_throw_error_msg(SCR_ERR_ERROR, msg, sizeof msg - 1); return NULL; @@ -8477,7 +8816,8 @@ static bool scr_dyn_json_write(ScrJsonBuf *b, const ScrDyn *d) { const ScrBytes *bytes = d->v.bytes; if (d->buffer) scr_jb_puts(b, "{\"type\":\"Buffer\",\"data\":["); else scr_jb_putc(b, '{'); - for (size_t i = 0; i < bytes->len; i++) { + size_t count = bytes->is_data_view ? 0 : bytes->len; + for (size_t i = 0; i < count; i++) { if (i > 0) scr_jb_putc(b, ','); if (!d->buffer) { char idx[32]; @@ -8486,6 +8826,32 @@ static bool scr_dyn_json_write(ScrJsonBuf *b, const ScrDyn *d) { } scr_jb_put_f64(b, scr_bytes_get(bytes, (double)i)); } + /* Named properties follow the elements; a Buffer's toJSON leaves them + * out. */ + ScrDyn *named = d->buffer || !bytes->properties ? NULL : scr_dyn_obj_keys(bytes->properties); + bool first = count == 0; + for (size_t i = 0; named && i < named->v.arr.len; i++) { + const ScrStr *key = named->v.arr.items[i]->v.str; + ScrDyn *value = scr_dyn_obj_read_receiver(bytes->properties, key->data, key->len, d); + if (!value) { scr_dyn_release(named); return false; } + ScrJsonBuf probe; + scr_jb_init(&probe); + bool present = scr_dyn_json_write(&probe, value); + scr_dyn_release(value); + if (!present) { + scr_jb_dispose(&probe); + if (scr_exc_pending()) { scr_dyn_release(named); return false; } + continue; + } + if (!first) scr_jb_putc(b, ','); + first = false; + scr_jb_put_json_str(b, key); + scr_jb_putc(b, ':'); + ScrStr *body = scr_jb_finish(&probe); + scr_jb_write(b, body->data, body->len); + scr_str_release(body); + } + scr_dyn_release(named); scr_jb_puts(b, d->buffer ? "]}" : "}"); return true; } @@ -10221,6 +10587,7 @@ bool scr_dyn_has_key(const ScrDyn *v, const ScrStr *key) { } if (v->kind == SCR_DYN_STR) return scr_dyn_canonical_own_index(key, (size_t)scr_str_utf16_len(v->v.str)); + if (v->kind == SCR_DYN_BYTES) return scr_dyn_bytes_in(v, key); return false; } @@ -10283,7 +10650,13 @@ static void scr_dyn_throw_property(const ScrDyn *object, const char *key, size_t scr_jb_puts(&buffer, deleting ? "Cannot delete property '" : "Cannot assign to read only property '"); scr_jb_write(&buffer, key, key_len); scr_jb_puts(&buffer, deleting ? "' of " : "' of object '"); - if (object->null_proto) scr_jb_puts(&buffer, "[object Object]"); + if (object->kind == SCR_DYN_BYTES) { + /* V8 names a typed array by its tag and a DataView by its class. */ + const char *kind = object->v.bytes->is_data_view ? "DataView" : scr_bytes_elem_name(object->v.bytes->elem); + scr_jb_puts(&buffer, object->v.bytes->is_data_view ? "#<" : "[object "); + scr_jb_puts(&buffer, kind); + scr_jb_puts(&buffer, object->v.bytes->is_data_view ? ">" : "]"); + } else if (object->null_proto) scr_jb_puts(&buffer, "[object Object]"); else { scr_jb_puts(&buffer, "#<"); scr_jb_puts(&buffer, name ? name : "Object"); @@ -10497,19 +10870,36 @@ void scr_dyn_key_set(ScrDyn *recv, ScrStr *key, ScrDyn *value) { } if (recv->kind == SCR_DYN_BYTES) { /* Integer-indexed exotic writes coerce even for an invalid canonical - * numeric index, then ignore an out-of-range index without an error. */ - double index = scr_string_to_number(key); - char spelling[32]; - size_t length = scr_f64_to_str(index, spelling); - bool negative_zero = key->len == 2 && memcmp(key->data, "-0", 2) == 0; - if (negative_zero || (length == key->len && memcmp(spelling, key->data, length) == 0)) { + * numeric index, then ignore an out-of-range index without an error. + * A DataView has no elements: its numeric keys are named properties. */ + double index; + if (!recv->v.bytes->is_data_view && scr_bytes_numeric_key(key, &index)) { double number; if (!scr_dyn_number_coerce_js(value, &number)) return; - if (!negative_zero && index >= 0 && index < (double)recv->v.bytes->len && trunc(index) == index) { + if (!signbit(index) && index < (double)recv->v.bytes->len && trunc(index) == index) { scr_bytes_set(recv->v.bytes, index, number); } return; } + /* Any other key is a named property of the view. */ + if (!scr_bytes_has_named(recv, key)) { + if (scr_bytes_getter_name(recv, key)) { + ScrJsonBuf message; + scr_jb_init(&message); + scr_jb_puts(&message, "Cannot set property "); + scr_jb_write(&message, key->data, key->len); + scr_jb_puts(&message, recv->v.bytes->is_data_view ? " of # which has only a getter" + : " of [object Object] which has only a getter"); + scr_throw_error(SCR_ERR_TYPE, scr_jb_finish(&message)); + return; + } + if (scr_bytes_protocol_name(key)) { + scr_bytes_protocol_fence(key->data, key->len); + return; + } + } + scr_dyn_object_key_set(scr_bytes_properties(recv), key, value, recv); + return; } ScrJsonBuf b; @@ -12181,6 +12571,11 @@ static ScrDyn *scr_json_member(const ScrDyn *holder, const ScrStr *key) { scr_dyn_release(view); return member; } + /* A view's named properties, getters included, read through the view. */ + if (holder->kind == SCR_DYN_BYTES && (holder->v.bytes->is_data_view || scr_bytes_has_named(holder, key))) { + ScrDyn *named = scr_bytes_named_get(holder, key->data, key->len); + return named || scr_exc_pending() ? named : scr_dyn_retain(scr_dyn_undefined()); + } if (holder->kind == SCR_DYN_ARR || holder->kind == SCR_DYN_BYTES) { size_t index = 0; for (size_t i = 0; i < key->len; i++) index = index * 10 + (size_t)(key->data[i] - '0'); @@ -12324,6 +12719,23 @@ void scr_dyn_key_delete(ScrDyn *recv, const ScrStr *key, bool strict) { scr_dyn_key_delete(recv->v.arr.properties, key, strict); return; } + if (recv->kind == SCR_DYN_BYTES) { + /* A typed array's elements cannot be deleted; other numeric keys name + * no property. Named properties follow their configurability. */ + double index; + if (!recv->v.bytes->is_data_view && scr_bytes_numeric_key(key, &index)) { + if (strict && !signbit(index) && trunc(index) == index && index < (double)recv->v.bytes->len) + scr_dyn_throw_property(recv, key->data, key->len, true); + return; + } + ScrDynEntry *entry = recv->v.bytes->properties ? scr_dyn_entry(recv->v.bytes->properties, key) : NULL; + if (entry && !entry->configurable) { + if (strict) scr_dyn_throw_property(recv, key->data, key->len, true); + return; + } + if (entry) scr_json_delete_member(recv->v.bytes->properties, key); + return; + } if (recv->kind == SCR_DYN_UNDEF || recv->kind == SCR_DYN_NULL) { const char *message = "Cannot convert undefined or null to object"; scr_throw_error_msg(SCR_ERR_TYPE, message, strlen(message)); @@ -13982,7 +14394,7 @@ ScrDyn *scr_dyn_get_own_property_names(const ScrDyn *value) { if (value->kind == SCR_DYN_ARR || value->kind == SCR_DYN_STR || value->kind == SCR_DYN_BYTES) { ScrDyn *keys = scr_dyn_new_arr(); size_t length = value->kind == SCR_DYN_ARR ? value->v.arr.len : - value->kind == SCR_DYN_BYTES ? value->v.bytes->len : + value->kind == SCR_DYN_BYTES ? (value->v.bytes->is_data_view ? 0 : value->v.bytes->len) : (size_t)scr_str_utf16_len(value->v.str); for (size_t i = 0; i < length; i++) { if (value->kind == SCR_DYN_ARR && !scr_dyn_arr_has_index(value, i)) continue; @@ -13992,8 +14404,10 @@ ScrDyn *scr_dyn_get_own_property_names(const ScrDyn *value) { } if (value->kind != SCR_DYN_BYTES) scr_dyn_arr_push(keys, scr_dyn_objwalk_key("length", 6)); - if (value->kind == SCR_DYN_ARR && value->v.arr.properties) { - ScrDyn *properties = scr_dyn_obj_own_keys(value->v.arr.properties); + ScrDyn *named = value->kind == SCR_DYN_ARR ? value->v.arr.properties + : value->kind == SCR_DYN_BYTES ? value->v.bytes->properties : NULL; + if (named) { + ScrDyn *properties = scr_dyn_obj_own_keys(named); for (size_t i = 0; i < properties->v.arr.len; i++) scr_dyn_arr_push(keys, scr_dyn_retain(properties->v.arr.items[i])); scr_dyn_release(properties); @@ -14258,7 +14672,7 @@ static ScrDyn *scr_dyn_objwalk(const ScrDyn *v, ScrObjWalk mode) { return out; } if (v->kind == SCR_DYN_ARR || v->kind == SCR_DYN_BYTES) { - size_t n = v->kind == SCR_DYN_ARR ? v->v.arr.len : v->v.bytes->len; + size_t n = v->kind == SCR_DYN_ARR ? v->v.arr.len : v->v.bytes->is_data_view ? 0 : v->v.bytes->len; for (size_t i = 0; i < n; i++) { if (v->kind == SCR_DYN_ARR && !scr_dyn_arr_has_index(v, i)) continue; char key[24]; @@ -14279,10 +14693,11 @@ static ScrDyn *scr_dyn_objwalk(const ScrDyn *v, ScrObjWalk mode) { scr_dyn_arr_push(out, pair); } } - if (v->kind == SCR_DYN_ARR && v->v.arr.properties) { - ScrDyn *names = scr_dyn_obj_own_keys(v->v.arr.properties); + ScrDyn *named = v->kind == SCR_DYN_ARR ? v->v.arr.properties : v->v.bytes->properties; + if (named) { + ScrDyn *names = scr_dyn_obj_own_keys(named); for (size_t i = 0; i < names->v.arr.len; i++) { - if (!scr_dyn_objwalk_entry(out, v->v.arr.properties, mode, names->v.arr.items[i]->v.str, v)) { + if (!scr_dyn_objwalk_entry(out, named, mode, names->v.arr.items[i]->v.str, v)) { scr_dyn_release(names); scr_dyn_release(out); return NULL; @@ -14386,6 +14801,7 @@ ScrDyn *scr_dyn_for_in_keys(const ScrDyn *v) { return keys; } case SCR_DYN_ARR: + case SCR_DYN_BYTES: return scr_dyn_obj_keys(v); case SCR_DYN_STR: { ScrDyn *keys = scr_dyn_new_arr(); @@ -14639,7 +15055,7 @@ static void scr_dyn_assign_strings_from(ScrDyn *target, const ScrDyn *src, bool scr_dyn_proxy_unsupported("Object.assign"); return; } - if (target->kind != SCR_DYN_OBJ && target->kind != SCR_DYN_FUNC) return; + if (target->kind != SCR_DYN_OBJ && target->kind != SCR_DYN_FUNC && target->kind != SCR_DYN_BYTES) return; if (src->kind == SCR_DYN_TYPED_REF) { ScrDyn *materialized = scr_dyn_typed_ref_materialize(src); if (materialized) scr_dyn_assign_strings_from(target, materialized, define); @@ -14702,13 +15118,15 @@ static void scr_dyn_assign_from(ScrDyn *target, const ScrDyn *src, bool define) return; } ScrDyn *view = src->kind == SCR_DYN_FUNC ? scr_dyn_fn_properties(src) : scr_dyn_retain((ScrDyn *)src); + /* A view's symbol properties live on its named-property table. */ + const ScrDyn *holder = src->kind == SCR_DYN_BYTES ? src->v.bytes->properties : view; ScrDyn *symbols = scr_dyn_new_arr(); - if (view->symbol_keys) for (size_t i = 0; i < view->symbol_keys->v.arr.len; i++) - scr_dyn_arr_push(symbols, scr_dyn_retain(view->symbol_keys->v.arr.items[i])); + if (holder && holder->symbol_keys) for (size_t i = 0; i < holder->symbol_keys->v.arr.len; i++) + scr_dyn_arr_push(symbols, scr_dyn_retain(holder->symbol_keys->v.arr.items[i])); scr_dyn_assign_strings_from(target, view, define); for (size_t i = 0; i < symbols->v.arr.len && !scr_exc_pending(); i++) { ScrDyn *key = symbols->v.arr.items[i]; - ScrDynEntry *entry = scr_dyn_symbol_entry(view, key, true); + ScrDynEntry *entry = scr_dyn_symbol_entry(holder, key, true); if (!entry || !entry->enumerable) continue; ScrDyn *value = scr_dyn_symbol_key_get(src, key, false); if (!value) break; @@ -15093,7 +15511,7 @@ bool scr_dyn_has_own(const ScrDyn *v, const ScrStr *key) { return scr_dyn_canonical_own_index(key, (size_t)scr_str_utf16_len(v->v.str)); } if (v->kind == SCR_DYN_BYTES) { - return scr_dyn_canonical_own_index(key, v->v.bytes->len); + return (!v->v.bytes->is_data_view && scr_dyn_canonical_own_index(key, v->v.bytes->len)) || scr_bytes_has_named(v, key); } if (v->kind == SCR_DYN_FUNC) { ScrDyn *desc = scr_dyn_own_descriptor(v, key); @@ -15130,7 +15548,8 @@ bool scr_dyn_property_is_enumerable(const ScrDyn *value, const ScrStr *key) { return (scr_dyn_canonical_own_index(key, value->v.arr.len) && scr_dyn_has_own(value, key)) || (value->v.arr.properties && scr_dyn_obj_enumerable(value->v.arr.properties, key->data, key->len)); if (value->kind == SCR_DYN_BYTES) - return scr_dyn_canonical_own_index(key, value->v.bytes->len); + return (!value->v.bytes->is_data_view && scr_dyn_canonical_own_index(key, value->v.bytes->len)) || + (value->v.bytes->properties && scr_dyn_obj_enumerable(value->v.bytes->properties, key->data, key->len)); return false; } ScrDyn *scr_dyn_obj_values(const ScrDyn *v) { return scr_dyn_objwalk(v, SCR_OBJWALK_VALUES); } @@ -16834,6 +17253,11 @@ ScrDyn *scr_dyn_freeze_data(ScrDyn *value) { ScrDyn *native = scr_dyn_freeze_native(value); if (native) return native; if (scr_dyn_class_integrity_fence(value, "Object.freeze")) return NULL; + if (value->kind == SCR_DYN_BYTES) { + scr_dyn_release(scr_dyn_freeze_data(scr_bytes_properties(value))); + if (scr_bytes_integrity_fence(value, "freeze")) return NULL; + return scr_dyn_retain(value); + } if (value->symbol_properties) scr_dyn_release(scr_dyn_freeze_data(value->symbol_properties)); if (value->kind == SCR_DYN_ARR) { value->non_extensible = true; @@ -16875,6 +17299,9 @@ bool scr_dyn_is_frozen(const ScrDyn *value) { if (value->kind == SCR_DYN_ARR) return scr_dyn_is_sealed(value) && (value->v.arr.len == 0 || value->v.arr.frozen) && (!value->v.arr.properties || scr_dyn_is_frozen(value->v.arr.properties)); + if (value->kind == SCR_DYN_BYTES) + return (value->v.bytes->is_data_view || value->v.bytes->len == 0) && value->v.bytes->properties && + scr_dyn_is_frozen(value->v.bytes->properties); if (value->kind == SCR_DYN_OBJ && !value->copied_from_native) { if (!value->non_extensible) return false; for (size_t i = 0; i < value->v.obj.len; i++) { diff --git a/packages/runtime/src/scr_symbol.c b/packages/runtime/src/scr_symbol.c index 647c31dc3..fb0b6cb0b 100644 --- a/packages/runtime/src/scr_symbol.c +++ b/packages/runtime/src/scr_symbol.c @@ -80,6 +80,11 @@ ScrSym *scr_sym_well_known(ScrStr *name) { scr_str_release(description); symbol->reg_next = g_sym_well_known; g_sym_well_known = scr_sym_retain(symbol); + { + ScrDyn *key = scr_dyn_new_symbol(symbol); + scr_dyn_install_well_known_symbol(key); + scr_dyn_release(key); + } if (name->len == 8 && !memcmp(name->data, "iterator", 8)) { ScrDyn *key = scr_dyn_new_symbol(symbol); scr_dyn_install_iterator_symbol(key); @@ -90,6 +95,11 @@ ScrSym *scr_sym_well_known(ScrStr *name) { scr_dyn_install_has_instance_symbol(key); scr_dyn_release(key); } + if (name->len == 7 && !memcmp(name->data, "species", 7)) { + ScrDyn *key = scr_dyn_new_symbol(symbol); + scr_dyn_install_species_symbol(key); + scr_dyn_release(key); + } if (name->len == 13 && !memcmp(name->data, "asyncIterator", 13)) { ScrDyn *key = scr_dyn_new_symbol(symbol); scr_dyn_install_async_iterator_symbol(key); diff --git a/tests/corpus/7752-typed-array-dynamic-methods.js b/tests/corpus/7752-typed-array-dynamic-methods.js index a728e3ce9..d4f077b49 100644 --- a/tests/corpus/7752-typed-array-dynamic-methods.js +++ b/tests/corpus/7752-typed-array-dynamic-methods.js @@ -123,3 +123,15 @@ function plainIterator(TA) { console.log(new TA(source), TA.from(source, (v) => v * 2), gets, nexts); } plainIterator(Int16Array); +// ToIndex of a Symbol or BigInt length, toLocaleString, and Symbol descriptions +// that are not strings. +function small(TA) { + for (const bad of [Symbol("s"), 1n]) { + try { new TA(bad); console.log("no throw"); } catch (e) { console.log(e.constructor.name); } + } + console.log(new TA([1, 1234.5, -0, 0]).toLocaleString(), new TA(0).toLocaleString(), typeof new TA(1).toLocaleString); +} +small(Float64Array); +small(Uint16Array); +const s = Symbol(1), t = Symbol(true), u = Symbol(2.5); +console.log(s.description, t.description, u.toString(), typeof s.description); diff --git a/tests/corpus/7753-typed-array-named-properties.js b/tests/corpus/7753-typed-array-named-properties.js new file mode 100644 index 000000000..b49f100b5 --- /dev/null +++ b/tests/corpus/7753-typed-array-named-properties.js @@ -0,0 +1,143 @@ +// Named properties on typed arrays, Buffers and DataViews (assignment, +// Object.defineProperty, reflection, deletion, integrity levels, JSON and +// inspection), and the Symbol.species constructor of map, filter, slice and +// subarray. +function box(value) { + const holder = {}; + holder.value = value; + return holder.value; +} + +function expandos(TA) { + const a = new TA([1, 2]); + a.foo = 1; + a.bar = "x"; + a[5] = 9; + a["1.5"] = 7; + console.log(a, a.foo, "foo" in a, a.hasOwnProperty("bar"), Object.keys(a), Object.entries(a).length); + console.log(Object.getOwnPropertyNames(a), JSON.stringify(Object.getOwnPropertyDescriptor(a, "foo")), JSON.stringify(Object.getOwnPropertyDescriptor(a, "0"))); + Object.defineProperty(a, "hidden", { value: 3, enumerable: false }); + Object.defineProperty(a, "0", { value: 8 }); + console.log(a, a.hidden, Object.keys(a)); + try { Object.defineProperty(a, "1", { value: 1, configurable: false }); } catch (e) { console.log(e.constructor.name, e.message); } + try { Object.defineProperty(a, "7", { value: 1 }); } catch (e) { console.log(e.constructor.name, e.message); } + try { Object.defineProperty(a, "-0", { value: 1 }); } catch (e) { console.log(e.constructor.name, e.message); } + try { Object.defineProperty(a, "0", { get() { return 1; } }); } catch (e) { console.log(e.constructor.name, e.message); } + let reads = 0; + Object.defineProperty(a, "g", { get() { reads++; return this.length; }, enumerable: true }); + console.log(a.g, reads, new TA(0)); + const e = new TA(0); + e.k = { deep: [1] }; + console.log(e); +} + +function species(TA, Other) { + const s = new TA([1, 2, 3, 4]); + const calls = []; + s.constructor = {}; + s.constructor[Symbol.species] = function (n) { calls.push(n); return new Other(n); }; + const m = s.map((v) => v * 1.5), f = s.filter((v) => v > 1), sl = s.slice(1, 3); + console.log(m, f, sl, calls); + s.constructor[Symbol.species] = function (buffer, offset, length) { calls.push([offset, length]); return new TA(buffer, offset, length); }; + const sub = s.subarray(1, 3); + sub[0] = 50; + console.log(sub, s[1], calls.length); + s.constructor[Symbol.species] = function () { return {}; }; + try { s.map((v) => v); } catch (err) { console.log(err.constructor.name); } + s.constructor[Symbol.species] = function () { return new TA(1); }; + try { s.slice(); } catch (err) { console.log(err.constructor.name); } + s.constructor = 5; + try { s.filter(() => true); } catch (err) { console.log(err.constructor.name); } + s.constructor = undefined; + console.log(s.map((v) => v + 1)); + const t = new TA([3, 1]); + Object.defineProperty(t, "constructor", { get() { calls.push("get"); return undefined; } }); + console.log(t.slice(), calls[calls.length - 1]); + const u = new TA([1, 2, 3]); + u.constructor = { [Symbol.species]: Uint16Array }; + console.log(u.filter(() => true), u.subarray(1), u.subarray(1).constructor === Uint16Array); +} + +function reflection(TA) { + const a = new TA([1, 2]); + a.foo = 1; + a[Symbol.for("s")] = 2; + const keys = []; + for (const k in a) keys.push(k); + console.log(keys, { ...a }, JSON.stringify(a), Object.values(a)); + console.log(a.propertyIsEnumerable("foo"), Object.hasOwn(a, "foo"), Object.getOwnPropertySymbols(a), a[Symbol.for("s")]); + console.log(Object.assign(new TA(2), { x: 1, 0: 9 }), Object.assign({}, a)); + delete a.foo; + delete a[5]; + delete a.length; + console.log(a, "foo" in a, a.length); + try { delete a[0]; } catch (err) { console.log(err.message); } + Object.defineProperty(a, "fixed", { value: 1 }); + try { delete a.fixed; } catch (err) { console.log(err.message); } + try { a.fixed = 2; } catch (err) { console.log(err.message); } + console.log(a.subarray(0, 1).fixed, a.slice().fixed); + let seen; + Object.defineProperty(a, "s", { set(v) { seen = [v, this === a]; } }); + a.s = 7; + console.log(seen); + a.map = 5; + try { a.map((v) => v); } catch (err) { console.log(err.message); } + for (const key of ["length", "byteLength", "byteOffset", "buffer"]) { + try { a[key] = 1; } catch (err) { console.log(err.message); } + } + try { a[Symbol.toStringTag] = "x"; } catch (err) { console.log(err.message); } + // Cycles through a view's own properties are collected. + const loop = new TA(1); + loop.self = loop; + loop.size = () => loop.length; + console.log(loop.self === loop, loop.size()); +} + +function integrity(TA) { + const results = []; + const attempt = (f) => { try { f(); results.push("ok"); } catch (err) { results.push(err.message); } }; + const sealed = new TA(1); + sealed.x = 1; + attempt(() => Object.seal(sealed)); + console.log(results, Object.isExtensible(sealed), Object.isSealed(sealed), JSON.stringify(Object.getOwnPropertyDescriptor(sealed, "x"))); + attempt(() => Object.seal(sealed)); + const frozen = new TA(1); + frozen.x = 1; + attempt(() => Object.freeze(frozen)); + attempt(() => Object.freeze(frozen)); + console.log(results, Object.isFrozen(frozen), JSON.stringify(Object.getOwnPropertyDescriptor(frozen, "x"))); + const closed = new TA(1); + Object.defineProperty(closed, "q", { value: 1 }); + Object.preventExtensions(closed); + try { closed.z = 1; } catch (err) { console.log(err.message); } + try { closed[Symbol("n")] = 1; } catch (err) { console.log(err.message); } + console.log(Object.isExtensible(closed), Object.isSealed(closed), Object.isFrozen(closed)); + const empty = new TA(0); + empty.k = 1; + Object.freeze(empty); + try { empty.k = 2; } catch (err) { console.log(err.message); } + console.log(Object.isFrozen(empty), Object.isSealed(empty), empty.k); +} + +expandos(Uint8Array); +expandos(Float64Array); +species(Int16Array, Float32Array); +reflection(Uint8Array); +reflection(Int32Array); +integrity(Uint16Array); + +const view = box(new DataView(new ArrayBuffer(2))); +view[0] = 5; +view.x = 1; +console.log(view, Object.keys(view), view[0], JSON.stringify(view), "0" in view); +try { view.byteLength = 1; } catch (err) { console.log(err.message); } +const buffer = box(Buffer.from([1, 2])); +buffer.foo = 1; +buffer[Symbol.for("k")] = 2; +console.log(buffer, Object.keys(buffer), JSON.stringify(buffer)); +for (const key of ["parent", "offset", "length"]) { + try { buffer[key] = 1; } catch (err) { console.log(err.message); } +} +const empty = box(Buffer.alloc(0)); +empty.foo = { a: [1, { b: 2 }] }; +console.log(empty); diff --git a/tests/harness/corpus-costs/7753-typed-array-named-properties.js.json b/tests/harness/corpus-costs/7753-typed-array-named-properties.js.json new file mode 100644 index 000000000..9ed866538 --- /dev/null +++ b/tests/harness/corpus-costs/7753-typed-array-named-properties.js.json @@ -0,0 +1 @@ +{ "plain": 3900, "san": 4400 } diff --git a/tests/harness/typed-array-property-refusals.test.ts b/tests/harness/typed-array-property-refusals.test.ts new file mode 100644 index 000000000..b2d6d498a --- /dev/null +++ b/tests/harness/typed-array-property-refusals.test.ts @@ -0,0 +1,64 @@ +import { execFile } from "node:child_process"; +import { mkdtempSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { promisify } from "node:util"; +import { expect, test } from "vitest"; +import { compile } from "@scriptc/compiler"; + +const execFileAsync = promisify(execFile); + +// The runtime's conversions, iteration and printing of a typed array, Buffer +// or DataView read these members from the prototype, so defining one on the +// view refuses with a catchable error instead of being ignored. +test("typed array members the runtime reads from the prototype refuse as own properties", async () => { + const outDir = mkdtempSync(join(tmpdir(), "scriptc-typed-array-refusals-")); + const entry = join(outDir, "main.mjs"); + writeFileSync( + entry, + ` +function attempt(define) { + try { define(); console.log("defined"); } catch (error) { console.log(error.name, error.message); } +} +function run(TA, view) { + const a = new TA(2); + attempt(() => { a.toString = () => "x"; }); + attempt(() => { a.valueOf = () => 1; }); + attempt(() => Object.defineProperty(a, "toJSON", { value: () => 1 })); + attempt(() => { a.join = () => ""; }); + attempt(() => { a[Symbol.iterator] = function* () {}; }); + attempt(() => { a[Symbol.for("nodejs.util.inspect.custom")] = () => "x"; }); + attempt(() => { view.toLocaleString = () => ""; }); + attempt(() => { a.label = "kept"; }); + console.log(a.label, String(a)); +} +run(Uint8Array, new DataView(new ArrayBuffer(1))); +`, + ); + const result = await compile(entry, { + backend: "llvm", + sanitize: process.env["SCRIPTC_SAN"] === "1", + outDir, + outPath: join(outDir, "program"), + }); + expect(result.ok, JSON.stringify(result.diagnostics)).toBe(true); + if (!result.ok) return; + const { stdout, stderr } = await execFileAsync(result.binaryPath, [], { encoding: "utf8" }); + const refused = (key: string): string => + `Error defining ${key} on a typed array, Buffer or DataView is not supported yet`; + expect(stdout).toBe( + [ + refused("toString"), + refused("valueOf"), + refused("toJSON"), + refused("join"), + refused("Symbol(Symbol.iterator)"), + refused("Symbol(nodejs.util.inspect.custom)"), + refused("toLocaleString"), + "defined", + "kept 0,0", + "", + ].join("\n"), + ); + expect(stderr).toBe(""); +}); From e4079abd4110ddbb72fcc66e49016e9abc87f732 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 21:39:03 -0500 Subject: [PATCH 041/259] Keep swap under the test memory cap and continue past OOM kills --- .github/workflows/ci.yml | 11 +++++++---- tests/harness/ci-test-plan.test.ts | 2 +- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5ab1d9331..26a38482a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -216,14 +216,17 @@ jobs: # Start the corpus immediately beside a serial side queue. One shared # worker budget covers both processes; file and case shard axes stay # separate so every fixture still runs exactly once in each lane. - # The tests run in a transient scope capped below the runner's 16 GB: - # past 13 GB the kernel kills the scope's largest process, so the job - # log names the test instead of the runner itself running out of memory. + # The tests run in a transient scope capped below the runner's 16 GB, so + # the runner itself keeps memory: past 14 GB of RAM the scope swaps, as + # the whole runner did before (a sanitized shard peaks near 16 GB), and + # when RAM and swap run out the kernel kills the scope's largest process. + # OOMPolicy=continue leaves the rest of the scope running, so vitest + # reports the killed worker and the job log names the test. - name: Tests (corpus and integration suites) run: | ulimit -c 0 if [ -d /run/systemd/system ]; then - exec sudo --preserve-env systemd-run --scope --quiet -p MemoryMax=13G -p MemorySwapMax=0 \ + exec sudo --preserve-env systemd-run --scope --quiet -p MemoryMax=14G -p OOMPolicy=continue \ --uid="$(id -u)" --gid="$(id -g)" -- env PATH="$PATH" HOME="$HOME" node scripts/ci-test.mjs fi node scripts/ci-test.mjs diff --git a/tests/harness/ci-test-plan.test.ts b/tests/harness/ci-test-plan.test.ts index 9ff730ddf..dd77039ca 100644 --- a/tests/harness/ci-test-plan.test.ts +++ b/tests/harness/ci-test-plan.test.ts @@ -298,7 +298,7 @@ test("pull requests run the full suite on Linux and the darwin suite on macOS", // runner, and directly elsewhere. const linuxRun = linux.steps.at(-1)!.run as string; expect(linuxRun.startsWith("ulimit -c 0\n")).toBe(true); - expect(linuxRun).toContain("systemd-run --scope --quiet -p MemoryMax=13G -p MemorySwapMax=0"); + expect(linuxRun).toContain("systemd-run --scope --quiet -p MemoryMax=14G -p OOMPolicy=continue"); expect(linuxRun).toMatch(/-- env PATH="\$PATH" HOME="\$HOME" node scripts\/ci-test\.mjs\n/); expect(linuxRun.endsWith("fi\nnode scripts/ci-test.mjs\n")).toBe(true); expect(macos.steps.at(-1)!.run).toBe("node scripts/ci-test.mjs"); From 96dbc6204f26ac380dfa253742812c88d2af2096 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 21:48:25 -0500 Subject: [PATCH 042/259] Keep int32 class fields beside Buffer.from over an ArrayBuffer range Buffer.from(arrayBuffer, byteOffset[, length]) lowers to buffer.poolFromDynRange with its operands as checked values. The int32 slot analysis treats any runtime helper with a checked-value argument as a possible store into a live class instance unless the helper is listed as read-only, so one such call dropped every int32 class field fact in the program (tsc-ts's scanner makes one). buffer.poolFromDynRange and buffer.poolFromDynOffset read their operands (the ArrayBuffer's view after Node's offset and length conversions, or a copy of a string's, array-like's or typed array's values) and store into no class instance, so they join DYN_READ_ONLY. --- packages/compiler/src/ir/int32-slots.test.ts | 46 ++++++++++++++++++++ packages/compiler/src/ir/int32-slots.ts | 5 +++ 2 files changed, 51 insertions(+) diff --git a/packages/compiler/src/ir/int32-slots.test.ts b/packages/compiler/src/ir/int32-slots.test.ts index be933ab38..9b838bb55 100644 --- a/packages/compiler/src/ir/int32-slots.test.ts +++ b/packages/compiler/src/ir/int32-slots.test.ts @@ -357,6 +357,52 @@ test("an Error subclass constructor forwarding dynamic arguments stores no class expect(slots.isField("C", "a")).toBe(true); }); +test("Buffer.from over an ArrayBuffer range and Buffer as a value keep class fields int32", () => { + // `Buffer.from(view.buffer, offset, length)` passes its operands as + // checked values, and a program that reads the Buffer function's value + // installs it in %main; neither stores into a class instance. + const classes = [cls("C", ["a"])]; + const view: IrExpr = { loc, kind: "dynFrom", value: ref("o", obj("C")), type: DYN }; + const libCall = (fnName: string, args: IrExpr[], type: IrType = VOID): IrStmt => + stmt({ loc, kind: "libCall", fn: fnName, args, type } as IrExpr); + const slots = analyzeInt32Slots( + mod(classes, [ + fn( + "load", + [ + { id: "o", type: obj("C") }, + { id: "storage", type: DYN }, + ], + [ + set(ref("o", obj("C")), "C", "a", num(1)), + libCall("dyn.typedRefIs", [ + view, + { loc, kind: "strLit", value: "object:C", type: STRING }, + ]), + libCall("buffer.installValue", []), + libCall("buffer.constructor", [], DYN), + libCall( + "buffer.poolFromDynRange", + [ref("storage", DYN), num(2), num(4)].map((arg): IrExpr => + arg.type.kind === "dyn" ? arg : { loc, kind: "dynFrom", value: arg, type: DYN }, + ), + ), + libCall("buffer.poolFromDynOffset", [ + ref("storage", DYN), + { + loc, + kind: "dynFrom", + value: num(2), + type: DYN, + }, + ]), + ], + ), + ]), + ); + expect(slots.isField("C", "a")).toBe(true); +}); + test("captured bindings share one proof across the declaring function and its closures", () => { const closure: IrExpr = { loc, kind: "closure", fnName: "inner", captures: ["s"], type: DYN }; const outer = (): IrFunction => ({ diff --git a/packages/compiler/src/ir/int32-slots.ts b/packages/compiler/src/ir/int32-slots.ts index a359a18c5..2c26fcf0f 100644 --- a/packages/compiler/src/ir/int32-slots.ts +++ b/packages/compiler/src/ir/int32-slots.ts @@ -451,6 +451,11 @@ const DYN_READ_ONLY = new Set([ "fs.utimesSync", // Buffer.prototype members read as values: a lookup by key. "buffer.prototypeMember", + // Buffer.from(value, offset[, length]) over checked values: an + // ArrayBuffer's view after Node's offset and length conversions, or a copy + // of a string, array-like or typed array's values. + "buffer.poolFromDynOffset", + "buffer.poolFromDynRange", "insp.dyn", "insp.dynS", // The dynamic-tier operators run their dyn twins (scr_js_value.c); the From 2a98dbfa329c8b9e176179257429edb8d2f6a5e6 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 21:57:25 -0500 Subject: [PATCH 043/259] Answer constructor reads on instances without a property bag The constructor read asked dyn.hasOwn on the instance's property bag, which is undefined until the instance has one, and on the bag's prototype, so it threw "Cannot convert undefined or null to object" for an instance without own properties (for example `new ParseFailure('p').constructor` for a class that extends SyntaxError). It now goes through a lifted helper that answers false before the instance has a bag and when the bag has no prototype, as the dyn.hasKey read did. --- .../lowering/class-dynamic-dispatch.ts | 96 ++++++++++++++++++- .../7621-class-methods-foreign-receivers.mjs | 39 ++++++++ 2 files changed, 134 insertions(+), 1 deletion(-) diff --git a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts index a1bc41782..5132e487f 100644 --- a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts +++ b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts @@ -3966,6 +3966,94 @@ export class ClassDynamicDispatch { return { kind: "call", callee: name, args: [bag, key], type: BOOL, loc }; } + /** `%dyn.class.bagHasOwn[OrPrototype]`: whether an instance's property bag + * holds `key` as its own property, or, with `prototype`, whether the bag's + * prototype object does. False before the instance has a bag. */ + private readBagHasOwn( + lowerer: Lowerer, + bag: IrExpr, + key: IrExpr, + prototype: boolean, + loc: SrcLoc, + ): IrExpr { + const name = prototype ? "%dyn.class.bagHasOwnOrPrototype" : "%dyn.class.bagHasOwn"; + let helper = lowerer.liftedFnNamed(name); + if (!helper) { + const value = varRef("p.0", DYN, loc); + const keyRef = varRef("p.1", STRING, loc); + const proto = varRef("proto", DYN, loc); + const hasOwn = (target: IrExpr): IrExpr => ({ + kind: "libCall", + fn: "dyn.hasOwn", + args: [target, keyRef], + type: BOOL, + loc, + }); + const returnFalse: IrStmt = { + kind: "return", + value: { kind: "boolLit", value: false, type: BOOL, loc }, + loc, + }; + helper = { + name, + params: [ + { localId: "p.0", name: "bag", type: DYN }, + { localId: "p.1", name: "key", type: STRING }, + ], + returnType: BOOL, + locals: [ + { id: "p.0", name: "bag", type: DYN, mutable: false }, + { id: "p.1", name: "key", type: STRING, mutable: false }, + ...(prototype ? [{ id: "proto", name: "proto", type: DYN, mutable: false }] : []), + ], + body: [ + { + kind: "if", + cond: { kind: "dynTest", test: "undefined", value, type: BOOL, loc }, + then: [returnFalse], + else_: null, + loc, + }, + ...(prototype + ? ([ + { + kind: "if", + cond: hasOwn(value), + then: [ + { + kind: "return", + value: { kind: "boolLit", value: true, type: BOOL, loc }, + loc, + }, + ], + else_: null, + loc, + }, + { + kind: "varDecl", + localId: "proto", + init: { kind: "libCall", fn: "dyn.getPrototype", args: [value], type: DYN, loc }, + loc, + }, + { + kind: "if", + cond: { kind: "dynTest", test: "nullish", value: proto, type: BOOL, loc }, + then: [returnFalse], + else_: null, + loc, + }, + { kind: "return", value: hasOwn(proto), loc }, + ] satisfies IrStmt[]) + : [{ kind: "return", value: hasOwn(value), loc } satisfies IrStmt]), + ], + loc, + }; + lowerer.liftedFns.push(helper); + } + this.generated.add(helper); + return { kind: "call", callee: name, args: [bag, key], type: BOOL, loc }; + } + /** The hints for which some boxed class declares a conversion method. A * string conversion calls toString first, so without a declared toString * or Symbol.toPrimitive it answers Object.prototype.toString's @@ -5633,12 +5721,18 @@ export class ClassDynamicDispatch { const cls = lowerer.coerceToExpected(classValueRef(lowerer, info, info.decl), DYN); const bag = this.branchPropertyBag(lowerer, info, receiver, false, loc); const key: IrExpr = { kind: "strLit", value: name, type: STRING, loc }; + // `constructor` is an own property of every class prototype, so an + // ancestor's prototype never answers for an instance of this class: + // the instance's own property answers, then one this class's + // prototype object defines (a reflected prototype, or a write to + // `C.prototype.constructor`), and otherwise the class itself. + const answered = this.readBagHasOwn(lowerer, bag, key, hasClassPrototypeData(info), loc); return [ { kind: "return", value: { kind: "ternary", - cond: this.readBagHas(lowerer, "dyn.hasKey", bag, key, loc), + cond: answered, then: { kind: "libCall", fn: "dyn.bagGet", diff --git a/tests/corpus/7621-class-methods-foreign-receivers.mjs b/tests/corpus/7621-class-methods-foreign-receivers.mjs index beb046ea4..8e4feedbd 100644 --- a/tests/corpus/7621-class-methods-foreign-receivers.mjs +++ b/tests/corpus/7621-class-methods-foreign-receivers.mjs @@ -128,3 +128,42 @@ report("square both", () => Square.prototype.both.call(foreign)); report("tiny describe", () => Tiny.prototype.describe.call(foreign)); report("tiny tag", () => Tiny.prototype.tag.call(foreign)); report("square describe on tiny", () => Square.prototype.describe.call(tiny)); + +// A base method that builds `new this.constructor()` on a subclass instance +// builds the subclass, also once the base prototype is complete (a super call +// above reads it) and `copy` is read through its prototype slot. +class Node3 { + constructor() { + this.a = 0; + } + copy(source) { + this.a = source.a; + return this; + } + clone() { + return new this.constructor().copy(this); + } +} +class Mesh3 extends Node3 { + constructor(geometry) { + super(); + this.geometry = geometry; + } + copy(source) { + super.copy(source); + this.geometry = source.geometry; + return this; + } +} +const copyValue = Node3.prototype.copy; +const mesh = new Mesh3({ id: 1 }); +mesh.a = 5; +const meshClone = mesh.clone(); +console.log( + meshClone instanceof Mesh3, + meshClone.constructor === Mesh3, + mesh.constructor === Mesh3, + meshClone.a, + JSON.stringify(meshClone.geometry), + typeof copyValue, +); From 52e84ad3b44e81e8d526d8f9291cf6d442a30f7b Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 21:57:53 -0500 Subject: [PATCH 044/259] Parse URL hosts and paths as the URL Standard does, and inspect URLs as Node does --- docs/content/limitations/builtin-apis/url.mdx | 3 +- .../src/generated/node-v24-compatibility.json | 6 +- .../generated/node-v24-internal.json | 8 +- .../ambient/scriptc-node-fallback.d.ts | 18 +- .../compiler/src/backend/llvm/lib-shared.ts | 1 + .../src/frontend/lowering/lower-inspect.ts | 15 + .../src/frontend/lowering/surfaces.ts | 1 + packages/compiler/src/frontend/type-mapper.ts | 10 +- packages/compiler/src/ir/builtin-effects.ts | 2 + .../compiler/src/ir/builtin-signatures.ts | 4 + packages/compiler/surface-manifest.json | 6 + .../8101-url-host-and-path-parsing.js.json | 6 + ...102-url-path-to-file-url-unc-hosts.js.json | 6 + .../tests/corpus/8103-url-inspect.ts.json | 6 + .../corpus/8104-url-to-http-options.ts.json | 6 + packages/runtime/src/scr_dyn.h | 4 + packages/runtime/src/scr_inspect.c | 60 ++++ packages/runtime/src/scr_url.c | 299 ++++++++++++++---- packages/runtime/src/scr_url.h | 6 + .../corpus/8101-url-host-and-path-parsing.js | 103 ++++++ .../8102-url-path-to-file-url-unc-hosts.js | 36 +++ tests/corpus/8103-url-inspect.ts | 19 ++ tests/corpus/8104-url-to-http-options.ts | 21 ++ 23 files changed, 575 insertions(+), 71 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8101-url-host-and-path-parsing.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8102-url-path-to-file-url-unc-hosts.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8103-url-inspect.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8104-url-to-http-options.ts.json create mode 100644 tests/corpus/8101-url-host-and-path-parsing.js create mode 100644 tests/corpus/8102-url-path-to-file-url-unc-hosts.js create mode 100644 tests/corpus/8103-url-inspect.ts create mode 100644 tests/corpus/8104-url-to-http-options.ts diff --git a/docs/content/limitations/builtin-apis/url.mdx b/docs/content/limitations/builtin-apis/url.mdx index 6345e2616..c9eee85b3 100644 --- a/docs/content/limitations/builtin-apis/url.mdx +++ b/docs/content/limitations/builtin-apis/url.mdx @@ -1,4 +1,4 @@ -- **URL:** Non-ASCII or percent-escaped hosts are unsupported. +- **URL:** Hosts of special URLs that hold non-ASCII text, or percent-escapes that decode to it, throw `ERR_INVALID_URL`, and `xn--` labels are kept without Punycode validation. Absolute inputs and relative inputs with runtime string or URL bases, including optional bases, compile. `URL.canParse`, `URL.parse`, `toString()`, and `toJSON()` compile; the factories use the same parser as construction, returning `false` or `null` for rejected inputs while preserving conversion errors. `href`, `protocol`, `username`, `password`, `host`, `hostname`, `port`, `pathname`, `search`, and `hash` support assignment in native code. @@ -6,4 +6,3 @@ Native URL assignments require statically known property keys; `+=` accepts primitive operands, while other assignment operators and object operands for `+=` are refused. `origin` is read-only. `searchParams` is a live view whose identity survives query and URL replacement. - Opaque paths retain their input bytes without WHATWG C0 encoding. diff --git a/docs/src/generated/node-v24-compatibility.json b/docs/src/generated/node-v24-compatibility.json index 1039bc3d8..2e30804fb 100644 --- a/docs/src/generated/node-v24-compatibility.json +++ b/docs/src/generated/node-v24-compatibility.json @@ -71509,9 +71509,9 @@ "inherited": true }, "static": { - "status": "not-implemented", - "detail": "No static compiler lowering is registered for this API yet.", - "verification": "registry-gap" + "status": "partial", + "detail": "Implemented for the call shapes accepted by the compiler lowering.", + "verification": "test-backed" } }, { diff --git a/internal/compatibility/generated/node-v24-internal.json b/internal/compatibility/generated/node-v24-internal.json index b3d91e453..72b79d801 100644 --- a/internal/compatibility/generated/node-v24-internal.json +++ b/internal/compatibility/generated/node-v24-internal.json @@ -99483,6 +99483,7 @@ "evidence": "derived:descendants", "tests": [ "packages/runtime/test/url-legacy.test.ts", + "tests/corpus/1794-searchparams-url-live.ts", "tests/corpus/5220-url-parse-warnings.ts", "tests/corpus/5221-url-parse-shapes.ts", "tests/corpus/5222-url-parse-hosts.ts", @@ -100741,8 +100742,11 @@ "inherited": true }, "static": { - "status": "not-implemented", - "evidence": "compiler-unmatched:url" + "status": "partial", + "evidence": "surface-manifest:node-builtin.url.urlToHttpOptions", + "tests": [ + "tests/corpus/1794-searchparams-url-live.ts" + ] }, "anchorSource": "exact" }, diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index b97548e3b..0f2466798 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -2796,8 +2796,9 @@ declare var URLSearchParams: { * slashes, non-empty host); pathToFileURL resolves the path and percent- * encodes it into a file: URL. The legacy API: parse() answers a Url * object, format() serializes a Url-shaped object, a string, or a URL, - * resolve() resolves one URL string against another, and the domain pair - * converts a hostname to and from its Punycode form. */ + * resolve() resolves one URL string against another, the domain pair + * converts a hostname to and from its Punycode form, and urlToHttpOptions + * builds http.request options from a URL. */ declare module "url" { export type URL = globalThis.URL; export type URLSearchParams = globalThis.URLSearchParams; @@ -2865,6 +2866,19 @@ declare module "url" { export function resolve(from: string, to: string): string; export function domainToASCII(domain: string): string; export function domainToUnicode(domain: string): string; + /** urlToHttpOptions's null-prototype request options. */ + export interface UrlHttpOptions { + protocol: string; + hostname: string; + hash: string; + search: string; + pathname: string; + path: string; + href: string; + port?: number; + auth?: string; + } + export function urlToHttpOptions(url: URL): UrlHttpOptions; } declare module "node:url" { export * from "url"; diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 21f32431c..58f7f6128 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -732,6 +732,7 @@ export const LIB_FN_SYMS: Record = { "punycode.ucs2Encode": "scr_str_from_code_point", "punycode.warn": "scr_punycode_warn", "url.domainToUnicode": "scr_url_domain_to_unicode", + "url.toHttpOptions": "scr_url_to_http_options_dyn", "url.pathToFileURL": "scr_url_from_path", "url.pathToFileURLPlatform": "scr_url_from_path_platform", "url.pathToFileURLWin32": "scr_url_from_path", diff --git a/packages/compiler/src/frontend/lowering/lower-inspect.ts b/packages/compiler/src/frontend/lowering/lower-inspect.ts index 82cdeb3ce..b4e9e1442 100644 --- a/packages/compiler/src/frontend/lowering/lower-inspect.ts +++ b/packages/compiler/src/frontend/lowering/lower-inspect.ts @@ -857,7 +857,10 @@ function inspectSupport( } // Generator objects print through their checked capsule: Node's // `Object [Generator] {}`, or the tag of the iterator they implement. + // URLs and URLSearchParams print through their handles. case "generator": + case "url": + case "searchParams": return null; default: return `'${lowerer.fmt(t)}' values have no inspect lowering`; @@ -957,6 +960,18 @@ export function inspectExpr( }; case "dyn": return { kind: "libCall", fn: "insp.dyn", args: [value, recurse, depth], type: STRING, loc }; + // URLs and URLSearchParams render through their checked-dynamic + // handles: Node's `URL { href: ..., hash: ... }` and + // `URLSearchParams { 'a' => '1' }`. + case "url": + case "searchParams": + return { + kind: "libCall", + fn: "insp.dyn", + args: [lowerer.coerceToExpected(value, DYN), recurse, depth], + type: STRING, + loc, + }; case "generator": return { kind: "libCall", diff --git a/packages/compiler/src/frontend/lowering/surfaces.ts b/packages/compiler/src/frontend/lowering/surfaces.ts index d133eeb43..c0ffd142e 100644 --- a/packages/compiler/src/frontend/lowering/surfaces.ts +++ b/packages/compiler/src/frontend/lowering/surfaces.ts @@ -1681,6 +1681,7 @@ export const BUILTIN_MODULE_FNS: Record< resolve: { fn: "url.legacyResolve", params: [DYN, DYN], result: STRING }, domainToASCII: { fn: "url.domainToASCII", params: [DYN], result: STRING }, domainToUnicode: { fn: "url.domainToUnicode", params: [DYN], result: STRING }, + urlToHttpOptions: { fn: "url.toHttpOptions", params: [DYN], result: DYN }, }, child_process: { // spawnSync's and spawn's call completions are entirely special-cased diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index fc159116f..161f73d27 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -1431,16 +1431,18 @@ let mapTypeDepth = 0; let contextResolutions = 0; /** node:url's legacy record interfaces: url.parse()'s Url instance (and - * its two query-typed refinements), url.format()'s UrlObject input, and the - * URL form's URLFormatOptions. The values are checked-dynamic objects — - * Node's Url instance carries its class name and null fields, and format() - * reads any object's fields with JS truthiness. */ + * its two query-typed refinements), url.format()'s UrlObject input, the + * URL form's URLFormatOptions, and urlToHttpOptions's result. The values + * are checked-dynamic objects — Node's Url instance carries its class name + * and null fields, format() reads any object's fields with JS truthiness, + * and urlToHttpOptions answers a null-prototype object. */ const LEGACY_URL_TYPES = new Set([ "Url", "UrlObject", "UrlWithParsedQuery", "UrlWithStringQuery", "URLFormatOptions", + "UrlHttpOptions", ]); export function isLegacyUrlType( diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index ce822df1a..4bc198df2 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -753,6 +753,8 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "url.legacyResolve", "url.domainToASCII", "url.domainToUnicode", + // ERR_INVALID_ARG_TYPE and the credentials' URIError. + "url.toHttpOptions", // The win32-target flavor of pathToFileURL (same runtime entry point — // the bridge dispatches by the binary's platform): Node's win32 arm // raises ERR_INVALID_ARG_VALUE TypeErrors for malformed UNC inputs, so diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 37d9769e0..3f59f7197 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -1028,6 +1028,10 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "url.legacyResolve": { argTypes: [DYN, DYN, BOOL], result: STRING }, "url.domainToASCII": { argTypes: [DYN, BOOL], result: STRING }, "url.domainToUnicode": { argTypes: [DYN, BOOL], result: STRING }, + /** url.urlToHttpOptions over a checked-dynamic argument: a URL answers + * Node's null-prototype options object; a primitive or null throws + * ERR_INVALID_ARG_TYPE. */ + "url.toHttpOptions": { argTypes: [DYN], result: DYN }, /** node:punycode (scr_url.c): punycode.js 2.1.0's string conversions; * decode/toUnicode (and, past 32-bit deltas, encode/toASCII) throw the * module's RangeErrors, ucs2Encode String.fromCodePoint's. warn marks the diff --git a/packages/compiler/surface-manifest.json b/packages/compiler/surface-manifest.json index 75541b8e5..5876c4289 100644 --- a/packages/compiler/surface-manifest.json +++ b/packages/compiler/surface-manifest.json @@ -2469,6 +2469,12 @@ "name": "url.resolve", "status": "static" }, + { + "id": "node-builtin.url.urlToHttpOptions", + "kind": "node-builtin", + "name": "url.urlToHttpOptions", + "status": "static" + }, { "id": "node-builtin.util", "kind": "node-builtin", diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8101-url-host-and-path-parsing.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8101-url-host-and-path-parsing.js.json new file mode 100644 index 000000000..d38f437bc --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8101-url-host-and-path-parsing.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8101-url-host-and-path-parsing.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8102-url-path-to-file-url-unc-hosts.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8102-url-path-to-file-url-unc-hosts.js.json new file mode 100644 index 000000000..987c72578 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8102-url-path-to-file-url-unc-hosts.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8102-url-path-to-file-url-unc-hosts.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8103-url-inspect.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8103-url-inspect.ts.json new file mode 100644 index 000000000..06632e9e7 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8103-url-inspect.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8103-url-inspect.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8104-url-to-http-options.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8104-url-to-http-options.ts.json new file mode 100644 index 000000000..aedf0a20c --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8104-url-to-http-options.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8104-url-to-http-options.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index bd76c12e2..469c550ab 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -1615,6 +1615,10 @@ typedef struct ScrDynHandleOps { /* Past the depth limit util.inspect prints `[cls]` (the class's * inspector returns `this`) instead of the bare class name. */ bool inspect_bracketed_past_depth; + /* The class's inspector formats its view with a new util.inspect call + * (URL's does): the view renders from the top level with the caller's + * depth, and its lines take the caller's indentation. */ + bool inspect_view_nested; /* The @@toStringTag when it differs from cls: String() answers * "[object ]" and util.inspect prints ` [] `, or * ` ` when the tag ends with "." and cls, as Node does. */ diff --git a/packages/runtime/src/scr_inspect.c b/packages/runtime/src/scr_inspect.c index 011a1f582..f5e429374 100644 --- a/packages/runtime/src/scr_inspect.c +++ b/packages/runtime/src/scr_inspect.c @@ -1495,6 +1495,54 @@ ScrStr *scr_insp_bytes(ScrBytes *b, double recurse, double depth) { return scr_insp_typed_array(b, recurse, depth); } +/* Node's URLSearchParams inspector: [Object] past the depth limit, and + * otherwise each pair as `name => value` with both strings inspected, on + * one line, or one pair per line when the pairs' text is longer than + * breakLength (the closing brace stays on the last pair's line). The lines + * take the caller's indentation, as a custom inspector's text does. */ +static ScrStr *scr_insp_search_params(ScrSearchParams *sp, double recurse, double depth) { + if (recurse > depth) return scr_str_new("[Object]", 8); + size_t n = (size_t)scr_sp_size(sp); + if (n == 0) return scr_str_new("URLSearchParams {}", 18); + ScrStr **items = malloc(n * sizeof *items); + if (!items) insp_oom(); + double length = -2; + for (size_t i = 0; i < n; i++) { + ScrStr *name = scr_sp_key_at(sp, (double)i); + ScrStr *value = scr_sp_val_at(sp, (double)i); + ScrStr *name_text = scr_insp_str(name); + ScrStr *value_text = scr_insp_str(value); + InspBuf item = {0}; + ib_str(&item, name_text); + ib_cstr(&item, " => "); + ib_str(&item, value_text); + items[i] = ib_take(&item); + length += (double)insp_utf16_len(items[i]->data, items[i]->len) + 2; + scr_str_release(name); + scr_str_release(value); + scr_str_release(name_text); + scr_str_release(value_text); + } + bool multiline = length > g_break_length; + InspBuf out = {0}; + ib_cstr(&out, multiline ? "URLSearchParams {\n " : "URLSearchParams { "); + for (size_t i = 0; i < n; i++) { + if (i) ib_cstr(&out, multiline ? ",\n " : ", "); + ib_str(&out, items[i]); + scr_str_release(items[i]); + } + free(items); + ib_cstr(&out, " }"); + ScrStr *text = ib_take(&out); + InspBuf indented = {0}; + for (size_t k = 0; k < text->len; k++) { + ib_char(&indented, text->data[k]); + if (text->data[k] == '\n') ib_spaces(&indented, g_indent); + } + scr_str_release(text); + return ib_take(&indented); +} + ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) { if (d->kind == SCR_DYN_PROXY) return scr_insp_dyn(d->v.proxy.target, recurse, depth); switch (d->kind) { @@ -1657,6 +1705,8 @@ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) { return scr_insp_weak_collection(d->v.handle.tag == SCR_DYNH_WEAK_MAP ? "WeakMap" : "WeakSet", recurse, depth); if (d->v.handle.tag == SCR_DYNH_DATE) return scr_insp_date(scr_dyn_native_date_value(d)); + if (d->v.handle.tag == SCR_DYNH_SEARCH_PARAMS) + return scr_insp_search_params(d->v.handle.ptr, recurse, depth); if (d->v.handle.tag == SCR_DYNH_ITERATOR) { ScrStr *iterator = scr_insp_native_iterator(d, recurse, depth); if (iterator) return iterator; @@ -1675,6 +1725,16 @@ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) { return ib_take(&out); } ScrDyn *view = ops->inspect_view(d->v.handle.ptr); + if (ops->inspect_view_nested) { + scr_insp_nested_begin(); + ScrStr *inner = scr_insp_dyn(view, 0, depth); + scr_dyn_release(view); + ScrStr *prefix = scr_str_new(ops->cls, strlen(ops->cls)); + ScrStr *rendered = scr_insp_nested_end(prefix, inner); + scr_str_release(prefix); + scr_str_release(inner); + return rendered; + } ScrStr *body = scr_insp_dyn(view, recurse, depth); scr_dyn_release(view); InspBuf out = {0}; diff --git a/packages/runtime/src/scr_url.c b/packages/runtime/src/scr_url.c index 025bd740f..0ea0e5824 100644 --- a/packages/runtime/src/scr_url.c +++ b/packages/runtime/src/scr_url.c @@ -6,7 +6,7 @@ * against Node by the differential corpus: * - scheme lowercasing; "Invalid URL" TypeError on schemeless input * - special schemes (http/https/ws/wss/ftp/file): authority parsing with - * host lowercasing, default-port removal (leading zeros stripped), + * percent-decoded, lowercased hosts, default-port removal (leading zeros stripped), * canonical bracketed IPv6 literals, * backslash-as-slash, and any run of leading slashes tolerated * (http:foo.com works); file: takes an authority only after exactly @@ -17,13 +17,14 @@ * (space, quotes, angle brackets, braces, non-ASCII UTF-8 bytes, ...); * existing %-sequences pass through verbatim (no decode, no case * normalization — like Node) - * - non-special schemes: "//" parses an authority (host case preserved), - * a single "/" roots a normalized path, anything else is an OPAQUE - * path kept verbatim (data:text/plain,hi there) + * - non-special schemes: "//" parses an authority (an opaque host, + * case preserved, C0-encoded), a single "/" roots a normalized path, + * anything else is an OPAQUE path with the C0 control set encoded + * (data:text/plain,hi there) * - * DOCUMENTED DIVERGENCES (SEMANTICS.md): non-ASCII and %-escaped hosts are - * rejected with "Invalid URL" (no IDNA/punycode), and opaque paths skip - * the spec's C0-encode pass (kept verbatim). + * DOCUMENTED DIVERGENCE: a special host that holds non-ASCII text after + * percent-decoding is rejected with "Invalid URL" (no UTS #46 processing), + * and "xn--" labels are kept without Punycode validation. * * Failures THROW catchable TypeErrors through the exception cell with * Node's messages; callers are compiler-emitted pending checks. */ @@ -176,7 +177,7 @@ static bool enc_query(unsigned char c, bool special) { } static bool enc_path(unsigned char c) { - return enc_query(c, false) || c == '?' || c == '`' || c == '{' || c == '}'; + return enc_query(c, false) || c == '?' || c == '^' || c == '`' || c == '{' || c == '}'; } static bool enc_userinfo(unsigned char c) { @@ -392,17 +393,58 @@ static bool url_ipv4_parse(const char *s, size_t n, UrlBuf *out) { return true; } -/* Shared constructor/setter host parsing keeps the existing ASCII-host - * boundary and canonical IPv6 serialization in both execution tiers. A - * special host that ends in a number is an IPv4 address: it serializes - * as dotted decimal, or the URL is invalid. */ +/* Byte classes for the host parser: URL_FORBIDDEN_HOST marks the URL + * Standard's forbidden host code points (opaque hosts), URL_FORBIDDEN_DOMAIN + * its forbidden domain code points (those plus the C0 controls, '%' and + * U+007F) and every non-ASCII byte, which a special host cannot hold + * without UTS #46 processing. */ +enum { URL_FORBIDDEN_HOST = 1, URL_FORBIDDEN_DOMAIN = 2 }; + +static const unsigned char url_host_byte_class[256] = { + 3, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 2, 2, 3, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 3, 0, 0, 3, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 3, 0, 3, 3, + 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 3, 3, 3, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, +}; + +static bool enc_c0_control(unsigned char c) { + return c < 0x20 || c > 0x7E; +} + +static int hex_val(char c) { + if (c >= '0' && c <= '9') return c - '0'; + if (c >= 'a' && c <= 'f') return c - 'a' + 10; + if (c >= 'A' && c <= 'F') return c - 'A' + 10; + return -1; +} + +/* The URL Standard's host parser for the constructor and the setters, + * with canonical IPv6 serialization: + * - a non-special (opaque) host refuses forbidden host code points and + * percent-encodes the C0 control set; + * - a special host is percent-decoded, lowercased, refused when it holds a + * forbidden domain code point, and serialized as dotted decimal when it + * ends in a number (or refused when that number is invalid). + * Divergence: a special host that decodes to non-ASCII needs UTS #46 + * processing, which this unit does not link, so it is refused; "xn--" + * labels are kept without Punycode validation. */ static bool parse_host(const char *hp, size_t host_len, bool special, bool is_file, ScrStr **host) { bool ipv6 = host_len > 0 && hp[0] == '['; size_t ipv6_end = host_len ? host_len - 1 : 0; if (ipv6 && (host_len < 3 || hp[ipv6_end] != ']')) return false; - /* Validate + lowercase (special) the host. Divergence: non-ASCII and - * %-escapes (IDNA territory) are rejected outright. */ UrlBuf hb; ub_init(&hb); if (ipv6) { @@ -410,22 +452,37 @@ static bool parse_host(const char *hp, size_t host_len, bool special, bool is_fi free(hb.data); return false; } - } else { + *host = ub_take(&hb); + return true; + } + if (!special) { for (size_t i = 0; i < host_len; i++) { unsigned char c = (unsigned char)hp[i]; - if (c >= 0x80 || c == '%' || c == ':' || c == '[' || c == ']' || - c <= 0x20 || c == '#' || c == '/' || c == '<' || c == '>' || - c == '?' || c == '@' || c == '\\' || c == '^' || c == '|') { + if (url_host_byte_class[c] & URL_FORBIDDEN_HOST) { free(hb.data); return false; } - if (special && c >= 'A' && c <= 'Z') { - c = (unsigned char)(c - 'A' + 'a'); - } - ub_push(&hb, (char)c); + ub_push_encoded(&hb, c, enc_c0_control); } + *host = ub_take(&hb); + return true; } - if (!ipv6 && special && url_ends_in_number(hb.data, hb.len)) { + for (size_t i = 0; i < host_len; i++) { + unsigned char c = (unsigned char)hp[i]; + int hi, lo; + if (c == '%' && i + 2 < host_len && (hi = hex_val(hp[i + 1])) >= 0 && + (lo = hex_val(hp[i + 2])) >= 0) { + c = (unsigned char)(hi * 16 + lo); + i += 2; + } + if (url_host_byte_class[c] & URL_FORBIDDEN_DOMAIN) { + free(hb.data); + return false; + } + if (c >= 'A' && c <= 'Z') c = (unsigned char)(c - 'A' + 'a'); + ub_push(&hb, (char)c); + } + if (url_ends_in_number(hb.data, hb.len)) { UrlBuf ip; ub_init(&ip); bool ok = url_ipv4_parse(hb.data, hb.len, &ip); @@ -438,7 +495,7 @@ static bool parse_host(const char *hp, size_t host_len, bool special, bool is_fi } /* file: "localhost" normalizes to "" at parse time (Node). */ if (is_file && hb.len == 9 && memcmp(hb.data, "localhost", 9) == 0) hb.len = 0; - if (hb.len == 0 && special && !is_file) { + if (hb.len == 0 && !is_file) { free(hb.data); return false; /* http:// — special non-file needs a host */ } @@ -481,6 +538,13 @@ static bool parse_authority(const char *raw, size_t len, bool special, bool is_f } const char *hp = at >= 0 ? raw + at + 1 : raw; size_t hp_len = at >= 0 ? len - (size_t)at - 1 : len; + /* Credentials need a host. A file: authority is a host alone, so its + * '@' and ':' reach the host parser, which refuses them. */ + if (at >= 0 && hp_len == 0) return false; + if (is_file) { + *port = scr_str_new("", 0); + return at < 0 && parse_host(hp, hp_len, special, is_file, host); + } /* host[:port], with IPv6 literals bracketed per WHATWG. */ long colon = -1; size_t host_len = hp_len; @@ -500,6 +564,7 @@ static bool parse_authority(const char *raw, size_t len, bool special, bool is_f } host_len = colon >= 0 ? (size_t)colon : hp_len; } + if (colon >= 0 && host_len == 0) return false; if (!parse_host(hp, host_len, special, is_file, host)) return false; /* Port: digits only, leading zeros stripped, defaults dropped. */ UrlBuf pb; @@ -700,11 +765,18 @@ ScrUrl *scr_url_new(ScrStr *input) { port = scr_str_new("", 0); path = parse_rooted_path(body, body_len, false); } else { - /* Opaque path — kept verbatim (divergence: the spec C0-encodes). */ + /* Opaque path: the C0 control set is percent-encoded, and a space + * right before a query or fragment becomes %20. */ userinfo = scr_str_new("", 0); host = scr_str_new("", 0); port = scr_str_new("", 0); - path = scr_str_new(body, body_len); + UrlBuf ob; + ub_init(&ob); + bool trailing_space = qmark < rest_len && body_len > 0 && body[body_len - 1] == ' '; + size_t kept = trailing_space ? body_len - 1 : body_len; + for (size_t i = 0; i < kept; i++) ub_push_encoded(&ob, (unsigned char)body[i], enc_c0_control); + if (trailing_space) ub_append(&ob, "%20", 3); + path = ub_take(&ob); } /* Query and fragment, encoded and stored WITH their sigils. */ @@ -823,18 +895,22 @@ ScrUrl *scr_url_new_base(ScrStr *input, ScrStr *base_input) { bool drive = file && path_len >= 2 && url_drive_letter(raw, 2) && (path_len == 2 || raw[2] == '/' || raw[2] == '\\'); if (base->has_authority) { + /* A drive letter relative to a file: base keeps the base's host. */ ub_append(&absolute, "//", 2); - if (!drive) { - if (base->userinfo->len) { - ub_append(&absolute, base->userinfo->data, base->userinfo->len); - ub_push(&absolute, '@'); - } - ub_append(&absolute, base->host->data, base->host->len); - if (base->port->len) { - ub_push(&absolute, ':'); - ub_append(&absolute, base->port->data, base->port->len); - } + if (base->userinfo->len) { + ub_append(&absolute, base->userinfo->data, base->userinfo->len); + ub_push(&absolute, '@'); } + ub_append(&absolute, base->host->data, base->host->len); + if (base->port->len) { + ub_push(&absolute, ':'); + ub_append(&absolute, base->port->data, base->port->len); + } + } else if (!opaque) { + /* A host-less base path can start with "//"; the "/." prefix keeps + * the resolved path from reparsing as an authority (dot-segment + * removal drops it). */ + ub_append(&absolute, "/.", 2); } if (!path_len) { ub_append(&absolute, base->path->data, base->path->len); @@ -1279,13 +1355,6 @@ void scr_url_set_checked(ScrUrl *u, ScrStr *field, const ScrDyn *value) { /* ── the file-URL bridge ─────────────────────────────────────────────── */ -static int hex_val(char c) { - if (c >= '0' && c <= '9') return c - '0'; - if (c >= 'a' && c <= 'f') return c - 'a' + 10; - if (c >= 'A' && c <= 'F') return c - 'A' + 10; - return -1; -} - static bool url_file_scheme(ScrUrl *u) { if (u->scheme->len == 4 && memcmp(u->scheme->data, "file", 4) == 0) return true; scr_throw_error_msg_code(SCR_ERR_TYPE, "The URL must be of scheme file", 30, "ERR_INVALID_URL_SCHEME"); @@ -1467,7 +1536,7 @@ static void scr_url_throw_arg_value(const char *reason, ScrStr *value) { * bindingUrl.pathToFileURL does, reusing the parser's rooted-path * machinery (WHATWG dot-segment removal with empty segments preserved, * backslash-as-slash when `backslash_sep`, the enc_path set): the bytes - * Node encodes BEYOND that set ('%', '[', ']', '^', '|' — and '\\' when + * Node encodes BEYOND that set ('%', '[', ']', '^', '|', '~' — and '\\' when * it is a path byte rather than a separator) pre-encode here so the * parser passes them through. */ static ScrStr *scr_url_encode_file_path(const char *raw, size_t len, bool backslash_sep) { @@ -1475,7 +1544,7 @@ static ScrStr *scr_url_encode_file_path(const char *raw, size_t len, bool backsl ub_init(&pre); for (size_t i = 0; i < len; i++) { unsigned char c = (unsigned char)raw[i]; - if (c == '%' || c == '[' || c == ']' || c == '^' || c == '|' || + if (c == '%' || c == '[' || c == ']' || c == '^' || c == '|' || c == '~' || (c == '\\' && !backslash_sep)) { char hex[4]; snprintf(hex, sizeof hex, "%%%02X", c); @@ -1537,24 +1606,30 @@ static ScrUrl *scr_url_from_path_impl(ScrStr *path, bool win32) { scr_str_release(resolved); return NULL; } - /* The URL host parser lowercases ASCII and TERMINATES at the URL - * delimiters '/', '?', '#' (Node feeds the servername through - * set_hostname: "\\\\?\\C:\\x" gets an EMPTY host and stays a - * drive path). No IDNA (documented divergence — Node punycodes - * non-ASCII names), and names with ':' or '%' stay verbatim where - * Node aborts on a native set_hostname assertion. */ - UrlBuf host; - ub_init(&host); + /* The servername goes through the host parser, as Node's hostname + * setter does: it drops tabs and newlines, stops at the URL + * delimiters '/', '?' and '#' + * ("\\\\?\\C:\\x" gets an empty host and stays a drive path), + * and a host it refuses throws ERR_INVALID_URL. */ + UrlBuf name; + ub_init(&name); for (size_t i = prefix; i < (size_t)host_end; i++) { char c = resolved->data[i]; if (c == '/' || c == '?' || c == '#') break; - if (c >= 'A' && c <= 'Z') c = (char)(c + 32); - ub_push(&host, c); + if (c != '\t' && c != '\n' && c != '\r') ub_push(&name, c); + } + ScrStr *host = NULL; + bool valid = parse_host(name.data, name.len, true, true, &host); + free(name.data); + if (!valid) { + scr_str_release(resolved); + scr_url_throw_invalid(); + return NULL; } ScrStr *encoded = scr_url_encode_file_path(resolved->data + host_end, resolved->len - (size_t)host_end, true); scr_str_release(resolved); - return scr_url_new_file(ub_take(&host), encoded); + return scr_url_new_file(host, encoded); } } else { ScrArr *pack = scr_arr_new(SCR_ELEM_STR, 1); @@ -1665,10 +1740,118 @@ static bool scr_native_url_set(void *ptr, const char *key, size_t len, const Scr return true; } +/* util.inspect's view of a URL: the properties Node's URL inspector lists, + * in its order, with the live searchParams object. Past the depth limit + * the inspector returns the URL itself, which util.inspect prints as + * [URL]. */ +static ScrDyn *scr_native_url_inspect_view(void *ptr) { + static const char *const keys[] = {"href", "origin", "protocol", "username", "password", + "host", "hostname", "port", "pathname", "search", + "searchParams", "hash"}; + ScrDyn *view = scr_dyn_new_obj(); + for (size_t i = 0; i < sizeof keys / sizeof keys[0]; i++) { + size_t len = strlen(keys[i]); + scr_dyn_obj_set(view, keys[i], len, scr_native_url_get(ptr, keys[i], len)); + } + return view; +} + +/* Node's urlToHttpOptions over a URL: protocol, hostname (an IPv6 literal + * without its brackets), hash, search, pathname, path (pathname and + * search), href, then port as a number when the URL has one and auth + * (the decoded username and password) when it has credentials. */ +ScrDyn *scr_url_to_http_options(ScrUrl *u) { + ScrDyn *options = scr_dyn_new_obj_null_proto(); + ScrStr *pathname = scr_url_pathname(u); + ScrStr *search = scr_url_search(u); + ScrStr *hostname = scr_url_hostname(u); + ScrStr *port = scr_url_port(u); + ScrStr *username = scr_url_username(u); + ScrStr *password = scr_url_password(u); + ScrStr *auth = NULL; + if (username->len || password->len) { + ScrStr *user = scr_str_decode_uri_component(username); + ScrStr *pass = user ? scr_str_decode_uri_component(password) : NULL; + if (pass) { + UrlBuf b; + ub_init(&b); + ub_append(&b, user->data, user->len); + ub_push(&b, ':'); + ub_append(&b, pass->data, pass->len); + auth = ub_take(&b); + } + scr_str_release(user); + scr_str_release(pass); + if (!auth) { + scr_str_release(pathname); + scr_str_release(search); + scr_str_release(hostname); + scr_str_release(port); + scr_str_release(username); + scr_str_release(password); + scr_dyn_release(options); + return NULL; + } + } +#define PUT_STR(key, value) \ + do { \ + ScrStr *text_ = (value); \ + scr_dyn_obj_set(options, key, sizeof key - 1, scr_dyn_new_str(text_)); \ + scr_str_release(text_); \ + } while (0) + PUT_STR("protocol", scr_url_protocol(u)); + if (hostname->len >= 2 && hostname->data[0] == '[') + PUT_STR("hostname", scr_str_new(hostname->data + 1, hostname->len - 2)); + else + PUT_STR("hostname", scr_str_retain(hostname)); + PUT_STR("hash", scr_url_hash(u)); + PUT_STR("search", scr_str_retain(search)); + PUT_STR("pathname", scr_str_retain(pathname)); + UrlBuf path; + ub_init(&path); + ub_append(&path, pathname->data, pathname->len); + ub_append(&path, search->data, search->len); + PUT_STR("path", ub_take(&path)); + PUT_STR("href", scr_url_href(u)); + if (port->len) { + double number = 0; + for (size_t i = 0; i < port->len; i++) number = number * 10 + (port->data[i] - '0'); + scr_dyn_obj_set(options, "port", 4, scr_dyn_new_num(number)); + } + if (auth) PUT_STR("auth", auth); +#undef PUT_STR + scr_str_release(pathname); + scr_str_release(search); + scr_str_release(hostname); + scr_str_release(port); + scr_str_release(username); + scr_str_release(password); + return options; +} + +ScrDyn *scr_url_to_http_options_dyn(const ScrDyn *value) { + if (scr_dyn_native_url_is(value)) return scr_url_to_http_options(value->v.handle.ptr); + if (!value || value->kind <= SCR_DYN_STR || value->kind == SCR_DYN_UNDEF || + value->kind == SCR_DYN_BIGINT || value->kind == SCR_DYN_SYMBOL) { + scr_dyn_arg_type_fail("url", "of type object", value); + return NULL; + } + static const char message[] = "url.urlToHttpOptions of an object that is not a URL is not supported yet"; + scr_throw_error_msg_code(SCR_ERR_ERROR, message, sizeof message - 1, "SC2020"); + return NULL; +} + ScrDyn *scr_dyn_native_url(ScrUrl *value) { static const ScrDynHandleOps ops = { - "URL", &scr_url_retain_v, &scr_url_release_v, &scr_native_url_invoke, - &scr_native_url_get, &scr_native_url_set, NULL, NULL, + .cls = "URL", + .retain = &scr_url_retain_v, + .release = &scr_url_release_v, + .invoke = &scr_native_url_invoke, + .get = &scr_native_url_get, + .set = &scr_native_url_set, + .inspect_view = &scr_native_url_inspect_view, + .inspect_bracketed_past_depth = true, + .inspect_view_nested = true, }; scr_dyn_handle_install(SCR_DYNH_URL, &ops); return scr_dyn_new_handle(value, SCR_DYNH_URL); diff --git a/packages/runtime/src/scr_url.h b/packages/runtime/src/scr_url.h index 435644419..c7c9c63c8 100644 --- a/packages/runtime/src/scr_url.h +++ b/packages/runtime/src/scr_url.h @@ -41,6 +41,12 @@ ScrStr *scr_url_href(ScrUrl *u); /* +1; also toString() */ void scr_url_set(ScrUrl *u, ScrStr *field, ScrStr *value); /* borrowed; href may throw */ bool scr_url_set_component(ScrUrl *u, ScrStr *field, ScrStr *value); /* borrowed; false for ignored writes */ void scr_url_set_checked(ScrUrl *u, ScrStr *field, const ScrDyn *value); /* borrowed; conversion may throw */ +/* url.urlToHttpOptions: Node's null-prototype options object for a URL. + * The checked-dynamic form throws ERR_INVALID_ARG_TYPE for a primitive or + * null and has no lowering for an object that is not a URL. Borrowed; +1, + * or NULL with the error pending. */ +ScrDyn *scr_url_to_http_options(ScrUrl *u); +ScrDyn *scr_url_to_http_options_dyn(const ScrDyn *value); /* node:url's legacy surface (scr_url_legacy.c — linked with the regex, * querystring and dyn-async units). url.parse() answers a checked-dynamic * Url instance; format() accepts a Url-shaped object, a string, or a diff --git a/tests/corpus/8101-url-host-and-path-parsing.js b/tests/corpus/8101-url-host-and-path-parsing.js new file mode 100644 index 000000000..6b04dd9ef --- /dev/null +++ b/tests/corpus/8101-url-host-and-path-parsing.js @@ -0,0 +1,103 @@ +// WHATWG URL host and path parsing: special hosts are percent-decoded and +// checked for forbidden domain code points (and read as IPv4 when they end +// in a number), opaque hosts and paths percent-encode the C0 control set, +// file: URLs take no port or credentials, empty hosts refuse credentials and +// ports, and host-less paths that start with "//" round-trip. Cases from the +// WPT url test data. +const parses = [ + ["file://example:1/", null], + ["non-special:opaque ?hi", null], + ["non-special:opaque #hi", null], + ["non-special:opaque \t\t \t#hi", null], + ["non-special:opaque \t\t #hi", null], + ["non-special:opaque\t\t \r #hi", null], + ["sc://faß.ExAmPlE/", null], + ["http://%30%78%63%30%2e%30%32%35%30.01", "http://other.com/"], + ["http://%30%78%63%30%2e%30%32%35%30.01%2e", "http://other.com/"], + ["sc://ñ.test/", null], + ["sc://%/", null], + ["sc://@/", null], + ["sc://te@s:t@/", null], + ["sc://:/", null], + ["sc://:12/", null], + ["x", "sc://ñ"], + ["wow:\uFFFF", null], + ["http://a\u007Fb/", null], + ["sc://\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\u000b\f\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f\u007F!\"$%&'()*+,-.;=_`{}~/", null], + ["asdf://%43%7C/", null], + ["C|", "file://host/dir/file"], + ["C|", "file://host/D:/dir1/dir2/file"], + ["C|#", "file://host/dir/file"], + ["C|?", "file://host/dir/file"], + ["C|/", "file://host/dir/file"], + ["C|\n/", "file://host/dir/file"], + ["C|\\", "file://host/dir/file"], + ["C|/", "file://host/"], + ["file:C:/", "file://host/"], + ["sc://ñ", null], + ["sc://ñ?x", null], + ["sc://ñ#x", null], + ["#x", "sc://ñ"], + ["?x", "sc://ñ"], + ["", "non-spec:/..//p"], + ["path", "non-spec:/..//p"], + ["../path", "non-spec:/.//p"], + ["non-special://%E2%80%A0/", null], + ["non-special://H%4fSt/path", null], + ["non-special:cannot-be-a-base-url-\u0000\u0001\u001f\u001e~\u007F\u0080", null], + ["foo://!\"$%&'()*+,-.;=_`{}~/", null], + ["foo://host/ !\"$%&'()*+,-./:;<=>@[\\]^_`{|}~", null], + ["wss://host/ !\"$%&'()*+,-./:;<=>@[\\]^_`{|}~", null], + ["non-special:\u0000y", null], + ["non-special:x/\u0000y", null], + ["non-special:\uFFFFy", null], + ["non-special:x/\uFFFFy", null], + ["data://:443", null], + ["javascript://:443", null], + ["mailto://:443", null], + ["intent://:443", null], + ["urn://:443", null], + ["turn://:443", null], + ["stun://:443", null], +]; +function describe(url) { + return [url.href, url.protocol, url.username, url.password, url.host, url.hostname, url.port, url.pathname, url.search, url.hash].join(" | "); +} +for (const [input, base] of parses) { + let line; + try { + line = describe(base === null ? new URL(input) : new URL(input, base)); + } catch (e) { + line = `throws ${e.code}`; + } + console.log(JSON.stringify(input), JSON.stringify(base), "=>", line); +} + +const writes = [ + ["host", "sc://x/", "ß"], + ["host", "file://y/", "loc%41lhost"], + ["hostname", "file://y/", "loc%41lhost"], + ["pathname", "a:/", "\u0000\u0001\t\n\r\u001f !\"#$%&'()*+,-./09:;<=>?@AZ[\\]^_`az{|}~\u007F\u0080\u0081Éé"], + ["search", "data:space ?query", ""], + ["search", "sc:space ?query", ""], + ["search", "data:space ?query#fragment", ""], + ["search", "sc:space ?query#fragment", ""], + ["hash", "data:space #fragment", ""], + ["hash", "sc:space #fragment", ""], + ["hash", "data:space ?query#fragment", ""], + ["hash", "sc:space ?query#fragment", ""], +]; +for (const [name, href, value] of writes) { + const url = new URL(href); + if (name === "host") url.host = value; + else if (name === "hostname") url.hostname = value; + else if (name === "port") url.port = value; + else if (name === "pathname") url.pathname = value; + else if (name === "protocol") url.protocol = value; + else if (name === "username") url.username = value; + else if (name === "password") url.password = value; + else if (name === "search") url.search = value; + else if (name === "hash") url.hash = value; + else if (name === "href") url.href = value; + console.log(name, JSON.stringify(href), JSON.stringify(value), "=>", describe(url)); +} diff --git a/tests/corpus/8102-url-path-to-file-url-unc-hosts.js b/tests/corpus/8102-url-path-to-file-url-unc-hosts.js new file mode 100644 index 000000000..a96d1252e --- /dev/null +++ b/tests/corpus/8102-url-path-to-file-url-unc-hosts.js @@ -0,0 +1,36 @@ +// pathToFileURL(path, { windows: true }) parses a UNC servername with the URL +// host parser after dropping tabs and newlines and stopping at '#' and '?': +// forbidden host code points throw ERR_INVALID_URL, and the +// name is lowercased, percent-decoded and read as IPv4 when it ends in a +// number. "~" in a path is percent-encoded. +import url from "node:url"; +const paths = [ + "\\\\exa mple\\share\\file.txt", + "\\\\host name\\share\\file.txt", + "\\\\host@name\\share\\file.txt", + "\\\\host:name\\share\\file.txt", + "\\\\host[name\\share\\file.txt", + "\\\\host]name\\share\\file.txt", + "\\\\h Date: Fri, 23 Oct 2026 22:08:02 -0500 Subject: [PATCH 045/259] Make Dates mutable objects with Node's setters and conversions --- benchmarks/runtime/README.md | 1 + benchmarks/runtime/workloads/date-math.json | 6 + benchmarks/runtime/workloads/date-math.ts | 52 +++++ .../content/limitations/builtin-apis/date.mdx | 9 +- .../compiler/src/backend/llvm/lib-dispatch.ts | 9 + .../compiler/src/backend/llvm/lib-shared.ts | 2 + .../compiler/src/diagnostics/diagnostic.ts | 2 +- .../frontend/lowering/abstract-equality.ts | 38 ++++ .../lowering/builtins/date-classes.ts | 22 +- .../src/frontend/lowering/builtins/dates.ts | 192 +++++++++++++++++- .../src/frontend/lowering/date-values.ts | 60 ++++-- .../frontend/lowering/expressions/binary.ts | 13 ++ .../lowering/expressions/property-access.ts | 6 +- .../lowering/expressions/relational.ts | 10 + .../frontend/lowering/expressions/typeof.ts | 1 + .../frontend/lowering/expressions/updates.ts | 31 ++- .../src/frontend/lowering/lower-calls.ts | 6 + .../src/frontend/lowering/lower-classes.ts | 23 +++ .../src/frontend/lowering/lower-exprs.ts | 1 + .../src/frontend/lowering/lower-generators.ts | 10 +- .../src/frontend/lowering/lower-stmts.ts | 27 ++- .../src/frontend/lowering/lowerer.test.ts | 2 +- .../compiler/src/frontend/lowering/lowerer.ts | 3 + .../src/frontend/lowering/surfaces.ts | 7 + .../compiler/src/ir/builtin-signatures.ts | 9 + packages/compiler/src/ir/ir.ts | 13 +- packages/compiler/src/ir/validate.ts | 19 +- packages/compiler/surface-manifest.json | 7 + packages/compiler/test/ir.test.ts | 10 +- .../tests/corpus/8020-date-setters.ts.json | 6 + .../tests/corpus/8021-date-coercions.ts.json | 6 + .../tests/corpus/8022-date-unions.ts.json | 6 + .../corpus/8023-date-clone-throw.ts.json | 6 + .../corpus/8024-date-setters-dynamic.mjs.json | 6 + .../corpus/8025-date-subclass-setters.ts.json | 6 + ...026-date-subclass-setters-dynamic.mjs.json | 6 + packages/runtime/src/scr_lib.c | 126 +++++++++++- packages/runtime/src/scr_number.h | 17 ++ tests/corpus/8020-date-setters.ts | 115 +++++++++++ tests/corpus/8021-date-coercions.ts | 47 +++++ tests/corpus/8022-date-unions.ts | 68 +++++++ tests/corpus/8023-date-clone-throw.ts | 32 +++ tests/corpus/8024-date-setters-dynamic.mjs | 24 +++ tests/corpus/8025-date-subclass-setters.ts | 30 +++ .../8026-date-subclass-setters-dynamic.mjs | 17 ++ tests/diagnostics/stdlib-fence.ts | 10 - .../__snapshots__/assert-class-fences.ts.txt | 2 +- .../class-interface-refinements.ts.txt | 4 +- .../__snapshots__/date-formatters.ts.txt | 4 +- .../dynamic-representable-types.ts.txt | 2 +- tests/harness/__snapshots__/generics.ts.txt | 2 +- .../harness/__snapshots__/maps-surface.ts.txt | 2 +- .../regex-match-destructuring-fences.ts.txt | 2 +- ...engine-2103-optional-tuple-elements.ts.txt | 10 +- .../harness/__snapshots__/stdlib-fence.ts.txt | 81 +++----- tests/harness/__snapshots__/tuples.ts.txt | 4 +- .../union-clone-override-width.ts.txt | 2 +- .../corpus-costs/8020-date-setters.ts.json | 1 + .../corpus-costs/8021-date-coercions.ts.json | 1 + .../corpus-costs/8022-date-unions.ts.json | 1 + .../8023-date-clone-throw.ts.json | 1 + .../8024-date-setters-dynamic.mjs.json | 1 + .../8025-date-subclass-setters.ts.json | 1 + ...026-date-subclass-setters-dynamic.mjs.json | 1 + 64 files changed, 1061 insertions(+), 180 deletions(-) create mode 100644 benchmarks/runtime/workloads/date-math.json create mode 100644 benchmarks/runtime/workloads/date-math.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8020-date-setters.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8021-date-coercions.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8022-date-unions.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8023-date-clone-throw.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8024-date-setters-dynamic.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8025-date-subclass-setters.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8026-date-subclass-setters-dynamic.mjs.json create mode 100644 tests/corpus/8020-date-setters.ts create mode 100644 tests/corpus/8021-date-coercions.ts create mode 100644 tests/corpus/8022-date-unions.ts create mode 100644 tests/corpus/8023-date-clone-throw.ts create mode 100644 tests/corpus/8024-date-setters-dynamic.mjs create mode 100644 tests/corpus/8025-date-subclass-setters.ts create mode 100644 tests/corpus/8026-date-subclass-setters-dynamic.mjs create mode 100644 tests/harness/corpus-costs/8020-date-setters.ts.json create mode 100644 tests/harness/corpus-costs/8021-date-coercions.ts.json create mode 100644 tests/harness/corpus-costs/8022-date-unions.ts.json create mode 100644 tests/harness/corpus-costs/8023-date-clone-throw.ts.json create mode 100644 tests/harness/corpus-costs/8024-date-setters-dynamic.mjs.json create mode 100644 tests/harness/corpus-costs/8025-date-subclass-setters.ts.json create mode 100644 tests/harness/corpus-costs/8026-date-subclass-setters-dynamic.mjs.json diff --git a/benchmarks/runtime/README.md b/benchmarks/runtime/README.md index 4f152e4bb..11c049140 100644 --- a/benchmarks/runtime/README.md +++ b/benchmarks/runtime/README.md @@ -10,6 +10,7 @@ Application-shaped workloads for measuring the speed of compiled executables. Ea | `atomics-contended` | cpu | four worker threads updating `SharedArrayBuffer` counters with `Atomics`: one shared counter, one counter per worker, a `compareExchange` loop, and `Atomics.wait`/`notify` handoffs | | `channel-messages` | cpu | 200,000 MessageChannel messages in one thread, half numbers and half small objects, all posted before the port delivers any | | `csv-numbers` | cpu | `split`, `Number`, `parseInt`, `toFixed` | +| `date-math` | cpu | schedules built with Date setters (local and UTC), weekday and month-end rules through the getters, Dates sorted by time value | | `cyclic-graphs` | cpu | object graphs with back references built and dropped: trees with parent and sibling links, rings of records sharing a long-lived registry, closures capturing their owner | | `dictionary-walks` | cpu | `Record` dictionaries walked with for-in and `Object.keys`/`values`/`entries` while entries are added, updated and deleted | | `dynamic-methods` | cpu | untyped JavaScript calling builtin methods on values it does not type: string `slice`/`indexOf`/`toUpperCase`/`padStart`, array `push`/`pop`/`includes`, `Map` and `Set`, and an object's own methods | diff --git a/benchmarks/runtime/workloads/date-math.json b/benchmarks/runtime/workloads/date-math.json new file mode 100644 index 000000000..b43078582 --- /dev/null +++ b/benchmarks/runtime/workloads/date-math.json @@ -0,0 +1,6 @@ +{ + "entry": "workloads/date-math.ts", + "args": [ + "40" + ] +} diff --git a/benchmarks/runtime/workloads/date-math.ts b/benchmarks/runtime/workloads/date-math.ts new file mode 100644 index 000000000..56ec1066e --- /dev/null +++ b/benchmarks/runtime/workloads/date-math.ts @@ -0,0 +1,52 @@ +// Calendar arithmetic on Dates: schedules built by adjusting Dates with the +// UTC and local setters, weekday and month-end rules read back through the +// getters, Dates compared and sorted by time value, and ISO text for a +// sample. Argument: the number of rounds. +process.env.TZ = "America/New_York"; + +const rounds = Number(process.argv[2] ?? "40"); +let seed = 2026; +function random(): number { + seed = (Math.imul(seed, 1103515245) + 12345) >>> 0; + return seed / 4294967296; +} + +/** The next business day at 09:00 local time on or after `from`. */ +function nextBusinessDay(from: Date): Date { + const day = new Date(from.getTime()); + day.setHours(9, 0, 0, 0); + if (day < from) day.setDate(day.getDate() + 1); + while (day.getDay() === 0 || day.getDay() === 6) day.setDate(day.getDate() + 1); + return day; +} + +/** The last day of `date`'s month, in UTC. */ +function monthEnd(date: Date): number { + const end = new Date(date.getTime()); + end.setUTCDate(1); + end.setUTCMonth(end.getUTCMonth() + 1); + end.setUTCDate(0); + return end.getUTCDate(); +} + +let checksum = 0; +let sample = ""; +for (let round = 0; round < rounds; round++) { + const due: Date[] = []; + const cursor = new Date(Date.UTC(2020 + (round % 7), 0, 1, 12)); + for (let i = 0; i < 4000; i++) { + cursor.setUTCMinutes(cursor.getUTCMinutes() + Math.floor(random() * 4000)); + const next = nextBusinessDay(cursor); + checksum += next.getDate() + monthEnd(next) + next.getHours(); + if (i % 3 === 0) next.setMonth(next.getMonth() + 1, 15); + due.push(next); + } + due.sort((a, b) => +a - +b); + let previous = due[0]!; + for (const date of due) { + checksum += (+date - +previous) / 3600000; + previous = date; + } + sample = due[due.length >> 1]!.toISOString(); +} +console.log(Math.round(checksum), sample); diff --git a/docs/content/limitations/builtin-apis/date.mdx b/docs/content/limitations/builtin-apis/date.mdx index 89266b745..d783984fa 100644 --- a/docs/content/limitations/builtin-apis/date.mdx +++ b/docs/content/limitations/builtin-apis/date.mdx @@ -1,6 +1,7 @@ -- **Date:** Spread constructor arguments, setters, thrown Date values, and locale formatters are unsupported. - Dates are objects: `===` compares identity, `new Date(date)` makes a new Date, and Dates compile in arrays (`includes`, `indexOf`, `lastIndexOf`, `join`, and default `sort` by `toString()` text), in `Date | undefined` and `Date | null` slots, as Map and Set keys and values, and in records, tuples, class fields, closures, promises and generators. - Unions of a Date with other non-nullish types are unsupported. - Zero-argument, single number/string, and local-time year/month field constructors, `getTime`, `valueOf`, `toISOString`, `toUTCString`, `toJSON` (a `string | null`: null for an invalid date, as in Node), `toString`, `toDateString`, `toTimeString`, `String(date)` and template literal conversion, relational comparison, calendar getters, `getTimezoneOffset`, and single-string `Date.parse` compile. +- **Date:** Spread constructor arguments and locale formatters are unsupported. + Dates are objects with identity: `===` and `==` compare identity, `new Date(date)` makes a new Date, setters change the one Date every reference holds, and Dates compile in arrays (`includes`, `indexOf`, `lastIndexOf`, `join`, and default `sort` by `toString()` text), in unions with other types, as Map and Set keys and values, and in records, tuples, class fields, closures, promises and generators. + Thrown and rejected Dates keep their identity; `structuredClone` and `postMessage` copy them. + Zero-argument, single number/string, and local-time year/month field constructors, `getTime`, `valueOf`, `toISOString`, `toUTCString`, `toJSON` (a `string | null`: null for an invalid date, as in Node), `toString`, `toDateString`, `toTimeString`, the local and UTC calendar getters and setters, `setTime`, `getTimezoneOffset`, and single-string `Date.parse` compile. + Unary `+`, `-` and `Number(date)` read the time value; `String(date)`, template literals and `+` with a string read the `toString()` text; `date[Symbol.toPrimitive](hint)` compiles with a literal hint. A Date converted to `unknown` is the same Date object. See [Dates and timezones](#dates-and-timezones) for timezone data. diff --git a/packages/compiler/src/backend/llvm/lib-dispatch.ts b/packages/compiler/src/backend/llvm/lib-dispatch.ts index 9cd11feb1..d8ca5add8 100644 --- a/packages/compiler/src/backend/llvm/lib-dispatch.ts +++ b/packages/compiler/src/backend/llvm/lib-dispatch.ts @@ -649,6 +649,15 @@ export function emitGenericLibCall(host: LlvmEmitterContext, e: LibCallExpr): Ll if (MAY_THROW_LIB_FNS.has(e.fn) && LIB_FN_SYMS[e.fn] === undefined) { throw new LlvmUnsupportedError(`libCall:${e.fn}`, e.loc); } + // A setter's write: the time value into the Date object (ScrDate.ms). + if (e.fn === "date.store") { + const date = emitBorrowedInput(host, e.args[0]!).name; + const ms = host.emitExpr(e.args[1]!).name; + const field = B.tmp(); + B.line(`${field} = getelementptr inbounds i8, ptr ${date}, i64 8 ; ->ms`); + B.line(`store double ${ms}, ptr ${field}`); + return { name: ms, type: e.type }; + } // queueMicrotask's checked-dynamic form carries the AsyncLocalStorage // context like the static one (lib-process.ts). const sym = diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 21f32431c..69d028539 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -334,6 +334,8 @@ export const LIB_FN_SYMS: Record = { "date.getTime": "scr_date_get_time", "date.valueOf": "scr_date_get_time", "date.fromTime": "scr_date_get_time", + "date.setFields": "scr_date_set_fields", + "date.timeClip": "scr_date_new_ms", "date.parseGetTime": "scr_date_parse", "date.utc": "scr_date_utc", "date.newLocal": "scr_date_new_local", diff --git a/packages/compiler/src/diagnostics/diagnostic.ts b/packages/compiler/src/diagnostics/diagnostic.ts index 2fd8b6fb0..55c3e9047 100644 --- a/packages/compiler/src/diagnostics/diagnostic.ts +++ b/packages/compiler/src/diagnostics/diagnostic.ts @@ -622,7 +622,7 @@ export function unsupportedTypeDiag(typeText: string, loc: SrcLoc): ScrDiagnosti code: "SC2001", message: `values of type '${typeText}' cannot be compiled yet ` + - `(supported: number, string, boolean, arrays, Maps, Sets, RegExp, read-only Date values, functions, classes, records, unions of those, and 'unknown')`, + `(supported: number, string, boolean, arrays, Maps, Sets, RegExp, Dates, functions, classes, records, unions of those, and 'unknown')`, loc, milestone: "M2", }; diff --git a/packages/compiler/src/frontend/lowering/abstract-equality.ts b/packages/compiler/src/frontend/lowering/abstract-equality.ts index 6c74b3546..634ff6f22 100644 --- a/packages/compiler/src/frontend/lowering/abstract-equality.ts +++ b/packages/compiler/src/frontend/lowering/abstract-equality.ts @@ -5,6 +5,7 @@ import { DYN, DYN_HANDLE_KINDS, F64, + STRING, type IrExpr, type IrStmt, type IrType, @@ -285,6 +286,43 @@ export function lowerAbstractEquality( }; return negated ? { kind: "unary", op: "!", operand: result, type: BOOL, loc } : result; } + // Two Dates are equal when they are the same object, as with ===. + if (left.type.kind === "date" && right.type.kind === "date") + return { kind: "bin", op: negated ? "!==" : "===", left, right, type: BOOL, loc }; + // A Date and a string or number compare through the Date's default + // primitive, its toString() text. + if (left.type.kind === "date" || right.type.kind === "date") { + const otherType = left.type.kind === "date" ? right.type : left.type; + if (otherType.kind === "string" || otherType.kind === "f64") { + // Both operands evaluate before the Date converts. + const l = lowerer.declareHiddenLocal("%looseA", left.type); + const r = lowerer.declareHiddenLocal("%looseB", right.type); + const stmts: IrStmt[] = [ + { kind: "varDecl", localId: l.id, init: left, loc }, + { kind: "varDecl", localId: r.id, init: right, loc }, + ]; + const primitive = (value: IrExpr): IrExpr => { + if (value.type.kind !== "date") return value; + const text: IrExpr = { + kind: "libCall", + fn: "date.toString", + args: [value], + type: STRING, + loc, + }; + return otherType.kind === "string" + ? text + : { kind: "libCall", fn: "num.fromString", args: [text], type: F64, loc }; + }; + const a = primitive(varRef(l.id, left.type, loc)); + const b = primitive(varRef(r.id, right.type, loc)); + const result: IrExpr = + otherType.kind === "string" + ? { kind: "strEq", negated, left: a, right: b, type: BOOL, loc } + : { kind: "bin", op: negated ? "!==" : "===", left: a, right: b, type: BOOL, loc }; + return { kind: "seqExpr", stmts, result, type: BOOL, loc }; + } + } if (!supportsPair(lowerer, left.type, right.type)) return null; if (left.kind === "strLit" && right.kind === "strLit") { return { kind: "boolLit", value: (left.value === right.value) !== negated, type: BOOL, loc }; diff --git a/packages/compiler/src/frontend/lowering/builtins/date-classes.ts b/packages/compiler/src/frontend/lowering/builtins/date-classes.ts index a2b0fc20a..c8aab8687 100644 --- a/packages/compiler/src/frontend/lowering/builtins/date-classes.ts +++ b/packages/compiler/src/frontend/lowering/builtins/date-classes.ts @@ -2,7 +2,13 @@ import * as ts from "../../ts7/adapter.js"; import { type Lowerer } from "../lowerer.js"; import { locOf } from "../../program.js"; import { type ClassInfo } from "../lower-classes.js"; -import { DATE_METHOD_HINT, dateJsonType, dateValueMethod } from "./dates.js"; +import { + DATE_METHOD_HINT, + dateJsonType, + dateSetterTime, + dateValueMethod, + isDateSetter, +} from "./dates.js"; import { dynUndefinedExpr, varRef } from "../../../ir/build.js"; import { BOOL, @@ -248,6 +254,20 @@ export function lowerInheritedDateMethodCall( type: result.type, loc, }); + if (isDateSetter(name) && name !== "setTime") { + // The field setters change the Date the class's time slot holds. + const date = lowerer.declareHiddenLocal("%dateTime", DATE_T); + stmts.push({ + kind: "varDecl", + localId: date.id, + init: timeOf(lowerer, value, root, loc), + loc, + }); + const current = varRef(date.id, DATE_T, loc); + const time: IrExpr = { kind: "libCall", fn: "date.getTime", args: [current], type: F64, loc }; + const next = dateSetterTime(lowerer, call, name, stmts, time); + return done({ kind: "libCall", fn: "date.store", args: [current, next], type: F64, loc }); + } if (name === "setTime") { // Every argument is evaluated before setTime converts the first one. let ms: IrExpr = { kind: "numLit", value: Number.NaN, type: F64, loc }; diff --git a/packages/compiler/src/frontend/lowering/builtins/dates.ts b/packages/compiler/src/frontend/lowering/builtins/dates.ts index 0204386ab..79696d1ba 100644 --- a/packages/compiler/src/frontend/lowering/builtins/dates.ts +++ b/packages/compiler/src/frontend/lowering/builtins/dates.ts @@ -2,12 +2,15 @@ import * as ts from "../../ts7/adapter.js"; import { type Lowerer, own } from "../lowerer.js"; import { locOf } from "../../program.js"; import { tryLowerExpression } from "../expressions/try-lower-expression.js"; +import { lowerToNumberArguments } from "../lower-exprs.js"; import { programDeclaresDateClass } from "./date-classes.js"; import { BOOL, + DATE_T, F64, type IrExpr, type IrLibFn, + type IrLocal, type IrStmt, type IrType, NULL_T, @@ -36,6 +39,32 @@ const DATE_GETTER_FNS: Readonly> = { getTimezoneOffset: "date.getTimezoneOffset", }; +/** The setters that change calendar fields: the field code + * scr_date_set_fields takes (scr_number.h SCR_DATE_SET_*; 8 marks the UTC + * forms) and the most arguments each takes. */ +const DATE_FIELD_SETTERS: ReadonlyMap = new Map([ + ["setMilliseconds", { code: 0, max: 1 }], + ["setSeconds", { code: 1, max: 2 }], + ["setMinutes", { code: 2, max: 3 }], + ["setHours", { code: 3, max: 4 }], + ["setDate", { code: 4, max: 1 }], + ["setMonth", { code: 5, max: 2 }], + ["setFullYear", { code: 6, max: 3 }], + ["setUTCMilliseconds", { code: 8, max: 1 }], + ["setUTCSeconds", { code: 9, max: 2 }], + ["setUTCMinutes", { code: 10, max: 3 }], + ["setUTCHours", { code: 11, max: 4 }], + ["setUTCDate", { code: 12, max: 1 }], + ["setUTCMonth", { code: 13, max: 2 }], + ["setUTCFullYear", { code: 14, max: 3 }], +]); + +/** Whether `name` is a Date setter scriptc lowers: setTime or a field + * setter. */ +export function isDateSetter(name: string): boolean { + return name === "setTime" || DATE_FIELD_SETTERS.has(name); +} + const DATE_TEXT_FNS: ReadonlyMap = new Map([ ["toString", "date.toString"], ["toDateString", "date.toDateString"], @@ -43,11 +72,11 @@ const DATE_TEXT_FNS: ReadonlyMap = new Map([ ]); export const DATE_METHOD_HINT = - "getTime(), valueOf(), toISOString(), toUTCString(), toJSON(), toString(), toDateString(), toTimeString(), the local/UTC calendar getters, and getTimezoneOffset() are supported; Date setters and locale formatters have no lowering"; + "getTime(), valueOf(), toISOString(), toUTCString(), toJSON(), toString(), toDateString(), toTimeString(), the local/UTC calendar getters and setters, setTime(), and getTimezoneOffset() are supported; locale formatters have no lowering"; -/** The Date slice: statics plus read-only Date values backed by one - * TimeClip'd millisecond scalar. Construction lives in lowerNew; - * identity and mutating methods remain fenced. */ +/** Date statics and methods on Date objects (a TimeClip'd millisecond + * time value with identity): getters, text forms and setters. + * Construction lives in lowerNew. */ export function lowerDateCall( lowerer: Lowerer, call: ts.CallExpression, @@ -67,16 +96,18 @@ export function lowerDateCall( if (lowerer.mapTypeOf(lowerer.typeOf(access.expression))?.kind !== "date") return null; if (!lowerer.isStdlibMember(access)) return null; const name = access.name.text; - // A Date a JavaScript file constructs is a mutable object; setTime on - // it takes the dynamic method call. So does every Date method on a + // A Date a JavaScript file constructs is a checked-dynamic value; a + // setter on it takes the dynamic method call, which changes the Date the + // handle holds. So does every Date method on a // checked-dynamic receiver when the program declares a class that extends // Date: the value can be an instance, whose class may declare the method. if ( - (name === "setTime" || programDeclaresDateClass(lowerer)) && + (isDateSetter(name) || programDeclaresDateClass(lowerer)) && tryLowerExpression(lowerer, access.expression)?.type.kind === "dyn" ) return null; if (name === "toJSON") return lowerDateToJson(lowerer, call, access); + if (isDateSetter(name)) return lowerDateSetter(lowerer, call, access, name); if (call.arguments.nodes.length !== 0) { lowerer.noLowering(`Date.prototype.${name} with arguments`, call, DATE_METHOD_HINT); } @@ -253,3 +284,150 @@ export function isDateJsonSource(lowerer: Lowerer, node: ts.Node): boolean { lowerer.isStdlibMember(access) ); } + +/** `d.setTime(t)` and the field setters (`d.setHours(h, m?, s?, ms?)` ...) + * on a Date object: the receiver, then the arguments in order, then the + * new time value (scr_date_set_fields over the time value the Date holds + * once the arguments have run) stored into the Date and answered. Missing + * optional arguments keep their fields; arguments past a setter's last + * one are evaluated and ignored. A Date local that holds its time value + * (date-values.ts) takes the new time value itself. */ +function lowerDateSetter( + lowerer: Lowerer, + call: ts.CallExpression, + access: ts.PropertyAccessExpression, + name: string, +): IrExpr { + const loc = locOf(call); + const nodes = call.arguments.nodes; + if (nodes.some((node) => ts.isSpreadElement(node))) + lowerer.noLowering(`Date.prototype.${name} with spread arguments`, call, DATE_METHOD_HINT); + const timeLocal = timeValueLocalOf(lowerer, access.expression); + const stmts: IrStmt[] = []; + let receiver: IrExpr | null = null; + if (timeLocal === null) { + // A checked-dynamic receiver takes the dynamic method call + // (lowerDateCall), so the value here is a Date object. + const value = lowerer.lowerExpr(access.expression); + if (value.type.kind !== "date") + lowerer.badType(access.expression, lowerer.typeOf(access.expression)); + const date = lowerer.declareHiddenLocal("%date", DATE_T); + stmts.push({ kind: "varDecl", localId: date.id, init: value, loc }); + receiver = { kind: "varRef", localId: date.id, type: DATE_T, loc }; + } + const time: IrExpr = + receiver === null + ? { kind: "varRef", localId: timeLocal!.id, type: F64, loc } + : { kind: "libCall", fn: "date.getTime", args: [receiver], type: F64, loc }; + const next = dateSetterTime(lowerer, call, name, stmts, time); + if (receiver === null) { + stmts.push({ kind: "assign", localId: timeLocal!.id, value: next, loc }); + return { + kind: "seqExpr", + stmts, + result: { kind: "varRef", localId: timeLocal!.id, type: F64, loc }, + type: F64, + loc, + }; + } + return { + kind: "seqExpr", + stmts, + result: { kind: "libCall", fn: "date.store", args: [receiver, next], type: F64, loc }, + type: F64, + loc, + }; +} + +/** The new time value of setter `name` called with `call`'s arguments on a + * Date whose time value `time` reads: the arguments evaluate into + * temporaries appended to `stmts` (ToNumber of each, an undefined one is + * NaN), and the result reads `time` after them. Missing optional arguments + * keep their fields; arguments past a setter's last one are evaluated and + * ignored. */ +export function dateSetterTime( + lowerer: Lowerer, + call: ts.CallExpression, + name: string, + stmts: IrStmt[], + time: IrExpr, +): IrExpr { + const loc = locOf(call); + const converted = lowerToNumberArguments( + lowerer, + call.arguments.nodes as readonly ts.Expression[], + ); + stmts.push(...converted.stmts); + const args: IrExpr[] = converted.values.map((value) => { + if (value.kind === "numLit") return value; + const arg = lowerer.declareHiddenLocal("%dateArg", F64); + stmts.push({ kind: "varDecl", localId: arg.id, init: value, loc }); + return { kind: "varRef", localId: arg.id, type: F64, loc }; + }); + const number = (value: number): IrExpr => ({ kind: "numLit", value, type: F64, loc }); + if (name === "setTime") + return { + kind: "libCall", + fn: "date.timeClip", + args: [args[0] ?? number(Number.NaN)], + type: F64, + loc, + }; + const setter = DATE_FIELD_SETTERS.get(name)!; + const used = args.slice(0, setter.max); + const operands = [...used]; + while (operands.length < 4) operands.push(number(0)); + return { + kind: "libCall", + fn: "date.setFields", + args: [time, number(setter.code), number(used.length), ...operands], + type: F64, + loc, + }; +} + +/** The local a Date binding that holds its time value lowers to, for an + * identifier `node` that names one (date-values.ts); null otherwise. */ +function timeValueLocalOf(lowerer: Lowerer, node: ts.Expression): IrLocal | null { + while (ts.isParenthesizedExpression(node)) node = node.expression; + if (!ts.isIdentifier(node)) return null; + const local = lowerer.resolveLocal(node); + return local !== undefined && local !== null && lowerer.timeValueDateLocals.has(local) + ? local + : null; +} + +/** `d[Symbol.toPrimitive](hint)` on a Date with a literal hint: "number" + * answers the time value, "string" and "default" the toString() text (a + * Date's default hint is a string). Null for other calls. */ +export function lowerDateToPrimitiveCall( + lowerer: Lowerer, + call: ts.CallExpression, + access: ts.ElementAccessExpression, +): IrExpr | null { + const key = access.argumentExpression; + if ( + !ts.isPropertyAccessExpression(key) || + key.name.text !== "toPrimitive" || + !ts.isIdentifier(key.expression) || + !lowerer.isStdlibGlobal(key.expression, "Symbol") || + lowerer.mapTypeOf(lowerer.typeOf(access.expression))?.kind !== "date" + ) + return null; + const loc = locOf(call); + const hint = call.arguments.nodes.length === 1 ? call.arguments.nodes[0]! : null; + const text = hint !== null && ts.isStringLiteralLike(hint) ? hint.text : null; + if (text !== "number" && text !== "string" && text !== "default") + return lowerer.noLowering( + 'Date.prototype[Symbol.toPrimitive] without a "number", "string" or "default" literal hint', + call, + ); + const raw = lowerer.lowerExpr(access.expression); + const date: IrExpr = + raw.type.kind === "dyn" + ? { kind: "libCall", fn: "date.checkedValue", args: [raw], type: DATE_T, loc } + : raw; + return text === "number" + ? { kind: "libCall", fn: "date.valueOf", args: [date], type: F64, loc } + : { kind: "libCall", fn: "date.toString", args: [date], type: STRING, loc }; +} diff --git a/packages/compiler/src/frontend/lowering/date-values.ts b/packages/compiler/src/frontend/lowering/date-values.ts index ef5eafebe..669bc1dbc 100644 --- a/packages/compiler/src/frontend/lowering/date-values.ts +++ b/packages/compiler/src/frontend/lowering/date-values.ts @@ -1,5 +1,6 @@ import * as ts from "../ts7/adapter.js"; import type { Lowerer } from "./lowerer.js"; +import { isDateSetter } from "./builtins/dates.js"; /** Date methods whose receiver is only read for its time value: a Date * local used as their receiver can store the time value instead of a Date @@ -41,12 +42,14 @@ const RELATIONAL = new Set([ /** True when a local `const` (or a `let` that is never assigned again) * initialized with `new Date(...)` can keep the Date's time value instead - * of a Date object: no use observes the Date's identity. Every use reads the time value as - * a Date method receiver, a String() or template operand, a relational or - * string `+` operand, or `new Date(d)`'s argument, inside the declaring - * function, or inside the block or loop that scopes a module-level - * binding (no closure captures it). Top-level module bindings keep the - * object. Other uses box the time value into a new Date at the use. */ + * of a Date object: no use observes the Date's identity. Every use reads + * the time value as a Date method receiver (a setter replaces it), a + * String(), Number() or template operand, a unary + or - operand, a + * relational or string `+` operand, or `new Date(d)`'s argument, inside + * the declaring function, or inside the block or loop that scopes a + * module-level binding (no closure captures it). Top-level module bindings + * keep the object. Other uses box the time value into a new Date at the + * use. */ export function isTimeValueDateDeclaration( lowerer: Lowerer, decl: ts.VariableDeclaration, @@ -94,17 +97,21 @@ function decideTimeValueDate(lowerer: Lowerer, decl: ts.VariableDeclaration): bo const symbol = lowerer.checker.getSymbolAtLocation(decl.name); if (!symbol) return false; let ok = true; + let sets = false; const visit = (node: ts.Node): void => { if (!ok) return; if (ts.isIdentifier(node) && node !== decl.name && node.text === decl.name.text) { if (lowerer.checker.getSymbolAtLocation(node) === symbol) { - if (enclosingFunction(node) !== fn || !readsTimeValue(lowerer, node)) ok = false; + const use = enclosingFunction(node) === fn ? timeValueUse(lowerer, node) : null; + if (use === null) ok = false; + else if (use === "set") sets = true; } return; } ts.forEachChild(node, visit); }; visit(scope); + if (ok && sets) lowerer.timeValueDateWrites.add(decl); return ok; } @@ -164,29 +171,46 @@ function enclosingFunction(node: ts.Node): ts.FunctionLikeDeclaration | null { return null; } -/** A use of the binding that reads only its time value. */ -function readsTimeValue(lowerer: Lowerer, id: ts.Identifier): boolean { +/** How a use of the binding uses its time value: "read" for a use that + * reads only the time value, "set" for a setter call that replaces it, or + * null for any other use. */ +function timeValueUse(lowerer: Lowerer, id: ts.Identifier): "read" | "set" | null { let node: ts.Node = id; while (ts.isParenthesizedExpression(node.parent)) node = node.parent; const parent = node.parent; + if (parent === undefined) return null; if (ts.isPropertyAccessExpression(parent) && parent.expression === node) { const call = parent.parent; - return ( - !parent.questionDotToken && - ts.isCallExpression(call) && - call.expression === parent && - !call.questionDotToken && - TIME_VALUE_METHODS.has(parent.name.text) && - lowerer.isStdlibMember(parent) - ); + if ( + parent.questionDotToken || + !ts.isCallExpression(call) || + call.expression !== parent || + call.questionDotToken || + !lowerer.isStdlibMember(parent) + ) + return null; + if (isDateSetter(parent.name.text)) return "set"; + return TIME_VALUE_METHODS.has(parent.name.text) ? "read" : null; } + return readsTimeValue(lowerer, node, parent) ? "read" : null; +} + +/** A use of the binding, other than a method call, that reads only its + * time value. */ +function readsTimeValue(lowerer: Lowerer, node: ts.Node, parent: ts.Node): boolean { if (ts.isTemplateSpan(parent)) return parent.expression === node; + // Unary + and -, the number hint. + if (ts.isPrefixUnaryExpression(parent)) + return ( + parent.operator === ts.SyntaxKind.PlusToken || parent.operator === ts.SyntaxKind.MinusToken + ); if (ts.isCallExpression(parent)) { return ( parent.arguments.nodes.length === 1 && parent.arguments.nodes[0] === node && ts.isIdentifier(parent.expression) && - lowerer.isStdlibGlobal(parent.expression, "String") + (lowerer.isStdlibGlobal(parent.expression, "String") || + lowerer.isStdlibGlobal(parent.expression, "Number")) ); } if (ts.isNewExpression(parent)) { diff --git a/packages/compiler/src/frontend/lowering/expressions/binary.ts b/packages/compiler/src/frontend/lowering/expressions/binary.ts index 00a23caf5..de6648836 100644 --- a/packages/compiler/src/frontend/lowering/expressions/binary.ts +++ b/packages/compiler/src/frontend/lowering/expressions/binary.ts @@ -1600,6 +1600,19 @@ export function lowerBinary(lowerer: Lowerer, expr: ts.BinaryExpression): IrExpr loc, }; } + // A Date against an untyped value: the same Date object, whose + // checked-dynamic handle the untyped value would hold. + if (dynSide.type.kind === "dyn" && scalarSide.type.kind === "date") { + const boxed = lowerer.coerceToExpected(scalarSide, DYN); + return { + kind: "dynScalarEq", + left: scalarSide === left ? boxed : left, + right: scalarSide === right ? boxed : right, + ...(negated ? { negated: true as const } : {}), + type: BOOL, + loc, + }; + } if ( dynSide.type.kind === "dyn" && (scalarSide.type.kind === "f64" || diff --git a/packages/compiler/src/frontend/lowering/expressions/property-access.ts b/packages/compiler/src/frontend/lowering/expressions/property-access.ts index 1a4883e5a..874c0c6cc 100644 --- a/packages/compiler/src/frontend/lowering/expressions/property-access.ts +++ b/packages/compiler/src/frontend/lowering/expressions/property-access.ts @@ -112,6 +112,7 @@ import { dynUndefinedExpr, nodeThrowExpr, numLit, strLit, varRef } from "../../. import { typedArrayLacksMember } from "../builtins/typed-array-members.js"; import { TEMPORAL_GLOBAL } from "../../builtin-modules.js"; import { tryLowerExpression } from "./try-lower-expression.js"; +import { DATE_METHOD_HINT } from "../builtins/dates.js"; import { cjsClassExprWholeExportOf, cjsExportAssignmentOf, @@ -2055,6 +2056,9 @@ export function lowerIntrinsicProperty( ); } if (kind === "date") { + // A Date held as a checked-dynamic value (a Date a JavaScript file + // constructs) answers its method values at run time. + if (tryLowerExpression(lowerer, expr.expression)?.type.kind === "dyn") return null; const methods = new Set([ "getTime", "valueOf", @@ -2083,7 +2087,7 @@ export function lowerIntrinsicProperty( lowerer.noLowering( `Date.prototype.${name}`, expr, - "getTime(), valueOf(), toISOString(), the local/UTC calendar getters, and getTimezoneOffset() are supported; Date setters and locale/string formatters have no lowering", + DATE_METHOD_HINT, lowerer.checker.getSymbolAtLocation(expr.name), ); } diff --git a/packages/compiler/src/frontend/lowering/expressions/relational.ts b/packages/compiler/src/frontend/lowering/expressions/relational.ts index 1651bf0d9..2903e4e14 100644 --- a/packages/compiler/src/frontend/lowering/expressions/relational.ts +++ b/packages/compiler/src/frontend/lowering/expressions/relational.ts @@ -288,6 +288,16 @@ export function lowerInstanceOf(lowerer: Lowerer, expr: ts.BinaryExpression, loc if (!target) { const date = lowerer.isStdlibGlobal(expr.right, "Date"); const url = lowerer.isStdlibGlobal(expr.right, "URL"); + // A catch binding holds a thrown Date as its checked-dynamic handle. + const caughtDate = date ? lowerer.caughtLocalOf(expr.left) : null; + if (caughtDate) + return { + kind: "libCall", + fn: "dyn.nativeDateIs", + args: [{ kind: "caughtToDyn", value: varRef(caughtDate.id, CAUGHT, loc), type: DYN, loc }], + type: BOOL, + loc, + }; if ((date || url) && !lowerer.caughtLocalOf(expr.left)) { const value = lowerer.lowerExpr(expr.left); if (value.type.kind === "dyn") diff --git a/packages/compiler/src/frontend/lowering/expressions/typeof.ts b/packages/compiler/src/frontend/lowering/expressions/typeof.ts index fbbc068b9..0676f3cf5 100644 --- a/packages/compiler/src/frontend/lowering/expressions/typeof.ts +++ b/packages/compiler/src/frontend/lowering/expressions/typeof.ts @@ -281,6 +281,7 @@ export function lowerTypeofExpr(lowerer: Lowerer, expr: ts.TypeOfExpression, loc promise: "object", bytes: "object", regex: "object", + date: "object", generator: "object", classval: "function", moduleNs: "object", diff --git a/packages/compiler/src/frontend/lowering/expressions/updates.ts b/packages/compiler/src/frontend/lowering/expressions/updates.ts index bdcd94a44..35d5d1a2e 100644 --- a/packages/compiler/src/frontend/lowering/expressions/updates.ts +++ b/packages/compiler/src/frontend/lowering/expressions/updates.ts @@ -120,6 +120,11 @@ function coercedUnion(lowerer: Lowerer, type: IrType): boolean { return arms.some((arm) => arm.kind !== "f64" && !isUnitType(arm)); } +/** ToNumber of a Date: its time value (valueOf, the number hint). */ +function dateTimeValue(date: IrExpr, loc: SrcLoc): IrExpr { + return { kind: "libCall", fn: "date.valueOf", args: [date], type: F64, loc }; +} + /** ToNumber of a boolean: 1 for true, 0 for false. */ function booleanToNumber(value: IrExpr, loc: SrcLoc): IrExpr { return { @@ -145,23 +150,25 @@ export function lowerPrefixUnary(lowerer: Lowerer, expr: ts.PrefixUnaryExpressio const operand = raw.type.kind === "bool" ? booleanToNumber(raw, loc) - : coercedUnion(lowerer, raw.type) - ? ({ - kind: "libCall", - fn: "dyn.toNumberCoerce", - args: [{ kind: "dynFrom", value: raw, type: DYN, loc }], - type: F64, - loc, - } satisfies IrExpr) - : raw.type.kind === "dyn" && isJsSourceFile(ts.getSourceFileOfNode(expr)) + : raw.type.kind === "date" + ? dateTimeValue(raw, loc) + : coercedUnion(lowerer, raw.type) ? ({ kind: "libCall", fn: "dyn.toNumberCoerce", - args: [raw], + args: [{ kind: "dynFrom", value: raw, type: DYN, loc }], type: F64, loc, } satisfies IrExpr) - : lowerOptionalNumber(lowerer, raw, loc, expr.operand); + : raw.type.kind === "dyn" && isJsSourceFile(ts.getSourceFileOfNode(expr)) + ? ({ + kind: "libCall", + fn: "dyn.toNumberCoerce", + args: [raw], + type: F64, + loc, + } satisfies IrExpr) + : lowerOptionalNumber(lowerer, raw, loc, expr.operand); if (operand.type.kind !== "f64") operatorUnsupported(lowerer, expr, "-", [raw.type]); if (operand.kind === "numLit") return { ...operand, value: -operand.value, loc }; return { kind: "unary", op: "-", operand, type: F64, loc }; @@ -185,6 +192,8 @@ export function lowerPrefixUnary(lowerer: Lowerer, expr: ts.PrefixUnaryExpressio return { kind: "libCall", fn: "num.fromString", args: [raw], type: F64, loc }; } if (raw.type.kind === "bool") return booleanToNumber(raw, loc); + // A Date's number hint answers its time value. + if (raw.type.kind === "date") return dateTimeValue(raw, loc); const classNumber = classToNumberConversion(lowerer, raw, expr.operand, "unary plus"); if (classNumber) return classNumber; const operand = lowerOptionalNumber(lowerer, raw, loc, expr.operand); diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 073ebed91..6ca6b7016 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -1,5 +1,6 @@ import { keyedHelperName } from "./stable-names.js"; import { perKeyOrder } from "./key-order-witness.js"; +import { lowerDateToPrimitiveCall } from "./builtins/dates.js"; import { isForwardedTupleSpread, lowerForwardingApply } from "./typed-arguments.js"; import { guardNullProto, nullProtoRecordShape } from "./null-prototype.js"; import { lowerDynStreamMemberCall } from "./dyn-streams.js"; @@ -1816,6 +1817,8 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { // The element spelling of an unsupported native Web method must fence // before lowering the callee into a checked-dynamic keyed read. if (ts.isElementAccessExpression(expr.expression)) { + const datePrimitive = lowerDateToPrimitiveCall(lowerer, expr, expr.expression); + if (datePrimitive) return datePrimitive; const timersDispose = lowerMockTimersElementCall(lowerer, expr, expr.expression); if (timersDispose) return timersDispose; const symbolMethod = lowerClassSymbolMethodCall(lowerer, expr); @@ -2456,6 +2459,9 @@ function lowerNumberConstructorValue( }; const optionalNumber = lowerOptionalStringNumber(lowerer, arg, loc); if (optionalNumber) return optionalNumber; + // A Date's number hint answers its time value. + if (arg.type.kind === "date") + return { kind: "libCall", fn: "date.valueOf", args: [arg], type: F64, loc }; // A program class instance converts through its own methods. const classNumber = classToNumberConversion(lowerer, arg, argNode); if (classNumber) return classNumber; diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index 3e49304d2..7655fcea7 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -10426,6 +10426,29 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { const time: IrExpr = { kind: "libCall", fn: "date.getTime", args: [arg], type: F64, loc }; return { kind: "libCall", fn: "date.newMs", args: [time], type: DATE_T, loc }; } + // A union (`Date | string | number`) or checked-dynamic value: the + // runtime's constructor reads a Date's time value, parses a string + // and converts anything else to a primitive and a number. + if ( + (arg.type.kind === "union" || arg.type.kind === "dyn") && + lowerer.dynConvertible(arg.type) + ) { + const value: IrExpr = { + kind: "libCall", + fn: "date.nativeNewValue", + args: [ + { + kind: "dynArrLit", + elems: [lowerer.coerceToExpected(arg, DYN)], + type: DYN, + loc, + }, + ], + type: DYN, + loc, + }; + return { kind: "libCall", fn: "date.checkedValue", args: [value], type: DATE_T, loc }; + } lowerer.noLowering( `new Date of '${lowerer.fmt(arg.type)}' values`, args[0]!, diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index f2b601619..88e9ddb12 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -2320,6 +2320,7 @@ export function typeofAnswer(arm: IrType): string | null { case "set": case "generator": case "regex": + case "date": case "bytes": case "url": case "searchParams": diff --git a/packages/compiler/src/frontend/lowering/lower-generators.ts b/packages/compiler/src/frontend/lowering/lower-generators.ts index f837cc0af..ccfa4ad39 100644 --- a/packages/compiler/src/frontend/lowering/lower-generators.ts +++ b/packages/compiler/src/frontend/lowering/lower-generators.ts @@ -183,13 +183,9 @@ export function lowerGenMethodCall( ); } arg = lowerer.lowerExpr(argNode); - if (arg.type.kind === "date") { - lowerer.unsupported( - "SC1090", - argNode, - ".throw() with a Date value (the exception channel cannot preserve Date's object kind; throw an Error or primitive instead)", - ); - } + // A Date throws as its checked-dynamic handle, the same Date object + // (the throw statement's rule). + if (arg.type.kind === "date") arg = lowerer.coerceToExpected(arg, DYN); if (arg.type.kind === "void" || arg.type.kind === "caught" || isUnitType(arg.type)) { lowerer.unsupported( "SC1090", diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index c50676863..9e9e75794 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -1624,6 +1624,7 @@ const THROWN_AS_DYN: ReadonlySet = new Set([ "bytes", "func", "regex", + "date", ]); export function lowerStmt(lowerer: Lowerer, stmt: ts.Statement): IrStmt | IrStmt[] | null { @@ -1828,9 +1829,7 @@ export function lowerStmt(lowerer: Lowerer, stmt: ts.Statement): IrStmt | IrStmt return { kind: "rethrow", localId: caughtLocal.id, loc: locOf(stmt) }; } // Exception-representable values move into the runtime's exception - // cell. `throw f()` of a void call has no value; Date has numeric - // storage internally, but cannot preserve its object kind through the - // untyped catch boundary. Reject both rather than changing JS identity. + // cell. `throw f()` of a void call has no value. let value = lowerer.lowerExpr(stmt.expression); if (value.type.kind === "void") lowerer.badType(stmt.expression, lowerer.typeOf(stmt.expression)); @@ -1842,19 +1841,12 @@ export function lowerStmt(lowerer: Lowerer, stmt: ts.Statement): IrStmt | IrStmt } else if (value.type.kind === "record" && lowerer.dynConvertible(value.type)) { value = { kind: "dynFrom", value, liveRef: true, type: DYN, loc: locOf(stmt.expression) }; } else if (THROWN_AS_DYN.has(value.type.kind) && lowerer.dynConvertible(value.type)) { - // Arrays, Maps, Sets, typed arrays, Buffers, functions, regexes and - // unions over them keep their identity and contents the same way: - // the catch binding, `typeof`, `instanceof`, `Array.isArray`, - // inspection and typed views read the thrown object. + // Arrays, Maps, Sets, typed arrays, Buffers, functions, regexes, + // Dates and unions over them keep their identity and contents the + // same way: the catch binding, `typeof`, `instanceof`, + // `Array.isArray`, inspection and typed views read the thrown object. value = lowerer.coerceInto(stmt.expression, value, DYN); } - if (value.type.kind === "date") { - lowerer.unsupported( - "SC1090", - stmt.expression, - "throwing Date values (catch bindings cannot preserve Date's object kind; throw an Error or primitive instead)", - ); - } // A dyn throw rides the REF cell arm (scr_throw_ref over the checked-dynamic tree // node — identity preserved through catch bindings, caughtToDyn // passes it back by reference). The JS-lane traced-call shape: @@ -5450,7 +5442,12 @@ export function lowerVarDecl( if (isTimeValueDateDeclaration(lowerer, decl)) { const loc = locOf(decl); const date = lowerer.lowerExprExpecting(decl.initializer!, DATE_T); - const local = lowerer.declareLocal(decl.name, decl.name.text, F64, isLet); + const local = lowerer.declareLocal( + decl.name, + decl.name.text, + F64, + isLet || lowerer.timeValueDateWrites.has(decl), + ); lowerer.timeValueDateLocals.add(local); const init: IrExpr = { kind: "libCall", fn: "date.getTime", args: [date], type: F64, loc }; return { kind: "varDecl", localId: local.id, init, loc }; diff --git a/packages/compiler/src/frontend/lowering/lowerer.test.ts b/packages/compiler/src/frontend/lowering/lowerer.test.ts index 7fbb9661f..f36695234 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.test.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.test.ts @@ -239,7 +239,7 @@ test("optional union widening keeps refused and missing contracts current", () = unionId: lowerer.unions.recursiveRef(recursive, () => "Recursive"), }; expect(lowerer.withUndefinedArmOf(pending)).not.toBeNull(); - lowerer.unions.finalizeRecursive(recursive, [{ kind: "date" }, STRING]); + lowerer.unions.finalizeRecursive(recursive, [{ kind: "promise", inner: F64 }, STRING]); expect(lowerer.withUndefinedArmOf(pending)).toBeNull(); expect(lowerer.withUndefinedArmOf(pending)).toBeNull(); diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 2fcfc063b..bdb7ce6c1 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -2362,6 +2362,9 @@ export class Lowerer { * Date's time value instead of a Date object (date-values.ts). */ readonly timeValueDateDecisions = new Map(); readonly timeValueDateLocals = new Set(); + /** Declarations of those locals that a setter call writes + * (date-values.ts). */ + readonly timeValueDateWrites = new Set(); /** Record bindings whose flow class reaches storage outside the class: * they keep the declared layout, so an initializer from unchecked reads * converts once instead of the binding adopting the widened variant. */ diff --git a/packages/compiler/src/frontend/lowering/surfaces.ts b/packages/compiler/src/frontend/lowering/surfaces.ts index d133eeb43..a2ca2cd1c 100644 --- a/packages/compiler/src/frontend/lowering/surfaces.ts +++ b/packages/compiler/src/frontend/lowering/surfaces.ts @@ -2329,6 +2329,13 @@ export const AMBIENT_SURFACE_FNS: readonly AmbientSurfaceRow[] = [ ], note: "zero arguments, one milliseconds/date-string argument, or local-time year/month fields; values are the read-only TimeClip scalar slice", }, + { + id: "stdlib.date.setters", + kind: "stdlib", + name: "Date.prototype setters", + fns: ["date.setFields", "date.timeClip", "date.store"], + note: "setTime and the local and UTC field setters, with their optional arguments", + }, { id: "stdlib.date.UTC", kind: "stdlib", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 37d9769e0..aaa58c088 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -4858,6 +4858,15 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ * lib-call argument passes the time value itself, and any other use * creates the Date. */ "date.fromTime": { argTypes: [F64], result: DATE_T }, + /** Date.prototype's field setters over a time value + * (scr_date_set_fields): time value, setter code, argument count and four + * arguments; answers the new time value. */ + "date.setFields": { argTypes: [F64, F64, F64, F64, F64, F64, F64], result: F64 }, + /** TimeClip of a number (setTime's argument). */ + "date.timeClip": { argTypes: [F64], result: F64 }, + /** Stores a time value into a Date object and answers it (a setter's + * write). */ + "date.store": { argTypes: [DATE_T, F64], result: F64 }, /** Date.prototype.toString / toDateString / toTimeString and String(date): * V8's local-time formats with the host zone's long name, "Invalid Date" * for an invalid date. Owned (+1) string; never throws. */ diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index d910374fb..b2511f8a8 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -855,9 +855,8 @@ export function funcOf(params: IrType[], ret: IrType): IrType { * promises nullable-only; declared maybe-promise unions are admitted by * maybePromiseUnionArmsOk. */ export function unionContainerArmsOk(arms: IrType[]): boolean { - return ( - arms.every((a, i) => a.kind !== "promise" || arms.every((b, j) => j === i || isUnitType(b))) && - dateUnionArmsOk(arms) + return arms.every( + (a, i) => a.kind !== "promise" || arms.every((b, j) => j === i || isUnitType(b)), ); } @@ -868,13 +867,7 @@ export function unionContainerArmsOk(arms: IrType[]): boolean { * non-thenable path). Data arms must not be thenable; the type mapper * checks that against the checker types before minting such a union. */ export function maybePromiseUnionArmsOk(arms: IrType[]): boolean { - return arms.filter((a) => a.kind === "promise").length <= 1 && dateUnionArmsOk(arms); -} - -/** A Date arm has a union home beside undefined and null arms only: no - * narrowing contract tells it from other data arms yet. */ -function dateUnionArmsOk(arms: IrType[]): boolean { - return arms.every((a, i) => a.kind !== "date" || arms.every((b, j) => j === i || isUnitType(b))); + return arms.filter((a) => a.kind === "promise").length <= 1; } /** Canonical, injective text form of an IrType — the building block of diff --git a/packages/compiler/src/ir/validate.ts b/packages/compiler/src/ir/validate.ts index a694e8d2c..b1c571db2 100644 --- a/packages/compiler/src/ir/validate.ts +++ b/packages/compiler/src/ir/validate.ts @@ -55,7 +55,6 @@ import { typeEquals, typeKey, maybePromiseUnionArmsOk, - unionContainerArmsOk, VOID, } from "./ir.js"; import { DYN_CLASS_PROPERTIES, callSiteReturnType, classValueConstructor } from "./ir.js"; @@ -814,9 +813,6 @@ export function validateModule(mod: IrModule): IrValidationError[] { loc: noLoc, }); } - if (arm.kind === "date" && !unionContainerArmsOk(u.arms)) { - errors.push({ message: `union ${u.id}: date arm ${i} beside non-unit arms`, loc: noLoc }); - } if (arm.kind === "record" && !recordsById.has(arm.shapeId)) { errors.push({ message: `union ${u.id}: arm ${i} references undeclared shape "${arm.shapeId}"`, @@ -6334,15 +6330,10 @@ function validateFunction( } } else { // throw: any exception-representable payload (the throw - // statement's rule). Date cannot retain its object kind in the - // untyped exception cell. + // statement's rule). if (e.arg === null) { err("genResume throw with no payload", e.loc); - } else if ( - e.arg.type.kind === "void" || - e.arg.type.kind === "caught" || - e.arg.type.kind === "date" - ) { + } else if (e.arg.type.kind === "void" || e.arg.type.kind === "caught") { err(`genResume throw of a ${e.arg.type.kind} value`, e.loc); } } @@ -6783,11 +6774,7 @@ function validateFunction( checkExpr(s.value); // dyn throws are allowed: the dyn node rides the REF cell arm by // reference (the JS-lane `throw err` of a dyn argument). - if ( - s.value.type.kind === "void" || - s.value.type.kind === "caught" || - s.value.type.kind === "date" - ) { + if (s.value.type.kind === "void" || s.value.type.kind === "caught") { err(`throw of a ${s.value.type.kind} value`, s.loc); } break; diff --git a/packages/compiler/surface-manifest.json b/packages/compiler/surface-manifest.json index 75541b8e5..2a98957b2 100644 --- a/packages/compiler/surface-manifest.json +++ b/packages/compiler/surface-manifest.json @@ -4251,6 +4251,13 @@ "status": "static", "note": "one date string, using V8's date parser shared with new Date(dateString)" }, + { + "id": "stdlib.date.setters", + "kind": "stdlib", + "name": "Date.prototype setters", + "status": "static", + "note": "setTime and the local and UTC field setters, with their optional arguments" + }, { "id": "stdlib.date.toDateString", "kind": "stdlib", diff --git a/packages/compiler/test/ir.test.ts b/packages/compiler/test/ir.test.ts index 7f5e9f3c9..5d835ef8a 100644 --- a/packages/compiler/test/ir.test.ts +++ b/packages/compiler/test/ir.test.ts @@ -8,12 +8,10 @@ test("hand-built fib module validates", () => { expect(validateModule(fibModule)).toEqual([]); }); -test("validator rejects Date union arms beside other data arms", () => { - const bad = structuredClone(fibModule); - bad.unions = [{ id: "u-date", arms: [{ kind: "date" }, { kind: "string" }] }]; - expect(validateModule(bad).map((e) => e.message)).toContain( - "union u-date: date arm 0 beside non-unit arms", - ); +test("validator accepts Date union arms beside other arms", () => { + const mixed = structuredClone(fibModule); + mixed.unions = [{ id: "u-date", arms: [{ kind: "date" }, { kind: "string" }] }]; + expect(validateModule(mixed)).toEqual([]); const nullable = structuredClone(fibModule); nullable.unions = [{ id: "u-date", arms: [{ kind: "date" }, { kind: "undefinedT" }] }]; expect(validateModule(nullable)).toEqual([]); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8020-date-setters.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8020-date-setters.ts.json new file mode 100644 index 000000000..5b23d8ecd --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8020-date-setters.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8020-date-setters.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8021-date-coercions.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8021-date-coercions.ts.json new file mode 100644 index 000000000..176788025 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8021-date-coercions.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8021-date-coercions.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8022-date-unions.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8022-date-unions.ts.json new file mode 100644 index 000000000..ab8c55b7b --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8022-date-unions.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8022-date-unions.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8023-date-clone-throw.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8023-date-clone-throw.ts.json new file mode 100644 index 000000000..934d260d8 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8023-date-clone-throw.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8023-date-clone-throw.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8024-date-setters-dynamic.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8024-date-setters-dynamic.mjs.json new file mode 100644 index 000000000..505f6305d --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8024-date-setters-dynamic.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8024-date-setters-dynamic.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8025-date-subclass-setters.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8025-date-subclass-setters.ts.json new file mode 100644 index 000000000..f1c4d20e0 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8025-date-subclass-setters.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8025-date-subclass-setters.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8026-date-subclass-setters-dynamic.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8026-date-subclass-setters-dynamic.mjs.json new file mode 100644 index 000000000..8a0fe9b5a --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8026-date-subclass-setters-dynamic.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8026-date-subclass-setters-dynamic.mjs" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_lib.c b/packages/runtime/src/scr_lib.c index fb3524c81..69c19e1b7 100644 --- a/packages/runtime/src/scr_lib.c +++ b/packages/runtime/src/scr_lib.c @@ -11660,6 +11660,56 @@ double scr_date_new_local(double y, double mo, double d, return scr_date_from_local(scr_date_v8_make_day(y, mo, d), scr_date_v8_make_time(h, mi, s, ms)); } +/* Date.prototype's setters over a time value, as V8's builtins-date.cc + * computes them: the fields of `t` (local fields for the local setters) + * with the first `argc` of them replaced, in the order the setter names + * them, by `a`..`d`, through MakeDay/MakeTime/MakeDate, then UTC(t) for + * the local setters and TimeClip. An invalid `t` stays invalid, except + * that setFullYear and setUTCFullYear start from +0: January 1 of the + * epoch year at midnight (local midnight for setFullYear). Returns the new + * time value; the caller stores it into the Date. Never throws. */ +double scr_date_set_fields(double t, double setter_code, double argc_count, + double a, double b, double c, double d) { + int32_t setter = (int32_t)setter_code, argc = (int32_t)argc_count; + bool utc = (setter & SCR_DATE_SET_UTC) != 0; + int32_t field = setter & ~SCR_DATE_SET_UTC; + ScrDateParts p; + if (isnan(t)) { + if (field != SCR_DATE_SET_FULL_YEAR) return NAN; + p = (ScrDateParts){1970, 0, 1, 4, 0, 0, 0, 0, 0}; + } else if (utc) { + if (!scr_date_utc_parts(t, &p)) return NAN; + } else if (!scr_date_local_parts(t, &p)) { + return NAN; + } + double y = (double)p.year, mo = p.month, dt = p.date; + double h = p.hours, mi = p.minutes, s = p.seconds, ms = p.milliseconds; + double args[4] = {a, b, c, d}; + double *slots[7] = {&y, &mo, &dt, &h, &mi, &s, &ms}; + /* The first field each setter names, in slots' order. */ + int first; + switch (field) { + case SCR_DATE_SET_MILLISECONDS: first = 6; break; + case SCR_DATE_SET_SECONDS: first = 5; break; + case SCR_DATE_SET_MINUTES: first = 4; break; + case SCR_DATE_SET_HOURS: first = 3; break; + case SCR_DATE_SET_DATE: first = 2; break; + case SCR_DATE_SET_MONTH: first = 1; break; + case SCR_DATE_SET_FULL_YEAR: first = 0; break; + default: return NAN; + } + /* Each setter takes at most the fields from its own down to the next + * larger unit's end: setHours up to milliseconds, setMonth up to the + * date, setFullYear up to the date. */ + int last = first <= 2 ? 2 : 6; + for (int i = 0; i < argc && first + i <= last && i < 4; i++) *slots[first + i] = args[i]; + double day = scr_date_v8_make_day(y, mo, dt); + double time = scr_date_v8_make_time(h, mi, s, ms); + if (!utc) return scr_date_from_local(day, time); + if (!isfinite(day) || !isfinite(time)) return NAN; + return scr_date_new_ms(day * 86400000.0 + time); +} + /* ── V8's date-string parser, the fallback ───────────────────────────── * scr_date_parse answers the bounded grammars directly and asks * this parser only when they produce NaN. It follows V8's DateParser @@ -13203,6 +13253,27 @@ ScrDate *scr_dyn_native_date_check(const ScrDyn *value, const ScrDynPath *path) static const char scr_date_to_date_string_name[] = "toDateString"; static const char scr_date_to_time_string_name[] = "toTimeString"; +/* The field setters a checked-dynamic Date answers (scr_date_set_fields). */ +static const struct { + const char *name; + int code, max; +} scr_native_date_setters[] = { + {"setMilliseconds", SCR_DATE_SET_MILLISECONDS, 1}, + {"setSeconds", SCR_DATE_SET_SECONDS, 2}, + {"setMinutes", SCR_DATE_SET_MINUTES, 3}, + {"setHours", SCR_DATE_SET_HOURS, 4}, + {"setDate", SCR_DATE_SET_DATE, 1}, + {"setMonth", SCR_DATE_SET_MONTH, 2}, + {"setFullYear", SCR_DATE_SET_FULL_YEAR, 3}, + {"setUTCMilliseconds", SCR_DATE_SET_UTC | SCR_DATE_SET_MILLISECONDS, 1}, + {"setUTCSeconds", SCR_DATE_SET_UTC | SCR_DATE_SET_SECONDS, 2}, + {"setUTCMinutes", SCR_DATE_SET_UTC | SCR_DATE_SET_MINUTES, 3}, + {"setUTCHours", SCR_DATE_SET_UTC | SCR_DATE_SET_HOURS, 4}, + {"setUTCDate", SCR_DATE_SET_UTC | SCR_DATE_SET_DATE, 1}, + {"setUTCMonth", SCR_DATE_SET_UTC | SCR_DATE_SET_MONTH, 2}, + {"setUTCFullYear", SCR_DATE_SET_UTC | SCR_DATE_SET_FULL_YEAR, 3}, +}; + static ScrDyn *scr_native_date_invoke(void *ptr, ScrDyn *self, const char *method, ScrDyn *const *args, size_t argc, const char *what) { (void)self; (void)what; @@ -13232,6 +13303,25 @@ static ScrDyn *scr_native_date_invoke(void *ptr, ScrDyn *self, const char *metho ((ScrDate *)ptr)->ms = scr_date_new_ms(time); return scr_dyn_new_num(((ScrDate *)ptr)->ms); } + for (size_t i = 0; i < sizeof scr_native_date_setters / sizeof *scr_native_date_setters; i++) { + if (strcmp(method, scr_native_date_setters[i].name)) continue; + /* V8's order: ToNumber of the first argument, then the time value, + * then (unless the date is invalid) ToNumber of the optional ones the + * setter takes. */ + int code = scr_native_date_setters[i].code, max = scr_native_date_setters[i].max; + double values[4] = {NAN, 0, 0, 0}; + if (argc > 0 && !scr_dyn_number_coerce_js(args[0], &values[0])) return NULL; + double t = ((ScrDate *)ptr)->ms; + int used = argc < (size_t)max ? (int)argc : max; + if (used < 1) used = 1; + if (!isnan(t) || (code & ~SCR_DATE_SET_UTC) == SCR_DATE_SET_FULL_YEAR) { + for (int k = 1; k < used; k++) + if (!scr_dyn_number_coerce_js(args[k], &values[k])) return NULL; + } + double next = scr_date_set_fields(t, code, used, values[0], values[1], values[2], values[3]); + ((ScrDate *)ptr)->ms = next; + return scr_dyn_new_num(next); + } #define DATE_GET(name, fn) if (!strcmp(method, name)) return scr_dyn_new_num(fn(ms)) DATE_GET("getFullYear", scr_date_get_full_year_local); DATE_GET("getUTCFullYear", scr_date_get_full_year_utc); @@ -13311,7 +13401,9 @@ static const char *const scr_native_date_methods[] = { "getFullYear", "getUTCFullYear", "getMonth", "getUTCMonth", "getDate", "getUTCDate", "getDay", "getUTCDay", "getHours", "getUTCHours", "getMinutes", "getUTCMinutes", "getSeconds", "getUTCSeconds", "getMilliseconds", - "getUTCMilliseconds", "getTimezoneOffset", "setTime", + "getUTCMilliseconds", "getTimezoneOffset", "setTime", "setMilliseconds", "setSeconds", + "setMinutes", "setHours", "setDate", "setMonth", "setFullYear", "setUTCMilliseconds", + "setUTCSeconds", "setUTCMinutes", "setUTCHours", "setUTCDate", "setUTCMonth", "setUTCFullYear", }; #define SCR_NATIVE_DATE_METHODS (sizeof scr_native_date_methods / sizeof scr_native_date_methods[0]) static SCR_TL ScrDyn *scr_native_date_method_values[SCR_NATIVE_DATE_METHODS]; @@ -13397,12 +13489,40 @@ static ScrDyn *scr_native_date_get(void *ptr, const char *key, size_t key_len) { return NULL; } +/* structuredClone of a Date: a new Date with the same time value. */ +static ScrDyn *scr_native_date_clone(void *h) { + return scr_dyn_native_date_from_ms(((ScrDate *)h)->ms); +} + +/* A Date crossing threads (postMessage, workerData) carries its time value + * in a plain allocation any thread may read and free. */ +static void *scr_native_date_share(void *h) { + double *ms = malloc(sizeof *ms); + if (!ms) scr_trap("scriptc: out of memory\n"); + *ms = ((ScrDate *)h)->ms; + return ms; +} + +static ScrDyn *scr_native_date_adopt(void *payload) { + return scr_dyn_native_date_from_ms(*(double *)payload); +} + +static void scr_native_date_drop(void *payload) { free(payload); } + +static const ScrDynHandleTransfer scr_native_date_transfer = { + .share = scr_native_date_share, .adopt = scr_native_date_adopt, .drop = scr_native_date_drop}; + /* A checked-dynamic handle for the Date object `date` (borrowed; the * handle retains it), so the value stays the same object. */ ScrDyn *scr_dyn_native_date(ScrDate *date) { static const ScrDynHandleOps ops = { - "Date", &scr_date_retain_v, &scr_date_release_v, &scr_native_date_invoke, - &scr_native_date_get, NULL, NULL, NULL, + .cls = "Date", + .retain = &scr_date_retain_v, + .release = &scr_date_release_v, + .invoke = &scr_native_date_invoke, + .get = &scr_native_date_get, + .clone = &scr_native_date_clone, + .transfer = &scr_native_date_transfer, }; scr_dyn_handle_install(SCR_DYNH_DATE, &ops); return scr_dyn_new_handle(date, SCR_DYNH_DATE); diff --git a/packages/runtime/src/scr_number.h b/packages/runtime/src/scr_number.h index a71b0ccfd..39564c061 100644 --- a/packages/runtime/src/scr_number.h +++ b/packages/runtime/src/scr_number.h @@ -111,6 +111,23 @@ double scr_date_now(void); /* integer ms since epoch, like Node */ extern SCR_TL const double *scr_date_mock_now; double scr_date_new_ms(double ms); /* TimeClip (NaN when invalid) */ double scr_date_get_time(double ms); +/* Date.prototype's setters (setMilliseconds ... setFullYear and their UTC + * forms) over a time value: the new time value for `argc` arguments + * `a`..`d` (scr_lib.c). `setter` is an SCR_DATE_SET_* code; it and `argc` + * are whole numbers passed as doubles, as the compiler's lib calls pass + * numbers. */ +enum { + SCR_DATE_SET_MILLISECONDS = 0, + SCR_DATE_SET_SECONDS = 1, + SCR_DATE_SET_MINUTES = 2, + SCR_DATE_SET_HOURS = 3, + SCR_DATE_SET_DATE = 4, + SCR_DATE_SET_MONTH = 5, + SCR_DATE_SET_FULL_YEAR = 6, + SCR_DATE_SET_UTC = 8, +}; +double scr_date_set_fields(double t, double setter, double argc, + double a, double b, double c, double d); /* A Date object: the TimeClip'd time value in milliseconds (NaN for an * invalid date). Dates are immutable; their identity is the pointer. * Retain/release follow the runtime's RC conventions (SIZE_MAX immortal). */ diff --git a/tests/corpus/8020-date-setters.ts b/tests/corpus/8020-date-setters.ts new file mode 100644 index 000000000..6bfeff5c8 --- /dev/null +++ b/tests/corpus/8020-date-setters.ts @@ -0,0 +1,115 @@ +// Date setters: every local and UTC setter with each argument count, the +// time values they return, normalization of out-of-range fields, local +// setters across a daylight saving transition, setters on invalid dates, +// explicit undefined arguments, fractional arguments, and the TimeClip +// range. A setter changes the one Date object every alias holds. +export {}; +process.env.TZ = "America/Chicago"; + +const show = (label: string, d: Date): void => { + console.log(label, d.getTime(), Number.isNaN(d.getTime()) ? "invalid" : d.toISOString()); +}; + +const d = new Date(Date.UTC(2026, 0, 31, 10, 20, 30, 400)); +console.log(d.setMilliseconds(999), d.getMilliseconds()); +console.log(d.setSeconds(5), d.setSeconds(6, 7)); +console.log(d.setMinutes(1), d.setMinutes(2, 3), d.setMinutes(4, 5, 6)); +console.log(d.setHours(7), d.setHours(8, 9), d.setHours(10, 11, 12), d.setHours(13, 14, 15, 16)); +console.log(d.setDate(15), d.setMonth(1), d.setMonth(2, 3)); +console.log(d.setFullYear(2025), d.setFullYear(2024, 1), d.setFullYear(2023, 4, 6)); +show("local", d); + +const u = new Date(Date.UTC(2026, 0, 31)); +console.log(u.setUTCMilliseconds(1), u.setUTCSeconds(2, 3), u.setUTCMinutes(4, 5, 6)); +console.log(u.setUTCHours(7, 8, 9, 10), u.setUTCDate(1), u.setUTCMonth(5, 30)); +console.log(u.setUTCFullYear(1999), u.setUTCFullYear(2000, 1, 29)); +show("utc", u); + +// Fields out of range carry into the next larger field, both ways. +const n = new Date(Date.UTC(2026, 0, 31, 12)); +n.setUTCMonth(1); +show("Jan 31 + month", n); +n.setUTCDate(0); +show("day 0", n); +n.setUTCMonth(13); +show("month 13", n); +n.setUTCHours(-1); +show("hour -1", n); +n.setUTCMinutes(60 * 24 + 1); +show("minutes past a day", n); +n.setUTCSeconds(-0.5); +show("fractional seconds", n); +n.setUTCMilliseconds(1.9); +show("fractional ms", n); + +// Local setters in a zone with daylight saving time: 2026-03-08 02:30 +// does not exist in Chicago and 2026-11-01 01:30 happens twice. +const spring = new Date(2026, 2, 8, 0, 0); +spring.setHours(2, 30); +show("spring gap", spring); +console.log(spring.getHours(), spring.getMinutes(), spring.getTimezoneOffset()); +const fall = new Date(2026, 10, 1, 0, 0); +fall.setHours(1, 30); +show("fall overlap", fall); +fall.setMinutes(fall.getMinutes() + 60); +show("fall overlap + 60 min", fall); +const walk = new Date(2026, 2, 7, 12); +for (let i = 0; i < 3; i++) { + walk.setDate(walk.getDate() + 1); + console.log("walk", walk.getDate(), walk.getHours(), walk.getTimezoneOffset()); +} + +// Invalid dates: setFullYear starts from +0 local time, the others keep NaN. +const bad = new Date(NaN); +console.log(bad.setHours(1), bad.setDate(2), bad.setUTCMonth(3), bad.setMilliseconds(4)); +console.log(bad.setFullYear(2020)); +show("after setFullYear", bad); +const badUtc = new Date("not a date"); +console.log(badUtc.setUTCFullYear(2021, 6)); +show("after setUTCFullYear", badUtc); + +// Explicit undefined and NaN arguments make the date invalid; a missing +// optional argument keeps the current field. +const opt = new Date(Date.UTC(2026, 5, 15, 9)); +console.log(opt.setUTCHours(10, undefined), Number.isNaN(opt.getTime())); +const opt2 = new Date(Date.UTC(2026, 5, 15, 9)); +console.log(opt2.setUTCMonth(Number.NaN), opt2.setUTCMonth(2)); + +// setTime and the TimeClip range. +const t = new Date(0); +console.log(t.setTime(8.64e15), t.setTime(8.64e15 + 1), t.setTime(-8.64e15), t.setTime(1.5)); +console.log(t.setTime(-0), Object.is(t.getTime(), 0), t.setTime(Number.NaN)); +const far = new Date(Date.UTC(275760, 8, 13)); +console.log(far.getTime(), far.setUTCMilliseconds(1)); + +// Every alias sees the change: a second binding, an array slot, a Map +// value, a record field, a closure and a parameter. +const shared = new Date(Date.UTC(2026, 6, 4)); +const alias = shared; +const list = [shared, new Date(Date.UTC(2000, 0, 1))]; +const byName = new Map([["shared", shared]]); +const holder = { when: shared }; +const bump = (): number => shared.setUTCDate(shared.getUTCDate() + 1); +const nextYear = (date: Date): void => { + date.setUTCFullYear(date.getUTCFullYear() + 1); +}; +alias.setUTCHours(6); +list[0]!.setUTCMinutes(30); +byName.get("shared")!.setUTCSeconds(15); +holder.when.setUTCMilliseconds(250); +bump(); +nextYear(shared); +show("shared", shared); +console.log(alias === shared, list[0] === shared, byName.get("shared") === holder.when); +console.log(list.map((x) => x.toISOString()).join(" ")); + +// A Date a loop adjusts in place. +const cursor = new Date(Date.UTC(2026, 0, 1)); +let weekdays = 0; +while (cursor.getUTCFullYear() === 2026) { + const day = cursor.getUTCDay(); + if (day !== 0 && day !== 6) weekdays++; + cursor.setUTCDate(cursor.getUTCDate() + 1); +} +console.log("weekdays in 2026", weekdays); +show("cursor", cursor); diff --git a/tests/corpus/8021-date-coercions.ts b/tests/corpus/8021-date-coercions.ts new file mode 100644 index 000000000..2410853a4 --- /dev/null +++ b/tests/corpus/8021-date-coercions.ts @@ -0,0 +1,47 @@ +// Dates converted to primitives as Node converts them: unary +, Number() +// and relational operators read the time value (the number hint), while + +// with a string, template literals and String() read the text (a Date's +// default hint is a string). Symbol.toPrimitive, valueOf and toString answer +// the same values; == compares two Dates by identity and a Date with a +// primitive through its default primitive. typeof, truthiness and +// instanceof treat a Date as an object, invalid ones included. +export {}; +process.env.TZ = "UTC"; + +const a = new Date(Date.UTC(2026, 9, 23, 8, 30)); +const b = new Date(Date.UTC(2026, 9, 24, 8, 30)); +const bad = new Date(Number.NaN); + +console.log(+a, -a, +b - +a, (+b - +a) / 3600000, Number(a), Math.max(+a, +b) === b.getTime()); +console.log(a + "!"); +console.log(`at ${a}`); +console.log(String(b)); +console.log("" + a === a.toString(), a + "1" === a.toString() + "1"); +console.log(a[Symbol.toPrimitive]("number"), a[Symbol.toPrimitive]("string") === a.toString()); +console.log(a[Symbol.toPrimitive]("default") === a.toString(), a.valueOf() === a.getTime()); +console.log(a < b, a <= b, a > b, a >= b, +b > a.getTime() + 1); + +const same = a; +const twin = new Date(a.getTime()); +console.log(a == same, a == twin, a === twin, a != twin, a.getTime() === twin.getTime()); +console.log(a == (a.toString() as unknown), a == (a.getTime() as unknown)); + +console.log(typeof a, typeof bad, a instanceof Date, bad instanceof Date); +console.log(Object.prototype.toString.call(a), !a, !!bad, bad ? "truthy" : "falsy"); + +// Invalid dates. +console.log(+bad, +bad - +a, `${bad}`, String(bad), bad + "", Number.isNaN(bad.getTime())); +console.log(bad.toJSON(), JSON.stringify({ when: bad, at: a })); +try { + bad.toISOString(); +} catch (error) { + console.log((error as Error).name, (error as Error).message); +} + +// Sorting and summing through the number hint. +const days = [b, a, new Date(Date.UTC(2026, 0, 1))]; +days.sort((x, y) => +x - +y); +console.log(days.map((x) => x.getUTCDate()).join(",")); +let span = 0; +for (let i = 1; i < days.length; i++) span += +days[i]! - +days[i - 1]!; +console.log(span / 86400000); diff --git a/tests/corpus/8022-date-unions.ts b/tests/corpus/8022-date-unions.ts new file mode 100644 index 000000000..dedcd8bf1 --- /dev/null +++ b/tests/corpus/8022-date-unions.ts @@ -0,0 +1,68 @@ +// Dates in unions with other arms: Date | string, Date | number and +// Date | a record, narrowed with instanceof and typeof, in arrays, Map +// values, optional fields and function results. A Date arm keeps its +// identity, so a setter through a union-typed alias changes the original. +export {}; +process.env.TZ = "UTC"; + +type When = Date | string | number; + +function describe(when: When): string { + if (when instanceof Date) return `date ${when.toISOString()}`; + if (typeof when === "string") return `text ${when}`; + return `ms ${when}`; +} + +function normalize(when: When): Date { + return when instanceof Date ? when : new Date(when); +} + +const fixed = new Date(Date.UTC(2026, 9, 23)); +const values: When[] = [fixed, "2026-01-02T03:04:05Z", 0, new Date(Number.NaN)]; +for (const value of values) { + const text = value instanceof Date && Number.isNaN(value.getTime()) ? "invalid" : describe(value); + console.log(text); +} +console.log(normalize(fixed) === fixed, normalize("2000-01-01").getUTCFullYear(), normalize(1e12).getUTCFullYear()); + +const held: When = fixed; +if (held instanceof Date) held.setUTCHours(12); +console.log(fixed.getUTCHours(), held === fixed); + +type Stamp = Date | { label: string; at: number }; +const stamps: Stamp[] = [fixed, { label: "start", at: 5 }]; +for (const stamp of stamps) { + console.log(stamp instanceof Date ? stamp.getUTCDate() : `${stamp.label}@${stamp.at}`); +} + +const byKey = new Map(); +byKey.set("a", fixed); +byKey.set("b", "later"); +for (const [key, value] of byKey) console.log(key, value instanceof Date ? value.getTime() : value); + +interface Task { + name: string; + due?: Date; + done: Date | null; +} +const tasks: Task[] = [ + { name: "write", due: fixed, done: null }, + { name: "ship", done: new Date(Date.UTC(2026, 11, 1)) }, +]; +for (const task of tasks) { + const due = task.due ? task.due.toISOString().slice(0, 10) : "none"; + const done = task.done === null ? "open" : task.done.toISOString().slice(0, 10); + console.log(task.name, due, done); +} +tasks[0]!.due!.setUTCDate(30); +console.log(fixed.getUTCDate(), tasks[0]!.due === fixed); + +function latest(dates: (Date | undefined)[]): Date | string { + let best: Date | undefined; + for (const date of dates) if (date && (best === undefined || date > best)) best = date; + return best ?? "none"; +} +const found = latest([undefined, fixed, new Date(0)]); +console.log(found === fixed, latest([])); + +console.log(JSON.stringify({ values, stamps })); diff --git a/tests/corpus/8023-date-clone-throw.ts b/tests/corpus/8023-date-clone-throw.ts new file mode 100644 index 000000000..b9d569d00 --- /dev/null +++ b/tests/corpus/8023-date-clone-throw.ts @@ -0,0 +1,32 @@ +// Dates through structuredClone and MessageChannel, which copy them as +// new Dates with the same time value, and Dates thrown and rejected as +// values, which keep their identity. +import { MessageChannel } from "node:worker_threads"; +process.env.TZ = "UTC"; + +const at = new Date(Date.UTC(2026, 9, 23, 7)); +const copy = structuredClone(at); +console.log(copy instanceof Date, copy === at, copy.getTime() === at.getTime()); +copy.setUTCFullYear(2000); +console.log(at.getUTCFullYear(), copy.getUTCFullYear()); + +const nested = structuredClone({ at, list: [at, at], invalid: new Date(Number.NaN) }); +console.log(nested.list[0] instanceof Date, nested.at === at, nested.list.length); +console.log(nested.at.toISOString(), Number.isNaN(nested.invalid.getTime())); + +try { + throw at; +} catch (error) { + console.log(error instanceof Date, error === at); +} + +const { port1, port2 } = new MessageChannel(); +port2.on("message", (data: { when: Date; again: Date }) => { + const { when, again } = data; + console.log("message", when instanceof Date, when === at, again instanceof Date, when.toISOString()); + port2.close(); + Promise.reject(at).catch((reason: unknown) => { + console.log("rejected", reason instanceof Date, reason === at); + }); +}); +port1.postMessage({ when: at, again: at }); diff --git a/tests/corpus/8024-date-setters-dynamic.mjs b/tests/corpus/8024-date-setters-dynamic.mjs new file mode 100644 index 000000000..9b6392b60 --- /dev/null +++ b/tests/corpus/8024-date-setters-dynamic.mjs @@ -0,0 +1,24 @@ +// Date setters in JavaScript, on Dates held as untyped values: each setter +// converts its arguments with ToNumber (valueOf runs, undefined is NaN) and +// changes the one Date object every alias holds. +process.env.TZ = "Europe/Berlin"; + +const d = new Date(Date.UTC(2026, 2, 28, 12)); +const alias = d; +const box = { d }; +console.log(d.setHours(1, 30), d.getHours(), d.getTimezoneOffset()); +console.log(alias.setDate(29), box.d.getHours(), d.getTimezoneOffset()); +console.log(d.setMinutes("15"), d.setSeconds(true), d.setMilliseconds(null)); +console.log(d.setUTCFullYear(2030, 11, 31), d.toISOString()); +console.log(d.setMonth(undefined), Number.isNaN(d.getTime())); +console.log(d.setFullYear(2001), d.toISOString()); + +let calls = 0; +const later = { valueOf() { calls++; return 45; } }; +console.log(d.setUTCMinutes(later, later), calls, d.toISOString()); + +const other = new Date(0); +console.log(other.setHours(5), other.getHours(), typeof d.setMonth); +const list = [new Date(0), new Date(86400000)]; +list.forEach((x, i) => x.setUTCHours(i + 1)); +console.log(list.map((x) => x.toISOString()).join(" ")); diff --git a/tests/corpus/8025-date-subclass-setters.ts b/tests/corpus/8025-date-subclass-setters.ts new file mode 100644 index 000000000..a6414a047 --- /dev/null +++ b/tests/corpus/8025-date-subclass-setters.ts @@ -0,0 +1,30 @@ +// Setters on instances of a class declared `extends Date`: each changes +// the instance's time value, which the inherited getters, the subclass's +// own methods and toISOString then read; invalid instances follow the same +// rules as Dates. +export {}; +process.env.TZ = "Asia/Kolkata"; + +class Deadline extends Date { + label: string; + constructor(label: string, ms: number) { + super(ms); + this.label = label; + } + extend(days: number): this { + this.setDate(this.getDate() + days); + return this; + } + describe(): string { + return `${this.label} ${this.toISOString()}`; + } +} + +const due = new Deadline("report", Date.UTC(2026, 9, 23, 18, 30)); +console.log(due.describe()); +console.log(due.setHours(9, 15), due.getHours(), due.getMinutes()); +console.log(due.extend(10).describe()); +console.log(due.setUTCMonth(0, 31), due.setMonth(1), due.getDate(), due.getMonth()); +console.log(due.setFullYear(2024, 1, 29), due.describe()); +console.log(due.setTime(Number.NaN), Number.isNaN(due.getTime()), due.setUTCFullYear(2030)); +console.log(due.describe(), due instanceof Date, due instanceof Deadline); diff --git a/tests/corpus/8026-date-subclass-setters-dynamic.mjs b/tests/corpus/8026-date-subclass-setters-dynamic.mjs new file mode 100644 index 000000000..8b89d6ec8 --- /dev/null +++ b/tests/corpus/8026-date-subclass-setters-dynamic.mjs @@ -0,0 +1,17 @@ +// Setters on instances of a JavaScript class declared `extends Date`, held +// as untyped values: the inherited setters change the instance's time value. +process.env.TZ = "America/Sao_Paulo"; + +class Shift extends Date { + start() { + this.setHours(8, 0, 0, 0); + return this; + } +} + +const shift = new Shift(Date.UTC(2026, 4, 5, 15)); +console.log(shift.start().toISOString(), shift.getHours()); +console.log(shift.setDate(31), shift.getMonth(), shift.setUTCHours(0), shift.toISOString()); +const values = [shift, new Shift(0)]; +for (const value of values) value.setUTCMinutes(45); +console.log(values.map((value) => value.toISOString()).join(" "), values[0] === shift); diff --git a/tests/diagnostics/stdlib-fence.ts b/tests/diagnostics/stdlib-fence.ts index d28333178..0952436e1 100644 --- a/tests/diagnostics/stdlib-fence.ts +++ b/tests/diagnostics/stdlib-fence.ts @@ -21,8 +21,6 @@ const fmt = new Intl.NumberFormat(); // Constructors. const d = new Date(...([2024, 0] as const)); // spread field arguments stay fenced -const mutableDate = new Date(0); -mutableDate.setUTCFullYear(2024); // mutation is outside the read-only Date slice const wr = new WeakRef({}); const px = new Proxy({ a: 1 }, {}); const buf = new ArrayBuffer(8); @@ -73,14 +71,6 @@ function pick(a: string | number, b: number | boolean): boolean { } const picked = pick(1, 2); -function throwDate(): void { - throw new Date(0); // the exception cell cannot preserve Date's object kind -} -throwDate(); -function* dateGenerator(): Generator { - yield 1; -} -dateGenerator().throw(new Date(0)); // Related classes may store one object under different union tags. A // structural arm beside them leaves no identity-preserving comparison. class FenceBase { diff --git a/tests/harness/__snapshots__/assert-class-fences.ts.txt b/tests/harness/__snapshots__/assert-class-fences.ts.txt index 29d2e4668..f70683e22 100644 --- a/tests/harness/__snapshots__/assert-class-fences.ts.txt +++ b/tests/harness/__snapshots__/assert-class-fences.ts.txt @@ -16,7 +16,7 @@ assert-class-fences.ts:12:16 - error SC2020: 'assert.Assert instances used as va hint: bind `new Assert(...)` with literal options to a const and only call methods on it (`const a = new Assert({ diff: 'full' }); a.strictEqual(x, y)`) -assert-class-fences.ts:13:22 - error SC2001: values of type 'object | Assert' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, read-only Date values, functions, classes, records, unions of those, and 'unknown') +assert-class-fences.ts:13:22 - error SC2001: values of type 'object | Assert' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, Dates, functions, classes, records, unions of those, and 'unknown') 12 | const passed = new Assert(); 13 | function useInstance(a: Assert | object): void { diff --git a/tests/harness/__snapshots__/class-interface-refinements.ts.txt b/tests/harness/__snapshots__/class-interface-refinements.ts.txt index 9d7d7b87f..89f3ead6d 100644 --- a/tests/harness/__snapshots__/class-interface-refinements.ts.txt +++ b/tests/harness/__snapshots__/class-interface-refinements.ts.txt @@ -7,7 +7,7 @@ class-interface-refinements.ts:8:26 - error SC2002: record shapes must match exa hint: width subtyping compiles as a copy (each expected field copied off the source; extra fields drop) — this pair is outside the copy's rules; build a literal with exactly the expected fields instead -class-interface-refinements.ts:12:16 - error SC2001: values of type 'AddedStorage' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, read-only Date values, functions, classes, records, unions of those, and 'unknown') +class-interface-refinements.ts:12:16 - error SC2001: values of type 'AddedStorage' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, Dates, functions, classes, records, unions of those, and 'unknown') 11 | interface AddedStorage extends Box { extra: string; } 12 | function added(view: AddedStorage): string { return view.extra; } @@ -23,7 +23,7 @@ class-interface-refinements.ts:13:13 - error SC2004: uses of 'added' inherit the hint: the declaration of 'added' did not compile — fix the diagnostic reported there and these sites clear with it -class-interface-refinements.ts:16:18 - error SC2001: values of type 'ChangedMethod' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, read-only Date values, functions, classes, records, unions of those, and 'unknown') +class-interface-refinements.ts:16:18 - error SC2001: values of type 'ChangedMethod' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, Dates, functions, classes, records, unions of those, and 'unknown') 15 | interface ChangedMethod extends Box { read(): number; } 16 | function changed(view: ChangedMethod): number { return view.read(); } diff --git a/tests/harness/__snapshots__/date-formatters.ts.txt b/tests/harness/__snapshots__/date-formatters.ts.txt index 75e15760b..d6dd27c5a 100644 --- a/tests/harness/__snapshots__/date-formatters.ts.txt +++ b/tests/harness/__snapshots__/date-formatters.ts.txt @@ -5,7 +5,7 @@ date-formatters.ts:4:1 - error SC2020: 'Date.prototype.toLocaleTimeString' is pa | ^~~~~~~~~~~~~~~~~~~~~~~~~ 5 | date.toLocaleString(); - hint: getTime(), valueOf(), toISOString(), toUTCString(), toJSON(), toString(), toDateString(), toTimeString(), the local/UTC calendar getters, and getTimezoneOffset() are supported; Date setters and locale formatters have no lowering + hint: getTime(), valueOf(), toISOString(), toUTCString(), toJSON(), toString(), toDateString(), toTimeString(), the local/UTC calendar getters and setters, setTime(), and getTimezoneOffset() are supported; locale formatters have no lowering date-formatters.ts:5:1 - error SC2020: 'Date.prototype.toLocaleString' is part of the standard library types but has no scriptc lowering yet @@ -14,4 +14,4 @@ date-formatters.ts:5:1 - error SC2020: 'Date.prototype.toLocaleString' is part o | ^~~~~~~~~~~~~~~~~~~~~ 6 | - hint: getTime(), valueOf(), toISOString(), toUTCString(), toJSON(), toString(), toDateString(), toTimeString(), the local/UTC calendar getters, and getTimezoneOffset() are supported; Date setters and locale formatters have no lowering \ No newline at end of file + hint: getTime(), valueOf(), toISOString(), toUTCString(), toJSON(), toString(), toDateString(), toTimeString(), the local/UTC calendar getters and setters, setTime(), and getTimezoneOffset() are supported; locale formatters have no lowering \ No newline at end of file diff --git a/tests/harness/__snapshots__/dynamic-representable-types.ts.txt b/tests/harness/__snapshots__/dynamic-representable-types.ts.txt index 21402b597..6241894f1 100644 --- a/tests/harness/__snapshots__/dynamic-representable-types.ts.txt +++ b/tests/harness/__snapshots__/dynamic-representable-types.ts.txt @@ -1,4 +1,4 @@ -dynamic-representable-types.ts:7:7 - error SC2001: values of type '[number, (string | undefined)?]' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, read-only Date values, functions, classes, records, unions of those, and 'unknown') +dynamic-representable-types.ts:7:7 - error SC2001: values of type '[number, (string | undefined)?]' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, Dates, functions, classes, records, unions of those, and 'unknown') 6 | const bare: any = 41; 7 | const optTuple: [number, string?] = [1]; diff --git a/tests/harness/__snapshots__/generics.ts.txt b/tests/harness/__snapshots__/generics.ts.txt index 4dfc8019f..86dd94bb9 100644 --- a/tests/harness/__snapshots__/generics.ts.txt +++ b/tests/harness/__snapshots__/generics.ts.txt @@ -12,7 +12,7 @@ generics.ts:30:10 - error SC1090: '.join()' on arrays of this element type (numb | ^~~~~~~~~~~ 31 | } -generics.ts:44:7 - error SC2001: values of type 'typeof Box' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, read-only Date values, functions, classes, records, unions of those, and 'unknown') +generics.ts:44:7 - error SC2001: values of type 'typeof Box' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, Dates, functions, classes, records, unions of those, and 'unknown') 43 | // The uninstantiated family as a value: no thunk, no single ctor ABI. 44 | const BoxAlias = Box; diff --git a/tests/harness/__snapshots__/maps-surface.ts.txt b/tests/harness/__snapshots__/maps-surface.ts.txt index c1db0576d..ed4ebb79f 100644 --- a/tests/harness/__snapshots__/maps-surface.ts.txt +++ b/tests/harness/__snapshots__/maps-surface.ts.txt @@ -1,4 +1,4 @@ -maps-surface.ts:21:11 - error SC2001: values of type '(v: number, k: string, theMap: Map) => void' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, read-only Date values, functions, classes, records, unions of those, and 'unknown') +maps-surface.ts:21:11 - error SC2001: values of type '(v: number, k: string, theMap: Map) => void' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, Dates, functions, classes, records, unions of those, and 'unknown') 20 | // The forEach callback receives (value, key) — no third map parameter. 21 | m.forEach((v, k, theMap) => console.log(k, v)); diff --git a/tests/harness/__snapshots__/regex-match-destructuring-fences.ts.txt b/tests/harness/__snapshots__/regex-match-destructuring-fences.ts.txt index d4eb59168..43d4eff77 100644 --- a/tests/harness/__snapshots__/regex-match-destructuring-fences.ts.txt +++ b/tests/harness/__snapshots__/regex-match-destructuring-fences.ts.txt @@ -5,7 +5,7 @@ regex-match-destructuring-fences.ts:6:16 - error SC1031: rest bindings over rege | ^~~~~~~ 7 | const { input = "none" } = m; -regex-match-destructuring-fences.ts:6:19 - error SC2001: values of type '{ [n: number]: string; input: string; 0: string; length: number; toString(): string; toLocaleString(): string; toLocaleString(locales: string | string[], options?: (NumberFormatOptions & DateTimeFormatOptions) | undefined): string; ... 39 more ...; with(index: number, value: string): string[]; }' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, read-only Date values, functions, classes, records, unions of those, and 'unknown') +regex-match-destructuring-fences.ts:6:19 - error SC2001: values of type '{ [n: number]: string; input: string; 0: string; length: number; toString(): string; toLocaleString(): string; toLocaleString(locales: string | string[], options?: (NumberFormatOptions & DateTimeFormatOptions) | undefined): string; ... 39 more ...; with(index: number, value: string): string[]; }' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, Dates, functions, classes, records, unions of those, and 'unknown') 5 | const m = /(a)(b)?/.exec("ab")!; 6 | const { index, ...rest } = m; diff --git a/tests/harness/__snapshots__/retired-engine-2103-optional-tuple-elements.ts.txt b/tests/harness/__snapshots__/retired-engine-2103-optional-tuple-elements.ts.txt index 4d3dd52c3..dfdb00720 100644 --- a/tests/harness/__snapshots__/retired-engine-2103-optional-tuple-elements.ts.txt +++ b/tests/harness/__snapshots__/retired-engine-2103-optional-tuple-elements.ts.txt @@ -43,7 +43,7 @@ retired-engine-2103-optional-tuple-elements.ts:19:1 - error SC2004: uses of 'f2' hint: the declaration of 'f2' did not compile — fix the diagnostic reported there and these sites clear with it -retired-engine-2103-optional-tuple-elements.ts:20:7 - error SC2001: values of type '[(string | undefined)?, (number | undefined)?]' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, read-only Date values, functions, classes, records, unions of those, and 'unknown') +retired-engine-2103-optional-tuple-elements.ts:20:7 - error SC2001: values of type '[(string | undefined)?, (number | undefined)?]' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, Dates, functions, classes, records, unions of those, and 'unknown') 19 | f2([]); 20 | const t: [string?, number?] = ["x"]; @@ -59,7 +59,7 @@ retired-engine-2103-optional-tuple-elements.ts:21:13 - error SC2004: uses of 't' hint: the declaration of 't' did not compile — fix the diagnostic reported there and these sites clear with it -retired-engine-2103-optional-tuple-elements.ts:22:7 - error SC2001: values of type '[(string | undefined)?, (number | undefined)?]' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, read-only Date values, functions, classes, records, unions of those, and 'unknown') +retired-engine-2103-optional-tuple-elements.ts:22:7 - error SC2001: values of type '[(string | undefined)?, (number | undefined)?]' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, Dates, functions, classes, records, unions of those, and 'unknown') 21 | console.log(t.length, `${t[0]} ${t[1]}`); 22 | const full: [string?, number?] = ["y", 7]; @@ -75,14 +75,14 @@ retired-engine-2103-optional-tuple-elements.ts:23:13 - error SC2004: uses of 'fu hint: the declaration of 'full' did not compile — fix the diagnostic reported there and these sites clear with it -retired-engine-2103-optional-tuple-elements.ts:24:7 - error SC2001: values of type '[(string | undefined)?, (number | undefined)?]' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, read-only Date values, functions, classes, records, unions of those, and 'unknown') +retired-engine-2103-optional-tuple-elements.ts:24:7 - error SC2001: values of type '[(string | undefined)?, (number | undefined)?]' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, Dates, functions, classes, records, unions of those, and 'unknown') 23 | console.log(full.length, `${full[0]} ${full[1]}`); 24 | const none: [string?, number?] = []; | ^~~~ 25 | console.log(none.length); -retired-engine-2103-optional-tuple-elements.ts:24:34 - error SC2001: values of type '[(string | undefined)?, (number | undefined)?]' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, read-only Date values, functions, classes, records, unions of those, and 'unknown') +retired-engine-2103-optional-tuple-elements.ts:24:34 - error SC2001: values of type '[(string | undefined)?, (number | undefined)?]' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, Dates, functions, classes, records, unions of those, and 'unknown') 23 | console.log(full.length, `${full[0]} ${full[1]}`); 24 | const none: [string?, number?] = []; @@ -98,7 +98,7 @@ retired-engine-2103-optional-tuple-elements.ts:25:13 - error SC2004: uses of 'no hint: the declaration of 'none' did not compile — fix the diagnostic reported there and these sites clear with it -retired-engine-2103-optional-tuple-elements.ts:27:7 - error SC2001: values of type '[string, ...number[]]' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, read-only Date values, functions, classes, records, unions of those, and 'unknown') +retired-engine-2103-optional-tuple-elements.ts:27:7 - error SC2001: values of type '[string, ...number[]]' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, Dates, functions, classes, records, unions of those, and 'unknown') 26 | // A rest-element tuple rides the same island representation. 27 | const r: [string, ...number[]] = ["head", 1, 2, 3]; diff --git a/tests/harness/__snapshots__/stdlib-fence.ts.txt b/tests/harness/__snapshots__/stdlib-fence.ts.txt index c183f7cdc..313a9391b 100644 --- a/tests/harness/__snapshots__/stdlib-fence.ts.txt +++ b/tests/harness/__snapshots__/stdlib-fence.ts.txt @@ -55,88 +55,65 @@ stdlib-fence.ts:23:11 - error SC2020: 'new Date with spread arguments' is part o 22 | // Constructors. 23 | const d = new Date(...([2024, 0] as const)); // spread field arguments stay fenced | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 24 | const mutableDate = new Date(0); + 24 | const wr = new WeakRef({}); hint: new Date(), new Date(milliseconds), new Date(dateString), and new Date(year, monthIndex, ...) with listed arguments are supported -stdlib-fence.ts:25:1 - error SC2020: 'Date.prototype.setUTCFullYear with arguments' is part of the standard library types but has no scriptc lowering yet +stdlib-fence.ts:24:7 - error SC2020: 'WeakRef<{}>' is part of the standard library types but has no scriptc lowering yet - 24 | const mutableDate = new Date(0); - 25 | mutableDate.setUTCFullYear(2024); // mutation is outside the read-only Date slice - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 26 | const wr = new WeakRef({}); - - hint: getTime(), valueOf(), toISOString(), toUTCString(), toJSON(), toString(), toDateString(), toTimeString(), the local/UTC calendar getters, and getTimezoneOffset() are supported; Date setters and locale formatters have no lowering - -stdlib-fence.ts:26:7 - error SC2020: 'WeakRef<{}>' is part of the standard library types but has no scriptc lowering yet - - 25 | mutableDate.setUTCFullYear(2024); // mutation is outside the read-only Date slice - 26 | const wr = new WeakRef({}); + 23 | const d = new Date(...([2024, 0] as const)); // spread field arguments stay fenced + 24 | const wr = new WeakRef({}); | ^~ - 27 | const px = new Proxy({ a: 1 }, {}); + 25 | const px = new Proxy({ a: 1 }, {}); hint: the type checker sees the full standard library, but only the supported surface compiles (https://scriptc.dev/limitations) -stdlib-fence.ts:26:12 - error SC2020: 'new WeakRef' is part of the standard library types but has no scriptc lowering yet +stdlib-fence.ts:24:12 - error SC2020: 'new WeakRef' is part of the standard library types but has no scriptc lowering yet - 25 | mutableDate.setUTCFullYear(2024); // mutation is outside the read-only Date slice - 26 | const wr = new WeakRef({}); + 23 | const d = new Date(...([2024, 0] as const)); // spread field arguments stay fenced + 24 | const wr = new WeakRef({}); | ^~~~~~~~~~~~~~~ - 27 | const px = new Proxy({ a: 1 }, {}); + 25 | const px = new Proxy({ a: 1 }, {}); hint: deref()-after-collect exposes GC timing — genuinely dynamic; hold a strong reference instead -stdlib-fence.ts:41:31 - error SC1090: '.split()' on a 'RegExp | string' separator (pass a string, or a regex literal) is not supported yet +stdlib-fence.ts:39:31 - error SC1090: '.split()' on a 'RegExp | string' separator (pass a string, or a regex literal) is not supported yet - 40 | const norm = "abc".normalize(); - 41 | const limited = "a,b,c".split(Math.random() ? "," : /,/, 2); // union separators stay fenced; limits lower + 38 | const norm = "abc".normalize(); + 39 | const limited = "a,b,c".split(Math.random() ? "," : /,/, 2); // union separators stay fenced; limits lower | ^~~~~~~~~~~~~~~~~~~~~~~~~ - 42 | const fixed = (1.5).toFixed(); // digit-free toFixed lowers now (the static ties-up integer) + 40 | const fixed = (1.5).toFixed(); // digit-free toFixed lowers now (the static ties-up integer) -stdlib-fence.ts:43:19 - error SC2020: 'Number.prototype.toLocaleString without a locale' is part of the standard library types but has no scriptc lowering yet +stdlib-fence.ts:41:19 - error SC2020: 'Number.prototype.toLocaleString without a locale' is part of the standard library types but has no scriptc lowering yet - 42 | const fixed = (1.5).toFixed(); // digit-free toFixed lowers now (the static ties-up integer) - 43 | const localized = (1234.5).toLocaleString(); + 40 | const fixed = (1.5).toFixed(); // digit-free toFixed lowers now (the static ties-up integer) + 41 | const localized = (1234.5).toLocaleString(); | ^~~~~~~~~~~~~~~~~~~~~~~~~ - 44 | // Unlowered call FORMS of lowered members. (push is fully variadic now — + 42 | // Unlowered call FORMS of lowered members. (push is fully variadic now — hint: the default locale is the host environment's, which a compiled binary cannot carry — pass it explicitly: x.toLocaleString("en-US") -stdlib-fence.ts:49:1 - error SC2020: '.forEach with 2 arguments' is part of the standard library types but has no scriptc lowering yet +stdlib-fence.ts:47:1 - error SC2020: '.forEach with 2 arguments' is part of the standard library types but has no scriptc lowering yet - 48 | const joined = nums.join(); // the omitted separator lowers - 49 | nums.forEach((x) => console.log(x), { unused: true }); // thisArg stays fenced + 46 | const joined = nums.join(); // the omitted separator lowers + 47 | nums.forEach((x) => console.log(x), { unused: true }); // thisArg stays fenced | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - 50 | const pos = "abc".includes("b", 1); // the position form lowers now (indexOf's clamp) + 48 | const pos = "abc".includes("b", 1); // the position form lowers now (indexOf's clamp) hint: the thisArg parameter has no lowering — use an arrow function -stdlib-fence.ts:77:9 - error SC1090: throwing Date values (catch bindings cannot preserve Date's object kind; throw an Error or primitive instead) are not supported yet +stdlib-fence.ts:84:10 - error SC1090: comparisons of related class values beside structural union members (narrow first: check a discriminant field, or compare with '!== undefined'/'!== null' for unit arms) are not supported yet - 76 | function throwDate(): void { - 77 | throw new Date(0); // the exception cell cannot preserve Date's object kind - | ^~~~~~~~~~~ - 78 | } - -stdlib-fence.ts:83:23 - error SC1090: .throw() with a Date value (the exception channel cannot preserve Date's object kind; throw an Error or primitive instead) is not supported yet - - 82 | } - 83 | dateGenerator().throw(new Date(0)); - | ^~~~~~~~~~~ - 84 | // Related classes may store one object under different union tags. A - -stdlib-fence.ts:94:10 - error SC1090: comparisons of related class values beside structural union members (narrow first: check a discriminant field, or compare with '!== undefined'/'!== null' for unit arms) are not supported yet - - 93 | function relatedStrict(a: FenceValue, b: FenceValue): boolean { - 94 | return a === b; + 83 | function relatedStrict(a: FenceValue, b: FenceValue): boolean { + 84 | return a === b; | ^~~~~~~ - 95 | } + 85 | } -stdlib-fence.ts:97:10 - error SC2020: 'Object.is over related class values beside structural union members' is part of the standard library types but has no scriptc lowering yet +stdlib-fence.ts:87:10 - error SC2020: 'Object.is over related class values beside structural union members' is part of the standard library types but has no scriptc lowering yet - 96 | function relatedSameValue(a: FenceValue, b: FenceSub): boolean { - 97 | return Object.is(a, b); + 86 | function relatedSameValue(a: FenceValue, b: FenceSub): boolean { + 87 | return Object.is(a, b); | ^~~~~~~~~~~~~~~ - 98 | } + 88 | } hint: narrow first: check a discriminant field, or compare with '!== undefined'/'!== null' for unit arms \ No newline at end of file diff --git a/tests/harness/__snapshots__/tuples.ts.txt b/tests/harness/__snapshots__/tuples.ts.txt index a6f58710e..440904095 100644 --- a/tests/harness/__snapshots__/tuples.ts.txt +++ b/tests/harness/__snapshots__/tuples.ts.txt @@ -12,14 +12,14 @@ tuples.ts:12:6 - error SC1090: tuple indexing with a non-literal index (tuples a | ^ 13 | -tuples.ts:15:7 - error SC2001: values of type '[string, (number | undefined)?]' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, read-only Date values, functions, classes, records, unions of those, and 'unknown') +tuples.ts:15:7 - error SC2001: values of type '[string, (number | undefined)?]' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, Dates, functions, classes, records, unions of those, and 'unknown') 14 | // Optional and rest elements have no fixed arity/shape. 15 | const opt: [string, number?] = ["x"]; | ^~~ 16 | const rest: [string, ...number[]] = ["y", 1, 2]; -tuples.ts:16:7 - error SC2001: values of type '[string, ...number[]]' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, read-only Date values, functions, classes, records, unions of those, and 'unknown') +tuples.ts:16:7 - error SC2001: values of type '[string, ...number[]]' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, Dates, functions, classes, records, unions of those, and 'unknown') 15 | const opt: [string, number?] = ["x"]; 16 | const rest: [string, ...number[]] = ["y", 1, 2]; diff --git a/tests/harness/__snapshots__/union-clone-override-width.ts.txt b/tests/harness/__snapshots__/union-clone-override-width.ts.txt index 6b5cc3566..8915968ef 100644 --- a/tests/harness/__snapshots__/union-clone-override-width.ts.txt +++ b/tests/harness/__snapshots__/union-clone-override-width.ts.txt @@ -1,4 +1,4 @@ -union-clone-override-width.ts:8:18 - error SC2001: values of type '{ kind: "left"; left: number; payload: WiderPayload; } | { kind: "right"; right: number; payload: WiderPayload; }' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, read-only Date values, functions, classes, records, unions of those, and 'unknown') +union-clone-override-width.ts:8:18 - error SC2001: values of type '{ kind: "left"; left: number; payload: WiderPayload; } | { kind: "right"; right: number; payload: WiderPayload; }' cannot be compiled yet (supported: number, string, boolean, arrays, Maps, Sets, RegExp, Dates, functions, classes, records, unions of those, and 'unknown') 7 | // copy its record. The inferred spread result keeps the wider payload. 8 | const result = { ...source, payload }; diff --git a/tests/harness/corpus-costs/8020-date-setters.ts.json b/tests/harness/corpus-costs/8020-date-setters.ts.json new file mode 100644 index 000000000..ad5d9a546 --- /dev/null +++ b/tests/harness/corpus-costs/8020-date-setters.ts.json @@ -0,0 +1 @@ +{ "plain": 2891, "san": 4454 } diff --git a/tests/harness/corpus-costs/8021-date-coercions.ts.json b/tests/harness/corpus-costs/8021-date-coercions.ts.json new file mode 100644 index 000000000..cd0090be6 --- /dev/null +++ b/tests/harness/corpus-costs/8021-date-coercions.ts.json @@ -0,0 +1 @@ +{ "plain": 2589, "san": 3385 } diff --git a/tests/harness/corpus-costs/8022-date-unions.ts.json b/tests/harness/corpus-costs/8022-date-unions.ts.json new file mode 100644 index 000000000..ce89111f9 --- /dev/null +++ b/tests/harness/corpus-costs/8022-date-unions.ts.json @@ -0,0 +1 @@ +{ "plain": 2786, "san": 3724 } diff --git a/tests/harness/corpus-costs/8023-date-clone-throw.ts.json b/tests/harness/corpus-costs/8023-date-clone-throw.ts.json new file mode 100644 index 000000000..50a23d33a --- /dev/null +++ b/tests/harness/corpus-costs/8023-date-clone-throw.ts.json @@ -0,0 +1 @@ +{ "plain": 2847, "san": 33492 } diff --git a/tests/harness/corpus-costs/8024-date-setters-dynamic.mjs.json b/tests/harness/corpus-costs/8024-date-setters-dynamic.mjs.json new file mode 100644 index 000000000..0007f1971 --- /dev/null +++ b/tests/harness/corpus-costs/8024-date-setters-dynamic.mjs.json @@ -0,0 +1 @@ +{ "plain": 2645, "san": 3529 } diff --git a/tests/harness/corpus-costs/8025-date-subclass-setters.ts.json b/tests/harness/corpus-costs/8025-date-subclass-setters.ts.json new file mode 100644 index 000000000..cb128790d --- /dev/null +++ b/tests/harness/corpus-costs/8025-date-subclass-setters.ts.json @@ -0,0 +1 @@ +{ "plain": 2383, "san": 3249 } diff --git a/tests/harness/corpus-costs/8026-date-subclass-setters-dynamic.mjs.json b/tests/harness/corpus-costs/8026-date-subclass-setters-dynamic.mjs.json new file mode 100644 index 000000000..0615e7224 --- /dev/null +++ b/tests/harness/corpus-costs/8026-date-subclass-setters-dynamic.mjs.json @@ -0,0 +1 @@ +{ "plain": 2483, "san": 3294 } From d68a7059758bf6e155dc9db2e2847afef836849a Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 22:31:08 -0500 Subject: [PATCH 046/259] Read a union's discriminant once in checked casts A checked cast into a union whose discriminant has four or more string literals reads the discriminant field once (scr_dyn_discriminant_case) and then tests only the arms whose literal it holds and the arms without a literal, in the union's arm order. Every other arm's literal test would fail, so the arm chosen and the error for a value no arm matches are unchanged. A typed capsule, an accessor or an inherited discriminant still takes the tests arm by arm. Unions with fewer literals emit the same code as before. --- benchmarks/runtime/README.md | 1 + benchmarks/runtime/workloads/json-unions.json | 6 + benchmarks/runtime/workloads/json-unions.ts | 155 +++++++++++++++++ packages/compiler/src/backend/llvm/dyn.ts | 160 ++++++++++++++++-- .../compiler/test/chunked-emission.test.ts | 8 +- .../6305-json-discriminant-dispatch.ts.json | 6 + packages/runtime/src/scr_dyn.h | 8 + packages/runtime/src/scr_json.c | 18 ++ .../corpus/6305-json-discriminant-dispatch.ts | 123 ++++++++++++++ .../6305-json-discriminant-dispatch.ts.json | 1 + tests/harness/dyncheck.test.ts | 48 ++++++ 11 files changed, 519 insertions(+), 15 deletions(-) create mode 100644 benchmarks/runtime/workloads/json-unions.json create mode 100644 benchmarks/runtime/workloads/json-unions.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6305-json-discriminant-dispatch.ts.json create mode 100644 tests/corpus/6305-json-discriminant-dispatch.ts create mode 100644 tests/harness/corpus-costs/6305-json-discriminant-dispatch.ts.json diff --git a/benchmarks/runtime/README.md b/benchmarks/runtime/README.md index 4f152e4bb..001880a38 100644 --- a/benchmarks/runtime/README.md +++ b/benchmarks/runtime/README.md @@ -16,6 +16,7 @@ Application-shaped workloads for measuring the speed of compiled executables. Ea | `functional-pipeline` | cpu | `filter`/`map`/`reduce`/`flatMap` chains, closures, small records | | `intern-table`, `intern-table-map`, `intern-table-1`, `intern-table-map-1` | cpu | worker threads interning the same type-like objects under string keys and records under number keys, then hits and misses: one shared `InternTable` per kind of key, or a module-level `Map` per thread (the `-map` entries), with 8 threads or 1 (the `-1` entries); under Node.js every thread has its own tables | | `json-records` | cpu | `JSON.stringify`, typed `JSON.parse`, Map aggregation | +| `json-unions` | cpu | `JSON.parse` into discriminated unions: an event log with eight kinds and nested expression trees with nine, evaluated after the cast | | `log-lines` | cpu | 200k immediate `console.log`/`process.stdout.write` lines into the runner's pipe | | `log-summary`, `inventory-report` | cpu | the multi-module applications from `benchmarks/builds`, on 300k-line inputs | | `number-maps` | cpu | number-keyed Map/Set: a dense-id table, sparse ids in many small maps, get/has/set mixes | diff --git a/benchmarks/runtime/workloads/json-unions.json b/benchmarks/runtime/workloads/json-unions.json new file mode 100644 index 000000000..925e8457b --- /dev/null +++ b/benchmarks/runtime/workloads/json-unions.json @@ -0,0 +1,6 @@ +{ + "entry": "workloads/json-unions.ts", + "args": [ + "6" + ] +} diff --git a/benchmarks/runtime/workloads/json-unions.ts b/benchmarks/runtime/workloads/json-unions.ts new file mode 100644 index 000000000..0f684c35f --- /dev/null +++ b/benchmarks/runtime/workloads/json-unions.ts @@ -0,0 +1,155 @@ +// JSON text parsed into discriminated unions: an event log with eight kinds +// of event and a nested expression tree with nine kinds of node, cast with +// `JSON.parse(text) as T`, then aggregated and evaluated. Argument: the +// number of rounds. +type Event = + | { kind: "click"; target: string; x: number; y: number } + | { key: string; kind: "key"; repeat: boolean } + | { kind: "scroll"; offset: number } + | { kind: "resize"; height: number; width: number } + | { kind: "focus"; target: string } + | { kind: "blur"; target: string } + | { kind: "load"; ms: number; url: string } + | { code: number; kind: "error"; message: string }; + +type Expr = + | { kind: "num"; value: number } + | { kind: "var"; name: string } + | { kind: "neg"; operand: Expr } + | { kind: "add"; left: Expr; right: Expr } + | { kind: "sub"; left: Expr; right: Expr } + | { kind: "mul"; left: Expr; right: Expr } + | { kind: "max"; items: Expr[] } + | { else: Expr; kind: "if"; test: Expr; then: Expr } + | { body: Expr; kind: "let"; name: string; value: Expr }; + +let seed = 12345; +function random(): number { + seed = (Math.imul(seed, 1103515245) + 12345) >>> 0; + return seed / 4294967296; +} + +const targets = ["menu", "search", "button", "list", "footer"]; +function eventText(i: number): string { + const target = targets[i % targets.length]!; + switch (i % 8) { + case 0: + return `{"kind":"click","target":"${target}","x":${i % 640},"y":${i % 480}}`; + case 1: + return `{"key":"k${i % 26}","kind":"key","repeat":${i % 3 === 0}}`; + case 2: + return `{"kind":"scroll","offset":${(i * 7) % 2000}}`; + case 3: + return `{"height":${400 + (i % 300)},"kind":"resize","width":${600 + (i % 500)}}`; + case 4: + return `{"kind":"focus","target":"${target}"}`; + case 5: + return `{"kind":"blur","target":"${target}"}`; + case 6: + return `{"kind":"load","ms":${i % 900},"url":"/page/${i % 50}"}`; + default: + return `{"code":${400 + (i % 100)},"kind":"error","message":"failed ${i % 13}"}`; + } +} + +const names = ["a", "b", "c", "d"]; +function exprText(depth: number): string { + const pick = depth <= 0 ? Math.floor(random() * 2) : Math.floor(random() * 9); + switch (pick) { + case 0: + return `{"kind":"num","value":${Math.floor(random() * 100)}}`; + case 1: + return `{"kind":"var","name":"${names[Math.floor(random() * names.length)]!}"}`; + case 2: + return `{"kind":"neg","operand":${exprText(depth - 1)}}`; + case 3: + case 4: + case 5: { + const kind = pick === 3 ? "add" : pick === 4 ? "sub" : "mul"; + return `{"kind":"${kind}","left":${exprText(depth - 1)},"right":${exprText(depth - 1)}}`; + } + case 6: + return `{"items":[${exprText(depth - 1)},${exprText(depth - 2)},${exprText(depth - 2)}],"kind":"max"}`; + case 7: + return `{"else":${exprText(depth - 2)},"kind":"if","test":${exprText(depth - 1)},"then":${exprText(depth - 2)}}`; + default: + return `{"body":${exprText(depth - 1)},"kind":"let","name":"${names[Math.floor(random() * names.length)]!}","value":${exprText(depth - 2)}}`; + } +} + +function evaluate(e: Expr, env: Map): number { + switch (e.kind) { + case "num": + return e.value; + case "var": + return env.get(e.name) ?? 1; + case "neg": + return -evaluate(e.operand, env); + case "add": + return (evaluate(e.left, env) + evaluate(e.right, env)) % 1000003; + case "sub": + return (evaluate(e.left, env) - evaluate(e.right, env)) % 1000003; + case "mul": + return (evaluate(e.left, env) * evaluate(e.right, env)) % 1000003; + case "max": { + let best = -Infinity; + for (const item of e.items) best = Math.max(best, evaluate(item, env)); + return best; + } + case "if": + return evaluate(e.test, env) > 0 ? evaluate(e.then, env) : evaluate(e.else, env); + case "let": { + const inner = new Map(env); + inner.set(e.name, evaluate(e.value, env)); + return evaluate(e.body, inner); + } + } +} + +const rounds = Number(process.argv[2] ?? "6"); +const eventsText = `[${Array.from({ length: 60000 }, (_, i) => eventText(i)).join(",")}]`; +const treesText = `[${Array.from({ length: 400 }, () => exprText(9)).join(",")}]`; +let clicks = 0; +let keys = 0; +let scrolled = 0; +let area = 0; +let loadMs = 0; +let errors = 0; +let focus = 0; +let total = 0; +for (let round = 0; round < rounds; round++) { + const events = JSON.parse(eventsText) as Event[]; + for (const event of events) { + switch (event.kind) { + case "click": + clicks += event.x + event.y; + break; + case "key": + if (event.repeat) keys++; + break; + case "scroll": + scrolled += event.offset; + break; + case "resize": + area += (event.width * event.height) % 1000; + break; + case "focus": + case "blur": + focus += event.target.length; + break; + case "load": + loadMs += event.ms; + break; + case "error": + errors += event.code % 7; + break; + } + } + const trees = JSON.parse(treesText) as Expr[]; + const env = new Map([ + ["a", 3], + ["b", 5], + ]); + for (const tree of trees) total = (total + evaluate(tree, env)) % 1000003; +} +console.log(clicks, keys, scrolled, area, loadMs, errors, focus, total); diff --git a/packages/compiler/src/backend/llvm/dyn.ts b/packages/compiler/src/backend/llvm/dyn.ts index d90239fc3..3d7533f22 100644 --- a/packages/compiler/src/backend/llvm/dyn.ts +++ b/packages/compiler/src/backend/llvm/dyn.ts @@ -193,6 +193,11 @@ function builtinStreamKind(className: string): number | null { return kinds[className] ?? null; } +/** Unions whose discriminant has fewer string literals keep one literal test + * per arm (dispatchValues): one runtime lookup costs about what a few + * literal tests do. */ +const DISCRIMINANT_DISPATCH_VALUES = 4; + export class LlDyn { private readonly dynMatchers = new Map(); private readonly dynBuilders = new Map(); @@ -413,6 +418,86 @@ export class LlDyn { return order; } + /** The string literals of `def`'s discriminant when its arms are chosen + * by reading the discriminant once (unionArmsByDiscriminant), or null + * when the union keeps one literal test per arm: some literal is not a + * string, or there are fewer than DISCRIMINANT_DISPATCH_VALUES. */ + private dispatchValues(def: IrUnionDef): string[] | null { + const values: string[] = []; + for (const guard of def.discriminant?.cases ?? []) { + if (guard.values.length === 0) return null; + for (const value of guard.values) { + if (typeof value !== "string") return null; + if (!values.includes(value)) values.push(value); + } + } + return values.length < DISCRIMINANT_DISPATCH_VALUES ? null : values; + } + + /** Branches to `hits[tag]` for the first arm in `order` that `%d` matches + * (unionArmMatch), or to `none` when no arm does, for + * a union whose discriminant literals are `values` (dispatchValues). The + * discriminant is read once (scr_dyn_discriminant_case, against the + * constant `table`), and only the arms whose literal it holds and the arms + * without a literal are tested, in `order`: every other arm's literal test + * fails. A value the runtime cannot classify that way (a typed capsule, an + * accessor, an inherited discriminant) takes the tests arm by arm. */ + private unionArmsByDiscriminant( + B: BlockBuilder, + def: IrUnionDef, + values: readonly string[], + order: readonly number[], + hits: readonly string[], + none: string, + preserveRefs: boolean, + table: string, + ): void { + const discriminant = def.discriminant!; + const literalsOf = (tag: number): readonly (string | number | boolean)[] | null => + discriminant.cases.find((candidate) => candidate.tag === tag)?.values ?? null; + const tryArms = (tags: readonly number[], literal: boolean): void => { + if (tags.length === 0) { + B.br(none); + return; + } + tags.forEach((tag, index) => { + const next = index === tags.length - 1 ? none : B.newLabel("du.c.n"); + if (literal) this.unionArmMatch(B, def, tag, hits[tag]!, next, preserveRefs); + else this.unionArmStructure(B, def, tag, hits[tag]!, next, preserveRefs); + if (next !== none) B.startBlock(next); + }); + }; + const armsFor = (value: string | null): number[] => + order.filter((tag) => { + const literals = literalsOf(tag); + return literals === null || (value !== null && literals.includes(value)); + }); + const host = this.host; + this.defs.push( + `${table} = private unnamed_addr constant [${values.length} x ptr] [${values.map((value) => `ptr ${host.internLiteral(value)}`).join(", ")}]`, + ``, + ); + host.declare(`declare i32 @scr_dyn_discriminant_case(ptr, ptr, ptr, ${host.sizeType})`); + const index = B.tmp(); + B.line( + `${index} = call i32 @scr_dyn_discriminant_case(ptr %d, ptr ${host.internLiteral(discriminant.field)}, ptr ${table}, ${host.sizeType} ${values.length})`, + ); + const tests = B.newLabel("du.tests"); + const unmatched = B.newLabel("du.none"); + const cases = values.map(() => B.newLabel("du.case")); + B.terminate( + `switch i32 ${index}, label %${tests} [ i32 -1, label %${unmatched} ${cases.map((label, k) => `i32 ${k}, label %${label}`).join(" ")} ]`, + ); + values.forEach((value, k) => { + B.startBlock(cases[k]!); + tryArms(armsFor(value), false); + }); + B.startBlock(unmatched); + tryArms(armsFor(null), false); + B.startBlock(tests); + tryArms(order, true); + } + /** Branch to a variant only after its literal discriminator and complete * structure match. Use the same path for predicates and builders. */ private unionArmMatch( @@ -450,6 +535,18 @@ export class LlDyn { }); B.startBlock(structure); } + this.unionArmStructure(B, def, tag, yes, no, preserveRefs); + } + + /** The part of unionArmMatch past the arm's literal test. */ + private unionArmStructure( + B: BlockBuilder, + def: IrUnionDef, + tag: number, + yes: string, + no: string, + preserveRefs: boolean, + ): void { const matches = B.tmp(); B.line( `${matches} = call zeroext i1 @${this.dynMatchHelper(def.arms[tag]!, preserveRefs)}(ptr %d)`, @@ -1275,11 +1372,26 @@ export class LlDyn { ); // Arms in canonical order; any full match answers true. const yes = B.newLabel("dm.y"); - for (let tag = 0; tag < def.arms.length; tag++) { - const ln = B.newLabel("dm.n"); - this.unionArmMatch(B, def, tag, yes, ln, preserveRefs); - B.startBlock(ln); - } + const values = this.dispatchValues(def); + if (values !== null) { + const no = B.newLabel("dm.n"); + this.unionArmsByDiscriminant( + B, + def, + values, + def.arms.map((_, tag) => tag), + def.arms.map(() => yes), + no, + preserveRefs, + `@${name}.cases`, + ); + B.startBlock(no); + } else + for (let tag = 0; tag < def.arms.length; tag++) { + const ln = B.newLabel("dm.n"); + this.unionArmMatch(B, def, tag, yes, ln, preserveRefs); + B.startBlock(ln); + } B.terminate(`ret i1 false`); B.startBlock(yes); B.terminate(`ret i1 true`); @@ -2459,12 +2571,8 @@ export class LlDyn { ); // Arms in unionArmOrder, first FULL match wins. The matched arm's // builder can no longer fail. - for (const i of this.unionArmOrder(def)) { + const build = (i: number): void => { const arm = def.arms[i]!; - const lHit = B.newLabel("dcu.h"); - const lNext = B.newLabel("dcu.n"); - this.unionArmMatch(B, def, i, lHit, lNext, preserveRefs); - B.startBlock(lHit); if (arm.kind === "undefinedT" || arm.kind === "nullT") { // A matched unit arm builds nothing: THE interned immortal // instance (rc == SIZE_MAX — no retain owed). @@ -2503,8 +2611,36 @@ export class LlDyn { ); B.terminate(`ret ptr ${u}`); } - B.startBlock(lNext); - } + }; + const order = this.unionArmOrder(def); + const values = this.dispatchValues(def); + if (values !== null) { + const hits = def.arms.map(() => B.newLabel("dcu.h")); + const unmatched = B.newLabel("dcu.n"); + this.unionArmsByDiscriminant( + B, + def, + values, + order, + hits, + unmatched, + preserveRefs, + `@${name}.cases`, + ); + for (const i of order) { + B.startBlock(hits[i]!); + build(i); + } + B.startBlock(unmatched); + } else + for (const i of order) { + const lHit = B.newLabel("dcu.h"); + const lNext = B.newLabel("dcu.n"); + this.unionArmMatch(B, def, i, lHit, lNext, preserveRefs); + B.startBlock(lHit); + build(i); + B.startBlock(lNext); + } if (preserveRefs) { B.line( `call void @scr_dyn_check_fail(ptr %path, ptr ${host.cstr("reference with its original layout")}, ptr %d)`, diff --git a/packages/compiler/test/chunked-emission.test.ts b/packages/compiler/test/chunked-emission.test.ts index b4912c9f6..2aec1e49b 100644 --- a/packages/compiler/test/chunked-emission.test.ts +++ b/packages/compiler/test/chunked-emission.test.ts @@ -9,9 +9,10 @@ import { inlineRcOption } from "../src/backend/llvm/shapes.js"; // Programs whose function bodies request module-level helpers and tables // that the chunk journal (emit-journal.ts) carries: checked-dynamic -// conversions, inspection, publication walkers, live record views, stream -// adapters, regex instances, colliding literal digests, interned C strings, -// speculative loop sites, typed message listeners and readers. +// conversions (with their discriminant tables), inspection, publication +// walkers, live record views, stream adapters, regex instances, colliding +// literal digests, interned C strings, speculative loop sites, typed message +// listeners and readers. const PROGRAMS = [ "1003-json-parse-unions.ts", "114-live-record-delete.ts", @@ -21,6 +22,7 @@ const PROGRAMS = [ "4900-console-instances.ts", "5612-readable-from-iterables.cjs", "5702-publish-candidate-buffers.ts", + "6305-json-discriminant-dispatch.ts", "7321-speculative-loop-bail-sites.ts", "7360-worker-typed-records.ts", "node24-text-utilities-coercion.js", diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6305-json-discriminant-dispatch.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6305-json-discriminant-dispatch.ts.json new file mode 100644 index 000000000..b83ada276 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6305-json-discriminant-dispatch.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6305-json-discriminant-dispatch.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index efb83d9fc..d46764d3d 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -677,6 +677,14 @@ void scr_dyn_copy_entry(ScrDyn *target, const ScrDyn *source, const ScrDynEntry bool scr_dyn_field_eq_str(const ScrDyn *d, const ScrStr *key, const ScrStr *value); bool scr_dyn_field_eq_num(const ScrDyn *d, const ScrStr *key, double value); bool scr_dyn_field_eq_bool(const ScrDyn *d, const ScrStr *key, bool value); +/* The case a union's checked match takes from its string discriminant: the + * index in `values` of the string `d`'s own data property `key` holds, or + * -1 when every literal test above fails (`d` is not an object, or its own + * data property `key` holds no string among `values`), or -2 when only the + * tests themselves can tell (a typed capsule, an accessor, or a property + * `d` does not own). Borrowed args. */ +int32_t scr_dyn_discriminant_case(const ScrDyn *d, const ScrStr *key, ScrStr *const *values, + size_t count); /* Object.keys/values/entries over the checked-dynamic tree: JS own-key order (array-index * keys ascending first), dyn-array results (+1); values/entries RETAIN diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 580b816c4..0ba6ec28d 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -1422,6 +1422,24 @@ bool scr_dyn_field_eq_num(const ScrDyn *d, const ScrStr *key, double value) { return matches; } +int32_t scr_dyn_discriminant_case(const ScrDyn *d, const ScrStr *key, ScrStr *const *values, + size_t count) { + if (!d) return -1; + if (d->kind == SCR_DYN_TYPED_REF) return -2; + if (d->kind != SCR_DYN_OBJ) return -1; + for (size_t i = 0; i < d->v.obj.len; i++) { + const ScrDynEntry *entry = &d->v.obj.entries[i]; + if (entry->key_len != key->len || memcmp(entry->key, key->data, key->len) != 0) continue; + if (entry->accessor) return -2; + const ScrDyn *member = entry->value; + if (!member || member->kind != SCR_DYN_STR) return -1; + for (size_t k = 0; k < count; k++) + if (scr_str_eq(member->v.str, values[k])) return (int32_t)k; + return -1; + } + return -2; +} + bool scr_dyn_field_eq_bool(const ScrDyn *d, const ScrStr *key, bool value) { ScrDyn *member = scr_dyn_discriminant(d, key); bool matches = member && member->kind == SCR_DYN_BOOL && member->v.b == value; diff --git a/tests/corpus/6305-json-discriminant-dispatch.ts b/tests/corpus/6305-json-discriminant-dispatch.ts new file mode 100644 index 000000000..ac4d992da --- /dev/null +++ b/tests/corpus/6305-json-discriminant-dispatch.ts @@ -0,0 +1,123 @@ +// JSON cast into a union with many string discriminant literals: the cast +// reads the discriminant once and tests only the arm whose literal it +// holds, plus the arms that are not records. An arm can list several +// literals, and values that are not objects reach the other arms in +// canonical order. Valid casts only (see 1002-json-parse-cast.ts); JSON keys +// and record fields alphabetical for stringify parity. + +type Expr = + | { kind: "num"; value: number } + | { kind: "str"; text: string } + | { kind: "neg"; operand: Expr } + | { kind: "add" | "mul"; left: Expr; right: Expr } + | { args: Expr[]; kind: "call"; name: string } + | { kind: "method"; name: string; target: Expr } + | { kind: "list"; items: Expr[] }; + +function show(e: Expr): string { + switch (e.kind) { + case "num": + return String(e.value); + case "str": + return JSON.stringify(e.text); + case "neg": + return `-(${show(e.operand)})`; + case "add": + return `(${show(e.left)} + ${show(e.right)})`; + case "mul": + return `(${show(e.left)} * ${show(e.right)})`; + case "call": + return `${e.name}(${e.args.map(show).join(", ")})`; + case "method": + return `${show(e.target)}.${e.name}()`; + case "list": + return `[${e.items.map(show).join(", ")}]`; + } +} + +function evaluate(e: Expr): number { + switch (e.kind) { + case "num": + return e.value; + case "str": + return e.text.length; + case "neg": + return -evaluate(e.operand); + case "add": + return evaluate(e.left) + evaluate(e.right); + case "mul": + return evaluate(e.left) * evaluate(e.right); + case "call": + return e.args.reduce((sum, arg) => sum + evaluate(arg), 0); + case "method": + return evaluate(e.target); + case "list": + return e.items.length; + } +} + +const source = + '{"kind":"add","left":{"kind":"mul","left":{"kind":"num","value":3},' + + '"right":{"kind":"neg","operand":{"kind":"num","value":4}}},' + + '"right":{"args":[{"kind":"str","text":"abc"},{"kind":"num","value":2}],"kind":"call","name":"sum"}}'; +const tree = JSON.parse(source) as Expr; +console.log(show(tree)); +console.log(evaluate(tree)); +console.log(JSON.stringify(tree) === source); + +const method = JSON.parse( + '{"kind":"method","name":"size","target":{"items":[{"kind":"num","value":1}],"kind":"list"}}', +) as Expr; +console.log(show(method), evaluate(method)); + +// A deep list of every arm, built from text. +const parts: string[] = []; +for (let i = 0; i < 200; i++) { + parts.push( + i % 3 === 0 + ? `{"kind":"num","value":${i}}` + : i % 3 === 1 + ? `{"kind":"neg","operand":{"kind":"num","value":${i}}}` + : `{"kind":"mul","left":{"kind":"num","value":${i}},"right":{"kind":"str","text":"xy"}}`, + ); +} +const list = JSON.parse(`{"items":[${parts.join(",")}],"kind":"list"}`) as Expr; +if (list.kind === "list") { + let total = 0; + for (const item of list.items) total += evaluate(item); + console.log(list.items.length, total); +} + +// Arms that are not records: a value that is not an object can only be one +// of them. +type Token = + | { kind: "ident"; name: string } + | { kind: "number"; value: number } + | { kind: "string"; value: string } + | { kind: "punct"; symbol: string } + | { kind: "comment"; line: number; text: string } + | string + | number; + +function describe(token: Token): string { + if (typeof token === "string") return `raw ${token}`; + if (typeof token === "number") return `count ${token}`; + switch (token.kind) { + case "ident": + return `ident ${token.name}`; + case "number": + return `number ${token.value}`; + case "string": + return `string ${JSON.stringify(token.value)}`; + case "punct": + return `punct ${token.symbol}`; + case "comment": + return `comment ${token.line}: ${token.text}`; + } +} + +const tokens = JSON.parse( + '[{"kind":"ident","name":"x"},{"kind":"punct","symbol":"="},{"kind":"number","value":42},' + + '{"kind":"string","value":"hi"},{"kind":"comment","line":3,"text":"note"},"spare",7]', +) as Token[]; +for (const token of tokens) console.log(describe(token)); diff --git a/tests/harness/corpus-costs/6305-json-discriminant-dispatch.ts.json b/tests/harness/corpus-costs/6305-json-discriminant-dispatch.ts.json new file mode 100644 index 000000000..7e2a9d53c --- /dev/null +++ b/tests/harness/corpus-costs/6305-json-discriminant-dispatch.ts.json @@ -0,0 +1 @@ +{ "plain": 5844, "san": 7609 } diff --git a/tests/harness/dyncheck.test.ts b/tests/harness/dyncheck.test.ts index 6a2d4dc61..5559be970 100644 --- a/tests/harness/dyncheck.test.ts +++ b/tests/harness/dyncheck.test.ts @@ -396,6 +396,54 @@ console.log("unreachable", s.kind); expect(r.stderr).toContain("Uncaught TypeError: expected object | object at $, got object"); }); + test("a union read by its discriminant fails with every arm named, as arm-by-arm tests do", async () => { + // Five record arms with six literals, plus string and number arms: the + // check reads `kind` once and tests only the arm it names and the + // arms that are not records. + const r = await compileAndRun( + "union-discriminant-dispatch", + `type Expr = + | { kind: "num"; value: number } + | { kind: "str"; text: string } + | { kind: "neg"; operand: Expr } + | { kind: "add" | "mul"; left: Expr; right: Expr } + | { items: Expr[]; kind: "list" } + | string + | number; +const inputs = [ + '{"kind":"num"}', + '{"kind":"nope","value":1}', + '{"kind":7,"value":1}', + '{"value":1}', + '{"kind":"neg","operand":{"kind":"add","left":{"kind":"num","value":1},"right":{"kind":"str","text":5}}}', + 'true', + '{"items":["a",3,{"kind":"mul","left":"x","right":2}],"kind":"list"}', +]; +for (const input of inputs) { + try { + console.log(JSON.stringify(JSON.parse(input) as Expr)); + } catch (error) { + console.log((error as Error).message); + } +} +`, + ); + const any = "number | object | object | object | object | object | string"; + expect(r.exitCode).toBe(0); + expect(r.stdout).toBe( + [ + `expected ${any} at $, got object`, + `expected ${any} at $, got object`, + `expected ${any} at $, got object`, + `expected ${any} at $, got object`, + `expected ${any} at $, got object`, + `expected ${any} at $, got boolean`, + '{"items":["a",3,{"kind":"mul","left":"x","right":2}],"kind":"list"}', + "", + ].join("\n"), + ); + }); + test("nested paths point at the offending element", async () => { const r = await compileAndRun( "nested-path", From 5d8804db382fb30944dc90fc910ccb76b0325fcd Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 22:40:04 -0500 Subject: [PATCH 047/259] Version string scans over the UTF-16 units of strings that are not ASCII `for (let i = 0; i < s.length; i++) if (s.charCodeAt(i) === 32) n++` over a text with any non-ASCII character failed the loop version's ASCII guard and ran the checked loop. Each read tested the ASCII bit, compared the string with the runtime's published scan receiver, tested the bounds, loaded the units pointer, and kept the opaque fallback. The guard now also accepts a version's one string receiver when it is not ASCII. One runtime read publishes the string as the scan receiver (ScrStrScan), whose UTF-16 units the runtime holds once a scan has read it enough. The guard then tests the accesses against the published unit count, and a third copy of the loop reads each unit with one 16-bit load from the units pointer taken in the guard. The guard takes that path only while the runtime publishes the receiver itself, so the length it took is the receiver's UTF-16 length on both fast paths. Both fast copies read it for the receiver's `length`, which a while loop's condition otherwise asks the runtime for on every iteration. The runtime drops a string's units when the string is released or appended to in place, or when its index entry is evicted because another non-ASCII string is indexed. The receiver is a binding the loop does not write, so the first two cannot happen while the loop runs. A units copy is emitted only for a loop that uses unit-safe operations (string-unit-versions.ts): numbers, locals, records and class fields, typed arrays, number arrays, Math, the receiver's charCodeAt and length, and calls of functions made of the same operations that read no string. Tests of `s.charAt(i)` against one-unit literals now become charCodeAt compares in the IR pass (char-unit-locals.ts), so a version sees one kind of read. --- .../backend/llvm/bytes-loop-versions.test.ts | 4 +- .../src/backend/llvm/bytes-loop-versions.ts | 143 +++++++++++- .../compiler/src/backend/llvm/emit-module.ts | 6 +- .../src/backend/llvm/emit-statements.ts | 36 ++- packages/compiler/src/backend/llvm/emitter.ts | 18 ++ .../src/backend/llvm/expr-containers.ts | 19 +- .../compiler/src/backend/llvm/string-reads.ts | 22 ++ .../backend/llvm/string-unit-versions.test.ts | 86 +++++++ .../src/backend/llvm/string-unit-versions.ts | 144 ++++++++++++ .../compiler/src/ir/char-unit-locals.test.ts | 23 ++ packages/compiler/src/ir/char-unit-locals.ts | 100 +++++--- .../test/string-char-loop-emission.test.ts | 8 +- .../test/string-unit-loop-emission.test.ts | 94 ++++++++ .../7305-string-unit-loop-versions.ts.json | 6 + .../corpus/7305-string-unit-loop-versions.ts | 219 ++++++++++++++++++ .../7305-string-unit-loop-versions.ts.json | 1 + 16 files changed, 874 insertions(+), 55 deletions(-) create mode 100644 packages/compiler/src/backend/llvm/string-unit-versions.test.ts create mode 100644 packages/compiler/src/backend/llvm/string-unit-versions.ts create mode 100644 packages/compiler/test/string-unit-loop-emission.test.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7305-string-unit-loop-versions.ts.json create mode 100644 tests/corpus/7305-string-unit-loop-versions.ts create mode 100644 tests/harness/corpus-costs/7305-string-unit-loop-versions.ts.json diff --git a/packages/compiler/src/backend/llvm/bytes-loop-versions.test.ts b/packages/compiler/src/backend/llvm/bytes-loop-versions.test.ts index aef39ef75..0c0f1aaa0 100644 --- a/packages/compiler/src/backend/llvm/bytes-loop-versions.test.ts +++ b/packages/compiler/src/backend/llvm/bytes-loop-versions.test.ts @@ -580,7 +580,9 @@ test("the guard tests a string's ASCII bit and the fast copy reads bytes", () => const body = /^define internal [^\n]*@sc_bf_kernel[^]*?^}/m.exec(emitLlvmModule(mod))![0]; const guard = body.slice(0, body.search(/^bytes\.version\.slow\d*:/m)); expect(guard).toMatch(/load i32, ptr %\S+\n\s+%\S+ = icmp slt i32 %\S+, 0/); - const fast = body.slice(body.lastIndexOf("bytes.version.fast")); + // The byte copy, up to the units copy that follows it. + const units = body.search(/^bytes\.version\.fast\.units\d+:/m); + const fast = body.slice(body.search(/^bytes\.version\.fast\d+:/m), units < 0 ? undefined : units); expect(fast).toMatch(/load i8, ptr %\S+\n\s+%\S+ = uitofp i8/); expect(fast).not.toContain("@sc_str_char_code_at_int"); // The checked copy keeps the inline helper and its fallback. diff --git a/packages/compiler/src/backend/llvm/bytes-loop-versions.ts b/packages/compiler/src/backend/llvm/bytes-loop-versions.ts index 1b51deee1..301f65de2 100644 --- a/packages/compiler/src/backend/llvm/bytes-loop-versions.ts +++ b/packages/compiler/src/backend/llvm/bytes-loop-versions.ts @@ -12,7 +12,13 @@ import { } from "./counted-loops.js"; import { emitBytesHeaderLength, emitBytesSharedStorage } from "./expr-bytes.js"; import { f64Lit } from "./common.js"; -import { emitStringAsciiFlag, emitStringByteLength } from "./string-reads.js"; +import { + emitStringAsciiFlag, + emitStringByteLength, + STRING_CHAR_CODE_AT_DECL, + stringScanType, +} from "./string-reads.js"; +import { unitSafeLoop } from "./string-unit-versions.js"; type Node = IrExpr | IrStmt; type VarRef = IrExpr & { kind: "varRef" }; @@ -73,6 +79,14 @@ export interface BytesLoopVersion { receivers: { ref: VarRef; global: boolean; string: boolean }[]; /** Receivers the guard requires to have no shared storage. */ ownedReceivers: number[]; + /** The string reads among `bounds`. */ + stringReads: ReadonlySet; + /** The version's one string receiver, when the loop may also run over + * its UTF-16 units if it is not ASCII (string-unit-versions.ts). */ + unitsReceiver: number | null; + /** The units receiver's `length` reads in the loop. Both fast copies + * read the length the guard took (its UTF-16 length) in their place. */ + unitLengths: ReadonlySet; fixed: FixedCheck[]; affine: AffineCheck[]; /** While loops: accesses at a counter below a loop-invariant bound. */ @@ -114,6 +128,9 @@ export interface BytesLoopFacts { /** String bindings held as a slice of another string (string-slices.ts): * they have no string header for the guard to read. */ scalarStrings: ReadonlySet; + /** The functions a loop over a string's UTF-16 units may call; absent + * or null where emitted code does not read the runtime's scan receiver. */ + unitSafeFunctions?: ReadonlySet | null; } const MAX_COST = 400; @@ -670,6 +687,19 @@ export function matchBytesLoopVersion( // Renumber the receivers the kept checks use. const order = [...used].sort((a, b) => a - b); const renumber = new Map(order.map((old, index) => [old, index])); + const stringReads = new Set(); + for (const group of [...fixedKept, ...affineKept]) + if (receivers[group.check.receiver]!.string) + for (const node of group.nodes) stringReads.add(node); + for (const group of boundedKept) + if (receivers[group.check.receiver]!.string) + for (const { node } of group.nodes) stringReads.add(node); + const strings = order.filter((index) => receivers[index]!.string); + const unitLengths = + facts.unitSafeFunctions != null && strings.length === 1 + ? unitSafeLoop(loop, receivers[strings[0]!]!.ref.localId, facts.unitSafeFunctions) + : null; + const unitsReceiver = unitLengths !== null ? renumber.get(strings[0]!)! : null; const needsBound = affineKept.length > 0 && counted !== null && @@ -679,6 +709,9 @@ export function matchBytesLoopVersion( owned: ownedNodes, receivers: order.map((index) => receivers[index]!), ownedReceivers: ownedKept.map(([receiver]) => renumber.get(receiver)!), + stringReads, + unitsReceiver, + unitLengths: unitLengths ?? new Set(), fixed: fixedKept.map((g) => ({ receiver: renumber.get(g.check.receiver)!, end: g.check.end, @@ -1018,13 +1051,22 @@ function findWhileCounterAccesses( /** Branches to `fast` when every access the version proves is in bounds for * every iteration and every view it proves thread-owned has no shared * storage, and to `slow` otherwise (including a counted loop whose - * integer form is not established, or a module receiver not yet set). */ + * integer form is not established, or a module receiver not yet set). + * + * With `unitsFast`, the version's units receiver may instead be a string + * that is not ASCII: the guard has the runtime publish it as the scan + * receiver (one read), tests the same accesses against its UTF-16 length, + * and branches to `unitsFast`. It returns the units pointer that copy + * reads, which stays valid while the loop runs (string-unit-versions.ts), + * and for a version with a units receiver, the receiver's UTF-16 length + * on both fast paths (an i64). */ export function emitBytesLoopVersionGuard( host: LlvmEmitterContext, version: BytesLoopVersion, fast: string, slow: string, -): void { + unitsFast?: string, +): { units: string | null; length: string | null } | null { const B = host.B; const next = (cond: string): void => { if (cond === "true") return; @@ -1043,19 +1085,36 @@ export function emitBytesLoopVersionGuard( } return value; }); - const lengths = receivers.map((receiver, index) => { - const len = version.receivers[index]!.string - ? emitStringByteLength(host, receiver) - : emitBytesHeaderLength(host, receiver); + const unitsIndex = unitsFast !== undefined ? version.unitsReceiver : null; + const units: { read: { pointer: string; taken: string; published: string } | null } = { + read: null, + }; + const widen = (len: string): string => { if (host.sizeType === "i64") return len; const wide = B.tmp(); B.line(`${wide} = zext ${host.sizeType} ${len} to i64`); return wide; + }; + const lengths = receivers.map((receiver, index) => { + if (index === unitsIndex) { + const read = emitUnitsLength(host, receiver); + units.read = read; + return read.length; + } + return widen( + version.receivers[index]!.string + ? emitStringByteLength(host, receiver) + : emitBytesHeaderLength(host, receiver), + ); }); const conditions: string[] = []; + // The published count is the receiver's UTF-16 length only while the + // runtime publishes the receiver itself. + if (units.read) conditions.push(units.read.published); // A string's byte length is its UTF-16 length when it is ASCII. version.receivers.forEach(({ string }, index) => { - if (string) conditions.push(emitStringAsciiFlag(host, receivers[index]!)); + if (string && index !== unitsIndex) + conditions.push(emitStringAsciiFlag(host, receivers[index]!)); }); for (const index of version.ownedReceivers) { const owned = B.tmp(); @@ -1158,7 +1217,7 @@ export function emitBytesLoopVersionGuard( // Unreachable: every term has a proven range. Stay checked. B.br(slow); B.startBlock(B.newLabel("bytes.version.dead")); - return; + return null; } const wide = widenInteger(host, integer); const sum = B.tmp(); @@ -1215,8 +1274,70 @@ export function emitBytesLoopVersionGuard( valid = all; } } - if (valid === "true") B.br(fast); - else B.condBr(valid, fast, slow); + const length = version.unitsReceiver !== null ? lengths[version.unitsReceiver]! : null; + const taken = units.read; + const target = taken ? B.newLabel("bytes.version.units") : fast; + if (valid === "true") B.br(target); + else B.condBr(valid, target, slow); + if (!taken) return { units: null, length }; + B.startBlock(target); + B.condBr(taken.taken, unitsFast!, fast); + return { units: taken.pointer, length }; +} + +/** The length of a version's units receiver `s` in UTF-16 units: its byte + * length when it is ASCII; otherwise, after one runtime read publishes it + * as the scan receiver, the published unit count (0 when the runtime does + * not hold its units). Also the units pointer, whether the loop is to + * read it, and whether the published receiver is `s`. */ +function emitUnitsLength( + host: LlvmEmitterContext, + s: string, +): { length: string; pointer: string; taken: string; published: string } { + const B = host.B; + const sz = host.sizeType; + const type = stringScanType(sz); + const ascii = emitStringAsciiFlag(host, s); + const bytes = emitStringByteLength(host, s); + const from = B.currentLabel(); + const publish = B.newLabel("bytes.version.publish"), + join = B.newLabel("bytes.version.length"); + B.condBr(ascii, join, publish); + B.startBlock(publish); + host.declare(STRING_CHAR_CODE_AT_DECL); + const read = B.tmp(), + receiver = B.tmp(), + same = B.tmp(), + pointerSlot = B.tmp(), + pointer = B.tmp(), + countSlot = B.tmp(), + count = B.tmp(), + published = B.tmp(); + B.line(`${read} = call double @scr_str_char_code_at(ptr ${s}, double 0.0)`); + B.line(`${receiver} = load ptr, ptr @scr_str_scan`); + B.line(`${same} = icmp eq ptr ${receiver}, ${s}`); + B.line(`${pointerSlot} = getelementptr inbounds ${type}, ptr @scr_str_scan, i32 0, i32 1`); + B.line(`${pointer} = load ptr, ptr ${pointerSlot}`); + B.line(`${countSlot} = getelementptr inbounds ${type}, ptr @scr_str_scan, i32 0, i32 2`); + B.line(`${count} = load ${sz}, ptr ${countSlot}`); + B.line(`${published} = select i1 ${same}, ${sz} ${count}, ${sz} 0`); + const end = B.currentLabel(); + B.br(join); + B.startBlock(join); + const length = B.tmp(), + units = B.tmp(), + taken = B.tmp(); + B.line(`${length} = phi ${sz} [ ${bytes}, %${from} ], [ ${published}, %${end} ]`); + B.line(`${units} = phi ptr [ null, %${from} ], [ ${pointer}, %${end} ]`); + B.line(`${taken} = phi i1 [ false, %${from} ], [ true, %${end} ]`); + const exact = B.tmp(); + B.line(`${exact} = phi i1 [ true, %${from} ], [ ${same}, %${end} ]`); + let wide = length; + if (sz !== "i64") { + wide = B.tmp(); + B.line(`${wide} = zext ${sz} ${length} to i64`); + } + return { length: wide, pointer: units, taken, published: exact }; } function scaleCounter(host: LlvmEmitterContext, value: string, scale: number): string { diff --git a/packages/compiler/src/backend/llvm/emit-module.ts b/packages/compiler/src/backend/llvm/emit-module.ts index e5258e583..069f3b615 100644 --- a/packages/compiler/src/backend/llvm/emit-module.ts +++ b/packages/compiler/src/backend/llvm/emit-module.ts @@ -61,7 +61,7 @@ import { hasLoneSurrogate, wtf8Bytes } from "../literals.js"; import { undefinedArmTag } from "../../ir/analysis.js"; import { NULLABLE_ABSENT, NULLABLE_NULL } from "./nullable-unions.js"; import { literalEqualityDefinition } from "./string-literal-equality.js"; -import { STRING_READ_HELPERS, stringScanDecl } from "./string-reads.js"; +import { STRING_READ_HELPERS, stringScanDecl, stringScanInline } from "./string-reads.js"; import { emitLibraryIdentityLines } from "../library-identity-markers.js"; import { InternalCompilerError } from "../../errors.js"; import { targetCpuAttribute } from "../target-cpu.js"; @@ -1586,9 +1586,7 @@ export function helperDefs(emitter: LlEmitter): string[] { // A scan's receiver reads inline too (ScrStrScan): from ordinary global // storage, or, in worker executables, from the thread's static TLS block, // one thread-pointer-relative load (see executableTls). - const scanInline = - emitter.executableTls || - (emitter.mod.workers !== true && emitter.mod.lib?.threadInstances !== true); + const scanInline = stringScanInline(emitter); let scanDeclared = false; for (const helper of STRING_READ_HELPERS) { if (!emitter.decls.has(helper.decl)) continue; diff --git a/packages/compiler/src/backend/llvm/emit-statements.ts b/packages/compiler/src/backend/llvm/emit-statements.ts index 55e31219c..6de298ec4 100644 --- a/packages/compiler/src/backend/llvm/emit-statements.ts +++ b/packages/compiler/src/backend/llvm/emit-statements.ts @@ -2082,28 +2082,56 @@ function emitVersionedLoop( const fast = B.newLabel("bytes.version.fast"), slow = B.newLabel("bytes.version.slow"), done = B.newLabel("bytes.version.done"); - emitBytesLoopVersionGuard(emitter, version, fast, slow); + const unitsFast = + version.unitsReceiver !== null ? B.newLabel("bytes.version.fast.units") : undefined; + const guard = emitBytesLoopVersionGuard(emitter, version, fast, slow, unitsFast); + const units = guard?.units ?? null; const originalBounds = emitter.bytesBounds, originalOwned = emitter.bytesOwned, - originalRanges = emitter.integerRanges; + originalRanges = emitter.integerRanges, + originalUnitReads = emitter.stringUnitReads, + originalLengthReads = emitter.stringLengthReads; LOOPS.of(emitter).bytesLoopVersioning.add(s); try { B.startBlock(slow); emitter.emitStmt(s); B.br(done); - B.startBlock(fast); - emitter.bytesBounds = new Set([...originalBounds, ...version.bounds]); if (version.owned.size > 0) emitter.bytesOwned = new Set([...originalOwned, ...version.owned]); if (version.ranges.size > 0) emitter.integerRanges = new Map([...originalRanges, ...version.ranges]); if (version.counted?.guarded || version.paired?.loop.guarded) LOOPS.of(emitter).provenCountedGuards.add(s); + B.startBlock(fast); + emitter.bytesBounds = new Set([...originalBounds, ...version.bounds]); + // Both fast copies read the string's length the guard took. + const length = guard?.length; + if (length != null && version.unitLengths.size > 0) + emitter.stringLengthReads = new Map([ + ...originalLengthReads, + ...[...version.unitLengths].map((node) => [node, length] as const), + ]); emitter.emitStmt(s); B.br(done); + if (unitsFast !== undefined && units !== null) { + // The string reads take the receiver's UTF-16 units. + B.startBlock(unitsFast); + emitter.bytesBounds = new Set([ + ...originalBounds, + ...[...version.bounds].filter((node) => !version.stringReads.has(node)), + ]); + emitter.stringUnitReads = new Map([ + ...originalUnitReads, + ...[...version.stringReads].map((node) => [node, units] as const), + ]); + emitter.emitStmt(s); + B.br(done); + } } finally { emitter.bytesBounds = originalBounds; emitter.bytesOwned = originalOwned; emitter.integerRanges = originalRanges; + emitter.stringUnitReads = originalUnitReads; + emitter.stringLengthReads = originalLengthReads; LOOPS.of(emitter).provenCountedGuards.delete(s); LOOPS.of(emitter).bytesLoopVersioning.delete(s); } diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 8106a6478..0a2756388 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -104,6 +104,8 @@ import { dropUnwrittenPropertyBags } from "../../ir/property-bags.js"; import { freezeInitOnlyGlobals } from "../../ir/init-only-globals.js"; import { hoistFinalFieldReads } from "../../ir/field-values.js"; import { holdCharLocalsAsUnits } from "../../ir/char-unit-locals.js"; +import { unitSafeFunctions } from "./string-unit-versions.js"; +import { stringScanInline } from "./string-reads.js"; import { findInt32Abis, INT32_ABI_SUFFIX, @@ -1477,6 +1479,12 @@ export class LlEmitter { * (one-unit tests and switches, charAtUnitRead), with the charAt each * stands for: a loop version's proof for the charAt covers its read. */ readonly charAtUnitReads = new Map(); + /** String reads a loop version proved in bounds of a string's UTF-16 + * units, with the units pointer to read (string-unit-versions.ts). */ + stringUnitReads: ReadonlyMap = new Map(); + /** `length` reads of a loop version's string, with the i64 UTF-16 + * length its guard took (bytes-loop-versions.ts). */ + stringLengthReads: ReadonlyMap = new Map(); /** Worker programs: typed-array accesses whose views an enclosing version * guard proved thread-owned. */ bytesOwned: ReadonlySet = new Set(); @@ -4305,11 +4313,21 @@ export class LlEmitter { workers: this.mod.workers === true, owned: this.bytesOwned, scalarStrings: new Set(this.stringSlices.keys()), + unitSafeFunctions: this.unitSafeFunctions(), }, paired, ); } + private unitSafe: ReadonlySet | null | undefined; + /** The functions a loop over a string's UTF-16 units may call, or null + * where emitted reads do not use the runtime's scan receiver. */ + private unitSafeFunctions(): ReadonlySet | null { + if (this.unitSafe === undefined) + this.unitSafe = stringScanInline(this) ? unitSafeFunctions(this.mod) : null; + return this.unitSafe; + } + /** The alias tag of a whole-slot load of a binding (module globals only). */ slotAlias(id: string): string { const binding = this.binding(id); diff --git a/packages/compiler/src/backend/llvm/expr-containers.ts b/packages/compiler/src/backend/llvm/expr-containers.ts index 279b8c044..bba7629b9 100644 --- a/packages/compiler/src/backend/llvm/expr-containers.ts +++ b/packages/compiler/src/backend/llvm/expr-containers.ts @@ -53,6 +53,7 @@ import { STRING_CHAR_CODE_AT_INT_MARKER, emitAsciiChar, emitAsciiCharCode, + emitUnitCharCode, STRING_UTF16_LEN_DECL, } from "./string-reads.js"; import { exactInteger, widenInteger } from "./integer-values.js"; @@ -322,6 +323,15 @@ export function charAtUnitRead( return read; } +/** The UTF-16 units an enclosing loop version proved the index of `e` + * below the count of (string-unit-versions.ts). */ +function provenUnitsRead(host: LlvmEmitterContext, e: IrExpr): string | null { + const units = host.stringUnitReads.get(e); + if (units !== undefined) return units; + const origin = host.charAtUnitReads.get(e); + return origin !== undefined ? (host.stringUnitReads.get(origin) ?? null) : null; +} + /** An enclosing loop version proved the string of `e` ASCII and its index * below the length (bytes-loop-versions.ts). */ function provenStringRead(host: LlvmEmitterContext, e: IrExpr): boolean { @@ -364,9 +374,14 @@ export function emitStrIntrinsic( const method = e.method; switch (method) { case "length": { + const t = B.tmp(); + const length = host.stringLengthReads.get(e); + if (length !== undefined) { + B.line(`${t} = sitofp i64 ${length} to double`); + return { name: t, type: e.type }; + } // sc_str_utf16_len (string-reads.ts) answers proven-ASCII strings inline. host.declare(STRING_UTF16_LEN_DECL); - const t = B.tmp(); B.line(`${t} = call double @sc_str_utf16_len(ptr ${r.name})`); return { name: t, type: e.type }; } @@ -376,6 +391,8 @@ export function emitStrIntrinsic( const index = e.args[0] ? exactInteger(host, args[0]!, e.args[0]) : null; if (index) { const wide = widenInteger(host, index); + const units = provenUnitsRead(host, e); + if (units !== null) return { name: emitUnitCharCode(host, units, wide), type: e.type }; if (provenStringRead(host, e)) return { name: emitAsciiCharCode(host, r.name, wide), type: e.type }; host.declare(STRING_CHAR_CODE_AT_INT_MARKER); diff --git a/packages/compiler/src/backend/llvm/string-reads.ts b/packages/compiler/src/backend/llvm/string-reads.ts index 441c925f3..08df79cf2 100644 --- a/packages/compiler/src/backend/llvm/string-reads.ts +++ b/packages/compiler/src/backend/llvm/string-reads.ts @@ -75,6 +75,19 @@ export function emitAsciiCharCode(host: LlvmEmitterContext, s: string, index: st return code; } +/** Unit `index` (an i64, below their count) of a string's UTF-16 `units` + * (ScrStrScan): one 16-bit load, as a double. */ +export function emitUnitCharCode(host: LlvmEmitterContext, units: string, index: string): string { + const B = host.B; + const pointer = B.tmp(), + unit = B.tmp(), + code = B.tmp(); + B.line(`${pointer} = getelementptr inbounds i16, ptr ${units}, i64 ${index}`); + B.line(`${unit} = load i16, ptr ${pointer}`); + B.line(`${code} = uitofp i16 ${unit} to double`); + return code; +} + /** The one-character string of unit `index` (an i64) of a proven-ASCII * string `s` whose length covers it: the immortal `@sc_ascii_chars` entry * for its byte, as the inline charAt helpers answer. */ @@ -114,6 +127,15 @@ function loadLength(sz: string): string[] { ]; } +/** Whether emitted reads use the runtime's scan receiver: from ordinary + * global storage, or, in worker executables, from the thread's static TLS + * block (executableTls). */ +export function stringScanInline(host: LlvmEmitterContext): boolean { + return ( + host.executableTls || (host.mod.workers !== true && host.mod.lib?.threadInstances !== true) + ); +} + /** The runtime's ScrStrScan record and the declaration naming it. */ export function stringScanType(sz: string): string { return `{ ptr, ptr, ${sz} }`; diff --git a/packages/compiler/src/backend/llvm/string-unit-versions.test.ts b/packages/compiler/src/backend/llvm/string-unit-versions.test.ts new file mode 100644 index 000000000..5b0634b1a --- /dev/null +++ b/packages/compiler/src/backend/llvm/string-unit-versions.test.ts @@ -0,0 +1,86 @@ +import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile, deserializeModule } from "../../index.js"; +import type { IrModule, IrStmt } from "../../ir/ir.js"; +import { unitSafeFunctions, unitSafeLoop } from "./string-unit-versions.js"; + +async function lower(source: string): Promise { + const dir = await mkdtemp(join(tmpdir(), "scriptc-unit-versions-")); + try { + const entry = join(dir, "main.ts"); + const outPath = join(dir, "main.ir.json"); + await writeFile(entry, source); + const result = await compile(entry, { outDir: dir, outPath, outputKind: "ir" }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + return deserializeModule(await readFile(outPath, "utf8")); + } finally { + await rm(dir, { recursive: true, force: true }); + } +} + +const loopOf = (mod: IrModule, name: string): IrStmt & { kind: "for" } => + mod.functions.find((f) => f.name === name)!.body.find((s) => s.kind === "for") as IrStmt & { + kind: "for"; + }; + +test("loops over a string's units call only functions that read no string", async () => { + const mod = await lower(` +function lower(c: number): boolean { + return c >= 97 && c <= 122; +} +function word(c: number): boolean { + return lower(c) || (c >= 48 && c <= 57) || Math.abs(c - 200) < 50; +} +function codeOf(t: string, i: number): number { + return t.charCodeAt(i); +} +function viaCodeOf(t: string): number { + return codeOf(t, 0); +} +function words(s: string): number { + let n = 0; + const starts = [0]; + for (let i = 0; i < s.length; i++) { + if (word(s.charCodeAt(i))) n++; + else starts.push(i); + } + return n + starts.length; +} +function pairs(s: string, t: string): number { + let n = 0; + for (let i = 0; i < s.length; i++) n += s.charCodeAt(i) + codeOf(t, i); + return n; +} +function both(s: string, t: string): number { + let n = 0; + for (let i = 0; i < s.length; i++) n += s.charCodeAt(i) + t.charCodeAt(i); + return n; +} +function concatenates(s: string): string { + let out = ""; + for (let i = 0; i < s.length; i++) if (s.charCodeAt(i) === 32) out += "-"; + return out; +} +console.log(words("ab c"), pairs("ab", "cd"), both("ab", "cd"), concatenates("a b"), viaCodeOf("x")); +`); + const safe = unitSafeFunctions(mod); + expect(safe.has("lower")).toBe(true); + expect(safe.has("word")).toBe(true); + // A string read, directly or through a call, makes a function unsafe. + expect(safe.has("codeOf")).toBe(false); + expect(safe.has("viaCodeOf")).toBe(false); + + const param = (fn: string, index = 0): string => + mod.functions.find((f) => f.name === fn)!.params[index]!.localId; + // A unit-safe loop answers its receiver's length reads: here the + // condition's `s.length`. + const lengths = unitSafeLoop(loopOf(mod, "words"), param("words"), safe); + expect(lengths?.size).toBe(1); + expect([...lengths!].every((e) => e.kind === "strIntrinsic" && e.method === "length")).toBe(true); + expect(unitSafeLoop(loopOf(mod, "pairs"), param("pairs"), safe)).toBeNull(); + expect(unitSafeLoop(loopOf(mod, "both"), param("both"), safe)).toBeNull(); + expect(unitSafeLoop(loopOf(mod, "concatenates"), param("concatenates"), safe)).toBeNull(); +}); diff --git a/packages/compiler/src/backend/llvm/string-unit-versions.ts b/packages/compiler/src/backend/llvm/string-unit-versions.ts new file mode 100644 index 000000000..022c3a513 --- /dev/null +++ b/packages/compiler/src/backend/llvm/string-unit-versions.ts @@ -0,0 +1,144 @@ +import type { IrExpr, IrModule, IrStmt } from "../../ir/ir.js"; +import { everyExprChild, everyStmtChild } from "../../ir/traverse.js"; + +/* Loop versions over the UTF-16 units of a string that is not ASCII. + * + * The runtime publishes the receiver of an indexed scan with its UTF-16 + * units (ScrStrScan, string-reads.ts), and drops them when the string is + * released or appended to in place, or when its index entry is evicted: + * the runtime indexes another non-ASCII string. A loop version's string + * receiver is a binding the loop does not write, which keeps it alive and + * unappended for the whole loop. Its fast copy over units therefore only + * needs a body that indexes no other string: the operations below, and + * calls of functions made of the same operations without string reads + * (`unitSafeFunctions`). */ + +const ARRAY_METHODS = new Set(["push", "pop", "length"]); + +/** Whether `e` (or statement `s`) uses only operations that index no + * string: numbers, booleans, locals, records and class fields, typed + * arrays, number arrays and Math. `reads` admits the string reads a + * version covers; `calls` the callees. */ +function unitSafe( + node: { e: IrExpr } | { s: IrStmt }, + reads: (e: IrExpr & { kind: "strIntrinsic" }) => boolean, + calls: (callee: string) => boolean, +): boolean { + const expr = (e: IrExpr): boolean => { + switch (e.kind) { + case "varRef": + case "numLit": + case "boolLit": + case "bin": + case "unary": + case "logical": + case "ternary": + case "toBool": + case "seqExpr": + case "assignExpr": + case "incDec": + case "recordGet": + case "fieldGet": + case "bytesIntrinsic": + break; + case "arrayGet": + if (e.type.kind !== "f64" && e.type.kind !== "bool") return false; + break; + case "arrIntrinsic": { + // Growing or shrinking an array of numbers allocates; it reads no + // string. + const array = e.receiver.type; + if ( + !ARRAY_METHODS.has(e.method) || + array.kind !== "array" || + (array.elem.kind !== "f64" && array.elem.kind !== "bool") + ) + return false; + break; + } + case "libCall": + if (!e.fn.startsWith("math.")) return false; + break; + case "call": + if (!calls(e.callee)) return false; + break; + case "strIntrinsic": + if (!reads(e)) return false; + break; + default: + return false; + } + return everyExprChild(e, expr, stmt); + }; + const stmt = (s: IrStmt): boolean => { + switch (s.kind) { + case "varDecl": + case "assign": + case "exprStmt": + case "if": + case "block": + case "while": + case "doWhile": + case "for": + case "break": + case "continue": + case "return": + case "recordSet": + case "fieldSet": + case "bytesSet": + break; + default: + return false; + } + return everyStmtChild(s, expr, stmt); + }; + return "e" in node ? expr(node.e) : stmt(node.s); +} + +/** The module's functions a units version may call: synchronous + * functions without captures whose bodies use only unit-safe operations, + * read no string, and call only such functions. */ +export function unitSafeFunctions(mod: IrModule): ReadonlySet { + const candidates = new Map( + mod.functions + .filter((fn) => !fn.async && !fn.generator && !(fn.captures?.length ?? 0)) + .map((fn) => [fn.name, fn]), + ); + const safe = new Set(candidates.keys()); + for (let settled = false; !settled;) { + settled = true; + for (const name of safe) { + const fn = candidates.get(name)!; + const ok = fn.body.every((s) => + unitSafe( + { s }, + () => false, + (callee) => safe.has(callee), + ), + ); + if (!ok) { + safe.delete(name); + settled = false; + } + } + } + return safe; +} + +/** The `length` reads of the binding `receiver` in a loop whose every + * part is unit-safe, reading only charCodeAt and length of `receiver` and + * calling only `safe` functions; null for any other loop. */ +export function unitSafeLoop( + loop: IrStmt & { kind: "for" | "while" }, + receiver: string, + safe: ReadonlySet, +): ReadonlySet | null { + const lengths = new Set(); + const reads = (e: IrExpr & { kind: "strIntrinsic" }): boolean => { + if (e.receiver.kind !== "varRef" || e.receiver.localId !== receiver) return false; + if (e.method === "length") lengths.add(e); + return e.method === "charCodeAt" || e.method === "length"; + }; + const calls = (callee: string): boolean => safe.has(callee); + return unitSafe({ s: loop }, reads, calls) ? lengths : null; +} diff --git a/packages/compiler/src/ir/char-unit-locals.test.ts b/packages/compiler/src/ir/char-unit-locals.test.ts index ad16ecebd..9ec25b75a 100644 --- a/packages/compiler/src/ir/char-unit-locals.test.ts +++ b/packages/compiler/src/ir/char-unit-locals.test.ts @@ -96,3 +96,26 @@ console.log(escapes("a b", 1), rebound(" x", 0), wide("ab", 0), against("a", "b expect(fn(after, name)).toBe(fn(before, name)); } }); + +test("charAt tests in place compare charCodeAt", async () => { + const mod = holdCharLocalsAsUnits( + await lower(` +function tests(s: string, i: number): number { + let n = 0; + if (s.charAt(i) === " ") n += 1; + if ("a" <= s.charAt(i) && s.charAt(i) < "n") n += 2; + if (s.charAt(i) === "ab") n += 4; + return n; +} +console.log(tests("a b", 1), tests("abc", 0), tests("", 2)); +`), + ); + // The two-unit literal keeps its string comparison. + expect(reads(fn(mod, "tests"))).toEqual([ + "charCodeAt", + "charCodeAt", + "charCodeAt", + "strEq", + "charAt", + ]); +}); diff --git a/packages/compiler/src/ir/char-unit-locals.ts b/packages/compiler/src/ir/char-unit-locals.ts index beeeffaf3..840b7478f 100644 --- a/packages/compiler/src/ir/char-unit-locals.ts +++ b/packages/compiler/src/ir/char-unit-locals.ts @@ -12,6 +12,8 @@ import { mapExprChildren, mapStmtChildren } from "./traverse.js"; type CharAt = IrExpr & { kind: "strIntrinsic" }; type UnitUse = IrExpr & { kind: "strEq" | "strCmp" }; +const FLIPPED = { "<": ">", "<=": ">=", ">": "<", ">=": "<=" } as const; + /** Character locals held as their code unit. * * `const c = s[i]` (or `s.charAt(i)`) followed only by tests such as @@ -28,7 +30,8 @@ type UnitUse = IrExpr & { kind: "strEq" | "strCmp" }; * * Only immutable unboxed string locals qualify, with one declaration whose * initializer is a one-argument charAt, and with no other mention of the - * local. */ + * local. The same tests of `s.charAt(i)` in place compare + * `s.charCodeAt(i)`, so a loop version sees one kind of read. */ export function holdCharLocalsAsUnits(mod: IrModule): IrModule { let changed = false; const functions = mod.functions.map((fn) => { @@ -43,7 +46,6 @@ function rewriteFunction(fn: IrFunction): IrFunction { const candidates = new Set( fn.locals.filter((l) => !l.mutable && !l.boxed && l.type.kind === "string").map((l) => l.id), ); - if (candidates.size === 0) return fn; // Every mention of a candidate, in any field, against the mentions the // rewrite understands. const mentions = new Map(); @@ -67,7 +69,7 @@ function rewriteFunction(fn: IrFunction): IrFunction { for (const key in node) if (key !== "loc") count(node[key]); } }; - count(fn.body); + if (candidates.size > 0) count(fn.body); const held = new Set(); for (const id of candidates) if ( @@ -76,7 +78,7 @@ function rewriteFunction(fn: IrFunction): IrFunction { mentions.get(id) === understood.get(id) ) held.add(id); - if (held.size === 0) return fn; + let changed = false; const unitRef = (id: string, loc: IrExpr["loc"]): IrExpr => ({ kind: "varRef", @@ -88,38 +90,28 @@ function rewriteFunction(fn: IrFunction): IrFunction { if (e.kind === "strEq" || e.kind === "strCmp") { const use = unitUse(e); if (use && held.has(use.id)) { - const code: IrExpr = { kind: "numLit", value: use.code, type: F64, loc: e.loc }; - const c = unitRef(use.id, e.loc); - if (e.kind === "strEq") - return { - kind: "bin", - op: e.negated ? "!==" : "===", - left: c, - right: code, - type: BOOL, - loc: e.loc, - }; - // The comparison with the local on the left. - const op = use.left - ? e.op - : ({ "<": ">", "<=": ">=", ">": "<", ">=": "<=" } as const)[e.op]; - if (op === ">" || op === ">=") - return { kind: "bin", op, left: c, right: code, type: BOOL, loc: e.loc }; - const negation: IrExpr = { - kind: "bin", - op: op === "<" ? ">=" : ">", - left: c, - right: code, - type: BOOL, - loc: e.loc, + changed = true; + return charUnitTest(e, unitRef(use.id, e.loc), use.code, use.left); + } + // `s.charAt(i)` in place: its unit read, `s.charCodeAt(i)`. + const direct = charAtTest(e); + if (direct) { + changed = true; + const read: IrExpr = { + ...direct.charAt, + method: "charCodeAt", + receiver: rewriteExpr(direct.charAt.receiver), + args: direct.charAt.args.map(rewriteExpr), + type: F64, }; - return { kind: "unary", op: "!", operand: negation, type: BOOL, loc: e.loc }; + return charUnitTest(e, read, direct.code, direct.left); } } return mapExprChildren(e, rewriteExpr, rewriteStmt); }; const rewriteStmt = (s: IrStmt): IrStmt => { - if (s.kind === "varDecl" && held.has(s.localId) && s.init?.kind === "strIntrinsic") + if (s.kind === "varDecl" && held.has(s.localId) && s.init?.kind === "strIntrinsic") { + changed = true; return { ...s, init: { @@ -130,7 +122,9 @@ function rewriteFunction(fn: IrFunction): IrFunction { type: F64, }, }; - if (s.kind === "switch" && s.disc.kind === "varRef" && held.has(s.disc.localId)) + } + if (s.kind === "switch" && s.disc.kind === "varRef" && held.has(s.disc.localId)) { + changed = true; return { ...s, disc: unitRef(s.disc.localId, s.disc.loc), @@ -143,11 +137,14 @@ function rewriteFunction(fn: IrFunction): IrFunction { body: c.body.map(rewriteStmt), })), }; + } return mapStmtChildren(s, rewriteExpr, rewriteStmt); }; + const body = fn.body.map(rewriteStmt); + if (!changed) return fn; return { ...fn, - body: fn.body.map(rewriteStmt), + body, locals: fn.locals.map((l) => (held.has(l.id) ? unitLocal(l) : l)), }; } @@ -179,6 +176,45 @@ function understoodMention(node: Record): string | null { return null; } +/** A one-unit test of a string that reads one character or "" (charAt), + * on its unit `unit`, which reads NaN for "": an equality, or an ordered + * comparison with the unit on the left when `unitLeft`. "" is below every + * one-unit literal, and NaN fails every ordered comparison, so `c < "x"` + * becomes `!(c >= 120)`. */ +function charUnitTest(e: UnitUse, unit: IrExpr, code: number, unitLeft: boolean): IrExpr { + const literal: IrExpr = { kind: "numLit", value: code, type: F64, loc: e.loc }; + if (e.kind === "strEq") + return { + kind: "bin", + op: e.negated ? "!==" : "===", + left: unit, + right: literal, + type: BOOL, + loc: e.loc, + }; + const op = unitLeft ? e.op : FLIPPED[e.op]; + if (op === ">" || op === ">=") + return { kind: "bin", op, left: unit, right: literal, type: BOOL, loc: e.loc }; + const negation: IrExpr = { + kind: "bin", + op: op === "<" ? ">=" : ">", + left: unit, + right: literal, + type: BOOL, + loc: e.loc, + }; + return { kind: "unary", op: "!", operand: negation, type: BOOL, loc: e.loc }; +} + +/** A test between `s.charAt(i)` and a literal of one code unit. */ +function charAtTest(e: UnitUse): { charAt: CharAt; code: number; left: boolean } | null { + const literalRight = e.right.kind === "strLit"; + const literal = literalRight ? e.right : e.left; + const other = literalRight ? e.left : e.right; + if (literal.kind !== "strLit" || literal.value.length !== 1 || !isCharAt(other)) return null; + return { charAt: other, code: literal.value.charCodeAt(0), left: literalRight }; +} + function isCharAt(e: IrExpr): e is CharAt { return e.kind === "strIntrinsic" && e.method === "charAt" && e.args.length === 1; } diff --git a/packages/compiler/test/string-char-loop-emission.test.ts b/packages/compiler/test/string-char-loop-emission.test.ts index 6f5756ce8..9f2553d85 100644 --- a/packages/compiler/test/string-char-loop-emission.test.ts +++ b/packages/compiler/test/string-char-loop-emission.test.ts @@ -43,8 +43,12 @@ console.log(spaces("a b c"), letters("abC1z"), chars("xyz").join("-"), chars("é ll.match( new RegExp(`define internal [^\\n]+ @sc_bf_${name}\\([^\\n]*\\) #0 \\{[\\s\\S]*?\\n\\}`), )![0]; - // The fast copy follows the checked one. - const fast = (fn: string): string => fn.slice(fn.lastIndexOf("bytes.version.fast")); + // The byte copy follows the checked one, and the units copy (for + // strings that are not ASCII) follows it. + const fast = (fn: string): string => { + const units = fn.search(/^bytes\.version\.fast\.units\d+:/m); + return fn.slice(fn.search(/^bytes\.version\.fast\d+:/m), units < 0 ? undefined : units); + }; // `s[i] === " "` compares the byte; the checked copy keeps the helper. const spaces = body("spaces"); diff --git a/packages/compiler/test/string-unit-loop-emission.test.ts b/packages/compiler/test/string-unit-loop-emission.test.ts new file mode 100644 index 000000000..32ee8411b --- /dev/null +++ b/packages/compiler/test/string-unit-loop-emission.test.ts @@ -0,0 +1,94 @@ +import { execFileSync } from "node:child_process"; +import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile, deserializeModule } from "../src/index.js"; +import { emitLlvmModule } from "../src/backend/llvm/emitter.js"; + +test("scans of strings that are not ASCII read their UTF-16 units", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-unit-loops-")); + try { + const entry = join(dir, "main.ts"); + await writeFile( + entry, + ` +function spaces(s: string): number { + let n = 0; + for (let i = 0; i < s.length; i++) if (s.charCodeAt(i) === 32) n++; + return n; +} +function skip(s: string): number { + let pos = 0; + while (pos < s.length && s.charCodeAt(pos) !== 32) pos++; + return pos; +} +function pairs(s: string, t: string): number { + let n = 0; + for (let i = 0; i < s.length; i++) if (s.charCodeAt(i) === t.charCodeAt(i % t.length)) n++; + return n; +} +let text = ""; +for (let k = 0; k < 400; k++) text += k % 3 === 0 ? "café " : "naïve façade "; +const other = text.replace(/a/g, "ä"); +let total = 0; +for (let pass = 0; pass < 4; pass++) + total += spaces(text) + spaces(other) + pairs(text, other) + skip(text); +console.log(total, spaces("plain ascii text"), spaces("")); +`, + ); + const outPath = join(dir, "main.ir.json"); + const lowered = await compile(entry, { outDir: dir, outPath, outputKind: "ir" }); + if (!lowered.ok) + throw new Error(lowered.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + const ll = emitLlvmModule(deserializeModule(await readFile(outPath, "utf8"))); + const body = (name: string): string => + ll.match( + new RegExp( + `define internal [^\\n]+ @sc_bf_${name}(?:\\.i32)?\\([^\\n]*\\) #0 \\{[\\s\\S]*?\\n\\}`, + ), + )![0]; + + const spaces = body("spaces"); + // A string that is not ASCII is published as the scan receiver once, + // before the loop, and its copy loads units. + expect(spaces).toMatch(/call double @scr_str_char_code_at\(ptr %\S+, double 0\.0\)/); + // The copies follow the checked one: bytes, then units. + const bytesAt = spaces.search(/^bytes\.version\.fast\d+:/m); + const unitsAt = spaces.search(/^bytes\.version\.fast\.units\d+:/m); + expect(bytesAt).toBeGreaterThan(0); + expect(unitsAt).toBeGreaterThan(bytesAt); + const units = spaces.slice(unitsAt); + expect(units).toMatch(/load i16, ptr %\S+\n\s+%\S+ = uitofp i16/); + expect(units).not.toContain("@sc_str_char_code_at_int"); + // An ASCII string still reads bytes. + const bytes = spaces.slice(bytesAt, unitsAt); + expect(bytes).toMatch(/load i8, ptr %\S+\n\s+%\S+ = uitofp i8/); + expect(bytes).not.toContain("@sc_str_char_code_at_int"); + // A while loop over a counter below the length reads units too. + const skip = body("skip"); + expect(skip).toMatch(/^bytes\.version\.fast\.units\d+:/m); + // Its fast copies read the length the guard took; the checked copy + // still asks for it. + const skipFastAt = skip.search(/^bytes\.version\.fast\d+:/m); + expect(skip.slice(0, skipFastAt)).toContain("@sc_str_utf16_len"); + expect(skip.slice(skipFastAt)).not.toContain("@sc_str_utf16_len"); + // Two strings cannot both be the scan receiver. + expect(body("pairs")).not.toContain("bytes.version.fast.units"); + + const exe = join(dir, "main"); + const built = await compile(entry, { outputKind: "exe", outDir: dir, outPath: exe }); + if (!built.ok) throw new Error(JSON.stringify(built.diagnostics)); + let text = ""; + for (let k = 0; k < 400; k++) text += k % 3 === 0 ? "café " : "naïve façade "; + const other = text.replace(/a/g, "ä"); + const count = (s: string): number => s.split(" ").length - 1; + let pairs = 0; + for (let i = 0; i < text.length; i++) + if (text.charCodeAt(i) === other.charCodeAt(i % other.length)) pairs++; + const total = 4 * (count(text) + count(other) + pairs + text.indexOf(" ")); + expect(execFileSync(exe, { encoding: "utf8" })).toBe(`${total} 2 0\n`); + } finally { + await rm(dir, { recursive: true, force: true }); + } +}); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7305-string-unit-loop-versions.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7305-string-unit-loop-versions.ts.json new file mode 100644 index 000000000..21b8255e4 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7305-string-unit-loop-versions.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7305-string-unit-loop-versions.ts" + ], + "diags": [] +} diff --git a/tests/corpus/7305-string-unit-loop-versions.ts b/tests/corpus/7305-string-unit-loop-versions.ts new file mode 100644 index 000000000..c7600167d --- /dev/null +++ b/tests/corpus/7305-string-unit-loop-versions.ts @@ -0,0 +1,219 @@ +// charCodeAt scans of strings that are not ASCII, repeated so the runtime +// holds their UTF-16 units: counts, hashes, neighbor reads, descending +// loops, reads past the end, line starts pushed to a number array, helper +// functions that read no string, a helper that reads another string, a +// second non-ASCII string read in the same loop, two texts scanned in +// turn, a short text, a text appended to between scans, surrogate pairs +// and lone surrogates, ASCII texts beside them, and while loops over a +// counter below the length: word and identifier scans, peeks past the +// counter, and a lexer class whose position is a field. Loops also read +// the length in their bodies, and loops over a fresh text that no scan +// has published run from its end and over its last units. + +function isWordUnit(c: number): boolean { + return (c >= 97 && c <= 122) || (c >= 65 && c <= 90) || c > 127; +} + +function isWordOrDigit(c: number): boolean { + return isWordUnit(c) || (c >= 48 && c <= 57); +} + +function spaces(s: string): number { + let n = 0; + for (let i = 0; i < s.length; i++) if (s.charCodeAt(i) === 32) n++; + return n; +} + +function hash(s: string): number { + let h = 7; + for (let i = 0; i < s.length; i++) h = (Math.imul(h, 31) + s.charCodeAt(i)) | 0; + return h; +} + +function rises(s: string): number { + let n = 0; + for (let i = 1; i < s.length - 1; i++) + if (s.charCodeAt(i) > s.charCodeAt(i - 1) && s.charCodeAt(i) >= s.charCodeAt(i + 1)) n++; + return n; +} + +function backwards(s: string): number { + let h = 0; + for (let i = s.length - 1; i >= 0; i -= 3) h = (h * 7 + s.charCodeAt(i)) % 1000003; + return h; +} + +function pastEnd(s: string): string { + let sum = 0; + for (let i = 0; i <= s.length; i++) sum += s.charCodeAt(i); + return String(sum); +} + +function lineStarts(s: string): number[] { + const starts = [0]; + for (let i = 0; i < s.length; i++) if (s.charCodeAt(i) === 10) starts.push(i + 1); + return starts; +} + +function wordUnits(s: string): number { + let n = 0; + for (let i = 0; i < s.length; i++) if (isWordOrDigit(s.charCodeAt(i))) n++; + return n; +} + +function codeOf(t: string, i: number): number { + return t.charCodeAt(i % t.length); +} + +function mixed(s: string, t: string): number { + let n = 0; + for (let i = 0; i < s.length; i++) n = (n + s.charCodeAt(i) * codeOf(t, i)) % 1000003; + return n; +} + +function sameAt(a: string, b: string): number { + let n = 0; + const end = Math.min(a.length, b.length); + for (let i = 0; i < end; i++) if (a.charCodeAt(i) === b.charCodeAt(i)) n++; + return n; +} + +function surrogates(s: string): string { + let high = 0, + low = 0; + for (let i = 0; i < s.length; i++) { + const c = s.charCodeAt(i); + if (c >= 0xd800 && c < 0xdc00) high++; + else if (c >= 0xdc00 && c < 0xe000) low++; + } + return `${high}/${low}`; +} + +function wordCount(s: string): number { + let pos = 0, + n = 0; + const end = s.length; + while (pos < end) { + while (pos < end && s.charCodeAt(pos) === 32) pos++; + if (pos >= end) break; + n++; + while (pos < end && s.charCodeAt(pos) !== 32) pos++; + } + return n; +} + +function wordUnitRuns(s: string): number { + let pos = 0, + total = 0; + while (pos < s.length) { + if (isWordUnit(s.charCodeAt(pos))) { + const start = pos; + while (pos < s.length && isWordOrDigit(s.charCodeAt(pos))) pos++; + total += pos - start; + } else pos = (pos + 1) | 0; + } + return total; +} + +function doubled(s: string): number { + let pos = 0, + n = 0; + while (pos < s.length) { + if (s.charCodeAt(pos) === s.charCodeAt(pos + 1)) n++; + pos += 1; + } + return n; +} + +class Scanner { + pos = 0; + src: string; + constructor(src: string) { + this.src = src; + } + line(): number { + const src = this.src; + const start = this.pos; + let pos = start; + while (pos < src.length && src.charCodeAt(pos) !== 10) pos++; + this.pos = pos + 1; + return pos - start; + } +} + +function lineLengths(s: string): number { + const scanner = new Scanner(s); + let total = 0, + lines = 0; + while (scanner.pos < s.length) { + total = (total * 31 + scanner.line()) % 1000003; + lines++; + } + return total * 1000 + lines; +} + +function remaining(s: string): number { + let pos = 0; + let sum = 0; + while (pos < s.length) { + if (s.charCodeAt(pos) === 32) sum += s.length - pos; + pos++; + } + return sum; +} + +function lastLineLength(s: string): number { + let last = s.length; + for (let i = 0; i < s.length; i++) if (s.charCodeAt(i) === 10) last = s.length - i - 1; + return last; +} + +function from(s: string, start: number): number { + let pos = start; + let sum = 0; + while (pos < s.length) { + sum = sum * 3 + s.charCodeAt(pos); + pos++; + } + return sum; +} + +const words = ["Größe", "naïve", "façade", "東京", "ok", "✓", "mañana", "plain", "😀", "end\n"]; +function text(count: number, seed: number): string { + let out = ""; + for (let k = 0; k < count; k++) out += words[(k * 7 + seed) % words.length] + (k % 5 === 0 ? " " : " "); + return out; +} + +const big = text(3000, 1); +const other = text(2000, 4); +const ascii = big.replace(/[^\x00-\x7f]/g, "x"); +const short = "café ✓ 東京"; +const lone = "a\uD800b\uDFFFc " + big.slice(0, 500) + "\uD83D"; +for (let pass = 0; pass < 3; pass++) { + console.log( + pass, + spaces(big), + hash(big), + rises(big), + backwards(big), + pastEnd(big), + lineStarts(big).length, + wordUnits(big), + ); + console.log(" ", spaces(other), hash(other), spaces(big), hash(other), wordUnits(other)); + console.log(" ", mixed(big, other), sameAt(big, other), surrogates(big), surrogates(lone)); + console.log(" ", spaces(ascii), hash(ascii), spaces(short), hash(short), hash(lone), rises(lone)); + console.log(" ", wordCount(big), wordUnitRuns(big), doubled(big), lineLengths(big)); + console.log(" ", wordCount(ascii), wordUnitRuns(other), doubled(lone), lineLengths(lone), wordCount("")); + const fresh = text(40 + pass, pass) + "ü"; + console.log(" ", remaining(big), remaining(ascii), lastLineLength(big), lastLineLength(other)); + console.log(" ", from(fresh, fresh.length), from(fresh, fresh.length - 3), from(big, big.length - 4)); +} + +let grown = text(1500, 2); +for (let round = 0; round < 3; round++) { + console.log("grown", round, grown.length, spaces(grown), hash(grown), hash(grown)); + grown += text(200, round) + "Ünïcödé"; +} +console.log("empty", spaces(""), hash(""), pastEnd(""), lineStarts("").length); diff --git a/tests/harness/corpus-costs/7305-string-unit-loop-versions.ts.json b/tests/harness/corpus-costs/7305-string-unit-loop-versions.ts.json new file mode 100644 index 000000000..f40375eee --- /dev/null +++ b/tests/harness/corpus-costs/7305-string-unit-loop-versions.ts.json @@ -0,0 +1 @@ +{ "plain": 10500, "san": 14500 } From 3dcd7308410edd057835a03a815e66617b5c8073 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 22:50:14 -0500 Subject: [PATCH 048/259] Detect class cycles by class identity when inspecting static fields --- packages/runtime/src/scr_inspect.c | 10 ++++--- .../6344-inspect-function-properties.cjs | 26 +++++++++++++++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/packages/runtime/src/scr_inspect.c b/packages/runtime/src/scr_inspect.c index 5f888e4c4..b3763f7dc 100644 --- a/packages/runtime/src/scr_inspect.c +++ b/packages/runtime/src/scr_inspect.c @@ -1609,9 +1609,11 @@ static ScrStr *scr_insp_dyn_func(ScrDyn *d, double recurse, double depth) { return tag; } /* A function already on the traversal stack renders as [Circular *N], - * keyed by the closure every box of the function shares, even past the - * depth limit. */ - double circular = scr_insp_circ_check(owner); + * even past the depth limit. Its identity is the class object for a class + * (each dynamic box of a class may carry its own closure) and the closure + * every box of a function shares otherwise. */ + const void *identity = cls ? (const void *)cls : (const void *)owner; + double circular = scr_insp_circ_check(identity); if (circular > 0) { scr_dyn_release(table); scr_str_release(tag); @@ -1628,7 +1630,7 @@ static ScrStr *scr_insp_dyn_func(ScrDyn *d, double recurse, double depth) { prefix[tag->len] = '\0'; scr_str_release(tag); size_t nseen = g_nseen; - g_pending_seen = owner; + g_pending_seen = identity; ScrStr *rendered = scr_insp_obj(table, recurse, depth, prefix); g_pending_seen = NULL; if (g_nseen > nseen) g_nseen = nseen; diff --git a/tests/corpus/6344-inspect-function-properties.cjs b/tests/corpus/6344-inspect-function-properties.cjs index 2b1c1aae7..5cab04172 100644 --- a/tests/corpus/6344-inspect-function-properties.cjs +++ b/tests/corpus/6344-inspect-function-properties.cjs @@ -34,3 +34,29 @@ shallow(S); shallow(A); console.log(util.inspect(g, { depth: 0 })); shallow(g); + +// A class that reaches itself through its static properties is one cycle, +// whichever dynamic box of it the inspection meets. +class Loop { + static get hidden() { + return 1; + } +} +Loop.self = Loop; +Loop.label = 'loop'; +class Left { + static get hidden() { + return 2; + } +} +class Right { + static get hidden() { + return 3; + } +} +Left.other = Right; +Right.other = Left; +show(Loop); +show(Left); +show([Loop, Loop]); +show({ a: Left, b: Right }); From f986d76d3ba7a2b9f6f83e68aa39db4417c80296 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 22:57:22 -0500 Subject: [PATCH 049/259] Bound Brotli parameter names in error messages --- .../8129-brotli-long-param-name.cjs.json | 6 +++++ packages/runtime/src/scr_brotli.c | 12 +++++++--- packages/runtime/test/common-symbols.test.ts | 1 + tests/corpus/8129-brotli-long-param-name.cjs | 23 +++++++++++++++++++ .../8129-brotli-long-param-name.cjs.json | 1 + 5 files changed, 40 insertions(+), 3 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8129-brotli-long-param-name.cjs.json create mode 100644 tests/corpus/8129-brotli-long-param-name.cjs create mode 100644 tests/harness/corpus-costs/8129-brotli-long-param-name.cjs.json diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8129-brotli-long-param-name.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8129-brotli-long-param-name.cjs.json new file mode 100644 index 000000000..33ef96201 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8129-brotli-long-param-name.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8129-brotli-long-param-name.cjs" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_brotli.c b/packages/runtime/src/scr_brotli.c index 617b0c60f..f66ecae75 100644 --- a/packages/runtime/src/scr_brotli.c +++ b/packages/runtime/src/scr_brotli.c @@ -161,10 +161,16 @@ static uint32_t scr_brotli_uint32(const ScrDyn *v) { return (uint32_t)m; } +/* ERR_BROTLI_INVALID_PARAM: the whole key, then Node's text. */ static void scr_brotli_invalid_param(const ScrStr *key) { - char message[160]; - int n = snprintf(message, sizeof message, "%.*s is not a valid Brotli parameter", (int)key->len, key->data); - scr_throw_error_msg_code(SCR_ERR_RANGE, message, (size_t)n, "ERR_BROTLI_INVALID_PARAM"); + static const char suffix[] = " is not a valid Brotli parameter"; + size_t len = key->len + sizeof suffix - 1; + char *message = malloc(len); + if (!message) scr_brotli_oom(); + memcpy(message, key->data, key->len); + memcpy(message + key->len, suffix, sizeof suffix - 1); + scr_throw_error_msg_code(SCR_ERR_RANGE, message, len, "ERR_BROTLI_INVALID_PARAM"); + free(message); } /* opts.params: each own key must name a parameter (0..8) once, and each diff --git a/packages/runtime/test/common-symbols.test.ts b/packages/runtime/test/common-symbols.test.ts index 43d4461e6..344bd01d6 100644 --- a/packages/runtime/test/common-symbols.test.ts +++ b/packages/runtime/test/common-symbols.test.ts @@ -38,6 +38,7 @@ async function commonSymbols(label: string, compiler: string[]): Promise Date: Fri, 23 Oct 2026 22:59:39 -0500 Subject: [PATCH 050/259] Divide by Math.pow(2, n) as a multiply by its reciprocal A quotient x / Math.pow(2, n) divided on every evaluation, and a division's latency bounds loops that carry the quotient, such as a key that keeps its low bits with k - Math.floor(k / Math.pow(2, n)) * Math.pow(2, n). A divisor that is a positive power of two from 2^-1022 to 2^1022 has a reciprocal that is a power of two too, whose bits are 0x7FE0000000000000 minus the divisor's, and the product with it is the quotient for every dividend. The quotient now multiplies by that reciprocal when the divisor's bits are such a power, and divides otherwise. Corpus 8180 compares the quotient with an ordinary division for every integer exponent from -1080 to 1030, including divisors that are subnormal, zero or infinite, and for exponents that are not integers. --- .../src/backend/llvm/expr-primitives.ts | 3 + .../src/backend/llvm/lib-filesystem.ts | 53 ++++++++++++++++- .../power-of-two-quotient-emission.test.ts | 46 +++++++++++++++ .../tests/corpus/8180-pow2-quotients.ts.json | 6 ++ tests/corpus/8180-pow2-quotients.ts | 57 +++++++++++++++++++ .../corpus-costs/8180-pow2-quotients.ts.json | 1 + 6 files changed, 165 insertions(+), 1 deletion(-) create mode 100644 packages/compiler/test/power-of-two-quotient-emission.test.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8180-pow2-quotients.ts.json create mode 100644 tests/corpus/8180-pow2-quotients.ts create mode 100644 tests/harness/corpus-costs/8180-pow2-quotients.ts.json diff --git a/packages/compiler/src/backend/llvm/expr-primitives.ts b/packages/compiler/src/backend/llvm/expr-primitives.ts index 04af0fcef..ccbe3edcc 100644 --- a/packages/compiler/src/backend/llvm/expr-primitives.ts +++ b/packages/compiler/src/backend/llvm/expr-primitives.ts @@ -46,6 +46,7 @@ import { type ArrayAccess, } from "./dense-array-access.js"; import { emitWrappingSum, markWrappingOperands } from "./wrapping-sums.js"; +import { emitPowerOfTwoQuotient, isPowerOfTwoCall } from "./lib-filesystem.js"; /** The signed integer predicates of the number compares. */ const INTEGER_COMPARES: Record = { @@ -348,6 +349,8 @@ export function emitOperatorExpr( : emitCheckedRemainder(host, l, r, li, ri); if (checked) return checked; } + if (e.op === "/" && isPowerOfTwoCall(e.right)) + return { name: emitPowerOfTwoQuotient(host, l.name, r.name), type: e.type }; if (arith[e.op] !== undefined) { B.line(`${t} = ${arith[e.op]} double ${l.name}, ${r.name}`); const uint32 = emitWrappingSum(host, e, l, r, li, ri); diff --git a/packages/compiler/src/backend/llvm/lib-filesystem.ts b/packages/compiler/src/backend/llvm/lib-filesystem.ts index 7d9be632d..f0b766936 100644 --- a/packages/compiler/src/backend/llvm/lib-filesystem.ts +++ b/packages/compiler/src/backend/llvm/lib-filesystem.ts @@ -1,7 +1,7 @@ /* Focused LLVM library-call emission extracted from emitter.ts. */ import { InternalCompilerError } from "../../errors.js"; import { undefinedArmTag } from "../../ir/analysis.js"; -import { DYN, F64, STATS_T, STRING } from "../../ir/ir.js"; +import { DYN, F64, STATS_T, STRING, type IrExpr } from "../../ir/ir.js"; import { mangleRecordNew } from "../mangle.js"; import { arrNewCall, traceArg, vAdapters } from "./shapes.js"; import type { LlvmEmitterContext, LibCallExpr, LlValue } from "./expr-context.js"; @@ -1027,6 +1027,57 @@ function emitPowerOfTwo(host: LlvmEmitterContext, n: string): string { return out; } +/** `Math.pow(2, n)`, the divisor emitPowerOfTwoQuotient takes. */ +export function isPowerOfTwoCall(e: IrExpr): boolean { + return ( + e.kind === "libCall" && + e.fn === "math.pow" && + e.args.length === 2 && + e.args[0]!.kind === "numLit" && + e.args[0]!.value === 2 + ); +} + +/** `left / divisor` for a divisor that is usually a power of two + * (`x / Math.pow(2, n)`). A positive power of two from 2^-1022 to 2^1022 + * has a reciprocal that is a power of two too, whose bits are + * 0x7FE0000000000000 minus the divisor's, and the product with it is the + * quotient for every `left`: both are `left` scaled by the same power of + * two, rounded once. Any other divisor divides. */ +export function emitPowerOfTwoQuotient( + host: LlvmEmitterContext, + left: string, + divisor: string, +): string { + const B = host.B; + const bits = B.tmp(), + mantissa = B.tmp(), + plain = B.tmp(), + biased = B.tmp(), + offset = B.tmp(), + normal = B.tmp(), + power = B.tmp(), + inverseBits = B.tmp(), + inverse = B.tmp(), + scaled = B.tmp(), + divided = B.tmp(), + out = B.tmp(); + B.line(`${bits} = bitcast double ${divisor} to i64`); + B.line(`${mantissa} = and i64 ${bits}, ${2n ** 52n - 1n}`); + B.line(`${plain} = icmp eq i64 ${mantissa}, 0`); + // Biased exponents 1 to 2045 with a clear sign bit. + B.line(`${biased} = lshr i64 ${bits}, 52`); + B.line(`${offset} = sub i64 ${biased}, 1`); + B.line(`${normal} = icmp ult i64 ${offset}, 2045`); + B.line(`${power} = and i1 ${plain}, ${normal}`); + B.line(`${inverseBits} = sub i64 ${0x7fe0000000000000n}, ${bits}`); + B.line(`${inverse} = bitcast i64 ${inverseBits} to double`); + B.line(`${scaled} = fmul double ${left}, ${inverse}`); + B.line(`${divided} = fdiv double ${left}, ${divisor}`); + B.line(`${out} = select i1 ${power}, double ${scaled}, double ${divided}`); + return out; +} + export function emitPrimitiveLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlValue { const B = host.B; if (e.fn === "math.min" || e.fn === "math.max") { diff --git a/packages/compiler/test/power-of-two-quotient-emission.test.ts b/packages/compiler/test/power-of-two-quotient-emission.test.ts new file mode 100644 index 000000000..4b748a2a1 --- /dev/null +++ b/packages/compiler/test/power-of-two-quotient-emission.test.ts @@ -0,0 +1,46 @@ +import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile, deserializeModule } from "../src/index.js"; +import { emitLlvmModule } from "../src/backend/llvm/emitter.js"; + +test("a quotient by Math.pow(2, n) multiplies by the divisor's reciprocal power of two", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-pow2-quotient-")); + try { + const entry = join(dir, "main.ts"); + const outPath = join(dir, "main.ir.json"); + await writeFile( + entry, + ` +function scaled(x: number, n: number): number { return x / Math.pow(2, n); } +function plain(x: number, d: number): number { return x / d; } +function other(x: number, n: number): number { return x / Math.pow(3, n); } +console.log(scaled(3, 4), plain(3, 16), other(3, 4)); +`, + ); + const result = await compile(entry, { outDir: dir, outPath, outputKind: "ir" }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + const mod = deserializeModule(await readFile(outPath, "utf8")); + const ll = emitLlvmModule(mod); + const fn = (name: string): string => + new RegExp(`^define internal [^\\n]*@sc_[bf]+_${name}(?:\\.i32)?\\([^]*?^}`, "m").exec( + ll, + )![0]; + // The reciprocal's bits are 0x7FE0000000000000 minus the divisor's; a + // divisor that is not a power of two from 2^-1022 to 2^1022 divides. + const quotient = fn("scaled"); + expect(quotient).toContain(`sub i64 ${0x7fe0000000000000n}, `); + expect(quotient).toMatch(/fmul double %\w+, %\w+/); + expect(quotient).toMatch(/icmp ult i64 %\w+, 2045/); + expect(quotient).toMatch(/select i1 %\w+, double %\w+, double %\w+/); + expect(quotient.match(/ = fdiv double /g)).toHaveLength(1); + for (const name of ["plain", "other"]) { + expect(fn(name)).not.toContain(`${0x7fe0000000000000n}`); + expect(fn(name)).toMatch(/fdiv double/); + } + } finally { + await rm(dir, { recursive: true, force: true }); + } +}); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8180-pow2-quotients.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8180-pow2-quotients.ts.json new file mode 100644 index 000000000..58c36cf5d --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8180-pow2-quotients.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8180-pow2-quotients.ts" + ], + "diags": [] +} diff --git a/tests/corpus/8180-pow2-quotients.ts b/tests/corpus/8180-pow2-quotients.ts new file mode 100644 index 000000000..f98d4e46e --- /dev/null +++ b/tests/corpus/8180-pow2-quotients.ts @@ -0,0 +1,57 @@ +// x / Math.pow(2, n) over every integer exponent from -1080 to 1030, against +// the same divisor read back from an array (an ordinary division): zeros, +// subnormals, values next to the limits, infinities and NaN, and a divisor of +// 2 ** n that is subnormal, zero or Infinity. Non-integer, signed-zero, +// infinite and NaN exponents give divisors that are not powers of two. +function bits(x: number): string { + const view = new DataView(new ArrayBuffer(8)); + view.setFloat64(0, x); + return view.getBigUint64(0).toString(16).padStart(16, "0"); +} + +const values = [ + 1, -1, 3, 0.1, -7.25, 0, -0, 5e-324, -5e-324, 2.2250738585072014e-308, 1.7976931348623157e308, + -1.7976931348623157e308, 4503599627370497, 123456789.123, Infinity, -Infinity, NaN, +]; +const divisors: number[] = []; +for (let n = -1080; n <= 1030; n++) divisors.push(Math.pow(2, n)); + +const scratch = new DataView(new ArrayBuffer(8)); +let digest = 0; +let mismatches = 0; +for (let n = -1080; n <= 1030; n++) { + const divisor = divisors[n + 1080]!; + for (const x of values) { + const quotient = x / Math.pow(2, n); + const plain = x / divisor; + scratch.setFloat64(0, quotient); + digest = (Math.imul(digest, 31) + scratch.getUint32(0)) | 0; + digest = (Math.imul(digest, 31) + scratch.getUint32(4)) | 0; + if (!Object.is(quotient, plain)) { + mismatches++; + if (mismatches <= 5) console.log("mismatch", x, n, bits(quotient), bits(plain)); + } + } +} +console.log("digest", (digest >>> 0).toString(16), "mismatches", mismatches); + +for (const n of [-1075, -1074, -1023, -1022, -1, 0, 1, 52, 1022, 1023, 1024]) { + console.log(n, bits(3 / Math.pow(2, n)), bits(-5e-324 / Math.pow(2, n)), bits(1.7976931348623157e308 / Math.pow(2, n))); +} +for (const e of [0.5, -0.5, -0, 1e-300, 1023.0000001, -1074.5, Infinity, -Infinity, NaN, 2 ** 31, -(2 ** 31)]) { + console.log("exponent", e, bits(10 / Math.pow(2, e)), bits(-0 / Math.pow(2, e))); +} + +// A divisor that changes every pass, and one computed once. +let total = 0; +for (let i = 0; i < 100000; i++) { + const shift = (i % 40) - 20; + total += (i * 7 + 3) / Math.pow(2, shift); +} +console.log("total", total); +let key = 12345; +const width = 34; +for (let i = 0; i < 100000; i++) { + key = (key - Math.floor(key / Math.pow(2, width)) * Math.pow(2, width)) * 4 + (i % 4); +} +console.log("key", key); diff --git a/tests/harness/corpus-costs/8180-pow2-quotients.ts.json b/tests/harness/corpus-costs/8180-pow2-quotients.ts.json new file mode 100644 index 000000000..63f95b985 --- /dev/null +++ b/tests/harness/corpus-costs/8180-pow2-quotients.ts.json @@ -0,0 +1 @@ +{ "plain": 2301, "san": 3300 } From 0b4deda1d0598375ef9910fea491f55f1b3dc099 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 23:05:32 -0500 Subject: [PATCH 051/259] Print URL {} past the inspect depth limit --- packages/runtime/src/scr_dyn.h | 4 +++- packages/runtime/src/scr_inspect.c | 8 ++++++++ packages/runtime/src/scr_url.c | 3 +-- tests/corpus/8103-url-inspect.ts | 8 +++++++- 4 files changed, 19 insertions(+), 4 deletions(-) diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index 469c550ab..6e3eac7b5 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -1617,7 +1617,9 @@ typedef struct ScrDynHandleOps { bool inspect_bracketed_past_depth; /* The class's inspector formats its view with a new util.inspect call * (URL's does): the view renders from the top level with the caller's - * depth, and its lines take the caller's indentation. */ + * depth, and its lines take the caller's indentation. Past the depth + * limit the inspector returns the instance, which has no own + * properties, so util.inspect prints `cls {}`. */ bool inspect_view_nested; /* The @@toStringTag when it differs from cls: String() answers * "[object ]" and util.inspect prints ` [] `, or diff --git a/packages/runtime/src/scr_inspect.c b/packages/runtime/src/scr_inspect.c index f5e429374..78f2fa71e 100644 --- a/packages/runtime/src/scr_inspect.c +++ b/packages/runtime/src/scr_inspect.c @@ -1717,6 +1717,14 @@ ScrStr *scr_insp_dyn(ScrDyn *d, double recurse, double depth) { * depth limit (`depth < 0`); the ones that return `this` there * print util.inspect's `[cls]`. */ if (recurse > depth && !ops->inspect_view_empty) { + /* A nested-view inspector returns the instance itself there, + * which has no own properties: `URL {}`. */ + if (ops->inspect_view_nested) { + InspBuf out = {0}; + ib_cstr(&out, ops->cls); + ib_cstr(&out, " {}"); + return ib_take(&out); + } if (!ops->inspect_bracketed_past_depth) return scr_str_new(ops->cls, strlen(ops->cls)); InspBuf out = {0}; ib_char(&out, '['); diff --git a/packages/runtime/src/scr_url.c b/packages/runtime/src/scr_url.c index 0ea0e5824..09ccb87fe 100644 --- a/packages/runtime/src/scr_url.c +++ b/packages/runtime/src/scr_url.c @@ -1743,7 +1743,7 @@ static bool scr_native_url_set(void *ptr, const char *key, size_t len, const Scr /* util.inspect's view of a URL: the properties Node's URL inspector lists, * in its order, with the live searchParams object. Past the depth limit * the inspector returns the URL itself, which util.inspect prints as - * [URL]. */ + * `URL {}` (it has no own properties). */ static ScrDyn *scr_native_url_inspect_view(void *ptr) { static const char *const keys[] = {"href", "origin", "protocol", "username", "password", "host", "hostname", "port", "pathname", "search", @@ -1850,7 +1850,6 @@ ScrDyn *scr_dyn_native_url(ScrUrl *value) { .get = &scr_native_url_get, .set = &scr_native_url_set, .inspect_view = &scr_native_url_inspect_view, - .inspect_bracketed_past_depth = true, .inspect_view_nested = true, }; scr_dyn_handle_install(SCR_DYNH_URL, &ops); diff --git a/tests/corpus/8103-url-inspect.ts b/tests/corpus/8103-url-inspect.ts index ef42709f8..005bb5831 100644 --- a/tests/corpus/8103-url-inspect.ts +++ b/tests/corpus/8103-url-inspect.ts @@ -1,6 +1,7 @@ // util.inspect and console.log of URL values print Node's URL view: the // URL's properties in its inspector's order, the live searchParams, and -// [URL] past the depth limit. URLSearchParams print their pairs. +// `URL {}` past the depth limit. URLSearchParams print their pairs, and +// [Object] past the depth limit. import { inspect } from "node:util"; const url = new URL("https://user:pass@example.com:8080/a/b?x=1&y=2#h"); @@ -17,3 +18,8 @@ console.log(inspect({ params }, { depth: 0 })); const long = new URLSearchParams(); for (let i = 0; i < 12; i++) long.append(`key${i}`, `value number ${i}`); console.log({ long }); +// Past the depth limit a URL prints as `URL {}` and URLSearchParams as +// [Object], nested or at a negative depth. +console.log(inspect({ a: { b: { c: url } } }), inspect(url, { depth: -1 })); +console.log(inspect({ a: { b: { c: params } } }), inspect(params, { depth: -1 })); +console.log(inspect({ a: url }, { depth: 0 }), inspect({ a: { b: url } }, { depth: 1 })); From 8c94f6f10c4cd613e65eb7cab70e333c219bda35 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 23:10:56 -0500 Subject: [PATCH 052/259] Fix Date setter edge cases and the library profile fences --- .../lowering/builtins/date-classes.ts | 10 ++-- .../src/frontend/lowering/builtins/dates.ts | 9 ++-- .../src/frontend/lowering/date-values.ts | 37 +++++++++++-- .../frontend/lowering/expressions/binary.ts | 22 ++++++++ .../corpus/8027-date-setter-order.ts.json | 6 +++ .../8028-date-setter-order-dynamic.mjs.json | 6 +++ tests/corpus/8027-date-setter-order.ts | 53 +++++++++++++++++++ .../corpus/8028-date-setter-order-dynamic.mjs | 17 ++++++ .../8027-date-setter-order.ts.json | 1 + .../8028-date-setter-order-dynamic.mjs.json | 1 + tests/harness/library-profile.test.ts | 1 + 11 files changed, 151 insertions(+), 12 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8027-date-setter-order.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8028-date-setter-order-dynamic.mjs.json create mode 100644 tests/corpus/8027-date-setter-order.ts create mode 100644 tests/corpus/8028-date-setter-order-dynamic.mjs create mode 100644 tests/harness/corpus-costs/8027-date-setter-order.ts.json create mode 100644 tests/harness/corpus-costs/8028-date-setter-order-dynamic.mjs.json diff --git a/packages/compiler/src/frontend/lowering/builtins/date-classes.ts b/packages/compiler/src/frontend/lowering/builtins/date-classes.ts index c8aab8687..9d152de56 100644 --- a/packages/compiler/src/frontend/lowering/builtins/date-classes.ts +++ b/packages/compiler/src/frontend/lowering/builtins/date-classes.ts @@ -255,17 +255,19 @@ export function lowerInheritedDateMethodCall( loc, }); if (isDateSetter(name) && name !== "setTime") { - // The field setters change the Date the class's time slot holds. + // The field setters change the Date the class's time slot holds once + // the arguments are evaluated: an argument that calls setTime on the + // instance gives the slot a new Date. const date = lowerer.declareHiddenLocal("%dateTime", DATE_T); + const current = varRef(date.id, DATE_T, loc); + const time: IrExpr = { kind: "libCall", fn: "date.getTime", args: [current], type: F64, loc }; + const next = dateSetterTime(lowerer, call, name, stmts, time); stmts.push({ kind: "varDecl", localId: date.id, init: timeOf(lowerer, value, root, loc), loc, }); - const current = varRef(date.id, DATE_T, loc); - const time: IrExpr = { kind: "libCall", fn: "date.getTime", args: [current], type: F64, loc }; - const next = dateSetterTime(lowerer, call, name, stmts, time); return done({ kind: "libCall", fn: "date.store", args: [current, next], type: F64, loc }); } if (name === "setTime") { diff --git a/packages/compiler/src/frontend/lowering/builtins/dates.ts b/packages/compiler/src/frontend/lowering/builtins/dates.ts index 79696d1ba..075047606 100644 --- a/packages/compiler/src/frontend/lowering/builtins/dates.ts +++ b/packages/compiler/src/frontend/lowering/builtins/dates.ts @@ -342,9 +342,9 @@ function lowerDateSetter( /** The new time value of setter `name` called with `call`'s arguments on a * Date whose time value `time` reads: the arguments evaluate into * temporaries appended to `stmts` (ToNumber of each, an undefined one is - * NaN), and the result reads `time` after them. Missing optional arguments - * keep their fields; arguments past a setter's last one are evaluated and - * ignored. */ + * NaN), and the result reads `time` after them. A missing first argument + * is NaN; missing optional arguments keep their fields; arguments past a + * setter's last one are evaluated and ignored. */ export function dateSetterTime( lowerer: Lowerer, call: ts.CallExpression, @@ -374,7 +374,8 @@ export function dateSetterTime( loc, }; const setter = DATE_FIELD_SETTERS.get(name)!; - const used = args.slice(0, setter.max); + // The first argument is required: a missing one is undefined, so NaN. + const used = args.length === 0 ? [number(Number.NaN)] : args.slice(0, setter.max); const operands = [...used]; while (operands.length < 4) operands.push(number(0)); return { diff --git a/packages/compiler/src/frontend/lowering/date-values.ts b/packages/compiler/src/frontend/lowering/date-values.ts index 669bc1dbc..f769e0866 100644 --- a/packages/compiler/src/frontend/lowering/date-values.ts +++ b/packages/compiler/src/frontend/lowering/date-values.ts @@ -102,7 +102,7 @@ function decideTimeValueDate(lowerer: Lowerer, decl: ts.VariableDeclaration): bo if (!ok) return; if (ts.isIdentifier(node) && node !== decl.name && node.text === decl.name.text) { if (lowerer.checker.getSymbolAtLocation(node) === symbol) { - const use = enclosingFunction(node) === fn ? timeValueUse(lowerer, node) : null; + const use = enclosingFunction(node) === fn ? timeValueUse(lowerer, node, symbol) : null; if (use === null) ok = false; else if (use === "set") sets = true; } @@ -174,7 +174,11 @@ function enclosingFunction(node: ts.Node): ts.FunctionLikeDeclaration | null { /** How a use of the binding uses its time value: "read" for a use that * reads only the time value, "set" for a setter call that replaces it, or * null for any other use. */ -function timeValueUse(lowerer: Lowerer, id: ts.Identifier): "read" | "set" | null { +function timeValueUse( + lowerer: Lowerer, + id: ts.Identifier, + symbol: ts.Symbol, +): "read" | "set" | null { let node: ts.Node = id; while (ts.isParenthesizedExpression(node.parent)) node = node.parent; const parent = node.parent; @@ -192,12 +196,34 @@ function timeValueUse(lowerer: Lowerer, id: ts.Identifier): "read" | "set" | nul if (isDateSetter(parent.name.text)) return "set"; return TIME_VALUE_METHODS.has(parent.name.text) ? "read" : null; } - return readsTimeValue(lowerer, node, parent) ? "read" : null; + return readsTimeValue(lowerer, node, parent, symbol) ? "read" : null; +} + +/** True when `node` calls a setter on the binding `symbol` names. */ +function callsSetterOf(lowerer: Lowerer, node: ts.Node, symbol: ts.Symbol): boolean { + if ( + ts.isCallExpression(node) && + ts.isPropertyAccessExpression(node.expression) && + isDateSetter(node.expression.name.text) + ) { + let receiver = node.expression.expression; + while (ts.isParenthesizedExpression(receiver)) receiver = receiver.expression; + if (ts.isIdentifier(receiver) && lowerer.checker.getSymbolAtLocation(receiver) === symbol) + return true; + } + return ( + ts.forEachChild(node, (child) => callsSetterOf(lowerer, child, symbol) || undefined) ?? false + ); } /** A use of the binding, other than a method call, that reads only its * time value. */ -function readsTimeValue(lowerer: Lowerer, node: ts.Node, parent: ts.Node): boolean { +function readsTimeValue( + lowerer: Lowerer, + node: ts.Node, + parent: ts.Node, + symbol: ts.Symbol, +): boolean { if (ts.isTemplateSpan(parent)) return parent.expression === node; // Unary + and -, the number hint. if (ts.isPrefixUnaryExpression(parent)) @@ -222,6 +248,9 @@ function readsTimeValue(lowerer: Lowerer, node: ts.Node, parent: ts.Node): boole ); } if (ts.isBinaryExpression(parent)) { + // A left operand converts after the right one is evaluated: a setter + // there changes the time value the comparison or concatenation reads. + if (parent.left === node && callsSetterOf(lowerer, parent.right, symbol)) return false; const other = parent.left === node ? parent.right : parent.left; const otherKind = lowerer.mapTypeOf(lowerer.typeOf(other))?.kind; if (RELATIONAL.has(parent.operatorToken.kind)) return otherKind === "date"; diff --git a/packages/compiler/src/frontend/lowering/expressions/binary.ts b/packages/compiler/src/frontend/lowering/expressions/binary.ts index de6648836..590fa745b 100644 --- a/packages/compiler/src/frontend/lowering/expressions/binary.ts +++ b/packages/compiler/src/frontend/lowering/expressions/binary.ts @@ -2037,6 +2037,28 @@ export function lowerBinary(lowerer: Lowerer, expr: ts.BinaryExpression): IrExpr loc, }; if (left.type.kind === "string" || right.type.kind === "string") { + // A Date on the left converts after the right operand is + // evaluated, which can run its setters. + if (left.type.kind === "date" && !isSafeToRepeat(right)) { + const date = lowerer.declareHiddenLocal("%plus", left.type); + const other = lowerer.declareHiddenLocal("%plus", right.type); + return { + kind: "seqExpr", + stmts: [ + { kind: "varDecl", localId: date.id, init: left, loc }, + { kind: "varDecl", localId: other.id, init: right, loc }, + ], + result: { + kind: "strConcat", + left: concatOperand(lowerer, varRef(date.id, left.type, loc), expr.left), + right: concatOperand(lowerer, varRef(other.id, right.type, loc), expr.right), + type: STRING, + loc, + }, + type: STRING, + loc, + }; + } return { kind: "strConcat", left: concatOperand(lowerer, left, expr.left), diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8027-date-setter-order.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8027-date-setter-order.ts.json new file mode 100644 index 000000000..cfdfddfc6 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8027-date-setter-order.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8027-date-setter-order.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8028-date-setter-order-dynamic.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8028-date-setter-order-dynamic.mjs.json new file mode 100644 index 000000000..0a1b69c5f --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8028-date-setter-order-dynamic.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8028-date-setter-order-dynamic.mjs" + ], + "diags": [] +} diff --git a/tests/corpus/8027-date-setter-order.ts b/tests/corpus/8027-date-setter-order.ts new file mode 100644 index 000000000..d0a175c2f --- /dev/null +++ b/tests/corpus/8027-date-setter-order.ts @@ -0,0 +1,53 @@ +// Date setters and evaluation order: a setter called without arguments +// makes the Date invalid, an argument that calls setTime on the same +// Date subclass instance is seen by the setter, and a comparison or +// concatenation reads its left Date after the right side runs a setter. +export {}; +process.env.TZ = "UTC"; + +const show = (label: string, d: Date): void => { + console.log(label, d.getTime(), Number.isNaN(d.getTime()) ? "invalid" : d.toISOString()); +}; + +// No arguments: the first argument is undefined, so NaN. +const local = new Date(Date.UTC(2026, 5, 15, 9, 30)); +// @ts-expect-error: the first argument is required +console.log(local.setHours(), Number.isNaN(local.getTime())); +const utc = new Date(Date.UTC(2026, 5, 15, 9, 30)); +// @ts-expect-error: the first argument is required +console.log(utc.setUTCMonth(), utc.setUTCFullYear(2020)); +show("utc after", utc); +const kept = new Date(Date.UTC(2026, 5, 15)); +const keep = kept; +// @ts-expect-error: the first argument is required +console.log(keep.setMinutes(), kept.getTime()); + +class Stamp extends Date { + label(): string { + return `stamp ${this.toISOString()}`; + } +} +const stamp = new Stamp(Date.UTC(2026, 0, 1)); +// @ts-expect-error: the first argument is required +console.log(stamp.setSeconds(), Number.isNaN(stamp.getTime())); +stamp.setTime(Date.UTC(2026, 0, 2)); +// @ts-expect-error: the first argument is required +console.log(stamp.setUTCDate(), stamp.setUTCFullYear(2024, 1, 29), stamp.label()); + +// An argument that calls setTime on the same instance. +const moved = new Stamp(Date.UTC(2026, 3, 10, 12)); +console.log(moved.setUTCHours((moved.setTime(Date.UTC(2000, 0, 1)), 5)), moved.label()); +const plain = new Date(Date.UTC(2026, 3, 10, 12)); +console.log(plain.setUTCMinutes((plain.setTime(Date.UTC(2001, 0, 1)), 7))); +show("plain", plain); + +// The left operand converts after the right operand runs a setter. +const a = new Date(Date.UTC(2026, 0, 1)); +const b = new Date(Date.UTC(2026, 0, 2)); +console.log(a < (a.setUTCDate(3), b), a > b); +const c = new Date(Date.UTC(2026, 0, 1)); +console.log(c >= (c.setTime(0), new Date(1)), c <= new Date(1)); +const s = new Date(Date.UTC(2026, 0, 1)); +console.log(s + (s.setUTCFullYear(1999), "!")); +const n = new Date(Date.UTC(2026, 0, 1)); +console.log(+n === (n.setTime(5), 5), +n); diff --git a/tests/corpus/8028-date-setter-order-dynamic.mjs b/tests/corpus/8028-date-setter-order-dynamic.mjs new file mode 100644 index 000000000..f52e410c1 --- /dev/null +++ b/tests/corpus/8028-date-setter-order-dynamic.mjs @@ -0,0 +1,17 @@ +// Date setters reached through untyped values: without arguments each +// one makes the Date invalid, and an argument that calls setTime on the +// same Date is seen by the setter. +process.env.TZ = "UTC"; + +const names = [ + "setMilliseconds", "setSeconds", "setMinutes", "setHours", "setDate", "setMonth", "setFullYear", + "setUTCMilliseconds", "setUTCSeconds", "setUTCMinutes", "setUTCHours", "setUTCDate", "setUTCMonth", "setUTCFullYear", +]; +for (const name of names) { + const d = new Date(Date.UTC(2026, 5, 15)); + console.log(name, d[name](), d.getTime()); +} +const d = new Date(Date.UTC(2026, 3, 10, 12)); +console.log(d.setUTCHours((d.setTime(Date.UTC(2000, 0, 1)), 5)), d.toISOString()); +const a = new Date(Date.UTC(2026, 0, 1)); +console.log(a < (a.setUTCDate(3), new Date(Date.UTC(2026, 0, 2)))); diff --git a/tests/harness/corpus-costs/8027-date-setter-order.ts.json b/tests/harness/corpus-costs/8027-date-setter-order.ts.json new file mode 100644 index 000000000..aff4bec01 --- /dev/null +++ b/tests/harness/corpus-costs/8027-date-setter-order.ts.json @@ -0,0 +1 @@ +{ "plain": 2489, "san": 3288 } diff --git a/tests/harness/corpus-costs/8028-date-setter-order-dynamic.mjs.json b/tests/harness/corpus-costs/8028-date-setter-order-dynamic.mjs.json new file mode 100644 index 000000000..a7aeb13a5 --- /dev/null +++ b/tests/harness/corpus-costs/8028-date-setter-order-dynamic.mjs.json @@ -0,0 +1 @@ +{ "plain": 2430, "san": 2975 } diff --git a/tests/harness/library-profile.test.ts b/tests/harness/library-profile.test.ts index b39daefa1..9ced69b5c 100644 --- a/tests/harness/library-profile.test.ts +++ b/tests/harness/library-profile.test.ts @@ -563,6 +563,7 @@ describe("library profile fences", () => { "stdlib.date.getUTCSeconds", "stdlib.date.now", "stdlib.date.parse", + "stdlib.date.setters", "stdlib.date.toDateString", "stdlib.date.toISOString", "stdlib.date.toString", From 36daee3f6187f755c758ac62647d3dbbde1528ce Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 23:16:58 -0500 Subject: [PATCH 053/259] Fix the CI failure --- scripts/zero-cost-compare.mjs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/scripts/zero-cost-compare.mjs b/scripts/zero-cost-compare.mjs index 160e33438..9247585e5 100644 --- a/scripts/zero-cost-compare.mjs +++ b/scripts/zero-cost-compare.mjs @@ -394,7 +394,8 @@ export function dynamicTierSymbols(names) { * not yet traced to its typed root. bench/thread-slots, * bench/channel-messages and bench/worker-messages, added later, link them * through worker messages: - * node:worker_threads values are dyn objects. bench/dynamic-methods is + * node:worker_threads values are dyn objects. bench/json-unions, added + * later too, decodes JSON.parse trees. bench/dynamic-methods is * untyped JavaScript. Every other bench workload is fully typed and must link none. The gate and * tests/harness/bench-dynamic-tier.test.ts enforce that, and the test also * fails when a listed workload stops linking them, so remove a workload here @@ -414,6 +415,7 @@ export const DYNAMIC_WORKLOADS = new Set([ "bench/typed-array-scan-workers", "bench/log-summary", "bench/inventory-report", + "bench/json-unions", ]); /** Names of the functions (text and weak symbols) in `nm` output. Mach-O From 043124071989a5a4f5c204a28662f38755422646 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 23:20:06 -0500 Subject: [PATCH 054/259] Reuse linked executables on Linux The native compiler's executable cache restored a linked executable only on darwin. On Linux every exe build linked again, even when the frontend and object caches answered the rest of the build. - The cache now opens on Linux when the linker is a clang driver. One link with `-v -Wl,-t` lists the driver's linker job and every file the linker loads; their identities are checked again before an entry is published and when it is restored. - On Linux a key's first link only records that it was linked. A later link of the same key traces and publishes, so a program built once pays no tracing. - The key names the runtime pack manifest by its file identity on Linux instead of by its text. - The executable and object caches share one digest of the LLVM text. - Content-addressed entries are hashed once, and identities are compared by field. darwin keeps its own driver check, dry run and key. --- packages/compiler/src/native/cache.ts | 34 +++++- packages/compiler/src/native/compiler.ts | 30 +++++- .../src/native/executable-cache-open.test.ts | 86 +++++++++++++++ .../src/native/executable-cache.test.ts | 58 ++++++++++ .../compiler/src/native/executable-cache.ts | 102 +++++++++++++----- 5 files changed, 278 insertions(+), 32 deletions(-) create mode 100644 packages/compiler/src/native/executable-cache-open.test.ts diff --git a/packages/compiler/src/native/cache.ts b/packages/compiler/src/native/cache.ts index 3c9bdf411..937b4b109 100644 --- a/packages/compiler/src/native/cache.ts +++ b/packages/compiler/src/native/cache.ts @@ -1,6 +1,7 @@ import { createHash } from "node:crypto"; import { closeSync, + existsSync, mkdirSync, mkdtempSync, openSync, @@ -88,14 +89,19 @@ export class NativeCache { } } - write(family: string, key: string, bytes: string | Uint8Array): void { + write( + family: string, + key: string, + bytes: string | Uint8Array, + digest = contentDigest(bytes), + ): void { let stage: string | null = null; try { const directory = join(this.root, family); mkdirSync(directory, { recursive: true, mode: 0o700 }); stage = mkdtempSync(join(directory, ".write-")); writeFileSync(join(stage, "payload"), bytes); - writeFileSync(join(stage, "digest"), contentDigest(bytes) + "\n"); + writeFileSync(join(stage, "digest"), digest + "\n"); const path = join(directory, key); // Concurrent writers publish identical content under the same key; // a reader between the two renames simply treats it as a miss. @@ -112,6 +118,29 @@ export class NativeCache { } } + /** Whether a marker or entry exists, without reading or checking it. */ + has(family: string, key: string): boolean { + return existsSync(join(this.root, family, key)); + } + + /** Records an empty marker that has() finds. */ + mark(family: string, key: string): void { + try { + const directory = join(this.root, family); + mkdirSync(directory, { recursive: true, mode: 0o700 }); + writeFileSync(join(directory, key), ""); + } catch { + /* Cache failures never change a build's result. */ + } + } + + /** Writes `bytes` under their content digest, and returns the digest. */ + writeContent(family: string, bytes: Uint8Array): string { + const digest = contentDigest(bytes); + this.write(family, digest, bytes, digest); + return digest; + } + /** Publish text parts without joining them into one string. */ writeParts(family: string, key: string, parts: Generator): void { let stage: string | null = null; @@ -149,6 +178,7 @@ export class NativeCache { "object", "sanitizer", "executable", + "linked", "binary", "dsym", "coverage", diff --git a/packages/compiler/src/native/compiler.ts b/packages/compiler/src/native/compiler.ts index a37d76f80..63769fba6 100644 --- a/packages/compiler/src/native/compiler.ts +++ b/packages/compiler/src/native/compiler.ts @@ -56,7 +56,7 @@ import { clearFenceEvalCaches } from "../library/fence-eval.js"; import { archiveNativeLibrary, localizeNativeLibrary, linkNativeWasmLibrary } from "./library.js"; import type { NativeToolchain } from "./toolchain.js"; import { evaluateNativeComptime } from "./comptime.js"; -import { contentDigest, fileDigest, type NativeCache } from "./cache.js"; +import { contentDigest, fileDigest, partsDigest, type NativeCache } from "./cache.js"; import { nativeProfileKey, nativeProfileRefusal, @@ -168,6 +168,7 @@ export class NativeCompiler { outputKind: "obj" | "asm", partitions = 1, profile?: NativeProfileOptions, + llvmDigest: () => string = () => fileDigest(input), ): string[] { const toolchain = this.toolchain; const outputs = nativePartitionPaths(output, partitions); @@ -186,7 +187,7 @@ export class NativeCompiler { key = contentDigest( JSON.stringify({ schema: 1, - llvm: fileDigest(input), + llvm: llvmDigest(), outputKind, optimization, source, @@ -253,6 +254,7 @@ export class NativeCompiler { stage: string, library: boolean, profile?: NativeProfileOptions, + llvmDigest?: () => string, ): string[] { // Library archives merge dev shards relocatably; executables link the // helper's program partitions directly. @@ -263,7 +265,16 @@ export class NativeCompiler { const split = llvm === null ? null : splitLlvmLibraryProgram(llvm); if (split === null) { const partitions = library ? 1 : nativeProgramPartitions(statSync(input).size); - return this.emitObject(input, output, source, optimization, "obj", partitions, profile); + return this.emitObject( + input, + output, + source, + optimization, + "obj", + partitions, + profile, + llvmDigest, + ); } const objects: string[] = []; for (const [index, shard] of split.shards.entries()) { @@ -358,6 +369,9 @@ export class NativeCompiler { return { ok: true, artifact: { kind: "ir", path: output } }; } const { llvm, features } = prepared; + // The executable and object caches key the same LLVM text. + let llvmDigest: string | undefined; + const digestLlvm = (): string => (llvmDigest ??= partsDigest(llvm)); const inputDirectory = join(stage, "input"); mkdirSync(inputDirectory); const llvmInput = outputKind === "llvm" ? stagedOutput : join(inputDirectory, "program.ll"); @@ -385,7 +399,14 @@ export class NativeCompiler { const executableCache = executablePack === null ? null - : openNativeExecutableCache(this.cache, toolchain, llvm, options, ffi, executablePack); + : openNativeExecutableCache( + this.cache, + toolchain, + digestLlvm, + options, + ffi, + executablePack, + ); const restored = executableCache?.restore(stagedOutput) ?? false; timing(restored ? "executable-cache-hit" : "executable-cache-miss"); if (!restored) { @@ -408,6 +429,7 @@ export class NativeCompiler { stage, false, profile, + digestLlvm, ); else this.emitObject( diff --git a/packages/compiler/src/native/executable-cache-open.test.ts b/packages/compiler/src/native/executable-cache-open.test.ts new file mode 100644 index 000000000..05e57148d --- /dev/null +++ b/packages/compiler/src/native/executable-cache-open.test.ts @@ -0,0 +1,86 @@ +import { chmodSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { afterEach, beforeEach, expect, test } from "vitest"; +import type { NativeRuntimeSelection } from "../backend/runtime-pack-native.js"; +import { NativeCache } from "./cache.js"; +import { openNativeExecutableCache } from "./executable-cache.js"; +import type { NativeToolchain } from "./toolchain.js"; + +const directories: string[] = []; +const saved = new Map(); +beforeEach(() => { + for (const name of ["SCRIPTC_LINKER", "SCRIPTC_LLVM_HELPER", "CC", "LDFLAGS", "LIBRARY_PATH"]) { + saved.set(name, process.env[name]); + delete process.env[name]; + } +}); +afterEach(() => { + for (const [name, value] of saved) { + if (value === undefined) delete process.env[name]; + else process.env[name] = value; + } + saved.clear(); + for (const path of directories.splice(0)) rmSync(path, { recursive: true, force: true }); +}); + +/** A toolchain whose linker is a driver script named `driver`; it answers + * `-print-prog-name=clang` with its own path. */ +function fixture(platform: string, driver: string) { + const root = mkdtempSync(join(tmpdir(), "scriptc-executable-cache-open-")); + directories.push(root); + const bin = join(root, "bin"); + const helper = join(root, "helper"); + const runtime = join(root, "runtime"); + for (const directory of [bin, helper, runtime]) mkdirSync(directory); + const linker = join(bin, driver); + writeFileSync(linker, '#!/bin/sh\necho "$0"\n'); + chmodSync(linker, 0o755); + writeFileSync(join(helper, "codegen"), "helper"); + writeFileSync(join(helper, "package.json"), "{}"); + writeFileSync(join(runtime, "package.json"), "{}"); + writeFileSync(join(runtime, "runtime-pack.json"), "{}"); + const toolchain = { + compilerVersion: "test", + target: { platform }, + helperExecutable: join(helper, "codegen"), + helperPackageRoot: helper, + runtimePackRoot: runtime, + linker, + linkerArgs: [], + dsymutil: "dsymutil", + } as unknown as NativeToolchain; + const pack = { + root: runtime, + manifest: { licenses: [] }, + packageText: "{}", + manifestText: "{}", + selected: { runtime: [], archives: [] }, + flavor: "release", + } as unknown as NativeRuntimeSelection; + const open = () => + openNativeExecutableCache( + new NativeCache(join(root, "cache")), + toolchain, + () => "llvm digest", + { outPath: join(root, "program"), outDir: root, optimization: "release" }, + null, + pack, + ); + return { open }; +} + +test.skipIf(process.platform === "win32")( + "Linux builds that link with a clang driver use the executable cache", + () => { + expect(fixture("linux", "clang").open()).not.toBeNull(); + expect(fixture("linux", "clang-22").open()).not.toBeNull(); + expect(fixture("linux", "gcc").open()).toBeNull(); + expect(fixture("windows", "clang").open()).toBeNull(); + expect(fixture("wasi", "clang").open()).toBeNull(); + // On darwin only Apple's driver at /usr/bin/clang qualifies. + expect(fixture("darwin", "clang").open()).toBeNull(); + process.env["SCRIPTC_LLVM_HELPER"] = "/elsewhere/codegen"; + expect(fixture("linux", "clang").open()).toBeNull(); + }, +); diff --git a/packages/compiler/src/native/executable-cache.test.ts b/packages/compiler/src/native/executable-cache.test.ts index 3199ef97f..e8019a5f9 100644 --- a/packages/compiler/src/native/executable-cache.test.ts +++ b/packages/compiler/src/native/executable-cache.test.ts @@ -217,3 +217,61 @@ test("a failed or empty link trace cannot publish a completed executable", () => }); expect(entry.trace([], f.stage)).toBe(false); }); + +test.each(["ld", "crt", "libc"] as const)( + "a Linux key's second link records the linker, startup objects and libc; replacing the %s misses", + (input) => { + const f = fixture(); + const lib = join(f.root, "lib"); + mkdirSync(lib); + const paths = { + ld: join(f.root, "ld"), + crt: join(lib, "Scrt1.o"), + libc: join(lib, "libc.so.6"), + }; + writeFileSync(paths.ld, "linker"); + writeFileSync(paths.crt, "startup object"); + writeFileSync(paths.libc, "c library"); + const nonshared = join(lib, "libc_nonshared.a"); + writeFileSync(nonshared, "archive"); + const program = join(f.stage, "program.o"); + writeFileSync(program, "program"); + // With -v, clang prints the linker job it runs, as -### would; GNU ld's + // -t names each file it loads, and an archive member as archive(member). + const job = ` "${paths.ld}" "-pie" "-o" "${f.output}" "${paths.crt}" "-L${lib}" "${program}" "-lc"`; + const loaded = [paths.crt, program, paths.libc, `${nonshared}(atexit.oS)`].join("\n"); + vi.mocked(spawnSync).mockImplementation((_command, args) => { + const verbose = (args as string[]).includes("-v"); + return { + pid: 1, + status: 0, + signal: null, + output: [], + stdout: verbose ? loaded + "\n" : "", + stderr: verbose ? job + "\n" : "", + }; + }); + const open = () => new NativeExecutableCache(f.cache, f.key, "clang", false, [f.runtime], true); + // A key's first link is not traced; the caller links the output itself. + expect(open().trace(["-o", f.output], f.stage)).toBe(false); + expect(spawnSync).not.toHaveBeenCalled(); + expect(open().restore(f.destination)).toBe(false); + // Its next link traces both the driver and the linker in one run. + const entry = open(); + expect(entry.trace(["-o", f.output], f.stage)).toBe(true); + expect(spawnSync).toHaveBeenCalledTimes(1); + expect(vi.mocked(spawnSync).mock.calls[0]![1]).toEqual(["-o", f.output, "-v", "-Wl,-t"]); + entry.publish(f.output); + const recorded = ( + JSON.parse(f.cache.read("executable", f.key)!.toString()) as { inputs: { path: string }[] } + ).inputs.map((saved) => saved.path); + expect(recorded).toEqual(expect.arrayContaining([...Object.values(paths), nonshared, lib])); + expect(recorded).not.toContain(program); + expect(open().restore(f.destination)).toBe(true); + const before = statSync(paths[input]); + writeFileSync(paths[input] + ".new", "x".repeat(before.size)); + utimesSync(paths[input] + ".new", before.atime, before.mtime); + renameSync(paths[input] + ".new", paths[input]); + expect(open().restore(f.destination)).toBe(false); + }, +); diff --git a/packages/compiler/src/native/executable-cache.ts b/packages/compiler/src/native/executable-cache.ts index c0ac755b9..1dfbf0b00 100644 --- a/packages/compiler/src/native/executable-cache.ts +++ b/packages/compiler/src/native/executable-cache.ts @@ -11,7 +11,7 @@ import { import { runNativeTool } from "../backend/native-tools.js"; import type { NativeRuntimeSelection } from "../backend/runtime-pack-native.js"; import type { NativeToolchain } from "./toolchain.js"; -import { contentDigest, NativeCache, partsDigest } from "./cache.js"; +import { contentDigest, NativeCache } from "./cache.js"; interface InputIdentity { path: string; @@ -48,9 +48,22 @@ function identity(path: string): InputIdentity { }; } +function sameIdentity(a: InputIdentity, b: InputIdentity): boolean { + return ( + a.path === b.path && + a.canonical === b.canonical && + a.kind === b.kind && + a.dev === b.dev && + a.ino === b.ino && + a.size === b.size && + a.mtime === b.mtime && + a.ctime === b.ctime + ); +} + function stillMatches(inputs: InputIdentity[]): boolean { try { - return inputs.every((input) => JSON.stringify(identity(input.path)) === JSON.stringify(input)); + return inputs.every((input) => sameIdentity(identity(input.path), input)); } catch { return false; } @@ -165,6 +178,8 @@ function stageSymbols(bytes: Buffer, binary: string): void { export class NativeExecutableCache { private inputs: InputIdentity[]; private traced = false; + /** Linux: no entry exists and the key was never linked before. */ + private readonly firstLink: boolean; constructor( private readonly cache: NativeCache, @@ -172,23 +187,28 @@ export class NativeExecutableCache { private readonly linker: string, private readonly debug: boolean, paths: string[], + /** Linux: trace with one verbose link, from a key's second link on. */ + private readonly linux = false, ) { - this.inputs = [...new Set(paths)].sort().map(identity); + this.firstLink = linux && !cache.has("executable", key) && !cache.has("linked", key); + // A first link neither restores nor traces, so it needs no identities. + this.inputs = this.firstLink ? [] : [...new Set(paths)].sort().map(identity); } restore(output: string): boolean { + if (this.firstLink) return false; try { const metadata = this.cache.read("executable", this.key); if (metadata === null) return false; const entry: unknown = JSON.parse(metadata.toString("utf8")); if (!validEntry(entry) || !stillMatches(entry.inputs) || !stillMatches(this.inputs)) return false; + const saved = new Map(entry.inputs.map((input) => [input.path, input])); if ( - !this.inputs.every((input) => - entry.inputs.some( - (saved) => saved.path === input.path && JSON.stringify(saved) === JSON.stringify(input), - ), - ) + !this.inputs.every((input) => { + const recorded = saved.get(input.path); + return recorded !== undefined && sameIdentity(recorded, input); + }) ) return false; if (this.debug !== (entry.symbols !== null)) return false; @@ -209,14 +229,24 @@ export class NativeExecutableCache { * Directories from the driver's search line detect a newly added candidate. * Private build inputs already belong to the LLVM/runtime cache identity. * A true result means the requested output was linked successfully and its - * inputs remained stable. The caller can publish that output directly. */ + * inputs remained stable. The caller can publish that output directly. On + * false, the caller links the output itself. */ trace(args: string[], stage: string): boolean { this.traced = false; try { + // On Linux a key's first link only records that it was linked; a later + // link of the same key traces, so a build that runs once traces nothing. + if (this.firstLink) { + this.cache.mark("linked", this.key); + return false; + } const roots = [resolve(stage), realpathSync(stage)]; - const dry = toolOutput(this.linker, [...args, "-###"]); - const driverInputs = tracePaths(dry, true, roots).map(identity); - const linked = toolOutput(this.linker, [...args, "-Wl,-t"]); + let driverInputs = this.linux + ? [] + : tracePaths(toolOutput(this.linker, [...args, "-###"]), true, roots).map(identity); + // On Linux, -v prints the jobs that -### would, while the link runs. + const linked = toolOutput(this.linker, [...args, ...(this.linux ? ["-v"] : []), "-Wl,-t"]); + if (this.linux) driverInputs = tracePaths(linked, true, roots).map(identity); const paths = tracePaths(linked, false, roots); if (paths.length === 0 || !stillMatches(this.inputs) || !stillMatches(driverInputs)) return false; @@ -233,10 +263,8 @@ export class NativeExecutableCache { if (!this.traced || !stillMatches(this.inputs)) return; const binary = readFileSync(output); const symbols = this.debug ? readSymbols(output) : null; - const binaryKey = contentDigest(binary); - const symbolsKey = symbols === null ? null : contentDigest(symbols); - this.cache.write("binary", binaryKey, binary); - if (symbols !== null && symbolsKey !== null) this.cache.write("dsym", symbolsKey, symbols); + const binaryKey = this.cache.writeContent("binary", binary); + const symbolsKey = symbols === null ? null : this.cache.writeContent("dsym", symbols); if (!stillMatches(this.inputs)) return; const entry: ExecutableEntry = { schema: "scriptc.native-executable.v1", @@ -254,16 +282,18 @@ export class NativeExecutableCache { export function openNativeExecutableCache( cache: NativeCache | null, toolchain: NativeToolchain, - llvm: readonly string[], + llvmDigest: () => string, options: CompileRequestOptions, ffi: FfiProfile | null, pack: NativeRuntimeSelection, ): NativeExecutableCache | null { - // Match the established complete-cache contract: default Apple driver, - // known runtime inputs, and no wrapper or caller-supplied library searches. + // Match the established complete-cache contract: the default Apple driver + // or a Linux clang driver, known runtime inputs, and no wrapper or + // caller-supplied library searches. + const platform = toolchain.target.platform; if ( cache === null || - toolchain.target.platform !== "darwin" || + (platform !== "darwin" && platform !== "linux") || options.sanitize || // The key names a profile by path, not by its bytes. options.profileGenerate !== undefined || @@ -277,9 +307,23 @@ export function openNativeExecutableCache( return null; try { const linker = commandPath(toolchain.linker); - if (realpathSync(linker) !== "/usr/bin/clang") return null; - const effective = commandPath(runNativeTool(linker, ["-print-prog-name=clang"]).trim()); - const debug = options.optimization === "dev" && !options.strip; + // Apple's driver at /usr/bin/clang, or a clang driver on Linux. Both + // name every input of a link in their -### and -Wl,-t traces. + if ( + platform === "darwin" + ? realpathSync(linker) !== "/usr/bin/clang" + : !/^clang(-\d+)?$/.test(basename(realpathSync(linker))) + ) + return null; + // Apple's /usr/bin/clang is a shim for the active developer directory's + // driver; a Linux clang driver is itself the driver. + const effective = + platform === "darwin" + ? commandPath(runNativeTool(linker, ["-print-prog-name=clang"]).trim()) + : linker; + // Linux keeps debug information in the executable; darwin keeps it in a + // separate dSYM, which the cache stores beside the executable. + const debug = platform === "darwin" && options.optimization === "dev" && !options.strip; const paths = [ linker, effective, @@ -291,6 +335,7 @@ export function openNativeExecutableCache( (artifact) => join(pack.root, artifact.path), ), ]; + if (platform === "linux") paths.push(join(pack.root, "runtime-pack.json")); if (debug) { const dsymutil = commandPath(toolchain.dsymutil); if (realpathSync(dsymutil) !== "/usr/bin/dsymutil") return null; @@ -299,11 +344,16 @@ export function openNativeExecutableCache( const key = contentDigest( JSON.stringify({ schema: 1, - llvm: partsDigest(llvm), + llvm: llvmDigest(), options, toolchain, runtimeIdentity: pack.packageText, - runtimeManifest: pack.manifestText, + // On Linux the manifest's identity names it: restore checks that + // identity again, as it does every other input. + runtimeManifest: + platform === "darwin" + ? pack.manifestText + : identity(join(pack.root, "runtime-pack.json")), linker: identity(linker), effective: identity(effective), environment: toolchainEnvironmentFingerprint(), @@ -311,7 +361,7 @@ export function openNativeExecutableCache( path: process.env["PATH"] ?? null, }), ); - return new NativeExecutableCache(cache, key, linker, debug, paths); + return new NativeExecutableCache(cache, key, linker, debug, paths, platform === "linux"); } catch { return null; } From 6722a01898b39cf0b472caa7d6994f6dd3003633 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 23:28:09 -0500 Subject: [PATCH 055/259] Track asserted typed-array reads that can be undefined in element state --- .../compiler/src/frontend/lowering/lowerer.ts | 18 +++++++++++++++- .../corpus/7394-non-null-typed-array-reads.ts | 21 +++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 2fcfc063b..af89c61a4 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -6488,6 +6488,22 @@ export class Lowerer { }); return keys; }; + // `t[i]!` on a typed array, stored into an array, keeps an invalid + // index's undefined (assertedReadObservesUndefined): `!` performs no + // runtime check. A read whose consumers treat undefined like NaN stores + // NaN instead. + const assertedReadMayBeUndefined = (node: ts.Expression): boolean => { + let e = node; + while (ts.isParenthesizedExpression(e)) e = e.expression; + if (!ts.isNonNullExpression(e)) return false; + let read = e.expression; + while (ts.isParenthesizedExpression(read)) read = read.expression; + return ( + ts.isElementAccessExpression(read) && + this.mapTypeOf(this.typeOf(read.expression))?.kind === "bytes" && + !nanCoded.isNumericRead(read) + ); + }; const elementStates = new ArrayElementStates({ elementAdmitsUndefined: (key) => { siteDependencies?.read(key); @@ -6497,7 +6513,7 @@ export class Lowerer { allocationOwner: (node) => ownership.allocationOwner(node), arrayKeys: arrayKeysOf, mayBeUndefined: (node) => { - if (explicitlyNonNull(node)) return false; + if (explicitlyNonNull(node)) return assertedReadMayBeUndefined(node); if (mayBeOptional(node)) return true; // `undefined as unknown as T` keeps the undefined value. for ( diff --git a/tests/corpus/7394-non-null-typed-array-reads.ts b/tests/corpus/7394-non-null-typed-array-reads.ts index 6f1ec9808..bab1bcf9c 100644 --- a/tests/corpus/7394-non-null-typed-array-reads.ts +++ b/tests/corpus/7394-non-null-typed-array-reads.ts @@ -57,3 +57,24 @@ line("slots", [optional, listed[0], listed[1], listed.length]); let total = 0; for (let i = 0; i <= int32.length; i++) total += int32[i]!; line("sum", [total]); + +// Arrays that store an asserted read past the end hold undefined, which +// their callbacks see. +const pushed: number[] = []; +pushed.push(int32[7]!); +pushed.push(uint8[1]!); +const literal = [float64[5]!, float64[0]!]; +const assigned: number[] = [1, 2]; +assigned[0] = uint8[9]!; +let visited = 0; +pushed.forEach((v) => { + visited += v; +}); +line("callbacks", [ + pushed.map((v) => v * 2).join(","), + visited, + literal.map((v) => typeof v).join(","), + literal.filter((v) => v === undefined).length, + assigned.map((v) => v + 1).join(","), + assigned.some((v) => v === undefined), +]); From 0309a211061953c20cdfd6c7c7b2438591b67d63 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 23:29:39 -0500 Subject: [PATCH 056/259] Fix the tsgo and tsc-ts IR identity failure --- tests/corpus/7455-tls-als-contexts.mjs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/corpus/7455-tls-als-contexts.mjs b/tests/corpus/7455-tls-als-contexts.mjs index 38783fdf9..bc59a78d4 100644 --- a/tests/corpus/7455-tls-als-contexts.mjs +++ b/tests/corpus/7455-tls-als-contexts.mjs @@ -21,7 +21,7 @@ const server = tls.createServer({ cert, key }, (socket) => { server.on("tlsClientError", (err) => serverEvents.push(`tlsClientError ${err.code} ${als.getStore()}`)); await als.run("listen", () => new Promise((resolve) => server.listen(0, "127.0.0.1", () => { serverEvents.push(`listening ${als.getStore()}`); - resolve(); + resolve(undefined); }))); const { port } = server.address(); await als.run("client", () => new Promise((resolve) => { @@ -32,7 +32,7 @@ await als.run("client", () => new Promise((resolve) => { client.on("data", () => clientEvents.push(`data ${als.getStore()}`)); client.on("close", () => { clientEvents.push(`close ${als.getStore()}`); - resolve(); + resolve(undefined); }); })); await als.run("untrusted", () => new Promise((resolve) => { From cdef55778a0d96e2d50e0cf965f2f858c4162e99 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 23:31:30 -0500 Subject: [PATCH 057/259] Answer Error.prototype only while an error keeps its built prototype Object.getPrototypeOf of an Error answers Error.prototype when the error's view was built from its fields and its prototype is still the object the view was built with. After Object.setPrototypeOf(error, {}), it answers the object that was set. --- packages/runtime/src/scr_json.c | 39 ++++++++++++------- tests/corpus/8115-error-prototype-identity.js | 9 +++++ 2 files changed, 33 insertions(+), 15 deletions(-) diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index b318114a3..1115c3a8a 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -8560,6 +8560,12 @@ typedef struct { * or NULL. The code slot holds only strings, and a subclass's typed view * rebuilds its properties from the slots on every read. */ ScrDyn *code; + /* The prototype a view built from the error's fields starts with + * (scr_error_dyn_fields: the holder of its default name and message, or + * none), retained so that no later object takes its address. Only such a + * view sets `fields_view`. */ + ScrDyn *view_prototype; + bool fields_view; } ScrErrDynEnt; static SCR_TL ScrErrDynEnt *scr_errdyn_cache = NULL; @@ -8664,6 +8670,7 @@ static void scr_errdyn_sweep(void) { scr_error_release(dead[i].err); scr_errdyn_release_node(dead[i].dyn); scr_dyn_release(dead[i].code); + scr_dyn_release(dead[i].view_prototype); } free(dead); } @@ -8685,6 +8692,8 @@ static void scr_errdyn_append(ScrError *e, ScrDyn *d) { scr_errdyn_cache[scr_errdyn_n].err = scr_error_retain(e); scr_errdyn_cache[scr_errdyn_n].dyn = scr_dyn_retain(d); scr_errdyn_cache[scr_errdyn_n].code = NULL; + scr_errdyn_cache[scr_errdyn_n].view_prototype = NULL; + scr_errdyn_cache[scr_errdyn_n].fields_view = false; scr_errdyn_n++; if (scr_errdyn_n * 2 > scr_errdyn_slots) { free(scr_errdyn_by_err); @@ -8741,6 +8750,7 @@ static void scr_errdyn_teardown(void) { scr_error_release(cache[i].err); scr_errdyn_release_node(cache[i].dyn); scr_dyn_release(cache[i].code); + scr_dyn_release(cache[i].view_prototype); } free(cache); } @@ -8844,24 +8854,17 @@ static void scr_error_dyn_add_stack(ScrDyn *d) { entry->enumerable = false; } -/* Whether `object` is the view of an error built as an Error (not a - * subclass or another error kind) whose prototype is still the one its view - * starts with: none, or the holder of its default `name` and `message` - * (scr_error_dyn_fields). Such an error's prototype is Error.prototype. */ +/* Whether `object` is the view scr_error_dyn_fields built for an error + * created as an Error (not a subclass or another error kind) and its + * prototype is still the one the view started with. Such an error's + * prototype is Error.prototype. */ static bool scr_dyn_error_view_on_error_prototype(const ScrDyn *object) { - const ScrDyn *holder = object->prototype; if (object->null_proto) return false; - if (holder) { - if (holder->kind != SCR_DYN_OBJ || holder->prototype || holder->null_proto || holder->v.obj.len > 2) return false; - for (size_t i = 0; i < holder->v.obj.len; i++) { - const ScrDynEntry *entry = &holder->v.obj.entries[i]; - bool known = (entry->key_len == 4 && memcmp(entry->key, "name", 4) == 0) || - (entry->key_len == 7 && memcmp(entry->key, "message", 7) == 0); - if (!known || entry->enumerable || entry->accessor) return false; - } - } size_t hit = scr_errdyn_find(object, false); - return hit != SIZE_MAX && scr_errdyn_cache[hit].err->vt == &scr_error_vts[SCR_ERR_ERROR]; + if (hit == SIZE_MAX) return false; + const ScrErrDynEnt *ent = &scr_errdyn_cache[hit]; + return ent->fields_view && object->prototype == ent->view_prototype && + ent->err->vt == &scr_error_vts[SCR_ERR_ERROR]; } ScrDyn *scr_error_dyn_fields(const ScrError *e) { @@ -8993,8 +8996,14 @@ ScrDyn *scr_dyn_from_error(const ScrError *e) { break; } } + bool fields_view = d == NULL; if (!d) d = scr_error_dyn_fields(e); scr_errdyn_append((ScrError *)e, d); + if (fields_view) { + ScrErrDynEnt *ent = &scr_errdyn_cache[scr_errdyn_n - 1]; + ent->fields_view = true; + ent->view_prototype = d->prototype ? scr_dyn_retain(d->prototype) : NULL; + } return d; } diff --git a/tests/corpus/8115-error-prototype-identity.js b/tests/corpus/8115-error-prototype-identity.js index 1eda2c2c0..5c98e1209 100644 --- a/tests/corpus/8115-error-prototype-identity.js +++ b/tests/corpus/8115-error-prototype-identity.js @@ -44,3 +44,12 @@ const values = [new Error("e"), {}, Object.create(null), [], JSON.parse('{"a":1} console.log(values.map(kind).join(",")); const proto = Object.getPrototypeOf(new Error("m")); console.log(proto.name, JSON.stringify(proto.message), Object.prototype.hasOwnProperty.call(proto, "name")); + +// After Object.setPrototypeOf, the prototype is the object that was set. +const custom = {}; +const moved = Object.setPrototypeOf(new Error("moved"), custom); +console.log(Object.getPrototypeOf(moved) === custom, Object.getPrototypeOf(moved) === Error.prototype); +const named = { kind: "named" }; +const movedNamed = new Error(); +Object.setPrototypeOf(movedNamed, named); +console.log(Object.getPrototypeOf(movedNamed) === named, Object.getPrototypeOf(movedNamed).kind); From 3b951ef4e22df32a4d5a703eb86c4e3233c155d0 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 23:43:30 -0500 Subject: [PATCH 058/259] Let objects inherit from JavaScript class prototypes --- .../limitations/builtin-apis/prototypes.mdx | 7 +- .../compiler/src/backend/llvm/lib-shared.ts | 1 + .../lowering/class-dynamic-dispatch.ts | 96 ++++++++++++- .../src/frontend/lowering/class-prototypes.ts | 71 +++++++++- .../src/frontend/lowering/lower-inspect.ts | 13 +- packages/compiler/src/ir/builtin-effects.ts | 1 + .../compiler/src/ir/builtin-signatures.ts | 1 + packages/compiler/src/ir/runtime-features.ts | 2 + .../8260-class-prototype-views.mjs.json | 6 + packages/runtime/src/scr_json.c | 43 +++++- packages/runtime/src/scr_qs.h | 2 + packages/runtime/src/scr_util_callable.c | 54 ++++--- tests/corpus/8260-class-prototype-views.mjs | 134 ++++++++++++++++++ .../8260-class-prototype-views.mjs.json | 1 + tests/harness/errors.test.ts | 30 ++++ 15 files changed, 439 insertions(+), 23 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8260-class-prototype-views.mjs.json create mode 100644 tests/corpus/8260-class-prototype-views.mjs create mode 100644 tests/harness/corpus-costs/8260-class-prototype-views.mjs.json diff --git a/docs/content/limitations/builtin-apis/prototypes.mdx b/docs/content/limitations/builtin-apis/prototypes.mdx index 170b11793..7a7e01635 100644 --- a/docs/content/limitations/builtin-apis/prototypes.mdx +++ b/docs/content/limitations/builtin-apis/prototypes.mdx @@ -1,5 +1,10 @@ - **Prototypes:** Named properties and methods on program class prototypes support replacement, inheritance, and deletion. - Bare prototype reflection, accessor replacement, and prototype storage on local, generic, mixin, or runtime-provided classes are unsupported. + A module-level JavaScript class's prototype can become the prototype of other objects: `Object.create(C.prototype)`, `Object.setPrototypeOf(F.prototype, C.prototype)`, `Object.setPrototypeOf(object, C.prototype)`, and `util.inherits(F, C)` with an ordinary constructor `F`. + The inherited methods and accessors run with the inheriting object as `this`. + Methods that use `#private` members or `super` throw a TypeError for a receiver that is not an instance of the class. + `C.prototype` also reads as a value for `Object.getPrototypeOf` and for `===` and `!==` comparisons. + Changing the prototype of a class prototype (`Object.setPrototypeOf(C.prototype, X)`, `util.inherits(C, F)`, or `Object.setPrototypeOf` on a class prototype reached through an instance) is unsupported. + Other bare prototype reflection, TypeScript class prototypes as values, accessor replacement, and prototype storage on local, generic, mixin, or runtime-provided classes are unsupported. Plain objects, arrays, functions, class instances, and Date, RegExp, Map, Set, WeakMap, WeakSet, and Promise values inherit `constructor`, `valueOf`, `toString`, `hasOwnProperty`, and `propertyIsEnumerable` from `Object.prototype` as in Node, so `value.constructor === Object` and `value.valueOf === Object.prototype.valueOf` compare identities exactly. Named reads such as `value.valueOf` answer these inherited members; computed-key reads such as `value[key]` do not. `Object.prototype`'s own members read as values; its mutation and other reflection, such as `isPrototypeOf` and `__proto__`, are unsupported. diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 014191314..20ad7fa02 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -82,6 +82,7 @@ export const LIB_FN_SYMS: Record = { "util.isDeepStrictEqual": "scr_util_is_deep_strict_equal", "util.styleText": "scr_util_style_text", "util.inherits": "scr_util_inherits", + "util.inheritsPrototype": "scr_util_inherits_prototype", "util.deprecate": "scr_util_deprecate", "util.callbackify": "scr_util_callbackify", "util.promisifyDyn": "scr_util_promisify", diff --git a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts index f219fd5e5..d658fb20a 100644 --- a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts +++ b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts @@ -4105,6 +4105,94 @@ export class ClassDynamicDispatch { return { kind: "call", callee: name, args: [bag, key], type: BOOL, loc }; } + /** `%dyn.class.bagHasOwn[OrPrototype]`: whether an instance's property bag + * holds `key` as its own property, or, with `prototype`, whether the bag's + * prototype object does. False before the instance has a bag. */ + private readBagHasOwn( + lowerer: Lowerer, + bag: IrExpr, + key: IrExpr, + prototype: boolean, + loc: SrcLoc, + ): IrExpr { + const name = prototype ? "%dyn.class.bagHasOwnOrPrototype" : "%dyn.class.bagHasOwn"; + let helper = lowerer.liftedFnNamed(name); + if (!helper) { + const value = varRef("p.0", DYN, loc); + const keyRef = varRef("p.1", STRING, loc); + const proto = varRef("proto", DYN, loc); + const hasOwn = (target: IrExpr): IrExpr => ({ + kind: "libCall", + fn: "dyn.hasOwn", + args: [target, keyRef], + type: BOOL, + loc, + }); + const returnFalse: IrStmt = { + kind: "return", + value: { kind: "boolLit", value: false, type: BOOL, loc }, + loc, + }; + helper = { + name, + params: [ + { localId: "p.0", name: "bag", type: DYN }, + { localId: "p.1", name: "key", type: STRING }, + ], + returnType: BOOL, + locals: [ + { id: "p.0", name: "bag", type: DYN, mutable: false }, + { id: "p.1", name: "key", type: STRING, mutable: false }, + ...(prototype ? [{ id: "proto", name: "proto", type: DYN, mutable: false }] : []), + ], + body: [ + { + kind: "if", + cond: { kind: "dynTest", test: "undefined", value, type: BOOL, loc }, + then: [returnFalse], + else_: null, + loc, + }, + ...(prototype + ? ([ + { + kind: "if", + cond: hasOwn(value), + then: [ + { + kind: "return", + value: { kind: "boolLit", value: true, type: BOOL, loc }, + loc, + }, + ], + else_: null, + loc, + }, + { + kind: "varDecl", + localId: "proto", + init: { kind: "libCall", fn: "dyn.getPrototype", args: [value], type: DYN, loc }, + loc, + }, + { + kind: "if", + cond: { kind: "dynTest", test: "nullish", value: proto, type: BOOL, loc }, + then: [returnFalse], + else_: null, + loc, + }, + { kind: "return", value: hasOwn(proto), loc }, + ] satisfies IrStmt[]) + : [{ kind: "return", value: hasOwn(value), loc } satisfies IrStmt]), + ], + loc, + }; + lowerer.liftedFns.push(helper); + } + this.generated.add(helper); + return { kind: "call", callee: name, args: [bag, key], type: BOOL, loc }; + } + /** The hints for which some boxed class declares a conversion method. A * string conversion calls toString first, so without a declared toString * or Symbol.toPrimitive it answers Object.prototype.toString's @@ -5866,12 +5954,18 @@ export class ClassDynamicDispatch { const cls = lowerer.coerceToExpected(classValueRef(lowerer, info, info.decl), DYN); const bag = this.branchPropertyBag(lowerer, info, receiver, false, loc); const key: IrExpr = { kind: "strLit", value: name, type: STRING, loc }; + // `constructor` is an own property of every class prototype, so an + // ancestor's prototype never answers for an instance of this class: + // the instance's own property answers, then one this class's + // prototype object defines (a reflected prototype, or a write to + // `C.prototype.constructor`), and otherwise the class itself. + const answered = this.readBagHasOwn(lowerer, bag, key, hasClassPrototypeData(info), loc); return [ { kind: "return", value: { kind: "ternary", - cond: this.readBagHas(lowerer, "dyn.hasKey", bag, key, loc), + cond: answered, then: { kind: "libCall", fn: "dyn.bagGet", diff --git a/packages/compiler/src/frontend/lowering/class-prototypes.ts b/packages/compiler/src/frontend/lowering/class-prototypes.ts index cb2ab2280..595b64e05 100644 --- a/packages/compiler/src/frontend/lowering/class-prototypes.ts +++ b/packages/compiler/src/frontend/lowering/class-prototypes.ts @@ -13,7 +13,7 @@ import { type IrStmt, type SrcLoc, } from "../../ir/ir.js"; -import { locOf } from "../program.js"; +import { isJsSourceFile, locOf } from "../program.js"; import { classMemberNameOf, classValueRef, @@ -503,6 +503,69 @@ export function isErrorPrototypeValue( ); } +/** Whether a bare `C.prototype` read becomes the prototype of another object + * or is only compared or inspected: the argument of `Object.create` or + * `Object.getPrototypeOf` / `Reflect.getPrototypeOf`, the prototype argument + * of `Object.setPrototypeOf` / `Reflect.setPrototypeOf`, or an operand of + * `===` / `!==`. In these positions the complete view of the + * prototype (reflectClassPrototype) answers. Objects that inherit from it + * run the class's methods with themselves as the receiver, which the + * methods' receiver-independent lowering (reflectedClassMethodValue) + * supports. Other positions, such as `Object.setPrototypeOf(C.prototype, X)`, + * which would relink the class, keep the diagnostic. */ +function prototypeViewPosition(lowerer: Lowerer, expr: ts.PropertyAccessExpression): boolean { + let node: ts.Node = expr; + let parent = node.parent; + while (parent && ts.isParenthesizedExpression(parent)) { + node = parent; + parent = parent.parent; + } + if (!parent) return false; + if (ts.isCallExpression(parent) && ts.isPropertyAccessExpression(parent.expression)) { + const args = parent.arguments.nodes; + const objectMethod = lowerer.stdlibGlobalMember(parent.expression, "Object"); + const reflectMethod = lowerer.stdlibGlobalMember(parent.expression, "Reflect"); + if ( + objectMethod === "create" || + objectMethod === "getPrototypeOf" || + reflectMethod === "getPrototypeOf" + ) + return args[0] === node; + if (objectMethod === "setPrototypeOf" || reflectMethod === "setPrototypeOf") + return args[1] === node; + return false; + } + return ( + ts.isBinaryExpression(parent) && + (parent.operatorToken.kind === ts.SyntaxKind.EqualsEqualsEqualsToken || + parent.operatorToken.kind === ts.SyntaxKind.ExclamationEqualsEqualsToken) + ); +} + +/** A module-level JavaScript class named directly (not a class value that + * may hold a subclass at run time): its prototype has a complete view whose + * methods accept any receiver. */ +function viewableClass(lowerer: Lowerer, info: ClassInfo, receiver: ts.Expression): boolean { + return ( + info.decl !== null && + info.localClass === undefined && + isJsSourceFile(ts.getSourceFileOfNode(info.decl)) && + exactClassOfReceiver(lowerer, receiver) === info + ); +} + +/** The complete prototype view of the class `node` names, when it is a + * viewable class (util.inherits's superCtor); null otherwise. */ +export function classPrototypeView( + lowerer: Lowerer, + node: ts.Expression, + loc: SrcLoc, +): IrExpr | null { + const info = exactClassOfReceiver(lowerer, node); + if (!info || !viewableClass(lowerer, info, node)) return null; + return reflectClassPrototype(lowerer, info, loc, classValueRef(lowerer, info, node)); +} + /** Named data and method slots have native descriptors. Bare reflection and * accessor replacement still require a complete view of the prototype. */ export function lowerClassPrototypeData( @@ -566,6 +629,12 @@ export function lowerClassPrototypeData( }); return reflectClassPrototype(lowerer, info, locOf(expr), receiver); } + if ( + name === null && + prototypeViewPosition(lowerer, expr) && + viewableClass(lowerer, info, expr.expression) + ) + return reflectClassPrototype(lowerer, info, locOf(expr), classValueRef(lowerer, info, expr)); if (name === null || (isCompiledPrototypeMember(lowerer, info, name) && !method)) { lowerer.unsupported( "SC1090", diff --git a/packages/compiler/src/frontend/lowering/lower-inspect.ts b/packages/compiler/src/frontend/lowering/lower-inspect.ts index e7a43bde1..cb7eba971 100644 --- a/packages/compiler/src/frontend/lowering/lower-inspect.ts +++ b/packages/compiler/src/frontend/lowering/lower-inspect.ts @@ -1,5 +1,6 @@ import { keyedHelperName } from "./stable-names.js"; import { perKeyOrder } from "./key-order-witness.js"; +import { classPrototypeView } from "./class-prototypes.js"; import { dynUndefinedExpr, boolLit, @@ -3433,8 +3434,14 @@ function lowerUtilCallableCall( member === "inherits" && expr.arguments.nodes[1] !== undefined ? builtinClassKindOf(lowerer, expr.arguments.nodes[1]) : null; + // A superCtor class whose prototype has a complete view (a module-level + // JavaScript class named directly) passes that view to the runtime. + const superView = + member === "inherits" && builtinBase === null && expr.arguments.nodes[1] !== undefined + ? classPrototypeView(lowerer, expr.arguments.nodes[1], loc) + : null; for (const [index, arg] of expr.arguments.nodes.slice(0, classArgs).entries()) { - if (index === 1 && builtinBase !== null) continue; + if (index === 1 && (builtinBase !== null || superView !== null)) continue; if (lowerer.mapTypeOf(lowerer.typeOf(arg))?.kind === "classval") lowerer.noLowering( `util.${member} over a class constructor`, @@ -3466,7 +3473,9 @@ function lowerUtilCallableCall( for (const arg of expr.arguments.nodes.slice(arity)) stmts.push({ kind: "exprStmt", expr: lowerer.lowerExpr(arg), loc }); const type = fn === "util.inherits" ? VOID : DYN; - const result: IrExpr = { kind: "libCall", fn, args, type, loc }; + const result: IrExpr = superView + ? { kind: "libCall", fn: "util.inheritsPrototype", args: [...args, superView], type, loc } + : { kind: "libCall", fn, args, type, loc }; return { kind: "seqExpr", stmts, result, type: result.type, loc }; } diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index 390c7fbc3..38512fdef 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -591,6 +591,7 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "util.styleText", "util.toUSVString", "util.inherits", + "util.inheritsPrototype", "util.deprecate", "util.callbackify", "util.promisifyDyn", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index e6ad0614a..b87ff24c6 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -1146,6 +1146,7 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ * arguments (scr_util_callable.c). The function results are native dyn * wrappers; call sites with a static function type check them back. */ "util.inherits": { argTypes: [DYN, DYN], result: VOID }, + "util.inheritsPrototype": { argTypes: [DYN, DYN, DYN], result: VOID }, "util.deprecate": { argTypes: [DYN, DYN, DYN, DYN], result: DYN }, "util.callbackify": { argTypes: [DYN], result: DYN }, /** util.promisify over an untyped function value: a native dyn function diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 2ae19375f..14402b6b5 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -144,6 +144,7 @@ const DYN_ASYNC_LIB_FNS: ReadonlySet = new Set([ "util.debuglog", "util.deprecate", "util.inherits", + "util.inheritsPrototype", "util.styleText", ]); @@ -173,6 +174,7 @@ const UTIL_CALLABLE_LIB_FNS: ReadonlySet = new Set([ "util.debuglog", "util.deprecate", "util.inherits", + "util.inheritsPrototype", ]); /** Entry points that link the regex unit: the regex and glob matchers (fs.glob's walk compiles its patterns with the glob matcher), and readline's terminal unit (scr_readline_tty.c), which measures with the regex unit's stripVTControlCharacters. */ diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8260-class-prototype-views.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8260-class-prototype-views.mjs.json new file mode 100644 index 000000000..6cf42e773 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8260-class-prototype-views.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8260-class-prototype-views.mjs" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 580b816c4..b8f3bf8f9 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -2169,6 +2169,40 @@ static bool scr_dyn_prototype_valid(const ScrDyn *prototype) { } /* A valid receiver or prototype whose kind this operation does not handle. */ +/* Compiled class prototypes. Compiled code binds a class's methods, its + * base chain and its instanceof answers when it compiles, so the + * prototype's own [[Prototype]] is fixed: scr_dyn_set_prototype refuses to + * change it. Each module-level class prototype registers when it is + * created (scr_dyn_name_class_prototype) and stays alive until its thread + * exits, as the class does. */ +static SCR_TL ScrDyn **scr_dyn_fixed_prototypes; +static SCR_TL size_t scr_dyn_fixed_count, scr_dyn_fixed_cap; + +static void scr_dyn_fixed_prototypes_cleanup(void) { + for (size_t i = 0; i < scr_dyn_fixed_count; i++) scr_dyn_release(scr_dyn_fixed_prototypes[i]); + free(scr_dyn_fixed_prototypes); + scr_dyn_fixed_prototypes = NULL; + scr_dyn_fixed_count = scr_dyn_fixed_cap = 0; +} + +static void scr_dyn_fix_prototype(ScrDyn *prototype) { + if (scr_dyn_fixed_count == scr_dyn_fixed_cap) { + if (scr_dyn_fixed_cap == 0) scr_atexit(scr_dyn_fixed_prototypes_cleanup); + size_t cap = scr_dyn_fixed_cap ? scr_dyn_fixed_cap * 2 : 8; + ScrDyn **grown = realloc(scr_dyn_fixed_prototypes, cap * sizeof *grown); + if (!grown) scr_json_oom(); + scr_dyn_fixed_prototypes = grown; + scr_dyn_fixed_cap = cap; + } + scr_dyn_fixed_prototypes[scr_dyn_fixed_count++] = scr_dyn_retain(prototype); +} + +static bool scr_dyn_prototype_fixed(const ScrDyn *object) { + for (size_t i = 0; i < scr_dyn_fixed_count; i++) + if (scr_dyn_fixed_prototypes[i] == object) return true; + return false; +} + static void scr_dyn_prototype_unsupported(const char *operation) { ScrJsonBuf b; scr_jb_init(&b); @@ -2285,6 +2319,11 @@ ScrDyn *scr_dyn_set_prototype(ScrDyn *object, ScrDyn *prototype) { return NULL; } if (!scr_dyn_prototype_valid(prototype)) return NULL; + if (object->kind == SCR_DYN_OBJ && scr_dyn_fixed_count && scr_dyn_prototype_fixed(object) && + !(prototype->kind == SCR_DYN_NULL ? object->null_proto : prototype == object->prototype)) { + scr_dyn_prototype_unsupported("Object.setPrototypeOf"); + return NULL; + } bool typed = scr_dyn_typed_ref_prototype(prototype); if (scr_exc_pending()) return NULL; if ((object->kind != SCR_DYN_OBJ && object->kind != SCR_DYN_ARR) || @@ -6354,7 +6393,9 @@ static void scr_dyn_name_prototype_chain(const ScrDyn *object) { } void scr_dyn_name_class_prototype(ScrDyn *prototype, const ScrStr *name) { - if (prototype->kind != SCR_DYN_OBJ || prototype->v.obj.class_name || name->len == 0) return; + if (prototype->kind != SCR_DYN_OBJ) return; + if (!scr_dyn_prototype_fixed(prototype)) scr_dyn_fix_prototype(prototype); + if (prototype->v.obj.class_name || name->len == 0) return; scr_dyn_stamp_prototype_name(prototype, name->data, name->len); } diff --git a/packages/runtime/src/scr_qs.h b/packages/runtime/src/scr_qs.h index fc5ca5da5..2232d2d48 100644 --- a/packages/runtime/src/scr_qs.h +++ b/packages/runtime/src/scr_qs.h @@ -62,6 +62,8 @@ bool scr_util_terminal_colors(void); * (scr_util_promisify.c). Arguments are borrowed; function results are +1 * native dyn functions, or NULL with Node's TypeError pending. */ void scr_util_inherits(struct ScrDyn *ctor, struct ScrDyn *super_ctor); +void scr_util_inherits_prototype(struct ScrDyn *ctor, struct ScrDyn *super_ctor, + struct ScrDyn *super_prototype); struct ScrDyn *scr_util_deprecate(struct ScrDyn *fn, struct ScrDyn *msg, struct ScrDyn *code, struct ScrDyn *options); struct ScrDyn *scr_util_callbackify(struct ScrDyn *original); diff --git a/packages/runtime/src/scr_util_callable.c b/packages/runtime/src/scr_util_callable.c index c905ea8ae..60de92121 100644 --- a/packages/runtime/src/scr_util_callable.c +++ b/packages/runtime/src/scr_util_callable.c @@ -149,23 +149,9 @@ static bool uc_define(ScrDyn *target, const char *key, ScrDyn *descriptor) { * Node 24's lib/util.js: nullish arguments and an undefined * superCtor.prototype throw ERR_INVALID_ARG_TYPE; then super_ becomes a * writable, configurable, non-enumerable own property and - * ctor.prototype's prototype becomes superCtor.prototype. */ -void scr_util_inherits(ScrDyn *ctor, ScrDyn *super_ctor) { - if (uc_nullish(ctor)) { - scr_dyn_arg_type_fail("ctor", "of type function", ctor); - return; - } - if (uc_nullish(super_ctor)) { - scr_dyn_arg_type_fail("superCtor", "of type function", super_ctor); - return; - } - if ((ctor->kind == SCR_DYN_FUNC && ctor->v.fn.class_obj) || - (super_ctor->kind == SCR_DYN_FUNC && super_ctor->v.fn.class_obj)) { - uc_fence("util.inherits over class constructors has no lowering; declare the subclass with extends"); - return; - } - ScrDyn *super_prototype = uc_get(super_ctor, "prototype"); - if (!super_prototype) return; + * ctor.prototype's prototype becomes superCtor.prototype. super_prototype + * is superCtor.prototype (owned), or NULL when superCtor is no object. */ +static void uc_inherits(ScrDyn *ctor, ScrDyn *super_ctor, ScrDyn *super_prototype) { if (super_prototype->kind == SCR_DYN_UNDEF) { scr_dyn_prop_type_fail("superCtor.prototype", "of type object", super_prototype); scr_dyn_release(super_prototype); @@ -198,6 +184,40 @@ void scr_util_inherits(ScrDyn *ctor, ScrDyn *super_ctor) { scr_dyn_release(super_prototype); } +void scr_util_inherits(ScrDyn *ctor, ScrDyn *super_ctor) { + if (uc_nullish(ctor)) { + scr_dyn_arg_type_fail("ctor", "of type function", ctor); + return; + } + if (uc_nullish(super_ctor)) { + scr_dyn_arg_type_fail("superCtor", "of type function", super_ctor); + return; + } + if ((ctor->kind == SCR_DYN_FUNC && ctor->v.fn.class_obj) || + (super_ctor->kind == SCR_DYN_FUNC && super_ctor->v.fn.class_obj)) { + uc_fence("util.inherits over class constructors has no lowering; declare the subclass with extends"); + return; + } + ScrDyn *super_prototype = uc_get(super_ctor, "prototype"); + if (!super_prototype) return; + uc_inherits(ctor, super_ctor, super_prototype); +} + +/* util.inherits(ctor, C) where C is a compiled class whose prototype the + * compiler exposes as super_prototype (borrowed): the class value's own + * properties do not hold it. ctor itself may not be a class. */ +void scr_util_inherits_prototype(ScrDyn *ctor, ScrDyn *super_ctor, ScrDyn *super_prototype) { + if (uc_nullish(ctor)) { + scr_dyn_arg_type_fail("ctor", "of type function", ctor); + return; + } + if (ctor->kind == SCR_DYN_FUNC && ctor->v.fn.class_obj) { + uc_fence("util.inherits over class constructors has no lowering; declare the subclass with extends"); + return; + } + uc_inherits(ctor, super_ctor, scr_dyn_retain(super_prototype)); +} + /* ── util.deprecate ──────────────────────────────────────────────────── * The wrapper warns once (and once per code across wrappers) before each * call reaches fn with the call's receiver and arguments; construction diff --git a/tests/corpus/8260-class-prototype-views.mjs b/tests/corpus/8260-class-prototype-views.mjs new file mode 100644 index 000000000..e08b8f206 --- /dev/null +++ b/tests/corpus/8260-class-prototype-views.mjs @@ -0,0 +1,134 @@ +// A class's prototype as the prototype of other objects: ES5 constructors +// that inherit from a class through Object.create, Object.setPrototypeOf and +// util.inherits, and plain objects that adopt a class prototype. Inherited +// methods, accessors and calls between methods run with the object as the +// receiver. +import util from "node:util"; + +class Shape { + constructor(name) { + this.name = name; + } + get label() { + return `${this.name} (${this.sides()} sides)`; + } + sides() { + return 0; + } + describe() { + return `${this.label}: area ${this.area().toFixed(2)}`; + } + area() { + return 0; + } +} + +class Polygon extends Shape { + sides() { + return this.points.length; + } + perimeter() { + let total = 0; + for (let i = 0; i < this.points.length; i++) { + const [x1, y1] = this.points[i]; + const [x2, y2] = this.points[(i + 1) % this.points.length]; + total += Math.hypot(x2 - x1, y2 - y1); + } + return total; + } +} + +// Object.create(Class.prototype) for an ES5 subclass. +function Square(size) { + this.name = "square"; + this.size = size; + this.points = [ + [0, 0], + [size, 0], + [size, size], + [0, size], + ]; +} +Square.prototype = Object.create(Polygon.prototype); +Square.prototype.constructor = Square; +Square.prototype.area = function () { + return this.size * this.size; +}; + +const square = new Square(3); +console.log(square.describe()); +console.log(square.perimeter(), square.sides(), square.label); +console.log(square instanceof Square, square instanceof Polygon, square instanceof Shape); +console.log(Object.getPrototypeOf(Square.prototype) === Polygon.prototype); +console.log(Object.getPrototypeOf(Polygon.prototype) === Shape.prototype); +console.log(Object.keys(square).join(",")); +const inherited = []; +for (const key in square) inherited.push(key); +console.log(inherited.join(",")); + +// Object.setPrototypeOf on an ES5 constructor's prototype. +function Circle(radius) { + this.name = "circle"; + this.radius = radius; +} +Circle.prototype.area = function () { + return Math.PI * this.radius * this.radius; +}; +Object.setPrototypeOf(Circle.prototype, Shape.prototype); +const circle = new Circle(2); +console.log(circle.describe(), circle instanceof Shape, circle instanceof Polygon); + +// util.inherits with a class as the superCtor. +function Triangle(a, b, c) { + this.name = "triangle"; + this.points = [a, b, c]; +} +util.inherits(Triangle, Polygon); +Triangle.prototype.area = function () { + const [[x1, y1], [x2, y2], [x3, y3]] = this.points; + return Math.abs((x1 * (y2 - y3) + x2 * (y3 - y1) + x3 * (y1 - y2)) / 2); +}; +const triangle = new Triangle([0, 0], [4, 0], [0, 3]); +console.log(Triangle.super_ === Polygon, triangle instanceof Polygon); +console.log(triangle.describe(), triangle.perimeter()); + +// A plain object that adopts a class prototype (rehydrating parsed data). +const parsed = JSON.parse('{"name":"lot","points":[[0,0],[2,0],[2,1]]}'); +Object.setPrototypeOf(parsed, Polygon.prototype); +console.log(parsed.sides(), parsed.perimeter().toFixed(3), parsed.label, parsed instanceof Polygon); +const fresh = Object.create(Shape.prototype); +fresh.name = "blank"; +console.log(fresh.describe(), fresh instanceof Shape, Object.getPrototypeOf(fresh) === Shape.prototype); + +// Native instances keep their own methods and answers. +const native = new Polygon("native"); +native.points = [ + [0, 0], + [1, 0], + [0, 1], +]; +console.log(native.describe(), native.perimeter().toFixed(3), native instanceof Polygon); + +// util.inspect names each object by its prototype's constructor. +function Plain() { + this.v = 1; +} +Object.setPrototypeOf(Plain.prototype, Shape.prototype); +console.log(new Square(1).size, fresh, new Plain(), Object.prototype.toString.call(fresh)); +console.log(util.inspect(new Plain()), util.inspect(parsed, { depth: 0 })); + +// A subclass keeps its own constructor below a base whose prototype other +// objects inherit: `new this.constructor()` in a base method builds the +// subclass, also while the subclass's prototype holds a replaceable method. +class Disc extends Shape { + area() { + return 3; + } + rebuild() { + return new this.constructor("copy of " + this.name); + } +} +const areaValue = Shape.prototype.area; +const disc = new Disc("d"); +const rebuilt = disc.rebuild(); +console.log(disc.constructor === Disc, rebuilt instanceof Disc, rebuilt.area(), rebuilt.name, typeof areaValue); diff --git a/tests/harness/corpus-costs/8260-class-prototype-views.mjs.json b/tests/harness/corpus-costs/8260-class-prototype-views.mjs.json new file mode 100644 index 000000000..f06add31f --- /dev/null +++ b/tests/harness/corpus-costs/8260-class-prototype-views.mjs.json @@ -0,0 +1 @@ +{ "plain": 8037, "san": 6172 } diff --git a/tests/harness/errors.test.ts b/tests/harness/errors.test.ts index c8849a10f..add31681d 100644 --- a/tests/harness/errors.test.ts +++ b/tests/harness/errors.test.ts @@ -2190,3 +2190,33 @@ for (const run of runs) { ); }); }); + +describe("class prototype relinks (JS lane)", () => { + test("relinking a class prototype reached through an instance throws", async () => { + // Compiled code binds a class's inherited methods, so its prototype's + // [[Prototype]] cannot change at run time. Node would print "other"; + // the native program refuses instead of answering A's method. + const r = await compileAndRun( + "class-prototype-relink", + `'use strict'; +class A { + a() { + return 'A.a'; + } +} +class B extends A {} +const prototype = Object.getPrototypeOf(new B()); +Object.setPrototypeOf(prototype, Object.getPrototypeOf(prototype)); +console.log('same prototype', new B().a()); +Object.setPrototypeOf(prototype, { a: () => 'other' }); +console.log(new B().a()); +`, + "cjs", + ); + expect(r.exitCode).toBe(1); + expect(r.stdout).toBe("same prototype A.a\n"); + expect(r.stderr).toBe( + "Uncaught Error: Object.setPrototypeOf with this value is not supported yet\n", + ); + }); +}); From cbb87e881246cef5fc9776ef877812a11bbe8bfa Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Fri, 23 Oct 2026 23:49:40 -0500 Subject: [PATCH 059/259] Address review comments --- .../frontend/lowering/class-to-primitive.ts | 5 ++ .../src/frontend/lowering/lower-inspect.ts | 47 +++++++++++----- packages/runtime/src/scr_dyn_invoke.c | 4 ++ packages/runtime/src/scr_inspect.c | 3 +- packages/runtime/src/scr_json.c | 55 ++++++++++++++----- packages/runtime/src/scr_json.h | 5 ++ .../7751-class-well-known-symbol-fields.ts | 39 +++++++++++++ 7 files changed, 127 insertions(+), 31 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/class-to-primitive.ts b/packages/compiler/src/frontend/lowering/class-to-primitive.ts index a260116f8..8807ac5a5 100644 --- a/packages/compiler/src/frontend/lowering/class-to-primitive.ts +++ b/packages/compiler/src/frontend/lowering/class-to-primitive.ts @@ -225,6 +225,11 @@ function classConversion( plan.method === "sym:toPrimitive" ? [{ kind: "strLit", value: hint, type: STRING, loc }] : []; return finish(accessorCall(lowerer, cls.def.name, plan.method, object, args, plan.ret, loc)); }; + // "[object Object]" reads nothing of the instance, but the receiver + // expression still runs, once. + const own = plans.get(info)!; + if (tops.length === 0 && own.method === null && !own.date && !own.tag && !isSafeToRepeat(value)) + prefix.push({ kind: "exprStmt", expr: value, loc }); let result = convert(info, receiver); for (let i = tops.length - 1; i >= 0; i--) { const top = tops[i]!; diff --git a/packages/compiler/src/frontend/lowering/lower-inspect.ts b/packages/compiler/src/frontend/lowering/lower-inspect.ts index eeb4c51da..e5e8b947c 100644 --- a/packages/compiler/src/frontend/lowering/lower-inspect.ts +++ b/packages/compiler/src/frontend/lowering/lower-inspect.ts @@ -18,6 +18,7 @@ import { jsFuncNameOf, type Lowerer } from "./lowerer.js"; import { isJsSourceFile } from "../program.js"; import { BOOL, + CAUGHT, DYN, F64, type IrExpr, @@ -1876,7 +1877,8 @@ function inspectHelper(lowerer: Lowerer, t: IrType, loc: SrcLoc): string { const visible = info.def.fields.filter((f) => isClassOwnEnumerableFieldName(f.name)); // A Symbol.toStringTag getter (an own tag field is listed instead) // brackets the tag after the name, `Name [tag] {`, when it is a - // nonempty string other than the name. + // nonempty string other than the name. A getter that throws shows + // no tag, as in Node. const tagGetter = info.fields.has(TO_STRING_TAG_FIELD) ? null : findMethodOn(lowerer, info, "get:sym:toStringTag"); @@ -1884,21 +1886,36 @@ function inspectHelper(lowerer: Lowerer, t: IrType, loc: SrcLoc): string { strLit(plain, loc); if (tagGetter?.sig.ret.kind === "string") { const owner = tagGetter.declarer.def.name; - locals.push({ id: "tag.0", name: "tag", type: STRING, mutable: false }); - body.push({ - kind: "varDecl", - localId: "tag.0", - init: accessorCall( - lowerer, - owner, - "get:sym:toStringTag", - lowerer.upcastTo(v(), owner), - [], - STRING, + locals.push( + { id: "tag.0", name: "tag", type: STRING, mutable: true }, + { id: "tagError.0", name: "tagError", type: CAUGHT, mutable: false }, + ); + body.push( + { kind: "varDecl", localId: "tag.0", init: strLit("", loc), loc }, + { + kind: "tryCatch", + tryBody: [ + { + kind: "assign", + localId: "tag.0", + value: accessorCall( + lowerer, + owner, + "get:sym:toStringTag", + lowerer.upcastTo(v(), owner), + [], + STRING, + loc, + ), + loc, + }, + ], + catchBody: [], + catchLocalId: "tagError.0", + finallyBody: null, loc, - ), - loc, - }); + }, + ); const tag = (): IrExpr => varRef("tag.0", STRING, loc); const shown: IrExpr = { kind: "logical", diff --git a/packages/runtime/src/scr_dyn_invoke.c b/packages/runtime/src/scr_dyn_invoke.c index b76fe38d2..0dab6aaaa 100644 --- a/packages/runtime/src/scr_dyn_invoke.c +++ b/packages/runtime/src/scr_dyn_invoke.c @@ -144,6 +144,10 @@ static void scr_dyn_display_buf(ScrJsonBuf *b, const ScrDyn *d, bool to_string) return; case SCR_DYN_TYPED_REF: { + /* ToString of a class instance that converts through + * Object.prototype.toString shows its Symbol.toStringTag getter's + * string. */ + if (to_string && scr_dyn_typed_ref_put_tag(b, d)) return; ScrDyn *materialized = scr_dyn_typed_ref_materialize(d); scr_dyn_display_buf(b, materialized, to_string); scr_dyn_release(materialized); diff --git a/packages/runtime/src/scr_inspect.c b/packages/runtime/src/scr_inspect.c index 4a89fbca8..23aa2aebd 100644 --- a/packages/runtime/src/scr_inspect.c +++ b/packages/runtime/src/scr_inspect.c @@ -1210,9 +1210,10 @@ static bool insp_tag_names_class(const char *tag, const char *cls) { /* The Symbol.toStringTag a class instance inherits from its class's * getter (+1), which Node brackets after the class name when it is a * nonempty string other than the name. An own tag field is listed with - * the fields instead. */ + * the fields instead. A getter that throws shows no tag, as in Node. */ static ScrStr *insp_inherited_tag(const ScrDyn *instance, const ScrStr *name) { ScrStr *tag = scr_dyn_typed_ref_class_tag(instance); + if (!tag && scr_exc_pending()) scr_exc_clear(); if (tag && (tag->len == 0 || (tag->len == name->len && memcmp(tag->data, name->data, name->len) == 0))) { scr_str_release(tag); return NULL; diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 8c31f80d5..a4234f1b1 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -4034,6 +4034,9 @@ ScrDyn *scr_dyn_index_get(const ScrDyn *d, double index) { return scr_dyn_typed_ref_element(d, i); } +static ScrStr *scr_dyn_typed_ref_conversion_tag(const ScrDyn *d); +static ScrStr *scr_dyn_tag_string(const ScrStr *tag); + ScrDyn *scr_dyn_typed_ref_string_view(const ScrDyn *d) { /* An instance of a class declared `extends Date` converts through its * toString, declared or inherited. With an exception pending the view is @@ -4047,6 +4050,16 @@ ScrDyn *scr_dyn_typed_ref_string_view(const ScrDyn *d) { scr_str_release(empty); return out; } + /* A class instance converting through Object.prototype.toString shows + * its Symbol.toStringTag getter's string. */ + ScrStr *class_tag = scr_dyn_typed_ref_conversion_tag(d); + if (class_tag || scr_exc_pending()) { + ScrStr *text = class_tag ? scr_dyn_tag_string(class_tag) : scr_str_new("", 0); + scr_str_release(class_tag); + ScrDyn *out = scr_dyn_new_str(text); + scr_str_release(text); + return out; + } ScrDyn *view = scr_dyn_typed_ref_materialize(d); const char *tag = scr_event_ref_hooks ? scr_event_ref_hooks->string_tag(d) : NULL; if (!tag || view->kind != SCR_DYN_OBJ || scr_dyn_property_owner(view, "toString", 8)) return view; @@ -8333,6 +8346,27 @@ static ScrStr *scr_dyn_tag_string(const ScrStr *tag) { return scr_jb_finish(&b); } +/* The Symbol.toStringTag getter's string of a class instance whose + * ToString is Object.prototype.toString (its class has no toString; the + * string hint never reaches valueOf, since that answers a string): +1, or + * NULL otherwise or with the getter's exception pending. */ +static ScrStr *scr_dyn_typed_ref_conversion_tag(const ScrDyn *d) { + ScrStr *to_string_key = scr_str_new("toString", 8); + bool own_conversion = scr_dyn_typed_ref_class_has(d, to_string_key); + scr_str_release(to_string_key); + return own_conversion ? NULL : scr_dyn_typed_ref_class_tag(d); +} + +bool scr_dyn_typed_ref_put_tag(ScrJsonBuf *b, const ScrDyn *d) { + ScrStr *tag = scr_dyn_typed_ref_conversion_tag(d); + if (!tag) return scr_exc_pending(); + scr_jb_puts(b, "[object "); + scr_jb_write(b, tag->data, tag->len); + scr_jb_putc(b, ']'); + scr_str_release(tag); + return true; +} + /* Object.prototype.toString of an object whose own or inherited * @@toStringTag is a string (+1), NULL otherwise or with a pending * exception from its getter. */ @@ -9676,22 +9710,13 @@ ScrStr *scr_dyn_string_coerce_js(const ScrDyn *d) { return NULL; } if (d->kind == SCR_DYN_TYPED_REF) { - /* A class instance without its own conversion methods converts with - * Object.prototype.toString, which reads its toStringTag getter. */ - ScrStr *to_string_key = scr_str_new("toString", 8), *value_of_key = scr_str_new("valueOf", 7); - bool own_conversion = scr_dyn_typed_ref_class_has(d, to_string_key) || - scr_dyn_typed_ref_class_has(d, value_of_key); - scr_str_release(to_string_key); - scr_str_release(value_of_key); - if (!own_conversion) { - ScrStr *tag = scr_dyn_typed_ref_class_tag(d); - if (tag) { - ScrStr *out = scr_dyn_tag_string(tag); - scr_str_release(tag); - return out; - } - if (scr_exc_pending()) return NULL; + ScrStr *tag = scr_dyn_typed_ref_conversion_tag(d); + if (tag) { + ScrStr *out = scr_dyn_tag_string(tag); + scr_str_release(tag); + return out; } + if (scr_exc_pending()) return NULL; ScrDyn *materialized = scr_dyn_typed_ref_string_view(d); ScrStr *out = scr_dyn_string_coerce_js(materialized); scr_dyn_release(materialized); diff --git a/packages/runtime/src/scr_json.h b/packages/runtime/src/scr_json.h index de4510264..8a4ecc62d 100644 --- a/packages/runtime/src/scr_json.h +++ b/packages/runtime/src/scr_json.h @@ -119,6 +119,11 @@ _Static_assert(offsetof(ScrJsonBuf, data) == 0 && offsetof(ScrJsonBuf, len) == s "LLVM backend expects ScrJsonBuf to start with { data, len, cap }"); void scr_jb_init(ScrJsonBuf *b); +/* String conversion of a class instance whose ToString is + * Object.prototype.toString and whose class has a Symbol.toStringTag + * getter: appends "[object Tag]" and answers true, also with the getter's + * exception pending; false when the ordinary conversion applies. */ +bool scr_dyn_typed_ref_put_tag(ScrJsonBuf *b, const ScrDyn *d); /* Release a buffer's text without finishing it (error paths). */ void scr_jb_abandon(ScrJsonBuf *b); /* Append a borrowed byte span verbatim, including embedded NUL bytes. */ diff --git a/tests/corpus/7751-class-well-known-symbol-fields.ts b/tests/corpus/7751-class-well-known-symbol-fields.ts index 445af40d6..d57fce3f8 100644 --- a/tests/corpus/7751-class-well-known-symbol-fields.ts +++ b/tests/corpus/7751-class-well-known-symbol-fields.ts @@ -74,3 +74,42 @@ console.log(values); const literal: unknown = { [Symbol.toStringTag]: "Literal", a: 1 }; console.log(Object.prototype.toString.call(literal), String(literal), `${literal}`); + +// util.inspect ignores a Symbol.toStringTag getter that throws, typed or +// held as an untyped value. +class Throwing { + get [Symbol.toStringTag](): string { + throw new Error("tag"); + } +} +const throwing: unknown = new Throwing(); +console.log(new Throwing(), [new Throwing()], throwing, [throwing]); + +// A conversion to "[object Object]" still evaluates its receiver. +let made = 0; +function make(): Plain { + made++; + return new Plain(); +} +function fail(): Plain { + throw new Error("receiver"); +} +console.log(Object.prototype.toString.call(make()), String(make()), made); +try { + console.log(Object.prototype.toString.call(fail())); +} catch (error) { + console.log((error as Error).message); +} + +// ToString of a class with valueOf and no toString reads its tag; the +// default hint calls valueOf. +class Valued { + valueOf(): number { + return 1; + } + get [Symbol.toStringTag](): string { + return "Valued"; + } +} +const valued: unknown = new Valued(); +console.log(String(valued), `${valued}`, [valued].join(), valued + "", Object.prototype.toString.call(valued)); From 970a53c1ba17516b203fe445de2769392321ab2f Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 00:05:48 -0500 Subject: [PATCH 060/259] Store (T | undefined)[] elements as T so widened arrays stay one array A number[], string[] or boolean[] seen as (T | undefined)[] through a cast, a binding or a parameter is the same array in Node: undefined written through either name is visible through both. The type mapper now stores (T | undefined)[] of a number, string or boolean T as T elements, which hold a present undefined by their slot state, so the wider name shares the storage instead of converting to a separate union array. Writers of these arrays store undefined as a present undefined: element writes, push, unshift and splice, literals, Array.from (with a length or a mapper), Array.of, generator drains, flatMap, rest packs, copies from Map and Set values and Object.values, and checked conversions from dynamic values. Promise.all over Promise[] fills the result inside the combinator's settlement, so it settles on Node's turn. The element-state analysis counts callbacks and iterables whose checker type admits undefined. Readers keep their optional reads: index reads through a union of arrays, searches with a direct needle, and asserted reads, which throw a TypeError for undefined. Comparators and callbacks that receive present elements take the element type, without an adapter. --- packages/compiler/src/backend/llvm/dyn.ts | 25 ++- .../src/backend/llvm/expr-stream-bridges.ts | 19 +- .../src/frontend/lowering/array-values.ts | 140 +++++++++++++++ .../frontend/lowering/builtins/promises.ts | 162 +++++++++++++++++- .../src/frontend/lowering/call-arguments.ts | 10 ++ .../frontend/lowering/coercions/structural.ts | 110 ++++++++++-- .../lowering/containers/array-callbacks.ts | 66 +++++-- .../lowering/containers/array-construction.ts | 67 +++++++- .../lowering/containers/array-methods.ts | 106 +++++++++++- .../lowering/containers/callback-arguments.ts | 13 +- .../lowering/containers/collection-methods.ts | 12 ++ .../lowering/containers/indexed-objects.ts | 106 +++++++++--- .../lowering/expressions/array-literals.ts | 23 ++- .../lowering/expressions/element-access.ts | 45 +++++ .../frontend/lowering/iterator-adapters.ts | 58 +++---- .../compiler/src/frontend/lowering/lowerer.ts | 58 ++++++- .../lowering/runtime-optional-elements.ts | 9 +- .../frontend/lowering/sanitize-class-types.ts | 2 + packages/compiler/src/frontend/type-mapper.ts | 19 +- packages/compiler/src/ir/ir.ts | 11 +- packages/compiler/src/ir/validate.ts | 10 +- ...ional-element-arrays-share-storage.ts.json | 6 + .../8001-optional-element-writers.ts.json | 6 + ...0-optional-element-arrays-share-storage.ts | 61 +++++++ tests/corpus/8001-optional-element-writers.ts | 103 +++++++++++ ...ional-element-arrays-share-storage.ts.json | 1 + .../8001-optional-element-writers.ts.json | 1 + 27 files changed, 1145 insertions(+), 104 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8000-optional-element-arrays-share-storage.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8001-optional-element-writers.ts.json create mode 100644 tests/corpus/8000-optional-element-arrays-share-storage.ts create mode 100644 tests/corpus/8001-optional-element-writers.ts create mode 100644 tests/harness/corpus-costs/8000-optional-element-arrays-share-storage.ts.json create mode 100644 tests/harness/corpus-costs/8001-optional-element-writers.ts.json diff --git a/packages/compiler/src/backend/llvm/dyn.ts b/packages/compiler/src/backend/llvm/dyn.ts index 6d02daa8b..f3c8231e1 100644 --- a/packages/compiler/src/backend/llvm/dyn.ts +++ b/packages/compiler/src/backend/llvm/dyn.ts @@ -547,6 +547,13 @@ export class LlDyn { /* ── dyn node plumbing ─────────────────────────────────────────────── */ /** Loads a dyn node's kind tag (after the size_t rc word). */ + /** i1: the checked-dynamic value `d` is undefined. */ + isUndefined(B: BlockBuilder, d: string): string { + const is = B.tmp(); + B.line(`${is} = icmp eq i32 ${this.kindOf(B, d)}, ${DYN_KIND.UNDEF}`); + return is; + } + private kindOf(B: BlockBuilder, d: string): string { const p = B.tmp(); const k = B.tmp(); @@ -1655,7 +1662,8 @@ export class LlDyn { * BUILD the typed value (+1), or throw the catchable path-annotated * TypeError and return a dummy with the pending flag set. */ dynCheckHelper(t: IrType, preserveRefs = false): string { - const key = typeKey(t); + // A `(T | undefined)[]` stored as T elements also takes undefined ones. + const key = t.kind === "array" && t.optionalElements ? `${typeKey(t)}?` : typeKey(t); const builderKey = preserveRefs ? `identity:${key}` : key; const existing = this.dynBuilders.get(builderKey); if (existing) return existing; @@ -2435,6 +2443,21 @@ export class LlDyn { B.line(`${ip} = getelementptr inbounds %ScrDynPath, ptr ${pathSlot}, i64 0, i32 2`); B.line(`store ${host.sizeType} ${i}, ptr ${ip}`); const e = this.itemAt(B, items, i); + if (t.optionalElements) { + // An undefined element is a present undefined element. + const undef = B.tmp(); + const storeUndefined = B.newLabel("dca.undef"); + const checkLabel = B.newLabel("dca.check"); + B.line(`${undef} = icmp eq i32 ${this.kindOf(B, e)}, ${DYN_KIND.UNDEF}`); + B.condBr(undef, storeUndefined, checkLabel); + B.startBlock(storeUndefined); + host.declare(`declare void @scr_arr_set_undefined(ptr, double)`); + const at = B.tmp(); + B.line(`${at} = ${sizeToDouble(this.S)} ${this.S} ${i} to double`); + B.line(`call void @scr_arr_set_undefined(ptr ${a}, double ${at})`); + B.br(doneLabel); + B.startBlock(checkLabel); + } const v = B.tmp(); B.line(`${v} = call ${this.valTy(elem)} @${c}(ptr ${e}, ptr ${pathSlot})`); this.pendingBail( diff --git a/packages/compiler/src/backend/llvm/expr-stream-bridges.ts b/packages/compiler/src/backend/llvm/expr-stream-bridges.ts index 46c2d884f..814ef76b5 100644 --- a/packages/compiler/src/backend/llvm/expr-stream-bridges.ts +++ b/packages/compiler/src/backend/llvm/expr-stream-bridges.ts @@ -744,13 +744,16 @@ export function streamTypedRefMaterializeAdapter( t: IrType, ): LlStreamTypedRefAdapter { const key = typeKey(t); - const existing = host.liveDynRefAdapters.get(key); + // A `(T | undefined)[]` stored as T elements shares T[]'s capsule type, + // but its adapters also store undefined elements. + const adapterKey = t.kind === "array" && t.optionalElements ? `${key}?` : key; + const existing = host.liveDynRefAdapters.get(adapterKey); if (existing) return existing; // The converter depends only on the static type. Intern the complete // graph across roots and union arms so recursive types emit once. const snapshot = `sc_ldr_${host.liveDynRefAdapters.size}_materialize`; const adapter: LlStreamTypedRefAdapter = { snapshot, commit: "null" }; - host.liveDynRefAdapters.set(key, adapter); + host.liveDynRefAdapters.set(adapterKey, adapter); host.journal?.allocated( snapshot.replace(/_materialize$/, ""), "streamTypedRefMaterializeAdapter", @@ -1257,6 +1260,18 @@ function liveArrayOps( G.terminate(`ret ptr ${boxed}`); const S = new BlockBuilder(); + if (t.optionalElements) { + // A `(T | undefined)[]` stores undefined as a present undefined. + const undef = host.dyn.isUndefined(S, "%v"); + const storeUndefined = S.newLabel("live.array.undefined"); + const other = S.newLabel("live.array.value"); + S.condBr(undef, storeUndefined, other); + S.startBlock(storeUndefined); + host.declare(`declare void @scr_arr_set_undefined(ptr, double)`); + S.line(`call void @scr_arr_set_undefined(ptr %p, double %i)`); + S.terminate(`ret i1 true`); + S.startBlock(other); + } const fits = S.tmp(); S.line(`${fits} = call zeroext i1 @${host.dyn.dynMatchHelper(elem)}(ptr %v)`); const store = S.newLabel("live.array.store"); diff --git a/packages/compiler/src/frontend/lowering/array-values.ts b/packages/compiler/src/frontend/lowering/array-values.ts index f191ad942..6e4a45f86 100644 --- a/packages/compiler/src/frontend/lowering/array-values.ts +++ b/packages/compiler/src/frontend/lowering/array-values.ts @@ -269,6 +269,140 @@ function readsMutableLocal(lowerer: Lowerer, e: IrExpr): boolean { }); } +/** A number, string or boolean element type. Arrays of it hold a present + * undefined in the element's state, so `(T | undefined)[]` stores T + * elements (the type mapper) and a T[] seen as one stays the same array. */ +export function primitiveElement(elem: IrType): boolean { + return elem.kind === "f64" || elem.kind === "string" || elem.kind === "bool"; +} + +/** `value` is the element type with undefined, stored into an array of a + * primitive element type: a present undefined or the element. */ +export function optionalElementValue(lowerer: Lowerer, value: IrExpr, elem: IrType): boolean { + if (!primitiveElement(elem)) return false; + if (value.type.kind === "undefinedT") return true; + return ( + value.type.kind === "union" && + lowerer.armTag(value.type.unionId, UNDEFINED_T) >= 0 && + typeEquals(lowerer.stripUndefinedArm(value.type), elem) + ); +} + +/** A value of a primitive element type that holds a slot until the value + * stored there replaces it (insertedValues), or stands for a slot that is + * not read. */ +export function elementPlaceholder(elem: IrType, loc: SrcLoc): IrExpr { + if (elem.kind === "f64") return { kind: "numLit", value: 0, type: F64, loc }; + if (elem.kind === "bool") return { kind: "boolLit", value: false, type: BOOL, loc }; + return { kind: "strLit", value: "", type: STRING, loc }; +} + +/** Values inserted into an array (push, unshift, splice, a literal), in + * source order. A value that can be undefined (optionalElementValue) is + * kept in a temporary: the insertion takes a placeholder for it, and + * `fill` then stores the value at the placeholder's index. */ +export function insertedValues( + lowerer: Lowerer, + values: readonly IrExpr[], + elem: IrType, + coerce: (value: IrExpr, index: number) => IrExpr, + loc: SrcLoc, +): { + stmts: IrStmt[]; + args: IrExpr[]; + optional: boolean; + fill: (arr: IrExpr, first: IrExpr) => IrStmt[]; +} { + if (!values.some((value) => optionalElementValue(lowerer, value, elem))) + return { stmts: [], args: values.map(coerce), optional: false, fill: () => [] }; + const stmts: IrStmt[] = []; + const args: IrExpr[] = []; + const held: { offset: number; value: IrExpr }[] = []; + values.forEach((value, offset) => { + // Every value is evaluated in order before the insertion. + if (value.type.kind === "undefinedT") { + if (value.kind !== "unitLit") stmts.push({ kind: "exprStmt", expr: value, loc }); + args.push(elementPlaceholder(elem, loc)); + held.push({ offset, value: { kind: "unitLit", unit: "undefined", type: UNDEFINED_T, loc } }); + return; + } + const temp = lowerer.declareHiddenLocal("%inserted", value.type); + stmts.push({ kind: "varDecl", localId: temp.id, init: value, loc }); + const stable = varRef(temp.id, temp.type, loc); + if (optionalElementValue(lowerer, value, elem)) { + args.push(elementPlaceholder(elem, loc)); + held.push({ offset, value: stable }); + } else { + args.push(coerce(stable, offset)); + } + }); + const fill = (arr: IrExpr, first: IrExpr): IrStmt[] => + held.map(({ offset, value }) => + arrayValueStore( + lowerer, + arr, + offset === 0 + ? first + : { + kind: "bin", + op: "+", + left: first, + right: { kind: "numLit", value: offset, type: F64, loc }, + type: F64, + loc, + }, + value, + elem, + loc, + ), + ); + return { stmts, args, optional: true, fill }; +} + +/** Statements appending `value` to `arr` inside a lifted helper. A value + * that can be undefined in a primitive array (optionalElementValue) is held + * in the helper's local `slot` (which the caller declares with the value's + * type) and stored as a present undefined or the element; any other value + * converts to the element type. */ +export function appendElement( + lowerer: Lowerer, + arr: IrExpr, + value: IrExpr, + elem: IrType, + slot: string, + loc: SrcLoc, +): IrStmt[] { + if (optionalElementValue(lowerer, value, elem) && value.type.kind !== "undefinedT") { + const held = varRef(slot, value.type, loc); + const length: IrExpr = { + kind: "arrIntrinsic", + method: "length", + receiver: arr, + args: [], + type: F64, + loc, + }; + return [ + { kind: "varDecl", localId: slot, init: value, loc }, + arrayValueStore(lowerer, arr, length, held, elem, loc), + ]; + } + return [ + { + kind: "exprStmt", + expr: { + kind: "arrIntrinsic", + method: "push", + receiver: arr, + args: [lowerer.coerceToExpected(value, elem)], + type: F64, + loc, + }, + loc, + }, + ]; +} + /** Store a stabilized value without changing the array's element ABI. */ export function arrayValueStore( lowerer: Lowerer, @@ -279,6 +413,12 @@ export function arrayValueStore( loc: SrcLoc, ): IrStmt { if (typeEquals(value.type, elem)) return { kind: "arraySet", arr, index, value, loc }; + // An undefined value of a `(T | undefined)[]` (primitiveElement). + if (value.type.kind === "undefinedT" && primitiveElement(elem)) { + const write: IrStmt = { kind: "arraySetUndefined", arr, index, loc }; + if (value.kind === "unitLit") return write; + return { kind: "block", body: [{ kind: "exprStmt", expr: value, loc }, write], loc }; + } if (value.type.kind === "union" && lowerer.armTag(value.type.unionId, UNDEFINED_T) >= 0) { // The tag test and the VALUE arm extraction both consume the value. Keep // an arbitrary expression (especially an array read or call) single diff --git a/packages/compiler/src/frontend/lowering/builtins/promises.ts b/packages/compiler/src/frontend/lowering/builtins/promises.ts index e9d4322ad..c3b2cd479 100644 --- a/packages/compiler/src/frontend/lowering/builtins/promises.ts +++ b/packages/compiler/src/frontend/lowering/builtins/promises.ts @@ -3,7 +3,8 @@ import { checkedPromiseAll, thenReader } from "../checked-promise-all.js"; import { InternalCompilerError } from "../../../errors.js"; import * as ts from "../../ts7/adapter.js"; import type { Lowerer } from "../lowerer.js"; -import { varRef } from "../../../ir/build.js"; +import { countedFor, varRef } from "../../../ir/build.js"; +import { arrayValueStore, optionalElementValue, primitiveElement } from "../array-values.js"; import { maybePromiseResolve, maybePromiseUnionOf } from "../maybe-promise.js"; import { isJsSourceFile, locOf } from "../../program.js"; import { @@ -14,6 +15,7 @@ import { type IrFunction, type IrStmt, type IrType, + type SrcLoc, UNDEFINED_T, VOID, arrayOf, @@ -435,6 +437,28 @@ export function lowerPromiseStaticCall( inner.kind === "void" ? { kind: "promise", inner: VOID } : lowerer.mapTypeOf(lowerer.typeOf(call)); + // Promise[] combines into a `(T | undefined)[]`, which + // stores T elements (primitiveElement): collect the values, then copy + // them in with their present undefined values. + if ( + resultT?.kind === "promise" && + resultT.inner.kind === "array" && + primitiveElement(resultT.inner.elem) && + optionalElementValue( + lowerer, + { kind: "unitLit", unit: "undefined", type: inner, loc }, + resultT.inner.elem, + ) + ) { + const joined = optionalPromiseAll( + lowerer, + entries, + inner, + resultT as IrType & { kind: "promise" }, + loc, + ); + if (joined) return joined; + } if ( resultT?.kind !== "promise" || (inner.kind !== "void" && @@ -954,3 +978,139 @@ export function lowerAwaitedUniformPromiseAll( loc, }; } + +/** `Promise.all(ps)` over `Promise[]` for a number, string or + * boolean T, whose result is a `(T | undefined)[]` (stored as T elements). + * The combinator joins the entries (promise.allTuple), and its builder + * reads each fulfilled entry into the result with its present undefined, + * inside the combinator's settlement, so the result settles on Node's + * turn. Entries of another type keep the general combinator. */ +function optionalPromiseAll( + lowerer: Lowerer, + entries: IrExpr, + inner: IrType, + resultT: IrType & { kind: "promise" }, + loc: SrcLoc, +): IrExpr | null { + const entriesT = entries.type; + if (entriesT.kind !== "array" || entriesT.elem.kind !== "promise") return null; + if (!typeEquals(entriesT.elem.inner, inner)) return null; + const outT = resultT.inner as IrType & { kind: "array" }; + const voidPromise: IrType & { kind: "promise" } = { kind: "promise", inner: VOID }; + const joinedT = arrayOf(voidPromise); + const key = `promise.allOptional:${typeKey(entriesT)}:${typeKey(outT)}`; + let helper = lowerer.arrHofHelpers.get(key); + if (!helper) { + helper = keyedHelperName(lowerer, "%promise.allOptional", key); + lowerer.arrHofHelpers.set(key, helper); + const builder = keyedHelperName(lowerer, "%promise.allOptionalValues", key); + const length = (arr: IrExpr): IrExpr => ({ + kind: "arrIntrinsic", + method: "length", + receiver: arr, + args: [], + type: F64, + loc, + }); + const joined = varRef("joined.0", joinedT, loc); + const out = varRef("out.0", outT, loc); + lowerer.liftedFns.push({ + name: builder, + params: [{ localId: "joined.0", name: "joined", type: joinedT }], + returnType: outT, + locals: [ + { id: "joined.0", name: "joined", type: joinedT, mutable: false }, + { id: "out.0", name: "out", type: outT, mutable: false }, + { id: "i.0", name: "i", type: F64, mutable: true }, + { id: "v.0", name: "v", type: inner, mutable: false }, + ], + body: [ + { + kind: "varDecl", + localId: "out.0", + init: { kind: "arrayLit", elems: [], type: outT, loc }, + loc, + }, + countedFor(loc, length(joined), (index) => [ + { + kind: "varDecl", + localId: "v.0", + init: { + kind: "libCall", + fn: "promise.fulfilledValue", + args: [{ kind: "arrayGet", arr: joined, index, type: voidPromise, loc }], + type: inner, + loc, + }, + loc, + }, + arrayValueStore(lowerer, out, index, varRef("v.0", inner, loc), outT.elem, loc), + ]), + { kind: "return", value: out, loc }, + ], + loc, + }); + const ps = varRef("ps.0", entriesT, loc); + lowerer.liftedFns.push({ + name: helper, + params: [{ localId: "ps.0", name: "ps", type: entriesT }], + returnType: resultT, + locals: [ + { id: "ps.0", name: "ps", type: entriesT, mutable: false }, + { id: "joined.0", name: "joined", type: joinedT, mutable: false }, + { id: "i.0", name: "i", type: F64, mutable: true }, + ], + body: [ + { + kind: "varDecl", + localId: "joined.0", + init: { kind: "arrayLit", elems: [], type: joinedT, loc }, + loc, + }, + countedFor(loc, length(ps), (index) => [ + { + kind: "exprStmt", + expr: { + kind: "arrIntrinsic", + method: "push", + receiver: joined, + args: [ + { + kind: "promiseVoidWiden", + value: { kind: "arrayGet", arr: ps, index, type: entriesT.elem, loc }, + type: voidPromise, + loc, + }, + ], + type: F64, + loc, + }, + loc, + }, + ]), + { + kind: "return", + value: { + kind: "libCall", + fn: "promise.allTuple", + args: [ + joined, + { + kind: "closure", + fnName: builder, + captures: [], + type: funcOf([joinedT], outT), + loc, + }, + ], + type: resultT, + loc, + }, + loc, + }, + ], + loc, + }); + } + return { kind: "call", callee: helper, args: [entries], type: resultT, loc }; +} diff --git a/packages/compiler/src/frontend/lowering/call-arguments.ts b/packages/compiler/src/frontend/lowering/call-arguments.ts index 060ffe9d2..6da0cb337 100644 --- a/packages/compiler/src/frontend/lowering/call-arguments.ts +++ b/packages/compiler/src/frontend/lowering/call-arguments.ts @@ -28,6 +28,7 @@ import { checkedIterableSpread } from "./checked-iterable-spread.js"; import { type ParamShape } from "./call-signatures.js"; import { arrayValueRead, arrayValueType } from "./array-values.js"; import { buildArrayConversion } from "./coercions/builders.js"; +import { lowerArraySpreadItems } from "./containers/array-construction.js"; import { restTupleElementTypes, typeKey } from "../type-mapper.js"; function fixedTupleSpreadInfo( @@ -403,6 +404,15 @@ export function completeArgs( } } if (restType.kind !== "array") lowerer.unsupported("SC1090", blame, "this call form"); + // A `(T | undefined)[]` rest (stored as T elements) packs undefined + // arguments as present undefined elements. + const restNodes = sources.slice(restAt); + if (restType.optionalElements === true && !restNodes.some(isIr)) { + out.push( + lowerArraySpreadItems(lowerer, restNodes as ts.Expression[], restType.elem, restType, loc), + ); + return out; + } // The rest pack is a fresh array per call; surplus SPREADS copy // their elements in (JS-exact — `f(a, ...xs, b, ...ys)` packs in // order, sources untouched). diff --git a/packages/compiler/src/frontend/lowering/coercions/structural.ts b/packages/compiler/src/frontend/lowering/coercions/structural.ts index 4321a5ead..93ae1c231 100644 --- a/packages/compiler/src/frontend/lowering/coercions/structural.ts +++ b/packages/compiler/src/frontend/lowering/coercions/structural.ts @@ -1,12 +1,13 @@ import { keyedHelperName } from "../stable-names.js"; import { constructedValue } from "../constructor-returns.js"; -import { dynUndefinedExpr, varRef } from "../../../ir/build.js"; +import { countedFor, dynUndefinedExpr, varRef } from "../../../ir/build.js"; import type { FieldLift } from "./structural-plans.js"; import { buildArrayConversion } from "./builders.js"; +import { arrayValueRead, arrayValueStore, primitiveElement } from "../array-values.js"; import type { WidthLift } from "../width-lift.js"; import { InternalCompilerError } from "../../../errors.js"; import type { IrExpr, IrFunction, IrRecordShape, IrStmt, IrType, SrcLoc } from "../../../ir/ir.js"; -import { BOOL, DYN, F64, STRING, UNDEFINED_T } from "../../../ir/ir.js"; +import { BOOL, DYN, F64, STRING, UNDEFINED_T, typeEquals } from "../../../ir/ir.js"; import { typeKey } from "../../type-mapper.js"; import { findStaticOn, findGenericStaticOn } from "../lower-classes.js"; import { lowerRecordOvfCaptureHelper } from "../containers/indexed-objects.js"; @@ -54,6 +55,9 @@ export function widthCoerce(lowerer: Lowerer, expr: IrExpr, expected: IrType): I return lowerer.classStaticsProjection(expr.type.className, expected.shapeId, expr.loc); } if (expected.kind === "array" && expr.type.kind === "array") { + const optional = optionalArrayHelper(lowerer, expr.type, expected, expr.loc); + if (optional) + return { kind: "call", callee: optional, args: [expr], type: expected, loc: expr.loc }; const helper = lowerer.arrayWidthHelper(expr.type, expected, expr.loc); if (helper) return { kind: "call", callee: helper, args: [expr], type: expected, loc: expr.loc }; @@ -518,6 +522,69 @@ export function emptyArrayLiftHelper( return name; } +/** Copy an array of `T | undefined` unions (a collection's values, an + * iterator drain) into a `(T | undefined)[]` of a number, string or + * boolean T, which stores T elements: undefined values become present + * undefined elements. Null for other element types. */ +function optionalArrayHelper( + lowerer: Lowerer, + fromT: IrType & { kind: "array" }, + toT: IrType & { kind: "array" }, + loc: SrcLoc, +): string | null { + const from = fromT.elem; + const to = toT.elem; + if ( + !primitiveElement(to) || + from.kind !== "union" || + lowerer.armTag(from.unionId, UNDEFINED_T) < 0 || + !typeEquals(lowerer.stripUndefinedArm(from), to) + ) + return null; + const key = `arrOptional:${typeKey(from)}:${typeKey(to)}`; + const existing = lowerer.valueHelpers.get(key); + if (existing) return existing; + const name = keyedHelperName(lowerer, "%arr.width", key); + lowerer.valueHelpers.set(key, name); + const input = varRef("a.0", fromT, loc); + const out = varRef("out.0", toT, loc); + lowerer.liftedFns.push({ + name, + params: [{ localId: "a.0", name: "a", type: fromT }], + returnType: toT, + locals: [ + { id: "a.0", name: "a", type: fromT, mutable: true }, + { id: "out.0", name: "out", type: toT, mutable: false }, + { id: "i.0", name: "i", type: F64, mutable: true }, + { id: "v.0", name: "v", type: from, mutable: false }, + ], + body: [ + { + kind: "varDecl", + localId: "out.0", + init: { kind: "arrayLit", elems: [], type: toT, loc }, + loc, + }, + countedFor( + loc, + { kind: "arrIntrinsic", method: "length", receiver: input, args: [], type: F64, loc }, + (index) => [ + { + kind: "varDecl", + localId: "v.0", + init: arrayValueRead(lowerer, input, index, from, loc), + loc, + }, + arrayValueStore(lowerer, out, index, varRef("v.0", from, loc), to, loc), + ], + ), + { kind: "return", value: out, loc }, + ], + loc, + }); + return name; +} + /** Copy an array through its validated element conversion. Intern before * building the body so recursive element conversions can reuse this helper. */ export function arrayWidthHelper( @@ -542,14 +609,37 @@ export function arrayWidthHelper( name, arrT, { kind: "arrayLit", elems: [], type: outT, loc }, - (element, _index, result) => ({ - kind: "arrIntrinsic", - method: "push", - receiver: result, - args: [lowerer.applyWidthLift(elemLift, element, toElem, loc)], - type: F64, - loc, - }), + (element, index, result) => { + let value = lowerer.applyWidthLift(elemLift, element, toElem, loc); + // A number, string or boolean array can hold present undefined + // elements (`(T | undefined)[]` stores T): they, and holes, copy + // as the target's undefined. + const missing = primitiveElement(fromElem) ? lowerer.wrappedUndefined(toElem, loc) : null; + if (missing !== null) + value = { + kind: "ternary", + cond: { + kind: "bin", + op: "===", + left: { kind: "arrayState", arr: varRef("a.0", arrT, loc), index, type: F64, loc }, + right: { kind: "numLit", value: 1, type: F64, loc }, + type: BOOL, + loc, + }, + then: value, + else_: missing, + type: toElem, + loc, + }; + return { + kind: "arrIntrinsic", + method: "push", + receiver: result, + args: [value], + type: F64, + loc, + }; + }, loc, ), ); diff --git a/packages/compiler/src/frontend/lowering/containers/array-callbacks.ts b/packages/compiler/src/frontend/lowering/containers/array-callbacks.ts index edf65ab2b..1062c56b1 100644 --- a/packages/compiler/src/frontend/lowering/containers/array-callbacks.ts +++ b/packages/compiler/src/frontend/lowering/containers/array-callbacks.ts @@ -42,6 +42,7 @@ import { arrayValueStore, arrayValueType, currentArrayIndexPresent, + primitiveElement, } from "../array-values.js"; import { typeKey } from "../../type-mapper.js"; import { @@ -1689,6 +1690,8 @@ function flatMapUnionPlan( } const converts = (t: IrType): boolean => { if (typeEquals(t, outElem)) return true; + // A `(T | undefined)[]` result stores T elements (primitiveElement). + if (t.kind === "undefinedT" && primitiveElement(outElem)) return true; if (outElem.kind !== "union") return false; return lowerer.armTag(outElem.unionId, t) >= 0; }; @@ -1754,24 +1757,21 @@ function flatMapUnionHelper( }; if (plan.arms[tag] === "empty") return []; if (plan.arms[tag] === "value") { + // A unit arm's value is the unit itself, which has no narrowed + // representation. + const value: IrExpr = isUnitType(arm) + ? { kind: "unitLit", unit: arm.kind === "nullT" ? "null" : "undefined", type: arm, loc } + : narrowed; return [ arrayValueStore( lowerer, outRef(), outLength(), - lowerer.coerceToExpected( - // A unit arm's value is the unit itself, which has no - // narrowed representation. - isUnitType(arm) - ? { - kind: "unitLit", - unit: arm.kind === "nullT" ? "null" : "undefined", - type: arm, - loc, - } - : narrowed, - plan.outElem, - ), + // An undefined value is a present undefined element of a + // primitive array (arrayValueStore). + arm.kind === "undefinedT" && primitiveElement(plan.outElem) + ? value + : lowerer.coerceToExpected(value, plan.outElem), plan.outElem, loc, ), @@ -2347,6 +2347,43 @@ function reduceHelper( return name; } +/** The comparator of a sort over a `(T | undefined)[]`, which stores T + * elements. The comparator only receives present elements (undefined + * elements sort last without a call), so the unannotated parameters of an + * inline comparator take the element type, and the runtime calls it + * without an adapter. */ +function lowerOptionalElementComparator( + lowerer: Lowerer, + argNode: ts.Expression, + comparator: ts.Expression, + elem: IrType, + arrT: IrType & { kind: "array" }, +): IrExpr { + if ( + arrT.optionalElements !== true || + !(ts.isArrowFunction(comparator) || ts.isFunctionExpression(comparator)) || + isJsSourceFile(ts.getSourceFileOfNode(comparator)) + ) + return lowerer.lowerExpr(argNode); + const rebound: { symbol: ts.Symbol; previous: IrType | undefined }[] = []; + for (const param of comparator.parameters.nodes.slice(0, 2)) { + if (param.type || param.initializer || param.dotDotDotToken || !ts.isIdentifier(param.name)) + continue; + const symbol = lowerer.checker.getSymbolAtLocation(param.name); + if (!symbol) continue; + rebound.push({ symbol, previous: lowerer.runtimeOptionalBindingTypes.get(symbol) }); + lowerer.runtimeOptionalBindingTypes.set(symbol, elem); + } + try { + return lowerer.lowerExpr(argNode); + } finally { + for (const { symbol, previous } of rebound) { + if (previous === undefined) lowerer.runtimeOptionalBindingTypes.delete(symbol); + else lowerer.runtimeOptionalBindingTypes.set(symbol, previous); + } + } +} + /** `a.sort(cmp)` / `a.toSorted(cmp)`, desugared to an interned synthetic * function like the other array HOFs. sort mutates and returns the receiver; * toSorted takes its shallow snapshot INSIDE the helper, after the receiver @@ -2435,7 +2472,8 @@ export function lowerArraySortCall( loc, }; } - let fnArg = undefinedArg ?? lowerer.lowerExpr(argNode); + let fnArg = + undefinedArg ?? lowerOptionalElementComparator(lowerer, argNode, unwrappedArg, elem, arrT); // Reusable JS comparators often accept checked values. Adapt the array's // element ABI just as other array callbacks do before sorting. if ( diff --git a/packages/compiler/src/frontend/lowering/containers/array-construction.ts b/packages/compiler/src/frontend/lowering/containers/array-construction.ts index 1ca51f526..25a98c8a6 100644 --- a/packages/compiler/src/frontend/lowering/containers/array-construction.ts +++ b/packages/compiler/src/frontend/lowering/containers/array-construction.ts @@ -35,7 +35,13 @@ import { typeEquals, } from "../../../ir/ir.js"; import { isJsSourceFile, locOf } from "../../program.js"; -import { arrayValueRead, arrayValueStore, arrayValueType } from "../array-values.js"; +import { + arrayValueRead, + arrayValueStore, + arrayValueType, + optionalElementValue, + primitiveElement, +} from "../array-values.js"; import { typeKey } from "../../type-mapper.js"; import { newFnCtx } from "../lowerer.js"; import { iteratorCanStep, iteratorValue } from "../iterator-consumption.js"; @@ -88,7 +94,8 @@ export function lowerArrayValueItems( ]; for (const value of values) { const stored = - lowerer.runtimeOptionalWidening(value.type, elem) !== null + lowerer.runtimeOptionalWidening(value.type, elem) !== null || + optionalElementValue(lowerer, value, elem) ? value : lowerer.coerceToExpected(value, elem); body.push(arrayValueStore(lowerer, outRef, length(), stored, elem, loc)); @@ -212,7 +219,8 @@ export function lowerArraySpreadItems( } else { const value = lowerer.lowerExpr(node); const stored = - lowerer.runtimeOptionalWidening(value.type, elem) !== null + lowerer.runtimeOptionalWidening(value.type, elem) !== null || + optionalElementValue(lowerer, value, elem) ? value : lowerer.coerceInto(node, value, elem); body.push(arrayValueStore(lowerer, outRef, length(), stored, elem, loc)); @@ -518,6 +526,20 @@ export function lowerArrayOfCall( if (call.arguments.nodes.some(ts.isSpreadElement)) { return lowerArraySpreadItems(lowerer, call.arguments.nodes, result.elem, result, locOf(call)); } + // A `(T | undefined)[]` (primitiveElement) stores undefined arguments as + // present undefined elements. + if (result.optionalElements === true) { + const nodes = call.arguments.nodes; + const values = nodes.map((arg) => lowerer.lowerExpr(arg)); + if (values.some((value) => optionalElementValue(lowerer, value, result.elem))) + return lowerArrayValueItems(lowerer, values, result.elem, result, locOf(call)); + return { + kind: "arrayLit", + elems: values.map((value, i) => lowerer.coerceInto(nodes[i]!, value, result.elem)), + type: result, + loc: locOf(call), + }; + } return { kind: "arrayLit", elems: call.arguments.nodes.map((arg) => lowerer.lowerExprExpecting(arg, result.elem)), @@ -959,6 +981,31 @@ export function lowerArrayFromCall( const arrT = lowerer.mapTypeOf(lowerer.typeOf(call)); if (arrT?.kind !== "array") lowerer.badType(call, lowerer.typeOf(call)); const elem = arrT.elem; + // A `(T | undefined)[]` (primitiveElement): n present undefined + // elements. + const elemTs = lowerer.checker.isArrayType(lowerer.typeOf(call)) + ? lowerer.checker.getTypeArguments(lowerer.typeOf(call) as ts.TypeReference)[0] + : undefined; + if ( + primitiveElement(elem) && + elemTs !== undefined && + (elemTs.isUnionType() ? ts.constituentTypes(elemTs) : [elemTs]).some( + (part) => (part.flags & ts.TypeFlags.Undefined) !== 0, + ) + ) { + return { + kind: "arrIntrinsic", + method: "fillUndefined", + receiver: { kind: "arrayNewLen", length: n, type: arrT, loc }, + // To the end: fill clamps an infinite end to the length. + args: [ + numLit(0, loc), + { kind: "bin", op: "/", left: numLit(1, loc), right: numLit(0, loc), type: F64, loc }, + ], + type: arrT, + loc, + }; + } const absent = elem.kind === "union" ? lowerer.wrappedUndefined(elem, loc) !== null || @@ -1085,7 +1132,10 @@ export function lowerArrayFromCall( // A generator (or an iterator adapted into one) drains in order. if (src.type.kind === "generator" && args.length === 1) { const arrT = lowerer.mapTypeOf(lowerer.typeOf(call)); - const drained = arrT?.kind === "array" ? generatorDrain(lowerer, src, arrT.elem, loc) : null; + const drained = + arrT?.kind === "array" + ? generatorDrain(lowerer, src, arrT.elem, loc, arrT.optionalElements === true) + : null; if (drained) return drained; } lowerer.noLowering( @@ -1159,6 +1209,11 @@ function buildArrayFromArrayFn( type: fnRet, loc, }; + // A result of another type than the element (`T | undefined` into a + // `(T | undefined)[]`, which stores T elements) is held in a local, so + // the store tests and converts one value. + const held = !typeEquals(fnRet, outElem); + const value: IrExpr = held ? varRef("v.0", fnRet, loc) : mapped; return { name, params: [ @@ -1171,6 +1226,7 @@ function buildArrayFromArrayFn( { id: "f.0", name: "f", type: fnT, mutable: true }, { id: "out.0", name: "out", type: outT, mutable: false }, { id: "i.0", name: "i", type: F64, mutable: true }, + ...(held ? [{ id: "v.0", name: "v", type: fnRet, mutable: false }] : []), ], body: [ { @@ -1191,7 +1247,8 @@ function buildArrayFromArrayFn( loc, }, body: [ - arrayValueStore(lowerer, out, i, mapped, outElem, loc), + ...(held ? [{ kind: "varDecl", localId: "v.0", init: mapped, loc } as const] : []), + arrayValueStore(lowerer, out, i, value, outElem, loc), { kind: "assign", localId: "i.0", diff --git a/packages/compiler/src/frontend/lowering/containers/array-methods.ts b/packages/compiler/src/frontend/lowering/containers/array-methods.ts index 4ef203edd..f406e57eb 100644 --- a/packages/compiler/src/frontend/lowering/containers/array-methods.ts +++ b/packages/compiler/src/frontend/lowering/containers/array-methods.ts @@ -32,6 +32,10 @@ import { arrayValueRead, arrayValueStore, arrayValueType, + elementPlaceholder, + insertedValues, + optionalElementValue, + primitiveElement, } from "../array-values.js"; import { typeKey } from "../../type-mapper.js"; import { @@ -125,6 +129,14 @@ function lowerOptionalArrayPush( return { kind: "seqExpr", stmts, result: length(), type: F64, loc }; } +/** The checker type of `node` admits undefined. */ +function checkerTypeAdmitsUndefined(lowerer: Lowerer, node: ts.Expression): boolean { + const type = lowerer.typeOf(node); + return (type.isUnionType() ? ts.constituentTypes(type) : [type]).some( + (part) => (part.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Void)) !== 0, + ); +} + /** `a.splice(start, count, v)` where v may hold undefined at run time. * Receiver, start, count, and v evaluate once, in order; a present v is * inserted as a plain element literal (which a statement-position splice @@ -658,7 +670,10 @@ export function lowerArrayMethodCall( const hasSpread = itemNodes.some(ts.isSpreadElement); const itemProbes = hasSpread ? [] : itemNodes.map((arg) => tryLowerExpression(lowerer, arg)); const statefulItems = itemProbes.some( - (probe) => probe !== null && lowerer.runtimeOptionalWidening(probe.type, elem) !== null, + (probe) => + probe !== null && + (lowerer.runtimeOptionalWidening(probe.type, elem) !== null || + optionalElementValue(lowerer, probe, elem)), ); const items: IrExpr = hasSpread ? lowerArraySpreadItems(lowerer, itemNodes, elem, receiverIr, loc) @@ -875,6 +890,65 @@ export function lowerArrayMethodCall( loc, }; } + // A `(T | undefined)[]` (primitiveElement) takes undefined values as + // present undefined elements, stored after the insertion. + if ( + (name === "push" || name === "unshift") && + primitiveElement(elem) && + call.arguments.nodes.some((a) => checkerTypeAdmitsUndefined(lowerer, a)) + ) { + const nodes = call.arguments.nodes; + const values = nodes.map((a) => lowerer.lowerExpr(a)); + const inserted = insertedValues( + lowerer, + values, + elem, + (value, i) => lowerer.coerceInto(nodes[i]!, value, elem), + loc, + ); + if (inserted.optional) { + const array = lowerer.declareHiddenLocal("%insertInto", receiver.type); + const arr = varRef(array.id, array.type, loc); + const length = lowerer.declareHiddenLocal("%insertLength", F64); + const count: IrExpr = numLit(values.length, loc); + const first: IrExpr = + name === "push" + ? { + kind: "bin", + op: "-", + left: varRef(length.id, F64, loc), + right: count, + type: F64, + loc, + } + : numLit(0, loc); + return { + kind: "seqExpr", + stmts: [ + { kind: "varDecl", localId: array.id, init: receiver, loc }, + ...inserted.stmts, + { + kind: "varDecl", + localId: length.id, + init: { + kind: "arrIntrinsic", + method: name, + receiver: arr, + args: inserted.args, + type: F64, + loc, + }, + loc, + }, + ...inserted.fill(arr, first), + ], + result: varRef(length.id, F64, loc), + type: F64, + loc, + }; + } + return { kind: "arrIntrinsic", method: name, receiver, args: inserted.args, type: F64, loc }; + } // Inserted values flow into the element slot like an assignment would: // union-element arrays wrap plain arm values (coerceInto is inert // when the types already agree). @@ -996,9 +1070,12 @@ export function lowerArrayMethodCall( const hasSpread = itemNodes.some(ts.isSpreadElement); const itemProbes = hasSpread ? [] : itemNodes.map((arg) => tryLowerExpression(lowerer, arg)); const statefulItems = itemProbes.some( - (probe) => probe !== null && lowerer.runtimeOptionalWidening(probe.type, elem) !== null, + (probe) => + probe !== null && + (lowerer.runtimeOptionalWidening(probe.type, elem) !== null || + optionalElementValue(lowerer, probe, elem)), ); - if (statefulItems && itemNodes.length === 1) { + if (statefulItems && itemNodes.length === 1 && itemProbes[0]?.type.kind === "union") { return lowerOptionalSpliceItem( lowerer, receiver, @@ -1734,7 +1811,28 @@ function arraySearchHelper( type: valueT, loc, }; - const value = directNeedle ? rawRead : optionalValue; + // A direct needle matches only a present value (`match` tests the state + // first); a present undefined of a `(T | undefined)[]` (primitiveElement) + // must not be read as T. + const value = !directNeedle + ? optionalValue + : primitiveElement(elem) + ? { + kind: "ternary" as const, + cond: { + kind: "bin" as const, + op: "===" as const, + left: stateRef, + right: numLit(1, loc), + type: BOOL, + loc, + }, + then: rawRead, + else_: elementPlaceholder(elem, loc), + type: elem, + loc, + } + : rawRead; const readT = directNeedle ? elem : valueT; const equal = arraySearchEquality( lowerer, diff --git a/packages/compiler/src/frontend/lowering/containers/callback-arguments.ts b/packages/compiler/src/frontend/lowering/containers/callback-arguments.ts index d95640978..de027e08c 100644 --- a/packages/compiler/src/frontend/lowering/containers/callback-arguments.ts +++ b/packages/compiler/src/frontend/lowering/containers/callback-arguments.ts @@ -2,6 +2,7 @@ import { keyedHelperName } from "../stable-names.js"; import * as ts from "../../ts7/adapter.js"; import type { Lowerer } from "../lowerer.js"; import { isJsSourceFile, locOf } from "../../program.js"; +import { primitiveElement } from "../array-values.js"; import { varRef } from "../../../ir/build.js"; import { typeKey } from "../../type-mapper.js"; import { @@ -144,12 +145,22 @@ export function lowerArrayCallback( const untyped = (checkerType.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) !== 0; const raw = untyped ? null : lowerer.mapTypeOf(checkerType); const mapped = raw ? lowerer.runtimeOptionalBindingType(param.name, raw) : null; + // A helper that passes present number, string or boolean elements + // (a `(T | undefined)[]` stores T elements) binds a `T | undefined` + // parameter to T, so the callback takes them without an adapter. + const presentElement = + mapped !== null && + primitiveElement(expected) && + mapped.kind === "union" && + lowerer.armTag(mapped.unionId, UNDEFINED_T) >= 0 && + typeEquals(lowerer.stripUndefinedArm(mapped), expected); if ( untyped ? !bindUntyped : mapped === null || (lowerer.coercibleValue(expected, mapped) && - !runtimeOptionalPairVariant(lowerer, expected, mapped)) + !runtimeOptionalPairVariant(lowerer, expected, mapped) && + !presentElement) ) return; const symbol = lowerer.checker.getSymbolAtLocation(param.name); diff --git a/packages/compiler/src/frontend/lowering/containers/collection-methods.ts b/packages/compiler/src/frontend/lowering/containers/collection-methods.ts index e043daf68..f18291a63 100644 --- a/packages/compiler/src/frontend/lowering/containers/collection-methods.ts +++ b/packages/compiler/src/frontend/lowering/containers/collection-methods.ts @@ -1,4 +1,5 @@ import { keyedHelperName } from "../stable-names.js"; +import { primitiveElement } from "../array-values.js"; import { nodeThrowExpr, boolLit, countedFor, numLit, strLit, varRef } from "../../../ir/build.js"; import { InternalCompilerError } from "../../../errors.js"; import * as ts from "../../ts7/adapter.js"; @@ -1137,6 +1138,17 @@ function setFromSeedValue( seed = strCharsCall(lowerer, source, loc); } else if (source.type.kind === "array" && typeEquals(source.type.elem, setT.elem)) { seed = source; + } else if ( + source.type.kind === "array" && + primitiveElement(source.type.elem) && + setT.elem.kind === "union" && + lowerer.armTag(setT.elem.unionId, UNDEFINED_T) >= 0 && + typeEquals(lowerer.stripUndefinedArm(setT.elem), source.type.elem) + ) { + // A `(T | undefined)[]` stores T elements: its present undefined + // elements copy as the Set's undefined. + seed = lowerer.coerceToExpected(source, arrayOf(setT.elem)); + if (!typeEquals(seed.type, arrayOf(setT.elem))) return null; } else if (source.type.kind === "record") { const shape = lowerer.shapes.get(source.type.shapeId); if (!shape?.tuple || !shape.fields.every((field) => typeEquals(field.type, setT.elem))) diff --git a/packages/compiler/src/frontend/lowering/containers/indexed-objects.ts b/packages/compiler/src/frontend/lowering/containers/indexed-objects.ts index 668603d47..1c07885ae 100644 --- a/packages/compiler/src/frontend/lowering/containers/indexed-objects.ts +++ b/packages/compiler/src/frontend/lowering/containers/indexed-objects.ts @@ -1,6 +1,7 @@ import { keyedHelperName } from "../stable-names.js"; import { nullProtoRecordShape, recordNullProtoTest } from "../null-prototype.js"; import { countedFor, numLit, varRef } from "../../../ir/build.js"; +import { arrayValueStore, optionalElementValue, primitiveElement } from "../array-values.js"; import { objectEnumerationReceiver } from "../object-enumeration-receiver.js"; import { InternalCompilerError } from "../../../errors.js"; import * as ts from "../../ts7/adapter.js"; @@ -156,7 +157,14 @@ export function objectIterOverIndexShape( // also holds numbers): each overflow value checks into the element type, // so a value of a dropped arm throws instead of mistyping. let ivNarrows = false; - if (valueT) { + // `T | undefined` values into a `(T | undefined)[]`, which stores T + // elements (primitiveElement): each value is stored with its present + // undefined. + const optionalValues = + member === "values" && + valueT !== null && + optionalElementValue(lowerer, { kind: "unitLit", unit: "undefined", type: iv, loc }, valueT); + if (valueT && !optionalValues) { const ivSurfaces = typeEquals(iv, valueT) || (valueT.kind === "union" && lowerer.armTag(valueT.unionId, iv) >= 0) || @@ -350,7 +358,25 @@ export function objectIterOverIndexShape( loc, }, then: [fieldStmt], - else_: undefinedElement ? [push(pushedOf(undefinedElement))] : null, + else_: undefinedElement + ? [push(pushedOf(undefinedElement))] + : member === "values" && valueT && primitiveElement(valueT) + ? [ + { + kind: "arraySetUndefined", + arr: outRef, + index: { + kind: "arrIntrinsic", + method: "length", + receiver: outRef, + args: [], + type: F64, + loc, + }, + loc, + }, + ] + : null, loc, }; } @@ -374,35 +400,45 @@ export function objectIterOverIndexShape( const kRef = varRef("k.0", STRING, loc); const readValue: IrExpr | null = !valueT ? null - : ivNarrows + : optionalValues ? { - kind: "dynCheck", - value: { - kind: "dynFrom", - value: { - kind: "recordKeyGet", - obj: rRef, - shapeId: argIr.shapeId, - key: kRef, - overflowOnly: true, - type: iv, - loc, - }, - type: DYN, - loc, - }, - type: valueT, - loc, - } - : { kind: "recordKeyGet", obj: rRef, shapeId: argIr.shapeId, key: kRef, overflowOnly: true, - type: valueT, + type: iv, loc, - }; + } + : ivNarrows + ? { + kind: "dynCheck", + value: { + kind: "dynFrom", + value: { + kind: "recordKeyGet", + obj: rRef, + shapeId: argIr.shapeId, + key: kRef, + overflowOnly: true, + type: iv, + loc, + }, + type: DYN, + loc, + }, + type: valueT, + loc, + } + : { + kind: "recordKeyGet", + obj: rRef, + shapeId: argIr.shapeId, + key: kRef, + overflowOnly: true, + type: valueT, + loc, + }; const loopPushed: IrExpr = member === "keys" ? kRef @@ -440,7 +476,26 @@ export function objectIterOverIndexShape( }, loc, }, - push(loopPushed), + ...(optionalValues + ? [ + { kind: "varDecl" as const, localId: "v.0", init: readValue!, loc }, + arrayValueStore( + lowerer, + outRef, + { + kind: "arrIntrinsic", + method: "length", + receiver: outRef, + args: [], + type: F64, + loc, + }, + varRef("v.0", iv, loc), + valueT!, + loc, + ), + ] + : [push(loopPushed)]), ], ), { kind: "return", value: outRef, loc }, @@ -457,6 +512,7 @@ export function objectIterOverIndexShape( { id: "ks.0", name: "ks", type: ksT, mutable: false }, { id: "i.0", name: "i", type: F64, mutable: true }, { id: "k.0", name: "k", type: STRING, mutable: false }, + ...(optionalValues ? [{ id: "v.0", name: "v", type: iv, mutable: false }] : []), ], body, loc, diff --git a/packages/compiler/src/frontend/lowering/expressions/array-literals.ts b/packages/compiler/src/frontend/lowering/expressions/array-literals.ts index c1b54a417..773f4cf0b 100644 --- a/packages/compiler/src/frontend/lowering/expressions/array-literals.ts +++ b/packages/compiler/src/frontend/lowering/expressions/array-literals.ts @@ -31,7 +31,7 @@ import { strCharsCall } from "../containers/array-construction.js"; import { generatorDrain } from "../iterator-adapters.js"; import { isSearchParamsIterable } from "../builtins/url.js"; import { varRef } from "../../../ir/build.js"; -import { arrayValueStore } from "../array-values.js"; +import { arrayValueStore, primitiveElement } from "../array-values.js"; import { classGeneratorIterable } from "../class-iterables.js"; /** JavaScript: whether `expr` is or holds an existing checked-dynamic @@ -102,6 +102,13 @@ function emptyNeverLiteral(lowerer: Lowerer, expr: ts.ArrayLiteralExpression): b * tsc's API doesn't surface it (ternary arms under an array context — * tsc accepts the arm covariantly, but a tagged element representation * must be BUILT as the slot's element type). */ +/** The checker type of `node` admits undefined. */ +function mayHoldUndefined(lowerer: Lowerer, node: ts.Expression): boolean { + const type = lowerer.typeOf(node); + const parts = type.isUnionType() ? ts.constituentTypes(type) : [type]; + return parts.some((part) => (part.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Void)) !== 0); +} + export function lowerArrayLiteral( lowerer: Lowerer, expr: ts.ArrayLiteralExpression, @@ -515,7 +522,13 @@ export function lowerArrayLiteral( // `[...it]` over a generator (or an iterator adapted into one): // drain it once, in order, into a fresh element array. if (src.type.kind === "generator") { - const drained = generatorDrain(lowerer, src, type.elem, locOf(el)); + const drained = generatorDrain( + lowerer, + src, + type.elem, + locOf(el), + type.optionalElements === true, + ); if (drained) src = drained; } // `[...sp]` and `[...sp.entries()]` over a URLSearchParams: its @@ -606,6 +619,9 @@ export function lowerArrayLiteral( let lowered: IrExpr; const directOptionalCandidate = runtimeOptionalElements.has(i) || + // An element that can be undefined in a `(T | undefined)[]` + // (primitiveElement) is stored as a present undefined. + (primitiveElement(type.elem) && mayHoldUndefined(lowerer, el)) || ts.isElementAccessExpression(el) || (ts.isCallExpression(el) && ts.isPropertyAccessExpression(el.expression) && @@ -683,7 +699,8 @@ export function lowerArrayLiteral( continue; } let value = el; - if (!typeEquals(value.type, type.elem)) { + // An undefined element is stored directly (arrayValueStore). + if (!typeEquals(value.type, type.elem) && value.type.kind !== "undefinedT") { const temp = lowerer.declareHiddenLocal("%arrayValue", value.type); body.push({ kind: "varDecl", localId: temp.id, init: value, loc }); value = varRef(temp.id, temp.type, loc); diff --git a/packages/compiler/src/frontend/lowering/expressions/element-access.ts b/packages/compiler/src/frontend/lowering/expressions/element-access.ts index 9ac6a04b6..70909ca7b 100644 --- a/packages/compiler/src/frontend/lowering/expressions/element-access.ts +++ b/packages/compiler/src/frontend/lowering/expressions/element-access.ts @@ -61,6 +61,8 @@ import { arrayValueType, lowerSafeBytesRead, lowerSafeIndexRead, + primitiveElement, + unionArrayValueRead, } from "../array-values.js"; import { lowerOptionalStringIndex, lowerUnionStringIndex } from "../string-index.js"; import { InternalCompilerError } from "../../../errors.js"; @@ -594,6 +596,8 @@ export function lowerElementAccess(lowerer: Lowerer, expr: ts.ElementAccessExpre } } if (key.type.kind === "f64") { + const optional = optionalArmIndexRead(lowerer, value, key, locOf(expr)); + if (optional) return lowerer.maybeNarrow(optional, expr); const safe = lowerOptionalArrayIndexRead(lowerer, expr, value, key); if (safe) return safe; } @@ -884,9 +888,14 @@ export function lowerElementAccess(lowerer: Lowerer, expr: ts.ElementAccessExpre // must be the element type (library ABI checks and the catchable // RangeError contract for an out-of-bounds assert). Where undefined is // representable, the assertion keeps JavaScript's unchecked read. + // A declared `(T | undefined)[]` element (stored as T) keeps its + // optional read: the assertion then narrows it with a catchable + // TypeError, as for a union element. + const declaredOptional = arr.type.optionalElements === true; const provenPresent = ts.isNonNullExpression(expr.parent) && expr.parent.expression === expr && + !declaredOptional && !assertedElementKeepsUndefined(lowerer, expr.parent); if (provenPresent) { return lowerer.maybeNarrow( @@ -2437,3 +2446,39 @@ export function lowerEnvironmentKey(lowerer: Lowerer, node: ts.Expression): IrEx return { kind: "libCall", fn: "dyn.toStringCoerce", args: [key], type: STRING, loc: key.loc }; return lowerRecordPropertyKey(lowerer, key, node); } + +/** A number-keyed read of a union of arrays with a `(T | undefined)[]` arm + * (stored as T elements, primitiveElement) whose element facts admit + * missing values: each arm reads its element by its state + * (unionArrayValueRead), where the keyed read would trap on a present + * undefined. The receiver and key evaluate once. Null for other unions. */ +function optionalArmIndexRead( + lowerer: Lowerer, + value: IrExpr, + key: IrExpr, + loc: SrcLoc, +): IrExpr | null { + if (value.type.kind !== "union") return null; + const arms = lowerer.unions.get(value.type.unionId)?.arms ?? []; + if ( + !arms.some( + (arm) => + arm.kind === "array" && + primitiveElement(arm.elem) && + arrayValueType(lowerer, arm.elem).kind === "union", + ) + ) + return null; + if (unionArrayValueRead(lowerer, value, key, loc) === null) return null; + const stmts: IrStmt[] = []; + const stable = (e: IrExpr, name: string): IrExpr => { + if (e.kind === "varRef" || e.kind === "numLit") return e; + const local = lowerer.declareHiddenLocal(name, e.type); + stmts.push({ kind: "varDecl", localId: local.id, init: e, loc }); + return varRef(local.id, e.type, loc); + }; + const receiver = stable(value, "%indexReceiver"); + const index = stable(key, "%indexKey"); + const read = unionArrayValueRead(lowerer, receiver, index, loc)!; + return stmts.length === 0 ? read : { kind: "seqExpr", stmts, result: read, type: read.type, loc }; +} diff --git a/packages/compiler/src/frontend/lowering/iterator-adapters.ts b/packages/compiler/src/frontend/lowering/iterator-adapters.ts index 9f2b1e31f..4909e7f45 100644 --- a/packages/compiler/src/frontend/lowering/iterator-adapters.ts +++ b/packages/compiler/src/frontend/lowering/iterator-adapters.ts @@ -1,3 +1,4 @@ +import { appendElement, optionalElementValue, primitiveElement } from "./array-values.js"; import { keyedHelperName } from "./stable-names.js"; import { dynUndefinedExpr, varRef } from "../../ir/build.js"; import { @@ -964,16 +965,27 @@ function generatorRetypeAdapter( return { kind: "call", callee: name, args: [expr], type: expected, loc }; } +/** A checked-dynamic yielded value for a `(T | undefined)[]` of a + * number, string or boolean T: converted to `T | undefined`, which the + * drain stores as a T element or a present undefined. */ +function optionalYield(lowerer: Lowerer, value: IrExpr, elem: IrType, optional: boolean): IrExpr { + if (!optional || value.type.kind !== "dyn" || !primitiveElement(elem)) return value; + return lowerer.coerceToExpected(value, lowerer.withUndefinedArm(elem)); +} + /** Drain a synchronous generator into a fresh `elem[]` — the eager * consumers of an iterator (`[...it]`, `Array.from(it)`). Each step resumes * the generator once and appends its value; completion stops the drain * without appending the return value, as in JS. Null when the yielded - * values cannot be extracted into the element type. */ + * values cannot be extracted into the element type. `optional`: the + * result is a `(T | undefined)[]`, which stores T elements, so a + * checked-dynamic value may also be undefined. */ export function generatorDrain( lowerer: Lowerer, source: IrExpr, elem: IrType, loc: SrcLoc, + optional = false, ): IrExpr | null { const gen = source.type; if (gen.kind !== "generator" || gen.async || gen.yieldT.kind === "void") return null; @@ -982,14 +994,16 @@ export function generatorDrain( const valueT = shape?.fields.find((field) => field.name === "value")?.type; if (!resultType || !valueT) return null; const arrT: IrType = { kind: "array", elem }; - const key = `genDrain:${typeKey(gen)}:${typeKey(elem)}`; + const key = `genDrain:${typeKey(gen)}:${typeKey(elem)}${optional ? "?" : ""}`; let name = lowerer.valueHelpers.get(key); if (!name && stepDrivable(gen)) { // The record-free drive: test done, then take the yielded value. const genRef = varRef("gen.0", gen, loc) as IrExpr & { type: typeof gen }; const outRef = varRef("out.0", arrT, loc); - const value = lowerer.coerceToExpected(genValue(genRef, loc), elem); - if (!typeEquals(value.type, elem)) return null; + const yielded = optionalYield(lowerer, genValue(genRef, loc), elem, optional); + const present = optionalElementValue(lowerer, yielded, elem); + const value = present ? yielded : lowerer.coerceToExpected(yielded, elem); + if (!present && !typeEquals(value.type, elem)) return null; name = keyedHelperName(lowerer, "%gen.drain", key); lowerer.valueHelpers.set(key, name); lowerer.liftedFns.push({ @@ -999,6 +1013,7 @@ export function generatorDrain( locals: [ { id: "gen.0", name: "gen", type: gen, mutable: false }, { id: "out.0", name: "out", type: arrT, mutable: false }, + ...(present ? [{ id: "v.0", name: "v", type: value.type, mutable: false }] : []), ], body: [ { @@ -1010,20 +1025,7 @@ export function generatorDrain( { kind: "while", cond: { kind: "unary", op: "!", operand: genStep(genRef, loc), type: BOOL, loc }, - body: [ - { - kind: "exprStmt", - expr: { - kind: "arrIntrinsic", - method: "push", - receiver: outRef, - args: [value], - type: F64, - loc, - }, - loc, - }, - ], + body: appendElement(lowerer, outRef, value, elem, "v.0", loc), loc, }, { kind: "return", value: outRef, loc }, @@ -1050,8 +1052,10 @@ export function generatorDrain( loc, ); if (!raw) return null; - const value = lowerer.coerceToExpected(raw, elem); - if (!typeEquals(value.type, elem)) return null; + const yielded = optionalYield(lowerer, raw, elem, optional); + const present = optionalElementValue(lowerer, yielded, elem); + const value = present ? yielded : lowerer.coerceToExpected(yielded, elem); + if (!present && !typeEquals(value.type, elem)) return null; name = keyedHelperName(lowerer, "%gen.drain", key); lowerer.valueHelpers.set(key, name); lowerer.liftedFns.push({ @@ -1062,6 +1066,7 @@ export function generatorDrain( { id: "gen.0", name: "gen", type: gen, mutable: false }, { id: "out.0", name: "out", type: arrT, mutable: false }, { id: "step.0", name: "step", type: resultType, mutable: false }, + ...(present ? [{ id: "v.0", name: "v", type: value.type, mutable: false }] : []), ], body: [ { @@ -1101,18 +1106,7 @@ export function generatorDrain( else_: null, loc, }, - { - kind: "exprStmt", - expr: { - kind: "arrIntrinsic", - method: "push", - receiver: outRef, - args: [value], - type: F64, - loc, - }, - loc, - }, + ...appendElement(lowerer, outRef, value, elem, "v.0", loc), ], loc, }, diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index af89c61a4..2ddf02dfc 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -6515,6 +6515,17 @@ export class Lowerer { mayBeUndefined: (node) => { if (explicitlyNonNull(node)) return assertedReadMayBeUndefined(node); if (mayBeOptional(node)) return true; + // A value the checker types as possibly undefined: `(T | undefined)[]` + // stores T elements (the type mapper), so its undefined values are + // facts of T's arrays. + const checked = typeOrNull(node); + if ( + checked !== null && + (checked.isUnionType() ? ts.constituentTypes(checked) : [checked]).some( + (part) => (part.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Void)) !== 0, + ) + ) + return true; // `undefined as unknown as T` keeps the undefined value. for ( let inner: ts.Expression = node; @@ -6533,7 +6544,37 @@ export class Lowerer { const symbol = symbolOf(e); return symbol !== null && iterationSymbols.has(symbol) && !provenPresent(e, symbol); }, - callbackReturnsUndefined: (node) => callbackReturnsOptional(node), + iterationMayYieldUndefined: (node) => { + const type = typeOrNull(node); + if (type === null || this.checker.isArrayType(type) || this.checker.isTupleType(type)) + return false; + // The first type argument of Set, Map and Set iterators, + // generators and iterables is the value they yield. + const element = + (type.flags & ts.TypeFlags.Object) !== 0 + ? panicSafe(() => this.checker.getTypeArguments(type as ts.TypeReference)[0], undefined) + : undefined; + if (element === undefined) return false; + return (element.isUnionType() ? ts.constituentTypes(element) : [element]).some( + (part) => (part.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Void)) !== 0, + ); + }, + callbackReturnsUndefined: (node) => { + if (callbackReturnsOptional(node)) return true; + // A callback the checker types as possibly returning undefined + // (`(m) => map.get(m)`): its results are present undefined + // elements of a `(T | undefined)[]`, which stores T elements. + const type = typeOrNull(node); + return ( + type !== null && + this.checker.getCallSignatures(type).some((signature) => { + const result = this.checker.getReturnTypeOfSignature(signature); + return (result.isUnionType() ? ts.constituentTypes(result) : [result]).some( + (part) => (part.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Void)) !== 0, + ); + }) + ); + }, isGlobal: (node, name) => this.isStdlibGlobal(node, name), isString: (node) => { const type = typeOrNull(node); @@ -6594,6 +6635,7 @@ export class Lowerer { const cached = scanSites.get(sf); if (cached !== undefined) return cached; const nodes: ts.Node[] = []; + const values: ts.Node[] = []; ts.walkPreorder(sf, (node) => { if ( ts.isVariableDeclaration(node) || @@ -6609,7 +6651,21 @@ export class Lowerer { ts.isPostfixUnaryExpression(node) ) nodes.push(node); + // The values these sites store, whose checker types mayBeUndefined + // reads: batched here, since dead bodies are scanned too. + if (ts.isArrayLiteralExpression(node)) + for (const element of node.elements.nodes) + values.push(ts.isSpreadElement(element) ? element.expression : element); + else if (ts.isCallExpression(node) || ts.isNewExpression(node)) + for (const arg of node.arguments?.nodes ?? []) + values.push(ts.isSpreadElement(arg) ? arg.expression : arg); + else if ( + ts.isBinaryExpression(node) && + node.operatorToken.kind === ts.SyntaxKind.EqualsToken + ) + values.push(node.right); }); + this.checker.prefetchCollectionTypes(values); scanSites.set(sf, nodes); return nodes; }; diff --git a/packages/compiler/src/frontend/lowering/runtime-optional-elements.ts b/packages/compiler/src/frontend/lowering/runtime-optional-elements.ts index 96d20d2c4..fffe79a51 100644 --- a/packages/compiler/src/frontend/lowering/runtime-optional-elements.ts +++ b/packages/compiler/src/frontend/lowering/runtime-optional-elements.ts @@ -16,6 +16,9 @@ export interface ElementStateHost { elementAdmitsUndefined(key: string): boolean; /** The value stored by `node` can be `undefined` at runtime. */ mayBeUndefined(node: ts.Expression): boolean; + /** Iterating `node`, an iterable other than an array (a Set, a Map's + * values, a generator), can yield `undefined`. */ + iterationMayYieldUndefined?(node: ts.Expression): boolean; /** A callback argument can return `undefined` at runtime. */ callbackReturnsUndefined(node: ts.Expression): boolean; /** The value may be a plain array-like object, whose missing indices @@ -353,7 +356,11 @@ export class ArrayElementStates { /** One stored value, or the elements a spread copies. */ private valueMayBeUndefined(value: ts.Expression): boolean { - if (ts.isSpreadElement(value)) return this.mayYieldUndefined(value.expression); + if (ts.isSpreadElement(value)) + return ( + this.mayYieldUndefined(value.expression) || + (this.host.iterationMayYieldUndefined?.(value.expression) ?? false) + ); return this.host.mayBeUndefined(value); } diff --git a/packages/compiler/src/frontend/lowering/sanitize-class-types.ts b/packages/compiler/src/frontend/lowering/sanitize-class-types.ts index 77478d76d..6b89b446a 100644 --- a/packages/compiler/src/frontend/lowering/sanitize-class-types.ts +++ b/packages/compiler/src/frontend/lowering/sanitize-class-types.ts @@ -16,6 +16,8 @@ export function sanitizeUnregisteredClassTypes( case "object": return hasClass(type.className) ? type : F64; case "array": + type.elem = rewrite(type.elem); + break; case "set": type.elem = rewrite(type.elem); break; diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 161f73d27..16b77b7f5 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -2341,6 +2341,23 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { elem = unitOnlyUnion(unions); if (!elem) return null; + // `(T | undefined)[]` of a number, string or boolean T stores T + // elements: an array slot holds a present undefined by its own state, + // so a T[] seen as `(T | undefined)[]` stays the same array. + let optionalElements = false; + if (elem.kind === "union") { + const arms = unions.get(elem.unionId)?.arms; + const present = + arms?.length === 2 ? arms.find((arm) => arm.kind !== "undefinedT") : undefined; + if ( + present !== undefined && + arms!.some((arm) => arm.kind === "undefinedT") && + (present.kind === "f64" || present.kind === "string" || present.kind === "bool") + ) { + elem = present; + optionalElements = true; + } + } // A dyn ELEMENT makes the WHOLE array the checked-dynamic value: // `unknown[]`, `object[]`, and the collapsed `(string | object)[]` // (the plugins-slot shape) — the checked-dynamic tree has real arrays, so length/ @@ -2362,7 +2379,7 @@ function mapTypeInner(type: ts.Type, ctx: TypeMapperCtx): IrType | null { // drain of the auxiliary-server registries): handles are ordinary // refcounted REF elements (their `_v` adapters, no trace — both drop // their closures at their terminal event). - return arrayOf(elem); + return optionalElements ? { kind: "array", elem, optionalElements: true } : arrayOf(elem); } // Tuples: `[string, string]` maps to an interned RECORD shape flagged // `tuple`, with one field per position named by its index ("0", "1", ...) diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index 8fb636608..58edd52d3 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -87,7 +87,16 @@ export type IrType = | { kind: "date" } | { kind: "string" } // heap, refcounted, UTF-8 | { kind: "bool" } - | { kind: "array"; elem: IrType } // heap, refcounted, monomorphic elements + | { + kind: "array"; + elem: IrType; + /** A `(T | undefined)[]` of a number, string or boolean T, stored as + * T elements (which hold a present undefined by their state). Not + * part of the type's identity (typeEquals, typeKey): it only lets a + * checked conversion from a dynamic value accept undefined + * elements. */ + optionalElements?: true; + } // heap, refcounted, monomorphic elements /** ES `Map` — heap, refcounted, insertion-ordered hash map with ONE * runtime representation (ScrMap) and type-directed key/value handling, * exactly the array pattern (never per-instantiation structs). Keys use diff --git a/packages/compiler/src/ir/validate.ts b/packages/compiler/src/ir/validate.ts index a694e8d2c..b9996fc6c 100644 --- a/packages/compiler/src/ir/validate.ts +++ b/packages/compiler/src/ir/validate.ts @@ -2050,12 +2050,18 @@ function validateFunction( } case "arrayNewLen": { // Mapper-less Array.from({length: n}): absent-slot fill exists - // only for refcounted element kinds (frontend fences scalars). + // only for refcounted element kinds. Number and boolean slots are + // filled with present undefined values right after + // (`(T | undefined)[]`); the frontend fences other scalar uses. if (e.type.kind !== "array") { err(`arrayNewLen must be array-typed, got ${e.type.kind}`, e.loc); break; } - if (!isRefCounted(e.type.elem)) { + if ( + !isRefCounted(e.type.elem) && + e.type.elem.kind !== "f64" && + e.type.elem.kind !== "bool" + ) { err( `arrayNewLen with non-refcounted ${e.type.elem.kind} elements (no absent value)`, e.loc, diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8000-optional-element-arrays-share-storage.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8000-optional-element-arrays-share-storage.ts.json new file mode 100644 index 000000000..8cdd32baf --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8000-optional-element-arrays-share-storage.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8000-optional-element-arrays-share-storage.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8001-optional-element-writers.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8001-optional-element-writers.ts.json new file mode 100644 index 000000000..fe45249bd --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8001-optional-element-writers.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8001-optional-element-writers.ts" + ], + "diags": [] +} diff --git a/tests/corpus/8000-optional-element-arrays-share-storage.ts b/tests/corpus/8000-optional-element-arrays-share-storage.ts new file mode 100644 index 000000000..fa31fcad2 --- /dev/null +++ b/tests/corpus/8000-optional-element-arrays-share-storage.ts @@ -0,0 +1,61 @@ +// A number[] or string[] seen as `(T | undefined)[]` is the same array, as +// in Node: undefined written through either name is visible through both, +// whether the wider view is a cast, a binding or a parameter. + +const c: number[] = [1.5, 2]; +(c as (number | undefined)[])[1] = undefined; +console.log(c); +const e: number[] = [1.5, 2]; +const f = e as (number | undefined)[]; +f[1] = undefined; +console.log(e, f, e === f); + +function clearFirst(values: (number | undefined)[]): void { + values[0] = undefined; + values.push(undefined, 4); +} +const a: number[] = [1, 2, 3]; +clearFirst(a); +console.log(a, a.length, a.indexOf(4), a.includes(undefined as unknown as number)); + +const names: string[] = ["x"]; +const wider: (string | undefined)[] = names; +wider.push(undefined); +wider.unshift(undefined); +console.log(names, wider === names, names.length, JSON.stringify(names)); + +// The wider arrays themselves: literals, pushes, splices and copies keep +// their undefined elements. +const lit: (number | undefined)[] = [1, undefined, 3]; +const maybe = (i: number): number | undefined => (i % 2 ? i : undefined); +const built: (number | undefined)[] = []; +for (let i = 0; i < 4; i++) built.push(maybe(i)); +built.splice(1, 0, undefined); +console.log(lit, built, lit.indexOf(undefined), built.filter((x): boolean => x === undefined).length); +console.log(built.map((x) => x ?? -1), built.find((x) => x !== undefined), [...built].reverse()); +let sum = 0; +for (const x of built) sum += x ?? 0; +console.log(sum, built.join("-"), JSON.stringify(built)); + +const flags: (boolean | undefined)[] = [true, undefined, false]; +const strs: (string | undefined)[] = ["a", undefined]; +console.log(flags, flags.filter(Boolean).length, strs.map((s) => s?.toUpperCase())); + +// Values from other containers keep their undefined. +const m = new Map([["a", undefined], ["b", 2]]); +const fromMap = [...m.values()]; +const fromSet = Array.from(new Set(["s", undefined])); +const sized = Array.from({ length: 2 }); +console.log(fromMap, fromSet, sized, sized.length); +const dict: { [key: string]: number | undefined } = { a: 1, b: undefined }; +console.log(Object.values(dict)); + +// An asserted element that is undefined throws a catchable TypeError. +function lengthAt(items: (string | undefined)[], i: number): number { + try { + return items[i]!.length; + } catch { + return -1; + } +} +console.log(lengthAt(strs, 0), lengthAt(strs, 1)); diff --git a/tests/corpus/8001-optional-element-writers.ts b/tests/corpus/8001-optional-element-writers.ts new file mode 100644 index 000000000..5dff693c3 --- /dev/null +++ b/tests/corpus/8001-optional-element-writers.ts @@ -0,0 +1,103 @@ +// Every way a value reaches a `(T | undefined)[]` of numbers, strings or +// booleans keeps its undefined: callbacks, generators, Array.of, rest +// packs, destructuring, class fields and copies into Sets and Maps. + +const slots = new Map([["a", 1]]); +const looked = ["x", "a", "y"].map((key) => slots.get(key)); +console.log(looked[0] === undefined, looked, looked.length); +const fromMapped = Array.from(["a", "b"], (key) => slots.get(key)); +console.log(fromMapped[1] === undefined, fromMapped); +const objects: { n?: number }[] = [{ n: 1 }, {}]; +const fields = objects.map((o) => o.n); +function pick(o: { n?: number }): number | undefined { + return o.n; +} +console.log(fields[1] === undefined, objects.map(pick)[1] === undefined, fields); +function wrap(value: T): T[] { + return [value]; +} +console.log(wrap(undefined)[0] === undefined); + +function* maybe(): Generator { + yield undefined; + yield 2; +} +const drained = [...maybe()]; +console.log(drained[0] === undefined, drained, Array.from(maybe())); +const yielding = function* (): Generator { + yield "s"; + yield undefined; +}; +console.log([...yielding()]); +console.log(Array.of(undefined, 1), Array.of(true)); + +function sum(...values: (number | undefined)[]): number { + return values.reduce((total, v) => total + (v ?? 0), 0); +} +const spread: (number | undefined)[] = [undefined, 4]; +console.log(sum(1, undefined, 2), sum(...spread), sum(...spread, undefined, 1)); + +const [first, second = 7, third] = [3, undefined, 1] as (number | undefined)[]; +console.log(first, second, third); +const strings: (string | undefined)[] = ["a", undefined, "a"]; +const seen = new Set(strings); +console.log(seen.size, seen.has(undefined), [...seen]); +for (const [i, s] of strings.entries()) console.log(i, s); +for (const key in strings) console.log("key", key); + +class Holder { + values: (number | undefined)[] = []; + add(value: number | undefined): void { + this.values.push(value); + } + first(): number | undefined { + return this.values[0]; + } +} +const holder = new Holder(); +holder.add(undefined); +holder.add(2); +console.log(holder.first(), holder.values, holder.values.length); + +const xs: (number | undefined)[] = [3, undefined, 1]; +xs.forEach((x, i) => console.log(i, x, typeof x)); +console.log(xs.findIndex((x) => x === undefined), xs.findLast((x) => x !== undefined)); +console.log(xs.some((x) => x === undefined), xs.every((x) => x !== undefined)); +console.log(xs.reduce((acc, x) => acc + (x ?? 10), 0), xs.join("/"), xs.at(1), xs.at(-1)); +console.log(xs.toSorted((a, b) => (a ?? 0) - (b ?? 0)), [...xs].sort()); +xs[1] ??= 5; +console.log(xs); +const flags: (boolean | undefined)[] = [undefined, true]; +console.log(flags.map((b) => !b), flags.indexOf(undefined), flags.includes(true), String(flags)); +const nested: (number | undefined)[][] = [[undefined], [1]]; +console.log(nested.flat(), nested[0]![0]); +const byKey = new Map([["k", [undefined, 1]]]); +console.log(byKey.get("k")![0], byKey); + +// Promise.all over `Promise[]` settles on Node's turn, with +// its undefined values. +const lookup = async (key: string): Promise => { + if (key === "x") throw new Error("missing " + key); + return slots.get(key); +}; +const turns: string[] = []; +const pending: Promise[] = [lookup("a"), lookup("b")]; +void Promise.all(pending).then((vs) => turns.push("all " + vs.join(",") + " " + (vs[1] === undefined))); +const failing: Promise[] = [lookup("a"), lookup("x")]; +Promise.all(failing).then( + () => turns.push("unexpected"), + (error: unknown) => turns.push("rejected " + (error as Error).message), +); +void Promise.all([] as Promise[]).then((vs) => turns.push("empty " + vs.length)); +void Promise.resolve() + .then(() => turns.push("t1")) + .then(() => turns.push("t2")) + .then(() => turns.push("t3")) + .then(() => console.log(turns.join(" "))); + +// Index reads through a union of arrays, and searches with a number +// needle, see the present undefined elements. +const pairs: ((null | undefined)[] | (number | undefined)[])[] = [[null, undefined], [undefined, 0]]; +for (const pair of pairs) console.log(pair[0], pair[1], pair[2]); +const sparse: (number | undefined)[] = [1, , undefined, 1]; +console.log(sparse.lastIndexOf(undefined), sparse.lastIndexOf(1, 2), sparse.indexOf(1, 1)); diff --git a/tests/harness/corpus-costs/8000-optional-element-arrays-share-storage.ts.json b/tests/harness/corpus-costs/8000-optional-element-arrays-share-storage.ts.json new file mode 100644 index 000000000..b3db55643 --- /dev/null +++ b/tests/harness/corpus-costs/8000-optional-element-arrays-share-storage.ts.json @@ -0,0 +1 @@ +{ "plain": 6206, "san": 8487 } diff --git a/tests/harness/corpus-costs/8001-optional-element-writers.ts.json b/tests/harness/corpus-costs/8001-optional-element-writers.ts.json new file mode 100644 index 000000000..31695bc47 --- /dev/null +++ b/tests/harness/corpus-costs/8001-optional-element-writers.ts.json @@ -0,0 +1 @@ +{ "plain": 3690, "san": 4000 } From fd768cd914b37428bb1053880463cde151c2e582 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 00:24:12 -0500 Subject: [PATCH 061/259] Initialize import cycles that re-export a member with export * MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit An `export * from` declaration binds each re-exported name to the binding of the module that declares it, like a named re-export, so it has no initialization state of its own. Import cycles whose modules re-export another member of the cycle this way now compile with the exact cycle initialization: re-exported names read the same values, and throw the same temporal dead zone errors, as in Node. `export * as ns` of a cycle member keeps the SC1016 refusal. pi-coding-agent's sdk.js (sdk.js → agent-session-runtime.js → agent-session-services.js → sdk.js) has this shape. Refs #1777. --- packages/compiler/src/frontend/program.ts | 6 ++++- .../8213-cycle-star-reexport/main.ts.json | 9 +++++++ tests/corpus/8213-cycle-star-reexport/main.ts | 11 ++++++++ .../8213-cycle-star-reexport/runtime.ts | 17 ++++++++++++ tests/corpus/8213-cycle-star-reexport/sdk.ts | 9 +++++++ .../8213-cycle-star-reexport/services.ts | 27 +++++++++++++++++++ .../8213-cycle-star-reexport/main.ts.json | 1 + 7 files changed, 79 insertions(+), 1 deletion(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8213-cycle-star-reexport/main.ts.json create mode 100644 tests/corpus/8213-cycle-star-reexport/main.ts create mode 100644 tests/corpus/8213-cycle-star-reexport/runtime.ts create mode 100644 tests/corpus/8213-cycle-star-reexport/sdk.ts create mode 100644 tests/corpus/8213-cycle-star-reexport/services.ts create mode 100644 tests/harness/corpus-costs/8213-cycle-star-reexport/main.ts.json diff --git a/packages/compiler/src/frontend/program.ts b/packages/compiler/src/frontend/program.ts index 8075379b8..bf75127c4 100644 --- a/packages/compiler/src/frontend/program.ts +++ b/packages/compiler/src/frontend/program.ts @@ -3927,10 +3927,14 @@ function exactCycleRefusal7( if (ts.isExportAssignment(stmt) && !stmt.isExportEquals) { return `the default export expression at ${lineOf(stmt)} has no initialization state inside the cycle`; } + // `export * from` binds each name to the declaring member's own + // binding, like a named re-export, so only `export * as ns` (a + // namespace object of a member) has state of its own. if ( ts.isExportDeclaration(stmt) && !stmt.isTypeOnly && - (stmt.exportClause === undefined || ts.isNamespaceExport(stmt.exportClause)) + stmt.exportClause !== undefined && + ts.isNamespaceExport(stmt.exportClause) ) { const dep = targetOf(stmt); if (dep !== null && members.has(dep)) { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8213-cycle-star-reexport/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8213-cycle-star-reexport/main.ts.json new file mode 100644 index 000000000..c22b59997 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8213-cycle-star-reexport/main.ts.json @@ -0,0 +1,9 @@ +{ + "order": [ + "/tests/corpus/8213-cycle-star-reexport/services.ts", + "/tests/corpus/8213-cycle-star-reexport/runtime.ts", + "/tests/corpus/8213-cycle-star-reexport/sdk.ts", + "/tests/corpus/8213-cycle-star-reexport/main.ts" + ], + "diags": [] +} diff --git a/tests/corpus/8213-cycle-star-reexport/main.ts b/tests/corpus/8213-cycle-star-reexport/main.ts new file mode 100644 index 000000000..04cd7cea1 --- /dev/null +++ b/tests/corpus/8213-cycle-star-reexport/main.ts @@ -0,0 +1,11 @@ +// A module of an import cycle re-exports another member with `export *` +// (pi-coding-agent's sdk.js → agent-session-runtime.js → +// agent-session-services.js → sdk.js). The re-exported names are live +// bindings of the member that declares them, so they read the same values, +// and the same temporal dead zone errors, as in Node. +import { createSession, describeRuntime, Runtime, SDK_VERSION } from "./sdk.ts"; +import { servicesReport } from "./services.ts"; + +console.log(servicesReport()); +console.log(createSession("main").describe()); +console.log(describeRuntime(), new Runtime("direct").name, SDK_VERSION); diff --git a/tests/corpus/8213-cycle-star-reexport/runtime.ts b/tests/corpus/8213-cycle-star-reexport/runtime.ts new file mode 100644 index 000000000..f3653d255 --- /dev/null +++ b/tests/corpus/8213-cycle-star-reexport/runtime.ts @@ -0,0 +1,17 @@ +import { createServices, servicesLabel } from "./services.ts"; + +export class Runtime { + readonly name: string; + constructor(name: string) { + this.name = name; + } + describe(): string { + return `${this.name} runtime with ${servicesLabel}`; + } +} + +export const runtimeLabel = "runtime"; + +export function describeRuntime(): string { + return `${runtimeLabel} (${typeof createServices})`; +} diff --git a/tests/corpus/8213-cycle-star-reexport/sdk.ts b/tests/corpus/8213-cycle-star-reexport/sdk.ts new file mode 100644 index 000000000..7d67384c4 --- /dev/null +++ b/tests/corpus/8213-cycle-star-reexport/sdk.ts @@ -0,0 +1,9 @@ +import { createServices } from "./services.ts"; + +export * from "./runtime.ts"; + +export const SDK_VERSION = "1.4.0"; + +export function createSession(name: string) { + return createServices(name); +} diff --git a/tests/corpus/8213-cycle-star-reexport/services.ts b/tests/corpus/8213-cycle-star-reexport/services.ts new file mode 100644 index 000000000..62e6b684e --- /dev/null +++ b/tests/corpus/8213-cycle-star-reexport/services.ts @@ -0,0 +1,27 @@ +import { Runtime, SDK_VERSION, describeRuntime, runtimeLabel } from "./sdk.ts"; + +export const servicesLabel = "services"; + +function probe(read: () => unknown): string { + try { + return String(read()); + } catch (error) { + return `${(error as Error).name}: ${(error as Error).message}`; + } +} + +// This module runs first: sdk.ts and runtime.ts have not run yet. +const early = [ + probe(() => SDK_VERSION), + probe(() => runtimeLabel), + probe(() => typeof describeRuntime), + probe(() => new Runtime("early").name), +]; + +export function servicesReport(): string { + return `early ${early.join(" | ")}; late ${SDK_VERSION} ${runtimeLabel}`; +} + +export function createServices(name: string): Runtime { + return new Runtime(name); +} diff --git a/tests/harness/corpus-costs/8213-cycle-star-reexport/main.ts.json b/tests/harness/corpus-costs/8213-cycle-star-reexport/main.ts.json new file mode 100644 index 000000000..ef439d096 --- /dev/null +++ b/tests/harness/corpus-costs/8213-cycle-star-reexport/main.ts.json @@ -0,0 +1 @@ +{ "plain": 3000, "san": 4500 } From bfb360a65952bfec75dc2d9d18f61e60794b2d9f Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 00:30:36 -0500 Subject: [PATCH 062/259] Add a runner for Node's test/parallel files tests/node-parallel/run.mjs builds files from a Node.js checkout's test/parallel with scriptc, runs each executable in that directory, and compares its exit status with Node's, writing a pass, fail or refused verdict and the first error line per file (results.json, results.md). --common minimal (the default) runs the files against a minimal test/common (common/index.cjs, common/wpt.cjs) whose helpers keep Node's semantics, so a verdict measures the module under test; --common node uses Node's own test/common. --- tests/node-parallel/README.md | 23 +++++ tests/node-parallel/common/index.cjs | 131 ++++++++++++++++++++++++++ tests/node-parallel/common/wpt.cjs | 32 +++++++ tests/node-parallel/run.mjs | 134 +++++++++++++++++++++++++++ 4 files changed, 320 insertions(+) create mode 100644 tests/node-parallel/README.md create mode 100644 tests/node-parallel/common/index.cjs create mode 100644 tests/node-parallel/common/wpt.cjs create mode 100644 tests/node-parallel/run.mjs diff --git a/tests/node-parallel/README.md b/tests/node-parallel/README.md new file mode 100644 index 000000000..35af64464 --- /dev/null +++ b/tests/node-parallel/README.md @@ -0,0 +1,23 @@ +# Node test/parallel files + +`run.mjs` builds files from a Node.js checkout's `test/parallel` with scriptc, runs each executable in that directory, and compares its exit status with Node's. It records a verdict per file: `pass` (same exit status), `fail` (different exit status), or `refused` (the build failed), with the first error line. + +```bash +git clone --depth 1 --branch v24.22.0 https://github.com/nodejs/node /path/to/node +node tests/node-parallel/run.mjs --node /path/to/node --pattern '^test-(url-|whatwg-url-|querystring)' +``` + +Options: + +- `--node`: a Node.js checkout, or its `test` directory. Use the version in `.node-version`. +- `--pattern`: a regular expression over file names in `test/parallel`. +- `--common`: `minimal` (the default) or `node`. + - `minimal` copies the selected files into `/tree/test/parallel` and uses `common/index.cjs` and `common/wpt.cjs` from this directory as `test/common/index.js` and `test/common/wpt.js`, with the checkout's `test/fixtures` and `test/common/fixtures.js`. The minimal common has the helpers these files use (`mustCall`, `mustNotCall`, `skip`, `expectWarning`, `invalidArgTypeHelper`, `spawnPromisified`, `hasIntl`, `isWindows`, ...) with Node's semantics, so a verdict measures the module under test rather than Node's full `test/common`. + - `node` builds the files in place against Node's own `test/common`. +- `--out`: where executables and results go (default `node_modules/.cache/scriptc-node-parallel`). +- `--cli`: the scriptc CLI entry (default `packages/cli/dist/main.js`). +- `--jobs`: concurrent files (default 4). + +Node runs each file with its `// Flags:` line. Results are written to `/results.json` and `/results.md`. + +Before a lane relies on the minimal common, run its files under Node in `/tree/test/parallel`: they should all pass there. diff --git a/tests/node-parallel/common/index.cjs b/tests/node-parallel/common/index.cjs new file mode 100644 index 000000000..b52bba638 --- /dev/null +++ b/tests/node-parallel/common/index.cjs @@ -0,0 +1,131 @@ +"use strict"; +// A minimal test/common for building Node's test/parallel files with scriptc: +// the helpers those files use, with the semantics of Node's +// test/common/index.js. Add a helper here, with Node's semantics, when a +// lane's files need it. +const assert = require("assert"); +const { inspect } = require("util"); + +const hasIntl = true; +const isDebug = false; +const isWindows = process.platform === "win32"; +const mustCallChecks = []; + +function runCallChecks(exitCode) { + if (exitCode !== 0) return; + const failed = mustCallChecks.filter((context) => { + if ("minimum" in context) return context.actual < context.minimum; + return context.actual !== context.exact; + }); + for (const context of failed) { + console.log( + "Mismatched %s function calls. Expected %s, actual %d.", + context.name, + String(context.exact ?? context.minimum), + context.actual, + ); + } + if (failed.length) process.exit(1); +} + +function noop() {} + +function mustCallInner(fn, criteria, field) { + if (typeof fn === "number") { + criteria = fn; + fn = noop; + } else if (fn === undefined) { + fn = noop; + } + if (criteria === undefined) criteria = 1; + const context = { actual: 0, name: fn.name || "" }; + context[field] = criteria; + if (mustCallChecks.length === 0) process.on("exit", runCallChecks); + mustCallChecks.push(context); + return function (...args) { + context.actual++; + return fn.apply(this, args); + }; +} + +function mustCall(fn, exact) { + return mustCallInner(fn, exact, "exact"); +} + +function mustCallAtLeast(fn, minimum) { + return mustCallInner(fn, minimum, "minimum"); +} + +function mustNotCall(msg) { + return function mustNotCall() { + assert.fail(msg || "function should not have been called"); + }; +} + +function skip(msg) { + console.log(`1..0 # Skipped: ${msg}`); + process.exit(0); +} + +function expectWarning(name, expected, code) { + if (typeof expected === "string") expected = [[expected, code]]; + else if (expected.length !== 0 && !Array.isArray(expected[0])) + expected = [[expected[0], expected[1]]]; + const check = mustCall((warning) => { + const [message, warningCode] = expected.shift(); + assert.strictEqual(warning.name, name); + if (typeof message === "string") assert.strictEqual(warning.message, message); + else assert.match(warning.message, message); + assert.strictEqual(warning.code, warningCode); + }, expected.length); + process.on("warning", (warning) => { + if (warning.name !== name) + throw new TypeError(`"${warning.name}" was triggered without being expected.`); + check(warning); + }); +} + +function invalidArgTypeHelper(input) { + if (input == null) return ` Received ${input}`; + if (typeof input === "function") return ` Received function ${input.name}`; + if (typeof input === "object") { + const name = input.constructor?.name; + if (typeof name === "string" && name !== "") return ` Received an instance of ${name}`; + return ` Received ${inspect(input, { depth: -1 })}`; + } + let inspected = inspect(input, { colors: false }); + if (inspected.length > 28) inspected = `${inspected.slice(inspected, 0, 25)}...`; + return ` Received type ${typeof input} (${inspected})`; +} + +function spawnPromisified(...args) { + const { spawn } = require("child_process"); + let stderr = ""; + let stdout = ""; + const child = spawn(...args); + child.stderr.setEncoding("utf8"); + child.stderr.on("data", (data) => { + stderr += data; + }); + child.stdout.setEncoding("utf8"); + child.stdout.on("data", (data) => { + stdout += data; + }); + return new Promise((resolve, reject) => { + child.on("close", (code, signal) => resolve({ code, signal, stderr, stdout })); + child.on("error", (code, signal) => reject({ code, signal, stderr, stdout })); + }); +} + +module.exports = { + hasIntl, + isDebug, + isWindows, + mustCall, + mustCallAtLeast, + mustNotCall, + skip, + expectWarning, + invalidArgTypeHelper, + spawnPromisified, +}; diff --git a/tests/node-parallel/common/wpt.cjs b/tests/node-parallel/common/wpt.cjs new file mode 100644 index 000000000..eeb7d9770 --- /dev/null +++ b/tests/node-parallel/common/wpt.cjs @@ -0,0 +1,32 @@ +"use strict"; +// The harness object of Node's test/common/wpt.js, without its WPT runner. +const assert = require("assert"); + +const harness = { + test: (fn, desc) => { + try { + fn(); + } catch (err) { + console.error(`In ${desc}:`); + throw err; + } + }, + assert_equals: assert.strictEqual, + assert_true: (value, message) => assert.strictEqual(value, true, message), + assert_false: (value, message) => assert.strictEqual(value, false, message), + assert_throws: (code, func, desc) => { + assert.throws( + func, + function (err) { + return typeof err === "object" && "name" in err && err.name.startsWith(code.name); + }, + desc, + ); + }, + assert_array_equals: assert.deepStrictEqual, + assert_unreached(desc) { + assert.fail(`Reached unreachable code: ${desc}`); + }, +}; + +module.exports = { harness }; diff --git a/tests/node-parallel/run.mjs b/tests/node-parallel/run.mjs new file mode 100644 index 000000000..4f2230c6b --- /dev/null +++ b/tests/node-parallel/run.mjs @@ -0,0 +1,134 @@ +// Builds Node's test/parallel files with scriptc and runs them next to Node. +// See README.md for the options. +import { spawn } from "node:child_process"; +import { + cpSync, + existsSync, + mkdirSync, + readFileSync, + readdirSync, + rmSync, + symlinkSync, + writeFileSync, +} from "node:fs"; +import { dirname, join, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; +import { parseArgs } from "node:util"; + +const here = dirname(fileURLToPath(import.meta.url)); +const repo = resolve(here, "../.."); +const { values } = parseArgs({ + options: { + node: { type: "string" }, + pattern: { type: "string" }, + common: { type: "string", default: "minimal" }, + out: { type: "string", default: join(repo, "node_modules/.cache/scriptc-node-parallel") }, + cli: { type: "string", default: join(repo, "packages/cli/dist/main.js") }, + jobs: { type: "string", default: "4" }, + }, +}); +if (!values.node || !values.pattern || !["minimal", "node"].includes(values.common)) { + console.error( + "usage: node tests/node-parallel/run.mjs --node --pattern [--common minimal|node] [--out ] [--cli ] [--jobs ]", + ); + process.exit(2); +} +const nodeTest = existsSync(join(values.node, "test", "parallel")) + ? join(values.node, "test") + : values.node; +const pattern = new RegExp(values.pattern); +const out = resolve(values.out); +mkdirSync(out, { recursive: true }); + +// The minimal lane copies the selected files into a tree whose test/common is +// this directory's index.cjs and wpt.cjs, next to the checkout's fixtures and +// common/fixtures.js. +let testRoot = nodeTest; +const files = readdirSync(join(nodeTest, "parallel")) + .filter((name) => name.endsWith(".js") && pattern.test(name)) + .sort(); +if (values.common === "minimal") { + testRoot = join(out, "tree", "test"); + rmSync(join(out, "tree"), { recursive: true, force: true }); + mkdirSync(join(testRoot, "parallel"), { recursive: true }); + mkdirSync(join(testRoot, "common"), { recursive: true }); + for (const name of files) + cpSync(join(nodeTest, "parallel", name), join(testRoot, "parallel", name)); + symlinkSync(join(nodeTest, "fixtures"), join(testRoot, "fixtures")); + cpSync(join(nodeTest, "common", "fixtures.js"), join(testRoot, "common", "fixtures.js")); + cpSync(join(here, "common", "index.cjs"), join(testRoot, "common", "index.js")); + cpSync(join(here, "common", "wpt.cjs"), join(testRoot, "common", "wpt.js")); +} + +function run(cmd, args, opts) { + return new Promise((done) => { + const child = spawn(cmd, args, { ...opts, stdio: ["ignore", "pipe", "pipe"] }); + let stdout = ""; + let stderr = ""; + child.stdout.on("data", (d) => (stdout += d)); + child.stderr.on("data", (d) => (stderr += d)); + const timer = setTimeout(() => child.kill("SIGKILL"), opts.timeout); + child.on("close", (code, signal) => { + clearTimeout(timer); + done({ code, signal, stdout, stderr }); + }); + }); +} + +const firstCause = (text) => + ( + text.split("\n").find((line) => /error|Error|assert|SC\d{4}/.test(line)) ?? + text.split("\n")[0] ?? + "" + ) + .replaceAll(testRoot, "test") + .trim() + .slice(0, 300); + +async function one(file) { + const dir = join(testRoot, "parallel"); + const source = readFileSync(join(dir, file), "utf8"); + const flags = (/^\/\/ Flags: (.*)$/m.exec(source)?.[1] ?? "").split(/\s+/).filter(Boolean); + const node = await run(process.execPath, [...flags, file], { cwd: dir, timeout: 120_000 }); + const exe = join(out, "bin", `${file}.exe`); + mkdirSync(join(out, "bin"), { recursive: true }); + const build = await run(process.execPath, [values.cli, "build", file, "-o", exe], { + cwd: dir, + timeout: 900_000, + }); + const result = { file, flags: flags.join(" "), nodeExit: node.code }; + if (build.code !== 0) { + result.verdict = "refused"; + result.cause = firstCause(build.stdout + build.stderr); + return result; + } + const native = await run(exe, [], { cwd: dir, timeout: 120_000 }); + result.exit = native.code ?? native.signal; + result.verdict = native.code === node.code ? "pass" : "fail"; + if (result.verdict !== "pass") result.cause = firstCause(native.stderr + native.stdout); + return result; +} + +const results = []; +const queue = [...files]; +await Promise.all( + Array.from({ length: Number(values.jobs) }, async () => { + for (let file = queue.shift(); file !== undefined; file = queue.shift()) { + const result = await one(file); + results.push(result); + console.log(`${result.verdict.padEnd(8)} ${file}${result.cause ? ` ${result.cause}` : ""}`); + } + }), +); +results.sort((a, b) => (a.file < b.file ? -1 : 1)); +const count = (verdict) => results.filter((r) => r.verdict === verdict).length; +const table = [ + "| file | verdict | first cause |", + "| --- | --- | --- |", + ...results.map((r) => `| ${r.file} | ${r.verdict} | ${(r.cause ?? "").replaceAll("|", "\\|")} |`), + "", + `pass ${count("pass")}, fail ${count("fail")}, refused ${count("refused")} of ${results.length} (test/common: ${values.common})`, +]; +writeFileSync(join(out, "results.json"), `${JSON.stringify(results, null, 2)}\n`); +writeFileSync(join(out, "results.md"), `${table.join("\n")}\n`); +console.log(table.at(-1)); From 67156096959b62ee12bfa54958d2b2d51e68c418 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 00:34:25 -0500 Subject: [PATCH 063/259] Place each source file's functions in the same partitions Partitions were filled by a hash of each function's name, so most calls crossed partitions and the thin link imported their small callees into nearly every partition. The emitter now writes a "; scriptc-group" line before the functions of each source file, and the text partitioner places a group's functions together: a group larger than the mean partition, or than 1 MiB, is divided into a power of two of chunks by name, and chunks go, largest first, to the lighter of two partitions chosen by hash. The 1 MiB bound keeps the code a partition optimizes together, and the inlining within it, from growing when a program has fewer partitions. Modules with fewer than 32 partitions, and functions without a group, keep their name-hash placement: with few partitions per core, the balance of the largest partitions decides the build time more than the imports. The placement still depends only on the module text and the partition count. --- docs/content/docs/how-it-works.mdx | 2 +- native/llvm-codegen/src/partition.cpp | 94 +++++++++++++++++++ native/llvm-codegen/src/partition.h | 14 ++- .../compiler/src/backend/llvm/emit-module.ts | 31 +++++- .../compiler/test/native-partitions.test.ts | 62 ++++++++++-- 5 files changed, 188 insertions(+), 15 deletions(-) diff --git a/docs/content/docs/how-it-works.mdx b/docs/content/docs/how-it-works.mdx index e017267d7..a6520b46e 100644 --- a/docs/content/docs/how-it-works.mdx +++ b/docs/content/docs/how-it-works.mdx @@ -58,7 +58,7 @@ The LLVM helper divides an executable's LLVM IR into partitions by its size. Up -The count depends only on the size of the LLVM text, so a program has the same partitions, and builds the same executable, on every host. A function's partition follows from its name, and a small internal function goes with the one function that calls it, so an edit leaves the other functions in their partitions. +The count depends only on the size of the LLVM text, so a program has the same partitions, and builds the same executable, on every host. In programs with 32 partitions or more, functions from the same source file are placed in the same partition, so that their calls to each other stay inside it; a file larger than 1 MiB of LLVM text or than an average partition is divided into parts by function name. Other functions, and the functions of smaller programs, are placed by their name, and a small internal function goes with the one function that calls it. An edit leaves almost every other function in its partition. These builds are not divided into partitions and compile on one thread: `--emit=asm`, `--emit=obj`, and `--print=native-link-info` output, library builds (`--lib`; `dev` library builds are compiled in pieces, one after another), and `--sanitize` builds, which compile the LLVM IR with the C compiler. diff --git a/native/llvm-codegen/src/partition.cpp b/native/llvm-codegen/src/partition.cpp index f4add0e6d..93b9af4a3 100644 --- a/native/llvm-codegen/src/partition.cpp +++ b/native/llvm-codegen/src/partition.cpp @@ -11,6 +11,7 @@ #include #include +#include using namespace llvm; @@ -36,6 +37,9 @@ struct Symbol { std::string PromotedHeader; std::vector Refs; std::vector Metadata; + // The source-module group the emitter wrote before this definition, or + // empty. + StringRef Group; unsigned Partition = NoPartition; }; @@ -70,6 +74,83 @@ uint32_t stableHash(StringRef Name) { return Hash; } +// Places the functions whose root carries a source-module group by group: a +// module's functions call each other most, so keeping them together leaves +// fewer calls for the thin link to import across partitions. A group larger +// than the mean partition, or than MaxChunkBytes, is divided into a power of +// two of chunks by the hash of each root's name, so the division changes only +// when the group's size doubles. Chunks are placed largest first, each in the +// lighter of two partitions chosen by hashes of its key, after the functions +// placed by name. The placement depends only on the module text and the +// partition count. Modules with fewer than MinGroupedPartitions partitions +// keep the placement by name: with few partitions per core, the balance of +// the largest partitions decides the build time more than the imports. +void placeGroups(std::vector &Symbols, ArrayRef Roots, + unsigned Count) { + constexpr unsigned MinGroupedPartitions = 32; + if (Count < MinGroupedPartitions) + return; + auto Bytes = [](const Symbol &S) -> uint64_t { + return S.Header.size() + S.Body.size(); + }; + std::vector Load(Count, 0); + uint64_t Total = 0; + StringMap GroupBytes; + for (unsigned I = 0; I < Symbols.size(); ++I) { + const Symbol &S = Symbols[I]; + if (S.Kind != SymbolKind::Function) + continue; + Total += Bytes(S); + StringRef Group = Symbols[Roots[I]].Group; + if (Group.empty()) + Load[S.Partition] += Bytes(S); + else + GroupBytes[Group] += Bytes(S); + } + if (GroupBytes.empty()) + return; + // A chunk is at most MaxChunkBytes, so the code a partition optimizes + // together, and the inlining within it, does not grow when a program has + // fewer partitions. + constexpr uint64_t MaxChunkBytes = 1024 * 1024; + uint64_t Chunk = + std::min(MaxChunkBytes, std::max(1, Total / Count)); + std::vector Keys(Symbols.size()); + StringMap KeyBytes; + for (unsigned I = 0; I < Symbols.size(); ++I) { + const Symbol &S = Symbols[I]; + StringRef Group = Symbols[Roots[I]].Group; + if (S.Kind != SymbolKind::Function || Group.empty()) + continue; + uint64_t Chunks = 1; + while (Chunks * Chunk < GroupBytes[Group]) + Chunks *= 2; + Keys[I] = Chunks == 1 + ? Group.str() + : (Group + "#" + + Twine(stableHash(Symbols[Roots[I]].Name) % Chunks)) + .str(); + KeyBytes[Keys[I]] += Bytes(S); + } + std::vector> Order; + for (const auto &Entry : KeyBytes) + Order.push_back({Entry.getKey(), Entry.getValue()}); + llvm::sort(Order, [](const auto &A, const auto &B) { + return A.second != B.second ? A.second > B.second : A.first < B.first; + }); + StringMap Where; + for (const auto &[Key, Size] : Order) { + unsigned First = stableHash(Key) % Count; + unsigned Second = stableHash((Key + "/2").str()) % Count; + unsigned Chosen = Load[Second] < Load[First] ? Second : First; + Load[Chosen] += Size; + Where[Key] = Chosen; + } + for (unsigned I = 0; I < Symbols.size(); ++I) + if (!Keys[I].empty()) + Symbols[I].Partition = Where[Keys[I]]; +} + bool startsWithLinkage(StringRef Rest) { for (StringRef Linkage : {"linkonce", "weak", "common", "appending", "extern_weak", @@ -326,6 +407,11 @@ std::optional partitionProgramText(StringRef Text, return true; }; + // The emitter writes "; scriptc-group " before the definitions of each + // source function; the group applies until the next such line, and an + // empty key ends it. + constexpr StringRef GroupLine = "; scriptc-group"; + StringRef Group; size_t Pos = 0; while (Pos < Text.size()) { size_t End = Text.find('\n', Pos); @@ -335,10 +421,15 @@ std::optional partitionProgramText(StringRef Text, size_t Next = End + 1; if (Line.empty() || Line.trim().empty()) { // Blank separator. + } else if (Line.starts_with(GroupLine) && + (Line.size() == GroupLine.size() || + Line[GroupLine.size()] == ' ')) { + Group = Line.drop_front(GroupLine.size()).trim(); } else if (Line.starts_with("define ")) { Symbol S; S.Kind = SymbolKind::Function; S.Header = Line; + S.Group = Group; if (!parseFunctionHeader(Line, S)) return std::nullopt; // The emitter indents every body line, so the first line that is @@ -466,6 +557,7 @@ std::optional partitionProgramText(StringRef Text, Referrer[Ref] = I; } } + std::vector Roots(Symbols.size()); for (unsigned I = 0; I < Symbols.size(); ++I) { if (Symbols[I].Kind != SymbolKind::Function) continue; @@ -479,8 +571,10 @@ std::optional partitionProgramText(StringRef Text, break; Root = Parent; } + Roots[I] = Root; Symbols[I].Partition = stableHash(Symbols[Root].Name) % Count; } + placeGroups(Symbols, Roots, Count); for (const Symbol &S : Symbols) { if (S.Kind != SymbolKind::Function) continue; diff --git a/native/llvm-codegen/src/partition.h b/native/llvm-codegen/src/partition.h index 838919443..35ef4c543 100644 --- a/native/llvm-codegen/src/partition.h +++ b/native/llvm-codegen/src/partition.h @@ -20,11 +20,15 @@ struct ProgramPartitions { }; // Divides the LLVM assembly scriptc emits into Count modules without parsing -// it, so the partitions can be parsed concurrently. Functions are placed by a -// stable hash of their name; an internal function referenced by exactly one -// other function stays with that function unless its body is too large to -// inline, and a global stays with the first function that references it. Returns nullopt for any construct outside the -// emitter's narrow top-level grammar; callers then split a parsed module. +// it, so the partitions can be parsed concurrently. In modules of 32 or +// more partitions, functions under a "; scriptc-group " line are placed +// with the other functions of that source-module group, which is divided +// into chunks when it is larger than the mean partition or 1 MiB; other +// functions are placed by a stable hash of their name. An internal function referenced by exactly one other function stays +// with that function unless its body is too large to inline, and a global +// stays with the first function that references it. Returns nullopt for any +// construct outside the emitter's narrow top-level grammar; callers then +// split a parsed module. std::optional partitionProgramText(llvm::StringRef Text, unsigned Count); diff --git a/packages/compiler/src/backend/llvm/emit-module.ts b/packages/compiler/src/backend/llvm/emit-module.ts index 5aa18bf9f..7faac3b33 100644 --- a/packages/compiler/src/backend/llvm/emit-module.ts +++ b/packages/compiler/src/backend/llvm/emit-module.ts @@ -65,6 +65,7 @@ import { STRING_READ_HELPERS, stringScanDecl } from "./string-reads.js"; import { emitLibraryIdentityLines } from "../library-identity-markers.js"; import { InternalCompilerError } from "../../errors.js"; import { targetCpuAttribute } from "../target-cpu.js"; +import type { IrFunction } from "../../ir/ir.js"; /** The function bodies emitted in `chunks` contiguous ranges, each by its * own emitter (LlEmitter.chunkEmitter), then merged in function order: the @@ -206,6 +207,26 @@ function functionAttributes(emitter: LlEmitter, hasNoInlineRecordClone: boolean) ]; } +/** The group line written before each function's text. Functions from one + * source file share a group, which the LLVM helper keeps in the same + * partitions so that their calls to each other stay inside a partition + * (native/llvm-codegen/src/partition.h). A group is numbered by the first + * function of its file in the module's function order, which does not depend + * on the host. Functions without a source file get no group. */ +function partitionGroupLines(functions: readonly IrFunction[]): string[] { + const groups = new Map(); + return functions.map((fn) => { + const file = fn.loc.file; + if (file === "") return PARTITION_GROUP_END; + let group = groups.get(file); + if (group === undefined) groups.set(file, (group = groups.size)); + return `${PARTITION_GROUP_END} ${group}`; + }); +} + +/** Ends the group of the definitions that follow. */ +const PARTITION_GROUP_END = "; scriptc-group"; + export function emitModuleParts(emitter: LlEmitter): string[] { // Function bodies first (the literal/unit/fn-value tables fill as they // emit), then the file assembles around them — the runtime ABI’s order. @@ -912,9 +933,13 @@ export function emitModuleParts(emitter: LlEmitter): string[] { for (const line of wrappers) out.push(line); for (const line of asyncDefs) out.push(line); for (const line of emitter.resolveThunkDefs) out.push(line); - out.push(fnDefs[0] ?? ""); - for (let i = 1; i < fnDefs.length; i++) out.push("", fnDefs[i]!); - out.push(""); + const groups = partitionGroupLines(emitter.mod.functions); + for (let i = 0; i < fnDefs.length; i++) { + if (i > 0) out.push(""); + out.push(groups[i] ?? PARTITION_GROUP_END, fnDefs[i]!); + } + if (fnDefs.length === 0) out.push(""); + out.push(PARTITION_GROUP_END, ""); // WebAssembly modules translated into this program, and the registry. for (const line of emitWasmModules(emitter.mod, flushedDecls, emitter.wasmBoundsChecks)) out.push(line); diff --git a/packages/compiler/test/native-partitions.test.ts b/packages/compiler/test/native-partitions.test.ts index ce1f14335..fcd0132e8 100644 --- a/packages/compiler/test/native-partitions.test.ts +++ b/packages/compiler/test/native-partitions.test.ts @@ -29,8 +29,7 @@ afterEach(async () => { /** A program whose internal functions, constants and state must stay * reachable across partitions. `edit` changes one function's addend. */ -function program(edit = 0, extra = ""): string { - const count = 24; +function program(edit = 0, extra = "", count = 24): string { const lines = [ "; partitioned program", "%Pair = type { i64, i64 }", @@ -74,11 +73,12 @@ function program(edit = 0, extra = ""): string { return lines.join("\n") + "\n"; } -function expectedExit(edit = 0): number { - const addends = Array.from({ length: 24 }, (_, index) => (index === 5 ? index + edit : index)); +function expectedExit(edit = 0, count = 24): number { + const addends = Array.from({ length: count }, (_, index) => (index === 5 ? index + edit : index)); let total = 5; // strlen("total") - for (let start = 0; start < 24; start++) - for (let index = start; index < 24; index++) total += (start === 0 ? 4 : 1) * addends[index]!; + for (let start = 0; start < count; start++) + for (let index = start; index < count; index++) + total += (start === 0 ? 4 : 1) * addends[index]!; return total % 251; } @@ -162,6 +162,56 @@ describe.runIf(helper !== null)("LLVM program partitions", () => { }); } + test("functions under one group line share a partition", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-partitions-groups-")); + dirs.push(dir); + // Groups of four steps, each smaller than the mean partition; main ends + // the last group. Placement by group applies from 32 partitions. + const steps = 128; + const grouped = (edit: number, count = steps) => + program(edit, "", count) + .split("\n") + .flatMap((line) => { + const step = /^define internal void @step(\d+)\(/.exec(line); + if (step !== null && Number(step[1]) % 4 === 0) + return [`; scriptc-group ${Number(step[1]) / 4}`, line]; + return line.startsWith("define i32 @main(") ? ["; scriptc-group", line] : [line]; + }) + .join("\n"); + const cache = join(dir, "cache"); + const options = { outputs: 32, optLevel: "0", cache } as const; + const objects = await emit(dir, grouped(0), { ...options, name: "grouped" }); + expect(await exitCode(dir, objects, "grouped")).toBe(expectedExit(0, steps)); + const owner = new Map(); + for (const [index, object] of objects.entries()) { + const { stdout } = await execFileAsync("nm", [object]); + for (const line of stdout.split("\n")) { + const defined = /^[0-9a-fA-F]+ [A-Za-z] _?step(\d+)$/.exec(line.trim()); + if (defined !== null) owner.set(Number(defined[1]), index); + } + } + expect(owner.size).toBe(steps); + // step0's only caller is main, so it goes with main. + for (let group = 0; group < steps / 4; group++) { + const members = [0, 1, 2, 3].map((offset) => group * 4 + offset).filter((step) => step > 0); + expect(new Set(members.map((step) => owner.get(step))).size).toBe(1); + } + + // An edit to one function still changes one partition's source. + const sources = await cacheEntries(cache, ".o"); + const edited = await emit(dir, grouped(7), { ...options, name: "edited" }); + const after = await cacheEntries(cache, ".o"); + expect([...after].filter((entry) => !sources.has(entry))).toHaveLength(1); + expect(await exitCode(dir, edited, "edited")).toBe(expectedExit(7, steps)); + + // With fewer partitions, functions keep their placement by name. + const contents = (paths: string[]) => Promise.all(paths.map((path) => readFile(path))); + const few = { outputs: 4, optLevel: "0" } as const; + expect( + await contents(await emit(dir, grouped(0, 24), { ...few, name: "few-grouped" })), + ).toEqual(await contents(await emit(dir, program(), { ...few, name: "few-plain" }))); + }); + test("a table written one element per line keeps the text partitioner and its reuse", async () => { const dir = await mkdtemp(join(tmpdir(), "scriptc-partitions-table-")); dirs.push(dir); From 68a9dea3fa0f23154c6850b6acc5c5d29ce6cc09 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 00:42:45 -0500 Subject: [PATCH 064/259] Give the capped Linux test workers the heap they had before the cap --- .github/workflows/ci.yml | 7 +++++-- tests/harness/ci-test-plan.test.ts | 4 +++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 26a38482a..2d3ecbf18 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -221,13 +221,16 @@ jobs: # the whole runner did before (a sanitized shard peaks near 16 GB), and # when RAM and swap run out the kernel kills the scope's largest process. # OOMPolicy=continue leaves the rest of the scope running, so vitest - # reports the killed worker and the job log names the test. + # reports the killed worker and the job log names the test. Node sizes + # its default heap from the memory it may use, which the scope lowers + # to about 3.5 GB; the workers keep the 4 GB heap they had on the bare + # runner. - name: Tests (corpus and integration suites) run: | ulimit -c 0 if [ -d /run/systemd/system ]; then exec sudo --preserve-env systemd-run --scope --quiet -p MemoryMax=14G -p OOMPolicy=continue \ - --uid="$(id -u)" --gid="$(id -g)" -- env PATH="$PATH" HOME="$HOME" node scripts/ci-test.mjs + --uid="$(id -u)" --gid="$(id -g)" -- env PATH="$PATH" HOME="$HOME" NODE_OPTIONS="--max-old-space-size=4096" node scripts/ci-test.mjs fi node scripts/ci-test.mjs diff --git a/tests/harness/ci-test-plan.test.ts b/tests/harness/ci-test-plan.test.ts index dd77039ca..6cee99370 100644 --- a/tests/harness/ci-test-plan.test.ts +++ b/tests/harness/ci-test-plan.test.ts @@ -299,7 +299,9 @@ test("pull requests run the full suite on Linux and the darwin suite on macOS", const linuxRun = linux.steps.at(-1)!.run as string; expect(linuxRun.startsWith("ulimit -c 0\n")).toBe(true); expect(linuxRun).toContain("systemd-run --scope --quiet -p MemoryMax=14G -p OOMPolicy=continue"); - expect(linuxRun).toMatch(/-- env PATH="\$PATH" HOME="\$HOME" node scripts\/ci-test\.mjs\n/); + expect(linuxRun).toMatch( + /-- env PATH="\$PATH" HOME="\$HOME" NODE_OPTIONS="--max-old-space-size=4096" node scripts\/ci-test\.mjs\n/, + ); expect(linuxRun.endsWith("fi\nnode scripts/ci-test.mjs\n")).toBe(true); expect(macos.steps.at(-1)!.run).toBe("node scripts/ci-test.mjs"); for (const job of [linux, macos]) expect(job.strategy.matrix.flavor).toEqual(["plain", "san"]); From 2764288376707d2111a0d1f214c854b7ccc64fc6 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 00:43:56 -0500 Subject: [PATCH 065/259] Dispatch untyped calls on plain arrays without the method ladder An untyped call of an array method went through the whole dispatch ladder on every call: the receiver-kind tests for handles, proxies, typed refs, objects, functions and primitives, then the array section's prologue (the hole scan and the frozen, sealed and extensibility tables) before the method itself. A dense array without holes, named properties or a prototype of its own, whose length and elements are writable, now runs push, pop, shift, at, includes and indexOf directly from the call site's cached method id. An argument that could run user code (a non-number index, a fromIndex) still takes the ladder, as does every other receiver. A statement-position push calls an entry that does not box the new length. Calls on arrays that the direct path refuses now also follow Node: - an array's own method, or one on its custom prototype chain (Object.setPrototypeOf), runs instead of the builtin; - push on a sealed or non-extensible array throws "Cannot add property N, object is not extensible", and pop or shift on a sealed array "Cannot delete property 'N' of [object Array]". --- packages/compiler/src/backend/llvm/emitter.ts | 4 + .../compiler/src/backend/llvm/expr-dynamic.ts | 14 ++ .../7984-untyped-array-methods.mjs.json | 6 + .../test/untyped-push-emission.test.ts | 42 ++++++ packages/runtime/src/scr_array.c | 8 ++ packages/runtime/src/scr_array.h | 4 + packages/runtime/src/scr_dyn.h | 7 + packages/runtime/src/scr_dyn_invoke.c | 122 ++++++++++++++++-- packages/runtime/src/scr_json.c | 15 +++ tests/corpus/7984-untyped-array-methods.mjs | 120 +++++++++++++++++ .../7984-untyped-array-methods.mjs.json | 1 + 11 files changed, 335 insertions(+), 8 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7984-untyped-array-methods.mjs.json create mode 100644 packages/compiler/test/untyped-push-emission.test.ts create mode 100644 tests/corpus/7984-untyped-array-methods.mjs create mode 100644 tests/harness/corpus-costs/7984-untyped-array-methods.mjs.json diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index fe50e974f..4a3cb5e53 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -5730,6 +5730,10 @@ export class LlEmitter { }); return; } + if (e.kind === "dynInvoke" && e.calleeNameValue === undefined) { + emitDynamicExpr(this, e, true); + return; + } this.emitExpr(e); } diff --git a/packages/compiler/src/backend/llvm/expr-dynamic.ts b/packages/compiler/src/backend/llvm/expr-dynamic.ts index 26905a7ef..b7a5c7736 100644 --- a/packages/compiler/src/backend/llvm/expr-dynamic.ts +++ b/packages/compiler/src/backend/llvm/expr-dynamic.ts @@ -23,6 +23,7 @@ import { isUnitType, typeEquals, typeKey, + VOID, } from "../../ir/ir.js"; import { BYTES_ELEM_NUM, closureIdentityEqual } from "./common.js"; import { DYN_KIND } from "./dyn.js"; @@ -57,6 +58,7 @@ export function emitDynamicExpr( | "caughtNarrow" | "caughtToDyn" >, + discarded = false, ): LlValue { const B = host.B; switch (e.kind) { @@ -257,6 +259,18 @@ export function emitDynamicExpr( // Each call passes its method name's id slot, so only the first call // looks the name up. const invoke = DYN_BUFFER_METHODS.get(e.method) ?? "scr_dyn_invoke_prepared_id"; + // A statement-position push drops the new length, so its entry + // need not box it. + if (discarded && e.method === "push" && invoke === "scr_dyn_invoke_prepared_id") { + host.declare( + `declare void @scr_dyn_invoke_discard_id(ptr, ptr, ptr, ptr, ptr, ${host.sizeType}, ptr)`, + ); + B.line( + `call void @scr_dyn_invoke_discard_id(ptr ${recv.name}, ptr ${prepared}, ptr ${host.cstr(e.method)}, ptr ${host.methodIdSlot(e.method)}, ptr ${argsPtr}, ${host.sizeType} ${args.length}, ptr ${host.cstr(e.calleeName)})`, + ); + host.emitPendingCheck(); + return { name: "", type: VOID }; + } host.declare(`declare ptr @${invoke}(ptr, ptr, ptr, ptr, ptr, ${host.sizeType}, ptr)`); let name = host.cstr(e.calleeName); if (e.calleeNameValue !== undefined) { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7984-untyped-array-methods.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7984-untyped-array-methods.mjs.json new file mode 100644 index 000000000..2c823a24f --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7984-untyped-array-methods.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7984-untyped-array-methods.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/untyped-push-emission.test.ts b/packages/compiler/test/untyped-push-emission.test.ts new file mode 100644 index 000000000..2abdf7f41 --- /dev/null +++ b/packages/compiler/test/untyped-push-emission.test.ts @@ -0,0 +1,42 @@ +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile, deserializeModule, validateModule } from "../src/index.js"; +import { emitLlvmModule } from "../src/backend/llvm/emitter.js"; + +// An untyped push in statement position drops the new length, so it calls +// the entry that does not box it; a push whose result is read keeps the +// ordinary entry, as do the other methods. +test("a statement-position untyped push skips boxing its result", async () => { + const dir = mkdtempSync(join(tmpdir(), "scriptc-untyped-push-")); + try { + const entry = join(dir, "main.mjs"); + const output = join(dir, "main.ir.json"); + writeFileSync( + entry, + `function fill(a, n) { + for (let i = 0; i < n; i++) a.push(i); + const length = a.push(n); + a.pop(); + return length; +} +console.log(fill(JSON.parse("[]"), 3)); +`, + ); + const lowered = await compile(entry, { outputKind: "ir", outDir: dir, outPath: output }); + if (!lowered.ok) throw new Error(JSON.stringify(lowered.diagnostics)); + const module = deserializeModule(readFileSync(output, "utf8")); + expect(validateModule(module)).toEqual([]); + const llvm = emitLlvmModule(module, {}); + const body = llvm.split(/\n(?=define )/).find((fn) => /@sc_[a-z]*f_fill\b/.test(fn))!; + const discarded = [...body.matchAll(/call void @scr_dyn_invoke_discard_id\(/g)]; + const kept = [...body.matchAll(/= call ptr @scr_dyn_invoke_prepared_id\(/g)]; + expect(discarded).toHaveLength(1); + // `a.push(n)` for its length, and `a.pop()`, whose result is dropped + // but which has no unboxed entry. + expect(kept).toHaveLength(2); + } finally { + rmSync(dir, { recursive: true, force: true }); + } +}); diff --git a/packages/runtime/src/scr_array.c b/packages/runtime/src/scr_array.c index 4c7b84d98..39998b8ff 100644 --- a/packages/runtime/src/scr_array.c +++ b/packages/runtime/src/scr_array.c @@ -1724,6 +1724,14 @@ static void scr_frozen_undeletable(double index) { scr_frozen_throw("Cannot delete property '", index, "' of [object Array]"); } +void scr_array_not_extensible_error(double index) { + scr_frozen_not_extensible(index); +} + +void scr_array_undeletable_error(double index) { + scr_frozen_undeletable(index); +} + /* Each case finds the operation's first write in the order the spec makes * its writes. */ bool scr_array_frozen_error(int op, size_t len, double x, double y, double z) { diff --git a/packages/runtime/src/scr_array.h b/packages/runtime/src/scr_array.h index 23390a183..48fa4f26f 100644 --- a/packages/runtime/src/scr_array.h +++ b/packages/runtime/src/scr_array.h @@ -231,6 +231,10 @@ bool scr_arr_is_frozen(const ScrArr *a); * end), 9 copyWithin (x = target, y = start, z = end), 10 splice (x = * start, y = delete count, z = item count). */ bool scr_array_frozen_error(int op, size_t len, double x, double y, double z); +/* Node's TypeErrors for a write that a non-extensible or sealed array + * refuses: adding the element at `index`, or deleting it. */ +void scr_array_not_extensible_error(double index); +void scr_array_undeletable_error(double index); /* The start of the dense slots' allocation: `data` less any head room. */ static inline uint64_t *scr_arr_block(const ScrArr *a) { diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index 257aa6444..7e91c37cf 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -1181,6 +1181,10 @@ void scr_weak_dispose(void *object); double scr_dyn_arr_len(const ScrDyn *d); ScrDyn *scr_dyn_arr_at(const ScrDyn *d, double i); ScrDyn *scr_dyn_arr_named_get(const ScrDyn *d, const ScrStr *key); +/* The member `key` of an array found before Array.prototype: an own named + * property, or one on its custom prototype chain (Object.setPrototypeOf). + * NULL when the chain reaches Array.prototype without it. +1. */ +ScrDyn *scr_dyn_arr_custom_member(const ScrDyn *d, const char *key, size_t key_len); void scr_dyn_obj_set(ScrDyn *obj, const char *key, size_t key_len, ScrDyn *value); void scr_dyn_obj_set_field(ScrDyn *obj, const char *key, size_t key_len, ScrDyn *value); ScrDyn *scr_dyn_define_property(ScrDyn *target, ScrDyn *key, ScrDyn *descriptor); @@ -1383,6 +1387,9 @@ ScrDyn *scr_dyn_invoke_prepared(ScrDyn *recv, ScrDyn *callee, const char *method * *mid_slot, the site's -1-initialized slot, caches the name's method id * after the first call, so later calls skip the name lookup. */ ScrDyn *scr_dyn_invoke_prepared_id(ScrDyn *recv, ScrDyn *callee, const char *method, int32_t *mid_slot, ScrDyn *const *args, size_t argc, const char *what); +/* scr_dyn_invoke_prepared_id for a call whose result is discarded: a plain + * array's push appends without boxing its new length. */ +void scr_dyn_invoke_discard_id(ScrDyn *recv, ScrDyn *callee, const char *method, int32_t *mid_slot, ScrDyn *const *args, size_t argc, const char *what); /* scr_dyn_invoke_prepared_id for Buffer.prototype method names * (scr_bytes_dyn.c), one entry per method family: a Buffer receiver runs * the method, any other takes the ordinary dispatch. */ diff --git a/packages/runtime/src/scr_dyn_invoke.c b/packages/runtime/src/scr_dyn_invoke.c index 1dd5711a0..5589c9978 100644 --- a/packages/runtime/src/scr_dyn_invoke.c +++ b/packages/runtime/src/scr_dyn_invoke.c @@ -771,6 +771,8 @@ ScrDyn *scr_dyn_prepare_method(ScrDyn *recv, const char *method) { return scr_dyn_invoke(recv, method, NULL, 0, method); if (recv->kind == SCR_DYN_OBJ) return scr_dyn_obj_read(recv, method, strlen(method)); + if (recv->kind == SCR_DYN_ARR && (recv->v.arr.properties || recv->prototype)) + return scr_dyn_arr_custom_member(recv, method, strlen(method)); if (recv->kind == SCR_DYN_PROXY) { ScrStr *key = scr_str_new(method, strlen(method)); ScrDyn *result = scr_dyn_proxy_get(recv, key); @@ -795,20 +797,117 @@ ScrDyn *scr_dyn_invoke(ScrDyn *recv, const char *method, return scr_dyn_invoke_impl(recv, method, dyn_method_of(method), args, argc, what, NULL); } -ScrDyn *scr_dyn_invoke_prepared_id(ScrDyn *recv, ScrDyn *callee, const char *method, - int32_t *mid_slot, ScrDyn *const *args, size_t argc, - const char *what) { - if (callee) return scr_dyn_invoke_prepared(recv, callee, method, args, argc, what); - /* The slot is the call site's, shared by every thread: each writes the - * same id. */ +/* A dense array without holes, named properties or a prototype of its + * own, whose length and elements are writable: its common methods below + * run without the dispatch ladder, which answers every other receiver and + * method as before. */ +static bool dyn_arr_plain(const ScrDyn *recv) { + return recv->kind == SCR_DYN_ARR && !recv->v.arr.presence && !recv->v.arr.properties && + !recv->prototype && !recv->null_proto && !recv->non_extensible && + !recv->v.arr.sealed && !recv->v.arr.frozen && !scr_dyn_is_array_prototype(recv); +} + +/* scr_dyn_strict_eq, with the number and string cases inline: an element + * search compares every element. */ +static inline bool dyn_elem_strict_eq(const ScrDyn *a, const ScrDyn *b) { + if (a->kind == SCR_DYN_STR && b->kind == SCR_DYN_STR) { + const ScrStr *x = a->v.str, *y = b->v.str; + return x == y || (x->len == y->len && memcmp(x->data, y->data, x->len) == 0); + } + if (a->kind == SCR_DYN_NUM && b->kind == SCR_DYN_NUM) return a->v.num == b->v.num; + return scr_dyn_strict_eq(a, b); +} + +/* push, pop, shift, at, includes and indexOf of a plain array, with the + * ladder's results. An argument that would run user code (a non-number + * index, a fromIndex) leaves the call to the ladder. True when answered. */ +static bool dyn_arr_fast(ScrDyn *recv, int mid, ScrDyn *const *args, size_t argc, + ScrDyn **result) { + size_t len = recv->v.arr.len; + switch (mid) { + case DYN_M_push: + for (size_t i = 0; i < argc; i++) scr_dyn_arr_push(recv, scr_dyn_retain(args[i])); + *result = scr_dyn_new_num((double)recv->v.arr.len); + return true; + case DYN_M_pop: + if (len == 0) { + *result = scr_dyn_retain(scr_dyn_undefined()); + return true; + } + recv->v.arr.len = len - 1; + *result = recv->v.arr.items[len - 1]; /* ownership moves out */ + return true; + case DYN_M_shift: + if (len == 0) { + *result = scr_dyn_retain(scr_dyn_undefined()); + return true; + } + *result = recv->v.arr.items[0]; /* ownership moves out */ + memmove(recv->v.arr.items, recv->v.arr.items + 1, (len - 1) * sizeof(ScrDyn *)); + recv->v.arr.len = len - 1; + return true; + case DYN_M_at: { + if (argc == 0 || args[0]->kind != SCR_DYN_NUM) return false; + double index = args[0]->v.num; + index = isnan(index) ? 0 : trunc(index); + if (index < 0) index += (double)len; + *result = index < 0 || index >= (double)len ? scr_dyn_retain(scr_dyn_undefined()) + : scr_dyn_retain(recv->v.arr.items[(size_t)index]); + return true; + } + case DYN_M_includes: + case DYN_M_indexOf: { + if (argc > 1) return false; + ScrDyn *needle = argc > 0 ? args[0] : scr_dyn_undefined(); + bool nan = mid == DYN_M_includes && needle->kind == SCR_DYN_NUM && needle->v.num != needle->v.num; + for (size_t i = 0; i < len; i++) { + const ScrDyn *item = recv->v.arr.items[i]; + if (nan ? item->kind == SCR_DYN_NUM && item->v.num != item->v.num + : dyn_elem_strict_eq(item, needle)) { + *result = mid == DYN_M_includes ? scr_dyn_new_bool(true) : scr_dyn_new_num((double)i); + return true; + } + } + *result = mid == DYN_M_includes ? scr_dyn_new_bool(false) : scr_dyn_new_num(-1); + return true; + } + default: + return false; + } +} + +/* The call site's method id. The slot is the site's, shared by every + * thread: each writes the same id. */ +static int32_t dyn_site_method(const char *method, int32_t *mid_slot) { int32_t mid = __atomic_load_n(mid_slot, __ATOMIC_RELAXED); if (mid < 0) { mid = dyn_method_of(method); __atomic_store_n(mid_slot, mid, __ATOMIC_RELAXED); } + return mid; +} + +ScrDyn *scr_dyn_invoke_prepared_id(ScrDyn *recv, ScrDyn *callee, const char *method, + int32_t *mid_slot, ScrDyn *const *args, size_t argc, + const char *what) { + if (callee) return scr_dyn_invoke_prepared(recv, callee, method, args, argc, what); + int32_t mid = dyn_site_method(method, mid_slot); + ScrDyn *result; + if (dyn_arr_plain(recv) && dyn_arr_fast(recv, mid, args, argc, &result)) return result; return scr_dyn_invoke_impl(recv, method, mid, args, argc, what, NULL); } +void scr_dyn_invoke_discard_id(ScrDyn *recv, ScrDyn *callee, const char *method, + int32_t *mid_slot, ScrDyn *const *args, size_t argc, + const char *what) { + /* A plain array's push whose new length nobody reads. */ + if (!callee && dyn_arr_plain(recv) && dyn_site_method(method, mid_slot) == DYN_M_push) { + for (size_t i = 0; i < argc; i++) scr_dyn_arr_push(recv, scr_dyn_retain(args[i])); + return; + } + scr_dyn_release(scr_dyn_invoke_prepared_id(recv, callee, method, mid_slot, args, argc, what)); +} + static ScrDyn *scr_dyn_invoke_impl( ScrDyn *recv, const char *method, int mid, ScrDyn *const *args, size_t argc, const char *what, ScrDyn *callback_recv) { @@ -1121,6 +1220,14 @@ static ScrDyn *scr_dyn_invoke_impl( if (frozen_op >= 0 && scr_array_frozen_error(frozen_op, len, (double)splice_start, frozen_op == 10 ? (double)splice_removed : items, items)) return NULL; + if ((mid == DYN_M_push) && grows && recv->non_extensible) { + scr_array_not_extensible_error((double)len); + return NULL; + } + if ((mid == DYN_M_pop) && shrinks && recv->v.arr.sealed) { + scr_array_undeletable_error((double)(len - 1)); + return NULL; + } if ((grows && recv->non_extensible) || (shrinks && recv->v.arr.sealed && !(mid == DYN_M_shift))) { static const char message[] = "Cannot modify a sealed or frozen array"; scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); @@ -1150,8 +1257,7 @@ static ScrDyn *scr_dyn_invoke_impl( scr_dyn_release(recv->v.arr.items[i - 1]); recv->v.arr.items[i - 1] = scr_dyn_retain(recv->v.arr.items[i]); } - static const char message[] = "Cannot delete non-configurable property"; - scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); + scr_array_undeletable_error((double)(len - 1)); return NULL; } ScrDyn *first = recv->v.arr.items[0]; diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 74fd53159..6ba182114 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -1704,6 +1704,21 @@ ScrDyn *scr_dyn_arr_at(const ScrDyn *d, double i) { return result; } +ScrDyn *scr_dyn_arr_custom_member(const ScrDyn *d, const char *key, size_t key_len) { + if (d->v.arr.properties && scr_dyn_obj_get(d->v.arr.properties, key, key_len)) + return scr_dyn_obj_read_receiver(d->v.arr.properties, key, key_len, d); + for (const ScrDyn *link = d->prototype; link && link != scr_builtin_array_prototype; + link = link->prototype) { + const ScrDyn *table = link->kind == SCR_DYN_OBJ ? link + : link->kind == SCR_DYN_ARR ? link->v.arr.properties + : NULL; + if (table && scr_dyn_obj_get(table, key, key_len)) + return scr_dyn_obj_read_receiver(table, key, key_len, d); + if (link->kind != SCR_DYN_OBJ && link->kind != SCR_DYN_ARR) break; + } + return NULL; +} + ScrDyn *scr_dyn_arr_named_get(const ScrDyn *d, const ScrStr *key) { if (d->v.arr.properties && scr_dyn_obj_get(d->v.arr.properties, key->data, key->len)) return scr_dyn_obj_read_receiver(d->v.arr.properties, key->data, key->len, d); diff --git a/tests/corpus/7984-untyped-array-methods.mjs b/tests/corpus/7984-untyped-array-methods.mjs new file mode 100644 index 000000000..a68ec305e --- /dev/null +++ b/tests/corpus/7984-untyped-array-methods.mjs @@ -0,0 +1,120 @@ +// Untyped calls of push, pop, shift, at, includes and indexOf: plain arrays +// take a direct path; arrays with holes, frozen, sealed or non-extensible +// arrays, Array.prototype, proxies, and arrays whose own property or +// prototype defines the method take the full dispatch. Each call is made +// both for its result and as a statement, whose result is dropped. +function attempt(label, f) { + try { + console.log(label, f()); + } catch (e) { + console.log(label, "threw", e.constructor.name, e.message); + } +} +function push(a, v) { + return a.push(v); +} +function pushOnly(a, v) { + a.push(v); + return a.length; +} +function push2(a, v, w) { + return a.push(v, w); +} +function pop(a) { + return a.pop(); +} +function shift(a) { + return a.shift(); +} +function at(a, i) { + return a.at(i); +} +function includes(a, v) { + return a.includes(v); +} +function indexOf(a, v) { + return a.indexOf(v); +} +function indexFrom(a, v, from) { + return a.indexOf(v, from); +} +function len(a) { + return a.length; +} + +const holes = JSON.parse("[1, 2, 3]"); +delete holes[1]; +attempt("holes push", () => push(holes, 4)); +attempt("holes push statement", () => pushOnly(holes, 5)); +attempt("holes includes", () => [includes(holes, undefined), indexOf(holes, undefined), at(holes, 1)]); +attempt("holes pop", () => [pop(holes), len(holes)]); +attempt("holes shift", () => [shift(holes), len(holes), 1 in holes]); + +const frozen = Object.freeze(JSON.parse("[1, 2]")); +attempt("frozen push", () => push(frozen, 3)); +attempt("frozen push statement", () => pushOnly(frozen, 3)); +attempt("frozen pop", () => pop(frozen)); +attempt("frozen shift", () => shift(frozen)); +attempt("frozen includes", () => [includes(frozen, 2), indexOf(frozen, 2), at(frozen, -1)]); + +const sealed = Object.seal(JSON.parse("[1, 2]")); +attempt("sealed push", () => push(sealed, 3)); +attempt("sealed push statement", () => pushOnly(sealed, 3)); +attempt("sealed pop", () => pop(sealed)); +attempt("sealed shift", () => [shift(sealed), JSON.stringify(sealed)]); +attempt("sealed includes", () => [includes(sealed, 2), at(sealed, 0)]); + +const fixed = Object.preventExtensions(JSON.parse("[1, 2]")); +attempt("fixed push", () => push(fixed, 3)); +attempt("fixed push statement", () => pushOnly(fixed, 3)); +attempt("fixed pop", () => [pop(fixed), len(fixed)]); +attempt("fixed shift", () => [shift(fixed), len(fixed)]); + +attempt("prototype includes", () => [includes(Array.prototype, 1), indexOf(Array.prototype, 1), at(Array.prototype, 0)]); + +const handler = new Proxy({ push(v) { return "proxied push " + v; }, at(i) { return "proxied at " + i; } }, {}); +attempt("proxy push", () => push(handler, 7)); +attempt("proxy push statement", () => pushOnly(handler, 7)); +attempt("proxy at", () => at(handler, 1)); + +const own = JSON.parse("[1, 2]"); +own.push = function (v) { + return "own push " + v; +}; +own.includes = function (v) { + return "own includes " + v; +}; +attempt("own push", () => [push(own, 9), len(own)]); +attempt("own push statement", () => pushOnly(own, 9)); +attempt("own includes", () => [includes(own, 1), indexOf(own, 1)]); +const notCallable = JSON.parse("[1, 2]"); +notCallable.pop = 5; +attempt("own non-callable pop", () => pop(notCallable)); + +const customProto = Object.create(Array.prototype); +customProto.push = function (v) { + return "proto push " + v + " onto " + this.length; +}; +const reproto = JSON.parse("[1, 2]"); +Object.setPrototypeOf(reproto, customProto); +attempt("reproto push", () => push(reproto, 9)); +attempt("reproto push statement", () => pushOnly(reproto, 9)); +attempt("reproto pop", () => [pop(reproto), len(reproto)]); + +const plain = JSON.parse("[]"); +for (let i = 0; i < 5; i++) push2(plain, i, i * 2); +for (let i = 0; i < 3; i++) pushOnly(plain, "s" + i); +attempt("plain", () => [len(plain), pop(plain), shift(plain), at(plain, -2), at(plain, 1.9), at(plain, -0), at(plain, NaN), at(plain, 100), at(plain, -100)]); +attempt("plain search", () => [includes(plain, 8), indexOf(plain, 8), includes(plain, "s1"), indexOf(plain, "s1"), indexOf(plain, "s9"), indexFrom(plain, 2, 3), includes(plain)]); +attempt("plain at string", () => [at(plain, "1"), at(plain, undefined), at(plain, { valueOf() { return 2; } })]); +const nans = JSON.parse("[1]"); +pushOnly(nans, NaN); +pushOnly(nans, -0); +attempt("nan", () => [includes(nans, NaN), indexOf(nans, NaN), includes(nans, 0), indexOf(nans, 0), indexOf(nans, -0)]); +const empty = JSON.parse("[]"); +attempt("empty", () => [pop(empty), shift(empty), at(empty, 0), includes(empty, undefined), indexOf(empty, undefined), len(empty)]); +const objects = JSON.parse("[]"); +const key = { k: 1 }; +pushOnly(objects, key); +pushOnly(objects, { k: 1 }); +attempt("objects", () => [includes(objects, key), indexOf(objects, key), indexOf(objects, { k: 1 }), at(objects, 0) === key]); diff --git a/tests/harness/corpus-costs/7984-untyped-array-methods.mjs.json b/tests/harness/corpus-costs/7984-untyped-array-methods.mjs.json new file mode 100644 index 000000000..5ae927c90 --- /dev/null +++ b/tests/harness/corpus-costs/7984-untyped-array-methods.mjs.json @@ -0,0 +1 @@ +{ "plain": 4100, "san": 4500 } From f713cd631c2cbcf36d46932b2b367b8abfbe2557 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 00:52:48 -0500 Subject: [PATCH 066/259] Run the int32 slot analysis once per module the emitter emits Release emission selects int32 arrays by analyzing each module selectInt32Arrays marks (provenInt32Arrays) until every candidate it marks is kept, then constructed LlEmitter on the returned module, whose constructor built a node index, found the initializer bindings and the dynamic field stores, and ran analyzeInt32Slots on that same module again. On tsc-ts the constructor's call alone took about 3 s. Each round now analyzes its module with the inputs the constructor gives the analysis (one node index, the initializer bindings and the dynamic field stores read through it), and the emitter of the module selectInt32Arrays returns takes over the last round's analysis and inputs instead of computing them again. The rounds also read the node index instead of walking the bodies. The emitted LLVM is unchanged. --- packages/compiler/src/backend/llvm/emitter.ts | 72 +++++++++++++------ 1 file changed, 50 insertions(+), 22 deletions(-) diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index fe50e974f..1135107d3 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -97,7 +97,12 @@ import { unshareNodes } from "../../ir/unshare.js"; import { runPairedWhileLoopsAsFor } from "../../ir/paired-while-loops.js"; import { copyStableCaptures } from "../../ir/capture-values.js"; import { resolveSelfCaptures } from "../../ir/self-captures.js"; -import { analyzeInt32Slots, dynamicFieldStores, type Int32Slots } from "../../ir/int32-slots.js"; +import { + analyzeInt32Slots, + dynamicFieldStores, + type DynamicFieldStores, + type Int32Slots, +} from "../../ir/int32-slots.js"; import { analyzeFinalFields, type FinalFields } from "../../ir/final-fields.js"; import { foldConstantGlobals } from "../../ir/constant-globals.js"; import { dropUnwrittenPropertyBags } from "../../ir/property-bags.js"; @@ -506,14 +511,24 @@ function versionParameters(mod: IrModule): IrModule { return versionLoopBoundParameters(mod, mangleFunction); } -/** The int32 arrays the int32 slot analysis keeps in `mod` (proven and - * checked), under the inputs LlEmitter gives it (selectInt32Arrays). */ -function provenInt32Arrays(mod: IrModule): ReadonlySet { - const slots = analyzeInt32Slots(mod, { - dynamicStores: dynamicFieldStores(mod), - initializerBindings: findInitializerBindings(mod), - }); - return new Set([...slots.int32Arrays, ...slots.checkedInt32Arrays]); +/** The int32 slot analysis of one module and the inputs it read: the + * constructor's own analyses of that module, which LlEmitter takes over + * instead of repeating them when it emits the same module. */ +export interface Int32SlotAnalysis { + readonly mod: IrModule; + readonly nodeIndex: IrNodeIndex; + readonly initializerBindings: ReturnType; + readonly dynamicStores: DynamicFieldStores; + readonly slots: Int32Slots; +} + +/** The int32 slot analysis of `mod`, with the inputs LlEmitter gives it. */ +function analyzeModuleInt32Slots(mod: IrModule): Int32SlotAnalysis { + const nodeIndex = new IrNodeIndex(mod); + const initializerBindings = findInitializerBindings(mod, nodeIndex); + const dynamicStores = dynamicFieldStores(mod, undefined, undefined, nodeIndex); + const slots = analyzeInt32Slots(mod, { dynamicStores, initializerBindings, nodes: nodeIndex }); + return { mod, nodeIndex, initializerBindings, dynamicStores, slots }; } /** The functions whose calls the backend may emit as calls of their @@ -530,8 +545,16 @@ function moduleEmitter(input: IrModule, options: LlvmTargetOptions): LlEmitter { // Facts are keyed by node identity: emit the same module whether it was // lowered in memory or read back from its serialized form. const mod = unshareNodes(input); + // Each round of selectInt32Arrays analyzes the module it marks; the + // emitter of the module it returns reuses that round's analysis. + const rounds: { last: Int32SlotAnalysis | null } = { last: null }; + const proven = (marked: IrModule): ReadonlySet => { + const analysis = analyzeModuleInt32Slots(marked); + rounds.last = analysis; + return new Set([...analysis.slots.int32Arrays, ...analysis.slots.checkedInt32Arrays]); + }; // Keep source storage intact for debugger inspection in dev builds. - return new LlEmitter( + const emitted = options.debugSources === undefined ? selectInt32Arrays( versionParameters( @@ -559,12 +582,12 @@ function moduleEmitter(input: IrModule, options: LlvmTargetOptions): LlEmitter { ), ), ), - provenInt32Arrays, + proven, resultEntryTargets, ) - : mod, - options, - ); + : mod; + const prepared = rounds.last; + return new LlEmitter(emitted, options, null, prepared?.mod === emitted ? prepared : null); } export function emitLlvmModule(input: IrModule, options: LlvmTargetOptions = {}): string { @@ -1562,6 +1585,7 @@ export class LlEmitter { readonly mod: IrModule, options: LlvmTargetOptions, journal: EmitJournal | null = null, + int32Analysis: Int32SlotAnalysis | null = null, ) { this.targetOptions = options; this.journal = journal; @@ -1572,7 +1596,7 @@ export class LlEmitter { options.debugSources === undefined); // One walk of every body, which the analyses below read instead of // walking the bodies themselves. - this.nodeIndex = new IrNodeIndex(mod); + this.nodeIndex = int32Analysis?.nodeIndex ?? new IrNodeIndex(mod); this.stackTraces = observesStacks(mod, this.nodeIndex); this.nullableUnions = new NullableUnions( mod, @@ -1591,14 +1615,18 @@ export class LlEmitter { this.nullableUnions.armTypes(), ); this.constantNumericTables = findConstantNumericTables(mod); - this.initializerBindings = findInitializerBindings(mod, this.nodeIndex); + this.initializerBindings = + int32Analysis?.initializerBindings ?? findInitializerBindings(mod, this.nodeIndex); // One walk finds the dynamic field stores every analysis below consults. - const dynamicStores = dynamicFieldStores(mod, undefined, undefined, this.nodeIndex); - this.int32Slots = analyzeInt32Slots(mod, { - dynamicStores, - initializerBindings: this.initializerBindings, - nodes: this.nodeIndex, - }); + const dynamicStores = + int32Analysis?.dynamicStores ?? dynamicFieldStores(mod, undefined, undefined, this.nodeIndex); + this.int32Slots = + int32Analysis?.slots ?? + analyzeInt32Slots(mod, { + dynamicStores, + initializerBindings: this.initializerBindings, + nodes: this.nodeIndex, + }); this.liveViewsReadOnly = mod.lib === undefined && !dynamicStores.all && dynamicStores.names.size === 0; this.int32Abis = this.debug === null ? findInt32Abis(mod, this.int32Slots) : new Map(); From 70c2b8246d244d5274056c2fc851f8938f5b7c1d Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 01:03:18 -0500 Subject: [PATCH 067/259] Share untyped module bindings that combine with strings and numbers A JavaScript module binding whose initializer joins an untyped value with a string, number or boolean through `||`, `&&`, `??` or `?:` (`export const APP_NAME = pkg.appConfig?.name || "app"`) stayed a local of the module's initializer, so reads from other modules and functions failed with "a binding form with no lowering". Such initializers now register the binding in checked-dynamic module storage, like the untyped initializers they combine. pi-coding-agent's config.js declares APP_NAME, APP_TITLE and isBundledNode this way. Refs #1777. --- .../src/frontend/lowering/lower-modules.ts | 17 ++++++++++------- .../main.ts.json | 6 ++++++ .../main.ts | 8 ++++++++ .../node_modules/app-config/dist/config.js | 18 ++++++++++++++++++ .../node_modules/app-config/dist/index.d.ts | 2 ++ .../node_modules/app-config/dist/index.js | 1 + .../node_modules/app-config/dist/usage.js | 12 ++++++++++++ .../node_modules/app-config/package.json | 1 + .../main.ts.json | 1 + 9 files changed, 59 insertions(+), 7 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8215-js-any-logical-module-bindings/main.ts.json create mode 100644 tests/corpus/8215-js-any-logical-module-bindings/main.ts create mode 100644 tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/dist/config.js create mode 100644 tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/dist/index.d.ts create mode 100644 tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/dist/index.js create mode 100644 tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/dist/usage.js create mode 100644 tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/package.json create mode 100644 tests/harness/corpus-costs/8215-js-any-logical-module-bindings/main.ts.json diff --git a/packages/compiler/src/frontend/lowering/lower-modules.ts b/packages/compiler/src/frontend/lowering/lower-modules.ts index 75f18fe37..19f7243ed 100644 --- a/packages/compiler/src/frontend/lowering/lower-modules.ts +++ b/packages/compiler/src/frontend/lowering/lower-modules.ts @@ -1183,19 +1183,22 @@ function jsDynHoldableInitializer(lowerer: Lowerer, init: ts.Expression | undefi } if (e.kind === ts.SyntaxKind.NullKeyword) return true; if (ts.isIdentifier(e) && e.text === "undefined") return true; - if (ts.isConditionalExpression(e)) { - return ( - jsDynHoldableInitializer(lowerer, e.whenTrue) && - jsDynHoldableInitializer(lowerer, e.whenFalse) - ); - } + // The arms of a conditional or logical expression: checked values, or + // strings, numbers and booleans, which box into the checked-dynamic + // result (`const APP_NAME = config.name || "pi"`). + const arm = (x: ts.Expression): boolean => { + if (jsDynHoldableInitializer(lowerer, x)) return true; + const kind = lowerer.mapTypeOf(lowerer.typeOf(x))?.kind; + return kind === "string" || kind === "f64" || kind === "bool"; + }; + if (ts.isConditionalExpression(e)) return arm(e.whenTrue) && arm(e.whenFalse); if ( ts.isBinaryExpression(e) && (e.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken || e.operatorToken.kind === ts.SyntaxKind.BarBarToken || e.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) ) { - return jsDynHoldableInitializer(lowerer, e.left) && jsDynHoldableInitializer(lowerer, e.right); + return arm(e.left) && arm(e.right); } // A member of a checked module value is itself checked, including a // callable whose inferred overloads cannot describe one native ABI. diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8215-js-any-logical-module-bindings/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8215-js-any-logical-module-bindings/main.ts.json new file mode 100644 index 000000000..0ae9f6f2b --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8215-js-any-logical-module-bindings/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8215-js-any-logical-module-bindings/main.ts" + ], + "diags": [] +} diff --git a/tests/corpus/8215-js-any-logical-module-bindings/main.ts b/tests/corpus/8215-js-any-logical-module-bindings/main.ts new file mode 100644 index 000000000..3a1d5eb17 --- /dev/null +++ b/tests/corpus/8215-js-any-logical-module-bindings/main.ts @@ -0,0 +1,8 @@ +// Module bindings of a JavaScript package whose initializers combine an +// untyped value with a string, number or boolean through `||`, `&&`, `??` +// or `?:` (pi-coding-agent's config.js): other modules and functions read +// the values as in Node. +import { banner, usage } from "app-config"; + +console.log(banner); +console.log(usage("check")); diff --git a/tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/dist/config.js b/tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/dist/config.js new file mode 100644 index 000000000..faecb8b2b --- /dev/null +++ b/tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/dist/config.js @@ -0,0 +1,18 @@ +import { readFileSync } from "node:fs"; +import { join } from "node:path"; + +let pkg = {}; +try { + pkg = JSON.parse(readFileSync(join(import.meta.dirname, "..", "package.json"), "utf-8")); +} +catch (e) { + if (e.code !== "ENOENT") + throw e; +} +const configName = pkg.appConfig?.name; +export const APP_NAME = configName || "app"; +export const APP_TITLE = configName ? APP_NAME : "App"; +export const CONFIG_DIR = pkg.appConfig?.configDir || ".config"; +export const VERSION = pkg.version ?? "0.0.0"; +export const RETRIES = pkg.appConfig?.retries ?? 3; +export const isBundled = typeof APP_BUNDLED !== "undefined" && APP_BUNDLED; diff --git a/tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/dist/index.d.ts b/tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/dist/index.d.ts new file mode 100644 index 000000000..4c4706926 --- /dev/null +++ b/tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/dist/index.d.ts @@ -0,0 +1,2 @@ +export declare const banner: string; +export declare function usage(kind: "check" | "list"): string; diff --git a/tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/dist/index.js b/tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/dist/index.js new file mode 100644 index 000000000..251303802 --- /dev/null +++ b/tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/dist/index.js @@ -0,0 +1 @@ +export { banner, usage } from "./usage.js"; diff --git a/tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/dist/usage.js b/tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/dist/usage.js new file mode 100644 index 000000000..736cef3c0 --- /dev/null +++ b/tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/dist/usage.js @@ -0,0 +1,12 @@ +import { APP_NAME, APP_TITLE, CONFIG_DIR, RETRIES, VERSION, isBundled } from "./config.js"; + +const USAGE = { + check: `${APP_NAME} check --dir ${CONFIG_DIR}`, + list: `${APP_NAME} list`, +}; + +export const banner = `${APP_TITLE} ${VERSION} (bundled: ${isBundled}, retries: ${RETRIES})`; + +export function usage(kind) { + return `${USAGE[kind]} [${APP_NAME.toUpperCase()}_HOME=${CONFIG_DIR}] ${typeof isBundled} ${RETRIES + 1}`; +} diff --git a/tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/package.json b/tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/package.json new file mode 100644 index 000000000..918204988 --- /dev/null +++ b/tests/corpus/8215-js-any-logical-module-bindings/node_modules/app-config/package.json @@ -0,0 +1 @@ +{ "name": "app-config", "version": "2.1.0", "type": "module", "main": "dist/index.js", "types": "dist/index.d.ts", "appConfig": { "configDir": ".app" } } diff --git a/tests/harness/corpus-costs/8215-js-any-logical-module-bindings/main.ts.json b/tests/harness/corpus-costs/8215-js-any-logical-module-bindings/main.ts.json new file mode 100644 index 000000000..d5d1c5f65 --- /dev/null +++ b/tests/harness/corpus-costs/8215-js-any-logical-module-bindings/main.ts.json @@ -0,0 +1 @@ +{ "plain": 2500, "san": 3500 } From 20339d9c277e1ffaf3be83bee35da5308fc4186b Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 01:13:00 -0500 Subject: [PATCH 068/259] Process non-ASCII URL hosts with UTS #46 as Node does --- docs/content/limitations/builtin-apis/url.mdx | 3 +- .../compiler/src/backend/llvm/emit-module.ts | 4 ++ .../compiler/src/backend/vendor-archives.ts | 14 ++++- packages/compiler/src/ir/runtime-features.ts | 18 ++++-- .../tests/corpus/8105-url-idna-hosts.js.json | 6 ++ .../runtime-pack-common/scripts/build.mjs | 4 ++ packages/runtime/src/scr_idna.c | 11 ++-- packages/runtime/src/scr_url.c | 45 +++++++++----- packages/runtime/src/scr_url.h | 4 ++ tests/corpus/8105-url-idna-hosts.js | 58 +++++++++++++++++++ 10 files changed, 142 insertions(+), 25 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8105-url-idna-hosts.js.json create mode 100644 tests/corpus/8105-url-idna-hosts.js diff --git a/docs/content/limitations/builtin-apis/url.mdx b/docs/content/limitations/builtin-apis/url.mdx index c9eee85b3..dddf2a8f7 100644 --- a/docs/content/limitations/builtin-apis/url.mdx +++ b/docs/content/limitations/builtin-apis/url.mdx @@ -1,5 +1,4 @@ -- **URL:** Hosts of special URLs that hold non-ASCII text, or percent-escapes that decode to it, throw `ERR_INVALID_URL`, and `xn--` labels are kept without Punycode validation. - Absolute inputs and relative inputs with runtime string or URL bases, including optional bases, compile. +- **URL:** Absolute inputs and relative inputs with runtime string or URL bases, including optional bases, compile. `URL.canParse`, `URL.parse`, `toString()`, and `toJSON()` compile; the factories use the same parser as construction, returning `false` or `null` for rejected inputs while preserving conversion errors. `href`, `protocol`, `username`, `password`, `host`, `hostname`, `port`, `pathname`, `search`, and `hash` support assignment in native code. Invalid component writes are ignored except for invalid `href` values, which throw; credentials are percent-encoded and ports accept valid leading digits. diff --git a/packages/compiler/src/backend/llvm/emit-module.ts b/packages/compiler/src/backend/llvm/emit-module.ts index 5aa18bf9f..7f4ac73b6 100644 --- a/packages/compiler/src/backend/llvm/emit-module.ts +++ b/packages/compiler/src/backend/llvm/emit-module.ts @@ -344,6 +344,8 @@ export function emitModuleParts(emitter: LlEmitter): string[] { // Fetch-referencing programs register native fetch before main. // Runtime selection compiles scr_fetch.c on the same predicate. const usesFetch = runtimeFeatures.fetch; + // URL programs give the host parser the IDNA unit's ToASCII. + const usesUrlIdna = runtimeFeatures.urlIdna; const snapshotsTlsCa = runtimeFeatures.tls || runtimeFeatures.tlsCa; // The process verdict has the same precedence as the C reference // emitter: node:test owns the final status when present; otherwise an @@ -396,6 +398,7 @@ export function emitModuleParts(emitter: LlEmitter): string[] { if (usesHttp2) emitter.declare(`declare void @scr_http2_dyn_install()`); if (usesHttp) emitter.declare(`declare void @scr_http_dyn_install()`); if (usesFetch) emitter.declare(`declare void @scr_fetch_install()`); + if (usesUrlIdna) emitter.declare(`declare void @scr_url_idna_install()`); if (usesNodeTest) { emitter.declare(`declare i32 @scr_test_exit_code()`); @@ -1027,6 +1030,7 @@ export function emitModuleParts(emitter: LlEmitter): string[] { ...(emitter.ffiHasForeignCallback ? [` call void @scr_ffi_install()`] : []), ...(snapshotsTlsCa ? [` call void @scr_tls_ca_install()`] : []), ...(usesFetch ? [` call void @scr_fetch_install()`] : []), + ...(usesUrlIdna ? [` call void @scr_url_idna_install()`] : []), ...(usesNet ? [` call void @scr_net_install()`, ` call void @scr_net_dyn_install()`] : []), ...(usesNetLookup ? [` call void @scr_net_lookup_install()`] : []), ...(usesHttp ? [` call void @scr_http_dyn_install()`] : []), diff --git a/packages/compiler/src/backend/vendor-archives.ts b/packages/compiler/src/backend/vendor-archives.ts index dbcaf2d36..ef63aa4e4 100644 --- a/packages/compiler/src/backend/vendor-archives.ts +++ b/packages/compiler/src/backend/vendor-archives.ts @@ -14,6 +14,10 @@ import type { CcDriver } from "./native/driver.js"; const execFileAsync = promisify(execFile); +/** The section flags the libregexp/libunicode objects build with (the + * runtime pack's executable_section_elimination flags). */ +const LRE_SECTION_FLAGS = ["-ffunction-sections", "-fdata-sections"]; + import { QJS_COMMIT, MBEDTLS_VERSION, @@ -191,13 +195,13 @@ export function createVendorArchives(context: VendorArchiveContext) { (sanitize ? "asan" : "plain") + (driver.argv.length === 1 && driver.argv[0] === "clang" ? "" : "-zigcc") + `-${vendorCacheTargetFlavor(driver)}-${buildIdentity}`; - const cacheDir = join(cacheRoot, `${QJS_COMMIT.slice(0, 12)}-lre-${flavor}`); + const cacheDir = join(cacheRoot, `${QJS_COMMIT.slice(0, 12)}-lre-sections-${flavor}`); return LRE_SOURCES.map((f) => join(cacheDir, f.replace(/\.c$/, ".o"))); } /** The libregexp objects for one flavor, compiled lazily on the first * regex-using build (~1s) and cached under - * /vendor/-lre---/*.o — with the same atomic-rename + * /vendor/-lre-sections---/*.o — with the same atomic-rename * publish (parallel first builds race safely; losers discard their work). * Plain is -Os to keep regex-using binaries small; asan matches the final link so * the sanitized lane instruments the matcher too. Cross targets get their @@ -228,6 +232,10 @@ export function createVendorArchives(context: VendorArchiveContext) { vendor: vendorEngineDir(), sources: LRE_SOURCES, objects: lreObjectPaths(sanitize, driver, buildIdentity, cacheRoot), + // Section elimination keeps only the libunicode tables a program + // reaches: the URL host parser's NFC links the normalization tables + // without the regex property ones. + flags: LRE_SECTION_FLAGS, }); } @@ -296,6 +304,7 @@ export function createVendorArchives(context: VendorArchiveContext) { vendor: string; sources: readonly string[]; objects: string[]; + flags?: readonly string[]; }): Promise { const { sanitize, driver, cacheRoot, flavor, name, vendor, sources, objects } = options; if ((await Promise.all(objects.map(validVendorArtifact))).every(Boolean)) return objects; @@ -312,6 +321,7 @@ export function createVendorArchives(context: VendorArchiveContext) { "-std=c11", ...driver.targetArgs, ...(sanitize ? ["-O1", "-fsanitize=address"] : ["-Os"]), + ...(options.flags ?? []), "-I", vendor, "-c", diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 118f0ef38..85b21af7b 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -715,6 +715,10 @@ interface RuntimeFeatureRule { /** Gives every rule in the table one type. */ const rule = (r: RuntimeFeatureRule): RuntimeFeatureRule => r; +/* The node:url and WHATWG URL entry points: every URL value comes from + * one, and parsing one can reach the UTS #46 host processing. */ +const URL_PREFIXES: readonly string[] = ["url."]; + /* The HTTP, HTTPS, HTTP/2 and TLS surfaces, which link the net unit. */ const NET_PREFIXES: readonly string[] = ["net.", "http.", "tls.", "https.", "http2."]; @@ -1063,9 +1067,10 @@ const RUNTIME_FEATURE_RULES = { /** scr_url_legacy.c parses and stringifies queries. */ qs: rule({ fns: [...QS_LIB_FNS, ...LEGACY_URL_LIB_FNS] }), /** scr_url_legacy.c lowercases and normalizes hostnames with the regex - * unit's libunicode, NODE_DEBUG matching in scr_util_callable.c and - * readline's terminal unit use the regex unit, and locale case mapping - * runs its default conversion. */ + * unit's libunicode, the WHATWG URL host parser runs UTS #46 through + * scr_idna.c (which links with the regex unit), NODE_DEBUG matching in + * scr_util_callable.c and readline's terminal unit use the regex unit, + * and locale case mapping runs its default conversion. */ regex: rule({ fns: [ ...REGEX_LIB_FNS, @@ -1074,13 +1079,17 @@ const RUNTIME_FEATURE_RULES = { "rl.terminal", "str.localeCase", ], + prefixes: URL_PREFIXES, expr: (node, _tables) => node.kind === "regexLit" || node.kind === "regexIntrinsic" || (node.kind === "strIntrinsic" && CASE_MAPPING_STR_METHODS.has(node.method)), - types: ["regex"], + types: ["regex", "url"], }), searchParams: rule({ fns: ["url.searchParams"], prefixes: ["sp."], types: ["searchParams"] }), + /** URL programs install the IDNA unit's ToASCII for the WHATWG host + * parser (scr_url_idna_install). */ + urlIdna: rule({ prefixes: URL_PREFIXES, types: ["url"] }), /** stdin setEncoding / string data listeners / stdio 'resize' events. A * typed string 'data' listener takes setEncoding-decoded chunks; the * process stream object's setEncoding and 'resize' members are reached @@ -1177,6 +1186,7 @@ function noRuntimeFeatures(): RuntimeFeatures { qs: false, regex: false, searchParams: false, + urlIdna: false, stdioExtended: false, stream: false, streamDyn: false, diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8105-url-idna-hosts.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8105-url-idna-hosts.js.json new file mode 100644 index 000000000..50ed1b401 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8105-url-idna-hosts.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8105-url-idna-hosts.js" + ], + "diags": [] +} diff --git a/packages/runtime-pack-common/scripts/build.mjs b/packages/runtime-pack-common/scripts/build.mjs index d4794b7d1..479d8aad4 100644 --- a/packages/runtime-pack-common/scripts/build.mjs +++ b/packages/runtime-pack-common/scripts/build.mjs @@ -386,6 +386,10 @@ async function build() { ? [ await archive("libregexp", lreSources, quickjs, [ ...vendorTarget, + // Section elimination keeps only the libunicode tables a + // program reaches: the URL host parser's NFC links the + // normalization tables without the regex property ones. + ...matrix.executable_section_elimination.compile_flags, "-std=c11", "-Os", "-I", diff --git a/packages/runtime/src/scr_idna.c b/packages/runtime/src/scr_idna.c index 34c9e3882..7507e5caa 100644 --- a/packages/runtime/src/scr_idna.c +++ b/packages/runtime/src/scr_idna.c @@ -1,8 +1,8 @@ /* UTS #46 domain processing for node:url — the conversions Node applies to - * url.parse() hostnames (ToASCII), url.domainToASCII()/domainToUnicode() - * and url.format()'s unicode option: nontransitional mapping, NFC, label - * validity (leading combining marks, ContextJ, and the RFC 5893 bidi rule), - * and Punycode. It matches Node 24's implementation, including its + * WHATWG URL hosts and url.parse() hostnames (ToASCII), + * url.domainToASCII()/domainToUnicode() and url.format()'s unicode option: + * nontransitional mapping, NFC, label validity (leading combining marks, + * ContextJ, and the RFC 5893 bidi rule), and Punycode. It matches Node 24's implementation, including its * validity-data snapshot and the shortcuts its label checks take; the * differential corpus and test/url-legacy-cases.txt (generated from Node) * are the oracle. @@ -511,3 +511,6 @@ ScrStr *scr_idna_to_unicode(const char *p, size_t n) { } return scr_jb_finish(&out); } + +/* The URL host parser's UTS #46 ToASCII (scr_url.c). */ +void scr_url_idna_install(void) { scr_url_host_to_ascii = &scr_idna_to_ascii; } diff --git a/packages/runtime/src/scr_url.c b/packages/runtime/src/scr_url.c index 09ccb87fe..a61286c63 100644 --- a/packages/runtime/src/scr_url.c +++ b/packages/runtime/src/scr_url.c @@ -21,10 +21,8 @@ * case preserved, C0-encoded), a single "/" roots a normalized path, * anything else is an OPAQUE path with the C0 control set encoded * (data:text/plain,hi there) - * - * DOCUMENTED DIVERGENCE: a special host that holds non-ASCII text after - * percent-decoding is rejected with "Invalid URL" (no UTS #46 processing), - * and "xn--" labels are kept without Punycode validation. + * - UTS #46 processing of non-ASCII hosts through the IDNA unit + * (scr_url_idna_install) * * Failures THROW catchable TypeErrors through the exception cell with * Node's messages; callers are compiler-emitted pending checks. */ @@ -430,16 +428,21 @@ static int hex_val(char c) { return -1; } +/* UTS #46 ToASCII (scr_idna.c), which programs that use URLs install at + * startup (scr_url_idna_install). NULL refuses hosts that hold non-ASCII + * text. */ +ScrStr *(*scr_url_host_to_ascii)(const char *p, size_t n) = NULL; + /* The URL Standard's host parser for the constructor and the setters, * with canonical IPv6 serialization: * - a non-special (opaque) host refuses forbidden host code points and * percent-encodes the C0 control set; - * - a special host is percent-decoded, lowercased, refused when it holds a - * forbidden domain code point, and serialized as dotted decimal when it - * ends in a number (or refused when that number is invalid). - * Divergence: a special host that decodes to non-ASCII needs UTS #46 - * processing, which this unit does not link, so it is refused; "xn--" - * labels are kept without Punycode validation. */ + * - a special host is percent-decoded and lowercased; when that leaves + * non-ASCII text it goes through UTS #46 ToASCII (as Node's host parser + * does, an ASCII host, "xn--" labels included, is only lowercased). The + * result is refused when it holds a forbidden domain code point, and + * serialized as dotted decimal when it ends in a number (or refused when + * that number is invalid). */ static bool parse_host(const char *hp, size_t host_len, bool special, bool is_file, ScrStr **host) { bool ipv6 = host_len > 0 && hp[0] == '['; @@ -467,6 +470,7 @@ static bool parse_host(const char *hp, size_t host_len, bool special, bool is_fi *host = ub_take(&hb); return true; } + bool non_ascii = false; for (size_t i = 0; i < host_len; i++) { unsigned char c = (unsigned char)hp[i]; int hi, lo; @@ -475,12 +479,27 @@ static bool parse_host(const char *hp, size_t host_len, bool special, bool is_fi c = (unsigned char)(hi * 16 + lo); i += 2; } - if (url_host_byte_class[c] & URL_FORBIDDEN_DOMAIN) { + if (c >= 0x80) non_ascii = true; + if (c >= 'A' && c <= 'Z') c = (unsigned char)(c - 'A' + 'a'); + ub_push(&hb, (char)c); + } + if (non_ascii) { + /* UTS #46 ToASCII, or refused without the IDNA unit. */ + ScrStr *ascii = scr_url_host_to_ascii ? scr_url_host_to_ascii(hb.data, hb.len) : NULL; + free(hb.data); + if (!ascii || ascii->len == 0) { + scr_str_release(ascii); + return false; + } + ub_init(&hb); + ub_append(&hb, ascii->data, ascii->len); + scr_str_release(ascii); + } + for (size_t i = 0; i < hb.len; i++) { + if (url_host_byte_class[(unsigned char)hb.data[i]] & URL_FORBIDDEN_DOMAIN) { free(hb.data); return false; } - if (c >= 'A' && c <= 'Z') c = (unsigned char)(c - 'A' + 'a'); - ub_push(&hb, (char)c); } if (url_ends_in_number(hb.data, hb.len)) { UrlBuf ip; diff --git a/packages/runtime/src/scr_url.h b/packages/runtime/src/scr_url.h index c7c9c63c8..13a7d093b 100644 --- a/packages/runtime/src/scr_url.h +++ b/packages/runtime/src/scr_url.h @@ -46,6 +46,10 @@ void scr_url_set_checked(ScrUrl *u, ScrStr *field, const ScrDyn *value); /* borr * null and has no lowering for an object that is not a URL. Borrowed; +1, * or NULL with the error pending. */ ScrDyn *scr_url_to_http_options(ScrUrl *u); +/* UTS #46 ToASCII for the host parser: NULL until scr_url_idna_install + * (scr_idna.c, emitted at startup by programs that use URLs) sets it. */ +extern ScrStr *(*scr_url_host_to_ascii)(const char *p, size_t n); +void scr_url_idna_install(void); ScrDyn *scr_url_to_http_options_dyn(const ScrDyn *value); /* node:url's legacy surface (scr_url_legacy.c — linked with the regex, * querystring and dyn-async units). url.parse() answers a checked-dynamic diff --git a/tests/corpus/8105-url-idna-hosts.js b/tests/corpus/8105-url-idna-hosts.js new file mode 100644 index 000000000..329566013 --- /dev/null +++ b/tests/corpus/8105-url-idna-hosts.js @@ -0,0 +1,58 @@ +// WHATWG URL hosts that hold non-ASCII text, directly or after +// percent-decoding, go through UTS #46 ToASCII as the host parser in Node +// does: mapped and normalized labels become Punycode, and disallowed code +// points, invalid joiners and bidi violations make the URL invalid. Cases +// from the WPT url test data, plus setters, pathToFileURL UNC hosts and +// URL.canParse. +import url from "node:url"; + +const parses = [ + ["http://é@é", null], + ["http://GOO\u200B\u2060\uFEFFgoo.com", "http://other.com/"], + ["http://www.foo。bar.com", "http://other.com/"], + ["http://Go.com", "http://other.com/"], + ["http://你好你好", "http://other.com/"], + ["https://faß.ExAmPlE/", null], + ["http://0Xc0.0250.01", "http://other.com/"], + ["ftp://%e2%98%83", null], + ["https://%e2%98%83", null], + ["file://a\u00ADb/p", null], + ["file://a%C2%ADb/p", null], + ["file://loC𝐀𝐋𝐇𝐨𝐬𝐭/usr/bin", null], + ["https://a%C2%ADb/", null], + ["http://münchen.de/straße", null], + ["https://日本語.jp/", null], + ["http://例え.テスト/", null], + ["http://xn--mnchen-3ya.de/", null], + ["http://a\u200Db.com/", null], + ["http://אa.com/", null], + ["http://ab�c/", null], + ["ws://ÉXAMPLE.org:8080/x", null], +]; +function describe(value) { + return [value.href, value.host, value.hostname, value.origin].join(" | "); +} +for (const [input, base] of parses) { + let line; + try { + line = describe(base === null ? new URL(input) : new URL(input, base)); + } catch (e) { + line = `throws ${e.code}`; + } + console.log(JSON.stringify(input), "=>", line, URL.canParse(input, base ?? undefined)); +} +const writes = [ + ["host", "https://x/", "ß"], + ["host", "https://example.com/", "a%C2%ADb"], + ["hostname", "https://example.com/", "a%C2%ADb"], + ["hostname", "https://example.com/", "BÜCHER.example"], +]; +for (const [name, href, value] of writes) { + const target = new URL(href); + if (name === "host") target.host = value; + else target.hostname = value; + console.log(name, JSON.stringify(value), "=>", describe(target)); +} +for (const path of ["\\\\münchen\\share\\f", "\\\\BÜCHER\\s\\f"]) { + console.log(JSON.stringify(path), url.pathToFileURL(path, { windows: true }).href); +} From d99fc851e66ffc3eadb95b30b226dbdcce5745c0 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 01:22:42 -0500 Subject: [PATCH 069/259] Type untyped JavaScript Maps, Sets and arrays from their uses In a JavaScript file, `const m = new Map()`, `new Set()` and `[]` type as Map, Set and any[], so every use lowered to the checked-dynamic collection operations: boxed keys and values, generic method dispatch, and dynamic arithmetic on what they returned. js-collection-types.ts proves types for such bindings from their uses. A `const` qualifies when every reference is a direct use of the collection: - for a Map: get/has/delete/clear, size, and set as a statement; - for a Set: has/delete/clear, size, and add as a statement; - for an array: push/pop/shift/at/includes/indexOf/join and length. The value then never leaves the binding. Its key, value or element type is the one primitive (string, number or boolean) of every expression the program writes. That is found by a fixed point that types `m.get(k) ?? d`, arithmetic, comparisons and constants defined from them, and it requires lookups of the same type. Any other reference (passing, returning, storing, exporting, iterating, inspecting, an optional call), a direct `eval` in the file, or any doubt keeps the binding untyped. A proven binding answers the lowerer's typeOf with a carrier type declared in scriptc-overrides.d.ts, which only the lowering program includes. `new Map()` and `new Set()` adopt it, so the binding lowers as the typed Map, Set or T[], as a JSDoc @type would make it. 7985 covers the typed cases and every refusal. --- .../compiler/ambient/scriptc-overrides.d.ts | 21 + .../frontend/lowering/js-collection-types.ts | 519 ++++++++++++++++++ .../src/frontend/lowering/lower-classes.ts | 10 +- .../compiler/src/frontend/lowering/lowerer.ts | 8 + .../compiler/test/js-collection-types.test.ts | 62 +++ .../7985-untyped-collection-types.mjs.json | 6 + .../corpus/7985-untyped-collection-types.mjs | 116 ++++ .../7985-untyped-collection-types.mjs.json | 1 + 8 files changed, 741 insertions(+), 2 deletions(-) create mode 100644 packages/compiler/src/frontend/lowering/js-collection-types.ts create mode 100644 packages/compiler/test/js-collection-types.test.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7985-untyped-collection-types.mjs.json create mode 100644 tests/corpus/7985-untyped-collection-types.mjs create mode 100644 tests/harness/corpus-costs/7985-untyped-collection-types.mjs.json diff --git a/packages/compiler/ambient/scriptc-overrides.d.ts b/packages/compiler/ambient/scriptc-overrides.d.ts index 2dafbcdf0..376eba9d5 100644 --- a/packages/compiler/ambient/scriptc-overrides.d.ts +++ b/packages/compiler/ambient/scriptc-overrides.d.ts @@ -70,3 +70,24 @@ interface PromiseConstructor { reject: (reason: Error) => void; }; } + +/* Carriers of the types the lowerer gives untyped JavaScript collections + * whose uses prove them (js-collection-types.ts). Nothing reads them at run + * time. */ +declare namespace __scriptcInferredCollections { + const map_string_string: Map; + const map_string_number: Map; + const map_string_boolean: Map; + const map_number_string: Map; + const map_number_number: Map; + const map_number_boolean: Map; + const map_boolean_string: Map; + const map_boolean_number: Map; + const map_boolean_boolean: Map; + const set_string: Set; + const set_number: Set; + const set_boolean: Set; + const array_string: string[]; + const array_number: number[]; + const array_boolean: boolean[]; +} diff --git a/packages/compiler/src/frontend/lowering/js-collection-types.ts b/packages/compiler/src/frontend/lowering/js-collection-types.ts new file mode 100644 index 000000000..2be3c067f --- /dev/null +++ b/packages/compiler/src/frontend/lowering/js-collection-types.ts @@ -0,0 +1,519 @@ +/* Types of untyped JavaScript collections that their uses prove. + * + * In a JavaScript file, `const m = new Map()`, `new Set()` and `[]` type as + * Map, Set and any[] to the checker, so every use lowers to + * the checked-dynamic collection operations. When every reference of such a + * `const` is a direct use of the collection, the value never leaves the + * binding. If its keys, values or elements are then each one primitive type + * wherever the program writes and looks them up, the binding lowers as the + * typed Map, Set or T[], as a JSDoc @type would make it: + * + * - Map: `m.get(k)`, `m.has(k)`, `m.delete(k)`, `m.clear()`, `m.size`, and + * `m.set(k, v)` as a statement (its result is the map). + * - Set: `s.add(k)` as a statement, `s.has(k)`, `s.delete(k)`, `s.clear()`, + * `s.size`. + * - Array: `a.push(...)`, `a.pop()`, `a.shift()`, `a.at(i)`, `a.includes(v)`, + * `a.indexOf(v)`, `a.join(separator)`, `a.length`. + * + * Any other reference (passing, returning, storing, exporting, iterating, + * spreading, inspecting the collection, an optional call), a direct `eval` + * in the file, or any doubt about a type keeps the binding untyped. + * + * The types come from carrier declarations in scriptc-overrides.d.ts, which + * only the lowering program includes. */ + +import * as ts from "../ts7/adapter.js"; +import { isJsSourceFile } from "../program.js"; +import { overridesDtsPath } from "../dts-paths.js"; +import type { Lowerer } from "./lowerer.js"; + +type Primitive = "string" | "number" | "boolean"; +const PRIMITIVES: readonly Primitive[] = ["string", "number", "boolean"]; + +type Collection = "map" | "set" | "array"; + +interface Candidate { + readonly kind: Collection; + readonly declaration: ts.VariableDeclaration; + /** Every identifier that names the binding, its declaration's included. */ + readonly names: ts.Identifier[]; + /** Map keys or Set members written by set/add. */ + readonly keyWrites: ts.Expression[]; + /** Map values written by set. Array elements written by push. */ + readonly valueWrites: ts.Expression[]; + /** Arguments compared with keys or elements: get/has/delete, includes/indexOf. */ + readonly lookups: ts.Expression[]; + /** Array indexes passed to at(). */ + readonly indexes: ts.Expression[]; + /** Separators passed to join(). */ + readonly separators: ts.Expression[]; + key: Primitive | undefined; + value: Primitive | undefined; +} + +const MAP_LOOKUPS = new Set(["get", "has", "delete"]); +const SET_LOOKUPS = new Set(["has", "delete"]); +const ARRAY_READS = new Set(["pop", "shift"]); +const ARRAY_SEARCHES = new Set(["includes", "indexOf"]); + +/** The inferred type of the binding a `new Map()` or `new Set()` initializes, + * which the construction adopts. */ +export function initializedCollectionType( + lowerer: Lowerer, + expr: ts.NewExpression, +): ts.Type | null { + const declaration = expr.parent; + return declaration !== undefined && + ts.isVariableDeclaration(declaration) && + declaration.initializer === expr && + ts.isIdentifier(declaration.name) + ? inferredCollectionType(lowerer, declaration.name) + : null; +} + +/** The inferred collection type of an identifier that names a proven + * binding, or null. Computed for every JavaScript file of the program on + * first use. */ +export function inferredCollectionType(lowerer: Lowerer, node: ts.Identifier): ts.Type | null { + const types = (lowerer.inferredCollectionTypes ??= inferProgram(lowerer)); + return types.size === 0 ? null : (types.get(node) ?? null); +} + +function inferProgram(lowerer: Lowerer): Map { + const out = new Map(); + const carriers = carrierTypes(lowerer); + if (carriers === null) return out; + for (const file of lowerer.program.getSourceFiles()) { + if (file.isDeclarationFile || !isJsSourceFile(file)) continue; + for (const candidate of inferFile(lowerer, file)) { + const name = + candidate.kind === "map" + ? `map_${candidate.key}_${candidate.value}` + : candidate.kind === "set" + ? `set_${candidate.key}` + : `array_${candidate.value}`; + const type = carriers.get(name); + if (type === undefined) continue; + for (const id of candidate.names) out.set(id, type); + } + } + return out; +} + +/** The carrier declarations' types, by name (`map_string_number`, + * `set_number`, `array_string`, ...), or null when the lowering program does + * not include them. */ +function carrierTypes(lowerer: Lowerer): Map | null { + const file = lowerer.program.getSourceFile(overridesDtsPath()); + if (file === undefined) return null; + const out = new Map(); + for (const statement of file.statements.nodes) { + if ( + !ts.isModuleDeclaration(statement) || + !ts.isIdentifier(statement.name) || + statement.name.text !== "__scriptcInferredCollections" || + statement.body === undefined || + !ts.isModuleBlock(statement.body) + ) + continue; + for (const member of statement.body.statements.nodes) { + if (!ts.isVariableStatement(member)) continue; + for (const declaration of member.declarationList.declarations.nodes) + if (ts.isIdentifier(declaration.name)) + out.set(declaration.name.text, lowerer.checker.getTypeAtLocation(declaration.name)); + } + } + return out.size > 0 ? out : null; +} + +function inferFile(lowerer: Lowerer, file: ts.SourceFile): Candidate[] { + const candidates = new Map(); + let directEval = false; + const declarations = (node: ts.Node): void => { + if ( + ts.isCallExpression(node) && + ts.isIdentifier(node.expression) && + node.expression.text === "eval" + ) + directEval = true; + if (ts.isVariableDeclaration(node)) { + const kind = candidateKind(lowerer, node); + const symbol = kind !== null ? lowerer.checker.getSymbolAtLocation(node.name) : undefined; + if (kind !== null && symbol !== undefined) + candidates.set(symbol, { + kind, + declaration: node, + names: [node.name as ts.Identifier], + keyWrites: [], + valueWrites: [], + lookups: [], + indexes: [], + separators: [], + key: undefined, + value: undefined, + }); + } + ts.forEachChild(node, declarations); + }; + declarations(file); + if (directEval || candidates.size === 0) return []; + + const names = new Set( + [...candidates.values()].map((c) => (c.declaration.name as ts.Identifier).text), + ); + const refused = new Set(); + const references = (node: ts.Node): void => { + if (ts.isIdentifier(node) && names.has(node.text)) { + const symbol = referencedSymbol(lowerer, node); + const candidate = symbol !== undefined ? candidates.get(symbol) : undefined; + if (symbol !== undefined && candidate !== undefined && node !== candidate.declaration.name) { + if (recordUse(candidate, node)) candidate.names.push(node); + else refused.add(symbol); + } + } + ts.forEachChild(node, references); + }; + references(file); + for (const symbol of refused) candidates.delete(symbol); + const proven = [...candidates.values()].filter( + (c) => c.valueWrites.length > 0 || c.keyWrites.length > 0, + ); + solve(lowerer, proven); + return proven.filter((c) => + c.kind === "map" ? c.key && c.value : c.kind === "set" ? c.key : c.value, + ); +} + +/** The collection a `const` declaration starts empty, when the checker + * types it as an untyped Map, Set or array. */ +function candidateKind(lowerer: Lowerer, declaration: ts.VariableDeclaration): Collection | null { + if (!ts.isIdentifier(declaration.name) || declaration.initializer === undefined) return null; + const list = declaration.parent; + if (!ts.isVariableDeclarationList(list) || (list.flags & ts.NodeFlags.Const) === 0) return null; + const statement = list.parent; + if ( + ts.isVariableStatement(statement) && + ts.getModifiers(statement)?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) + ) + return null; + const init = declaration.initializer; + let kind: Collection | null = null; + if (ts.isArrayLiteralExpression(init) && init.elements.nodes.length === 0) kind = "array"; + else if ( + ts.isNewExpression(init) && + init.typeArguments === undefined && + (init.arguments?.nodes.length ?? 0) === 0 + ) { + if (lowerer.isStdlibGlobal(init.expression, "Map")) kind = "map"; + else if (lowerer.isStdlibGlobal(init.expression, "Set")) kind = "set"; + } + if (kind === null) return null; + // A JSDoc type, or anything else the checker already knows, stands. + const type = lowerer.checker.getTypeAtLocation(declaration.name); + const args = + kind === "array" + ? lowerer.checker.isArrayType(type) + ? lowerer.checker.getTypeArguments(type as ts.TypeReference) + : [] + : lowerer.checker.getTypeArguments(type as ts.TypeReference); + const arity = kind === "map" ? 2 : 1; + if (args.length !== arity || !args.every((a) => (a.flags & ts.TypeFlags.Any) !== 0)) return null; + return kind; +} + +function referencedSymbol(lowerer: Lowerer, id: ts.Identifier): ts.Symbol | undefined { + const parent = id.parent; + if (parent !== undefined && ts.isShorthandPropertyAssignment(parent) && parent.name === id) + return lowerer.checker.getShorthandAssignmentValueSymbol(parent); + return lowerer.checker.getSymbolAtLocation(id); +} + +/** Records a reference's use, or answers false when the reference is not + * one of the collection uses this inference proves. */ +function recordUse(candidate: Candidate, id: ts.Identifier): boolean { + const access = id.parent; + if ( + access === undefined || + !ts.isPropertyAccessExpression(access) || + access.expression !== id || + access.questionDotToken !== undefined + ) + return false; + const name = access.name.text; + const call = access.parent; + if (call !== undefined && ts.isCallExpression(call) && call.expression === access) { + if (call.questionDotToken !== undefined) return false; + const args = call.arguments.nodes; + if (args.some(ts.isSpreadElement)) return false; + switch (candidate.kind) { + case "map": + if (MAP_LOOKUPS.has(name) && args.length === 1) + return (candidate.lookups.push(args[0]!), true); + if (name === "clear") return args.length === 0; + if (name === "set" && args.length === 2 && isStatement(call)) { + candidate.keyWrites.push(args[0]!); + candidate.valueWrites.push(args[1]!); + return true; + } + return false; + case "set": + if (SET_LOOKUPS.has(name) && args.length === 1) + return (candidate.lookups.push(args[0]!), true); + if (name === "clear") return args.length === 0; + if (name === "add" && args.length === 1 && isStatement(call)) + return (candidate.keyWrites.push(args[0]!), true); + return false; + case "array": + if (name === "push") return (candidate.valueWrites.push(...args), true); + if (ARRAY_READS.has(name)) return args.length === 0; + if (name === "at" && args.length === 1) return (candidate.indexes.push(args[0]!), true); + if (ARRAY_SEARCHES.has(name) && args.length === 1) + return (candidate.lookups.push(args[0]!), true); + if (name === "join" && args.length <= 1) return (candidate.separators.push(...args), true); + return false; + } + } + return (candidate.kind === "array" ? name === "length" : name === "size") && isPlainRead(access); +} + +function isStatement(call: ts.CallExpression): boolean { + let node: ts.Node = call; + while (node.parent !== undefined && ts.isParenthesizedExpression(node.parent)) node = node.parent; + return node.parent !== undefined && ts.isExpressionStatement(node.parent); +} + +/** A read that neither writes nor deletes the property. */ +function isPlainRead(access: ts.PropertyAccessExpression): boolean { + let node: ts.Node = access; + while (node.parent !== undefined && ts.isParenthesizedExpression(node.parent)) node = node.parent; + const parent = node.parent; + if (parent === undefined) return false; + if ( + ts.isBinaryExpression(parent) && + parent.left === node && + isAssignment(parent.operatorToken.kind) + ) + return false; + if ( + (ts.isPrefixUnaryExpression(parent) || ts.isPostfixUnaryExpression(parent)) && + (parent.operator === ts.SyntaxKind.PlusPlusToken || + parent.operator === ts.SyntaxKind.MinusMinusToken) + ) + return false; + return !ts.isDeleteExpression(parent); +} + +function isAssignment(kind: ts.SyntaxKind): boolean { + return kind >= ts.SyntaxKind.FirstAssignment && kind <= ts.SyntaxKind.LastAssignment; +} + +/** Decides each candidate's key and value types: a fixed point in which a + * decided candidate's reads type the expressions built from them. */ +function solve(lowerer: Lowerer, candidates: Candidate[]): void { + const bySymbol = new Map(); + for (const c of candidates) { + const symbol = lowerer.checker.getSymbolAtLocation(c.declaration.name); + if (symbol) bySymbol.set(symbol, c); + } + for (let changed = true; changed;) { + changed = false; + for (const c of candidates) { + if (c.kind !== "array" && c.key === undefined) { + const key = uniform(lowerer, bySymbol, c.keyWrites); + if (key !== null) { + c.key = key; + changed = true; + } + } + if (c.kind !== "set" && c.value === undefined) { + // Each candidate type is assumed for this collection's own reads. + const accepted = PRIMITIVES.filter((assumed) => { + c.value = assumed; + const found = uniform(lowerer, bySymbol, c.valueWrites); + c.value = undefined; + return found === assumed; + }); + if (accepted.length === 1) { + c.value = accepted[0]; + changed = true; + } + } + } + } + for (const c of candidates) { + const element = c.kind === "array" ? c.value : c.key; + // Lookups compare with the stored type; an index is a number. + const lookupsAgree = + element !== undefined && + c.lookups.every((e) => primitiveOf(lowerer, bySymbol, e, new Set()) === element) && + c.indexes.every((e) => primitiveOf(lowerer, bySymbol, e, new Set()) === "number") && + c.separators.every((e) => primitiveOf(lowerer, bySymbol, e, new Set()) === "string"); + if (!lookupsAgree) { + c.key = undefined; + c.value = undefined; + } + } +} + +/** The one primitive type of every expression, or null. */ +function uniform( + lowerer: Lowerer, + bySymbol: Map, + exprs: readonly ts.Expression[], +): Primitive | null { + let found: Primitive | null = null; + for (const e of exprs) { + const p = primitiveOf(lowerer, bySymbol, e, new Set()); + if (p === null || (found !== null && p !== found)) return null; + found = p; + } + return found; +} + +function checkerPrimitive(type: ts.Type): Primitive | null { + const flags = type.flags; + if (flags & (ts.TypeFlags.String | ts.TypeFlags.StringLiteral)) return "string"; + if (flags & (ts.TypeFlags.Number | ts.TypeFlags.NumberLiteral)) return "number"; + if (flags & (ts.TypeFlags.Boolean | ts.TypeFlags.BooleanLiteral)) return "boolean"; + return null; +} + +/** The primitive type `e` always evaluates to, or null. The checker answers + * where it knows; where it types `e` as `any`, the value's structure does: + * a read of a decided candidate, arithmetic and comparisons over such + * values, and constants defined from them. */ +function primitiveOf( + lowerer: Lowerer, + bySymbol: Map, + e: ts.Expression, + visiting: Set, +): Primitive | null { + const type = lowerer.checker.getTypeAtLocation(e); + if ((type.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) === 0) return checkerPrimitive(type); + const of = (x: ts.Expression): Primitive | null => primitiveOf(lowerer, bySymbol, x, visiting); + if (ts.isParenthesizedExpression(e)) return of(e.expression); + if (ts.isPrefixUnaryExpression(e)) { + if (e.operator === ts.SyntaxKind.ExclamationToken) return "boolean"; + return e.operator !== ts.SyntaxKind.PlusPlusToken && + e.operator !== ts.SyntaxKind.MinusMinusToken && + of(e.operand) === "number" + ? "number" + : null; + } + if (ts.isConditionalExpression(e)) { + const yes = of(e.whenTrue); + return yes !== null && yes === of(e.whenFalse) ? yes : null; + } + if (ts.isBinaryExpression(e)) { + const op = e.operatorToken.kind; + switch (op) { + case ts.SyntaxKind.LessThanToken: + case ts.SyntaxKind.GreaterThanToken: + case ts.SyntaxKind.LessThanEqualsToken: + case ts.SyntaxKind.GreaterThanEqualsToken: + case ts.SyntaxKind.EqualsEqualsEqualsToken: + case ts.SyntaxKind.ExclamationEqualsEqualsToken: + case ts.SyntaxKind.EqualsEqualsToken: + case ts.SyntaxKind.ExclamationEqualsToken: + return "boolean"; + case ts.SyntaxKind.QuestionQuestionToken: + case ts.SyntaxKind.BarBarToken: { + // `m.get(k) ?? d` and `a.pop() || d`: the stored type or a default of it. + const stored = storedRead(lowerer, bySymbol, e.left); + const fallback = of(e.right); + return stored !== null && stored === fallback ? stored : null; + } + case ts.SyntaxKind.PlusToken: { + const left = of(e.left); + const right = of(e.right); + if (left === "number" && right === "number") return "number"; + return left !== null && right !== null && (left === "string" || right === "string") + ? "string" + : null; + } + case ts.SyntaxKind.MinusToken: + case ts.SyntaxKind.AsteriskToken: + case ts.SyntaxKind.SlashToken: + case ts.SyntaxKind.PercentToken: + case ts.SyntaxKind.AsteriskAsteriskToken: + case ts.SyntaxKind.BarToken: + case ts.SyntaxKind.AmpersandToken: + case ts.SyntaxKind.CaretToken: + case ts.SyntaxKind.LessThanLessThanToken: + case ts.SyntaxKind.GreaterThanGreaterThanToken: + case ts.SyntaxKind.GreaterThanGreaterThanGreaterThanToken: + return of(e.left) === "number" && of(e.right) === "number" ? "number" : null; + default: + return null; + } + } + if (ts.isCallExpression(e) || ts.isPropertyAccessExpression(e)) + return candidateRead(lowerer, bySymbol, e); + // A constant defined from such an expression. + if (ts.isIdentifier(e) && !visiting.has(e)) { + const symbol = lowerer.checker.getSymbolAtLocation(e); + const declaration = symbol?.valueDeclaration; + if ( + declaration !== undefined && + ts.isVariableDeclaration(declaration) && + declaration.initializer !== undefined && + ts.isVariableDeclarationList(declaration.parent) && + (declaration.parent.flags & ts.NodeFlags.Const) !== 0 + ) { + visiting.add(e); + const p = primitiveOf(lowerer, bySymbol, declaration.initializer, visiting); + visiting.delete(e); + return p; + } + } + return null; +} + +/** The candidate a use reads, when `e` is `c.member` or `c.member(...)` of a + * candidate `c`. */ +function candidateOf( + lowerer: Lowerer, + bySymbol: Map, + e: ts.Expression, +): { candidate: Candidate; member: string } | null { + const access = ts.isCallExpression(e) ? e.expression : e; + if (!ts.isPropertyAccessExpression(access) || !ts.isIdentifier(access.expression)) return null; + const symbol = lowerer.checker.getSymbolAtLocation(access.expression); + const candidate = symbol !== undefined ? bySymbol.get(symbol) : undefined; + return candidate !== undefined ? { candidate, member: access.name.text } : null; +} + +/** The type of a candidate's read that may answer undefined: `m.get(k)`, + * `a.pop()`, `a.shift()`, `a.at(i)`. */ +function storedRead( + lowerer: Lowerer, + bySymbol: Map, + e: ts.Expression, +): Primitive | null { + while (ts.isParenthesizedExpression(e)) e = e.expression; + if (!ts.isCallExpression(e)) return null; + const read = candidateOf(lowerer, bySymbol, e); + if (read === null) return null; + const { candidate, member } = read; + if (candidate.kind === "map" && member === "get") return candidate.value ?? null; + if (candidate.kind === "array" && (ARRAY_READS.has(member) || member === "at")) + return candidate.value ?? null; + return null; +} + +/** The type of a candidate's read that always answers a value: size, + * length, has, includes, indexOf, push. */ +function candidateRead( + lowerer: Lowerer, + bySymbol: Map, + e: ts.Expression, +): Primitive | null { + const read = candidateOf(lowerer, bySymbol, e); + if (read === null) return null; + const { candidate, member } = read; + if (!ts.isCallExpression(e)) return member === "size" || member === "length" ? "number" : null; + if (member === "has" || member === "includes" || member === "delete") return "boolean"; + if (member === "indexOf" || (candidate.kind === "array" && member === "push")) return "number"; + if (candidate.kind === "array" && member === "join") return "string"; + return null; +} diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index b829b6ddc..c4dd6bce1 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -113,6 +113,7 @@ import { PoisonError, dynFallbackType, jsFuncNameOf, newFnCtx, own } from "./low import { isAssertClassNew } from "./assert-instances.js"; import { isCjsRequireGlobal } from "./lower-node-module.js"; import { lowerArrayConstructor } from "./containers/array-construction.js"; +import { initializedCollectionType } from "./js-collection-types.js"; import { lowerMapSeedNew, lowerSetSeedNew } from "./containers/collection-methods.js"; import { lowerObjectConstructor } from "./containers/indexed-objects.js"; import { knownBufEncoding, lowerBufferConstruct } from "./containers/bytes.js"; @@ -10568,7 +10569,11 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { // expression). The CONTEXTUAL type carries the annotation — adopt // it when it is a supported map. TS type arguments keep winning: // their expression type already maps. - if (mapped?.kind !== "map" || contextualSeed) { + const inferred = initializedCollectionType(lowerer, expr); + if (inferred) { + tsType = inferred; + mapped = lowerer.mapTypeOf(inferred); + } else if (mapped?.kind !== "map" || contextualSeed) { const ctx = lowerer.checker.getContextualType(expr); const ctxMapped = ctx ? lowerer.mapTypeOf(ctx) : null; if (ctx && ctxMapped?.kind === "map") { @@ -10708,7 +10713,8 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { // `new Set()`: construct + bulk add from supported values, // including live collection cursors. Duplicates collapse in insertion order. if (ts.isIdentifier(identifier) && lowerer.isStdlibGlobal(identifier, "Set")) { - const tsType = lowerer.typeOf(expr); + const inferred = initializedCollectionType(lowerer, expr); + const tsType = inferred ?? lowerer.typeOf(expr); let mapped = lowerer.mapTypeOf(tsType); const fieldType = assignedThisFieldType(lowerer, expr); if (mapped?.kind !== "set" && fieldType?.kind === "set") mapped = fieldType; diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index af89c61a4..78d1fafad 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -156,6 +156,7 @@ import { trackClassFieldCreation, } from "./class-dynamic-dispatch.js"; import { guardClassAttributeWrites } from "./class-attributes.js"; +import { inferredCollectionType } from "./js-collection-types.js"; import { guardFrozenWrites, markSloppyRecordWrites } from "./frozen-records.js"; import { applyHandleProperties } from "./handle-properties.js"; import { installBufferValue } from "./containers/bytes.js"; @@ -2846,6 +2847,9 @@ export class Lowerer { /** Parameters read as `any` in the error-path copy of an error-first * callback. */ readonly anySymbols = new Set(); + /** The collection types that uses prove for untyped JavaScript bindings, + * by every identifier naming one (js-collection-types.ts). */ + inferredCollectionTypes: Map | undefined = undefined; /** overload-choice's answers per call, binding and function. */ readonly dynamicOverloadAnswers = new Map(); /** Error parameters of an error-first callback with a known value in @@ -9055,6 +9059,10 @@ export class Lowerer { } typeOf(node: ts.Node): ts.Type { + if (ts.isIdentifier(node)) { + const inferred = inferredCollectionType(this, node); + if (inferred) return inferred; + } if (this.anySymbols.size > 0 && this.readsAnySymbol(node)) return this.checker.getAnyType(); // A checked-dynamic argument that another overload could take at run // time leaves the resolved overload's return a guess, and JS bindings diff --git a/packages/compiler/test/js-collection-types.test.ts b/packages/compiler/test/js-collection-types.test.ts new file mode 100644 index 000000000..88e2006b7 --- /dev/null +++ b/packages/compiler/test/js-collection-types.test.ts @@ -0,0 +1,62 @@ +import { mkdtempSync, readFileSync, rmSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile, deserializeModule, validateModule } from "../src/index.js"; + +// Corpus 7985 exercises every refusal: only the collections whose uses +// prove their types lower as typed collections; the rest stay untyped. +test("untyped JavaScript collections take the types their uses prove, and only those", async () => { + const dir = mkdtempSync(join(tmpdir(), "scriptc-js-collection-types-")); + try { + const entry = join( + import.meta.dirname, + "../../../tests/corpus/7985-untyped-collection-types.mjs", + ); + const output = join(dir, "main.ir.json"); + const lowered = await compile(entry, { outputKind: "ir", outDir: dir, outPath: output }); + if (!lowered.ok) throw new Error(JSON.stringify(lowered.diagnostics)); + const module = deserializeModule(readFileSync(output, "utf8")); + expect(validateModule(module)).toEqual([]); + const types = new Map(module.globals.map((g) => [g.name, JSON.stringify(g.type)])); + const map = (key: string, value: string) => + JSON.stringify({ kind: "map", key: { kind: key }, value: { kind: value } }); + const set = (elem: string) => JSON.stringify({ kind: "set", elem: { kind: elem } }); + const array = (elem: string) => JSON.stringify({ kind: "array", elem: { kind: elem } }); + // Untyped collections hold checked-dynamic keys, values and elements. + const typed = (t: string) => !t.includes('"dyn"'); + expect(Object.fromEntries([...types].filter(([, t]) => typed(t)))).toEqual({ + counts: map("string", "f64"), + seen: set("f64"), + stack: array("f64"), + words: array("string"), + byNumber: map("f64", "string"), + nums: array("f64"), + flags: set("bool"), + cache: map("string", "f64"), + "%loaded": '{"kind":"bool"}', + }); + for (const untyped of [ + "strings", + "numbers", + "mixedKeys", + "mixedValues", + "mixedElements", + "passed", + "stored", + "iterated", + "eachSet", + "shown", + "chained", + "optional", + "indexed", + "truncated", + "spread", + "unread", + "exported", + ]) + expect(typed(types.get(untyped)!), untyped).toBe(false); + } finally { + rmSync(dir, { recursive: true, force: true }); + } +}); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7985-untyped-collection-types.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7985-untyped-collection-types.mjs.json new file mode 100644 index 000000000..a807063cc --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7985-untyped-collection-types.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7985-untyped-collection-types.mjs" + ], + "diags": [] +} diff --git a/tests/corpus/7985-untyped-collection-types.mjs b/tests/corpus/7985-untyped-collection-types.mjs new file mode 100644 index 000000000..a60a2ea04 --- /dev/null +++ b/tests/corpus/7985-untyped-collection-types.mjs @@ -0,0 +1,116 @@ +// Untyped Maps, Sets and arrays whose uses prove their key, value and +// element types compile as typed collections; any other use keeps them +// untyped. Both must answer as Node does, including SameValueZero keys, +// lookups of another type, and every use that refuses the typing. + +// Typed: counters, membership sets and stacks used only through their +// methods. +const counts = new Map(); +const seen = new Set(); +const stack = []; +const words = []; +for (let i = 0; i < 40; i++) { + const key = "k" + (i % 7); + counts.set(key, (counts.get(key) ?? 0) + 1); + seen.add(i % 5); + stack.push(i * 2); + if (stack.length > 6) stack.shift(); + words.push(key); +} +console.log(counts.size, counts.get("k3"), counts.get("missing"), counts.has("k6"), counts.delete("k0"), counts.size); +console.log(seen.size, seen.has(4), seen.has(5), seen.delete(4), seen.has(4)); +console.log(stack.length, stack.at(-1), stack.at(0), stack.pop(), stack.includes(70), stack.indexOf(72), words.join("|").length); + +// SameValueZero keys and NaN elements on typed collections. +const byNumber = new Map(); +byNumber.set(NaN, "nan"); +byNumber.set(-0, "zero"); +byNumber.set(1.5, "x"); +console.log(byNumber.get(NaN), byNumber.get(0), byNumber.get(-0), byNumber.size, byNumber.has(1.5)); +const nums = []; +nums.push(NaN); +nums.push(-0); +console.log(nums.includes(NaN), nums.indexOf(NaN), nums.includes(0), nums.indexOf(0)); +const flags = new Set(); +flags.add(true); +console.log(flags.has(true), flags.has(false), flags.size); + +// Captured by a closure that only uses it. +const cache = new Map(); +const latest = () => cache.get("c") ?? -1; +console.log(latest()); +for (let i = 0; i < 3; i++) cache.set("c", i * 10); +console.log(latest(), cache.size); + +// Lookups of another type: the typing refuses, and the answers stay Node's. +const strings = new Map(); +strings.set("1", "one"); +console.log(strings.get(1), strings.get("1"), strings.has(1)); +const numbers = []; +numbers.push(1); +console.log(numbers.includes("1"), numbers.indexOf("1"), numbers.at("0")); + +// Mixed key, value and element types. +const mixedKeys = new Map(); +mixedKeys.set(1, "number"); +mixedKeys.set("1", "string"); +console.log(mixedKeys.size, mixedKeys.get(1), mixedKeys.get("1")); +const mixedValues = new Map(); +mixedValues.set("a", 1); +mixedValues.set("b", "two"); +console.log(mixedValues.get("a"), mixedValues.get("b")); +const mixedElements = []; +mixedElements.push(1); +mixedElements.push("two"); +console.log(mixedElements.join(","), mixedElements.length); + +// Escapes and other uses that keep the collection untyped. +const passed = new Map(); +passed.set("x", 1); +function sizeOf(m) { + return m.size; +} +console.log(sizeOf(passed)); +function make() { + const made = new Set(); + made.add("y"); + return made; +} +console.log(make().has("y")); +const stored = []; +stored.push(3); +const holder = { list: stored }; +holder.list.push(4); +console.log(stored.length, holder.list.join("+")); +const iterated = new Map(); +iterated.set("a", 1); +iterated.set("b", 2); +for (const [k, v] of iterated) console.log("entry", k, v); +const eachSet = new Set(); +eachSet.add(3); +eachSet.forEach((v) => console.log("member", v)); +const shown = new Map(); +shown.set("s", 1); +console.log(shown); +const chained = new Map(); +chained.set("a", 1).set("b", 2); +console.log(chained.size); +const optional = new Map(); +optional.set("o", 1); +console.log(optional?.get("o"), optional.get?.("o")); +const indexed = []; +indexed.push(1); +indexed[3] = 2; +console.log(indexed.length, indexed.join(",")); +const truncated = []; +truncated.push(1, 2, 3); +truncated.length = 1; +console.log(truncated.length, truncated.at(0)); +const spread = []; +spread.push(5); +console.log(Math.max(...spread)); +const unread = new Map(); +console.log(unread.size, unread.get("none")); +export const exported = new Map(); +exported.set("e", 1); +console.log(exported.get("e")); diff --git a/tests/harness/corpus-costs/7985-untyped-collection-types.mjs.json b/tests/harness/corpus-costs/7985-untyped-collection-types.mjs.json new file mode 100644 index 000000000..6915a85fe --- /dev/null +++ b/tests/harness/corpus-costs/7985-untyped-collection-types.mjs.json @@ -0,0 +1 @@ +{ "plain": 2400, "san": 2600 } From 9496e429689146193892d09933645783348478e0 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 01:27:44 -0500 Subject: [PATCH 070/259] Keep a pointer-wrapped argument on the heap when its callee keeps the narrowed payload A union parameter's proof covered the union, not its payload: narrowing it and storing, returning or pushing the result, a narrowed nullish read, and a store into a nullable-pointer field all counted as projections. That holds for a boxed union, whose payload is a separate object. A record passed through a nullable-pointer union is that payload, so forwarding it to such a callee let a record in its caller's frame escape the frame. A pointer-wrapped argument now needs a second fact from the callee's union parameter: its payload stays in place too. The payload is in place when it is only tested, narrowed for a field read (directly or through the checked narrowing a field read of a `T | undefined` parameter compiles to), or passed on to a parameter that is proved in turn. The facts that other arguments use are unchanged. Corpus 7663 has callees that push (directly and through a non-null assertion), default, store in a global record field or a class field, or pass on the narrowed record, and one that only reads it. --- .../src/backend/llvm/call-lifetimes.test.ts | 105 ++++++++++++++++ .../src/backend/llvm/call-lifetimes.ts | 119 +++++++++++++++--- .../7663-pointer-union-stored-payload.ts.json | 6 + .../7663-pointer-union-stored-payload.ts | 83 ++++++++++++ 4 files changed, 297 insertions(+), 16 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7663-pointer-union-stored-payload.ts.json create mode 100644 tests/corpus/7663-pointer-union-stored-payload.ts diff --git a/packages/compiler/src/backend/llvm/call-lifetimes.test.ts b/packages/compiler/src/backend/llvm/call-lifetimes.test.ts index 52b2a8775..5c40bb4ce 100644 --- a/packages/compiler/src/backend/llvm/call-lifetimes.test.ts +++ b/packages/compiler/src/backend/llvm/call-lifetimes.test.ts @@ -806,3 +806,108 @@ test("a wrap into a pointer union forwards the wrapped binding to the callee's p expect(analyzeWith(true).parameters.get("outer")).toBeUndefined(); expect(analyzeWith(true).locals.get("outer")).toEqual(new Set()); }); + +test("a pointer-wrapped binding needs a callee that keeps the narrowed payload in place", () => { + const wrapCell: IrExpr = { + kind: "unionWrap", + unionId: "optional", + tag: 0, + value: ref("cell", record), + type: optional, + loc, + }; + const outer = helper("outer", []); + outer.locals.push(local("cell", record)); + outer.body = [ + { + kind: "varDecl", + localId: "cell", + init: { kind: "recordLit", fields: [], type: record, loc }, + loc, + }, + ret(call("leaf", [wrapCell])), + ]; + const read = (value: IrExpr): IrExpr => ({ + kind: "recordGet", + obj: value, + shapeId: "cell", + field: "x", + type: F64, + loc, + }); + const keeps = (leaf: IrFunction, ...more: IrFunction[]): boolean => { + const result = analyzeCallLifetimes( + new Map([outer, leaf, ...more].map((fn) => [fn.name, fn])), + (className) => className === "Node", + undefined, + undefined, + undefined, + undefined, + () => true, + ); + return result.locals.get("outer")?.has("cell") !== true; + }; + const leafWith = (body: IrStmt[]): IrFunction => ({ ...helper("leaf"), body }); + // Tag tests and field reads of the narrowed payload leave it in place. + expect(keeps(leafWith([{ kind: "exprStmt", expr: tag("value"), loc }]))).toBe(false); + expect(keeps(leafWith([ret(read(narrow("value")))]))).toBe(false); + // So do field reads through a checked narrowing, which throws on the + // other arm (`value.x` of a `T | undefined` parameter). + const checked: IrExpr = { + kind: "ternary", + cond: tag("value"), + then: { kind: "libCall", fn: "error.nodeThrow", args: [], type: record, loc }, + else_: narrow("value"), + type: record, + loc, + }; + expect(keeps(leafWith([ret(read(checked))]))).toBe(false); + // Returning it keeps the payload. + const returnsChecked = leafWith([ret(checked)]); + returnsChecked.returnType = record; + expect(keeps(returnsChecked)).toBe(true); + // Returning the narrowed payload, or a narrowed nullish read, keeps it, + // although the union itself is only projected. + const returned = leafWith([ret(narrow("value"))]); + returned.returnType = record; + expect(analyze(returned).parameters.get("leaf")).toEqual(new Set([0])); + expect(keeps(returned)).toBe(true); + const defaulted = leafWith([ + ret({ kind: "nullish", left: ref("value"), right: ref("other", record), type: record, loc }), + ]); + defaulted.locals.push(local("other", record)); + expect(keeps(defaulted)).toBe(true); + // So does a nullable-pointer field store of the union. + const self: IrType = { kind: "object", className: "Node" }; + const stored = leafWith([ + { + kind: "fieldSet", + obj: ref("this", self), + className: "Node", + field: "next", + value: ref("value"), + loc, + }, + ]); + stored.params = [{ localId: "value", name: "value", type: optional }]; + stored.locals.push(local("this", self)); + expect(keeps(stored)).toBe(true); + // A narrowed payload passed on, or the union passed on, is in place when + // the next callee keeps it in place. + const inner = (body: IrStmt[], type: IrType = record): IrFunction => { + const fn = helper("inner"); + fn.params[0]!.type = fn.locals[0]!.type = type; + fn.body = body; + return fn; + }; + const passNarrowed = leafWith([ret(call("inner", [narrow("value")]))]); + expect(keeps(passNarrowed, inner([ret(read(ref("value", record)))]))).toBe(false); + const returnsRecord = inner([ret(ref("value", record))]); + returnsRecord.returnType = record; + expect(keeps(passNarrowed, returnsRecord)).toBe(true); + const passUnion = leafWith([ret(call("inner", [ref("value")]))]); + expect(keeps(passUnion, inner([ret(read(narrow("value")))], optional))).toBe(false); + const innerReturned = inner([ret(narrow("value"))], optional); + innerReturned.returnType = record; + expect(keeps(passUnion, innerReturned)).toBe(true); +}); diff --git a/packages/compiler/src/backend/llvm/call-lifetimes.ts b/packages/compiler/src/backend/llvm/call-lifetimes.ts index 8055c7958..becd24805 100644 --- a/packages/compiler/src/backend/llvm/call-lifetimes.ts +++ b/packages/compiler/src/backend/llvm/call-lifetimes.ts @@ -14,6 +14,11 @@ import { storedLastUseRead } from "./local-extents.js"; interface ForwardedUse { callee: string; index: number; + /** The binding reached the call inside a nullable-pointer union + * (PointerWrapTest): the callee's parameter holds the binding itself as + * its payload, so the callee must keep the payload, not only the union, + * in place. */ + wrapped: boolean; } interface Uses { @@ -21,6 +26,13 @@ interface Uses { written: Set; declarations: Map; forwards: Map; + /** Union bindings whose payload a use may keep: a narrowed read that is + * not projected or passed on, a narrowed nullish read, a store into a + * nullable-pointer field. The union itself can still be only projected. */ + payloadKept: Set; + /** Narrowed payloads of union bindings passed directly as call arguments: + * the payload stays in place if the callee's parameter is proved. */ + payloadForwards: Map; } interface Parameter { @@ -117,7 +129,37 @@ function collectUses( written: new Set(), declarations: new Map(), forwards: new Map(), + payloadKept: new Set(), + payloadForwards: new Map(), }; + const forward = ( + table: Map, + localId: string, + use: ForwardedUse, + ): void => { + let forwards = table.get(localId); + if (!forwards) table.set(localId, (forwards = [])); + forwards.push(use); + }; + /** The union binding `x` whose payload `value` is: `unionNarrow(x)`, or a + * checked narrowing `unionIsTag(x) ? : unionNarrow(x)` (either + * order), whose other branch is visited as any use. */ + function narrowedBinding(value: IrExpr): string | null { + if (value.kind === "unionNarrow") + return value.value.kind === "varRef" ? value.value.localId : null; + if ( + value.kind !== "ternary" || + value.cond.kind !== "unionIsTag" || + value.cond.value.kind !== "varRef" + ) + return null; + const id = value.cond.value.localId; + if (value.else_.kind === "libCall" && narrowedBinding(value.then) === id) + return expr(value.else_) ? id : null; + if (value.then.kind === "libCall" && narrowedBinding(value.else_) === id) + return expr(value.then) ? id : null; + return null; + } const aliases: { alias: string; source: string }[] = []; const stringInput = (value: IrExpr): boolean => { if (value.kind === "varRef" && value.type.kind === "string") return true; @@ -151,6 +193,12 @@ function collectUses( if (borrowsMapReadInputs(node)) return expr(node.receiver) && node.args.every(stringInput); break; case "unionNarrow": + // The payload may escape; the union itself does not. + if (node.value.kind === "varRef") { + uses.payloadKept.add(node.value.localId); + return true; + } + break; case "unionIsTag": if (node.value.kind === "varRef") return true; break; @@ -167,12 +215,16 @@ function collectUses( node.left.kind === "varRef" && node.left.type.kind === "union" && node.type.kind !== "union" - ) + ) { + uses.payloadKept.add(node.left.localId); return expr(node.right); + } break; case "fieldGet": case "recordGet": - if (node.obj.kind === "varRef") return true; + // A field read of a binding, or of a union binding's narrowed + // payload, keeps neither. + if (node.obj.kind === "varRef" || narrowedBinding(node.obj) !== null) return true; break; case "dynFrom": // A copied record converts field by field; a live capsule keeps it. @@ -206,17 +258,19 @@ function collectUses( return node.args.every(expr); case "call": node.args.forEach((arg, index) => { - const value = - arg.kind === "unionWrap" && arg.value.kind === "varRef" && pointerWrap(arg) - ? arg.value - : arg; + const narrowed = narrowedBinding(arg); + if (narrowed !== null) { + forward(uses.payloadForwards, narrowed, { callee: node.callee, index, wrapped: false }); + return; + } + const wrapped = + arg.kind === "unionWrap" && arg.value.kind === "varRef" && pointerWrap(arg); + const value = wrapped ? arg.value : arg; if (value.kind !== "varRef") { expr(arg); return; } - let forwards = uses.forwards.get(value.localId); - if (!forwards) uses.forwards.set(value.localId, (forwards = [])); - forwards.push({ callee: node.callee, index }); + forward(uses.forwards, value.localId, { callee: node.callee, index, wrapped }); }); return true; case "assignExpr": @@ -260,8 +314,11 @@ function collectUses( node.value.kind === "varRef" && node.value.type.kind === "union" && nullableField(node.className, node.field) - ) + ) { + // The field retains the payload. + uses.payloadKept.add(node.value.localId); return expr(node.obj); + } const stored = fieldStore( node.obj, node.value, @@ -360,6 +417,9 @@ export function analyzeCallLifetimes( const usesByFunction = new Map(); const lazyCaptures = new LazyCaptures(functions); const nodes = new Map(); + /** Union parameters that keep their payload in place too, which a + * pointer-wrapped argument needs (ForwardedUse.wrapped). */ + const payloadNodes = new Map(); const unsafe: Parameter[] = []; const consumed: { fn: string; index: number }[] = []; const result: CallLifetimes = { @@ -472,23 +532,50 @@ export function analyzeCallLifetimes( return node; }), ); + payloadNodes.set( + fn.name, + fn.params.map((param) => { + if (param.type.kind !== "union") return undefined; + const node: Parameter = { safe: !uses.payloadKept.has(param.localId), callers: new Set() }; + if (!node.safe) unsafe.push(node); + return node; + }), + ); } + /** The fact a forwarded use needs from the callee's parameter. */ + const target = (use: ForwardedUse): Parameter | undefined => + use.wrapped ? payloadNodes.get(use.callee)?.[use.index] : nodes.get(use.callee)?.[use.index]; for (const fn of functions.values()) { const params = nodes.get(fn.name); const uses = usesByFunction.get(fn.name); if (!params || !uses) continue; - fn.params.forEach((param, index) => { - const node = params[index]!; + const depend = (node: Parameter, callees: (Parameter | undefined)[]): void => { if (!node.safe) return; - for (const use of uses.forwards.get(param.localId) ?? []) { - const callee = nodes.get(use.callee)?.[use.index]; + for (const callee of callees) { if (!callee) { node.safe = false; unsafe.push(node); - break; + return; } callee.callers.add(node); } + }; + fn.params.forEach((param, index) => { + const node = params[index]!; + const forwards = uses.forwards.get(param.localId) ?? []; + depend(node, forwards.map(target)); + const payload = payloadNodes.get(fn.name)?.[index]; + if (!payload) return; + // The payload stays in place when the union does, when every callee + // the union reaches keeps its payload too, and when every callee its + // narrowed payload reaches proves that parameter. + depend(payload, [ + node, + ...forwards.map((use) => payloadNodes.get(use.callee)?.[use.index]), + ...(uses.payloadForwards.get(param.localId) ?? []).map( + (use) => nodes.get(use.callee)?.[use.index], + ), + ]); }); } for (let i = 0; i < unsafe.length; i++) { @@ -520,7 +607,7 @@ export function analyzeCallLifetimes( ) continue; const forwards = uses.forwards.get(local.id) ?? []; - if (forwards.every((use) => result.parameters.get(use.callee)?.has(use.index) === true)) { + if (forwards.every((use) => target(use)?.safe === true)) { projected.add(local.id); if (eligible(local) && !uses.written.has(local.id)) safe.add(local.id); } diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7663-pointer-union-stored-payload.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7663-pointer-union-stored-payload.ts.json new file mode 100644 index 000000000..51998f0eb --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7663-pointer-union-stored-payload.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7663-pointer-union-stored-payload.ts" + ], + "diags": [] +} diff --git a/tests/corpus/7663-pointer-union-stored-payload.ts b/tests/corpus/7663-pointer-union-stored-payload.ts new file mode 100644 index 000000000..92ac68bfb --- /dev/null +++ b/tests/corpus/7663-pointer-union-stored-payload.ts @@ -0,0 +1,83 @@ +// Records passed to `T | undefined` parameters whose callee keeps the +// narrowed record: pushed into a global array (also through a non-null +// assertion), kept through `??`, stored in a nullable class field or a record +// field, or passed on to a callee that keeps it. Each record must outlive its +// caller's frame. A callee that only reads the narrowed record lets it stay +// where it is. +interface Tagged { + id: number; + tags: string[]; +} +interface Slot { + held: Tagged | undefined; +} +const kept: Tagged[] = []; +const slot: Slot = { held: undefined }; +function pushNarrowed(t: Tagged | undefined): void { + if (t !== undefined) kept.push(t); +} +function pushAsserted(t: Tagged | undefined): void { + kept.push(t!); +} +function keepDefaulted(t: Tagged | undefined): void { + kept.push(t ?? { id: -1, tags: [] }); +} +function storeInSlot(t: Tagged | undefined): void { + if (t !== undefined) slot.held = t; +} +function keepRecord(t: Tagged): void { + kept.push(t); +} +function passOn(t: Tagged | undefined): void { + if (t !== undefined) keepRecord(t); +} +function readOnly(t: Tagged | undefined): number { + return t === undefined ? 0 : t.id + t.tags.length; +} +class Holder { + last: Tagged | undefined = undefined; + take(t: Tagged | undefined): void { + this.last = t; + } +} +const holder = new Holder(); +function fill(round: number): number { + let read = 0; + for (let i = 0; i < 3; i++) { + const a: Tagged = { id: round * 10 + i, tags: ["a", String(i)] }; + pushNarrowed(a); + const b: Tagged = { id: round * 10 + i + 100, tags: ["b"] }; + keepDefaulted(b); + const c: Tagged = { id: round * 10 + i + 200, tags: ["c"] }; + storeInSlot(c); + const d: Tagged = { id: round * 10 + i + 300, tags: ["d", "d"] }; + holder.take(d); + const e: Tagged = { id: round * 10 + i + 400, tags: [] }; + passOn(e); + const g: Tagged = { id: round * 10 + i + 600, tags: ["g", "g", "g"] }; + pushAsserted(g); + const f: Tagged = { id: round * 10 + i + 500, tags: ["f"] }; + read += readOnly(f); + } + return read; +} +// Reuses the stack the callers above ran on, and allocates collectable +// records, before the kept ones are read. +function churn(n: number): number { + let total = 0; + for (let i = 0; i < n; i++) { + const t: Tagged = { id: i, tags: [String(i), String(i + 1)] }; + total += t.tags.length + readOnly(t); + } + return total; +} +let reads = 0; +for (let round = 0; round < 4; round++) { + reads += fill(round); + reads += churn(200); +} +console.log("reads", reads); +console.log("kept", kept.length); +for (const t of kept) console.log(t.id, t.tags.join("+")); +console.log("slot", slot.held === undefined ? "none" : slot.held.id, slot.held?.tags.join("+")); +console.log("holder", holder.last === undefined ? "none" : holder.last.id, holder.last?.tags.join("+")); From 937db546561ca427cc85b027f3033239d8164084 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 01:42:23 -0500 Subject: [PATCH 071/259] Raise the capped Linux test scope to 15 GB of RAM The sanitized self-hosting native-frontend build needs about 15 GB by itself: its clang compile of the whole frontend under ASan peaks at 10.5 GB beside a 3.8 GB compile in Node. In the 14 GB scope, with the shard's other work running beside it, the kernel killed that clang intermittently, so SC5004 reported clang's warnings and no error (SAN 16/20 and 19/20). The scope now caps RAM at 15 GB, still below the runner's 16 GB, and may still swap past it. --- .github/workflows/ci.yml | 12 +++++++----- tests/harness/ci-test-plan.test.ts | 2 +- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2d3ecbf18..edb2b5731 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -217,19 +217,21 @@ jobs: # worker budget covers both processes; file and case shard axes stay # separate so every fixture still runs exactly once in each lane. # The tests run in a transient scope capped below the runner's 16 GB, so - # the runner itself keeps memory: past 14 GB of RAM the scope swaps, as - # the whole runner did before (a sanitized shard peaks near 16 GB), and - # when RAM and swap run out the kernel kills the scope's largest process. + # the runner itself keeps memory: past 15 GB of RAM the scope swaps, as + # the whole runner did before, and when RAM and swap run out the kernel + # kills the scope's largest process. A sanitized shard peaks near 16 GB, + # and the sanitized self-hosting native-frontend build alone needs 15 GB + # (its clang compile of the frontend takes 10.5 GB). # OOMPolicy=continue leaves the rest of the scope running, so vitest # reports the killed worker and the job log names the test. Node sizes # its default heap from the memory it may use, which the scope lowers - # to about 3.5 GB; the workers keep the 4 GB heap they had on the bare + # below 4 GB; the workers keep the 4 GB heap they had on the bare # runner. - name: Tests (corpus and integration suites) run: | ulimit -c 0 if [ -d /run/systemd/system ]; then - exec sudo --preserve-env systemd-run --scope --quiet -p MemoryMax=14G -p OOMPolicy=continue \ + exec sudo --preserve-env systemd-run --scope --quiet -p MemoryMax=15G -p OOMPolicy=continue \ --uid="$(id -u)" --gid="$(id -g)" -- env PATH="$PATH" HOME="$HOME" NODE_OPTIONS="--max-old-space-size=4096" node scripts/ci-test.mjs fi node scripts/ci-test.mjs diff --git a/tests/harness/ci-test-plan.test.ts b/tests/harness/ci-test-plan.test.ts index 6cee99370..29268c841 100644 --- a/tests/harness/ci-test-plan.test.ts +++ b/tests/harness/ci-test-plan.test.ts @@ -298,7 +298,7 @@ test("pull requests run the full suite on Linux and the darwin suite on macOS", // runner, and directly elsewhere. const linuxRun = linux.steps.at(-1)!.run as string; expect(linuxRun.startsWith("ulimit -c 0\n")).toBe(true); - expect(linuxRun).toContain("systemd-run --scope --quiet -p MemoryMax=14G -p OOMPolicy=continue"); + expect(linuxRun).toContain("systemd-run --scope --quiet -p MemoryMax=15G -p OOMPolicy=continue"); expect(linuxRun).toMatch( /-- env PATH="\$PATH" HOME="\$HOME" NODE_OPTIONS="--max-old-space-size=4096" node scripts\/ci-test\.mjs\n/, ); From 1ddec6df7cc7c81eb934d90675651724f3c15922 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 01:52:11 -0500 Subject: [PATCH 072/259] Freeze the symbol-keyed fields of class instances A frozen class instance kept its symbol-keyed fields writable through typed references, and Object.isFrozen, isSealed and isExtensible reported it unfrozen, because the field write checks and the instance's checked view covered its string-keyed fields only. This held for Object.freeze through an untyped value and for a typed Object.freeze alike. - Writes to a symbol-keyed field of a hierarchy with an integrity word are checked like other field writes, and throw Node's TypeError naming the symbol ("Cannot assign to read only property 'Symbol(tag)' ..."). - The checked view applies the instance's integrity state to its symbol-keyed properties too, and the commit of an untyped freeze, seal or preventExtensions counts them. - The commit removes a symbol-keyed field's entry from the property bag whatever its attributes (scr_dyn_obj_delete_symbol_field), as it does for string-keyed fields, so a sealed view no longer leaves the field's old value in the bag. Corpus 7407 covers freeze and seal of symbol-keyed fields through unknown and through typed calls, on a class and a subclass, and matches Node. --- .../src/backend/llvm/expr-stream-bridges.ts | 8 ++- .../src/frontend/lowering/class-attributes.ts | 40 ++++++++++++--- packages/runtime/src/scr_dyn.h | 3 ++ packages/runtime/src/scr_json.c | 50 +++++++++++++++---- tests/corpus/7407-frozen-class-instances.ts | 38 ++++++++++++++ 5 files changed, 120 insertions(+), 19 deletions(-) diff --git a/packages/compiler/src/backend/llvm/expr-stream-bridges.ts b/packages/compiler/src/backend/llvm/expr-stream-bridges.ts index 757e4349f..357db2fae 100644 --- a/packages/compiler/src/backend/llvm/expr-stream-bridges.ts +++ b/packages/compiler/src/backend/llvm/expr-stream-bridges.ts @@ -498,7 +498,9 @@ export function streamTypedRefCommitAdapter( host.declare( meta.def.tracksOwnFields ? `declare void @scr_dyn_symbol_key_placeholder(ptr, ptr)` - : `declare void @scr_dyn_key_delete_computed(ptr, ptr, i1 zeroext)`, + : withAttributes + ? `declare void @scr_dyn_obj_delete_symbol_field(ptr, ptr)` + : `declare void @scr_dyn_key_delete_computed(ptr, ptr, i1 zeroext)`, ); [...symbols.values()].forEach((globalId, index) => lines.push( @@ -506,7 +508,9 @@ export function streamTypedRefCommitAdapter( ` %bag_sym${index} = call ptr @${host.dyn.toDynHelper(SYMBOL_T)}(ptr %bag_symraw${index})`, meta.def.tracksOwnFields ? ` call void @scr_dyn_symbol_key_placeholder(ptr %bag, ptr %bag_sym${index})` - : ` call void @scr_dyn_key_delete_computed(ptr %bag, ptr %bag_sym${index}, i1 zeroext false)`, + : withAttributes + ? ` call void @scr_dyn_obj_delete_symbol_field(ptr %bag, ptr %bag_sym${index})` + : ` call void @scr_dyn_key_delete_computed(ptr %bag, ptr %bag_sym${index}, i1 zeroext false)`, ` call void @scr_dyn_release_v(ptr %bag_sym${index})`, ), ); diff --git a/packages/compiler/src/frontend/lowering/class-attributes.ts b/packages/compiler/src/frontend/lowering/class-attributes.ts index de7cc8ca7..cdd53efa6 100644 --- a/packages/compiler/src/frontend/lowering/class-attributes.ts +++ b/packages/compiler/src/frontend/lowering/class-attributes.ts @@ -303,6 +303,32 @@ export function lowerClassFieldDefine( }; } +/** The property key of `field` when it is the storage of a symbol-keyed + * field of `info`, as the read-only TypeError names it: the symbol's + * String() form ("Symbol(tag)"), read from the module global that holds + * the symbol. Null for other fields. */ +function symbolFieldKey( + lowerer: Lowerer, + info: ClassInfo, + field: string, + loc: SrcLoc, +): IrExpr | null { + if (info.symbolFields === undefined) return null; + for (const [symbol, name] of info.symbolFields) { + if (name !== field) continue; + const global = lowerer.globalsBySymbol.get(symbol); + if (global?.type.kind !== "symbol") return null; + return { + kind: "libCall", + fn: "sym.toString", + args: [varRef(global.id, global.type, loc)], + type: STRING, + loc, + }; + } + return null; +} + function classDisplayName(info: ClassInfo): string { return info.def.jsName ?? info.decl?.name?.text ?? info.def.name.replace(/^%/, ""); } @@ -367,12 +393,15 @@ export function guardClassAttributeWrites(lowerer: Lowerer, functions: IrFunctio if ( statement.kind !== "fieldSet" || statement.attributesChecked || - !guarded.has(statement.className) || - !isClassOwnEnumerableFieldName(statement.field) + !guarded.has(statement.className) ) return statement; const info = lowerer.classes.get(statement.className)!; const loc = statement.loc; + // A symbol-keyed field is an own property under its symbol. + const symbolKey = symbolFieldKey(lowerer, info, statement.field, loc); + if (!symbolKey && !isClassOwnEnumerableFieldName(statement.field)) return statement; + const key = (): IrExpr => symbolKey ?? strLit(statement.field, loc); const receiver = local(statement.obj.type, loc); const value = local(statement.value.type, loc); const masked = (field: string, bit: number): IrExpr => ({ @@ -405,7 +434,7 @@ export function guardClassAttributeWrites(lowerer: Lowerer, functions: IrFunctio expr: { kind: "libCall", fn: "class.throwNotExtensible", - args: [strLit(statement.field, loc)], + args: [key()], type: VOID, loc, }, @@ -420,10 +449,7 @@ export function guardClassAttributeWrites(lowerer: Lowerer, functions: IrFunctio expr: { kind: "libCall", fn: "class.throwReadOnly", - args: [ - strLit(statement.field, loc), - instanceClassName(lowerer, info, receiver, helpers, loc), - ], + args: [key(), instanceClassName(lowerer, info, receiver, helpers, loc)], type: VOID, loc, }, diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index bf3b8d426..9df51f90a 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -1220,6 +1220,9 @@ void scr_dyn_key_delete(ScrDyn *recv, const ScrStr *key, bool strict); /* Removes the own property `key` of an ordinary object whatever its * attributes, as scr_dyn_obj_set_field replaces values. */ void scr_dyn_obj_delete_field(ScrDyn *obj, const ScrStr *key); +/* The same for the own symbol-keyed property `symbol` of an ordinary + * object. */ +void scr_dyn_obj_delete_symbol_field(ScrDyn *obj, ScrDyn *symbol); /* This thread's global object box (borrowed). Every spelling of the global * object answers it; its symbol-keyed properties are the global object's * (scr_node_builtin.c). */ diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 2f8e4b6f8..bc14a8a1e 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -2415,10 +2415,14 @@ double scr_dyn_class_view_integrity(const ScrDyn *view, double bits, ScrDyn *bag state |= SCR_CLASS_NOT_EXTENSIBLE; if (bag && bag->kind == SCR_DYN_OBJ) bag->non_extensible = true; bool sealed = true, frozen = true; - for (size_t i = 0; i < view->v.obj.len; i++) { - const ScrDynEntry *entry = &view->v.obj.entries[i]; - if (entry->configurable) sealed = false; - if (!entry->accessor && entry->writable) frozen = false; + /* The string-keyed entries, then the symbol-keyed ones. */ + for (const ScrDyn *table = view; table; table = table == view ? view->symbol_properties : NULL) { + if (table->kind != SCR_DYN_OBJ) continue; + for (size_t i = 0; i < table->v.obj.len; i++) { + const ScrDynEntry *entry = &table->v.obj.entries[i]; + if (entry->configurable) sealed = false; + if (!entry->accessor && entry->writable) frozen = false; + } } if (sealed) state |= SCR_CLASS_SEALED; if (sealed && frozen) state |= SCR_CLASS_FROZEN; @@ -7969,6 +7973,22 @@ bool scr_dyn_has_key_computed(const ScrDyn *value, const ScrDyn *key) { return s bool scr_dyn_has_own_computed(const ScrDyn *value, const ScrDyn *key) { return scr_dyn_key_probe_computed(value, key, 1); } bool scr_dyn_property_is_enumerable_computed(const ScrDyn *value, const ScrDyn *key) { return scr_dyn_key_probe_computed(value, key, 2); } +static void scr_json_delete_member(ScrDyn *object, const ScrStr *key); + +void scr_dyn_obj_delete_symbol_field(ScrDyn *obj, ScrDyn *symbol) { + if (obj->kind != SCR_DYN_OBJ || !obj->symbol_properties) return; + ScrStr *name = scr_dyn_symbol_storage_key(symbol); + scr_json_delete_member(obj->symbol_properties, name); + scr_str_release(name); + for (size_t i = 0; obj->symbol_keys && i < obj->symbol_keys->v.arr.len; i++) { + if (!scr_dyn_strict_eq(obj->symbol_keys->v.arr.items[i], symbol)) continue; + scr_dyn_release(obj->symbol_keys->v.arr.items[i]); + size_t remaining = --obj->symbol_keys->v.arr.len - i; + memmove(&obj->symbol_keys->v.arr.items[i], &obj->symbol_keys->v.arr.items[i + 1], remaining * sizeof(ScrDyn *)); + break; + } +} + void scr_dyn_key_delete_computed(ScrDyn *value, const ScrDyn *raw_key, bool strict) { ScrDyn *key = scr_dyn_property_key_value(raw_key); if (!key) return; @@ -16914,17 +16934,27 @@ void scr_dyn_class_field_attributes(ScrDyn *view, ScrStr *name, double bits) { if (b & SCR_FIELD_NOT_CONFIGURABLE) entry->configurable = false; } -void scr_dyn_class_view_attributes(ScrDyn *view, double bits) { - unsigned b = (unsigned)bits; - if (b == 0 || view->kind != SCR_DYN_OBJ) return; - view->non_extensible = true; - for (size_t i = 0; i < view->v.obj.len; i++) { - ScrDynEntry *entry = &view->v.obj.entries[i]; +/* The integrity state `b` on the entries of `table`: a view, or the table + * of its symbol-keyed properties. */ +static void scr_dyn_class_table_attributes(ScrDyn *table, unsigned b) { + table->non_extensible = true; + for (size_t i = 0; i < table->v.obj.len; i++) { + ScrDynEntry *entry = &table->v.obj.entries[i]; if (b & (SCR_CLASS_SEALED | SCR_CLASS_FROZEN)) entry->configurable = false; if ((b & SCR_CLASS_FROZEN) && !entry->accessor) entry->writable = false; } } +void scr_dyn_class_view_attributes(ScrDyn *view, double bits) { + unsigned b = (unsigned)bits; + if (b == 0 || view->kind != SCR_DYN_OBJ) return; + scr_dyn_class_table_attributes(view, b); + /* Symbol-keyed fields, and symbol-keyed properties added to the + * instance, take the same state. */ + if (view->symbol_properties && view->symbol_properties->kind == SCR_DYN_OBJ) + scr_dyn_class_table_attributes(view->symbol_properties, b); +} + /* Object.defineProperty on a declared class field. The descriptor applies to * a one-property object holding the field's current value and attributes, * so validation and errors match ordinary objects. Answers that object (+1), diff --git a/tests/corpus/7407-frozen-class-instances.ts b/tests/corpus/7407-frozen-class-instances.ts index 0732b8c35..6a3a14c54 100644 --- a/tests/corpus/7407-frozen-class-instances.ts +++ b/tests/corpus/7407-frozen-class-instances.ts @@ -136,8 +136,46 @@ function added(): void { console.log((p as any).extra, JSON.stringify(p)); } +const tag = Symbol("tag"); + +class Tagged { + [tag] = 1; + name = "n"; + bump(): void { + this[tag] += 1; + } +} + +class Subtagged extends Tagged { + extra = 0; +} + +function symbols(): void { + const t = new Tagged(); + freezeUnknown(t); + console.log(integrity(t), Object.getOwnPropertyDescriptor(t, tag)?.writable); + try { t[tag] = 5; } catch (e) { report(e); } + try { t.bump(); } catch (e) { report(e); } + console.log(t[tag]); + + const s = new Subtagged(); + sealUnknown(s); + s[tag] = 3; + console.log(integrity(s), s[tag], Object.getOwnPropertyDescriptor(s, tag)?.configurable); + freezeUnknown(s); + try { s[tag] = 4; } catch (e) { report(e); } + console.log(integrity(s), s[tag]); + + const u = new Tagged(); + Object.freeze(u); + console.log(integrity(u)); + try { u[tag] = 9; } catch (e) { report(e); } + console.log(u[tag]); +} + frozen(); sealed(); notExtensible(); untouched(); added(); +symbols(); From 03e677a9c4d2d6af3ff71f30451ca94c5b5103b4 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 03:14:24 -0500 Subject: [PATCH 073/259] Inherit the base constructor after a prototype's constructor is deleted A constructor read on a class instance through an untyped value answered the class itself whenever the class's prototype object did not hold an own `constructor`. After `delete Object.getPrototypeOf(new Middle()).constructor`, Node reads the property the base class's prototype holds, and past the last class's prototype Object.prototype's. The read now checks the instance's own property, then walks the class's prototypes: each answers its own `constructor`; a prototype without one answers its class unless reflection had populated it, in which case the program deleted the property and the read continues to the base class's prototype, and from the last one to Object.prototype. Reflection sets a per-class flag when the prototype initializes, so the answer does not depend on whether the reflection was compiled before the read. Corpus 8260 gains the deletion case. --- .../lowering/class-dynamic-dispatch.ts | 128 +++++++++--------- .../src/frontend/lowering/class-prototypes.ts | 23 ++++ .../src/frontend/lowering/lower-classes.ts | 4 + tests/corpus/8260-class-prototype-views.mjs | 21 +++ 4 files changed, 111 insertions(+), 65 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts index d658fb20a..68e755592 100644 --- a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts +++ b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts @@ -52,6 +52,7 @@ import { import { classPrototypeData, hasClassPrototypeData, + prototypeReflectedFlag, observedPrototypeMethod, reflectClassPrototype, } from "./class-prototypes.js"; @@ -4105,34 +4106,13 @@ export class ClassDynamicDispatch { return { kind: "call", callee: name, args: [bag, key], type: BOOL, loc }; } - /** `%dyn.class.bagHasOwn[OrPrototype]`: whether an instance's property bag - * holds `key` as its own property, or, with `prototype`, whether the bag's - * prototype object does. False before the instance has a bag. */ - private readBagHasOwn( - lowerer: Lowerer, - bag: IrExpr, - key: IrExpr, - prototype: boolean, - loc: SrcLoc, - ): IrExpr { - const name = prototype ? "%dyn.class.bagHasOwnOrPrototype" : "%dyn.class.bagHasOwn"; + /** `%dyn.class.bagHasOwn`: whether an instance's property bag holds `key` + * as its own property. False before the instance has a bag. */ + private readBagHasOwn(lowerer: Lowerer, bag: IrExpr, key: IrExpr, loc: SrcLoc): IrExpr { + const name = "%dyn.class.bagHasOwn"; let helper = lowerer.liftedFnNamed(name); if (!helper) { const value = varRef("p.0", DYN, loc); - const keyRef = varRef("p.1", STRING, loc); - const proto = varRef("proto", DYN, loc); - const hasOwn = (target: IrExpr): IrExpr => ({ - kind: "libCall", - fn: "dyn.hasOwn", - args: [target, keyRef], - type: BOOL, - loc, - }); - const returnFalse: IrStmt = { - kind: "return", - value: { kind: "boolLit", value: false, type: BOOL, loc }, - loc, - }; helper = { name, params: [ @@ -4143,47 +4123,28 @@ export class ClassDynamicDispatch { locals: [ { id: "p.0", name: "bag", type: DYN, mutable: false }, { id: "p.1", name: "key", type: STRING, mutable: false }, - ...(prototype ? [{ id: "proto", name: "proto", type: DYN, mutable: false }] : []), ], body: [ { kind: "if", cond: { kind: "dynTest", test: "undefined", value, type: BOOL, loc }, - then: [returnFalse], + then: [ + { kind: "return", value: { kind: "boolLit", value: false, type: BOOL, loc }, loc }, + ], else_: null, loc, }, - ...(prototype - ? ([ - { - kind: "if", - cond: hasOwn(value), - then: [ - { - kind: "return", - value: { kind: "boolLit", value: true, type: BOOL, loc }, - loc, - }, - ], - else_: null, - loc, - }, - { - kind: "varDecl", - localId: "proto", - init: { kind: "libCall", fn: "dyn.getPrototype", args: [value], type: DYN, loc }, - loc, - }, - { - kind: "if", - cond: { kind: "dynTest", test: "nullish", value: proto, type: BOOL, loc }, - then: [returnFalse], - else_: null, - loc, - }, - { kind: "return", value: hasOwn(proto), loc }, - ] satisfies IrStmt[]) - : [{ kind: "return", value: hasOwn(value), loc } satisfies IrStmt]), + { + kind: "return", + value: { + kind: "libCall", + fn: "dyn.hasOwn", + args: [value, varRef("p.1", STRING, loc)], + type: BOOL, + loc, + }, + loc, + }, ], loc, }; @@ -4193,6 +4154,45 @@ export class ClassDynamicDispatch { return { kind: "call", callee: name, args: [bag, key], type: BOOL, loc }; } + /** The `constructor` an instance of `info` inherits when it has no own + * one. The class's prototype view answers its own `constructor` (a + * replacement, or the class once reflection installed it). A view + * without one answers the class itself unless reflection had populated it + * (prototypeReflectedFlag, set when the view initializes): then the + * program deleted the property, and the read continues to the base + * class's prototype and past the last one to Object.prototype, as in + * Node. */ + private inheritedConstructor( + lowerer: Lowerer, + info: ClassInfo, + key: IrExpr, + loc: SrcLoc, + ): IrExpr { + const cls = lowerer.coerceToExpected(classValueRef(lowerer, info, info.decl!), DYN); + const prototype = hasClassPrototypeData(info) ? classPrototypeData(lowerer, info, loc) : null; + if (!prototype) return cls; + const base = info.base; + const next: IrExpr = + base && !base.builtinError && base.decl && !base.generic && !base.localClass + ? this.inheritedConstructor(lowerer, base, key, loc) + : { kind: "dynKeyGet", value: prototype, key, type: DYN, loc }; + return { + kind: "ternary", + cond: { kind: "libCall", fn: "dyn.hasOwn", args: [prototype, key], type: BOOL, loc }, + then: { kind: "dynKeyGet", value: prototype, key, type: DYN, loc }, + else_: { + kind: "ternary", + cond: varRef(prototypeReflectedFlag(lowerer, info), BOOL, loc), + then: next, + else_: cls, + type: DYN, + loc, + }, + type: DYN, + loc, + }; + } + /** The hints for which some boxed class declares a conversion method. A * string conversion calls toString first, so without a declared toString * or Symbol.toPrimitive it answers Object.prototype.toString's @@ -5951,15 +5951,13 @@ export class ClassDynamicDispatch { !info.classDecorators ) { this.constructors.set(info.def.name, info); - const cls = lowerer.coerceToExpected(classValueRef(lowerer, info, info.decl), DYN); const bag = this.branchPropertyBag(lowerer, info, receiver, false, loc); const key: IrExpr = { kind: "strLit", value: name, type: STRING, loc }; // `constructor` is an own property of every class prototype, so an - // ancestor's prototype never answers for an instance of this class: - // the instance's own property answers, then one this class's - // prototype object defines (a reflected prototype, or a write to - // `C.prototype.constructor`), and otherwise the class itself. - const answered = this.readBagHasOwn(lowerer, bag, key, hasClassPrototypeData(info), loc); + // ancestor's prototype answers for an instance of this class only + // after the program deletes the class's own: the instance's own + // property answers, then the class's prototype (inheritedConstructor). + const answered = this.readBagHasOwn(lowerer, bag, key, loc); return [ { kind: "return", @@ -5973,7 +5971,7 @@ export class ClassDynamicDispatch { type: DYN, loc, }, - else_: cls, + else_: this.inheritedConstructor(lowerer, info, key, loc), type: DYN, loc, }, diff --git a/packages/compiler/src/frontend/lowering/class-prototypes.ts b/packages/compiler/src/frontend/lowering/class-prototypes.ts index 595b64e05..d005e64d1 100644 --- a/packages/compiler/src/frontend/lowering/class-prototypes.ts +++ b/packages/compiler/src/frontend/lowering/class-prototypes.ts @@ -299,6 +299,23 @@ function declaresPrototypeMembers(decl: ts.ClassLikeDeclaration): boolean { ); } +/** The global that is true once the class's prototype view has been + * populated by reflection (reflectClassPrototype): the view then holds an + * own `constructor` unless the program deleted it. A view that was never + * reflected leaves `constructor` implicit. */ +export function prototypeReflectedFlag(lowerer: Lowerer, info: ClassInfo): string { + if (info.prototypeReflectedFlag) return info.prototypeReflectedFlag; + const id = `%g.%prototype.data.${info.def.name}.reflected`; + lowerer.globalsList.push({ + id, + name: `${info.def.jsName ?? info.def.name}.prototype.reflected`, + type: BOOL, + mutable: true, + }); + info.prototypeReflectedFlag = id; + return id; +} + /** Populate the shared prototype view before exposing it to reflection. * Methods and accessors are non-enumerable and retain declaration identity. */ export function reflectClassPrototype( @@ -399,6 +416,12 @@ export function reflectClassPrototype( { key: "value", value: classValueRef(lowerer, info, info.decl) }, writable, ]), + { + kind: "assign", + localId: prototypeReflectedFlag(lowerer, info), + value: { kind: "boolLit", value: true, type: BOOL, loc }, + loc, + }, ); const context = newFnCtx(false, null, null, DYN); lowerer.fnStack.push(context); diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index ac1864051..2394b728b 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -481,6 +481,10 @@ export interface ClassInfo { localPrototypeData?: true; prototypeMethodValues?: Map; prototypeReflectionReady?: true; + /** The global that records at run time that the prototype view was + * populated by reflection, so it holds its own `constructor` until the + * program deletes it (prototypeReflectedFlag). */ + prototypeReflectedFlag?: string; prototypeObservedMethodsReady?: true; /** The globals holding each observed method's original prototype value * (set when the prototype data is built), by method name. A typed call diff --git a/tests/corpus/8260-class-prototype-views.mjs b/tests/corpus/8260-class-prototype-views.mjs index e08b8f206..35e55f5f4 100644 --- a/tests/corpus/8260-class-prototype-views.mjs +++ b/tests/corpus/8260-class-prototype-views.mjs @@ -132,3 +132,24 @@ const areaValue = Shape.prototype.area; const disc = new Disc("d"); const rebuilt = disc.rebuild(); console.log(disc.constructor === Disc, rebuilt instanceof Disc, rebuilt.area(), rebuilt.name, typeof areaValue); + +// Deleting a reflected prototype's constructor: instances read the +// constructor their base class's prototype holds, then Object's; a +// replacement answers again. +class Root { + hi() { + return "hi"; + } +} +class Middle extends Root {} +class Tip extends Middle {} +const members = [new Middle(), new Tip(), new Root(), {}]; +const constructorNames = () => members.map((member) => member.constructor.name).join(","); +console.log(constructorNames(), Object.getOwnPropertyNames(Object.getPrototypeOf(new Middle())).join("|")); +delete Object.getPrototypeOf(new Middle()).constructor; +console.log(constructorNames(), Object.getOwnPropertyNames(Object.getPrototypeOf(new Middle())).join("|")); +console.log(new Middle().constructor === Root, new Tip().constructor === Tip); +delete Object.getPrototypeOf(new Root()).constructor; +console.log(constructorNames(), new Middle().constructor === Object); +Middle.prototype.constructor = function Named() {}; +console.log(constructorNames()); From 949c715f7bc52771d1f3978a721a20371ff88c3c Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 03:27:00 -0500 Subject: [PATCH 074/259] Keep comparator sorts and untyped-source copies out of units loops A units copy reads the receiver's UTF-16 units through the pointer its guard took, which stays valid only while nothing indexes another non-ASCII string: that evicts the receiver's index entry and frees the units. The classifier admitted every typed-array and Buffer method, so a loop that sorted a typed array with a comparator function value, or copied an untyped source into one (`ta.set(source)`, whose element reads can run getters), got a units copy, and a comparator or getter that indexed other strings made the loop read freed memory. The units copy now admits only the typed-array and Buffer methods that call no program code and read no checked-dynamic value or string. Corpus 7307 sorts with such a comparator and copies from such a source inside scans of a warmed non-ASCII text; the sanitized build of the previous commit reports a heap-use-after-free on it. --- .../backend/llvm/string-unit-versions.test.ts | 40 ++++++++++ .../src/backend/llvm/string-unit-versions.ts | 66 ++++++++++++++++- .../7307-string-unit-loop-evictions.ts.json | 6 ++ .../corpus/7307-string-unit-loop-evictions.ts | 73 +++++++++++++++++++ .../7307-string-unit-loop-evictions.ts.json | 1 + 5 files changed, 185 insertions(+), 1 deletion(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7307-string-unit-loop-evictions.ts.json create mode 100644 tests/corpus/7307-string-unit-loop-evictions.ts create mode 100644 tests/harness/corpus-costs/7307-string-unit-loop-evictions.ts.json diff --git a/packages/compiler/src/backend/llvm/string-unit-versions.test.ts b/packages/compiler/src/backend/llvm/string-unit-versions.test.ts index 5b0634b1a..e21803948 100644 --- a/packages/compiler/src/backend/llvm/string-unit-versions.test.ts +++ b/packages/compiler/src/backend/llvm/string-unit-versions.test.ts @@ -84,3 +84,43 @@ console.log(words("ab c"), pairs("ab", "cd"), both("ab", "cd"), concatenates("a expect(unitSafeLoop(loopOf(mod, "both"), param("both"), safe)).toBeNull(); expect(unitSafeLoop(loopOf(mod, "concatenates"), param("concatenates"), safe)).toBeNull(); }); + +test("loops that sort with a comparator or copy an untyped source get no units copy", async () => { + // Either can run program code that indexes other strings, which evicts + // the receiver's units while the loop reads them. + const mod = await lower(` +function sorts(s: string, values: Float64Array, compare: (a: number, b: number) => number): number { + let n = 0; + for (let i = 0; i < s.length; i++) { + n += s.charCodeAt(i); + if (i === 3) values.sort(compare); + } + return n; +} +function copies(s: string, values: Float64Array, source: any): number { + let n = 0; + for (let i = 0; i < s.length; i++) { + n += s.charCodeAt(i); + if (i === 3) values.set(source); + } + return n; +} +function sortsNumbers(s: string, values: Float64Array): number { + let n = 0; + for (let i = 0; i < s.length; i++) { + n += s.charCodeAt(i); + if (i === 3) values.sort(); + } + return n; +} +const values = new Float64Array([2, 1]); +console.log(sorts("abcdef", values, (a, b) => a - b), copies("abcdef", values, [4, 3]), sortsNumbers("abcdef", values)); +`); + const safe = unitSafeFunctions(mod); + const param = (fn: string): string => + mod.functions.find((f) => f.name === fn)!.params[0]!.localId; + expect(unitSafeLoop(loopOf(mod, "sorts"), param("sorts"), safe)).toBeNull(); + expect(unitSafeLoop(loopOf(mod, "copies"), param("copies"), safe)).toBeNull(); + // A numeric sort calls no program code. + expect(unitSafeLoop(loopOf(mod, "sortsNumbers"), param("sortsNumbers"), safe)).not.toBeNull(); +}); diff --git a/packages/compiler/src/backend/llvm/string-unit-versions.ts b/packages/compiler/src/backend/llvm/string-unit-versions.ts index 022c3a513..368b8eae8 100644 --- a/packages/compiler/src/backend/llvm/string-unit-versions.ts +++ b/packages/compiler/src/backend/llvm/string-unit-versions.ts @@ -1,4 +1,4 @@ -import type { IrExpr, IrModule, IrStmt } from "../../ir/ir.js"; +import type { IrBytesIntrinsicMethod, IrExpr, IrModule, IrStmt } from "../../ir/ir.js"; import { everyExprChild, everyStmtChild } from "../../ir/traverse.js"; /* Loop versions over the UTF-16 units of a string that is not ASCII. @@ -15,6 +15,68 @@ import { everyExprChild, everyStmtChild } from "../../ir/traverse.js"; const ARRAY_METHODS = new Set(["push", "pop", "length"]); +/* The typed-array and Buffer methods a units copy may run: those that + * call no program code and read no checked-dynamic value or string. A + * comparator sort (sortCompare) calls back into the program, and a copy + * from a checked-dynamic source (setFromDyn) reads its elements through + * getters; either can index another string, which evicts the receiver's + * units while the loop reads them. */ +const UNIT_SAFE_BYTES_METHODS: ReadonlySet = new Set([ + "buffer", + "length", + "byteLength", + "byteOffset", + "get", + "slice", + "subarray", + "copyWithin", + "sortNumeric", + "toReversed", + "with", + "toArray", + "setFrom", + "readNum", + "writeNum", + "readNumVar", + "writeNumVar", + "equals", + "compareBuf", + "indexOfNum", + "lastIndexOfNum", + "includesNum", + "indexOfElem", + "lastIndexOfElem", + "includesElem", + "fill", + "fillNum", + "fillElem", + "copy", + "swap16", + "swap32", + "swap64", + "dataViewNew", + "dvGetUint8", + "dvGetInt8", + "dvGetUint16", + "dvGetInt16", + "dvGetUint32", + "dvGetInt32", + "dvGetFloat16", + "dvGetFloat32", + "dvGetFloat64", + "dvGetBigUint64Number", + "dvGetBigInt64Number", + "dvSetUint8", + "dvSetInt8", + "dvSetUint16", + "dvSetInt16", + "dvSetUint32", + "dvSetInt32", + "dvSetFloat16", + "dvSetFloat32", + "dvSetFloat64", +]); + /** Whether `e` (or statement `s`) uses only operations that index no * string: numbers, booleans, locals, records and class fields, typed * arrays, number arrays and Math. `reads` admits the string reads a @@ -39,7 +101,9 @@ function unitSafe( case "incDec": case "recordGet": case "fieldGet": + break; case "bytesIntrinsic": + if (!UNIT_SAFE_BYTES_METHODS.has(e.method)) return false; break; case "arrayGet": if (e.type.kind !== "f64" && e.type.kind !== "bool") return false; diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7307-string-unit-loop-evictions.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7307-string-unit-loop-evictions.ts.json new file mode 100644 index 000000000..cb5864986 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7307-string-unit-loop-evictions.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7307-string-unit-loop-evictions.ts" + ], + "diags": [] +} diff --git a/tests/corpus/7307-string-unit-loop-evictions.ts b/tests/corpus/7307-string-unit-loop-evictions.ts new file mode 100644 index 000000000..94e98e5b4 --- /dev/null +++ b/tests/corpus/7307-string-unit-loop-evictions.ts @@ -0,0 +1,73 @@ +// A units copy must not run program code that indexes other strings: a +// comparator sort or a copy from an untyped source can evict the scanned +// text's UTF-16 units while the loop reads them. + +function bigText(seed: number): string { + let s = ""; + for (let i = 0; i < 9000; i++) s += String.fromCharCode(0xe9 + ((i * seed) % 7)) + "ab "; + return s; +} + +const others = [bigText(3), bigText(5), bigText(11), bigText(13), bigText(17)]; + +let touched = 0; +function touchOthers(): void { + for (let k = 0; k < others.length; k++) { + const o = others[k]; + for (let j = 0; j < 80; j++) touched += o.charCodeAt((j * 997 + k) % o.length); + } +} + +function spaces(s: string): number { + let n = 0; + for (let i = 0; i < s.length; i++) if (s.charCodeAt(i) === 32) n++; + return n; +} + +function sortedWhileScanning( + s: string, + values: Float64Array, + compare: (a: number, b: number) => number, +): number { + let sum = 0; + for (let i = 0; i < s.length; i++) { + sum += s.charCodeAt(i); + if (i % 4096 === 100) values.sort(compare); + } + return sum; +} + +function copiedWhileScanning(s: string, values: Float64Array, source: any): number { + let sum = 0; + for (let i = 0; i < s.length; i++) { + sum += s.charCodeAt(i); + if (i % 4096 === 100) values.set(source); + } + return sum; +} + +const text = bigText(7); +// Repeated scans make the runtime hold the text's units. +let warm = 0; +for (let r = 0; r < 4; r++) warm += spaces(text); +console.log("warm", warm); + +const values = new Float64Array([3, 1, 2]); +const byValue = (a: number, b: number): number => { + touchOthers(); + return a - b; +}; +console.log("sorted", sortedWhileScanning(text, values, byValue), values.join(",")); +for (let r = 0; r < 2; r++) warm += spaces(text); + +const source: any = { + length: 3, + get 0() { + touchOthers(); + return 9; + }, + 1: 8, + 2: 7, +}; +console.log("copied", copiedWhileScanning(text, values, source), values.join(",")); +console.log("touched", touched > 0, spaces(text)); diff --git a/tests/harness/corpus-costs/7307-string-unit-loop-evictions.ts.json b/tests/harness/corpus-costs/7307-string-unit-loop-evictions.ts.json new file mode 100644 index 000000000..bb380e241 --- /dev/null +++ b/tests/harness/corpus-costs/7307-string-unit-loop-evictions.ts.json @@ -0,0 +1 @@ +{ "plain": 2500, "san": 3000 } From 4581dd2f123d917ddba44829c0699441acbe8047 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 04:05:54 -0500 Subject: [PATCH 075/259] Keep a Date boxed when a toJSON argument calls its setter A Date local kept as its time value was read as toJSON's receiver before the arguments ran, so a setter in an argument (d.toJSON(d.setTime(0))) did not change the result. Such a local now keeps its Date object, and toJSON reads it after its arguments, as in Node. --- .../src/frontend/lowering/date-values.ts | 6 +++++- tests/corpus/8027-date-setter-order.ts | 17 +++++++++++++++-- 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/date-values.ts b/packages/compiler/src/frontend/lowering/date-values.ts index f769e0866..8931d0f80 100644 --- a/packages/compiler/src/frontend/lowering/date-values.ts +++ b/packages/compiler/src/frontend/lowering/date-values.ts @@ -43,7 +43,8 @@ const RELATIONAL = new Set([ /** True when a local `const` (or a `let` that is never assigned again) * initialized with `new Date(...)` can keep the Date's time value instead * of a Date object: no use observes the Date's identity. Every use reads - * the time value as a Date method receiver (a setter replaces it), a + * the time value as a Date method receiver (a setter replaces it; the + * arguments of a method that reads it call no setter on it), a * String(), Number() or template operand, a unary + or - operand, a * relational or string `+` operand, or `new Date(d)`'s argument, inside * the declaring function, or inside the block or loop that scopes a @@ -194,6 +195,9 @@ function timeValueUse( ) return null; if (isDateSetter(parent.name.text)) return "set"; + // The method reads the time value after its arguments are evaluated: + // a setter there (`d.toJSON(d.setTime(0))`) changes what it reads. + if (call.arguments.nodes.some((arg) => callsSetterOf(lowerer, arg, symbol))) return null; return TIME_VALUE_METHODS.has(parent.name.text) ? "read" : null; } return readsTimeValue(lowerer, node, parent, symbol) ? "read" : null; diff --git a/tests/corpus/8027-date-setter-order.ts b/tests/corpus/8027-date-setter-order.ts index d0a175c2f..b87f3a656 100644 --- a/tests/corpus/8027-date-setter-order.ts +++ b/tests/corpus/8027-date-setter-order.ts @@ -1,7 +1,8 @@ // Date setters and evaluation order: a setter called without arguments // makes the Date invalid, an argument that calls setTime on the same -// Date subclass instance is seen by the setter, and a comparison or -// concatenation reads its left Date after the right side runs a setter. +// Date subclass instance is seen by the setter, a comparison or +// concatenation reads its left Date after the right side runs a setter, +// and toJSON reads its Date after an argument runs a setter. export {}; process.env.TZ = "UTC"; @@ -51,3 +52,15 @@ const s = new Date(Date.UTC(2026, 0, 1)); console.log(s + (s.setUTCFullYear(1999), "!")); const n = new Date(Date.UTC(2026, 0, 1)); console.log(+n === (n.setTime(5), 5), +n); + +// Locals a function keeps as their time value: a method reads the time +// value after its arguments run a setter. +function locals(): void { + const json = new Date(Date.UTC(2026, 0, 1)); + console.log(json.toJSON(json.setUTCFullYear(1999)), json.toJSON()); + const key = new Date(Date.UTC(2026, 0, 1)); + console.log(key.toJSON(String(key.setTime(Date.UTC(2021, 5, 1))))); + const read = new Date(Date.UTC(2026, 0, 1)); + console.log(read.toJSON(), read.getTime()); +} +locals(); From c652e418f64ceffdd7782f20406ec4c147d26153 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 04:10:52 -0500 Subject: [PATCH 076/259] Read the discriminant again after an arm's check fails An arm's field check can run a getter that changes the discriminant. The checked cast now reads the discriminant again after each failed arm; when its case changed, the tests continue arm by arm after the failed arm, so the cast picks the arm the arm-by-arm tests pick. --- packages/compiler/src/backend/llvm/dyn.ts | 79 ++++++++++++------- .../6306-discriminant-getter-dispatch.ts.json | 6 ++ .../6306-discriminant-getter-dispatch.ts | 55 +++++++++++++ .../6306-discriminant-getter-dispatch.ts.json | 1 + tests/harness/dyncheck.test.ts | 41 ++++++++++ 5 files changed, 154 insertions(+), 28 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6306-discriminant-getter-dispatch.ts.json create mode 100644 tests/corpus/6306-discriminant-getter-dispatch.ts create mode 100644 tests/harness/corpus-costs/6306-discriminant-getter-dispatch.ts.json diff --git a/packages/compiler/src/backend/llvm/dyn.ts b/packages/compiler/src/backend/llvm/dyn.ts index 3d7533f22..218d316dc 100644 --- a/packages/compiler/src/backend/llvm/dyn.ts +++ b/packages/compiler/src/backend/llvm/dyn.ts @@ -440,8 +440,12 @@ export class LlDyn { * discriminant is read once (scr_dyn_discriminant_case, against the * constant `table`), and only the arms whose literal it holds and the arms * without a literal are tested, in `order`: every other arm's literal test - * fails. A value the runtime cannot classify that way (a typed capsule, an - * accessor, an inherited discriminant) takes the tests arm by arm. */ + * fails. An arm's failed check can run a getter that changes the + * discriminant, so it is read again after each one; when its case + * changed, the tests continue arm by arm after the failed arm, as they + * would have run from the first arm. A value the runtime cannot classify + * that way (a typed capsule, an accessor, an inherited discriminant) takes + * the tests arm by arm. */ private unionArmsByDiscriminant( B: BlockBuilder, def: IrUnionDef, @@ -455,47 +459,66 @@ export class LlDyn { const discriminant = def.discriminant!; const literalsOf = (tag: number): readonly (string | number | boolean)[] | null => discriminant.cases.find((candidate) => candidate.tag === tag)?.values ?? null; - const tryArms = (tags: readonly number[], literal: boolean): void => { - if (tags.length === 0) { - B.br(none); - return; - } - tags.forEach((tag, index) => { - const next = index === tags.length - 1 ? none : B.newLabel("du.c.n"); - if (literal) this.unionArmMatch(B, def, tag, hits[tag]!, next, preserveRefs); - else this.unionArmStructure(B, def, tag, hits[tag]!, next, preserveRefs); - if (next !== none) B.startBlock(next); - }); - }; - const armsFor = (value: string | null): number[] => - order.filter((tag) => { - const literals = literalsOf(tag); - return literals === null || (value !== null && literals.includes(value)); - }); const host = this.host; this.defs.push( `${table} = private unnamed_addr constant [${values.length} x ptr] [${values.map((value) => `ptr ${host.internLiteral(value)}`).join(", ")}]`, ``, ); host.declare(`declare i32 @scr_dyn_discriminant_case(ptr, ptr, ptr, ${host.sizeType})`); - const index = B.tmp(); - B.line( - `${index} = call i32 @scr_dyn_discriminant_case(ptr %d, ptr ${host.internLiteral(discriminant.field)}, ptr ${table}, ${host.sizeType} ${values.length})`, - ); + const classify = (): string => { + const index = B.tmp(); + B.line( + `${index} = call i32 @scr_dyn_discriminant_case(ptr %d, ptr ${host.internLiteral(discriminant.field)}, ptr ${table}, ${host.sizeType} ${values.length})`, + ); + return index; + }; + // The arm-by-arm tests, entered at any arm (`from[i]` tests order[i] + // and the arms after it). const tests = B.newLabel("du.tests"); + const from = order.map((_, i) => (i === 0 ? tests : B.newLabel("du.t"))); + const after = (position: number): string => + position + 1 < order.length ? from[position + 1]! : none; + // Tests the arms a value in case `k` (-1: no literal) can match. + const tryCase = (k: number): void => { + const value = k < 0 ? null : values[k]!; + const positions = order + .map((_, position) => position) + .filter((position) => { + const literals = literalsOf(order[position]!); + return literals === null || (value !== null && literals.includes(value)); + }); + if (positions.length === 0) { + B.br(none); + return; + } + positions.forEach((position, index) => { + const tag = order[position]!; + const failed = B.newLabel("du.c.f"); + this.unionArmStructure(B, def, tag, hits[tag]!, failed, preserveRefs); + B.startBlock(failed); + const next = index === positions.length - 1 ? none : B.newLabel("du.c.n"); + const same = B.tmp(); + B.line(`${same} = icmp eq i32 ${classify()}, ${k}`); + B.condBr(same, next, after(position)); + if (next !== none) B.startBlock(next); + }); + }; + const index = classify(); const unmatched = B.newLabel("du.none"); const cases = values.map(() => B.newLabel("du.case")); B.terminate( `switch i32 ${index}, label %${tests} [ i32 -1, label %${unmatched} ${cases.map((label, k) => `i32 ${k}, label %${label}`).join(" ")} ]`, ); - values.forEach((value, k) => { + values.forEach((_, k) => { B.startBlock(cases[k]!); - tryArms(armsFor(value), false); + tryCase(k); }); B.startBlock(unmatched); - tryArms(armsFor(null), false); - B.startBlock(tests); - tryArms(order, true); + tryCase(-1); + order.forEach((tag, position) => { + B.startBlock(from[position]!); + this.unionArmMatch(B, def, tag, hits[tag]!, after(position), preserveRefs); + }); } /** Branch to a variant only after its literal discriminator and complete diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6306-discriminant-getter-dispatch.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6306-discriminant-getter-dispatch.ts.json new file mode 100644 index 000000000..ba7cba509 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6306-discriminant-getter-dispatch.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6306-discriminant-getter-dispatch.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6306-discriminant-getter-dispatch.ts b/tests/corpus/6306-discriminant-getter-dispatch.ts new file mode 100644 index 000000000..4f0a1244f --- /dev/null +++ b/tests/corpus/6306-discriminant-getter-dispatch.ts @@ -0,0 +1,55 @@ +// A checked cast into a union with many string discriminant literals reads +// the discriminant once, but a getter that runs while an arm's fields are +// checked can change it. The cast then continues with the arms after the +// one that failed, testing each arm's literal again, and matches the arm +// the new discriminant names. Each getter changes the discriminant on its +// first call only; the program reads the getter once itself, so Node (where +// the cast runs no code) reaches the same state. Valid casts only (see +// 1002-json-parse-cast.ts). + +type Shape = + | { kind: "circle"; radius: number } + | { kind: "square"; side: number } + | { kind: "rect"; height: number; width: number } + | { kind: "tri"; a: number; b: number; c: number }; + +function area(shape: Shape): number { + switch (shape.kind) { + case "circle": + return Math.round(Math.PI * shape.radius * shape.radius); + case "square": + return shape.side * shape.side; + case "rect": + return shape.width * shape.height; + case "tri": { + const s = (shape.a + shape.b + shape.c) / 2; + return Math.sqrt(s * (s - shape.a) * (s - shape.b) * (s - shape.c)); + } + } +} + +// The circle arm reads `radius`, whose getter turns the value into a square. +let squareReads = 0; +const square: any = { + kind: "circle", + get radius() { + squareReads++; + if (squareReads === 1) square.kind = "square"; + return "none"; + }, + side: 3, +}; +const asSquare = square as Shape; +void square.radius; +console.log(square.kind, asSquare.kind, area(asSquare)); + +// Values without getters take the arm their discriminant names. +const plain: any[] = [ + { kind: "rect", width: 2, height: 5 }, + { kind: "tri", a: 3, b: 4, c: 5 }, + { kind: "circle", radius: 2 }, +]; +for (const value of plain) { + const shape = value as Shape; + console.log(shape.kind, area(shape)); +} diff --git a/tests/harness/corpus-costs/6306-discriminant-getter-dispatch.ts.json b/tests/harness/corpus-costs/6306-discriminant-getter-dispatch.ts.json new file mode 100644 index 000000000..2c49e2f02 --- /dev/null +++ b/tests/harness/corpus-costs/6306-discriminant-getter-dispatch.ts.json @@ -0,0 +1 @@ +{ "plain": 3800, "san": 4900 } diff --git a/tests/harness/dyncheck.test.ts b/tests/harness/dyncheck.test.ts index 5559be970..1ceabce53 100644 --- a/tests/harness/dyncheck.test.ts +++ b/tests/harness/dyncheck.test.ts @@ -444,6 +444,47 @@ for (const input of inputs) { ); }); + test("a getter that changes the discriminant during an arm's check continues with the later arms", async () => { + // Each getter sets `kind` and fails its arm's check: to a later arm's + // literal (that arm matches), to an earlier arm's literal (arm-by-arm + // tests do not go back), and to a literal no arm holds. + const r = await compileAndRun( + "union-discriminant-getter", + `type Shape = + | { kind: "circle"; radius: number } + | { kind: "square"; side: number } + | { kind: "rect"; height: number; width: number } + | { kind: "tri"; a: number; b: number; c: number }; +const flip = (value: any, to: string): string => { + value.kind = to; + return "none"; +}; +const later: any = { kind: "circle", get radius() { return flip(later, "square"); }, side: 3 }; +const earlier: any = { kind: "square", radius: 2, get side() { return flip(earlier, "circle"); } }; +const unknown: any = { kind: "square", get side() { return flip(unknown, "hexagon"); } }; +const inputs = [later, earlier, unknown]; +for (const input of inputs) { + try { + const shape = input as Shape; + console.log("matched", shape.kind); + } catch (error) { + console.log((error as Error).message); + } +} +`, + ); + const any = "object | object | object | object"; + expect(r.exitCode).toBe(0); + expect(r.stdout).toBe( + [ + "matched square", + `expected ${any} at $, got object`, + `expected ${any} at $, got object`, + "", + ].join("\n"), + ); + }); + test("nested paths point at the offending element", async () => { const r = await compileAndRun( "nested-path", From 1d1fccccd59249a22cabcb04bae88979879b7a06 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 05:56:14 -0500 Subject: [PATCH 077/259] Compare identical references and accept any message in the test262 adapter assert.sameValue, assert.notSameValue and assert.compareArray elements treat identical references as the same value and a reference as different from every primitive. Only two distinct references still refuse, because a conversion at the native boundary can copy a reference but never merge two. Assertion messages may be any value and convert with String, as in the upstream helpers. --- tests/harness/test262.test.ts | 57 +++++++++++++++++++++--- tests/test262/README.md | 2 +- tests/test262/harness.ts | 84 ++++++++++++++++++++--------------- 3 files changed, 101 insertions(+), 42 deletions(-) diff --git a/tests/harness/test262.test.ts b/tests/harness/test262.test.ts index f1b616578..fd35a08fb 100644 --- a/tests/harness/test262.test.ts +++ b/tests/harness/test262.test.ts @@ -237,6 +237,47 @@ assert.notSameValue(1, "1"); status: "fail", source: "assert.throws(TypeError, () => { throw 1; });", }, + { + name: "identical references", + status: "pass", + source: ` +const object = {}; +const list = [1]; +const fn = function () {}; +assert.sameValue(object, object); +assert.sameValue(list, list); +assert.sameValue(fn, fn); +assert.compareArray([object, fn], [object, fn]); +`, + }, + { + name: "a reference is not a primitive", + status: "pass", + source: + "assert.notSameValue({}, 1); assert.notSameValue([], undefined); assert.notSameValue(null, {});", + }, + { name: "reference and primitive mismatch", status: "fail", source: "assert.sameValue([], 0);" }, + { + name: "identical references are not different", + status: "fail", + source: "const object = {}; assert.notSameValue(object, object);", + }, + { + name: "array element reference and primitive mismatch", + status: "fail", + source: "assert.compareArray([{}], [1]);", + }, + { + name: "non-string messages", + status: "pass", + source: + "assert.sameValue(1, 1, false); assert.notSameValue(1, 2, 0); assert(true, null); assert.compareArray([], [], 1);", + }, + { + name: "failure with a non-string message", + status: "fail", + source: "assert.sameValue(1, 2, false);", + }, ]; describe(`Test262 host assertion contract${shardSuffix()}`, () => { @@ -259,8 +300,8 @@ describe(`Test262 host assertion contract${shardSuffix()}`, () => { ["{}", "[1]", "function () {}"], (value) => `reference:${value}`, )) { - test(`reference assertions are explicitly refused: ${value}`, async () => { - const source = `const value = ${value}; try { assert.sameValue(value, value); } catch { }`; + test(`distinct reference assertions are explicitly refused: ${value}`, async () => { + const source = `try { assert.sameValue(${value}, ${value}); } catch { } try { assert.notSameValue(${value}, ${value}); } catch { }`; expect(() => runUpstream(source)).not.toThrow(); const result = await runSource(source, { sanitize }); expect(result, JSON.stringify(result)).toMatchObject({ @@ -270,8 +311,8 @@ describe(`Test262 host assertion contract${shardSuffix()}`, () => { }); } - test("array element identity assertions are refused", async () => { - const source = "const value = {}; try { assert.compareArray([value], [value]); } catch { }"; + test("distinct array element references are refused", async () => { + const source = "try { assert.compareArray([{}], [{}]); } catch { }"; expect(() => runUpstream(source)).not.toThrow(); const result = await runSource(source, { sanitize }); expect(result, JSON.stringify(result)).toMatchObject({ @@ -359,9 +400,15 @@ const propertyControls = shardSelect( }, { name: "reference value", - status: "harness-refusal", + status: "pass", source: "const f = function() {}; const o = { a: f }; verifyProperty(o, 'a', { value: f });", }, + { + name: "distinct reference value", + status: "harness-refusal", + source: + "const o = { a: function() {} }; try { verifyProperty(o, 'a', { value: function() {} }); } catch { }", + }, ], (item) => `property:${item.name}`, ); diff --git a/tests/test262/README.md b/tests/test262/README.md index 2f8a0ed3e..5474fa2c3 100644 --- a/tests/test262/README.md +++ b/tests/test262/README.md @@ -32,7 +32,7 @@ The current profile is `static-adapted-v6`. It adapts strict scripts to standalo The unmodified upstream assertion helper currently reaches scriptc's JavaScript function-expando refusal. Test262 explicitly permits host implementations of harness functions in its [interpretation rules](https://github.com/tc39/test262/blob/7ab7fafa0003f73fc85c1b95d88094d33f7eb8bd/INTERPRETING.md#host-defined-functions). `harness.ts` supplies `assert`, `assert.sameValue`, `assert.notSameValue`, `assert.compareArray`, `assert.throws` for selected Error constructors, `$DONE`, and `Test262Error`. Scalar SameValue and scalar array-element comparisons use the statically compiled `node:assert/strict` implementation. Contract tests compare successful and failing assertions with the original Test262 helpers under Node, including NaN, signed zero, null/undefined, differing primitive types, and premature termination. -Reference-equality assertions terminate with a distinct harness-refusal result: conversion at a native function boundary can copy references, so this adapter cannot faithfully compare every object, array, or function identity. Tests cannot catch this refusal and accidentally pass. Sparse array comparisons are not yet handled faithfully across that boundary. The adapted `propertyHelper.js` admits direct `verifyProperty` calls with an inline descriptor literal or `undefined`; reference-valued comparisons still refuse, while other property helpers and descriptor expressions remain excluded. The adapted `testTypedArray.js` keeps the upstream constructor lists, argument factories and `testWith*` helpers. It omits the `TypedArray` (%TypedArray%) binding, so tests that name it are excluded. Its resizable and immutable buffer factories run only where `ArrayBuffer.prototype` provides `resize` and `transferToImmutable`, as the upstream feature checks intend. Contract tests compare its successful and failing uses with the upstream helper under Node. Assertion aliases, mutation, reflection, additional assertion methods, and other `includes` helpers remain excluded. +Conversion at a native function boundary can copy references, so one object, array, or function may reach the adapter as two distinct references. A copy cannot merge two references into one. `assert.sameValue`, `assert.notSameValue`, and `assert.compareArray` elements therefore treat identical references as the same value and a reference as different from every primitive. Two distinct references terminate with a distinct harness-refusal result, which tests cannot catch and turn into a pass. Assertion messages may be any value; the adapter converts them with `String`, as the upstream helpers do. Sparse array comparisons are not yet handled faithfully across that boundary. The adapted `propertyHelper.js` admits direct `verifyProperty` calls with an inline descriptor literal or `undefined`; reference-valued comparisons follow the same identity rule, while other property helpers and descriptor expressions remain excluded. The adapted `testTypedArray.js` keeps the upstream constructor lists, argument factories and `testWith*` helpers. It omits the `TypedArray` (%TypedArray%) binding, so tests that name it are excluded. Its resizable and immutable buffer factories run only where `ArrayBuffer.prototype` provides `resize` and `transferToImmutable`, as the upstream feature checks intend. Contract tests compare its successful and failing uses with the upstream helper under Node. Assertion aliases, mutation, reflection, additional assertion methods, and other `includes` helpers remain excluded. Raw tests, module variants, agents, resolution negatives, and runtime negatives remain excluded. Parse negatives pass only when a source-matched syntax or vetted JavaScript early-error diagnostic appears; TypeScript type errors and harness-only failures never satisfy a negative expectation. `$262`, dynamic evaluation, observable script-global state, and other unsupported host requirements are excluded as well. The runtime and compiler continue to enforce their existing refusal boundaries for admitted source. diff --git a/tests/test262/harness.ts b/tests/test262/harness.ts index c44d32869..b478b4555 100644 --- a/tests/test262/harness.ts +++ b/tests/test262/harness.ts @@ -17,68 +17,80 @@ export function $DONE(error?: unknown): void { console.log("__scriptc_test262_complete__"); } -function scalar(value: unknown): void { - // Native-to-unknown conversion can copy references (notably arrays). - // Refuse these assertions before comparing altered identities. Terminate +function reference(value: unknown): boolean { + return (typeof value === "object" && value !== null) || typeof value === "function"; +} + +function refuse(): never { + // Native-to-unknown conversion can copy references (notably arrays), so + // two distinct references may be one value in the program. Terminate // instead of throwing so a test's catch block cannot turn this into a pass. - if ((typeof value === "object" && value !== null) || typeof value === "function") { - console.error("SCRIPTC_TEST262_HARNESS: reference equality requires an identity-preserving adapter"); - process.exit(86); + console.error("SCRIPTC_TEST262_HARNESS: reference equality requires an identity-preserving adapter"); + process.exit(86); +} + +function scalar(value: unknown): void { + if (reference(value)) refuse(); +} + +/** The upstream helpers accept any message value and convert it to a string. */ +function text(message: unknown, fallback: string): string { + return message === undefined ? fallback : String(message); +} + +/** SameValue of two operands. A copy made at the conversion boundary can only + * separate one reference into two, so identical references are the same value + * and a reference is never the same value as a primitive. Two distinct + * references refuse. */ +function same(actual: unknown, expected: unknown): boolean { + if (reference(actual) || reference(expected)) { + if (actual === expected) return true; + if (reference(actual) && reference(expected)) refuse(); + return false; + } + try { + nodeAssert.strictEqual(actual, expected); + return true; + } catch { + return false; } } -export function assert(value: unknown, message = "Expected true"): void { - if (value !== true) throw new Test262Error(message); +export function assert(value: unknown, message?: unknown): void { + if (value !== true) throw new Test262Error(text(message, "Expected true")); } export namespace assert { - export function sameValue(actual: unknown, expected: unknown, message = "Expected SameValue"): void { - scalar(actual); - scalar(expected); - try { - nodeAssert.strictEqual(actual, expected); - } catch { - throw new Test262Error(message); - } + export function sameValue(actual: unknown, expected: unknown, message?: unknown): void { + if (!same(actual, expected)) throw new Test262Error(text(message, "Expected SameValue")); } - export function notSameValue(actual: unknown, expected: unknown, message = "Expected different values"): void { - scalar(actual); - scalar(expected); - try { - nodeAssert.notStrictEqual(actual, expected); - } catch { - throw new Test262Error(message); - } + export function notSameValue(actual: unknown, expected: unknown, message?: unknown): void { + if (same(actual, expected)) throw new Test262Error(text(message, "Expected different values")); } - export function throws(expectedErrorConstructor: unknown, func: () => unknown, message = "Expected exception"): void { + export function throws(expectedErrorConstructor: unknown, func: () => unknown, message?: unknown): void { const outcome = throwsOutcome(expectedErrorConstructor, func); if (outcome === "invalid") throw new Test262Error("assert.throws requires a function to run"); if (outcome === "unsupported") { console.error("SCRIPTC_TEST262_HARNESS: assert.throws needs an Error instance"); process.exit(86); } - if (outcome !== "pass") throw new Test262Error(message); + if (outcome !== "pass") throw new Test262Error(text(message, "Expected exception")); } - export function compareArray(actual: unknown, expected: unknown, message = "Expected matching array contents"): void { + export function compareArray(actual: unknown, expected: unknown, message?: unknown): void { + const failure = text(message, "Expected matching array contents"); if (!Array.isArray(actual) || !Array.isArray(expected)) { scalar(actual); scalar(expected); - throw new Test262Error(message); + throw new Test262Error(failure); } - if (actual.length !== expected.length) throw new Test262Error(message); + if (actual.length !== expected.length) throw new Test262Error(failure); for (let i = 0; i < actual.length; i++) { const left: unknown = i in actual ? actual[i] : undefined; const right: unknown = i in expected ? expected[i] : undefined; - scalar(left); - scalar(right); - try { - nodeAssert.strictEqual(left, right); - } catch { - throw new Test262Error(message); - } + if (!same(left, right)) throw new Test262Error(failure); } } } From 8a02468073255db4bad38f098f7206052d99a408 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 05:57:26 -0500 Subject: [PATCH 078/259] Take number and string boxes out of the candidate buffers before pooling them scr_dyn_release returned the last reference of a number or string box to the free list without scr_cyc_dead, because the release paths never buffer those boxes. A collector pass can: capture boxes trace their payload, and scr_xg_release, which settles the cross-generation edges a restricted pass skipped, calls scr_cyc_on_release on the target whatever its kind. The pooled block then stayed in its candidate buffer, and the next box that reused it carried the stale buffer position. Its death swapped another object into that slot, which corrupted the buffers and crashed a later scr_cyc_on_dead. The fast path now takes a buffered box out of its buffer first. The sanitized runtime does not pool boxes, so only plain builds were affected. --- packages/runtime/src/scr_json.c | 8 ++++++-- packages/runtime/src/scr_json.test.c | 25 +++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 2 deletions(-) diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index c2396212d..eb03ab6cc 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -1286,10 +1286,14 @@ void scr_dyn_release(ScrDyn *d) { return; } #ifndef SCR_RC_AUDIT - /* Number and string boxes own at most one string, are never cycle - * candidates and cannot be weak keys: return them to the free list. */ + /* Number and string boxes own at most one string and cannot be weak + * keys: return them to the free list. Their releases never buffer them, + * but a collector pass can (a box that traces its payload reaches them, + * and scr_xg_release buffers what it settles), so a buffered box leaves + * its candidate buffer first. */ if ((d->kind == SCR_DYN_NUM || d->kind == SCR_DYN_STR) && !d->prototype && !d->symbol_properties && !d->symbol_keys && scr_dyn_free_count < SCR_DYN_FREE_MAX) { + scr_cyc_dead(d); if (d->kind == SCR_DYN_STR) scr_str_release(d->v.str); d->v.str = (ScrStr *)scr_dyn_free_misc; scr_dyn_free_misc = d; diff --git a/packages/runtime/src/scr_json.test.c b/packages/runtime/src/scr_json.test.c index a28759876..29ba4bfe3 100644 --- a/packages/runtime/src/scr_json.test.c +++ b/packages/runtime/src/scr_json.test.c @@ -391,6 +391,30 @@ static bool buffered_after_read(ScrDyn *d) { return buffered(d); } +/* A collector pass can buffer a number or string box that it reached + * through an owner that traces it: scr_xg_release, settling an edge a + * restricted pass skipped, calls scr_cyc_on_release on the target. The + * box's last release must take it out of its candidate buffer before its + * block returns to the free list, which hands it to the next box. */ +static void buffered_leaf_release(void) { + for (uint16_t gen = SCR_CYC_NURSERY; gen < SCR_CYC_NGENS; gen++) { + ScrStr *text = scr_str_new("buffered", 8); + ScrDyn *leaves[2] = {scr_dyn_new_str(text), scr_dyn_new_num(0.5)}; + scr_str_release(text); + for (int i = 0; i < 2; i++) { + scr_cyc_set_gen(scr_cyc_hdr(leaves[i]), gen); + scr_cyc_on_release(leaves[i]); + scr_dyn_release(leaves[i]); + } + ScrDyn *fresh[2] = {scr_dyn_new_num(1.5), scr_dyn_new_num(2.5)}; + assert(!buffered(fresh[0]) && !buffered(fresh[1])); + scr_collect_cycles(); + assert(fresh[0]->v.num == 1.5 && fresh[1]->v.num == 2.5); + scr_dyn_release(fresh[0]); + scr_dyn_release(fresh[1]); + } +} + static ScrDyn *parse_text(const char *text) { ScrStr *input = scr_str_new(text, strlen(text)); ScrDyn *parsed = scr_json_parse(input); @@ -823,6 +847,7 @@ int main(void) { shared_property_keys(); checked_leaf_cycles(); checked_number_storage(); + buffered_leaf_release(); json_intact_regions(); json_schema_parse(); json_schema_special_names(); From 486e92a628a794489bd7c8eb3878ec5bc29f25d5 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 06:11:16 -0500 Subject: [PATCH 079/259] Collect the supplied files' global names only for programs with scripts Reusing the stored diagnostics of the declaration files scriptc supplies (lib-diagnostics.ts) needs those files' global names to tell whether a program's scripts could change what checking them reports. The first build that stored an answer collected them by reading every supplied file's syntax tree, which a program made only of modules does not otherwise read, and that build is every cold build. A program of modules cannot collide with those names, so its answer is now stored without them, and the first program with scripts that uses the answer collects them and stores them with it. The entry schema is scriptc.lib-diagnostics.v2. A cold dev build of the 17-module build benchmark takes 676 ms instead of 689 ms, and of the log-summary benchmark 375 ms instead of 396 ms, with peak RSS 5.7 MiB and 4.5 MiB lower. --- .../src/frontend/ts7/lib-diagnostics.test.ts | 50 +++++++++++++++ .../src/frontend/ts7/lib-diagnostics.ts | 62 +++++++++++++++---- 2 files changed, 99 insertions(+), 13 deletions(-) diff --git a/packages/compiler/src/frontend/ts7/lib-diagnostics.test.ts b/packages/compiler/src/frontend/ts7/lib-diagnostics.test.ts index f041a6cb5..e87db5f1a 100644 --- a/packages/compiler/src/frontend/ts7/lib-diagnostics.test.ts +++ b/packages/compiler/src/frontend/ts7/lib-diagnostics.test.ts @@ -219,3 +219,53 @@ test("a supplied file that changes is a different entry", () => { expect(store.entries.size).toBe(2); writeFileSync(fallback, fallbackText); }); + +/** The program's files, recording which ones were read. */ +function recording(texts: Record): ((name: string) => SourceFile | undefined) & { + read: string[]; +} { + const inner = files(texts); + const read: string[] = []; + return Object.assign((name: string) => (read.push(name), inner(name)), { read }); +} + +test("a program of modules stores its answer without reading the supplied files", () => { + const store = memoryStore(); + setLibDiagnosticsStore(store, "checker"); + const sources = recording({ [main]: "export const n: number = 'x';\n" }); + reusedLibDiagnostics( + sessionProgram({ semantic: new Map([[main, []]]) }), + names, + supplied, + sources, + ); + expect(sources.read).toEqual([main]); + const [text] = [...store.entries.values()]; + expect(JSON.parse(text!).globals).toBeNull(); + // A later program of modules reuses it, again without reading them. + const again = recording({ [main]: "export const n: number = 'x';\n" }); + const program = sessionProgram({ semantic: new Map([[main, []]]) }); + expect(reusedLibDiagnostics(program, names, supplied, again)).not.toBeNull(); + expect(program.asked).toEqual([`checked ${main}`]); + expect(again.read).toEqual([main]); +}); + +test("a script that uses an answer stored without global names collects and stores them", () => { + const store = memoryStore(); + setLibDiagnosticsStore(store, "checker"); + const semantic = new Map([[main, []]]); + reusedLibDiagnostics(sessionProgram({ semantic }), names, supplied, moduleFile); + const script = recording({ [main]: "const total = 1;\n" }); + const program = sessionProgram({ semantic }); + expect(reusedLibDiagnostics(program, names, supplied, script)).not.toBeNull(); + expect(program.asked).toEqual([`checked ${main}`]); + expect(script.read).toEqual([main, lib, fallback]); + const [text] = [...store.entries.values()]; + expect(new Set(JSON.parse(text!).globals)).toEqual(new Set(["NaN", "Array", "process"])); + // A script that declares one of them runs the full check, and the entry keeps its names. + const clash = sessionProgram({ semantic }); + reusedLibDiagnostics(clash, names, supplied, files({ [main]: "declare var NaN: number;\n" })); + expect(clash.asked[0]).toBe("getGlobalDiagnostics"); + expect(store.entries.size).toBe(1); + expect(JSON.parse([...store.entries.values()][0]!).globals).not.toBeNull(); +}); diff --git a/packages/compiler/src/frontend/ts7/lib-diagnostics.ts b/packages/compiler/src/frontend/ts7/lib-diagnostics.ts index 827b337bd..30c6e81f0 100644 --- a/packages/compiler/src/frontend/ts7/lib-diagnostics.ts +++ b/packages/compiler/src/frontend/ts7/lib-diagnostics.ts @@ -10,7 +10,14 @@ * (getDiagnosticsOfCheckedFiles), and the semantic diagnostics merge in the * order the full check sorts them, by file name. An answer is stored only * when the full check reports no global diagnostics: the global diagnostics - * of checking the other files are then the full check's. */ + * of checking the other files are then the full check's. + * + * The global names the supplied files declare matter only to programs with + * scripts, and collecting them reads every supplied file's syntax tree, + * which a program of modules does not otherwise read (about 4 MB at the + * peak of a small build). An answer stored by such a program leaves them + * out; the first program with scripts that uses the answer collects them + * and stores them with it. */ import { createHash } from "node:crypto"; import { statSync } from "node:fs"; import type { Node, SourceFile } from "./ast-types.js"; @@ -25,7 +32,7 @@ export interface LibDiagnosticsStore { write(key: string, text: string): void; } -const SCHEMA = "scriptc.lib-diagnostics.v1"; +const SCHEMA = "scriptc.lib-diagnostics.v2"; let configured: { store: LibDiagnosticsStore; checker: string } | null = null; @@ -89,7 +96,14 @@ export function reusedLibDiagnostics( const key = entryKey(checker, options, libs); if (key === null) return null; const stored = readEntry(store, key, libs); - if (stored !== null && !collides(stored.globals)) { + // An answer stored without the supplied files' global names: a program + // with scripts collects them and stores them with the answer. + let globals = stored?.globals ?? null; + if (stored !== null && globals === null && scripts.length > 0) { + globals = suppliedGlobalNames(libs, sourceFile); + if (globals !== null) writeEntry(store, key, globals, Object.fromEntries(stored.files)); + } + if (stored !== null && (scripts.length === 0 || (globals !== null && !collides(globals)))) { const checked = program.checkedFileDiagnosticData(own); if (checked === null) return null; const byFile = new Map(stored.files); @@ -104,20 +118,35 @@ export function reusedLibDiagnostics( const semantic = program.diagnosticData("getSemanticDiagnostics"); // A server that cannot check only some files could never use the answer. if (global.length === 0 && stored === null && program.checkedFileDiagnosticData([]) !== null) { - const globals = suppliedGlobalNames(libs, sourceFile); - if (globals !== null && !collides(globals)) { + const names = scripts.length === 0 ? null : suppliedGlobalNames(libs, sourceFile); + if (scripts.length === 0 || (names !== null && !collides(names))) { const files: Record = {}; for (const name of libs) files[name] = program.diagnosticData("getSemanticDiagnostics", name); - try { - store.write(key, JSON.stringify({ schema: SCHEMA, globals: [...globals], files })); - } catch { - // Best effort: a failed write is a later miss. - } + writeEntry(store, key, names, files); } } return { semantic, global }; } +/** Stores an answer: the supplied files' diagnostics, and their global names + * when they were collected (null otherwise). Best effort: a failed write is + * a later miss. */ +function writeEntry( + store: LibDiagnosticsStore, + key: string, + globals: ReadonlySet | null, + files: Record, +): void { + try { + store.write( + key, + JSON.stringify({ schema: SCHEMA, globals: globals === null ? null : [...globals], files }), + ); + } catch { + // A failed write is a later miss. + } +} + /** Whether a file cannot add to or change the global declarations the * supplied files declare: a module with no `declare global`, no module * augmentation and no UMD `export as namespace` declaration. */ @@ -276,7 +305,7 @@ function readEntry( store: LibDiagnosticsStore, key: string, libs: readonly string[], -): { files: Map; globals: Set } | null { +): { files: Map; globals: Set | null } | null { let text: string | null; try { text = store.read(key); @@ -290,7 +319,11 @@ function readEntry( } catch { return null; } - if (entry.schema !== SCHEMA || entry.files === undefined || !Array.isArray(entry.globals)) + if ( + entry.schema !== SCHEMA || + entry.files === undefined || + (entry.globals !== null && !Array.isArray(entry.globals)) + ) return null; const files = new Map(); for (const name of libs) { @@ -298,7 +331,10 @@ function readEntry( if (!Array.isArray(list)) return null; files.set(name, list); } - return { files, globals: new Set(entry.globals.filter((name) => typeof name === "string")) }; + const globals = Array.isArray(entry.globals) + ? new Set(entry.globals.filter((name): name is string => typeof name === "string")) + : null; + return { files, globals }; } /** Each file's diagnostics (already in the checker's order) in the order the From 4c0572c49e9fa7d72a7fa24ac28d6f24c157def1 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 06:25:57 -0500 Subject: [PATCH 080/259] Decode an undefined TextDecoder input as no bytes In Node, `decoder.decode(undefined)` returns "" like `decode()`, and flushes bytes pending from streamed input. scriptc refused a statically undefined argument and an argument typed `Uint8Array | undefined` with SC2020, and `decode(x!)` on an undefined value threw a TypeError. The decode input lowering now evaluates a statically undefined argument for its effects and decodes an empty Uint8Array, and reads the undefined arm of `Uint8Array | undefined` as an empty Uint8Array, in both the decoder-value and the `new TextDecoder(label).decode(...)` paths. A non-null assertion passed to decode keeps the undefined it removes, instead of the checked narrowing other optional standard library parameters keep. Inputs that may be null are refused as before (`decode(null)` throws a TypeError in Node). --- .../frontend/lowering/builtins/text-codecs.ts | 26 ++++++++++++++-- .../src/frontend/lowering/lower-exprs.ts | 15 +++++++++ .../text-decoder-undefined-input.ts.json | 6 ++++ ...-non-null-assertion-nullish-destination.ts | 4 +-- tests/corpus/text-decoder-undefined-input.ts | 31 +++++++++++++++++++ .../text-decoder-undefined-input.ts.json | 1 + 6 files changed, 79 insertions(+), 4 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/text-decoder-undefined-input.ts.json create mode 100644 tests/corpus/text-decoder-undefined-input.ts create mode 100644 tests/harness/corpus-costs/text-decoder-undefined-input.ts.json diff --git a/packages/compiler/src/frontend/lowering/builtins/text-codecs.ts b/packages/compiler/src/frontend/lowering/builtins/text-codecs.ts index 8d47c8e3a..34cc7aa14 100644 --- a/packages/compiler/src/frontend/lowering/builtins/text-codecs.ts +++ b/packages/compiler/src/frontend/lowering/builtins/text-codecs.ts @@ -16,6 +16,7 @@ import { type IrType, STRING, type SrcLoc, + typeEquals, } from "../../../ir/ir.js"; import { lowerBuiltinValuePreservingUndefined, @@ -24,6 +25,27 @@ import { } from "./arguments.js"; import { type BuiltinModuleFn } from "../surfaces.js"; +/** The input of `decoder.decode(input)`. An undefined input decodes no bytes, + * as `decode()` does in Node: a statically undefined argument (after its + * effects) and the undefined arm of `Uint8Array | undefined` read as an + * empty Uint8Array. */ +function lowerDecodeInput(lowerer: Lowerer, node: ts.Expression, loc: SrcLoc): IrExpr { + const empty: IrExpr = { kind: "bytesNew", source: null, type: BYTES_U8, loc }; + const undefinedArg = lowerStaticallyUndefinedArgument(lowerer, node); + if (undefinedArg) return defaultAfterUndefined(undefinedArg, empty); + const value = lowerer.lowerExpr(node); + if (value.type.kind === "union") { + const def = lowerer.unions.get(value.type.unionId); + if ( + def?.arms.length === 2 && + def.arms.some((arm) => arm.kind === "undefinedT") && + def.arms.some((arm) => typeEquals(arm, BYTES_U8)) + ) + return { kind: "nullish", left: value, right: empty, type: BYTES_U8, loc }; + } + return value; +} + /** StringDecoder writes preserve pending bytes; end(input) performs the * final write and flushes the state. String input passes through unchanged. */ export function lowerStringDecoderMethodCall( @@ -413,7 +435,7 @@ function lowerStoredTextCodecCall( : { kind: "bytesNew", source: null, type: BYTES_U8, loc } : cls === "TextEncoder" ? lowerer.lowerExprExpecting(call.arguments.nodes[0]!, STRING) - : lowerer.lowerExpr(call.arguments.nodes[0]!); + : lowerDecodeInput(lowerer, call.arguments.nodes[0]!, loc); if ( cls === "TextDecoder" && (arg.type.kind === "dyn" || (arg.type.kind === "bytes" && arg.type.elem !== "u8")) @@ -622,7 +644,7 @@ export function lowerTextCodecCall( ); } const argNode = call.arguments.nodes[0]!; - let arg = lowerer.lowerExpr(argNode); + let arg = lowerDecodeInput(lowerer, argNode, loc); if (arg.type.kind === "dyn" || (arg.type.kind === "bytes" && arg.type.elem !== "u8")) { arg = { kind: "libCall", diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 033f482d1..8d9b9d410 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -975,6 +975,18 @@ function assertionDestinationHoldsNullish( return constituentTypes(contextual).some((type) => (type.flags & nullish) !== 0); } +/** Whether `declaration` is TextDecoder's `decode` method. */ +function isTextDecoderDecode(declaration: ts.Node): boolean { + if (!ts.isMethodSignatureDeclaration(declaration) && !ts.isMethodDeclaration(declaration)) + return false; + if (!ts.isIdentifier(declaration.name) || declaration.name.text !== "decode") return false; + const owner = declaration.parent; + return ( + (ts.isInterfaceDeclaration(owner) || ts.isClassDeclaration(owner)) && + owner.name?.text === "TextDecoder" + ); +} + /** Whether `argument` of `call` binds an optional parameter of a standard * library declaration (`decoder.decode(input?)`). The undefined such a * parameter's type holds comes from its optionality, and the builtin @@ -989,6 +1001,9 @@ function optionalStdlibParameter( const declaration = lowerer.checker.getResolvedSignature(call)?.declaration; if (declaration === undefined || !lowerer.isStdlibFile(ts.getSourceFileOfNode(declaration))) return false; + // TextDecoder.decode reads an undefined input as no bytes, as Node does + // (builtins/text-codecs.ts lowerDecodeInput). + if (isTextDecoderDecode(declaration)) return false; const index = call.arguments?.nodes.indexOf(argument) ?? -1; const parameter = declaration.parameters?.nodes[index]; return ( diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/text-decoder-undefined-input.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/text-decoder-undefined-input.ts.json new file mode 100644 index 000000000..a1f5f49d9 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/text-decoder-undefined-input.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/text-decoder-undefined-input.ts" + ], + "diags": [] +} diff --git a/tests/corpus/7189-non-null-assertion-nullish-destination.ts b/tests/corpus/7189-non-null-assertion-nullish-destination.ts index 632655cff..4cd7e291f 100644 --- a/tests/corpus/7189-non-null-assertion-nullish-destination.ts +++ b/tests/corpus/7189-non-null-assertion-nullish-destination.ts @@ -46,8 +46,8 @@ console.log(String(names.get("a")!), String(names.get("b")!)); console.log(Number(amounts.get("a")!), Number(amounts.get("b")!)); console.log(kindOf(names.get("a")!), kindOf(amounts.get("a")!), kindOf(names.get("b")!)); -// An optional parameter of a standard library method keeps the checked -// narrowing: `decode(input?)` reads the asserted Uint8Array. +// TextDecoder.decode reads the asserted Uint8Array; an undefined input +// decodes no bytes (text-decoder-undefined-input.ts). const chunks = new Map([["a", new TextEncoder().encode("chunk")]]); interface Read { done: boolean; diff --git a/tests/corpus/text-decoder-undefined-input.ts b/tests/corpus/text-decoder-undefined-input.ts new file mode 100644 index 000000000..6a3be354c --- /dev/null +++ b/tests/corpus/text-decoder-undefined-input.ts @@ -0,0 +1,31 @@ +// TextDecoder.decode(undefined) decodes no bytes, as decode() does: it +// returns "" and, after streamed input, flushes the pending bytes. +const decoder = new TextDecoder(); +const encoded = new TextEncoder().encode("bytes"); +const inputs = new Map([ + ["present", encoded], + ["absent", undefined], +]); + +console.log(JSON.stringify(decoder.decode(undefined))); +console.log(JSON.stringify(decoder.decode(inputs.get("present"))), JSON.stringify(decoder.decode(inputs.get("absent")))); +console.log(JSON.stringify(decoder.decode(inputs.get("absent")!)), JSON.stringify(decoder.decode(inputs.get("missing")!))); +console.log(JSON.stringify(new TextDecoder("utf-8").decode(undefined))); +console.log(JSON.stringify(new TextDecoder("utf-8").decode(inputs.get("absent")))); + +let calls = 0; +function nothing(): undefined { + calls++; + return undefined; +} +console.log(JSON.stringify(decoder.decode(nothing())), calls); + +interface Chunk { + done: boolean; + value?: Uint8Array; +} +const chunks: Chunk[] = [{ done: false, value: new Uint8Array([0xe2, 0x82]) }, { done: true }]; +const streaming = new TextDecoder(); +let text = ""; +for (const chunk of chunks) text += streaming.decode(chunk.value, { stream: !chunk.done }); +console.log(JSON.stringify(text), text.length); diff --git a/tests/harness/corpus-costs/text-decoder-undefined-input.ts.json b/tests/harness/corpus-costs/text-decoder-undefined-input.ts.json new file mode 100644 index 000000000..b156827d6 --- /dev/null +++ b/tests/harness/corpus-costs/text-decoder-undefined-input.ts.json @@ -0,0 +1 @@ +{ "plain": 1937, "san": 2233 } From 314024a8c7a8c39864c1ea08c5ded3bf3ec129c4 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 06:29:47 -0500 Subject: [PATCH 081/259] Copy typed array sets of the same element kind on shared memory as bytes TypedArray.prototype.set with a SharedArrayBuffer view as its source or target converted every element through a double, even when both arrays had the same element kind. That cost about 5 ns per byte, and it changed NaN payloads: a Float32Array signaling NaN came back quieted (7fa00001 became 7fe00001), where Node copies the bytes. The same element kind now copies the source's bytes with the relaxed shared stores. A source that overlaps the target range, a view of the same buffer in a program without workers, is copied out first. Different element kinds still convert each element. --- .../8106-shared-typed-array-set.ts.json | 6 ++ ...107-shared-typed-array-set-workers.ts.json | 6 ++ packages/runtime/src/scr_bytes.c | 21 +++- packages/runtime/src/scr_bytes.test.c | 47 +++++++++ tests/corpus/8106-shared-typed-array-set.ts | 97 +++++++++++++++++++ .../8107-shared-typed-array-set-workers.ts | 63 ++++++++++++ 6 files changed, 238 insertions(+), 2 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8106-shared-typed-array-set.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8107-shared-typed-array-set-workers.ts.json create mode 100644 tests/corpus/8106-shared-typed-array-set.ts create mode 100644 tests/corpus/8107-shared-typed-array-set-workers.ts diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8106-shared-typed-array-set.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8106-shared-typed-array-set.ts.json new file mode 100644 index 000000000..8b7a07fac --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8106-shared-typed-array-set.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8106-shared-typed-array-set.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8107-shared-typed-array-set-workers.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8107-shared-typed-array-set-workers.ts.json new file mode 100644 index 000000000..338b4bc03 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8107-shared-typed-array-set-workers.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8107-shared-typed-array-set-workers.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_bytes.c b/packages/runtime/src/scr_bytes.c index 3926bf83e..e6df837c8 100644 --- a/packages/runtime/src/scr_bytes.c +++ b/packages/runtime/src/scr_bytes.c @@ -755,12 +755,29 @@ void scr_bytes_set_from(ScrBytes *dst, const ScrBytes *src, double offset) { } size_t width = scr_bytes_elem_size(dst->elem); if (dst->shared || src->shared) { - /* Convert a private copy of the source, then publish the target range. */ SCR_BYTES_SNAPSHOT(src); size_t bytes = src->len * width; + uint8_t *target = dst->data + (size_t)t * width; + if (dst->elem == src->elem) { + /* The same element kind copies the source's bytes, NaN payloads + * included. A source range that overlaps the target range (views of + * one buffer, where no snapshot was taken) is copied out first. */ + uintptr_t to = (uintptr_t)target, from = (uintptr_t)src->data; + bool overlap = to <= from ? from - to < bytes : to - from < bytes; + if (!overlap) { + scr_bytes_raw_out(dst, target, src->data, bytes); + return; + } + uint8_t *copy = scr_bytes_scratch(bytes); + scr_bytes_raw_in(src, copy, src->data, bytes); + scr_bytes_raw_out(dst, target, copy, bytes); + free(copy); + return; + } + /* Convert a private copy of the source, then publish the target range. */ uint8_t *scratch = scr_bytes_scratch(bytes); scr_bytes_convert_span(scratch, dst->elem, src->data, src->elem, src->len); - scr_bytes_raw_out(dst, dst->data + (size_t)t * width, scratch, bytes); + scr_bytes_raw_out(dst, target, scratch, bytes); free(scratch); return; } diff --git a/packages/runtime/src/scr_bytes.test.c b/packages/runtime/src/scr_bytes.test.c index 58f52fa63..8b2ff3cc1 100644 --- a/packages/runtime/src/scr_bytes.test.c +++ b/packages/runtime/src/scr_bytes.test.c @@ -37,6 +37,52 @@ static void external_set(void) { } } +/* Same-kind sets into and out of shared storage copy raw bytes, NaN + * payloads included, also between overlapping views of one shared buffer. */ +static void shared_set(void) { + enum { COUNT = 37 }; + for (ScrBytesElem elem = SCR_BYTES_U8; elem <= SCR_BYTES_F16; elem++) { + size_t width = scr_bytes_elem_size(elem), bytes = COUNT * width; + uint8_t pattern[COUNT * 8], expected[COUNT * 8]; + for (size_t i = 0; i < bytes; i++) pattern[i] = (uint8_t)(i * 37 + 0x7f); + /* Signaling NaNs, which a conversion through double would quiet. */ + const uint16_t nan16 = 0x7d01; + const uint32_t nan32 = 0x7fa00001; + const uint64_t nan64 = UINT64_C(0x7ff4000000000001); + for (size_t i = 1; i < COUNT; i += 6) { + if (elem == SCR_BYTES_F16) memcpy(pattern + i * width, &nan16, width); + if (elem == SCR_BYTES_F32) memcpy(pattern + i * width, &nan32, width); + if (elem == SCR_BYTES_F64) memcpy(pattern + i * width, &nan64, width); + } + for (int direction = 0; direction < 2; direction++) { + ScrBytes *shared = scr_bytes_new(elem, COUNT); + scr_bytes_make_shared(shared); + memcpy(shared->data, pattern, bytes); + ScrBytes *src = direction ? scr_bytes_subarray(shared, 3, COUNT) : scr_bytes_subarray(shared, 0, COUNT - 3); + double offset = direction ? 0 : 3; + memcpy(expected, pattern, bytes); + memmove(expected + (size_t)offset * width, pattern + (direction ? 3 : 0) * width, (COUNT - 3) * width); + scr_bytes_set_from(shared, src, offset); + assert(!scr_exc_pending()); + assert(memcmp(shared->data, expected, bytes) == 0); + scr_bytes_release(src); + + ScrBytes *local = scr_bytes_new(elem, COUNT); + memcpy(local->data, pattern, bytes); + ScrBytes *head = scr_bytes_subarray(local, 0, COUNT - 1); + scr_bytes_set_from(shared, head, 1); + memcpy(expected + width, pattern, bytes - width); + assert(memcmp(shared->data, expected, bytes) == 0); + memset(local->data, 0, bytes); + scr_bytes_set_from(local, shared, 0); + assert(memcmp(local->data, expected, bytes) == 0); + scr_bytes_release(head); + scr_bytes_release(local); + scr_bytes_release(shared); + } + } +} + static void copied_storage(void) { /* Same-kind copies preserve NaN payloads, signed zero and ownership. */ const uint64_t bits[] = {UINT64_C(0x7ff8000000000042), UINT64_C(0x8000000000000000), @@ -79,6 +125,7 @@ static void filled_storage(void) { void scr_bytes_test_bulk_storage(void) { long before = scr_bytes_live_count(); external_set(); + shared_set(); copied_storage(); filled_storage(); assert(scr_bytes_live_count() == before); diff --git a/tests/corpus/8106-shared-typed-array-set.ts b/tests/corpus/8106-shared-typed-array-set.ts new file mode 100644 index 000000000..7e20aad72 --- /dev/null +++ b/tests/corpus/8106-shared-typed-array-set.ts @@ -0,0 +1,97 @@ +// TypedArray.prototype.set where the source, the target or both are views of +// a SharedArrayBuffer: same element kinds (bytes copied as is, NaN payloads +// included), different kinds (converted per element), offsets, overlapping +// ranges of one buffer, Buffer targets and out-of-bounds offsets. +function bits(label: string, buffer: ArrayBufferLike): void { + const words = new Uint32Array(buffer); + const out: string[] = []; + for (let i = 0; i < words.length; i++) out.push(words[i]!.toString(16)); + console.log(label, out.join(",")); +} + +const shared = new SharedArrayBuffer(32); +const bytes = new Uint8Array(shared); + +// Private source into a shared target, then shared into shared and shared into private. +bytes.set(new Uint8Array([1, 2, 3, 4, 5]), 2); +console.log("private into shared", bytes.subarray(0, 8).join(",")); +const other = new Uint8Array(new SharedArrayBuffer(8)); +other.set(bytes.subarray(2, 7)); +console.log("shared into shared", other.join(",")); +const local = new Uint8Array(12); +local.set(other, 3); +console.log("shared into private", local.join(",")); + +// Overlapping ranges of the same buffer, forward and backward. +const overlap = new Uint8Array(new SharedArrayBuffer(10)); +overlap.set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); +overlap.set(overlap.subarray(0, 6), 3); +console.log("overlap forward", overlap.join(",")); +overlap.set(overlap.subarray(4, 10), 1); +console.log("overlap backward", overlap.join(",")); + +// Same kind, wider elements: a signaling NaN keeps its bits. +const floatBits = new Uint32Array(new SharedArrayBuffer(8)); +floatBits[0] = 0x7fa00001; +floatBits[1] = 0xffc00002; +const floatsShared = new Float32Array(floatBits.buffer); +const floatsLocal = new Float32Array(2); +floatsLocal.set(floatsShared); +bits("f32 shared into private", floatsLocal.buffer); +const floatsBack = new Float32Array(new SharedArrayBuffer(8)); +floatsBack.set(floatsLocal); +bits("f32 private into shared", floatsBack.buffer); + +const doubleBits = new Uint32Array(new SharedArrayBuffer(16)); +doubleBits[0] = 5; +doubleBits[1] = 0x7ff40000; +doubleBits[2] = 0; +doubleBits[3] = 0xc0090000; +const doublesShared = new Float64Array(doubleBits.buffer); +const doublesCopy = new Float64Array(new SharedArrayBuffer(16)); +doublesCopy.set(doublesShared); +bits("f64 shared into shared", doublesCopy.buffer); +console.log("f64 values", doublesCopy[1]); + +const signed = new Int16Array(new SharedArrayBuffer(8)); +signed.set(new Int16Array([-32768, -1, 32767]), 1); +console.log("i16 private into shared", signed.join(",")); + +// Different kinds convert each element. +const clamped = new Uint8ClampedArray(new SharedArrayBuffer(4)); +clamped.set(new Int16Array([300, -5, 128, 255])); +console.log("i16 into shared clamped", clamped.join(",")); +const wrapped = new Uint8Array(new SharedArrayBuffer(4)); +wrapped.set(new Int16Array(signed.buffer, 2, 3)); +console.log("shared i16 into shared u8", wrapped.join(",")); +const narrowed = new Int8Array(4); +narrowed.set(new Float64Array(doublesShared.buffer, 8, 1)); +narrowed.set(new Uint8Array([200, 127]), 2); +console.log("f64 and u8 into i8", narrowed.join(",")); +const fromClamped = new Uint8Array(new SharedArrayBuffer(4)); +fromClamped.set(clamped); +console.log("shared clamped into shared u8", fromClamped.join(",")); + +// Buffer views over shared memory take the same paths. +const buf = Buffer.from(shared, 16, 8); +buf.set(Buffer.from("scriptc"), 1); +console.log("buffer", buf.toString("latin1", 1, 8), bytes[17], bytes[23]); +const into = Buffer.alloc(4); +into.set(buf.subarray(1, 4)); +console.log("buffer into private", into.toString("hex")); + +// Offsets past the end throw before writing. +for (const offset of [-1, 30, 31]) { + try { + bytes.set(new Uint8Array([9, 9]), offset); + console.log("set at", offset, bytes[30], bytes[31]); + } catch (error) { + console.log("set at", offset, (error as Error).name, (error as Error).message); + } +} +try { + floatsBack.set(new Float32Array(3)); +} catch (error) { + console.log("too long", (error as Error).name, (error as Error).message); +} +console.log("unchanged", floatsBack.join(",")); diff --git a/tests/corpus/8107-shared-typed-array-set-workers.ts b/tests/corpus/8107-shared-typed-array-set-workers.ts new file mode 100644 index 000000000..6be32668b --- /dev/null +++ b/tests/corpus/8107-shared-typed-array-set-workers.ts @@ -0,0 +1,63 @@ +// TypedArray.prototype.set on SharedArrayBuffer views in a program with +// workers: the same cases on the main thread and in a worker (same element +// kinds with NaN payloads, overlapping ranges of one buffer, converted +// kinds), and a worker's set into a buffer that the main thread reads after +// a message. +import { isMainThread, parentPort, Worker, workerData } from "node:worker_threads"; + +interface Job { + shared: SharedArrayBuffer; +} + +function hex(buffer: ArrayBufferLike): string { + const words = new Uint32Array(buffer); + const out: string[] = []; + for (let i = 0; i < words.length; i++) out.push(words[i]!.toString(16)); + return out.join(","); +} + +function cases(where: string): string[] { + const lines: string[] = []; + const bytes = new Uint8Array(new SharedArrayBuffer(12)); + bytes.set([0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); + bytes.set(bytes.subarray(0, 8), 4); + lines.push(`${where} overlap forward ${bytes.join(",")}`); + bytes.set(bytes.subarray(5, 12), 0); + lines.push(`${where} overlap backward ${bytes.join(",")}`); + + const floatBits = new Uint32Array(new SharedArrayBuffer(8)); + floatBits[0] = 0x7f800001; + floatBits[1] = 0x7fc12345; + const local = new Float32Array(2); + local.set(new Float32Array(floatBits.buffer)); + const back = new Float32Array(new SharedArrayBuffer(12)); + back.set(local, 1); + lines.push(`${where} f32 ${hex(local.buffer)} ${hex(back.buffer)}`); + + const halves = new Uint16Array(new SharedArrayBuffer(8)); + halves.set(new Uint16Array([65535, 1, 2]), 1); + const signed = new Int16Array(4); + signed.set(halves); + const clamped = new Uint8ClampedArray(new SharedArrayBuffer(4)); + clamped.set(signed); + lines.push(`${where} kinds ${halves.join(",")} ${signed.join(",")} ${clamped.join(",")}`); + return lines; +} + +if (isMainThread) { + for (const line of cases("main")) console.log(line); + const shared = new SharedArrayBuffer(16); + const job: Job = { shared }; + const worker = new Worker(new URL(import.meta.url), { workerData: job }); + worker.on("message", (message: string) => { + console.log(message); + console.log("worker wrote", new Uint8Array(shared).join(",")); + void worker.terminate(); + }); +} else { + const { shared } = workerData as Job; + const target = new Uint8Array(shared); + target.set(new Uint8Array([9, 8, 7]), 2); + target.set(target.subarray(2, 5), 10); + parentPort!.postMessage(cases("worker").join("\n")); +} From b6050f96bd04ea373b5ea18f4f8c3581a19d5c83 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 06:40:00 -0500 Subject: [PATCH 082/259] Read the runtime ABI marker in the native toolchain fixture from the compiler - The native toolchain test's fixture runtime pack hard-coded ABI v37, so with this branch's marker (v40) the toolchain refused the pack and the test saw exit status 1. It now takes RUNTIME_ABI_VERSION and RUNTIME_ABI_MARKER from runtime-abi.ts, as the native driver test does. --- tests/harness/self-hosting-native-toolchain.test.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/harness/self-hosting-native-toolchain.test.ts b/tests/harness/self-hosting-native-toolchain.test.ts index c5476328e..4b4af5ac6 100644 --- a/tests/harness/self-hosting-native-toolchain.test.ts +++ b/tests/harness/self-hosting-native-toolchain.test.ts @@ -9,6 +9,10 @@ import { nativeCodegenTarget } from "../../packages/compiler/src/backend/targets import type { NativeLinkFeatures } from "../../packages/compiler/src/backend/native-link-info.js"; import type { RuntimePackManifest } from "../../packages/compiler/src/backend/runtime-pack-core.js"; import type { NativeToolchainManifest } from "../../packages/compiler/src/native/toolchain.js"; +import { + RUNTIME_ABI_MARKER, + RUNTIME_ABI_VERSION, +} from "../../packages/compiler/src/backend/runtime-abi.js"; const root = join(import.meta.dirname, "../.."); const entry = join(root, "tests/fixtures/self-hosting/native-toolchain.ts"); @@ -109,7 +113,7 @@ for (const backend of ["llvm"] as const) { object_format: target.objectFormat, minimum_os: target.minimumOs, }, - runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + runtime_abi: { version: RUNTIME_ABI_VERSION, marker: RUNTIME_ABI_MARKER }, compiler: { command: "fixture", identity: "fixture", target: target.llvmTriple }, macros: { executable: [], excluded: [], sanitizer: "external-toolchain-required" }, flavors: { From 854f3ae8103d5573f9c39e829f850b8a7f76661f Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 06:41:00 -0500 Subject: [PATCH 083/259] Construct readline.Interface and builtin classes bound through require() members in JavaScript --- .../lowering/builtins/module-bindings.ts | 26 ++++++++++ .../frontend/lowering/builtins/readline.ts | 36 ++++++++----- .../src/frontend/lowering/lower-classes.ts | 16 ++++-- packages/compiler/src/frontend/tsc-codes.ts | 6 +++ ...30-readline-interface-constructor.cjs.json | 6 +++ .../8231-builtin-member-binding-new.cjs.json | 6 +++ .../8230-readline-interface-constructor.cjs | 51 +++++++++++++++++++ .../8231-builtin-member-binding-new.cjs | 35 +++++++++++++ ...30-readline-interface-constructor.cjs.json | 1 + .../8231-builtin-member-binding-new.cjs.json | 1 + 10 files changed, 167 insertions(+), 17 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8230-readline-interface-constructor.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8231-builtin-member-binding-new.cjs.json create mode 100644 tests/corpus/8230-readline-interface-constructor.cjs create mode 100644 tests/corpus/8231-builtin-member-binding-new.cjs create mode 100644 tests/harness/corpus-costs/8230-readline-interface-constructor.cjs.json create mode 100644 tests/harness/corpus-costs/8231-builtin-member-binding-new.cjs.json diff --git a/packages/compiler/src/frontend/lowering/builtins/module-bindings.ts b/packages/compiler/src/frontend/lowering/builtins/module-bindings.ts index 5465aeafa..4ded700fe 100644 --- a/packages/compiler/src/frontend/lowering/builtins/module-bindings.ts +++ b/packages/compiler/src/frontend/lowering/builtins/module-bindings.ts @@ -185,6 +185,32 @@ export function builtinMemberRequireDecl( return spec !== null && canonicalBuiltinModule(spec) !== null; } +/** The member's own symbol for a variable bound to a builtin module's + * member (`const SD = require("string_decoder").StringDecoder`, + * builtinMemberRequireDecl) when the member is a class, so the variable + * resolves as a named import of the class does. The symbol itself + * otherwise. */ +export function builtinMemberBindingTarget( + lowerer: Lowerer, + symbol: ts.Symbol | null, +): ts.Symbol | null { + const decl = symbol?.valueDeclaration; + if ( + decl === undefined || + !ts.isVariableDeclaration(decl) || + !builtinMemberRequireDecl(decl.name, decl.initializer) + ) + return symbol; + const init = decl.initializer as ts.PropertyAccessExpression; + let member = lowerer.checker.getSymbolAtLocation(init.name); + if (member && member.flags & ts.SymbolFlags.Alias) + member = lowerer.checker.getAliasedSymbol(member); + // Only a class member: `require("events").EventEmitter` is a static + // property of the exported class, which builtinEmitterInfoOf follows + // from the variable itself. + return member?.declarations.some(ts.isClassDeclaration) ? member : symbol; +} + /** The supported builtin module when `decl` destructures a builtin * NAMESPACE binding (`const crypto = require('crypto'); const { * createSign, sign: mySign } = crypto;` — test/common/crypto.js's diff --git a/packages/compiler/src/frontend/lowering/builtins/readline.ts b/packages/compiler/src/frontend/lowering/builtins/readline.ts index aca209017..c2b6984ce 100644 --- a/packages/compiler/src/frontend/lowering/builtins/readline.ts +++ b/packages/compiler/src/frontend/lowering/builtins/readline.ts @@ -302,6 +302,15 @@ function interfaceClassModule(lowerer: Lowerer, node: ts.Expression): string | n : null; } +/** `new readline.Interface(...)` and `new readlinePromises.Interface(...)`: + * the constructor createInterface calls, with the same arguments. Null for + * other constructors. */ +export function lowerReadlineInterfaceNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr | null { + const module = interfaceClassModule(lowerer, expr.expression); + if (module === null) return null; + return lowerReadlineCreateCall(lowerer, expr, locOf(expr), module === "readline/promises"); +} + /** `rl instanceof readline.Interface` and `rl instanceof * readlinePromises.Interface` over a readline Interface: an interface is * an instance of the class of the module that created it (Node's @@ -1059,10 +1068,12 @@ function lowerOutput(lowerer: Lowerer, node: ts.Expression): IrExpr | "stdout" | * goes through rl.terminal with the completer. */ export function lowerReadlineCreateCall( lowerer: Lowerer, - expr: ts.CallExpression, + expr: ts.CallExpression | ts.NewExpression, loc: SrcLoc, promises: boolean, ): IrExpr { + const argNodes = expr.arguments?.nodes ?? []; + const what = ts.isNewExpression(expr) ? "new Interface" : "createInterface"; let input: IrExpr | null = null; let output: IrExpr | "stdout" | "none" = "none"; let crlf: IrExpr = numLit(0, loc); @@ -1112,39 +1123,38 @@ export function lowerReadlineCreateCall( }); terminal = { kind: "varRef", localId: local.id, type: BOOL, loc }; }; - const optsNode = expr.arguments.nodes[0]; + const optsNode = argNodes[0]; if (optsNode === undefined) { lowerer.noLowering( - "createInterface without arguments", + `${what} without arguments`, expr, "pass { input: process.stdin, output: process.stdout } or createInterface(input, output)", ); } if (!ts.isObjectLiteralExpression(optsNode)) { // createInterface(input, output?, completer?, terminal?) - if (expr.arguments.nodes.length > 4) { + if (argNodes.length > 4) { lowerer.noLowering( - `createInterface with ${expr.arguments.nodes.length} arguments`, - expr.arguments.nodes[4]!, + `${what} with ${argNodes.length} arguments`, + argNodes[4]!, "pass createInterface(input, output, completer, terminal) or one options object", ); } input = lowerInput(lowerer, optsNode); - if (expr.arguments.nodes[1] !== undefined) - output = lowerOutput(lowerer, expr.arguments.nodes[1]); - const completerNode = expr.arguments.nodes[2]; + if (argNodes[1] !== undefined) output = lowerOutput(lowerer, argNodes[1]); + const completerNode = argNodes[2]; if ( completerNode !== undefined && !(ts.isIdentifier(completerNode) && completerNode.text === "undefined") ) { setCompleter(completerNode); } - if (expr.arguments.nodes[3] !== undefined) setTerminal(expr.arguments.nodes[3]); + if (argNodes[3] !== undefined) setTerminal(argNodes[3]); } else { - if (expr.arguments.nodes.length > 1) { + if (argNodes.length > 1) { lowerer.noLowering( - "createInterface with more than one argument", - expr.arguments.nodes[1]!, + `${what} with more than one argument`, + argNodes[1]!, "pass every option in the one options object", ); } diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index b829b6ddc..8bd5e57d7 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -18,8 +18,11 @@ import { superIntoResultSlot, } from "./constructor-returns.js"; import { checkedIterableSpread } from "./checked-iterable-spread.js"; -import { lowerReadlineUiNew } from "./builtins/readline.js"; -import { builtinMemberRequireDecl } from "./builtins/module-bindings.js"; +import { lowerReadlineInterfaceNew, lowerReadlineUiNew } from "./builtins/readline.js"; +import { + builtinMemberBindingTarget, + builtinMemberRequireDecl, +} from "./builtins/module-bindings.js"; import { checkedClassUnionAssertion } from "./class-assertions.js"; import { collectClassMethodMutations } from "./class-method-mutations.js"; import { InternalCompilerError } from "../../errors.js"; @@ -9819,7 +9822,7 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { } const worker = lowerWorkerNew(lowerer, expr); if (worker) return worker; - const readlineUi = lowerReadlineUiNew(lowerer, expr); + const readlineUi = lowerReadlineUiNew(lowerer, expr) ?? lowerReadlineInterfaceNew(lowerer, expr); if (readlineUi) return readlineUi; const channel = lowerMessageChannelNew(lowerer, expr) ?? lowerBroadcastChannelNew(lowerer, expr); if (channel) return channel; @@ -10132,7 +10135,12 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { // (a no-op for every non-import= binding). if (ts.isIdentifier(expr.expression)) fenceEarlyAliasUse(lowerer, expr.expression, expr); const identifier = ts.isIdentifier(expr.expression) ? expr.expression : expr.expression.name; - const symbol = ts.isIdentifier(identifier) ? lowerer.resolveValueSymbol(identifier) : null; + // `const SD = require("string_decoder").StringDecoder; new SD()` + // constructs the member, as a named import of it does. + const symbol = builtinMemberBindingTarget( + lowerer, + ts.isIdentifier(identifier) ? lowerer.resolveValueSymbol(identifier) : null, + ); if (ts.isIdentifier(identifier) && lowerer.isStdlibGlobal(identifier, "Array")) { return lowerArrayConstructor(lowerer, expr, expr.arguments?.nodes ?? []); } diff --git a/packages/compiler/src/frontend/tsc-codes.ts b/packages/compiler/src/frontend/tsc-codes.ts index e6c0be7cd..8816615cf 100644 --- a/packages/compiler/src/frontend/tsc-codes.ts +++ b/packages/compiler/src/frontend/tsc-codes.ts @@ -128,6 +128,12 @@ export const JS_RELAXED_TSC_CODES: ReadonlySet = new Set([ // JavaScript subclasses may widen fields or add method parameters. // Class lowering checks native storage and override ABIs at each use. 2415, + // a private or protected constructor (`new readline.Interface(...)`, + // whose declaration is protected): JavaScript has no constructor + // accessibility, and Node constructs the class. Each `new` meets the + // lowerer's per-site constructor fences. + 2673, + 2674, // unresolvable modules: Node throws WHEN the require executes — the // binding types as any and reached uses fence instead of passing unchecked 2307, diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8230-readline-interface-constructor.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8230-readline-interface-constructor.cjs.json new file mode 100644 index 000000000..05573974c --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8230-readline-interface-constructor.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8230-readline-interface-constructor.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8231-builtin-member-binding-new.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8231-builtin-member-binding-new.cjs.json new file mode 100644 index 000000000..1f54f4886 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8231-builtin-member-binding-new.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8231-builtin-member-binding-new.cjs" + ], + "diags": [] +} diff --git a/tests/corpus/8230-readline-interface-constructor.cjs b/tests/corpus/8230-readline-interface-constructor.cjs new file mode 100644 index 000000000..6d7eea0e4 --- /dev/null +++ b/tests/corpus/8230-readline-interface-constructor.cjs @@ -0,0 +1,51 @@ +// `new readline.Interface(...)`: Node's createInterface calls this +// constructor with the same arguments, and a JavaScript file may call it +// directly. Its declaration is protected, which JavaScript does not +// enforce. +"use strict"; +const readline = require("readline"); +const readlinePromises = require("readline/promises"); +const { Interface } = require("readline"); +const { PassThrough } = require("stream"); + +// The options form. +const a = new PassThrough(); +const rlA = new readline.Interface({ input: a, terminal: false }); +console.log("instanceof", rlA instanceof readline.Interface); +const linesA = []; +rlA.on("line", (line) => { + linesA.push(line); +}); +rlA.on("close", () => { + console.log("options", JSON.stringify(linesA)); +}); +a.write("one\ntwo\n"); +a.end("three"); + +// The positional form, through a destructured binding. +const b = new PassThrough(); +const outB = new PassThrough(); +const rlB = new Interface(b, outB); +const linesB = []; +rlB.on("line", (line) => { + linesB.push(line); +}); +rlB.on("close", () => { + console.log("positional", JSON.stringify(linesB)); +}); +b.write("four\r\nfive\n"); +b.end(); + +// readline/promises' Interface. +const c = new PassThrough(); +const rlC = new readlinePromises.Interface({ input: c, crlfDelay: Infinity }); +console.log("promises instanceof", rlC instanceof readlinePromises.Interface); +const linesC = []; +rlC.on("line", (line) => { + linesC.push(line); +}); +rlC.on("close", () => { + console.log("promises", JSON.stringify(linesC)); +}); +c.end("six\nseven"); + diff --git a/tests/corpus/8231-builtin-member-binding-new.cjs b/tests/corpus/8231-builtin-member-binding-new.cjs new file mode 100644 index 000000000..1549425f7 --- /dev/null +++ b/tests/corpus/8231-builtin-member-binding-new.cjs @@ -0,0 +1,35 @@ +// `new` of a builtin class bound through a member of a require() result +// (`const SD = require("string_decoder").StringDecoder`, the spelling of +// Node's own tests): the binding resolves to the class, as the +// destructured `const { StringDecoder } = require(...)` does. +"use strict"; +const SD = require("string_decoder").StringDecoder; +const Readable = require("stream").Readable; +const PassThrough = require("stream").PassThrough; +const Transform = require("stream").Transform; + +const decoder = new SD("utf8"); +console.log(decoder.encoding); +console.log(JSON.stringify(decoder.write(Buffer.from([0xe2, 0x82])))); +console.log(decoder.end(Buffer.from([0xac]))); +const hex = new SD("hex"); +console.log(hex.encoding, hex.write(Buffer.from("hi"))); +console.log(new SD().encoding); + +const r = new Readable({ read() {} }); +r.on("data", (chunk) => console.log("readable", String(chunk))); +r.on("end", () => console.log("readable end")); +r.push("abc"); +r.push(null); + +const p = new PassThrough(); +p.on("data", (chunk) => console.log("passthrough", String(chunk))); +p.end("xyz"); + +const upper = new Transform({ + transform(chunk, encoding, callback) { + callback(null, String(chunk).toUpperCase()); + }, +}); +upper.on("data", (chunk) => console.log("transform", String(chunk))); +upper.end("shout"); diff --git a/tests/harness/corpus-costs/8230-readline-interface-constructor.cjs.json b/tests/harness/corpus-costs/8230-readline-interface-constructor.cjs.json new file mode 100644 index 000000000..9b459042f --- /dev/null +++ b/tests/harness/corpus-costs/8230-readline-interface-constructor.cjs.json @@ -0,0 +1 @@ +{ "plain": 3500, "san": 3000 } diff --git a/tests/harness/corpus-costs/8231-builtin-member-binding-new.cjs.json b/tests/harness/corpus-costs/8231-builtin-member-binding-new.cjs.json new file mode 100644 index 000000000..54e11997a --- /dev/null +++ b/tests/harness/corpus-costs/8231-builtin-member-binding-new.cjs.json @@ -0,0 +1 @@ +{ "plain": 2500, "san": 2500 } From 21570a963c24d3170cc09f823058cb47cc3ec867 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 07:07:20 -0500 Subject: [PATCH 084/259] Cut repeated work in LLVM module emission Emitting the LLVM text of large programs spent seconds rebuilding the same sets, rescanning the finished text and walking every function for passes that change a few of them. The output is unchanged. - computeMayThrow builds the set of temporal-dead-zone globals once per module instead of copying it into a new set for every function. - limitInlineReleases finds the release sites of every family in one walk over the module text, and rewrites only the parts that hold a function over its limit. - The mentioned-function and node:test checks of parking analysis scan the text with indexOf instead of global regular expressions. - resolveSelfCaptures rewrites only the functions it changes, specializeCallbackCalls appends to its write lists instead of copying them and counts nodes in a walk it already makes, and CaptureFlow reuses one callback for nested statements. --- .../src/backend/llvm/emit-function.ts | 6 +- packages/compiler/src/backend/llvm/emitter.ts | 28 ++++++- .../compiler/src/backend/llvm/shapes.test.ts | 16 ++++ packages/compiler/src/backend/llvm/shapes.ts | 80 +++++++++++-------- packages/compiler/src/backend/may-throw.ts | 19 +++-- .../src/ir/callback-specialization.ts | 27 +++++-- packages/compiler/src/ir/capture-values.ts | 6 +- packages/compiler/src/ir/self-captures.ts | 5 ++ 8 files changed, 133 insertions(+), 54 deletions(-) diff --git a/packages/compiler/src/backend/llvm/emit-function.ts b/packages/compiler/src/backend/llvm/emit-function.ts index 8f306035a..d7efafd36 100644 --- a/packages/compiler/src/backend/llvm/emit-function.ts +++ b/packages/compiler/src/backend/llvm/emit-function.ts @@ -1307,8 +1307,10 @@ export function emitArgPackAndTrampolinePrologue( * code. */ export function parkingFunctions(emitter: LlEmitter): Set | null { if (emitter.wasi || emitter.mod.workers === true) return null; - for (const decl of emitter.decls) if (/@scr_test_sub\b/.test(decl)) return null; - for (const text of emitter.fnDefText.values()) if (/@scr_test_sub\b/.test(text)) return null; + const testSub = (text: string): boolean => + text.includes("@scr_test_sub") && /@scr_test_sub\b/.test(text); + for (const decl of emitter.decls) if (testSub(decl)) return null; + for (const text of emitter.fnDefText.values()) if (testSub(text)) return null; // Reverse mention edges, then propagate "may park" to every mentioner. const mentionedBy = new Map>(); const parks = new Set(); diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 6760f3b74..0de85d477 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -598,6 +598,16 @@ export function llStrBytes(text: string): string { const NO_BORROWED: ReadonlySet = new Set(); +/** [A-Za-z0-9_] */ +function isIdentifierByte(code: number): boolean { + return ( + (code >= 48 && code <= 57) || + (code >= 65 && code <= 90) || + (code >= 97 && code <= 122) || + code === 95 + ); +} + /** Runtime entry points (and await-call entries) that may park the running * execution context, as they appear in emitted function text. */ export const SUSPENDS = @@ -2235,9 +2245,23 @@ export class LlEmitter { this.mangledFunctions.set(mangleBorrowedFunction(fn.name), fn.name); } } - for (const match of text.matchAll(/@(sc_b?f_[A-Za-z0-9_]+)/g)) { - const callee = this.mangledFunctions.get(match[1]!); + // The names `@(sc_b?f_[A-Za-z0-9_]+)` matches, found with indexOf. + for (let at = text.indexOf("@sc_"); at >= 0;) { + let start = at + 4; + if (text.charCodeAt(start) === 98 /* b */) start++; + if (text.charCodeAt(start) !== 102 /* f */ || text.charCodeAt(start + 1) !== 95 /* _ */) { + at = text.indexOf("@sc_", at + 1); + continue; + } + let end = start + 2; + while (end < text.length && isIdentifierByte(text.charCodeAt(end))) end++; + if (end === start + 2) { + at = text.indexOf("@sc_", at + 1); + continue; + } + const callee = this.mangledFunctions.get(text.slice(at + 1, end)); if (callee !== undefined) yield callee; + at = text.indexOf("@sc_", end); } } diff --git a/packages/compiler/src/backend/llvm/shapes.test.ts b/packages/compiler/src/backend/llvm/shapes.test.ts index 7af16ab83..f91ee2f58 100644 --- a/packages/compiler/src/backend/llvm/shapes.test.ts +++ b/packages/compiler/src/backend/llvm/shapes.test.ts @@ -280,6 +280,22 @@ describe("inline release budgets", () => { ); }); + test("each family's budget applies to its own sites in a function that has both", () => { + const strings = body("mixed", INLINE_STR_RELEASES_PER_FUNCTION + 1, "str"); + // One function: string sites over their budget, dyn sites within theirs. + const mixed = strings.replace( + " ret void", + ` call void @sc_rc_release_dyn(ptr %v)\n call void @sc_rc_release_other(ptr %v)\n ret void`, + ); + const other = body("other", 2, "str"); + const limited = limitInlineReleases([mixed, other], "release").join("\n"); + const out = limited.slice(0, limited.indexOf("@other(")); + expect(out).not.toContain("@sc_rc_release_str("); + expect(out).toContain("call void @sc_rc_release_dyn(ptr %v)"); + expect(out).toContain("call void @sc_rc_release_other(ptr %v)"); + expect(limited).toContain(other); + }); + test("a function over the string budget calls the runtime string release at every site", () => { const small = body("small", INLINE_STR_RELEASES_PER_FUNCTION, "str"); const large = body("large", INLINE_STR_RELEASES_PER_FUNCTION + 1, "str"); diff --git a/packages/compiler/src/backend/llvm/shapes.ts b/packages/compiler/src/backend/llvm/shapes.ts index b3f5084d3..2c851b462 100644 --- a/packages/compiler/src/backend/llvm/shapes.ts +++ b/packages/compiler/src/backend/llvm/shapes.ts @@ -692,34 +692,32 @@ export function limitInlineReleases( parts: readonly string[], mode: InlineRcMode | undefined, ): string[] { - const dyn = limitInlineReleaseFamily(parts, "dyn", INLINE_DYN_RELEASES_PER_FUNCTION); - return mode === "release" - ? limitInlineReleaseFamily(dyn, "str", INLINE_STR_RELEASES_PER_FUNCTION) - : dyn; -} - -function limitInlineReleaseFamily( - parts: readonly string[], - family: "dyn" | "str", - max: number, -): string[] { - const call = `call void @${inlineRcName(family, "release")}(`; - const runtime = `call void @${INLINE_RC_FAMILIES[family]!.release}(`; + const families: readonly ("dyn" | "str")[] = mode === "release" ? ["dyn", "str"] : ["dyn"]; + const limits = families.map((family) => + family === "dyn" ? INLINE_DYN_RELEASES_PER_FUNCTION : INLINE_STR_RELEASES_PER_FUNCTION, + ); + const calls = families.map((family) => `${inlineRcName(family, "release")}(`); + const runtimes = families.map((family) => `call void @${INLINE_RC_FAMILIES[family]!.release}(`); + const head = "call void @"; + const prefix = `${head}${inlineRcName("", "release")}`; // The function each release site belongs to: the last `define` line - // before it, counted over the joined text. + // before it, counted over the joined text. One walk over each part finds + // the sites of every family. const sites = ( part: string, - each: (offset: number, fn: number) => void, + each: (offset: number, family: number, fn: number) => void, first: number, ): number => { let fn = first; let define = part.startsWith("define ") ? 0 : part.indexOf("\ndefine "); - for (let at = part.indexOf(call); at >= 0; at = part.indexOf(call, at + call.length)) { + for (let at = part.indexOf(prefix); at >= 0; at = part.indexOf(prefix, at + prefix.length)) { + const family = calls.findIndex((call) => part.startsWith(call, at + head.length)); + if (family < 0) continue; while (define >= 0 && define < at) { fn++; define = part.indexOf("\ndefine ", define + 1); } - each(at, fn); + each(at, family, fn); } while (define >= 0) { fn++; @@ -727,29 +725,47 @@ function limitInlineReleaseFamily( } return fn; }; - const counts = new Map(); + const counts = families.map(() => new Map()); + // The functions each part's sites can belong to. + const spans: number[] = []; let fn = 0; - for (const part of parts) fn = sites(part, (_, f) => counts.set(f, (counts.get(f) ?? 0) + 1), fn); - const over = new Set([...counts].filter(([, n]) => n > max).map(([f]) => f)); - if (over.size === 0) return [...parts]; - fn = 0; - return parts.map((part) => { - const cuts: number[] = []; + for (const part of parts) { + spans.push(fn); fn = sites( part, - (at, f) => { - if (over.has(f)) cuts.push(at); - }, + (_, family, f) => counts[family]!.set(f, (counts[family]!.get(f) ?? 0) + 1), fn, ); + spans.push(fn); + } + const over = counts.map( + (count, family) => new Set([...count].filter(([, n]) => n > limits[family]!).map(([f]) => f)), + ); + if (over.every((set) => set.size === 0)) return [...parts]; + const anyOver = new Set(over.flatMap((set) => [...set])); + const touches = (from: number, to: number): boolean => { + for (let f = from; f <= to; f++) if (anyOver.has(f)) return true; + return false; + }; + return parts.map((part, index) => { + const from = spans[2 * index]!; + if (!touches(from, spans[2 * index + 1]!)) return part; + const cuts: { at: number; family: number }[] = []; + sites( + part, + (at, family, f) => { + if (over[family]!.has(f)) cuts.push({ at, family }); + }, + from, + ); if (cuts.length === 0) return part; let out = ""; - let from = 0; - for (const at of cuts) { - out += part.slice(from, at) + runtime; - from = at + call.length; + let next = 0; + for (const cut of cuts) { + out += part.slice(next, cut.at) + runtimes[cut.family]!; + next = cut.at + head.length + calls[cut.family]!.length; } - return out + part.slice(from); + return out + part.slice(next); }); } diff --git a/packages/compiler/src/backend/may-throw.ts b/packages/compiler/src/backend/may-throw.ts index 0cfab9244..693d20b3b 100644 --- a/packages/compiler/src/backend/may-throw.ts +++ b/packages/compiler/src/backend/may-throw.ts @@ -93,7 +93,7 @@ export function computeMayThrow( const classes = new Map((mod.classes ?? []).map((cls) => [cls.name, cls])); const constructorClasses = new Map(); const classValueCallers = new Map>(); - const tdzGlobals = (mod.globals ?? []).filter((g) => g.tdz).map((g) => g.id); + const tdzGlobals = new Set((mod.globals ?? []).filter((g) => g.tdz).map((g) => g.id)); for (const cls of mod.classes ?? []) { constructorClasses.set(`%${cls.name}.constructor`, cls.name); for (const m of cls.methods ?? []) { @@ -113,11 +113,10 @@ export function computeMayThrow( if (explain) f.calleeLocs = new Map(); // TDZ reads and non-initializing writes can throw ReferenceError. // Capture locals carry the same flag as the declaring binding. - const tdzIds = new Set([...tdzGlobals, ...fn.locals.filter((l) => l.tdz).map((l) => l.id)]); - const mutableTdzIds = new Set([ - ...tdzGlobals, - ...fn.locals.filter((l) => l.tdz && l.mutable).map((l) => l.id), - ]); + // Every TDZ global counts for both reads and writes; the module's set is + // shared by every function. + const tdzLocals = new Set(fn.locals.filter((l) => l.tdz).map((l) => l.id)); + const mutableTdzLocals = new Set(fn.locals.filter((l) => l.tdz && l.mutable).map((l) => l.id)); // Traverse typed executable nodes without copying the IR into unknown. const visit = (rec: IrExpr | IrStmt): boolean => { const threw = f.throws; @@ -133,13 +132,17 @@ export function computeMayThrow( case "varRef": case "incDec": case "assignExpr": - if (tdzIds.has(rec.localId)) f.throws = true; + if (tdzGlobals.has(rec.localId) || tdzLocals.has(rec.localId)) f.throws = true; break; case "assign": // A declaration is allowed to fill an empty box. Legacy const // TDZ stores also initialize; only mutable subsequent stores // introduce the new write-side exception edge. - if (rec.initializes !== true && mutableTdzIds.has(rec.localId)) f.throws = true; + if ( + rec.initializes !== true && + (tdzGlobals.has(rec.localId) || mutableTdzLocals.has(rec.localId)) + ) + f.throws = true; break; case "dynCheck": case "caughtCheck": diff --git a/packages/compiler/src/ir/callback-specialization.ts b/packages/compiler/src/ir/callback-specialization.ts index 6038ccaa5..4764754af 100644 --- a/packages/compiler/src/ir/callback-specialization.ts +++ b/packages/compiler/src/ir/callback-specialization.ts @@ -130,10 +130,7 @@ export function specializeCallbackCalls( const { written, closureWritten } = rebindings(mod); const copies = new Map(); const candidates = new Map(); - let totalNodes = 0; for (const fn of mod.functions) { - const nodes = countNodes(fn); - totalNodes += nodes; if ( !(fn.ownsPrototype || fn.name.startsWith("%arr.")) || fn.name === mod.entry || @@ -142,10 +139,11 @@ export function specializeCallbackCalls( fn.captures !== undefined || fn.classCaptures?.length || fn.fastRead !== undefined || - fn.speculativeDispatch || - nodes > MAX_FUNCTION_NODES + fn.speculativeDispatch ) continue; + const nodes = countNodes(fn); + if (nodes > MAX_FUNCTION_NODES) continue; const rebound = written.get(fn.name)!; const slots: number[] = []; fn.params.forEach((param, index) => { @@ -165,19 +163,30 @@ export function specializeCallbackCalls( const definitions = new Map>(); const globalIds = new Set(mod.globals?.map((global) => global.id)); const globalWrites = new Map(); + // The sum of countNodes over every function, counted by the walk below. + let totalNodes = 0; for (const fn of mod.functions) { + let nodes = 0; const values = new Map(); const counts = new Map(); const record = (id: string, value: IrExpr | null, weight: number): void => { counts.set(id, (counts.get(id) ?? 0) + weight); - if (value) values.set(id, [...(values.get(id) ?? []), value]); + if (value) { + const list = values.get(id); + if (list === undefined) values.set(id, [value]); + else list.push(value); + } }; everyStmtList(fn.body, { stmt: (stmt) => { + nodes++; if (stmt.kind === "varDecl") record(stmt.localId, stmt.init, stmt.init ? 1 : 0); if (stmt.kind === "assign") { - if (globalIds.has(stmt.localId)) - globalWrites.set(stmt.localId, [...(globalWrites.get(stmt.localId) ?? []), stmt.value]); + if (globalIds.has(stmt.localId)) { + const list = globalWrites.get(stmt.localId); + if (list === undefined) globalWrites.set(stmt.localId, [stmt.value]); + else list.push(stmt.value); + } record(stmt.localId, stmt.value, 1); } if (stmt.kind === "forOf") record(stmt.localId, null, 2); @@ -186,6 +195,7 @@ export function specializeCallbackCalls( return true; }, expr: (expr) => { + nodes++; if (expr.kind === "assignExpr" || expr.kind === "incDec") { record(expr.localId, null, 2); if (globalIds.has(expr.localId)) globalWrites.set(expr.localId, []); @@ -208,6 +218,7 @@ export function specializeCallbackCalls( ) single.set(id, list[0]!); definitions.set(fn.name, single); + totalNodes += Math.min(nodes, MAX_FUNCTION_NODES + 1); } const globalDefinitions = new Map(); for (const global of mod.globals ?? []) diff --git a/packages/compiler/src/ir/capture-values.ts b/packages/compiler/src/ir/capture-values.ts index 779ca1b76..bcc587f1b 100644 --- a/packages/compiler/src/ir/capture-values.ts +++ b/packages/compiler/src/ir/capture-values.ts @@ -538,7 +538,7 @@ export class CaptureFlow { facts.callees.add(e.callee.localId); break; } - return everyExprChild(e, expr, (s) => stmt(s, false)); + return everyExprChild(e, expr, nested); }; // `split` mirrors rewrite(): only statement lists reached through // ordinary nesting from the body are expanded. Switch cases share one @@ -599,8 +599,10 @@ export class CaptureFlow { list(s.body, split) ); } - return everyStmtChild(s, expr, (child) => stmt(child, false)); + return everyStmtChild(s, expr, nested); }; + // Statements nested in expressions and in other statements' heads. + const nested = (s: IrStmt): boolean => stmt(s, false); list(fn.body, true); return facts; } diff --git a/packages/compiler/src/ir/self-captures.ts b/packages/compiler/src/ir/self-captures.ts index e009e9a11..74f634d4a 100644 --- a/packages/compiler/src/ir/self-captures.ts +++ b/packages/compiler/src/ir/self-captures.ts @@ -118,7 +118,12 @@ export function resolveSelfCaptures(mod: IrModule): IrModule { } if (resolved.size === 0) return mod; + // Only the resolved bodies and the functions that create their closures + // change. + const touched = new Set(resolved.keys()); + for (const name of resolved.keys()) for (const site of sites.get(name)!) touched.add(site.owner); const rewritten = mod.functions.map((fn) => { + if (!touched.has(fn.name)) return fn; const own = resolved.get(fn.name); const self = own === undefined ? null : fn.captures![own]!; let changed = false; From a5eca18f1eb62446a109069f75aae5077683d9e5 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 07:22:00 -0500 Subject: [PATCH 085/259] Read fs.promises as a module, end CommonJS entries at a top-level return, and check fs read and write arguments as Node does fs.promises read as a member of the fs module (a binding, an inline require('fs').promises, destructuring) is the node:fs/promises namespace, as in Node. It failed at run time before. A return at the top level of the entry CommonJS module ends its evaluation, as in Node's module wrapper: preflight admits TS1108 in CommonJS JavaScript files. A CommonJS module the program requires with a top-level return is refused with SC1090, because the exports assigned after the return would stay undefined, which their storage cannot hold. fs.ReadStream(...) and fs.WriteStream(...) called without new construct their stream, as Node's stream constructors do. fs.read, fs.readSync and fs.write check their arguments in Node's order and with Node's errors: the fd, the buffer, the offset, `length |= 0`, number and bigint positions (validatePosition), the empty-buffer error and the buffer window. fs.read accepts a Proxy options object. A readSync call whose JavaScript arguments are untyped or bigint takes the same checks at run time (fs.readSyncDyn). fs.write threw no error for an invalid fd, offset or length before. --- .../compiler/src/backend/llvm/lib-shared.ts | 1 + .../lowering/builtins/filesystem-calls.ts | 24 +- .../frontend/lowering/builtins/fs-streams.ts | 31 ++- .../lowering/builtins/module-bindings.ts | 4 +- .../src/frontend/lowering/lower-calls.ts | 10 +- .../src/frontend/lowering/lower-modules.ts | 36 +++ .../compiler/src/frontend/lowering/lowerer.ts | 11 +- packages/compiler/src/frontend/program.ts | 22 +- packages/compiler/src/ir/builtin-effects.ts | 1 + .../compiler/src/ir/builtin-signatures.ts | 1 + .../corpus/8270-fs-promises-member.cjs.json | 6 + .../corpus/8271-cjs-top-level-return.cjs.json | 6 + .../8272-fs-stream-call-without-new.cjs.json | 6 + ...273-fs-read-write-argument-checks.cjs.json | 6 + .../main.js.json | 7 + packages/runtime/src/scr_bytes.h | 2 + packages/runtime/src/scr_bytes_io.c | 244 ++++++++++++++---- packages/runtime/src/scr_lib.c | 40 +-- tests/corpus/8270-fs-promises-member.cjs | 25 ++ tests/corpus/8271-cjs-top-level-return.cjs | 20 ++ .../8272-fs-stream-call-without-new.cjs | 21 ++ .../8273-fs-read-write-argument-checks.cjs | 69 +++++ .../cjs-required-top-level-return/lib.js | 5 + .../cjs-required-top-level-return/main.js | 8 + .../package.json | 3 + .../cjs-required-top-level-return/main.js.txt | 6 + .../8270-fs-promises-member.cjs.json | 1 + .../8271-cjs-top-level-return.cjs.json | 1 + .../8272-fs-stream-call-without-new.cjs.json | 1 + ...273-fs-read-write-argument-checks.cjs.json | 1 + 30 files changed, 551 insertions(+), 68 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8270-fs-promises-member.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8271-cjs-top-level-return.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8272-fs-stream-call-without-new.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8273-fs-read-write-argument-checks.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/cjs-required-top-level-return/main.js.json create mode 100644 tests/corpus/8270-fs-promises-member.cjs create mode 100644 tests/corpus/8271-cjs-top-level-return.cjs create mode 100644 tests/corpus/8272-fs-stream-call-without-new.cjs create mode 100644 tests/corpus/8273-fs-read-write-argument-checks.cjs create mode 100644 tests/diagnostics/cjs-required-top-level-return/lib.js create mode 100644 tests/diagnostics/cjs-required-top-level-return/main.js create mode 100644 tests/diagnostics/cjs-required-top-level-return/package.json create mode 100644 tests/harness/__snapshots__/cjs-required-top-level-return/main.js.txt create mode 100644 tests/harness/corpus-costs/8270-fs-promises-member.cjs.json create mode 100644 tests/harness/corpus-costs/8271-cjs-top-level-return.cjs.json create mode 100644 tests/harness/corpus-costs/8272-fs-stream-call-without-new.cjs.json create mode 100644 tests/harness/corpus-costs/8273-fs-read-write-argument-checks.cjs.json diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 7a16c37e8..40daa8205 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -523,6 +523,7 @@ export const LIB_FN_SYMS: Record = { "fs.openSync": "scr_fs_open", "fs.openNumericSync": "scr_fs_open_numeric", "fs.readSync": "scr_fs_read_sync", + "fs.readSyncDyn": "scr_fs_read_sync_dyn", "fs.writeSync": "scr_fs_write_sync", "fs.writeStrSync": "scr_fs_write_str_sync", "fs.closeSync": "scr_fs_close", diff --git a/packages/compiler/src/frontend/lowering/builtins/filesystem-calls.ts b/packages/compiler/src/frontend/lowering/builtins/filesystem-calls.ts index 0bbc3b3fa..6b5e2d8ae 100644 --- a/packages/compiler/src/frontend/lowering/builtins/filesystem-calls.ts +++ b/packages/compiler/src/frontend/lowering/builtins/filesystem-calls.ts @@ -2,7 +2,7 @@ import { dynUndefinedExpr, boolLit, numLit, varRef } from "../../../ir/build.js" import * as ts from "../../ts7/adapter.js"; import { type Lowerer } from "../lowerer.js"; import { lowerFsPath } from "./fs-paths.js"; -import { locOf } from "../../program.js"; +import { isJsSourceFile, locOf } from "../../program.js"; import { type BuiltinModuleFn, FS_WRITE_FILE_DOCUMENTED_OPTIONS, @@ -403,6 +403,28 @@ export function lowerFsReadSyncCall( } lowerer.noLowering("readSync with a non-literal options argument", optionsNode, supported); } + // JavaScript arguments outside the typed signature (an untyped fd or + // buffer, a bigint or untyped position) take Node's argument checks at + // run time, then the same read. + if (isJsSourceFile(ts.getSourceFileOfNode(expr))) { + const nodes = expr.arguments.nodes; + const typed = [F64, BYTES_U8, F64, F64, F64].every((want, i) => { + const node = nodes[i]; + if (node === undefined) return true; + let value: ts.Expression = node; + while (ts.isParenthesizedExpression(value)) value = value.expression; + if (i === 4 && value.kind === ts.SyntaxKind.NullKeyword) return true; + const t = lowerer.mapTypeOf(lowerer.typeOf(node)); + return t !== null && (want.kind === "bytes" ? t.kind === "bytes" : t.kind === "f64"); + }); + if (!typed) { + const args = [0, 1, 2, 3, 4].map((i): IrExpr => { + const node = nodes[i]; + return node === undefined ? dynUndefinedExpr(loc) : lowerer.lowerExprExpecting(node, DYN); + }); + return { kind: "libCall", fn: "fs.readSyncDyn", args, type: F64, loc }; + } + } const args: IrExpr[] = [ lowerer.lowerExprExpecting(expr.arguments.nodes[0]!, F64), lowerer.lowerExprExpecting(expr.arguments.nodes[1]!, BYTES_U8), diff --git a/packages/compiler/src/frontend/lowering/builtins/fs-streams.ts b/packages/compiler/src/frontend/lowering/builtins/fs-streams.ts index 498f9b6d4..6c6f8fa79 100644 --- a/packages/compiler/src/frontend/lowering/builtins/fs-streams.ts +++ b/packages/compiler/src/frontend/lowering/builtins/fs-streams.ts @@ -4,7 +4,7 @@ * and everything inherited goes through the stream spoke. */ import * as ts from "../../ts7/adapter.js"; import { type Lowerer } from "../lowerer.js"; -import { locOf } from "../../program.js"; +import { isJsSourceFile, locOf } from "../../program.js"; import { isNodeTypesPath } from "../../dts-paths.js"; import { dynUndefinedExpr } from "../../../ir/build.js"; import { @@ -178,3 +178,32 @@ export function lowerFsStreamNew( locOf(expr), ); } + +/** `fs.ReadStream(path, options)` / `fs.WriteStream(...)` called without + * `new` in JavaScript: Node's stream constructors construct when called as + * functions, so the call is the `new` form. Null for other calls. */ +export function lowerFsStreamCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr | null { + if (!isJsSourceFile(ts.getSourceFileOfNode(expr))) return null; + const callee = expr.expression; + const name = ts.isPropertyAccessExpression(callee) + ? callee.name + : ts.isIdentifier(callee) + ? callee + : null; + if (name === null || !ts.isIdentifier(name)) return null; + const symbol = lowerer.checker.getSymbolAtLocation(name); + const resolved = + symbol && symbol.flags & ts.SymbolFlags.Alias + ? lowerer.checker.getAliasedSymbol(symbol) + : symbol; + const cls = fsStreamClassOf(lowerer, resolved); + if (cls === null) return null; + return fsStreamCreateExpr( + lowerer, + expr.arguments.nodes, + cls === "ReadStream", + `fs.${cls}`, + expr, + locOf(expr), + ); +} diff --git a/packages/compiler/src/frontend/lowering/builtins/module-bindings.ts b/packages/compiler/src/frontend/lowering/builtins/module-bindings.ts index 5465aeafa..5bac5651a 100644 --- a/packages/compiler/src/frontend/lowering/builtins/module-bindings.ts +++ b/packages/compiler/src/frontend/lowering/builtins/module-bindings.ts @@ -213,7 +213,9 @@ export function builtinNamespaceDestructureModuleOf( if (ts.isCallExpression(init)) { const cr = createRequireSpecOf(lowerer, init); module = cr !== null && cr.spec !== null ? canonicalBuiltinModule(cr.spec) : null; - } else if (ts.isIdentifier(init)) { + } else if (ts.isIdentifier(init) || ts.isPropertyAccessExpression(init)) { + // `const { open } = fs.promises` / `= require("fs").promises`: a member + // that is itself a supported module. module = lowerer.builtinNamespaceModuleOf(init); } if (module === null) return null; diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 14565aebc..884c106b7 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -24,7 +24,11 @@ import { import { lowerMockTimersElementCall } from "./lower-test.js"; import { objectEnumerationReceiver } from "./object-enumeration-receiver.js"; import { InternalCompilerError } from "../../errors.js"; -import { isFsStreamMember, lowerFsStreamMethodCall } from "./builtins/fs-streams.js"; +import { + isFsStreamMember, + lowerFsStreamCall, + lowerFsStreamMethodCall, +} from "./builtins/fs-streams.js"; import * as ts from "../ts7/adapter.js"; import { isZlibStreamMember, @@ -375,6 +379,10 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { const buffer = lowerBufferConstruct(lowerer, expr); if (buffer) return { kind: "dynFrom", value: buffer, type: DYN, loc }; } + { + const stream = lowerFsStreamCall(lowerer, expr); + if (stream) return stream; + } // A package shim's runtime intrinsic (a bodiless `declare function` // named scriptcUnixDgram* in a shipped shim): a direct runtime call. if (ts.isIdentifier(expr.expression) && isShimIntrinsicName(expr.expression.text)) { diff --git a/packages/compiler/src/frontend/lowering/lower-modules.ts b/packages/compiler/src/frontend/lowering/lower-modules.ts index 19f7243ed..5c30c2250 100644 --- a/packages/compiler/src/frontend/lowering/lower-modules.ts +++ b/packages/compiler/src/frontend/lowering/lower-modules.ts @@ -1346,6 +1346,25 @@ export function collectGlobals( // "m.". const rawTag = lowerer.fileTag.get(sf) ?? ""; const tag = rawTag === "" ? "e." : rawTag.replace(/^%/, ""); + // A `return` at the top level of a CommonJS module ends its evaluation + // (preflight admits it). In the entry module that ends the program's + // top-level code. A module the program requires would leave the exports + // assigned after the return undefined, which its typed export storage + // cannot hold, so it is refused there. + if (rawTag !== "" && isJsSourceFile(sf)) { + const early = topLevelReturnOf(sf); + if (early !== null) { + try { + lowerer.unsupported( + "SC1090", + early, + "top-level return statements in CommonJS modules the program requires (only the entry module can end its evaluation early)", + ); + } catch (e) { + if (!(e instanceof PoisonError)) throw e; + } + } + } // Expando function members (`foo.bar = 12` anywhere in the file) // register their module globals first — reads inside function bodies // collected earlier in this pass must resolve them (lower-expando.ts). @@ -3579,3 +3598,20 @@ export function buildMain(lowerer: Lowerer): IrFunction { loc, }; } + +/** The first `return` statement at the top level of `sf` (outside every + * function body and class), which a CommonJS module may contain. */ +function topLevelReturnOf(sf: ts.SourceFile): ts.ReturnStatement | null { + let found: ts.ReturnStatement | null = null; + const visit = (node: ts.Node): void => { + if (found !== null || ts.isFunctionLike(node)) return; + if (ts.isClassDeclaration(node) || ts.isClassExpression(node)) return; + if (ts.isReturnStatement(node)) { + found = node; + return; + } + ts.forEachChild(node, visit); + }; + for (const stmt of sf.statements.nodes) visit(stmt); + return found; +} diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 78980d322..eb7928dd4 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -13766,7 +13766,7 @@ export class Lowerer { if ( ts.isPropertyAccessExpression(expr) && !expr.questionDotToken && - ts.isIdentifier(expr.expression) + (ts.isIdentifier(expr.expression) || requireSpecOf(expr.expression) !== null) ) { const outer = this.builtinNamespaceModuleOf(expr.expression); if (outer === null) return null; @@ -13971,6 +13971,15 @@ export class Lowerer { `library functions as values (call '${ts.getTextOfNode(expr)}' directly)`, ); } + // A member that is a supported module in its own right (`fs.promises` + // is node:fs/promises, as in Node) reads as that module's namespace. + { + const sub = this.builtinNamespaceModuleOf(expr); + if (sub !== null) { + const type: IrType = { kind: "moduleNs", moduleId: `builtin:${sub}` }; + return { kind: "moduleNsRef", moduleId: type.moduleId, type, loc }; + } + } this.noLowering( `${bi.module}.${bi.member}`, expr, diff --git a/packages/compiler/src/frontend/program.ts b/packages/compiler/src/frontend/program.ts index bf75127c4..f9be2b832 100644 --- a/packages/compiler/src/frontend/program.ts +++ b/packages/compiler/src/frontend/program.ts @@ -1379,9 +1379,16 @@ function suppressedJsStrictness7(d: ts.Diagnostic): boolean { return ts.flattenDiagnosticMessageText(d, "\n").includes("'any'"); } // The deprecated Buffer(...) call without `new`, which Node's Buffer - // function accepts (containers/bytes.ts lowers it). + // function accepts (containers/bytes.ts lowers it), and fs.ReadStream(...) + // and fs.WriteStream(...), which construct their stream + // (builtins/fs-streams.ts). if (d.code === 2348) { - return ts.flattenDiagnosticMessageText(d, "\n").includes("'BufferConstructor'"); + const text = ts.flattenDiagnosticMessageText(d, "\n"); + return ( + text.includes("'BufferConstructor'") || + text.includes("'typeof ReadStream'") || + text.includes("'typeof WriteStream'") + ); } return false; } @@ -5358,6 +5365,16 @@ function preflight7(load: LoadResult): { return new RegExp(`\\btypeof\\s*\\(?\\s*${name.replace(/\$/g, "\\$")}(?![\\w$])`).test(sf.text); }; + /** A CommonJS file runs inside Node's module wrapper function, so a + * `return` at its top level ends the module's evaluation (TS1108 in a + * plain script). The lowering ends the module initializer there. */ + const cjsTopLevelReturnSuppressed = (p: ts.Program, d: ts.Diagnostic): boolean => { + if (d.code !== 1108 || d.fileName === undefined || !isJsSourceFileName(d.fileName)) + return false; + const sf = p.getSourceFile(d.fileName); + return sf !== undefined && isCjsJsFile(sf, p); + }; + const workspaceImplicitAnySuppressed = (p: ts.Program, d: ts.Diagnostic): boolean => { if (d.code !== 7016 || d.fileName === undefined || d.pos === undefined || d.end === undefined) return false; @@ -5404,6 +5421,7 @@ function preflight7(load: LoadResult): { !isNpmStaticSubclassArgument(p, d) && !workspaceImplicitAnySuppressed(p, d) && !typeofTestedNameSuppressed(p, d) && + !cjsTopLevelReturnSuppressed(p, d) && !jsdocTypeSuppressed(p, d, commentDup), ); }; diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index 390c7fbc3..fb24f6596 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -1028,6 +1028,7 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "fs.openSync", "fs.openNumericSync", "fs.readSync", + "fs.readSyncDyn", "fs.writeSync", "fs.writeStrSync", "fs.closeSync", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 216e46a4d..a1d969667 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -1195,6 +1195,7 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "fs.openSync": { argTypes: [STRING, STRING], result: F64 }, "fs.openNumericSync": { argTypes: [STRING, F64, F64], result: F64 }, "fs.readSync": { argTypes: [F64, BYTES_U8, F64, F64, F64], result: F64 }, + "fs.readSyncDyn": { argTypes: [DYN, DYN, DYN, DYN, DYN], result: F64 }, "fs.writeSync": { argTypes: [F64, BYTES_U8, F64, F64, F64], result: F64 }, "fs.writeStrSync": { argTypes: [F64, STRING, F64, STRING], result: F64 }, // fs.watch's callback func type is program-dependent (zero params, or diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8270-fs-promises-member.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8270-fs-promises-member.cjs.json new file mode 100644 index 000000000..eb3938040 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8270-fs-promises-member.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8270-fs-promises-member.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8271-cjs-top-level-return.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8271-cjs-top-level-return.cjs.json new file mode 100644 index 000000000..2fcecbe67 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8271-cjs-top-level-return.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8271-cjs-top-level-return.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8272-fs-stream-call-without-new.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8272-fs-stream-call-without-new.cjs.json new file mode 100644 index 000000000..7fdb114e4 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8272-fs-stream-call-without-new.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8272-fs-stream-call-without-new.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8273-fs-read-write-argument-checks.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8273-fs-read-write-argument-checks.cjs.json new file mode 100644 index 000000000..60e64d369 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8273-fs-read-write-argument-checks.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8273-fs-read-write-argument-checks.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/cjs-required-top-level-return/main.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/cjs-required-top-level-return/main.js.json new file mode 100644 index 000000000..d8eeb4f76 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/diagnostics/cjs-required-top-level-return/main.js.json @@ -0,0 +1,7 @@ +{ + "order": [ + "/tests/diagnostics/cjs-required-top-level-return/lib.js", + "/tests/diagnostics/cjs-required-top-level-return/main.js" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_bytes.h b/packages/runtime/src/scr_bytes.h index 7c0a935cc..6efb970f8 100644 --- a/packages/runtime/src/scr_bytes.h +++ b/packages/runtime/src/scr_bytes.h @@ -524,6 +524,8 @@ ScrDyn *scr_fs_lchmod_sync_chk(const ScrDyn *path, const ScrDyn *mode); ScrPromise *scr_fsp_lchmod_chk(const ScrDyn *path, const ScrDyn *mode); void scr_fs_read_chk(const ScrDyn *fd, const ScrDyn *buffer, const ScrDyn *offset, const ScrDyn *length, const ScrDyn *position, const ScrStr *fence); +double scr_fs_read_sync_dyn(const ScrDyn *fd, const ScrDyn *buffer, const ScrDyn *offset, + const ScrDyn *length, const ScrDyn *position); void scr_fs_stream_opts_chk(const ScrDyn *path, const ScrDyn *opts, const ScrStr *fence); /* The fs streams' option pieces (scr_fs_stream.c): the getOptions, * options.fd and path checks above without the fence; the checked path diff --git a/packages/runtime/src/scr_bytes_io.c b/packages/runtime/src/scr_bytes_io.c index 253cad1da..bebc2a479 100644 --- a/packages/runtime/src/scr_bytes_io.c +++ b/packages/runtime/src/scr_bytes_io.c @@ -638,6 +638,8 @@ void scr_fs_cb_schedule(const ScrDyn *callback, ScrDyn *result, const ScrDyn *bu static bool scr_fs_read_validate(const ScrDyn *, const ScrDyn *, const ScrDyn *, const ScrDyn *, const ScrDyn *); static bool scr_fs_encoding_chk(const ScrDyn *); static bool scr_fs_int_range_chk(const ScrDyn *, const char *, double, double, const char *); +static bool scr_fs_length_int32(const ScrDyn *, double *); +static bool scr_fs_write_validate(const ScrDyn *, const ScrDyn *, const ScrDyn *); static bool scr_fs_mode_chk(const ScrDyn *, const char *); /* Where Node's signature handling finds the callback: a fixed position, or @@ -856,7 +858,7 @@ static ScrDyn *scr_fs_cb_invoke(ScrStr *member, ScrDyn *const *args, size_t argc * (below); every other form checks it here, before its path. */ bool late = !strcmp(op, "access") || !strcmp(op, "copyFile") || !strcmp(op, "chmod") || !strcmp(op, "open") || !strcmp(op, "mkdir") || !strcmp(op, "fchmod") || !strcmp(op, "ftruncate") || !strcmp(op, "truncate") || - !strcmp(op, "read"); + !strcmp(op, "read") || !strcmp(op, "write"); if (!late && !scr_fs_cb_chk(callback, legacy ? "callback" : "cb")) { scr_arr_release(vectors); return NULL; } size_t count = timestamp ? argc : slot < argc ? slot : argc; #define ARG(index) scr_fs_cb_arg(args, count, index) @@ -889,7 +891,8 @@ static ScrDyn *scr_fs_cb_invoke(ScrStr *member, ScrDyn *const *args, size_t argc const ScrDyn *params = count == 3 ? ARG(2) : scr_dyn_bytes_is(ARG(1), SCR_BYTES_U8) ? NULL : ARG(1); bool object = !params || scr_fs_dyn_absent(params) || params->kind == SCR_DYN_OBJ || params->kind == SCR_DYN_BYTES || - (params->kind == SCR_DYN_TYPED_REF && !scr_dyn_ref_is_array(params)); + (params->kind == SCR_DYN_TYPED_REF && !scr_dyn_ref_is_array(params)) || + (params->kind == SCR_DYN_PROXY && scr_dyn_is_object(params)); if (!object) { scr_dyn_arg_type_fail("options", "of type object", params); return NULL; @@ -902,6 +905,22 @@ static ScrDyn *scr_fs_cb_invoke(ScrStr *member, ScrDyn *const *args, size_t argc if (!scr_fs_cb_chk(callback, "cb")) return NULL; } if (!strcmp(op, "read") && count >= 4 && !scr_fs_read_validate(ARG(0), ARG(1), ARG(2), ARG(3), ARG(4))) return NULL; + /* write checks its fd first, then the buffer form's callback, offset and + * length (validateOffsetLengthWrite), or the string form's data and + * callback. */ + if (!strcmp(op, "write")) { + if (!scr_fs_int_range_chk(ARG(0), "fd", 0, 2147483647.0, ">= 0 && <= 2147483647")) return NULL; + if (ARG(1)->kind == SCR_DYN_BYTES) { + if (!scr_fs_cb_chk(callback, "cb") || !scr_fs_write_validate(ARG(1), ARG(2), ARG(3))) return NULL; + } else { + if (ARG(1)->kind != SCR_DYN_STR) { + scr_dyn_arg_type_fail("buffer", "of type string or an instance of Buffer, TypedArray, or DataView", + ARG(1)); + return NULL; + } + if (!scr_fs_cb_chk(callback, "cb")) return NULL; + } + } bool descriptor = timestamp_fd || vector || newControl || !strcmp(op, "close") || !strcmp(op, "fstat") || !strcmp(op, "fsync") || !strcmp(op, "read") || !strcmp(op, "write") || !strcmp(op, "fchown"); /* truncate checks len, then the callback, before the open its request * starts with. */ @@ -1100,7 +1119,10 @@ static ScrDyn *scr_fs_cb_invoke(ScrStr *member, ScrDyn *const *args, size_t argc return NULL; } else { double offset = ownedBuffer ? scr_fs_cb_option_number(options, "offset", 0) : scr_fs_cb_number(ARG(2), "offset", 0); - double length = ownedBuffer ? scr_fs_cb_option_number(options, "length", bytes->len - offset) : scr_fs_cb_number(ARG(3), "length", bytes->len - offset); + double length = bytes->len - offset; + if (ownedBuffer) length = scr_fs_cb_option_number(options, "length", length); + else if (readOp && count >= 4) scr_fs_length_int32(ARG(3), &length); + else length = scr_fs_cb_number(ARG(3), "length", length); double position = ownedBuffer ? scr_fs_cb_option_number(options, "position", -1) : scr_fs_cb_number(ARG(4), "position", -1); if (!scr_exc_pending()) result = scr_dyn_new_num(readOp ? scr_fs_read_sync(fd, bytes, offset, length, position) : scr_fs_write_sync(fd, bytes, offset, length, position)); } @@ -1877,68 +1899,134 @@ static bool scr_fs_int_range_chk(const ScrDyn *v, const char *name, double min, return true; } -static bool scr_fs_read_validate(const ScrDyn *fd, const ScrDyn *buffer, const ScrDyn *offset, - const ScrDyn *length, const ScrDyn *position) { - if (buffer->kind != SCR_DYN_BYTES) { - scr_dyn_arg_type_fail("buffer", "an instance of Buffer, TypedArray, or DataView", buffer); +/* `length |= 0`: ToInt32 of the length argument (a non-numeric value is + * 0). False with the exception pending when ToNumber throws. */ +static bool scr_fs_length_int32(const ScrDyn *length, double *out) { + double n; + if (length->kind == SCR_DYN_NUM) { + n = length->v.num; + } else if (!scr_dyn_number_coerce_js(length, &n)) { return false; } + if (!isfinite(n)) { + *out = 0; + return true; + } + double m = fmod(trunc(n), 4294967296.0); + if (m < 0) m += 4294967296.0; + *out = m >= 2147483648.0 ? m - 4294967296.0 : m; + return true; +} + +/* A bigint read position in [-1n, 2n ** 63n - 1n - BigInt(length)] + * (validatePosition); false with ERR_OUT_OF_RANGE pending otherwise. The + * received value groups the digits past 2^32 in threes, as Node's + * ERR_OUT_OF_RANGE does for bigints. */ +static bool scr_fs_bigint_position_chk(ScrBigInt *position, double length) { + ScrBigInt *top = scr_bigint_from_i64(INT64_MAX); + ScrBigInt *span = scr_bigint_from_f64(length); + ScrBigInt *max = scr_bigint_sub(top, span); + scr_bigint_release(top); + scr_bigint_release(span); + ScrBigInt *low = scr_bigint_from_i64(-1); + bool ok = scr_bigint_cmp_f64(position, low) >= 0 && scr_bigint_cmp_f64(position, max) <= 0; + scr_bigint_release(low); + if (ok) { + scr_bigint_release(max); + return true; + } + ScrStr *limit = scr_bigint_to_string(max, 10); + scr_bigint_release(max); + ScrStr *decimal = scr_bigint_to_string(position, 10); + if (!limit || !decimal) { + if (limit) scr_str_release(limit); + if (decimal) scr_str_release(decimal); + return false; + } + ScrBigInt *bound = scr_bigint_from_i64((int64_t)1 << 32); + ScrBigInt *negBound = scr_bigint_from_i64(-((int64_t)1 << 32)); + bool group = scr_bigint_cmp_f64(position, bound) > 0 || scr_bigint_cmp_f64(position, negBound) < 0; + scr_bigint_release(bound); + scr_bigint_release(negBound); + /* addNumericalSeparator: underscores every three digits from the right, + * after an optional sign. */ + char digits[200]; + size_t len = decimal->len < 120 ? decimal->len : 120, out = 0; + size_t start = len > 0 && decimal->data[0] == '-' ? 1 : 0; + for (size_t i = 0; i < len; i++) { + if (group && i > start && (len - i) % 3 == 0) digits[out++] = '_'; + digits[out++] = (char)decimal->data[i]; + } + digits[out] = '\0'; + char msg[384]; + int n = snprintf(msg, sizeof msg, + "The value of \"position\" is out of range. It must be >= -1 && <= %.*s. Received %sn", + (int)limit->len, (const char *)limit->data, digits); + scr_str_release(limit); + scr_str_release(decimal); + scr_throw_error_msg_code(SCR_ERR_RANGE, msg, n < 0 ? 0 : (size_t)n, "ERR_OUT_OF_RANGE"); + return false; +} + + +/* fs.read(fd, buffer, offset, length, position, cb)'s argument checks, in + * Node's order: the fd, the buffer, the offset (an integer >= 0), the + * length as `length |= 0`, the position (validatePosition, against that + * length), then for a non-empty read the empty-buffer and + * validateOffsetLengthRead checks. */ +static bool scr_fs_read_validate(const ScrDyn *fd, const ScrDyn *buffer, const ScrDyn *offset, + const ScrDyn *length, const ScrDyn *position) { if (fd->kind != SCR_DYN_NUM) { scr_dyn_arg_type_fail("fd", "of type number", fd); return false; } + if (buffer->kind != SCR_DYN_BYTES) { + scr_dyn_arg_type_fail("buffer", "an instance of Buffer, TypedArray, or DataView", buffer); + return false; + } double buflen = scr_bytes_byte_len(buffer->v.bytes); + double off = 0; if (!scr_fs_dyn_absent(offset)) { - /* validateInteger's MAX_SAFE range first, the buffer bound second — - * Node renders each with its own max. */ if (!scr_fs_int_range_chk(offset, "offset", 0, 9007199254740991.0, ">= 0 && <= 9007199254740991")) { return false; } - if (offset->v.num > buflen) { - char range[64]; - snprintf(range, sizeof range, ">= 0 && <= %.0f", buflen); - if (!scr_fs_int_range_chk(offset, "offset", 0, buflen, range)) return false; - } + off = offset->v.num; } + double count = 0; + if (!scr_fs_length_int32(length, &count)) return false; if (!scr_fs_dyn_absent(position)) { - if (position->kind != SCR_DYN_NUM) { + if (position->kind == SCR_DYN_BIGINT) { + if (!scr_fs_bigint_position_chk(position->v.bigint, count)) return false; + } else if (position->kind != SCR_DYN_NUM) { scr_dyn_arg_type_fail("position", "of type bigint or integer", position); return false; - } - if (!scr_fs_int_range_chk(position, "position", -1, 9007199254740991.0, - ">= -1 && <= 9007199254740991")) { + } else if (!scr_fs_int_range_chk(position, "position", -1, 9007199254740991.0, + ">= -1 && <= 9007199254740991")) { return false; } } - double off = offset->kind == SCR_DYN_NUM ? offset->v.num : 0; - if (!scr_fs_dyn_absent(length)) { - if (length->kind != SCR_DYN_NUM || !(isfinite(length->v.num) && trunc(length->v.num) == length->v.num) || - length->v.num < 0) { - /* Node renders the bare ">= 0" form here (checkPosition's cousin). */ - if (length->kind == SCR_DYN_NUM) { - char recv[48], msg[160]; - scr_num_received(length->v.num, recv); - const char *shape = (isfinite(length->v.num) && trunc(length->v.num) == length->v.num) - ? "It must be >= 0." - : "It must be an integer."; - int len = snprintf(msg, sizeof msg, - "The value of \"length\" is out of range. %s Received %s", shape, recv); - scr_throw_error_msg_code(SCR_ERR_RANGE, msg, (size_t)len, "ERR_OUT_OF_RANGE"); - return false; - } - scr_dyn_arg_type_fail("length", "of type number", length); - return false; - } - if (length->v.num > buflen - off) { - char recv[48], msg[160]; - scr_num_received(length->v.num, recv); - int len = snprintf(msg, sizeof msg, - "The value of \"length\" is out of range. It must be <= %.0f. Received %s", - buflen - off, recv); - scr_throw_error_msg_code(SCR_ERR_RANGE, msg, (size_t)len, "ERR_OUT_OF_RANGE"); - return false; + if (count == 0) return true; + if (buflen == 0) { + if (scr_bytes_is_buffer(buffer->v.bytes)) { + static const char empty[] = + "The argument 'buffer' is empty and cannot be written. Received "; + scr_throw_error_msg_code(SCR_ERR_TYPE, empty, sizeof empty - 1, "ERR_INVALID_ARG_VALUE"); + } else { + scr_dyn_arg_value_fail("buffer", "is empty and cannot be written", buffer); } + return false; + } + if (count < 0 || off + count > buflen) { + char recv[48], range[64], msg[192]; + scr_num_received(count, recv); + if (count < 0) snprintf(range, sizeof range, ">= 0"); + else snprintf(range, sizeof range, "<= %.0f", buflen - off); + int len = snprintf(msg, sizeof msg, + "The value of \"length\" is out of range. It must be %s. Received %s", range, + recv); + scr_throw_error_msg_code(SCR_ERR_RANGE, msg, (size_t)len, "ERR_OUT_OF_RANGE"); + return false; } return true; } @@ -1991,3 +2079,69 @@ bool scr_fs_stream_mode(const ScrDyn *value, double *mode) { } return scr_fs_cb_file_mode(value, "mode", mode); } + +/* fs.readSync(fd, buffer, offset, length[, position]) with arguments the + * compiler could not type (JavaScript): Node's checks (validateBuffer + * first, then the fd, the offset, `length |= 0` and the position, which + * may be a bigint), then the typed read. */ +double scr_fs_read_sync_dyn(const ScrDyn *fd, const ScrDyn *buffer, const ScrDyn *offset, + const ScrDyn *length, const ScrDyn *position) { + if (buffer->kind != SCR_DYN_BYTES) { + scr_dyn_arg_type_fail("buffer", "an instance of Buffer, TypedArray, or DataView", buffer); + return 0; + } + if (!scr_fs_read_validate(fd, buffer, offset, length, position)) return 0; + double count = 0; + if (!scr_fs_length_int32(length, &count)) return 0; + if (count == 0) return 0; + double at = scr_fs_dyn_absent(position) ? -1 + : position->kind == SCR_DYN_BIGINT ? scr_bigint_to_f64(position->v.bigint) + : position->v.num; + ScrBytes *bytes = scr_dyn_bytes_unbox(buffer); + double read = scr_fs_read_sync(fd->v.num, bytes, scr_fs_dyn_absent(offset) ? 0 : offset->v.num, + count, at); + scr_bytes_release(bytes); + return read; +} + +/* ERR_OUT_OF_RANGE for the number `n` of argument `name`. Always false. */ +static bool scr_fs_num_range_fail(const char *name, const char *range, double n) { + char recv[48], msg[192]; + scr_num_received(n, recv); + int len = snprintf(msg, sizeof msg, "The value of \"%s\" is out of range. It must be %s. Received %s", + name, range, recv); + scr_throw_error_msg_code(SCR_ERR_RANGE, msg, (size_t)len, "ERR_OUT_OF_RANGE"); + return false; +} + +/* fs.write(fd, buffer, offset, length, position, cb)'s buffer checks: the + * offset (an integer >= 0 unless omitted, null or the callback), a + * non-number length defaulting to the rest of the buffer, then + * validateOffsetLengthWrite. An options object in the offset slot is read + * by the write itself. */ +static bool scr_fs_write_validate(const ScrDyn *buffer, const ScrDyn *offset, const ScrDyn *length) { + if (offset->kind == SCR_DYN_OBJ || offset->kind == SCR_DYN_TYPED_REF || offset->kind == SCR_DYN_PROXY || + offset->kind == SCR_DYN_NULL) + return true; + double buflen = scr_bytes_byte_len(buffer->v.bytes); + double off = 0; + if (!scr_fs_dyn_absent(offset) && offset->kind != SCR_DYN_FUNC) { + if (!scr_fs_int_range_chk(offset, "offset", 0, 9007199254740991.0, ">= 0 && <= 9007199254740991")) + return false; + off = offset->v.num; + } + double len = length->kind == SCR_DYN_NUM ? length->v.num : buflen - off; + char range[64]; + if (off > buflen) { + snprintf(range, sizeof range, "<= %.0f", buflen); + return scr_fs_num_range_fail("offset", range, off); + } + if (len > buflen - off) { + snprintf(range, sizeof range, "<= %.0f", buflen - off); + return scr_fs_num_range_fail("length", range, len); + } + if (len < 0) return scr_fs_num_range_fail("length", ">= 0", len); + if (!(isfinite(len) && trunc(len) == len)) return scr_fs_num_range_fail("length", "an integer", len); + if (len > 2147483647.0) return scr_fs_num_range_fail("length", ">= 0 && <= 2147483647", len); + return true; +} diff --git a/packages/runtime/src/scr_lib.c b/packages/runtime/src/scr_lib.c index fb3524c81..b7deae018 100644 --- a/packages/runtime/src/scr_lib.c +++ b/packages/runtime/src/scr_lib.c @@ -4236,27 +4236,35 @@ double scr_fs_read_sync(double fd, ScrBytes *buf, double offset, double length, scr_throw_error_msg_code(SCR_ERR_RANGE, msg, (size_t)mlen, "ERR_OUT_OF_RANGE"); return 0; } - /* Node returns after the offset and position validation when the - * requested length normalizes to zero: buffer-window bounds and fd are - * not consulted. Preserve the existing size_t coercion's [0, 1) case. */ - if (length >= 0 && length < 1) return 0; - if (offset > (double)bytelen) { - numbuf[scr_f64_to_str(offset, numbuf)] = 0; + /* `length |= 0`, then Node's order: a zero length reads nothing after + * the offset and position checks; otherwise the buffer must not be + * empty and the window must fit it (validateOffsetLengthRead). */ + if (!isfinite(length)) { + length = 0; + } else { + double wrapped = fmod(trunc(length), 4294967296.0); + if (wrapped < 0) wrapped += 4294967296.0; + length = wrapped >= 2147483648.0 ? wrapped - 4294967296.0 : wrapped; + } + if (length == 0) return 0; + if (bytelen == 0) { + static const char empty[] = + "The argument 'buffer' is empty and cannot be written. Received "; + scr_throw_error_msg_code(SCR_ERR_TYPE, empty, sizeof empty - 1, "ERR_INVALID_ARG_VALUE"); + return 0; + } + if (length < 0 || offset + length > (double)bytelen) { + char recv[48], range[48]; + scr_num_received(length, recv); + if (length < 0) snprintf(range, sizeof range, ">= 0"); + else snprintf(range, sizeof range, "<= %.0f", (double)bytelen - offset); mlen = snprintf(msg, sizeof msg, - "The value of \"offset\" is out of range. It must be >= 0 && <= 9007199254740991. Received %s", - numbuf); + "The value of \"length\" is out of range. It must be %s. Received %s", range, + recv); scr_throw_error_msg_code(SCR_ERR_RANGE, msg, (size_t)mlen, "ERR_OUT_OF_RANGE"); return 0; } size_t off = (size_t)offset; - if (length < 0 || (double)length > (double)(bytelen - off)) { - numbuf[scr_f64_to_str(length, numbuf)] = 0; - mlen = snprintf(msg, sizeof msg, - "The value of \"length\" is out of range. It must be <= %zu. Received %s", - bytelen - off, numbuf); - scr_throw_error_msg_code(SCR_ERR_RANGE, msg, (size_t)mlen, "ERR_OUT_OF_RANGE"); - return 0; - } size_t want = (size_t)length; uint8_t *bounce = buf->shared ? malloc(want ? want : 1) : NULL; if (buf->shared && !bounce) scr_trap("scriptc: out of memory\n"); diff --git a/tests/corpus/8270-fs-promises-member.cjs b/tests/corpus/8270-fs-promises-member.cjs new file mode 100644 index 000000000..86448f012 --- /dev/null +++ b/tests/corpus/8270-fs-promises-member.cjs @@ -0,0 +1,25 @@ +'use strict'; +// fs.promises is node:fs/promises, as in Node: through a binding, an +// inline require, destructuring and a direct member call. +const fs = require('fs'); +const path = require('path'); +const os = require('os'); + +const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'scriptc-fsp-')); +const file = path.join(dir, 'data.txt'); +const fsPromises = fs.promises; +const { readFile, stat } = require('fs').promises; +const { open } = fs.promises; + +(async () => { + await fsPromises.writeFile(file, 'abc'); + await fs.promises.appendFile(file, 'def'); + console.log(await readFile(file, 'utf8')); + console.log((await stat(file)).size); + const handle = await open(file, 'r'); + const { bytesRead, buffer } = await handle.read(Buffer.alloc(3), 0, 3, 1); + console.log(bytesRead, buffer.toString()); + await handle.close(); + await fsPromises.rm(dir, { recursive: true }); + console.log(fs.existsSync(dir)); +})(); diff --git a/tests/corpus/8271-cjs-top-level-return.cjs b/tests/corpus/8271-cjs-top-level-return.cjs new file mode 100644 index 000000000..9f5cc6d23 --- /dev/null +++ b/tests/corpus/8271-cjs-top-level-return.cjs @@ -0,0 +1,20 @@ +'use strict'; +// A return at the top level of the entry CommonJS module ends its +// evaluation, as in Node's module wrapper: from a block, a loop and a try +// statement, whose finally block still runs. +const fs = require('fs'); + +console.log('start'); +for (const name of ['a', 'b', 'c']) { + if (name === 'c') { + try { + console.log('returning at', name); + process.on('exit', (code) => console.log('exit', code)); + if (!fs.existsSync('/scriptc-missing-path')) return; + } finally { + console.log('finally runs'); + } + } + console.log('visited', name); +} +console.log('not reached'); diff --git a/tests/corpus/8272-fs-stream-call-without-new.cjs b/tests/corpus/8272-fs-stream-call-without-new.cjs new file mode 100644 index 000000000..91fe0a6c0 --- /dev/null +++ b/tests/corpus/8272-fs-stream-call-without-new.cjs @@ -0,0 +1,21 @@ +'use strict'; +// fs.ReadStream and fs.WriteStream called without new construct their +// stream, as in Node. +const fs = require('fs'); +const path = require('path'); +const os = require('os'); + +const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'scriptc-streams-')); +const target = path.join(dir, 'out.txt'); +const writer = fs.WriteStream(target); +writer.on('finish', () => { + const reader = fs.ReadStream(target, { encoding: 'utf8' }); + let text = ''; + reader.on('data', (chunk) => (text += chunk)); + reader.on('end', () => { + console.log(text); + fs.rmSync(dir, { recursive: true }); + }); +}); +writer.write('hello '); +writer.end('streams'); diff --git a/tests/corpus/8273-fs-read-write-argument-checks.cjs b/tests/corpus/8273-fs-read-write-argument-checks.cjs new file mode 100644 index 000000000..623d5286f --- /dev/null +++ b/tests/corpus/8273-fs-read-write-argument-checks.cjs @@ -0,0 +1,69 @@ +'use strict'; +// fs.read, fs.readSync and fs.write check their arguments in Node's order +// and with Node's errors: the fd, the buffer, the offset, `length |= 0`, +// number and bigint positions, and the buffer window. +const fs = require('fs'); +const path = require('path'); +const os = require('os'); + +const dir = fs.mkdtempSync(path.join(os.tmpdir(), 'scriptc-fs-args-')); +const file = path.join(dir, 'data.txt'); +fs.writeFileSync(file, 'abcdef'); +const fd = fs.openSync(file, 'r+'); +const noop = () => {}; + +function attempt(name, fn) { + try { + fn(); + console.log(name, 'ok'); + } catch (error) { + console.log(name, error.name, error.code, error.message); + } +} + +attempt('read offset -1', () => fs.read(fd, Buffer.alloc(3), -1, 3, 0, noop)); +attempt('read offset NaN', () => fs.read(fd, Buffer.alloc(3), NaN, 3, 0, noop)); +attempt('read length -1', () => fs.read(fd, Buffer.alloc(3), 0, -1, 0, noop)); +attempt('read length 4', () => fs.read(fd, Buffer.alloc(3), 0, 4, 0, noop)); +attempt('read length 1.5', () => fs.read(fd, Buffer.alloc(3), 0, 1.5, 0, noop)); +attempt('read length "x"', () => fs.read(fd, Buffer.alloc(3), 0, 'x', 0, noop)); +attempt('read position 1.5', () => fs.read(fd, Buffer.alloc(3), 0, 3, 1.5, noop)); +attempt('read position -2', () => fs.read(fd, Buffer.alloc(3), 0, 3, -2, noop)); +attempt('read position ""', () => fs.read(fd, Buffer.alloc(3), 0, 3, '', noop)); +attempt('read position 2n ** 63n', () => fs.read(fd, Buffer.alloc(3), 0, 3, 2n ** 63n, noop)); +attempt('read position -2n', () => fs.read(fd, Buffer.alloc(3), 0, 3, -2n, noop)); +attempt('read empty buffer', () => fs.read(fd, Buffer.alloc(0), 0, 1, 0, noop)); +attempt('read fd true', () => fs.read(true, Buffer.alloc(3), 0, 3, 0, noop)); +attempt('read buffer number', () => fs.read(fd, 3, 0, 3, 0, noop)); + +const read = (position) => { + const buffer = Buffer.alloc(3); + const count = fs.readSync(fd, buffer, 0, 3, position); + return `${count} ${buffer.toString()}`; +}; +attempt('readSync position 1n', () => console.log(read(1n))); +attempt('readSync position 0n', () => console.log(read(0n))); +attempt('readSync position 2n ** 63n', () => read(2n ** 63n)); +attempt('readSync offset 4', () => fs.readSync(fd, Buffer.alloc(3), 4, 1, 0)); +attempt('readSync buffer number', () => fs.readSync(fd, 3, 0, 1, 0)); +attempt('readSync fd null', () => fs.readSync(null, Buffer.alloc(3), 0, 1, 0)); +console.log(fs.readSync(fd, Buffer.alloc(3), 0, 0.5, 0), fs.readSync(fd, Buffer.alloc(3), 0, 2.5, 0)); + +attempt('write fd null', () => fs.write(null, Buffer.alloc(1), 0, 1, noop)); +attempt('write fd "1"', () => fs.write('1', 'x', noop)); +attempt('write offset -1', () => fs.write(fd, Buffer.alloc(0), -1, noop)); +attempt('write offset NaN', () => fs.write(fd, Buffer.from('abcd'), NaN, 4, 0, noop)); +attempt('write offset 5', () => fs.write(fd, Buffer.from('abcd'), 5, noop)); +attempt('write length 5', () => fs.write(fd, Buffer.from('abcd'), 0, 5, 0, noop)); +attempt('write length -1', () => fs.write(fd, Buffer.alloc(0), 0, -1, noop)); +attempt('write data number', () => fs.write(fd, 4, noop)); +attempt('write no callback', () => fs.write(fd, Buffer.from('a'), 0, 1, 0)); + +fs.read(fd, Buffer.alloc(2), 0, 2, 2n, (error, count, buffer) => { + console.log('read 2n', error, count, buffer.toString()); + fs.write(fd, Buffer.from('XY'), 0, 2, 0, (error2, written) => { + console.log('wrote', error2, written, fs.readFileSync(file, 'utf8')); + fs.closeSync(fd); + fs.rmSync(dir, { recursive: true }); + }); +}); diff --git a/tests/diagnostics/cjs-required-top-level-return/lib.js b/tests/diagnostics/cjs-required-top-level-return/lib.js new file mode 100644 index 000000000..62e017964 --- /dev/null +++ b/tests/diagnostics/cjs-required-top-level-return/lib.js @@ -0,0 +1,5 @@ +'use strict'; + +exports.ready = true; +if (process.env.SCRIPTC_SKIP_LIB === '1') return; +exports.value = 42; diff --git a/tests/diagnostics/cjs-required-top-level-return/main.js b/tests/diagnostics/cjs-required-top-level-return/main.js new file mode 100644 index 000000000..0b62093c2 --- /dev/null +++ b/tests/diagnostics/cjs-required-top-level-return/main.js @@ -0,0 +1,8 @@ +// A top-level return in a CommonJS module the program requires: the +// exports assigned after it may stay undefined, which the module's typed +// export storage cannot hold, so the return is refused. The entry module's +// own top-level return compiles (tests/corpus/8271-cjs-top-level-return.cjs). +'use strict'; + +const lib = require('./lib.js'); +console.log(lib.ready, lib.value); diff --git a/tests/diagnostics/cjs-required-top-level-return/package.json b/tests/diagnostics/cjs-required-top-level-return/package.json new file mode 100644 index 000000000..5bbefffba --- /dev/null +++ b/tests/diagnostics/cjs-required-top-level-return/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/tests/harness/__snapshots__/cjs-required-top-level-return/main.js.txt b/tests/harness/__snapshots__/cjs-required-top-level-return/main.js.txt new file mode 100644 index 000000000..db3d72b88 --- /dev/null +++ b/tests/harness/__snapshots__/cjs-required-top-level-return/main.js.txt @@ -0,0 +1,6 @@ +cjs-required-top-level-return/lib.js:4:43 - error SC1090: top-level return statements in CommonJS modules the program requires (only the entry module can end its evaluation early) are not supported yet + + 3 | exports.ready = true; + 4 | if (process.env.SCRIPTC_SKIP_LIB === '1') return; + | ^~~~~~~ + 5 | exports.value = 42; \ No newline at end of file diff --git a/tests/harness/corpus-costs/8270-fs-promises-member.cjs.json b/tests/harness/corpus-costs/8270-fs-promises-member.cjs.json new file mode 100644 index 000000000..04488e737 --- /dev/null +++ b/tests/harness/corpus-costs/8270-fs-promises-member.cjs.json @@ -0,0 +1 @@ +{ "plain": 4040, "san": 4008 } diff --git a/tests/harness/corpus-costs/8271-cjs-top-level-return.cjs.json b/tests/harness/corpus-costs/8271-cjs-top-level-return.cjs.json new file mode 100644 index 000000000..33a1c426c --- /dev/null +++ b/tests/harness/corpus-costs/8271-cjs-top-level-return.cjs.json @@ -0,0 +1 @@ +{ "plain": 1907, "san": 2109 } diff --git a/tests/harness/corpus-costs/8272-fs-stream-call-without-new.cjs.json b/tests/harness/corpus-costs/8272-fs-stream-call-without-new.cjs.json new file mode 100644 index 000000000..dab2504e6 --- /dev/null +++ b/tests/harness/corpus-costs/8272-fs-stream-call-without-new.cjs.json @@ -0,0 +1 @@ +{ "plain": 2099, "san": 2373 } diff --git a/tests/harness/corpus-costs/8273-fs-read-write-argument-checks.cjs.json b/tests/harness/corpus-costs/8273-fs-read-write-argument-checks.cjs.json new file mode 100644 index 000000000..1989bfb5f --- /dev/null +++ b/tests/harness/corpus-costs/8273-fs-read-write-argument-checks.cjs.json @@ -0,0 +1 @@ +{ "plain": 2379, "san": 2450 } From 5ad3576c1e71e49750ad854cb12b4a7be36b7d66 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 07:39:14 -0500 Subject: [PATCH 086/259] Hold a Map.get result as the entry's reference until the map can change A local initialized from Map.get of a reference value retained the value and released it at the end of its scope. In the common update const cur = counts.get(key); if (cur === undefined) counts.set(key, new Counter()); else cur.num++; the map is written only on the branch that does not read the local, so the entry keeps the value alive for every read. A stable local whose every use comes before any statement that may change a reference edge (ReferenceEffects) now holds the entry's own reference: no retain on the read and no release at scope exit. An if statement passes its condition's state to both branches and joins them; any other statement that names the local is judged whole. Number keys and inline string keys take this path, for nullable results and for the stack-boxed results of union locals. --- .../src/backend/llvm/emit-function.ts | 18 ++- .../src/backend/llvm/emit-statements.ts | 15 +- packages/compiler/src/backend/llvm/emitter.ts | 3 + .../src/backend/llvm/expr-containers.ts | 59 ++++++++ .../src/backend/llvm/map-number-lookup.ts | 25 ++-- .../backend/llvm/map-read-lifetimes.test.ts | 10 +- .../src/backend/llvm/map-read-lifetimes.ts | 96 ++++++++++++- .../test/map-get-borrow-emission.test.ts | 58 ++++++++ .../tests/corpus/8181-map-get-borrows.ts.json | 6 + tests/corpus/8181-map-get-borrows.ts | 130 ++++++++++++++++++ .../corpus-costs/8181-map-get-borrows.ts.json | 1 + 11 files changed, 405 insertions(+), 16 deletions(-) create mode 100644 packages/compiler/test/map-get-borrow-emission.test.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8181-map-get-borrows.ts.json create mode 100644 tests/corpus/8181-map-get-borrows.ts create mode 100644 tests/harness/corpus-costs/8181-map-get-borrows.ts.json diff --git a/packages/compiler/src/backend/llvm/emit-function.ts b/packages/compiler/src/backend/llvm/emit-function.ts index 8f306035a..4f04df59c 100644 --- a/packages/compiler/src/backend/llvm/emit-function.ts +++ b/packages/compiler/src/backend/llvm/emit-function.ts @@ -20,7 +20,12 @@ import { constructorClass } from "../../ir/final-fields.js"; import { findLoopArrayBorrows } from "./loop-array-borrows.js"; import { findCallArrayReads, findLocalArrayReads } from "./local-array-reads.js"; import { findScalarStringSlices, findScratchStringSlices } from "./string-slices.js"; -import { findMapReadLifetimes, findReadNumberMapWrites } from "./map-read-lifetimes.js"; +import { + findMapReadBorrows, + findMapReadLifetimes, + findReadNumberMapWrites, +} from "./map-read-lifetimes.js"; +import { borrowableMapGet } from "./expr-containers.js"; import { findMapEntryFusions } from "./map-entry-fusion.js"; import { findLocalStackUnions } from "./stack-unions.js"; import { findLocalStackObjects, findReassignedStackObjects } from "./stack-objects.js"; @@ -193,6 +198,17 @@ export function emitFunction(emitter: LlEmitter, fn: IrFunction): string { fn, emitter.boxedUnionsById, emitter.callLifetimes, + emitter.referenceEffects, + ); + const stable = emitter.callLifetimes.bindings.get(fn.name); + emitter.borrowedMapGets = findMapReadBorrows( + fn, + emitter.referenceEffects, + (decl) => + decl.init !== null && + stable?.has(decl.localId) === true && + !emitter.mapReadLifetimes.locals.has(decl.localId) && + borrowableMapGet(emitter, decl.init), ); emitter.readNumberMapWrites = findReadNumberMapWrites(fn); emitter.mapEntryFusion = emitter.debug === null ? findMapEntryFusions(fn) : null; diff --git a/packages/compiler/src/backend/llvm/emit-statements.ts b/packages/compiler/src/backend/llvm/emit-statements.ts index 55e31219c..fdcc54b55 100644 --- a/packages/compiler/src/backend/llvm/emit-statements.ts +++ b/packages/compiler/src/backend/llvm/emit-statements.ts @@ -32,7 +32,7 @@ import { allocateLocalUnion, storeLocalUnion } from "./local-union-storage.js"; import { boxAccess, boxNewCall, elemAccess } from "./shapes.js"; import { dynHoleRead } from "./loop-array-borrows.js"; import { endsWithJump, matchStringSelfConcat } from "../../ir/analysis.js"; -import { charAtUnitRead, emitDiscardedSplice } from "./expr-containers.js"; +import { charAtUnitRead, emitBorrowedMapGet, emitDiscardedSplice } from "./expr-containers.js"; import { InternalCompilerError } from "../../errors.js"; import { emitDenseArrayGet, @@ -104,6 +104,19 @@ export function emitStmtBody(emitter: LlEmitter, s: IrStmt): void { break; } const b = emitter.binding(s.localId); + if ( + emitter.borrowedMapGets.has(s.localId) && + b.kind === "local" && + s.init?.kind === "mapIntrinsic" + ) { + // The map entry's own reference: no retain now, no release at scope + // exit (findMapReadBorrows). + const borrowed = emitBorrowedMapGet(emitter, s.init); + if (borrowed) { + B.line(`store ptr ${borrowed.name}, ptr ${b.slot}`); + break; + } + } if (emitter.walkBorrows.has(s.localId) && b.kind === "local") { // A borrowed walk pointer: no retain now, no release at scope exit. const v = s.init === null ? "null" : emitter.emitReadReceiver(s.init).name; diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 6760f3b74..53cb99c9e 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -1145,6 +1145,9 @@ export class LlEmitter { readonly checkedNarrows: CheckedNarrows; callArrayReads = new Map(); mapReadLifetimes: MapReadLifetimes = { locals: new Map(), arguments: new Map() }; + /** Locals of the current function that hold a Map.get result as the + * entry's own reference (findMapReadBorrows, borrowableMapGet). */ + borrowedMapGets: ReadonlySet = new Set(); readNumberMapWrites: ReadonlySet = new Set(); /** The current function's fused string-key Map get-then-set pairs (map-entry-fusion.ts). */ mapEntryFusion: MapEntryFusion | null = null; diff --git a/packages/compiler/src/backend/llvm/expr-containers.ts b/packages/compiler/src/backend/llvm/expr-containers.ts index 279b8c044..906f03b76 100644 --- a/packages/compiler/src/backend/llvm/expr-containers.ts +++ b/packages/compiler/src/backend/llvm/expr-containers.ts @@ -1127,6 +1127,65 @@ export function emitArrIntrinsic( } } +/** Whether `e` is a Map.get that emitBorrowedMapGet can emit without a + * retain: a typed map with number or inline string keys, a reference value, + * and a nullable result (the value's pointer, or the absent arm's). */ +export function borrowableMapGet(host: LlvmEmitterContext, e: IrExpr): boolean { + if (e.kind !== "mapIntrinsic" || e.method !== "get" || e.args.length !== 1) return false; + if (!borrowsMapReadInputs(e) || e.receiver.type.kind !== "map") return false; + const { key, value } = e.receiver.type; + if (!isRefCounted(value) || value.kind === "union" || key.kind === "union") return false; + if (e.type.kind !== "union" || !host.nullableUnions.has(e.type.unionId)) return false; + const arg = e.args[0]!; + const access = mapKeyAccess(key); + return ( + (access === "f64" && arg.type.kind === "f64") || + (access === "str" && arg.type.kind === "string") + ); +} + +/** A borrowableMapGet read as the entry's own reference: no retain, and + * no owner. The caller proves that nothing can change the map while the + * value is used (findMapReadBorrows). Null, before emitting anything, for + * a key held as a split span, which takes the runtime's owned lookup. */ +export function emitBorrowedMapGet( + host: LlvmEmitterContext, + e: IrExpr & { kind: "mapIntrinsic" }, +): LlValue | null { + const arg = e.args[0]!; + if (arg.kind === "varRef" && host.splitSpans.get(arg.localId) !== undefined) return null; + const B = host.B; + const mapType = e.receiver.type as IrType & { kind: "map" }; + const r = host.emitStableReceiver(e.receiver, e.args); + const k = emitMapLookupKey(host, e.args[0]!, true); + const numberKey = inlineNumberKey(k); + const stringKey = entryStringKey(k); + const value = mapType.value; + let raw: string; + if (numberKey !== null) raw = emitNumberMapGetRef(host, r.name, numberKey, value, true); + else if (stringKey !== null) + raw = emitStringMapGetRef( + host, + r.name, + stringKey, + value, + compactMapValues(host, mapType.key, value), + true, + ); + else throw new InternalCompilerError("llvm emitter bug: borrowed Map.get without an inline key"); + const resultType = e.type as IrType & { kind: "union" }; + const absent = host.unitInstanceRef( + resultType.unionId, + undefinedArmTag(resultType, host.unionsById), + ); + if (absent === "null") return { name: raw, type: e.type }; + const isnull = B.tmp(), + t = B.tmp(); + B.line(`${isnull} = icmp eq ptr ${raw}, null`); + B.line(`${t} = select i1 ${isnull}, ptr ${absent}, ptr ${raw}`); + return { name: t, type: e.type }; +} + export function wrapNullable( host: LlvmEmitterContext, raw: string, diff --git a/packages/compiler/src/backend/llvm/map-number-lookup.ts b/packages/compiler/src/backend/llvm/map-number-lookup.ts index 6d219b50a..64bc3516e 100644 --- a/packages/compiler/src/backend/llvm/map-number-lookup.ts +++ b/packages/compiler/src/backend/llvm/map-number-lookup.ts @@ -122,14 +122,16 @@ export function emitStringMapGetScalar( } /** Map.get of a reference value: a +1 value, or null when absent — the - * contract of scr_map_get_f64_ref. */ + * contract of scr_map_get_f64_ref. `borrow`: the entry's own reference, + * without a retain, for a reader that finishes before the map can change. */ export function emitNumberMapGetRef( host: LlvmEmitterContext, map: string, key: string, value: IrType, + borrow = false, ): string { - return emitMapEntryGetRef(host, emitNumberMapEntry(host, map, key), value); + return emitMapEntryGetRef(host, emitNumberMapEntry(host, map, key), value, false, borrow); } /** Map.get of a reference value under a string key, with scr_map_get_str_ref's @@ -141,16 +143,25 @@ export function emitStringMapGetRef( key: string, value: IrType, compact = false, + borrow = false, ): string { - return emitMapEntryGetRef(host, emitStringMapEntry(host, map, key, compact), value, compact); + return emitMapEntryGetRef( + host, + emitStringMapEntry(host, map, key, compact), + value, + compact, + borrow, + ); } -/** The +1 value of a found entry, or null for a missing (null) entry. */ +/** The +1 value of a found entry (its own reference when `borrow`), or + * null for a missing (null) entry. */ function emitMapEntryGetRef( host: LlvmEmitterContext, entry: string, value: IrType, compact = false, + borrow = false, ): string { const B = host.B; const found = B.tmp(); @@ -160,10 +171,8 @@ function emitMapEntryGetRef( join = B.newLabel("mapn.join"); B.condBr(found, hit, miss); B.startBlock(hit); - const retained = host.retainFrame( - compact ? emitCompactMapSlot(host, entry) : emitNumberMapSlot(host, entry, "ptr"), - value, - ); + const loaded = compact ? emitCompactMapSlot(host, entry) : emitNumberMapSlot(host, entry, "ptr"); + const retained = borrow ? loaded : host.retainFrame(loaded, value); B.br(join); B.startBlock(miss); B.br(join); diff --git a/packages/compiler/src/backend/llvm/map-read-lifetimes.test.ts b/packages/compiler/src/backend/llvm/map-read-lifetimes.test.ts index 3725db060..d91e2b211 100644 --- a/packages/compiler/src/backend/llvm/map-read-lifetimes.test.ts +++ b/packages/compiler/src/backend/llvm/map-read-lifetimes.test.ts @@ -120,7 +120,12 @@ test("local map results keep scalar and owned reference payloads without heap wr expect(ir).toContain("call ptr @sc_map_entry_str("); expect(ir).not.toContain("@scr_map_get_"); } - if (value === STRING) expect(ir).toContain("@scr_str_release"); + // Nothing can change the map before the tag test, so a reference + // result is the entry's own (findMapReadBorrows): no retain or release. + if (value === STRING) { + expect(ir).not.toContain("@scr_str_retain"); + expect(ir).not.toContain("@scr_str_release"); + } } } }); @@ -132,7 +137,8 @@ test("nullable record results are the looked-up pointer itself on both ABIs", () expect(ir).not.toContain("%ScrUnion"); expect(ir).not.toContain("@scr_union_"); expect(ir).toMatch(/icmp (?:eq|ne) ptr %\w+, null/); - expect(ir).toContain("@sc_rrelease_"); + // The pointer is the entry's own reference until the tag test. + expect(ir).not.toContain("@sc_rrelease_"); } }); diff --git a/packages/compiler/src/backend/llvm/map-read-lifetimes.ts b/packages/compiler/src/backend/llvm/map-read-lifetimes.ts index 6b58d314a..0f22f9e05 100644 --- a/packages/compiler/src/backend/llvm/map-read-lifetimes.ts +++ b/packages/compiler/src/backend/llvm/map-read-lifetimes.ts @@ -9,6 +9,7 @@ import { } from "../../ir/ir.js"; import { everyExpr, everyStmt, everyStmtList } from "../../ir/traverse.js"; import type { CallLifetimes } from "./call-lifetimes.js"; +import type { ReferenceEffects } from "./reference-effects.js"; import type { LlValue, LlvmEmitterContext } from "./expr-context.js"; import { emitNumberMapGetRef, @@ -68,6 +69,10 @@ export function borrowsMapMutationReceiver(expr: IrExpr): boolean { export interface LocalMapRead { /** The Map.get expression itself. */ expr: IrExpr; + /** A local's reference result may stay the entry's own reference: every + * use of the local runs before anything that can change a reference + * edge (findMapReadBorrows), so the entry still holds the value. */ + borrowed?: boolean; type: IrType; receiver: IrExpr; key: IrExpr; @@ -126,6 +131,7 @@ export function findMapReadLifetimes( fn: IrFunction, unions: ReadonlyMap, lifetimes: CallLifetimes, + effects?: ReferenceEffects, ): MapReadLifetimes { const result: MapReadLifetimes = { locals: new Map(), arguments: new Map() }; if (fn.async || fn.generator) return result; @@ -150,6 +156,85 @@ export function findMapReadLifetimes( return true; }, }); + if (effects) { + const borrowed = findMapReadBorrows(fn, effects, (decl) => { + const read = result.locals.get(decl.localId); + return read !== undefined && isRefCounted(read.value); + }); + for (const id of borrowed) result.locals.get(id)!.borrowed = true; + } + return result; +} + +/** The locals, declared by statements `candidate` accepts, that can hold a + * map entry's own reference instead of a +1 copy. The statements after the + * declaration run in order, and every one that names the local must + * preserve reference edges (ReferenceEffects) and run before any statement + * that may not, so no write, deletion or unknown call can release the value + * while the local is read. An `if` passes its condition's state to both + * branches and joins them; any other statement that names the local is + * judged whole. A later pass of an enclosing loop declares the local again, + * so only the rest of its own statement list matters. An update such as + * `const c = m.get(k); if (c === undefined) m.set(k, v); else c.n++` keeps + * the borrow: the write runs only on the branch that does not read `c`. */ +export function findMapReadBorrows( + fn: IrFunction, + effects: ReferenceEffects, + candidate: (decl: IrStmt & { kind: "varDecl" }) => boolean, +): Set { + const result = new Set(); + if (fn.async || fn.generator) return result; + const names = (node: IrStmt | IrExpr, id: string, isStmt: boolean): boolean => { + let found = false; + const visitor = { + stmt: () => !found, + expr: (expr: IrExpr) => { + if (expr.kind === "varRef" && expr.localId === id) found = true; + return !found; + }, + }; + if (isStmt) everyStmt(node as IrStmt, visitor); + else everyExpr(node as IrExpr, visitor); + return found; + }; + // Whether an edge may have changed after `list`, or null when a statement + // names the local after such a change (or changes edges itself). + const walk = (list: readonly IrStmt[], id: string, changed: boolean): boolean | null => { + for (const stmt of list) { + if (stmt.kind === "if") { + const preserving = effects.preserves(stmt.cond); + if (names(stmt.cond, id, false) && (changed || !preserving)) return null; + const condition = changed || !preserving; + const then = walk(stmt.then, id, condition); + const otherwise = stmt.else_ === null ? condition : walk(stmt.else_, id, condition); + if (then === null || otherwise === null) return null; + changed = then || otherwise; + continue; + } + if (stmt.kind === "block") { + const inner = walk(stmt.body, id, changed); + if (inner === null) return null; + changed = inner; + continue; + } + const preserving = effects.preservesScope([stmt]); + if (names(stmt, id, true) && (changed || !preserving)) return null; + changed ||= !preserving; + } + return changed; + }; + const visit = (list: readonly IrStmt[]): void => { + list.forEach((stmt, index) => { + if ( + stmt.kind === "varDecl" && + candidate(stmt) && + walk(list.slice(index + 1), stmt.localId, false) !== null + ) + result.add(stmt.localId); + for (const nested of nestedStmtLists(stmt)) visit(nested); + }); + }; + visit(fn.body); return result; } @@ -303,13 +388,14 @@ export function emitStackMapRead(host: LlvmEmitterContext, read: LocalMapRead): let owner: StackMapRead["owner"] = null; const number = inlineNumberKey(key); const string = entryStringKey(key); + const borrow = read.borrowed === true; if (number !== null) { if (isRefCounted(read.value)) { - const raw = emitNumberMapGetRef(host, receiver.name, number, read.value); + const raw = emitNumberMapGetRef(host, receiver.name, number, read.value, borrow); B.line(`${found} = icmp ne ptr ${raw}, null`); B.line(`store i64 0, ptr ${payload}`); B.line(`store ptr ${raw}, ptr ${payload}`); - owner = { slot: payload, type: read.value }; + if (!borrow) owner = { slot: payload, type: read.value }; } else { // Booleans are stored as 0/1, already the widened union payload. const scalar = emitNumberMapGetScalar(host, receiver.name, number); @@ -326,8 +412,10 @@ export function emitStackMapRead(host: LlvmEmitterContext, read: LocalMapRead): let raw: string; const mapType = read.receiver.type; const compact = mapType.kind === "map" && compactMapValues(host, mapType.key, mapType.value); + // The runtime's other key kinds return +1, which the frame then owns. + const borrowed = borrow && stringKey !== null; if (stringKey !== null) - raw = emitStringMapGetRef(host, receiver.name, stringKey, read.value, compact); + raw = emitStringMapGetRef(host, receiver.name, stringKey, read.value, compact, borrowed); else { raw = B.tmp(); host.declare(`declare ptr @scr_map_get_${access}_ref(ptr, ${keyType})`); @@ -336,7 +424,7 @@ export function emitStackMapRead(host: LlvmEmitterContext, read: LocalMapRead): B.line(`${found} = icmp ne ptr ${raw}, null`); B.line(`store i64 0, ptr ${payload}`); B.line(`store ptr ${raw}, ptr ${payload}`); - owner = { slot: payload, type: read.value }; + if (!borrowed) owner = { slot: payload, type: read.value }; } else { const scalar = read.value.kind === "f64" ? "f64" : "bool"; B.line(`store i64 0, ptr ${payload}`); diff --git a/packages/compiler/test/map-get-borrow-emission.test.ts b/packages/compiler/test/map-get-borrow-emission.test.ts new file mode 100644 index 000000000..950fe35c2 --- /dev/null +++ b/packages/compiler/test/map-get-borrow-emission.test.ts @@ -0,0 +1,58 @@ +import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile, deserializeModule } from "../src/index.js"; +import { emitLlvmModule } from "../src/backend/llvm/emitter.js"; + +test("a Map.get local read before any reference write holds the entry's reference", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-map-get-borrow-")); + try { + const entry = join(dir, "main.ts"); + const outPath = join(dir, "main.ir.json"); + await writeFile( + entry, + ` +class Counter { + num = 1; +} +function count(m: Map, keys: number[]): void { + for (const key of keys) { + const cur = m.get(key); + if (cur === undefined) m.set(key, new Counter()); + else cur.num++; + } +} +function named(m: Map, key: string): number { + const cur = m.get(key); + return cur === undefined ? 0 : cur.num; +} +function replaced(m: Map): number { + const old = m.get(1); + m.set(1, new Counter()); + return old === undefined ? 0 : old.num; +} +const numbers = new Map(); +count(numbers, [1, 2, 1]); +console.log(named(new Map([["a", new Counter()]]), "a"), replaced(numbers)); +`, + ); + const result = await compile(entry, { outDir: dir, outPath, outputKind: "ir" }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + const mod = deserializeModule(await readFile(outPath, "utf8")); + const ll = emitLlvmModule(mod); + const fn = (name: string): string => + new RegExp(`^define internal [^\\n]*@sc_bf_${name}(?:\\.i32)?\\([^]*?^}`, "m").exec(ll)![0]; + // The update writes the map only where the entry is absent, and a + // string key's lookup is inline: neither read retains the value. + for (const name of ["count", "named"]) { + expect(fn(name)).not.toContain("@sc_retain_Counter"); + expect(fn(name)).not.toContain("@sc_release_Counter"); + } + // A write between the read and its use keeps the read's own reference. + expect(fn("replaced")).toContain("@sc_retain_Counter"); + } finally { + await rm(dir, { recursive: true, force: true }); + } +}); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8181-map-get-borrows.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8181-map-get-borrows.ts.json new file mode 100644 index 000000000..39f43aa85 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8181-map-get-borrows.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8181-map-get-borrows.ts" + ], + "diags": [] +} diff --git a/tests/corpus/8181-map-get-borrows.ts b/tests/corpus/8181-map-get-borrows.ts new file mode 100644 index 000000000..be546cf73 --- /dev/null +++ b/tests/corpus/8181-map-get-borrows.ts @@ -0,0 +1,130 @@ +// Map.get results held in locals across the operations that can and cannot +// release the entry's value: an update on the absent branch, a write, delete +// or clear before a later read, a call that may change the map, loops, +// string keys, and values that are stored, returned or compared. +class Counter { + num: number; + label: string; + constructor(num: number, label: string) { + this.num = num; + this.label = label; + } +} + +function count(keys: number[]): Map { + const counts = new Map(); + for (const key of keys) { + const cur = counts.get(key); + if (cur === undefined) counts.set(key, new Counter(1, `k${key}`)); + else cur.num++; + } + return counts; +} + +function report(counts: Map): string { + const parts: string[] = []; + for (const [key, value] of counts) parts.push(`${key}:${value.num}:${value.label}`); + return parts.join(" "); +} + +console.log("count", report(count([3, 1, 3, 2, 3, 1, 9]))); + +// A write replaces the entry's value while the old one is still read. +function replaceThenRead(m: Map): string { + const old = m.get(1); + m.set(1, new Counter(100, "new")); + return old === undefined ? "none" : `${old.num}:${old.label}`; +} +const replaced = new Map([[1, new Counter(5, "old")]]); +console.log("replace", replaceThenRead(replaced), replaced.get(1)!.label); + +// Deleting and clearing release the value before the read. +function deleteThenRead(m: Map): string { + const held = m.get(2); + m.delete(2); + return held === undefined ? "none" : held.label; +} +function clearThenRead(m: Map): string { + const held = m.get(2); + m.clear(); + return held === undefined ? "none" : `${held.label}:${m.size}`; +} +console.log("delete", deleteThenRead(new Map([[2, new Counter(1, "two")]]))); +console.log("clear", clearThenRead(new Map([[2, new Counter(1, "two")]]))); + +// A call that may change the map runs between the read and the use. +let shared = new Map([[7, new Counter(7, "seven")]]); +function mutate(): void { + shared.set(7, new Counter(70, "seventy")); + shared = new Map(); +} +function callBetween(): string { + const held = shared.get(7); + mutate(); + return held === undefined ? "none" : `${held.num}:${held.label}`; +} +console.log("call", callBetween()); + +// Reads on both branches, a write on one of them, and a read after the join. +function branches(m: Map, k: number, write: boolean): string { + const held = m.get(k); + if (held === undefined) return "absent"; + if (write) m.set(k, new Counter(0, "zero")); + else held.num += 10; + return `${held.num}:${held.label}`; +} +const branchMap = new Map([[4, new Counter(4, "four")]]); +console.log("branches", branches(branchMap, 4, false), branches(branchMap, 4, true), branches(branchMap, 5, true)); + +// The value escapes into an array and a returned object. +function escape(m: Map): Counter[] { + const kept: Counter[] = []; + for (let k = 0; k < 4; k++) { + const value = m.get(k % 2); + if (value !== undefined) kept.push(value); + } + m.clear(); + return kept; +} +const escapes = escape(new Map([[0, new Counter(0, "zero")], [1, new Counter(1, "one")]])); +console.log("escape", escapes.map((c) => c.label).join(",")); +function returned(m: Map): Counter | undefined { + const value = m.get(3); + return value; +} +const returnMap = new Map([[3, new Counter(3, "three")]]); +const got = returned(returnMap); +returnMap.clear(); +console.log("returned", got?.label); + +// String keys, including keys built at run time. +function words(text: string): string { + const seen = new Map(); + for (const word of text.split(" ")) { + const entry = seen.get(word); + if (entry === undefined) seen.set(word, new Counter(1, word.toUpperCase())); + else entry.num++; + } + const parts: string[] = []; + for (const [word, entry] of seen) parts.push(`${word}=${entry.num}/${entry.label}`); + return parts.join(" "); +} +console.log("words", words("a b a c b a")); +const prefix = "k"; +const byName = new Map([["k1", new Counter(1, "one")]]); +const named = byName.get(prefix + "1"); +byName.set("k1", new Counter(2, "two")); +console.log("named", named?.label, byName.get("k1")?.label); + +// A loop whose body writes the map after the read on every pass. +function loopWrites(m: Map): number { + let total = 0; + for (let i = 0; i < 5; i++) { + const value = m.get(i % 2); + if (value !== undefined) total += value.num; + m.set(i % 2, new Counter(i, "loop")); + if (value !== undefined) total += value.num * 100; + } + return total; +} +console.log("loop", loopWrites(new Map([[0, new Counter(1, "a")], [1, new Counter(2, "b")]]))); diff --git a/tests/harness/corpus-costs/8181-map-get-borrows.ts.json b/tests/harness/corpus-costs/8181-map-get-borrows.ts.json new file mode 100644 index 000000000..d5d1c5f65 --- /dev/null +++ b/tests/harness/corpus-costs/8181-map-get-borrows.ts.json @@ -0,0 +1 @@ +{ "plain": 2500, "san": 3500 } From ab9cfd7e91cf2844ff6033d60a54ac299ebb5916 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 07:53:04 -0500 Subject: [PATCH 087/259] Speculate integer loops through pure helper calls, powers of two and byte reads - A speculated write may call a function whose body is one return of arithmetic, Math.floor and Math.pow over its number parameters. The fast copy evaluates the expanded body; the double copy still calls the function. Union tests on the parameters (`number | undefined`) fold against the wrapped argument. - `Math.pow(2, n)` and `Math.floor(a / 2^n)` run as checked i64 shifts: with n an integer in [0, 52], both equal the double results for every safe integer a. - Element reads of integer typed arrays are speculative leaves, read before any check, as string and array reads are. - A write's other calls of program functions are hoisted: the fast copy evaluates each once into a local of its own, and a failed check resumes at a copy of the write that re-runs only the arithmetic over those locals. This applies only when no call can write a local the write reads. - k-nucleotide's key chain (`key = bitwiseTrimLeft(key, m) * 4 + seq[i]`) now runs in i64. --- .../src/backend/llvm/emit-statements.ts | 37 +- packages/compiler/src/backend/llvm/emitter.ts | 44 ++ .../backend/llvm/speculative-integers.test.ts | 100 +++++ .../src/backend/llvm/speculative-integers.ts | 383 +++++++++++++++++- .../7757-speculative-key-chains.ts.json | 6 + tests/corpus/7757-speculative-key-chains.ts | 67 +++ .../7757-speculative-key-chains.ts.json | 1 + 7 files changed, 613 insertions(+), 25 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7757-speculative-key-chains.ts.json create mode 100644 tests/corpus/7757-speculative-key-chains.ts create mode 100644 tests/harness/corpus-costs/7757-speculative-key-chains.ts.json diff --git a/packages/compiler/src/backend/llvm/emit-statements.ts b/packages/compiler/src/backend/llvm/emit-statements.ts index 55e31219c..ab87b3439 100644 --- a/packages/compiler/src/backend/llvm/emit-statements.ts +++ b/packages/compiler/src/backend/llvm/emit-statements.ts @@ -2136,6 +2136,7 @@ export function emitLoopCopies( ); }, (id) => emitter.speculativeLocal(id) || emitter.speculativeInvariantGlobal(id), + emitter.speculationContext(), ) : null; if (!plan) { @@ -2193,6 +2194,20 @@ export function emitLoopCopies( B.line(`${both} = and i1 ${ok}, ${trying}`); ok = both; } + // Hoisted leaves live in locals of their own, which the resume copy of + // their write reads (see SpeculativeValue). + for (const { leaves } of plan.values.values()) + for (const leaf of leaves) { + emitter.currentLocals.set(leaf.localId, { + id: leaf.localId, + name: "speculated leaf", + type: leaf.expr.type, + mutable: true, + }); + B.entryAllocas.push( + `${emitter.binding(leaf.localId).slot} = alloca double ; speculated leaf`, + ); + } const fast = B.newLabel("spec.fast"), slow = B.newLabel("spec.slow"); B.condBr(ok, fast, slow); @@ -2218,6 +2233,7 @@ export function emitLoopCopies( throw new InternalCompilerError("llvm emitter bug: speculative loop copy without a header"); B.startBlock(B.newLabel("spec.tail")); emitter.speculationResume = resume; + emitter.speculationResumeValues = plan.values; emitter.speculationHeader = () => { B.br(header!); B.startBlock(B.newLabel("spec.unused")); @@ -2226,6 +2242,7 @@ export function emitLoopCopies( emitCopy(exit); } finally { emitter.speculationResume = null; + emitter.speculationResumeValues = null; emitter.speculationHeader = null; } B.startBlock(fast); @@ -2274,6 +2291,7 @@ export function emitLoopCopies( deferred, bails, ran, + values: plan.values, }; try { const leave = B.newLabel("spec.leave"); @@ -2531,9 +2549,22 @@ export function emitSpeculativeWrite( // at once: a bailing path then owns nothing, and reads have no effect // whose reordering before the arithmetic could be observed. const reads = new Map(); - if (target.value !== null) { + const rewritten = emitter.speculation!.values?.get(s); + const value = rewritten?.value ?? target.value; + if (rewritten !== undefined) { + // Hoisted leaves run first, in the write's order, and keep their + // doubles for the resume copy. emitter.frames.push([]); - for (const read of speculativeReads(target.value)) reads.set(read, emitter.emitExpr(read)); + for (const leaf of rewritten.leaves) { + const evaluated = emitter.emitExpr(leaf.expr); + B.line(`store double ${evaluated.name}, ptr ${emitter.binding(leaf.localId).slot}`); + reads.set(leaf.ref, evaluated); + } + emitter.releaseTemps(emitter.frames.pop()!); + } + if (value !== null) { + emitter.frames.push([]); + for (const read of speculativeReads(value)) reads.set(read, emitter.emitExpr(read)); emitter.releaseTemps(emitter.frames.pop()!); } emitter.frames.push([]); @@ -2548,7 +2579,7 @@ export function emitSpeculativeWrite( B.line(`${biased} = add i64 ${result}, ${Number.MAX_SAFE_INTEGER}`); B.line(`${outside} = icmp ugt i64 ${biased}, ${2 * Number.MAX_SAFE_INTEGER}`); bail(outside); - } else result = emitSpeculativeInteger(emitter, target.value, bail, reads, resume === undefined); + } else result = emitSpeculativeInteger(emitter, value!, bail, reads, resume === undefined); // Speculable values read only numbers past this point. if (emitter.frames.pop()!.length > 0) throw new InternalCompilerError("llvm emitter bug: speculative write owns a temporary"); diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 6760f3b74..4080084de 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -338,6 +338,13 @@ import { } from "./shapes.js"; import type { ExprOf, LibCallExpr, LlStreamTypedRefAdapter, LlValue } from "./expr-context.js"; import { INLINE_LITERAL_BYTES } from "./string-literal-equality.js"; +import { + inlinableNumberFunction, + withSpeculativeValue, + type InlinableFunction, + type SpeculationContext, + type SpeculativeValue, +} from "./speculative-integers.js"; import { emitFfiCallbackDefs, emitLibDefs, @@ -1435,11 +1442,41 @@ export class LlEmitter { * integer loop has neither. */ bails?: string; ran?: string; + /** Writes that speculate a rewritten value (rewriteSpeculable). */ + values?: ReadonlyMap; } | null = null; /** Speculative loop sites numbered so far in the module. */ speculativeLoopSites = 0; /** The ordinary copy being emitted: resume labels still to place. */ speculationResume: Map | null = null; + /** The rewritten values of the writes `speculationResume` resumes at. */ + speculationResumeValues: ReadonlyMap | null = null; + /** Hoisted speculative leaves numbered so far in the module. */ + private speculativeLeaves = 0; + private readonly inlinableFunctions = new Map(); + + /** What speculative loop planning may assume here (SpeculationContext). */ + speculationContext(): SpeculationContext { + return { + inlinable: (callee) => { + if (!this.inlinableFunctions.has(callee)) { + const fn = this.fnByName.get(callee); + this.inlinableFunctions.set(callee, fn ? inlinableNumberFunction(fn) : undefined); + } + return this.inlinableFunctions.get(callee); + }, + unaliased: (id) => { + const local = this.currentLocals.get(id); + return ( + local !== undefined && + !local.boxed && + !this.captureIds.has(id) && + !this.lazyCaptureBoxes.has(id) + ); + }, + leafId: () => `%spec.leaf.${this.speculativeLeaves++}`, + }; + } /** Run once at the top of the next loop copy's header * (`enterLoopHeader`): records the ordinary copy's header, or sends the * third copy's header there. */ @@ -5591,6 +5628,13 @@ export class LlEmitter { resume.placed = true; this.B.br(resume.label); this.B.startBlock(resume.label); + // A write with hoisted leaves re-executes its arithmetic over the + // leaves' stored doubles: each leaf ran once, in the fast copy. + const rewritten = this.speculationResumeValues?.get(s); + if (rewritten !== undefined && rewritten.leaves.length > 0) { + this.emitStmt(withSpeculativeValue(s, rewritten.value)); + return; + } } if (this.speculation?.writes.has(s)) { this.emitSpeculativeWrite(s, this.speculation.resume.get(s)); diff --git a/packages/compiler/src/backend/llvm/speculative-integers.test.ts b/packages/compiler/src/backend/llvm/speculative-integers.test.ts index 3acfec0fb..86055b1b6 100644 --- a/packages/compiler/src/backend/llvm/speculative-integers.test.ts +++ b/packages/compiler/src/backend/llvm/speculative-integers.test.ts @@ -1,9 +1,11 @@ import { expect, test } from "vitest"; import { F64, type IrExpr, type IrStmt } from "../../ir/ir.js"; import { + inlinableNumberFunction, isSpeculableValue, planProvenIntegerLoop, planSpeculativeLoop, + rewriteSpeculable, speculativeReads, } from "./speculative-integers.js"; @@ -266,3 +268,101 @@ test("bounded cursors with proven writes are shadowed in a proven integer loop", planProvenIntegerLoop(forLoop([...body, jump]) as never, cursors, all, () => false, all), ).toBeNull(); }); + +const libCall = (fn: string, args: IrExpr[]): IrExpr => + ({ kind: "libCall", fn, args, type: F64, loc }) as never; +const call = (callee: string, args: IrExpr[]): IrExpr => ({ + kind: "call", + callee, + args, + type: F64, + loc, +}); +const pow2 = (n: IrExpr): IrExpr => libCall("math.pow", [num(2), n]); +/** `function trim(v, n) { return v - Math.floor(v / Math.pow(2, n)) * Math.pow(2, n); }` */ +const trim = { + name: "trim", + params: [ + { localId: "v", name: "v", type: F64 }, + { localId: "n", name: "n", type: F64 }, + ], + returnType: F64, + locals: [], + body: [ + { + kind: "return", + value: bin( + "-", + ref("v"), + bin("*", libCall("math.floor", [bin("/", ref("v"), pow2(ref("n")))]), pow2(ref("n"))), + ), + loc, + }, + ], + loc, +} as never; + +test("calls of small pure number functions expand into a speculated write", () => { + const inlinable = inlinableNumberFunction(trim)!; + expect(inlinable.params).toEqual(["v", "n"]); + const context = { inlinable: (callee: string) => (callee === "trim" ? inlinable : undefined) }; + // key = trim(key, m) * 4 + c + const value = bin("+", bin("*", call("trim", [ref("key"), ref("m")]), num(4)), ref("c")); + expect(isSpeculableValue(value)).toBe(false); + const rewritten = rewriteSpeculable(value, context)!; + expect(rewritten.leaves).toEqual([]); + expect(JSON.stringify(rewritten.value)).not.toContain('"call"'); + const write = assign("key", value); + const plan = planSpeculativeLoop( + loop([write, increment("i")]) as never, + all, + () => false, + () => false, + all, + context, + )!; + expect(plan.writes.has(write)).toBe(true); + expect(plan.values.get(write)).toEqual(rewritten); + // `m`, an input of the expanded body, is checked on entry with the others. + expect([...plan.locals.keys()].sort()).toEqual(["c", "i", "key", "m", "n"]); +}); + +test("Math.floor needs a power-of-two divisor, and expansion pure arguments", () => { + const context = { inlinable: () => inlinableNumberFunction(trim) }; + expect(rewriteSpeculable(libCall("math.floor", [bin("/", ref("a"), num(8))]), {})).not.toBeNull(); + expect(rewriteSpeculable(libCall("math.floor", [bin("/", ref("a"), num(6))]), {})).toBeNull(); + expect(rewriteSpeculable(libCall("math.floor", [bin("/", ref("a"), ref("b"))]), {})).toBeNull(); + // An argument that is itself a call is evaluated once: no expansion. + expect(rewriteSpeculable(call("trim", [call("other", []), ref("m")]), context)).toBeNull(); + const effectful = { + ...(trim as object), + body: [{ kind: "exprStmt", expr: call("log", []), loc }], + }; + expect(inlinableNumberFunction(effectful as never)).toBeUndefined(); +}); + +test("other leaves are hoisted only when no call can change the write's locals", () => { + let next = 0; + const leafId = (): string => `%leaf.${next++}`; + const value = bin( + "%", + bin("+", bin("*", ref("acc"), num(7)), call("noisy", [ref("i")])), + num(1000003), + ); + const hoisted = rewriteSpeculable(value, { unaliased: () => true, leafId })!; + expect(hoisted.leaves.map((leaf) => leaf.expr)).toEqual([call("noisy", [ref("i")])]); + expect(rewriteSpeculable(value, { unaliased: (id) => id !== "acc", leafId })).toBeNull(); + // Without leaf ids nothing is hoisted. + expect(rewriteSpeculable(value, { unaliased: () => true })).toBeNull(); + const write = assign("acc", value); + const plan = planSpeculativeLoop( + loop([write, increment("i")]) as never, + (id) => !id.startsWith("%leaf"), + () => false, + () => false, + (id) => !id.startsWith("%leaf"), + { unaliased: () => true, leafId }, + )!; + expect(plan.values.get(write)!.leaves).toHaveLength(1); + expect([...plan.locals.keys()].some((id) => id.startsWith("%leaf"))).toBe(false); +}); diff --git a/packages/compiler/src/backend/llvm/speculative-integers.ts b/packages/compiler/src/backend/llvm/speculative-integers.ts index 00fabb788..69066a5b4 100644 --- a/packages/compiler/src/backend/llvm/speculative-integers.ts +++ b/packages/compiler/src/backend/llvm/speculative-integers.ts @@ -1,5 +1,6 @@ -import type { IrExpr, IrStmt } from "../../ir/ir.js"; +import type { IrExpr, IrFunction, IrStmt } from "../../ir/ir.js"; import { everyExprChild, everyStmtChild } from "../../ir/traverse.js"; +import { InternalCompilerError } from "../../errors.js"; import { f64Lit } from "./common.js"; import type { LlValue, LlvmEmitterContext } from "./expr-context.js"; import { exactInteger, widenInteger } from "./integer-values.js"; @@ -30,6 +31,273 @@ export interface SpeculativeLoopPlan { * than through its condition, `break` or a failed check: no calls, no * throwing operations, no labeled jumps and no `return`. */ observerFree: boolean; + /** The writes that speculate a rewritten value (rewriteSpeculable). */ + values: Map; +} + +/** A write's value as speculation evaluates it: calls of small pure number + * functions expanded in place, and other number leaves (`leaves`) replaced + * by references to fresh locals. The fast copy evaluates each leaf once, + * stores it to its local and checks it as an integer; a failed check + * resumes at a copy of the write that reads the locals, so a leaf is never + * evaluated twice. */ +export interface SpeculativeValue { + value: IrExpr; + leaves: { localId: string; expr: IrExpr; ref: IrExpr }[]; +} + +/** What the planner may assume about the code around a loop. */ +export interface SpeculationContext { + /** The parameters and the returned expression of `callee` when it is a + * small pure number function (inlinableNumberFunction). */ + inlinable?: (callee: string) => InlinableFunction | undefined; + /** A local that no call can write: not captured, boxed or global. */ + unaliased?: (localId: string) => boolean; + /** A fresh local id for a hoisted leaf. */ + leafId?: () => string; +} + +export interface InlinableFunction { + params: readonly string[]; + body: IrExpr; +} + +/** `s` (a speculated write) writing `value` instead. */ +export function withSpeculativeValue(s: IrStmt, value: IrExpr): IrStmt { + switch (s.kind) { + case "assign": + return { ...s, value }; + case "varDecl": + return { ...s, init: value }; + case "exprStmt": + if (s.expr.kind === "assignExpr") return { ...s, expr: { ...s.expr, value } }; + break; + default: + break; + } + throw new InternalCompilerError(`llvm emitter bug: speculated ${s.kind} with a rewritten value`); +} + +/** Calls nest at most this deep in one expansion. */ +const MAX_INLINE_DEPTH = 4; +/** An expansion larger than this stays a call. */ +const MAX_INLINE_NODES = 64; + +/** A function that only returns arithmetic over its number parameters: + * `function trim(v, n) { return v - Math.floor(v / Math.pow(2, n)) * Math.pow(2, n); }`. + * Its call evaluates nothing but its arguments, so a speculated write may + * expand it in place. */ +export function inlinableNumberFunction(fn: IrFunction): InlinableFunction | undefined { + if ( + fn.async || + fn.generator || + (fn.captures?.length ?? 0) > 0 || + (fn.classCaptures?.length ?? 0) > 0 || + fn.returnType.kind !== "f64" || + fn.params.some((p) => p.type.kind !== "f64" && p.type.kind !== "union") || + fn.body.length !== 1 || + fn.body[0]!.kind !== "return" || + fn.body[0]!.value === undefined + ) + return undefined; + const params = fn.params.map((p) => p.localId); + const known = new Set(params); + let nodes = 0; + // A parameter of a union type (`number | undefined`) is read only + // through its tag test and narrowing, which a wrapped argument folds. + const union = (e: IrExpr): boolean => e.kind === "varRef" && known.has(e.localId); + const pure = (e: IrExpr): boolean => { + if (++nodes > MAX_INLINE_NODES) return false; + if (e.kind === "boolLit") return true; + if (e.kind === "unionIsTag") return union(e.value); + if (e.kind === "unionNarrow") return e.type.kind === "f64" && union(e.value); + if (e.type.kind !== "f64") return false; + switch (e.kind) { + case "numLit": + return true; + case "varRef": + return known.has(e.localId); + case "ternary": + return pure(e.cond) && pure(e.then) && pure(e.else_); + case "bin": + return (INTEGER_OPS.has(e.op) || e.op === "/") && pure(e.left) && pure(e.right); + case "unary": + return e.op === "-" && pure(e.operand); + case "libCall": + return (e.fn === "math.floor" || e.fn === "math.pow") && e.args.every(pure); + case "call": + return e.args.every(pure); + default: + return false; + } + }; + const body = fn.body[0]!.value!; + return pure(body) ? { params, body } : undefined; +} + +/** `e` with each parameter reference replaced by its argument. A tag test + * or narrowing of a wrapped argument folds, and so does a ternary over a + * folded test. */ +function substitute(e: IrExpr, args: ReadonlyMap): IrExpr { + switch (e.kind) { + case "varRef": + return args.get(e.localId) ?? e; + case "unionIsTag": { + const value = substitute(e.value, args); + if (value.kind !== "unionWrap" || value.unionId !== e.unionId) return { ...e, value }; + return { + kind: "boolLit", + value: (value.tag === e.tag) !== (e.negated === true), + type: e.type, + loc: e.loc, + }; + } + case "unionNarrow": { + const value = substitute(e.value, args); + return value.kind === "unionWrap" && value.unionId === e.unionId && value.tag === e.tag + ? value.value + : { ...e, value }; + } + case "ternary": { + const cond = substitute(e.cond, args); + if (cond.kind === "boolLit") return substitute(cond.value ? e.then : e.else_, args); + return { ...e, cond, then: substitute(e.then, args), else_: substitute(e.else_, args) }; + } + case "bin": + return { ...e, left: substitute(e.left, args), right: substitute(e.right, args) }; + case "unary": + return { ...e, operand: substitute(e.operand, args) }; + case "libCall": + case "call": + return { ...e, args: e.args.map((a) => substitute(a, args)) }; + default: + return e; + } +} + +/** Whether `e` is a power of two speculation can shift by: + * `Math.pow(2, n)` or a literal 2^k with k in [0, 52]. */ +function powerOfTwo(e: IrExpr): boolean { + if (e.kind === "numLit") { + const k = Math.log2(e.value); + return Number.isInteger(k) && k >= 0 && k <= 52; + } + return ( + e.kind === "libCall" && + e.fn === "math.pow" && + e.args.length === 2 && + e.args[0]!.kind === "numLit" && + e.args[0]!.value === 2 + ); +} + +/** Typed-array element kinds whose elements are integers. */ +const INTEGER_ELEMENTS = new Set(["u8", "u8c", "i8", "u16", "i16", "u32", "i32"]); + +/** A typed-array element read of an integer kind with no effect: an + * out-of-range read gives NaN, which fails its check. Float elements would + * only bail. */ +function isSpeculativeByteRead(e: IrExpr): boolean { + return ( + e.kind === "bytesIntrinsic" && + e.method === "get" && + e.type.kind === "f64" && + e.receiver.type.kind === "bytes" && + INTEGER_ELEMENTS.has(e.receiver.type.elem) && + e.args.length === 1 && + isEffectFree(e.receiver) && + isEffectFree(e.args[0]!) + ); +} + +/** Rewrite a write's value that isSpeculableValue refuses into one it can + * speculate (SpeculativeValue), or null. Expansion and the new operations + * (`Math.pow(2, n)`, `Math.floor(a / 2^n)`, byte reads) evaluate nothing + * but numbers, so the fast copy may evaluate them in any order. Hoisted + * leaves run in the write's evaluation order before the arithmetic; that + * reorders nothing only when the write reads no heap and every local it + * reads is one no call can write. */ +export function rewriteSpeculable( + value: IrExpr, + context: SpeculationContext, +): SpeculativeValue | null { + const leaves: SpeculativeValue["leaves"] = []; + let reads = false; + const locals: string[] = []; + const rewrite = (e: IrExpr, depth: number): IrExpr | null => { + if (e.type.kind !== "f64") return null; + switch (e.kind) { + case "numLit": + return Number.isSafeInteger(e.value) && !Object.is(e.value, -0) ? e : null; + case "varRef": + locals.push(e.localId); + return e; + case "bin": { + if (!ARITHMETIC_OPS.has(e.op)) break; + const left = rewrite(e.left, depth); + const right = left && rewrite(e.right, depth); + return left && right ? { ...e, left, right } : null; + } + case "unary": { + if (e.op !== "-") break; + const operand = rewrite(e.operand, depth); + return operand ? { ...e, operand } : null; + } + case "libCall": { + if (powerOfTwo(e) && e.kind === "libCall") { + const exponent = rewrite(e.args[1]!, depth); + return exponent ? { ...e, args: [e.args[0]!, exponent] } : null; + } + const quotient = e.args[0]; + if ( + e.fn === "math.floor" && + e.args.length === 1 && + quotient?.kind === "bin" && + quotient.op === "/" && + powerOfTwo(quotient.right) + ) { + const left = rewrite(quotient.left, depth); + const right = left && rewrite(quotient.right, depth); + return left && right ? { ...e, args: [{ ...quotient, left, right }] } : null; + } + break; + } + case "call": { + const fn = depth < MAX_INLINE_DEPTH ? context.inlinable?.(e.callee) : undefined; + // Arguments are evaluated before the body: an expansion may read + // them in another order, or twice, only when they are pure. + const plain = (a: IrExpr): boolean => + isSpeculableValue(a, false) || + (a.kind === "unionWrap" && isSpeculableValue(a.value, false)); + if (fn !== undefined && fn.params.length === e.args.length && e.args.every(plain)) { + const args = new Map(fn.params.map((id, i) => [id, e.args[i]!])); + return rewrite(substitute(fn.body, args), depth + 1); + } + break; + } + default: + if (isSpeculativeRead(e) || isSpeculativeByteRead(e)) { + reads = true; + return e; + } + break; + } + // Only calls of program functions are hoisted: other leaves (a string's + // length, a Map read) are cheap where they stand, and would turn every + // loop that adds one into a second copy. + if (context.leafId === undefined || e.kind !== "call") return null; + const ref: IrExpr = { kind: "varRef", localId: context.leafId(), type: e.type, loc: e.loc }; + leaves.push({ localId: (ref as { localId: string }).localId, expr: e, ref }); + return ref; + }; + const rewritten = rewrite(value, 0); + if (rewritten === null) return null; + if (leaves.length > 0) { + const leafIds = new Set(leaves.map((leaf) => leaf.localId)); + if (reads || !locals.every((id) => leafIds.has(id) || context.unaliased?.(id) === true)) + return null; + } + return { value: rewritten, leaves }; } type SpeculativeLoop = Extract; @@ -170,13 +438,16 @@ function isEffectFree(e: IrExpr): boolean { } } -/** The speculative reads of a speculable value in evaluation order. */ +/** The speculative reads of a speculable value in evaluation order, those + * of a rewritten value (rewriteSpeculable) included. */ export function speculativeReads(e: IrExpr, out: IrExpr[] = []): IrExpr[] { - if (e.kind === "bin" && ARITHMETIC_OPS.has(e.op)) { + if (e.kind === "bin" && (ARITHMETIC_OPS.has(e.op) || e.op === "/")) { speculativeReads(e.left, out); speculativeReads(e.right, out); } else if (e.kind === "unary" && e.op === "-") speculativeReads(e.operand, out); - else if (isSpeculativeRead(e)) out.push(e); + else if (e.kind === "libCall" && (e.fn === "math.floor" || e.fn === "math.pow")) + for (const arg of e.args) speculativeReads(arg, out); + else if (isSpeculativeRead(e) || isSpeculativeByteRead(e)) out.push(e); return out; } @@ -195,6 +466,8 @@ function hasProduct(e: IrExpr): boolean { if (e.kind === "bin") return e.op === "*" || e.op === "%" || hasProduct(e.left) || hasProduct(e.right); if (e.kind === "unary") return hasProduct(e.operand); + // Math.floor(a / 2^n) and Math.pow(2, n) replace a division and a call. + if (e.kind === "libCall") return e.fn === "math.floor" || e.fn === "math.pow"; return false; } @@ -202,6 +475,7 @@ function hasArithmetic(e: IrExpr): boolean { if (e.kind === "bin") return ARITHMETIC_OPS.has(e.op) || hasArithmetic(e.left) || hasArithmetic(e.right); if (e.kind === "unary") return e.op === "-" || hasArithmetic(e.operand); + if (e.kind === "libCall") return e.fn === "math.floor" || e.fn === "math.pow"; return false; } @@ -236,8 +510,11 @@ export function planSpeculativeLoop( integral: (localId: string) => boolean = () => false, proven: (e: IrExpr) => boolean = () => false, invariantEligible: (localId: string) => boolean = eligible, + context: SpeculationContext = {}, ): SpeculativeLoopPlan | null { const writes = new Map(); + const values = new Map(); + const leafIds = new Set(); const unspeculable = new Set(); const reads = new Set(); // Locals with at least one read the static analysis does not prove. @@ -263,11 +540,9 @@ export function planSpeculativeLoop( // make the body's work integer. let inCondition = false; - const expr = (e: IrExpr): boolean => { - if (rejected) return false; - nodes++; - if (!OBSERVER_FREE_EXPRESSIONS.has(e.kind) || (e.kind === "bin" && e.left.type.kind !== "f64")) - observerFree = false; + // What the integer writes read and consume. A rewritten value is noted + // here alone: its original, which `expr` walks, has its effects. + const note = (e: IrExpr): void => { if (e.kind === "varRef") { reads.add(e.localId); if (!proven(e)) unproven.add(e.localId); @@ -281,6 +556,20 @@ export function planSpeculativeLoop( } else if (e.kind === "arrayGet" || e.kind === "arrayHas" || e.kind === "arrayState") consume(e.index); else if (e.kind === "bytesIntrinsic" || e.kind === "strIntrinsic") e.args.forEach(consume); + }; + // An expanded call is emitted in the fast copy: it counts toward the + // duplicated code. + const noteAll = (e: IrExpr): boolean => { + nodes++; + note(e); + return everyExprChild(e, noteAll, () => true); + }; + const expr = (e: IrExpr): boolean => { + if (rejected) return false; + nodes++; + if (!OBSERVER_FREE_EXPRESSIONS.has(e.kind) || (e.kind === "bin" && e.left.type.kind !== "f64")) + observerFree = false; + note(e); return everyExprChild(e, expr, nested); }; // Statements inside expressions (sequence expressions) run mid-expression, @@ -307,7 +596,11 @@ export function planSpeculativeLoop( if (s.kind === "arraySet" || s.kind === "bytesSet") consume(s.index); const target = speculativeWriteTarget(s); if (target) { - if (target.value === null || isSpeculableValue(target.value)) { + const rewritten = + target.value === null || isSpeculableValue(target.value) + ? null + : rewriteSpeculable(target.value, context); + if (target.value === null || isSpeculableValue(target.value) || rewritten !== null) { const list = writes.get(target.localId) ?? []; list.push(s); writes.set(target.localId, list); @@ -315,6 +608,11 @@ export function planSpeculativeLoop( reads.add(target.localId); if (s.kind !== "exprStmt" || !proven(s.expr)) unproven.add(target.localId); } else expr(target.value); + if (rewritten !== null) { + values.set(s, rewritten); + for (const leaf of rewritten.leaves) leafIds.add(leaf.localId); + noteAll(rewritten.value); + } return !rejected; } unspeculable.add(target.localId); @@ -341,25 +639,28 @@ export function planSpeculativeLoop( // write runs: speculated itself, already an integer, or loop-invariant // (checked on entry). A value computed from doubles the loop writes // would only fail its check on every entry. + const valueOf = (s: IrStmt): IrExpr | null => + values.get(s)?.value ?? speculativeWriteTarget(s)!.value; const grounded = (e: IrExpr): boolean => { if (e.kind === "varRef") { const id = e.localId; return ( + leafIds.has(id) || proven(e) || locals.has(id) || integral(id) || (!writes.has(id) && !unspeculable.has(id) && invariantEligible(id)) ); } - if (isSpeculativeRead(e)) return true; + if (isSpeculativeRead(e) || isSpeculativeByteRead(e)) return true; return everyExprChild(e, grounded, () => false); }; for (let changed = true; changed;) { changed = false; for (const id of [...locals.keys()]) { for (const s of writes.get(id)!) { - const target = speculativeWriteTarget(s)!; - if (target.value !== null && !grounded(target.value)) { + const value = valueOf(s); + if (value !== null && !grounded(value)) { locals.delete(id); changed = true; break; @@ -376,6 +677,7 @@ export function planSpeculativeLoop( if (e.kind === "varRef") { const id = e.localId; if ( + !leafIds.has(id) && !proven(e) && !locals.has(id) && !writes.has(id) && @@ -388,11 +690,11 @@ export function planSpeculativeLoop( return everyExprChild(e, invariant, () => true); }; for (const s of speculated) { - const target = speculativeWriteTarget(s)!; - if (target.value === null) arithmetic = true; + const value = valueOf(s); + if (value === null) arithmetic = true; else { - if (hasArithmetic(target.value)) arithmetic = true; - invariant(target.value); + if (hasArithmetic(value)) arithmetic = true; + invariant(value); } } if (!arithmetic) return null; @@ -401,13 +703,12 @@ export function planSpeculativeLoop( [...locals.keys()].some((id) => multiplied.has(id)) || [...speculated].some((s) => { const target = speculativeWriteTarget(s)!; - return ( - target.value !== null && - (hasProduct(target.value) || isVariableStep(target.localId, target.value)) - ); + const value = valueOf(s); + return value !== null && (hasProduct(value) || isVariableStep(target.localId, value)); }); if (!heavy) return null; - return { locals, writes: speculated, observerFree }; + for (const s of values.keys()) if (!speculated.has(s)) values.delete(s); + return { locals, writes: speculated, observerFree, values }; } /** A proven integer loop. The bindings integer-ranges.ts bounds over a for @@ -682,6 +983,19 @@ export function emitSpeculativeInteger( bail(negativeZero); return result; } + case "libCall": { + // A rewritten value's Math.pow(2, n) and Math.floor(a / 2^n) + // (rewriteSpeculable): with n an integer in [0, 52], 2^n is exact and + // so is a / 2^n for a safe integer a, whose floor the arithmetic shift + // computes, also for negative a. No result is -0. + if (e.fn === "math.pow") return shiftOne(host, exponentOf(host, e, bail, reads, integral)); + if (e.fn !== "math.floor" || e.args[0]?.kind !== "bin") break; + const a = emitSpeculativeInteger(host, e.args[0].left, bail, reads, integral); + const n = exponentOf(host, e.args[0].right, bail, reads, integral); + const result = B.tmp(); + B.line(`${result} = ashr i64 ${a}, ${n}`); + return result; + } case "unary": { if (e.op !== "-") break; const a = emitSpeculativeInteger(host, e.operand, bail, reads, integral); @@ -699,6 +1013,31 @@ export function emitSpeculativeInteger( return speculativeLeaf(host, reads.get(e) ?? host.emitExpr(e), e, bail); } +/** The exponent of a power of two (Math.pow(2, n) or a literal 2^k) as an + * i64 in [0, 52]; other exponents bail. */ +function exponentOf( + host: LlvmEmitterContext, + e: IrExpr, + bail: (condition: string) => void, + reads: ReadonlyMap, + integral: boolean, +): string { + if (e.kind === "numLit") return String(Math.log2(e.value)); + if (e.kind !== "libCall") + throw new InternalCompilerError("llvm emitter bug: speculative power of two"); + const n = emitSpeculativeInteger(host, e.args[1]!, bail, reads, integral); + const outside = host.B.tmp(); + host.B.line(`${outside} = icmp ugt i64 ${n}, 52`); + bail(outside); + return n; +} + +function shiftOne(host: LlvmEmitterContext, n: string): string { + const result = host.B.tmp(); + host.B.line(`${result} = shl i64 1, ${n}`); + return result; +} + /** The safe i64 of an evaluated number: its proven integer, or a checked * conversion. */ function speculativeLeaf( diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7757-speculative-key-chains.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7757-speculative-key-chains.ts.json new file mode 100644 index 000000000..274151b18 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7757-speculative-key-chains.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7757-speculative-key-chains.ts" + ], + "diags": [] +} diff --git a/tests/corpus/7757-speculative-key-chains.ts b/tests/corpus/7757-speculative-key-chains.ts new file mode 100644 index 000000000..bdbd12e1e --- /dev/null +++ b/tests/corpus/7757-speculative-key-chains.ts @@ -0,0 +1,67 @@ +// Speculative integer loops over writes that call small pure number +// functions, use Math.pow(2, n) and Math.floor(a / 2^n), read bytes, or +// call other functions: every fallback gives Node's numbers. +function trim(value: number, length: number): number { + return value - Math.floor(value / Math.pow(2, length)) * Math.pow(2, length); +} +function maybeTrim(value: number | undefined, length: number): number { + return (value ?? 0) - Math.floor((value ?? 0) / Math.pow(2, length)) * Math.pow(2, length); +} + +function chain(codes: Uint8Array, length: number): number { + const mask = length * 2 - 2; + let key = 0; + let sum = 0; + for (let i = 0; i < codes.length; ++i) { + sum = (sum + key) % 1000000007; + key = trim(key, mask) * 4 + codes[i]!; + } + return sum * 31 + key; +} + +function optionalChain(codes: Uint8Array, length: number): number { + let key = 0; + let sum = 0; + for (let i = 0; i < codes.length; ++i) { + sum = (sum * 3 + key) % 1000003; + key = maybeTrim(key, length * 2) * 4 + codes[i]!; + } + return sum + key; +} + +// Exponents past 52, negative and fractional values, and NaN reads leave +// the integer copy and finish in the double one. +function shifts(start: number, exponent: number, steps: number): number[] { + const out: number[] = []; + let v = start; + for (let i = 0; i < steps; i++) { + v = Math.floor(v / Math.pow(2, exponent)) * 3 + i * 7; + out.push(v); + } + return out; +} + +let calls = 0; +function noisy(x: number): number { + calls++; + return x % 5 === 0 ? x / 2 : x * 2; +} +// A call that the write cannot expand runs once per iteration, also on +// the iteration whose check fails. +function hoisted(n: number): number { + let acc = 1; + for (let i = 0; i < n; i++) acc = (acc * 7 + noisy(i)) % 1000003; + return acc; +} + +const codes = new Uint8Array(5000); +let seed = 7; +for (let i = 0; i < codes.length; i++) { + seed = (seed * 1103515245 + 12345) % 2147483648; + codes[i] = seed % 4; +} +for (const length of [1, 2, 3, 6, 12, 18, 27]) console.log(length, chain(codes, length), optionalChain(codes, length)); +console.log(shifts(1000, 3, 6), shifts(-1000, 2, 6), shifts(5, 53, 3), shifts(7.5, 1, 3), shifts(2 ** 52, 1, 3)); +console.log(hoisted(20), calls); +const short = codes.subarray(0, 3); +console.log(chain(short, 2), chain(new Uint8Array(0), 2)); diff --git a/tests/harness/corpus-costs/7757-speculative-key-chains.ts.json b/tests/harness/corpus-costs/7757-speculative-key-chains.ts.json new file mode 100644 index 000000000..be69de5f7 --- /dev/null +++ b/tests/harness/corpus-costs/7757-speculative-key-chains.ts.json @@ -0,0 +1 @@ +{ "plain": 2200, "san": 2900 } From d9f1457cd55dd99cf60f630eb1d610a1545207f3 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 08:07:52 -0500 Subject: [PATCH 088/259] Run CommonJS top-level return, untyped assert forms, and untyped instanceof Object as Node does --- .../limitations/builtin-apis/assertions.mdx | 2 + .../limitations/builtin-apis/prototypes.mdx | 1 + .../compiler/src/backend/llvm/lib-shared.ts | 4 + .../lowering/expressions/relational.ts | 15 +- .../src/frontend/lowering/lower-assert.ts | 316 +++++++++++++++++- .../src/frontend/lowering/lower-calls.ts | 15 +- .../src/frontend/lowering/lower-stmts.ts | 40 +++ .../compiler/src/frontend/lowering/lowerer.ts | 8 +- .../src/frontend/lowering/surfaces.ts | 6 + packages/compiler/src/frontend/program.ts | 11 + packages/compiler/src/frontend/tsc-codes.ts | 4 + packages/compiler/src/ir/builtin-effects.ts | 1 + .../compiler/src/ir/builtin-signatures.ts | 8 + .../8062-assert-message-values.cjs.json | 6 + .../8065-cjs-top-level-return/main.js.json | 7 + .../corpus/8066-object-hasown-delete.cjs.json | 6 + .../8067-assert-throws-validators.cjs.json | 6 + .../8076-assert-instance-identity.cjs.json | 6 + .../8078-instanceof-object-function.cjs.json | 6 + .../8190-assert-function-values.cjs.json | 6 + .../8191-assert-function-values.ts.json | 6 + packages/runtime/src/scr_assert.c | 314 +++++++++++++++++ packages/runtime/src/scr_assert.h | 13 + packages/runtime/src/scr_json.c | 72 ++++ tests/corpus/8062-assert-message-values.cjs | 41 +++ .../corpus/8065-cjs-top-level-return/early.js | 6 + .../corpus/8065-cjs-top-level-return/main.js | 16 + .../8065-cjs-top-level-return/package.json | 3 + tests/corpus/8066-object-hasown-delete.cjs | 23 ++ .../corpus/8067-assert-throws-validators.cjs | 22 ++ .../corpus/8076-assert-instance-identity.cjs | 50 +++ .../8078-instanceof-object-function.cjs | 55 +++ tests/corpus/8190-assert-function-values.cjs | 30 ++ tests/corpus/8191-assert-function-values.ts | 16 + tests/coverage-fixtures/startup-fences.js | 4 +- tests/diagnostics/assert-fences.ts | 8 +- .../__snapshots__/assert-fences.ts.txt | 8 +- tests/harness/coverage.test.ts | 4 +- 38 files changed, 1121 insertions(+), 44 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8062-assert-message-values.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8065-cjs-top-level-return/main.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8066-object-hasown-delete.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8067-assert-throws-validators.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8076-assert-instance-identity.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8078-instanceof-object-function.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8190-assert-function-values.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8191-assert-function-values.ts.json create mode 100644 tests/corpus/8062-assert-message-values.cjs create mode 100644 tests/corpus/8065-cjs-top-level-return/early.js create mode 100644 tests/corpus/8065-cjs-top-level-return/main.js create mode 100644 tests/corpus/8065-cjs-top-level-return/package.json create mode 100644 tests/corpus/8066-object-hasown-delete.cjs create mode 100644 tests/corpus/8067-assert-throws-validators.cjs create mode 100644 tests/corpus/8076-assert-instance-identity.cjs create mode 100644 tests/corpus/8078-instanceof-object-function.cjs create mode 100644 tests/corpus/8190-assert-function-values.cjs create mode 100644 tests/corpus/8191-assert-function-values.ts diff --git a/docs/content/limitations/builtin-apis/assertions.mdx b/docs/content/limitations/builtin-apis/assertions.mdx index f7f5c9354..381fc3802 100644 --- a/docs/content/limitations/builtin-apis/assertions.mdx +++ b/docs/content/limitations/builtin-apis/assertions.mdx @@ -3,6 +3,8 @@ When `strictEqual` compares function values, `actual` and `expected` read as `undefined`; when `assert.throws` or `assert.rejects` reports an error that is not an instance of the expected class, or that does not match an expected object, `expected` reads as `undefined`. Values whose type can be cyclic, such as recursive records, also read as `undefined`. `assert.AssertionError` used as a value outside `instanceof` throws `SC2020`. + The comparison methods, `ok`, `fail` and `ifError` are function values that assert as the methods do; called through a stored value, `ok` without a message reports `value == true`, where Node quotes the call, and `fail` takes at most one argument. + `throws`, `rejects`, `doesNotThrow`, `doesNotReject`, `match` and `doesNotMatch` as values throw `SC2020`. `assert.deepEqual` and `assert.notDeepEqual` follow Node's loose comparison, including Maps, Sets, Dates, regular expressions, typed arrays, and errors; operands whose type can be cyclic or holds functions inside a structure are refused. `assert.partialDeepStrictEqual` follows Node's partial comparison over the same values, with the same refusals. Checked-dynamic values compared deeply have no cycle detection. diff --git a/docs/content/limitations/builtin-apis/prototypes.mdx b/docs/content/limitations/builtin-apis/prototypes.mdx index 170b11793..ce7bec74c 100644 --- a/docs/content/limitations/builtin-apis/prototypes.mdx +++ b/docs/content/limitations/builtin-apis/prototypes.mdx @@ -6,3 +6,4 @@ The constructors `Object`, `Function`, `Date`, `RegExp`, `Map`, `Set`, `WeakMap`, `WeakSet`, and `Promise` read as function values; through a stored value only `Object` can be called. `new` through a stored `Object`, `Date`, `Map`, `Set`, `WeakMap`, or `WeakSet` builds the same value as the `new` expression. `new` through a stored `RegExp` or `Promise`, `new` of a stored `Object` with a primitive argument, and `instanceof` against these constructors are unsupported. + `instanceof Object` and `instanceof Function` on untyped values follow the prototype chain as in Node, so an object built with `Object.create(null)` is not an `Object`. diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 7a16c37e8..46798e275 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -37,6 +37,7 @@ export const ASSERT_VERDICT_LIB_FNS: ReadonlyMap = new Ma export const LIB_FN_SYMS: Record = { "assert.expectsErrDyn": "scr_assert_expects_err_dyn", + "assert.throwsValidate": "scr_assert_throws_validate", "insp.jsonDyn": "scr_util_format_j", "http.reqH2StreamOrThrow": "scr_http_req_h2_stream_or_throw", "intl.segmenterNew": "scr_intl_segmenter_new", @@ -399,6 +400,9 @@ export const LIB_FN_SYMS: Record = { "assert.eqBool": "scr_assert_eq_bool", "assert.eqSym": "scr_assert_eq_sym", "assert.eqDyn": "scr_assert_eq_dyn", + "assert.messageValue": "scr_assert_message_value", + "assert.methodValue": "scr_assert_method_value", + "assert.messageClear": "scr_assert_message_clear", "assert.looseResult": "scr_assert_loose_result", "assert.deepResult": "scr_assert_deep_result", "assert.looseDeepResult": "scr_assert_loose_deep_result", diff --git a/packages/compiler/src/frontend/lowering/expressions/relational.ts b/packages/compiler/src/frontend/lowering/expressions/relational.ts index 1651bf0d9..5cd63013e 100644 --- a/packages/compiler/src/frontend/lowering/expressions/relational.ts +++ b/packages/compiler/src/frontend/lowering/expressions/relational.ts @@ -2178,23 +2178,10 @@ function lowerRuntimeKeyIn( return { kind: "call", callee: helper, args: [keyIr, recv], type: BOOL, loc }; } -/** Standard-library constructors the untyped instanceof helper has no - * instance test for: an untyped `x instanceof Object` always refuses. */ -const DYN_INSTANCEOF_REFUSED: ReadonlySet = new Set(["Object", "Function"]); - /** The SC1090 message `x instanceof C` throws, with the site's position, - * when `C` is a runtime constructor with no instance test. A right-hand - * side that names one of DYN_INSTANCEOF_REFUSED always reaches that - * refusal, so the site is listed with the runtime fences. */ + * when `C` is a runtime constructor with no instance test. */ function dynInstanceOfRefusal(lowerer: Lowerer, expr: ts.BinaryExpression): string { const diag = unsupportedDiag("SC1090", locOf(expr), "instanceof against this native constructor"); - const symbol = lowerer.checker.getSymbolAtLocation(expr.right); - if ( - symbol !== undefined && - lowerer.isStdlibSymbol(symbol) && - DYN_INSTANCEOF_REFUSED.has(ts.symbolName(symbol)) - ) - lowerer.runtimeFences.push(diag); const sf = ts.getSourceFileOfNode(expr); const line = ts.getLineAndCharacterOfPosition(sf, diag.loc.start).line + 1; return `${diag.message} [${diag.code} at ${diag.loc.file}:${line}]`; diff --git a/packages/compiler/src/frontend/lowering/lower-assert.ts b/packages/compiler/src/frontend/lowering/lower-assert.ts index b996abed7..39ec9c959 100644 --- a/packages/compiler/src/frontend/lowering/lower-assert.ts +++ b/packages/compiler/src/frontend/lowering/lower-assert.ts @@ -51,11 +51,14 @@ import { STRING, type SrcLoc, VOID, + isDynTypedRefType, isUnitType, typeEquals, typeKey, } from "../../ir/ir.js"; import { boolLit, countedFor, dynUndefinedExpr, numLit, strLit, varRef } from "../../ir/build.js"; +import { checkedClassInstanceOf } from "./class-construction.js"; +import { isJsSourceFile } from "../program.js"; /** node:assert/strict binds the loose NAMES to the strict comparisons — * Node's own aliasing (`strict.equal === assert.strictEqual`). */ @@ -73,6 +76,63 @@ function canonicalAssertMember(module: string, member: string): string { return member; } +/** The assert methods that are function values (scr_assert_method_value). */ +const ASSERT_FUNCTION_VALUES: ReadonlySet = new Set([ + "ok", + "fail", + "equal", + "notEqual", + "strictEqual", + "notStrictEqual", + "deepEqual", + "notDeepEqual", + "deepStrictEqual", + "notDeepStrictEqual", + "partialDeepStrictEqual", + "ifError", +]); + +/** The assert method a `const` binding holds (`const ok = assert.ok`, + * `const eq = strictEqual`), or null. */ +export function assertFunctionAliasOf( + lowerer: Lowerer, + ident: ts.Identifier, +): { module: string; member: string } | null { + const decl = lowerer.checker.getSymbolAtLocation(ident)?.valueDeclaration; + if ( + !decl || + !ts.isVariableDeclaration(decl) || + !ts.isIdentifier(decl.name) || + !ts.isVariableDeclarationList(decl.parent) || + (decl.parent.flags & ts.NodeFlags.Const) === 0 || + !decl.initializer + ) + return null; + let init = decl.initializer; + while (ts.isParenthesizedExpression(init)) init = init.expression; + const bi = ts.isPropertyAccessExpression(init) + ? lowerer.builtinMemberOf(init) + : ts.isIdentifier(init) + ? lowerer.builtinImportOf(init) + : null; + if (!bi || (bi.module !== "assert" && bi.module !== "assert/strict")) return null; + return ASSERT_FUNCTION_VALUES.has(canonicalAssertMember(bi.module, bi.member)) ? bi : null; +} + +/** An assert method read as a value (`emitter.on("x", assert.fail)`, + * `const eq = assert.strictEqual`): an untyped function that asserts as + * the method does, the same value for every read. Null for other + * members. */ +export function assertFunctionValue( + bi: { module: string; member: string }, + loc: SrcLoc, +): IrExpr | null { + if (bi.module !== "assert" && bi.module !== "assert/strict") return null; + const member = canonicalAssertMember(bi.module, bi.member); + if (!ASSERT_FUNCTION_VALUES.has(member)) return null; + return { kind: "libCall", fn: "assert.methodValue", args: [strLit(member, loc)], type: DYN, loc }; +} + /* Node's AssertionError carries actual, expected and operator. Where the * verdict is computed in compiled code, the failure branch records them * (assert.record) before the throwing call, so a passing assertion boxes @@ -166,11 +226,22 @@ function requireStatementPosition(lowerer: Lowerer, call: ts.CallExpression, wha ); } +/** The message the runtime reads from a registered value + * (SCR_ASSERT_VALUE_MESSAGE in scr_assert.h). */ +const VALUE_MESSAGE = "\u0001scriptc:assert-message-value"; + +/** A message argument that is not a string, met while one assertion + * lowers (withValueMessage). */ +let valueMessage: { value: IrExpr; has: string; text: string } | null = null; + /** The optional trailing message argument: Node accepts a string or an * Error (throwing the Error itself) — the STRING form lowers; a literal * `undefined` counts as omitted (Node's `message == null` test). Returns * the libCall's (msg, hasMsg) pair — a "" dummy when omitted, so the - * runtime can distinguish an omitted message from an empty one. */ + * runtime can distinguish an omitted message from an empty one. Any other + * value that crosses into the checked-dynamic tree (an untyped + * `failures.join('')`, an Error) is registered with the runtime at the call + * instead (withValueMessage). */ function lowerMessageArg( lowerer: Lowerer, node: ts.Expression | undefined, @@ -180,14 +251,112 @@ function lowerMessageArg( return { msg: { kind: "strLit", value: "", type: STRING, loc }, hasMsg: boolLit(false, loc) }; } const msg = lowerer.lowerExpr(node); - if (msg.type.kind !== "string") { + if (msg.type.kind === "string") return { msg, hasMsg: boolLit(true, loc) }; + const value = + valueMessage === null && (msg.type.kind === "dyn" || lowerer.dynConvertible(msg.type)) + ? lowerer.coerceToExpected(msg, DYN) + : null; + if (value === null || value.type.kind !== "dyn") { lowerer.noLowering( `assert messages of type '${lowerer.fmt(msg.type)}'`, node, "only string messages lower (Node also accepts an Error to throw — construct and throw it directly)", ); } - return { msg, hasMsg: boolLit(true, loc) }; + const has = lowerer.declareHiddenLocal("assert.hasMessage", BOOL); + const text = lowerer.declareHiddenLocal("assert.messageText", STRING); + valueMessage = { value, has: has.id, text: text.id }; + return { msg: varRef(text.id, STRING, loc), hasMsg: varRef(has.id, BOOL, loc) }; +} + +/** Lowers one assertion; a message value met on the way is evaluated after + * the assertion's other arguments, as Node evaluates them. A null or + * undefined message is omitted (Node's `message == null` test); a truthy + * one is registered with the runtime, which the failure reads; any other + * value is the empty message, which Node's comparison diffs treat as no + * message too (createErrDiff tests the message's truthiness). */ +function withValueMessage( + lowerer: Lowerer, + expr: ts.CallExpression, + loc: SrcLoc, + lower: () => IrExpr | null, +): IrExpr | null { + const outer = valueMessage; + valueMessage = null; + try { + const lowered = lower(); + const message = valueMessage as { value: IrExpr; has: string; text: string } | null; + if (lowered === null || message === null) return lowered; + // assert.ok's statements evaluate the value first; its call is last. + const before = lowered.kind === "seqExpr" ? lowered.stmts : []; + const call = lowered.kind === "seqExpr" ? lowered.result : lowered; + if (call.kind !== "libCall") { + lowerer.noLowering( + "assert messages that are not strings in this assertion form", + expr, + "pass a string message", + ); + } + const stmts: IrStmt[] = [...before]; + const args = call.args.map((arg, index) => + arg.kind === "varRef" && (arg.localId === message.has || arg.localId === message.text) + ? arg + : stableValue(lowerer, stmts, arg, `assert.arg${index}`, loc), + ); + const local = lowerer.declareHiddenLocal("assert.message", DYN); + const value = varRef(local.id, DYN, loc); + stmts.push( + { kind: "varDecl", localId: local.id, init: message.value, loc }, + { + kind: "varDecl", + localId: message.has, + init: { kind: "dynTest", test: "nullish", negated: true, value, type: BOOL, loc }, + loc, + }, + { + kind: "varDecl", + localId: message.text, + init: { + kind: "ternary", + cond: { kind: "dynTest", test: "truthy", value, type: BOOL, loc }, + then: strLit(VALUE_MESSAGE, loc), + else_: strLit("", loc), + type: STRING, + loc, + }, + loc, + }, + { + kind: "if", + cond: { kind: "dynTest", test: "truthy", value, type: BOOL, loc }, + then: [ + { + kind: "exprStmt", + expr: { + kind: "libCall", + fn: "assert.messageValue", + args: [value, { kind: "dynTest", test: "error", value, type: BOOL, loc }], + type: VOID, + loc, + }, + loc, + }, + ], + else_: null, + loc, + }, + { kind: "exprStmt", expr: { ...call, args }, loc }, + ); + return { + kind: "seqExpr", + stmts, + result: { kind: "libCall", fn: "assert.messageClear", args: [], type: VOID, loc }, + type: VOID, + loc, + }; + } finally { + valueMessage = outer; + } } /** The module-function dispatch — the spoke's entry, called from both the @@ -201,6 +370,15 @@ export function lowerAssertModuleCall( loc: SrcLoc, ): IrExpr | null { if (bi.module !== "assert" && bi.module !== "assert/strict") return null; + return withValueMessage(lowerer, expr, loc, () => lowerAssertMember(lowerer, expr, bi, loc)); +} + +function lowerAssertMember( + lowerer: Lowerer, + expr: ts.CallExpression, + bi: { module: string; member: string }, + loc: SrcLoc, +): IrExpr | null { switch (canonicalAssertMember(bi.module, bi.member)) { case "ok": return lowerAssertOk(lowerer, expr, loc); @@ -880,7 +1058,7 @@ export function lowerAssertDirectCall( 'use the default import: import assert from "node:assert")', ); } - return lowerAssertOk(lowerer, expr, loc); + return withValueMessage(lowerer, expr, loc, () => lowerAssertOk(lowerer, expr, loc)); } /** assert(value[, message]) / assert.ok(value[, message]): the truthiness @@ -889,7 +1067,24 @@ export function lowerAssertDirectCall( * the same bytes at compile time). */ function lowerAssertOk(lowerer: Lowerer, expr: ts.CallExpression, loc: SrcLoc): IrExpr { requireStatementPosition(lowerer, expr, ts.getTextOfNode(expr.expression)); - if (expr.arguments.nodes.length < 1 || expr.arguments.nodes.length > 2) { + if (expr.arguments.nodes.length === 0) { + // Node's message for a call without arguments. + const text = "No value argument passed to `assert.ok()`"; + return { + kind: "seqExpr", + stmts: [recordOnFailure(lowerer, boolLit(true, loc), null, boolLit(true, loc), "==", loc)], + result: { + kind: "libCall", + fn: "assert.ok", + args: [boolLit(false, loc), strLit(text, loc), boolLit(true, loc)], + type: VOID, + loc, + }, + type: VOID, + loc, + }; + } + if (expr.arguments.nodes.length > 2) { lowerer.noLowering( `${ts.getTextOfNode(expr.expression)} with ${expr.arguments.nodes.length} arguments`, expr, @@ -1056,9 +1251,22 @@ function lowerAssertEqual( // would answer false where Node can answer true (the value's own // earlier crossing) — a miscompare, never lowered. Bytes fence both // ways (the dyn copy cannot carry the Buffer/Uint8Array brand the - // checker type knows); class instances and everything non-convertible - // keep the fence too. - if (a.type.kind === "dyn" || b.type.kind === "dyn") { + // checker type knows); everything non-convertible keeps the fence too. + // A class instance crosses as a reference to the instance itself, so + // strict compares are honest reference equality, between two instances + // too (assert.strictEqual(e, e.setMaxListeners(1))). + const instanceType = (t: IrType): boolean => + isDynTypedRefType(t) && !lowerer.isSubclassOf(t.className, "%Error"); + const instance = (e: IrExpr): boolean => + !deep && + (instanceType(e.type) || + (e.type.kind === "union" && + (lowerer.unions + .get(e.type.unionId) + ?.arms.every((arm) => instanceType(arm) || isUnitType(arm)) ?? + false))) && + lowerer.dynConvertible(e.type); + if (a.type.kind === "dyn" || b.type.kind === "dyn" || (instance(a) && instance(b))) { const box = (e: IrExpr, node: ts.Expression): IrExpr => { if (e.type.kind === "dyn") return e; const k = e.type.kind; @@ -1067,6 +1275,18 @@ function lowerAssertEqual( k === "f64" || k === "string" || k === "bool" || + // A union of scalars and units crosses by value, like its arms. + (e.type.kind === "union" && + (lowerer.unions + .get(e.type.unionId) + ?.arms.every( + (arm) => + arm.kind === "f64" || + arm.kind === "string" || + arm.kind === "bool" || + isUnitType(arm), + ) ?? + false)) || (k === "func" && lowerer.dynConvertible(e.type)) || // Runtime handles cross by REFERENCE (identity preserved), so the // strict compare is honest: assert.strictEqual(this, server) — @@ -1082,6 +1302,9 @@ function lowerAssertEqual( // same). The deep walk compares the retained error data without // re-encoding and losing identity (SEMANTICS.md). (k === "object" && e.type.kind === "object" && e.type.className === "%Error") || + instance(e) || + // A symbol crosses as itself, so strict compares are identity. + (!deep && k === "symbol") || (deep && k !== "bytes" && k !== "object" && lowerer.dynConvertible(e.type)) || // Under skipPrototype the prototype a class instance or Buffer // brand would carry is not compared. @@ -1470,17 +1693,29 @@ function classifyThrowsExpected( displayName: rec ? rec.lib : info.def.name.replace(/^%/, ""), }; } - if ( - (surface === "assert.doesNotThrow" || surface === "assert.doesNotReject") && - expectedT?.kind === "func" - ) { + if (expectedT?.kind === "func") { const value = lowerer.lowerExpr(node); + // An untyped value there (a dynamic-tier function's result) is checked + // at run time like any untyped expected value. + if (value.type.kind === "jsval" || value.type.kind === "dyn") { + const boxed = lowerer.coerceToExpected(value, DYN); + if (boxed.type.kind === "dyn") return { form: "errValue", value: boxed }; + } + // A JavaScript function accepts any argument; a typed one must take + // unknown values (the caught value need not be an Error). if ( value.type.kind === "func" && - value.type.params.every((param) => param.kind === "dyn") && + (value.type.params.every((param) => param.kind === "dyn") || + isJsSourceFile(ts.getSourceFileOfNode(node))) && lowerer.dynConvertible(value.type) ) { - return { form: "predicate", value: lowerer.coerceToExpected(value, DYN) }; + // The boxed function carries its source name (Node's message names + // a named validation function). + const fnName = jsFuncNameOf(node); + return { + form: "predicate", + value: { kind: "dynFrom", value, ...(fnName !== null ? { fnName } : {}), type: DYN, loc }, + }; } lowerer.noLowering( `${surface} with this validation callback`, @@ -1546,7 +1781,9 @@ function classifyThrowsExpected( // tracingChannel suite's shape): the value crosses as a dyn error and // the runtime compares per Node's expectsError key walk. A // checked-dynamic expected rides directly; a static %Error boxes. - if (expectedT?.kind === "dyn") { + // An untyped JavaScript value (a parameter) too: a function there is + // checked at run time (assertThrowsHelper). + if (expectedT?.kind === "dyn" || expectedT === null) { const value = lowerer.lowerExpr(node); if (value.type.kind === "dyn") return { form: "errValue", value }; } @@ -1943,6 +2180,46 @@ function assertThrowsHelper( return { e: strLit("", loc), has: false }; })(); + // expectedException's function branch: a function with a prototype that + // the caught value is an instance of passes; anything else is called as + // a validation function, whose result must be true. + const validateStmts = (fn: IrExpr): IrStmt[] => { + const actual = (): IrExpr => ({ kind: "caughtToDyn", value: caughtRef(), type: DYN, loc }); + const prototype: IrExpr = { + kind: "dynKeyGet", + value: fn, + key: strLit("prototype", loc), + optional: true, + type: DYN, + loc, + }; + return [ + ifStmt( + { kind: "dynTest", test: "undefined", negated: true, value: prototype, type: BOOL, loc }, + [ + ifStmt( + checkedClassInstanceOf( + lowerer, + actual(), + fn, + "assert.throws against this native constructor is not supported yet", + loc, + ), + [doReturn], + ), + ], + ), + lib("assert.throwsValidate", [ + actual(), + fn, + strLit(mode === "rejects" ? "rejects" : "throws", loc), + m(), + hm(), + ]), + doReturn, + ]; + }; + let catchBody: IrStmt[]; if (mode === "dnr" || mode === "dnt") { const actual = (): IrExpr => ({ kind: "caughtToDyn", value: caughtRef(), type: DYN, loc }); @@ -2116,7 +2393,13 @@ function assertThrowsHelper( // caught value crosses as a dyn value (identity-preserving) and // the runtime walks the expected's keys — a mismatch throws the // deep-equal AssertionError. + // A function there is a validation function (or an error class + // value) as in the predicate form. catchBody = [ + ifStmt( + { kind: "dynTest", test: "function", value: varRef("ev.0", DYN, loc), type: BOOL, loc }, + validateStmts(varRef("ev.0", DYN, loc)), + ), lib("assert.expectsErrDyn", [ { kind: "caughtToDyn", value: caughtRef(), type: DYN, loc }, varRef("ev.0", DYN, loc), @@ -2127,7 +2410,8 @@ function assertThrowsHelper( ]; break; case "predicate": - throw new InternalCompilerError("assert validation callback only enters a no-error helper"); + catchBody = validateStmts(varRef("predicate.0", DYN, loc)); + break; } } diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 14565aebc..a75796cba 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -1,3 +1,4 @@ +import { assertFunctionAliasOf } from "./lower-assert.js"; import { keyedHelperName } from "./stable-names.js"; import { perKeyOrder } from "./key-order-witness.js"; import { isForwardedTupleSpread, lowerForwardingApply } from "./typed-arguments.js"; @@ -1052,6 +1053,13 @@ export function lowerCall(lowerer: Lowerer, expr: ts.CallExpression): IrExpr { } const bi = lowerer.builtinImportOf(expr.expression); if (bi) return lowerBuiltinCall(lowerer, expr, bi, loc); + // A constant bound to an assert method (`const ok = assert.ok`) called + // directly is that assertion, with the message Node quotes the call for. + { + const alias = assertFunctionAliasOf(lowerer, expr.expression); + const served = alias ? lowerer.lowerAssertModuleCall(expr, alias, loc) : null; + if (served) return served; + } // The assert module binding called DIRECTLY (`assert(x)` — a default // import or the CJS `const assert = require("assert")`): Node's // module object IS assert.ok; namespace-import bindings fence inside @@ -8703,7 +8711,12 @@ function lowerObjectStaticCall( (probed && isDynTypedRefType(probed.type)) || (probed?.type.kind === "object" && lowerer.errorHierarchyClassOf(probed.type.className)) || (probed && constructor && (constructor.callableBase || hasRuntimeStatics(constructor))) || - (probed?.type.kind === "func" && lowerer.dynConvertible(probed.type)) + (probed?.type.kind === "func" && lowerer.dynConvertible(probed.type)) || + // null, undefined and unions of untyped JavaScript values: the same + // probe, whose ToObject throws Node's TypeError on nullish. + (probed && + (isUnitType(probed.type) || probed.type.kind === "union") && + lowerer.dynConvertible(probed.type)) ) { const loc = locOf(call); const receiver = lowerer.coerceToExpected(probed, DYN); diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index c50676863..ddb764305 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -1626,6 +1626,44 @@ const THROWN_AS_DYN: ReadonlySet = new Set([ "regex", ]); +/** A `return` at the top level of a CommonJS module (preflight admits it + * there only): it ends the module's evaluation, and its value is + * evaluated and discarded, as Node's module wrapper does. Top-level + * bindings and export assignments after it would be left uninitialized + * where Node leaves them in their temporal dead zone or absent, so a + * module with any keeps a refusal. Null for a return inside a function. */ +function lowerModuleLevelReturn(lowerer: Lowerer, stmt: ts.ReturnStatement): IrStmt | null { + let top: ts.Node = stmt; + while (top.parent !== undefined && !ts.isSourceFile(top.parent)) { + if (ts.isFunctionLike(top.parent) || ts.isClassStaticBlockDeclaration(top.parent)) return null; + top = top.parent; + } + const sf = top.parent; + if (sf === undefined || !ts.isSourceFile(sf)) return null; + const stmts = sf.statements.nodes; + const later = stmts.slice(stmts.indexOf(top as ts.Statement) + 1); + if ( + later.some( + (s) => + ts.isVariableStatement(s) || ts.isClassDeclaration(s) || cjsExportAssignmentOf(s) !== null, + ) + ) { + lowerer.unsupported( + "SC1090", + stmt, + "a top-level return in a CommonJS module that declares variables or classes, or assigns exports, after it", + ); + } + const loc = locOf(stmt); + const ret: IrStmt = { kind: "return", value: null, loc }; + if (!stmt.expression) return ret; + return { + kind: "block", + body: [{ kind: "exprStmt", expr: lowerer.lowerExpr(stmt.expression), loc }, ret], + loc, + }; +} + export function lowerStmt(lowerer: Lowerer, stmt: ts.Statement): IrStmt | IrStmt[] | null { if (ownPrototypeResetStatement(lowerer, stmt)) return { kind: "block", body: [], loc: locOf(stmt) }; @@ -1735,6 +1773,8 @@ export function lowerStmt(lowerer: Lowerer, stmt: ts.Statement): IrStmt | IrStmt if (ts.isForOfStatement(stmt)) return lowerer.lowerForOf(stmt); if (ts.isLabeledStatement(stmt)) return lowerLabeled(lowerer, stmt); if (ts.isReturnStatement(stmt)) { + const moduleReturn = lowerModuleLevelReturn(lowerer, stmt); + if (moduleReturn) return moduleReturn; // Implicit-any instance RETURN INFERENCE (function-returns.ts // resolveInferredReturn): the value lowers BARE and the statement // records itself — the post-pass settles the instance's return type diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 78980d322..8ef5a42a4 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -593,7 +593,11 @@ import { lowerTestMethodCall, lowerTestCtxProperty, } from "./lower-test.js"; -import { lowerAssertModuleCall, lowerAssertDirectCall } from "./lower-assert.js"; +import { + assertFunctionValue, + lowerAssertModuleCall, + lowerAssertDirectCall, +} from "./lower-assert.js"; import type { AssertInstanceOptions } from "./assert-instances.js"; import { lowerUtilModuleCall } from "./lower-inspect.js"; import { lowerSystemErrorMapValue } from "./lower-system-errors.js"; @@ -13985,6 +13989,8 @@ export class Lowerer { * deliberately narrower than table membership because many table rows * are only dispatch sentinels for call-site-specific lowering. */ lowerBuiltinCallableValue(bi: { module: string; member: string }, loc: SrcLoc): IrExpr | null { + const assertion = assertFunctionValue(bi, loc); + if (assertion) return assertion; if (bi.module === "util" && bi.member === "types") return utilTypesModuleValue(this, loc); if (bi.module === "util/types" && builtinModuleFnOf(this, bi.module, bi.member)) return lowerUtilTypeValue(this, bi.member, loc); diff --git a/packages/compiler/src/frontend/lowering/surfaces.ts b/packages/compiler/src/frontend/lowering/surfaces.ts index 90acabce6..310d6f50b 100644 --- a/packages/compiler/src/frontend/lowering/surfaces.ts +++ b/packages/compiler/src/frontend/lowering/surfaces.ts @@ -873,6 +873,12 @@ export const OBJECT_CALLABLE_VALUES: Record result: DYN, valueParams: exactValueParams(DYN, DYN), }, + hasOwn: { + fn: "dyn.hasOwnComputed", + params: [DYN, DYN], + result: BOOL, + valueParams: exactValueParams(DYN, DYN), + }, keys: { fn: "dyn.objKeys", params: [DYN], result: DYN, valueParams: exactValueParams(DYN) }, values: { fn: "dyn.objValues", params: [DYN], result: DYN, valueParams: exactValueParams(DYN) }, entries: { fn: "dyn.objEntries", params: [DYN], result: DYN, valueParams: exactValueParams(DYN) }, diff --git a/packages/compiler/src/frontend/program.ts b/packages/compiler/src/frontend/program.ts index bf75127c4..664759d54 100644 --- a/packages/compiler/src/frontend/program.ts +++ b/packages/compiler/src/frontend/program.ts @@ -5358,6 +5358,16 @@ function preflight7(load: LoadResult): { return new RegExp(`\\btypeof\\s*\\(?\\s*${name.replace(/\$/g, "\\$")}(?![\\w$])`).test(sf.text); }; + // A `return` at the top level of a CommonJS module (TS1108): Node runs + // the module as a function body, so the return ends the module's + // evaluation. ES modules and TypeScript keep the error. + const cjsTopLevelReturnSuppressed = (p: ts.Program, d: ts.Diagnostic): boolean => { + if (d.code !== 1108 || d.fileName === undefined || !isJsSourceFileName(d.fileName)) + return false; + const sf = p.getSourceFile(d.fileName); + return sf !== undefined && isCjsJsFile7(sf, p); + }; + const workspaceImplicitAnySuppressed = (p: ts.Program, d: ts.Diagnostic): boolean => { if (d.code !== 7016 || d.fileName === undefined || d.pos === undefined || d.end === undefined) return false; @@ -5404,6 +5414,7 @@ function preflight7(load: LoadResult): { !isNpmStaticSubclassArgument(p, d) && !workspaceImplicitAnySuppressed(p, d) && !typeofTestedNameSuppressed(p, d) && + !cjsTopLevelReturnSuppressed(p, d) && !jsdocTypeSuppressed(p, d, commentDup), ); }; diff --git a/packages/compiler/src/frontend/tsc-codes.ts b/packages/compiler/src/frontend/tsc-codes.ts index e6c0be7cd..e8ffc29fb 100644 --- a/packages/compiler/src/frontend/tsc-codes.ts +++ b/packages/compiler/src/frontend/tsc-codes.ts @@ -132,6 +132,10 @@ export const JS_RELAXED_TSC_CODES: ReadonlySet = new Set([ // binding types as any and reached uses fence instead of passing unchecked 2307, 2792, + // `delete` of a property the inference typed required (2790): JS deletes + // any configurable property, and the lowering checks each delete's + // receiver itself + 2790, // useUnknownInCatchVariables' annotation demand ("'e' is of type // 'unknown'", "Object is of type 'unknown'"): a JS catch clause CANNOT // annotate its variable, so the demand is unsatisfiable in source — diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index 390c7fbc3..1924dc7b2 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -976,6 +976,7 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "assert.noErrorPredicate", "assert.regexDynTest", "assert.expectsErrDyn", + "assert.throwsValidate", "assert.ifErrorErr", "assert.ifErrorF64", "assert.ifErrorStr", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 216e46a4d..25a86a82b 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -4410,6 +4410,12 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ // The equality quartet over checked-dynamic operands (the frontend // boxes a static side into the checked-dynamic tree first). "assert.eqDyn": { argTypes: [DYN, DYN, BOOL, BOOL, STRING, BOOL], result: VOID }, + /** A message argument that is not a string, registered for the next + * failing assertion (scr_assert_message_value). */ + "assert.messageValue": { argTypes: [DYN, BOOL], result: VOID }, + /** An assert method as a function value, by canonical name. */ + "assert.methodValue": { argTypes: [STRING], result: DYN }, + "assert.messageClear": { argTypes: [], result: VOID }, "assert.looseResult": { argTypes: [BOOL, BOOL, STRING, STRING, STRING, BOOL], result: VOID }, // The throws(fn, {shape}) accumulator: begin/slot calls never throw; // shapeEnd throws the Comparison diff. The error slot is the @@ -4435,6 +4441,8 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ * against the caught value's; a mismatch throws the deep-equal * AssertionError (scr_assert.c). MAY THROW by design. */ "assert.expectsErrDyn": { argTypes: [DYN, DYN, STRING, BOOL], result: VOID }, + /** A validation function against the caught value (Node's expectedException). */ + "assert.throwsValidate": { argTypes: [DYN, DYN, STRING, STRING, BOOL], result: VOID }, // assert.ifError's typed entries (always throw; unit args never // lower). The error slot is program-dependent — any %Error-hierarchy // class, root or subclass (the insp.error precedent, null slot). diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8062-assert-message-values.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8062-assert-message-values.cjs.json new file mode 100644 index 000000000..78ba99298 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8062-assert-message-values.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8062-assert-message-values.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8065-cjs-top-level-return/main.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8065-cjs-top-level-return/main.js.json new file mode 100644 index 000000000..22edecf3f --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8065-cjs-top-level-return/main.js.json @@ -0,0 +1,7 @@ +{ + "order": [ + "/tests/corpus/8065-cjs-top-level-return/early.js", + "/tests/corpus/8065-cjs-top-level-return/main.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8066-object-hasown-delete.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8066-object-hasown-delete.cjs.json new file mode 100644 index 000000000..bf862b8f2 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8066-object-hasown-delete.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8066-object-hasown-delete.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8067-assert-throws-validators.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8067-assert-throws-validators.cjs.json new file mode 100644 index 000000000..89f59e97c --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8067-assert-throws-validators.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8067-assert-throws-validators.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8076-assert-instance-identity.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8076-assert-instance-identity.cjs.json new file mode 100644 index 000000000..b4212e234 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8076-assert-instance-identity.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8076-assert-instance-identity.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8078-instanceof-object-function.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8078-instanceof-object-function.cjs.json new file mode 100644 index 000000000..90af753d1 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8078-instanceof-object-function.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8078-instanceof-object-function.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8190-assert-function-values.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8190-assert-function-values.cjs.json new file mode 100644 index 000000000..730dd6360 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8190-assert-function-values.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8190-assert-function-values.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8191-assert-function-values.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8191-assert-function-values.ts.json new file mode 100644 index 000000000..0837dc2ee --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8191-assert-function-values.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8191-assert-function-values.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_assert.c b/packages/runtime/src/scr_assert.c index 4917b1291..738a7729c 100644 --- a/packages/runtime/src/scr_assert.c +++ b/packages/runtime/src/scr_assert.c @@ -212,7 +212,56 @@ bool scr_assert_skip_prototype(void) { return (g_instance_options & SCR_ASSERT_SKIP_PROTOTYPE) != 0; } +/* A message argument that is not a string (an untyped value, or an Error + * to throw): the compiled call registers it before the assertion and passes + * SCR_ASSERT_VALUE_MESSAGE as its message, which the failure paths compose + * like any custom message. A failure whose message starts with it throws + * the Error itself (innerFail's `message instanceof Error`) or puts + * String(value) in its place with generatedMessage `!value`, as Node's + * AssertionError does. Matching the sentinel keeps a registration that no + * failure consumed from reaching another assertion. */ +static SCR_TL ScrDyn *g_message_value; +static SCR_TL bool g_message_error; + +void scr_assert_message_value(ScrDyn *value, bool error) { + if (g_message_value) scr_dyn_release(g_message_value); + g_message_value = scr_dyn_retain(value); + g_message_error = error; +} + +void scr_assert_message_clear(void) { + if (g_message_value) scr_dyn_release(g_message_value); + g_message_value = NULL; +} + void scr_assert_fail(ScrStr *message, bool generated) { + static const char sentinel[] = SCR_ASSERT_VALUE_MESSAGE; + const size_t n = sizeof sentinel - 1; + if (g_message_value && message->len >= n && memcmp(message->data, sentinel, n) == 0) { + ScrDyn *value = g_message_value; + g_message_value = NULL; + if (g_message_error) { + scr_str_release(message); + scr_assert_record(NULL, NULL, NULL); + g_instance_options = 0; + scr_dyn_throw(value); + return; + } + ScrStr *text = scr_dyn_string_coerce_js(value); + generated = !scr_dyn_truthy(value); + scr_dyn_release(value); + if (!text) { + scr_str_release(message); + return; + } + ScrJsonBuf b; + scr_jb_init(&b); + scr_jb_write(&b, text->data, text->len); + scr_jb_write(&b, message->data + n, message->len - n); + scr_str_release(text); + scr_str_release(message); + message = scr_jb_finish(&b); + } ScrError *e = scr_assert_error(message, generated, scr_assert_diff_full() ? "full" : "simple"); g_instance_options = 0; scr_throw_obj(e, &scr_error_retain_v, &scr_error_release_v, scr_error_trace_arg()); @@ -2703,6 +2752,60 @@ bool scr_assert_no_error_predicate(ScrDyn *predicate, ScrDyn *actual) { return matched; } +/* assert.throws/rejects with a validation function (expectedException's + * function branch, after its instanceof check): the function runs with a + * fresh object as `this` and the caught value, and any result but true + * fails, with Node's generated message unless the call passed one. The + * caught value and the function are the AssertionError's actual and + * expected. Borrows all. */ +void scr_assert_throws_validate(ScrDyn *actual, ScrDyn *validate, ScrStr *op, ScrStr *msg, + bool has_msg) { + ScrDyn *receiver = scr_dyn_new_obj(); + scr_dyn_this_push_dyn(receiver); + ScrDyn *result = scr_dyn_call(validate, &actual, 1, "expected"); + scr_dyn_this_pop(); + scr_dyn_release(receiver); + if (!result) return; + if (result->kind == SCR_DYN_BOOL && result->v.b) { + scr_dyn_release(result); + return; + } + ScrStr *message; + bool generated = !(has_msg && msg->len > 0); + if (!generated) { + message = scr_str_retain(msg); + } else { + ScrAssertBuf b = {0}; + ab_cstr(&b, "The "); + ScrDyn *name = scr_dyn_fn_get(validate, "name", 4); + if (name && name->kind == SCR_DYN_STR && name->v.str->len > 0) { + ab_cstr(&b, "\""); + ab_bytes(&b, name->v.str->data, name->v.str->len); + ab_cstr(&b, "\" "); + } + if (name) scr_dyn_release(name); + ab_cstr(&b, "validation function is expected to return \"true\". Received "); + ScrStr *shown = scr_assert_cf_inspect(result); + ab_bytes(&b, shown->data, shown->len); + scr_str_release(shown); + if (scr_dyn_ref_is_error(actual)) { + ScrStr *text = scr_dyn_string_coerce_js(actual); + if (!text) { + scr_dyn_release(result); + scr_str_release(ab_take(&b)); + return; + } + ab_cstr(&b, "\n\nCaught error:\n\n"); + ab_bytes(&b, text->data, text->len); + scr_str_release(text); + } + message = ab_take(&b); + } + scr_dyn_release(result); + scr_assert_record_dyn(actual, validate, op); + scr_assert_fail(message, generated); +} + /* ── assert.ifError ─────────────────────────────────────────────────── * Node throws for ANY value but null/undefined (falsy included); the * frontend routes null/undefined to a no-op and everything else here. @@ -2879,3 +2982,214 @@ ScrError *scr_assert_error_new(ScrDyn *options) { scr_assert_attach_values(e, generated, actual, expected, op, diff); return e; } + +/* ── assert functions as values ────────────────────────────────────────── + * `assert.fail` stored or passed as a function (`emitter.on("x", + * assert.fail)`): one function per method, which takes its arguments as + * untyped values and asserts as the method does. */ + +/* Node's message argument: absent or null/undefined (a generated message), + * a string, an Error (thrown when the assertion fails), or another value + * (String(value)). The value is registered as scr_assert_fail reads it; the + * caller clears it after the assertion. +1 into *msg. */ +static void scr_av_message(ScrDyn *const *args, size_t argc, size_t i, ScrStr **msg, bool *has) { + const ScrDyn *m = i < argc ? args[i] : NULL; + if (!m || m->kind == SCR_DYN_UNDEF || m->kind == SCR_DYN_NULL) { + *msg = scr_str_new("", 0); + *has = false; + return; + } + *has = true; + if (m->kind == SCR_DYN_STR) { + *msg = scr_str_retain(m->v.str); + return; + } + bool error = scr_dyn_ref_is_error(m) || + (m->kind == SCR_DYN_OBJ && scr_dyn_obj_get(m, "%error", 6) != NULL); + scr_assert_message_value((ScrDyn *)m, error); + *msg = scr_str_new(SCR_ASSERT_VALUE_MESSAGE, sizeof SCR_ASSERT_VALUE_MESSAGE - 1); +} + +static const ScrDyn *scr_av_arg(ScrDyn *const *args, size_t argc, size_t i) { + return i < argc ? args[i] : scr_dyn_undefined(); +} + +static ScrDyn *scr_av_done(ScrStr *msg) { + scr_str_release(msg); + scr_assert_message_clear(); + return scr_dyn_retain(scr_dyn_undefined()); +} + +/* assert(value, message) and assert.ok: Node's generated message quotes + * the call's source, which a function value has no fixed site for; the + * message here is AssertionError's own `value == true`. */ +static ScrDyn *scr_av_ok(ScrClosure *c, ScrDyn *const *args, size_t argc) { + (void)c; + const ScrDyn *value = scr_av_arg(args, argc, 0); + if (scr_dyn_truthy(value)) return scr_dyn_retain(scr_dyn_undefined()); + scr_assert_record(scr_dyn_retain((ScrDyn *)value), scr_dyn_new_bool(true), "=="); + if (argc == 0) { + static const char text[] = "No value argument passed to `assert.ok()`"; + scr_assert_fail(scr_str_new(text, sizeof text - 1), true); + return NULL; + } + ScrStr *msg; + bool has; + scr_av_message(args, argc, 1, &msg, &has); + if (has) { + scr_assert_fail(scr_str_retain(msg), false); + return scr_av_done(msg); + } + ScrStr *shown = scr_assert_cf_inspect(value); + ScrAssertBuf b = {0}; + ab_str(&b, shown); + ab_cstr(&b, " == true"); + scr_str_release(shown); + scr_assert_fail(ab_take(&b), true); + return scr_av_done(msg); +} + +/* assert.fail(message): "Failed" without a message. */ +static ScrDyn *scr_av_fail(ScrClosure *c, ScrDyn *const *args, size_t argc) { + (void)c; + if (argc > 1) { + static const char text[] = "assert.fail with more than one argument through a function value is not supported yet"; + scr_throw_error_msg_code(SCR_ERR_ERROR, text, sizeof text - 1, "SC2020"); + return NULL; + } + ScrStr *msg; + bool has; + scr_av_message(args, argc, 0, &msg, &has); + scr_assert_record(scr_dyn_retain(scr_dyn_undefined()), scr_dyn_retain(scr_dyn_undefined()), "fail"); + if (has) scr_assert_fail(scr_str_retain(msg), false); + else scr_assert_fail(scr_str_new("Failed", 6), true); + return scr_av_done(msg); +} + +/* equal / notEqual: Node's loose comparison, NaN equal to NaN. */ +static ScrDyn *scr_av_loose(ScrDyn *const *args, size_t argc, bool negated) { + const ScrDyn *a = scr_av_arg(args, argc, 0), *b = scr_av_arg(args, argc, 1); + bool nan = a->kind == SCR_DYN_NUM && b->kind == SCR_DYN_NUM && isnan(a->v.num) && isnan(b->v.num); + bool equal = nan || scr_dyn_abstract_eq(a, b); + if (scr_exc_pending()) return NULL; + if (negated ? !equal : equal) return scr_dyn_retain(scr_dyn_undefined()); + ScrStr *msg; + bool has; + scr_av_message(args, argc, 2, &msg, &has); + scr_assert_record(scr_dyn_retain((ScrDyn *)a), scr_dyn_retain((ScrDyn *)b), negated ? "!=" : "=="); + ScrStr *ia = scr_assert_cf_inspect(a), *ib = scr_assert_cf_inspect(b); + scr_assert_loose_result(equal, negated, ia, ib, msg, has); + scr_str_release(ia); + scr_str_release(ib); + return scr_av_done(msg); +} + +static ScrDyn *scr_av_equal(ScrClosure *c, ScrDyn *const *a, size_t n) { + (void)c; + return scr_av_loose(a, n, false); +} +static ScrDyn *scr_av_not_equal(ScrClosure *c, ScrDyn *const *a, size_t n) { + (void)c; + return scr_av_loose(a, n, true); +} + +/* The strict and deep comparisons, through the untyped assert paths. */ +enum { SCR_AV_STRICT, SCR_AV_DEEP_STRICT, SCR_AV_DEEP, SCR_AV_PARTIAL }; + +static ScrDyn *scr_av_compare(ScrDyn *const *args, size_t argc, int form, bool negated) { + ScrDyn *a = (ScrDyn *)scr_av_arg(args, argc, 0), *b = (ScrDyn *)scr_av_arg(args, argc, 1); + ScrStr *msg; + bool has; + scr_av_message(args, argc, 2, &msg, &has); + if (form == SCR_AV_DEEP) scr_assert_loose_deep_dyn(a, b, negated, msg, has); + else if (form == SCR_AV_PARTIAL) scr_assert_partial_deep_dyn(a, b, msg, has); + else scr_assert_eq_dyn(a, b, negated, form == SCR_AV_DEEP_STRICT, msg, has); + return scr_av_done(msg); +} + +static ScrDyn *scr_av_strict_equal(ScrClosure *c, ScrDyn *const *a, size_t n) { + (void)c; + return scr_av_compare(a, n, SCR_AV_STRICT, false); +} +static ScrDyn *scr_av_not_strict_equal(ScrClosure *c, ScrDyn *const *a, size_t n) { + (void)c; + return scr_av_compare(a, n, SCR_AV_STRICT, true); +} +static ScrDyn *scr_av_deep_strict_equal(ScrClosure *c, ScrDyn *const *a, size_t n) { + (void)c; + return scr_av_compare(a, n, SCR_AV_DEEP_STRICT, false); +} +static ScrDyn *scr_av_not_deep_strict_equal(ScrClosure *c, ScrDyn *const *a, size_t n) { + (void)c; + return scr_av_compare(a, n, SCR_AV_DEEP_STRICT, true); +} +static ScrDyn *scr_av_deep_equal(ScrClosure *c, ScrDyn *const *a, size_t n) { + (void)c; + return scr_av_compare(a, n, SCR_AV_DEEP, false); +} +static ScrDyn *scr_av_not_deep_equal(ScrClosure *c, ScrDyn *const *a, size_t n) { + (void)c; + return scr_av_compare(a, n, SCR_AV_DEEP, true); +} +static ScrDyn *scr_av_partial_deep_strict_equal(ScrClosure *c, ScrDyn *const *a, size_t n) { + (void)c; + return scr_av_compare(a, n, SCR_AV_PARTIAL, false); +} + +static ScrDyn *scr_av_if_error(ScrClosure *c, ScrDyn *const *args, size_t argc) { + (void)c; + scr_assert_iferror_dyn(scr_av_arg(args, argc, 0)); + return scr_exc_pending() ? NULL : scr_dyn_retain(scr_dyn_undefined()); +} + +static const struct { + const char *name; + ScrDynThunk thunk; + uint32_t arity; +} scr_av_methods[] = { + {"ok", &scr_av_ok, 0}, + {"fail", &scr_av_fail, 1}, + {"equal", &scr_av_equal, 3}, + {"notEqual", &scr_av_not_equal, 3}, + {"strictEqual", &scr_av_strict_equal, 3}, + {"notStrictEqual", &scr_av_not_strict_equal, 3}, + {"deepEqual", &scr_av_deep_equal, 3}, + {"notDeepEqual", &scr_av_not_deep_equal, 3}, + {"deepStrictEqual", &scr_av_deep_strict_equal, 3}, + {"notDeepStrictEqual", &scr_av_not_deep_strict_equal, 3}, + {"partialDeepStrictEqual", &scr_av_partial_deep_strict_equal, 3}, + {"ifError", &scr_av_if_error, 1}, +}; +#define SCR_AV_COUNT (sizeof scr_av_methods / sizeof scr_av_methods[0]) +static SCR_TL ScrDyn *scr_av_values[SCR_AV_COUNT]; +static SCR_TL bool scr_av_registered; + +static void scr_av_cleanup(void) { + for (size_t i = 0; i < SCR_AV_COUNT; i++) { + scr_dyn_release(scr_av_values[i]); + scr_av_values[i] = NULL; + } + scr_av_registered = false; +} + +/* The function value of an assert method by its canonical name (the frontend + * maps assert/strict's aliases), +1; one value per method, so stored copies + * compare equal. */ +ScrDyn *scr_assert_method_value(ScrStr *name) { + for (size_t i = 0; i < SCR_AV_COUNT; i++) { + if (strlen(scr_av_methods[i].name) != name->len || + memcmp(scr_av_methods[i].name, name->data, name->len) != 0) + continue; + if (!scr_av_values[i]) { + if (!scr_av_registered) { + scr_av_registered = true; + scr_atexit(scr_av_cleanup); + } + scr_av_values[i] = scr_dyn_new_func(scr_closure_new(NULL, 0), scr_av_methods[i].thunk, + scr_av_methods[i].arity, "native:assert", + scr_av_methods[i].name); + } + return scr_dyn_retain(scr_av_values[i]); + } + return scr_dyn_retain(scr_dyn_undefined()); +} diff --git a/packages/runtime/src/scr_assert.h b/packages/runtime/src/scr_assert.h index 8037f08ec..57158a69a 100644 --- a/packages/runtime/src/scr_assert.h +++ b/packages/runtime/src/scr_assert.h @@ -24,6 +24,19 @@ void scr_assert_fail(ScrStr *message, bool generated); /* takes ownership; alway * consumes them; a passing call clears them. */ void scr_assert_set_options(int options); void scr_assert_clear_options(void); +/* A message argument that is not a string, for the next assertion that + * fails with SCR_ASSERT_VALUE_MESSAGE as its message (scr_assert.c): an + * Error (`error`) is thrown as it is, anything else reports String(value). + * Borrows value; clear drops a registration the call did not consume. */ +#define SCR_ASSERT_VALUE_MESSAGE "\x01scriptc:assert-message-value" +void scr_assert_message_value(struct ScrDyn *value, bool error); +void scr_assert_message_clear(void); +/* An assert method as a function value, by canonical name (+1). */ +struct ScrDyn *scr_assert_method_value(ScrStr *name); +/* assert.throws/rejects with a validation function: its result must be + * true (Node's expectedException), else the AssertionError. Borrows all. */ +void scr_assert_throws_validate(struct ScrDyn *actual, struct ScrDyn *validate, ScrStr *op, + ScrStr *msg, bool has_msg); bool scr_assert_diff_full(void); bool scr_assert_skip_prototype(void); void scr_assert_record(ScrDyn *actual, ScrDyn *expected, const char *op); /* values move in */ diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index eb03ab6cc..ecc49e8cf 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -4665,6 +4665,71 @@ int scr_dyn_has_instance_hook(const ScrDyn *value, const ScrDyn *callee) { return truthy ? 1 : 0; } +/* `value instanceof Object`: whether Object.prototype is on the value's + * prototype chain. Primitives answer false, and so does an object whose + * chain ends in null first (Object.create(null), a null-prototype record). + * Objects without a chain the runtime walks (class instances, native + * handles, errors, promises) inherit Object.prototype. False with the + * exception pending when a prototype read throws. */ +static bool scr_dyn_instanceof_object(const ScrDyn *value) { + switch (value->kind) { + case SCR_DYN_UNDEF: + case SCR_DYN_NULL: + case SCR_DYN_BOOL: + case SCR_DYN_NUM: + case SCR_DYN_STR: + case SCR_DYN_BIGINT: + case SCR_DYN_SYMBOL: + return false; + default: + break; + } + ScrDyn *current = scr_dyn_retain((ScrDyn *)value); + for (;;) { + if (current == scr_builtin_object_prototype) { + scr_dyn_release(current); + return true; + } + ScrDyn *next = NULL; + if (current->kind == SCR_DYN_FUNC) { + /* A function's prototype is Function.prototype, whose own is + * Object.prototype, unless the program set it. */ + if (scr_closure_identity(current->v.fn.clo)->props) { + ScrDyn *table = scr_dyn_fn_properties(current); + next = table->prototype ? scr_dyn_retain(table->prototype) + : table->null_proto ? scr_dyn_new_null() : NULL; + scr_dyn_release(table); + } + } else if (current->kind == SCR_DYN_OBJ || current->kind == SCR_DYN_ARR || + (current->kind == SCR_DYN_TYPED_REF && + strncmp(current->v.typed_ref.type_key, "object:", 7) != 0)) { + next = scr_dyn_get_prototype(current); + if (!next) { + scr_dyn_release(current); + return false; /* the read threw: pending */ + } + } + scr_dyn_release(current); + if (!next) return true; + if (next->kind == SCR_DYN_NULL) { + scr_dyn_release(next); + return false; + } + current = next; + } +} + +/* `value instanceof Function`: every function, unless the program set its + * prototype to null or to a non-function. */ +static bool scr_dyn_instanceof_function(const ScrDyn *value) { + if (value->kind != SCR_DYN_FUNC) return false; + if (!scr_closure_identity(value->v.fn.clo)->props) return true; + ScrDyn *table = scr_dyn_fn_properties((ScrDyn *)value); + bool result = table->prototype ? scr_dyn_instanceof_function(table->prototype) : !table->null_proto; + scr_dyn_release(table); + return result; +} + bool scr_bytes_instanceof_at(const ScrDyn *value, const ScrDyn *callee, const ScrStr *refusal) { if (!callee || callee->kind != SCR_DYN_FUNC) { static const char message[] = "Right-hand side of 'instanceof' is not callable"; @@ -4673,6 +4738,13 @@ bool scr_bytes_instanceof_at(const ScrDyn *value, const ScrDyn *callee, const Sc } int hooked = scr_dyn_has_instance_hook(value, callee); if (hooked >= 0) return hooked == 1; + if (callee->v.fn.sig && callee->v.fn.name) { + if (strcmp(callee->v.fn.sig, "native:constructor") == 0 && strcmp(callee->v.fn.name, "Object") == 0) + return scr_dyn_instanceof_object(value); + if (strcmp(callee->v.fn.sig, "native:function-constructor") == 0 && + strcmp(callee->v.fn.name, "Function") == 0) + return scr_dyn_instanceof_function(value); + } /* An error constructor held as a value (`inst instanceof params.Parent` * with Parent === Error): the error kind's interval, and for Error itself * objects inheriting Error.prototype. */ diff --git a/tests/corpus/8062-assert-message-values.cjs b/tests/corpus/8062-assert-message-values.cjs new file mode 100644 index 000000000..7f84ccd37 --- /dev/null +++ b/tests/corpus/8062-assert-message-values.cjs @@ -0,0 +1,41 @@ +'use strict'; +// node:assert messages that are not string literals: an untyped string, an +// Error to throw, null/undefined (omitted) and falsy values, and +// scalar-union operands against untyped values. +const assert = require('assert'); + +function attempt(label, fn) { + try { + fn(); + console.log(label, 'passed'); + } catch (e) { + console.log(label, e.name, JSON.stringify(e.message), e.generatedMessage, e.code); + } +} + +const failures = []; +for (const x of ['a', 'b']) if (x === 'c') failures.push(`\n${x}`); +attempt('joined passes', () => assert.strictEqual(failures.length, 0, failures.join(''))); +const untyped = JSON.parse('"untyped message"'); +attempt('untyped', () => assert.strictEqual(1, 2, untyped)); +attempt('untyped deep', () => assert.deepStrictEqual([1], [2], untyped)); +attempt('untyped notStrict', () => assert.notStrictEqual(1, 1, untyped)); +attempt('error message', () => assert.strictEqual(1, 2, new TypeError('own error'))); +attempt('error deep', () => assert.deepStrictEqual({ a: 1 }, { a: 2 }, new RangeError('own range'))); +const none = JSON.parse('null'); +attempt('null message', () => assert.strictEqual(1, 2, none)); +const zero = JSON.parse('0'); +attempt('zero message deep', () => assert.deepStrictEqual([1], [2], zero)); +attempt('passing error message', () => assert.strictEqual(1, 1, new Error('unused'))); +attempt('later string message', () => assert.strictEqual(1, 2, 'plain')); + +// Operand order: both operands evaluate before the message. +const order = []; +const mark = (label, value) => (order.push(label), value); +attempt('order', () => assert.strictEqual(mark('a', 1), mark('b', 2), mark('m', JSON.parse('"m"')))); +console.log(order.join(',')); + +const row = [['a', 'b', true], ['c', 'd', 'x']]; +for (const [, , expected] of row) { + attempt('union operand', () => assert.strictEqual(JSON.parse(JSON.stringify(expected)), expected)); +} diff --git a/tests/corpus/8065-cjs-top-level-return/early.js b/tests/corpus/8065-cjs-top-level-return/early.js new file mode 100644 index 000000000..8d7de4ba3 --- /dev/null +++ b/tests/corpus/8065-cjs-top-level-return/early.js @@ -0,0 +1,6 @@ +'use strict'; +exports.ready = true; +console.log('early module start', typeof helper); +if (exports.ready) return; +console.log('early module end'); +function helper() {} diff --git a/tests/corpus/8065-cjs-top-level-return/main.js b/tests/corpus/8065-cjs-top-level-return/main.js new file mode 100644 index 000000000..7743eaac5 --- /dev/null +++ b/tests/corpus/8065-cjs-top-level-return/main.js @@ -0,0 +1,16 @@ +'use strict'; +// A CommonJS module may end its evaluation with a top-level return: the +// rest of the module does not run, while timers, exit handlers and the +// modules it already required keep their effects. +const early = require('./early.js'); +console.log('early exports', early.ready); +setTimeout(() => console.log('timer ran'), 1); +process.on('exit', () => console.log('exit handler')); +for (const value of [1, 2, 3]) { + if (value === 2) return 'ignored value'; + console.log('value', value); +} +console.log('not reached'); +function hoisted() { + return 'hoisted'; +} diff --git a/tests/corpus/8065-cjs-top-level-return/package.json b/tests/corpus/8065-cjs-top-level-return/package.json new file mode 100644 index 000000000..5bbefffba --- /dev/null +++ b/tests/corpus/8065-cjs-top-level-return/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/tests/corpus/8066-object-hasown-delete.cjs b/tests/corpus/8066-object-hasown-delete.cjs new file mode 100644 index 000000000..11668b521 --- /dev/null +++ b/tests/corpus/8066-object-hasown-delete.cjs @@ -0,0 +1,23 @@ +'use strict'; +// Object.hasOwn over nullish receivers and as a value, and `delete` of +// properties JavaScript inference types as required. +const o = { a: 1, b: undefined }; +console.log(Object.hasOwn(o, 'a'), Object.hasOwn(o, 'b'), Object.hasOwn(o, 'c')); +console.log(Object.hasOwn([1, 2], 1), Object.hasOwn([1, 2], 2), Object.hasOwn(Object.create({ x: 1 }), 'x')); +for (const value of [null, undefined]) { + try { + Object.hasOwn(value, 'a'); + } catch (e) { + console.log(e.name, e.message); + } +} +const pick = Math.random() < 2 ? { k: 1 } : null; +console.log(Object.hasOwn(pick, 'k')); +const hasOwn = Object.hasOwn; +console.log(hasOwn({ k: 1 }, 'k'), hasOwn({}, 'k'), [{ a: 1 }, {}].map((x) => hasOwn(x, 'a')).join()); +const record = { a: 1, b: 2 }; +delete record.a; +console.log(Object.keys(record).join(), Object.hasOwn(record, 'a'), record.a); +const table = { one: 1, two: 2 }; +for (const key of Object.keys(table)) if (key === 'one') delete table[key]; +console.log(JSON.stringify(table)); diff --git a/tests/corpus/8067-assert-throws-validators.cjs b/tests/corpus/8067-assert-throws-validators.cjs new file mode 100644 index 000000000..189f4221a --- /dev/null +++ b/tests/corpus/8067-assert-throws-validators.cjs @@ -0,0 +1,22 @@ +'use strict'; +// assert.throws and assert.rejects with validation functions, constructor +// functions, and untyped expected values (Node's expectedException). +const assert = require('assert'); +function show(label, fn) { + try { fn(); console.log(label, 'passed'); } catch (e) { console.log(label, e.name, JSON.stringify(e.message), e.generatedMessage, e.operator, e.actual && e.actual.message); } +} +function check(err) { return err.message === 'x'; } +show('named false', () => assert.throws(() => { throw new Error('y'); }, check)); +show('named true', () => assert.throws(() => { throw new Error('x'); }, check)); +show('custom message', () => assert.throws(() => { throw new Error('y'); }, check, 'custom')); +show('returns 1', () => assert.throws(() => { throw new Error('y'); }, () => 1)); +show('non-error thrown', () => assert.throws(() => { throw 'str'; }, (v) => v === 'str')); +show('non-error fails', () => assert.throws(() => { throw 42; }, () => undefined)); +function MyErr(m) { this.message = m; } +show('constructor', () => assert.throws(() => { throw new MyErr('q'); }, MyErr)); +function untyped(expected) { assert.throws(() => { throw new Error('u'); }, expected); } +show('untyped validator', () => untyped((e) => e.message === 'u')); +show('untyped validator fails', () => untyped(function v() { return false; })); +show('untyped object', () => untyped({ message: 'u' })); +assert.rejects(Promise.reject(new Error('r')), (e) => e.message === 'r').then(() => console.log('rejects passed')); +assert.rejects(Promise.reject(new Error('r')), () => false).catch((e) => console.log('rejects', JSON.stringify(e.message), e.operator)); diff --git a/tests/corpus/8076-assert-instance-identity.cjs b/tests/corpus/8076-assert-instance-identity.cjs new file mode 100644 index 000000000..e8cedf3d6 --- /dev/null +++ b/tests/corpus/8076-assert-instance-identity.cjs @@ -0,0 +1,50 @@ +'use strict'; +// assert.strictEqual and notStrictEqual compare class instances by +// reference: two instances, an instance and the same instance read back +// through an untyped value, and an instance a method returns. Symbols +// compare by identity too. +const assert = require('assert'); +const EventEmitter = require('events'); + +class Box { + constructor(v) { + this.v = v; + } + self() { + return this; + } +} + +const b = new Box(1); +const c = new Box(1); +assert.strictEqual(b, b.self()); +assert.notStrictEqual(b, c); +const e = new EventEmitter(); +assert.strictEqual(e, e.setMaxListeners(1)); +const untyped = [e, b][0]; +assert.strictEqual(untyped, e); +assert.strictEqual(e, untyped); +assert.notStrictEqual(untyped, b); + +try { + assert.strictEqual(b, c); +} catch (error) { + console.log(error.code); + console.log(error.message); +} +try { + assert.notStrictEqual(b, b.self(), 'same box'); +} catch (error) { + console.log(error.code, error.message); +} +// A symbol read back through an untyped value is the same symbol. +const symbol = Symbol('s'); +const read = Reflect.get({ k: symbol }, 'k'); +assert.strictEqual(read, symbol); +assert.notStrictEqual(read, Symbol('s')); +try { + assert.strictEqual(read, Symbol('other')); +} catch (error) { + console.log(error.code, error.message.split('\n')[0]); +} +console.log('done'); diff --git a/tests/corpus/8078-instanceof-object-function.cjs b/tests/corpus/8078-instanceof-object-function.cjs new file mode 100644 index 000000000..9a72de00f --- /dev/null +++ b/tests/corpus/8078-instanceof-object-function.cjs @@ -0,0 +1,55 @@ +'use strict'; +// `x instanceof Object` and `x instanceof Function` on untyped values follow +// Node: objects are instances of Object unless their prototype chain ends +// in null first, and functions (classes and arrows included) are instances +// of Function. +class Shape {} +class Square extends Shape {} + +const nullProto = Object.create(null); +const underNull = Object.create(nullProto); +const regrown = Object.create(null); +Object.setPrototypeOf(regrown, {}); +const orphan = function orphan() {}; +Object.setPrototypeOf(orphan, null); +function declared() {} + +const values = { + 'plain object': {}, + array: [1, 2], + 'Object.create(null)': nullProto, + 'object under a null-prototype object': underNull, + 'Object.create(null) given a prototype': regrown, + 'Object.create(plain object)': Object.create({ a: 1 }), + 'parsed JSON': JSON.parse('{"a":[1]}'), + 'function declaration': declared, + 'bound function': declared.bind(null), + 'arrow function': () => 1, + 'async function': async () => {}, + class: Square, + 'class instance': new Square(), + 'function with a null prototype': orphan, + map: new Map(), + date: new Date(0), + 'regular expression': /x/, + error: new TypeError('t'), + 'typed array': new Uint8Array(2), + promise: Promise.resolve(1), + number: 1, + string: 's', + boolean: false, + null: null, + undefined: undefined, + symbol: Symbol('s'), + bigint: 10n, +}; + +for (const [label, value] of Object.entries(values)) { + console.log(`${label}: Object ${value instanceof Object}, Function ${value instanceof Function}`); +} + +function describe(value) { + if (!(value instanceof Object)) return 'primitive or null-prototype'; + return value instanceof Function ? 'function' : 'object'; +} +console.log([nullProto, {}, describe, 0].map(describe).join(', ')); diff --git a/tests/corpus/8190-assert-function-values.cjs b/tests/corpus/8190-assert-function-values.cjs new file mode 100644 index 000000000..b91434899 --- /dev/null +++ b/tests/corpus/8190-assert-function-values.cjs @@ -0,0 +1,30 @@ +'use strict'; +// assert methods are function values: stored, passed and called through +// aliases, they assert as the methods do, and every read is the same +// function. A constant bound to a method and called directly reports +// the call as Node quotes it. +const assert = require('assert'); +const { strictEqual, deepStrictEqual } = require('assert'); +const strict = require('assert/strict'); +const EventEmitter = require('events'); +console.log(typeof assert.fail, assert.fail === assert.fail, strict.equal === assert.strictEqual, strictEqual === assert.strictEqual); +const ok = assert.ok; +ok(1); +const tryIt = (label, fn) => { try { fn(); console.log(label, 'passed'); } catch (e) { console.log(label, e.name, e.code, JSON.stringify(e.message), e.generatedMessage); } }; +tryIt('ok', () => ok(0)); +tryIt('ok none', () => ok()); +tryIt('ok msg', () => ok(false, 'nope')); +tryIt('ok err', () => ok(false, new TypeError('own'))); +tryIt('fail', () => assert.fail.call(null)); +tryIt('fail msg', () => (0, assert.fail)('boom')); +tryIt('equal', () => assert.equal.call(null, 1, '1')); +tryIt('equal fail', () => [assert.equal][0](1, 2)); +tryIt('notEqual fail', () => [assert.notEqual][0](1, '1')); +tryIt('strict', () => strictEqual(1, 2)); +tryIt('deep', () => deepStrictEqual({ a: 1 }, { a: 1 })); +tryIt('deep fail', () => [deepStrictEqual][0]({ a: 1 }, { a: 2 }, 'differs')); +tryIt('ifError', () => [assert.ifError][0](null)); +const checks = [assert.ok, assert.fail, assert.strictEqual]; +checks.forEach((check, i) => console.log(i, typeof check, check === checks[i], check.name)); +[1, 'x', true].forEach((value) => assert.ok(value)); +console.log('done'); diff --git a/tests/corpus/8191-assert-function-values.ts b/tests/corpus/8191-assert-function-values.ts new file mode 100644 index 000000000..8ef24153b --- /dev/null +++ b/tests/corpus/8191-assert-function-values.ts @@ -0,0 +1,16 @@ +// assert methods read as values in TypeScript: a constant alias called +// directly, a stored value, and a method passed as a callback. +import assert from "node:assert"; +const eq = assert.strictEqual; +eq(1, 1); +const fail = assert.fail; +const checks: unknown[] = [assert.ok, assert.fail]; +console.log(typeof checks[0], checks[1] === fail); +try { + eq(1, 2, "one is not two"); +} catch (error) { + console.log((error as Error).message); +} +const run = (fn: (v: unknown) => void) => fn(true); +run(assert.ok); +console.log("done"); diff --git a/tests/coverage-fixtures/startup-fences.js b/tests/coverage-fixtures/startup-fences.js index 22aad4e0a..5e1d00b62 100644 --- a/tests/coverage-fixtures/startup-fences.js +++ b/tests/coverage-fixtures/startup-fences.js @@ -2,8 +2,8 @@ // a fence inside a function runs when the function is called. "use strict"; var value = JSON.parse("{}"); -console.log(value instanceof Object); +console.log(value instanceof WeakRef); function check(other) { - return other instanceof Object; + return other instanceof WeakRef; } console.log(check([])); diff --git a/tests/diagnostics/assert-fences.ts b/tests/diagnostics/assert-fences.ts index 823c64c40..7cf96bc5b 100644 --- a/tests/diagnostics/assert-fences.ts +++ b/tests/diagnostics/assert-fences.ts @@ -5,8 +5,8 @@ // (typed arrays, class instances), namespace-object calls, unsupported // throws/rejects expectations (properties outside the static error // surface, empty shapes, non-literal objects, doesNotReject shapes — -// Node's own TypeError), ifError over uncomparable types, and assert -// functions as values. Every reached site terminates in a named +// Node's own TypeError), ifError over uncomparable types, and assert.throws +// as a value. Every reached site terminates in a named // diagnostic — never a miscompare, never silence. import assert from "node:assert"; import * as assertNs from "node:assert"; @@ -47,8 +47,8 @@ assert.throws(() => { throw new Error("x"); }, {}); // Node rejects the empty sh void assert.doesNotReject(async () => {}, { name: "TypeError" }); // Node's own TypeError (function or RegExp only) assert.ifError(new Map()); // no honest ifError rendering for this type -const eq = assert.strictEqual; // assert functions as values -eq(1, 1); +const throwsFn = assert.throws; // assert.throws as a value: it takes the function to run +throwsFn(() => {}); interface Tree { label: string; kids: Tree[] } const tree: Tree = { label: "t", kids: [] }; diff --git a/tests/harness/__snapshots__/assert-fences.ts.txt b/tests/harness/__snapshots__/assert-fences.ts.txt index 2ab78f117..041c20e9b 100644 --- a/tests/harness/__snapshots__/assert-fences.ts.txt +++ b/tests/harness/__snapshots__/assert-fences.ts.txt @@ -104,12 +104,12 @@ assert-fences.ts:48:16 - error SC2020: 'assert.ifError over 'Map hint: numbers, strings, booleans, Errors, null/undefined, and unions of those are the lowered forms -assert-fences.ts:50:12 - error SC2020: 'assert.strictEqual' is part of the standard library types but has no scriptc lowering yet +assert-fences.ts:50:18 - error SC2020: 'assert.throws' is part of the standard library types but has no scriptc lowering yet 49 | - 50 | const eq = assert.strictEqual; // assert functions as values - | ^~~~~~~~~~~~~~~~~~ - 51 | eq(1, 1); + 50 | const throwsFn = assert.throws; // assert.throws as a value: it takes the function to run + | ^~~~~~~~~~~~~ + 51 | throwsFn(() => {}); hint: the type checker sees the full standard library, but only the supported surface compiles (https://scriptc.dev/limitations) diff --git a/tests/harness/coverage.test.ts b/tests/harness/coverage.test.ts index e1831c609..1046ca6af 100644 --- a/tests/harness/coverage.test.ts +++ b/tests/harness/coverage.test.ts @@ -221,10 +221,10 @@ test("deferred fences in a module's top-level code report as running at startup" ]); const out = report(fixture("startup-fences.js")); expect(out).toMatch( - /runs at startup {3}1 site .*\n.*instanceof against this native constructor\n\s+at tests\/coverage-fixtures\/startup-fences\.js:5:13/, + /runs at startup {3}1 site .*\n.*'instanceof' right-hand sides other than classes declared in the program\n\s+at tests\/coverage-fixtures\/startup-fences\.js:5:30/, ); expect(out).toMatch( - /deferred to runtime {3}1 site .*\n.*instanceof against this native constructor\n\s+at tests\/coverage-fixtures\/startup-fences\.js:7:10/, + /deferred to runtime {3}1 site .*\n.*'instanceof' right-hand sides other than classes declared in the program\n\s+at tests\/coverage-fixtures\/startup-fences\.js:7:27/, ); const envelope = coverageEnvelope(coverage, { compilerVersion: "test", sourceTexts }); expect(envelope.diagnostics.map((d) => [d.scope, d.line, d.startup])).toEqual([ From cd3c48d2b0d7dff2a3b910770e65b6d05df40980 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 08:19:25 -0500 Subject: [PATCH 089/259] Fence fs.readSyncDyn with fs.readSync The readSync form whose arguments are checked at run time lowers to fs.readSyncDyn, which the determinism attestation demotes on. List it as an alias of fs.readSync so the readSync fence witnesses it. --- packages/compiler/src/frontend/lowering/surfaces.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/compiler/src/frontend/lowering/surfaces.ts b/packages/compiler/src/frontend/lowering/surfaces.ts index 90acabce6..15606cc3a 100644 --- a/packages/compiler/src/frontend/lowering/surfaces.ts +++ b/packages/compiler/src/frontend/lowering/surfaces.ts @@ -2127,6 +2127,8 @@ export const BUILTIN_MODULE_FN_ALIASES: Record< ], // The utf8 string overload; the table row is the Buffer-window form. writeSync: ["fs.writeStrSync"], + // The form whose arguments Node checks at run time. + readSync: ["fs.readSyncDyn"], // The { recursive, mode } option lowerings. mkdirSync: ["fs.mkdirModeSync", "fs.mkdirRecursiveSync", "fs.mkdirRecursiveModeSync"], // The { recursive, force } and maxRetries/retryDelay option lowerings. From 427e383b5e104ce59b33014ec4f5e21a3acec5c1 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 08:22:30 -0500 Subject: [PATCH 090/259] Cache untyped property access in programs that declare classes (reland) Reapplies #2017, which #2038 reverted after effect's observability-otlp fixture crashed in plain builds. The crash was the candidate-buffer corruption that the previous commit fixes: the cached property sites change when the collector runs, and with enough environment variables a pass buffered a string box that was later pooled while still buffered. --- benchmarks/runtime/README.md | 1 + .../runtime/workloads/dynamic-properties.json | 6 + .../runtime/workloads/dynamic-properties.mjs | 56 ++++++ packages/compiler/src/ir/js-ic.test.ts | 188 ++++++++++++++++++ packages/compiler/src/ir/js-ic.ts | 92 ++++++++- packages/compiler/test/js-ic-emission.test.ts | 44 ++++ packages/runtime/src/scr_js.h | 11 +- packages/runtime/src/scr_js_object.c | 32 ++- packages/runtime/src/scr_js_object.test.c | 26 ++- scripts/zero-cost-compare.mjs | 5 +- tests/harness/library-mode.test.ts | 20 ++ tests/library-mode/js-ic-sessions/lib.ts | 6 + tests/library-mode/js-ic-sessions/probe.c | 25 +++ .../library-mode/js-ic-sessions/profile.json | 14 ++ tests/library-mode/js-ic-sessions/work.mjs | 26 +++ 15 files changed, 521 insertions(+), 31 deletions(-) create mode 100644 benchmarks/runtime/workloads/dynamic-properties.json create mode 100644 benchmarks/runtime/workloads/dynamic-properties.mjs create mode 100644 tests/library-mode/js-ic-sessions/lib.ts create mode 100644 tests/library-mode/js-ic-sessions/probe.c create mode 100644 tests/library-mode/js-ic-sessions/profile.json create mode 100644 tests/library-mode/js-ic-sessions/work.mjs diff --git a/benchmarks/runtime/README.md b/benchmarks/runtime/README.md index 57d1eaf1a..03238871d 100644 --- a/benchmarks/runtime/README.md +++ b/benchmarks/runtime/README.md @@ -13,6 +13,7 @@ Application-shaped workloads for measuring the speed of compiled executables. Ea | `cyclic-graphs` | cpu | object graphs with back references built and dropped: trees with parent and sibling links, rings of records sharing a long-lived registry, closures capturing their owner | | `dictionary-walks` | cpu | `Record` dictionaries walked with for-in and `Object.keys`/`values`/`entries` while entries are added, updated and deleted | | `dynamic-methods` | cpu | untyped JavaScript calling builtin methods on values it does not type: string `slice`/`indexOf`/`toUpperCase`/`padStart`, array `push`/`pop`/`includes`, `Map` and `Set`, and an object's own methods | +| `dynamic-properties` | cpu | untyped JavaScript reading and writing properties of values it does not type: records built by object literals in two key orders, nested records, and instances of a class and its subclass | | `functional-pipeline` | cpu | `filter`/`map`/`reduce`/`flatMap` chains, closures, small records | | `intern-table`, `intern-table-map`, `intern-table-1`, `intern-table-map-1` | cpu | worker threads interning the same type-like objects under string keys and records under number keys, then hits and misses: one shared `InternTable` per kind of key, or a module-level `Map` per thread (the `-map` entries), with 8 threads or 1 (the `-1` entries); under Node.js every thread has its own tables | | `json-records` | cpu | `JSON.stringify`, typed `JSON.parse`, Map aggregation | diff --git a/benchmarks/runtime/workloads/dynamic-properties.json b/benchmarks/runtime/workloads/dynamic-properties.json new file mode 100644 index 000000000..398981ef3 --- /dev/null +++ b/benchmarks/runtime/workloads/dynamic-properties.json @@ -0,0 +1,6 @@ +{ + "entry": "workloads/dynamic-properties.mjs", + "args": [ + "1000000" + ] +} diff --git a/benchmarks/runtime/workloads/dynamic-properties.mjs b/benchmarks/runtime/workloads/dynamic-properties.mjs new file mode 100644 index 000000000..d0ee3802c --- /dev/null +++ b/benchmarks/runtime/workloads/dynamic-properties.mjs @@ -0,0 +1,56 @@ +// Untyped JavaScript reading and writing properties of values it never +// declares types for: records built by object literals in two key orders, +// nested records, property updates, and instances of a class and its +// subclass read and written the same way. Argument: the number of +// iterations. +const rounds = Number(process.argv[2] ?? "1000000"); +class Cursor { + constructor(x, y) { + this.x = x; + this.y = y; + } + step(dx, dy) { + this.x += dx; + this.y += dy; + return this; + } +} +class Marker extends Cursor { + constructor(x, y, label) { + super(x, y); + this.label = label; + } +} +function makeItem(i) { + if (i % 3 === 0) + return { id: i, price: i % 17, qty: i % 5, meta: { tag: i % 7, weight: i % 11 } }; + return { id: i, qty: i % 5, price: i % 13, meta: { weight: i % 9, tag: i % 5 } }; +} +function cost(item) { + return item.price * item.qty + item.meta.weight; +} +function restock(item, round) { + item.qty = (item.qty + round) % 7; + item.meta.tag = (item.meta.tag + 1) % 7; +} +function distance(a, b) { + return Math.abs(a.x - b.x) + Math.abs(a.y - b.y); +} +const items = []; +for (let i = 0; i < 1024; i++) items.push(makeItem(i)); +const cursors = []; +for (let i = 0; i < 64; i++) + cursors.push(i % 2 === 0 ? new Cursor(i - 32, 7 - i) : new Marker(i - 32, 7 - i, "m" + i)); +const origin = { x: 0, y: 0 }; +let checksum = 0; +for (let r = 0; r < rounds; r++) { + const item = items[r & 1023]; + checksum += cost(item); + restock(item, r & 3); + checksum += item.meta.tag; + const cursor = cursors[r & 63]; + checksum += distance(cursor.step((r % 3) - 1, (r % 5) - 2), origin); + if (cursor.x > 100 || cursor.x < -100) cursor.x = 0; + if (cursor.y > 100 || cursor.y < -100) cursor.y = 0; +} +console.log(checksum, items[5].qty, items[6].meta.tag, cursors[3].x, cursors[3].y, cursors[3].label); diff --git a/packages/compiler/src/ir/js-ic.test.ts b/packages/compiler/src/ir/js-ic.test.ts index f71a1e9db..f5391b83e 100644 --- a/packages/compiler/src/ir/js-ic.test.ts +++ b/packages/compiler/src/ir/js-ic.test.ts @@ -126,6 +126,140 @@ test("property helpers whose class branches only test capsules are cache sites", expect(sites.site("%dyn.class.property.1")).toEqual({ kind: "set", key: "y" }); }); +test("bags converted between dyn and jsval are still the receiver", () => { + // A program that declares a class returns its bags as jsvals, and the + // helpers read them through js.toDyn. + const toDyn = (value: IrExpr): IrExpr => ({ + kind: "libCall", + fn: "js.toDyn", + args: [value], + type: DYN, + loc, + }); + const fromDyn = (value: IrExpr): IrExpr => ({ + kind: "libCall", + fn: "js.fromDyn", + args: [value], + type: { kind: "jsval" }, + loc, + }); + const jsvalBag = helper( + "%dyn.class.readPropertiesOrEmpty.js", + ["v"], + [capsuleBranch("v"), ret(fromDyn(ref("v")))], + ); + const staticBag = helper("%dyn.class.staticProperties", ["v"], [ret(ref("v"))]); + const getter = getHelper( + "%dyn.class.property.0", + "x", + [capsuleBranch("p.0")], + call(staticBag.name, toDyn(call(jsvalBag.name, ref("p.0")))), + ); + const setter = setHelper("%dyn.class.property.1", "y"); + const write = setter.body[0] as Extract; + const keySet = write.expr as Extract; + keySet.args[0] = toDyn(call(jsvalBag.name, ref("p.0"))); + // A converted value that is not the receiver stays a helper call. + const foreign = getHelper( + "%dyn.class.property.2", + "x", + [], + toDyn(fromDyn({ kind: "dynObjLit", type: DYN, loc } as IrExpr)), + ); + const sites = sitesOf(jsvalBag, staticBag, getter, setter, foreign); + expect(sites.site("%dyn.class.property.0")).toEqual({ kind: "get", key: "x" }); + expect(sites.site("%dyn.class.property.1")).toEqual({ kind: "set", key: "y" }); + expect(sites.site("%dyn.class.property.2")).toBeNull(); +}); + +test("a bag helper may first rebind its parameter to a bag of it", () => { + // Programs with subclasses normalize the value before the class branches. + const normalize = helper("%dyn.class.normalize", ["v"], [capsuleBranch("v"), ret(ref("v"))]); + const rebind = (value: IrExpr): IrStmt => ({ kind: "assign", localId: "v", value, loc }); + const normalized = helper( + "%dyn.class.readPropertiesOrEmpty.normalized", + ["v"], + [rebind(call(normalize.name, ref("v"))), capsuleBranch("v"), ret(ref("v"))], + ); + const replaced = helper( + "%dyn.class.readPropertiesOrEmpty.replaced", + ["v"], + [rebind({ kind: "dynObjLit", type: DYN, loc } as IrExpr), ret(ref("v"))], + ); + const sites = sitesOf( + normalize, + normalized, + replaced, + getHelper("%dyn.class.property.0", "x", [], call(normalized.name, ref("p.0"))), + getHelper("%dyn.class.property.1", "x", [], call(replaced.name, ref("p.0"))), + // The property helper itself normalizes its receiver first, too. + getHelper("%dyn.class.property.2", "x", [ + { kind: "assign", localId: "p.0", value: call(normalize.name, ref("p.0")), loc }, + capsuleBranch("p.0"), + ]), + ); + expect(sites.site("%dyn.class.property.0")).toEqual({ kind: "get", key: "x" }); + expect(sites.site("%dyn.class.property.1")).toBeNull(); + expect(sites.site("%dyn.class.property.2")).toEqual({ kind: "get", key: "x" }); +}); + +test("keyed helpers may test capsules between the key's coercion and the read", () => { + const read = (object: IrExpr, key: string): IrExpr => ({ + kind: "libCall", + fn: "js.fromDyn", + args: [{ kind: "dynKeyGet", value: object, key: ref(key), type: DYN, loc }], + type: { kind: "jsval" }, + loc, + }); + const guard = (test: "symbol" | "nullish", tested: string, object: IrExpr): IrStmt => ({ + kind: "if", + cond: { kind: "dynTest", test, value: ref(tested), type: BOOL, loc }, + then: [ret(read(object, "p.key"))], + else_: null, + loc, + }); + const keyed = (name: string, between: IrStmt[]): IrFunction => + helper( + name, + ["p.0", "p.key"], + [ + capsuleBranch("p.0"), + guard("symbol", "p.key", call(identityBag.name, ref("p.0"))), + guard("nullish", "p.0", ref("p.0")), + { + kind: "varDecl", + localId: "key.string", + init: { + kind: "libCall", + fn: "dyn.toStringCoerce", + args: [ref("p.key")], + type: STRING, + loc, + }, + loc, + }, + ...between, + ret(read(call(identityBag.name, ref("p.0")), "key.string")), + ], + ["key.string"], + ); + const errorBranch: IrStmt = { + kind: "if", + cond: { kind: "dynTest", test: "error", value: ref("p.0"), type: BOOL, loc }, + then: [ret(ref("p.0"))], + else_: null, + loc, + }; + const sites = sitesOf( + keyed("%dyn.class.computed.0", []), + keyed("%dyn.class.computed.1", [capsuleBranch("p.0"), capsuleBranch("p.0", "dyn.classIs")]), + keyed("%dyn.class.computed.2", [errorBranch]), + ); + expect(sites.site("%dyn.class.computed.0")).toEqual({ kind: "keyed" }); + expect(sites.site("%dyn.class.computed.1")).toEqual({ kind: "keyed" }); + expect(sites.site("%dyn.class.computed.2")).toBeNull(); +}); + test("any other prefix or tail keeps the helper call", () => { const errorBranch: IrStmt = { kind: "if", @@ -237,3 +371,57 @@ test("bag helpers that exit early for values no class branch matches are still t expect(sites.site("%dyn.class.property.2")).toBeNull(); expect(sites.site("%dyn.class.property.3")).toBeNull(); }); + +test("helpers that answer plain values first with the same operation are cache sites", () => { + const negated = (test: "classCapsule" | "funcKind"): IrExpr => ({ + kind: "dynTest", + test, + negated: true, + value: ref("p.0"), + type: BOOL, + loc, + }); + const exit = (body: IrStmt[], test: IrExpr = negated("classCapsule")): IrStmt => ({ + kind: "if", + cond: test, + then: [{ kind: "if", cond: negated("funcKind"), then: body, else_: null, loc }], + else_: null, + loc, + }); + const store = (key: string): IrStmt[] => [ + { + kind: "exprStmt", + expr: { + kind: "libCall", + fn: "dyn.keySet", + args: [ref("p.0"), str(key), ref("p.1")], + type: VOID, + loc, + }, + loc, + }, + ret(null), + ]; + const load = (key: string): IrStmt[] => [ + ret({ kind: "dynKeyGet", value: ref("p.0"), key: str(key), type: DYN, loc }), + ]; + const sites = sitesOf( + setHelper("%dyn.class.property.0", "x", [exit(store("x")), capsuleBranch("p.0")]), + getHelper("%dyn.class.property.1", "x", [exit(load("x")), capsuleBranch("p.0")]), + // An exit for another key, or one plain values do not take. + setHelper("%dyn.class.property.2", "x", [exit(store("y"))]), + setHelper("%dyn.class.property.3", "x", [ + exit(store("x"), { + kind: "dynTest", + test: "classCapsule", + value: ref("p.0"), + type: BOOL, + loc, + }), + ]), + ); + expect(sites.site("%dyn.class.property.0")).toEqual({ kind: "set", key: "x" }); + expect(sites.site("%dyn.class.property.1")).toEqual({ kind: "get", key: "x" }); + expect(sites.site("%dyn.class.property.2")).toBeNull(); + expect(sites.site("%dyn.class.property.3")).toBeNull(); +}); diff --git a/packages/compiler/src/ir/js-ic.ts b/packages/compiler/src/ir/js-ic.ts index 752316db3..48019636a 100644 --- a/packages/compiler/src/ir/js-ic.ts +++ b/packages/compiler/src/ir/js-ic.ts @@ -61,13 +61,68 @@ export class JsIcSites { if (fn.params.some((p) => p.type.kind !== "dyn")) return null; const receiver = fn.params[0]?.localId; if (receiver === undefined) return null; + const second = fn.params[1]?.localId; + const exits: JsIcSite[] = []; let i = 0; - while (i < fn.body.length && this.capsuleBranch(fn.body[i]!, receiver)) i++; + for (; i < fn.body.length; i++) { + const s = fn.body[i]!; + if (this.capsuleBranch(s, receiver) || this.rebinding(s, receiver)) continue; + const exit = this.plainExit(s, receiver, second); + if (exit === null) break; + exits.push(exit); + } const tail = fn.body.slice(i); - if (fn.params.length === 1) return this.getTail(tail, receiver); - if (fn.params.length !== 2) return null; - const second = fn.params[1]!.localId; - return this.setTail(tail, receiver, second) ?? this.keyedTail(tail, receiver, second); + let site: JsIcSite | null; + if (fn.params.length === 1) site = this.getTail(tail, receiver); + else if (fn.params.length !== 2 || second === undefined) return null; + else site = this.setTail(tail, receiver, second) ?? this.keyedTail(tail, receiver, second); + if (site === null || site.kind === "keyed") return exits.length === 0 ? site : null; + // An exit answers plain values with the operation the site caches. + return exits.every((exit) => exit.kind === site.kind && exit.key === site.key) ? site : null; + } + + /** `if (!classCapsule(receiver)) { [if (!funcKind(receiver))] OP }`, no + * else: an exit that runs the helper's generic operation directly on a + * value no class table matches. OP is `return [js.fromDyn](dynKeyGet(R, + * K))` or `dyn.keySet(R, K, value); return`, with R the receiver (or a + * bag of it). */ + private plainExit(s: IrStmt, receiver: string, value: string | undefined): JsIcSite | null { + const negated = (e: IrExpr, test: "classCapsule" | "funcKind"): boolean => + e.kind === "dynTest" && e.test === test && e.negated === true && isVar(e.value, receiver); + if (s.kind !== "if" || s.else_ !== null || !negated(s.cond, "classCapsule")) return null; + let body = s.then; + const inner = body[0]; + if ( + body.length === 1 && + inner?.kind === "if" && + inner.else_ === null && + negated(inner.cond, "funcKind") + ) + body = inner.then; + const [first, ret] = body; + if (body.length === 1 && first?.kind === "return") { + const read = unwrapFromDyn(first.value); + if ( + read?.kind !== "dynKeyGet" || + read.key.kind !== "strLit" || + !this.bagOf(read.value, receiver) + ) + return null; + return { kind: "get", key: read.key.value }; + } + if ( + body.length !== 2 || + first?.kind !== "exprStmt" || + ret?.kind !== "return" || + ret.value !== null + ) + return null; + const call = first.expr; + if (call.kind !== "libCall" || call.fn !== "dyn.keySet" || call.args.length !== 3) return null; + const [bag, key, stored] = call.args; + if (!bag || !this.bagOf(bag, receiver) || key?.kind !== "strLit") return null; + if (value === undefined || !isVar(stored, value)) return null; + return { kind: "set", key: key.value }; } /** `varDecl bag = BAG(receiver); return [js.fromDyn](bag === receiver ? @@ -109,10 +164,14 @@ export class JsIcSites { /** `if (typeof key === "symbol") return dynKeyGet(BAG(receiver), key); * if (receiver == null) return dynKeyGet(receiver, key); * const s = String(key); return dynKeyGet(BAG(receiver), s)`, each read - * possibly under js.fromDyn. */ + * possibly under js.fromDyn. Capsule branches may precede the final read: + * a program that declares classes looks the string key up in each class's + * key table there. */ private keyedTail(tail: IrStmt[], receiver: string, key: string): JsIcSite | null { - const [symbol, nullish, decl, ret] = tail; - if (tail.length !== 4) return null; + const [symbol, nullish, decl] = tail; + const ret = tail[tail.length - 1]; + if (tail.length < 4) return null; + if (!tail.slice(3, -1).every((s) => this.capsuleBranch(s, receiver))) return null; if (!this.guard(symbol, "symbol", key, (read) => this.bagOf(read, receiver), key)) return null; if (!this.guard(nullish, "nullish", receiver, (read) => isVar(read, receiver), key)) return null; @@ -159,9 +218,12 @@ export class JsIcSites { } /** Whether `e` is the receiver itself for every ordinary object or array: - * the receiver, or a chain of property-bag helpers applied to it. */ + * the receiver, or a chain of property-bag helpers applied to it. A + * conversion between the dyn and jsval forms keeps the object it holds. */ private bagOf(e: IrExpr, receiver: string): boolean { if (isVar(e, receiver)) return true; + if (e.kind === "libCall" && (e.fn === "js.toDyn" || e.fn === "js.fromDyn")) + return e.args.length === 1 && this.bagOf(e.args[0]!, receiver); return ( e.kind === "call" && e.args.length === 1 && @@ -182,6 +244,13 @@ export class JsIcSites { return ret.kind === "return" && ret.value !== null && this.bagOf(ret.value, param); } + /** `param = `, such as the subclass normalization + * `value = %dyn.class.normalize(value)`, which leaves an ordinary object + * or array in `param`. */ + private rebinding(s: IrStmt, param: string): boolean { + return s.kind === "assign" && s.localId === param && this.bagOf(s.value, param); + } + /** A property-bag helper that returns its argument unless a capsule * branch is taken. */ private identityHelper(name: string): boolean { @@ -204,7 +273,10 @@ export class JsIcSites { identity = fn.body .slice(0, -1) - .every((s) => this.capsuleBranch(s, param) || this.kindExit(s, param)) && + .every( + (s) => + this.capsuleBranch(s, param) || this.kindExit(s, param) || this.rebinding(s, param), + ) && last?.kind === "return" && last.value !== null && this.bagOf(last.value, param); diff --git a/packages/compiler/test/js-ic-emission.test.ts b/packages/compiler/test/js-ic-emission.test.ts index 47d641bff..54ea13d26 100644 --- a/packages/compiler/test/js-ic-emission.test.ts +++ b/packages/compiler/test/js-ic-emission.test.ts @@ -64,6 +64,50 @@ console.log(read(o), at(dyn([5, 6]), 1), call(o), o.n); } }); +test("property sites keep their caches in programs that declare classes and subclasses", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-js-ic-class-")); + try { + const entry = join(dir, "main.js"); + const outPath = join(dir, "main.ir.json"); + // Declared classes give every property helper class branches and + // property-bag lookups, and a subclass adds a normalization step; plain + // objects still read through the caches. + await writeFile( + entry, + ` +class Point { + constructor(x) { this.x = x; } +} +class Tagged extends Point { + constructor(x, tag) { super(x); this.tag = tag; } +} +function dyn(v) { return v; } +function read(o) { return o.x; } +function write(o, v) { o.x = v; } +function at(a, i) { return a[i]; } +var o = dyn({ x: 1 }); +var p = dyn(new Point(4)); +var t = dyn(new Tagged(6, "t")); +write(o, 3); +write(p, 5); +write(t, 7); +console.log(read(o), read(p), read(t), at(dyn([5, 6]), 1), at(p, "x"), at(t, "tag")); +`, + ); + const result = await compile(entry, { outDir: dir, outPath, outputKind: "ir" }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + const mod = deserializeModule(await readFile(outPath, "utf8")); + expect(validateModule(mod)).toEqual([]); + const llvm = emitLlvmModule(mod); + expect(body(llvm, "read")).toContain("@scr_js_load_probe("); + expect(body(llvm, "write")).toContain("@scr_js_store_probe("); + expect(body(llvm, "at")).toContain("@scr_js_keyed_probe("); + } finally { + await rm(dir, { recursive: true, force: true }); + } +}); + test("typed programs have no cache sites and keep the ordinary runtime", async () => { const dir = await mkdtemp(join(tmpdir(), "scriptc-js-ic-typed-")); try { diff --git a/packages/runtime/src/scr_js.h b/packages/runtime/src/scr_js.h index 6fa20fdb8..1d874b31e 100644 --- a/packages/runtime/src/scr_js.h +++ b/packages/runtime/src/scr_js.h @@ -195,10 +195,13 @@ bool scr_js_truthy(ScrJsVal value); * index and which keys an object lacks. * * Each property site of compiled dynamic-tier code owns one zeroed, - * thread-local ScrJsIc. The code at the site is fixed: it tests entry 0 - * inline and calls a probe for everything else. Probes never run user - * code: they answer from plain data properties or return a miss (NULL / - * false) with nothing done, and the site then runs its generic path. + * thread-local ScrJsIc with static storage: the reset that frees a + * thread's shapes (at thread exit, and when a library session ends) clears + * every record that holds entries. The code at the site is fixed: it tests + * entry 0 inline and calls a probe for everything else. Probes never run + * user code: they answer from plain data properties or return a miss + * (NULL / false) with nothing done, and the site then runs its generic + * path. * * load entry: shape = receiver shape; target = NULL for an own property * (slot indexes the receiver's entries), else the shape of diff --git a/packages/runtime/src/scr_js_object.c b/packages/runtime/src/scr_js_object.c index 63929ab57..0e0ec0908 100644 --- a/packages/runtime/src/scr_js_object.c +++ b/packages/runtime/src/scr_js_object.c @@ -18,6 +18,7 @@ #include "scr_key.h" #include +#include /* The compiler's inline cache tests read these in place (64-bit targets; * backend/llvm/js-ic.ts). */ @@ -37,10 +38,10 @@ _Static_assert(sizeof(ScrJsIcEntry) == 40 && sizeof(ScrJsIc) == 168, "cache layo * take the generic path and its hash index. */ #define SCR_JS_SHAPE_MAX 64 -/* Shapes live until the thread exits, so a thread creates at most this - * many, holding at most this many key bytes. Once either budget is spent, - * objects whose key sequence has no shape yet stay unshaped; shapes that - * exist keep serving. */ +/* Shapes live until the thread exits or a library session ends, so a thread + * creates at most this many, holding at most this many key bytes. Once + * either budget is spent, objects whose key sequence has no shape yet stay + * unshaped; shapes that exist keep serving. */ #define SCR_JS_SHAPE_BUDGET ((size_t)1 << 16) #define SCR_JS_SHAPE_KEY_BYTES_BUDGET ((size_t)4 << 20) @@ -63,12 +64,25 @@ static SCR_TL size_t scr_js_transition_count; static SCR_TL size_t scr_js_shape_key_bytes; static SCR_TL bool scr_js_shapes_registered; +/* The cache records that hold entries. Entries name shapes and prototype + * objects, so the reset that frees the shapes also clears these records: a + * library's next session runs the same sites with the same records. */ +static SCR_TL ScrJsIc **scr_js_filled_ics; +static SCR_TL size_t scr_js_filled_count; +static SCR_TL size_t scr_js_filled_capacity; + /* The shape word of an object whose key sequence has no shape within the * budgets. No cache entry names it, so its accesses take the probes, * which answer with a miss until the key set changes. */ static ScrJsShape scr_js_unshaped; static void scr_js_shapes_reset(void) { + for (size_t i = 0; i < scr_js_filled_count; i++) + memset(scr_js_filled_ics[i], 0, sizeof *scr_js_filled_ics[i]); + free(scr_js_filled_ics); + scr_js_filled_ics = NULL; + scr_js_filled_count = 0; + scr_js_filled_capacity = 0; while (scr_js_all_shapes) { ScrJsShape *shape = scr_js_all_shapes; scr_js_all_shapes = shape->all_next; @@ -192,6 +206,16 @@ static size_t scr_js_shape_find(const ScrJsShape *shape, const char *key, size_t /* Fills a cache entry: `stale` (a matching entry whose hit failed) when * there is one, else a free or replaceable one. */ static void scr_js_ic_add(ScrJsIc *ic, uint32_t stale, ScrJsIcEntry entry) { + if (ic->count == 0) { + if (scr_js_filled_count == scr_js_filled_capacity) { + size_t capacity = scr_js_filled_capacity ? scr_js_filled_capacity * 2 : 64; + ScrJsIc **grown = realloc(scr_js_filled_ics, capacity * sizeof *grown); + if (!grown) scr_trap("scriptc: out of memory\n"); + scr_js_filled_ics = grown; + scr_js_filled_capacity = capacity; + } + scr_js_filled_ics[scr_js_filled_count++] = ic; + } uint32_t index; if (stale < ic->count) { index = stale; diff --git a/packages/runtime/src/scr_js_object.test.c b/packages/runtime/src/scr_js_object.test.c index a14aa9ff6..6b6934dea 100644 --- a/packages/runtime/src/scr_js_object.test.c +++ b/packages/runtime/src/scr_js_object.test.c @@ -24,11 +24,17 @@ static ScrDyn *object_with(const ScrStr *key, double n) { return object; } +/* Cache records have static storage, as the compiled sites' do: the reset + * at exit clears every record that holds entries. Each check starts from + * an empty record. */ +static ScrJsIc load_ic; +static ScrJsIc store_ic; + /* Whether a load probe answers `object.key` and returns `n`. */ static bool probe_reads(ScrDyn *object, const ScrStr *key, double n) { - ScrJsIc ic; - memset(&ic, 0, sizeof ic); - ScrDyn *value = scr_js_load_probe(object, key, &ic); + ScrJsIc *ic = &load_ic; + memset(ic, 0, sizeof *ic); + ScrDyn *value = scr_js_load_probe(object, key, ic); if (!value) return false; assert(value->kind == SCR_DYN_NUM && value->v.num == n); scr_dyn_release(value); @@ -66,14 +72,13 @@ static void budget_bounds_shapes(size_t key_len, size_t budget) { /* A store probe that would add a new shape leaves the add to the generic * store; one that replaces through an existing shape still runs. */ - ScrJsIc ic; - memset(&ic, 0, sizeof ic); + memset(&store_ic, 0, sizeof store_ic); ScrStr *added = scr_str_new("added", 5); ScrDyn *value = scr_dyn_new_num(8); - assert(!scr_js_store_probe(object, added, value, &ic)); + assert(!scr_js_store_probe(object, added, value, &store_ic)); assert(object->v.obj.len == 1); - memset(&ic, 0, sizeof ic); - assert(scr_js_store_probe(object, first, value, &ic)); + memset(&store_ic, 0, sizeof store_ic); + assert(scr_js_store_probe(object, first, value, &store_ic)); assert(probe_reads(object, first, 8)); scr_dyn_release(value); scr_str_release(added); @@ -90,10 +95,9 @@ static void immortal_objects_stay_unshaped(void) { object->rc = SIZE_MAX; assert(!probe_reads(object, key, 3)); assert(object->v.obj.shape == NULL); - ScrJsIc ic; - memset(&ic, 0, sizeof ic); + memset(&store_ic, 0, sizeof store_ic); ScrDyn *value = scr_dyn_new_num(4); - assert(!scr_js_store_probe(object, key, value, &ic)); + assert(!scr_js_store_probe(object, key, value, &store_ic)); assert(object->v.obj.shape == NULL); scr_dyn_release(value); scr_str_release(key); diff --git a/scripts/zero-cost-compare.mjs b/scripts/zero-cost-compare.mjs index 9247585e5..a1ab3ca60 100644 --- a/scripts/zero-cost-compare.mjs +++ b/scripts/zero-cost-compare.mjs @@ -395,8 +395,8 @@ export function dynamicTierSymbols(names) { * bench/channel-messages and bench/worker-messages, added later, link them * through worker messages: * node:worker_threads values are dyn objects. bench/json-unions, added - * later too, decodes JSON.parse trees. bench/dynamic-methods is - * untyped JavaScript. Every other bench workload is fully typed and must link none. The gate and + * later too, decodes JSON.parse trees. bench/dynamic-methods and + * bench/dynamic-properties are untyped JavaScript. Every other bench workload is fully typed and must link none. The gate and * tests/harness/bench-dynamic-tier.test.ts enforce that, and the test also * fails when a listed workload stops linking them, so remove a workload here * when a leak fix makes its binary clean. */ @@ -411,6 +411,7 @@ export const DYNAMIC_WORKLOADS = new Set([ "bench/thread-slots", "bench/channel-messages", "bench/dynamic-methods", + "bench/dynamic-properties", "bench/worker-messages", "bench/typed-array-scan-workers", "bench/log-summary", diff --git a/tests/harness/library-mode.test.ts b/tests/harness/library-mode.test.ts index 7eecd3c93..784dc747b 100644 --- a/tests/harness/library-mode.test.ts +++ b/tests/harness/library-mode.test.ts @@ -363,6 +363,17 @@ globals: undefined fenced expect(run.stdout).toBe(SESSION + SESSION + SESSION); }); + test("K4: untyped property caches start empty in every session", async () => { + // The shapes a session's cache entries name are freed when it ends; + // the next session's sites must not find those entries. + const { archive, outDir } = await buildLibrary("js-ic-sessions", emission); + const probe = buildProbe("js-ic-sessions", archive, outDir); + const run = runProbe(probe); + expect(run.signal).toBeNull(); + expect(run.status).toBe(0); + expect(run.stdout).toBe("run: 20000\n".repeat(3)); + }); + /* ── K5/K6/K7: the trap channel ──────────────────────────────────────── */ test("K5: a trap delivers to the sink exactly once, host survives", async () => { @@ -582,6 +593,15 @@ survived, sink_calls=1 expect(run.stdout).toBe(SESSION + SESSION + SESSION); }); + platformTest("K10: property caches across sessions under ASan", async () => { + const { archive, outDir } = await buildLibrary("js-ic-sessions", emission, { sanitize: true }); + const probe = buildProbe("js-ic-sessions", archive, outDir, { sanitize: true }); + const run = runProbe(probe); + expect(run.signal).toBeNull(); + expect(run.status).toBe(0); + expect(run.stdout).toBe("run: 20000\n".repeat(3)); + }); + platformTest("K10: K5/K7 under ASan", async () => { const { archive, outDir } = await buildLibrary("traps", emission, { sanitize: true }); const probe = buildProbe("traps", archive, outDir, { sanitize: true }); diff --git a/tests/library-mode/js-ic-sessions/lib.ts b/tests/library-mode/js-ic-sessions/lib.ts new file mode 100644 index 000000000..ebea59a54 --- /dev/null +++ b/tests/library-mode/js-ic-sessions/lib.ts @@ -0,0 +1,6 @@ +// The library's typed export over untyped code (work.mjs). +import { runAll } from "./work.mjs"; + +export function run(): number { + return runAll() as number; +} diff --git a/tests/library-mode/js-ic-sessions/probe.c b/tests/library-mode/js-ic-sessions/probe.c new file mode 100644 index 000000000..7dbcb56bf --- /dev/null +++ b/tests/library-mode/js-ic-sessions/probe.c @@ -0,0 +1,25 @@ +/* Three sessions of a library whose untyped code reads and writes through + * property caches: each prints the same result, and under the sanitize + * flavor no session reads a cache entry the previous session freed. */ +#include +#include + +extern void kj_init(void); +extern void kj_set_panic_sink(void (*fn)(void *, const uint8_t *, size_t, uint64_t), void *ctx); +extern void kj_collect(void); +extern double kj_run(void); + +static void sink(void *ctx, const uint8_t *msg, size_t len, uint64_t addr) { + (void)ctx; (void)addr; + printf("UNEXPECTED SINK: %.*s", (int)len, (const char *)msg); +} + +int main(void) { + kj_set_panic_sink(sink, NULL); + for (int session = 0; session < 3; session++) { + kj_init(); + printf("run: %.0f\n", kj_run()); + kj_collect(); + } + return 0; +} diff --git a/tests/library-mode/js-ic-sessions/profile.json b/tests/library-mode/js-ic-sessions/profile.json new file mode 100644 index 000000000..fd802b42c --- /dev/null +++ b/tests/library-mode/js-ic-sessions/profile.json @@ -0,0 +1,14 @@ +{ + "profile_format": 1, + "name": "conformance-js-ic-sessions", + "entry": "lib.ts", + "emission": "llvm", + "abi": { + "prefix": "kj_", + "init_symbol": "kj_init", + "sink_register_symbol": "kj_set_panic_sink", + "collect_symbol": "kj_collect", + "result_reset_symbol": null + }, + "exports": [{ "export": "run", "symbol": "kj_run", "params": [], "returns": "f64" }] +} diff --git a/tests/library-mode/js-ic-sessions/work.mjs b/tests/library-mode/js-ic-sessions/work.mjs new file mode 100644 index 000000000..5c1afcd18 --- /dev/null +++ b/tests/library-mode/js-ic-sessions/work.mjs @@ -0,0 +1,26 @@ +// Dynamic-tier property caches across library sessions: objects built empty +// and filled through untyped stores, read back through untyped loads, and a +// class instance at the same kind of sites. Each session must start with +// empty caches, since the shapes their entries named are freed when the +// previous session ends. +class Box { + constructor(v) { + this.v = v; + } +} +function fill(o, n) { + o.a = n; + o.b = n + 1; + return o; +} +function sum(o) { + return o.a + o.b; +} +function unbox(b) { + return b.v; +} +export function runAll() { + let total = 0; + for (let i = 0; i < 100; i++) total += sum(fill({}, i)); + return total + unbox(new Box(total)); +} From 878f03288630b2097c7102de0146e016214d74f9 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 08:35:30 -0500 Subject: [PATCH 091/259] Crypto parity: RSA key generation lengths, RSA-PSS keys and encrypted private keys --- .../limitations/builtin-apis/crypto.mdx | 9 +- .../ambient/scriptc-node-fallback.d.ts | 31 +- packages/compiler/src/ir/runtime-features.ts | 11 +- .../corpus/8165-rsa-keygen-lengths.cjs.json | 6 + .../tests/corpus/8166-rsa-pss-keys.cjs.json | 6 + .../8167-encrypted-private-keys.cjs.json | 6 + packages/runtime/src/scr_cipher.c | 45 +- packages/runtime/src/scr_cipher_names.h | 100 ++ packages/runtime/src/scr_lib.c | 5 + packages/runtime/src/scr_lib.h | 3 + packages/runtime/src/scr_pki.c | 1387 ++++++++++++++++- packages/runtime/src/scr_webcrypto_pki.c | 3 +- tests/corpus/8165-rsa-keygen-lengths.cjs | 40 + tests/corpus/8166-rsa-pss-keys.cjs | 104 ++ tests/corpus/8167-encrypted-private-keys.cjs | 114 ++ .../8165-rsa-keygen-lengths.cjs.json | 1 + .../corpus-costs/8166-rsa-pss-keys.cjs.json | 1 + .../8167-encrypted-private-keys.cjs.json | 1 + 18 files changed, 1787 insertions(+), 86 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8165-rsa-keygen-lengths.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8166-rsa-pss-keys.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8167-encrypted-private-keys.cjs.json create mode 100644 packages/runtime/src/scr_cipher_names.h create mode 100644 tests/corpus/8165-rsa-keygen-lengths.cjs create mode 100644 tests/corpus/8166-rsa-pss-keys.cjs create mode 100644 tests/corpus/8167-encrypted-private-keys.cjs create mode 100644 tests/harness/corpus-costs/8165-rsa-keygen-lengths.cjs.json create mode 100644 tests/harness/corpus-costs/8166-rsa-pss-keys.cjs.json create mode 100644 tests/harness/corpus-costs/8167-encrypted-private-keys.cjs.json diff --git a/docs/content/limitations/builtin-apis/crypto.mdx b/docs/content/limitations/builtin-apis/crypto.mdx index 329aa6809..bbe9cca21 100644 --- a/docs/content/limitations/builtin-apis/crypto.mdx +++ b/docs/content/limitations/builtin-apis/crypto.mdx @@ -31,18 +31,21 @@ `checkPrime`, `checkPrimeSync`, `generatePrime`, and `generatePrimeSync` support bigint, ArrayBuffer, typed-array, Buffer, and DataView values and the `checks`, `safe`, `add`, `rem`, and `bigint` options on native targets, with Node's errors; the callback forms compute before they return and call back in a later macrotask. Candidates and sizes longer than 262144 bits throw a coded SC2020 error, and wasm32-wasi builds are refused. Node calls their callbacks with `undefined` as the error, which a callback whose error parameter is typed `Error | null`, as @types/node declares it, receives as `null`. - RSA, EC, Ed25519, and X25519 private and public KeyObjects come from `generateKeyPairSync`, `generateKeyPair`, `createPrivateKey`, and `createPublicKey`, on native targets. + RSA, RSA-PSS, EC, Ed25519, and X25519 private and public KeyObjects come from `generateKeyPairSync`, `generateKeyPair`, `createPrivateKey`, and `createPublicKey`, on native targets. `generateKeyPairSync` and `generateKeyPair` check their arguments in Node's order, with Node's errors, including the OpenSSL errors for RSA modulus lengths below 512 or above 2147483647 bits and for public exponents of 0, 1, or an even number, which `generateKeyPair` passes to its callback. - RSA keys generate with even modulus lengths from 1024 to 8192 bits and public exponents up to 2147483647; other lengths and exponents that Node accepts, and `paramEncoding: 'explicit'`, throw a coded SC2020 error. + RSA keys generate with modulus lengths from 512 to 8192 bits, an odd length from 2048 bits yielding one bit less as in Node, and odd public exponents up to 4294967295; longer moduli that Node accepts, and `paramEncoding: 'explicit'`, throw a coded SC2020 error. The EC curves are prime256v1 (P-256), secp384r1 (P-384), secp521r1 (P-521), and secp256k1. Keys read and write PEM and DER as PKCS#1, SEC1, PKCS#8, and SubjectPublicKeyInfo, and JWK (Ed25519 and X25519 keys use PKCS#8, SubjectPublicKeyInfo, and JWK); `createPublicKey` also takes a private key or an X.509 certificate. EC, Ed25519, and X25519 keys also read and write the `raw-public` and `raw-private` formats, including compressed EC points. Raw X448, Ed448, and post-quantum keys, EC scalars of 0 or at least the curve order, and the EC point at infinity, which Node accepts, throw a coded SC2020 error. They support `type`, `asymmetricKeyType`, `asymmetricKeyDetails`, `export()`, `equals()`, and `instanceof KeyObject`. `crypto.sign`, `crypto.verify`, `createSign`, and `createVerify` support RSA PKCS#1 v1.5 and PSS padding and ECDSA with DER and IEEE P1363 encodings over SHA-1 and SHA-2 digests, and Ed25519 through `crypto.sign` and `crypto.verify` with a `null` or `undefined` algorithm. + RSA-PSS keys follow their RSASSA-PSS-params as Node does: PSS padding only, the key's digest and MGF1 digest, and salts of at least the key's length, with OpenSSL's errors; their details name the parameters, they export as PKCS#8 and SubjectPublicKeyInfo only, and digests other than SHA-1 and SHA-2 in their options throw a coded SC2020 error. Ed25519 signing, verification, and private keys link when a string literal in the program names `ed25519` (in any case); without one they throw a coded SC2020 error, while Ed25519 public keys still import and export. Sign and Verify values accumulate `update()` data and are not writable streams. - Encrypted private keys (`passphrase`, `cipher`), the other key types (`rsa-pss`, `dsa`, `ed448`, `x448`, and the rest), and wasm32-wasi builds throw a coded SC2020 error or are refused. + Private keys export encrypted (`cipher`, `passphrase`) with aes-128, aes-192, and aes-256 in CBC and ECB modes and with des-ede3-cbc, PKCS#8 as PBES2 with PBKDF2-HMAC-SHA256 and PKCS#1 and SEC1 as traditional PEM, and the ciphers OpenSSL refuses for a form throw its errors; a cipher option can also be an OID; other ciphers Node encrypts with throw a coded SC2020 error. + Encrypted private keys import with a `passphrase` from PBES2 with HMAC-SHA PRFs and the CBC and ECB ciphers, and from traditional PEM with the CBC ciphers, with Node's errors for a missing or wrong passphrase; other schemes and ciphers throw a coded SC2020 error once a passphrase is given. + The other key types (`dsa`, `ed448`, `x448`, and the rest) and wasm32-wasi builds throw a coded SC2020 error or are refused. Comparing keys of different types with `equals()` answers false; Node also leaves an OpenSSL error queued, which a later key operation can report. `publicEncrypt`/`privateDecrypt` remain unsupported. The WebCrypto `crypto` global, which node:crypto also exports as `webcrypto`, supports `randomUUID()` and `getRandomValues()`, also read as values from untyped JavaScript. diff --git a/packages/compiler/ambient/scriptc-node-fallback.d.ts b/packages/compiler/ambient/scriptc-node-fallback.d.ts index 1fa787e35..2c056c148 100644 --- a/packages/compiler/ambient/scriptc-node-fallback.d.ts +++ b/packages/compiler/ambient/scriptc-node-fallback.d.ts @@ -2914,6 +2914,8 @@ declare module "crypto" { export interface AsymmetricKeyExportOptions { type: "pkcs1" | "spki" | "pkcs8" | "sec1"; format: T; + cipher?: string | undefined; + passphrase?: string | Buffer | undefined; } export interface AsymmetricKeyDetails { modulusLength?: number; @@ -2938,6 +2940,7 @@ declare module "crypto" { format?: "pem" | "der" | undefined; type?: "pkcs1" | "pkcs8" | "sec1" | undefined; encoding?: string | undefined; + passphrase?: string | Buffer | undefined; } export interface PublicKeyInput { key: string | Buffer; @@ -2974,12 +2977,22 @@ declare module "crypto" { modulusLength: number; publicExponent?: number | undefined; publicKeyEncoding: { type: "pkcs1" | "spki"; format: PubF }; - privateKeyEncoding: { type: "pkcs1" | "pkcs8"; format: PrivF }; + privateKeyEncoding: { + type: "pkcs1" | "pkcs8"; + format: PrivF; + cipher?: string | undefined; + passphrase?: string | undefined; + }; } export interface ECKeyPairOptions { namedCurve: string; publicKeyEncoding: { type: "pkcs1" | "spki"; format: PubF }; - privateKeyEncoding: { type: "sec1" | "pkcs8"; format: PrivF }; + privateKeyEncoding: { + type: "sec1" | "pkcs8"; + format: PrivF; + cipher?: string | undefined; + passphrase?: string | undefined; + }; } export function generateKeyPairSync( type: "rsa", @@ -3007,7 +3020,12 @@ declare module "crypto" { ): KeyPairKeyObjectResult; export interface ED25519KeyPairOptions { publicKeyEncoding: { type: "spki"; format: PubF }; - privateKeyEncoding: { type: "pkcs8"; format: PrivF }; + privateKeyEncoding: { + type: "pkcs8"; + format: PrivF; + cipher?: string | undefined; + passphrase?: string | undefined; + }; } export function generateKeyPairSync( type: "ed25519", @@ -3020,7 +3038,12 @@ declare module "crypto" { export function generateKeyPairSync(type: "ed25519", options?: {}): KeyPairKeyObjectResult; export interface X25519KeyPairOptions { publicKeyEncoding: { type: "spki"; format: PubF }; - privateKeyEncoding: { type: "pkcs8"; format: PrivF }; + privateKeyEncoding: { + type: "pkcs8"; + format: PrivF; + cipher?: string | undefined; + passphrase?: string | undefined; + }; } export function generateKeyPairSync( type: "x25519", diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 85b21af7b..1cae265d5 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -875,10 +875,11 @@ const RUNTIME_FEATURE_RULES = { mod.functions.some( (fn) => fn.async === true && fn.generator === undefined && fn.returnType.kind === "dyn", ), - // The legacy url functions, crypto.createCipheriv and - // ecdh.setPublicKey emit their deprecation warnings through the - // dyn-async unit (WebCrypto's encrypt and decrypt link scr_cipher.c - // too); scr_wasm.c boxes its handles and promises through it. + // The legacy url functions, crypto.createCipheriv, + // ecdh.setPublicKey and generateKeyPair's rsa-pss options emit their + // deprecation warnings through the dyn-async unit (WebCrypto's + // encrypt and decrypt link scr_cipher.c too); scr_wasm.c boxes its + // handles and promises through it. fns: [ ...DYN_ASYNC_LIB_FNS, ...READABLE_DYN_ASYNC_LIB_FNS, @@ -889,6 +890,8 @@ const RUNTIME_FEATURE_RULES = { "webcrypto.wrapKey", "webcrypto.unwrapKey", "crypto.ecdhNew", + "crypto.generateKeyPairCb", + "crypto.generateKeyPairSync", ], prefixes: [...READABLE_DYN_ASYNC_PREFIXES, "wasm."], expr: (node, tables) => diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8165-rsa-keygen-lengths.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8165-rsa-keygen-lengths.cjs.json new file mode 100644 index 000000000..45346fc86 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8165-rsa-keygen-lengths.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8165-rsa-keygen-lengths.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8166-rsa-pss-keys.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8166-rsa-pss-keys.cjs.json new file mode 100644 index 000000000..623419ef3 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8166-rsa-pss-keys.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8166-rsa-pss-keys.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8167-encrypted-private-keys.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8167-encrypted-private-keys.cjs.json new file mode 100644 index 000000000..e5e03f8e9 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8167-encrypted-private-keys.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8167-encrypted-private-keys.cjs" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_cipher.c b/packages/runtime/src/scr_cipher.c index a2db11434..33780fdfc 100644 --- a/packages/runtime/src/scr_cipher.c +++ b/packages/runtime/src/scr_cipher.c @@ -12,6 +12,7 @@ * compared in constant time. A cipher used as a stream reads and writes * through its own native Transform, which the stream unit builds on first * use, as Node's LazyTransform is. All arguments are borrowed. */ +#include "scr_cipher_names.h" #include "scr_runtime.h" #include @@ -114,52 +115,12 @@ static const ScCipherSpec sc_specs[] = { static const struct { const char *name; unsigned iv_len; -} sc_legacy[] = { - {"des", 8}, {"des-cbc", 8}, {"des-ecb", 0}, {"des-cfb", 8}, {"des-cfb1", 8}, {"des-cfb8", 8}, - {"des-ofb", 8}, {"desx", 8}, {"desx-cbc", 8}, {"bf", 8}, {"bf-cbc", 8}, {"bf-ecb", 0}, - {"bf-cfb", 8}, {"bf-ofb", 8}, {"blowfish", 8}, {"cast", 8}, {"cast-cbc", 8}, {"cast5-cbc", 8}, - {"cast5-ecb", 0}, {"cast5-cfb", 8}, {"cast5-ofb", 8}, {"rc2", 8}, {"rc2-cbc", 8}, {"rc2-ecb", 0}, - {"rc2-cfb", 8}, {"rc2-ofb", 8}, {"rc2-40-cbc", 8}, {"rc2-64-cbc", 8}, {"rc4", 0}, {"rc4-40", 0}, - {"rc4-hmac-md5", 0}, {"seed", 16}, {"seed-cbc", 16}, {"seed-ecb", 0}, {"seed-cfb", 16}, - {"seed-ofb", 16}, {"idea", 8}, {"idea-cbc", 8}, {"idea-ecb", 0}, {"idea-cfb", 8}, {"idea-ofb", 8}, -}; +} sc_legacy[] = {SCR_CIPHER_LEGACY_ENTRIES}; /* crypto.getCiphers() on Node 24.22 (OpenSSL 3.5). Names in this list that * have no implementation throw a coded SC2020 error instead of Node's * ERR_CRYPTO_UNKNOWN_CIPHER. */ -static const char *const sc_known[] = { - "aes-128-cbc", "aes-128-cbc-cts", "aes-128-ccm", "aes-128-cfb", "aes-128-cfb1", "aes-128-cfb8", - "aes-128-ctr", "aes-128-ecb", "aes-128-gcm", "aes-128-gcm-siv", "aes-128-ocb", "aes-128-ofb", - "aes-128-siv", "aes-128-wrap", "aes-128-wrap-inv", "aes-128-wrap-pad", "aes-128-wrap-pad-inv", - "aes-128-xts", "aes-192-cbc", "aes-192-cbc-cts", "aes-192-ccm", "aes-192-cfb", "aes-192-cfb1", - "aes-192-cfb8", "aes-192-ctr", "aes-192-ecb", "aes-192-gcm", "aes-192-gcm-siv", "aes-192-ocb", - "aes-192-ofb", "aes-192-siv", "aes-192-wrap", "aes-192-wrap-inv", "aes-192-wrap-pad", - "aes-192-wrap-pad-inv", "aes-256-cbc", "aes-256-cbc-cts", "aes-256-ccm", "aes-256-cfb", - "aes-256-cfb1", "aes-256-cfb8", "aes-256-ctr", "aes-256-ecb", "aes-256-gcm", "aes-256-gcm-siv", - "aes-256-ocb", "aes-256-ofb", "aes-256-siv", "aes-256-wrap", "aes-256-wrap-inv", - "aes-256-wrap-pad", "aes-256-wrap-pad-inv", "aes-256-xts", "aes128", "aes128-wrap", - "aes128-wrap-inv", "aes128-wrap-pad", "aes128-wrap-pad-inv", "aes192", "aes192-wrap", - "aes192-wrap-inv", "aes192-wrap-pad", "aes192-wrap-pad-inv", "aes256", "aes256-wrap", - "aes256-wrap-inv", "aes256-wrap-pad", "aes256-wrap-pad-inv", "aria-128-cbc", "aria-128-ccm", - "aria-128-cfb", "aria-128-cfb1", "aria-128-cfb8", "aria-128-ctr", "aria-128-ecb", "aria-128-gcm", - "aria-128-ofb", "aria-192-cbc", "aria-192-ccm", "aria-192-cfb", "aria-192-cfb1", "aria-192-cfb8", - "aria-192-ctr", "aria-192-ecb", "aria-192-gcm", "aria-192-ofb", "aria-256-cbc", "aria-256-ccm", - "aria-256-cfb", "aria-256-cfb1", "aria-256-cfb8", "aria-256-ctr", "aria-256-ecb", "aria-256-gcm", - "aria-256-ofb", "aria128", "aria192", "aria256", "camellia-128-cbc", "camellia-128-cbc-cts", - "camellia-128-cfb", "camellia-128-cfb1", "camellia-128-cfb8", "camellia-128-ctr", - "camellia-128-ecb", "camellia-128-ofb", "camellia-192-cbc", "camellia-192-cbc-cts", - "camellia-192-cfb", "camellia-192-cfb1", "camellia-192-cfb8", "camellia-192-ctr", - "camellia-192-ecb", "camellia-192-ofb", "camellia-256-cbc", "camellia-256-cbc-cts", - "camellia-256-cfb", "camellia-256-cfb1", "camellia-256-cfb8", "camellia-256-ctr", - "camellia-256-ecb", "camellia-256-ofb", "camellia128", "camellia192", "camellia256", "chacha20", - "chacha20-poly1305", "des-ede", "des-ede-cbc", "des-ede-cfb", "des-ede-ecb", "des-ede-ofb", - "des-ede3", "des-ede3-cbc", "des-ede3-cfb", "des-ede3-cfb1", "des-ede3-cfb8", "des-ede3-ecb", - "des-ede3-ofb", "des3", "des3-wrap", "id-aes128-ccm", "id-aes128-gcm", "id-aes128-wrap", - "id-aes128-wrap-pad", "id-aes192-ccm", "id-aes192-gcm", "id-aes192-wrap", "id-aes192-wrap-pad", - "id-aes256-ccm", "id-aes256-gcm", "id-aes256-wrap", "id-aes256-wrap-pad", - "id-smime-alg-cms3deswrap", "sm4", "sm4-cbc", "sm4-ccm", "sm4-cfb", "sm4-cfb128", "sm4-ctr", - "sm4-ecb", "sm4-gcm", "sm4-ofb", "sm4-ofb128", "sm4-xts", -}; +static const char *const sc_known[] = {SCR_CIPHER_KNOWN_NAMES}; enum { SC_NO_TAG = -1 }; enum { SC_TAG_UNKNOWN, SC_TAG_SET_BY_USER, SC_TAG_COMPUTED }; diff --git a/packages/runtime/src/scr_cipher_names.h b/packages/runtime/src/scr_cipher_names.h new file mode 100644 index 000000000..38b31e06e --- /dev/null +++ b/packages/runtime/src/scr_cipher_names.h @@ -0,0 +1,100 @@ +/* crypto.getCiphers() on Node 24.22 (OpenSSL 3.5), the names a cipher + * option can give. The cipher and pki units each include it: names + * without an implementation there throw a coded SC2020 error instead of + * Node's ERR_CRYPTO_UNKNOWN_CIPHER. */ +#ifndef SCR_CIPHER_NAMES_H +#define SCR_CIPHER_NAMES_H + +#define SCR_CIPHER_KNOWN_NAMES \ + "aes-128-cbc", "aes-128-cbc-cts", "aes-128-ccm", "aes-128-cfb", "aes-128-cfb1", "aes-128-cfb8", \ + "aes-128-ctr", "aes-128-ecb", "aes-128-gcm", "aes-128-gcm-siv", "aes-128-ocb", "aes-128-ofb", \ + "aes-128-siv", "aes-128-wrap", "aes-128-wrap-inv", "aes-128-wrap-pad", "aes-128-wrap-pad-inv", \ + "aes-128-xts", "aes-192-cbc", "aes-192-cbc-cts", "aes-192-ccm", "aes-192-cfb", "aes-192-cfb1", \ + "aes-192-cfb8", "aes-192-ctr", "aes-192-ecb", "aes-192-gcm", "aes-192-gcm-siv", "aes-192-ocb", \ + "aes-192-ofb", "aes-192-siv", "aes-192-wrap", "aes-192-wrap-inv", "aes-192-wrap-pad", \ + "aes-192-wrap-pad-inv", "aes-256-cbc", "aes-256-cbc-cts", "aes-256-ccm", "aes-256-cfb", \ + "aes-256-cfb1", "aes-256-cfb8", "aes-256-ctr", "aes-256-ecb", "aes-256-gcm", "aes-256-gcm-siv", \ + "aes-256-ocb", "aes-256-ofb", "aes-256-siv", "aes-256-wrap", "aes-256-wrap-inv", \ + "aes-256-wrap-pad", "aes-256-wrap-pad-inv", "aes-256-xts", "aes128", "aes128-wrap", \ + "aes128-wrap-inv", "aes128-wrap-pad", "aes128-wrap-pad-inv", "aes192", "aes192-wrap", \ + "aes192-wrap-inv", "aes192-wrap-pad", "aes192-wrap-pad-inv", "aes256", "aes256-wrap", \ + "aes256-wrap-inv", "aes256-wrap-pad", "aes256-wrap-pad-inv", "aria-128-cbc", "aria-128-ccm", \ + "aria-128-cfb", "aria-128-cfb1", "aria-128-cfb8", "aria-128-ctr", "aria-128-ecb", "aria-128-gcm", \ + "aria-128-ofb", "aria-192-cbc", "aria-192-ccm", "aria-192-cfb", "aria-192-cfb1", "aria-192-cfb8", \ + "aria-192-ctr", "aria-192-ecb", "aria-192-gcm", "aria-192-ofb", "aria-256-cbc", "aria-256-ccm", \ + "aria-256-cfb", "aria-256-cfb1", "aria-256-cfb8", "aria-256-ctr", "aria-256-ecb", "aria-256-gcm", \ + "aria-256-ofb", "aria128", "aria192", "aria256", "camellia-128-cbc", "camellia-128-cbc-cts", \ + "camellia-128-cfb", "camellia-128-cfb1", "camellia-128-cfb8", "camellia-128-ctr", \ + "camellia-128-ecb", "camellia-128-ofb", "camellia-192-cbc", "camellia-192-cbc-cts", \ + "camellia-192-cfb", "camellia-192-cfb1", "camellia-192-cfb8", "camellia-192-ctr", \ + "camellia-192-ecb", "camellia-192-ofb", "camellia-256-cbc", "camellia-256-cbc-cts", \ + "camellia-256-cfb", "camellia-256-cfb1", "camellia-256-cfb8", "camellia-256-ctr", \ + "camellia-256-ecb", "camellia-256-ofb", "camellia128", "camellia192", "camellia256", "chacha20", \ + "chacha20-poly1305", "des-ede", "des-ede-cbc", "des-ede-cfb", "des-ede-ecb", "des-ede-ofb", \ + "des-ede3", "des-ede3-cbc", "des-ede3-cfb", "des-ede3-cfb1", "des-ede3-cfb8", "des-ede3-ecb", \ + "des-ede3-ofb", "des3", "des3-wrap", "id-aes128-ccm", "id-aes128-gcm", "id-aes128-wrap", \ + "id-aes128-wrap-pad", "id-aes192-ccm", "id-aes192-gcm", "id-aes192-wrap", "id-aes192-wrap-pad", \ + "id-aes256-ccm", "id-aes256-gcm", "id-aes256-wrap", "id-aes256-wrap-pad", \ + "id-smime-alg-cms3deswrap", "sm4", "sm4-cbc", "sm4-ccm", "sm4-cfb", "sm4-cfb128", "sm4-ctr", \ + "sm4-ecb", "sm4-gcm", "sm4-ofb", "sm4-ofb128", "sm4-xts", + +/* The ciphers OpenSSL 3 keeps in its legacy provider, which Node 24 does + * not load, with their IV lengths: OpenSSL knows their names, and using + * them fails with its "unsupported" error. */ +#define SCR_CIPHER_LEGACY_ENTRIES \ + {"des", 8}, {"des-cbc", 8}, {"des-ecb", 0}, {"des-cfb", 8}, {"des-cfb1", 8}, {"des-cfb8", 8}, \ + {"des-ofb", 8}, {"desx", 8}, {"desx-cbc", 8}, {"bf", 8}, {"bf-cbc", 8}, {"bf-ecb", 0}, \ + {"bf-cfb", 8}, {"bf-ofb", 8}, {"blowfish", 8}, {"cast", 8}, {"cast-cbc", 8}, {"cast5-cbc", 8}, \ + {"cast5-ecb", 0}, {"cast5-cfb", 8}, {"cast5-ofb", 8}, {"rc2", 8}, {"rc2-cbc", 8}, {"rc2-ecb", 0}, \ + {"rc2-cfb", 8}, {"rc2-ofb", 8}, {"rc2-40-cbc", 8}, {"rc2-64-cbc", 8}, {"rc4", 0}, {"rc4-40", 0}, \ + {"rc4-hmac-md5", 0}, {"seed", 16}, {"seed-cbc", 16}, {"seed-ecb", 0}, {"seed-cfb", 16}, \ + {"seed-ofb", 16}, {"idea", 8}, {"idea-cbc", 8}, {"idea-ecb", 0}, {"idea-cfb", 8}, {"idea-ofb", 8}, + +/* The OID texts OpenSSL's providers register as cipher aliases, with the + * name each fetches (crypto.getCipherInfo(oid).name on Node 24.22). */ +#define SCR_CIPHER_OID_ALIASES \ + {"2.16.840.1.101.3.4.1.1", "aes-128-ecb"}, {"2.16.840.1.101.3.4.1.2", "aes-128-cbc"}, \ + {"2.16.840.1.101.3.4.1.3", "aes-128-ofb"}, {"2.16.840.1.101.3.4.1.4", "aes-128-cfb"}, \ + {"2.16.840.1.101.3.4.1.5", "id-aes128-wrap"}, {"2.16.840.1.101.3.4.1.6", "id-aes128-gcm"}, \ + {"2.16.840.1.101.3.4.1.7", "id-aes128-ccm"}, {"2.16.840.1.101.3.4.1.8", "id-aes128-wrap-pad"}, \ + {"2.16.840.1.101.3.4.1.21", "aes-192-ecb"}, {"2.16.840.1.101.3.4.1.22", "aes-192-cbc"}, \ + {"2.16.840.1.101.3.4.1.23", "aes-192-ofb"}, {"2.16.840.1.101.3.4.1.24", "aes-192-cfb"}, \ + {"2.16.840.1.101.3.4.1.25", "id-aes192-wrap"}, {"2.16.840.1.101.3.4.1.26", "id-aes192-gcm"}, \ + {"2.16.840.1.101.3.4.1.27", "id-aes192-ccm"}, {"2.16.840.1.101.3.4.1.28", "id-aes192-wrap-pad"}, \ + {"2.16.840.1.101.3.4.1.41", "aes-256-ecb"}, {"2.16.840.1.101.3.4.1.42", "aes-256-cbc"}, \ + {"2.16.840.1.101.3.4.1.43", "aes-256-ofb"}, {"2.16.840.1.101.3.4.1.44", "aes-256-cfb"}, \ + {"2.16.840.1.101.3.4.1.45", "id-aes256-wrap"}, {"2.16.840.1.101.3.4.1.46", "id-aes256-gcm"}, \ + {"2.16.840.1.101.3.4.1.47", "id-aes256-ccm"}, {"2.16.840.1.101.3.4.1.48", "id-aes256-wrap-pad"}, \ + {"1.2.410.200046.1.1.1", "aria-128-ecb"}, {"1.2.410.200046.1.1.2", "aria-128-cbc"}, \ + {"1.2.410.200046.1.1.3", "aria-128-cfb"}, {"1.2.410.200046.1.1.4", "aria-128-ofb"}, \ + {"1.2.410.200046.1.1.5", "aria-128-ctr"}, {"1.2.410.200046.1.1.6", "aria-192-ecb"}, \ + {"1.2.410.200046.1.1.7", "aria-192-cbc"}, {"1.2.410.200046.1.1.8", "aria-192-cfb"}, \ + {"1.2.410.200046.1.1.9", "aria-192-ofb"}, {"1.2.410.200046.1.1.10", "aria-192-ctr"}, \ + {"1.2.410.200046.1.1.11", "aria-256-ecb"}, {"1.2.410.200046.1.1.12", "aria-256-cbc"}, \ + {"1.2.410.200046.1.1.13", "aria-256-cfb"}, {"1.2.410.200046.1.1.14", "aria-256-ofb"}, \ + {"1.2.410.200046.1.1.15", "aria-256-ctr"}, {"1.2.410.200046.1.1.34", "aria-128-gcm"}, \ + {"1.2.410.200046.1.1.35", "aria-192-gcm"}, {"1.2.410.200046.1.1.36", "aria-256-gcm"}, \ + {"1.2.410.200046.1.1.37", "aria-128-ccm"}, {"1.2.410.200046.1.1.38", "aria-192-ccm"}, \ + {"1.2.410.200046.1.1.39", "aria-256-ccm"}, {"0.3.4401.5.3.1.9.1", "camellia-128-ecb"}, \ + {"0.3.4401.5.3.1.9.3", "camellia-128-ofb"}, {"0.3.4401.5.3.1.9.4", "camellia-128-cfb"}, \ + {"0.3.4401.5.3.1.9.9", "camellia-128-ctr"}, {"0.3.4401.5.3.1.9.21", "camellia-192-ecb"}, \ + {"0.3.4401.5.3.1.9.23", "camellia-192-ofb"}, {"0.3.4401.5.3.1.9.24", "camellia-192-cfb"}, \ + {"0.3.4401.5.3.1.9.29", "camellia-192-ctr"}, {"0.3.4401.5.3.1.9.41", "camellia-256-ecb"}, \ + {"0.3.4401.5.3.1.9.43", "camellia-256-ofb"}, {"0.3.4401.5.3.1.9.44", "camellia-256-cfb"}, \ + {"0.3.4401.5.3.1.9.49", "camellia-256-ctr"}, {"1.2.156.10197.1.104.1", "sm4-ecb"}, \ + {"1.2.156.10197.1.104.2", "sm4-cbc"}, {"1.2.156.10197.1.104.3", "sm4-ofb"}, \ + {"1.2.156.10197.1.104.4", "sm4-cfb"}, {"1.2.156.10197.1.104.7", "sm4-ctr"}, \ + {"1.2.156.10197.1.104.8", "sm4-gcm"}, {"1.2.156.10197.1.104.9", "sm4-ccm"}, \ + {"1.2.156.10197.1.104.10", "sm4-xts"}, {"1.2.392.200011.61.1.1.1.2", "camellia-128-cbc"}, \ + {"1.2.392.200011.61.1.1.1.3", "camellia-192-cbc"}, \ + {"1.2.392.200011.61.1.1.1.4", "camellia-256-cbc"}, {"1.2.840.113549.3.2", "rc2-cbc"}, \ + {"1.2.840.113549.3.4", "rc4"}, {"1.2.840.113549.3.7", "des-ede3-cbc"}, \ + {"1.2.840.113549.1.9.16.3.6", "id-smime-alg-cms3deswrap"}, {"1.3.14.3.2.6", "des-ecb"}, \ + {"1.3.14.3.2.7", "des-cbc"}, {"1.3.14.3.2.8", "des-ofb"}, {"1.3.14.3.2.9", "des-cfb"}, \ + {"1.3.14.3.2.17", "des-ede"}, {"1.3.111.2.1619.0.1.1", "aes-128-xts"}, \ + {"1.3.111.2.1619.0.1.2", "aes-256-xts"}, {"1.3.6.1.4.1.3029.1.2", "bf-cbc"}, \ + {"1.3.6.1.4.1.188.7.1.1.2", "idea-cbc"}, {"1.2.410.200004.1.3", "seed-ecb"}, \ + {"1.2.410.200004.1.4", "seed-cbc"}, {"1.2.410.200004.1.5", "seed-cfb"}, \ + {"1.2.410.200004.1.6", "seed-ofb"}, {"1.2.840.113533.7.66.10", "cast5-cbc"}, + +#endif diff --git a/packages/runtime/src/scr_lib.c b/packages/runtime/src/scr_lib.c index fb3524c81..b7736bc35 100644 --- a/packages/runtime/src/scr_lib.c +++ b/packages/runtime/src/scr_lib.c @@ -8137,6 +8137,11 @@ static bool scr_digest_alg(const char *name, size_t len, ScrDigestAlg *out) { return false; } +bool scr_digest_known(const char *name, size_t len) { + ScrDigestAlg alg; + return scr_digest_alg(name, len, &alg); +} + /* createHash() and crypto.hash() also accept "dss1" in any case. */ static bool scr_hash_alg(const char *name, size_t len, ScrDigestAlg *out) { if (scr_digest_alg(name, len, out)) return true; diff --git a/packages/runtime/src/scr_lib.h b/packages/runtime/src/scr_lib.h index fa447ff41..7ba9e2907 100644 --- a/packages/runtime/src/scr_lib.h +++ b/packages/runtime/src/scr_lib.h @@ -63,6 +63,9 @@ bool scr_lib_fork_info(double *target, uintptr_t *read_handle, * direct startup never filters user arguments. */ bool scr_lib_should_collapse_reexec_arg(ScrStr *cmd, ScrArr *args); ScrStr *scr_process_platform(void); /* +1 interned ("darwin", "linux", ...) */ +/* Whether OpenSSL, as Node 24 links it, names a digest `name` (its names, + * aliases and object identifiers, case-insensitively). */ +bool scr_digest_known(const char *name, size_t len); ScrStr *scr_process_cwd(void); /* +1 fresh (getcwd) */ bool scr_stdio_write(int fd, const void *data, size_t len); diff --git a/packages/runtime/src/scr_pki.c b/packages/runtime/src/scr_pki.c index a1d5b98a6..908129243 100644 --- a/packages/runtime/src/scr_pki.c +++ b/packages/runtime/src/scr_pki.c @@ -1,7 +1,7 @@ /* node:crypto asymmetric keys and signatures over the vendored mbedTLS * public-key layer: createPrivateKey, createPublicKey, generateKeyPairSync - * and generateKeyPair for "rsa", "ec", "ed25519" and "x25519" keys, - * crypto.diffieHellman (ECDH and X25519), the PrivateKeyObject and + * and generateKeyPair for "rsa", "rsa-pss", "ec", "ed25519" and "x25519" + * keys, crypto.diffieHellman (ECDH and X25519), the PrivateKeyObject and * PublicKeyObject handles (type, asymmetricKeyType, * asymmetricKeyDetails, export(), equals()), crypto.sign and crypto.verify, * and the Sign and Verify objects of createSign and createVerify. Keys read @@ -10,7 +10,8 @@ * prime256v1, secp384r1, secp521r1 and secp256k1, and the Ed25519 * arithmetic is scr_ed25519.c. Argument checks * and errors follow Node 24's lib/internal/crypto/keys.js, keygen.js and - * sig.js. Encrypted keys and other key types throw a coded SC2020 error. + * sig.js. Private keys export and import encrypted as PBES2 PKCS#8 and as + * traditional PEM. Other key types throw a coded SC2020 error. * All arguments are borrowed. */ #include "scr_runtime.h" @@ -23,6 +24,7 @@ #include "mbedtls/asn1.h" #include "mbedtls/asn1write.h" #include "mbedtls/base64.h" +#include "mbedtls/cipher.h" #include "mbedtls/bignum.h" #include "mbedtls/ecdh.h" #include "mbedtls/ecdsa.h" @@ -30,11 +32,13 @@ #include "mbedtls/md.h" #include "mbedtls/oid.h" #include "mbedtls/pk.h" +#include "mbedtls/pkcs5.h" #include "mbedtls/platform_util.h" #include "mbedtls/rsa.h" #include "mbedtls/x509_crt.h" #include "scr_pki.h" +#include "scr_cipher_names.h" /* ── errors ───────────────────────────────────────────────────────────── */ @@ -187,6 +191,13 @@ typedef struct SpKey { * bytes as given, before clamping, and the public key */ uint8_t ed_seed[32]; uint8_t ed_pub[32]; + /* An RSA-PSS key (id-RSASSA-PSS): signatures only, with PSS padding. + * With RSASSA-PSS-params it signs only with pss_md and MGF1 over + * pss_mgf1, and salts of at least pss_salt bytes. */ + bool rsa_pss; + bool pss_params; + mbedtls_md_type_t pss_md, pss_mgf1; + int pss_salt; } SpKey; static void *sp_key_retain(void *h) { @@ -245,6 +256,27 @@ static bool sp_is_ed(const SpKey *k) { return k->ed25519; } static bool sp_is_x(const SpKey *k) { return k->x25519; } +/* The PSS fields of `from` on `to`. */ +static void sp_pss_copy(SpKey *to, const SpKey *from) { + to->rsa_pss = from->rsa_pss; + to->pss_params = from->pss_params; + to->pss_md = from->pss_md; + to->pss_mgf1 = from->pss_mgf1; + to->pss_salt = from->pss_salt; +} + +/* Node's name for a digest RSASSA-PSS-params can name. */ +static const char *sp_pss_md_name(mbedtls_md_type_t md) { + switch (md) { + case MBEDTLS_MD_SHA1: return "sha1"; + case MBEDTLS_MD_SHA224: return "sha224"; + case MBEDTLS_MD_SHA256: return "sha256"; + case MBEDTLS_MD_SHA384: return "sha384"; + case MBEDTLS_MD_SHA512: return "sha512"; + default: return NULL; + } +} + /* An Ed25519 or X25519 key: 32-byte private and public keys, no details. */ static bool sp_is_okp(const SpKey *k) { return k->ed25519 || k->x25519; } @@ -341,10 +373,102 @@ static int sp_write_ed_der(const uint8_t *prefix, size_t prefix_len, const uint8 return (int)n; } +/* A digest AlgorithmIdentifier with NULL parameters, written backwards + * at *c; the written length or a negative error. */ +static int sp_write_md_alg(unsigned char **c, unsigned char *start, mbedtls_md_type_t md) { + const char *oid; + size_t oid_len; + int r, len = 0; + if ((r = mbedtls_oid_get_oid_by_md(md, &oid, &oid_len)) != 0) return r; + if ((r = mbedtls_asn1_write_null(c, start)) < 0) return r; + len += r; + if ((r = mbedtls_asn1_write_oid(c, start, oid, oid_len)) < 0) return r; + len += r; + if ((r = mbedtls_asn1_write_len(c, start, (size_t)len)) < 0) return r; + len += r; + if ((r = mbedtls_asn1_write_tag(c, start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) < 0) return r; + return len + r; +} + +/* An RSA-PSS key's AlgorithmIdentifier, as OpenSSL writes it: id-RSASSA-PSS + * with no parameters for a key without restrictions, or RSASSA-PSS-params + * omitting the fields at their defaults (SHA-1, MGF1 with SHA-1, salt 20). */ +static int sp_write_pss_alg(unsigned char **c, unsigned char *start, const SpKey *k) { + int r, len = 0; + if (k->pss_params) { + int params = 0; + if (k->pss_salt != 20) { + int field = 0; + if ((r = mbedtls_asn1_write_int(c, start, k->pss_salt)) < 0) return r; + field += r; + if ((r = mbedtls_asn1_write_len(c, start, (size_t)field)) < 0) return r; + field += r; + if ((r = mbedtls_asn1_write_tag(c, start, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 2)) < 0) + return r; + params += field + r; + } + if (k->pss_mgf1 != MBEDTLS_MD_SHA1) { + int field = 0; + if ((r = sp_write_md_alg(c, start, k->pss_mgf1)) < 0) return r; + field += r; + if ((r = mbedtls_asn1_write_oid(c, start, MBEDTLS_OID_MGF1, MBEDTLS_OID_SIZE(MBEDTLS_OID_MGF1))) < 0) + return r; + field += r; + if ((r = mbedtls_asn1_write_len(c, start, (size_t)field)) < 0) return r; + field += r; + if ((r = mbedtls_asn1_write_tag(c, start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) < 0) return r; + field += r; + if ((r = mbedtls_asn1_write_len(c, start, (size_t)field)) < 0) return r; + field += r; + if ((r = mbedtls_asn1_write_tag(c, start, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1)) < 0) + return r; + params += field + r; + } + if (k->pss_md != MBEDTLS_MD_SHA1) { + int field = 0; + if ((r = sp_write_md_alg(c, start, k->pss_md)) < 0) return r; + field += r; + if ((r = mbedtls_asn1_write_len(c, start, (size_t)field)) < 0) return r; + field += r; + if ((r = mbedtls_asn1_write_tag(c, start, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0)) < 0) + return r; + params += field + r; + } + if ((r = mbedtls_asn1_write_len(c, start, (size_t)params)) < 0) return r; + params += r; + if ((r = mbedtls_asn1_write_tag(c, start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) < 0) return r; + len += params + r; + } + if ((r = mbedtls_asn1_write_oid(c, start, MBEDTLS_OID_RSASSA_PSS, MBEDTLS_OID_SIZE(MBEDTLS_OID_RSASSA_PSS))) < 0) + return r; + len += r; + if ((r = mbedtls_asn1_write_len(c, start, (size_t)len)) < 0) return r; + len += r; + if ((r = mbedtls_asn1_write_tag(c, start, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) < 0) return r; + return len + r; +} + +static int sp_write_pkcs1_public_der(SpKey *k, unsigned char *buf, size_t size); + static int sp_write_spki_der(SpKey *k, unsigned char *buf, size_t size) { if (sp_is_okp(k)) return sp_write_ed_der(sp_is_x(k) ? sp_x_spki_prefix : sp_ed_spki_prefix, 12, k->ed_pub, buf, size); - return mbedtls_pk_write_pubkey_der(&k->pk, buf, size); + if (!k->rsa_pss) return mbedtls_pk_write_pubkey_der(&k->pk, buf, size); + /* SubjectPublicKeyInfo ::= SEQUENCE { AlgorithmIdentifier, BIT STRING + * RSAPublicKey } */ + unsigned char inner[SP_DER_MAX]; + int n = sp_write_pkcs1_public_der(k, inner, sizeof inner); + if (n < 0) return n; + unsigned char *c = buf + size; + int r, len = 0; + if ((r = mbedtls_asn1_write_bitstring(&c, buf, inner + sizeof inner - n, (size_t)n * 8)) < 0) return r; + len += r; + if ((r = sp_write_pss_alg(&c, buf, k)) < 0) return r; + len += r; + if ((r = mbedtls_asn1_write_len(&c, buf, (size_t)len)) < 0) return r; + len += r; + if ((r = mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) < 0) return r; + return len + r; } /* RSAPublicKey (PKCS#1) DER. */ @@ -414,6 +538,11 @@ static int sp_write_pkcs8_der(SpKey *k, unsigned char *buf, size_t size) { const char *oid; size_t oid_len; size_t alg_len = 0; + if (k->rsa_pss) { + if ((r = sp_write_pss_alg(&c, buf, k)) < 0) goto done; + len += (size_t)r; + goto version; + } if (sp_is_rsa(k)) { if ((r = mbedtls_asn1_write_null(&c, buf)) < 0) goto done; alg_len += (size_t)r; @@ -439,6 +568,7 @@ static int sp_write_pkcs8_der(SpKey *k, unsigned char *buf, size_t size) { alg_len += (size_t)r; len += alg_len; } +version: if ((r = mbedtls_asn1_write_int(&c, buf, 0)) < 0) goto done; len += (size_t)r; if ((r = mbedtls_asn1_write_len(&c, buf, len)) < 0) goto done; @@ -476,6 +606,622 @@ static ScrStr *sp_pem(const char *label, const unsigned char *der, size_t len) { return s; } +/* ── encrypted private keys ─────────────────────────────────────────── + * PKCS#8 EncryptedPrivateKeyInfo as OpenSSL 3 writes it (PBES2 with + * PBKDF2-HMAC-SHA256 over a 16-byte salt and 2048 iterations), and the + * traditional PEM encryption of PKCS#1 and SEC1 keys (Proc-Type and + * DEK-Info headers, the key from EVP_BytesToKey with MD5), for the ciphers + * below. Reading takes PBES2 with any HMAC-SHA PRF and these ciphers, and + * traditional PEM with the CBC ciphers through mbedTLS. */ + +typedef struct { + const char *name; /* OpenSSL's name */ + const char *pem; /* its DEK-Info name */ + mbedtls_cipher_type_t type; + const char *oid; + size_t oid_len, key_len, iv_len; + bool ecb; + /* What OpenSSL does when PKCS#8 or traditional PEM encryption takes + * the cipher, an SpKeyCipherError. */ + unsigned char pkcs8_error, traditional_error; +} SpKeyCipher; + +typedef enum { + SP_KC_OK, /* it encrypts */ + SP_KC_NO_OID, + SP_KC_EVP_CIPHER, + SP_KC_PARAMETER, + SP_KC_INPUT_LENGTH, + SP_KC_ZERO_CONTENT, + SP_KC_OPERATION, + SP_KC_PEM_CIPHER, + SP_KC_UNSUPPORTED, +} SpKeyCipherError; + +static const struct { + const char *packed, *library, *reason, *code; +} sp_key_cipher_errors[] = { + [SP_KC_NO_OID] = {"0680006C", "asn1 encoding routines", "cipher has no object identifier", + "ERR_OSSL_ASN1_CIPHER_HAS_NO_OBJECT_IDENTIFIER"}, + [SP_KC_EVP_CIPHER] = {"0300006B", "digital envelope routines", "unsupported cipher", + "ERR_OSSL_EVP_UNSUPPORTED_CIPHER"}, + [SP_KC_PARAMETER] = {"0300007A", "digital envelope routines", "cipher parameter error", + "ERR_OSSL_EVP_CIPHER_PARAMETER_ERROR"}, + [SP_KC_INPUT_LENGTH] = {"1C8000E6", "Provider routines", "invalid input length", "ERR_OSSL_INVALID_INPUT_LENGTH"}, + [SP_KC_ZERO_CONTENT] = {"068000DE", "asn1 encoding routines", "illegal zero content", + "ERR_OSSL_ASN1_ILLEGAL_ZERO_CONTENT"}, + [SP_KC_OPERATION] = {"1C800066", "Provider routines", "cipher operation failed", + "ERR_OSSL_CIPHER_OPERATION_FAILED"}, + [SP_KC_PEM_CIPHER] = {"04800071", "PEM routines", "unsupported cipher", "ERR_OSSL_PEM_UNSUPPORTED_CIPHER"}, + [SP_KC_UNSUPPORTED] = {"0308010C", "digital envelope routines", "unsupported", "ERR_OSSL_EVP_UNSUPPORTED"}, +}; + +#define SP_AES_OID(last) "\x60\x86\x48\x01\x65\x03\x04\x01" last, 9 +static const SpKeyCipher sp_key_ciphers[] = { + {"aes-128-cbc", "AES-128-CBC", MBEDTLS_CIPHER_AES_128_CBC, SP_AES_OID("\x02"), 16, 16, false}, + {"aes-192-cbc", "AES-192-CBC", MBEDTLS_CIPHER_AES_192_CBC, SP_AES_OID("\x16"), 24, 16, false}, + {"aes-256-cbc", "AES-256-CBC", MBEDTLS_CIPHER_AES_256_CBC, SP_AES_OID("\x2a"), 32, 16, false}, + {"aes-128-ecb", "AES-128-ECB", MBEDTLS_CIPHER_AES_128_ECB, SP_AES_OID("\x01"), 16, 0, true, SP_KC_OK, SP_KC_PEM_CIPHER}, + {"aes-192-ecb", "AES-192-ECB", MBEDTLS_CIPHER_AES_192_ECB, SP_AES_OID("\x15"), 24, 0, true, SP_KC_OK, SP_KC_PEM_CIPHER}, + {"aes-256-ecb", "AES-256-ECB", MBEDTLS_CIPHER_AES_256_ECB, SP_AES_OID("\x29"), 32, 0, true, SP_KC_OK, SP_KC_PEM_CIPHER}, + {"des-ede3-cbc", "DES-EDE3-CBC", MBEDTLS_CIPHER_DES_EDE3_CBC, "\x2a\x86\x48\x86\xf7\x0d\x03\x07", 8, 24, 8, false}, +}; +static const struct { + const char *alias, *name; +} sp_key_cipher_aliases[] = { + {"aes128", "aes-128-cbc"}, {"aes192", "aes-192-cbc"}, {"aes256", "aes-256-cbc"}, {"des3", "des-ede3-cbc"}, +}; + +/* The names OpenSSL 3.5 refuses to encrypt a private key with in one form + * or both, from Node 24 (the legacy-provider names fail in both). Other + * names Node knows encrypt there and are refused here. */ +#define SP_KC_FAIL(name, pkcs8, traditional) \ + {name, NULL, MBEDTLS_CIPHER_NONE, NULL, 0, 0, 0, false, SP_KC_##pkcs8, SP_KC_##traditional} +static const SpKeyCipher sp_key_cipher_failures[] = { + SP_KC_FAIL("aes-128-cbc-cts", NO_OID, OK), SP_KC_FAIL("aes-128-ccm", EVP_CIPHER, OK), + SP_KC_FAIL("aes-128-ctr", NO_OID, OK), SP_KC_FAIL("aes-128-gcm", PARAMETER, OK), + SP_KC_FAIL("aes-128-gcm-siv", NO_OID, OK), SP_KC_FAIL("aes-128-ocb", NO_OID, OK), + SP_KC_FAIL("aes-128-siv", NO_OID, PEM_CIPHER), + SP_KC_FAIL("aes-128-wrap", INPUT_LENGTH, INPUT_LENGTH), + SP_KC_FAIL("aes-128-wrap-inv", NO_OID, INPUT_LENGTH), + SP_KC_FAIL("aes-128-wrap-pad-inv", NO_OID, OK), SP_KC_FAIL("aes-128-xts", EVP_CIPHER, OK), + SP_KC_FAIL("aes-192-cbc-cts", NO_OID, OK), SP_KC_FAIL("aes-192-ccm", EVP_CIPHER, OK), + SP_KC_FAIL("aes-192-ctr", NO_OID, OK), SP_KC_FAIL("aes-192-gcm", PARAMETER, OK), + SP_KC_FAIL("aes-192-gcm-siv", NO_OID, OK), SP_KC_FAIL("aes-192-ocb", NO_OID, OK), + SP_KC_FAIL("aes-192-siv", NO_OID, PEM_CIPHER), + SP_KC_FAIL("aes-192-wrap", INPUT_LENGTH, INPUT_LENGTH), + SP_KC_FAIL("aes-192-wrap-inv", NO_OID, INPUT_LENGTH), + SP_KC_FAIL("aes-192-wrap-pad-inv", NO_OID, OK), SP_KC_FAIL("aes-256-cbc-cts", NO_OID, OK), + SP_KC_FAIL("aes-256-ccm", EVP_CIPHER, OK), SP_KC_FAIL("aes-256-ctr", NO_OID, OK), + SP_KC_FAIL("aes-256-gcm", PARAMETER, OK), SP_KC_FAIL("aes-256-gcm-siv", NO_OID, OK), + SP_KC_FAIL("aes-256-ocb", NO_OID, OK), SP_KC_FAIL("aes-256-siv", NO_OID, PEM_CIPHER), + SP_KC_FAIL("aes-256-wrap", INPUT_LENGTH, INPUT_LENGTH), + SP_KC_FAIL("aes-256-wrap-inv", NO_OID, INPUT_LENGTH), + SP_KC_FAIL("aes-256-wrap-pad-inv", NO_OID, OK), SP_KC_FAIL("aes-256-xts", EVP_CIPHER, OK), + SP_KC_FAIL("aes128-wrap", INPUT_LENGTH, INPUT_LENGTH), + SP_KC_FAIL("aes128-wrap-inv", NO_OID, INPUT_LENGTH), + SP_KC_FAIL("aes128-wrap-pad-inv", NO_OID, OK), + SP_KC_FAIL("aes192-wrap", INPUT_LENGTH, INPUT_LENGTH), + SP_KC_FAIL("aes192-wrap-inv", NO_OID, INPUT_LENGTH), + SP_KC_FAIL("aes192-wrap-pad-inv", NO_OID, OK), + SP_KC_FAIL("aes256-wrap", INPUT_LENGTH, INPUT_LENGTH), + SP_KC_FAIL("aes256-wrap-inv", NO_OID, INPUT_LENGTH), + SP_KC_FAIL("aes256-wrap-pad-inv", NO_OID, OK), SP_KC_FAIL("aria-128-ccm", EVP_CIPHER, OK), + SP_KC_FAIL("aria-128-cfb1", NO_OID, OK), SP_KC_FAIL("aria-128-cfb8", NO_OID, OK), + SP_KC_FAIL("aria-128-ecb", OK, PEM_CIPHER), SP_KC_FAIL("aria-128-gcm", PARAMETER, OK), + SP_KC_FAIL("aria-192-ccm", EVP_CIPHER, OK), SP_KC_FAIL("aria-192-cfb1", NO_OID, OK), + SP_KC_FAIL("aria-192-cfb8", NO_OID, OK), SP_KC_FAIL("aria-192-ecb", OK, PEM_CIPHER), + SP_KC_FAIL("aria-192-gcm", PARAMETER, OK), SP_KC_FAIL("aria-256-ccm", EVP_CIPHER, OK), + SP_KC_FAIL("aria-256-cfb1", NO_OID, OK), SP_KC_FAIL("aria-256-cfb8", NO_OID, OK), + SP_KC_FAIL("aria-256-ecb", OK, PEM_CIPHER), SP_KC_FAIL("aria-256-gcm", PARAMETER, OK), + SP_KC_FAIL("camellia-128-cbc-cts", NO_OID, OK), SP_KC_FAIL("camellia-128-cfb1", NO_OID, OK), + SP_KC_FAIL("camellia-128-cfb8", NO_OID, OK), SP_KC_FAIL("camellia-128-ecb", OK, PEM_CIPHER), + SP_KC_FAIL("camellia-192-cbc-cts", NO_OID, OK), SP_KC_FAIL("camellia-192-cfb1", NO_OID, OK), + SP_KC_FAIL("camellia-192-cfb8", NO_OID, OK), SP_KC_FAIL("camellia-192-ecb", OK, PEM_CIPHER), + SP_KC_FAIL("camellia-256-cbc-cts", NO_OID, OK), SP_KC_FAIL("camellia-256-cfb1", NO_OID, OK), + SP_KC_FAIL("camellia-256-cfb8", NO_OID, OK), SP_KC_FAIL("camellia-256-ecb", OK, PEM_CIPHER), + SP_KC_FAIL("chacha20", NO_OID, OK), SP_KC_FAIL("chacha20-poly1305", NO_OID, OK), + SP_KC_FAIL("des-ede", OK, PEM_CIPHER), SP_KC_FAIL("des-ede-cbc", NO_OID, OK), + SP_KC_FAIL("des-ede-cfb", NO_OID, OK), SP_KC_FAIL("des-ede-ecb", OK, PEM_CIPHER), + SP_KC_FAIL("des-ede-ofb", NO_OID, OK), SP_KC_FAIL("des-ede3", NO_OID, PEM_CIPHER), + SP_KC_FAIL("des-ede3-cfb", ZERO_CONTENT, OK), SP_KC_FAIL("des-ede3-cfb1", ZERO_CONTENT, OK), + SP_KC_FAIL("des-ede3-cfb8", ZERO_CONTENT, OK), SP_KC_FAIL("des-ede3-ecb", NO_OID, PEM_CIPHER), + SP_KC_FAIL("des-ede3-ofb", NO_OID, OK), SP_KC_FAIL("des3-wrap", OPERATION, PEM_CIPHER), + SP_KC_FAIL("id-aes128-ccm", EVP_CIPHER, OK), SP_KC_FAIL("id-aes128-gcm", PARAMETER, OK), + SP_KC_FAIL("id-aes128-wrap", INPUT_LENGTH, INPUT_LENGTH), + SP_KC_FAIL("id-aes192-ccm", EVP_CIPHER, OK), SP_KC_FAIL("id-aes192-gcm", PARAMETER, OK), + SP_KC_FAIL("id-aes192-wrap", INPUT_LENGTH, INPUT_LENGTH), + SP_KC_FAIL("id-aes256-ccm", EVP_CIPHER, OK), SP_KC_FAIL("id-aes256-gcm", PARAMETER, OK), + SP_KC_FAIL("id-aes256-wrap", INPUT_LENGTH, INPUT_LENGTH), + SP_KC_FAIL("id-smime-alg-cms3deswrap", OPERATION, PEM_CIPHER), SP_KC_FAIL("sm4-ccm", NO_OID, OK), + SP_KC_FAIL("sm4-ecb", OK, PEM_CIPHER), SP_KC_FAIL("sm4-gcm", NO_OID, OK), + SP_KC_FAIL("sm4-xts", NO_OID, OK), SP_KC_FAIL("des", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("des-cbc", UNSUPPORTED, UNSUPPORTED), SP_KC_FAIL("des-ecb", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("des-cfb", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("des-cfb1", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("des-cfb8", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("des-ofb", UNSUPPORTED, UNSUPPORTED), SP_KC_FAIL("desx", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("desx-cbc", UNSUPPORTED, UNSUPPORTED), SP_KC_FAIL("bf", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("bf-cbc", UNSUPPORTED, UNSUPPORTED), SP_KC_FAIL("bf-ecb", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("bf-cfb", UNSUPPORTED, UNSUPPORTED), SP_KC_FAIL("bf-ofb", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("blowfish", UNSUPPORTED, UNSUPPORTED), SP_KC_FAIL("cast", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("cast-cbc", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("cast5-cbc", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("cast5-ecb", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("cast5-cfb", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("cast5-ofb", UNSUPPORTED, UNSUPPORTED), SP_KC_FAIL("rc2", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("rc2-cbc", UNSUPPORTED, UNSUPPORTED), SP_KC_FAIL("rc2-ecb", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("rc2-cfb", UNSUPPORTED, UNSUPPORTED), SP_KC_FAIL("rc2-ofb", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("rc2-40-cbc", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("rc2-64-cbc", UNSUPPORTED, UNSUPPORTED), SP_KC_FAIL("rc4", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("rc4-40", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("rc4-hmac-md5", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("seed", UNSUPPORTED, UNSUPPORTED), SP_KC_FAIL("seed-cbc", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("seed-ecb", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("seed-cfb", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("seed-ofb", UNSUPPORTED, UNSUPPORTED), SP_KC_FAIL("idea", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("idea-cbc", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("idea-ecb", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("idea-cfb", UNSUPPORTED, UNSUPPORTED), + SP_KC_FAIL("idea-ofb", UNSUPPORTED, UNSUPPORTED), +}; +#undef SP_KC_FAIL + +static bool sp_ascii_eq_ci(const char *a, size_t len, const char *b) { + if (strlen(b) != len) return false; + for (size_t i = 0; i < len; i++) { + char c = a[i]; + if (c >= 'A' && c <= 'Z') c = (char)(c - 'A' + 'a'); + if (c != b[i]) return false; + } + return true; +} + +/* The cipher an export names, by a name or the OID text of one: true with + * *out set (an entry of sp_key_ciphers, or of sp_key_cipher_failures); + * false with Node's + * ERR_CRYPTO_UNKNOWN_CIPHER pending, or the SC2020 refusal for a cipher + * Node encrypts with that keys here do not. */ +static bool sp_key_cipher(const ScrStr *name, const SpKeyCipher **out) { + const char *data = name->data; + size_t len = name->len; + static const struct { + const char *oid, *name; + } oids[] = {SCR_CIPHER_OID_ALIASES}; + for (size_t i = 0; i < sizeof oids / sizeof oids[0]; i++) { + if (strlen(oids[i].oid) == len && memcmp(data, oids[i].oid, len) == 0) { + data = oids[i].name; + len = strlen(data); + } + } + const char *wanted = NULL; + for (size_t i = 0; i < sizeof sp_key_cipher_aliases / sizeof sp_key_cipher_aliases[0]; i++) + if (sp_ascii_eq_ci(data, len, sp_key_cipher_aliases[i].alias)) wanted = sp_key_cipher_aliases[i].name; + for (size_t i = 0; i < sizeof sp_key_ciphers / sizeof sp_key_ciphers[0]; i++) { + if (wanted ? strcmp(wanted, sp_key_ciphers[i].name) == 0 : sp_ascii_eq_ci(data, len, sp_key_ciphers[i].name)) { + *out = &sp_key_ciphers[i]; + return true; + } + } + for (size_t i = 0; i < sizeof sp_key_cipher_failures / sizeof sp_key_cipher_failures[0]; i++) { + if (sp_ascii_eq_ci(data, len, sp_key_cipher_failures[i].name)) { + *out = &sp_key_cipher_failures[i]; + return true; + } + } + static const char *const known[] = {SCR_CIPHER_KNOWN_NAMES}; + for (size_t i = 0; i < sizeof known / sizeof known[0]; i++) { + if (sp_ascii_eq_ci(data, len, known[i])) { + sp_not_supported("private keys encrypted with this cipher"); + return false; + } + } + sp_throw(SCR_ERR_ERROR, "ERR_CRYPTO_UNKNOWN_CIPHER", "Unknown cipher"); + return false; +} + +/* Whether encryption in the form (PKCS#8, or traditional PEM) can take + * the cipher for `len` bytes of key: false with OpenSSL's error pending, + * or the SC2020 refusal for a cipher OpenSSL encrypts with that keys here + * do not. The key wrap ciphers fail only on a length that is not a + * multiple of 8; AES key wrap then encrypts, and Node's 3DES key wrap + * corrupts its heap. */ +static bool sp_key_cipher_ready(const SpKeyCipher *ci, bool pkcs8, size_t len) { + unsigned char error = pkcs8 ? ci->pkcs8_error : ci->traditional_error; + if ((error == SP_KC_INPUT_LENGTH || error == SP_KC_OPERATION) && len % 8 == 0) error = SP_KC_OK; + if (error != SP_KC_OK) { + sp_throw_openssl(sp_key_cipher_errors[error].packed, sp_key_cipher_errors[error].library, + sp_key_cipher_errors[error].reason, sp_key_cipher_errors[error].code, true); + return false; + } + if (ci->type == MBEDTLS_CIPHER_NONE) { + sp_not_supported("private keys encrypted with this cipher"); + return false; + } + return true; +} + +/* `in` through the cipher with PKCS#7 padding, as OpenSSL's EVP layer + * pads CBC and ECB: the output (+1 malloc'd, *out_len), or NULL when + * decryption finds bad padding. */ +static unsigned char *sp_key_cipher_run(const SpKeyCipher *ci, bool encrypt, const unsigned char *key, + const unsigned char *iv, const unsigned char *in, size_t in_len, + size_t *out_len) { + const mbedtls_cipher_info_t *info = mbedtls_cipher_info_from_type(ci->type); + size_t block = mbedtls_cipher_info_get_block_size(info); + size_t padded = encrypt ? (in_len / block + 1) * block : in_len; + if (!encrypt && (in_len == 0 || in_len % block != 0)) return NULL; + unsigned char *src = malloc(padded ? padded : 1), *out = malloc(padded ? padded : 1); + if (!src || !out) scr_trap("scriptc: out of memory\n"); + memcpy(src, in, in_len); + if (encrypt) memset(src + in_len, (int)(padded - in_len), padded - in_len); + mbedtls_cipher_context_t ctx; + mbedtls_cipher_init(&ctx); + int r = mbedtls_cipher_setup(&ctx, info); + if (r == 0) r = mbedtls_cipher_setkey(&ctx, key, (int)ci->key_len * 8, encrypt ? MBEDTLS_ENCRYPT : MBEDTLS_DECRYPT); + if (r == 0 && !ci->ecb) r = mbedtls_cipher_set_padding_mode(&ctx, MBEDTLS_PADDING_NONE); + if (r == 0 && !ci->ecb) r = mbedtls_cipher_set_iv(&ctx, iv, ci->iv_len); + size_t written = 0; + for (size_t i = 0; r == 0 && i < padded; i += block) { + size_t n = 0; + r = mbedtls_cipher_update(&ctx, src + i, block, out + written, &n); + written += n; + } + if (r == 0 && !ci->ecb) { + size_t n = 0; + r = mbedtls_cipher_finish(&ctx, out + written, &n); + written += n; + } + mbedtls_cipher_free(&ctx); + mbedtls_platform_zeroize(src, padded); + free(src); + if (r == 0 && !encrypt) { + unsigned char pad = written ? out[written - 1] : 0; + bool ok = pad >= 1 && pad <= block && pad <= written; + for (size_t i = 0; ok && i < pad; i++) ok = out[written - 1 - i] == pad; + if (ok) written -= pad; + else r = -1; + } + if (r != 0) { + mbedtls_platform_zeroize(out, padded); + free(out); + return NULL; + } + *out_len = written; + return out; +} + +/* EncryptedPrivateKeyInfo DER of the PKCS#8 `plain` (+1 malloc'd, + * *out_len), as OpenSSL 3 writes it; NULL on failure. */ +static unsigned char *sp_encrypt_pkcs8(const unsigned char *plain, size_t plain_len, const SpKeyCipher *ci, + const unsigned char *pass, size_t pass_len, size_t *out_len) { + unsigned char salt[16], iv[16], key[32]; + sp_random(NULL, salt, sizeof salt); + sp_random(NULL, iv, ci->iv_len); + if (mbedtls_pkcs5_pbkdf2_hmac_ext(MBEDTLS_MD_SHA256, pass, pass_len, salt, sizeof salt, 2048, + (uint32_t)ci->key_len, key) != 0) + return NULL; + size_t enc_len; + unsigned char *enc = sp_key_cipher_run(ci, true, key, iv, plain, plain_len, &enc_len); + mbedtls_platform_zeroize(key, sizeof key); + if (!enc) return NULL; + size_t size = enc_len + 256; + unsigned char *buf = malloc(size); + if (!buf) scr_trap("scriptc: out of memory\n"); + unsigned char *c = buf + size; + int r, len = 0, w; +#define SP_W(call) do { if ((w = (call)) < 0) { r = w; goto fail; } } while (0) + SP_W(mbedtls_asn1_write_octet_string(&c, buf, enc, enc_len)); + len += w; + /* encryptionScheme: the cipher with its IV (empty for ECB) */ + int scheme = 0; + SP_W(mbedtls_asn1_write_octet_string(&c, buf, iv, ci->iv_len)); + scheme += w; + SP_W(mbedtls_asn1_write_oid(&c, buf, ci->oid, ci->oid_len)); + scheme += w; + SP_W(mbedtls_asn1_write_len(&c, buf, (size_t)scheme)); + scheme += w; + SP_W(mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); + scheme += w; + /* keyDerivationFunc: PBKDF2 { salt, 2048, hmacWithSHA256 } */ + int kdf = 0, prf = 0; + SP_W(mbedtls_asn1_write_null(&c, buf)); + prf += w; + SP_W(mbedtls_asn1_write_oid(&c, buf, MBEDTLS_OID_HMAC_SHA256, MBEDTLS_OID_SIZE(MBEDTLS_OID_HMAC_SHA256))); + prf += w; + SP_W(mbedtls_asn1_write_len(&c, buf, (size_t)prf)); + prf += w; + SP_W(mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); + prf += w; + kdf += prf; + SP_W(mbedtls_asn1_write_int(&c, buf, 2048)); + kdf += w; + SP_W(mbedtls_asn1_write_octet_string(&c, buf, salt, sizeof salt)); + kdf += w; + SP_W(mbedtls_asn1_write_len(&c, buf, (size_t)kdf)); + kdf += w; + SP_W(mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); + kdf += w; + SP_W(mbedtls_asn1_write_oid(&c, buf, MBEDTLS_OID_PKCS5_PBKDF2, MBEDTLS_OID_SIZE(MBEDTLS_OID_PKCS5_PBKDF2))); + kdf += w; + SP_W(mbedtls_asn1_write_len(&c, buf, (size_t)kdf)); + kdf += w; + SP_W(mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); + kdf += w; + int params = kdf + scheme; + SP_W(mbedtls_asn1_write_len(&c, buf, (size_t)params)); + params += w; + SP_W(mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); + params += w; + SP_W(mbedtls_asn1_write_oid(&c, buf, MBEDTLS_OID_PKCS5_PBES2, MBEDTLS_OID_SIZE(MBEDTLS_OID_PKCS5_PBES2))); + params += w; + SP_W(mbedtls_asn1_write_len(&c, buf, (size_t)params)); + params += w; + SP_W(mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); + params += w; + len += params; + SP_W(mbedtls_asn1_write_len(&c, buf, (size_t)len)); + len += w; + SP_W(mbedtls_asn1_write_tag(&c, buf, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)); + len += w; +#undef SP_W + memmove(buf, c, (size_t)len); + mbedtls_platform_zeroize(enc, enc_len); + free(enc); + *out_len = (size_t)len; + return buf; +fail: + (void)r; + mbedtls_platform_zeroize(enc, enc_len); + free(enc); + free(buf); + return NULL; +} + +/* OpenSSL's EVP_BytesToKey with MD5 and one round over the first 8 IV + * bytes, as traditional PEM encryption derives its key. */ +static void sp_bytes_to_key(const unsigned char *pass, size_t pass_len, const unsigned char *salt, unsigned char *key, + size_t key_len) { + const mbedtls_md_info_t *md5 = mbedtls_md_info_from_type(MBEDTLS_MD_MD5); + unsigned char digest[16]; + size_t done = 0; + mbedtls_md_context_t ctx; + mbedtls_md_init(&ctx); + mbedtls_md_setup(&ctx, md5, 0); + for (bool first = true; done < key_len; first = false) { + mbedtls_md_starts(&ctx); + if (!first) mbedtls_md_update(&ctx, digest, sizeof digest); + mbedtls_md_update(&ctx, pass, pass_len); + mbedtls_md_update(&ctx, salt, 8); + mbedtls_md_finish(&ctx, digest); + size_t n = key_len - done < sizeof digest ? key_len - done : sizeof digest; + memcpy(key + done, digest, n); + done += n; + } + mbedtls_md_free(&ctx); + mbedtls_platform_zeroize(digest, sizeof digest); +} + +/* The traditional encrypted PEM of a PKCS#1 or SEC1 key (+1), or NULL. */ +static ScrStr *sp_encrypted_pem(const char *label, const unsigned char *der, size_t len, const SpKeyCipher *ci, + const unsigned char *pass, size_t pass_len) { + unsigned char iv[16], key[32]; + sp_random(NULL, iv, ci->iv_len); + sp_bytes_to_key(pass, pass_len, iv, key, ci->key_len); + size_t enc_len; + unsigned char *enc = sp_key_cipher_run(ci, true, key, iv, der, len, &enc_len); + mbedtls_platform_zeroize(key, sizeof key); + if (!enc) return NULL; + ScrStr *body = sp_pem(label, enc, enc_len); + mbedtls_platform_zeroize(enc, enc_len); + free(enc); + /* The headers follow the BEGIN line, then a blank line. */ + const char *nl = memchr(body->data, '\n', body->len); + size_t head = (size_t)(nl - body->data) + 1; + ScrJsonBuf out; + scr_jb_init(&out); + for (size_t i = 0; i < head; i++) scr_jb_putc(&out, body->data[i]); + scr_jb_puts(&out, "Proc-Type: 4,ENCRYPTED\nDEK-Info: "); + scr_jb_puts(&out, ci->pem); + scr_jb_putc(&out, ','); + static const char hex[] = "0123456789ABCDEF"; + for (size_t i = 0; i < ci->iv_len; i++) { + scr_jb_putc(&out, hex[iv[i] >> 4]); + scr_jb_putc(&out, hex[iv[i] & 15]); + } + scr_jb_puts(&out, "\n\n"); + for (size_t i = head; i < body->len; i++) scr_jb_putc(&out, body->data[i]); + scr_str_release(body); + return scr_jb_finish(&out); +} + +/* OpenSSL's errors for an encrypted private key: the message, Node's + * code, and the error stack OpenSSL leaves for the input's form. */ +static void sp_throw_key_decrypt(const char *message, const char *library, const char *reason, const char *code, + const char *const *stack, size_t stack_len) { + ScrStr *text = scr_str_new(message, strlen(message)); + ScrError *e = scr_error_new(SCR_ERR_ERROR, text); + scr_str_release(text); + ScrDyn *list = scr_dyn_new_arr(); + for (size_t i = 0; i < stack_len; i++) { + ScrStr *entry = scr_str_new(stack[i], strlen(stack[i])); + scr_dyn_arr_push(list, scr_dyn_new_str(entry)); + scr_str_release(entry); + } + scr_error_set_prop(e, "opensslErrorStack", 17, list); + const char *keys[] = {"library", "reason", "code"}; + const char *values[] = {library, reason, code}; + for (size_t i = 0; i < 3; i++) { + if (i == 2) scr_error_set_code(e, code); + ScrStr *value = scr_str_new(values[i], strlen(values[i])); + scr_error_set_prop(e, keys[i], strlen(keys[i]), scr_dyn_new_str(value)); + scr_str_release(value); + } + scr_throw_obj(e, &scr_error_retain_v, &scr_error_release_v, scr_error_trace_arg()); +} + +static const char sp_err_interrupted[] = "error:07880109:common libcrypto routines::interrupted or cancelled"; +static const char sp_err_bad_decrypt[] = "error:1C800064:Provider routines::bad decrypt"; + +/* No passphrase for an encrypted PEM key (pkcs8: whether it is PKCS#8). */ +static void sp_throw_passphrase_missing(bool pkcs8) { + static const char *const pkcs8_stack[] = {"error:04800068:PEM routines::bad password read", sp_err_interrupted, + "error:1C80009F:Provider routines::unable to get passphrase", + sp_err_interrupted, sp_err_interrupted}; + static const char *const pem_stack[] = {"error:04800068:PEM routines::bad password read", sp_err_interrupted, + sp_err_interrupted}; + sp_throw_key_decrypt(sp_err_interrupted, "common libcrypto routines", "interrupted or cancelled", + "ERR_OSSL_CRYPTO_INTERRUPTED_OR_CANCELLED", pkcs8 ? pkcs8_stack : pem_stack, pkcs8 ? 5 : 3); +} + +/* A passphrase that does not decrypt the key: PKCS#8 in PEM, PKCS#8 in + * DER, or traditional PEM. */ +static void sp_throw_bad_decrypt(int form) { + static const char cipherfinal[] = "error:11800074:PKCS12 routines::pkcs12 cipherfinal error"; + static const char *const stacks[][4] = { + {cipherfinal, sp_err_bad_decrypt, cipherfinal, sp_err_bad_decrypt}, + {cipherfinal, sp_err_bad_decrypt}, + {"error:04800065:PEM routines::bad decrypt", sp_err_bad_decrypt}, + }; + sp_throw_key_decrypt(sp_err_bad_decrypt, "Provider routines", "bad decrypt", "ERR_OSSL_BAD_DECRYPT", stacks[form], + form == 0 ? 4 : 2); +} + +/* The cipher name of an encrypted traditional PEM key's DEK-Info header + * into `name` (NUL-terminated), or false for other input. */ +static bool sp_pem_dek_info(const unsigned char *data, size_t len, char *name, size_t cap) { + const char *text = (const char *)data; + const char *begin = NULL; + for (size_t i = 0; i + 11 <= len && !begin; i++) + if (memcmp(text + i, "-----BEGIN ", 11) == 0) begin = text + i; + if (!begin) return false; + const char *end = text + len, *line = memchr(begin, '\n', (size_t)(end - begin)); + bool encrypted = false; + while (line && ++line < end) { + const char *eol = memchr(line, '\n', (size_t)(end - line)); + size_t n = (size_t)((eol ? eol : end) - line); + if (n && line[n - 1] == '\r') n--; + if (n >= 10 && memcmp(line, "Proc-Type:", 10) == 0) { + for (size_t i = 10; i + 9 <= n; i++) + if (memcmp(line + i, "ENCRYPTED", 9) == 0) encrypted = true; + } else if (n >= 9 && memcmp(line, "DEK-Info:", 9) == 0) { + if (!encrypted) return false; + size_t i = 9; + while (i < n && line[i] == ' ') i++; + size_t o = 0; + while (i < n && line[i] != ',' && o + 1 < cap) name[o++] = line[i++]; + name[o] = 0; + return true; + } else if (n == 0 || memchr(line, ':', n) == NULL) { + return false; + } + line = eol; + } + return false; +} + +/* Before mbedTLS reads an encrypted traditional PEM key: false with + * OpenSSL's error pending for a DEK-Info cipher it does not know, a + * missing passphrase, or a legacy-provider cipher, or the SC2020 refusal + * for a cipher mbedTLS does not decrypt; true for other input. */ +static bool sp_pem_dek_check(const unsigned char *data, size_t len, const ScrBytes *pass) { + char name[64]; + if (!sp_pem_dek_info(data, len, name, sizeof name)) return true; + size_t n = strlen(name); + static const char *const known[] = {SCR_CIPHER_KNOWN_NAMES}; + static const struct { + const char *name; + unsigned iv_len; + } legacy[] = {SCR_CIPHER_LEGACY_ENTRIES}; + bool is_known = false, is_legacy = false; + for (size_t i = 0; i < sizeof known / sizeof known[0]; i++) + if (sp_ascii_eq_ci(name, n, known[i])) is_known = true; + for (size_t i = 0; i < sizeof legacy / sizeof legacy[0]; i++) + if (sp_ascii_eq_ci(name, n, legacy[i].name)) is_legacy = true; + if (!is_known && !is_legacy) { + static const char *const stack[] = {"error:04800072:PEM routines::unsupported encryption"}; + sp_throw_key_decrypt(stack[0], "PEM routines", "unsupported encryption", "ERR_OSSL_PEM_UNSUPPORTED_ENCRYPTION", + stack, 1); + return false; + } + if (!pass) { + sp_throw_passphrase_missing(false); + return false; + } + if (is_legacy) { + static const char unsupported[] = "error:0308010C:digital envelope routines::unsupported"; + static const char *const stack[] = {"error:04800065:PEM routines::bad decrypt", unsupported}; + sp_throw_key_decrypt(unsupported, "digital envelope routines", "unsupported", "ERR_OSSL_EVP_UNSUPPORTED", stack, + 2); + return false; + } + /* mbedTLS decrypts these names, as OpenSSL writes them. */ + static const char *const read[] = {"AES-128-CBC", "AES-192-CBC", "AES-256-CBC", "DES-EDE3-CBC"}; + for (size_t i = 0; i < sizeof read / sizeof read[0]; i++) + if (strcmp(name, read[i]) == 0) return true; + sp_not_supported("private keys encrypted with this cipher"); + return false; +} + +/* The PKCS#8 inside a PBES2 EncryptedPrivateKeyInfo `der` (+1 malloc'd, + * *out_len): 1 decrypted, 0 another scheme or cipher, -1 a passphrase + * that does not decrypt it. */ +static int sp_decrypt_pkcs8(const unsigned char *der, size_t len, const unsigned char *pass, size_t pass_len, + unsigned char **out, size_t *out_len) { + unsigned char *p = (unsigned char *)der; + const unsigned char *end = der + len; + size_t n; + mbedtls_asn1_buf alg, params; + if (mbedtls_asn1_get_tag(&p, end, &n, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) return 0; + end = p + n; + if (mbedtls_asn1_get_alg(&p, end, &alg, ¶ms) != 0 || alg.len != MBEDTLS_OID_SIZE(MBEDTLS_OID_PKCS5_PBES2) || + memcmp(alg.p, MBEDTLS_OID_PKCS5_PBES2, alg.len) != 0 || + params.tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) + return 0; + unsigned char *q = params.p; + const unsigned char *params_end = params.p + params.len; + mbedtls_asn1_buf kdf, kdf_params, scheme, scheme_params; + if (mbedtls_asn1_get_alg(&q, params_end, &kdf, &kdf_params) != 0 || + kdf.len != MBEDTLS_OID_SIZE(MBEDTLS_OID_PKCS5_PBKDF2) || memcmp(kdf.p, MBEDTLS_OID_PKCS5_PBKDF2, kdf.len) != 0 || + mbedtls_asn1_get_alg(&q, params_end, &scheme, &scheme_params) != 0) + return 0; + const SpKeyCipher *ci = NULL; + for (size_t i = 0; i < sizeof sp_key_ciphers / sizeof sp_key_ciphers[0]; i++) + if (scheme.len == sp_key_ciphers[i].oid_len && memcmp(scheme.p, sp_key_ciphers[i].oid, scheme.len) == 0) + ci = &sp_key_ciphers[i]; + if (!ci || scheme_params.tag != MBEDTLS_ASN1_OCTET_STRING || scheme_params.len != ci->iv_len) return 0; + /* PBKDF2-params ::= SEQUENCE { salt OCTET STRING, iterationCount + * INTEGER, keyLength INTEGER OPTIONAL, prf AlgorithmIdentifier DEFAULT + * hmacWithSHA1 } */ + unsigned char *k = kdf_params.p; + const unsigned char *k_end = kdf_params.p + kdf_params.len; + size_t salt_len; + int iterations, key_len = (int)ci->key_len; + if (kdf_params.tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) || + mbedtls_asn1_get_tag(&k, k_end, &salt_len, MBEDTLS_ASN1_OCTET_STRING) != 0) + return 0; + const unsigned char *salt = k; + k += salt_len; + if (mbedtls_asn1_get_int(&k, k_end, &iterations) != 0 || iterations < 1) return 0; + if (k < k_end && *k == MBEDTLS_ASN1_INTEGER && (mbedtls_asn1_get_int(&k, k_end, &key_len) != 0 || + key_len != (int)ci->key_len)) + return 0; + mbedtls_md_type_t prf = MBEDTLS_MD_SHA1; + if (k < k_end) { + mbedtls_asn1_buf prf_oid, prf_params; + if (mbedtls_asn1_get_alg(&k, k_end, &prf_oid, &prf_params) != 0 || mbedtls_oid_get_md_hmac(&prf_oid, &prf) != 0) + return 0; + } + if (mbedtls_asn1_get_tag(&p, end, &n, MBEDTLS_ASN1_OCTET_STRING) != 0) return 0; + unsigned char key[32]; + if (mbedtls_pkcs5_pbkdf2_hmac_ext(prf, pass, pass_len, salt, salt_len, (unsigned)iterations, + (uint32_t)ci->key_len, key) != 0) + return 0; + *out = sp_key_cipher_run(ci, false, key, scheme_params.p, p, n, out_len); + mbedtls_platform_zeroize(key, sizeof key); + return *out ? 1 : -1; +} + static ScrDyn *sp_dyn_buffer(const unsigned char *data, size_t len) { ScrBytes *bytes = scr_bytes_new(SCR_BYTES_U8, (double)len); bytes->is_buffer = true; @@ -761,12 +1507,13 @@ static SpKey *sp_public_of(SpKey *k) { return pub; } unsigned char der[SP_DER_MAX]; - int n = sp_write_spki_der(k, der, sizeof der); + int n = k->rsa_pss ? mbedtls_pk_write_pubkey_der(&k->pk, der, sizeof der) : sp_write_spki_der(k, der, sizeof der); SpKey *pub = sp_key_alloc(false); if (n < 0 || mbedtls_pk_parse_public_key(&pub->pk, der + sizeof der - n, (size_t)n) != 0) { sp_key_release(pub); return NULL; } + sp_pss_copy(pub, k); return pub; } @@ -888,7 +1635,158 @@ static SpKey *sp_ed_from_der(const unsigned char *der, size_t len, bool private_ return k; } +/* RSASSA-PSS-params at *p (RFC 4055): true with the restrictions set on + * `k`, false when they are malformed or unsupported, which leaves the key + * without restrictions, as OpenSSL reads a negative or oversized salt. */ +static bool sp_pss_params_read(unsigned char **p, const unsigned char *end, SpKey *k) { + size_t n; + if (mbedtls_asn1_get_tag(p, end, &n, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) return false; + const unsigned char *params_end = *p + n; + mbedtls_md_type_t md = MBEDTLS_MD_SHA1, mgf1 = MBEDTLS_MD_SHA1; + int salt = 20; + if (*p < params_end && **p == (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0)) { + mbedtls_asn1_buf oid, params; + if (mbedtls_asn1_get_tag(p, params_end, &n, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0) != 0 || + mbedtls_asn1_get_alg(p, *p + n, &oid, ¶ms) != 0 || mbedtls_oid_get_md_alg(&oid, &md) != 0 || + !sp_pss_md_name(md)) + return false; + } + if (*p < params_end && **p == (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1)) { + mbedtls_asn1_buf oid, params; + if (mbedtls_asn1_get_tag(p, params_end, &n, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1) != 0 || + mbedtls_asn1_get_alg(p, *p + n, &oid, ¶ms) != 0 || oid.len != MBEDTLS_OID_SIZE(MBEDTLS_OID_MGF1) || + memcmp(oid.p, MBEDTLS_OID_MGF1, oid.len) != 0) + return false; + /* MGF1's parameters are the hash's AlgorithmIdentifier, whose + * content starts with the hash's OID. */ + if (params.tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) return false; + unsigned char *alg = params.p; + mbedtls_asn1_buf hash_oid = {.tag = MBEDTLS_ASN1_OID}; + if (mbedtls_asn1_get_tag(&alg, params.p + params.len, &hash_oid.len, MBEDTLS_ASN1_OID) != 0) return false; + hash_oid.p = alg; + if (mbedtls_oid_get_md_alg(&hash_oid, &mgf1) != 0 || !sp_pss_md_name(mgf1)) return false; + } + if (*p < params_end && **p == (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 2)) { + if (mbedtls_asn1_get_tag(p, params_end, &n, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 2) != 0 || + mbedtls_asn1_get_int(p, *p + n, &salt) != 0 || salt < 0) + return false; + } + *p = (unsigned char *)params_end; + k->pss_params = true; + k->pss_md = md; + k->pss_mgf1 = mgf1; + k->pss_salt = salt; + return true; +} + +/* An RSA-PSS key from PKCS#8 or SubjectPublicKeyInfo DER whose algorithm + * is id-RSASSA-PSS; NULL when the DER is neither, or with *failed set and + * Node's decoder error pending. A private key wanted as public answers its + * public key. */ +static SpKey *sp_public_of(SpKey *k); + +static SpKey *sp_pss_from_der(const unsigned char *der, size_t len, bool private_key, bool *failed) { + *failed = false; + unsigned char *p = (unsigned char *)der; + const unsigned char *end = der + len; + size_t n; + if (mbedtls_asn1_get_tag(&p, end, &n, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) return NULL; + end = p + n; + bool pkcs8 = p < end && *p == MBEDTLS_ASN1_INTEGER; + if (pkcs8) { + int version; + if (mbedtls_asn1_get_int(&p, end, &version) != 0 || version != 0) return NULL; + } + if (mbedtls_asn1_get_tag(&p, end, &n, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) return NULL; + const unsigned char *alg_end = p + n; + size_t oid_len; + if (mbedtls_asn1_get_tag(&p, alg_end, &oid_len, MBEDTLS_ASN1_OID) != 0 || + oid_len != MBEDTLS_OID_SIZE(MBEDTLS_OID_RSASSA_PSS) || memcmp(p, MBEDTLS_OID_RSASSA_PSS, oid_len) != 0) + return NULL; + p += oid_len; + SpKey *k = sp_key_alloc(pkcs8); + k->rsa_pss = true; + if (p < alg_end && !sp_pss_params_read(&p, alg_end, k)) k->pss_params = false; + p = (unsigned char *)alg_end; + int r; + if (pkcs8) { + r = mbedtls_asn1_get_tag(&p, end, &n, MBEDTLS_ASN1_OCTET_STRING); + if (r == 0) r = mbedtls_pk_parse_key(&k->pk, p, n, NULL, 0, sp_random, NULL); + } else { + r = private_key ? -1 : mbedtls_asn1_get_bitstring_null(&p, end, &n); + if (r == 0) r = mbedtls_pk_parse_public_key(&k->pk, p, n); + } + if (r != 0 || !sp_is_rsa(k)) { + sp_key_release(k); + *failed = true; + sp_unsupported_input(); + return NULL; + } + if (pkcs8 && !private_key) { + SpKey *pub = sp_public_of(k); + sp_key_release(k); + return pub; + } + return k; +} + +/* Whether `der` is a PKCS#8 EncryptedPrivateKeyInfo: a SEQUENCE of a PKCS#5 + * or PKCS#12 password-based AlgorithmIdentifier and an OCTET STRING. */ +static bool sp_is_encrypted_pkcs8(const unsigned char *der, size_t len) { + unsigned char *p = (unsigned char *)der; + const unsigned char *end = der + len; + size_t n; + mbedtls_asn1_buf alg, params; + if (mbedtls_asn1_get_tag(&p, end, &n, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) return false; + end = p + n; + if (mbedtls_asn1_get_alg(&p, end, &alg, ¶ms) != 0) return false; + static const char pkcs5[] = MBEDTLS_OID_PKCS5, pkcs12[] = MBEDTLS_OID_PKCS12_PBE; + bool password = (alg.len > sizeof pkcs5 - 1 && memcmp(alg.p, pkcs5, sizeof pkcs5 - 1) == 0) || + (alg.len > sizeof pkcs12 - 1 && memcmp(alg.p, pkcs12, sizeof pkcs12 - 1) == 0); + return password && mbedtls_asn1_get_tag(&p, end, &n, MBEDTLS_ASN1_OCTET_STRING) == 0 && p + n == end; +} + +static SpKey *sp_parse_with(const unsigned char *data, size_t len, bool private_key, const ScrBytes *pass); + static SpKey *sp_parse(const unsigned char *data, size_t len, bool private_key) { + return sp_parse_with(data, len, private_key, NULL); +} + +/* sp_parse with a passphrase for an encrypted private key (NULL: none). */ +static SpKey *sp_parse_with(const unsigned char *data, size_t len, bool private_key, const ScrBytes *pass) { + { + unsigned char *decoded; + const unsigned char *der; + size_t der_len; + if (sp_der_of(data, len, &decoded, &der, &der_len) && sp_is_encrypted_pkcs8(der, der_len)) { + bool from_pem = decoded != NULL; + SpKey *k = NULL; + unsigned char *plain = NULL; + size_t plain_len = 0; + int r = 0; + if (!pass) { + if (from_pem) sp_throw_passphrase_missing(true); + else sp_throw(SCR_ERR_TYPE, "ERR_MISSING_PASSPHRASE", "Passphrase required for encrypted key"); + } else { + r = sp_decrypt_pkcs8(der, der_len, pass->data, (size_t)scr_bytes_byte_len(pass), &plain, &plain_len); + if (r < 0) sp_throw_bad_decrypt(from_pem ? 0 : 1); + } + if (r > 0) { + k = sp_parse_with(plain, plain_len, private_key, NULL); + mbedtls_platform_zeroize(plain, plain_len); + free(plain); + } + if (decoded) { + mbedtls_platform_zeroize(decoded, der_len); + free(decoded); + } + if (r == 0 && pass) sp_not_supported("private keys encrypted with this scheme or cipher"); + return k; + } else if (decoded) { + mbedtls_platform_zeroize(decoded, der_len); + free(decoded); + } + } { unsigned char *decoded; const unsigned char *der; @@ -896,6 +1794,7 @@ static SpKey *sp_parse(const unsigned char *data, size_t len, bool private_key) if (sp_der_of(data, len, &decoded, &der, &der_len)) { bool failed; SpKey *ed = sp_ed_from_der(der, der_len, private_key, &failed); + if (!ed && !failed) ed = sp_pss_from_der(der, der_len, private_key, &failed); if (decoded) { mbedtls_platform_zeroize(decoded, der_len); free(decoded); @@ -912,6 +1811,7 @@ static SpKey *sp_parse(const unsigned char *data, size_t len, bool private_key) break; } } + if (pem && !sp_pem_dek_check(data, len, pass)) return NULL; unsigned char *buf = malloc(len + 1); if (!buf) scr_trap("scriptc: out of memory\n"); memcpy(buf, data, len); @@ -919,15 +1819,19 @@ static SpKey *sp_parse(const unsigned char *data, size_t len, bool private_key) size_t n = pem ? len + 1 : len; SpKey *k = sp_key_alloc(private_key); bool ok; + const unsigned char *pwd = pass ? pass->data : NULL; + size_t pwd_len = pass ? (size_t)scr_bytes_byte_len(pass) : 0; + int private_rc = 0; if (private_key) { - ok = mbedtls_pk_parse_key(&k->pk, buf, n, NULL, 0, sp_random, NULL) == 0; + private_rc = mbedtls_pk_parse_key(&k->pk, buf, n, pwd, pwd_len, sp_random, NULL); + ok = private_rc == 0; } else { ok = mbedtls_pk_parse_public_key(&k->pk, buf, n) == 0; if (!ok) { SpKey *priv = sp_key_alloc(true); mbedtls_pk_free(&k->pk); mbedtls_pk_init(&k->pk); - if (mbedtls_pk_parse_key(&priv->pk, buf, n, NULL, 0, sp_random, NULL) == 0) { + if ((private_rc = mbedtls_pk_parse_key(&priv->pk, buf, n, pwd, pwd_len, sp_random, NULL)) == 0) { sp_key_release(k); k = sp_public_of(priv); ok = k != NULL; @@ -949,7 +1853,10 @@ static SpKey *sp_parse(const unsigned char *data, size_t len, bool private_key) free(buf); if (!ok) { sp_key_release(k); - sp_unsupported_input(); + /* An encrypted traditional PEM key mbedTLS read. */ + if (private_rc == MBEDTLS_ERR_PK_PASSWORD_REQUIRED) sp_throw_passphrase_missing(false); + else if (private_rc == MBEDTLS_ERR_PK_PASSWORD_MISMATCH) sp_throw_bad_decrypt(2); + else sp_unsupported_input(); return NULL; } if (!sp_key_supported(k)) { @@ -1011,13 +1918,16 @@ static ScrDyn *sp_create_key(ScrDyn *input, bool private_key) { const ScrDyn *format = scr_dyn_undefined(); const ScrDyn *type = scr_dyn_undefined(); const ScrDyn *encoding = NULL; + const ScrDyn *passphrase = NULL; if (sp_is_object(input) && !scr_buffer_storage_is(input)) { data = sp_opt(input, "key"); format = sp_opt(input, "format"); type = sp_opt(input, "type"); encoding = sp_opt(input, "encoding"); - if (!sp_absent(sp_opt(input, "passphrase"))) { - sp_not_supported("encrypted private keys"); + passphrase = sp_opt(input, "passphrase"); + if (!sp_absent(passphrase) && passphrase->kind != SCR_DYN_STR && passphrase->kind != SCR_DYN_BYTES && + !scr_buffer_storage_is(passphrase)) { + sp_property_invalid("key.passphrase", passphrase); return NULL; } SpKey *inner = sp_key_of(data); @@ -1055,7 +1965,16 @@ static ScrDyn *sp_create_key(ScrDyn *input, bool private_key) { scr_dyn_arg_type_fail(data == input ? "key" : "key.key", sp_key_input_types, data); return NULL; } - SpKey *k = sp_parse(bytes->data, (size_t)scr_bytes_byte_len(bytes), private_key); + ScrBytes *pass = NULL; + if (passphrase && !sp_absent(passphrase)) { + pass = sp_source_bytes(passphrase, NULL); + if (!pass) { + scr_bytes_release(bytes); + return NULL; + } + } + SpKey *k = sp_parse_with(bytes->data, (size_t)scr_bytes_byte_len(bytes), private_key, pass); + if (pass) scr_bytes_release(pass); scr_bytes_release(bytes); return k ? sp_key_box(k) : NULL; } @@ -1296,7 +2215,13 @@ static ScrDyn *sp_export_plain(SpKey *k, const ScrDyn *options) { scr_dyn_arg_type_fail("options", "of type object", options ? options : scr_dyn_undefined()); return NULL; } - if (sp_is_str(format, "jwk")) return sp_export_jwk(k); + if (sp_is_str(format, "jwk")) { + if (k->rsa_pss) { + sp_throw(SCR_ERR_ERROR, "ERR_CRYPTO_JWK_UNSUPPORTED_KEY_TYPE", "Unsupported JWK Key Type."); + return NULL; + } + return sp_export_jwk(k); + } bool pem = sp_is_str(format, "pem"); if (!pem && !sp_is_str(format, "der")) { sp_property_invalid("options.format", format); @@ -1311,11 +2236,7 @@ static ScrDyn *sp_export_plain(SpKey *k, const ScrDyn *options) { sp_property_invalid("options.type", type); return NULL; } - if (!sp_absent(sp_opt(options, "cipher")) || !sp_absent(sp_opt(options, "passphrase"))) { - sp_not_supported("encrypted private key export"); - return NULL; - } - if (pkcs1 && !sp_is_rsa(k)) { + if (pkcs1 && (!sp_is_rsa(k) || k->rsa_pss)) { sp_incompatible("pkcs1", "can only be used for RSA keys"); return NULL; } @@ -1323,6 +2244,30 @@ static ScrDyn *sp_export_plain(SpKey *k, const ScrDyn *options) { sp_incompatible("sec1", "can only be used for EC keys"); return NULL; } + /* parseKeyEncoding's cipher and passphrase checks, then the cipher. */ + const ScrDyn *cipher = sp_opt(options, "cipher"), *passphrase = sp_opt(options, "passphrase"); + const SpKeyCipher *ci = NULL; + if (k->private_key) { + bool encrypted = !sp_absent(cipher) && cipher->kind != SCR_DYN_NULL; + if (encrypted) { + if (cipher->kind != SCR_DYN_STR) { + sp_property_invalid("options.cipher", cipher); + return NULL; + } + if (!pem && (pkcs1 || sec1)) { + sp_incompatible(pkcs1 ? "pkcs1" : "sec1", "does not support encryption"); + return NULL; + } + if (passphrase->kind != SCR_DYN_STR && passphrase->kind != SCR_DYN_BYTES && !scr_buffer_storage_is(passphrase)) { + sp_property_invalid("options.passphrase", passphrase); + return NULL; + } + if (!sp_key_cipher(cipher->v.str, &ci)) return NULL; + } else if (!sp_absent(passphrase)) { + sp_property_invalid_because("options.cipher", cipher, "is required when a passphrase is specified"); + return NULL; + } + } unsigned char *der = malloc(SP_DER_MAX); if (!der) scr_trap("scriptc: out of memory\n"); int n; @@ -1343,6 +2288,26 @@ static ScrDyn *sp_export_plain(SpKey *k, const ScrDyn *options) { ScrDyn *result = NULL; if (n < 0) { sp_unsupported_input(); + } else if (ci && !sp_key_cipher_ready(ci, pkcs8, (size_t)n)) { + /* OpenSSL's error, raised once the key is encoded. */ + } else if (ci) { + const unsigned char *start = der + SP_DER_MAX - n; + ScrBytes *pass = sp_source_bytes(passphrase, NULL); + const unsigned char *pass_data = pass ? pass->data : (const unsigned char *)""; + size_t pass_len = pass ? (size_t)scr_bytes_byte_len(pass) : 0; + if (pkcs8) { + size_t enc_len; + unsigned char *enc = sp_encrypt_pkcs8(start, (size_t)n, ci, pass_data, pass_len, &enc_len); + if (enc) { + result = pem ? sp_dyn_str(sp_pem("ENCRYPTED PRIVATE KEY", enc, enc_len)) : sp_dyn_buffer(enc, enc_len); + free(enc); + } + } else { + ScrStr *text = sp_encrypted_pem(label, start, (size_t)n, ci, pass_data, pass_len); + if (text) result = sp_dyn_str(text); + } + if (pass) scr_bytes_release(pass); + if (!result) sp_unsupported_input(); } else { const unsigned char *start = der + SP_DER_MAX - n; result = pem ? sp_dyn_str(sp_pem(label, start, (size_t)n)) : sp_dyn_buffer(start, (size_t)n); @@ -1372,6 +2337,12 @@ static ScrDyn *sp_key_details(SpKey *k) { ScrBigInt *big = scr_bigint_from_u64(exponent); sp_set(details, "publicExponent", scr_dyn_new_bigint(big)); scr_bigint_release(big); + if (k->pss_params) { + const char *md = sp_pss_md_name(k->pss_md), *mgf1 = sp_pss_md_name(k->pss_mgf1); + sp_set(details, "hashAlgorithm", sp_dyn_str(scr_str_new(md, strlen(md)))); + sp_set(details, "mgf1HashAlgorithm", sp_dyn_str(scr_str_new(mgf1, strlen(mgf1)))); + sp_set(details, "saltLength", scr_dyn_new_num(k->pss_salt)); + } } else { const SpCurve *curve = sp_curve_of(k); sp_set(details, "namedCurve", sp_dyn_str(scr_str_new(curve->name, strlen(curve->name)))); @@ -1429,6 +2400,7 @@ static ScrDyn *sp_key_get(void *h, const char *name, size_t len) { if (len == 17 && memcmp(name, "asymmetricKeyType", 17) == 0) return sp_is_ed(k) ? sp_dyn_str(scr_str_new("ed25519", 7)) : sp_is_x(k) ? sp_dyn_str(scr_str_new("x25519", 6)) + : k->rsa_pss ? sp_dyn_str(scr_str_new("rsa-pss", 7)) : sp_is_rsa(k) ? sp_dyn_str(scr_str_new("rsa", 3)) : sp_dyn_str(scr_str_new("ec", 2)); if (len == 20 && memcmp(name, "asymmetricKeyDetails", 20) == 0) return sp_key_details(k); @@ -1640,7 +2612,7 @@ static bool sp_check_encoding_plain(const ScrDyn *enc, const char *name, const S return false; } } - if (!*refusal && encrypted) *refusal = "encrypted private key export"; + (void)encrypted; return true; } @@ -1648,10 +2620,122 @@ static bool sp_check_encoding_plain(const ScrDyn *enc, const char *name, const S typedef struct { enum { SP_GEN_RSA, SP_GEN_EC, SP_GEN_ED25519, SP_GEN_X25519 } kind; double bits, exponent; /* RSA */ + bool pss; /* an RSA-PSS key, restricted when pss_params */ + bool pss_params, md_set, mgf1_set, salt_set; + mbedtls_md_type_t md, mgf1; + int salt; const SpCurve *curve; /* EC */ } SpKeyGen; +static bool sp_digest_of(const ScrStr *name, mbedtls_md_type_t *md); + +/* A digest name of rsa-pss's options: true with *md set, or false with + * Node's ERR_CRYPTO_INVALID_DIGEST pending ("Invalid digest: x" or "Invalid + * MGF1 digest: x"), or the SC2020 refusal for a digest OpenSSL has and + * RSASSA-PSS-params here cannot name. */ +static bool sp_pss_digest(const ScrDyn *name, bool mgf1, mbedtls_md_type_t *md) { + if (sp_digest_of(name->v.str, md) && sp_pss_md_name(*md)) return true; + if (scr_digest_known(name->v.str->data, name->v.str->len)) { + sp_not_supported("generateKeyPair rsa-pss with this digest"); + return false; + } + scr_pki_throw_fmt(SCR_ERR_TYPE, "ERR_CRYPTO_INVALID_DIGEST", "Invalid %sdigest: %.*s", mgf1 ? "MGF1 " : "", + (int)name->v.str->len, name->v.str->data); + return false; +} + +/* rsa-pss's options after the modulus and exponent, in Node's order + * (lib/internal/crypto/keygen.js): saltLength, hashAlgorithm, + * mgf1HashAlgorithm, and the deprecated hash and mgf1Hash with their + * DEP0154 warnings, then the digest lookups of RsaKeyGenTraits. */ +static bool sp_pss_keygen_options(const ScrDyn *options, SpKeyGen *gen) { + const ScrDyn *salt = sp_opt(options, "saltLength"); + const ScrDyn *hash_alg = sp_opt(options, "hashAlgorithm"), *mgf1_alg = sp_opt(options, "mgf1HashAlgorithm"); + const ScrDyn *hash = sp_opt(options, "hash"), *mgf1_hash = sp_opt(options, "mgf1Hash"); + if (!sp_absent(salt)) { + if (salt->kind != SCR_DYN_NUM) { + scr_dyn_prop_type_fail("options.saltLength", "of type number", salt); + return false; + } + double x = salt->v.num; + bool integer = isfinite(x) && trunc(x) == x; + if (!integer || x < 0 || x > 2147483647.0) { + ScrStr *received = sp_received(salt, true); + scr_pki_throw_fmt(SCR_ERR_RANGE, "ERR_OUT_OF_RANGE", + "The value of \"options.saltLength\" is out of range. It must be %s. Received %.*s", + integer ? ">= 0 && <= 2147483647" : "an integer", (int)received->len, received->data); + scr_str_release(received); + return false; + } + gen->salt_set = true; + gen->salt = (int)x; + } + if (!sp_absent(hash_alg) && hash_alg->kind != SCR_DYN_STR) { + scr_dyn_prop_type_fail("options.hashAlgorithm", "of type string", hash_alg); + return false; + } + if (!sp_absent(mgf1_alg) && mgf1_alg->kind != SCR_DYN_STR) { + scr_dyn_prop_type_fail("options.mgf1HashAlgorithm", "of type string", mgf1_alg); + return false; + } + const struct { + const ScrDyn *value, *preferred; + const char *name, *preferred_name; + } deprecated[] = { + {hash, hash_alg, "options.hash", "options.hashAlgorithm"}, + {mgf1_hash, mgf1_alg, "options.mgf1Hash", "options.mgf1HashAlgorithm"}, + }; + for (size_t i = 0; i < 2; i++) { + if (sp_absent(deprecated[i].value)) continue; + ScrJsonBuf text; + scr_jb_init(&text); + scr_jb_puts(&text, "\""); + scr_jb_puts(&text, deprecated[i].name); + scr_jb_puts(&text, "\" is deprecated, use \""); + scr_jb_puts(&text, deprecated[i].preferred_name); + scr_jb_puts(&text, "\" instead."); + /* process.emitWarning: reported on the next tick, dropped under + * process.noDeprecation, and thrown from its own tick under + * process.throwDeprecation. */ + ScrStr *message = scr_jb_finish(&text); + ScrStr *code = scr_str_new("DEP0154", 7); + ScrDyn *warning = scr_warning_new(message, "DeprecationWarning", code); + scr_str_release(code); + scr_str_release(message); + scr_warning_emit_deferred(warning); + scr_dyn_release(warning); + if (deprecated[i].value->kind != SCR_DYN_STR) { + scr_dyn_prop_type_fail(deprecated[i].name, "of type string", deprecated[i].value); + return false; + } + const ScrDyn *preferred = deprecated[i].preferred; + if (preferred->kind == SCR_DYN_STR && preferred->v.str->len > 0 && + !scr_str_eq(preferred->v.str, deprecated[i].value->v.str)) { + sp_property_invalid(deprecated[i].name, deprecated[i].value); + return false; + } + } + /* `hashAlgorithm || hash`: an empty string reads as absent. */ + const ScrDyn *md = hash_alg->kind == SCR_DYN_STR && hash_alg->v.str->len > 0 ? hash_alg : hash; + const ScrDyn *mgf1 = mgf1_alg->kind == SCR_DYN_STR && mgf1_alg->v.str->len > 0 ? mgf1_alg : mgf1_hash; + if (md->kind == SCR_DYN_STR) { + if (!sp_pss_digest(md, false, &gen->md)) return false; + gen->md_set = true; + } + if (mgf1->kind == SCR_DYN_STR) { + if (!sp_pss_digest(mgf1, true, &gen->mgf1)) return false; + gen->mgf1_set = true; + } + /* OpenSSL's defaults: MGF1 over the digest and a salt of the digest's + * length once a digest is given, SHA-1 and 20 otherwise. */ + gen->pss_params = gen->md_set || gen->mgf1_set || gen->salt_set; + if (!gen->md_set) gen->md = MBEDTLS_MD_SHA1; + if (!gen->mgf1_set) gen->mgf1 = gen->md; + if (!gen->salt_set) gen->salt = gen->md_set ? (int)mbedtls_md_get_size(mbedtls_md_info_from_type(gen->md)) : 20; + return true; +} + /* createJob's checks for generateKeyPair(Sync)(type, options) in Node's * order: the type, the options object, the public and private key * encodings, then the options of the type. False with the error pending. @@ -1677,7 +2761,8 @@ static bool sp_keygen_check(const ScrDyn *type, const ScrDyn *options, SpKeyGen if (!sp_absent(exponent) && exponent->kind != SCR_DYN_NULL && !sp_check_uint32(exponent, "options.publicExponent", &gen->exponent)) return false; - if (pss && !refusal) refusal = "generateKeyPairSync for this key type"; + gen->pss = pss; + if (pss && !sp_pss_keygen_options(options, gen)) return false; } else if (sp_is_str(type, "dsa") || sp_is_str(type, "dh")) { if (!sp_check_object(options, "options")) return false; if (!refusal) refusal = "generateKeyPairSync for this key type"; @@ -1723,6 +2808,23 @@ static bool sp_keygen_check(const ScrDyn *type, const ScrDyn *options, SpKeyGen } if (!refusal) refusal = "generateKeyPairSync for this key type"; } + /* The job's private key cipher, which Node looks up once the options + * of the type are read. */ + { + const ScrDyn *enc = sp_opt(options, "privateKeyEncoding"); + const ScrDyn *cipher = sp_is_object(enc) ? sp_opt(enc, "cipher") : scr_dyn_undefined(); + const SpKeyCipher *ci; + if (cipher->kind == SCR_DYN_STR) { + if (!sp_key_cipher(cipher->v.str, &ci)) return false; + /* OpenSSL's errors for the cipher come from the export once the + * key is generated; a cipher it encrypts with and keys here do not + * is refused first. */ + bool pkcs8 = sp_is_str(sp_opt(enc, "type"), "pkcs8"); + if (ci->type == MBEDTLS_CIPHER_NONE && (pkcs8 ? ci->pkcs8_error : ci->traditional_error) == SP_KC_OK && + !refusal) + refusal = "private keys encrypted with this cipher"; + } + } if (refusal) { sp_not_supported(refusal); return false; @@ -1730,6 +2832,54 @@ static bool sp_keygen_check(const ScrDyn *type, const ScrDyn *options, SpKeyGen return gen->kind != SP_GEN_ED25519 || sp_ed() != NULL; } +/* An RSA key of `bits` bits with public exponent `exponent`, within + * OpenSSL's limits rather than mbedtls_rsa_gen_key's (even lengths from + * 1024 bits, exponents up to INT_MAX): any length from 512 bits and odd + * exponents up to 2^32 - 1. From 2048 bits OpenSSL generates two primes + * of equal length (SP 800-56B), so an odd length yields one bit less. + * The primes have (bits + 1) / 2 and bits / 2 bits, each with its top + * bits set (mbedtls_mpi_gen_prime's FIPS 186-4 bound), so their product + * has exactly `bits` bits; each prime minus one is coprime to the + * exponent. 0 on success. */ +static int sp_rsa_generate(mbedtls_rsa_context *rsa, unsigned bits, uint64_t exponent) { + if (bits >= 2048) bits &= ~1u; + mbedtls_mpi P, Q, E, N, T, G; + mbedtls_mpi_init(&P); + mbedtls_mpi_init(&Q); + mbedtls_mpi_init(&E); + mbedtls_mpi_init(&N); + mbedtls_mpi_init(&T); + mbedtls_mpi_init(&G); + unsigned char e_bytes[8]; + for (int i = 0; i < 8; i++) e_bytes[i] = (unsigned char)(exponent >> (56 - 8 * i)); + int r = mbedtls_mpi_read_binary(&E, e_bytes, sizeof e_bytes); + const int flags = MBEDTLS_MPI_GEN_PRIME_FLAG_LOW_ERR; + while (r == 0) { + r = mbedtls_mpi_gen_prime(&P, (bits + 1) / 2, flags, sp_random, NULL); + if (r == 0) r = mbedtls_mpi_sub_int(&T, &P, 1); + if (r == 0) r = mbedtls_mpi_gcd(&G, &E, &T); + if (r != 0 || mbedtls_mpi_cmp_int(&G, 1) != 0) continue; + r = mbedtls_mpi_gen_prime(&Q, bits / 2, flags, sp_random, NULL); + if (r == 0) r = mbedtls_mpi_sub_int(&T, &Q, 1); + if (r == 0) r = mbedtls_mpi_gcd(&G, &E, &T); + if (r != 0 || mbedtls_mpi_cmp_int(&G, 1) != 0 || mbedtls_mpi_cmp_mpi(&P, &Q) == 0) continue; + r = mbedtls_mpi_mul_mpi(&N, &P, &Q); + if (r == 0 && mbedtls_mpi_bitlen(&N) == bits) break; + } + /* The larger prime is p, as OpenSSL orders them. */ + if (r == 0 && mbedtls_mpi_cmp_mpi(&P, &Q) < 0) mbedtls_mpi_swap(&P, &Q); + if (r == 0) r = mbedtls_rsa_import(rsa, &N, &P, &Q, NULL, &E); + if (r == 0) r = mbedtls_rsa_complete(rsa); + if (r == 0) r = mbedtls_rsa_check_privkey(rsa); + mbedtls_mpi_free(&P); + mbedtls_mpi_free(&Q); + mbedtls_mpi_free(&E); + mbedtls_mpi_free(&N); + mbedtls_mpi_free(&T); + mbedtls_mpi_free(&G); + return r; +} + /* OpenSSL's error for an RSA modulus length or public exponent it does not * generate, as Node reports it, or NULL. */ static const char *sp_rsa_keygen_failure(double bits, double exponent) { @@ -1773,16 +2923,22 @@ static SpKey *sp_keygen_run(const SpKeyGen *gen, bool *job_error) { scr_pki_throw_fmt(SCR_ERR_ERROR, NULL, "%s", failure); return NULL; } - /* mbedTLS generates even modulus lengths from 1024 to 8192 bits and, - * past the checks above, odd exponents up to INT_MAX. */ + /* Moduli past mbedTLS's 8192-bit numbers stay unsupported (OpenSSL + * generates up to 16384 bits). */ double b = gen->bits, e = gen->exponent; - if (b < MBEDTLS_RSA_GEN_KEY_MIN_BITS || b > MBEDTLS_MPI_MAX_BITS || fmod(b, 2) != 0 || e > 2147483647.0 || - mbedtls_pk_setup(&k->pk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) != 0 || - mbedtls_rsa_gen_key(mbedtls_pk_rsa(k->pk), sp_random, NULL, (unsigned)b, (int)e) != 0) { + if (b > MBEDTLS_MPI_MAX_BITS || mbedtls_pk_setup(&k->pk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) != 0 || + sp_rsa_generate(mbedtls_pk_rsa(k->pk), (unsigned)b, (uint64_t)e) != 0) { sp_key_release(k); sp_not_supported("generateKeyPairSync with this RSA modulus length or exponent"); return NULL; } + if (gen->pss) { + k->rsa_pss = true; + k->pss_params = gen->pss_params; + k->pss_md = gen->md; + k->pss_mgf1 = gen->mgf1; + k->pss_salt = gen->salt; + } return k; } if (mbedtls_pk_setup(&k->pk, mbedtls_pk_info_from_type(MBEDTLS_PK_ECKEY)) != 0 || @@ -1799,7 +2955,7 @@ static SpKey *sp_keygen_run(const SpKeyGen *gen, bool *job_error) { * pending, and *job_error as sp_keygen_run sets it. */ static ScrDyn *sp_key_pair(const ScrDyn *type, const ScrDyn *options, bool *job_error) { *job_error = false; - SpKeyGen gen; + SpKeyGen gen = {0}; if (!sp_keygen_check(type, options, &gen)) return NULL; SpKey *k = sp_keygen_run(&gen, job_error); if (!k) return NULL; @@ -1910,8 +3066,11 @@ static bool sp_algorithm(const ScrDyn *alg, mbedtls_md_type_t *md) { typedef struct { SpKey *key; /* +1 */ int padding; /* RSA_PKCS1_PADDING (1) or RSA_PKCS1_PSS_PADDING (6) */ - int salt; /* -1 digest length, -2 maximum (sign) or auto (verify) */ + int salt; /* -1 digest length, -2 maximum (sign) or auto (verify), + * -4 the digest length or the maximum, if smaller */ bool p1363; /* dsaEncoding: "ieee-p1363" */ + bool padding_given, salt_given; + mbedtls_md_type_t mgf1; /* PSS's MGF1 digest; NONE for the message's */ } SpSigKey; /* The key argument of a signing operation: a KeyObject, key material, or @@ -1932,6 +3091,9 @@ static bool sp_sig_key_plain(const ScrDyn *value, bool sign, SpSigKey *out) { out->padding = 1; out->salt = sign ? -2 : -2; out->p1363 = false; + out->padding_given = false; + out->salt_given = false; + out->mgf1 = MBEDTLS_MD_NONE; const ScrDyn *options = NULL; if (sp_is_object(value) && !sp_key_of(value) && !scr_buffer_storage_is(value)) { options = value; @@ -1948,6 +3110,7 @@ static bool sp_sig_key_plain(const ScrDyn *value, bool sign, SpSigKey *out) { return false; } out->padding = (int)padding->v.num; + out->padding_given = true; } const ScrDyn *salt = sp_opt(value, "saltLength"); if (!sp_absent(salt)) { @@ -1956,6 +3119,7 @@ static bool sp_sig_key_plain(const ScrDyn *value, bool sign, SpSigKey *out) { return false; } out->salt = (int)salt->v.num; + out->salt_given = true; } } SpKey *direct = sp_key_of(options ? sp_opt(options, "key") : value); @@ -2022,6 +3186,40 @@ static int sp_p1363_to_der(const unsigned char *sig, size_t len, unsigned char * static size_t sp_ec_size(SpKey *k) { return (mbedtls_pk_ec(k->pk)->MBEDTLS_PRIVATE(grp).nbits + 7) / 8; } +/* An RSA-PSS key's restrictions on a signature over a `md` digest, as + * OpenSSL's provider applies them: PSS padding only (the default), and + * for a key with RSASSA-PSS-params its digest, its MGF1 digest and salts + * of at least its own (the default). Without parameters a signature + * salts with the digest's length, or the most the key holds when that is + * less (RSA_PSS_SALTLEN_AUTO_DIGEST_MAX). False with OpenSSL's error + * pending. */ +static bool sp_pss_key_rules(SpSigKey *key, mbedtls_md_type_t md, size_t hash_len, bool sign) { + const SpKey *k = key->key; + if (!k->rsa_pss) return true; + if (key->padding_given && key->padding != 6) { + sp_throw_openssl("1C8000A5", "Provider routines", "illegal or unsupported padding mode", + "ERR_OSSL_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE", true); + return false; + } + key->padding = 6; + if (!k->pss_params) { + if (!key->salt_given) key->salt = sign ? -4 : -2; + return true; + } + if (md != k->pss_md) { + sp_throw_openssl("1C8000AE", "Provider routines", "digest not allowed", "ERR_OSSL_DIGEST_NOT_ALLOWED", true); + return false; + } + key->mgf1 = k->pss_mgf1; + if (!key->salt_given) { + key->salt = k->pss_salt; + } else if (key->salt != -2 && (key->salt == -1 ? (int)hash_len : key->salt) < k->pss_salt) { + sp_throw_openssl("1C8000AC", "Provider routines", "pss saltlen too small", "ERR_OSSL_PSS_SALTLEN_TOO_SMALL", true); + return false; + } + return true; +} + /* Applies the RSA padding of a signature operation. */ static bool sp_rsa_padding(SpSigKey *key, mbedtls_md_type_t md) { if (!sp_is_rsa(key->key)) return true; @@ -2030,11 +3228,119 @@ static bool sp_rsa_padding(SpSigKey *key, mbedtls_md_type_t md) { return mbedtls_rsa_set_padding(rsa, MBEDTLS_RSA_PKCS_V15, MBEDTLS_MD_NONE) == 0; } +/* MGF1 over `mgf1` (RFC 8017 B.2.1), XORed into mask[0, len). */ +static int sp_mgf1_xor(mbedtls_md_type_t mgf1, const unsigned char *seed, size_t seed_len, unsigned char *mask, + size_t len) { + const mbedtls_md_info_t *info = mbedtls_md_info_from_type(mgf1); + size_t h = mbedtls_md_get_size(info); + unsigned char block[MBEDTLS_MD_MAX_SIZE]; + mbedtls_md_context_t ctx; + mbedtls_md_init(&ctx); + int r = mbedtls_md_setup(&ctx, info, 0); + for (uint32_t counter = 0; r == 0 && (size_t)counter * h < len; counter++) { + unsigned char c[4] = {(unsigned char)(counter >> 24), (unsigned char)(counter >> 16), + (unsigned char)(counter >> 8), (unsigned char)counter}; + if ((r = mbedtls_md_starts(&ctx)) == 0 && (r = mbedtls_md_update(&ctx, seed, seed_len)) == 0 && + (r = mbedtls_md_update(&ctx, c, 4)) == 0 && (r = mbedtls_md_finish(&ctx, block)) == 0) { + for (size_t i = 0; i < h && (size_t)counter * h + i < len; i++) mask[(size_t)counter * h + i] ^= block[i]; + } + } + mbedtls_md_free(&ctx); + mbedtls_platform_zeroize(block, sizeof block); + return r; +} + +/* An RSASSA-PSS signature whose MGF1 digest differs from the message's + * (RFC 8017 9.1.1 and 8.1.1), which mbedtls_rsa_rsassa_pss_sign_ext + * cannot make: the encoding here, then the private-key operation. */ +static int sp_pss_sign_mgf1(mbedtls_rsa_context *rsa, mbedtls_md_type_t md, mbedtls_md_type_t mgf1, + const unsigned char *hash, size_t hash_len, int salt_len, unsigned char *sig) { + size_t bytes = mbedtls_rsa_get_len(rsa); + size_t em_bits = mbedtls_rsa_get_bitlen(rsa) - 1; + size_t em_len = (em_bits + 7) / 8; + size_t salt = (size_t)salt_len; + if (em_len < hash_len + salt + 2) return MBEDTLS_ERR_RSA_BAD_INPUT_DATA; + unsigned char em[MBEDTLS_MPI_MAX_SIZE] = {0}; + unsigned char *db = em, *h = em + em_len - hash_len - 1; + size_t db_len = em_len - hash_len - 1; + unsigned char salt_bytes[MBEDTLS_MPI_MAX_SIZE]; + int r = sp_random(NULL, salt_bytes, salt); + /* H = Hash(0x00 * 8 || mHash || salt) */ + mbedtls_md_context_t ctx; + mbedtls_md_init(&ctx); + static const unsigned char zeros[8] = {0}; + if (r == 0 && (r = mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md), 0)) == 0 && + (r = mbedtls_md_starts(&ctx)) == 0 && (r = mbedtls_md_update(&ctx, zeros, 8)) == 0 && + (r = mbedtls_md_update(&ctx, hash, hash_len)) == 0 && (r = mbedtls_md_update(&ctx, salt_bytes, salt)) == 0) + r = mbedtls_md_finish(&ctx, h); + mbedtls_md_free(&ctx); + if (r == 0) { + /* DB = PS || 0x01 || salt, masked with MGF1(H). */ + db[db_len - salt - 1] = 0x01; + memcpy(db + db_len - salt, salt_bytes, salt); + r = sp_mgf1_xor(mgf1, h, hash_len, db, db_len); + } + if (r == 0) { + db[0] &= (unsigned char)(0xff >> (8 * em_len - em_bits)); + em[em_len - 1] = 0xbc; + unsigned char block[MBEDTLS_MPI_MAX_SIZE] = {0}; + memcpy(block + bytes - em_len, em, em_len); + r = mbedtls_rsa_private(rsa, sp_random, NULL, block, sig); + mbedtls_platform_zeroize(block, sizeof block); + } + mbedtls_platform_zeroize(em, sizeof em); + mbedtls_platform_zeroize(salt_bytes, sizeof salt_bytes); + return r; +} + +/* Verifies an RSASSA-PSS signature whose MGF1 digest differs from the + * message's (RFC 8017 9.1.2), which mbedtls_rsa_rsassa_pss_verify_ext + * cannot: it hashes M' with the MGF1 digest too. `salt_len` -2 accepts any + * salt length. */ +static bool sp_pss_verify_mgf1(mbedtls_rsa_context *rsa, mbedtls_md_type_t md, mbedtls_md_type_t mgf1, + const unsigned char *hash, size_t hash_len, int salt_len, + const unsigned char *sig, size_t sig_len) { + size_t bytes = mbedtls_rsa_get_len(rsa); + if (sig_len != bytes) return false; + unsigned char decoded[MBEDTLS_MPI_MAX_SIZE]; + if (mbedtls_rsa_public(rsa, sig, decoded) != 0) return false; + size_t em_bits = mbedtls_rsa_get_bitlen(rsa) - 1; + size_t em_len = (em_bits + 7) / 8; + if (bytes > em_len && decoded[0] != 0) return false; + unsigned char *em = decoded + (bytes - em_len); + if (em_len < hash_len + 2 || em[em_len - 1] != 0xbc) return false; + size_t db_len = em_len - hash_len - 1; + unsigned char *h = em + db_len; + unsigned char top = (unsigned char)(0xff >> (8 * em_len - em_bits)); + if (em[0] & (unsigned char)~top) return false; + unsigned char db[MBEDTLS_MPI_MAX_SIZE]; + memcpy(db, em, db_len); + if (sp_mgf1_xor(mgf1, h, hash_len, db, db_len) != 0) return false; + db[0] &= top; + size_t i = 0; + while (i < db_len && db[i] == 0) i++; + if (i == db_len || db[i] != 0x01) return false; + size_t salt = db_len - i - 1; + if (salt_len >= 0 && salt != (size_t)salt_len) return false; + static const unsigned char zeros[8] = {0}; + unsigned char check[MBEDTLS_MD_MAX_SIZE]; + mbedtls_md_context_t ctx; + mbedtls_md_init(&ctx); + int r; + if ((r = mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md), 0)) == 0 && (r = mbedtls_md_starts(&ctx)) == 0 && + (r = mbedtls_md_update(&ctx, zeros, 8)) == 0 && (r = mbedtls_md_update(&ctx, hash, hash_len)) == 0 && + (r = mbedtls_md_update(&ctx, db + i + 1, salt)) == 0) + r = mbedtls_md_finish(&ctx, check); + mbedtls_md_free(&ctx); + return r == 0 && memcmp(check, h, hash_len) == 0; +} + /* Signs a digest: +1 Buffer or NULL with the error pending. */ static ScrDyn *sp_sign_hash(SpSigKey *key, mbedtls_md_type_t md, const unsigned char *hash, size_t hash_len) { unsigned char sig[MBEDTLS_PK_SIGNATURE_MAX_SIZE]; size_t sig_len = 0; int r; + if (!sp_pss_key_rules(key, md, hash_len, true)) return NULL; if (!sp_rsa_padding(key, md)) { sp_unsupported_input(); return NULL; @@ -2047,12 +3353,15 @@ static ScrDyn *sp_sign_hash(SpSigKey *key, mbedtls_md_type_t md, const unsigned size_t max = bytes - hash_len - 2 - ((bits - 1) % 8 == 0 ? 1 : 0); if (salt == -1) salt = (int)hash_len; else if (salt == -2) salt = (int)max; + else if (salt == -4) salt = (int)(hash_len < max ? hash_len : max); if (salt < 0 || (size_t)salt > max) { sp_throw(SCR_ERR_ERROR, "ERR_OSSL_RSA_DATA_TOO_LARGE_FOR_KEY_SIZE", "error:1C8000A5:Provider routines::data too large for key size"); return NULL; } - r = mbedtls_rsa_rsassa_pss_sign_ext(rsa, sp_random, NULL, md, (unsigned)hash_len, hash, salt, sig); + r = key->mgf1 != MBEDTLS_MD_NONE && key->mgf1 != md + ? sp_pss_sign_mgf1(rsa, md, key->mgf1, hash, hash_len, salt, sig) + : mbedtls_rsa_rsassa_pss_sign_ext(rsa, sp_random, NULL, md, (unsigned)hash_len, hash, salt, sig); sig_len = bytes; } else { r = mbedtls_pk_sign(&key->key->pk, md, hash, hash_len, sig, sizeof sig, &sig_len, sp_random, NULL); @@ -2077,6 +3386,7 @@ static ScrDyn *sp_sign_hash(SpSigKey *key, mbedtls_md_type_t md, const unsigned * not verify or does not parse. */ static bool sp_verify_hash(SpSigKey *key, mbedtls_md_type_t md, const unsigned char *hash, size_t hash_len, const unsigned char *sig, size_t sig_len) { + if (!sp_pss_key_rules(key, md, hash_len, false)) return false; if (!sp_rsa_padding(key, md)) return false; if (sp_is_rsa(key->key) && key->padding == 6) { mbedtls_rsa_context *rsa = mbedtls_pk_rsa(key->key->pk); @@ -2084,6 +3394,9 @@ static bool sp_verify_hash(SpSigKey *key, mbedtls_md_type_t md, const unsigned c int salt = key->salt; if (salt == -1) salt = (int)hash_len; else if (salt == -2) salt = MBEDTLS_RSA_SALT_LEN_ANY; + if (key->mgf1 != MBEDTLS_MD_NONE && key->mgf1 != md) + return sp_pss_verify_mgf1(rsa, md, key->mgf1, hash, hash_len, salt == MBEDTLS_RSA_SALT_LEN_ANY ? -2 : salt, + sig, sig_len); return mbedtls_rsa_rsassa_pss_verify_ext(rsa, md, (unsigned)hash_len, hash, md, salt, sig) == 0; } if (sp_is_ec(key->key) && key->p1363) { @@ -2127,6 +3440,9 @@ ScrDyn *scr_crypto_sign_oneshot(ScrDyn *algorithm, ScrDyn *data, ScrDyn *key) { SpSigKey k; if (!sp_sig_key(key, true, &k)) return NULL; if (sp_reject_x25519(&k)) return NULL; + /* A null algorithm signs with an RSA-PSS key's own digest. */ + if ((algorithm->kind == SCR_DYN_UNDEF || algorithm->kind == SCR_DYN_NULL) && k.key->pss_params) + md = k.key->pss_md; ScrBytes *bytes = scr_bytes_buffer_source(data); if (sp_is_ed(k.key)) { ScrDyn *result = NULL; @@ -2165,6 +3481,8 @@ ScrDyn *scr_crypto_verify_oneshot(ScrDyn *algorithm, ScrDyn *data, ScrDyn *key, return NULL; } if (sp_reject_x25519(&k)) return NULL; + if ((algorithm->kind == SCR_DYN_UNDEF || algorithm->kind == SCR_DYN_NULL) && k.key->pss_params) + md = k.key->pss_md; ScrBytes *bytes = scr_bytes_buffer_source(data); ScrBytes *sig = scr_bytes_buffer_source(signature); if (sp_is_ed(k.key)) { @@ -2186,7 +3504,7 @@ ScrDyn *scr_crypto_verify_oneshot(ScrDyn *algorithm, ScrDyn *data, ScrDyn *key, scr_bytes_release(bytes); scr_bytes_release(sig); sp_key_release(k.key); - return scr_dyn_new_bool(ok); + return scr_exc_pending() ? NULL : scr_dyn_new_bool(ok); } /* ── Sign and Verify objects ──────────────────────────────────────────── */ @@ -2305,7 +3623,7 @@ static ScrDyn *sp_signer_invoke(void *h, ScrDyn *self, const char *method, ScrDy sig->data, (size_t)scr_bytes_byte_len(sig)); scr_bytes_release(sig); sp_key_release(k.key); - return scr_dyn_new_bool(ok); + return scr_exc_pending() ? NULL : scr_dyn_new_bool(ok); } scr_pki_throw_fmt(SCR_ERR_TYPE, NULL, "%s is not a function", what); return NULL; @@ -2466,7 +3784,11 @@ static const char sp_dh_public_types[] = /* Node's message names: a KeyObject's asymmetricKeyType. */ static const char *sp_type_name(const SpKey *k) { - return sp_is_ed(k) ? "ed25519" : sp_is_x(k) ? "x25519" : sp_is_rsa(k) ? "rsa" : "ec"; + return sp_is_ed(k) ? "ed25519" + : sp_is_x(k) ? "x25519" + : k->rsa_pss ? "rsa-pss" + : sp_is_rsa(k) ? "rsa" + : "ec"; } /* A key input of diffieHellman's options: a primitive other than a string @@ -2683,8 +4005,9 @@ ScrPkiKey *scr_pki_key_public_of(ScrPkiKey *key) { return sp_public_of(key); } ScrPkiKey *scr_pki_generate_rsa(unsigned bits, uint64_t exponent) { SpKey *k = sp_key_alloc(true); - if (exponent > 2147483647 || mbedtls_pk_setup(&k->pk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) != 0 || - mbedtls_rsa_gen_key(mbedtls_pk_rsa(k->pk), sp_random, NULL, bits, (int)exponent) != 0) { + if (bits < 512 || bits > MBEDTLS_MPI_MAX_BITS || exponent < 3 || exponent % 2 == 0 || + exponent > 4294967295u || mbedtls_pk_setup(&k->pk, mbedtls_pk_info_from_type(MBEDTLS_PK_RSA)) != 0 || + sp_rsa_generate(mbedtls_pk_rsa(k->pk), bits, exponent) != 0) { sp_key_release(k); return NULL; } diff --git a/packages/runtime/src/scr_webcrypto_pki.c b/packages/runtime/src/scr_webcrypto_pki.c index 7439a12db..458cfeae8 100644 --- a/packages/runtime/src/scr_webcrypto_pki.c +++ b/packages/runtime/src/scr_webcrypto_pki.c @@ -380,7 +380,8 @@ static ScrPromise *sw_generate_key(const ScrDyn *args) { scr_throw_domex("OperationError", "algorithm.publicExponent must be odd"); goto done; } - if (bits > 16384 || value < 3) { + /* The pki unit's numbers hold moduli up to 8192 bits. */ + if (bits > 8192 || value < 3) { scr_wc_unsupported("generateKey", "this RSA modulus length or public exponent"); goto done; } diff --git a/tests/corpus/8165-rsa-keygen-lengths.cjs b/tests/corpus/8165-rsa-keygen-lengths.cjs new file mode 100644 index 000000000..35e2cb28f --- /dev/null +++ b/tests/corpus/8165-rsa-keygen-lengths.cjs @@ -0,0 +1,40 @@ +// RSA key generation within OpenSSL's limits: any modulus length from +// 512 bits (an odd length from 2048 bits yields one bit less, as +// OpenSSL's SP 800-56B generation does) and odd exponents up to 2^32 - 1. +"use strict"; +const crypto = require("crypto"); + +const cases = [ + [512, 65537], + [513, 65537], + [1023, 3], + [1024, 0x10001], + [2049, 65537], + [768, 4294967295], + [520, 17], +]; +for (const [modulusLength, publicExponent] of cases) { + const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", { modulusLength, publicExponent }); + const details = privateKey.asymmetricKeyDetails; + const data = Buffer.from("rsa key lengths"); + const signature = crypto.sign("sha256", data, privateKey); + console.log( + modulusLength, + details.modulusLength, + details.publicExponent, + publicKey.asymmetricKeyDetails.modulusLength, + signature.length, + crypto.verify("sha256", data, publicKey, signature), + ); +} +for (const [modulusLength, publicExponent] of [[511, 65537], [1024, 1], [1024, 4], [1024, 0]]) { + try { + crypto.generateKeyPairSync("rsa", { modulusLength, publicExponent }); + console.log(modulusLength, publicExponent, "generated"); + } catch (error) { + console.log(modulusLength, publicExponent, error.message); + } +} +crypto.generateKeyPair("rsa", { modulusLength: 515, publicExponent: 3 }, (error, publicKey) => { + console.log("async", error, publicKey.asymmetricKeyDetails.modulusLength); +}); diff --git a/tests/corpus/8166-rsa-pss-keys.cjs b/tests/corpus/8166-rsa-pss-keys.cjs new file mode 100644 index 000000000..aad90f6aa --- /dev/null +++ b/tests/corpus/8166-rsa-pss-keys.cjs @@ -0,0 +1,104 @@ +// RSA-PSS keys (id-RSASSA-PSS): generation with and without +// RSASSA-PSS-params, their details, SubjectPublicKeyInfo and PKCS#8 in +// OpenSSL's encoding, import of both, and the restrictions on signatures: +// PSS padding only, the key's digest and MGF1 digest, and at least its +// salt length. The deprecated hash and mgf1Hash options run in a child +// process, whose DEP0154 reports are printed with process ids normalized. +"use strict"; +const { spawnSync } = require("child_process"); +const c = require("crypto"); +const fmt = (v) => JSON.stringify(v, (k, x) => (typeof x === "bigint" ? `${x}n` : x)); +const tryIt = (label, fn) => { + try { + const r = fn(); + console.log(label, typeof r === "string" ? r.split("\n")[0] : Buffer.isBuffer(r) ? `buffer ${r.length > 0}` : fmt(r)); + } catch (e) { + console.log(label, e.name, e.code, e.message); + } +}; +const algOf = (spki) => { + // The AlgorithmIdentifier: the SEQUENCE after the outer header. + const start = spki[1] & 0x80 ? 2 + (spki[1] & 0x7f) : 2; + const len = spki[start + 1]; + return spki.subarray(start, start + 2 + len).toString("hex"); +}; +const report = (label, options) => tryIt(label, () => c.generateKeyPairSync("rsa-pss", { modulusLength: 512, ...options }).publicKey.asymmetricKeyDetails); + +function main() { + const cases = { + none: {}, + sha256: { hashAlgorithm: "sha256" }, + full: { hashAlgorithm: "sha256", mgf1HashAlgorithm: "sha384", saltLength: 16 }, + sha1: { hashAlgorithm: "sha1" }, + salt: { saltLength: 10 }, + s512: { hashAlgorithm: "sha512", saltLength: 0 }, + mgf: { mgf1HashAlgorithm: "sha256" }, + }; + for (const [name, options] of Object.entries(cases)) { + const { publicKey, privateKey } = c.generateKeyPairSync("rsa-pss", { modulusLength: ["full", "sha1", "salt", "mgf"].includes(name) ? 512 : 1024, ...options }); + const spki = publicKey.export({ format: "der", type: "spki" }); + const pkcs8 = privateKey.export({ format: "der", type: "pkcs8" }); + console.log(name, publicKey.asymmetricKeyType, fmt(publicKey.asymmetricKeyDetails), fmt(privateKey.asymmetricKeyDetails)); + console.log(name, "spki alg", algOf(spki), "pkcs8 alg", pkcs8.indexOf(Buffer.from(algOf(spki), "hex")) > 0); + tryIt(`${name} pkcs1`, () => privateKey.export({ format: "pem", type: "pkcs1" })); + tryIt(`${name} jwk`, () => publicKey.export({ format: "jwk" })); + tryIt(`${name} pem`, () => privateKey.export({ format: "pem", type: "pkcs8" })); + const reimported = c.createPublicKey(publicKey.export({ format: "pem", type: "spki" })); + const fromPrivate = c.createPublicKey(privateKey.export({ format: "pem", type: "pkcs8" })); + const privateAgain = c.createPrivateKey({ key: pkcs8, format: "der", type: "pkcs8" }); + console.log(name, reimported.equals(publicKey), fromPrivate.equals(publicKey), privateAgain.asymmetricKeyType); + const data = Buffer.from("rsa-pss"); + const signature = c.sign(null, data, privateAgain); + console.log(name, c.verify(null, data, publicKey, signature), c.verify(null, data, reimported, signature)); + } + + const data = Buffer.from("restricted"); + const { publicKey, privateKey } = c.generateKeyPairSync("rsa-pss", { + modulusLength: 512, + hashAlgorithm: "sha256", + saltLength: 16, + }); + tryIt("sign sha1", () => c.sign("sha1", data, privateKey)); + tryIt("sign pkcs1", () => c.sign("sha256", data, { key: privateKey, padding: c.constants.RSA_PKCS1_PADDING })); + tryIt("sign salt 8", () => c.sign("sha256", data, { key: privateKey, saltLength: 8 })); + tryIt("verify salt 8", () => c.verify("sha256", data, { key: publicKey, saltLength: 8 }, Buffer.alloc(64))); + for (const saltLength of [16, 20, 30]) { + const signature = c.sign("sha256", data, { key: privateKey, saltLength }); + console.log( + saltLength, + c.verify("sha256", data, publicKey, signature), + c.verify("sha256", data, { key: publicKey, saltLength: c.constants.RSA_PSS_SALTLEN_AUTO }, signature), + ); + } + const signer = c.createSign("sha256").update(data); + console.log("createVerify", c.createVerify("sha256").update(data).verify(publicKey, signer.sign(privateKey))); + const free = c.generateKeyPairSync("rsa-pss", { modulusLength: 1024 }); + const freeSignature = c.sign("sha512", data, free.privateKey); + console.log("free sha512", c.verify("sha512", data, free.publicKey, freeSignature)); + + report("bad digest", { hashAlgorithm: "nope" }); + report("bad mgf1", { mgf1HashAlgorithm: "nope" }); + report("negative salt", { saltLength: -1 }); + report("upper", { hashAlgorithm: "SHA256" }); + report("alias", { hashAlgorithm: "RSA-SHA256" }); +} + +if (process.argv[2] === "deprecated") { + report("hash", { hash: "sha256" }); + report("conflict", { hashAlgorithm: "sha256", hash: "sha1" }); + report("mgf1Hash", { hashAlgorithm: "sha256", mgf1Hash: "sha384" }); + report("hash type", { hash: 5 }); + // Node drops deprecations while noDeprecation is set when it reports + // them, so the flag is set once the reports above are out. + setTimeout(() => { + process.noDeprecation = true; + report("quiet", { hash: "sha512" }); + console.log("end of turn"); + }); +} else { + main(); + const child = spawnSync(process.execPath, [process.argv[1], "deprecated"], { encoding: "utf8" }); + console.log(`status: ${child.status}`); + console.log(child.stdout); + console.log(child.stderr.replace(/\(node:\d+\)/g, "(node:)")); +} diff --git a/tests/corpus/8167-encrypted-private-keys.cjs b/tests/corpus/8167-encrypted-private-keys.cjs new file mode 100644 index 000000000..561a0aec3 --- /dev/null +++ b/tests/corpus/8167-encrypted-private-keys.cjs @@ -0,0 +1,114 @@ +// Encrypted private keys: PKCS#8 as PBES2 and PKCS#1 and SEC1 as +// traditional PEM with the CBC and ECB ciphers, import with a passphrase, +// generateKeyPair with a cipher, and OpenSSL's errors for missing and +// wrong passphrases, unknown ciphers, and ciphers a form refuses. +"use strict"; +const c = require("crypto"); +const show = (e) => + `${e.name} ${e.code} ${e.message}${e.library ? ` [${e.library}: ${e.reason}]` : ""}${ + e.opensslErrorStack ? ` ${JSON.stringify(e.opensslErrorStack)}` : "" + }`; +const tryIt = (label, fn) => { + try { + console.log(label, fn()); + } catch (e) { + console.log(label, show(e)); + } +}; +// The PEM label and headers, without the random IV. +const head = (pem) => + pem + .split("\n") + .filter((l) => l.startsWith("-----BEGIN") || l.includes(":")) + .map((l) => l.replace(/,[0-9A-F]+$/, "")) + .join(" | "); + +const ec = c.generateKeyPairSync("ec", { namedCurve: "P-256" }); +const rsa = c.generateKeyPairSync("rsa", { modulusLength: 1024 }); +const same = (key, pair) => c.createPublicKey(key).equals(pair.publicKey); + +for (const cipher of ["aes-128-cbc", "aes-192-cbc", "aes-256-cbc", "aes-128-ecb", "aes-256-ecb", "des-ede3-cbc", "aes256", "AES-128-CBC", "2.16.840.1.101.3.4.1.42"]) { + for (const format of ["pem", "der"]) { + tryIt(`pkcs8 ${format} ${cipher}`, () => { + const out = ec.privateKey.export({ type: "pkcs8", format, cipher, passphrase: "top secret" }); + const key = c.createPrivateKey({ key: out, format, type: format === "der" ? "pkcs8" : undefined, passphrase: "top secret" }); + return `${format === "pem" ? head(out) : Buffer.isBuffer(out)} ${key.asymmetricKeyType} ${same(key, ec)}`; + }); + } +} +for (const cipher of ["aes-128-cbc", "aes-256-cbc", "des-ede3-cbc", "des3"]) { + tryIt(`sec1 ${cipher}`, () => { + const out = ec.privateKey.export({ type: "sec1", format: "pem", cipher, passphrase: Buffer.from("pw") }); + return `${head(out)} ${same(c.createPrivateKey({ key: out, passphrase: "pw" }), ec)}`; + }); + tryIt(`pkcs1 ${cipher}`, () => { + const out = rsa.privateKey.export({ type: "pkcs1", format: "pem", cipher, passphrase: "pw" }); + return `${head(out)} ${same(c.createPrivateKey({ key: out, passphrase: Buffer.from("pw") }), rsa)}`; + }); +} +tryIt("empty passphrase", () => { + const out = rsa.privateKey.export({ type: "pkcs8", format: "pem", cipher: "aes-128-cbc", passphrase: "" }); + return same(c.createPrivateKey({ key: out, passphrase: "" }), rsa); +}); + +// Reading encrypted keys. +const p8pem = ec.privateKey.export({ type: "pkcs8", format: "pem", cipher: "aes-256-cbc", passphrase: "pw" }); +const p8der = ec.privateKey.export({ type: "pkcs8", format: "der", cipher: "aes-256-cbc", passphrase: "pw" }); +const sec1 = String(ec.privateKey.export({ type: "sec1", format: "pem", cipher: "aes-128-cbc", passphrase: "pw" })); +tryIt("public from encrypted", () => c.createPublicKey({ key: p8pem, passphrase: "pw" }).equals(ec.publicKey)); +tryIt("public from traditional", () => c.createPublicKey({ key: sec1, passphrase: "pw" }).type); +tryIt("pkcs8 pem no passphrase", () => c.createPrivateKey(p8pem)); +tryIt("pkcs8 der no passphrase", () => c.createPrivateKey({ key: p8der, format: "der", type: "pkcs8" })); +tryIt("sec1 no passphrase", () => c.createPrivateKey(sec1)); +tryIt("public no passphrase", () => c.createPublicKey(p8pem)); +tryIt("pkcs8 pem wrong", () => c.createPrivateKey({ key: p8pem, passphrase: "nope" })); +tryIt("pkcs8 der wrong", () => c.createPrivateKey({ key: p8der, format: "der", type: "pkcs8", passphrase: "nope" })); +tryIt("sec1 wrong", () => c.createPrivateKey({ key: sec1, passphrase: "nope" })); +tryIt("passphrase type", () => c.createPrivateKey({ key: p8pem, passphrase: 5 })); +tryIt("dek unknown", () => c.createPrivateKey({ key: sec1.replace(/DEK-Info: AES-128-CBC/, "DEK-Info: NOPE-CBC"), passphrase: "pw" })); +tryIt("dek legacy", () => + c.createPrivateKey({ key: sec1.replace(/DEK-Info: AES-128-CBC,([0-9A-F]{16})[0-9A-F]+/, "DEK-Info: DES-CBC,$1"), passphrase: "pw" }), +); +tryIt("dek legacy no passphrase", () => + c.createPrivateKey(sec1.replace(/DEK-Info: AES-128-CBC,([0-9A-F]{16})[0-9A-F]+/, "DEK-Info: DES-CBC,$1")), +); + +// Export options. +const opts = (extra) => ({ type: "pkcs8", format: "pem", ...extra }); +tryIt("unknown cipher", () => ec.privateKey.export(opts({ cipher: "nope", passphrase: "x" }))); +tryIt("cipher without passphrase", () => ec.privateKey.export(opts({ cipher: "aes-128-cbc" }))); +tryIt("passphrase without cipher", () => ec.privateKey.export(opts({ passphrase: "x" }))); +tryIt("cipher type", () => ec.privateKey.export(opts({ cipher: 5, passphrase: "x" }))); +tryIt("sec1 der", () => ec.privateKey.export({ type: "sec1", format: "der", cipher: "aes-128-cbc", passphrase: "x" })); +tryIt("pkcs1 der", () => rsa.privateKey.export({ type: "pkcs1", format: "der", cipher: "aes-128-cbc", passphrase: "x" })); +// OpenSSL refuses these ciphers for PKCS#8, and the last ones for +// traditional PEM too (the P-256 key's PKCS#8 and SEC1 lengths are not +// multiples of 8, which key wrap needs). +for (const cipher of ["aes-128-gcm", "aes-256-ccm", "aes-128-ctr", "chacha20-poly1305", "aes-128-xts", "des-ede3-cfb", "2.16.840.1.101.3.4.1.6"]) + tryIt(`refused pkcs8 ${cipher}`, () => ec.privateKey.export(opts({ cipher, passphrase: "x" })).length > 0); +for (const cipher of ["aes-128-wrap", "id-aes256-wrap", "des-cbc", "rc4"]) { + tryIt(`refused pkcs8 ${cipher}`, () => ec.privateKey.export(opts({ cipher, passphrase: "x" })).length > 0); + tryIt(`refused sec1 ${cipher}`, () => ec.privateKey.export({ type: "sec1", format: "pem", cipher, passphrase: "x" })); +} +for (const cipher of ["aes-128-ecb", "aes-256-ecb", "des-ede3"]) + tryIt(`refused sec1 ${cipher}`, () => ec.privateKey.export({ type: "sec1", format: "pem", cipher, passphrase: "x" })); + +// generateKeyPair with a cipher. +const encoding = (cipher, type = "pkcs8") => ({ + namedCurve: "P-256", + publicKeyEncoding: { type: "spki", format: "pem" }, + privateKeyEncoding: { type, format: "pem", cipher, passphrase: "gen" }, +}); +tryIt("keygen sync", () => { + const { publicKey, privateKey } = c.generateKeyPairSync("ec", encoding("aes-256-cbc")); + return `${head(privateKey)} ${c.createPublicKey({ key: privateKey, passphrase: "gen" }).equals(c.createPublicKey(publicKey))}`; +}); +tryIt("keygen unknown", () => c.generateKeyPairSync("ec", encoding("nope"))); +tryIt("keygen gcm", () => c.generateKeyPairSync("ec", encoding("aes-128-gcm"))); +tryIt("keygen sec1 ecb", () => c.generateKeyPairSync("ec", encoding("aes-128-ecb", "sec1"))); +// One job at a time: Node's jobs finish in either order. +c.generateKeyPair("ec", encoding("des-ede3-cbc", "sec1"), (err, publicKey, privateKey) => { + console.log("keygen async", err, head(privateKey)); + console.log("keygen async key", c.createPublicKey({ key: privateKey, passphrase: "gen" }).equals(c.createPublicKey(publicKey))); + c.generateKeyPair("ec", encoding("aes-128-ccm"), (err) => console.log("keygen async ccm", show(err))); +}); diff --git a/tests/harness/corpus-costs/8165-rsa-keygen-lengths.cjs.json b/tests/harness/corpus-costs/8165-rsa-keygen-lengths.cjs.json new file mode 100644 index 000000000..bbf64dca5 --- /dev/null +++ b/tests/harness/corpus-costs/8165-rsa-keygen-lengths.cjs.json @@ -0,0 +1 @@ +{ "plain": 11640, "san": 77506 } diff --git a/tests/harness/corpus-costs/8166-rsa-pss-keys.cjs.json b/tests/harness/corpus-costs/8166-rsa-pss-keys.cjs.json new file mode 100644 index 000000000..436e9ed51 --- /dev/null +++ b/tests/harness/corpus-costs/8166-rsa-pss-keys.cjs.json @@ -0,0 +1 @@ +{ "plain": 11459, "san": 74658 } diff --git a/tests/harness/corpus-costs/8167-encrypted-private-keys.cjs.json b/tests/harness/corpus-costs/8167-encrypted-private-keys.cjs.json new file mode 100644 index 000000000..0f258ddbb --- /dev/null +++ b/tests/harness/corpus-costs/8167-encrypted-private-keys.cjs.json @@ -0,0 +1 @@ +{ "plain": 3144, "san": 8504 } From 6aec284766d2baa928a56f81777d52af31fb4dc7 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 08:50:22 -0500 Subject: [PATCH 092/259] Inline the array release fast path under --optimization=speed Speed builds now release arrays through the inline fast path the other RC families use: an array that stays alive and has no cycle header is decremented in place, and only the last release or a headered array calls scr_arr_release. --- packages/compiler/src/backend/llvm/shapes.test.ts | 4 ++-- packages/compiler/src/backend/llvm/shapes.ts | 11 +++++------ 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/compiler/src/backend/llvm/shapes.test.ts b/packages/compiler/src/backend/llvm/shapes.test.ts index f91ee2f58..61c1a074d 100644 --- a/packages/compiler/src/backend/llvm/shapes.test.ts +++ b/packages/compiler/src/backend/llvm/shapes.test.ts @@ -110,10 +110,9 @@ describe("LLVM runtime RC symbols", () => { expect(releaseSym(host, { kind: "union", unionId: "u0" } as never)).toBe( "@sc_rc_release_union", ); - // Array retains inline; array releases stay calls. const array = { kind: "array", elem: { kind: "string" } } as never; expect(retainSym(host, array)).toBe("@sc_rc_retain_arr"); - expect(releaseSym(host, array)).toBe("@scr_arr_release"); + expect(releaseSym(host, array)).toBe("@sc_rc_release_arr"); expect(retainSym(host, { kind: "dyn" })).toBe("@sc_rc_retain_dyn"); expect(releaseSym(host, { kind: "dyn" })).toBe("@sc_rc_release_dyn"); // Unmirrored families and caught snapshots keep their runtime entry points. @@ -125,6 +124,7 @@ describe("LLVM runtime RC symbols", () => { expect(declarations).toContain("declare void @scr_str_release(ptr)"); expect(declarations).toContain("declare void @scr_cyc_on_release(ptr)"); expect(inlineRcDecls(host).sort()).toEqual([ + "declare void @scr_arr_release(ptr)", "declare void @scr_cyc_on_release(ptr)", "declare void @scr_dyn_release(ptr)", "declare void @scr_dyn_release_survivor(ptr)", diff --git a/packages/compiler/src/backend/llvm/shapes.ts b/packages/compiler/src/backend/llvm/shapes.ts index 2c851b462..a966ff305 100644 --- a/packages/compiler/src/backend/llvm/shapes.ts +++ b/packages/compiler/src/backend/llvm/shapes.ts @@ -550,17 +550,16 @@ interface InlineRcFamily { * scr_dyn_release_survivor for kinds whose candidacy is per value, * including arrays and objects of intact documents (ScrDynRegion). * - * Releases stay plain calls for: - * - arr: array releases are the most numerous release sites and the - * least hot (at most 1% self time across the benchmark suite), and - * inlining them roughly doubled the code growth for no measured speedup. - * Array retains are inlined. */ + * The array release inlines the decrement of an array that stays alive + * and is not headered (`a->cyc`): those are most array releases in + * type-checker workloads, where scr_arr_release's own prologue and checks + * took about half of its time. */ export const INLINE_RC_FAMILIES: Readonly> = { str: { cycle: "none", retainNull: false, release: "scr_str_release" }, bytes: { cycle: "none", retainNull: false, release: "scr_bytes_release" }, regex: { cycle: "none", retainNull: false, release: "scr_regex_release" }, bigint: { cycle: "none", retainNull: true, release: "scr_bigint_release" }, - arr: { cycle: "arr", retainNull: false, release: null }, + arr: { cycle: "arr", retainNull: false, release: "scr_arr_release" }, map: { cycle: "map", retainNull: false, release: "scr_map_release" }, union: { cycle: "always", retainNull: false, release: "scr_union_release" }, closure: { cycle: "always", retainNull: false, release: "scr_closure_release" }, From f2e710d65f4233424be8a0c01db56520b440828b Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 09:05:16 -0500 Subject: [PATCH 093/259] Answer stream, StringDecoder and handle-object members in untyped code as Node does --- packages/compiler/src/backend/llvm/dyn.ts | 45 +++--- .../compiler/src/backend/llvm/expr-dynamic.ts | 2 +- .../src/backend/llvm/expr-stream-bridges.ts | 5 +- .../frontend/lowering/expressions/typeof.ts | 7 +- .../src/frontend/lowering/f64-handles.ts | 15 ++ packages/compiler/src/ir/ir.ts | 26 +++- packages/compiler/src/ir/runtime-features.ts | 7 +- .../8232-native-streams-untyped.cjs.json | 6 + .../8233-string-decoder-values.cjs.json | 6 + .../tests/corpus/8234-handle-typeof.ts.json | 6 + packages/runtime/src/scr_bytes.h | 6 + packages/runtime/src/scr_dyn.h | 1 + packages/runtime/src/scr_stream.c | 96 ++++++++++++- packages/runtime/src/scr_text_codec_dyn.c | 128 +++++++++++++++++- tests/corpus/8232-native-streams-untyped.cjs | 56 ++++++++ tests/corpus/8233-string-decoder-values.cjs | 33 +++++ tests/corpus/8234-handle-typeof.ts | 24 ++++ .../8232-native-streams-untyped.cjs.json | 1 + .../8233-string-decoder-values.cjs.json | 1 + .../corpus-costs/8234-handle-typeof.ts.json | 1 + 20 files changed, 437 insertions(+), 35 deletions(-) create mode 100644 packages/compiler/src/frontend/lowering/f64-handles.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8232-native-streams-untyped.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8233-string-decoder-values.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8234-handle-typeof.ts.json create mode 100644 tests/corpus/8232-native-streams-untyped.cjs create mode 100644 tests/corpus/8233-string-decoder-values.cjs create mode 100644 tests/corpus/8234-handle-typeof.ts create mode 100644 tests/harness/corpus-costs/8232-native-streams-untyped.cjs.json create mode 100644 tests/harness/corpus-costs/8233-string-decoder-values.cjs.json create mode 100644 tests/harness/corpus-costs/8234-handle-typeof.ts.json diff --git a/packages/compiler/src/backend/llvm/dyn.ts b/packages/compiler/src/backend/llvm/dyn.ts index da31ffdbb..c7b80b71d 100644 --- a/packages/compiler/src/backend/llvm/dyn.ts +++ b/packages/compiler/src/backend/llvm/dyn.ts @@ -43,7 +43,7 @@ import { isDynTypedRefType, isRefCounted, isUnitType, - recordTextCodecClass, + recordHandleCodecClass, textCodecRecordClass, typeKey, } from "../../ir/ir.js"; @@ -98,14 +98,16 @@ export const DYN_HANDLE_TAG_NUM: Record = { /** The handle tags of TextEncoder and TextDecoder records boxed as dyn * (scr_dyn.h; scr_text_codec_dyn.c boxes and unboxes them). */ -export const TEXT_CODEC_TAG_NUM: Record<"TextEncoder" | "TextDecoder", number> = { +export const TEXT_CODEC_TAG_NUM: Record<"TextEncoder" | "TextDecoder" | "StringDecoder", number> = { TextDecoder: 76, TextEncoder: 77, + StringDecoder: 78, }; /** The decoder record fields scr_text_decoder_to_dyn reads, in its * parameter order. */ const TEXT_DECODER_FIELDS = ["%TextDecoder", "%fatal", "%ignoreBOM", "%state"] as const; +const STRING_DECODER_FIELDS = ["%enc", "%pending"] as const; /** Handle kinds whose runtime unit boxes them through its own function, * which installs the tag's ops on first use (scr_crypto.h). Programs that @@ -1825,11 +1827,18 @@ export class LlDyn { const codec = textCodecRecordClass(t, (id) => host.recordsById.get(id)); if (codec !== null) { // The record the codec's handle box holds (+1), or the path TypeError. - host.declare(`declare ptr @scr_text_codec_from_dyn(ptr, i1 zeroext, ptr, ptr)`); const checked = B.tmp(); - B.line( - `${checked} = call ptr @scr_text_codec_from_dyn(ptr %d, i1 ${codec === "TextDecoder"}, ptr %path, ptr ${want})`, - ); + if (codec === "StringDecoder") { + host.declare(`declare ptr @scr_string_decoder_from_dyn(ptr, ptr, ptr)`); + B.line( + `${checked} = call ptr @scr_string_decoder_from_dyn(ptr %d, ptr %path, ptr ${want})`, + ); + } else { + host.declare(`declare ptr @scr_text_codec_from_dyn(ptr, i1 zeroext, ptr, ptr)`); + B.line( + `${checked} = call ptr @scr_text_codec_from_dyn(ptr %d, i1 ${codec === "TextDecoder"}, ptr %path, ptr ${want})`, + ); + } B.terminate(`ret ptr ${checked}`); this.defs.push( `define internal ptr @${name}(ptr %d, ptr %path) ${FN_ATTRS} {`, @@ -2917,14 +2926,14 @@ export class LlDyn { return matched; } - /** A TextEncoder or TextDecoder record boxes as its handle (+1), which - * holds the record by reference. A decoder passes the byte offsets of the - * fields its boxed decode reads. */ + /** A TextEncoder, TextDecoder or StringDecoder record boxes as its + * handle (+1), which holds the record by reference. The decoders pass + * the byte offsets of the fields their boxed methods read. */ private textCodecToDyn( B: BlockBuilder, t: IrType & { kind: "record" }, shape: IrRecordShape, - codec: "TextEncoder" | "TextDecoder", + codec: "TextEncoder" | "TextDecoder" | "StringDecoder", ): void { const host = this.host; const rc = vAdapters(host, t); @@ -2939,10 +2948,12 @@ export class LlDyn { const base = host.nullableUnions.fieldBase(t.shapeId); const start = B.tmp(); B.line(`${start} = ptrtoint ptr %v to ${this.S}`); - const offsets = TEXT_DECODER_FIELDS.map((field) => { + const fields: readonly string[] = + codec === "StringDecoder" ? STRING_DECODER_FIELDS : TEXT_DECODER_FIELDS; + const offsets = fields.map((field) => { const index = shape.fields.findIndex((f) => f.name === field); if (index < 0) - throw new InternalCompilerError(`llvm emitter bug: TextDecoder record lacks ${field}`); + throw new InternalCompilerError(`llvm emitter bug: ${codec} record lacks ${field}`); const p = B.tmp(); const at = B.tmp(); const offset = B.tmp(); @@ -2953,11 +2964,11 @@ export class LlDyn { B.line(`${offset} = sub ${this.S} ${at}, ${start}`); return `${this.S} ${offset}`; }); - host.declare( - `declare ptr @scr_text_decoder_to_dyn(ptr, ptr, ptr, ${this.S}, ${this.S}, ${this.S}, ${this.S})`, - ); + const fn = + codec === "StringDecoder" ? "scr_string_decoder_to_dyn" : "scr_text_decoder_to_dyn"; + host.declare(`declare ptr @${fn}(ptr, ptr, ptr, ${fields.map(() => this.S).join(", ")})`); B.line( - `${r} = call ptr @scr_text_decoder_to_dyn(ptr %v, ptr ${rc.retain}, ptr ${rc.release}, ${offsets.join(", ")})`, + `${r} = call ptr @${fn}(ptr %v, ptr ${rc.retain}, ptr ${rc.release}, ${offsets.join(", ")})`, ); } B.terminate(`ret ptr ${r}`); @@ -3137,7 +3148,7 @@ export class LlDyn { const shape = host.recordsById.get(t.shapeId); if (!shape) throw new InternalCompilerError(`llvm emitter bug: to-dyn of unknown shape ${t.shapeId}`); - const codec = recordTextCodecClass(shape); + const codec = recordHandleCodecClass(shape); if (codec !== null) { this.textCodecToDyn(B, t, shape, codec); break; diff --git a/packages/compiler/src/backend/llvm/expr-dynamic.ts b/packages/compiler/src/backend/llvm/expr-dynamic.ts index b7a5c7736..3d9aec3cc 100644 --- a/packages/compiler/src/backend/llvm/expr-dynamic.ts +++ b/packages/compiler/src/backend/llvm/expr-dynamic.ts @@ -89,7 +89,7 @@ export function emitDynamicExpr( // Bytes already box their shared mutable storage directly. A second // capsule would split identity between checked and native views. const errorRef = v.type.kind === "object" && host.shapeHost.isErrorClass(v.type.className); - // A TextEncoder or TextDecoder record boxes as its own handle, which + // A TextEncoder, TextDecoder or StringDecoder record boxes as its own handle, which // keeps the record's identity (toDynHelper). const codecRef = textCodecRecordClass(v.type, (id) => host.recordsById.get(id)) !== null; if (!errorRef && !codecRef && ((e.liveRef && v.type.kind !== "bytes") || identityRef)) { diff --git a/packages/compiler/src/backend/llvm/expr-stream-bridges.ts b/packages/compiler/src/backend/llvm/expr-stream-bridges.ts index 675932d47..28f5ae5bc 100644 --- a/packages/compiler/src/backend/llvm/expr-stream-bridges.ts +++ b/packages/compiler/src/backend/llvm/expr-stream-bridges.ts @@ -1,7 +1,7 @@ import { typedRefConstructor } from "./shapes.js"; /* Focused LLVM expression emission extracted from emitter.ts. */ import { InternalCompilerError } from "../../errors.js"; -import { streamTypedRefEligible, undefinedArmTag } from "../../ir/analysis.js"; +import { streamRooted, streamTypedRefEligible, undefinedArmTag } from "../../ir/analysis.js"; import { type IrRecordShape, type IrType, @@ -843,8 +843,7 @@ export function streamTypedRefMaterializeAdapter( host.declare(`declare ptr @scr_error_dyn_fields(ptr)`); B.line(`${out} = call ptr @scr_error_dyn_fields(ptr %p)`); } else if ( - meta.def.runtime && - RUNTIME_STREAM_CLASSES.has(t.className) && + ((meta.def.runtime && RUNTIME_STREAM_CLASSES.has(t.className)) || streamRooted(meta)) && !meta.def.instancePrototypeHelper && !meta.def.prototypeDataHelper ) { diff --git a/packages/compiler/src/frontend/lowering/expressions/typeof.ts b/packages/compiler/src/frontend/lowering/expressions/typeof.ts index fbbc068b9..ba1aba68e 100644 --- a/packages/compiler/src/frontend/lowering/expressions/typeof.ts +++ b/packages/compiler/src/frontend/lowering/expressions/typeof.ts @@ -35,6 +35,7 @@ import { isExecExceptionType, refuseExecExceptionCode } from "../builtins/errors import { InternalCompilerError } from "../../../errors.js"; import { TEMPORAL_GLOBAL } from "../../builtin-modules.js"; import { isTemporalGlobalRoot } from "../lower-namespaces.js"; +import { isF64HandleTyped } from "../f64-handles.js"; export function lowerTypeofExpr(lowerer: Lowerer, expr: ts.TypeOfExpression, loc: SrcLoc): IrExpr { const webAssembly = lowerWebAssemblyTypeof(lowerer, expr.expression); @@ -287,7 +288,11 @@ export function lowerTypeofExpr(lowerer: Lowerer, expr: ts.TypeOfExpression, loc undefinedT: "undefined", nullT: "object", }; - const folded = FOLD[operand.type.kind]; + // An f64 handle (a readline Interface, a Timeout) is an object. + const folded = + operand.type.kind === "f64" && isF64HandleTyped(lowerer, expr.expression) + ? "object" + : FOLD[operand.type.kind]; if (folded) { const result: IrExpr = { kind: "strLit", value: folded, type: STRING, loc }; return isSafeToDiscard(operand) diff --git a/packages/compiler/src/frontend/lowering/f64-handles.ts b/packages/compiler/src/frontend/lowering/f64-handles.ts new file mode 100644 index 000000000..0d7da0ff9 --- /dev/null +++ b/packages/compiler/src/frontend/lowering/f64-handles.ts @@ -0,0 +1,15 @@ +import * as ts from "../ts7/adapter.js"; +import type { Lowerer } from "./lowerer.js"; + +/** Whether `node`'s value is an f64 handle: an object whose class + * type-mapper.ts represents as an f64 id into a runtime registry (a + * readline Interface, a Timeout or Immediate, an AsyncLocalStorage, a + * diagnostics_channel Channel). Its checker type is an object type that + * maps to f64; the Number wrapper interface maps to f64 for primitives. */ +export function isF64HandleTyped(lowerer: Lowerer, node: ts.Node): boolean { + const type = lowerer.checker.getTypeAtLocation(node); + if ((type.flags & ts.TypeFlags.Object) === 0) return false; + const symbol = type.getSymbol(); + if (symbol !== undefined && ts.symbolName(symbol) === "Number") return false; + return lowerer.mapTypeOf(type)?.kind === "f64"; +} diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index 3818433f8..c6dcb6e08 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -1781,16 +1781,32 @@ export function recordTextCodecClass(shape: IrRecordShape): "TextEncoder" | "Tex return null; } -/** The codec class of a TextEncoder or TextDecoder record type, else null. - * Such a record crosses an `unknown` slot as a native handle that holds the - * record itself (scr_text_codec_dyn.c), never as a copy or a field view. */ +/** The class of a record that crosses checked-dynamic slots as a native + * handle: the codecs, and a StringDecoder (type-mapper.ts: its canonical + * encoding and the packing of its pending bytes). */ +export function recordHandleCodecClass( + shape: IrRecordShape, +): "TextEncoder" | "TextDecoder" | "StringDecoder" | null { + const codec = recordTextCodecClass(shape); + if (codec !== null) return codec; + return shape.fields.length === 2 && + shape.fields[0]!.name === "%enc" && + shape.fields[1]!.name === "%pending" + ? "StringDecoder" + : null; +} + +/** The codec class of a TextEncoder, TextDecoder or StringDecoder record + * type, else null. Such a record crosses an `unknown` slot as a native + * handle that holds the record itself (scr_text_codec_dyn.c), never as a + * copy or a field view. */ export function textCodecRecordClass( t: IrType, getRecord: (shapeId: string) => IrRecordShape | undefined, -): "TextEncoder" | "TextDecoder" | null { +): "TextEncoder" | "TextDecoder" | "StringDecoder" | null { if (t.kind !== "record") return null; const shape = getRecord(t.shapeId); - return shape ? recordTextCodecClass(shape) : null; + return shape ? recordHandleCodecClass(shape) : null; } /** Object-literal ACCESSOR properties (`{ get x() {...}, set x(v) {...} }`) diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 85b21af7b..917406d6c 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -2,6 +2,7 @@ import type { IrClassDef, IrExpr, IrModule, IrRecordShape, IrType, IrUnionDef } import type { IrLibFn } from "./builtin-signatures.js"; import { isDirentShape, + recordHandleCodecClass, recordTextCodecClass, RUNTIME_EMITTER_CLASS, RUNTIME_EVENT_CLASS, @@ -586,7 +587,7 @@ function mentionsDgramSocket(t: IrType, tables: TypeTables): boolean { const textCodecLeaf: CarrierLeaf = (t, tables) => { if (t.kind !== "record") return false; const shape = tables.records.get(t.shapeId); - return shape !== undefined && recordTextCodecClass(shape) !== null; + return shape !== undefined && recordHandleCodecClass(shape) !== null; }; const textDecoderLeaf: CarrierLeaf = (t, tables) => { @@ -596,7 +597,7 @@ const textDecoderLeaf: CarrierLeaf = (t, tables) => { }; /** Whether converting a value of type `t` to or from dyn converts a - * TextEncoder or TextDecoder record, which boxes it as a handle of + * TextEncoder, TextDecoder or StringDecoder record, which boxes it as a handle of * scr_text_codec_dyn.c (the same carrier walk as dgram sockets). */ function mentionsTextCodec(t: IrType, tables: TypeTables): boolean { tables.textCodecCarriers ??= leafCarriers(tables, textCodecLeaf); @@ -858,7 +859,7 @@ const RUNTIME_FEATURE_RULES = { (node.kind === "dynFrom" && mentionsDgramSocket(node.value.type, tables())) || (node.kind === "dynCheck" && mentionsDgramSocket(node.type, tables())), }), - /** A TextEncoder or TextDecoder record converts to or from an untyped + /** A TextEncoder, TextDecoder or StringDecoder record converts to or from an untyped * value (its handle box, or a boxed function, record or collection that * carries one): scr_text_codec_dyn.c. */ textCodecDyn: rule({ diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8232-native-streams-untyped.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8232-native-streams-untyped.cjs.json new file mode 100644 index 000000000..2b07cde52 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8232-native-streams-untyped.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8232-native-streams-untyped.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8233-string-decoder-values.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8233-string-decoder-values.cjs.json new file mode 100644 index 000000000..a734fb48c --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8233-string-decoder-values.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8233-string-decoder-values.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8234-handle-typeof.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8234-handle-typeof.ts.json new file mode 100644 index 000000000..7f37dbc5d --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8234-handle-typeof.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8234-handle-typeof.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_bytes.h b/packages/runtime/src/scr_bytes.h index 7c0a935cc..c7ea68988 100644 --- a/packages/runtime/src/scr_bytes.h +++ b/packages/runtime/src/scr_bytes.h @@ -369,6 +369,12 @@ ScrDyn *scr_text_decoder_to_dyn(void *rec, void *(*retain)(void *), void (*relea void *scr_text_codec_from_dyn(const ScrDyn *d, bool decoder, const struct ScrDynPath *path, const char *want); bool scr_text_codec_is(const ScrDyn *d, bool decoder); +/* StringDecoder records as checked-dynamic handles (the same unit): the + * byte offsets of the encoding (string) and pending (f64) fields. */ +ScrDyn *scr_string_decoder_to_dyn(void *rec, void *(*retain)(void *), void (*release)(void *), + size_t encoding, size_t pending); +void *scr_string_decoder_from_dyn(const ScrDyn *d, const struct ScrDynPath *path, + const char *want); bool scr_buffer_is_ascii(const ScrDyn *input); bool scr_buffer_is_utf8(const ScrDyn *input); ScrBytes *scr_buffer_transcode(const ScrDyn *source, const ScrDyn *from, const ScrDyn *to); diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index 82fe1a6d9..1c7a9a0e0 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -200,6 +200,7 @@ typedef enum { X(SHARED_ARRAY_BUFFER, 37) \ X(SIGN, 67) /* node:crypto Sign (scr_pki.c) */ \ X(STDIO, 27) /* stable process stdin/stdout/stderr values */ \ + X(STRING_DECODER, 78) /* compiled StringDecoder record (scr_text_codec_dyn.c) */ \ X(TEXT_DECODER, 76) /* compiled TextDecoder record (scr_text_codec_dyn.c) */ \ X(TEXT_ENCODER, 77) /* compiled TextEncoder record (scr_text_codec_dyn.c) */ \ X(URL, 28) /* native WHATWG URL */ \ diff --git a/packages/runtime/src/scr_stream.c b/packages/runtime/src/scr_stream.c index ec061e10c..33382363b 100644 --- a/packages/runtime/src/scr_stream.c +++ b/packages/runtime/src/scr_stream.c @@ -6634,6 +6634,12 @@ ScrStream *scr_stream_on_dyn(ScrStream *s, ScrStr *name, ScrDyn *cb, bool once, return (ScrStream *)scr_emitter_on_dyn((ScrEmitter *)s, name, cb, adapter, error ? scr_ee_inv_fixed1 : scr_ee_inv_fixed0, once, prepend); } + /* The stream emits 'pipe' and 'unpipe' with its source stream; other + * names reach the listener only through emit calls, with every argument + * they pass. */ + bool piping = (name->len == 4 && memcmp(name->data, "pipe", 4) == 0) || + (name->len == 6 && memcmp(name->data, "unpipe", 6) == 0); + if (!piping) return (ScrStream *)scr_emitter_on_flex((ScrEmitter *)s, name, cb, once, prepend); static const char message[] = "this stream event has no checked-dynamic listener adapter"; scr_throw_error_msg_code(SCR_ERR_ERROR, message, sizeof message - 1, "SC2020"); return NULL; @@ -8058,10 +8064,68 @@ static ScrStream *scr_stream_view_receiver(const ScrDyn *value) { /* The members a native stream answers to checked-dynamic calls. */ static const char *const scr_stream_dyn_methods[] = { "on", "once", "addListener", "prependListener", "prependOnceListener", - "off", "removeListener", "pipe", "unpipe", "read", "pause", "resume", "isPaused", - "setEncoding", "write", "end", "destroy", "cork", "uncork", + "off", "removeListener", "removeAllListeners", "listenerCount", "eventNames", "pipe", + "unpipe", "read", "push", "unshift", "pause", "resume", "isPaused", "setEncoding", "write", + "end", "destroy", "cork", "uncork", "setDefaultEncoding", }; +/* An event name argument: a string, +1; other values throw the "not + * supported yet" Error. */ +static ScrStr *scr_stream_dyn_event_name(const ScrDyn *value) { + if (value->kind == SCR_DYN_STR) return scr_str_retain(value->v.str); + static const char message[] = "event names other than strings on a native stream are not supported yet"; + scr_throw_error_msg_code(SCR_ERR_ERROR, message, sizeof message - 1, "SC2020"); + return NULL; +} + +/* push(chunk, encoding): a string with an encoding pushes the string's + * bytes in that encoding, undefined pushes an empty chunk outside object + * mode, and other chunks push as push(chunk) does. */ +static ScrDyn *scr_stream_dyn_push(ScrStream *stream, ScrDyn *const *args, size_t argc) { + ScrDyn *chunk = argc ? args[0] : scr_dyn_undefined(); + ScrDyn *encoding = argc > 1 ? args[1] : scr_dyn_undefined(); + if (chunk->kind == SCR_DYN_STR && encoding->kind == SCR_DYN_STR) { + ScrStr *canonical = scr_bytes_normalize_encoding(encoding->v.str); + if (!canonical) return NULL; + bool more = scr_stream_push_str_enc(stream, chunk->v.str, canonical); + scr_str_release(canonical); + return scr_dyn_new_bool(more); + } + if (chunk->kind == SCR_DYN_UNDEF && !(stream->st->has_r && stream->st->r.object_entries)) { + ScrStr *empty = scr_str_new("", 0); + bool more = scr_stream_push_str(stream, empty); + scr_str_release(empty); + return scr_dyn_new_bool(more); + } + bool more = scr_stream_push_dyn(stream, chunk); + return scr_exc_pending() ? NULL : scr_dyn_new_bool(more); +} + +/* unshift(chunk): whether the stream takes more data afterwards, Node's + * canPushMore. */ +static ScrDyn *scr_stream_dyn_unshift(ScrStream *stream, const ScrDyn *chunk) { + scr_stream_unshift_dyn(stream, chunk); + if (scr_exc_pending()) return NULL; + ScrStreamState *st = stream->st; + bool more = chunk->kind != SCR_DYN_NULL && st->has_r && !st->destroyed && !st->errored && + !st->r.ended && (st->r.length < st->r.hwm || st->r.length == 0); + return scr_dyn_new_bool(more); +} + +/* eventNames(): the stream's event names as a string array, +1. */ +static ScrDyn *scr_stream_dyn_event_names(ScrStream *stream) { + ScrArr *names = scr_emitter_event_names((ScrEmitter *)stream); + ScrDyn *result = scr_dyn_new_arr(); + double length = scr_arr_len(names); + for (double i = 0; i < length; i++) { + ScrStr *name = scr_arr_get_ref(names, i); + scr_dyn_arr_push(result, scr_dyn_new_str(name)); + scr_str_release(name); + } + scr_arr_release(names); + return result; +} + /* A checked-dynamic call of one of a native stream's members (borrowed * stream): the result, +1, with `this` results answering `self`, or the * current `this` when self is NULL. */ @@ -8086,6 +8150,29 @@ static ScrDyn *scr_stream_dyn_call(ScrStream *stream, ScrDyn *self, const char * argc > 1 ? args[1] : scr_dyn_undefined()); scr_emitter_release(registered); } + } else if (!strcmp(method, "removeAllListeners")) { + bool all = first->kind == SCR_DYN_UNDEF; + ScrStr *name = all ? scr_str_new("", 0) : scr_stream_dyn_event_name(first); + if (name) { + scr_emitter_release(scr_emitter_remove_all((ScrEmitter *)stream, name, all)); + scr_str_release(name); + } + } else if (!strcmp(method, "listenerCount")) { + ScrStr *name = scr_stream_dyn_event_name(first); + if (name) { + ScrDyn *only = argc > 1 ? args[1] : scr_dyn_undefined(); + double count = only->kind == SCR_DYN_UNDEF || only->kind == SCR_DYN_NULL + ? scr_emitter_listener_count((ScrEmitter *)stream, name) + : only->kind == SCR_DYN_FUNC ? scr_emitter_listener_count_dyn((ScrEmitter *)stream, name, only) : 0; + scr_str_release(name); + if (!scr_exc_pending()) result = scr_dyn_new_num(count); + } + } else if (!strcmp(method, "eventNames")) result = scr_stream_dyn_event_names(stream); + else if (!strcmp(method, "push")) result = scr_stream_dyn_push(stream, args, argc); + else if (!strcmp(method, "unshift")) result = scr_stream_dyn_unshift(stream, first); + else if (!strcmp(method, "setDefaultEncoding")) { + ScrStream *returned = scr_stream_set_default_encoding(stream, first); + if (returned) scr_stream_release(returned); } else if (!strcmp(method, "pipe") || !strcmp(method, "unpipe")) { ScrStream *destination = first->kind == SCR_DYN_UNDEF && !strcmp(method, "unpipe") ? NULL : scr_stream_view_receiver(first); @@ -8220,6 +8307,11 @@ ScrDyn *scr_stream_dyn_view(ScrStream *stream) { const char *name = scr_stream_dyn_properties[i]; scr_dyn_obj_set(view, name, strlen(name), scr_stream_dyn_property(stream, name)); } + if (stream->st->has_r) { + int flowing = stream->st->r.flowing; + scr_dyn_obj_set(view, "readableFlowing", 15, + flowing < 0 ? scr_dyn_new_null() : scr_dyn_new_bool(flowing == 1)); + } if (stream->st->native && stream->st->native_ops && stream->st->native_ops->view) { ScrClosure *cb = scr_closure_new((void *)scr_stream_view_call, 2); cb->caps[0] = scr_box_new_obj(scr_stream_retain_v, scr_stream_release_v, scr_stream_trace); diff --git a/packages/runtime/src/scr_text_codec_dyn.c b/packages/runtime/src/scr_text_codec_dyn.c index 5102bc558..37fdfb27b 100644 --- a/packages/runtime/src/scr_text_codec_dyn.c +++ b/packages/runtime/src/scr_text_codec_dyn.c @@ -1,9 +1,10 @@ -/* WHATWG TextEncoder and TextDecoder instances as checked-dynamic values - * (SCR_DYNH_TEXT_ENCODER, SCR_DYNH_TEXT_DECODER). A codec is a compiled +/* WHATWG TextEncoder and TextDecoder instances, and node:string_decoder + * StringDecoder instances, as checked-dynamic values (SCR_DYNH_TEXT_ENCODER, + * SCR_DYNH_TEXT_DECODER, SCR_DYNH_STRING_DECODER). A codec is a compiled * record (type-mapper.ts): the handle holds that record by reference, so * a codec stored in an untyped slot and read back keeps its identity and * a decoder keeps its streaming state. The compiler passes the record's - * reference-count entry points and, for decoders, the byte offsets of the + * reference-count entry points and, for a TextDecoder, the byte offsets of the * encoding, fatal, ignoreBOM and state fields when it boxes one. A unit * of its own so programs that never box a codec link none of it * (native-toolchain gating: the textCodecDyn runtime feature). */ @@ -213,3 +214,124 @@ bool scr_text_codec_is(const ScrDyn *d, bool decoder) { return d->kind == SCR_DYN_HANDLE && d->v.handle.tag == (decoder ? SCR_DYNH_TEXT_DECODER : SCR_DYNH_TEXT_ENCODER); } + +/* node:string_decoder StringDecoder instances (SCR_DYNH_STRING_DECODER). + * The decoder is a compiled record of its canonical encoding (a string) + * and its pending partial sequence (an f64 packing, scr_bytes.c's + * scr_strdec_* helpers); the compiler passes both fields' byte offsets + * when it boxes one. */ +typedef struct { + void *(*retain)(void *); + void (*release)(void *); + size_t encoding, pending; +} ScrStringDecoderLayout; + +static SCR_TL ScrStringDecoderLayout scr_sdd_layout; + +static void *scr_sdd_retain(void *rec) { return scr_sdd_layout.retain(rec); } +static void scr_sdd_release(void *rec) { scr_sdd_layout.release(rec); } + +static ScrStr *scr_sdd_encoding(const void *rec) { + ScrStr *encoding; + memcpy(&encoding, (const char *)rec + scr_sdd_layout.encoding, sizeof encoding); + return encoding; +} + +static double scr_sdd_pending(const void *rec) { + double pending; + memcpy(&pending, (const char *)rec + scr_sdd_layout.pending, sizeof pending); + return pending; +} + +static void scr_sdd_set_pending(void *rec, double pending) { + memcpy((char *)rec + scr_sdd_layout.pending, &pending, sizeof pending); +} + +/* write(buf): a string answers itself; an ArrayBuffer view decodes with + * the pending bytes before it; other values throw Node's + * ERR_INVALID_ARG_TYPE. +1 or NULL. */ +static ScrStr *scr_sdd_write(void *rec, const ScrDyn *buf) { + if (buf->kind == SCR_DYN_STR) return scr_str_retain(buf->v.str); + if (buf->kind != SCR_DYN_BYTES) { + scr_dyn_arg_type_fail("buf", "an instance of Buffer, TypedArray, or DataView", buf); + return NULL; + } + ScrBytes *bytes = scr_bytes_raw_view(buf->v.bytes); + ScrStr *encoding = scr_sdd_encoding(rec); + double pending = scr_sdd_pending(rec); + ScrStr *text = scr_strdec_write(encoding, pending, bytes); + scr_sdd_set_pending(rec, scr_strdec_next(encoding, pending, bytes)); + scr_bytes_release(bytes); + return text; +} + +static ScrDyn *scr_sdd_invoke(void *rec, ScrDyn *self, const char *method, ScrDyn *const *args, + size_t argc, const char *what) { + (void)self; + ScrDyn *buf = scr_tcd_codec_arg(args, argc, 0); + if (strcmp(method, "write") == 0) { + ScrStr *text = scr_sdd_write(rec, buf); + return text ? scr_tcd_str(text) : NULL; + } + if (strcmp(method, "end") == 0) { + /* end(buf): write(buf) when buf is not undefined, then the pending + * bytes' replacement text. */ + ScrStr *head = buf->kind == SCR_DYN_UNDEF ? scr_str_new("", 0) : scr_sdd_write(rec, buf); + if (!head) return NULL; + ScrStr *tail = scr_strdec_end(scr_sdd_encoding(rec), scr_sdd_pending(rec)); + scr_sdd_set_pending(rec, 0); + ScrStr *text = scr_str_concat(head, tail); + scr_str_release(head); + scr_str_release(tail); + return scr_tcd_str(text); + } + if (strcmp(method, "text") == 0) { + static const char message[] = "StringDecoder.prototype.text is not supported yet"; + scr_throw_error_msg_code(SCR_ERR_ERROR, message, sizeof message - 1, "SC2020"); + return NULL; + } + scr_tcd_codec_not_a_function(what); + return NULL; +} + +static ScrDyn *scr_sdd_get(void *rec, const char *key, size_t len) { + if (len == 8 && memcmp(key, "encoding", 8) == 0) + return scr_dyn_new_str(scr_sdd_encoding(rec)); + if ((len == 8 && memcmp(key, "lastChar", 8) == 0) || + (len == 8 && memcmp(key, "lastNeed", 8) == 0) || + (len == 9 && memcmp(key, "lastTotal", 9) == 0)) { + static const char message[] = "StringDecoder lastChar, lastNeed and lastTotal are not supported yet"; + scr_throw_error_msg_code(SCR_ERR_ERROR, message, sizeof message - 1, "SC2020"); + } + return NULL; +} + +static const ScrDynHandleMethod scr_sdd_methods[] = { + {.name = "write", .length = 1}, + {.name = "end", .length = 1}, + {.name = "text", .length = 2}, + {.name = NULL}, +}; + +static const ScrDynHandleOps scr_sdd_ops = { + .cls = "StringDecoder", + .retain = scr_sdd_retain, + .release = scr_sdd_release, + .invoke = scr_sdd_invoke, + .get = scr_sdd_get, + .set = scr_tcd_codec_set, + .methods = scr_sdd_methods, +}; + +ScrDyn *scr_string_decoder_to_dyn(void *rec, void *(*retain)(void *), void (*release)(void *), + size_t encoding, size_t pending) { + if (!scr_sdd_layout.retain) { + scr_sdd_layout = (ScrStringDecoderLayout){retain, release, encoding, pending}; + scr_dyn_handle_install(SCR_DYNH_STRING_DECODER, &scr_sdd_ops); + } + return scr_dyn_new_handle(rec, SCR_DYNH_STRING_DECODER); +} + +void *scr_string_decoder_from_dyn(const ScrDyn *d, const ScrDynPath *path, const char *want) { + return scr_dyn_handle_unbox(d, SCR_DYNH_STRING_DECODER, path, want); +} diff --git a/tests/corpus/8232-native-streams-untyped.cjs b/tests/corpus/8232-native-streams-untyped.cjs new file mode 100644 index 000000000..b70017b5a --- /dev/null +++ b/tests/corpus/8232-native-streams-untyped.cjs @@ -0,0 +1,56 @@ +// Native streams passed to untyped helpers: push, unshift, the listener +// members, setDefaultEncoding and readableFlowing answer through the +// untyped value as on the typed one, also for a program subclass and in +// object mode. +const { Readable, Writable } = require("stream"); + +function feed(s) { + console.log("push", s.push("a"), s.push("b", "utf8"), s.unshift("z")); + console.log("counts", s.listenerCount("data"), s.eventNames().join(",")); + s.on("custom", (x, y) => { + console.log("custom", x, y); + }); + s.emit("custom", 1, 2); + s.removeAllListeners("custom"); + console.log("after removeAll", s.listenerCount("custom"), s.readableFlowing); + s.push(null); +} + +const r = new Readable({ read() {} }); +const chunks = []; +r.on("data", (c) => chunks.push(String(c))); +r.on("end", () => console.log("end", chunks.join("|"))); +feed(r); + +class Source extends Readable { + _read() {} +} +const sub = new Source(); +sub.on("data", (c) => console.log("source data", String(c))); +console.log("source push", sub instanceof Readable); +(function (s) { + console.log(s.push("from untyped"), s.readableLength); + s.push(null); +})(sub); + +const objects = new Readable({ objectMode: true, read() {} }); +console.log("flowing before", objects.readableFlowing); +objects.on("data", (c) => console.log("object data", c)); +(function (s) { + console.log(s.push({ n: 1 }), s.push(undefined), s.push(2), s.readableFlowing); + s.push(null); +})(objects); + +function drain(w) { + w.setDefaultEncoding("latin1"); + w.write("é"); + w.end(); +} +const w = new Writable({ + write(c, e, cb) { + console.log("wrote", c.length, e); + cb(); + }, +}); +w.on("finish", () => console.log("finish")); +drain(w); diff --git a/tests/corpus/8233-string-decoder-values.cjs b/tests/corpus/8233-string-decoder-values.cjs new file mode 100644 index 000000000..475a31d57 --- /dev/null +++ b/tests/corpus/8233-string-decoder-values.cjs @@ -0,0 +1,33 @@ +// A StringDecoder passed to untyped code keeps its identity and its +// pending bytes, and answers write, end and encoding as in Node. +const { StringDecoder } = require("string_decoder"); + +function feed(decoder, chunks) { + let out = ""; + for (const chunk of chunks) out += decoder.write(chunk); + return out + decoder.end(); +} + +const euro = Buffer.from("€ and 😀"); +const utf8 = new StringDecoder("utf-8"); +const parts = []; +for (let i = 0; i < euro.length; i++) parts.push(euro.subarray(i, i + 1)); +console.log(feed(utf8, parts), utf8.encoding); + +const hex = new StringDecoder("hex"); +console.log(feed(hex, [Buffer.from([1, 2]), Buffer.from([255])]), hex.encoding); + +const utf16 = new StringDecoder("ucs2"); +const pending = [Buffer.from([0x61]), Buffer.from([0x00, 0x62]), Buffer.from([0x00])]; +console.log(JSON.stringify(feed(utf16, pending)), utf16.encoding); + +function passThrough(d) { + return d; +} +const kept = passThrough(utf8); +console.log(kept === utf8, typeof kept, kept.write("text"), kept.end(Buffer.from([0xf0, 0x9f]))); +try { + kept.write(null); +} catch (e) { + console.log(e.code, e.message); +} diff --git a/tests/corpus/8234-handle-typeof.ts b/tests/corpus/8234-handle-typeof.ts new file mode 100644 index 000000000..f18240130 --- /dev/null +++ b/tests/corpus/8234-handle-typeof.ts @@ -0,0 +1,24 @@ +// typeof of the objects the runtime keeps as numeric handles answers +// "object", as Node's does: readline interfaces, timers, async-local +// stores, diagnostics channels and event-loop histograms. +import * as readline from "node:readline"; +import { PassThrough } from "node:stream"; +import { AsyncLocalStorage } from "node:async_hooks"; +import * as dc from "node:diagnostics_channel"; +import { monitorEventLoopDelay } from "node:perf_hooks"; + +const rl = readline.createInterface({ input: new PassThrough(), terminal: false }); +const timeout = setTimeout(() => {}, 1); +const interval = setInterval(() => {}, 1000); +const immediate = setImmediate(() => {}); +const store = new AsyncLocalStorage(); +const channel = dc.channel("handles"); +const tracing = dc.tracingChannel("handles"); +const histogram = monitorEventLoopDelay(); +const wrapped: Number = 5; +console.log(typeof rl, typeof timeout, typeof interval, typeof immediate); +console.log(typeof store, typeof channel, typeof tracing, typeof histogram, typeof wrapped); +clearTimeout(timeout); +clearInterval(interval); +clearImmediate(immediate); +rl.close(); diff --git a/tests/harness/corpus-costs/8232-native-streams-untyped.cjs.json b/tests/harness/corpus-costs/8232-native-streams-untyped.cjs.json new file mode 100644 index 000000000..bec4e42a8 --- /dev/null +++ b/tests/harness/corpus-costs/8232-native-streams-untyped.cjs.json @@ -0,0 +1 @@ +{ "plain": 4000, "san": 5000 } diff --git a/tests/harness/corpus-costs/8233-string-decoder-values.cjs.json b/tests/harness/corpus-costs/8233-string-decoder-values.cjs.json new file mode 100644 index 000000000..bb380e241 --- /dev/null +++ b/tests/harness/corpus-costs/8233-string-decoder-values.cjs.json @@ -0,0 +1 @@ +{ "plain": 2500, "san": 3000 } diff --git a/tests/harness/corpus-costs/8234-handle-typeof.ts.json b/tests/harness/corpus-costs/8234-handle-typeof.ts.json new file mode 100644 index 000000000..4c7ad07f1 --- /dev/null +++ b/tests/harness/corpus-costs/8234-handle-typeof.ts.json @@ -0,0 +1 @@ +{ "plain": 2500, "san": 5500 } From 48cbf3a89eef85d456b06a24df7d83ee8099d98a Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 09:20:05 -0500 Subject: [PATCH 094/259] Verify runtime pack artifacts once per file identity, and store pack selections Every native exe build that the executable cache does not restore hashed each selected runtime artifact before staging it, and every exe build parsed and validated the whole runtime-pack.json manifest to select its artifacts. - Staging still copies each artifact. It skips the SHA-256 of an artifact when the file's identity (device, inode, size, mtime, ctime) is the one recorded the last time that path matched the same size and digest, and the identity does not change while the file is read. Other artifacts are hashed as before, and their identities are recorded after they match. - A pack's selection for a target, compiler version, feature set, flavor and mode is stored, keyed by the file identities of package.json and runtime-pack.json. A stored selection skips parsing and validating the manifest; the manifest is parsed only when a caller needs it, through runtimePackManifest. - The native compiler keeps both in its cache, in the runtime-pack family, which prune covers. --- .../src/backend/runtime-pack-native.test.ts | 155 ++++++++++- .../src/backend/runtime-pack-native.ts | 255 ++++++++++++++++-- packages/compiler/src/native/cache.ts | 1 + packages/compiler/src/native/compiler.ts | 32 ++- .../src/native/executable-cache-open.test.ts | 2 +- .../compiler/src/native/executable-cache.ts | 4 +- .../compiler/src/native/sanitizer.test.ts | 1 + packages/compiler/src/native/sanitizer.ts | 11 +- 8 files changed, 432 insertions(+), 29 deletions(-) diff --git a/packages/compiler/src/backend/runtime-pack-native.test.ts b/packages/compiler/src/backend/runtime-pack-native.test.ts index 20214818f..723deba39 100644 --- a/packages/compiler/src/backend/runtime-pack-native.test.ts +++ b/packages/compiler/src/backend/runtime-pack-native.test.ts @@ -1,12 +1,26 @@ +import { createHash } from "node:crypto"; +import { mkdirSync, readFileSync, renameSync, statSync, utimesSync, writeFileSync } from "node:fs"; import { mkdtemp, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import { afterEach, expect, test } from "vitest"; +import { afterEach, expect, test, vi } from "vitest"; import { nativeCodegenDiag } from "../diagnostics/diagnostic.js"; +import { compilerReleaseVersion } from "../library/sidecar.js"; import type { NativeLinkFeatures } from "./native-link-info.js"; -import { RuntimePackError } from "./runtime-pack-core.js"; -import { selectNativeRuntimePack } from "./runtime-pack-native.js"; -import { WASM32_WASI_TARGET } from "./targets.js"; +import { RuntimePackError, type RuntimePackManifest } from "./runtime-pack-core.js"; +import { + runtimePackManifest, + selectNativeRuntimePack, + stageNativeRuntimeSelection, + type NativeRuntimeSelection, + type RuntimePackStore, +} from "./runtime-pack-native.js"; +import { MACOS_ARM64_TARGET, WASM32_WASI_TARGET } from "./targets.js"; + +vi.mock("node:crypto", async (original) => { + const crypto = await original(); + return { ...crypto, createHash: vi.fn(crypto.createHash) }; +}); const dirs: string[] = []; afterEach(async () => @@ -45,3 +59,136 @@ test("a missing native helper keeps the reinstall hint", () => { "reinstall scriptc with optional dependencies enabled for this host", ); }); + +/** A runtime pack with one runtime object and a license, and a store that + * keeps entries in memory. */ +async function packFixture() { + const root = await mkdtemp(join(tmpdir(), "scriptc-runtime-pack-store-")); + dirs.push(root); + const target = MACOS_ARM64_TARGET; + const version = compilerReleaseVersion(); + writeFileSync( + join(root, "package.json"), + JSON.stringify({ name: target.runtimePackPackage, version }), + ); + mkdirSync(join(root, "artifacts")); + const object = join(root, "artifacts", "base.o"); + writeFileSync(object, "base object"); + writeFileSync(join(root, "license.txt"), "license"); + const unit = { + source: "scr_base.c", + predicate: true, + variants: [ + { + id: "default", + when: {}, + defines: [], + path: "artifacts/base.o", + sha256: createHash("sha256").update("base object").digest("hex"), + size: Buffer.byteLength("base object"), + }, + ], + }; + const manifest: RuntimePackManifest = { + schema: "scriptc.runtime-pack.v1", + format: 1, + package: target.runtimePackPackage, + version, + target: { + name: target.name, + llvm_triple: target.llvmTriple, + architecture: target.architecture, + object_format: target.objectFormat, + minimum_os: target.minimumOs, + }, + runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + compiler: { command: "clang", identity: "fixture clang", target: target.llvmTriple }, + macros: { + executable: [], + excluded: ["SCR_LIB", "SCR_THREAD_INSTANCES", "SCR_RC_AUDIT"], + sanitizer: "external-toolchain-required", + }, + flavors: { + release: { optimization: "-O2", runtime_units: [unit] }, + dev: { optimization: "-O0", runtime_units: [unit] }, + }, + archives: [], + system_libraries: [{ name: "System", predicate: true }], + licenses: [{ path: "license.txt", license: "fixture" }], + }; + const manifestText = JSON.stringify(manifest); + writeFileSync(join(root, "runtime-pack.json"), manifestText); + const entries = new Map(); + const store: RuntimePackStore = { + read: (key) => entries.get(key) ?? null, + write: (key, text) => void entries.set(key, text), + }; + const select = () => + selectNativeRuntimePack( + root, + target, + version, + {} as NativeLinkFeatures, + "release", + "executable", + store, + ); + let stages = 0; + const stage = (selection: NativeRuntimeSelection) => { + const directory = join(root, `stage-${stages++}`); + mkdirSync(directory); + return stageNativeRuntimeSelection(selection, directory, store); + }; + return { root, object, manifestText, entries, select, stage }; +} + +test("a stored selection answers while the pack's files keep their identities", async () => { + const f = await packFixture(); + const first = f.select(); + expect(first.selected.systemLibraries).toEqual(["System"]); + expect(f.entries.size).toBe(1); + // The next selection reads the stored answer instead of the manifest. + const [key, text] = [...f.entries][0]!; + const stored = JSON.parse(text); + stored.selected.systemLibraries = ["Stored"]; + f.entries.set(key, JSON.stringify(stored)); + const second = f.select(); + expect(second.selected.systemLibraries).toEqual(["Stored"]); + expect(second.licenses).toEqual(first.licenses); + expect(second.manifest).toBeUndefined(); + expect(runtimePackManifest(second).flavors.release).toEqual(first.manifest!.flavors.release); + // Writing the manifest again, with the same text, gives it a new identity. + writeFileSync(join(f.root, "runtime-pack.json"), f.manifestText); + expect(f.select().selected.systemLibraries).toEqual(["System"]); +}); + +test.each(["replaced", "rewritten in place"])( + "staging hashes an artifact again when it is %s, even at the same size and mtime", + async (change) => { + const f = await packFixture(); + const selection = f.select(); + f.stage(selection); + const before = statSync(f.object); + const changed = change === "replaced" ? f.object + ".new" : f.object; + writeFileSync(changed, "x".repeat(before.size)); + utimesSync(changed, before.atime, before.mtime); + if (changed !== f.object) renameSync(changed, f.object); + expect(() => f.stage(selection)).toThrow( + "runtime pack artifact hash mismatch: artifacts/base.o", + ); + }, +); + +test("staging does not hash an unchanged artifact again", async () => { + const f = await packFixture(); + const selection = f.select(); + const hashes = () => vi.mocked(createHash).mock.calls.length; + let start = hashes(); + f.stage(selection); + const firstStage = hashes() - start; + start = hashes(); + const staged = f.stage(selection); + // Only the store key is hashed; the staged copy has the verified bytes. + expect(hashes() - start).toBe(firstStage - 1); + expect(readFileSync(staged.runtimeObjects[0]!, "utf8")).toBe("base object"); +}); diff --git a/packages/compiler/src/backend/runtime-pack-native.ts b/packages/compiler/src/backend/runtime-pack-native.ts index bd38e2ef0..f51b24221 100644 --- a/packages/compiler/src/backend/runtime-pack-native.ts +++ b/packages/compiler/src/backend/runtime-pack-native.ts @@ -1,6 +1,8 @@ /** Synchronous runtime-pack host for the statically compiled driver. Each - * selected artifact is hashed and copied from the same read into private - * storage. This host has no persistent cache or mutable installed link inputs. */ + * selected artifact is verified and copied from the same read into private + * storage. With a store, a pack's selections and the identities of the + * artifacts it verified are kept between builds: an artifact whose file + * identity is unchanged since it was hashed is not hashed again. */ import type { NativeOptimization } from "./optimization.js"; import { createHash } from "node:crypto"; import { @@ -10,6 +12,7 @@ import { mkdirSync, openSync, readFileSync, + statSync, writeSync, } from "node:fs"; import { dirname, join } from "node:path"; @@ -34,13 +37,63 @@ export interface NativeRuntimePack { export interface NativeRuntimeSelection { root: string; - manifest: RuntimePackManifest; + /** The parsed manifest; a selection read from a store has none until + * runtimePackManifest parses it. */ + manifest?: RuntimePackManifest; + licenses: RuntimePackManifest["licenses"]; packageText: string; manifestText: string; selected: RuntimePackArtifacts; flavor: NativeOptimization; } +/** Text entries kept between builds (the native compiler's cache). */ +export interface RuntimePackStore { + read(key: string): string | null; + write(key: string, text: string): void; +} + +interface FileIdentity { + dev: number; + ino: number; + size: number; + mtime: number; + ctime: number; +} + +function fileIdentity(path: string): FileIdentity { + const info = statSync(path); + return { + dev: info.dev, + ino: info.ino, + size: info.size, + mtime: info.mtimeMs, + ctime: info.ctimeMs, + }; +} + +function sameIdentity(a: FileIdentity, b: FileIdentity): boolean { + return ( + a.dev === b.dev && + a.ino === b.ino && + a.size === b.size && + a.mtime === b.mtime && + a.ctime === b.ctime + ); +} + +function storeKey(text: string): string { + return createHash("sha256").update(text).digest("hex"); +} + +/** A stored selection: what selecting from the pack's files, with these + * identities, returned. */ +interface StoredSelection { + schema: 1; + licenses: RuntimePackManifest["licenses"]; + selected: RuntimePackArtifacts; +} + export function selectNativeRuntimePack( root: string, target: NativeTargetSpec, @@ -48,38 +101,197 @@ export function selectNativeRuntimePack( features: NativeLinkFeatures, flavor: NativeOptimization, mode: RuntimePackMode = "executable", + store?: RuntimePackStore, ): NativeRuntimeSelection { - if (!existsSync(join(root, "package.json"))) { + const packagePath = join(root, "package.json"); + const manifestPath = join(root, "runtime-pack.json"); + if (!existsSync(packagePath)) { throw new RuntimePackError( `runtime pack for ${target.name} is not installed; install ${target.runtimePackPackage}@${compilerVersion} in your project or set SCRIPTC_RUNTIME_PACK to its directory`, "missing", "scriptc includes the runtime pack for its own platform only; other targets need their runtime pack package in the project", ); } - const packageText = readFileSync(join(root, "package.json"), "utf8"); - const manifestText = readFileSync(join(root, "runtime-pack.json"), "utf8"); + // The pack's files by identity, with everything else selection reads. + let key: string | null = null; + let identities: FileIdentity[] = []; + if (store !== undefined) { + try { + identities = [fileIdentity(packagePath), fileIdentity(manifestPath)]; + key = storeKey( + JSON.stringify({ + schema: 1, + root, + identities, + target: target.name, + compilerVersion, + features, + flavor, + mode, + }), + ); + const stored = readStoredSelection(store.read(key)); + if (stored !== null) { + const packageText = readFileSync(packagePath, "utf8"); + const manifestText = readFileSync(manifestPath, "utf8"); + // The texts read are the ones with the stored identities. + if ( + sameIdentity(fileIdentity(packagePath), identities[0]!) && + sameIdentity(fileIdentity(manifestPath), identities[1]!) + ) { + return { + root, + licenses: stored.licenses, + packageText, + manifestText, + selected: stored.selected, + flavor, + }; + } + } + } catch { + key = null; + } + } + const packageText = readFileSync(packagePath, "utf8"); + const manifestText = readFileSync(manifestPath, "utf8"); const identity = JSON.parse(packageText) as { name?: string; version?: string }; const manifest = parseRuntimePackManifest(JSON.parse(manifestText)); validateRuntimePackIdentity(manifest, identity.name, identity.version, target, compilerVersion); const selected = selectRuntimePackArtifacts(manifest, features, flavor, process.env, mode); - return { root, manifest, packageText, manifestText, selected, flavor }; + if (store !== undefined && key !== null) { + try { + // Stored only when the files selected from still have the identities + // in the key. + if ( + sameIdentity(fileIdentity(packagePath), identities[0]!) && + sameIdentity(fileIdentity(manifestPath), identities[1]!) + ) { + const entry: StoredSelection = { schema: 1, licenses: manifest.licenses, selected }; + store.write(key, JSON.stringify(entry)); + } + } catch { + /* A failed write is a later miss. */ + } + } + return { + root, + manifest, + licenses: manifest.licenses, + packageText, + manifestText, + selected, + flavor, + }; } -function stageArtifact(root: string, stage: string, artifact: RuntimePackArtifact): string { +/** The selection's parsed manifest. */ +export function runtimePackManifest(selection: NativeRuntimeSelection): RuntimePackManifest { + return (selection.manifest ??= parseRuntimePackManifest(JSON.parse(selection.manifestText))); +} + +function readStoredSelection(text: string | null): StoredSelection | null { + if (text === null) return null; + const value: unknown = JSON.parse(text); + if (value === null || typeof value !== "object") return null; + const entry = value as Partial; + if ( + entry.schema !== 1 || + !Array.isArray(entry.licenses) || + entry.selected === undefined || + entry.selected === null || + typeof entry.selected !== "object" || + !Array.isArray(entry.selected.runtime) || + !Array.isArray(entry.selected.archives) || + !Array.isArray(entry.selected.systemLibraries) + ) + return null; + return entry as StoredSelection; +} + +/** An artifact path's identity when its bytes last matched the manifest's + * size and digest. */ +interface VerifiedArtifact { + path: string; + sha256: string; + dev: number; + ino: number; + size: number; + mtime: number; + ctime: number; +} + +interface StoredVerification { + schema: number; + artifacts: VerifiedArtifact[]; +} + +function readVerified( + store: RuntimePackStore | undefined, + key: string, +): Map { + const verified = new Map(); + try { + const text = store?.read(key) ?? null; + if (text === null) return verified; + const stored = JSON.parse(text) as StoredVerification; + if (stored.schema === 1) + for (const artifact of stored.artifacts) verified.set(artifact.path, artifact); + } catch { + /* A malformed entry verifies everything again. */ + } + return verified; +} + +function stageArtifact( + root: string, + stage: string, + artifact: RuntimePackArtifact, + verified: Map, + newlyVerified: VerifiedArtifact[], +): string { const source = join(root, artifact.path); const destination = join(stage, artifact.path); let bytes: Buffer; + let before: FileIdentity; + let after: FileIdentity; try { + before = fileIdentity(source); bytes = readFileSync(source); + after = fileIdentity(source); } catch { throw new RuntimePackError(`runtime pack artifact is missing: ${artifact.path}`, "invalid"); } + // The bytes are those last hashed when the file kept the identity it had + // then for the whole read. + const known = verified.get(artifact.path); + const unchanged = sameIdentity(before, after); + const trusted = + known !== undefined && + known.sha256 === artifact.sha256 && + known.size === artifact.size && + unchanged && + known.dev === before.dev && + known.ino === before.ino && + known.size === before.size && + known.mtime === before.mtime && + known.ctime === before.ctime; if ( bytes.length !== artifact.size || - createHash("sha256").update(bytes).digest("hex") !== artifact.sha256 + (!trusted && createHash("sha256").update(bytes).digest("hex") !== artifact.sha256) ) { throw new RuntimePackError(`runtime pack artifact hash mismatch: ${artifact.path}`, "invalid"); } + if (!trusted && unchanged) + newlyVerified.push({ + path: artifact.path, + sha256: artifact.sha256, + dev: before.dev, + ino: before.ino, + size: before.size, + mtime: before.mtime, + ctime: before.ctime, + }); mkdirSync(dirname(destination), { recursive: true }); const fd = openSync( destination, @@ -123,15 +335,19 @@ export function stageNativeRuntimePack( export function stageNativeRuntimeSelection( selection: NativeRuntimeSelection, stageRoot: string, + store?: RuntimePackStore, ): NativeRuntimePack { - const { root, manifest, selected, packageText, manifestText } = selection; + const { root, licenses, selected, packageText, manifestText } = selection; const packagePath = join(root, "package.json"); const manifestPath = join(root, "runtime-pack.json"); - const runtimeObjects = selected.runtime.map((artifact) => - stageArtifact(root, stageRoot, artifact), - ); - const archives = selected.archives.map((artifact) => stageArtifact(root, stageRoot, artifact)); - for (const license of manifest.licenses) { + const key = storeKey(JSON.stringify({ schema: 1, verified: root })); + const verified = readVerified(store, key); + const newlyVerified: VerifiedArtifact[] = []; + const stage = (artifact: RuntimePackArtifact): string => + stageArtifact(root, stageRoot, artifact, verified, newlyVerified); + const runtimeObjects = selected.runtime.map(stage); + const archives = selected.archives.map(stage); + for (const license of licenses) { try { readFileSync(join(root, license.path)); } catch { @@ -144,5 +360,14 @@ export function stageNativeRuntimeSelection( ) { throw new RuntimePackError("runtime pack changed while staging verified artifacts", "invalid"); } + if (store !== undefined && newlyVerified.length > 0) { + for (const artifact of newlyVerified) verified.set(artifact.path, artifact); + const entry: StoredVerification = { schema: 1, artifacts: [...verified.values()] }; + try { + store.write(key, JSON.stringify(entry)); + } catch { + /* A failed write only means hashing again next time. */ + } + } return { runtimeObjects, archives, systemLibraries: selected.systemLibraries }; } diff --git a/packages/compiler/src/native/cache.ts b/packages/compiler/src/native/cache.ts index 937b4b109..f48410d1d 100644 --- a/packages/compiler/src/native/cache.ts +++ b/packages/compiler/src/native/cache.ts @@ -179,6 +179,7 @@ export class NativeCache { "sanitizer", "executable", "linked", + "runtime-pack", "binary", "dsym", "coverage", diff --git a/packages/compiler/src/native/compiler.ts b/packages/compiler/src/native/compiler.ts index 63769fba6..bcd5c1935 100644 --- a/packages/compiler/src/native/compiler.ts +++ b/packages/compiler/src/native/compiler.ts @@ -31,7 +31,9 @@ import { } from "../backend/native-tools.js"; import { selectNativeRuntimePack, + runtimePackManifest, stageNativeRuntimeSelection, + type RuntimePackStore, } from "../backend/runtime-pack-native.js"; import { RuntimePackError } from "../backend/runtime-pack-core.js"; import { @@ -160,6 +162,17 @@ export class NativeCompiler { return result; } + /** Runtime pack selections and verified artifact identities, kept in the + * cache. */ + private runtimePackStore(): RuntimePackStore | undefined { + const cache = this.cache; + if (cache === null) return undefined; + return { + read: (key) => cache.read("runtime-pack", key)?.toString("utf8") ?? null, + write: (key, text) => cache.write("runtime-pack", key, text), + }; + } + private emitObject( input: string, output: string, @@ -394,6 +407,8 @@ export class NativeCompiler { toolchain.compilerVersion, features, optimization, + "executable", + this.runtimePackStore(), ) : null; const executableCache = @@ -449,16 +464,24 @@ export class NativeCompiler { toolchain.compilerVersion, features, optimization, + "executable", + this.runtimePackStore(), ) : null; - if (pack !== null) stageNativeRuntimeSelection(pack, join(stage, "runtime")); + if (pack !== null) + stageNativeRuntimeSelection(pack, join(stage, "runtime"), this.runtimePackStore()); const info = pack === null ? undefined : formatNativeLinkInfo( { programObject: output, target, ffi }, toolchain.compilerVersion, - pack, + { + root: pack.root, + manifest: runtimePackManifest(pack), + selected: pack.selected, + flavor: pack.flavor, + }, ); renameSync(stagedOutput, output); return { @@ -473,7 +496,7 @@ export class NativeCompiler { const pack = executablePack!; const runtime = options.sanitize ? buildSanitizedRuntime(toolchain, pack, join(stage, "runtime"), "executable", this.cache) - : stageNativeRuntimeSelection(pack, join(stage, "runtime")); + : stageNativeRuntimeSelection(pack, join(stage, "runtime"), this.runtimePackStore()); timing("runtime-stage"); const plan = executableLinkInputs({ target, @@ -617,6 +640,7 @@ export class NativeCompiler { features, profile.optimization, profile.instancePerThread ? "library-thread" : "library", + this.runtimePackStore(), ); const runtime = options.sanitize ? buildSanitizedRuntime( @@ -626,7 +650,7 @@ export class NativeCompiler { profile.instancePerThread ? "library-thread" : "library", this.cache, ) - : stageNativeRuntimeSelection(pack, join(stage, "runtime")); + : stageNativeRuntimeSelection(pack, join(stage, "runtime"), this.runtimePackStore()); timing("runtime-stage"); const stagedArchive = join(stage, wasm ? "output.wasm" : "output.a"); const localizeSymbols = libraryLocalizeSymbols(profile); diff --git a/packages/compiler/src/native/executable-cache-open.test.ts b/packages/compiler/src/native/executable-cache-open.test.ts index 05e57148d..09a8b9cc9 100644 --- a/packages/compiler/src/native/executable-cache-open.test.ts +++ b/packages/compiler/src/native/executable-cache-open.test.ts @@ -52,7 +52,7 @@ function fixture(platform: string, driver: string) { } as unknown as NativeToolchain; const pack = { root: runtime, - manifest: { licenses: [] }, + licenses: [], packageText: "{}", manifestText: "{}", selected: { runtime: [], archives: [] }, diff --git a/packages/compiler/src/native/executable-cache.ts b/packages/compiler/src/native/executable-cache.ts index 1dfbf0b00..74c935d88 100644 --- a/packages/compiler/src/native/executable-cache.ts +++ b/packages/compiler/src/native/executable-cache.ts @@ -331,8 +331,8 @@ export function openNativeExecutableCache( join(toolchain.helperPackageRoot, "package.json"), join(toolchain.runtimePackRoot, "package.json"), join(toolchain.runtimePackRoot, "runtime-pack.json"), - ...[...pack.selected.runtime, ...pack.selected.archives, ...pack.manifest.licenses].map( - (artifact) => join(pack.root, artifact.path), + ...[...pack.selected.runtime, ...pack.selected.archives, ...pack.licenses].map((artifact) => + join(pack.root, artifact.path), ), ]; if (platform === "linux") paths.push(join(pack.root, "runtime-pack.json")); diff --git a/packages/compiler/src/native/sanitizer.test.ts b/packages/compiler/src/native/sanitizer.test.ts index 1415f2971..31a8c3355 100644 --- a/packages/compiler/src/native/sanitizer.test.ts +++ b/packages/compiler/src/native/sanitizer.test.ts @@ -64,6 +64,7 @@ test.skipIf(process.platform !== "linux" && process.platform !== "darwin")( { root: directory, manifest, + licenses: manifest.licenses, packageText: "", manifestText: "", flavor: "dev", diff --git a/packages/compiler/src/native/sanitizer.ts b/packages/compiler/src/native/sanitizer.ts index cb3728ec0..5d228a615 100644 --- a/packages/compiler/src/native/sanitizer.ts +++ b/packages/compiler/src/native/sanitizer.ts @@ -4,7 +4,11 @@ import { mkdirSync, readFileSync, readdirSync, writeFileSync } from "node:fs"; import { basename, join } from "node:path"; import { NativeCodegenError } from "../backend/native-codegen-core.js"; import { requireNativeArtifact, runNativeTool } from "../backend/native-tools.js"; -import type { NativeRuntimePack, NativeRuntimeSelection } from "../backend/runtime-pack-native.js"; +import { + runtimePackManifest, + type NativeRuntimePack, + type NativeRuntimeSelection, +} from "../backend/runtime-pack-native.js"; import { runtimePackFlavorKey, type RuntimePackMode } from "../backend/runtime-pack-core.js"; import { LRE_SOURCES, ZLIB_SOURCES } from "../backend/vendor-inputs.js"; import { contentDigest, type NativeCache } from "./cache.js"; @@ -119,8 +123,9 @@ export function buildSanitizedRuntime( } return output; }; - const key = runtimePackFlavorKey(selection.manifest, selection.flavor, mode); - const flavor = selection.manifest.flavors[key]; + const manifest = runtimePackManifest(selection); + const key = runtimePackFlavorKey(manifest, selection.flavor, mode); + const flavor = manifest.flavors[key]; if (flavor === undefined) throw new NativeCodegenError("SC3003", `runtime pack lacks ${key}`); const wanted = new Set(selection.selected.runtime.map((artifact) => artifact.path)); const common = [ From 580e8ac7234896a9d6aa2f559c27b1ad3afe2d7e Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 09:34:59 -0500 Subject: [PATCH 095/259] Analyze int32 slots in queue order, after fixing an order-dependent narrowing --- packages/compiler/src/ir/int32-slots.test.ts | 6 ++++++ packages/compiler/src/ir/int32-slots.ts | 15 ++++++++++++--- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/compiler/src/ir/int32-slots.test.ts b/packages/compiler/src/ir/int32-slots.test.ts index 0739bbb4f..b94dee341 100644 --- a/packages/compiler/src/ir/int32-slots.test.ts +++ b/packages/compiler/src/ir/int32-slots.test.ts @@ -523,6 +523,12 @@ test("counting-down recursion proves its parameter from the call-site ranges", ( ); const rising = analyzeInt32Slots(mod([], [up, fn("user", [], [stmt(call("up", [num(-18)]))])])); expect(rising.facts("up").params?.get("d")).toEqual({ min: -18, max: 0 }); + // The same with the caller first, so the fixpoint analyzes it after the + // parameter dropped: the narrowing still sees its argument. + const callerFirst = analyzeInt32Slots( + mod([], [fn("user", [], [stmt(call("up", [num(-18)]))]), up]), + ); + expect(callerFirst.facts("up").params?.get("d")).toEqual({ min: -18, max: 0 }); // A negative start counts down past the smallest int32. const negative = analyzeInt32Slots(mod([], [count, even, odd, user([18, -1])])); diff --git a/packages/compiler/src/ir/int32-slots.ts b/packages/compiler/src/ir/int32-slots.ts index 06a173c1a..1616a2a77 100644 --- a/packages/compiler/src/ir/int32-slots.ts +++ b/packages/compiler/src/ir/int32-slots.ts @@ -1208,8 +1208,11 @@ export function analyzeInt32Slots(mod: IrModule, inputs: Int32SlotInputs = {}): // Each function's parameter and result writes under its latest analysis: // at the fixpoint, the ranges of every write under the final facts. const lastWrites = new Map>(); - while (queue.length) { - const fn = functions.get(queue.pop()!)!; + // First in, first out: a function whose slots change while others wait + // goes after them, so a caller of many callees is analyzed again once + // for all of their changes, not once for each. + for (let head = 0; head < queue.length; head++) { + const fn = functions.get(queue[head]!)!; queued.delete(fn.name); const params = slots.facts(fn.name).params; if (params) for (const id of params.keys()) reads(`param:${fn.name}\0${id}`, fn.name); @@ -1663,8 +1666,14 @@ function narrowSlotRanges( // The ranges every function was last analyzed under. let analyzed: Map = new Map(proven); let verified: Map = new Map(proven); - // Functions whose recorded writes predate their current facts. + // Functions whose recorded writes predate their current facts: those + // whose parameters rangedParameters proved, and their callers, which + // wrote nothing into those parameters while they had no fact. const dirty = new Set(changed); + for (const name of changed) { + const callers = readersOf(`ret:${name}`); + if (callers) for (const caller of callers) dirty.add(caller); + } // The narrowing operator: a bound moves at most once from its proven // value (a revived result's from int32), so recursion that shifts its // argument (`f(d - 1)`) cannot walk a bound down one step per round. From 537dfbeb687f1022e68978c68a524e65cf468043 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 09:37:24 -0500 Subject: [PATCH 096/259] Evaluate assert.fail's value messages after declaring them, with Node's defaults assert.fail with a message that is not a string read the message's hidden locals before they were declared: the call stored the message and its generated flag in temporaries ahead of the message's declarations, so `assert.fail(new RangeError('re'))` crashed. Arguments computed from the message now read it after the declarations. assert.fail also follows Node's defaults for such values: null and undefined report "Failed" with generatedMessage true, an Error is thrown as is, and any other value, falsy ones included, becomes the message as its string, with generatedMessage set to !value. --- .../src/frontend/lowering/lower-assert.ts | 76 ++++++++++++------- tests/corpus/8062-assert-message-values.cjs | 7 ++ 2 files changed, 57 insertions(+), 26 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/lower-assert.ts b/packages/compiler/src/frontend/lowering/lower-assert.ts index 39ec9c959..02faa7ade 100644 --- a/packages/compiler/src/frontend/lowering/lower-assert.ts +++ b/packages/compiler/src/frontend/lowering/lower-assert.ts @@ -57,6 +57,7 @@ import { typeKey, } from "../../ir/ir.js"; import { boolLit, countedFor, dynUndefinedExpr, numLit, strLit, varRef } from "../../ir/build.js"; +import { everyExpr } from "../../ir/traverse.js"; import { checkedClassInstanceOf } from "./class-construction.js"; import { isJsSourceFile } from "../program.js"; @@ -231,8 +232,9 @@ function requireStatementPosition(lowerer: Lowerer, call: ts.CallExpression, wha const VALUE_MESSAGE = "\u0001scriptc:assert-message-value"; /** A message argument that is not a string, met while one assertion - * lowers (withValueMessage). */ -let valueMessage: { value: IrExpr; has: string; text: string } | null = null; + * lowers (withValueMessage). `fail` marks assert.fail's message, which + * Node uses for every value but null and undefined. */ +let valueMessage: { value: IrExpr; has: string; text: string; fail: boolean } | null = null; /** The optional trailing message argument: Node accepts a string or an * Error (throwing the Error itself) — the STRING form lowers; a literal @@ -246,6 +248,7 @@ function lowerMessageArg( lowerer: Lowerer, node: ts.Expression | undefined, loc: SrcLoc, + fail = false, ): { msg: IrExpr; hasMsg: IrExpr } { if (!node || (ts.isIdentifier(node) && node.text === "undefined")) { return { msg: { kind: "strLit", value: "", type: STRING, loc }, hasMsg: boolLit(false, loc) }; @@ -265,7 +268,7 @@ function lowerMessageArg( } const has = lowerer.declareHiddenLocal("assert.hasMessage", BOOL); const text = lowerer.declareHiddenLocal("assert.messageText", STRING); - valueMessage = { value, has: has.id, text: text.id }; + valueMessage = { value, has: has.id, text: text.id, fail }; return { msg: varRef(text.id, STRING, loc), hasMsg: varRef(has.id, BOOL, loc) }; } @@ -285,7 +288,12 @@ function withValueMessage( valueMessage = null; try { const lowered = lower(); - const message = valueMessage as { value: IrExpr; has: string; text: string } | null; + const message = valueMessage as { + value: IrExpr; + has: string; + text: string; + fail: boolean; + } | null; if (lowered === null || message === null) return lowered; // assert.ok's statements evaluate the value first; its call is last. const before = lowered.kind === "seqExpr" ? lowered.stmts : []; @@ -298,13 +306,25 @@ function withValueMessage( ); } const stmts: IrStmt[] = [...before]; + // An argument computed from the message (assert.fail's generated flag) + // reads it after the declarations below; the others are evaluated first. + const readsMessage = (arg: IrExpr): boolean => + !everyExpr(arg, { + stmt: () => true, + expr: (e) => + !(e.kind === "varRef" && (e.localId === message.has || e.localId === message.text)), + }); const args = call.args.map((arg, index) => - arg.kind === "varRef" && (arg.localId === message.has || arg.localId === message.text) - ? arg - : stableValue(lowerer, stmts, arg, `assert.arg${index}`, loc), + readsMessage(arg) ? arg : stableValue(lowerer, stmts, arg, `assert.arg${index}`, loc), ); const local = lowerer.declareHiddenLocal("assert.message", DYN); const value = varRef(local.id, DYN, loc); + // The runtime reports a registered value: a truthy one for the other + // methods, any value but null and undefined for assert.fail (Node's + // `actual == null` test), whose other values read "Failed". + const registered: IrExpr = message.fail + ? varRef(message.has, BOOL, loc) + : { kind: "dynTest", test: "truthy", value, type: BOOL, loc }; stmts.push( { kind: "varDecl", localId: local.id, init: message.value, loc }, { @@ -318,9 +338,9 @@ function withValueMessage( localId: message.text, init: { kind: "ternary", - cond: { kind: "dynTest", test: "truthy", value, type: BOOL, loc }, + cond: registered, then: strLit(VALUE_MESSAGE, loc), - else_: strLit("", loc), + else_: strLit(message.fail ? "Failed" : "", loc), type: STRING, loc, }, @@ -328,7 +348,7 @@ function withValueMessage( }, { kind: "if", - cond: { kind: "dynTest", test: "truthy", value, type: BOOL, loc }, + cond: registered, then: [ { kind: "exprStmt", @@ -1148,22 +1168,26 @@ function lowerAssertFail(lowerer: Lowerer, expr: ts.CallExpression, loc: SrcLoc) generated = boolLit(true, loc); } else { // Node's AssertionError sets generatedMessage to !message, so an - // empty custom message counts as generated. - msg = stableValue( - lowerer, - stmts, - lowerMessageArg(lowerer, msgNode, loc).msg, - "%assertFailMessage", - loc, - ); - generated = { - kind: "strEq", - negated: false, - left: msg, - right: strLit("", loc), - type: BOOL, - loc, - }; + // empty custom message counts as generated. A message that is not a + // string is read from the hidden local that withValueMessage declares + // after these statements, so it is used as is. + const { msg: lowered, hasMsg } = lowerMessageArg(lowerer, msgNode, loc, true); + if (lowered.kind === "varRef" && hasMsg.kind === "varRef") { + // A value message: generated when Node reads "Failed" for null or + // undefined; the runtime sets the flag for a registered value. + msg = lowered; + generated = { kind: "unary", op: "!", operand: hasMsg, type: BOOL, loc }; + } else { + msg = stableValue(lowerer, stmts, lowered, "%assertFailMessage", loc); + generated = { + kind: "strEq", + negated: false, + left: msg, + right: strLit("", loc), + type: BOOL, + loc, + }; + } } const falseLit: IrExpr = { kind: "boolLit", value: false, type: BOOL, loc }; stmts.push(recordOnFailure(lowerer, boolLit(true, loc), null, null, "fail", loc)); diff --git a/tests/corpus/8062-assert-message-values.cjs b/tests/corpus/8062-assert-message-values.cjs index 7f84ccd37..fc37a71e4 100644 --- a/tests/corpus/8062-assert-message-values.cjs +++ b/tests/corpus/8062-assert-message-values.cjs @@ -39,3 +39,10 @@ const row = [['a', 'b', true], ['c', 'd', 'x']]; for (const [, , expected] of row) { attempt('union operand', () => assert.strictEqual(JSON.parse(JSON.stringify(expected)), expected)); } + +// assert.fail with a message that is not a string: an Error is thrown as +// is; other values become the message, generated when falsy. +attempt('fail error', () => assert.fail(new RangeError('re'))); +attempt('fail value', () => assert.fail(JSON.parse('{"a":1}'))); +attempt('fail zero', () => assert.fail(zero)); +attempt('fail null', () => assert.fail(JSON.parse('null'))); From e792cf47713ad7c0e23b2ab10e4f089be894bc69 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 09:49:01 -0500 Subject: [PATCH 097/259] Test RSA-PSS verification with an automatic salt length on restricted keys Node recovers the salt length under RSA_PSS_SALTLEN_AUTO without enforcing the minimum in an RSA-PSS key's parameters, while an explicit saltLength below it throws and the default saltLength requires the key's. The corpus program pins that behavior for MGF1 digests equal to and different from the message digest, through crypto.verify and createVerify. --- .../8178-rsa-pss-auto-min-salt.cjs.json | 6 ++ tests/corpus/8178-rsa-pss-auto-min-salt.cjs | 57 +++++++++++++++++++ .../8178-rsa-pss-auto-min-salt.cjs.json | 1 + 3 files changed, 64 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8178-rsa-pss-auto-min-salt.cjs.json create mode 100644 tests/corpus/8178-rsa-pss-auto-min-salt.cjs create mode 100644 tests/harness/corpus-costs/8178-rsa-pss-auto-min-salt.cjs.json diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8178-rsa-pss-auto-min-salt.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8178-rsa-pss-auto-min-salt.cjs.json new file mode 100644 index 000000000..7b3e5eef7 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8178-rsa-pss-auto-min-salt.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8178-rsa-pss-auto-min-salt.cjs" + ], + "diags": [] +} diff --git a/tests/corpus/8178-rsa-pss-auto-min-salt.cjs b/tests/corpus/8178-rsa-pss-auto-min-salt.cjs new file mode 100644 index 000000000..97b9d1c05 --- /dev/null +++ b/tests/corpus/8178-rsa-pss-auto-min-salt.cjs @@ -0,0 +1,57 @@ +// Verifying with RSA_PSS_SALTLEN_AUTO against an RSA-PSS key whose +// parameters set a minimum salt length still enforces that minimum, as in +// Node: a valid signature with a shorter salt does not verify. The keys use +// an MGF1 digest equal to the message digest and a different one. The +// stricter public key is the generated one with its minimum salt length +// raised from 16 to 32 in its DER. +const c = require("node:crypto"); + +const data = Buffer.from("restricted salt"); + +function raiseMinimumSalt(publicKey) { + const der = publicKey.export({ format: "der", type: "spki" }); + const from = Buffer.from([0xa2, 0x03, 0x02, 0x01, 0x10]); + const at = der.indexOf(from); + if (at < 0) throw new Error("no saltLength field"); + der[at + 4] = 0x20; + return c.createPublicKey({ key: der, format: "der", type: "spki" }); +} + +function attempt(label, fn) { + try { + console.log(label, fn()); + } catch (e) { + console.log(label, "throws", e.code, e.message); + } +} + +for (const mgf1HashAlgorithm of ["sha256", "sha384"]) { + const { privateKey, publicKey } = c.generateKeyPairSync("rsa-pss", { + modulusLength: 1024, + hashAlgorithm: "sha256", + mgf1HashAlgorithm, + saltLength: 16, + }); + const strict = raiseMinimumSalt(publicKey); + const { mgf1HashAlgorithm: mgf1, saltLength: minimum } = strict.asymmetricKeyDetails; + console.log(mgf1HashAlgorithm, "strict key", mgf1, minimum); + for (const saltLength of [16, 20, 32, 40]) { + const signature = c.sign("sha256", data, { key: privateKey, saltLength }); + const label = `${mgf1HashAlgorithm} salt ${saltLength}`; + attempt(`${label} auto, key minimum 16:`, () => + c.verify("sha256", data, { key: publicKey, saltLength: c.constants.RSA_PSS_SALTLEN_AUTO }, signature), + ); + attempt(`${label} auto, key minimum 32:`, () => + c.verify("sha256", data, { key: strict, saltLength: c.constants.RSA_PSS_SALTLEN_AUTO }, signature), + ); + attempt(`${label} default, key minimum 32:`, () => c.verify("sha256", data, strict, signature)); + attempt(`${label} digest length, key minimum 32:`, () => + c.verify("sha256", data, { key: strict, saltLength: c.constants.RSA_PSS_SALTLEN_DIGEST }, signature), + ); + const v = c.createVerify("sha256"); + v.update(data); + attempt(`${label} createVerify auto, key minimum 32:`, () => + v.verify({ key: strict, saltLength: c.constants.RSA_PSS_SALTLEN_AUTO }, signature), + ); + } +} diff --git a/tests/harness/corpus-costs/8178-rsa-pss-auto-min-salt.cjs.json b/tests/harness/corpus-costs/8178-rsa-pss-auto-min-salt.cjs.json new file mode 100644 index 000000000..b1711dea1 --- /dev/null +++ b/tests/harness/corpus-costs/8178-rsa-pss-auto-min-salt.cjs.json @@ -0,0 +1 @@ +{ "plain": 5740, "san": 60808 } From 648e8e05c6dccf163690ba362e5f7d1f69862873 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 09:50:02 -0500 Subject: [PATCH 098/259] Read the node index in more LLVM emission analyses Several analyses the emitter runs per function or per module walked whole bodies to collect facts from a few node kinds. They now read those kinds from the module's node index (ir/node-index.ts), which records every node once in walk order, and the output is unchanged. - numberGlobalWriters, readsLoopMetrics, closure creation sites (LazyCaptures) and the ambient receiver readers visit only the kinds they inspect. - findLoopArrayBorrows visits only loop statements, and findIntegerViews returns at once for a function without a loop, where it wants no view. - foldConstantGlobals records which candidates each function reads during its write walk instead of walking every function again. --- .../src/backend/llvm/emit-function.ts | 3 +- packages/compiler/src/backend/llvm/emitter.ts | 50 ++++++----- .../src/backend/llvm/integer-views.ts | 12 ++- .../src/backend/llvm/lazy-captures.ts | 16 ++-- .../src/backend/llvm/loop-array-borrows.ts | 14 +++- packages/compiler/src/ir/constant-globals.ts | 20 +++-- packages/compiler/src/ir/receiver-readers.ts | 82 +++++++++++++------ 7 files changed, 135 insertions(+), 62 deletions(-) diff --git a/packages/compiler/src/backend/llvm/emit-function.ts b/packages/compiler/src/backend/llvm/emit-function.ts index d7efafd36..e015c2d72 100644 --- a/packages/compiler/src/backend/llvm/emit-function.ts +++ b/packages/compiler/src/backend/llvm/emit-function.ts @@ -159,6 +159,7 @@ export function emitFunction(emitter: LlEmitter, fn: IrFunction): string { emitter.optionalArrayReads, emitter.referenceWrites, emitter.fnByName, + emitter.nodeIndex, ) : new Set(); emitter.localArrayReads = findLocalArrayReads( @@ -324,7 +325,7 @@ export function emitFunction(emitter: LlEmitter, fn: IrFunction): string { const paramIds = new Set(fn.params.map((p) => p.localId)); if (emitter.debug === null) { - for (const id of findIntegerViews(numericFn)) { + for (const id of findIntegerViews(numericFn, emitter.nodeIndex)) { // An i32 slot is its own view. if (emitter.int32Locals.has(id)) continue; const slot = B.slot(); diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 59b4b64a4..6729da197 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -176,7 +176,7 @@ import { type MapEntryFusion } from "./map-entry-fusion.js"; import { emitBorrowedFieldSequence, guardedValue } from "./borrowed-receivers.js"; import { emitBorrowedInputs } from "./borrowed-inputs.js"; import { findWalkBorrows, type WalkBorrowHost } from "./walk-borrows.js"; -import { IrNodeIndex } from "../../ir/node-index.js"; +import { eachNodeOfKinds, IrNodeIndex, type IrNodeKind } from "../../ir/node-index.js"; import { lastUseRead } from "./local-extents.js"; import { findReboundParameters } from "./rebound-parameters.js"; import { ReferenceEffects } from "./reference-effects.js"; @@ -621,6 +621,11 @@ export function llStrBytes(text: string): string { const NO_BORROWED: ReadonlySet = new Set(); +/** The nodes that write a binding by its id (numberGlobalWriters). */ +const GLOBAL_WRITE_KINDS: readonly IrNodeKind[] = ["assign", "varDecl", "assignExpr", "incDec"]; +/** Runtime library calls (readsLoopMetrics). */ +const LIB_CALL_KINDS: readonly IrNodeKind[] = ["libCall"]; + /** [A-Za-z0-9_] */ function isIdentifierByte(code: number): boolean { return ( @@ -1842,9 +1847,9 @@ export class LlEmitter { ) : NO_INTEGER_CLONES; this.stackCallbacks = new StackCallbacks(this.fnByName); - this.receiverReaders = new AmbientReceiverReaders(this.fnByName); + this.receiverReaders = new AmbientReceiverReaders(this.fnByName, this.nodeIndex); this.stackCaptures = new StackCaptures(this.fnByName, this.callLifetimes, this.stackCallbacks); - this.lazyCaptures = new LazyCaptures(this.fnByName); + this.lazyCaptures = new LazyCaptures(this.fnByName, this.nodeIndex); const traced = computeTraced(mod, dynamicStores, cycleMutability); this.tracedShapes = traced.shapes; this.tracedUnions = traced.unions; @@ -3621,15 +3626,14 @@ export class LlEmitter { set.add(fn.name); writers.set(localId, set); }; - everyStmtList(fn.body, { - stmt: (s) => { - if (s.kind === "assign" || s.kind === "varDecl") note(s.localId); - return true; - }, - expr: (e) => { - if (e.kind === "assignExpr" || e.kind === "incDec") note(e.localId); - return true; - }, + eachNodeOfKinds(fn, this.nodeIndex.scan(GLOBAL_WRITE_KINDS), (node) => { + if ( + node.kind === "assign" || + node.kind === "varDecl" || + node.kind === "assignExpr" || + node.kind === "incDec" + ) + note(node.localId); }); } this.globalWriters = writers; @@ -5409,13 +5413,21 @@ export class LlEmitter { private loopMetricsRead: boolean | undefined; readsLoopMetrics(): boolean { if (this.loopMetricsRead !== undefined) return this.loopMetricsRead; - const visitor = { - expr: (e: IrExpr): boolean => - !(e.kind === "libCall" && (e.fn === "perf.loopStart" || e.fn === "perf.idleTime")), - stmt: (): boolean => true, - }; - this.loopMetricsRead = !this.mod.functions.every((fn) => everyStmtList(fn.body, visitor)); - return this.loopMetricsRead; + let found = false; + const scan = this.nodeIndex.scan(LIB_CALL_KINDS); + for (const fn of this.mod.functions) { + eachNodeOfKinds(fn, scan, (node) => { + if ( + node.kind === "libCall" && + (node.fn === "perf.loopStart" || node.fn === "perf.idleTime") + ) + found = true; + return !found; + }); + if (found) break; + } + this.loopMetricsRead = found; + return found; } private lastUseMovesAllowed(): boolean { diff --git a/packages/compiler/src/backend/llvm/integer-views.ts b/packages/compiler/src/backend/llvm/integer-views.ts index c38770160..579f010a2 100644 --- a/packages/compiler/src/backend/llvm/integer-views.ts +++ b/packages/compiler/src/backend/llvm/integer-views.ts @@ -1,6 +1,9 @@ import type { IrExpr, IrFunction, IrStmt } from "../../ir/ir.js"; import { everyExprChild, everyStmtChild } from "../../ir/traverse.js"; import { byteNumberAccess } from "../../ir/byte-numbers.js"; +import { eachNodeOfKinds, type IrNodeIndex, type IrNodeKind } from "../../ir/node-index.js"; + +const LOOP_KINDS: readonly IrNodeKind[] = ["for", "forOf", "while", "doWhile"]; /** Keep a computed ToUint32 view beside an ordinary number when integer * consumers in loops can reuse it. The number remains authoritative for floating @@ -14,9 +17,16 @@ import { byteNumberAccess } from "../../ir/byte-numbers.js"; * compare converts the stored number back, and LLVM moves that number's * conversion into the join of a NaN-coded typed-array read (`phi [sitofp x, * 0.0]`), where nothing folds it back to the integer. */ -export function findIntegerViews(fn: IrFunction): Set { +export function findIntegerViews(fn: IrFunction, nodes?: IrNodeIndex): Set { const wanted = new Set(); if (fn.async || fn.generator) return wanted; + // Every view is wanted inside a loop: a body without one wants none. + let loops = false; + eachNodeOfKinds(fn, nodes?.scan(LOOP_KINDS), (node, statement) => { + if (statement && LOOP_KINDS.includes(node.kind)) loops = true; + return !loops; + }); + if (!loops) return wanted; const initialized = new Set(fn.params.map((p) => p.localId)); const excluded = new Set( [...(fn.captures ?? []), ...(fn.classCaptures ?? [])].map((c) => c.localId), diff --git a/packages/compiler/src/backend/llvm/lazy-captures.ts b/packages/compiler/src/backend/llvm/lazy-captures.ts index 2014869af..85acff2ef 100644 --- a/packages/compiler/src/backend/llvm/lazy-captures.ts +++ b/packages/compiler/src/backend/llvm/lazy-captures.ts @@ -1,5 +1,8 @@ import type { IrExpr, IrFunction, IrStmt } from "../../ir/ir.js"; import { everyStmtList } from "../../ir/traverse.js"; +import { eachNodeOfKinds, type IrNodeIndex, type IrNodeKind } from "../../ir/node-index.js"; + +const CLOSURE_KINDS: readonly IrNodeKind[] = ["closure"]; /** The local a node rebinds. Writes through the bound reference, such as a * field store or an array push, leave the binding unchanged. Catch bindings @@ -37,7 +40,11 @@ export class LazyCaptures { private readonly pending = new Set(); private sites: Map | null = null; - constructor(private readonly functions: ReadonlyMap) {} + constructor( + private readonly functions: ReadonlyMap, + /** The module's node index, read instead of walking the bodies it holds. */ + private readonly nodes?: IrNodeIndex, + ) {} /** The captures of closure body `fnName` that hold one value for the * closure's whole life: at every creation site the captured binding is @@ -103,16 +110,15 @@ export class LazyCaptures { private creationSites(): Map { if (this.sites !== null) return this.sites; const sites = new Map(); + const scan = this.nodes?.scan(CLOSURE_KINDS); for (const fn of this.functions.values()) { - const visit = (node: IrStmt | IrExpr): boolean => { + eachNodeOfKinds(fn, scan, (node) => { if (node.kind === "closure") { let list = sites.get(node.fnName); if (!list) sites.set(node.fnName, (list = [])); list.push({ owner: fn.name, captures: node.captures }); } - return true; - }; - everyStmtList(fn.body, { stmt: visit, expr: visit }); + }); } this.sites = sites; return sites; diff --git a/packages/compiler/src/backend/llvm/loop-array-borrows.ts b/packages/compiler/src/backend/llvm/loop-array-borrows.ts index 9335894d9..cc9e03a5c 100644 --- a/packages/compiler/src/backend/llvm/loop-array-borrows.ts +++ b/packages/compiler/src/backend/llvm/loop-array-borrows.ts @@ -1,5 +1,6 @@ import { F64, isRefCounted, type IrExpr, type IrFunction, type IrStmt } from "../../ir/ir.js"; import { everyStmtList, transformStmtList } from "../../ir/traverse.js"; +import { eachNodeOfKinds, type IrNodeIndex, type IrNodeKind } from "../../ir/node-index.js"; import type { CallLifetimes } from "./call-lifetimes.js"; import type { ReferenceEffects } from "./reference-effects.js"; import type { OptionalArrayReads } from "./local-array-reads.js"; @@ -57,6 +58,8 @@ export function dynHoleRead(value: IrExpr): (IrExpr & { kind: "arrayGet" }) | nu return same(cond.left.arr, then.arr) && same(cond.left.index, then.index) ? then : null; } +const LOOP_KINDS: readonly IrNodeKind[] = ["forOf", "for", "while", "doWhile"]; + /** Limit a borrow to a loop whose complete iteration preserves heap edges. * Initialization and unrelated work elsewhere in the function may mutate. * The array remains owned by its unchanged local or global binding; the @@ -72,6 +75,8 @@ export function findLoopArrayBorrows( optionalReads?: OptionalArrayReads, writes?: ReferenceWrites | null, functions?: ReadonlyMap, + /** The module's node index, read instead of walking for the loops. */ + nodes?: IrNodeIndex, ): ReadonlySet { const result = new Set(); if (fn.async || fn.generator) return result; @@ -88,9 +93,10 @@ export function findLoopArrayBorrows( (!local.boxed && !local.tdz && (bindings?.has(local.id) || parameters.has(local.id))) ); }; - everyStmtList(fn.body, { - expr: () => true, - stmt: (loop) => { + eachNodeOfKinds(fn, nodes?.scan(LOOP_KINDS), (node, statement) => { + if (!statement) return true; + const loop = node as IrStmt; + { if (loop.kind === "forOf") { const local = locals.get(loop.localId); if ( @@ -187,7 +193,7 @@ export function findLoopArrayBorrows( }, }); return true; - }, + } }); return result; } diff --git a/packages/compiler/src/ir/constant-globals.ts b/packages/compiler/src/ir/constant-globals.ts index f18764223..76b086f40 100644 --- a/packages/compiler/src/ir/constant-globals.ts +++ b/packages/compiler/src/ir/constant-globals.ts @@ -36,7 +36,11 @@ export function foldConstantGlobals(mod: IrModule): IrModule { if (value && (value.kind === "numLit" || value.kind === "boolLit")) values.set(id, value); else values.delete(id); }; - for (const fn of mod.functions) + // Per function, the candidates it reads: the rewrite below visits only the + // functions that read a constant. + const readsByFunction = new Map>(); + for (const fn of mod.functions) { + let read: Set | undefined; everyStmtList(fn.body, { // Every node other than a read that names the binding is a write // (assignments, loop and catch bindings, compound updates); only a @@ -48,16 +52,21 @@ export function foldConstantGlobals(mod: IrModule): IrModule { return true; }, expr: (e) => { - if (e.kind !== "varRef" && "localId" in e && typeof e.localId === "string") - write(e.localId, null); + if (e.kind === "varRef") { + if (candidates.has(e.localId)) { + if (read === undefined) read = new Set(); + read.add(e.localId); + } + } else if ("localId" in e && typeof e.localId === "string") write(e.localId, null); return true; }, }); + if (read !== undefined) readsByFunction.set(fn, read); + } const constants = new Map(); for (const [id, value] of values) if (writes.get(id) === 1) constants.set(id, value); if (constants.size === 0) return mod; - const reads = (e: IrExpr): boolean => !(e.kind === "varRef" && constants.has(e.localId)); const rewriteExpr = (e: IrExpr): IrExpr => { if (e.kind === "varRef") { const value = constants.get(e.localId); @@ -68,7 +77,8 @@ export function foldConstantGlobals(mod: IrModule): IrModule { const rewriteStmt = (s: IrStmt): IrStmt => mapStmtChildren(s, rewriteExpr, rewriteStmt); let changed = false; const functions = mod.functions.map((fn): IrFunction => { - if (everyStmtList(fn.body, { stmt: () => true, expr: reads })) return fn; + const read = readsByFunction.get(fn); + if (read === undefined || ![...read].some((id) => constants.has(id))) return fn; changed = true; return { ...fn, body: fn.body.map(rewriteStmt) }; }); diff --git a/packages/compiler/src/ir/receiver-readers.ts b/packages/compiler/src/ir/receiver-readers.ts index 3d0e6f35d..f5270aa7d 100644 --- a/packages/compiler/src/ir/receiver-readers.ts +++ b/packages/compiler/src/ir/receiver-readers.ts @@ -1,6 +1,6 @@ import { isBorrowSafeMath } from "./analysis.js"; import type { IrExpr, IrFunction, IrLibFn, IrStmt } from "./ir.js"; -import { everyStmtList } from "./traverse.js"; +import { eachNodeOfKinds, type IrNodeIndex } from "./node-index.js"; /** Expression kinds that run no user code of their own and never consult * the ambient receiver stack. Calls are admitted here and resolved through @@ -85,6 +85,25 @@ const RECEIVER_FREE_STMTS = new Set([ "runtimeFence", ]); +/** The kinds whose nodes the readers walk answers true for without looking + * at them: every receiver-free statement, and the receiver-free expressions + * other than calls, library calls, string conversions and data intrinsics. */ +const TRIVIALLY_RECEIVER_FREE = new Set([ + ...RECEIVER_FREE_STMTS, + ...[...RECEIVER_FREE_EXPRS].filter( + (kind) => + kind !== "call" && + kind !== "new" && + kind !== "virtualCall" && + kind !== "libCall" && + kind !== "toString" && + kind !== "arrIntrinsic" && + kind !== "strIntrinsic" && + kind !== "mapIntrinsic" && + kind !== "setIntrinsic", + ), +]); + /** Runtime library calls beyond scalar Math that only compute or build and * park a native error: the f64[] folds behind Math.max/min(...xs), * `new Error(message)` (scr_error_new), and the checked-read TypeError @@ -133,7 +152,11 @@ function opaqueOperand(e: IrExpr): boolean { export class AmbientReceiverReaders { private readers: Set | null = null; - constructor(private readonly functions: ReadonlyMap) {} + constructor( + private readonly functions: ReadonlyMap, + /** The module's node index, read instead of walking the bodies it holds. */ + private readonly nodes?: IrNodeIndex, + ) {} ignores(fn: IrFunction): boolean { if (fn.async || fn.generator) return false; @@ -153,6 +176,7 @@ export class AmbientReceiverReaders { } const readers = new Set(); const callers = new Map(); + const scan = this.nodes?.scanExcept(TRIVIALLY_RECEIVER_FREE); for (const fn of this.functions.values()) { const callees = new Set(); let reads = fn.async === true || fn.generator !== undefined; @@ -161,32 +185,36 @@ export class AmbientReceiverReaders { callees.add(name); return true; }; + const expr = (expr: IrExpr): boolean => { + if (!RECEIVER_FREE_EXPRS.has(expr.kind)) return false; + switch (expr.kind) { + case "call": + return edge(expr.callee); + case "new": + return edge(`%${expr.className}.constructor`); + case "virtualCall": { + // Any class's override may run: admit only when every + // same-named method is itself receiver-free. + const targets = byMethod.get(expr.method) ?? []; + return targets.length > 0 && targets.every(edge); + } + case "libCall": + return isBorrowSafeMath(expr.fn) || RECEIVER_FREE_LIB_FNS.has(expr.fn); + case "toString": + return !opaqueOperand(expr.operand); + default: { + const operands = dataIntrinsicOperands(expr); + return operands === null || !operands.some(opaqueOperand); + } + } + }; if (!reads) - reads = !everyStmtList(fn.body, { - stmt: (stmt) => RECEIVER_FREE_STMTS.has(stmt.kind), - expr: (expr) => { - if (!RECEIVER_FREE_EXPRS.has(expr.kind)) return false; - switch (expr.kind) { - case "call": - return edge(expr.callee); - case "new": - return edge(`%${expr.className}.constructor`); - case "virtualCall": { - // Any class's override may run: admit only when every - // same-named method is itself receiver-free. - const targets = byMethod.get(expr.method) ?? []; - return targets.length > 0 && targets.every(edge); - } - case "libCall": - return isBorrowSafeMath(expr.fn) || RECEIVER_FREE_LIB_FNS.has(expr.fn); - case "toString": - return !opaqueOperand(expr.operand); - default: { - const operands = dataIntrinsicOperands(expr); - return operands === null || !operands.some(opaqueOperand); - } - } - }, + eachNodeOfKinds(fn, scan, (node, statement) => { + const free = statement + ? RECEIVER_FREE_STMTS.has((node as IrStmt).kind) + : expr(node as IrExpr); + if (!free) reads = true; + return free; }); if (reads) readers.add(fn.name); for (const callee of callees) { From 38730910c86b64f031d469cabaec6a8f00973de1 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 09:56:15 -0500 Subject: [PATCH 099/259] Write the first stdin chunk after both readers start in the 'readable' EOF case A reader that starts after the second chunk arrives reads both chunks in one 'readable' event. On loaded test workers Node started that late while the compiled program did not, so the two outputs differed. The first chunk now waits 500 ms. --- tests/harness/event-loop-cases.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/harness/event-loop-cases.ts b/tests/harness/event-loop-cases.ts index 50a7d2b85..e0ecfc899 100644 --- a/tests/harness/event-loop-cases.ts +++ b/tests/harness/event-loop-cases.ts @@ -37,9 +37,11 @@ export const eventLoopCases: EventLoopCase[] = [ { title: "stdio values: 'readable' drains with read(), then fires once more at EOF", fixture: "stdio-readable.mjs", + // The first chunk waits until both readers run: a reader that starts + // after the second chunk arrives reads the two in one 'readable'. script: { writes: [ - { delayMs: 0, data: "alpha " }, + { delayMs: 500, data: "alpha " }, { delayMs: 60, data: "beta\n" }, ], end: true, From e35621323dfdceb4b56a01bcbe8c9523591e495a Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 10:06:35 -0500 Subject: [PATCH 100/259] Trust no certificate for an empty ca in TLS clients tls.connect, https.request and http2.connect verified the server against the default CAs when ca was an empty Buffer, because the runtime read a zero-length ca as none. The compiled calls now pass a null ca for none (an omitted ca, or an empty string, which Node reads as no ca) and a non-null one for any Buffer, and runtime option records read ca the same way, so an empty Buffer or array trusts no certificate, as in Node. The connection pool keys tell an empty ca from none. An empty array, which threw, is an empty trust store too. A runtime-valued empty string ca in http2.connect is refused instead of being read as an empty store. --- docs/content/limitations/tls-certificates.mdx | 3 + packages/compiler/src/backend/llvm/lib-abi.ts | 20 ++++ .../compiler/src/backend/llvm/lib-dispatch.ts | 7 +- .../compiler/src/backend/llvm/lib-http2.ts | 3 +- packages/compiler/src/backend/llvm/lib-tls.ts | 5 +- .../corpus/8176-tls-empty-context-ca.ts.json | 6 + .../corpus/8177-tls-empty-client-ca.ts.json | 6 + packages/runtime/src/scr_http2.c | 4 +- packages/runtime/src/scr_http2.h | 6 +- packages/runtime/src/scr_tls.c | 99 ++++++++++++----- packages/runtime/src/scr_tls.h | 2 +- tests/corpus/8176-tls-empty-context-ca.ts | 73 ++++++++++++ tests/corpus/8177-tls-empty-client-ca.ts | 104 ++++++++++++++++++ .../8176-tls-empty-context-ca.ts.json | 1 + .../8177-tls-empty-client-ca.ts.json | 1 + 15 files changed, 300 insertions(+), 40 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8176-tls-empty-context-ca.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8177-tls-empty-client-ca.ts.json create mode 100644 tests/corpus/8176-tls-empty-context-ca.ts create mode 100644 tests/corpus/8177-tls-empty-client-ca.ts create mode 100644 tests/harness/corpus-costs/8176-tls-empty-context-ca.ts.json create mode 100644 tests/harness/corpus-costs/8177-tls-empty-client-ca.ts.json diff --git a/docs/content/limitations/tls-certificates.mdx b/docs/content/limitations/tls-certificates.mdx index bbe4ceaf9..639dd3d83 100644 --- a/docs/content/limitations/tls-certificates.mdx +++ b/docs/content/limitations/tls-certificates.mdx @@ -2,6 +2,9 @@ On a TLS socket held in an `unknown` or `any` value, or in an untyped JavaScript parameter, they throw an error that names the call as not supported. Client certificates follow Node: `tls.createServer`, `https.createServer`, and `new tls.TLSSocket` take `requestCert`, `rejectUnauthorized`, and `ca`, and `tls.connect` and `https.request` take `cert` and `key`. A server's `authorized` and `authorizationError` report the client certificate's verification as Node does, and a server, client, or `tls.createSecureContext` given a `ca` also sends the chain it completes, as OpenSSL's automatic chain does. +A server verifies client certificates against the `ca` of the context it serves, including contexts from `addContext()` and `setSecureContext()`: an empty `ca` (an empty Buffer or array) trusts no certificate, and an omitted `ca` trusts the default CAs. +The same holds for a client's `ca` in `tls.connect`, `https.request`, and `http2.connect`, where an empty string is no `ca`, as in Node. +In `http2.connect`, a `ca` held in an `unknown` or `any` value that is an empty string is refused. `requestCert` beside a TLSSocket's `secureContext` or an `SNICallback`, client certificates on http2 secure servers, and a `cert` without a `key` (or the reverse) are refused. `server.addContext()` and `server.setSecureContext()` follow Node on tls and https servers, including wildcard names, which match one label without regard to case. A name with regular-expression groups or alternation, or one outside ASCII, is refused, as are both methods on a server that is not a tls or https server. diff --git a/packages/compiler/src/backend/llvm/lib-abi.ts b/packages/compiler/src/backend/llvm/lib-abi.ts index 6917d8256..ea5ab82a2 100644 --- a/packages/compiler/src/backend/llvm/lib-abi.ts +++ b/packages/compiler/src/backend/llvm/lib-abi.ts @@ -73,6 +73,26 @@ export function rawBytes(host: LlvmEmitterContext, value: LlValue): AbiArgument[ return [ptr(data), { type: host.sizeType, name: length }]; } +/** A TLS client's `ca` as rawBytes, with a null pointer for none: an empty + * string, which Node reads as no ca (and which an omitted ca lowers to). + * A Buffer's pointer is never null, so an empty one is an empty trust + * store. */ +export function caBytes(host: LlvmEmitterContext, value: LlValue): AbiArgument[] { + const B = host.B; + const [data, length] = rawBytes(host, value); + const test = B.tmp(), + pointer = B.tmp(); + if (value.type.kind === "string") { + B.line(`${test} = icmp eq ${host.sizeType} ${length!.name}, 0`); + B.line(`${pointer} = select i1 ${test}, ptr null, ptr ${data!.name}`); + } else { + // An empty Buffer's data pointer may be null; its object stands in. + B.line(`${test} = icmp eq ptr ${data!.name}, null`); + B.line(`${pointer} = select i1 ${test}, ptr ${value.name}, ptr ${data!.name}`); + } + return [ptr(pointer), length!]; +} + export function callbackType(value: LlValue): IrType & { kind: "func" } { if (value.type.kind !== "func") throw new InternalCompilerError("runtime callback must be a function"); diff --git a/packages/compiler/src/backend/llvm/lib-dispatch.ts b/packages/compiler/src/backend/llvm/lib-dispatch.ts index 9cd11feb1..e371b10a4 100644 --- a/packages/compiler/src/backend/llvm/lib-dispatch.ts +++ b/packages/compiler/src/backend/llvm/lib-dispatch.ts @@ -22,7 +22,7 @@ import { } from "./lib-shared.js"; import { isDynUndefined } from "../../ir/runtime-features.js"; import { DYN_KIND } from "./dyn.js"; -import { rawBytes } from "./lib-abi.js"; +import { caBytes } from "./lib-abi.js"; import { emitInlineAtomicsOp } from "./expr-bytes.js"; import { regexLiteralCaptures } from "./regex-matchers.js"; @@ -595,7 +595,8 @@ export function emitGenericLibCall(host: LlvmEmitterContext, e: LibCallExpr): Ll // The https URL row is the http one with the TLS entry point — same // three arguments, same response-callback adapter. The https options // row is wider: rejectUnauthorized stays an i1, while its ScrStr or - // ScrBytes CA value expands to the runtime's raw pointer + length. + // ScrBytes CA value expands to the runtime's raw pointer + length + // (caBytes: a null pointer for none). const isTls = e.fn.startsWith("https."); const isUrl = e.fn.includes("requestUrl"); const isTlsOptions = isTls && !isUrl; @@ -629,7 +630,7 @@ export function emitGenericLibCall(host: LlvmEmitterContext, e: LibCallExpr): Ll if (isTlsOptions) { callArgs = [ ...callArgs.slice(0, 8), - ...rawBytes(host, args[8]!).map((arg) => `${arg.type} ${arg.name}`), + ...caBytes(host, args[8]!).map((arg) => `${arg.type} ${arg.name}`), ]; host.declare( `declare ptr @scr_https_request(ptr, double, ptr, ptr, double, ptr, i1 zeroext, i1 zeroext, ptr, ${host.sizeType}, ptr, ptr)`, diff --git a/packages/compiler/src/backend/llvm/lib-http2.ts b/packages/compiler/src/backend/llvm/lib-http2.ts index 321f1d005..d750fb7c5 100644 --- a/packages/compiler/src/backend/llvm/lib-http2.ts +++ b/packages/compiler/src/backend/llvm/lib-http2.ts @@ -9,6 +9,7 @@ import { callbackType, finishRuntimeCall, ptr, + caBytes, rawBytes, requestHandler, } from "./lib-abi.js"; @@ -204,7 +205,7 @@ export function emitHttp2LibCall(host: LlvmEmitterContext, e: LibCallExpr): LlVa ); return finishRuntimeCall(host, e, "scr_http2_connect", [ ...a.slice(0, 2), - ...rawBytes(host, args[2]!), + ...caBytes(host, args[2]!), ...handler, ]); } diff --git a/packages/compiler/src/backend/llvm/lib-tls.ts b/packages/compiler/src/backend/llvm/lib-tls.ts index 307aeb3dd..dbe492180 100644 --- a/packages/compiler/src/backend/llvm/lib-tls.ts +++ b/packages/compiler/src/backend/llvm/lib-tls.ts @@ -8,6 +8,7 @@ import { finishRuntimeCall, nullableReference, ptr, + caBytes, rawBytes, requestHandler, } from "./lib-abi.js"; @@ -184,7 +185,7 @@ export function emitTlsLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlValu ); return finishRuntimeCall(host, e, "scr_https_request_agent", [ ...a.slice(0, 8), - ...rawBytes(host, args[8]!), + ...caBytes(host, args[8]!), a[9]!, ...handler, ]); @@ -204,7 +205,7 @@ export function emitTlsLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlValu ["ptr", "ptr"], ); // Evaluate arguments once before selecting which transport consumes the callback. - const pem = rawBytes(host, args[9]!); + const pem = caBytes(host, args[9]!); const B = host.B, tls = B.newLabel("request.tls"), plain = B.newLabel("request.plain"), diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8176-tls-empty-context-ca.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8176-tls-empty-context-ca.ts.json new file mode 100644 index 000000000..536027066 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8176-tls-empty-context-ca.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8176-tls-empty-context-ca.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8177-tls-empty-client-ca.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8177-tls-empty-client-ca.ts.json new file mode 100644 index 000000000..b28587594 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8177-tls-empty-client-ca.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8177-tls-empty-client-ca.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_http2.c b/packages/runtime/src/scr_http2.c index 55d880c01..489946a12 100644 --- a/packages/runtime/src/scr_http2.c +++ b/packages/runtime/src/scr_http2.c @@ -2617,11 +2617,11 @@ static void scr_h2_on_established(void *ctx) { * TLS client transport with ALPN ["h2"] (scr_tls.c — linked whenever * this unit is): the same preface/SETTINGS buffer through the handshake * and everything after establishment is protocol-identical. `ca` - * replaces the client trust anchors (len 0 = none) and + * replaces the client trust anchors (NULL = none) and * reject_unauthorized false disables the verify gate — the local-CA * self-connect shapes. Throws catchably on unparsable input. */ ScrH2Session *scr_http2_connect(ScrStr *url /*borrowed*/, bool reject_unauthorized, - const char *ca /*borrowed, len 0 = none*/, size_t ca_len, + const char *ca /*borrowed, NULL = none*/, size_t ca_len, ScrClosure *cb /*moves, nullable*/, ScrH2ConnectFn fn) { const char *p = url->data; const char *sep = strstr(p, "://"); diff --git a/packages/runtime/src/scr_http2.h b/packages/runtime/src/scr_http2.h index 25e236e6f..c4ce850d0 100644 --- a/packages/runtime/src/scr_http2.h +++ b/packages/runtime/src/scr_http2.h @@ -69,7 +69,7 @@ void scr_http2_server_on_session(ScrNetServer *s, ScrClosure *cb /*moves*/, ScrH * reject_unauthorized false disables the verify gate — the local-CA * self-connect shapes); throws catchably on bad input */ ScrH2Session *scr_http2_connect(ScrStr *url /*borrowed*/, bool reject_unauthorized, - const char *ca /*borrowed, len 0 = none*/, size_t ca_len, + const char *ca /*borrowed, NULL = none*/, size_t ca_len, ScrClosure *cb /*moves, nullable*/, ScrH2ConnectFn fn); /* +1 */ /* end_stream: -1 = the method's payload-meaningless default, 0/1 explicit */ @@ -173,7 +173,7 @@ ScrHttpClientReq *scr_https_request(ScrStr *host /*borrowed*/, double port, ScrStr *path /*borrowed*/, ScrStr *method /*borrowed*/, double timeout_ms, ScrArr *header_pairs /*borrowed*/, bool auto_end, bool reject_unauthorized, - const char *ca /*borrowed, len 0 = none*/, size_t ca_len, + const char *ca /*borrowed, NULL = none*/, size_t ca_len, ScrClosure *cb /*moves, nullable*/, ScrHttpRespFn fn); /* +1 */ /* The URL-string form (https.get('https://host/path')): scr_http.c's * shared parse, then the options form's dial with Node's no-options @@ -187,7 +187,7 @@ ScrHttpClientReq *scr_https_request_agent(ScrStr *host /*borrowed*/, double port ScrStr *path /*borrowed*/, ScrStr *method /*borrowed*/, double timeout_ms, ScrArr *header_pairs /*borrowed*/, bool auto_end, bool reject_unauthorized, - const char *ca /*borrowed, len 0 = none*/, size_t ca_len, + const char *ca /*borrowed, NULL = none*/, size_t ca_len, const struct ScrDyn *agent /*borrowed*/, ScrClosure *cb /*moves, nullable*/, ScrHttpRespFn fn); /* +1 */ /* The fetch unit's https leg (defined in scr_tls.c): a client transport diff --git a/packages/runtime/src/scr_tls.c b/packages/runtime/src/scr_tls.c index 2f448a417..e764926b2 100644 --- a/packages/runtime/src/scr_tls.c +++ b/packages/runtime/src/scr_tls.c @@ -253,7 +253,10 @@ struct ScrSecureCtx { mbedtls_x509_crt cert; mbedtls_pk_context pk; /* the ca option: a socket created from this context (a TLSSocket's - * secureContext) sends the chain it completes */ + * secureContext) sends the chain it completes, and a server that serves + * the context verifies client certificates against it. has_ca tells an + * empty ca (an empty trust store) from none (the default store). */ + bool has_ca; mbedtls_x509_crt ca; }; @@ -573,6 +576,9 @@ static void scr_tls_srv_client_auth(ScrTlsSrv *s, const ScrTlsClientAuth *auth) typedef struct ScrTlsCli { mbedtls_ssl_config conf; + /* the ca option, which replaces the default store; has_ca tells an + * empty ca (an empty trust store) from none */ + bool has_ca; mbedtls_x509_crt ca; char *hostname; /* the SNI name; NULL sends none (an IP literal, servername: "") */ char *verify_name; /* the name the leaf is checked against; NULL fails the check */ @@ -696,6 +702,7 @@ static ScrTlsCli *scr_tls_cli_new2(ScrStr *host, bool reject_unauthorized, const mbedtls_ssl_conf_rng(&c->conf, mbedtls_ctr_drbg_random, &scr_tls_drbg); c->verify_recorded = reject_unauthorized || verify_optional; c->reject = reject_unauthorized; + c->has_ca = ca != NULL; if (ca_len > 0) { int r = scr_tls_parse_crt(&c->ca, ca, ca_len); if (r != 0) scr_tls_bad_material("ca certificate", r); @@ -705,7 +712,7 @@ static ScrTlsCli *scr_tls_cli_new2(ScrStr *host, bool reject_unauthorized, const } else { mbedtls_ssl_conf_authmode(&c->conf, reject_unauthorized ? MBEDTLS_SSL_VERIFY_REQUIRED : MBEDTLS_SSL_VERIFY_OPTIONAL); - mbedtls_ssl_conf_ca_chain(&c->conf, ca_len > 0 ? &c->ca : scr_tls_system_ca(), NULL); + mbedtls_ssl_conf_ca_chain(&c->conf, c->has_ca ? &c->ca : scr_tls_system_ca(), NULL); } /* The host is the verified name; it is also the SNI name unless it is * an IP literal. */ @@ -799,6 +806,9 @@ typedef struct ScrTlsSock { unsigned char *hello; /* the raw ClientHello flight, replayed at DONE */ size_t hello_len, hello_cap; ScrSecureCtx *sni_ctx; /* owned; the answer (NULL = default cert) */ + /* scr_tls_f_cert verified client certificates against sni_ctx's ca + * (or the default store without one), not the server's */ + bool ctx_verifies; /* new tls.TLSSocket(socket, { isServer: true }): the program holds this * socket before the handshake, so a failed handshake is its 'error' * (tls.createServer's sockets fail without one) */ @@ -1889,8 +1899,8 @@ static ScrStr *scr_tls_pool_key(ScrStr *host, bool reject_unauthorized, const ch uint64_t h = 1469598103934665603ull; for (size_t i = 0; i < ca_len; i++) h = (h ^ (unsigned char)ca[i]) * 1099511628211ull; char buf[64]; - int n = snprintf(buf, sizeof buf, "%d:%zu:%016llx:", reject_unauthorized ? 1 : 0, ca_len, - (unsigned long long)h); + int n = snprintf(buf, sizeof buf, "%d:%s%zu:%016llx:", reject_unauthorized ? 1 : 0, + ca != NULL ? "" : "-", ca_len, (unsigned long long)h); ScrJsonBuf b; scr_jb_init(&b); scr_jb_write(&b, buf, (size_t)n); @@ -2148,7 +2158,7 @@ ScrHttpClientReq *scr_https_request(ScrStr *host /*borrowed*/, double port, ScrStr *path /*borrowed*/, ScrStr *method /*borrowed*/, double timeout_ms, ScrArr *header_pairs /*borrowed*/, bool auto_end, bool reject_unauthorized, - const char *ca /*borrowed, len 0 = none*/, size_t ca_len, + const char *ca /*borrowed, NULL = none*/, size_t ca_len, ScrClosure *cb /*moves, nullable*/, ScrHttpRespFn fn) { ScrStr *servername = scr_https_take_servername(); ScrTlsCli *cli = scr_tls_cli_for(host, reject_unauthorized, ca, ca_len, servername); @@ -2189,7 +2199,7 @@ ScrHttpClientReq *scr_https_request_agent(ScrStr *host /*borrowed*/, double port ScrStr *path /*borrowed*/, ScrStr *method /*borrowed*/, double timeout_ms, ScrArr *header_pairs /*borrowed*/, bool auto_end, bool reject_unauthorized, - const char *ca /*borrowed, len 0 = none*/, size_t ca_len, + const char *ca /*borrowed, NULL = none*/, size_t ca_len, const ScrDyn *agent /*borrowed*/, ScrClosure *cb /*moves, nullable*/, ScrHttpRespFn fn) { ScrStr *servername = scr_https_take_servername(); @@ -2242,6 +2252,14 @@ static bool scr_tls_dyn_truthy(const ScrDyn *v) { * the exception pending. `what` names the fence ("a tls.createServer * 'cert' option"). */ static ScrBytes *scr_tls_pem_dyn(const ScrDyn *v, const char *what, bool concat) { + if (v->kind == SCR_DYN_TYPED_REF) { + /* a typed array (an array literal in a typed record): its entries */ + ScrDyn *plain = scr_dyn_typed_ref_materialize(v); + if (plain == NULL) return NULL; + ScrBytes *b = scr_tls_pem_dyn(plain, what, concat); + scr_dyn_release(plain); + return b; + } if (v->kind == SCR_DYN_STR) { ScrBytes *b = scr_bytes_new(SCR_BYTES_U8, (double)v->v.str->len); memcpy(b->data, v->v.str->data, v->v.str->len); @@ -2292,6 +2310,33 @@ static ScrBytes *scr_tls_pem_dyn(const ScrDyn *v, const char *what, bool concat) return NULL; } +/* A `ca` option from a runtime value: NULL for none (an empty string, + * which Node reads as no ca), empty bytes for an empty Buffer or array + * (an empty trust store), else the PEM bundle (+1). False with the + * exception pending. */ +static bool scr_tls_ca_dyn(const ScrDyn *v, const char *what, ScrBytes **out) { + *out = NULL; + ScrDyn *plain = v->kind == SCR_DYN_TYPED_REF ? scr_dyn_typed_ref_materialize(v) : NULL; + if (v->kind == SCR_DYN_TYPED_REF && plain == NULL) return false; + const ScrDyn *ca = plain != NULL ? plain : v; + bool ok = true; + if (ca->kind == SCR_DYN_ARR && ca->v.arr.len == 0) { + *out = scr_bytes_new(SCR_BYTES_U8, 0); + } else if (ca->kind != SCR_DYN_STR || ca->v.str->len > 0) { + *out = scr_tls_pem_dyn(ca, what, true); + ok = *out != NULL; + } + scr_dyn_release(plain); + return ok; +} + +/* A client's ca for scr_tls_cli_new2: NULL for none, and never NULL for a + * given ca, even an empty one. */ +static const char *scr_tls_ca_data(const ScrBytes *ca) { + if (ca == NULL) return NULL; + return ca->data != NULL ? (const char *)ca->data : ""; +} + /* https.request/get with a runtime options record: the http walk, then * the TLS options the literal https path lowers (rejectUnauthorized, ca, * servername) and a client certificate (cert and key). Other tls.connect @@ -2330,8 +2375,7 @@ ScrHttpClientReq *scr_https_request_dyn(const ScrDyn *opts /*borrowed*/, bool au if (r != NULL && r->kind == SCR_DYN_BOOL && !r->v.b) reject = false; const ScrDyn *c = ok ? scr_dyn_obj_get(rec, "ca", 2) : NULL; if (c != NULL && c->kind != SCR_DYN_UNDEF && c->kind != SCR_DYN_NULL) { - ca = scr_tls_pem_dyn(c, "an https.request 'ca' option", true); - if (ca == NULL) ok = false; + ok = scr_tls_ca_dyn(c, "an https.request 'ca' option", &ca); } const ScrDyn *oc = ok ? scr_dyn_obj_get(rec, "cert", 4) : NULL; if (oc != NULL && oc->kind != SCR_DYN_UNDEF && oc->kind != SCR_DYN_NULL) { @@ -2366,7 +2410,7 @@ ScrHttpClientReq *scr_https_request_dyn(const ScrDyn *opts /*borrowed*/, bool au if (cb) scr_closure_release(cb); return NULL; } - const char *ca_data = ca ? (const char *)ca->data : NULL; + const char *ca_data = scr_tls_ca_data(ca); size_t ca_len = ca ? ca->len : 0; ScrTlsCli *cli = scr_tls_cli_for(o.host, reject, ca_data, ca_len, servername); ScrStr *key = scr_tls_pool_key(o.host, reject, ca_data, ca_len, servername); @@ -2397,13 +2441,17 @@ ScrHttpClientReq *scr_https_request_dyn(const ScrDyn *opts /*borrowed*/, bool au /* The literal path's runtime-valued cert/key extraction (the compiler's * tls.pemDyn libCall): `what` arrives precomposed. undefined throws — the - * literal walk required the member's presence. */ + * literal walk required the member's presence — and so does an empty + * string, which Node reads as no material while empty bytes here are an + * empty ca. */ ScrBytes *scr_tls_pem_from_dyn(const ScrDyn *v, const char *what) { - if (v->kind == SCR_DYN_UNDEF || v->kind == SCR_DYN_NULL) { + bool empty = v->kind == SCR_DYN_STR && v->v.str->len == 0; + if (v->kind == SCR_DYN_UNDEF || v->kind == SCR_DYN_NULL || empty) { ScrJsonBuf b; scr_jb_init(&b); scr_jb_puts(&b, what); - scr_jb_puts(&b, " holding undefined has no static lowering — pass PEM material (a string or a Buffer)"); + scr_jb_puts(&b, empty ? " holding an empty string" : " holding undefined"); + scr_jb_puts(&b, " has no static lowering — pass PEM material (a string or a Buffer)"); scr_throw_error(SCR_ERR_ERROR, scr_jb_finish(&b)); return NULL; } @@ -2565,14 +2613,7 @@ static bool scr_tls_srv_opts_walk_ex(const ScrDyn *opts, const char *api, ScrByt char what[96]; snprintf(what, sizeof what, "a %s 'ca' option", api); scr_bytes_release(auth->ca); - /* An empty string is no ca, as Node reads it; an empty Buffer is - * an empty trust store. */ - if (v->kind == SCR_DYN_STR && v->v.str->len == 0) { - auth->ca = NULL; - } else { - auth->ca = scr_tls_pem_dyn(v, what, true); - if (auth->ca == NULL) ok = false; - } + if (!scr_tls_ca_dyn(v, what, &auth->ca)) ok = false; } continue; } @@ -2658,6 +2699,7 @@ ScrSecureCtx *scr_tls_create_secure_context_dyn(const ScrDyn *opts /*borrowed*/) int r = scr_tls_parse_crt(&c->ca, (const char *)auth.ca->data, auth.ca->len); if (r != 0) scr_tls_bad_material("ca certificate", r); } + c->has_ca = true; scr_bytes_release(auth.ca); } scr_bytes_release(cert); @@ -2810,8 +2852,10 @@ static int scr_tls_f_cert(mbedtls_ssl_context *ssl) { scr_tls_chained_copy(&t->served_chain, &pick->cert, store); own = &t->served_chain; } - if (s->request_cert) - mbedtls_ssl_set_hs_ca_chain(ssl, pick->ca.raw.len > 0 ? &pick->ca : scr_tls_system_ca(), NULL); + if (s->request_cert) { + t->ctx_verifies = true; + mbedtls_ssl_set_hs_ca_chain(ssl, pick->has_ca ? &pick->ca : scr_tls_system_ca(), NULL); + } return mbedtls_ssl_set_hs_own_cert(ssl, own, &pick->pk); } @@ -3261,8 +3305,7 @@ static ScrNetSocket *scr_tls_connect_plain(double port, ScrStr *host /*borrowed, } if (strcmp(e->key, "ca") == 0) { scr_bytes_release(ca); - ca = scr_tls_pem_dyn(v, "a tls.connect 'ca' option", true); - if (ca == NULL) ok = false; + if (!scr_tls_ca_dyn(v, "a tls.connect 'ca' option", &ca)) ok = false; continue; } if (strcmp(e->key, "cert") == 0 || strcmp(e->key, "key") == 0) { @@ -3386,8 +3429,7 @@ static ScrNetSocket *scr_tls_connect_plain(double port, ScrStr *host /*borrowed, if (dial_addr) scr_str_release(dial_addr); } ScrTlsCli *cli = scr_tls_cli_new2(verify_host, reject, - ca != NULL ? (const char *)ca->data : NULL, - ca != NULL ? ca->len : 0, !reject); + scr_tls_ca_data(ca), ca != NULL ? ca->len : 0, !reject); if (servername != NULL) scr_tls_cli_set_servername(cli, servername); if (own_cert != NULL) scr_tls_cli_set_own(cli, own_cert, own_key); scr_bytes_release(own_cert); @@ -3441,7 +3483,7 @@ void scr_tls_server_wrap_h2(ScrNetServer *s, const char *cert, size_t cert_len, /* The h2-over-TLS CLIENT wrap (http2.connect with an https authority): * a client transport offering ALPN ["h2"] — SNI/verification against - * the authority host; `ca` replaces the trust anchors ("" = none) and + * the authority host; `ca` replaces the trust anchors (NULL = none) and * reject_unauthorized false records like tls.connect's. The session's * preface/SETTINGS ride the socket's write buffer until establishment. */ void scr_tls_h2_client_wrap(ScrNetSocket *sock, ScrStr *host /*borrowed*/, @@ -3595,7 +3637,8 @@ void scr_tls_sock_each_trusted(ScrNetSocket *s, bool (*visit)(void *ctx, const u void *ctx) { ScrTlsSock *t = scr_tls_sock_of(s); if (t == NULL || (t->cli == NULL && t->srv == NULL)) return; - const mbedtls_x509_crt *c = t->cli != NULL ? (t->cli->ca.raw.len > 0 ? &t->cli->ca : scr_tls_system_ca()) + const mbedtls_x509_crt *c = t->cli != NULL ? (t->cli->has_ca ? &t->cli->ca : scr_tls_system_ca()) + : t->ctx_verifies ? (t->sni_ctx->has_ca ? &t->sni_ctx->ca : scr_tls_system_ca()) : t->srv->has_ca ? &t->srv->ca : scr_tls_system_ca(); for (; c != NULL && c->raw.len > 0; c = c->next) diff --git a/packages/runtime/src/scr_tls.h b/packages/runtime/src/scr_tls.h index 94bf41d33..8e044f12d 100644 --- a/packages/runtime/src/scr_tls.h +++ b/packages/runtime/src/scr_tls.h @@ -85,7 +85,7 @@ void scr_tls_sock_on_secure(ScrNetSocket *s, ScrClosure *cb /*moves*/, bool once * every http2-using binary links the TLS unit (the moduleUsesTls * switch), so no registration indirection is needed. */ void scr_tls_server_wrap_h2(ScrNetServer *s, const char *cert, size_t cert_len, const char *key, size_t key_len, ScrNetNativeConnFn h2_conn, void *h2_ctx /*moves*/, void (*h2_ctx_free)(void *), ScrClosure *sni_cb /*moves, nullable*/, void *sni_answer_fn); -void scr_tls_h2_client_wrap(ScrNetSocket *sock, ScrStr *host /*borrowed*/, bool reject_unauthorized, const char *ca /*borrowed, len 0 = none*/, size_t ca_len); +void scr_tls_h2_client_wrap(ScrNetSocket *sock, ScrStr *host /*borrowed*/, bool reject_unauthorized, const char *ca /*borrowed, NULL = none*/, size_t ca_len); /* ── tls.SecureContext + the SNI callback (scr_tls.c) ───────────────── * A SecureContext is an opaque refcounted parsed cert/key pair diff --git a/tests/corpus/8176-tls-empty-context-ca.ts b/tests/corpus/8176-tls-empty-context-ca.ts new file mode 100644 index 000000000..510c9881a --- /dev/null +++ b/tests/corpus/8176-tls-empty-context-ca.ts @@ -0,0 +1,73 @@ +// An explicitly empty ca is an empty trust store for client certificates, +// in the server's options, in setSecureContext and in addContext, even when +// the client certificate's issuer is a default CA +// (tls.setDefaultCACertificates); an omitted ca trusts the default CAs. +// Each server has requestCert, with rejectUnauthorized false (the server's +// verdict) and true (the client is dropped). +import { readFileSync } from "node:fs"; +import type { AddressInfo } from "node:net"; +import * as tls from "node:tls"; + +const D = "tests/fixtures/server/certs"; +const r = (f: string): Buffer => readFileSync(`${D}/${f}`); +const ca = r("ca.pem"), cert = r("localhost.pem"), key = r("localhost-key.pem"); +const alt = r("alt.pem"), altKey = r("alt-key.pem"); +const client = r("client.pem"), clientKey = r("client-key.pem"); + +tls.setDefaultCACertificates([ca.toString()]); + +function listen(server: tls.Server): Promise { + return new Promise((res) => server.listen(0, () => res((server.address() as AddressInfo).port))); +} + +type Handler = (s: tls.TLSSocket) => void; + +async function run(label: string, make: (h: Handler) => tls.Server, servername: string): Promise { + const events: string[] = []; + const server = make((s) => { + events.push(`server authorized=${s.authorized} error=${s.authorizationError}`); + s.end("ok"); + }); + const port = await listen(server); + await new Promise((done) => { + const c = tls.connect({ port, servername, ca, cert: client, key: clientKey }); + c.on("secureConnect", () => events.push("client secureConnect")); + c.on("data", (d: Buffer) => events.push(`client data ${d}`)); + c.on("error", (e: NodeJS.ErrnoException) => events.push(`client error ${e.code}`)); + c.on("close", () => setTimeout(done, 50)); + }); + console.log(label, "|", events.join(" ; ")); + await new Promise((res) => server.close(() => res())); +} + +for (const reject of [false, true]) { + const opts = { cert, key, requestCert: true, rejectUnauthorized: reject }; + const tag = reject ? "reject" : "request"; + await run(`${tag} omitted`, (h) => tls.createServer(opts, h), "localhost"); + await run(`${tag} empty array`, (h) => tls.createServer({ ...opts, ca: [] }, h), "localhost"); + await run(`${tag} setSecureContext empty`, (h) => { + const server = tls.createServer(opts, h); + server.setSecureContext({ cert, key, ca: [] }); + return server; + }, "localhost"); + await run(`${tag} setSecureContext omitted`, (h) => { + const server = tls.createServer({ ...opts, ca: [] }, h); + server.setSecureContext({ cert, key }); + return server; + }, "localhost"); + await run(`${tag} addContext empty array`, (h) => { + const server = tls.createServer(opts, h); + server.addContext("alt.localhost", { cert: alt, key: altKey, ca: [] }); + return server; + }, "alt.localhost"); + await run(`${tag} addContext empty Buffer`, (h) => { + const server = tls.createServer(opts, h); + server.addContext("alt.localhost", tls.createSecureContext({ cert: alt, key: altKey, ca: Buffer.alloc(0) })); + return server; + }, "alt.localhost"); + await run(`${tag} addContext omitted`, (h) => { + const server = tls.createServer({ ...opts, ca: [] }, h); + server.addContext("alt.localhost", { cert: alt, key: altKey }); + return server; + }, "alt.localhost"); +} diff --git a/tests/corpus/8177-tls-empty-client-ca.ts b/tests/corpus/8177-tls-empty-client-ca.ts new file mode 100644 index 000000000..0fb596ddb --- /dev/null +++ b/tests/corpus/8177-tls-empty-client-ca.ts @@ -0,0 +1,104 @@ +// An explicitly empty ca is an empty trust store for a client's view of +// the server certificate, in tls.connect, https.request and http2.connect, +// even when the server certificate's issuer is a default CA +// (tls.setDefaultCACertificates); an omitted ca, or an empty string, trusts +// the default CAs. +import { readFileSync } from "node:fs"; +import * as http2 from "node:http2"; +import * as https from "node:https"; +import type { AddressInfo } from "node:net"; +import * as tls from "node:tls"; + +const D = "tests/fixtures/server/certs"; +const r = (f: string): Buffer => readFileSync(`${D}/${f}`); +const ca = r("ca.pem"), key = r("localhost-key.pem"); +// The servers send their issuer too, so each client sees the same chain. +const cert = Buffer.concat([r("localhost.pem"), ca]); + +tls.setDefaultCACertificates([ca.toString()]); + +function listen(server: tls.Server | https.Server | http2.Http2SecureServer): Promise { + return new Promise((res) => server.listen(0, () => res((server.address() as AddressInfo).port))); +} + +async function watch(label: string, c: tls.TLSSocket): Promise { + const events: string[] = []; + await new Promise((done) => { + c.on("secureConnect", () => { + events.push(`secureConnect authorized=${c.authorized} error=${c.authorizationError}`); + c.end(); + }); + c.on("error", (e: NodeJS.ErrnoException) => events.push(`error ${e.code}`)); + c.on("close", () => done()); + }); + console.log("tls.connect", label, "|", events.join(" ; ")); +} + +{ + const server = tls.createServer({ cert, key }, (s) => s.end()); + const port = await listen(server); + const host = "localhost"; + await watch("omitted", tls.connect({ port, host })); + await watch("empty string", tls.connect({ port, host, ca: "" })); + await watch("empty Buffer", tls.connect({ port, host, ca: Buffer.alloc(0) })); + await watch("empty array", tls.connect({ port, host, ca: [] })); + await watch( + "empty Buffer, rejectUnauthorized false", + tls.connect({ port, host, ca: Buffer.alloc(0), rejectUnauthorized: false }), + ); + await watch("empty array, rejectUnauthorized false", tls.connect({ port, host, ca: [], rejectUnauthorized: false })); + server.close(); +} + +function report(label: string, req: ReturnType, done: () => void): void { + req.on("response", (res) => { + console.log("https.request", label, "| status", res.statusCode); + res.resume(); + res.on("end", done); + }); + req.on("error", (e: NodeJS.ErrnoException) => { + console.log("https.request", label, "| error", e.code); + done(); + }); + req.end(); +} + +{ + const server = https.createServer({ cert, key }, (_req, res) => res.end("ok")); + const port = await listen(server); + await new Promise((done) => + report("omitted", https.request({ host: "localhost", port, path: "/", agent: false }), done), + ); + await new Promise((done) => + report("empty string", https.request({ host: "localhost", port, path: "/", agent: false, ca: "" }), done), + ); + await new Promise((done) => + report( + "empty Buffer", + https.request({ host: "localhost", port, path: "/", agent: false, ca: Buffer.alloc(0) }), + done, + ), + ); + const options: unknown = { host: "localhost", port, path: "/", agent: false, ca: [] }; + await new Promise((done) => + report("empty array in a runtime record", https.request(options as https.RequestOptions), done), + ); + server.close(); +} + +{ + const server = http2.createSecureServer({ cert, key }, (_req, res) => res.end("ok")); + const port = await listen(server); + for (const [label, ca] of [["omitted", undefined], ["empty Buffer", Buffer.alloc(0)]] as const) { + await new Promise((done) => { + const session = ca === undefined ? http2.connect(`https://localhost:${port}`) : http2.connect(`https://localhost:${port}`, { ca }); + session.on("connect", () => { + console.log("http2.connect", label, "| connect"); + session.close(); + }); + session.on("error", (e: NodeJS.ErrnoException) => console.log("http2.connect", label, "| error", e.code)); + session.on("close", () => done()); + }); + } + server.close(); +} diff --git a/tests/harness/corpus-costs/8176-tls-empty-context-ca.ts.json b/tests/harness/corpus-costs/8176-tls-empty-context-ca.ts.json new file mode 100644 index 000000000..2f8507d0f --- /dev/null +++ b/tests/harness/corpus-costs/8176-tls-empty-context-ca.ts.json @@ -0,0 +1 @@ +{ "plain": 7322, "san": 94064 } diff --git a/tests/harness/corpus-costs/8177-tls-empty-client-ca.ts.json b/tests/harness/corpus-costs/8177-tls-empty-client-ca.ts.json new file mode 100644 index 000000000..d7df308c8 --- /dev/null +++ b/tests/harness/corpus-costs/8177-tls-empty-client-ca.ts.json @@ -0,0 +1 @@ +{ "plain": 4335, "san": 61880 } From 53baad4ebee91f746f0e4c310c889cfa1cff4dde Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 10:12:06 -0500 Subject: [PATCH 101/259] Pump untyped iterable pipeline sources A pipeline whose first stage is a checked-dynamic value now checks it at run time, as Node's stage ladder does: a stream is piped as before, and a string or a value with a Symbol.asyncIterator or Symbol.iterator method is pumped into the next stage through an async generator over its iterator. A typed Set, Map, generator or async generator object as the first stage takes the same path. This covers the callback and stream/promises forms, with or without function stages and pipeline options. A write whose callback fails synchronously no longer sets needDrain, so no 'drain' follows the error and a pumped source stops at the failed write, as in Node. RUNTIME_ABI_VERSION goes from 37 to 42 for scr_stream_dyn_iterable_source. --- .../builtin-apis/streams-and-readline.mdx | 5 +- packages/cli/test/native-link-info.test.ts | 4 +- .../compiler/src/backend/llvm/lib-shared.ts | 1 + packages/compiler/src/backend/runtime-abi.ts | 4 +- .../src/backend/runtime-pack-targets.test.ts | 2 +- .../compiler/src/backend/runtime-pack.test.ts | 2 +- .../src/frontend/lowering/lower-stream.ts | 626 ++++++++++++++---- packages/compiler/src/ir/builtin-effects.ts | 1 + .../compiler/src/ir/builtin-signatures.ts | 4 + packages/compiler/src/ir/runtime-features.ts | 1 + .../test/native-codegen-integration.test.ts | 4 +- .../7503-pipeline-untyped-sources.mjs.json | 6 + ...04-pipeline-untyped-source-errors.mjs.json | 6 + .../7505-pipeline-untyped-sources.cjs.json | 6 + .../corpus/7506-pipeline-any-source.ts.json | 6 + .../7507-stream-write-error-drain.mjs.json | 6 + .../runtime-darwin-arm64/scripts/build.mjs | 2 +- .../runtime-pack-common/scripts/build.mjs | 2 +- packages/runtime/src/scr_console.c | 2 +- packages/runtime/src/scr_core.h | 2 +- packages/runtime/src/scr_stream.c | 38 +- packages/runtime/src/scr_stream.h | 4 + .../corpus/7503-pipeline-untyped-sources.mjs | 102 +++ .../7504-pipeline-untyped-source-errors.mjs | 90 +++ .../corpus/7505-pipeline-untyped-sources.cjs | 40 ++ tests/corpus/7506-pipeline-any-source.ts | 48 ++ .../corpus/7507-stream-write-error-drain.mjs | 37 ++ .../7503-pipeline-untyped-sources.mjs.json | 1 + ...04-pipeline-untyped-source-errors.mjs.json | 1 + .../7505-pipeline-untyped-sources.cjs.json | 1 + .../7506-pipeline-any-source.ts.json | 1 + .../7507-stream-write-error-drain.mjs.json | 1 + .../self-hosting-native-toolchain.test.ts | 2 +- 33 files changed, 911 insertions(+), 147 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7503-pipeline-untyped-sources.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7504-pipeline-untyped-source-errors.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7505-pipeline-untyped-sources.cjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7506-pipeline-any-source.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7507-stream-write-error-drain.mjs.json create mode 100644 tests/corpus/7503-pipeline-untyped-sources.mjs create mode 100644 tests/corpus/7504-pipeline-untyped-source-errors.mjs create mode 100644 tests/corpus/7505-pipeline-untyped-sources.cjs create mode 100644 tests/corpus/7506-pipeline-any-source.ts create mode 100644 tests/corpus/7507-stream-write-error-drain.mjs create mode 100644 tests/harness/corpus-costs/7503-pipeline-untyped-sources.mjs.json create mode 100644 tests/harness/corpus-costs/7504-pipeline-untyped-source-errors.mjs.json create mode 100644 tests/harness/corpus-costs/7505-pipeline-untyped-sources.cjs.json create mode 100644 tests/harness/corpus-costs/7506-pipeline-any-source.ts.json create mode 100644 tests/harness/corpus-costs/7507-stream-write-error-drain.mjs.json diff --git a/docs/content/limitations/builtin-apis/streams-and-readline.mdx b/docs/content/limitations/builtin-apis/streams-and-readline.mdx index f9d69e3db..561840268 100644 --- a/docs/content/limitations/builtin-apis/streams-and-readline.mdx +++ b/docs/content/limitations/builtin-apis/streams-and-readline.mdx @@ -3,7 +3,8 @@ `readable.pipe(process.stdout)` and `readable.pipe(process.stderr)` compile and, as in Node, do not end the process stream. When an untyped value reaches `NodeJS.ReadableStream` or `NodeJS.WritableStream`, those two interfaces hold any value, so JavaScript stream objects (constructor-function streams, plain objects with `on` and `pipe`) pass through TypeScript functions typed with them and come back to JavaScript as the same objects. Member calls on such a value use the native stream when it is one and call the object's own members otherwise; `readable.pipe()` into a JavaScript destination follows Node's pipe protocol. - A `pipeline` stage and a `for await` source that arrive as untyped values must be native streams, or `Cipheriv` and `Decipheriv` values, at run time; other values throw a not-supported error. + The first `pipeline` stage may arrive as an untyped value that is a native stream, a `Cipheriv` or `Decipheriv` value, or an iterable: a string, an array, a generator object, or any value with a `Symbol.asyncIterator` or `Symbol.iterator` method, which the pipeline pumps into the next stage as Node does. + Later `pipeline` stages and `for await` sources that arrive as untyped values must be native streams, or `Cipheriv` and `Decipheriv` values, at run time; other values throw a not-supported error. Native streams expose no `emit` to JavaScript, so a JavaScript stream whose own `pipe()` emits on its destination (the legacy `Stream` pipe) cannot pipe into one. `Readable.from` accepts strings, Buffers, arrays, Sets, Maps, Map and Set iterators, generators, async generators, and class iterables and async iterables, and in JavaScript any iterable or async iterable. In JavaScript, a sync iterator value with a `then` method that is not a promise, and an object whose `[Symbol.asyncIterator]` or `[Symbol.iterator]` method is a generator method, are unsupported. @@ -14,7 +15,7 @@ `node:stream/consumers` and readline interfaces read object-mode streams of strings and Buffers; other values throw a not-supported error. `pipeline` accepts function stages anywhere among its streams: async generator functions (`async function* (source)`, iterating `source` with `for await`), an async generator source function (`async function* ({ signal })`), an async generator function as the destination, and an async function destination whose value resolves the promise form and reaches the callback's second argument. A stage is written inline, or named by a function declaration or a `const` bound to a function expression that nothing reassigns. - The source may also be an array, a string, a synchronous generator object, or a synchronous generator function without parameters; their elements reach the next stage on the same ticks as in Node. + The source may also be an array, a string, a `Set`, a `Map`, a generator or async generator object, or a synchronous generator function without parameters; their elements reach the next stage on the same ticks as in Node. Stages may take the `{ signal }` argument. With a function destination, `pipeline()` returns an object-mode PassThrough that receives an async generator destination's values, or an async function destination's value unless it is `null` or `undefined`. `@types/node` types that result as `NodeJS.WritableStream`, so `for await` over it needs the `PassThrough` type (`pipeline(...) as PassThrough`, or a JSDoc `@type`). diff --git a/packages/cli/test/native-link-info.test.ts b/packages/cli/test/native-link-info.test.ts index 8ac579449..5e862e126 100644 --- a/packages/cli/test/native-link-info.test.ts +++ b/packages/cli/test/native-link-info.test.ts @@ -72,7 +72,7 @@ describe.runIf(supported)("macOS arm64 native link info", () => { minimum_os: "14.0", }, program: { object, entry_symbol: "main" }, - runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + runtime_abi: { version: 42, marker: "scr_runtime_abi_v42" }, runtime_pack: { kind: "precompiled", package: "@scriptc/runtime-darwin-arm64", @@ -165,6 +165,6 @@ describe.runIf(supported)("macOS arm64 native link info", () => { () => null, (failure: { stderr?: string }) => failure, ); - expect(error?.stderr).toContain("scr_runtime_abi_v37"); + expect(error?.stderr).toContain("scr_runtime_abi_v42"); }); }); diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 7a16c37e8..9c38c0983 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -795,6 +795,7 @@ export const LIB_FN_SYMS: Record = { "procStream.write": "scr_proc_stream_write", "stream.stdioWritable": "scr_stream_stdio_writable", "stream.unboxDyn": "scr_stream_unbox_dyn", + "stream.dynIterableSource": "scr_stream_dyn_iterable_source", "stream.handleStream": "scr_stream_handle", "stream.pipeDyn": "scr_stream_pipe_dyn", "stream.unpipeDyn": "scr_stream_unpipe_dyn", diff --git a/packages/compiler/src/backend/runtime-abi.ts b/packages/compiler/src/backend/runtime-abi.ts index 11bde6c2b..0eda18a5d 100644 --- a/packages/compiler/src/backend/runtime-abi.ts +++ b/packages/compiler/src/backend/runtime-abi.ts @@ -2,8 +2,8 @@ * of the link contract: a program object keeps this symbol undefined and the * matching runtime defines it, so incompatible manual links fail before the * program can start. */ -export const RUNTIME_ABI_VERSION = 37 as const; -export const RUNTIME_ABI_MARKER = "scr_runtime_abi_v37" as const; +export const RUNTIME_ABI_VERSION = 42 as const; +export const RUNTIME_ABI_MARKER = "scr_runtime_abi_v42" as const; /** Object consumption is useful today, but the complete scr_* surface may * still change before 1.0. The versioned marker prevents accidental mixing; diff --git a/packages/compiler/src/backend/runtime-pack-targets.test.ts b/packages/compiler/src/backend/runtime-pack-targets.test.ts index 9846e8d89..6f39c6d08 100644 --- a/packages/compiler/src/backend/runtime-pack-targets.test.ts +++ b/packages/compiler/src/backend/runtime-pack-targets.test.ts @@ -52,7 +52,7 @@ async function fixture(target: NativeTargetSpec, workers = false) { object_format: target.objectFormat, minimum_os: target.minimumOs, }, - runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + runtime_abi: { version: 42, marker: "scr_runtime_abi_v42" }, compiler: { command: "fixture", identity: "fixture", target: target.llvmTriple }, macros: { executable: [], excluded: ["SCR_LIB"], sanitizer: "external-toolchain-required" }, flavors: { diff --git a/packages/compiler/src/backend/runtime-pack.test.ts b/packages/compiler/src/backend/runtime-pack.test.ts index e2b24f8ca..4561fad54 100644 --- a/packages/compiler/src/backend/runtime-pack.test.ts +++ b/packages/compiler/src/backend/runtime-pack.test.ts @@ -128,7 +128,7 @@ async function fixture(target: NativeTargetSpec = MACOS_ARM64_TARGET) { object_format: target.objectFormat, minimum_os: target.minimumOs, }, - runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + runtime_abi: { version: 42, marker: "scr_runtime_abi_v42" }, compiler: { command: "clang", identity: "fixture clang", diff --git a/packages/compiler/src/frontend/lowering/lower-stream.ts b/packages/compiler/src/frontend/lowering/lower-stream.ts index 04c2fa043..72bea5dd7 100644 --- a/packages/compiler/src/frontend/lowering/lower-stream.ts +++ b/packages/compiler/src/frontend/lowering/lower-stream.ts @@ -2837,6 +2837,107 @@ export function streamClassAliasDecl( const PIPELINE_STAGE_EXPECTED = "of type function or an instance of Blob, ReadableStream, WritableStream, Stream, Iterable, AsyncIterable, or Promise or { readable, writable } pair"; +/** A checked-dynamic pipeline stage (an untyped source or destination): + * a boxed native stream unwraps at run time; other values (functions, + * pairs) throw the not-supported Error there. */ +function unboxDynStage(lowerer: Lowerer, v: IrExpr, node: ts.Expression): IrExpr { + noteUntypedStreamFlow(lowerer, null); + return { + kind: "libCall", + fn: "stream.unboxDyn", + args: [ + v, + strLit( + lowerer.dynNodeStreams + ? "pipeline stages other than native streams (JavaScript stream objects, iterables, generators, plain functions, and { readable, writable } pairs) are not supported yet" + : "pipeline stages other than native streams (iterables, generators, plain functions, and { readable, writable } pairs) are not supported yet", + locOf(node), + ), + ], + type: { kind: "object", className: "%Duplex" }, + loc: locOf(node), + }; +} + +/** A pipeline whose first stage is checked-dynamic, lowered with that + * stage already evaluated: `expr` is the stream it unboxes to, or, when + * `iterable` is set, the value to pump as an iterable source. */ +interface DynPipelineSource { + expr: IrExpr; + iterable: boolean; +} + +/** pipeline() whose first stage is a stream argument (not a function + * stage, an iterable of a static type, or a cipher value), lowered here. + * When the value is checked-dynamic, Node keeps a stream there and pipes + * it, and keeps an iterable (a string, an array, a generator, any value + * with an iterator method) and pumps it into the next stage. The value is + * evaluated once, and stream.dynIterableSource picks the lowering at run + * time. Null when the first stage is not such an argument. */ +function lowerDynSourcePipeline( + lowerer: Lowerer, + node: ts.Expression, + loc: SrcLoc, + build: (source: DynPipelineSource) => IrExpr, +): IrExpr | null { + if (pipelineStageFunction(lowerer, node) !== null) return null; + if (iterableSourceType(lowerer, node) !== null || isValueStream(lowerer, node)) return null; + let value = lowerer.lowerExpr(node); + // A Set, a Map or a generator object is iterated through its + // checked-dynamic value. + if (BOXED_SOURCE_KINDS.has(value.type.kind) && lowerer.dynConvertible(value.type)) { + value = { kind: "dynFrom", value, type: DYN, loc: value.loc }; + } + if (value.type.kind !== "dyn") { + let stream: IrExpr; + try { + stream = streamArgOf(lowerer, node, value, "pipeline"); + } catch (e) { + if (e instanceof StreamArgTypeThrow) return e.expr; + throw e; + } + return build({ expr: stream, iterable: false }); + } + const local = lowerer.declareHiddenLocal("%pipelineSource", DYN); + const ref = varRef(local.id, DYN, loc); + const stream = build({ expr: unboxDynStage(lowerer, ref, node), iterable: false }); + const iterable = build({ expr: ref, iterable: true }); + const type = stream.type; + return { + kind: "seqExpr", + stmts: [{ kind: "varDecl", localId: local.id, init: value, loc }], + result: { + kind: "ternary", + cond: { kind: "libCall", fn: "stream.dynIterableSource", args: [ref], type: BOOL, loc }, + then: lowerer.coerceToExpected(iterable, type), + else_: stream, + type, + loc, + }, + type, + loc, + }; +} + +/** The static types of a pipeline source that lowerDynSourcePipeline boxes + * as checked-dynamic values. An array or a string reaches it when the + * checker types the argument as any while its value keeps a static type. */ +const BOXED_SOURCE_KINDS: ReadonlySet = new Set([ + "set", + "map", + "generator", + "array", + "string", +]); + +/** lowerPipelineStages' source arguments for a checked-dynamic first stage. */ +function stagesSource( + src: DynPipelineSource | null, +): [ReadonlyMap | undefined, IrExpr | undefined] { + if (src === null) return [undefined, undefined]; + return src.iterable ? [undefined, src.expr] : [new Map([[0, src.expr]]), undefined]; +} + /** A stream-rooted argument, lowered — or the pointed fence (pipeline's * iterable/generator/function stages have no lowering yet). `what` picks * the validation ladder: finished() rejects EVERY non-stream through @@ -2848,7 +2949,16 @@ function lowerStreamArg( node: ts.Expression, what: "finished" | "pipeline" | "addAbortSignal" | "compose", ): IrExpr { - const lowered = lowerer.lowerExpr(node); + return streamArgOf(lowerer, node, lowerer.lowerExpr(node), what); +} + +/** lowerStreamArg over the argument's lowered value. */ +function streamArgOf( + lowerer: Lowerer, + node: ts.Expression, + lowered: IrExpr, + what: "finished" | "pipeline" | "addAbortSignal" | "compose", +): IrExpr { // A Hash, Hmac, Cipheriv or Decipheriv stage is its Transform; pipeline // and compose stages keep the value alive until the stream settles. const v = isValueStream(lowerer, node) @@ -2857,24 +2967,7 @@ function lowerStreamArg( // A checked-dynamic pipeline stage (an untyped source or destination): // a boxed native stream unwraps at run time; other values (iterables, // functions) throw the not-supported Error there. - if (v.type.kind === "dyn" && what === "pipeline") { - noteUntypedStreamFlow(lowerer, null); - return { - kind: "libCall", - fn: "stream.unboxDyn", - args: [ - v, - strLit( - lowerer.dynNodeStreams - ? "pipeline stages other than native streams (JavaScript stream objects, iterables, generators, plain functions, and { readable, writable } pairs) are not supported yet" - : "pipeline stages other than native streams (iterables, generators, plain functions, and { readable, writable } pairs) are not supported yet", - locOf(node), - ), - ], - type: { kind: "object", className: "%Duplex" }, - loc: locOf(node), - }; - } + if (v.type.kind === "dyn" && what === "pipeline") return unboxDynStage(lowerer, v, node); const info = v.type.kind === "object" ? lowerer.classes.get(v.type.className) : undefined; if (!streamSidesOf(lowerer, info)) { // A provably-non-stream value in a JS source (the invalid-input @@ -3210,57 +3303,82 @@ export function lowerStreamModuleCall( ? pipelineOptions(lowerer, lastArg) : null; const stageArgs = opts ? args.slice(0, -1) : args; - if (hasPipelineFunctionStage(lowerer, stageArgs)) { - const staged = lowerPipelineStages(lowerer, stageArgs, loc); - const type = staged.destPromise ?? { kind: "promise", inner: VOID }; - // A promise destination's value settles the result (same type). - if (!opts) { - return staged.wrap({ - kind: "libCall", - fn: "sp.pipelineStages", - args: staged.args, - type, - loc, - }); - } - // the options: end, and the signal (flags bit 6) - const flagsArg = staged.args[3]!; - if (flagsArg.kind !== "numLit") - throw new InternalCompilerError("pipeline flags not a literal"); - const args = [...staged.args, boolLit(opts.end, loc)]; - if (opts.signal) { - args[3] = numLit(flagsArg.value | 64, loc); - args.push(opts.signal); - } - return staged.wrap({ kind: "libCall", fn: "sp.pipelineStagesOpts", args, type, loc }); - } - let streams: IrExpr[]; - try { - streams = stageArgs.map((a) => lowerStreamArg(lowerer, a, "pipeline")); - } catch (e) { - if (e instanceof StreamArgTypeThrow) return e.expr; - throw e; - } - if (opts) { - const head = [numLit(streams.length, loc), ...streams, boolLit(opts.end, loc)]; - return { - kind: "libCall", - fn: opts.signal ? "sp.pipelineOptsSignal" : "sp.pipelineOpts", - args: opts.signal ? [...head, opts.signal] : head, - type: { kind: "promise", inner: VOID }, - loc, - }; - } - return { - kind: "libCall", - fn: "sp.pipeline", - args: [numLit(streams.length, loc), ...streams], - type: { kind: "promise", inner: VOID }, - loc, - }; + const build = (src: DynPipelineSource | null): IrExpr => + lowerPromisePipeline(lowerer, stageArgs, opts, src, loc); + return lowerDynSourcePipeline(lowerer, stageArgs[0]!, loc, build) ?? build(null); } return null; } + return lowerStreamModuleCallbackCall(lowerer, call, bi, loc); +} + +/** stream/promises pipeline(...stages[, options]), with the first stage + * pre-lowered when it is checked-dynamic (lowerDynSourcePipeline). */ +function lowerPromisePipeline( + lowerer: Lowerer, + stageArgs: readonly ts.Expression[], + opts: ReturnType | null, + src: DynPipelineSource | null, + loc: SrcLoc, +): IrExpr { + if (src?.iterable === true || hasPipelineFunctionStage(lowerer, stageArgs)) { + const staged = lowerPipelineStages(lowerer, stageArgs, loc, ...stagesSource(src)); + const type = staged.destPromise ?? { kind: "promise", inner: VOID }; + // A promise destination's value settles the result (same type). + if (!opts) { + return staged.wrap({ + kind: "libCall", + fn: "sp.pipelineStages", + args: staged.args, + type, + loc, + }); + } + // the options: end, and the signal (flags bit 6) + const flagsArg = staged.args[3]!; + if (flagsArg.kind !== "numLit") throw new InternalCompilerError("pipeline flags not a literal"); + const args = [...staged.args, boolLit(opts.end, loc)]; + if (opts.signal) { + args[3] = numLit(flagsArg.value | 64, loc); + args.push(opts.signal); + } + return staged.wrap({ kind: "libCall", fn: "sp.pipelineStagesOpts", args, type, loc }); + } + let streams: IrExpr[]; + try { + streams = stageArgs.map((a, i) => + i === 0 && src !== null ? src.expr : lowerStreamArg(lowerer, a, "pipeline"), + ); + } catch (e) { + if (e instanceof StreamArgTypeThrow) return e.expr; + throw e; + } + if (opts) { + const head = [numLit(streams.length, loc), ...streams, boolLit(opts.end, loc)]; + return { + kind: "libCall", + fn: opts.signal ? "sp.pipelineOptsSignal" : "sp.pipelineOpts", + args: opts.signal ? [...head, opts.signal] : head, + type: { kind: "promise", inner: VOID }, + loc, + }; + } + return { + kind: "libCall", + fn: "sp.pipeline", + args: [numLit(streams.length, loc), ...streams], + type: { kind: "promise", inner: VOID }, + loc, + }; +} + +/** The node:stream and stream/consumers members of lowerStreamModuleCall. */ +function lowerStreamModuleCallbackCall( + lowerer: Lowerer, + call: ts.CallExpression, + bi: { module: string; member: string }, + loc: SrcLoc, +): IrExpr | null { if (bi.module === "stream/consumers") { const args = call.arguments.nodes; // text/json/buffer/arrayBuffer(stream) → a pending promise the @@ -3411,67 +3529,9 @@ export function lowerStreamModuleCall( "the supported form is pipeline(source, ...streams, callback)", ); } - if (hasPipelineFunctionStage(lowerer, args.slice(0, -1))) { - const staged = lowerPipelineStages(lowerer, args.slice(0, -1), loc); - const cbNode = args[args.length - 1]!; - const cbParams = - ts.isArrowFunction(cbNode) || ts.isFunctionExpression(cbNode) - ? cbNode.parameters.nodes.length - : 0; - if (staged.dest === 2 || (staged.dest === 1 && cbParams > 1)) { - // callback(err, value): the destination's value (undefined for - // an async generator) reaches the callback through the - // checked-dynamic path. - const cb = lowerer.lowerExprExpecting(args[args.length - 1]!, DYN); - // SCR_PIPE_TYPED_CB: a typed callback whose error parameter cannot - // hold undefined takes null for no error; others take undefined. - const stagedArgs = [...staged.args]; - const flagsArg = stagedArgs[3]!; - if (flagsArg.kind !== "numLit") - throw new InternalCompilerError("pipeline flags not a literal"); - if ( - !isJsSourceFile(ts.getSourceFileOfNode(call)) && - !callbackErrorAdmitsUndefined(lowerer, cb) - ) - stagedArgs[3] = numLit(flagsArg.value | 128, loc); - return staged.wrap({ - kind: "libCall", - fn: "stream.pipelineStagesDyn", - args: [...stagedArgs, cb], - type: staged.last, - loc, - }); - } - const { cb, dyn } = lowerEosCallback( - lowerer, - "pipeline", - args[args.length - 1]!, - staged.last, - ); - return staged.wrap({ - kind: "libCall", - fn: dyn ? "stream.pipelineStagesDyn" : "stream.pipelineStages", - args: [...staged.args, cb], - type: staged.last, - loc, - }); - } - let streams: IrExpr[]; - try { - streams = args.slice(0, -1).map((a) => lowerStreamArg(lowerer, a, "pipeline")); - } catch (e) { - if (e instanceof StreamArgTypeThrow) return e.expr; - throw e; - } - const last = streams[streams.length - 1]!; - const { cb, dyn } = lowerEosCallback(lowerer, "pipeline", args[args.length - 1]!, last.type); - return { - kind: "libCall", - fn: dyn ? "stream.pipelineDyn" : "stream.pipeline", - args: [numLit(streams.length, loc), ...streams, cb], - type: last.type, - loc, - }; + const build = (src: DynPipelineSource | null): IrExpr => + lowerCallbackPipeline(lowerer, call, args, src, loc); + return lowerDynSourcePipeline(lowerer, args[0]!, loc, build) ?? build(null); } if (bi.member === "compose") { @@ -3484,6 +3544,75 @@ export function lowerStreamModuleCall( return null; } +/** pipeline(...stages, callback), with the first stage pre-lowered when it + * is checked-dynamic (lowerDynSourcePipeline). */ +function lowerCallbackPipeline( + lowerer: Lowerer, + call: ts.CallExpression, + args: readonly ts.Expression[], + src: DynPipelineSource | null, + loc: SrcLoc, +): IrExpr { + if (src?.iterable === true || hasPipelineFunctionStage(lowerer, args.slice(0, -1))) { + const staged = lowerPipelineStages(lowerer, args.slice(0, -1), loc, ...stagesSource(src)); + const cbNode = args[args.length - 1]!; + const cbParams = + ts.isArrowFunction(cbNode) || ts.isFunctionExpression(cbNode) + ? cbNode.parameters.nodes.length + : 0; + if (staged.dest === 2 || (staged.dest === 1 && cbParams > 1)) { + // callback(err, value): the destination's value (undefined for + // an async generator) reaches the callback through the + // checked-dynamic path. + const cb = lowerer.lowerExprExpecting(args[args.length - 1]!, DYN); + // SCR_PIPE_TYPED_CB: a typed callback whose error parameter cannot + // hold undefined takes null for no error; others take undefined. + const stagedArgs = [...staged.args]; + const flagsArg = stagedArgs[3]!; + if (flagsArg.kind !== "numLit") + throw new InternalCompilerError("pipeline flags not a literal"); + if ( + !isJsSourceFile(ts.getSourceFileOfNode(call)) && + !callbackErrorAdmitsUndefined(lowerer, cb) + ) + stagedArgs[3] = numLit(flagsArg.value | 128, loc); + return staged.wrap({ + kind: "libCall", + fn: "stream.pipelineStagesDyn", + args: [...stagedArgs, cb], + type: staged.last, + loc, + }); + } + const { cb, dyn } = lowerEosCallback(lowerer, "pipeline", args[args.length - 1]!, staged.last); + return staged.wrap({ + kind: "libCall", + fn: dyn ? "stream.pipelineStagesDyn" : "stream.pipelineStages", + args: [...staged.args, cb], + type: staged.last, + loc, + }); + } + let streams: IrExpr[]; + try { + streams = args + .slice(0, -1) + .map((a, i) => (i === 0 && src !== null ? src.expr : lowerStreamArg(lowerer, a, "pipeline"))); + } catch (e) { + if (e instanceof StreamArgTypeThrow) return e.expr; + throw e; + } + const last = streams[streams.length - 1]!; + const { cb, dyn } = lowerEosCallback(lowerer, "pipeline", args[args.length - 1]!, last.type); + return { + kind: "libCall", + fn: dyn ? "stream.pipelineDyn" : "stream.pipeline", + args: [numLit(streams.length, loc), ...streams, cb], + type: last.type, + loc, + }; +} + /** A pipeline() function stage: an inline function or arrow function, or * an identifier bound to a function declaration or to a `const` * initialized with one, which nothing reassigns. */ @@ -3788,6 +3917,237 @@ function lowerWebStreamSource( }; } +/** A checked-dynamic pipeline source that is an iterable at run time + * (stream.dynIterableSource), as an async generator closure that iterates + * it as Node's pipeline does with `for await`: the value's async iterator, + * or its sync iterator stepped like the typed iterable sources. Each value + * is yielded; leaving early closes the iterator through its return(). */ +function lowerDynIterableSource( + lowerer: Lowerer, + value: IrExpr, + loc: SrcLoc, +): { closure: IrExpr; out: SyncGenType } | null { + const out: SyncGenType = { + kind: "generator", + async: true, + yieldT: DYN, + retT: VOID, + nextT: UNDEFINED_T, + }; + const genResultT = genResultRecord(DYN, VOID, lowerer.shapes, lowerer.unions); + if (!genResultT) return null; + const key = "dynIterableSource"; + let maker = lowerer.valueHelpers.get(key); + if (!maker) { + maker = `%stream.dynIterableSource.${lowerer.valueHelpers.size}`; + const genName = `${maker}.gen`; + const frame = new LiftedFrame(loc); + const srcId = frame.local("src", DYN, false); + const itId = frame.local("it", DYN, false); + const syncId = frame.local("sync", BOOL, false); + const nextId = frame.local("next", DYN, false); + const stepId = frame.local("step", DYN, true); + const activeId = frame.local("active", BOOL, true); + const closeId = frame.local("close", DYN, false); + const it = (): IrExpr => varRef(itId, DYN, loc); + const sync = (): IrExpr => varRef(syncId, BOOL, loc); + const step = (): IrExpr => varRef(stepId, DYN, loc); + const get = (obj: IrExpr, name: string): IrExpr => ({ + kind: "dynKeyGet", + value: obj, + key: strLit(name, loc), + type: DYN, + loc, + }); + const awaitDyn = (v: IrExpr): IrExpr => ({ + kind: "libCall", + fn: "async.awaitDyn", + args: [v], + type: DYN, + loc, + }); + const call = (callee: IrExpr, calleeName: string): IrExpr => ({ + kind: "dynCall", + callee, + receiver: it(), + calleeName, + args: [], + type: DYN, + loc, + }); + const setActive = (on: boolean): IrStmt => ({ + kind: "assign", + localId: activeId, + value: boolLit(on, loc), + loc, + }); + const nextCall = (): IrExpr => call(varRef(nextId, DYN, loc), "iterator method"); + const body: IrStmt[] = [ + { + kind: "varDecl", + localId: itId, + init: { + kind: "libCall", + fn: "dyn.iteratorResult", + args: [ + { + kind: "libCall", + fn: "dyn.asyncIteratorOpen", + args: [varRef(srcId, DYN, loc), strLit("", loc)], + type: DYN, + loc, + }, + ], + type: DYN, + loc, + }, + loc, + }, + { + kind: "varDecl", + localId: syncId, + init: { kind: "libCall", fn: "dyn.asyncIteratorWasSync", args: [], type: BOOL, loc }, + loc, + }, + { kind: "varDecl", localId: nextId, init: get(it(), "next"), loc }, + { kind: "varDecl", localId: stepId, init: dynUndefinedExpr(loc), loc }, + { kind: "varDecl", localId: activeId, init: boolLit(false, loc), loc }, + { + kind: "tryCatch", + tryBody: [ + { + kind: "while", + cond: boolLit(true, loc), + body: [ + setActive(false), + { + kind: "assign", + localId: stepId, + value: { + kind: "libCall", + fn: "dyn.iteratorResult", + args: [ + { + kind: "ternary", + cond: sync(), + then: nextCall(), + else_: awaitDyn(nextCall()), + type: DYN, + loc, + }, + ], + type: DYN, + loc, + }, + loc, + }, + { + kind: "if", + cond: { + kind: "dynTest", + test: "truthy", + value: get(step(), "done"), + type: BOOL, + loc, + }, + then: [{ kind: "break", loc }], + else_: null, + loc, + }, + setActive(true), + { + kind: "exprStmt", + expr: { kind: "yieldExpr", value: get(step(), "value"), type: VOID, loc }, + loc, + }, + ], + loc, + }, + ], + catchBody: null, + catchLocalId: null, + finallyBody: [ + { + kind: "if", + cond: varRef(activeId, BOOL, loc), + then: [ + { kind: "varDecl", localId: closeId, init: get(it(), "return"), loc }, + { + kind: "if", + cond: { + kind: "unary", + op: "!", + operand: { + kind: "dynTest", + test: "nullish", + value: varRef(closeId, DYN, loc), + type: BOOL, + loc, + }, + type: BOOL, + loc, + }, + then: [ + { + kind: "exprStmt", + expr: awaitDyn(call(varRef(closeId, DYN, loc), "iterator return")), + loc, + }, + ], + else_: null, + loc, + }, + ], + else_: null, + loc, + }, + ], + loc, + }, + { kind: "return", value: null, loc }, + ]; + const srcLocal = frame.locals.find((l) => l.id === srcId)!; + srcLocal.boxed = true; + lowerer.valueHelpers.set(key, maker); + lowerer.liftedFns.push({ + name: genName, + params: [], + returnType: VOID, + async: true, + captures: [{ localId: srcId, name: "src", type: DYN }], + locals: frame.locals, + body, + generator: { yieldT: DYN, nextT: UNDEFINED_T, resultType: genResultT }, + loc, + }); + const makerSrc: IrLocal = { id: "src.0", name: "src", type: DYN, mutable: false, boxed: true }; + lowerer.liftedFns.push({ + name: maker, + params: [{ localId: makerSrc.id, name: makerSrc.name, type: DYN }], + returnType: funcOf([], out), + locals: [makerSrc], + body: [ + { + kind: "return", + value: { + kind: "closure", + fnName: genName, + captures: [makerSrc.id], + type: funcOf([], out), + loc, + }, + loc, + }, + ], + loc, + }); + } + return { + closure: { kind: "call", callee: maker, args: [value], type: funcOf([], out), loc }, + out, + }; +} + function lowerIterableSource( lowerer: Lowerer, node: ts.Expression, @@ -3951,6 +4311,7 @@ function lowerPipelineStages( stageArgs: readonly ts.Expression[], loc: SrcLoc, preLowered?: ReadonlyMap, + dynSource?: IrExpr, ): PipelineStagesLowering { if (stageArgs.length > 52) { lowerer.noLowering( @@ -3975,6 +4336,15 @@ function lowerPipelineStages( const argOrder: { list: IrExpr[]; index: number }[] = []; for (let j = 0; j < stageArgs.length; j++) { const arg = stageArgs[j]!; + if (j === 0 && dynSource !== undefined) { + const source = lowerDynIterableSource(lowerer, dynSource, loc); + if (source === null) lowerer.noLowering("pipeline over this source", arg); + positions += 1; + argOrder.push({ list: stages, index: stages.length }); + stages.push(source!.closure); + srcT = source!.out; + continue; + } // compose's head and tail functions arrive as Duplex.from streams const fn = preLowered?.has(j) ? null : pipelineStageFunction(lowerer, arg); const syncSourceFn = diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index 390c7fbc3..1821b6a6b 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -91,6 +91,7 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "procStream.write", "child.stdioStream", "stream.unboxDyn", + "stream.dynIterableSource", "stream.handleStream", "stream.pipeDyn", "stream.unpipeDyn", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 216e46a4d..2cc5c708e 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -2786,6 +2786,10 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ argTypes: [DYN, STRING], result: { kind: "object", className: "%Duplex" }, }, + /** Whether pipeline() pumps a checked-dynamic first stage as an + * iterable (a string, or a value with an iterator method that is not a + * stream with pipe() and on()) instead of piping it as a stream. */ + "stream.dynIterableSource": { argTypes: [DYN], result: BOOL }, /** The Transform a Cipheriv or Decipheriv reads and writes as a stream * (+1, created on first use and owned by the cipher). */ "stream.handleStream": { diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 85b21af7b..f66697567 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -263,6 +263,7 @@ const STREAM_LIB_FNS: ReadonlySet = new Set([ "stream.prop", "stream.stdioWritable", "stream.unboxDyn", + "stream.dynIterableSource", "stream.handleStream", "stream.unpipeDyn", "stream.workerStdio", diff --git a/packages/compiler/test/native-codegen-integration.test.ts b/packages/compiler/test/native-codegen-integration.test.ts index cecebb49c..1be1b7a3f 100644 --- a/packages/compiler/test/native-codegen-integration.test.ts +++ b/packages/compiler/test/native-codegen-integration.test.ts @@ -378,7 +378,7 @@ done: expect(await symbols(helperObject, ["-u"])).toEqual(await symbols(clangObject, ["-u"])); expect(await symbols(helperObject, ["-gU"])).toEqual(await symbols(clangObject, ["-gU"])); expect(await symbols(helperObject, ["-gU"])).toEqual(["0000000000000000 T _main"]); - expect(await symbols(helperObject, ["-u"])).toContain("_scr_runtime_abi_v37"); + expect(await symbols(helperObject, ["-u"])).toContain("_scr_runtime_abi_v42"); const clangExe = join(dir, "clang-program"); const linkDriver = join(dir, "clang-driver.c"); @@ -712,7 +712,7 @@ done: .split("\n"); expect(undefinedSymbols).toContain("_sf_scale"); expect(undefinedSymbols).toContain("_sf_callback_mix"); - expect(undefinedSymbols).toContain("_scr_runtime_abi_v37"); + expect(undefinedSymbols).toContain("_scr_runtime_abi_v42"); }); test("helper and clang object paths retain the same outbound FFI C ABI", async () => { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7503-pipeline-untyped-sources.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7503-pipeline-untyped-sources.mjs.json new file mode 100644 index 000000000..4d93af132 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7503-pipeline-untyped-sources.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7503-pipeline-untyped-sources.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7504-pipeline-untyped-source-errors.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7504-pipeline-untyped-source-errors.mjs.json new file mode 100644 index 000000000..19402586b --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7504-pipeline-untyped-source-errors.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7504-pipeline-untyped-source-errors.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7505-pipeline-untyped-sources.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7505-pipeline-untyped-sources.cjs.json new file mode 100644 index 000000000..29d85351d --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7505-pipeline-untyped-sources.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7505-pipeline-untyped-sources.cjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7506-pipeline-any-source.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7506-pipeline-any-source.ts.json new file mode 100644 index 000000000..942a2b3e8 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7506-pipeline-any-source.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7506-pipeline-any-source.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7507-stream-write-error-drain.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7507-stream-write-error-drain.mjs.json new file mode 100644 index 000000000..6fa55d09d --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7507-stream-write-error-drain.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7507-stream-write-error-drain.mjs" + ], + "diags": [] +} diff --git a/packages/runtime-darwin-arm64/scripts/build.mjs b/packages/runtime-darwin-arm64/scripts/build.mjs index b6b855c05..56f5ca559 100644 --- a/packages/runtime-darwin-arm64/scripts/build.mjs +++ b/packages/runtime-darwin-arm64/scripts/build.mjs @@ -366,7 +366,7 @@ async function build() { package: packageManifest.name, version: packageManifest.version, target: RUNTIME_PACK_MATRIX.target, - runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + runtime_abi: { version: 42, marker: "scr_runtime_abi_v42" }, compiler: { command: compiler, identity: compilerVersion, diff --git a/packages/runtime-pack-common/scripts/build.mjs b/packages/runtime-pack-common/scripts/build.mjs index 479d8aad4..c571a25c5 100644 --- a/packages/runtime-pack-common/scripts/build.mjs +++ b/packages/runtime-pack-common/scripts/build.mjs @@ -469,7 +469,7 @@ async function build() { package: packageManifest.name, version: packageManifest.version, target: matrix.target, - runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + runtime_abi: { version: 42, marker: "scr_runtime_abi_v42" }, compiler: { command: compiler, identity: compilerVersion, diff --git a/packages/runtime/src/scr_console.c b/packages/runtime/src/scr_console.c index 086340014..6c15f932c 100644 --- a/packages/runtime/src/scr_console.c +++ b/packages/runtime/src/scr_console.c @@ -148,7 +148,7 @@ static void scr_enable_utf8_console_output(void) { } #endif -void scr_runtime_abi_v37(void) {} +void scr_runtime_abi_v42(void) {} void scr_init(void) { #ifdef SCR_WORKERS diff --git a/packages/runtime/src/scr_core.h b/packages/runtime/src/scr_core.h index 3707b8d50..5415ccdc6 100644 --- a/packages/runtime/src/scr_core.h +++ b/packages/runtime/src/scr_core.h @@ -81,7 +81,7 @@ void scr_init(void); /* Program objects emitted by the bundled LLVM helper reference this symbol. * Its versioned spelling makes a mismatched manual runtime link fail before * the program can start. */ -void scr_runtime_abi_v37(void); +void scr_runtime_abi_v42(void); void scr_runtime_workers_v8(void); /* ── the trap funnel (scr_console.c; scr_library.c under -DSCR_LIB) ────── diff --git a/packages/runtime/src/scr_stream.c b/packages/runtime/src/scr_stream.c index ec061e10c..be6d3635f 100644 --- a/packages/runtime/src/scr_stream.c +++ b/packages/runtime/src/scr_stream.c @@ -6866,10 +6866,12 @@ static bool scr_stream_write_chunk_enc(ScrStream *s, ScrBytes *chunk /*borrowed* scr_stream_do_write(s, scr_stream_wchunk_retain(st, chunk), cb, enc); } /* Node computes the answer AFTER the (possibly synchronous) write: - * a sync completion has already drained its bytes from length. */ - bool ret = st->w.length < st->w.hwm && !st->destroyed && !st->errored; - if (!ret) st->w.need_drain = true; - return ret; + * a sync completion has already drained its bytes from length. Only + * the length sets needDrain; an errored or destroyed stream answers + * false without waiting for 'drain'. */ + bool below = st->w.length < st->w.hwm; + if (!below) st->w.need_drain = true; + return below && !st->destroyed && !st->errored; } static bool scr_stream_write_chunk(ScrStream *s, ScrBytes *chunk /*borrowed*/, ScrClosure *cb /*moves*/) { @@ -8407,3 +8409,31 @@ ScrStream *scr_stream_unbox_dyn(const ScrDyn *value, const ScrStr *message) { scr_throw_error_msg_code(SCR_ERR_ERROR, message->data, message->len, "SC2020"); return NULL; } + +/* pipeline.js's first stage: a value with pipe() and on() methods is a + * readable node stream, which the stage ladder tests before isIterable; + * a string, or a value with a Symbol.asyncIterator or Symbol.iterator + * method, is an iterable the pipeline pumps into the next stage. */ +bool scr_stream_dyn_iterable_source(const ScrDyn *value) { + ScrStream *stream = scr_stream_of_handle(value); + if (!stream) stream = scr_stream_boxed(value); + if (stream) { + scr_stream_release(stream); + return false; + } + if (value->kind == SCR_DYN_STR) return true; + if (value->kind == SCR_DYN_OBJ) { + ScrDyn *pipe = scr_dyn_obj_read(value, "pipe", 4); + if (!pipe) return false; + bool streamish = pipe->kind == SCR_DYN_FUNC; + scr_dyn_release(pipe); + if (streamish) { + ScrDyn *on = scr_dyn_obj_read(value, "on", 2); + if (!on) return false; + streamish = on->kind == SCR_DYN_FUNC; + scr_dyn_release(on); + if (streamish) return false; + } + } + return scr_dyn_iterable_kind(value) > 0; +} diff --git a/packages/runtime/src/scr_stream.h b/packages/runtime/src/scr_stream.h index a4798c629..7acad0eeb 100644 --- a/packages/runtime/src/scr_stream.h +++ b/packages/runtime/src/scr_stream.h @@ -145,6 +145,10 @@ ScrStream *scr_stream_pipe_general(ScrStream *src, ScrStream *dst, bool end); /* A boxed native stream out of a checked-dynamic pipeline stage (+1), or * NULL with `message` thrown as the not-supported Error. */ ScrStream *scr_stream_unbox_dyn(const struct ScrDyn *value, const ScrStr *message); +/* Whether pipeline() keeps a checked-dynamic first stage as an iterable + * to pump rather than as a stream (false with an exception pending when + * reading the value's members throws). */ +bool scr_stream_dyn_iterable_source(const struct ScrDyn *value); /* Handles that are Transforms (ScrDynHandleOps.transform: Cipheriv and * Decipheriv). scr_stream_of_handle: the handle's Transform (+1), built on * first use, or NULL when the value is not such a handle. diff --git a/tests/corpus/7503-pipeline-untyped-sources.mjs b/tests/corpus/7503-pipeline-untyped-sources.mjs new file mode 100644 index 000000000..3dbc90eee --- /dev/null +++ b/tests/corpus/7503-pipeline-untyped-sources.mjs @@ -0,0 +1,102 @@ +// pipeline() over untyped iterable sources: arrays, strings, Sets, generator +// objects, async generator objects, class iterables and object values, +// into Writables, a Transform chain, a function stage and the promise form. +// Each source is pumped as Node pumps an iterable, on the same ticks. +import { pipeline, Writable, Transform } from "node:stream"; +import { pipeline as pipelineP } from "node:stream/promises"; + +const log = []; +function show(chunk) { + return typeof chunk === "string" ? chunk : Buffer.isBuffer(chunk) ? chunk.toString() : JSON.stringify(chunk); +} +function objectSink(label) { + return new Writable({ + objectMode: true, + write(chunk, _enc, cb) { + log.push(`${label} write ${show(chunk)}`); + cb(); + }, + final(cb) { log.push(`${label} final`); cb(); }, + }); +} +function sink(label, objectMode = false) { + if (objectMode) return objectSink(label); + return new Writable({ + write(chunk, _enc, cb) { + log.push(`${label} write ${typeof chunk === "string" ? chunk : Buffer.isBuffer(chunk) ? chunk.toString() : JSON.stringify(chunk)}`); + cb(); + }, + final(cb) { log.push(`${label} final`); cb(); }, + }); +} +function* gen() { + log.push("gen start"); + yield "g1"; + log.push("gen mid"); + yield "g2"; + log.push("gen end"); +} +async function* agen() { + yield "a1"; + await null; + yield "a2"; +} +const sources = { + array: () => ["x", "y"], + string: () => "hey", + set: () => new Set(["s1", "s2"]), + gen: () => gen(), + agen: () => agen(), + iterable: () => ({ *[Symbol.iterator]() { yield "i1"; yield "i2"; } }), + objects: () => [{ n: 1 }, { n: 2 }], +}; +const names = Object.keys(sources); +async function run(name) { + const src = sources[name](); + const objectMode = name === "objects"; + await new Promise((resolve) => { + queueMicrotask(() => log.push(`${name} microtask`)); + pipeline(src, sink(name, objectMode), (err) => { + log.push(`${name} done ${err ? err.code ?? err.message : err}`); + resolve(); + }); + log.push(`${name} after call`); + }); +} +for (const n of names) await run(n); + +// a transform chain and a function stage after an untyped source +const src2 = ["p", "q"]; +await new Promise((resolve) => + pipeline( + src2, + new Transform({ transform(c, _e, cb) { cb(null, c.toString().toUpperCase()); } }), + sink("transform"), + (err) => { log.push(`transform done ${err}`); resolve(); }, + ), +); +const src3 = new Set(["f1", "f2"]); +await new Promise((resolve) => + pipeline( + src3, + async function* (source) { for await (const c of source) yield c + "!"; }, + sink("fnstage"), + (err) => { log.push(`fnstage done ${err}`); resolve(); }, + ), +); +// promises form +const src4 = ["m", "n"]; +await pipelineP(src4, sink("promises")); +log.push("promises resolved"); +// an error thrown by the source +function* bad() { yield "ok"; throw new Error("source failed"); } +const src5 = bad(); +await new Promise((resolve) => + pipeline(src5, sink("bad"), (err) => { log.push(`bad done ${err && err.message}`); resolve(); }), +); +// a source of non-string values into a byte-mode writable +const src6 = [1, 2]; +await new Promise((resolve) => + pipeline(src6, sink("numbers"), (err) => { log.push(`numbers done ${err && err.code}`); resolve(); }), +); +console.log(log.join("\n")); diff --git a/tests/corpus/7504-pipeline-untyped-source-errors.mjs b/tests/corpus/7504-pipeline-untyped-source-errors.mjs new file mode 100644 index 000000000..fcbfa9d60 --- /dev/null +++ b/tests/corpus/7504-pipeline-untyped-source-errors.mjs @@ -0,0 +1,90 @@ +// pipeline() over untyped iterable sources: a destination that fails closes +// the source, backpressure waits for drain, an abort signal stops the pump, +// and async generator and Map sources reach object-mode destinations. +import { pipeline, Writable, PassThrough } from "node:stream"; +import { pipeline as pipelineP } from "node:stream/promises"; + +function* counted(label, n) { + try { + for (let i = 0; i < n; i++) { + console.log(label, "yield", i); + yield `${label}${i}`; + } + } finally { + console.log(label, "finally"); + } +} +function pick(v) { + return v; +} + +// the destination fails on its second write: the source's finally runs +await new Promise((resolve) => { + let n = 0; + const dst = new Writable({ + write(chunk, _e, cb) { + n++; + console.log("fail write", String(chunk)); + cb(n === 2 ? new Error("write failed") : null); + }, + }); + pipeline(pick(counted("f", 5)), dst, (err) => { + console.log("fail done", err && err.message); + resolve(); + }); +}); + +// backpressure: a one-byte highWaterMark and asynchronous writes +await new Promise((resolve) => { + const dst = new Writable({ + highWaterMark: 1, + write(chunk, _e, cb) { + console.log("slow write", String(chunk)); + setTimeout(cb, 1); + }, + }); + pipeline(pick(counted("b", 3)), dst, (err) => { + console.log("slow done", err); + resolve(); + }); +}); + +// an abort signal +const ac = new AbortController(); +try { + await pipelineP( + pick(counted("s", 10)), + new Writable({ + write(chunk, _e, cb) { + console.log("signal write", String(chunk)); + if (String(chunk) === "s1") ac.abort(); + cb(); + }, + }), + { signal: ac.signal }, + ); +} catch (err) { + console.log("signal rejected", err.name); +} + +// an untyped async generator into a PassThrough read with for await +const out = new PassThrough({ objectMode: true }); +const both = pipelineP( + pick((async function* () { + yield "u1"; + yield "u2"; + })()), + out, +); +for await (const c of out) console.log("passthrough", c); +await both; +console.log("passthrough resolved"); + +// a Map source of entries into an object-mode sink +await new Promise((resolve) => { + pipeline( + pick(new Map([["k", 1]])), + new Writable({ objectMode: true, write(c, _e, cb) { console.log("map write", JSON.stringify(c)); cb(); } }), + (err) => { console.log("map done", err); resolve(); }, + ); +}); diff --git a/tests/corpus/7505-pipeline-untyped-sources.cjs b/tests/corpus/7505-pipeline-untyped-sources.cjs new file mode 100644 index 000000000..6dd67b4ff --- /dev/null +++ b/tests/corpus/7505-pipeline-untyped-sources.cjs @@ -0,0 +1,40 @@ +// pipeline() over untyped sources in CommonJS: a source that a function +// answers, which may be an array, a generator, a stream, a string, or a +// Buffer, whose bytes are numbers that a byte-mode Writable refuses. +const { pipeline, Readable, Writable } = require("node:stream"); + +function sink(label) { + const parts = []; + return new Writable({ + write(chunk, _enc, cb) { + parts.push(String(chunk)); + cb(); + }, + final(cb) { + console.log(label, parts.join("|")); + cb(); + }, + }); +} + +function* letters() { + yield "a"; + yield "b"; +} + +const sources = [ + () => ["one", "two"], + () => letters(), + () => Readable.from(["r1", "r2"]), + () => "xyz", + () => Buffer.from("buf"), +]; + +function run(i) { + if (i === sources.length) return; + pipeline(sources[i](), sink(`source ${i}`), (err) => { + console.log(`source ${i} done`, err === undefined ? "ok" : err.code); + run(i + 1); + }); +} +run(0); diff --git a/tests/corpus/7506-pipeline-any-source.ts b/tests/corpus/7506-pipeline-any-source.ts new file mode 100644 index 000000000..84eec0cf4 --- /dev/null +++ b/tests/corpus/7506-pipeline-any-source.ts @@ -0,0 +1,48 @@ +// pipeline() in TypeScript over sources typed any or unknown, and over a +// Set, a Map and an async generator object, which are pumped as iterables. +import { pipeline, Writable } from "node:stream"; +import { pipeline as pipelineP } from "node:stream/promises"; + +function sink(label: string): Writable { + const parts: string[] = []; + return new Writable({ + objectMode: true, + write(chunk: unknown, _enc, cb) { + parts.push(JSON.stringify(chunk)); + cb(); + }, + final(cb) { + console.log(label, parts.join(" ")); + cb(); + }, + }); +} + +async function* ticks(): AsyncGenerator { + yield "t1"; + await new Promise((r) => setTimeout(r, 1)); + yield "t2"; +} + +async function main(): Promise { + const anySource: any = ["any1", "any2"]; + await pipelineP(anySource, sink("any")); + const unknownSource: unknown = new Set([1, 2, 3]); + await pipelineP(unknownSource as any, sink("unknown")); + await pipelineP(new Set(["s"]), sink("set")); + await pipelineP( + new Map([ + ["a", 1], + ["b", 2], + ]), + sink("map"), + ); + await pipelineP(ticks(), sink("async generator")); + await new Promise((resolve) => { + pipeline(anySource, sink("callback"), (err?: Error | null) => { + console.log("callback done", err); + resolve(); + }); + }); +} +void main(); diff --git a/tests/corpus/7507-stream-write-error-drain.mjs b/tests/corpus/7507-stream-write-error-drain.mjs new file mode 100644 index 000000000..8298bcb42 --- /dev/null +++ b/tests/corpus/7507-stream-write-error-drain.mjs @@ -0,0 +1,37 @@ +// A write whose callback fails synchronously: write() answers false and +// writableNeedDrain stays false, so no 'drain' follows the error, and a +// pipeline pumping a generator stops at the failed write. +import { pipeline, Writable } from "node:stream"; + +const w = new Writable({ + write(_chunk, _enc, cb) { + cb(new Error("bad write")); + }, +}); +w.on("error", (e) => console.log("error event", e.message)); +w.on("drain", () => console.log("drain")); +const r = w.write("a"); +console.log("returned", r, "needDrain", w.writableNeedDrain, "errored", w.errored.message); + +function* source() { + try { + for (let i = 0; i < 4; i++) { + console.log("yield", i); + yield `c${i}`; + } + } finally { + console.log("source finally"); + } +} +let writes = 0; +pipeline( + source(), + new Writable({ + write(chunk, _enc, cb) { + writes++; + console.log("write", String(chunk)); + cb(writes === 2 ? new Error("second write failed") : null); + }, + }), + (err) => console.log("pipeline done", err.message), +); diff --git a/tests/harness/corpus-costs/7503-pipeline-untyped-sources.mjs.json b/tests/harness/corpus-costs/7503-pipeline-untyped-sources.mjs.json new file mode 100644 index 000000000..d2d431b0f --- /dev/null +++ b/tests/harness/corpus-costs/7503-pipeline-untyped-sources.mjs.json @@ -0,0 +1 @@ +{ "plain": 5499, "san": 7259 } diff --git a/tests/harness/corpus-costs/7504-pipeline-untyped-source-errors.mjs.json b/tests/harness/corpus-costs/7504-pipeline-untyped-source-errors.mjs.json new file mode 100644 index 000000000..4fd20681f --- /dev/null +++ b/tests/harness/corpus-costs/7504-pipeline-untyped-source-errors.mjs.json @@ -0,0 +1 @@ +{ "plain": 3431, "san": 4529 } diff --git a/tests/harness/corpus-costs/7505-pipeline-untyped-sources.cjs.json b/tests/harness/corpus-costs/7505-pipeline-untyped-sources.cjs.json new file mode 100644 index 000000000..3bb5df076 --- /dev/null +++ b/tests/harness/corpus-costs/7505-pipeline-untyped-sources.cjs.json @@ -0,0 +1 @@ +{ "plain": 3197, "san": 4220 } diff --git a/tests/harness/corpus-costs/7506-pipeline-any-source.ts.json b/tests/harness/corpus-costs/7506-pipeline-any-source.ts.json new file mode 100644 index 000000000..454dcb2c0 --- /dev/null +++ b/tests/harness/corpus-costs/7506-pipeline-any-source.ts.json @@ -0,0 +1 @@ +{ "plain": 3250, "san": 4741 } diff --git a/tests/harness/corpus-costs/7507-stream-write-error-drain.mjs.json b/tests/harness/corpus-costs/7507-stream-write-error-drain.mjs.json new file mode 100644 index 000000000..35f298bef --- /dev/null +++ b/tests/harness/corpus-costs/7507-stream-write-error-drain.mjs.json @@ -0,0 +1 @@ +{ "plain": 2735, "san": 4076 } diff --git a/tests/harness/self-hosting-native-toolchain.test.ts b/tests/harness/self-hosting-native-toolchain.test.ts index c5476328e..f4121bf88 100644 --- a/tests/harness/self-hosting-native-toolchain.test.ts +++ b/tests/harness/self-hosting-native-toolchain.test.ts @@ -109,7 +109,7 @@ for (const backend of ["llvm"] as const) { object_format: target.objectFormat, minimum_os: target.minimumOs, }, - runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + runtime_abi: { version: 42, marker: "scr_runtime_abi_v42" }, compiler: { command: "fixture", identity: "fixture", target: target.llvmTriple }, macros: { executable: [], excluded: [], sanitizer: "external-toolchain-required" }, flavors: { From 205f09995788d8bb8821538c1175c853c82d947a Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 10:26:38 -0500 Subject: [PATCH 102/259] Keep an unchanged executable on its first Linux rebuild On Linux the executable cache stored an executable only from a key's second link on, so the first unchanged rebuild after a build linked again, and only the build after that restored the executable. - A key's first link on Linux is traced, in the same verbose link. Instead of storing the executable, the cache records the output's file identity together with the link's inputs once the output is in place. - keep() answers an unchanged rebuild whose output still has that identity and whose inputs are unchanged. The build then neither links nor copies: the output stays as it is. - A rebuild whose output changed or is missing links again; from that second link on, the executable is stored as before and restored where needed. - The cache records the output after every Linux build that places one, so the next unchanged rebuild keeps it. darwin keeps its existing behavior. --- packages/compiler/src/native/cache.ts | 15 +- packages/compiler/src/native/compiler.ts | 9 +- .../src/native/executable-cache.test.ts | 38 +++-- .../compiler/src/native/executable-cache.ts | 137 +++++++++++++----- 4 files changed, 138 insertions(+), 61 deletions(-) diff --git a/packages/compiler/src/native/cache.ts b/packages/compiler/src/native/cache.ts index 937b4b109..712c1c232 100644 --- a/packages/compiler/src/native/cache.ts +++ b/packages/compiler/src/native/cache.ts @@ -118,22 +118,11 @@ export class NativeCache { } } - /** Whether a marker or entry exists, without reading or checking it. */ + /** Whether an entry exists, without reading or checking it. */ has(family: string, key: string): boolean { return existsSync(join(this.root, family, key)); } - /** Records an empty marker that has() finds. */ - mark(family: string, key: string): void { - try { - const directory = join(this.root, family); - mkdirSync(directory, { recursive: true, mode: 0o700 }); - writeFileSync(join(directory, key), ""); - } catch { - /* Cache failures never change a build's result. */ - } - } - /** Writes `bytes` under their content digest, and returns the digest. */ writeContent(family: string, bytes: Uint8Array): string { const digest = contentDigest(bytes); @@ -178,7 +167,7 @@ export class NativeCache { "object", "sanitizer", "executable", - "linked", + "kept", "binary", "dsym", "coverage", diff --git a/packages/compiler/src/native/compiler.ts b/packages/compiler/src/native/compiler.ts index 63769fba6..a4582ec49 100644 --- a/packages/compiler/src/native/compiler.ts +++ b/packages/compiler/src/native/compiler.ts @@ -407,7 +407,9 @@ export class NativeCompiler { ffi, executablePack, ); - const restored = executableCache?.restore(stagedOutput) ?? false; + // An unchanged rebuild keeps the executable the last build left. + const kept = executableCache?.keep(output) ?? false; + const restored = kept || (executableCache?.restore(stagedOutput) ?? false); timing(restored ? "executable-cache-hit" : "executable-cache-miss"); if (!restored) { let programObjects = [object]; @@ -524,7 +526,10 @@ export class NativeCompiler { irPath = join(options.outDir, `${stem}.ir.json`); writeTextPartsSync(irPath, prepared.ir!); } - renameSync(stagedOutput, output); + if (!kept) { + renameSync(stagedOutput, output); + executableCache?.recordOutput(output); + } if (target.platform === "darwin" && (optimization !== "dev" || options.strip)) rmSync(output + ".dSYM", { recursive: true, force: true }); return { diff --git a/packages/compiler/src/native/executable-cache.test.ts b/packages/compiler/src/native/executable-cache.test.ts index 83a493721..97f9a3571 100644 --- a/packages/compiler/src/native/executable-cache.test.ts +++ b/packages/compiler/src/native/executable-cache.test.ts @@ -224,7 +224,7 @@ test("a failed or empty link trace cannot publish a completed executable", () => }); test.each(["ld", "crt", "libc"] as const)( - "a Linux key's second link records the linker, startup objects and libc; replacing the %s misses", + "a Linux key's first link records the linker, startup objects and libc; replacing the %s misses", (input) => { const f = fixture(); const lib = join(f.root, "lib"); @@ -257,26 +257,46 @@ test.each(["ld", "crt", "libc"] as const)( }; }); const open = () => new NativeExecutableCache(f.cache, f.key, "clang", false, [f.runtime], true); - // A key's first link is not traced; the caller links the output itself. - expect(open().trace(["-o", f.output], f.stage)).toBe(false); - expect(spawnSync).not.toHaveBeenCalled(); - expect(open().restore(f.destination)).toBe(false); - // Its next link traces both the driver and the linker in one run. + // A key's first link traces the driver and the linker in one run, and + // records the output it leaves instead of storing the executable. const entry = open(); expect(entry.trace(["-o", f.output], f.stage)).toBe(true); expect(spawnSync).toHaveBeenCalledTimes(1); expect(vi.mocked(spawnSync).mock.calls[0]![1]).toEqual(["-o", f.output, "-v", "-Wl,-t"]); entry.publish(f.output); + expect(f.cache.read("executable", f.key)).toBeNull(); + entry.recordOutput(f.output); + expect(open().keep(f.output)).toBe(true); const recorded = ( - JSON.parse(f.cache.read("executable", f.key)!.toString()) as { inputs: { path: string }[] } + JSON.parse(f.cache.read("kept", f.key)!.toString()) as { inputs: { path: string }[] } ).inputs.map((saved) => saved.path); expect(recorded).toEqual(expect.arrayContaining([...Object.values(paths), nonshared, lib])); expect(recorded).not.toContain(program); - expect(open().restore(f.destination)).toBe(true); const before = statSync(paths[input]); writeFileSync(paths[input] + ".new", "x".repeat(before.size)); utimesSync(paths[input] + ".new", before.atime, before.mtime); renameSync(paths[input] + ".new", paths[input]); - expect(open().restore(f.destination)).toBe(false); + expect(open().keep(f.output)).toBe(false); }, ); + +test("a Linux build whose output changed links again, and then stores the executable", () => { + const f = fixture(); + const open = () => new NativeExecutableCache(f.cache, f.key, "clang", false, [f.runtime], true); + const first = open(); + expect(first.trace(["-o", f.output], f.stage)).toBe(true); + first.publish(f.output); + first.recordOutput(f.output); + // The output is overwritten: it is not kept, and the next link publishes. + writeFileSync(f.output, Buffer.from([1, 2, 3, 4])); + expect(open().keep(f.output)).toBe(false); + const second = open(); + expect(second.restore(f.destination)).toBe(false); + expect(second.trace(["-o", f.output], f.stage)).toBe(true); + second.publish(f.output); + second.recordOutput(f.output); + expect(open().keep(f.output)).toBe(true); + // The stored executable restores at another path. + expect(open().restore(f.destination)).toBe(true); + expect(readFileSync(f.destination)).toEqual(readFileSync(f.output)); +}); diff --git a/packages/compiler/src/native/executable-cache.ts b/packages/compiler/src/native/executable-cache.ts index 1dfbf0b00..b9058e947 100644 --- a/packages/compiler/src/native/executable-cache.ts +++ b/packages/compiler/src/native/executable-cache.ts @@ -124,6 +124,41 @@ function tracePaths(output: string, driver: boolean, roots: string[]): string[] return [...paths].sort(); } +/** Linux: the output a build left, which an unchanged rebuild keeps while + * the output and every input keep their identities. */ +interface KeptEntry { + schema: "scriptc.native-kept.v1"; + output: InputIdentity; + inputs: InputIdentity[]; +} + +function validIdentity(input: InputIdentity): boolean { + return ( + input !== null && + typeof input === "object" && + typeof input.path === "string" && + isAbsolute(input.path) && + typeof input.canonical === "string" && + (input.kind === "file" || input.kind === "directory") && + [input.dev, input.ino, input.size, input.mtime, input.ctime].every( + (value) => typeof value === "number" && Number.isFinite(value), + ) + ); +} + +function validKept(value: unknown): value is KeptEntry { + if (value === null || typeof value !== "object") return false; + const entry = value as Partial; + return ( + entry.schema === "scriptc.native-kept.v1" && + entry.output !== undefined && + validIdentity(entry.output) && + Array.isArray(entry.inputs) && + entry.inputs.length > 0 && + entry.inputs.every(validIdentity) + ); +} + function validEntry(value: unknown): value is ExecutableEntry { if (value === null || typeof value !== "object") return false; const entry = value as Partial; @@ -135,18 +170,7 @@ function validEntry(value: unknown): value is ExecutableEntry { (typeof entry.symbols === "string" && /^[0-9a-f]{64}$/.test(entry.symbols))) && Array.isArray(entry.inputs) && entry.inputs.length > 0 && - entry.inputs.every( - (input) => - input !== null && - typeof input === "object" && - typeof input.path === "string" && - isAbsolute(input.path) && - typeof input.canonical === "string" && - (input.kind === "file" || input.kind === "directory") && - [input.dev, input.ino, input.size, input.mtime, input.ctime].every( - (value) => typeof value === "number" && Number.isFinite(value), - ), - ) + entry.inputs.every(validIdentity) ); } @@ -178,8 +202,8 @@ function stageSymbols(bytes: Buffer, binary: string): void { export class NativeExecutableCache { private inputs: InputIdentity[]; private traced = false; - /** Linux: no entry exists and the key was never linked before. */ - private readonly firstLink: boolean; + /** The inputs of the entry restore() used. */ + private restoredInputs: InputIdentity[] | null = null; constructor( private readonly cache: NativeCache, @@ -187,30 +211,46 @@ export class NativeExecutableCache { private readonly linker: string, private readonly debug: boolean, paths: string[], - /** Linux: trace with one verbose link, from a key's second link on. */ + /** Linux: trace with one verbose link, keep an unchanged output, and + * store the executable from a key's second link on. */ private readonly linux = false, ) { - this.firstLink = linux && !cache.has("executable", key) && !cache.has("linked", key); - // A first link neither restores nor traces, so it needs no identities. - this.inputs = this.firstLink ? [] : [...new Set(paths)].sort().map(identity); + this.inputs = [...new Set(paths)].sort().map(identity); + } + + /** Whether `recorded`, the inputs of an entry, still match and cover this + * build's inputs. */ + private covers(recorded: InputIdentity[]): boolean { + if (!stillMatches(recorded) || !stillMatches(this.inputs)) return false; + const saved = new Map(recorded.map((input) => [input.path, input])); + return this.inputs.every((input) => { + const found = saved.get(input.path); + return found !== undefined && sameIdentity(found, input); + }); + } + + /** Linux: true when `output` is the executable the last build of this key + * left there, unchanged, and its inputs are unchanged; the caller keeps it. */ + keep(output: string): boolean { + if (!this.linux) return false; + try { + const metadata = this.cache.read("kept", this.key); + if (metadata === null) return false; + const entry: unknown = JSON.parse(metadata.toString("utf8")); + if (!validKept(entry)) return false; + const current = identity(output); + return sameIdentity(current, entry.output) && this.covers(entry.inputs); + } catch { + return false; + } } restore(output: string): boolean { - if (this.firstLink) return false; try { const metadata = this.cache.read("executable", this.key); if (metadata === null) return false; const entry: unknown = JSON.parse(metadata.toString("utf8")); - if (!validEntry(entry) || !stillMatches(entry.inputs) || !stillMatches(this.inputs)) - return false; - const saved = new Map(entry.inputs.map((input) => [input.path, input])); - if ( - !this.inputs.every((input) => { - const recorded = saved.get(input.path); - return recorded !== undefined && sameIdentity(recorded, input); - }) - ) - return false; + if (!validEntry(entry) || !this.covers(entry.inputs)) return false; if (this.debug !== (entry.symbols !== null)) return false; const binary = this.cache.read("binary", entry.binary); const symbols = entry.symbols === null ? null : this.cache.read("dsym", entry.symbols); @@ -219,6 +259,7 @@ export class NativeExecutableCache { if (symbols !== null) stageSymbols(symbols, output); writeFileSync(output, binary); chmodSync(output, 0o755); + this.restoredInputs = entry.inputs; return true; } catch { return false; @@ -234,12 +275,6 @@ export class NativeExecutableCache { trace(args: string[], stage: string): boolean { this.traced = false; try { - // On Linux a key's first link only records that it was linked; a later - // link of the same key traces, so a build that runs once traces nothing. - if (this.firstLink) { - this.cache.mark("linked", this.key); - return false; - } const roots = [resolve(stage), realpathSync(stage)]; let driverInputs = this.linux ? [] @@ -250,7 +285,14 @@ export class NativeExecutableCache { const paths = tracePaths(linked, false, roots); if (paths.length === 0 || !stillMatches(this.inputs) || !stillMatches(driverInputs)) return false; - this.inputs.push(...driverInputs, ...paths.map(identity)); + // The driver's job line and the linker's trace name many of the same + // files; each is checked once. + const listed = new Set(this.inputs.map((input) => input.path)); + for (const input of [...driverInputs, ...paths.map(identity)]) + if (!listed.has(input.path)) { + listed.add(input.path); + this.inputs.push(input); + } this.traced = true; return true; } catch { @@ -260,7 +302,10 @@ export class NativeExecutableCache { publish(output: string): void { try { - if (!this.traced || !stillMatches(this.inputs)) return; + // On Linux the first build of a key only records its output (see + // recordOutput); the executable is stored once a later build relinks. + if (!this.traced || (this.linux && !this.cache.has("kept", this.key))) return; + if (!stillMatches(this.inputs)) return; const binary = readFileSync(output); const symbols = this.debug ? readSymbols(output) : null; const binaryKey = this.cache.writeContent("binary", binary); @@ -277,6 +322,24 @@ export class NativeExecutableCache { /* Build artifacts remain valid when caching is unavailable. */ } } + + /** Linux: records `output`, the executable this build left in place, for + * keep(). */ + recordOutput(output: string): void { + if (!this.linux) return; + try { + const inputs = this.traced ? this.inputs : this.restoredInputs; + if (inputs === null || !stillMatches(inputs)) return; + const entry: KeptEntry = { + schema: "scriptc.native-kept.v1", + output: identity(output), + inputs, + }; + this.cache.write("kept", this.key, JSON.stringify(entry)); + } catch { + /* Build artifacts remain valid when caching is unavailable. */ + } + } } export function openNativeExecutableCache( From 56b9158de21b5d25612c535f37b588ff1d17fcde Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 10:42:05 -0500 Subject: [PATCH 103/259] Keep integer index arithmetic in integers across nested counted loops --- .../src/backend/llvm/counted-loops.ts | 10 +- .../backend/llvm/dense-array-loops.test.ts | 1 + packages/compiler/src/backend/llvm/emitter.ts | 17 +- .../src/backend/llvm/wrapping-sums.ts | 50 ++++-- .../src/ir/expression-inlining.test.ts | 145 ++++++++++++++++ .../compiler/src/ir/expression-inlining.ts | 157 ++++++++++++++++++ .../compiler/src/ir/integer-loops.test.ts | 68 ++++++++ packages/compiler/src/ir/integer-loops.ts | 105 +++++++++++- .../corpus/8193-counted-loop-products.ts.json | 6 + tests/corpus/8193-counted-loop-products.ts | 59 +++++++ 10 files changed, 588 insertions(+), 30 deletions(-) create mode 100644 packages/compiler/src/ir/expression-inlining.test.ts create mode 100644 packages/compiler/src/ir/expression-inlining.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8193-counted-loop-products.ts.json create mode 100644 tests/corpus/8193-counted-loop-products.ts diff --git a/packages/compiler/src/backend/llvm/counted-loops.ts b/packages/compiler/src/backend/llvm/counted-loops.ts index 1ff4c6580..bb402d5b8 100644 --- a/packages/compiler/src/backend/llvm/counted-loops.ts +++ b/packages/compiler/src/backend/llvm/counted-loops.ts @@ -50,8 +50,8 @@ export function emitCountedLoopLimit( } /** The run-time test of a guarded counted loop: an unproven limit is within - * the integer form's finite range and an unproven start is an exact safe - * integer. Returns `true` when nothing needs testing. */ + * the integer form's finite range and an unproven start is an exact integer + * within the loop's start bound. Returns `true` when nothing needs testing. */ export function emitCountedLoopSafety( host: LlvmEmitterContext, loop: IntegerCountedForLoop, @@ -65,7 +65,11 @@ export function emitCountedLoopSafety( `${safe} = fcmp ${loop.step > 0 ? "ole" : "oge"} double ${bound.name}, ${f64Lit(loop.guardLimit)}`, ); } - if (loop.startGuarded) safe = andSafe(host, safe, emitExactStart(host, loop.start)); + if (loop.startGuarded) { + const start = host.emitExpr(loop.start); + const bound = loop.startBound; + safe = andSafe(host, safe, emitExactIntegerTest(host, start.name, -bound, bound).ok); + } for (const follower of loop.followers) { if (follower.startGuarded) safe = andSafe(host, safe, emitExactStart(host, follower.start)); if (follower.tripGuarded) safe = andSafe(host, safe, emitFollowerReach(host, loop, follower)); diff --git a/packages/compiler/src/backend/llvm/dense-array-loops.test.ts b/packages/compiler/src/backend/llvm/dense-array-loops.test.ts index a88c38575..9ec2d5d39 100644 --- a/packages/compiler/src/backend/llvm/dense-array-loops.test.ts +++ b/packages/compiler/src/backend/llvm/dense-array-loops.test.ts @@ -122,6 +122,7 @@ const counted = ( guarded: false, limitGuarded: false, startGuarded: false, + startBound: Number.MAX_SAFE_INTEGER, guardLimit: 0, followers: [], ...fields, diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 6729da197..27389e4ff 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -80,6 +80,7 @@ import { } from "./emit-journal.js"; import { specializeNumericCalls } from "../../ir/numeric-call-specialization.js"; import { versionLoopBoundParameters } from "../../ir/parameter-versions.js"; +import { inlineExpressionFunctions } from "../../ir/expression-inlining.js"; import { allocatedLiteral, fillAllocationLength, @@ -562,13 +563,15 @@ function moduleEmitter(input: IrModule, options: LlvmTargetOptions): LlEmitter { scalarizeNumericRecords( specializeCallbackCalls( specializeNumericCalls( - foldConstantGlobals( - copyStableCaptures( - resolveSelfCaptures( - hoistFinalFieldReads( - freezeInitOnlyGlobals( - holdCharLocalsAsUnits( - dropUnwrittenPropertyBags(runPairedWhileLoopsAsFor(mod)), + inlineExpressionFunctions( + foldConstantGlobals( + copyStableCaptures( + resolveSelfCaptures( + hoistFinalFieldReads( + freezeInitOnlyGlobals( + holdCharLocalsAsUnits( + dropUnwrittenPropertyBags(runPairedWhileLoopsAsFor(mod)), + ), ), ), ), diff --git a/packages/compiler/src/backend/llvm/wrapping-sums.ts b/packages/compiler/src/backend/llvm/wrapping-sums.ts index c736fcf72..e93d66909 100644 --- a/packages/compiler/src/backend/llvm/wrapping-sums.ts +++ b/packages/compiler/src/backend/llvm/wrapping-sums.ts @@ -4,13 +4,15 @@ import { integerArithmeticRange, type IntegerRange } from "../../ir/integer-rang import type { LlValue, LlvmEmitterContext } from "./expr-context.js"; import type { LlInteger } from "./integer-values.js"; -/** Marks the `+` and `-` operands whose number only reaches ToInt32/ToUint32 - * consumers (`| 0`, the other bitwise operators, `Math.imul`, `Math.clz32`), - * directly or through further sums, in the emitter's `wrappingSums`. Called - * by the consumer before its operands emit. */ +/** Marks the `+`, `-` and `*` operands whose number only reaches + * ToInt32/ToUint32 consumers (`| 0`, the other bitwise operators, + * `Math.imul`, `Math.clz32`), directly or through further sums and + * products, in the emitter's `wrappingSums`. Called by the consumer before + * its operands emit. */ export function markWrappingOperands(host: LlvmEmitterContext, ...operands: IrExpr[]): void { for (const operand of operands) { - if (operand.kind !== "bin" || (operand.op !== "+" && operand.op !== "-")) continue; + if (operand.kind !== "bin" || (operand.op !== "+" && operand.op !== "-" && operand.op !== "*")) + continue; if (operand.type.kind !== "f64" || host.wrappingSums.has(operand)) continue; host.wrappingSums.add(operand); markWrappingOperands(host, operand.left, operand.right); @@ -128,12 +130,15 @@ function wrappingOperand( return { low, valid }; } -/** ToUint32 of `left op right` (`+` or `-`) in 32-bit arithmetic when the - * expression only reaches ToInt32/ToUint32 consumers and both operands are - * exact integers or NaN with an exact result. Both conversions are - * arithmetic mod 2^32, so the wrapping i32 sum of the operands' low halves - * is the converted exact sum; a NaN operand makes the sum NaN, which - * converts to 0. Returns undefined, emitting nothing, for any other sum. */ +/** ToUint32 of `left op right` (`+`, `-` or `*`) in 32-bit arithmetic when + * the expression only reaches ToInt32/ToUint32 consumers and both operands + * are exact integers or NaN with an exact result. Both conversions are + * arithmetic mod 2^32, so the wrapping i32 sum or product of the operands' + * low halves is the converted exact result; a NaN operand makes the result + * NaN, which converts to 0. A product is exact when the operands' magnitude + * bounds multiply to at most 2^53; it may be -0 (`0 * -1`), which converts + * to 0 like the integer 0. Returns undefined, emitting nothing, for any + * other expression. */ export function emitWrappingSum( host: LlvmEmitterContext, e: IrExpr & { kind: "bin" }, @@ -142,15 +147,23 @@ export function emitWrappingSum( li: LlInteger | null, ri: LlInteger | null, ): string | undefined { - if ((e.op !== "+" && e.op !== "-") || !host.wrappingSums.has(e)) return undefined; + if ((e.op !== "+" && e.op !== "-" && e.op !== "*") || !host.wrappingSums.has(e)) return undefined; const leftRange = li ? li.range : integerOrNaNRange(host, e.left); const rightRange = leftRange && (ri ? ri.range : integerOrNaNRange(host, e.right)); - if (!rightRange || !integerArithmeticRange(e.op, leftRange!, rightRange)) return undefined; + if (!rightRange) return undefined; + if ( + e.op === "*" + ? !exactProduct(leftRange!, rightRange) + : !integerArithmeticRange(e.op, leftRange!, rightRange) + ) + return undefined; const B = host.B; const left = wrappingOperand(host, l, li, leftRange!); const right = wrappingOperand(host, r, ri, rightRange); const sum = B.tmp(); - B.line(`${sum} = ${e.op === "+" ? "add" : "sub"} i32 ${left.low}, ${right.low}`); + B.line( + `${sum} = ${e.op === "+" ? "add" : e.op === "-" ? "sub" : "mul"} i32 ${left.low}, ${right.low}`, + ); let valid = left.valid ?? right.valid; if (valid === null) return sum; if (left.valid && right.valid) { @@ -162,6 +175,15 @@ export function emitWrappingSum( return out; } +/** Whether every product of a value in `left` and one in `right` is an + * integer of magnitude at most 2^53, which the double product holds + * exactly. */ +function exactProduct(left: IntegerRange, right: IntegerRange): boolean { + const magnitude = (range: IntegerRange): number => + Math.max(Math.abs(range.min), Math.abs(range.max)); + return magnitude(left) * magnitude(right) <= 2 ** 53; +} + /** The number locals of `fn` that only hold exact integers (never -0) or NaN, with the range of * those integers: locals declared once with an initializer, neither parameters nor captured or * boxed, whose initializer and every later write `integerOrNaNRange` covers. A local joins once diff --git a/packages/compiler/src/ir/expression-inlining.test.ts b/packages/compiler/src/ir/expression-inlining.test.ts new file mode 100644 index 000000000..ae68c44ea --- /dev/null +++ b/packages/compiler/src/ir/expression-inlining.test.ts @@ -0,0 +1,145 @@ +import { expect, test } from "vitest"; +import { inlineExpressionFunctions } from "./expression-inlining.js"; +import { BOOL, F64, VOID, type IrExpr, type IrFunction, type IrModule, type IrStmt } from "./ir.js"; + +const loc = { file: "expression-inlining.ts", start: 0, end: 0 }; +const num = (value: number): IrExpr => ({ loc, kind: "numLit", value, type: F64 }); +const ref = (localId: string): IrExpr => ({ loc, kind: "varRef", localId, type: F64 }); +const bin = (op: "+" | "*" | ">>>", left: IrExpr, right: IrExpr): IrExpr => ({ + loc, + kind: "bin", + op, + left, + right, + type: F64, +}); +const call = (callee: string, args: IrExpr[]): IrExpr => ({ + loc, + kind: "call", + callee, + args, + type: F64, +}); +const local = (id: string, extra: object = {}) => ({ + id, + name: id, + type: F64, + mutable: true, + ...extra, +}); + +// a(i, j) = ((i + j) * (i + j + 1)) >>> 1 +const a: IrFunction = { + loc, + name: "a", + params: [ + { localId: "i", name: "i", type: F64 }, + { localId: "j", name: "j", type: F64 }, + ], + locals: [local("i"), local("j")], + returnType: F64, + body: [ + { + loc, + kind: "return", + value: bin( + ">>>", + bin("*", bin("+", ref("i"), ref("j")), bin("+", bin("+", ref("i"), ref("j")), num(1))), + num(1), + ), + }, + ], +}; + +/** `caller` running `body` in a loop. */ +function caller(body: IrStmt[], extra: object = {}): IrFunction { + return { + loc, + name: "caller", + params: [], + locals: [local("x", extra), local("y"), local("out")], + returnType: VOID, + body: [{ loc, kind: "while", cond: { loc, kind: "boolLit", value: true, type: BOOL }, body }], + }; +} + +const loopBody = (fn: IrFunction): IrStmt[] => (fn.body[0] as IrStmt & { kind: "while" }).body; + +const mod = (fn: IrFunction): IrModule => ({ + irVersion: 17, + sourceFile: "expression-inlining.ts", + entry: "caller", + functions: [a, fn], +}); + +test("calls passing literals and locals take the callee's expression over them", () => { + const result = inlineExpressionFunctions( + mod(caller([{ loc, kind: "assign", localId: "out", value: call("a", [ref("x"), num(3)]) }])), + ); + const assign = loopBody(result.functions[1]!)[0] as IrStmt & { kind: "assign" }; + expect(assign.value).toMatchObject({ + kind: "bin", + op: ">>>", + left: { + kind: "bin", + op: "*", + left: { + kind: "bin", + op: "+", + left: { kind: "varRef", localId: "x" }, + right: { kind: "numLit", value: 3 }, + }, + }, + }); + // Every substituted read is a fresh node. + const left = (assign.value as IrExpr & { kind: "bin" }).left as IrExpr & { kind: "bin" }; + const factors = [left.left, (left.right as IrExpr & { kind: "bin" }).left] as (IrExpr & { + kind: "bin"; + })[]; + expect(factors[0]!.left).not.toBe(factors[1]!.left); + expect(result.functions[0]).toBe(a); +}); + +test("calls with other arguments, boxed locals or callees with other bodies keep their call", () => { + const nested = call("a", [call("a", [ref("x"), ref("y")]), num(1)]); + const kept = inlineExpressionFunctions( + mod(caller([{ loc, kind: "assign", localId: "out", value: nested }])), + ); + const outer = (loopBody(kept.functions[1]!)[0] as IrStmt & { kind: "assign" }).value; + // The inner call inlines; the outer one passes a computed argument. + expect(outer).toMatchObject({ + kind: "call", + callee: "a", + args: [{ kind: "bin", op: ">>>" }, { kind: "numLit" }], + }); + const boxed = caller( + [{ loc, kind: "assign", localId: "out", value: call("a", [ref("x"), ref("y")]) }], + { + boxed: true, + }, + ); + expect(inlineExpressionFunctions(mod(boxed)).functions[1]).toBe(boxed); + const twoStatements: IrFunction = { + ...a, + body: [{ loc, kind: "exprStmt", expr: ref("i") }, ...a.body], + }; + const unchanged: IrModule = { + ...mod( + caller([{ loc, kind: "assign", localId: "out", value: call("a", [ref("x"), ref("y")]) }]), + ), + functions: [ + twoStatements, + caller([{ loc, kind: "assign", localId: "out", value: call("a", [ref("x"), ref("y")]) }]), + ], + }; + expect(inlineExpressionFunctions(unchanged)).toBe(unchanged); +}); + +test("calls outside loops keep their call", () => { + const outside: IrFunction = { + ...caller([]), + body: [{ loc, kind: "assign", localId: "out", value: call("a", [ref("x"), num(3)]) }], + }; + const m = mod(outside); + expect(inlineExpressionFunctions(m)).toBe(m); +}); diff --git a/packages/compiler/src/ir/expression-inlining.ts b/packages/compiler/src/ir/expression-inlining.ts new file mode 100644 index 000000000..377cfaf3f --- /dev/null +++ b/packages/compiler/src/ir/expression-inlining.ts @@ -0,0 +1,157 @@ +import type { IrExpr, IrFunction, IrModule, IrStmt } from "./ir.js"; +import { everyExprChild, everyStmtChild, mapExprChildren, transformStmtList } from "./traverse.js"; + +/** Callee bodies above this many nodes keep their call. */ +const MAX_EXPRESSION_NODES = 32; + +/** Number operators that run no other code and cannot throw. */ +const PURE_BINARY = new Set([ + "+", + "-", + "*", + "/", + "%", + "**", + "&", + "|", + "^", + "<<", + ">>", + ">>>", +]); + +/** The returned expression of a function whose body is `return ` over + * its number parameters: literals, parameter reads, and the number + * operators of PURE_BINARY, unary `-` and `~`. Null for any other function. */ +function inlinableExpression(fn: IrFunction): IrExpr | null { + if (fn.async || fn.generator || fn.captures !== undefined || fn.classCaptures?.length) + return null; + if (fn.tier === "dynamic" || fn.returnType.kind !== "f64") return null; + if (fn.body.length !== 1) return null; + const only = fn.body[0]!; + if (only.kind !== "return" || only.value === null) return null; + const params = new Set(); + for (const param of fn.params) { + if (param.type.kind !== "f64") return null; + params.add(param.localId); + } + const locals = new Map(fn.locals.map((local) => [local.id, local])); + for (const id of params) { + const local = locals.get(id); + if (local === undefined || local.boxed || local.tdz) return null; + } + let nodes = 0; + const pure = (e: IrExpr): boolean => { + if (++nodes > MAX_EXPRESSION_NODES || e.type.kind !== "f64") return false; + switch (e.kind) { + case "numLit": + return true; + case "varRef": + return params.has(e.localId); + case "bin": + return PURE_BINARY.has(e.op) && pure(e.left) && pure(e.right); + case "unary": + return (e.op === "-" || e.op === "~") && pure(e.operand); + default: + return false; + } + }; + return pure(only.value) ? only.value : null; +} + +/** A call argument that reads the same value wherever the inlined body + * reads it: a number literal or a read of one of the caller's own unboxed + * locals outside the temporal dead zone. The body writes nothing, so every + * read sees the value the call would have passed. */ +function duplicableArgument(e: IrExpr, caller: ReadonlyMap) { + if (e.type.kind !== "f64") return false; + // A literal whose source spelling does not round-trip keeps its call. + if (e.kind === "numLit") return e.spelling === undefined; + if (e.kind !== "varRef") return false; + const local = caller.get(e.localId); + return local !== undefined && !local.boxed && !local.tdz; +} + +/** A fresh copy of `e`: facts downstream are keyed by node identity. */ +function copy(e: IrExpr, substitute: (ref: IrExpr & { kind: "varRef" }) => IrExpr): IrExpr { + if (e.kind === "varRef") return substitute(e); + return mapExprChildren( + { ...e }, + (child) => copy(child, substitute), + (stmt) => stmt, + ); +} + +/** The direct calls of `body` that run inside a loop body or condition. */ +function callsInLoops(body: IrStmt[]): Set { + const found = new Set(); + let depth = 0; + const expr = (e: IrExpr): boolean => { + if (depth > 0 && e.kind === "call") found.add(e); + return everyExprChild(e, expr, stmt); + }; + const stmt = (s: IrStmt): boolean => { + const loop = + s.kind === "for" || s.kind === "while" || s.kind === "doWhile" || s.kind === "forOf"; + if (loop) depth++; + everyStmtChild(s, expr, stmt); + if (loop) depth--; + return true; + }; + body.forEach(stmt); + return found; +} + +/** Inlines functions whose body is one number expression over their + * parameters (`function a(i, j) { return (((i + j) * (i + j + 1)) >>> 1) + + * i + 1; }`) at direct call sites that pass literals or reads of the + * caller's locals. + * + * The callee runs no other code, allocates nothing and cannot throw, so + * the call's only effect is its result. Its arguments are reads that + * nothing between them and the callee's reads can change, so substituting + * them gives the same value. The caller's loop and integer analyses then + * see the arithmetic on its own counters (`a(i, j)` inside a counted loop + * over `i` and `j`). Only calls inside loops are inlined: elsewhere the + * integer analyses gain nothing. The function itself stays for its other + * uses. */ +export function inlineExpressionFunctions(mod: IrModule): IrModule { + const members = new Set((mod.classes ?? []).flatMap((cls) => cls.methods ?? [])); + const expressions = new Map(); + for (const fn of mod.functions) { + if (fn.name === mod.entry || members.has(fn.name)) continue; + const value = inlinableExpression(fn); + if (value !== null) expressions.set(fn.name, { fn, value }); + } + if (expressions.size === 0) return mod; + let changed = false; + const functions = mod.functions.map((fn) => { + const locals = new Map(fn.locals.map((local) => [local.id, local])); + const inLoops = callsInLoops(fn.body); + if (inLoops.size === 0) return fn; + let inlined = false; + const body = transformStmtList(fn.body, { + stmt: (s) => s, + expr: (e) => { + if (e.kind !== "call" || e.callee === fn.name || !inLoops.has(e)) return e; + const target = expressions.get(e.callee); + if (target === undefined || target.fn.params.length !== e.args.length) return e; + if (!e.args.every((arg) => duplicableArgument(arg, locals))) return e; + const args = new Map(target.fn.params.map((param, i) => [param.localId, e.args[i]!])); + inlined = true; + return copy(target.value, (ref) => { + const arg = args.get(ref.localId); + if (arg?.kind === "numLit") + return { kind: "numLit", value: arg.value, type: arg.type, loc: ref.loc }; + if (arg?.kind === "varRef") + return { kind: "varRef", localId: arg.localId, type: arg.type, loc: ref.loc }; + return ref; + }); + }, + }); + if (!inlined) return fn; + changed = true; + return { ...fn, body }; + }); + return changed ? { ...mod, functions } : mod; +} diff --git a/packages/compiler/src/ir/integer-loops.test.ts b/packages/compiler/src/ir/integer-loops.test.ts index 2cca43a00..48be67fbf 100644 --- a/packages/compiler/src/ir/integer-loops.test.ts +++ b/packages/compiler/src/ir/integer-loops.test.ts @@ -552,3 +552,71 @@ test("counters stepped beside the tested one run as integers", () => { { startGuarded: true, tripGuarded: true }, ]); }); + +/** `counted(limit)` with the body `x = ((i + k) * (i + k + 1)) >>> 1` + * inside a nested `for (let j = 0; j < 4; j++)` loop. */ +function productLoop(limit: IrExpr, start: IrExpr = number(0)): IrStmt & { kind: "for" } { + const s = counted(limit); + if (s.init?.kind === "varDecl") s.init.init = start; + const sum = (extra: number): IrExpr => { + const base: IrExpr = { kind: "bin", op: "+", left: ref("i"), right: ref("k"), type: F64, loc }; + return extra === 0 + ? base + : { kind: "bin", op: "+", left: base, right: number(extra), type: F64, loc }; + }; + const product: IrExpr = { kind: "bin", op: "*", left: sum(0), right: sum(1), type: F64, loc }; + const inner = counted(number(4)); + if (inner.init?.kind === "varDecl") inner.init.localId = "j"; + if (inner.cond?.kind === "bin") inner.cond.left = ref("j"); + if (inner.update?.kind === "assign") { + inner.update.localId = "j"; + if (inner.update.value.kind === "bin") inner.update.value.left = ref("j"); + } + inner.body = [ + { + kind: "assign", + localId: "x", + value: { kind: "bin", op: ">>>", left: product, right: number(1), type: F64, loc }, + loc, + }, + ]; + s.body = [inner]; + return s; +} + +test("guarded counted loops whose products the counter bound proves exact may hold nested loops", () => { + const scope = new Map(locals); + for (const id of ["limit", "start", "k", "x", "j"]) + scope.set(id, { id, name: id, type: F64, mutable: true }); + const tight = matchIntegerCountedForLoop(productLoop(ref("limit"), ref("start")), scope); + expect(tight).toMatchObject({ + guarded: true, + limitGuarded: true, + startGuarded: true, + startBound: 2 ** 25, + guardLimit: 2 ** 25, + range: { min: -(2 ** 25), max: 2 ** 25 - 1 }, + }); + // A literal trip count past the bound keeps the safe-integer bound, and + // a guarded loop under that bound holds no nested loop. + expect(matchIntegerCountedForLoop(productLoop(number(1e9), ref("start")), scope)).toBeNull(); + const plain = counted(ref("limit")); + plain.body = [productLoop(number(4)).body[0]!]; + const inner = plain.body[0] as IrStmt & { kind: "for" }; + inner.body = [ + { + kind: "assign", + localId: "x", + value: { kind: "bin", op: "|", left: ref("i"), right: number(0), type: F64, loc }, + loc, + }, + ]; + expect(matchIntegerCountedForLoop(plain, scope)).toBeNull(); + // Without a nested loop the product bound still applies to the limit. + const flat = productLoop(ref("limit"), ref("start")); + flat.body = (flat.body[0] as IrStmt & { kind: "for" }).body; + expect(matchIntegerCountedForLoop(flat, scope)).toMatchObject({ + startBound: 2 ** 25, + guardLimit: 2 ** 25, + }); +}); diff --git a/packages/compiler/src/ir/integer-loops.ts b/packages/compiler/src/ir/integer-loops.ts index 2f7d2bea6..7cc49b7a0 100644 --- a/packages/compiler/src/ir/integer-loops.ts +++ b/packages/compiler/src/ir/integer-loops.ts @@ -24,8 +24,12 @@ export interface IntegerCountedForLoop { /** The limit needs the run-time `guardLimit` test (part of `guarded`). */ limitGuarded: boolean; /** The start has no proven integer range: the versioned loop also tests - * that it is an exact integer (not -0) of at most 2^53 in magnitude. */ + * that it is an exact integer (not -0) of at most `startBound` in + * magnitude. */ startGuarded: boolean; + /** The magnitude the guarded start is tested against: 2^53 - 1, or + * PRODUCT_COUNTER_BOUND when the body multiplies sums of the counter. */ + startBound: number; guardLimit: number; range: IntegerRange; /** Counters declared and stepped beside this one that the condition does @@ -50,6 +54,64 @@ export interface IntegerLoopFollower { range: IntegerRange; } +/** The counter magnitude below which a product of two sums of counters and + * small literals stays exact in a double: `(i + j) * (i + j + 1)` with both + * counters within 2^25 is below 2^52. A guarded loop whose body multiplies + * such sums for a bitwise operator tests its counter against this bound, so + * the product's integer form is proven exact. */ +export const PRODUCT_COUNTER_BOUND = 2 ** 25; + +/** Whether `e` is a sum or difference of locals and safe integer literals + * of magnitude at most 2^20, and whether it reads `counter`. */ +function localSum(e: IrExpr, counter: string): { sum: boolean; reads: boolean } { + let reads = false; + const sum = (x: IrExpr): boolean => { + if (x.kind === "varRef") { + if (x.localId === counter) reads = true; + return true; + } + if (x.kind === "numLit") return Number.isSafeInteger(x.value) && Math.abs(x.value) <= 2 ** 20; + return x.kind === "bin" && (x.op === "+" || x.op === "-") && sum(x.left) && sum(x.right); + }; + return { sum: sum(e), reads }; +} + +/** Whether a bitwise operand `e` multiplies two sums of locals and + * literals, one of which reads `counter` (`((i + j) * (i + j + 1)) >>> 1`). */ +function multipliesCounterSums(e: IrExpr, counter: string): boolean { + if (e.kind !== "bin") return false; + if (e.op === "*") { + const left = localSum(e.left, counter), + right = localSum(e.right, counter); + return left.sum && right.sum && (left.reads || right.reads); + } + return ( + (e.op === "+" || e.op === "-") && + (multipliesCounterSums(e.left, counter) || multipliesCounterSums(e.right, counter)) + ); +} + +const BITWISE = new Set(["&", "|", "^", "<<", ">>", ">>>"]); + +/** Whether `body`, nested loops included, takes a bitwise operator of a + * product that multipliesCounterSums matches. */ +function bodyMultipliesCounter(body: IrStmt[], counter: string): boolean { + let found = false; + everyStmtList(body, { + stmt: () => !found, + expr: (e) => { + if ( + e.kind === "bin" && + BITWISE.has(e.op) && + (multipliesCounterSums(e.left, counter) || multipliesCounterSums(e.right, counter)) + ) + found = true; + return !found; + }, + }); + return found; +} + /** The bound of the run-time follower test. */ export const FOLLOWER_GUARD_LIMIT = 2 ** 52; /** The magnitude a follower that passed the test can reach. The test's four @@ -171,6 +233,23 @@ export function matchIntegerCountedForLoop( // The condition tests the driving counter; every other declaration // follows it. const driver = declared(cond.left) ?? declared(cond.right); + // A body that multiplies sums of the driver tests it against the bound + // under which those products are exact. A limit proven past that bound + // (a literal trip count) keeps the safe-integer bound instead. + const limitSide = driver !== null && declared(cond.left) === driver ? cond.right : cond.left; + const knownLimit = + limitSide.kind === "numLit" + ? { min: limitSide.value, max: limitSide.value } + : ranges.get(limitSide); + const driverBound = + driver !== null && + !( + knownLimit && + Math.max(Math.abs(knownLimit.min), Math.abs(knownLimit.max)) > PRODUCT_COUNTER_BOUND + ) && + bodyMultipliesCounter(stmt.body, driver) + ? PRODUCT_COUNTER_BOUND + : Number.MAX_SAFE_INTEGER; const counterIds = decls.map((d) => (d.kind === "varDecl" ? d.localId : "")); const stepOf = (id: string): number | null => { const steps = updates.map((u) => constantStep(u, id)).filter((v) => v !== null); @@ -191,7 +270,8 @@ export function matchIntegerCountedForLoop( ? { min: start.value, max: start.value } : ranges.get(start); const guarded = !known && start.kind !== "numLit" && start.type.kind === "f64"; - const range = guarded ? { min: -Number.MAX_SAFE_INTEGER, max: Number.MAX_SAFE_INTEGER } : known; + const bound = id === driver ? driverBound : Number.MAX_SAFE_INTEGER; + const range = guarded ? { min: -bound, max: bound } : known; const step = stepOf(id); if ( !range || @@ -248,7 +328,9 @@ export function matchIntegerCountedForLoop( ); if (!stableLoopValue(limit, locals, stmt.body, true, local.id, stableLength)) return null; const inclusive = op === "<=" || op === ">="; - const guardLimit = step > 0 ? 2 ** 53 - (inclusive ? 1 : 0) : -(2 ** 53) + (inclusive ? 1 : 0); + const limitBound = driverBound === Number.MAX_SAFE_INTEGER ? 2 ** 53 : driverBound; + const guardLimit = + step > 0 ? limitBound - (inclusive ? 1 : 0) : -limitBound + (inclusive ? 1 : 0); const boundRange = limit.kind === "numLit" ? { min: limit.value, max: limit.value } : ranges.get(limit); const limitGuarded = @@ -264,7 +346,9 @@ export function matchIntegerCountedForLoop( Number.MAX_SAFE_INTEGER, boundRange ? Math.ceil(boundRange.max) - (inclusive ? 0 : 1) - : Number.MAX_SAFE_INTEGER, + : limitGuarded + ? Math.ceil(guardLimit) - (inclusive ? 0 : 1) + : Number.MAX_SAFE_INTEGER, ), ), } @@ -275,7 +359,9 @@ export function matchIntegerCountedForLoop( -Number.MAX_SAFE_INTEGER, boundRange ? Math.floor(boundRange.min) + (inclusive ? 0 : 1) - : -Number.MAX_SAFE_INTEGER, + : limitGuarded + ? Math.floor(guardLimit) + (inclusive ? 0 : 1) + : -Number.MAX_SAFE_INTEGER, ), ), max: startRange.max, @@ -366,9 +452,15 @@ export function matchIntegerCountedForLoop( const bodyStmt = (s: IrStmt): boolean => { if (s.kind === "bytesSet" && counter(s.index)) useful = true; if (!guarded && s.kind === "arraySet" && counter(s.index)) useful = true; + // A guarded loop's copy duplicates nested loops too, so only a body + // whose counter products the bound proves exact may hold a nested + // `for` loop; the node budget counts its body. if ( guarded && - (s.kind === "for" || s.kind === "forOf" || s.kind === "while" || s.kind === "doWhile") + (s.kind === "forOf" || + s.kind === "while" || + s.kind === "doWhile" || + (s.kind === "for" && driverBound === Number.MAX_SAFE_INTEGER)) ) return false; return (!guarded || ++cost <= 80) && everyStmtChild(s, expr, bodyStmt); @@ -383,6 +475,7 @@ export function matchIntegerCountedForLoop( guarded, limitGuarded, startGuarded, + startBound: driverBound, guardLimit, range, followers, diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8193-counted-loop-products.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8193-counted-loop-products.ts.json new file mode 100644 index 000000000..7a3b97b6c --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8193-counted-loop-products.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8193-counted-loop-products.ts" + ], + "diags": [] +} diff --git a/tests/corpus/8193-counted-loop-products.ts b/tests/corpus/8193-counted-loop-products.ts new file mode 100644 index 000000000..d347aee76 --- /dev/null +++ b/tests/corpus/8193-counted-loop-products.ts @@ -0,0 +1,59 @@ +// Nested counted loops whose bounds arrive at run time, with the counters' +// products reaching bitwise operators. Starts and limits take the integer +// copy or the double copy: negative, fractional, NaN, -0, and starts or +// limits past 2^25, past which the guarded copy no longer proves products +// exact. +function a(i: number, j: number): number { + return (((i + j) * (i + j + 1)) >>> 1) + i + 1; +} + +function rows(start: number, end: number, n: number): number[] { + const out: number[] = []; + for (let i = start; i < end; i++) { + let t = 0; + for (let j = 0; j < n; j++) t += 1 / a(i, j); + out.push(t); + } + return out; +} + +function mixed(start: number, end: number, n: number): number { + let h = 0; + for (let i = start; i < end; i++) { + for (let j = start; j < n; j++) h = (h + ((i - j) * (j - i + 3) | 0)) | 0; + } + return h; +} + +function wide(start: number, count: number): number[] { + const out: number[] = []; + for (let i = start; i < start + count; i++) out.push(((i * (i + 1)) >>> 0) ^ (i * i) | 0); + return out; +} + +const args = process.argv.slice(2).map(Number); +const big = 2 ** 25; +for (const [start, end, n] of [ + [0, 4, 6], + [-3, 2, 5], + [1.5, 4, 3], + [-0, 2, 2], + [NaN, 2, 2], + [big - 2, big + 2, 3], + [0, 3, args.length > 0 ? big + 1 : 4], +]) { + console.log(start, end, n, rows(start!, end!, Math.min(n!, 8)).map((x) => x.toFixed(12)).join(" ")); + console.log("mixed", mixed(start!, end!, Math.min(n!, 8))); +} +for (const start of [0, -5, 2 ** 26, 2 ** 31 - 2, 2 ** 52, -(2 ** 40), 0.5]) console.log(start, wide(start, 4).join(" ")); +console.log(Object.is(((-0 * 5) >>> 0), 0), a(-1, 0), a(0, -1), a(2 ** 30, 2 ** 30)); + +// Single-expression functions inlined at calls that pass literals and +// locals, also read as values and called with other arguments. +function mix(x: number, y: number): number { + return ((x * 31 + y) ^ (y << 3)) % 1000; +} +const table = [mix, (x: number, y: number) => x - y]; +let acc = 0; +for (let k = 0; k < 5; k++) acc += mix(k, 7) + mix(3, k) + table[k % 2]!(k, 2) + mix(k * 2, args.length); +console.log(acc, mix(2 ** 40, -0), mix(NaN, 1), mix(Infinity, 2), [1, 2, 3].map((v) => mix(v, v)).join()); From 2967a1b8c064094958b6b1b8fc23af76f5141bf6 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 11:03:34 -0500 Subject: [PATCH 104/259] Propagate exceptions by unwinding from directly called functions on Linux MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Emitted functions report an exception by returning with the thread's pending flag set, and every caller tests the flag after each call that may throw. On Linux executables (glibc and musl), functions reached only by direct calls now propagate exceptions by unwinding the native stack instead: - unwindAbiFunctions selects the may-throw functions that are not async or generators, constructors, virtually called or overridden methods, closure targets, the entry, library exports, module initializers or callees of coroutine bodies. - A native unwind costs about 2 µs a raise and 0.1 µs a frame, so functions that exceptions are likely to cross keep the flag: those with a `throw` of their own, those up to three calls above one, and recursive functions, counting calls through methods, closures and callbacks. - Their propagating exits call scr_unwind_raise (scr_unwind.c), a forced unwind through _Unwind_ForcedUnwind with the exception still in the active cell. - Direct calls to them are `invoke`s without a pending check. The landing pad runs the frame's usual unwind path: it releases the frame's values and then enters the enclosing try handler or resumes the unwind. - Remaining plain calls to them (wrappers, adapters, runtime-facing entry points) become invokes whose landing pad continues on the pending flag, or resumes when the wrapper is itself invoked. Every other call is marked `nounwind`, so inlining a raising function at an invoke keeps its calls plain. - When emitted text breaks these rules (a raising function's address is taken, or an invoked function returns with the flag pending), the module is emitted again with those functions on the pending flag. Emitted code does not declare scr_unwind_raise `noreturn`, so sanitized builds do not run the sanitizer's no-return hook, which needs stack bounds that fiber stacks do not report. Instead, scr_unwind_raise clears the shadow of the frames it unwinds. Executables link a static unwinder: libgcc_eh with the host toolchain and the glibc runtime packs, and Zig's libunwind with Zig and the musl packs. macOS, Windows, Android, WASI, libraries and debug builds keep the pending flag everywhere and emit the same code as before. The throw-chains runtime workload measures exceptions caught 2, 5 and 20 recursive calls above the throw, through direct calls and a callback, and a parser that backtracks by throwing. --- benchmarks/runtime/README.md | 1 + .../runtime/workloads/throw-chains.json | 6 + benchmarks/runtime/workloads/throw-chains.ts | 196 +++++++ packages/compiler/src/backend/llvm/blocks.ts | 14 +- .../src/backend/llvm/emit-function.ts | 10 +- packages/compiler/src/backend/llvm/emitter.ts | 135 ++++- .../compiler/src/backend/llvm/expr-calls.ts | 31 +- .../src/backend/llvm/unwind-abi.test.ts | 285 ++++++++++ .../compiler/src/backend/llvm/unwind-abi.ts | 491 ++++++++++++++++++ .../compiler/src/backend/native/executable.ts | 12 + .../src/backend/native/runtime-inputs.ts | 1 + packages/compiler/src/index.ts | 1 + packages/compiler/src/native/prepare.ts | 1 + .../runtime-linux-arm64-gnu/scripts/build.mjs | 6 +- .../scripts/build.mjs | 6 +- .../runtime-linux-x64-gnu/scripts/build.mjs | 6 +- .../runtime-linux-x64-musl/scripts/build.mjs | 6 +- .../runtime-pack-matrix.mjs | 1 + packages/runtime/src/scr_exception.h | 5 + packages/runtime/src/scr_unwind.c | 76 +++ scripts/zero-cost-compare.mjs | 5 +- 21 files changed, 1269 insertions(+), 26 deletions(-) create mode 100644 benchmarks/runtime/workloads/throw-chains.json create mode 100644 benchmarks/runtime/workloads/throw-chains.ts create mode 100644 packages/compiler/src/backend/llvm/unwind-abi.test.ts create mode 100644 packages/compiler/src/backend/llvm/unwind-abi.ts create mode 100644 packages/runtime/src/scr_unwind.c diff --git a/benchmarks/runtime/README.md b/benchmarks/runtime/README.md index 03238871d..726a9951b 100644 --- a/benchmarks/runtime/README.md +++ b/benchmarks/runtime/README.md @@ -30,6 +30,7 @@ Application-shaped workloads for measuring the speed of compiled executables. Ea | `regex-logs` | cpu | regex `exec` with groups, `test`, global `replace` | | `region-builds` | cpu | a watch-mode build loop over `LifetimeRegion`: each build binds a program in a new region and releases the previous one, which a cache keeps referenced for two builds | | `template-render` | cpu | template literals, escaping, `map`/`join` | +| `throw-chains` | cpu | exceptions caught 2, 5 and 20 recursive calls above the throw, through direct calls and through a callback, and a backtracking parser that throws on a failed alternative | | `thread-slots`, `thread-slots-cache` | cpu | worker threads reading one published type graph from an `InternTable` and keeping per-thread state for each type they visit: a `ThreadSlots` family, or a direct-mapped cache by id in front of a `Map` by id (the `-cache` entry); under Node.js both are per thread | | `typed-array-kernels` | cpu | element-wise loops that run to one typed array's length and index others at the same position: `Float64Array` axpy, `Float32Array` blend, `Uint8Array` mask, wrapping `Int32Array` add, `Uint8ClampedArray` brighten, RGBA to gray, a row-major `Float32Array` matrix-vector product, and `reduce`/`some`/`map` callbacks | | `typed-array-scan`, `typed-array-scan-workers` | cpu | element-by-element scan loops over `Uint8Array`, `Uint16Array`, `Int32Array` and `Float64Array`; the second entry is a worker-enabled executable (it can start a worker), so each access also checks for shared storage | diff --git a/benchmarks/runtime/workloads/throw-chains.json b/benchmarks/runtime/workloads/throw-chains.json new file mode 100644 index 000000000..79cf5ea87 --- /dev/null +++ b/benchmarks/runtime/workloads/throw-chains.json @@ -0,0 +1,6 @@ +{ + "entry": "workloads/throw-chains.ts", + "args": [ + "1" + ] +} diff --git a/benchmarks/runtime/workloads/throw-chains.ts b/benchmarks/runtime/workloads/throw-chains.ts new file mode 100644 index 000000000..c96816aed --- /dev/null +++ b/benchmarks/runtime/workloads/throw-chains.ts @@ -0,0 +1,196 @@ +// Exceptions that cross many frames: throws from helpers below a recursion, +// caught 2, 5 and 20 recursive calls up (direct calls, then calls through a +// callback), with each frame holding an array across its call, and a +// backtracking parser that uses exceptions for control flow. +class ParseError extends Error { + readonly at: number; + constructor(at: number, message: string) { + super(message); + this.at = at; + } +} + +/** A thrown value that is not an Error (no stack to capture). */ +class Stop { + readonly code: number; + constructor(code: number) { + this.code = code; + } +} + +const held: number[][] = []; +function fail(n: number, plain: boolean): number { + if (plain) throw new Stop(n); + throw new RangeError("chain " + n); +} +function check(n: number, plain: boolean): number { + return (n & 3) === 0 ? fail(n, plain) : n; +} +function validate(n: number, plain: boolean): number { + return check(n, plain) + (n & 1); +} +function bottom(n: number, plain: boolean): number { + const box = [n, -1]; + const r = validate(n, plain); + held[0] = box; + return r + box.length; +} +function walk(n: number, depth: number, plain: boolean): number { + const box = [n, depth]; + const r = depth === 0 ? bottom(n, plain) : walk(n, depth - 1, plain); + held[depth] = box; + return r + box.length; +} + +function chains(rounds: number): string { + const out: string[] = []; + for (const depth of [2, 5, 20]) + for (const plain of [false, true]) { + let caught = 0; + let sum = 0; + for (let i = 0; i < rounds; i++) { + try { + sum += walk(i, depth - 2, plain); + } catch (error) { + caught++; + sum += error instanceof Stop ? error.code & 7 : 1; + } + } + out.push(`depth ${depth} ${plain ? "object" : "error"}: caught ${caught} sum ${sum}`); + } + return out.join("\n"); +} + +// The same chains through a callback: each level visits the next with a +// closure, as tree visitors do. +function visit(n: number, depth: number, each: (n: number, depth: number) => number): number { + const box = [n, depth]; + const r = depth === 0 ? bottom(n, false) : each(n, depth - 1); + held[depth] = box; + return r + box.length; +} +function visits(rounds: number): string { + const out: string[] = []; + const each = (n: number, depth: number): number => visit(n, depth, each); + for (const depth of [2, 5, 20]) { + let caught = 0; + let sum = 0; + for (let i = 0; i < rounds; i++) { + try { + sum += visit(i, depth - 2, each); + } catch (error) { + caught++; + sum += error instanceof RangeError ? 1 : 0; + } + } + out.push(`visit depth ${depth}: caught ${caught} sum ${sum}`); + } + return out.join("\n"); +} + +// expr := term (("+" | "-") term)*; term := atom ("*" atom)*; +// atom := number | "(" expr ")" | name "(" expr ("," expr)* ")" | name. +// A call and a name start alike: the parser tries the call first and +// backtracks when it fails. +let text = ""; +let pos = 0; +function peek(): string { + return pos < text.length ? text[pos]! : ""; +} +function expect(c: string): void { + if (peek() !== c) throw new ParseError(pos, `expected ${c}`); + pos++; +} +function name(): string { + const start = pos; + while (pos < text.length && text.charCodeAt(pos) >= 97 && text.charCodeAt(pos) <= 122) pos++; + if (pos === start) throw new ParseError(pos, "expected a name"); + return text.slice(start, pos); +} +function call(): number { + const callee = name(); + expect("("); + let value = expr() + callee.length; + while (peek() === ",") { + pos++; + value += expr(); + } + expect(")"); + return value; +} +function atom(): number { + const c = peek(); + if (c >= "0" && c <= "9") { + let value = 0; + while (peek() >= "0" && peek() <= "9") value = value * 10 + (text.charCodeAt(pos++) - 48); + return value; + } + if (c === "(") { + pos++; + const value = expr(); + expect(")"); + return value; + } + const start = pos; + try { + return call(); + } catch (error) { + if (!(error instanceof ParseError)) throw error; + pos = start; + return name().length; + } +} +function term(): number { + let value = atom(); + while (peek() === "*") { + pos++; + value = (value * atom()) % 1000003; + } + return value; +} +function expr(): number { + let value = term(); + while (peek() === "+" || peek() === "-") { + const op = text[pos++]; + value = op === "+" ? value + term() : value - term(); + } + return value; +} + +let seed = 4242; +function random(): number { + seed = (Math.imul(seed, 1103515245) + 12345) >>> 0; + return seed / 4294967296; +} +function source(depth: number): string { + const r = random(); + if (depth > 6 || r < 0.25) return String(Math.floor(random() * 100)); + if (r < 0.45) return "abcdefgh".slice(0, 1 + Math.floor(random() * 8)); + if (r < 0.6) return `(${source(depth + 1)})`; + if (r < 0.8) return `${source(depth + 1)}${random() < 0.5 ? "+" : "*"}${source(depth + 1)}`; + return `f${"xyz".slice(0, Math.floor(random() * 3))}(${source(depth + 1)},${source(depth + 1)})`; +} + +function parse(count: number): string { + let total = 0; + let failed = 0; + for (let i = 0; i < count; i++) { + // Every tenth input lacks its last character, which fails deep inside it. + const full = source(0); + text = i % 10 === 0 ? full.slice(0, -1) : full; + pos = 0; + try { + total = (total + expr()) % 1000003; + if (pos !== text.length) throw new ParseError(pos, "trailing input"); + } catch (error) { + if (!(error instanceof ParseError)) throw error; + failed++; + } + } + return `parsed ${count}: total ${total} failed ${failed}`; +} + +const scale = Number(process.argv[2] ?? "1"); +console.log(chains(Math.floor(60000 * scale))); +console.log(visits(Math.floor(60000 * scale))); +console.log(parse(Math.floor(40000 * scale))); diff --git a/packages/compiler/src/backend/llvm/blocks.ts b/packages/compiler/src/backend/llvm/blocks.ts index 354e631c6..eee4d00b9 100644 --- a/packages/compiler/src/backend/llvm/blocks.ts +++ b/packages/compiler/src/backend/llvm/blocks.ts @@ -9,6 +9,7 @@ * code after it); here the lines are DROPPED instead, and emitStmts skips * whole statements once the current block is terminated, so no dropped * definition can leak into a later block. */ +import { UNWIND_RESUME, UNWIND_SLOT } from "./unwind-abi.js"; export class BlockBuilder { private readonly blocks: { label: string; lines: string[]; term: string | null }[] = []; @@ -86,7 +87,18 @@ export class BlockBuilder { terminate(s: string): void { if (this.cur.term === null) { - if (this.returnEpilogue && s.startsWith("ret ")) this.line(this.returnEpilogue); + if ( + this.returnEpilogue && + (s.startsWith("ret ") || + s.startsWith("call void @scr_unwind_raise()") || + s === UNWIND_RESUME) + ) + this.line(this.returnEpilogue); + if (s === UNWIND_RESUME) { + const exception = this.tmp(); + this.line(`${exception} = load { ptr, i32 }, ptr ${UNWIND_SLOT}`); + s = `resume { ptr, i32 } ${exception}`; + } this.cur.term = ` ${this.withDebugLocation(s)}`; } } diff --git a/packages/compiler/src/backend/llvm/emit-function.ts b/packages/compiler/src/backend/llvm/emit-function.ts index e015c2d72..749c91858 100644 --- a/packages/compiler/src/backend/llvm/emit-function.ts +++ b/packages/compiler/src/backend/llvm/emit-function.ts @@ -56,11 +56,14 @@ import { emitIntegerClone, emitIntegerDispatcher } from "./integer-clones.js"; import { beginFunctionLoops, LOOPS } from "./loop-state.js"; import { runningExtremumUpdates } from "./running-extrema.js"; import { findIntegerOrNaNLocals } from "./wrapping-sums.js"; +import { UNWIND_PERSONALITY, UNWIND_SLOT } from "./unwind-abi.js"; export function emitFunction(emitter: LlEmitter, fn: IrFunction): string { const B = new BlockBuilder(); emitter.B = B; emitter.currentFunctionName = fn.name; + emitter.currentUnwindAbi = emitter.unwindAbi.has(fn.name); + emitter.usesLandingPads = false; emitter.findInt32Allocations(fn); emitter.currentTier = fn.tier; // Fiber switches restore the active exception cell before control @@ -596,6 +599,8 @@ export function emitFunction(emitter: LlEmitter, fn: IrFunction): string { B.terminate(cleanup.terminator); } + if (emitter.usesLandingPads && emitter.currentUnwindAbi) + B.entryAllocas.push(`${UNWIND_SLOT} = alloca { ptr, i32 }`); if (emitter.logArgSlots > 0) { B.entryAllocas.push(`%logargs = alloca [${emitter.logArgSlots} x %ScrLogArg]`); } @@ -636,7 +641,10 @@ export function emitFunction(emitter: LlEmitter, fn: IrFunction): string { const debug = emitter.debugScope === null ? "" : ` !dbg ${emitter.debugScope}`; const symbol = borrowed ? mangleBorrowedFunction(fn.name) : mangleFunction(fn.name); emitter.privateGlobalSlots.clear(); - let body = `define internal ${ret} @${symbol}${int32Abi ? INT32_ABI_SUFFIX : ""}(${params.join(", ")}) ${attrs}${debug} { ; ${fn.name}\n${B.render()}\n}`; + // Landing pads (emitDirectCall) need the personality. + const personality = emitter.usesLandingPads ? ` ${UNWIND_PERSONALITY}` : ""; + if (emitter.usesLandingPads) emitter.declare(`declare i32 @__gcc_personality_v0(...)`); + let body = `define internal ${ret} @${symbol}${int32Abi ? INT32_ABI_SUFFIX : ""}(${params.join(", ")}) ${attrs}${personality}${debug} { ; ${fn.name}\n${B.render()}\n}`; if (int32Abi) body += "\n" + emitter.emitInt32AbiWrapper(fn, symbol, int32Abi); if (emitter.integerClones.members.has(fn.name)) { body += "\n" + emitIntegerClone(fn, emitter, emitter.stackChecks?.has(fn.name) === true); diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 6729da197..814c1a23e 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -128,6 +128,16 @@ import { type FfiCallbackAdapter, } from "../ffi-callbacks.js"; import { computeMayThrow } from "../may-throw.js"; +import { + UNWIND_PERSONALITY, + UNWIND_RAISE, + UNWIND_RAISE_DECLARATION, + UNWIND_RESUME, + UNWIND_SLOT, + UnwindAbiViolation, + bridgePlainUnwindCalls, + unwindAbiFunctions, +} from "./unwind-abi.js"; import { mangleAsyncInlineAwaitCall, mangleAsyncSpawn, @@ -439,6 +449,12 @@ export interface ForkPrimitives { export interface LlvmTargetOptions { /** C ABI target; omitted direct emission uses the host ABI. */ targetTriple?: string; + /** Linux (glibc and musl) executables: functions reached only by direct + * calls propagate exceptions by unwinding the native stack (unwind-abi.ts). */ + unwindAbi?: boolean; + /** Functions kept on the pending-flag ABI under `unwindAbi`: the ones an + * earlier emission found breaking its rules (UnwindAbiViolation). */ + unwindExcluded?: ReadonlySet; /** Emit the function bodies in this many contiguous ranges, each by its * own emitter, and merge them in function order (emit-journal.ts). The * output is the same as one emitter's. Debug builds (`debugSources`) @@ -590,16 +606,36 @@ function moduleEmitter(input: IrModule, options: LlvmTargetOptions): LlEmitter { return new LlEmitter(emitted, options, null, prepared?.mod === emitted ? prepared : null); } +/** Emits the module's parts, emitting it again with the functions an + * UnwindAbiViolation names on the pending-flag ABI. */ +function emitModuleText(input: IrModule, options: LlvmTargetOptions): string[] { + for (let excluded = options.unwindExcluded ?? new Set(); ;) { + const emitter = moduleEmitter(input, { ...options, unwindExcluded: excluded }); + try { + return emitter.emitParts(); + } catch (error) { + if (!(error instanceof UnwindAbiViolation)) throw error; + const names = new Set(excluded); + for (const name of emitter.unwindAbi) + for (const symbol of [mangleFunction(name), mangleBorrowedFunction(name)]) + if (error.symbols.has(symbol) || error.symbols.has(symbol + INT32_ABI_SUFFIX)) + names.add(name); + if (names.size === excluded.size) throw error; + excluded = names; + } + } +} + export function emitLlvmModule(input: IrModule, options: LlvmTargetOptions = {}): string { - return moduleEmitter(input, options).emit(); + return emitModuleText(input, options).join("\n"); } /** emitLlvmModule's text as parts that concatenate to it, without the copy * that joining them makes: a large program's text is 150 MB. */ export function emitLlvmModuleParts(input: IrModule, options: LlvmTargetOptions = {}): string[] { - return moduleEmitter(input, options) - .emitParts() - .flatMap((part, index) => (index === 0 ? [part] : ["\n", part])); + return emitModuleText(input, options).flatMap((part, index) => + index === 0 ? [part] : ["\n", part], + ); } /** Keep large translation units below the host's single-string limit. */ @@ -609,7 +645,7 @@ export function emitLlvmModuleSource( ): string | readonly string[] { // IR validation, contracts and the frontend's disposal run after lowering without checks. relieveHeapPressure(true); - const parts = moduleEmitter(input, options).emitParts(); + const parts = emitModuleText(input, options); const length = parts.reduce((total, part) => total + part.length, Math.max(0, parts.length - 1)); if (length <= 256 * 1024 * 1024) return parts.join("\n"); return parts.flatMap((part, index) => (index === 0 ? [part] : ["\n", part])); @@ -1253,6 +1289,10 @@ export class LlEmitter { /** May-throw analysis (computeMayThrow): pending * checks are emitted only after calls that can actually raise. */ readonly mayThrow: Set; + /** The functions that propagate exceptions by unwinding (unwind-abi.ts). */ + readonly unwindAbi: Set; + /** Whether the function being emitted is one of unwindAbi. */ + currentUnwindAbi = false; readonly indirectMayThrow: boolean; /** Worker programs: the functions that poll for termination on entry * (workerTerminationPolls); null outside worker programs. */ @@ -1711,6 +1751,16 @@ export class LlEmitter { nodes: this.nodeIndex, }); this.mayThrow = mt.fns; + this.unwindAbi = + options.unwindAbi === true && + !this.wasi && + mod.lib === undefined && + options.debugSources === undefined && + (options.targetTriple + ? /-linux-(?:gnu|musl)/.test(options.targetTriple) + : process.platform === "linux") + ? unwindAbiFunctions(mod, this.mayThrow, options.unwindExcluded) + : new Set(); this.workerEntryPolls = mt.workerEntryPolls ?? null; this.stackChecks = mt.stackChecks ?? null; // A stackless call's eager prefix borrows its caller's stack; the @@ -1846,6 +1896,9 @@ export class LlEmitter { : undefined, ) : NO_INTEGER_CLONES; + // Integer clones and their dispatchers call each other through their + // own lowering, which keeps plain calls and flag tests. + for (const name of this.integerClones.members) this.unwindAbi.delete(name); this.stackCallbacks = new StackCallbacks(this.fnByName); this.receiverReaders = new AmbientReceiverReaders(this.fnByName, this.nodeIndex); this.stackCaptures = new StackCaptures(this.fnByName, this.callLifetimes, this.stackCallbacks); @@ -2125,7 +2178,8 @@ export class LlEmitter { return this.emitParts().join("\n"); } emitParts(): string[] { - return emitParts(this); + const parts = emitParts(this); + return this.unwindAbi.size > 0 ? bridgePlainUnwindCalls(parts) : parts; } /** The dispose-observer gates the emitted frees and record writers test @@ -3235,6 +3289,13 @@ export class LlEmitter { terminator = `br label %${target.label}`; } else if (this.currentCoro !== null) { terminator = `br label %${this.currentCoro.finalLabel}`; + } else if (this.currentUnwindAbi && this.inLandingPad) { + // The unwind that entered the landing pad goes on to the caller's. + terminator = UNWIND_RESUME; + } else if (this.currentUnwindAbi) { + // The caller's invoke takes the exception at its landing pad. + this.declare(UNWIND_RAISE_DECLARATION); + terminator = UNWIND_RAISE; } else { const t = this.llType(this.currentReturnType); terminator = @@ -3265,6 +3326,7 @@ export class LlEmitter { passThrough !== undefined && !target && this.currentCoro === null && + !this.currentUnwindAbi && !this.currentInt32Result ) { const t = this.llType(this.currentReturnType); @@ -3451,6 +3513,46 @@ export class LlEmitter { B.startBlock(B.newLabel("exc.dead")); } + /** Emits `line`, a `call` of `callee`, and reports whether the call + * needs no pending check after it: a call of an unwinding-ABI function + * becomes an `invoke` whose landing pad runs this frame's unwind (the + * same releases and handler as emitPendingCheck's unwind path), and the + * normal path continues in a fresh block. Coroutine bodies keep plain + * calls (unwindAbiFunctions excludes their callees). */ + emitDirectCall(line: string, callee: string): boolean { + const B = this.B; + if (!this.unwindAbi.has(callee) || this.currentCoro !== null || B.isTerminated()) { + B.line(line); + return false; + } + const ok = B.newLabel("inv.ok"); + const pad = B.newLabel("inv.lp"); + this.usesLandingPads = true; + // A trailing comment goes after the invoke's labels. + const comment = line.indexOf(" ; "); + const text = comment < 0 ? line : line.slice(0, comment); + B.terminate( + `${text.replace(/^((?:%[\w.]+ = )?)call /, "$1invoke ")} to label %${ok} unwind label %${pad}`, + ); + B.startBlock(pad); + const exception = B.tmp(); + B.line(`${exception} = landingpad { ptr, i32 } cleanup`); + if (this.currentUnwindAbi) B.line(`store { ptr, i32 } ${exception}, ptr ${UNWIND_SLOT}`); + this.inLandingPad = true; + this.emitUnwind(); + this.inLandingPad = false; + B.startBlock(ok); + return true; + } + + /** Whether emitUnwind runs for a landing pad, whose unwind goes on with + * `resume` instead of raising again. */ + private inLandingPad = false; + + /** Whether the function being emitted has a landing pad (its definition + * needs the personality). */ + usesLandingPads = false; + /** A recursive function's entry check: below the running stack's guard, * throw Node's RangeError and unwind like any other pending exception. */ emitStackCheck(): void { @@ -5214,7 +5316,22 @@ export class LlEmitter { if (fn.captures !== undefined) params.unshift("ptr %sc_env"); const ret = this.llType(fn.returnType); const call = `call ${ret} @${mangleBorrowedFunction(fn.name)}(${params.join(", ")})`; - B.line(ret === "void" ? call : `%result = ${call}`); + // The owned entry of an unwinding-ABI body releases the borrowed + // parameters on the unwind too, then resumes it to its caller. + const unwinding = this.unwindAbi.has(fn.name) && kept.size === 0; + if (unwinding) { + const ok = B.newLabel("adapt.ok"); + const pad = B.newLabel("adapt.lp"); + B.terminate( + `${ret === "void" ? "" : "%result = "}invoke ${call.slice(5)} to label %${ok} unwind label %${pad}`, + ); + B.startBlock(pad); + const exception = B.tmp(); + B.line(`${exception} = landingpad { ptr, i32 } cleanup`); + for (const index of borrowed) this.releaseFrame(`%p${index}`, fn.params[index]!.type); + B.terminate(`resume { ptr, i32 } ${exception}`); + B.startBlock(ok); + } else B.line(ret === "void" ? call : `%result = ${call}`); // A borrowed result is reachable from the parameters: own it first. A // throwing body returns a null dummy, which needs no owner (and string // or array retains do not accept NULL). @@ -5240,7 +5357,9 @@ export class LlEmitter { B.terminate(ret === "void" ? "ret void" : `ret ${ret} ${result}`); const symbol = kept.size > 0 ? `${mangleBorrowedFunction(fn.name)}.virtual` : mangleFunction(fn.name); - return `define internal ${ret} @${symbol}(${params.join(", ")}) ${FN_ATTRS} {\n${B.render()}\n}`; + if (unwinding) this.declare(`declare i32 @__gcc_personality_v0(...)`); + const personality = unwinding ? ` ${UNWIND_PERSONALITY}` : ""; + return `define internal ${ret} @${symbol}(${params.join(", ")}) ${FN_ATTRS}${personality} {\n${B.render()}\n}`; } canBorrowCallArgument(value: IrExpr): boolean { return canBorrowCallArgument(this, value); diff --git a/packages/compiler/src/backend/llvm/expr-calls.ts b/packages/compiler/src/backend/llvm/expr-calls.ts index 6ff52619e..d411d9172 100644 --- a/packages/compiler/src/backend/llvm/expr-calls.ts +++ b/packages/compiler/src/backend/llvm/expr-calls.ts @@ -244,38 +244,46 @@ export function emitCallExpr( ? INTEGER_DISPATCH_SUFFIX : ""; const target = `@${borrowed ? mangleBorrowedFunction(e.callee) : host.callTarget(e.callee)}${abi ? INT32_ABI_SUFFIX : ""}${dispatch}`; + // A call of an unwinding-ABI callee is an invoke (emitDirectCall): + // its landing pad unwinds, so no pending check follows it. if (e.type.kind === "void") { - B.line(`call void ${target}(${argList})`); - if (host.mayThrow.has(e.callee)) host.emitPendingCheck(); + const invoked = host.emitDirectCall(`call void ${target}(${argList})`, e.callee); + if (!invoked && host.mayThrow.has(e.callee)) host.emitPendingCheck(); if (borrowed) host.releaseTemps(host.frames.pop()!); return { name: "", type: e.type }; } const t = B.tmp(); if (abi?.union) { - B.line(`${t} = call ${SCALAR_UNION_RESULT} ${target}(${argList})`); - if (host.mayThrow.has(e.callee)) host.emitPendingCheck(); + const invoked = host.emitDirectCall( + `${t} = call ${SCALAR_UNION_RESULT} ${target}(${argList})`, + e.callee, + ); + if (!invoked && host.mayThrow.has(e.callee)) host.emitPendingCheck(); if (borrowed) host.releaseTemps(host.frames.pop()!); if (stackResult) return host.stackScalarUnion(t, e.type); return host.own({ name: host.boxScalarUnion(t, e.type), type: e.type }); } if (abi?.result) { - B.line(`${t} = call i32 ${target}(${argList})`); + const invoked = host.emitDirectCall(`${t} = call i32 ${target}(${argList})`, e.callee); const out = host.int32Result(t, e.type); - if (host.mayThrow.has(e.callee)) host.emitPendingCheck(out); + if (!invoked && host.mayThrow.has(e.callee)) host.emitPendingCheck(out); if (borrowed) host.releaseTemps(host.frames.pop()!); return out; } - B.line(`${t} = call ${host.llType(e.type)} ${target}(${argList})`); + const invoked = host.emitDirectCall( + `${t} = call ${host.llType(e.type)} ${target}(${argList})`, + e.callee, + ); let out: LlValue; if (borrowed && host.borrowedReturns.has(e.callee)) { // A borrowed-return body hands back +0 (a null dummy when it threw): // test the exception first, then own the result before the // argument snapshots that keep it reachable are released. - if (host.mayThrow.has(e.callee)) host.emitPendingCheck(); + if (!invoked && host.mayThrow.has(e.callee)) host.emitPendingCheck(); out = host.own({ name: host.retainFrame(t, e.type), type: e.type }); } else { out = host.own({ name: t, type: e.type }); - if (host.mayThrow.has(e.callee)) host.emitPendingCheck(out); + if (!invoked && host.mayThrow.has(e.callee)) host.emitPendingCheck(out); } if (borrowed) { host.toFrame(out); @@ -1366,10 +1374,11 @@ export function emitBorrowedResultCall(host: LlvmEmitterContext, e: ExprOf<"call ) .join(", "); const t = host.B.tmp(); - host.B.line( + const invoked = host.emitDirectCall( `${t} = call ${host.llType(e.type)} @${mangleBorrowedFunction(e.callee)}${abi ? INT32_ABI_SUFFIX : ""}(${argList}) ; borrowed result`, + e.callee, ); - if (host.mayThrow.has(e.callee)) host.emitPendingCheck(); + if (!invoked && host.mayThrow.has(e.callee)) host.emitPendingCheck(); return { name: t, type: e.type }; } diff --git a/packages/compiler/src/backend/llvm/unwind-abi.test.ts b/packages/compiler/src/backend/llvm/unwind-abi.test.ts new file mode 100644 index 000000000..5f7f5895b --- /dev/null +++ b/packages/compiler/src/backend/llvm/unwind-abi.test.ts @@ -0,0 +1,285 @@ +import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile, deserializeModule } from "../../index.js"; +import { validateModule } from "../../ir/validate.js"; +import { emitLlvmModule } from "./emitter.js"; +import { UnwindAbiViolation, bridgePlainUnwindCalls } from "./unwind-abi.js"; + +async function moduleFor(source: string) { + const dir = await mkdtemp(join(tmpdir(), "scriptc-unwind-abi-")); + try { + const entry = join(dir, "main.ts"), + output = join(dir, "main.ir.json"); + await writeFile(entry, source); + const result = await compile(entry, { outDir: dir, outPath: output, outputKind: "ir" }); + if (!result.ok) + throw new Error(result.diagnostics.map((item) => `${item.code}: ${item.message}`).join("\n")); + const module = deserializeModule(await readFile(output, "utf8")); + expect(validateModule(module)).toEqual([]); + return module; + } finally { + await rm(dir, { recursive: true, force: true }); + } +} + +/** The definition of the source function `name` (its i32 or borrowing entry when it has one). */ +function body(ir: string, name: string): string { + return new RegExp( + `^define internal [^\\n]*@sc_b?f_[^\\n(]*${name}(?:\\.i32)?\\([^]*?^}`, + "m", + ).exec(ir)![0]; +} + +const SOURCE = ` +function leaf(n: number): number { + if (n === 3) throw new RangeError("three"); + return n * 2; +} +function first(n: number): number { + return leaf(n) + 1; +} +function second(n: number): number { + return first(n) * 3; +} +function third(n: number): number { + return second(n) - 2; +} +function mid(n: number): number { + const parts: string[] = ["a" + n]; + const r = third(n); + parts.push("b"); + return r + parts.length; +} +class Counter { + total = 0; + add(n: number): void { this.total += mid(n); } +} +function outer(n: number): string { + try { return "ok " + mid(n); } catch (e) { return "caught " + (e as Error).message; } +} +const counter = new Counter(); +for (let i = 0; i < 5; i++) { console.log(outer(i)); try { counter.add(i); } catch { console.log("add", i); } } +const f = (x: number) => mid(x); +console.log(f(1), counter.total); +`; + +const LINUX = { targetTriple: "x86_64-unknown-linux-gnu", unwindAbi: true } as const; + +test("directly called functions raise, and their callers invoke them without a pending check", async () => { + const ir = emitLlvmModule(await moduleFor(SOURCE), LINUX); + // leaf throws: the exception starts on the pending flag, and the three + // calls above it test the flag too; mid raises it on. + for (const name of ["leaf", "first", "second", "third"]) + expect(body(ir, name)).not.toContain("@scr_unwind_raise"); + const mid = body(ir, "mid"); + expect(mid).toMatch(/= call double @sc_b?f_[^(]*third\(/); + expect(mid).toContain("call void @scr_unwind_raise()"); + // outer invokes mid; the landing pad takes the exception to its handler. + const outer = body(ir, "outer"); + expect(outer).toMatch( + /= invoke double @sc_b?f_[^(]*mid[^\n]* to label %inv\.ok\d+ unwind label %inv\.lp\d+/, + ); + expect(outer).toMatch(/inv\.lp\d+:\n\s+%t\d+ = landingpad \{ ptr, i32 \} cleanup/); + expect(outer).toContain("personality ptr @__gcc_personality_v0"); + expect(ir).toContain("declare i32 @__gcc_personality_v0(...)"); + expect(ir).toContain("declare void @scr_unwind_raise() cold"); +}); + +test("a method of a class outside any hierarchy is on the unwinding ABI; closures keep the flag", async () => { + const ir = emitLlvmModule(await moduleFor(SOURCE), LINUX); + // Counter.add invokes mid and resumes the unwind from its landing pad; the + // closure over mid is a pointer target and returns with the flag. + const add = body(ir, "Counter_add"); + expect(add).toMatch(/invoke double @sc_b?f_[^(]*mid/); + expect(add).toMatch(/resume \{ ptr, i32 \} %[\w.]+/); + expect(add).not.toContain("@scr_unwind_raise"); + const closures = ir + .split(/\n(?=define )/) + .filter((def) => /^define internal [^\n]*@sc_b?f_[^\n(]*fn_/.test(def)); + expect(closures.length).toBeGreaterThan(0); + for (const def of closures) expect(def).not.toContain("call void @scr_unwind_raise()"); +}); + +test("recursive functions keep the pending flag, also when they recurse through a callback", async () => { + const source = ` +function leaf(n: number): number { + if (n < 0) throw new RangeError("negative"); + return n; +} +function one(n: number): number { return leaf(n) + 1; } +function two(n: number): number { return one(n) + 1; } +function three(n: number): number { return two(n) + 1; } +function four(n: number): number { + const parts: string[] = ["a" + n]; + const r = three(n); + return r + parts.length; +} +function walk(n: number, depth: number): number { + const parts: string[] = ["w" + n]; + const r = depth === 0 ? four(n) : walk(n, depth - 1); + return r + parts.length; +} +function visit(n: number, depth: number, each: (n: number, depth: number) => number): number { + const parts: string[] = ["v" + n]; + const r = depth === 0 ? four(n) : each(n, depth - 1); + return r + parts.length; +} +const each = (n: number, depth: number): number => visit(n, depth, each); +for (let i = -1; i < 2; i++) { + try { console.log(walk(i, 3), visit(i, 3, each)); } catch (e) { console.log((e as Error).message); } +} +`; + const ir = emitLlvmModule(await moduleFor(source), LINUX); + expect(body(ir, "four")).toContain("call void @scr_unwind_raise()"); + for (const name of ["walk", "visit"]) { + expect(body(ir, name)).not.toContain("@scr_unwind_raise"); + expect(body(ir, name)).toMatch(/invoke double @sc_b?f_[^(]*four/); + } +}); + +test("without the option, and off Linux, emission keeps the pending-flag ABI", async () => { + const mod = await moduleFor(SOURCE); + for (const options of [{}, { targetTriple: "arm64-apple-macosx14.0.0", unwindAbi: true }]) { + const ir = emitLlvmModule(mod, options); + expect(ir).not.toContain("invoke "); + expect(ir).not.toContain("@scr_unwind_raise"); + expect(ir).not.toContain("personality"); + } +}); + +test("bridgePlainUnwindCalls keeps the pending-flag contract at plain calls of raising functions", () => { + const raising = [ + "define internal ptr @sc_bf_raises(ptr %p) #0 { ; raises", + "entry:", + " call void @scr_unwind_raise()", + " unreachable", + "}", + ].join("\n"); + const caller = [ + "define internal ptr @sc_f_adapter(ptr %p0) #0 {", + "entry:", + " %result = call ptr @sc_bf_raises(ptr %p0) ; borrowed result", + " br label %next", + "next:", + " %v = phi ptr [ %result, %entry ]", + " ret ptr %v", + "}", + ].join("\n"); + const [out] = bridgePlainUnwindCalls([`${raising}\n${caller}`]); + expect(out).toContain( + "%result.ub = invoke ptr @sc_bf_raises(ptr %p0) to label %ub.n.0 unwind label %ub.lp.0", + ); + expect(out).toContain("%result = phi ptr [ %result.ub, %ub.n.0 ], [ null, %ub.lp.0 ]"); + // The split block's successor now comes from its last part. + expect(out).toContain("%v = phi ptr [ %result, %ub.ok.0 ]"); + expect(out).toMatch( + /define internal ptr @sc_f_adapter\(ptr %p0\) #0 personality ptr @__gcc_personality_v0 \{/, + ); + expect(out).toContain("declare i32 @__gcc_personality_v0(...)"); +}); + +test("an invoked wrapper of a raising function resumes the unwind; its address must not escape", () => { + const raising = [ + "define internal double @sc_bf_body.i32(i32 %a) #0 {", + "entry:", + " call void @scr_unwind_raise()", + " unreachable", + "}", + ].join("\n"); + const wrapper = [ + "define internal double @sc_bf_body(double %a) #0 {", + "entry:", + " %i = fptosi double %a to i32", + " %r = call double @sc_bf_body.i32(i32 %i)", + " ret double %r", + "}", + ].join("\n"); + const caller = [ + "define internal double @sc_bf_caller(double %a) #0 personality ptr @__gcc_personality_v0 {", + "entry:", + " %r = invoke double @sc_bf_body(double %a) to label %ok unwind label %lp", + "lp:", + " %x = landingpad { ptr, i32 } cleanup", + " call void @scr_unwind_raise()", + " unreachable", + "ok:", + " ret double %r", + "}", + ].join("\n"); + const [out] = bridgePlainUnwindCalls([[raising, wrapper, caller].join("\n")]); + expect(out).toContain( + "%r = invoke double @sc_bf_body.i32(i32 %i) to label %ub.ok.0 unwind label %ub.lp.0", + ); + expect(out).toContain("resume { ptr, i32 } %ub.v.0"); + expect(() => + bridgePlainUnwindCalls([ + `${raising}\n@table = internal constant [1 x ptr] [ptr @sc_bf_body.i32]`, + ]), + ).toThrow(UnwindAbiViolation); + try { + bridgePlainUnwindCalls([ + `${raising}\n@table = internal constant [1 x ptr] [ptr @sc_bf_body.i32]`, + ]); + } catch (error) { + expect([...(error as UnwindAbiViolation).symbols]).toEqual(["sc_bf_body.i32"]); + } +}); + +test("an invoked function that never tests the pending flag needs no raise", () => { + const raising = [ + "define internal void @sc_bf_raises() #0 {", + "entry:", + " call void @scr_unwind_raise()", + " unreachable", + "}", + ].join("\n"); + const leaf = [ + "define internal double @sc_bf_leaf() #0 {", + "entry:", + " ret double 1.0", + "}", + ].join("\n"); + const caller = (callee: string) => + [ + "define internal double @sc_bf_caller() #0 personality ptr @__gcc_personality_v0 {", + "entry:", + ` %r = invoke double @${callee}() to label %ok unwind label %lp`, + "lp:", + " %x = landingpad { ptr, i32 } cleanup", + " call void @scr_unwind_raise()", + " unreachable", + "ok:", + " ret double %r", + "}", + ].join("\n"); + expect(() => + bridgePlainUnwindCalls([[raising, leaf, caller("sc_bf_leaf")].join("\n")]), + ).not.toThrow(); + const testing = leaf.replace( + " ret double 1.0", + " %f = load i32, ptr @scr_exc_flag\n ret double 1.0", + ); + expect(() => + bridgePlainUnwindCalls([[raising, testing, caller("sc_bf_leaf")].join("\n")]), + ).toThrow(UnwindAbiViolation); +}); + +test("calls that cannot unwind are marked nounwind", () => { + const raising = [ + "define internal void @sc_bf_raises(ptr %b) #0 {", + "entry:", + " %n = call i64 @scr_bytes_length(ptr %b) ; length", + " call void @scr_bytes_release(ptr %b), !dbg !4", + " %r = call ptr %b(ptr %b)", + " call void @scr_unwind_raise()", + " unreachable", + "}", + ].join("\n"); + const [out] = bridgePlainUnwindCalls([raising]); + expect(out).toContain("%n = call i64 @scr_bytes_length(ptr %b) nounwind ; length"); + expect(out).toContain("call void @scr_bytes_release(ptr %b) nounwind, !dbg !4"); + expect(out).toContain("%r = call ptr %b(ptr %b) nounwind"); + expect(out).toContain(" call void @scr_unwind_raise()\n"); +}); diff --git a/packages/compiler/src/backend/llvm/unwind-abi.ts b/packages/compiler/src/backend/llvm/unwind-abi.ts new file mode 100644 index 000000000..4dc611913 --- /dev/null +++ b/packages/compiler/src/backend/llvm/unwind-abi.ts @@ -0,0 +1,491 @@ +/* The functions that propagate exceptions by unwinding instead of the + * pending flag (see unwindAbiFunctions). */ +import type { IrExpr, IrModule } from "../../ir/ir.js"; +import { everyStmtList } from "../../ir/traverse.js"; + +/** How many calls above a `throw` functions keep the pending flag. */ +const THROW_LEVELS = 3; +/** The call graph's node for calls through values. */ +const ANY_FUNCTION = " any function"; + +/** The nodes of `edges` on a cycle (a recursion), by Tarjan's algorithm + * without recursion of its own: a large module's call chains are deeper + * than the host stack. */ +function recursiveFunctions(edges: ReadonlyMap): Set { + const index = new Map(); + const low = new Map(); + const stack: string[] = []; + const onStack = new Set(); + const result = new Set(); + let counter = 0; + const enter = (name: string): { name: string; next: number } => { + index.set(name, counter); + low.set(name, counter++); + stack.push(name); + onStack.add(name); + return { name, next: 0 }; + }; + for (const root of edges.keys()) { + if (index.has(root)) continue; + const work = [enter(root)]; + while (work.length > 0) { + const top = work[work.length - 1]!; + const out = edges.get(top.name) ?? []; + if (top.next < out.length) { + const callee = out[top.next++]!; + if (!index.has(callee)) work.push(enter(callee)); + else if (onStack.has(callee)) + low.set(top.name, Math.min(low.get(top.name)!, index.get(callee)!)); + continue; + } + work.pop(); + const parent = work[work.length - 1]; + if (parent !== undefined) + low.set(parent.name, Math.min(low.get(parent.name)!, low.get(top.name)!)); + if (low.get(top.name) !== index.get(top.name)) continue; + const members: string[] = []; + let member: string; + do { + member = stack.pop()!; + onStack.delete(member); + members.push(member); + } while (member !== top.name); + if (members.length > 1 || out.includes(top.name)) for (const m of members) result.add(m); + } + } + return result; +} + +/** The may-throw functions whose exceptions reach their callers by + * unwinding the native stack (scr_unwind_raise) instead of returning with + * the pending flag set. Their callers call them with `invoke`, so the call + * needs no flag test; the landing pad runs the frame's unwind. + * + * A function qualifies only when every way it can be reached is a direct + * `call` from emitted code that can lower it as an `invoke`: it is not + * async or a generator, not a constructor, not a method a virtual call can + * reach or one a vtable holds (an overridden method), not a closure + * target, not the entry or a library export, not named by any node other + * than a `call`'s callee, and not called from an async or generator body + * (coroutine bodies keep plain calls). + * + * A native unwind costs about 2 µs a raise and 0.1 µs a frame, against a + * few nanoseconds for a flag test, so the functions an exception is likely to + * cross many of keep the flag: those with a `throw` or rethrow of their own + * and those up to THROW_LEVELS calls above one (a handler near the throw + * takes it without a native unwind), and the recursive ones (deep stacks + * are recursions). */ +export function unwindAbiFunctions( + mod: IrModule, + mayThrow: ReadonlySet, + excluded: ReadonlySet = new Set(), +): Set { + const names = new Set(mod.functions.map((fn) => fn.name)); + const blocked = new Set(excluded); + blocked.add(mod.entry); + // The runtime calls the error property readers through the pointers the + // module installs (emit-module.ts). + blocked.add("%error.name.read"); + blocked.add("%error.message.read"); + for (const entry of mod.lib?.exports ?? []) blocked.add(entry.fnName); + // Methods a virtual call can reach, and the overridden methods of class + // hierarchies (whose vtables list them), are called through pointers; the + // others are called directly, like functions. A virtual call reaches its listed + // targets, or else the method in its receiver class's hierarchy; a + // receiver that is no class of the module (an interface) may reach any + // class's method of that name. + const classes = new Map((mod.classes ?? []).map((cls) => [cls.name, cls])); + const anyClass = new Set(); + for (const fn of mod.functions) + everyStmtList(fn.body, { + expr: (e: IrExpr) => { + if (e.kind !== "virtualCall") return true; + if (e.targets !== undefined) for (const target of e.targets) blocked.add(target); + else if (classes.has(e.className)) blocked.add(`%${e.className}.${e.method}`); + else anyClass.add(e.method); + return true; + }, + stmt: () => true, + }); + // A hierarchy's vtables hold the methods declared by more than one of its + // classes (an override and what it overrides). + const rootOf = (name: string): string => { + let cls = classes.get(name); + while (cls?.base !== undefined && classes.has(cls.base)) cls = classes.get(cls.base); + return cls?.name ?? name; + }; + const declarers = new Map(); + for (const cls of mod.classes ?? []) + for (const m of cls.methods ?? []) { + const key = `${rootOf(cls.name)}\0${m}`; + declarers.set(key, (declarers.get(key) ?? 0) + 1); + } + for (const cls of mod.classes ?? []) { + blocked.add(`%${cls.name}.constructor`); + blocked.add(`%${cls.name}.construct`); + const root = rootOf(cls.name); + for (const m of cls.methods ?? []) + if (anyClass.has(m) || declarers.get(`${root}\0${m}`)! > 1) blocked.add(`%${cls.name}.${m}`); + } + // Any function a node names other than as a call's callee may be reached + // through a pointer. + const referenced = new Set(); + const noteNames = (node: object, skip: string | undefined): void => { + for (const key in node) { + if (key === skip) continue; + const value = (node as Record)[key]; + if (typeof value === "string" && names.has(value)) referenced.add(value); + } + }; + // The call graph, for the functions near a throw and the recursive ones. + // Calls through values (closures, class values, dynamic calls, callbacks + // passed to the runtime) reach ANY_FUNCTION, which reaches every function + // a value can hold. + const throws = new Set(); + const callers = new Map(); + const callees = new Map(); + const edge = (from: string, to: string): void => { + let list = callers.get(to); + if (list === undefined) callers.set(to, (list = [])); + list.push(from); + let out = callees.get(from); + if (out === undefined) callees.set(from, (out = [])); + out.push(to); + }; + const methodsNamed = new Map(); + for (const cls of mod.classes ?? []) + for (const m of cls.methods ?? []) { + let list = methodsNamed.get(m); + if (list === undefined) methodsNamed.set(m, (list = [])); + list.push(`%${cls.name}.${m}`); + } + for (const fn of mod.functions) { + const coroutine = fn.async === true || fn.generator !== undefined; + everyStmtList(fn.body, { + expr: (e: IrExpr) => { + const kind = e.kind as string; + if (kind === "throw" || kind === "rethrow") throws.add(fn.name); + if (e.kind === "call") { + edge(fn.name, e.callee); + // The entry's callees (the module initializers) run once: on the + // flag they keep landing pads out of the top-level code inlined + // into the entry. + if (coroutine || fn.name === mod.entry) blocked.add(e.callee); + noteNames(e, "callee"); + return true; + } + noteNames(e, undefined); + if (e.kind === "virtualCall") + for (const target of e.targets ?? methodsNamed.get(e.method) ?? []) edge(fn.name, target); + else if (e.kind === "new") { + edge(fn.name, `%${e.className}.constructor`); + edge(fn.name, `%${e.className}.construct`); + } else if (kind === "callValue" || kind === "dynCall" || kind === "newValue") + edge(fn.name, ANY_FUNCTION); + else if ("args" in e) { + const args: unknown = e.args; + if (Array.isArray(args)) + for (const arg of args as IrExpr[]) + if (arg.type.kind === "func") edge(fn.name, ANY_FUNCTION); + } + return true; + }, + stmt: (s) => { + const kind = s.kind as string; + if (kind === "throw" || kind === "rethrow") throws.add(fn.name); + noteNames(s, undefined); + return true; + }, + }); + } + for (const name of referenced) { + blocked.add(name); + edge(ANY_FUNCTION, name); + } + // A throw starts on the pending flag, and so do the functions up to + // THROW_LEVELS calls above it. The union narrowing helpers' throws (a + // failed narrowing) don't count for their callers. + for (const name of throws) blocked.add(name); + let level = [...throws].filter((name) => !name.startsWith("%union.")); + const near = new Set(level); + for (let i = 0; i < THROW_LEVELS; i++) { + const next: string[] = []; + for (const name of level) + for (const caller of callers.get(name) ?? []) + if (!near.has(caller)) { + near.add(caller); + next.push(caller); + } + level = next; + } + for (const name of near) blocked.add(name); + for (const name of recursiveFunctions(callees)) blocked.add(name); + const result = new Set(); + for (const fn of mod.functions) { + if (!mayThrow.has(fn.name) || blocked.has(fn.name)) continue; + if (fn.async === true || fn.generator !== undefined) continue; + result.add(fn.name); + } + return result; +} + +/** What an unwinding-ABI function's unwind ends with when no handler of + * its own takes the exception. */ +export const UNWIND_RAISE = "call void @scr_unwind_raise()\n unreachable"; +/** What the unwind of a landing pad ends with when no handler of the + * function takes the exception: the unwind goes on (`resume`) with the + * exception the landing pad stored in UNWIND_SLOT. The block builder + * expands it (BlockBuilder.terminate). */ +export const UNWIND_RESUME = "resume { ptr, i32 } "; +/** The function's slot for the exception its landing pads take. */ +export const UNWIND_SLOT = "%unw.exc"; +/** scr_unwind_raise's declaration. It is not `noreturn`: sanitized builds + * would call the sanitizer's no-return hook before it, which fails on fiber + * stacks; scr_unwind_raise clears the unwound frames' shadow itself. */ +export const UNWIND_RAISE_DECLARATION = "declare void @scr_unwind_raise() cold"; + +/** The personality of functions with landing pads: the landing pads are + * cleanups that scr_unwind_raise's forced unwind runs. */ +export const UNWIND_PERSONALITY = "personality ptr @__gcc_personality_v0"; + +/** An unwind leaving the function: a raise, or a landing pad's `resume`. */ +const UNWINDS = /call void @scr_unwind_raise\(\)|\n\s+resume /; +/** A pending-flag test: the thread's exception word, the active cell, or the runtime query. */ +const PENDING_TEST = /@scr_exc_flag\b|%exc\.cell\b|@scr_exc_active\b|@scr_exc_pending\(/; + +/** Functions emission found breaking the unwinding ABI's rules + * (bridgePlainUnwindCalls), by symbol: the caller emits the module again + * with them on the pending-flag ABI. */ +export class UnwindAbiViolation extends Error { + readonly symbols: ReadonlySet; + constructor(symbols: ReadonlySet) { + super(`unwinding ABI: ${[...symbols].slice(0, 3).join(", ")} must keep the pending flag`); + this.symbols = symbols; + } +} +const DEFINE_NAME = /^define [^@\n]*@([\w.$%-]+)\(/; +const PLAIN_CALL = /^(\s*)(%[\w.$-]+) = call (.*?)@([\w.$%-]+)\(|^(\s*)call (.*?)@([\w.$%-]+)\(/; +const RETURN_ATTRIBUTES = + /\b(?:zeroext|signext|noalias|nonnull|noundef|inreg|dereferenceable(?:_or_null)?\(\d+\)|align \d+)\s+/g; + +/** A call instruction's line. */ +const CALL_LINE = /^\s*(?:%[\w.$-]+ = )?(?:(?:tail|musttail|notail) )?call /; +/** A call's callee (a function or a register) and the parenthesis that + * opens its arguments. */ +const CALLEE = /[@%][\w.$%-]+\(/; + +/** The index of the parenthesis that closes the argument list opened at `open`. */ +function argumentsEnd(line: string, open: number): number { + let depth = 0; + let close = open; + for (; close < line.length; close++) { + const c = line.charAt(close); + if (c === "(") depth++; + else if (c === ")" && --depth === 0) break; + } + return close; +} + +/** A call that cannot unwind, marked so: only scr_unwind_raise and the + * raising functions propagate an unwind (runtime code and every function + * reached through a pointer return normally), so every other call is + * `nounwind`, and the inliner keeps it a call where it inlines a raising + * function at an invoke. */ +function markNounwind(line: string): string { + const call = line.indexOf("call "); + const callee = CALLEE.exec(line.slice(call)); + if (callee === null || callee[0] === "@scr_unwind_raise(") return line; + const close = argumentsEnd(line, call + callee.index + callee[0].length - 1); + return close >= line.length + ? line + : `${line.slice(0, close + 1)} nounwind${line.slice(close + 1)}`; +} + +/** The value a bridged call yields on its landing pad: the dummy a + * pending-flag callee returns with an exception pending. */ +function dummyValue(type: string): string { + if (type === "ptr") return "null"; + if (type === "double" || type === "float") return "0.0"; + if (/^i\d+$/.test(type)) return "0"; + return "zeroinitializer"; +} + +/** Rewrites every remaining plain call of an unwinding-ABI function (one + * that raises, scr_unwind_raise, or resumes an unwind) in `parts`, the module's text, into an + * invoke whose landing pad continues after the call with the exception + * pending and the call's dummy result: the pending-flag contract those + * call sites were emitted for, whichever lowering emitted them. Calls of + * these functions that emitDirectCall lowered are invokes already. */ +export function bridgePlainUnwindCalls(parts: string[]): string[] { + const raisers = new Set(); + const split = parts.map((part) => part.split(/\n(?=define )/)); + for (const chunks of split) + for (const chunk of chunks) { + const m = DEFINE_NAME.exec(chunk); + if (m !== null && UNWINDS.test(chunk)) raisers.add(m[1]!); + } + if (raisers.size === 0) return parts; + // An invoke's callee must raise or never test the pending flag: one that + // returned with the flag pending would pass the exception by its invoking + // caller unseen. A wrapper an invoke reaches (an int32 or borrowed-ABI + // entry forwarding to the body) propagates its callee's unwind instead + // (`resume`), so it raises too. A raising function must be reached only by + // calls: a pointer to it (a vtable or table entry, a runtime callback) + // could be called without a landing pad. Functions that break either rule + // go back to the pending-flag ABI (UnwindAbiViolation). + const violations = new Set(); + const invoked = new Set(); + const testsFlag = new Set(); + for (const chunks of split) + for (const chunk of chunks) { + const m = DEFINE_NAME.exec(chunk); + if (m !== null && PENDING_TEST.test(chunk)) testsFlag.add(m[1]!); + for (const c of chunk.matchAll(/ invoke [^@\n]*@([\w.$%-]+)\(/g)) invoked.add(c[1]!); + } + const resumers = new Set(); + for (let grew = true; grew;) { + grew = false; + for (const chunks of split) + for (const chunk of chunks) { + const m = DEFINE_NAME.exec(chunk); + const name = m?.[1]; + if (name === undefined || raisers.has(name) || !invoked.has(name)) continue; + if (![...chunk.matchAll(/ call [^@\n]*@([\w.$%-]+)\(/g)].some((c) => raisers.has(c[1]!))) + continue; + if (testsFlag.has(name)) continue; + raisers.add(name); + resumers.add(name); + grew = true; + } + } + for (const name of invoked) if (!raisers.has(name) && testsFlag.has(name)) violations.add(name); + for (const chunks of split) + for (const chunk of chunks) + for (const line of chunk.split("\n")) { + if (line.startsWith("define ")) continue; + for (const m of line.matchAll(/@([\w.$%-]+)/g)) { + if (!raisers.has(m[1]!)) continue; + const at = m.index!; + if ( + /(?:call|invoke) [^@]*$/.test(line.slice(0, at)) && + line.charAt(at + m[0].length) === "(" + ) + continue; + violations.add(m[1]!); + } + } + if (violations.size > 0) throw new UnwindAbiViolation(violations); + let personality = false; + let counter = 0; + const out = split.map((chunks) => + chunks + .map((chunk) => { + if (!DEFINE_NAME.test(chunk) || !chunk.includes("call ")) return chunk; + const lines = chunk.split("\n"); + const resume = resumers.has(DEFINE_NAME.exec(chunk)![1]!); + const result: string[] = []; + // The label a block's terminator now follows, for phi operands. + const moved = new Map(); + let block = ""; + let changed = false; + for (let i = 0; i < lines.length; i++) { + const line = lines[i]!; + const label = /^([\w.$-]+):/.exec(line); + if (label !== null) block = label[1]!; + const m = PLAIN_CALL.exec(line); + const callee = m === null ? undefined : (m[4] ?? m[7]); + if (m === null || callee === undefined || !raisers.has(callee)) { + const marked = CALL_LINE.test(line) ? markNounwind(line) : line; + changed ||= marked !== line; + result.push(marked); + continue; + } + // The call's text from its callee to the end of the argument list. + const close = argumentsEnd(line, line.indexOf(`@${callee}(`) + callee.length + 1); + const head = line.slice(line.indexOf("call ") + 5, close + 1); + const tail = line.slice(close + 1); + const meta = /,\s*!/.exec(tail); + const attrs = ( + meta === null ? tail.replace(/;.*$/, "") : tail.slice(0, meta.index) + ).trimEnd(); + const dbg = meta === null ? "" : tail.slice(meta.index).replace(/\s;.*$/, ""); + const n = counter++; + if (block === "") { + result.splice(1, 0, "entry.ub:"); + block = "entry.ub"; + } + const indent = m[1] ?? m[5] ?? " "; + const ok = `ub.ok.${n}`; + const pad = `ub.lp.${n}`; + if (resume) { + // The wrapper holds nothing to release: the unwind goes on to + // its caller's landing pad. + const assign = m[2] !== undefined ? `${m[2]} = ` : ""; + result.push( + `${indent}${assign}invoke ${head}${attrs} to label %${ok} unwind label %${pad}${dbg}`, + ); + result.push( + `${pad}:`, + `${indent}%ub.v.${n} = landingpad { ptr, i32 } cleanup`, + `${indent}resume { ptr, i32 } %ub.v.${n}`, + ); + result.push(`${ok}:`); + } else if (m[2] !== undefined) { + const type = (m[3] ?? "").replace(RETURN_ATTRIBUTES, "").trim(); + const normal = `ub.n.${n}`; + result.push( + `${indent}${m[2]}.ub = invoke ${head}${attrs} to label %${normal} unwind label %${pad}${dbg}`, + ); + result.push(`${normal}:`, `${indent}br label %${ok}`); + result.push( + `${pad}:`, + `${indent}%ub.v.${n} = landingpad { ptr, i32 } cleanup`, + `${indent}br label %${ok}`, + ); + result.push( + `${ok}:`, + `${indent}${m[2]} = phi ${type} [ ${m[2]}.ub, %${normal} ], [ ${dummyValue(type)}, %${pad} ]`, + ); + } else { + result.push( + `${indent}invoke ${head}${attrs} to label %${ok} unwind label %${pad}${dbg}`, + ); + result.push( + `${pad}:`, + `${indent}%ub.v.${n} = landingpad { ptr, i32 } cleanup`, + `${indent}br label %${ok}`, + ); + result.push(`${ok}:`); + } + moved.set(block, ok); + changed = true; + } + if (!changed) return chunk; + if (moved.size === 0) return result.join("\n"); + personality = true; + const header = result[0]!; + const brace = header.lastIndexOf(" {"); + if (!header.includes("personality") && brace >= 0) { + // Before the function's metadata attachments (`!dbg`), if any. + const dbg = header.slice(0, brace).search(/\s!dbg !\d+$/); + const at = dbg >= 0 ? dbg : brace; + result[0] = `${header.slice(0, at)} ${UNWIND_PERSONALITY}${header.slice(at)}`; + } + // A split block's successors now come from its last part. + if (moved.size > 0) + for (let i = 0; i < result.length; i++) { + const line = result[i]!; + if (!line.includes(" phi ")) continue; + result[i] = line.replace(/, %([\w.$-]+) \]/g, (all, name: string) => { + const to = moved.get(name); + return to === undefined ? all : `, %${to} ]`; + }); + } + return result.join("\n"); + }) + .join("\n"), + ); + if (personality && !out.some((part) => part.includes("@__gcc_personality_v0(...)"))) + out[0] = `declare i32 @__gcc_personality_v0(...)\n${out[0]}`; + return out; +} diff --git a/packages/compiler/src/backend/native/executable.ts b/packages/compiler/src/backend/native/executable.ts index ceb162bcc..1364bca4d 100644 --- a/packages/compiler/src/backend/native/executable.ts +++ b/packages/compiler/src/backend/native/executable.ts @@ -43,6 +43,7 @@ import { cacheTargetIdentity, isZigDriver, isMuslTarget, + type CcDriver, } from "./driver.js"; import { resolveProgramShardMergeIdentity, @@ -821,6 +822,7 @@ export async function compileCInternal( // generated/native input that references inflate symbols. Cross // and targetless Zig builds use vendored zlib objects in the input section above. ...(((opts.zlib ?? false) || nativeFetch) && !isZigDriver(driver) ? ["-lz"] : []), + ...unwinderLinkArgs(driver), // glibc keeps libm separate from libc. This must trail the generated // program and every native FFI input because GNU ld resolves archives // from left to right. @@ -1068,6 +1070,7 @@ export async function compileCInternal( ...(mbedtls && targetPlatform(driver) === "win32" ? ["-lbcrypt"] : []), ...(tlsCa && targetPlatform(driver) === "win32" ? ["-lcrypt32"] : []), ...(((opts.zlib ?? false) || nativeFetch) && !isZigDriver(driver) ? ["-lz"] : []), + ...unwinderLinkArgs(driver), ...driver.linkArgs, ...executableLinkFlags, ]; @@ -1080,6 +1083,7 @@ export async function compileCInternal( ...(mbedtls && targetPlatform(driver) === "win32" ? ["-lbcrypt"] : []), ...(tlsCa && targetPlatform(driver) === "win32" ? ["-lcrypt32"] : []), ...(((opts.zlib ?? false) || nativeFetch) && !isZigDriver(driver) ? ["-lz"] : []), + ...unwinderLinkArgs(driver), ...driver.linkArgs, ...executableLinkFlags, ]; @@ -1689,3 +1693,11 @@ export async function compileC(opts: CcOptions): Promise { await rm(`${opts.outPath}.dSYM`, { recursive: true, force: true }); } } + +/** Linux runtimes raise through the native unwinder (scr_unwind_raise): + * Zig's libunwind, or the toolchain's libgcc_eh. Both are static archives, + * so programs load no shared library for them. */ +function unwinderLinkArgs(driver: CcDriver): string[] { + if (targetPlatform(driver) !== "linux") return []; + return isZigDriver(driver) ? ["-lunwind"] : ["-lgcc_eh"]; +} diff --git a/packages/compiler/src/backend/native/runtime-inputs.ts b/packages/compiler/src/backend/native/runtime-inputs.ts index c7c5bc32b..d32867331 100644 --- a/packages/compiler/src/backend/native/runtime-inputs.ts +++ b/packages/compiler/src/backend/native/runtime-inputs.ts @@ -53,6 +53,7 @@ export const EXECUTABLE_RUNTIME_SOURCES = [ "scr_object.c", "scr_union.c", "scr_exception.c", + "scr_unwind.c", "scr_error.c", "scr_console.c", "scr_lib.c", diff --git a/packages/compiler/src/index.ts b/packages/compiler/src/index.ts index e2d1c97cc..4fb64968b 100644 --- a/packages/compiler/src/index.ts +++ b/packages/compiler/src/index.ts @@ -875,6 +875,7 @@ async function prepareExecutableInput( pointerBits: buildPlatform === "wasi" ? 32 : 64, wasi: buildPlatform === "wasi", runtimeAbiMarker: useRuntimePack, + unwindAbi: buildPlatform === "linux", objectAudit: opts.sanitize === true, lowRegion: lowRegionTarget(buildPlatform, opts.sanitize === true), ...(opts.sanitize === true ? { wasmBoundsChecks: true } : {}), diff --git a/packages/compiler/src/native/prepare.ts b/packages/compiler/src/native/prepare.ts index 67a4b5a9e..e90c1f043 100644 --- a/packages/compiler/src/native/prepare.ts +++ b/packages/compiler/src/native/prepare.ts @@ -402,6 +402,7 @@ export function prepareNativeExecutable( pointerBits: toolchain.target.pointerBits, wasi: toolchain.target.platform === "wasi", runtimeAbiMarker: outputKind === "obj" || outputKind === "exe", + unwindAbi: outputKind === "exe" && toolchain.target.platform === "linux", objectAudit: options.sanitize === true, lowRegion: lowRegionTarget(toolchain.target.platform, options.sanitize === true), functionWorkers: emitWorkers(), diff --git a/packages/runtime-linux-arm64-gnu/scripts/build.mjs b/packages/runtime-linux-arm64-gnu/scripts/build.mjs index 729c3fbb6..d16fb1528 100644 --- a/packages/runtime-linux-arm64-gnu/scripts/build.mjs +++ b/packages/runtime-linux-arm64-gnu/scripts/build.mjs @@ -24,6 +24,10 @@ process.env.SCRIPTC_RUNTIME_PACK_CONFIG = JSON.stringify({ }, ...toolchain, compileFlags: ["-ffunction-sections", "-fdata-sections"], - systemLibraries: [{ name: "m", predicate: true }], + // scr_unwind_raise: the static libgcc_eh, which loads no shared library. + systemLibraries: [ + { name: "m", predicate: true }, + { name: "gcc_eh", predicate: true }, + ], }); await import("../../runtime-pack-common/scripts/build.mjs"); diff --git a/packages/runtime-linux-arm64-musl/scripts/build.mjs b/packages/runtime-linux-arm64-musl/scripts/build.mjs index 10635d857..6c9b38244 100644 --- a/packages/runtime-linux-arm64-musl/scripts/build.mjs +++ b/packages/runtime-linux-arm64-musl/scripts/build.mjs @@ -26,6 +26,10 @@ process.env.SCRIPTC_RUNTIME_PACK_CONFIG = JSON.stringify({ }, targetArgs: ["-target", "aarch64-linux-musl"], compileFlags: ["-ffunction-sections", "-fdata-sections"], - systemLibraries: [{ name: "m", predicate: true }], + // scr_unwind_raise: Zig's libunwind. + systemLibraries: [ + { name: "m", predicate: true }, + { name: "unwind", predicate: true }, + ], }); await import("../../runtime-pack-common/scripts/build.mjs"); diff --git a/packages/runtime-linux-x64-gnu/scripts/build.mjs b/packages/runtime-linux-x64-gnu/scripts/build.mjs index 811bb537b..53df5f7e7 100644 --- a/packages/runtime-linux-x64-gnu/scripts/build.mjs +++ b/packages/runtime-linux-x64-gnu/scripts/build.mjs @@ -24,6 +24,10 @@ process.env.SCRIPTC_RUNTIME_PACK_CONFIG = JSON.stringify({ }, ...toolchain, compileFlags: ["-ffunction-sections", "-fdata-sections"], - systemLibraries: [{ name: "m", predicate: true }], + // scr_unwind_raise: the static libgcc_eh, which loads no shared library. + systemLibraries: [ + { name: "m", predicate: true }, + { name: "gcc_eh", predicate: true }, + ], }); await import("../../runtime-pack-common/scripts/build.mjs"); diff --git a/packages/runtime-linux-x64-musl/scripts/build.mjs b/packages/runtime-linux-x64-musl/scripts/build.mjs index 33fc4c3d1..88538de76 100644 --- a/packages/runtime-linux-x64-musl/scripts/build.mjs +++ b/packages/runtime-linux-x64-musl/scripts/build.mjs @@ -26,6 +26,10 @@ process.env.SCRIPTC_RUNTIME_PACK_CONFIG = JSON.stringify({ }, targetArgs: ["-target", "x86_64-linux-musl"], compileFlags: ["-ffunction-sections", "-fdata-sections"], - systemLibraries: [{ name: "m", predicate: true }], + // scr_unwind_raise: Zig's libunwind. + systemLibraries: [ + { name: "m", predicate: true }, + { name: "unwind", predicate: true }, + ], }); await import("../../runtime-pack-common/scripts/build.mjs"); diff --git a/packages/runtime-pack-common/runtime-pack-matrix.mjs b/packages/runtime-pack-common/runtime-pack-matrix.mjs index 600637ba6..4df534739 100644 --- a/packages/runtime-pack-common/runtime-pack-matrix.mjs +++ b/packages/runtime-pack-common/runtime-pack-matrix.mjs @@ -30,6 +30,7 @@ export const BASE_RUNTIME_SOURCES = [ "scr_object.c", "scr_union.c", "scr_exception.c", + "scr_unwind.c", "scr_error.c", "scr_console.c", "scr_lib.c", diff --git a/packages/runtime/src/scr_exception.h b/packages/runtime/src/scr_exception.h index e99f84243..63dd4a3ca 100644 --- a/packages/runtime/src/scr_exception.h +++ b/packages/runtime/src/scr_exception.h @@ -123,6 +123,11 @@ static inline ScrExcCell *scr_exc_swap_cell_inline(ScrExcCell *cell) { _Static_assert(offsetof(ScrExcCell, kind) == 0 && sizeof(ScrExcKind) == 4 && SCR_EXC_NONE == 0, "the LLVM emitter's inline pending check loads an i32 kind at offset 0"); +/* Unwinds the native stack to the nearest landing pad of emitted code with + * the exception pending in the active cell (the unwinding ABI of emitted + * functions, unwind-abi.ts). Linux (glibc and musl) only; it never + * returns. */ +SCR_COLD _Noreturn void scr_unwind_raise(void); SCR_COLD void scr_throw_f64(double v); SCR_COLD void scr_throw_bool(bool v); SCR_COLD void scr_throw_str(ScrStr *v); /* takes ownership */ diff --git a/packages/runtime/src/scr_unwind.c b/packages/runtime/src/scr_unwind.c new file mode 100644 index 000000000..9bdf2dbd2 --- /dev/null +++ b/packages/runtime/src/scr_unwind.c @@ -0,0 +1,76 @@ +/* scr_unwind_raise: the native unwind of the unwinding exception ABI of + * emitted functions (the compiler's unwind-abi.ts). Linux (glibc and musl) + * only; elsewhere this unit is empty. */ +#include "scr_runtime.h" + +#if defined(__linux__) && !defined(__ANDROID__) && !defined(__wasi__) +#include +#include +#include +#include +#include + +#if defined(__SANITIZE_ADDRESS__) +#define SCR_UNWIND_ASAN 1 +#elif defined(__has_feature) +#if __has_feature(address_sanitizer) +#define SCR_UNWIND_ASAN 1 +#endif +#endif +#ifdef SCR_UNWIND_ASAN +#include +#endif + +#ifdef SCR_UNWIND_ASAN +/* The lowest stack address the unwind has not cleared yet. The unwind + * outlives the frame that started it: landing pads resume it. */ +static SCR_TL uintptr_t scr_unwind_low; +#endif + +/* Emitted landing pads are cleanups: they release the frame's references + * and then either take the exception (a handler of theirs, or a frame on + * the pending-flag ABI that returns with it pending) or resume the unwind. + * So the unwind is forced, a single pass through every landing pad; the + * exception itself stays in the active cell. */ +static _Unwind_Reason_Code scr_unwind_stop(int version, _Unwind_Action actions, + _Unwind_Exception_Class cls, + struct _Unwind_Exception *exc, + struct _Unwind_Context *context, void *arg) { + (void)version; + (void)cls; + (void)exc; +#ifdef SCR_UNWIND_ASAN + /* The frames this unwind passes never return, so it clears their + * redzones' shadow itself. Emitted code calls scr_unwind_raise as an + * ordinary function: the sanitizer's hook before no-return calls needs + * stack bounds, which fiber stacks do not report. */ + uintptr_t cfa = _Unwind_GetCFA(context); + if (cfa > scr_unwind_low) { + __asan_unpoison_memory_region((void *)scr_unwind_low, cfa - scr_unwind_low); + scr_unwind_low = cfa; + } +#else + (void)context; +#endif + (void)arg; + if (actions & _UA_END_OF_STACK) { + fputs("scriptc: an exception unwound past the program's outermost frame\n", stderr); + abort(); + } + return _URC_NO_REASON; +} + +static SCR_TL struct _Unwind_Exception scr_unwind_exception; + +void scr_unwind_raise(void) { + struct _Unwind_Exception *exc = &scr_unwind_exception; + memset(exc, 0, sizeof *exc); + exc->exception_class = 0x5343524950540000ull; /* "SCRIPT\0\0" */ +#ifdef SCR_UNWIND_ASAN + scr_unwind_low = (uintptr_t)__builtin_frame_address(0); +#endif + _Unwind_ForcedUnwind(exc, scr_unwind_stop, NULL); + fputs("scriptc: the native unwinder could not raise an exception\n", stderr); + abort(); +} +#endif diff --git a/scripts/zero-cost-compare.mjs b/scripts/zero-cost-compare.mjs index a1ab3ca60..b23f61a0a 100644 --- a/scripts/zero-cost-compare.mjs +++ b/scripts/zero-cost-compare.mjs @@ -395,7 +395,9 @@ export function dynamicTierSymbols(names) { * bench/channel-messages and bench/worker-messages, added later, link them * through worker messages: * node:worker_threads values are dyn objects. bench/json-unions, added - * later too, decodes JSON.parse trees. bench/dynamic-methods and + * later too, decodes JSON.parse trees. bench/throw-chains, also added + * later, tests caught values with `instanceof`, as bench/validate-errors + * does. bench/dynamic-methods and * bench/dynamic-properties are untyped JavaScript. Every other bench workload is fully typed and must link none. The gate and * tests/harness/bench-dynamic-tier.test.ts enforce that, and the test also * fails when a listed workload stops linking them, so remove a workload here @@ -417,6 +419,7 @@ export const DYNAMIC_WORKLOADS = new Set([ "bench/log-summary", "bench/inventory-report", "bench/json-unions", + "bench/throw-chains", ]); /** Names of the functions (text and weak symbols) in `nm` output. Mach-O From 396c6944ecad5bda1d8ab9dd0179181aa0cf97a2 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 11:20:47 -0500 Subject: [PATCH 105/259] Report how well the native compiler's profile matches its functions The native compiler is built with a committed optimization profile. A function whose control flow changed since the profile was collected is optimized as without one, so the profile loses its gain as compiler code changes, with nothing to show it. With --profile-use, the helper now counts what the profile annotation reports while it applies the profile: functions that took the profile's counts, functions whose control flow no longer matches (hash mismatch), and functions the profile has no record of. It sums the counts over partitions, keeps each partition's counts beside its cached summary, and prints them as one line of JSON after a successful emit. The compiler reads that line (an older helper prints none) and returns it as the executable artifact's profileMatch. build-native-cli prints the share of profiled functions that match, and warns below 90% that the profile should be refreshed. On main aa1c26845, a profile refreshed on that commit matches 92.7% of the compiler's profiled functions, and the one committed about 200 commits earlier 87.2%; that one kept about half of the fresh profile's gain on a cold tsc-ts build. --- native/llvm-codegen/src/emit.cpp | 157 +++++++++++++++++- .../compiler/src/backend/native-codegen.ts | 10 +- .../src/backend/native-profile.test.ts | 13 ++ .../compiler/src/backend/native-profile.ts | 39 +++++ packages/compiler/src/compile-types.ts | 3 + packages/compiler/src/index.ts | 5 + scripts/build-native-cli.mts | 25 +++ 7 files changed, 242 insertions(+), 10 deletions(-) diff --git a/native/llvm-codegen/src/emit.cpp b/native/llvm-codegen/src/emit.cpp index 9cae164d3..35d7ce4f0 100644 --- a/native/llvm-codegen/src/emit.cpp +++ b/native/llvm-codegen/src/emit.cpp @@ -19,6 +19,7 @@ #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineFunctionPass.h" #include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/IR/DiagnosticHandler.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" #include "llvm/IR/LegacyPassManager.h" @@ -41,11 +42,13 @@ #include "llvm/Support/SourceMgr.h" #include "llvm/Support/ThreadPool.h" #include "llvm/Support/Threading.h" +#include "llvm/Support/JSON.h" #include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" #include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/Utils/SplitModule.h" +#include #include #include #include @@ -170,6 +173,108 @@ void limitProfileImports() { (void)Limited; } +// How the --profile-use profile matched the functions it annotated, summed +// over partitions: functions that received its counts, functions whose +// control flow changed since it was collected (hash mismatch), and functions +// it has no record of (new, or never run in training: the merged profile is +// sparse). A partition reused from the cache without its counts is counted +// in Unknown. +struct ProfileMatch { + std::atomic Annotated{0}; + std::atomic Mismatched{0}; + std::atomic Missing{0}; + std::atomic Unknown{0}; + + void add(const ProfileMatch &Other) { + Annotated += Other.Annotated; + Mismatched += Other.Mismatched; + Missing += Other.Missing; + } + + std::string serialize() const { + return formatv("{0} {1} {2}", Annotated.load(), Mismatched.load(), + Missing.load()) + .str(); + } + + bool deserialize(StringRef Text) { + SmallVector Parts; + Text.split(Parts, ' '); + uint64_t Values[3]; + if (Parts.size() != 3) + return false; + for (size_t I = 0; I < 3; ++I) + if (Parts[I].getAsInteger(10, Values[I])) + return false; + Annotated += Values[0]; + Mismatched += Values[1]; + Missing += Values[2]; + return true; + } +}; + +// Counts the profile annotation's hash-mismatch and missing-function +// warnings instead of printing them. Every other diagnostic takes the +// context's default handling. +class ProfileMatchHandler : public DiagnosticHandler { +public: + explicit ProfileMatchHandler(ProfileMatch &Match) : Match(Match) {} + + bool handleDiagnostics(const DiagnosticInfo &Info) override { + if (Info.getKind() != DK_PGOProfile) + return false; + std::string Message; + raw_string_ostream Stream(Message); + DiagnosticPrinterRawOStream Printer(Stream); + Info.print(Printer); + if (StringRef(Message).contains("hash mismatch")) + ++Match.Mismatched; + else if (StringRef(Message).contains_insensitive("no profile data")) + ++Match.Missing; + else + return false; + return true; + } + +private: + ProfileMatch &Match; +}; + +// The annotation warns about functions the profile does not describe only +// when asked; the match counts need those warnings. Process-wide, set once. +void reportMissingProfiles() { + static const bool Reported = [] { + if (cl::Option *Option = + cl::getRegisteredOptions().lookup("pgo-warn-missing-function")) + Option->addOccurrence(0, "pgo-warn-missing-function", "true"); + return true; + }(); + (void)Reported; +} + +// Functions of `M` that the profile annotated with counts. +uint64_t annotatedFunctions(const Module &M) { + uint64_t Count = 0; + for (const Function &F : M) { + if (F.isDeclaration()) + continue; + std::optional Entry = F.getEntryCount(); + if (Entry && !Entry->isSynthetic()) + ++Count; + } + return Count; +} + +// Prints the profile match as the successful emit's one line of JSON. +void reportProfileMatch(const ProfileMatch &Match) { + json::Object Profile{{"annotated", Match.Annotated.load()}, + {"mismatched", Match.Mismatched.load()}, + {"missing", Match.Missing.load()}, + {"unknown_partitions", Match.Unknown.load()}}; + json::Object Response{{"ok", true}, {"profile", std::move(Profile)}}; + outs() << formatv("{0}\n", json::Value(std::move(Response))); +} + // Reads the profile's header once, before any partition needs it: it must // hold IR-level counts. std::optional inspectProfile(const EmitOptions &Options) { @@ -387,9 +492,16 @@ std::optional publish(StringRef TemporaryPath, std::optional emitModule(Module &M, TargetMachine &Machine, OptimizationLevel Level, std::optional Profile, CodeGenFileType Type, - StringRef OutputPath, std::vector> &Temporaries) { + StringRef OutputPath, std::vector> &Temporaries, + ProfileMatch &Match) { + bool Annotating = Profile && Profile->Action == PGOOptions::IRUse; + if (Annotating) + M.getContext().setDiagnosticHandler( + std::make_unique(Match)); Pipeline P(Machine, Level, std::move(Profile)); P.PB.buildPerModuleDefaultPipeline(Level).run(M, P.MAM); + if (Annotating) + Match.Annotated += annotatedFunctions(M); if (std::optional Failure = verify(M, "post_optimization_verification_failed")) return Failure; @@ -555,20 +667,32 @@ std::optional compileOptimizedPartitions(const EmitOptions &Options, const PartitionPlan &Plan, OptimizationLevel Level, StringRef Salt, const ArtifactCache &Cache, - std::vector> &Objects) { + std::vector> &Objects, + ProfileMatch &Match) { size_t Count = Plan.Modules.size(); + bool Annotating = !Options.ProfileUse.empty(); std::vector> Summaries(Count); SharedFailure Failures; forEachPartition(Count, [&](size_t I) { std::string Key = hashParts({Salt, "summary", Plan.Modules[I]}); - if ((Summaries[I] = Cache.lookup(Key, "bc"))) + if ((Summaries[I] = Cache.lookup(Key, "bc"))) { + if (Annotating) { + std::unique_ptr Counts = Cache.lookup(Key, "match"); + if (!Counts || !Match.deserialize(Counts->getBuffer())) + ++Match.Unknown; + } return; + } std::string LookupError; std::unique_ptr Machine = createTargetMachine(Options.Target, Options.OptLevel, LookupError); if (!Machine) return Failures.set({"target_machine_failed", LookupError}); LLVMContext Context; + ProfileMatch PartitionMatch; + if (Annotating) + Context.setDiagnosticHandler( + std::make_unique(PartitionMatch)); Expected> Loaded = loadPartition(Options, Plan.Modules[I], I, Context, *Machine); if (!Loaded) @@ -598,6 +722,12 @@ compileOptimizedPartitions(const EmitOptions &Options, /*EmitModuleHash=*/true)); MPM.run(Mod, P.MAM); } + if (Annotating) { + PartitionMatch.Annotated += annotatedFunctions(Mod); + Match.add(PartitionMatch); + // Stored before the summary, so a reused summary finds its counts. + Cache.store(Key, "match", PartitionMatch.serialize()); + } StringRef Contents(Bitcode.data(), Bitcode.size()); Cache.store(Key, "bc", Contents); Summaries[I] = MemoryBuffer::getMemBufferCopy(Contents); @@ -744,7 +874,8 @@ compileOptimizedPartitions(const EmitOptions &Options, std::optional compilePartitions(const EmitOptions &Options, const PartitionPlan &Plan, - std::vector> &Objects) { + std::vector> &Objects, + ProfileMatch &Match) { // Everything besides a partition's own bytes that determines its // artifacts. The caller's cache directory already identifies the exact // helper build; source content and partition count arrive per module. @@ -778,7 +909,7 @@ compilePartitions(const EmitOptions &Options, const PartitionPlan &Plan, return compileUnoptimizedPartitions(Options, Plan, Salt, Cache, Objects); return compileOptimizedPartitions(Options, Plan, optimizationLevel(Options.OptLevel), Salt, - Cache, Objects); + Cache, Objects, Match); } // Publishes in-memory partition objects through private sibling files. @@ -819,6 +950,8 @@ int emitPartitions(const EmitOptions &Options) { std::vector> Objects; std::optional Failure; bool Compiled = false; + // A failed attempt's counts are discarded with its objects. + auto Match = std::make_unique(); { ErrorOr> Input = MemoryBuffer::getFile(Options.Input, /*IsText=*/false, @@ -830,15 +963,16 @@ int emitPartitions(const EmitOptions &Options) { Input->reset(); PartitionPlan Plan{std::move(Text->Sources), std::move(Text->PublicSymbols)}; - Compiled = !compilePartitions(Options, Plan, Objects); + Compiled = !compilePartitions(Options, Plan, Objects, *Match); } } } if (!Compiled) { + Match = std::make_unique(); PartitionPlan Plan; Failure = splitParsedModule(Options, Plan); if (!Failure) - Failure = compilePartitions(Options, Plan, Objects); + Failure = compilePartitions(Options, Plan, Objects, *Match); } std::vector> Temporaries; if (!Failure) @@ -851,6 +985,8 @@ int emitPartitions(const EmitOptions &Options) { return reportError(Failure->Code, Failure->Message, Options.DiagnosticFormat); } + if (!Options.ProfileUse.empty()) + reportProfileMatch(*Match); return 0; } @@ -895,6 +1031,8 @@ int emit(const EmitOptions &Options) { return reportError("invalid_import", "runtime bitcode import requires an optimized build", Options.DiagnosticFormat); + if (!Options.ProfileUse.empty()) + reportMissingProfiles(); if (std::optional Failure = inspectProfile(Options)) return reportError(Failure->Code, Failure->Message, Options.DiagnosticFormat); @@ -957,9 +1095,10 @@ int emit(const EmitOptions &Options) { ? CodeGenFileType::ObjectFile : CodeGenFileType::AssemblyFile; std::vector> Temporaries; + ProfileMatch Match; std::optional Failure = emitModule(*Mod, *Machine, Level, profileOptions(Options), Type, - Options.Outputs[0], Temporaries); + Options.Outputs[0], Temporaries, Match); if (!Failure) Failure = publish(Temporaries[0], Options.Outputs[0]); if (Failure) { @@ -968,6 +1107,8 @@ int emit(const EmitOptions &Options) { return reportError(Failure->Code, Failure->Message, Options.DiagnosticFormat); } + if (!Options.ProfileUse.empty()) + reportProfileMatch(Match); return 0; } diff --git a/packages/compiler/src/backend/native-codegen.ts b/packages/compiler/src/backend/native-codegen.ts index 5b91c60e7..413fb7e02 100644 --- a/packages/compiler/src/backend/native-codegen.ts +++ b/packages/compiler/src/backend/native-codegen.ts @@ -30,6 +30,8 @@ import { compilerReleaseVersion } from "../library/sidecar.js"; import { nativeProfileHelperArgs, nativeProfileKey, + parseNativeProfileMatch, + type NativeProfileMatch, type NativeProfileOptions, } from "./native-profile.js"; import { writeTextParts } from "../text-parts.js"; @@ -69,6 +71,8 @@ export interface NativeCodegenArtifact { dependencies: NativeArtifactDependency[]; /** Every emitted file, starting with the requested output path. */ outputPaths: string[]; + /** How the build's profile matched, when it used one and the helper ran. */ + profileMatch?: NativeProfileMatch; } const resolvedHelperCache = new Map>(); @@ -458,7 +462,7 @@ export async function emitNativeArtifact( try { if (isLlvmFile(options.llvm)) await copyFile(options.llvm.file, input); else await writeLlvmSource(input, options.llvm, 0o600); - await invoke(helper.binaryPath, [ + const { stdout } = await invoke(helper.binaryPath, [ "emit", "--input", input, @@ -502,7 +506,9 @@ export async function emitNativeArtifact( for (let index = 0; index < stages.length; index++) await rename(stages[index]!, outputs[index]!); await pruneBuildCache(root); - return artifact; + const profileMatch = + options.profile?.use === undefined ? null : parseNativeProfileMatch(stdout); + return profileMatch === null ? artifact : { ...artifact, profileMatch }; } finally { await Promise.all([ ...stages.map((stage) => rm(stage, { force: true }).catch(() => undefined)), diff --git a/packages/compiler/src/backend/native-profile.test.ts b/packages/compiler/src/backend/native-profile.test.ts index 590c39eef..b2cb0c75d 100644 --- a/packages/compiler/src/backend/native-profile.test.ts +++ b/packages/compiler/src/backend/native-profile.test.ts @@ -1,6 +1,7 @@ import { expect, test } from "vitest"; import { executableLinkInputs } from "./link-plan-core.js"; import { + parseNativeProfileMatch, nativeProfileHelperArgs, nativeProfileKey, nativeProfileRefusal, @@ -71,3 +72,15 @@ test("only the instrumented link adds the profile runtime", () => { "-fprofile-generate", ); }); + +test("the helper's profile match is read from its output", () => { + expect( + parseNativeProfileMatch( + '{"ok":true,"profile":{"annotated":120,"mismatched":7,"missing":40,"unknown_partitions":1}}\n', + ), + ).toEqual({ annotated: 120, mismatched: 7, missing: 40, unknownPartitions: 1 }); + // A helper that predates the report prints nothing. + expect(parseNativeProfileMatch("")).toBeNull(); + expect(parseNativeProfileMatch('{"ok":true}\n')).toBeNull(); + expect(parseNativeProfileMatch('{"ok":true,"profile":{"annotated":-1}}\n')).toBeNull(); +}); diff --git a/packages/compiler/src/backend/native-profile.ts b/packages/compiler/src/backend/native-profile.ts index 4cd766319..904994a7d 100644 --- a/packages/compiler/src/backend/native-profile.ts +++ b/packages/compiler/src/backend/native-profile.ts @@ -44,6 +44,45 @@ export function nativeProfileHelperArgs(profile: NativeProfileOptions | undefine return []; } +/** How an optimized build's profile matched the program's functions, as the + * helper reports it: functions that took the profile's counts, functions + * whose control flow changed since the profile was collected, functions the + * profile has no record of (new, or never run while it was collected), and + * partitions reused from the cache without their counts. */ +export interface NativeProfileMatch { + annotated: number; + mismatched: number; + missing: number; + unknownPartitions: number; +} + +/** The profile match in a successful helper emit's output, or null when the + * helper reports none (a helper that predates the report). */ +export function parseNativeProfileMatch(stdout: string): NativeProfileMatch | null { + for (const line of stdout.split("\n")) { + let parsed: unknown; + try { + parsed = JSON.parse(line); + } catch { + continue; + } + const profile = (parsed as { profile?: Record } | null)?.profile; + if (typeof profile !== "object" || profile === null) continue; + const count = (key: string): number | null => { + const value = profile[key]; + return typeof value === "number" && Number.isInteger(value) && value >= 0 ? value : null; + }; + const annotated = count("annotated"); + const mismatched = count("mismatched"); + const missing = count("missing"); + const unknownPartitions = count("unknown_partitions"); + if (annotated === null || mismatched === null || missing === null || unknownPartitions === null) + continue; + return { annotated, mismatched, missing, unknownPartitions }; + } + return null; +} + /** Cache-key part; empty without a profile so other keys are unchanged. */ export function nativeProfileKey(profile: NativeProfileOptions | undefined): string { if (profile?.generate !== undefined) return `profile-generate:${profile.generate}`; diff --git a/packages/compiler/src/compile-types.ts b/packages/compiler/src/compile-types.ts index c50931c6a..2a5cea5ea 100644 --- a/packages/compiler/src/compile-types.ts +++ b/packages/compiler/src/compile-types.ts @@ -2,6 +2,7 @@ import type { TargetCpu } from "./backend/target-cpu.js"; import type { WindowsSubsystem } from "./backend/targets.js"; import type { NativeLinkInfo } from "./backend/native-link-info.js"; import type { NativeOptimization } from "./backend/optimization.js"; +import type { NativeProfileMatch } from "./backend/native-profile.js"; import type { ScrDiagnostic } from "./diagnostics/diagnostic.js"; import type { CoverageInput } from "./coverage/report.js"; import type { TierMode } from "./frontend/tier-analysis.js"; @@ -100,6 +101,8 @@ export type CompileArtifact = path: string; translationUnitPath: string; backend: "llvm"; + /** How a `profileUse` build's profile matched the program's functions. */ + profileMatch?: NativeProfileMatch; }; export type CompileFailure = { diff --git a/packages/compiler/src/index.ts b/packages/compiler/src/index.ts index e2d1c97cc..607298427 100644 --- a/packages/compiler/src/index.ts +++ b/packages/compiler/src/index.ts @@ -94,6 +94,7 @@ import { createNativeLinkPlan } from "./backend/link-plan.js"; import { nativeProfileKey, nativeProfileRefusal, + type NativeProfileMatch, type NativeProfileOptions, } from "./backend/native-profile.js"; import { @@ -659,6 +660,7 @@ interface NativeProgramObject { partitionPaths: string[]; artifactPath: string; dependencies: NativeArtifactDependency[]; + profileMatch?: NativeProfileMatch; } async function emitNativeProgramObject( @@ -694,6 +696,7 @@ async function emitNativeProgramObject( partitionPaths: artifact.outputPaths.slice(1), artifactPath, dependencies: artifact.dependencies, + ...(artifact.profileMatch === undefined ? {} : { profileMatch: artifact.profileMatch }), }; } catch (error) { await removeNativeProgramObject(linkPath, nativePartitionPaths(linkPath, partitions)); @@ -1851,6 +1854,7 @@ async function compileTracked( } await pruneBuildCache(cacheRoot); timing("complete"); + const profileMatch = nativeProgramObject?.profileMatch; return { ok: true, artifact: { @@ -1858,6 +1862,7 @@ async function compileTracked( path: opts.outPath, translationUnitPath: llvmPath, backend, + ...(profileMatch === undefined ? {} : { profileMatch }), }, binaryPath: opts.outPath, llvmPath, diff --git a/scripts/build-native-cli.mts b/scripts/build-native-cli.mts index e539cea1d..30e0ae39b 100644 --- a/scripts/build-native-cli.mts +++ b/scripts/build-native-cli.mts @@ -20,6 +20,12 @@ const sanitize = process.env["SCRIPTC_SAN"] === "1"; // SCRIPTC_NATIVE_PROFILE_USE names; an empty SCRIPTC_NATIVE_PROFILE_USE // builds without one. const profileGenerate = process.env["SCRIPTC_NATIVE_PROFILE_GENERATE"] || undefined; +// Below this share of matching functions, the build warns that the profile +// has lost most of its gain. A profile refreshed on the same commit matched +// 92.7% of the native compiler's profiled functions, one refreshed 1.5 days +// and about 200 commits earlier 87.2%, and that one kept about half of the +// fresh profile's gain on a cold tsc-ts build. +const PROFILE_MATCH_WARNING = 0.9; const committedProfile = join(root, "packages/compiler/native/cli.profdata.gz"); const requestedProfile = process.env["SCRIPTC_NATIVE_PROFILE_USE"]; const useProfile = @@ -127,6 +133,25 @@ if (!result.ok) ) .join("\n"), ); +// How well the profile still describes the compiler: a function whose +// control flow changed since the profile was collected is optimized as +// without one. The share falls as compiler code changes, and with it the +// profile's gain (refresh it with scripts/refresh-cli-profile.mjs). +const match = useProfile && "artifact" in result ? result.artifact.profileMatch : undefined; +if (match !== undefined) { + const profiled = match.annotated + match.mismatched; + const share = profiled === 0 ? 0 : match.annotated / profiled; + console.log( + `native compiler profile: ${match.annotated} of ${profiled} profiled functions match (${(100 * share).toFixed(1)}%); ${match.missing} functions have no profile` + + (match.unknownPartitions > 0 + ? `; ${match.unknownPartitions} partitions reused without counts` + : ""), + ); + if (match.unknownPartitions === 0 && share < PROFILE_MATCH_WARNING) + console.warn( + `warning: the native compiler profile matches ${(100 * share).toFixed(1)}% of the functions it describes; run scripts/refresh-cli-profile.mjs`, + ); +} const compilerVersion = ( JSON.parse(readFileSync(join(root, "packages/compiler/package.json"), "utf8")) as { version: string; From c09385c7ab1cbd6fd10409d3afb9158cd9e65cc8 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 11:29:56 -0500 Subject: [PATCH 106/259] Emit function bodies on up to eight workers The native compiler forked four worker processes to emit the function bodies of a large module. It now forks one per available core, up to eight. SCRIPTC_EMIT_WORKERS still sets the count. The output is the same text at any count. --- packages/compiler/src/native/prepare.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/compiler/src/native/prepare.ts b/packages/compiler/src/native/prepare.ts index 67a4b5a9e..2efc3e4d7 100644 --- a/packages/compiler/src/native/prepare.ts +++ b/packages/compiler/src/native/prepare.ts @@ -2,6 +2,7 @@ import { targetCpuField, targetCpuTargetRefusal } from "../backend/target-cpu.js import { nativeCodegenDiag, type ScrDiagnostic } from "../diagnostics/diagnostic.js"; import type { CompilationTiming } from "../timing.js"; import { readFileSync } from "node:fs"; +import { availableParallelism } from "node:os"; import { basename, dirname, join, resolve } from "node:path"; import type { CompileFailure, @@ -546,10 +547,12 @@ export function prepareNativeLibrary( return input; } -/** Worker processes that emit function bodies at a time - * (SCRIPTC_EMIT_WORKERS; 0 or 1 emits in this process). */ +/** Worker processes that emit function bodies at a time: up to eight, one + * per available core (SCRIPTC_EMIT_WORKERS sets the count; 0 or 1 emits in + * this process). */ function emitWorkers(): number { - const value = Number(process.env["SCRIPTC_EMIT_WORKERS"] ?? "4"); + const configured = process.env["SCRIPTC_EMIT_WORKERS"]; + const value = configured === undefined ? Math.min(8, availableParallelism()) : Number(configured); return Number.isFinite(value) && value > 1 ? Math.floor(value) : 1; } From 557daa3e9d1f134ba9b2d81ce98de444f050f203 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 11:47:19 -0500 Subject: [PATCH 107/259] Refresh the native compiler's optimization profile The committed profile was collected before about 200 commits that changed 12,800 lines of the compiler. Functions whose control flow changed since are optimized as without a profile, so its gain had mostly gone: a cold tsc-ts speed build was 2.7% faster with it than with no profile, against 5% to 6% with a fresh one. Regenerated with scripts/refresh-cli-profile.mjs on this commit. --- packages/compiler/native/cli.profdata.gz | Bin 1701590 -> 1751358 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/packages/compiler/native/cli.profdata.gz b/packages/compiler/native/cli.profdata.gz index b5f1e079f522bd1acd58a9d574272a2e272a8f2a..31423fa043e0a12aba496a4ae1604d79da4773ef 100644 GIT binary patch literal 1751358 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 z%0D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 FZb9Q_mW0nQa`|zjX^=^02Ug?S~ME+oD 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

OaGw0X0$FmR5F_ACy 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≫={Tk{t(BZD7H!-XU6b4sPhqL$hdLS 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

oV{Ezg6C?D0&7e{@no9S+X1r++~X_7tF)g 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 T#+&My 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%0Dpv=6^sL;#aedv%=`Sz5;aoy8)F1fLkt61I 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

  • K7I{Rt0Ez+YPt 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%0A=z%r)FY!#;I7012uh!8fi}Z@m};c#wAb0 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
    uNBT8?bFx0Z7{W<3l}8j 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

    9C(vwyz$$*DzRy#7SAv(4y4p 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 z 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

    ?@cb#d=SP$whOLZR~aTb;Ya%6ZOUE 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�AB~4Eg1-OKvnr9Y;Q&bum%*bh5 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 z zrzY3`iwFQ-{D*UT73=(_dD<`Qu-Z24GyD~ea?{sL6zYD+Bf^E$4eYCu5ZN6Dy(HAj z1>K(2#)?v6rKepS=Id5G_Rv6!(xXgs8T`WwqNAOy zgHyq3?AVR)Jq;-F&Lg7>DP>zHdD&{JE$ZBp48PR=hZh1$&fL1C71Tmn>gg50JdX{* zHvd#VfuS8-%ddO6IPWR++AJse;W>1u;=-)*jk*dvWc+m&Wa$zF^%A=%eWRBcPF@C* zu-UeUY!}D(%=*igQDUU1L`Xv1#LGvMRIM!yf#FmAg2-(^##!aH(vTquz{89j>$`95 z=W{9H?r+=?UuRB|QGx}i?19eqip@m!u_4DPbG$33*ec{6UsU(q?g@vqiSxASdiSsf z<+z#UX>rHc+dL3hf41wN^nn_03cMF#9;{Y8EwFkC@7(QmQV5F`yKF z7h*+R(jnmPEB?y-nlBD^S>3P;7y?eDlf3^ur`i2nxD3fewA10sN7z=pX~9xO7Pp`5 z65vt^ni^63S56TI{_r~=+Y`F}l3bxK)o6Jk5tA?nlTJU6A94Bv5XJZQg4+G+2<8&f zxk)eiWZ1g`3G754NBcZ<>~==iLEKrt7CJE07|50749=8-bZ@joJ5T#Dw<0Mqx(mtA zzn>Wx@4dzvQ65!l)XkZjLxp)TY;5aOX@mkGOnx#ukJs|m=}-L0_hgC*cqQ-vmL9Wn zZ7p#c({4YcqeY^D3NWxOCuWaf$0C*1@PR`rXOA;%G@S?i{y zWbys6{)d@7wQ6?&H#<%|Vb8(TQqUQFdEenhT?w$Ay}&70dC4Py-0G-VYvJJEG^D9Rs{@QR-irVQ&km*7XJ>pm5 zxK(@a#`IYy*(G1^k2ck(fI4?Bb24`my5F<>0)xm?#oK3L-cz)doa;jiFtbsmjg{;l z^oQPFxv3Y459->MJu0k##LBJfWND>K4{mr<;uRIT5w279WnJ`^z7E9Ey?0Q?8?n1= zjYBB)(#&(Agc7*@FNZTSHdH%G^ys{7<6_=D!bSB}xIbu#WFJsw1hlyFw0ba)3~|-@ zmB@Xg*Hi>#%8I8ESe2auM7%rkx@nKY+E(!gi{VU;v{xy42*IZyqv$otVW zo+bt5a`7qS*^hcCy${s*>xu2Qea{jZr(TmDzFkneq_!ex3o*~L(3FJ_?}N4scd;5T zmIkL4iT@?Xp=jj?nulQFpJLRz4gd7ne46mGZTJ{^4=PGFa9 z{nX~LwyWU8E$$c`8}vCYuP(L>c=#=AtgPvNi;iUcjYYi%q+^B6*DCdnKPOs8Ctxq) z1@AY~T@paZ^U>_!X+(>0Dfzt3 zuhc6~zWF+Y`>V|}ZqHoiBidtLjuX>c&8*!gCX!h6ykn-r7vatpASijtaK3y!pa0ah zo!u|S6L)c*+DfBzKc*ExYq!TgjYpxcJ>e$~zU7Se=kqV_1_bV9I@GqeNS?T&t{lUX zt{2p+6m4Y9O>>rT)1r?R!_DdFpneUh0ch--lcApSsP*G z)m?^RJ7h4c5ML~NqdUhvp`f^cN{kI&XPxrgQGk-a#J&&CXru>)s3avBqAHR&?q9RqNYg+jSK=JmT8 zA03+XvnP~Pz5<8|(hVA`&R(lcdKHN}0h&0Nf9nYd^0<9rmyc`M?GDmIw}LTpmuRE} ziQPJl(E0Q()>b+DIb_d(i(S;GLDRxylJmdq5%~z(fk(ksQ=FKs;|${fu9F!P*7(cs zruU@mu0cP(Hqe68f4U

    *P@Y`qcO~;T+SwX8 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 TUH4=%HTny2dXYb>e(C%lSAWI3 literal 1701590 zcmYhiQ*@?Xw5?llDo!f4Z5x$*v2EM7Q?XsKZQHhO+vd0HU#p$H&wKIS%$s>JM{B)5 zy$^y&=pX-mpkSALZkfM^UOF-^f(r)lx=13d8CFjN@d1J&NCPQjI)tgX5;63-g!!ep zxw-y^Ct?bht5oQ;VY!s~t6%x0>PQf1Up~KGujvz|$De|HfYPQMJa)%Z85}oV9xM+z z6{{BxoHbMAvLF(KjCU12L~r{w2qA|h8E>d8JG0V$bO^;;*EXKiU9%pges7PbD~DVG zi%U*08ThZ&ILP+`>hVpmK|RHY{En`KGVD1oW6fETUZgLUXyOf%CwjC}+{wo?IxB>6 z$7wSsM-Wzj6+idO2rAz?zkJF{=3$F3c~o+@yt|vU-pd-tx_wHhZ)poh3b0D%YhJqD zsdb=fsKKr5ABXr$=3Uquz8S!&yo3e_@zx;)D16hL$~_0|{c5{UTA=w$w2m?*ciPzg z-mnt?jp<^1{cO>933nlYSdjaG%&}vsaB$bC{cYH@`!Ia`ka$q4bOtzfYVZ{CZJ)Yy zk7%{L&0mtB7q9CxJzuy=AF$1thH(wusD{lKRy5CcoxPk3@*tBM$!YB4cObE#6(=EF zAVbDUKDl|{-`0NksS~ns@)Ahps)~XdkjxdXWGs}#MSXHP2R7`JCe(Mm6f|{R$Hoj3 zAx@4h=kqkG1~gQ#kLabO9dKxrW+A32pnOlGg=DM}C%45-Zn=Dw%Q8srKU3Rx_1tuA zIe+pjUh@d;2TvykQFVW9s#`GgX(>vIB;s|WSE!N~&1T)Nu|u38a2A%r^#E5uB}+L{ z*G=#s>jaYy!H(&R6UEJ`;B74Zby$6E5#K7c2rsHi3RvVk`-s&!f&X|kU&lGd@S2K; zv~b43iU5J&WK4|nRzO*QCOjm56J;_VAvsd~`!bW}H|n1hp>QK|5zw3}*d02PT=;sf zHRoAqa4s~Qi=iiTMPbw!JD8N1hMVrUA&rrK=0jdG!}O5Tf>7LI{O7wSE6r0T+@~ll zCw%q-y+O}0&T~@ezAMhNQ~ZxF$Fy}EMwuQ%Vb>J$JG<~U1L-*js{ZNx@}!>0^9Y(q zDX$#hlnrN~h7ym0_;nQX@mgi(?4yXT+ZCVqLbdB9G0!J$llYO3+lfu^UVh-qb0CLc z`*YZubF%jS@W;LWk9%FA`xC-9RdIgAv6iTKv2-==X(HC>csmr59nL;)Vba*~4r|h! z;4$HMiqvNlZl?WAhw2p}-PUVG*_I!?1y~5GN-6+tU;RSwy?1Ard&^KvCr$2n$Dqu~xJ=7mo)yFWO_q&po61w|%*kg-0q0FyYJGz;-= z=!=~R{pY%*(3v`JW&AsY6!utZoL|A&C_pm)Sg)vG(q5i^2hkk}Hxg-)3XE}Y3Fbja zH|^NiyYR?D2z$sZI{u8?8h;%EHo8}zrqzH!)ZQ=5Od8~5Xvmz#!FgN~kif5(otYamxGDdkfNB{gcEGRw zf_!0{R6T+wbIm<<(K&x|EKtoyD|M$LsyXxXHNnqZ8sB%y{Y%-Mq23*}m4KO(JA@zY zQcvZ+B_lfWt%gQG$B^6dkCs1$d#~xp7;N4a7cLB9b`j&$+$Xy(LwyA@XU9WqMPzed z#x>K=`OYF7PiM~(3zxVwxQiS78C^%$g{;Q&b`c7o`zq+;<#A$_b{{g4J1p(Q53bN` z7TeeN(qP*{_;x!M?~kW992At2x?RPFNrF8CT=$yDRx7$knx5>=LiF$@QoRsV3xWxFyi=0W9dl$1 z5ZZCG4(Zl^iq+!tsDwoP{Ls?ecS72UH;}trufA)Ia6Yj+dnp@@A44WgC_8m`)v|0mFn$Dsz>I(iCG@$Y&Q@6i(E#4Pt<*~>R!_w0l_*894SEZ1dxfSkyG=)JSX-L5$z#a%Cq5SVn zFfQF>!h~RaWC5nrN;btpI}X`4@4tf1W-Yp)_uyM2AQu1*_XrZsB^Is)$~SfbO|%RZ(XX5-zf1mj83=t`y8nz-LS;J5*a(;ht_{MN%QJIOCdhI?Htb^ zkd40Z#W`Y=yfsoY_Z#qFlfUY$tzOA`SGCDaYR>-@XaP4G169%t&|!2}kjIj7uxCDx z)is2b8Hj%(ZI<(PSPtfs6ec5qfl){Rse(m8B0Db1(Cf4hFq2*{1joUY3K$jR#^;Dz z1BU>erfI;o}D|r>EmN?Mi zkNwDbgYPwX5chkMlGB!c`qo5krLYoUS)cSseI!1T;`>Y6R55T%hn(2+mjJNAbPtwg zlF-J`vy~Udl8aV&<3R_^wDqccYqm80gHGyP}(dFS+5 zz91}jY&sz*8W;SCGcwcV-bGp{eP5^yO<@0oVQ=Zadkng~mt}Ao`v7~ffRHQJYUe;d z*!qO2UZ(5P95LfD?RAPv0k28 zhzNApc`bs=cKV+!ifbhaM%8j?$w4QvM1!@%PHr*nu;pe$RC_Wfm}ITL*Hz#TrcR4Hz8b>Cr87`oI^4#vT~KZ&{I%y%0~StvrrS`1r%vSq}@#ESvOl z5RqWpd;7*tw873qx5PvtSwkgR{-YU<9G+mx-~GHCZ9H0xL}a`ju13f75>QUyo>e}< z^=lPYg#erC0y~nX-QRsLAx*<-doY4OI}ad%0?0-b=T8R!^eX<=n==btnnlJ;S>ei3 zD4}v~$@XL=u3d-~SJKE4InP0b1`%ujVKnd0wt^D!P{Up8AzA<(5Jw1#Z~L`4D&T9) z!NUW=qBR7&6>sP8xlhdR@j31VupYwT?f-g8$l1&=quYEei7xcBj-=q@FbkIZ4~akTIYhfp z`ob;7x`&RFeblfM43xYwl}P27F}j0QhZEwr7PuOo*q;LGp7YW0`soLR0e!N%qY4i& z{MA}My5KNgr=bokOjT3#yW#K*pxw5I!pkTpD~NsO57IQY*)+ewf2V=dfn8$$h*V*f8MttC!oeN*vLP*rjHlF4F4U;o<{d`}sM+s>a65 z8GGh6=+!f#+xKRVOtG=AKtsYW@avE7zurL1qoo$IoAMBmkAf%`bQCX)(Hb{}y-sQh zF~uP?Cy&g?#==Y2i#Bc}^JgxOsO1YQ(&6Xvo}cQOr35dCYWd zjv4L59;~ur#KIR`!>COjKhwLFGi7g@q3!w;d3KY+h9l|vlNMM-eKZX@6{6Xx_}-!OOPg>k5{$>ui_3K0gvS()S(8vel=D~f3 z;=Sh`(xf_qY_M;}(}q?ZW8@oJ^cXFaZ~?C1zV!>asS7dz)r`OFKP}^%yWcpUf@EbX zjoEeGBw)`UFLGO^`Cs?v7szcCl!lbT=Ksqe0;4|dW>ZEobq)U1jX zu{1~)nT$uk_D9p8&B?mUx27DdLu~;|INn@gpR^#?en=&{J|@N1(kiMDX_&a4h$@6R zD?~$%xPQ6onkaK9)R%vm0{aO~!qL8+m@)ww-EQMYVo2h#F0ql;vlPV(J4}hM2Nhwk zO}}~;w$<&99NhVi*^XF2?i4dJ2Qk(hKMZP_ZI2QGUjgQ7R`(p)5IxeX&vhNea+DTO z)S}Ez7t3s{3pwE5x-oa7F*3kQLDO6^w3QZl}3%i=I(r6kI`jfY+7L(HY)!Cs5Be}^5U zvU6*3-PfxE*U2EjQtU$wgj#EhV9OFAf=FC$98Nin+mUA7xYsOUr{Vs?@H3eymE1DF z95XQJh^qs{+qcF{bi2`}VpRsmS|UuY&I(SCBzuN{!rgOc%r84s#X=&O1%zb6HFUuS z&f!ByNKoUhHQ;8{%;$Q&?M3h$0=kE7q;+IETo&6MHb~SX?8!kxJZ>!MRn7Z*n z={M$P$hYsJ?tB1Qg4-uGo$9ioh$PMQ?WA^7MP-psbY(PxZ}-kTDaWtgI& zGc1(hjT&#V-g{4jwta!+=4lxNnwM z_~o5D`;`}e^ETE}cC|Yvq;u2z+DE-O!!MC6BimM$W9sD_#9k@qjCsttui5QVHsg#%KM!`FHDuc@HaN$7D<#Qem(^C6|k+cEj$^ ziqfu1QXgRnESyrLzulW~EIt;`AuP(fRF0@}xQHDjZNCMbAzrG6xQLoD1`R8t+4|y2wzw#SLXXZ+$228u=s(8c{3r=SG)E_rw9F};d-w9$G zd`c!T0~j&6t^!Ggix9?3%mwi2w{#nVUTL0YvL6V-kd{>0585i0}jX)<28pQ9jeqNLM-3ujNDf$y{8Tn!&<`LLK7PvdWLdJ`)Ozk zD0%6i5J>inSy`Vt3TILAr0tM5#dNlLIDbHXh;jaD4of!isw*>%L?Jr=?YrM5&U|>LmI6j2ajR@&!`S|tZk0lS#4%nvtJRDo zux00iIahunN{Rk}*nEfh`E%QJLkYHyrw~mxmu))FB7ZWUr_ie~L@Mw!;n`+CwP_|= zj~xs00)9F?w;;07qqA%V3Y2G;0%YsP>;CJ~Ce+uxyRXG~%3Zet2RqZi{bxm&3wC{# zZ~glL+%-jg_6)^Sa!z^0j%9~;eaNs*{sGf=a#JSfTWS8Q(cVOvX?NA7`%Lq2EJO*B z4xKM2U*6=!D}n=X1&qG)b%b*T9u4FNLTx5x1j@N)mQi+dW38RB@eNW2!+dwT4(?MS zf6yF+rYeL6nuxQQIb<`MS9ps60Vf#{^V{7~G~NV&%oTnNt^v1k**VMW=>vIu-Owcx z>D$JVgM-m@oluU|NIw?R7o5fXH}omcTM*aJec@_|sz?l9q+40$kZjF9EFb#N>U!G4 zU}*p;U{l&-~ zq0RxS+J$Vx+^1m9F85;1Nhm)M0AEbk9_;wkL7oMp3t!wk5%je&pgnDAiXYnqtpRD3 zvfEtD!F<7?V}z$Ilid9g_xJDJfY-t8iq#!!Ni8u$81D!p3`yR-nbZd1RcOiX;9$w% zpv1v*)bn8L6?bjP()14va6vRS3H0NwV?U3tZxitA=8L?a=he4Bw6E%X;E3G|pEz#o zNg2rr5TT@YYHEP;V2*q(VB^LGG)HHbRLG4nf0|`pqiguZ_b#4yL$`szw=}o^!3Um7 zQXn%A1}m8muRK!L4EyV#$cwh!+YSpQIp51ARc+<<9V$|fwzd}(mbP}caY2l>HkV#d zWsPk4wG^*iOFsYtJ@Z<=8SWP1PHL{WrNwb}jgPZm=nw7G8rX;}*o|^Y2jLDET9on@ zMDE!%mN0V$tt6C7WBiz^Kn`+T)Yw6GiT=0RTn9Y005nic+q*Bhs>d7xV>LEZZ&zh7 zGGFKAN6q!3wtmz(H3;I-mS4h}XJa2M<`Ht0z-E_YVp?;!l11Q&&;Sj+s#f;k_Ycp57=^iXB`L{*pGefrdg9y%oi53(%O9ZF;BIKK_=o=GT*b1o zqFhq5Fu2P$;8(R}45C~CAOOun_E00nWT;kZR5gQVa;AS9<__#mS@R;9$1jKj7ahew z3FSCDMG49QwSxOpZQuDV>$=xtY2u~m64-uZrg1BhpDY%1=2~wlA&e}5a&!3o{IL|B z#~5y(B#t~l?OL)iQ|HsA>oQE)GXm=!)NS#}n$^LF6++q;-YtrAeB0c%_f z(JXi#AiRI2o3f-4d_)>Ehsrv6lVQB+L)-IffZX2!coEv86_SdofDQpbatAiq!w2^E^ij3i!4(^xE?A9PT71SLxE>AE=%DPJHN%~aGfw97AK zy;@&AH_?!%5Xdz>vUi7|{PepcpV}V-WP+)3_N%jnoR{B2RW^g0|L=yX64&c5pKs#7 zB!Ak|E)4nCum%m&+Hs-4BM_Ab(@yIXIg7J2IJ6#tmMMjN`h9%U!NZ`Q+?wW^9Y}E+~ zC;T)1`LADgWk?Yt8N=0DC~s;kj*8(3EqQXO#BJz>N+Z56FRfrJWFU6Cfi+FB1Yah7 z^gJGvWQ_`Sy`{ykv;0ekI^84Ec7ldfK;|@?NUn8Oty3VPDZm%;B77bs1qv8CeP)*7 zupT`LoMO+}3G{{nVnj~63}F#e;MZccs4#6??SJYilI{F*Nt!-Q;C?Rt+Srn(7_&}@`F;I9q_V4gRiu+TpjpKZKA~mHCsst1#VlSOx7K%RD4um z>|ZTEQd5`Ye;OET`j`lP5tt<}b*!v7^6W1?(3At0mvYIOL-uoN8PK= zJnE{qJXa6lk|%JFfzi;g=YPI*WbSzt%$23?yQ;Tf)irqVrj=%=t>p(Eglu9j)UAwK zmK?vPo!e5iCSH}!xxSWH;=H9Jh&ZY%O#J{dYk26&vDvUEdG03}qAtq1E3BI;a!)ZV zHn^G>R4zD%RSlaN#&f6A{_o6wtiK;C&rN3vvA?I&1*jp*mXY{L`qHy$#f^14=!81T z%LB>}ysgLP7I5sJF=c0Zs#4CCbPg)ZXEj{oOcaz(k>N1 zQD8zvb+{3-oW&c=xL`XdEGT}Fr13s4*saeY+w&OIrG?m1C_^ahVZ|5VMaxzAE{AmGm~P+ARfcA>K;$f` z>`yMLTToy(r5}Olq{I89@j?jNWp1C<@Vs>;a))0x0Lwa^pV}fKPWhzglV-6wxGNrU zaf`@Q?wWLL=Gf!{Re?_#nth(q(O!ZlaU;c-tu@KuMHAeUePHxU0?KsFun4-Tc!7D? zm2=fb7a6gv8*-1o zw3*U=KcWVtpc2``{TQi@>d!O#ffTjYwAKo;nN-O8QltJjuCdpke75W+i+&}$L)n8- z3Q+rDLn;ri;uNqO6iHwMe3=m59AjKOBl0pakz`?ZdRti`kYh)bqxMS=)gUR^IBRJD zeR-G_Z9CtYF(D^GjcG9(w?9tk=EBiC|8%E$7!zRz#ZrGm#aaYK;-oTtXG8qtIzNr4 zb(bAScwj9(3X?OUQp9qnRMTv`j!j}0IG{-7MXB6o=j=dC`NE3XGl_|Z5RJEx$W?g0 zF~?VmPeR3l05p;lY>d)QTr4elD_$evmlmXr2tY^qkW&6w_$ZUbSX{(*YrXtHWOtDW z{!A?;?2G-7N{18zUT8fhfloJQ8Tyn%M|(7F;~`uW2oOk=Zu9 zYGHH5ui`C^G_j4)0_dg**|D5666KnkB!dt`&#lZ|InzB-JhAtp>9Z+aT0RmQlKH<& z>L9mKlwtKmZ~{sDr?=7>l>z@OEd;vyfBJ+Ju1s8W<49d!NCuk|_iYF5*PBz(X-NZ2 z<#0s#?~8iU@9x&I<)Q<*^;{jk6nL4dY<=zyE7}D~!k(|@j^8zx$k*F2O*j7!WE|1j zSA3%|aGI!ad=>w~D1~h-!`Hw~&-eGzQ>BRiH2cg772pqNqfyuWCslWiB~YC40rvdiRxbEo63n4P46%gA4VO%$<|W z31RG2lzf{-3f-UGg5?Pop!tF}vHv0PnAfM@>eqD~P7e~CA2K=#+GO+Lq#+4qu`+F~M;C2- zY&2$=I0(_n$||mm?eFuw5b&An6NL-t}GO2~yd)CRaurtu_vUlDn%uGZ}5>~s&wXc!nJo%K(!w)$A8 zckvL~9`+ExO7K6TPLYFV!(B!4<>wqLsM|@~(kDh(j*kitMj&vGUt*8*jR7IZ%EE^t zTY@@CEn6AbOzW3=+GM@t6&v*&wv}NX-H+6e8@Iq*6Ulmn?+zGNOs~q5?d*iIk=ENEx|0=*~YMc z-QyV}8ikDaVAGxbh7{{s4 zx6jYV4jep3_Q5(Krh;jGF?sqcnyvjcC}nqRvG-(;MdoS?T%#H~(!z&jFCMmhgS(Gc z)9ayn^YE5NotQ(Rkc^<6?VJ=Z4Rm)4nq|cuvc6wC&bi@vh2SNt-=uEK+rUcqH9HSL z)arJUWB1%#J9J&*k$BoCR$CL*7WT~9_;_12^e%;)2&<%pWgfZB6kG^bJi>NdiQY21 z$tGa&|C_At)orC8zixm82-0#E0A&V!vT z+rbsMh{U;!P|WkyjUV}-THT|sh>n{~#iXc3S0-a}$sU^NaaUI}bAid1E_z5h)i)7B z3yPkFbJxaWLIlw zVf$*VaJ^2Y0!3WGQa>8J72sM(7jw;#P(#bZYv-bNx_Xw4vQ$^Vk`L*u0TojH(zz^P zFjjACu`wx^yka9_)601%zjiZ;;I)ljZqoY+OnbXBRWeIc4r~{dB2N>%C+V_wUFK(d-I9S8>xtNeb6p*LiJ%+x zzsYEsr;m2{dwVVxWKp6ObVjE&b@KJQ4K7${1^iB$@u4gJMWz~|*{**mZzeAV&STDC z9{6w(Xt*yqs0DuW#T^w@Q4HPPEDmD;NS*y;D3*3O1V3vquNh-FUfiB5bkcGv#$q9Q z{NR1~B5Xx9c(&U6)b}C?nVE7XP`v4gm$J)Yg$Q9`Y1CzG>J5B{li%JF-+r_jf$L^? z<`rF0pxpZQzAz zE}jYz#AtmR_0<*5{oSuZPQ%0-1>Z?jQO5TOiD61;4aV(p*?n_bgNAW#vnio28E^kR zkxp8`A1TbFuqnyE;oG;I<0cHSFa&oBHL&QwIK{7F`d=#euZJ|y1$n#e_e6Z3zG+HT z+o@ta)E+gsjwChOCRH!s>yEW>b(Hyb6sz&apFYbo4mH$51uFHcKUW4=|qz||tQ z`Yk^l@}sl2zVTEZBH-sJdS1gUPs5ho*=&$~&Kbvs5qbknU!?V2q(MtO{Fu~LbC7~I z63mQbrN~4hX}#oX^sre*-O7%E$F8fRK*s&G*2hDCu!neK^RRftV0}XV^XBU7iQa_7 zKw@TmvLD;^)(vi7F%7>b?I<9qkRyAA2aIDNK|9ndpB0jRE^sV-?~==$m(e)mTe zug%_0L}_VPk?XY{)JTQuz$w5Fx7!&1OQ2b)PtEZ5o>1MFh`m5=h41!ZLX0cFYc8Nb z{P5ck=pBSS3AjvTEjKL~ z==#xMYIZ8ld#{h+qUQ#cyt-cl`_a_c#9*d~GDXhB7kF(0WkRv+Rec!tE5{ca zX}LuJMHbgj2QxiSL(g+qvsm?G=zL^hqi^Yuo2Viv4Dmo6EzWxdFiYW~l|NRgowVQp z8~wAZq&xP)ZTlktGK1a@j=C7}=1POzxh*+l~GGti1Lo?V4eIsAaN*$X2 zcs2YtL9$AM3VIS3NeNp+}w{DqZU#Y_WbffZ%}Hu8gu8}%FgDu=adx;wylW1*G9AGtBr# z=>s z=TV*iFrCski&~N@|l zVxCvNP9{+7EmtcFXje*d_2)}i)saEOq@$+%laYXHlzWVz?(w-ip$4sK!|?9n9eaO- z99lpcQ(~BHo3>P^mi>G=YO}O*2O{}bGq-5YdWx_;J}J*i>|JA}#i6&#nAoD-(eF&qR0^!Xo^ElZPZ8{v6D6q0KcWPU;kH_nHTr@JDG@>jSl;3s2&+h+!c63wjmqy#p z3@q*w+d~LzGS&Rfb`40r(hOfPd42cnI*)3IIQH%+UkQgR^%SThFE#z>hLa(BRg-7i zEL9tQhV9`!>7v-Jv(t;)i{3Y0zkVryKm4X&I>9*vr!V-27XDROZD=emTU~c5t+^ok zZz^k-Jjb3;>!P(?7uE}F{DMA4U?y7mdw=yFB8%!@6?~TSzbP^fP}oOy125OE;CHdL z!5(feL*seD+q6F^(E2a|E#m!-E%C-1g=nykwnyVae_IBx9$T;eH8x={(;>k__B_%` z@J_h7o(E#RIIP+XR1n&g&FwI)7CS|+Uk@{EW7pdM%8`eVsCMagEd1r)v|52rGbKwq zV$*=n_3;@xg&je73lxzvHjgYsBUr3S)T&;6`#6rSE#x;@dhiT@E#=pLnQterPanmO z7~b%qpJ}|Q={ysRgs*VaKark@%nmv53C-+2YT6L^`0<^`Nf$+n(4vC|rPN{5N9mNoE_NWRgd&vm?0|W+41J#1!b8HVu+Y8CXl#gBY*VQ zBcr585Jyii8IIYHBjqy=EEpA zV5P(X+*gHDBF`kAMOmTYB3LkIQ_rOhQkLP__x_B7FLZ`e_K_*=V){ck4Q5IW-PTIJ zL$SKvZPcs5s@a###neURY2rIGy{zWXVa9N6;EZ$Wg}2_$uoU2pzb)j#r9CRq{fu2; z_(Mo>Yx9Y*CveAw+xWu4>=oqns1SLBqqmqxx7WtPVT`zu-bk^!=;E?LqjaR3oZ4LAk5$0*65~Oi)ed>JKP#$lA%|N)MIQRmyE;Qk8U+ zL~LaEEF7Md@?ouw@oel=<|0YEi8}Olz5@MHj+1c?_l%&RxhqE7f4HmuR%7!t8ZQpJ z84a+B;cYp*(mhU`+B4zV@|C+yJ$p1W|K}BZ;aa+&Q7w9TP)dhK+n}XVmR{zpC9zw5iYz zFs)7Rq-ehS{ew3(i@jb?&GNqo$KAwE!Tm6%Jso=kDjN7_=zQFwv^xQ<-u^AZoLl3; z)fO-_R-OG7>9!pHGdE9@f@dB-Q?mWy*nOT$Snl^c)uT##Q*2a3FjbX5k-REUjimvQRyXP1xhBiFfwS439SGoEFS2{*Cfy~{ zPf(LM1Pn>pT7Fac8gc56f`Q^RQFkWEas4irgm^^qQxJbKy9)S30g+zkd=|A#p zxz@lLix$AIAz55i_=)M!7++GtTl;cz{cEp|=M{Ipx^2&-_O0pLV`cway{IH?O`o#q zzO|!*;@I<(7@oj@FI#c_x+$>{5EfcUh$1z2CZy)As1rn5TshKf#+B4f{-au5t`Cc{ zl@-N`5*=+5eYjv$+D~awUe22^T7=KvqNUX?CAB$8(-1K_7d1HsL-*6*mt99yU!y?q zMb)x$ssb6Hg?(^6wK51IzY*$3#ari@#XgvH_{@V6=FQ_c<%|0os)CQ5&_o;}jZSF9Mb~Y2#SR+vc1WjQ;(H@Wk zIGW!6dMh2-2#GCcMka%G)uE%Je2jgLy7$Vu4xG?!{kL9pM`2StEKlXh%co%ZoZH^{ zBJ#n;!2xZC*h0k@vAF-w72$lO8bx@yLRxUzDPk9IHk2L8%E-3!h+UB>7&yxopb76Q zH>Ubabi_{aYRkQ0(m-Qb_IJ_{bmd_}hWH4HEI#7Nwiu*xN~FT+b2^9He0v!zz<;D7 zPZ=Rig~QGB8+!xYhAmQcGjqQpz6nZ3Sr*Y){8m5SM@xCAa2rcuD?vGzkUc1dK3+uS z1~mMORE@iMKBiLS;kV^PdnX(-iD&c6#bXrNS{*_sx`Fyismh~UU}LkW5RY$?%t=V6 z^8zd7at%WQjJi%LfK#F=bpPvVIJdHa&zFq+PocL z_&RIBT>F-)O`%dyrT=olNjEA13HIEr|FyAf8;HGLgg8q8sOY-3}b?LJ9kd zTETv8TF*4?Dk~7ylD)qSb~M!`eS>rduqp?jyNALYN&nw|+i0sDt}s5FC^%iYx5>!a z3u*WRCDqYj*o?P*@v21V?ILy=E_GZy)d8)1Yp<5L;gRA|}|$ zS&@01=SkK`!c)~&S~P@L^tswNgQ_|NXa0Ym^VWY=i02PtaaYW8rd)5ZQ<0Lzoz!J& zA?eBn+`P+AZ4L0GMunh{&yRjD{@baMtw0DZwJ$Hn8Q=9d5je$*OL38nYRfMtEJ`1j z2zQ#UI8z862zt4GE?TC`{+ySR%J-yVOEbWfP-XoI&B;&%Pm{(_TzvC-de>N3D(c_Q zX*|?-hd_8*ihK*nEZ7sqWNSUBZ>hcjJjUakBmQ0CoH~Lh&xI9Ggr(ym?z~zY=f)#O z@6Nc?34Hd##v560^-ndPBdUlRrO|PVO;hsCmtQU%)jUJC<%ktoLn}2EB zV>jRm&Pw&zLK5nA*L&<87Vfb%Px*;fwQZU@$X&EsPryk7GJMi-PcD5PtT`MJ?x|~3p6*M*zekTB(buhTV71E5vP^fkb z%sRloOI283GwV@(q>R*KWjry8Z#wZR24T2e*9mY=+Og+q%InoTWdg-fdXAdV(es7h zOY6F$wkn_`wt+coCFR&8)1v1TRD%meP>-KG&Ex=n0c6*A2%%VlS6GuM>=dCr7)t0j zSU;|QD%DwONA>@#EM!EP5Qm$HD0O)#X&ZjBMVBpT52QY}9`N)I-ANmE%p9HQB&6!B z6gS{m08g~y?{}U>TO{c6b8d^c??+D3^EYJ;B^r&$XWqXDBRPUyDN#ZSDiFX5f*4lJ z5g62IJ?(^!rW7W+MHn`qY%hmFIrotaA2T^9&GF>>xPS`od^_Z0Mvz^hc)R~sV27dq z@#xeJU(%u9TJVN(^7Y>5^Q??qEnywa|nrN>(P-4@hEs{0_X z!)}-x04}O*9#9N+&M!Q1`qy`?vF3V^8*rJ_GPmg=Tw{eE(`Vv-#cai(_|8Y*i1 zL+1d0s*lM7r`~!pZJ5jZ<|!K@3mqIHRHih|w4BHF*o!*aGRpkP@ka57z|lJ1@dT`} z6T~6LG*4r@g9=ajKg}bnVc69~_t;1f(a4yYR-9BJ9%waOBFOZTTc`^?jf*sZS-_oo#b8!ka~2<6Bq4u-7?Q>B9_0d`UHSi8@|60T9hm z*5a?cfZl1xcG7W#;Xcr#|6A(BeJiD5Z%HV$RFN?%kwEiVLE#gvOv+a(y?$}cuC;S= zu8>EzP}m2@4}-Bp`@V)LuIc!#5EHSMrh6V!b=bQ@;TpD`)`!U*Z;Gb5LW;-O4?BR4 z>)WDjcOAPID~0;3rex=<4cOW9T9Bg}8Gfms zN^=iKGGWlJz~eMlfLVYeQ-t8>J9pb<#(}UxB57op<;yb>z7i{~p~i20jD(fGFE+z^ zzF-QK;(aH(VXiavK&y|Xu!K6y+4Q~sm?5jJA5MVH)ABE+X&H8oo+@N_gLo+6gZJUN z3C^)rBfWK;-6y#2*o5j7-b9e=-Chw8@VN3Rh(VUIT7BnNqN5(SR7;)@Dku3;SQ#HH z-97)^$-_atv7^j)VpJY6QB;m8kh}}D)Us7^<15vqUI{$ki@le$^UxcVwmcl@P{R-a z!81g5g+d(*{5PT_h*4@9(H>V5FAW_e!2;_Pj+$GH0$-1(m5uY$=Fh#ETsmf=I$`Ko zs!8Th1CH3ebRsho{bk(^WimB#8ueC$+c`t`jg%4rMFzU)WQ$Rh7RVmme=tpzNV2!L z_TwY-88S{IY#B2}SwO2u8L-z2cp<4F<4u*6o-Y{6j4fmv6VjjC0OPgPHNh{{yr@OTR2hGR<(3MAI^dj>tCV*07Eg&WC*qRrv9; z6Ve>)nCC=AVQ7}68HVL}Hc=n;E!1;6{9TTmjImV8b0Vu7hR7)ZT`KLJ5sOSqsq>ru zaebTTTSoAc7w8Tz2uMaj(ivWJh?=US?(r6wl)&WiPNF*~=|peGk5ggTS1~^9OEDN) z6da1c19m+zbLgI9#i{7r>96Iv#~)|jU%`5xU&Zx3KkkmYlltSTn>!?*#In7_v7AB+ z94qr8FNOsnG>xW=`rVa!jrE2wp~LJ0jr8KCkXmEU%s5}8|=-3^m?EPSwmCZ z8tT4^_1MXaUXcysPY{@bDlqyq<#9l#JdTG5?N z?)^G{%k!x)78nh2S!Sjxl)gw>RRmj0-T3qFBl#C~H1q2s*cLn=h}d-iuNN4BLlp)C zS26I;e1GK2mp?u?o2lc9d)pZK(-q2w#C_Bg{T5tN)H7PtFRtt-s5{=j@qdS&iQ#JGcmZ`aUX~rp)%YZ}S3q|KiY}@=;B+0R zi~k-!MY;WNvLjOVpbB1pGpLGhi~ArWavt{_1r@WYVM+|V=y&*0{Vdh(mA7|o=>h#L zkq$#*dDgD0E|;e2lLJngbKcBf{-^6ea-&L8CpE$MsR@p3l6ao7U6OpwSD&@U`wNN~ zPClgtt3@L{frY(=t8$hfEE=4K+rmB<xHFtS z&ouXFP*gnl@18|HKFiKTZ;!aYBrwptg!G7Npv$r|6rTl}@th-q{iv@KUx>fRhU4c%ugtxvNIN#i2bqg%0 z_fXYGc+|C^z#I#2os{RNJHFEun$}S{QP<0};LOyM&ouc%S?#gF0t+mt5PXx8*nCk@ ze_Bo@=O=X2WDZhJ^Ek_Gij^5!$=xK1A;*kdZ2O!>E!Fb-OBNp|U1zrwS%Wc{e4`$BzXwJ9mIq$sWtkN?juvEIP*4Qdn5T^%PR6z2Eo#F#Gp>8HQIwON zWnN$;j%8?`mcuVmTRbzkf%EETb0ea7i#qmxpDUMra!xpFlpW2*$#&K62SvrfgC-4H zS9L(^G6Q70uCeM%1K(OdVOI{iO!+)nF>y)}Z&Tyne=O(u%V40hoE~1QKulec>emZ{ z7n6+wE=PZlTUY%jKRoa2t>24|a*CZUI#c{q96F!e?0UD^62 z3KgAF;ypl=jL~25LM~Ci0bK=+wS(SP&)eIeg5Sj(T>>x6gx9#=Z8F+EjF^x2#Dddh z^=7%*0e_K^XD0~jLfp^Bx#fHd#l&;Io6y9nv*pH0ErcObZfZ>(JU6F#xe-rp$=TN z>dVQOLe`IP^tl)490EqUQ*S)m*Ra z1pn8ll6qu)hsO1+zG6M6x5b|pSYUw#7FbaKAW?l>jPZT18rG|ORdG8D%@iKu&<6QF zRyp&{)P|%3%(O4&yX&f{f79w2KjJQNg>)Q$hSH_F>3ePs*#Q<(Qx;W^uiz@i4UmBH??bZ@NMrUv;G^Mb%*)s7b!K%H+{{XyUEN$KMorIGRRCD#wbrP>)#UN zSDu1dAo;*#xV2>Hd<6MtzFDzUvs@TIbHY?C=EDD*6@19dzhR~l5^%G#W2jyN0W$I~ zGo6bBYCx}kads%vzCwo9OUE!iB+JJb#TO;dU?e{#2K_%X(}QNZ&}<;|+rjv%Jp)6( zv(|SlsEi&?5&Nih!*Bj$@00lTFIwPug^@T;RAfa7iwOPK{Gt~oB6J@$xcSd(t{4*i zFiug>c!iUtfOL)b{8EzmklJg!*r4r$rRQHaj950WIUI^08-gewzwe!^7hd^FR>LZa zuxV!TQnkXt%c8&Ud1>`5-CO-yz2Lp5cKWqcF{&fi_6R1_c7n={ssA^PmSH<1zNiDpQCGO~gQzk~15`31g*^~K32 zTzg{i5Bgng%Y*91Z^^qe3vhR%lf-`Np5sMtZfpp>)MLZ_Cq*)CcdLHqR4_vI`kjHe z;Ss98&^PMAal5)cmzECq96X93h2F&-ac=V}bG#g&w(bVKUQ5M$jbxdnX_l86nHRb6 zi%sq3H6`H4ZybfhSYSna5 zta2)f2Y!e99{2pqTH3OJ;w{g(R0!jKM%h2Vf6c&w5e`=K%oQBF zaqnBrU-JK)M?!AE-O?Qk(EoQw)~(Ru%I-4ylDcWh?X52TE4tTG=LLtvYJ#HCJnFSH zC>&>hO+DCa%m-_iLc(kbFFWMkS(#@g39vi|kPY zxpugvtkFMGDa~hPe)b=1^xEi+78uT8B~4&hnSJ^38-_d1pPCF8vD!7Q8#24BaX(Qv zZ~WNXVtbtDh$srsWCm!OVK{K-h`=3(SDQ;bf|-x^9FdR7P?p|8M-mZwJ) z%ZAFx3{U_g(9B3&7f+4|IrD4~3RFffpqp>k^!Y^QLWE#ctYQgCgX-?x86` zM9$+$l4@&s-QK0weh4d9ZaZz@P$+48uCX{EQXs|`wkAbPe>&TSX>6Kp^9!rSU*u>T zj-lL!UDe=#!g8#xfm1~P{>qyUv?zyn%RDk_isGe+EZg!6#x%P2sZzWRA_yW{uonO~ z@Tz`~cYs%Qx|cq1<0V(ja#63=ll`X^y{2zqJ-5!#FpFVztbR~48f+QT7Fb}xX%3C* zNIk~Z()>FRgFmH`^%@%^jRpOYv{{1mI^8d=7#oA$iSkvWdeZJ@n0&Js|2y5FqQ|LO z+w?7nWOruSY}0;ev36lDqW_1SmkSt$kwli(fX>f6*tzd-8=7UJo}P0PL`)Gmwy|q$ zuk08XC2pAEMTM3{K~y+N4m*W4-CP0Mml_#Gj_p8J{*?B|pR_a!q^OGxJ-HRte0d~ zju|WaJq}(btL8g=070JZi!~pPd2D@~aL#raUOOY4I_w;HovO<@6WBepy-@X`9Q^&e zkzMvSqOFY?b>lZb6v8vm_lGMOr`8T#o@u~4%CGvJ`beM}fddIg`Mp3b>hE#;y&jhf zc>Aj^*R&fSZSX`6ORTWuU%h~3UE^cm{Rg7|@5Sc9_hX+jl@85RHl7Sk+aTY;=RZFY z`o4|TH5Sw%C8n({f8P(wn?2bgf_|a9JZ@n3GCU*E3`a|x#G&$+#1@-&!<5Y%?~b}E zEvb^Ch%~PQTEwkN$9n-JepR}i?W$c1=5@Ue1{Lh2!X^TT+pchcGkBJfY0>fPh}CyK zb97?bmBQPMFEX@tZcv+)GP8Z=y^X&RND?KEXLv>tB!Ona?i}iAng}y7+rQh}o+)0? zy9B^-J~7fb7e$#?Sz6&0S;39-J357?1Q9tOE5@^N>ATLhsjDU(INCdUjHjk)tRxyN z&FEo)Y5lNPSy$Vqy@fgJI^~9!UG8!&UXy_mIJsR^(4voI6d>*ggE(6tIMUE96vi{A2 z4;Oc7_)AXb(`+KF?%13%rs-kZ)am%6?%yCoHnc@zNXAf9Lp5j>XyT|P&)>Gw>CL)2 zL7d5TB!9X*uV`9d=!g4XZ9y`2LOa{`>aVG7ZvL%B1izH2uBws*BtsBXMWK`5?0NUg zL)@hi!1L3irvwrGIjqRpwsvDZZBCTN0~SV__5$&iyrS`dk%PgXTk}8f{$sn@*{O(r z5G%#$cX*w*r%gKe{MKg%=7ra<{M@H-s$@7EDl0ltT0Q<+AW$7Pc&T~E*|%oFeseK8 z?=0wGsi+t{*S2odgMEh{h&p%Dh6qGW5;dJ?(7CfIw&-5AEA7|6*4d9&cVtfBcwP~i zz^OMvn7VT`J+#Ph6tpe>#J($UT9X&ffaNKxDuEjudFKDwyYBcXino7dF9|918j&U- zo$WAiOaJ+_jA%U!s;5Mn_@MMOmu6ciLxek#Q-N>KzAK~Vt}QC>ww5kbXX5qUr1 zc9PuO&F$Xh5(4h`k35;Z-Koz!^UO2P%qR+dS%%hN^sx@5t?tq906nEtbU-1Umv?L% z{K4A_OtNAR<(kJEQUh*MVL4hQNnT+!?~^~!ulCVn)p$Y$o9b7wB0^J&0x-=xQ4Ig-(2 z5|>C`(3G`bU;5mm6BgP2g5u0V=ssXV3U<}O=b8NhnqU85iyj`M(<}AoopdTA29kz| z^ucPti--x+U_|~8#1M#Q@&%n&_cN5Aq0o0=V@MNw?EJwF8nvPK@}aPiLkC=rbG80a z`U22bFVmTLub$8`TV%UrBJ$JSYG12=B~kyC&5xBGKQLZ&*MHcjCwNzieun{X+)(re zzD>{Yd|lc5A}jK_47~@}3wR%c!n>gNCg}7Lo!+2Z#)ddzhvD}Dz`6Et{9v)=Stva? z-bWDMKMTbV$D8PT$pS;_20ffVJ@DbkXTL@JX%Qq#vp7dngg^=u4r{#op{^aBL~rN9 ze-`yTsI-sPcq0xWW;ohC$QPo>eqJ?S^@Yx?pNeuQ2>S*kda5Z}=^Eg?bjefS&C3Mx ztTD=#m0xm^BFTy(MQEZbj#{(-)1BQe&$Nc+f{<4|1Ly;JTx3 zFL0nm`7OcW9l`ouYnpTq_4e_K!Qe18B*Hs`#XrJbxXJ2B3ir!F&L>`c>}2s0;8R_G zC!|j;at8#CVMvnZOMFAy?ioM3#4i-cksTS4a}LzO3uQuJu=C#j2NY+1t7tg`_`)wu zEAh}6QRH)Tno3bP%@L$XEIBxuzjSR42jH_#hSS=i&UIfb-1^5`pe6^#xO9{y-2Q-~ z22^EGet|y_3XafL?)>H2U!U2R3A`hl_YHpsCPDCI=rt%TI>Yau)Xyqh#aS{he_?t!9O3+B@q+Gq4*{VS z<38JbhT`2~D5T~Wgw8xra9Na9yyU2B-YrYG_;SCu)?WEeEm(=$Y)@A08RL9z^auA1 zJcV2$q#0hIDN4X`LZBHQ*7=sa8>ZLIMv36D&h6K&rG6Y4f9+J1IEqyjNtBqV1~S$tWu<72BUzTDX_mq{ChAJwQ=7txykkcRu<_0}M{Tu#@@D+(D>y}q zil*^AqrurfjEH-@bMnJ)1{ysVcS{DV5fsVuG9@c&jsFdQ_{C$ZYXIf1bs z`DxweH*Bs2hTxuYt-U-!%Zei7D#?L-)8z&dpbSTs$~4 z?nUu}Oo;-|%e*Qw@I~=c^#hR_=rR1OFQ=T&K=JToXV&Ua{hjv%|A!xKv76f;=qJi~ zZdFuCisd*)<(OuzcE509&eu+OPFD|65A~9)ceCG(NHYErCMDuz=l0`uUcG&Cd-OU; zKFyrDhFcBz&N#_?`yBbe94CSv6Zl>!Xp|!$_WYk1N?wJ6fIU z35Ej2^B-A%^rv!rg)bW)_NkdLwoydhUNJm@%;UV_lKZezPc@02B$adMpfwiPWSSsp zy5)hJ@VA-_wF5s`6^o>a>&DZZ?6*Rr8z;v*k55wwkx?{OkmacJ_%3q9rqL-CI;jEk z20ZyydbGR@DQ*t7cD>dEGsyZZ=R*&7S^nVVfM@g4Vkj>(ULuV}pQ0*#{Axh<_Jy_`x|1XD#aVH}9&_xi2@OsU=akKtOE6!zsJFQ# zOluW|CsK~r!{NSms|_tAj)qk}7XIMn z^?JE_*dyfZ*UHh(yuI7u#g<)=`^U%N1eBZ>CMfpy0Plds@GJZNA2(c2>cdN>xZyk<4nYR zGjzY3O*7NtrVHZxzxA=x-3Z5vh$q=Ic-yPtneO0+oDq6EpdfvaKNvml&55h;!||cs z+oMFzxIuo*0+qi+=OI-+Z%MSA=NfL;=?L9W(pHxfTe{dR{D%Sa0n8@=t@ZBF8S$n>h}|#Yb^!Gc*LN+bJ>Yh*V8KG_f$Ddle_H*|f`#)3<&P*SKO-u3zBKsu zA8I}fb{@t!g01ApEmdGuTv0?q*6KFv-L(Ai0&O7*(99r5Wqb6mbDnViINJ9yIKMl_ z>6iJG+Y{_Jt015TgC4(cf+v(Wwzxp;6_{FBau{xKYTnZIeaau3@=j(1jZXA>=h%09 zTplRBY2u@tSOup!USkvzCvlZ|W!t~?cQ-oi+F)&Uu~3DWT*codi%hGj&Y-$lAkzLL z^>6W^1qg{qkXN1oC-*XjN0qU(b>z$mt{Yyuik z-2~0L^Tm*y*J=EzM;gEVU=BE#*R1LP5$HuQ<;384@?z6vSY-HL{ffh99Ffm!B4^k) zIq$l3{)rzR1y^U!iZR2cNq0fOKTVZGeM7;~g}#s{UmfF-ydK}w$LjQ4^}shQ2Chy> z*PX$Js$sf7zwF`Fha&0Zdy{LavW(y6+%itNY0iF7WqiX}vvf%kG@8;liO`t5pNH(d za_tt^cD-`$)z3|I=}kUOU#T7pRX#YRv%0+xZVcT7F-;w;YJNAH-&DnuY&`|__gW?y zu4p~M@!fhsd|J`+fq0C{0rFQ_>DNfGJ^&^rC=1S2OgP8$U)jda$MglK(Z!K`R8ja{ z=IFM*krd!+eS?qah)?18L};+5^^HMJB0dG_gZcpRfZsuQx-0hgXN#YG;POEIcEn*i z!yMPAT}_>5_dU2>s|ujKKz=~}Q29@Fe*}E-0v4GboDYz`+4_WW{2VhYiU~UGfO>)J z3)D|l_rI!!QTb7DLF4z^27K~*T4Lko*;<4*m{36x(2a7Og2+ntyD|M_mH036rKU29opY8G&Ur!+|tS(SFHvkC(6)s|zB zciY_I{C8>I{Rg&#od~F#-U*&__xAeb>Aed*UPTSS7rg&uPrk&F>mGMHf7o|`eS8wI zuIH8IsGN0OP&tVwcukggifl3B&c&NX)dW_*wt8t_(yfUrnnpgKnVVQ%%W7+}b5!w^ z$2kXB&D|TFH@&(jcduY*xL;A-Q`L}r7A3k1#DJKuhSWfC{>|TIXx(SJ^koAZd<7w} zHvORI_fI-9KXY}OrB~eV2g3BrSHoYvr?b$t(Cp>f8Px~@FuUiz|M>3#)U7BZQLrnp7Ye&*l8}O>;`#R>AZh` zZ9j1o96mKLIxqPw>n^!kDX94a`C`c9_dQf+zAoYQ8E~JNsR>N;~pq zjN4+%t_|f>o)CCW!Zn42FXj5?aF}L(8m5QzAGS1%3`Zxu&iQ3_{n2fu(sikrtw1Xz zFLR7Qi7Ex(iPh@4Fw1?sHcSt!bs*Au!ui^VuitUuapWC>G{JBL!4U+(k~qai-RS!p z6Q(>!HYkNpL>zu35J#>O6K6)FR`Pd-s&8lOD!AJ56JA# zquV)rE3i*-OFYZSDz7k$voWop4$`t&$ls5`{@_s;rbBLuTktqaoApWK8@EI z_QV9_1>Ky0a}>prBu5e?L%|%?zHzt{-Z0l5GlkckZ5+4%(Y_AI!2EJW3k5_ODi}k} zKX&NFS4(^L`0=r+t(?Rze;>L7YEqbI%!ci@9nL9#WsbV>6>v6L`FoUoYLPoYvLcU5 zDlM_H(ss}I**~vqkOhXo`sK1@i*tKsSv%}>PHj4G^52KR65o{Aox`Kd8WC`7WXWyj zsw_zi{>IX=mrfk?xgB2HJJcwWCOb;*bmp}EzJ0?waqp96DTQPtNhBFofbWy;mhiB= z%lX0EYns;H(<}zhlqM;%6sM7V$yL0xJLvTnZ5#SoyYHG`n*)aC0}gZ4W{Vx>q3#L` z3m+utJa+KzJI?EWSQa`wFgLnSl~*fhjaPU{6G@tZ?_%6N-bh{8>pXJ%j_gH`10`%? zdbGMga=2T~_k?-{i+%DKS=2PYSMm6!UUT1?49^=aa*ifw?gY6Tf_QH%6h5GT*hAmH zdis|5=`4oA_Z#G^6;w&>Ag3KivbTjp7;kb}$qli{1rHp3F^HP|zP3(L^W0p-?}@%|_V*?R?P-*s+yv7z zLYBergA0A#~V@uZdD~zTHyp)!PyZ5Ht+ar z_?}vw^)KsIFpqVss4i-l{Jlm65JO==#oWJ$qY!y~HEx8Iq>6)K7cU*kg z@fTl@cV#)rFeE9m3M2C(Y@Pw`4ls@GKZl&(bXZqJKbea*f|a-^Ynn<>nxs$+cl&_L ziH*lr*Kk36Zgh#jvy{M+1S3!s%TYMN@~{zMOGa#kxvYMUJ8v)g zz4`8ko5h=js)8tzf=cl+Po0?(9=m+O!A9$r*8-ef&wxfVU&GJe(rG=N zUiV{aRxD09{~ktq+tx(dH+W4VB~1_oUZ8(#HTt$GCpVSaH_VFTvIhLgdHGcWadkCYxzh#2nSFTy?8i=Q-ET8A&$3M)i&|DW+;J zT-otg78+aQOI$o)**Gm&_|M9p+zS2wuQJTtO9g5K6x$LOy0g;{vRI8O781 zKcct6a;b5O#xK~VBBZC&21++OMg7H*;Crc($6ou{?Z>$`3l`3OfN}m8XX~8D_yXv1N6KRzuM2>!hcWH-i+Kr8{RDmkRf5oz4Pm-nWw%?qK z3LJ;0Jq(PC<<8^RdD`RigxnNI9Uq!T&pXN00&38^y7R+Pd$MVtbj~|j=cXfn=Ryh< zw5ds?aE+EFQKNCs`c6f=@7q_aUlpnF*(r`c`z(pB%0l)z)=vhO>nm7T;6-q6nt?pb zF6CW2cHt*q9how%ll~;eUKD+U0YkZmdNj47tRB zfh0CYNp8*OW(1m21VYploO=JU(Vs8x`d23KhC~AUCs_@>w1Gj~nr<=YZX@$OnxRJi`3WTGRu7_Rt_HUm# z?g0BPV)#7flO*95eZ{>!p??Nlx3Ro);|CkUNBll`f0*7q43$oO%wGJzODFvfoW{!S zDOF@QAyDuh(k@O^RE@Azo;f(y01T^-+hPr?swk6;qS1<^Nn)Rzyb{i+1GNBHu}?P; zi}p%ZAIr+t7+X1T*lG3#69SD>B!ZzRnG-1uCD6_nJmO5vcW8lj0rt~h-bTML1{;%u z{(RNV@&dsLf~bm|=AO{|zIYpxQSPP5qF#c}&BlYSnP%AQoVfY{2jH!darZMYEFnmm zsBjX&d!PJ)ezpIW(nBI(cy5XR+;hvh#iifaQ}Z3VEt+H7=FE9)$cP5fQq-#i+#FeQ zu(}%Xh+fatDlAdotAmm{7h#@zp6gTheQ=yPeo^!wK+~iHhf&~i}ELgB$p)x>Rd2aZ%)E-;C^LN?k z)YkXt-y-SxGS4^iM`&SCKfoS*U}@xYV21?t3&PFy=m3?uFx`Ja<&+b|pD0?^s2=T8 zC&lrZeSWsUWn1~NV8Ma~3l=O`IG5&wVBQ7KtI8a1+F~_lNJUHUiE~;aPSFC-(iF~8 zlpw(Fvn_PTHdsS1OQIe2?v`U6FYX9-1IKXe45+fZ$fJbv+#=2>3QaSDAeNj%|509M z{T$#rXXNx)cD7RoZ0ddXtt*}Yj+wKflhk}}f|po|<`h}x`6+>=eHN@BbFvUKv7FN4 zqy`|b9k9EOT=H}75#X6NCpxF$txi5M5bzhdX;I-Bil;b%l^@+PaaM^}d$LOL7g)ve zZnt&BnE&g4=xE(e=%$T6r_?LvONuzgGu0=C3Ii&9OzD-3+0;8>hcef!B>NFYsgoS( z9_sCv?+Kkb=s3UROk7d&s-sm|^~{VuDfNerX0y;0dmVo{)cC2o(cP!~rXG^#rsgeO z-=|!^*`Rw&A4T3!Ltrb%bzhTxZRzP(0Zdt;=y6MB) z+SLBBR_pU@NT_VnLK)vu*liant`r58?-aclC9gIQ0W+z4gG^e@uR^^mcQ^_Wn#w9rOH@Z6G zg&S2c+`u4Q-ymGiAY9iVT*n|>`z(j8`nT%es(-8gt@{6O)_;~kxQ0PE!yue~mcwZV zVOJ%GjdlrH{BOx0tNyL}uj;Vf))Sjv+^f!{_e!_p*M!YWB_|K?v?^0Psfv{FTZ6;> z+-;iW?5HHaB}anKD+_1q_@w_@x)v;0uwcPLb%YZ!PNJv<3l=O`h>fyU%wE_4;_#(E zU5C7pQ=v7PRs>2ASPj0BGdtnr`e5DfZgS(U<6vR7+<8Lf7G_D2m1t5@NllR8LxncF zQE~UfGU_yXQe}bNBFe{!Bq>H9d7ctToFH)6#p$8-;WXYux@ru>iUona9ewP8ePmWSo3AO*FCu~eqU1vl~QF=#x*7CNW_ctGh@a* z1{?lw=$^SNL5cEWmWag(T2cjqR+KX(+BWpFcHcF>HV3Q=++&YVjevFx8jlh8*%xoS zF#e6+BrCB5jY|SU2=&^YIK3__0|QNYYhJPfbpn?E&X4n-^_8B%95Zc(ltqff6_MrD zBS$9w-nGfAF4V3tqw672cGLO^=G|eNgxz;L(fr$-R%njNCpg?4P^Wr=AvG{sE%1uP zZdr=r9F)7;Bd;P5oZbS|P zv_Rnk#o{c-vK&dm!@$(%!)fFq&jX!;jTkO0x#hmr(S;~$VNnqaLT*M@R7p@tRiiYw zC%?c8m*b(&nj=yXvBE=7t$p1Qd1EmDGvlcGkmw8YUBwYb@BMc7Q{iGhdT0S&e)x~cOSl6T8~ zU$8J=RVL)A0kwCb#~bSK`q$2B&;FQ&BhnD`m;_>pL6Y#O#vH)qWb~K^Cef!j4duu2l;$zAa~q%e?IK{*)a*a zvUl9l^+anFV_b&8%TQFBrzmn?}6+f6wUxFINudmfCuwa&eRs{c z*!h1ArQl9<#{6#NC9%J2+{_tQ4uJUPPB14&0NvCg@_prSSib7_%h-O=uU>D+nrr{= z6_j7~o5fFuHW`l{if=L-+bRKv$La5FJQ{o4x(aHq#wPOv-uqMcV8H5x;{k^DhLtRD z>L&R9K&YHxRRiRgN-`e}#yL&Z6O1+{+Z$NjP>v#ndh!hr{0V|yPv?=R z^eMNVF|c(GoI%1u?{CoAt*aj1uNP#$p3xi9ldJE>i25n*ZwCFfmQi~m>IK9Lmm4l; zs!+=$pCqeY*D}zDKs&?jmMo0w4MY#lJ^j|?@C@?#fu7F~8$|LkYIWoRdu+Z%p{mZ) zWTE^S=4<00PBVOzDtTHfMdf7bC6e0+J5<4HC& zZnl6ZjEkzNwXw3XMsMB^AbmxG=YfdR0vFT?bNHkj+c^cZ&Lybx%W=KDz$L2-WLH7S z&0&y00JmLl);|!l%-La#u+~vEa`J5HB>*Vt)Y9a8uzn8o_nnaZu4sEWZ5Gako?_wL zKrX`GP}y?ge8s1k75jc+1=Am^D`Hpav}Prhvwn)=sj5}J<}jackN}iQ5~&r+WjbQ_TiA{^uf08Hxl!ujzk0UQ^i53!*iKJFSnMfdMAt84i^Lq`&J?>6Uqxl?a{%W-48~*(j zZ|wNM^C=L01)^P`i)TT&OOhATCM$2NJL;MY*ERWlRp;9%{Y2N-E>CejFNbJLh>t+H zWx6F>%#3GM9d9~w^gUL3BqOzyk!zRJlr>IirE z`Tvr1w5c;EHT5a#n+#q+loPd1w^C=whV#R}JdtEQnJs<>;yXYeO)`D6yF)-dm6rdG zaC*z`h)nmbtaC%&iHBo9ZvfHC!lDHE9@O&b>+PoaGf`}+W{Nm;XpimE3KnqWLVL9+ z*FvbDF07<+A=!AHh%lhHA>wsRPL7}FQ}OwEK_!oy)g^vd-nLIL9r*pm5Dgf#n;&Wi zkDj3nUB1sqvYzY)m=jD-bmg z0YIIW6E&}0YES5SqVv>L9fp<-Q6qU|l>2TFHPR!D#6upUzAi&Nzcj(;mq66)ch^G{ zg%J=%;R1-F0Ppiejz17ZAs3<*<&#vGBL|`=G=(S%10YHiC)Xb(L>SOLvr;Q}la0@A z(0@Y-Mho<(D~jwf^(ugNy1i-XgvbPb*5&d$h2iI~%&MAsR}Y8++&U>ad&pl+?QzHJ zxk(o5-cNJ8CzjZpRC^A2k{$ZkK9Ps{Sdb?*q&jS!2Ooqb4 zlH`*%2szdYqA-6ZimM9a=dZHj1sJ6-M4xUS`To%13C>$=vE#`!&^u7$&4-TU`d2}r zy;AgH7=33|%r5FM(2G#=w@;Gk!g_BFh+YE4n{2&-@Az4<`5@u>Frwao-%amImjAmZ zCbp2*1VNX4ogP7(r+EB=<7-|?<6}kRZ9XeC>j@PF%ug52s+e69H9pSP1>cH5Wc>Fe zS)iK@VkJPEu~!4D^50eB;(6*8^|Pi(USjN%9M3 zFprt6^Tm@;J13fd;AcA-%6}V3E?o*yfED_IE_mO_?-%G9?i~z2f4iu9tbc%hHXPB< zxWf45FnW%vj}=KCd;`Z*Sx8iW1bX$sP;7m>v|l7S|LNY;p44~A%KuE0$yIc{vxYsA zqVU??v0s4wicr{ew>>F&V>WCyo@8OxezOQs&iM&Gza_!?;?L51M&n-w6d!LpyLi;( z`i$9g%u@AU!vy0y*J0LgvbuxQ1^fYM+^wgN>wgwRJ|C;U|6;IWdNp9<5XWXvVqKpHjWPQrYV@C=9G-a?I>G0cll~ zUb223T#Dr)nBTA_`Dc%TBS~?O*kSnjEo?Z4yK5xJC-8UOP09!Oz5CeI@agodNLu`_ zIr~hq{*>7^3+EF)fX4U18HvsBnj;(_!95B_=jRV=2kmpPM^XS*7Z_&G3rY0->ISp< z2j_Kw^FMd%x3~B26}!bMd)rl($#iIln*IH|1h1W3l;UeDQF8OECXp0iW@mc@wP3-5 z1q&Abix^i$_qWkjRfqKv-LTN^nee?RBMt6-_+z!hs(U8axP z?RK4l-%^iy#b4j{N2{R?H|vpi`Tg^)KM_lw0pb2#cbslG`GIaA?ZUd(p8Br+Uwc4! z`gMJJ&v@@0283U^f8~jWzl0Kxo`YUH?ttz>9X7B%xS;<9uTe@7%g99^IizH zMS|}g(Dx4L`!YZ88?lFr`b@v>E?`Mprqgn_k7_Nl_^G* zal36kcB<`5Oa5FAs%cToYGPE8Bv_myL|)p14SKe&cdQ*gvK#EA1-0PU%dk}sC%V*T zcB*H$EyPxSQFFET3vej)$k>+#=Zghyjh9)R;c1HF`1_}QH{ykc_hGFO2|R0$A5Ile z=~OiRR2`K8$Ah}@*J)dfDg2=p2j2(GR1nQf`2>%UWfe&Z4%Dj8rrc(R* zR^9(3(R+Q{L461OzpK>_?uGY8Fd+WL*hf=8-13{Cj2&%1`u|4Mxlj-DW%c4!0&apK-T7ij z4R}Pa=W5mM$K82i@aEBJk29IC)dceK>(OD_NEdibGf_Qu3D&mzw_?*ZU|ZL+xYvBs zDy52?s^Nmjj2N(a$6v$u)B@)i|5-ui{?k@9*l+Up{S}PQY{xOnc->78Qp+$~q1OJ> z+0Em(X^9k;6Y(_oALvHttI*1Q->qZs53 zlv3C3z)3uN^_Yuvi$B-h+;`w0KlnQ^!2|Tj>@aod={#^-?B`6-bA+#~d7_>eK)yVV zIa<$q_mz4;lj#{-+y?!DkXt4+S(8Lr5^3qHn?Ag)P3<3RwLZ^g(w|oH0#2FovIe6* zTkz;Ve}LH-UdA)QP(YpGrb&SkNJhYUmKJE9chu@Qw(k{Rl%C0dy&l&E$RyTc%R=g& zmqr2sxhsYuO$vfrD)e|m9^c4-KjaS;7pTM3P@Z48x#%?hY?tZj;PAtF4~FZ8XnJlm zWm!EugFX4wNja+~_f~ysRTsMk8fjVI}Il))x#tl=DLtYKQ*jRraK0 z*>hOq1CM?>W?EbuflMnrONkOKsw`|HsEsV-3)tO#W_9X#l#OP1P{?poFf8dF>Mv3Q zYQQb$sq*x`swNhCLnFn2nBUv46pt+~P?sDW&0o56tGIv5$zAtb0^P#8RXHyn{T{)*Mgi_I|%gyTm zuw_E7HzPPuv|n{b>o~QvK*a*9^>im{qrlA|sI6Y0etdogo@z%>peverOC|od%-D7FC=kKM7kZ zPlu#h&o?#qrrZ@^8Z7z#;c4Sl_;oTC=MWfia)808@SvCgZt!sZyH}Gio?AOAqW_xt z{_P#|IUlozdU?yP6AtbP#j#adW$}XLcs+Hpker=2Ftq!LEA)bTN#+z{vFA~}d!?^^ zs8bo?jl~WO8uT`%p7w{0ZNNPHZKq5OzRst1E460W+gD-}MS!2iC9cE>Eg|I!_hJitJB?2v0}BN|AiP!Na+?cFqWdw8EOktywebnFkwqi0#`c8ri!2I^PX~k7SQ>F~2;?)1CyQBO9iM@hA#HnL{yXWtiV-Lw2Jj=5G#gR2sXHArumKN%4KbaLnh$02JB zcbGdqlX4R{Dn$GmmoNLj=&XJ)2+NN$fYP^KKs7u;W+~I;t#wQWjKSAS;Jahx9RPzcfDsKf&yJDqmrYvT$`?ps`(@ zAq_W<9enTkrxYOMu5Te~b$D~;6Xlu+ENn-PuobBvgM&@JIS+WoU*iGwl9mRZJ^>&4 zR?eU{;la=bnV3(nbbkL{2n>@wp`F)9%s|u4y6D0HW!!d3TXE{5SE#_*FTRUB(7dM0 ziKvf-7G(dVns5OxuYx~Eh#%0!_UJ$!>f_fMbM&}BGU6^D3FzmxHKZD<@1SuGdV{^+$rUp9Ti-v3~Kph1aWZzAxpU&#=0JBgG?z?UpZqNUE_6zME@uc z64xJAQ>7-IZF#$PPj_PY?^n;v%1-MX%RHK@*3EAZHcT0w}?mVFGV0C+mL?< z2`0`lyS52oAfiMA!s+3bh{n`M-0p`LV`JOd?;oMFIWu(_bWF2Nf15)tRc83R-E&*; zq3_nkFB(DaU3&H4+`FMkPmKv=D}g=lZA6u_8ADat6Zve8GbR`RGzlMHVMX;lm02Q{ z(7+3Y*4Rk0-1;s%>DbV9I|qSLSaPd)R4slT8D4C$v#w7iTr@ux-x6R7b2a@_A%TNF z)jFB+!-Zy}o11UL!Gm?B@PlfoKVAJo$jfZ236IaNXg@H+O*dhoM24+T%1dsc%0sF zyV&J+gayF4NjLj=;H4_;i>hS*`-g!4qQ-)E?)%_DRZM?Vzp`eR$@+tI6bs7b3p`x^ zg}4AW9ef^h7Jh)!ZN6@xjf(86>v>#_u^GAEzv-HQFL4#Hp6WY_DA+Im-olNhcJI*c z9v8Pt9)b{j{d%(^Ts?jgaMii{5=5+vxP4ytA8`E2LgEzm2;h=9gS+w)KF~WyX!D$b zKJPS-7s$pVby420Z!`p+Zp>RL$>-t){zS-s$Xc;|12&jc*8@g1`* z#Q>dCs1QZdypbxkoH00)W&LCG4X&@=9s2kZ06K>^j{%N_xCoE28@08S6s6nv%61KB z7KP-2{5(Iv=Ab}9|JT^=0W(E@Ka_Q>nQp;B#J2%=P8OA0TBBBr$ct#8b^T*jCrc@% z*ptZWBq3aLgoHI_v{7G_CTo3AVtnS!tD9b^uN~nFLL|GV9`~Pm&a6Ms1|yuKE)89sxg zBm+VxXRxV81{I|w2B_c_%Bi=Fx(gtbZp0^P|D(y(=TPKxhu0uCY3RsVs?MOfF{^Knqz33Ib<3sO7FMQ+#?XpUZP3VUVz!(^N^~=*d7<{d zJJYIBTVQYj;|%k;f-cqKcJg>ft}MVKn1bB5@e{@8a&4I|sV z+}Y@7Id-6EUrO$m=6z$8({p@JEgHkGXrw5%0Rg^Sy=C9&^8F1|g05raJ7NG{kX&|G zn7iQo(ulWkiT{Tffwd)BHRGOcDWg>e$4-HqZqas4eO#lNlw_P~}0;^#hCj^;$ZX&Pe>WHLz^q*2yt ziKzn5BZK|j=yb@ql2XmdJCou4{D=MTJ_f~_24tGanh4*7 z9>RX&0=h{{mpnNO14rUN9&)H(b}0yctsG>?CydkZIvxDw#d8b+%=u1)M28Bshu#h9 z&zmj$riSt`2qNjM`Q?qG&@1(aEgs{8Y{#_NEa2t z853)I)3hXaHw6CeB&zQ|T*Lkd9l_33`$)*>kwd1a`oC5F0mQH71NzwA&kZEEHZ}Kd*Cm ze~*7|SXdc8(|N^MQL+SyO}~g)Mka} z2{(t$roc@(*z(I{|GF4~@WB^Xoj^2C*c{goUyTbB_D^3^6yb_{e$vs2Lz)f+cfS$m z)J!2w1LA{)I_mVZCc2UifdZcSuTds#U7Tb=PI)Dz9g{tY`W@I{{oCEd)*TY!va6U7 zdL*UU5Sn@)mz@&XioEaicJsFF9=+*(=I8ZJp>*i0ze+$YSKsZy1>eLV<<* z*%PgYgr}}RW{0Nv@1kZcOVb|`gs;-4*4#vw0;+l+?*06n)uYEo=+^wkQb&dKuhuZ5 zJ|EJphCllML&bcs{%+bNvhIO5#!IDtr{Qbt1@q4Qb$#3ZixGI`-mcv8%Ye-NFGKU+ z(?31qQ}iFE2JWzz2B%x-s@FNui*AK6yrUr6VtYN?ak2eJk)yTi%360Cq=5D=r-(U> z$~(hMC#K9LqWrOvKr67Ho$x`3&J*Lz&|I1oT7N%yipu|N9%e!*ZFD?^d}CyX9fvRh z@d>*6c^CM$30|(>R+zJ~$5KR2z2aF&l@Dqdf7o&m)s@9YIF+=u;1ZH}PLEGaG0HLKv>dUf<}Aas7}&op<< zlf8A+VHk9wU&g+!PRl$ix_n}iUe|qUHrcK%J^db;0APII1p2?(Iy*~up720_=A`iT zKmQb~-cwddC*5?r9W=VB^2Rp(bku0;E|+gmOf;w|xb|s5s(XWGL2C6bph>vDh^36q zvHXPeeY(|&`0sIgi8(sDes%SKe&qjBN-BE|`@8?gEn$eRLaE~b=R;Px6W3?ef|_bi z-+qdS+*O->;S1ZWs~l7rFh(JfdN+Z{}x9j@|-M&r+j)rW+H9y!$Db^eKF0~u*SrGpkr%5c)O{VQPfVu4Tj z82Q}v(3aj_tx)eD+E^Nm9LnTQOxf$Q-K~SVlH&xF(swtEf8QhHT`m2eZ(teWjmw0i zT}lFrXLcVt<+Y?Lx-<(0VI?&sv(1p6{hHn)0@mEsK%_qJc8=i>1J@L&^GF|j2 z%^C+@U-ex73eYwt5wzo8H`dW!KMT*-dLDp$o}4e0t9ja}9;1h1N-7zmRVOAIX7={+ z-ADh$iTwvz1^;ut(%j9wqV*&Ctw6}gK90w`ohZseq{pP&sN43iDbfVW zxo{_*9>Fy5h%BFJ>1nhk$h$a@XXy*XF=G7LZ%Zh{m>`0-W39N9I4Bo+xCKy9h#Ft? zD&p}TLQF;aPCh_E?@kw-a2%)bFg$IFv{B!;bhM-rP*{KV37qL#rDT7E^X|XQte|~F z66Q*_Zrw!gDVXo6rO2;;_5yYUGg7U$H=UT4zioYYHwFscso(gO?rw)|cu7YH>tdrB z7Yi5akl$Zq9`%P_BIPHpAD(%MF&~`rH4b0Cd`i7N$P~q~gg`$h3f^CAJ(abrfbo76 z+W3D12Jiy8-iKeTy?)dQ531(GDx<)>N;-;~;l*fhhNOp6!b{&|0_s$KyY)w7<8RC4 z4Mf2a=)W387;|y+^@Il1&c$MGtAVll)Nw+~r0_fuOJ{SlSe$gXlmIY^&ZhVAxRtMW z8Dm73GELg|)U>~I9skgLA(D6fT~TzMP>3zR3*uyupap`cpf&G620#K6oQ75PC&51W1emX!`#1bl0%5eINJ`Xb*SFO752XMosw!)9bcR^ z)0XoRyKf+J#o9zWSG2<;{;fj&hmrc)NxVfhf%b`IR#y%&K;{YDn#_|z0)6!LbW|&H zpGI7RFX8N&+pIjXp-;8?!PYI^dC6FCuRTP+<2@~?{JQmi@L&09V|yzx$Mm%@7n16< zpFWI#<}ACv^6RZ8{3v@3&v3kCdIaUqJ@C@jA!l_jAG${X1SZ1$eBOz-i%pIG;c_>a zd*{4QF>eb-q87yVYJV4hM|%@8H?n(Z3UJ=cQhn|!(DmIbY`qY_aIvz@DE1*fa7ig% ztrVPIjgY-{b9gFQ2{ny;Rs2=_0An= z%K5Jyl-v+i`_1i)^5G|GkT%2gH<@;6)d14OeO2gEO;tSgJm#m~zJn{}f+IFTqQhU4 ziD=O>mQYyd$aBZ!Vba~$d7kgrZ>dG^*uOK9p3H)CRcs4Vd?KuUJnPPmO*K>H18Uc1O)2u3qM`)!AZIa3~$lNH$ZK$p2Bge{K3fV?h2eg z>@II79kooMw)v1Zr%>^R{6W;A+I%tKxmKX2Lu|Jn4B;YheNSNS(H|MZg0hO@FUn5At<6SHld0%%$Be5&Kl@5&jC&6AhG8B?x_YNU9adTEz( z`eD;vuayWILzCZzGGcQp^@*V54UXVH^|k)z`Z+J`v>N0(l9>zJQm*7eG1JI1!a_mq zERZ+Q-gWj56}}op-B9Dbp83fPuL}hwbXQ<}o?&VWOL9=w;8*S|t^{6rm!sp&u;xNL zbaFF2dHGnfMU1MfQ5tO1WlpUTXjI7DDXDC>9gU*pc)VJ<=8aLKHn4jA1)CvHKV$g_ za0OJX5BRYget4uM6n%64lkS^u&x8%9hC$Ii*+Bx|wJs5SmP;`Cqn?;)meze*XRS^k zaNF3}Zu8RAq*xXqdg0YWI@DWp9q`pM|2F zOWRN$t|S?Aw^`1cW-8?i9yBV%J%y^h*D(#rB3jWonv`J1s!&53BRW^XGo!^>L%#Pz z+gMh=Ov>OiTcd9-@u2^}g}v^}UgBBHz~-J-RSO=zaa{m5v!F}lr6M7szob+mU;!;f(CV|o+!-v|t}XP(0H3}KW!_sp~7=UAh9V{Cb?kr{#Y*=E&CpXaKU*rLA{z-Z-fhL;BDy@gO=s-izS7ZsP zer@4&JAnN@sAhxY3~s+{)S>aOYzIX%{^(_nf-9$SfX>?Lsl<`$%m`dd$rdSGNChu1 zg5Z>6_xRmrjXLPOubjwEMm3o;&l*cNbjo$Tkh95XbLaSV9mhL#bO0Z6(D-tn&FP!N z_~DQ(`%A`W7!2)X!xvQ8TP!O0`W6OSbo(OJYdlBZp$abLdu9Z*@J!AE9r!+cWj%d!5X*w?f^jhd3DrWyHNlH2 zn|<^-wGJ7a6Np-Yn=ILHbpTl7KEI`FRFN-ruHSW-dPqaeDGeyUWmjley~n;Dw~`Rj zdrUT)6qDJcUN`P2X`8O++xIx^@+TqnP+(xytML#m1h=qCn2#qvKI!aS_pMq$GEUWu ziCWhF*3gZ}3P|pzthLO=dcAV`E7v7FTXXVh{x!3@4Jf$^eV7WgzTJEQYBCNF9u+Tb z?J-?6%$x^ucC+JV8PZH84uMKFS4mW!{UDM7a!Oqqq31>YEZ=LI6Ck}-@>AzbTQBcf z1zN$PXLq%jvhq_*d;?ZJioWF%f_?n<;YX0?m%ERUUdHE}0vw4y>IlEOr!ZvGLp-P1 zxQ3@24FBEBptwp1!xD9@&0`CrOqNE#SrziBbYukc(o+vQXNdAFd^aE;F@5}l?|lVP zuN;6cVmYlwo7rXx8&csGcZ`s1%~b6Gi25yaApqqXAeeiRKT^;5Z7)0OaU6rTl%=ay z47ap5re^*ox~C0)NTEGS_tH%$ycuMh;w{>oVZT~3^I0kdRMZue3?qL{jSDqK&7K( z!J{VdzkR_8*(SU*L?P(|2p%xgzDsr{%?PcXAt4|?T_a(bH(Psr9}K=eov4xUJ8;zt z$J1CmjMTj3uMN2>V1$Q?w0(KH0pvX9@bO26z>SrEdrrqVC0`7)|10TS$ML?(K(c?Qd`ZO#ihx?~f-~dy<&NEUnQFQjwI-1oLV>_`ajhGzOuwBPJP>l1l>Xcf zUS%jHFazy6e6h;Tq(_>Ouk-GZ`b9ag0QIk(BI$E5es^4URGfoH9dWr~qov9#(KJ?U zY!5?J%WsJ@XDU>?B~!mCPR@X}fdjM>FN-9s88;~Dd5*~jiAAMx4oEB~!pI3HaJ-L1 zpx48;**k|Au!T{VR6?P)frq^J|NB7$OisA7HlC|{z6Vc1k<9sMKj7od>G6*hI8{!q zEW@!8#8fn-dhZt=xGqjTeXz6s4R!zK)^Hx(dy`vh^ywz&1Q$m>g8<|gx2sP&qu5t9 zw|`yn6Plqa=&-6>hsp27FXaB09a1XT)y^R#u<;*}g)J7Pp zmovBwS8VGr1%xONDt*_dQX&bi<9!$h2CB5*HR46#KXBAoDlfHS$8_FCy2ej(tpEMQ}$+mIY$S*KZkS zmXzf*Mk_)>@k$Tuz=7V2zd*&Sy*-+Amj{TikG!aKcn);*)A|hGbH?I%f<=Kzh62Iw`$I38`f)-LDeC z(QA4-)TWI=D@*4pi3zbmpJR6#X9!bdQpymBtzD8m{QTJ^>!rVnAIB1nDx74zOL4K3 z6W?}_*&I#$zFu}2o*}VI|5thU>tvcl|Eb;|s*cBvf<8%L1~X(pRbf$Ue|dB`J&1uI z{kJxN(&M5l=w{UB>}L^d0VNCu4niJTNs7)dzxwI6(#7{uz^X$e*NUxpVlU6Q3&V(7 z?SPub;)-AUAl^4=!+M2vkf*PGC?*}Q-dC)cWCYzX>9trll_j^o9w!5B%mO!@QMrkD z?E`W!qRC-#yLMm)^b2~tiJuKVhkkxAlI`~{z?kq+K2N=%uQ|Gt{9m`(6z%f9@1RHu zcbV_heu(^R*!8SCNJW_&q!kig(AK>GM#R6i+QDz%>+j`3wR3uH&ua5uxtQ9eh|a2WHo^765sSHm=aId}y^*iklR zodZ#?ufjz63dQ=3tAN(*`ES8nrP{^rTVUf#GojCrvRLv)PNG>Sf%_E*oo?B2pWVsk zNwp|H=9>RMKnNzllxzJ~bjC{xeUauJ+)$z0uM7Km1;Sn5r>l5ooykTu)o;T49EF%? z?ww#ETR_cQ5XTpV4D7yVE2|%o)xPfr-oJTpW&p{AX7@wwTo zY75ssT~@JTE}Vx}_7qp5e5GZoCR|OW*>LuPcg7z^Fzvmt|mcF4+W?M zc!ksW!>m|-;lwA*2p*ACaI+ZRUtKU z#ZqxK?8GyS%h#JNYTbeAE7jLJRl4X{3|jh@N}F7evT=*8UCk}xb44j}j9`9;R=@WF zX&9Nh@L(;pari?+gX1S?8vwJBl2i}6l?U(;>szm`lR6J1H*bG4l=XIe z%-J{OPVpoH6!GPx2diPHDFz^Z@u2l-a}TUhI3wto}fyIuC@9)ae~^nIye7bXNuJLSz^mW zjlTehI2>J4B+J9t_DqnR({Z9@YXLiz#LFb6^*ET5x z`Y}{;yM-%#zHh|`TVq(<6lXvG+)#_Hadq-}3W+E?nVJmAVjXRf(X+_T`+yvd?%u~` z<3Jg?T!%GG(|8vLB^9icoPwGv8d(vf0WvT@w((ECh(Je z5Dt$|m<%C;0*nfYC;dU66y2D7c|G}@N$ioT9;k2qe=P6a;aWd_NYkVcocsfjpWo)< znpE3ig!1nja&t8)YMed92oZoQTixZpA%-4!&(Dme&vuU?MC)&j$$KL4uaLWo;0i2f z47>{DikiFoSFmF8&}*XBY*e0oVideT{LT};-o{IzQS#(z73Y`Y*79=OrwXc9yWCj! z9aEdUWtrqHgply|lCw>sedeuXjWqK_-YTXO->C((phQ8x19GZ!Zxx>e49*Nn1T|66 zRgzzZr5s?~*)in_kiPS}%r=E{Hs95r-PiEsVMFpIhZHZk%qDM-ryz#U8dCh=E-u3t zgTq&L*KxP1tc~gzp|x^jOUP`B(CA%cOi<~Iyf~1DX@1Oo-c;IhA`~mBwm27bc~M%# zq-AWqrbG*HO`4t=yV>V22k}0v5`&DO1BS{*Ta$-9B-^1vP&^fKwG!VS(qB7XY%CP# zI26e=A`;i6F`Y~N3%koueYb+>3I2WtnVS6#)=AaT+?7eN@b({0u_SSFVy7e5YzOju zchkrjyovdfsF`dD&uQA%{p_uzOl{uU@i~5Ae15t-GAj-(kDqMZR7=u2Gk= zkP4xln#brCyP6V*MR4BZ@ql`9zcpvL%~(Qg3e^|?*h}Me3bl{l51%XZo(*Ds723`n zpMm$4_;n#9^!i3~ggj#LI|J9fyX45G;MqcV-|IgR?Jp?=eFO5ap^2VaXA07$ip@l{^Ld$7by)o??MZ&`fTRxWa2^JwQ-*obV(fUKMeZ_JYDa`94*f2KIp=8)$8+o;|g!I>ORLPFYfx+!Y>zIbxg>uZjNR^V|np2bWeJ{lh z;OCi8s~6V5=D8AvhHd-4vEsk*^*qA**>G@3ke}xIIM7$t*jsV^(jIPA>n?46Dl;vK z)aO0txM(QDto}t%)u&9?G{pkk<7`Nb<6#mQe^Wlv#wI3f3!&XFgYw*p`j0r%+GzlM4&0jDPmNXer$13QD9(mElDY$uUK?ce$wJ_B!h6472Ol%B; zUtk7Z*P1@RoTT;tzWIPFGU4tB-#~}G7FX_iOTS|`w|VH!ik}_~9v>0EQw%WnB9M}P zp-^hdD`VwwG8PWnADnEr3|3#y@j`#FYKUJ9aNrsD8SpMW_;h;REncYB68z_E+!uGF z6v21d1XR+2h_8Sx#EyUD$Z2A&Y zG`!XMRk4k&UM4qBuyQ8!f;)kW38s8PPec>+IYV7DTHQz1l;RQF1M8!tBh_BnEf?kNFwT zQ9wpXWZ&}r>TUMS;R;>OT<4NmAm3AnZ!?QBK8Sw{mzfM_nAEn5K9er)O~JkpHgJhG zn1V8iKtbF}Z(8QqjTe8)%s$V@(0hBSskm!Ek)-S#)-8e(^<*c53iIwXB9A^5WNpBA z8s91o{z3cA6TlqsKdhPK5Fpsb?0oF5|8N;%6M3!APJPVP2$Bxr#Eha9+ z?1`MpEN*N-Z=8ve5l`pDKlApgxs$vmn{S!6?Q>?D$Gme+DksPpOw_hmsx*bgC z^LyE4Bm=%;dE|J^=UUtCHxFDE)4T3h(A0OO#s15w<{CR(HdkhuyirxUq zCdNf4-r?3Qe7_&+4dRB=o6gpb%&M1|s5-FeJZ2eBt$Q*u=~UHit*}t|T>}$`+lIoz zQVsP}i!h6vIE?C0!6tu>7(?l~6;b2m2e(!5w}>^%=oyk_mP})@byFf9eQ?z`dXlxxqh9U!V#-n-?K&@agU+ApskGt5P4`-93% z-7f~~@90ef_vMU~H3IlYI{RvhA3YE>XS6d0JjCO9ep$yP8F`5IoJO(N*uLoO8eBv& zUAY8QC8o*@_*a{ay7`orbqP!(2zJQVEIroSbk?`{A_)YgG4|8eJekH%f_M7L-&j8A z0LAbjW%)yMEAU=M$1HUmfux(kF_1E3_mCbXa=hK2;L(U=nWTUn3u&(HWzb_g=t3Fp zm^Gt4mI-u@F7dD_Hhg;E9L9eNB-`(-bGbKyT8nQFcdAFFQ~*OAk(0Gj8&5!f&gbax z$?=i=&b}Bd-T7Jy(jxG*X&2ONJiAURb~?r>9Ug|CwCSU%AHKSmQ%k6(@{+czNGb0g zLP%A_wPc-^Uk9UW&3Q7M@dO@TKlXW5U4=GD)!tBlv@}x_cShiw;u|R4Uv4UK7se%O z*NvmTB;xeGS?PdYvou)Ulh9hB5hkm7L;!{eXU0R2&(P-wDP|go>(oY3Uc$MhuYy{F za<;LZUswwvnP1+#9(!*Qc9}5(;^<6y$>*GOAL?NTja48-%$?k%(|dL5vJ(Whc|Tav znaQRI-c2uB(vcD~Rl5kx$`)j<_45(Hl-gf{Di5!;beBUfAK`p~($%ZpvZ7;v>6Q_}#3Un+>P6J0U#&>M zL6o{OU&(o+u2%EG?S5`Qllu=lBs*Tv9u{u?Ja5Q6g=`~JXNCIxG}m~8>Qd?%WIN}+ zcrxs{ckE`6Xqk0VnbEI?{BY#UwEMMbai*PP9yEJjzou1+2&|jX76=2PnDquGVNoLcxUM1{4y}% z0y#Of)B|bG%fGz+h<(hV!`fIAXX|1ZA7D>b7Yr1*abM2_t`083Y*3yj7I{cO(1a5| z&_$aZT{Dorb<$mW)mSVHg=mJ4XeMPoW}uUh#o%L*Cw7}|%61x!xw5Z@L)-7?`G&!l z7ZT(XQOP9O6g31XGTyKEMXqCK?=@b`LEed`E#2FJ>LLOi%^7;5PYkjLBz8msQ?R~? z#k3zj!O{=5b{9}yveO3bWP4rK_l3GakZY9LzcZ?Y$wse_DW-?a~up0*Zen@ zI{DvtBDQR~#ugSCRd6>_m33x>fe$(T(?5Bc!`8Q;-Z)zaP}_jC)hT}#C}>sUER0%S z$MjL3a|f{nCXjjKuI^_oeTJR`A;jxli8j~hJq*<_JON-7kVYYreOS zRHN4LrMHO+RVh>pWb{b*`bKZbpXoM*uho~Y82BG&bWKVqXEE!_kaDEvq3SWpnBT9v z3s>2PQ2d%5jg%@HxBNv2?*uTcG8+h+ON}N393Yp47Y6k;KU=WF3%+QI&T$xF!|K*T zEOyj;iBFQE$k@`5$7KMN@^TE=3(ZfF`^8~a-HljLMaeQ|w6xP7gmj*MbfVUJ6e^gb?eM2m5DfBUk^jLg& z**5^;(z>&u{8FW$9w)0BYS;eE5a&C;>Hu0kEr@76E~3@>BBO_88?x_{g3+N<|IC?t zuVW9o9l5<%4rcH?{n<(bt5z`7*fUnir~KvSkN-6&Kc0krsn&XEfW~WJpIsyv5wH$( zZq+V2>5zFPoiRwa$+APyp|#{aO>kjNIxXoHxntrEJ>D0Y%yckaN4+_Jb7qR0<$CCBu_{v&u|Rg`cPqf&K1CDm|P>Nc1_SN?6FC3!{ynAXa1WYDlV@km$kTA4s z#`{X{KwBy@FL4GuLTu_h8ngAhHL&YlFFSMzOy5p*q^`IB(oxM!*HT>nunj(FujcIs z1w^kLYLW>Xz1PfL2Vt@DAka=A3mft zX|5lvqejAdJZvP!_AJr{9Od9byqIvi@s2y#RC1$|fHmQN!k z2Xn}^Wrka)*gsouvpZIIMt&RcGiw_(Ze~N!k1b&vyRbWgS>W(qqK4z85Fykj z{;B;afAt~{yV@JwmIF3^sl&vYV&CA011=;K)f0bbV;qF-HyB9LH`4&L%o@@VrII?Y zmbX%}coHlXf7C@kJ=ZO7DBM)S0ul*2ua-OMIm>3;^>wWY*P>6rX7R9lBU?m8>nfEj zm@D=zW>VBSCdHCP0$sBo?I~@T-xDLEUh6Vp+q6>=UJ1i8lp*Y{6CZfKmxi51?`V4z2ZpZK zz={=O(B{v-eK?Q|w5JpY%7+{MFpps*w#}cV662c_l7?(jL4g_QKMC2yxaR#va>KhS z)cG2%Tu)~yNg(=KVif1!X&UC42;?fJ6cZl!`9eu_4Agm{-F%xh`&BrxA4yr9b{Fzg zDF{{AD$T2`o%Y@&c8}V zHn%&v#gi?UC%Bi>19*ctE@ScSfkmK+^M6e_UH>x4nKrgsNh$ zsk4Ngm??t*46Z~X5Z8$cqi+QLmLvU>1P%(Ba1-(Y^JIS>^wQW0v6p(lbb8D=c0&V| zU6tAsU{;p@8Fcg*&Y1tbNVa^CKNcHwX$t9l=Ma7Ifz{!IRn$dl@x$lZS%FkS%R?41 z@1TajMuFPTdmGl8fy#axj*fN$pSjDtzg5)o=P%GM^J-4ym+-cZD<#icYNcDoXtkUo zqB|Y3KF3-#h#!0x2hJL0Ep#vIXFEOgnSAyWxe0NbH&jZngvn5~j4vLq?3= z+D0wMwnT?DsU>*cR8^i{=m$;m@xFAgp~g`g#!j4H*>vXoTl$EL#L$h;v^B)O4VBl5 z!5sB=7%2Fj5^Uz25m{SEkwA1M8Ocy751ku};gPS-YqX5;G!%|39FQgO9Z$n)4@P4x zvQBZFBtIHGLS z5PvG|h1uxenx9;j_ZMEaK$GvTt1!wfAdy#-G27H`X>iuh>=vljtloi%HdiL#6qE+i zf8>AB9i9P-g>C)Z?8hugSTEw~Y0V13ou{&q8B#PsVkLx*zK!yj)F{uV3!&n}-H`t{ z(ih9^3hfTOb$5<;x#S5 z$8)~B@+~|=w%Z|1eM(3_m@J}mN(tNPPO#5cgUA@9Nomu!d2`4;(t~*?{8ZvMV|9ix zmnYvr?6#~RC^F8d0{8Zc%rXV%l(;fgd}X;bfPlO6-xvhIY(cE|ZSYEe>q!KTe39(3 zc3pjSQc_?HlfNY-_q{r;FmOHHxw8Q31DA})scN8xw}J!Lp7ojm3F3yLM16`#y6{@b zcw(8Fx~hDA4^JCk@wzd+LX=*nljcwy*{7X1*wK#1Hl==z5;PkbmWmH_X0_2;rfw?# z`5Xf-3Jijt>)(3e9EoB}qoBdZY2ga7@?pm^&coF!iKEb+=IFzWceP(0=sQ8|4KmH* zwFrLqVj>Jl1tXAx13??(S!#ZP0AJ)XJpIJL#X;8%*fQQ2c%5IM-V4 zovlp+6L9zE=gYJ7V8*Kq7uAU~|N;yq@D<({GoJb^AXLa#(fh**5!E zqo{E&?zqZd+EO9g^r5da%6NAMwgwCWBbApuy}_`F_ubVoIC0LYs%MGuZ{2{L!>^yf zy4bsNZ7no81c5Dp0Q-zo#&T_NWO@(;Lw=-HZs}Nexw)`s# z-$umgBpXPLT#EaBRuOF~hcdcsc2RJ8{{Ovbh@x6k1kt8QVl?#?g7o|SJexpn@XjjS zxUFPVu$!xbz&eFvAxdiPB>|1x$ zecFUcjd*`|a>eDyIL1#HN^4@M4sS4|1Q&K6>1A8LJ35Iv&-_N{*Do1asFg1=@J(P-7b==j|44xta8~1gnRHAiJ_oh)g>Pqc4_~iA8BQ71( zC6m01#Sdi)(#fE*?FCg|?FL*yut6a*3Tf;7DT;zgmU}yTpO9`cMY8TLjo3`BH z4*LLy=jz@u7(6Lk6jJiWSAX0}+XD*L1f*J3dcHD}Cu#t^qbc_*zXedOufowX|LTFp z7a{>&<_xhxji;u_C7&p8qdsmu_!InvFV|%0Rg7g5stel-q?+CfpgK;FYhW#vo_YU; zr?PpAXa(_MAT{_00opN5rIw=1`eSY!f7fo-h3+qWK`&J8(D{Yx0$WLoa_{dqGvIys zYTkMkde$$vQS?nOG)+1tZsEkukE6B!-yLXcDZ(aYjWn`c$*678t0)W2_Sd%fgD(?{ z5S?7%U&)cC)ixv5(vxEs5kB4&LIVaVlY9WJPt!hLTD=cN=JPZ`jn*xH+o}MHv1;U3 zxCEpLoWI|CF?Ms$sa5;DC^?t_u_|cZE(>L0d$Fxu4fZE8^3mH%aY9$97J(cJ2!clD zOS2=-f#BaMcj&KpxCdJhdra|u^iBDeu(w`^xLc@se*1)(oVuPv-jpApu9SFo0VUR* z;PR0SxGGX$pyztIQy}DE#MH!vi;YxPCnO`Aip$`lyzBCfgf`JaHb}u`}|G;ke!EIl~+E7R7%WB7~>C}JRhefJ4zrAtO ze%^`jgaKhWgqE%6wB-u=&UH=B`E>3@D}i>WPc%(@t97is}-u>>6@_EgB zxRS1jW}_k%heiGzwN1+}d)f4m9MX!N!@A}T#H7&4@Xhdk%MN>h2I{IX>a4eY_@I(B z0Yn_7E(J)B%0!UMs34pEVeJp~8Z(dUgjbD{(FGdO45*m9WeMtg^01iL)qRLo87sPX;I9njS zZmWQN>Sjy4WI-3ITB*=6h-oNh;V&?|8?-?uE8FKW|>6}sqOUh zU>5Hkka^})>2b`|T#AkPI%HG0pyU5B^^T2^aAC9V#I|iGlT7SPY}>Zev2EL)*tTuk zw#}30-DhL{f$r7)~XPrrmfJMvlbEZE^!S*j{j>426UqPZqd3;sX zxQBAKSzl;zrs1E)hR$1~`O9Z7aLi$KNy;IjgpPc>I$DRw7W<>sQLOSIvMBI95hxd0 zY71@sDEpr_L`uqR_)5`Va!t4U60KFPV~_-_eU=8el3|chg^iJG=js93@Hn>|M?DTJ z#1Ez&OZGd@$*d-xJ~k^%dP~2X7S%6qFleCDN5mUO?*Fgo4(y~}-4nPAC;b3^e8_4# zJ-l8v-7UlW1N*R(p(KUqS;l_c zl;LkYrR$F52IMKlpD)U zcz${HI3ioWy&lb+>gP6MiUVoD&azIujzrJWhp7G$!yZNZ*e4D5RfgpgwvP8mx@sEqAP}a0Z)frtxP)>mX@wg`+gIDF&X$Pl{|s5qUNIHmsG%`=LUG=eH6%9j6Em>%j6khlkR-uYY~nFy0^0={wCNPQ;hV#D|kZWZ8DXmP)iO zExle`+fLT9{+$N6ksd!xjU;Tgg8bu#%RbVJigX;e0hCl!H8yJ0j<~O&HNn>nL8p^C zKudxy?rte5Aw1M}@}7q2@^PVkeXtc+hL=fZ7KYMhK0(mPWme`~64c&?c4L!xq!>U2 zAG^j;V5aAl=59tBpTbd%zpF3D!Tg?|&QM7#CXa!UTN1o`2oEGjWrhqDt4J{_FGd+4K_<0z@@^ zcHZTgFBDen98rs?k`~Nnj*K(^gOcRMyDPTb{KF(R%kE&+Mr>ijxU^(wdi;#z9dks^ zESiAJZ;vVt0F~~&e0*i~8PpNFx{aI7Ovlf)$^m#}Yp4;Vlj?n+%-en@2P)z2LD3 zwwRQYZvUMRf`%uecOb`BjwWZ*sx17 z#muYrFF_RJ0tC*ne60rSHQlA=Afv{o!S3kodhH)tTM+XFfD_Y1<1-Qk9w%~J)iFw% zUY~WeskC}h=F3^jRZ&kPo>W}X*iTh`CGFW0pof_mVsY-2dq3WqkPirvu%I0d4=0xd zzJPBmBc%CxL|AW9tQ>jmyc#?c-3Su^N^A@{qEeV;NU5Yd&0RN@p{gOpeFy0)j=v9v zCgP>>eFV06^{nq5PHrZVPOuH>QLkZ6CFY1irrR^XhX{i9ss#;iElM;@^X{bm_Fz%3 zLvhCvtPuF-&yOoDTr2sc&lAf4sHL_1Q%l{lB5+Asntaa|)d4C0&sGBQK%acuImqgc|<{L&J{r@7< zj@qL_l^6fSkrMb#5N)$Qj3nE(OF=c`5l2)Mj$#wV*Wn)kTw=(KFf$XDn+m~~&(FVn z{qF=7Vh0#N#U(kX$1kGFi?42;ZVQ3?A3_<4s>B0JOlf|I{93VU4bk`=9d;2qrG+yz>opdX;bkqQB>(Zg)QV|e6lbu2j; zP5EB4Gmg?BGR@{kVvpGt=kue@yN4#ec#q;R*(FpGjz{J?)rpml)3s6%j`(RPW zWEz2sG(O8hWS;fbeF!{ri6Z9kc17GK4K*2rv{eIa&F z=<}7V=2Ign+iOux;-p~F`e6R#Siy#3=qd&q<|pLYe@`@Q8?AX(Nj)44P^(IWq)+saHNufmR8gEYUE5D_HB)gCOHV3> z%z`ZCP*n>%!pc4{7k*=PgKMtIFavt~i;V60Px(2wD}-J=tBwAF=p!uj?w4T$*-(IR z(MxiBonBaL!~G;)lXNlutIZc_LnV)BC@R%mhaBPz@I;EwANQgFsKK}EhCeJmvb-#K zrClcK$>{3-hw9PCgM{a2#ZrWm#>UiksJR8!Hu#L3SEmYR7^V-dK=EW zT`brQ9)BfZ9^R|%3v1h@T+Yfot{pT0w{wb05t&v+h$3MLAd+gJ2xZ0FW~>;qzIVrs zIw5k94XMqm-TrHJye_Z>OS5I7W3+w$H2s^%6rf2Oa|Bkrr_%UCjHR1;#xOm6h?X+< zJn}L0Rf@FyLV61Bi;pgNZF=Wbb9&N?O7A7rIca4YK1PLfg>a+U`<+I7rlwbZ{8n@N z$}z$rKuRg2psq1z4wg-Vu6vDeUvLBgV+{juOi)z|E!A!+=sKr|wRA0B(CiXOF5_mkQ zSO3ZuSxJ7^EDg!XVRe82+`9Z-%wU}Ik=yuRitwT0+Q<1|spn(9R*<^X^EzwJSIH^g z_{`V0s{(C{ZEYlCEi@)8`o*zt(d*)Kp2dX05DQO^iAQm$8EW^DMW{8!i>W`7a_+WVRjLYtCV{ zx07{Y1L&!MiR1&HMs9m>T!ENLLOW&kA@DNeeXUXz|F2D0ENLlK!w?O#be|^iHQB(L ze7V)Vjn6^b+h#gH9FnUCqx~&wlOIMkH9p}X!lcu?p5QM8g&#fU$+c?yVbyTwMHEsu z`in~t8h+o13ribOJWN4NS8h{9LGcrNJv2B1on>W((KQi` z3!_Nlm6w8^rlJrga3U_8iGrRF1K(^Oi^hP~w!u2%Wg;dcB;;9(0uh=*0ys~epAE+P zl^Q7SfqcCUWC~4{1*-br5|nh3aL}xgNJ!(tQ;GUqebZ)+?y`-H4}*&oLT^0ul(m&_;jDHT#7yk#cWvXy)9lXS7*rp?w2?T6JdA0!<*gKb!z zl7RlT&ex%3OkmnoHdCJnl6MSR$@STQ__7v-ge7FXd5ZO9#YStuc_6@fEFN_*tYQR) zdwlQ;{@z$qCWj;EqXA-q?;g2-iZ7GgzG4K0bhxbid(N^+$KC6#bEr6HOnJTqI`NH< z#B<%uKLifKC>O4ouKh)MZnIp#PUekGypzB(s)jtJG^wsECf{|+kBti1Pzev?@HNgl^FtON zfPyA+LJD@=fV&;o8&4y8TG@(vxo0S_PpOUprEG#)Osx3K(r)uPMNsMdGIXhJKWADn zX~bI(*KW|+`IMs%L95<_hbg{H1&?2YOB|?q&b0nnK(O9>309tly|mM005#X0i*;dt zeCXP!GtXiiK7Hx-`Q{8|onh119hv5#wDWt`-Tu!~4$ZOiK7+Y|UZO@_V`}tzv_*4F z8^xaw=fr%6w%=l$}Ot*k;Z&B=WQL!8P}2U9uy_H09t93@V-CDw8WQJ z=9D~bFZ~{oVGltEJ+3t^4t>tSp5~uxQiOk&A?v&Q6w>n*sq^ZA9}5q!Y@MaO7sBh* z*$q*x?G;|O3&33Y=3G|oyQpDh5a`T(3~{#3o@5G4{gSzn+%NNvTa=20#_OceUM}Yb z(w^USbX<)7%tie2WMG`@680K!iHp@3d!D7c@2r%(4A{hIg!MV3lcfaiEyM0TWpK0A zJt2@+Pv`TTSaH#|c(L%PpbPKtsaZYN-rUR<%2)m6M!G+d!mVRnl1$O+$sxg4z3z02 z5l7+{RtV|8+_+Zh&uP0j_%&S_K07`f6UsQM3bgcVP zZxc=tR7PB}lA%<0Eklt)+o^3Wkz(5+#}`OEy?xBLCiCE#t9nkgvm;s}EuWm5l|H=x z1Uo%j^f)!^piJM9H3u!O#J9dCZRvKiFQ{jRc0Z{WSp=$0iY1>ymTdJjio5qW;LC)8 zXu-E{1x=!RMMK_As5(Q?wGhN^_Jo-2C)Y53A-beOIP&@@&4+iK@L--XA`FApo;h(m;w zBiYx52LjXUP{_!Bs>$~1uGrLvAgCXc-&jbP*hqya$xw4D#%47`+6sRkx~xJk%;BF2 zmA*R}9fStNdx-VtUMtU4dLVb%$RAXqntU-RP+>-XQ8XXsqg|;$=MRMSwQ_9O3pX!z zJo@R-^eUu8F-iWZNVW!CTt?XJ%I}7($+ptr-mhJ0UbQGgVU1l>g#`VC7%+KBaG&+3 zj!DmqHbNRTeCp(sG61veY2xXOYnFa%$!uanTdBy^;z+V~bFJM6e6@`3~$C_3;!{UH*`!qeKkA6rrFbp|B{9 ze~zC9Zmj05Bx;L4Z@xy%zZV6KiIAE56}boPnZ?14Z*p$G)FG$?lsu>b@$25!uAB#u z5^_Q+^Pq9K%uSzld;V_XY;NIWu{H$vlVz2|-%$N+_hQM8?q2cqqNlsgXt3^+fNMWK zUYzC{LvYVCTvRiSz@+QyqnT~t2(|8SH2Lg|NxyCi;;j%LwxqUQrVCAPx2x99V*X=U z$kkVDeyR>i3tBp{C4?c|E3Ypb984U~zz)#R*PeOkilp|6o6Yp6X_=3$Zej4X1SER7 z{2m78{#n#f(AH5~D=jcDWc5!C=gSa{>c>oA^uT>Vn!XPh0d*or^&(1vrN=I=u+wJN z62rz2z4E+R)WiGyhqD#S?d6jxb&uZI5d@OSo3=ux_^FY|mMO=1Uj*;z=H8)AALSb; zDRv(v?l}+2$e8-LwU-hvoW;iL&*iz>&LFW4Sq_zXa~V=M>1sw9zB23kTWn%9dBiJq< zW*zQXVq6aHSv0#d-qeuoYL>xfooWc9-K$~tTo&G?^JY*F38NDUet`ttQuCd?i-F^6 zOQiZVJf14_PRr}l2zhA`dB>nan1Ke(77<)tOXo5y-K9LZm19!itss%;RZNml(#zw_ zj3V7h#xQ2NW^q!Tz6}{z*vfKuw!DwB>|V1as4FMAh8MBRgs5L*gf^_N$9yxLj-yTX zZdyoBhQ223QJH>k=(ur!4Lf9Qc}l0nd(4J5bZf>r@U@-weE7k{82v(bCuyahtXzC8(gIWdlb3So*razu~Nh<8Y`iq24 z@pwtj6z^^KY};;+1o}}AnA*rx;UsRsdW9+Ocxo>D?N~Pq*7&;*^cwVQtKNsV8d}>P zJ;cuLl$W`bC=Eq-byMOG!k0VcpE1p^d82gZdYg%s(ZBz*LCSAnE#0R}3tq%bc{<6B zU7tk6s`(d-MWa&sBdhuQd3;D2=wWWq6kJZnsChrsLCLcpE}1FMD=EmEDa0HkwhIQj zcKD7JH@vRzPmGbwAE~`tDh{j5T3cgpEb{~V=f;6bQ&RU*GFt8Sto5+j zDzfsJZU!(dtoN_ho9C0t=ZnCE|LuRWYD6O99;mzTH{&@T~wE*qRP|u^F!2)<#a&LB>wZTZr*6TtZ`I2^0r?fG4$9Tokh zU2Hqyr`aaS2-3}lrb(F=k+h`nE8$-(G=czEKSZ8R#6vser#H{TyYh_d1?;R3Hfr(Y zZU_^uXwtNm!|HbG^L#^>Y~ZGfGMc}fTKEB0cu=!4#9swRm_p8NYYd7CPa7fKn!gyx zGxybnG@yegg+k*7BVca_^ghrY*u&X~l;Dnm-aakbdY&W=n+_zXKGv(v;cS^qw7pV8ivfuK11nIrZ1&_n8C; zptsfNuO`>k9%i(mvKB1t^W28D5Cb_L=Hm0k)0>ANx4{5y7S`fLP0&54OCJt#IIkBV zM4wjWtm!MfX&%VEtZR!|Gp{}E82=X71Tmy`49fR=^h$^bYUA5T&JuWsv8pRO$o zTlA&kRc%vnnT~T3M4x>*|9AE6{+xi9;^LS}O=ed$NkT|QfT@%4P?8T5SvAs-Z>CW=pC3nVw(wr7QI{t9 z%DeVpS@-!sV~8&{A^?2~%MVQ}h=|M21g84CPvGr1W=0-d;O#oFHP<@>%-pzIR&(6h?$Nu~=W8_Qb|~NUxc#xJTt*agn5= zgI9*e{`=-Cjf=naA3X|dVc0%8~nu2+-5@i|%sZL0Y z!gDoBxr1xlrrRO~#58HJa>;0!03~;MePTrcszsa)tso7Z$;!2QY+8LCOvDy1WYfd= z?-nQ;(bkf!>+`!e(v*C(l2`rmZdHc@>#&SVnlCYT@5z|IVUMn%i;&~7Q=Tzg)7nPR zE}GY`DLJj5W}NJgFjk5Kl%<{B{C2BQvpg}{-+b%5$A8D>y1aTOmn{R@UiP%}V8<_c zt<+0h($hgNz~yavsl8w3kTA*w781@c1T$q%Q$8z|6N3XJiTTK}kMmJo7ol*-d8;}Uv zP-jwy=d$wclao^2-N4!YZymNkvYkA1l=w2LPvwS=Xg~S5RR4@$1<;e<|G7;uD$8A8 z-8O>$v!4DO`Mn`V35=6J9wgon)9d_sRDCXFgWe=km86%v<$=)c#0k6Ym-o$EKHab6 z4K6zAlrKHb{va(OuS;`5cD##C<~ej%3c#2jc6b!u`Ps0J0+J zUpnut2r66LJbYyldamL}sM$$S;>9}=dhrET)gG4s@Q56*cet7-c>8r*drRA(SW2Be zGXL1ph%wTd?4WpJ^rl}Zg zwz4fPn503Fr(O)ElmLa|ZVjsP%F(U(ps<(aNQw~0!*?Oc3+F4=^2#=c_Idh*PR~$#DwjQpzEkjcDJo_X#){jqCH^)ng>)wN!gJVg*CDce zJE5thd9l0@0>YZ+^q2nG(52oEJzSN0uR6JP*-_eVqIkM0mb{#j4iVR>?1c4)4lw)5 z%r_liM6R364ig_2x65qD<)*V#Ehq4f?{)?R#3D<)p^EbD66syi@jl093x4SD4OBqH z(QzT=1lDcz^K{}qtDVh(eE<93ilbxU$<__;?S}iQVG$w(yAx7z$%YB0@TuP8gkQwQ zx`~?wPZSE#GTnLfdYG@hohhP<{)%x9fRMLBE9;*n!gun+>oWX`hsS-!q_Yv&eZ$_AI-~@tQ96mSg!bJjV%|7s2-(~%YwWOu$MI>WVhFPpBDZ@) z7UeFMww|$0>>*)HvWrXuA@q0PXZDk>t@=GrO|m-b88&#j{n3$5$4BK3_Xzs>*xR&L z7Zu#gl^ym#lA-6?uQ{V>2DS5zr!Tu`d+I-}fzqKW=Vy=-LX`m z&Vu_(5rQ0&6&1pGbmDo>`sx-i?;}!x$TQ*JHdg1KKIt=gH$2tq^+c2}%JifOjRnw@ zqGSDZnN#)iviK_+O{Ys=^_>+05btI6(Qzpdk%dDeDMKMrDo`n+Z`c0P1$SO9Yw?*u z9<}GdM?#pkPJM0oY;SZ~;l(PyfxS6NatQh!|C>tcWbi)l(7=@`StDqPQW9aePZ{c#nPMMc)Hk;IcSrF7bGUBUSE^$nZ zBRI+4QfmBXoa3lx(JcoOEpFH{ckz8l=E1*SoMnAyYu>&%O$bS>M3ta0QjVoclh<3d zfD*ED7`Sj=S$@J>dYIKeslOl<3@sE31s+!oF7Rxgggt}&VSe)mnA zW*pmk(Cf@dKPKh)+G8wSPoo#%T{+hEz)qYl-pr?w9ak8NpxpEQ{JQ_HkHXbJm|Mo! zw`%)c3kFRjfnk(d&mt07WMEOW2bYwJspA@=-o(;}DnECPB6Yno>|&Y1(oD1FK}8XZ zDjQEcngA>dD*aB6>wazE`nvX;DB>piGxag!_;k6~$cJVM75QY>*=@5G+m2m+ zM_%t_OJm%H``z@cpR90Iqv%dpx}($uN%w+gQ>bYO^80mA4iyWdw(twNOV^TU@84yL z#-BOGO3H5f)B8JrtOSQNE1yoo>$z5{+T`e=a%@QjSc-8{dV2-ZYKun$CAI}YPYfvO zpG|>=?L+pa{ZA!D)tL=~4tbfIOk4m)5Iu3q3&dr&(}-8!hY_kvNg4IH7`C(=>S*4T z++(F=mE4@)z33oGXGmW}@t%hSjts))A;IeTcc=SmQ|E~nX*8L7nu%lBj=rcKAc`(H zl2SB#&~d=K)8XvQHe1k^TM={+nt2#NDq2(V3x+2GZac|*Qo!~fZteK8=cbh&a>P=} zVO%7W?wu>kPEk|N@@3l#OtmF5Jq>LoqGJeddfV6F6bST2C(xlr!5^}Hc9Z#IXG?

    K{yH){|<+Oo@+RK+o|gnypK-CM2X*Pqn9qA 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 z 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 z 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

    3f&^%Su_N3Dd0UnlS_1D@h_lKMb~=U zkJPS=0O2PdRT?&gWA@!`naMU3jMfk0Vii7cOeJ#55qz(YL$!WnUDV!)8V!03)j}G@ zyu8`W2^N#Q!wgSP;y?I|Z(mS|El0r60A<9-_X;L>ip-REGkP)3d0Rqe{&oF2k(~Ma zT-k;#3j@GUZfXfr#!R@g~*O|@}%Yb92%QiXyCYX!J#rr@0AKRoi8rf0c+{C(I} zh&=FcUCDN66{FWnaHB@kE+C1d*GzE7DM3Z}D~crWxQJxM+Z4#a>ZfI{X6mq_o9%G; z{qu5)z+?8{-_R*v@l0I_&DOpgP}mI6{S|hGUYRG;aRdAc?V$8oaslKll>5zh?Wrwy_OrrUkn?oy4QuKJIN!V_d1 z=!D1f>Ff=-`5xp<+>cFK@S55__)j#5I@fvm!Yn@W zOlUr?)ZnDq_yobi^s}z-(h%JDJqA+l6wZje6(Z-drDJrk(a!hjI(28&+ywI`I@HgX zQrw7qPnEa1Bh1OYjcHy{y=+R=SqSQv-nw&x0hX~ZMj?`=Eum#6_k3zqy4%g?sbbeu zGiWPeU-8g#EFRT#UhDz5-X7v7vmE#)N9g*$ie{x7o`(-%d5FPIHo&2XO4aSGqW&oP z64V`?NYv!^xMk-pl4sFwE@?yQkfLwRuwm3Etr{g2`g;<{SM?nDOKcX+7z0dbWn)!1 zV!_h~YBHx_&yeK3KgM~DJ{iqWuoF3?4%qDlJRFJ=)u#_B&2d~eXsg29Cb1PBH9_{L z7SL3c9V-PGGy(p_3jih9w_eA%9v^mt`*)BxJ(-z)-D^dP^vPU#q}y=%At>`*ftU2d zRpZ8cuq!ugKe)K-9r&aQs;J;m2YnYl@?9K2EGyy2*|L|lR`(oS!M*LvC|aBP=MFhT zLt9VxkFeRPIm?6SbNwpSSlETT$I!fg;6`nbVR?04RXk@qmmb?-R$Q~Tx^P8#mx20P zB7Iq!8g)iQvF&VS0`nvFRWfDu3`rdSC--X8u#1z{oO;|x0K2?-{8yhELkJ;5lh8!P zyMq)n+R|Ic*AdMNheOv)=I6Xs-Rr89$Om#%QR<{z`wE)ktF%TUx68;S`vaf)!LbVm zS-_I#Y=$a5mtdgHG+cDC3iV@YB04^vAK6XC$>R6H8`$d-Jq;WrOA{( z_q&TKm4an545QH9>zLecL(p+V4&}R_(e?!>RYH9+f1gNSwT^awNn-Gp^*>gP_c!4F zMVTn+)%@WH!HzWUaB@~{6m*G_=()VuJ-xNNyos}jnJxH>e5J&ZW$6U7vJ6`p$fIk^-sYyyclyq!TY^|m7eNdybW!mLMR`A_LoWoaS z6o!xTOJjgW?H}Qzsbl1@$%)gY{-pDK8X(*SJ3>X*NrK7(-12lf~=Z? z>a3@3EMOg8vr%{G(9>u-8=&sh5NP^{P7%bRnro3=Y>})?=xZ_b7S+8Kt;@>`cG{xm zwoQ!z=hx$6?9(kxfQ4xzrl(>qh2qllov48I)@(BajTzo;-S_CF1vthy)UCWoWD$=e zq9zI}!LrjCeeG#~(^u|ESP!uD{@$Gl;W23LWqyso7MwWl{-F@r2$Z_K@rm;yEP@ig zf5l6@9fIRh5w zy9sTHo9$u}U$P=AYS|TrF16#{;zugU2-NsSA@lq;*59%_hE9#4$G&6|3rRvNW0jLQ z#k!^7NnJ&VC}>8`S5`cUOs&A$ue8LTt}x;2CyQP4wqPD|lCiErOJt7fFZ7XPizwg~ zoV}F&(xhN0F1M%1VsFK*etHhzaPAj7%kUMye`qtj9$Qc>7IqSK3OXTdpXp_Jp=SDO z!~#f&pc{@%*kd4*w%*&VI5*s~4Z~84Wv$FAU$uM~XSe%-_S@RBZhqk0OEcb9=_Bmz zQ)X3gVJ=rsa?>U4c+^DSbCv2C9B3@b?5G^|qYtWe=J9?)b?HXx;`S@lkL8fD=w~E1G>$x^Qry8-LI z$tV}0l_mc*tcW@$z7q!y;TQ1PAxVKGztqCwt+I6z+Id$+C>+ zkj^{nm)T}7ngF^%46RqkQ<&nw3moy&^dif^3loY*0k7!1DbAMTkUS1SYEWfT^=kyU-|?FKbOd#H??#)qF9O}l z)aisUT=Z^f+UU#;ZM3i}Q|A%hm~+PP{R%YW=511^ z_KmWs9_#8%=Svji>fGbP!e7J&KP1-0F{XY+OGyXmJI`NSn(-X@EDe^Ys*t7}p zOzc935ts;#KG>M3$PLB|_bP>9?lf~7Q{tfKu8*HQvLqGr_uz}H)5Va-?qrY>J#biy zv<}jbvM>5_reW46Xs710(nifDt#SUG@+;bnI;{NEbmM<4)MSsTmd;gOWW8K3{eJjT zZ=^U?-JI$w-OCtcEoR@nHs=5`Z_JWH*7FBg%W~%{Ft1DQfML!$ zeU+OaY7aQGPN?^;>QJ~~*zRg|MJ%yBj}WC7yWA!l{?o>VM_G~6z0D?@jf|y7JfEvl z`>2KWU6*Q&)_<>&jsFqTfH#(Wm*`m7?iRoc^4nK+Z}aIZ|ItTy(&|U%7qRJ{4nM!l z#qMnqZoDSMt3ao#(?P+(9T(xJ;Nb2Gt`l0YpHj3KMN}b)Qc{6G@8cM1bk*+^8X@O@ zKLcw=Pf=EDgI>4JPqPG@1Eqf+H@M`IQ|*zp&0+E{s8>9V0}=#{Kdc4$OOF*u82$(8 z#o;|W-y323ea0ii`5P<{BRa*?aKMH$p;5r)dtF8Hm&B9zAS<1E6(OL5(Z->^?9gi0 z5^!RYU!4()7qss0X|%=K)Uf7?``XR%uF~#|A1;{dmw8x6!#QhYu&mXg{=9@sBkYb! zACw0bHUpk@ldT_otrBQ-xwn6AKwUcvGX>lCx~yvCdEKA)_{WovWAd65LL!IA+~e2l zU5vOr zPh!vR0sgR;IUBV5--W_iwtQ|Ro;;97VTELWeO>sc=N87a0j`;mD-N}N6WOoia$dF) z^tkZ+>=)6Ll|Gy`PM5cnvC4KanHZh;FNPPu&+!PgF|%VFLSeYJy ze&;J6HYd+wd%9#qCHynW%DW-?HGZGd3h+4jNKGapOSs7G(fgKWMBBXx;MAMKInuwK zpBGA1_lu0GJ)4dx2hADT8nO(_ue(cYkW`R$OXCTwZcN>@{;JFoFE$7gUs4f63=j49&g>`ZOc$?#ylBk6r zQ?Ntrz`70hjz0$DzO^BnMH*NCQJp=cDT|IxaZhL(Ob%SKYi(PBP6y{8x;aN^H)|t4 zsY8HVXA~2rRlI{zt0(u3ere2s+3TOim@aw};P>>}Jz_t@;b(f@|D!zomTJxXUWow- z!SgwnQe$1ogk1|txV%~Q@>*Yxd513k{xgeV%$Ah-ZF$l*#;@{hzC9hw@7{dpEiZ>+ z9hvMr{dq{q3vT)I(KH1KaVBfl%h;p^QgOwGE~P#1Y_=?7W|d|Sot9d*qdTp2mY2xU zy#7X>_;zb;;pA~^#}mVNl-~Gl^##TXsMx5p<7SxYY4MwNyGD8W<)!FhX$u$M==G89 z8UJcH17=v$!IdbJfK_`tYzl-B#rny>+=O(aJjfZ_94S)CD)wA&7WkZ)>pQbjEmd)T z$R#P;K*-6#yLq8zTkhFb8{M6#t>HIevE$0M4h^u(f6uRdia;fw77%&vE!m+S@qhi1 z2*1l0gXwW4G}MetnX!U$l5Azpz0L0XiKH|oEj!lA%U^r>?Y)Wnqpi^mcTKQ^^Pk0o zFx9cxzzK+y$Q=4LDc3;1`Va^KF*{SAvYqJk7g~!1Pqu^4rPDibBxEQg+H)_csL8Lh z_RgaH$CO}kT9cPk?dLh%=6(|9sf$WBK}y2bq+CDgG6n1V|i@ zzU+`|P<2_pypF&$6(gdZ+De?yz`P1eO2eXJcu-Cd1Jf0K+ zViM`g!4?31L;DjMc>$wQ_cQqApZWmrloYXz(65<=+TjC`45`kV#JHWyr*keR5nW9 zy=MOSep0a(Gx_mcU`lOmr9x@Bg`I_!$%${h?c687*gIOap4HWg5vh6XEz{P={KCal ziY16*%$Icjq1NCI!mHqaV=)_3niA%wh~7S$=Fs!6aX0N4 zMt*bKa52qSO4z=(bv=v-Fb=17?#-_I#R$w}r{e2mY9IU8tC=H?ivgu(s7Ihotjp9m zI@gW$R86blSeSgM38=nA3V_4SaKirnc`q1PcpuV3MRzFspYJ`!#UICgttW0%~! zilpNHVL-x$3V7F(7G)|5V&`7yANY7F5jX$ze!U#=Ep)%kyE=_OePA)oHRGHW-=B(& zllK}J>8{<{kC6VH<(S=93yAeg)l~V#Z**bj!XE3a;eEw)`f2(Q^ad|HGR@SGHd5@a zn1t54UGa;?Js;-NJ8d-fl#{-rjUdwycEclWko2o@g}+ z`f7-@NFzwu=JzZ2xTK+!)R&XiPAU3*vI4J~VzH{D)MWu^@4a6$0-TA>h$dcfjPh)x zRho{IeHxId9*QFS`HCB(jP;Co`By}KdeTkf%kn1k1RYwuTDj`R)qY1I)2w$Ee%0;o zZ#n{r@$5r3C#TDF=!?f%H4ua8d09&VNTh!;vww%hN7BG2)JVo<;@1%vH_SY_2$&(> za#rvHfqA`;MAgf@xOF%h$uzP1vMcBC8{t8v$Ao#N7vi3Cv99hp>Ac)bm2)QF-KL+n z1x!G6W6~08H-;(2JMO$aq{(*RvltahOJ%-k0p1zZcyYtvWFY7kC`~;N_Oaf%o3JjY zmoOf-A}}sI4!qZAT%9l$+gyz1_%xiW{5Z!=f*G=cBL#Ks=tx<=f)KqkCpTLnz(Wx*v zd_exa1y#3f{(5WP?8-DNvsJam*7ljS-&m9xYUVv)1q4IX>{KAW!QGM7JvFt)F(fL$5Wkqc2nU}^a#n3G~J6p2X zU3ga|?wxwd(?{}4flS)d84JHJ zu=l3Pi2k3kUz6gW!ZJnqKZjhQzVA|k1=_z^qJFXC-U`dxUl#LVh}yg^U>?bPp#OhH z?%@iiTF%#6^#4B=7(bYPyLXG(0P!jQpLxuwRwP?9oZDg$_?aK32BLEuoNL?k5-Q67 zZ#5FZoe~#PU(4p#!Z`%KS8cs^%E3W429W&Uhph`?LqgQoKmV=as|seKkUzP4JLW~+ zLATS;WCBajP{gjc7Ghioi60WANle{2hQawLh!k{U|NHs>EVUCiP{cx&J8Qz`|2;V4 z{cEX{?a~<+Zp0Jwzcc^8Z-GN_dr-DtRbbqc=|=qTy#Be60Tn_2dtv4@M8{qWNO+Uc z0O)Pxg?}BVX3l@DjdJh5dU}_jR7tb?%2&Y)ozDQp7qN_7prtqU9x_^fow@*npwt=$ z2QHhYu0(B$3ApYH%f-gfp-Twg-#$}~w#`l|CR11)WS2#VW1rhle-m6bMf~60eLBhrHrjDiQAxV-+SsKp zgLIAu(@)rD))-~)t^u{a)2qeTVd1o#Lu`4u>Zv{;RLC!wZ*hPxG%`h17X^LjCly_q z+sVZ_$VIC?zj1b{Nt!b$E-{6U)asT<+Yf~o3DIsA+$S|s)>ItZRCiT zA46ul)zNutq?E)(gGP0L14q)sex$upYs_a_2 zT9R|(!%CV~;>q_1C^DtBshihoCIis*>VUZ~>C3hIV2C72i#J2|>zvK&|4MXGx@)+p z9LJ`wjr2O#s>jz2<%vr!tF)uvP8x>tB##ZFCfh$xTlb!g7$2Fl>H1tfM_I{<eQ5N(1aK%vr;+c(d>8RI9k zx*W>7_3-4~PuyPTl$%V}TRi;Hj@jHAA*)T8Rm`oc(t$_ri5)A1UCl{x+543tP0(eb zXf@(Gj*rEHLF?-`%7?ULOjOTS?$q{_o0RWYw-a*!(^z3fXjq6$rUIX}ch&9n&>PT7 z!Sf5%yn4t(G^!X zvCV(e@-_gzC44Qo$8b6&gCeK&s`_*qg{0goJTbc`qqnQ2_vq;(@)C_Z%jfo0w>v`_ zP~Q*BY`6lf!B}KhoMYdoo7w1B0bwAd z-+pC)9YKX9oBzUBD}ey}c^?6kO*mUZqBQoicK#%4dhT_&TCd&f>}5(9tTv zPv?5QtfLw5^bw-{&y7lMS>doUr!hPA#H72nHB}_}Wp* z=-JKh*!xT~SV@Y(#m(SR^SAr+#Bs^|&@Rs;IC}J+&BYFGSHE^OLgrw6KfT57L9S*C zcKjLXseJ|+=K^LQyvs*dLD|7bW$5+YzZT!WxxcaPL&DFXiSC5B@=xf1!^{PP-D;Xmmo^jYdSTo*o0i^a&Ko}&qh-HbVL(ZWFckh7?}?YJ}Yc@oLJDS z^;$$cold^Y<;F2^tq(U5jU&`iIJyg(9qif}`TbAdv4-kN<%qs}i{(6rY$M6`mZw~| zdco(JA1DKCDuL@l_N*0$tRwm!Ift!i3w-%lSyMY5rAC>kkg(UkWpJtPGJklVXNb8< zS7DD=Voz4%#?Gyh#E@Qt+vr?#@oFC5DTyY7Zku938#J$rG%7scx|mWBYa8(aY$pml z6`0w1v(x(g{n*h^xZ0&cktidwBB{=O;78ZqF5k>J0p{>0%;EwuD!8G@z{Qf;#4s%4 zx$E74y3N~tMXr&x*pq)kJhr;B8zMKGdVFr$x;|`?xC`o<{tHcvDP>NTCluAE{|B1* z`+r=yKi+ef2PVHQw>SZ47~A&E%qb4nZse@BFsRjbJ2P`{wTE>0>_L(1^KIDMlfNDL z%2R^VRmBmQXoa?S!yMr@!+OfJ{j`6&+@_ge>wzcHK*NW)7Shp8(>a>yJukL<`ArWZ ziDCu(^bo?}657L7Ig^*Hp4i8=MqF-p(|HhTMzTA@Wk~;XY7>8xsmYZ;f(Z}Sef)b+ z5ay&`YAiCSIeYeXzOo=nc}FRMZ$Qt7nEcksTfViole%*|ORxji$9m$lEH%%B5!|@O zc$@5WfgKxB0|alU5$6M5oQ2)|)6@e;#X6z_zQ;U=-lgBX3{m7)y8XVdW&=rjHD&Rlu~)Pe z`t;R^#zbEP?5O4LzIY2hY0lu3NO2mUeElMlAwAU9yWO7iKX0REnh&78oiSniNtEs^ zMj&*c2sJ#pQyp0WoRC&?GD+xe(S{=^(h(GDXM2v3aMw>vG54hwHLc_ev8g$_%3y1@g;(OBvO8+ zt(uYLY?Q}G->w_%UGC8V)G`l8>a3|YkFUHA-jt^{S6Fo_)$4yU!lB>!R>;8cv8^dS zWXIU7CtqQvxrQBo{J1<=jIWzP7uzurMWwP^{5D^J&o#4qEvda+C@jkP;2|zyE}Wh5 z-Nz2?H)hfo3aC&>KPOI5o&a9HX|?9lc$k*tVdsAM84ut6bb zIp9awC9#3K-1-LVG2h!nfu9II2i0&4f|jbeXgHU(#Nc(n}njD262N%^3s5|K$?s_q>8CIiqz#&=G1UeIHc0UX;D&;O^;`^Kwfy3G-1gGR;Azd2R)WN(vi<4 zmDM#=NWof8`;LT#a%dm8v$N~DbuZ?H%YT+*X2(f)IMKGP273$=RF|+u_DJhV!QckK zy%s2+xwsYIXMDD~3m6B@F|qId$B$7VLI3s^q*Qhni$>M2gpj(a4zm=!7`%NbFzt3& z)wk|RsznuiO#?Jx)BE;K!LU)&^}X)RCT-Ji!XG|45XM2GmJWN{5h}6?GiH00H`71f zGoa8ZaKgQ_LH+TuZMD;W?klY3PyTsgKIYhkn^W_LE$Fk#%jUDssn(Y+y_h@}Ra0$` zOA~e0KxthzIk_7qvELRX9Oaa)M|Qa1xfY5UCDq7Mh**%10|lv>#&Q;Uras~=`pVKAoQA`$%;dYlph3b} zj}}_0x`Do;kgDShw0wVtmw!cr3myLD+s^jbZLZ9Xed$rgexV2+axhrDu+nl_E-O*C zg|vKQAjW8ei)a?#8#^eTx8u3^11OKmC(<+r!$&OdCig z78@B4XKRCs=#KX8#*YvT93Ygk_eMwcLyi#iA5bT`X^($`CG$;{e3MJ^mGF*`e8c$d z_utp&kD|}8E1yfhQ?_%`i!ynk_)gf#ZxOTT&R%t^w*mG+XGWl*7$jp!vtv>0zIk+` zC+f)VZxF?=$#Y6O;!xLFZR%5@_?}+&1KtVNubYpQaLaE1yB2RZMbsq~6MnN7XXJbI z0Lk1h)CunzE!o^8M4xL09FWQR5|TwLKSkw_!Lm0xDztYEQu}*sF*3sWv-UQDiF9A2 zRX5RQ67JzJl%m}W6&wcJyx?*fcAt11=<9Pw`$^!tWGqfg$_xu>ESC!DT=D!}jO@}4 zQ*RYGJl_?3m4h9Rcgk0;6v$ADGaPZB90k~JGBMydn|Ntgy>Dr?=G*Z#+zqhv)MUo)TI#WtLzk{UrI{je;PjtMe%s3D%P*L(@TL1c=i)Y-d`@rX{y z0@;z$FSwwMV&C??Qy1MB$~)2$y6k;E(H_7zu@fGJpa7`I;p```-L53HaPMaA=zuBIK6@HSDj_u?mCm!Q5J`wXPXdcin z?wKIfmfh?9pzC<;rc}^6mZE?S$GlDChOgS{%K#xA`ycqBe7(yO#OgO4%m<@c>2MWRy^3=Ls77j=3n9zTBgP{C@j^r&c+WQsM`C z`7}4hug~fs+p(F32CZ>)mavd$J=B4L+E-3pOH4L_M{r;1BBmp;^?0i($I2g$#SG@1 z4yUR3eGkr%wT-uiaXZ|ENnRb~cZ%rm7XZZQil^nxvi&7~@fY!|szc|PYA*4Ze0K6Z z=gQSqh3i)Qa<14`R=Et`^T^a|xJ6^R6l}c|ETII=bn(kF0?GK!52h%it7*qEO8(b3 znB4d?%l>jg6;Mabu6-o&n>%r)w_>V~~ z)yA6>W*Kt<5%WYrx4{LNu(Fiz9|YNMBPtB?tdY%zGsUoRg@o(;K0TO{3PHLq4tK85 zDnBcgKMpV%KT9tYrcf?ArJRto4AEJ;gr$5+dYd_^9kH@ikKau8#T#B<@LEPbZFq-F zhQ~9_I#BO*p=m1k0mRpYIZ)XpXUC_DcEQ>vbu zSQEkIZ!~a(0$W_e%7W)i3pS|$44zz|74p%)g*DB*RT$GjR{WO7^JGDb8EJs!v{1GO zZynE1NV!~1p&jzB`!$~}1n?>OpdT9x3p2=uB9`XiUIHYIdF^Jvx0qwsl`J>iRC`P@ z1RQhJYUXqbTDpI}H-pgtDA%p{1bidC2;XVj@oB%kb+a{~AZE&YWVp$(#dj*O9Z}iE zA-y}mOqG2kzOB7Rw0pHao=?}d`SrA%*h{oQ?^i4bnt9y2w=7=D00iT(@`|T=;VX;yre3*}K5o2-$3Yx@qQ^$+w#Ho;$j~1}Xu7 zOSZZ8VJqz0+~!eRwJnckPw<#{XNT*xT^o0ycr5V!+EX*Pgyx$8C8m1 zrA%SoVnP&dA}if~n#K|RJ>-#$I_%fi_3Iz6pLvAZhtEf@DC6aV(ysIUYdHUVGYSJU zsvx-XXZ=}t)!l63pZLbXY7$^~_$==BWybB!p(K_;)Tg` zT=G{6w_Xvp-3s@nPi@hq#WQ0AkJ(5fe}2Yc0v!z)y+mN2gw#?ICm6%|MjOT3K97eNSQYpvriFBcVG8Vucm@R zyXFrS-*+ksrFn!|+h}Mlu0GQIVz)PO9+Oh7Bx6#~M}c=On`^+h^?hkZHBO({K@c8B zNWmrt2jP7Ohnu^At5PTmSwt~cS{}ES@l%ZrGkA=ur=R|?@&4^6A1x3@oYotof#^1R zg1LdtDH_eyRzu9yc?vHTaD86C?ac>KmW}hOP&PHDjGc9BnUH$pNaLwS@U^ARksx1~ zXl&(qJxjoj903|^F`QYdTOT^!Hn6%IwMc~8)78_6QQAFZCvaE=X5F49*;dX(>>^^= zsA>>zaAYkth4!A|1j~oLP?fHk#jfGmtMyf1`8XQrVss5VV)4um@n1M5Tg?{JR09Ro1PC>(=p2)b~K+4-GGEd&VlEoRBtcPS_T%3m9^0W zOub4Vm$<9Hw&LPA%4d>kdCxsuSFPB#arJo3;)-&4Kl2lBi`@j@hYvI8=tLB;5fmcf zHPnjj;S^cq%(13~?m`?koLG|vN104g%tnh3<`d->ek*8 z)QtCWc~3O5`VRP5Zut9nSj0f_ zJI0h>7_2uE9jb)y738WeF=mCWo_Slr^f}ou-qp6hkciT49sZA=HJLUqY!V^*FFi53(V<+T zKy4MRO4tyFlkO;p0vGzH0ZIO{AH;B~)5XdNj)U%(gT-C15qBzmU+WtoMv?M2;LT%R zkin}Ji(o-{{|!y{0h(>vjr-baaOnpdjH&EFtj_CWCsWQxEpjw<-<3>0mn4WK@&eri zXEW{IBRX>2fOeYDYdB^5Bd2pe)~@V~;#4n*e{4%uY3Gs{x-RU31h*d-)EK})EjecY zjR68GFshQM1e&X-GS@#c5*!&_R8&AD6gm1FC`B~y;So26VhQ;~4juRM;OcC%^bO7krSSrPN>DEP?weZwc& zx*e*;$q_TUGTw76xXgf4Sd2IG*$_*em455%MjPNTFk7H2=BJ zsFilvHl(%?-pdcPNosl`eL6G!ai-gSiZ0z}*|M48vH1>%x!BEaOlSWKELSpEEFuz> z4WlI!83!tbmojm!-gUEC`y67+(LH%dlqPBFh3{f>!6$9lPRF>-!1DwbF(t*r?p|D} zuw{;hAWs3j|JO1VJ3^b_-Q??Q^!Ag?-LE(8LcH9 ztfl5Z1pjgq?Sr`Q84Us%!6OtsBL0X5h=yG|O&|;W<=z{NwHr-5hdjDay3Itao(z?_ zYY;1gko{xc6ja;E%US;d$f3$W>C*_+G|tA zNlg}#2^1v_TBQTYC|LTh#e6^vTr9Y>C!dpAx5v2}WkZiLVzsk*U6MNV1_vW4gHvQ* z0**mu^Fc-&?mg#k*t)J(L9y>Yy5At$4=_wP*0Gj}cUAxP_N5275JL{BohSs1Upnxp zZZ_zTO%22mzLC!|L8rNyF+)`gp%B<8-f+w?8#f-Gx#u(AyG@e}hX#z;zvcOLD_8p= z@gwYO?WoM#4k*BnXmdzG>oMrSmTWR!Y3&(J0Cz7U9Y~-z0-l&oM|{}_tqLCT zZgPS&8;JS73y=NPjw6%yzK<7Cdtf~cDbuFy!TOUVnO*stptB?-mHaLIAK0&!(UCZe zvk4NlmpQsk5xCvlJsGy5(o}}D)Hy3m-TOm>3PZ<-SxBn%D3OCnaq78ie=V%jS$BUi zcJ!t9#0OH%z?0XpjkBIaj8wATyXhaF^QPgN5uj42z!f0;8*3nmOejGPZYVu|WZxH% zX0#dk<;~h`TyFSmHH*c*YecB4b$D{*LshNQ#FTvr{!{B-aFTNMvv= zic*Tfzc>6;04{_$tjYUTH*77+TuRxVzCuquG0>!FT`>LLavMIFhm?Ypu0OotR|yXC z<3Ogs!?m!pH)-LdLix93;exdv)uKZv$w;H)|d_Gs?5B>F`hw6$Jb@qH_qA^|o33|Bb*^EGKG@fb%Rd?Dphir?H zx_I;+lYFoe9>ahov+cO|K~<@r3^rWynbeQ$kSR3x2r@D~aQJT|ma9g6`rs5<5!Xaw z6R%?Z;%V|ZFHeKur<2#-iUOkHO<<``EcV7;INZ0@$7h6A?q@TiZxm8TU zOyAcZ)>+RVMqY-m>DlyQ3?q`|QJe5~uy<50)A3t29B?@q87v}Q-0}oNuYp%{li-O4 z;zwc1n7(YRFxk0hP@D-r5(BK#V-mj$*U*h720lIZwEI1KkCMXJr{y1UVIS(SAkaqK zFID6M?d23*jk~=1PluC7E5S6q{nS?wM-Lt4YDYC%-dyUu4Jh?r;uPalA0L*>0J3_u2x#2w+!1#m zI*<%1kPO-f_n_kOu&Q_O;r>gld0mN1n~vtyV( zQeXL)KsXlIc-X!F^YP54c)*=Imq2oTGV}oDdP6XxBWQT@!nh4<@=K%?bvV9Gj2SEf z2YIuGm`hALlKCxZ^(;G@v6(WMql^+=6)ar_OjTw5&oGAPs$^1sbu2uV%&_=Mo}dY$ z$3qx4rP(imD-e+kd4FAM_&oWP8aTs_g8!?rXZ7SA!7D2<>BPivC4>=VrGHtvhoDJz zL-cnzxsXh^OsX0GR1qn1uzX#f8buC7(`=^8s~kMcHOmAA7_A+4*<=e>v*S{uoUCUj zLn+AkJbQo8fg9C)js08-2DE&oI;6AhzU^HXfu(|2fq%eTjV zq;waEh;o%h3;gCuUnSa32CEqU8|~|c?kJoEy=|pE>aAbse@0v+62=6(ywggh6h2m2 zU{4>!yauTl-lvL0ZL-m88on1i;D(0?rGb|*))!R#@~YGisU}`6LvvQvzVb7m zm(I7zd-Nb9cep#301dMD$3{>Qmo3Enk5-kPI>r(KJLBzlF_l0!x>oB&roYRJ{9eS& z@r#N3;O|K%v90F4$LAh38-l5mQNBa0+O~xEOT-{DnaNUGF z^>7Q{B~5DXAeb;5BGey)s}qjq9R*A>(s8`A?=Z}J{iDNUNGglX&QKcyepywowD^^a zbPV3(9|`eO*Cbv^UGV>6nCdtHQ=7N*Ia<^?(d>9A?#l1P(XZZdw|>hb7^|>_At2*1 zj^ON&1^C*7tgxZvoQlXMLh<5uZm&Z=e3uO;LEh^e)GnybxlK&m_Cdy2V4>^hXJbI_ zhlCu(_W7Hqh2V_yZ}cwywbuOTA?AYbn6H97Rf;WmcT`^uS*1H|J`O1@8{BzkFmGI0}e+tus(wpUr%P!~PMOsF}Kp{lP{N!Aa>emtYz8Ek?vOi=p~x zqKhviVPT_8M8)xI7axF%GaOIS@{EAY3sup57l|0dz4C&@G z?UTDt$*ZUTvblI5T;9VVu(<#WG@27hUe!QO?t-y3Qcs!S8q$3k7hwnsjs6AJ$4GD> z)I!oVOPQ`w&UCd>rqjxqPAz9TB}^JO5!20ETiz<#_q5Q{LP{GLZj6HJC0=IVXMFYWdb6zIQU2uc$) zr>m!=cp#Uq&D$gqozrT&JP5e3r9ad`@wYFJF`=KA7I5DY=@mn_(0uT|>}#6a z6|{K%9|=yD++Y)#;%q=ta=p`ckanZpp}K8~OpYe9W88gQsZb)9G}DKjbAqSKE-kEO zKC))R^l^JK@LTSss0}nDDv~5~w3fC`xvAt1ds6R^+{DtB-PmkBwe=^*3s^t(49$w1 zz;GPPu?$ZI_^H2mk1yzLTSpS6h$d#|po^wQC*X@9I93!zmZBJzpqYSRNjZA3q=&Kb zR+^dTcet-r&dc?2MFmPq-#ubv%O_|PU39QP$Gb{>2POL;d%~RdhvDJnveW z=RN*n|EIdZ#j`r0sB?-*gG@>)#qfkG65JDA^94`uoTQUwEc(YAs-}srUw3sLIU!5g z?<&8oYi$h9QilWiGSwG73Yah~?XobIHCMVq|3Y1_XhBzh9B#eh*3($bJiVCWKc59- z@bS&mZyYxx{TitOZ$+(>aQR$q>(PX%_o$dFyWahxS_&1kwYN3@viik`(r@g5XZv-w zlCx!le97UlE7=aIz@6*#cw;jUb~(L)mUb@w>4B1Gfz*SsemL@zwb|Tz*|@m(4?;%l zui(c_El=_ckP2)7C@iHBEK6wgnAGae4HjeLMg7x(gn%Pq`ZIrU3%b`H)x%pJEmzFSS?aYt8yX5$?f8h~_o)8s| zVP#bW0T(aX*|@v~^Gg@TjcoI1kci+V@)j6|;8~Uf5)dEVJ5=brCaFjeO@^H(qIr7# z&nKO;wFs0L!QhAbWMN6$(5ZtZmm9cj?mXv|&HaDO{I%(AX>jiL3WLjfUN#y!nwyNb ze%*aUMxZdFL_erNq=2GvoJLU1n{m7UO8GINv^x65n?on_6FaO6zB=8agy=rl=3vkB z0GExHR8kgbO(Pg7p>0<3KLdB9x6{8Yugl!3a=9BD;q%xs=2uyy++>K1c6Tz@iJfoy zcSMlYl&89EBum)xB@b}fr9AsBz?LhyQL$NKD__1d8{$?|7xR!M{Huw-H3^)l#j!*I zLy4TK$O=i4msZlzQTOeww{}T7?6IUUIB>S!VE*~noV%X7zbGtnV$c;rDXb(jKqe&a z*SEXf-*U#=sWDMY=b(KW4!R&|V=3Q{LTDJJUuaP zr>oiY`p`4mAI4s+QasHHEJqSFMbV7Nqx{=cUDoy_xzBy^i+nXkp zCV5##way&I;5d*^>}`HH_WR~{Jqj=4O5AR$ij8C#o9tAltsL0s?3bV28CxBx@4Zz# zHy*^E9{ZU0o}Z-r&Ue6{e)ZEMPucqC^~|?>yvL<{$u+T;9ptHlopy%@xX?N9aWZZW z3^KQf8Gg^dYD>HTMxExcDPB8dn+i0$0}OUK3xLZr?dy#Cg+zm`aqzravz%J4@bf|D zla3dYr;4yjHw2y(OWxz)LZ`+lfq(B&h<1;)QNaWAC~3$Qwn%%Mr%VxcpOar1{Zq+85V9 z2L!N>VNt~TDZGtoB?iX5Q#_0_aRQJ@Z~nn{A#!Qo;L= zp+g<+w5vmbr_kjXHmv}hZl7__oZoIp#|0{r#J(>)%d0XLvi>Ldv!c($* zTHtIhFsTr@J$)T^&u}TP5cHf{;M)4@sMLe?_oXHy?7&Wa*V~T45H{2(-Bgy%pC%pm zMmf>S>xFNs^&? znrC>LCsC$;akX$oOfZj}rF0#-I3ch(6AEnXk*@|kRg#OJJWBY7ux!9tlVjM1n4*TyG*3GFQ1__{+$!e9hTKPGm6Lg1CP-3duA^JtMgMwJ!d(5+ z{O(sak?t({>es>TOFv`rbxXzsU%H;o&2-j#XEpLYr}tuOeKyq?<9qSjQr?R}iZlfI zj?(eXI4dw#S2{J7pO zlg!f3e1oZ9xb{?~V}8OW5Cly|W_pOd>_UH1~)7!-6J#tNlpn;&LV zr{3HEG9~pff-T+BP$W50&`3@YWGS=b_HpYc-kRR{3h!7`CFO%Z_uX%P@#N^Q`<=&W zols&pt&=tSDxHQIxckkk*ED(S%->MwWU$|fK-W3pIaW}BMhOhbUeY=7Qex>EFLU1-$v5(r3 zdapQHj%O%};AtYj!t=atR`W5YgeS~fHmpb+oLMJuvAVnlo-S3EWR4L5FLTV97DMkJ zf9}m9YtEZX%_2T&-bFS3lp2x|I2=~Gt07V(U^Z$`r{4O1Hg8J!}Mt_l?3fWi|B zpm#p{q*#)op8XABXv4N@jX8eoiSNIAqXnL#I^_x8{b|q?hmFvHMoA=T?Q^`+*Wva^4h1B(|6st3-DeWllv9S2Z1`_O zRPD2J0o^fUqg`@E!5pJMhA;+s4mZe-2X$4rE*Oh?2MJ%rNQBPWMxPq_BZHdgHV zhwVc92lk6GO#N2qm^AsPBc;!?k$lT5xtMJ%U3()fkBo4h7{l~yX19e6rxb^{0GVh;PyQnpHbFz8EzjaKCNvqulRiA@Yg!R3&TFe*E`S`qC{x2DDbi( zu`)}~KDzJqtwjn4-46xFMKYWie;H1FL_v%d{L@)T`gO#{bt;lRi!}5QlCEwHo&F2y znA1oaIcXQE#6j4Aq}L$nXOQ$$Ncu^PAOn}a3rSBw(sm?0Doi@s|Cgu#jfR)azc5XI z*fJ@!pFBy^C`q6=k*C;NZBATVo01qC7vU)%ul)0xS=f5hp4C&JL^_BHSUyE^HbruS zY{gjs)Jv`d+^8bh%Q2CXnT_Uw18US`C&Jdw3))(dp=g2UNP!ipb}ubHy6gxS8>xF( z+EzKFytobTm|MR%cSw)-VHorBooZt@%`+NWsXUyjga#zo!!E#Y;Q5s zebNWbc_5?-G({_v#8Iru10tvi^hYtFabVwXHUGIKx%v5%P^cJ0faz1Ia!4+hbBawC zNtGo?ffMNfL!qIy!j1I%=FZy&C*D(}A~`bXNV6=VNW3V~JWr13GG(YYE?)v75Gt)% zePCTaG~fG8!P#@0@ODugL5MU-@C?fe1Q(#Fw?S7%9oGg|#HZ##%NlRpmmZoFDFjPX zyet49@)IXM=;x-V#h*SIbl1%KrEJ~~v((Pggx=gZuz8nmP)XMB232w9=i5E#?RN_V z2Ntu-oJoH)t5b^*E}t1qWeGx{2~w3%m(LSo{4s=ZE}z4>EKUlOP7ISyxXkJJFzL9< zlr|c^G{5jd=FMOWykXj0f=~e)N%7ukrQ|->MBcgP`U$DE!%Wy#m~=bcdar4O>v~9a z|Lw!i(VW;RRw6Mf-(!$uhPR^$=xx*Z+HC8JY)a%RUaOM8f?ulHX<(I_6#d5 z$OAp|Kt6DI+<9Bt|I>Q0l#bry!R<9m$2Bp(7qQ>S^u)yshz&F3l?A8^dz?;n;57fi zT>t6q?^HV#`i@x<2}WTxmg7Y2A7a6<&f8xw!s*wGkMYAOl=kKc%Qrje@1@)}K}o}&#BvPZ@9;1~1aUw*09sW+Y-VrbH9A5M`R zMRNp&vO|L?lOGN&;<#CL{!s7aWXLNdCI#>c0z*)uOafWriGBrJn@(T)Q!*q4*1BcG z5Z*{Eo-f}0wB98sem)Z!^+ibM-G`(XBGdO*49$Rm#&My;q}w9t)?v~pO+wr)88X78 z8-z*M36riJW*b7&(f*G1ceKBw{T=P^Xn#lh8{gk1!zuIhHXU}naXf+mXPhLfnk*`$ z2*hv!&YBuSrz;9@<&?MlQK=PEKQtfQ0ppZ;6n}5u2M@quxB)*5GGJ6u7JD`L%zvX=h;XK43_G5YHJTSxnF|nTDnC(v*ifR% zB^!s{BcF~7o;DiJnQuJj$shh6v@e<(7ew|!FgB2H_hfrqc1KQjo?QXnkU~Fgc=B3yhp?tUb)fufR4^r8sm4dXC-g2|9zasBw|h?)x_e>N|)&w5$| z94B%#$#Mw`KmYF3u*`V$wxE?Ocn9Ks#{qo5wBMB%!daB!jG}Sh9X3{MeQ=y&f@OX} z%n$OY<|XD#z_g@QTH<6Nh@8g2X<4)RkfUEd-#Q@Pymjb*uS~rY zE5&CdMUy2UbDSoj7K1URraLJXZbgqlg)KrWSkMe7P>Ra%l1dMG`}%)>Nc*kG!{hE! z>d@euUd?hMeQ}qUjS(D|C`nL7krfGEQgFwmMwf}GH^QVFm9c&Y%UF+t5qEqI%h$t+ zoQJv>c_autF_d(Z#3`c4NE$;5BH4oY{!4NAnB*s~aE{~cDAN^%C`6&kIQm)^_n+@= z{rnJ=HOvci*OX5Rf(=Y9aAn(X0WqiJ-r2Tbd%B~HCF5A8&JnUC6%{zQ>s2yR6(zfd zN&{(CRPT*Q{aYgAoQ^!d6{%-uOg~h0JFff{+|Y8Tx!Sxz$yiogq*ay`Nl}$}4rRq5 zSKK1v;u>43H=%EtydDl{W)Ph{UhCew_Ql4#s?SMj9wDn4 zPMZ|{9p}ZgK^3jBiW}1=7E`?s`tkgk>TPGzBLpH;ui;He*Y2UFG z^GHzugCJH5CH;O$98YqjEHR>_w7(IYocXOW4W}HN66W`ma`szU-^U+0T3hUUpBdfA zSwC=XmAIs!yhaNiujlUbeQ&Sdb8Y`rxV-+-2k>1TKc(Xu*zRv*X=wao-RU$a8=qZV zqMC1GNxJLt|BZaC&-p}@07iPt818m5T)J3Cu&t%e*+&-CcVWE}@jOlQ96{5h$Wojb zpjoHmYM9PwYnhaHV$t=l1X1-bc9P9{%d!__I}2S3=;q8v{m(#nVim3#R?AQ3w|iVX z+yP&VuPm0MZ2i4XXfF8@A7Vp-#T3or}f-d3n1=H(1joWk?JZ{Y*O&DJdi@Lz=e!?YSdRC|<&$ou4B)iu|R2JTvPY zpAN}?q>kk9Wm6XJ%bABBcn*r4mYaf!om81uRN#&1$}nHOF05Mf<%kg~2#-&C3`|Qxp#u-VVC_!c^jues(&b`6wY#c^_x;^pg?2K@t;IHAHp<|rk z$y#K`Sfmr0aTxyce&p|vDaSgL2-+7z4*&eL%+ zhEYyHxFQIsPw*45q4{i7Lk*|he=yGf>==drDiOQha^}-_4Cy1_4dom07{0_Sy6T?i zbO7k|)vHeAi?p+U^)ayLY*W+j3YN^&iBOVNQ9j_}uaeO-R&l;p+c=~ct_|vDtl;;` zDiz2;%1OCG`X{}N^?~y?DZ=;aV#=u*-AJzL-7m(_+0x^e8H?Y~gDm{Qq(H$4Lo>dE z_)Q*r-TW<>n(W%tLAYvf%QI ztKxQ5HN;-y<>AH|O^0(l5``#4AqsGx>uh<0p4PVDGbr*45=z;ptnE;31jPeN(g;>m zsJf?fYp?z05kuWDr`L<$P@n+&WZ-)H zPs0A;PZ>$K8cQc}K;7h^lA`bQ4EpPB+Jcey$0r2;9tTkV-BZu67K}qyfe5e0oOY-k{7;JQ={&Q1|q+=z9 zX&?)g^5%jjIchH?aV(?yL2kd^LS*bL(*^^h7{nQ|5y4S&U>hZ z0i#mje!o)36Ib8H2(D}>Z#fh6jWt8x!{+MT*B?54IiPDSoz&^fllsML&vbt}S6iPj z*#`ggB2#cWFPQx47~CJ=#Df8CSLx58b7`Ya@Vn^0uhZYRVD=SQ&L)FD9nQk^8_@A- z%mRR)tw)%?Ejs>Ie_^j)k@?2Z>kqfiP|qq`kniDli;#MJWAw+U-TjyG!OMZ|*=Pu! zA3EO}mr)U^@f9Yly-L+SqHv8LqK$?@mU%t@89va8JudRB3RD0HhGYW*S$1ww+TsRV zI!?c-%kYmv27&deXS15BavDdX=dHS!tWAcY7Gv`NwjQ9M_a`FQ9S=kK?sx{t6M*9B z>UP_69DSzAF1z}_qZ8lCSh6p%Mf9F03Q?#qh%TonL?H@MxVBiwp_c74SD6>p#4?V8 z#F3=RklrZUDC0P=)O_kqmgZeLy)*YiY;iQh3oJ_jj^sq#wMOJl(8pM6ZnEqeRoEQa z#*o`3Fd4X}*))w-2?o$2$uM)49N4mG=lcm6m?EI*R&toFO4{8EL(>%}7B(3ozwI=B|aP+C2#*vq4N_UQ~>MI&l1Yd2W(qxb=uYR-a z`aaesp^m*I#cCQ&Gn~vbm%K-yXWx2knX{WqlSe$v2f!ENthusAfk9{&&%H$kAyY5j_ zbELP*dxaFvV7sjOR5jE`BDNG$)*MTt#Rr5!3GN+!k-Q3RB*~*DwcW#Rbh(zt*S-Gh zXOr>KJ_teJXjo3-;|iX5<6NXLx}_>@C?Iq zG{*(RX8HR$Uxvppqczde`^YoBlGC7>P-5Wbt*a4Gq|K`yJxp@t0FT?II2~?}t5ESc zU7u{9^5?OfGqKm}c?{8S>;E+Rry+F82#z1pr&P*Je++*=t_%2X(Wzns{nF^1ew+5M z{`*CpH+mSECuqKDll-4IK&=04VTQeajnLmW#(W3!#pRDaw_RZ(mHF7Y)MMe_XPXp2 z4XygY*S*`B4{VG^QZi69N#>Y0``y}M$C5`9V1NC*%U|8%yItjTgZ%TZ%5kHdz*o$7 z_zfW6GT?!(Uyg`}yY7+DmdL!!u$)Yhl*Y5`->R9hq}uYdMf#@|#cRXCeJa6!7ymKL zcb!V9{uZnE$OO!DXj%M<(SH&)Yw7>quln=3n0(&Xv4+tvfpt)Me_gC{zw;5g+&6mbv7#V=vOp1BFJAcDR6| z2Qg(tK&YA|l8UUMa-$W=IPz3z8Tjb7w{!P3K)6CbxfGCDmgH2C)KqD0=kEV@Xs|U7 zCsuA;X0koa^4SfYh7A2Aq!5b{X2>-9ZM(K3eL2eKy?|yolQ^AAI$4ZKebMxK0u*PY|3p?mNja0mt=qI+xtafGgm! zW9Mz}{Q?Wf4K{v~3>Z<<6oqB!nSZAaJy?HVD&$scBDmtV;prB~^)2_`UlgtAB}_1d zJjpY_>-e3M1yKbm&kGb4xBj7*d*mjePT4wMCed7~DR>(9I}SRQ@;OX*C}X{wl=C~Z zKKMJI8J3TyebV>%y`e*nP=dg!Bn3oGWoju9Hr*oL|JVfK8xBL^34Idc1{S(afh ze%9cJ+D#4q9a~b6&JvW(Rp{{8^FbfrvU{W)aOTlH;~$>9vq&@w6?FH<_@^OWTgu}$ zk2C;P0B&)acF*FDn`2qlW8k<$cR~Tg)IdpPJ|l`gb-&?~s|Qf>`rF+e?WYgFs`b^U zDK}o_e8koye_UArd50IGvB%0eV;{7<^33xuKSn_6vN;&xA{kCqD1l^TmHc&Qy7bj& zcgEI^u&55DeBJ?rE3V1&EcZ@HaXvN+?hBg}g6#_|Er~3{XaY$Ac5?N0e>I$!27{a= z>Y4R}#M>BLzGXzFD{A>R1UUvmj;fEI|DXD$0?u-8kA8`es~`P)>J{jsFAI3NakpN9 z^ZIu;>+fIG-|uhq{|@RN{Amn+T!nWf^^p3&bUZ?sA!GiB(I4-M&~)hxQjg9^zG(d* zK2<@N60l#OMP^(D<^Nll@6q5B6s)N8=P>zR>rn41um68-yrOV*0o+GWx<9+b z9$4G=zn(N2jU~3ok#pzGthf2=N8tVm({RroT_95TZTkm)Q}o=3c@EQ-qJ8)=%NO*l zl}~vxO4KZH&!-hpV`xzlSf1UR_FQU%PoGGGUVi`V=#PKZIi^E;x^>6OV$mMAH2k6A z|DG?BrWRD9;7DX&h4 zN3uJBYmnCF=Eu&v`nZbZM)&E{Z<`@FF8dHXWm)!n?>kP!S@5C+oCAGleu4LljC#(G zi@5A(EH^B9|3HIAScfAbDH1fr5VSywBoh#yVei+z;lBe@g2}MXa?!>8I=44m98-fX z4uw@|Qc(fJaN?4}R{P@W4^Bj#QsyIR+&yZ1gzuqsU1!-b_=$!0z1tKkT2!YwY)YQw zcH0VE&H~`_OtZ1V;X!>@EIY!*;!cb2$5hl>eZi9cf|Ay6a!7$OO_G$v$cjia0a}k= zyywGHbg$rJTKcC0i+s`2>*HtN`V+r4Nsi@sk|Ah@Bv>MFf;4^GH$l#ra7C=Q^c(Ww zP2aU`5~@`)M@y2*3NjBkZzPo|M@QYax8B+%>9A>?8i&S#6LW)Q;)Sz+X5J3PDK8m< zi)+2^lq3oe1jhl65v5vl{%)7vF(V$mUV~@WX62Q=mhnBDta5|pi92g;Ym^BWU>|=9 zPZBIj;%^@*Klew8KtT{b)-kkYPYXL^U$@+T|J<+J&#jG>T;`J`X>$Y5pnyA^O(xvP zy=}?Japdgkhb3B+ATkukPz1^HBFmt2lGIoDBba)>ZAl%saZ$>K&_0qFkyLq2Qb~s3 z(7L-4a6Pio!o;U7aqh_otb2*P30_qwLSrdLU{DR$n6SOR#d7q8#oOL#nGv|BmncJK zB#9MyN~CC|R+|$YR{fh$6q#D9AK4tl%f~;l{Lo<3`R!exxOQX^DKAO0wkdW`Zg!q? z%3#Tp+kYiF|Mb^?V&_$h2!AiDg3UK2T5+kD=o%cU!ic`|CqWffRCi zVjva16o}D#n#lHEv-K);C?31h5%W*t_5G&*o=`1n&3;uv)R}M;s$#yxmGV6tHiY@z z6z08{QkHM3qW&talkb=?{cxqzhbY~NLPgFWJa4nd5}$D-PkJ$kT%*J(m*Zqjl>jMd zG#&T*r>ULNq;!;4Z2!Yl%G2#$OZ>Nc&Yry?^eLWX1WjOAMIu=ZJ;kSnJ;m>{bieD) zRl@NMJR|GXBw%Gu;y8t-2+i`tVs*#tUPamy6MGx|aPKsK91c3`??K#1$KoE}^RZ9) zpTFlvNL1Th7imBLX!$FD^rU(D!A~yhy(Y1_G>#=%nPxPJ;166F zb_bjMUNuzx=?XI%4qMvxO{??zeMO>EW3UbqG!}?7 zkX4$MPS!kq({pWKNJAw(ulJ4%nqJn%|GnvV`S1h!>%;WQYd3 z`6gY2^SJ*00lhJ*El)8P9NzmDdihTqv42U zxiD|9FawIJjsy{@QiO0ReC4HZ<3oXGS^;?Ho3D)xmUpivhLMtHV5Exi70lViWAZg( zq?=Izgbz}}PLQLPzqW4cp5bT^$PpFaq*1EGaipwKj6lv_x$f}E5*Iy3Ue$@j2LB>h zCS1`cEX$T{n6PdnoSOxBF)E-Kg_T7~)o6Z=;g$ir&J-kMhB@t3HJBnym(>G{sgmo9 z=csPs% znzyIHof5}lhhx2KMEG7=A-Rh3#ogqY4CgKVvwm#6#MvG{nd}aav&cw|wt=ZYDfD>v zs{VGz#J-M#LXUfn_S1@fGYXT?gA}UXexQo^%mWxB-Sd`qBaaMy>7k}Um^ht>gW3~> zt*^sFQ`vb=j~iv>p3_YkSBa*G1PaA#_=4rzZVz>hJr~-tQC0!XiV~r)0u{e&%-!|Z zE-8|$#YappE?Uk%xSk&&Ltmb&i_22;Z6rb2WT!gq>HGd@+%bP!DmvBGFmv?NxX|fH z-wT&6ZjZsbOV`{iAGg^OIGxmqwWos5}_<| zET&rF<|9O!a(m z!SPnlW$j~ej(cCUgx(?G^NQoA60IM!uD0!?w9pE91f$Rtpe2srWOOuYWAje3a;vNx zw?E!8h?vtS<@EKEDA)!{UT>bm-27mdQvq%_%A*OJY6ZoC3oF&SVC1WDr|*D7eqN1W z4dNA1lu4E51c|!j9`(W2={wwaj55|h#@&Nx%pKNoN8Odmj+cG?(0HwX|4pRy--r7s z+SW&Xq_?Xgb!1x25|k{?|I+3!feF zrJ;f{G`(A_+b%+O@L`t^Z)vTQRlO(oHS^~imLa43n~qWcfzUPBK13*+V)DP7*|Ws= zArv|8)$t=peyHqnoKDPsyW5BVp6gTHQ(o{Da7On<2HSC?DY%GigxiNtLRWJ-&Ku$T zVB4Cqtt>d+IG7*q5&`j3!NmDfmsgM@;M8>g^l6}<2K ze!o}8)Nk6|{$alE{3x`*1ubuPE#Cs@v%PwiZa&ow*CzDs>@&1Zn(Z4$&&R$A^PA3! zxNr8+l_UB>{A#IhfsGvPoA44F6CH;t0LOWg-~LdbkH_)`zVUdNsGM>kee1bSU%#V# z^>}-O|Gv}g89iOfn>B)^9vf7Q3o-gUQW&n|m6-a${!GJgNYM49QIC>%u(dyr z)fIXFXQbYc{(h_P+XWpXJJi0TzXm;Z-BswzalhctFQEL_Vf1XTzhHb<=O2y*@4>;y zKJ%*1myFf<6u3`9e7a?_-~5BtkZ@jp@j>u?3Bn6E`SN*A_2It<_`Z8fr~C7D_V6X0 zp*gYCKbQskrtiC9L;UmEpl{T9xci2VIa zqCm(%qGe7*{r!);QSs|XG+kOK@Ao*EbeyP=@9@@J)vReVhdpLUh7y$^%7DclU}Z_8 zc$(2vfu>j9+Bxs5KHsN6EtwvOgkuT9lJ`bf=6PinPS&^XsJVmM`vl&71ktAIUfg)=H1%)=e;8fS5|Xt*8Sc3-jNbgwk~TNqfs;< zG=f5#VIPIdx}~+}gzVj`GV%TjSc0TQk`oAyVM#LJ0;ZOJ1el8*46`-y!qAVep8$U; zp#!QaHjdph^STdacKXYhTFFEkcY$a$WLevFcm3M%&5->II7Q?HLgZvF!1TT&CTo+S zoi+KU2U;(99SW{*!0UM_EK5m(OlZ6;?py!w=vKYhSX3K(&t+2dLd%6|-0$IFVHxXz zeuvXHXlGqAsMdFrQ|e(yG@s-cn_H0_LxH5C<0)V#Gi_ab^Y))ilc4%>33u4897S^h z;8pUL6k4D;1yEYe=0lEt`F!hyID~e^VrW@xgbg$r80(tdNAH=xG=iB$suB;pJ|0*~ z#m%f$mnq5yS}siEeh&v_^+B2xamTaPg&prnH}`CV2xt6lgjrjzMIBpeCI#Z$Kac|G&(9u04Rldmu~4sxa=N)8r^gbTexU_|Kj1Pmj+Qe8s}|AMI_#Ar|K`kUi67FEdITIRDXPXx0$})@ z+y(2pm-O9&;K0KASx;>5pYhmiti=N&kxthet+y!+9%en& z0*h1gZ7j)MQeoNJK)t_y33o-+!r;Ji`di)ijlTV+jj-npKg--Qcz0wu$RaEK4&SF1|`cwkWm{_L3;khJi`F%Ticd?cJv73UUNh8^c*EC zBts|+$F@1TeNN7snaN2(=vGBmae%eU^=sxEkHG1^9**n?Os-*=Ft`t zmvs0$84B9sk+Kpmb9b5y+14A!w_7{yVv)6Z&=~I`FOiH&NHR@G%LwM)1w)0TvW6>b zSjFF6ZfJOowyV5zFWWk|pw7}^okDv36e(HdIZ@<*q@i9vXX}v#njr$KW?0%W+$xQ3 z|H=ca;h}nANV9vMmRUfkq@YrALffq5e+KSIhqA!(-t<+~O<`Ju&(q47UupS`Ncjw7 z#K*`HR-^RJ?sYXg1WqI5{6O2fx;+D(>Lp*GwyCsaQzVa)+dWSzbc4i%k<0BRCRbLR zKMub!jkJzlS9skb5grG28iUMdffT(Ksw$zV8Wd({Oxd!8dVXz@lgg%P{@7p$o?dA5 z7k!|n_S=yS?j_{;VkGTG(x}mpilk9{Ni-1ga3nnpNe@BNgTkcII6wW6G`b=6K+@fj z^bJV*dL-SxlxcI(Sd6inw@mqV{vU8ezA*+$AA!J=nnVFcQbbhxxZmiH-$F{-Z!FzR zh>fN%OWJ4{Yu$6CdET+du|gYy6=*`#Xi^|#RA|GLnwuMMwO@Sk6LX8uK1XC(lW2{R zC`lyRt-kKwrGsuxNN-0|F!pE$B{fou#`7w0(!EuO!DDPF}U@iSf3C3B&)Ri)#BNA zb}qOp7U!kn734uR%U5)QUogbr6hsGL<+6|J{X~_xa<`r_(yC?p{`(&wd3m$y8Wj+!bd|BC95%I@DQZT$W#zn2voFo#`3g!HGZaNsie5=^*4 z@~eY13}_>rcu4uAN+gZj&$e-t6Mpn-L0I@ zaqoAlpz>3ycv_`IIDAG!p0#ys>-qz&Q1lwaZ|$W(T$h5|^_b=uZUkDp%Mu)~ zA%y20N#!V>logE(P?o=AoE=k0q4o6MsizvW4I(S?Murpp1H2~B?pxaQ76Rzt$t65cD*0`oRsKCZ_xfpE9Lqu z>$oPCb9_=T>69?#` zb*={0En3!yc54)_ouy$k+-o)D)lB%lWyr$`;8~s{ctRy4BIw~H(#UMZ<<7Rg^3wGy z4_Kgu7S~Xk6rQl!|VYRrwUv>9g0)6J95_Vo_x~S>5T+<`G$-4 zjr$#^1QY4yS2(4bz$V{kZQAeiSwFrDFQ}UZMgjGjkO6{M6oF-VRqfv8g^u#(R%vjb zhQ0j*qA}1-f6ztGTGSo*w$g)*Kpnqk(|vftPx=QVeHks+^*b->s^gsg{-^)=o1$}mn}+nyL><4NV;F-a+vuO)s2}~mgN`$kDv19@{2Lm0y~76SmceQP>{DNR28VA%(8l=_)}T~MvzldB3F@cwfA2*NH$bX z|F+fH#tr(!t()PS(1&_fY`qti@%wP!DGr}#?VHE_7vh68{jUOc=;K=xnXfaE{LuGc z{o#9gdOxkyz0ZHx&{yu-;i20P!I>PqeLo{NI&hq!E zSMTWf*~>l{^R0`<&;9z2FJbR|6r^`(k+kL6HP0Z20&I#*C2qDJ_;}heQ?09Hs^T43 zJYwzf+WVv4sSlaD%n)9p>Y-Ei@!d6 z)OxhdR`-EEAze@q0^mhjW4v1W=p9tE1l-hJU`?7?qvNm~I0(O|20NPok|tE1C4o!> zTb|wRnNe+d`U6vT#!p5l2+nhPy)g1U+$=XCj2EO}JaRfly?Y!((j$?2LeIHd^p2sC z_a{eKzak$WI{ppuwB8?i4^|tNhYQv48s_(y3Z@3bF$|{xX;({3ySE~i!Ta=zL6eYM zOu_rl7>42HOL-{2+>AX6Fmh|Qp8hx9e?FiGx#;_$--q}ll3tQ(Y5 zqv@y9f@3sDEZQ#IcM#*sapd~r_mB`3YjryN0)@~syW@J z9XKtiY#71|di|E@X*u3sAcbOBF77$RgBu6Oa}q;8hZyD~BmKo0{rl}m+<)^u*iYXK z4o=r2%_j;~3(rNnpiGci!Xn#CqGG&YG8p3ITlZ`k^LekjVFZzokB9H00vsB%AC>ie z)b_OnMi5rk_fh$5LJ{A(-1_vM11EO81J7PB)eCaQCj^^Qo&Xe2Uk`8%nhach9V(cb zohuc9FNeRjqr=MeDZfWuSVbWUQHVkmq7a2D22(k|i)!XZA-XOCzbkEo%xaa?j;NMx z6e>#C$O%W`Xt>5uL{Bf&s7rSaDc^4uWXBY8kRaClIU&AYc7 z{V)!Sb+n$g)_SDloSRNUZR--T0bO3ZJG;Z?;u(e(NKRq^#~ipY><%{hy=rhvdAE6R z99Ysb);kNEa3`O|YL&7)14K=s1dioUtx{OM$hAsWTU$?EsD5pQS^%?geN0iLZ79%y z3pf;CXeqaDcX)hl&yM-qQlb9NpilfYd7f+M>x94l^0!>6t!t#m%_tu~TilixtrNzO z{TKZUHKksP31~}6OG$=gIGLpgilwzjpP$(Ag`@-NP_cFFRA1$mB3u94x`rcE%37tD z4wcIIF}(=zh>jQ)JCp3ez=prN+<0)5(Cr{ALK z)iKO7`hR~W%F9IIDum+2zTVpC=u3pKBBbRf!!aDgD9@1dA0Y71)5oZI zt3n3GP&H1JNWdwAOrn7?aLx=;Fh!aSTdiuN*XHI=4_PFmk*Xr`8cAsZu{hH8GDV$) zeO=Q(jTX7p`uw5%Lh_f;k$+WDqZO5-S%Jqz{=FL;`S(5R*4Te@v?oJH{$(hNBUufw zJf-d$-C#|Vlp!&&&b2Q1XFlM6CQMn|tktK!HfqMV5e5QOSsDO}QVCID(LjJV8R4Md z2J1ts{rogz?B~!fU}~UUKt9D2wgSmD(eB9URp?MI*(86^>h})M*J@J@>iwJF@GoJY zKI(tz`{O^O{NKBt2>w2VP3Fj!JLDvo82@~>n}X+yes@GgZx!W7g5;x*U78`>O@u$`{FPw5Tsu_u?j>uAsM9B=ni85-clNe?y zg_~-X6;CX-it@#q>U?JXv5j+C-&;a^?iW~25d}?QcuxNL=aFYSG}szfRuhDnQvQzT zYIa!nuYK%X&kI2Ug%)pi8czwDL}?VKh;Xw*K zK%byIhoGr4O$aO{QL|UBJA86&ofKF#cnnNMMi%D<6!Za-3S91}m3BkpT|5WY@?a0DuHs!T|#%*()2(00yq zTSpiJTw+v}E+WpX%T%`dn9Asu0sRhd)411qW6L=Mw)GAo2yuI)oc4u+$_j))5)4T& zIk^jNdpJ2i3C^9~Y5v$?2%aupdHbwS4}ETE${eg)Mv@eGf+j?g;W&yDXw)s^!#YRz zFE$4Bk5*64z*_R*$YRRLnj!+4AW4?y(3o=N^@(w<`0_JWQNH-iX1}!)x%}^!Z^nx2 z6osb=h6F0dGpMUg6mYILiz(nw)`_otbYp%x-gziX5+qNMyy&IAB#+M0oAkWq7=st_ zll6%&*oEgCL7Cj<672ytlBT>4QI*`kV{2ddb;ftqYKQ5_e3L(haKI2ceF6FX0Omai ztHR_LxEK#vUpOn?WOcX1a|wRJLIBJ_GryXYD48Qff|KvOIQre6>hDVp$1YSBD^%Qw zBi2L5FT6FiX(+L@L};=o@UkMYGAfonx6&9C2bOfyy6}Not0&=O>5@FhaUvm-JSzw+ z6)^D%b!C0hgqz#HSnV5rdA}Y7`L@+T`8JK!2$7XojUlL+2c##xF>`Sj%>p*9*2@c88SL%MS8Xw@q<6+#Xk<;&Hkj-8)q1ye7#6yYI9y z+~oMxI&soWV%X!*EpIT7*R(*|m`#W5^H2^=rb z3{MaN(V|D|UDX3q#BWw(%h^9l4?~AhBe7R4f^C?a&jxO{m;T6hhvb^JZq~}DNA}%s zggPw87nbe-7mw}clh*#nCO7QV2ol2I4Z*n*r>m!=203bJM@yTl^W*&+` z=LUsgBB?SmyODl3xs3Uv-{G0kKdlR&942(Tw_4!#s46y!q;0ZOoyLuQF|9*~l?t6V}(Y_+KPY8;` z^Hcv=pIdOl%*a!O#J1=-J4{z(he;QA!Fg*!2kwuhXW&6^ z9{!-mv4Sj$luF1v)qbd{_Uw1sCO}$$Pg42DuDstznh$(l+Var%4_DFI;;=DN7X4pq zy$;XF>oXz{sw%3WG8)GVJWt?+s@DoUYpR&<@IqB%*0$A0zN~Hyv7@pyPmnCnur$Y$ z0Z}^bdR%8V7PCmR3eq~h*6It$G5#Jj?4+tnv_{A>E79V<{skwNYi{Ek<&>UOloTdX zK*Jn%4dW3B=ZFbjP{8}WOl0-0N8WF*kLc(!uIh@86nmwOLumnW)4TPV>eBmli(Vmk z?;OrK)3q|b71bXoGz+8ajeFjrPw?Nj^!8tOYr6ZVN9fqz#{WB67k0m>U-85H_Schx zzXyLutMQyp@^Id8(dU?E7^-7_Zy%vp7e23!`TlYNe)o^d>dhYBdZs5{aKW&Y!16T7 z^BgBqEV>E3`L-|PowabBVp7&W`LRF$-48Cx!Pw({pq`@Qbf|Xko%>BMzWdm`G5^NE zgW8aF`a!ReKaTwToSc=|_5v6wr$&%-nveis{4ITO07^2INl+F6U1<$kuRc8G;TQv%0P1TPAr zzyxq_83TMWD)ZfoFr!#E>jmivYK|wQQ$<3*i>KYxpXy{Q(8r&J0V6Y*=ba7ppXLY@Q*RRLlYZ6Ewif>Fsn&b&y z;y6J1BB<3q*pe~vwlP2UF5nRDwCpnW0D3M$8Q0!?x<8f6a0{-j{% zTeZVS20{;>J; zf-Q5vkt!>yfTsv;#1DTEyLNt<3c16o3N?f$hUTmjpWnIt13sh@A}tG~N-G?r02!x* zxH|^dOO`BmQ|8M9De#CfKA@NE4!g(3vQ&qQw;kC0=B%_tL=;k9(Mz!`+?wUssLYw& zH6kS?S)>_2Ne-Ly!O&P_k~mirZt6PHJVWfF+ltH z$%l-7*ns>VI59h9B_+)wde5$pV@g;8l1)cb1U5S+)MDp@0OpsaNUd7oYH3PpfX$~8&i4w~Jjbl|w+SGIV znsJ|{qc?afOF_;3_hT-LTx~FKehV*{WCem|D4rpBhM>8C%j_**_%i&#h@+s_W!?94 zlj@&;4k9SXb5Sy~ z6R*f3P*oN%?0uZt-D|K`4Uvh2!(xZ6Cf+G4W&JZ7?;8hY?|%i_7v^)EPv|ggS^?;u zYtK`~O)F-+Jm8M>NpNg$)+MoeAgnuw`f_Qdi zYWqaHQ(@(frTcx~#pqv7>;JQN9pF(EU;OUUAcW96(wlN+djUjx??q6=Wy@@GkX*vu zg`%iPRTM$M2BLzf2&h;A8>nDGP%Nk*iUkyGU_mT@BW^Z@u zn>X*hc{5|hGprD%uVjW#^V^ZeFf5)2^O>}>h;C=@IXzPO&+?g7D|a3ax9i>iMUgG@ zdTV-VQmLqc=HFk`zDs8mwc9h6DR-KsgFTU7#DU<>&CyR3g(t1}FIL#n9v)tUln12; z8`3Wg5Y-RTMPG}ZJZPnB*u&>G2ptjY+FQ;27BqaV4yRKzefS*4`&P1@7r?daXk_!b z-EJ?8?jAk*v56xaz5usU!?rYk&`uH=-D)vEVFVq?JNh=|^<*_XiLbOh}PFfx+f`Q=@E{!VZ^ ztSQSH%@~rT8gzt5Y}|(H?Of=~>8!QHu83)@q_eul@&YZQD`JUS*GjVMm0OLQSK8row`F>?w+IiNWgZekoZC0I z`|GK>4I>SWrG^BfGk`WlUNnGdyX&!6LQ5m)R8J#e`8A;7&inqBcOSa}uaQfPAkh*h zivll+OvLV+pRL}Rhsk2Nb0PD?gIjKdbT&OUoiV1!h`J$BjGzzMaJ+MfA)x9BZU`q4ARy zM&`%Q;2++RbW5>?^GADlXtPC+$9rC0B%1H(%CGF5s5<8l-OzR3Tg8U2sLpCSD@eS_ z$vRI1QZf3g9pTp1kmqpyafU?~)~5Yp7Sa+S=sgH!Cm}N(&iJjUmX@_2&eitE*+b@7;hV^GnW(c*jq|*JPgi@O z`39}9Z-T!=46!83N39Rw#?!&pb9mD{{QXlRi#nAu978$*YJuU}0*HxyB8XNGNP+6YgIFY6Wj;3UuLFJL<7H5>I;Ic5C z^V_H8^POU>&@ep53KC6Gv_!EHD>ThsEUMjZtjLq))NVTYf&P0jEkvDvzc zSNHaxa98b<&sAHCwAd4f#nKDKE{pMBZb{g=mgyD>SuV>uu)pkmzP_MQt(tDXxHA;FnqrG$0~PcD?^V} zj7o^4i=N{*(h7$n&!HxKEn>>7hxAo;peTeF1;UF47huLpS^ME!ZGV(Eyk-&1 zJabo396Gb^vYwltC58PCr;+2 z7!Nl_mR{4=bMkyZ@r$C#@uI=YtY##>jy=KId--Dvo}W=U(&QEh`V}y7_OR5|rEP41 z8;ky&)@5-ao!8#d8;#jYk7ZACWQ>73NucLem>)eS6`gA|3`{HlfnXoi zXXF5XSASO8h&$IWpR}M#o3rGcd!d1xlS|r_fZ%M64>C>&zat>HQ0cAeMV>#Q9|A%T zr=EW1c}DM5&rta?&yo6Op62}R72MwE%ebq0n&|Cfn};s6`7ZMUt1pp9E^ZJxo#0HO z#5H-Uv+0m(4?prZTs?zcWKoYA5@b#_D4pSSAS}P;Bjt|IZm`$IWRd7WoAKVOQpWVk znhtImcB=Ek8@4p;u^YO-O^Ixn!izZaRi9TMu9~3m5yeupXwteNNT#A|^y;S$PHf&} zTr!$#ot%^k=}7!8@Ee_VI(Mte4T!bL!DK_%$C(00(GhogZcU0Fq9kOu-Q+ybdD)Mi z>)~?sy^$?t`V^L>Lq1I`%jpD0_aJb?HT zwnO&o!@s{>d;F8z-U>H!1Ex*r6xvS6rDq-$1jMx#87Uy|9rfj#(a{dI`-q`baVl_rGP1D3(xpbX9JVbF_!skUTa8?S8 zZP#pGwA$$k%}Z$QF2U}vTIfu&y|Z+YJ;q)!R$wGS5+#Y_B?|RdxWV#`XoH;}?{u!4 zdGp|tYoRyy+o_Q>!%>uVtxbQB9}L~VboiP|&vXF8Z0}>b`o%a3{fia6-{Y}3=_R_u zwd-k;N6I@HCMRegIom+{6UK4RaqrcN)1O^2@p$h~wa2E5t{8h19Cw!@@1-F9Q(k)) z8saWdOTo}Za-4E>N|63KVL}3e^8pen0NbO}H#&aqbQaA0srq41e9mZUG|^rbbU?A1 zt^>|o_wDhGFLtl)*j7%9$C1V{Di+H;sQ%IMc*Jv0+dk;Taaf!3e?elULtcIFc)XRe@LuCYpW;I%p3eTC| zGGKqZpPEjqnubx%)5@r{g1y01e^RToEbc12fMMY(Nlh(9mOujZbVr`Xdc{Zs|+nar$Kwh-bkdr2FF#$jp* zF|^8Rad<@~%$$eg4J7@ulfK=y%sKg_yfW)!tlfo?M1f;jiKS#l<|8f>d`vlUPJ^rQ+86g>IRZoR0xwYpD@ihX#p45(9U1Pa`d`)P6LU#+k2xQ2 z=$M#!0-K#=hWf(b8I#gc2K0PNSsBo3r}yLDqqo1=BuaKA{8(ieMl={z6WBt2eE6z) zdrP1Feq~bZFf!k@&h#&r^dHwJ%DJo2&bpy=Sv7gy)EJIJ4U5c24h;D{;cSzcJNJJh z;Pe#b%+k;q);i1S22WF(CjIRg_Gf6Kf%K*!VWMbf51(Mr1GlQg8MKw+Okij{wT$tU z(;Sb-)L@T2;RM^Cuk_?e7OJL^WMIvJ6sru*4_!i|=5!5N_Cq%Pu*+wAb*ewI&8A9~ zVbkQ@8Xii>m^)xkbc{UX+;y_n`z`7;^>_jmRChX>Ul7!vfOWV*Z>F8$}6 zH#IyOs5S`8hgp`EB$1+IR^lW&f`_e+LqrbS2B)fPw9I~b>csV9K_oLDe;boVR z-kF5yC3s%Qibh4@VT%-dA^aT1;qUM}NT}{swy4k1{68KNoor@VH|ln>mfl$_ft#(v zFm5_s2Z@vsuw36Jcs1n)=Zn*`4_>k&k;CSJq|vITYcfk~=wb64%URxyr}%w5IPGU9 zUA#uL(Yd4GrUTQvH!Nl4i!wGPj^;H$0YTQ#ixwX2o+u~VsLi_R_Pt}*=47&mc>BFBrY%t(yHFcJ4Aykhy^ z)x_>!f5~}O#~t_XPQy!!G{egxC(^vYQ#>7Ug5R5#q2m#37B4&R>%DXHXB}hSHzBDE zW$30xYn+VUH&ON@9A9xx`9WfrJ=Fl;skt=ED|wTBz!(8?^982qglK*G1!BfQPy752 zkve*(MYsNx6m7Hfp}uRs8nF_dnsLa1nci86QsCw8YOYuB;SJ=gK|NbBLpRNPuLCW9 ze=hm!FaE83)fwiOcO`{~aEq&?pY7U3*Va~A=Uy~I-k*cX7Y^wHODH&WnioeK zCHUT5@hRU1T}a%*wv!ni?6u7oTCfq;+^`D>ZSI)_Kq=q8%n~w{3MU zx^&y#XV+nMUPEJKiB&1h01~QVSG7dWZ>@NpCedf8lKO9Rem~`d4_~+s+rk1T(1Iva zGQ;x}8*x6yC-aN`68hqD*zP>)ueANgBQ+v(D1A?s#GFbo8O zd4A9br`Nbu$~^d{;{S zA(h|^zIk%=unw}|bA8RS7VjHp=JIjUFC!AUn4Xmckz-7bX0i7%&T*U__KM~U;Z;9I%lq%ShGe| z$j4VlwF+=54S0dmSe@gF4g~l5fgW6uN8 zZsA$h^P`B1dcUOT7Or>)oer|<-@!ULbeuI*W?RAvc-$do6c8G!n!*{KQ ztXjr3_gk!thr(O8$65ldWm?~9UBwD8%L_37p{e1*{xU1Q|Ex<|)+C3=|GTy5g$Jwz z?|nP``cE&61&F533A8~|v}B+@^qGo1Y8aW*Z_az? ze|M+9Ei@D!jW)eVl#&blSzt(Bpzu=dz^oTm{dH_olVr#m>R1_Xu(HXuTIMB-0(N0) zyz4aaPE>B2gC1+1T-F{r?%c%wHe}Vlm`buCajHO3BBiPtsw5|4tPnVvFUj_gbHIWQ z;uA{~n8##6pk!7vb(R8|4{Uqp>KDGqXc1>o?sTITCSI$I~E4rY7Mo*LxEq5dY(RbitUR)0)R5B~z6d8EC2|Xc6|7YpsbXw{2q7 z>#&`4ZaMzu){g%{^{LdINl<+<1yyGyR?q=s^6V{#zufS8F*~`PiXIj>Wm34Mus*Ui z;(EkvGZl%qLY4tqAn}&=*zs48if=;VkHm@Jjl`EA@jK(hZ;ca2Zbh}_A@N)!ZXoe- zWsHxok@i0q+W(|;#up0?cKjT&l7wzH4DH_Q(c@T}zx}<*Q_IQgaMRmaQe`f9l-DWN zah~=Mp`%knedKn;QW}@**NnHPEdK-V%qM9o;3=9B3<0$(qCVP5aRq}U*IR+XtFvn2 z?TQR9N+K|Mb|hFoFSO zngJTG=o-~(RL;yL?Z#Arta88g6`YGf)sI!q>2vPC9bbtzG?&C80v%@qdF%^ zh5-x#h?=T_pC`TD>9@>#szQ$>*>Vi+XZbeIf2K&ThX=Clf3zr^8Z1%|eanl~qV|@L zdAs`IA$Is6u*ZPN1_f0HRAkUUPp!+=V<$;pQier zEuih(6sd>f0;}(-;$o}s`3{txljA(MCHOm`GlFQK&yjr3HvN)*CLlQf==WTk2MGuW z2nbFMZO^j)b+Ln-_8wiHARr((b&&ByKydEObLW~o)RJ@!0g<-}&J%t~aB=km8Mj35 zARr)on1FzQ;Nn6>UlDY!_z`y@@)7~Tc>}Va=KKarn&6y357GqZG|IZ)>ujUOIaZFd z-EOFzpyoN+Z_utw4v)Mr^{n$9=(+>Z(<+uPT`cqH`HnL^f7Ce7$6M>uoPP2JMqdQy z7OI~k`g7&;oDUFrfuJJL76~tu`jGKLKtMo1kjVT%KyWVTK?FpPBK(fvT*LWpUr#&F z+p{h5T}AC%xmfqVoaue3#Qtz$qZ(;~v%()Mnjc>1$Us7Z^JD(ZxXA0@^a82Rxqhyt z<2)I64pOdjay+Gy`6Xt%TMoliK^`wXFfUuDwtM4rEhQI+sp0s?}IbQ}{u|L8~~O+fmOfPjF2fPjF2fPjF2 zfPjF2fZ!rUy#2&*pITYhBXM@~W;UD6Zv7o?&CYIX=K5pZ*E!EW(878$#0mqtqM3>^ zh2fQ4HD8&e<`jT{Ld&$M0fuLJO|>sv_SriP2H2s`&Qv5s0pEKKxfG>Raamfpn$G-o zb+aAKttWk=ltq>m-4E0t7^DWhlfa08*frn#@2lTWTR7%KQi}D#_xA8G9!iSP()HcW z7mig;g$D`T5?O=-pEu8^_(4$3QUuWitN>I^rG*(MuipG^{Vy}BB7KPSX{us{P0HBU z8F4Go%C#!HO8*%*!qZo!l1hY%?e$r0NwZ4VKyYB5;WfR$KfoIZ7CxtBN(4IKB-+rw z`ESI{eEJ)iu+Kj196gLIL~EDl{x_(F&oqeaOurxG05t#nG>N!DnJmv~W90y%k;w+z_d?x&{Hs=_solmtT?CN3caf%4?!2;K|BOI>?wZJ6I@ zb~EeASGK4mVtRdsLi4hu^BQLY&6s{?@YOY+EwM4F#-uLSxEmzV)PS=S) zuD_yBbJ}`xZ)D4qW@Ur&44`CzpfZJ3mEhET(AA$+kPCdlz%7q;q^>`-v3LSTH-xvb zxW`?{>^92v&oc+x9{j3~^<;EO6$3#v%UxiwvOw!1Ez5@1Z1wJ4 zp@|OCZ2D8R3d7Ilgi975BH5YO6#f2Cb6hbP*E>sZOKZ8fk@e(gdPGYDzdz5f_|#mW zO!j+&;N+F#-P{$+s$QMoESo~)KY|N@E(jeH5D*X$5M223NQscly1vUCUBAI4(5BHP znxe_kx+IyVX2=xSwd6s0{Fp!*)cxek%Bmhnu76y+YWG^$Fw&M&+Ll2Z0;9_e$I!wD zS2tMGq{`4FsL8BDoccB=v#PsxjIaGO0=W}%FtBG&_!K08_!ht2ahzgr^T^wCJLOn2DPBtZCzbc zpSp5gy*|xi8*Bo3xj^AKUZymjp+uT_IoNM;X?sn1_mrIOv&7C+x;T4{!`9t(>x64= zTlzS(l&&rz1|wIISw+h;ram(7w@W(azL|ku)!M**Zg2@m+udDT!8C>%5tAp-CJi)| z(}1ZnC{KVNG($3Ih8;{jT}z*9FkDj(u^%?HpY3TAv(A z&OFB}IeC+TzgM8APtP-eF$}22?iCXTU-r>&DT~Tk=0<0kWi>iW={G9l_l?f6c01Mj zHY#I16MarV5PRzGc4=npEc&{h zeQ*?i?|8UypC3&O1CnS^IxlH7FDeEI1pRqa6{GXiX|IG-4VaXU3FASJApnOjYxQ^e zYOmK;w}P@*{iJA0oi0-bqshD~7~1$=+txRn{YT2!1j~X7$z{DT2K~PADSlu5G<^?M z)Jx)|mr=puM~(B8HJq>IE>!st`q9fiWvGgyXascSM$*H1HxcGngs(E|s ztzA|PYDKlEDcv zOOxRtA_FWHiwa}fwMN(&8`~L%ZD*ERTni=lXV{T@_EndP1I!z=fYKz^;NF1TL0{7#Z2^G zM>Hl11XEBoQ{V(v&Jmw&^j}Xdb)fadP9*KC<1}nKMuqNH&h&bfG5y_+vgK3O^n1lA zFC+ti=5NUhFI(}!Rl?uzV2!f2j_~*3@6)Z2Lrh3Rk^Emq-XDr7Crk&n*L0-)YzgLf zI+<9wKybC|xt9jl?9`!g!&OD zj4`ia*#S$-EGyHJ#4$9(Q7AhYw4ms(gO2DqjCExnnb`chD`NO>`hl)Y_8P%#g`p%( zPuR;hbit%E!o!S=@(FK=0t#gnb?V>wc3NqPdZf5i z&*6Pv9Bqh*wc&Far5l=P2qq^OJi7Ffj7eK@*{=EN&#UgO5jp0qguOm*P!XA|?0eRA zFE!ZjPm4DJk8^qQFFUYAfeRk@MqelixsS_?&gg=!8LYrJ{dw*)4_>R_XKCRA%@?;WlVsCe^|SAL{GBy;C0%A^mKJE4lLeY$A|?piiK3uQ zW^|g-T*Jm*Idk78H~~pv(qf@!y5GPi9!BQ#dWTGZzn}37B%&x% zCM}94C!z}^>#S5Bs1toYjT{KNYwaIN+iDN38`*9-hF_sMPRUh+!0%Oayw?GAplyho zzTtZ9_g#N{@mNe1N0$tSGdY$sST3rHQz=dunJ;jq_V#@+eO%1-V44#cUgQ|gR85pA zwK$f9VR)u%cC9ABMc*toVuuhuaeMKpjYNt7x`GL1G$Dz?2RxO`)_IR@Vng=~vlfhpe9DF&#bBpF%R z_e@)qo?97qZ$|CtA)c&qTr&$c?Z3ZMlSmD=gsdcu)^(NR1zDz|y3H3P7}_v#oIK;O z<+|va``iDwF}CXi#mNRG8t(_B|F^;`S)9brz1ts#x-tb-HFTL3O%dFBMQ}{d zidSYT>0%^FMg4*M)Sy>?aDZ%;mzXqFRQ zPq(JF&b}(`*mlYuLy2eqeKyljT&(41Ss*IzRTgM@x zc%+pm>76bTJyVjE-IkarWw%XoHJV$n=$~JjBcDdy^~D*01vDdvCXHK{ee>FVySAp` z+%(1`A@29G0{0zPK~2Xctj11rU3>g!${n+7L|PF_Yb>nXz4apnrFVUHZV_E$i9ddB za5ZZE%N>7g#>$I44+I%VqQtNgDlZD(=qS^A zyDBc}=`Q-W+Q**5n|MTqW@TQad6|}3ia{m#V|;XJsw9UwuFchRU1kcltyqrcRMXTX zpaHb4sw2Wz{Iw5P_dTW&4kjwD2P6I|}1i@^#h3~fer_YlXSf9Gj z^HZMfam=#i1;9LSfLVh}Iz!wVPLEe$en$^~pJ zfh3occ*R$clj99!ck`=0JsSiRU8C%q-^jk}mS?IpM(DV_^z5jhbWS($4$KQ&SyLXj z=gulVG$XonXL@sjz^{mg&gm?#>b%Om`f$I6ulIV%)(Xk1RXJ~zXjQ>CQEaRfJ&t>h z;$ci@=9IA3+j ziv4`aX&N)NE9g7CW_7pgshP)f58c`vzf@9ckx`U%hEoA=8U`vv+sCJ3dTpuegSXqf z^Tm9;`B(rNFepOcP0_S0(x}j0)lxkU zVX|1}y2n=k;R(GHvdb{0%$cenXcPrdyNoko!e8NP(&6B9oBBh?!*QjWFz8oxp!j7& z(+!4VDTx=evhTU3M#k^OYuUIxF!9dVz{TyhRjysUJiPW*4e^X3WGRvufe#HrhSO@b z`DMZ1V;dGPN_U7ePjyI;W!Y_yxUL+TRC`5FC?M94vY~<%xgrnr?uDlv4FeMkynfJK z&B=Lu+l^Oz+Id@LR4iV-_Z-<7LvU8aN{8)H7Zo^o=h7F7{V!t8HVmusq7EpU1>BD} zdE4x3H`)e;!?ERb{Dt3@_4~0Ebno2Q({z6wnl5g3depUY>(7mLJc6A#RGJr9UFB5P zq}sfH<&D3sty4U4z|*>FB+O)2yH4JaIiYgD29bQdgr!N0C~6uf=msO9>m!MqVb-`F z*gLp&{*;(Ykfm2uqb@-XXc9X_^G&j?b+!6v!=InJ8%E|^ifwBmtqY>4u`I*ZYV(Uy zx>+A+Shiub*0u4K-x@BgOUIKad6rU!0X@%e^vcPb+&xDP1VA8E?ciY3?PZytZhxlx zl#ya`N;%aX9FeVcEv>(6*Uv4X3egN_?Dq#1plS?n0AL859#Z92Jo((wdHnV&&CWC4 zcBb-4vaNSrdHCR%@l>j%BOIRNz%PR)P0P+0$X+1p`e_WfI9 z_vd=oV;gS$qkD5Wu{{)xZRsXwnj&S2x}lc%0eb(QaM`0B-mVH+|JU~DA&RfdD21W# z$J?l$T>RT}u1mT#U*GiAdXbutU(d<&0mUy$nhJP|W&}e>e6#)rm#JO4?e4o{d!uQl ztctuYbDRdyv}b4I(%$5n_vU5aKfD%>lhsjVU!D;aEw8|50HYf)^Za1N$nP?1Jw7oR zb~K&ogIj>2!GE;(p9YR8EXQ67MV+y*~6cszdwtad)%c4aWw2g-s|Rw{(VIKFHn(t zQyPxEx4N90?(6-(y>RGEPl+~kcv%J}03u*SwZ*kNFYQ}7rwZ!xJOx>1flmI(7R@Tx zS~6$r@G|H5Ffw>&q~BqG{yU~x zn5ESBZ1{KgSUjnITDV1ZsV#iG|Mp~2g74VF>29QDHE3a#?`AqW9d^d(j*?YQXIk`j zz#aT?wv1LKJbQ<$efxHGK6*B$Zp%wFEwTb90yX*$!g}`DVPw8LUH|Oc=gIyI&J~rS z&J`SIiYyQ`gXI}^+RbUq-4CQLi$im0JSC1g70>T0CC=DP^m{b_YMAe3mkQSEDF4tRuX@5LR7;Q=RCL)CWlq&qmKH;nzqX_A%U^YPcx9CR z1T&+Di6Y+jueYo{C%M&s<09=YYT7h_Z*hl(mB~XjY|oLs0dV557^qwBzZ5_C?`) zwG(rVE6IAVYvTgf@O!V1u}sRatjtq_DvPF$E|cO;DTudBnvRLvZJ)cgH-3Kg&KB6M zOmwWROrw(GRro8{(&#C@yw|(Q9cDuHE^W)fsC|T!qL8Td!qIH}HgCpUFJ?yGIbov`d--e@p zW7JVE0bZvl!;pD~f3@Sou6w)otc+Xi!d<$7`@N#iWG_AQq=d~pM_k{ol6vp^zBOVS zi*i{P1Nc#bn`}{L!~5{Ynvr}nY>$8-H~YHU zb0Oa@_-$FQhKgU7W3F3wezYp*?#xK8V(1FZ(uK#FPOIN$(ZT&S9H`TBuWGilijK8# z_4?cO?v=O9ezR_|mr4|mQI=yAuP?{z14I0IS$;Lw@>3aXj{BtF%&o?J2Q;s}p!lqN42dq<3Q|fjSMBooGeK?O9|+*{hLh_&Fg=z?g_c64)zo_-b=TFV85y{j_vlp5E>%RVivP4OwDYTH{PfFMMWr{Xh>L0dwf5e`ecZ_5;gIj8)weHcw1_Sc>6$NOP3T zQCvs}<%I~}!=@HP^I*+f)!aLT&$B*Ai+2JAjY^a8kASM~uJYJ>&9-iY%e$*18!wlq zBqba8y+Jh#jPeGvdzvQDg8~1AY`Ta_`^#KR+mLVU@1*!*4VBa z_`$LKw020scb(%|O1?iYANYe)6^7xyAKZ7v@}xeOMrCACH8_ezU1>hGzMN$l)P`FOT(#maWZ;HOQ}@b$p7*Sq z4YS@A?R+Uy;3*1(dPC&LwjI1%Z!|L%?)_bvR58S}?8@lzM4#i*Nfe_T;o+&)tD@TF z^eey3+%xF`ZQVON;B^A8FPK+s!=VZ<1?cL}8lvhGy84U}el<5g&(ari^0ErRq#8z_ zOP0J_d~3#+h!z#^R$&ygk$60}IT^zlrebU^6@?b|@Gx??wQ^6}x^ds*wW4fvDH-Xe z$_TuyN&=Kjxl!ndLM?;{;itWwaIW7XrB4 z>lZYAwBNS!(Ta)*&V+piDe~? z<0V~GO;kLpJ-o%b1JUL^`;FtXxP{eH{&xzJ>~^TQdx z%KZAIYcG(!DAiA~x_&eCQiR}#-!gF z6QY3WHZBD6A2F(xDN9BXLeoVn__)+U(065P0jv#inXyfKx2NE_28 zQlX0FiJ|398J?3DM766n4xHk`xNpopz9XX@R&kL8ism#R)0|p#XCHVe}(Sj1r&y5L*80?_N{xz1|G=Gu7aK#Gk97N6KS_Ud|vqjb6n5XZyJPsS77a>f#KWV zWroFHLgFyoXB|1W7}-x3e|XDorH8)2_z?Q)4~b?J<7p9?ydlwml?#3KYaeLIh8*_b zn2fhf8-L}ollz51D>@#p6Z^zqiDp~6&FfSBQ&C5{MYo4n7jH4^;ig`Bq}|aWPEG zY8lzSv5t00vEu!#_uwdp@%OHX-3V2Y@YJo41KezlUbC6%aQE(z^oYs=zdz5fDdmc%y(X&nP?yIWX9lGqvbKO!Riq z%5nQobD!wctImy2Cv@eBA>Z$*5=GP*@l(OPXZ>E9T-Vhd1(j-5ay-{phB@qxi&?ay}FRW5}|g z>a<=$9`o*LwPjm0M(!Tw57A_P_iI%mhGn8h?lp#<; z)XNRuNli*9v?1>&%EI8u-*(##ZevDLrM%^r;^*x`Yr1L}J$*s{)WRo>Ch!_VOERNH z(AGYy4L?r8HPMZ3_PuZIBZjnz?443Ro{A5seh>(TJh;^?&^^y*db4_X{mH*BtGDs+ zs>-md;B8jhtCdY)vD;?3Zy%~}X@5uTYesbmFtQ;VjG&@4?oP)gJ;&X*L;A7LKEcvB z%}_i~i!>`xtSm=fd5-hDD9K`xTkQA7>c*RkcSS^L#iFa*2ZCG;_ygnm@Xvp{e0tKE zJ{+-b1%Fr41b4X?rcS%@`8vgSbVZ)&S=xbG7bwc0O@;!%d{{~`znt}M@?fF~5tIXq zD|qptgsAUx|8Y;HhCdYV3W#!&O=+SQDHW)yA!>#sJi2Z4l+dn-j0!JQ5k^?kQ)3%W z(OvG&Xnm*W@k!8|We9$EBQ2Q{rBSA&n)1@|KMj7N?tRHP2aS(zh#jve;PN@u{FMsY zm7pZ(pt0P&?asZM@4KfVeo_x@^;boWVg!NaIRo7T4VP}yuq5$-JL}l>Y5V?+eR>hg zbAkypmN!j4@3(oSPcN!bPHJ@69(3ow*|0;?_AT-9cj+Nwn!3!Inm~y_ZmrkeUs~vf z81IOk>4WZLe!feGO#C(&L#F_*YO2Pms5e=iokf2gubb$2TjdVC5SVykSM0MIfW+t; zrBXbr$>>=PjS?Q)tKH3VQ@1`rH;ZjQDO6%jO$*(#pfZA{zBu^PR!d`;Pr4u>?)S0+ z_gzJ~%vVoX4}8*nNs>GzYZ-p)xG89yD(Rd`MO;a`-#UOjE#Z#Z=>7)G9k)C=rdGp? zoJnz<#K~O57TlU|Y$(z+-+!hs-1K`nYYIU6Kh}RiA-H&8U`gvii`jI2lA7VRRpW^3LKvR4u4~qTfzY#a{>2GAh@p;|t z9ixVkIlbrpz3ZC1`6FYhDWYJivMF+ctg>iBb;VZVefOk0*XO;|HV&K7X_IEC(5Wyq z%4TvLjs&Uq1NWxtN59CoQV)<}RBst$3o`^25J_*eJxmN6FzBtY?@-2|Gc^XMXh3khwQc&U>y-B0yh z$^Y^>U@fQV7KjYzfth) ztQC`DO#q=AdSo3?43Kzq0Dabyt7F@? zZ992m+s>qa|G8_;thwvX`=Q>d+Gp3UI;TFIQ~P=Lwq&KYsH>PS8>*eI`fxA=$g3JR zC_q+OyeEHYUE6V?``~OkvM)(xr zf5zOg3A{r16y@iC#@q4vuEN82i9X{10rd`!UwvEp2M~(>XZL>$|KF`Xmv6k$NXNGp z|2`|BC<1(}TiP{8pXg6WTG}qvUq46LiShC8G-&4NzA-n3?-|RUasS3()cKzg_k#Xw zb^V+&;uZRzDWXMm3?guTYvI3tukCwvT;C>v`>y`Mn*K3<{+HmI>wo&XiT=Cp|I_^6 zYyH25>uwLdCHWqYef~Z4KQsStE1}=kx6kj``q=)%RPp`06yG!I-<(+f8-4k|IqCj4 zr+@u3OhCDCz`v)zZ#gd{B+oZa;uRnNUW)(t8)x)CvVX#VvVX#F+5b`at@uy#|DZU7 z)w`Ml_uJ(^1l|8{ff6F2^4z$ddAE4*(Pd>eD5|N?ulnvC3$pM-?wxxuowV|%tpIrN zhhGk#O_{-hCGY+9uxx{jWGyd-4imR0DGRscGj?9rq;b8b&$=X!%SxA%i;aTQIh^c5 zZPq;ng%W;=aqBP8b9F5Pf=AerTRCb~qDv zPMo_1E`I*y8L*J!f_Qu|eFx?@J(AH-fUmSahHfC0=(>k?L+0{&cg4{x8Tnu+R{B}5 zW+%^~E+E%d4yL}^OSPB*JkyUgq8i}t{L{jk{iV@p0?8sl?+90-CbGrPu=(SBYpwPK z=4#6o!;>kV>#&YlQ)n&UcZmi5N2|uvLRS~R+`|d}bVtWcjcnFImV}jgp;-7>}8j+2z4_dP?bBMfD#zHfE$k5Bh1r7dRPBo#rFN4R3T zl}rYpx=GjsED2G{ClW=b2{F|I<$3C22T=}5iYx!Ndj7R5nW*DafSgzzPRAVWbCX8J zzug@zD9Ix5h^fq3zGd2=P!iCrMld(!RN;A5FG_cnEo4U$>i^i4C)Y`u0ZX7j3$K0x z=aQtk0oJJ6L*b(u7HD}4MI#rUY$9dF>Y_)q?r1{F*>-`Vgy{k1V-r)3f$b9GL-FTi z4KIBNmBxP2Gsr+G8BrNWuH*V(o~-IS-K(s~L3nX`cBZw^U69?zovUke2G2JgLDl2a zj;(uFYz^ld%$KKtmOgCyciC}s#&0Y@TM{>MIOb=8K-hNK{q>A-1TNjlna?K1x`!o} zt<9boO^q5>j+@NQD>Qv!H63J~ua9iPr%(6VatiQK!p+jVB3r5F-h}nrG>%rC@k~O< z_QWb}S{wCPcvea}-utM<}E>~F2JJaz3t>`yVoysW9L3Hw+;tFA=wioVc%Riq6qMPTKV%s{j zL~vCga?yyUu4;}KdDyDX)Qe3l*kPO5388eh?+#y(`5?>G!%NE3a>dgs?B0jYKHUqw z&m_-@w&lEYRPXi^h^+!x zplpj$aldx)P!8`@j6Rqi*s@#&76uEr9lLq7xThkB!tmK?%CiIi-J-3;$rKc5v^xyE zer(@*?Oz{5NFXZIE0V|daAl-vT8YVyws3o2?s7Sgewic$J43vqr6Tu^J%9oA>#m;0 zI#0?sj^gBY{JL=XoG6K45F7ZlM=*P}H;9DhdFpKeNm7C7NmwR-=CTdC35Upox8a!3VmDbTXOU_o&c6TEXHR6879Zp$Ov zv;_v*)WeatU|m(0RF#_v#a_jeNI77@|dDXt6!)kLTVaxn}MMhgsJC8c+ zFR!qHsSdmn|IdmA5;v!-qC(VRMus{mL!A^?Tqj<+w^41Fo4K@aux!!+x}O2FU}2Sh zd(~%UVvb7w#Dm4InFr&x_f7k2+{0anF+#QM4Hk8*;}9~1A~4{cZP%FhBT7oGosFI# zO)t29bfZgp1eCH%L zpPPrHV*_4r7c!E56Xqe0Z+OjwhPA0(|NOC(oIV-!Rj&3dJ@Ap3Nsb?2e8+}&K5o-IS@Q{uDiqI6|*_B*k#<< zI+CUc0Y3RJS{3&)@2r$=Sb|OaSr-q+Eb$lFKi-wHid~hmH*cKiU8+32?_=Y1B0<&W8to{@y{4-G-| zB2qQMrTTYWL66fj(%Mt9V9KIePCAPY#F5eT|46a_K_CxV>$K15>$Kgb_aLn8ra#*R zh>em{{mDlcq_URPlT+mLGJG!>SLb=$t_za7`9&L=anL8D3z3iYHeDp6R{2&f{9)RcCNRr<#F= zbJgA*fW&>=sT3aSKCh;RawVhq{)9FnlkFD9*?JB(A&SZkbrMzz4$xXeyFcBm7udPJ z1Bc?NfN&-AMNqu!jqmI)n6jYc!e8B#Cvo<|Y0}ABZ<>0);g@`mMoKdh4nxE6J8%ul zlUJ-@<8VgpNIu}HI3IqSLd29rmq_aC$tIdz&^Cm{Rk&I(&u7MhHHN0)hY@+ z`mv{(i6RI}8gQ1|l@*fh%ydgPNrYib(Tpi@;43Ch2?O2I2xK&1w&Hz!rEcd115l-H ziN2FVE_Tn_5yTqv$47hi|Ms~h@au)*f%?iqd^EGReFa}ylqraTORJ&;(MAftf{pKb zhCIAALiU>rp#^ch27Sf;?3DfnF@1do%-&(dd+Ia6ufUpm^uS(TmAXwAlkozuEzE+J zrGuB1{?3x)YHPGUodJIJYj#7y5t%vp7LQl_S*}_GHgihhfvU7`5IN~kKOXyGhO!xW zhl%uGK#1I^kiw{;V{8r}0t%ooMX?SB#OkPlY*ElTkJuKtuqT0CWJH^Y0r`-KQ!#Fw zFg(%I2u_|a-vRl(w_&k&LE=wXL_qj}uE?%MxZ4>1bU7f(v!rsNK}mKsuU+51V`>b# zkdeEZ^?$)7cOGZT=Mk|$!n#yv0sU9D0J5}84{?(amzMirLApo7rob8p_G-^iVxNvjr!)e!_f zjn>6q2g8RB04Yj#SuA$Ka9KxbP$ZAPz)zc|x7p7FU(CgCES#}cK^rr-2L2bble}<# z$NC>^*6*+ey+uw@#lanKjp{gNC6Rw%q<+`>nYFNu7lZ$L=bydv6ejc8e^~}ow4v^_ zIbs;^b)D+CroYLHdg%D}i03}M34F~zAOJ@$AHh&&^i;FI7>|Q<;gUZpbpql~yPLDi zC#zhy%$aY(!)ye|nr7qDI~>fCRc~+obRRH29JJXYr?wJbSKMS=PS94_JsSMy->~Mh z{+x#$yt#lK$=cfK%W)|8IkBkQI={2(AfQom4iW$*AG9azSsQFZxW|}#$F~NZrpmtrPaK5 zMH&ZeK(UM*9q%S?;5J$Sg@a}O&y~Zv#BX*jJc@vt=R0k}7mihuW^yqmaw(|!hm$k4 zVrn+h(4Mh4kEroiGQ@FK?`r@2D<9ecccX%)q}fuAnnt2gu>UyWac$h=O{u#F%RyQ<_Q}s_7R^*&XQPWMRVny|dck>t?Xg9=tvQEQ zE(~X3s&S|_Oommu)(TU2>1wp~aCw-YNR94^3se9m2Q}?S9$Z=qm)=(Jo5%`ecLM0F zbC6H|CbsVD)F6L+NFI8|a-M5J3oj9tg+ik~o*hR{cnWi)a`LNT`Rnb_OSz#*p7M*G zaq8o(ymObn;YobrDuSyg(Os`NS3Ke^tUql1gN5vN_owcdVfn?Kc{)fXnjE{)sI{Vv z45Yk8fRU?9SF0D@0CWzsf!r zb>=n0DkLPFX=HA}cQMwT9VCW*y26Lbj+9x`a_nJw!s6SeQ?bPW3{R&?lZe{kN0n%# z;ZEJwNGXOBWWaDX4bz}Q`t6?>A7!>KG{Tr@8hbcw6i%L8xRFr^@B5aO&7XIxrCFE( zhu^H^A63Rjd#d$Lt8y@YDirDlF6SQ|9?PPSg}M717uX2TZ6xSd&fy0(Zs7-(fAMqK zEtlQgtKVI2d31lDICK)N*&Z;b$-C*Gk*Lu8546GC+vgO?DO-gxB=gAr9qjT784abA zGv3c^+4ZF$tLRmr%Q3TfJZm$>=iwLe<9h=+>JJraPSX~TXiP|C+^toRR2{q#wL{kf zx1qTE4`B&nXDpz9zuwY(^-_*PbEVvUcUc+R`8?XQTz64nWfJ9oY%W5w(qM4n=sC4} zA<+#hC^_nut-HHxQkzRQgYt?7{W(TG$KZsAjuVig6czQopR6P*9cEe0O}vjQM_{#g z25w2HBun%xe>Lk|R!mk;8q51SqSukeEz*jw{$NyV*>frN!U}V!kTq=ROFh6$!MWdg z`t{|1y}{|N9UOk7b0^7>3qWr>A0T9`lh@8}9CIkRU4nbug^f{lvA=99x78=tK<550T3^;b!9)WOo-*b(_p*oyaLw z9dg}dzu~moJ=Sqt@aZyD!w*5?GGVVoBB<)w(wvkn1vtQ;X%EPT$ zSPe!O089|0h1Xe_O}`GUoEk>i@s8YZ%6{upm(HUPqlkHYlhR|J{bCDQcj3%&|8+K_ z=FQX9mA#b6ln&d#sOarqt^V;aMUmg{YwMRS2{@gPh0u=kYAG5!*t8xZ2BcGnOALTL z*{-vGG(bpEU%vdi07f`X2V1#j79g7q13l=hEZ0Hg5}m_m}g&TLja_7e&E1Ev2@3*HP7#4IKi7 zI<_Q`3TU2CZd2w!jE%p=Z}T=boVT+g7nYstwdD8<@Cc4*71L^)<~{5B9!%O z7mq{l?#qD&Fu7tioHt5{A8OI4%-RObGoDMwN#*`DOu+^X^!^b@Nz)9@#?701rAh4* z^?6te=4*p<=4#2T$^nebf?nUevYY=Hhe+m)_Q?fn6yDjUuf<&29m(|*4u9xG*9$Xi zMLB8{2kfB9?3jh?6VdGw6-CEilm?x5?WbdsRIN9k5R@3;R`W{eJT0xisRuSI(@*__&c`Xc8}gZni5Ol$9H^d(Rs zx9)Y74;#O6deeVewkQp;L>;wVh~r(bL^~KOuOl_%=UgL^WN4EVh}x+ejFAWtSX}TS zjgK($-_5;wuVbE%vdCT=_Ly`85M>vdDOw}1RGBF`0pX7%W1&bx^Fawn#1s4T3wXul zx>!S_)sO0VDGN+ec*W_wiqkhY0=89Somvo4vazho-7!A(54W?^{|nB@-YW8ZInk z5D)UYiQAWc%2~mpz2{fIww1UxaTR0!0NIoTkK9mFb+>$UZ>>kZz_w82Czo4Z;FAiQ z7&Ryd-Yl^ax;hFvoducDFg-Ocz4;LR#^kmz)6ciXFb_|Pb)!{x z_>Q@UI>5a%|D%lfXVFA$QRw{b*`MJVqO2(0uj+o?YJTCvWb`*QXb}khLn-M)tmSq3 zuPcEo)qr(}OZGubfL(a^-d1Z>m!;$jjJupr zl!LM585HLpIU^lo3cp!i%SF?k6y+GDUW^<-WWLG{jHRqwG~LTyGmY#ZCsI;^x`rV$ ziY;|WR#;lb^?l=(gW4a9?nk@Hkzg9HG3fq?l5D`8N@Mr%mgsY2vDJmh-w2hxMr)m2 zbsa=kR>#at>|Cd>7&uiEqI%aQMHA~3!OPb{E(WCZwK{&ezkOxlSx3`noaztYAu!f0 zo%cG+z0&=HEqSZ3n(;7Mb~Hr~*c$cfmPmHF2qDW90`Oq+yV83x88=+jTfDSC$y#k> z3ZxZoOFXyKrSJy=EeHt3&(Iw0J)qsth7?9dL8c-n$B~DR%Ol4NM-iy; z4aX19F#tiKGN|_Kj?E-yb8%=Fzf{lz;QgK0y6m8^+3I*YoJ?>3I=x4HtP%>&1?xfZ zBp63PhbpWNdli^d#b$@5Gs5|k=5ssB<~lTV13Fv}D#}DXtNw*SR4DFF2vuo%_Qvj?3&QoRWWX6A{{AT_U;gbR;>BOXo9Hr|1m6r!~e{|J_ zt#wc-7L|3ZnD{t%SMx=B!h(4J{=;yHyF_@}xL??O53T6vD7F&Iy!wPFYUP zqEJ`4P6)7GTATvW?A}JOCJHcq%yFk1fo`Jm{P3K;@~NU7Gtm<g(L2Sn5Vh;*Q>)2_m@Gx2UCiaRr%MgS9T_g_PbE6pG zuoJwyHtJ4pG}vm3(Y72||DzTS%sonvUF~1fJe=yZMRijDp^k%_4}1pj#r@UUe}>=fBEk5uC&wDeNj>^IBg&O$E~{`=#r4W9xZUEWIzlgjE#n*BWcjm z+jy~S^?9Ae6c`>^nhCU*0T_i4o0d&W9nNsIpnVMnwPsevH3`gr1TmhU!L$LX<%)i2 zAKGyR*0^%*Uf@F{1v%RVhKny8c81=+zzkWOlCqFfyVdP-AYkuA1qqc*@IG2TH4}56 zBgT=w&G5I~{fNbt#JXaNY+&$hfI3(y+0vJ%$Nsn$F)n%H#9SR^E<)?q5?kBWV)1e! zc<;;14tqvYq2zfVNWhF!=oz=#LCZ5^+J-on% zd5f5i`XC}L8x))dulfwY2WtK+yOfMAvN_g!bo*$7KFY(}hQ0TbB+J>8T8wN(jxLHi z6J0rh%CfE{>H=u!W3Y}rOM0=$9cyLqy@fOwRiO9eW%KP4(bTE#uWB$kX)JIo>5D(= zcWsXDJ54@0#khW9`=!rX^9zWwoq6+>lGRr(%=ssyyFm2exn^vo6hnU(8ZMFpHECE< z=8)JJOgDHZP8l8mfb?#x8*9m)2x`%CW;t@$2P(W7LT(Z+OFR=81JW2N&L|#&fqG!k z8|-nAH2t7hhcF*ms@G~hW4C8^$|zv)_-oEdSa z?RmOBAa-=#5s1@{e!!vkI4}z$Fo*Y@(Y;nX0K*QFshdf*TAT6dd5FXRkgUZ9LI3^3 zQ;f*-72-$4&V0pQM6z?sEyT!Ta0qSQD~uWP2{y`gD|f;am_qwT`jz~PZ$#+B=s4xt4gi-WSsiPmhs{wbtS!f1JZFws z-y(6S@e*XBO3sIo`UTCC!Dca~CL%iGG9>j%aIg1Cf1mIx=bDi6R{qk&-w}vJ7JaK$ z7H~LTM?#(!QZ~6X0;R^2Ij}9Ncyo^ffy|Sl1yeU1R3Fua6mRWO@J}OyV;p zYPVs&jag02<*>yEP#D_iO0Smjje#0h3G|iHidjA{huNFnSieQ-A^Mu_fFU>DE9S*{ z)raRrhj&Z;PH~Sr9xR;hRdZG?t5LSa-zDKJhML+srSt_V&u+o#HXr7uTr_QMHMvDG zUq6I$LJaz6ZUnbdYhMmHCi_BFb|NvH*PGQ{F3z@GO|Y5i9*5G=P;h^!=PCbQD%q3$ zSG@*rdY2+970)rpa#loFR0QYdm1 zQV34-X>i515q z!D}-2uZ&0K+3SKVFPxeyxy}^xAuk!ed1B$9jHU5o<&q*#m|WM2T<*yi&YAZnEG%q< zjkU@S@ck)13%}LjZx-6d>M{ySBJnM#-OWFkJZ#PDgQin*q=;1--tg(2G|uD_bDLr0 zGC+ldb132w-n!ne7YNLnQA332JyK-DZWuF7>n~p3a8!k$3JM^hC++fjYU+Z)71|&Z z@>1u*9?OsTY`s)ON?=MHq3Of(ecBA=QjnrziUlc9&_Jk{n(#s@QD?he988*Zp~X+X z;|lO$(wS09l4taVWwTB^U)Ta3%vyY5jXFgN@<*S#7~C9@VEmSeB%aa=2w#FyYr~mV z;)GA0z=^-q6Ng%2F5TC~bW>G{K5B%gBfyyn3(czo&WTj2#nwgq{=)Fnan;|}-)Ae3P zRo#2#9>*d)kgsgE=)vtxjfJ*TIBpoTZibcV}v!x@!3Pk z2hT?*FEgP%&3xv1q?)&7opXca_{hOM!pG3Hp6 z?8+pewammBddu!Z@%E}8OfJlHq3PDi)0pA{KVQtbvR0Njk+S?00!edPbDRFzI~X0O zob;tYduz~w{1n)-$|1#q|8e7)^%vld(3)D3m<%|MjNLC;&a31t$~p3VHqEu@E_KqX zsBiUefIb3qj(QdXv&6(C-qHI_9KvX<2X6xvI}O!#-c1uJZmE;0MrJiW01hcw;z7#c zFpM@EKv7>%GV`6W75S+*9VFpWO?=58Snyr>F=ru|TT~ya&pJzt9y2>4OrMHuYfCRZ ztYtcoQUP(BBukEh`SR{l7=PUXJRHuaT87L2vi1D+%EuZ- zeTW_HUIoESU0*mDAM&tOUv!Pu$3zxUhQP8of7DUvv$MkYjg~{=jnb6EHM0xrW*``* zv>h0MMO^`rJP8bO_y)PH;8J7)zkM&#SQC|C!_{3i#^*+oa{MQ>v;%eTPh#P~7B^(> z+LjSl4;R-ebQ7Y`b+k@;V}4Pju6QWH(BC^OOPG>7o+RaKLF4+2SL7z0f4oMJMZH1o z01XUoJU$E#JE_D>{)9Doz{EhEwiEKb?wpin81X9QcbIsbJ zpg9=+5RqbIK3i@LHanI0a%LB(XgY7!xqLQCB4>zMJh20r8cA9nI6cM{&!HvTrwByn233u&CQ?W;g$1DOBd;{bEV9tMb_zv>NG=H_5BcQTQY>i8;2x9 zTO5Xt?DEA6P?MAy5nvYrILaXpHxiE~Chx_2658v3+ch^b7?Wb{QD5{;|FmoR49s6{ z`KinMqZ8-3&XRmM^pxQM36$!9WbA4#% z(~IhbxwIu=&O8|pO&9BbKM}HAF!?DjhGFH4Fh&y##Tjy}5!x#HrI*f=dbb(gaWyod zoi7c^L)czPW4M*+7yw+v3&5hbp22ij(PLm}uUy2gJ?pc#o}GU*YWTw{GGWks3N~~? zf&7IXs*Qs1BG^H)-0vi$>UzZgp>!ptY-4M)&ufdpK-cGivvcrc^B#Z$34sN%I77as zic|Qh>vr6Z>-7k0wOZvW!kp@UkZ)sYi8vM~NeW6f7MKU+TlDiF(;d!6!jzkvgJVoV zLflOi-Z16p>GM8i$BG>I==|!=9k@&sqwuu|h1M+yE#VcU%addK!D;@6$3xd^RbxsW7D(LOV=r)y>Mal^-ENm`&fg~!simGIK#-c9|EL>W)$K3;{)BUm)L zr@G8PCmf1OG17O;6o#jzu9_HXXi}qY|E|c@;<)uJhF$qbnn-BIb|#an%$_vW>A+t@ zJ(3o1r0gTuZi}Ic(AykRIcfs5E%d@bP&^;5s)~GGe^>9<>y%Wm=U)Yo{-6c?!0|ca zJ;51yVoS~W=K8`7vjd4-1+CH^0^#oq!OLZ!{8WJ@BiPgC>XR`%jn1zuConLW4)3>w z3n8@4qVFHi2Sy1OSyn2%T>;)9Y|dK3)GEBX?$?U0LApBF!E_ANC)ir(pV|)`g`O!~ z+qcm24kU|gQkslHYnZO@LVbpvkujnW^F7oa@}Ex#z0-UGw{)BnC$1$fAY1bxq2MGRxLY1)&sds2}HxsP_^?NXQaBE0kkrO0)OQ|1+D&R zf?a3N`~2)^G1Cl3Ddo&Hr~A=^ks4S0n4U)0_JO6a?4)}?9o;g|887@Id}79vwgue|Bqgg^5Dq1Wf21 zxqQ{$8msri?aM5c%ui#EIQ z*<>p|rmaGmxy}VNJUH6ZSKE?+PNy5Yf6B9G!@FmDS|gCup{HUQ4qX8Zy%Qw0gcf`JxezD zwKSGa`X2|Br!5`@PmHNUL@b+Bw>}j>waq8GcmD#&-Q6=OuV*8f`z!tD9cZjR$uQ=*-%V)!}vubCq4fXCeQrl2N zQD3bh=YGAu9~xRsA`+myY*U;w*}9N)T^L(z_N)9&uoSvnzB9T93yWE|I-6r}HuO8zMvLHTAqaqQilRmu|y zZD|uOG$x&z!mVAVZm#jEzwf;bhURq}LPTFAtp1?jXuvj&j%{sdss7-Rg=W!1XirL# zHKe{&i**(pcn*%2u&0znN~A6~_3S@$!ptb#Yv`{BdffITKQ$XLGNaPrvu8w{Ezck> zC#0}P9?TQ+0U?DMWX?Qxb?XI`+eCNlQJ5n3+k#HZGyc_RHW{Ad%KGJ0b#Et_k8&)s zyPrPab#Vv1^^|O&h6xEO$;91@NZj_}8djBsqQ`kDV(^m4%7nI`Zd+(#ia*ye#z-le zQ+1Eh7$tPZ={u7|%=t{^0Y^jIHv#Khm@OD7!(o3q={3WPWo*NT_RVT-MQ)=Q%QLx; zl-w^~Q_O4(W&q&nlt#Ca?gB@s8sI zCiOCp{rBkvZZn~8k6%}N@d2o#&8%v&@Nnhu&FU?2e0M?hAJ$b*`>6%HwXI3$H8QR* z>)1>X+>p}5N@+$U@^g`}t`hhH>`SKe;hb`L-4!bP%#MZX{Jv)Zi)Y99Fjq!uf@@6pAGtS_ zv{@5vl((GxH+|fftq6(BfESAdc}`S#r?pv850*e$8+~r?0Ig3B31y+6J+UC~lhO5H zGoB(6{z@Cc@zdPZlnR_*Kb^I*;nFSQJ{rZ6i;a2^;t}mXn>9DD!_B!-4-5!zW;3ts zL8KnZs)4fNF@DE#U|dY6;4D`1rN9%tbw3NO7ZXWlF;9ImRsvp z-KN*~#jOnw(^gk|O=;%0gMN84#Qn%>GNJuQ${dO;Lv&%J=klYD7ncjoc$coGrE zy!Nq{=ymbNi)tIqD6Tg$xV2vp7!346BvfOB@O2Z?LkmCw4_`wIC?K2jZxxlpo~Wg1 zNIG7{C#`Uh#2;j;BLA#`njWq5*Vyt|(0n3^&r994j6uxi?%J1fpu_Hh(SN`bULp=F z0+ToXYjtJy*TLcpEn?cRvft9J&)V)!0ar$XUMAy|P=@OxIYXRo#!HVJ(<5WtAMrS1 zW8Kx1+6~n>ER5OQ5?TsxGslIE`fq?ztY|_p$OkG5F0vtITE5;!6L(L?(-gU(TPmm) zdnN;|E-=)LnCrHDp#a;|t$F9%Na5r`<5Lp#c$EntFKej+}= zDPTC~)6{DneWAL_kA#e5?7_xR&fCqWd7TxpQn!7#wv&r!6+j-nC;nR=-9J(OZCzX{ zylKOFT?#ujm6O2ddr3M#GmNFR$fIM>r&}HoIu@>95RtyjZEm^uh`tX+Sxe` zX0#;sgd`Nnp~#_6YrF)(tB%pa0`5?C#zJj-S2V)K&on*jC=&w9#Q5P8AG0^>_Kw^= zty;Wa&g13{yns%4l?)i$Bsw~}*R8n15_iTnLiqZ(IA!g)N8`AMYcu$5fjK$hP9tV0 z&N-hLZ3iAKIro|F`^gb$YG!QF{nB9%b#yE&jQw0R_Iv-`6L z2sT%FKmB&x!gp8*4LMw3VAF#Q+=E)0KTE%GYy$bTe%Jf|AV1aG(Doyk$=WE!;`8ZY zHHN#HcKCWt)Sel(5@ZhpGA$ql7A6FX?$3<2h(zGB+ckx)(@&HWxnbV&<(6cHx zIpwCChDm=GH4R+X3Ma~J&9fO3Q+AATJ}B$5oW1CBouBj3^z<&7a*aUKo!O>2y4oU7 z(pCRayrQ$)E_%e%WRI|4rTZsCa??OBH1%j7MF130(5x~vJm0e6 z6vO87DeLBds=6`XQ$)Carp-T{ID61k5j%OEvyX?YcdM)#Vfyoaspw}2w0|CI@Qw>( zq)0iYEJfbHL@V3%+z=e4?sAxhn{{c|u*p+|9__jQ7I51w6<&e&%vWX0>?Y|s>B=0IWf6bVp_jDjg)zpkHayj*q*$>sX`&VcJMZq-&E;UQQ? zg_K2Nk7VRnsEn$07T3+TYujSr;HWL+qc=)cLhf`FH@~hY&?p~P23`O*#c?S8HA<-D zzAN#RJz=~LWbM(T@NG8%ZNhx)yDjn8PsYS%q8BGfU8Fcq%y_=24ca%#c)l=lavS^? z7O~Ht13De7V9|pqLiy@G3m5g2d9%sM%IZa+(M2dgENkA6y7J^><+9Mwb33?^zm`sZ zQ`}e>bYDeho)s+RGL`WApAVnh!pVbh=oD5{whL#Y+q&@_3zbC(Aee9ozt?(CuZms< zB{-USx`OxA22u0pneC?NaBaPLJzChgEXXdbMOtX{O)f9lg0 zAAcCkmZmtlcLA(=ncR5df74s=iFR9<=eQN8)Z--+xUJA4%UHZd;wm=H^C}(+C-10v z?X1{)U3&;hhlfiEdaQh29oYqX!R{1e{w}5?S*JC{mk_@+)0Yx0?*6i!>$Y(^0}UY0 zAnf8wsI8b^l5w>Yj5!oQnDWc|AslV*0pe{EeT-KMe(OabbvN|hQX_STTs!?BF&Cv7 zX$Y4kU=))iE>bt_GO)iT>&bbohu-e2pFt1|2gQ^~^g1g6H#UIs0dk|Zta=^+fUHkV z?1GjtB3CIei=u&T2+Dgd!G#?(BWyouRIfH^j5183L(BlhheRfVqW<~p;Exo35Wat{ zhTW7M>Ow~MzIQl@a}Bl8s%)3ateynou2=6pf9F{SxVm+p5!lhe#7oSB^dX$Xa^&3O z*@B9xYEe$4oJW*|Cl-_=&!W2MH8Xw6B&hN^AD*P?(?-@{e=hKalAZf=`ZS#T zoNx@)g^~3sxqp`6M>z(aqpmQ&kMwzVpuv?qEckL9j38`3`L`WMfBsgZ@w}-!6fT7C zGphzc#O?(Ba0)1mG_&s58Eq?sXJ!vB6jz<5jlX7w&~q_27*6MYgLB?Ewaj_7%xF$0 z=sWSFd>JT#xkl!|5%}E@wtjHz*atsP)0%YpvAskm_zh|j+Zt5s*!4b9 z#l7ZE%$-F62X{0bhQ)8_H^mhgxtTKW$f#c0RZlGnG;?CoR_h#$xBIbvyrXfyMTs)W zI?d}x8Q$iwdG30lT)Vede|UlK1sC2DIE)3RgjHdM3?^ND#Rx@Ukr{bZBbXgHyF%~$ zhiu_}8i-v7E-J)i1a~Du{D}BzS-W#}wyUfPjwwUup)t;KL7mex5#%P*r2lxt2mdlS z-lmVohtIu5MoKW^$!{Jj-2669OQ+rq+%o{@4D^zd zzIvjshQ_j+!NE}rZVx{@du%?NV7XFioa0?3oW&i%uZ>Mw3 zKEbcD!l(<+^%_pyrF0<+iGLfL#qp!;xXr${QRcsG{;xo5$+D<6d>QdSj#Shxmz)v+ z{Ob5f)?VH%MqPM!YL8+eMpe5F`?uwR?DfOH|KX)Mmggj?IoY#Mwucp$QZ?bZO01mz z`JrvI{7LXsWYKerji+@7iOdo(>!t>mW8EK4lO zKI)$ZMj#n{{33~mCQe{Pyn5C6o!TWwB9v`(>3Z}!R`eh1Lup?Ea_VnD#z*33zcQ-w zS!liTnX@g8_TLr@b=L<%b=KAHJ~~cgZl_`*C|7lC?J!daJ5@<1E{j`qR%&(j|GQy5|C?g_H;5~ooZ@viT6%Q5 zbg&EC6kMmC!u?A|t3j3`J_?u^v4903pktQF<%{Eoe3 z@AIZZ{?}UFO^_HtswOBu+w5(bc=rF>HTh=uA5EFK{kG>2WRu z=4-KzKX(4A0v?*6GpUaGfwI8M_-%O36P>TP;XZ zaUp-0v#i`ZeL}iokl6gffSlY@q6j873{pUe;=;XJkuC00z`E@(=1l(vS*3P0nyo)i z!mG-tX?^E}OcW_c6ur@A({f)Q(?^Q1F?P~ZsQ0~s0CHS!B7WL4S{YXq@44gOcJntx z_uH8nS4_vIOLN4d+R?-_IRh$+#CpT!s!I6WZ$pFz$|mnGj|UoNf7_R!T|`1J9V@d) zJH;vu4?n$=9aFcr>b%d6umSQSpkQxI!t9%i65=YQHTHG?(U^3VHGz6PHPePc(4Qcw zaNha}?@(Vj%kh#$@zL2ey(QUN0pnrf9z)4#Ir|L`EEY9u6&Np79(@R99Vp{9>Xbyf z7_I`pa$(7daFlwRi+fUlo|_UgCvIwFdEPw6HAoy~8CWQ<9DNmvz%?g$Ff*0AQX&?9 zD=aKD76G&U2z~6HeQUX4%8N)|jKnKUKZi*7lZ%TKw*o&LinWf_faji07#A;Q=U;XpVp#KgfrW6kIG&O$F|vOzPxqdwOB?Y*^{L%VS!0@OxUtd8xZV>=z&wr$%sI<{@wX2-Uj zUu^T_{m+>*Giz?@s;+8%SJhK{fA)Un$UoZ(AVKW3GpSqkATA5IBqLHJ)iMuA6=tC% zkFvJPYp5H(q^oOtU$bHknTy`^)&g_onjm{)K|b(Gq~dqnZE;{y;5@zhN)ei7 zb06TvaI1jW1JIQf(ZNc0E@|0artn6vZ8Q}iZLK#g;zIZF;HIPGB=2H^o^*Jj?D(BM zvUnlvEB;Y%%Tw;%e~a!6B{ewq;$iT@4LhS@y5Lr&abU)f86dD_G*HaZh}C7}A))|2 z8a^Aea>awf9Ax>_lXwdc*z>O|qeaO!WO=$ZbJ?pOuL2;pE#9J*AI7U^t(b0zqkdmH z&;6o5_ekqmsy^{h%YIUNT+m1iDF9S9xCAY~i<~BVb`z|qy)++fF1urKWf<|-213@# zuB}o!GY#;<9|GD{N+$}-7Q!rKqmj*3RNZ9?!fojygvrgWmt0{h>UW<3+nCCoYH86% zK1Tke6fwIN{1{BAF=B2IDJ$@@3aCGtzx^!+pWGKMK8!HeO{M`dqPwiIN?_{CCkCFv z(;`P2EW=ws{1>8?ebOzD7{^389b*nI*~*B+Zf#LXW?~|MrLFg2kLwkV_Zs=jQk2kM_C|_$vr6))sh#~)Dq4af+P4hrW z{!hTH{X6R8;tSs^i#I7Bp`W{1498-MB4$XsGqCFaPOHMn0dN~hMT4=$U}!gHqC ze#1#<)LGfoJ*z?M;XT`f*DmMm*Q7m&s(Qn7zMY(};ta6XBJM))F~koHYlYAH<{UuR zoi#qKft13KLT;{_2Nie(4wEOf3ffV@jTC7Jv)XB0=L0}x2fsrekO7V-G5@P?o&gx% zV!r&u-l^yEC@fA>sa%?hNK;PN@IFVjGWRKF8SL%UW^m`8=!wC~wbMo{a#g3DL&RQrP-OYN!`k4`(myWqF;Z>3t6BXtvvU zUt^Uw(MrP~kHzX^|7{s1#-7RX&Jtz&P& zj6*MdmMy|YEaJbWh|L&CF$h5E30Ujz9ekwg4jQLNW*Eju6nV&m{zt~ZnatoBKej&n zBvoa3_L|g%&cLHX{T#bxz!r|@r$M8TJl>Lbjj9s_e+dXiJMV=ddj!y?< zBj+}{;w+fiCJGIhj8!VgP#wZRGRr#~-LV&k&n%6xh^JQ&RX+{;-$1$onGhY-T02fQ zWQT;s-l8AC4vMYbAtmM-N$MghixM1CHNEt#Y~Zq)nQ^F+9z?2kR6uq#p0>}=Zfw6q z)T-EkW1PkfbqRM$sX)=b1HfCopTyS5B@ium5|@jR3H(n9O;!oMojyR>AQN9d#?he8Y&tPj_ES zd9jv{Q=(>XDXVK2Xg>SVd#nx=ZG~Ekf-#V8IUiteR+7j~FLt29j)IW2Nv|X;B+a8} z68u%fOAFpWd9Pth9Y+#k=u2C;mAqY>Q4-b}JT~uN#ohAGy_J-8S=7aFTSh%G>Fipk zKq5t9)7uK^asBJlfC>L%G(59x{up5n1iP?gruoMDwm?&hdbQr03oMJ~O6z7Z1z^bs z#u;&o!y}@1-G53@337jss{uwx+{?GZmHfVmifw4Nmn^{s7$7RjTN>OCU_YPFy>-9D zef?Cu;@Dv}hkge6K0PtMuVG#7ykdC0MA0TnV5KePlfIg({6vg}M?a=*3L_w&4Z z@)4wQ6v`N2TNvQbN{?QZVHg%aXA`4Kl>!Mn>n=z226h*?9{wLD)JgC2q`O~T=jd4ZY<0*Z6R~M)=(0%?0a1; zPIy&LokkOg9GM`EHA!EZy#rmnufARkFfebgn~(jJcgHAdkK@YhAY;vVA3ml|k%&v6 zk_H%lpyzm_K~d>b7m~&0S6!Ks!#?+)-;w zZex58YJJb_}) z@b9(nwwy_IA z+^B1jJ2k@B6meeYF*}heB%insg&}GKjD#KkLkyzVXT)P4pt0VFLp%Pv9|=yKWCw5T zI}vKkmht79(NkEPT=m-|8n1CT9{1(%T#B7b=FIOpfmU zJ@n5pkJSryrCE8LLM+wrEL@K*?=^nG# zd9Raec}4t4ZgM!7x9vmjP==-5XKI;0bqzeqiQ_Muff4;LCIL%i9DQR?S>|-dox=9ZMpk z=glS1yq=gP1;Le7!?vNfyApf_AI(%0O_&hM(;Hjh!gyfLQC8`c6~)%N%seaS^&DZf zj`aRUWv$uFGK}nR0*!!^_=XxbQ}h0EjWRnD0v(Jh3;~{>)zELti$%CxL-<((ahzP# z>GZqH;8e8kSq5CPYeamtmi$CltJ{sj3%`)%JvvzLItlK#KB0_)AXB0*PIY;P*Zkgz z@2AWwN$WF~QI6hk$mB-JAy3fqWnzSy?363466hw+DC>3QqIc=q9UsFMEKIb>3At^M z12jH?Ik6rZApP7RoHpQL^vvQqXb_B z+=p#rrl~b|WFee!tlY;HS{^59wxSx7?Q&97VruB>`jIvqM1&r@JzW$u$gL&NP=U9#q3rgj?yG-isr;TFOzxx7zbhF`s5RKJ=R znTdGm3U_ih5xf~~Z+PcSZsfGwqwL-^g)4fLlbwQ#`N`4mPNrh*IT?Hsd7a%QOe< zEkU_tk8RG$xw+4`zPXaF=xT}k} zv8_{+;d6^dGP*=1<^hKEq4Ma$uO)f?HE^E1*^`_cbv+_^HKQ&RcsT$;Df!FH<57Y5 z!N_v;O;5L@^3>C!>V3x`&u=;Dmd`>_?i|sChj!5TyWsN$_t>MbZS-*@TdF^L0T;9r zB<9QhWdZN_L80;T(s*|Jg{q)*QF6d&c?Wa_K>{O9S6Ach`L!ojRq3cvm9?tp{D7#o zwq#$i~EK_uScB{w|B{O!HjrIVFC(P%|UeBY&As0m$`^3q$;__pk?(hTjibqy1yDbl}ag4n$W7Hu9??3*CvNN1|#nM9Q# zwgQ>wxibQ1J=1*RKaP%uQD-=`{2STk4Lpg|9=b!8T~XV))_st)6gbXZeH(VF(achI zq93fwclbz0E|VABwGB8W8o3ROU02_Uf7WeXn8I}W+U15`9+Ho=CJ zZ52ixEO+(GZ;3Ia6yCf`)e*i+r-k4-X8u(7{G{0tX9zD{%+onM?+2abLW%}WInRXoad!{SE72mS8K{*rFncn=CM)xfCAy;qvn)FMf;97c7vo863AJV<{+4uh< zVia7x>JS+@Ygv3hEWCY6!(lR$y&`sX9Fdq4GIar27nt;z>xQF!!_)mQc+cH=?!2N4 zWa|7p@diO;)PCm8kLJwYH;W%|pT@D}YsNt5*-u)I(#xI~^-;2JcY#c5zjM&^h&0#= zomQTtA5@_P>_&5^%@Ysf%EdZ7xd6|o{oX%^cVUp|Djc!cfq_XZnJop2yYiin2M?iA zM|AKp=iYkt?Brm%G4Lpg>gVx144QmD!ua;+Qb?Zvmi0^b^x60qLV&O+%b@P(*U+E8 z?7%t+jnLcrL^xXZ*;fi4S^ut_XCD@^Pmxgw7DEE=oNJjseZ3<-Knscx^iF`M^M3QT zD35AOx&tk4dRrgwT^mgauWtH{{uF**yw&of>a>z?w$kiZh}y#nASLzvitw+ooanLk zrQ`8zGI!CukL<~~{EILiR^ST;+jTXTuVy`TeZlCD0hIv?(mx9;lh5)#7_g)p1*(}9*F2`Gj(qMnA$bIgNan<&y2I?sLe`#Doi~KQaW9VB~D=U1?OQ6Ic z4!yeiDJgIxGz;?~U{Y1LHOO_YH?(ypgCLRk|Jyqt^psyWRMH%*-@pg;uz6Zq=fPMf z@C;-2vG-S12}m)K)Zf1V-5Zd zj96za?KIma@HMR*AT0!{(k(OpFJn(=$*s)EZ6I)#Q_>In2SUfe zC6-)T)@PX$L#B;g0Ik6Mr35_pv%jT4@XcS}qJ%)C6JF`aMDmnQMc=dDj zK0F3dzpUS@ltI}Ix!{3w%hF5*nTo3G&|9Nkci9lw-8GV-`vm!O-BCAHh^c|9o`K44 z`etg?pHaFurq)=b{waPZ`M8{{E&f4XequVh|S;e{2cMx~4joDTumDPaa>NU=h zg?GKYtf1j^=7!-e{vNr9mW^OoFY2&| zPefxM`7sAt=n_j{azJ0>OpE2qgo_`amNWzb3j)4$;WC%?dw;Hj>%ogJT?8ozJD96P~(p5r2Wt@6Yr9!6Y?gZkC`M+Sm8hcqKh0}?WuFOec8xsvzym( zEo4gk<$zQ4f08t|c1a)ibB^}E`V{OP&j;d_D<|b!)Jg0lh-jT?^5=-; zQH~MXNz8?&4TR+g0$zqOHd@U!q5f3R5qz+(8etnh<1N^`+2l7 z_2gAGhM@sShV$OLMq90qRc7kR^9M^4tl{N$d>2q0)41!{!^U`T zyPyvf@t!b&o*za~sAA!NDB!$1Gq35Sgf4S}oCY#(ThB zt~4c#pCV5%hZPeDM_J_k$qFqcH7+Sh4?lVGROS2vGneMnb$)~-ke^&i+%?M9V7ITD zL6JYA$2eW*L&W|!-XC2(0uoipoKpl2Czg#x&;f!)&*eK)$JP=h0)&p` z6+d<5;GrDYAwkJd87>?|1Xx2r#{ZEHMph{P6E;+u%T+%G1wZMHg;v?Iz+o*1EFfDFU!_kNEn z^!8@lCagYj$J&cdMz@(Fx609w|E$(=-Jth3zn>cr{gt_&j5u{bqM->AQFMb#nP=wH zQHrzog3@*I+4Fg{u?KF9cOdA3knuaaVdYZwsE@FBg_(hE=KR-7s`u@v7Z;zj6r#~4 z!N!)z=~DRRRmJ3P3+x2!_h$#Y(+B+;Ve}twn^PN%A#T^zFYwfL{N9IEpIKc6OUUi& zmn_tyNi@)k8PX0NW)%Pl>+Eq|w}6FP){b)!e^}9OQJAC$y5NgHzl&tW89IGZmG20QPsi#joU_&Ur%%yoVGUKq`0LJQKslygaXVnpg3~2 zd^#-i*OWv1FbBubR! z^}MSt{Z|zR)>JYiQKU?RABd(R3*J#jXsQO|eA6g{c+S!h0 zxb6RE5NxSa@ibOYaswu(0E-|m@HTAV^5fB^F^$f})_i@YB-$%ET9k#UoXSXODtQDT zd88N?{Xg<2g-1@6mCW3@f3?Xn@L3{{mRYNxD~$3zFH|9@JPQTP2$N!V#`RtKf12)@ zg2r;}RwB>wL6{YWdbXb~=$Y7NZ}Ad2pmnVZSi<$|YQI@dL{lAH(f|_}Dq^($WS|4} zCn<~_m;1%&h9<)b!#acJL>Nkz)$r3H5@zA!$>-}TTn@?@dD%}H9N?K@+|e&H8Z)Ew z{UWxt`^Gzh@8ClY4D2pI3>~wVv+=xx=9S!uCl4s!X}0d39u7$b07tEr$nm+;)Yg0r z{ONWfmZnu1_i4yutON2Eeu6ZCV zFb71+DBHWCWq+2z6~nsTQ~-Zrlgs0X-QlS#tjn0`dpSEF?rxE82(CdYo{SL7)=vmG zyphu7c9!!DI-Jr8{L>EQCRXGDFwd=cns5P!Nw$dPlz=Te_ifvM5(H%vW@z4=ck`O} zQVW{dYOaHyMV6zg7?J`TkthRw_+pZx#v2V?fjFz_BG4q?hPKKEB9f7;DqsvI`gA-^ zoMG|t)AnqtdH4TU4g4lODOsZ}*}B1*F!RSX*Lx4t-EK)0()5COQ_H1&LdpH9akjvV zAhj0|D-rV&k5)w}3+jV=kNa4PA8~j+|H;~UhR3^rk3S>X{YveO{#Id&Q;^3Y$ye{K z4v6>ja9N1mE@XiJEgeSa0mb7y^ECD*2)d9pyjR|Kuk%F6JxoT<)B8=Ct#aPd=D%G> z`F5>?5~KvBGf{qKmUQc(A`n>`^v>oC;!KpQ=`s9CO&>s>{co9(5!m^YH17HycENRL zMFu?eL7Z1(kY-7iC#2`i$63>#2e|dgclqzP+156Y5nog~Mpi7Ea;t5#cP&jgxb_L% z796Z^Y~#OD(dOEIaM>9L)-D305VwQlGe+JellP*oM}J2JDbV(!fB;)mT3-cK&zUmQ zkFB47t8kt?FP;}drqnpQM{Y-{S~_*Fyn!-qawcqA%ijXVlmEIX8NuTYTY~^cy_w*b z0S1O+Xxjr|P>M-Vs)?*U*AoZ?G)>)t%Px8wyAPim_HE`3?>a#vmJ7SS;^y3JKbyfL z^s!R%FmptFYU$>xt62W%E*%|S;fzdrlM_!CKj+8aD*v4aB4iCvFu7+lHA%cEe%IP2 zfW*0#ZKGg>1x(()fqwDYJ~Kb%)BxkFjbkPXDXFAJj$qrRN)BWy4u87$2#&#?NX2w2 ze6in157FY}0SSWnr%-4>b(%D8VsZQ&!`P4Ko=inv$>4fg*)Z8FZ3x6^?m6<~m~o_g zWxvZzIcM$Z2kD^A>b1hXVbPPi#k;*-z%^+Ktw{fgTkKDUmWa2Z&C1svB4O&8&;DSR zu5NfGO`wWaZ{KApK-s}vXW(SgH!U=YlJ;4yFuh9D& zm`B%y{DN*j`Or=1h)okt7W(Kt;sT62^6ojTJ{eD}9q1$UuMXN7H5IkO33jtv z8;$N2nrbM}U|I z9b*JEhD-ygo+6yC5^*KqZiE{{QTtm*h&gA*5}bTwfZ-fdpR#lVP2Q(~OKY-o{amS| z_d~0c{aKUCdY-j0Xkx`Se0mi#8Fa$|j^nexBvR^i^=n#0 zN%2#5?eej5Tn(@0{8HD|=&l$d`3>mDx>xNN^^=zgu5uOk?BPF!#wTd{7frkYCo9_n z*h9~!b_)ROHiPazy^BR=b!l=d$|#KhcIM~>XI}dkUmD8YV>T5Ve}G}tFhIp3BEdvB zmq5_Bt>;ZEku9#?vIq(u@-KcL1BIVhB@hFMSbW9L`=ouPLoX3x(85N5(@F`P%S$Q> z!a?w7G}dF|4Cpe`%uILsVsWebOQ;;M7f>LM8pO4%tXunP?zOS<@6ZaT3-b3?5zqS1 zvhA%g3CGO^Ay1o_vLy$WJPA=%30l#M?%-G{1{ys$bN4y9~{xeEBLiUJR&7*TKd69TKhZh z&L+*#n(S6^G)kd2|5FX2JPg!>9>rq@%J3*ae*5MIKG9;T@m#{VwdB=`(+1wjzMWwl zGA}KUfqs>Xav{~i1*Ivnh^F!zMqlw;!j<~}_dl=fbuyB&^Fc~n5E8f8%2u6tJ49sI`zp=p5aIdB0 z=VK&4#03JDfo2jKXD*^-pNaB*(O*7=&THo^1{8J}PYq!$K6-=5QFT*j*Lld#>;5I$Rz|9jT6mOlvzmq9r-K2FqS^0 ztv9`my|>SkK%xx%wu;x8ZhWV0`Fi!L&V~Vx7=m;Pt{VrvICYfE z;?&>@-Jx;#qITZp;|yCgb0`myDW#Ca9Cx53aCBnJw7taxb$>63E*%ACAT?XH{x#Asl0t-(_*F*XZ8BR6E$)L-;o()W zLFDwyW8}`J(2o~iqavRbBCbeuEEu-|k-g4p67O(wuhI1uh%@LgxQcNcHdcvlGmoxo zj!W(l+?3touF?RMK=Y9mC)TOpWfMQUWW(k;ZZdG9=Gq+=UsT8F7je;S7c)8HD9%qy zKzYwxjrLL|!H?{|CCP>%vVC`$f5^8vg1q~*6xQJl4{F0xyy6m<(_1=k5)N)$S>pJG%t)#~r{dNdlyQM|-cjvF;2TGEpc-;7|+ns@yS@?~UW?fMO1$a*QtGCKS%se1{?^I$c$S*T> zjMqd!cwXc)f3+ADc}qirVIRCuD(mM)??BF~g*P}d&Ph+j>nr{^;~%BC0Hh68LYTA&>G8%JLQ&Ir!@r+X@g zzFp@lt5W0{bqV11laA(AfR9pcMxftdY3cTM!W%U>;|PTNqcNHmEe6YydD(yOSz%kg zR(buLwZx%SLfjH)BR0eV{`EZ`zuh_~v;5Q8D{3{0hv)an&;#u3KPZX_V(q~2Hek;f za(mn8r0gMSP~!VeFl{R-6%#h)QMUO^%`5Eshzr5SmFLWidwn)8CobGxZ4td;q_&<>+~b__TCekhvB&{x#xayG;;*Ca=UCm0wYJ4{7O31M){H+mqr^`;zTc1e4CMbL+j$sq zDS;&k&1L-2U7Tkx)KPK9a4O#wIoTDotp_mY1}K{z*K1mZRGDWiOFB5F+g#*udfj-ig{P;1F((m8-pmH9_mDj+F37X{PP`CWV+LeWzCs{))TGRUW@%OlG3)zqN=Zq(0E{~ zGpH}10|Bq5B?v@B%#=al z>vh}TEaXNYV;*85rxf(`hxJugBOg5hyBmYnTl6k$@Ch}2d=k%+&sOk;m|ay~y-$*g z^Z=}vuOeLjyYKLu!tB#q;;0hx4X@@Pmq;mh9|CV<4ZT+Cut7V&UT@N6Z17GwSADcY zv>l{^?{@d4y%_B;CA`yHq{m;OPN#rm!{9{?R+5Yi0RrdD4qmLz`4Vl_lB0<8Prtq!o|X3k&K3yyH0v0{lyl zo$w%QH4_Xl3*oKvD4xg4X+E;nWA&V6yO{ ziaD0Cg&FvaWEcJ60+LNtOA%WC`UXPIf(JZZUiZJ;=RZj(yuiwj((?Q&|DrV~u@ceF z&mbMemJ`?9v`^o{N;;3GX_Y1AN)El6+LoHVmj8khJx0wF|NUFRH^De<)2sVNA+od8@B`(QDsJc)}Q6TTUUZf85|@)kT>OpcnaQbRaJe&eGAnRb6MRbm!i z1|mUlBgJN1GugGh?jZWeOHX`9vkWBy5NE8e)WC@O6{0b0=^u2DXMZXBb znUL^dQ@!zOJR0fH-mF@a+g56I$mY^uH**cnVWYep?+ecm9_@m0Psbu><(n1j;>8PX z%t-R_t-Fd%v_?+?eN%Hp)Y>tL_p^JpeI4(9(g59do1D67%-vMCdbi%(b=7S^)fwX2U(B2L z)s%Rl1S=Lf6cEZdY*L!nz*1A6?!vaH<{0ypQwERMNHt^c7iD7%9KvyIdTJ60Ah@m4 z+Q_5i>qN*_oki^zKCc-(fbgwPLZxnW+oG@n@DlqlgwbSPGmPx|cF^t&8^UQ>`Yw1kp^LCfV zwLO>~D2B9kgLk&EOOci;D;5JpB{WcTba@+Ru?jiHDZ0^p!@$^Eh)-{w{ht!!p29JC zJ%{_BD1_&JN_b2z(#Sd0B36(A`~0nwWIiad-;_<($K}BWnaBe_Ap^DtyI}C`fv!9e3)t{32N?M1?ehnl`(=Qomr_+!s^r;h`ZTcjM6!wM z6;A`xT?BAMzj+0nAfbdYWWev5IuE}ImvVZSlc)iA{HZ&#Jt-xz?ylqM=**|Now5{?3%vSgQj}$1S_h+s{4_0ja69;u0)e z^0s#fV;5&g4lah}()Y2G;&-TDWo8lTze^8*+@1@_vz#YB3?4Zv zEJ7@CqZJ(6A-#C$2OEmrohUmg=E{>2{?x8%3mrT>PnB%g>ad(3SzK%n9%{8Ea%~(| zRcgPm+$%?&<`6!RYK+!MYvyKljbbE**n7G>HjdJ-79FA8Hz8G@cw9p{Vw)3SXdHzve_^{FYUi$;xe8V$1%#9M#~) zM!BQEK@E=uaTkeGky&v*0+g!KMQuI!Q5H)5{b=bHHtucdzDI)&MQhO8K(Ft$QVch@ z5Hh4Zx_15;pe@^7pvsBq+F}X>QYWmVA`c5jh%Wuv_wlUPogI^DCQLL=qc1`N>@N&) zN1{Myv>u6&hwc#LWpxdZt*p(0Mk(w7;#$ zKV@f*XnWyzZ{fn>{U)5x`sJ5oEe0p1!4?u`oLFcmEXDYJ&n0n-j^@9RFw$j5RgS)U zV#PmQE=ru;41?z>gvO+K6-=O{4N+;%l}uTAJI9B2T5`+zsqteGQ5%`Xr=Oy44gcIS z;w~o)4n_-XKUXTs8g`Ra5vn)rlOp9&A@j5r;9}LTbP@K&v0MC_uhLY5Q_f9sAA&4|;jC$- z3G5040}4=?y@izVE*<_30bh3`J-RirOp1z`h=(WZdA)lR7<51gHvn){j&l=-izi`; zbE3O`o<~I}mIgH-@7QV{LG@pN$?TFQ8zGUyki_%K2mEk_=WY;JUTjK@tw+2)kb;ebmzDJ-UJlOOlv!H?Iy~VZRszE zV7t5QI#}akI*%9fE33ks=x1B)?4!y~`lHzlo=GN04V=Bs{+)TNik1KG3E!X%)7`yH zl;002P*@r(9Qb3RsTS23@0?^MoBWbj7-L$p5=T}$wevB@lP*P>o8dyY zEZjTFZKO((btH`tHRUqw+1XXcBUySkyKc%EH5ZO?Wm>gKO6{89RDKB#kvy-sO1Mpg z77njAKczQWi#r7nz*Wv1Y=b3U+=8i^SjeNz59{%_h=PR`6`JB9(DZRo-Ujq&i7I|FFx8pZ7Lv9 zLrj0fkvl?R4R=3H2Ka188DJEg-c%dpx!xX#xN*z`!rvlfpXXv+7I%@xeP4GML9cl!Gfu#prx5ppZCFwM=HkfLt z`NQN<+*FiIwNYA(LYi?Nf@Ax3dB13yl8LFk2WA|lf%J}iZpPv`o{TOYc6GqyJuL%p zaKD-9$%3e(F2dB^TIATcQ9Q9AzclI&k1nUOS4{|N7*p^j5{ov6;?#-V^Ck?B2ZoBy z$4~`lt_wb9L^vepm>}uK-Bf=&NKhyZJ&&{3z>n&ou?4PM_d0G=2}{DS!=x;G zh(xd~^UuSKfh^#O`&4L`q$AIy-*}FfT2^#BD_ZRb&yf9fKI}JsWVeeP zrAQLx2{8BOpIMxb``JK`1KtRtZR{klZGVtiu)Mkb>f+RH7A{Z?I@yIBt$rR6=Vcc; z>87{JjXvT>v+bQ`1>qeH>_fO9NTON!@Qj2%b9SJ+Xf6U>=nnUYz?Bj|mRc2}?|pcE zU;beW!plqHpPg78p)F!8U`Bu71PTk})4ylJa%PBTWaL^3&po>*mzjRmH&DxEOcn<2 zGC6KuBc{fqlG9j1F;(ksUF3N&7md5E06o12kF!u@-QZ$8((#I}iLIcUrGeD-pO1ek z-)jAsO}t7Z!xUZl-*Or~9os|=_pvU(2Nm-zQ1 zKBL^x)f~;Sz?)L^I}Zt=rkX}0I>)a$5Dy@qVy=cB?YBqGqw9;W9?oT%DDY2d(tnIg zhTcly-ihIWCP$qo@A^HMz=tvqLOA6O0yjM~_{=j5b|p3q!q^oQ`$i(UZK5?>I^;K6 zWV{FLEoZ&AA_|%bmr+ac1ZNUPP74j);xxsUrRR_-f?k44H`VJ$`lGQqzOyk#5M}eN ztL0OK-P4C=V%#7a>WpCacoR&DWzUN-CoiT>5>;BmElW-AT8mp>nMm)5pT&4!$$kV( zrb;kNzKKVK6A`$eB!5A}&BX5$ZLT?j?qMkhK&QLtx1WuxhBd)xq-utf9aOF6Ag3>S zye_X!JHVOhfvoFcUx8dG1QZ88dvo+w?e-n9OCq>A##}_;8QM& zZ1u{>EC9NwlLNhj`3N`Cf6{N7#`@JvG5M!jgHOggPJiqzBMp75+YXx6JJpD(EIFR3 zY7V~(kF^Gsi6lLoF^Jja@eQ;=ZHdd+;}dvCoi*<0ygXKJ=WG6gxqOFo)93F6lr?Mf z|CvDto58OaJDJWbGVA|4y#F)4uE6M<92hfLt3Q!H`(WPwOD|&5j!9K3gJQUdW}ffP zZ0>BO>`U#jx+Cvo%xt6Iaj|4)^T8g0@mFJ!0j%kXP4_Ur>l_YkqmJ+BQd^@eObu{l z{vdJyUQ7==TMe_n&lqXfMg);|bdyWjbc_r53&GD)sXRW`b$f>KB&9}FC%U#r>$SFd zx?(D@B48avqqDnX=VdR8WPi@~uOJG0o`z$)$oE}zRhNJeSw%%V#B~8Og{D3TFQCox4bc2qL4Pp&?nLA#KfB#@N5i6e8O&s=hzkap1qhx|_lr;4;S~2f#6ux?S|x zd<^MxOWrpt1`ge!w_fbJAvZ2@lg+Gft_Y_c!0}IJw}@mQrIz`=H-mN#)|QHQ(?*Fk zqmD=el#mLEWm79#ELWLFenYt$Aj;{_M<9n|8VFYw|GqtTT6|AD{Yje)P1y z7PQH40_YOBzc3Y0HB=FWK1!olqdj>`&>4SCdi?q0v7kTMq*D0WWfaia%{RN2n6Gz} z)MX$%KY5_nixpHIni0F<8xY}^`{s!F@8%~x9JpO+Zuo&)I`+(H{YKj{0dp#Xn?wiJ zPCO++oqkNo#?ARwk1^x=QVHrnFm*k!!wZ`M?wifA*DY?!g-i?r<{^Ng62P+IplMC= zYQzS~-Qzg$EaNF=Pz4!3ij9b!kxyAvzrBc@v!fLG^0kOO{yj=sav(+h)=Gd&XKOTHfz-eN`qO1@2hyFmMni<9k;dSAe8JB!Yq zklM_oJeoL}e}UH2yidh8eP!gu64OIUBsJ{$?Qr<&B+)Yc5z_&(l66h9^83=&b;6wD zBxtfPLETG93eq$0^lTngSx0}Fh3XXj&eHo& zE%>WQ50vZ!7)}o&LUvGCR)->8lYc>kYr2BrQ>OQa+$r1a&FYjj{|EkYBIu8rB7|*r zv-%9K!QY9^^45ikd-3V8D~w$-!!>w;9Cxr~IsNs&0Np?$ztCROJONLZ*WY^G`D5;{ zkH=Oj;)qyz#ix1EKUz%ohb{;$109opYukSk?uYr|x|)%Ao)a}q)D#$YpGuDs)AU7F zdLYt=Dk(R{<*o78K__RI!*8yO9P>#vbSO!XWmugjV?Nc5lAgQ{I{DM@eyTMtX<*or zc*W2dPCyE;2#p60Za1*&zPuYqY|Gp-vwq862W^W;*do+Y^$TvgJA3pD&F@xoTqoS0-!Vw~l@5wK6@u20oxSM&63&;Jy_^=tei^P*p2jiZn za&Zf1$!<4J$6H|I=pkQqd`L2%%%OE10>Ir<_IAk9bghprYks#^*ERp`-rR_FTBk8% zcXo#C&2=PxVfGL3$=NwamH(w4ocGo%-#VYTLV2f~ZC*224H4yg zerMs{w}R^_&pTU;S7Gaop;aN@?|6y&`DTm%(~H>;*XsPenesl3k9-?=wx>LZK8zeu z78w#y3{gi4!;)cMotAseYOwK}xWMOJWSc+9Pz_zzfhdKy`Ku5c8Hbkp9$3vkoE>{} zjZlu#JXpkGhIn`Pi~(}SXx-;0j~9P08y<)5IPZgZ7kys&f%wQ>DI!_nI6;+FStYx& zf<;%p55~`4e5S{iXk!fviYBoV0+0y_&WqtGsvc||*uLj~%bKzHv@|=MoW(G1ZKAjH zg@djxdPcVHYrp6IF^_dQpO{2!JTzQ)e1t@Hl-7(8*)ra$^t zpgZwkSq>l(NUX>K5E?^V@)kjZ#MjQ4x$||#fAUBjQRb`O@q_7P~Ib<@fCiwlRxdYg6U_^-nQ&C-EasX z1Q=En1%xDoAh~Gznf5Ga<7h=}154-E7tF#F7TRX_U?tP!W5BDH#tE=ipVG;6m`-Ek`;g8a(o7A zzb9!29lP{Rl;;kq~bmU70dlHylPcU9=~>m*##9939=$109gg^ zf@BENajk+e3FPzn&fwjU^xKc+%*m2}NJ}s2x_6K}!b)@Wb%YhreXk*kW5OP=;(=7=9Kv_b&!DD~@@7=_~ zRYGTXK6e0+Tg~#Sa^UD|?Kl0A{6ij_7gy+Q;cKuydEIT#?T9G22(lnaJOfpo;lm0p zRV;95x!;1R{hwR?T^e;2BOoZUz>5%xA{jyw!;z@XX7_;D_uKut2jWnsFVobWp)sVp zdINxKuXu9QX4$&W^WCR2o9<0bE>BrF(E@Jp8nX>InrW=en_9%}AfHg~1sex6i|yYD zhXf1b_b)TY<5x~2JIG^4j0|AES6Rk_p(`_AY4lnu=>f1FrB?L{S=)N0%va%F*$Z|} zZaQbhl!((^RU}S@qAoK=_~~BB6&Z)lzaPN9j5!Tz-PVkL3gYnwvT}cADWl9-%d*69 zk|7F)fnbP)LFL2tf$t|wy7%sP=<*TIBLo=$B*+UaAHs*7L%DbwwLSa6cVnCj)=#Kj z;EXJkZ0H6jF_6h29c0|fpPa$i;Rv4&E&2dBJ>iz=&+M)cDwr1ZuLvcv<$sg+uUkDM z6@N?fuUK@Z`XKme_N)y(8e<|*I~;p}pdyL7zzeF*(S+nJF~Qj32%kPm2+5>}#Lmvh z={t${`&sBD$@Nd3Et4Us%TT(CrlY3^fIkFo*e|v2*|i#N67viaB*-965|AMAiV_!hy-&M?O(fN^WOtljR-l(VyQ?hW1S@oFCLh#h;TK9F2-CQWY4 zgC92L;tfR4)L0Xq&%)_Z#K6xX-kZN9IK7*~IA3hns+YUqdknnV=#^oQb&ANqLrFtW zU{y5&1K+l6#UM^A5{-d zLn8e+QDKfC1&avY?)u6EAty*h3?TtLL`>M$L^_KgEq)?0^H_qT|Cw0t+X&LwAQg|r zN$}~J>?LRqT@%6xlE6x=B(jJXg%BUWr#JgA;6v#?%D(U`nCaMaQ=PmhCIz`hsZuGwnjHeWH2E6gw45s?V2-=W>%5q6WNY({~g+Q&n z{IA11_TF3edJ5sb+UbJRaTbgye`o7;yXp6c*&K)1fE6GsK#rHlY4H0yx!wIh07rx93%+@aa4bx?%WA{El4m{; z=5Q52=vK2bGITX?t3S)zM;|lRLLJRfsW{McNr<+Ubag-M`ox|GzGIHv4hm z2H8*{;ABH#G{n~4d2G_XJJzPWK$PtzDzP08t|{rpjy1KeHG|oLr%dH4yf3#_D^};? zH_T3d+zc<$-OT^#j z5p#>f3Wd*FnDsCZQlL56?!7LU#pzE>qP=E%Cec6hO#GIK6|7s04Q|(r$AWe1sb+rv z5_9!(sqcg+>)V=0zh{>Bl*u5Rdo1_EkN27!P+ezGJ9-j}9rO2x(n=@)zsz>U5k$+0 zqWk~x$8&KvbDq|ExIz%_*ef>!-o(!iHS=@D2I0wO#SWOBCz_h=JOLb0{f`0HLnkzT z_%P!=XYt;To_kAx^`CoX)t_@3go=82*E3l-PIPzo7y(`D?2|LY`#@=?X9L z0K`C~35b(twc7aWkMEx?gY6M#6_Tls8*OU)Z;$+57UlnTM4CJgY=QR*Q=c%E(C%#@ z7{z|(d&ej=z)3uxLNJoJ{ZlHG>|848{4N(D`&lfoHWKoLVn^Q0#Q&{@>z}EWsY`fm zr@}!oF+Fz7%~Ko4hnu+&AqX{%=M0I_myRg&>c-E??zAPsQibM4{4VYaYo{GWq;%#{ z+*Ljfb?u?Ps$nRVeXjryKG>vY%v+d!FA#;*+|sm(-draD?rdLHw(bi|bo1y)uddHO zeUy)-P5k{OW<8b;YtJ4u=+jj-2xcrq+~E-G?lYmc?DOkB@=&QWfgO}|ezDg< zCo@=IP{22Ymg#08>sGR~iD#A{^sYL#xC}m~U6~plSGmE|R+#oFOHG1uJ=L{j4LD%A zqOSTlvTq88lNenWB|%};`m66*$5h`Cmq6rI{2^!vf7W;Q>-Zks2q5P=orEMHFai`p zZ9(2%n)~ZOWm*x9;5RQE+HmA=?ARxalZsqVnqJKfWRc?~mNg^|zW&4Yv7IOEPOMhM zMkYo1e^LqM7wva+F|IM()be;e-_2B;aG6sC9cr=&REE6Skw9pIV=TwM2|W77bNB4m zBiaJ%y2R#0)7Ft7hP4I0VS0Q-99k}bSq*wUF>n%||GmR%lo`m1qQNT+r?IQ64w_ik zb3Sp&6;7+m+uPL@1!>M;4R7}%YMR;=GQUP)$U~%ju~!~Is{+&apOy8 zrbRxw&7r=mpeT&MbL7$O97^5@oaH!dE=?Ooy@ zIx3<&dC1EuVic$u8tLz0wYeova0cVhk_7m^Q$F%)tvZnut2!%-oTO_k!!xvVXzb0f z8hKgO87*@l!SA;n{aEY_Li;s}8(jJb-Pb)UE4!;#(|wt-zEL7N4}2e z4gdU(sW-#-tGzcvdn=t@pB$qGQD6Ynp{h&z`Sz*1mnA30;jsC@GJuZ$k zF35~68BUhoY2D!YlY`n!N~lktoVkYBUfJi%8t>Mi1OyK1j0#jzqG)GXT6Z|M@do$k zpRkcrcDPlkGRV+41puIGcvZT!r@!ku{*jaO;xKPIoxmi}o?AKVn4b4v5BP5XWl1sg5brzjmL1X)w!dHY|I6o5^ROH>Qjx4mIxDF%C%-lM#){8YOnIKj zlWa#k@f?flWeM%sZ6;o1PPMKChZ7+3Nv7ORvbs(B93kE8EgPA$b`xn_@43$4`ivzS zPWs14rQ{!zx1&bx#~Q=~E6+-W9f!-c|4G2@#=#;?la{>t*0kssvVX4B@x566QQaBL zsBAYIfNfE%{>NL#zos^8t+~MeG}E8P1V6`VoNsv(H;fIYgJha~AH!U;{r6k6m-hc$ zS4nSez2J?<|7m;XkHk>cN6U1>5XVPzo6>T+9X{TA;D>*{gEjKKtAwM{x+aRMBnyft z>TXXCyQXXIW_i}+>vK54e)-1 z<=uaVMgDF?T;x?)QeYJkt1pEd%(Q5K7b0z#5NMxum0@1IOAJf@DUzF@lnYRik^nX!7VA_@hU3Z7v*~!FVQ@x9_5jf%R*mv zv7w|qn8p$7o1AB(u5kVIqKlk=dX($0u=^PXSi<>Tt`I}vipcp`(l=ohQ!Ay#JgOxnXsy=xXkc(&xa(rr?q73YI5u8q@Q^ zSUW(hvlxQ@V7cH$S1`YxPT`jin&~$va>cYL<(MvnHY1*(gP4DsO4R>NBA?oX_63jc zVxoRkhh(FNJKXOuXUK4Y25e6w9_#J8pHqlXw`ap ztc4tp-2g!zFp|UwENNzP4?gpvoT<1RI!x;_xS{WPx@|neGOP$i!~qF0EFz0oVBvyQ zhm&u<_qG00>k#4(F^h9OdkGrSIDwHN(6pp>i_b6Lwke6!`y42wPq_yP1>YEp|MR=w zfYU3c?0VrC)jO@gN>CIa5247gFvP?1YkhLFZu=0egb{G?OH21X@jLDuT4W~#BzIpm zD_d{xl`|&#Jt5JZQYbidz&-G~cYhnx?>@R?OehJElQM}4`Mhx+nGx82vcV)nt-41lGe54_L|IBx=eIXv`1%s@cvnJf^ z3HZr!vZ({_g|R=+nD|L+y5D*v3J@6@fC!O(>u)eSYDJVxfyvM-L|g|y;=Fr z?^qRRn#gdh4nu;dR-!EPY`8A_rx!j-rnW}{tiT8|&+DvC-nlpypW9Cd&CE5+_Kbl; zR@`uEW!Z+I#Ssx(fxEpwkmC;3Jwgw-Cji;)(JD4P;VxMIPYW6ripd%SH$7DQgV|** zJdz_fu+Lqs9Km0Ly^4I=DQMj>F8AXtw2t*F>q#L^jin&Ew zeP7u8@%zz!XZ7CXQf4(KJEG&Y{P0xUQAR8qRakbFQCW!v2IS%Tq2C^MZ@nomEcNNzepFR9GmeA(r>wo~lnF&XeJanZIoR z^9`)WEpX#A=Vl`dZ(lTIQBII+@@{9Vs^M`_1x%;oE@-UKn|aGcHhX0?-e7qJa-zUK)-6SIY36aLON!SMw z$-~m_%hUWa;F(0;y{Syp51Y-UTl7PZQqqM+tDCPxdHybup6Cp2_o^uCPoBY-qbOP$ zn-d8;G{@wEwvt^${c-s?;s!1UpRM3K2`|J(p1;w;by2>zD9Z815fbt9@lodA(qcSu zdok`z^dELf+$qZWjp6@_IDc(#r8X3VFR$?WUo4dE^u6%0 z8AI-wbw9SYYv&>b=nDbxIDuQR|MUXbIbK-RLd10L^)_TyzwpqJ70dHTp7)WNbqV}fY9%@>j>-@la@o$k+uiv!Wx0iU=;G2RvzkQFMy^i=MTVwz(-;bmi6Px486^t;T_SpR z@)Fr6F22Ubx2SAUmr|BX2VAB5#kB(Daz1^9)cazc)sQv@sYR>@UcXty^8}0imH8W+r+h|4y<*Jwf9=v&#yHo>iWfWqv}=OKQeg%!5p(g3#0#(eLk)`OP4%=_yw zK~FG!x$P>QANW2Fo*yJV?d^#CoR$wxV>^BlUu?PUL5qXG;@&&LzH+e7njR&bzZGCR z%pDYZP2R^KpC?o3L@edG6*RTDmy%4uu~C*&RJpwpCH;|^-(KSXRN}oFl<_42-)s1j zQcrB(u2IIVuyE!Q(+xMVpIGfH*!RkdlzyjOH+#v%w2;=M{i&6Grjyc+>csPswsRX> zLVTf>FSX+C?_?O9y%z7&#tmOzZd=59G$GQJi^(s0i^zXp?EWrk!1H^L#d}*U#=Wro znyZlS6*t~m3}t+pSbS$?ubviV{hdXW!%JE|yxil-M0-Eg>OE&M`OrwEC~4=uA=FM_g|A$>Qy$Yr_=)y{=KahQzD1e_RCp=~K*oA;n%I_Bt&BBp0&Y z_B^$rF!aqH?@I$Xc7$Yig$>sbOt{J~gx*oi?|WGE57uuCFJwQG_m~G$SZ!|#HYq0K*SH8CrLe4Ce#G5pVW*wjPJKNGa|NeD>z2uiZjZmCZs$_m`?RBKimHz$wjNq#36fAnH*2(9O4=bDo>s-K&#bS{|9`1Qry+va7u z2-h7hFqLV7%gR_h5!Hdgo`^F@|-IX82p4Fi!0f|Eb zKyFR<2Ygu*)5ou0$Sq$MLyj0N!Vv~~FoYN3VdlQFD_*2VRTm||@+>bwgm@&1WIWS- zrol`3vf-QRbi53WWplEao%ERYoX9bP1SCmhAPNm}eoJyN4lQCSJk*Q-cU&AcKJ4NO zGyPaLXa0G7x;M~wq@1na6Z`&OwJW5@VvE$jia4mnJ@G2(@4F-gx93H(pZYnAmv2d* z?8RTCd@ojgUreM;zgHpOoH_l_s21iEF*Nc^?i@rs=kA_0Uiay~oVoAGzTK?N7`)doO-pIt?oA3SGDi~uR)3|*V2@{^rVlEF& zSbqO6hp$ZU(FUD}7~Wb{MUE9@2_nTH112pPaFafol=su5};hChnN6LP(RY}x7Tm_$a zr{+!lAa!#ENMa!3c|j0)79vP)u7|(MEo3>Bx~+y&AN+CPBS&#`?tNi9j%Re);3Y*u z09<&cd3?GWNc?=o&Kom7PN`)rhA);yO<85)?(%IpKkY``16Y^TPz1BjBu)Oa70}kqA6QjL0(#&+rTkQMlZ0?q<6wOwVSx!S_z< zNvrCG7J$cQtk;v}b^G*yJi;xivczaQGGtvNBWeyYHE!?4)0m$v@UF*Rc=ba%f5owY z0~{wo5lVu@0J1g1TIJ$p)S#U^;C;JZ`P|(pvSw95iohsP6f~Youkvj7BXJ93Nqymr zA|8LzBTs)0-x6jI7LL}%97XtbV0bceBqP>95Q>7LiH0b+p4}!r^0%`tQPv!zaCIx} z`$c8dD_A@yVNnrH=E?8qy3sG-#1GH-KmDUjsNkllZjM8woTgT$O|h?Fhb`^*ym5be zsK&RT@?Jwo;TT3jhA6+^Y0J`~pOz){0|U;vqMl05AUXUyxOPl@Mypk|B2T590L2W? z8LY}Pn#jw0|L>o{^*f_javm+eM5g{^xj0RGZUyclTDXwk(K`M+ID6A`16Ms!JMvEE z&&t%@j3)4`u5w6Hr8T{F*Iy7}BjX56`@gV2`%WvN@zWg9_FMbIzqS1M_X?p3n}T7Q z0T531C|_Ovdv!8a)T}grL>p^9f0^!qpS8)J!#1lPT4w&ii~&_B14$GO5zTzz)gz~u zRn99~osf&SnfI1}`TVO&!RgSVe}v!!_ig9?c(}g~OCeYVXe=Y}s-lBWs_&hgI{S~5 zszhEzy+W5*LirT7ywJYb4{ti(EyG&|tDFkNjn82zJl?!B9m(C*o8j^5x99L1ojrPn z=HLHszq?V=#xzXk*IXA97Kavl1WvxL_t0ZaBkGY^O)^A=1)L;8lK!VqS`_0r2A`R& zj7Wi)2vmze1O&}6G+C1+r0Tc5^5vdQHx5e1CtG9~?%~B8gE1FrY;P~2?`VwCF?eDAL!y9&RQhrp-nsa?d$-T55Xy}e+*+W- zOdqh#|3~r<33$-9#}saBA59O)yJz6D6>Xxok1lIn)xMs9e!hLG@awY5$+)LG6naBF3FkoZ z_IW33(+>}F#TT#UmPCaURDw^@GW?z&aWde!=FuO_(jCaq69b| z@zPSqq#nD@WhXQ)W?z&Rzu>UoTcWLZNxP z&hiEN%Nb+!z7sQ*tc*T8YEJCi?z3bZm22ybHv|=V>OW@?CgBtFeUhDVh1vSACdeO( z1a#}^j-yw+UY)un<>&_(QC9?(n(`}7|X*kgRNC(FZA5}nj<42l-SsC?Ltf`m1EB{d!E@~ z!_@*dJ+tYV4cFc}y3VEpHe7~u0IR64)vzF!%Q~!SF9{p2VW?nt!DR(y?RMH=Ly`G= z8*H$_1{-X!;p&kqN;Mu;t&P^=}2D|H_uqc-i~@l|5fsZ|1 z7NH>N29yMzyuTecB!QB31N5b~zuK&)vAZ3L`ywOD*GX1Kx{(28M&mVB#2M$fi<1w{gOSV82(|0Wm8*0PcWRiRIR!gaQ8-0V6^)Z* zRI~2Zw@*wv979^i_oX;!>03k>LD7EqLJ>Rbg$S#vV9|}xnCU6MzkM7#$Oz-1GZS&V z+vD$$zmocm^!WP*vV3}T_|TL)kFLto4dD*wuFu6oifP=RzfPK=53cJr`&YTC`J@YN z?X$eQubwG;10J>C#BAL?LJ#zleIxWh#fB&TTb7&{i)Yc?)S}hJW z0|k5u=&Ha8s>-sAB9QbTo|1QSbXU@-eM}GBZDGR~ak|Qg63-g4!nyq!S>r1mtOw@Y z@lOoSb#_)TCV}=mzqc8*{q@LI#8!Vnv6^j4#< zek;4MM(E5Aa<<5c?tXruukQDIvb>}hl~12a42wgH>x>@gWBmH?t9T)0hh0cO;gJTR zA_9hCrj8l3X4S?R+=M>nSRFOfqhi8i-D0qGszd1BX#KHDN`i(v`)e8*5B8nr&GAOw zTlS6ict^DNPxPuoZ;;Qu@bq(zs+1a#1hytolXFB3d$tQs-|7m+oQdn1xKT_n-+}YJ z&U^rg@}VRA^UxmZgI4YOuF=9*u*;vL6yC+-)w+5$eS%v>imD^dFo4XY4jS;|?nnBk zRxRS{iMvSDBCd$<(Y<%~MWf$nukZP+W+Y0kiK?or3=5ILT-Yg(4SMj~oLvgjr25Xt zICSstho*YsyYJwm@chOL9MWV409`{g&u^FdGHgtg>6jwcyQCdxMjL*yADX-2)|Bt= zizu;iipVMu3Q&a%$)Wv1odNw(W~(X-EBp}2EtbOQx+oz{Q+b0V=>JkMSyF#Ad}aHM4LV)N?vA0LcpEoFddVRX+b=v z60d;>97%4rGS9O%6SmHx!E36fA(a;q8MYu#*rS#)7*+ea5f7_`8QPqnUx2lW`Bjml zWqk*_^`?aHpB_>pwE7p~iSbNO-fC86rYAtQpeKPtXV6eo_lIc*_RqtvJD;PuEcON5 zGLRL4V>E`9z|Wb-=KL2k*U31pEqLTIuOA-Sq3F%Gg=gN{UMp0VHiuQ4=yj_ZvfuB{ z_GM-3zQ9B`D;(+7_4%id^071n3s(tM&*>P3UVXamGY_Ax9A?w>>f_x$M&t~nA(nxR zaIS8jhlc;XI?qMzI&*Vg;fz*J9*+K@rbmr8 zl7?WxxK(aEu*X*CD$<@a^=T<)rK*~hVpl~LHwKwi_&<~7?QA|@*uYl2+Hm=hlHn-1 z-i_loB}5qrNCmvA8w!AkA;{9UIv z7gWY45jdV&))>_6xxMX@zoAkj2pBxx?QWyW&wf+`Y<=$q9NY9q|dRYsrZ0(nn{OlH`i5DQ_r;8{QrPSk0uPx z#k@NgXPL6xf5Xl7^=vMhyUwIFv61UO9)W33u3?7bWjZjw<|9^Kp(s^pxFmm^r)K1`+EqG=` z8i!+S3=eHjxZ^1`%Nx+Wf!v54^EbewS`tkX?@L5kq zJv|@vUHv>&HwSpWQ9ja zfvT)SvN%_v7vBTu*^C8fP2VV#CA_Ti8l!8R4po}6Wbq|B0VK=CY1(ruI9kM$zN1mw zYdnNLmX43!xhRb7P66u%kpVp7ctcgiqp!8!l(WO&v7T4URmicPg?#G#o zS8ua0tTF@vAWhX-Str?mgs6LJ0eZh~{}$`}M>dJ$WWeewP&LHLWIK9OrLCvX{LedV zZ#n_zT`neE-ijzn94pEal-Qn=THkqV#g~(Y6>)LYEujF+zef39HCN%NP#&9B#Ck=$ zz2j{(fv8_gi|_iE5)s4WgmIGDF=Q;@#YH?qYgfYcE$wik`E1KGXwA|^fA@n_#z;aU z3xOy}qQpZfMCdqgD!+b=4PU}D=$o_-2fl4?aqutkhODTNlUZTjw|&I6OUt-$2~{m= z%px?U`NBqfpRP@(XF0pBU)MFa40&EqG=Y-^^_$mUTJ5>RpMY0Q3!;QY)VO3XppXCW zy3a?~gF`PaW#`n3Rgg)JAQx-X7G znXPunffUM48Zd4k(y38y0i8^Yon~B5{7+8Exs-g$5FA4?@&6=?dK7l!tW24R_n8&G z!<>1w%!;%&`{N69R>Ya<2hHzpGb=E~#Gg^>g$WK;ZJdn>=3tjl+Fy&(4$Y$dg;kJT zEW_Gpp(%BbdmFvf$Y|W}oAl6Au7W$a43WUeIw$eQm*qZ=JJEG@e6&om%W~6Ojh6Ov zH0%399b!3!J*HMA!0Ms^5W}bsEZo2T$(}Y za&TSCDAW<6D9IXxlEmp6O&zhQ%B7i~WVtv^du|08DMhOX`5mp}*Ptb_Ev63a){MSt zG7*d1e%a77CSFJ@fB~G!s=5Fbx2kaR`<=Ed9r|fmaxUE$g-{k=L-GL{l-{dH#buR4 zE9DQ!BU+3_sxBdcmvYpfv+hev_%r#31iXsB+U*R&1I@*#zwHdG?+abUo6y_iKI^WG zsuOzLQh-}y3`G(JMU|04#bITI*MPGQB-{Hp9iAMg6E{R=k=nCg^?ig(j9J%O&? zfbR45la&m;t2f~Dc>NxgUp94Ihh>`_b)7{c(=;8WmHsNZl&M^T!-nEON-38YbCKV_ zR-r1f9?DVDxIZfpY*9G^lj|$mb(Tobmqd$on^4Gcb`dy+(yj_coJY~Nvw{VCN!BO1 zi1aGPLak8Tbsuw)*R#ETZMdAFAfp=}#K?V#o?MWa`gIHHAvnv4tRX@mD2zfLf-|kd z=_4)1RT9Z@bDWox4$+pLl=?JG3v zrxV|=$n*42fb%clvPa@%MpJZF);RL)vu{GQ%JTQIFG+x&Hj(_8_oz%Bf-g#-V+e zFK8gsNIu6jUXj(&?R_KMs=~DJfRL`V8r%Gm_oEs$Rt^0-13#IQU$UmU5!^QJ+pnr^ zdnPrllo#IoZ(}Gc;Q&g!xwo&{#611DGpzbdR2Wf*NRdV5q3UNV-P5qOBTw1YBo_@e zzx>jarS2zs58vj+XDICnE9IT0_>4tVe81ooQ#Z<$&;8)w(%^D4OgWM~7F%F0fPmTb zS#5Ih4l{j=xwLLH%bR0X?5|?#I&pgrpcxG&A3d2C@rJ(+1WjT@g_C(b><#~!7C3Z7 z51~8$x4%gzwL&OuGY8b;^#t4q3NsFVoy}C=5Qoj`pE7&wNC}_w;<_C|Ga3xNw?2yK zy@odcCvvRJ8XP3O*Q_<|8u1D0k%qzP&;@xE%}5XzZ)g&65Co*iEZ~vEDdF8LG)#$% zL(4seMh{=ramm-|q2(4dVMPX#R94b-RjSzVgu9?g+`Z1ib*|HK9Chj$oAhGd!mJia z3oUSptf&mb0$ndx?(}l^)|(P)Sg_5-Jp?Fe^+8+-eMk4waROD}y!73a8PttS69CW@ z4yc+E!j@Dr*Od|VPJ9Z<{-pc6uEXZYl#BI7h8*Z2XS-QWKoSEDUSPRBo!iI0*>PkU zk_uKVp}wvdWq$4`^K+L_z1+oYPjUOh9i?{LA+KaKW&9LH+1AsYr`NIc1x4veu{Z@;6N*?qN|r>ce?IQRlS zSMr1i&~C6Xe4IpUV=VvAxYqC9)H1TDBP*(;@G7GqgWvLI!j9vsD&^g_d+Q=GrTKMC z;BUD-F>TwrYN00sKJ%uFPlO_4aFV1*3QHciU=|MJ7Q_U+(G}eybvnxM;{$W6Efj0h z+2Opa3B1U%P*NFHXTG_0-7wPb|Ju&CW+d6j= z>5)XbACV?ayh!J}q-Qwtt_*9DCQZUf8(osIAul>M3A5)E1kzHV4w0^HktQu|(kW*G zE=M{3u5$c0s3-nnCf%e#VxY|GysWAc{ICPN;?JHt%HkvWmrICUw#uid<>2pV-_xG| zRN7X=lyYe#svLiRV3Ge+wJ@5uV6T@fZ3ip40)$8zEl4{KBx;CQhE~$_K07wiEjIgr%E>~n6T5c15;VskeUfe2z z4*?*FkcAA-i4p@tZuq}rosJDHFQ!YME{z z@EfXY4^=C`J~%Bfx!JblZ{6uVQ1?{C`%etV2)x27K+zC+|7nPY+|z=}R0#aUpKrP2 zAy56#qVtYDS-`nRdUT)cQ%6p`-RlYTGCJh=^L(~@G)0LO7$5)yxg6)9q*`+354lCHqbiF#^3B#aW6>9R9u&gr2?b4rieZRQRke1j zHoV^S@mtf#P#lMx;l-q#CdOyWG_M(ilLyBx6E8QhU^ePsqAlHs@9N(YoIXih1MFs2 zKB}2sb3^d|jl#(0Iq(dT9!P2Dv$J#Yo#r2+Ij)d0 zPM6#J1I+%$zFV+StgB4v{QtOlIQM|FXz5RPM#jC&@gLJX_k)MNi%jP3G8bI)YLT%* zWaDY+3~Jv>!Y}b(bt2>I$^@^od+IqOV!`xm^3(R-l)?ZhvyylN*p5ZU#UBtip7kQY>4 zC0##RJBYZI|KHq0f2?_#x^)Ad<0KJ5N#r<|3GwTBn9s$Ps9wo?@>_45(Z2Usy4P@C z$Wc2A0xu$7;zGJ<{b%OAc?x&XlmF$dyQjs!7?s_QE(53_9ddk#-3~|K(9Y_^zqXBy z>$acX6oH2_K;tI+<$H44 z#t@4N6W#@`@ZVwFkodnIk+EiGESY=VBLwfQQ|NG8B8}^V9hK~H1=oWi-fK$Wk(7S; z+!?-oxLUP~I6maYwUlT#3E1b>SmHT$qV_34;pdwb#kLkRV#2qBv_T+!cx?%@e-{M= zbC*0w@XEIm{n;wY{P6kGDx!WzVlGa-Nbs8-Sf_;R`@nUDD-XXvr48}iG$V^F;bLV*Z~X(mxXEjYN7DX}M3Nvx)R@B7Fyu zMnpQDNXHZDv&8zwF7E4|XthmS(ex#q_`j(@0m;$cpREEP(eesbwEZ8m*6HkRaJ z&ozmh#xTTU&VC%Ffu_}a`EukC-Z|#=YK_lEcB~IMMN@S{LMOy7~p z>5>9kImIo1e+g+a_eU9AXB0o>k6$MDc{HM95m6Ueh0#QfXB5)02h)7lkno@8dY7qhc5u?E?Ka8jzO419sfRb5= zn4IWnoc#0jc7M)1c{HtZA-nkyfxoj5bdxU9bfg^uIUQs9cAE$9ymbw|w>cn593w%9 zSS0WQjj_CgN=zs4Bj0}WiN0Mh0~p3>R5+KgBlV1I-Pch!{JREMUs^NywwRbG7eRpl zfP8kjdY*$xQCt``6oEy&#>pJyuCMyetb!LtTNJbVTNLwu+WRd^sQg8x?B0+pkH&n( zI41K`_CIviHxOGjY)%cc5p$+3cGrOJlLJ}4E*EA_jzM;I@rA{`YTQ|MR}{kpmWsqA2nJi4d_yQ9Vsh=GSL_x0f=br~y_izZ|ASo^^ZtJ+id18G5G)*;&4T zzrCvJe*fDaZP#*+fv~m4-e+@LzVi3n_RTQy>N>f&;U!vSF2_v%_upErz4-~cfv|)) zmg5*CF%r*+A=<$IR^>LKCB=p6Oul`3{|?HUh-a@7FDV+3WnJJDauQafj?irW&M}WA z^+>22Iwyj>iy=;OxA*zviM_^qb)SEvC!2ILww!`P%bd%9v7_eTL!Z|R?XUl5@5uvf zs{ViP&1%dbJIT%$iM!u(#uj7WGm31_UCm?W&Ggx$oYypU?SxKIgNT-3?L#BPbNhGn&TWs_uI% zd`;PH^MqPMrXIWN&oDXw0?h%M6&N2U$_1 z1d-=?Dx``DhRO9rqVKUMg#qe{hyE7OH0=$0MXm{yBFG%gi?TTGb0P7cH)c4H<zp43EGJb1vYZ>9k#e!>hPtd%M z$w^w^21elWg4uQSDlS)AhU7`hRy7=nH6?Dqr-cK9kH*{2=i4|WnUNn9t0=0dKqxVA zfqT{HPBSjrZY^crw`viemo@y?>W#vc1<~~vg(zG(`><*W_ea&}{)$2rt{4%Y-L_2F zRC(Q8u8xVvzf9HRq#4?oCHXXuOUiWJsX0e!zPks@&;44+!y|&zhECEFgM;gzU{&`@ z;i=S=JJWwhikpK?#eM-BY>{C&T4V$c^0L#Fm6I92Z|J98FU(AcR6mInwB_DEC!Ofs z_tc&O51DI)HuHqrTy?{WO9TyYtWHS^B|)6i_>kz4W}VPtO4~063<~Q5oZ$eV1y0c^ z(L8?FK705ywBGf?0>`#hwQfg(oRKC>6azSCR<<%`;Dj9Qjtwul;%fF!OpH*FTl96e zL3rcQk@vmxtVLKiR-o~)ZnqfPNM#k)&2HN$oOCwuv~wb}fL}~Ti{}mfr%t)9OrOi0 zmhJZXB)8Ao-;2_a^FRag;`Ix!TDEf8b16P9%zST%<0b)ZJ zAqP39;`evk(L2GdAWgjfnUedK)Z3`)n;(|_{$G0?#5 zF`7FuVenE{p$o_EjkTcEx+yz_i$7Of@nQpn_=%xw0C1*fNIBX7ZIsLF^Gv|+mQIXI zF-=3O+%2?!z1`ahLy_)!ce3uf%yFzPNtD9!{4p?-8(6)Dtr4M5cyPmy%1HN{R8L9k zFDb2cB0|d-yX`|^@7xyUP7fnrhH{KZ2^{1gWCUIe3E%zL>Og_nF{EYnkuY&Szo+e@ zu(8N_odLS6@Y4TNptxGYaeJin!5-nY4`Q-AKY3FqeSmEyQE;Y7Ilf$v)-^MGoKtmq zG{u*eneEoRIL)w%Sl!2h_p{A6x4%#$v^tOCFU#qHG^a4Sz%qgoVq!}+5BgmA1D-lo z{cM=XPJpFEMie*zD3J@9l|T4E+J#ufej#o8v<>%6MP5Mqn-JX`FFHMWwtu(!FL+=3 zZRzZ-J=}2!39m5<{}pqa*{x@!$nOgwXQI9qewh%uG<>R4Xrfd-QrIRY{}j;e76l&? z;E-QzA0N1pybxS&Uv}V^M^jJ)E0q#iSrBwV*74b*h?N}?#`T`_>A|%87?}<;zFHG> zUIUUK$}0OSz0lR@;mJv8pkfzY*~is8m)LeD`7*UDxtR5#=g(NY7pa0&(j&nsDzB*h zEm)&Rg}vQwXz|yEr!XbaHjF#54n9})< zY%~9z@Z_VjKY636MOYA-)p?0mI355TrSv9F*9oEduQ_gMQ+QoKf#X@4;xvh(Rs7KG z8u8NjQP^GM=vHwv`LLlmjslEGGf)uO&`8No8$9(Zgen}iUxYVLyf^-n-w|^?!{o5> z$Cgq2QXNmO;-_gdT;7hEF3GET&-D0p+Gih5iA6*t?iCm1Gcb=<8P}ICvHpv&?wRpB z=C=;31IX(Nr7DcVF%pC807gpI70k`ALci0AJD7t=WLw|FMxSGx+V~vFtq#iejPd43 ziq>E98<)E0Ju%WY!2Jb>3rI*0xhe*EngN9{Q^O_+9rYxgi3rSXa?2owczUOly&c^bM| zE(&K85?&iIy+Y__QM2;I&2qLn0gr$-$q_yct;Z%N=|f)`oPp5n$ruxU5mJDsc})Tu zublgWdST*JEoK5XWIHjA7o|u=xwxK5Yhlyygd;qEx*X?UvHVBqxiMzQ**yxP_zk#_=KGu+j?7>^<&RFyI zCllt`hLKYEygqIWSe#MNXo5%2Hb#n6Z8u}>z7AbAV4gQ|51pK$m;YAh;C5!m1?S&4 z#A3*EBzhi0oA=Lcyf?_$2*^Vt^4M4>#&%hu05#afQPUo{>CaV&qB&|aJ-c+5TXnLc zt}!gDLP>y=AN6frePC|LrI(Fxrp89tqM}kLu_b(;EXQ+*O?%8ZF{nu-Bcq8DtI~qZ z%9>&|GMN>E+wl2!;THpXAOFq@dN#9_=za3Y#EU?ouhSh zOPLeAF0WJ1bt^tswmV((`7$-{EB8Fs_~PzL<*b6+mMisjpD0e8|MZPh|EU`)tSjI= zR83bYS?6h9lJfKzs(#yu^;3`t-@lL&oZ>+Gzn~rE#Zxg4Y<$z~YPg^svP!G8pvh2@ zDP(3Kjn|7Q;q#>hqV+U?uU5b#Jy9`f;65Ifh>!g6D%YtCZ}lESC=tFOh(y_+(cSYj^E(&ktV{8Ae{< zbV{HoAVMBz7&jGp-&YZre>bOdW^6d(9ta{Y%aWu^I*$|g54_yhG!3n(y4b4mwzT7R zbbd55U&G$)EX}FViVh&lXsoPk@%5a0w)xJKdL`u96HEAgq~(`&xnyx+ZSgQ)g7 zn0Ms2y{Wi-U)={=--99^OfIyGH7Ctee#E3?ba-RR+mChsCo!4OU?1dLL=_W4*glQ2F26BTH>I^E{c9Ya#x1 zlYTI1E|Q9$GncqCGN(aJ6(B3r>s`H>-zxcfjD@sWjERjP617>dsHnXzY*NrBu8z&w z3)o`A=k)PnlZ-csmHRx>X9=9h7(Pe@te#AQ~TEa*#X@z)2J z&F%iY32j%fE)~cC1xhN#3DS&ZYfqdhq%+;mz@4hG1z#|_W*Bnk=RSn~QwIBSw>5j^ww07Z|c^qwZQhd5~IO^IKf zts5$BDQJhtP?Rc)ln51QN<#cqu}(y(4SPRQvB8vN^j~lB=L(O!J+~qvZx@(|4Oo_P zx^pu#UEYi?<8wT>x?R40`XJ`U6B`>GrZdE&GaZPe`Ab z?x`8Nr1SV-+`tH5(Yr-b$^FGe`u&HuWH$>fIh>Q@0H@k1dpurKHKNYoK(SV4kG@-{ zBLz>BNF9ZJjzEDC0nMwr&dVzoW^86ZOwPa6>4h;C-CvE2Y`%2l&8=eZvE9y9|B8qx zbcR;_dIgdSX&h0+6uG+LqHX0Te|Bh@AF(vXjEaT=0|5<0N~4qwO_;1X+66n>BrA=y zy&)x7NvP9njPauX1>QTz*n{#2KD6M@f47-`x3Xz)T2!c>P&!jt$q{^P*=hx*1)rOq z(}VLTrv>Nd;h}vnT(K6*ug3CtXq^#Q9*=0+8_V~?^4M_OYGe5eSpUvr`7>Dl6qetG z<#%HF4Y+_B%Rh?cAI9=`8R;)S9UOJx!&c34N$WEavhWBV#9o+$l>NyM8-Lb=yGSemL<7;E~URG zd$gwbaPDYKovwNH?RcSC&;(D9wL&GM#VRe{+2gxFj;;(iS`c{AAIg_wVMt_R=cYi7 zA0&{f$P%|~>glXe8R;LIX+SZwbDYQJ(>l4_-8D(oJcIAueI`>q5{HJrQpd`sDT4N! zf>Zo?D-1!A@}%c@xveg9Y#WCyM?AjpV|mp(wL{OGLWh9LQ#{WJib6xJ%4g>sQlW$A zg_z*fs?Hp7!*4b2Xy2)+i7Y$Vbs6JKLwbOkn&!8+)4aH3+ZAV?hAyBx#C6`gX0+%| zwr~Id(iA5^QJ@7z3{h|V%2=C_xDCAGuGyb|zwsxs8kxcgjK~05(!`Qd`gWU7d@`<@ z_xWR{m=YMTHu{CjrV2O$k?EYfl*ai1B$7^`dfE}Pw{%kiz4{u>@BUr>X0d#s!OuQ zFtQfnOEAtn4ej3qaodI_EB`n|J}?BxGa_JEIxjjqgKx&AXTnSDCWz(QCY{cBE`qyQ z3d)Se3mnTclGR=8)P(T)(gIRFC9VJ4QsO$ljaXKHmpFIF{kwV`Z5B$O;HFr>+12Hi zG6T`YoGx!(?r6g&R{6!LXem8rn8-YUrPf>cZt0}8l{^m|QkXS&>4$8nO&=MP?V!*yFXCEast(shL4 zPa@M`(#vqzgSbO zR{7w=Vf+eZajcMcU)5#2rsVou?os`-y)M6QT?;T^w%=(;0>&vLfo`%%m61)@G;xpn z@5ztd*Czd3JA4Aha64Q46CrXyu?kEC_f>NKVEI}_Vn-;butYZQDJ~2Q2@87 zyD4Jk`bn|wXJ?o0XcG2P2{4o_XgcI+sN&t2N+|kCG3MtsSwngexe+KxlB#f`OiK*T zjqI5l7sQopkGER1%SBuJIjhx=5mo#u;c~+@oXK28SAVjFOAT^M_OEhs=D}Fhq z+h^@Xv>4wq<=_G2CCKSep(MSOX-WXRz_J{KJR7pCkmR!$v5JkN(tcq2=3(f>`-MQFWP7?uN`_O@bxB}ZUXvkH zx8bf=PEY`FQ!dMq~E<#%oF#O2pLp|?Ip3zk#nDB{(vL}uaYGNP|zh! zqbOaZm|ZvQSKq0)FOkM7Uf(8s!>s-)7i1qLz=|kMujM_by)IeSI-P1Z%gwC7!9h?&ZfH zsu{YpJfjrdqxtVHR8`PKpwkj9;T8g2u@pCWz+IYHX?exu|F=z?`ANGDqh1JaKga2s z=)W$LIMGx)?nlFCz>fsq0qFTNFObmEdm=yh?6YwX)(#^QW}Pl?n&dUuDBNJ9M-@j< z8d}Hu;;o-2crVrut1K;1x(tCRD-ti`>HuHv2n^);Wr6fDL&a^|P+L$wwCbIra#!PZ z&pE^M*tDiekO7=1E85A=`aDzkCaLZpfpoPIEc`~|weD`Q`M=8>?|jFE$IjDo6NA*; zGNcf|R0uehayr zOwFea$nyZ#+vRt6oB6l2ZFjSi*)hl(=gS!L)Mhi!7ngr>*ba)D%J=d?^SDCpabN=+kpO;62U8R^jDbiqQUP946T8SM?S*X1{sd!fu zm)Xq!ssVhy&>B4`Hh%ikenS`}F1wjzL+SB3p`>yYD+;_f7F29h=M=|#OL2vfn8cvCU6-8O4pbB)L<4O!8W6jghnhuLgMkfC8_nQ>?Vgb1{ zqnth5K9)((%=UTxhfrRwOQx2kxqaT{+h5rIL9O0)9KYOdP}*%0iaG{giT2j@pZ}{_ zxljsh^f)I&gAd~>!EbARm5g5a+8&%*0sh|CL=Nnz_}#*R-|JNxlTR4~XY;gk!1!*O zUzgjf`O>5u@AvN|9`$zjB;zKZkt#iu!_vqH@Eei(r*fL-al|(suo1R!mgW=`QKnf| z6eLcaG`js1{)@p$c+|;iSZX8WOA1v>_&%9=|5hAwz^C55KP>akDXah$jbb#we+8>A3ugRcx^o+{Q+fM^DN!7RCw=ie_Nk^n^ zyJCv@e+=ROmvCVCWP}#8T)!vTq7a4435q4nC@6H7tLKf5*MO zB8hJjmVKubMv+-gqG(ahdlvAWj^CCKjE$7BJ1hQmKJG%}h4n*Em_p8BIj7gp!{s?5 zALx-3O+EQS$M?^bKazjY+*QPNa8{gKcjSDjCmK@oa9E5gC_rN*pfl8W;}0%Ae#)DK z=n!N_I@-uvDR0y#QcLGW{cw|&uRIoB^Fh}YC^4)ki7+IxO|!G4vM-A7{I#u4i+16c zjt)3oQ=m#~5{rlJZfLoqY+%l*KkPJbp}9e86e9ylq-5wGsBL8i34BhVlv$9|O}w^*>F z*184NkA)Y)X%LF6!mB!`gv49O*ATI+D-Qf|Zq0!2IyN9*CKQB~NiRH=>X5WTAuUYKjhzHZ(dg)%ZRaos`k%f{hv7##JvZ?m3RT_%b62SM##|EF? zgq&>dO*C7zFyQ*7n{cT7#>7+G{yE&WsC805Z;eeSFyC`v8cjQ`xUnS zVz09HN1<$hBuz{JFZ@Em)AdBYJY`G+Lwh}Er6 zcu&C6N`(I_5z^A4)*ZG)U`smEw`RQvRW@mkQ&>*WBnEOMmCe$&OmdX*ZjMxUDG{7~ zX!sWup7@`UHwz-;7YqA>gu-c(TXp$OJVsZVJ@en)mC7M`^l(0ywWxxnv8B8z3Rse4 z(19B{@X@}AC85ldj>h{dF?;Zt z!nnNupEg$P2kri}7fy@1qf)?-4rATtID|uULJ>odvnXEFfuQIb52;T5>7OT_d^Kdz zA&RhFsc-%YU|XXLUsY;LG~uB%g^~qYqf}PFeMKOLKm8&;U#wwR z*q*a{5T-LGx~|cr-;HB`1h#K(#ai$q))SokuVKMXlk^K4;MgZ7`~f-;dytM5{I8LI zXiPhYiI-m{wC@ms97nc>`><7x)&de|BMtUeMoQ9rpJO48DlHox+J@f4sBVOHvt*5d;~q ziZqW+{PNpEmsz)!E1eOo1y<~^Z+rZu@b?cq6j)sag3c*Qn@`*6^-RM2u1yF|Lr1m_ zsG8E@iP5dYd$E!<3D5$|s{+G3_T_++KmL8cJ>RsXQqg)BW2*~h9%=v3Bd>;^O;u1O zUIvOtt2#cL_mvM{M_rJ*eQBdD|Dcj5#}nvQo&nB|9*;D^&?xg?b!lFI6iuI>_4y;# z*$!l{OvdA7-tbo-t@Bs#^B*vqwprMB9Tpn+3{#x_sAF(G)#&Ko7Ap$>|BrqDEiuUf z0v_HGTW}V|<$05=6%?DT*XZE)c`UyUD-U;zh{u!5#qusJk9+GLisf%1@Er)S<&nQj zN%^)|K9wMyLBLw%TVi>fUBY#4@yHVB6ib-)eTxNm4_}PahdZ!&d@m;a_~QGKwrC&D z_uXL8UOZo$z}(mf^e&#qeX~@u$XB$;<7yJP&3bu@JR)NkjCtqhRWGcTaOUj^9b5lc zej@h%7>o7X1Iu^E@>s-7Tbf0_gT?yhE!GDfDh;Q9>shRaT18wB*IDGz{5;6N2frV) z_nCroEV=cfzKcEyr;#nHjG)rA#>haxHL{sm=4mJ$&;)$#WILrz3~S%T=mOvFCv zHns1X7#p18K>EL+9ZkW^H#5IIHXZFa6Yq0bGz|)=GIg2wNta5GwM}VC;N5Ctyvc3? zFJeWv;NKxv!uVQjWDouyhsUwBJ+`OITHoKAo^KA?jT`mYxPi!i-6TkiK|KkKvv>A5 z&7*mo?rfjdO>=7=my+jjw1?a4liZ5d+3z`5jjxbhZQbWF<&h`1k(tKEGSW##oCd}4 z-82Mar27-%I7IrK^d5rECFHo5+&~)47J%tptcX&oXf3dkMpMI%H9cHpO)3z;v+mKYFnHuwFxN+zmT}v3Ps$%WwpO!uh4mojV|pdTtiU6WbmNTmpmBu zJ;EF)Oe^NW zFsW>`x2rum&yfJSEiLPD+ir{Q=aRr9(IL2|*4M(TWL(P{KU^yObGhf$DzI~D2Y#*< z;d|62=G`16e4j05y|wKn`~Py$GiY5Lz|uEkgU|mym=+|ibu-Ht$o7POqUWUbi@wjY zX!k6_1iv2_e!r0F-DR|^e1!iaZJgrXc_Zx-p78$&i}qNRTUzBMms0&@^<7bU=CZ;c zQ79gOLP5*(P)ky$9+8QhKX`}FQMw*Rb zQWz7Q;y`-7jDP{xmJ)$>sbCpK5ERx=iVfP>0O$iA`{JRIXo;JuZ$g!36qQqCNzt6D z=Jk29C)6IdZ4vYQniy1EBP_KM@?=#h2=3igp|kCUuzVdVyg)%5#lmlWRsP4~M({i{yw6SkBQ6_A2CPLXvdte}R* zk6QM~zO(us!EF{O&I*ui(jj9oIv5Sxfz^vpdk3uHND;bbta<$lVuJs_TrdMeZ?U*R z0XD9WW8X6tN99zkJd$4=yR8jqy6w=Gq~i_A2s98kC)21VR%%$N$IkUsgBgv!)d>GB;ih88vkP?{8Y$eds*2 ziqDxSm$M=l&}-|Fm6Pr9_0fFN0L`17Iac#)xAkl$ZK>Jh20I?wYt@&5qK3x=(h811 zdTW$QzN(>sWJ?2`T5TTnXaYJ2O^h-NyGWp9N)#xO<3yT1c!zCf-9pxx$n8p9i%QeL zvIc^C{w|X!Dt=G6EC>qFGD`E|W|CtKH1|&qc6ryl>@M;uqN8!K0YIFk& zZ&S}d_yzJ>P?Hn|ElYFil*~dJa2l=in|n@dy=T$f1SH4Su`Q#Qa0}^Wv<1^j={r(f z)ox&Pi~0?ARz+<8j+9U)ho?Y*$q58I$cuT{!|n2Ud$`@2r&sEdZ{jz68@n;e<3u3} zQTUJ3c>h&2n0SS@EB+GK*SCnzOM2tbJG%9v5QQj2Aqo+k59BN0o}lhfu;}_aNU?zs zVLVI9aZ)lPF@i|TipqYq{=$&PUHMqtQJk1?c{+^Oi}IxBRxq`g`WyInXfdE!}@y#9!!+PLjfhMz(uE_$FOg->b z#Znwd{}&AAZD3`ejVX`SM7oKqOk-<6ozWCp6d6&H=A0b;-mu4hs6b!hO;Fs>hD9y^ zTH#vkwn3oci09v@JCrN5I*qwivz#fk1Q>vCSTNz)*<&jPqhb;$mQrDcK7Nc`IBPnD! zvKWeWYFRE{?`*~IqRb;r@ar!p&3>iXnA2HF-HIsNc;^zyLLM*Ta}t!)SmmP?z6yicqoWkCB!qx7_14l-%Gmh9fWdjEMhsA+qNcpQyYci z>~9<&BE0z^;e18-u6Y<5wJ=V|0d&VHV$HJ*nQsbpu5M^1_}yLy^b`EH2>XWAT3uMJ z-1S4G{L~%b#39>jQ@0=-v?{a>Su`y=b&sa?cDXh0;_(eTf6%&BIV7!k3Zt&h#b4gZ zE9hD-NOiQYGUOv<8(Kd$q-!p>FFT(VVDeaj&YIh+<+B2Bp6;@)QzgRp zGD~SxHpfO$WJv&ziqhG*#^j7ti3yhBt;fcFsj=_hG6ov=%ki~6G8rR!4&#F74YvnZ zVj`1CTJ`h43TXWBc@4!fcY!Z9dRELlMUw?m27&?3fnG6P^Lky`?*5+a(VF7(8%le9 zo?OM3?WworLS3m)c+#Kk!KpREyBiFxb=^%lr^1@sQi3LHYF^wH+0@)N!6L=$jj>Gv zf39EmcFP8cE+j^5U?|#oo6F7|5>+}WE6%QZkL)F?IhbnpO`r!14Jvblf zDKH7NsMS7^J>DQx-iDgy(G=%6m+H%Kax&m}hN5|z2e|kx)$nkzfF)J5^mb}Qv#*Ge zXla&#A}vZ3#d3Hg+IA6Q;esK*2dvAz&e`S(ba&OCe0Rn0luT<9lm%T`IQqwauT*~` zwlRq_sbLSBFD)R|Q_}ihuULih8c(XjNSuM-+1)l zi#Ih0EvV3qkId4n%0db<`9}MA1xbV@wET)`*JzEy#Ig)$=RCWALuyx8deQ~3jBzVNlNnrDJjVL4G_ zAk;L4TF~vY>&`acnSyrAsIlf1o%4ln2>OoneMzBy+@&d(#FRK}_kn*KRG|M%HnBAg z1h}C&UI2g-MFubc@F785A24Dk_b6{ZhxdVD%c?zc(^NEv-NPYepzFNONq)07zVOH=6E)Ha_`AC3*BQTMYsU%wi#gKsvRTO zaY#=g$7~pAAoIK^$vneQ1$qkYC*1Xh@8{ZfQcU?scZJ;+*^Jq34}k6JGxHX1s1=T| zD|c1~ue$16Pa zz(dK?uTpksWt=Sv*8m(X;XEFXGhY|CV*gv!bJXI!C2`^N2!1wF6co7;0maQTzDI|4 zS7Ymbh}ccze-yxTtdX~J3wODIto86P_{jB#Yv6T6K2+fWU__P`1x~>E&`3qM2q!)a zD$%PBRn^e2zh!!s^AKoIkXR@dQnpjd{qkhHoiEtY$>7BVlql~l=H(ITyYAS?;nWU` zF=#ZFubBVsBY=*nvgY?@$TahS&6I=;m}bflYN8?nRTCzSZa; zHC<3-nUWQVv&XSSf@2PtI_%c5hezcH-HbCUTai>*rWrs9483~CjR%|DbyM<6tjve7 z5gUeN{>Iw*a6};OV{qb#OA-wc(=*1f4qF{aA2C|8#*nKqMrS6p3m&fgQN-?R+Zfvu zMHjx+(D7<+NC28`3GDm2?*{V71*78{?^n4R!3&)IUmzW5putAQi%pV)zgv!tOEsh1 zAsFRo6qoNS6rEuk9Kma`-RM9%AKfh&=~S$qtF67bD&ZP~;T>XB)ck=!17^M$$bWAz z;iw;YG;Y+NdDSjW`8$n#6Jy=w%riLQhLQarW3=b?iT0p*>9RYpVH)nT1*Pat@Sa^U zK`AiiX@IfbZ!`2vdK>(y)&B_Q#00l1|Hw1a&ut}pzo>xbCsaDK5X@XVdgiq02)`dq zHp9h`Q*;_ovd-(k>6Sd6>~WepKyr`L-pf6?c>QiFWlkAgYgWBP8ZApKG$r4$EB$C;PCiW8bY(Q ztdHVtQ80sP7@dHG65~s`o}^3UxD3^UFI zm9n0q5Ct;;g+yq1N1ELp7GI$JLeR-or|N?Xklb}?Xncdh4ya|CRs{;^lE`bHZ34?z ze|jqaKCQ?k7~%QVzT(Sa*Wo>`u=Z6h;`_zLu+(MhUx6TY5xCQHbJYWTklMD1Ts@2C zoE|MFb3&I)ElYFz@*Xk_rEroaNrIsF{^a5Rt(<&35os%}G*tHEh6j(!h<(B9cIAVm z)0@GVat(6BeyHYGPY6?2-uk5R--5ws_ROJ%y^JL0;ATfT?asUJKw;yWtxl}_{m^5b zD&>#PVsNo(GPS!E64Fh!nTbYtQGq(70ZRk!hm4jf&eJoJ(Fo7k6A;!FNUL@A4Cwt$yQi}zA_cHQftHL$s1w{y#jo_{%<*LBXdd4LC(oSd z*W>BMCxuv&w$3qo=`4JQZ8=!Jas4hmop^o1aJl2Ys#d6^8u;j+6 z3&QFL%Q6jVO%QZS)lKz-6D`uvkzWaJn=z~HA_lG5k)~HGlFmxJ!mz9Y`QNLZ|I^;` zK>1bwQNo}KW>oV)RR1D657!{v(XeR$#~%-*AE%hl&*IAFc{{-cz1W}@ifos`k$FY7v4Bxb{q=L_^2a1#Tj+d zer*6b(%?F9{ii88KXgDED&1oW=n0?4A6d}DD+0@EqArWH!m~3@eYI(O1w^=wPfjpR z^DB-CCZcO%V$g)ggGsMnvFkqfox%Bi6N2*tFuVKySpI()Mbi@#pSHyE4YB-u?64S* z<%eVWjTk+C6PEu6lX{=W^5?Mpk63;_mY;&wZMc@RUmKaW>*rs3K_v&xgfeNVoKgNbn z^TjHTV0meBa`2ksFkT$b(-wIW3u`ku{><_*7I`ZYDcb(a(|)_{b@0+1UEaU*MPy!_ zVEX`F^$qk$${4>;&@JV7GqQd0`-V;}YQQ@B2Uv|NG~T^RT17#8S*Oc8FvF8Q&hN-2PmqnD(_gK31f`+% zd<0s)bWizt-&@$MsS?j=y1)TO#)s|ch}Yle;LP^4_P?u<1S1j@N)=fS%8bO~!HDo3 zP|~}jveG^)t+0}0Q`;{;Rxv2rhMj(p0&vvTz5Me zR@6jF<9UW-@Q}O>E$cWAhL8MFo;A%vV6TgeE(?+dpsBzf=?9b2(0WgRufBTp&O^y) zqc;n)(M3w3ILNEALTOukJ?9p-v6qXvf#ec?A8GkzT`p-E|f00_PF#gW@&>qo}jj^2puL+MFea%ij_C$_n{eDV-C_<4D@MG`B19nqR z7*%lwEQ~2P;lc^DvX3U29!3gBQzECy3{ah(KtT0QIS-BPnKC8ewyRu^;I^o|@S2#1 zw=fQ)Qgld51Wltu5QXTzi(ZOF!4y&wgU_u`jkG?N+OYoxEXDC{(=u*vNud&fjdfh% z`w6wXLKup_Fp+!)beiS)VEAanE%py)ziB#{{~o3J4%`@@Gwr-s5nXDb%c@C6YWUc) zjfj|O{vE8Ec*pwmT{Vg1KSQ%DEpQYAAuEQcm(_bc(6c`rq#FJJzke}l=9{A|cwz}K zDhp&)mHm-Z`psP3KMoaXmvBl!Y6 zRZ451j)mN*VNA)&Dd_WA@c!pL?`bhSyx#*_qZCTyb-;!O?|F{M>z@brJ-74X$vene zhk^)bhNB?|D4rHXd|Aw?VAcG8!K$Zk$i2NHQqC#lAGC1L8;)bQq`g!9)l)1fWXG0uMM!!jg=vV3;rS+A3uCdyHT({4a zrKM|`n&R*L?vu59f0fle5!KKtB{)TZME%FgNL*0RrwZ`5H)8G=IkawOn4>gK6h&H< z0H;vLj}QK{b*=4jDaEWiwusNkZLbQuzMsDN(d!!($eqFonJ9@81dY)}hUadKefr70 zU)@)+j`5|K{omk#3kI(mJiO|k5id1Iu5w3)4qg_^z`*uR^JIIyd3x%7y#qA;wfnbb zU7sEsgZ9>A#@sD2FnyMRJKGy&zR{*tUdm&w8Emn?c?R(XC#he z{SK<2BI)?$OzU-lqUbJxCu7&!gYuzsa|3Md>$B_Vj7Y8tp~9(9W_5~_bo`pIBG#pn z>JL>cqoJ-?O5c%h3+lo5U)uHaY)GWs8A#Kt07QzWDVk?+60J#Ga2h&i4dL{u-yUlH zGCJmVu%^eHE{l*88A|72(m2P*XFod~pBptQkHUW#(xOA~pMclxm-qjFOZfjqi~sFc z*z+hv;Zg#kW|5%f7$zUNTA*FD-b(`TGS%BET5m+q{t_Q7*Lr=OE^&PWqxD4ucNsFp z#zuKcgVHJYN~6nKT_y8sbusRamiM11ue9jN(r*8?N+(<`c)zsZIt>3KC@uUSg(zIj zc<55?zbi(5QA|8`cXVn0r=YZrB_q9+z0x(GBUP`#9jAVg7#Sb6xR?W9h438d<1i5p zEEWvJ#zeP5iJ&%?N7@b&_S|DpPWfwWT*`W%;{o7TTw^8`I9-8j*P?qo623}{@HvY9 zblx6}ry@LgaPRpb8Ykw z@&Egc^bz~jDR;S2+t;;-?;}3mDpp%(Y@WW0ZrmtDAqtlm3T%HG!H=rz<33QsnutLP zuskP-8c;;sL~N810lbZ&+t9L3a2~HR*2cj2Zi6R%dwY0;cBo4nkTqH5bq=>eo|9l+ zHUo1n+&T1_Ey#{<2HE8^FL0X5GEfjjy-tly5C7G7PsJOJ&q`|46ko#sN$N4@hiknZz=X?CMN+SjQeNtpC1abKT$HPtT8;5r3ihK+#4IQp51^{P{ z$Cc&s8{Bsp?{}x`P4nBPc7Ax-zLAUSCRVU$o*PR`8%S=&d3a>S;iGrA2=A#t(?uY% zx(sPK1V=nYLU{tTW$43p-c=`bnfcwZ2yBoy79~3?%N63Aw+5Dm)*`|ulV*MR%JpG8 zATSaO6qy%gz~dcw29Sz|Fg0d;@~L6r5h##27Ra)yvJ8!vT`QJUb~`w3?FwOS)f%CL z6R!nTb_E2%3#bYBr z+&aRF7mjY2zl3NyE7FYL#WTw>tiZDz-kW)bJoi1qa5-$9VCKaaS32+dpYdccVGnv; zqui1&*Q529JW`hC(>wzw;QUBJ%jw>1yfmrW<_w@%5ud??kt%M{TCZ zc%BV8qYD(z>Kp|azIB~1H!K@}dvf(FM4DIJ??^b&Ve0`Cf4{rWAKlUBF|n@q?|jjJ zK+3Wv$=o}Gzp3P$)w*ImLfyCq2d;7OG@(=I+>i+6y<|84Ud4_*pOK;-y@RF6Si6!5 z?JVjJ=>h+Ib>!ZTkA&SJtisSd4SAX6Luk;CiH@*(!nZEuHc5QBDH+3=_@{QcRhN5I z4>ykO<_szyA-3xUKiGHUnKzc1xW(`q#7(PQ4Jc4hWPuU^yeawFsUy#C&UcHEfUUVm zsVcjzH(WoqBD?h&YF6c&h(ReBBmb?D!H_f)(ID|==UHCbm~ zX3f{k+C_Vh^gjN)R}sU`#8|wKmq+$HF#xvy=cVs9ENVrj#zU8}lAY=I=F~SQt4CH& zw#VniDfE-}@N3CoONSqQH)Pcp0GdE$zrWWHUB>xGs+8j#qfPKSWyq=w6eONy<)&Se zXU!gZAqK7HR%-)Qy}l&4O0VIY>2HERjC6S4GyC?x_$G?^S|}RG=y6VlVehXK^ZMkr z=j=%sN-C<0l4Of~!S=chuAH&0_352xZM#mO+k(B%<|`1A_@x1ybap5DX5Uth64%=n(1zuTfAl)&>3qKq0?~e=5b@fF8TI@OEtp;J- z7k*~%$u{c82)HLKj(W7pMjN|q<)pwHOP)8{(7y}Y_5Z1QyXHL+T*q@VxC_ULkdrABjm|V83rppE%y6&7orEpS2STy1<{%5Kk(B0 z@xnVxKB=?jRXna7U$&=t?{+u$zkP`9)Fqz$=tWW#q7a2BL?H@S9z@UQC`2I&QHVkm ziVx(wvEguKgCjK#-x>BshnHxX2eM4-w2I&8lqU!chQrtNgSVY+iDZ;FhZLL_!GdR* z1J8q-Y8DEAB6XmQg0`8(NC32?ilQp2 zfaT7%YP#=(TD|Q^Kwi0sji?-9BOSJJ@TX5|yvXhgA0}9)fCzOCPyo>Q6=Jmr>lz0? zI&^or&u2FZT@9wg0f8(qEY0f_hhOqPEW`$-p<_Q0N}u(*aH0b;MV}oiYz@6$QZ*%0 z@@NAzuWw*(PG&%x;zX0&oG;$U^ZbG5Ss6^TpsZrJ|s zsom1Mg$XOf0G<|j4sbLpaukkMe7ghbVuIq$-Ei`YW5(3iDu?2FWrE_Aa&k1c>Qto6 zOdQEqQl{C>7vz0#%ZBr7wDm;PD`|pGb3Cu>JouyGfCv3o=cs)sR#D`*=YIJ3=z&k( zk{C9;Gt1GOr0X)!WX&|Zb6txxwB8x8%cj3KH$EBmUWFBOs46lLc_!pu<1Vrq#^7 zPZ3ug$5I@_2!N+3mgne@!)*BKz|t5_P%oYZe|~%F!ft;cF9ah^`yn{Td0alt+dEs4 zGPl>G?rXX^u^cJ_UAN(BanCS^Z8j9fuGxFEIXSK~fY2X&ouhe%71@wp|74W4m{7%R zxTAc|FliISdK8v$*@oKi)o`AJ7h8=mc0ix?>gs1B$krkoFaum?S zDHn&l`AyBQl2JS}WLglZmb;aM8-y9!TH?8daQ_zOlnHQ8@ zH|$s6skkqZ#tNQi;c8>vC33|PX+7vY()(8B?6^WgxZ&*}>7Olx4bnC&uCRwljfsAC zhgM`pkQAI6TV#;#Z6e+xPr~nFPR^LVmQ1mVtiUlWCGs4k1rQPlv%j$;mJk>45_s^n zRb6_FH0hB)C}OKzUI7BjYZ5C1VN}NayXGWil|wyRV2~up@(EQtn?R~8fxY)ouf4lB zJk!WPC;?8TC7u^?rZFbsv0Dn$>VH3fgNB0Ttx60%ym^ifs7!SA4)Rk+=@Z;anv|J& z{#^4$KO8TYQV}B&Vr@~d6~RC{wuJv*Y5jFv=J71;?;R2L^J+8LFK+%)J&$xfIm&2V zUSt00q7a2^8p!4lPs7@DwNGk{B43s83=lcU(kufgnrCqeG1-!kS_ZqupIYDM{_x?Z zWkFLlmSO!7*{#A&x4`nak<34Y_iu<$HeEp7u7W={e5&Hjtr2zGAE$1CB5OdSG*#xg zhwrbD@K^aG35c7-CGNQ4QKCilt6<;UC%B)p(ZCHh9XOp;I8~<%1bo6p}@*zmG4 z;f|yN_8h&3zh5wkYhmKH_M88;GG5eOZq><25~s)_Ppb+&`BC52)d%JhHRN&2goYMV z)0yy{6*Mg2`()MX=V9yVUpKN%L1T5YU}RK%jFWnF_`NH-UYMDHIFC1;3O4S*^RHqx zA(_P2ThDBBUxefL@`I*str^OldHgaMm)q$PbRY;klmN>L$Nn97Z(+ge z@;LJ}bTzJrUo~m-(&{IOY_!1Zv><6Ls{x3!(bBP^N}67R8z=QY-)KO1wo?&VS)vsl zNGgl7oyif`^(uVu&1%j5>=4OD6Iq6)DOurZ5m;?BJVr|$ixxE_d}jqEH5VgqwAbLX z4gc=yByzzNl3(bAR)9- z9H5sj)OCFADY-9v8+Y~!<(VUeMp5!JIuDl-@*S_(qw6U;Zr46E zvG{)(W^27HI=`0$5JB)Z9RA$gzdCe`kVX*z!>WSJ@VYADG)hL(;FJW98*}YRAkk#+ z!3RE{|6=^@^+UxVg(!SUm2!MemXUx2B@RGMz!e0UiAh0eXiYoe)_EVLHTj`_nC`RC z>CVaOlb0eOxlnpkRh$ef;`C=4 zv8cW9m)j>#8TiRfCM3F{gk|Ux3C?saOLF^MN;>i(g{+_P>Q+8Ts_qj=?VR=LiSi}} z)@Up}n&KSiQhgatT@y7~Ruzrc`Cl4H_troEL}Gji4~>GRdRtRZ}71+awgli9Wdu=CzG{yudx8kuJ18V-4GuOtaThUavJSCuWk zo^#JO-Ogt?d3S75@yqkJ*tTiyFek+h!8vVUlf|3Da=cImGNUV;CP^V)4}1Mlg|P3AzzggP zUGIhYDt4xbo0B(^V%M`gl$@ zXQ#pE5LVq0sz&H?`?3*gr8%cIUQ&EL+^ROdx67@0or+9(dk*h=v0kGJh)-{0D_a=s zDCmy=%!<#0g8y;Jbc%&s2z`3I(#gJGe4M;2oo0OTWb#{4kB%hMu%#kK!W=m>!Ei*^+ys~iV$i*K|tJo4lEGVr?NQ>$Y zw<_Uzl109_%x_XDl~-0!7}*sj%D;w9Q`k>`oE3quB7voWu5lbA@+!$!(W{r3x5Mj0 zdD3$dl$Kj!cf?fMF<7hiSJUsFjEoufnz1D;j~qItXXknpZT5E+I~{8MML9&g+BXI$ zgt03EDgAw5J&rW;Z^Z?t|DF&0f9DT@bexg;-p9_8oU)zA0&?O6?D_k&?4f+iLKKiG zc3~LWIY84jkLFgiJl#L9)0>->C3z-H+0-$1ZTZAlbbEDVf;}jWyfr7`+3&yk;lb*N zZZfmX-~i*yb&vD-jf2#ijz4>s-_{VnS*~u8M%ttp+xPInb%WzBJVVwO05r!^BE@kW zq<9dbFR-ve_$t1KdwcZgd3{cJZ|S_kQb14u#Q+WG!Ta85Rl};U>&lPJjnE!YrUgcn zAf+f=h&`aoh+O&4bUR@Re}q4upThoH&ZIkjuiSq7pu%psGbArQU>A+TI6G;XoPnDf zO}}BY*dRRbsg2b<6P!R6L_rr+S!DV0Qx0a=nX%7qwG4KakL>x*^2IABQb6D1<&e?Z z@9^M@I3ph2spnxahl;(DbH%}t=>nP{aEj=e34Ym2vZv&Z^dqwx5zv4zdZ*({JzrtDNS9Wn~aVkpM1W8~BNXS>`!&4bVC z;)+(s$3M`wZsN=D<_Dgb5od-AG* z*m%pB!h~K1@;A7GUybiNBnR`m{RWxWmuhix{$doc)EJz0h7wM#u*3nT% zWdFB3W8TmoD+Z?wwx1AW$iXQIjv4hmWz_G9Dcb*rk8GlrAnw6ksV@mC$`p_rFgbTy`NL26r!0+h$I-An<$RFMPb>8;@vs_-y+b_rG%65Bqb*=k)`fsO` zn_gn!RD$i=f&z-rk-FgFAE%B!iAMBh6Rbi*%Bf|!e0_7XWX;n@%IT*0(iJIF@>FSh z+F95!lcUJ>$EV)jeM7anEK=dz8(V-Qd>%>B{GOmFURHDo@`}*(>-%2)?K)5aRd^^l ze439LVhb>X|756HGZ;6BSOf7qYmu*4!h9Wze2o(3D_!CF==ev+|Gzl?c3VQ~z~SST z9_`xLO7<9V8srp2s4EmyX;$HJ(NrZ%VQpe+mwUKfD-VPrBK@l7lmsPO&^duuVh8p- z^w#ESDMi)dM=-01&+#@VraqonePc?WdZB_FqrvI~w^Q*4C~)R@vU4<#Z-SF%PxR~Y z^x~63Ea@)3q&lGm&FeNV>5k4hCg*3ceiOqx)7?^zHzV8EU-D&mO}$+GU=N>$o}VeH z2QO}Nw9RN7dOd;H&pLa%bj?p!4bVpUsi_&u)}A=Crdobjta%2RgU4P;usp>prN)1f z^WL4u5vAYEOuDA(BFAe2$ElJ;((I~96slHFeeURd76-)^y!Q~}MXH|g}1xmpsxZ7jQ)6j0!NWK2_ytd67hYxWnh#ap_v@Fsv zME9-^p$|1u^}f|+WW8HEbmJ8EjG_4beL#s)fHWi1vEgva&-v@&31i~BMM(aVBD!vF z&?nCGdHZfj`Tt#?di(LsUghnu>xEWXs4%P|a+FM3FMAS6OY(-)EsGyM?rMm--`|w5 zWt@JDA-UCF+Jqyup1*5nt=@JdI_X+s;<{dH``>FFo%2yx*LM^Jcp0)HONr1FDIAIo zpN7_ZV`}!Gsf~|+7uNNiq^rEjDS+pphP%F-XP`|K#O&R;;CyJ6RO%w-nJxAETey8v zSytD11~4kD()9GjHH9uk?Zq5shmB4>wPx^vvCrq%9cxy%qB0aMYNDb6W#hNMzCG$b z-gdw7MOExnxKtJ>b;>A0b!mHXs2vlW7I%DNV}i%KY7yJ-z`lP4d#`qkd42eIQEwIh zZHRRKN$UmS9y+z$`Xw*dT@$IpIY|aG0D{O+Ar9vrCg8vQcLmbtj3u064^Nb#)9Ym; zP2UknKW|Dx-E3;r>!0d*`d!{5ZciNSgF|I7sQ=S|{*^Cjh0Vr=bGYaHH~`S3_|-_<>IF0wer>CKhBK9?`o zFLh0m+^S2Je46)-1B;jaQvRQc`Gz{__MkM=7@kbR{#vjqIK@GTkOqkKJ&XT{9a0}jczN?<`@?Gb(<&5YU6p~Vgv6hY zCl=i?b(%J%*6DhYgiog^k%fMD3}WQr)8h#(i1dG}a&0C2j;u}6HFZRdJtrQ$H|(Hm zEJH()Rdk&SF|Uy0NrT=awZTivAAI8iI!<<&65BvwR7TV(N`tJ^qvbh@?lL~d^T?PV zpJd~ACCtUTLUI}ZnUPL2YRSNM^ryzwU1=cDw+&2<{QDfkHpl>i^8$fz@FRHJNY5Gd zd}in=%ug_%8Xjw>ZV#@f5~1GGhD9a3;a!9n6=Nk$GCKN9N_dGQf=7%L*E%0*%;!jZ zFa|`Bwjz-3Hr{&xYsUs-?@lw+A3nxUnqv05OEHYEgJ=?#yCc*HdC7* z=PzwYwq4m!7{$f~;io>Sr)O4(8`lWo!AfR?6l9z^9#@vj=NhY}WxKsTPp;z2_Vn}A z`I+1K1mCWF-4J0$WT~x$`J%dwEGsBDSNf%9j<2$K)dLMeMXsTiyBsS^ye9i~bfw3> z9B?2bscH(s^pzv7azHA->B%?Vcsjgdxu8Ln7A2jPIR%f^P~XDgf2=J%b>#yqdT}0d z)B=_hIe`P5zzPCjL)48^;=)&vp89;fo7(ldA6)<}F!QBDQ30pK9X%dt!T?RpRW!d- z;-4N^QLkCIbxA)*I9oWUS1T$>h>lYfE;-zQr8v~L$QSkf`b8`^Qsqdi@9P({T&r;_ zZh1FEmtGV~5$Y4q^gZxX@Ar++|24xn$Y2G50#Mg@5pvsxfBBtrSBHdrlTCs{nCd0u z3ip<>m;LQArSlz0c{)Ayy-)XFf5)MAi2Jme(dy7S&gIJ(kn8rVNCXs4rOb3CJ4XwQ zID}B4B|+DD&8f)r&|^0*e6rt&ayaWhzhm)PjNm|@x24|s&{3Z&8^!ypA8M_W#R4Hf z+NJv>-~X}q+;L76-zT|#+|fj;H0edyUQ&=QAiXPK*fM(ra><$GXo{kOf}*0JQdAJJ z&{Y($OA$e({ZPS*g=)tJD&p@GZs#tUWU{#e9DeuxGnviq^m+5%n^!za7ug>Ob@Tf| z0l(J^0%0Pr@jvSytbZz{%2IQ`T~x^axODFy{G@!lbcp`_Rk}J)>jOp4zq0Da$5zwL znF;^901w;Y_R)WQsqhOE-%fH005TzRD$R-8dR?*l*=w?@wm^h!5TMVA&yu`mLf=E} z;j3caheGO!mgsz~OGu~|eQz;=yyioET!lUeIGv=*W0hu z{yKc;Rw!AT+#?RvM2bb^N4Ievui6iU#`)DS(NTAP|I_=Ij!Idf5A;~wGJCvU#gB+z zmc>XbVGQ!J8s3-+J|>v!!(y3o+?;C@OfbO&6HGYYa8zd>b{;dwqB22_IRyWcFn5+!PFu^=;Ot_G+)LbVfm|)^*6U_A$0cqwCnfSnjGS5ePlHcc;^K0%y6Hipy zak3>@PWmO%ze`QO0FGZrex;X^qzB1SECA%LgYQ1EZu^tnD zRE~Ky?YZJZsyPG~b)DMG`MfCj8<#Kda}!K3&k=mSywA@!9cO|GCjDfB2`2m(@Dh%{ zi1gZ$9>tHi?GLR#a@7a-V;v4t9K%v9Pq4JWv7AVw4u{unDk``Z=IC|X8y;SKl%56s zC2cCHATrt(3q(zjIY3DA%01L~6TOR4pzr-7h~u#{dV0bjy--l%jC-uTwfODG_uj$= z9TZuTlu1RDBuPbs4(gHb4Sm7G>c-mdcxU=svqK4k;wiKw$t=eas;uII;&sMUV6`ar z_nLxtZu_xD?BXbn!tDvUDKc-|BdfbbEQ;N_V!<(N065J)Z23!1w|EhT?1>jxh9yaN zXi5Q4y9DwI^MNlE>=N*VrgZSoRBrd-a}FHnnbzVW34Dy|Yn~bZ{bbwucdZMvX04X- z_Q~$;18*3TF!l$b(jqHUysB~}x_nZwMSJa+)Wb#bl)JCDN4_T% z0s(hOomvzwytmI2TF&}IAO8JiPI{8N!??rw_TT3Be&YAfuo#af1)gL@mg888rfCYr zc#rA6<~w5-x6f|*rqjU&lcCqDUMa;@6a^{Q<4H22yLWzmVMvm_pr;3T)gVjHI`PHE zEya;R+h@d2ixGQDvP=wV@w13-S=vpNdCkk6cFf@*(358N~U`}U|JTA_(1tDOpmfP&d#ldZdf7B?JV2KF8 zEUE-W2`aBi+_?bEwGKC<=Z^X(1tn3eWge>A?NsOY2X$zf>?WcpMr9RICR84!#20^% z5|zeQc87hv-%uCk??J8yN0w}RTuB>7&0GBSA?71U0g z7JjuP5l49eI)v^MM?zE)z7$LpSX*)uAb0Z01Y_o6Gp3E6CxIreW-t6wiKtcyF^d4drHP9#Kz zCnT_w)UJMU6{kt?y#>qoUT=rP9yJvXB33V;Re5s|Vz=8J(f^PC#agcR4$`Tr?Q;;80m*k~D`s4NZB?=B>CuexeUDoY z$b>+>sT(J)g8mt{h0`8LjJo`z8MWrL@F!V@>h=vPj1+Q1CN2u5dhHzrL4s z8QZAn_j^T%1%z_cYqi{GA8Hx>O8WBpv9iyID*=k7L{g+=Q6L5B^&ao89J8xhYAM-Y zdfc%*urPQJ2;f=^hL;5CA>}j0ku_An3la5CoZI9lotVm| z?l0Oq)pkawv25`p_M91=2OPZ)JA@)nGbAT)yeO~)E22aA=b@q@{J+%rL->gOgITnz zV-vg@5Kqu5FA0(YMD$v!T`5rIPg@zs z!6^M-KObxrw6D$c)dUkvFu?>9OfbO&6HNH8!N3S{-5ic_heJA{ErTFPHM$`hrb4V)LxIxJa+bKct3O65;O4mEXleR zDHs~=0h6Ad{r2{Stg8yt^Mw~0tx}>{;B+L-KyE4U_408 zs36Z$GcJ&aDmgWN9`_tV6$4~nrbyUc*fn^ z7ow>iUJ&+U(arA*`vC|A-2ot}!E=Ajx#l`@(~0F-X~<|;OL-`)v0FCIcz8zf?K@7F zf~5)fV4(N|YEQ3!Qa7&@41yr4Q*m!r{4{p!t+QXfX?63}YwO3JL~^7b2~D6GmSH)O zN#8fBdH*VR7GGf9hUr)j3vT?Mw|83BdFY0}JK*btclDIJuYVEk_z0a zCs^PQ0@Sn`?=_4o-hIat}a_(CT`Mv-4SR zKeM3yZ~bq}j9ratzFQEs)Kl-N8$opyR*9bmtKiCC;(YhDE`QWZNb9Mr%5pp_YKppd z{t|Kgs9^EJ)~?qHag;E}l9wCowO>B8ef9{rq@Rmp#!1t>J6{S+7z}PK^aMZ;Dd3&b z)#Fn=zP#Yf+y8M5o7*xwaDk_Pc}jG8vEjJYVuA^k7D{&fCi@Oc&m+wa*N#P(VaARm z`9wCLlM(8!7WU|V!~Wg+c@ycGcqdFW!LbBIGaN;bA{FCwpoLVFiv8kO@rK=*|K0Zl}B{i8MWQ~{8_l=qnKIY(>m}N`0uJ`OG^YboiGNf)C%2g*_13XPi8o`M) ztI8;``cu=QBl>%t3IDz-uBJWq7VWK_er(eePq^nZq`M&Cp9p-CPXS@G+$lZ%f&A}& z7<}j7d^Jd1kTTA#_BkQ-fa7u zJ#OgV2#;y=X}2dh-0x9)OfCo%Sqz}k!2PbYs5Ex{9I`jt{o=bs!vuy8G%YZsNH7d1 z(lNroeLw3X*9^Bpzq8Bx7mhgjP(oLTiU2r)<|S2SB$RV|S+HS>{=uF;{=wCsd=5Qn z7Q_^N&Qf0Bz8)5QclM)HE)+VXUlyHOFsQt=21+GO`_HX%_kU#twt~LHp_5bgE1z%o!jS^F)*|e%0(puS0AZiDK%oer%A_c& zsBf?)NZJUgw@K1y?X>-`Z+ag3Aw3~7pd?OWRf3lRL8Hi^K6b~QvCnz`SE^CdB-~*U zswycIA=3mazt`}9x~N<7yiOSmu6F(yT23&_$PUMc|$^y z?D2X+Q{0~5K(FNSh3^(5j}HXSnWRo{m47nOE06;Zchr~qk#b6=N+v$T@%+aVYIYc! z@G6>6WmZu+jiOXC?p5?#25D@)RUPxL{PX+Aa}4}ftAJ4$icx45UCTCX(bXLPEUEeT zq1p+HW@v#{1XU9$l0%CQU?ut09ot9mx%Q=p@bV9l<`|yhIErNnl44M5cBJmMbXi+m z6*V10>wd^CABe4jBuJWMNS5MAnqtWq5zDRHi<&>TE(`plMg`4(ZT0Fc) zhiy(pO5=G>zS>{^nHisUOUp;j<8;hr4{EVp)0W(K*_iK_TFUqRq;h_LZ3TUA>k7ag!x}z8Yqn&Nq0Goh)CXlHRc3B=Qiio@q&qjFPn; zc^`Ejl3|cfFJ(TZg7c-dnnI61R8y#mLHpCn*&eGweMawF4fvZYkbHH6{+6}HX}N5ZzB1JkoRv!^4Fsq63Guk@yp!t7j1#R>Q4?CFtjV z&zih+M(UeF8l;H1{OHtTiJwmvP9p?9y2E;L$VrXl+ZzlB${nL}!7L0pi^EuH27+ZA z2Kc`F*rwm!`oTRVWOQA}x@Jc-=Y3cKEiH(gK+!ZIG8D^lD80Glv!Zl3MggL(quHak z9~@0VvB@mF*hH2jPLv6Pk_d1`osIYY*?&*9b`?Z2WS8@Q-22%TRR6^eg@hM_G;n-5 z@xx}-uT6ZJ$O{Cgh2s}cvVvYFK2#%FcC?`*P5ZpsOkYBGzp})uDhote(FD}p?_YYI z|5y{Jv0PCT#}D6gA5FXl>P8MM(V7Vqh5rdq8YeIWOQjcHm=urdnmO(jTkUN2QXcGNInx1OW31wBxO%@Abd$W^ zejr~4fqmE4TNyd%Z+>J=61lf_)a}<}_zjr^vNfU%glNGng+d^|Aaw2lMX7`!Xfz|U zQdp!Njv|QjV3^ZB@wGfoh-I}kEubwStsI%`!XfD zBd(2u&$zAQd!wNa%d_#ufFj+2b2{E5JZflMk)twx?rS?Y-+wsGNMJr3N#Vg*h&;y; zlI0gEw{^5^_7E7*E+JDX)11l*0wocQf-;q#<>T(-uX2Q@-L)m~gV8)G5-A9Zrco41 ziex6;4Z<;F<(c`;!HI)yshT9yfKh2yR?&X^Qp1WVn{<3|`=FEd22Jt(2mr-BDLnmd zCLB+J0V2l$ZT=^N501;Ol?%IbMT2C!LpeItnQ?5uZOOPB6lD$oh38dOi*YwN4XI&T zIoHiJ%lUyG74#jRE~XvF4!iolab03vMFOaRA!J$*I0e<7>5D9_*jeKpy=wa=yjNVu z+_-hf3MtSGPsoBm9GpGtmz+(DQc(uBei_H3ei^?n>4VcTp;O0#Y1I=(yp?E55J*yy zNQuKmyiLbcVY75`TzhyYv1=1t+`SSkZeHe9UL+J+B82>-%9h7_YjaT`9dB=H{f#n3&L6%k~eJ88bnEhwyhIWMz9IJ9do`vGvoJzNeHw6 zK?tfM%d|{zs6Z>HoK`MI-SW=c0i9l81&tTG6?AO;Z_0%5=t3KO2Q70r- zDhRnXP0$2FlsK8<+@AabFWR3%j7Y4nV|=A|_|)D$6-;(3n#%A3O|mQ?#?BWHO#j%Li&L+zo+O8h`_5u;16A6^WIW)b z93MUO{MqXNCXQX9(L4dskK{mtIKG)P4?M^XzWkKd+l$FHw`_0WU~kaK9A zfOB9eN~3rn(LAlb7V0zaRGW8m8(ZRZtrRUOwZnkY!UZZ9ciP%4V;x7>7>Q)3|CuxRaNRG8^-Bk0E-T6}43r%6oFn@!+l)VH z8Ij;9k`;J@<9Rm5{>Mm`Z?!0nN1iQA8@#S5GAzgz1`|PGiaQ)1gcdbgRaABM;;%O^ zOrX46J0&{B{a;$ZeRp>St>?R~$;!P|$CEuaF8R)apB;hZ2#%pCmgY%;iBUH7HYh64 zj|oeoI(9$OWbO4c5~>%AG|7ZRvx`8CuU`D3HE|ldCj5^13;Z{|z4G6W#?Z=1Q_j!J=OsKus9?=q7v^4(spT*3huS)4?V?3D_bPSrD_xU$X z;Hfn>-enojyS<(e2uR)@6M-+(U&;q7#{czhSU3nv`W_>l_`ZxS3pzgf;)PldOoFFk z0iHD$S(ztEN+L;3U1^!xZ{P0)8K}_YcJ|`pW3+x;-sn9X+|aUO+l!WmC%rm{rN#-q> zyrrD~=U6Tcz+YiZa&&u`96z^a;wub=Vnu=!04b3S>TV&&kOG+MAV=4DuJPu6h$J$W z5f%jZka1E07!2|}!BAj|dy*$Kt~*e?QUIs}0xAd$40!y3u+>cX0~)BT%mA8`WFdXu zs1JJnGrQO|26R($g`P_-X73a+l-mqib$hzc7I( z4_@F!hM_5eBzc-ePyU%%i6{OphuY;;&`NERaA_5Zs7RXBXpW~8Mbywcve%F_b`)nj zyl>B3vFBt$8be|jS`+~*>L{iaTflTcx7Rz$tJ!Wa((QWSWZ z&{T@0XPx+B! z%3DmBC>pjec;$z?Zci<(*>h=?B+vit!F)&I*!BHp-Ur>j9gOE2i=*A%u=>k6eVc&+ zf5;!2QUJOHgPuI!{o;hL`|o}-ZIZJ$Mf7`R@8LCX zKXH}g{lvr`rLY7eQyMF)G)nCKkYU7_KI|BLbiLzj@5I!SL~}ye@<-7W9;KGXW6TI1 zcJ%7@zNgkBPW<&ytn%VHEZ*HC<@x-* zZCLKO^)AP>b@Pj9T9>vMCxRZd7Yc4)~l`;4Q1ujW@B+SM$U#V$r%VX;x6PX&Q) zVMB>7!5|2Pg_N1S8jR7L6VsrAoliI6eOH&wzCWTUy+$|PosHboLVf4EnwPD!uoKTX zHY^X;UnnKU|CG$IjK%@R=cK(wmmljt9bL+XtZ}q_ewF>r`EXQzw#233G=HFn6n5On zkrGEsv?eP;qbuLr@ZCEtyg^v-fA`=OSp@OV%>IhZm^7=$KMt z`)@7JG>YA6C9+6bp+uDyBw1s?Iay?_!_DZqqy9;On=B1UQAoq^{v~VsB}bQE|E#~~ zeS8caMj%9I@Y3ANKSRRtn1Ndg68w9^LZ%;lGQ6)V!B^RZRF;pn>b z!DM)mu;chRY)c7X&{F8iPn>krhCJdDVc_6f?%g*{|v)G(<=jn7kzZM52a1bN- z&qdaOkxcl%3YBFZaFB(tv}xrOB>q?CyQ0U%TE_pC)cENMy@9vt@7a-cfW8NjP0pJuH9H z=kh!3F|yh5T}pb_5zfTQ?LeS-T4KVw`XZ{_ZiH4!>e}k~Vnv^we@ulpuW>Zb^Jy{c z+q-9Q$T@5JBE#;JzwEeny7ROZZrD51&d)@Yuy^k`2H&=ISw4x?xE6Vlrg0? z45u(Wp^#$O?E2;hv-7hc3T@FaI?d2)ZPWm_$v<;g-+rB7kKwgtc$OAeTHpnaWQEwc zH>vs>=#M=izH&I<8T624OyZj}QWL{CQ5FSWLvPMfu+wqaF@5o_t^Hd=Nk=@V6AUG~ zi~Nif1|)B>qhig!?#1j|hh?K{%H1TsY!4^%JKt;Wu;cwdtICJQ!aWqnXg8k{DR

    kmzQ`_6}&KG8B|w8ezV2}}C#Dn!m9xe>zG+brWrmVfpfFQ+wy>ri zT9V#8N%;VJ{nMwEas~8zv7Fzx#T;bAk$ex#dt5nBe5>U<$74TPZ*Q}-34Y9rY&QcT zH$`xyDo6^TN$T*7kM3zv{pV`UO$1rSk^jX(d@FO8m!H`wksTTbv4+-tl9L zCdRs~Yyw(bj6n#sikq6^{G*aeu%{*@cm7nr zM8>`P|LD4{eu<82vhR&$>DdhwN8Z*PK^VU)y& zRTPS2WRg=Q`IhmWZf8FpnT;Bb*GP{}(dQKfeXQksAAg%w!+G?vnYkSf!7+-s%^E++ zO%o004ojCJF0i^MsTWu>=Cz#FTaG!ldn&ZX8JNJCPB`qSMiM+pYm3HzKVU=cg{e5{ zW+z+Xd_@7Sp7PdTt%BNzmV=+_+Rovlcdgu3C82`}MFk?IY6P#+bX*4$^{XUKV;4Xj z=cA8b`Nf8RYsBvBV#j%&kej1XP3o8QGwK*d+rVb2=R7#(*syhX;qPKenxrX0b4ca1P+x&q&7%)fLVbuWW0+Y9y2!$1xNN zTiFodsJSGkvLbQh$jCoB*4vU+R`R1oDWBs8$7X5dZ1eSk5y907!m>m-NF+J-Tp*er zlO-k8+ZO_PATSgJLk;dd_NQl5u-F4mN|NjdhR|-OY89+-5dQTj%f39m^el8}!)*FJ_}70CC|9`;bTJ=?MfwT>^O{JfU$z z3Ihe+!eEy`Ua-q%s@s}Pb#g|VQcDv|Fu?>9OenW>#{?5hsJsBl`L@pAZoO~O6~996 zzivFou3}i#TlIS6u7#Qg0>h<17q3SO-gMi2*K}s*y-RFN zQ!MSAchy>Mzq$$(e?1pp{1vu-cPo@gDl*Vy0g#u?{`0D8j{51SY`#hb$uhQ=@jV<9 z*3MaH^$WG^4WJf%X57_7xdT8_gIx?Exd~!Z2?Qat zgeFO((rdbNd7yh{4jRRtJ5MTw6;&=;4$R}8<6yuAk`@d|TD(j;`y5!mW#}ylqf}`C z(6mNNqAZZ8tPHPg#yVS$JvDgw$H{~|(PRbijHHSRN1`E5w$z9}YHNQ;JP7bR-1p^$ zN4wZANV#~^OwPIF=2qAL*`;ah?hgxBW5Uy&^O(}xr}En2mLBn&}wb zf&5~rdic5?rVh~oiNVugctGv%`Fi?5EO}0R8k2??5;DP zyZh5ek5t78+Yi(%Y66%V|2a${>|0Q_W7%ry=`7g%%C^-h32glZmL^$>WLTEq#Tdsp zFTY)sj=)yY$C)v-c4+kaV#Dl|_*+mDNRi?tRS^#Tb^6&im;R9DDJN5Is_LCzp-0L^ zYA5dMxT-morQH74I$xc>_-p4HcuTi5JwAJ^I}Q#iQa}yI_s#Ptl6Teg4x6ug_LOz^ zMV7IdGP}wJsRrBBoL3Vr`X`0;H)Jmu5b)%Ae0$sf=)8(m zbD+G?UNt&JVUC`Lkmpdo!|Ux!(I5CN(WwQ=qwhmNyj~W&*lC&>ov%2`WTf-qb-k}l zbtUv1N|7u@kcy=7M10So(_2NSD8T1`X5rd#o%77;fjc(81t}yVt|5DI+$M@6Se8;W z;aq6(^nIh4CS&Gj!jrHAhIK`spGM?h={!X&>a=-)~|`Uq?H8E=~Ws0}q92z3Rjgq$ER~Q~5doxHEjqPe&Nmd^Nm4|=1M~btBrodg;zmT2 z0@ua;Nc%*Cdg1@a_3zhV+PmLi{LA`(EhJ4A_>|~02A|jx;{o{mLjP}+zu4`osQ*QS z^;h2V;r>m<{GWw6zl`Rktj~?ko164~H3``V!&0INq+uzg+rOoSRR;K|c;8_5F(h+3 zBIoiqm~uNJd5C9@TjQVOIQSe>{^Qo@6op%oEdNpyQB;`d&0zoHpk|Wg!}IT(3#1^> z!<25AV1fz%aS$=|1*9uBrbg4%=z04&!cV?ti{=kedZuoA32)Uj(#?9cbJCm3Y&MJS zoKz?){w+?bnZKy{_mTYD82%YT6$3d?ra?a4K;UO20JIt8tp<5CJ{D2R?>iz7u0rxg zfn3q?%QnaxjbBCQ)5PM%Xs)2WjLkc8M5iCzr6hSjFYMw3hxp)!lLPK-5 zd-b#Hy?F^uJZQkH49iLk0AgGdkE;z*v|i15Su^Uh8@^BIOM_>4Rb&N4mN^3FOXG8F zB$DyY&ClFREw{ic$<7I4+e|6Jd^C!2aDdNf`n7GoPGzpaez>r}>e zpx@zbJ_?-M8-3TdZxcAT2d#1DmQ)Fi7HCZ-7!l4b>XYL;Ogu7+CI0hpB>BiD)h#78 zTiU$U%qNw%S^~~s{~6y7Spe^a7sOI0`6Lx~n4|br(7!Njgm>(Tk0;T)a*DP2@4Tj{ zyvg}R`APYSWwRA6vn|0albu(-aZ9@imnSq(5I9lbWkm+8qM%3%$9C8(Q=Peu0uwi^ zg$|8I#vLfeoeu(e;F)Xpw{7`yW)>veRxKGSuQV8PpjYg{ z{Et5GuBQ@)T|mj|?gr%b`BIcGSxPrKN45X-rW$h-E+vsy37#ftR;6WhDZO{K6;t%h z&J}+L7I`)%ESe{1f{`g&q+(a;0PHHg)%nnGHD)eNV8z5TBuP^o#j+wLiZOA-Mh_{f zWWs>>t-saz*SaRu#>0@CnI4y$5ok`J30~GzT1p+-=d-t7zB3ono-j;khF*aqJsKzV z(J2=~pW~f+RbBNaI`x9O>1*@>o6%HGcdo7R<}EYk!Z!Dc&w;5dEwK_UDJnhjrH@B% zI}oejp^NQb=lj<5l1Hbsf$` zMNg=%S(79ig)`>J!HBr38i>Gh3_E|jbIQEQ(uO(^+r){%5CDpMl1B}VbBm&)aRN;$ ztjs=of6ML@HVsXO^gfK4RvSqxdfVG9cR2s)(Q}q>Sz>No3&+S~08jBEpR8T%9Zqfe zp@~n=PV7OBr6omHX(FtJnXCu7@~T%Gui`tM#Jbg_^>RqJ2~kWzNb-cO78#9DfGo)r z;8By$N2&N}Y)yALciki(ZFvfMb$cseBtI7s0nI@2vk*)*6UpC* z?!IGhD>Y;3xk%ra3@^UcZCmZ|VE~7Gx4x>6S<8oPtd{$nS&yIHy2sNL zq08e2L<0)VYCO$K5+NA{L#u9p^2_SV8~0sS1>xbWq*>Yfo&Fj#-yHKqZ7dCyPYQ%v z_WQkkJs}iFkI2SN$pg+m`<ZEHGviN*<`49clyPoJWq3vvS(WC9OfbQOihvTGu!o%gOv-rWz*?v@ zI!;d`BN!8+N>G%b@|wh<)>026DGKQG)`->{N}*>JbHodsGY3AL(|re4-Jd2Yie*TF z76gVBI1*L&UsN?ZMLWOHX+LxMrd7=oYG;Nm3J6gXC5lzz+aT(u5V$mU$RBe)JMyc0 zj*L%OuL?w!CKQ&VNG)!??pA3D)7W~KIA7bk;gItfHf%X5k`iD^8ZaDzhAppJ%9Ula zJmI{d_9tC}pOX5MIPR2-wB=Zia`z2u%YlF%IsgPb6M@<- ziry6|$u;2#XQR(gPJCreGkgOggVF#_6iHfQWsYVR>^r%mPK0A;Bi;OxL0;~3-qdx< zH3Bp;8k-hVX+9mcISY638sGx~DdZ2h6`5>vh%59T`z8Hp6FvQ>Wf9g2l1*4EC^f-^ z{}M#1ZbzD8+AJ%bwZDG<<0Eqt+sXk(6DU>_NQIYNTkgI4&cFF;@JK~teAP(uG+gOi zRrkX;r+~zkS1eEzKuM~k5HS{)4y?z4)y~(xRhzMQ#-WoUidIEIr2$KlER#3xk=5NI z=p>urp|;jZZNE8?>cPkTVpx$TDTZc5lHyq&M~dOASm#`|uKlwUUxQVQjn@kx@Uo`J zG!Fo~x5lznX>|u?mPEO$Skl;LdCqxb=A2RY-fUnlCo!5t$O0{s3_5AEcV)ya`#I;A zwdb_GeP*#AibS?CnkWzyB`F*$%L}ggutsDQ$;t}VFHpHSGYy;NdFM&S{?0Kco_k|*#Ih#0*9h$Aq{r`O4aP?u% zh^eD^%H7x7Bi|DWfpBbZ83eo_80-?9;!}DS`jn8z?+c=wol#(kl6Ji9?00m?tm7k_ z$8PUv-p(fl0{%&Ej^cTl;((+GF+2TVM@qulQY<^1$Ey7x^j9Fh9vE9&K0~>EKnj3h zXyAmrK0&{4pcERnJ%8i7JL~ne!iBNoNqzg3F$CuhXPsF`4yF}A3*0X)aSx7jq10(n zlQ>QmRGyZnKM;Cj<-vJa{#8Q;ez?Iz!1p!l`8^jB;rqy{cR1DN`FC~wt5F;&R`GVw z7*5h;MU{AtJhvU*>U*g5_lQ*sqv5?=T^pfyy{?} z0MA4a7@*C3+$TQr>Z@t9%sDh630R`1w;wad!h~dK!Gq2%ZKvKn?z@awK7IToH;ppo z%+~6dfKxp)#nt`l8hG9nG=Wf5063mN$D#AgMi{}z zm(J%bdnXTD4$Gb!pUqTdjT9JBB!TwPa(|mtyOs^zCc*ySH!!+`{q%ISPECB)_xzlS zUpi;33{C3yRkG}X%2Ev{JAw_}aN6wejC?JeP#mQAyS$Q4vH|V+EYoQO5J0Y&viX?z;MCWRKkz|+K5zqG6M2nR1Ww=wt@!ZscO2JM zfuUPbpF#x&B7;!sg_)ro+xaO6?_cG6=O1s}^hNe#H7(Ht9^<=6xOUFaVeb1nR)g+6 z%j>)7(mVNna!#5cTi*F15%DiGl1Okg$&e(468~(?_-SlSzd7f8bNf|K?!?~!h$Jnt ztjGxrCo)Wokj0_PO!nAtRs8O};>#<=Ws_l)v02%1_zQw_Px6Gu_0IG813>LssA(Y3 zC6HH`4}2lFA`_oJ@!9O!yyy%giA#!GsG2k$g-_6d&`4vuYM| z)5G6FKaopgg#sR5$RFWdKRC{#g}V6*eWBp=wHsVdkNU|5B~>{HIok`P0MhF`D~6QF zh)y{tw%+h#)&@L7Acz7_a16y#1Wm@qh?#Cs#VP0Tp|`bt6hIC+j(_cZUT{y8ydHI6 z0H_{C3V~N9`jp3xbE!~g;J2DZ)p3L3^UHGtYgAfxR_wHM!1Gruv>r+9QeRd@hNlRg zr9@O5mxC?(Pv-*b>h8VGkV%QUHx+1( zr4+!3sz$@0DQ@*izFoDKe@xGW-ey}OBM3!r(6hP?`M;*M^gAqC_HxGg1@qb1XI@Xl z{qnr1F{C0>oTQ-K?__<_of9olY3wjrT{Dg^f9)D2VcZ}f@G7COf=seJE^d&5o#a&4 z^|om*ynjov-gvwlVo@x*A@1o9beSZ1LPJ8T$7h+lX7#66zns=9&LCM5==oL@hio;d z*W|=64X|R@X0EHneH&)Ce*oSGjLeEzo0`uZ)-wV!$@3gfXRpW__zK-I3kp(yZCLc< zl)kFlwT<6~)H1#g;l0%OeYsNK^H2>A=UW^NXT|FE|DYGRQ^(RbBT8xcNQH-+L_fF= zajD-+SF5X|H-y&}bK2|w--`*ceg|gGV9cB;a`gX=?kP&|)L(?LCRXVAt(b8*lNSH^ zYo*-Nw80u%kMt9jHp45uu1H9L*7|(5NBogD)hmE%j<-yX{{JIPJv)$wO~tggv%V?1 z=d5~$ zloQ9n;+8dxe%=^!&2hIud3RPa9NrZ3yf>1EA*i7cd#7zJuDxNuhDyp^>98g-G(f@)9KOa zlx8N~6$wou&YY~cG+GT;vq_BuYb8i26vVQ{xJ6 zH+xsg+3nWH&l8jPUx!tgftq`s>g!QTy$af#A`?s~g+R8h>(HP-j_#aY9PBD3Au?5D zPGt#&qcxhWeq!RYPxy}Ij?q6oYP#n%;eT)w*(?oQsoP%|I`MGkq;@A84Y!8HgiDh4(-8{v6mX*fo`LU;MAr3GByUCDx0Z4r zG%(oDrQJ`~QtmS-fUI9h&NEZ6S2^j6{~Dlzcbvjw1J}kip?>{u#yS@T5-Z5GNQkn^ zqs~Pk6f{bXF|}Hnx|Tff(rumt(C+S_C5ACAvAZKgS>#EDRz>-i@ttmGKOUKlqLEKd z79DKMPGrS>UQtlm^3eD3+HfsgGp^{-_@~oQ19WML0+~J_>J(p*397pw;4c7y&=j{I zUjBCBW0x(tEC;%@$wpF(!E+1dy^6}8ulN2d@0a$yONI_9Uf3;Nga65V=I{eh^<{dj zAXm4_XBhWDPXX|He4uAx@SJ%!2!??A+I?Hje%*J!&7+sFK|j=8dj26>;OpFPz^DqyH;TSW-mtQ6u696=~=C`q%i6b=WMh<9iNdUWMwE!NP`J+EqAABYY?$h=e$)&}6 zJ-uYm!h>43Zr!?({~P&=Mf15xKF7?LD{qd!IsWGOo8y0>^Hxho*N$J^tJ)2R$HB7^ z=Q50_C-N*yQH;QI6oE$6tBa(y;!v59Fb?4qQPa(A0}3W3N$$~VVO+H3{)hL5@G&(g ziX&)>6M2p!c`+soOsCh2I+OW(D&|CYx&Gb#;GYk>u8im$Dkx$Jq39l?n^X`g41j@B zK*|qZ_LOQnT=$C{*uB5nC1#?_N_C`Iy1KrUoBlTHRVY4;=kAjt#IU!`As|$B^ZmP5 zRmn_+(^6G$2=sGowI<$(u->k&A&-vTbbMzMWM1Okco7sW@FY)@g2=uy;6U?5d$(oa zF0NA%p#<*#(n6|%P^7$IOTc_Z4ry1{;eQuAbb3#{IAn6M?*=MNB-0utFg&w&{t|Kg zs9*-{z;SDIYO%!6muSs)bItY6p7Le_-zcI;@)W~|!!gkWPoewdjaPN|xGC|g=;q43 zq1)-BufWiXnXzjDIw~gIgMs1?s6D;@N!`Mm1_a#&;SB>qAP{WTdg8qw?>(G~UWfi@ zk4{m@!|bO14Wm=k9o6v)7B%%kCLP6P(9Z1mqbIJq>3Gx4=&4twc+PsdhClb&z%9G5 z96HaEJi&`JPm-d*#F&xwPECw9db$?npPe{>hu5=n@g90LK^9b+7kEWfdrfyP4|LDW zX^#{;<~*^NW6o1KV+@|-px^?r)dfjn6Pu-%D~(;c@~KJiDq~X|M=g}7hw>QV4@>}o z{$NtqhR@Vmm-ThEA^KNnV3U^-L)hvFS&@VJ&SLN!hlO*J{NAXXRD*J=8$3_89;1F& zFJ*s>;6m3|*#M%gUakfcXSDrxI;0*3rp1%`@SG-4B1LM1%+4pKR-M}5-&`|{tqCSv zcsO5|dAXS9MvCYS{zuw#zA&)W(#JLbj?~El)MMhvnGR#hhgviHm-P3dlKwk@v zVY$||A!W?iwMP>N6Cq??Q&>e22|30;!}u!k%f8mNpzZOiPi}(b&A@ovm!gUqt*9K$ z3Vex!!TOUnFQ(S4N`WN7j3hZnyozLBmutrB-#jt71MH>^$2L)dyGtM-P3hqUVbAhI zLQ)8XgS><}sa4bO-#Orxwz<%;=L-F1VEfLZv$4gkMd{14quX_}RFrPho$vgr%MCW_ zwEYg9o6FVb84YiFuTEolkcA8xS~$d3y*&-|9dfivw8Za1yIhe`9uUzWu7a@gS0Gn| z^^klgq&$bg2Cr*Cs%0AFQG|lZ*HBk&HHz0;KbPx4p9cO&Mr1=%vdT-c2q<1K64|6< zBzMW8KuamVt0?`Zl%#j+AlDlMKKS~(PawCvAXeuypAlGhz7$f%b@6%!gFG;Kfc9sb zeRJvWhh_MYie4<^q4;1qJ8bm*D@cA0=DpUK_kBs$Yg8`oJKX=RlkE3{=V@F`xYTHv z;jVYreB5!|4fSJbmhFwvklKO@jklV&1q%R(Fe-gbqj=ThsNf zjz{Lydf>){u97t#P^u_$l0qstSIMohRmiT8a#leChfRPab>0YXIOhQkL?aRZcI3$8pjYk&GK$fet{S5k&Lay>zerN&-*5Q zns|3`yhaHuscH((q0YrpG4ivLItp9^M~rk@UaJ>7Y9&>WJg0CXFLMG=&_N64Bs*w@ zuBDHpe);V;ScZipM1p2{nx+|n5JZ$=nYz4a$kt(F(N1xlu(jGg-h;nkVHt|!DW0b} zhN8I`as6n$=w8@P+~j)oy0_L%`yN)&E8apTRF+XBl2cTInf2uAV<%T#UIo&Jn-D@V z+501_QxtwV#0#=M(Gv(2O5Pz}f2gZJ9M%x1=rU>g0_YA4A@LgQ$<-NB!;8VvRh!wp5toJXXU8&6Kcec zS!CEaT0l|STAhD7hMkW4TuuJ3)_YZ+OmOW@ax}$?Jj)3pA#&(q>#N_Q)xyR;o9|lA zO#9~>1@>>R6_1})RTOE8;Z#M_&f%HMTK?E^`9B%OjPh}&YEs9;0&6t+jWSB^s?h}d z!a#KUr>8~dZ%U2MPxVI+>Bqk4ytpK~zAnfmSKE5g`3^|84k03-HxU&*HpxBXw_w#qHIZSYFbMzviK>m>o>N-NW4WvEH*4O?FXm-u#qA1DiZnyW zoS@0t0M7%T4LZ>_Hy1&?jrG2PoM=2#Lm##~^&Ua;t-n6~PwC>X&bq4eVx4%=G7`7l zW_iX{|LQuY>NJ8>Q|ko$J10qu2qZzIH1Jxe&%9G@-pz&FYrQhkZ}rOgeX`}B?{aa$ zKA&;D*6Ph0=g+SbhgMX)eqT7K2Ez-SCP*a5#6(Q_`D_Yi(XDaG-;DUcG71u*KgUj7 zKFiW>zZ?XCi6A)4rvlC61L_0f4IldpuTHZY^srYs|4;V)Ybt0)sv2AtobMPRm6tJH z>uNHlZ=EHJ@RTIQa}2|i9Ki{^5Nn$8)oLBPPs5>+b*_dvwO@a4a*bF@GLkgmg!}h) z|1dHhbZGA_0vOrP_!AK-0q8f;((gA9BmlH=!6uFY{ z8idcg$VJXy(uUT<4n>&Ep;(#FBvoZ8cG;4xb?1)yCj}L{zEtXoe$BOgGdcWP79!$RW$L+MOu6?xgzE*qjRqzZiu#7+v6wNYh45i*?V^N#e zVwi!gu2J^J9U5K>shQ)pc+?CDXpW!-o+CK!9&P8YCBOWVc3lOn15^Q}Ns{lE7dros zh%B3&r}0Ap=UALDnAawiY`jVk><-u3J5Rp)!v2Il{=*^aWR}zj4rnMnHvvnC?{fXp zb8(x^t?I`f8zqumnsIx4!2+O!t_4%hyzYH9-njwc>m<9i%XNJE^G_b>3@ORD_t!E{ z5VXirDkl|-Gtt}YDoKtf9)Iq3J=%Bt>~5gA3!Vr-s0_^#3PG_Mt=eb*)qhVl7{&eSavDrto%P?q zD^J=kOu0B-%WB#0BA)u~#u=U9`pJwdW8#6PkOE2Yyvj{KzOAwQzK+!zma%QWAnMO&s^zW{Ilc0 zW_aM* z8I3dpRh$>VZRF2fy{5l@a`xneBrl)^O`#=9lqeM?c{>v}%$hpxsy1*`nC@;tEzo= za{IUbzFfBSo0Y2Y^y&gN^I#YM_{dfHv2ZQVK zEd4%I5ZuGUL0txeJWntbh{51Scd*G$e2V2e*XN%PO)a<&;+LhhS)+-UNUu3%f%5LZFI)UK@JeOHC-pJ?xJ;jjy7~fqOTT{?)1vpm zHyB>#A?t-H-^4E$2EQb`-iKcz`}k7F^Z&K^F!9iZT~FtGJWwVTwN`?HOBezfh93V} zPao7f=+_Hwrk9&3wMXdo)c519%F1*3JMc+^vNckxjXuO_6_7hY;e+Idc zddWa`Xfu#8w!+K<>}MlH&n^Q=anKaWZ-n%xUhpVg2--F?x&LwPuc7a!dO9A{^gos$ z<5Y-g=imxzUupjrkpHa+-uy%FhlI4ZCz4;CWQa8MJ2*bI5d+9w$hx~%N63Bo=oHfb zke-F>zfh-VAJ)GE$a%99NrQJ4z3`HLP{0(e55k%|i{9_7*YmA4{(BJLz;TA(q4l5u z-GagL;CpRaM&lur-GvvOIrF2x`$%7(*Xs-MvX+VWOA2P+ysNL1-uggu>B;@SNM9e> zNWIBwgcy}?)E)?Mo;(;aqG~DI`$p}kx0JD*{|aOl&-v0;TTf2yjx`418C7M&28XiDwcIoOmS0v~ zUTh3fJITQ*xySk5RrmVeMs?g>Z02N%Sz<+MMLxB+PX&|REJ0H$p#fC@^4R&}f$1Mx zb8&9O=jnw0bbYXSV=YWz&Ye_oyjDdt%vJ1$VBFnXjzvvszBNnp97l zGVmaF+mIqFD~hTBi3O+))pgmW+oM*?FRp=hdC$r!kYk)4yKTanTZ&A|0;_R=XYSnk z_Y-a2SecoP$n0^ctpd)H=(YX3>%Hvv0&nb1cr{LwoIuDF$;-TeUX54B4#z3i--mC! zqjPh3P<4)TP|yxy>qg*q4nLz^C+(z*S%o!K~({5EAAh&H8suZ_WX zZ7S)3VYU3}YJA(7vny|d?9p?vD)5EjD|mMRgrq#T2vmxb6_OB0a*j~=pmRo#VvhNn z>d~nQCR|9st-q4R{+Fxo`rXetk6{tLK#Cg02r8kd8j9$t+|ur?zg^_!x5q553H5Cv z4Y!K*Z2-fGf}j9NRGD-7HgEMk)cX6zH|Iiu+UB(6Qi~;i9*@+|y2hpb*{M?|Y~Rw@ zgD9V*8F#)X5by_p+EdE+c&9Yn(z5Gj=Rq4B<^EZT)06r^Ussp(&%eDW{cC@88qmE^ zx13%+oMyB9>ssfoF<{tYs8;!G%wZKLb}lbG^7a$o9XV9P1`YdeA>vmApEp4yC^uwB zr|^F?Eicmk*LB^vf|ZXyozNbT5H(5S6;c%yoYoXfQL9u`i^|9zFtzxk#Wm@zjtt~nO6?B+^U^sy}fqV`@g}PfG_dl0XGY1hSwBE5CJp& zfzTT(56;8J^Su$dYFcP8mGJ!=GfFpQ2UE-UKK|gntdsImlln*J!I7z(z+ONSS(O1Q zL$MTixz9}<_bi^5(J+p@&r%LgkrnlQMQs+`cX<1N%R9~gXmbbge#pkeF_Vd8V|YOn zR9;ain&$g9Yqo3N{d9VrON`v5(~Rh#+MTk$IJGpp4cyR?`rc7W=d8%M`%59uMDYLY zU3Yww#T!r3UD^V&hip-X^6nv$q!bVYDN|V*-f=Gtq)AOuXjO(d5X1#2ASeh9mIFn_ z4TyUHf{LJsfGqhTZV}Pnr}VwHx#Tjs3-9-z%e{Huo6kM>+;h)8m*vULbGm>xq~$j} z9F99=j{6^$sHwHlv4Ml_6S3kqqX0#rMV?_)5misFHigeTnE$l0{&Tw5i+@R%1ZP*) z3lj$fQq?GlWqbL5p(_Av9V^s54Os%aS-u%Urhi`>yo(JMWWv{ZF zO!JBg6pj31&1e0IQ<*7lL>@O`bSOCWH_DQ`SCiV?IIdDYd{axx0ZoUV)H||2(ytvb z{j4HGvb7#+nCG<}a16J$a(AztvHk}*f^*`7*T)>`aCszkh}Sd0E9I`+JM=n!>-)*G z>KFwcspFo3(3z*a^{FiPDdn9hqy68&g#r8$qP_L4J$pWUe|(8qlR3mXQBY-qq$x=v zSfcbMhVQ;>e7tBk30f$X_cAZsd%KZBqvA-c8+Ybf5;vPVTJN~-uAgWA8U7TqqOlAM z6oIEWWr9p@*i2@B)u` zuqFw|AXlG4_c?80c962LCx+d1wdOo?f4a$cQ7~gI>r;^x$bSY*-Poqy&^X9YZ%>I% z_h2z~x4yM#w$;}k&X`1a6_F&dEW=8oEGYo>D|gR|24NQt-K{G={oiBLmo-NgR%Lf+ z6p<1XQBnzplh7TSK}d+6%|Neyiga%(9f7jqO1>qm@BaMnf$!EZ_(m#qfHA1ZbP#wQ zipS*wivMch241H!+&RH56~okGnm*Weh>^JjaNdB5Kk*a}GW; zdnuI;Y58&Z1tzb`x-P7=%&hgr@u|zcYX!-wAU-TvsWiniBB3xM%f0VOUQP&0EcfW2 zCYTIFgShjg9??$V7UcbkUO;kn1@z(#gm<1 zzcR0ZzL)ctzDLxcJ5DaS(t7uo8{S&}0nECLm5@vIIz*x9wmsl=N-pQkz%c>%J5k#g zj2f`t4AnwUAX4IXUF!GS0^_lZOg*hkq^fzhQ*xrI+(NwD9Hq z9*3$HDyyn|4Uu+jh-s&W<*awZYHqItEV1^ozLAxfwQ&)4I53Pz^BhUgj3|&y(EVC> z>BHd~Yz|hd*U~OyRx`*fwkL-e4x(6m|K`U$JB9onO+1iU( z|8{!g80W8=64s5yl+k_$j7530AS-EHpngFTVr;L3^HkYk(4T>t0DcR-w{_Rx*T39- z8hSE(pv)FJa1?E2oRf!kjywK{?fFmRpkvL62*E+ab$G@PZj$WAXx;vYDJXotRS!4o zA#~UUx34xLmh$Lr;9HUSW=uXX9hmN2dPwQdllZ{r+2+9K2P~nVKZESwCn1hlhF}Cp z`24Pj>&HIU12eZhGr2cx=`wde6`!-#k1nxCq#&&8jeVo5jB;+#Wcv8Gjc|@dww(??+K0+7(oRZBWtL~`^zz%eR+gY zeR-7cl^4~OE>2rE$hzv@H5aF@fC}0WJ7Hyam1t6u1XWWAR^gs{cT~YGM>hs3AYt-7 z&B4qt7FZ&V&%xIBHjdu0#SQgvp$)HTAgC%3DF8^WQRkD6vc}$b$9UG#Vj60VTiN>L zQU;!}+ZamYBMQatPKunJc=G+%0)LK2Epm9`*>td3UdqhW;riFm3HJww0z(McwuzX5 zV~X&+s%>M^F!8hq@5N){@ln>xK>3gwljSlIUr% zcF0W93^TKo4z%Ic4|Wf{<#`&OsyJ#2$@#T>A5a|}EpaNrv$6=-A|>nIIoq$i_r8s( zEoxc&%a!yUY^LGXRdcU(Wo!*^D9A7@tq>ewMM_I;(Cf0Y*Ofe=8_R#&G!nPH-a6pW z=9O3O3qb>AZmr-cPNG?gS5?-3&l_9I9&C@6DV1h9+PeDf`Um6w2pxV%UorFKcQt()7&I_HJ=h?$w$IYp# zDglC*R8>NYKOAFZG}cOW*rJa3C49<^Oi`Q&R1q*i7k#7meI}PIHg2$Xyd- z=3hMJ806}k>nze87YitZ!IbPNZlM13L$?kSe*H7uj!*!c=$jxjDtf`@9hT_6Ylr#% zkg0OMhySA{SYKH}KQ|%oQ+oKVB`^-t?WGrRlsWwWCggctMJbJ0+H>mgkx<~hJG{UP z7)6#uN@9QrX8t$k?SswtrKQK1Wo1{vY?7?&?fv8y&%#O!39dxZ$W)}fBKtT8DT^u% z7?x8dB6;yIIm3>1O^0;&JmwDZ|3!KH(PC1pVB|H=-R9M3>CN(k7!5sbK+7)GQu#EmJC$R3B z^XK;04o7ujngl$-3#`Ty40>X^vX3ZM)saU_C4GlKF+IV$_R2Lc-k1hyHOGWu>Ll&R z^!W#S)N@t>BS3-wRNKRE9pBhENJz{=a+gn=D>$HXtfL=bI$Zg8SV2ReWr^fvMglU6 z&Zl2}V#Xxxv<{fNcWKY|7X^>i0Fz@{JU%FqDZ0l!+GEg>t2NOI=5$^A;|*{w9}*wc zgsOV-Wf#cuO5)5hPUHc7r*_6|y@)o3j-q+K)N{_eF zGr9?>e-={lt$Mz2dWGd}sLv3O>hY`ef$)VMU!pg}oqBq|AcvVJAocSj@+Ar==V#Os z`O9pYWPNhVZ)bNcg(GKC8C?QAv_KIo#|nf>3xbFqT0pO|&%lgyh*8MKOnd~LNPGl} zE=|jARri^XJ4S}L0|bP~X_}-k6vf`(`q0*d=0i&K`y1hIFmiGN?lkl_$JV+Q(@oZw ztp&n!$*@d$A*8V)i!?7#fO9hNW@~rdacbQ|{r@R(`q>l{Ru%=^WbJ=yQ(Bkh&4Xn( zZ;{aLbUVB(PYNPUDT>T$=yl}L3v>C_6`StoR$Lx_nM`vWLDMoPhzf;H>(64-F0h{c zYVF}oy;_!`vf#8;fs_?VrUe2ponD=}iDTQ3ty=oCBrm4??h5mJl4?bGOL? zZ|{7k%kOmeEpl#|Rpbm3_*!)vH%smOLOh(c|I)paH)s?(9F-nA#J!IKJ;RH>5C7ko z5bJz%pY_zwIUC-lTLd?|Pv051B3~j&ndAYdQYw4ru*6jX?VedY@id=bT!vRuLT7cK z_2y5Lh8-{2>=T-Y8nmRya+*pJD$UY|g|kOC{k1PKu98i5qD`){EE`j*NklX1Rk!L@ zQPefdTcf-e7M&a8)_}n$3>c^zh^ylN4b<)aHDJJi0Th*G+t3J+r_it!5~ANVic(Ii zYI&`;&7%h2H(}jr*++T>9|7BLY0+b5!564cOsfMg2}=uO~MvNAhNQRFIjM z=PJB@yXElN^*hr4G@8^v9f0#kqYVrgFkm1Q%G#WiUF+O$U9go(dhg9B9X%@&B>+ND zX_6q(^A0bhh8Ic9ruo*s+v{JJ@?6Q0kGQaz(UL-mqQKE2P@i}cEd9rJeY~cBI`)lg zj7~LRpq%Riv*{u0z6nEnJbDwf)+=NDsar7XYXpXI3~}ZGm(vaU<@=l-H)_nBgXEDA z11}2noxjkU*`Q0_KQBT{;zhySDA=RAzRT|$wBR{g(M^TW zcKivQ*DTjVocj*c%FI&94ZqO(dV+RtBQjp$>+{2>Qm&B0_CPd8pLLg z_!Sc^B`mVepXsvo`wE(S-itYY2sc!)g*H_1f86^U zDk=Xq)jU+&gc&wvsWQ&A*t)X*bC=(8xO4DOE?Mf+wBX410bkZcU*Cc}kJs-TpaQqw z=`Vcg@A3W1+H^k=S2>iv*t&LK){e9i55xU~OI398U8OiqA~>4iq+h>nnO}5=CS)MG zL21+;A4+qk>+kDI3<_})uE?D)PY1a3&5?YlY4q;lxUsUtdNi}yh|lkc=4_=ZNrXyK zqNLHr*-Gr$%B9vmAMG3=^bdP%kp(PEh#DnoYS6L8$G>Zf>8xeep1lsJ!@p~fOjH3L zKNyzKc#73jS?1uqU+4^XXL?|W0(~Co7WjrG|2=NK=6^r^_2S^LwPy%gqIgQ<6q-kC zKVc>A(B>Lzw*7@ZdB%*=oK6t*Hc{Qv*O zXp=UoW%)=B{SI$t|BUsX#xah=oa z&zD@iJzlS8iqGN9&2tTRdHlt3pl%s`*RZm)-)HHeLuq*UUW+qrw(>viR^C2{Cqjx~ zNs?`g?J_(nB z`SiOJzS$C<#wk*yMNOm`l~7O`XQDn~x7E5}TI*AjZwh~rl1K>>qX|62Fmn8eYrfg^ z>RstLCqQu#;&YJ|66Cb^Cq!H3_pRwe6IR~%EcCP4&Wxiwnu2~Eua{htfY;~n$P9Kv}PI zZZO5+l{J}T6q)0AQvSWeuzSjS8~aW_JDnIc!EUosFU@)F<+b6D^a>J37u~F;DgsA+ zV1DjI+gsC7-t$yqbPa(Qvvyf0gX9}mEQD^EHbtY&@dAIo*X)nIbW(zx@T77${*1z6&}ZZ;3J< z?eeg)mZz48jj_i%bWV?tH(m=l_K;9(K9T1&S`k^1R~d)T<(bm>P)E8*_CkG>M)Fk} zkLBdwSeu_{lQ(EFB*B6*dcIr-$%@UiCwdmSQK(nWrnSTvhei9wdSu^${&%%W4wl_q zYQ95^{U*x8);<@lf8F&Er0oZiL(w)XvLdOGBq38|y*?eM_U$*jewsP_xU6g#R(?i% z82wfAFe5x9+V>k*Q+vc2{cphNr}GYF*D47C{N<#Tm^Rw_ZNubX`CQdxN03vc+h1vf zk%oS@UNI`^@wiv1V8O4{m8jsD;`HYXk=#zDA8;$+++zZ8l&pz_Dl5!6quD_6VlE9Uw25x$$!I`s25k@(-b$}&!Gz*jm4{(nLz zEwk>^t=Z(z>Ar`=m+9#i=$gZIePa{h(=ZG87m;Lu9{PLg`mx3OI&58WID35Y2e4WV zqRb!W0~McpF{_@h%%RJRVynI-`5KbW9}NP-+J;g#_M5eHy{EIbXc2Y~HK$v3Xf(r- zny9IqqRe>E|JIt_^RXWHk})gkNF|EZ5p{e8-^Vk@zpTv;o;f*pHS{LhAjIt{EJHXn zN%8x#H8OEL_031^5+F(EYzd_4pt!GmUAM{{SYY(ph>VW|<3E3d3~5ARupWs|M&fx$ zoI~Qrk)eA4iGPj6KSSb(Gh)+vB>n^vzXyrWLgF)#cn%Wpjl^w8+=|3e=klG9cs)J7 zzv+|DJ8wOkO_%6pPFuUY+UWS>kjIAFR0!6KDxQ3|f4E=rgIwVD_miA15aj;Nj0w@P zblUoD`j7LPrek%|5(P9xAxKH)K<91OO)GodP$%RD-L$yy1J`2u+d6T^zvhOQL0)(_ zuD+xoII>(GH-Ju@L9Ww3z+Gf{Sak8w;ywk|UP~vXrbig!m8Ctx-9r4g^|9uolRLZ! zRg6c?AykYqBXqrGP$SXWwLQ4I4?eiNySuwHxVu{hAKYPZcXuZ+xH}B)?(XE{obNn8 z-`Z8FPNmc7q>}8r_qwmOA|R!b5M@-4)T1+@{XKOOatI^gF%kHy zeK%o|Npt6 z&Xz|g_JIrR-}-IUqVgcL=4|eO@*(s4tt^PC$@Nvz>lQk2w0Ch@po>}Sv2CWZ{PTs~ zO+>b~q~V|LV#ZwXZD5oA0mVpkJydP>-vc<r z)Dk$Cyj{Yo;a&pXy=R`_Tk*cw7_Gz+N(Kc+MrjvuakL@Adu>N;Pd2Zet2wa=ISGdL z($iMc71q-gmsDgz|BnG&O~{?Ckqr3%$B|`#hDNOPiKeG_1>e@`>D3)WE<$ktjx2By zGkXCOz;;`?aj&-d@w#d_T~QKzYJ&m+Z9`_`L&Rrvc(nRgYU=3~{{`=VW3l?BV!?uU zrRCg8)?$eAxQ#P}qwUZ`I$D_KSFyTip~~HrxZNsV%jf2s!{z;Vc|F+l7Wo@mh6YR} zwe6{&5taWIJXv?|xq!2itB!O1QT5)7tqR_tiSkfO#>HGjxGB1=i~BZ0!|gOmZd{R{ zU>NcqLxw2P0{Ad=rsYokoK4+XZ?Jc3_V)KwA94u$P>dum-`E>1X@;GE zMe^Ta;r%^p^*#5GniWn@JdP)_1S}Y@UWQ1m0}Feh!a zV|YzV)rFv|%n1^XTNU$}^XtrB_M`iqCldx12WHZDbEHI@wgil(?!Vmgq&#(3Yo6R4 zxy>~6_+@Z7G;5NNz9CBeh9`?49~NZ25q}(4z!~=Zi@9BEyZd*D4x!DDHUm_kk)kHZ zPN*;SB`Dc%QGl(m|gXljk;Jk zgmTg+h(Y12jxQLBAXk{JBJTpJc00?lrj{}dO(Y#a#afCdl8pHt;MJ_x(V@q?Y(#Y7 z;2b3L!rl=`g~+J1B=Lyy{h|B!38&JN7U?~WV-CuQf9!6|`tVNAw_sB)xBczWGBMcG zK4!phPlYeH;zWZ}BGZdd@Ye-W2Jkos<3BW+`)7e!aw!@80EE@OQGXt73TKQ(Xb0$; zv){(A)Pt0JFxOON9f?3)})+mci18i&Qld4v#Uugx8o-96cRx^F)(ibCZPmqe608TZ``x z9AjZDTd#PxNvKno@vA-A+_&5!oN&4aCw$6}8kRXig4zUa8GDJU%Iq~0g5P{}&4ECDeIiz@l)C=MDEkTHQFDc@2M$23iENG;GEkQ zh%$0ZGeleQzbg&h)2%Yr&$;*Go>&W_7wp+mm1L7@N*u>!AJ8-L=AP3Z@#9~#4GfYA z#NFqpjz6QGr@b7FzN;I0Q|PuA+wz>{C$nvxsBnt=K&>?vTx2^`WJ^~Uy=rhp^ZonZ zWH6S-Rba3@NK34dMj%iWeL1E{b1P}NrdBiMzr_RjbT)pTle|)^MGZd!&cwz#+4>dn zdf(wQdZUa3z(6k$&h6*0xBRNP0Yn&D{a$!%TpY`!k!31tIj{NiESViE*zTaE<{K9O zyMbi24ApXj6nW|l>Bf*=muN94LEy5Qm&#lIu!n%F40?x=Lxd`SCn8I*@M2^!$h~zk zo2794Fnl{KsCz-MxG6&0iYJmH(#gm!zNvI8e1^7;HY|V$3U8Y&NtH$ z2^3&2;Uc4j))Fq5?Iky#`_;f+FMjjVy-f)t5e2D$j>*LOpIE8lfL1jBA-`OB-xtpo z?yR41*-$^%+6tb+YXy-;FJERjrF45x%8)fR#IddDtIJO*mP@a6dIVWQ=Y&FZPk&0| zR;R93gqz+wnTMD&W07|E!Ob3Y5*L$BaQ+}9&Gsy;qV_|167<{b%Ch-(->Hf$w$gGa zBrE^OIXsI_bsZ!fNg#y*F7aEWh#Wh7xSl_{`GblOcja`_qmL(<<5i=W9~f*7C8Oz` zlgDBGCB3@qn7fP#|J`;TmOdLSVOfwuhn4`%qsLzg%({J zDWSLFwAps*Iy~;>=o4+P=XI+VBV*L(ywO*zR)S9?Duv{t}Zd^@u zoiOMiY3o{Zz~V{5g}c8wQ)Vr67|HoQe0xLNw~K7#vtj*>AKKv5WIk2| z@#LZ;G7=IJLC6*a36^VN{($3?xbIXqO5gIe*ZX+-l)Rg@g#G$=Jq_gxvD)6gy=b+iQ z(XEGBD>RJW8XSBksCJBky^^r?Qs-@`Z56oLe~y|b`lWY0ohd43pxDaWTO9-rLuJD% z0v2?nJ!AEFGJf`Cm;O6ZO0B!gQ){NnH?rODYR7B;p{2*+6d0q9Z>}v;X)2c61Y@j8o2e(g~qqyHZXo+3R`}kRW`?wrMu_8r9a-oOUUJwpR3#j@*=ONm`7#HA7!ngN5JXK(hCHbR) zh|-Yg8T4l6{EV$S)%w$WGXFsdW>55J3pW3YFebfW7moyy)3EbNxKkY`)V05Ql6{8~ zG_r)Ny4njCt^KFmIYlJh`N#u&!)w={Q;1+C9s%%bxdMon`g2cVw-|-JQGeW! zU^vcz(=&n_{C$QIyQOrzV*glCJz4mPe?P1cZm_`zEmxG^1P0m165V?jNkXF(%lG(? z$y{8OAVX4JCc0IC&rCYl-S_Vs?KWPJmQ{)=RHCRm_rp22vsMes*&Gw058%!iDXO(h zQPFdDRVv?0vcwE(1m=^_Sx-j^>Wm>@jGby_$=q^zo}n{zJiNd*Alx-}Je?9?zH(=vr-r`!9u-Mp8k#KdFOIZ9A*prLA^kxIp*_zlG0 z7{Slyr-&XLkDWXkW>TWM4&w2NWq4p-L+6bp0+XA=a5~j&W}@-P3m1*j>1cbXrB2k|*#$CPVPua*1hg zx=WWyaLAj;qGpBC?{4k0wgbp(fa`39^a;Mfo_A8y;yteHo+uRfpz>scuglZU?5DqP#L;HJTvdcK^HR z{rI2EH{N!h{2ZFH3DNAmbGx31_*ik|9BXKeKr_UE`JX_Lv{V3gF` zn}m7y|0_=9-m$WMbsscNdxJ#^-N=E+4^dntl=O>JX0JniHkm^xnK2W8xQV!`U5Hu> zJ=-x5rS%AXI?LjXYFvd!s1dMBIJEhXy>}Hm773%d3rF8sMkK<*k>N}_p1D5nHJd8_ z?Ox-T`;GU@Nj^b8Da7=W{lo!R;Zph-JNx)O|8&{m134mHD_V>6wJKD13+2%neoTL|9OTtgqvxxk!< z$kn>G->)ffGD|=#+bS|>GnJ3xus=l#C4!dsEzK;X?`2=Jj`&yov53W#cCwy{PVgZh z2oS1GMj(hBzPR(f!vazr>$)It)}C;_0Yg`=0?>MXdMiNxqTmoEYZ@Rly`o;LBbKtK zVeM}*-t1cT0V18H5Cp9;7aS{h=XCMsA&))@Om7;ATWln1r?%?R~=J8IlxB-nO^gR zdz1OSqt;4&^=Nk@4Ea}1`SL=QJgG>!{gg>Zmm60fP|x6UBqH(6Gi;jiI)lBjK-*Oy zqn4-p?x;V!C;5hd;n)P6{ahsE%Dim);5irzGFsnZC!qZTk_#{;OuW?lZ`ArfN&Agu zY+@$?NB)+CYJY7()?w%pqO;N|3Ca=Ia8;uZ-7Tfd>>J$CM1O z5%)ivSzY;EY$=pAWROeQwE2cE8>V2TvjV$7{FB|Z`E}sOl7v+N#idJoXJr5E$Yy|r|O(y>X`Hwo}ObXdUutHhz zYE)7}&QdbcNH_9j;~%)(6i>a(5( zx?ZRjk79ru{bP-YBUxLkXKo8(bH4)Qn$k@(OW^bIi_A+b9%(n-ww|b2U{u*W;;lva zNNEveBd5(9(Evsd+g8zpeFdFi$mCecke2D>nO+XF=d#5xK(t}QjzJ$%R__z~~3va1zos*nRp#t#6`*&K~&sv-u= ze6kOAQ7##e$t}}qmMy?Ul2$ILCFpu2=%m2bnLgG;61DGIOO$>;UOuku#t1>il`EKV`b#ZzYnm^?87f#Dz=KYc80Fa z598tQ;d*lqMpLpK@*Z7fF#M1uDBogNO9D7QywDfAYrp4WqGrS&Q8a3bxsDuBe=d{o zcVAeUBfk+|f=*{12B40844eFsGwe_=gC-3vgp@Q02>M#yFXI|IJyEqt?w#|3uxKwH zky-{MgzQHyV4IZyKNa(M4Zgm2R$XH@Mbx91$~pc4mufszlIFh;7Q{8xlXNs*)F1QP zR~p654B~}qD7yd zO0PYOb+ojWoi?XJM0-yd%T|V#wvt zL9NOlX(`aN_!C6mEz}ccG5-KDegn^%M-;1!vJf{v=;K37m8QgaI~ZD0OY!Fk7!t)$ zw6VQ1U+wb`3D3ys`SKTndfArnb9CS;oU~!>s>dWS((lPCVh{U$(Via#G6jsazwy22 z!E)H`ba=?KH{R8q3=Bhw+VW-0mqN}j*+;7J#C>f}%V&bGxrWftTHR&DsK`7hUR^aG z>@5tG@dEI8p(gau_Rc=nY);xdmBj%r1@v>?-At(AANJ9-RnfMOU?rv%;)RlsWB-PH z{;vj>GsBJANL4V|G6C57$A5s&I5(G5j5l28*SeLC&~W#z7^mlgbW5E$jx*(TMePyi z8g-E^1WSZC!1M&ANW!DL&z)f5{X?1pG}^M;lvcXk;I;gyy$SF9dPPd`Gx;^yL}oVO z0L*ak#5uQdQLI~bM^R%Z^BzJEG^F&(SA%l(D_B)Ww@^EA;W-|e+gNM&@3x;%gTkMT zF5Y5sT zXW$)#YfcMfNJ>nnLxs)}RP%;T0FK%*lxWqneHaf(cedR&s4}7719*DX@1!B(#&*|B z{X*)8ve8*L@JF%8j})L7#Z0__o!knT^&a_?c1mg3Bkb7E%m~JUia@*OTv>mmEx66j zfIUClQZs(rBiFd2@FJaqrJZB0lTiXCDU37X`KeFfqZeYx9AMYk^YUCx+#Fhw^-&UE zk@chWk3{$}Y)&di;87?Z%IlVHqp#r7tQ=Jcc23+3g{LSE8ew38ygxVDO%N-bmY+daXPG3e`r`A;ccjWxw-F98s>tW z5b6?T6om$nbkSdB{`Tdj_tutRwzIxY5g@R|q*{CSitHyK`1o^cE6?xbW0SSzwhQOL z*Q&#-;$_Z4@J!(2Hb1s+f^1>L0#kI?Thtg&QF3LZW+*}OR;y(gnG+q~0~w$if`*qs zh8vn6bRo9(bAHo)en{WXtPNor3NL}mDiM<=HXkZbDvFpm0nOi5&vm|J_5+A$S~K+} z0;wU6-z1|>Siv+gT*NBtXv=S{)cAb>f7bFDBV5!HSA>$MFM54tOXU1KEG2S~>$l&84Ox29Q{%g>B%11Xxd$>f4B zHA`DNn)SCrd^fgUz7rptTr6~m6>&6w+F7f6we!8Xq91ar;u#%&({cRbW)~+)E=%We zc&#y#zcL}{FDv^nF{%X{Sq3MY`+&MPE1saCPVa%*?0cNLGL$R%7+vGzTF;o3wahCz zC#ZZs?@;K7MTNobDM_F4D_kUodICc0espX6{oYX2RZLBtLfb%U%(`a(X)Frr@U&dY z{J`?RLW&KJQ)VXiJlLAcCqO~yG3`8TC^Ru!LV-d%7L6js)bVEjqwYM-2z^LHZDlX! zvNGwn(DW--4JXP!qOq6vu)*>fvA&HP(o}3jgY%GXqaHmPUfqL^^YhJ~m@vvMwPD(g z61``Tr3aE93KD4^$3jm{p!59)m;r>?^E#1vyYh=W&0(j%ffyj14p4Pr(krYGE7wJ{ zFS7O(_(AmcT5;`3|2vEJntfWPf_!5pKA=-4oe%rF#3=P-iC7B;vHzXqmYh{avDYkip&t9z-mZ{GSHI_olC-?uCQh0ZL%am;V1F?-l+sk&EmZ7ToEU1bHOWYo8`cR~R2lgXUxeb}2OM zWcEc*LvlVcn@g6YUh7U3In^2<;{~k29f()oxDyMHtK%ym52^4w9S@NkYcDUp{O=i$?FJ>iDG!N**5KI`*)onGr`%yuSb7DZzPr3^stwYcLaK&au_<(lFU z?dVAGPv}@9qAqu6Ktt)(Jtp?l$M-4>Jy_9b>-6z8=}co9q_{s8(m4_67NBHe%y-W1 z09W=ToqgRI1B>Sk%!8A$BiMg&ec1_Z_38*vA20`=$T$ zU=+{hlsda>Ru@Y)5z0Z%*~|c2JcTlEpu1t7pvf9xNtUn3+E)&ozIwnkTnIR>H<;E> zO#VfVccQBV3uX-_7lK#35aCksQJb53&iCMhNwfx~LJ12c4Nrr?9d{AIAr2n#$IFCg zT+1*fo5E&Jz7gnT>|`McAx%db%ZJ6$rN%Jw$cw9yBK_smAEdge$NiVrrZ<317J|5n z116-tKwWEnL=mg&{m_(kvma3^0&`lGUy2P=ilr>***v@F(4@i23^>#+zrqi*8Q4kF zcG*sF@~vmRPnA&_X8+K;>r+JWsmK*)H}<^wD01)CG@>lHI;A7*X|wJ2VFS%|vA$T? zNL=BZcx&lFylJ8z5Qcg8V^JvRGuNd> zX&&Ct6$&VIH_VnRcY)v9v*I{-&YbqDBC&iqS0y})If!u#o120b@hRQu`2L6iGt}FW z!ZM|b1w#Y95!1tul!j>zvY<_PIAx1Z#@7~=ul%lT4Lt)+CQFc|NqCx6yP0;kkV2fS zUl(<^M0^qyrVTPOL$-T8R8bs}?6TRjz;G05s9vn+t3Ae*PgC1(;41d|fDp+S`w1Db z54Qb_z5p}xjV;y$s*?h0o&TZadKrQaQkh(pR69o^DL}WEf?*Y<`2q3uZp@0yrTE8= zW}a2pkKn@-mM5Y}5_o-Ukki5dL+%!s9^DE$zna<)H9N{JsoUU!PTnlp)P0w1FoqH9 zs}GAnPBN-^`E4wYGNkhYcpC6lr?5c=(W*Y#HZCS` zl{_A>vTt@qb@Ex-LkTv1(RdjO0v8C2&SG%^kViQxV6G@qE*ToLT<1lKtOR6{{0gjJ852K38-lOgg2Vd%(KnoDI^gcKouhY|O3Us;WfVXqn({>M z%+No+8}egNZDody7Q}r-?$r2KF4iGYV|0lp^22beh~r-$KKHgiKU6CG+$+|3Y6iXC zX!T>Ggh#Djkfu_wi}Ae+n*Ulu>B{M{6|m_+Ftd$H`{?wwII5KOWAa@KzpQes4zx`& zx{soFgl@K-$WZt=CqA?~gAWMWP(GY1n8S;Yn(zcT@BnfcgOR-Kw^lkv*C( z(rrt>6nM;wktU@I)Aqr>I1Q(7^Ht4wvNO5*tz$jNy2ShMMk^w%q9FQS)Q~unm$Q;X zaiiX@ZuFsjmFkTb?ObwDY1KhmDCm8H&MrJtV3ZJ!KU*}rim-lB$_X!-iF6NoXP?dG z3O4sbW^TFBl7v{5W|sa|n1DG4^Yl z%KKb7<-fg&g7FZHV~*#66~at-77kJRiml5iMYD~Qi|6K#^foOF`@jd@&&=h@c53t#LEVCKeY`+5 z7zhrI%;%T2gFmr8@PSAj(UNAw-r?j!`TiTKxz<<#YB%53b)a~=`! zr~|^lVMLevB|xC3Zd3t*3IJLW^}=*jpYz9Wn9d47eN9bwIm`9mvR!uiV1EW3cBfen z6WJqi#8m>i1>MJ+Qgvpa#y&6rgbyo7oxGwhpb{+*p5rHf=eJ9YDsR`naZ?)%4xz}7 z9asFBU6@&-RUV)RQ!f6Ap{nZDfzL&a_$xv(0ReTFkm+|%6HQ<_I zwhdxtGNi&VfjtqOJUt&VnlrT4~d-i)K($nz4%)t6b53c zftNX8$|4apNxvPz9?1Vb!t?tf&$@dcsIZecCgEP;PaBQsiw*vD&>8nz0@ubc@?@Zz zrU>lQG-5wDrCg04^ZFH(szb|?-EwwgPlBU#t=9M>X@iYUBUky}Szd=>00a&+BRemL z>9awSjm;Oz=td^MWt_)PZIHBS)w*7PU1;hV4!lp%fRa_#NZc7DsRTOwY5H0m^`31a z_T7Z8zD|YF+ksk_WvI-6hK<1R`i#;Fp;|iU)!bz+ZrOtmE~tQ_O0pfUW64y1Tc-jM z`MuvbO7JzqX=&3v~7T>qwTcn~NB_n5(yY51D4C5n7d z&Rv|$`;MDR&}?pw`UgX;glOME%+c6uQmKv)K>^`LdOR2SrG8$S#$gj29&jsMk`J3q~4BPP>5`SW%bfOv!$qhVzKrrj+T1zI2PTK{BVwI5l?r36l zFzV*BOosFE3KG-A2G3i^mC`fOG;RgJxwD6(D47^XHOYJ7L0 zm7?_c$KqYb(VScZI4~Ty8pr4C_&CE^hR0ySvNhteTXGsFJk8KZpIAgIwfIEAzf~}2 z=7_nc(dZ_aW*T#t%{?s)XMAv{$~pgRXDE6eLwxYmV7cx*fA>*LDN~&H8z;ib8Tjw+ z-Jb(o?a^%-Amo)tchVbq@}6%APn(i0fk$LFZ}HDpBb+zj?(h(%q8s_P6y#l=| zS0(5On*{scSii^R^l#b#Uyfu5+a#R)Th}l>{Hfr5}uhcl%sLocOY3NQ}r^ zqke*vY$IUi=Ooi@KpoCINI47FXW)?quqi5-sXH?#7HE_w-1F>wMsWbW73_fGnlk!P zI$8_K(nxMDDd59R zwjarywIiYl*8RJSHBQ;w7KVcx`*XI?xg#~KBMKxE#HSsR<`ss*GeyJu41_j%ZtwPj zVE`z4^#-ET^?=88k!aw!DA2*-fe_(l$M4ZA{Zb9YwjuHf*gPLl{YCjR%GY>L-~EnE8yyV zGdoV3@+4Pd!6k8sKaMk-5^YXowm1uE)HJ76Vpp?>pS{6JT&!)!jitn3RigcyeN==I zLB8S1pDVI%;*)mg>n;~&_y?S5>8ytz^!zgc)b1d`amH@0S(cleYixp`iH0unMofuq zdhQ8rBDS^94T99U_I(x78?qKnJg)8KZWQ>S+I$CjVSmxeq=ei^O(R@w%>`R$2=Na39N<77f zT*r9lkqRfwC&KmRM4tL*Esc9IwrJ&o2o+Z1#W+&CW$~dq zsB)9vSoephX{%9F@OhTQ>nem^3WHrN3X&#~9&O*n%R%<|fqY_D^evI`J`wJOl=k9F`N^Q2Yk;U#bK!A>j)m)u zdwnsiP+Cl*+-cA@%LNRdYRu@jdoTbBYFE ze3FL1OJWilf3@VVoaDrxJjjNA2rw@0q`ps$8aoBlAa-R#3*_H3yTZZioBa_(D2-3^ zuY9_U!=)I3jZTN~Bj#X|+B-gc{S7@!v*UDQg=1Q0fFoH)s)Jh`BO{v(;$kn^;DuVx z2FIRPeVf_0En}-DCAQk68F=rTmk2k{uGohetdRrRuuHrIob*1I-$<@4K?~P|6PMFu@@#)l+NBlNLi+6_pVpcJ2W1ZD0!l+13xVmAi+ocBgq~J>X{}k! zgPF8dPn)p3b&=rqC28(2Lov*^j(dffTLZe1t!H}66Kz8ufD&sf?|huOfHr2`tO%#X zRs)|r{U{SJo?#SOF6MNzZemR>HDIe4^zE)s;LoNu1E!~a+!NTx<+DlJR>L|YTbr!K z4}qy=_tRi$za{UEbX^@ix+UC` zlRnwq%+MPSHsq3}8Q#j4(P}li_8wolcK%~tv(l6Ip-tLdJ#N9kv)X;y)2Cpx%`XFS z+X`Y@-B@j4=X=4-R;}=6RMF92u*H77G6G=%+691Or1QtJkSq^dPh>4zCB489*`#UG z^c2p(YQXXYyj`3Xu-5J>190r}kE+A>yH_W2)OlsI=sg7WG4{?~xt)MS)AJ5^r$A$g zF-u0CCKzMw9E*!_)!Fcvu4928@}jS(AWMyy-5E6QBmGeaYvOt*c>lDrpw3cGnO%n5 z1(T7_2F3U$f~|)19Xiynp&LlK&=y*Gc;bR)mQ12XCZE&MW`PbaxP)4Kd1o(*FmyO{ z*yJi}peL@!^fOy+s#g&~Z8(m^%GZyW^({4Rtwr|@nthzXG*@S+0ry&X?%$8N4)Qo% zCb73(Ogp0Si%KENfL9yx^*#eLZ$pG;e#EhsmEy0grd>thEjqUO6?3q1sXXSiFPJ# zaAT32@l-L{4*eTXbl%=vw^lhk5!_N5#xPBUVY38D!oXx0Zo%~YfKo;{UkW?u_g{V| zi_ym=IiD;=d+m~M&2Ys8+dRJE-Ugf-Z$#^6aL%=U<#%g4JgP*v(3IT%0gm}%t{u}W zVJHx?JO=7-vMqbEv zFj)Dkgel^Z<_Co@8=$nhlJ!Ohm45VwT|zZTS~=*K#f`LNk#3ho?#sI4S;}($rU`($ zzydOSoDIq=9OBAsyBqu2mH)_(AlK{lQ4%2U@b$8i2oHR}QcrFKgdhcLYiS^6Tt}#6*Q=G5@>Y5T#l|Bx1MdqNFi8b0&W8H zu_DCm=v~`Q5=zL($m;fHJcRd*B!3&BlWx+8c8P>|$%c5Dggno}-elAmsfM)ih`#$> z2sNG{y&~2`J>}%9B(35zycRm!h~O>m<9p491LL;J0Mo> zjKTL^?@5TABVQmOG*u35x4rS~DE5!J_bq(X`a-^1+jr;KRkJIXtw&%_2O(=H%0zxx zUXiSKKzM=bk4jm@V%Vbo^vomKbrugTU}IxaUiK{#nl4i!;Mj|dh?7XGuMG-=D|55i zsH=IhCoNSZW-8v8mAZpn{EHrQ7(HAl5Swq39*x}hd8D$C11{HV;jXXqzTah5j;;zV zEec+KKpdFmAA7cGR1MzOe|U8+JPr9ly!|C=VZzNpl@^|%7pw0wU!mIVVmm}Gxx)yb zOt~Yhxe#i((m&B%uOV}jz3JOF?iq(QyYaDb>KQ+{KR`^#+Ptd$^Riux(xVNEO8$p= zHS8{Smg+A5Qz^BPSU0s%R6PXrlW#X`KxFW=6pdU5HjYTK|6Qm$w#ie0v@r6uy=6BE z_vCa*S5%85R6Pj{!X4(|0H`quBNUl;*RN;9nl7wGcieltC<6jVs`*cx&O^N2glL+`Nl9sN3&?#T0P{Ka7WF2uno zDv|hMQ4Hr0bi<(^M|7ZX^!S@uXtgpT$9e6pgxa0^0BS5ZZ%5POYdIpb7DeOMKTDyY zDvoB%BPOJY`mVMjpn~IUn^u;qJ$0FnLz1^aoaZtlIY~(!hfvFn|2wnsw>YZ{pkQtO z?PL|%1$Rx@?S*0Pni9>zhUMn4chn6KRtnvJM4Y^W_tF1yBw1Vk za*dk;zmO6eoB(zL3yDwxUQle*&5slVjjnIphW#H;%{8bInxK1~kjGz-Apo+oQq4vE zTBdjpiU-tHOZWLb0a_a1AxjMo*@YH++1?(~MtDWdM{$$Q7?tMmE!HAm!G#uaMB&@B zf5ARoyy4coSaa;G7OTa2Rj=Q&63Uwvx<7@~@zs-!PN&AA8}`|AjkOSnqj_s?)vQ-| zBe*y`mthGN{>4pe}3 zkl3MF;*Pma0xTowtPsY+!Iuvyi%KCNy>G$fF9aZW>tVcIphh<=Z>6bUFja4DXG_KD z3KVRdd)dw|!$aQ6%Rh}k&Y{=2!Q(SiTNp+W8_lA&fHYxT#9ZQ15?)ClE;MoX47)X` zOT2#fwUm!`;fZBWCFb|KF8Em9&p;m+(k&8=!xN#7rC6d(x{qYSmC+yG_j1_~HC%I1 zf8|T<9Mbl?_@8-`p1Tu$F_?~-wC0Qj|1rRJ^77>$L|%+Z(Xr&8s~`D>U(}ruT=TNv z8N?R$X+mnBfa+rd+y7wW-(NjRZtwrO7>BZj+ek!q|t}=7A&k%ad zjD*N0eDzwzP>LaE9Af|IdyeAu5Dufp4e9-Fn1Kp!wpqqPg&x=2M=erO9`lZ zI>P`S7x2?V#S@4*{}6Njitb@&D!{zHP8r7>kz=Y>GX zPdXbdnFu*9)0jr^ugmLgi99P#OvDIREn)}spSGV>^~AjJlHkIi+;jZW&u-iI7^nMK z_*2a0nG0q8#Ob4vJD+!=!95pcn(U!zJPu@o8r&9moQw-Kf+KUQjHS(CWc z4=}ToZ=~%J6r#BD!hnAiMZ#5iD7g%h%kd+#;FHqx&8C7)!RU`Y^44gUVev9rA%Jp*yjnP*c z3gf;}CrWSGg@%tGZLmW1tn8DjkP`FY63PTI4U2JZExhKbN(;F$57TWDVke*M;pg7^iPlWj1T`pzBAhkbmO+A4|qAj!NI8+^od zZ@(3KEAh_?wow^VbO}4lJ6C)Xz#xg|p|LA8kZadj{=3Xt7&@tw;}lOn5PD?%(DP?L zb^C{$@2zWUo%cI~x`41DZqWTVjq9l3yvBzStXKi?SC{arKqBQ(Z|Dk0@@)~R=V$LPky^=4JZ9yz>k&&y{QrX+ zqaVa|Cg%G={x(f9U-L`_c3F?mT!4H(Zf;?nxR;^IM`Ur<0qZ?4G-4LuHW{o?;Qz45 zW{BdjW|?#$ehO*^sOW18>x z%0w>4lkAKf_fJ>`x?GBIew%pSD7rSD(eZ}%cSJF^xjiG+&7hQvps(&SJ|?frVS8x6c`KxI@I^ z9UV|7*Z+*$43jQ8I{?fxDlCbYjmUFztOsmA>_2#P zXq5Vjws003tbP5TfT-|d^Uv>h$2OF(Eq!x|{(4Eghv zJOl*?0=Tagp*L-dgXrVdkT8MsdynR?ep7IlUkI|AjO|;C9lJniIeEeQcsR226U*rjFqJ{EzygcJIgyY02=K`Se2d zko(K@uAlpIk`^yJI#;NcajrC}o^6r*>@qcH0)~s0)2&-7Zo7^9uoxv?SA$Y(b(3sB z+)l66!-#k~diY0n)uj!TS{n4pM#vdV>*Dyli_X2hXS-l!q=j#+OhYoW)vTS}_ajL# z0lhg`MR*COJSutO8Ds<7WHom=49K3PVN(Sf7EyY7ytJz9jh>`j0v0j@qRaTn~fm*7+`srK}i)ayRD{Lwa;wl z8Eg&YjU{fRrGo(|EUkZ(Jp?AdA*meln{l8pDmckgz|B3<%M;K#(5#^-%hH>1 zw)~l165X*_2vC#}JM?$xT>e34%6XpYtCB&m?Ts8O4wsIl z(F_s1N}*^KhIXXuGs4|3-ZJe(AN!r>oovm3M8EP+B(tHXQ{G6k?%cG~U=le?Xa%=& z1YVE8pBVeX-k^ov>pzN2N%tVClM?|OWP%;aeNf_+O?xHtKm0Va*z|7h=0cA19XHKc zYRxa}FUo)M;qzA@GMfKDr=Gy|pq*d?R*iCvD~a%aUQ*ORT5EO`YH-K|{LS$>taOwI zyM+6``p0K5!_#d^GIfbOjyxLHMPK8zU^)cJQjVCJ)a7>~+@V(?XaWe)C4f%F{Kih%W=TN7EmkI3xilPhcQV(1>PV%`Q?&P$faD~ z7@>{md^|S+(33Qg2C-VYtEO42LWI{{cHELhC7mucYmOC`)2kZt2-SdTNG(>Rrl(yI zNbEKJVtlGcLi72Bf2Cc4uiT2~J?m}w?l-wsF~P~6#T3v(r|{(Xo}E+*!Jl=hkZF*N zH^@pCgz-AQ;66J zGsk9+09uOo$3CYrbh4sJYiLTO8-qz)b&s-lR^iKQ5^E{^s9AiODE0YVY#Rry@Lh73 zMp`7E!AM<^bmMq;|AM7aKk1h7GT$=TXXHsDa54si0>j5fEuw~p4f2bG5)nbeHvz+h zk^n14C@>LIeh!e@+%(`^>Ds?6v-n(@@bzBv^sw;ourM(F7#+LTMW0MDV2*@WVuoa} zr7d?7z@H=#xOzWD#5Mg#UE)Xq@$Mp4tQw$2Gv>EuQ1IFsr5nYd?Mv_5u6jvR23Hw6 zA9C=GN(rH8ATdN3VKvM!Y0c5-*=r1Gq$)68UsAldinKnur~k={>TH?qG_eKF$v^at zU+OlCZ8`G@dU7aEhCic;8Es5fM*2G)taP(-L*lPR*9|*^C$ZKJaf+^1%?wNNKyt4j zN<0zRo2Aoter2aLaRPyQT}#S^x7W=nr<&|h*uw1}-lgN&aDD-uRD66+=w3}9d~uIk zZB6f)hsHy~o;3d-0MbA$zgFmAFdnfk4sp2jwD5A}7l$}pP3t5P*=KMm4yq%9EwnDF zTgv?_TDODsVyveL!_&d~my5AnTz;{J<|v2cYl-putCdf%#P~c8afm}4t~WlkNMh`6 zHP3js?(10*yto%vducSQP#j6CJV)GfVdUEfYwatafoxjQLTR-5&A(lO*#j;{J;Tnfm;P`#RYs$B};N=0`=E&N%M%>TasY5&2?GW{NSBI#iBTb z-^Z8@s@dCmyK`5Y*A5#5|IqS$Ky|8u#*j1(XjY_|?5;WY?S3>Fx6NBi*^^=^zY`7e zn`((}B&TA-(Dbo(duVla>g}lFrjR79DGUu*QZS60(jYN7#l4ReaNkK~#A=}V;E$aL zSs&XgrHSRSYA1#ic~;;!K@doR3k?#qMOSHY*oi&Z+BEgh=B$R;06i*AiYiGctgLE( zG#>cC*mD~S1N2OcdASd_zPSC7VGH^}3%6qC3tlDL<1Pq(#xS%%auNeL1~pz-kDX;B ztus&6?(pQ4TDYzfI9g;VvA_h1WW|txT9&WOg@X~kgfZ3*ndH9CbLxavz1TU1D# z$ciAy1X}xLDT$c8oz_3zdqisTNkpp-7HEnfYMRD?kgU64t1Vm0eL9S}^C-M@wKX-Q z+BqakIu%b&Zk`|Xk@5#;c|8*zZB^~o7AudZR@F=RO+R3Ls9E?SUZ8i}aJ>nrj&{bZ z;1t5k`b;>am$MQ>D95S6-ycCJHr&bJa|?nWF|ZN&j0!B3dd*Bh^FX{YkaoK%az1GJ zr3F}@ln-K~I!6rNe^|;G#z!u3C?6c4^Tr6iIBW?!J}A7rB)a^Xma@LNDdEM{JCV)i zV`upMMx~W)|KE9;^pUu;8VYl{W7)9i^4%L_K*%nbdA|s`YF8EM-`_EJHt)a2#fqa> zsNAxezZPU&TQGDu*77pSsGS+6|2D+B|3W?h!u!t1|2Idl-AoN)qE+jOsV{%p`PnEg zpfbFwv7|yVKmlPdpdPpj$7TWRA2r8!%lauyG&21n1QcUwXJ5%}_ozS}2qe{qUWr)x zMdh$*Xpx%Lw&0YLsuJn)1;=RuLrXkGF)~`xGJE(GEy-favO4#Tzxl^!3eTp)7@{*Y zbI}leuor+HQXpK_id>(>NL-2_R-W$O?A~=EI^`YX=ber}5ZXXX=-ybSRmqfn$OEEH_IF@C2P5$zA zVcDu(#|y7`#Nq0M+W%4NYBuFrO`V4tb&T(qcFOXETp{k$o~=ya3etLeIwG(*Q&`? zB~u)(XPNkdp29m#(7{3uvR+zWA>G3DMxXvG5U0a&xRms2OeyJAwEJ3o|0`R7M;y?U z_G^9oUcXA~d%c+6Un~7S8nbX~CI+uZ_&dUm90YPCx8J4Mvw$)Vc%81m+2!E;T!1AmW%GN#j_sp$OpW8po!7N467oA9S2mZ(RF3sCGXjLNg za0+vuYp4Mb^MtPbWmEe5dz5CV59pHSjU?y^b zAGp4f*Xx+kK7y^=TIE@fvAex!egmQSZ=I52JNfZ(e! zOi34mKKd%kx$}WRKJY!xkygVvT`UoFDdC*An5J2){_)4b3Ej!hH*81bi(jfodvSG>UGR-<{x2^L{t|s{P7v$fWrZ|qI1zrU# zdj3P0j7a+o>$wMBynX%Lh^})uSyMQg06?Pv>N@9$z9~Ga8}tlG48}u?oMlaZelmTN z4=VCjhOYh`me3u=UyPd32l%r*s?DS358Qe9N=&v7zCD}pEyqR`-{881IQ zMlwUa$C@ZBx+bA?9bD4y;di+2qs{l|6|&1b8o@TW_*}A>R#=B@J~ov74S#El=o8?lQz04@{vq*NtG5AidJ}r2rD~C@*X~IhD`Hl}ed;I}T zf@(#&Wyv$5NCJga0moOW^y?bu$DIp(l~urWYOK%88Y*0(eDJ=?p0_^!@Pk0j!A}mJ z;YpSiL_wfffQN4y7dH9{hXOauwy=e9PPN_W~ ztr=$1(*qR%5vZCVv64VYXrKa1nEsALd0(_v>fi8=)#oDau{2N!5|9KZ$}GCa9*t46 zVm7^E&Hb%m_o}9d{=Q|2S5+2>vZ4uL{eAyy;IJM(|J95WwqCW)dTuiJcoN?896|9S zOVb3yiaZlK3)kwY9n;iTt*h^8r3H~ z+CE)pP5I%LO4N;bMvtNhK_m&07I>cJLddOWt3Dxs_|n6eWSJO@QU9b zGDV#2vL@1;NCQ@61a!8~)eS-J)tw7esS}KccH1Uvhg&M1I5@WvUZgKFDAhDZ78t;) zGR-9K9QEpl=W3RR15zQzEx)J=TdcpmGIT=c#gIE~7)I75X~yXVx91f&K+IRNfi<_l z7sUM!zxhJ7+bgF*%Dzhrq>>g~R#gli*>yzt=WAo!S&Cl(94cStWGI7LRU7(sbmtivB3+F|iLpg|U9NobZ2i~P8tvA3pWjv|l;J71U;!Z!3a82( zEwCuZQz;?Zh5D_v_3eiaG`X)DR_}B%Fi?(^8yXkr1FWof!1~3UY8yJAk0e#fq(pN( z!D^Be5_Rj7(-p&}p}fxbR`b4;oPMJX2q(kGOgO){?x|VfplcWQpi}~k#tID23#5o1 zls=IVE5-c5`rwBTaBF{prdVe}2VKo~JCy>-%Be`%*-rYYn@wre#y?VMz147T-JrCz zP*(Yry+Zb&wMF9D8y@sE2$g+`Tu~F8^J2s)IU5WqIAiIj)xU7Y_f}7L5)^(qRxNEs z4q4k#^Zy)qIO080j$=7eWO;@n)UfwR6AaSOX@A&y_}e}?Q_nXv1q-9$h_EK8tg1>9 zAu-^Me!H74h~Tj*5hM4S4E8c3z%@B^E(3xkrsg_a0IW0NQjfn z!Kuj<9xv+cpRBi!eD{ZP|3+qWS&<|;L10K$)NXfww7fXcE{~b4cn60+TQ@(oWzv%^ zn&9bB@#&=U6e-XOp)!h6`+q%;yncLH8qS+-LX5P?V*1T`x9|P$Q@+59{UXg%B+rtZ zNU%J`puFEdY-FA$!mu%|T)M)XzFPeEc0VN0uEz6uNhMb6fm~KQ`|Fkw3rSkIk zk-eEQ3Xm096&S#%D1UM`8JG88)`uG;zkB44$YwFDzyMWLHAMmxx6ZVhLw&3isw z^RwDUA{|4bdBa;rc#-ZO>*({3&OLAx4)v69DltZ3S%%Um9&qgFSN?9Z{jH|uahkAY z3E}bIW7L-5Po~aW>kjDsMDFy6J0(j}8mkHf3nV4%PWg3G)|c*DSJA~ zNqxGEn3SSMq}aAR@UU|B^T@{qBE_qU#`6LpqTAz8BsF31qTM0Y_R;?qX6>z66Sq4s zB1Z}wNpm7e2_bt!pK`%zh%|0nHEn+G%qJS*sdbTl7H|?RkcuoYREPsj1>0%mZ29-R zw{xHitJ)x0mJtPxrFfF21P*r;Ix7WNLIvCIjJ5C28W4HQ5j0MwfuQiJ!lSisgspug z+veqssqd=7;A#h=W7yy#%FUCrUB0YgQua9D_02lI@k4QfB?ERvU5su7m!hui(AAe_ zfM0qEud0pDd;6a%??83bjv$p7MUYO}qvms?U+iR>(zXH`*LC9+l2G46@SO(lL)%@= zmdSQno;4+^Q*wzU1zJ)8!;{pTeW(5SS+R&-<;zHN!|ATe3ewByJG?rrhOP1-kMj7& zLPt9Zp<6P;6VA*$$$Qb~S-~l`RZ)P?mzng>Co4Z|XU;Xn;d+K!pk6)R71sn5u{AYq zZ{BXo&EL@suPe_X8P1vGQS-9FzyR0X4M_exFYuvi^ADm_o7c4M`DfFuAD)2baxY=I zVS#sE)TFP z(|&5YwP^&|h7wt)+v5ig$q$Ozd;6p%TGNH?|4zq=ILFLab|#rkjcliz3|~q7+8EFL z<&Zq#^ny&6&kwuc7{-rQDkP}1Vl=@ErsmE;LkV^mR5w6H?3V33Bc zk`^}e%eLR9-2)lhtgwtNsj0F+@-)RVth?@B%Zc^XLO8#CJ$-O^+4Or0n`!2=ehN5&7j`o9$lr?6j?`%=&DeIf>%4W$q-LSVVVR2N1)$KDL3H+X zXS>{iBjIi?kgfWvG#YSx*P3Q2a51{D_w!QP$-u6}&tk(K4A(I(`2wac5 zc&WQvw&d?4$}}8O8CDP zrTjiV-=eE;i}-qqLmc7|r8LUf>ehO1*zp8--WW#N8e|kmu`DN&GDVZ>=Zlt39C*BS z2C8*UFXJkjO@eL9hB`ItoPrkAVa#Z9C_%UwbW`$z{$7{I>+(!oEU_AlVK+iS` zWFj^WoK7@eA5dJ((2oF!9|Nf$=Yz-j6*GN3S8Rqpzl&}P%kwuC1hY)qbysHGQ3 zQKJ|^B@|Udwe%ZwRbm5u;yjxkjH5+bOkHdrZYtMp*-Melc`1eASf0>G0;sZe#pKhg zs}~yYwY9|7%r3TD7wkPW=;`{Q>$aF0SY#z2141O_z~Rj1-uqjgY;Z>gG%9-JlsRH* z1b7QdtF24ou@min!rS+9lt_z|$g(U;a8!uRZJKTXwGr!uriX24PS@{#-xApXN@69B z5&+LgG=-jhrDNyNEw+AZm(K519vY|&uNg{lSc(Xki1l`9{{GpLJLkMG;PbQ<6^~-Z z64f~GK%O(mcjxr9d7D5AgSl7I|92dA6{ft>-dCt%!p-*plt)Isnn8YOd-_IM544{e zTVktstnZC3)%DREe20!F>h*b7$Dt$lq$tZjSH}N0m9YKgk@lxXIi5*nJijg#2r>3E z1URm-TBR{1EYF0L*Aw$RR!F)`{cKdesf_1s(j}@dN_SFANKhG_UVK)aw2ho!PK^Ebsa^pVVOa{j!=f4J?`vn2 z4ZSpBOl=xs=tid)$MZwvd(mhgL+A;Ep%YC?InV0HxK68-a$Pe~uCuvF!!lAX4;_T_ z39Y9k;qsK98e@MsFY~_f?qw<`2h$H|{El<_LjPZKbo~nZ3;rMHYni=5`>-pn{<jAKX#WK-+TjEF2j1f1A(M|$NJ|z$#yCSZR{n)2^@-FKPzUi&2?tQ8{Qis?-S;#VYnOo1(B@= z0k2ESc1@BBuFG_tnCsm+vi7R_rKDt52PuzW6toN2h7mEVFgk)#H*TvahO7%TWt)xX^ic~g?;DrwMIU%RwP*xSwWTs z5CLKoABTIyiq zVD3cK+2T(31ycI1z@%#Vj!pyg;e(ew%{5>j1>jcQW!l>b!3EbrrX;Eyf-8yuY#qZU{d_sYCw3e0eFmWP5k(+2yMrjO@cv zBRHDWL`~D!u$OX;T&{$YD8;to=q&ocUlGgINS*||#tAAB{xa}UgEX{U)s}UZsnI+G zZ%4w2EGr5E&x^Fku^~?GZ%PZUaA*<0c8~4cu>J&O^m6fxo=Qk0sQ^`GNM@C3QlFiF zm-ZCRTCeSn7PFZ5(;@@`Bn6hFIF=e!jb>SrWl2I~NlG;G8~uu&b})D!E8xC6P)5UhAj)ki!IW=1TWLt&@e85<#2tx6 zbW#r}#c`Uz&=OBkjNJVDd)NO~S*TDLjJRRs6vF((;E3V1Y6UatFCgm*#h)_3=NsU? z3~<5#Z)AX%Gr&^}@NZ3#@x2E47Y6uS26(*x$=D{11L_QX<5@q zmJNv(f@6g9Z8H{k>FxDH4sJ>~Z8Xa|WtUrZ08Prv_7Bd_1^p$jl;hjXobIaKG(HJx zemd$~VTUNw(z6AVZT~#fN$vPqWDh<(BNGzMX&R-FXdr?0hGpDgYyH%ug$Z{yMkXz? zYiq9T0)?}{GC(6VUXy7mrA6EHvwgQ$gr4fEl~UBKcA4zyj##35f5cL<{CdY&pBtn6 zU+)O~L~vl&DYknu+aE~URp>C;9PSW?bNX_n3GRWw*UfEJrQ8B-dijjxyV+MNHY%g8 zCa*Ke11_5>wo3P%X?6=AQLt4sMiW_DqbMTe1fZTh&@=GB^L&S3JanDjYkRH!9qy@V zcn{SiD=;KMh#bxELWqRWNOxO=x|k~}VVbS$Fk$-3PeMwtG9o3QB!!}6l9VZd>e*=K z=y~T?XFy+X0}V_K(DwtcuxY|^bLqareUCm*zC_AKG+(@%&FQvb6JGzbdWYu7@CRMZ z<*2~HVlGhfvL(N3Jm~56gG}Jv`F6kG+NlFm&X#fg9Z~+TV;Pm#=`zhL`&HJigsX&% zUMb!6rLOOlYRA>mPw?!peHblA0lcZFNk|I+Kha>_Bp~^s>_6^1GqTRAAn8qzUBP^p zg#15RXp4D%QwjUGEvEgje(9#G6Vef0<7%zv^#)T6)&q&mpK$y`O3-)r*}5NZy>;>E zXv1^~G%IK_DXNktp|a_-?Tlp88Mf1P9&tYV9OQZT6mg_p-Swtd5EPPTNKW7s8g;h$ z5EGoXK}^dZVnP)*#n%>U!;oA(7~h8Q()S?$2M9g}!ABb4gHgU2!TTEEJz~VW8t`Q{ z1m_W)LvZxQ6k~wX2;QP_EN0o}bs!F|@xvJ##xgA=M%2Yf=`N3ZuxA`_56brVZ*|dJD+!C*KAXe}Q|~-}~_^=R9+FBJ3_0i*)HXfh>As1eQaPKwAQT zKm#@(HV40l>3ilt+AU6VW6~o$YFoE=+e;!o4zNPa=S5H7JjPEvsqh? z*x2cQGL)VotB7+B0y&b~?^61EJ(*r9r@+E;kSEWpfNrjAki2u$u5SO%N`Z{mOLAlz z)0GHeMLjv4Ky;?}iNSapa_1%i!T&}~LnQ3|R=J8F(?wV6$e zY#TfMw6FGNSY&8Ka?S1JNKR2DS|ce%LJt~FGq|jm*rwM1V?nzo>fm>%ix#>9kTqH2 zWQ9%o<&zhrHFtyq1r)84++QtB9|r&;E0EF>|7X64FYu={Z}azIQD9VpilXR!Nc+2!f({ znfPOF{YN%$xGw{e2m9dQH1;~Iuz}g{nx;VaZQ;6D*P^kUvv;;0Q!l_2_Xl7c+Tjj^ z5-q0ZZCj3ixb>S^k&UQmi69hNR8&qym&v-%gR_3n61m9dZQkA6_DmZa#>ZeW^LCXd zHK3@RKoCw9`21c^zEiz_Udzn|7JQIAkHDlj7!mbUf5EnV?iACe!%YxT2jilTk~AO! zMHVFuJoo z)A9#DK5{#j_oi5mWf)FmR1KiK_n0GrLOc8(?ft~pZM7cQw&k`(%|fYaasHs-9M(xu zno3bTAqk4=bmin`fAUJD=8O7`DWt25DweL-aP;7H+nTSPlbTG%_K8T73`Gg52t*R? zlUHMA$KJBpzAm@E@4ZmK?Go|Cksu_F7ipfA0LNRN{zQE2oEeR_vnoba{i;iJA~(n! z9>+aLp>qjOB+>8ignzTGs{B{0cmCH3KOe*0IQ02FUT`tA&8%~yY86DhhScZ2`=i>u&2ZJ+ zLzK-1{*F!i?ypX>euBJ5n9ybyr>)1^RZ_B?gsLeNMNl%w$=k<%v$9pk-&4?&gwIOI zbVU1IBTH=War5RKThm*WH05~Y;Nk>NXpE#N8sJf8bnbHjAFW!IK(-^g2jL#B~)i`4WnTz@Kl{6<@UX( z&<1LueOT=;hV;0hd;c`jKwLv1+2D|*B_>f{|~j@xc|fVXg$W&3#9Y(9zT>C zoZe>+ZttPg@ccY{?ncJACgwX>{|S2fT5|An6H;Fse!W3U#54f@u2A*6*?0Z>8kJnQ zW_H=muDa*9#q+{!XT=msl18ec%J70hp?=^uM_Hw!W%`xv<+ht^H2StmC^J+1xQG^s zjrR9ytUtc2km-l&&ZDLDOKUOhvF)gJB+pzION|(U7ifxSXqsRtnhf#w-f6VX)ol~Q z7O}^6_W1Ha9jmn|CZ(C8b7xU-d=<`%#nU%M+rwYmUTiR~+h?gY!|1Q{+cb(ms02q6 z3MWaua0X{-{a|xN=Hcep&gYPKr|4-e+sn z<&z86`h`9{!iY5->6ATrZndwJ1AP398UOA{zk5hJ>IR2HQV8&{V!H0Z_J+%JtZ6nK zwB^0@SxV3Cc$SJFX+j`4krOF`rHBxIN8fBMSbpcQZNkI%HkvX3tE-R+m8EEblr&mG zbrq&4kC2Lr`_VSAT|%FcuS2RbHk7Kcs;mHpR0&OEGqdK6u3Y{%3wnLu5~KdgjKR&O z6Smx{n{K@Qy9S}{FKE6_UrF9+&jQLgpaujOU-Rul?<&578Ig_9p7`CCd{>9RRvyKV zEhF$0BMKrTh%Cj0TqQlEv)%)+V|&iV?0>%k^*z1_kq{|{rdWy=Igtq2pr-#XkoTw9 zBL21I=QV3{t{)WQ_aud`K8DwgE4sSJySyHE4siQ#0r?f1R2lO{n`#-amvEU}ZkH2R z+Qmg2;&3g3CBA+vrJQM8g>&zUJT0ipnC$A6`tBS150Ih2CQ?viR zwNCjYL>Ghu^!-YNpF_`TCnCgTJc8dHMtF#%D!;qsDSB_5eCmk#HiQC0q)d0(eAI42tGR! z(e)W65)35)1!#Z>>-sFqAPt>s>Gn!*XP><-8OyU$0!5L$$nXp&QbMQ}IYXaHx!5Ag z**mUN|J}O++C~2o?p`m+IVE4dTj}jlr0hX{k5|eB1A#9u+h6I#{-M?`&B~Qj!(UQI z(j^tlODoVP#`qj{tCtvMdbt%K(bK<*_ASjfZs*sw4x@3>mxAsKj3%80p0FGs7r0g6 zR$RarR{M0!9Gs#6pYO&BUN!9V@BeesGxZ?d*%7kGhI9BR5>=k;*!!QacBMj3#Je$Z zQPAfQ-+h(DQ7P()n)a_6*L}gfzYbnYs=1w{B+@j+atghf=)v~`_ z;iYXY?~Ck`o96&0Ns>q^npXA8GZv|s%H&QYH7>KBz45c3^f~u7UW#W)mKI2YA$d+D zLKOv#4U4F6KQTT1*Oj)Kq1tq)m60fw6=;f7X_-QVbfxdn4lExpOJ`GZf|__RmFlPXyblj>*hk~!p;CTd+V`e1{;sUxX4BOL zSGqs0_x`B0Hp0JZ11+ZJ8Q-s1=3?+iEZlklv(5`5c8FG0r2Se4{NFr86yK{Jv!ww=3PCem9pgpVIbIwDl~j z`o$p**CXIVp|!R*t$Syq^Iap@Gm9j5@%kUf3ltq<&#bHqWY`GVOW+c3ZGY|E{24ta z!h`(c(=)y&1B$ALdkx(S*!R{l-f{SI4 zU-`Lna2kElguVZFcO9r#KC)E-CrKK|ks3h}oZ0h9O7ZIlwPJ2AXTkRm0Z_dYUWE{?XZ*!{q_`>WOo?cL%=8ayFtv_!DHN>u%=ecv|rg6_r)^8&@pe#Esn?;>CGIYT2&vvdV8(N_ZUiJl1-Y zRXyvQW6QVuB~oj`e9`jpzEn87z1rsNCkrhab`-W`}5m=OoM8Jss?GS zP&JI08_7XN)xvjzePM$Nxnm^g>I8e8yC9@&?*a=q;MFbN@^XQ<5AbJs)PjrM=%wze zQBrHOsiXbFKJVXo@=Tb3w!xOHBJb?x^|<}Otqua-@h%1UW-fi+#}_`EUmntqmH_8GK(_sB)R|#XIKfX@6wuFUz&Fc;|DPz;i%kS(>9!CN|bP zMi$d8_Awo*p5MMSG83zbD#6RF$_kXU_aUiMaT(#1CnYHT^YQ2$-`!&GUAx=&R4u6b zZdo~uV9E+mFzuIH;IUoGhEnN3AgKqE{vz9V784spsn+hN|L+$aPsXTcry?zYaoBe0 z-)nt>MHG5ST*VQG%MWngq4RmFIr98R=X12*U#$SwV;rt+fOObsKEinn=Wmk1^Ekxe za=^1`!D&A|Y|lqJo$gse{=$ZJ@^L>ACyzk?1<@gT>x9IqH{eqtlND7|kO)e2( z#$}5uuOG5cz;$)0_=yftrk5JfaxNA9NXFnsDGqS;Oh(=trKnto!{ZQ#YYFgLrM`B8 z+p_1^Sz%6si6%7p;O ztx76_BNRT_9QnOb{cgBS?I|lL(z_0{zt(H+2mX)oZoe6k5Ey}`Ihv&jCd326!bbwX z{>BtB&_0`eyKeUbb&w%J+&VC_Mgo?SB*1Sw|EFX4>Nm^7wKECfs+^cc)x~gMMI>O5 zy~483x7K|U)@5ecx+scF$f8CHk_HYR9{y+h+FOz`O4!ks7@yxdx}B$?n@L6rqU7SWIi@915ALN5yj6Fh-E zrn=Ss(CM!HrvA{ZV{7P0c;wrhzq_ryc-ia3Vn`0BphoWY9G+~b{8_6vh9a%r`H}Ihqsth7=os0k>F?zT?!vt zqLbQ+igVi^nYid}ceRKP*a%f204vFo%t&D!u$4cQ7%>gqZ2k5XlRa-&+g?AyoG)NO zUG8j`8w^ysNja|Ud~~KTSt&D=ZS-Ik%P3>T5QAZo5N$D_J57x4CW`TSLz zpK=yAgq-v?s`k>VT+h-A2fdC>krur z?Hv-sEj)^sSOTy#&jMcAF>cqV%MN5f8N4uff!?~OkjoWtPI~o9P0~r+TK)Nxj|N_( zVnzj;q)b>BDCun-hm)W-Vq&si_laI#uSefifs9d?E^shlJDTbqreH{Sw_X5@ZuO$h z0DPuj4r=*kAWftL`NLs;xvM#-z3|Q_?DI2vtfE=Ea%vz5W-uz>AKX4TmN)D9yre%E zspB;&1#b^27~bgMw7~6+#|8xc@JqiyjjQUHI_~-<@O**ZkQ2I<(wllmHPWpipLr`# zQocSAcJ%HR661ZUo_?uMl+DP-^XB$II$ftf74`Q=^!LB&^JS-=+F`%y?;nYhS{hl@ z<;@Ge-SX%o$ZZ!SkZYG3!FVg4aBy4?7(uNdPh6n?waE{o)svTC1`>nIFz!E)~6DUDdHY`##djh8?_I+ zBLha{REZ^6Mhl5ukQg&hbFY1T`5O)mC>J5X6~zz?#R@!4(li;;o{?swB4*fsk?)&r zE)+TDM-1hts)WY#3@gi$kkX=U`q{qQE4G8$mss5xquQHNejhFPYDD+m=zqBUlo-Ru z9*I&?Q_`YUC*E)G_tnURVMFU6a&_?TFViY335>vKn!4FFzVQdk-c5q@qUFLsYI`I& zjTKg!gX@S6ab{hFx*&Hf&LY%wBhm-m5v|742!+^#?3%A5I2uOuX#}5#;0@6TT?Y6W zWNfz~_<97Nh~UF@eAn2$)wb_H;p&6D?}^~;5j+9GQFYYD!a4JRz2f#add^x0`I9i7 z#B(^hz{RVS<5C8@fY;%YGUqIR@nq8C3Mr_^aEyW%`#e@i!Q@v&*B-R5=~Uz4j&IZt zqf!sDJEjEZU>`pS_sK4Geb$1)C@=U}O(LUl zKvWf4VEGD9z5nvab>Ee5jLGT*t5TTwfS34=y11K&?@L~ml0K# z;YmedNSUQ)9^d!+mcq8A>!ce^O~nqNiWB+-L?~W@tkk=ZzCf>_NBe)X=^6Xx#!IKH zn-p1l4OE#@XhIb=K$TW|ogCwH{J1Z-Pi%MJ$%Rg-Zpd2{5UM~ z@tYz6nw2Gymjv*6)4IL)W&B(YcXa&y_N1um65Ppa?Wdld{K0)Hym{6moC^R!4BX4= z>GlJ!d$1&DgT7!wzgE**bzeI(10G&vAe882li*4uVa@`hh3m~?w@7oa&hGK__}jS& zzXJ=z#oJj0ci~Av3_0*^ZLkBcv-h3wj{PVd`6xtDWm%;JO4LXmRd9ERnqIEA`xdtA zH6p1_Xk&^;l%_R`XJv-x2`Xu3pVq}&Q_Zl9jrQ%M&9_aR7l}FIcu4{j#j!x)Q09oN z96k*#X|w%{gUe>-PO2SxLRah_Kg)822pECq#3|c<`M7wPB{vinmYIXn=r^D(_WKT# z;;${5;Li;5+%AvXS+nOR~yvXF&z?N!i=^*Oxz8c z>bqib%bk^Gm4mzA4>1zeAFlIY)1e*xvHiUx=N{fOBhr+XXoXZ*Sz`dHpi{a!CJim= zQ~Q@s{q$DnjxZijv7i%0Q(9noffpHxlR4R`NN&}oN`6pq8@GN_|3lwf>SUnSUW*W> z`&K<@ z1upGII$0Tcug*^BfzMC97r@7vgFEi#TEW}SdA;5r>kml1;GKz)85}D@2O+dT7%!;G z{vJ6?a=L?cBJexEk@id1R?XG#%?_LwXyA)$^s@oM9Mle6Q1aD!zx@lj6}@7sb#sT; z^nM<;E-<3`4+ir6TJH#$R(n_f|K|x|-;dV&v6Vg!^YpW;BYHW9NaSoouSacU-1$;6 z+C>Xxhu!`_hm>XQu=;jQp&3b$X^|HwRNp>HpP1G61rH~_xZU=X?8 zN6_zqoG(K;eTw8Bt_Vh z5IIU)t*36kJmmXp`0>wGOr4~fP69CT$GEIt{+`Dh`zE-0KCBlu_ ztv48In$t==dB3suo-*#Iu}>A+@}!5M@*F2nDhVW&(CF9LDZH@tWCbf`>#bDAeOFfb zC77-+NcfMn_i_Q$2eiQ~ttLqSCK$}yRLr#H zImYkf5Ql4Vzep(M_i=~=PKO*E#d5FxpQ-on`2oNkwfLc@;v`81J@rHlCyKb%@9cdX z?~={mg~p{>VI+=%Gbt_GGr{J`bE}d!zxkNC|9E?N%NK6wKLw_AW({-LwB!QeKD%Y| zjpnJRYK5}--b_XF0^sy20?jcJAPI@5t27#LeAk+0g+4veb8MUeLAWjtR@;AXf5}~G z+$&X~fkBwN8aWJ2IpsW8w%SL^9Rz^d&As!9$usY1ep8`}Bc+7tmDiRXv!5*YJ#)O! z$Y^X>B{Ps^hT!LV^G^ z2{c)hG`U{Q*B|=3@Ait2FMYX`@g9u6k2Qbz|7gE6`ron3tlB*mAsTP+x!ei+lri_b zI4HUBHcsErMMbl8;4IAU&Cm6F`gqj5?2BsAllj|xz3cZb|DH~Un(LXoZ;5Xmafm}4 zt}k%LyC4p6h{H7oOX6J+?~gcK_0ZOU&q#@PQ5>!TNV!VaRUG0Fhd9I`4snP>9O4j% zvIlr=LHm!kAD)BOiBE;g3YAJZU#}HNyUyAf*K5Tg4y9k8(5yA%3b*4@IkYHiE2^}s zZ2aq#(f4((()wL#ZwB#w=Gua*)r>GckK%AGLrT2;afm}4;t+>8#QA~v{u+m?aNZd? zwN8n#oRrJlp7=V5Lmc7|hd9I`4snP>9O7`jKvKL5E(=)V{U3*`Xq_jO@cX1vK955j z;t+>8T-*E$&K;e_^picmN%Gbe>cH zgij$9xq&=oACUOhTw68hyE{zCgyNxbXi^3wE2t_jXtmy}<5;?SODgmSX%rp|2St_n z#ZKQTPuXX}hKryijo?Y11V9Z5&kW(%0&|qb{b^tD_j+%WCVF^}urX6vnsq9k>};U; z?H+eQq(#5g?e_R3zsuwHEuWO#_VL+tG8#X1X+m%c0bVIVBb=aJRnky#MS&;&vbVi; z>DD~`w4Ebsuc}{eKw$t;_LJzQ%~|{38}lEVOv7j!#atj4wUMD% zQq>qrP+1jqiTs*95wp(E*(*3+Y}>C@Bx))vyuu2aEU65QQq#eD#+iCI4#ZNFf9zXM z&;P(Z5yn(+nGi}*7={Y?Kec+jQhtB0$M5my=K`C@>-9`1=uG!7?q7#zZAg~%Ohz1z z@A+|vL+EllZ(nt;%DD^2BNIj-D5}g85(Oj$4f~j)yGj4IF0PCV_WSybIQ?v|$aIO3 zd5uv-K~N=>E`5-I%i8R?v-VH7+dgk-D#kKmcS?o;EU!@##lF#Rchdzs-b=wsG z5)IzR3b^me>VjBCgdH*1QMkp?sVdbvyAkYxtgr*GDk`98LE}}Kz4u@;k@s^QGtP)6 z7fFo(U$+EDrQ2JMSvC@K)blM7IckL#3*tx7G6U$PLXx&`+Q*6g;)^^8Y^m`+C`))L zX2~qcaaZD6d6T_$C>0E54=I*&_RbzAWsd`1pHuO;eSUAA;`ew_vUtdhV?~o4J0|^F zWo`QiB54juGtO*Rj?3TEo$YdifdOIOxAxbbM~esWgJgb`Uf7Hnx0qzd{*${W=2d_} zSRV;bp*2^wA9$UrCJ{gq1c}qgHy7=Ct={k16;Nk!n=wRra~a)o-F%tCzdJ4Aaolqp zUe@)%(PfJ%%`tlF{@s#KxtRlG#`;CJ(M$NgU% zPuo?$Nf_BNAUXyJlE^!|c|C4FaI1rWcf3mhK2(exlM$RwD2JoA8ID5_4Hh=;!$&hG zIf4-hUL-||(|hQOWUD_Dktsj&2l6WQ$azJf}*Gz^a_W(Kywp9Z5|X z9KSHDIwtPye|Ot4H{w-QI??BxgFuet_PdmV5UI{g;O{5j1{8k*hN`dLE#YFU>ey4Y z+5T=SR2J+hT8xDeiWpI48J<)WhLq6&+dw402t~QSR}Mb2A3&v+5QbRUU;4L+S@tYA`tPzY?NAQtI?0Fi&XCl<|W(2Q+ z;A;@6V>*IAg{KUyuqQU!_; zNKqg-hGlq`7C4kDbk_;bC~Ofm9cvm6UYWEWQoAtWiZAX&9&cAk$#PN*Nl6k(hyo|p zZ~XDPQ&Wy4p!4_hcHzV0;hq~owBNnjykz;K-{H50T8_cly%*n;(ZWb&O7WDlcXrnt zm%m{D201Q&*NM4aR8jhyWQlSj)N|~A`R&=J?r$V~~$F6uMp zFk8JwGYl)yyeO(H-0Gd`{{7W{Z1vWvRLB8;mJpnpOyO}Hp#L-4{EQ;ZCdTngf?G^Y z99Gcw&gH2s@TyfkaD6YI$34jJb-6QLTK*tO0|nd|dH_}59C?m5aa4QqnW|^%!UORx z5hDKqj$lYt6aX#mTl??Grrp@Y#z?lq%R1D0lz^5CaolqwI9Ea+Rp-pn$~R3NLryJe zYPzinew>SIDj4h_-j&f~&`iiMk2d_mc*tsZKCOM8ECBUOv zBN-#mGmj0?UgO!_p!{ z3A`A>iH*>+y32y=s#cCMl^?EAb3|=KFCDbU(*n<`q^wX1t9@EYtdhQbfB9&Gc;lcY zatv+86tpQ;Ox`y-{59Ks`*9}B`B=HI+=xh0 zg2oD@NK4ka_cZPFZ;xa}&)R}?|2#c4;^fd#g8?~X&CiVC{BRr?`uwjFa&}i+NbRew zK9}l162GS1mlH6PgQ9JE#)~hmI?H`Z7W|T4Q!bm>;??TtNOmH!V61 z#FUia{i`a5Zo_=)Am5{a<})QFGQFy8us@_C|I5JSQ`Y-S?Gk=>r4QQU2mNt~1=bhi zS@gM+kYF(vQllycQV`1T#QOgfgZBv-{6@!KWx&lVn$-yv?}|wVBq@r7s>l*e393R| z_;G!;Lep?r7ad>L@uV`MC`BSD<=E0<(bsb`u|lrMQH($p=ut_U5O`F`tzSFv>vZMt zB~XqHw@jY>NgBGo5PYNSlC ztj2LW<~%LlHp-U*rO7(_MgdLq&ZYG21f24LaMtu@T1A<~%l3*DlqrNeE zI?CXEtS}~m9-u4$%?GE7;vFl*EuF?Z6H%W)X$r+tfR%U@=1LFf_#wBF6|K zC(sOwuF(&E4WxdoC4$Y->tOYMD@Vg~+pWbq3ph!VDX6%TMUCryQ{L=Nmg*RKheCCv z>ndU1*D?4GZ;5vg?|Hxs^Vroc zIE64+-@c~QjkQh=$E43@cS#x!_3!KP`gcJAB&!h=MR455H|$p5tGF|jL^A$zRphhG zuU1_iXY5}_Sq}Uk?*B&l{63|0iW74gsbSE1;IBq@b@bZZDz(CUa1!oG39IxJNSRj| zg;Yst%UEXPl7sCk{BeoK>QW!s+@^CxXBx)Y=Br^GN(vSO7CjDEc6>_<@$tR3`eTP~ zeC%x+{CrYEc$H34dhk4q)mSJgJu-f|;Yyc}qpxVaaJ)cQM|R7PjwH^9766;W2`dCp z2$>@Rq0(HDd60MU>b`%Eo0tfP@^5o+`m>(?VGjR3y^M4gf15*P&f+pA%1$K~zPrU? zdh8X7c@8Vyu%t)}B*&8^NAfI%iZ|skH80|<`#b#iHt*J{BUa175Hu-@q$qMEC6EMx z7LlP#Iu)@+40O!iQLWw72cgVY+?HD(K>hAEB|0zOI_@{Y4ZOZASFY2S?U_*RP!sx* zQU4}D%5uycoT31q=VNO$)UoVvuc6DQz-}F0tVYm?y5Ope#%ctu5*%to-NPK5BJL{+ zpBpI^%%+i!FI#*%^3ZfBITtesR23&rvb(2rcz?=GXUwQZzRT^Gc9|A+))+_UYR$(j zIKb&oUJ8{5adxCV-F}+7#pPB9`8{4>&jQN01NL_s9NAyl0yUYduC}mrA?=qPFU*~o zkhwmx{e?yWm6lmbWdMz;FQ)IP9X9U-lj;CR4|Z|%se#ooaug-7DbUQ=Jl{mh9q1mYx>1|mgMiVRRgpj#^ivK*Bg?L^cZZ~RgFf1AcdVT7oV z1%^$e0BD8586jRTkW@zB;fZvnqu2Spe^vPds;$O`DkE|zL2zaQw>?X8yFs?E+#RPT zyscDCIEK-T;<#rV*vq)n`d(%E^}WLF=vzkPbn_Kj1Zh#u7hF5bs@~B$Z$%l>hB5YY zX*HP^Og-wwIPN^AfBVKbZy_#3*$&By`5)rv*s@CpltE>KtS zEJH9XL53(S78saiSWI_0F4VZYR)@2A%MXqe7={)Eo*)R347u`VG3d0r9CWYg{l4)* zYS<&x4_nZ!79cR9DsierQh8q=`{ADLZb;(Fg-GHQ$KdJX zhTiLp(h(M=(JD;=Mb=0$?g*=FV8?aRj%tZlw)~>4>t2Ut=v#Xq>Rms~W?Xn$BC4uP za-_@)ih5DQetg9J-_%^aup(@RYLKGk-s>1~X6wiURU#Uc0iNYKf+ti$B2a^}Kkf<^ z1JW?!Ls3JgIUd{J?fq8Iw}FCFrBL>d6orc$wv5zhJ+d)*D_uF}NR=AhWFjGX9%mY=2ulzdvq>ZoJ>F7I|LH)lUhsQi8{SdX3Wc zCt5!vynJHhd~n~#`W(Wy26*i#+h>%b`F|Vb^V*nt{BcA0?`p?L)ysN4!vDX7p?l@8 z@NO1|{}!O@2d_zIlJeuVF#UhIfj7k=4p$D)eR@ue*Hl25brtUTW18c^`bTPazr`S|gRBq?&vBe4 zbEqq-nJJMefY~&|aq`0HTX)uh=bK~kwmuX`sw_*ej7n%rrY)B9YfjH-j%i}|c9HQ* z4Y=}4TCX?C$RW%dQ5$T|a&)hDu=&CVu%}%#O$jnXa3bK8=G%wfb$WI65Kmr4wJw?m z4>*=*-P^BeTX@RZ1!uzN^*bqrrdc3Mv?8%iMJ5hS`|5#am42z%^g3JTm)c^qsP`Xo zy!rR35AMGJSNhDbD_tNZNh1gnXe2m%c=(^~Yi~&^Y0Qy^F+RuFeYRumTj$(g*DLgu z8_un!Ov;L;Fd{1u#oTJ%oPWnA|Ic*_?{mIXJ~*AKr|=-PJ*F}*Asm>IJIyS_8fOfG z*F+Q+s)0Z=0>OtMIBFEr4Z%?(sx}DT)L@WM;}ld6h*|~IF-2Bv)il6S#<+@sAeB)# z7Ee0%=Qrx~$z!cTsagS13#ij+j&XJeZs3*t92#MDskKymQpFTB{dUgp)KS>ZU&HSWl*Z`#TTkM=pMI7b%*cNlhXo zz<=`1Ub}Vqw<#?R^c7bMdPj-(E@k~&m9n0#Own%kOC6?h?cZKEDx%el#L}#w2pp?$ z3~Dt~3p)pvJI2ia;H6h876xtzJ$=rhdEV*r6)z={ad|H>i$DaZOp{xaaq@-oxK)jbEvO<;pp&KL0S6 z7j$!FgW|EJ9$wdY`s3!FsrE}W;0u<7$D>ViJ01;6QNX=N%Z;{P*Bivz4@U2c7ST(N ze|A4zzQL<-%OcE}xmP^wtqPQE$qRaW6e;^#dzFQ!K!b{nqudK23;eWh7(NSm|Eccb z`cuTyHT?fDXaj*LAs5rZDTF3;aC)Vnh_>_pst9BQMidGe znU(-aQldtv8-E%0$wxx<Qcea#Kh@jP7{ zkcBLN_}xQ@{0hlVA9HxJfSYEh(&Bf0$Tk?X8-CY8FQB6-ct;1R-w*@AR!<89_{~G;WRxv*IakzfvSrmS$du{i_m8Ki*Y0|%j<9s~TE5z8|IQ+MuLX7k>R{lB8Z^zaj zPh6t?1(s`6KKj4-_(jK;#`Sh_h(jFW5QjL#;aZ2{X78l{)6Tw<+wM^de4a|Gui!4)c;NN>26^(l3i$22I(Y^0)S!iDCvTuYPn1TnB2xRgLz&t(yT)O7-AsrO%a5fAO<`$G;CcSzR_$Ny(DJK9 z7+43r?vi6rgUlFfoKwmckGRA=IwHb;8+=)Qmm_V-s8^c*P&;(LEpniv0+N?_hNCrA zp1Jgeqra}MUJmZ7)#>0A!jrX)278Yq^W=el+pfTdeWf{$`agTe9p_ZhOmZDKs`TDF zzFz3%k^s_=UW~8o;{v(lOme`fARsCrC@Lx-NLQ4iVgW_E1qB5ZJ`n{hNKsJiSdi}* z^7ihs$tJl%QQ!QtnV0vr&d$!x&dv}t&4?mFvSL_Z$XEQqUv-jkC47?cNj zw*J=UozGWC2&z+XOOy=ECQ1+~jiynrJ{6Oq7jZnJ>@#~hJbfYRHB^~bM2_SMK~Tc3 zp{9La8#7xz&nWvpt%^Gx65oKb;c_m^Fjt&Ufd1N`GAVa_Fl%=i4Y|2xMQRR7{c}A% ztUqXpe8=crFhei4oUZhIT>t-^C3I{l41;+I!5>7fWt;W#AJWSgbe8vVQYZ(6uo#)E z@QNp)KhMx{JJOz{7&II{0MX|(lN@;tR>kx;n!lv~@todo_v(M#tWUh)Hyv%~dW|1=Lb2K=Mpp<>e8iDH(Ab0Cg78O3cjhQ`Rh!GE;> zV!=PPe~Sy3pAO~w-|8LLUH1g;rGhEW#-=sGkFye@^Xu+9K3QKsrt2LX%keSH7v=lV z3(I7Tq?Lxy-}lJ>&m#4U^3e`(eC-wrsNwt~&W7a6UmEj;-3 zL@3jrF@*`>0k2G=Mzf+OiUiL(lq{f(@8j|0boZ!v)>nV|q|1SEVY|no!qKL|bYIg@ z9QPiIqtE49(Z9n1&Kb`a8IvBl>y_1`qHeNiLEtn%@;pVd=qBsLu;8x;ds;A}_}3X5 z*MFG2cOBfw3n6L|zvOf~yec7Uq6{ce(zq}G9z2aLv%5UxWiR_I5mU6J1k>q^*H6wk z)A=#zqilG%%FF5Yd!V~kj&gu(r@woiANcxsB(} z?%SHh*vFyk70xqkYvg${^1Mx)e4|Z_|BDJ`khB42KAz5~^6upW4MgY>abEar)E$_z zyyF&-*WarGZ$FP8_#7VD2fP!&ky$f;EVp@4V!YNnIYs^w zQn{bIBMp_qR30@TguNXtEg-Q&GF{X$mzpmeARPVoR@P>2H#nF@ZC&vqsPkl6( zCf0hW&m`nFNoalBgNI2hL|y%*&flemT@I?7>MO6i+$&xB@QJ{lM$U zaY;`1AfN#+a4Vou)1h@Q@2i*w)x=BnL+E3=Jk~@XA1EHmy1X;3f3RnsUlmM;pR|Ph zf0G^$1N<3G-_)Bk>d)X0a96P5kJJmc`}E}C^J$sEv>_2%PAoQYKBM_-OP^cTrgFIO zk}oDZ{SK1m?;Vu9rm)z8c08^Gv+28xVdbigd0|roA_|^JG6c&DG$9Zy#}Ygdb|ks) zjbItAQgKCmpHaKjt_BzHhpvi;7Zjnp$JGUWQgHOkb-5(j1%?D910U)s_j9B&XFLf1ZQkPWSJ%e90Lu5x1@R(p);rklFNehAsWwwmHqC z&Tvgp6&`33si-VE!&4BkFA=kIDJb%{3`>o54fb8?q(3hdlY4ppdb3x;Od(jllC`uITT5fjAQOs;4wh&Pac zWHw#QSeCZF)1VPIhcgXiAs~52kAO-DsQo0b*E7*q*h9aqV~rurUQ11bbn2NEn(jfS z(#g1ea{if7_NLb+Y}|)soFvIp6hqQ1L2xw72q@!R-7s<$3X1qEV?yFLqI*ANA2adc zWN3jC1cDF+9?*5FZ<_mizx@@U)?u@wWP=jx`=aI#-;ejZSnnN6yS7A%mWQ`Ax|HGk zbnCjCM&2CGUPFnP3dR6bS-3D&X8d<*V+5Yp;qJgt%nL2@!F@G3>` zt^2Y1W`%>PB$Dx_7-O*M8jba)BEGk&nE7nEK^X8BQ@pgDXuWsLLzBLpRV$pf3pqn( z7>6y_2h@PR9`%C^HD&1-ZEE=LAjz6|s>w^2ze)`+Q_Xg;11O%V0I6+y%nEH2uV?Z&v#pJ zy2KRg+55J%n!h7@h#i?=X+=~;0x$sGGu~7aH&M%4%RN4XqgvL-=k3qUxiVQrS)dqN zpjlN2E5JSmS3m{p*~U-r`l>dp{F;cBCrN<=ip;T+EZ&{&x3)avNq`>f2kMkoUoUKx zuAhfyQ7`G^d*|R_`e@%^T19{VkJiBqDs&7!IIc77zw||ar+%F4FLErqiq=bCy!yra zM`7>6>jI(2FeF9NEJXr|5f)_;?Zjd3p;A1rs3 z`nB9O9w%emjeaa$MM-7rcPmzQn{qDd@q)rgG^YYZqGSP;^XR1!zjujt zc+QAC!6+KdFhD~O&+o&e;U(3uHYTNvF)Ta|%ZVg-tBj^Fsz{3>rxnDst~GJzlhpdP z35m#zj&*-SKs2~Gjim|EY?@7VtSPTnZK`F!D>joNRaPW8S!D!;p(qJf7FB1Li@}77 zTICdMmFrsfwk}&neIR;#P?aN9O6F;nrZ_Y{Xj0sYv4+;#_dK!sy++vUCx8(MN!B!m zBEqhpluIZo{Wr39sMqdLl?U**U3gxj6_FKrl|i?l@kXF6D6X-!(*t#19@+=?NECjT{Zohep+?vwqQC=uiWfb!6E2u z4z2Tx$Y?|OK;QMWLq={Sg2PSjT0MoTm_vF2BkP9t!PY6k^i>^Sh*5FCVvZq0It}WS zbn7iRa8K!*^Dj3Azhw3Lf22o$Z*)(vLeK(cvd%1kj;s3aZp|IRo;|Qvub*C#BxIJr zdfkeI-G=pn{SNB^`x(}w9cD(r{)6>^{Q{K=ZzH!{UZz9)Ls(%BX(xmPWW0W>7TSI| zPOl>6L3lqcv^-eO8U2HgGt43FUTcnAJ}ei~F{D$N52RB_kGOnMdV=E*#~Y3>9M>dd zuEKecPp3NmPK8kVd(Rx2cGnAj!VDcIu2 z#9%u0>)`XXdPjV!n^vXk_#JwO*4G2#eWla=k*&IDtUpg}8(QDS7`of18=hv26X zaiSiA=OLzlZzBxo1?1SHyG|E(tlmS{+Bu&5F#*oICRVc3g~z^l1Fn%%Es@qp5fG9@ z@w7k)ity~8_y7ItGD~mFx?J3QbnzO{rXeW~Dj~cu8L3|)l8*(!6XUFh3G==s#{b5) zDLUYt@HDk{e&(rPerO3zqc4U_$k`0XI9yIY@JcS56S&k{K%TEhugux=4{k0CxlwVW z|K3!>@2^FVg__W`uvYg7tshtqXZf;-dkTW21d3C5P8NY>Xu@>sl6Hx3AsBOmXz2>1 z`&QN-w|uSDx`eleA}NaGNM2xBk>+?2Jt$qG@2ozu;EHHtbvEAdVvir;?(w#WyGKP9 zDUKx-g5}}v5#8v<8!o&BGJ3 zY!Uunt%!WES~2-1`W=2UQC7=BJuFOri;q;V4F+1zKQfibq>C z7NduOxM+QhOgJ<=1q$hfEJfjc3tkZwMr1UF7A2ORdG`3GUHQ7H@|YCD0_5O3F){iq zOOCP9noXtiz1h^k`plk$&uU-7k_y8yG)IdBLvsvG(rCw;%Y~-lq|(v)Sx&#?F3qA^ z1qz%fODZ5GN+eLLz;;4Vc6@DQu)F`R7UT$Ugiv167UAfL#pDTt^t6tiU+skA-(qb55Fz{fM-lkZVGqFDi)d$7z`U&1Te{Bcb$NYb zZD&wSK>(P}2Oa_xA=Al@Hmi-@TmJ{Po+!3+mC+n*H^IBa%JQ?V=f0;x&e#2}#sYW0&TYaW>a|tS`Pc zV{^SvqUTMsDn&{_q-07#^IrJ_F7N)e8NaE+%UeoTj26Lwu5bW?*`g>+ZpW6FvWr^*r#IgLs3zxU@rm)}wW zLtoG#&Ir9gXyXALn8K96eBabuTvjv8TJ~FQr@XCRG~E+P0A3YnR-z^L3adFgV)oJM zg)V+1#Yn?xY_xS9c;}Nj-e|UN0s~lvRshYDB5Lba%Mv+7OB!t*-M81Xb?<{?MMOLs zB}9rLfI=|}%PLEc5B$PXE4}+wrmy5{^j&f>^GPn@^M89}fdUFUCighGqArx&XGWLY zWtCJoi4bX(VkVAyp`Nd&w;Z$_7&$eV{sxO^99raPeamycWvFET4Z;t+h|Z>>?hUOD zcKdOwb;BoP9~=hVv0+wYMHG1;NSw@(a&RNy^a8~nb{T4325N8LmBZgHN8OvN9=wu``}_ZGn|!Y(GuLDyC0ZXCTGQq%vW74P%iyYXUcCiHVENHAVP~N%WCOVdsv6%Q2wnLasSDQ z0u6Xcq*Q`iwA1zYtqB4!;8G#dhVmurq3<;Te66< zrc8>OCUF#@kktI6gM`k{rCDN`rxuhk$(rLo++ow-P#=G!pbRzJK{A3v_NaL;5d)kF zCzd9o-i-Uj(Er?JDP6p@@+sI}PqmKP<~VoHmgw3wQRY+`C<4#~DNKmR^zBsZ;q0ep z&$$TCpBG>}DLP#NM{%Uc5;Q?Fq{0igjQVlZAN}@MKu@UCis+U;?K-=$|E*@x-ow3* zJ}*~9t>fP@G-7CeIEB_!>#;63bE{v8dhHO5>widk~JQp7ZTR!+B8uKh~S zec5pyaxo%B$TCUE0#BfaTn>c$JBsXEVwN>$U1RXU&(S$wq3f0?=i8^JJ@oWG1P?Fr z0juTc`pl%yqw?{9gGY*FM2%L%A}iIvX8oYG-tOoBY?}rr{DFw;yh<|~kOY;X7`jH& zGIQS?cyBuN;kHB94s?WhBU}-(QmB^}_0*GsY+Ci59&|W&93jJwNEZ z==FV9ujjpWLi^-sV#)Hy!O_I%_~z}8 zfq&fkX*OGJ%39qCo@salV?35-1ChcM&=Yu_erYVYYv=8)8_sw*6?z71jucl?+<^ZM zIVOaV;{xkD2Nyiknu1Xl4%7}OM@AGKiVH~Y+#H+7J5+Mzf~l*|ogO=`s(C`fjn&Wu zW2}w-HozD+0}Lnv7{~7h7+}El;tvM@F~Fc70}L?sWB-Nx47f4Y31i(b)>Q-kIbfW3 z8eo6{r3LU3Q=)0HwG91e@1Ng{9(hqFRKUoR3}lKyBQG9~v#iC|THF2@x2ZimawH;O zip!RA9K5R1fh(7!q)Gmq=ChvNHO$=LIxW#S(W$s1m8F#Gfx7{>*t)M7lQHmnIG{NZ z2b3gbS|DgmqdE4}0C~>Tju*|)vrj^2WE0T2bct@U)wkuzS!z1G)qJLa5DG35%Y;gi z1Wf{sCJTb8&VHiBjxzOsOoLZbYm5s`NAwA%+v`TI0(=j`0&{35qW6W{B6n5mB6tFV z??X0BlMozy_5_3+**+ zHn>*oh`3g8fp}Un&ndh_y)^AH@bn4N485JOHwV+nx(kaB-wURa{{KYX<)Wa!HwXC+ z2i@wF?rbR_jaAmW344!Ig1`(>EgEztK7=CouX>k9%y^6YF{uBL7|& zn}?)mK~Gy>Q%~k}Uj_+nLAa@5VXq+sCCY?G(E-mLD}^NO_>8@Y{bO|JZzL3XiA_+iPR`2qNnNxG1Bmn zT5p}#GvnSihp^%UM-n6}(u~NFG))NT>dxyPH%4Jgc)_~i&2bq)38dL{{K= zN?=$HEuvm}Xc}I`Myoh}=8*#pqWc5mBt}$8k`wrF7jli=xV&Goeo2GxpRF*s1>6sHB0z^wGw_GFI2#c0plrjmvz^7*6y92su^CDfaK1GN$y8lC+FPvCto2M z$u0>gI^L+UyR6?oJ1B9$yr>@VD4CFfDDi+LY19MW=^{GavzT^U->teMFv({U99fu}EAH{a0UFmU-A5NJL^Q(Xz z??cvC-+6jX_AU9FH!%^!Fxr3ax%yeHQku5v(St9vsBewuF%X+g6L*s6*Ddf9A|7b9+>8nVd$Gl&tb1 zr-`V@Is_Y>`>^$P&ohUfFvE}vsS$jiGXm>yOW8o}A?5gUy}<7Esgcatob7GS7gmx66cxH!wo}m$Xy2(@jD1Oi4T=5s$kyB zzzt!H`k)c9F6cr{Rb(zhfXc{U^mGa$K-^r!p@h|Lh-|+6F}}kEyX=d3ehSk+DW$Y| z!BH}W;E<7^3Qp8x{g9;ixHL*1QxYP-2kAOqIxQ;w#tW84MSCCCdteFkD{8s%LcD&n z2OxOEwD{%)N(Zs{QE8v)ca`$J zr8}H!38W|DE%DvdI7g48Q>>=Dcrpjpa}S3^1Vh zaQOz8>-XrI|4))`?0U9p_urBITA#|4(tIxNdB%5^(0t02 za{E3jQ?&QeV#wEXEhQ_zxc!8F2d61oUz~n_fBB-72lILTDk+YVkaDipKISQNeC=#s zN*3Zpou(_zk^8}d8DA6y_ZAs$wL&jjgiRX5OOM(tiK*W20krDJBtgj{%DGV z2f5pKqCx05nc^H599-{n9-N*vuap$@_af)HpISoO&BP#7_j}*@Ph6z{ z+UPjX#xOWIeUkP1OhKOCC{SGed@Q|rxj6eVmY#Y-5gBj1`tw+NyuPNQtzYq06Sbc@ zRZ8-oB?g@q^<2SK%z7*-=7JAOSq_d>kMvS5FYy}nQ*r6RfRe#0Mi&@x6#y7+!VECL z00Rs#zyJdbFre6go4xc!4{ySBtHpG}x~k>QHnaA^ZXF)6TNwiIqQ(%iKoV7&efQAsV``Oy zr!lc^MOKQ^+`=Pp!n*iTd)H^bj_MbP5Hwj4IZoqAEuvqb*M~(qg_oFVI4hC97FIl%d0eKFE5hRiafCF-vM}h1gaQyJ1b&6|X?%|GDmP@lF&C)za(E?2g zT$sO&OV0-j*^i-}i`Ib)dk@<>C#tg+O_dpvR%DfAd7QHr)M?9UEU_losx_E<`JSI) zk;@{@15OrHl9V)>)3}z;@9h5UV1M}{+FgYC(!u%GDe1~+F{Rkf*Bh~lyA0XL0ZU|Q zK;dMO;gNla1+lqb?;RBMUZe;f}qar`fjMT-ow+vj~1`3oWuhmIzLj zDN&X>j3g&qEPEmawdQHjq^MF;x~V1NMz7+`<_1{e?rEclPK^Zfh9SQ}t~0R|XQ zd?--hRI%->`+lS6mq6XoBs~q$9RU##tR|8SDJhK>ZXk#J>`97s6REfcr??Yvi>bP; z&+fBZpWX_uR!2A|4IDm9bgKR=2T6#$q7kYruvDfGv`;vDsXTN77we94toV(v_p00W zP2Q|F`8awc5K3kxf~7QCBxUpvq)8fXT=|#P_%*G#rketY{EKM^4PxB0m9)i5A zpSjn^oba5IC0Qd0Gf_4E|&LU`k?-JzCi4eNCPm`!T)p}6BOUK-iN#wMcoX=`1l z8CeU1*D7ZHihD*;AFeC37% z&mLOeG+*g#!KAoZ*8-`D8S}oy#MzFI*nQuxA2tZ5xfHVN)p+_NKTAs=e*@4b#@8PsRs-(wx@QQBTDI$FUkv zfX`RojH^dq z+srdVZ)-6*Ka>i74Ur`v3$!Y-62;c3zG?37{q|RYp$|X_Pp@KqU)22J`|*Ak>%H5q z@tSyBoT8!GG{iRJx&2R$>0ddVbrhc0BoW5rUrCBQuM3D{sBLoDWk0>zBKWeJY?`DTu3$)u9-i!+Tt8560eP(F z$Jv2a!*#e`Fdf$2T{wE(zfxLHR z_0SR=C3G->=2u$KyK3othnsqut>dM4lkC61aI3K;gpfOfFhG z&8D%okDsf=j5R?~_=Ti!hE5Tz17th>nSQU+J$8WP_4{6(oI8EVyPkxN#q8)##r&>* z2?w}FF~92==X+*MM;8^6iuqn~BcG!6jyDQqLY(==+YhnKpZ_iPf(=T^Pu^%f9gOr} z{TOOTsD*k4IR2STlBb4mWb zQjSAoD3Vu5mgiOFn5|plOBq>dsIS>|rBumvapw0fe^zjwTctlhHH01ufDPz<>(WzGzVU|?Emu=5Px+GBOvVuf%ya0G!qDAz=;h-P&4?ow{TDr1r^39=mc+q#-8up}D zA8s90gC?jdP&vTMk_=D{+VT_iF^92?Sm{EC{%W>^7MP#bpLB0NyDAN`AM|cstQ0?E z=GuOK>GQT_cR|^AK-utdCV9c(^ko8<_W6PB%*9^WY1%*B(^htKW7}_l0S1(CCz@{b z!GB>q(e)zUaYx^ScyZ~bsNY@f_pjDGFy@sp|NhNTAb&q-tCe+VPu=Zs+dlxe?I$@$ zCdiiDey5U|mo0l-0moO?NjV;`-&gzn#h+~}4q$&-5tLF$ieD3)~7A=5_jk&oLh4 z4H(RHt6z3t0wm0&vBC6Z-SB8&V_d@)*~Tt<>kj8;yyG;2XK8|BXoe>Rk_l_t%%6kl zsl>=dEVBJo?eyxD1-0;Mn1EV|ltrLPoF>uW>#v9ZdUMTPNjOf5>Rm=#qW=$h%59dS z64_!~k1C2D)%>QqN?dR_fpL~8U zq`})Fs|hKBmH?qptSq)__i;*cjRC2Uj-gJuU8(W+r){ej&9i2`gwStTse1hx>X0D6_wyriY7>A>cjqR z&mDObdlH`-gPGypFRDdCVhP{J+y6gjTiV+^t$8w}mIV>1MP^8a7I~GXDSlN}g&*s8 zqRYZTIA#t_Q8*Sum^fxGEh<}Q%i8^07vF(~_;uF{6#cFmArb(PJVmOMH2>(JBUxo` zN{6hjeB4EDux;JanXR=2N)i_e4s^Z#fTJacml8D|ND?J0G<{i|WG*w|Tv@n?Eh}OQ zVU4+990Ri>DFB83&p_T65geuGvKUd<$ggDinN2U)Iy+bXqOO8RDN_q*QdJxz!F)Wm z{aaHzUNoaYoZO|nfb_-E@XNM--`tUP=bh1y^Eif-IF6GvLF4P&roUGBIB%mbnC`wU zzIl^i+GJxE|8eTkJMgj?Npm#E5iCWr6h(%e^AcNw^xqXDsBW_DTt5H)4j$O3&&?6} z8ZQwlU}=Grz`!k?mfXMo$3)b6Z&r-xpA(ROb7`^Pc0OBvkkUXTC)MBLhyA6;fts>Z+KD;N$^| zX{+tivdOLoUaW(c2eN6Fc1#cgE(8G>3?})Xcx)bfJiBKqln4|gEoZuHol|rqao4XW zwmq?JCmm00yOW7++nLzOOl;f6#J25B)Uk2$e(!hIxjB7N>wjOhs(0=E+t1Vd&D*=; z;zKBPi8snCP*#MPPjN+Td9+k{gm z5pOqTXhKM1=}uE@2lxIl;mU^sVq@bN1dHB4K3hkgC&DN;aM(`a(!20u0H9!q9^BYA zx2L`M%#`P2(E*b7ayKIs{8L?3VsV~)6yiEQA$RWi)OR{=$f}$;MCbsD^gh$XW6YM^ z9m=b&R1k=*Zm8DUY`p>2VCvNvgnNV47tPpHRMej@-Dp6|H2K6rv4oAyuQ}1pMqpGs zQO-OHbhMC1?Z%OKgwn~sP_6s8nfVre9K~O2c4xboy8bE!R!<6yJx1VYD^2%~FUsEA zs)xp-{q}3kHhh4mLso|zF6MeMZxK^1`EMM9flMVOT+Vi#O3enO`oGGQD$^(?(rsyv zUL$aelrDHanXNpr3*(dk8lLzGnD5=#M>_MYzSwt6`0a7{L4{XcX2mm@o0{EraPqs} z4xdoI&?1Ygx+9O`z9@o{%&z?)?$jF-rrg~Y8_DUc?$>=6G9UAZw8d&3bK*U>7YKIk z8$Ms6$NkAao1p>&>@5-s#>*!H>*U)#O`i9f@mUl78|;qlZ@p*n+9Db}qQ+XW+x1T~ z^satxDUyUcIE%`D%6XHVMtzGc9!)&k9Xj{D)+di^=-ltwNey|(+3nT12y$1tn|?JI zPc}rLa?p7L_`_;^qM#fjlP##B?Gf_fuUk7Lu}a|YB)|*jE))xNRe{{&HhlQZ?^spUo;$>qw; zI7h$*ch8{l6!Eu@V;KFH{q$ky_A%I4crOvn^}mzF|IQe5lfNl_R=!-?Vn^o8Uch|N z>`6WZXFoY`UL}1gqm$bese~$i$@@VyE zDVRLNaE}4mlQN{@6!B^%N|iqc09HTxhr_Eb&q>f2U48B-0FDBU^W%bOe)afg2I!o8 zl9-^F-yy=}9#O#Wh#&vdaqwdt|B8!)hZzR(3Vg9l%5TPC{E_eNJzXq=!JIiI9Ey^( z3@&(h9C4!fbG1^)?`-XdWJJ1TJi#~%qAUyeV2JqStF%y?7qn`~pvwT)a~(0V?TJ3Z zv^}_8q^ER|r$zy8qM{&Aq$P`)9~}oO73-vM4zsWnHKzpk;F%a7a3i`eZiVadg2mXH zY>5_?-YG=bqEX6$;S`gmYsA=VA+>2y$WWKsXGJahm_~!bLYYD;4B<9Q)u5;CH9LrY zukhjkdH$+kTJmvcTqzJX6fnw87vXhPh2iep-7LVdH<9B%k$;WByFs&x@Sh}hplf2` zQ-^2PM`vClJ@-V^|S6oisG z9r)1*>q8?VZ)l>RtR9I|_`M{JP>YFKS`xsNK?gM6(nkx{WH9oLtjLgxbzbDo=&rlS zI}^P7d*?ycrW}9;r9nw6kq;y2{j|bQD3M$hMOzo5lY;Ia7d)Wyf=q1inrS<0AZyoF z3kdrsT`S2OnLvwW0ifT|J3bjoNs>s8GEMs^1E%;!%zl10{*o_>q%~4;3{&MXUw_zu zp@;qivStQ{K&F{6r4VcK5S@DJ55#WoKY8kg?|(%mbwne~&0HeFlRRU%eWwuS{T)U+_yvD+RAWV}Z*=a8|*e~tX6mrZMF%`%0Z z`W}Y+5dMK4BGB71(SKwY!$$5wiBimvO`SH}JsgaP>(w4oeRkL1gJ#J)5D<%40o16S zKMJ~UVT@p&Vb;6SO14UD!>a?4F>mIRKyHBr;u7&3*_61GdC<|f0-jA&mp+L)JzQXO z%X+iuiRtmj&!Xyx%p}`sa2F^1s01V`xLz?onSvB0uKBxVq?>=cgAQfpC44pnbT2#zn>PDD4X8h-Tfh9$mpX7D?BfAQPd=3 zmy;kmKL9Y2IhWhk&x!1MM&FCU4N}vE>b7n4g#eE?bEL{*r7ZbB;tMIjM34~jRQw&) z<(B+c{dBU{-Bv_BRxN=)fG}SmV~UbdIyi!Q>g6i%`^XF>P#G(N7jt?Nq(DXG59}~P zFP4k;NAb&Ov)|1%(RJnf%q#}Y^7!tGP|j@0#$-=OQ)ZB}c^(^qvc`hC)w*!4OWKZ? zA9lkMO=D?0(PjttfX)t=LCU_emZG>Da8@wpc|T^uv@_v~%4Lq~4(ft*khNl&xPi$@&` z^5lTPZ(B>T_gi}(p`v{kNUG`i!Nr-lEty9&C{E}UhRI|^HJkXZsZ2=n~Rmn1ej6z0@H+fgU;GRlu$@DyY zOaFS6ed$Eu=!ZI{w89~+C>gt3WowuH>g&y;ifIA|*C&&8kNNx3_hXaRUb&e1Ia!8r z$Domle7?iz4g1Mc5xA=OXzsN5Os+H)!PXa>*z3*_dQVzKYVVCGY2MeD@W(9g4|i}y zhAWRi=ewj%;Pj6YZ<}I+#4M%~q3PW_ZB8T_KaO)Py!TVB;cgP)si!>)G@nYJcKUUaVVPJ67dYz?nrGVh8L}|qso7YQ?)MQ6b)1ik zIH{UWH(yROPM7Xj50`fRx=z30X=l5j9%sgzN^Yr>hefql{usjR^<4ouL%xdc0LuQ$xnpYpZ$@kO!viRplgGqJ!4 zKgLKs+sHHpz3=6py}j=H2)*?Br*TO(OiU}_e>&Q@mi6`T+3Qq9DO{4XYf0e4^8gWN zfZ{a;T?x_~d#l4#WdMDCWY_-9qIrw5L&hRj&*UE5A97xWJcaGz*=2t7s4OO2$Dhx?f25mNeblyJh6q%4fYU(S)q_ z&Kz`2sPgrm?@GQO3wIX4R@iK1tr$%cl~iSBJ?TZVlHH`XFy9gCJBS+jX`C^HH`eks z516JzqUXI@zs=j8R&&*pm?#g&yJxe5PDHHyK*7`s#!Vr;#MR^Lp8NNeW%UX5dPzC2 z8$T2LXK>M2ax@>@Aa2pC9Mr_;Z+(v>PtLI2=zY{=Pg;=nu{&mvpG2!SS)x}pXg(-G zJrO(WXm5Cs{s3sfb@1Wxy7ywB`>`)8Tt}TcoX#P{n46Bek}k0a;8XS11E-PdA^IU^ zZSz(44%P%x8lJ9yltTm+E|w_^Cd)PjsN)SasiMa;x8WCX*5UAOTYK40zLaG~nZ3u6 zu!DKoPu28Fp!nI%Fs0@wA#;svlfFKfnxva^!wFY2swI9K^ri*--+TohCh^XF^u5e# z3O+Kx+roF=hdbpsKI@*>`TEp^tEpL&cVTby4$?!0n3X4}T#2lRl|W1d04S2Iz#M;p z@QsbC4y_(FQ^kL6KvI0SPp4I|MpN0r6os%Mfkd@p3<|C=?bBlkhkczI^5@W7!r?a+ zm(lQ4z~m*dJV~x1Hs?f$G(IP`_bZrt)tR&?p@uwk@T9np4CEFAB;X?O_&}ot^&75p=d^q*{D)$tt`!Q@<3#Qo^5k zkx0Ycx9Alr7K(A~;dAh~iSgY%dm6=W03sQ(VZgdZU zV5dz#b1s&w(tX&K^4*E{xyUwKmJGgi{_W4c(x&}7E+Kf*`e+*2XoiH7_XfWg6bmI? zN;60Oi|*kE`!yBLmwN#q6;H%5t@^>Nu953t?C;8s)uiI-6Ni8P%81CksYSdg&_Mz0 zJOJC+ntg`i%ZC~>p*ODvIg4qGJ_9K(Nj|+m{*NvJCzR1c@PKKp76C`OBF%}JdGNc1 zt6(BAdev#uQa|LBCs&rP+#He~(d*Ec#ps=d$eyKF@va z-8(cmeP<|`6nc`usliB+(u-Bdyb5-A^qdj*E`ENl*87LEGt*r=A(qgVOQ`^`+#VZE zvGkU>Ugb`^c&EMT!&?e!4d`WdhRg)&swMNRm=z-A+Mtrx=DRID@g=Ond(K3ls=XsI zM{62SK4$lRk{^OccJNM&~ zkiDA1FhPH3uY=E|B(cvgb{Y#IE7fninelO2d>wxd;uVprS0pL#pMJFjPlP&5m;6sc zFFsgB|tC|ZuA5MkBY{~U)PQ|)5eMmUY z64DcQy7~%vKT=iU2tI)6iMszV5QY1btgfvgu8qDv{SRP$m}p9Mk_7G=Q?E?ClOAIy z_pi_B)c(^HZuPUjJKj#`M*)7&K3otvZy?q$sE7U(KkH{8AArOrn`Wj8wrfLL!gm8Nuzh$9oC5jV(~v#XnPZko_YbqkH^LBw7wCed*c^`Vz2(Tc z$zsw6v17BVIpcUkoSm9|C$MQ+vQZT>gwvcJ|NS{#O7=SuY-Zk+Pbt8H%X-KoRp?47UmITh}*QVzz_kOA;Ku_Xv{Kf8L03EE>JtQp=IFA-+{ zlrhdArnF1Fp4ot|zSDUGRUxh+9~vv~{r7Gk+IwS9e z0~jekp{uYm*3mzcqH_-A@fQe>Hf7HaD1w(34qGE zJYhz73VEFWcT?*lOVEahH>OAr*P8hD{%HZtUUX6PfCUmA;%h>|6J|J|fdb0@lvdz- zD0S!r%Iyv9#C0UVLOwPl7dPo(8JIMML?_StIcP3BMhxr2Uzk5 zH_xL4qvqPRIc10+8$sQ!ntrPDt%#!)zFy)oLkJlV$^~@s{bq%(A zyo4)oNG7<%ZJoM$wZlu3T1XK};y7CQ;O&3TQbEW#*O;;%uC&Bv_gro*&g$>oQcS{U zioyq=Z4s{&+58l2U{MG~ELprE222>tj#-E3nAM7ZciE;*YeE&I)j)`AAmXma!riL2sSenKi< z1>}2VlUjLeo_l%A)P$^wtMR6(;mUR@P#DZuy00oSVrIUk8lm*zsi49}7K934K?Na2 zCAF7Y#$yRRIDr@cqJ8jX@BSixeWAy`ZglYv=x+%n#)GDU#Rf1FmCB7oJYf-#?qxdH zUYPI5%q<(XIWAB0ZpTYU{Ah6uhE_y1Uy@h?^pbe^Jj)=4fD%FCk0xXLwB&ZF-Bv!$ zsN1dzq(hm1{GGp8zxc6h+0IEs5$%*36e&iKkvJYqHnKhzEOudXEswl^Ki~Ts+jrS1 zPyxRve#f7PL{jsw|C8hfJd#^_u(F@`3$>kmgaygO?*3$KHFA?+-@_N!s%(BfFXt!~ z_+Hvk!Eeii$6ou}Y^_HXkk#`6P3OX-5s?dCI7pwk`mIJ1OwfS%7|VOiDve9+he$Q%H@V!?Y+2ZJcj8al8*PmV9)~)7&1KeV}>^!I&Z~@ zi3+Vl@9M?LJ={xOCx)d_AAi2NhOu8zgVL8duaPbKa7b4qxccjnwYg!g!3{_z)cxh} zs0CMB=0_Lq&N!6ele3-A7Y8ovksU!rsJx0Y33AO|x)dH)1pl*ATAjN3 zr)KH$Cc<)1z5H;0xs+Q4F|wO<0F;;wle+M>eM5W(s@N2gMfIu977U6`qm+1ODB=)Y zmL&+>aEtA_y>4#VV1@dwjKx=cOZTOF;pyy@aio(5m%-+_i=RsRWxR*7CW$}}a8KW* zby#8L8l4O2Ri&7AAd?ImobeHMpPOxTIzT6C)aA?EXm)T2F}@L%_z_?TnLr{AG?{_u z#b)&yvPm~rT-n&AaD=QD^ZtvJQg4~)U=aw#!OpDv&{{n}b-Ft`%KwQm+W@o7YAc2I z>}y0D(RH1wc|

    &d^C0Hof;`EA2a?!G@=l>Bx~m)UXbGHhfHj8M%rGTX~-gDM(va zRQh$WW$x+^u!i1^1X_SvPX-VBxrFuqo8IDpoWZqOconE1FWKmmPEBj(|x&)=nEmIWV_hNOn8>{%D@ zdF_@iV@v?hpBVUstQ;&aA&F(2q~4~C4LuTGdShn7Dvw20@!$x~8lEb=HTo8UG!Ee&KT zs+=uTQ4FDGC;>hUt12#I(suY&bri<2npQH(q0+KEh`YJT?Xnt1v5J$@r zvkj-D$3N~@*)P6*F0KEQHJ~vU>IL#8aEef=fqhF)Ql1W*ehTV|r5xaQnqEJq;4bBR zg_l|hB*#}Qr5=9wa=(V1KwJo0Z?+wF`Ke4>Xq#Zg*uJTFP$Q1L|eVr%JfsKzJ zjEwHS-F?1K>W{g70*Zv%%#BsbQha{mLZp$)Vs)#HvrL_>%lRDR?x?1b6ojf|gEZjs ziI4>p!~~q=N>rI`ru$51l&`;M?R`FsVqSLnmX!VkVtYy!51)Y!U0VhG)RwJ=Fyjrq zR)ICjhtKPNe}Q;pmf3rdB0C8!c5f|i#1ueU#uWfGoR5_o>&4yGT@XchUog}P* z>!L<+((&2V3>u zZgIoE{cG0ZIE~K$4|)s1;Gtg__XUp>bG5tNT&D@R?$wX=7aeB}*O>WPE^=$OaaD9w zTzJOw_$^M(+Dp`}T6bQ-a@7i5Yl(Skn#v(~OeGKKT9_kdtl^lOqF#~0d*+JM13hK| zOv$Lm-_5HP?%o#a+Yy|9{}gf0P?W6is`G}X;Hn%#roY{Q`sP>II&N#$danEqFc~c~ z-ql)Ay4Rdo88em3SCQE^%%6Uo$DcRmNHuH#o{oJkBu(0l@FGzubVw*J>$N1a9@gd$ zf9_W7CsRaqziyk_H zDMF2`uRG1lCenQHz@M@+yEu_@rtn$YY^6P-mflj~Zp!WNud|gRsiNRe(XlHR4|HRY z9*7^$c%T(}-qQ9%0}cHt6wfY@4m#jTEb(;VZD;<19dujvtXRhv{A-xykB5mSsg0CV zjgEBNDN-Y->an&LJPVzgw-Ps(0xx4jA4Es2n7xfdM&}bsGpid|S?gunYSMLgaR*r@ zgH%`0Q*GtSf-(ODCMbuTVSWdx3kU=PwlViR zWRFfde&vgr7aCkjGp{`snP%PE!nx1#ScEm&V>)dt(1o3^@lQFC_!b#nIegq@zYi#8 z4WFNUd&U@=uRd~tB8ZI-5|x20Q7QjX!eOs^6zBI!FKl|zLJ4U9Xr5@wdoD_S`Y^Df z1^UTWCq|&AGk=sn0=}koESjg|U+4cx_etbl)tLC}g+WO+R z-}zk4XT(9y^S<25v|C4Iy|{HgRwTf+PFGxC^ym1}HxgRla4k)xM-8n2M-;lgJYI&}(L=F6E8v~NxcHV$l%3^~E%q19VP3_3Z=Vy2_C z!<}M@&G(UbWT;%;f&<-qf%^&6-ii9TC`qEokVACoIKs-&dj!G0Z{J394l6bsc2>pC zGKza8vVNRAn;^anp^tzpVURJw|k5T3dnE8I-3}B@sWX9;8uE#RM*yDE};J{Ae1F zBE&B2uM+D}k-4SUDb5W7yJ?q($#iOObR6#?;C`7t5i0nM{$T&Vhu4xX$FQ>ZUSZ=j zmqv^iu5e@_q*fv{qGWD3*i5jmr`-4MisuEt>D}>ly^;bxw|Ns}3&5airEqS$rq7bW z8b~nhYE}O*zg6&nHywvIm4r6kw14XN{Jrlyzy^)_qUCMoGowdB=_M)i$~L~5m>Np5 zM=wn_QGZ9q1S&_&sg13nkbqFY@#?0T(!BLYsf1OPu8?4jP^+x}<QAh#r!r;Qp77vx!OiA4DuUpEz3XzWG;<@Aw1Zo)oTJaHKjwa(vxthb zX4D3on1Aadp{n5G4P(GzJ(-vO*tV$*jRQ?P-1S03NstkvFioTml=oy+aRCYSB%F!6e#!*YS&^8MfA&t1O~ z_~hd4Rc1NsyOY{77QkwN!_9axT&;k*(%Zwo3G8kb|3-K z!rEV17{(k}0c(r=ifV%@bkD>*CD~~d`Ef(4GWnjrb^b0_U6I@tpZoIGOe;wxiiBrg z;9KH&O2XYx)Yt{s{584}73{p5vH%Br!rhjI7gSnUE~1@)8i*VYK+NK%7t^SuJz zsBNj>N}Mh@^cr;%fQ|5E9WQ&Vm4E%GI;SUl3!%iDE=Hggo+#`IcKR8qp)Jxl+`nqBv|+tl;$R0AwM3UkbX_-!_TxzVh}=)r ziGDe%E_`F1dlSX!o@4x666vzAue$}Z7+KxX(-qRdSB^Ar(AJ%>mKA|9fwnIi&c!r+ zECW3yTGtD6R2`EG;>^jez-x>duKu$ZB6h9lLQJZDZ!AH9&^XtQ38SIfzSH``4#^-9!{7<%@ z>}$)`T7YXQ2@AM9Yo@R=fL`h65L49HaC*w2m)(gM;9r}o?UgRbMrViM`xU+R`=O)o z^_lYCYmg0|$E)-ziLrb2#?hqv_`+}_&K6}4VV^wi+jhf1$>ZC<8b!CPY;b9zAcP2; zNR#RTvxzG?7y86$`{|TUx>ITJ0ezFAY@$4Sb|c}BW|F-vq1r!$-#T>^7f* z4>SV4(o*inS&H1+O(xpiLTb27mWxk@?bB#-XlWM3cDOLgM)MW(UD&FJ*&Q(Yg7-Xu zJ>m?t6p{`TpR3-NJSCCGNqY7KS^JQM+)zN~ASvoluUsRf8mGXH|DZqvNyzAS((-dT z5LEoWh@f0*YUh#pE6SLd2qf5;;+1cLr1l`D44W-kCe45eV(u1ZknNw%tpEJ-;DStP z7$$9LB2xfHp?p884$7g#%IPLeS_Jv(k zAn~e8D&isNXGx`EIju^JO4nMe85gPIu@}komTj*iMeu*rkgx&u&(IH5vAhX-4bs*E z>p_E`sizwm!@P-wyxABQVIfdpaI5s88n;tvRHj+yF;ncj>v5RN!ynwT%mr?M)MH0`=!WD`E(U7i}+JcuZ6fQemlg zx`BIJWgRC_>NHEZ^2HOrt`PvXled#&B&PjG0G-*}x)|pV8j0)bwGJ+uLcz4mFd0jugZ-&zD)>x{#x z;7Q_|tbAaM0x>WN(Gh$S_n7~1R;+(mevZo|@6>aMJfD~Dlj7DG0>!=O_#7sE_Zwg& zx_pGoqov?7f580)HxSgS=jU1Kd8J#ie*83nmk!5~)?FQj>AE|0Aaqv_WK1F}M-(Zq z4KAviyh|U{;;-?y8{4i4U~A@#1?*$$X{d!3XnRdSKpb@^|Fd40Fp?{&YH^hhJ;ESy zfF|3{*gu!i`U##nmyK~8UrLMXY9%%B+rHBr0jZ04YQZhbZvV`shWR|Csg1VIq5UW> z-Cz_q0tw=@g7^lXM&M=9@%?V>Y_a!WO6IaTj)}-Vb|nruCtw~uod_;w8-XMfswn0r z+#?u92l1xBr!-5Vi9n)fJp9OgO`9){0s6J6`6MARb56Q60Y1Db_078=*b`@^ceP+M>dT|&6g|UKHayfz{|c&>J^e^ za(qU{`Oi-i_#{VljiT(hdFFl2QMpFv3AKJg&fb@vWVnJ)0dPd; z3hgV6I9w5B%ypmh^iJCf)j;_Pq_s8Q8NGE?n_Aay2UC$6U1_=4j`( zo*5E>46^Lwp(j01S6E9WVx8apTFZb9aqhP-Ilvwybj2}f;unCq;)cjh-gaH#yWiZ1 zFInuKw8URrthDEn3-;H}4l`}&TFY#>lz3e+1(t?Xp3z&l7i8Z7p1*t@VrTx@zwsD5 zAtrZuWZ5t)U=aznb}28Cwd7F-cYV3X(qC1!J-=$J#PZc{FV3`9V8ozf`k-ZyvFQpS z(|H!WM&n;>M~vJQ2%z?ys|HcyewE`A_vhxrsIz`A?Ow!4kZQ^^*zh=J{}tUN+gyX` z@PkjoTIMF--~7~HzDD|ILJVQyYlBOKE!WShz*^@4w*CL3FmbD0qUN+Geq-fpj5{?Gtw|kgw`6IF=rfj9uq|*Q>p(ra=n$fvNQfv^YBl z2BqGScJxnajWFXsRblW%Wl7cFc`+(G6agT=dkLkxx!NonlDXd#zrbtu;D=_c%_}b- zy*hH}>@WS((D3?eU9D^y#X_|JU&)KDJxyW|R60wa%(*V>wm;{uV{Zh;%=K=^Qv+vEyCR3{uZw^?XFK--{M6P2MLYIS-Tx4f${AXs>4;@cZJ_zdC0%T z>XZYvg#s1`^enTS#;2dj&ly&Hek-T*fV*SUmhU08PP8tZ-M~aIME%ENWN>oY3XG$t^#94jZF|3aFrL?06OF@4aG^ey49PL&e|BFiMopcvv<9J2Tg{@+=J9D}Ql zLNe1tHs5Ge9(#v44PV*ED({~caoT|7S0`BN-8<~?Nvf9nw@9W~+GU92PYAMT^z^@3 zNxrI~iMiwyIUdK;CA?K7uWy*Xoi;uqHAjr(V7MdwiSBrm3(ac#a^<#oY=ez;i4aJ~Q&my=D%zxt;h z8@ZWrzfl2=&xf_!lu(rlO=!L`_Hnm6Bmk`-2TPtDCYh>H-d#sB4{^=w&LM;BnMJkbmC$&I2nglL;=O^cs zlC8j>U?sCu-8Ag;(|0rcTGuVY;+RDG4Fy_Mw+Zc|`(#?6e<+6eui}cA*r(%t6!yTq z6*q4aO_VF=c!@3p|H#OHOAn@7@&c0IM9lm=xKsBqiIvPFD95hQ<7kqfh|bpSVKzZq zF1Z(~c8G)DdjDbcYEpK-U@bXT_=@QgN1ADU+1Qw);F)MLVeywzip7U^DJN^2eRl$D zn0rVg8yK?9S&7IUgD7wT6WU7;%fTMI#tBhUtdq@0`q#&y!^wc#$F7FUbi>y<#8USG0=x{lp*eMDw`|uL?wIU}Hgt{`rGvWueR%0P`0&wI z%V+k`gX#?#e8vZ!+T2Cg(4Sxc$hqY8Eo&`gT5g71j%7aE< z!-9%F89^~T7c_QfdAquFKhHeA=4m5kgbV7mh%DiO$7Z9l%HN9_*>x_tciY~p#{{+v}d zFwq*&q5PV%@&uAPpsQ-DsHeNWk7{Qv3gQ+x^G8{BHQgTlN#)Omv7=+JP(bVw`FsYZ z?qR9-!DeGFxD%~D)XbwDnTRPG}qpo1vbD_et=L38nM5pOOl`()R zB4!g;R9uucC{D`GP3p##(apQ7{ay@nR`?SwY+0IJ`i1&mPN9F|$NwI>=7q$lvo!h} zvorEcKB?xcm>}t zn-6u}jEa-sYJ?QDohl=+$`sQis!Btt9%pyHg$m;~0D`OP&6bfR0ie3#Yo7ATj z;rf*845U0~_^7Pih<*6@IuVC32&U$EqLO&}YaLJ!r{M;7vpNU89y9(O!BfX9nS_U@ zIkrV%)r^Di)h_9-J2u3=5`69sAv5?MXJ0FYb$-sbw--#7g!ddVshEK{o+3pKU{ggn)7DZPZyu~Rhbu_Z@$ndKk%@`^KbBD-wV*N`x;#gePB zMPxAZ`%4ebj~^V>xvEdfDusA`Bgu45xKuN^ns1X|u2vg?{G0ePbD8|7-lQdYRl&zQ z8!)w~gdnwDo_z+ajU*X5U)$dB8_>DiJ5sMc`sigJ+{=t zAb_X|-kJ{VUWe^UgX=;`&7_^VWjN{Jpb`3}C}!DJJF-lA8Z(CCx{+0UO9-DGTSt7q zm7_Ww>Am23l5^YA~jY+Sa{dwxZ7|L=>-&6PE_6_5Mlk>)&3vu@ZBvDn6|dzAj1cKz^4wdhV_5Z6F@q zXVCo}eGCYZU+B*LsSRUKwRD@=o}dkwD;OLA{iDC)Myw}%yMnedl07VH){COO`|I%u zLsma6O{>gNyl8dJz+5biPIb&qV@)m6Ce2s=vra%5p7t7c58wGbvmK7B7MwsQJI_P8 z%U1N)s`hveT?{emt0KEDChmya)Cy1;V&fR9CFoOzlty>aDz#Uc*S-`|Wh%$lX- zXvOt7UMyn}N(FmnQ%mXX!X}t&uV`Z9=70)u31wd^FYGZpOoWgWbUGv*iI{H+$1pG} zt`M6x?F}9zPc(>VsY+}g(`p*wmpf6$k{ z{Abz0k5&kGH#KCFB4^tjEe!JfVCP94=4$sLW;xNS0Fk-K-uTGc!?J>f6J%YLZ)ZX+ zv8(}2|I~xIYsbtq!eNo1zExn)p?X6v5Me1~xXz8@v8+?Df;stN#(aoqYz$K)IVk6p^~EUa5Mh7F35>L2q?* zFwEyt+i)4e1e48BG5V#xW zRSdTMxRZj4Y#rI*U{XS)&9}c<;;>U`^pMC~UlyuLn84@A>z~sr zR*ho9TlY1V=@@PweKMUNFLLNayM-DOwD;-)gkYCYC6J59GHq1Ip`Hi*ShtJ|4tCcToLSQ-}WpB zZxWB&Rhj#DgQTpM*Et~6`h(_?w$|#b27i*2r}OtxvqTp$VZ)8?fe2KDGRL$E!QeGT ze;A<}!}OLP{1@PeM24o(*ZZnOqhrktxkO!^8@68Q$la-uBng~4f!SGPPLromqX#Oxr!+3xziKgSF_U+SwA1a#pKzf z-EIzBm3qCOR(HK~Nn%(WyJ#$g6G<=d()lk{6P{_r|mRXTx^1zeLS9qSrJL*Jit>7|Inq5HWk zOdW|?jANl>TyMI?w(~51nMy7?*OfV;OCi%Jt0>6ex;+Ga8F5gX;mL4lmUuoBMP4Fh zcHQm%ZyAamJ|txF5T2Ac&k=$07uA;VN)@+Ng{8Z7LtwBxIhl5=M38{n=xEkn#q8wQ z7A>^DVt7bG5#O{iBgzyEI%t38E%;p;C7@YA!-)87#J)F&o)pU8e&swi-X}RW^TYq-IPCs|t_`l@J;7hC! zDULqd&D5R19OdWll$VxsNbFs4J;@SY2h`p_Usd0h2rN@{hMa~8b0FAjw!WRTqy6O~ zbv8YtU&Y=9*Aza@6$?Su8gVkurH~kMvz?9-+HkhiEcGQ7#a7_o6fGl*!=|QB^#4Vc z0{d0Lx?gK|;<@&Jy#M6?<{-7H7w+5?OaT#ZH!tiq7k!b>bc!U(t7Hj4xBM)2pc_TN z9gc)-vXC4Ns$O+J;*3>A(9u;ssjya`7fU7B8ggwZ<<|c8uR_~LT@{KRvVsLuLPlkV zc*|xyoX}gahZmz3zJV7roY8jewp+;yXHVc8LE~bGwzm5~FT{)-^(H2%5m>-0s{wUZ zNyEayY3*DzWSvYyS5t$h3t34ngwCPTVWCEmMe1KI=|d=^XLE7y$cBvLB3u(s zbz|G)i@+`+$5tna($r5DXg8FOjltM!@BW*ok%L>G%NYa@$IuS zD#Qq<(!!aO$yHLhK@HgyQ;r1wysnIh zeWaNOt)tJApLaM+@lGBx6Op&-&(#Wh-0jRsj1dg8qBGVHBqGPcWPi{KU}T5)*OS*k z)ZKU|vq~gX9Xjjk%r^*oEKb1s5z<8Rx<*qaW78(?rI&kzD=^=-zaHs#H66@XYMYPF z?N?COvBHgh{HNs@AMz3s?)p@#?1y*uiu6^|x@(MjQSZuy&@pa#tgA+Ck9c{(w6a>n z_z1MB(KweU|B48qL$9PD+`(4b*KKBV6~(;zp>yYw|4m&%eq2baKL+hhU@iN@NcUCj z&9>zs+Ura>*D@g$QxsdBpxc#2UzOW(mqDJMG0(Dfnz4A?213V2UGGB|(|)!Ha+=3i zCW7oaEAdwip3^e(@`f9kE{LKIEyOsK0d^TvDXp2g!S{Z`b9i*Qw^Zo60+^v^EPqrn zispvGmtl~5oZ#vdL-p1C+h5}ERn1E$%g9k~|;*VESl zwy26sIPz!|QK|&OA>6rNce^BESR~x8bv94D4b=?Y&<_U$j)BUOGYZo7-!e3YT`%?a zafcW+ji$tw!2PZwF>a=V4|s-3L=NImnEz$0a{ut=S&A9Py28;`oiG>b>OAk1VQo_^ zB==15O7=C=*C%3+-@sOw3`DV}Q9s#Czw+AuXpY|D@GDoh0I535i~roL7toj69S;Ll!%QG z-e5>VY+x`%7wY?BU@ZBWtdIX;et$z{4&KnJowU^4xswi6!c6UpLcRX?{b-S6zW-g~ zV=diE^x_R9{I^x(O~{Ex6zzRnbIkG6FCdoJPuy`3S8*GIklxWQjhf4*u1StmT&dkO zIMlYAd7u*v$i{3+?`DrYXo201BBzV($&WC%*>)~9l=F(Uk)Q*^KFmw_k>kZtWHF3d zU$1o%*XbP4C)4$48$|pdNYYBLhCVtfm3 zYRim7ivK&|3Qunm8W4^31d%CIbIg`%zwl^V^PK-UBAyc2_55omo(Mk6xVUCTj~tVK zGoAp-9hQ9k2$2iGOR*Sl740j5-Rk)V=kXRG5$asqy}aAtojtgglap!(CHP-cu25S|G2!X=jzeSB6k?|x5Bk=Iw!NB)c8IT z+0pAJe#F>}uaGlt#LY9yUc%hyw8x@I2-}(J zjoCa;`pP@KfpC{YcFmUOw`WnvI^;+0MoN|0qhtc%l(iKb^!_|<_OK32Ma;?Jm1GGB ztIN7g%V@aMYxb~z z*_LP)TgGF%Cuzd$_WJJElr$LFLSVp#NI-qbRxwFlnnj%Itm|46Z)La^GG*2qV*+SU zsUXsmwW2W$=ZeYix|dwm6-|1!y3q$y*RZl3NyrM%Zjmqxjj0CWaQx9X^QlKUFGH5yO z45@b*j0&|OEoF$BX41ht>g7jsq~j6YJKB7CcX35M?`*)B2yh()B%oSwA2X%sQsW+} z$e0rIJqXT9+?=Bz<-BmNcw9+)UM~6~JYp)+MheB%7l!)l8z@JKFrNXnKp!_HVdrxC zUUJ{8@@(9Yx_wT6n2PabCt}7YVaO$lagh<_0wc@|WM^%f;eY$;3mR!CUXJ3Uy0Iy! zDAcg2&|qTLOrK)CSC@^I-U*erL{L20Po->iHUP+#j0*Tc8l1rJGC`_?=DNQp%uBD! zE$b#YI^J60fF_1FM!0b}91LTfba7yLOk=}6-tQaRIo+wQy@rHG985HTD}c&0#lm!} zRCEjl#qL8!3nF6q(h6pCk09Zb$&<|pOecltJe>p+pPw?D{2zOWEk(8$!(8q^s5Hfk z%^y(=p65@~>)_fy>u*l)6KNH6C@5r(Xk?WC*Nv6Xz2se?RFfBVFkePx2(^@BZB@l6ruNs$|Ml(Wb!^}pq&ZB>o?%^B;jg-J?n;fRkff|0 zPokE5DAgJ}cT_5}w7&Hl7*ce@uQY;RW)zgzp+^KPHLUXQ0YYWf@s7}Sv>?ve z6#uK_K|=WST3p(3#XnRk4%fq|e0B-lzy>sQ{iS7s^L*dio>bT+2t7=(?&&GQd=v91g&QvKa${^Pb^oSEt8fROmD z%APg*8w;^_pxs{shVtDC;S$oJvihFA&3tB!`xcxk`sDWh`CO5M%#npSk^YBGzLs5N zM9p2>%`4os@@!Fj5&ICMKMRG%=_->uar_2kJtm&!{5{{iKC!uCpXbmRMp1B1)nxQO zNyFDmFuqM)^^JIznR86qa17z>$A5i@UFJ^H;1;+VrL``2$DQEuqB>U7#LOYx&^^e4 zcG$;5KCUuJO4x{>^JAAKvlKr zS;y(Zo+!7+c09xC9g3WN?5LT8rXQ4uxnc8V=l(UjkZ54}1_k4be!$!FfDOnJzkBAN zxxPx9t^XdE{AJbGEXGOSi>rNTpGF}i=hxDe73cmPcy?=#e62Sb3muCfYFtkp(b?Z{ z1A4HJ0KP6hFG@`pOcO}KnkmQQO_>b{Vbp!ru7F-rTMI&vj`%h= zHjP+q);@dLKj27(84?50M3p1SU;^pJw!Q8Se{z0I9+jLT=yq}F$}z5CU3@;ojb4ji z3uqU)2k)7NX~ML=v7oy5Sf2BjdM7Nx`%M|UnhwF#BA|*TSx76Bs^MK2PCe%lgu z%U76FOVs(xpcT>@I(<7;6F=Py<$c0OS2POCOF4hjKWhd*oDvClamp_|0SdqMY-;K7 z>El}@q(WCy9xw z*(`Z=N!Aks=S79wmY-aPu&aQFq}s$&_6Xt*6pG9c11fA2uTwU-gUcilZqrK*qy6kD zN#F(b^&`W-K}9vxDeN<;aMce+|37eMeW4IXu4GXAI#H*ZaV`HsbbW21-zFwOdv`-E zIg_hzfDaujx8n7kb-fsqD)`Z}*tvB^ZBr{X!97k@JsKS_T?3z@e`_bB6PP~4kq=z+ z`O32#?O7EvPe;){NTL?Of(bJn>V3WcE(*ss1(C5?Y{TCs%qMy7QEp&Np7;d9=9e?P z*%%!A&V7%gxJcH#6=4kXP}Yz=Cy^bd|4GrrJ@_-u04(g)F_XTJan@g&8p)cm1av!toR&#h$r2ogE?eM1e2`4!; zTmdK8&4>N4DeP$an?+n9$LAery?%Vr-^dT`XRjQKrN@Gyu90Y|Uc_YnqDnO{!0l6g zNOU>>sT~K;TQ;B^EUbFPaCw2?h6RPS(;~9%SLT7vHSg~O{i0X6D}I`{%^nmObl!x# zBpQ#iBk3y|SD0)$4SGr~_NKpl!!0iS9?1dEu$*@PjpE|311`lD1OHoL7oQ6=Oi4X+J`Vtq74~~5k)^rDMe2N z+du6i0B7l-C7_YM+42|M;5`LJo^9G0>H6>WJesO6(D9MxP%;onbhN%u z776rUeZ1bfgley5Y|=`4z5NdmY`~n*`^4(@nPjwn6XbOw_homth5aB)@#r%bxctEg zu7Y|924vD9ADQKHhN50#Sk1qKH6!5d?a?nOd=`LWGyCl3W+E-LL7_vl0EKv{4YWZ`>(nV^v$7_^ z1K&oQw^Nt9E5X?oVG5NUZiPJzzu=@gDpnKvD@}aI&DS^LH^@>us(fk%!`6m7d#}=R z+W76`%(J`K@t}BS{h<=K654J(S7L)i4W=Kg= zqoBzkcFsrS4WIMPHznS#n_lQBqEO#*vRAePt?lA|QexixcxM3Lq3t(1wjt;8UT!P{O*2^5bAlspxIpwtOjp&KrdErI22lv_z_L$oHQ}t+8IZItpNKaRo;}5v zyb%TB$V&0PioE#UZA;enmS6`JcW8@n=F_uVL~bL>SKm3qURpnYn3>&{$<{P3{N|SG zKSit}{hUR}J96vMe(+)t7&uMT9Jn?Zvs&@W>t2H=R$6Y3scJv+ZCdO$;?CoOo#B9$ zagDBDuR<0`J9(viIbIzaK5Oq>+v^D%W1PJ&Yd$_MIAS%?Uru^~^ise(ub0m_Z`mAO z8E*nV;u=PVGj789m2}}xkqKH$`|sHEiizWXPmdUj9ns3(mwS2T4IhC8tl(v+o#7+I zkSUjIr#DZ`)9yPJ@ZpuaFI>=G`ovYW3G%97N{{@=6HUgGO~e--(xGhT>8rQ=NFA|b ze*+jjAAQH;dWPpr=rf1m?hAKzU;RUqGw5udZOZ$Kpw!0^<$BY~KJ)Ku-{Ws9doK&o z$8_*f@3NWKB%|2R{NR@2g(yC#97fag5q7LnJ(E8L#a33IX0F+P{rl9uwFfOuWcTU zoQkZoHo_i41Y`SZkjh_2Lg?=etQ#qyuuTTY#s9RC%wnT;5xZUKjlD&^t8ur|4Nr+m zGgwJI9{jdsIl1guQP0I_MY6?(Z8P5?5({v_GT=<;G?BN;O!%!l_$MQtLO&V&){r9_ zdPQDE5Cdd2Q%J@D;W$(`twGyAmuR7`BC)Jj@^&lO5H8w#V+__B; zv9vHD?1p^m<925InqW^1NdJ+Vjb%wVQenieg7N~wbIphI@*Ry$5AHN3`RHhK9l~Pr zTT&Jx2h`qAxScb)ZmTr)`kQ~^m_3%!E^dcZ^L?N1JyeV6bIPASRCbZ{B|XBP00Ia< ztuQ1qi{IcEcv8V8sW84oM>ow05e8};t_D<5&v|HVs!KjT<{hq7t!Q0KM7-J^GaqYC zUl$s)pOwhP@DBZ7(*hm~u;&sa_cvYfk_vWRCYee@Z39Y|RZiR)^1Tg-mn(xWWtdkK z_YtdAPht2|#VrIaB?`~ew|hCUGEOqjXJ+0e^L+fyV{{nb@GG~oj!xc@juIwK5=($o zp?2E2A7B%%SxP!~1SLO0dt4+hfEoC|Eanierj?edF+*>9yeulSZu{?foElTDTD%4Ch$dX(N0B`*5Xax@_Os zJJY`-z`;J{v*al#IOW4h>DIZ7wOw`X^({aI^AY!6+YP7rDiU@RFy>sOl6bp|`J55M>jsZCGdU3oq} zJ$B>VOS5tjS&b{WnPqO9k^B?Y$h;JO=|(?29XkY_dS znu>DRIvrh3W6z8+9~2lt+vnpDby|Su3gVHZi>%v7uQmX%6C5`|2Encw3{@aUrc~Fy zn>q<1f$mAs9cB>lI~W8AV&-uyjWK7rOa8$Gy~QT$1SHLLywT`gee}tBI6`* zBVGpKsj-8p8VyVGf&JaH?$IxyXcm z^rftrVh~&%`1`B5i_i6Lda_0=xQ44FH&hdKwn2T#{Ky<@39~qWCg)2C7=Y36_BZU~8JY{MyMeXt>6o84UFspiwq5RqhuLr*L8H z3CZyaVkF1ZX=ZUsZYXC?F!Hq+2#-n06D=@-5S|08vIiq~^#;bT_6W@6v*1k|%AQ;? zt6E@b$;n?Fe=WUNwHSn=*ff*}5y*zo{gh=hFux-aWWe# z51aNcj}B9-jT|SCzQ<6IdMHc1nCv+fgEIC8V}9Uuqz(ps^uz?!Sv`L5G%r8pteu&Z zE~}J$OwEB9kEfI0#Rw~D!S}hcCWkgHgWd9Al>2kcgUWn9b|75SgMZ%HgON8ULMZ?H zo3?$0LQ*kEZ5r&DyLj1_>9Gh9M^tF3?>SkkD?SbHw@1>p`KOXf9nnZZ-6+R){+iIh zlkv{M%Kt;(jH9V;o8zgP0on1du6)d3m793KnSzm2c(H;*1tIy9>(}mv^*u-n@!|>& zM;cj)@@#++bMJ2}3*wvmqkEzaBuh3yvM8zeL#ZGQ%CLXM+Mn0c#egS_+|&nAUKoMC zX!ml)_A=6ltG1^sY=J%fWz04(+We7Fi0^(F;lA6G$l%ASv$g1_GIIQ`)*Ec0a>jYG zIGKJxx&=mb60S=lO9S)Uac829bawi;O@z>QF|=$MqUtok`SFL zdgD$shBQyT#7jIOdqdzaJT0gketH4M@45K2IJhs>+4uX*YWrUQsJe|)a#6l4pRPPm zq&!n>puKGOr7yDT8XEd-)aNMHiA(pwmiR$rn9>s-UWryUd05Lo-yz$~J-Ea$3gCK~ zvmAR?O7s+C_i@B=H>R*l3Gz?(%Ef&{;ahq9!Ht`(4k?0S54ZmVv&PNdzNsJUFxa@Y zmgp%HpMmiGNK0uUf0(uC_VO*C0_(O z)}oFpQ-6Rb1|xUv3~c}4!2{u^8m}uh`VpV8;}osHBTJR_P13WJpO{@cU;f(8=k-f- zb#+|f!syg5nN}_5g7i05izXKfN@#hz9RED2W4-JNM< z2V4T-RCWf%lW4+{FfbDaHB$^;g1pv?>4Z*{CnI;qpo&Avnc?8zM9go$g!vImmd^`! z9Z!p!_{>b?k2!9f{+BbgiRxCtU-o#}e@tLUg97a2w1gR2#;++>3%XJ|y~r$lp-^1&da5qXL`F~x>zV^n`{wf?Z@`Q-{r4O3TqJa| zCBFpmBu(}B9h^?><(%YqcXcC%SdHrWGVpiavAI5Dyx(7UMHSsEZ1?~~(K#I18-#%w zuBjai`0Gmz&hV{`zNevPfUDPsWz5Yf2%hJeB8|eWf-V5iW`H7_Xv9z?_5}Il^@$%b zcU|zGid{VHV?ceiioh-tvUWZB4EUz%dUy5qD{J#*Y2yEs6WNvR5OdD(mVN8C3_NX* zfUoNJ4HqcIL^_^~s%es>v8FrW8@~GNn`>m3N`5f_8J$8IR-hdmH@DrfH(>O|Fe3Hc zk-Nk@BrRWjPHDpt)r9POp3t34E+s3HX67KWYafRWvl4Hws#DqUpz_9c8-?5<9ki=j zidRA=mV9ilA1@Ye@c-~1@#`fObzJm|t{$()yQj|y`>vp0XB0Tgj(3m$31{H+kWVrm zFao~%rjZP{aBoA~^gg%M=(Emz5DcRT1EpZH30H~E0LIQJvjH9=i4M2hsrs4qi;sG! z?EY!Nl=vCU@!#!p(K#!s4;PH|{bh&u@ChC%5oDrD<=;)5f9c!nl>g-{E|}!-C8GHg z&pIjk$|=B}>O0+PuHqXE5Pec$dk=*g0uTncB1yP1d!o$oZ4U-=Z`j%f2 zS2V9)x5J^C8BvWvoFtrC3Jm38c+0q;jmvchDRC+Z$QPvH9Ut7HadhyvwI;1|pm#g6 zF!L@HbS&~xDEg9Tm}$PhGbgZu^eqC-z`1GvY>`@509KovuKlKMCf>Xo3%IAX_yZjA z(oj}UC*evTrqF8bKypWQ2>)2|y}$Z$h92<*40h7Q89T%$6?66G=09lia}oLxZ>YK@9X8@3Z?ck(Qe`XkvcjN$bN`i!+Bi9IEWuJjzIp$85-HHR0m&(T)%1ELto>6C|q~7b2v@1@b!*eMAt1BS8*Y?YA{$5P9Xx) zos!*(X|`s~d{Tz#6C>|E^{%8Dn({~XZ#nJECSAJPS?@P+QZoNJH=_04cx1l#B;>vx z{A*KbskB%$kq-c+B9%UNBe_HXNY1&7qfH$-q!N5dOGVEgy#MDAD>?oJPRlnT_TuZj z>LLP#FBs`Uy#Wk+A8r9(xJlcp#uI|dui(9|8G~91`A?K#a7c!U3Q>r2HMh7dit*=G z|6^|EG31W5U*NqVYL9uxc!Mjn{jlP?c!HipnL_mg#~Q-tVnC-=$l{2>{_%p>6KdBxcONWzApH0-w|@k z-;m0&!Gt1yRn7K#JHz@xy(ng{i3Zh52$D|ooq@*fW`VsV%y}a95?~t;G|JP1?#w3= z%HzX0d${P*kznru@@l-v=2>E)6Q{Wi$0zNDJEZ|;4q84=&x;#m1ety$mQ-}KapvoD zpKT^(S5!+^)1oOC<%p~_-+N3wCfDGawtBIuAHkcuTBRA6IsdD^XCgxdeusG-wMn?7nzH9J^JV+ohyn6}4<%>rE{L^*n9P{^=Hg>viD%W}^5xoTR z%6<_bbP{u7&*D3iMR^>Y?ADkGD zgJ@W5IX=#lTDHPP!0sC&q>T!5X?-+ITyzYc>8H24w2)?XiOG||-Y~RK?6qOO_7j@l zl4{E@5R~(9;!K%?<+WwocIWq~@lW(m7J~Y>@)frv=S`>~oL7lI-hxxy#PSL)9aqmL zu@$BuH`#3+X8LWfx?;td*vxsBXODKV-iF2Pwl~Osmgle{CE!M4KqL*CtxRi&Br5rJ zMo`xO)o15VSw*f>)xW$&ePuxCQ$^@Aq>zZ?>I)7EZWS#^BGw+ndplb66d3E_Ef)pE zB~mK)n`V=c@g_nAn|rL7hG%kIDZPGOT(rO3D`aCoK1B=dRLX^w2hNHetn@7wci zTI9S8qx@l9)wA1|nkjS)lvRJPRw8GyBB@Tm*Z*qKR!3O9FTfaWN)U;tIYUx#dx4UoR`lyZi_l z=|rJBf|5UM1Z;bOOXKOBD5}EUTX&CvAL|)*BO5bV2*Lcx_C%sat*YNet0Mzl*?0BA zm;)P8URJ048bRgKgPSVhYm6cDR zgSD)(nH+fbq?q+GH$Yh|+llVpDFeEIN;5zDp4#nwPNF@Q1bQDXW?mGtk#RJwApQ+8 z=l$3!7?Twr;{8`K!XSO~bAZDs+j-YfY%840dcDvO@%$Z1BS-6WUTM_^J>YVT^V$24 zwzP=NRl`K_@ny=)#94#{NS&<@1#S+en~ssV3MM!EUUuOO2?yyM!C==T*@niYvdaq9 zY9J%g7YHF&aFJM&DYv$1VC@XR4tnSoQD>DnNo?a$gM3-`Np=PPSZ@Zg^7ZFzMK_5F zM4xdz#pp_#;8y2jb_FD>{m@NmpN~gl@W;C)VvlEI@Jn=Q$t{2Xjlvb?8+?k{Bxy6s z?mn@%RGC{BQO#nJ8)S{zFXmRUn-_@+?d=D8F6BGzqLhKQ&~`uF5Iev#4a|1#E>#n- zk6!kfe<8Cub*mBR&5&W|)mpoD0k@qcgBI+-5{Aw;KH&3|Ed@UWjVg1^c^UBIm*$e@0Dk8d38 zb}M|$QFq0_YdRs1t1}UJ852dLQc68$wFgBUjoj5J~sr+p*(0Nzav zoGe6#4i#0CLdGeCHTc{TEvF)0`Oz0MUW7zP_tpFgy3+OEVlNdqB66oB2j(_IBPYSV|7GXa6Yd9LR87;Vhb=7QG zY;U+8>hh20Z`W8jXi#cr=ZpEf78}rocRUsM77w2C%n8s2`srJOFEHd=6>(W^^D3sT zdXwICj*I_+>bp@GRn=f#*++Vw1HK{2Js+QGctRcd2UNbXc|`>)8+B`EIVdjA@s%rP zDLX%23iHbL^h|%38iJB2j=<5Y!iB+-oq^nN%2NOLuN_4Mq9eDxevF*ucsr??t2nIf zZ_fQ4%Nd^w6CObIhsq`jZ;Rnh>22#X^03*LSO6M92iIa{ar&q}d@oSeK4?ugS+?>pBj2EA75F`Azd zbp#>v2qCvlE8JJ0gg#z_`cC<8VX|Q-@sy-9^)h3$RMNB;JMY2D5|AMV7sJDJ*Cfs{ zdzlO~5W(j5@uamkLqRiRztjB5mhGN`eg?lMzH!C>LKywSHoQkCT1SU#jvik=AG&?9 z{qeluUghEhK24sP#^fgC^%L0cU9d@s86eBo{io(T8B+bWei-_}M(~kbb}5MGW1Cn8 zxL6DBfkfD<-adK~=0+@J0fQg(?MnWhozs#VzEr#<)@&?cO&8qf6TO2NU?LEo^;#Ju z>Jujd%MIOsa`^3h- zWg+;py2c(+9W&KJ6PE-?JA%zNG3@rf{b6Ee#)TAl`r7M!KT|S?Lp}>p6YGzMHS!YR zX>6?(YyylQ;2yYwC~(oG2n$bO4%;yc+IK*cQj_P6L0a1;3CTi|)~FR6 zT2jLMBZT$jQ{GpVyP9}N-FaLcrhO`uz(obg>}enGu;$GH$Q-YE&Sdx>Kea+drP%Ew zD!4_@qe`%ZV(O(HR3_m_sWUJ5#g=JNUI5=|F0495*<3_*%Sls<6UW>CGuZ zi{b6fQV;$iEfuN^kw-5MD&^+J zV?)Ql9CaA}on7@7hG~@2?!|5iGmEB$B&!xJBsa-GglkL1q+%rV=Jgx@{)f^P<2C!V-+nBZo2`GK%E`bRngX3q8(TTS_UD}lBr_t2AQ zX?vObUEwT^3x~j;`X#zI9{lrHhR3$A?S=-nSQJkNxx3Y{84Fp2UwV(H)iIjjgr0!~ zA}QZ8(b$2;&+dC|>d3>B9ofFlzd}yP z5mdEsEnwk}Vau-3U2V&3eFcc;KEXDKw2xk*VKukAGx5KvH;)_eEGk-6OuHb~TyzWO z>_O%*?b@T>hzggUc)vdtpJ7wNlT;4z@Q<6&uxHW8`I+{C*)UHI7|;5f9+$FNvmS*z zanAPsT$C!LQgI~e3P`-FZpQ^D%k8gRcb}i0aqj^^@$ud@K$2IEvm_U`sf29;)q!9>RWvK~DJSds%z3YODpJ`0 zU|av2``wX0!qLLr+0^c2%Cn-%mt3k#MSNMu?ucqzyz_@sou*w0`xLNEQ0nQF{SHc< zo+I7rsB%K(X@BP;bN`SHF|)Dzegr`KmbvKdMf(Xispt6T4zzOUAT&^ZN4FOasADG< ztV2@te4!V@qGB=)THqv8T1Ln0_#Fyxc$`y9ZufWZ<<})0J)rWfqH^v22RAvyE0L+` zH{0xgJtx$6wP^qK>7Wd>hTnPTC7UBe?V;M82sW0Qgx%Kmx7plb6@S*+h?L5ZZ!9=I z%c`_iO^m=m5ND#BN??-}hZ*F%y*D(%Ur$B3&v9-X$#k9_m6sZz3!{`0j@L>z9N63Q z_cTm!jC9~xVg~dT;B!obm#1UeOMhpBpaFgbsW-4TWpYJ@IY}eRhcswR#eLkh?@e0M zs+SboKLwzx?cj)|6}mxt=zZ>~3|+^ELjWm?sw{33{+n#C+4gL@bBRI3a=VQunOf-V z?edjp@@_Z+ut~n%;L1B+ESv$P;k`e*mW)y|M0|Y*(Xw)}R0TtRd!F{Thk!^|5XNd` z1%!V0jQdkK&`}muX?0rpUyhGuFnQ;h)O0WZeEf8~Bc(61u;=&@|Z<_Z``ARjFs ztf;*lLUA-D*eb&2w#C)IZFR)qQdmWweHA&fR4-;qjE`jp`7rrZrZO3D6 zq7ob(N@@i2ZF)pnlJep$l91s};5w-y2>Inz97C{jrYbefZRVfY{B|%ZrF;^3TxxhT zpP_T!ntj2b7**sFS1$Rty$l_f3T^R=KBU8>w)1X0%*AP)P*@oXLF?KN*fF9aD{0(4 zOHWszN!PmA{z3j=SSwi_MNzQB-KcgP^RGFS;oT`&V!M^J(PbE#|dT0AiknRvsQQ(rh?HuZd0+j@Y$E9;>!QutK}cACJ5>Q%CLEf5i;EtqP|emFVYq8O>GIO54va{tCpY~Jg} zjZf>dRW*7ZT(k^mIDf;u^~Rb(m38(XflNpNj!XI9Th_k{+Kbb*88>sBMD!zi!Ty6w zh4(SqIZH+1{_)%R1pYr{c{WeRz{0sxux;`hGh((RkZ*W~FTjyao|TR0sK#8n;5)p_ z$eFqd@45*AMAPI+4O8i3FXBIK922PokZlGLd|;t?C7AN*B*JlVl>0`UhvSn?z2a^( zxg}}cA;E3SXJp5Ft{@Z_hRXLG+gj|vQ`AII1(hfd?0!{T3S3_F`k4>q!BevVft*ih z2Ym~QxX!*YYsk-n8sTb7zsLzYo94I5_V0H1=4DFUyI`XcjDs`vJFqAgu0<6^uRwjV zq%c_A(RT>|IMBmAFrPq=ToRzy2c`H*i%X44^*pAgOh~H+i$93s|^xYkT?EvnRM` z9_Ece3zwZw`#hGHR5#a?oeuCs0e)n}oYCdHdZYgp=}0Z;RnM9po-byE)NOE4Fn9F`DZmYrXu zxmb-}0X@VC1o8~q4qOW;fAEuSYS{yCJ;5-z^%h7&X#f93@|K*l|6{V7VSR- z*AK_VIksRvyyIlt^Fv%E2Q)OWzYvk19dI@25@|%ivYo+8_6Qp`TM9GZvT>tD*ir7P z>t!m|QfTr3I04sC=9!x&cs4!i7teW$70sK`;P|OmyCy{#B{1Jh(W6uN#^p!fz}&&4 z=-&3(*70EHF1^!4V=Y&$-aKXH#!B|PRxE-;DUrq8!i}nglh9oIzHfvgQx#ze)8qMD zo=P~LT=!nJ!W%ogsdy3x(82l!Obq00;$y* zP(ZAifw*vjsCf~fWMO0x#m5A(7uZoylcf*%5$ZM9NPK{vw{J~8$J4rSD?a6F$3}lm zFy+m@&%V>M#jQYtx#5$db_xgEY^uvldSYBtYk=bU#vys*6=QO`o8juyx*=2v8$?E} zjKVA&=cZN}M*28d8cZ@Lx>sp%&2>JzZYqao=Srgd{r zJQ5YZ?clajOq?o1?2Gz~3iAC}e#Jn%nW=VH)UJLrq?3Al4orr9S&-$qK9!uv*qAkfjMZkT*c zSlN_EqEe4Ixt0)rcbq*X*%ZtM6=cN^)5CtwnuTlHkM9$&JeoOAr-4Xd2Jbx|4@X6B zu6JyDm^PU z<6FD;*s-8`8{j>KH5Gm)Nv3B~-RCuY@=&v-edGRi;$Jeo|H!MYZz!dm1SzM~lLow{ z*TW;86rA_BuBN(Blkrc(euIqVJe! z=Y8+eaRL^1_hgOHW#eVM1vlX53@9!a(*DTb2GHyv#j81l>MQl3&E4mUm(SgCD$G~1BbYa^U?U8X1AC491#;PFMcmCQ@1-`S zWJ41u9$Y6a4l=|oJFt&zOH1?e3L~GEfQc_}*IkR*kF)r~!SZsMah!nxA7@5@Rbyon z(zHPc)LOB#zf)fxaDWC68$#wlT^~##CF}0)S>(xS; zuizj5V#@gsO=?cY}{z!zVY*{@vG2Mb*kM#&Q(U8vsc>D+XaJTeNzJ=$eR)!N_F z6x$0RrMy4Cd!f7KYe|R5IV+ToeebnUk7rS`0eV&6CF!d{$u2J{=i6JF6;;ogZqJqD zL^{{x{JoGGW?udb-DE{$DGFaDS!X3e(&I<;R196?fmQ)8siwMroM{?4MLb~Xk;=k( zwAg!M(tU*aer+k^%Y$%`c?Gq5P0ihju?Uxr+BaIwOTg%RVt}_yS7A->sZ0NU-$8}r z^zQpJC6u`Ly^UM=o|c<<8mUwVjL2oj#^d)#7h`OZMmh>UQaWiSIoO85El<(krs1;9 ze_TDo70d5fubPN$7F(EJA?JSOs-I$M9s z`E8A&p<=N;3?#>45~;fjUQyd|d|FO5ia4=?p}L6qV^QE~QbGoh*K;gi22l}`Hxu*C zj$t-oTgDgSM(?>Nqweaj1W&xu4BLf#At&Iu25d#5RL^nG93w-xBA!eK#6|FJz2C!i zpVTojLSI;E)F9Hs6dFbPCs{{DDal4jK5+~~diQuArP8!>1ZkS7sJSH-W8y6pM^18j zfZaq6@Ll=b?(U6IJEM-HG3zT+fSE|6_8k9XFxYesmA1*uZKCEBw#KxaXN}%xt##G# zg8Xr9>j?3IBFxGr&df(y0Y^){JT|Q&QVZ*$pT-el<-Ox3p=HjZM+}GnbeL4|n7xfu z%%p5dMGtF(6WfyXtTM^os$tDOOtv(J?ZU!J>@vf58PmFq-!tZYT(?C{k3Rnz3|E+p zJ3bCWB#7}CCc}|Y=!};l-l=J>kXd*hcf~r_j~zS2gcFXl!qPEtQ>1_ z#EIqN9?r4%q~;tq$SlnW8lDv7zkjC^}?kT5N5PndX~Q0{uYqen zFQ+ZqC2l4T9)0Cd5sZA4p#QsYs7RY=oc80?LtxiFy=)Ce`{R5f0Q`c(aw+aSncWWm zN?Bp~rh2uFp=kT(<&`P2H~#t~6nqPu>!LJfxmtwoqk>%amc>ipq2Wvjmd&6r)h9v-GnFZcF4gNvFZ%EnoWLYQu0D#fB z)d#az@@xinm+A5dTPGypeI(&zR>)=hpg-4Acv`?RjG6ku!T6>f+<|28q)*>#IPfQL z@TJ!1DtDn!SP2a6XbemV!{$m4+JWO>Fq|yKGQ*C)s}DA>(!g3l&I>Rs-vB4DiddY( z5i~yBmo1;wHvQGtt7MDpclIXrROddbRan$!%uj(!Jnt`@L^~p*?gvK)ijPwl!Oy4D zq*w(SExCUb{v^_%DMtI_rc063uVNlaLuqpQ;n8IPKWBFNzNN*Och#_G!~KLLG}6jx z@j~!i+e17TpxW!;sntLegJEO)a$$!nR-itmdU8JGuR?pd&UpU42GS1VP+=Pg8l$;F z(a>XLaV?}XPt_Itp|poQJO0`#i@a5voSiu88#gi(jGzd(KIZjqk;KQ(0- z?KUSI@3EiuAtl8JG4M98;|XvI33Pckoe(AlAGEKmHq2Ry2CrfnVI5ykW{gquKXuhC z6;RzI@|pK;CTx5O)Sxunp=p1rJdY5xy5mFo@_S?ra`Kb7TWZQfc*Q(<8HIm3#`;Tx z04Pt~f6AV`f)Mo`Ql!kfHF7))B3elzk2e7%Tkq{_w7c>@hFmgnmq4wPK-V z84XzKUd0ZI+Bs2kjzKUEyWn=`j&{0+_wx#(Gu!DMJ9*KHGe0e_l>++PteH@dj;!C``u4e|*F`FMl88Id=euB89%?$WK^exwf| zoFq9Kr#O~oFcu>TScLdOWurCsd-^Aj<#p;l3b_3qR8+-qNp&kqa8N&cuB`MDTynNj zy=mWb2j03R0WAI2O9HEzvACq?fxps^54?TO%yX54r5>{6AV|s~=E`Fi*&F_P;Iqeq zyz0H%xqNBq{4~_?{+*s$v(BpbQVe1|h!Rg>xWI4(4tpgW*Dzc4(3tOU>Jgc_w==1r}`{!Wga z+`L|>dmNDyXqJ=|mZSN-Gw1Omig~821tD4j0`ZC}oGv%K^UjSSE0kn~Cu9|4Ws-y| z+^JE{`Vc1t=ZgqgbL+4X6Z$>dD=ql?MWbW#SeM_^wjYNgyFs+ID) zYNaeU`8sWl$zd}ft*yuN&#!L$ai}1U5}~pjg|nPU1qE>gu4dsh7`aC-N$Wk*X4O8-}DM z?X4rX-?`?O`mNAsf?#K)ip!JlR=VWoX2ZTnKe){tCJ`g7f3;qmeBb3(#SZeYxQxbW zheuGA?6C!Tk;F(s!X<^J#Q1$f5A?V?B>`0Y_${GlnS&Tb_}uP=9^_UJ&FIyNkP(At zASuFpVkz@R=YGKXRLfXrd&Rszsb~dI){(2YV}Jeyu&=5vU(e7oPx6$YkU0Lz#LDSI z$;V?14vVJGw1sq!mOc&yW(fTh5I&&&^`htzoG^M$61%Vy(YDy!&A7sYte*qG*;R7>>sY4C5FaX3Ou_#Fxtv zdkSlpZt8-!N+fn={TZWNwO5{`m6S498W_wSc^CSaI9E+G$fE6oa1JhuV z(#g8%y#;-y+QC{~Y0{CvlZ+!r$q^NIx-vFHCDU4tk2yLo9<27J&_FjuESKwb%(j?1 zTUYKI(LQE=XiwRyNRgr-iWJ94DU*NclE3k2GALv13IE(CW$BY9Ha0wd29(#?y33oH zZTZR|0183lZ~zo=;6d{%-K>Y#?wv2*0u&>T>0_7bbjc13Cs>>oL`fjniO+ktEITv< z8SEw|Od%8eex$m*rS&w57D}dD=O`xAxku{+kBr;v79<}l!e9)8GXjGt>hP>t!>XnJ zTzDyQA|@~`PGgH#2v7P&gS?SXe#Hyyv!GH zXEjeXC#Mg+8Uq&i{40TJkaSghKCCMWWo_0L2gf!3)>BXC2CG;s1%gx=9;X!&gYT>! z*Y^H(ae=D@PJ^qqTQAgNPd@Wf$f`L`!bu8eI7TAjsykQr7xtszXVTAWgZRJ}jVnU- zx{tN-_XEW9vqFx(LSY;!5}c~4s_y8IGY6(Hpq>}Cqpx-R`K|BnOKnz+@6#n1**-l_ z+NV4w(j==$(z`D5($N?4aoPB>#O-TNp~WHI%(K7IUeaZK0H=M#yPIf|r79uqnE ze1Z~N_O}vqdQI+qxn=N)EAVu}_~J(mbh?#-7*dK$Zs#P4VPxl}0Wl2dwgIW}A?04{ z!xP5sb-aw!n&)_yWO15i7@8(I4rZR-ZS7yHJrYsd`5>#@_R3Lq06MY;i_tVkvJA~* z7)J()O*?2J;R}dP46;7=G2Y~du1LwGsFJ**aty}G94wg}Zq^rDquG3ah9L43e74TzrAxH5n%6XEVx!{plyp+fu4VQRr`Ov}EDJ<`_ z9c>y)7%z(gCCU^}5(8P7)#(dMKA8kK(HR%d3?>Fw$0I}x#9}`7$z!;@17D< zvAQ4D@3v_9_C&DsrX&W+NGg9?B_b4yF-g{a%G=c{|Ir@J{1?%Z3~_`ac{_VN&f%^= zqN1#3?{YmkCJ|Qch`mYHqGWv_tIq?UFksFOg`P87q)1f|6e9PfI$lfH8?Kow>vPF9M#Zf|U&FFILy;KH^At_f!4%?O&CqWxqKYi*%nxS7 zztla{U4=?>B!w$9OVJ{HS0QRAPB;y&$2NlA*PzdBT7I$~BZ0FHDL30^tL4mfbyGZE zr%UktvzA8u+?Z@BN5HyE|AXlKl|j=vwbwe5mt za|s&fec?%Q8pp`so$=G=aoVW_W!IBuZ7C)_85>^@DTeZisToRe%c@QJypP|qur>|4ZG3zk(LkM5BEEx z_l~EQFB-!2p>FUVw0gTbvtCXD8|CEC8zmuJ)n6B;K}TIMiX5hVCL_hFp=?G>7(9b={5 zot%)}1I^NM1VghVhLeQvlp16>uDs`;iY7?0{aEWWi%xHR@XL^!wV((xB}pQ~Gdyau z4p-QU-mD+DX4g70`surx1xqpt_Z*({EplOOS0OuF6r_=T1h^#K{-@G;sdrF_OUN|_sUcI{wWaLRNi|zw7^y-ot`u_nDqOYff zv+oI;+Rd>3Hh9eeZ|^YBofKJ8@i`?S7#4-@PuILY=nmHl@~G!VFfXZO?SQ{S5Bx0a z$?eqo+xCV=cSYeifsiDUWJMU=9erXE=>D>G!;-w(?=Ea&3anZW-9?e*C03#+hLbmC zeAVLRy&opjNA%8UlP#$<1@&E7S!afOqiQiNu-^H`NBd*zh4eYVVK^bkfq9a)q9S1ers4|A3Md8#bqgI6_L5(0y$he%`q(ri_sElsimR$b zP@)J+Bj(;8cr!HPJEPlxW!6f~k1jj9yM8eDSPaowf}>QPVP#cjVB@)!2JFl-Yvz_M zw$*2<2TOa4D<9AVGwI_A?K98aTBs6@QkINV)?_xlW&JhTm6lQotz$z_JjUQWNpTcT zPz=l?yEF>?dkktIS6k0+s&{E$_t0(;WP-$1*>}Pv6w|$*2)pZ9&GDsNU!V=Ets9Sz z9d)DwAaYp&Vs(fGzx7yE=?!p>>lG9F94E^J zPxFGJ5Mut3ZvwX7(og_Ms&XJjW3Pi7_mR`Sb~3YWkF+o#}hl>2KfF3`+x5 zaB(`VCs>Y_Fp;Me3cGWTQtzjGEGY{r$TXCc+4`@!yZ{H>NDr{BOIRP+Y-?#~o(tt+ zEBr1{eR0tL;5*cNFw`>tH_4KvobWrglk~`_{2t>JeYR2pCu3n-H>Hp=1mb z7(pUw*0M2ugLB54saK%`%wb4e_=EPxJgYxFf5iWw=~jQ9(%w5Q`JZoZ>|Zsm;r=G1 zYHH$7YZsnvwDMXADFKHnApaTPCb0gdtNdvv@IZ4l(diBU2+ZB(Kks!u?Jud7cJSz+ zz5e{zz_pya!=HYqwQGyUNWWJva9m-N zvB0*!uUS7ene_7|Z|euvzf;wy%M(liSvd1%85F ze5-VgD(&|Vy%pJesQ2OLv88Mm_#Q5&-ZetRe^!();)D9&{-K%c?biQGIWBXAF-?O-a>Wd5afj38amtF% zC7Uf*&d*jn@NJI8u+_V*_jH)_)OGe+6LtHNvm!jlUHYqU)+` z@Sv>0e4W?Tjne=B+PaRp!Phkr-7l{zU8pGQ+EUKrbG_Fs5k=h!0g=wb^$sm_v(vrQ za$2tyB}CAFmHyqR5DlXig($v8$01zUd|TO2+J2gzb_*T$=1=e z8V^f3k8>2F5QQj2Av`G3nf=tdqSO2BTi*fv`rWN@%mE>cFao%!?COgcXH&dcxw0+a zTi~bCGc0cD{E4y6Eyu&;R?kB3EsoL8S4VtT9Z@d)-C_eS7*!6+c|M2(JwMETK8bkV zz#Mu!!Y${%M17|1hq%bb|9UeIpuHgfeVqRPXCsvERzbK8Nz$ILDj}Bvd!>QfYeF2t zED;{+jG%fc4>zFyRm#}WJShKM+_mY~Jgwc84GzoY#Y9#&n0FXnsB?YRS-9^#AK}1- z`+m4CE>Y{lUB-tIxZOtmNV9~d12D8KAp)jZuI)UZH3&cx?tb{ZrEKZNwSsHC-+}dh z`UbguOE5(t3Q>qc6iUM{qV_+S|7%igkJG!4`qY~FzYi9Q|AdTqN2xf=tExx{G6zSz zbJW*Uze!N|R+nqbw=^EZS+bMVy zkKeFXqLX;9RuNIv%_2-%0s^(J$tGxwwB$il-0SvwB`s(yD;KBB$kIZ2H1_dC1HC z&O8i!1Y`wcOb$*k4n>f%d`7exYP!=UdmNI84Z-@wczU^0Vdt7p+-?b(kGzowtyga& zHm@57+y&`-!IcP^U{wrLc+%lkM!TI}rTdsXH*8Wo=P0V0FRkb81KvK<80m->6D5+C zXjLR791dfUVUDa<7Sp#@dG#ONGt)sNn6o-VPhy-S+qX{rp`?0y6?euc#ogN_D`Wa) z33E+#dB%;Er)-Q zYQ@?h4&V!De1VbstD0HcyPEpS%Ibmh#B1s}>vsCnHMRXMcWLFf*3?EofRM@vmD;BV2NxRCd8Pe~6LfQ~n+paQdNRi7DJzh!+P67IYVG?#4N zlxsA80H0rj@B+~9s$m{b>lqwqs~YeHaD-&QsKcQLpD<`ojS7Mf;lijAu4Ar((8F-? zzEPNXNJcmx;W{r%Fu>1S5%^yz!u3=cfyX8UKT=j&Y)0$NT*2^uWC_2kC|;0ErNsO4 z#_!~MeumM}KRF_NH@ZhRYX7Xf!19gOg%SRnuhF`IA*F)jk=bCLt{46MXN@Hy{3$QE z)_BkwQQi-G{g{7xqyI^L?Z7-<6AtC|^gq9l zBc6ob8<84_CxBnR1HliR(o!IPZwJX|%n&}J&I@x=0{N6C2s(_aCmw;f)uDR9rJMt? z0INgw8qs~YJ>iBggWHps94H4fMYw+hNHsV&SfF*3Rzi9nE?sI}%6$WjPo_pM_-i~q zC^{NxyCa2by>FxD3vTxl34!Y>(s8aR-ny>Wcs`O)G21&{Ygc|$BkYC*m=8T<4z!q# z^{{-wNfSpe%*f_!iRz>+CnF$GVO)2(~N}953^%C{rYS+j={s zr4DXAFIfNT^_FMb@8AqtwXRerb<;&j+g%stj+A_Nsk{94_ z-OxxI&6iK!V!CXN*}C-AA&GUN<>$Y)_XKsvIBx9)P*y(*0gXE{$Mg~09>oo--t-6))rvF&u2^T7TAz7$7&@LOMld+W zQzTFF42I!wJkQf+Kh8d1L%#}(={IX~&C?rd#v-dAScc;`24_f$!5EH(tGJ|T`Tb(i zui`iBUoEQKv$Z*(A$htqL{LaUp#%xXNP$__XyvjER7~E+hfB-WH20sDlq02t)RWv0<^ma1@j2`E@!UG;p69qJ1`bg1WHv@1rxJQ{qpawdRB8n8LiHuM%A>v zI(WO|k(khjA5JD!0aH|#VkvmTsfjGRmaXp^qT}ibK%|!yv=hr?T@K0T^}vzm&dpQY z-mwk_JCo6S!K-JPSQM*qqRe9Q)wR8Rf8__hI2*e2EGeooC&{WPad79qLY7_McF)1Q zhQEygz90G&M@K)a0JdDrk*P?zZn;Nx?&ty^5Q?XO7pi%xIXQjk)tLA&X*cTsqDD2e z9j#%TK4}i<@JihdON4||GSBh^PRBInCoQ{kL~3;i{bLQ51q^pY_`IZ(YB4po&6N9W7~s$E{$ATJ0yci(JaFV49`n)P>{WN zH)?*;Y*XLw{#`R1teDCALH2TlJclX?GDl&oO3B=ZUGdd_*!NTcxYnbLc3q=#N?H&2 z4)s0i`SI&y>2o~H5PoJ;Q(K!;8}e(gWH9mt+I$fl=P0ll$yA0rJzn=%hg*^I-5%#C zrH|s0ovz`-vu3U6S`010pj1V!?v}RO$mOxN@nD15X41tTHP_u;kg^;KPVow^2og_V zdmcEvv`vRA39!3`l4{Y0`(4cl|3_O-w6@(n;KO;Z{13hCS%M%j9H$r@$9Rl_mwkiv z{sI$_<9n;^o?HKV^5BrhIwZaD_$LXf%wZf!(j2Z!#b3`3Okn`e54T0N<91uFY5CI+ z%x;24GM}(P7V^9fisczqVMK|dIT)k9OAJhdYiegxvKvhOWT~dhZ<-%mQx1WV4%O+B zy9(Lao!xF>Y^EZ}o-YQj|EBhQ zYu7D(&aPLgR|XvI8cm0y$vS^}N~?M6GEEG<)SqT*;^P;~m|PZhjIrJB%-s9dmra6K zLSe^*JjY07tjED)G)WQ?FHp2%o<8@GkB#0Rk9?QpbE(xOH{T@-?y)b76IkJ|jfIB3y)*>arp?wfE%npjHr!#ee)zdO zt^*R2D2gV1+!RHy7)}s8j7cABw#2b@QA|xoo4fA6=QsWYv>%otNPE6VksXA@i>jos zBF-r7oFtKR^pz2x-MP53X3KH?O!_1?BYJ|aP_W=X>TI-#INW7>^woo1=+)@k4VIu7io+RMsB3kN&ksQnM48~(5!%#s-&sLgV-bAFF#Af@t&Rw5Aa000| zQe5EyRvQ66no?Va+oL|V{KkL3o*4@cftNxHF=WQpKNiKiMj`{dmV6Tgdr$stOW zrlcx1;eJ7O0)WAw4VoLOFBN2atNMqi216jxa~rY;>i;v z#irzlio5BSdL!$8`dTHRu{uG!bV#gU-rX2x`{ps7 z!8P4)dp0TQ%z^!NP(+u;agxJmj-*+N2)byPQpJztJ6Kc&4qLZh{_2}Pr9N7ysk$6A ztBN$o)09Loec!v&=DTD7D1JwYhw%a1$`v{NGtV|P1yUS{{wkvs_gDvqDH21e63)`p zl({E9n6vl81k}VghEml3kwW8Ze0Z-PHZ>M(i$;uiVohpDUz0q8Q#?V-yvnh#ugU6A zvDFay;8~MwZ|~_;efS$}F!Dni0ZTZn+1+!TUa#UV*a$j%Jc`@f+vUkqB(K#e`UFG! zhSXcuIHhk4SR1qA!#!v_ZLcn!u|D%(u$NRVLLax{AT%YM51;>P?Y@>j#2C%_pI!WB z4KH?hM)x_K!k{FCmq(TJ(4G3vL3>d3M!M{rw#+Isj?J4GQn6IQ6-5;=mEa`_RxA}0 z0#lPoKVO6~BWxL)mKVjez94BEic3G>t3KADa+UhU5c;%Jz;FgGs z3Eo&pf^&%Z&TQG|O|fg1;B@tH{hPmHfpyMFlN8~WX=G`Yg5b027^Lt{5CfH06Y4p9 z&jDYmCzTLeV3ShV<&_0de_62{*UObk6awcp5wYS%+L}+SG^onqP#h3O5G>D7xJbw{ z%mK}FTXfUlmHnXY>DCLM%Sc9FYLFzwa=4EP!YP*HVB#@I)9>tz=*ok(W(k%it6tL4 zo`ZZR6TG9~N+V;mOL2R$oOzC1->(eyvmNfdExlcFVC&j^UK4Il;yPT;XV2TASZ~-t-(8<_C%@EMfz3 zi4i%5qEw!dzJHNzl#+Hi3Er;jMTlu=9%qd0XXldC-nHrn&wMe~R8=Fw=CYwyj9H}JRsiu{@O{U2Hbk7_5ZOIrI`gJbel zbNQ5iqv6r@!k-%rZ*EljaHD{clbdTjzv05QJ}HGey}xNGu=;MMedvt~?|&lzuT?5x zKgz0oVBTRTLVtBM2c&>LwA608-I`#(K|){(p6^KuOpnCr{|}x6`~=T|jAX1iFdY*Y zn6``wOq0xkDOm6D|8RLQOoCEyPt?R5dOqVIJT^o9fZGA;hs!lX^`mZNQ15~AQ0SOu zKnGC}UrzK2b)Fh$>v(^wx2$JFni8>;hzTU4s)Q6|tG)qwSbfNr`lu)6nQxm07hNP$ zWEq;16qVp8oOZ~H$Lr1=3s>GfK@>zvK%qvVjk&L3? z7{e2s0xJ@ni7=v%+4QV!(Auu1Ee^0 zWAvmrl)%xV%Hp)5(hYl2rq|b;w>V0;%o;{T#5V-gjBvgZOIZGm4n=Eew(aiv2bzCz zXIML}sBoA}DI6gx{CoCE-+w-LM&VBTHe`=CyOd!B->!OXy8c%6viS~esr$0+_;+K! zWtN9zy(ALnM4HDjiVkwLgVqn3Yy0S>|LZy6!4M9uXo@2_j^ikrV2Gfr)h{)ts}3`Y z^?J?LpxNmYwNIgU9+D(^oWd9$r)e^nen0q*Km7tx#cQ^?AHV;3_tSuSSB=+|^NTFW zU^u5xEZuiApQ?795I0r(;+*F2J4GvUmd2!KLDK=wc3Bz|Gd(s?Hgs0ID*8(+XR+4e z^zUzsRV;@2UPsf-4fUG(XMBOiGHi%92jGVTl9>(E_`{Z(qwh+60|T&u?*KlH>K2$% zS|rit8a_R&nTS3TZwgt?WXN_Ma5%Uo6PT(|iZ3Cy5Cj;qLH!4tW9@AGqc{t$QU?@*Oc{o55WR`DgiI9Z@fDPH3LHYUyd01v_qy<~s zAYaRXTY{C$sv6{h%m7U9y9sR9PZ@ zo+~-A_LZ!f%MZ;6YB>ytAtzCr4u6L!*kH!Br)O6LB8La6;&k-sa?@F@sZ$aAh?@0s{ZPI>Pb0uY}`% zUzqc-%=TpSQE$DLP$-uP#rdlQhpRX%&=Rf8?s>4^hw}t+oeV)U;1i1+Ak_k(YUNqqQHwVs++=;PZgp1O4|$fcUt__K(J3wFRD(K z90b99I_mJ3K9%~)rt$@pBIin5>kX+BZ(WQWA638vj2AFT!U&YyF5K}kn^xJj{cU;Z zmX||nvH1kz6i+B5#lq@U-4JPTO{;BnTJCxFrMX~7pWRH43Ueebl8hvhibOl4EJYe= zb&5Tl*@{oatM~X-S6+C(Ze?qP^tVZb&!Z59D40yP_aa*-P0DCpmA0JnUe`^+{J-aW zH#R=p=aCf1>kNG3dj8t^P>Y zQE~;rGs_J=&lLrKk}D{ks3_x?e1olX{=LxkS<1P6$u|jJlytn{`ADwd_;bC+DLFzs zzS-#Ve}zxH-t&oCkCvN!JS{iq{##!B;LQdwo=3+g3Q>qc6rvD?B4|=fn<+_`A6aAT z!cPA8{iSFl1d1hS9QT>0(KNvXg~7|zjNo@5jL6p5X6^iX^s47U1;zAqJetK|yL=v} z7>Qyr3FoCJGUJyPSJbJgeff%(AA^W~V>Yd`ea7be(Wy|E?QV2fJb|Djl@n;5XOttW zt`2F@gN}tYZm*aBGBYA?E@Ash>f8bT4(;t}i*3&4_o}M@(^38MSs(HN)`u;RKh6oo zRKLDz9gMSjP&Ch5ZRck-|8SlM9Y_hMd6vc*p2b*_V1w)_ztAG}z0wR-#dh1`vG-o4 z`hhC+B3I!o;gE#v?0!zK;;G)aOT*p8LRKYB3`_wy!d7tm*f#B(j?MQ}2_1Em#{`9= zWl>Ui6*fKk;%+md>|M5n&+Phc;}xKEjxZDh-m`gurxcEpIEkTKci4U3s*&TXz@ht$ zf*KgTSJu$pa&5{%DTrE3pW94vEr;V%K~TpBf+tKv9MaL*VBWx50jUvoeQxWz`S?S-zYS^ChAS8^ z;0i5sJOiWFNJPOgraiWdF6-}=|E-H!oIJ(R7>g4ON6}pHelkp}f<)A?$M*E-HgemE zp>^U_oTpTtWl0*Bx}?QE;S1#q4%3Yc(vm_^3tK-t?!BZ!gAyGlyS^>RqbRaN7BN8) zM2_KD`RjMy*ytSUNdROo1-`gnj-`Srv;W2Hhb@xQCwlZ zq-4fY%I~k2=+R;dj~<#$U)WCNO#N~DEg?BST*3vB@u8>6z?|Q|S_<4)J%`*Y58B4> z=@HKj1m+JDO}djg+9`Xp92_PPBt}vqL14*uFaGb9QiSX$Y~D{UKH0Vb7QD7Xxx05O59T}FN|)R*id+!?B&W_l zLh)rcBI1^uw#|Rx^+})H3b>ZZx?GD$VuVO5GRAV$>C=OLZC`JDTuFVU#YXrX-S#uK z`#;{*>cl<3XTtm-X3^<#dL1;59si-_sNb^>7X~ruq@AzMm@5iKd~Z9}tG+n@9<)OQ zo}_V(pjigs2{}%w zo70o$i+Ip-&wvS+m)9!9G*C|NH*Eebep^$x8Xcj!TM&F(fX)tQ0sC17@(M zDKv9vHeI%Pwl-l_39oCG}3|6i-XqS}NRnQng7z!bob z$fo^ld*p|jx3B*$43UsbQ#>ZB3{5IDN+k64bwc2;5&5r6*uE+yY)6%_MMA&W=Cd3z zqdpk;x~Vz>6dH4k_Jx-6^vM^qot`X3UcX?CBmc81sgFST{*=ZOUV?15hk;aU*U^!8Z#NHouYu-*v9E^N zUp%GJ{nh>s{I%1ccbWqiSzGP>pPmS;=TEIauV~|NK^up!frmwitivYml2$II<&&Ys z4&WBV_W&+I`Oh_X7}Fsl0m{J}_!~IRq~E?F+R2lHgpKcLw4_PPz$3uPN&fPVuJq>* zYu^vQ%N#HsD7c`#UrS@R|1UOhJe?nEQYtXty+fCGP$RRKo-JR3P^E+ima{2qr@aJXayAF=1WJkRBM;SBoiKYC0c1p>{t-Ouo z;qgUXYRs%4nk#({hsP519T&R6$|WtkX{1Dai7K(SJw7{SG9!>{JbS2=;bku&ehi3|7hD= zVR@h(kLkFTC^!+t==Tf2VvR2_3OSvJm<9&IKSir=eu}9=0_-Jde+kzEQ^qn1Bf9^{ z4YL2-=umW$`@?qU%03-zox+T*suCE*^DHNDGy%s}^~P7U&YA4XFTVa+rt@Iz8r^shspI^O0 z&c~@h0yTY?zmiRF1XlLKPP6V>F00{*w_n-$@x_n0kP;06CvlR%WQHPwq8{F+;mp(8 zCa|D(U_N+066`xheBVf>5A(l3>O6!ml#GOS9u0C8{GSt8PNSjG5TrbxRGKv z9qK*$fz)QfBCDd4G>$u*o_jpGu6}}AFnbP3BqI%}Wj0l|H}lpwcK1b{p)TsSBJwIO z5SYM7T#c3&9L42TmWaDo#s1ms@2_kN;RTguIgZ3xg5pS)po2n_KW;XvqN@GRMF;;_ z(I}+Ta)A^uTBHN4+vaRk4+8nYQj@Nn$?1}^^JT^3AW4?R2?ggV z68r8KCa=kzWD4-8mo`NoSH62DCgA^#(0ky2kfPvpQ&U9$7xl81{l^P`zS!t}Ak-wtFZMQsM<=@KtqY)va5QPd0UpyQggD6BH3Q>qc6rvD? zDExPz=%8EQo_La)nKlv#8+FV-iVGVVfg>qOR4H5%>wZ|j+oI*$6M>9zgc|5M|I+SA z8`Ho(Wd6f%U%C&iea#RgjpI1O;sl9tG%O*R_PIaZg^W&{SnDlWw>cyry(WpBTDF|kL?^JR3nhl^>Bc&|knO?v8eLblW!Y;n}R z$?JdGn#QMeJo$OVSk)Y!gq!ov84o{-8H1dVYVE3l$S2=KM=K;+S_iM`h=+o!jG z7w8e_n1rh?2gXP^Ns1zaVeIsmKX`G@FP>CbMP($EhQmJVo2j?3$C%I6bEY>AZj;w7 zND4Ua5uC&7RK1Ga!!6_}!?R`$tCsq6p)Nrx;uyn076GtAKs+Mf!tPjM+MZE6cV>H?uHHF$xo&TU znz&%+|Fyr=If(|vRSP}tBQ!<3kD)yL|A>_E$^kGdF7*FV2rWjjm|EK>j!&!k&If4I zFP39?hQSz|;Tet#3b#8_XE_zGqP2bWq@nE&>5gJ0+k{ zx{dwUk#i@1`w>vY*nl=`VmL`v6;h%VT>hldSMrBd_9fy`q^OYXK-<#aZr?uhiA7gG z0c7!kxL_JaW1M5SPb}w@3QP-oyF6aOB^9WHjoQ^&J<##Kl!Xzta601ocUm*2+aoKl z9YUdXh_(iL)QPMeaC-na`Ua+-Hx5i;H~>9wk`b5(-+}VJD<@T^XAuS;C|%3JC9H?Y z4op$c;r~(F`ppjQO8H&OGAi$8r;ud@;p!$AXJ2D=Hv1)g0`r>+sWoBm^uqEzi|T+g zMlqFPU%XC?-8C%r!nTc1R)PbWwkhQl5%#BA{@v%n4;uyZH9qHSI87J#zUGi}b8?*C z;aRg*bS=i)e3KlQ2D2Qb{m@0CpKT4&Pl-ZEJVmk+p|U~YJv+SVPjkZTli5Vs*FV*G z;19n5@nV)qXT!sBhc`dZudbe<_7U7dj%VwFfrn4lJ(8Lfp&T&MVUID~P0@W`WJ_>Zjxh1-HeMHYKJ#llofH+Nj6wD3l{OE#>>&wStl!J1p1uyNWVS<=u{oIv+P1 zM8`P_*8}3CLlA{1L?H?{1^*u)+Y5tlH2MyJY|-aeO6tEuE+Ym+jxsV)h(Z*i5QS1e zks3`0`<+`S@{5Lo>wx0ocTN88R#lFn6p~X&RfUD`%`{p1mdb%CTvG>o{BIeDW;jFD zgHsI4sthL*3=P-QHC{i3>oJ=;+J}e(wv20nyx9^|nU*PuqiJ4&Z??{wBOSoI?4K>( zwd?#0aHnvrsJejIJ5HDEpecdGFhY_UR-O2~cgwOvGfcG+HKarNTMb&2j`+?9nwIi? z)ZM~ecK+e)J4On?&r$1YLF1A`QM5x=q-?>h$eD^a-|g~U{au*eN^I4*p*c-scAn6R zwQ3~+CxKwZfxafKO=30e{R5gZ<0;;srq;YM%ByJbY?%GywEp#nzMr9eP|2Ww?V)^G zk1Jdbs=c7U2U7#vZ-VMCYk0qu|3~4*hW61R2n)cD`HZOlKk9k^n`}PprHpU}#tD=I z()IV2tUT0rsQD;uy8%7iWeTL%Y4u80?ytSdrhRWBHi(0%CHp?LjQ4@j*BCF~uVDMt zn@vnN1%&HjAi9r4Aqr85!p#9_+t1E+fm`wOw>;3D1q@7}Ju1a9A}>g!z=_P?ohyB{ zJS8y}m>< zQvidY^;S|dJ$ie1|C>$s*vGb=_rv>pLPV;kSd7Fmnx0aIeN6%}Lkp7#X7VYwKUIJ9e=y)(e;k%iJbJC=Z%#8?O3UO5AI3oXhZq@ z{=j$I%WrKC`5q`AF7GWZI@+$Df#cF(aZEtF zK{=Vwx IX&Sx)W3wI*i+-EpZ{O^ginSvYKY+yra6S%u{eIN&*KFCA}?H)3BvzJBl1XD-zFtWgo?uiDr5`EuOF zhxyPqrAfrMC+NISlGb zq#TB7Pve$e*?yoUde?<*UmY&r4%{`%nJvTNpt@}AV8BTXw}1BX{rL-OH-*LyQdLn# zDekcjMUW*`krWnVq$zVxd@yJ4hY9r&9g@s}DeC`70rg$=GCFg><)Cy~ET$3m7FEw5 z{Gk;Xx=VV@AW7p4j>{M;b25lIRe$scbBVW>#{e|$38f}Pego7L*iRv>OHm`jWfo_U zk2N^uSrE%`ggxUiJ88who}e4uO<_rq$1q-{MWKLeJ~w#k;X2FbRspr1GKWrsIoOeQ z)AZFRS3C<)bc02gP|~u*asok8B7OVsgYOfMKb+j}20yQ?{Evp=ioeF=2~vAG)f?`v zG16{d^U0ZIJHv1m#&Q@h%Q(i%EQN9w)&>h*tx2M-b1}_RF0)t#Xw)U9cX7^ z+4h_jSDrYxwLZkL1(G%eR|QqYcvT{(+}R7-czU^0tCSMe;M8RB+*s6{W3NU%y=m3! zI@^O!H&=56L-LM(Qf{8o*(GF;^*B8(_Y9a&JS-)En6T^3vkx2b&CiD$)d`kAyZr)a zH?7h%#|b3EaTF|azJ)RCrs0a5Uo({~Z#L!I??_60_1F-!HnU7n49RgSgX6F^^Q1@p z>A|qaX`DU#T;IM=t!|D!Zxm=V=eoNKQkFx&RgMrOR$^7WQ%sGGsdsd@G=K_!JVNJF zk6&YFRhXr0zC&NjjkmimbzSoPkM+?KJ0CAXDio*4IL(Pc-cJ`JLVJw2e`VdVZ#xZW z|J`WXPjG_F5ro9xICo^#)gdi<(6KP-bJe~+v=6QquT3C+89S6OU03 zzf!wCBx($tQi7uinUYk3N*johdi3mD#K@HT8>GSYPPQL6x7?3fb}dhEA%xd~Ov$2iwgHcL#ggKBslt7BhE*_B@TT zvMR7FLrE$;fcM3sihj<1rRF2j05_1Qx7Me=1@6N{8Yfv2XE9NdH+%1y@mrhSmC_Jr z=dfAEQhpz9`PaH!G^_if{YtGB$2&b1dgoLGQ4j^1Y`4bJElF6($yXeV7r+P&$9N9t@iIt*0XtqE?p}T$KCVW~__U?z#)T zCq!$T!JfhNWv(3UaW$+rT*%Bw;|!srq?yL4UtU(R{OtDhm?z@*b%Jf-+_crCB+Mr^ zG=;n=KeW{n(Gff87jQM~or0f+wn!5Ph#MN_zRyJ(T|XcM2Ca=$7x4vlV`W5DH+u+? zLAHMQWJmWdPCdY^p;zVJ%geT2aT;46%=c{W^OBf*P|3z=0OB1v?Nv47?88AMdO1SR zl8uSDCB}m0dYHcTAp#G?jeHDD75#&~bDw6O+*04O?)>@-qs#SMhwIu{{Dlf_CX^S^ z)QhhWPp-eaofwTookONILI>tzCs~gP=vgtco{hSAG7P-}VKWeExAD@P6O%)zH4K~# zvPikV5U9l{K5fVmR3H!$s9S%W#hEAVR;{ar-%Fo|6)wiA-0KvS_nMu_-pKp=EH8y&RsHn-qcKu|`&(UPz>3d3ou+PI;%*XbnKVjXCDBl&evQn8>SKb zDg;Y+&A`*TwsOg@oZb!V@WvMcK-5>5RReCPT24v$f)-9+mtg>4r+k{*9U&Rw9FQy7 z>wB96QBb(su8o3zRJa__g4k;Hw4F~0$y@XEB3+$hx-MY%FIchF;_ZVqIJ1Ov(!O-> z=f4<`Ua<5K!*-W_@N@^1x26Zu<&IszKWhmxFKm6oATeGH&2od+^k+wtH9i6Owno#> zFW^jO1DT1Af%g>gH;LAUfS5%SKkzBKVP{z0>yJm-WQb244V(X(i}`g0TWb_!I>7$= zVo6$(5v|ee8v5T(XWpkNq#>K|8xUj%LLc;vxB~w2SKwWIzoa^Xq>ousvyA)4OO!)h8#z%h9{f?Qz{jq+doL#CD)yjHHt;4= z9Y!k)zzp-16sP_yxW}h_2t_WFO{rx zt*+)YBmtnmcvkgpUxoI%Ebc6w_FWTT)|h_zks(YqG!wx@QyD5=&K~0U-j*Kj;Oys! zemvf5UZRnum6u+*JN4fwX!*v#FhxVkz=FyJk+W<&xkI(Bzd=}x@2vJ5!{R9jKJ^^l zCh1eNPM0mqo()pI+I!)zaos^3P`K3ghHV=qQ^-YgNT5Q@Pd6u(eU_~qAwxm?szWiG zm%nS>Ztz%@GBB*WByVaKuVmGK76|q7+*3?URf~41yR~J@>h;ZgOZT4t){20L;-q4j z2pTe?AM7=p5Ffi{cRRH%sOMhUugcE~_el@Fi*1}{q!vsNg715d)ZAWGcW8bFKe`AV`8 za$u@TV@L8}7nh~mZgjbYdd72p2=npg9neWT8KiCWGj~Yhk@+kdr@vz$++blmu4)&y zZFDGJ9h11j(T2GWE+ zY|8PUxb2wokFtv@yKk;h{U#)k5o}rWi%Dxia>Xv7lz^90f-j}sI8$OG%LSs55njGr zruWJ8`RXqkNz4Gtg)ghwOIL_)J|gVIFWpD>&h7tUVmyu3ZwIlnj-yUp;hiT)KuCz1BYCq^>$ zVLwX#*Y|Ip2{Ml1y&ODkSMYW}o+;~f)%|l4SxjUacaQWXDy zbbOFoecj0~6GC11-{jzP1p!`}lZTYD#RC)zNik-ukz=kcSVVzQ3KDY3M9D4qW8K#p z*1}S7IZ<|I9Wfacho}LS`~?@gW)kY(fnPc7LKTbn_5803)M=R}tzjaG;8N*{@!4DY zckaACsA-ojaHVQ^7K}IdM{R~kQl3gkfy%#12fG|R3xY2YYuKxUFUq>;2dt9sKSJkT z$;DR@78&|sC!M78@-P-(@PrtoaTe3C4FOZ&z$Xn{ufu<1*Qz~~5xR3@mcd3Sz#p($ zk$55uap6&F^_zNnL*m168})5}Fgzt*pVU%>^PY=`GYnok5}4DTuV&9GJl1vK>d~@} z;P%sawaj{>s?vp!I;taC)*HuRITM4v8j~(_0iNifOY7TX)e#0v`?ZNrLh=MtuuKxD zAmE=pKq??vMzdfFqOsWH$aA5O4kUwrtbn4P&mE z(8r;NtV(w^TBk~(=?Cng zoRjlc{Ks~MYN=FYQMB0Qs`K9?$axwLN^q(@lpkwddgb&Y|GdU$g|?|8fh=+mJH_~8 z+aD!|oIvNvnc3dNU3Pp!$(_U@lyrwBGL)n$RJCBtuJ4V1n|=4u2Psy<8;-*bG{al_ z8M4qDI{E+7n{amHDtMCn}tJe-X)B2}A;u95kD6Kx{|J2i~)V!(750@dr+9 zn8fe=I!f!i3b|*7yRQqH8_oYLRKWiO$%Q`=7jj>Bz>Sa`#)~`&?osbRSF_qkaK3Op zgz=Q05U}s1j5=b7N^YFUR6pLKzak$YS)*pdC;Wq!dw3N187#JMo*^30KV9gyTUq9S_^l{u5NfMkcPZ`89e>nRAX%Q{i*lIBH}_U1OC|J-qbV z*M;Qo?`2>Mg*5U6tp44*f%ES49wsNvhqKtL@=)PsF7#e2|i;IE2vGq+ptu#wk~% zDw^JC_I4)ktEmH)T#u#%fMoYP4o$w5s2(<%c(pj3Yj3^)YPID0O$DZBlSQ{Cc*i6g z-xhoT&41@{lWH1fMz}?yCK??%zWXK7O+@}5o>hv))C4apbIBTSZe~)bdQgCbyLBHg zv-EKaW7DampyznXd!n=&6t%1&UyKwxUO;)3!fr<6^qZa5QukDY8<*S|SCY9wC_b)d z-DUr3K2Yc<-p6A-jm0D$N~PH-&wH;yW1pS0vSU2=_cElneZ;Z3;h*L{&p-a?*0X@J z5`ACSvhNGgg6WdK(Ij!aRofpb65I;dg{o*6mJukZy4-WVOCZXaeGl7`Wt?%-r#BTH z&-auDy2~P?E0`gU@RTb@cYhqwF@4Oa0x!>)TD*Q3Rj@c=ftunvlXCRwlnxuMV~mhF2ag7A%)rIDZR>+gTgU(X@YJVjKPGYp_~h@km69^p(9LEJdGM5;O1UWlD!n4M87 zERIt|$J~wGa_aoG+DK0G*>vsMNu)HRrQb?C>kkytXCr)kh5E`i5681Y@W4Syz%d_z z&9_C@gjLHj$BLG>^HO6PPl49!m8JcJS)w&&V$I&^5Cy^ zHnu|~CFXA*m(L=%im>NTvHGsrO1!v#8u2T?$>$68i=&AEcCStz)J2r6l1`u_1}wAx zP-Bz@@uS)5zg>t2f)tCRUvG@$Sm4Pc3#TSn#wm$MDUl~4#xg`#%#{N!z&sY6g`+2_ ziAs(`qRLg7m12#O-r*n9TppovMsSVqA)+Q`mhP7{Ug>%v&2krk2j?JRVk$38z`;fem z@aiT+=Mb0>gqB#jJx3ZN6HhFpB1VraBczZ(66pyHj3ky-j9e7}>){6#R8T}!Kte<- z_Wtq_+TPY>vrp2=e?QJ0@9ApwF*i3eH^+=lq6|DBCf?_bFDIz3%Wzc2M4nn4!27gzxA*D@2Qt85>Rq*LsyS=#wLcCot(|Au!vhS% zNpf1?{wYPCE05{6hNbS11Ta!l`?9>EE(yY_*PwpuBIAn1*nN@CM4-}F@y!crsJeNv zo@-HxqG>wCa1r-643trf9)gCA7K=%_7 zclwqmsF5emStK}$fKcK$ag>D-@6utpmznn}W;Mn5AmcjcZ%oOGTqZUH6mKBE9Y=i2 zjboHrdafB#V0;4*M@dKEdCR%#Wv-j9TkBFXe--$qyhp6y#@t-jL+LfUw0$U@ zKR7NfqbRJgv3TlGn=R+AG`RZqb-+qTD*@j-z|*lv3ZAS@64wFq()mvvm{Rh=^9TZG zUdBaX0%!dSo`lKxh$KD;$=7Z%^Fd6DCseuF7v9wlHtQPP95Cq4m8x` zpoI#!J%(RNXB4#ns30#0t`3$AdY)b-iTcVV@*-h0oH38h$0dUN_2%8wHV* zyjd%}%^9&0jy|om-OX>w#~*(9Xjj{Wad%yqkF`}!G~V_OwuyYPhsF#SNgvzo_9KkD zZEm7Qpt980P1=WGDMX}7eW;%fqflP6Prj>6(jQHCa0SUyLYKu1q$3K;{SfS&jLGg; z;V0v!Hu6qTORx3bFDZ|CMNI~DNB0bU{)tlm2Uyl@m1Am&?1_V`tNXix4Tqb6GWXL(s9 zXZW?BXON=|{wD|8`RD!GVgF8?o%zbKDPK@u5abSMF4@qs5DS3~{>tK26Fh&{e9bl% zIKRVARx-sL_7SO zIAxrtS08LIx1<5x$L7vwq4P%PW?v5pG1hVXF^hOer1JGFlXo<74J<+TwXZ-0!FJ16 zP+z8JIc4y6lmTRp345d|3A+gs(VRG)+T^iX?VI&CKLzQ8^Qe~5)C@cuS5FwPs9`HO zZJ)r@4an0AfkG1|_c=sfow^yRz#2J!7(H21!{UF3Z>`&$TlzGa56e?C%g%Wo@6#wL ztV}7P&Kl!>7#M^p=s3qK?Wb&RbmZ?vSk>lMp|mGPMKo4bDWHZWWEFS|(P?41G$Ein zhV`48ihXF1^SeK+TrB5x)L$AJhxwgP&IG2QISF6Y02&FI(mkoUcD*k63J}VQ`0wFR>;{d$w>iSrL&jdSIW_RH4O1THZ%ao%@PgE&q>426 zbiAL`9`^)1^U5N@${+Cb@4Ccu26`0UWfbeckS3*D>k7{@9kBiRs@(| zf>d?i!he0J3ek2r$i<+5$&s1j7)?&}s(bt#FY~4{9F>ZOl)mEv=W~Fx_HiK^ErXj+ zn7vB%D^PXWltmR&EmBe-dG>?JLDsHFs*SmQcq|{gP6H4`MUN$fj-W)9yjn3EF4DkX zFdBxm*@C6=m&4+oV4cs7v)2ym@w>dR7D_}PpCf^bAq%MHQRxS-s>3!fx|counkwgc zMmV{|sEhjcF@KAKGfjycUN!SMU0htfyex5sI#2SEPjfs3`|mqL*{!$_r&ogRMt=~6 zYX?&9bd&)2wE@o-T}fvL?jn4-$P~98pIhFMe(o(RS87Fhok9`Y*2gMEL3 zF4f1=K#}Qv2Q2h)EMj-}1%JU@C(5-LV%yBBpzr+lUX{QN7Sy^Qzy$B;L3Iz zMGWq@hsVaY_K?B9-aVbSib}~^C^>SD=<=)Q>_2RHZ}X(--@T{;^YQ=<+kOO|8;2_&zEtRs0~7ZF&%yY6>qpgPp1*5H%)^{H)F-i?!MhuAmTHd9nB5H%F2 z%@?c+{X{ThRj&KwzjerxP}5t_mX?I%tSrIKd|0E|-kU($%R%OD14`3{RD~9M>(y%M zgXiMj*MWBBvG!~L8|(Lq&F@o-?~eIqzZGy0W-&xYubu@?A=-RjrVkN=Jh3C|Ii7m= zj$i{zc4TOkK0%#d-KRrj(BuWXh&Krc{T3hg5W;+aO&+kq2;HdLg4ROAl)QoD+4{6V9IO3%lWn)MGz@MQlPV} zVFo{129Sm>yD>{%K+Qz@>AqTf7n&~B_F?ZbbXhyOC&Lg*;K(5q!8cEjAi4f4LxA}g ze$qDv@ySwUM!HN9Ye(D~7QY!^lK)jPn^93-*hG=cJ!F_s>UeJcMARnbZ*|w7Pu^RGZAqT58&&tcA3%#6d zUX}|Qz|fKoGlXy#$0+xxrQDdFKW-#F#uQXqBhx-ap^HEg^wBb?fiS#x|sBx8uZE z0Pe-xAD0%)@R~YO@?*HA3|(V=(|3fWCqfs})v?Vb z&m+y0^<6Ue9D`B~;lu06TmqO+ev&`Jxfv(Y)zlB>7P{ygb}sE^<9r|1$S~!MCE|>T zccmYJj|(7yut{(o`zNS>OHL)0gEN+x)b}=M6H`AWhqzHL zeQo1$n0J~(P>_RbaMtw7vfMA=cJYUt-E*Ei^S#+u?}3Ns{v|_2 zGP4aAr>88N1&Fa8yICO%UkEieF>hQz<$Qy(@LSZq4@dPSe2n8Pi{nV$wD@&lb-hM; z&F{Uy zC}7UENOXgL>G%XnBX6xeoK~+oUtV6&dhYqMurdv|E<+>-j|bvqC)uX<7+luI`4+IJ zJ`H`o7i8cWP2`YeLKWUa67ODUl6=BRG+s0KIv40fdrJ}=+Uj+&VRfA16my7cdPA+1 zSM#Pl!Ovd$n5Rzh*F0U87haF`b-r%zLgn7NH#56qf!%%6-<}n&^ux_j`sDoF`Z_=! zWcU_+sQX-wVZSKxo5If0`Rug1c`&rR-5xLUDol)b^$R=kqhVbXZ~J4Bdhfi3ONQFZ zYx}RA_v-#NpTkGVbbg|6F28A_gRXASoba+hpwFT_Va6Re#UFL%!i-Mups zJYh?FDt_;~Ob}1lW$!_oI$tKM!?qK>Uy*0)ie2l~Ch*auRwd{YR45)$+G@}n3!Vflwj8iDsVmqX(Hq}mb z>0z_IXw|YH-@2UUEgKh#kvh`vFq=S3LYf+AlG3f32wR@#E4ezF7N&-`!0@saO=JIX z1rh5eUb;ERrfrwoC2jHFZRAu+F}>$PRS-p$$Ryj4GPlaaybZG7)kc+JX#9zIs{K9- zJbiS*EZdZeB@z!+65}O`eGjrPe6t^ofvX_j@cw1&NOSh@e_f9&9Rp0Vr1}x6tkwPQ zmv{jfuBa+G=!_}(lz}l0TERr6SEI|L9XEGHodpPW6L+}3%Ry&ER>N!7!zVn$T=zH0 z*M0a|=1boE(zPahvbjg+M zDCdD85P(#)h9$6!OM2SQSJP8inf$8~-&8G%-7wJy088HDTgBzV-`x1kH2lr$1h{j~ z)90!6@Tm^-YvTl`2PtT!+KM3kr_+KL4UmRcvG9hNqLzHkzPGnz&0=!V+U*>ZeOxQE z%>{FBmFU~XYw?KLVJRXq=#Kb>9u-Hn`qd`i zzNA2)(i!o1Gw*RsVGn`zB7xH3G5fV9KBkI093L;Va4%wGbW4ak0WnTYLPJ1m7Vw0R zB<@ez(Uf+5uA=5W4W1`t>LdDMxgm~%H@m3Q38kvDylvxGg_f@AkH5 z@TZZnH|0FQrF0)>J>ItTsPB{fn<@N%v{Q%#d&m0T5BwCkeS;j%KK8gTjICdMu07x^ z|B)&Q%{l&(+v5PzX4%R=TA;e#_pSSLQ4c8l5X_^UT2c0hV5&7RntP8`%Wl|5cN{bMB66Pk zYB$Xsbnra_)22$9bvu1XM_DfYcB|UkF8sHoz$6}?MJNd?CtjA%grb0QVP4tmv{VS< zSB91DHkbcP?qHY~y6>%Ftdf_!8o>L=$h-nB!*`Nzq>0RO?GoJ##n-#<3=L$z&0cy( zYtF@=3B1qUyx0?5jb_}=wU@`Dpzjv&$eTjMv~Uj%lYOS(W3UWtM;|R4exnetVAljt zzi5RksicHqC<`;zWyd`EN9XO981m`AA9UkMKBO50x>u)^C&a;qmRa(zAm406!hA@gG|ido3cFOf zR_Q(2)zWkKVf=dR=WS~C>b?jmowr=Kns!=#%BvV7;}<=3qz=t1>P1uK~{E5 z4^6_<%7auK0KMzZj%fa~IL=rqz=C_^#kK8f&Y0a;v)$(U{JNcY=lREzLomcD6{Tws zwF8E2evlS2Q~^ljeJ{JXvY+#!2tzE+T~73#E0GxKFEZ-2JJ$1vHoF{BP59KOY4@Dv z21KE6OwSe)viKZTWh4(lJuMm0!}rF-I6eHe3-uVv6%Dbw_sT|YCcOkn&_58g+{V5m zs7Kw_ea^`UX*8J5l4Ox5+=kGT>Tc$5{9X$xi?7j+>J!os1qQKQP(3?d>LcG3TQ8JK zL0&jdkmo}v*nR&mHT&QrX$ZdH>zEvtx z>$Ys^Hn!B+Ue7X_?re1FL!!~7jA$n$St!Veu{7g0ld_8Z-{&T3i;1L)WDatM4AFyo zOf4?|fdiy#$SZtHC;l4Ti7Xg)BCtoOpNW%8@^|9y1eIYdLJ}?AFDnBx-yOTV7A3Jj zG=leOA>VS}j`)-oV71Y3hiyZ7#1FOTlMr~E-bB^%ln|J)NbNX8B6&R@xcvw{!DGGP zkKXviegYZh0#hQtn>qsn#ujcRC~^}RU)7RA(3PO4!mL}VIEzmmyX^qb=SFS5Umv;_0WEF4+ zoj3v#WQKH8e`>~=HiH*;)SLEvjt}|NA#_27f0F;>S*9I8(Xluc=aUm|h$E~`Hv)4z zmL6<@MXTmeP#uK!RRe~9*35G@c>(S_jlE{;wf906mUF;`y;4P&a7UwEv|s zGGr8M02@Q$nrp&`smJl~K3;^ey^E^U^Xivh$JwZ%gqsoBp@##D%{37lMNjQGo%&93 zI_V3cl|8dcx6h8eUu!Cle~WA1tF4JT>fijwZ4m_r^mfTn7AZ{BB7l=Gr3uG;zOO4r|6{+c;{;@<){iCyT>f{q@+ z4A^&2vuLxm?o;Ui zP=8N;s4~7n73SIzmnjaMfG5Mk>l8XoX3CXf3tRTN!m8RgJa3-b9WL14e!_j99|yX3 zGuyFtO!zzbTNk_aXdUTYeVy%~tAXK*Exsx4vrf$Z0)b`d`vqc0+BW}!`QO{0i@!BO z1iObv=%=sGAf~W9p!OG|pkJ49aX|L+SS62q4Ler?Zeg!ova3t+1&(!&PPMb3`*&ND z6ByjjUWW|;c>c&XSE)JrD((qSW5<*?tPE&x9(Xg(fJbR^)sG>$shh(7p#I%s7A>Q6 zmj{*)BWekd?$|=07l(#)0g|Fm0;yjcuQ}iw0am}vKYEdu<+CP)nI`f(ypU_v0v*f4Np!>G;?g&r5 znbt1Xz~>+fB=MoSg{LddT6}#vFeAT3-o+r?d8D}rU>Wjw&hCbsem{zy{~ADdzv`w0 zTt;DECmnkzk#gveGQh&WtZ_r7u-Z1-XU)prK(fGf7FuJgBoLuy4TGYaZ#*f@$Z#3d z_(L1SjJn6BHRxxg-1#*99pAXm1k97YNjvoK))dU#dL%Q-Cz(@={svb3uY?P#)L)sVg3@*_JjB>ND9Q31yATb1eNi0H6-XK1P8Z?P26lut&Lw zogNC*{Ij^-I#K0?wiopDy!4dD!ha&K!%E zO;`}&FEd|7g7L(p6A7-1On$$01>XJW15^=HKejaW6t0bLY!=V8sR+1$WSeDG(ARE{ zNM$t+K~l1iVK5uxS*R;F+P}K)EZPtq*#PIKhNZe0v`DigUAY~!mERfzErT{2!C0@u z<9Ks_h(TlPIer$*q!CHQ2mTPpG$*C~fhrTcu<|lkfx)R*imSj>B9${$RW-v@4L}oa zy|fHgKz3=ht%uM;f9)?AVtPzv45cn8tIHx}w8?h0=E*!UQ*lXklGC#VFGv*JfD2vx z`5rO+I(Zl;^Ck$*VEm@1#`)8|uq6e_rC1&unTwOnSDaiAfbFpL2TD-*%#h2N0c_b? z%ByX&Kj0c{N9D4;qqY*iqLs!Kfu<%fYL$o>zGMx5h7*0GI_$r$))Ms_r2h8$s^{jx z8((~>Q(f<3>eqvyOjH1s{D&+2k44THR=kgRoH>S|H@dT_rc_%5VWVCe;Yw?WB^uQR zCJx;($2pQNF6#ih+68*uLHpsW#Ou$DmPI!`+@<9ft7V}xRD__kL_WOlY>ld@#>40y zGgJuRsR_<<+itR_$KnjOkTRA~GZH4J>VRew&73M&&ZzgD35h8CsbTA$)9bXbdyH5D z*_;#k#3C_|F{gN!c%~bv0$|20^=qo$)bDIc-R)x$M){s z9C4hWdW<%9MhMDj^|g+T~->VH+h?*3RAoSAF}E;{3Xs`w^s2Y6X%RyB;n7OSpIk zl;Tv{D}{UF!~8HVYsJL}DSJ0_(vzlMq;8`jddz}R?R5bNkaTeie5S ziY=!6TMKEDK&Gpa6AnKzSnS>m4^iH$PT&UX_r2Jg>BZsaC|zAjVm=cxAr{ZFJK9pe zJqkVDyRTyNaRM)Pk1-0(-jt);v@=*BcW9M_U4QB7yJ9xB$tsF~$8-nzsHR=O)eZZM zO=l~Y#fQq)cdH9`Lgif^T#c=LX#W}NZmcb7){L|O5v*T zU6bFyc=mW^r=Hkq1eS=YC^(8V;=p0VBcjaCbB?WN_H|nJ++5U5*Cre-Lzxn{P$D&X zx9fx?Y?pE4yh49dw0GgR)0saKq^x#EaW?P$Jv4COsaivKj=y|7uy5(k6`t~!1&Y&g zyfl=-#K=8+HomiwOk;EJO<2W2F3@55s;Z)XP0>5*@EM9mR+5Qm3KVSR`k1fLP35%G zuhM&&LWeHwc}pG;#?XhUy&P2)833Fxg;y+j^rtu)|FjcFVyW*z4a>6%v|ejoIep#~ezxjVx@wgX)V2E+r0<<2{++!%}JY@1B%#hD2Be?1m&?+oIOCQonG6y>c_i6`-pOYL?sy(GWYtpuq zu220Dsm8+wFA+dPEX2L}83N#jtgOTfTZz;_x++pFFAs84gkK%Qvp>5Vd^z0&JAEpV z`N9C~yAxH|jc1x02aBP#I5bf`cAzrJs=!H>V$q28-(ttSvu5qRT0eEc&5AbYqjjjm z$Q;6nS?~}zQ3=eM=<77SU!L)Qqq}xS47;cxtAZ!HKzHmx;5g9Ptvkj>Vr?IHM(FYe zv~{c6@-)gge3*)@5+ck~?P1cN{^jC!QO!f3E z8!hW?FZHvp^){g6k|CSM<8L0oy8;~FB9+mBff120&GpITZ$Whur%&+mB?1uOr*YJD zc*b}#FxB-(@q@@(1WDlG>@p!-HkF@T4?Ki=lnX3m6eVCWunO#|pX5Kc%+-sR*Uh~q zPlrgBU&y8jx(IIE>bEyi|F}|4v^2S^-bmXzKew(WKZtx;bkKvHKt&&5g&3SpR-~c? zl@L@lI|-82rBI(67htq%{E)Mk#~{LJe6$6F`x8$YO4tQVXFLPY|6SM78JD z{I0M=%%QhjXHg~4jDPe=jp(fR{R(4qwdJv26Pdk)zrPANJv+*50regwyd9KLR#D5W zCkb+Cy>YGf0jCIUz+nARwO`3yyRtfDqi71=f!uDdo2qNW>mQ0wQihmx&-^X5^0k1s z@!o`?Gz|B^L&m@nOxWK&)Jj_Qe3anyt(IQF>QjWw3l_PwC zw;&3V1j9Zo@2R%Ck%DeExGSL59(32yDoS7h$Q)>els5PLLF|6|9~V>5jH$}UXgjYf z>sGT3kDm^3Z8CiH_cKlM33Qcb52*Sz`$MGoX&O079)jf?&!bbNqj(a26S%rku^1B< zM#3IoR?NWNSYM9JkDbGR#lbNT9JXqtjdA}AwI;-?>i;fpXnpy(aeI7RB`6uSu_`H; z=At}86uNiVQ#8&~s9sD!zGD1(G(rcGNc zU;UbXnX*y+Cl|J?_VRB#S@4RgL@d>}(1o`JRT3Q)h|WqbxRf8ZO=!`&-DMldgnjS} z)api}(S)i%X{t+<)ZhNI+%uHsKZ*SQ?yjc56kSxovf(Th(z`FyC9*9s4}9sVOSb8% zB)JzB45{SNUq$ZOX^URIsZDkU5$qk+vbTwT(os`Ts=4HVqd9pm*yRQldpbzzfCX9z zvvRC?xslS`22%ERp`;b#MM$pGF;IFZ3(ichpE7)BpR`>9wc zwIC%{JR@rWNFso6}+QgrwE z*}^D4V9N)6*(+M0e{Jfvor|oHEs9Ryn0x>Q*Qe4e*9{1EG?5gy^@}<6yo0B9>M+KXcNA=< zh$#1C`NP9^IWRKtvx|6Vs_4kSe*CR4_gW95=vog(c>pHQiabgWC{AID11bw9g4E;mJ^Su}bgBHbB)f};9_@s+#jY7J^* zJnq6StAqMHd^byCp^9)GG~kQ?Yp5@QLwHcBHn}k5y+)4HvB7me z3ofEWxur3;%5v%SNV}OFhge+n<+^+F2JhhP;u-uC#Se4G@r#`xqjK1wNviToe5*4u zOIEatM_Y^FRzuM9=1gI3lgLY}wRfG@}GNd;nRx z3_A{Ef?7^pkz7S@$zUo&zCW0!rcqi6^P5E7F_>rRR1hu3rCXsn;<`NNveMy%Tz{6s|$Xt;Cs z@mpHc#WG_lKf=$Or2Mj8?ZoCW5y|MWZoW>*|mzo6svOL$ zjWxEvJg1i*uvYv{RL%!gH8BayyS1A3b46cqi>X$f-{!HGw!EE^zP_;*j65bbr{NKH zAe}_y5q9SAHob1n_y@yb??plF;WzE^M69h+BsUnI2aAKbn+P%(wD~cNkFa>%!9WMmeib5oxApzLK1{M62M-_k{mR)>?3T z(DebGQSwkzr~ouH$Gqppv_7?)!M{v8lJ4Iipfwni|JF-1wR$|$ zm{>luz+*0lW{Oe7rQNF|b#zl2U(Q-fHk#GH^S;NpD43CxGjUWxWYA3DXp2iq&@5fo z_pG?V$z}BCV3UdU?Ga$cj6FatZV*ZNExUn_d{bRFyt-IJg)7JS{=>Jzw)HI8nkkoT zeV?Cjvvc2v6n0j$(_ zlc6YO6*yR;RY8r7s5GqL>bjZ_he+(O+RRzP$s@y#%wb~fo#|O3%`Zn^r}|UmH~73o z_!uKx&9?_DUiJVTsNCxW@PXO6&3%)%y*{ zpr5#kvlA3bgqlG{A5m~6Min=ysS8V?t6nkxwml+nhhy=RcHxvgWXwTwS3`EN8V||M z@X21`MZ+zajma;s$#C(ZO{sX!?d2D3?&@ua2O&82Z27C7ou^dVxtp*BJvB|AfwwQM z9+gi{Z$@@jLITlV(hXQVg1fLS!y2~$S9QPVh)Z&ag|A@EE^wonGOdvnlg;@*jJ;EE zWntT`-7!1q*iJfj(y?vZwyhPTV>>Ih)v;~cw(Xtwd;jm>r+XdDT2=F4R?UN1&$!1m z#;y5S?b`?D#wKz*hTNkVBv@V`NX^g%4|Y1;TGG7wXd#BM{;-_qYMv|1jM?pB_D}6b zg08yQjvtyrcI4~^${Rwl`z$cS4VTi_WCbzXoytcg*KF~p=Q~IFZX|z1*?7Wo+Z7Fd z{p}-C+O?s%3Cz&-o%*k{4%Otk`1{t!{i!a3`cFE-guG0uSxQ? zlzSayYWLv&oq%5E3gn$QcdXmQ+}aKm+1D8ouRN^GvgV4gJPISw>R!m=ulvQJI73aP zw^pLJS5?4|i>T~;k7z>Z$Zf{V-z4of#i{ou3i85AZ|PW9nK&v}PkSOBGu^#bcChx&>Vr&y907kUb z+x&I>#I1V^lPR9%6L(b;eHMc`1w`ljQEZ$8j>3K{YJO z@}|Zy)@=6iCTi!Q3bP0NbCwjb%f#$zcVm%GTxf+mniIPjfM?sMG6@{R(WC6#&<|7M zvSAA|PgVlxA?DmK1C(sEq=#&B%aiPedk-b|*7lJ4N*^)L!BCZ}aEC9DA(6}kGzCTC z$%$=zD(uY1#|W;?)YwfF=|nVzpHureN-D{*4(Y$WSkgJ2FTYe(&8vN0&bN<2N#1=c zo~l{eo$9Q&ayvt_?Xnf?-uc4sQt>7+Ou`m70aI;LA4*>o(->%X7Wo{!5ab61%*K0^ z&GhtLV{w}Ld?j0gR@)btjlx=F29M;E+3N+9SNIZny$^KY2hOPOpjF%u%2S7T(W=}5 zVv3oce!uJ`Qo!8Hcb`zLKM2RK!I~j3s529lW}#t(2AB0vjE* z-S8B_1*B4g;_@mu$$Bm>3nQ&0C-~-zMfzB35I@D%ru-sqE9J2Vw|)J5B^P}G7cc0e zonC!VNswQdADtPIrSR3m;iJ3fonUyDiI<%?MtZk`M=hp|Wt4&a47emz6+sfn74JcP z(hQ8VA|hL+dJF9~V?yw&96S^9EdDd>qB}G_-QF@U8iuQ=sSlq5Rw?^U4*2?jEmVA~rb`yC)D(2JKx@LARE0896HnQ>v1xs3Cx>*Y&Ape; zK3>6*jIOL|;GnSI3D}$6F4{O2ULN-}-LRU|Z`O_#<%xk1lWO@8tA9c?GlyKosrc%D z>dW6IUQKxgzql1)$sBSQFfbPBuKi!)Ru?RHJ)Ess#iB=h@F`yyq=_$~Yx{omsxFU7 znrV!RbdWko*q;8~ZmGVQ@0l5l_gpf124iWIj1H>Bf+1}}VW^Da_Vm{qL3J7V!dF12 zMqCc{JQDku6w}`wCce^Hy-?bszsU;nz%=MWGV5t5ZLuB<%kDdpRj6t!i*4{b6pF73 zVV3ghCDl|2cZ4#Gng*Uil?wakO{X zhB0~n&@m{#j@YFCETRS4IV=pKP%hwa;XPz~5Spc%$%R-|GNgZ0PjoG;<(6;5y;?ed z8zss6S1&901UY*cnK+#0%N+}Rz{G*T9R(Vr{DNU*arm@xk~Vbf)TZ0$lpb=Ri!|mt z2vL)cf22WOL0x#*j^a1Z^2C<~Oo8;wRr#3iy#~U_TzhVX)a1i{OH07j*_tR1zrR*! zBMMR;sDQ&HfLG*1d)skLz(D|MJ|yM*E3EWO3UCdnmNgb)R(eRk z?A(F5mu2PKwh@T3ga^@=bG49>03%r_F8P~sdkE(7Bd#}wprQ#WtV~zItL-pY< zC?IjODOv&-OgvAuFop%;QG4T>NV8z3LUlFzs|X#zy;b$IPg4!4PJ>Z8g3}b~YI5{G)ZEyb@V}lv0{gFif?gJG8z-qmq0>Oy!+S9=WmfJq61Iv~~F3#bKZJ&tao1Q+W;1_jzB&Oj|C{~WLXaxy;X zqwhkL1$E9mv1lX2a*)s1O9F4&qNKJZ%UK4fZ!|QAb}U{H-R9T6|11yPLs-Qg3&8BC zNWb}Gkk}!x@U89F^0KR^L1X@=@}mTyI&|Kyfqt~p7S%q&$X#Wh>S{=Z+RbX`A+yWq zHzh)c_4=D)K8zg2iJRtNEBm85{8R_pCkJk@F4V|CYCx zl{ssyus1xq<#pIJNml>d+@y%Nf!o~skpSuT=mL>QH)_&H5VNoNZi3kOk>m4F2=k<7 zj`U!xE)Oj^AR!Phj>d~s6r-)mB-ZF{?`AP*!cK)CigpOh6J;QJu`3U zXX71)AsO%@;VeD&u=IFFMexh^h8ozZUU>dRB!$KWtA^Bwn=ya>lC*O4OtaG> zkqXqo;%>B8&YHGb&l58x+Sh?WL8bpWYc{|1>XOpa)3RUA`HN07R)k9 z%rrM$%!w^#t0zPLmbA>{g(T--5LHSgzYzM=+DlO>J`+Z1QAskQ2;N6kRB@Zq7>~i+ zl>=dEduhu>4-ntDvM5HPjx`tn*0D)hs7yD~u0Fy1MPeV4#}tSckb+k4yO|yMx1h>eEL#RvjdAQ0 z)F<%$YA-k$R{`aqiJYn}I)ur%eDAxaHPG z&9`}7Pu7~nc~@mGeHFy~5nUp@g?#EU3-_g^zx649_Hh^yJexpgQv{x#OBR5v0X*xl zv{r2rxj^oTo47FH2B)AWs1O0Go&L1y8K?$!GM8P36FT@KD}$<`>8iOU5rBy$zqNN9 z!KpOo79GE3QW)S4PSemiGPO^U4Oy=#zJXjd7@3KR&Y3Rc!5OZ+;cV3!o4FN5d ze3RF)x-L-;StM+>AriNXrZUKwPNe@$^T3w0r>umk@MNy#%XSQBwH_nz^l_3^uT_fs z;|eIR1FVd$^8VvP{lMEJ!u^_8H^}yW>d0@C6vq*a?_-Z1z``f-h>olwdOt<9K_-+q zrFOlO(_?w|fqs335V`{&VWyFS>;Q;qcZq8eoDK{Ow~^W{d)eLMak?R`Km+?2B1yiB z#NCs_30Eur(OZkS&S87amCCVtxp5Mj3@J$3PmtjZD2*P_1{|e#8GMrMWDJZPG*(ax zWVjx>kQ7umnpKu?U9{uOA-(lxg2txSXH1>JP~d;N_FaV2Q{>-3Ve-eTqJDdm(X`^W zCs%!qPEz%uXcsMs0;*Vq02*(U6n!J2bi-xU56veo<;AN58q`#ot5rnrTdj*vJ%379 z%`a%!)I3RW5(8MFgvgRbyLP9I>I8sv37(L2^aJ;1ZZt&ULv<#mo0-i&C^~75w^cnA zVm0p@YBhK;lsB@o`y=HUnoY~5hm)RRLs} zr$pa{aS{)s61{_F3YEW;esZ&9+M<{*PIekJ&cI>dd&Dc>o% zksnL4RVYmqOL*Oo4QyjNyY3oRaQA>Yrev=s#zNa$ln})8cV;U-U@b`OM;fO$yGVj; zHj`i+s1N&7L;O@X}xasY3& zJN%=Lvi$eb0fvi)Y|jRr&23!%iQ-fC$3chnliR0F-0!+pRKH}sy5yYj zTeeiqA+rm}@u$J%>M^BCsG_r4sJ)cG+!CnT5e}MhSIs}LFY_gA>a&QvVC+V zS94_M6>K3-n$^;>{8m*OZ(Kru8!WIth0LIT5bPYcA*?z14<*PP@(K{tbeFW$q z-n8EP(O1688XU7`evyUj$(#dG&+QS)VeQ>1y3brO7{xQGR>rq#iPxo&A@4Q)FFn9g- zqd@q>QxTfCmGU0%{c`~nm91g!a~EY2u2OoYeY}R|w*w|EH73fA$>F^Zx(@CLAHY-( zSZj4!rNTJQWuM&R@ppiMsh3aGr~lHJ(Z|-V?OO11(?uf=SLdePLNixF*VJ7*%W2x- zJ>@PY9fjyayq#nhSY=`d6Y|;{L~(Z2Oz+>wOv#xT|7;naNROy^q@*OvAQH>J+M}Sy zHuP~>5OT7gxy(r+Xrq5LMqhbg2g#DB+{}YlQyy2bgw|tFXMz5&_X3J&utyXD=-}*^ z!daLu6)0{x2+J72DLpQI{rQ@v@BV@rMe*=|o{spwrjPf*!Vo#w5SLBav)54a>3;VE z*LUuvnFIGpKG!1;%(I$ePpHHSm_xrZM|bP)-G-pH=q?8hL;vk{p^%6_s6B?#bzJ*$ z*opj9_-0c>nG*{PX+mHXI-p8hJ_kP!>c~agYv35Pz#asxXN-ph#Qxc71G+OVCdR&F zY8=No`6n87L#&}|1%2&n0dqU7vfPC?!kXMv&x#4HRWg%xTQ z&KlWU-mQ)KkDuu6lN)v-jiUMPnu+S+C=?p0O$}c~4+9l5At|lLMvrfrUXPnE;HjCu zClxT^qz$Y{oJMXQJUjuiTcEmn_B!jY+LGDIW0?&^A+7U%iu`j{?>;9>7Y=XPDoaz@ zPDE79RPy1y48*^$m4gOe$A&9>>zcOgO^4s#L*ht5U3!|JaPa`n1=SIe32! zc_Jol^&r=sy*L1maU(N=|8Srmbv;h|MOnm+$tGul;~}Md-l3xUS~)a$+s`mVDaIx% zu!tCd2iI~B8F4ykD+#4(Qy{F~EKhxCPQI10Y9@n$IEkBWjX6-kdIzi>KC}g_RcxK8 zcs+10cdzCdV9T?z`;S()0$O!lKEAF*`ps=)9lldC1A-eImM+83r=<)0`q{aop`v502=;sSQyMU?pwDoe+T zAS*GTFRAdaLl|Jne_=%2?l(VIo=H1FWU2!!7E8r$juS*&M{39wf0-d~>yY%q1@Fm2 zjyT;+2GRb5gxNVk>Fb@tBcje&nKoArne`&tb!JQaopY}$-ncOzFcsMiT5-`JQ@$MzL%R6i!+%T5D^S5UF&J z1~8sXaleT6+4jt-t*O|UsLZ)RgkALGKf$FZEe;Lb-j|%D4HvwGI$~`Xx7M zK*yGkop(73ur8I2Nb#3&x&ebmV#G7|Gi)y@bjGg}^{4T0+XOa8_{~SzGqg3U{HG7@ z0OHJm<5p{CwaS<3$z3*(;w1G<^TTU5+t-iWkqIM5Y}~W+^G8V%IGy_z?oqEdC}n!x z&ojAT>#Kz0>q?K4ZPI@CCg;p+Rf3`DzsPF5B?!3`@rD+ee^Eur$%O3;rH0-%ELT?T zAP1qq;(pS=O0L*xckVjBc)1&!R1mwxlMY-V^7f&>erhjmxuWt>qjFy2>Q`W=}{}IqG^q!FwIHx~Hl97+op;28qNG;Q3)RAK4?6 zS-|h%WTPR+!`ukd(1$Tz##A-nwttFqzGyiufx;-0aJyMp@_IqZD_C8`*;yI8qvE2y zYgYrjLb5EAv?gf0?wUANN6Ob+{(Jd^QHPplNv3Hl)k_{m&qXxf8@}C(D`azfr@$=I zFLfFI>Bv!f0t*axW3B7k*UBs0HkOwc+7oEhr*v~UaxRt46of8Hm`rw!LaGLsWH z*#3brYqpm;@a-f}P-|bk>irkvu0lw}$m&vfd6hPTU03!Vi)saY+T2$BhmPjgAX+dF z{r=}2I)fi*$GoivReMQZNCH%&H{!TCRO$$tszyz`*R^~=US#VCx{#(Z=}JPQBKZzs z{Yk3ZC_;X8tGJ?t=G2{i-?=g@tVYXD*Pi^)eu1qn-^Y9_uf5vT_Ez=LhuJikQRdHY zI@T8q)4Sk*VebDD-5ozvY5K*o*f-fSI62U*36?&`!;TH&%{33fA(fyJ5E7IL{6SEI z9ZpU$U(RRpv*k*Pc_`8UP^l^UNE(njrrSUMgq|JN9cAakg?6pMvgLQ?hY~qI{KW;l zitQ-#G4AWjSD)!|&*}JRc?n>d&4upa|K75**M)1ma%QDof4K9XPK9X#Cqw0u5CoTK3}{Wq8I2pt1)}SpxV@zzmi>A0a2E)2`9&wcTz-JHvlZw7 zvIjnR*TFOMHloyPH6NI>XWzVT^OPtpcb~QBdogN$*$A&dW7#f%{oW;zU+0~9K=wZ7 zs>V>&mK%bBxPkvZW{ps&IQN7mExGc<2tDt0Tc~8T`RQ~G&mf&91@+L+xo{-lDuhSd zDc9yS6hkLS@%gmPk(6De>s)M2C%eS<8|4v>lRv-4mclujWk02Y4(8uUU%N zrtpqjJW$9I#LNT<>!Xt0aJOq*iZ+P2SX)rj;A)Utayu#*tBdAv=pLwSxbHU&bjR_e zp5*|Q|7_hj{>*aZ8O1D)NwE+d;7B4SJBS&K9tzc2R>wr0M?M0jp_)8kpFWE&g0TI? z>!}3k-R4^eJBvAnhG+;i5qR;mpv3dACB?KHhW{1)ztEK6tGf_g3cJTpDO>0 zGjw zSBu@$acw)X8fTa(m$2vk{{wOiAXrd4|Kuh1c7d~dxYe$oC;AU50(uM4=(s6KjG0Cr z>7)gfPx$XMEq9ZsgnUtA4J`#zV>q5Vx!%(b{8w()1h=2NQd~G9dX1yz18kF}(6DrS z@MJsS95y{}TG6~Q z2l}hGnpv7H*f?t$mF4@a`gi{b7vLn<0SZZnkhXF;0r7#E8*N6mV-@06HOs0IM(jm( zb&}VX;6~;GimjozeZ!S^A;qF5jvC2kX#Pns2pIamn;f}l$24Er>xL<#gU@uk4*2@w z+E_whQY-Wm$Hz$9rQGK271tZQ(~Tx7)UZ|Bt6d9#6sT0dVodB}7@)CzK#x7U;yY5M ze=5WPl(gIX%H@j?S5~D!N)9V)L4C~j$m3`@?tI-#)~AC<-ja<<#yNWxe$|&VWQp-& z7RL^5akA_@L(89j9P6eK`@Y7V_TE*>og^P>`XIgWwpOVqDT?&bzbOxmJJ@SK@%mai zR^>g(`r+yPXX|qXz8!}p!G0Tv#L2)}TM8azNjUjcn8G)~lTGSIA)r~Ve4~>&E6{pS2nu`Y?nBWFd3~Zy=Ds-a@Rc0MMdEr?z_J0Kk zRjRej`V`6P&IRU~&e00}vVg95^46gT+UwGQ0&91xGnSict|V*uP2Yd;rKaecRdLsq zJKxQX()SZUA1=~dD9>cM46gnbFQL?q$IW6cl(sE)-;B~F-7oJtVz!b)&1n~fw*HFp^-Q#^-npaU_zu0*ODTp4 zNALNIg1;V^VHAHF!g>>$#kb2OVOi3=zsMyn0Pp0DlzDy_h6UBAIio(gi4P?zgRk@9 zO2%mi!`3fOgGXjRn#>~PZ@|gW5sE1__8IV%W<5WxBh=JBN!&ds_7bWNLBtU6 zxe_A=!~(mh5mL8xVwktPogJmuWj+(R5~M~#;ofx~AIJ|fDLt<*g>SuIP*Wh>8F^pr z?_rzF(IRgd>l-hn>2b(aT8|tK;m(IJAOlCp>s2?fG#iW6{-bVHLbpaMSNP-Mi67xo zlQgs_R3b3(gi{>H+n4TS6QIwFk*TOh9AbAVufW$FWW~;YkB}Tpcq7ViLUH(H`lJSX z_>}9+K9>5udc=0b1|*zu&I-c6TmzsfT9+AH6K7{s;(cu%s?s`{hIjWYdt}NuI+b@m ziLDjw3&u;-^C1YzG9r6A*N5dC#ralV?(t?0e^taa(6=A9CB!VK4!LZnML-&XyDO4@4c}K z?{gUAQAq2G799PzhwMAfmYE01i>|bcvb7`Do;`8jrL6v;{}u!s62Si|d>47rOzx73 zC^B%ZTy6a7#PiU;$=ln{tJae#_l; z&hka)_gjHR2niAY+n43>%bo{TGoDrR>94a%luyCX@}L|3^oN^y4Kt-#+6<)??{?F( z#Ds3`4tYX2_K_j{!x{io^S=fAQJ&Q8RzAkgorCX%@-UW#95|;LRdPid0r*n!-_(lM zpO6!rKePGy6}COiX^y#k+ca&D5+?d5CSg*OP-GHPxW)cM;o@ZLa+IdpqVS$bQRFRp zaUSK5O;5$#?|vkk05Ft)YK^WSZ6f+H#vu;ZuU&ddUU?H3wEFrsgx3`95YSdFNUuXylZL4JSSfXk!Y=(HE_n`Dt6Ks@OlkwW4R z;cSedkB{0$*KaIQy$WiO1zYiSRihbi5}uuS>JVhuUArc-Est?@!5k#YJ(RP^)!W89 zG^}sm9g0HrNfpn04f1M#-V=`n=bD666;N}TN7++05=Rd#eNt^dFsnR8?2s)mq2xYuGQ}SIqTWhzStug2V%WtGO!l1P?=xnv{5~5?4V>0Dz zs`mX)QKr2}_s^iCBPn0LVavz_V8#sesHV3X_e^n<-b{YILx+s~;5TNN2)(SHV5++$7+gmA4mC09%G zx;(%-29BRw!CEA9!v4+OawR)SZjO;Mgiu5Tdve!^fm&@&hkT|O+CcNwbX25%{5 zCIw#wWA)P_vpC{a`|koNq^+#7C>~8E!(zo3EyW%Ob4lqs28m7F554k_w=`4pjzV5b zRPD10^H&4VS_RI8;T4l*^Zi?YHfr7Mo)U}5Xi6%m0lBvvOKSqEW8oDeOP{e%k4m*y zKB}>KY&O*;@NN!lt9pjAMIRA?gJ=m~Y zh$WjS6n&{8+pRT!Ild60u|`u~zv{boJ0IfGZzWwZE*U@U#62b%*)N=S!>h{ZdZA{f zQaw|(tHC#7^h0Ri7E>M=TRu_uyByN&<$gop7<00_(#D-VNWMQviyJV#kpQL*Flh&q zhF)yFqu(lWVWuiDk}R8N7i^*JVbn@swYy+T@ZvIpsM|(U+4e}9L+#%2r%~LSFAw{( zX!@Z0pkBSFgoBlcN(bGlVMwZG7sCa8e+eMN*oFW|iRW_xd={S)sPKKvK;jI|fu@3L zo5sKcGF^0saF2c9b+wXBRD^o=!-Ir_Q;Tohh zz$v))9vmm{Rr75=F2?c{dpD`Elp=Ca6lsPYaFlTW7MfK3*=(5KsrmshYS^eTb}Fog zoDF2zXlN0T|@NJsFI9?3V``4Z?z4uR+f}kADON!d|E3_EdK%76?V~)NBLQy{0(^ z8QEW{83||r?ui_Ci}nEV89cu#WBCrMExYxt;o6T7lQ>WDpr4@@da0cO6HQt>G1fF& zKWnlFyFs*$VT%#*qsDy=M685gC=T@Mu_mohq{ARYr0v~QBSOS3zLoDAxUQN-coL?j zJ|&3SOcz+%SRb6YiFe$?I6WAGvTg9_v4wWXaEpaNytBY|dE@iv7TUpVg2H;JW1)5S zgd<_OV&D+(#Po5FVJ^uy;Y!gZTN;ktF@o&$S8W3{e;U4++Ryj4`YN4Z z{30znd3F>W+Z#)9vH5mU%G#1(q}60|5o5~==WJbBObyl*qQFLs?E}_{nR9y(S!r za8=-oH!K0X|MRD098Gt)1gcnD5CQzvud1CTvEFA`^_}XSb9XG)FuXyrPp>FeLvN&< zM-u*rFIpZ)Zix^7Q?;|CVeji30>K<87TGYmAB)voggzU=t|&ElFE+$ONHZ{}c9}r? zdNyG>3UDTDK4J2(&lz@-SN^@gLx^<5Gltd;Ee=OrW5c_{fAiv=y8aJvd2qrpVY;!1 zQo^C;pG2)<&Th=_pZSr)FaCq29Dnd*v?FXtY2ut~FzSc5?gWgvMqcRDgf9biG7#e$&Y?gGo^+g9Sh9-+Keg+)AZDWyXq2bqx(hW7%eo;Th?DNar zNA;^2aODd<5Z^%Eln|x*EJ8}pF=F<$=|6j)n|fiu+lB8u8SSlr_Q@IDzvG2Gb=#K; zlJX+O3`Xu))v9=thCB^iuO3Xl^Q1kj^b(}&a0Q0z%GA22fbN~*-R42R8`yV>z3&TDMetoxC&Faso~frrM)WG-`JRr{&v9u0zUdEmkd1}5<$x~3|#OaRXE zr(?d$_&>2ObWG&+H1zUyq~XYDCS8v_nRo=he(D0oE!&=|O%bEQQ5MkT1Bxv9Q|3!b zs=%mXZ$HVTa7S@ZyBd=O5PJ{;h|5V^VI#F|;YDI#Je=4rOPjO{@+OUCK5X=^nqD|( zxYF}_Vk!7R(iKoe7fk8CTMmZMSVxKCo)|Ji<$7M+c+PuiN8;R_XM9b4*6t>_?65`S z*pyn}Nm{zWbE1BRPbyKOH~9}Iu``(S}8SK>+s3?rZVA8DEc_x`cZ z^qF8;iC(Ibq1S)`av9uMvf56NQ-#gzQQ9ccSl z&LBzV@mc+?cbHz|J~&zw!Y}|#biOqY?FdtDD#VN{D`29ko~s+Kxxa}{!dP!$+jyng zUAm5NjjjFp${SyMU}W+Iw&Fl?eosqD=BO0-{7EZ6-2U^^0oIejw>Ms$w@F`+>Q%S* z)aTA^$MdNc^Na7IZP+ze=Af%4&v#M0g7+op>iX8P_Lj59by;7u{8j7`jB<;#f-k$< z9#_(9^;*jEc?=>pQ87dGkOhMIwu*;iy;I_s?;Orcm)`=$j(Ahet1|n>MmIX6ZIe^n z%ak4JXIBJ1V3US2QZ3{Jr`^Hpcc1HgJ5S~m*e^b?DIK|}=n4W*)GM40K7`$ptc2bB zJCvZKpS3p|!kA4G4udfCZY}|PZRyvamI+z9v-}9-i3V4e=#<^Y8%FNpJdA1MWzi5V z3OQ~)MNX9^w9Yux??rzl(6F2)!*t5`{CRi$|>0A*=J>m z9u@xH_0#{TQ{>nzv$!!8*|uknhX$#%Lu=oQi>SwEmbZ2S)6!SxZI*J3vwFv9L&Ahz z1q`>Zb)zn5OX9#&{pZ}VjH!^<-HwrFCRU(nFH^)$X1=q;0lUtO^R&15z`Rjt*|K~J zeJc9DEiAAj!3eJ2=Zc5|Cpt?lqc#yu-ezCs+eQdoQ)9_k5mjW$@HqRv0@&gBMERhJ z*>&B|{)+^=&6w6|$5w@>zlq(TY*XU!az323D}1y%ICEcvx9u4DB5cxn0gX*~(8V}} zF#>F}_yM2bhmmkgo+EztUG(3Xuc3DPaM8Vii$S>il;z;u0nD@9orQt(*6Xs<#cR0L zAO?geez@XSvDCSHk!f%MWWyE+IsrW1uhZ#H%NmxO;Q1yAyTlu_4)=YPe`#`Eid%8%{Y&MpkdRfg~% zBw_6cmp7^>HXRwZ@)+N}~hMJxNae=6I3WAyW) zPF7E1thJZ?LrL6*-gUvZoji5JMi58<4vL@Mw8g&th5}vHA+|33v?L9d$9+>0j za0%zC^@bq^0CwD9BHP#!zL~`O5i7QqoupUcdcR~7O|;&PxJ$Q7SYQl+gVJN{6dc{; zNKvv{JiF~jcMa<96x|qodbc_>6evfsqw0*nwX*A|xMX6IhO2Ds%kF6lZO0GrB;QzXllBLo5A&Jf+P^h7rlh=D*CCwmH5`2sL(S~abqwsly01xM`Mg6^A)vMtYU#!JmQ=Urb{XB*^V#Kr0ZyMh>Zgi?&@ zzmHq1l*auYvR=pWUgeO97x2gmX7UWKEStEKxDNYamG6Iwh`cFCTXyxsa_57{E^eGx zy~qvchd|E8GPj~H4$m7h4n~BZ+b(6FP&U=)ZnF&Z`k%DWr8$=J@_ePO@Ub4pwiR-J zGuPsov0!ZdJt#i(_`3VH6~#VFwLM~5*`f(bOqrSKy_R)2!|lhah`-l(x5GW;)@I2v z0qNLY4W6rOY9EY+J99scqR_@_@`_4rn})5b_@nLK|Mt{BEos))AY<3GI?Nt}w2e%5 zKH}>o2m&*-ufYQv;!|v2|P*@v+0WhmywLD7I11s@a*9B z=jx+ZolCS``$+h2zR2H0w8t&quaBLCao)5rCR1dnoa`*k#Xr+KPJt$Q=AX=UTHxWm zCD>z=+I6?jG1QicLMnR3a2UI9+>u)_A`PMrtH$;4HEQmI508z+h9F~1d7=f~#k=g; zVo%cGo)~20Vk!+Ybyvll9x(?6vqusi8HO!2_O&_{Q@^>h0clsJ(n}A&wWU)X{vKv4 z_IfaLA@C7i1Sill>G3Q9B>vvL3r5`)N*4d4HU<`{OH)YkBX9nA+dG)+!e6MCXqeX| z)r4iLtfeA5BQ9@t{ssN&^U{3(%Aw%tvMjdX!+*j<<=-tud~isy?K;Of5DQALLlZ8` za$k7CJtdt%rf?BI*9qu9^gr3^Uu^+-ZYO6otR*|Ck9?&Zkn(1D6d? ze7Odmg11k#nIq=3fAn28K0Ss5{`q5Ckat-qrbNV_nc$s+Q}S=-&GeuXv2(debH`=> z#%Z1OLa6J2%=Q#KJ?25G&z;!+{S#?|)) z5MFX%qTP{1%@l7K{YUUSeh~;kIK$ z9o2DJPARHYR-66Sn~SFw(vT)d+M7(;;A=5QtP>uQebmfj)7Q^Q&O4Ec!h|CKoLhLZ zHZ(LnP9+!%=jy{1#7?&c!z{O%1j+&R(nI9s4yDyDw!%Gv#oME_#OPlyN0{Gz$y}A$ zcb?}?2(rqgy5BR9k=sRBtt~phqypMl8&z$EpO0ZjDDS{YlBH;u} z?CC(kWm7^xK$0&Y_`4rDo6@vCvc4LpJmy55fYvjVL{!ok>&k|8@gifUK=A^O<*gDU zbu6;}>wYRlsz{lYooRgLgHG1*fJ$KdiGl<8w>zm4Jlz(vz2O-~nYV(GlfMJIXbH(o ztkY+>!6qLFK>n*A6Z?eFFeqL|cw0A08TIM*L@fueR1q;v$t(LKDwJ0CkV6py5OK)S>y zkJK?w7)Ci!+KZ4<`vmGsjA~c*P0TYU8j+wHn+Gl8P9kLQu`<4@RL2^D_!Bcm4n2vr z?=zX$?%3IN<&jtL+z0~?2x2AnI2n|DE-tF1N(Q8>ZiKi#2Ce-! zwuNx-YSu@oqe;=&t{pg3u_z9$VEsQmp+%tm#VK=YYgrO z+m93Z_t{nRAcDa_)%5*TKaN$bht-iJ^e+pBQK9bN5qlrMV>rE~AvOtWgMT!X!P6Hx z(m_DGWzgRYON0F|qI$U7T79eL+ZnO9C{^=sRD=g*l)uzBYw&GoQ+~(B@EoqW$*425UPNlnIL%fcJhyir9H}=Ej#Xr!X+UPj zP5{Y~`bZwRxM?@vI+^qMDEq#r3h>m9iDgph{Rq4r&8I9{h5Li5dz}^1<~Y0sB@nM1 zqb0vH3Ecb61A=nWRv^^CaU%ouC|ce3h-WZX`{by0+!A)Z*(iISXbNfAba{U35Z{X^ zu0;JQ-b4e5iWsp@3uz4#yRchHDTt|Cj6#3t(C1$Fhpn3Q-=@XqJH8wNp>;*be4h)) zK8UUG&66zvI=wZxd$kOm-^o@O9iCf6-)GKvwP>do=>Yxa%E6k3;O-|swR5K7;8&hN1$lQ{vUgxMxsT6I~BdAO1&7)0-}c?IHfNZjixB zPkjHvj-c@=7pwL`4+IN5bD>l%aIeszu8jXiCEPY?0&BaTt>185amlk0!Wt;*6T2lN z32U_HPx$#trZM%&Y?iW{zLw92_n#p1J_ZwJ63=fSeM;UmMhlO;lC)zMH^3a7y{3<# z{OMKIlvHtxvqaS@uSrV34lfvoE^b8_X zF!iS1Ny|olh{zPu~>OjMvU0^#lk*Zyb`kVf zh9|ad+s@>h|IA#><-ULSe)n4Id49`Z*WBOVD+eXb;<-zci^JIzTGpSyus!eP<3cml zjBh9m&iahO_Vw{Y)fIX22zwl1yEOv9jd`4T=xE7rPk2O74(a>xsD9uTwYe&PhsLi} zq-8((k}Do6;0u-D$W&FKOiXtZ1#co&vasW=?l{~MSy*6dSM!;)y~*56MD1Kc;B}-lXw=EJMdLa!E8Xovomk@DkJ2ZA&=3IWh(w@N=v6fhkJfX;JtNQ zsz$nQj@vAxeiKB`L3iC&R0jBo`sjS?q~wnD-ta0=KZAU@{;YoHn8>&gBw6~I;jXi8 zU{=f@K82CL8I#@KnU*~edf8>^KUh!fe4z}Zlj3lTN^z9ltIR6bMyvQtT#L}56Oxz> z3g#-T0A+@Fewe*h()a^(c)*7f!|6;sm42E;?ULe4qPp9@zgN?yF}C=8p=G06q1$t< zj1Ql|m?;&ZuF}gauBd0&8K&iYmZK9O;Ae=NBa~X}!1KNy;B+9tx^~%$$-hW> zbvAjCOb@>_DTLKCf3?x}hZmCm-*|L2yfVW83h9LYAGBSy-W5h?3#+u3tDBroi*b;p zuEWuBtEWb5sC_JLq{rO%O1FKQEFY*exd%ITs?=mlx0kCq4mtSj`#I#(q6#h#)Xrsu zaG8UnNf9sY7f;QY%;jpNWX5f?mJnH1Z+;&`{C>xq-qrk}M~-GTUTEJ8M5Rqtg;H8K zi(EY3w281i{|;CA87>=5J2kBOd2Pt!(kA{~?qUWrFx8v0$TI!f`#$_C!COs;4b!E5 z0=WgYFN3kf-?W)^ti`e@(@{k@lQ5*jOBRvPKjJiOzI*5kH?Px?X}l>(qw^m5@PWQ4CU_7Z8exc|IsU)djNtE&X1M;x{kQ4Z0JWrM8;Y} zNml08*mLiO_45e@w2L6GLrCqnil~^8A!UR0LJV+n{W99EN6 zT?^u7@3eBGNwg6if{wJH-TsGzoNXB2cU7qnGlE(M51RoAi3#?o6n(?;d!K5VQAM!t z>e-vA&~H6Hn3H&yi>IXno3O(Lo?Tp}6`U(l-o=xMn?#6qsGU-jT10C>1*7SCC#;i+ zY7rSq#LCeFSOg&m(7yy_7?*Egv~9LYS{bWnA3)tNC66F%y5Uh9dJ5$#z^2ERyUA-{ z-m0@tkD&k3WlJhM#EEVbs@qBR1Iy(hZ;j|qbZO&n_pF4yI&&INLb#Yah@cOj)V$Z5 zAYC{W4Z+L9#lTPP!w=Wr+_n2t>6d}@30+dLvi4u?oa^UnbTj`O4W(lbcSV-Znn{Z{ zH*T; zuSVzxil{7C^^zVpAApN)DVS(_23lsB91_v7yn3B-8+i!WlEjJB$+Bb)+a}5W=f-{) zj)z?;#O}tHLI;%MsFv{wF{Dn`fa#^=B& zzrANfk8si1xSpXKeX^J6M{C!RL*e2mbVB{svZTt@V^^<9&6QGE)tb!}9kNaV!+i}P zTap-d4y8W>ms6t*G=ErUte9@DR;SxU9Q8RA%L~1S@bS%jgtcrB*;i#S<*!b5Ld?Ac zQc!lQITc*A8oRFZ%jL!LM70n>q79F?Q>hh0B+&2gM#dj^oRZK4WRv_@KcLkkdV?5? z#2)(y!dBf3hQaS-e4`|{;|t!_#M*%DGdBePc6ATe*WG{e2@`ht@9G@ugFmc0di&Dg zi5%V^y-&ZF%n05;AV8Zg8Bf6Nykvek%BG|~I$m_irH=uIxVkKAM{SMQ?>=9u&QYs` zpjrH4g{9_P%Dlo@neh!-?HZFQlcI(RqSVpB$J(KE4rEn&KE&T|SHZ zeS`WSiM+N*&c;yiUDR`gG3z(V@>xh>aT~DeqZw%qE3DwY&vIHxc1S^5xr5_{+-3aH z?Rx*<87!Od2%uAQ9eT8AoLu{_`lN2=Mm#gI8BR z@cC~e)Ux4ulW0o)4q!h5e`)CNhHXG+teL2OFPa=Z30G-eAmW(PSg_r;mZ-uLFofU( z)?MD(Ft|u4o0s5Yv%t!vTZ@qkcJgDCQw^cylij$TowZ8ec(eE)UQi0!@D4KG_MNa7 zQqNV}Aj?N51Y4hnU+F%{EzMhZ$MqOJ#MxIGhAf#)nq&~}vG30js6pfdYcHj}C^fkJ z)zsR@^1;10lDA|S^^ zjb`_{605kIWoOHh?5x_uLkZ9^glhy2iW1YG?YxC2P1;$shfKkA5i>C15Fozi2R#@~ zWFVi*_0Nbd9zX#FRuMLJ?4^0?UNETT#0KYiinXgKu?XSz=NEcLo2r=QZb3eV%4fT{hfU6Q4! zx8D-bHKX!8IFKpHMv~dDk>7D7Mi{s*E87L!GU?U62T5DP7H<8rb`{3aMcqAW-8~x@ z_~wFT;h@^I#W;0%S!A(HFBH$FsZ1J~yLVhp!Jm=3Nf(Od{kszXl}lSXah##D&^y)! zbDW!5YhuL(q>C`TI;QgrHjS$_a1#kuHss}blat*iKi*b>Y(k4z+6XTZyq<@D9l};3 z8k-=j>R8DrPVH2y-2h2-6PJxp8gwKu00IfgAmL#7p+Q`OHn(DrxjgTy2-NtpFEbc{j$UUpM;br9TtEe<#HpGT3tYAdiBBhu~gssEWN4)VkKQ z%STAxbOwrmoXGBAHsiuZ7h~H-7sm!|hnwc+33j6DLchPQgWh)rO)@`Kvellabe&-I zg@C9GKzCQ49p75(Y>vTo7rh-asUpt6TvO^YbAgbFZx=Gm^m*ldZYGDREQ5Ki&MO`l zLs8Vqb{xo_WqPwK<1K6U2{NZDJdGijx|Hrc10XIcqs(@mqQ}hFr|;J%8h~F8pBtr z#J0B|v$>zgbE(-)wwK}*l=?V76F00i#G|9;XJ%^;U&KX5=A&$tC#>`O%iBoXA+2U> zFwXLf*!PX+n@}t*hX|e8HqV}FBqmcgf5H~G*Y==eLBBoIN2Zu47N^CDossbImn*$R zNj@uCQHoz!WgS*E0{p%!lq4yHLujc&Kt`9){P z^2H$jxskMHWtgt&lAdCrKa-nBucOXk^Nn$}0tr;4Ii}0Px~=!C&7?6-T~ExcjhrnG z0k<0z<4EIS)@>2#jstPu1+m}dHu>Zx0IiLH8j3UFye8@j!%;?BqY~o@4>QL{&`>WkNffb+Gb`P22c@#dcO;b<3HUxd z+%~`}>Eq7OYMf5G@JayvayFoIE4PFxuYVQ?j&;7U)P)CWbZj%Hk%6b)3z8Id`|yk{ zqS1j%Z}s4o|B*+F0l{tpGZGY#prWP@ndVdV(3H{iy%F&b(d-&yPFpslDMcGSPq28(iUU`~UYMaryPLlesDkNce zX`*7V8cAA3E_LHB{>aUcSOISYfNB?MtNp0Mg9wmxatazL2^LuxC7N)t9q&g~I}8wEB{7?a_&`6s})wyKg;|N71QuPrZ}Yb>f|=Bk&wjB>l*sm$N3Mpz2ZBC{-%cE}~*6dvnj zqa{23@@~q^kxHqFhV|<&1bP3YR9UQk1dUSFZde9~TrIz7A_dD#9eUe2&C!dVUUPNJ zB(4uI5skYQ$OS%2v(}1$aIF=*FM=#gFaOfo*C7f9sFr5^M!m$^wo)b7$7UH3_c30D z8NXA5f)l~dzUHCXmy<}J)(u07czB0x5@|3sas|hrNNGpOQ3H(fK=i2A=7_;1FyRcCx~j&EKS8bj^wqWcs}*y%_7}C zUG56>IrH(=KLuRhHX}phU96GhTu71K7^~%B$75mznqdd#J6_aaSM@#qWDD5^-1Fl; zF2;M-uFFfI#RZg{+6`CkUKCTO)Tr(Pkh&LL9~o|^#*R1t8Ay!W8qPN1g1nr9@a>yn zgt~+5jNMmO&%zceKk9hlOh-6soWCI^Qr#MSClFanG;1a9F=Oh1NZk0J(I3BQZ!&~F zEwdT~KUnaeeM5KESb9W(?sLaeu`GMrnmg%W!=Dvl=j8YP9Dk}Pb1zfvQk-%1=RRFW zOV;&!Z-U7Rs@a#=+kU}3vwpm{*WincL`=xE=_Ms||3%+^Uaj#BMzzt`g5fy8^ww=k zzG-KrrL(rM8eubg{ks2or|an^oSipxvg5w&kK;1m8PkmmFNhAkpv#Q^4Uj0X2dql& zzBL^ob8cR5u@LY#K1vl}Tfl!t@j|G1N;{0^6@h1adP$z=JmX~0AcpIYg@$@;6SE_y zw^RjxJ_ZyIyyjj%m#JtAZ|2so&-jHa-Rb6ei|K?3V|2HizsdcfviA;xypm|_<@!~N z?H_Ki(0Jt=k<&lMb5Ug${p3#r*h`!5n?zCtzTr2n26f5@5p11SqjWqbx=2*(ZucCi zp}bVONt*n*;q=}6cvLRz?G3nQ|XCO5Zyg@;B z!SBP)uX|G8;l1fCI3G!6*inOKFfI1bds4?FieuXG@+jfWod&uMJ#&vkR1gC(#rWjF_Vi^Bq8^xOwf7}r_ZJvyw%NUbGmW?= z!zmoT5RutO343E9`F6VHu>t2fg~dH)>n_N#!zEc1^11n_$qA0e(nL>d0duxVV9*6# zI`s0ledW=p<3cbxoW+t)rCs!co3BisEn?6C=l9P}%HH0#X6di&0t+En zZ*1gj3B3~d*g(+G(jwe+|8w$WeCQybpAqS3h$a@Vnyt*GHtTPj?m8J^^awA5qqAt% zI(j`Ha_@2%P0M|^fhu^ze7eKzVg+;P&nr6E%TIm7bE z(sD^NyFW;KZNE)#_*d=rfym#s?-DPIM>+^28whJ+1gFt3(Z#P5Ydjczg`*5nobhh; zY+j{Pzok1V!_#Lv^Pb}%+yr&HY$13BJ!gS`-$IHEu(x-g*r=GSZEV!h6698TMZR!v zT8hchr&kaSx&@r<0e>T^kvSoI_Q&$nop#?jzL#rbOXkKKg19EoZ}6(ASB~uLIHrQW_q~g|WwLtV`So5KjuQ>f zwbKpBGNv9B#GOW0fLS6Ot*_&&U}h58$w#g4Q2^>kvMi&})~G2joh}_#Yq`0j>m--w2cMhO54rnjo1v`&=YU zo~)Fe+)r#V%p&-b@lDsY6_iDizO=m)%wOt#hevI$s!!ch95?M38vN=#RYH1c9|JCu zM?N*uK~ykhf6f|WSi$6Z*gyR4(sI&CEkprxtMQ*9w&5<@UK)#6*BlamzHVv` z0aLl1QeQs*G!Ost{I%4a9P`@Lo6OB4y30=I%6Z}0?7RELlQjMTg~j27?Dl!Zp~!!* znG!DcFT4;ViFF{0UT14dKl{CNdQhjx-*6?Q&)-z+u4=#XHe2Ip+V@2y{2OJZV0NOc zWAC!uK=Ai5AwjPl%hmP0LHDEJo_ivp3*-ahJY-L)4?_m>ih=w3yet8xCVf{c%54Ix z+g0A+%pO?QR1YNTO~!#e?ztZ-JfqKckr7+%*w41vaOE3YX$ur0ajtJ`o`|-wdO!y?-p6 zHH&qGcL~Jc1-v25LVk+!3q;^KUygqbS*zuF1zp-&qaB|)Wvw;q-X<40bxWM2wKmXC zroI5E5sll%wdt!n;7>e!!K!X=9GW1oE}gAB)?fRastRbj*&3hwC(v4m)D7x1=Xm+f zowuG<4qX@G%SLDJB)%%u4rBOyZ&z~}ap;2xgCud~d#xIgn4Z5d*3u{b9}xFcI2Vn+ z9dGhvL1+42VXA^um$z*S;>h9$tau=6N*)nw9G@ZFAD+(WNc}*S{syG>l2I5|ErLO})}b)oj2}?Ahwa z>U<-r9s~fwZ9;~cN#L|;^VUq>Bs4T=KiC=%*Pnatq%77rM~E4o23%F$l8QTwCLjks zSJKqRWzBJR;^$hyQlPVH(x=@ zsYXnVSc{U~_BMKiaFlH%0!U~}hE*QX)ow*=xea@$6H|GJ9w5iHkDcLakos?WK+5^G zR}g(l{{N5zF_QY>xShK&66KzY*Q4=twiT~NtS%LcySHt^O$;QuK@-#sMKqa%itZ52 zGy`<4Q=%>0+hKN&yp!x%Y|f0+awHP9d8F43w9fDZ=LxT&joWS$6u(|8f#msT86~~1 zV5{&A1+$f_E$jGGKlk>&pqr`qY5lXl%lXfIGcgLGpQuREC)N1=1kJ+wbpmS} z8x9_m!VDLMzikv}yb808Uu9c3Z%)-DMyseDVuhn~Od7hVsf$a4q?G~CUvsi7j2#*a zX^vkW()P|jC_dM@w{`1`&4iFm;txvWBy6H0n-a^g?5X@Wr=L=Ne@^}qXQw`fa!xlk zh_UxpfPs1mFleeK{PUd2B0LYAZPVoLv3D0XK2dZKPwt~np&fKznU8Uwm^65ru~wassT#NtQyPCdsxZ zWnN4B{axiGGp|5}2&}jE24uXhz@@m4wrCx`x=_vTg<_(Yfw048xMwC=kN<_pAj@+1 z?dRbE_b}~#bY=f)LONKQQcKzA0-9lQNz+p!ka80-sj0&_I})l&12uT5&bfl*;lw0b^CYz2i(8whAJ z)Vuw0Fr7ITP^)L4hvroG^DYH9M|6w~XcK+tk*7#AcBGH9aTAh#s*YdWFG_7w8VJ{? z$#AZw%{2^inH^2irZ2xI$=31edWdhLN%}=U@B6sldnm7O=Hs2=dF3Ppjxc*~rvAr3 z812n3ZSj*~?5Jhj^gtFgmyv8MkbD0m;W3{7AyyRrdGd1m>R-|MId6>R0(YjwX7`Sc zGvrAG)Nvx}U|Or$)*G=lcy&h0h?1{a3;Qw&P|qek6!Jsf@$I|UG4pq476kNsWwa;D z90!}RANW?n;g(+FV;VUUYwSVq+_`V@E%Cw{sWuwEj$HvGqmps<1xC;8G`Sl@+5CC1 z3lko3VptT2rx&e+vfxV;KwtN<+L0G8+=euXL*t zonc1v`uXhCxOxPhZV9KaSag>{0*Ngnd-00w?64>9IhnTh@j)kieJfo&V4lC;*z*}L zi5aYEF(2v{1`ZLPoCF!{36U&%CO+czvtGQ7Zw-5#n8yf?wWhONF|3tw|6GJ!wpTge zL@pAf;uh%qbxKn5d-SC0CONi}ywigAX2^z~pvSTooH|0y?{m(|k<$3^@cTjE>=`>N z(ebj_DtKGym-&gSTk!Fc$;cpiONgH|7lOmJgDd~!N2x>jYCO5lxGwKO@Ezl9l^Ka9 z_6`q`as~$WClBqf_A5VY>)$q;t?B89pm;^ecUiDit{LZh=doB(35(413?my^L8l#j zkgpJ)k2XDczB*Q9nqk)*P8AGfs5pU2gLo05@OSje+G}DWk7{F)dvm_Gz9DCOro%yT z{IPY|YKJIFnxvf#zJiIHuze`f+<8j`R;f1jU*(l4;6Ofo^|z0%Q-ofaCq+t~?uvFQ zu_;jwl9B%^98C8VAo-ld96x+4{f!Lhbk#~0j|mcenMHaD$#Vl!g%9nwcEZ|PCm+R%pWk`gr9{#)_$J)4@u-4&UO)vcKqU#Um@aF8B9_JaI0S z)QPmn$i|W}5g-uvjjNNK=x3b`3G)`0X6llHje!(RL{LZRV{S?@j$By)dN&W&m z7G<~u&STa6-#%fVvRT)4isd4RW>ZM&r+2v9@)193fuCb*n9h~%qr8PRdGrx=A=URB zhBMCvEpQi1pq~hzYYFR-0O!bk(iC&e^aN6%d4ArR59}&?m`1-l5Xrole!^Op!|RwD ze^>&X7TKk_V0tZ`T0$LPUh_|;ns^-t)q;A$e!(t?TPeS%%6b^i(`9M_Y?}nmg1_63 zWe6#BuU6yN8v9PQYiRlFIOA^+rXod_%MWvB=%$y(u%3V3Jszn!Gn~JbRK!tTwik;u zAJG^p#9+R<3&1TIbiGHPCB`CADW;&j+ln2tzP$ebh-A!IrQ{@Zp5J<)Zg-nktNX~w zgdI^AFtja8RSdDLzI^elE-n_c(Jpu1`8JvSd;$|uIHIh>w9sq$?ro zN-jKooj(8gDmD^yrV30N(iV*+V$A4~rKW583Yedayb;@e@cIGc>(Gq6*@~1G{pj8O z%KX5cC!On0tJhD54simHI@{lEd+0squ94K^?by;PSgHf+fxRS(vQ@P`#7#oF&(@4b zlPiAP4Qy7&`Clth;0{^sbpF_`A+`UVe%*FKqdkJd>iIrS>~eR5u@Kt)_@j7rI>PNo zv2l4QO;e-p)8FT+P(z)7HQ3`GHTUQ_+IJ||6?>uegYTS>1Xh63SnNPoR~e1VLaYJW z&||@;uBel=pi-4jgkr9%PCG`t@Z?z(+-;Dd{~7|>?A^vT)CV*9o8g9ywkQvj(Hc(V z)o1U#6ZG4s2ie)tc8UWxpvhkT)B%YfVK-`BnTJ=&jniNfA=2k_Z)xZaN=WJR8;`LN z(@rx5Amdsd^zoa(>$Dn3g&LJvGTKp4S|*4c6{4^8HTK{C*dOB4JQYm6#F4PZ`J!J@ zbiPkY+N)1;#v*pSAa6Z>f41_wnDS4Ed%yI#%J8*kBY`V4%&Jnqe)Zke zC8jCQl#I?KZN08k@O$+r*J!JEFE6)-xK*&^%MeXI_(I7-ZwghgwCqTqb|N1L4m-TK z3q7eiwN;yw5LD!@IzLZL15Yr%vL>8*Iv`AhHK(M)mc{MK*o+X~sjCJ_pVC*Lg^0wh$&=FeRqN?Bolhzu9X?S^V`+L|fRYYejyrLYnDCfz< zw1O9^@VwExVf%1FJ-Erp_8yVD2+|R|iKlei zV7D|7yK84ULuh%HmFAx#Kv@g#RQ+|NA}Nq-XnmIO--77zWSe~dnRaP&P7BD_RFq9r z&p-ppb+J)qj*k-1x;OV9p4+LknxgZ_bmvTfkacS{$I#{7IZm`Nn=lD^%gO8`x_O() zZqUg_HT7(5_uBK%ca@X)Ygh7p7Wn!un%XHM?}dBjfr1Wy6Id{|D%QmT5ox3TQc81! zdqk6}H#*3knO;omY~KaVOwA!`ARy zq@xqc+d<`fE{_2KzAYS>pemS(9as-?akgp-TOA#?!>rNtfY?X&!3PAaEJ&Z$e}&YU zc~`vSV9g)m-JRq3tBqWh^oCa-Vb4C+zu*0(0`Jz%OzyJ|vgVc6pHH+s!S!{6 zM5Cz+40psf=0|Z&(&+i^CDDFB>3r1c6`8MBa4d9Xgj~Rw7?rXCV-hJ%P)+l-CIWpq z=09A$a^FmSQbW;Iu#YOnj;-w4-vzR`Ze+Oe6^eONw0?YzXPzfEL;7FRT;i9$_>i@k z8s~vK@5o0lY|R}FaRbpvRES?Yj>Zq23m(LNc!#$%3mr4L67NUEPA=Ut$hxi4$WMII zKyzY;|Ho`Nbgp%uuU?xA2UemC z=1Z&$n7aK?Pdu6acRX2f7h%ka`okRO_H-%%B7nY~Ol?Y3yi(tKJd?%OT}{|-2yiHg z0(5@Mx$DZ08R_<32+bn$@GL0bV3!do7U5U4KQ!of^~Q;cOQNhv`daF;bHHO!jEmN7 zIx}IGNe^UE#o^8{S+IRx;3(M>!WJiE0Vo90TXcxS32busjz$cYC#Gu~%UnwS)r*Nh zRclOTyZH?N%Xs&rqoWo!>RfmGQ@OXI?xu^VAZMi+Nz=&GFr z{-7Z-*yHCPVsqQ#og)pY1o~kVYI-4a1CE;=NVWEv!9dYgIs-B4J`rDBw3#NA2mk@9 zZ1)%_ZH}Pu99pFVezr00r%Dsq!>6sVNf(W6{ILmVm#qPxeh7X<)4z3lIPy%yz{~u3 z_-TR{{O4)~o9Q(+2sT{tohM*36rjbW{QB|e6Ds6QyYFyVAtF0!KUe_NEfTO6*GL55 zU+ftfzyoe=&iC954k$`rFiwiujq} zH0K5vZt_Oxhrh=T?TI`QtyGeHFd_1N3<9tsL|9kiei2M$Y+7@=2mtB^nv@}o? z{{I7jskA<|(O%C-ReKE-H9^3n>%bS3+klO)FMUgYuH^mP+;Y)=kLC&A5NfBB*Ic@) z11ZYb!|NC30X{WwIL{{(JK1i1@$f9qw@P(yLv`w49V(O0K%eZTV|V^p{g@#|K>o*J z`-lM_kNhPY=1?ZZ;y||h@Y1x^Q?g#@?s15*fd;N6P+;%0_Ft>zKgbTDt?F6J`IIkg z9!|A%yk!Vs{+g<=Qrr1(S%P9b4hr*PJo-ey2YZv|0$U zO$x>YL0Po7x0~<+UwD3oK5s}cH5K(F6LI13j>P1==Y58VstqZgLL=w-8~(yYC@OIM z^pBFa?z3|SulcJA>scnoglhK{Ux#-jhHl*;m{5TxtOc*#v}-R;B}@e0(jxbHMl)~2 zyJ;}^NgfMR`XSZwcv;Z5f}}KGElh#G6EWHlr+|;9oI)s&OR-#i+20#jhHskv>z2)+ zJ6ubQT{R4JDo)(x#7cLyGF-Xd0pN>CGp^m5%TevhG#>{4 z45o%AGIsnnW#q0Xw!k#OlT=GgccLVjgT`)HMe12e zY82@_D~xzg+NO_>yuEYIof0j6X^oi^Ba22Esz{-H+fh@^faknEE<3Q4RQJbA*>TW? zAJ;B0RZ&0evOlxc-;~JgCGMjZRG^Z}MOy>%(g{HtDI&Qz*Wp6j;{R%_5nUknqC>$} zzs$7z;Ds@ZZ~w;$uB_b~ej8Zg5f6(|d261bv85fDmD34$9UxT(`x zGHo!(>;CIm1oB+1TT40p+XKD$>l=X1Yf>o*jyf5I;q@1fo}Xi00XC@pj%cG! zU<@+}W0GL}6wF(_%GnB{NQVKx5HzGNh z-jTxoLBM7d8|lqCNiEIbEP2rB9BGVHb1!uldRBK1g)U1PSksixrG`@l?hst^odz+pgWpA@2a4Y*Ssm zoMr~BQV71?uX-Oj23}W^x~15e^|ag+?v%D6mkc~jAOgmXQr_mx;Lvj6CgvS2VKN%q zGM5eggvWDa-oGM!7sdp9Jw68-j3u>#_ha`(f`X^ zjUtFfxhe~qlUjXzRQN8Z&C?KuY0wxJ@riV5Mo*9M;Qp934%#Nu9sk zd&~w>g8Pd0v9LinK!;Zu`sTru)Wx&p-iIOg_C-eX{_{TjqVW@9ujQ z##WALKQxWDELo`_GK0I{Oj}euj6I{``-!LNo4+{o`xuD8E%0!Rg2m^nYuJd6GBWH` z$1W4G46-Aih7~@EKP>74T6SX7`_SL@CpZnDxi09X^&Bb)AfTFZ-XGHBt7T3?9C_y) z=WE0XTg&-;x&RpSSyM~y584RI0QOD%v=8uP;^keEoWy^?N-rhpy*yPU=5V6Y_({di z(?M)n7sX2zX_J$I4Ux%k4U$GDDvhWu;r6S|6E^a^zqe}cD{S?+gmwPI3eqO7(#Ggf zi)hV%Zr6^qZ!m0!N~9H}*TVP+provD0g*zCw&syOA83H|)oq{jfKK%nOXdx(b$@TI z-y^m54<{9QupL8@0Gh%t!K?BiDl|C(Rb}mO-5}4a%J|3TmA7{M{tpt@WQr*oj>SVH zYOWU6S~RGj($~`8Q!P>xp4l+x;dJ7}?xSe=gQa#*H39j;*5*t66T8q_4*M)GIeZ=2 zF~#(^eH1K&VO)shnV;7c9|XAO{bm$g&m>|3!zF%d65?7qsvk0AzoPWEP=Sb;jW+muL2SDsnH z9|u&!kmQtFH8Mk_9XYs=in={czf)-TnZ1(}_-k5zr+oH6cHba{Jo-muZ8}q40DKs* zY0RO}CCFxHo^r*~#) z?Xx@W*_BTA(HEuLEwp}6g*Kf1Y9x5)G{FvjvD_p0Qx=RQA5F^7tmgv~Aldx#tE^2g zT=4x4UKaujmaI&)W=*peL?csM-4n&fXsg6Oa($g5|5VO9H9Joy6cYHXafAnG+|=M%@WsOzLj7hJnL}*&uJ{_)LnjoVel_YLoZ{;?%40BxU1`Wwa_ykEE9}F+wgMk*`A}^n+>~Ci zIit0CGB8l@_^vj{Xc1f_SC6tvKr!JsD2D#lt~@|w->ixo0zXy`WU9^KRr156rY&* zRb?yc`>(z!&lM$4u-`sZRWo<1xnx8cbB1JzsX0jk2Sna9boW+YotoM0 zrZw2@jEd6BFCvU=8oA9mAO|N1waAYDeAKR*V4YdqmUU@BwWqr_Iw3}q1>WQzGX{X4 zD2diKAEut9=B1krlH`ah%f47Yw&3Qj$R^c4IbEQcz*AYi4bcFU%*)QgHtzN<9F}x zK%FmC+6#GsTcV5cE^$nFVv||g9{DD_ytJW&(k@<+(nsp}*O*tQv)b?6pT&)ATfu>U znd{ayk_*Lj|6(IpybPU%Q}D&5eZg1baJWKe(e!rt%KmQawdUZpx=MAl498y?t!?0$ zlwJM_)(&fqtbzHDRW=NN?>1J+;xX8@TY|00xzZ&Qt-vATsUxl+h0x$&Bcgs73AIUL zqC+N;N6mz6GMF4*JdkCKqo*Id_goF1PmFb?dEOq3k9ngCc^>ZZ|0Z5ftgeT#=rAum z7%$25JRc#T@NFdZbOFat&H^mC#7v{o+@kK29!**m_&1T%QQqYq9tQE({bSy*FCai# zTl&z@NR4`-7XRO&uhErFAc9+Wqu;Iy+u8nHYsn zV@;Q#rt2U2#~A@7)ieFTL>i40N1U0~PGjz&fa~JPm`xwnYZN9?Lr;-%Y&d?ZCSGH( z_%EWhUBi!eV#~)?w%e7*1^20c*MPowRvAZLF(tH)IE9HVr)Nwl-<57N>{>=1WU+s2 z-J*&Gl8Qm1J1s6J$!-EUjvzB0Z!jtsx9`*+e^>dB7f%tfPNn!iiTvJq*$htrA{Z$s~A2TrF3~1pyb~8 z$BhEPP& z0<0#ggs%B|Ou`X~cIApLPt3DrI6y~12kKFz6%}p@OJ)%&SpG79z{JYOOB>7UwGQuH1p<-V9Xbo>E zp(@=eLfo}({@Wfi?ZWjB1pQFI!O4wCPqW&wD1Jf3fU{5I^1vFmsCRkRJ4}*~@C`ihR8i$AS9GpYeNG zZCzB$b5k%FLa0M9DRPo{)a`GX2EUaWUo2{rB3S^b90~Mpbj`MLVw>@Rz}<>RdNMH- z-faRwms+m~OCWH@gM=!wLFS%f@h)e|xivp;ZuH95=Wy-iM^#TOTJ>OmXQE2?h?JymQ|Ava=M z1BD@qv=YX|6x-(%^Ib-p*N%>)44+ERW{T~hw|x3hOB}jcj!@ONuKAv3n;^14nv_q4 zt|t5fEB0CU=Yx16q}MB21M_tKIs@>1wV5*J$N`GCh`D?Wp?Q+x{@Mb{L^Kdeh3Pfo z$H3_U4&mXZ|Ae;O&5KV7>-GFUjZ1gQd1mm>jis#^fRDUB0f#o-B%PL5o2n%6pF=v4 zXEuhZ)?O}2jfZkcFzcX}xyC+2x{btPeIj_8-H#0-xT-m{MEn#gIHg2H#C3knIqr>*WqUI5zoxru-&Dycdx^@RrL?}z=Wx|x8|}N( z?36(XB2_p8ERth;YM_@m{?B2OeEY|dTVdxjZ z`H)t$->~bj8Y&*VnEKO4wfbq-Maj$_#CeY_U!jzitKyLIe^WwcJ-@LU~9PFw{kleqbgViZ@k zFy_7w>Cr`RrY&W9gk9I6l{t(@G{M{i=a7qH`;giraK5C$XjSCuJMm_wjye$ujsFNIQThIcl9cKTXRtJBv)Xhaysj8TCN%<2^n*|!4iPdcgV zBsB24yOi~qul2bO0x<12xt7$1?^C4p$j^?*_Kabll}t1NpOZ##DQ~=$&a`s0*H;h zt+hZ_7(4Ip~h=b$v#;yt|BiO2C)9$AUD(mY5`gps|22AQ7noMmfnyh(E2+52Q z?sg@?;W;43Jo_KL--+w}{rkCJ*2zw<%a>DjqrRu>7+GWzTM9efc&M$~XOpXas1?|M zH|9WdaOX6EUUg5W{R`7RcwjHgU>s+UaB4oR-Q^(1%N%RHkMq9( z!azO0ciDT?$UHuOu!kk2rE?58G4!p@Rwy13yq_bpAoQTRtgf#|bg1O3&xmP}niSEP zC|`>nDytpL@hze>sS%y-r_FbSnjcDG{(AK`8rRDg0gXgwr?v0PmXOBvG*vTNXdpk@ z!~_;~>n`WdPOydd@wKagNY*1%?$5=7w*w+6LOZUpDWR29T`i}r0UuHRuj(++t|xEX zY3sY#6%nxf>VVH^vyO_%--1R^vpY0Mo0b9PnsjhMN$;ewHo2)pg7PbzJ?Z zqjmRH^DQ5(EhkB>etDH)E!6eVpkjgf-_3x3)71RF1oK`$0}DL*4wH^~9PzV~U7Mos zX$Zc%npry^qIOtYB5?WevmOEYy=c%+;B?qKHu!uD^GBPV7u9sSPQ8#v@@uLbDW>9O zmcV*|-hq+nA@=_Rs(S-II)8djsQS+ob-f&_FBAA(uLDM1i`1qjgXa;=2K+JO=)K3xu~6AbVNXgUtWRa>3+uZ1|VoAWu%AT!KZRbAU3kv~4^QK(jd z*K~e=)e`tQz51Z>QC~+7enh9-tbBeStap|vOkoOBn8FmMFoh{hVG7fOLPf!PAK6`g zPtz{2ko^j+Ptm?b7Ff@r^$Se%N;7iV_Hu&Y24D0Ai!QM|##U*@jKnpI0Y(>g+Q-y> zWk&S=bhP{&SpJb=RH?2>Ia_s&t;MF-so%Ii+NaL7!S40hhysI>jxNHektnoaon6*3 zx#K^aG;32m$~ixPS!j*w(0=fqgn@B9F!9$1rEZ3;`mtVO@Ua<}n{capa?jP#nZfTZViN6i(lje5k_huoFzMw@Soba% zRPII;s{Wur)u$9(5(QSl2}MEGuQ2@61;m=w*%21_2yJRI1;$3muHN7CN_y`Vmcvg=0GmvpQ_rNe zob8jG=hHa` zXK)h3NRneI!mnR`sG5l@>-q-mX5F2!p-qd?=*mcW-oKYnJmEV)oa8+yjgAiwe(wDt z*oMr6sxhH`b-LQTdsV!+kXixlJZ=r~_q$Eg?ohtO1F8!5$>)1R3%MS8{llX3Twc|J zyyj;LF~9s0n*RQ=m;%mK;c<{ZLVRp%DVRF=ppPe00p)F|YHwsAkCXdld=@s*_o&=R z(}P8Q3b`K__PC0VxHt2|{o3AnT^>i6!W7mE!&F%M^8G^hyBvrJkH`CpvX98;ao!5g zH(?6P<1qc(=}!A*__yn6mb+Zuy`E=AjqzNN%F5Kc(+6AJBfuL-$C~qjFJu^vvS~r#IgtyXu{` zPs6Lhusvb<(CtkmNVgX7yN#%XK|9Asgf>3QhuB|GekeujiKqg~13mXaq1qYlmY$g3 z^%MNQP`whyM+BBXef}f*@qT!?stox0OmNDUR5vIbVuzj*{C^F1~yGmg>7^X0VDNJDsQ<%aOoO13|_OLFP zlJ&wjuLO^<<0NTOlDrNDC=y;-jx;QzkG0yODs3k;3@u2QpeO`~vl79G%Cpz|JrO8K zSbklN7q*LXiw?GgxQ@?nlqmR~evmM$wb&EO&QI!&JPoYPY2WOqdK~LW7d$D$ZinjX zD9P!b6wk=XM;>WhY;00&DNxkNqItu2uPZ-pwe&g|{p=caGd_3F#%zBNPTVQVjD(S# zM8i;x2ip14(Q2fuHR`hBK(rS77v0xt-Mzt6?NA5-+6j_icoG+6lEt^S#^1>upnd+5 z!r_TgKKU&Ny{GrS-tVW(_eRXYa`i8-JFKTxS74*RL4szGzZguTc-|qWi>VoIS!y-1 zT~@m2Ny$j>n~=528zu&IhS`IC0&!UjUs`O0S(E0yUklcs2Ti;3%4B!) zj$Ch960~tIF@8^j1vUubMu;N!=8vTR{|3a^w(ep`ab$5ornaw zPUPaj`|ld?_EUf-0-U6#lhw2g;BhsbdUVtIy|$XR0Tn^6_aZ^bT=Y*- z8@eQD_sF~SJi;wNy=NBk-_3cfACemng@}#nvCAAdh54Z0(fb~CLV2v1R;&0?73k$u z!CR-Kmaj2@&sEHUQ#eJ3$c9lKJ8B%K@H8rvQ z^tgs)szhEe|GU|RdPjo?Z2AmSn8FmMFoh{M#r?~_Z=F?(-z*#W_g7TA!Luf9Y62L& z_pDBNrPX{|rUy?EttzWkqa$@pY0cBMX{pBA@(Px2M~)X{^COo3qvQ<%aOroyFX z4VU#}tZT|F`rYy|+6tL!@>|v`=?>mW@Df82G%j#I|7`!OapIOJv_(-8($+2nrQ9*Zn<+apU{m+LDD2k6C6Vj7{_rO13mv&-QX+xbsf+D z6RkC#x^(pX*Se7f2pXdan!`wvVQI=QvcQ(teW7%V-n8hjf0A{=q)!_@{vBffxPa_e zBo4`Y)6nj&(2)0u#oQu`i1@%>v-a*w;_>*e# zS{P&0WhPtq9lnvwt*z$Im0WceBq7t|U~rMeNCu->MIM~|@*Aylac9OYvnKU#;3?J< ze|&Ui$dO?2h7_L01d^2)mgiu+q0u@iENO~WaZkZ+Ek?GjK!2e7p zdk8KeP4>txcar$fyYcJiN21KmxA&!M)q(Iiru{us%3=6aYvj{u&dAQeV-;~E!?QRo zIh_IzV-;P|&3l?Pb3?|-hFA5+5JzD&=Ih}M#rTb(_QkZRe-Y1EhaCU7X7UDfbYw|{ zKX+-CcSy3BA<3;X(lR|MX|h#F&5~y}xG=I3wj(MN)W7l_mYe20{=LE-DlhRa%@dZp z{NBB)Z)at8Oa)*tH+X#MiAM1R?oBbpdRp?HcFFidem(bQ^xq)yh)Ssk-_fBohK z6eMnUl%L#Cg$G4A+Q^FRa>-KH3@IyB?wFq9NfA<0M#(O>Bh!^3%5HbXmEVszQ1qF& zyt;5a6s1k|{*Gv2bnw3$l~dQ?xnJ{`pWTwb?+TSlg!rBC??&Y}F%ZH{{v~@!Tttri zN4i&HqW)Z04&agoxI`W?bPW<;$T-db7t14#Eg&wcgI^x@-O^8DSG0^a&^^NKad+C| zrgRty185?FFl8=vU_-J`;3S z6L3jzG9u~3FdSwar#oTJv2K3VYI`QR6j;CIWSx?p;&D(syQ%fovg^+*D~f~y3TB$$ zOAR@7m}iZBWQACvQ8l1{`rV64mmE$-lo&x0owPuHo!Y#lrP|VBdg`uG)0ztDJ)^(p z)w~R!*SpnZG0nHGKKWFSqaW&81Xv6sXrAD3j^!DKf~zG;&2ENH+swD#SoF<9N)}ox z9gOsAncTyXT;B2?gz2|dBiO84LS9=w*lH9zAR({Mhkc)ewLR<5+1^7{& zM)^QZQ7~w|kY<0YDcZt$RDHe+=sf7E)LQWVK!6!F{SeK~>U)iJj!Jb>(|3^Csy^3H z#~ubdHN5wBN#$cR6%WuE{t4jsGeF*>2(Kb&mug_1LD`fr2bc5J&4KG1Q7pVZ3RB^& zF)gN7tVd|BZprRwHoh2WHs*OwQ5ca`I9&X((b8T=hJ0x*o6n+48T>u^F0r5 zFi&~u73)`j9o-f42VzhQjhz(5OIJ8dAf1xHNYd`vi}@k_+%ZUYEd&`(1lV7NSYj2c z&6)FLMRdKlN1!5|oItarD6<^R>%};a0jWs`>)$k9W=-qcXyo@xf_^6Uyi<}z z`1MoOQ=Vp3GPaG;V*jsSX+4=}nnedu0|*-9NseN8mLv%dssWEO+PTEPgg32YX3q5d za1veYZJ~d$mt`=gED!|6bNKPM|LI$+9UWQYE*nhssIm^OoX`5@*H2jJy=krWi@&z_ z@Azea-jpM32&WXtHt@(L)KdpC%25- z_$ktuPnh(V&5DG}PMK$Aj>N{z^nASP;4G7#I&uTxR}5-&L+3ps8d$*R^@QenE9R)% z^ZAabY3l`^tK?y_YotRUMen6j4wof*SLvwF*A9I$0Znpqb=Guq4Z>HWzt6o(VXntS z-I;v!-9&7#w)w337~!Yj-g0=Ez%YtqafTq_ZhK?H5xUWO_4zp!W=$;RuhQkVOpz?} zYnNzh@^v-=>A^kY^JkgLDSL~xdDnMepWFa_Ux$F-CyNxvNHQgH7a1tYU8fOTa<^60rtJeEI`vYBN?rZCXeV>kv!$J`p z48=<#MaeABOJ)B|F0(p_;6QW;oSAWk`23*|uT9R&ng|*(a|#gBn^z zLLd~Uf(wEoLCt5hJ5Gn`yR6MSeck!yiJ)G27?C4!jOGbUVxd=_o$5NX^C@5Yv}%do z7p2AiMSp8uv8{T12H1Tu0i=$SwSe<~5E^qVXO|jWWBPm|SX~H>XNV5s_A$u%zMA1WC<+X_k{Ci>1 z^Ok}=ufM%;)>@@q$??CvjReP9OCZ5P3!ESk6pKqdQLgyH!w*M9NA|kQtytk6_oDl4 zp=Hh^zasOQ&x5`YJZqhKb;z)CO=fa}Necuo@N@hf$VaDMCDRBx*NwS>TdhMK|%fF99Li}6S_b#zG zj~3kst%hG7oban-*Y0iJ>ZQe5Q?<`81-nUS8)>lwZX)C0bdd-gzf1-783XWnaN6Mr zz>fh{wIRT5fz0k)MvH#~ruQS@G{ltzEnW;xN6Y~D2e2Hd3h;8USydg>X9=iJb@2Qy zpaZ@Hrkd#hzXvp%cK}{)fO`SV0z4Kdkage+6W}R84#@z&50t-TfPVsGZ7{&i0X_}n z+ZGjXi7qwjhY=0`hxW(Krt{WMm&qrFEq=&fxlEN@4vuuB2_D(yJLOmBho?E=`i5et z_HZ`rWvGk%Ztb+jEq)UdY ztso{lFef45l;D&J8L!v$s{wBheKMi)ecm9a&37grePh&RYu!oDeNg7S!F>e6>EwBg z;VE2(YsxOV4R+1iZ)fK9GHq-65Boq1JX}^do)T#%!((GTUkSNam(_r(W$Z8dy7m2e z*c)5k*0lstJkQev$6*9P5jYPmLD$vEdWCKYH?7~7E;jt(rnQ2t#(h_3B#Gxqf?_05 zQ5-30nW>P8r>WvPhUy60M+@wBJ^-&43R}o55be{ zKD@KSt>y2YwGj8XU+*kp3R4I|F2dI6Sjkg;wxgLVmvhP?!yN?AcAc^G`2~%y#v)bf z{N~`P2|RZe{0?#Ey5N6LUuQJ#B5i*Ue170t-3&HBae@#Tl4V5FPoPBV<{f1#O|JYg zx)>5Dy94U_1TT;@C$a*?V~*iM>d@YvG|ywDpSQhVx^I*RnV41Ob1+hFqqL@VBnF_X zPvkTZ=}y}t^OqkQk<~-Y-&!WR0!paxr2cOICK&q1auBr=GQRP}wbKvKSs+P0r z>hs4<+UL=8UBUb4`;Zfcv^ec^Znana5~0n%2*?N4YiP7KUz88Z7v+b_L+!S>md)x!yIg+AToMSMG<_Ly_+JvCq)SX7^6;aeyapd^A z{mW(Vp9b;%kFyNR;EaM{a@BKF-dQ|QFh7jMZHVWk>lM&#M}FT&@9DiCYQB5!k$n<2nfuYb3g5^UJczfOMkzZ(8yBU?emaomyO?&Qu$?=2{DpOKle zLv-RW2#m*I946R)c%lN)^1~3$(K#s!$9YNS6q?gJN4Mr4i9}c~!g{|Okt3grMu$1H ztqilNgpC`M_{q<6kluCC6m;cHu{0q&C7$3|tV)fq-#e(WR%u(?kv|kYm>R&?y z?d4K`_gpXxO@k}7wl#uaa~szj$%1=ayIcKk?I=+cU1lp|P*#3#{uFdEWHD8;*|s#D z_Qbv*-YL>ZM~b_3s^E6Fk;PQOC3wTB!1FR^=KroqVM>7y5Zw!IUYoO}3}qslSP z(K=Zchsv&Yf+$F`W3cS;9*WZI6_V zT;Ah~uI@qL9D`#FOVBJuQ~s8WbB0CKur+^!-fEqO#&^A_poSWfk)2K_K{|P!cz787P8qO$^Ob{$9DlFcm zX3cMAO(&zv85B0k5?W;tJz4VJGR0!5YkP9!OUn|eY=1(*@5stLO=B!0lMFAGn>8Tf zc$bn1==$x(I`?+yzgypzPF(J*$M@>?eVVEl%}VyAGtil@ioO(S3YXOXwAE?EW>JAx zU@O(=cHYMISX@ujuK`_lK--(Pvfx37&nZLL<>I8n7EO_=BV0d>BqI`xZI zzcWL9e`GmrJ@=}=AMNT(>!a^(>-)nH_3t~>%fV~a{N`=+{h|EBW{sLzL#=NXs24g# z(MLV1wL!&if%<-ik zT1L(xC>}b8Sf`Hkf;)$(Z+q|fOR00tqOohwIfLl(8KGPpC1M;SaD*VR+h+GaCcU_# zXcRE18l~BbVv9BeVUZ$5G*gbAJCIOuv;mGZz~S=mP5EY1BU`=rW{Yk-S=oOu0@Hu_2|OI|do>TEzO>B?Fh(+IFhq zfZp7xhWaI{Y-R{Y7w@fDZ)ot$%+!v>m^B}MV<>6^H!O0k|1sPMKCp|ZKH?aeob zF;1ykE(^S$af)ReVn({xyQ#Z};PN;`ClR@4+2ai(r^FWproO@okEg#Q(a!eJ))~7J2k`OE>*qfnf+^O$Dm1}7|{Q2<)J=WOKAt&m(1uv zMH{0%;to0X{Mvz8@AiUeO5 zLAe%XAm<_su-O3LtMbjJPPV4!ZVeuBpqjp1mPV#KM6ZF>Yv1pf-a&A8mPdAVwoO=& zxWIx$b9Ya{_7ii4RW}=B74{rH9P}a*Co?!NFqo4kX?PK7t7>p{773jC7umx`J~jRM z(bt0tOpX7GKms$yAoVY|mu=wlmlmIi4DRfLXD|*^NFHPSK6Q<{>ucl|E~m)ewlwF| zpW1ZS-JGBmhLSMB$Zd)T?uH4m{h=hZ=?6~nm>9z)c1^@+kBT- zJDWqEefrr})ot2q(5L!mCY(*YN{-HH;&ql$aI-zo|^Xi)pHToRZbt%(Fo>&Y8<=A zCu~ZCSz=#VQ<(BWp|Xv=!}a*L$JH@%Em!Iu*RSY3Dz~6CQdmfsR zAG*VQg=}eE$m0?!*)4Q@N;ZhNGySBz&T|byTu?R%(clmlZ3@#p9H;k+?zVimTXeVO z(A}mxE%*MbENzhQjmW(HjtJ#jSoTbN9-l{NXFBQp zy`?ID9?9o=4)U#=n&069>S-YSxXBd}yj*y=w9_5xr`roCuQ!BvXtf(CM~|PEz;ozO zY}v@X@mH^26{130M;VRFj|yp?yVKX+(7a)!|LA=$`h7rz7Q+n%>a6b9^dmT zNBe;k=2zJA`A*NzU#k3B6nSUrU+FIEmJ8{Z zbo9e^VLMBh!W5?|<2cDzNKo&^nmR`=YfY@4{O`jg$VUG)cWRH~#qaGb$p zR>GVZMwYH~-jVxg^bT`gxj5MNL(>hPFYi#&zwtEJ1BnY=OC}1r8ZKJ(pnEFMMW)!k zdw74tOΠ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

    EUyTCz1;GCpfGvQ(e**sX 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�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 z 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

    }dYZ!XoR4hePNvP**WH|J8JZoo%4`CjleW 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

      %ap3}3?b3XgriHGXU;p~K~s((@Cu@Pt%6ej zrc`j%h)Ehg`XjuSPrOn zfm_ANTKYaz`);rcYw2nYlbyBvbm;#~ZS*>6*Oz-tzVF}cC8>(5Q{LB4o;w0=gO?Oy zN%e7yM}0s0mjVC$uY6o`h9msb$yvw7gb7@QDHZ zzyK4n=Mcm38pOmbF&Ji)UNZ-|jr#*y)d0SpjnV)9S1p~O^?wKS|3b)(aSz}-qL^em z4LUu6aRvbNO5ylDt2BH8wS}%){eO%qT;=s(VTg*ONr-8a;%e~v_EG9!aCmDH;P58O zl+3XtgJC4Q+u7rp%S{g@0zK3P2!DyF=kWhV?-dumj4PXRQHQw{*FELt|9OxM=m%3K z1(Bgyils;nwr{J8Wbsm64e#AL;n2J){#=j4DGYC!Lt+w*@iK#{GB)q=q?oJazKQ{y z&QeX!WFVw~`GB^rXB#ZHsjgqH{;=`;<#o~9>J2~swoKXUK!R3DPGU%vox0HZ&PMk$ zem-CT)HI-5)cZ9}C7TbSzK`~LUc;pYKj@K1RpC zmjt*=*Mw-@)Sm^Y;~I1_`H(#dE&Ajbj$}BNXK9M#F%sq`@5{({E_L_OYPwa_ai!Hx zZohIjV5L8e*JGtsfx>v1kX4FSTe9_9U3&O%1n^nE(d;{X7YzvVX1|Z}b8m?(o&WDt z*kf?Ex!L1#r$Icl`5EO)N>{i^KP@X^U1VL<*PJ-J+jXvFMk3 z!mLkca6Rz6y&tL%(8Y0$V8DS%fX1t|-$UUEv=5Y12l@__3%6e|cpr!AF#@=JRJo-M zNr-ytn8FYYJ7353hP4@Ux-HOe9p*1(E9y#;l6Zn(6`IF*W^|%8W!I$dqDL51U4Nkd z^KYR;;{}9^nddcO%5^Tk;XmA@v3=0s|E)La2AY}?+WSuxv;R#X8OPLmp?&`fl)ryU zXx|UkmZ~8J{;3Y^EZ)iZAVPNda)^8RdAf9U;*TJX9smz8J_)uPC%BI^JVi1Tln;N?ov^dAl`z(O3SBBzwj$vq=H);9&9n%8JcWFT&MU3`}`TXJ>r8h%i@@`j~`FNKH4g*=!jtD(jlS0clp~wWO zGQ=BACy9M~UXOP`-C3qlL^Fu@17to9Y`nemSN!7;PfKczogd-5z)sXs5I*I*s=~&Qj8V3ALDX=*$u-puXFuA^M>{`FMS_k3`gGF?jxOfsqC~oY};P_Qhay$uWfINDOXIEjb+PPk+GPhsc(14Kv zC6-Y!8mCyA=5!+imZvN}DGcEG<1H+RcHHao9C0VkT8w0m8P&^T@d8JZ49p&XV-75k z^slbHtLl*mXWEZ({`4YCRve@Ke5NL#it6q-` zcl@t--wpaOwD*DB8px5VmvTQMih2INS#m9-cEp8vKD30-5#jwO3}FaE7{YMJLiqkN z3}FaE7{YKTL7~cR57)}b7e9J!Kk%#8O-psui5Y80A={Z_SGuHUjq&=X5z`gz$)E3> zo#@rQ1ag7vF}~@@a>2EyhpSTDOM{1&M`~Qsl1M5N&2TiP!Wx%VLhgJom)bU|`>ajC z$VJDaUIt09R%NWs*+EgW>`H&dnPbm%SS1l_IQo&uvr)?6SdaL6em$H;JqEV#b%2KhvTJWO-(2s!`&D`UbgAqs_3y#!)Co*~eN0PZYiuOMP6AHXU@OU$s=7siI33pDtR-j~wcV0ZqW}_a%oJ z(fZ_3s8!t0_2%X-J2%q>RTffW5hqxJOfVF|(IO{Dn9o;x>(^ni4es#e(y09ar9(=6 zdG7C;-Dcs^xB7v(HQV2>TLyvgRw*kzUAdv%-#6RQDdV?De0!FqX^^KDSZMtWly3v& zlb{K+)Sx>ng6#H+JA@oiE?Zll%WM|AZb~A+OMln32P#QU^+bz!+ir?B@mny^aiUF^|+HH@FIHZuC6|sND~| zKm<9S7SmwYxd~72>2MBh8%$FSO|Te+GbG8geqkdbUdm7BBNnB>uBD%T7CA}PaeM7` z6pb^OkEiGnf&;Fhv$md&j79AnFY^OgOir zpwtnk^ivq*AU)NZO%J(-{BzI#=1WshsAd?B<2i!lNRDR-8pgvQ&Dih$2viML*Gghz z?aBhc^;lg-LlH<-;AK^$M5gkAn1^3D$3z0=r;XW{d1`LfPfNO0nN6bW-gy@L8NaV&uN_A zpISLtXq z+QNvB>-$rTp4SzE6lqSRF`2~#n0P81RyN#q`jZZwK0k&w~!XC-yxbk1fh zmT$t=UlHVVTc$F|)<+q$_r$eo6Ym~qt{axlh9L}h4D75Q#z7du5QZ?^3@GHSM!J%l z{Cc#bL(kJdhBs6T%%-Ivi+a@c^R*AF42l6fJg3X`lNclLJSB+&Ek++5IwNJ%@?>!6 zshk*Wv+XWt)01+IdjdOYQdv=E367Bz9`456S*W5Xy2ke#yf5n*kZJ1**(FwCRYg`Q z0#|RioY>pzt0tG~OiTn)n2J?`OHC&Id@Lk^Pd1Q4!rt;BKHbkde|dx;4?w&@KF&aJ z7-f)0Nz_fyX~1ln;yV1pg}A#v0to6>^z7mdiXgL;N@1MW(+pj$Rii%Miy%@29*nh<%kaA&$JXG!H0)44imaj;id zmmy?ZRgO?3io-ccQEOJ)KJRLuBguDZpLKt^WJe>T??WvgydUg$M(<7kxNKKexIWZX z-gH;1HLv!J8Wb=jq)cO+qVlSWiK1>u$U5f0sXtlIaIKketkajr(UJg?$8e72D4xS8 zit>{Q#+vmPn8GS%yV_2fzKOgN&}WY-5I5ZAFqp{e`s^9B$KsR10G`iFN3~;)tJ>U* zTI-WROBW;;w!>)`B*kiHS(Tz$ndV7R&TOiI$%|Ki>q}t6%0n|+{qzv!snoan=j;B*^EGdBK8*h`{=@hW<3Ei5F#f~%592?K|1kc;_z&YhjQ^X9e~W3Z>-(SY znG$y@)n5`@B=9;fDwINC3Zn{@W*uDJIQ8qqh6v$INqtpWZc@3o3#1^T^v!jx-c@nx z2U~zdXRMw?hm=K;5>y)FSVdPBY6&t$VHKro=`S*V($yff{)$i50#Yp>AOteUu!P7l zG{Fnf8q1vT-hTA?XjJIgmWjS8>i=NDs5}7Ql(PB?Tpn5_bfK&FOfJ)2pvg7F6%7X<7+zquUrJ)OUL1&6te#K&b7g5Y|;QoN2hBXJv1zBDyl)qI@ z)5D+-<-#Zk2n)3|3!+~RT2J8l)eu^D07N6^1!}&8I{zyhlm{UB7UMP8b+bY-x6&|# zAq-)--66HuM};-6#hE<$ZiyGENkOWz=4p*GsxMA&`y|N_1%eMEMRi|q2wx?suBf8h(gV6!Ei?5}d zW1msj*_U0vKGr*J+f*RDE23`Wbta&7lqm?4Ho!JKQ}CLSH99hQ@-LgJ6nGYxtM%lp z)?%iTQPrDWJ0HmPsR!L#qBpGl}~fXKh{iZ?*;cf~E|WRoN= z-?jV+rHHK&YgI-ona(~!hSGU#w!KoLAFM@*1OSkHjW?|J9an=fQAh312Gp4nIUL7X zju%;l*43GcKpYcI2LBftneTO-GEIKFVs3*#-KVI0O6uXr%IvQ^nq#vo-bi66ENnCw zbWrq4))zhBcBhy{lDEdsVoo6|~C`0kGHSKV=bZGkh0IW#^okSy-n(;VBG`RikJe9vZ9{}9&vn<#;ihq~V*bo8XhUXBhN#%B zS=nB`Q%LV;S7e(cI2Efv5i};sEQLu#-Ktf;tX=ND2(auvV)ji@Ey!~XuCsgEjw(7r z^gyCPY~*ktDjtE8|3h07vE z3hJV~{_YX+l@kH-jr?^KlHixF*po9F?0t;Zp8TZ80C+v4NLjK1IQ72bNJVlwZu~1s z5-(7)#7L~Tb_PTKm3u4}_D8-!vmY7sM}B`dZw_thoc&0@yn_k8|AXfM?s-iAdFibp zr(At5q{qM0Iw0{-6w5KV$Vn1Oqljmx**7(r^z&%qIp?b9if+Fly&iHw%fNBUsxnkB zo70*pIBlbqJ~w9eX;W7oOWhv@Z-;y4l@vYaT{C7!{qw{c^f`=RaE`z@lHxFuV*Pw{ ze4+Kf0@7E>1y^rZz2+0Qf)Q91?N7i2PgosJIo&4qR=geVqGU=+r;W+w=AZ8rU)&gj zVQ1%M162_6|C==qRYE++ls1?{e15Cj6^4H&p3P;{E^{&8|F_U1dPl$LYB^YqTzCO! zpiC{?J-rd>al$pV)dy4CTrtCOPb{gW+eEqvYWMxY)pUP{zU`(LoIA_w?7kf56&2*G zop^=V-7_;4`-G9LmmcmoG3nq<8pldOz6T$efY-(Wz8y0B4z3q2=Zcn65G&LQJ~>19 z*ry@8k#^6V8)U!Ml@Nb$JK=V{5%1eCxSb|M|Kf`|F5vq5t`OT<(*KJ~N5G+Dd+0g9 z*DD&nxMcn3t&;=eH|ZZ={I){i8-_)aKAnK{_rFVL{s9htO_0kz?Bn8*<@xDEEguId zh`y+$!~$P@H-+d7MQKoeMC!7L;5V&pbsOV{=x8-Mo8}={x_14!fHa1 z2)eCkaQp~%TZ=TP2h8VQTG|aU&M*Kx!YP0=2tqiK;)}-G*<0c*J=H0BMjX4DuM1zuO=Wt7*XM7R{hM%$LHK`*7G1*p3UZ zZ?(BOU$uMksU498`{-}3V^x-a+Auo};-G!*PB>N)NrGWnh7rKsiJv+~Rs=#k@w@A} zclWJ%?gjMy15437g;O+6k~qWp`Cwj_q)%mqRs7+K%A9<7(dmFrr5K!GSWLwUQdD%E zN=;1&och;$&9&;_BjamL*XddjMH8GCIFTT6NyQiC_2=4cjI)5QWi>MDn%O;k;N@La zI|S)2TNH2}lSP>pI0CK=rPNbcnZ>Tw*BHcsUwL3B?r#{3DA{xh%xI$7Y$0!WlYUEcd4@~YJ0p>;D|A<~a=w_sQ z>pXI5cM~$Ely~Cc1V!L9slu9{afrhanv9~{7w&rNn@yj9X)#uBT2Qh?(mW@S63%>5 z_g$vEWxF}fpo%CcEsl6M!smP+nSZj$ zpbZDLbY6&K660>3)-~@vXTab^GRF{@pokbD%5dm|DDxvp#-dKqY|ZSX5v9+zpA(glaZnr+X@R_xAkR+eA0?m?^-bv8A1i88Jgr64Ce?Aqx~FHey)+?DdgmA;{N>n z%Wc+@fTHe2Qxqptf{byrtjPGuH?BX}pbH%dOY53M->uea6hVGObaY0_Ob>ZFiih z4eU0}C>*%g{8lrT9IsJewzd*<(En9h9A)DUGDcj zY4AcsL5RIodb<=yv8qB)s-)ul@4*V@ED*h%*2{}k|X*LIzHW$9z-2LO;18<*O zh;}}U(>P613`OBMhI4*%e75GxAp$YSo4d>P-233&p8_@}TbGSd8Af0gUX(ZttKRRS zD%KxnCx8+@X&AWkM*kZxt9QE>{pqgr=GMS&(piF4REgqA8uN3Lo=_p!vjXKlI{8uQ z?hip-vvupDNk!y1nHDKUICEymA9ttjk4h{iaYTmr9MyKpz5LMUD}Q_vTzO%ZAQ&l} zC0d>uFeoeMo~RDmca@>kgvgtMe6O-W`^%~xQ;6*->+eguoSU`EnoW$m!Lg3}-!lh1 zfG8{}@)*Xev?#y_kke-0)MV1n7gou+pMP$_VrFwg|5HK{Pbsw3mXV!qlWaHaEYrJW z_Q{f!zN+Q$&rN>*cuOo`>1|2AX|V9vw!mp|4wb&!{ypv=__bLF+anoBO5hZk5^#p% z8JK|_4;{OW2J#;Fx`#7bteh5j7)6nxXjR5pfrp3jm?jJcTF!@{g8YZ^UU$q4+k1Jx z2lnBvh@#A}3@hV|uDA^_%snWU?W)5PnmT2Z`GD5TU9~jC_*G3)J3X3387LHIS&Kgzuwyg6{68+tfS$$?zKf;uk^|w6+IdIO) z4ip-L<}nUeL|(=>n#T7&`g?W^tUXix7H?J6gUnYiX1i;Ya(in8P4<1=e8p^XLiRR|Q&gMQPnBTWLSau8b_{e)sdEx;_8yI5ff-9H%LQW(b<57?y_- zHs!heN_Le)RWZbU&mlSCrPl%p_$U>ZC4p6OLRDb_-?U%z$E5O5-_*Y*t9$3Fk7i*P z0iD)0>n#Bo&5Arl3baa-Lry=@IfnYf3^tIrV|>%QO~IxA*82^!Np#ombS)#TIdGKM zFA7EOBxcRmg7yYW?&v*7DGslFcBUdZ>rvIG4c)Rl;vq22?)6>XL4L_F-*#;6sfnAR zoe$)}|L}7d)*|}3GFHEwP~l~b`djtzO;G^;A8+=(4}<~yKOV6gqQ0wtk8gfqJKy}0 zw))?l3){hzDh#m{?og5WJD1O$_i{)Cya39>WC;zcp*{u&Ex}J%IACeFUuD1M69rG-#d06rAMKY_hp)Jd)e1ZKJ?`bV*f^ zBpLHs*yC@VNqzCVci%F@ZTO{x$8xjjQTOKqK7FS4>cB!l3R7`O!bB05skTSkT3crv zNC;LaSR0YAZSbD4Kr_dEcHHNG&6xx^fF=PvJL59Oas(;SD$DM6_IT!U(?f}MN+=V* z*_yXyRW2$lU5@+MsXo|(oUfcP-^`S)1*~~bQeH=ooi_v>v1hVG0Ime@$zkMR9(pQjdy?XY`M#y=ha6~ z=%RzhDIzZ894~RAH0_@U-~Be_WWmhNMiAh-DBm+>e*@_pI6c7Uvqomr%%0#r(y;Xt z`=*v?vKKW?h%dmw|Z6vi=*3wUL0kaA_$hkMVb~Tk8C%M z_6&)K3H~4LB!9Jr{`1m;Gw~&RAGOs@bWfa^`hc)FaFAezkR(BtX-1&ogZM6_r-x~7 zv+&!tsA|EWnwL~np=5~_1=7@EQxr^&Idp$K_a`-?KhBAPvVHA`J00w`}wg}w= z>zxXdwnc;o_YQ)VVHAWR3}Fbv9U;@0?rv$i{=}T6NX;Pz=P5-}86G43RL@&4%1`SA zEkK#+{(R=9p#VM90D4yj>jD)XM=V+4U$`;hw{0a9q?(pPU$C29YJj-A> z$?_P-UKaA52sRYEg``5qw+@Yq2N*} zTmHi3p{4Kh-J550e0}jgAW1tI;WtoT6=g}LX-4E#mJ=?_|2mSGwkO6>Mz|k>c>W;b zJ@^)63-o-5K|MpD?}BZYImG^049c?@^!LH=`W%KJ0A*!qHZ61~n(A9ueHd8vpTHRf z!$gcEX^|#pdx|O@_iw)`Gn*E< ztta9#XLUz&4J6L743Fb1gX1Jlg|5B!oV)e^Hoo^w1{jPT=v|#<1x8>593w^b<618H z{p6#uxWNi%3i1Ea0!xVR6*unk?drZ1MN<~jV)wjaPg0AbKPE*cBlo->G!JMZcsGk0r(z+&MjA`PVJ2MUlGLUH+-c*ABfL1oz8JEXOez z$H)SU;(ljE-r8=$^`r7e@1dY_DfbU956%59ai4cacXeh0%^)2=1BFoqC|n^(UXWOt zkfVDG;HravpFi@UC zX%kya&%2-cR~2=iTpj zf1pz1iAVu~%n=HsNGv8PBrG7fFELb_S>^7#XlvS6-O>UxQ_5(?KF*4<1S8SBst7!D zq*By@*GElA1`E>?Lcc21bNGLw_eu*UN8Oxq&^zC1_sW%Xs_owbd{||ph|w<`VYXdS z6{j?!zv9SBAFap*vHKi3UwqWy;*QD%PI#n9-?X%;a>bgQ1((+6Mpz1FV>+{laM@q)ufbWh!?3@1maLM?@!U?n9 zof~!W@v3c+^OL1{PT?7Ww3Dv=FmkV2Bmkm&mT7Ri&wdDC7r}ElK`}Is(H!k> zNHShi9kn2h?%r_6%zf<5xt|BHUFT^Y!+C~aND8O?+;;(Iz46FiY;o7y{(8G;7AYfS z7>*zbjA40_!Fj(Nb@#c`lbkIGgoNld(LF$kBkK8+7o)Ozb z0eY!R^j8ekmVSfRkuZf^NU$t-4NST zG06Ao1})nBpL@m!kN*5N4-A0z#_7!_j$ko{P&scnLaRNW`_5lOuEqcJcHHpjb7dr7 zd>P6|hPdkAX~MDFt-Zzdgthe!!_Pod817WDacKfzPbx(Era&kO3n#&PGvDHy-lsjE zU=Eyafyx`B7g~mx?P6e9|74XCz&FAq`OO@_ZLHX_`VT7_QLTrU{OUJf(b1Kj zEnO2L@7Dgmpc&uI)%r2R?E60WAG{CV1Lc5z-cEb7p0>;p_itZSeLVhJ8d{E6cvDDH zB+06ZLNS7$H=W59QRnod?#R3PJmNVCPOek+Pp)=F&XE)=!Ap{YVUjH2bb||Nok#zE zvcSPYaRufjWmJn>ZfP;dmYZBYO1yQ{eIzMK?Rg4)y+Ftej*%px2sC{C7pf~#v&rNB zed6N!+igJdd=4SvNEe*Fg={N>GYn1R5=#ph|K{)aZ~DGd46A**_9joKWg)(|EXZ<3 z8{9ROG|t875bv^@++;j9L9`1kGs$!BI@0dBHFweeGznc`vep4ghLGvBN!mrG*STKD ztW2je)|n%ud&APg4)$Jb5Gu_ccURs{k9sN+xW(>PsAp_<+676m+C^NH6h_8KPNr#c z_W6_B_ZL{5f7VPtEx<#BFCJ2$GgkGu!1;?Yf%9;vQ#hY&kWUJc^)2mu!Y$5+@qcUb z7Sjp0Qvb0kbuI-~@>NxdB}jr$F&wK~wd$8em3%irW%Gzhe!@K$vu{6lETF4CjG|SB zlLVe&V9yfqh}3^E`O-Za|E*tqY(XrJXum#XP$Z=(2W8na1gF=me{1c9HRXs#$oQwh zu4d8D`3BYtZHYK98UgD4x=>nDD6TGaEyM?Lrm}@zI{bMs|KAlPzJnc~UWoTf+ZY=j zFO=WNgdpV>#bv7_p?VS^d09#6)Lce%Tv|}UV4X0P5gx)&wz2@T>7;wZ%wa9lJ_9GP zCI0d#pNM<{!&5RXN(?8h;iA-&Gd_;&`!7Ql7N(aw5(>GhGj1{OkuLMT0cX3t{$hm; z8q-`RbyDoM(Td#BnPu;gC660TXaA`7+Z27fcvPtw5jch4Gb#rFeTS~isQwp@{yF!~ zkH)Y6VlfbKj_~2$LBI-HQAvi!Sy@#;$k~c%_nkksxnT^rU1s*g>9XBQlhzEuso3+?$E+g+2dpj%q+aEabKrY-(|su)C9V#rwWLrS zCWxv^5tyv2wUiJMIQ6ghN4KrtiN&wk0$73QscMT^V+SbCYl}aRE@}mG6gmVaTZ*?N zSWK7QkIc%jyq*~#NHEQj1VM2OOENg^=iog>J1pLVP@=u;uGsK&&-cD6aPaBh?+gyN zW(rQ*Xr-S$OSPpd{S`IGA*5$M_I{;5&s~WIgIU~2grNuQyyE`-;OL`Q);I7c60fvZ zGmFElUF=>VTBh7RGdssQ&@OmoYq0b;^xFS&ufDYKvAV;82pgy{DnYV@BoY*swBmy; z55Dzf0_?AG_4j4Fq`~!pJnA_Lu2(CaV-{QvT7~r=_t#5nIi3>&$u|UE78pX7MTL`K z`9{S`X5G|(h)o_cdYq%yA+&NohA}wHPz=VhJWu-R#dm;G|0>L$ia*Reb=qDZz2MxS zpiHOTrZ}uBgOh^SF(s|Yw(om>-)LuS99V9uTYOU^h_;{_743jb^D#d!X#SFJA?O3~v4&(CGSM=vvgek%Eai>2weqRN>#bFpl<1Ec$3`Sv-RJ1V=!O}cIQ#?!IG>Or01$8uitwb}bf)^%z@#nU275!(8 zh9$33y_LprIA#ngwwM1%BzyMM-m*V&O?CfH6pfEWF^nYOgv?SL9OgdRaJ0*N7Nz%C z+T;-;G#<#2tw=fPHyDIoSy|ZwY)&P*{VRitGDN*f>5ODCRq}k3cWstyK6)@|1}AZz zV5po&VK@0wn8P5cMFEO|xfEQYfbj#E5Gz!jW1nlFy++82fADxUq< z4laB?9lg6y-Y7>LL-II}(f*Die$@oN=aEBM)zcqaIP=rSfqnW*1SyIx3Zm)Yex2IFZQMvv8?iWJZO&FbiDJCJsDB!S~JL6a=a z5CrSDxi?0LnG4Zh!;_smXKUuM>i%cBBIuVXk>q5YkVKmPYGJdkIX_l6qYQ^abv}>g zqH22Hdoc6Gdkd5obnc~#ip~U9RcMw}Ns-~EI1dR$&2j)tumroI)bWtlI@imohz)fnpW7y1F4(*Vxm{=8UReF`%83sB$7E zbBaPTB5dc>=xn}7f5sT!zQXy!$z>?r?ULFHYZ zm;d*WBPzbSKl@wMZxx42jN-K$76ePL$1@fTy&e$--CTt}rJH+x>$!0Hj8rg+Tp?lE z6)TS8UKx}$qS_Bf<)t&t3H1>LwnjXMBAc0ZLC;aCQ8}nQoX#=@E*G??zd`-Q9oz^L z?umF@Y?hc>3z{}QD+cuwa5}R)rrVTE zXP3+lwoKWUIlQmmnY-%|)WqjJTZEojv(f<97VCfImqAd3)h>+bFwUtss6LfCJKlLD z0-ou?E;*6K{I0AZvV`r54Y7ZbxB2#j*2HY(>65xFFX_iLe;%nwTy6^EX^talPQ_3+ zD{pfapR}RJw+Z065fg4Pwe~!B@{3sq?*(df3v}iT&XCp&+t^=X{z(~g{`~}?F?Vlv zIiJ)7J-^x8e{0Wu;twNJh6Q%$ArbIKptr%Nuel=mkCbt^Q4mm&E3ivYl4%@yxr zma&F`E_U^Z;GTz?k1c5Yx}USAWY(|f&%YMEnym-o23&NzgpWa(=OIHfVIx8G*Nv9@CNsuS9PMe3PvToXn~! zfeRD|j|{8X9-{SF(mk#F>_}VkOF&&piDgvp?J7&t9O}ehp0fC)Fu>1^j*dSU{FmVw zxM^C@GlcXFP`(9}zYEImhR_e+ z3?;!n9Uugrf%33_893U;Q7C^H${&LAA42)Jp!^0Xzs4Z{43u|5`IZKYY#9Gx{D<)$ z#(x<9|8D%7O*x*AKfUshwU6%ENL#l*s&`L4C=$=umD1;8eFKNX0*t+hHRJwtVnjsOj5?=cNsB|DQCM zjIKWchGAO1WkT`Vf3pLSgCmq^AdR?L?MMpC*={Kml@1kMTP&tAo|b=4&-{93-~&BN z;}XqKJSG!}l z)aY%rT>?pYtu!%jxB-SDNmTGhI0z)DVwxv+$c~2nTImQIi-b{;1PmidRaPVkb{Tdk zNQVc7eVXoR`oABl{`PSI!xc9H#*}Er*Fnyw= z3JgW_5=QZ;Fn!f;@e)}*$b9u;w!5@BnnY7@lhtgR>8bKpc8j?0fJ%Hn|0O5q)$hRrldVv0w_K zZloFnJrD~#M-n?c7dy48|0>|Mz{gpps0sdwswb*mE%#NyeM1J~EQNOT^{glM!k$Cl zejUiMyTVgz z(#mZQz5s3mrkZq@nS9r=I7ZQwSHVnS#V=c*&Rv_H7;WV2E!Z<@uTZDlqNBk6@wHDwLKBI9UlRXN^6j-V}AOS)}j6yqF&M7>y4=Aw^CL?3Rb@|>~T#W9s=vH zmUhw*S}w?~B{IZuK#kkP5T#Ex?LjLo-)g4*2y>cV1_&#-5tOH0i%)9qTR*Tg1$;zB zsGs|_g`!(E-}*k#vQ3`UQq2j{1DY$+9$I@})#eGQ&4WgW{+$L=U2PnCXzhwK>q}pO zo9~Uqr2k-<)<(BEJs0k=n>{aXCi@KfG|iuzE@b3!LZmT?V;Dllfr>`;G5eMin>R&( zA>Re1CPW@>jIq_z`@Wjh*St|Tpa4to>i=4KNx&qUltfaHVKLU${k|#O>8+ke?|*)E zrEh~c?lPi8%dDizDyg83y9u{=EQ57{e6zXd;04u;_vN6|Qe zaUAAn^iU4k{{6{+hv$=5E*;(84lHCv)Ei~VO5pSjt-9XM1v9QTx@v)^_4!gl$wqVO zzE{%vjq=5PUWoUdp5G6zuV1}wK>u>0O7e=zF&HcBN5vd(4xIYeyW8`(v+I*pM+f$- zM2aFt@iIw^6ajly>JqfvZjUFs*MuF5WU!vO_0PMGtPI5}Njyg4IHq8PJb7fhX|!iZ zJSRFSJjn06#QLsND1e>z?=5Ek+LqA{lZwDgNly=LpzrD%Xi%>xCGM=G z@C@QPJnkPu`Dei$1Jv)~2KDVSI2{0bdRr@So|Yd_O8vdrr$S2^(O1N6e(DXDu1b3P zU#)f6X&^l*E;Kb@k5K=E_1dNh!plPqm$i1sX=1CE+JH`k_`ByKe8+pG*1_Et{r5&{ z-%pD1eGWTo1?9bu>K8)#Rs(Rp=D<=%6rND@+A_#-H!?4-28~C1gL0b%Ne6IwaD62$ z|JI+L-|-~({m@NE@FPL07leGvMx9K z6M${mh18OX98tY}&tvL2YR#72Nf6cNpUiMB|77;t&ij^pIBR1BtXFZgl-Bfh#q7p% zOY!P~>qC`ONE7dSQrEvaYF873>rjruMM98eNsu=F{LyzOhBhlu9fOHC^l5O&le+)& zl-09=8qR`%MuIdiQXk z=8g}a1>3TYlDZZYgT$=;6)DRucS+A0(=lCeI24C9$Dy3xIN7r9g}V}VY9;)w72U@I z?*H=B&e{n8q_wW)r{7NSZP{7v9zup@v3r6q0UR;=K7RljprjxrD5(12Nyt#|T3R{E_dP#?)XEvBrE?+GBN^8O z3kkmYlTb%%KpgADn!fT@0eT;l*A|lfHf|Ug@1Puzf_fJs%0qp>7g}(TyEbBVHA4sY zFofa14Dk9=)M;UKeprPYzt25?zQu%dY5Tx`LwgMRZvMU(t`s^g%=JtaoSf$^v;s0M z6PV263@^&?0jfce@{uADqdf<@RXNXn2lmRnh0Y5L0|qEEk0}(xQi@FEbj`|1ZCJ}Z zut-nC5C$Wtcbl-D7SnOhH}%E#eOm=#St0Q>qewDK)0lMfjq49K=t4)r9oZaxYdQqi z3-YMvMqn-G;lLWCWyNt%-n}2zdhUE6ja`P|S%xKLiQq9ns&nTSN|>- zKI~XvFIV8a@D{}X{<$Y)7E{UjV3D4ECfaEX=!s8r<|NJEq6T z*f0uiKumZX!+8D|&Xbt%)V`(rVsa^!WAt5Y8TA)7G)gX``onY_hA@P_Uztr`dq(}b zF6NgOfi=M;iIrrDrwN{8VNLMaiNV(Ojb~ruSLR&!0VskMx&9p^f-oZlXSFNYg59AE zaAr8+`(L!h_BjvnLG`0u7XejzT?-zPlqg>2Sx%wzRp~3Au1|U+fdO$@n+V?&2GsK+ zA>%!lsx^tJ`7tn!w}7N-W2c1j*4X z36EdPpzHeGBlfMl@LhED4V=X&9K(2q#%P}4{XB5|PUokU5rzpC(`C>3S%+J$ode{B zMP20r3v-o{D1qcTPUUFW!u;vVzA3Cw^E7nFZR8;r=oDY}jBfmV-j$gF9X((;PEeFc z;*7$=jvfa7ou4+F5;*lo$rVr3mhD3?zH1N#TM#f_P@{q!I3JucEe)4o)h=|DB!5z5%!d~=yEH28r_D*= z9pPn--huV*5bga78m)EHz8l!i;*(Cz(Auf#dw@Kc^Eo3*MgyQ+M>!)5#^yD=c<$Li#*FufOtW7n_nUcg#vpS0ry3#Zfi$YAo*0#Sz6scU35#{ce8sv1z{l zgLFsTz~6)a;qTt6Yx++^kqGa3rsKlt&l5UnPo_rsjkmV2GlaEQ))>XEc>UryM|2*W zZC4x)uOjwn#csFB%8mC#k&<{?RTY^N-hT9PTfKdc6_~n*Aq-&%!@ms@>Xz>J-5{nI zKJTuDM2l3ce%@@VmX~v?L!B8<1I}TU{%L~eM4G2rMZ)>J9=*HwXA!>@c#|n#M%D>M z4}nodetX(iZSj`<lWq5gftROo)Ykljs5&sOaC zhD!?)=U+(xM^J|WW8}C^3^EHh>^gZV?f$|4JYL`b6s#8|hQeimQAvWwCH7iup5scn zuL=(8;KUee$aRY;E$@j14<)2dLwZkTD2BvYmgg~&;V>RP|3qm%<2NFB-n6`&-8I(y zdK~v>rhT~*g0l{EumkcLk$(29;dUXzDrIFloc0{anPrEW>>rU#cB8y~v+&K_5nx)N z7v!9xY3nFuT$bALMh${3Q;`Rb%U1dcb|J&DdSPQMDy3g6DD!zupw(5&cY)H-$G%Bk zh1Y7nZ!OSypK8{d&IH3tio(;XB;rqh5Y>BR?3YQPSCh2^)*;A!+Ey(+1R3BigQh>q zhkmHO^}+iip?tilc;&Rx(x1$sk#uQ63c|MAY-*af@rP#*^gkBZ7d9r6I89?L&ym8S zy#8Ffjd2!>PI>xtLFV1{(AaBVH9>o)VQCuYXbk6gnxSdG`Pf>M>1H9Tpz_`o-<(`? zuU;HK$%@k?Jk#WMsG{h+&wd@kB*cM3o^ip}@}*T*XD?WNw}JSo0a| zY9iJD#9TzVnidFNka(4o>Bsv=Zz!tsXyn+Wu&R6W`fskg^VvpVe210Oos$Gjsyu~Z zEX&kuxADGbc6?!0{v|H%V7*QFE+XnC)f@H@`0vI?)$ov(>AVd?7;a~%g;*b|7L&d$ zhprBPvW9VfYV0-6FhBoGu^KDKF)&D{+fIZQ{@V`-%^6(%RnP?2{!c z*5QiNI+hfyPGzhUzCL@XQoD#?PUsP)&Up(PNpl}R5Xja_R#X`iRT`%S0k&MdRal#W zwyuj8hvHteI24MzYjL;W?(S0D-Q8V^JH=g#6-#g}1P{((&b7`y&ptPKlB@r}%NXO6 zxAmzrKLB}ki5DDEp)~#C56M#FiQ8g-LT?yN+`@L9u@F@ z#j{Nd*an#eXSTrnD;iSvt!yAu_DLtl@VIYg%s9Q3yXCWlrQwQLNpm?&Zk;zd&1*lI zss!WvVchqty)jRF-lcsQ46_ETB)?i`t5p1t2@^H>cRZpqG>gN_VzQKx$eJ%?cH_KW z_h!jk#FjoRp9WdI(@v2w&bj%MK-TM0`oshT3f0CzZVpIcd$#ueK&HI@%9{J?e^dQW zr~1v+5VM{LM+a9Tnw&-oOQoI&VXli4G58GrW4NQ@(fScufbvHpWQ~KIHSg*l!KU_m zepvsjfURzlDG#;dbl6m9i7otPt&Ur_DlUM=Tw_!wjOlliN>jcfTMz;lXyoD!eT1q7 zadBRt^}z7PcMW>v->-)+W{9!lo`gkae5v;y-QVgB<4uPXv;y<*7j7A3A=ZX(1SdHG z81_6yzLlSM|4LF!MyPpZ#m7o~Q5m`fM-;pE&_$unZ15j0>yko3P=U+I9va`DNC zQpGfK15p=;D9mJ_ZZ;MyUCD3}P8d=`Oc$AX8HnYv>I~W`y7(uHwN$C@wkWn1@tHQfnC>Ik-Q_-#++mJ zy)9P103fQ=$PC`=Q|dk>KeCyaSym_L)?|LBWrmDyWNp@+aGFm zrVl*SSQ}*Ns=Witv-YLJ|Cj379IM5vz>CndH**xC-(~oFLQo%uMw3^~;rR^KA?l3p zEp(s3xg%`1U%8HGF;X_Zgk~@XA=0?`sJJ)E^I`0}HLkX5Ol5xA6t5<7MC+Q=7(t%k zNRNAYQSp(LftCJkutpTBbTz?5qd-H?*6Om+S_OEl&_vrwIr>RhUBrJZ_0KnU(MkX5 zue{*hZ&lY*4N$GzTgny$W0yTYt^uakO89mA(&+9up|D@tWclaNuIsR7@sW3y1pM5G zfE8b%&HK<0DfHvTlj>>*x0&W-iYKqNo+@VZUndF)3L|~~_MZzlWh#jN4SMCGrMjL# z0CP&rmt;f6zW9>)7uV0ycgd*BA?;bE?Xcw*2elPznO^L<2$uP_V8UHs2NWoQQS?PRvBywB=dv3{}cRZMIC|AYjuQ_$g@g2 zB5%Y*2i*d5B8{j18IWi2CzD8u4g^P{L8p}$UuwX8R{4yHBY~-osf^i6jU0)CLMPl< z*bl~Ta`ntIOV)=~guH&wnz>lwb_Di#A9VA9)aAP6)F*-s9(2616GBcSDkQrFXsDx$ zz0#7+;-y$WMgeKXAzPP2^KwpJZ?8XSJ2(qPU3S!#Q^^AT<{2dS-OzHVN+!#STizw$ ztQHz`7dXL9u@yX=h6M(tYLRqh!OcT9c-NHcwxc=+E@LK~X|zF2$ghWh;EmES$7>)is1qIn}6ykKR)FB`o&Bv`8X#)!ej>WbU4 zxuI?&%h3e*C4fvrV`jkfq^=kr?;P(DxSJ?8vTGQst{O+yC5S?sgWB;dQ{GMvu%`!l z>ebo%x}(vbu0e~Tzy zm#{*fk%|5h(<8EDM@cltZCag~rv+hiwHY+3l}1u2>O97wfW6jFqwkxp1h&;BmIyf!w_HIHu3sm6N6#vG)fBej)I({}0^mzl1v@ z5${8B>`CwEsVP6|;j9FRxATT&uHk=)E^m3t+H?TzR691oG{`63o1cxQCAP%ywIQ;a z2&u)P-ePZ!0JDa_N(VDuJ`WeafpLp>d4sAgbTY^#<5;Ip^^%{v^_&{mSRJL~W;u!C zXMf8oA=ygciJ$&~6p>|YWi4z}1=AbQMC^UCnaK;R{ifldJe?DVu4V0VHu?xyK0~E9 zjl-Bs)n|>aK5*}udhU7I80#&KhzYETs6=PWA8JvEg(REwXl+7NWY`IfL>}SC1!tz7 z_g~yR6okk7aj)r>3)u!zC}-pZreLL5=F951A46!CvX?bwiqZXz&}9|IUDYTqzUw+s zEF;Tqz4Q=Abaed)WUoFW%f^ANx7XHLRz6=GeM$&qDx&8@yt#R+60YPF?kmYpC?qJ6 z)-UAQ2x5Hd@~|9LPN3d^MJ8!u+C~jscRJ!HLm=Dc>v8Zu96#z)3@YcH549m1WGMND zKLKGl$SMdQfNQoE1;j=1r(|Qq^iPYc&({U&jB*WLT<^=pZ#2V}>`3kLov%puQK{;T z5gc1_2^K&kLp1k5FJLdJC%ITE z11Sk5@j%+`Xx%LCCUe6L6-EK;0|^1^Dx9fG>N;zZ8AqaDZSU#E=YLE_f|*Vq;XH{r zax@QG&s|>9??N17qt3&2V|f0NZ6}jx`L%mGoBw>(t=XgnHH+*EMOcpj3B0kd{bL9Y z{xN^e`kteCRJYYuv|iw8;(l(GRSs43t%n*~ebr%QaiFMWgtXSW= zQrcd#kleLDoi-eIWtA2tPUFrz<7SzDm7wQK{q+uA`Su1 z9a8=NeX%ir-3BakokojkgJUjVy;&iBZ*tWXthD;g)D+NX;R&~i#}@lThJiK;r>>W; zw$aV%uk?hK@~HgC?Y>i0tbhorOnk2NVpFho^&2;SBS}jy&x^mHE}t>$S4iNR)*^I%HN*^YQ;v-EGd zdxQ7=eiyFM)CvcN;}GT_!u`aA4=+Pnibq6da`MPIyI$Y=WAD++T8vObB^jL}E31Ym zDwc(X%&+cv=>IOZLiU8By)U&H{^gXLX&ZFlA>GDqEW0XrmiE<+s0GDOgZp6-GkV7s zHyc9rH?j}o=9~YVs!KHy!$SbKQc~B-+A21YYc4X_8;|}Q7k(zmUrXP8zJ}rHXYe?h+Gl1lZm8?N)~J`O9|7c z?yZZdeEW79HB3OVaM&YV{PaelILSQ7F{W;NL{6hqDZ6;4?-UG zBfR{Q2$Q4m<$(0!_j9-#fBNq-$>;;5d|X*gGrDXE!l1ExxJ7K)4hD}S`!t7M(@9Si z3?!U7Wi07N28=;!--fT@$oL7_;x{`Q0l5&`s@h{er2Oh5U8=llPJkM{iYl(+-dm^l zQ^wFMtA+=lgiw~D44hK0%Ad0PFT&Z-Lgb2WF~4UgCR395OIXFKO2;DO#9DYT)5J+5 zV~GCR-p}1e@A5+^TcyQ#ii(Z$f$u97%^_wbxPwgfndU4eQ}+k{{sD%0(A~NbU)GYI zv7~;Xxk5uJtq_P`asT2Zo#vmnF#wr+&@~lc?U2YX1}hMPFNA1lHx5oPn#{JlC2IiHleTXEcCIYntv+kC(O0R)kA1Z+9-N1R#z}5n zYjz>w)XhKnwQJ(?#%%h|Q&SL}>#YJ43gjq+4l$(%Y?Cl%Di|K3>9N1sTP|vPIZvhi zDwAs)g2qu&+JuOZS1mHeoT zcfuJ`jtyc7g0owA>v8N}dfc61Q^{kyET(g9!unvSZ?9xV*6nWea3^S{U)+i`-p9%` zQ8HjoXuAHzRSKNogzor*FUVyytIB|uc6ttymn32G2~_rIyKXkB)@Gt1xuxjZF*U|rz$&7_!dJNfwh{V7gL!RzufnREaCG~W1-NYZXpW$Tlq!L%z66aG_}5UXG= zf70r6(Qt$fiW4t5;hSwOCZgc^tj7%D8!g!hIPs=tLE9FNjP>i8P;KMhLfh3+r z13>?PUxe2y%ihe|NQ{TfLkoX3WsIeKhwFHTRkCO!Qf6>qski29Ui`=4@Ad+!0C(=) zsnq{vY5|TVdF-FQ%5Z%U$^PdbosMZ0HuB#?pI=M+f#rBs(^IRpbPPL#rw-EDZ{Tjz zFkeoYzU4VR*s1RM(@}GysBR2=&jx4M_%h#(4R1dkr(t4Sb4%7M_kkBdWO=}KRpJFy+3Q}XicS_h;0MqyJnxWaE|yC z>CImln0pxM0XZ?e?`50?>Fn9RTd?ZoUFr8KcxR6evF@LJisZ}S%>@Gw*|Q7I(%zLA zcYUqP^b?%Po*eUUrp;S~;y(Bgt2aXGs(eq5YhzO=c?`BbX7h~y_gnt|Uiv>jq2O)l zGco|j7i^q^?|6$1-plI+#Jm5X_YV6p`NQ_KopRBBz|>a_l^+JxXL&@}sF`(bbhR>u z&#t9=c?PJ625GH_n7UaPzKJ4VzaEYI&YAWpp`6K0K#k@a>Pe~bA2XCBuaS876fyX; z<)5k$-jsw4JqA}tvXtgdm@ffwN`aIRd|6jEFj~CpiO#Ma?GwN|&Nfo7Axu03|3gc+ zC40U;!VW(I79OE|I&%x2;KFB>$5OhXE`mDsTck*cfA&?AB=~(6@H$o%dK||P*?yx3 zG)2>*w$q0dM3jt_sOPosDX&JAM1=a~Cw17|;LeN#I8G)jfdmKD?709^XuC@143-gf znkd+YdBTchqQ6QMe&cGV@^zWnn>p?@WzpS{cuyzDE`}=b96_Mr^aXdbK6c(|+L6;F z8+)hkAY~uWC6z9S$i*;9e^H2;*zIk!UgqZW82IG+5rEp(&Za=jH$%d!+x?qu)HM`a zHTdja!dh9qXcXDKa(HPUcF3E94Ylk~)1S9bkXRR7M24T(v`N35c9@gz)o7AJN$D)h z4K0tli{%*m`;P;DfPr?eW<@~rX4{J(+{Ak`Q5*##5U+T|1bmAT#ly-iyDIpNt z*axwJKgR#s2(JzEUd6Eq-N|!C8}C({+}hDDw$Tq@VKk!Gm6HaT%VZratnx606OHE; zZy^gP^=5eKJJd5sv87g z{79a3_*Sl4A5S!)mmM9ix>d#=%^B+y8j-6YSg84?W^h(a^V?xf{|2X5#^;8Pmcom# zz;)ptzRh#@T|4gh`Ve}7iqA|FmrRV)fVcGtLoJZ0Kd)tl z-dCZVtPBWJPpqLP`GqGmu`CvJXLGVQwYUC;63B}`tN&kPCb5*7Fg1vfN(xk7k#pyk z`3BJXVIu~Nm@^celmtoN{36p)dM%$9fD=}AAWQa{P6CNfSw|CAl#i6c!(*>a^LIUh z;wyl7J2DY_j>?-#*KI}Q@-9CAKVz$`dp_GSBR5MrJdB_64P4;YOf2l5nx6GOz;1QXXVVI zJkq1u#~KmQdkd`VCGFCB5h$|Ux};#TYMA`hLKl;bNN4>Xj6Zy3x;fz#*>{F-cY739 z=Zuy#vb5sc_C^oZMF=b!i|!FoK^;PdQ&2O;@qL~dXt5F7XIS@f1f_U;IKRERODMqn z{HmdXN0+=$lY_iTrggvMlOn7wR;OdH5ILZsw+GBy_g3ohx!%wU-)TorM>B#Z?dYW@ z3>STViUqD>F!RKAPdpD4Xaw*k`NsiimGBe+v`o|#jojO zuMc@M z#;5WgR>KHglj#&H8koA_`?lA&*@f9T0TKy0ldtG5Rj6n;prOI;cMk_1X!ftTHMcK# zL!v;o>KFwK{`>zFyT_!|B&5qdO^mxZ0N`a=*Ph^z6M`ZR?dpJL-n6~1WCJQEGPY$pU!Fls_@r*XnSOl z`M~%++Wdld;-3xj71{#kXGh2R<`A!-DTJnf`Sojx31*%!S`d2PdRWgT1C0lL#^kHE z!URw0F>XBIlYH0PzKogN#q2B$myWu2*1Q+_&A+qP_6A)cb2pkzuK*Q#4rZ3^K4Il) zmj&?U%dv>#pZdIWFc<;S!I#9jRZl?jmpUwsM#BQW-zDdhz{8NG{2{G4M`kdOMuDmr z?U~x-xU6q}t6N`9$bvX$PPiAiQnCG2JgU0AmJOz)k_3}CJF>FqY<23_ci?6dQxyt)1aIAGPq#%COz%Tb=50 zT(P?(Msj-24!T=xu>Zx^(}akaR176O#Z)b)WR7Q_^D9%zD}xhs-&Er7DuJx-m19Jg z!$_Ay07Ie`Z~fZ5tpBOQcMOcb(pr$H|9zH1`^m;CfAP7lu7@jU9}zr0((b`0%s?9W zfO7m-5lU@~OOysqC5=;|RQ+a?#?W8Cy?_@ft4}-AWVB_-hUnlfZlm|T4s?0sl60gk zS}2)xNC&`KaP@AA?`8g`5qnKm`)r?Iehi>GSFf4aBEmZ zcw~o5BfOZ5l+%HA6}Y#vOt6cf^1Z$!X;(;^K;dpZU$|)|wC(|j$kw?t7?gphVl)<7 zd&=m00(F0w_H5QqvHI99qht`^;5~oKuD)!6BZ!kQhhzMPz;D_EawM{?+h~{ant0@q zY38!@@Ico!BTE0-v#7^?)n1am%HzdrJo@Vw)5scverIwc|Mzeo>a~kszUAww|7vsf zF$fMP-F<`BcVlQhdiBoJC1e-@tBh~hY{>p&SlPSt@#31tcCQHX3lYaoBlEYb(M9i& zKUY1?idb)zm`_5JNPdPpKD?%~KoUKN`@gK&BV8Z719UTJCrai;5sNC{wd(e!sxO-1 zRve5Dor$}3DS8x+_pVM)r=jwUP1?!7szg#;Nb^OLhFmv4vr79V_cDnEV*2{oOJ-QZUWIy7m{M zF;(Q8>5jxfgG5au8_cjh-Q|*PK%6T2zk^O6;A;J6K!ho3T{$ZF=7!k+p}JX-C(8q# zu6fJaRknH(8Za*tl^SnA#MS)GUQsqGw>XAw=y`K-XpJwhHB>AVF*R#9lCijqtW%Mu zKd9>ypR`5ySEvkM-xQxa0V-FJp5-OCeW>jixd&8`~D=sTZyZU@ub?wW1;P3K_5MWmp-?LD~t*q>_be?KnH9-a;T z=r6tcc2;!M^#fd%uxPs+2p`CUXO(Y35MBhIUQUlLNCMgtpj*DA)?>>lSlnRKsNrk1 zM0xQR$vbVKN1r%v>l92Lt3S@r@z|Dne7JJ`J%p&|(z7vop4s?Xb{v2r6K$-Kg)I?J zjkk~X*+DPOq;VLNt)I`Or~IGcT*Dep+|pGool7V(R2@BCRS3GigXEt}ik#!~qX75a z_#G8aP8Fo6=`=vjuSMMP=(-&Glg z-M95AYqDDnpGGJycB3wGf~~FsbmF&7{FL`lTR(sUkp0arlo^mpU}v|!IuKlQ$}eWn z{gw|fgdndZT8BstE+&<{()dq#Avcxr!St1%957?#&+KD&g>Dh~RQDFyAJ0sWJsJ2$ z3wdSSHQrH}oLh`{_!U)5QO+krZN}aXS)&VfRiE9uBte|VeqM87bX-X{1f!oxTdT5K zd6yaSgMJ{l8SM!Us4vnop=5pXBI)d%2(%4|^X~0CYONiEjo?0jH=Nw?D?dIjx<$D8 za>id{GTqJwDia1Zp0b|2DplyG}+yjXnZ0!*7^&m%+FdyP&c-f~=gKEtx44(8c+M@D1sRyiF%eMSf8OKR}nt@FA12caiY z>XNG#IeCsM7<60?eX@w}^x6MNyMOrXx9xf5AOs(2CzyA(JOh-QDrv5=VG6qh7gX3?Q6-&x)| zClv_rr15mEJ&i-A7TxAZD&i#5=(X10C(d~833PiX9zz35FE5$Ei>V_0OxBQ%sjT8e zl2ysXX(q++>1NK(@U3Pb(}7`OfzQW>*QDkR7NPy)Jx|h#9An+q4tS2`eA`Prk1<-y zkVFZ!Z`w*BbYiMSherOT1XHgjuBiGGC{|@6PaWskV(EK>_hy*zSg?#{_;D-E9>>IC z#A2u_wyk6Ecp$q{)f=lY_(}o3llKB48^XZG?a+m7BLOrMS{3uvuljbXoX~o;rq5O( zr`h$kbOg21z4E`;QV;-BTCEA8H)0}FvZ?Cn6*yKU#%kc-Ue3k^BMCHO`R#(q*(L(4 z3@r(IBCny`<~80e-M(;gLOQcrt%r8J=o1(JGU{Z|ak`oQLi?`sTQBzXavn*3Q|>Y$ zk%$h93xTl+HEfliMEW}{24lR6@+=`tm9#8=lb)G!9}CIq)^+d6I}HL=-72~~dc=L) z1qoT`Ykm!2uAekp=!ebuC@BRR4ZV{__O;Iw%^+2eS5mT;xLk)4?D}zYALIIc`n7#2g1i=IHyKW`O({h0uO7lINwBd`Y}^A9Mxj)u+MO~fB)(58kYtD zi}oX1wH4;P+wTHfW$*aBgkpCj0s9i+dj#PXLoa-On&v}kw^UB!)cYuG8CsXH$7sDsI*DOz%|cd0so%u*L9Ce za4NX4O%?vTuH=BfeY}H*6%{WKu+ynP>q*u$h%H$VNB`M2cy0j)0$>sW#iX(ND%yoX z{+@_Jy7H~#L8i?z$&K{!cAoVpx0*i}O(8$d|08h~Mr!d(*=sK9f>+0KDm()|#cZG| zBnpTp7mGxah+bRa^1maKLE9K*hPMLw*C1#4wF6?ZHm!)XsPS#QO|-CDt55(`7jxex z!Jl+rMbEWcV>ayPoGhR#EE{QhZDZ`~rbBl;*8aZ}QIHFiC*^L#&Jz;L5KcDH|0|#c z!5AxZibDxdQa@Xb5%`E-l)9xU-yju>Y0pgsVxpL zN^whB77)L)_GeqisC4Bi2A z^i69vJz)UD@i9wE=|wtOrP^tKI)Y=gmzd3u!i%aVaCpB=p;$e?yaTU%(C_>!E%__e z*oYnJ>0M(f5s_(O@@+J~R|Di4Mrd$08^XRP!jF}u+vze<;E zd{*UOUgkC+{*h?9lZnN2Sa2g)BnsHZ)uMU~@Kg5Lc!a*7J0NYK!1*Yr3Ns&WaE3%y zhBy6mF*b`B2Up>49oxzbe%`710hH@$N*3$=z%9;@{FVI1R_bkRN2wNK(p#WAyE3xe^*3&HYwvC)KY7>K z=JQoa59D`CKS9K`Y@qYw%I8=ND)3lNuczixeIxy@s(j$ z&|q7O)SCD0#xnAJ>Of9DlE`*`75lqULrmocz?mGbTv-7)-12u+NB#ajQO%Q}QBq6} zYuiD(YbGmw_^waydcwQ+t2e?ehz#z%^}>N?GMC5v9zK;PTj$RqCjeAwUa?LgZ3Q09 z?jD1>^S2jQQ}su(i9`X>KX6JnZkc{_UnIajUAvoJ2G@ttDvfI`W8Jf!Sy>w-*^wGD z$T_7<$rdohbw7D8&cW^{na}42k8gjs|5PSo3WkyT8XAVt-nF3pVab$MkX8g7=?$?W z8E;w|q?9>mOUF}z;>1217=CrXS>PN^P!*shNSwlJv-nWe}y z8Wk8#`Y6BtW;A`a1v`9EUL-0JrmGV_s$oqA`{&JQZBZUBJXR5!22`hC`H3o;Us|?8 zFwz+vnu%_l4W`Fl)|X4$XP*OG55dIGJ>2b2_NEEaRKre;m$nL+U3Z>A0|W@=UZVkm zr^97}8fr#@l{+4m(>KWuzbqC5z}H{DY`Qfn5SNA{0;47M@H6DI`J9@tJ2tcKN%Zc` zXqCZWE=cR3r=H^}&_<16cq0@RKwr_j@tdg&I*WP&r!Yt&rX`3d@vdpKdauxPyUnl* zgjj>lgK-)rMM-p+jRywf8BS)WTuGZTCytE4fgev`I3n=2rA!Rv+3MHjuQ9H+$# zz}Cq>z)N_y-sW$`qv1%nfzsCO7W$9*!B97zIQhp_es~{5x7@$^_}m|}f=l;7$IP@aD6eoXnZH&QxinzHrnIN_2oXo2hB&FerqDOYPs0xY51>^EJO)8 zeqDE~xH;?s%{&{haF`uMF%CyKR~MCfc}%Ht28N+4}r`0OF+J+8`$4Se)vkFF#OeX3khYseQVA zE2&6P1_zGk3O6K-`Mv(-tug!+qG2$A@g>U?>0}Ji){LaO0qi_4uWa9Ie11nqkLCWWNQ?HNI1e#?-<7_I^u5%<>F^e@socO5ZV?`WFl8I|_g=VY5mR_KM#S^0={j~r zf^*DCs3&lEa!$~d7RaNCLl<7+m2OHHzB@GS{^$1Gm9{(@8z>tCO!_KJ7{O|$nHW@= zh@*fFb%fHn#mN`jGPJ*e+w4CQC%VDmz~Hg|JX^LN6G)ih*p#N~^mf-lO@mn%LTw$D z?k%;zGgX?Q<>|#C5kAF!Ed?AW_NH>&pK=A- zJuUE4?|ndHd6k85DRe#Xn47pJ&JkFY94j`ccyYfe+qN-@)?E--gcCQM7a2WuvEX?J zidki|T6Xoe9IzerqB-1Z>Gsh^p9{`JQBJ6FC?S!M;_25fd=k~%$;j?tc)Mk}SiPt( z1*+gS=_r(%D?ru$NW5Y+dq3EE9*$)m1ImmQ;4~3rH?D0B{Jjz+Q5{V)a*)Oc4IVJn zgf@*L5qKMFNU*F?&4Qgk?W5z|V5w`*(ZrbIyS@Fg5%^7&0h6v{|IwR8)SGEKXM7nI zYP#?uxO|GiRxdpYmrrgktUek3X>Ui{a&d$3Vep>L3==LSBQ?2SZ?s6Z^T-5g8}3hO zG`53k0OP0*RSsAmnRn5Q10%Sjxh7>bh;~-h3Q)}gKID1y)e!@~NIyaV3ZCu96 z#v|L`Rg|k-m1%B>JLrc^P_!fL`;({*;jld0yQo8L^$jA%KMA1oSfhFJ11Ds8*$4t) zM82cSvXRhZ!O$ifr-05Qj0hyn8E3alq8mom!*jp|pE-j=$FW-`<%3J1KF5(aw%Z?{ zJaJ81cNb2og9Oy5`T${c_2}@~<}&G+@ag7}zmzF`Zwc-cu$?qYA4xJi6i@xSqUhaJ zBvGxI#)B%n6;ueb0?Z~FG4Ldj{H9K5@8EHZ-woCK{UMt4C#fX|+veEIeufnqcD?tA z)b>fe66?8IV)Gs|nxY6!9?kNE+}(XC4us8=6raTzu)oa>9RQa7>(1w_8Nv2s^5sfN zp>+i%8|oFz(%Glu=}SL}y4uoBluNsma^Lns4k~-y8-_ z6sSP2N-N`Us-dboVO~|=C>C)hYETETb@vLs1l)vmQ-5dbP|9VH_Lr;7R^J5gcy@sI zm_1iGlYQo*Q}nF&i2kB=kaMZ?qp?Hs~v0P|3I$d??dSy;b|C+gdG4WDP#YAUZcwW}4;H$N(= zuB%ZJP#w2jD&Re{bKqVv+7)^Ll5>aQUw?eGXKiA}1$DUdj`=o^kwfc7bn`oE;VfYU zP14ZdwpGhErEOy6VE&7Q3jd)SHW zo66PR+wL3%xbLIRtOJ?BXJtJLDPE61-}wSH|MXn-*gdXX12HyzVjGeFMq)_BCsV82Ho13! zgX`pVdI<8uB}c2Ls~8q`=E59~dj5nlb+K5SWHMMZj2v;A2=FG#1&9^e8im*k)1C-$s}{pFhlH2 z(j{Hg#J9xF+%;15#bFHx#Z#Wz_v#qnlmKr>&vikr^orHv2fZ>3ZRi^D>>qchx7r}$2ClwU?ls-%K1_;48;WHDl~O{L zRGBpVpSJ*rl4jhN9=yhLRO^M)sj$7Dg6^8|TSx@67nKQ$j0(9oIU`Pq%?!fUjnquk zvg$UfXx=_E{tQJG(hUg&APe1)?~?)!Tk9pR<423z{Z4hyM!=wgfJ0F!Fcd`;NTa?R z+(VJInI{`{iTtQtGQVNV!AcIB=h*%3Jp(ukd^EkA^LZR;SSbSjn(|AlnKt}+DdUU**vn#fHPQpRZ?w2W}A`{6+Q_(b0Qjf3!|b`;*V)qU8(NzEb%? zzSLnpbq2mgzkUB0W7B~icKX36+21E(B28s$C0kOWM`GGDifvLMR>eUD#67b4+2IB) zF~BjUMAUtlaAyw(3paO{E`5habN3{}Gd|m8t}0GjBlgss8j-nwdA4tZl}#Ra8Vu4y zl%nPlCFcQPYO^tMxzJEc)*SykE1iDp9vV`(G@~p$w$!RXbz36{`%IJk87WIWvcfRd*r`%ecEr!5dHpD@HPvOd6 z%O?_t)Zsg!6DRaYgj|_=eOcy%asM5Bx(mA_!kfOKmvIYYpMOi!Pr3gwQ|e1Py~#f< zYzy-R_I{hId6SV@u2M(oIfP5!PLA{nCfg1f zg^nxB`6aj)5YIf+m6VQcL<7lC0bNC+Uwq*GRkJkDE)v?`i2T5&TL+jnOLh&oozfO+ z7@+iu``GV}2~-lTlb?%aoe?`VsBwZ@HBKSe8PA=q2)yGH*dmT{GoEea~+m z{$sDm?xecXP75-NEi)IlP#Lb7)chiWn3u~u%JP0KPwhilU-2ptMW&H~_Mqwt1^iD_ zeD`YK>|NM-)`d?WaT%v6yb-@)(C)wy^U=2^GNbU_%d?cZ>pX=B411oe#;^*$@@bZ+ zq|n9V()^?{`@C#r*TVa^Xzz&*Ely`k*$|j9yYf3ADZXG4%HP$}5;{jDk%%!mh+M-V zref|zc-=4gx15iO%_(8Yp5UHeLr0=nC*Q#?(!3L>46wHW@j~>eo0LT~FU=*{ zR`<0$;Q1H5^?kDnX66F!6mxsRo%c(AXCQb@aSH3OKTcJt$TL;Sr|8?$T8WR|zo*$Q zKwwg|ngmSu?)>81JI(M9&W=`>UZgCO?Gu>&cRe?ROAW!=HM2a*ro_z?>u`WFt>8#! zSa7j5@*`0H2LfWWE~480oz6M~=JFniWwUjuQr^|%KtVyw?6exPBwcAKJ!PH$<=3^7 z6TrKAWpox*Di-b7F{2%$dTX8PZm)X_Yt6l31MtfnGv6a{_XHCx{%vrS&nM>Q|HGF;KMz(9;#Ch?|(yz;{18@woR zy9C>}zElZNN!TbCbHW1Rm(O?;c#7jG1}Cp4@JFiyt*LfHK>gbcbL4!#&KsZ#iTnztwRnp~M%5S+TW zg33TMTNB(esJF}Lel874lM?RU)NtWJ-&FC`D2WcKQ&#d-FzMk}DF-hf_=2#Hq)<9p z44nNKZIK65t;X-TzgJ8C7>aP~0dIYI>eW0GEbGFL)i*>2*6vHs%O z)+~H!W>J%Lcrt3ZD>+UAT8)tgch@Mkc&id*?JYwo+8Ey~A*2*@9z5Xrca%-lHZG9z zO?~J!amo^5Mk-%+q@_j&JFEJLxwWvy_ni5tD3Zk+DgghiclSDbB+N>{rc&RgEkQ`h;CO|sex54nxJ_;$bT}or|IamZ zy1{e6!znYPK6~P*{ruFbWXo3q_j^e=cVn*=@aHqAW~QnZ#iNyUoeUT+ZJ^K#~}Jw45$=o!G-O93}V|uc@*s*x<0DA(*7y&_VDrr zR^j?mg)OWb%Lc0K_Ba?`N#xYwX~R+q!v06ovDlg%nll9i7{EZh#b(bQP@Iiw&-I78 zoa$T;-rSuXyZ^1pt)HqAbb>sB*fPDC`}LAF4&n&-v(uoip4^Bt0dkvh_-KwZpT!r9ihzro9fq7jph(l#TjW1 z9{+Ba$$8?HNB*OE`){LUUs>RaPTNRAL-5hZil&`i4r}Z`IQywY2-%}M$0A;Pgc2k? zgy;C>f&czqaz#7blrYK^=jlIQGQ4!8y9Sk|n^{#*cnOBXqb<7rs3DD%`2@8lwpF|d zZ}jpyhu+df7^|ip7r~JdY&}H>pX7UBw?%9cG{SHx;d=ImtN3BMDFq#&5xFuVoAM&A(|9DM6b`o)i zYMkyacSo6$vF+tN>KDJ0>%m`?!kUuRHv7opdg0W2JND#)kU^Hb`*E|Z#p7d$NhR>{ zCEm%@LxRS6{@gr8M{LvA$cDC!rr>rwE+qUZJbkeV5@uNj#&Lmdr$%u{`$*!3v_5`} zH?PAY;6i8#a3p%yo#eXt_M^hI%-r8H8YR!3#pLy{W(lC*i;&8K0|>r&BaV1cv0H|YIG*3o1=>prqo3);44`pFWVFs^C_x^KG@(7ooWKdS?IC{pNaBQu#?8RP0KVH3sG>=|b_W%C$ z2c@o}C6Z+SE2!v%*uvm)q{vQ$opOjRw0{C7ih;P6wdla679681f*EGU?wHAZj4z{Tg)`=v}aPl7(?Q9ylm~|t?Bqm$; z4TM>Wmj>6`Qkp8`-T+Q++VuQq3>~%`l#zS}$?#=!zp85Cw7{qdl5-m|{xzH=JZbU` z@&%<}yy*UA_U*~$;Bm)rKFR!g)OP-N_UOHRtGy?%^}OP=1sOjn3|&YTxedA#UAn*6 z*=t*9#eOPvv$C*uwE{2p7g!u5e8b4f|3m?(OFNWNG=fv4mdQ3A@_YEQaxMlO>mYrf zhrA7RuKQk`?p!xwetDz5n@=oF3p01Rdb()Oynj;sR`C8N{q|vsm8ZTpP{aMXM9_cD z)O^q%*4etU#(+U@j#HCBvgb7Rv#m_>@LTdtU`_#!dbYA|K&C3&o;NC?mX-eUw^yEe}P-Aa)Ei?b%=;S>gd+_SS>U0p1s_aE7QWa+;5oY+;L__M+1kQFBaO?>BO&X?l^hNeCBa{)NH(!VcBJ5F+5tMZD(PA)EQtWXE2mAftYNkp#xHs=Yt z(qwd%or_Z)^a2<+a~RW{l(kOi6~&8Ove0HJK&2E)=%-!`U4Iwrw2J7ufs^G6O04m%xY>pgCY{u09;YQgKXCy1-<>wFE z($WYLI#am-$nrh{z3(^Ntm0W@vv?!}5)`?$qJ^@o!(IMLq-n}gGl_TDW^aqe!(VCk z)gr5WGoCn1D-CY}(|gJlftC^EWg>QUbRzRq?1H|{|N5ig?_ZOZI}m^%pndj5xYH<+WU zEeeMyQtBOsDP!C=bX_idZWrLxA4)lC?Id&C3w~hkL{n1#$vhGD7c09|CT-PAwnze| zR`70pH9`Wk2$Z}x~`M$?k4Sdb7a+|ePP`KEV9sC8HLVF z3fR$uY*_MhLa#I7=Z~uvXT*|X;&q&2BVskeT34<_$XQAa1;j{LkKQE1J ztbjLGggNumm0XBNva-KDh9R!i1QC8!CovvO)Uy42gBSa-V8^#7|Nc}%X!;}t>gH4| zhbxpTmT@{(=;z4E3)>& zJ@RW6_HLTOIBJv|;edwvB#~yi{B6q0HObcv2$`RwYFjdd!F|HlEpF1SX0mE3zoss- znhKLR&-o;*KtNzwHc@^Jod+TQ1a1mt6-JwJq`Ncs8K_XWKfHLuqI9>QK5c+eDIo|y z{F&*PVy<>1u;HU;v*${Wsgq-@O2QG7a>JR!@+d^v_M^RrAglq$TeYx0mrX|zRZX)~ zM>sowI9@zCP$k5}w4m(I)lntWx`n4_L2}CZwVQMIIpHkR_HE%OIzxVW86tpMb)Y6# z^E_Q6>7T`8LRkq zz#;!!=h30_!&oVwkA{o}ytte}Lfvk-j(0?T*_!3fjlpnVlsAGXf1yRJ9v_OTn=b{boa)!24p+l_5Cwr%aGX>2`xcH z>)CzgOOc9Y)D^4G}@72RC^} zdrpJn>tAh7n1UkcmuhVrbHd64AB6xhx^hWew-p9j!-k))GnnQ^SPzh<4=(t1CqTwB zP&p094!t4M*8-DaSw6G*$wR)^dPx+LT9xkt)+}_GS(5+MCjO0+As*kVZYLKm*^6;7 zRF^&tIQWNpU;&sCV8>wbu1$VsffEb?!G^+Oqq3mubO*0c$z4{!lZQ9!k$Lp>q+muAMW1lPv;gRfw{ZK zsv$Rc4iU5Go^mIMU2GDQi9Lq0<&XuXg;hj#CYlj)Ky}3gA?03h_3F26nVt+SBXLsnF6XJg@q{Q8}ad;*TKbb zWctBXufV&h>c#6AVfJqq8}tgt74}jAuiR?_bTY2ak;hf0z30#vA3fee_d*YhuJ;Sr zg;n@Pg&y%U%&>4oSba5D=Z0$awLd}`xT`_jK|oPf1K*ofsbU> z+19g79yi`8;LG`^CC6EiLbj)| zW!z}nxbc-h4fxcJ^^w6u?cyCx`1zLSc=A*)r&fL}MB0^@Dcr`P{?9oH&z-2&Ud>{a zTXh5(yFrYi7iS*LQDL_jt1#y~QV}>{;&0d(4ewJBXVJlvslP@>{tp-}TJ9K3YV_nX zaIM}07huOdXxp$y>)D5*S~ao|14#iorIevob+i-407ns&NNl8Hc?02{63gUV43~?f z;xyYPDCB8%UHkKV`P-K-dDiu~!1XyZ+Y3>!IGA_G7os7R5vlf@8_GCB@c=qywM<5} z@$7{L@c zPXPj}KVq?GwExKU=sm5^#ggWfa>1ybZN&`P6|n9R;4S+ESzD7Q+Mvrn>6cGSk++Mk zjn>~?+96XW(}mZsrtr^`EqaEovTPS!^R%bX{A6QBK>)jzh~KyZ%BS=W$|#Bo%J_?e z;Dx-9uJPzo3)M0l=_3O1a(+U?y~{=Cn%F0_z?&Y_ecs0;33#)jQU)Pqh?re2p0fdb z+JL_yNJ-Ya`(9hb6_R03tLr@lfqwS6dy)*grU>E1I?+oidcAex)`VZJ%|Jeev?@43 zF}TAS6;jE#QbrbhU%xXv0um%_@FnZe0-V=U6LnpLQ zYyjLM1O15!v!5<7NR)NJ5&Sq`0iOy>)_cwJ)zt77sws$EdM}jQ#4e5bk&ZoZ<`}8> zq8#r!1-8lupm{_gDr zttDe&cuZKT74zqtaLcJt@CM7vM<*9m)fifb{~0UZ?p&G#H^hSXuS4JRtJe_{k#(s@ zPX`Gi7*kq^RERTKjY(g|s>NRGwTu=PshRbFSIXduTf28yd~`m#kS@w;1fCwh%2C+T z+C3#4Ysk^b?TW)r(n}jSXc7H<9kooE5{#5>aWY{0n zkn?Q<=l41^_vA?Auv|k}+uqe4@LeOm#1GCKG2yohl43K5l#7t>#eG)7FVWSwjy>Uj zqsPt}$%!L&Af5VHQbHSK#r~M5vF^e;zsW5{^&p+cd)A)A5FJU#S<4$PWS(F_)j!VB z-wW`54a*`ulv=Jj#xr5eo}3~sjd*#qh$ztM8W7|kC|fv7D^-7BZ}y+Jz*zXWd(OhR zTjvw;%1YzJ-&&=%eUoZJo=ZH7mq3emV;d_Fby+bQ-X~L#F&^){=v)!x7XFB)(;p!? zALtgA7iDD`UCOUjY60bS0&G^Zw&jqTVdaW^B7AILhwIWxO@eJj@d-jq2_haBjX5Nf zzO$xxhEE}jbi|Pj#7>c+!u%q27mzG8VeKh(N0Ka*c*sv3M3v%1Br&%m6!dlEt!3mA z*zulD>-`#vOy554xtwZ4#T{}?EuM~D_;rlvPV?j)1?2-yvb^qCe@P$uOl8~Mc;3xY9@>96~;+^cIayeJX zuD2AnC1tVAYa!un8Lj%Ee=YaAFpV#%heCqDZ52LM;v0feG{w^QuVx}uQLld}kFh4` zop|E!!Ol+^!KoKZBNGSS6zG{bSk^JLLm_UwOYtk&G<&E0hd^r*kCj(7cT03~%;HkE z*6)ps)hKGh$6D7nV0Di}1x^tsA|)Mn)yBYo#oYRt%c&xPse$%x zA3SIPx+x6%B`iy{f0YFMp@*5~tewD|`o)=_sOMOn6w)n{;E|MAFr9PQ4<4rL=;J3B z&i##-@eKDHam_j$5rLRHTsw+D*=NW2aoOK~cM*vWJg>mTGmA?_fHdN2a)<*^PtdfYl*);J49^EczCF^ z|0;j4m~c~n4~*!SD~9&d+RYBGz|Z({@7Ubw`oLKJ&Xnaz!{b*L@Di*gb4RS*PPfU) z4Zo%_PIctOky}@jhNaSeu{V|vSnO~%Fden7{fek(U?w*h@HuLf1)nb${3D9Ug}q0j z7k@2}G#knL=zQN*PQ7BvhFeNRK-i-)SPu?6Bx2Xs7|aP8?Uw^Pg8rQDywGb}_$ZPi z219r7DtVvgs}tQTL&x#^>MiihJoNkOhbjy7c}cv$5hpb}i<>eacRzo%PSAgD`AB4b z@tC5-#RROEcdqnO_XIC4{#(V8Rf0u;lq#YA1)1&M@xZDNbyb%w|K|V1jrZL+ z5hVa&m&9->j4{H>ihWaNFVHn#z6}GfE9MluH#!Jqno}#P5f3(}6(gP=;k(zYk}?ql zPJk^J2RHjj@_{)~O+JVN&LQF{LKW!9(_Up!L~musqtFTWYz z_TnW$+_A|rpv{#Sm)Q{c{u*=Cr<&`mjk4S00~uu0mHQ8tnw@kHI|b`r!PPkaOg^aC zR8viIgs|V39BY7w-8Z;?e#VlJc7wPWTStbf`eP#+oHa?iL!m4FFooj}xMa@GE#Gw~k0@47rO;LsH9JH%7|_mge}raX+~Nq}+e+o8ISfyTQRl;Yvw?z%18T zI#y`#m#iD#lrp1U=m31*)U7B$Viy5q70*4!2>F9h4MD940N;`5_t)Gj(sW9>4}Bjz zdmB9d_64G1r+e>LQDiJ728MfEZQR8laj;I?GuA(^yvAc2J@Bv;maaVo?7@X!HN?^7=zlE#!HtUcGBT`otNZp_9r|lKJX;H)js+ z`_p0Y~)%bu(jQAuV}W z9-rTLcR@^aVn=JgdGzP1a7==w-6+Rv2)`+|X;CpS*2oNPk8&(CMiJc>2falvFJ!f= z*aP{`4Kv8+WBxDzCZZ2Zf)canXWlpC-WoxJx`27+D=$92G#vg!zl7gx-@7!;wlu%Q zhTs%=DNlkVjPXta0nj@JGj*6ePrB3!8;5@lDv*{S*BMX2y1j56*S?GHBgA?p8TFyq zlk*KUaHo7)z zNoeqo$6z4EH;JeYv~7mIOG;Q0|8N$Agr3B+?-l#3S%YB&|`lke?jmW?mnPv30) z9X%(Ts@YG`ClzYAYy-W~wm8lf(zQ?yrBS?MfGs{r2n`Dx( zx;6}Hn7dmUFcJCe9lY!_rVsqO^UUqRR0&>8PZwFGGR&Qi9~D`B&LWiv2^*>B{0Z`S zducZ6*Pm5?`*!Ke_43)5HV3*-_Ze*M<9-1%2Yj0?qx`7lPMgu5n+!kd-C87WGC29> zh7gdeBiP#CpCvw-6-$t*0h1^?x9QeE;|~5A>`N}%!ZqSOsxOM9_y7`HIt!q(Fwd)G zEi`?*Cz>vLU?C}jX7a$==S_NyggYeKsq_Bb{Z-1J>`S8>VoSsF@QtAy{$4Up)~wFM zVhF#r#5a~MyNo;EdPk03-w+Jk+#CCFaK^()cZ*z-#KfRr*#Sd#D!p8ZwUnV{cMmxD zo`1Z~+&)U1XrJ3yiTOtl)?{a|cg}bwNYOK}r{0yy8#~TqFMBxY-+YzC?a6hdi#==31aFHx~)FJ=K|0lZr2TD7?)CqkR!l3m--H8 z^dH~;c-Ugct4lf;LxZSbvp{|hg5>ExE?7JM^JgbINtCg)g}LidY@a`eX?1P_j`(SS?D1@S(^p9?_@A&2-WwCGy%v1hReM7_y=&M$bTc$MYbz>hJ?wOCK%ukUw@!ST^29O7& znpuU3FK)6%xpu4pYH(UAs|vf+h#$Q-fAHCCmn)&o+Rp{pPO{z~@d;issj-n>UpzkQ z9l1x|`cYJJEFpjQXQm|(+yFyKv+B8ScUqPX=1e^}TZ7T!{a1W|`LxuJi$P`Vn0 zydcu3!m~ZDb}Ef7l25MUJ`qa%Z*|B>U&Bz&2zolg0`j;C6@z8{t-h0wKo>X}Vdsrw z7nWPDkq7P9KEZh-(?I-=8ZZpeTE`jjv%8?dAW$=v(-XNUk27pyh=sU8!4czvXW z*J1a!pj}S|f`Rg}KS$@_e{Js-qFM~~KjvQE=D|T6GtXvXc!z!fs9^!{Ni>erSu2&E z23-Q$i`!pVV*Y_;iHT;x^5PjxQQ0_=kBbj94?j@*z2dIaa@>s`QV*9oU;MF+CJrQB zAHZ!X?Pm(y73zH?$M1D0P(%kvIM9&ayo7|zD!yFSs1QGxMpmu#_kJyjY^>4n=I62b zmC)fiVuJ@#&(JDpuSYfp$0DK7IweE(cl-BeQIyN9KdkVX(pW68nnxZkoi{E;7YMS^%wc7{Wtk+Ml; z**XhbD;b?aX&XX_AkFLWFR&>OwScOjP{ZBc?eKZsUanB_^|xtG3cAOdwbVR*a=9hM z3rm08)_s$+1ZJFo`k81q?0|O~zh&!p1)>-~OY0XFu3bHG$oaQ{pwo^3L2V!u>-H}J6Y76Y-l);ii0CixR)pzc3hC-;Ml4>>L+xK}8~uRFl!-a4{=4doB|174#OeDjr-F=x`0R>$W?cg|W=X?LyQ=OX!elqCAd zTFD1CXn@bzo7D<`rBcPB#)L2`=XccsQUx)e-Dum^aS$q9XqNxO>RKs%xP#FOxDc&; zk=^^`!qIi&u@F;COLppkLw1@>bpB_<^@@9g&=Lth4awYc z-K58`scflL`1qMKJY)I@l!qRGwgTrsX3$RG74b)K`o2^~v1BqjpH}IRe_DgT;MyDV zFUEv7^%Ez8{AcABXKEQry~a|9v9$aF8#fCD+tu&m;l*9RxEeES*A_H8<|tc1v8E7m z^sq68X8d_iaRo$0)j2gvtZk?T&ne(Pf{nn^_^DVIUtu#BQ%x~5mNgpdLz6V~`>+0k ziRgr|0Ca^5$#!0muVw( zJ5;kS-~u}>u+xn&@BVXy9Pi8GjLOf?{xA2&ZR8?s_)GcRzV9^GJ(QFXHG?k#fN(R4p zD{cxc=}Y12O;+TU+(pEcgl+D9w%*8Vv+uQSuknJ13y4fi`6c@Cxq)zwLEv@?U(Fmp z9M@7xI{IWr(qLWmMfCHbzB)k06XC@1*3J+%M#2@+1L5YdJ2x2XDp>Hm-d4k<5oh5P z+7)27SMV<}Id1S|s43ge9?Ts2kdyYav^l1dq1n?9$OB|4;OJIk&fq1Gi+u~SY5B9l z*OgcBp-gJ0CVCP`&sC{MAI9F8Y(O59kcP*7qXQGCD+^gf0 z3qL^c>+X6OVEnOs*V3=e>C{g+D{aiefh?(JN*|5&TPJ>q+u0Ia(El_g?015w_VJOr+NY=LqZ9D z{xO45sp_$NTi-&ad2Pq+J06eUdqvkgYKe9((6XmnLB2d5n=1wiyU4Y6qmT8)V`TN1 zYwK~R^=-aDnd!J~8{KVuXVm!G@P_y5eSPtoG@dg9T`GlABDGeWiJDLW0UkWN<2Jyr z>Rxd8=HmQ7+pDl`gso9ct{GGKL1W*GyhUS`a=<4gCZ=IuNl#9XD=C7G!34!<_KGbj zri#Ihh@^JdqM{*r2uAMsuk*Ay$Dn>tB=F;ywny->m-o6i%ZIfsB{R9dpH=7z@Z*X1 zr>X&t9M-PJ_hLENQ8{s;21Menz`?#BcA1vYce&Zb!e8jJg8G!}TWDU>v&tBAxXXpJpuknOElmAyB?GzMfye=pq0M+A)J2L zS@%XA?gj))JZcO4l|$p@^tKcXzP9h=^V8}w+@<>#C&7ZYlHHANxmBWgEoOadi+oAc zw(3wcy=oP{?0f3Q^0V8r0jKQVH8;SZUZpTj)0LRCp=ZtL@a7nGfjV*CQP(BWMbN-8 zvg73g9xydo8-m3Zt6tSZcTM2>l+QJ{LDvu~^0TI{C=3lqwXw;~)lV`p8@l5q;X^u+ zszMrh7vO%^TO`z~>JTh(`uOuMQ{1PQWvgDmXHA_d4(`(ZuJH!y1#Gxbb+SU-r76#p zmtz5pt!L2wdK#4wIORq?q%IVZiZA5?1NaM)Ph+milC7X2=nGT?TRRV}Xjw<3D|7xb z%+f8CHIllzp1FmAL%Y7IS>Wk`rrusdUr+?}Z=yHbGCq)uS)DR-R4tEGoxk*XJ+B8v zL(AIurBce-~6URttn(2EnK_Y0oNPAOt)DEA;`RKQxN0u|L{P;x3UaW!FG-CW6gSrZx zNM}IG%=NsS75V2rgt-8e{}`0;V%(r(kM1+*9;dHL!b!&m>&0##?A*br7hnk7?R^Xa z?05XA{8%7lP(AiL{>oQ(bsn&xAjy|{a`~WU|?Pm1Yi4>wTVV1+-t4TT^ z2iOQYt%-0WmdWs=C%HMv$J7xoJ>!Pr#>4f!(;02-%`=rap5IcJ>{l~lq|q1i zJSxRYPFqp|4-PfxjxM9M=GqFYS_1%)BnO^Ho#Fm|3HvPfR+?L;{^pYu}I5-eU)N&$q3CmCc2B&EJw!n5*itdtJb1ss)zN zsWWU{X66mg0kub=&+&m3&pQPqHMn?tZz>hk_8B{U3OUQdAb!$EBRC~=Oe#~xDl;VJ zqgtiJIHKNwSfg9OFxDvmp`VB`c^A zG01OVX_JtwdeWcZfueZ*6Fb|SWN12Zo|223IY9cgG;Q*Vtg{$PZ)=v$d7}PM5P&t| zSZZiU-+A;ye?@m9_7$x>tXx-5V72kr?8^w*N8lWHVhLK@Jh74q%IqHBxU>5&##is& zIW7Rwj92y}v4aaqn8_-4qBhMuBkt;Rd~9+Y#J+7*&J!d z0Sy5y!CU^Nu}_mLMi_rDxs1$i2vknT?getG3|&q0IaJ0b^*1>WUP3e7I{-*|&NhYW zqMCzGL$)_ENjNhh-lz~b_Arq*Em(NR=I7-fO!h65fOOrR0YI}jJHxqQ0FU+zN zgxs16lG$dXewm0b52`PJcTTi9W6|3X8a%4dRO^BeQn7UpfV>Rea!=b>br3kx(m<8v zzM}KR#zycPLBE z1rL)8<1a@tD$F$42B6MVjPlPqFm`P_R9lnUB6C&#=xuF3U;NRp$TkRr^}SL_HvFM4 zOW+NbIdPp?`^D3^%~tX{a=wF>4V8)@x9nfvca<}5&m~tL6|CwoP9N=B@m4V@MsaRu zo_zAQ;x1S4UP@u}uZ5$Q3rE4eb~%zp(O#XNm6jpS#sdJ?mgM{zZO(y?9y~C zZBJ2bt6*s8%u;Wm1AwE{7+HzWm%OcF;Adazb+ub-%*jHUTn(N*HvoXfopYw2<=SDfomULPx^hNSK3eziMS+hUe-JkV7(4 zg00)X((DAH-79uo*LbZeNy|sW$hh!@WAF{n3ynm`MX%?`3v5BSTnLPFY-HMBtG2#) zHF~5H?acZ^9b6hwSp9O#-M{Rc;(7Y!W{lgJ{oKt{9NUWR$=oqUXnZ2`u4msXbW-Jm zQ4T;6M9d!a(K2Jt!X@%}9X2wGur#l~nRHm}{_!^sUFHFRMG^PKg))uFdv{Qz(xD|+ z;_VONL64nb&DL;lvN-<`QiwP@N}VhUb6Ss}B(9JO3E_d=%XMsK->U-GC?-nz0>@Xi zTI!ZY^Jo%7%8ET}ff?=2@lE@wzmTJJNmRmSqr+|UyOUU{s~7r#GnkT)U|=}vR?ler={ z8R_I(3&$v>==i+YcFu1RpvVMG~Kq8dP4l-yPui-=IiGP^$Q|bM;-MQ^X_SVq7)vugk9x z20jXeF#4k0zlPBdNq(WM0Z)5k9r-Me4p{3R(>`?e%oMIDq}Wo}HjAeXg2H_lAg-mn zF_G-DKiR|}pW2^qj^ZIN+c2R@>$MrFWFlT)XN*Qd8t%>R16Gsn}_Fwtiwse2w7#3MY=H>TzE27VwFR2 z=MU}o6E=LB-S#eq)J7xsWy-^b(4JBCY3!=1s=~;D)3;Lf`88(}(nyJ3-=6N&BHQOd z^pW}HbLVFdi&%;!E|s_5A^qC+3NKFFaoPX-?d7`}Ea%6DT}Y_59SXJ`h_bwu%IJvB z)=-OaAZyB95$AMw3u#^hny7oFhO$!6=&QB-hq@N;QF|eY<>4vs)WmR+0G=5`^hi_$ zh$rklRQ=?v9?url+wrjrkUvnRYT0kDYl^s`pPui?xmfRO=N%fIMI<5@)ZFQ7Y8|St zW9l6Gx}G&ldo18e7?@8pQHER?zoT{7bZ_d9MNxG1HT94YZg(&x8I()U4avnYt$#y& zgTREf@eT4yFvM)yK~2Gbw>p{Z24v+Yqq2X|Ags|cYdL%!IRMi3yEEO?z3EdcKq{{Z z8}ZLl80DQ{h66r*PzO2X$F!wuN=TXdeBD<)30R7n;BdY#Iv)&9sfeqzXO!|fe#uL{ zW=RINkl$(6jU2s>7(TAkv9uG#*%By)_$L1-|@^$;aEBNNq#Yj+vE7AUL{XB<(q5 zL|F7ari`4sc(>KxVM=t5CHy8=&aPT!k&vvzYz9$AuyShS-5cKbW)AM`o&Id!6Q^bF zx}l`1Y#l>puB&a@5^{a63gP0*m`t*5zeHjGMTTkBb3xPD`-pP>qNUJuok=>W-EkV4 zpoqn#YK}j?Af$BbuVbIB4WIGx$Z!bkMZt4?D#KYZzS;A-oF6m#fvQfgNp6jDfK3~R zw;dBdvhJFy_F?w z@cyyG_DX?`ds-QdJat(Uiy2o}u8T<@huxj_;AuE96%rXMj?d z^TW!;-n0tFxh=8aj8B7lVXCoL6G;0->RxDu1YgU$ZpKCO>nP{{`;6-KExYz4>Nw9f z)`8)FtIvpq*P zXWF5Dxq&%bt!ZmvdX{L)O`MK(Y>?9cX~J4Q1$XtaEBdyz%-G>M_J1MeW6l!KZAw(X zgRNMlh<8JR%{R!z6Y)pbP2%P-3tttQefC}~?icMrv?uv1k1A1U@=a3C5;kOCN)waJ z&!4}*@I#XafqBL{+|u^!XWA*lPo~z7$o8=+STX8N^x47d8@G}jp?}Q6Clp2jx#pSs zBR#?M3$|$YytfpOw*vbcVf+kyVj#^iPHHSv-2QBeD{+r0|C2+TPAFYutrm&@tmGUb zV}U(;Mu*=3#oZIl|0;LgKC+n--dF$h-uLo4ld)&#(}k0cNv*qU8J%HqmhLuVMSL`~ z4lZx{G*^kKUi_hZ=x07QM)vHFqO_1EXvM1F33rlDvV5K>EO;$jZ@i7QLgk8w`?|78 zdZ~0s*w=;|NBWS>hRf@ z{N-D0gp|ASDG4g+C&46C&k!rmul#+R;`eQV$4@Hqy;Qx;h%Q}DJumCZV3Ji##i;7V znF*mmd3**_r2hQ`b}xGtnUGy-VgDTAX=kGRyGO9uZQ*+Xgw>uEWkn|SWeLp5x6Ilx za~!d!HMfvGJRF}^YMk!v7De-Wzk3{kQ z{fh!L(fQF#b~?$q35}MD)W70q**F zQ8q914R`!nVD-jAH?#+&x@1a)HJQUNGhW`kG4K9MGcG&+*ASToD6GqyL2)8&av95g zp?0D^Zoguln1Wll6gaU%RhdT)i2aGFoc0#(ZJxe;HN&Y10Pc8>*E!)zSBPV(>ku4R zCjYou-LYAD&NH1!(}>zI6HeAy2?>GnKNw||%n?iZ&7O;es5JZ=ind@Ge^uVjnouN^ z^(B8ipkpv}b8xSMKRHQNRZ0yTM;bFNcZBdBinnE!k!Og)*+anT zCh%mbU$hMl?wrOB-_MZ2(*OozSXU>%4?2OR{_L#}ZS7i|yGKUkC= zzTq|Sdi*u?-fp=`^K4HFa3dRM>sbu38z7CNAn*J5)s~E3(LDfGuIT=Q{o&n&Xljcx z(=M1V5c7f9na4=sL_7-a28;M>q`BOXZKWza5j`LcqgvTB&X(Po(wjjI6t|TRi!M9_ zK_&uSy$PKZ|4I|31VP59BImu?5Ocaf-w$zlN=ijCkd(LkgoE$Tx?;jAjJc)M3G_HP zWJ>=c%#4TEDzC!N!c6k5=>vfidt8uHdLfG5Sf#re(K1`Br3@0fJr}H2mXPAyOd51S3SjjB9&el z5I>Ea-p8v`l@o5evidvk+WGE<`}la$NgDk_qm{Xt3NWdH8jVbV#)wC(i@K~2xp36O zIza)U7if%5u}vcNAwI(X6H!f~3^)d}DU5vJrfzMyWg928kQbWjUOCN=KzW))JE_T7 zkH8crzE9srZEVr$J4P)d-?$eoRo_~N4=V1#1M>{+rn}vM&3b`18$H3|<5vW8fynUeN*q~Iw5%~@jmKQEx1rEic7%-^)lx$7(g6RH32 zKw!d5L`I^z!*N*+)`8dE*@GZ7+;!ZAsp=(Wj|JovIKiw6+`wltG zgehc4IdJ{`tahhHVCkq;&fC=Kh|vA{lJg*96zZ8S>%cMu5s&bpBg@?(1o5Bp!@0>7 ze!EZ8pLVH?W-Ie}Tyd&7bhT#>v@$B-`A^sWkGTEsWkSD6`!@FcHdECHhrbaGM~ehC z*di1@-iQ_7T{etg=NQTAH`_-Ce#L!hf2H4gHV_$9IcbF8cB3t=40f!i=QEmUMrBO^@AU>#S1&0*~UTqWdohH)KQNTynurX9?FOx^m&^+}y zzg(7?=yrSuyeh9%`~6aD;Dh#j=l4YVpXH#NKmDzXldW4*3?W-y)-uVT+r6REsaQwXAyo=CS*0eKFo_)Gvowmz$~g}jJ_Qa1RuSdC0EXSohx?<3@_1O# zJBu0^JHHSiL)|4GFH!X2^^oMge*%vFc9y0H0k6iV>o~SW^d-UAXMgaZ48y)4hTK?< z+FbhwE`riJ_aFXxK4bTzc&&n-xA z>I@$1k~P!~vc&^?xt(_NNP&9%uFzk>F@=mVNt&cj9?HU9?W>Kajs!GWX4Y91x^YGS zSL91H4{uEu1Q=e_^RGAsK6J)0*CZLtb=F#@dF*U*H$4xQjvx%nT+i7)n$Iu*_tWI+eT^Y2bO*kuRxV18Txs2f zhae8NB!&``j$e*>{bTGt7rbsm=Qx5GJhBIUd#LDZ{J7&Ko?!wq^``PrtV*+aad>fW(7D|dUbe&e& z%5RFP&V9zu{$J4!ZQ5a&(KIMyNjGQsUUWO<)TzjRrAkUe);QWx7Ne7tWj8`PfR zL8o#1K&xv@yQDEl2QB|N(p3Iba<}#e*oWonGP7Z&Uo5BSv7t#w=K_moEnj5Hn4>>y zZ3uqLKY!n9;jNXFZXIFB{^Jv}PmpcKhxvmDme6#@+Cj|v*NK1LhzMKdC)sX_9RGC< z`4-*GF2|5;GvlpoCdiF9-+EwKA%Z!#Qe&3cZ^kRZ2K)vv8|WC3WG5O&si;JvQir;I zX*Dk~cIxILuyl0yh|X8WEfwYo*w{=BX1%|wJstJ)*znH$KoBkLUl*pN@C)9vKJm}{nOrd zfkzz=KEV8Q3i>6d?PGKS72PYEehg8s6x1>sZ%WLJLg|28?jHuIfSsDV6^u{E(T$mE zWZ6T5?xrQP=znx9t#0rp#_Y7BA;VPGy?9OPOns5-_WnP9%>w@SO&_nE zi#hnjnYPVb7c;5TDSQ1cZdc5KJZrI%_H0!NfWl4JI19dD92(WVQ@`2oebGTLaX34} zQ}L+{C$!$eHxzdwdCw4?7$1FQO1+MuAHqYTPq{Ti5%!He{(QvHlg5zg*wVWi(SwM% z*Uf{z%;Wu(+(suk+vxVIS`rTf91l|u&;1vNgSh?B5z$4K7~=o3(uD}=6+TX4tA3v? z4#jOG8aEDKYRaLVg~=1&4AI)Tq8dnUyyy+49(dO_pKfYj%i8Z`x3Y&U;HY55Xj}+z znD%+-+sN;_R3y~Uaq%D&i~J=>f{X2oX76|dld$S8zpZ9(QtE!t`}HYg?*Q}Ee>L#+ z=HCv(PIys?ZZ@9(*?(YSRk=i5p;c$5#W$7L{amhC{op;*8t^Y@mSU4r<)E!8{fR~W zb!+Ra8fYZQ&K)o%#baXg%aS@ae|gWS$pwC~WOjRLVoPZV~t2a5adB zo3Xqr`{+xr0L6-MaAXEZ3!x)qF$#7s0QwxpoQ$S(yPh(V(<)aRox}&#scCzU0Bg(m zPT&W9elM>m_<65iP1Ux6bB`0a0De``*8*M-O!Zqt4@_Caq0>tryC`Ldc9;4!Z+J<| z141-NBzLOsjR1!BX9ee-b%CP?-_YVaHNSK4i7~bQQLXhgLKAicg#=8me4T_dQ*j!iijh9{)c+>15_Dyejz_5jt>OjU zz7UJ5NSw>02+K{?Pid4=BnVmhI~KXUp=Z8N%-1W%(ZDAl6Lzdm$H+3-jx7517eDG9 z)K;`ZR)Z|5w^o2#DXHB)oUV((2XYBVh#|jykm!bRPZhY*gD9FKJU^c!oZj9Rp?{iA zM~^k~rKcl?)5_+WpY(ejpD9d+e^ZbcQ^ZLxnS1c40#77>{d#6^D|?2JlyVcXWNMfp zuTi~}B)-Ua^}k7tMCNCa34mdNL>s+;&2LtxSHsQ|IsG>Ao11m zdqaMA*wLWtuzZ<|e6h!37pK(BwZ!2IF^joMS(^+x`33|WQ3cM5)g|~l zPNx0$0f|!v>FO*d=P`iK{lz$=Rb#E>juGbhEQxsCaZQJF#tp%oxY|IeLImRG5??se z<6l!7(L@sT{Vdo|K1Ui1L6)zsiWy-2T{&^}NNa@g{EH|LpZDZmd>L$UJ*?%(_O~tY zVNXD}OK380o2(|Kb$Tgv+^Dh#zTfo{r&C70guz?Y(`XNkT(zS|Zje{Y`a$y>VG@~3 z7AC=W6RF@~mAixATFab+&b|NheWU(ia2x;@@l#x1_k2*l4+|EGT~azTd>brHQarr1b5M`F#Gah)iRyUk&-!Mtw}4?!THUj-Wuf)Qo5%*M(h2<$(?Qi!DG?0 zhN#-_&dasA^0I0|EN-ogDa34^y!Jtt$-)-`6~RX|!?@YMA;1aQrxueC;L!s2PSZms zllWf*F5~K&8OQVlbS}7dZj)Ix6>&jdp>-Yr;lW3wp4X`9=V>b@4wo2>lPQK>>dbJ7XQ!d4@}{9H;ud= z1t8{0c;ieAT@UquoSln&ai%U{C917O4C$P>eg!YPwgK6{wq3oMsyg|a0w^buSdmf~ zhj@G2xlj~YGR9t;S(4d5cV-g^MXVjkS}DG7&LSFJ6Q7MUpqHNgvkf9aC2ev2?uW!4?4H?4GPCBE55>bCG7W(-h!TI&{FLs zn4-6-&r@90LVz{4esMc|OP+ozm{5WZj|II4clp|^5X_d=)EU3kn!m$?Y@#ULo?BRn z-vS&`1sIZqo4b?<>wOZQ$qKUk>bw|Dz+I+Kwq0vBnIRh1tj;}1*c}~f37l(1^F#T8 z`)sMX!KddGc4poY%N&E?p~}Aa&r2k|mo%D?;o#CsDO9JcP9g1i{J|We2kyH8;idTl z-nvSC){*QA>hN-i`h*rbYhxsJP)oi+OgyluWT+t0H}>!U2X7ypzs;5%x#;^4yRMo8PzEPdl@#AzK`KEDB;Q972Bfs2~tM- z_4#!pd+6-#F&T7Dlk-e6=}7pM<#^mtPzn9Xf3T*LL_GiCxG{GAWTR+8^F!mkR3w&= z+@XeR8j~*(k%NY_(P5dMB15y{4Vbg`5L2LRDZ?hs;7M#A(wpR(XnZ%l6rMUuTlBP` zWnhae2R?O-eev^#b_EfsiN2ho5}{{|>QF97sovc57@FZIQD`ddYy8dFRsg^!dUFJW zyvtBc-9r~{%K1J>&_qB_#tL(zN!I!0HVNeX5r-}uQ`St`E)UNFYC7 zTt%|J@c~2|xg!KbJQ^d~@Z-q*jmOp(NyC>gcOx9ucjo|dv=i-`DJsn2%F z-Y&sF=^3UW#*i4(;$mm0DSQb3Yzup%ROXJCj?0`UJrkWxXI+ZFTX)|w7i*>-;0PG~ zyn*LrIq%IJjN^Pzgx;}1Q;K!Q__ZOhK^~RON(-LzG+GxIbU4<4on)3+NoXaa?G18sFk^8w#EMC{=Z9olP8&u^RBWusT6;yLR7o3z2w~M z#pI*wwN5?x+~640cCLu@YHid{HmHAUQ!z_p*e8JT!J}uhA_-T9VI>*{DL66v(QIUL z^oV{5{r8{Y+K;bXZw>}=CKk~t_;HkJL_|r~Tufd>yptxZ$1fdQPc&V%>KgYD;chVl zF~l=1*!HBdWLhaR%S(rXf|18VCs(N8TSQ)B>vo*p5EUUYn398en2}Uw)CThYUPF$+ z&=i%8dvWk!PPww@;j{E?9Ic{DEeIf31sVQtR0Iv~5j1p$_Q?ZcP-e9j$5)~rSswg& zMDOlih<+AoqnD?pc^8(Py~01?ny|E&S%}9jQP>@+lr1-pfhF!NZF=uL00+s$h<>Bc zakxh$vp;;6f~-W}r*n%hMw#3*MNbpl4V){$04BBAqcN5vAIKU_yS_>#3EI_A$LtrkIi|G;^VuQ@GD6%ICdN{`e8sR=h5!T(b zigPk1U@#lFg9Yee0vCc-N2h6NJQ8rFQcn;fD6M0XWpNUUU$5`R7z`FuKk-(1@mb^J z0@HN0biVK5Xr)m%Zhpl!kD+?X8zxm$Od)kV%V|wuOh12j7vYl5Um_9eaK;OnxbLc3yWB*ms6^ zr8^!28sqxQ_SbX+QhDnR-IZ4$$=le^GO2GdBE<9IP}9-OVv9(Vm1)AtF24QwIjdJA zsZ{4m-x~q1#HAJ`#F9tDx}PxC=zX@>Akd@0k>;}2b7~ZjAQTAwdnKXu{{YuOD8E^D zYw6c8B9L`{ORsm6{=1@K zxbY`Mz9QJ8BT}jPXV~mi9r?;QD}T}ddcDt{U-u_iR$hwiuZkxynI~BRmznoFckY;O zTa+=@a$!UJTHgM~7g&Gdmn=8<&)uFfe%a2b(jQ4GB1Q2Ep>knI95$w*q`z1FC#LmX zbLc8CxVs`9av(^F5Ez1%Sp`EKa`-4IG__bF=a)c-98lX_X1;3kulh3%Q2Aev=lq>=)=(sJtWET63qt%OdfW-mSLEb-td3_ z_oFSgw(1xzI!DqVMT*6h;6Zd63-g>`M=H^&u9Y(pm2L62NlN-`{z0@2Us7aM5EX(D z71$p5L(H2%Z~K>Bdy3q$IV0TGJFUo0uD0en9SCyyG8w^XVl! zp6r2E)HT}^V;`sF3r?>?8s`)WJh?8f-E-c9_JGSiDhys^Ep?c1Ao4+3)bIM^wbfs= ze(i16Ev=*NG&00_Tg`xCui_abcm){s-nSX8?p^<;{51!9<`}s@OEZ$FVl1IZ4C?;F z!Aq-WS%T{YdDQQEa3)T(-xTMK0&w{7CZIb6;3$oruTG{OW*T2ej z;MHIHHVCKn5c?;$cOBQOdAUpBM$Mn)A}sl5k9}p>(U*;!L7*gBCJ07g7)6H9AYf|b zn!f2By(Qo~)b|yIDN5Cpi#~(!vH$ra-R{bt+yZGZ4(>dNDj{MLi>r(RuMG`!Cvm&K z)$Cpm)cF=nV)H1I7<2~DaxBRTtor6PxAggJ*&}JSEt-=xLEoV#ZI9pi@2GQo?l!oz z^D4v9G>Z#7p~BPGMkq;-^he3fU;4=9N4vhT*KdJeS3J?9Q>NtIM0IUrRB@$!(Us{+E|Nb8N1o1+tEy8K0FH z45MjACKy;G*zsPnAx^&6f8#T4e!1_fs3Ny4;y5M<6oV-eEOOuYS-cwMK7YTfuW!Ef zBlH;=4r4GJ$8Zv7$Os{+{-c?Y8zDu&Z~bEm24(GNjfeLR+885P`#7&4O&=%}cnjT% z$L>@-!DGZ)_RQOdW(5x|p?3RkHQej({4F=+3}4nPsvga7g2(OY>3P1YK zcG;YDwpBYc^HH64K^6+Uc9|lAu{IQyV8b>X({8thq~SFk@IU@Q9`0Tk{a!o8@i<5E zDn+wAe6QWAJ5WdcPaPP4*E2=Y&&!JvNlU@2jS>!Th!5;rl8%Pz8jVDk|M@??ir)10 zq;6tzZ(5sW4h3BYDYh z{x?%!z3kDY-Sv7^UJp92{@7)Qr@-Y=X!7oF%J&OacQztM^f$lIem|zX+b;SJ&UyKQ zP-K=Qcpg&;^<>_(oi}Wsn$)<8ta^$19xeX=?*F&Xg5~n2_TlqehRh7jvK+^doJ5p* zrG%$B7dg!*{15N{-`Pg{!LmLks{30JS8;)mSVm#Rycd6^whh^ALAg8sM(6i$sz^|1 zr}KL|gYRcoa4SV`x=;AOo^|G`m$pSX?}k1bPcnK(<9|rd(fB0GDgU9IPpnV#Ezxut zT!aXMqj`a%c^;p2{lm>aylq$#IHK$r7ridM=hbb`KIQ+Zr84o?mpbd&hM3^ZsEH1@ z5_D>1FA&^{)0;b~PlHF^ytW=FtogtPL-9h(!@t9D-TegX3hi{OKS3*wK_FUxUUpj~Hf(D>>Ue%&98w zagH3P5R{r0|M?=_b;Ls%H)@~CS~?BNry8VN06lfg$uMwnKEI@jkTMIAPenXOLA=+U zk_@)XC|^d!Xo~e-M@^7 ztR($uL1;^NB3fQ9^oxI7)3;O8{ssa`xmeOAaalA$m!j-r90f|A!>J4@^f+8jn!Njn z?~QGxI_+R<lln>UfeX^NE<3B#oCZc+yI zJ-j3dM(h#RP=wEllMwW|X-dGAIhgLgMCYWkNYaA9(wHm@umG5X6ado$U5j3uIB`#u zC}0E`j6TldEX&b+SOjuZC=F0Wdf?3uxA;4J*b=>H22GNJgsCb?NIc1|JKa0;kzW_3 zpeU$mg()c`aQll7PCW5{QJtcyvPj{iB+59=Ms$h_+rRY#QfCIbbzFXJ(`2;q0;70} z!by(CDU8Os*yCx}4LtGOve$bQMC}@l%NV1u3dONh#I6n0NyG7|UVyjOS$=M81m^`_ z*-qg+jFRgSqf{@jc#-(~jXfiDpzPjun9>Q~BkH0_9;7yMue@FIWCXGUO#&_dFRypM zmm+L=db~nT??ORfD1}p5f~2XO+{LpV&dkq9hETGp4yuCcngn*;x+=BNUZ8e$OO7BP zVI>=QgA}Ky#Jg4SlKq?OQyY){&$Vf{SJ0jbKR4>6GEv%fO$m)!RZv+GhX7De3X5l* zpmE2c6b3xT`cWr2Q{ogaEjlaw#R_`jdf7_QGH~#ZokjiYgP9+i7S3aWJ}A!Ls~X~R z7YT0J;mqk@P>@%=;)?p41X8jbjFCHBXpm+iT&*0pi+$ew$736Zv`QZ5G;@ATxQL)! z?1{jkaYE;>Hbvc#Bp5~#B%a_Ug@HFDlMyD3WMq|X0{s_!d8q%whT$4_$fX8`>~n6` z4_n`yUl)7}-0LUGpN`GaHn4YPgO$`zrI&5X+9FGKivMKBzOR~p@?^|@b1Dj`1E6gK z0sM}|kJs%PuEvJi*n&2$fkIxMC`i)>tEwV-J+be;wF|toC4a=uR+mC=hD1om3A-AM zi{4+76pzQ{9#`O21bLjR&@Cw+*H4}iJZhQ&8A}@`7?0Zp_OHHT%i5074?4?=8a(W! ziaajDM@t@FVH9P$1-_Tgb-M0Yl#Ptw;UvZBbvqP~ohC6_kYzZ31=tji-2A z!WoPe*wtV3e&gld)6;;(fPdv=b|1+pgD%dgDA;mg1kfe-g~{ovuhz#96LE$SMo(juWMydcUvKYrup z*?T%!OT)9C>QS@T(3;*p6A~-qToD+U)#})DZy4ks%z23JyYp{o)ZD3CZfiCQ7~Og8$tcaF!+7i1vbBl z8V{Hr!LEK*jL%EU)tC$q<$*E)eqRQC2g+*)^`jl4UvT~H4UQk`d7}MTl!-6>18>@A z{%~I-v{ONz!f1-37@DMTHr(^=4(%j`7g0t3K$lThzk=NgkPKX=(!uXJk;&gs{?(Xd!fNsry~WeQAIly=F#O`U)24u;ep?ZxP3(|(v*eC z0>KbCDdHRlo3hek#`Y0`X`g;}@Y#JW(U#WW#WzVL7?$QS2A96MW#Z7=`V`e`1g(<| zYP^+jWMKRK&6a%J5zNkC5dtYvJW+BMWUNwX^F-JiV!gcV@J%M{!?&2 z&*%me9IJ1=K{oht!Xkc*3Jg;3l@w>;_`f1r@ylYPt zf2UWDSLb=tN^VcpNjPHyYwl|GQ`;6%orVP?pD;2ht1>O2oQAp6LQ{(+a$e7ASQ|*k zYX#?__u(Mc@P1+=9Tlo>jQOkz=HWiGij+C+|teqq&^Md08d}QY3Lsfn81mAD?g<&Z#B^ zs1Xf+>~>q!qX$7B`x2w#q^QvF(Sww`i1R&oVqi%}atGoe`S2#*xia#R@{ReLXOkr@j9e>M^`sWd+5HT@d>gD0f_ZtVj7fIRUnrngQ+FXcBNI( z_+2QFVbIFgt{jcmiD(6z68Lvv&!bcAfPXKH?i_)|X^x-?l~L5q%lEw2>SSKMo;u67 z-tVzOvnm?nhKPJao%i%`Ik|$gfxhx*53Ibd{ilDrqViK&kyV0~1%_u-n4iWT+RPCc zIdIiab4$I0UKQEEAPWSk@+?E~O0V(hpOnAFb{B+~R$XU)(*mzjU;o_a_UN}QIe`=u zfu#wF6i(a5{&B4Bth%WX`_4v4SSUab{q(^2d(MsDehrXi3&Pu!Pm_G`nw|H2Y!A<9 zb=lFGmp?l6pL8G(!fwYBb)BkgT!Dq1UwMf=j)#jQdLdk{R-B64A&qc|!BecT52B8(j1HS8uxRW( z>gX4M&`^MOCr3!4LJ^!O6AHP;a`VXDrwY>Gz#)UHdGQ!*Fh4lXb|;!aH#10uHcN4! z)9k>xyT^lxniIj!L6S^~hnW#BNyr-|J!{D7o}{tF(S0ut3tVxa zU+Q~8yBVbxi%9F1s&b@=u?&W>9Li#$K&b_hUjkte%>P^KSn%q{Xc5qJJnxsBs#p5tX!rg8Y3 zd%D4Sy(NI9ow5wR8g%AvYXr+GgORL61n-5Y+_k-y{r>g8_tpcBsrUUB>UnGFk&=8s zYY8fqwGQK)1r)rdEM)PIQ^Vr znH{h_Y`bT}V`v8vJjJs-fwLsX1pmisl$ss5vsdz|yyL*yy(=ZcD!^-(f=9Zf=|h}7 zw@;c%wk%G6HNvuDf(aK2SS$EEQT1Bm{9Uh|);P;I`rL%tv4G7E6n{HZuKRPx@Z~Gi zzpC3iTq(A*yoiY$PY^U4wvcV}pjMfOpIg&L%8I%|iox@`I3Z&M8Ro8d(}ZM1!DpMU zJ+p<35cuMJ(0c|iAN1bt!tA+%2X?4ENvow1LV_(*Zs!Dkc(&*NeRqG9p$fT-r-%ZM zi4=n?B;2FMh)Qgh+XI)4%G#H^4DEr7WEh5HNt&jEyHQ~qQS~${*ewXL;`Tru^Y$mN z-VAz?8@(3_Ces*=NrXU%E0T6)cX=~C1K3i#Ln-Y1wR_y=mpcMY4?gc{whBzf-pG=- zKr$-NVLZoR`6uV&=RT>Q0aW0^;*zw7HqQ&1gc`B{fY=YbCi;L7wV;my%@Q_78&(jc z!u?iBdc}h!KQz{+w7VutJ)&9XW@-UhC%j&g{s{cUXY#OeeXKWITzL)6l!FQ+oCSHTK>e82rfm;>8}o8TO_|P%tpco)fe`3SO6c zgv(Vhz~KzK9%``c>HG7tNSo29m2e{&iwP!F9N2hmlhstO2_~3O^Po(kyC<-9!;~Kf zoCQ|=a%auUg(blRQKCdqP%#`>@!^GfC6vMd|2`91sNr*01E4%CO2NW2Y+ke>@>a{e zflgfN^X*a%2(h9d@`@gj;5e#8>c*YedQemFpb<9wLmj_y0GJYb)EwgQlvuppPB!(P2 z861-<4VG6IDz9q=*+gZ*p9orwcYO5PuQz^EY6yFN#^8H!dj~_~3IIOr)W%?aRtTTE zLiOmCTiswq*wFypO4dHI6rag1&F#Gej=Q6I>2}}XcnO-D2K=Wxj zbACyjxX~EFldK4w8-l<|xSn1KntK#%NDz(zBkxUGdW{ZkgCN;OT7J8hHi5 zNwiYcv|3Xg_F8LryTIneNFZaGTJc2hnnbp+J%qnibxvo|&lo`jC z2RfWnj+~eZf?k(9VpMjZhv3i06d62IkqW&IXU-Ux$KiFjoZY#x3nvW=Sb_P#qp`yq zwX`Y3E{!+qiNFUFPaXcxbZ}8|&QIaZqIkaKBExlpdypdK?S1Km1?1~((zmxVC%8P^ z`g+Bl$GbmwO$86k#Coyz_C?X3&(cz`;o#FMfQ`DO_WVvQ-zg=uJ*V2&QasSowp#xJ zQ2%M|_kLQwVM=V{R$HNs$s%e6JOt$d9nM}9nSOJ$e20|C?*S-|k^g{A1`rgatxmfy zv($`wLAiRN#_H&34d9Azb8B=us_Ob4*HYK(l`DJ$r4?L-9t9~+@Mas_y-O>pJfq6p zLkRu{=Buan;xAgB(;C*<;PZIb1=yiR{TQDcg?F^}KdbHD)nlXo-V%~dQDF4FiuMz< z6U@W!+V3Z!@n@iUxl=nCv5+oFU%Rw+l!pR951Sxin%W@_SWP-xg@ysl$fKtEViXsa}2YK8N`=6C)m=`eBq#n&|xQ z)XJ};l|Pm?)~-*qw4*kE#hO6b6f$g#(@t}&gXk5&q}0kOFV=CNpB;JJ!TNbW9m)ql zy-N+^!G#7lLHYM|evg-b0seU%#J`Nv4LpDG0+2ti*6=Z-arLe{Fo1QZs`;#?g8c84 z!S||boZ)s=^*SCec(it})UH9lQ^gm3Q>v-oDG2%Y{TT5EK)0;u{2jdCuZFw$vc@<+ zRn15A=)ais$Ne4{XY%a-BAELMZPr74F@d7_x1Qetm}R<#3w2n zhFIfkuUTv*T~&hJud**qqS-cM9he@_~;b5)nz zQd{^Nd?@x-#Cscc5bRc+^}o94z^L9*RdkqaaNWO9&cRg{KZVCxPd}aoM*Q&rm^fL$cfbX-&Q=yxCi z;&Ds$=+Q7e1AY3Z3w*;@kB?QAy`Z+}l`uKY*V3U{dRfwip)X(Tum{QuI=>sW2h|q4 zLRIS%)djHLTvSW#{U_u6E?)hsSAyD|XubSm2Y5X-+f-q^HZ$+Gp zx?vUb9a}AvU#p65auDD8yoT}B3mx?K!RjVxAFRuNE=>8t1XB;LhA-C4`-p4lE>iGt0woc{qmD`2@epkJKd&5!Z@b`|8qM)gGV+;Gj- zvrj)4nqI8%a)Qcfr^5%~@rKjqEESuN&s$aQIQ2vDn@hCR^=NGCKxMc0mHwga0&uA& z7kynx^%mrYre`dnX`&$2dSTEnXn!YLXnLXZCAfR}kHuFGJZ=EmAn5Ir=PD+*)wFpz zhd6)>pFiEM_5WhMcTm~zKz8);mmZCb_b@ckk&B8Jh2kN6FP<1yl6Ji(G(Rmj^gVDc z=QNZ8_(dnL2YP-5d-biJd4k6QhUQSZLy3)#C7L~?K=^>-KUWc*xnMzoP(_cZ|XlTm>@Ut(c7?a16p#CR8{Q&7-2IahS4dQDr(w>Be<~t+C8}64;ds25T zt%rC%7$NY&{&dyFJ*Gus2`9`Jo9Vm&KB7`*?gVtE8KV`z+uhr4xjxv&#ro{X|x zV8@8{eiYmfm=Edsvxeo5OLgc9@H;RbzrlPy#se{c-fWiWeDH=i6{j05k@?Myi1Ckg z-5FayGCrf^1RG)Z8n+E4)bH~{D?pPfJ2mJMVTPVK({k#iLussLj zH#Qx47akTA{-^7drw5dl?$#WJDmuRdXmNRL_2}^%6n(`CR}hiqewfa1NKV?NBN(Ch z2bk9`8o&B4^xpsJv^U;)OZ5JT-nwmcS&H}E;Uzl#((7+Co#%dQ^m&QbUzb%U-`wCj z`Ba?sKM~_SS$FG-;mN1Ais4O?j{Kv?mta4FFkVnP`gvENck19*OD#qDO>SU|Y}Xs7 zrNIAk9<<)1*YNg?)4`9s`ozb_|6_?ve*+D!=X&c=-wGbIh}G}p7;QlV`rqvK9$s6Zan_?hFfV6QzaYbNinXIHJwj^ z_JDIKpx6ft>P0BLvBkLV)-$N5>d6z9D&ilp!ZVF4_Wd>WW5Z89D5zk6Q1PZRApA@8 zIi4F5Z0D&h_!F=FtG4tf*7i4xb9`zm-s{aH%$NVIn;3klZv2Afggq7$DwF@UsiJwW zDR#yrgM6f84VQ;5)OD`5>9dw9(q}I;KMBbd>}MkrC2KTvui*OC*`Pd@oFKZXYWhkP zU)Xbj@_~yTl6CM!Z`+bLDDU;EW%h(v>C{?7`=QrP{36Hq3q_8rEc{A=@XJ=g{>BPe zEs;~Jd;DuVq+cZZNKKXROg-JSJ6uTXy0w9 zOfbO&6HGASA^|wwP@?VosB;BNv@}ag|3vu9YhJER){u5S9q5)lz;*d_%`tZA2}X}( z_jujPO?HyRFrMOZoa1W3h!{=sq`DZzB z%GAwTT7{_E?K275F1X!xk1JoXV+zj*oFWJ$MQ!n3^T?l7{Jc%m<6WVS+xANZhT7GI- z1#Y*JrwAU!?#4-x5ov*D6rQ!qipT4A6}K#UcNwv6ZBjDSZg@ix&Ub?l){1!FW?2=u zX60kIPj3dUNTxRl!!FfnCsbKvSf1t>o@(`S$KS>+Oi6hn&RxxJRlIvw)xk$El*{qe zHGWlw7dm+OlesRN5C=aoiZ{&-zGvcL?S$sFwB6=mrP?W%G&k|e1QSd!*FzI(fL_%N z!S|a(a_vuub@5*v`B%@GQ8(y4z4d32!S(9#1miiV_W=`iOfaFw12F2Y3Y?qCHy+vo z81BbtX^2sm!x@@XSc>6P+3v}66*WH4kz6?WY!cX#7@r)P!T^5nmK?biR?G8&zPZnB z`1~ed!7XQ8E@#1&aFrw_mE<^)TX(v5<|Dr@O3}M+IjxR9r;EHTvN|yCc5A;gt-#*H zRgw2B@`VCBjwzfV(5ymXif_Z&8#)c4lRH2a4X&mOA8@@OkNRB?*2U>y5&jN6@Gk^* zyMCpcZUm8)uPTR>PNm51##KTUa9JdHmhJM{b+;W~+oTRatt=?jqX4UAT_EGpyFZxT zp(V8DhTF>_(rHtP(^|nLFdNDbS#%4logV_+N#o+IWW=mGf`oIm( zA8o(zY2YpGspPPMb2z;&Z3uCmuq*iv?>Mg@O&=)~j8z0#zMOn@WOsks!fIl%bt?IN z6KWTLg{m!-qPC9V`>#nc;*W_>H3QNRJkDl$B_K@t^w=HyfwC28%O0l)j^KHYWH}t( zvEQr}MIvf=C9q}s8Q-L%AVTHd@Wn@4fmp&mB5!cM!|PStc1bAk7P^%Iu9;Z?fBeGNMh@AC5{0v*Oh^(gz=v#50UGM*3~ytd?<)$KRa7qOkd4){CGhn# zu2rAp0#UIbC0v}tNh&zZqm-h7LSEjjsX52~p8HkGQxG=*0wIV>(oaj*Xcg}U3R$|b z??8*H`a7fVfpSsrf#>jh0^&W?^HDm_2P2+?-^Xjq=3Z;)d*JyF4Ou?1Mt{!&^}oI5 zmSGR{JN%u|_x9+FFRA5sBA(;Wc>fnc8>r`_5Wj==eSjDb_`SO;s@>|8Q_<%n;<*6j zap*mFO6c=}H9g#66~m-*JT~?G-&SkzhaO)Xo5~JYz5z(fk2Gr_ymIRM-+@;X@H`26 zZY$-{+XB928(&&JwsW{itDHJ7$U=eF&Ji?@5sIXW0%3RL7vweS@=KqUXVXg0Dz-G( z9kemygTURB&%SqCkIvyjUb*Hd0>{fDukf-e*;PlLGI*xLBGyAG9^yYJV&2D%S+-E3Com=H(5iA46EV4f#>GUJel-Gy>N5MG>?>P zCuqA4&7 zO1dIyJvyeAq;Gv&^27Z(DTclSF}&gLhaFA|dERbeiQL4jNejsj((LfZyQhZaV^wfI z4yaR~kr6gBWXrGg6G(JDsrqlPts z?E(LfZ_Jz1lr5*lMb@o3`*;sKPVsmgE~nkC+*GJ|yyqX$l!(y`BQTgEU%R>A$l#6& zkQxqIuff2DG(1&IS z`v_N&;#S;tkK*;_DdTblw;~T!@(L992$v*y9WJM5T#MaL_QA624THMWS__tVV+&(L z(Ar>dMNr$5X zH>awyDr1z$u;LH@j=!DGe6Jpu(AyeDPQ$s#7Xj|!>GhkW0Gr)Y;WSg|EMc-z6e&goZdpcRufiB>xm)Lb95aaN!tKrW7T2^xTy)^W^C#803uMHD!kp4Pw zu)#Y=XWY^vT&pU#YLhAZfaHZHT@dCxGBrB^T1>;nABu@PpcxK5wzV8=NxjxRT1jWgiB&#sje}Ijg zhSzi;@NDMyySlUn-I-&J%Jl_-69rrl7@lNX%{-pId6AOYQ~UHaGBH#OEE%)4N!g(h z39Gf5)^>hCMEHNTDf>Zd`div}bF}9hY0Z|N8jAn*wTcKWKc$v%$Fj*g82F?2S(kTC zH?%D-pC&oG;Poo`1tn?`!>}qNGK7G!obcA*?Q3q_nGNreZ;jI&XR{m$T!#PTzO@(9 zK1T2ukKq)>usFeCVa(*r`jYbgLEMr)5;*kIT}#_`00e$j2w{MYMUs~VMpY?E=5{Sw z!B3m)NdsNXOb-2UK2%WnARi5U_tvxf*FOySdu}9i2*cV{hmt3ccIFjN@FpXhpY^AIXzy%>D^W2Z=KqFOgbp#7*zVD6>Qb9K!+>+YhJvs zkCu;c!dPnzi!MiD)3R^ta&Fs2HIMLyBOt9vnztC z5F9QloFdDE&eZvNV`EEQ?GwD380@LQuH!fJch&_boF|oaAy0PO8OEM3conxp$aCDR z*mD$b$351@8;`6kb(r*>cB1#BEi|1`Zi1qzGG$Edbm01&`6H7$BCm!}7=>Xh%VI3U zaU30X(|o$dhdUy#hWryK>Px46<%#YbQl>D50FD1peBwZsF@0z*$zg zOR+&V;c&{zOuI`B_GIfvt3JQw@WxV?Zg*(TB#vu0Th!qt7s`^qdEtEeRep*0%T*^! z?pLk+swBNni&6J@|IoX=f6lZbM)+)CKmW$;Gy#1PmM3T$X9u241 zJDB8!5hq!|RZgLKT%|d3>1X?-@3yx~0bWLd=d!yYx<+|4dnZmJMEe;@+yBRDn^MAYF`mE;IYP(+E||Lf*i$J)-Sn-ZrWgGPaR z`_uTHmn}FN<)$2g5j@Uf6p0f&$HBz1u0uM1$=-kEuzQX_^9NYJ#zZDo&4r*{ zrf8gIL{?N~Dt+nk+_6Wx*98i>`_)Df`#1cc(aCPOe^cko9Se__UfZ)p8heJII9%Z{ znc*>2_RdP0c4s;jC;4Sn(%PC8XZfiHjT}bbtEn)j9In?nPa{c&Xa`<6y}N9(Nv;>> z`^W9=ljqqwJ3BMGJKLg`mC4CQ!A(Owt<@;@Vs&7&xpo1$E9)6P)tG6 zbxNYNeM9#C_RK0HXHpZfPNhnFIW|Cjq8S!e-ul=sFk|jBH$HJZ8igHF@$BQB>kb?I z#+QVh`6xwUmu2%NypX+b?GF1XgdAmjDzl~+4aisPg{(W74cPIAUG1d?mZ^_3` zU~=+9R`{GV`aK-@?>}MF#M(yYkP{WZT_Ep&Z=LgT|2U39!sZvAiZZ_xC_Y>iQ56!K zZXZZ{v-Kl6hdWh}x?S_zj$%Wl6*9UoMD9zTj7g2(Q?*HR%e8) z2fF29Vz>4Db8C*uwgmJ+8OerQmp~iOFURI@NZ{|1reslOWu6uUn!!~bw`Hxphj5<1 zOCWdl;{&&hKt|oo@f1pybCr7Lx@V1a`@N-O3*Ck%ue{Ctde5IFV#OkpmvA$8>fBge_H)T$0 zM)xKw>=A>gTk(25^Iek32pUh(tS*~)U*;vrt$*O(-!^p~Q|1e8bUb@R*d?W*hTY?t z+Om5d`tGL zhi#yHd>h?>z`X6Z4e0k%0*yS{E0(HqI&CV3BzJsd%(t8Nt;@!HDZ7$FOL;Yq51eyN z#;KRx)g4oy;`yBvbWIa^LkX`mJv083-nZ^}C6lx?(7I)GNcz39Abs~z4Gq_qQoQr% z_`tY6Yv0_lAQgX|3McZSscVcWvAE~{rG!biILWRc^xe{0+C8+mj?yKq?Ko_7p#8qK zXZ?OfFY?@0ahUKrO=+yoDH<={_v+LIVe322UJ9%St1WLd$ZUC?mGe+Sp^@*tl0k`w z85&k};MiZiuZ>+x+qXq7;AI&14OVRc2?b?0WHTNthYOkqJV3xE}QtpS>5C67UOz6K&R3u)J1x;5} z3U9go#17#D9eZ;>&K#W`o3vi+qQ#gMr@_Req`)~co8NBffLKzBZX;TBO)`oVx4%#u zUSMc*!rn(qi&amNuXW!8u8IUU!CP5tz$t;i=4K~9KQFPjHC56LQ42dIQ55-@FD|BBb3S(B zQ$%SMc~!FSyp{Z&ybdrd@aHgQ!6G%`x(m&yroqS(Z&EzI?s5QY&;#~leL6Z&>f740 z*;Qx}Z%6!gj%+Vscvg}PmQp!Z+&**H)N|jO=_KuB$*krKky*`jNZ*rNe@r0M@iPCS z^U13)G($6tC`y#fiIhmZ)`{HOX9WH?eEFoo4r&=e!kJWaY> zwRJr;SZhMObrs83)l2(wQ)W-+1)7)MK()DyEQd+5MDd)=GLpOy6;|g| z_4!th4{Ccs%j~v<=Id$IN$KSGcG-F_vHic z+EiwrB5Zij6!&Olo`E(y#B6lfvNhS9GbiwTudW~8a80Y&jLPm~E%dvXSeLbE7sq!* zf+-HX_EFcX=1d?@nKB=C@XJvW!wIYqGiBamP0tSyvM3IWKJ|xt-}x1ZfiET&19gh0 zRFmT*PUE)E+_k>{;9oLvm(Nw*51Z#$c=gE-jckG!}OCSG^)L12fZ;HhUsjNq$vii)#EVPF!Y5^Fil`fm%CXvmwhPbP`D;lgb{B}PzArIIPcfce#d6zgxx2~2YH48W zmF$oUx+K2Lh*D%u)&+*66=k*k{A_vC*c_5k^=`rRs(OtSNJ~erl31RzkcuF!sA^$6d4qopD-5 zGA>46H$C6uofE#v$Wtgbz+S(Sgo6JeeEKm2)sFXAZ`ttINE~D|Bf< zI793)WnPcirM2>glv!QnD2)!^pN4w6)BJ5~n1?r%ZLJ=Lg*HN*JP5a6!4XxbeL;C7K+k2bMAN3fz0XY7)s>p@JI>#8Sq#7n8vT-jY9*|=8qcO(mOkzH0 zO<=@!+qHp9w|4pCo7WLXigP%s{Ct*5$%?_tqM^`c{%yN=73>{fX3jeS%i;t=(NCzg zp13YBApNGIg=L1r(Q$i%32#GYC4pr%+O>Vq@fGjowC*lR`EJbeyjKS7MRNu{wybncjUR`E;ZpNt`5b6hl!mPsgm1EU~V=TI?W^&8>kwAFVac&nqKYdpwe5O_nnl zL!)Hg{OrbIx#xY|ArrBioycyFSwqknsACBnpba6cEK>cxO&w22q;i$F{hEM#>rJ-& z3&~3*G|kWwE7G(qgbx|x-TS|^=rA^m+XKh`a#`P1ZU-E4ryh;9UHM_MJnudLdamV|C<+jN`_T@R=c zo_|l^%gX}tz~_*DGc}$eDZFW3mpO)~RDopAEycpwSeB(J+qTvP{=DJ25llORixr7U z=3)h1JKr4(anUw2Y3tknp6{h9wwmXSD6=EzxpK9v1%#6MJ64;-6qT!!1~RDi)uB z#fM_?ld$+eEZz!>@5U^NUtsaqvG~had<_=Iuc$A;;wlzDAB#`I;={3ct`&c);G~!K z+;;CFe;JKG5E$0?GzWidVm~D;uNu0f%cdgW`(+*2C{DgF`QgCwm)gI!{~|O<;w~+y zg3e03teZ3?A6cVmv!@puwnk)N>1Cy;$;OuBvB2WjE??UAcCrR5(y}1&oWL`pOtUc> ztnqB5lADPBeI5_|epyle=Ua)p!FZNpB~BIvTI6{t=7ipF1g)SvhmC=DOFnXaee1y3 z9B`@KW$k7krD%$7xD2;%uGbi<`3vV6c)qriu687Dyr%*yewcA+&swxH|8;D>70;B& zjG&4#&uWy!ymx=cC%)O;($S%jPou5dks4=H;BkB5*C(|jQx?O8k7f!IEpU=7$0*M~ zTLbpFOG#O53A}TG{|etl-4dJB!pr!yAn~F~tCA*j-S#itc<1?w9of@{q*&J>)oiOF z)%h)|Fm=&vUnu4KAX@N{q})A|oW>=hndT4e!nnr+1Ad9IH3=QnyPhQhYv_rW6&aiZ;i^9&_z? ze-uvlWg_zFe$z22swJ-k=I!q_KrSMl`cr91R%wctcu~U7VW(;{Ezj=Nzzwb5y4?(x z9m6}@;_erYyTY-<$AHTED60|BiIssEC@p}9o%~Rwu5qF>l7P8DX?b|sojB%%< zA*(H{sv%>0VC$5nkKVp6p-y2k2F>yuPs@f7SEnHD*0&}3y}TSB2EI9`*W2CiPP|E0 zr*uQ+Xqu5EdBpdBTvCyJWmLNE9|bz}y~a6cKbh=Vh87r(V=0c4Sy8UMq+9tTXt7qKlA0u7inloq#sGSir&>%==QVBM8h|?$d7Nh zI-Qu;7lDG2D|^3v8xqd;R-oWnn&~wRmzU=#&SaEuV+*(i?kOxh2g~Ux+(d&7Yuu=e zZyd)@o%O)t8A;;!w4BU6VR_j?0aZDF06RG0ZZ}g`Ihxf}o#sW-Za4C<-4pmA^QV!o zjY_=NR%2LRXJ}5~XgXu(bgui1Rat1*9wKNM_;b=m*4u_XH)Q`;9bar!);xOy-+ley zSrdn#GQAkr`e+&)%j=ZRsV4hm|GPIoyEfA?8BE*_64hPJ&u*gafX3n8K>j0dy|(b? z`g^WBEmS5R2u^2~P|`V^lr`PHXJO&Wb54c|b%$eMYUS~^88 zW*T?On4Pz_X^=hG_u zfA_bK_WQx}{B*qqP#n(}21p2!Ac5dcf&_Q>1cGZII4tf?a1Rgwuxt7fLPrh0m2`@Q$Q_dV^HCqrLDV#&q3+m;78+-}<=%$q@iHZmk8 z5s3`M^=S5@)n@Ax94m)vA|hwLhNlS^4%xPe#HZv=+qOXWG0xS{CKYsVFQOmYzz<{m zzH@% zl7|Fs@Ck!Wj=DEs35wwQ8p!{Mg;bT{vU`pg!wI9E2| zFw7a|^DXmInE1KOnCA>S%Zu||$d=O1qv}2?4xH*!v!-e(@fq#A2AY^nY^yE ziodl~lKsc+cUuQC6cae(#r(D}C>n}svx8USP_14XzeYt9+PEEh9aHYDp(Wl`-a8Na zXW3Q%*HyaLN)AuXJt3HKdjg8N$cn|y&FG{xM0r>5X2lg>Db}@Wd!KPakgNGL1#_^0?Nb$sd;>i_$dtXVYfIGdec<(M z-H+wEpxGZ)x*bGPfTJAxICJ`#Jx^If;}kV>?VI)!I@36EALrsh9;l(XdnuzbF}K67 zI@WsrN|1kG!tb;0{`#9NC!<&`CO2eWlT=|lw4#!Is)N6xR$1t=bQdEkr{&yyi$8pe z9YhZjx<>J-Wuy93xao$tNw;<)7@}!JZyj*bxY0#5rhPW=eHs4Rqm;`A7IETG+l-xh zxNfy5`=>3`0}JcY;|YRzzMmOJ)Mxb03ws#0t%AHS`b6z8zi9M6@F1zNn>UymSQ>0H zf*bHWzg!reu1_JqC@6pwdeK8=W*SE7%DigAoNq+%W3Z`T@?K1f>^n+jmI(d5VEyF9 z419Y@PxDmG&TF`IBGZH%`(`kdtQ;6d@iazZs;yp=HmVwiU2t=75@9wWWe!ZM@v%=RoHyhE$K*}uC)MkVva;^0!#X%n{#gcgilW7k7mwA#DXkNH}5cW>j{~SW+jk*x!CQ zZhTvP-1Iw8!*g85HAre@qwntZF0q*l&Y-(we=kZy&UDeRJfkuPXm4^3KTE5jf~vF; zbKT!@Q(FRyPM9vAgrrdAlijbp!0ZGkq_)*PyS0#Gqn`vwaeFjz_+J6$ z2dTQ$e*Uw-8ts$Dj_#jX+k-IYF9$`xS!Y zY?oi+4m!L#;Qot)#nX0%Ut*)X;BURk2I`Kt4Mo-3Wh{3?-=yyl5I)?z{@*Bv=s3IT zSehY2Vf&~^LRptX4++-;POXM5uXE{vgxWw8t1rp46k-{T`vn?K>Jn`y!G=a{kUSu# zVAi$O9mBwRz7YzYTp$BOL)Y-oNuc~-7Jqj80x>?&QflFih_sentmt(#Wr7!q(7h`r zfj^c_O}JKO4`i*zL!NmZG4kbS(jEfA%bUo~fc|Vb9Dkfhv50=kKFEy`%)91RUl!tS z3{%&7T;_c8F?3W~$o78*b8IsO(5D%jeGzqbi6t-*F3L8&3nKf>58`8AEYuzs@UN0R zM(_UZDyiZ+x503NHP{F45k=)>H<31j=6&)GGz_%p^c;9`9k*33+phE$i+BU5ivXbzspRPAB6L?@X8BOE`6FVF zERZ}Lq+r4P^djK}1dO<1uL?z1upD|QlrGk%`XvtIB= z10}Wr8)7Lp&*-~#@lFmsr=yTo2%iu7#GToTwx<3HhAfka-IOy91s#4f-?iTaNf9e& zlK}1FPO$c<1BfPMv=>R8;Je(8wmL3sv{%*DOI3f59=GgnE!euKtr@u33qc~+i7Qch zy9;Q&y=KGuDA&OR^srS;EX$}Ekw;TJm)mv!8pf;p=<(_k-j>2gHrdQ=X)66 zC7LTW9|ahi^7?Z>1@%gg)R^O30LW6xgpLA=C3vI0xs%ITP!?&Cfma4kx z5LX+2W$w1>F~?vces&e_?QqaS`!iB1eTPOWnO>Fv2}l*a>yw9CAKq>EcXXv=5ofRU z?wognIAzxIOfD?9zj1dJV*3A(EJWbH*qX|=RWBnjbtPF@<3=u{QYF^V zgRjBErvqzRk-FjQDV+CKVj{DNwD08XC6mG`uiQ(hd3-349(82Pe`UKC8>sx6`ef=d z#4)Sh+V+R)S(eaxi&0fM`8PgMPMTTO&P`GWNCa$Cl*U|`w%KwfFi!W{vDO*O?c#$( z+b5EuO`g?sCnYWX%aEnw320XN9ktWWUEIVYuuTXzg*5KNI@Q4}J4^FNhdsgzcejWv z62?Um^&lK#ps`juFKkp-?39FjVAsk1tg-&xIGMK`L|8%FLTip4Nu5{oB%MC%(a>#4 zk^j2jN+nRjEz@iIn9oaN5)V@Q(35w@6H}ycz-@x|sXU{J(?1Q!rW8}2 zzPN|e{7il9`DK0TBES0wUpf1@Lj}|RpytQRsG4A(w&Ir?L%9kiSW(qU)vXL*XSHInEPw$RAwy<){s->L_aw7aW}N)ENKBZb`BKcze|U9z^odnDl~x`-T}B>*Wf%zN9tZTZu~SVScoRa9;Z9y}4_cL%3U)rNYtF!3h2ShCMI z34F1Gp}H&2#c9DISzjt*b$ri>0Aoa_X~iDs_)Y$^dQAiX9sLK`bd+Xj%*c^ZDJwu; z@?o@&k87T1QcTBF#Du4p;Wc%AZy{xo)X;wAUZoF;QG$FGe#HF6(zRvMaYkkGh`dZ^ zH9moRxalM@E=Xx$Y|Snoxy?c}Hdr9oIsa%I*frnQW_z`W+_ZBVd{!*;L|vTGKPgj7Y>c z&dHHU@}w`CqNU=_{eEdkZQ?1x){_C#=7m6=+hgA4Wh!;}@J@;qZ-I||*5xIt+9G== zM)3LFKBK7q9HDhO5bGzFA3~HaQTCr;fvZ)per(+{O`*Sh#6uJzS%OCCqbTim%9Gt! z#FxQVa`b~j3#0qP4lb(B>h8!0wpu42If44OKY1eqC zNwTs0sk?WMk@i1dOWo4eGJSjp<34y9=5 z!3oVB0od~B!+vM!yilm<8wab z;6B!b)(P_R7%6~#CfKcURjFQ6pVCk%f3xex>8mvR2J%qH+|mg(+hzrg1^zf=m!zVm zvBj&(qZ2jGDZ3)V<6msZ3BclrL%-N97zNJ-xs}lG-raY=^gmvhC(^1KndM@!%*md+ zZPa6<=Qy-AMY)!c$?+CV4bTIwKFL9Uk15{vJJ$89x#SE#D3NaH`P_GHK8Ca;{NbE^ zvm4>dHD%J}-MlE+7Q!%O2T2{r)LBWz?-r@DY+#8)-$`AafL}dXyMLS8j}1boOp z9}_yvpmpm^`%nQ=Aw&|p+ZO?!v3<)vuIVpyuAi)ILyDep9pM&`>dY7%&OZQD(CY_w2wvzFsS81Z?pAK>Ep2P%Al1)`>GGbsY%{?HY% z)vb3g$2VDkbJeDhrVwWpG1n?%qUr*CS2Ba&Vn^F?TR(6q3a2FF%rU|>XhXui6L+64 z`;3_X+y~Jgc$asauD-d{#ps zpA9rUE-CamVr&mxe^$iY0r>;i+j_f{gYWcB_69f)qRsSLbMYAfw4idUKnUBuz#npN z*}+EQp`IxSWSJ2x**#Nzz-|n_${I@ldEh2XMq8daQddOsBY4Z!csT{7slo1LGkcI~ z%C4O{cYlCESiU~uQ+-{7Yi|ck0eW;kE@zC0h;Zm0VDR1t9#$NBcl8}8+(n(QN1&e% zqG$p;9wlHvLE>X)Em59wQ+oXl7&mw+x9E|WgQ#Nut>%w+OEmo*b%2`TFsBrhHh<8G z$dymSr*GX*84qrP*3of$*(#?Wkr8-*hEj1TDmpeg6WF$X0PI6GkXh^By@43ns_EnV zxGx`D%y%ZIE)dn_5(VZkrW0%h9#dO9+B+^Mqe9K*0ZaaV#uh4N%$9J0RCu(OP5-(- zD)QRC%8|dxT-L-B&O34w?N0G^6>%Y*lj?!9rh1mwBp8>HfF zZs8!f3ufUBz_(;{1F~>lGuF{4?ClIpq6Z#&!&j}(LHfp;3FWvigptNn;gzH@*VW{Gx-*rR#8U$3-41t7&!!%<&A~M4af-&V40vo6}yF+ zcJynk;V5=O3+ARxf$^Q0M5=yWk6ezaNnwC*-8Vf5jB#DOcOiF;-Try#M_myv5pqY& zgwYIz^Rc$3MiA36Y&7V$-AbAHl%IoRv(H+o*faR16&r}95bwwN0%vTWrnaN&jcpW4 z=pz+64!-_aJyrQGhJ^k2&d)*BbZkJin16|%<$h*zHFHx_vc zm1j@C?PrX2?VB(s7ijQ}ZnyC4udS@<*+dOLn*??kt;b? zoot1>JdnQMw$YOfR#CxVP?h;UwoH?%pU9%*INSts?Q}`ca)uMIOkWUi+_tTu) zN599vm9jgF>@bk(DX+ZQ1L3>{*F~`$_hRN}@{26m!4C4uwq6$(e;<4setHJ`@%9Vf z(8ozy61bmM-=IFHSN|Ywo`H`K`4HpNns+G--G}mt8$h=>Zb1=p{epKxazq4}6ZeyV)y!XwYtJ-&e z^d0bmp0&z+dDm_e=>-UA7wbRV$Dc|kchcUD<`=Jddwj_@Z4{F-)ia5d zA|Sl)?NE2sr)3JN50&U0P;aj-uDkH|qv`mfUlm_v z%L+EuUD<{d^deomGeTYbTOV4;A z*y7a$O!KEms^2E&*(BENTt+Ibc9@$jeazUh@lYW%kPkY!CAp8W?eb^eKke|oJgI)K z|MG)-)CrMEhI670gH$3Q`)~N;&EyG8SxSUx)mbujBAK*A2487XOQa~JRbL0LC2o-e zQFKaQ;I$~&Buz-xZzfQ$G&t;m*axy=w2qdq)wi_Ytw?k$NKXkfe6C<+IRnviAol;L z>q8?0tX91CGh4ncV{8cz}KYn^s|ef>nvm#NT{TMXr&w9aar#RzHG_2ehuS4+Z%q2B{arkM~^g!f#syI6Ccts zw~J``pcD9$M2ZFXYZ}7hX<$?!QTW#uq7#36r{zOJFu3Lhlw_~{u+he-%z6~5*e%i9 z0R;abUry%a8Lv#q!|OOTtr7zHdIsi=rB!%X5I=vkAv`_toeujwRxLrT+U(Imh-_%cJW`h-3pEDN2gTrw=CEm&k+35x*WRo{qy}la& z=p-X48B2yHAcgK37X)f2TM*Z4KQcEW%^XP7D>bu+ls9QfsH^Mz_LxePU09f3u%ez8 zWtGMsUC4{rv5fl+s+5_~4P<-lSa#jODPX;n&tYZ%H0n%6C(r31x+mtlv-#|>;~tq{ zZf01$dsA9uuyPPzee5CXF?<|*4d?uMZ!s`9=U(ueJTKi;>T~!G{9a{RSwTSfOf89SiHMNX9Xm>9883*unu1UH zISk?R2`p}`J!cF7GaEQ1e5O);`>|(<-3a0E)rKcJg3S2fmx)&h>8xEAA~~Ppq_Hc^ zC1(EV40GPay;W49+gI>-7gO?zCp?N|+9dgl8X^Ku%=L9>7KOM;?Ti0W#Tqn&_Rh~T z9t^ECvPi~SJi2*E&y#+o^(BEUHlWWdDgWmsm!RI;BTb&j&_=-TV{2487vlePk^v;~ zY%=HO5-gPevWDw{cW>^S${Z=o?hya0haUn$tE&Sj&=3+Oy2SZ!-u|!HQqH49a|a05 zY;F)Pxh5L$atk0JSejy6?|bUdX1_*Y_eVqs7N3{8|1kV*|;do6zw{nckqRC;$D=W!`Z9Qcn) z9>)d8+49pnErOnPX*~t=;}3Wmt!T5bm8%Pc;{m-V#tz#q+cMu?%BuWO5x$4USVt(4 zM)_LptR`=SEzDO`Y6tkwjAje6i|w|R2eDqCImZ0W1@ zD@c}uyeR$ZW75M42@Zmq;-1n``%KNAL~Tv$j(t$bSUf1@XZu2^3PrrwMy|Ro-?aPi zBU*x=@^#ikS}HJ=B#-a&jMNa|&s|&Vg{h)HsO;-6(F_Uh2H)Gwr zZiNZz5a-#m`1cIBl?p~~vXUOxWM#nLhF#ttM;ByS3ufI{HMRe2G?A!gv#qWo{hsW< z7(4B>u((S-?W4N(G%(yDU!J?Ch_84eI>~JrE0}8`O}>*b-?f4dC#e5_C2q`u*71<> zADoNs^bNQ@->2Gp_+UQui*^pE&}Ls~x}Ugiu}ThR?T>M03+cP_^$IotZJ)3UmevKEol zD+sMT%GFpCu!60+2yh&)m2x;G4{g6!N$Kvd-q|e9(EQ{S#33pxJa-e{KU#iaRWngp zoyBeM!FM#w>8()B0H`k4VsIKpF*~p5OGA-xx9>by78|g05be6R)rmc18T$0lQFoAk zqxQtQ@tj<$4;!_S*xRB@oXKCX!6S~CaP*YSdhe3XOQepY z*FiP$$m{J@yP*6s7{2c$C*|_%wTNaWjrcud^S$@QtU$e>wsJufkvQiXt3*7KK9}b_ zcYinXXz|nZgWF2ur;)OYS`ROl9duo!bT{t?8^fIgae9L`#t7De`=WbaFU&tCf*4sS zArU_SIP>T&;Jv9h_*5+{*v6S%uqhnLh6|1TN}t@ zL(;UGr$=sxnATCz=@vMvTLS5u$lr9l*ert|E+$>P%UIT3Y|tu(R3mK57~7Zq{0^Wk zZCu~flzOM#-Vf+{0>c7>_L#k<89r#{<(ph&9jQeL|2n5(^ulmhqlMlki8qaw4^!ob*U?1cP(He!oB527j{V*^ zw*)-0^A?K*(fJRFK-(LrTf!r?bzJ_LQ(c^`!fQ8Yc+?mh9Vg^8PpdaPH6OiK>Eyp9 zfA>rl?ObT?l2oH&lZ%p>iI;hsw{0nEc>e3hYk?BzDH+~dsN?UtTe{o+(!pr|;du(z zyn4{nBS4Z%51^Ba{EhSLHzPBkej~J8ku8Y_ToMKeGYgt0W+`#&B6Ieer*nD?1%_`G zrXsW=L{`_*#kecsh#AV0y|Bs(C(`)Q!Fk3a!Ra)9VC)yovgu>78{_ic{Q|N-aZSxb{5Rn_3el*|nayOll<*C=t@v<`6XWLJ3 z@7aF|rfen~OGbuqe^sB<4o`7SC^Aj4zkLKKTa{B-oIIRuikc}1p)02*=7#vCwht?L zfQ^0xJA0HiAE_DLzl^5|(1&*v6o@xfbhtfwX0#5RAD_391a@VF z7RiDBl1+u)D7JZNK499UZ)KFr7%^+QhMvza0sQU7#aS|qw9|@_BncE*st81mbC3mf)m=kg=UQ1heDpUCJ`Bwt``G@jSf+h@IOBZ_&sG&%@=hc9>` z!ZZdwE}bva9^z_vDRC7M>UT3oUW$OjHdO?&_>irybq%mQjG~0dT}{>9osv^>?e@nE z)b|G5+KtDec90~)GY2yAil)mVP%7oY?QLT>Pfen!At-8-6y(dcuq~PmX!JlR4`8W* z#>?=o=|rMQn8ysf!SdB9Y={46iljESwp5}S3Zc8bZE^*(+=xiLs=3o86!M#rUrvEL&LXrD^5Sui}C8FNq7@KY3 zk7c)dMY9Dyac?AEwu5njK9`$PCzUYvw+9ivk8{Eg!NAp8lgWPcR$XPdRe_|?7iipT zb{6;{1B31`v##fYXz==hCw3djFG57Hg5mdcTTR4)e(Go3M(OB+=iD*OkHEuZ-{y2%egj!Vmn z9W{#13X5aXeo?@0{H7w?a_mDY2SIO>!sq>bEK$=DS`qipQ97;TaGz+1Y zW}HRGrbtgLoK?^-wzHuR9wsI!cHGZe>7qX^X6KJ-U7GQg=Qx%0s`h){)7J>nSR+Y# z4BuNfj{U)lVcR`d*ZlE#qb=Vj0&~;hc0(bkH<$cNK}OI(16txXgOgGe%btp{a-WR!UyjXJZcC1&6>FuXSJ(8z(Fha+};Zc#~Q zjQa@~z2|5SG7&j!ZF{*;zvW3@LM!ZXg19qM+caB~X|tg2Tz7NZHmf0B23rmzJV3sg zdXj=hS5xXfk1+ccV@LIZ%6-CN8i%5sHi`&sL%pt5CnhRJMU2HCUl|e*gkW|Q<(A+m zU&NQd#k|X@~LSCSzvZNGvu=bKpb$s%ccL%P(x~p0&1g7>q=p>nrnCm*=&oBpYAe zuW)Xyc#p2w8t+GC4@P%fJDcjV{L24wPDWYUOAm(I1nH7m|7^;An|j^SB>Z&pfO=kK zO*3s_r>}WjvgxeO1JIl}I%<8>HC4*8Y?mMbHLqx`2A2h&zmY)C>#`vm{3a->?3wy5 zxM1S#Q$yFEvlgGe7mY#A%ZLXL8pTa~pt=HJMy&Y-46SaB9(IUH5~^PRb7Ym9+}}1} zFz5fl)0nNuYN{~Fdb3@S8Y6p`g&F1zVr_!3Wm-gK=vI&bK=0W;G0P~Si>#gRbdXx* zjp>@xYHKRUYSO%F^4xn*BLz2wP_~+{$B0$8Bg+zuLgZNLtfoQqX;DM9U>~llCS0M8 zM4-V~X#bXW(kD~R5_NRewhQHO_p$0!za3Oa5on+6GyJS*!A68koNkR`tj`Hsbl3aZP5Wwrh`|+YdVpBmv~>znUkFo zbMNKDX7Eh;Vs_FAn{EWOI6Wpm{*XGyPi4wy>7$W9NvAu||9!u|Kg{j~l zIs}5?n2K%%@beCkJy~dzV?R)JvRUR2J6L=(s?Yfo3bS-r)TzmnBW;V(<7p9y*bSS0_W@{?9 z(QS?}1V4&qO}<#7{x$EjJ(;3*E^D_w$O?|GGd%#$)|+1p*Ul-57F@z^rY-=L)SINq zycfPwE~`NNr^i0EtruW2#gq4sqdVGpq{*I7DlGjle- zxZ_I_6e?acFQC=+dDHO82b>r0J6ksY@O(Z=N9mR(nv;WCv@UHo3lDhkSDr!Y0c7uYd7HQ1-NU=O@V>(3u&H_L?!5G}3# z=$|o32*^iEIIKrq-)G6K9~C zYs-Y7UYM2!dP)y!{SO@ek7?f}ZcD>bP+F#Zm zIru)1JafY;SRLzfQyE96134QttKBsLgXRs@=0fgO_R<12t(}@-I(FGESL=IL%49EJ@=M)noY~ad|^SlIdVw9s9!%ne|{Ln2{c({2q0a&6OKk@sOKi36T4`AM961#KyZ zZrem)vk)fcAM>w9BhKU0)gMhKY!)v<{cgltl1|4bJ7R!*%VMFd%MtaH)+}Q`8qoDc z*{9g0@ku0G*+7h27v6i;ez7-WbE6X8*LTj7(-Xo+*+(1+Hgq;Dw#pGzxMYpq5)OLT z2UR}gY32107Cf}LhxhPJ^96?c;>Ugqbl~mj!84do!tGK?9fJwolwzWKN0dfDp2TZ^ zskf8aEh|#v^C{*U`*W~C(@QWf^>H*8EB`va8$JKJ{&zto2Hs1Kep-rZf8Xcjv0`RV zZo)qsI2Lm~p@Fo0$Z-$iqqERsLWcv*aV1DBVkjZpC^G&nVwVVzT|Sh*FOAaUu)ym3 zbZy3G8gGf>?hzDGr%f#u7+Jq!I)WxBwgN3X^``U|o50*`WwB(#>G zoesNBi_+_{T1>a0KA*OzZG?-yO)fBBGQyl84u2`I9t@IC&6>2 zxR%T84G&uIh`}uK9YfQ+Vn0<&#FyDcp)Fc&@2=fAq{Ep{=KHPBjiYj{&OYyDji6YW zOxlj_ADcXv^Pr`7i7gkA6*Org?+^b#$DWzc!#SCy!*P`56F;LT$_(m(rz-V*WGjWk zip7Q6XTV$`!GIde2n}M{ZPR4Jv)B5C`VhL41`+c60yR>j?Qkc16qt6OfMXSQhiptS z29P5WIH9Pk=_HhbdsJcikemI^bHZDE$6jU!f*4ecDaWVSk1eq3&{q#Glnkl8^I7(S zp$@VrJEJLS5QirbeIv94O^tKO_Uso;GKh)Y93+p2&&*pc&GP)z^pNVEdH%U^Vyw2m z@ml+?^Psfh9d#-d?Mzw0B*!V`j~e#IcM~CK23G(vE9Xum37X@AA9b8I$+^nB5%Lju zogB_z!WYi&&_wKo2V>=Rr9wPnCPD}dZeaBix`i7rsk>UT5QU#ximz|{SDVrYYvX+l zmM*6rO8ruf+qGSVWyj=l$~3p7;l5TXrJf^?-hzECh=b0|#!G_q%dT#@3u2lK>Hlmr zew3#sreEA1vFXw(b6wpU?{K^%1wRvty99kTsvzC4K=Csh#Mn4cm(K>@N{OT}$j+*N=m zyEQj8^g)SF8CYSr7$V29`0i|NyM|@BJ4_$lyJM?B)x&L}o^f$V>E_z$_+L2&5Q3si z+QYR$1c&^;#sz9gm-?t@geQJsu$(au_HR3eaB0&5uy(SKUv7F=RtD;}sMe11cFx|D z_Ue}4;RA@ahHe=kO0#_8P5Q79n4EYRIEt}8^mBP0eLw%B-!QRQ)Yw7RWIJC~3wTx0 zmP+HzLx%}%dXXd`BJP88|IiyjBPxcl8}Tf-Kgf)M=Tjvem+b6-Ox3WclWOoF(NibwL9 z2O(FoJa=|zhjRyHd07BeWZNwLMD~j%V>$y4oW8mYLjoJ$S z8LkOQ{+>5YY=2R{OJ-aI`5Qlo2u*Y9b`Sg_QHLN*Rs{^qylDTq)YrfisXne>A*XfB6FNBr(#+meYypn;=1#_B%QrMJtr>l z+ftHb@=~36$?|koGv%?}_ZUkS=At}M>VmjL?24uI;*z1sN9p6G1hhn){J9x&wocff zx*4Gnp>{fW^6x%7u?)!wtXQw!^4p6YUy=>Ix44a$-d5@#v06#hB88uMaM&&${zA|a zD^1-!Z-Z@rj(+0|jyL%{9x&nimpr^~{((kb-)_A3cQg$mwsS887CT4!PO;OwTi`VB z1E6H@H%@S<->TP4?V3dUPzCj&A$$IQt9@A>)j2uffExnDWHZZUO^?Pmax1)ByvgmB zFC<(}9};!5?s=$m(NE@)Gt|%JVD%_;&YSm?8#qrV=Ff0S*HJFQgXz1ggRyrDb=?y z-b^iSNUNsqs$=>$PhB^*#rkyX8d(cAn9qP=Bfw2WStIU}>|P_%%Dgm>?Y$1U)6`Ww zY?4c~>VG}|U{E`Cm;YWTcqi6gN_u|SNW)Tx_{F+^qPD~Pu2AN-b*^M+Bvz@o)7p1o z*qW0&(4etLo*DN{M1!nl!55heldbO_X~(@1Uu+4DtM89IU1dS%h83%4`U~*4O08IZKXjq~Jnv!CcJy-LZ#r?PHu4=EORLCtc!(DKWkk+_ z`}V@5_pQ_>k?L_l1f37V_rA$}9$#@IjFa9EqOgn!r( z-dy;VH7mzik@qNk%>rLh#{pI$7S*bUrJ8>yq4_$eeESz%CW>-kxB#O-oHXd_R zxBeAx5-s|>d`zyfKaajv?=#)s25zBcUpt^pybugDd586B%(lrx=rGIoU}{UGNL=Hn zx*u5Vr5p&h4ms86aDUIayukc?vCgo|RTA&wo6R#mZcqH;{)p7$>gr;aK^Upr1&^v+ zbz&It6u>?Y!IC*{BYqIk{_$+Rwtp5ONm)OgH|o@pbhhafhpq45MmmNSW7&~qWcG`| zUar!!TV$95AL2pkoynYSa6ed02Yi{)X!nE1GW!un7*Xkb{8xEZsYDN1W09FIos??h zO0YNLIr>Bksv|2X4mR-fvVOhgXR+PxM$rAFczbM8@qr@p9Yrm$SQl4JFw0q#H#-+R z^R^0S>Y`1zzbrTD)yPf9-*ob9cRHsJUj_fvjo-gwiMZ}whT=1cq92I`<7iV3U zF=btpc}SW5o~sezJPNIzQx{dl%uioD-|7F1ib z(epTqeT3<Wo0)8>U!Or#jl(`GVuvlLZ8!Wvz*E+DOlzTLT+1}Ys zQsJR`GB6vQ`8e+H#M)3+bEU^_88P)ebb55$wh-9wpPNwJ?tUl0GKDjW6n_yALE055 za=%JNeQevUnP)jbJ%AqRYp} z^``g(UpW~{gc7U*30#DLaRfz-EF1pz4)w>Xx@(u_)Epy(%sXz3ZN9Vfxdjj8_FSWG zAk8~Cz5ogzIN*>93;l}&+&d|ts1*7-0El3y`3fPR`c;nDtAKp>%x;hW9GCX{F$o=k zqJd>qK|z_giqf7}Ukwg;R;w|yP7%6d;o}Tt&Al38lMc&Vp51>v!1M1W_3t@1_5)t0 z!>t1n5ZkLLVv^o;7B!>8D#Q6-D4v{2}Z$ zLiAhx95@~!HSBYzJx(gJB7)`T5(n>M+~soFSI2A!pJ$M7Sr7vBCS685$jPMGGF`QRymJMba8dE>)%Eu6kp1>a{ue^T!*AmVZBz)`XUo!NH~34W9-aIo zo_^}ciwQ?5&m^sxd%=FMXJ2`J@kg}fU9sMf=wi!2(0NS`pCXhZRLT=)`1AE*4+y@* z10TIpL_VkZH+u*H`Qoe!VMPevU+c&Bk?IJv72J|dvKu-WUj74f1oSx?pPNZst)RGx z!n2mk2;S1Ymj3@b!qexm9@#fe+=;$zR+DDYs`l0Poj=zw4a;k)$;XG)tDoRaa_TMw z7IzK_W8_98Ft~{kRGP)`o;SHq`}O5+wo(f<}= zm-*=6ww6mwi2>$bf^8PzW&QG$gmW$Ui@_^|k-;y#+>%L`{jKACgsq4OB^(v(;%>kD3%%b-t|(=zfs(z55KI`Pnx zq`ytAJ59a(B7p;bVgR*Tra<2YXJ@4S133OBzjQ4-eQju9XNtA>_p+;cJT}6Gli7fJ z%BT4bM<`DYD+l^+so)OkRUztkcR#!12gqUhsj8W~%5HG}2ZI^#$h~YDv-M$-S^;NXF@>Wr~1&i5TmOOU;E#47ZXp znE%Z;z{_&7h3Zu#`eUV4PH822;TO-GPJ{rdzb<KVqEAWlie_)|Q z;|_RnKq%Vpuva|#Z~gg>3=W?0p>FTPlYFgcWB7#O1$VUc zvb9TkeT$B;O}Ft60HZSFj96i^Pys@|us9i^eYcN=Fx3BVBn01f+0p;dQ~%`<5K45r z1m7d<|98{yqHXN|mH#^htpE49{;Y<2{P5q^e|0$q|4wJ{58?oRgU}@x!u|XI%Hf?W z2PTyYJjy22#<1@HuMXQz|EvA~KQTrMGXvE9S8ql6Pzj(JG%f|HSP~xV?c&7FTghy8 z6C2tqyPz?*2B3<@{*2!L34W-LqH%U1iu&*klz$g6Og)ados-uBj5eJlx5=-lW9Ga@ zTAygssL!$#@vId_{||-Zv#rcAp;{Flx(hqZj}X2HBV-WG-u!{jv@WnEk8z{A$JXo2 zmK8rUaPPBUKJ^iiPf#%CC5CzlIw$EVVR|aSe;ncu^bTB{XYQS<7(&bZd{Osd)I;|r znfz_`NAtM)VrBDj7LkqvQxRhFmHDC-+S<(Fl05seR>#eh_Am;#?UIjNen$J?aOY&n z<2gEV-{Il+LrZFsX$ss{J4r_(`l2%9;6azcpPggGQ;I;fer898G9wIw5^%8;Ela;04eSEdtUB;<8nH?hxO!Bds*6EuTf+uKEvf@Or6t2%`hoV zb?JuB@AZ_n>T%Y-4__#qG8Zdpz4) z|9nk|II%IZEb=r*bAm*1j6mZP+o?ZB!hd>_sIJqVmN(^pU2;}0@(`~$>=>C6X<0FJ z(Ud>_Y*5>ZV?8tFVbpz3)+0|g|KVLUjHZ@nTBLhjG{d-x6~EyvREi2OG+eU`f3FYi zZ8q;)myPo9PK<X2evAjY;SG7`B*(2>Ua^0&rI5_J@;I` zzxy|Hp6WxMsf!s&auq8j!#s1{`WUxvEHLz;nr8TXU%c6N%l<)cXP|y4o$8DV8yh-Q zP!SwaszI+kJ#r2g9wj>6(_2@XLE5lf~tG zBJmqaqs!3imxyxGwORE94X3Too)@NUyCXOlm3e(;+=)+NR6!FcK~ZE*z3?Qn%ZZMk zur|PD>{C%_HP&+$`zvskx8o5h#nQ75&alYSl6i($g*?MzlD(~TE?*N}hZa_NJEr^H zjV5L*eA$we3$1b-em9cftIeW^LB17w+C>Y4gRF8NYn89BRi0m(M{{=x8`fu9@hp3M z;d7Mre6ke}IHK!y@d=UebSwUk6<$qHm77{WP*{CNpmaN1&uT%h)N0~78C`nzt3?y++~tUxyv1Qu-|_sv)P^c=FOWoZ{A#+1c%Z@bF5`ZThn^S z2b)@lt_P+nnhO9}1cJ1V0vd1uhXVR*8c;lLboKiUlIQj~z91lVABINApid{BXSrjMtAVm|Lv2z%U!=QDQQG0X~JNEmqt4!m2!I}aSF?0`*~QcEa|Up7xd-V>ijuijyKQF-lnsx!;_Mmgs$idmfSoMwBlBrIXO1Z)a+GH z_bs-p--d*txpehbsnd1(hzqJfBJ3&-FbYjm0zn9xy5h@G!qrb@SS(RCmx}Trz2w~c z5Bq{ARYXlZ^xTu%Y!lpRkmxs$4bI`|6kLvscba8U)o&f0^e216 z{WV|wf1ul@b`XX*8$)U!zi=NUz38kg_@P5eT($k-Mrt8 zf4Eo98*uJuZVoeyN!n_2j|XyZw;SZh_WXf%r!3iP{CnT(XTOn>nwPRLo*}_;6>ZcZ zm5X>`<974jz3YkmFP?|((=fDYC6~+UcIE)9BnuoZ%e=?|a@&yEUH3e2ZyMaKJ%XrZ zk5n&R`AYje4o_4|%y)Q|_*LFP&(9xsa7#P=$s^%rVv?|Gc@AYvel8f`a^{SbTvE>H zY$+GGQ%A7dZ&=Hxz)|`UUl^jQh`Ob0h}u!osg0e{`gr{drk>ut35sElgc*$tLs@M( zxptdk^Na!tu+0Fj5i@|x?v&I~z?0{4czV4y_~Saqt3g?_`6P2txNLR!a?M+9%sl18 zbq9EFs!zO5wQHt7Srnc%6bP~`E6^;@OMnu^CJkP>^W5+~HLgt1be3Mq|8ei9Cn$eQ zId_o76dNZR;Js$cxf(BT%?g!$i>Z8Qk|QaGB3W8nwC?G^sbW@Mosf(&qr{6i#6WMo z#*JP$^<4-2e61_NSnC)!KiZk+Qb1ox$p+_Fe>TT$fAl?bW~G<{XQdiQXu`y!J;%M5 z9Ork*alV(F;K6A&jqnCOm@xa%9reN}^c-NO)kU$KLNlty2(s9A&$u}S_It1xKWl}* zj_du>kP6iq2J?dP-e;?RKPZF5n}AZB$nylr3Jk&1B9Gb@tf?NkM&rGwfA09h)AvIK z<;ZZ-FA=OH5ZD+msbaQOb}q zp|BcFs*JjK#lzyX3GTEDUHm~IzkE|~(_6a+$3wIHpLb2aap&rfk8GJn^FWalg`j1U z899dO-K>~y`kWr#uZL5x{U~`mxSy(e+kwcM9-dPeNhTSfs5GkS`MQreViQW<8LeEL zkASlJR#VtnLvyttk~LBUGDQ=j+W4!R2L_6->1f`!Hys?^S%ZcqUlhyN9`aR`G)WEEbC;($rL5akFWv_o@2gSj&xg{v=W&%h3!e zFakkxA!gHK$otNR{#%kUZEf>z{AR}1rX#{|h5}VAOQ3dMzciisnynaTc#td%CpHex zZ9_-vbnlH1uKoL(?sS zZo9#|`*e-d>Zw-v1=9I$vrC>~Qmz#cs-OufA(5JTWI*raE&Z}Hx|C3$iB;fuB%SlpYA?4sZlk^ zaaY%hTpslQ_DDJ4?=`ordgK(s7-E%NBSlk+Rr&Us=T#uEeBta4- zMi2paewn`F%Td|f#MBg+T&+4xP%)|^@kN&4VnJO;YnIJ=sAgV^?t13WT)njJ;x`{& z3*#&HE~(aJ@U|BZ>mO4!rVRPHXUm0q^!Sl;wO?yKyjj+Vdi>^*&X4~bzPAsIFPgm| zc^Q$s2F3@u%s1^>HR(MV|7pSJM^{h1%exa9`1ePNUysD0;n?HPC)fP$+q?VLL;lYw zWjrkkqtZ>CO+R##_uoJM)XMK6Ct29+sdsPOz54+2`Kw6$IXyh{Q8m{G)pKux25E1- zxM$NZFAkgkDDpnkQH>w?45-^8X@R82+s+(t-@b>|?;L}?uiGV=-aFObzGI8;Y!5h$ zYQA|O|Ja1qaF^sZ@7(>}>z_Id*;$72?6Uhs>EcjqntN0At0J1kd@g&edkqt==w8WnKbcui0x>GzhS zmQML=+XW>FJc?R9#@4r(Zu2@%wYp(xlgKh9%WEoNG)@Fm$nmwTr0{7&KAIJpa4ONXTX%8lzk{UIQ&i@e}7owYlgeLAFlMjx8YYPhZH~Ws9SxyNQNOP zT2Lfbrf`OyFhmVKQA5yZ#~h7ghZiS)mv{bECr9--jh%1=kyANQBsfYE&dyZp+Lf+-<(j|?LaDastRq2KWv9#Koar9y0WQhobPaao z=6T$=Y&-Z)@r6dNE;mio!%=!Ts4H#;S>>%V{J^7wRzb1pm(*}#6Dbf1CrSbVDDvLx zd(2Ng_j6UK?&h6(UOM|usU2QL2hSA^*Qs)LQt)gk>CcbrC777R1=}GbNys^Ct!x!Hw4FA$U-=)h%t1#!}QZaOu zjP#qu7~%#J03i;cCpl<}zTdn1+xPG3n+BbJ&8-t=;lmSFyK^RR75c}5`mt+3{*!%9 z9DH{Ek}CER67p7HXA7AoSy*$<$;!$2|rUV zk^VCHk1-w$dbxc2)#%UCtrKQr`llQ6JOwji&VD3*{pbdx%oz8`%qASJOxk>iTq-Qb;9E_ouyYc#_XG{uO`HyqeoV8IGIPSwjl4yhM3 zB7i;-?$X0{*x~T3_n|(Ax8M6|WJ@`fBLF4Klq9igtfw!`rp?~Wv2XmA+yrZbA=0YM z5DF;@Duvo$^omh(FUsx(@11`<-2ZUhNG8Zkfnyhz5LuaFP!r@;kxv;bl0vAosL7lnrz{%Qu{hs2)g~I> zecjv1boA`VWsy%!14@!)iIfyx3_1L9hwje!LnU%v7SkKv_4B@ZsNGupVS7zuXhGvR zRo2icrB$55;v3$+>87576K}Mxs0t4>iBwb;&CC*KW@giy-u3K5FMU%TdifymUOr@2 z77EUcv5X{na@#H5_||wcYK-5ioQSU#Cf=%qUZ-8N}hN5QEF7Fj5lsYN3U~d)o1rlt}Nm~1617&)F zk3c0Gpe{i^PYTXC-4s3^T7vhz`)*x2v+-BZ6W{SLPJ>v6D>Psj>#^AjTq70uDXjU= zZE3_Wy)#Pc1b~SWN3T;upGPB%R7|=C;^jnpy_=r6{q-L@wZL<97f|$-F-Z$RqZNYD zgaT)zUu0LQn+X}azj|z0CYknmPv6V-82%XK5*S-z=&VB1WP&6(l~X0T{Z$`MdVc!s z8t9?31(-}1#Q0vKF`$gn!I=~9^SZ{(xpi-KI4|!EJ1^5fVL6pofyT=cIj_#SyKYUd zi*!$E9W@gCe^feLB;^*>xWF-lK%wT-v&Svtth~Aq7O;a_M zU}TP$!+LL;Q#&|Bf&0IR2E5*XEKd*Z<&3CS<5`}PNm?WrE&N$&bCfW29`Soy40z~? z51z*ANf?sgIa**Tf#*b#3%Po0M_Od^_ItB;d~yF{JDP{;?TYL_3C=p*;hgE{lc)7} zC{ESpn7ZM}`(IxBeaB2RdAXE4&+qNFW9G(589aWVhY@J4E^tF0aC^@GMJg=K)1s;g zD!BI59>a=rfzRretXO7K!29;=udcUm&k9vh7cn4CrWlT*d6J>E=hnafis$D>X55}< zW}KVx_(5{qDJ^8e*X`8HynN88dXsV|V)rL2GL1h;1q z&;89?)qc)9#|=e=FHB+O;PdBWIU3NMM6;5>k#nY9J&!$fU6pzm3b2$hWh^b_`}m3X zw0HL2qc42C2J)aVmsA$IC~!yx2VAWTF9VhoXr5!ZC*Hko*6ib3<94VpAz}S_&O3H_ zt*ZW+a5r^zMi|kL67|9l1Pf-+F! z44?r61}Yo+l#tIF)&vF&BpyYA-Cy1zTdLLJ8eup3RasP2iexyBVbMKci>{Y~-qgm_ zkCxp(-a`|fW1GAeQAbM>3d3kB4J1+utD}7=#}X8xfX_d9J$yMVCX=tVIwfO?0+r<9 z?#JQ9^X7=4x65PGB*l|?=b1Mj=z6XS)DA2d7@RtcqtDB$GflqUO+FtnPRt5jVHCHx zB^iNZHGvZe#x*bFghfn2_oxD;Jo;1IUvN^fmC&-liLtLe=D)p2#clSz=iRZ$dNbU= z+?yI^Ss{vr8}b93t`ScuV^J1h->VBs5{-@upMSFy4IQ{l97%)j!^N zyx(0aLPAxO0RsjuRWvU)9flk0W|PJD!;vL3wnsUMKxhoX39?90fJaXv+=Vr5PxiIc zRM)i5wL=BGpbMjU>WgQD&JBxg@}WC!(S^xWU*mTBxAgxiOg##WP)M3Vtx(W8eq?8_O>>oY>rRuwDB2xw9x(s4;u^KF{+t8Lr0Q25IYV+Kfyg4J%D0nY0%N94Mj z%)C!={=7Q_^=9)KVrBs__dh?ROE!6WI91Pcp(QvJ;*`C{An%_=hsU2#Gj5>|i7% zf#7ITWLZERe*e)=lXeIxaQEJf)EUOjG4?Hf6QPc;+6UE6jeG^WTH{$!Yd$h-8Q#=mfcJujZ4ed)Fq%z^I zMH(h7yTxsN-;ys+z58be*p<0qyHey>RbVMvP-(Wo-`i?>8-8648XeWqY4Sxq4xj&S zPE;8i`d<0wgFou+hPGxk!(A)P6w7;kj%i_mV+0yY zq^1`B%DC+G8I62f)H4&Vw8VV*fS?E>S>Rlr-vIhF{?VJIo=NoC4Y!Td?(5VC`OT1^v|QRZsUVW*2t$x}=~GZS^L;7x#>MGUFC_ zt{89F&$HIvIkF8nF5Jgk;20ga+^DsWtWT4Tkm+n*R03$}`*h>GV{ZEr?z8R;GoC0x zu-e@H@*RU69^ld>1&q#<-N2)Kxw^-$SL&yBN)TD5=`C1qPH;7vk1G5_zh(GBm}Uw8 zJw)UG6~6c`Y^5-LZmI;XTY4h}9E8v>(&-njZ-khE#JgVjwyp2P70kPXvLhZ(r3nBy zAgUaz(xtz|t&?xmp+n0|?cmn|eJQc3mB;DIw`27J>o4EUAxK z;IMr01rE9*scy!pqiNs28@_1Sa%rPbwRkZ>g_C4n6*+=bNFcr5|HG#yeNqEeetla) z*^>4hZrAqj?>9D&Ja3*i*b!L@$O6aFDn*{QPy6J5A5KZaO>rN`I9Gmzd9Oj7>EOPP zUB+g7HKwmy#oZQ>g%A`^ikzg10;7bm5QJ+tib}bn?mE8`!~7H}Z)YIC?fl0yMb%{q&g z^il|fb-3gySR5A!3&3$+Fdg&SJlEN(N7HcEy2d_^yZhFzczt!xnROk|I`Jv7S+PXQT&Oy2MzcBN9N!VeIEbx(9d_}+jTPLw1sDk zx8lzjQ=-OD01zbLI<({wUHyDb-M_aNG?Qbnmxy!FK^kox-?-97Jz_M@ZR zghmPiAb3e-DF)@BZ(fNbrlCIPz&khmGC1;GXo4cBfT1*&5z(X%EW#x{+&9uXYWvn6 z@E};tv@r6dC|YwRj|aFMqn&v!rBEBd^KTrxXWqx@U&q*VwkV{hQ13@u~B zv0`FHl>VuY89${p9Ef+yh?agvDW|B)IyD*Nv0}7e(Oi11ulJO<_tg8U0Zt{r3M@m2 zG$+tJ&r+yDAT6p;ImXwx--|grTR`6p%R*(0;ulX!GQrSN!J0*rYhJzfy%mH0PKOKI z+g=-VQ57f_(>Ndf!P_2C1Ny$06z<4ijn{&QyNetK|ra?9kzO47zI5^T0xG@)7RvvOTM(yzNad&(7-!+JZt zrMIU8(KBq+XPGBEkIBI1*jH{Hmg(tohbJgH$fcIKS91^&# z8Mt`Y|MBV_(i4=gfyyn+`nkC5@k2_ zxgOR_58uww?CMf6{5uKx4tJ{`1hiK|j_h2p4@$IMkXFKV2)fT&wS?G%tVP9&%fB^#rDifeR$Y5jw+kjl6XF)6_QMnA& zlXXDi&5$^1cbO7pK2O5Tw`P;%J9sx)a}yu=!W4z%6c(t0#)`K!pSAt*RFnID&bm-$+4t3~PHT_Wf@PZ$wrmAnz<9t(48zC`#tqF~{_~0y z*uDoah7zM{MJ^-G0g~+d`q_71vMbPEP{Z(UXu%BN%D2)iPiks`6H$?Vb@+l4yC1kW z4H}%tRYDu3G?2?kGxR}~#C(Ty^eX$B-}BzzAN6m6v_tTfqADfR63uh8z(6Nis7uyn zn3a;*1bq2zy7pXQhF;#nIQ=T_<&C2xf>J4tU}$;8m!pKMpUSYn67RM|UM41)9KI>H z)f+hB4D|oHIy`}BHoFJ7tTamjUM6H-k+`&WovQpfd{2$e`j>xRS-Q>F(taQF61iGz z|EE_gS$gl>9A9~Q#P}YXE{;MSz9y~rkGZog?9nL^d$izMDM=Jr4JgEr5B|Gx)hlnN zv_*1$`G1LN`9`|c)Po7Si>dyA$j{OL(fCgoYoCsBmIF-($BZ4m43ZvoavkLHXNQOM zOb)|Pg?D$1blGxj1#a)p-@(*ZvfCG&a1Q=z%E{D2m&-j%1}X&hAe*&STLs6T(rJ7Q z@|_nWD;lUAF#64a0Rsjz6Z6GDz&Q0_^uTY<%PE*{+vXJ3zXJz9R*5u)LO9M(tf%zLqF{XhG!D2cpQU zxO&8k%4(lu*!LOjU6$*^)Qdb0D(gBm^&)-WFvj*wDb*1`HT5V4z|E z-A^d)Hm~@ZKeNf@JCOeOx6izJWznPaDCRh?(0d-ma@L{t@sfQyaJj86kZYIn2LXF7 zaJ{`^_;b@+)J$oFWV%2P2_#&AgeK&F6XySm4V>>mv&rMzHE~PZrgPx-&^IPbBeJw$ z?Q56Z?(?1p6{p>8Rh)J^P&}jab7ZI8-Tn94lc#;%IUR1WoqT6d*bpLROmO(*J;8C) zBSX&zxepHwTPH=o-K?XdkYuhNUKlQGnb<9Kd&~!U< zfK`-OS|kLDqeW`Yw5#W_hpwwq4@vov%-|4xo+xxOm+pN$_00C|f4EW7#Q8BgrR8Z- zQc0E&D21Myz3S<{|NFKI?5ynP3c~}I@Xc>A&GqeRKZ!K@Ev(#~M*WQ;hMFlIC3Bt#eziy=Odh?m9QTb5|Eo^AupENR6T; ziX{l3v_8?I|BT?$M@IuT6r^8e*CL6 zoM-m5DDkpJT9oIpmak43m$OdH1NvTHgH}U+o%K7U*k0i&7AS(k2|(aPM(+LO>|Zz4 zs|rWOusDgsVp{3z{oLFS_uDf=QPwChH?}ni=huh-+d6Rh?<*NmN36I_9xOmj$4u-a`iz$l^v%I)BH8W{pAzKylenlSD<77@iSBMnnzl;9BFGuwdmEA3Yw6*iS10 z12lz|7+S!I{cM%O+2FoclEXev6vqEb;`zG4?RazO%`iXA0vU2(r zt8`H$hCSrlJ^EnZkFslr%A-2%+Z;BJl@_T5<3Dzvt$H*K%AvdUN(4$MhgwVz`>q?a z5PW(n3pevI1VK_1!LuAq^8zKHQ{P+N3d7o%EFSj#L2fuOVp^9_xgOD|@sxF_y?>6) zQ*c{|3%H&38DLCyo@4p|r|Z-IWj$3~*iVbOf{*yFOIfEh?g=$|?ZZsHj3`>Cx%=20 zs?9O=8US+LeY1fw9jGJZX+ZJtcXj`B*~&9%EfPc_mztX#*w~Nwej4z4^Now^g-WR| z2bgJfDFh{`A}>-ZqyFA<)Y2(`ZMz_#-WK=jWu0&CuKly~*Y%D@Su96chZfv)0$f%N zI2172BYA8}Z`tYc^mRHst^%E-YZ%Cpfol|yRFv4}ZZ*ePq{n@q?Cy6%zB?;S3tYIf zNfR_#0E)~gBDHtL!{W3F?ljm6Z!IkxNB^8Fj2~Q9D<~dH-%t9QzJI*gNYHnr{dV)d*XPFkxeo?LP204<$V^azlk;`gxcw9Dz+opWp zbI?n#e7`;e%5_UjC1w2^ea{`NY58$5p7ql_P0%bWk_07)e8{Rt;R?gL=I~i;^gTg! z&1f(;J#;jvIaZ2!D@$G4aMJ@dAn|uvkQz3u+cF8$qR;p`cy@1Fd>RtlvWPcOi3F`E zvdWP>MZfysXD>B5ZLi)5X&#&wDN!bVB^BjqjP~`(`>+n-bHt1N;E$Gg74!tdo~}L*G7M`*@U4RhdS7yf>~C9 z;t3#0l*kBToyF%m*SM-tYE2}0cr)djrR?L=DJ6Rk-?T6J9!meO)#Oy{#LSDFM5+oW zQ>=ha%zgE=8pq67w)%$M*v5ilR9RWh{&yw!>tx)%VeoU$5D6 z9Gd~faUx4l93k)&ONca@!NVEBVJL-c^PQb}`_j#+4MT+sSHT+8=CHa{fh9SSWHecl zzx#L0t!$OIt3yt8M_TwWG^h7{?Uyb4>f^)M%8(>Q(LBuv1Vs`w&!Lt1d3#|Gy$#Hm zEOz^@9Nc_w%>htG_y$kzRzeY3nWO|D2z33^*>yL4aj&UqbU&OKz#tefEFa#9(mhwIyezC$M- zUUu?u?a;<3zNltd^2L+;hp%7z$OS5gi|If)dtph`GR$H+K3nDov?chF@sRw5gtKE5pgMENP4+5ZvrfS9^TlyQ`#PW?>XvkT6u# zJ?=YN=b;+&&NYDxxa3f+5y>;wyj)fC0ClKSk?c&robMjkbz|!Ma?*L3Dp~plDtG@; zQQ|1t##r7lQR-pAgeb;TGCGFb=D6?Z=Ig#$lN8w?NMvcCs*)rza)@1RBP>h(&39a0 zJ@B5f@QtmOaA^yqASxQr2!f#hcek{5{cU$u8I4)tpth-KYhPs!|6Md{y$bUI%&)T^ z_CV6_agkU4TQAb+Hn=rP>t}txKUy2u+BVgngxw{VXoXZ*Sz`dHSlxE#%o_CGD2l|?>{T}{uac7ivzvm1(BXIzHoI#6@7h1JYjjrYP?lU=9^^bXG8Bv&LQBK>A?dv%_De{>+iDzV1P&pE) z=-L2hK$~Q$<-cvI{Mjvip#?^-)KDD<%?s9C{S`l zQ8`!;BCA!(^dX~b7Gpm*OAx&@tKjY4EY9Z@1&xsq_kXlSZdNJj$rMG@GEg=mT`m8r zz5n$Xv=my5g|{G)R4LbERd`hp309^_Rz~eelA;JYwfys^Juz(31>?6tVO0S}ujWQL6sJ@RomEMev)bHa z9X8KkhvEV`z~MRb%jsoj2j^rgG8@!l;L^uu2Avx)=+Queus=clXOKbJj4RyuD(`WJ zmM78WN_2e^m0qml!{CFL=E}=#YUp3{%e&q!yWolSZ|a6FOc;i-&a`>5$4T})Fxuk+ zQqCx#0NV`UvMMs!pnld&;YwApn}L-h8$+V zSPvNM7Xt<=GjLY_7E_l0r0?o~pKk(BhMo;Q_X+Qqp{>IuM_;E3)B@*@ZmVXS1=OLy zG1Zg3eae4JCuAN;UW(*_>eg>TLWsVY(1eLYqhSUUhgW8xUM-@7nn{ETj4vC|@i>E*?uZna#zA(ACKM=n;I>p*%`w zOpJUZ%b!1>(Z_>tgSKyBJcZ@3j8$o5v>EZ8rkff2q&6Z+2IWYS76CRY|*{ zXs@lY|GTu4-#1N;cob2UC7EMHz{?yH_9)`yC?T4!#njZl?aLca%e5olJ4L7xFY=tM z2(s4qm7mT$G2??YXep^7VZ4AREl{`h)+pZ%O;8_bn6_!^Kk6McZO$9e!gyI2(k$@T zZ7*=>JbI?hqhu3Z+fD4hwo5WRLo_iZd{};D)x!UI^&95w9ReZ?ng;2M_t>eagCL6ZtSBx09V<%32KGHP-18!%wNm`4-3`mvZg z`ak*Ed-%8?`XT=%bO{HSK!kOuy?Vvo45{952MS3YDjr9qNqmU-yQvbkmGjVpAOF}_6k*G7r*&VWi^3h3T~nxrTMdu zj_I*8e=mFQ!0(an9$_htp&6QBSxO+# zyGN2o6oyrYhtGoWU*TDL-EXHNdPQL+Mo?*7ya7ATR z9?-HX0S$FH)FtNWjPvjObj;5yUx-+Tg3A$Uz-o%Z5@;QcVeWq6{KJ13+j8-Mh;@)< zjuj*z3xpz|b%^~I#2)^@1TURUg>hYJS6v0&Y|W88z*VT|FSug~t%MDeb`Sq8U!LhP z=@8VQ7js)zq(PT8S)hT;ON_>y*Pz$+wxSFC{iGr_iFS22zJ^!(o$J>0oi;ndMV35A z3S7aZLmWd=EK16cy;fM&moO9e)&8$GPTaJ;8*IWbSN0aTM4(7s1Dq&Pn%HdR{l6c{ z8I<0jgyS?d%JbAH@25sdr{oe|PyhCR8}yv98y->GS~a9Ca%e&*RMP7gTF=n>O1Yjq z7Z?QWxxn>k&kp1FY`e1R4GGfAm6MLY-0~@}a#z;+Bnn9tG`*BkewS2E{he}&j+e?h zo)eu;G-uu=g{6$gA#Pk+5}aRBl<-pLcLod?xb#rm^tQOJv#0;TW)Cbq`Zc`!#T5R^ zWiSJ{@~w;pM1r9SQB>*04}ACL{d?a@YZPU55w8tvtg99jWp$%7-cxyB|GT%Y0t4DW zeOoxk4iw2-mGgIgtHULi%Q4_MH*-6( zVEg+9rb`mHAmg=ny6LjQ`!VvR9+$XZqE+VLFwq!R!P?JRLHo05DZkGs=kj)rQ>&9) zM*Wr?XL+EUg34v_evgxDZY`&IGFo}xzeJ3PVLQS4RCf8|>C5y$8yvqVU6zzi;dk$w zFYWev@)DK1aB|hKN-l3biRs6tm*=p*Fh4sD|DFaa5w5}5)|gHG{SUmAn?2?JFxRWO z9AKu^Rd79*B#SD?YT);lqn1wjYg<(~40h|ATA$UAoPAMt1N?U^tJ|#alX$~7USKJT zV`+{e2!`QMYoVw0EH`7au$Tt=&FbVf8?=VFELegiD1qfDQsgO$L36lWzkB5{CWnFk zoB#ZH{u)12#233`t;q0-;Uonxnj(upfR}dGZgK7RpFPti4a&L;kPrp>9IxOWV_dvD594k z{=d5%eJ_11JTTuY{H{lilxw9_j*?VCBUm7R{ro@wYdwHXMlEayU!+}FG+!9UJ&%UG zwk0bE`W>F6M*1h!UH95Y$J*&nri9*$ox^gJb(*`kYieG>1wHNoc@D*6b2`T4=Yl7@ zPu%(Ks@By9MJdo~{TRGO4CYYDM0|1cru6S6SHo=_+`Q;oWG-2XJlh;^(PSrL`=N*FMG&_`&>-&{FWgTkopJVfQ zfXixkO6n+}J=P|_jkn>~)u8(9S|lI8US)Xe;8%LQah$C`)_>Q+uX=6yAmZ&|ge-ET zB$13Ds_5-usU`0AasDSAx8JnS9oZG(xSGQ=+ABa!MePiaNZq>pLb=B5eQCI6;7kq zOglN^<@)z0x5i}9B}zO|z~xig{1esD4PqAUG{5%p%fDrHhSIDMG}Jtj&0%%PBA_&y zk$72TzWaB~t!$OIt3y&rzolN-Ftp33`fonm*Kfazg}RL}LL^HF=dZsQ>~MP|hXVT8 z9IDMR)qVb7hLwOo1CkD7Ux!zfHO#jsFF5oZPS+haz}IVSp_1Joob6*QO@#5K>?o zRglnxiAMvD0PTKa+H2RJ_^LrDyLBmcrvq4Byv!&P$xwtQvM96dT?NNr9RBZTPS{fQ z0Id2VOSq~7QD6x{5-6SmwWdGj`q}ziGL+2L>HRdPc5sMdPJ-?_UZm&OEwgM$c{4&L zubCs4!-TX$qJT>eK8NAYdij2VHB?EgBv({O%3E-8%b)h#CNi zWI0-q7>U*hoCcsD5~AoA^E8p~f9L3A)7lG%q;fOE4JVbCSW@Ce1#rahbIP&1n{TNm z=n4I-+p@uPWc!nX+XScaybJk%K0-bs=DR+~cQ`6WZ^(wOy?W?jCq3MQo&!g|yAP2$ z??p1)rhhO-7v7W2!J;aUA@kly9M%V#25v)+&|RVD3w176=pp1PS7X{C+Kuvw;sSJ( z|6w!C!l=d@AqClQ3SMRnNr_EnMavOw%fX;CgU-s5&N}EJ3F#s&I9^%l@Pdxlpu-Z; zVcl}3!$WLv+=nDMSl8HY)s5Ug*Oy?>jTfuGpRN0>ecl`#hu^{XVgJt7JFH>5;5dYC z(QfLjf56lXes0qVYXNLf-SJ9oJ)Ix*c7*5MRa0;|V7zxyaA-o_yWFulsfcC^nmo&t znOU6Zengh!Hz4r<(ykKHuDg)@HX-pxk@#FBej^h1AaMs0pN_=kC~;KhISh#pLE?jv zIJ#po0Ewgg3K@>3&PW{c>tmbFe16A!H@Q&N&sik?3le_~iMK%FsO}a$=7YLpMKv<$ zypa|qo)U!*UuyM1%lje{zaoli&vIcNneD&p)6eo#Iz#tdBf}`zXjUvZ!sYOckz7-O zr+2Px7|4-<%RTg)7uN3FwlEV;&+GN@>ve_W(~e}jK8lJr$#jc<H^2lu#~7Bw3XRmZBI` zpLORPGbZ8JpT6&g6}#c!FTPWxD+KiZwAg*9)5@WKGt*}sd;fYG@5Vm%?V480%eJRLw42Lzsxr$rLYp|(Ew zc3NMaV3t*8WR@dTpopqEWrcWf?jdt#T})e6 z)w69LXCG9>?8^L5LS+d09d5(v9{-q$>)+3t9@z?qVmY2-2vP(g8^cYplkReV>I)}& z-90QTbd^-h2#1nXQY9&h1>B#z`#nfxy_Et5uLqG8-fmnWwz#Y5;(lLJv`BDzSuws> z(kaO}RudbND|ovl`uujhRNLbQ!Plp)CO=%CJ zR>g!66@BxjYXw&+KDyLPj5H~MGi^n>@#G6h@$5EOwzg0^8KzXgF z3>YwAz<_~70=)^ceX;$>NG_($rbqqHwLj^6{mFqiAPp zoqwm}z#`?lj{1{XMM(#_NXeBPHf6M=f%A_zK~!ahRTV)cHazFMp+(av$*A~SH$lyY zKQH*CKc!yM+gE%a=3csD=LLCA)EJIaIF44(c0qU4irQtP|E|UU4WF-t!v3Jpv~3QL zv$!`4QV^_t3yu>*hZd5m)@l3Gf19eNC#PW6YPhvsXn~&cdp|l8=&}ad=Y%=g9%L5D zYa}Q0JjDyzg!U(gZt5|uTD=$x0nseZo_axFd1fW}PSB!8c-Fsh$b?S&dSe}Z$sC|X zMbuPlkGAgfe~Q|jAk{S=OvY)WDz|+50WG2@w|UvMoL$+ z80BC-C4{7$s@p9GuwKz#@{jtyqk8JD$Xr7Zc!Cf_hE%8!u2JhLbNHm+@Jlx=zv>GQ zY#1SI!w{OlNu)$djHsZuPeSZXj@IWp{hOCwz2e_hkf<=0RN8rWU{+C5Bu1u0O=H9n z1Gm3>Zup)W(3on+tkNy{O8b4RSkG*|Rajinwylc>cL)&NCAhl;_uvk}-91PF!QFxs z?(Xgu++7NHcelE%wf8;Wc{p$5dCWe?oPG4awWekKBE0H7GwaPGNdv*{RNEO^6v|#y zm%4H10em@|m@}|imlKQ%IC{ST%z#md-^S} z{V*Wi`pRM?GecZRD&IO$r2ioW@ZK6rx>!yVHG>s#p)3!N3Y@1?l@)c$41Ko#3Cu}CM3gL4oQ^x9~w_M?lqI04U> zggNQ_eyN<7dpEtvGsPTg3cg`DJc={{3YYDH@95wcR&8|m6!S;J>Dv9K$TOv2l&-K! zK?Um81B6=x%@F(i!9xp4=GB|N*okck6dGCcBF#VH`zHu}Q4V|~ZF_M)5_8mKij4(; z+LG{5mGEV32OL_X`@Gagz6oN#!f#O3tPPKtA+qh zUET4IT`f!sfgiY>iihNh_zg@WC4Oe_NA?@U4+#7 z?w{O%4p4g~K_v+}aP0xixAQ-4Yh!d?&eTapP!?WOmgXH6C+t?O9exxGZ*JOeaXKb1 zqbnOE@Pz+`5Ou~bMYXTB+$jTaoAq%{mC=sFyaUt+2hO()3g4juVpk`KU}4W%kBu}I`|)kpLxLF;sK!YR;pujhC#R{K2{X#p&75Tuq_1G01Ec zxW#9k+VXW@Ff5#E+{1Vr3yc9?e+Ag4-*ii2?4!jLT4wFSMq_IaaSFfJUom%mQR@?` zWVRPl3a{RbePVAoT@Lverq`BK$BT%E4LSHB09=fe)s}jncvIp4m}8EcSa>!vk01oe z$9Ie)?M=6KO$nu?=;0=sbI=jLck3iwT2uRQ_?~8awt&#D_zAI$-Xsre8Z6x)QCj@P zATNZT|I1EfK0UX>?#RoTLq|0bma7?1jDqiXlZxavsW+cv8+3g3lbZX_m{-(O{+fE( z#Oy&brJFXd!&j^%5G>>rYYx~k65htX+uRmh&`{V+n`swH2dev%(jSpG+ya72@82kS z#Bccy3_EPk7NA$fiCHNrSp5s|fQz)Q|0qMX|G+dSZGx@r!0N}ZwX!4;#+F$|;!XZ! zj>f~$v`gJTmrc`a?L%T;NnY>kCF`rB&dgI6cy!{_5|Z#IgjKps>>umRJv&%-!?(7B z2Ib^fhTi#;J7z7n`=`%4(fxinLvkuXYD6EvDtr~!QD0`_0>0S2mkn)<0=i`*BL(QF zezT>g=D1#^Bhb8!$eeGUzA|I*$t!nrW;9kOadU#$73&TmKhJi)CJ8u)@AAUgSKZf> zZq)!EC}MIVe8uAY(InbwOtNwj9za+_RWnYfZJ)4AoNwhRKH(>dpFP!w(w6;ZgSI}i zvz8RrMy04qnYXn=VUVP}j`@4zD>2)k1Kr07VDs%b@NagHcAmM)5rZhgj{x02LX!fa zeDb3cu-3i$^i!Jvm(a@s*IRMbeShwLLTuE9?AQoQ4eZ@hxqp9@f~BkxR+3j-SHT9m zN*4xvlnIzRYFfdG(y|o8anHi5?-~-ShnIeil;01>s)4&^(fF{)Gl=#zS=oGElE2hq zfa~QC-3sLf=`b#~{?f+g@-f}7m$0u=6;){5#2UE!#h-S!fz6|eoZx$=qI0mH9y|2k zSEgj7adIY)!Ktdw{TJWrMtJsI>~_NFZ9D@EI%N|lc4;Epl(+LusEgF*m(s8%{JO!B z1ag&%!JsvWKkZkC4&dXkqXs-!(;$^DR(pDco1E~EG{cQdw-~7 z@0b3}w3*dg67Wa{(;r}C0Gw$AZ#S^ak_m#Tf*J3$L?Co18Cr7ht6m?~N+=)B$c3c- zB#D&eUQ4U#H{1GSVZfZ*<9>&WRBAaHqTVgGZSifM8{csA0k7#HLj&%r@oC0a&!Zj1e>FG9eYdG&AuQo{^>2TRmRbmS(Jikp=!nHxn_40^EG1S?dSzeyIDBvYcB?56f7Xqclnwu6AagN-E%Big zkB>c~{sCfTuQ|Wa=TA|HuqBnSs_3CZ{E356nS-D1dM|?WAvOiN{PDG=6%R?Rf>J5l zB0$c%qkA`{kv;Jzx7#T*CXzg>6u~Gbl#7o1)8lJQd`e}W{3te!W!@Ll`70ZdaoZM+ zUn6a4nw%?NxLbjtPQV{X84DK~2zvQ~W$V;v&{?*{I$Iotm#U$tdv=Dp=hlLog2S>M z^yKTCLD;(z<7Wrj^jejvK1Z$1SSrldZ^&wj9BfBp{-T@v ziklPBRjfZlc=AF${?Q$EbTG3%=Ur=MOA#=)yyQ&H{O-8~N3aUl@bhdqIgFgZb@xMB zZ=Vb-E7=I48dmp9w<5S0KPi$WqhXLMmTLU}_)d-WJn`5P5oSMPqCYJ+qTN9-RarHS zW)u#m(}aPs8vK->x5IOz5Hfkg-8O%u@z`Ljeb1yR)6D6D^;49AkMu0R0Sxgk{E0j z+yC>PSCfo4Q`qxN`!aj_9vW7STnQzE`LE=0Ae+euI`-kY3MAKfC6&$-LFx%Kg$H8N zaTO$28qmol2y0=oy_0`V#X>My>1=Gw2ir9*_m;I%iGd z+AoSvVoR?Eqaw)Gyfn?5&WU0P@Q zrI|}1zPbuJ$3IZB1ERDb5|U*B6vJT9uzTPO%6fKfH13aP+GzMXuGRQV>mxr<0f!71 zUINDMSE3b80U$VH@WD15L2yi`@r%B~U(YmE1O?@S&-&-{yO{!wJ3?rHepAzRP2!WZ zJf77tZ}7U}_)Qd$SRK%veqPX?3gUQH)LV`K55HXaJ;w-nakUQ};GH``(!mLyClIG;r6_4G!maGo$!hd5w`O*M+S;?p0{2^+eymC2#r#q4^lQfcPN zO{-Kzzjxu#^JL6!u8~IQ`4A5%?-<@HmI*wNiN}J~DX?PN!+b{8H(7$N*UKdId|3b% z59uMf38JX7ApZSf=+;0Q5k*f=PoW~#w46zya$7D;D8V&CZ)BLJkV0KHs14p@8>KlW zZ}!f!Pm*TEXZh*m%4j~9B=YDqMr`;3ZvaVi#X$qlAQnM55?b<*=r&Wxq@mRS>wdRk zt1}?d^d3o9;hD>;|4u~(8b#-z8}t9A7Hq$Ilb-?ro+|ygEa`1^mPvZ$C0tEmd4FI< z%75s|A}BX)+`zg1#Z&E^R8+$z6;5XH$X+9O4nKd?b-G-PYcGV}N3BrHFva?5;RdO0&sYC?RB71rL-B=U^;%9!8<4G$!=D5aB--PgIoCrI^#^ z;U^W{G1Z=j4>u}-QaF6TfYYsBc~$(T$ah}Y4!erJ5B3arwRa1A!_7b53Xx41!K#^b z*qCx9Np@j{5t|Mij^q%%sR*0Z!ii#l_a4GxA@WRb08C>l!SPa#XuD7jsqy2%Vi(I1 zojdK*5hoF6;h5yZDfxH*o(}WY*IuUb?wzcIfJt7!OEVSAuq_Zbdt`@_v)9tLSr@Cd zm#yolh)eocg4v&k!oylN6_OU<-?-ZSqZw(5cLCMzM~FGnJMAY~xu(c}bPfc%WO$zF z9;>n4c_M)@P_@5}pjU|qFCZmtQZ`*qA4Ir&VYeBPoQ}j~$!u>*(V^*J_D#;n(lTBA z6OaNO+xXg8dDPZw_y_!cB4E2HIyN$lYUmayHE#3{#cXQV>2u#CwrCfdk5uV?9BTzI zeP!a(PvU0cBDxSsZk)zZCqmX=jC4}ZqSdo)t4?7DSFI}2XVy8|%G8NW6c42NF}HURjOe@>{c$~ooTyEJ^*gxncY z&jP6Tc&ot9y9^!^DvJ~|$N8K4$3(Ar8^03cAi?`M@pH$qtx6w|@`R6XWP;#Yyb$QI z>#7goM2$Khd1*g%%dYB^sI;YBN20s0H^dA>G}7&TMt+E++VEtJVSQR&$nU*xB#U5p zt-wPJcvl4EIVYo=Kevl~rmSCB3Gp=@Gjg&Z9nWiipqX_Fat&A}1T;ZcbYIY|-yu?G zcHx$O@NBKZRvHSb4v0(G9BP5EEcT|MRfYIuTScSx6?>D~sY4tLdK2=Pgfkm z#BliRFOtBC4V>iFoEXX|o8_=zE5+qad90J@*Kf#wK4?PoZ+PXmRI@F@d>-tEP zxL{uKVd&E!8Lq_{fBk zvQC@`R`moo%7_|S8X!R-kt|I{@gUu{G1(fx6ho$Is%e|9d_j5ib*8*ML@MwH#x2Cm zW;{)#fuQO$9merek@i>V$X-^UswY0bX6==&|0UpVDzTq8uo?~c7q3pOk5iGM4`xwQ z1_DsVfZSOERrq<@@FuX%<7n4N0x$Yws8fA!r+s=#h% z%cQ#ZsNQ7;Xh#cYw&n7z34^A2f*hUkLYUO1AIFvyCJ>cqv7h+-K=tmW;5`DXNy`5y zq(4Xc$lKrrOX&ZRUHl*Y#s4m7<*+x8zjskta4{lf;JvPze1LKlEU(iG*B|gT5Cus? zA3vM`J&pVGxm4r=2VV!fl~Kj8Gzzao(C#cW9IfpZ2Q^}SUe9)-CZ$^wg}x(iPB$~< z?oSY;GU{ho?30Z57TRCA7(Hp9Z-EJ@3|C!iI)6Lj#RvsvqEsQUSWM1u#5rvn9H-@G z%HH~HE7n}Z79352J}!NZOwfa;Gu3SP@voHa+lO!gNh{+uC?Wc=Hr&mD;J8uk|@p&mWT3mcBQ zZT%np2|5~lK7uUF?gqyH?92G~FHB#H@IEbF{?io5LOf$uZ&C^d9b!f8s%^8bfAQM_VvW70~S;p%Z@5eN;Bz1oMi#^>{B^q_P6g>;5^-IAvfe*Mi zZDus`onvwaG*(i&n#xRj#yoT=MLAn=@RbvoSoTgENr*K(4EIFsY7H6wj>;_!^4T^f z!?Hq?3mgolQv68AH%YamTs7d!51i~TWevfp6x@Zi7tlz$)>ypJHEZ5gh$bKUN5ITz zIL?rNSbNi{1)^K@YPF{#T1sZy!J;CPavLiVIChFjoM*F+otNz+q5n?uoslHs!7uO0 zP`l7j`)6_BUz&aL83+0z!kHh?xKdrr#{!>MC6-14rNf-=+0G4VGD$<>7PnfPjO+*~XfqMeiaEaP*uF z{L&sz43V10< z{cG%kuL`_ZJ!gc&EUD4}pKd0$4a~yr@E&noKGKwnm{tqV^OAA0f}Ojx-g0>T*t9su zQ|ab$YRDu&B$(t|{kYY*@7J~Z8M1EmD2qKLnAMp5a`b+hXe77IxPN4~zaJbiSsi3a zOlQk>G=0h6+#4>;D2Q2(PMbxg-2*N1b4A#;`@J85WP#XnzSJPYOw796BZlSLg$iC& z62IFf2!Bd46&nskUS;i-ZkXqvu6@USZR&h^9cf|25z~gxY1*FZ$}Pp>&92+Gz{%p$ zeZuNh9FC2aXB}-Tb+Iy;XM79Z3Gvywn>jUkZ>M*|jgOv*$RHPcs7Y!L#=?Ke8k-f# zLx`vD&nE!=l&0WW>rCUc`O{?eUzQdORI&6jTdi~c0vV&N6*;~Tl zA4+$CJTTUK_7PYdoX!01&}d8d_6FL8PRX!#5J)qn(;$oVc(l|2qITr3{Sv8K2W>Jb zd9(=_w4Xd*WevcZyy@5dvKLNrxh*t(Jv;6zfJ<@H=7X|t68MX)@qL}{7)UzGhlZ_S zK{5$TGFn|JHySxN43k?%@u1nLEKr)TDXcpUA-2t9`Ss9~o8>qb_|+;uj|@7k-AXx1 zvv8$w<10eyZ*QAi>1j@m=CE<~m7$lpsiqA-h{BcXoa zs(ks>8+58@Z=Vz}SOZ@CX5&0hWDh`UYEdot>Ov2JNap-)BK$vY+f#6}p~blE z<}2hDnWkQySC6{*HueT^9iDmoRN9HR9hmv0^!>+q;}IfthX=eW!WqtvTgU0Mq-HA$ zRjkKB@=#Chc1!kS%mj6`yAsfV&go3=veOv4pXO~#Uo}d7ir4p(GU`C*Knh5GHSxd# zx4LUb2ohp-xxY~>kIQCgyh98*3?wA;zi7+{;91@5P!$;rIVljR@ zl<9Yb%s@{dg7lx1+~*Wdv1!RVi6+gQWfI~(tBYUxVGq^A>KS#5H<=ggJ({I_s@FMs zRKm$>HMQ@=kOpyy-L$Of0T{hDcv>+(b8t!Gs2G05YoVgrytrD;eAiQq)pY+Y_#QBH zI;q+DY(Gs>g6jJ1BgulZbRetGaHHcQ{*x_rAES zxihzn7vgkeq^*7AE}-euMaNRF?#O+&>3u3-c@%%An$m+=&kwGV%yf#SM)&{<-GlA^ zvhpFg@3GU(92fmlac{ZG!kFbb^giz&3!{xp5a_L|kgR8b$kw-OEp;t*`#rc=)gKHh z_HkS&z0?U&k`FydmQGG_He+@KnT7fi$Ej)Be{Qz#prG!{-<#ZO6BLF1KHr+`^ zwm+!OE!Zo{qll|HyR4;m8L5a5Xivw%U+W zz_qD_X??oAhi8E9tg8eiY^I4cR7cIp7CWP#+x&5e8o+IRc%n}*7MGr$g#C$(iY>+) zm26C$AlxHb^tNC3z>i+Q(Rc%8_hfHNyZa)^e=>oiT)Ckvu>54Enq%cnC!%w_0tGnzrPEr6?AU^)TNQ4!>+T6-kOV1FwPS>y1QlmlrO*KAN%gBAIvS zm{&p`1aL`0g39tbp0k@oo2AF*IL5T=jNuqPu`=Fi%>{dd!K8Ja(QK^RBV+$=a4)iW zdlM1ty)zb}G8H1qo8`VyPzm!W)HZoAN8}*-ya{fwp2A%h9H9 zOo4F7gx{*bKR$5dd_u|IS23-GeX_+j#D*k#rdKjc#Fj=MZr2Y3b4hG+JdG>CuFE0Tkh;NS}a!RdHJ+gJh zJ*6>_8$Qi0Nua+rkNy&9!cGwL>nSVwKr}t|bp-FG)!>-p?qGthR&NtYov3v5wvwZW zJPc$dmlBjOH^WFZeUE_PrG490qigo%RuN@v#t5h>EGUI*m_L)jUXpyUxn&t!mIkhS0y#fYy&Gi#CAHl{Qfc%|(+scZl)r!bz9M z#CGt^IX^@3978p2M3q%@Z0iHishe;t$afa}Ivi>OB9xAK5q=>Y0C7u)pZek6j zzR}=z{qmwN8wylJN|I;eBfFxv*0v2GI#b&WSrW(^vbPG(&T4Hiebf_b>Xsw2$-YR6 ze4w6AOG|dLla5GEJQ?#ko{Rj%wNd=-RLE=Hi0wmR9=|Zx^K-VlyhwMxYsk&n_~ENd?>*^}->cuORsyzLC%C*H7#f z#5HK8@DuSZ8FdZ3SSC>Ic-(iP6itE10k}m=)WKbFa|1kSZHlzo3+x-+gFymDe!=jU z%ujq=HwLz~;+2{en>3`5hfoYLiCuDUlh)7n;KSL;Y&3fl0bbK^OV_&==KxBUx-b6p z@O%=6-1U$5XT^!L1QIp=e-#<=Iy&O?CLf)W+jP1rV;`5@b_>rZf)q{Cm2c^ z1#MGy6y?Q(cgCuGyU{G?u6B|gotQdzFTS9XdPn#uB19x|CMUb;tT#JX^0-9Mpm3RM z7}UHb4#HgH-kt_;ZL?X1Tt4+!RF8n$D2xf=L8t{oq}?1_ z&eyF*$2D(SzB6(jO^p8-fXCj>eI?sU08Diu<;cC?8VlloAxeDu&gzW!5*aq1&Nbz? zHvE&`r7GcX!iVMTbJ~jd&u@Ev{$xRIaWTxueEtVC|A;cjvE?^R{-uh*g9gDCI>=ej zwG!@Ez8I$=`aI8g2)@3#B}C5L|J7v};*}Lra0J#!^!ot{mQ2^t5Pc5_Y)&{LYYgnF zF4gRe6&(~zz$Pf)(|ze?$i6&DD~%OIeDpq$tT~JmpyIuC2>?~0y0qT#jb{P%Qg1}q zC_B^RISh`1hQqHsa6hIZ@1|xi<(cfQ1r0j^)CP%u{A%CHGvr4K5hQ`A8Ca%LLQh7k zy7`8L?FioAV1um?x^xR2yY4;0fhwCz-s;WA(9XH|ZrVY<-+_gH+M)8-9`vS_+|t?gqJ>aZ6y@^85KRZeA8Beb6v0Yvkrp5&MeH+i_8g_ z*d#sJi%3_sMBT}Wb?X6R6^#qAsS=DGO; zoKL&ymU<1lRBzBr?y+BXTAGST}3LGc`8&bgV8ucwu(A`7wLd>X<~dFBOBe2D+L> zV9GkLD1L2|-!HrEVQ&PRKfwZS{3QnSr)EonI#QR&!059SrRP0>1Tx}K zChyB4mq|#V=Vx}AAWFSd3+3so`hcCxu#J4Io!^{WN=Xbl0p+3L6VlU0h^34yRhUtf zYTY_Gpj47D2`M8IDK~dkl$n6riW~e zJW=FcQ)@*a*vN*lw~nOT6@cE+4scvA-s!RzYm{;Xn}@}kipQ&zFRh~5&;<~*Y5AP6 z>w>y}M%ts5Uh*eXzx#!(*HH)@vP&uJT|n0HiOqTd8sh3n`X`Vwmi} z)?c0sJPX_JHb-Ax5~&jFI?2>K>M-uN6&(SYhB^9Y?$~kBMp|vIgd1luo)^!O6Y64` z7iN2x1RnECgAE&czNfb`kV(5wE&E6?s?15Ak*dUF3iao*U!TK=;-A2D?_Hx4P8sU5Jlifj1dpr)Wz8; z!x6LhzF*av035B#!M9F;LNiHmwk)x8GQRFE4|qzt0+!Rd_vGZ%cXOV2f@xgRHJ3aV znKT|o-E~7Z)2Z&ccuqr}H#10;v%MNc;j}XHO~5C?QK(g6$@^ugEEbP;I`K{|HS+ei z2@dT)LiR(SOYQ`BSA~GLh9u^$c1x#vekyLV`i7#!GI;p+qwd|WwZ{(g0U^K@`8|#d z1^u(Jk<=T|K6KvS0vk%DLmH?zE(?!;zI^m7&Lx z4*%C&Im=(JU+&ulKa*hh_7F*WaLOL*w-v$cUosLH{y9i|wWjhXgR>G;1klcz0n7t~ z=Xl%g!C>2u!wtS|^86xMD243S*SbvR&3*i{N%6l+8coB$p)R~CY*HuKW}Dro(Y(#y zmr<&5MQDVrl0ckTB^%0h9wAaHk%0&}uo%v*%8Jj>MYxhL2j9VjawLJ#-wKWbE6^#c zF)IQkQQCMU)k_P;hF<)hKhE920%$mizB4#jD#=#K8WIUh_ZMQl;lbHD_1^|ZVk=m0 z%Ij`;>mRQzMu%RRz?+c-#7Fr0U{&mpUCx9!Hw{TCPAt$2mhast>^@itTe{yS4+)_=8Z1Rq;(?AckIVFEK|h&D=fW+6)2-RW9>LI+xHxud$a+1Sd!<0GH^?7eSX8zbufr0BiTAF?#9D6Je*TuDCHagS6KxFMC@}eNj^r zoMZ*JBf_mglFKc>aIbhAg+z(9a*K*N2jN{65&@*M7A*sC%mR!LlvIfMwXHQ_^v6-Z z6>bs!k&UWQ^}*%pb_69I<_$?D;%8FJM9|yuQ={>(f94dOna*& zkJceiHnZ*5_>C3dl7VX;V2v^{S;3Poab4Nn_6$n)o3Wdtq?;=%x&@9~me}zTB{uJr zdmCT9uP2hlGVH_V@5_?Ana>qoDj6!#J5P$@ABW&k`A1gl_sjA9xb5_s@f|AS_9t=@ z*pXz5bAyd*gXdAPJ;i%}_2CmF94qFbr`RRT~eRxbkWe(B!#g#gm}^?daQcR8bLD))yC4 zKySL*=`H+frdO=S(c`Bp-wqmFQL-C*(s%oFhxkF<9G_vDwx9lVURLU1+xw-vAo9Za zmsjA9S289%BvtCfAR3|=OTEv{D#Ay`#uWo7VmNRz4TQoea*I4b8!`Cv%3Z8zLjAjq zsL|e2*RWJl4A~S7*?I6LNjqR#$G)pu(>uQv++oGMR)2m3S#9LodcGC=-Jyj4_a4)( zFI<}SKAdl>A%p$+t#^Z}2sehEX^e*dBnv}je%{2G7Tv`5tJTx=D+p&ZxCtGgTR~16 zNIDEvS(h`g!T-=mJj0!jG@nnC9P2vX70V5H@~hZP>(tbeU_;hH6^i>i)+}&4s#})` z3c->Hclav_rGOi8K{d-M^S!NROx=H0vfPx=uEkf%z{~VuVvf}Au6OQBZ&;gjIY)nu zPbO!3lcL|ltvttr-8;Rx#XYO%JI|?lci>=G7bn+)W#itf!OMpqC>ALK8iPh+0f#pe zwxI`|a02=?DLIx~3q-2QDs;ZmX^iYl>$ZgqJCYp1$P9^4BCp?Lop%2Eju2jY8yBvc zE;5SPuNqXMN()EyXTrOxddRPDWrv~yMZC}~Z5lxqx6h7rH@f^Eb95`+txxPktM|u~ zl!<`e7l?@~fx=Oad>|2%7}=sH(PHX%KxQ@PQ=^OXAFWvbcs8ZcZxe{vk^E2^+QdoM zAF;xXA{^r+@uW$s%7|Bq|YSQv3Idzs5KeaPvimBS(YJx zz4m75OEd#r`ttf0Xrh*N5jn`AR~)ZCG3vxWGGuzhk2_ACm&x8s6JuaxKt6(!V_pvy z_5{`^zp!rUyr0sGx;5wcutwmU-DR7(bSvyBP-tJ^sX)%`wYQcRR%ha0VR!K`VMuiG zJI_;yOWYGpwo5Ml&_!WY7+2<$6uiXx++CMLW}abxCuj{yY|8mgco~gR9ZpJ1I!ca? zpq#{9=`!%v>3~`$rqPH{q%kr2coyj}<{Mpnx2gwFMwTt3PGIY0hf*3r){v<*UW`eG z`)u|J@5*yt?jn_4Yjy0eiQabD28D5N3gP2BUFdX16Fb>o+KLYkp^81$_nW9Mxd_Z9 zI;BItCfnWFCI9WxF3%!zy~VVI6A03!lif6}n!LM%Ysw-4{UQ*|@GcmX~$;cR$a>hk?ow=tN6=w(SInT_zbf-^O9X9?4VwvbhOz zm~T)uL>B(qh{d6ZP8W;=qhCC&_;hr?)uZ3cn5xL3BRKKXpT>MQ>_KL;A}Vc&06E4v zn439*K_-D*YK{<>>yi6g6+Sde7M9YB03$Q8;O+VjL7=i^QR&r|5=sIO2UK~C=Y3H;9pc{TMoEfak^ z-ejthD}6an=x0w`jOwS2-w!X9&9Kf_!0L-6JjFw^zf0JV{$Ge&!PbujhR9}TfV z?!rvJaMm*3+Ml}DyJ(us8e5!L)`Y4FdL;+gf=rkE=WLeFd)AdEA0bBQywB@cNe+?5O9N)iY&Q^ z<7^(kN(5dWj@Cm@jrN-aZKPX+wqU&J`zw~we46;#g*Tl|)JoN9En5owKV~{(Q94fI}?^2>VqEXj#aIX2_ZIY3 zVjvj$r<2-pueLL}EA#5MNb?BlaW!UljOq#R?F3&|ab)_P6Kjc_p?n#u;%5tcMvHYNlddfXz=veP!)AD^zF>?z!69CY&KgF#7AJ zY20u9s$N!^akfL7UhcefIzp)2-e_>4bKjeME&ZN|iX41MVr}n!5?isMXalh%WOM0I zE0)AhCkl(m=1YG|#*vQZyW~>dM^DA)f}PL$kLu8rMhbdV1IcH1!lu|C1b@Dqct$pXu-!-OcN9Mox4k{fE|mBf#NZ-YBZTxH7g zM0wJYFo40+EHW!s_1{k3HQi0d@-k~yfkt&}dadHdQKY#=$b7eL2z*VP2Hefshb@Jm46rbSMJDlb3$ZIer7CWl# zCF5|-XPHo(qf>Zsh`!()2!Hi*u+2D+!lfp)s<@18q}G*cX98yeHL$Dm+`D=K%$!@ERo4)O3$c1Cb205P| zIDI#f@ln`3+)fef8mk-E`24!(mdS3Zq$UNSktkDn^be^N>*z!XDcvmrFmmL(B+t;q z*`=S*DCQ!E?M8jT|G%>p^Wm)0Ti_B=OPeSSGJr zFeI($Jw8!DkvP5Q;~skPlAXuzvlH6p?`SQZurBrPRO>Ej8S{(FY~V&xPGcQy|4E)Y zi3R84e=9&3N>W0^MJ=p*p4g|6TgjL3nRWU6y8T@aDBd&fE3&_?2u^Njd1`Z+c$kWK zhg_6>Zu5Tm;S#)a4=ymPqgdfE z_-p*_z+&z$q3ygD=>&2reJ}5%OZBpmL{mzR->56|0)L%4wO$o!snW#|QlIf@E}C^w zkG*t+>4r(Xq)bFuY)g1)%{vX%MXOA`uP<78oNOY3;}&-E@ZVXSIZ;eeM~Nfe7W(BD zD-j=3z)3V4-_SNSR>m|XKUH!Zr`G!}R2p$2$Rf$F(kG1tB@5nm`!JoWUO3 zKWIh&N~KzKC|{T$|DrMd5dw40S^#NY3dql~%|!#O%iN4YM47vpBh~^X7NTN^!*1UX z;~UD18fK~u8Tq;e@I^Bw%;Go}ouY9L7~wTa9{Pqq42)&ADN+U>!1250V~@=)eeHs`LvwVr+X%YCE9DQc5O zJ@G{(2Xi;=sQa@>ArYiSpfKb7|NrHr6HEP216^YZ)`-Wvb?JUeiULtqlW^a;RAE(% zDlKpc8@O*a`6#}*4lwo6_IXtvDyrpGPYLp=I9Kwr^LBr|W~n&rN+73zt^a~ptwP9n zB*5%Wf~d&wHV+I2RjuVp0%Be_k%7s#zCJZ4^56()kVeB3gm)(V=X8fA0;(UAa4dA) z$P++Re=&I@d@Z_~YzEEz>E_4eeb6SdvRkX<0d>ySu3FDu>@Dd7_D|(|d_-ObnRV`c zkYTY&+}{6ndBxZSxxF>K_7NoG82Vz71==ZB=%?kF1^JY^~gZeys7z43m z7&3S$W(dX2HNfU(<^h$3#UMU&wP;W;GYZ750M+2*POvtoDQ{_s9pI=_uQ_V-QfzPr zSyD^vbQ7f%j&Mj(n*Y)0COy(hDN^>L`XoUK3iCb9ABO1vdVV=S9|`R=t)Nw`OyqsR z1e#gn&-)ghrM7fp5k@^V{O1PYWWk>>n)&gj4;M$)8RwZ)uv1wSm3hbDhc28DkJs8= zi6o(Nk(IWljD$sSm}G{IzSvyN4GTDBKEJhlWdd}&VLd(QiTV5>|6i_w5eir=u5bur z{SxKfbobq?880|7)jFsR=bxdGZGad)4X7#3a)7 z-^oI%b_;*#J*eX5>N2QUi=H(B?kmqTCK{c`>X?|OWW^aMyJW791p>gMo+E~hKwU-`HSWDpenLvv}BI_$|<3H``6l_hKMqS-pjzsDwfW%gc`NBYbFFx-%U@!e=i7;~_^S^G-yzC5~;y^k`VLTDoBv|o@e zpj2({s-q84h_)sw*m8CC!L`9mVlUdu_@QZc)TXs}3qh-xh?Di#$}8nQmk|8oyXeGO zAeL3Rlb`6gE(9t{zAv45HBm!BQBz$E*CDq;_z3Qr<8C@aqpB3>D3B;89I_;wz$9P( zKR@a$qpvH08F<$jY>WKuc~t*W7dU3XFA684kxU^v5(TGY`vN1-{?yk%(nN9@Oo+H_ zq30vTS8Szk8P6aLl_6dMZN`+BQ@67l_xxThXh?LkG)zdw5-8u3K-RHOP`G|sWSZ1o z_Uv#|*!1?|(eDU-fkO&10-Ym`0zLx4n%H`PU7p^JLtccoFLYLWt61Os9OwJ9aT}s_$G}Gp;h1_kYE6izKe3E; zCmslyx+dMf_`{gh(y=apnQgY5zSYmt%lwL?&%IKb-#A#pNhv1agL6X|H|iM00<4)F zW~%=vUwpjzg*U{cyeG=va&Yuv3z$)_1KT@`D`pSk+e?`Sjg&4afG> zr=g2Kz-j!mdNrnjpPxutsb^i_kUINL3%bN@fY-x`O$H5NI-su6vBiiTt*JRQeDP8T&^!pcReujsHaONmk3npk=6=S ztHPjY{U~rZ@KcCIBW_`@q`J|stA=9Psk$LoqAbnd~M&0yh_5& z*rQ~QhHb5zv(bE=fH+~;N*0)Ii)iZ;E*u*59(vXVER>aUbhtbPiMjXFs+`d96YiQm zx^CS|Uy1+t6EjpWn@*$89F_8}^q};90o+T$XVA^Xi^=iKvVaLF##0tw86_%$W30Nf zIsXQJ-3Qc!sl5Jmkv(Tco%x?eKl;LOBPD3;g&r_fy7|!d|55c$!Ikvi8*e7IZQC{{ zb~3R!v9)8{w#~`J6Hjd0nmF09vrpdNId!W3U48Mr>8`$7z3@Dr)nNDmT+i6{qQ*np zsvfi#%s6Cv$v`>nJnwZ^BzGDh1$iR;sXxWHPA5FF5|{v)+Rmr<|Cpo*ZpfD*Q5FYg)cT+$SX+x%N9BZY^?no4@kS?9W=_)@Y>vEkor zo&J>-o{>THYw3{N3ZW(^KB+|gseW&he;3L9Oe(SULD|xe+l-KvCDtF2NZDUVK zJ@sPSW|TmQQEKNO%7&xyW=meWlz26f|9h1^O^+=b017D9in0@qH4=)=GGes`32l$Y zj5w@K-mT~@UgbTtnuLT$VKO8$PDDbExPX&jb55$r5M@fOG9tV`u9Qp zM*&n(DS1@xwus;CSjWj~jKe32zCFS6;mA~rKMFaye0*jFt>Zbzo7S<%3pe9nLal8#~RId%aD0u0d zx@3}S`+$gwsI+;=tdJFsjVbnxpd_5udJ#A4P@$FNI;OM?Iwf;VaSBPd8Fx63l?y4* z91)cDMt$fueu(_<@Qq-qc(#%YK%a?caL|h+4gdc?V;oKJKtd?zp?GTIQ?v}6a!CRG zNt$4Ot98Gz*3*IL4lp%o0=7myrK zxNg1?)D;cRA-))$5y~mSY=rGkH6Zx)9>1&j^0|Zz=?)@2$cMhHqW=4h%y!Bo2`qxW zl2ibQP{>c?ei7;giTXXssRw_e`N9RSNB|Eas~h3^NhE<{(DjQSfGg>U_mCBW8OK`@ zv(ASaleNUvf0yXd+sTRTcQ^S!s%!q?Xk8>@DGGGcA}tOv=B71 zN`2P!0Dg0OxU?_D8-03>%A)zA=hSlIV!aSwa&UAYFyY^ss*Q1 z_~}0kTnL!2H{N@FU5?b>GK@7C<14iDk9ft50YN6tp9B!U=A5n{XWrch9swfaJsrPF zLyLjbls994V?3EI9wM-WAe@_ZhCHlv2SzozHmX77A=)r|am~rv{ash9pf4SK$`?ot4SIv z)=E9vCpDJRo}o_Wy>;2C3y$4}2K4bvRCXiqhqXDygU{eL=6;FL(j7g$E~odHnRdQW zkH-7{r?PGCZg;Iwe!g}Xs`cE#=%%p{OR-QYm(8A?%_T5){Z#dKU2Un+4Of>+YM>cQ zD$5h1!l9c=6p|k|m!3mdQErlFcUNp0Vkr7ZU4 zM}}f!D(z#=tU3hC%Uf-WaNZhAI)%C*-8p=bI%9uOSeuX0Hs;Z2D(=s?As2tG<)@qU zI-Yl?cp~rjyGGTYcxBGjV6-~3bl`awTaBju%%F`@ty4Z>ewuxA$z4d@14wQ=yxOp= z{?2!iIN`a6{eq2f1j4ci*LZ`w=|s%JTXs@+#XU&BjcO_w?}uMS!7^eA&&7WaNr$s% z_@zL-p$}cxB0$xOe?||s4uWtfZ7K3-k~Mv_D}=kmRS7u<-YYLF^Dk5QWyN0}sb&?m zh_lr^>fmt$ZQFN45Y7h50uEXtE_qmhsjTL2AE`qDLXVl))7vwnZENmHcrKr5So!-5 z6TDGwsmdFu8@a)^_ooi!SfAKfB|&hBImUiA^0ClHP)zUeQTGmLwDEDXuN5d;1s1AX z|DF9Yqgk>{g18vi#Kp<=13YF!f}Jk#*3!gbsAJL~IVU(-8%L@`xW??idUaj-E}grGu&Z3F)`sHnzJ1DI%a>vJF%M7>Dz)nh9Zd(ie7q^-rJR39{0pdSc`6 zPwv1*1V;dxkYXkc2j&;YNsTH4H#s*^_fL%DQF;g!j`0Qrhue>f+EjP_+BU>Pg-3gp zNCo%EY%5by8e*LA(+dgWvJ9^O8S@{n?N0jbK@1dIBDE+8SsxzkpxgB8nKf5rkug}} zet@C4_v-SbatX!V9}9&aYE0mdL(xzSfSFaLjie?BbHEIWs zxnBLOw#LVJYIj(V+|2dDwY}z!t)f3s_AC!tfB#g1M%gx4;^V!II}g43WaNH*O3&|i zqf8>a0sa0vc(aW98gYae`CN(8f03yE8CF9&%-p zI|4PTHi--FD=^t^kv%I7SV3qf=5>s=|8#cN9erA&)3J@_7S7?eU!GK}(PWZuvQ#`z zWzX*ZDb4r}`^i>J{vg4~kwLcpG(ZcI1WurKF$D9l_RqPVx1he`&ZEGt=?F^z6VTql zf_oEougRbFV0$q7+bEt>V0(~~?w}yA17qJPOS|n+yNH89(eq5f0l~YSXoM{kJ<+=? zWY5@;0hs-B2hmRy&weNT3A+qv?;eo7c>OpO&vrkcUU5|I6C<%Ik{*tc%?0@>+G8gZ zhGFyLcIjY0G1&`dNqGj)x=4acc;-LiX9t|!dPtwYiu^l(Q1DLVt~}~y$gT%1$u`f$ zy`F7`CvixuH1m9cIvOET(scH2Wm%jkkQg>ToKzx&q0q+a+-3h{*heXs*G5Zxh=r39 zH}%Z~RO0c~pni}Hv09dJa$EbJ=b#d|I%#(9%Mu{y;&(<6NeE*3E5c3jEC*>6yt_it zj?hm8TTj8u+OGkrh58=Ndn4<-e}Lxu#ext6TFMsPL8PJZQ(PNG?pm?7O`!R*2BUlj zeuMS5=5zkh+dc?+9kwf^2#is5`qpm^S)uUkPJ`iZA-Nm@#!gJ3@Je!dElhohrnroO zDb2&Yk+Xa9I?p}*P?|ROIxncyl?7)w0jbQ1F zb-_(%PbSn;dmZy0;bBS(HS>S%fwS~N!0@(-o%EDZj`*lzAnrY{S(~N1Q}LpGnODk! zp8zt_#o)`+LZEmF`^s16AZkR-wJQ}jjaPlboSr?GWe z21e$74||dP;S#Zm6SN?ME2<72IT=AII*VjW5>1h0|2;Tx6YTTjF3A}$=GWr>TTLQ7 zc~5(KMY4DXKd%LJbL&^T>nJ=~v7h1-Dq(x)=ySRbO^&&HLykT5aN5)Rvcou);N-D` z;sM%|6Hj1xhYG7;a!sv9ju}b2>5R_4lEw8~#y)U`#j}{4F-VLpLZAa=}jtAYJPbk2LTz{y}nuM3Z2{Zot%R1oggIl=`$o-vZZB2QYhU@Y5yv3w5sO$3Y<>$1&zPvwf^z-i@9_&u8Gl_e z!ZY}^MM{i?QvuEzf-|`{n6Nopgf>&0rmQV)E7Er$rkV?nF#c$m&5@bTZO(UT6)D6r zHUP2sd43g&*Hk8MWIYr<37&k&NvgYzViW0c2lBvgpl$8A@T`LY; z&HrYS@}N#IpYxN7Ukvo8-}kYgCUO+F8bz_~#eNitz%ptn361xYE z1fymp4bt)QRV0(;0I#j~A3qnVtD~ZmL;F+qYmLPad0+{2g{MbB86aTiZvMoj zs-#Ue4pzQ;v{HMG$uW2%j3($2h2Va7wwHL&mQZjA*d?08DI1B1!&CHmdHwGDsYv2D z1IJRBdNCdekNRE1#JaG=Gi#YWZ>HiS#=nF4vdNt~#|u(+)MoC(m>$j6{9DbD2xxKV z$)oo(XSf}C-zwSidy=_V5?rUJ0vC3?aOO9e-`Wte`wTukuNZ%XgqG;QJInCKuI>-N zEeYWA-UhynfzCu;E;mcEXzY{hIV(}J)m#-yKx@xf3Z7JMwI~)6U>$$WEmo6R@Z?oV#6nMF=Hb|hW>Ew%Jv zDoJ{p1;|j`!PNCSW3IZ*Q1eZLd{Q}jtAnF^<|m_L9WBb}EG}leHa0rLfhl{qU4P0g zA9y;?`Ydk+m)&ctR|E*ck?pCY0a92?BHghs>xtJ4)dfxuR=8%uNE12<(fOdXveo5! zGHdq`H;k_G@qwrsA^J8WjE}GONv_Ww|NrJ$Ht@aT4;Tzm4s{w0hrJv)a^{d+oTutX{{^F)T5kK=+VOWk zj0eR<9@U-ya}X*x%W+W4Uway(KFS$F7iWG#5I{;;p0NvP|1ueC0-vJZ(O)zw-e8=GajKdEJmjs>1mm&(dq2{C5;;*s2P1g02Gt9G3oMjh>%q95U zzg*>OnfEEZqK$z@T$Zm#g7PL{i_JZ;4f?j)PQ1In<^n#WytQOT8;{!O!gL#Tp=X!*4pV|tJjZ40knpGY)RQ3Xwc*;cw zz{HcX9`9XiQ0)wg`1;PjGnGPhCebQ%I!Y9RUpah;ugRpdS&X!1ZE%KX3;Ot()3=gU zZUHyTk}rN?FpFS?P?2F$Q4AvZx%wFwU6**!d1h*NMJ`==_WcGyvZSv*;(_21v<*A6 z>M9!zH%uluA|OBo!Lh9fPIBGQEx?7vJOJ1e?EYR#@Q-znPj-636;uCe+*80}1gv7k z!09a9yUM6;Oi7GFi6b2Hkacs^k-PoVu*Aj+5`b%o;q56r$9B)>yAu@Z(u1d?sB%5a z6fSV#9==wnBxTh@kaUYr@lu!+r=?4g5%UO?$P8*DBSU!Pj?E`YMTw`$?CtN*hFVw9 z_T1_$*~|J`$Y(i!L`;eUr}jsQom?zMw5Xxx&c+ouJgaNZ8pg;4=xL5kOL*#3P20>W zF~wBRfzs`^*)a?db1Ow3{g~*%>QFTWF_~atoK7^wBp5+Rk(x`c;6=|q*6A}$=kCjf@b%aqrdcAP<+`2{JA7?P1R*$^$7XB zZ+V?1Cb^Xzg8?#mYC$H<{R=s~71({DpJbu&6E=woEWyyj@Y(ePmAm69d2~1r{kENy z^{u-vg@u?|*qcacqfEl5DRp$B7Fi}NjiftZSn2gc0pZ^~pM0JT4Qm?;Dh&6P{cJ1J zUobfYG?#o%1WYf=urw}RRY2O;8ii;WWUQ?eczaP1GCJh5mcgY`v%qsc>*o@|(!Um8 ztLIrF;ici&>(mcDcNAaiq?=aM$Gxcvn5K`P4KL82pBI$)vO=YMqkVMHOo#YLlaA{brj@e->6t68y z%WnOFfk%FrZ6Mm>f)B#l>N`(z-=*aZX~Gmk1vl0X)}+!PJIsLY>O8G}YMN8h6)3mk z#?C2|-Yt{hQ4rAE9J^4{Wh23PRctc{e*_uV;zJLPdtY$H+QI8m3>X*k4w^lb2GS*7{2 zHljZWJOicf*o6=ORYn>!e0XaW(8Je1w?0Et&t|8cxY)1cOV;n2Cs1S zHz@-7o%ivE%*3GVa6Ge5d<%7WUjT^3C;2FW;=l1}Mx&`&@KXLXa(=jroiM`42l(#t zop&MOjH~d+IGF*w5Q*HORepZ+H2NuK)TYObtCa{7-_>co{a>H@#8PU3(pE;-u#Y3e zFvuU}v;Dq_r`QO0riy)LHkvdU%mP}P&EwecTSU`&w8K`hW$hhiRaL1{m7F$ikB&B8 zhvzPu$zh__=H*|UTp9LgYA{1}STHZ$%{Qwi`yD@>ndRnS^T_dVJi42u5z7wF*~U4) zww8Q&Ce1ybd0QwYS@%)mgw$h?qi=0(qNXo@lO&ew9-YV9&D{TmMr5kXH?1?A*O4-B{qK;yG3l`89H6bTXs(zBGXHWrtLgedkIj zRjbLzDV5c}s0ABJikt81AWkoWX`meS0hx0T59P4$$_ue`r`hy}&DTy$K>IyqbY>ZC7?gfF~jxlDsM zfgWuK68r>G76Y+{?dRXT9{!67C6U&i*5~rnLtJ%2w%xc1Gw{Vkb#;GvYXiA|1KJ-*l6>$t&YD6y(2&Q)xJCm%Ik$%bv)~^lFcRx zd;*0oi$Zyr_=1Utaf3k6-clU~9Udq^M5k(IBrC}z(4gjR%b{ai1v5j5u7M`+j)#%` zk*@>8Pe9bx6=W`v*>0Ym*HQKd&^~ms40{bypD}wy2?IdpB+7IBy#aH8LGf* zoNDzCp}*m8-XBY@3Aw7No=;Lq;Z2QKU2WMgZ1{Ld3^j{J?391r%`VM$SU^c_Gzvr? zYN4?r$^ughqhAqfkcAiawWRYLWY%cdr0?gkv5^wYobL<0F+KO#b_)NfY z+F5ES6ssj^av_J&Tu^@46d|6e)k!ba$!7i&m}KGwZ?T*}Afoo`JcyXI;Ix)nK2hh5 z+)i&6oGR!`5#c$fLH44w^yT0t@wLk+dl^aLnDYtp7>+tHt~k07k4m$b+I@Z$L-Bj} zSTu0UF5}FngiKp;Ta3o4S%bmmqX6Cy38)d_v_xwbN@0)}V&<8GIZIhQ8adzXQRk4* zZVP4uEbcjTG4+F#+8##VUeZo_kP!!9;h9qCi^5;{75b91Xq=2HVh;$8|B(jES#5{b z-$o;T&z=kW*=yVS`KFcMQe2utZ~(TSk@4PV>t{HL`+!$FLDDMYzV}0s+S(ANbo|4^ zXZz%lV7rFvh!M?94GP2E9j2zt61;x<1U@agt3Yk)6=7c1f4Av4zO3y<5IVsyTMbT) zBCwDC$M=M75EYG?*T9A7JXF^CIb*C-jyfF=mE<0-=8B9V_8u~e?spQ#H#*qZ50{7R zF`j)E_ClR6s-UVdZ14djwt)-|04Gn@^Y~$i5#tX0JgflQ!43>5%7{vOpFX>GELZf7 ze#}+Uw)!m~i=fA^asWoBjojTRY!cv=HsNoE(Nbk+6&Suky_u6%$h=0o%79~sP<{$M zb%d{#gv+y{U7u?jW5wr(w1>43TL*I@I=AGcw*E6W>sJMoeT&ZU7B7${#l;xB^mbz+svFC*p<5+Rj z58vB3l}VqWE3rO@%t6!134hrzqu5F#jsK#+bFzn4vTuY({*ccLcx5jk3ed+|gweWy z`v`a~G8TKPL;9ljdIn=ve8fU{ z#a>~T1b7hK?FP{Rx$&77&6i~$n@<@S;E6+P~QC;TxTM~os7B{H8au~RD)Ul zKhn-=kY2{49lChxcP#|Qe$(!r3$)H;j*u=8VX1B|OQuuf!Lzb|xp{w|e_W^Ex^6m_ zqNFt<$AD`oyqwN(f@KT{Kl^b(!NyW2B1+s|;3ya5Z~Bww_=-VVf7*$vBW^dxJ}{g! zyVnwA$ABkz{3+d@By!>t9E_;BL;QK+ALjzGCG6Ry?tyb}ot>SevAX%%$@aOZlbj2Z z%&#z8N7-qsSVHvZWE_5C=97P@v5L4HG3{~$sNiw!Wml68!?)7sdw!d|vzvUc*6Y8k zmxo$N!$UoeqB;b}XuPzO$Y}chq%kz}()6P@dOIQ7eH)FdbaRkjP3T3VcDJGQmD)Gh z20GXAT(|2*2ZJ&>5OR?hK%?1_tT;-hdi3WGYV!UbGS^6D&PCciqY2%~p+4j|S~xfG zY;2`kpftDQ;KISxzd1!7SOS>~I;~w3q4B6vSuHZxQjfS7|xtu z4#xY_e#YDYBq%{+)Yk*f{%|P)wFep+cYg@Nna68HR`&^aqJx#yZNv5T*WSk_1FW6! z?i5?U6w~t+$un~vR41?RxGRJ0RKrdDCnRvZy~_!ZJF@?u2D9*0LiQx&9OAUo<_XZs zbAQ;*W5dd%W8nq%T^v(`>hiC{X+YdFDZ#oN$7^bX($R;ordPeE9Vn+eV!}~5H-dk7 zkXEqdWq-eajWGtIYNFS{8-xNRy$MO*XIuIqi?7}>l*L9X*Ju6uqdp1u(Ub+7mio_=VZ zw{IcGcXRh{u)=Md3g5J9gD{P&8cLMl$W-lmwbiTqn2d7=FW6I8~{ z;IW~RHY@Ks6k*q747oHbJt^-!c)Uj@XKv6Y?ysxgRv(5Tdpgu%sgM-B6YMi{{8QuA z$OBDVcH?J&g%Fi_MsxmZW1cR>L}Irf=wwsNgt@|7L!T@E{!2-uIQE)d{&V-kJSdmFBf zs80STpS74u8SJWA^;fw630_^ncUBK};xw^zo5Q!~ZCf>JPA1R=-4 zpOk=}lF5wuJiqUA#3;j??iV9Dm6{Hw1YK$2T`l>U?G@mqzV>ZfMmHe-UO-8|+ zgJ(|Z-cdaYC*G^Srl;d#<$H1cc{VvmsSKRek55L*7Gq#CISKN8eSm90E#E5Xe5p(# zrMxpDof9EdvK6Xzh8VQSBQj>D;K3Np;5Yj+3>|$_>Q)G#a@{m(z7R9?}{IXc;fxOnoM}|7dt7x z)_VlZuXg1Kdf-9{)iNnRFWh#bDQL}=1IDin)@4ym)9Z^foE>mHK55o)rJtRKO<~)n zYg!h644!uuOS{@y1aoV>NRW8^)xa1Q;40k66FonlCaMB$3U54YTxgClnI5vS-abi6 zl{y8!_YQk)Pnm$LUy^T z$HOUEpoNLZc>MMp7o7nfL^R;d>5 zpLg!*MRpprHhf`xup3uVXm~aj>CN2G?e2OOwTEJ#z^9B}+l&&FO+dsA1XTfi;gImC zynW8&5}q^pi~D&A1I$dyBehS7Tl$fap};#|itbfo4B((%P!h3(0t*Byccv!wt(2Z^ zW%gU8b2F5bxsv$$+!nsh;bd!gPg@^;9w=wZG$#t4jU+{6df;B4AcAu875>^WJ?`~y zjNsM4Jp{bH%?U3kBN_Ml&bq5WL0Dv1h;2J*WFwqbrvVq`ig!lAPQx9%ZG>;$XjyI= zXL{!M^aPXhJl}f&)*%TrgpTd5gni>th=0UC0$ZV3Urm$s7$20f~E)4z|~?Lu_NQlX|-!s=3hrKW=- zOG7!tMT0aesMj9pfxRK&Vl8uPFjR_mjJtmh;e&lVYK6UjVLWO8kjZh_`PWQw+cD~P zz}tD5Whk^EOA@t_{DF?m{SxUy=JR#f`=K!IP-W1^UN-qyC+{a`mIbozAmwJe64 zczj;!$e(jrP|MPapqKlzcK~)I;~ZXChMV5G1eN5P-j;Jt)0;IfoN>Q50k+(zF3!$< zb%A#Emph=}Fk&Ms;!S#*1&<=PmcuQylby}AT7ov-2jy{P3mUB}hcLSs%mU`wpcbrm zBKGD(zD5TZPv0-w^d2L}!f5wE)u{B|Flwi!#4G6Q#*xgf$o$p)r$`x!BR>Tbz<-VK zesdWsno}!s!QwfyC(&W8=CA3Zx~8_v7~n z4^_n#@&+_aDx2E+h&+n5L*)VU4{PHY=--l_Fm5{ySUuh9ufyNPRwNaf*3~SQs2uZj zeJ192*!6}hee!KpOhF=qUbk-)1-^o4x?k(*9!F)OQ^MP&+c{bP!$2iVr{z&Ra2eEh z++Q^cs4)*R&GU?CvEBPcmRJMsKrQwU#F+y@EZlXtT=jm7)&ukG6e@_uf$+1|970S` z9QMKpks0|{ua}a)U_3$-yqM)-`)d>2*D2ZpQ)YHJhR=TYT|&J8sS|R+xwD+d0M98EIHK=~O6b&`+WT#!zis z8Y^yl;F>*=D?$HqfU8EtpGrDu)NqP(oN?rR)DvBMB>Cg==Rd^ee@cqk#CqA_og1tv zy|zc0Hu>W4KFt3;;(3fEB?NTc-e0}Y7u|*`+y*m_F8thdy(BvAXfb(=+lGs-(h5NP zQ3id9SZ=`oy*%a`{Jw;#(m^&6?V6z|IvL41{ij>738a*{m6xzP(5PpIJ6B0Q80z|+ z>iIk+UY3j({z+G2BX0UseM@|3Dak!vUZD@QK`B8-TLt@HUzL1Y@QF6Tb__ zvLI>3P0nNga|!i7rbovZGIvBX@Y&It51iutBWsD?g)zeXcp@! z$@w9?rB;@+u=KZV)mDO2a>~32wr7uoM#IKs7LIA}9KWBM^)0a<-mTjW*5mskLDvx| zUN`rY?fr{%zcCM-kHDiSvBELoqSN7kcZvC}6+aD9kje@QSRo!l#=!nw`&W}!+>6^D z9flwzn6~61GuFK+=;{N*#W{>df>#RFMdo>FH+uuH&sz1%+!F${`^Zrrn+r1}l%#$}*ZJpUYDZBcwGjX=BY*og_?6RY+0T zg4+&VIV}q(#glpE>^s zhKk#vB`?olZ%$WxLd4Q`I=GTwC49rWoC)3Vu4RNd^AqU>G##mSA~U6d@9#VQdhK<} ze+9UdwA7kvB!W49pk4lv|2{4si|(j3DCtl@H-3$gB1IKE^LGc}3Xi~_nvB{=SFv5e zwB~%{K~_>M2fi%BF2w&X8CuCDXb&jZ+xnctQDIu<(O=+5Sc9;yD$sk6yLT72X}!|rbKgDutG(_9S5a*2{Q7q(GRq_cpPNTYK}1`$5$X|Xss@TV zvl-t%Ip&=oV;{`+eE;M(dvFJLUC4(m7nZJ=c3O5!Um0Qx^3dgcl%U~RAhOch*Xw+j zlVO%YC$`5luFV?U9tFZ?Yxl1~qa!?=6V-uK8d-&S_s`VCdL9^0Q5%ZABp0zlJ~&je zsFcwZKf=YPJQn1Hyr(v6h`Sc_Xt3h9r=3cq$1%mm$cw<@x;)l0^{#y{W){~~H7)2W z{*`qFiiFzkU8(ii-ZrI>S&9tAFrVr_J^9 zkYb|Gwx&^$hEvCvjKFK3yv2?8Y(RCis$a=aj&<5^ZN+52+15KI;y$%MIjbwDf-GJP zm9zvlHM$ubA`wee<+8Ugk;NF&wZs7?c7MHvJ|N00bxPMCy$8$Mv(hq3EY}^KJr6V}d0y}$t+aPzY zdyl+3_H=oFx1sR+zJ5jv;jWtctt`kjq`GS(9o>CiPWJ07EKML;OnC*}&T%6u`{K2W z4>0F!T~EeXVjsX0oV?FSic@Wi@`p`i28d(~IZr&BulniXlgD{y;6|T!<6rl@+(m)k zh$4PNzh6c66Yx4nEz9}hE!ko*_3Owh{vLqPM`2*<_p%MGpf)#{T#n;c`=sy;FV2e~ z^3D!>N4|lT`mS4Bv7q)zaG<`8!O!bZd2{U`^r71T_GgGz^h8-t9nm!Kn8Xw{WCCrb zkf8S1?X`_<+%=YkvHuPAuq1b^|4o%YJVD}xdyxU;63Vh+i#&tV6PQGT&iY3FXJ$X1 zqXzF{LFx)_?y+$88%9P$^$po6tcdE4C|1zbiZk>BrKFA$U`0`*Xu;XyqF@LN#rc-e zVe^Ys9l_vNuz}XHxiI#TQ^vODB|eyA)KxprJ`&kgt5*5=LfUFI+-;Mh*Yv6V!%aW4 zm@hloLTAw{KAq+#BJYmV-v{eODqtas{g*xG!bfarZp^#qpt*9$0dK?k3AyZ;rwup(6;sT zooixjV-ON1o12pYS*Tg%+@EJ)S`)!@?m~9Jx35{d2Kn0dFpNB8JnA+z6!04oF@x4# zy^!&A*$xSrDl*j`oZ7xN$H%+Ak>-$wqKfI&Pg#^%p9K{~)yR2Q2FM-5I<53Xhj2Z) zJ&|c8jY9x$#~9z;{Wa1o;z`ZZQ%^j7lFw(5-($D14Wh5eR0?TM!h*8B`fxiUBSFkWd4yiT{Brv(mG(9CS=K%;IO z-6a!uJeGIV3|UZq&mWfwWoF&rHx#FsD?o+jNx4?CT$7;ZR-e>X+x>)Mppid1PL^Co zD;2i7qo=$74Ur>pG-jgVvUa!`UX&Roew>|)FqLog^5RDKO^rv5zsLe|e^lf@uMPm; zHyj0?XHV_>*|xeO1*ep^5^SE&^ksUrV_aQwSV?TGH1)aZsn$?s30wS=&+}n};D;yO zqAi4MwIuO`k-Z=JeXq^97oVTgJGF{hVQkwhmPvuMuHX<}I_ir>4>`TUp7$@jmFFkA zQWvZ_;q6Bach|pb|Gphi$fnakB_9By_vpSoAm2AkYsU3yvQ2(`yc_rldvRv_Ja96o zR+mPBQ^7fQIOKw)a|})sk?=Hz%UG*(cck_FEiz(wPVx3WKU+kqvy9@J;lJk>Y8awZ zLPeg?pG3<_9N$`c;@m8;NUzNF6(L9@Vh+qg%BoUM-O;vo)%Y~|SMt|~>utsz`&{`8 zBgG^lPTe7jIWtbplgrOrVeS9!Beg$?D2dec{3m2k0N%zq5JTx7+FX?a%~zL98NBSsGuG20 zPX5J*mbbZpT9P?d)IV(yN%fddJF$bk?Un3t+i*Z`%##PrETc3BXFn>UbTqk~a6Uk} z0ek??>I!fLE$!jILD(QLTJ#kdU9b&}U7{&)Kh=2;#{z_V=!Zswt3PF2tFR+(_VLb@ z@D18)hBrqWMfu=HIqO^?v4lCZhDed>cs4$SdjVLkf*j4;=onM*p`$UWu#j+zpSQ{} zKmPva86n8Ue{#=#JFUw}U1RwRrM#Pl0|u5=j2o1Ox0L3283NkyZ|a~^15V+bhJVvV znLP0433jls^K65i_62wq>1Z)RWZW#=NFR=3(PbQCKKcJCMm^CFC2>kF56DOCDs+z>wjS2m-gm z2wbQh{r=&NM2+5CJ|cwHWL1rMf=v*-`aTFGhfFrD#0kM2B!y$}5yVVwWa-v?9^gj&zaS2z5qr6sb4^I588(~IrwgV8d=(eCW;)@BQLLKEpbGAA za~%aJhlJxX4BH)M{!f#6;$0#hy4iFwG&1Ra^%FIe0Oe0Y48u89^f=Bn2}z;!zz zLGm%Yj167|FHHqAU0U`W;t$rXqU9!LoqO-wX<*#IK|LH*9aU8*{ZU74^!Hzs6xChB zNt${}`F{QVMPqed@)cVEN|4WDQr(UOTRm zPjnd%%e}KPTdNGdJ+(?U(KKdx0(l()H?HzU-LuQDMY&LtYRkSE18}bbm}A0!9hY2o z$_1_hMjtXy+vNC{h+LA|`AgijG{AX(xCsoWrNA(-h(gx>tX@yloc`2kd1+wujjvm& zUW=~|ANlHPZ@xrp#^vMUN8w)fYD z?5l+Sdlua`AItAoVK2kb*Ewi{3``=qkuY* zL;%l7I_Na9jFBJg-LW;rZ$U5U86=&5-7O@9D7nbq;?|nC4L)Sn|M0c-tG`)z<72j_ zme&0~gak2nk8yxh`O%1ZHaA%VjoR#xa<`fbu%17zL-NR5$4>y(MeRHdop0UCd+&j+ zz^ zjr1P5h?G^#>*%V*|F7wF#4O1vqdYAA zF>9!?J3lotRPuVsuQsB?Kz%L$8g&j5{+-Kz&)+h<()Nq>S}RLmnKe6@Od)y6F%yEHtsdR2}vz*pT z@Ge*xQ%M3{tSFTsR28WZ`h9DFZ|61sb#z#N@P=O0LO$-4=QrQYk$d(pgHG6nODZFahO%0x*;%J#9teTkA+ zBDMiMUBuqm1%mNa^rlmYr+KqNr*(j@@i!^V@5z?hLHkhQuyBk{QVI8O#2%7KFA-{zLElIO7ftG|EYjhUPDnY_V@fee8l`twIP0SQv| z`;=yoq{mf>=;xpOpeKhs_G9tvb&kx3Gq)`Yv@g z*fnOk;&H27>ZsiNzC;`z45U_?z8jxU4A-(*lBUzZjUT8h=QA|qozgUt(G-|TSl{C$ zw@PBX<;>1`uRagniB8qSP3aJrSiwio5rEQ4V$_zz3F#R>;mV@=KMKaK0^Cn43 zGK;7yCD$ua*jK3JsxN%hSb8#bvZzX(Ea$lTNVrP*to@eO0odadj#cvZmiwB=(;YPB zn$<-scs9>17G@x838Xu>>(WcfTBoM>4E1*IcvVhUiaB(lj^7H(t3yg8#g4*Kj?*u5 z!PugT*YF-{fGY9OGSN_-W=xYa}9U+I>&$54NnhbAJ{wNwVQhU*JZgG=ke zTXaI6_UMnS=+~_F{L;hK$-ATP!CMywufSo{XKM0@K%_a}YDLmwDg&yj*Bffip3oov z!*JU_ltVA}hcaM8eeOEV-Oq^mjR9{1yoU0}J(V}+PT`;1uFk0l`zt~thL~ZEGWsOZ&0hmA~Sr?{|^BCKm)&)nDmnV#U@?Lc(7(5y;E0}4$_}LJ1vlEF9nPZ zHth>m7eY(gH|_{efoJJ0>Xsf%5tr%@ni}-{ffIp-4Mujr*2sHaz5ea(0%`lEmWYxO zY;F_80`=XN!TGLwkim!bt*cdGAmwHU8f0G=+^}Ki0`>YZB(tR++T`HgK>GWHKzc$C z26mGaD32~9CzyonJaeW7$}>72?$$Os4zm`Le<#WV~J-MtL_ zcnmT)`oPZB z^Iz*9PDj4Soz9Z_d>+C0?-`EdJ66(;aAI2^-FPH;Z@`_loOe$-Dy8OrtQ$?5h)}Zt z-8O)sti6B+oKBz)aHs`#&@b2KvPpK^WZ=xVs{TiR?n>|ax|EQN4q83^kW133!yJ8* z^7NKKW9?r0^9C3(q$PYFr4>pYgXcdb1gGne=Vr|NDEnF+dH-o-k#<4KNkQKK3B%{% zq_K()gjUtwzu4u);Nn8@DY(V+W!l2I;~s#FWtf0$TCSCrNQws{&xjnzOu1?6g1+aH zp-p~wJ$+M8YwH$x-|0v)K;M8LsvV3ws=kptr5n3{r$=eqtaE%ofBqJNY^xHC`V{B6 zYkSLU9)A^{?3XaObvl6^Ncq6(R20B4gs4)2!dq34?{Yc{(Q9{&kQ6<5NAJ0{Mrb^` zOp=P8C3x(IRy-}7gj`k$`v!f~ZMim=mEuIy%=UyiI1TN7qNf(9(e3EpaHnh?&d`jb ztg6$Imj~1VAV&ty{J%%-`u+5q1xfdoQgcw+gZ{F9cd5#)==N1L$u&MoNjAQUjDrOu zw-{*x6aORgcB$~Sn7*WVTy;m2)OIM*?+@KFimr=OiY$v9%W1qSOdZ#CI(uMLYTYPT zuH_Q1K=ggQX>T>pb6HD<|B~1e(OCptnhsoN5_k&GtW0t=9k|Yf-kp91Gwv2sx+ib- z7q8Xa#_7K-GGQbIil?mo?Y(nsE*EfGL5|HexInhs^0R?@AqZ)o0?DbqIwrZ=fa{MX zLvd}Op7ziMGH7|%Umu3v$(4(5u=sS(w)uaynKB!yYj%cex^ftvDQPC%!|ss%R*S3K z-F!ABCn4!o$cbEGOLqUkOUsw{FK6}LEWrizxXfIXCST(3V-SPO3Gn_>s(Uh1M_u)| z6H0I;?nCSDQuMo_oOKw;k#b!&WmsX3?69K}Tz}*qbovd^Hz|0Juj#3^yYGoJts5g^ zZ;()_D&z%Thn8i{ns0YZ{PC8D4%T0@q(%{!-7In%%5By5eDLSQ$2U77U&a+kN+B4D zss3_1+WD<}R!Y^He^J=%qbBw-^ zg4FPI9c8_js=b%XxL&OG<6!D_RkJ^6yIk?5Yjx{4g3N5z7&ROc8>jQ6f%Bbg|$}LiyguGmwov zqxP>o)^asuukHxTUXcP%(0~?rO#^cmZ+ra7Gx^m})up3Va9Vag`x;MYX@9Qy_WJrS zB~MCRPDue)r$|WzK@be!NcG0N?M-;UcCffvmo zdBT4g)Rs5QHr8fGdC|ps!4rn#P_(V*l|7$*ZSBw?lGcu(6$X$jApliDRdu5#;EHbV zS@r7AGf!Dy^LJXp&9%&Onn;L1Wr22RO!fI6$IUX0s9>dLwJ^A7if}YlUT9E8W$VR; z%F>iobiW%Qc`5|gs>XO1i;*5#&&e_ekAKnioq^rmXit}3 z!l~Uw4$LNn7nLcN(L_e&RRvu5O|?0J;%eai;lw}v1|~vJHLvLDp5)*Z{{EuAHlK@f zjlP(KYc}h7pIiTL_c={M$-UlcwJE{D_a(zR3d8%N%9M~761 zcJCwDv-0WSAK;#}>gn(#;Zld`ia}LZR`&9Y9{2F$bGK!N(wmar3@HEvj#fkl@F<~a zjU}c7Ji8BFOQk;)!5J*ca~#R@JVBET!JvLHHtP5~0#n5RPxTk>X*bIUkK0y-uDFuU z=_En}gd&N&q6j9YnzhUQy-h=^_{?2putmoilc!&UaDO2z2}u*yez`818fJI6@~xVrxbnYW|MvOi zGgUL}_76V zNYC=a2TjYzK?D6!I6j=EMe8udkq5GJC3|7ME#GQWL9WZD*?=>Dpp*mD!;_c2SJK%q zF4U@})Tni{=kr^e4}GTt9QNyk_{Jl91#S-O)Xt752 z?0hSISn61~17xIx)28`tsvLPe9R;~A;LJZgCJX^-S4=F;ufFX->%u72cU%9ATe zaRaC1+9=T~qC}9I#;63!le@4*kM(TZd;7}`hG4~AhG1!e7Z{!-Xps{+RNT$FC9s^j z<>RVwc!oE9n}|PRaPy302=wMzlbYd0&*HM3p02%D&p*1VR;XkYB-Rpan@;=c|58Fj zu(w`hu@*lYF3((I=BBgDAb)`IG9S2&0%THUI9XO0{x|!$-M8+#Bd$&*;Y(X{<$RAf zFevccytZ@mj5H|FZH+9@(Ilm6lEP7fq%8aUr)v)9^i76?u@I+<)NKQ6B~-0NX)#Uk z45!8%KXFfFEe^|3iXy2h%SkM%#Tk-mE>)cqJY)K|@Ac5n&>;AvIgD0}l>kYwBw$&B zzF-i%wg0!RJx%UThpLplb)rj6rttYi=3sO{&n){OoytP;sBdaC-`9YxG0OKUXTB$r z?_rQf1nwd{fPmWOb}eQ8dL-W&$zNAA7ZW{}+t%(~=L@4XwX066z*%!77jOm~I9SI5 z*OXE6|4PzC2)dFeB$6JUCKh_kUw8kw@A770v>ipLsR;rh&;rLYV$lWY%!%8UP;1x3 z#Un)~W2!Qh*a9P6d@gRjz4PS8c*SRE3{#>(^3KseY}sH=D5Wmbh%VplktaU2Eqz1e&~5|(vdqeoBFKF5 zl1(j#{@AvNMBJl0+pwmWk4TzL_jt~8@7>&UNHl?d0nm7f&;&u`LjwH@n3@EGmIzV4 zS5|0rk;=vChT}~$Jj@sQJF=dERC-nj2b9BeR%bzOPrFU}R;r_QnUDad74kmcAvgSS zJW+Xl0Ybc(;o0B6;kB>526f8QO13#ivgNw>PM!SE$5*AGF1Ah>G!*x|v`pR%Pu@yb z;@eCTf`B3n>%IHJIbl18%%K@$YmWKgs2pS;_rdh3fM=9TvQ z_%haWsm*DMw~cw8`IBtJx zq?=qEBT^zw@(L-+=uNJ_8uJ$__~n*@z&gdsVUKy5P2GCckq&SN+!RLN&vAj!CIMGc z105>Znz_t-V%Qfc9T7T&LYKdS(~5?ny#gb8S~r+DjTlZO?hnp?S4v3>eINII!pw_< zg1GvJ#9to1C(7H-c^k_nDsu&;dw(*rjmKBe{MyU-9G!Qgata$&E?(L%5&qbtoUao# zE2sXY7kLk=lU}~>CpWq{?fmW{9i_nge0{Dm{incXfLCShZ?xAzrQkbNMxK?wr9D#G#z!#e8)v5h-iHK2NOuoF(xSa3fPiCI<^r|tfdwdo?nkB)Ll*qC?OOp&mQ>bW}yeUxNyxO=?U+kII zeVCllr7fcO4mEKW1Zz*bBNvqP4;JpuZ?x*9;x;_(G1H?nUcIkDsDNAIU{oRqj$$N& zRiwnvM&F;YW=Rd4Jt@AbXFQH~dOx(Y89eKn8`|9*nx!w?56vCh-{t~N$v#rD7l8an zH$0lUwn(ma?=%RFS8-mRJyUsy9oSTO>n@QT8bG6345K3~=>sh7pw&Nhl3 z!5e&EUbtB0;%#=9d(7^Q{l{Df@dX!)+~MpkDcM#<&}52X1)3qHjyHkRks^_Q_ig0g zanB9epPcf&k0(bfJTv%v3pRcN@oieTlS`WASdOG=g;p5cKDN*toSIDG^L>#+O4P#) zdMMY{U@0~XGw&s#zCj+H%Gw6`s|@lr4D!_t@~H;-Vp6fvQ}Bd!kaVbeC<~%0R*Io7 zcu-<9zy1BEO?5)b`A|<&>ILV^uRML;bNKJiH(6IgYpv`s^q3@A>qMu`1%`u3u09|a zI3*WQhZW{36F=Fz_4|y&)!+%lI=$ed=87e?&wFeSymrT_DNya67hdhI0Zmo~lA&+k({i(CCWWTLv`g=a-0ML=pKuc&nOr{7zD>xM(snj;li z8(m!K8LbcIalhl>6Kln^2Q3G`(l>iPdFIIRKVK$8S2`lHkb-q!f!!|2b}+(k!Ip2; zY{0Jekn%xC8%_QD@4tf{Ts=6U=pv|oIC&a0IIebmQh9 zZSYO|Ar56@r(qldPb;IN;Ap?wol>^)(eH4Bwbe8A_S6qE)rbbvK%@v&q^A@r@NV4^&KSjX^meAvOfDd5A%!1BLLu5ZWSX3}SF4(Ypi;{WJQ#taLNs zG8vZ`#2^MSJ}w3^s0=99V6D4$e`~sbk=co!25Bq_R@OL{AT&`FaT?1X&B3Y36h7Y< z(O9AyNL1m1DoTpK{m3)nubIDoeZ0N?OI~P5W&e4l!Vy4X1Vtu5z|tYVgxl{scTBFg z=6uVvkwx7PEMRz2dyih-B1G|;q}TO~{ybf8=E|jkfjy=FUTsw1pHK8g4%an>&?LjX zIq>}B8i4|!QB4#5BK0!8oQXPJf#!{e_4H=lrN~VE0q*tZ@MJMr|86NlHV^CeqtMaNaJ{_yuM0HTqYu!i`vX0Ce{~=~ zBR!BO^m<{?%JEd-pHn{vAG2iF2_As@bM)W!i+$<3Ja#=|rS$pT;m2W{?!|U%T%cT+ zew_rO4P0K$M+Sd)-zFwdUsm~CNUbs>$8v~&V%Ph@>uCLs;QS(_pSzLkFh>zng?kVL znT+K3A>CPtG|7h z*X^~ax5k>?Z5kZOJGDZK9QB}<=$j+jSn=VQUd>=dgQ%6&%bJcen0wt zo)j@PVctW3htLNxx9odoFvfk}xO`oI@@z0hzJvIlKY-X&y{-i3r!$fBzrGioPoG@1 zram^_mzK{on?Cb=8^5$JXNw%!i4pw1nSn@15^7-37*n*x^ra_n$=~P4-HZ3o#s~sK z&;&;^6i<^hdXk)?-(szSF;D!`laX?^ZuPe!wq4~VLeyvgv`~-Fd1MA=SoV2@K2O{= z>AEmphx1+1*p3AfNy;P-IF(Y_vDpjnek?U71@2~#bOi!yMtu;0`7 zmy|wJZh+`l!WT*jrdgy^ic&a%WK{L|@ln5bYOp<_tQTa{OZhtY8yVbjUMj%SXJXhMUlhDGB!vP{tihBwa9o~X9V&74u9};?@s*t!J%5A;~4Bq zk=nmj=#Wuj>>g|szHB^3p74w>=-qJEr$#n!EYAi)SoCz{`aPSwLTuhrD~y%-$&<6c zRS)Sj6gg(4g)*27$62+4T&1T2I2DkkN_j5e%zXES-ghrQoiyHTia|L5@{sVtNv$h% zJX0@nJ;_M^<|x1aCWf+=0+)MGw)SOQx6nx}otLi`$g4TvRmN{OBEnD2^(o>QK)pB?z=ytPPFP7ZAy zO;OeysZa)bJlLVYRp87W=E`yT-TH27|4-&KU#zjj$0Uu25WBD(gBZl1vgwPZg377r za$^vKa6E{`^qXg6%9C%dcn$^-?2Zc_OtGYO=%m4tGaopuO19*@puca#%$S(f{hBmf zG-PN}l!)Zf=QQT`%Idg)X7~Q$fyY^4V!irLL3l0tyx~@(s3h`PWNkfH^ zbDr;}Zs(^r4RbQ+q5`784=haTwP9-F`G=@yUC&8@OzQG)l)RBh$Q1bLZ{IaI?WtD4Xr83`*MQP zA(MqGd{$6R`e~#{t1K&$qAKx4ZZ)my;cw38em?G}6lgNm29uf%x{JGR-zI__9efm) z;$@njvDfy%Bh|s-I>F1N$SX9fiVAVzNVU$f7WCZF=i?ypH;Ry99Q8ZhyXeJ5Z!cem zjVxT!z!p76{?S}o!cx<_YVSnXZ}*4kcCp_thO#RDt+1au($(LV3-b3*tbPaJmp z+W7KeYfbOMIm6%ly;HqVTrFw^%TZRj&>zkm^*TAKRtR>^PeZdDXgqIrc81Ql3qIeGR42Zv^JV-kxzjB37MJ1aDgi>|#; zUH#9=oDFrh7Tx%4>Lqq3|1h<01W%eIOK}V(a+E-j41wNGvg)xIpNzxxyoLAg$IZig zybpKLX{Ly~s34Il!D>JdMCtkWMoqfwDb!R+wVnN{_4y~N^MEd2!)na zR$&3E)P@&r&=jr7V!GD5yw~}9^RkK*@$Ev$~F zDV0&f`lWxsAVq66o7#BAjyt?F@*>7uPgJ>aDjd~IR!3Bwu2jNz^>-sy18?|n=@vnp#tDBb8uSTfw!1Cc%NI? z=zGs5=;bIcTssA;l3kEH9;g@c1mGxH6A4vjlyP>s`>26EiVA$JW^hGsAX^0b90xdu z8y&oL@1B0H_5$e8CXAK8KemJ_$eJMYlBg)CjsKvy$U|Z_b@H}~n{;Dl5_EsC(-Klg zv1^I`emicz-zSIN4ir}}paG}TmOD0M_MX*e>TOPfF7oTprQ0gYI>DFAR$DTfm^n0< zn5l2=;CwG6-x`_5hDaW9xnt6hJQC~1L?U_AGYsm+s|Av8Zjf(gkZ+3Qn;7J;Hpn*$ zv!Ej7q5GpolP&zNA6|MUsc3EpZ=>Ur5B~Lcn7bv#D~{JBftP8Z60Cy8)A(#md{7#? z;&?CflQ?8hvk1X;XpyG~k)i~a;CKPOzH*c9i2wRz+@cn|E91R0mmi1Ym=U_Db6AqK zjt7N7sBhcnOnVZ#l@h%h89eV%M1X^Lyz)XlB&}P)?QV3D$pow~ z@gmh%FUpP6Y!bacOnYi(=k-{eB}Il78Hy4qktS(cL~*vW?h9xewuy*zKAM^HNBi$P+A@6v2JujU`!aMdh*Ldp)*nE>%5Y+M zWaHUfO5Gv+d=esB-l$)Rf;XekZB#_^aCFgKJ`3}n3G;qwAv3Og2>z))08i)xI$tmE zYCXLQL+4G%xIq7U@UGpvdOBPm&OO3Rd9Lm`*$&T1Ve3IU&iqp z9FJQCoxSr8dk#GNSQ7+QN~{9O>9poZc~(^h8lX6i@-nZ%3nnHD0q1YupVhUkVeDLUIWCSxxudEFo?|t6|H`w<{aNdTv z9{m}it7DOkjYIM*k{^ZK5Y0sLeMe>g#`Plf!#{Wtj|8Cxy#PMar?HQ5OG$Luuci6#DAgLXpxaa6@Iie^ zX+0t1To8P}=8vyte{i?6*bRGkZ~dJw{kkWzE{zpfO;ahEAcT;>nH1(ueRuDJg)I}^ z&q9egtcO*O7FCJUG)7Sc=q5IE;r#THT}6Jy}dy-b2@{x@zUZ$l52K z6M-l*sw6W!%Jf$=*yysnwb!q_zl$2lQ321ff&w&3U`Q5qRPe8!?$*;K*bTL>_rZC6 zpT2r0R(_!wl4DtlBv_tdIgvrTg7aw#tLW?f>(iM92ggSAjLWhN!7vm>D6$mRGj0te zMWF@;v5R??{@&l(Igd8n7->jVAPEAei43jr=#cisq@gtp_HOC0vdtI2Mn(@>6cvG0 zG)e#js+|1BQ0yGy9r3JX)T~+fY2yTzVo93i2#)26kZJp;{w)CkX<+=ju`#F!0%taj@t(@5+44OfT!i~A z5f`CINg5*(1j|xd+8-YsY{Sn3PVL{njv8uf>&qbWPUHffGE4*ZF#S>qmifTbDoqXY}6}>ggixNR`0?;&-MgvVjFp5c3tjD<1JG)c$v>h9u9^;PidJIh?6;Y#PN#>_4kVmDL z2$5#59$%pod#AVFYukQoQe@c|rbYhqXq!4|kkiV_G$2WiU{ywYf8p@1{^(ceZR3yY z2T1Rm^{Pc|KuyCSU{3GhgWSSyqgsS=NJz*^lCbu-_bSZwW8z@R=?aNi*ArVwzPCUk zI@qd5#5qb6cn*jxOLH`ebEOYRHNpG#p5z6e{a!P4C6x?<#fhlt+3N}6t1QN^Lhp*l zM`R2;Q6INR1yB-jwY$=f~;lspP!zEJ2r^!LcTHE%>7EP;?UN~KAj3t6DU zYXqwL`nEt`l+8i;(7~GQO{|kVZ}}Nc|0RrzYDFp-o9(jNa`RnMt^ypIbrLO=Flrs_ zu;n{)dpn&DCwKI4pOOx{t5q0zyxV(z;1eG|+6f|ScG&X)LR2*gr~=C<#o_-RTG)DP zYLj15V590;!lyVupW{z_rg-n^HEqx@O*63Sc9N$Ffh1Xm5*a!KKWse$+*N(eceSezUeHVqx_`@H{~GBacLX{emvQ(Tj(SV@tx$_}-# z%i(Hy>2v<9hT6exuOe4L(RRQ*`g?J|XL{qPDeo-%Hxo}2wOp&9N|MUa8l!@cgUL87 z3eWN`{(Sd9@_$hO+tiHGCABa&5ChSg=XB%&r>oFPQT)`w@3O<*n;j3o>$0tEGGkf4 ztNOgtL*B0Lhr9f|Afl`<@jy~pT4rgPiGI=^_S&;&o|-?elm5%11k5H`(!4)MDwM%s zrz6Lf4~7C)fiw5i3!T=aKe;3Br3&hMwDyB#U5Itc_??l(KztcDhM2PX%7#V=9#{~3 zgJuJ@kp&E)I;Pyx9@LsI5>1Q2#TjRdX^!{1zDNFH60Zs6bV>?nnk`rDm#czFR!U_k zhL!x18n|PDxNq74b9x;Ea#vc2ujKM@EbJU_t9_&B7xzRIKm?KoA}f%BD)XoSqN`Jj zQj;lszIcOu)caW%%g3ElBktX*#A+HVQWU|+=-$2kOasi+&h<`hy8iLTOCaO4EX;Wa zBZ}5M$>jph+?&9Kz|VuUfj49(tz5dS$cjF{iXrV>?^IFUv$l4`S<)z#r8SBrNiAfS zzB31>CR6x)@hr{vzO}RW>}}KFP_8mX!@Cm9!uOWDkAGX!0%h@0)1nJn6YYByM+YAF zo*8|z+leiip@MMHDWD)&L5|IJv%`N9m_KX5y`!yZcNXzj=rvp1wOib^T-cV!y~>P* zEoS@~`F=A?t0YZR9Ia?!?>CS7C~_J)$BVq31>R_ zPqX0EWD1|}i%=nysm(NCN)wB|ebPIa+wQAt!Rlp5p5l0#6BvQxMGBR>bM@1tXDvAF zSmM2EY1)0adg0OOw9soMIW#L;U4?l-9SZUb?5+iI6I|%1)*wu75g5SkFTWq zOS`0(c&FMvd46FbR`tvRpaPC0R8=ET)pPYy%b?4=6A$cL{^Aj+pgIz|*#wyn(y9df z#x(*dymb5EB=0?67hOIotAoR;%VaJ0GRN;-xNlEnwTdRnf~crG2e=U532QN-=9YU$ z+tN3_w5(Yu*)E|nDY%s@WtosiRC7-@qS#`8kWD03)+_8W=Hc5vaA=b${`lycSA ztG_jK@u`gJ<1TZ~eMLFR+{N-jTV9O??pj^^MIPrAB%grMEG0$R&J~#LA{mn!jZbnF zA#!N`Sug#>uf4u%(4Yjf6GE5(C6O$nF&s%Lvz~qN#OXD4)8GKt?i4^(+rmIs^A`kC z*Mi`DD3Ms{{p+_*PrtMjGV2-P@4)6ea)4FPc#4u_o>Vny+ieGbuzu7n2^v@2j-iFP z-=l@{eviVgw2JvI1GDT_dS8m~<=)yZGC?P00xryGrTrq8 zt%wxh070?>N26u8z_KL&^QJ9$Z^KKw!&vp(Ri~9?7;BE?0#2J`w@n7tY$+dQj5q1} zw5=9g9jm>o=;3XLHH;{WvW%z-G|3XOprEp-tf#|~ZVbnE>lN=^j>BV)ejesXy|_w( z6BLDDMTwSZoSfq58l0L;;q$m_Z6)z0@a$D@+;j8uHdrFKCSiGsr9_&d37+9XB$4NI z4+U1NB>tNB?sHFN-F+XF4#T;MVg$}#pDoWHM7gJw@5*mk_}R1mpt_Kn&(THwKeq(L zli!*Irx32K-L8~;@J4Uuj@D|@5d4)R|1rNHG7Q6rA}iA95aj$X(6sGMaaC;gcKq&- zhbJF{H-qv*MD+^?{EQ&XIJQ5JXs|s2s)+^NOz?!cay9|8X^XesvL(Z7aj^S?!>O}q z9+0G@0f7>g59y_Awr-x04u#p1<-R+#)obo@{Qf_Rmi^$cB!vZClqc1d*6+&@F7cO|p+TY$g$L3d= zUeJaOmR#8*oc8`Uxu;~ee|Bqw)s54J#6dRubkt4w*gMD7Q8<3o;0~G~P!tUWm1F>V z2QAaEj!(VEZhZHVU40`en@K_A2_P{fqwwfvJHG+0=sn&?Qa3d7oy^3Kp#Kn>A|#nn z1W8i0vDpi&W&U-pD8TzHy&tzDX=q)adD9Me>Tq{6tZG9d6-`nUMP^A2Rc(Br7kg*a zi+QiN*_V^8o^3_8H|B_{4S}a*k)s)oR+-P=s68?T%u9pj(Z}8^8>T*>pT8f{8}HGF zw{c=Hy9RlJYxLhy%fzvm^8ePk?m2ovH|dNIbX>H*e$`g7?Dc-J+Wzvs{t?+QmC;y6 zB1K-2WRwk?eJ(gPnZoCbk?>2e z0*X6RpHIM)eb`%X>Xs8XTcD}b9cBykF@iP5RMes_@Mgb1^pKyup~F z#FOG>aMIf{!;vX=G!o1NnUzUi0|b%y+35Q-)-0(3`HbP_Xeq1DyR&=!t9@VMmmE!! zEJX_fO_Bmja_Ev9sN=^ptnBx*H@o-7I^IbJ+@B(FKom$;7DG-Kn`4`Q%KP=$^Se8? zxdzWB`G-oC@?2J4R#-_B2$>@lt1TzbzTn`{Y;H_qkvRKM{osr7XkI`F8SL>_X(^u- zzA@+C0{!79%Z9$WaO~Zk5{lma#k-=>cHj6tcoic-QGPWeLDB*v5+Qt2yrIZ@##`5N z=h*^0?WFv!BN>4vIFTU)RwykicE-DRR+E-XpNOpO5D1EtB;M};N=CIEeG`nZ@el7? zbB4XW<3*^p3S*K0O&hJU#Id|6i!4WiY4cp~tlmE#>)sf3Q`g5}t;6?^l=AGgyzk?8 z?XzBW{F_gmb4DJ0l2sYNE4(6zA){Z*kQT)IXzloScQl7}%ne(INNb!x(WFH1V8)KW zm$!Lmb#f|ZPlh-BZKj74wWdDy^(9V3gp#L1LGgt&9BX*fOY%bxc(PiV-&5w`ldyetmnk!>>DC zX+aa#etw7U!|V=MzE$zNPj(h4E{78(SPd*jl~(s%tFWAB2UL>09L~m(=l!-tE}JsU z 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 z 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

      G)uZx3(^uP<+jQ?h!{vH(sy+2B1vHV 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

      SCRIPTC_CHECKER
      The TypeScript 7 API server that checks the program: tsc-ts (the default), which scriptc includes, or tsgo, from the typescript package scriptc also includes. Both give the same diagnostics and generated code.
      + +
      SCRIPTC_CHECKER_SERVER
      +
      Set to 1 on Linux and macOS to check with a tsc-ts server that later builds share. A build connects to the server for its working directory, starting it when none answers, and the server keeps the files it parsed, so the next build of the same program loads it faster. A build that finds the server in use by another build, or cannot start or reach it, checks with its own tsc-ts process. The server exits after 5 minutes without a build, or after a build when its resident memory is above 2048 MB (TSC_TS_LISTEN_MEMORY sets another limit in megabytes). Diagnostics and generated code are the same with and without it. It applies to the default checker, tsc-ts.

      4di=<@xe%*eltxQANCDA!5P1fFz$ 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 From d037c66e8c009ae8863855ad8ecf91421f78be8c Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 24 Oct 2026 09:53:48 -0700 Subject: [PATCH 108/259] Report JSON.parse syntax errors with V8's messages and positions JSON.parse's SyntaxError messages were shaped like V8's but differed from Node's in several ways: - Every positional message now ends with V8's "(line L column C)", where \n, \r and \r\n end lines. - Positions are UTF-16 offsets, as in Node, not byte offsets. - An object or array cut off after '{', a property name, a value or an array element reports the token V8 expected ("Expected property name or '}'", "Expected ':' after property name", "Expected ',' or '}' after property value", "Expected ',' or ']' after array element") instead of "Unexpected end of JSON input". - After a comma in an object the message is "Expected double-quoted property name". - An unterminated string reports the end of the input, and a truncated \u escape is a "Bad Unicode escape" there. - A leading zero followed by a digit is an "Unexpected number". - A misspelled literal names the first differing character, or the end of the input. - An unexpected character is named with the source as V8 does: whole when it is under 21 units, otherwise ten units of context on each side; the sources "NaN", "Infinity", "undefined" and "[object Object]" name only themselves; a quote or a number there is an "Unexpected string" or "Unexpected number". The new corpus program 7993-json-parse-error-messages pins 76 inputs against Node, including non-ASCII text before the error, line breaks, and long sources with split surrogate pairs at the context edges. Co-Authored-By: Claude Opus 5.5 --- .../7993-json-parse-error-messages.ts.json | 6 + packages/runtime/src/scr_dyn.h | 4 +- packages/runtime/src/scr_json.c | 206 ++++++++++++++---- packages/runtime/test/json.test.ts | 33 ++- tests/corpus/1004-json-parse-errors.ts | 8 +- .../corpus/7993-json-parse-error-messages.ts | 30 +++ .../7993-json-parse-error-messages.ts.json | 1 + tests/harness/dyncheck.test.ts | 12 +- 8 files changed, 229 insertions(+), 71 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7993-json-parse-error-messages.ts.json create mode 100644 tests/corpus/7993-json-parse-error-messages.ts create mode 100644 tests/harness/corpus-costs/7993-json-parse-error-messages.ts.json diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7993-json-parse-error-messages.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7993-json-parse-error-messages.ts.json new file mode 100644 index 000000000..4fec854a7 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7993-json-parse-error-messages.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7993-json-parse-error-messages.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index 82fe1a6d9..d3997ebd9 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -23,8 +23,8 @@ * Ownership: the checked-dynamic tree owns its children (strings, items, entry keys+values); * releasing the root releases the tree recursively. scr_json_parse borrows * the text and returns +1 — or THROWS a catchable string shaped like Node's - * V8 messages ("Unexpected end of JSON input"; approximate fidelity, see - * SEMANTICS.md) and returns NULL. scr_dyn_obj_get returns a BORROWED + * V8 messages ("Unexpected end of JSON input", "... in JSON at position + * (line column )") and returns NULL. scr_dyn_obj_get returns a BORROWED * member (the compiler's builders retain what they extract themselves). */ diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 49af072ed..45ba766a1 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -9,10 +9,10 @@ * arrays, objects (later duplicate keys win, like JS), and the * four JSON whitespace characters. Syntax errors THROW catchable * SyntaxError instances (the depth cap a RangeError, like V8's) whose - * messages are shaped like Node's V8 texts ("Unexpected end of JSON - * input", "Unexpected token 'x', \"...\" is not valid JSON") — - * APPROXIMATE message fidelity by design (SEMANTICS.md; e.name is exact, - * e.message is ours), pinned by the runtime C tests. + * messages are Node's V8 texts ("Unexpected end of JSON input", + * "Unexpected token 'x', \"...\" is not valid JSON", "... in JSON at + * position (line column )"), reported where V8 + * reports them. * - scr_dyn_check_fail is the shared failure path of the compiler-emitted * dynCheck builders: a TypeError instance carrying "expected at * , got ", thrown through the exception cell. @@ -11115,26 +11115,142 @@ static void scr_json_throw(const ScrJsonP *p, const char *msg) { scr_throw_error_msg(SCR_ERR_SYNTAX, msg, strlen(msg)); } +/* V8's location of a JSON error at byte `pos`: the UTF-16 offset (the + * text is WTF-8; a four-byte sequence is two units), and the 1-based line + * and column, where \r, \n and \r\n end a line. */ +static void scr_json_location(const ScrJsonP *p, size_t pos, size_t *unit, size_t *line, + size_t *column) { + const unsigned char *s = (const unsigned char *)p->s; + size_t units = 0, ln = 1, line_start = 0; + for (size_t i = 0; i < pos; i++) { + unsigned char c = s[i]; + if ((c & 0xC0) == 0x80) continue; + if (c == '\r' && i + 1 < pos && s[i + 1] == '\n') { + i++; + units++; + c = '\n'; + } + units += c >= 0xF0 ? 2 : 1; + if (c == '\r' || c == '\n') { + ln++; + line_start = units; + } + } + *unit = units; + *line = ln; + *column = 1 + units - line_start; +} + /* Errors stay out of line so the scanners that report them keep their - * registers for the common path. */ -static __attribute__((noinline, cold)) void scr_json_throw_pos(const ScrJsonP *p, const char *what, - size_t pos) { + * registers for the common path. V8's positional messages: + * " in JSON at position (line column )". */ +static __attribute__((noinline, cold)) void scr_json_throw_located(const ScrJsonP *p, + const char *what, + const char *where, size_t pos) { if (p->quiet) return; - char buf[128]; - int n = snprintf(buf, sizeof buf, "%s in JSON at position %zu", what, pos); + size_t unit, line, column; + scr_json_location(p, pos, &unit, &line, &column); + char buf[192]; + int n = snprintf(buf, sizeof buf, "%s%s at position %zu (line %zu column %zu)", what, where, unit, + line, column); scr_throw_error_msg(SCR_ERR_SYNTAX, buf, (size_t)n); } -/* V8-flavored bad-token message with a short snippet of the input around - * the offending character. Approximate fidelity (documented). */ -static void scr_json_throw_token(const ScrJsonP *p) { +static __attribute__((noinline, cold)) void scr_json_throw_pos(const ScrJsonP *p, const char *what, + size_t pos) { + scr_json_throw_located(p, what, " in JSON", pos); +} + +/* Appends the text's UTF-16 units [from, to) as WTF-8: a surrogate pair the + * range cuts contributes its half as a lone surrogate, as V8's substring. */ +static size_t scr_json_unit_slice(const ScrJsonP *p, size_t from, size_t to, char *out) { + const unsigned char *s = (const unsigned char *)p->s; + size_t n = 0, unit = 0, i = 0; + while (i < p->len && unit < to) { + unsigned char c = s[i]; + size_t width = c < 0x80 ? 1 : c < 0xE0 ? 2 : c < 0xF0 ? 3 : 4; + if (i + width > p->len) width = p->len - i; + if (width == 4) { + uint32_t cp = ((uint32_t)(c & 0x07) << 18) | ((uint32_t)(s[i + 1] & 0x3F) << 12) | + ((uint32_t)(s[i + 2] & 0x3F) << 6) | (uint32_t)(s[i + 3] & 0x3F); + bool high = unit >= from && unit < to, low = unit + 1 >= from && unit + 1 < to; + if (high && low) { + memcpy(out + n, s + i, 4); + n += 4; + } else if (high) { + n += scr_wtf8_put(out + n, 0xD800 + ((cp - 0x10000) >> 10)); + } else if (low) { + n += scr_wtf8_put(out + n, 0xDC00 + ((cp - 0x10000) & 0x3FF)); + } + unit += 2; + } else { + if (unit >= from) { + memcpy(out + n, s + i, width); + n += width; + } + unit++; + } + i += width; + } + return n; +} + +/* V8's report of an unexpected token at byte `pos`: the end of the input, + * a string or a number, or any other character, named with the source (a + * short one whole, a longer one as up to ten units on each side), except + * that the sources "NaN", "Infinity", "undefined" and "[object Object]" + * name only themselves. */ +static __attribute__((noinline, cold)) void scr_json_throw_unexpected(const ScrJsonP *p, + size_t pos) { if (p->quiet) return; - size_t start = p->pos > 8 ? p->pos - 8 : 0; - size_t take = p->len - start < 16 ? p->len - start : 16; - char buf[192]; - int n = snprintf(buf, sizeof buf, "Unexpected token '%c', %s\"%.*s\"%s is not valid JSON", - p->s[p->pos], start > 0 ? "..." : "", (int)take, p->s + start, - start + take < p->len ? "..." : ""); + if (pos >= p->len) { + scr_json_throw(p, "Unexpected end of JSON input"); + return; + } + char c = p->s[pos]; + if (c == '"') { + scr_json_throw_pos(p, "Unexpected string", pos); + return; + } + if (c == '-' || (c >= '0' && c <= '9')) { + scr_json_throw_pos(p, "Unexpected number", pos); + return; + } + static const char *const special[] = {"NaN", "Infinity", "undefined", "[object Object]"}; + char buf[256]; + int n; + for (size_t k = 0; k < sizeof special / sizeof special[0]; k++) { + if (p->len == strlen(special[k]) && memcmp(p->s, special[k], p->len) == 0) { + n = snprintf(buf, sizeof buf, "\"%s\" is not valid JSON", special[k]); + scr_throw_error_msg(SCR_ERR_SYNTAX, buf, (size_t)n); + return; + } + } + size_t unit, line, column, total; + scr_json_location(p, pos, &unit, &line, &column); + scr_json_location(p, p->len, &total, &line, &column); + char token[8]; + size_t token_len = scr_json_unit_slice(p, unit, unit + 1, token); + enum { CONTEXT = 10 }; + size_t from = 0, to = total; + const char *before = "", *after = ""; + if (total >= 2 * CONTEXT + 1) { + if (unit < CONTEXT) { + to = unit + CONTEXT; + after = "..."; + } else if (unit < total - CONTEXT) { + from = unit - CONTEXT; + to = unit + CONTEXT; + before = after = "..."; + } else { + from = unit - CONTEXT; + before = "..."; + } + } + char source[4 * 2 * CONTEXT + 8]; + size_t source_len = scr_json_unit_slice(p, from, to, source); + n = snprintf(buf, sizeof buf, "Unexpected token '%.*s', %s\"%.*s\"%s is not valid JSON", + (int)token_len, token, before, (int)source_len, source, after); scr_throw_error_msg(SCR_ERR_SYNTAX, buf, (size_t)n); } @@ -11159,12 +11275,13 @@ static void scr_json_put_cp(ScrJsonBuf *b, uint32_t cp) { /* Four hex digits at pos, or -1 (throws). */ static int32_t scr_json_hex4(ScrJsonP *p) { - if (p->len - p->pos < 4) { - scr_json_throw(p, "Unexpected end of JSON input"); - return -1; - } uint32_t v = 0; for (int i = 0; i < 4; i++) { + if (p->pos + (size_t)i >= p->len) { + /* V8 reports the escape at the end of the input. */ + scr_json_throw_pos(p, "Bad Unicode escape", p->len); + return -1; + } char c = p->s[p->pos + (size_t)i]; uint32_t digit; if (c >= '0' && c <= '9') digit = (uint32_t)(c - '0'); @@ -11205,7 +11322,7 @@ static int scr_json_string_span(ScrJsonP *p, const char **span, return -1; } } - scr_json_throw_pos(p, "Unterminated string", p->pos); + scr_json_throw_pos(p, "Unterminated string", p->len); return -1; } @@ -11221,7 +11338,7 @@ static ScrStr *scr_json_string_slow(ScrJsonP *p, size_t prefix) { for (;;) { if (p->pos >= p->len) { scr_jb_dispose(&b); - scr_json_throw_pos(p, "Unterminated string", open); + scr_json_throw_pos(p, "Unterminated string", p->len); return NULL; } unsigned char c = (unsigned char)p->s[p->pos]; @@ -11325,6 +11442,12 @@ static bool scr_json_number_value(ScrJsonP *p, double *out) { } if (s[pos] == '0') { pos++; + /* A leading zero followed by a digit: V8's unexpected number there. */ + if (pos < len && s[pos] >= '0' && s[pos] <= '9') { + p->pos = pos; + scr_json_throw_pos(p, "Unexpected number", pos); + return false; + } } else { while (pos < len && s[pos] >= '0' && s[pos] <= '9') { if (ndig < 15) { @@ -11405,7 +11528,10 @@ static bool scr_json_lit(ScrJsonP *p, const char *word, size_t n) { p->pos += n; return true; } - scr_json_throw_token(p); + /* V8 names the first character that differs, or the end of the input. */ + size_t i = 1; + while (p->pos + i < p->len && i < n && p->s[p->pos + i] == word[i]) i++; + scr_json_throw_unexpected(p, p->pos + i); return false; } @@ -11465,7 +11591,7 @@ static ScrDyn *scr_json_array(ScrJsonP *p) { scr_json_ws(p); if (p->pos >= p->len) { scr_dyn_release(arr); - scr_json_throw(p, "Unexpected end of JSON input"); + scr_json_throw_pos(p, "Expected ',' or ']' after array element", p->pos); return NULL; } if (p->s[p->pos] == ',') { @@ -11595,18 +11721,20 @@ static ScrDyn *scr_json_object(ScrJsonP *p) { } uint32_t shape = 0; /* the empty layout */ bool shaped = true; /* obj holds exactly the keys on shape's path */ + bool first = true; for (;;) { scr_json_ws(p); - if (p->pos >= p->len) { + if (p->pos >= p->len || p->s[p->pos] != '"') { + /* V8: the first member may also close the object; after a comma + * only a property name may follow. */ scr_dyn_release(obj); - scr_json_throw(p, "Unexpected end of JSON input"); - return NULL; - } - if (p->s[p->pos] != '"') { - scr_dyn_release(obj); - scr_json_throw_pos(p, "Expected property name or '}'", p->pos); + scr_json_throw_pos(p, + first ? "Expected property name or '}'" + : "Expected double-quoted property name", + p->pos); return NULL; } + first = false; /* Keep the key borrowed until insertion determines whether it already * exists or can reuse a recycled slot. Escaped keys own their decoded * string until the value has been parsed and inserted. */ @@ -11644,8 +11772,7 @@ static ScrDyn *scr_json_object(ScrJsonP *p) { if (p->pos >= p->len || p->s[p->pos] != ':') { scr_str_release(decoded_key); scr_dyn_release(obj); - if (p->pos >= p->len) scr_json_throw(p, "Unexpected end of JSON input"); - else scr_json_throw_pos(p, "Expected ':' after property name", p->pos); + scr_json_throw_pos(p, "Expected ':' after property name", p->pos); return NULL; } p->pos++; /* ':' */ @@ -11672,7 +11799,7 @@ static ScrDyn *scr_json_object(ScrJsonP *p) { scr_json_ws(p); if (p->pos >= p->len) { scr_dyn_release(obj); - scr_json_throw(p, "Unexpected end of JSON input"); + scr_json_throw_pos(p, "Expected ',' or '}' after property value", p->pos); return NULL; } if (p->s[p->pos] == ',') { @@ -11730,7 +11857,7 @@ static ScrDyn *scr_json_value(ScrJsonP *p) { return scr_dyn_new_null(); } if (c == '-' || (c >= '0' && c <= '9')) return scr_json_number(p); - scr_json_throw_token(p); + scr_json_throw_unexpected(p, p->pos); return NULL; } @@ -11750,10 +11877,7 @@ ScrDyn *scr_json_parse(ScrStr *text) { scr_json_ws(&p); if (p.pos < p.len) { scr_dyn_release(d); - char buf[96]; - int n = snprintf(buf, sizeof buf, - "Unexpected non-whitespace character after JSON at position %zu", p.pos); - scr_throw_error_msg(SCR_ERR_SYNTAX, buf, (size_t)n); + scr_json_throw_located(&p, "Unexpected non-whitespace character after JSON", "", p.pos); return NULL; } return d; diff --git a/packages/runtime/test/json.test.ts b/packages/runtime/test/json.test.ts index 3315cb415..14aaed199 100644 --- a/packages/runtime/test/json.test.ts +++ b/packages/runtime/test/json.test.ts @@ -53,9 +53,8 @@ beforeAll(async () => { // The C side parses/inspects dyn values as checks and routes each expected // failure through scr_exc_print_uncaught. Parse failures are SyntaxError // INSTANCES (the depth cap a RangeError, dynCheck failures TypeErrors), so -// every uncaught line renders "name: message" — e.name is Node-exact while -// the V8-flavored message wording stays approximate (SEMANTICS.md): these -// lines pin OUR rendering, not Node's. +// every uncaught line renders "name: message"; the JSON syntax error +// messages are Node's (V8's wording, positions and line/column). test("json runtime: parser, dyn, dynCheck failure path, stringify buffer", async () => { const { stdout, stderr } = await execFileAsync(bin); expect(stdout).toMatch(/^(\d+)\/\1 checks passed\n$/); @@ -63,21 +62,21 @@ test("json runtime: parser, dyn, dynCheck failure path, stringify buffer", async [ `Uncaught SyntaxError: Unexpected end of JSON input`, `Uncaught SyntaxError: Unexpected end of JSON input`, - `Uncaught SyntaxError: Expected property name or '}' in JSON at position 1`, + `Uncaught SyntaxError: Expected property name or '}' in JSON at position 1 (line 1 column 2)`, + `Uncaught SyntaxError: Unexpected end of JSON input`, + `Uncaught SyntaxError: Expected ',' or ']' after array element in JSON at position 3 (line 1 column 4)`, + `Uncaught SyntaxError: Expected ':' after property name in JSON at position 4 (line 1 column 5)`, + `Uncaught SyntaxError: Expected double-quoted property name in JSON at position 7 (line 1 column 8)`, + `Uncaught SyntaxError: Expected property name or '}' in JSON at position 1 (line 1 column 2)`, + `Uncaught SyntaxError: Unterminated string in JSON at position 13 (line 1 column 14)`, + `Uncaught SyntaxError: Bad escaped character in JSON at position 6 (line 1 column 7)`, + `Uncaught SyntaxError: Bad control character in string literal in JSON at position 6 (line 1 column 7)`, + `Uncaught SyntaxError: Bad Unicode escape in JSON at position 5 (line 1 column 6)`, + `Uncaught SyntaxError: No number after minus sign in JSON at position 1 (line 1 column 2)`, + `Uncaught SyntaxError: Unterminated fractional number in JSON at position 2 (line 1 column 3)`, + `Uncaught SyntaxError: Exponent part is missing a number in JSON at position 3 (line 1 column 4)`, + `Uncaught SyntaxError: Unexpected non-whitespace character after JSON at position 2 (line 1 column 3)`, `Uncaught SyntaxError: Unexpected end of JSON input`, - `Uncaught SyntaxError: Expected ',' or ']' after array element in JSON at position 3`, - `Uncaught SyntaxError: Expected ':' after property name in JSON at position 4`, - `Uncaught SyntaxError: Expected property name or '}' in JSON at position 7`, - `Uncaught SyntaxError: Expected property name or '}' in JSON at position 1`, - `Uncaught SyntaxError: Unterminated string in JSON at position 0`, - `Uncaught SyntaxError: Bad escaped character in JSON at position 6`, - `Uncaught SyntaxError: Bad control character in string literal in JSON at position 6`, - `Uncaught SyntaxError: Bad Unicode escape in JSON at position 5`, - `Uncaught SyntaxError: No number after minus sign in JSON at position 1`, - `Uncaught SyntaxError: Unterminated fractional number in JSON at position 2`, - `Uncaught SyntaxError: Exponent part is missing a number in JSON at position 3`, - `Uncaught SyntaxError: Unexpected non-whitespace character after JSON at position 2`, - `Uncaught SyntaxError: Unexpected token 'n', "nul" is not valid JSON`, `Uncaught RangeError: Maximum call stack size exceeded`, `Uncaught TypeError: expected number at $.items[2].price, got string`, `Uncaught TypeError: expected object at $, got undefined`, diff --git a/tests/corpus/1004-json-parse-errors.ts b/tests/corpus/1004-json-parse-errors.ts index e65a9752e..aad0817d7 100644 --- a/tests/corpus/1004-json-parse-errors.ts +++ b/tests/corpus/1004-json-parse-errors.ts @@ -1,9 +1,7 @@ // JSON.parse syntax errors are CATCHABLE, exactly like Node's SyntaxError. -// The message text itself is unobservable here (the supported catch form is -// bindingless) and its V8-flavored shape is deliberately approximate — -// exact-message assertions live in the runtime C tests (test_json.c), per -// SEMANTICS.md. This program only proves the throw/catch/recover behavior -// matches Node for every syntax-error class. +// This program proves the throw/catch/recover behavior matches Node for +// every syntax-error class; 7993-json-parse-error-messages pins the +// messages themselves. function attempt(raw: string, label: string): void { try { diff --git a/tests/corpus/7993-json-parse-error-messages.ts b/tests/corpus/7993-json-parse-error-messages.ts new file mode 100644 index 000000000..76605e501 --- /dev/null +++ b/tests/corpus/7993-json-parse-error-messages.ts @@ -0,0 +1,30 @@ +// JSON.parse syntax error messages, exactly as Node's V8 writes them: the +// expected token at the end of the input inside objects and arrays, the +// position as a UTF-16 offset with its line and column (\n, \r and \r\n +// end lines), the unexpected character named with the source (whole when +// short, ten units of context on each side when longer), and the special +// sources that name only themselves. +const inputs: string[] = [ + "", " ", "[", "[{", "{", '{"a"', '{"a":', '{"a":1', '{"a":1,', '{"a":1,}', "{,", "{1:2}", "{'a':1}", + '{"a" 1}', '{"a":1 "b":2}', "[1", "[1,", "[1,]", "[1 2]", "[,1]", '"abc', '"a\\', '"\\u12', '"\\u12x4"', + '"\\u12"', '"\\x"', "tru", "nul", "fals", "t1", 'n"', "-", "-x", "1.", "1.e", "1e", "1e+", "01", "-01", + "[01]", "+1", "1 2", "{} x", "[]]", "\u0001", '"\u0001"', '{"a":[1,{"b":', '[{"a":1},', '{"a":{"b":{}', + "[[[", " [ \n { \n", "\n\n{", "\r\n\r\n{", "\r\r{", '{"a":tru}', "NaN", "Infinity", "undefined", + "[object Object]", " NaN", "-Infinity", "[-]", + // Positions count UTF-16 units: non-ASCII text before the error. + '{"é":1 x}', '["😀" 1]', '{"😀😀":', '"é\u0001"', "é", + // Long sources: the unexpected character with its context. + '{"name":"some long value","other":x}', '[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,]', + 'x{"name":"some long value","other":1}', '{"name":"some long value","other":1}x', '{"a":"0123456789abcdef"x}', + '["😀😀😀😀😀😀", x, "😀😀😀😀😀😀"]', '["😀😀😀😀😀😀",x]', '{"k":[true,false,null,"s",1.5e3,-2] ]', + '\n\n {\n "a": [1, 2,\n 3 4]\n }', +]; +for (const text of inputs) { + try { + JSON.parse(text); + console.log(JSON.stringify(text), "parsed"); + } catch (e) { + const err = e as Error; + console.log(JSON.stringify(text), err.name, JSON.stringify(err.message)); + } +} diff --git a/tests/harness/corpus-costs/7993-json-parse-error-messages.ts.json b/tests/harness/corpus-costs/7993-json-parse-error-messages.ts.json new file mode 100644 index 000000000..85179832c --- /dev/null +++ b/tests/harness/corpus-costs/7993-json-parse-error-messages.ts.json @@ -0,0 +1 @@ +{ "plain": 3600 } diff --git a/tests/harness/dyncheck.test.ts b/tests/harness/dyncheck.test.ts index 69e97dc6d..a0c43cd0c 100644 --- a/tests/harness/dyncheck.test.ts +++ b/tests/harness/dyncheck.test.ts @@ -191,11 +191,11 @@ for (const text of inputs) { expect(r.stderr).toBe(""); expect(r.stdout.split("\n")).toEqual([ "SyntaxError: Unexpected end of JSON input (same)", - "SyntaxError: Expected ',' or '}' after property value in JSON at position 19 (same)", - "SyntaxError: Bad escaped character in JSON at position 11 (same)", - "SyntaxError: Unexpected non-whitespace character after JSON at position 22 (same)", - 'SyntaxError: Unexpected token \']\', ...","x":[1,],"qty":"... is not valid JSON (same)', - "SyntaxError: Bad Unicode escape in JSON at position 21 (same)", + "SyntaxError: Unexpected number in JSON at position 19 (line 1 column 20) (same)", + "SyntaxError: Bad escaped character in JSON at position 11 (line 1 column 12) (same)", + "SyntaxError: Unexpected non-whitespace character after JSON at position 22 (line 1 column 23) (same)", + 'SyntaxError: Unexpected token \']\', ..."a","x":[1,],"qty":1}"... is not valid JSON (same)', + "SyntaxError: Bad Unicode escape in JSON at position 21 (line 1 column 22) (same)", "RangeError: Maximum call stack size exceeded (same)", "TypeError: expected number at $[0].qty, got undefined (plain ok)", "TypeError: expected number at $[1].qty, got boolean (plain ok)", @@ -268,7 +268,7 @@ try { "err TypeError: expected number at $.id, got undefined", "err TypeError: expected number at $.id, got null", "err TypeError: expected object at $, got array", - "err SyntaxError: Unexpected end of JSON input", + "err SyntaxError: Expected ',' or '}' after property value in JSON at position 39 (line 1 column 40)", "ok Infinity \uFFFD 0 ", "ok 7 reordered 0 ", "err expected number at $[1].qty, got string", From ff70c33e382cb5ef7666eb0f00450cb46750eeaf Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 11:59:33 -0500 Subject: [PATCH 109/259] Divide one-limb BigInt quotients in one pass and chain limb carries Dividing BigInts of the same limb count, where the quotient is one limb, takes Knuth's quotient estimate from the top limbs as they read normalized and settles it with one pass of a - q * b over the operands, instead of copying both operands shifted and running algorithm D. The remainder, when wanted, is that pass's result. The limb loops for add, subtract, multiply by a limb, and multiply-add and multiply-subtract by a limb process four limbs a pass, with the carries in add-with-carry chains (__builtin_addcll and __builtin_subcll where the compiler has them). --- packages/runtime/src/scr_bigint.c | 192 +++++++++++++++++++++++++++--- 1 file changed, 173 insertions(+), 19 deletions(-) diff --git a/packages/runtime/src/scr_bigint.c b/packages/runtime/src/scr_bigint.c index dd0a70ff7..5af2eafaa 100644 --- a/packages/runtime/src/scr_bigint.c +++ b/packages/runtime/src/scr_bigint.c @@ -215,30 +215,81 @@ static int bi_cmp_limbs(const bi_limb *a, size_t an, const bi_limb *b, size_t bn return 0; } -/* r = a + b over n limbs; returns the carry. r may alias a or b. */ +/* x + y + carry_in (0 or 1), with the carry out in *carry: the add-with- + * carry builtins compile to one adc chain. */ +#if defined(__has_builtin) +#if __has_builtin(__builtin_addcll) && __has_builtin(__builtin_subcll) && \ + __has_builtin(__builtin_addc) && __has_builtin(__builtin_subc) +#define BI_HAVE_ADDC 1 +#endif +#endif +static inline bi_limb bi_addc(bi_limb x, bi_limb y, bi_limb *carry) { +#if defined(BI_HAVE_ADDC) && BI_LIMB_BITS == 64 + unsigned long long c; + bi_limb s = __builtin_addcll(x, y, *carry, &c); + *carry = c; + return s; +#elif defined(BI_HAVE_ADDC) + unsigned c; + bi_limb s = __builtin_addc(x, y, *carry, &c); + *carry = c; + return s; +#else + bi_limb s = x + y; + bi_limb c1 = s < x; + bi_limb t = s + *carry; + *carry = c1 | (t < s); + return t; +#endif +} + +/* x - y - borrow_in (0 or 1), with the borrow out in *borrow. */ +static inline bi_limb bi_subc(bi_limb x, bi_limb y, bi_limb *borrow) { +#if defined(BI_HAVE_ADDC) && BI_LIMB_BITS == 64 + unsigned long long b; + bi_limb d = __builtin_subcll(x, y, *borrow, &b); + *borrow = b; + return d; +#elif defined(BI_HAVE_ADDC) + unsigned b; + bi_limb d = __builtin_subc(x, y, *borrow, &b); + *borrow = b; + return d; +#else + bi_limb d = x - y; + bi_limb b1 = x < y; + bi_limb t = d - *borrow; + *borrow = b1 | (d < *borrow); + return t; +#endif +} + +/* r = a + b over n limbs; returns the carry. r may alias a or b. Four + * limbs a pass keep the carry in one chain. */ static bi_limb bi_add_n(bi_limb *r, const bi_limb *a, const bi_limb *b, size_t n) { bi_limb carry = 0; - for (size_t i = 0; i < n; i++) { - bi_limb x = a[i], s = x + b[i]; - bi_limb c1 = s < x; - bi_limb t = s + carry; - carry = c1 | (t < s); - r[i] = t; + size_t i = 0; + for (; i + 4 <= n; i += 4) { + r[i] = bi_addc(a[i], b[i], &carry); + r[i + 1] = bi_addc(a[i + 1], b[i + 1], &carry); + r[i + 2] = bi_addc(a[i + 2], b[i + 2], &carry); + r[i + 3] = bi_addc(a[i + 3], b[i + 3], &carry); } + for (; i < n; i++) r[i] = bi_addc(a[i], b[i], &carry); return carry; } /* r = a - b over n limbs; returns the borrow. r may alias a or b. */ static bi_limb bi_sub_n(bi_limb *r, const bi_limb *a, const bi_limb *b, size_t n) { bi_limb borrow = 0; - for (size_t i = 0; i < n; i++) { - bi_limb x = a[i], y = b[i]; - bi_limb d = x - y; - bi_limb b1 = x < y; - bi_limb t = d - borrow; - borrow = b1 | (d < borrow); - r[i] = t; + size_t i = 0; + for (; i + 4 <= n; i += 4) { + r[i] = bi_subc(a[i], b[i], &borrow); + r[i + 1] = bi_subc(a[i + 1], b[i + 1], &borrow); + r[i + 2] = bi_subc(a[i + 2], b[i + 2], &borrow); + r[i + 3] = bi_subc(a[i + 3], b[i + 3], &borrow); } + for (; i < n; i++) r[i] = bi_subc(a[i], b[i], &borrow); return borrow; } @@ -277,9 +328,22 @@ static bi_limb bi_sub_into(bi_limb *r, size_t rn, const bi_limb *a, size_t an) { return borrow; } -/* r = a * m + carry over n limbs; returns the high limb. r may alias a. */ +/* r = a * m + carry over n limbs; returns the high limb. r may alias a. + * Four limbs a pass: the four products, then one carry chain adding each + * product's high limb into the next low limb. */ static bi_limb bi_mul1(bi_limb *r, const bi_limb *a, size_t n, bi_limb m, bi_limb carry) { - for (size_t i = 0; i < n; i++) { + size_t i = 0; + for (; i + 4 <= n; i += 4) { + bi_wide p0 = (bi_wide)a[i] * m, p1 = (bi_wide)a[i + 1] * m; + bi_wide p2 = (bi_wide)a[i + 2] * m, p3 = (bi_wide)a[i + 3] * m; + bi_limb c = 0; + r[i] = bi_addc((bi_limb)p0, carry, &c); + r[i + 1] = bi_addc((bi_limb)p1, (bi_limb)(p0 >> BI_LIMB_BITS), &c); + r[i + 2] = bi_addc((bi_limb)p2, (bi_limb)(p1 >> BI_LIMB_BITS), &c); + r[i + 3] = bi_addc((bi_limb)p3, (bi_limb)(p2 >> BI_LIMB_BITS), &c); + carry = (bi_limb)(p3 >> BI_LIMB_BITS) + c; + } + for (; i < n; i++) { bi_wide p = (bi_wide)a[i] * m + carry; r[i] = (bi_limb)p; carry = (bi_limb)(p >> BI_LIMB_BITS); @@ -287,10 +351,27 @@ static bi_limb bi_mul1(bi_limb *r, const bi_limb *a, size_t n, bi_limb m, bi_lim return carry; } -/* r += a * m over n limbs; returns the high limb. */ +/* r += a * m over n limbs; returns the high limb. Four limbs a pass: one + * carry chain forms the four product limbs, a second adds them to r. */ static bi_limb bi_addmul1(bi_limb *r, const bi_limb *a, size_t n, bi_limb m) { bi_limb carry = 0; - for (size_t i = 0; i < n; i++) { + size_t i = 0; + for (; i + 4 <= n; i += 4) { + bi_wide p0 = (bi_wide)a[i] * m, p1 = (bi_wide)a[i + 1] * m; + bi_wide p2 = (bi_wide)a[i + 2] * m, p3 = (bi_wide)a[i + 3] * m; + bi_limb c = 0, k = 0; + bi_limb t0 = bi_addc((bi_limb)p0, carry, &c); + bi_limb t1 = bi_addc((bi_limb)p1, (bi_limb)(p0 >> BI_LIMB_BITS), &c); + bi_limb t2 = bi_addc((bi_limb)p2, (bi_limb)(p1 >> BI_LIMB_BITS), &c); + bi_limb t3 = bi_addc((bi_limb)p3, (bi_limb)(p2 >> BI_LIMB_BITS), &c); + r[i] = bi_addc(r[i], t0, &k); + r[i + 1] = bi_addc(r[i + 1], t1, &k); + r[i + 2] = bi_addc(r[i + 2], t2, &k); + r[i + 3] = bi_addc(r[i + 3], t3, &k); + /* r + a * m over these limbs stays below B^5, so this cannot wrap */ + carry = (bi_limb)(p3 >> BI_LIMB_BITS) + c + k; + } + for (; i < n; i++) { bi_wide p = (bi_wide)a[i] * m + r[i] + carry; r[i] = (bi_limb)p; carry = (bi_limb)(p >> BI_LIMB_BITS); @@ -301,7 +382,23 @@ static bi_limb bi_addmul1(bi_limb *r, const bi_limb *a, size_t n, bi_limb m) { /* r -= a * m over n limbs; returns the borrow limb. */ static bi_limb bi_submul1(bi_limb *r, const bi_limb *a, size_t n, bi_limb m) { bi_limb carry = 0; - for (size_t i = 0; i < n; i++) { + size_t i = 0; + for (; i + 4 <= n; i += 4) { + bi_wide p0 = (bi_wide)a[i] * m, p1 = (bi_wide)a[i + 1] * m; + bi_wide p2 = (bi_wide)a[i + 2] * m, p3 = (bi_wide)a[i + 3] * m; + bi_limb c = 0, k = 0; + bi_limb t0 = bi_addc((bi_limb)p0, carry, &c); + bi_limb t1 = bi_addc((bi_limb)p1, (bi_limb)(p0 >> BI_LIMB_BITS), &c); + bi_limb t2 = bi_addc((bi_limb)p2, (bi_limb)(p1 >> BI_LIMB_BITS), &c); + bi_limb t3 = bi_addc((bi_limb)p3, (bi_limb)(p2 >> BI_LIMB_BITS), &c); + r[i] = bi_subc(r[i], t0, &k); + r[i + 1] = bi_subc(r[i + 1], t1, &k); + r[i + 2] = bi_subc(r[i + 2], t2, &k); + r[i + 3] = bi_subc(r[i + 3], t3, &k); + /* a * m + carry over these limbs stays below B^5: the borrow fits */ + carry = (bi_limb)(p3 >> BI_LIMB_BITS) + c + k; + } + for (; i < n; i++) { bi_wide p = (bi_wide)a[i] * m + carry; bi_limb lo = (bi_limb)p; carry = (bi_limb)(p >> BI_LIMB_BITS); @@ -543,6 +640,56 @@ static void bi_divmod_knuth(bi_limb *q, bi_limb *r, const bi_limb *a, size_t an, free(un); } +/* a / b for a and b of n >= 2 limbs each, b's top limb nonzero: the + * quotient is one limb. Knuth's estimate comes from the top limbs as + * they read normalized (three of a, two of b) and is the quotient or one + * more, which one pass of a - qhat * b over the operands as they are + * settles, with no normalized copies. r, unless NULL, receives the n + * limbs of a % b. */ +static bi_limb bi_div_qlimb(bi_limb *r, const bi_limb *a, const bi_limb *b, size_t n) { + unsigned s = bi_clz(b[n - 1]); + bi_limb d1 = b[n - 1], d0 = b[n - 2], u2 = 0, u1 = a[n - 1], u0 = a[n - 2]; + if (s) { + unsigned t = BI_LIMB_BITS - s; + bi_limb b3 = n >= 3 ? b[n - 3] : 0, a3 = n >= 3 ? a[n - 3] : 0; + d1 = (d1 << s) | (d0 >> t); + d0 = (d0 << s) | (b3 >> t); + u2 = u1 >> t; + u1 = (u1 << s) | (u0 >> t); + u0 = (u0 << s) | (a3 >> t); + } + bi_limb qhat, rhat; + bool rhat_big; /* rhat >= B: the estimate needs no further test */ + if (u2 >= d1) { + qhat = BI_LIMB_MAX; + rhat = u1 + d1; + rhat_big = rhat < d1; + } else { + bi_divisor top = bi_divisor_of(d1); + qhat = bi_div21(u2, u1, top.d, top.v, &rhat); + rhat_big = false; + } + while (!rhat_big && (bi_wide)qhat * d0 > (((bi_wide)rhat << BI_LIMB_BITS) | u0)) { + qhat--; + rhat += d1; + rhat_big = rhat < d1; + } + /* a - qhat * b: negative when the product's high limb or the borrow + * reaches past a's n limbs */ + bi_limb carry = 0, borrow = 0; + for (size_t i = 0; i < n; i++) { + bi_wide p = (bi_wide)b[i] * qhat + carry; + carry = (bi_limb)(p >> BI_LIMB_BITS); + bi_limb d = bi_subc(a[i], (bi_limb)p, &borrow); + if (r) r[i] = d; + } + if (carry || borrow) { + qhat--; + if (r) bi_add_n(r, r, b, n); + } + return qhat; +} + /* ---- comparisons and hashing ----------------------------------------- */ static int bi_cmp_abs(const ScrBigInt *a, const ScrBigInt *b) { @@ -709,6 +856,13 @@ static void bi_divmod_abs(const ScrBigInt *a, const ScrBigInt *b, ScrBigInt **qo if (rout) *rout = bi_u64_signed(rem, 1); return; } + if (an == bn) { + ScrBigInt *r = rout ? bi_alloc(bn) : NULL; + bi_limb q = bi_div_qlimb(r ? r->limb : NULL, a->limb, b->limb, bn); + if (qout) *qout = bi_u64_signed(q, 1); + if (rout) *rout = bi_finish(r, bn, 1); + return; + } size_t qn = an - bn + 1; ScrBigInt *q = bi_alloc(qn); ScrBigInt *r = rout ? bi_alloc(bn) : NULL; From 4f0975cbbe0d43e5ce2a3c2be936472227ff253c Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 12:01:26 -0500 Subject: [PATCH 110/259] Compile more npm and CommonJS JavaScript dependencies statically --- .../builtin-apis/intl-segmenter.mdx | 5 +- .../src/backend/executable-features.ts | 1 + .../compiler/src/backend/llvm/lib-shared.ts | 3 + .../src/backend/native-link-info-core.ts | 3 + .../compiler/src/backend/native/contracts.ts | 3 + .../compiler/src/backend/native/executable.ts | 2 + .../compiler/src/backend/runtime-pack-core.ts | 2 + .../src/executable/executable-cache.ts | 1 + .../src/frontend/lowering/binding-analysis.ts | 17 +- .../frontend/lowering/builtins/reflection.ts | 34 +++- .../lowering/class-dynamic-dispatch.ts | 1 + .../lowering/expressions/identifiers.ts | 32 +++ .../src/frontend/lowering/function-returns.ts | 17 ++ .../src/frontend/lowering/lower-calls.ts | 12 +- .../src/frontend/lowering/lower-classes.ts | 183 ++++++++++++------ .../src/frontend/lowering/lower-namespaces.ts | 50 ++++- .../src/frontend/lowering/lower-stmts.ts | 138 ++++++++++++- .../compiler/src/frontend/lowering/lowerer.ts | 35 +++- .../lowering/module-namespace-elements.ts | 124 +++++++++++- .../compiler/src/frontend/package-shims.ts | 47 +++-- packages/compiler/src/frontend/program.ts | 121 +++++++++--- packages/compiler/src/index.ts | 1 + packages/compiler/src/ir/builtin-effects.ts | 1 + .../compiler/src/ir/builtin-signatures.ts | 6 + packages/compiler/src/ir/runtime-features.ts | 4 + .../compiler/src/native/sanitizer.test.ts | 1 + .../main.ts.json | 6 + .../main.ts.json | 6 + .../main.ts.json | 6 + .../8218-cjs-namespace-imports/main.mjs.json | 9 + .../8219-cjs-stable-var-exports/main.js.json | 9 + .../main.js.json | 9 + .../main.ts.json | 6 + .../8222-js-class-static-reflection.js.json | 6 + .../runtime-pack-matrix.mjs | 2 + packages/runtime/src/scr_blob.h | 12 +- packages/runtime/src/scr_dyn.h | 3 + packages/runtime/src/scr_grapheme.c | 55 ++++++ packages/runtime/src/scr_json.c | 39 ++++ packages/runtime/src/scr_module_namespace.c | 121 ++++++++++++ .../8214-unshimmed-package-version/main.ts | 5 + .../node_modules/chalk/package.json | 1 + .../node_modules/chalk/source/index.d.ts | 3 + .../node_modules/chalk/source/index.js | 16 ++ .../node_modules/chalk/source/styles.js | 1 + .../8216-module-namespace-live-values/main.ts | 11 ++ .../node_modules/ns-registry/counter.js | 7 + .../node_modules/ns-registry/index.d.ts | 5 + .../node_modules/ns-registry/index.js | 40 ++++ .../node_modules/ns-registry/package.json | 1 + .../main.ts | 8 + .../node_modules/text-width/index.d.ts | 2 + .../node_modules/text-width/index.js | 11 ++ .../node_modules/text-width/package.json | 1 + .../client/index.mjs | 12 ++ .../client/package.json | 1 + .../client/transport.js | 26 +++ .../8218-cjs-namespace-imports/main.mjs | 13 ++ .../8218-cjs-namespace-imports/table.cjs | 10 + .../8219-cjs-stable-var-exports/lib/core.js | 31 +++ .../8219-cjs-stable-var-exports/lib/index.js | 8 + .../lib/options.js | 12 ++ .../8219-cjs-stable-var-exports/main.js | 21 ++ .../8219-cjs-stable-var-exports/package.json | 3 + .../classes/comparator.js | 22 +++ .../formdata.js | 26 +++ .../main.js | 39 ++++ .../package.json | 3 + .../ranges/outside.js | 13 ++ .../main.ts | 10 + .../node_modules/token-parser/dist/index.d.ts | 4 + .../node_modules/token-parser/dist/index.js | 131 +++++++++++++ .../node_modules/token-parser/package.json | 1 + .../corpus/8222-js-class-static-reflection.js | 94 +++++++++ .../cjs-mutable-exports/main.js | 5 + .../cjs-mutable-exports/package.json | 1 + .../cjs-mutable-exports/reassigned.js | 4 + .../cjs-mutable-exports/redeclared.js | 4 + .../cjs-mutable-exports/stable.js | 3 + .../cjs-mutable-exports/written.js | 4 + tests/diagnostics/intl-segmenter.ts | 4 +- .../node_modules/word-segments/index.d.ts | 1 + .../node_modules/word-segments/index.js | 9 + .../node_modules/word-segments/package.json | 1 + .../fixtures/npm-static/word-segments-cli.ts | 3 + .../__snapshots__/intl-segmenter.ts.txt | 10 +- .../main.ts.json | 1 + .../main.ts.json | 1 + .../main.ts.json | 1 + .../8218-cjs-namespace-imports/main.mjs.json | 1 + .../8219-cjs-stable-var-exports/main.js.json | 1 + .../main.js.json | 1 + .../main.ts.json | 1 + .../8222-js-class-static-reflection.js.json | 1 + tests/harness/coverage.test.ts | 10 + tests/harness/npm-static.test.ts | 22 +++ tests/harness/package-shims.test.ts | 30 ++- 97 files changed, 1725 insertions(+), 119 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8214-unshimmed-package-version/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8216-module-namespace-live-values/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8217-intl-segmenter-word-construct/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8218-cjs-namespace-imports/main.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8219-cjs-stable-var-exports/main.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8220-js-class-static-destructuring/main.js.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8221-js-recursive-generator-returns/main.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8222-js-class-static-reflection.js.json create mode 100644 packages/runtime/src/scr_module_namespace.c create mode 100644 tests/corpus/8214-unshimmed-package-version/main.ts create mode 100644 tests/corpus/8214-unshimmed-package-version/node_modules/chalk/package.json create mode 100644 tests/corpus/8214-unshimmed-package-version/node_modules/chalk/source/index.d.ts create mode 100644 tests/corpus/8214-unshimmed-package-version/node_modules/chalk/source/index.js create mode 100644 tests/corpus/8214-unshimmed-package-version/node_modules/chalk/source/styles.js create mode 100644 tests/corpus/8216-module-namespace-live-values/main.ts create mode 100644 tests/corpus/8216-module-namespace-live-values/node_modules/ns-registry/counter.js create mode 100644 tests/corpus/8216-module-namespace-live-values/node_modules/ns-registry/index.d.ts create mode 100644 tests/corpus/8216-module-namespace-live-values/node_modules/ns-registry/index.js create mode 100644 tests/corpus/8216-module-namespace-live-values/node_modules/ns-registry/package.json create mode 100644 tests/corpus/8217-intl-segmenter-word-construct/main.ts create mode 100644 tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/index.d.ts create mode 100644 tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/index.js create mode 100644 tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/package.json create mode 100644 tests/corpus/8218-cjs-namespace-imports/client/index.mjs create mode 100644 tests/corpus/8218-cjs-namespace-imports/client/package.json create mode 100644 tests/corpus/8218-cjs-namespace-imports/client/transport.js create mode 100644 tests/corpus/8218-cjs-namespace-imports/main.mjs create mode 100644 tests/corpus/8218-cjs-namespace-imports/table.cjs create mode 100644 tests/corpus/8219-cjs-stable-var-exports/lib/core.js create mode 100644 tests/corpus/8219-cjs-stable-var-exports/lib/index.js create mode 100644 tests/corpus/8219-cjs-stable-var-exports/lib/options.js create mode 100644 tests/corpus/8219-cjs-stable-var-exports/main.js create mode 100644 tests/corpus/8219-cjs-stable-var-exports/package.json create mode 100644 tests/corpus/8220-js-class-static-destructuring/classes/comparator.js create mode 100644 tests/corpus/8220-js-class-static-destructuring/formdata.js create mode 100644 tests/corpus/8220-js-class-static-destructuring/main.js create mode 100644 tests/corpus/8220-js-class-static-destructuring/package.json create mode 100644 tests/corpus/8220-js-class-static-destructuring/ranges/outside.js create mode 100644 tests/corpus/8221-js-recursive-generator-returns/main.ts create mode 100644 tests/corpus/8221-js-recursive-generator-returns/node_modules/token-parser/dist/index.d.ts create mode 100644 tests/corpus/8221-js-recursive-generator-returns/node_modules/token-parser/dist/index.js create mode 100644 tests/corpus/8221-js-recursive-generator-returns/node_modules/token-parser/package.json create mode 100644 tests/corpus/8222-js-class-static-reflection.js create mode 100644 tests/coverage-fixtures/cjs-mutable-exports/main.js create mode 100644 tests/coverage-fixtures/cjs-mutable-exports/package.json create mode 100644 tests/coverage-fixtures/cjs-mutable-exports/reassigned.js create mode 100644 tests/coverage-fixtures/cjs-mutable-exports/redeclared.js create mode 100644 tests/coverage-fixtures/cjs-mutable-exports/stable.js create mode 100644 tests/coverage-fixtures/cjs-mutable-exports/written.js create mode 100644 tests/fixtures/npm-static/node_modules/word-segments/index.d.ts create mode 100644 tests/fixtures/npm-static/node_modules/word-segments/index.js create mode 100644 tests/fixtures/npm-static/node_modules/word-segments/package.json create mode 100644 tests/fixtures/npm-static/word-segments-cli.ts create mode 100644 tests/harness/corpus-costs/8214-unshimmed-package-version/main.ts.json create mode 100644 tests/harness/corpus-costs/8216-module-namespace-live-values/main.ts.json create mode 100644 tests/harness/corpus-costs/8217-intl-segmenter-word-construct/main.ts.json create mode 100644 tests/harness/corpus-costs/8218-cjs-namespace-imports/main.mjs.json create mode 100644 tests/harness/corpus-costs/8219-cjs-stable-var-exports/main.js.json create mode 100644 tests/harness/corpus-costs/8220-js-class-static-destructuring/main.js.json create mode 100644 tests/harness/corpus-costs/8221-js-recursive-generator-returns/main.ts.json create mode 100644 tests/harness/corpus-costs/8222-js-class-static-reflection.js.json diff --git a/docs/content/limitations/builtin-apis/intl-segmenter.mdx b/docs/content/limitations/builtin-apis/intl-segmenter.mdx index 41a61711c..2682acaf0 100644 --- a/docs/content/limitations/builtin-apis/intl-segmenter.mdx +++ b/docs/content/limitations/builtin-apis/intl-segmenter.mdx @@ -1,2 +1,3 @@ -- **Intl.Segmenter:** Default Unicode grapheme segmentation, iteration, and `containing()` compile. - Locale negotiation, word and sentence segmentation, `resolvedOptions()`, and detached methods are unsupported. +- **Intl.Segmenter:** Unicode grapheme segmentation, iteration, and `containing()` compile, with the default locale or one language tag of the form language[-script][-region] written as a string literal (grapheme clusters do not depend on the locale). + In JavaScript dependencies, word and sentence segmenters construct, and their `segment()` throws an SC2020 error. + Locale negotiation over several locales, word and sentence segmentation, `resolvedOptions()`, and detached methods are unsupported. diff --git a/packages/compiler/src/backend/executable-features.ts b/packages/compiler/src/backend/executable-features.ts index 2afb887ea..b51f957a3 100644 --- a/packages/compiler/src/backend/executable-features.ts +++ b/packages/compiler/src/backend/executable-features.ts @@ -19,6 +19,7 @@ export function executableLinkFeatures(mod: IrModule): NativeLinkFeatures { ...(features.wasm ? { wasm: true } : {}), ...(features.warningReplace ? { warningReplace: true } : {}), ...(features.stdioExtended ? { stdioExtended: true } : {}), + ...(features.moduleNamespace ? { moduleNamespace: true } : {}), zlib: features.zlib, ...(features.brotli ? { brotli: true } : {}), assert: features.assert, diff --git a/packages/compiler/src/backend/llvm/lib-shared.ts b/packages/compiler/src/backend/llvm/lib-shared.ts index 7a16c37e8..de2fbaa2e 100644 --- a/packages/compiler/src/backend/llvm/lib-shared.ts +++ b/packages/compiler/src/backend/llvm/lib-shared.ts @@ -40,6 +40,7 @@ export const LIB_FN_SYMS: Record = { "insp.jsonDyn": "scr_util_format_j", "http.reqH2StreamOrThrow": "scr_http_req_h2_stream_or_throw", "intl.segmenterNew": "scr_intl_segmenter_new", + "intl.segmenterRefusing": "scr_intl_segmenter_refusing", "weakMap.is": "scr_weak_map_is", "weakSet.is": "scr_weak_set_is", "weakMap.new": "scr_weak_map_new", @@ -254,6 +255,7 @@ export const LIB_FN_SYMS: Record = { "global.native": "scr_global_native", "process.builtinModule": "scr_process_builtin_module", "process.builtinUnsupported": "scr_process_builtin_unsupported", + "module.namespaceValue": "scr_module_namespace_value", "fs.callbackValue": "scr_fs_callback_value", "fs.callbackCall": "scr_fs_callback_call", "process.hrtimeValue": "scr_process_hrtime_value", @@ -987,6 +989,7 @@ export const LIB_FN_SYMS: Record = { "dyn.keySetComputed": "scr_dyn_key_set_computed", "dyn.keyDelete": "scr_dyn_key_delete", "dyn.keyDeleteComputed": "scr_dyn_key_delete_computed", + "dyn.reflectDeleteProperty": "scr_dyn_reflect_delete_property", "dyn.hasKeyComputed": "scr_dyn_has_key_computed", "dyn.hasOwnComputed": "scr_dyn_has_own_computed", "dyn.propertyIsEnumerableComputed": "scr_dyn_property_is_enumerable_computed", diff --git a/packages/compiler/src/backend/native-link-info-core.ts b/packages/compiler/src/backend/native-link-info-core.ts index 1e9994422..6af58fb0e 100644 --- a/packages/compiler/src/backend/native-link-info-core.ts +++ b/packages/compiler/src/backend/native-link-info-core.ts @@ -34,6 +34,9 @@ export interface NativeLinkFeatures { /** The program uses process.stdin.setEncoding, string 'data' listeners * or stdio 'resize' events: links the SCR_STDIO_EXTENDED events unit. */ stdioExtended?: boolean; + /** Module namespace objects as checked-dynamic values link + * scr_module_namespace.c; absent (false) otherwise. */ + moduleNamespace?: boolean; zlib: boolean; /** node:zlib's Brotli forms: scr_brotli.c and the vendored brotli archive. */ brotli?: boolean; diff --git a/packages/compiler/src/backend/native/contracts.ts b/packages/compiler/src/backend/native/contracts.ts index 40bb2352b..ce89cb829 100644 --- a/packages/compiler/src/backend/native/contracts.ts +++ b/packages/compiler/src/backend/native/contracts.ts @@ -147,6 +147,9 @@ export interface CcOptions { warningReplace?: boolean; /** SCR_STDIO_EXTENDED: stdin encoding, string data listeners, resize. */ stdioExtended?: boolean; + /** Module namespace objects as checked-dynamic values: compiles + * scr_module_namespace.c. */ + moduleNamespace?: boolean; /** The program uses the process-events surface (signal/exit listeners, * stdin events, for-await over stdin — moduleUsesProcessEvents on the * IR): compiles scr_events.c into the binary. Event-free binaries keep diff --git a/packages/compiler/src/backend/native/executable.ts b/packages/compiler/src/backend/native/executable.ts index ceb162bcc..1dd88117e 100644 --- a/packages/compiler/src/backend/native/executable.ts +++ b/packages/compiler/src/backend/native/executable.ts @@ -194,6 +194,8 @@ const RUNTIME_UNITS: readonly RuntimeUnit[] = [ unit((u) => u.opts.dynTier, "scr_js_value.c", "scr_js_object.c"), unit((u) => u.opts.eventTarget || u.nativeFetch, "scr_event_target.c"), unit((u) => u.opts.wasm, "scr_wasm.c"), + // Module namespace objects as checked-dynamic values. + unit((u) => u.opts.moduleNamespace === true, "scr_module_namespace.c"), unit( (u) => u.opts.dynAsync || diff --git a/packages/compiler/src/backend/runtime-pack-core.ts b/packages/compiler/src/backend/runtime-pack-core.ts index 49165d8df..22bba85d2 100644 --- a/packages/compiler/src/backend/runtime-pack-core.ts +++ b/packages/compiler/src/backend/runtime-pack-core.ts @@ -94,6 +94,7 @@ export interface RuntimeFeatureSet extends NativeLinkFeatures { warningReplace: boolean; stdioExtended: boolean; brotli: boolean; + moduleNamespace: boolean; nativeFetch: boolean; netEffective: boolean; httpEffective: boolean; @@ -293,6 +294,7 @@ export function effectiveRuntimeFeatures( warningReplace: features.warningReplace === true, stdioExtended: features.stdioExtended === true, brotli: features.brotli === true, + moduleNamespace: features.moduleNamespace === true, nativeFetch, netEffective, httpEffective, diff --git a/packages/compiler/src/executable/executable-cache.ts b/packages/compiler/src/executable/executable-cache.ts index 754c20648..e641b8db0 100644 --- a/packages/compiler/src/executable/executable-cache.ts +++ b/packages/compiler/src/executable/executable-cache.ts @@ -62,6 +62,7 @@ export interface EarlyExecutableNativeFeatures { wasm?: boolean; warningReplace?: boolean; stdioExtended?: boolean; + moduleNamespace?: boolean; zlib: boolean; brotli?: boolean; assert: boolean; diff --git a/packages/compiler/src/frontend/lowering/binding-analysis.ts b/packages/compiler/src/frontend/lowering/binding-analysis.ts index 1987c86ba..c88c06c90 100644 --- a/packages/compiler/src/frontend/lowering/binding-analysis.ts +++ b/packages/compiler/src/frontend/lowering/binding-analysis.ts @@ -19,6 +19,18 @@ export function bindingNeverReassigned( ): boolean { const cached = lowerer.neverReassignedCache.get(sym); if (cached !== undefined) return cached; + const written = fileWritesBinding(sym, ts.getSourceFileOfNode(decl), resolve); + lowerer.neverReassignedCache.set(sym, !written); + return !written; +} + +/** True when something in `file` writes `sym` (the writes + * bindingNeverReassigned counts), resolving identifiers with `resolve`. */ +export function fileWritesBinding( + sym: ts.Symbol, + file: ts.SourceFile, + resolve: (ident: ts.Identifier) => ts.Symbol | null | undefined, +): boolean { let written = false; // Text pre-check keeps the file walk cheap: only same-named // identifiers pay a symbol resolution. @@ -62,9 +74,8 @@ export function bindingNeverReassigned( } ts.forEachChild(n, visit); }; - ts.forEachChild(ts.getSourceFileOfNode(decl), visit); - lowerer.neverReassignedCache.set(sym, !written); - return !written; + ts.forEachChild(file, visit); + return written; } /** Strips the value-preserving wrappers off an expression: parens, diff --git a/packages/compiler/src/frontend/lowering/builtins/reflection.ts b/packages/compiler/src/frontend/lowering/builtins/reflection.ts index 8e1e6fd94..2ce07ea2f 100644 --- a/packages/compiler/src/frontend/lowering/builtins/reflection.ts +++ b/packages/compiler/src/frontend/lowering/builtins/reflection.ts @@ -3,7 +3,8 @@ import * as ts from "../../ts7/adapter.js"; import { type Lowerer } from "../lowerer.js"; import { locOf } from "../../program.js"; import { builtinModuleFnOf } from "../surfaces.js"; -import { BOOL, DYN, type IrExpr, STRING, arrayOf } from "../../../ir/ir.js"; +import { hasRuntimeStatics } from "../class-runtime-statics.js"; +import { BOOL, DYN, type IrExpr, STRING, arrayOf, isUnitType } from "../../../ir/ir.js"; /** Reflect.ownKeys uses native computed-key reflection. Reflect.apply(target, * thisArg, argsList) where the TARGET is a builtin @@ -63,6 +64,37 @@ export function lowerReflectCall( loc, }; } + // Reflect.deleteProperty over a value with a live property table: a + // checked-dynamic value, or a JavaScript class whose statics are runtime + // properties of its constructor + // (`Reflect.deleteProperty(Response, "getResponseState")`). + if ( + reflectMember === "deleteProperty" && + call.arguments.nodes.length === 2 && + !call.arguments.nodes.some(ts.isSpreadElement) + ) { + const loc = locOf(call); + let target = lowerer.lowerExpr(call.arguments.nodes[0]!); + const info = + target.type.kind === "classval" ? lowerer.classes.get(target.type.className) : undefined; + // A primitive target throws the TypeError, so it boxes as is. + const primitive = + isUnitType(target.type) || + ["bool", "f64", "string", "bigint", "symbol"].includes(target.type.kind); + if ( + primitive || + (info !== undefined && hasRuntimeStatics(info) && lowerer.dynConvertible(target.type)) + ) + target = lowerer.coerceToExpected(target, DYN); + if (target.type.kind !== "dyn") return null; + return { + kind: "libCall", + fn: "dyn.reflectDeleteProperty", + args: [target, lowerer.lowerExprExpecting(call.arguments.nodes[1]!, DYN)], + type: BOOL, + loc, + }; + } if (reflectMember === "get" || reflectMember === "set") { const required = reflectMember === "get" ? 2 : 3; if ( diff --git a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts index fc6d0a922..a943b9156 100644 --- a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts +++ b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts @@ -262,6 +262,7 @@ const KEY_CALLS = new Map([ ["dyn.propertyIsEnumerableComputed", "any"], ["dyn.hasOwnComputed", "value"], ["dyn.keyDeleteComputed", "value"], + ["dyn.reflectDeleteProperty", "object"], ["dyn.keySetComputed", "value"], ]); diff --git a/packages/compiler/src/frontend/lowering/expressions/identifiers.ts b/packages/compiler/src/frontend/lowering/expressions/identifiers.ts index f7ba7a115..db1c1938a 100644 --- a/packages/compiler/src/frontend/lowering/expressions/identifiers.ts +++ b/packages/compiler/src/frontend/lowering/expressions/identifiers.ts @@ -57,6 +57,7 @@ import { contextualUndefReadType, fenceEarlyAliasUse, isTemporalGlobalRoot, + cjsNamespaceImportDep, lowerNsIdentifierValue, nsUndefRead, } from "../lower-namespaces.js"; @@ -958,6 +959,37 @@ export function lowerIdentifierExpr(lowerer: Lowerer, expr: ts.Identifier, loc: // representation (ambient namespaces compile to Node's // ReferenceError instead — the object never exists at runtime). { + // `ns.name` through a namespace import of a CommonJS module, where Node's + // namespace has no `name` property (its lexer does not detect it), or + // `ns.default` (module.exports itself). + const cjsNamespace = cjsNamespaceImportDep(lowerer, expr); + if ( + cjsNamespace !== null && + ts.isPropertyAccessExpression(expr.parent) && + expr.parent.expression === expr && + ts.isIdentifier(expr.parent.name) + ) { + const name = expr.parent.name.text; + const { names, assignedLater } = lowerer.cjsNamespaceOf(cjsNamespace); + if (name === "default") + lowerer.unsupported( + "SC1090", + expr.parent, + `reads of 'default' through namespace imports of CommonJS modules (module.exports itself: read it through a default import)`, + ); + if (!names.has(name)) + lowerer.unsupported( + "SC1090", + expr.parent, + `reads of '${name}' through namespace imports of CommonJS modules (Node's lexer does not detect '${name}' among the module's exports, so Node reads undefined)`, + ); + if (assignedLater === "all" || assignedLater.has(name)) + lowerer.unsupported( + "SC1090", + expr.parent, + `reads of '${name}' through namespace imports of CommonJS modules whose functions assign exports (Node's namespace keeps the values from the end of the module's evaluation)`, + ); + } const moduleNs = lowerer.mapTypeOf(lowerer.typeOf(expr)); if (moduleNs?.kind === "moduleNs") { return { kind: "moduleNsRef", moduleId: moduleNs.moduleId, type: moduleNs, loc }; diff --git a/packages/compiler/src/frontend/lowering/function-returns.ts b/packages/compiler/src/frontend/lowering/function-returns.ts index 6d0989e2b..c4563a234 100644 --- a/packages/compiler/src/frontend/lowering/function-returns.ts +++ b/packages/compiler/src/frontend/lowering/function-returns.ts @@ -175,6 +175,23 @@ export function declaredReturnType( // `() => void`), and throw-only callbacks are ordinary code // (`.action(() => { throw ... })`). `never` VALUES stay unmapped. if (retTsType.flags & ts.TypeFlags.Never) return VOID; + // A JS generator whose result the checker cannot infer (mutually + // recursive methods returning `yield*` of each other, as in yaml's + // Parser) has the return type `any`: a generator over untyped values. + if ( + isJsSourceFile(ts.getSourceFileOfNode(decl)) && + decl.asteriskToken && + retTsType.flags & ts.TypeFlags.Any + ) + return { + kind: "generator", + ...(decl.modifiers?.nodes.some((modifier) => modifier.kind === ts.SyntaxKind.AsyncKeyword) + ? { async: true as const } + : {}), + yieldT: DYN, + retT: DYN, + nextT: DYN, + }; let mappedReturn = lowerer.mapTypeOf(retTsType); // A generator declared to return Iterable returns a generator over T. if (mappedReturn && decl.asteriskToken) diff --git a/packages/compiler/src/frontend/lowering/lower-calls.ts b/packages/compiler/src/frontend/lowering/lower-calls.ts index 14565aebc..4b833ee50 100644 --- a/packages/compiler/src/frontend/lowering/lower-calls.ts +++ b/packages/compiler/src/frontend/lowering/lower-calls.ts @@ -8464,7 +8464,17 @@ function lowerObjectStaticCall( ...(fnName !== null ? { fnName } : {}), }; } - if (target && isUnitType(target.type)) { + // A class value whose statics are runtime properties of its constructor + // boxes to that constructor function, as for Object.defineProperty above. + const runtimeStaticClass = + target?.type.kind === "classval" ? lowerer.classes.get(target.type.className) : undefined; + if ( + target && + (isUnitType(target.type) || + (runtimeStaticClass !== undefined && + hasRuntimeStatics(runtimeStaticClass) && + lowerer.dynConvertible(target.type))) + ) { target = { kind: "dynFrom", value: target, type: DYN, loc: locOf(call.arguments.nodes[0]!) }; } if (target?.type.kind === "dyn") { diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index b829b6ddc..e50466114 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -11,7 +11,7 @@ import { lowerDateStaticCall } from "./builtins/dates.js"; import { keyedHelperName } from "./stable-names.js"; import { lowerValueReturningConstructorNew } from "./js-dynamic-objects.js"; import { adaptPromiseExecutor } from "./promise-executor-adapter.js"; -import { dynUndefinedExpr, nodeThrowExpr, varRef } from "../../ir/build.js"; +import { dynUndefinedExpr, nodeThrowExpr, strLit, varRef } from "../../ir/build.js"; import { constructedFromValue, constructedValue, @@ -124,6 +124,7 @@ import { lowerWorkerNew, } from "./builtins/workers.js"; import { + noLoweringDiag, unsupportedPackageValueDiag, unsupportedDiag, type ScrDiagnostic, @@ -5687,15 +5688,22 @@ export function lowerStaticFieldRead( ): IrExpr | null { if (expr.name.text === "prototype") return null; if (expr.questionDotToken) return null; + const info = staticReceiverClass(lowerer, expr.expression); + if (!info) return null; + return lowerClassStaticRead(lowerer, info, expr.name.text, expr.expression, expr); +} + +/** The class a static member read through `receiver` reads exactly: the + * class a name binds (directly, through a require binding, or through a + * const alias), or null. */ +export function staticReceiverClass(lowerer: Lowerer, receiver: ts.Expression): ClassInfo | null { if ( - !ts.isIdentifier(expr.expression) && - expr.expression.kind !== ts.SyntaxKind.ThisKeyword && - exactClassOfReceiver(lowerer, expr.expression) === null + !ts.isIdentifier(receiver) && + receiver.kind !== ts.SyntaxKind.ThisKeyword && + exactClassOfReceiver(lowerer, receiver) === null ) return null; - const symbol = ts.isIdentifier(expr.expression) - ? lowerer.resolveValueSymbol(expr.expression) - : null; + const symbol = ts.isIdentifier(receiver) ? lowerer.resolveValueSymbol(receiver) : null; const info = (symbol ? lowerer.classBySymbol.get(symbol) : undefined) ?? // A require binding over `module.exports = class {…}` (the alias @@ -5703,7 +5711,7 @@ export function lowerStaticFieldRead( // or `C.name` below would fall through to paths that answer for // stdlib globals instead of this class. propertyAssignedClassInfoOf(lowerer, symbol) ?? - exactClassOfReceiver(lowerer, expr.expression) ?? + exactClassOfReceiver(lowerer, receiver) ?? undefined; if (!info) return null; // A decorated name that can REBIND (a replacing decorator): the @@ -5712,22 +5720,36 @@ export function lowerStaticFieldRead( // whose devirtualization and .name rules answer for every legal // runtime value. if (info.classDecorators?.valueGlobalId !== undefined) return null; - const loc = locOf(expr); - const found = findStaticOn(lowerer, info, expr.name.text); + return info; +} + +/** The static member `name` of `info` read through `receiver` (an exact + * reference to the class, see staticReceiverClass): `C.name` for the + * property access `site`, or a destructuring element over `C` whose + * initializer is `site`. Null when the class has no such member. */ +export function lowerClassStaticRead( + lowerer: Lowerer, + info: ClassInfo, + name: string, + receiver: ts.Expression, + site: ts.Expression, +): IrExpr | null { + const loc = locOf(site); + const found = findStaticOn(lowerer, info, name); // A Date static read as a value through a class declared `extends Date`: // the statics lower only as calls. if ( !found && dateRootOf(info) && - ["now", "parse", "UTC"].includes(expr.name.text) && - !(ts.isCallExpression(expr.parent) && expr.parent.expression === expr) + ["now", "parse", "UTC"].includes(name) && + !(ts.isCallExpression(site.parent) && site.parent.expression === site) ) - lowerer.noLowering(`Date.${expr.name.text} read through a class that extends Date`, expr); + lowerer.noLowering(`Date.${name} read through a class that extends Date`, site); if (hasRuntimeStatics(info) && !found?.field) return { kind: "dynKeyGet", - value: lowerer.coerceToExpected(classValueRef(lowerer, info, expr.expression), DYN), - key: { kind: "strLit", value: expr.name.text, type: STRING, loc }, + value: lowerer.coerceToExpected(classValueRef(lowerer, info, receiver), DYN), + key: { kind: "strLit", value: name, type: STRING, loc }, type: DYN, loc, }; @@ -5735,11 +5757,11 @@ export function lowerStaticFieldRead( // name: in JS the brand lives on that one constructor object, so // `D.#s` (a subclass receiver) throws Node's TypeError instead of // reaching up the chain — reported as SC1090 instead of resolved. - if (found && expr.name.text.startsWith("#") && found.declarer !== info) { + if (found && name.startsWith("#") && found.declarer !== info) { lowerer.unsupported( "SC1090", - expr, - `reading the private static '${expr.name.text}' through the subclass '${info.def.name.replace(/^%|^%m\d+\./, "")}' (JS brands the declaring class object alone — Node throws a TypeError here; spell the declaring class's name)`, + site, + `reading the private static '${name}' through the subclass '${info.def.name.replace(/^%|^%m\d+\./, "")}' (JS brands the declaring class object alone — Node throws a TypeError here; spell the declaring class's name)`, ); } if (found?.field !== undefined) { @@ -5749,29 +5771,31 @@ export function lowerStaticFieldRead( type: found.field.type, loc, }; - return found.field.runtimeOptional ? value : lowerer.maybeNarrow(value, expr); + return found.field.runtimeOptional || !ts.isPropertyAccessExpression(site) + ? value + : lowerer.maybeNarrow(value, site); } if (found) { - return staticMethodValue(lowerer, found.declarer, expr.name.text, found.method, expr, loc); + return staticMethodValue(lowerer, found.declarer, name, found.method, site, loc); } // A GENERIC static method as a VALUE: the pinned-value rule verbatim // (lowerGenericFnValue) — a slot spelling one concrete signature names // an instance, an unpinned reference fences by name. { - const gfound = findGenericStaticOn(lowerer, info, expr.name.text); - if (gfound) return lowerer.lowerGenericFnValue(expr, gfound.info); + const gfound = findGenericStaticOn(lowerer, info, name); + if (gfound) return lowerer.lowerGenericFnValue(site, gfound.info); } // `C.name` — the JS-observable class name, a compile-time constant on // the direct spelling (tsc rejects user statics named `name`, so the // chain above can never shadow it in TypeScript sources). A class of an // import cycle reads it from its class object instead, whose reference // checks the class's initialization (checkCycleBindingAccesses). - if (expr.name.text === "name" && info.def.jsName !== undefined) { + if (name === "name" && info.def.jsName !== undefined) { if (lowerer.classInitFlags.get(info.def.name)?.cycle === true) return { kind: "libCall", fn: "class.name", - args: [classValueRef(lowerer, info, expr.expression)], + args: [classValueRef(lowerer, info, receiver)], type: STRING, loc, }; @@ -5780,26 +5804,26 @@ export function lowerStaticFieldRead( if (info.callableBase) return { kind: "dynKeyGet", - value: lowerer.coerceToExpected(classValueRef(lowerer, info, expr.expression), DYN), - key: { kind: "strLit", value: expr.name.text, type: STRING, loc }, + value: lowerer.coerceToExpected(classValueRef(lowerer, info, receiver), DYN), + key: { kind: "strLit", value: name, type: STRING, loc }, type: DYN, loc, }; - const data = classStaticDataFor(lowerer, info, expr.name.text, loc); + const data = classStaticDataFor(lowerer, info, name, loc); if (data) { const value: IrExpr = { kind: "dynKeyGet", value: data, - key: { kind: "strLit", value: expr.name.text, type: STRING, loc }, + key: { kind: "strLit", value: name, type: STRING, loc }, type: DYN, loc, }; // JavaScript often assigns public statics after the class declaration. // Their storage stays mutable and checked, while reads retain the // checker's concrete type instead of losing the method receiver. - const type = isJsSourceFile(ts.getSourceFileOfNode(expr)) + const type = isJsSourceFile(ts.getSourceFileOfNode(site)) ? null - : lowerer.mapTypeOf(lowerer.typeOf(expr)); + : lowerer.mapTypeOf(lowerer.typeOf(site)); return type ? lowerer.coerceToExpected(value, type) : value; } return null; @@ -6625,7 +6649,7 @@ function staticCallOn( kind: "dynInvoke", recv: lowerer.lowerExprExpecting(access.expression, DYN), method: access.name.text, - calleeName: access.name.text, + calleeName: ts.getTextOfNode(access), args: call.arguments.nodes.map((argument) => lowerer.lowerExprExpecting(argument, DYN)), type: DYN, loc, @@ -9902,34 +9926,47 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { const args = expr.arguments?.nodes ?? []; const undefinedArg = (arg: ts.Expression): boolean => (lowerer.typeOf(arg).flags & ts.TypeFlags.Undefined) !== 0; - if (args.length > 2 || (args[0] && !undefinedArg(args[0]))) { + // A literal language tag: Unicode grapheme clusters have no locale + // tailoring. Only tags of the form language[-script][-region] are + // accepted; each is well-formed, so Node constructs the segmenter + // without the RangeError a malformed tag throws. + const literalLocale = (arg: ts.Expression): boolean => + ts.isStringLiteralLike(arg) && + /^[A-Za-z]{2,3}(-[A-Za-z]{4})?(-([A-Za-z]{2}|[0-9]{3}))?$/.test(arg.text); + if (args.length > 2 || (args[0] && !undefinedArg(args[0]) && !literalLocale(args[0]))) { lowerer.noLowering( "Intl.Segmenter locale negotiation", expr, - "omit the locale or pass undefined for default Unicode grapheme segmentation", + "omit the locale, pass undefined, or pass one language tag as a string literal", ); } + // JavaScript dependencies may construct word and sentence segmenters + // that they use only on some paths (pi-tui's shared word segmenter): + // the construction compiles and their segment() throws SC2020. + // TypeScript sources keep the build-time refusal. + const granularities = isJsSourceFile(ts.getSourceFileOfNode(expr)) + ? ["grapheme", "word", "sentence"] + : ["grapheme"]; const options = args[1]; - if ( - options && - !undefinedArg(options) && - !( - ts.isObjectLiteralExpression(options) && - options.properties.nodes.every( - (property) => - ts.isPropertyAssignment(property) && - (ts.isIdentifier(property.name) || ts.isStringLiteral(property.name)) && - property.name.text === "granularity" && - ts.isStringLiteral(property.initializer) && - property.initializer.text === "grapheme", - ) - ) - ) { - lowerer.noLowering( - "Intl.Segmenter options", - options, - 'the native segmenter supports default options and { granularity: "grapheme" }; word and sentence segmentation remain unsupported', - ); + let granularity = "grapheme"; + if (options && !undefinedArg(options)) { + const properties = ts.isObjectLiteralExpression(options) ? options.properties.nodes : null; + const property = properties?.length === 1 ? properties[0] : undefined; + if ( + property === undefined || + !ts.isPropertyAssignment(property) || + !(ts.isIdentifier(property.name) || ts.isStringLiteral(property.name)) || + property.name.text !== "granularity" || + !ts.isStringLiteral(property.initializer) || + !granularities.includes(property.initializer.text) + ) { + lowerer.noLowering( + "Intl.Segmenter options", + options, + 'the native segmenter supports default options and { granularity: "grapheme" }; word and sentence segmentation remain unsupported', + ); + } + granularity = property.initializer.text; } // Explicit undefined expressions can carry effects; retain argument order. const stmts: IrStmt[] = args.map((arg) => { @@ -9940,7 +9977,28 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { loc: locOf(arg), }; }); - const result: IrExpr = { kind: "libCall", fn: "intl.segmenterNew", args: [], type: DYN, loc }; + let result: IrExpr = { kind: "libCall", fn: "intl.segmenterNew", args: [], type: DYN, loc }; + // A word or sentence segmenter carries its segment() refusal, which + // coverage lists as deferred to runtime. + if (granularity !== "grapheme") { + const surface = `Intl.Segmenter segmentation with granularity '${granularity}'`; + lowerer.runtimeFences.push( + noLoweringDiag( + surface, + loc, + "only grapheme segmenters segment; word and sentence segmenters construct", + ), + ); + const line = ts.getLineAndCharacterOfPosition(ts.getSourceFileOfNode(expr), loc.start).line; + const refusal = `${surface} is not supported yet [SC2020 at ${loc.file}:${line + 1}]`; + result = { + kind: "libCall", + fn: "intl.segmenterRefusing", + args: [strLit(refusal, loc)], + type: DYN, + loc, + }; + } return stmts.length ? { kind: "seqExpr", stmts, result, type: DYN, loc } : result; } // A package declaration without a compiled constructor cannot provide @@ -11266,13 +11324,18 @@ function genericFieldFnNodeOf( } /** Whether a JavaScript class's own binding is the target of - * `Object.defineProperty`/`defineProperties` in its file - * (`Object.defineProperty(Definition, "name", { value })`): its constructor + * `Object.defineProperty`/`defineProperties` or `Reflect.deleteProperty` in + * its file (`Object.defineProperty(Definition, "name", { value })`, + * `Reflect.deleteProperty(Response, "getResponseState")`): its constructor * then needs a live own-property table. */ function definedThroughReflection(lowerer: Lowerer, decl: ts.ClassLikeDeclaration): boolean { const name = decl.name; const sf = ts.getSourceFileOfNode(decl); - if (name === undefined || !sf.text.includes("definePropert")) return false; + if ( + name === undefined || + (!sf.text.includes("definePropert") && !sf.text.includes("deleteProperty")) + ) + return false; const symbol = lowerer.checker.getSymbolAtLocation(name); if (symbol === undefined) return false; let found = false; @@ -11281,9 +11344,11 @@ function definedThroughReflection(lowerer: Lowerer, decl: ts.ClassLikeDeclaratio if ( ts.isCallExpression(node) && ts.isPropertyAccessExpression(node.expression) && - (node.expression.name.text === "defineProperty" || + (((node.expression.name.text === "defineProperty" || node.expression.name.text === "defineProperties") && - lowerer.stdlibGlobalMember(node.expression, "Object") !== null + lowerer.stdlibGlobalMember(node.expression, "Object") !== null) || + (node.expression.name.text === "deleteProperty" && + lowerer.stdlibGlobalMember(node.expression, "Reflect") !== null)) ) { const target = node.arguments.nodes[0]; if ( diff --git a/packages/compiler/src/frontend/lowering/lower-namespaces.ts b/packages/compiler/src/frontend/lowering/lower-namespaces.ts index ea844ab1e..13d1c29fc 100644 --- a/packages/compiler/src/frontend/lowering/lower-namespaces.ts +++ b/packages/compiler/src/frontend/lowering/lower-namespaces.ts @@ -42,7 +42,7 @@ import { isPackageShimFile, isShimIntrinsicName, packageShimFor } from "../packa import type { Lowerer } from "./lowerer.js"; import { boundIdentifiersOf } from "./lowerer.js"; import type { FileParts } from "./lower-modules.js"; -import { locOf, resolveImport } from "../program.js"; +import { isCjsJsFile, isJsSourceFile, locOf, resolveImport } from "../program.js"; import { F64, type IrExpr, type IrStmt, type IrType, STRING } from "../../ir/ir.js"; import { TEMPORAL_GLOBAL } from "../builtin-modules.js"; @@ -311,6 +311,30 @@ function moduleNsSourceFileOf(lowerer: Lowerer, e: ts.Expression): ts.SourceFile return null; } +/** The CommonJS module a JavaScript namespace import binding names + * (`import * as ns from "./m.cjs"`, `ns`), or null. */ +export function cjsNamespaceImportDep(lowerer: Lowerer, e: ts.Expression): ts.SourceFile | null { + if (!ts.isIdentifier(e)) return null; + const decl = lowerer.checker.getSymbolAtLocation(e)?.declarations.find(ts.isNamespaceImport); + const stmt = decl?.parent?.parent; + if ( + decl === undefined || + stmt === undefined || + !ts.isImportDeclaration(stmt) || + !ts.isStringLiteral(stmt.moduleSpecifier) + ) + return null; + const from = ts.getSourceFileOfNode(decl); + if (!isJsSourceFile(from)) return null; + const dep = resolveImport(lowerer.program, from, stmt.moduleSpecifier.text); + return dep !== null && + !dep.isDeclarationFile && + lowerer.fileTag.has(dep) && + isCjsJsFile(dep, lowerer.program) + ? dep + : null; +} + /** The member identifier of a qualified namespace reference, when `access` * reads a member declared in a lowered (or type-only) namespace block — * or an EXPORT of a program module read through its namespace-import @@ -330,6 +354,21 @@ export function nsMemberIdentOf( if (!ts.isIdentifier(access.name)) return null; const memberSym = lowerer.checker.getSymbolAtLocation(access.name); if (!memberSym) return null; + // A CommonJS module's namespace has the names Node's lexer detects, with + // the values they had when the module finished evaluating; the member + // then reads like the named import `import { name }`. `default` is + // module.exports itself. + const cjs = cjsNamespaceImportDep(lowerer, access.expression); + if (cjs !== null) { + const { names, assignedLater } = lowerer.cjsNamespaceOf(cjs); + const name = access.name.text; + return name !== "default" && + names.has(name) && + assignedLater !== "all" && + !assignedLater.has(name) + ? access.name + : null; + } if (nsBlockKindOfSymbol(lowerer, memberSym) !== null) return access.name; if (moduleNsSourceFileOf(lowerer, access.expression) !== null) return access.name; return null; @@ -857,6 +896,15 @@ export function nsWritableTarget( const nsMember = nsMemberIdentOf(lowerer, access); if (!nsMember) return null; const memberSym = lowerer.checker.getSymbolAtLocation(nsMember); + // An export read through a module namespace object (`import * as ns`): + // the object is read-only, and Node's assignment throws a TypeError. + if (memberSym && nsBlockKindOfSymbol(lowerer, memberSym) === null) { + lowerer.unsupported( + "SC1090", + access, + `assignment to the module namespace member '${nsMember.text}' (module namespace objects are read-only: Node throws a TypeError)`, + ); + } if (memberSym) fenceEarlyNsMemberRef(lowerer, access, memberSym); const resolved = lowerer.resolveValueSymbol(nsMember); const g = resolved ? lowerer.globalsBySymbol.get(resolved) : undefined; diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index c50676863..95e4f7e80 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -168,6 +168,7 @@ import { import { bindingNeverReassigned, deadUnmappableBinding, + fileWritesBinding, nullishExprUnitOf, nullishGenericBindingUnitOf, } from "./binding-analysis.js"; @@ -181,7 +182,12 @@ import { classStaticDataFor } from "./class-static-data.js"; import { objectFactorySignature } from "./object-factory-new.js"; import { isClassCallback, lowerClassCallbackAssign } from "./class-callbacks.js"; import { classForInHasKey, classPropertiesHelper } from "./class-dynamic-dispatch.js"; -import { genericIfaceBindingKeepsClass, superConditionLead } from "./lower-classes.js"; +import { + genericIfaceBindingKeepsClass, + lowerClassStaticRead, + staticReceiverClass, + superConditionLead, +} from "./lower-classes.js"; import { lowerStreamUnderscoreAssign, streamClassAliasDecl, @@ -3053,6 +3059,18 @@ export function lowerBindingPattern( ); return; } + // A class in a JavaScript file, destructured through its own name + // (`const { ANY, parse } = Comparator`): each element is the static + // read `Comparator.ANY` — the static getter, field or method as Node + // reads it, with the element's default applied when the read answers + // undefined. Other class-valued sources keep the refusal below. + if ( + srcType.kind === "classval" && + ts.isObjectBindingPattern(pattern) && + isJsSourceFile(ts.getSourceFileOfNode(pattern)) && + lowerClassValuePattern(lowerer, pattern, isLet, out) + ) + return; if (srcType.kind === "dyn") { // A runtime computed first key evaluates after RequireObjectCoercible: // a nullish source throws before the key's side effects run. Later @@ -4364,6 +4382,60 @@ function stdlibGlobalTokenDestructure( return out; } +/** `const { ANY, parse } = Comparator` in a JavaScript file, where the + * declaration's initializer names the class exactly (staticReceiverClass): + * one static read per element, left to right. False, with nothing + * emitted, for other sources (a parameter or nested pattern over a class + * value), which keep the class-value refusal. */ +function lowerClassValuePattern( + lowerer: Lowerer, + pattern: ts.ObjectBindingPattern, + isLet: boolean, + out: IrStmt[], +): boolean { + const decl = pattern.parent; + if (!ts.isVariableDeclaration(decl) || decl.initializer === undefined) return false; + let receiver: ts.Expression = decl.initializer; + while (ts.isParenthesizedExpression(receiver)) receiver = receiver.expression; + const info = staticReceiverClass(lowerer, receiver); + if (info === null) return false; + for (const el of pattern.elements.nodes) { + if (el.name === undefined) continue; + if (el.dotDotDotToken) + lowerer.unsupported( + "SC1031", + el, + "rest bindings over class values (the rest object copies the class's own enumerable statics)", + ); + const prop = el.propertyName ?? el.name; + const name = + ts.isIdentifier(prop) || + ts.isComputedPropertyName(prop) || + ts.isStringLiteralLike(prop) || + ts.isNumericLiteral(prop) + ? patternKeyNameOf(lowerer, prop as ts.PropertyName) + : null; + if (name === null) + lowerer.unsupported( + "SC1031", + el, + "destructuring with computed keys that do not fold to one property name", + ); + if (name === "prototype" || name.startsWith("#")) + lowerer.unsupported("SC1031", el, `destructuring '${name}' from a class value`); + let value = lowerClassStaticRead(lowerer, info, name, receiver, receiver); + if (value === null) + lowerer.unsupported( + "SC1031", + el, + `destructuring the property '${name}' the class '${info.def.jsName ?? info.def.name}' does not declare as a static`, + ); + if (el.initializer) value = applyBindingDefault(lowerer, el, value); + lowerer.bindPatternTarget(el.name, value, isLet, out); + } + return true; +} + /** `x = dflt` on a pattern position whose source value always EXISTS * (tuple positions, record fields): JS evaluates the default exactly * when the value is undefined — the undefined-arm ternary, lazy, so @@ -7262,6 +7334,66 @@ function lowerDeleteStatement(lowerer: Lowerer, expr: ts.DeleteExpression): IrSt ); } +/** True when the `var`/`let` binding `nameNode` names cannot change after + * the top-level CommonJS export statement `exportNode` that exports it by + * reference, so importers read the value Node copies at the export: its + * module's top level declares it once, with an initializer that runs + * before the export, and nothing assigns it. The initializer runs earlier + * in the same module, or in a module the exporting module required before + * the export (`var hljs = require('./core'); module.exports = hljs;` over + * highlight.js's `var highlight = HLJS({}); module.exports = highlight;`). */ +function unchangedAfterExport( + lowerer: Lowerer, + nameNode: ts.Identifier, + exportNode: ts.Node, +): boolean { + const topLevelDeclaration = (symbol: ts.Symbol): ts.VariableDeclaration | null => { + const decl = symbol.declarations.length === 1 ? symbol.declarations[0]! : undefined; + return decl !== undefined && + ts.isVariableDeclaration(decl) && + ts.isIdentifier(decl.name) && + decl.initializer !== undefined && + ts.isVariableDeclarationList(decl.parent) && + ts.isVariableStatement(decl.parent.parent) && + ts.isSourceFile(decl.parent.parent.parent) + ? decl + : null; + }; + const exportFile = ts.getSourceFileOfNode(exportNode); + let exportStatement: ts.Node = exportNode; + for (let parent = exportNode.parent; parent !== undefined && !ts.isSourceFile(parent);) { + if (ts.isFunctionLike(parent) || ts.isClassDeclaration(parent) || ts.isClassExpression(parent)) + return false; + exportStatement = parent; + parent = parent.parent; + } + const runsBeforeExport = (decl: ts.VariableDeclaration): boolean => { + const statement = decl.parent?.parent; + return statement?.parent === exportFile && statement.end <= exportStatement.pos; + }; + const sym = lowerer.resolveValueSymbol(nameNode); + const decl = sym ? topLevelDeclaration(sym) : null; + if (!sym || !decl || !bindingNeverReassigned(lowerer, sym, decl)) return false; + if (ts.getSourceFileOfNode(decl) === exportFile) return runsBeforeExport(decl); + // A binding of another module: the exporting module's own binding + // `nameNode` names holds that module's require, evaluated before the + // export, and this file does not assign the binding either. + const local = lowerer.checker.getSymbolAtLocation(nameNode); + const localDecl = local ? topLevelDeclaration(local) : null; + if (!localDecl || !runsBeforeExport(localDecl)) return false; + let init: ts.Expression = localDecl.initializer!; + while (ts.isParenthesizedExpression(init)) init = init.expression; + if ( + !ts.isCallExpression(init) || + !ts.isIdentifier(init.expression) || + init.expression.text !== "require" || + init.arguments.nodes.length !== 1 || + !ts.isStringLiteralLike(init.arguments.nodes[0]!) + ) + return false; + return !fileWritesBinding(sym, exportFile, (ident) => lowerer.resolveValueSymbol(ident)); +} + /** A top-level CommonJS export statement (see cjsExportAssignmentOf): * `exports.f = ` and each expression-valued property of * `module.exports = { ... }` assign their pre-registered export globals @@ -7445,7 +7577,7 @@ function lowerCjsExportStatement( const fenceMutable = (nameNode: ts.Identifier): void => { const sym = lowerer.resolveValueSymbol(nameNode); const g = sym ? lowerer.globalsBySymbol.get(sym) : undefined; - if (g?.mutable) { + if (g?.mutable && !unchangedAfterExport(lowerer, nameNode, cjs.expr)) { lowerer.unsupported( "SC1090", nameNode, @@ -7605,7 +7737,7 @@ function lowerCjsSingleValueExport( } const g = lowerer.globalsBySymbol.get(sym); if (g) { - if (g.mutable) { + if (g.mutable && !unchangedAfterExport(lowerer, rhs, expr)) { lowerer.unsupported( "SC1090", rhs, diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 78980d322..59dda3d08 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -1,6 +1,6 @@ import { isDeclBoundaryFile } from "../decl-projection.js"; import { relieveHeapPressure } from "../../heap-pressure.js"; -import { moduleNamespaceObject } from "./module-namespace-elements.js"; +import { moduleNamespaceObject, moduleNamespaceValue } from "./module-namespace-elements.js"; import { keyedHelperName } from "./stable-names.js"; import { positionTag, StructuralPositions } from "./structural-positions.js"; import { onlyForwarded, stripTypeWrappers } from "./typed-arguments.js"; @@ -269,6 +269,8 @@ import { type StartupCrash, cjsExportAssignmentOf, cjsExportDiscardReason, + cjsExportsAssignedInFunctions, + cjsNamespaceExportNames, fallbackDtsPath, isCheckedJsSourceFile, isCjsExportTableLiteral, @@ -3998,6 +4000,31 @@ export class Lowerer { return null; } + /** For each CommonJS module read through a JavaScript namespace import: + * the property names of Node's namespace object + * (cjsNamespaceExportNames), and the exports the module assigns inside + * functions, which the namespace does not see + * (cjsExportsAssignedInFunctions). */ + private readonly cjsNamespaces = new Map< + ts.SourceFile, + { names: ReadonlySet; assignedLater: ReadonlySet | "all" } + >(); + + cjsNamespaceOf(dep: ts.SourceFile): { + names: ReadonlySet; + assignedLater: ReadonlySet | "all"; + } { + let namespace = this.cjsNamespaces.get(dep); + if (namespace === undefined) { + namespace = { + names: cjsNamespaceExportNames(this.program, dep), + assignedLater: cjsExportsAssignedInFunctions(dep), + }; + this.cjsNamespaces.set(dep, namespace); + } + return namespace; + } + sourceFileOfModuleNamespace(type: IrType): ts.SourceFile | null { if (type.kind !== "moduleNs" || !type.moduleId.startsWith("file:")) return null; const path = type.moduleId.slice("file:".length); @@ -9792,10 +9819,8 @@ export class Lowerer { // so its module binding is too (`ReleaseEmitter = EventEmitter` over // `const EventEmitter = require("events")`). if (expr.type.kind === "moduleNs" && isJsSourceFileName(expr.loc.file)) { - const object = moduleNamespaceObject( - this, - expr as IrExpr & { type: IrType & { kind: "moduleNs" } }, - ); + const ns = expr as IrExpr & { type: IrType & { kind: "moduleNs" } }; + const object = moduleNamespaceObject(this, ns) ?? moduleNamespaceValue(this, ns); if (object) return object; } if ( diff --git a/packages/compiler/src/frontend/lowering/module-namespace-elements.ts b/packages/compiler/src/frontend/lowering/module-namespace-elements.ts index cf828c6f0..2c8e6a475 100644 --- a/packages/compiler/src/frontend/lowering/module-namespace-elements.ts +++ b/packages/compiler/src/frontend/lowering/module-namespace-elements.ts @@ -1,4 +1,5 @@ import { dynUndefinedExpr, strLit, varRef } from "../../ir/build.js"; +import { arrayOf, funcOf } from "../../ir/ir.js"; import * as ts from "../ts7/adapter.js"; import { DYN, @@ -9,7 +10,7 @@ import { type IrType, } from "../../ir/ir.js"; import { locOf } from "../program.js"; -import { newFnCtx, type Lowerer } from "./lowerer.js"; +import { newFnCtx, PoisonError, type Lowerer } from "./lowerer.js"; /** Computed namespace reads select live exports instead of copying a * namespace into a registry snapshot. Constructor registries may contain @@ -171,3 +172,124 @@ export function moduleNamespaceObject( loc, }; } + +/** A module namespace taken as an untyped value whose exports a copy + * cannot represent: a binding that can change after initialization (`let`, + * `var`), or an export the copy cannot name. The value is the runtime's + * namespace object (scr_module_namespace_value): one per module, whose + * property reads call a compiled getter for the export's current value and + * whose writes throw Node's TypeError. An export whose value has no + * checked-dynamic form throws its fence when it is read, and listing the + * object's keys or inspecting it throws the "not supported yet" error. */ +export function moduleNamespaceValue( + lowerer: Lowerer, + ns: IrExpr & { type: IrType & { kind: "moduleNs" } }, +): IrExpr | null { + const source = lowerer.sourceFileOfModuleNamespace(ns.type); + if (!source) return null; + const symbol = lowerer.checker.getSymbolAtLocation(source); + if (!symbol) return null; + const exports: { key: string; declaration: ts.Node | undefined }[] = []; + for (const exported of lowerer.checker.getExportsOfModule(symbol)) { + const target = + exported.flags & ts.SymbolFlags.Alias ? lowerer.checker.getAliasedSymbol(exported) : exported; + if (!(target.flags & ts.SymbolFlags.Value)) continue; + exports.push({ key: ts.symbolName(exported), declaration: target.valueDeclaration }); + } + exports.sort((a, b) => (a.key < b.key ? -1 : a.key > b.key ? 1 : 0)); + const name = `%module.namespace:${ns.type.moduleId}`; + const loc = ns.loc; + if (!lowerer.liftedFns.some((fn) => fn.name === name)) { + const context = newFnCtx(false, null, null, DYN); + const previousClass = lowerer.currentClass; + lowerer.currentClass = null; + lowerer.fnStack.push(context); + try { + const body: IrStmt[] = []; + for (const { key, declaration } of exports) { + const node = declaration ?? source; + const diagsBefore = lowerer.diags.length; + let read: IrStmt[]; + try { + const identifier = declaration?.name as ts.Node | undefined; + if (!identifier || !ts.isIdentifier(identifier)) { + lowerer.unsupported( + "SC1090", + node, + `reading the unnamed export '${key}' through a module namespace object`, + ); + } + const value = lowerer.lowerExprExpecting(identifier, DYN); + if (value.type.kind !== "dyn") { + lowerer.unsupported( + "SC1101", + identifier, + `reading the export '${key}' ('${lowerer.fmt(value.type)}') through a module namespace object`, + ); + } + read = [{ kind: "return", value, loc }]; + } catch (err) { + if (!(err instanceof PoisonError)) throw err; + const fence = lowerer.deferToRuntimeFence(diagsBefore, node, { kind: "statement" }); + if (!fence) throw err; + read = [fence]; + } + body.push({ + kind: "if", + cond: { + kind: "strEq", + negated: false, + left: varRef("key", STRING, loc), + right: strLit(key, loc), + type: { kind: "bool" }, + loc, + }, + then: read, + else_: null, + loc, + }); + } + body.push({ kind: "return", value: dynUndefinedExpr(loc), loc }); + lowerer.liftedFns.push({ + name, + params: [{ localId: "key", name: "key", type: STRING }], + returnType: DYN, + locals: [{ id: "key", name: "key", type: STRING, mutable: false }, ...context.locals], + body, + loc, + }); + } finally { + lowerer.fnStack.pop(); + lowerer.currentClass = previousClass; + } + } + const value: IrExpr = { + kind: "libCall", + fn: "module.namespaceValue", + args: [ + strLit(ns.type.moduleId, loc), + { + kind: "arrayLit", + elems: exports.map(({ key }) => strLit(key, loc)), + type: arrayOf(STRING), + loc, + }, + { + kind: "dynFrom", + value: { kind: "closure", fnName: name, captures: [], type: funcOf([STRING], DYN), loc }, + type: DYN, + loc, + }, + ], + type: DYN, + loc, + }; + if (ns.kind === "moduleNsRef") return value; + return { + kind: "seqExpr", + stmts: [{ kind: "exprStmt", expr: ns, loc }], + result: value, + type: DYN, + loc, + }; +} diff --git a/packages/compiler/src/frontend/package-shims.ts b/packages/compiler/src/frontend/package-shims.ts index 10beeaae8..06a6c4eca 100644 --- a/packages/compiler/src/frontend/package-shims.ts +++ b/packages/compiler/src/frontend/package-shims.ts @@ -55,6 +55,10 @@ interface ImplementationShim { /** Supported major versions and their entry modules, relative to the * shim root. */ versions: ReadonlyMap; + /** Major versions without an entry module that `--npm-static` compiles + * from the package's own published JavaScript. An installed version that + * is in neither list stays out of the program. */ + sourceVersions?: ReadonlySet; /** The entry has a default export (a CommonJS package's whole export * object, which a default import reads). */ defaultExport?: boolean; @@ -98,6 +102,7 @@ const IMPLEMENTATION_SHIMS: ReadonlyMap = new Map< mainFile: "source/index.js", typesFile: "source/index.d.ts", versions: new Map([[5, "chalk/v5.ts"]]), + sourceVersions: new Set([6]), }, ], [ @@ -233,10 +238,17 @@ export function configurePackageShims(entryPath: string): void { unloadedPackages = packages; } -/** True for a package name the registry implements or the project marks - * never loaded: such a package never compiles its published JavaScript. */ -export function isPackageShimName(name: string): boolean { - return IMPLEMENTATION_SHIMS.has(name) || unloadedPackages.has(name); +/** True when `--npm-static` leaves the package `name` out of its package + * list: the project marks it never loaded, or the registry implements it + * and the version installed for `entryPath` has an entry module or is not + * one of the entry's `sourceVersions`. */ +export function npmStaticOmitsPackage(entryPath: string, name: string): boolean { + if (unloadedPackages.has(name)) return true; + const shim = IMPLEMENTATION_SHIMS.get(name); + if (shim === undefined) return false; + const dir = installedPackageDir(entryPath, name); + const major = dir === null ? null : installedMajorVersion(dir, name); + return major === null || shim.versions.has(major) || !shim.sourceVersions?.has(major); } /** True when `specifier` names a package the project marks never loaded. */ @@ -272,9 +284,9 @@ function installedPackageDir(fromFile: string, name: string): string | null { return found; } -/** The shim entry for an installed package directory, or null when the - * directory is not a registered package at a supported major version. */ -function shimEntryForPackageDir(pkgDir: string, expectedName: string | null): string | null { +/** The installed package's name and major version from its package.json, + * or null when either is missing. */ +function installedPackageVersion(pkgDir: string): { name: string; major: number } | null { const text = trackedReadFile(join(pkgDir, "package.json")); if (text === null) return null; let pkg: { name?: unknown; version?: unknown }; @@ -284,11 +296,24 @@ function shimEntryForPackageDir(pkgDir: string, expectedName: string | null): st return null; } if (typeof pkg.name !== "string" || typeof pkg.version !== "string") return null; - if (expectedName !== null && pkg.name !== expectedName) return null; - const shim = IMPLEMENTATION_SHIMS.get(pkg.name); + return { name: pkg.name, major: Number(/^(\d+)\./.exec(pkg.version)?.[1] ?? NaN) }; +} + +/** The major version of the package `name` installed at `pkgDir`, or null. */ +function installedMajorVersion(pkgDir: string, name: string): number | null { + const installed = installedPackageVersion(pkgDir); + return installed === null || installed.name !== name ? null : installed.major; +} + +/** The shim entry for an installed package directory, or null when the + * directory is not a registered package at a supported major version. */ +function shimEntryForPackageDir(pkgDir: string, expectedName: string | null): string | null { + const installed = installedPackageVersion(pkgDir); + if (installed === null) return null; + if (expectedName !== null && installed.name !== expectedName) return null; + const shim = IMPLEMENTATION_SHIMS.get(installed.name); if (shim === undefined) return null; - const major = Number(/^(\d+)\./.exec(pkg.version)?.[1] ?? NaN); - const entry = shim.versions.get(major); + const entry = shim.versions.get(installed.major); if (entry === undefined) return null; return join(packageShimRoot(), shim.variant?.(pkgDir) ?? entry); } diff --git a/packages/compiler/src/frontend/program.ts b/packages/compiler/src/frontend/program.ts index bf75127c4..ce5f3c2bc 100644 --- a/packages/compiler/src/frontend/program.ts +++ b/packages/compiler/src/frontend/program.ts @@ -96,8 +96,8 @@ import type { import { configurePackageShims, isPackageShimFile, - isPackageShimName, isShimmedImport, + npmStaticOmitsPackage, } from "./package-shims.js"; import { provenanceEntryFor, provenancePaths } from "./provenance-registry.js"; import { cjsLexedExportsOfFile, cjsVisibleNames } from "./cjs-syntax.js"; @@ -1072,12 +1072,13 @@ export function loadProgram( } externalTypes.set(specifier, declarationPath); } - // Packages scriptc implements itself or the project marks never loaded - // (package-shims.ts) never compile their published JavaScript, even when - // named. + // Packages scriptc implements itself, and packages the project marks + // never loaded (package-shims.ts), never compile their published + // JavaScript, even when named. A registry entry's `sourceVersions` + // (chalk 6) compile from their own source. configurePackageShims(entryPath); const npmStaticPackages = [...new Set(opts?.npmStatic ?? [])].filter( - (name) => !isPackageShimName(name), + (name) => !npmStaticOmitsPackage(entryPath, name), ); // Resolve authored declaration entries before enabling the JS-only // package resolver. Safe overload metadata binds through the runtime @@ -5941,9 +5942,15 @@ function preflight7(load: LoadResult): { // to Node's no-op, the module still evaluates through its // ordinary init edge, and no member is ever read through the // lexer facade (self-imports of a CJS module included — the - // partially-built exports are never observed). Any OTHER use - // keeps the fence. - if (!nsBindingUsesAreBareStatements7(program, sf, clause.namedBindings.name)) { + // partially-built exports are never observed). In JavaScript + // sources every use passes here: member reads lower through the + // names Node's lexer detects, and the other reads refuse at + // their site (lower-namespaces.ts, cjsNamespaceImportDep). Any + // OTHER use in TypeScript keeps the fence. + if ( + !isJsSourceFileName(sf.fileName) && + !nsBindingUsesAreBareStatements7(program, sf, clause.namedBindings.name) + ) { diags.push( unsupportedDiag( "SC1013", @@ -6372,6 +6379,89 @@ function preflight7(load: LoadResult): { * Node refuses the program). This walk asks Node's question at compile * time, in Node's exact ORDER, and answers with Node's exact message. */ +/** The CommonJS program file a re-export (`module.exports = require(spec)`) + * of `from` resolves to, or null: reexport targets union in only when they + * resolve to CommonJS program files (Node's cjsPreparseModuleExports rule). */ +function cjsReexportDep7(program: ts.Program) { + return (from: ts.SourceFile, spec: string): ts.SourceFile | null => { + const dep = + resolveImport7(program, from, spec, "require") ?? + npmStaticDepSf7(program, from, spec, "require"); + return dep !== null && isCjsJsFile7(dep, program) ? dep : null; + }; +} + +/** Node's lexer analysis of a CommonJS file. A bundler rewrite spells some + * lexer-visible names as accessors. */ +function lexWithAccessorNames(sf: ts.SourceFile): ReturnType { + const lexed = cjsLexedExportsOfFile(sf); + for (const name of npmStaticLexerVisibleNames(sf.fileName)) lexed.exports.add(name); + return lexed; +} + +/** The property names of Node's namespace object for the CommonJS module + * `dep`: the names its lexer detects, CommonJS re-exports included (the + * rule of the named-import link check), plus `default` and + * `module.exports`. */ +export function cjsNamespaceExportNames(program: ts.Program, dep: ts.SourceFile): Set { + const names = cjsVisibleNames(dep, lexWithAccessorNames, cjsReexportDep7(program), new Map()); + return new Set([...names, "default", "module.exports"]); +} + +/** The export names a CommonJS module assigns inside functions + * (`exports.current = value` in a function body), or "all" when such code + * writes a computed name, replaces module.exports or redefines exports + * through Object.defineProperty. Node's namespace object of the module + * holds the values the exports had when the module finished evaluating, + * so it does not see those writes. */ +export function cjsExportsAssignedInFunctions(sf: ts.SourceFile): ReadonlySet | "all" { + const names = new Set(); + let all = false; + const exportsObject = (e: ts.Expression): boolean => + (ts.isIdentifier(e) && e.text === "exports") || isModuleExportsAccess(e); + const target = (e: ts.Expression): void => { + while (ts.isParenthesizedExpression(e)) e = e.expression; + if (isModuleExportsAccess(e)) all = true; + else if (ts.isPropertyAccessExpression(e) && exportsObject(e.expression)) + names.add(e.name.text); + else if (ts.isElementAccessExpression(e) && exportsObject(e.expression)) { + if (ts.isStringLiteralLike(e.argumentExpression)) names.add(e.argumentExpression.text); + else all = true; + } + }; + const visit = (node: ts.Node, inFunction: boolean): void => { + if (all) return; + const nested = inFunction || ts.isFunctionLike(node); + if (nested) { + if ( + ts.isBinaryExpression(node) && + node.operatorToken.kind >= ts.SyntaxKind.FirstAssignment && + node.operatorToken.kind <= ts.SyntaxKind.LastAssignment + ) + target(node.left); + else if ( + (ts.isPrefixUnaryExpression(node) || ts.isPostfixUnaryExpression(node)) && + (node.operator === ts.SyntaxKind.PlusPlusToken || + node.operator === ts.SyntaxKind.MinusMinusToken) + ) + target(node.operand); + else if (ts.isDeleteExpression(node)) target(node.expression); + else if ( + ts.isCallExpression(node) && + ts.isPropertyAccessExpression(node.expression) && + ts.isIdentifier(node.expression.expression) && + node.expression.expression.text === "Object" && + node.arguments.nodes[0] !== undefined && + exportsObject(node.arguments.nodes[0]) + ) + all = true; + } + ts.forEachChild(node, (child) => visit(child, nested)); + }; + visit(sf, false); + return all ? "all" : names; +} + interface BadCjsImport { /** The export name requested from the CJS module. */ exportName: string; @@ -6412,20 +6502,7 @@ function cjsNamedImportLinkCheck( const npmStatic = npmStaticDepSf7(program, from, spec); return npmStatic; }; - // Reexport targets union in only when they resolve to CommonJS program - // files (Node's cjsPreparseModuleExports rule). - const resolveCjsDep = (from: ts.SourceFile, spec: string): ts.SourceFile | null => { - const dep = - resolveImport7(program, from, spec, "require") ?? - npmStaticDepSf7(program, from, spec, "require"); - return dep !== null && isCjsJsFile7(dep, program) ? dep : null; - }; - // A bundler rewrite spells some lexer-visible names as accessors. - const lexWithAccessorNames = (sf: ts.SourceFile): ReturnType => { - const lexed = cjsLexedExportsOfFile(sf); - for (const name of npmStaticLexerVisibleNames(sf.fileName)) lexed.exports.add(name); - return lexed; - }; + const resolveCjsDep = cjsReexportDep7(program); const visible = (dep: ts.SourceFile, name: string): boolean => // `default` is the module.exports binding itself — always provided. // The program already owns native source ASTs; reuse them without diff --git a/packages/compiler/src/index.ts b/packages/compiler/src/index.ts index e2d1c97cc..033d98d3d 100644 --- a/packages/compiler/src/index.ts +++ b/packages/compiler/src/index.ts @@ -595,6 +595,7 @@ async function compileExecutableNative( ...(features.wasm ? { wasm: true } : {}), ...(features.warningReplace ? { warningReplace: true } : {}), ...(features.stdioExtended ? { stdioExtended: true } : {}), + ...(features.moduleNamespace ? { moduleNamespace: true } : {}), zlib: features.zlib, ...(features.brotli ? { brotli: true } : {}), assert: features.assert, diff --git a/packages/compiler/src/ir/builtin-effects.ts b/packages/compiler/src/ir/builtin-effects.ts index 390c7fbc3..69b2d8dd0 100644 --- a/packages/compiler/src/ir/builtin-effects.ts +++ b/packages/compiler/src/ir/builtin-effects.ts @@ -683,6 +683,7 @@ export const MAY_THROW_LIB_FNS: ReadonlySet = new Set([ "fs.callbackCall", "dyn.keyDelete", "dyn.keyDeleteComputed", + "dyn.reflectDeleteProperty", "dyn.hasKeyComputed", "dyn.hasOwnComputed", "dyn.propertyIsEnumerableComputed", diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 216e46a4d..072c006e9 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -196,6 +196,7 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ * arguments; other receiver representations retain a runtime refusal. */ "dyn.keyDelete": { argTypes: [DYN, STRING, BOOL], result: VOID }, "dyn.keyDeleteComputed": { argTypes: [DYN, DYN, BOOL], result: VOID }, + "dyn.reflectDeleteProperty": { argTypes: [DYN, DYN], result: BOOL }, "dyn.hasKeyComputed": { argTypes: [DYN, DYN], result: BOOL }, "dyn.hasOwnComputed": { argTypes: [DYN, DYN], result: BOOL }, "dyn.propertyIsEnumerableComputed": { argTypes: [DYN, DYN], result: BOOL }, @@ -3425,6 +3426,10 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "process.builtinId": { argTypes: [DYN, arrayOf(STRING)], result: STRING }, "process.builtinModule": { argTypes: [STRING, DYN], result: DYN }, "process.builtinUnsupported": { argTypes: [STRING, STRING], result: DYN }, + /** A module namespace object as a checked-dynamic value + * (scr_module_namespace_value): the module id, its sorted export names + * and the compiled getter. One object per module. Never throws. */ + "module.namespaceValue": { argTypes: [STRING, arrayOf(STRING), DYN], result: DYN }, "fs.callbackValue": { argTypes: [STRING], result: DYN }, "fs.callbackCall": { argTypes: [STRING, DYN], result: DYN }, "process.hrtimeValue": { argTypes: [], result: DYN }, @@ -3710,6 +3715,7 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ "ffi.argument": { argTypes: [DYN, STRING], result: DYN }, "ffi.memoryModule": { argTypes: [DYN], result: DYN }, "intl.segmenterNew": { argTypes: [], result: DYN }, + "intl.segmenterRefusing": { argTypes: [STRING], result: DYN }, "arrayBuffer.is": { argTypes: [DYN], result: BOOL }, "arrayBuffer.isView": { argTypes: [DYN], result: BOOL }, "arrayBuffer.byteLengthGetter": { argTypes: [], result: F64 }, diff --git a/packages/compiler/src/ir/runtime-features.ts b/packages/compiler/src/ir/runtime-features.ts index 85b21af7b..bddb3f78b 100644 --- a/packages/compiler/src/ir/runtime-features.ts +++ b/packages/compiler/src/ir/runtime-features.ts @@ -1124,6 +1124,9 @@ const RUNTIME_FEATURE_RULES = { utilPromisify: rule({ fns: ["util.promisifyDyn"] }), /** process.emitWarning is assigned (process.setEmitWarning). */ warningReplace: rule({ fns: ["process.setEmitWarning"] }), + /** Module namespace objects as checked-dynamic values + * (scr_module_namespace.c). */ + moduleNamespace: rule({ fns: ["module.namespaceValue"] }), /** The WebAssembly API (scr_wasm.c). */ wasm: rule({ prefixes: ["wasm."] }), /** crypto.subtle importKey/sign/verify/digest and CryptoKey: @@ -1188,6 +1191,7 @@ function noRuntimeFeatures(): RuntimeFeatures { searchParams: false, urlIdna: false, stdioExtended: false, + moduleNamespace: false, stream: false, streamDyn: false, handleProps: false, diff --git a/packages/compiler/src/native/sanitizer.test.ts b/packages/compiler/src/native/sanitizer.test.ts index 1415f2971..689d67367 100644 --- a/packages/compiler/src/native/sanitizer.test.ts +++ b/packages/compiler/src/native/sanitizer.test.ts @@ -87,6 +87,7 @@ test.skipIf(process.platform !== "linux" && process.platform !== "darwin")( warningReplace: false, stdioExtended: false, brotli: false, + moduleNamespace: false, regex: true, copying: false, textDecoderLegacy: false, diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8214-unshimmed-package-version/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8214-unshimmed-package-version/main.ts.json new file mode 100644 index 000000000..6a6a885dc --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8214-unshimmed-package-version/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8214-unshimmed-package-version/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8216-module-namespace-live-values/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8216-module-namespace-live-values/main.ts.json new file mode 100644 index 000000000..d856e307e --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8216-module-namespace-live-values/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8216-module-namespace-live-values/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8217-intl-segmenter-word-construct/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8217-intl-segmenter-word-construct/main.ts.json new file mode 100644 index 000000000..d2ad44948 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8217-intl-segmenter-word-construct/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8217-intl-segmenter-word-construct/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8218-cjs-namespace-imports/main.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8218-cjs-namespace-imports/main.mjs.json new file mode 100644 index 000000000..d627f9153 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8218-cjs-namespace-imports/main.mjs.json @@ -0,0 +1,9 @@ +{ + "order": [ + "/tests/corpus/8218-cjs-namespace-imports/table.cjs", + "/tests/corpus/8218-cjs-namespace-imports/client/transport.js", + "/tests/corpus/8218-cjs-namespace-imports/client/index.mjs", + "/tests/corpus/8218-cjs-namespace-imports/main.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8219-cjs-stable-var-exports/main.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8219-cjs-stable-var-exports/main.js.json new file mode 100644 index 000000000..71e59739d --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8219-cjs-stable-var-exports/main.js.json @@ -0,0 +1,9 @@ +{ + "order": [ + "/tests/corpus/8219-cjs-stable-var-exports/lib/core.js", + "/tests/corpus/8219-cjs-stable-var-exports/lib/index.js", + "/tests/corpus/8219-cjs-stable-var-exports/lib/options.js", + "/tests/corpus/8219-cjs-stable-var-exports/main.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8220-js-class-static-destructuring/main.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8220-js-class-static-destructuring/main.js.json new file mode 100644 index 000000000..7a2ede696 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8220-js-class-static-destructuring/main.js.json @@ -0,0 +1,9 @@ +{ + "order": [ + "/tests/corpus/8220-js-class-static-destructuring/classes/comparator.js", + "/tests/corpus/8220-js-class-static-destructuring/ranges/outside.js", + "/tests/corpus/8220-js-class-static-destructuring/formdata.js", + "/tests/corpus/8220-js-class-static-destructuring/main.js" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8221-js-recursive-generator-returns/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8221-js-recursive-generator-returns/main.ts.json new file mode 100644 index 000000000..003137231 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8221-js-recursive-generator-returns/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8221-js-recursive-generator-returns/main.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8222-js-class-static-reflection.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8222-js-class-static-reflection.js.json new file mode 100644 index 000000000..2e961ad08 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8222-js-class-static-reflection.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8222-js-class-static-reflection.js" + ], + "diags": [] +} diff --git a/packages/runtime-pack-common/runtime-pack-matrix.mjs b/packages/runtime-pack-common/runtime-pack-matrix.mjs index 600637ba6..88348bdc2 100644 --- a/packages/runtime-pack-common/runtime-pack-matrix.mjs +++ b/packages/runtime-pack-common/runtime-pack-matrix.mjs @@ -80,6 +80,8 @@ export const OPTIONAL_RUNTIME_SOURCES = [ ["scr_perf.c", "dynAsync"], // perf_hooks event-loop metrics, only for programs that read them. ["scr_perf_loop.c", "perfLoop"], + // Module namespace objects as checked-dynamic values. + ["scr_module_namespace.c", "moduleNamespace"], // Blob and File box their reads as dyn promises through scr_async_dyn.c. ["scr_blob.c", "dynAsync"], ["scr_zlib.c", "zlib"], diff --git a/packages/runtime/src/scr_blob.h b/packages/runtime/src/scr_blob.h index 15f4a10d4..0882e41b6 100644 --- a/packages/runtime/src/scr_blob.h +++ b/packages/runtime/src/scr_blob.h @@ -1,5 +1,6 @@ -/* scriptc runtime — Blob and File (scr_blob.c). Included by scr_runtime.h, - * which says where new declarations go. */ +/* scriptc runtime — Blob and File (scr_blob.c), and module namespace + * objects as checked-dynamic values (scr_module_namespace.c). Included by + * scr_runtime.h, which says where new declarations go. */ #ifndef SCR_BLOB_H #define SCR_BLOB_H @@ -23,9 +24,16 @@ ScrPromise *scr_blob_array_buffer(ScrDyn *self); bool scr_blob_is(const ScrDyn *value, double kind); ScrDyn *scr_intl_segmenter_new(void); +/* A word or sentence Intl.Segmenter whose segment() throws `refusal` + * (borrowed), the compiler's SC2020 message. */ +ScrDyn *scr_intl_segmenter_refusing(ScrStr *refusal); ScrStr *scr_process_builtin_id(ScrDyn *id, ScrArr *known); ScrDyn *scr_process_builtin_module(ScrStr *id, ScrDyn *getter); ScrDyn *scr_process_builtin_unsupported(ScrStr *id, ScrStr *member); +/* A module namespace object as a checked-dynamic value (scr_module_namespace.c): + * one handle per module `id`, whose reads call `getter` with the export + * name when `keys` lists it. Borrows all three; +1 handle. */ +ScrDyn *scr_module_namespace_value(ScrStr *id, ScrArr *keys, ScrDyn *getter); ScrDyn *scr_global_native(ScrArr *known); ScrDyn *scr_global_native_init(ScrArr *known, ScrDyn *(*console_get)(void)); ScrDyn *scr_console_native(void); diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index 82fe1a6d9..cc2506b90 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -186,6 +186,7 @@ typedef enum { X(MATCH_SOURCE, 55) /* a match result's pending metadata (scr_regex.c) */ \ X(MESSAGE_EVENT, 50) /* ScrEvent with data — BroadcastChannel's 'message' */ \ X(MESSAGE_PORT, 36) \ + X(MODULE_NAMESPACE, 78) /* module namespace object read through its exports (scr_module_namespace.c) */ \ X(NET_BLOCK_LIST, 48) /* net.BlockList (scr_net.c) */ \ X(NET_SERVER, 3) /* ScrNetServer — net.Server (http.Server rides the same handle) */ \ X(NET_SOCKET, 2) /* ScrNetSocket — net.Socket */ \ @@ -195,6 +196,7 @@ typedef enum { X(REGEXP, 26) /* native RegExp, shared compiled pattern */ \ X(SEARCH_PARAMS, 33) /* live WHATWG URLSearchParams */ \ X(SEGMENTER, 19) /* default Unicode grapheme segmentation */ \ + X(SEGMENTER_REFUSING, 80) /* word or sentence Segmenter whose segment() throws (scr_grapheme.c) */ \ X(SEGMENTS, 20) /* iterable immutable segmentation result */ \ X(SET, 25) /* native Set, shared backing map */ \ X(SHARED_ARRAY_BUFFER, 37) \ @@ -875,6 +877,7 @@ bool scr_dyn_has_key_computed(const ScrDyn *value, const ScrDyn *key); bool scr_dyn_has_own_computed(const ScrDyn *value, const ScrDyn *key); bool scr_dyn_property_is_enumerable_computed(const ScrDyn *value, const ScrDyn *key); void scr_dyn_key_delete_computed(ScrDyn *value, const ScrDyn *key, bool strict); +bool scr_dyn_reflect_delete_property(ScrDyn *target, const ScrDyn *key); ScrStr *scr_dyn_string_constructor(const ScrDyn *value); ScrDyn *scr_dyn_property_key_value(const ScrDyn *value); ScrDyn *scr_dyn_to_numeric(const ScrDyn *value); diff --git a/packages/runtime/src/scr_grapheme.c b/packages/runtime/src/scr_grapheme.c index 2c93bc395..f9e5ca28d 100644 --- a/packages/runtime/src/scr_grapheme.c +++ b/packages/runtime/src/scr_grapheme.c @@ -201,3 +201,58 @@ ScrDyn *scr_intl_segmenter_new(void) { scr_dyn_handle_install(SCR_DYNH_SEGMENTS, &segments); return scr_graphemes_box(NULL, SCR_DYNH_SEGMENTER); } + +/* A word or sentence Segmenter, which JavaScript dependencies may build at + * module load and use on some paths only: it constructs, and its segment() + * throws the compiler's SC2020 message. */ +typedef struct { + size_t rc; + ScrStr *refusal; /* retained */ +} ScrRefusingSegmenter; + +static void *scr_refusing_segmenter_retain(void *ptr) { + ScrRefusingSegmenter *value = ptr; + value->rc++; + return value; +} + +static void scr_refusing_segmenter_release(void *ptr) { + ScrRefusingSegmenter *value = ptr; + if (--value->rc) return; + scr_str_release(value->refusal); + free(value); +} + +static ScrDyn *scr_refusing_segmenter_invoke(void *ptr, ScrDyn *self, const char *method, + ScrDyn *const *args, size_t argc, const char *what) { + ScrRefusingSegmenter *value = ptr; + if (strcmp(method, "segment") == 0) { + ScrStr *input = scr_dyn_string_coerce_js(argc ? args[0] : scr_dyn_undefined()); + if (!input) return NULL; + scr_str_release(input); + scr_throw_error_msg_code(SCR_ERR_ERROR, value->refusal->data, value->refusal->len, "SC2020"); + return NULL; + } + return scr_graphemes_invoke(&(ScrGraphemes){ .rc = 1 }, self, method, args, argc, what); +} + +static ScrDyn *scr_refusing_segmenter_get(void *ptr, const char *key, size_t len) { + (void)ptr; + return scr_graphemes_get(&(ScrGraphemes){ .rc = 1 }, key, len); +} + +ScrDyn *scr_intl_segmenter_refusing(ScrStr *refusal) { + static const ScrDynHandleOps segmenter = { + .cls = "Segmenter", .retain = scr_refusing_segmenter_retain, + .release = scr_refusing_segmenter_release, .invoke = scr_refusing_segmenter_invoke, + .get = scr_refusing_segmenter_get, .set = scr_graphemes_set, + }; + scr_dyn_handle_install(SCR_DYNH_SEGMENTER_REFUSING, &segmenter); + ScrRefusingSegmenter *value = calloc(1, sizeof *value); + if (!value) scr_trap("scriptc: out of memory\n"); + value->rc = 1; + value->refusal = scr_str_retain(refusal); + ScrDyn *boxed = scr_dyn_new_handle(value, SCR_DYNH_SEGMENTER_REFUSING); + scr_refusing_segmenter_release(value); + return boxed; +} diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 49af072ed..4eb53bbec 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -8017,6 +8017,45 @@ void scr_dyn_key_delete_computed(ScrDyn *value, const ScrDyn *raw_key, bool stri scr_dyn_release(key); } +/* Reflect.deleteProperty(target, key): a TypeError for a primitive target, + * then the key's ToPropertyKey and a sloppy-mode delete. Answers whether + * the property is absent afterwards (false when it is non-configurable). + * A Proxy would observe the own-property check through its traps, and a + * compiled object's native fields keep their values after a delete through + * its checked-dynamic view, so both refuse. */ +bool scr_dyn_reflect_delete_property(ScrDyn *target, const ScrDyn *raw_key) { + switch (target->kind) { + case SCR_DYN_NULL: + case SCR_DYN_UNDEF: + case SCR_DYN_BOOL: + case SCR_DYN_NUM: + case SCR_DYN_STR: + case SCR_DYN_BIGINT: + case SCR_DYN_SYMBOL: { + static const char message[] = "Reflect.deleteProperty called on non-object"; + scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); + return false; + } + default: + break; + } + if (target->kind == SCR_DYN_PROXY) { + scr_dyn_proxy_unsupported("Reflect.deleteProperty"); + return false; + } + if (target->kind == SCR_DYN_TYPED_REF) { + static const char message[] = "Reflect.deleteProperty on a compiled object is not supported yet"; + scr_throw_error_msg_code(SCR_ERR_ERROR, message, sizeof message - 1, "SC2020"); + return false; + } + ScrDyn *key = scr_dyn_property_key_value(raw_key); + if (!key) return false; + scr_dyn_key_delete_computed(target, key, false); + bool deleted = !scr_exc_pending() && !scr_dyn_has_own_computed(target, key); + scr_dyn_release(key); + return deleted; +} + /* Native call/apply/bind lowering still owns these prototype operations. * Refuse overrides until every typed call site observes the property table. */ static bool scr_dyn_fn_property_fence(const ScrStr *key) { diff --git a/packages/runtime/src/scr_module_namespace.c b/packages/runtime/src/scr_module_namespace.c new file mode 100644 index 000000000..b0d7e80c4 --- /dev/null +++ b/packages/runtime/src/scr_module_namespace.c @@ -0,0 +1,121 @@ +/* Module namespace objects as checked-dynamic values + * (module-namespace-elements.ts lowers `import * as ns` values here). */ +#include "scr_runtime.h" + +#include +#include + +/* A module namespace object taken as a checked-dynamic value + * (module-namespace-elements.ts). The compiled getter answers an export's + * current value by name, so reads see live bindings; `keys` lists the + * namespace's export names. One object per module keeps its identity. + * Writes throw Node's strict-mode TypeError for a frozen namespace. */ +typedef struct ScrModuleNamespace { + size_t rc; + ScrStr *id; + ScrDyn *getter; + ScrArr *keys; + struct ScrModuleNamespace *next; +} ScrModuleNamespace; + +static SCR_TL ScrModuleNamespace *scr_module_namespaces; +static SCR_TL bool scr_module_namespace_cleanup_registered; + +static void *scr_module_namespace_retain(void *handle) { + ScrModuleNamespace *ns = handle; + ns->rc++; + return ns; +} + +static void scr_module_namespace_release(void *handle) { + ScrModuleNamespace *ns = handle; + if (--ns->rc) return; + scr_str_release(ns->id); + scr_dyn_release(ns->getter); + scr_arr_release(ns->keys); + free(ns); +} + +static void scr_module_namespace_cleanup(void) { + while (scr_module_namespaces) { + ScrModuleNamespace *ns = scr_module_namespaces; + scr_module_namespaces = ns->next; + scr_module_namespace_release(ns); + } +} + +static bool scr_module_namespace_has(const ScrModuleNamespace *ns, const char *key, size_t length) { + for (size_t i = 0; i < ns->keys->len; i++) { + ScrStr *entry = (ScrStr *)scr_arr_get_ref(ns->keys, (double)i); + bool same = entry->len == length && memcmp(entry->data, key, length) == 0; + scr_str_release(entry); + if (same) return true; + } + return false; +} + +static ScrDyn *scr_module_namespace_get(void *handle, const char *key, size_t length) { + ScrModuleNamespace *ns = handle; + if (!scr_module_namespace_has(ns, key, length)) return NULL; + ScrStr *name = scr_str_new(key, length); + ScrDyn *arg = scr_dyn_new_str(name); + scr_str_release(name); + ScrDyn *result = scr_dyn_call(ns->getter, &arg, 1, "module namespace export"); + scr_dyn_release(arg); + return result; +} + +static bool scr_module_namespace_set(void *handle, const char *key, size_t length, const ScrDyn *value) { + (void)value; + ScrModuleNamespace *ns = handle; + ScrJsonBuf text; + scr_jb_init(&text); + if (scr_module_namespace_has(ns, key, length)) { + scr_jb_puts(&text, "Cannot assign to read only property '"); + scr_jb_write(&text, key, length); + scr_jb_puts(&text, "' of object '[object Module]'"); + } else { + scr_jb_puts(&text, "Cannot add property "); + scr_jb_write(&text, key, length); + scr_jb_puts(&text, ", object is not extensible"); + } + ScrStr *message = scr_jb_finish(&text); + scr_throw_error_msg(SCR_ERR_TYPE, message->data, message->len); + scr_str_release(message); + return true; +} + +static ScrDyn *scr_module_namespace_invoke(void *handle, ScrDyn *self, const char *key, + ScrDyn *const *args, size_t argc, const char *what) { + ScrDyn *fn = scr_module_namespace_get(handle, key, strlen(key)); + if (fn == NULL) { + if (scr_exc_pending()) return NULL; + fn = scr_dyn_retain(scr_dyn_undefined()); + } + scr_dyn_this_push_dyn(self); + ScrDyn *result = scr_dyn_call(fn, args, argc, what); + scr_dyn_this_pop(); + scr_dyn_release(fn); + return result; +} + +ScrDyn *scr_module_namespace_value(ScrStr *id, ScrArr *keys, ScrDyn *getter) { + static const ScrDynHandleOps ops = { + .cls = "Module", .retain = scr_module_namespace_retain, .release = scr_module_namespace_release, + .get = scr_module_namespace_get, .set = scr_module_namespace_set, .invoke = scr_module_namespace_invoke, + }; + scr_dyn_handle_install(SCR_DYNH_MODULE_NAMESPACE, &ops); + for (ScrModuleNamespace *ns = scr_module_namespaces; ns; ns = ns->next) { + if (ns->id->len == id->len && memcmp(ns->id->data, id->data, id->len) == 0) + return scr_dyn_new_handle(ns, SCR_DYNH_MODULE_NAMESPACE); + } + if (!scr_module_namespace_cleanup_registered) { + scr_atexit(scr_module_namespace_cleanup); + scr_module_namespace_cleanup_registered = true; + } + ScrModuleNamespace *ns = malloc(sizeof(*ns)); + if (!ns) scr_trap("scriptc: out of memory\n"); + *ns = (ScrModuleNamespace){ 1, scr_str_retain(id), scr_dyn_retain(getter), scr_arr_retain(keys), scr_module_namespaces }; + scr_module_namespaces = ns; + return scr_dyn_new_handle(ns, SCR_DYNH_MODULE_NAMESPACE); +} diff --git a/tests/corpus/8214-unshimmed-package-version/main.ts b/tests/corpus/8214-unshimmed-package-version/main.ts new file mode 100644 index 000000000..d582a339b --- /dev/null +++ b/tests/corpus/8214-unshimmed-package-version/main.ts @@ -0,0 +1,5 @@ +// A package that scriptc implements at some major versions (chalk 5) +// compiles from its own source at a version without an implementation. +import chalk, { level } from "chalk"; + +console.log(chalk.version, level, chalk.red("red"), chalk.bold("bold")); diff --git a/tests/corpus/8214-unshimmed-package-version/node_modules/chalk/package.json b/tests/corpus/8214-unshimmed-package-version/node_modules/chalk/package.json new file mode 100644 index 000000000..7ab814eb0 --- /dev/null +++ b/tests/corpus/8214-unshimmed-package-version/node_modules/chalk/package.json @@ -0,0 +1 @@ +{ "name": "chalk", "version": "6.0.0", "type": "module", "exports": { "types": "./source/index.d.ts", "default": "./source/index.js" }, "imports": { "#styles": "./source/styles.js" } } diff --git a/tests/corpus/8214-unshimmed-package-version/node_modules/chalk/source/index.d.ts b/tests/corpus/8214-unshimmed-package-version/node_modules/chalk/source/index.d.ts new file mode 100644 index 000000000..84dd75758 --- /dev/null +++ b/tests/corpus/8214-unshimmed-package-version/node_modules/chalk/source/index.d.ts @@ -0,0 +1,3 @@ +export declare const level: number; +declare const chalk: { version: number; red(text: string): string; bold(text: string): string }; +export default chalk; diff --git a/tests/corpus/8214-unshimmed-package-version/node_modules/chalk/source/index.js b/tests/corpus/8214-unshimmed-package-version/node_modules/chalk/source/index.js new file mode 100644 index 000000000..2d85a4ae3 --- /dev/null +++ b/tests/corpus/8214-unshimmed-package-version/node_modules/chalk/source/index.js @@ -0,0 +1,16 @@ +import { styles } from "#styles"; + +export const level = 0; + +function paint(name, text) { + const [open, close] = styles[name]; + return level > 0 ? `\u001B[${open}m${text}\u001B[${close}m` : `${text}`; +} + +const chalk = { + version: 6, + red: (text) => paint("red", text), + bold: (text) => paint("bold", text), +}; + +export default chalk; diff --git a/tests/corpus/8214-unshimmed-package-version/node_modules/chalk/source/styles.js b/tests/corpus/8214-unshimmed-package-version/node_modules/chalk/source/styles.js new file mode 100644 index 000000000..03e60b5e0 --- /dev/null +++ b/tests/corpus/8214-unshimmed-package-version/node_modules/chalk/source/styles.js @@ -0,0 +1 @@ +export const styles = { red: [31, 39], bold: [1, 22] }; diff --git a/tests/corpus/8216-module-namespace-live-values/main.ts b/tests/corpus/8216-module-namespace-live-values/main.ts new file mode 100644 index 000000000..419ce772e --- /dev/null +++ b/tests/corpus/8216-module-namespace-live-values/main.ts @@ -0,0 +1,11 @@ +// A module namespace object stored as an untyped value, here in a registry +// keyed by module name (pi-coding-agent's VIRTUAL_MODULES): reads see the +// exports' current values, both registry entries are the same object, and +// writes throw Node's TypeError. +import { addThrough, bumpThrough, describe, same, writeThrough } from "ns-registry"; + +console.log(describe()); +bumpThrough(); +bumpThrough(); +console.log(describe()); +console.log(same(), writeThrough(), addThrough()); diff --git a/tests/corpus/8216-module-namespace-live-values/node_modules/ns-registry/counter.js b/tests/corpus/8216-module-namespace-live-values/node_modules/ns-registry/counter.js new file mode 100644 index 000000000..b971201d8 --- /dev/null +++ b/tests/corpus/8216-module-namespace-live-values/node_modules/ns-registry/counter.js @@ -0,0 +1,7 @@ +export let count = 0; +export var legacy = "legacy"; +export const label = "counter"; +export function bump() { + count++; + legacy = `legacy ${count}`; +} diff --git a/tests/corpus/8216-module-namespace-live-values/node_modules/ns-registry/index.d.ts b/tests/corpus/8216-module-namespace-live-values/node_modules/ns-registry/index.d.ts new file mode 100644 index 000000000..451d646f7 --- /dev/null +++ b/tests/corpus/8216-module-namespace-live-values/node_modules/ns-registry/index.d.ts @@ -0,0 +1,5 @@ +export declare function describe(): string; +export declare function bumpThrough(): void; +export declare function same(): boolean; +export declare function writeThrough(): string; +export declare function addThrough(): string; diff --git a/tests/corpus/8216-module-namespace-live-values/node_modules/ns-registry/index.js b/tests/corpus/8216-module-namespace-live-values/node_modules/ns-registry/index.js new file mode 100644 index 000000000..51558bcba --- /dev/null +++ b/tests/corpus/8216-module-namespace-live-values/node_modules/ns-registry/index.js @@ -0,0 +1,40 @@ +import * as counter from "./counter.js"; + +export const registry = { + counter: counter, + "alias/counter": counter, +}; + +export function describe() { + const ns = registry["counter"]; + return `${ns.count} ${ns.legacy} ${ns.label} ${typeof ns.bump} ${typeof ns}`; +} + +export function bumpThrough() { + registry.counter.bump(); +} + +export function same() { + return registry.counter === registry["alias/counter"]; +} + +function assign(target, key, value) { + try { + target[key] = value; + } catch (error) { + return `${error.name}: ${error.message}`; + } + return "no error"; +} + +function lookup(name) { + return registry[name]; +} + +export function writeThrough() { + return assign(lookup("counter"), "count", 5); +} + +export function addThrough() { + return assign(lookup("alias/counter"), "extra", 5); +} diff --git a/tests/corpus/8216-module-namespace-live-values/node_modules/ns-registry/package.json b/tests/corpus/8216-module-namespace-live-values/node_modules/ns-registry/package.json new file mode 100644 index 000000000..30fae6921 --- /dev/null +++ b/tests/corpus/8216-module-namespace-live-values/node_modules/ns-registry/package.json @@ -0,0 +1 @@ +{ "name": "ns-registry", "version": "1.0.0", "type": "module", "main": "index.js", "types": "index.d.ts" } diff --git a/tests/corpus/8217-intl-segmenter-word-construct/main.ts b/tests/corpus/8217-intl-segmenter-word-construct/main.ts new file mode 100644 index 000000000..5a2a42e08 --- /dev/null +++ b/tests/corpus/8217-intl-segmenter-word-construct/main.ts @@ -0,0 +1,8 @@ +// A package builds its segmenters at module load (pi-tui, grok-mermaid): +// a grapheme segmenter with a locale tag, and a word segmenter that only +// some paths use. Grapheme segmentation matches Node; the word segmenter +// constructs, and this program never segments with it. +import { columns, describe } from "text-width"; + +console.log(describe()); +console.log(columns("éa👍🏽🇫🇷"), columns("abc")); diff --git a/tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/index.d.ts b/tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/index.d.ts new file mode 100644 index 000000000..471b4fd0a --- /dev/null +++ b/tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/index.d.ts @@ -0,0 +1,2 @@ +export declare function columns(text: string): string; +export declare function describe(): string; diff --git a/tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/index.js b/tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/index.js new file mode 100644 index 000000000..d58b4ccbb --- /dev/null +++ b/tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/index.js @@ -0,0 +1,11 @@ +const graphemes = new Intl.Segmenter("en", { granularity: "grapheme" }); +const words = new Intl.Segmenter(undefined, { granularity: "word" }); +const sentences = new Intl.Segmenter(undefined, { granularity: "sentence" }); + +export function columns(text) { + return [...graphemes.segment(text)].map((part) => part.segment).join("|"); +} + +export function describe() { + return `${typeof words} ${typeof sentences}`; +} diff --git a/tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/package.json b/tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/package.json new file mode 100644 index 000000000..4f3af53f4 --- /dev/null +++ b/tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/package.json @@ -0,0 +1 @@ +{ "name": "text-width", "version": "1.0.0", "type": "module", "main": "index.js", "types": "index.d.ts" } diff --git a/tests/corpus/8218-cjs-namespace-imports/client/index.mjs b/tests/corpus/8218-cjs-namespace-imports/client/index.mjs new file mode 100644 index 000000000..f0d49451f --- /dev/null +++ b/tests/corpus/8218-cjs-namespace-imports/client/index.mjs @@ -0,0 +1,12 @@ +import * as transport from './transport.js' + +export function connect (origin) { + const pool = new transport.Pool(origin, transport.defaults) + console.log(transport.setGlobalDispatcher(pool), pool.connections, transport.defaults.keepAlive) + return pool +} + +export function describe (pool) { + const format = transport.format + return format(pool.request('/status')) +} diff --git a/tests/corpus/8218-cjs-namespace-imports/client/package.json b/tests/corpus/8218-cjs-namespace-imports/client/package.json new file mode 100644 index 000000000..c866a30a1 --- /dev/null +++ b/tests/corpus/8218-cjs-namespace-imports/client/package.json @@ -0,0 +1 @@ +{ "name": "ns-client", "version": "1.0.0", "main": "index.mjs" } diff --git a/tests/corpus/8218-cjs-namespace-imports/client/transport.js b/tests/corpus/8218-cjs-namespace-imports/client/transport.js new file mode 100644 index 000000000..8d9efbe36 --- /dev/null +++ b/tests/corpus/8218-cjs-namespace-imports/client/transport.js @@ -0,0 +1,26 @@ +'use strict' +// A CommonJS module of the package: member exports, a class, and a table +// whose getter stops Node's lexer before the names after it. +class Pool { + constructor (origin, options) { + this.origin = origin + this.connections = options.connections + this.requests = 0 + } + + request (path) { + this.requests += 1 + return `${this.origin}${path} #${this.requests}` + } +} + +function setGlobalDispatcher (dispatcher) { + exports.current = dispatcher + return dispatcher.origin +} + +exports.Pool = Pool +exports.setGlobalDispatcher = setGlobalDispatcher +exports.current = null +exports.defaults = { connections: 4, keepAlive: true } +exports.format = function format (value) { return `[${value}]` } diff --git a/tests/corpus/8218-cjs-namespace-imports/main.mjs b/tests/corpus/8218-cjs-namespace-imports/main.mjs new file mode 100644 index 000000000..7d2d0e862 --- /dev/null +++ b/tests/corpus/8218-cjs-namespace-imports/main.mjs @@ -0,0 +1,13 @@ +// Namespace imports of CommonJS modules in JavaScript: member reads, calls, +// constructions and a method read as a value, through a package's ES +// module and directly. Each name is one Node's lexer detects. +import * as table from './table.cjs' +import { connect, describe } from './client/index.mjs' + +console.log(table.add(20, 22), table.scale) +const add = table.add +console.log(add(1, 2)) + +const pool = connect('http://localhost') +console.log(describe(pool)) +console.log(describe(pool)) diff --git a/tests/corpus/8218-cjs-namespace-imports/table.cjs b/tests/corpus/8218-cjs-namespace-imports/table.cjs new file mode 100644 index 000000000..38696c6f9 --- /dev/null +++ b/tests/corpus/8218-cjs-namespace-imports/table.cjs @@ -0,0 +1,10 @@ +'use strict' +const add = (a, b) => a + b +const scale = 10 +let calls = 0 +module.exports = { + add, + scale, + get calls () { return calls }, + bump () { calls += 1 } +} diff --git a/tests/corpus/8219-cjs-stable-var-exports/lib/core.js b/tests/corpus/8219-cjs-stable-var-exports/lib/core.js new file mode 100644 index 000000000..1210659ac --- /dev/null +++ b/tests/corpus/8219-cjs-stable-var-exports/lib/core.js @@ -0,0 +1,31 @@ +// highlight.js's lib/core.js shape: the module builds one instance and +// exports the var that holds it. +'use strict'; + +const HLJS = function (options) { + const languages = new Map(); + const prefix = options.classPrefix || 'hljs-'; + + function registerLanguage(name, keywords) { + languages.set(name, keywords); + } + + function listLanguages() { + return Array.from(languages.keys()); + } + + function highlight(code, name) { + const keywords = languages.get(name); + if (keywords === undefined) throw new Error(`Unknown language: "${name}"`); + return code + .split(' ') + .map((word) => (keywords.includes(word) ? `${word}` : word)) + .join(' '); + } + + return { registerLanguage, listLanguages, highlight, versionString: '10.7.3' }; +}; + +var highlight = HLJS({}); + +module.exports = highlight; diff --git a/tests/corpus/8219-cjs-stable-var-exports/lib/index.js b/tests/corpus/8219-cjs-stable-var-exports/lib/index.js new file mode 100644 index 000000000..5f7726ea2 --- /dev/null +++ b/tests/corpus/8219-cjs-stable-var-exports/lib/index.js @@ -0,0 +1,8 @@ +// highlight.js's lib/index.js shape: require the core instance, register +// languages on it and export the same var. +var hljs = require('./core'); + +hljs.registerLanguage('javascript', ['const', 'let', 'function', 'return']); +hljs.registerLanguage('python', ['def', 'return', 'lambda']); + +module.exports = hljs; diff --git a/tests/corpus/8219-cjs-stable-var-exports/lib/options.js b/tests/corpus/8219-cjs-stable-var-exports/lib/options.js new file mode 100644 index 000000000..17512396f --- /dev/null +++ b/tests/corpus/8219-cjs-stable-var-exports/lib/options.js @@ -0,0 +1,12 @@ +// A let that is never reassigned, exported in a table. +'use strict'; + +let tabReplace = ' '; +let calls = []; + +function render(text) { + calls.push(text); + return text.split('\t').join(tabReplace); +} + +module.exports = { tabReplace, calls, render }; diff --git a/tests/corpus/8219-cjs-stable-var-exports/main.js b/tests/corpus/8219-cjs-stable-var-exports/main.js new file mode 100644 index 000000000..8607165a6 --- /dev/null +++ b/tests/corpus/8219-cjs-stable-var-exports/main.js @@ -0,0 +1,21 @@ +// A var and a let exported by reference, where neither changes after the +// export: importers see the same instance and value as Node. +'use strict'; + +const hljs = require('./lib'); +const core = require('./lib/core'); +const options = require('./lib/options'); + +console.log(hljs === core, hljs.versionString); +console.log(hljs.listLanguages()); +console.log(hljs.highlight('const x = function', 'javascript')); +hljs.registerLanguage('ruby', ['def', 'end']); +console.log(core.listLanguages().length, core.highlight('def run end', 'ruby')); +try { + hljs.highlight('x', 'cobol'); +} catch (error) { + console.log(error.message); +} + +console.log(JSON.stringify(options.tabReplace), options.render('a\tb'), options.render('\tc')); +console.log(options.calls); diff --git a/tests/corpus/8219-cjs-stable-var-exports/package.json b/tests/corpus/8219-cjs-stable-var-exports/package.json new file mode 100644 index 000000000..5bbefffba --- /dev/null +++ b/tests/corpus/8219-cjs-stable-var-exports/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/tests/corpus/8220-js-class-static-destructuring/classes/comparator.js b/tests/corpus/8220-js-class-static-destructuring/classes/comparator.js new file mode 100644 index 000000000..3b128847c --- /dev/null +++ b/tests/corpus/8220-js-class-static-destructuring/classes/comparator.js @@ -0,0 +1,22 @@ +'use strict' +// semver's Comparator: a static getter returning a module symbol. +const ANY = Symbol('SemVer ANY') + +class Comparator { + static get ANY () { + return ANY + } + + static loose = false + + static parse (text) { + return new Comparator(text) + } + + constructor (text) { + this.semver = text === '' ? ANY : text + this.value = text === '' ? '' : `>=${text}` + } +} + +module.exports = Comparator diff --git a/tests/corpus/8220-js-class-static-destructuring/formdata.js b/tests/corpus/8220-js-class-static-destructuring/formdata.js new file mode 100644 index 000000000..851d3ba28 --- /dev/null +++ b/tests/corpus/8220-js-class-static-destructuring/formdata.js @@ -0,0 +1,26 @@ +'use strict' +// undici's FormData: statics that read private instance state, taken off +// the class before the class is exposed. +class FormData { + #state = [] + + append (name, value) { + this.#state.push({ name, value }) + } + + static getFormDataState (formData) { + return formData.#state + } + + static setFormDataState (formData, state) { + formData.#state = state + } + + static get boundary () { + return undefined + } +} + +const { getFormDataState, setFormDataState, boundary = '----formdata-default' } = FormData + +module.exports = { FormData, getFormDataState, setFormDataState, boundary } diff --git a/tests/corpus/8220-js-class-static-destructuring/main.js b/tests/corpus/8220-js-class-static-destructuring/main.js new file mode 100644 index 000000000..6cc17b94e --- /dev/null +++ b/tests/corpus/8220-js-class-static-destructuring/main.js @@ -0,0 +1,39 @@ +'use strict' +// Object patterns over a class value read its static getters, fields and +// methods as Node does, defaults included. +const Comparator = require('./classes/comparator') +const { outside, ANY, any, isLoose, name } = require('./ranges/outside') +const { FormData, getFormDataState, setFormDataState, boundary } = require('./formdata') + +console.log(typeof ANY, ANY === Comparator.ANY, any === ANY, isLoose, name) +console.log(outside(''), outside('1.2.3')) +console.log(Comparator.parse('').semver === ANY, Comparator.parse('2.0.0').semver === ANY) + +const form = new FormData() +form.append('a', 1) +form.append('b', 'two') +console.log(getFormDataState(form)) +setFormDataState(form, [{ name: 'c', value: true }]) +console.log(getFormDataState(form), boundary) + +class Defaults { + static count = 0 + static missing = undefined + static nested = { inner: 'value' } +} +const { count = 5, missing = 'fallback', nested: { inner, other = 'other' } } = Defaults +console.log(count, missing, inner, other) + +// Inherited statics, and a static getter reading the class it is read +// through. +class Base { + static tag = 'base' + static get label () { return `label:${this.tag}` } + static make () { return this.tag } +} +class Sub extends Base { + static tag = 'sub' +} +const { tag, label, make, name: subName } = Sub +const { label: baseLabel } = Base +console.log(tag, label, typeof make, subName, baseLabel) diff --git a/tests/corpus/8220-js-class-static-destructuring/package.json b/tests/corpus/8220-js-class-static-destructuring/package.json new file mode 100644 index 000000000..5bbefffba --- /dev/null +++ b/tests/corpus/8220-js-class-static-destructuring/package.json @@ -0,0 +1,3 @@ +{ + "type": "commonjs" +} diff --git a/tests/corpus/8220-js-class-static-destructuring/ranges/outside.js b/tests/corpus/8220-js-class-static-destructuring/ranges/outside.js new file mode 100644 index 000000000..a8ffe06f2 --- /dev/null +++ b/tests/corpus/8220-js-class-static-destructuring/ranges/outside.js @@ -0,0 +1,13 @@ +'use strict' +// semver's ranges/outside.js and ranges/subset.js destructure the class's +// statics at module load. +const Comparator = require('../classes/comparator') +const { ANY } = Comparator +const { ANY: any, loose: isLoose = true, parse, name } = Comparator + +const outside = (text) => { + const comparator = parse(text) + return comparator.semver === ANY ? 'any' : comparator.value +} + +module.exports = { outside, ANY, any, isLoose, name } diff --git a/tests/corpus/8221-js-recursive-generator-returns/main.ts b/tests/corpus/8221-js-recursive-generator-returns/main.ts new file mode 100644 index 000000000..72b9a7b10 --- /dev/null +++ b/tests/corpus/8221-js-recursive-generator-returns/main.ts @@ -0,0 +1,10 @@ +// A JavaScript package's parser of mutually recursive generator methods that +// return `yield*` of each other (yaml 2.9.0's parse/parser.js): the checker +// cannot infer their results. Tokens, values passed to next() and return +// values reach each generator in the same order as in Node. +import { parseTokens, drive, spreadTypes, walkAll } from "token-parser"; + +for (const token of parseTokens("a { b [ c d ] e } f")) console.log(token); +console.log(drive("{ x } y ! z")); +console.log(spreadTypes("[ 1 2 3 ]")); +console.log(await walkAll("a ( b c ) d ( e )")); diff --git a/tests/corpus/8221-js-recursive-generator-returns/node_modules/token-parser/dist/index.d.ts b/tests/corpus/8221-js-recursive-generator-returns/node_modules/token-parser/dist/index.d.ts new file mode 100644 index 000000000..763a34ae4 --- /dev/null +++ b/tests/corpus/8221-js-recursive-generator-returns/node_modules/token-parser/dist/index.d.ts @@ -0,0 +1,4 @@ +export declare function parseTokens(source: string): string[]; +export declare function drive(source: string): string; +export declare function spreadTypes(source: string): string; +export declare function walkAll(source: string): Promise; diff --git a/tests/corpus/8221-js-recursive-generator-returns/node_modules/token-parser/dist/index.js b/tests/corpus/8221-js-recursive-generator-returns/node_modules/token-parser/dist/index.js new file mode 100644 index 000000000..aab64a1ac --- /dev/null +++ b/tests/corpus/8221-js-recursive-generator-returns/node_modules/token-parser/dist/index.js @@ -0,0 +1,131 @@ +'use strict' + +class Parser { + constructor (source) { + this.tokens = source.split(' ') + this.index = 0 + this.stack = [] + } + + * parse () { + while (this.index < this.tokens.length) { + const done = yield * this.step() + if (done) return 'stopped' + } + return yield * this.end() + } + + * step () { + const token = this.tokens[this.index++] + if (token === '{') return yield * this.blockMap(token) + if (token === '[') return yield * this.flowSeq(token) + if (token === '!') return true + return yield * this.scalar(token) + } + + * blockMap (open) { + this.stack.push(open) + yield { type: 'map-start', depth: this.stack.length } + while (this.index < this.tokens.length && this.tokens[this.index] !== '}') { + const stop = yield * this.step() + if (stop) return stop + } + this.index++ + this.stack.pop() + const reply = yield { type: 'map-end', depth: this.stack.length + 1 } + if (reply !== undefined) yield { type: 'reply', value: reply } + return false + } + + * flowSeq (open) { + this.stack.push(open) + let count = 0 + while (this.index < this.tokens.length && this.tokens[this.index] !== ']') { + yield * this.step() + count++ + } + this.index++ + this.stack.pop() + yield { type: 'seq', count } + return false + } + + * scalar (token) { + const value = yield { type: 'scalar', source: token } + if (value !== undefined) return yield * this.scalar(String(value)) + return false + } + + * end () { + yield { type: 'end', depth: this.stack.length } + return this.index + } +} + +function parseTokens (source) { + const tokens = [] + for (const token of new Parser(source).parse()) tokens.push(JSON.stringify(token)) + return tokens +} + +// next(value) reaches the innermost delegated generator, and return values +// pass back through each yield*. +function drive (source) { + const parser = new Parser(source).parse() + const log = [] + let result = parser.next() + while (!result.done) { + const value = result.value + log.push(JSON.stringify(value)) + result = parser.next(value.type === 'map-end' ? 'ack' : value.source === 'x' ? 'x2' : undefined) + } + log.push('return ' + result.value) + return log.join('\n') +} + +function spreadTypes (source) { + const tokens = [...new Parser(source).parse()] + return tokens.length + ' ' + tokens.map((token) => token.type).join(',') +} + +// Async generator methods with the same mutual recursion. +class AsyncWalker { + constructor (source) { + this.tokens = source.split(' ') + this.index = 0 + } + + async * walk () { + while (this.index < this.tokens.length) yield * this.next() + return this.index + } + + async * next () { + const token = this.tokens[this.index++] + await null + if (token === '(') return yield * this.group() + yield token + return token + } + + async * group () { + const inner = [] + while (this.tokens[this.index] !== ')') inner.push(yield * this.next()) + this.index++ + yield 'group:' + inner.join('+') + return inner.length + } +} + +async function walkAll (source) { + const seen = [] + const walker = new AsyncWalker(source).walk() + let result = await walker.next() + while (!result.done) { + seen.push(result.value) + result = await walker.next() + } + return seen.join(' ') + ' -> ' + result.value +} + +module.exports = { parseTokens, drive, spreadTypes, walkAll } diff --git a/tests/corpus/8221-js-recursive-generator-returns/node_modules/token-parser/package.json b/tests/corpus/8221-js-recursive-generator-returns/node_modules/token-parser/package.json new file mode 100644 index 000000000..1fa77c2eb --- /dev/null +++ b/tests/corpus/8221-js-recursive-generator-returns/node_modules/token-parser/package.json @@ -0,0 +1 @@ +{ "name": "token-parser", "version": "1.0.0", "main": "dist/index.js", "types": "dist/index.d.ts" } diff --git a/tests/corpus/8222-js-class-static-reflection.js b/tests/corpus/8222-js-class-static-reflection.js new file mode 100644 index 000000000..74027cc64 --- /dev/null +++ b/tests/corpus/8222-js-class-static-reflection.js @@ -0,0 +1,94 @@ +'use strict' +// A class's statics extracted, then removed with Reflect.deleteProperty, and +// redefined with Object.defineProperties (undici's FormData and Response). + +const kEnumerableProperty = { __proto__: null, enumerable: true } + +class FormData { + #state = [] + append (name, value) { this.#state.push({ name, value }) } + static getFormDataState (formData) { return formData.#state } + static setFormDataState (formData, state) { formData.#state = state } +} + +const getFormDataState = FormData.getFormDataState +const setFormDataState = FormData.setFormDataState +console.log(Reflect.deleteProperty(FormData, 'getFormDataState')) +console.log(Reflect.deleteProperty(FormData, 'setFormDataState')) +console.log(Reflect.deleteProperty(FormData, 'missing')) +console.log(typeof FormData.getFormDataState, typeof FormData.setFormDataState) + +const form = new FormData() +form.append('a', 1) +form.append('b', 'two') +console.log(getFormDataState(form)) +setFormDataState(form, [{ name: 'c', value: true }]) +console.log(getFormDataState(form).length, getFormDataState(form)[0].name) +try { + FormData.getFormDataState(form) +} catch (error) { + console.log(error.constructor.name, error.message) +} + +class Response { + #status + constructor (status) { this.#status = status } + get status () { return this.#status } + static json () { return new Response(200) } + static error () { return new Response(0) } + static getResponseState (response) { return response.#status } +} + +const getResponseState = Response.getResponseState +Reflect.deleteProperty(Response, 'getResponseState') +Object.defineProperties(Response, { + json: kEnumerableProperty, + error: kEnumerableProperty +}) +const response = Response.json() +console.log(response.status, Response.error().status, getResponseState(response)) +for (const key of ['json', 'error', 'getResponseState']) { + const descriptor = Object.getOwnPropertyDescriptor(Response, key) + console.log(key, descriptor === undefined ? 'absent' : [descriptor.enumerable, descriptor.writable, descriptor.configurable, typeof descriptor.value]) +} + +// Statics a subclass inherits, a static field and a static accessor. +class Base { + static helper () { return 'helper' } + static count = 3 + static get label () { return 'label' } +} +class Child extends Base {} +console.log(Child.helper(), Child.count, Child.label) +console.log(Reflect.deleteProperty(Base, 'helper'), Reflect.deleteProperty(Base, 'count')) +console.log(typeof Child.helper, Child.count, typeof Base.helper, Base.count) +console.log(Reflect.deleteProperty(Base, 'label'), Base.label, Child.label) +Base.helper = () => 'replaced' +console.log(Base.helper(), Child.helper()) +Base.count = 4 +const countKey = { toString () { return 'count' } } +console.log(Reflect.deleteProperty(Base, countKey), Base.count) +class Key { + constructor (name) { this.name = name } + toString () { return this.name } +} +Base.count = 5 +console.log(Reflect.deleteProperty(Base, new Key('count')), Base.count) + +// Checked-dynamic objects and primitive targets. +const parsed = JSON.parse('{"a":1,"b":2}') +console.log(Reflect.deleteProperty(parsed, 'a'), parsed) +const frozen = Object.freeze(JSON.parse('{"a":1}')) +console.log(Reflect.deleteProperty(frozen, 'a'), frozen) +const attempt = (run) => { + try { + run() + } catch (error) { + console.log(error.constructor.name, error.message) + } +} +attempt(() => Reflect.deleteProperty(1, 'a')) +attempt(() => Reflect.deleteProperty('text', 'a')) +attempt(() => Reflect.deleteProperty(null, 'a')) +attempt(() => Reflect.deleteProperty(undefined, 'a')) +attempt(() => Reflect.deleteProperty(true, 'a')) diff --git a/tests/coverage-fixtures/cjs-mutable-exports/main.js b/tests/coverage-fixtures/cjs-mutable-exports/main.js new file mode 100644 index 000000000..ac16cc4ec --- /dev/null +++ b/tests/coverage-fixtures/cjs-mutable-exports/main.js @@ -0,0 +1,5 @@ +const reassigned = require('./reassigned'); +const written = require('./written'); +const redeclared = require('./redeclared'); +const stable = require('./stable'); +console.log(reassigned.n, written.tab, redeclared.twice, stable.n); diff --git a/tests/coverage-fixtures/cjs-mutable-exports/package.json b/tests/coverage-fixtures/cjs-mutable-exports/package.json new file mode 100644 index 000000000..a3c15a7a6 --- /dev/null +++ b/tests/coverage-fixtures/cjs-mutable-exports/package.json @@ -0,0 +1 @@ +{ "type": "commonjs" } diff --git a/tests/coverage-fixtures/cjs-mutable-exports/reassigned.js b/tests/coverage-fixtures/cjs-mutable-exports/reassigned.js new file mode 100644 index 000000000..6c77f3b43 --- /dev/null +++ b/tests/coverage-fixtures/cjs-mutable-exports/reassigned.js @@ -0,0 +1,4 @@ +// Reassigned after the export: Node's importers keep the first object. +var counter = { n: 1 }; +module.exports = counter; +counter = { n: 2 }; diff --git a/tests/coverage-fixtures/cjs-mutable-exports/redeclared.js b/tests/coverage-fixtures/cjs-mutable-exports/redeclared.js new file mode 100644 index 000000000..3150903f6 --- /dev/null +++ b/tests/coverage-fixtures/cjs-mutable-exports/redeclared.js @@ -0,0 +1,4 @@ +// Declared twice: the second declaration assigns the binding again. +var twice = 1; +module.exports = { twice }; +var twice = 2; diff --git a/tests/coverage-fixtures/cjs-mutable-exports/stable.js b/tests/coverage-fixtures/cjs-mutable-exports/stable.js new file mode 100644 index 000000000..c2846bbc9 --- /dev/null +++ b/tests/coverage-fixtures/cjs-mutable-exports/stable.js @@ -0,0 +1,3 @@ +// Initialized before the export and never assigned. +var stable = { n: 3 }; +module.exports = stable; diff --git a/tests/coverage-fixtures/cjs-mutable-exports/written.js b/tests/coverage-fixtures/cjs-mutable-exports/written.js new file mode 100644 index 000000000..8e0c29cd2 --- /dev/null +++ b/tests/coverage-fixtures/cjs-mutable-exports/written.js @@ -0,0 +1,4 @@ +// Written by a function: the table holds the value at the export. +let tab = ' '; +function setTab(next) { tab = next; } +module.exports = { tab, setTab }; diff --git a/tests/diagnostics/intl-segmenter.ts b/tests/diagnostics/intl-segmenter.ts index 42bdae846..0cf30eabb 100644 --- a/tests/diagnostics/intl-segmenter.ts +++ b/tests/diagnostics/intl-segmenter.ts @@ -1,5 +1,5 @@ -// The native implementation covers default Unicode grapheme segmentation. -new Intl.Segmenter("en-US"); +// The native implementation covers Unicode grapheme segmentation. +new Intl.Segmenter(["en-US", "de"]); new Intl.Segmenter(undefined, { granularity: "word" }); new Intl.Segmenter(undefined, { granularity: "sentence" }); // End of the diagnostic fixture. diff --git a/tests/fixtures/npm-static/node_modules/word-segments/index.d.ts b/tests/fixtures/npm-static/node_modules/word-segments/index.d.ts new file mode 100644 index 000000000..2fd45310e --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/word-segments/index.d.ts @@ -0,0 +1 @@ +export declare function splitWords(text: string): string; diff --git a/tests/fixtures/npm-static/node_modules/word-segments/index.js b/tests/fixtures/npm-static/node_modules/word-segments/index.js new file mode 100644 index 000000000..a67aa5381 --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/word-segments/index.js @@ -0,0 +1,9 @@ +const words = new Intl.Segmenter(undefined, { granularity: "word" }); + +export function splitWords(text) { + try { + return [...words.segment(text)].map((part) => part.segment).join("|"); + } catch (error) { + return `${error.code}: ${error.message}`; + } +} diff --git a/tests/fixtures/npm-static/node_modules/word-segments/package.json b/tests/fixtures/npm-static/node_modules/word-segments/package.json new file mode 100644 index 000000000..37b0d6f73 --- /dev/null +++ b/tests/fixtures/npm-static/node_modules/word-segments/package.json @@ -0,0 +1 @@ +{ "name": "word-segments", "version": "1.0.0", "type": "module", "main": "index.js", "types": "index.d.ts" } diff --git a/tests/fixtures/npm-static/word-segments-cli.ts b/tests/fixtures/npm-static/word-segments-cli.ts new file mode 100644 index 000000000..28e3bd5e1 --- /dev/null +++ b/tests/fixtures/npm-static/word-segments-cli.ts @@ -0,0 +1,3 @@ +import { splitWords } from "word-segments"; + +console.log(splitWords("two words")); diff --git a/tests/harness/__snapshots__/intl-segmenter.ts.txt b/tests/harness/__snapshots__/intl-segmenter.ts.txt index e50205eec..19a13ef4f 100644 --- a/tests/harness/__snapshots__/intl-segmenter.ts.txt +++ b/tests/harness/__snapshots__/intl-segmenter.ts.txt @@ -1,15 +1,15 @@ intl-segmenter.ts:2:1 - error SC2020: 'Intl.Segmenter locale negotiation' is part of the standard library types but has no scriptc lowering yet - 1 | // The native implementation covers default Unicode grapheme segmentation. - 2 | new Intl.Segmenter("en-US"); - | ^~~~~~~~~~~~~~~~~~~~~~~~~~~ + 1 | // The native implementation covers Unicode grapheme segmentation. + 2 | new Intl.Segmenter(["en-US", "de"]); + | ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 3 | new Intl.Segmenter(undefined, { granularity: "word" }); - hint: omit the locale or pass undefined for default Unicode grapheme segmentation + hint: omit the locale, pass undefined, or pass one language tag as a string literal intl-segmenter.ts:3:31 - error SC2020: 'Intl.Segmenter options' is part of the standard library types but has no scriptc lowering yet - 2 | new Intl.Segmenter("en-US"); + 2 | new Intl.Segmenter(["en-US", "de"]); 3 | new Intl.Segmenter(undefined, { granularity: "word" }); | ^~~~~~~~~~~~~~~~~~~~~~~ 4 | new Intl.Segmenter(undefined, { granularity: "sentence" }); diff --git a/tests/harness/corpus-costs/8214-unshimmed-package-version/main.ts.json b/tests/harness/corpus-costs/8214-unshimmed-package-version/main.ts.json new file mode 100644 index 000000000..d5d1c5f65 --- /dev/null +++ b/tests/harness/corpus-costs/8214-unshimmed-package-version/main.ts.json @@ -0,0 +1 @@ +{ "plain": 2500, "san": 3500 } diff --git a/tests/harness/corpus-costs/8216-module-namespace-live-values/main.ts.json b/tests/harness/corpus-costs/8216-module-namespace-live-values/main.ts.json new file mode 100644 index 000000000..d5d1c5f65 --- /dev/null +++ b/tests/harness/corpus-costs/8216-module-namespace-live-values/main.ts.json @@ -0,0 +1 @@ +{ "plain": 2500, "san": 3500 } diff --git a/tests/harness/corpus-costs/8217-intl-segmenter-word-construct/main.ts.json b/tests/harness/corpus-costs/8217-intl-segmenter-word-construct/main.ts.json new file mode 100644 index 000000000..d5d1c5f65 --- /dev/null +++ b/tests/harness/corpus-costs/8217-intl-segmenter-word-construct/main.ts.json @@ -0,0 +1 @@ +{ "plain": 2500, "san": 3500 } diff --git a/tests/harness/corpus-costs/8218-cjs-namespace-imports/main.mjs.json b/tests/harness/corpus-costs/8218-cjs-namespace-imports/main.mjs.json new file mode 100644 index 000000000..ffabf028f --- /dev/null +++ b/tests/harness/corpus-costs/8218-cjs-namespace-imports/main.mjs.json @@ -0,0 +1 @@ +{ "plain": 7000, "san": 7200 } diff --git a/tests/harness/corpus-costs/8219-cjs-stable-var-exports/main.js.json b/tests/harness/corpus-costs/8219-cjs-stable-var-exports/main.js.json new file mode 100644 index 000000000..f8d95630e --- /dev/null +++ b/tests/harness/corpus-costs/8219-cjs-stable-var-exports/main.js.json @@ -0,0 +1 @@ +{ "plain": 8300, "san": 7400 } diff --git a/tests/harness/corpus-costs/8220-js-class-static-destructuring/main.js.json b/tests/harness/corpus-costs/8220-js-class-static-destructuring/main.js.json new file mode 100644 index 000000000..8b730689b --- /dev/null +++ b/tests/harness/corpus-costs/8220-js-class-static-destructuring/main.js.json @@ -0,0 +1 @@ +{ "plain": 10100, "san": 9400 } diff --git a/tests/harness/corpus-costs/8221-js-recursive-generator-returns/main.ts.json b/tests/harness/corpus-costs/8221-js-recursive-generator-returns/main.ts.json new file mode 100644 index 000000000..e6c42bf47 --- /dev/null +++ b/tests/harness/corpus-costs/8221-js-recursive-generator-returns/main.ts.json @@ -0,0 +1 @@ +{ "plain": 6600, "san": 6000 } diff --git a/tests/harness/corpus-costs/8222-js-class-static-reflection.js.json b/tests/harness/corpus-costs/8222-js-class-static-reflection.js.json new file mode 100644 index 000000000..7f7902ca1 --- /dev/null +++ b/tests/harness/corpus-costs/8222-js-class-static-reflection.js.json @@ -0,0 +1 @@ +{ "plain": 4500, "san": 4100 } diff --git a/tests/harness/coverage.test.ts b/tests/harness/coverage.test.ts index e1831c609..5b541cc54 100644 --- a/tests/harness/coverage.test.ts +++ b/tests/harness/coverage.test.ts @@ -543,6 +543,16 @@ test("settled generic rest-order fences count each source statement once", () => expect(coverage.stats.statementsFailed).toBe(2); }); +test("CommonJS var and let exports that can change after the export keep their refusal", () => { + // JavaScript refusals defer to run time: they are the runtime fences. + const { coverage } = analyze(fixture("cjs-mutable-exports/main.js")); + const refused = [...coverage.diagnostics, ...(coverage.runtimeFences ?? [])] + .map((d) => /exporting the mutable 'let' binding '(\w+)'/.exec(d.message)?.[1]) + .filter((name) => name !== undefined) + .sort(); + expect(refused).toEqual(["counter", "tab", "twice"]); +}); + test("inferred JavaScript compiles natively", async () => { // The js-gap fixture turns noImplicitAny off. Its inferred parameter // uses checked native values alongside the JSDoc-typed neighbor. diff --git a/tests/harness/npm-static.test.ts b/tests/harness/npm-static.test.ts index 388da2138..838302af4 100644 --- a/tests/harness/npm-static.test.ts +++ b/tests/harness/npm-static.test.ts @@ -523,6 +523,28 @@ describe(`npm-static pilots${sanitize ? " (sanitized)" : ""}`, () => { } }); + test("a word segmenter in a package constructs, and its segment() throws SC2020", async () => { + const entry = join(pilotRoot, "word-segments-cli.ts"); + const { coverage } = analyze(entry, { npmStatic: "auto" }); + expect(coverage.npmStatic).toEqual([{ package: "word-segments", status: "static" }]); + expect(coverage.diagnostics).toHaveLength(0); + const outDir = join(cacheDir, "word-segments", sanitize ? "san" : "plain"); + const result = await compile(entry, { + backend: "llvm", + npmStatic: "auto", + sanitize, + outDir, + outPath: join(outDir, "program"), + }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + const nativeRes = await runBinary(result.binaryPath, []); + expect(nativeRes.stdout.toString()).toMatch( + /^SC2020: Intl\.Segmenter segmentation with granularity 'word' is not supported yet \[SC2020 at .*index\.js:1\]\n$/, + ); + expect(nativeRes.exitCode).toBe(0); + }); + test.each([ 'import { Console as Logger } from "node:console"; new Logger({ stdout: process.stdout }).dir(1);', 'import * as output from "console"; new output.Console(process.stdout).table([1, 2]);', diff --git a/tests/harness/package-shims.test.ts b/tests/harness/package-shims.test.ts index ca3d1589b..a21c4e768 100644 --- a/tests/harness/package-shims.test.ts +++ b/tests/harness/package-shims.test.ts @@ -8,7 +8,8 @@ * stays unloaded: its require throws MODULE_NOT_FOUND; * - a shimmed package that is not installed, or whose major version has no * shim, resolves exactly as before (here: refused like any missing or - * uncompiled package); + * uncompiled package), and `--npm-static` does not compile a version the + * registry entry does not list in `sourceVersions`; * - the undici shims keep memory bounded against a peer that sends endless * chunk-size lines and large or compressed bodies, and the 5.x profile * rejects a Host value with CR or LF as undici 5.29 does (the vendored @@ -253,6 +254,33 @@ describe("package shims", () => { } }, 180_000); + test("--npm-static leaves out an implemented package at a version it does not list", async () => { + const dir = join(scratch, "undici-v6-npm-static"); + const pkg = join(dir, "node_modules/undici"); + mkdirSync(pkg, { recursive: true }); + writeFileSync( + join(pkg, "package.json"), + '{ "name": "undici", "version": "6.21.0", "main": "index.js" }\n', + ); + writeFileSync(join(pkg, "index.js"), "exports.version = 6;\n"); + writeFileSync( + join(dir, "main.mjs"), + 'import { version } from "undici";\nconsole.log(version);\n', + ); + const result = await compile(join(dir, "main.mjs"), { + outPath: join(dir, ".scriptc/program"), + outDir: join(dir, ".scriptc"), + npmStatic: ["undici"], + sanitize, + }); + // The package's JavaScript is not part of the program, so the import + // has no declarations. + expect(result.ok).toBe(false); + expect(result.diagnostics.map((d) => d.message).join("\n")).toContain( + "Could not find a declaration file for module 'undici'", + ); + }, 180_000); + for (const name of ["undici7", "undici5"]) { test(`${name}: endless chunk-size lines and large bodies stay in bounded memory`, async () => { const { dir, binary } = await buildInCase(name, "undici-bounded.ts"); From 41664c903b18e943bb26e94c0cd743692b364036 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 12:03:38 -0500 Subject: [PATCH 111/259] Walk files iteratively in the untyped collection inference The declaration and reference sweeps recursed through ts.forEachChild, two JS frames per AST level, so a 7000-level expression overflowed the stack before the expression lowering's 200-level SC1090 fence. Both sweeps use ts.walkPreorder now, and primitiveOf answers null past the same 200 levels. --- .../frontend/lowering/js-collection-types.ts | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/js-collection-types.ts b/packages/compiler/src/frontend/lowering/js-collection-types.ts index 2be3c067f..8820ade4a 100644 --- a/packages/compiler/src/frontend/lowering/js-collection-types.ts +++ b/packages/compiler/src/frontend/lowering/js-collection-types.ts @@ -55,6 +55,8 @@ const MAP_LOOKUPS = new Set(["get", "has", "delete"]); const SET_LOOKUPS = new Set(["has", "delete"]); const ARRAY_READS = new Set(["pop", "shift"]); const ARRAY_SEARCHES = new Set(["includes", "indexOf"]); +/** The expression lowering refuses deeper nesting (SC1090). */ +const MAX_DEPTH = 200; /** The inferred type of the binding a `new Map()` or `new Set()` initializes, * which the construction adopts. */ @@ -153,9 +155,8 @@ function inferFile(lowerer: Lowerer, file: ts.SourceFile): Candidate[] { value: undefined, }); } - ts.forEachChild(node, declarations); }; - declarations(file); + ts.walkPreorder(file, declarations); if (directEval || candidates.size === 0) return []; const names = new Set( @@ -171,9 +172,8 @@ function inferFile(lowerer: Lowerer, file: ts.SourceFile): Candidate[] { else refused.add(symbol); } } - ts.forEachChild(node, references); }; - references(file); + ts.walkPreorder(file, references); for (const symbol of refused) candidates.delete(symbol); const proven = [...candidates.values()].filter( (c) => c.valueWrites.length > 0 || c.keyWrites.length > 0, @@ -381,16 +381,20 @@ function checkerPrimitive(type: ts.Type): Primitive | null { /** The primitive type `e` always evaluates to, or null. The checker answers * where it knows; where it types `e` as `any`, the value's structure does: * a read of a decided candidate, arithmetic and comparisons over such - * values, and constants defined from them. */ + * values, and constants defined from them. An expression nested deeper than + * the lowering's nesting limit answers null. */ function primitiveOf( lowerer: Lowerer, bySymbol: Map, e: ts.Expression, visiting: Set, + depth = 0, ): Primitive | null { + if (depth > MAX_DEPTH) return null; const type = lowerer.checker.getTypeAtLocation(e); if ((type.flags & (ts.TypeFlags.Any | ts.TypeFlags.Unknown)) === 0) return checkerPrimitive(type); - const of = (x: ts.Expression): Primitive | null => primitiveOf(lowerer, bySymbol, x, visiting); + const of = (x: ts.Expression): Primitive | null => + primitiveOf(lowerer, bySymbol, x, visiting, depth + 1); if (ts.isParenthesizedExpression(e)) return of(e.expression); if (ts.isPrefixUnaryExpression(e)) { if (e.operator === ts.SyntaxKind.ExclamationToken) return "boolean"; @@ -461,7 +465,7 @@ function primitiveOf( (declaration.parent.flags & ts.NodeFlags.Const) !== 0 ) { visiting.add(e); - const p = primitiveOf(lowerer, bySymbol, declaration.initializer, visiting); + const p = primitiveOf(lowerer, bySymbol, declaration.initializer, visiting, depth + 1); visiting.delete(e); return p; } From 31d3ba07ca60ded1bc78d97010a6d24529556699 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 12:22:19 -0500 Subject: [PATCH 112/259] Reuse dev builds' frontend output after edits that keep token positions A native build reuses its stale frontend cache entry when every changed source is token-equivalent to the text the entry was built from, but dev builds never did: their debug information records source lines and columns, which a token-equivalent edit can move. Builds with debug information (dev builds without --strip) now reuse the entry when every changed source is token-equivalent and every token keeps its line and column (tokenPositionEquivalentSource): edits to a comment's text within its line, comments and whitespace after the last token, and trailing whitespace. Edits that move a token still rebuild. The token scanner also reads a `/` after a non-null assertion as division (`data[i]! / 7`). It used to read it as the start of a regular expression and give up on the file, so comment edits in files with that pattern always rebuilt. A `!` after a line break, or after an operator or a keyword such as `return`, still starts a negated regular expression, and a `!` after `)`, `}`, `++` or `--` gives up. --- .../src/frontend/token-equivalence.test.ts | 51 ++++++++++- .../src/frontend/token-equivalence.ts | 89 ++++++++++++++++--- packages/compiler/src/native/prepare.test.ts | 34 ++++++- packages/compiler/src/native/prepare.ts | 17 ++-- 4 files changed, 173 insertions(+), 18 deletions(-) diff --git a/packages/compiler/src/frontend/token-equivalence.test.ts b/packages/compiler/src/frontend/token-equivalence.test.ts index 880a07221..7bbe08929 100644 --- a/packages/compiler/src/frontend/token-equivalence.test.ts +++ b/packages/compiler/src/frontend/token-equivalence.test.ts @@ -1,8 +1,10 @@ import { expect, test } from "vitest"; -import { tokenEquivalentSource } from "./token-equivalence.js"; +import { tokenEquivalentSource, tokenPositionEquivalentSource } from "./token-equivalence.js"; const equivalent = (previous: string, current: string, path = "/src/a.ts") => tokenEquivalentSource(path, previous, current); +const positionEquivalent = (previous: string, current: string, path = "/src/a.ts") => + tokenPositionEquivalentSource(path, previous, current); test("whitespace and plain comments are trivia", () => { expect(equivalent("const a = 1;\n", "const a = 1; // one\n")).toBe(true); @@ -105,3 +107,50 @@ test("text the scanner cannot classify is never equivalent", () => { expect(equivalent("const a = ; // a\n", "const a = ; // b\n", "/src/a.tsx")).toBe(false); expect(equivalent('const s = "open\n', 'const s = "open // \n')).toBe(false); }); + +test("a / after a non-null assertion divides", () => { + expect( + equivalent("const q = data[i]! / 7; // ratio\n", "const q = data[i]! / 7; // the ratio\n"), + ).toBe(true); + expect( + equivalent("const q = value! / 7; // ratio\n", "const q = value! / 7; // the ratio\n"), + ).toBe(true); + expect(equivalent("const q = this! / 7; // ratio\n", "const q = this! / 7; // the ratio\n")).toBe( + true, + ); + // A prefix `!` negates a regular expression, whose `//` is code. + expect( + equivalent("const t = !/[//]/.test(s); c = 1;\n", "const t = !/[//]/.test(s); c = 2;\n"), + ).toBe(false); + expect(equivalent("return !/[//]/.test(s); // one\n", "return !/[//]/.test(s); // two\n")).toBe( + true, + ); + // After a line break, `!` starts a new expression. + expect(equivalent("a\n!/[//]/.test(s); c = 1;\n", "a\n!/[//]/.test(s); c = 2;\n")).toBe(false); + // `f()!` and `if (a) !` read the same up to the `/`. + expect(equivalent("const q = f()! / 2; // one\n", "const q = f()! / 2; // two\n")).toBe(false); +}); + +test("position equivalence also keeps every token's line and column", () => { + const source = "const a = 1; // one\nconst b = a; /* two */ f(b);\n"; + // A comment's text within its line, after the line's last token. + expect( + positionEquivalent(source, "const a = 1; // the first\nconst b = a; /* two */ f(b);\n"), + ).toBe(true); + // Comments and whitespace after the last token, and trailing whitespace. + expect(positionEquivalent(source, source + "// appended\n\n")).toBe(true); + expect( + positionEquivalent(source, "const a = 1; // one\nconst b = a; /* two */ f(b); \n"), + ).toBe(true); + expect(positionEquivalent(source, source.replaceAll("\n", "\r\n"))).toBe(true); + // A longer comment before a token moves its column; a new line moves the + // lines below it. Both stay token-equivalent. + const column = "const a = 1; // one\nconst b = a; /* the second */ f(b);\n"; + const line = "// header\nconst a = 1; // one\nconst b = a; /* two */ f(b);\n"; + expect(positionEquivalent(source, column)).toBe(false); + expect(positionEquivalent(source, line)).toBe(false); + expect(equivalent(source, column)).toBe(true); + expect(equivalent(source, line)).toBe(true); + // A token edit is never equivalent. + expect(positionEquivalent(source, source.replace("1", "2"))).toBe(false); +}); diff --git a/packages/compiler/src/frontend/token-equivalence.ts b/packages/compiler/src/frontend/token-equivalence.ts index 7a0f6cc79..9f6fd4613 100644 --- a/packages/compiler/src/frontend/token-equivalence.ts +++ b/packages/compiler/src/frontend/token-equivalence.ts @@ -17,7 +17,10 @@ * before it. After `)` it divides unless the parenthesis closes an `if`, * `while`, `for`, `for await`, or `with` header. After `}`, `++` or * `--` the scanner cannot tell which, so it gives up, as it does for - * escaped identifiers, which can spell keywords. + * escaped identifiers, which can spell keywords. After `!` in + * TypeScript it divides when the `!` follows an operand on the same line + * (a non-null assertion, `x! / 2`) and gives up when that operand is a + * `)`, `}`, `++` or `--`. * - A `/` with a line break (or a comment that spans lines) since the * previous token gives up: whether automatic semicolon insertion ends the * statement before it decides how it reads. @@ -35,6 +38,8 @@ interface Token { text: string; comment: boolean; lineBreakBefore: boolean; + /** The offset of the token's first code unit. */ + start: number; } /** Keywords after which `/` starts a regular expression. */ @@ -135,14 +140,20 @@ function scan(path: string, source: string): Token[] | null { // A line break, or a comment spanning lines, since the last token other // than a comment. let breakSinceCode = false; - // The previous token and the one before it, and whether a `)` closed a - // statement header. - const last: { token: string | null; before: string | null } = { token: null, before: null }; + // The previous token and the one before it, whether a line break came + // before the previous token, and whether a `)` closed a statement header. + const last: { token: string | null; before: string | null; broke: boolean } = { + token: null, + before: null, + broke: false, + }; let closedHeader = false; + // Every token ends at `index` when it is pushed. const push = (text: string, comment = false): void => { - tokens.push({ text, comment, lineBreakBefore }); + tokens.push({ text, comment, lineBreakBefore, start: index - text.length }); lineBreakBefore = false; if (!comment) { + last.broke = breakSinceCode; breakSinceCode = false; last.before = last.token; last.token = text; @@ -291,7 +302,19 @@ function scan(path: string, source: string): Token[] | null { else if (before.startsWith("'") || before.startsWith('"') || before.endsWith("`")) regex = false; else if (before.startsWith("/") && before.length > 1 && before !== "/=") regex = false; - else regex = true; + else if (before === "!" && typeScript && !last.broke && last.before !== null) { + // `x! / 2` divides: a `!` right after an operand on the same line is + // a non-null assertion. `!/re/.test(s)` negates a regular expression. + const operand = last.before; + if (operand === ")" || operand === "}" || operand === "++" || operand === "--") return null; + regex = !( + operand === "]" || + operand.startsWith("'") || + operand.startsWith('"') || + operand.endsWith("`") || + (/^[A-Za-z0-9_$]/.test(operand) && !EXPRESSION_KEYWORDS.has(operand)) + ); + } else regex = true; if (regex) { const start = index; index++; @@ -373,9 +396,33 @@ function scan(path: string, source: string): Token[] | null { return tokens; } -/** Whether `current` differs from `previous` only in whitespace and in - * comments that cannot affect compilation. */ -export function tokenEquivalentSource(path: string, previous: string, current: string): boolean { +/** The line and column of each token's start, with the line terminators + * source locations count (backend/source-locations.ts). */ +function tokenPositions(source: string, tokens: readonly Token[]): number[] { + const positions: number[] = []; + let line = 0; + let lineStart = 0; + let offset = 0; + for (const token of tokens) { + for (; offset < token.start; offset++) { + const code = source.charCodeAt(offset); + if (code === 13 && source.charCodeAt(offset + 1) === 10) offset++; + if (code === 10 || code === 13 || code === 0x2028 || code === 0x2029) { + line++; + lineStart = offset + 1; + } + } + positions.push(line, token.start - lineStart); + } + return positions; +} + +function equivalentSources( + path: string, + previous: string, + current: string, + positions: boolean, +): boolean { if (previous === current) return true; const left = scan(path, previous); if (left === null) return false; @@ -387,5 +434,27 @@ export function tokenEquivalentSource(path: string, previous: string, current: s if (a.text !== b.text || a.comment !== b.comment) return false; if (index > 0 && a.lineBreakBefore !== b.lineBreakBefore) return false; } - return true; + if (!positions) return true; + const before = tokenPositions(previous, left); + const after = tokenPositions(current, right); + return before.every((value, index) => value === after[index]); +} + +/** Whether `current` differs from `previous` only in whitespace and in + * comments that cannot affect compilation. */ +export function tokenEquivalentSource(path: string, previous: string, current: string): boolean { + return equivalentSources(path, previous, current, false); +} + +/** Whether `current` is token-equivalent to `previous` (tokenEquivalentSource) + * and every token keeps its line and column: the edit leaves the source + * positions debug information records unchanged (a comment's text within + * its line, comments and whitespace after the last token, trailing + * whitespace). */ +export function tokenPositionEquivalentSource( + path: string, + previous: string, + current: string, +): boolean { + return equivalentSources(path, previous, current, true); } diff --git a/packages/compiler/src/native/prepare.test.ts b/packages/compiler/src/native/prepare.test.ts index 7ae2d1d5f..5d0f9faae 100644 --- a/packages/compiler/src/native/prepare.test.ts +++ b/packages/compiler/src/native/prepare.test.ts @@ -70,7 +70,7 @@ function fixture() { loads++; return runFrontend(path, loadProgram, npmStatic, externalTypes); }; - const prepare = (extra: { emitIr?: boolean } = {}) => + const prepare = (extra: { emitIr?: boolean; optimization?: "release" | "dev" } = {}) => prepareNativeExecutable(entry, { ...options, ...extra }, null, toolchain, frontend, cache); return { root, entry, dependency, cache, options, prepare, loads: () => loads }; } @@ -123,6 +123,38 @@ test("comment and whitespace edits reuse the frontend output a fresh build repro expect(edited.ok && edited.llvm.join("")).not.toBe(first.llvm.join("")); }); +test("a dev build reuses its frontend output after edits that keep every token's position", () => { + const f = fixture(); + const dev = { optimization: "dev" as const }; + const first = f.prepare(dev); + expect(first.ok, JSON.stringify(first)).toBe(true); + if (!first.ok) return; + // Debug information records lines and columns: a comment after the last + // token and trailing whitespace keep them. + const appended = 'export const value = "first"; \n// The exported value.\n'; + writeFileSync(f.dependency, appended); + const reused = f.prepare(dev); + expect(f.loads()).toBe(1); + expect(reused.ok).toBe(true); + if (!reused.ok) return; + expect(reused.llvm.join("")).toBe(first.llvm.join("")); + expect(new Map(reused.sources).get(f.dependency)).toBe(appended); + const fresh = prepareNativeExecutable( + f.entry, + { ...f.options, ...dev }, + null, + fixtureToolchain(), + (path, npmStatic, externalTypes) => runFrontend(path, loadProgram, npmStatic, externalTypes), + new NativeCache(join(f.root, "fresh-cache")), + ); + expect(fresh.ok && fresh.llvm.join("")).toBe(first.llvm.join("")); + // A comment that moves the token after it is rebuilt. + writeFileSync(f.dependency, '// The exported value.\nexport const value = "first";\n'); + const moved = f.prepare(dev); + expect(f.loads()).toBe(2); + expect(moved.ok && moved.llvm.join("")).not.toBe(first.llvm.join("")); +}); + test("a comment edit inside source text the output carries is rebuilt", () => { const f = fixture(); // A failing assert(value) reports its call's source text. diff --git a/packages/compiler/src/native/prepare.ts b/packages/compiler/src/native/prepare.ts index 2efc3e4d7..7118e47b9 100644 --- a/packages/compiler/src/native/prepare.ts +++ b/packages/compiler/src/native/prepare.ts @@ -32,7 +32,10 @@ import { import { compilerOwnedFileRoots } from "../frontend/dts-paths.js"; import { provenanceSources } from "../frontend/provenance-registry.js"; import { processFork } from "../frontend/process-fork.js"; -import { tokenEquivalentSource } from "../frontend/token-equivalence.js"; +import { + tokenEquivalentSource, + tokenPositionEquivalentSource, +} from "../frontend/token-equivalence.js"; import { llvmBytes, wtf8Bytes } from "../backend/literals.js"; import { prepareLibrary } from "../library/prepare.js"; import type { LibraryProfile } from "../library/library-profile.js"; @@ -143,9 +146,11 @@ function readFrontendCache( /** The stale entry's input when every changed source is token-equivalent to * the text the entry was built from (edits to whitespace and to comments * that cannot affect compilation; see token-equivalence.ts). Equivalent - * sources lower to the same IR apart from source locations, which only dev - * builds' debug information and the serialized IR carry. Diagnostics carry - * locations too, so an entry that reported warnings is rebuilt. A changed + * sources lower to the same IR apart from source locations, which only the + * debug information of dev builds and the serialized IR carry. A build + * with debug information accepts only edits that keep every token's line + * and column, the positions the debug information records. Diagnostics + * carry locations too, so an entry that reported warnings is rebuilt. A changed * source whose raw text or line positions the frontend read (call-site text * in messages, comptime callbacks, test locations) is rebuilt as well: * frontendInputsSemanticallyMatch refuses its `text` probe. */ @@ -155,17 +160,17 @@ function equivalentFrontendInput( exclusions: FrontendInputExclusions, ): { input: NativeExecutableInput; probes: FrontendInputSnapshot } | null { if ( - options.optimization === "dev" || options.sanitize === true || options.emitIr === true || stale.ir !== null || (stale.input.warnings?.length ?? 0) > 0 ) return null; + const debugInfo = options.optimization === "dev" && !options.strip; const match = frontendInputsSemanticallyMatch( stale.probes, new Map(stale.input.sources), - tokenEquivalentSource, + debugInfo ? tokenPositionEquivalentSource : tokenEquivalentSource, exclusions, ); if (match === null || match.changed.length === 0) return null; From 8796e91f5ef6a358a9b4cb6c4372827b9618c3e0 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 12:37:29 -0500 Subject: [PATCH 113/259] Keep while-loop counters bounded by a typed array length in integers --- .../src/backend/llvm/emit-statements.ts | 2 +- .../compiler/src/ir/integer-loop-facts.ts | 90 +++++++- .../compiler/src/ir/integer-ranges.test.ts | 74 ++++++- packages/compiler/src/ir/integer-ranges.ts | 16 +- .../8002-while-byte-length-companions.ts.json | 6 + .../test/while-induction-emission.test.ts | 94 ++++++++ .../8002-while-byte-length-companions.ts | 201 ++++++++++++++++++ .../8002-while-byte-length-companions.ts.json | 1 + 8 files changed, 477 insertions(+), 7 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8002-while-byte-length-companions.ts.json create mode 100644 packages/compiler/test/while-induction-emission.test.ts create mode 100644 tests/corpus/8002-while-byte-length-companions.ts create mode 100644 tests/harness/corpus-costs/8002-while-byte-length-companions.ts.json diff --git a/packages/compiler/src/backend/llvm/emit-statements.ts b/packages/compiler/src/backend/llvm/emit-statements.ts index 55e31219c..d356bfa3d 100644 --- a/packages/compiler/src/backend/llvm/emit-statements.ts +++ b/packages/compiler/src/backend/llvm/emit-statements.ts @@ -2437,7 +2437,7 @@ function planProvenLoop( loop: Extract, ): ProvenLoopPlan | null { if ( - loop.kind !== "for" || + loop.kind === "doWhile" || !emitter.speculativeLoopsEnabled || emitter.speculation !== null || emitter.speculationResume !== null || diff --git a/packages/compiler/src/ir/integer-loop-facts.ts b/packages/compiler/src/ir/integer-loop-facts.ts index 8807212dc..d66153b19 100644 --- a/packages/compiler/src/ir/integer-loop-facts.ts +++ b/packages/compiler/src/ir/integer-loop-facts.ts @@ -152,7 +152,7 @@ export function boundedIntegerLoopFacts( e.receiver.kind === "varRef" && stable(e.receiver.localId) ) - return { min: 0, max: Number.MAX_SAFE_INTEGER }; + return BYTES_LENGTH_RANGE; // Every evaluation of an array length lies in its range, so the // condition bounds each pass even when the body resizes the array. if (isArrayLength(e)) return ARRAY_LENGTH_RANGE; @@ -225,6 +225,12 @@ export function boundedIntegerLoopFacts( return result; } +/** Every length, byteLength and byteOffset of a typed array, DataView or + * Buffer: each counts elements or bytes of one allocation, and every + * supported target addresses less than 2^48 bytes. Counters and offsets + * derived from them then stay exact integers far below 2^53. */ +export const BYTES_LENGTH_RANGE: IntegerRange = { min: 0, max: 2 ** 48 }; + /** Every length an array can have: SCR_ARR_MAX_LENGTH (scr_array.c). */ export const ARRAY_LENGTH_RANGE: IntegerRange = { min: 0, max: 4294967295 }; @@ -353,6 +359,13 @@ export function guardedLoopCounterFacts( stable(e.receiver.localId) ) return { min: 0, max: STRING_MAX_UNITS }; + if ( + e.kind === "bytesIntrinsic" && + (e.method === "length" || e.method === "byteLength") && + e.receiver.kind === "varRef" && + stable(e.receiver.localId) + ) + return BYTES_LENGTH_RANGE; // An array length can change on any pass, but never leaves its range, // which is all a ceiling needs. if (isArrayLength(e)) return ARRAY_LENGTH_RANGE; @@ -402,9 +415,84 @@ export function guardedLoopCounterFacts( if (Number.isSafeInteger(start.min) && Number.isSafeInteger(max)) result.set(id, { min: start.min, max }); } + // Companion counters: a binding the loop changes only by positive literal + // increments that no condition bounds (`out[k++] = ...` beside + // `while (i < n)`). A bounded counter that every pass advances before it + // can continue limits the number of passes, and each pass adds at most + // the companion's increments in the body. Increments inside nested loops + // can repeat within a pass, so those companions are not bounded. + let passes = Infinity; + for (const [id, range] of result) { + const hi = ceiling.get(id)!; + const step = guaranteedStep(loop.body, id); + if (step <= 0) continue; + passes = Math.min(passes, Math.floor((hi - range.min) / step) + 1); + } + if (!Number.isSafeInteger(passes) || passes < 0) return result; + const repeated = new Set(); + for (const inner of nested) for (const id of writtenLocals(inner.body)) repeated.add(id); + for (const [id, total] of budget) { + const local = locals.get(id), + start = initial.get(id); + if (result.has(id) || refused.has(id) || repeated.has(id) || ceiling.has(id)) continue; + if (!local || local.boxed || local.tdz || !start) continue; + const max = start.max + passes * total; + if (Number.isSafeInteger(start.min) && Number.isSafeInteger(max)) + result.set(id, { min: start.min, max }); + } return result; } +/** The increments of counter `id` that every pass of `body` makes before it + * can start another pass: those of the leading statements up to the first + * one that can continue the loop or holds a nested region (0 when there is + * none). A pass that leaves the loop earlier starts no further pass, so the + * count bounds the passes that continue. */ +function guaranteedStep(body: readonly IrStmt[], id: string): number { + let step = 0; + for (const s of body) { + if (s.kind === "assign" && s.localId === id) { + const delta = increment(id, s.value); + if (delta === null || delta <= 0) return 0; + step += delta; + continue; + } + if (s.kind === "exprStmt" && s.expr.kind === "incDec" && s.expr.localId === id) { + if (s.expr.op !== "+") return 0; + step += 1; + continue; + } + if (mayContinue(s)) break; + } + return step; +} + +/** Whether `s` can start another pass of the enclosing loop before its + * following statements run: it holds a `continue`, a loop or another + * region whose control flow is not walked here. */ +function mayContinue(s: IrStmt): boolean { + let found = false; + const stmt = (x: IrStmt): boolean => { + if ( + x.kind === "continue" || + x.kind === "for" || + x.kind === "while" || + x.kind === "doWhile" || + x.kind === "forOf" || + x.kind === "tryCatch" || + x.kind === "switch" || + (x.kind === "block" && !!x.labels?.length) + ) { + found = true; + return false; + } + return everyStmtChild(x, expr, stmt); + }; + const expr = (e: IrExpr): boolean => everyExprChild(e, expr, stmt); + stmt(s); + return found; +} + /** The largest value counter `id` takes in one pass of `body`, which starts * at most at `entry`. The caller has checked that the body changes the * counter only by positive literal increments outside switch, exception and diff --git a/packages/compiler/src/ir/integer-ranges.test.ts b/packages/compiler/src/ir/integer-ranges.test.ts index 5ae04d28f..318ff2c09 100644 --- a/packages/compiler/src/ir/integer-ranges.test.ts +++ b/packages/compiler/src/ir/integer-ranges.test.ts @@ -828,6 +828,72 @@ test("a while condition on a string's length bounds a counter, and guarded incre expect(run((inside) => [observe(inside), bump, rebound]).after).toBeNull(); }); +test("a while counter every pass advances bounds the companions the loop increments", () => { + // pos = 0; k = 0; while (pos < text.length) { pos++; observe(k); if (unknown === 1) k++; k++; } observe(k) + const text: IrExpr = { loc, kind: "varRef", localId: "text", type: STRING }; + const length: IrExpr = { + loc, + kind: "strIntrinsic", + method: "length", + receiver: text, + args: [], + type: F64, + }; + const set = (localId: string, value: IrExpr): IrStmt => ({ loc, kind: "assign", localId, value }); + const bump = (localId: string): IrStmt => ({ + loc, + kind: "exprStmt", + expr: { loc, kind: "incDec", op: "+", prefix: false, localId, type: F64 }, + }); + const maybe = (then: IrStmt[]): IrStmt => ({ + loc, + kind: "if", + cond: condition("===", ref("unknown"), num(1)), + then, + else_: null, + }); + const run = (body: (inside: IrExpr) => IrStmt[]) => { + const inside = ref("k"), + after = ref("k"); + const loop: IrStmt = { + loc, + kind: "while", + cond: condition("<", ref("pos"), length), + body: body(inside), + }; + const f = fn([set("pos", num(0)), set("k", num(0)), loop, observe(after)]); + f.locals.push( + { id: "pos", name: "pos", type: F64, mutable: true }, + { id: "k", name: "k", type: F64, mutable: true }, + { id: "text", name: "text", type: STRING, mutable: false }, + ); + const facts = analyzeIntegerRangeFacts(f); + return { + inside: facts.ranges.get(inside), + after: facts.ranges.get(after), + loop: facts.loopRanges.get(loop)?.get("k"), + }; + }; + // At most 2^31 - 1 passes, each adding at most 2. + const bounded = { min: 0, max: 4294967294 }; + expect(run((inside) => [bump("pos"), observe(inside), maybe([bump("k")]), bump("k")])).toEqual({ + inside: bounded, + after: bounded, + loop: bounded, + }); + // A pass that can continue before advancing the counter, or an increment a + // nested loop repeats, bounds nothing. + const skip: IrStmt = maybe([{ loc, kind: "continue" }]); + expect(run((inside) => [skip, bump("pos"), observe(inside), bump("k")]).after).toBeNull(); + const repeat: IrStmt = { + loc, + kind: "while", + cond: condition("===", ref("unknown"), num(1)), + body: [bump("k")], + }; + expect(run((inside) => [bump("pos"), observe(inside), repeat]).after).toBeNull(); +}); + test("a nested while loop may advance a counter its own condition bounds", () => { // while (pos < text.length) { observe(pos); while (pos < text.length && unknown === 1) pos++; pos += 2; } const text: IrExpr = { loc, kind: "varRef", localId: "text", type: STRING }; @@ -1323,7 +1389,7 @@ test("a for loop bounds cursors it resets and copies, and their writes keep the } }); -test("a cursor of a loop over a typed array keeps its writes exact up to 2^53 - 1", () => { +test("a cursor of a loop over a typed array keeps its writes within the largest length", () => { // for (x = 0; x < bytes.length; x++) changes = changes + 1; const bytes: IrExpr = { loc, @@ -1355,7 +1421,7 @@ test("a cursor of a loop over a typed array keeps its writes exact up to 2^53 - { id: "changes", name: "changes", type: F64, mutable: true }, { id: "bytes", name: "bytes", type: { kind: "bytes", elem: "u8" }, mutable: false }, ); - // The sum of the header range passes 2^53 - 1; the write takes the loop - // range instead. - expect(analyzeIntegerRanges(f).get(counted)).toEqual({ min: 0, max: Number.MAX_SAFE_INTEGER }); + // The sum of the header range passes the largest typed array length; the + // write takes the loop range instead. + expect(analyzeIntegerRanges(f).get(counted)).toEqual({ min: 1, max: 2 ** 48 }); }); diff --git a/packages/compiler/src/ir/integer-ranges.ts b/packages/compiler/src/ir/integer-ranges.ts index 683ceab75..1909040c4 100644 --- a/packages/compiler/src/ir/integer-ranges.ts +++ b/packages/compiler/src/ir/integer-ranges.ts @@ -2,6 +2,7 @@ import type { IrExpr, IrFunction, IrStmt } from "./ir.js"; import { everyExprChild, everyStmtChild, everyStmtList } from "./traverse.js"; import { byteNumberAccess, byteNumberRange } from "./byte-numbers.js"; import { + BYTES_LENGTH_RANGE, boundedIntegerLoopFacts, guardedLoopCounterFacts, integerPathFallsThrough, @@ -821,7 +822,7 @@ export function analyzeIntegerRangeFacts( const numeric = byteNumberAccess(e); if (numeric && !numeric.write) range = byteNumberRange(numeric); else if (e.method === "length" || e.method === "byteLength" || e.method === "byteOffset") - range = { min: 0, max: Number.MAX_SAFE_INTEGER }; + range = BYTES_LENGTH_RANGE; else if (e.method === "get" && e.invalidNaN !== true && e.receiver.type.kind === "bytes") { const elem = e.receiver.type.elem; if (elem === "u8" || elem === "u8c") range = { min: 0, max: 255 }; @@ -1075,6 +1076,19 @@ export function analyzeIntegerRangeFacts( // inside and after the loop. const guarded = s.kind === "while" ? guardedLoopCounterFacts(s, loopLocals, facts) : noInvariants; + // The same bounds hold on entry and at every write in the loop, + // which is what a proven integer loop needs (loopRanges). A loop + // analyzed again keeps the bindings every analysis bounds. + if (s.kind === "while") { + const previous = loopRanges.get(s); + if (!previous) loopRanges.set(s, new Map(guarded)); + else + for (const [id, range] of previous) { + const other = guarded.get(id); + if (other) previous.set(id, union(range, other)); + else previous.delete(id); + } + } const loop = new Map(facts); havocWith(loop, [s], loop, guarded); for (const [id, range] of guarded) set(loop, id, range); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8002-while-byte-length-companions.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8002-while-byte-length-companions.ts.json new file mode 100644 index 000000000..e2a36c22a --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8002-while-byte-length-companions.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8002-while-byte-length-companions.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/while-induction-emission.test.ts b/packages/compiler/test/while-induction-emission.test.ts new file mode 100644 index 000000000..08fbab849 --- /dev/null +++ b/packages/compiler/test/while-induction-emission.test.ts @@ -0,0 +1,94 @@ +import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile } from "../src/index.js"; + +async function emitLlvm(source: string): Promise { + const dir = await mkdtemp(join(tmpdir(), "scriptc-while-induction-")); + try { + const entry = join(dir, "main.ts"); + const outPath = join(dir, "main.ll"); + await writeFile(entry, source); + const result = await compile(entry, { + outDir: dir, + outPath, + outputKind: "llvm", + }); + expect(result.ok, JSON.stringify(result.diagnostics)).toBe(true); + return await readFile(outPath, "utf8"); + } finally { + await rm(dir, { recursive: true, force: true }); + } +} + +/** The definition holding the function's statements: the borrowed-argument + * body when there is one, otherwise the function itself. */ +function body(ll: string, name: string): string { + const definition = (prefix: string): number => + ll.search(new RegExp(`define [^\\n]*@${prefix}_${name}\\(`)); + const start = definition("sc_bf") >= 0 ? definition("sc_bf") : definition("sc_f"); + expect(start).toBeGreaterThanOrEqual(0); + return ll.slice(start, ll.indexOf("\n}\n", start)); +} + +test("a while loop bounded by a byte length keeps its counter and companions in integers", async () => { + const ll = await emitLlvm(` +function reversed(line: Uint8Array, target: Uint8Array): number { + const len = line.length; + let read = 0; + let written = 0; + let lines = 0; + while (read < len) { + const c = line[len - 1 - read]!; + read++; + if (c === 10) { + if (read === len) break; + read++; + } + target[written] = c; + written++; + if (written % 60 === 0) { + target[written] = 10; + written++; + lines++; + } + } + return written + lines; +} +console.log(reversed(new Uint8Array([65, 10, 66]), new Uint8Array(8))); +`); + const fn = body(ll, "reversed"); + expect(fn).toContain("alloca i64 ; integer read"); + expect(fn).toContain("alloca i64 ; integer written"); + expect(fn).toContain("alloca i64 ; integer lines"); +}); + +test("a companion a nested loop advances, or a counter a continue can skip, stays a double", async () => { + const ll = await emitLlvm(` +function nested(line: Uint8Array): number { + let read = 0; + let total = 0; + while (read < line.length) { + read++; + for (let j = 0; j < 2; j++) total++; + } + return total; +} +function skipped(line: Uint8Array): number { + let read = 0; + let total = 0; + while (read < line.length) { + if (line[read] === 0) continue; + read++; + total++; + } + return total; +} +console.log(nested(new Uint8Array(3)), skipped(new Uint8Array([1, 2]))); +`); + expect(body(ll, "nested")).not.toContain("; integer total"); + // The counter compared with the length directly is an integer. + expect(body(ll, "skipped")).toContain("; integer read"); + expect(body(ll, "skipped")).not.toContain("; integer total"); +}); diff --git a/tests/corpus/8002-while-byte-length-companions.ts b/tests/corpus/8002-while-byte-length-companions.ts new file mode 100644 index 000000000..e37ec9e57 --- /dev/null +++ b/tests/corpus/8002-while-byte-length-companions.ts @@ -0,0 +1,201 @@ +// While loops bounded by a typed array or Buffer length, with companion +// counters that only grow: reversed copies with line breaks, steps of two, +// early exits, skipped passes, nested loops and loops inside loops. + +function reverseLines( + line: Uint8Array, + target: Uint8Array, + start: number, +): number { + const len = line.length; + const right = len - 1; + let read = 0; + let written = 0; + let count = 0; + let lines = 0; + while (read < len) { + let c = line[right - read]!; + read++; + if (c === 10) { + if (read === len) break; + c = line[right - read]!; + read++; + } + target[written] = c + 1; + written++; + count++; + if ((count + start - lines) % 5 === 0) { + target[written] = 10; + written++; + count++; + lines++; + } + } + return written * 1000 + lines * 10 + count; +} + +const text = Buffer.from("ABCDEFGHIJ\nKLMNOPQRST\nUVWXYZ\n"); +const out = new Uint8Array(64); +for (const start of [0, 1, 3, 7]) { + const summary = reverseLines(text, out, start); + console.log( + start, + summary, + Buffer.from(out.subarray(0, Math.floor(summary / 1000))).toString("latin1"), + ); +} + +function pairs(values: Uint16Array): number[] { + let i = 0; + let sums = 0; + let odd = 0; + const result: number[] = []; + while (i < values.length) { + i += 2; + sums++; + if ((values[i - 2]! & 1) === 1) odd += 3; + result.push(values[i - 2]! + (values[i - 1] ?? -1)); + } + result.push(i, sums, odd); + return result; +} +console.log(pairs(new Uint16Array([1, 2, 3, 4, 5]))); +console.log(pairs(new Uint16Array(0))); +console.log(pairs(new Uint16Array([65535, 65535]))); + +function firstZero(bytes: Uint8Array): string { + let i = 0; + let seen = 0; + let total = -5; + while (i < bytes.length) { + i++; + if (bytes[i - 1] === 0) break; + seen++; + total += bytes[i - 1]!; + } + return `${i} ${seen} ${total}`; +} +console.log( + firstZero(new Uint8Array([3, 4, 0, 9])), + firstZero(new Uint8Array([1, 2])), + firstZero(new Uint8Array(0)), +); + +function skipping(bytes: Uint8Array): string { + let i = 0; + let kept = 0; + let skipped = 0; + while (i < bytes.length) { + const b = bytes[i]!; + i++; + if (b > 100) { + skipped++; + continue; + } + kept++; + } + return `${i} ${kept} ${skipped}`; +} +console.log(skipping(new Uint8Array([1, 200, 3, 250, 255, 7]))); + +function repeated(bytes: Uint8Array): string { + let i = 0; + let inner = 0; + let outer = 0; + while (i < bytes.length) { + i++; + outer++; + let j = 0; + while (j < bytes[i - 1]!) { + j++; + inner++; + } + } + return `${i} ${outer} ${inner}`; +} +console.log(repeated(new Uint8Array([2, 0, 5, 1]))); + +function grid(rows: Float64Array[]): string { + let total = 0; + let cells = 0; + for (const row of rows) { + let k = 0; + let doubled = 0; + while (k < row.length) { + k++; + cells++; + doubled += 2; + total += row[k - 1]! * doubled; + } + total += k * 0.5; + } + return `${cells} ${total}`; +} +console.log( + grid([ + new Float64Array([0.5, 1.5]), + new Float64Array(0), + new Float64Array([-2, 3, 4.25]), + ]), +); + +function views(buffer: ArrayBuffer): string { + const view = new DataView(buffer, 2); + let offset = 0; + let words = 0; + const parts: string[] = []; + while (offset < view.byteLength) { + offset += 2; + words++; + if (offset <= view.byteLength) + parts.push(view.getUint16(offset - 2, true).toString(16)); + } + return `${offset} ${words} ${parts.join(",")}`; +} +const backing = new Uint8Array([9, 9, 1, 2, 3, 4, 5]).buffer; +console.log(views(backing)); + +function captured(bytes: Uint8Array): number { + let i = 0; + let n = 0; + const read = (): number => n; + while (i < bytes.length) { + i++; + n++; + } + return read() + i; +} +console.log(captured(new Uint8Array(4))); + +function fromNegative(bytes: Int8Array): string { + let i = 0; + let level = -3; + let low = -0; + while (i < bytes.length) { + i++; + level++; + if (bytes[i - 1]! < 0) low++; + } + return `${level} ${low} ${Object.is(low, -0)}`; +} +console.log( + fromNegative(new Int8Array([-1, 2, -3])), + fromNegative(new Int8Array(0)), +); + +function throwing(bytes: Uint8Array): number { + let i = 0; + let n = 0; + while (i < bytes.length) { + i++; + n++; + if (bytes[i - 1] === 7) throw new Error(`stopped at ${i} after ${n}`); + } + return n; +} +try { + console.log(throwing(new Uint8Array([1, 2]))); + console.log(throwing(new Uint8Array([1, 7, 3]))); +} catch (error) { + console.log((error as Error).message); +} diff --git a/tests/harness/corpus-costs/8002-while-byte-length-companions.ts.json b/tests/harness/corpus-costs/8002-while-byte-length-companions.ts.json new file mode 100644 index 000000000..d22ff8534 --- /dev/null +++ b/tests/harness/corpus-costs/8002-while-byte-length-companions.ts.json @@ -0,0 +1 @@ +{ "plain": 3948, "san": 3569 } From 684a0abd59e0645f609566a400a1052f782c76b7 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 24 Oct 2026 09:22:05 -0700 Subject: [PATCH 114/259] Store AbortController and AbortSignal handles in class fields A class field typed AbortController or AbortSignal (plain, optional, nullable, or in an array) maps to checked-dynamic storage, and the class-field rule refused it (SC1090) although the same handles already live in locals, Map values, and closures. They now take the checked-dynamic slot, like the fetch Headers, Request, and Response handles. controller?.abort() on a nullable controller was refused as a method call (also for locals): the static abort lowering ran only without an optional chain. It now runs again once the chain has narrowed the receiver. Found by pi's TUI Editor (autocompleteAbort: AbortController | undefined). Co-Authored-By: Claude Opus 5.5 --- .../src/frontend/lowering/lower-stdlib.ts | 12 +++-- .../compiler/src/frontend/lowering/lowerer.ts | 3 +- packages/compiler/src/frontend/type-mapper.ts | 18 ++++--- .../class-abort-controller-fields.ts.json | 6 +++ tests/corpus/class-abort-controller-fields.ts | 52 +++++++++++++++++++ .../class-abort-controller-fields.ts.json | 1 + 6 files changed, 82 insertions(+), 10 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/class-abort-controller-fields.ts.json create mode 100644 tests/corpus/class-abort-controller-fields.ts create mode 100644 tests/harness/corpus-costs/class-abort-controller-fields.ts.json diff --git a/packages/compiler/src/frontend/lowering/lower-stdlib.ts b/packages/compiler/src/frontend/lowering/lower-stdlib.ts index dc9d3def8..3b5be4d23 100644 --- a/packages/compiler/src/frontend/lowering/lower-stdlib.ts +++ b/packages/compiler/src/frontend/lowering/lower-stdlib.ts @@ -1630,16 +1630,22 @@ export function lowerStaticAbortControllerCall( call: ts.CallExpression, ): IrExpr | null { const access = call.expression; + // An optional chain (`controller?.abort()`) lowers the call again once it + // has narrowed the receiver (Lowerer.chainHandled). if ( - call.questionDotToken || + (call.questionDotToken && !lowerer.chainHandled.has(call)) || call.arguments.nodes.some((argument) => ts.isSpreadElement(argument)) || (!ts.isPropertyAccessExpression(access) && !ts.isElementAccessExpression(access)) || - access.questionDotToken || + (access.questionDotToken && !lowerer.chainHandled.has(access)) || staticResponseMemberName(lowerer, access) !== "abort" ) { return null; } - const receiverTs = lowerer.checker.getBaseTypeOfLiteralType(lowerer.typeOf(access.expression)); + const receiverTs = lowerer.checker.getBaseTypeOfLiteralType( + access.questionDotToken + ? lowerer.checker.getNonNullableType(lowerer.typeOf(access.expression)) + : lowerer.typeOf(access.expression), + ); const symbol = receiverTs.getAliasSymbol() ?? receiverTs.getSymbol(); if ( symbol === undefined || diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 78980d322..988b4b804 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -3910,7 +3910,8 @@ export class Lowerer { /** Declared class fields may store a DYN value only when its static type * is `unknown` or `object` (also with `null` or `undefined`, or an array * of those), names checked protocol identity, is an owned runtime - * handle (a Worker or MessagePort, a fetch Headers/Request/Response, or + * handle (a Worker or MessagePort, a fetch Headers/Request/Response or + * AbortController/AbortSignal, or * a node:crypto ECDH, DiffieHellman or DiffieHellmanGroup), or is a * WeakMap/WeakSet (native weak collections live in checked-dynamic * storage, as locals of those types do); `any` fields stay refused. */ diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 161f73d27..e52361dc8 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -1747,9 +1747,17 @@ export function mapAsyncGeneratorAnnotation(type: ts.Type, ctx: TypeMapperCtx): return { kind: "generator", async: true, ...channels }; } -/** The native fetch handles (Headers, Request, Response), optionally in - * arrays or with null/undefined: checked-dynamic handles wherever they are - * stored, like the worker handles above. */ +const FETCH_HANDLE_NAMES: ReadonlySet = new Set([ + "Headers", + "Request", + "Response", + "AbortController", + "AbortSignal", +]); + +/** The native fetch handles (Headers, Request, Response, AbortController, + * AbortSignal), optionally in arrays or with null/undefined: checked-dynamic + * handles wherever they are stored, like the worker handles above. */ export function isFetchHandleType( type: ts.Type, ctx: Pick, @@ -1765,9 +1773,7 @@ export function isFetchHandleType( const symbol = member.getSymbol(); if ( !symbol || - (ts.symbolName(symbol) !== "Headers" && - ts.symbolName(symbol) !== "Request" && - ts.symbolName(symbol) !== "Response") || + !FETCH_HANDLE_NAMES.has(ts.symbolName(symbol)) || !symbol.declarations.some( (d) => (ts.isInterfaceDeclaration(d) || ts.isClassDeclaration(d)) && diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/class-abort-controller-fields.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/class-abort-controller-fields.ts.json new file mode 100644 index 000000000..80466c474 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/class-abort-controller-fields.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/class-abort-controller-fields.ts" + ], + "diags": [] +} diff --git a/tests/corpus/class-abort-controller-fields.ts b/tests/corpus/class-abort-controller-fields.ts new file mode 100644 index 000000000..b82f11a0a --- /dev/null +++ b/tests/corpus/class-abort-controller-fields.ts @@ -0,0 +1,52 @@ +// Class fields typed AbortController and AbortSignal (plain, optional, +// `| undefined`, `| null`, in arrays) hold the live handles: aborting +// through the field is seen through every other reference, and optional +// calls on a nullable field skip an empty slot. +class Editor { + private abort: AbortController | undefined; + private signal: AbortSignal | null = null; + private readonly lifetime = new AbortController(); + history: AbortController[] = []; + last?: AbortSignal; + start(): AbortSignal { + this.abort?.abort(); + this.abort = new AbortController(); + this.history.push(this.abort); + this.signal = this.abort.signal; + this.last = this.signal; + return this.signal; + } + cancel(reason?: string): boolean { + this.abort?.abort(reason); + return this.signal?.aborted ?? false; + } + reason(): unknown { + return this.signal?.reason; + } + dispose(): boolean { + this.lifetime.abort(); + return this.lifetime.signal.aborted; + } +} + +const idle = new Editor(); +console.log(idle.cancel(), idle.reason()); + +const e = new Editor(); +const first = e.start(); +let events = 0; +first.addEventListener("abort", () => { + events++; +}); +const second = e.start(); +console.log(first.aborted, second.aborted, events, e.history.length); +console.log(e.cancel("stop"), e.reason(), second.aborted, second.reason); +console.log(e.history[0]!.signal === first, e.last === second, e.dispose()); + +// A nullable local takes the same optional call. +let maybe: AbortController | undefined = e.history.length > 5 ? new AbortController() : undefined; +maybe?.abort(); +console.log(maybe?.signal.aborted); +maybe = new AbortController(); +maybe?.abort("late"); +console.log(maybe?.signal.aborted, maybe?.signal.reason); diff --git a/tests/harness/corpus-costs/class-abort-controller-fields.ts.json b/tests/harness/corpus-costs/class-abort-controller-fields.ts.json new file mode 100644 index 000000000..28efce0e8 --- /dev/null +++ b/tests/harness/corpus-costs/class-abort-controller-fields.ts.json @@ -0,0 +1 @@ +{ "plain": 4302 } From b11cd04ce995db33b9eb442a6ce9624c40430bad Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 24 Oct 2026 09:28:38 -0700 Subject: [PATCH 115/259] Answer instanceof against the primitive wrapper constructors `value instanceof Boolean` (or Number, String, BigInt, Symbol) died at run time in JavaScript with Node's TypeError for a function without a prototype object, because those constructors are compiled as plain conversion closures; in TypeScript the right-hand side was refused (SC1090). A compiled program never creates a boxed primitive (`new Boolean(...)` has no lowering) and a primitive is never an instance, so the test is false for every value. It now folds to false after evaluating the operand. typebox's value guards (IsBoolean, IsNumber, IsString) test this way, so pi's tool-schema construction and validation died at its first guard. Co-Authored-By: Claude Opus 5.5 --- .../lowering/expressions/relational.ts | 16 +++++++++++++ ...nstanceof-primitive-wrappers-typed.ts.json | 6 +++++ .../instanceof-primitive-wrappers.mjs.json | 6 +++++ .../instanceof-primitive-wrappers-typed.ts | 14 +++++++++++ .../corpus/instanceof-primitive-wrappers.mjs | 24 +++++++++++++++++++ ...nstanceof-primitive-wrappers-typed.ts.json | 1 + .../instanceof-primitive-wrappers.mjs.json | 1 + 7 files changed, 68 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/instanceof-primitive-wrappers-typed.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/instanceof-primitive-wrappers.mjs.json create mode 100644 tests/corpus/instanceof-primitive-wrappers-typed.ts create mode 100644 tests/corpus/instanceof-primitive-wrappers.mjs create mode 100644 tests/harness/corpus-costs/instanceof-primitive-wrappers-typed.ts.json create mode 100644 tests/harness/corpus-costs/instanceof-primitive-wrappers.mjs.json diff --git a/packages/compiler/src/frontend/lowering/expressions/relational.ts b/packages/compiler/src/frontend/lowering/expressions/relational.ts index 1651bf0d9..393425cdd 100644 --- a/packages/compiler/src/frontend/lowering/expressions/relational.ts +++ b/packages/compiler/src/frontend/lowering/expressions/relational.ts @@ -96,6 +96,8 @@ const NO_CLASS_INSTANCE_KINDS: ReadonlySet = new Set([ "nullT", ]); +const PRIMITIVE_WRAPPERS = ["Boolean", "Number", "String", "BigInt", "Symbol"] as const; + /** `x instanceof C` for a program-declared class C. When x's static * class and C are both in extends-hierarchies the test is dynamic — the * O(1) preorder-interval check against the vtable (`instanceOf` node). @@ -187,6 +189,20 @@ export function lowerInstanceOf(lowerer: Lowerer, expr: ts.BinaryExpression, loc loc, }; } + // The primitive wrapper constructors: a compiled program never creates a + // boxed primitive (`new Boolean(...)` and friends have no lowering), and + // a primitive is never an instance, so the test is false for every value + // (typebox's IsBoolean/IsNumber/IsString guards). The operand still runs. + if (PRIMITIVE_WRAPPERS.some((name) => lowerer.isStdlibGlobal(expr.right, name))) { + const value = lowerer.lowerExpr(expr.left); + return { + kind: "seqExpr", + stmts: [{ kind: "exprStmt", expr: value, loc }], + result: { kind: "boolLit", value: false, type: BOOL, loc }, + type: BOOL, + loc, + }; + } if (lowerer.isStdlibGlobal(expr.right, "FinalizationRegistry")) { const value = lowerer.coerceInto(expr.left, lowerer.lowerExpr(expr.left), DYN); return { kind: "libCall", fn: "finalizationRegistry.is", args: [value], type: BOOL, loc }; diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/instanceof-primitive-wrappers-typed.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/instanceof-primitive-wrappers-typed.ts.json new file mode 100644 index 000000000..fba491f13 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/instanceof-primitive-wrappers-typed.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/instanceof-primitive-wrappers-typed.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/instanceof-primitive-wrappers.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/instanceof-primitive-wrappers.mjs.json new file mode 100644 index 000000000..e2dddae48 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/instanceof-primitive-wrappers.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/instanceof-primitive-wrappers.mjs" + ], + "diags": [] +} diff --git a/tests/corpus/instanceof-primitive-wrappers-typed.ts b/tests/corpus/instanceof-primitive-wrappers-typed.ts new file mode 100644 index 000000000..dc065e569 --- /dev/null +++ b/tests/corpus/instanceof-primitive-wrappers-typed.ts @@ -0,0 +1,14 @@ +// Typed operands tested against the primitive wrapper constructors: always +// false, with the operand's side effects kept. +let reads = 0; +function pick(n: number): unknown { + reads++; + return n === 0 ? "text" : n === 1 ? 7 : n === 2 ? { ok: true } : [n]; +} +const seen: string[] = []; +for (let i = 0; i < 4; i++) { + const value = pick(i); + seen.push(`${value instanceof String}/${value instanceof Number}/${value instanceof Boolean}`); +} +const record: object = { a: 1 }; +console.log(seen.join(" "), record instanceof Object, record instanceof String, reads); diff --git a/tests/corpus/instanceof-primitive-wrappers.mjs b/tests/corpus/instanceof-primitive-wrappers.mjs new file mode 100644 index 000000000..11bcaba07 --- /dev/null +++ b/tests/corpus/instanceof-primitive-wrappers.mjs @@ -0,0 +1,24 @@ +// `instanceof` against the primitive wrapper constructors (Boolean, Number, +// String, BigInt, Symbol), as typebox's value guards test: false for +// primitives and for every object, and the operand still evaluates. +function IsBoolean(value) { + return value instanceof Boolean; +} +function IsNumber(value) { + return value instanceof Number; +} +function IsString(value) { + return value instanceof String; +} +function IsUint8Array(value) { + return value instanceof globalThis.Uint8Array; +} +const values = [true, 1, "s", 2n, Symbol("k"), null, undefined, new Uint8Array(2), {}, [], () => 1, new Date(0)]; +for (const v of values) + console.log(typeof v, IsBoolean(v), IsNumber(v), IsString(v), IsUint8Array(v), v instanceof BigInt, v instanceof Symbol); +let calls = 0; +const next = () => { + calls++; + return { n: calls }; +}; +console.log(next() instanceof Number, next() instanceof globalThis.String, calls); diff --git a/tests/harness/corpus-costs/instanceof-primitive-wrappers-typed.ts.json b/tests/harness/corpus-costs/instanceof-primitive-wrappers-typed.ts.json new file mode 100644 index 000000000..d06ba3ac5 --- /dev/null +++ b/tests/harness/corpus-costs/instanceof-primitive-wrappers-typed.ts.json @@ -0,0 +1 @@ +{ "plain": 2217 } diff --git a/tests/harness/corpus-costs/instanceof-primitive-wrappers.mjs.json b/tests/harness/corpus-costs/instanceof-primitive-wrappers.mjs.json new file mode 100644 index 000000000..68ee374b9 --- /dev/null +++ b/tests/harness/corpus-costs/instanceof-primitive-wrappers.mjs.json @@ -0,0 +1 @@ +{ "plain": 2265 } From 864feec4cf66894f88598507829b0f2a57b5d4c5 Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 24 Oct 2026 09:53:28 -0700 Subject: [PATCH 116/259] Map resolved empty mapped types as the empty object type A mapped type with no members was refused (SC2001) to keep `Partial` inside a generic body, where keyof T is still unknown, from interning a wrong empty record. That also refused mapped types the checker resolved from concrete inputs whose key filter keeps no key: `Record`, `Partial<{}>`, and a catalog type such as `{ [K in KeyOf as Id]: Model }` for data without image models. When the mapped type comes through an alias whose arguments mention no type parameter (or a module-level alias without arguments), it is the empty object type and lowers like `{}`. pi-ai declares its per-provider image and classifier model catalogs this way; most providers have none, which refused 105 declaration groups. Co-Authored-By: Claude Opus 5.5 --- packages/compiler/src/frontend/type-mapper.ts | 45 ++++++++++++++++++- .../corpus/empty-mapped-alias-types.ts.json | 6 +++ tests/corpus/empty-mapped-alias-types.ts | 33 ++++++++++++++ .../empty-mapped-alias-types.ts.json | 1 + 4 files changed, 83 insertions(+), 2 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/empty-mapped-alias-types.ts.json create mode 100644 tests/corpus/empty-mapped-alias-types.ts create mode 100644 tests/harness/corpus-costs/empty-mapped-alias-types.ts.json diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index 161f73d27..9d450716f 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -7015,6 +7015,43 @@ function immutableSourceType(type: ts.Type, ctx: TypeMapperCtx): ts.Type | null return null; } +/** A mapped type reached through a type alias whose arguments mention no + * type parameter (`Record`, `Catalog`, + * a module-level alias without arguments): + * the checker computed its members from concrete inputs, so an empty + * result really is the empty object type, unlike `Partial` inside a + * generic body. */ +function resolvedMappedAlias(t: ts.Type, ctx: TypeMapperCtx): boolean { + if (!isMappedShape(t) || t.getAliasSymbol() === undefined) return false; + const args = t.getAliasTypeArguments(); + const seen = new Set(); + const concrete = (part: ts.Type): boolean => { + if (part.flags & (ts.TypeFlags.TypeParameter | ts.TypeFlags.Index)) return false; + if (part.flags & (ts.TypeFlags.IndexedAccess | ts.TypeFlags.Conditional)) return false; + if (seen.has(part)) return true; + seen.add(part); + if (part.isUnionType() || part.isIntersectionType()) + return ts.constituentTypes(part).every(concrete); + if (!part.getAliasTypeArguments().every(concrete)) return false; + return ( + (part.flags & ts.TypeFlags.Object) === 0 || + ((part as ts.ObjectType).objectFlags & ts.ObjectFlags.Reference) === 0 || + ctx.checker.getTypeArguments(part as ts.TypeReference).every(concrete) + ); + }; + // An alias without type arguments is concrete when it is declared at + // module level (a function body's alias may mention that function's type + // parameters). + if (args.length === 0) + return t + .getAliasSymbol()! + .declarations.every( + (d) => + ts.isTypeAliasDeclaration(d) && (ts.isSourceFile(d.parent) || ts.isModuleBlock(d.parent)), + ); + return args.every(concrete); +} + /** True for MAPPED-type results — `Partial`, `Record<"a", n>`, * whatever `Pick`/`Omit` reduce to. Their shape is computed by the checker, * not declared anywhere: the only declaration behind them is the utility @@ -7969,8 +8006,12 @@ function mapRecordTypeInner( // still unknown there) — interning `{}` would give a wrong type. The // degenerate empties (`Partial<{}>`, `Omit`) go with it. // An INDEX-SIGNATURE shape is exempt: `Record` legitimately - // has zero declared members — the signature is the shape. - if (computed && props.length === 0 && !indexValue) return null; + // has zero declared members — the signature is the shape. So is a mapped + // alias instantiated over concrete arguments (`Record`, a + // catalog type whose key filter keeps no key): the checker resolved it, + // and it is the empty object type below. + if (computed && props.length === 0 && !indexValue && !resolvedMappedAlias(widened, ctx)) + return null; // An empty object type — `{}` (spelled, the checker's shared // intrinsic, or inferred from an empty object literal), `interface // Empty {}` — is tsc's TOP type over non-nullish values: every number, diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/empty-mapped-alias-types.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/empty-mapped-alias-types.ts.json new file mode 100644 index 000000000..08ec4c0f3 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/empty-mapped-alias-types.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/empty-mapped-alias-types.ts" + ], + "diags": [] +} diff --git a/tests/corpus/empty-mapped-alias-types.ts b/tests/corpus/empty-mapped-alias-types.ts new file mode 100644 index 000000000..43f3ed831 --- /dev/null +++ b/tests/corpus/empty-mapped-alias-types.ts @@ -0,0 +1,33 @@ +// Mapped types instantiated over concrete arguments whose key filter keeps +// no key (a per-kind model catalog with no models of that kind, +// `Record`, `Partial<{}>`) are the empty object type: values flow +// through them like any `{}`-typed value. +type Groups = Record>; +type Key = { [A in keyof G]: keyof G[A] }[keyof G] & string; +type KeyOf = Extract, `${T}:${string}`>; +type Id = K extends `${string}:${infer M}` ? M : never; +type Catalog = { + [K in KeyOf as Id]: { id: Id; name: string }; +}; + +const data = { api: { "chat:a": { id: "a", name: "A" }, "chat:b": { id: "b", name: "B" } } }; + +const chat: Catalog = { a: { id: "a", name: "A" }, b: { id: "b", name: data.api["chat:b"].name } }; +const image: Catalog = {}; +const video: Catalog = image; +console.log(chat.a.name, chat.b.id, JSON.stringify(image), video === image); + +const none: Record = {}; +const partial: Partial<{}> = { extra: 1 } as {}; +console.log(JSON.stringify(none), JSON.stringify(partial)); + +function describe(value: Catalog): string { + return JSON.stringify(value); +} +const catalogs: Catalog[] = [image, {}, none]; +console.log(describe(image), describe({}), catalogs.map(describe).join(" ")); + +// A module-level alias without type arguments whose filter keeps no key. +type Flags = { [K in "a" | "b" as K extends "c" ? K : never]: boolean }; +const flags: Flags = {}; +console.log(JSON.stringify(flags), JSON.stringify([flags, none])); diff --git a/tests/harness/corpus-costs/empty-mapped-alias-types.ts.json b/tests/harness/corpus-costs/empty-mapped-alias-types.ts.json new file mode 100644 index 000000000..855a18b97 --- /dev/null +++ b/tests/harness/corpus-costs/empty-mapped-alias-types.ts.json @@ -0,0 +1 @@ +{ "plain": 2395 } From 50b7c806ce664754263101f9053e7227f13f4f72 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 12:52:54 -0500 Subject: [PATCH 117/259] Check unchanged frontend inputs by file identity before hashing them A warm native build validates its frontend cache entry by reading and SHA-256 hashing every source and declaration file the frontend read. A tracked read now also records the file's identity (device, inode, size, modification and change time) when the identity is the same before and after the read and the file had been unchanged for two seconds. A later check accepts a file whose identity is unchanged without reading it, and hashes it otherwise. A write always gives a file a newer change time, which tools cannot set back, so an unchanged identity means the content hashed with it. The equivalent-edit check uses the same identity for the unchanged sources. --- .../src/frontend/input-tracker.test.ts | 46 +++++++++++++++ .../compiler/src/frontend/input-tracker.ts | 56 +++++++++++++++++-- 2 files changed, 97 insertions(+), 5 deletions(-) diff --git a/packages/compiler/src/frontend/input-tracker.test.ts b/packages/compiler/src/frontend/input-tracker.test.ts index b4f3957f5..d6f9a91b7 100644 --- a/packages/compiler/src/frontend/input-tracker.test.ts +++ b/packages/compiler/src/frontend/input-tracker.test.ts @@ -270,3 +270,49 @@ test("synchronous tracking restores parents after throws and propagates unstable trackedFileExists(join(dir, "outside.ts")); expect(parent.snapshot()).toEqual(before); }); + +test("a settled file is checked by its identity, and any write invalidates it", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-inputs-")); + scratch.push(dir); + const source = join(dir, "entry.ts"); + await writeFile(source, "export const answer = 1;\n"); + const written = fs.statSync(source); + // The file was last changed long enough before the read. + vi.useFakeTimers({ toFake: ["Date"] }); + vi.setSystemTime(Date.now() + 5000); + const tracker = new FrontendInputTracker(); + try { + tracker.run(() => trackedReadFile(source)); + } finally { + vi.useRealTimers(); + } + const snapshot = tracker.snapshot(); + const probe = snapshot.probes.find((entry) => entry.op === "file"); + expect(probe?.op === "file" && probe.identity !== undefined).toBe(true); + expect(validFrontendInputSnapshot(snapshot)).toBe(true); + const reads = vi.mocked(fs.readFileSync); + reads.mockClear(); + expect(frontendInputsStillMatch(snapshot)).toBe(true); + expect(reads.mock.calls.filter(([path]) => path === source)).toHaveLength(0); + // A same-size rewrite that restores the modification time still changes + // the change time. + await writeFile(source, "export const answer = 2;\n"); + fs.utimesSync(source, written.atime, written.mtime); + expect(frontendInputsStillMatch(snapshot)).toBe(false); +}); + +test("a file changed shortly before the read is hashed on every check", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-inputs-")); + scratch.push(dir); + const source = join(dir, "entry.ts"); + await writeFile(source, "export const answer = 1;\n"); + const tracker = new FrontendInputTracker(); + tracker.run(() => trackedReadFile(source)); + const snapshot = tracker.snapshot(); + const probe = snapshot.probes.find((entry) => entry.op === "file"); + expect(probe?.op === "file" && probe.identity).toBeUndefined(); + const reads = vi.mocked(fs.readFileSync); + reads.mockClear(); + expect(frontendInputsStillMatch(snapshot)).toBe(true); + expect(reads.mock.calls.filter(([path]) => path === source)).toHaveLength(1); +}); diff --git a/packages/compiler/src/frontend/input-tracker.ts b/packages/compiler/src/frontend/input-tracker.ts index d27ab6285..c23a87313 100644 --- a/packages/compiler/src/frontend/input-tracker.ts +++ b/packages/compiler/src/frontend/input-tracker.ts @@ -12,7 +12,8 @@ import { observeSourceText } from "./ts7/ast-node.js"; * behind an old resolution answer. */ export type FrontendInputProbe = - | { op: "file"; path: string; digest: string } + /** `identity` (fileIdentity) lets a later check skip hashing the file. */ + | { op: "file"; path: string; digest: string; identity?: string } | { op: "read-error"; path: string } | { op: "kind"; path: string; kind: "file" | "directory" | "other" | "missing" } | { op: "entries"; path: string; files: string[]; directories: string[] } @@ -53,6 +54,36 @@ function frontendSourceDigest(text: string): string { return createHash("sha256").update(text).digest("hex"); } +/** How long a file must have been unchanged before a read for its identity + * to stand for its content: a later write then gets a newer change time + * even on file systems whose timestamps tick once a second or every two. */ +const IDENTITY_SETTLE_MS = 2000; + +/** The device, inode, size, modification time and change time of `path`. A + * write changes the change time, which no tool can set back, so an equal + * identity means the content is the one hashed with it. */ +function fileIdentity(path: string): string | null { + try { + const info = statSync(path); + return `${info.dev}:${info.ino}:${info.size}:${info.mtimeMs}:${info.ctimeMs}`; + } catch { + return null; + } +} + +/** The text of `path` with its identity when the identity was the same before + * and after the read and the file had been unchanged for IDENTITY_SETTLE_MS. */ +function readWithIdentity(path: string): { text: string; identity: string | null } { + const readAt = Date.now(); + const before = statSync(path); + const text = readFileSync(path, "utf8"); + const after = fileIdentity(path); + const identity = `${before.dev}:${before.ino}:${before.size}:${before.mtimeMs}:${before.ctimeMs}`; + const settled = + before.mtimeMs <= readAt - IDENTITY_SETTLE_MS && before.ctimeMs <= readAt - IDENTITY_SETTLE_MS; + return { text, identity: settled && after === identity ? identity : null }; +} + function pathKind(path: string): Extract["kind"] { try { const info = statSync(path); @@ -199,8 +230,11 @@ export function trackedReadFile(path: string): string | null { const virtual = virtualSources.get(path); if (virtual !== undefined) return virtual; try { - const text = readFileSync(path, "utf8"); - record({ op: "file", path, digest: frontendSourceDigest(text) }); + const { text, identity } = readWithIdentity(path); + const digest = frontendSourceDigest(text); + record( + identity === null ? { op: "file", path, digest } : { op: "file", path, digest, identity }, + ); return text; } catch { record({ op: "read-error", path }); @@ -337,6 +371,9 @@ export function frontendInputsStillMatch( } switch (probe.op) { case "file": { + // An unchanged identity stands for the content hashed with it. + if (probe.identity !== undefined && fileIdentity(probe.path) === probe.identity) + return true; try { return frontendSourceDigest(readFileSync(probe.path, "utf8")) === probe.digest; } catch { @@ -443,6 +480,11 @@ export function frontendInputsSemanticallyMatch( probes.push(probe); continue; } + if (probe.identity !== undefined && fileIdentity(probe.path) === probe.identity) { + currentSources.set(probe.path, previous); + probes.push(probe); + continue; + } let current: string; try { current = readFileSync(probe.path, "utf8"); @@ -460,7 +502,7 @@ export function frontendInputsSemanticallyMatch( if (rawText.has(probe.path) || !isSemanticEquivalent(probe.path, previous, current)) return null; changed.push({ path: probe.path, previous, current }); - probes.push({ ...probe, digest: currentDigest }); + probes.push({ op: "file", path: probe.path, digest: currentDigest }); } const adjusted: FrontendInputSnapshot = { ...snapshot, probes }; if (!frontendInputsStillMatch(adjusted, exclusions)) return null; @@ -488,7 +530,11 @@ export function validFrontendInputSnapshot(snapshot: unknown): snapshot is Front if (typeof value.path !== "string" || typeof value.op !== "string") return false; switch (value.op) { case "file": - return typeof value.digest === "string" && /^[0-9a-f]{64}$/.test(value.digest); + return ( + typeof value.digest === "string" && + /^[0-9a-f]{64}$/.test(value.digest) && + (value.identity === undefined || typeof value.identity === "string") + ); case "read-error": return true; case "kind": From 94c650a9c252a2d5913d56104d7847e973f8a9d1 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 13:07:38 -0500 Subject: [PATCH 118/259] Write a number-keyed Map update through the entry its read found m.set(k, f(m.get(k))) and a get followed by a set of the same key, with a number or boolean value, now reuse the entry the read resolved, as string-keyed maps already do: the write overwrites the value in place when the map is the same and the key has the read's bits, and takes the ordinary set otherwise. Before, the write probed the table again: the two lookups were not merged, because each sits behind its own direct-index test. --- .../src/backend/llvm/expr-containers.ts | 16 ++-- .../src/backend/llvm/map-entry-fusion.test.ts | 20 +++-- .../src/backend/llvm/map-entry-fusion.ts | 40 +++++---- .../src/backend/llvm/map-read-lifetimes.ts | 1 + .../6307-number-map-get-set-fusion.ts.json | 6 ++ .../corpus/6307-number-map-get-set-fusion.ts | 82 +++++++++++++++++++ .../6307-number-map-get-set-fusion.ts.json | 1 + 7 files changed, 138 insertions(+), 28 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6307-number-map-get-set-fusion.ts.json create mode 100644 tests/corpus/6307-number-map-get-set-fusion.ts create mode 100644 tests/harness/corpus-costs/6307-number-map-get-set-fusion.ts.json diff --git a/packages/compiler/src/backend/llvm/expr-containers.ts b/packages/compiler/src/backend/llvm/expr-containers.ts index 279b8c044..f8c21a1c5 100644 --- a/packages/compiler/src/backend/llvm/expr-containers.ts +++ b/packages/compiler/src/backend/llvm/expr-containers.ts @@ -1461,6 +1461,7 @@ export function emitMapLikeIntrinsic( : emitStringMapGetScalar(host, r.name, stringKey!); found = scalar.found; if (stringKey !== null) rememberMapEntry(host, e, r.name, stringKey, scalar.entry); + else rememberMapEntry(host, e, r.name, numberKey!, scalar.entry, "double"); readHit = () => { const hit = B.tmp(); B.line( @@ -1532,7 +1533,13 @@ export function emitMapLikeIntrinsic( const vAcc = elemAccess(receiverType.value); if (vAcc === "ref") host.toHeap(v); const ordinary = (): void => host.mapSet(r.name, kAcc, vAcc, k.name, v.name); - if (kAcc === "f64" && vAcc !== "ref" && host.readNumberMapWrites.has(e)) { + if ( + (kAcc === "str" || kAcc === "f64") && + vAcc !== "ref" && + emitFusedMapSet(host, e, r.name, k.name, { name: v.name, access: vAcc }, ordinary) + ) { + // Written through the read's entry, or inserted. + } else if (kAcc === "f64" && vAcc !== "ref" && host.readNumberMapWrites.has(e)) { const bits = B.tmp(); B.line( vAcc === "f64" @@ -1540,12 +1547,7 @@ export function emitMapLikeIntrinsic( : `${bits} = zext i1 ${v.name} to i64`, ); emitNumberMapSetScalar(host, r.name, k.name, bits, ordinary); - } else if ( - kAcc !== "str" || - vAcc === "ref" || - !emitFusedMapSet(host, e, r.name, k.name, { name: v.name, access: vAcc }, ordinary) - ) - ordinary(); + } else ordinary(); return { name: "", type: e.type }; } case "add": { diff --git a/packages/compiler/src/backend/llvm/map-entry-fusion.test.ts b/packages/compiler/src/backend/llvm/map-entry-fusion.test.ts index 58d3a33d6..9c8ffb84c 100644 --- a/packages/compiler/src/backend/llvm/map-entry-fusion.test.ts +++ b/packages/compiler/src/backend/llvm/map-entry-fusion.test.ts @@ -137,12 +137,20 @@ test("a read followed by a write of the same map pairs, and the write reuses the } }); -test("number keys keep the write-after-read lookup instead of pairing", () => { - // findReadNumberMapWrites stores such writes into the found entry through - // a read-only probe that LLVM merges with the read's. - const mod = fixture((map, k) => [declare(map, k), set(map, k, increment(F64))], F64, F64); - expect(pairs(mod)).toBe(0); - expect(body(mod)).not.toContain("mapfuse.hit"); +test("number keys pair, and the write compares the key's bits with the read's", () => { + for (const value of [F64, BOOL]) { + const mod = fixture((map, k) => [declare(map, k), set(map, k, increment(value))], F64, value); + expect(pairs(mod)).toBe(1); + for (const bits of [32, 64] as const) { + const ir = body(mod, bits); + expect(ir).toContain("mapfuse.hit"); + expect(ir).toContain("alloca double ; fused map read: key"); + expect(ir).toMatch(/icmp eq i64 %t\d+, %t\d+/); + // The miss still inserts through the runtime. + expect(ir).toMatch(/call void @scr_map_set_f64_(?:f64|bool)\(/); + expect(ir).toContain("@sc_map_entry_f64("); + } + } }); test("the single-statement form pairs an unconditional nested read", () => { diff --git a/packages/compiler/src/backend/llvm/map-entry-fusion.ts b/packages/compiler/src/backend/llvm/map-entry-fusion.ts index bc2ca07f3..fe6f66d9c 100644 --- a/packages/compiler/src/backend/llvm/map-entry-fusion.ts +++ b/packages/compiler/src/backend/llvm/map-entry-fusion.ts @@ -14,10 +14,10 @@ * key match by identity implies the SameValueZero match the set would find. * * Only scalar values (number, boolean) fuse: overwriting them releases - * nothing, exactly like the runtime's own overwrite. Only string-keyed - * typed maps fuse here: a number-key write after a read of the same key - * already probes through the read-only entry lookup that LLVM merges with - * the read's (findReadNumberMapWrites, map-read-lifetimes.ts). + * nothing, exactly like the runtime's own overwrite. String-keyed and + * number-keyed typed maps fuse. A number key matches when its bits are the + * read's: such keys are SameValueZero-equal, and a key that is equal with + * other bits (-0 for 0) takes the ordinary set. */ import type { IrExpr, IrFunction, IrStmt } from "../../ir/ir.js"; import { everyExprChild, everyStmtChild } from "../../ir/traverse.js"; @@ -30,7 +30,7 @@ type MapOp = Extract; /** One fused read/write pair. The slots exist once the read emits through * an entry path; a write whose read took another path stays ordinary. */ export interface MapEntryPair { - slots: { map: string; key: string; entry: string } | null; + slots: { map: string; key: string; entry: string; keyType: "ptr" | "double" } | null; } export interface MapEntryFusion { @@ -38,13 +38,14 @@ export interface MapEntryFusion { writes: Map; } -/** A typed string-keyed Map read/write with a scalar value. */ +/** A typed string- or number-keyed Map read/write with a scalar value. */ function fusableOp(e: IrExpr, method: "get" | "set"): e is MapOp { if (e.kind !== "mapIntrinsic" || e.method !== method) return false; const receiver = e.receiver.type; - if (receiver.kind !== "map") return false; + if (receiver.kind !== "map" || receiver.key.kind === "union") return false; if (receiver.value.kind !== "f64" && receiver.value.kind !== "bool") return false; - if (mapKeyAccess(receiver.key) !== "str") return false; + const access = mapKeyAccess(receiver.key); + if (access !== "str" && access !== "f64") return false; return method === "get" ? borrowsMapReadInputs(e) : borrowsMapMutationReceiver(e); } @@ -219,23 +220,25 @@ export function findMapEntryFusions(fn: IrFunction): MapEntryFusion { return out; } -/** After a fused read resolved `entry` for the string `key` in `map`: park - * all three for the paired write. */ +/** After a fused read resolved `entry` for `key` in `map`: park all three + * for the paired write. `keyType` is the key's LLVM type: a string's ptr or + * a number's double. */ export function rememberMapEntry( host: LlvmEmitterContext, read: IrExpr, map: string, key: string, entry: string, + keyType: "ptr" | "double" = "ptr", ): void { const pair = host.mapEntryFusion?.reads.get(read); if (!pair) return; const B = host.B; if (pair.slots === null) { - const slots = { map: B.slot(), key: B.slot(), entry: B.slot() }; + const slots = { map: B.slot(), key: B.slot(), entry: B.slot(), keyType }; B.entryAllocas.push( `${slots.map} = alloca ptr ; fused map read: map`, - `${slots.key} = alloca ptr ; fused map read: key`, + `${slots.key} = alloca ${keyType} ; fused map read: key`, `${slots.entry} = alloca ptr ; fused map read: entry`, `store ptr null, ptr ${slots.entry}`, ); @@ -243,7 +246,7 @@ export function rememberMapEntry( } const slots = pair.slots; B.line(`store ptr ${map}, ptr ${slots.map}`); - B.line(`store ptr ${key}, ptr ${slots.key}`); + B.line(`store ${slots.keyType} ${key}, ptr ${slots.key}`); B.line(`store ptr ${entry}, ptr ${slots.entry}`); } @@ -270,13 +273,20 @@ export function emitFusedMapSet( both = B.tmp(), reuse = B.tmp(); B.line(`${parkedMap} = load ptr, ptr ${slots.map}`); - B.line(`${parkedKey} = load ptr, ptr ${slots.key}`); + B.line(`${parkedKey} = load ${slots.keyType}, ptr ${slots.key}`); B.line(`${entry} = load ptr, ptr ${slots.entry}`); // The entry is valid only between its read and this write. B.line(`store ptr null, ptr ${slots.entry}`); B.line(`${found} = icmp ne ptr ${entry}, null`); B.line(`${sameMap} = icmp eq ptr ${parkedMap}, ${map}`); - B.line(`${sameKey} = icmp eq ptr ${parkedKey}, ${key}`); + if (slots.keyType === "ptr") B.line(`${sameKey} = icmp eq ptr ${parkedKey}, ${key}`); + else { + const parkedBits = B.tmp(), + keyBits = B.tmp(); + B.line(`${parkedBits} = bitcast double ${parkedKey} to i64`); + B.line(`${keyBits} = bitcast double ${key} to i64`); + B.line(`${sameKey} = icmp eq i64 ${parkedBits}, ${keyBits}`); + } B.line(`${both} = and i1 ${sameMap}, ${sameKey}`); B.line(`${reuse} = select i1 ${found}, i1 ${both}, i1 false`); const hit = B.newLabel("mapfuse.hit"), diff --git a/packages/compiler/src/backend/llvm/map-read-lifetimes.ts b/packages/compiler/src/backend/llvm/map-read-lifetimes.ts index 6b58d314a..6053d70eb 100644 --- a/packages/compiler/src/backend/llvm/map-read-lifetimes.ts +++ b/packages/compiler/src/backend/llvm/map-read-lifetimes.ts @@ -314,6 +314,7 @@ export function emitStackMapRead(host: LlvmEmitterContext, read: LocalMapRead): // Booleans are stored as 0/1, already the widened union payload. const scalar = emitNumberMapGetScalar(host, receiver.name, number); found = scalar.found; + rememberMapEntry(host, read.expr, receiver.name, number, scalar.entry, "double"); B.line(`store i64 ${scalar.bits}, ptr ${payload}`); } } else if (string !== null && !isRefCounted(read.value)) { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6307-number-map-get-set-fusion.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6307-number-map-get-set-fusion.ts.json new file mode 100644 index 000000000..36c6b7a10 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6307-number-map-get-set-fusion.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6307-number-map-get-set-fusion.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6307-number-map-get-set-fusion.ts b/tests/corpus/6307-number-map-get-set-fusion.ts new file mode 100644 index 000000000..d373782ef --- /dev/null +++ b/tests/corpus/6307-number-map-get-set-fusion.ts @@ -0,0 +1,82 @@ +// A number-keyed Map read followed by a write of the same key: the write +// goes through the entry the read found when the map and the key's bits +// are the same, and through an ordinary set otherwise (a miss, -0 against +// 0, another map). Values, sizes and insertion order match Node for +// directly indexed keys, hashed keys, fractional keys, NaN and signed +// zeros. + +function show(map: Map): string { + const parts: string[] = []; + map.forEach((value, key) => { + parts.push(`${Object.is(key, -0) ? "-0" : String(key)}=${value}`); + }); + return `${map.size} [${parts.join(" ")}]`; +} + +// The counting update over small integer keys (direct index) and wide keys +// (hashed). +const keys = [3, 1, 3, 2, 1, 3, 1e12, 2 ** 40 + 1, 1e12, 0.5, 0.5, -7, 2 ** 40 + 1]; +const counts = new Map(); +for (const key of keys) counts.set(key, (counts.get(key) ?? 0) + 1); +console.log(show(counts)); + +// The read as a declaration, then the write. +const sums = new Map(); +for (let i = 0; i < 40; i++) { + const key = (i * 7) % 11; + const current = sums.get(key); + sums.set(key, current === undefined ? i : current + i); +} +console.log(show(sums)); + +// Signed zeros: -0 and 0 are one key, which the map stores as 0. +const zeros = new Map(); +const zeroKeys = [-0, 0, -0, 0, 0]; +for (const key of zeroKeys) zeros.set(key, (zeros.get(key) ?? 0) + 1); +console.log(show(zeros), Object.is([...zeros.keys()][0], -0)); +const plusFirst = new Map(); +for (const key of [0, -0, -0]) plusFirst.set(key, (plusFirst.get(key) ?? 0) + 1); +console.log(show(plusFirst)); + +// NaN is one key whatever its producer. +const nans = new Map(); +const nanKeys = [NaN, 0 / 0, Math.sqrt(-1), Number("x")]; +for (const key of nanKeys) nans.set(key, (nans.get(key) ?? 0) + 1); +console.log(show(nans)); + +// A read of one map and a write of another take the ordinary set. +const source = new Map([ + [1, 10], + [2, 20], +]); +const target = new Map([[2, 5]]); +for (const key of [1, 2, 3]) target.set(key, (source.get(key) ?? 0) + 1); +console.log(show(source), show(target)); + +// Overwrites keep the insertion order; deleted keys come back at the end. +const order = new Map(); +for (const key of [5, 4, 3, 2, 1]) order.set(key, (order.get(key) ?? 0) + 1); +order.delete(3); +for (const key of [1, 3, 5]) order.set(key, (order.get(key) ?? 0) + 10); +console.log(show(order)); + +// Boolean values. +const seen = new Map(); +for (const key of [1, 2, 1, 1e9, 1e9]) seen.set(key, !(seen.get(key) ?? false)); +const flags: string[] = []; +seen.forEach((value, key) => flags.push(`${key}:${value}`)); +console.log(flags.join(" ")); + +// A large table, where the hashed probe and growth run. +const big = new Map(); +for (let i = 0; i < 50000; i++) { + const key = (i * 2654435761) % 100003; + big.set(key, (big.get(key) ?? 0) + 1); +} +let total = 0; +let most = 0; +big.forEach((value) => { + total += value; + if (value > most) most = value; +}); +console.log(big.size, total, most); diff --git a/tests/harness/corpus-costs/6307-number-map-get-set-fusion.ts.json b/tests/harness/corpus-costs/6307-number-map-get-set-fusion.ts.json new file mode 100644 index 000000000..c4ebfea74 --- /dev/null +++ b/tests/harness/corpus-costs/6307-number-map-get-set-fusion.ts.json @@ -0,0 +1 @@ +{ "plain": 3800, "san": 4200 } From 50ccfbcbe290b0751723e3af04012217d41f273b Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Fri, 23 Oct 2026 13:41:29 -0700 Subject: [PATCH 119/259] Report inferred shapes for untyped npm JavaScript (shape inference, stage 1) SCRIPTC_DEBUG_SHAPES=1 runs a whole-program allocation-site points-to analysis over opted-in npm packages' JavaScript and the user files that call into them, and prints which object and array literals a native record would represent exactly, the inferred class field types, the census of writes and reflection on untracked receivers, and the hot functions' parameter and return types. Report only: nothing reaches the lowering, and the analysis runs only when the variable is set. Design: results/design-shape-inference/DESIGN.md (scriptc-perf). Co-Authored-By: Claude Opus 5.5 --- packages/compiler/src/frontend/program.ts | 5 + .../src/frontend/shape-inference/analyze.ts | 2864 +++++++++++++++++ .../src/frontend/shape-inference/domain.ts | 153 + .../src/frontend/shape-inference/index.ts | 21 + .../src/frontend/shape-inference/report.ts | 374 +++ .../compiler/test/shape-inference.test.ts | 166 + 6 files changed, 3583 insertions(+) create mode 100644 packages/compiler/src/frontend/shape-inference/analyze.ts create mode 100644 packages/compiler/src/frontend/shape-inference/domain.ts create mode 100644 packages/compiler/src/frontend/shape-inference/index.ts create mode 100644 packages/compiler/src/frontend/shape-inference/report.ts create mode 100644 packages/compiler/test/shape-inference.test.ts diff --git a/packages/compiler/src/frontend/program.ts b/packages/compiler/src/frontend/program.ts index bf75127c4..8e582af89 100644 --- a/packages/compiler/src/frontend/program.ts +++ b/packages/compiler/src/frontend/program.ts @@ -140,6 +140,7 @@ import { } from "./type-only-imports.js"; import { moduleSourceCandidates } from "./module-source-candidates.js"; import { planDeclProjection, type DeclProjection } from "./decl-projection.js"; +import { reportShapes } from "./shape-inference/index.js"; import { inferredJsDiagnosticSuppressed } from "./inferred-js-diagnostics.js"; import { containsJsx, @@ -1260,6 +1261,10 @@ export function loadProgram( npmStaticPackages.length > 0, projector, ); + // Shape inference, stage S1: a report only (SCRIPTC_DEBUG_SHAPES). + const shapes = process.env["SCRIPTC_DEBUG_SHAPES"]; + if (shapes !== undefined && shapes !== "" && shapes !== "0" && npmStaticPackages.length > 0) + reportShapes(load.program, shapes); return { ...load, services, diff --git a/packages/compiler/src/frontend/shape-inference/analyze.ts b/packages/compiler/src/frontend/shape-inference/analyze.ts new file mode 100644 index 000000000..55e0e0107 --- /dev/null +++ b/packages/compiler/src/frontend/shape-inference/analyze.ts @@ -0,0 +1,2864 @@ +/* Shape inference (results/design-shape-inference/DESIGN.md), stage S1: + * a whole-program allocation-site points-to analysis over the JavaScript of + * opted-in npm packages and the user files that call into them. + * + * Stage S1 is report-only: the analysis runs when SCRIPTC_DEBUG_SHAPES is + * set and prints its plan (report.ts). Nothing it computes reaches the + * lowering yet, so every program compiles exactly as before. + * + * The analysis (DESIGN.md §4): + * - Andersen-style inclusion constraints, solved with a worklist. Locals + * and parameters are one value node per binding (flow-insensitive in S1); + * heap fields are one node per (atom, name); arrays one element node. + * - Calls resolve by the callee's atoms: functions, class constructors, + * methods by the receiver's class chain (inherited members, getters and + * setters, `this.constructor`), closures stored in fields, `bind`, and + * builtin summaries for the common library surface. + * - Escape: an atom escapes when it reaches code the analysis cannot see + * (a ⊤ callee, a builtin without a summary, a store into a ⊤ object). + * Escaped functions run with ⊤ arguments; everything reachable from an + * escaped atom escapes. + * - Census: writes and reflection whose receiver may be ⊤ apply to every + * escaped atom (§5.4); the report uses them to decide which allocation + * sites could become native records (§5.5). */ +import * as ts from "../ts7/adapter.js"; +import { isJsSourceFile } from "../program.js"; +import { npmStaticPackageOfPath } from "../npm-static.js"; +import { AtomTable, MODELED_GLOBALS, STRING_METHOD_RESULTS, type Atom } from "./domain.js"; + +type Node = ts.Node; + +export interface ValueNode { + readonly id: number; + readonly atoms: Set; + readonly succ: Set; + /** Constraints to run for each atom that arrives. */ + readonly onAtom: ((atom: Atom) => void)[]; + /** Every atom that arrives escapes. */ + escapeSink: string | null; +} + +export interface FunctionInfo { + readonly node: Node; + /** The analysis context: "" or a method's receiver (`C`). */ + readonly ctx: string; + /** The function whose clone the context is (bindings inside it are per context). */ + readonly root: Node | null; + /** Bodies are walked on first call: code that never runs adds no facts. */ + walked: boolean; + readonly label: string; + readonly params: number[]; + /** Index of a rest parameter, or -1. */ + readonly rest: number; + readonly thisNode: number; + readonly ret: number; + readonly isArrow: boolean; + readonly isAsync: boolean; + readonly isGenerator: boolean; + /** Reads `arguments` other than through `...arguments` forwarding. */ + usesArguments: boolean; + /** `f(...arguments)` forwarding: one node per argument position. */ + argPos: number[] | null; + /** The class whose member this function is (method, accessor, constructor). */ + readonly ownerClass: Node | null; + readonly inPackage: boolean; +} + +export interface LiteralSite { + readonly atom: Atom; + readonly node: Node; + readonly kind: "object" | "array"; + /** Static keys in creation order; null when a spread or computed key makes them unknown. */ + readonly keys: string[] | null; + readonly hasAccessor: boolean; + readonly hasProto: boolean; + readonly hasComputedKey: boolean; + readonly spreads: number[]; + readonly inPackage: boolean; +} + +export interface Op { + readonly kind: + | "read" + | "write" + | "computedRead" + | "computedWrite" + | "delete" + | "freeze" + | "seal" + | "defineProperty" + | "setPrototypeOf" + | "assign" + | "proxy" + | "lengthWrite"; + readonly recv: number; + readonly name: string | null; + readonly node: Node; +} + +export interface CallEdge { + readonly caller: FunctionInfo | null; + readonly callee: FunctionInfo; + readonly inLoop: boolean; +} + +export interface ShapeAnalysis { + readonly atoms: AtomTable; + readonly nodes: ValueNode[]; + readonly functions: Map; + readonly sites: LiteralSite[]; + readonly ops: Op[]; + readonly calls: CallEdge[]; + readonly escaped: Map; + readonly topWriteNames: Map; + readonly topComputedWrites: Node[]; + /** Fields per atom: name → node id. */ + readonly fields: Map>; + readonly elements: Map; + readonly top: Atom; + readonly files: readonly ts.SourceFile[]; + readonly packageFiles: number; + readonly checker: ts.TypeChecker; + readonly budgetExceeded: boolean; + readonly steps: number; + readonly topCause: ReadonlyMap; + readonly nodeLabel: ReadonlyMap; +} + +/** Array.prototype members: other names on an array are own properties. */ +const ARRAY_METHODS: ReadonlySet = new Set([ + "at", + "concat", + "copyWithin", + "entries", + "every", + "fill", + "filter", + "find", + "findIndex", + "findLast", + "findLastIndex", + "flat", + "flatMap", + "forEach", + "includes", + "indexOf", + "join", + "keys", + "lastIndexOf", + "map", + "pop", + "push", + "reduce", + "reduceRight", + "reverse", + "shift", + "slice", + "some", + "sort", + "splice", + "toLocaleString", + "toReversed", + "toSorted", + "toSpliced", + "toString", + "unshift", + "values", + "with", +]); +const MAX_STEPS = 20_000_000; + +function list(arr: { readonly nodes: readonly T[] } | undefined): readonly T[] { + return arr?.nodes ?? []; +} + +function isStatic(node: Node): boolean { + const mods = (node as { modifiers?: { nodes: readonly Node[] } }).modifiers; + return list(mods).some((m) => m.kind === ts.SyntaxKind.StaticKeyword); +} + +function unparen(node: ts.Expression): ts.Expression { + let n = node; + for (;;) { + if (ts.isParenthesizedExpression(n)) n = n.expression; + else if (ts.isNonNullExpression(n)) n = n.expression; + else if (ts.isAsExpression(n) || ts.isSatisfiesExpression(n)) n = n.expression; + else return n; + } +} + +function propertyNameText(name: Node): string | null { + if (ts.isIdentifier(name) || ts.isPrivateIdentifier(name)) return name.text; + if (ts.isStringLiteral(name) || ts.isNoSubstitutionTemplateLiteral(name)) return name.text; + if (ts.isNumericLiteral(name)) return String(Number(name.text)); + if (ts.isComputedPropertyName(name)) { + const e = unparen(name.expression); + if (ts.isStringLiteral(e) || ts.isNoSubstitutionTemplateLiteral(e)) return e.text; + if (ts.isNumericLiteral(e)) return String(Number(e.text)); + } + return null; +} + +function shortFile(fileName: string): string { + const norm = fileName.split("\\").join("/"); + const nm = norm.lastIndexOf("/node_modules/"); + if (nm >= 0) { + const rest = norm.slice(nm + "/node_modules/".length).split("/"); + const pkgLen = rest[0]?.startsWith("@") ? 2 : 1; + const pkg = rest.slice(0, pkgLen).join("/"); + return `${pkg}/${rest[rest.length - 1]}`; + } + return norm.slice(norm.lastIndexOf("/") + 1); +} + +export function locLabel(node: Node): string { + const sf = node.getSourceFile(); + const { line } = ts.getLineAndCharacterOfPosition(sf, node.getStart(sf)); + return `${shortFile(sf.fileName)}:${line + 1}`; +} + +/** Whether a source file belongs to an opted-in package's JavaScript. */ +export function isPackageJsFile(sf: ts.SourceFile): boolean { + return isJsSourceFile(sf) && npmStaticPackageOfPath(sf.fileName) !== null; +} + +function isLoop(node: Node): boolean { + return ( + ts.isForStatement(node) || + ts.isForOfStatement(node) || + ts.isForInStatement(node) || + ts.isWhileStatement(node) || + ts.isDoStatement(node) + ); +} + +const LOOP_CALLBACK_METHODS: ReadonlySet = new Set([ + "map", + "forEach", + "filter", + "some", + "every", + "find", + "findIndex", + "findLast", + "findLastIndex", + "reduce", + "reduceRight", + "flatMap", + "sort", +]); + +export function analyzeShapes(program: ts.Program, checker: ts.TypeChecker): ShapeAnalysis { + return new Analyzer(program, checker).run(); +} + +class Analyzer { + readonly atoms = new AtomTable(); + readonly nodes: ValueNode[] = []; + readonly functions = new Map(); + readonly sites: LiteralSite[] = []; + private readonly siteAtoms = new Set(); + readonly ops: Op[] = []; + readonly calls: CallEdge[] = []; + readonly escaped = new Map(); + readonly topWriteNames = new Map(); + readonly topComputedWrites: Node[] = []; + readonly fields = new Map>(); + readonly elements = new Map(); + readonly top: Atom; + private readonly bindings = new Map(); + private readonly exprMemo = new Map(); + /** Current analysis context and the function whose clone it is. */ + private ctx = ""; + private ctxRoot: Node | null = null; + private readonly classInfo = new Map(); + private readonly boundCalls = new Set(); + private readonly escapedFunctionCalls = new Set(); + private readonly worklist: [number, Atom][] = []; + private steps = 0; + private budgetExceeded = false; + private currentFn: FunctionInfo | null = null; + private loopDepth = 0; + private files: ts.SourceFile[] = []; + private packageFiles = 0; + private readonly prims = new Map(); + /** Per call site: the calling function and whether the site is in a loop + * (constraints fire during solving, after the walk has moved on). */ + private readonly siteCtx = new Map(); + private forceLoop = false; + + noteSite(site: Node): void { + if (!this.siteCtx.has(site)) + this.siteCtx.set(site, { caller: this.currentFn, inLoop: this.loopDepth > 0 }); + } + + edgeFor(site: Node, callee: FunctionInfo): void { + const ctx = this.siteCtx.get(site); + this.calls.push({ + caller: ctx?.caller ?? null, + callee, + inLoop: (ctx?.inLoop ?? false) || this.forceLoop, + }); + } + + constructor( + private readonly program: ts.Program, + private readonly checker: ts.TypeChecker, + ) { + this.top = this.atoms.intern("top", () => ({ kind: "top", label: "⊤" })); + } + + run(): ShapeAnalysis { + for (const sf of this.program.getSourceFiles()) { + if (sf.isDeclarationFile) continue; + const name = sf.fileName.split("\\").join("/"); + const inPackage = isPackageJsFile(sf); + if (!inPackage && name.includes("/node_modules/")) continue; + this.files.push(sf); + if (inPackage) this.packageFiles++; + } + for (const sf of this.files) this.checker.prefetchSourceFile(sf); + for (const sf of this.files) this.moduleBody(sf); + this.finish(); + return { + atoms: this.atoms, + nodes: this.nodes, + functions: this.functions, + sites: this.sites, + ops: this.ops, + calls: this.calls, + escaped: this.escaped, + topWriteNames: this.topWriteNames, + topComputedWrites: this.topComputedWrites, + fields: this.fields, + elements: this.elements, + top: this.top, + files: this.files, + packageFiles: this.packageFiles, + checker: this.checker, + budgetExceeded: this.budgetExceeded, + steps: this.steps, + topCause: this.topCause, + nodeLabel: this.nodeLabel, + }; + } + + // ---- value nodes ------------------------------------------------------- + + newNode(): number { + const id = this.nodes.length; + this.nodes.push({ id, atoms: new Set(), succ: new Set(), onAtom: [], escapeSink: null }); + return id; + } + + /** Debugging (SCRIPTC_DEBUG_SHAPES_WHY): where each node's ⊤ came from. */ + readonly topCause = new Map(); + readonly nodeLabel = new Map(); + private cause: number | null = null; + private readonly traceTop = process.env["SCRIPTC_DEBUG_SHAPES_WHY"] !== undefined; + + add(node: number, atom: Atom): void { + const n = this.nodes[node]!; + if (n.atoms.has(atom)) return; + n.atoms.add(atom); + if (this.traceTop && atom === this.top && !this.topCause.has(node)) + this.topCause.set( + node, + this.cause ?? + (new Error().stack ?? "") + .split("\n") + .slice(2, 4) + .map((l) => l.trim()) + .join(" < "), + ); + this.worklist.push([node, atom]); + } + + edge(from: number, to: number): void { + if (from === to) return; + const n = this.nodes[from]!; + if (n.succ.has(to)) return; + n.succ.add(to); + const saved = this.cause; + this.cause = from; + for (const a of n.atoms) this.add(to, a); + this.cause = saved; + } + + on(node: number, fn: (atom: Atom) => void): void { + const n = this.nodes[node]!; + n.onAtom.push(fn); + for (const a of [...n.atoms]) fn(a); + } + + sink(node: number, reason: string): void { + const n = this.nodes[node]!; + if (n.escapeSink !== null) return; + n.escapeSink = reason; + for (const a of [...n.atoms]) this.escape(a, reason); + } + + constNode(atom: Atom): number { + const n = this.newNode(); + this.add(n, atom); + return n; + } + + prim(name: string): Atom { + let a = this.prims.get(name); + if (a === undefined) { + a = this.atoms.intern(`prim:${name}`, () => ({ kind: "prim", label: name })); + this.prims.set(name, a); + } + return a; + } + + builtin(path: string, receiver?: Atom): Atom { + const key = receiver === undefined ? `builtin:${path}` : `builtin:${path}@${receiver.id}`; + return this.atoms.intern(key, () => ({ kind: "builtin", label: path, path, receiver })); + } + + solve(): void { + while (this.worklist.length > 0) { + if (++this.steps > MAX_STEPS) { + this.budgetExceeded = true; + return; + } + const [id, atom] = this.worklist.pop()!; + const n = this.nodes[id]!; + this.cause = id; + for (const s of n.succ) this.add(s, atom); + this.cause = null; + for (const f of n.onAtom) f(atom); + if (n.escapeSink !== null) this.escape(atom, n.escapeSink); + } + } + + // ---- heap ---------------------------------------------------------------- + + field(atom: Atom, name: string): number { + let m = this.fields.get(atom); + if (m === undefined) { + m = new Map(); + this.fields.set(atom, m); + } + let id = m.get(name); + if (id === undefined) { + id = this.newNode(); + m.set(name, id); + if (this.traceTop) this.nodeLabel.set(id, `${atom.label}.${name}`); + const reason = this.escaped.get(atom); + if (reason !== undefined) { + this.sink(id, reason); + if (this.topComputedWrites.length > 0 || this.topWriteNames.has(name)) + this.add(id, this.top); + } + } + return id; + } + + element(atom: Atom): number { + let id = this.elements.get(atom); + if (id === undefined) { + id = this.newNode(); + this.elements.set(atom, id); + const reason = this.escaped.get(atom); + if (reason !== undefined) { + this.sink(id, reason); + if (this.topComputedWrites.length > 0) this.add(id, this.top); + } + } + return id; + } + + escape(atom: Atom, reason: string): void { + if (atom.kind === "prim" || atom.kind === "top") return; + if (atom.kind === "builtin" && atom.receiver === undefined) return; + if (this.escaped.has(atom)) return; + this.escaped.set(atom, reason); + const via = `via ${atom.label}`; + const fm = this.fields.get(atom); + if (fm !== undefined) { + for (const [name, id] of fm) { + this.sink(id, via); + if (this.topComputedWrites.length > 0 || this.topWriteNames.has(name)) + this.add(id, this.top); + } + } + const el = this.elements.get(atom); + if (el !== undefined) { + this.sink(el, via); + if (this.topComputedWrites.length > 0) this.add(el, this.top); + } + if (atom.receiver !== undefined) this.escape(atom.receiver, via); + if (atom.kind === "function") { + const info = this.infoOfAtom(atom); + if (info !== undefined) this.escapeFunction(info, via); + } + if ((atom.kind === "instance" || atom.kind === "class") && atom.node !== undefined) { + // Unknown code may call any member with any arguments. + for (const member of this.classMembers(atom.node, atom.kind === "class")) { + const info = this.functionInfo(member, this.ownerOf(member), this.receiverCtx(atom)); + this.add(info.thisNode, atom); + this.escapeFunction(info, via); + } + } + if (atom.kind === "promise") this.sink(this.field(atom, "value"), via); + } + + /** A function unknown code may call: ⊤ arguments and receiver; its + * results escape. */ + escapeFunction(info: FunctionInfo, reason: string): void { + if (this.escapedFunctionCalls.has(info)) return; + this.escapedFunctionCalls.add(info); + this.activate(info); + for (const p of info.params) this.add(p, this.top); + if (!info.isArrow && info.ownerClass === null) this.add(info.thisNode, this.top); + this.sink(info.ret, reason); + } + + /** Property names that untyped code writes on receivers that may be ⊤ (census). */ + noteTopWrite(name: string | null, node: Node): void { + if (name === null) { + const first = this.topComputedWrites.length === 0; + this.topComputedWrites.push(node); + if (first) { + for (const atom of [...this.escaped.keys()]) { + for (const id of (this.fields.get(atom) ?? new Map()).values()) + this.add(id, this.top); + const el = this.elements.get(atom); + if (el !== undefined) this.add(el, this.top); + } + } + return; + } + if (this.topWriteNames.has(name)) return; + this.topWriteNames.set(name, node); + for (const atom of [...this.escaped.keys()]) { + const id = this.fields.get(atom)?.get(name); + if (id !== undefined) this.add(id, this.top); + } + } + + // ---- classes --------------------------------------------------------------- + + /** The base class declaration of `decl`, via the checker; null at a + * builtin base or none; undefined when unresolved. */ + baseClass(decl: Node): Node | null | undefined { + const heritage = list((decl as ts.ClassLikeDeclaration).heritageClauses).find( + (c) => c.token === ts.SyntaxKind.ExtendsKeyword, + )?.types?.nodes[0]; + if (heritage === undefined) return null; + const e = unparen(heritage.expression); + if (!ts.isIdentifier(e) && !ts.isPropertyAccessExpression(e)) return undefined; + let d = this.resolve(ts.isIdentifier(e) ? e : e.name); + // `var C = class C { … }` (bundler output) + if ( + d !== undefined && + ts.isVariableDeclaration(d) && + d.initializer !== undefined && + ts.isClassExpression(unparen(d.initializer)) + ) + d = unparen(d.initializer); + if (d !== undefined && ts.isClassLikeDeclaration(d)) return d; + if (d !== undefined && d.getSourceFile().isDeclarationFile) return null; + return undefined; + } + + classChain(decl: Node): Node[] { + const out: Node[] = []; + let cur: Node | null | undefined = decl; + while (cur && out.length < 64 && !out.includes(cur)) { + out.push(cur); + cur = this.baseClass(cur); + } + return out; + } + + /** Method, accessor and constructor declarations of a class chain. */ + classMembers(decl: Node, statics: boolean): Node[] { + const out: Node[] = []; + for (const c of this.classChain(decl)) { + for (const m of list((c as ts.ClassLikeDeclaration).members)) { + if (isStatic(m) !== statics) continue; + if ( + ts.isMethodDeclaration(m) || + ts.isGetAccessorDeclaration(m) || + ts.isSetAccessorDeclaration(m) + ) + out.push(m); + else if (ts.isPropertyDeclaration(m) && m.initializer !== undefined) { + const init = unparen(m.initializer); + if (ts.isArrowFunction(init) || ts.isFunctionExpression(init)) out.push(init); + } + } + } + return out; + } + + lookupMember( + decl: Node, + name: string, + statics: boolean, + ): { + kind: "method" | "getter" | "setter" | "both"; + get?: Node; + set?: Node; + method?: Node; + } | null { + for (const c of this.classChain(decl)) { + let get: Node | undefined; + let set: Node | undefined; + for (const m of list((c as ts.ClassLikeDeclaration).members)) { + if (isStatic(m) !== statics) continue; + const mn = (m as { name?: Node }).name; + if (mn === undefined || propertyNameText(mn) !== name) continue; + if (ts.isMethodDeclaration(m)) return { kind: "method", method: m }; + if (ts.isGetAccessorDeclaration(m)) get = m; + if (ts.isSetAccessorDeclaration(m)) set = m; + if (ts.isPropertyDeclaration(m)) return null; // an own field: data + } + if (get || set) + return { + kind: get && set ? "both" : get ? "getter" : "setter", + ...(get ? { get } : {}), + ...(set ? { set } : {}), + }; + } + return null; + } + + // ---- symbols ----------------------------------------------------------------- + + resolve(id: Node): Node | undefined { + let sym = this.checker.getSymbolAtLocation(id); + if (sym === undefined) return undefined; + if (sym.flags & ts.SymbolFlags.Alias) { + try { + sym = this.checker.getAliasedSymbol(sym); + } catch { + return undefined; + } + } + return sym.valueDeclaration ?? sym.declarations[0]; + } + + binding(decl: Node): number { + const key = this.ctxKey(decl); + let id = this.bindings.get(key); + if (id === undefined) { + id = this.newNode(); + this.bindings.set(key, id); + if (this.traceTop) + this.nodeLabel.set( + id, + `binding ${(decl as { name?: { text?: string } }).name?.text ?? "?"}@${locLabel(decl)}${this.ctx !== "" ? ` [${this.ctx}]` : ""}`, + ); + } + return id; + } + + /** Bindings and expressions inside the function being cloned belong to + * the clone's context; everything else to the default context. */ + ctxKey(node: Node): string { + const root = this.ctxRoot; + const inside = + root !== null && + node.getSourceFile() === root.getSourceFile() && + node.pos >= root.pos && + node.end <= root.end; + return `${inside ? this.ctx : ""}|${this.nodeKey(node)}`; + } + + receiverCtx(atom: Atom): string { + return atom.kind === "instance" || atom.kind === "class" ? `C${atom.id}` : ""; + } + + infoOfAtom(atom: Atom): FunctionInfo | undefined { + if (atom.node === undefined) return undefined; + return this.functions.get(`${atom.ctx ?? ""}|${this.nodeKey(atom.node)}`); + } + + // ---- functions --------------------------------------------------------------- + + functionInfo(node: Node, ownerClass: Node | null, ctxArg = ""): FunctionInfo { + // A nested closure walked inside a clone shares the clone's context. + const inherit = + ctxArg === "" && + this.ctxRoot !== null && + node.getSourceFile() === this.ctxRoot.getSourceFile() && + node.pos >= this.ctxRoot.pos && + node.end <= this.ctxRoot.end; + const ctx = ctxArg !== "" ? ctxArg : inherit ? this.ctx : ""; + const root = ctxArg !== "" ? node : inherit ? this.ctxRoot : null; + const fkey = `${ctx}|${this.nodeKey(node)}`; + const existing = this.functions.get(fkey); + if (existing !== undefined) return existing; + const savedCtx = this.ctx; + const savedRoot = this.ctxRoot; + this.ctx = ctx; + this.ctxRoot = root; + const fn = node as ts.FunctionLikeDeclaration; + const isArrow = ts.isArrowFunction(node); + const params: number[] = []; + let rest = -1; + for (const p of list(fn.parameters)) { + const id = this.binding(p); + if (p.dotDotDotToken !== undefined) rest = params.length; + params.push(id); + } + const mods = list((fn as { modifiers?: { nodes: readonly Node[] } }).modifiers); + const sf = node.getSourceFile(); + const nameNode = (fn as { name?: Node }).name; + const name = nameNode !== undefined ? (propertyNameText(nameNode) ?? "") : null; + const owner = ownerClass !== null ? this.className(ownerClass) : null; + const label = `${owner !== null ? `${owner}.` : ""}${name ?? (ts.isConstructorDeclaration(node) ? "constructor" : "")}@${locLabel(node)}`; + const info: FunctionInfo = { + node, + ctx, + root, + walked: false, + label: ctx === "" ? label : `${label} [${this.ctxLabel(ctx)}]`, + params, + rest, + thisNode: isArrow && this.currentFn !== null ? this.currentFn.thisNode : this.newNode(), + ret: this.newNode(), + isArrow, + isAsync: mods.some((m) => m.kind === ts.SyntaxKind.AsyncKeyword), + isGenerator: (fn as { asteriskToken?: Node }).asteriskToken !== undefined, + usesArguments: false, + argPos: null, + ownerClass, + inPackage: isPackageJsFile(sf), + }; + this.functions.set(fkey, info); + this.ctx = savedCtx; + this.ctxRoot = savedRoot; + return info; + } + + /** Walks a function's body the first time it can run. */ + activate(info: FunctionInfo): void { + if (info.walked) return; + info.walked = true; + if (ts.isSourceFile(info.node) || ts.isClassLikeDeclaration(info.node)) return; + const fn = info.node as ts.FunctionLikeDeclaration; + const savedCtx = this.ctx; + const savedRoot = this.ctxRoot; + const saved = this.currentFn; + const savedLoop = this.loopDepth; + this.ctx = info.ctx; + this.ctxRoot = info.root; + this.currentFn = info; + this.loopDepth = 0; + for (const p of list(fn.parameters)) { + if (p.initializer !== undefined) this.edge(this.expr(p.initializer), this.binding(p)); + if (p.dotDotDotToken !== undefined) { + const arr = this.atoms.intern(`rest:${this.nodes.length}`, () => ({ + kind: "array", + label: `rest@${locLabel(p)}`, + node: p, + })); + this.add(this.binding(p), arr); + } + this.bindPattern(p.name, this.binding(p)); + } + const body = fn.body; + if (body !== undefined) { + if (ts.isBlock(body)) this.stmts(list(body.statements)); + else this.edge(this.expr(body as ts.Expression), info.ret); + } + this.currentFn = saved; + this.loopDepth = savedLoop; + this.ctx = savedCtx; + this.ctxRoot = savedRoot; + if (info.usesArguments) { + for (const p of info.params) this.add(p, this.top); + } + } + + /** The atom of a function node (memoized by its info). */ + fnAtom(node: Node, ownerClass: Node | null, ctx = ""): Atom { + const info = this.functionInfo(node, ownerClass, ctx); + return this.atoms.intern(`fn:${info.ret}`, () => ({ + kind: "function", + label: info.label, + node, + ctx: info.ctx, + })); + } + + ctxLabel(ctx: string): string { + if (ctx.startsWith("C")) return `this=${this.atoms.atoms[Number(ctx.slice(1))]?.label ?? ctx}`; + return ctx; + } + + className(decl: Node): string { + const own = (decl as ts.ClassLikeDeclaration).name?.text; + if (own !== undefined) return own; + const p = decl.parent; + if (p !== undefined && ts.isVariableDeclaration(p) && ts.isIdentifier(p.name)) + return p.name.text; + return ``; + } + + classAtoms(decl: Node): { cls: Atom; inst: Atom } { + const name = this.className(decl); + const cls = this.atoms.intern(`class:${this.nodeKey(decl)}`, () => ({ + kind: "class", + label: `class ${name}`, + node: decl, + })); + const inst = this.atoms.intern(`inst:${this.nodeKey(decl)}`, () => ({ + kind: "instance", + label: name, + node: decl, + })); + this.ensureClass(decl); + return { cls, inst }; + } + + private readonly nodeKeys = new Map(); + nodeKey(node: Node): number { + let k = this.nodeKeys.get(node); + if (k === undefined) { + k = this.nodeKeys.size; + this.nodeKeys.set(node, k); + } + return k; + } + + /** Registers a class: member functions, field initializers (as a pseudo + * function run at construction) and static initializers. */ + ensureClass(decl: Node): { initFn: FunctionInfo; staticInit: FunctionInfo } { + const existing = this.classInfo.get(decl); + if (existing !== undefined) return existing; + const c = decl as ts.ClassLikeDeclaration; + const label = this.className(decl); + const mk = (suffix: string): FunctionInfo => ({ + node: decl, + ctx: "", + root: null, + walked: true, + label: `${label}.${suffix}@${locLabel(decl)}`, + params: [], + rest: -1, + thisNode: this.newNode(), + ret: this.newNode(), + isArrow: false, + isAsync: false, + isGenerator: false, + usesArguments: false, + argPos: null, + ownerClass: decl, + inPackage: isPackageJsFile(decl.getSourceFile()), + }); + const entry = { initFn: mk(""), staticInit: mk("") }; + this.classInfo.set(decl, entry); + const cls = this.atoms.intern(`class:${this.nodeKey(decl)}`, () => ({ + kind: "class", + label: `class ${label}`, + node: decl, + })); + this.add(entry.staticInit.thisNode, cls); + const saved = this.currentFn; + for (const m of list(c.members)) { + const statics = isStatic(m); + if ( + ts.isMethodDeclaration(m) || + ts.isGetAccessorDeclaration(m) || + ts.isSetAccessorDeclaration(m) || + ts.isConstructorDeclaration(m) + ) { + continue; + } + if (ts.isPropertyDeclaration(m)) { + const name = propertyNameText(m.name); + const init = statics ? entry.staticInit : entry.initFn; + this.currentFn = init; + const value = + m.initializer !== undefined + ? this.exprIn(m.initializer, decl) + : this.constNode(this.prim("undefined")); + if (name !== null) this.storeConstraint(init.thisNode, name, value, m); + continue; + } + if (ts.isClassStaticBlockDeclaration(m)) { + this.currentFn = entry.staticInit; + this.stmts(list(m.body.statements)); + } + } + this.currentFn = saved; + return entry; + } + + /** An initializer expression: arrow functions in field initializers take + * the instance as `this` and belong to the class. */ + exprIn(e: ts.Expression, ownerClass: Node): number { + const u = unparen(e); + if (ts.isArrowFunction(u) || ts.isFunctionExpression(u)) { + const n = this.newNode(); + this.add(n, this.fnAtom(u, ts.isArrowFunction(u) ? null : ownerClass)); + return n; + } + return this.expr(e); + } + + /** `new C(args)` on a class atom: the instance, the field initializers of + * every class in the chain, and the constructor (or the implicit one). */ + construct( + decl: Node, + args: number[], + spread: boolean, + dst: number, + site: Node, + inst?: Atom, + ): void { + const atoms = this.classAtoms(decl); + const instance = inst ?? atoms.inst; + this.add(dst, instance); + this.callConstructorChain(decl, instance, args, spread, site); + } + + callConstructorChain( + decl: Node, + instance: Atom, + args: number[], + spread: boolean, + site: Node, + ): void { + const key = `ctor:${this.nodeKey(decl)}:${instance.id}:${this.nodeKey(site)}`; + if (this.boundCalls.has(key)) return; + this.boundCalls.add(key); + const entry = this.ensureClass(decl); + this.add(entry.initFn.thisNode, instance); + const ctor = list((decl as ts.ClassLikeDeclaration).members).find((m) => + ts.isConstructorDeclaration(m), + ); + if (ctor !== undefined) { + const info = this.functionInfo(ctor, decl, this.receiverCtx(instance)); + this.activate(info); + this.add(info.thisNode, instance); + this.bindArgs(info, args, spread); + this.edgeFor(site, info); + return; + } + const base = this.baseClass(decl); + if (base) this.callConstructorChain(base, instance, args, spread, site); + } + + bindArgs(info: FunctionInfo, args: number[], spread: boolean): void { + if (info.argPos !== null) { + for (let i = 0; i < info.argPos.length; i++) { + if (spread || i >= info.argPos.length - 1) { + for (const a of args.slice(i)) this.edge(a, info.argPos[i]!); + if (spread) this.add(info.argPos[i]!, this.top); + } else if (i < args.length) this.edge(args[i]!, info.argPos[i]!); + else this.add(info.argPos[i]!, this.prim("undefined")); + } + } + if (spread) { + for (const p of info.params) this.add(p, this.top); + for (const a of args) this.sink(a, `spread into ${info.label}`); + return; + } + for (let i = 0; i < info.params.length; i++) { + if (i === info.rest) { + const restAtoms = [...this.nodes[info.params[i]!]!.atoms]; + for (const ra of restAtoms) + for (let j = i; j < args.length; j++) this.edge(args[j]!, this.element(ra)); + break; + } + if (i < args.length) this.edge(args[i]!, info.params[i]!); + else this.add(info.params[i]!, this.prim("undefined")); + } + } + + /** Call of a function atom with a receiver node. */ + callFunction( + info: FunctionInfo, + thisNode: number | null, + args: number[], + spread: boolean, + dst: number, + site: Node, + ): void { + // `() => Object.create(null)` helpers: each call site gets its own + // dictionary, as if the helper were inlined. + if (this.isFactory(info.node)) { + const d = this.atoms.intern(`dict:${this.nodeKey(site)}`, () => ({ + kind: "dictionary", + label: `Object.create@${locLabel(site)}`, + node: site, + })); + this.add(dst, d); + return; + } + this.activate(info); + const fnNode = info.node; + const key = `call:${info.ctx}|${this.nodeKey(fnNode)}:${this.nodeKey(site)}:${thisNode ?? -1}:${dst}`; + if (this.boundCalls.has(key)) return; + this.boundCalls.add(key); + if (thisNode !== null && !info.isArrow) this.edge(thisNode, info.thisNode); + this.bindArgs(info, args, spread); + if (info.isAsync) { + const p = this.promiseAtom(fnNode, `async ${info.label}`); + this.awaitInto(info.ret, this.field(p, "value")); + this.add(dst, p); + } else if (info.isGenerator) { + this.add(dst, this.top); + } else this.edge(info.ret, dst); + this.edgeFor(site, info); + } + + private readonly factories = new Map(); + isFactory(node: Node): boolean { + let r = this.factories.get(node); + if (r === undefined) { + r = false; + const fn = node as ts.FunctionLikeDeclaration; + let e: Node | undefined = fn.body; + if (e !== undefined && ts.isBlock(e)) { + const st = e.statements.nodes; + e = st.length === 1 && ts.isReturnStatement(st[0]!) ? st[0]!.expression : undefined; + } + if (e !== undefined && !ts.isSourceFile(node)) { + const u = unparen(e as ts.Expression); + r = + ts.isCallExpression(u) && + u.expression.getText() === "Object.create" && + u.arguments.nodes.length === 1 && + u.arguments.nodes[0]!.kind === ts.SyntaxKind.NullKeyword; + } + this.factories.set(node, r); + } + return r; + } + + promiseAtom(site: Node, label: string): Atom { + return this.atoms.intern(`promise:${this.nodeKey(site)}`, () => ({ + kind: "promise", + label: `Promise@${label}`, + node: site, + })); + } + + /** dst ⊇ awaited(src). */ + awaitInto(src: number, dst: number): void { + this.on(src, (a) => { + if (a.kind === "promise") this.edge(this.field(a, "value"), dst); + else this.add(dst, a); + }); + } + + syntheticArray(site: Node, tag: string): Atom { + return this.atoms.intern(`arr:${tag}:${this.nodeKey(site)}`, () => ({ + kind: "array", + label: `${tag}[]@${locLabel(site)}`, + node: site, + })); + } + + // ---- statements ---------------------------------------------------------------- + + moduleBody(sf: ts.SourceFile): void { + const info: FunctionInfo = { + node: sf, + ctx: "", + root: null, + walked: true, + label: ``, + params: [], + rest: -1, + thisNode: this.constNode(this.prim("undefined")), + ret: this.newNode(), + isArrow: false, + isAsync: false, + isGenerator: false, + usesArguments: false, + argPos: null, + ownerClass: null, + inPackage: isPackageJsFile(sf), + }; + this.functions.set(`|${this.nodeKey(sf)}`, info); + this.currentFn = info; + this.stmts(list(sf.statements)); + this.currentFn = null; + } + + stmts(stmts: readonly Node[]): void { + for (const s of stmts) this.stmt(s); + } + + stmt(s: Node): void { + if (ts.isVariableStatement(s)) { + for (const d of list(s.declarationList.declarations)) this.varDecl(d); + return; + } + if (ts.isExpressionStatement(s)) { + this.expr(s.expression); + return; + } + if (ts.isReturnStatement(s)) { + if (s.expression !== undefined && this.currentFn !== null) + this.edge(this.expr(s.expression), this.currentFn.ret); + return; + } + if (ts.isFunctionDeclaration(s)) { + const b = this.binding(s); + const saved = this.currentFn; + this.currentFn = null; + this.add(b, this.fnAtom(s, null)); + this.currentFn = saved; + return; + } + if (ts.isClassDeclaration(s)) { + const b = this.binding(s); + this.add(b, this.classAtoms(s).cls); + return; + } + if (isLoop(s)) { + if (ts.isForOfStatement(s) || ts.isForInStatement(s)) { + const src = this.expr(s.expression); + const target = this.newNode(); + if (ts.isForInStatement(s)) this.add(target, this.prim("string")); + else this.iterateInto(src, target, s); + const init = s.initializer; + if (ts.isVariableDeclarationList(init)) { + for (const d of list(init.declarations)) { + this.edge(target, this.binding(d)); + this.bindPattern(d.name, this.binding(d)); + } + } else this.assignTo(init as ts.Expression, target); + } + this.loopDepth++; + if (ts.isForStatement(s)) { + if (s.initializer !== undefined) { + if (ts.isVariableDeclarationList(s.initializer)) + for (const d of list(s.initializer.declarations)) this.varDecl(d); + else this.expr(s.initializer as ts.Expression); + } + if (s.condition !== undefined) this.expr(s.condition); + if (s.incrementor !== undefined) this.expr(s.incrementor); + } + if (ts.isWhileStatement(s) || ts.isDoStatement(s)) this.expr(s.expression); + const body = (s as { statement?: Node }).statement; + if (body !== undefined) this.stmt(body); + this.loopDepth--; + return; + } + if (ts.isTryStatement(s)) { + this.stmts(list(s.tryBlock.statements)); + if (s.catchClause !== undefined) { + const v = s.catchClause.variableDeclaration; + if (v !== undefined) { + this.add(this.binding(v), this.top); + this.bindPattern(v.name, this.binding(v)); + } + this.stmts(list(s.catchClause.block.statements)); + } + if (s.finallyBlock !== undefined) this.stmts(list(s.finallyBlock.statements)); + return; + } + if (ts.isThrowStatement(s)) { + this.sink(this.expr(s.expression), `thrown at ${locLabel(s)}`); + return; + } + if ( + ts.isImportDeclaration(s) || + ts.isExportDeclaration(s) || + ts.isInterfaceDeclaration(s) || + ts.isTypeAliasDeclaration(s) + ) + return; + if (ts.isExportAssignment(s)) { + this.expr(s.expression); + return; + } + // Blocks, ifs, switches, labels: walk children, evaluating expressions. + ts.forEachChild(s, (child) => { + if (ts.isExpression(child)) this.expr(child); + else this.stmt(child); + return undefined; + }); + } + + varDecl(d: ts.VariableDeclaration): void { + const b = this.binding(d); + if (d.initializer !== undefined) this.edge(this.expr(d.initializer), b); + this.bindPattern(d.name, b); + } + + /** Destructuring: binding elements read from the source node. */ + bindPattern(name: Node, src: number): void { + if (ts.isIdentifier(name)) return; + if (ts.isObjectBindingPattern(name)) { + for (const el of list(name.elements)) { + const b = this.binding(el); + if (el.dotDotDotToken !== undefined) { + this.add(b, this.top); + continue; + } + const keyNode = el.propertyName ?? el.name; + const key = keyNode !== undefined ? propertyNameText(keyNode) : null; + if (key !== null) this.loadConstraint(src, key, b, el); + else this.add(b, this.top); + if (el.initializer !== undefined) this.edge(this.expr(el.initializer), b); + if (el.name !== undefined) this.bindPattern(el.name, b); + } + return; + } + if (ts.isArrayBindingPattern(name)) { + let i = 0; + for (const el of list(name.elements)) { + if (ts.isBindingElement(el)) { + const b = this.binding(el); + if (el.dotDotDotToken !== undefined) this.add(b, this.top); + else this.iterateInto(src, b, el, i); + if (el.initializer !== undefined) this.edge(this.expr(el.initializer), b); + if (el.name !== undefined) this.bindPattern(el.name, b); + } + i++; + } + } + } + + /** Element values of an iterable. */ + iterateInto(src: number, dst: number, site: Node, _index?: number): void { + this.on(src, (a) => { + if (a.kind === "array" || a.kind === "collection") this.edge(this.element(a), dst); + else if (a.kind === "prim" && a.label === "string") this.add(dst, this.prim("string")); + else if (a.kind === "prim" || a.kind === "object" || a.kind === "dictionary") { + /* not iterable (a TypeError): no value. Literals with a + Symbol.iterator member have a computed key; they are G sites. */ + } else { + this.add(dst, this.top); + if (a.kind !== "top") this.escape(a, `iterated at ${locLabel(site)}`); + } + }); + } + + // ---- expressions --------------------------------------------------------------- + + expr(e: ts.Expression): number { + const key = this.ctxKey(e); + const memo = this.exprMemo.get(key); + if (memo !== undefined) return memo; + const id = this.exprUncached(e); + this.exprMemo.set(key, id); + if (this.traceTop && !this.nodeLabel.has(id)) + this.nodeLabel.set( + id, + `expr ${e.getText().slice(0, 40).replace(/\s+/g, " ")}@${locLabel(e)}`, + ); + return id; + } + + private exprUncached(e: ts.Expression): number { + const u = unparen(e); + if (u !== e) return this.expr(u); + switch (e.kind) { + case ts.SyntaxKind.StringLiteral: + case ts.SyntaxKind.NoSubstitutionTemplateLiteral: + case ts.SyntaxKind.TemplateExpression: + if (ts.isTemplateExpression(e)) + for (const span of list(e.templateSpans)) this.expr(span.expression); + return this.constNode(this.prim("string")); + case ts.SyntaxKind.NumericLiteral: + return this.constNode(this.prim("number")); + case ts.SyntaxKind.BigIntLiteral: + return this.constNode(this.prim("bigint")); + case ts.SyntaxKind.TrueKeyword: + case ts.SyntaxKind.FalseKeyword: + return this.constNode(this.prim("boolean")); + case ts.SyntaxKind.NullKeyword: + return this.constNode(this.prim("null")); + case ts.SyntaxKind.RegularExpressionLiteral: + return this.constNode(this.builtin("RegExp.instance")); + case ts.SyntaxKind.ThisKeyword: + return this.currentFn !== null + ? this.currentFn.thisNode + : this.constNode(this.prim("undefined")); + case ts.SyntaxKind.SuperKeyword: + return this.constNode(this.top); + } + if (ts.isIdentifier(e)) return this.identifier(e); + if (ts.isObjectLiteralExpression(e)) return this.objectLiteral(e); + if (ts.isArrayLiteralExpression(e)) return this.arrayLiteral(e); + if (ts.isArrowFunction(e) || ts.isFunctionExpression(e)) { + const n = this.newNode(); + this.add(n, this.fnAtom(e, null)); + if (ts.isFunctionExpression(e) && e.name !== undefined) + this.add(this.binding(e), this.fnAtom(e, null)); + return n; + } + if (ts.isClassExpression(e)) { + const n = this.newNode(); + this.add(n, this.classAtoms(e).cls); + return n; + } + if (ts.isPropertyAccessExpression(e)) { + this.noteSite(e); + const recv = this.expr(e.expression); + const name = e.name.text; + const dst = this.newNode(); + this.loadConstraint(recv, name, dst, e); + this.ops.push({ kind: "read", recv, name, node: e }); + return dst; + } + if (ts.isElementAccessExpression(e)) { + const recv = this.expr(e.expression); + const key = unparen(e.argumentExpression); + const dst = this.newNode(); + const name = + ts.isStringLiteral(key) || ts.isNoSubstitutionTemplateLiteral(key) ? key.text : null; + if (name !== null) { + this.loadConstraint(recv, name, dst, e); + this.ops.push({ kind: "read", recv, name, node: e }); + } else { + this.expr(e.argumentExpression); + this.computedLoad(recv, dst, e); + this.ops.push({ kind: "computedRead", recv, name: null, node: e }); + } + return dst; + } + if (ts.isCallExpression(e)) return this.call(e); + if (ts.isNewExpression(e)) return this.newExpr(e); + if (ts.isBinaryExpression(e)) return this.binary(e); + if (ts.isConditionalExpression(e)) { + this.expr(e.condition); + const n = this.newNode(); + this.edge(this.expr(e.whenTrue), n); + this.edge(this.expr(e.whenFalse), n); + return n; + } + if (ts.isAwaitExpression(e)) { + const n = this.newNode(); + this.awaitInto(this.expr(e.expression), n); + return n; + } + if (ts.isTypeOfExpression(e)) { + this.expr(e.expression); + return this.constNode(this.prim("string")); + } + if (ts.isVoidExpression(e)) { + this.expr(e.expression); + return this.constNode(this.prim("undefined")); + } + if (ts.isDeleteExpression(e)) { + const target = unparen(e.expression); + if (ts.isPropertyAccessExpression(target) || ts.isElementAccessExpression(target)) { + const recv = this.expr(target.expression); + const name = ts.isPropertyAccessExpression(target) ? target.name.text : null; + this.ops.push({ kind: "delete", recv, name, node: e }); + } + return this.constNode(this.prim("boolean")); + } + if (ts.isPrefixUnaryExpression(e) || ts.isPostfixUnaryExpression(e)) { + const operand = e.operand; + this.expr(operand); + if ( + e.operator === ts.SyntaxKind.PlusPlusToken || + e.operator === ts.SyntaxKind.MinusMinusToken + ) + this.assignTo(operand, this.constNode(this.prim("number"))); + if (ts.isPrefixUnaryExpression(e) && e.operator === ts.SyntaxKind.ExclamationToken) + return this.constNode(this.prim("boolean")); + return this.constNode(this.prim("number")); + } + if (ts.isSpreadElement(e)) return this.expr(e.expression); + if (ts.isTaggedTemplateExpression(e)) { + this.expr(e.tag); + return this.constNode(this.top); + } + if (ts.isYieldExpression(e)) { + if (e.expression !== undefined) + this.sink(this.expr(e.expression), `yielded at ${locLabel(e)}`); + return this.constNode(this.top); + } + if (ts.isMetaProperty(e)) return this.constNode(this.top); + // Anything else: evaluate children, answer ⊤. + ts.forEachChild(e, (child) => { + if (ts.isExpression(child)) this.expr(child); + return undefined; + }); + return this.constNode(this.top); + } + + identifier(id: ts.Identifier): number { + if (id.text === "undefined") return this.constNode(this.prim("undefined")); + if (id.text === "arguments") { + const fn = this.enclosingNonArrow(); + if (fn !== null) { + const parent = id.parent; + const forwarding = parent !== undefined && ts.isSpreadElement(parent); + if (!forwarding) fn.usesArguments = true; + const arr = this.syntheticArray(id, "arguments"); + for (const p of fn.params) this.edge(p, this.element(arr)); + return this.constNode(arr); + } + } + const decl = this.resolve(id); + if (decl === undefined) return this.globalNode(id.text); + if (decl.getSourceFile().isDeclarationFile) return this.globalNode(id.text); + if (!this.files.includes(decl.getSourceFile())) return this.constNode(this.top); + if (ts.isFunctionDeclaration(decl)) { + const b = this.binding(decl); + const saved = this.currentFn; + this.currentFn = null; + this.add(b, this.fnAtom(decl, null)); + this.currentFn = saved; + return b; + } + if (ts.isClassDeclaration(decl) || ts.isClassExpression(decl)) { + const b = this.binding(decl); + this.add(b, this.classAtoms(decl).cls); + return b; + } + if (ts.isFunctionExpression(decl)) return this.binding(decl); + if ( + ts.isImportSpecifier(decl) || + ts.isImportClause(decl) || + ts.isNamespaceImport(decl) || + ts.isImportEqualsDeclaration(decl) + ) + return this.constNode(this.top); + if (ts.isSourceFile(decl) || ts.isModuleDeclaration(decl)) return this.namespaceNode(decl); + return this.narrowed(id, decl, this.binding(decl)); + } + + /** Flow narrowing at guarded references (S1 handles the guards hot code + * uses: `x instanceof C` and calls of predicate functions whose body is + * `… && x instanceof C`, in the true arm of an `if`, `?:` or `&&`). The + * narrowed value keeps the guard's class arms and ⊤. */ + narrowed(id: ts.Identifier, decl: Node, value: number): number { + let child: Node = id; + let p = id.parent; + while (p !== undefined && !ts.isFunctionLike(p) && !ts.isSourceFile(p)) { + let cond: ts.Expression | undefined; + if (ts.isIfStatement(p) && p.thenStatement === child) cond = p.expression; + else if (ts.isConditionalExpression(p) && p.whenTrue === child) cond = p.condition; + else if ( + ts.isBinaryExpression(p) && + p.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken && + p.right === child + ) + cond = p.left; + if (cond !== undefined) { + const cls = this.guardClass(cond, decl); + if (cls !== null) { + const out = this.newNode(); + this.on(value, (a) => { + if (a.kind === "top") this.add(out, a); + else if ( + cls === "Promise" + ? a.kind === "promise" + : a.kind === "instance" && + a.node !== undefined && + this.classChain(a.node).includes(cls) + ) + this.add(out, a); + }); + return out; + } + } + child = p; + p = p.parent; + } + return value; + } + + /** The class a condition proves `decl`'s value an instance of, if any. */ + guardClass(cond: ts.Expression, decl: Node): Node | "Promise" | null { + const e = unparen(cond); + if (ts.isBinaryExpression(e)) { + if (e.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) + return this.guardClass(e.left, decl) ?? this.guardClass(e.right, decl); + if (e.operatorToken.kind !== ts.SyntaxKind.InstanceOfKeyword) return null; + const l = unparen(e.left); + if (!ts.isIdentifier(l) || this.resolve(l) !== decl) return null; + return this.instanceofTarget(e.right); + } + if ( + ts.isCallExpression(e) && + ts.isIdentifier(unparen(e.expression)) && + e.arguments.nodes.length === 1 + ) { + const arg = unparen(e.arguments.nodes[0]!); + if (!ts.isIdentifier(arg) || this.resolve(arg) !== decl) return null; + const fnDecl = this.resolve(unparen(e.expression)); + let fn: Node | undefined = fnDecl; + if (fn !== undefined && ts.isVariableDeclaration(fn) && fn.initializer !== undefined) + fn = unparen(fn.initializer); + if ( + fn === undefined || + !(ts.isArrowFunction(fn) || ts.isFunctionDeclaration(fn) || ts.isFunctionExpression(fn)) + ) + return null; + const param = fn.parameters.nodes[0]; + if (param === undefined || !ts.isIdentifier(param.name)) return null; + let body: Node | undefined = fn.body; + if (body !== undefined && ts.isBlock(body)) { + const stmts = body.statements.nodes; + body = + stmts.length === 1 && ts.isReturnStatement(stmts[0]!) ? stmts[0]!.expression : undefined; + } + if (body === undefined) return null; + return this.predicateClass(body as ts.Expression, param); + } + return null; + } + + /** `… && p instanceof C` in a predicate body over parameter `p`. */ + predicateClass(e: ts.Expression, param: Node): Node | "Promise" | null { + const u = unparen(e); + if (!ts.isBinaryExpression(u)) return null; + if (u.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) + return this.predicateClass(u.right, param) ?? this.predicateClass(u.left, param); + if (u.operatorToken.kind !== ts.SyntaxKind.InstanceOfKeyword) return null; + const l = unparen(u.left); + if (!ts.isIdentifier(l) || this.resolve(l) !== param) return null; + return this.instanceofTarget(u.right); + } + + instanceofTarget(right: ts.Expression): Node | "Promise" | null { + const r = unparen(right); + if (!ts.isIdentifier(r)) return null; + const d = this.resolve(r); + if (d === undefined || d.getSourceFile().isDeclarationFile) + return r.text === "Promise" ? "Promise" : null; + return ts.isClassLikeDeclaration(d) ? d : null; + } + + private readonly namespaces = new Map(); + /** `import * as ns`: an object whose fields are the module's exports. */ + namespaceNode(mod: Node): number { + const existing = this.namespaces.get(mod); + if (existing !== undefined) return existing; + const n = this.newNode(); + this.namespaces.set(mod, n); + const atom = this.atoms.intern(`ns:${this.nodeKey(mod)}`, () => ({ + kind: "object", + label: `namespace ${shortFile((mod as ts.SourceFile).fileName ?? "")}`, + node: mod, + })); + this.add(n, atom); + const sym = this.checker.getSymbolAtLocation(mod); + if (sym !== undefined) { + for (const ex of this.checker.getExportsOfModule(sym)) { + let target = ex; + if (target.flags & ts.SymbolFlags.Alias) { + try { + target = this.checker.getAliasedSymbol(target); + } catch { + continue; + } + } + const d = target.valueDeclaration ?? target.declarations[0]; + if (d === undefined) continue; + const value = this.declValue(d); + if (value !== null) this.edge(value, this.field(atom, String(ex.escapedName))); + } + } + return n; + } + + declValue(d: Node): number | null { + if (d.getSourceFile().isDeclarationFile || !this.files.includes(d.getSourceFile())) return null; + if (ts.isFunctionDeclaration(d)) { + const b = this.binding(d); + const saved = this.currentFn; + this.currentFn = null; + this.add(b, this.fnAtom(d, null)); + this.currentFn = saved; + return b; + } + if (ts.isClassDeclaration(d)) { + const b = this.binding(d); + this.add(b, this.classAtoms(d).cls); + return b; + } + if (ts.isVariableDeclaration(d) || ts.isBindingElement(d) || ts.isParameter(d)) + return this.binding(d); + if (ts.isSourceFile(d)) return this.namespaceNode(d); + return null; + } + + globalNode(name: string): number { + if (MODELED_GLOBALS.has(name)) return this.constNode(this.builtin(name)); + if (name === "NaN" || name === "Infinity") return this.constNode(this.prim("number")); + return this.constNode(this.top); + } + + enclosingNonArrow(): FunctionInfo | null { + const fn = this.currentFn; + if (fn === null) return null; + if (!fn.isArrow) return fn; + // An arrow's `arguments` is its enclosing function's. + let p: Node | undefined = fn.node.parent; + while (p !== undefined) { + if (ts.isFunctionLike(p) && !ts.isArrowFunction(p)) + return ( + this.functions.get(this.ctxKey(p)) ?? this.functions.get(`|${this.nodeKey(p)}`) ?? null + ); + p = p.parent; + } + return null; + } + + objectLiteral(e: ts.ObjectLiteralExpression): number { + const keys: string[] = []; + let keysKnown = true; + let hasAccessor = false; + let hasProto = false; + let hasComputedKey = false; + const spreads: number[] = []; + const inPackage = isPackageJsFile(e.getSourceFile()); + const label = (): string => + `{${keys.slice(0, 6).join(",")}${keys.length > 6 ? ",…" : ""}${keysKnown ? "" : ",…"}}@${locLabel(e)}`; + // keys first, so the label is complete + for (const p of list(e.properties)) { + if (ts.isSpreadAssignment(p)) { + keysKnown = false; + continue; + } + const name = (p as { name?: Node }).name; + const key = name !== undefined ? propertyNameText(name) : null; + if (key === null) { + hasComputedKey = true; + keysKnown = false; + continue; + } + if (key === "__proto__" && ts.isPropertyAssignment(p) && !ts.isComputedPropertyName(p.name)) + hasProto = true; + if (!keys.includes(key)) keys.push(key); + } + const atom = this.atoms.intern(`obj:${this.nodeKey(e)}`, () => ({ + kind: "object", + label: label(), + node: e, + })); + const n = this.newNode(); + this.add(n, atom); + for (const p of list(e.properties)) { + if (ts.isSpreadAssignment(p)) { + const src = this.expr(p.expression); + spreads.push(src); + this.copyFields(src, atom, p); + continue; + } + if (ts.isGetAccessorDeclaration(p) || ts.isSetAccessorDeclaration(p)) { + hasAccessor = true; + const info = this.functionInfo(p, null); + this.activate(info); + this.add(info.thisNode, atom); + const key = propertyNameText(p.name); + if (key !== null && ts.isGetAccessorDeclaration(p)) + this.edge(info.ret, this.field(atom, key)); + continue; + } + const name = (p as { name?: Node }).name; + const key = name !== undefined ? propertyNameText(name) : null; + if (name !== undefined && ts.isComputedPropertyName(name)) this.expr(name.expression); + let value: number; + if (ts.isPropertyAssignment(p)) value = this.expr(p.initializer); + else if (ts.isShorthandPropertyAssignment(p)) { + const sym = this.checker.getShorthandAssignmentValueSymbol(p); + const d = sym?.valueDeclaration ?? sym?.declarations[0]; + const id = p.name as ts.Identifier; + value = d !== undefined ? (this.declValue(d) ?? this.identifier(id)) : this.identifier(id); + } else if (ts.isMethodDeclaration(p)) { + const fa = this.fnAtom(p, null); + this.add(this.infoOfAtom(fa)!.thisNode, atom); + value = this.constNode(fa); + } else continue; + if (key !== null) this.edge(value, this.field(atom, key)); + else this.edge(value, this.anyField(atom)); + } + if (!this.siteAtoms.has(atom) && this.siteAtoms.add(atom)) + this.sites.push({ + atom, + node: e, + kind: "object", + keys: keysKnown ? keys : null, + hasAccessor, + hasProto, + hasComputedKey, + spreads, + inPackage, + }); + return n; + } + + /** Values written under unknown keys. */ + anyField(atom: Atom): number { + return this.field(atom, "*"); + } + + copyFields(src: number, dstAtom: Atom, site: Node): void { + this.on(src, (a) => { + if (a.kind === "top") { + this.edge(this.constNode(this.top), this.anyField(dstAtom)); + return; + } + if (a.kind === "prim" || a.kind === "builtin") return; + if (a.kind === "array") { + this.edge(this.element(a), this.anyField(dstAtom)); + return; + } + // Copy every own field the source has, now and later. + const fm = this.fields.get(a); + const copied = new Set(); + const copy = (): void => { + for (const [name, id] of this.fields.get(a) ?? new Map()) { + if (copied.has(name)) continue; + copied.add(name); + this.edge(id, this.field(dstAtom, name)); + } + }; + copy(); + if (fm === undefined) this.fields.set(a, new Map()); + this.lateCopies.push(copy); + if (a.kind === "instance" || a.kind === "dictionary" || a.kind === "collection") + this.edge(this.constNode(this.top), this.anyField(dstAtom)); + void site; + }); + } + + /** Field copies re-run after solving rounds (fields created later). */ + private readonly lateCopies: (() => void)[] = []; + + arrayLiteral(e: ts.ArrayLiteralExpression): number { + const atom = this.atoms.intern(`arr:${this.nodeKey(e)}`, () => ({ + kind: "array", + label: `[]@${locLabel(e)}`, + node: e, + })); + const n = this.newNode(); + this.add(n, atom); + const el = this.element(atom); + let hasHole = false; + for (const item of list(e.elements)) { + if (ts.isOmittedExpression(item)) { + hasHole = true; + continue; + } + if (ts.isSpreadElement(item)) this.iterateInto(this.expr(item.expression), el, item); + else this.edge(this.expr(item), el); + } + if (!this.siteAtoms.has(atom) && this.siteAtoms.add(atom)) + this.sites.push({ + atom, + node: e, + kind: "array", + keys: null, + hasAccessor: false, + hasProto: hasHole, + hasComputedKey: false, + spreads: [], + inPackage: isPackageJsFile(e.getSourceFile()), + }); + return n; + } + + binary(e: ts.BinaryExpression): number { + const op = e.operatorToken.kind; + if (op === ts.SyntaxKind.EqualsToken) { + const value = this.expr(e.right); + this.assignTo(e.left, value); + return value; + } + if ( + op === ts.SyntaxKind.BarBarEqualsToken || + op === ts.SyntaxKind.QuestionQuestionEqualsToken || + op === ts.SyntaxKind.AmpersandAmpersandEqualsToken + ) { + const n = this.newNode(); + this.edge(this.expr(e.left), n); + const value = this.expr(e.right); + this.edge(value, n); + this.assignTo(e.left, value); + return n; + } + if (op >= ts.SyntaxKind.FirstCompoundAssignment && op <= ts.SyntaxKind.LastCompoundAssignment) { + this.expr(e.left); + this.expr(e.right); + const result = this.constNode( + op === ts.SyntaxKind.PlusEqualsToken ? this.top : this.prim("number"), + ); + if (op === ts.SyntaxKind.PlusEqualsToken) { + this.nodes[result]!.atoms.clear(); + this.add(result, this.prim("string")); + this.add(result, this.prim("number")); + } + this.assignTo(e.left, result); + return result; + } + if ( + op === ts.SyntaxKind.BarBarToken || + op === ts.SyntaxKind.QuestionQuestionToken || + op === ts.SyntaxKind.AmpersandAmpersandToken + ) { + const n = this.newNode(); + this.edge(this.expr(e.left), n); + this.edge(this.expr(e.right), n); + return n; + } + if (op === ts.SyntaxKind.CommaToken) { + this.expr(e.left); + return this.expr(e.right); + } + const l = this.expr(e.left); + const r = this.expr(e.right); + switch (op) { + case ts.SyntaxKind.EqualsEqualsEqualsToken: + case ts.SyntaxKind.ExclamationEqualsEqualsToken: + case ts.SyntaxKind.EqualsEqualsToken: + case ts.SyntaxKind.ExclamationEqualsToken: + case ts.SyntaxKind.LessThanToken: + case ts.SyntaxKind.LessThanEqualsToken: + case ts.SyntaxKind.GreaterThanToken: + case ts.SyntaxKind.GreaterThanEqualsToken: + case ts.SyntaxKind.InstanceOfKeyword: + case ts.SyntaxKind.InKeyword: + if (op === ts.SyntaxKind.InKeyword) + this.ops.push({ kind: "computedRead", recv: r, name: null, node: e }); + return this.constNode(this.prim("boolean")); + case ts.SyntaxKind.PlusToken: { + const n = this.newNode(); + const strOrNum = (a: Atom): void => { + this.add( + n, + a.kind === "prim" && a.label === "number" ? this.prim("number") : this.prim("string"), + ); + if ( + a.kind === "prim" && + (a.label === "boolean" || a.label === "null" || a.label === "undefined") + ) + this.add(n, this.prim("number")); + if (a.kind === "top") this.add(n, this.prim("number")); + }; + this.on(l, strOrNum); + this.on(r, strOrNum); + return n; + } + default: + return this.constNode(this.prim("number")); + } + } + + assignTo(target: ts.Expression, value: number): void { + const t = unparen(target); + if (ts.isIdentifier(t)) { + const decl = this.resolve(t); + if (decl === undefined || decl.getSourceFile().isDeclarationFile) { + this.sink(value, `global write at ${locLabel(t)}`); + return; + } + this.edge(value, this.binding(decl)); + return; + } + if (ts.isPropertyAccessExpression(t)) { + const recv = this.expr(t.expression); + this.storeConstraint(recv, t.name.text, value, t); + this.ops.push({ + kind: t.name.text === "length" ? "lengthWrite" : "write", + recv, + name: t.name.text, + node: t, + }); + return; + } + if (ts.isElementAccessExpression(t)) { + const recv = this.expr(t.expression); + const key = unparen(t.argumentExpression); + if (ts.isStringLiteral(key) || ts.isNoSubstitutionTemplateLiteral(key)) { + this.storeConstraint(recv, key.text, value, t); + this.ops.push({ kind: "write", recv, name: key.text, node: t }); + } else { + this.expr(t.argumentExpression); + this.computedStore(recv, value, t); + this.ops.push({ kind: "computedWrite", recv, name: null, node: t }); + } + return; + } + if (ts.isObjectLiteralExpression(t)) { + for (const p of list(t.properties)) { + if (ts.isPropertyAssignment(p)) { + const key = propertyNameText(p.name); + const n = this.newNode(); + if (key !== null) this.loadConstraint(value, key, n, p); + else this.add(n, this.top); + this.assignTo(p.initializer, n); + } else if (ts.isShorthandPropertyAssignment(p)) { + const n = this.newNode(); + const id = p.name as ts.Identifier; + this.loadConstraint(value, id.text, n, p); + this.assignTo(id, n); + } + } + return; + } + if (ts.isArrayLiteralExpression(t)) { + for (const el of list(t.elements)) { + if (ts.isOmittedExpression(el)) continue; + const n = this.newNode(); + this.iterateInto(value, n, el); + this.assignTo(ts.isSpreadElement(el) ? el.expression : el, n); + } + } + } + + // ---- loads and stores ------------------------------------------------------------ + + loadConstraint(recv: number, name: string, dst: number, site: Node): void { + this.on(recv, (a) => this.loadAtom(a, name, dst, site)); + } + + loadAtom(a: Atom, name: string, dst: number, site: Node): void { + switch (a.kind) { + case "top": + this.add(dst, this.top); + return; + case "prim": + if (name === "length" && a.label === "string") this.add(dst, this.prim("number")); + else if (a.label === "string" || a.label === "number" || a.label === "boolean") + this.add(dst, this.builtin(`${a.label}.${name}`, a)); + return; + case "instance": { + const decl = a.node!; + if (name === "constructor") { + this.add(dst, this.classAtoms(decl).cls); + return; + } + const member = this.lookupMember(decl, name, false); + if (member?.kind === "method") + this.add( + dst, + this.fnAtom(member.method!, this.ownerOf(member.method!), this.receiverCtx(a)), + ); + if (member !== null && member.get !== undefined) { + const g = this.functionInfo(member.get, this.ownerOf(member.get), this.receiverCtx(a)); + this.activate(g); + this.add(g.thisNode, a); + this.edge(g.ret, dst); + this.edgeFor(site, g); + return; + } + if (this.classChain(decl).some((c) => this.baseClass(c) === undefined)) + this.add(dst, this.top); + this.edge(this.field(a, name), dst); + return; + } + case "class": { + const decl = a.node!; + if (name === "prototype") { + this.add(dst, this.top); + return; + } + if (name === "name") { + this.add(dst, this.prim("string")); + return; + } + const member = this.lookupMember(decl, name, true); + if (member?.kind === "method") + this.add( + dst, + this.fnAtom(member.method!, this.ownerOf(member.method!), this.receiverCtx(a)), + ); + if (member?.get !== undefined) { + const g = this.functionInfo(member.get, this.ownerOf(member.get), this.receiverCtx(a)); + this.activate(g); + this.add(g.thisNode, a); + this.edge(g.ret, dst); + return; + } + // static fields of the class and its bases + for (const c of this.classChain(decl)) { + const cls = this.classAtoms(c).cls; + this.edge(this.field(cls, name), dst); + } + return; + } + case "function": + if (name === "call" || name === "apply" || name === "bind") + this.add(dst, this.builtin(`function.${name}`, a)); + else if (name === "prototype") this.add(dst, this.top); + else if (name === "name") this.add(dst, this.prim("string")); + else if (name === "length") this.add(dst, this.prim("number")); + else this.edge(this.field(a, name), dst); + return; + case "array": + if (name === "length") this.add(dst, this.prim("number")); + else if (/^\d+$/.test(name)) this.edge(this.element(a), dst); + else if (ARRAY_METHODS.has(name)) this.add(dst, this.builtin(`array.${name}`, a)); + else this.edge(this.field(a, name), dst); + return; + case "object": + this.edge(this.field(a, name), dst); + this.edge(this.anyField(a), dst); + if (name === "constructor" || name === "hasOwnProperty" || name === "toString") + this.add(dst, this.builtin(`object.${name}`, a)); + return; + case "dictionary": + this.edge(this.anyField(a), dst); + this.edge(this.field(a, name), dst); + return; + case "promise": + if (name === "then" || name === "catch" || name === "finally") + this.add(dst, this.builtin(`promise.${name}`, a)); + return; + case "collection": + if (name === "size") this.add(dst, this.prim("number")); + else this.add(dst, this.builtin(`collection.${name}`, a)); + return; + case "builtin": + this.loadBuiltin(a, name, dst); + return; + } + void site; + } + + ownerOf(member: Node): Node | null { + const p = member.parent; + return p !== undefined && ts.isClassLikeDeclaration(p) ? p : null; + } + + loadBuiltin(a: Atom, name: string, dst: number): void { + const path = a.path ?? ""; + if ( + path === "Number" && + (name === "MAX_SAFE_INTEGER" || + name === "MIN_SAFE_INTEGER" || + name === "EPSILON" || + name === "MAX_VALUE" || + name === "MIN_VALUE" || + name === "POSITIVE_INFINITY" || + name === "NEGATIVE_INFINITY" || + name === "NaN") + ) + this.add(dst, this.prim("number")); + else if (path === "Math" && /^[A-Z0-9_]+$/.test(name)) this.add(dst, this.prim("number")); + else if (path === "Symbol") this.add(dst, this.prim("symbol")); + else if (path === "Error.instance" || path === "error") { + if (name === "message" || name === "stack" || name === "name") + this.add(dst, this.prim("string")); + else this.add(dst, this.top); + } else if ( + a.receiver === undefined && + MODELED_GLOBALS.has(path.split(".")[0]!) && + path.split(".").length < 4 + ) + this.add(dst, this.builtin(`${path}.${name}`)); + else if (path === "RegExp.instance") this.add(dst, this.builtin(`regexp.${name}`, a)); + else this.add(dst, this.top); + } + + storeConstraint(recv: number, name: string, value: number, site: Node): void { + this.on(recv, (a) => { + switch (a.kind) { + case "top": + this.noteTopWrite(name, site); + this.sink(value, `stored into ⊤.${name} at ${locLabel(site)}`); + return; + case "instance": { + const member = this.lookupMember(a.node!, name, false); + if (member?.set !== undefined) { + const s = this.functionInfo(member.set, this.ownerOf(member.set), this.receiverCtx(a)); + this.activate(s); + this.add(s.thisNode, a); + if (s.params[0] !== undefined) this.edge(value, s.params[0]); + return; + } + this.edge(value, this.field(a, name)); + return; + } + case "class": + case "function": + case "object": + case "dictionary": + this.edge(value, this.field(a, name)); + return; + case "array": + if (/^\d+$/.test(name)) this.edge(value, this.element(a)); + return; + case "prim": + return; + default: + this.sink(value, `stored into ${a.label} at ${locLabel(site)}`); + } + }); + } + + computedLoad(recv: number, dst: number, site: Node): void { + this.on(recv, (a) => { + switch (a.kind) { + case "top": + this.add(dst, this.top); + return; + case "array": + case "collection": + this.edge(this.element(a), dst); + return; + case "prim": + if (a.label === "string") this.add(dst, this.prim("string")); + return; + case "object": + case "dictionary": + case "instance": + case "class": + case "function": { + // every field, now and later + const seen = new Set(); + const copy = (): void => { + for (const [name, id] of this.fields.get(a) ?? new Map()) { + if (seen.has(name)) continue; + seen.add(name); + this.edge(id, dst); + } + }; + copy(); + this.lateCopies.push(copy); + if (a.kind === "instance" || a.kind === "class") this.add(dst, this.top); + return; + } + default: + this.add(dst, this.top); + } + void site; + }); + } + + computedStore(recv: number, value: number, site: Node): void { + this.on(recv, (a) => { + switch (a.kind) { + case "top": + this.noteTopWrite(null, site); + this.sink(value, `stored into ⊤[k] at ${locLabel(site)}`); + return; + case "array": + this.edge(value, this.element(a)); + return; + case "prim": + return; + default: + this.edge(value, this.anyField(a)); + } + }); + } + + // ---- calls --------------------------------------------------------------------------- + + args(e: ts.CallExpression | ts.NewExpression): { args: number[]; spread: boolean } { + const out: number[] = []; + let spread = false; + for (const a of list(e.arguments)) { + if (ts.isSpreadElement(a)) { + const inner = unparen(a.expression); + if (ts.isIdentifier(inner) && inner.text === "arguments") { + // `f(...arguments)`: forward the enclosing function's parameters. + const fn = this.enclosingNonArrow(); + if (fn !== null && out.length === 0) { + if (fn.argPos === null) fn.argPos = [0, 1, 2, 3, 4, 5].map(() => this.newNode()); + out.push(...fn.argPos); + continue; + } + } + spread = true; + out.push(this.expr(a.expression)); + continue; + } + out.push(this.expr(a)); + } + return { args: out, spread }; + } + + call(e: ts.CallExpression): number { + this.noteSite(e); + const callee = unparen(e.expression); + const dst = this.newNode(); + if (callee.kind === ts.SyntaxKind.SuperKeyword) { + const { args, spread } = this.args(e); + const fn = this.enclosingNonArrow(); + const owner = fn?.ownerClass ?? null; + const base = owner !== null ? this.baseClass(owner) : undefined; + if (fn !== null && base) { + this.on(fn.thisNode, (inst) => { + if (inst.kind === "instance") this.callConstructorChain(base, inst, args, spread, e); + }); + } else if (base === undefined) + for (const a of args) this.sink(a, `super(...) at ${locLabel(e)}`); + return dst; + } + if (ts.isPropertyAccessExpression(callee) || ts.isElementAccessExpression(callee)) { + const recvExpr = unparen(callee.expression); + const { args, spread } = this.args(e); + if (recvExpr.kind === ts.SyntaxKind.SuperKeyword && ts.isPropertyAccessExpression(callee)) { + // super.m(...): the base class member with the current receiver. + const fn = this.enclosingNonArrow(); + const owner = fn?.ownerClass ?? null; + const base = owner !== null ? this.baseClass(owner) : undefined; + if (fn !== null && base) { + const member = this.lookupMember(base, callee.name.text, isStatic(fn.node)); + if (member?.method !== undefined) { + this.callFunction( + this.functionInfo(member.method, this.ownerOf(member.method), fn.ctx), + fn.thisNode, + args, + spread, + dst, + e, + ); + } + } + return dst; + } + const recv = this.expr(recvExpr); + let name: string | null = null; + if (ts.isPropertyAccessExpression(callee)) name = callee.name.text; + else { + const k = unparen(callee.argumentExpression); + if (ts.isStringLiteral(k) || ts.isNoSubstitutionTemplateLiteral(k)) name = k.text; + else this.expr(callee.argumentExpression); + } + if (name !== null) this.ops.push({ kind: "read", recv, name, node: callee }); + // Per receiver atom: the member it resolves to runs with that atom as `this`. + const member = name; + this.on(recv, (a) => { + const fnNode = this.newNode(); + const self = this.constNode(a); + if (member !== null) this.loadAtom(a, member, fnNode, callee); + else this.computedLoad(self, fnNode, callee); + this.invoke(fnNode, self, args, spread, dst, e); + }); + return dst; + } + const calleeNode = this.expr(callee); + const { args, spread } = this.args(e); + this.invoke(calleeNode, null, args, spread, dst, e); + return dst; + } + + invoke( + callee: number, + recv: number | null, + args: number[], + spread: boolean, + dst: number, + site: ts.CallExpression, + ): void { + const undefNode = recv === null ? this.constNode(this.prim("undefined")) : recv; + this.on(callee, (a) => { + switch (a.kind) { + case "function": + this.callFunction(this.infoOfAtom(a)!, undefNode, args, spread, dst, site); + return; + case "builtin": + this.callBuiltin(a, args, spread, dst, site, recv); + return; + case "class": + return; // calling a class throws + case "prim": + return; + default: + for (const x of args) this.sink(x, `argument of ⊤ call at ${locLabel(site)}`); + if (recv !== null && a.kind === "top") + this.sink(recv, `receiver of ⊤ call at ${locLabel(site)}`); + this.add(dst, this.top); + } + }); + } + + newExpr(e: ts.NewExpression): number { + this.noteSite(e); + const dst = this.newNode(); + const callee = this.expr(e.expression); + const { args, spread } = this.args(e); + this.on(callee, (a) => { + switch (a.kind) { + case "class": + this.construct(a.node!, args, spread, dst, e); + return; + case "function": { + // An ES5 constructor function: one instance atom per function. + const inst = this.atoms.intern(`fninst:${this.nodeKey(a.node!)}`, () => ({ + kind: "object", + label: `new ${a.label}`, + node: a.node, + })); + this.add(dst, inst); + const info = this.infoOfAtom(a); + if (info !== undefined) { + this.activate(info); + this.add(info.thisNode, inst); + this.bindArgs(info, args, spread); + this.edge(info.ret, dst); + } + return; + } + case "builtin": + this.constructBuiltin(a.path ?? "", args, dst, e); + return; + default: + for (const x of args) this.sink(x, `argument of ⊤ constructor at ${locLabel(e)}`); + this.add(dst, this.top); + } + }); + return dst; + } + + constructBuiltin(path: string, args: number[], dst: number, site: Node): void { + switch (path) { + case "Map": + case "Set": + case "WeakMap": + case "WeakSet": { + const c = this.atoms.intern(`coll:${this.nodeKey(site)}`, () => ({ + kind: "collection", + label: `${path}@${locLabel(site)}`, + node: site, + })); + this.add(dst, c); + if (args[0] !== undefined) this.iterateInto(args[0], this.element(c), site); + return; + } + case "Error": + case "TypeError": + case "RangeError": + case "SyntaxError": + this.add(dst, this.builtin("Error.instance")); + return; + case "Promise": { + const p = this.promiseAtom(site, locLabel(site)); + this.add(this.field(p, "value"), this.top); + this.add(dst, p); + if (args[0] !== undefined) { + const resolver = this.constNode(this.builtin("promise.resolver")); + this.on(args[0], (f) => { + if (f.kind === "function") + this.callFunction( + this.infoOfAtom(f)!, + null, + [resolver, resolver], + false, + this.newNode(), + site, + ); + }); + } + return; + } + case "Date": + this.add(dst, this.builtin("Date.instance")); + return; + case "RegExp": + this.add(dst, this.builtin("RegExp.instance")); + return; + case "Array": { + this.add(dst, this.syntheticArray(site, "Array")); + return; + } + default: + for (const x of args) this.sink(x, `argument of new ${path} at ${locLabel(site)}`); + this.add(dst, this.top); + } + } + + /** Builtin call summaries; anything unmodeled makes its arguments escape. */ + callBuiltin( + a: Atom, + args: number[], + spread: boolean, + dst: number, + site: ts.CallExpression, + recvNode: number | null, + ): void { + const path = a.path ?? ""; + const recv = a.receiver; + const arg = (i: number): number => args[i] ?? this.constNode(this.prim("undefined")); + const prim = (p: string): void => this.add(dst, this.prim(p)); + const callback = (i: number, cbArgs: number[], ret: number | null): void => { + if (args[i] === undefined) return; + this.on(args[i]!, (f) => { + if (f.kind === "function") { + const saved = this.forceLoop; + this.forceLoop = LOOP_CALLBACK_METHODS.has(path.slice(path.indexOf(".") + 1)); + this.callFunction(this.infoOfAtom(f)!, null, cbArgs, false, ret ?? this.newNode(), site); + this.forceLoop = saved; + } else if (f.kind === "top" || f.kind === "builtin") { + for (const x of cbArgs) this.sink(x, `argument of ⊤ callback at ${locLabel(site)}`); + if (ret !== null) this.add(ret, this.top); + } + }); + }; + const escapeAll = (): void => { + for (const x of args) this.sink(x, `argument of ${path} at ${locLabel(site)}`); + this.add(dst, this.top); + }; + // Methods of builtin receivers. + if (recv !== undefined) { + const method = path.slice(path.indexOf(".") + 1); + if (path.startsWith("array.")) { + const el = this.element(recv); + const num = this.constNode(this.prim("number")); + const recvN = this.constNode(recv); + switch (method) { + case "push": + case "unshift": + for (const x of args) { + if (spread) this.iterateInto(x, el, site); + else this.edge(x, el); + } + prim("number"); + return; + case "pop": + case "shift": + case "at": + this.edge(el, dst); + this.add(dst, this.prim("undefined")); + return; + case "find": + case "findLast": + callback(0, [el, num, recvN], null); + this.edge(el, dst); + this.add(dst, this.prim("undefined")); + return; + case "forEach": + callback(0, [el, num, recvN], null); + prim("undefined"); + return; + case "some": + case "every": + case "includes": + callback(0, [el, num, recvN], null); + prim("boolean"); + return; + case "findIndex": + case "findLastIndex": + case "indexOf": + case "lastIndexOf": + callback(0, [el, num, recvN], null); + prim("number"); + return; + case "join": + case "toString": + prim("string"); + return; + case "map": + case "flatMap": { + const out = this.syntheticArray(site, method); + const outEl = this.element(out); + if (method === "map") callback(0, [el, num, recvN], outEl); + else { + const r = this.newNode(); + callback(0, [el, num, recvN], r); + this.iterateInto(r, outEl, site); + } + this.add(dst, out); + return; + } + case "filter": + case "slice": + case "concat": + case "reverse": + case "sort": + case "splice": + case "toSorted": + case "toReversed": + case "flat": { + if (method === "filter") callback(0, [el, num, recvN], null); + if (method === "sort" || method === "toSorted") callback(0, [el, el], null); + if (method === "reverse" || method === "sort") { + this.add(dst, recv); + return; + } + const out = this.syntheticArray(site, method); + this.edge(el, this.element(out)); + if (method === "concat") + for (const x of args) this.iterateInto(x, this.element(out), site); + if (method === "splice") for (const x of args.slice(2)) this.edge(x, el); + this.add(dst, out); + return; + } + case "reduce": + case "reduceRight": { + const acc = this.newNode(); + if (args[1] !== undefined) this.edge(args[1], acc); + else this.edge(el, acc); + callback(0, [acc, el, num, recvN], acc); + this.edge(acc, dst); + return; + } + case "keys": + case "values": + case "entries": { + const out = this.syntheticArray(site, method); + if (method === "values") this.edge(el, this.element(out)); + else if (method === "keys") this.add(this.element(out), this.prim("number")); + else { + const pair = this.syntheticArray(site, "entry"); + this.add(this.element(pair), this.prim("number")); + this.edge(el, this.element(pair)); + this.add(this.element(out), pair); + } + this.add(dst, out); + return; + } + case "fill": + for (const x of args) this.edge(x, el); + this.add(dst, recv); + return; + } + escapeAll(); + this.escape(recv, `array.${method} at ${locLabel(site)}`); + return; + } + if (path.startsWith("string.") || path.startsWith("number.") || path.startsWith("boolean.")) { + const r = STRING_METHOD_RESULTS.get(method); + if (r === "array") { + const out = this.syntheticArray(site, method); + this.add(this.element(out), this.prim("string")); + this.add(this.element(out), this.prim("undefined")); + this.add(dst, out); + this.add(dst, this.prim("null")); + } else if (r !== undefined) prim(r); + else if (method === "replace" || method === "replaceAll") prim("string"); + else escapeAll(); + if (method === "replace" || method === "replaceAll") + callback(1, [this.constNode(this.prim("string"))], null); + return; + } + if (path.startsWith("regexp.")) { + if (method === "test") prim("boolean"); + else if (method === "exec") { + const out = this.syntheticArray(site, "exec"); + this.add(this.element(out), this.prim("string")); + this.add(dst, out); + prim("null"); + } else escapeAll(); + return; + } + if (path.startsWith("promise.")) { + const out = this.promiseAtom(site, locLabel(site)); + const value = this.field(recv, "value"); + const ret = this.newNode(); + if (method === "then") { + callback(0, [value], ret); + callback(1, [this.constNode(this.top)], ret); + } else if (method === "catch") { + callback(0, [this.constNode(this.top)], ret); + this.edge(value, ret); + } else { + callback(0, [], null); + this.edge(value, ret); + } + this.awaitInto(ret, this.field(out, "value")); + this.add(dst, out); + return; + } + if (path.startsWith("collection.")) { + const el = this.element(recv); + switch (method) { + case "add": + case "set": + for (const x of args) this.edge(x, el); + this.add(dst, recv); + return; + case "get": + this.edge(el, dst); + prim("undefined"); + return; + case "has": + case "delete": + prim("boolean"); + return; + case "clear": + prim("undefined"); + return; + case "forEach": + callback(0, [el, el], null); + prim("undefined"); + return; + case "keys": + case "values": + case "entries": { + const out = this.syntheticArray(site, method); + this.edge(el, this.element(out)); + if (method === "entries") { + const pair = this.syntheticArray(site, "entry"); + this.edge(el, this.element(pair)); + this.nodes[this.element(out)]!.atoms.clear(); + this.add(this.element(out), pair); + } + this.add(dst, out); + return; + } + } + escapeAll(); + return; + } + if (path.startsWith("function.")) { + if (recv.kind !== "function" || recv.node === undefined) { + escapeAll(); + return; + } + if (method === "bind") { + const info = this.infoOfAtom(recv); + if (info !== undefined && args[0] !== undefined && !info.isArrow) + this.edge(args[0], info.thisNode); + if (info !== undefined && args.length > 1) { + this.activate(info); + for (const p of info.params) this.add(p, this.top); + for (const x of args.slice(1)) this.sink(x, `bound argument at ${locLabel(site)}`); + } + this.add(dst, recv); + return; + } + if (method === "call") { + this.callFunction( + this.infoOfAtom(recv)!, + args[0] ?? this.constNode(this.prim("undefined")), + args.slice(1), + spread, + dst, + site, + ); + return; + } + // apply: arguments from an array + const info = this.infoOfAtom(recv); + if (info !== undefined) { + this.activate(info); + if (args[0] !== undefined && !info.isArrow) this.edge(args[0], info.thisNode); + for (const p of info.params) + if (args[1] !== undefined) this.iterateInto(args[1], p, site); + this.edge(info.ret, dst); + } + return; + } + if (path.startsWith("object.")) { + if (method === "hasOwnProperty") prim("boolean"); + else if (method === "toString") prim("string"); + else escapeAll(); + return; + } + escapeAll(); + return; + } + // `Object.prototype.m.call(o, …)`-style calls of builtin prototype methods. + if (/^(Object|Array|String|Function)\.prototype\.\w+\.(call|apply)$/.test(path)) { + const m = path.split(".")[2]!; + if (m === "hasOwnProperty" || m === "propertyIsEnumerable" || m === "isPrototypeOf") + prim("boolean"); + else if (m === "toString") prim("string"); + else escapeAll(); + return; + } + switch (path) { + case "Object.keys": + case "Object.getOwnPropertyNames": { + const out = this.syntheticArray(site, "keys"); + this.add(this.element(out), this.prim("string")); + this.add(dst, out); + return; + } + case "Object.values": + case "Object.entries": { + const out = this.syntheticArray(site, path === "Object.values" ? "values" : "entries"); + const vals = this.newNode(); + if (args[0] !== undefined) this.computedLoad(args[0], vals, site); + if (path === "Object.values") this.edge(vals, this.element(out)); + else { + const pair = this.syntheticArray(site, "entry"); + this.add(this.element(pair), this.prim("string")); + this.edge(vals, this.element(pair)); + this.add(this.element(out), pair); + } + this.add(dst, out); + return; + } + case "Object.freeze": + case "Object.seal": + case "Object.preventExtensions": + this.ops.push({ + kind: path === "Object.freeze" ? "freeze" : "seal", + recv: arg(0), + name: null, + node: site, + }); + this.edge(arg(0), dst); + return; + case "Object.isFrozen": + case "Object.isSealed": + case "Object.isExtensible": + case "Array.isArray": + case "Number.isInteger": + case "Number.isNaN": + case "Number.isFinite": + case "Number.isSafeInteger": + case "isNaN": + case "isFinite": + prim("boolean"); + return; + case "Object.assign": { + this.ops.push({ kind: "assign", recv: arg(0), name: null, node: site }); + this.on(arg(0), (t) => { + for (const s of args.slice(1)) this.copyFields(s, t, site); + if (t.kind === "top") + for (const s of args.slice(1)) + this.sink(s, `Object.assign into ⊤ at ${locLabel(site)}`); + }); + this.edge(arg(0), dst); + return; + } + case "Object.defineProperty": + case "Object.defineProperties": + case "Reflect.defineProperty": + this.ops.push({ kind: "defineProperty", recv: arg(0), name: null, node: site }); + this.sink(arg(2), `property descriptor at ${locLabel(site)}`); + this.sink(arg(1), `property descriptor at ${locLabel(site)}`); + this.edge(arg(0), dst); + return; + case "Object.setPrototypeOf": + case "Reflect.setPrototypeOf": + this.ops.push({ kind: "setPrototypeOf", recv: arg(0), name: null, node: site }); + this.sink(arg(1), `prototype at ${locLabel(site)}`); + this.edge(arg(0), dst); + return; + case "Object.create": { + const d = this.atoms.intern(`dict:${this.nodeKey(site)}`, () => ({ + kind: "dictionary", + label: `Object.create@${locLabel(site)}`, + node: site, + })); + this.add(dst, d); + return; + } + case "Object.fromEntries": { + const d = this.atoms.intern(`dict:${this.nodeKey(site)}`, () => ({ + kind: "dictionary", + label: `fromEntries@${locLabel(site)}`, + node: site, + })); + const pairs = this.newNode(); + if (args[0] !== undefined) this.iterateInto(args[0], pairs, site); + const vals = this.newNode(); + this.iterateInto(pairs, vals, site); + this.edge(vals, this.anyField(d)); + this.add(dst, d); + return; + } + case "Object.getPrototypeOf": + case "Reflect.getPrototypeOf": + this.add(dst, this.top); + return; + case "Object.is": + prim("boolean"); + return; + case "Array.from": + case "Array.of": { + const out = this.syntheticArray(site, path); + if (path === "Array.of") for (const x of args) this.edge(x, this.element(out)); + else if (args[1] !== undefined) { + const els = this.newNode(); + if (args[0] !== undefined) this.iterateInto(args[0], els, site); + callback(1, [els, this.constNode(this.prim("number"))], this.element(out)); + } else if (args[0] !== undefined) this.iterateInto(args[0], this.element(out), site); + this.add(dst, out); + return; + } + case "JSON.parse": + this.add(dst, this.top); + return; + case "JSON.stringify": + prim("string"); + prim("undefined"); + return; + case "String": + case "encodeURIComponent": + case "decodeURIComponent": + case "encodeURI": + case "decodeURI": + prim("string"); + return; + case "Number": + case "parseInt": + case "parseFloat": + case "Number.parseInt": + case "Number.parseFloat": + prim("number"); + return; + case "Boolean": + prim("boolean"); + return; + case "Symbol": + case "Symbol.for": + prim("symbol"); + return; + case "BigInt": + prim("bigint"); + return; + case "Promise.resolve": { + const p = this.promiseAtom(site, locLabel(site)); + if (args[0] !== undefined) this.awaitInto(args[0], this.field(p, "value")); + else this.add(this.field(p, "value"), this.prim("undefined")); + this.add(dst, p); + return; + } + case "Promise.reject": { + const p = this.promiseAtom(site, locLabel(site)); + this.add(dst, p); + if (args[0] !== undefined) this.sink(args[0], `rejection at ${locLabel(site)}`); + return; + } + case "Promise.all": + case "Promise.allSettled": + case "Promise.race": + case "Promise.any": { + const p = this.promiseAtom(site, locLabel(site)); + const items = this.newNode(); + if (args[0] !== undefined) this.iterateInto(args[0], items, site); + if (path === "Promise.all") { + const out = this.syntheticArray(site, "all"); + this.awaitInto(items, this.element(out)); + this.add(this.field(p, "value"), out); + } else if (path === "Promise.race" || path === "Promise.any") + this.awaitInto(items, this.field(p, "value")); + else this.add(this.field(p, "value"), this.top); + this.add(dst, p); + return; + } + case "promise.resolver": + for (const x of args) this.sink(x, `promise resolution at ${locLabel(site)}`); + return; + } + if (path.startsWith("console.")) { + prim("undefined"); + return; + } + if (path.startsWith("Math.")) { + prim("number"); + return; + } + if (path === "Date.now") { + prim("number"); + return; + } + if (path.startsWith("Date.instance") || path === "Error.instance") { + escapeAll(); + return; + } + void recvNode; + escapeAll(); + } + + /** Re-run deferred field copies until nothing new flows. */ + finish(): void { + for (;;) { + const before = this.steps; + for (const c of this.lateCopies) c(); + this.solve(); + if (this.steps === before || this.budgetExceeded) return; + } + } +} diff --git a/packages/compiler/src/frontend/shape-inference/domain.ts b/packages/compiler/src/frontend/shape-inference/domain.ts new file mode 100644 index 000000000..36978d4c9 --- /dev/null +++ b/packages/compiler/src/frontend/shape-inference/domain.ts @@ -0,0 +1,153 @@ +/* Shape inference (results/design-shape-inference/DESIGN.md), stage S1: + * the abstract domain of the allocation-site points-to analysis. + * + * An abstract value is a set of atoms. An atom names a set of runtime + * values: a primitive kind, an allocation site (object or array literal, or + * a value a builtin creates at one call site), the instances of one class, + * one class value, one function (closure site), a builtin object, or ⊤ — + * every value the analysis does not track. Value nodes hold atom sets and + * flow into each other along inclusion edges; the solver (analyze.ts) + * attaches load, store and call constraints that fire as atoms arrive. */ +import type * as ts from "../ts7/adapter.js"; + +export type AtomKind = + | "prim" + | "top" + | "object" + | "array" + | "instance" + | "class" + | "function" + | "builtin" + | "promise" + | "collection" + | "dictionary"; + +export interface Atom { + readonly id: number; + readonly kind: AtomKind; + /** Short display name, e.g. `string`, `ZodString`, `{status,value}@types.js:804`. */ + readonly label: string; + /** The syntax that creates the atom: the literal, class or function + * declaration, or the builtin call. Undefined for prims, ⊤ and builtins. */ + readonly node?: ts.Node | undefined; + /** builtin atoms: the dotted path (`Object.keys`, `array.push`). */ + readonly path?: string | undefined; + /** method atoms of builtin receivers: the receiver atom. */ + readonly receiver?: Atom | undefined; + /** function atoms: the analysis context of the function's clone (a + * method's receiver class), "" for the context-insensitive default. */ + readonly ctx?: string | undefined; +} + +export class AtomTable { + readonly atoms: Atom[] = []; + private readonly byKey = new Map(); + + intern(key: string, make: (id: number) => Omit): Atom { + let atom = this.byKey.get(key); + if (atom === undefined) { + const id = this.atoms.length; + atom = { id, ...make(id) }; + this.atoms.push(atom); + this.byKey.set(key, atom); + } + return atom; + } +} + +/** Object.prototype members: a read of one of these names on a plain + * object resolves on the prototype, never to an absent own key. */ +export const OBJECT_PROTOTYPE_MEMBERS: ReadonlySet = new Set([ + "constructor", + "hasOwnProperty", + "isPrototypeOf", + "propertyIsEnumerable", + "toLocaleString", + "toString", + "valueOf", + "__defineGetter__", + "__defineSetter__", + "__lookupGetter__", + "__lookupSetter__", + "__proto__", +]); + +/** Global names the analysis models as builtin objects. Any other global is ⊤. */ +export const MODELED_GLOBALS: ReadonlySet = new Set([ + "Object", + "Array", + "JSON", + "Math", + "Number", + "String", + "Boolean", + "Symbol", + "Promise", + "Map", + "Set", + "WeakMap", + "WeakSet", + "Error", + "TypeError", + "RangeError", + "SyntaxError", + "Date", + "RegExp", + "console", + "Reflect", + "parseInt", + "parseFloat", + "isNaN", + "isFinite", + "encodeURIComponent", + "decodeURIComponent", + "encodeURI", + "decodeURI", + "BigInt", +]); + +/** Results of string (and number) methods, by name. Anything else is ⊤. */ +type MethodResult = "string" | "number" | "boolean" | "array"; +export const STRING_METHOD_RESULTS: ReadonlyMap = new Map< + string, + MethodResult +>([ + ["at", "string"], + ["charAt", "string"], + ["charCodeAt", "number"], + ["codePointAt", "number"], + ["concat", "string"], + ["endsWith", "boolean"], + ["includes", "boolean"], + ["indexOf", "number"], + ["lastIndexOf", "number"], + ["localeCompare", "number"], + ["match", "array"], + ["matchAll", "array"], + ["normalize", "string"], + ["padEnd", "string"], + ["padStart", "string"], + ["repeat", "string"], + ["replace", "string"], + ["replaceAll", "string"], + ["search", "number"], + ["slice", "string"], + ["split", "array"], + ["startsWith", "boolean"], + ["substring", "string"], + ["substr", "string"], + ["toLowerCase", "string"], + ["toUpperCase", "string"], + ["toLocaleLowerCase", "string"], + ["toLocaleUpperCase", "string"], + ["toString", "string"], + ["trim", "string"], + ["trimEnd", "string"], + ["trimStart", "string"], + ["valueOf", "string"], + ["test", "boolean"], + ["toFixed", "string"], + ["toPrecision", "string"], + ["toExponential", "string"], +]); diff --git a/packages/compiler/src/frontend/shape-inference/index.ts b/packages/compiler/src/frontend/shape-inference/index.ts new file mode 100644 index 000000000..88c2100ee --- /dev/null +++ b/packages/compiler/src/frontend/shape-inference/index.ts @@ -0,0 +1,21 @@ +/* Shape inference for untyped npm JavaScript + * (results/design-shape-inference/DESIGN.md). Stage S1: report only. */ +import type * as ts from "../ts7/adapter.js"; +import { analyzeShapes } from "./analyze.js"; +import { buildShapeReport } from "./report.js"; + +export { analyzeShapes } from "./analyze.js"; +export { buildShapeReport } from "./report.js"; + +/** SCRIPTC_DEBUG_SHAPES: `1` reports package code in hot functions, + * `verbose` every package site, `all` user files too, any other value only + * files whose path contains it. Writes to stderr; changes nothing else. */ +export function reportShapes(program: ts.Program, filter: string): void { + const start = performance.now(); + const analysis = analyzeShapes(program, program.getTypeChecker()); + const report = buildShapeReport(analysis, filter); + const ms = (performance.now() - start).toFixed(0); + process.stderr.write( + `[shapes] ${ms} ms\n${report.lines.map((l) => `[shapes] ${l}`).join("\n")}\n`, + ); +} diff --git a/packages/compiler/src/frontend/shape-inference/report.ts b/packages/compiler/src/frontend/shape-inference/report.ts new file mode 100644 index 000000000..c18d9eb56 --- /dev/null +++ b/packages/compiler/src/frontend/shape-inference/report.ts @@ -0,0 +1,374 @@ +/* Shape inference stage S1: the plan the analysis would hand the lowering, + * as a report (DESIGN.md §4.5, §5.5). Nothing here changes compilation. + * + * Per allocation site of package code, the verdict: + * P local — a native record would be exact: no reflection, no added + * keys, no computed writes, and its objects never escape; + * P escaping — exact as a record behind identity-keeping capsules: it + * escapes, but the census leaves every later operation + * answerable (fields untyped code may write become dyn); + * G — keeps today's dynamic object, with the rule that decided. + * Plus class field types, the census, and the hot functions' value types. */ +import * as ts from "../ts7/adapter.js"; +import { OBJECT_PROTOTYPE_MEMBERS, type Atom } from "./domain.js"; +import { locLabel, type FunctionInfo, type LiteralSite, type ShapeAnalysis } from "./analyze.js"; + +export interface SiteVerdict { + readonly site: LiteralSite; + readonly label: string; + readonly verdict: "P-local" | "P-escaping" | "G"; + readonly reasons: string[]; + /** P-escaping: fields untyped code may write (they become dyn slots). */ + readonly writableByTop: string[]; + readonly freezable: boolean; + readonly brand: boolean; +} + +export interface ShapeReport { + readonly sites: SiteVerdict[]; + readonly hot: Set; + readonly lines: string[]; +} + +const MAX_ATOMS_SHOWN = 6; + +function fieldKeys(fields: ReadonlyMap | undefined): string[] { + return fields === undefined ? [] : [...fields.keys()]; +} + +function fieldEntries(fields: ReadonlyMap | undefined): [string, number][] { + return fields === undefined ? [] : [...fields.entries()]; +} + +export function describeValue(analysis: ShapeAnalysis, node: number): string { + const atoms = [...analysis.nodes[node]!.atoms]; + if (atoms.length === 0) return "∅"; + const labels = [...new Set(atoms.map((a) => a.label))]; + labels.sort((a, b) => (a === "⊤" ? 1 : b === "⊤" ? -1 : a.localeCompare(b))); + const shown = labels.slice(0, MAX_ATOMS_SHOWN).join(" | "); + if (labels.length <= MAX_ATOMS_SHOWN) return shown; + return `${shown} | +${labels.length - MAX_ATOMS_SHOWN}${labels.includes("⊤") ? " | ⊤" : ""}`; +} + +function atomsOf(analysis: ShapeAnalysis, node: number): Set { + return analysis.nodes[node]!.atoms; +} + +/** Functions reached from call sites in loops (or loop callbacks), and + * everything they call: the static hotness heuristic (DESIGN.md §8.1). */ +export function hotFunctions(analysis: ShapeAnalysis): Set { + const hot = new Set(); + const callees = new Map(); + const work: FunctionInfo[] = []; + for (const c of analysis.calls) { + let l = callees.get(c.caller); + if (l === undefined) callees.set(c.caller, (l = [])); + l.push(c.callee); + if (c.inLoop && !hot.has(c.callee)) { + hot.add(c.callee); + work.push(c.callee); + } + } + while (work.length > 0) { + const f = work.pop()!; + for (const g of callees.get(f) ?? []) { + if (!hot.has(g)) { + hot.add(g); + work.push(g); + } + } + } + return hot; +} + +export function buildShapeReport(analysis: ShapeAnalysis, filter: string): ShapeReport { + const lines: string[] = []; + const all = filter === "all" || filter === "verbose"; + const verbose = filter === "verbose"; + const fileFilter = filter !== "1" && !all ? filter : null; + const wanted = (n: ts.Node, inPackage: boolean): boolean => { + if (fileFilter !== null) return n.getSourceFile().fileName.includes(fileFilter); + return all || inPackage; + }; + + // Census facts: operations whose receiver may be ⊤ reach every escaped atom. + + // Index ops by the site atoms they can reach directly. + const byAtom = new Map(); + const topOps: typeof analysis.ops = []; + for (const o of analysis.ops) { + const atoms = atomsOf(analysis, o.recv); + for (const a of atoms) { + if (a.kind !== "object" && a.kind !== "array") continue; + let l = byAtom.get(a); + if (l === undefined) byAtom.set(a, (l = [])); + l.push(o); + } + if (atoms.has(analysis.top)) topOps.push(o); + } + + // Key-order groups: sites with the same key set and different orders need brands. + const orders = new Map>(); + for (const s of analysis.sites) { + if (s.kind !== "object" || s.keys === null) continue; + const set = [...s.keys].sort().join(","); + let o = orders.get(set); + if (o === undefined) orders.set(set, (o = new Set())); + o.add(s.keys.join(",")); + } + + const verdicts: SiteVerdict[] = []; + for (const s of analysis.sites) { + if (!s.inPackage && !all && fileFilter === null) continue; + const reasons: string[] = []; + const escapedWhy = analysis.escaped.get(s.atom); + const escapes = escapedWhy !== undefined; + if (s.hasAccessor) reasons.push("accessor in literal"); + if (s.hasProto) reasons.push(s.kind === "array" ? "hole in literal" : "__proto__ in literal"); + if (s.hasComputedKey) reasons.push("computed key in literal"); + for (const sp of s.spreads) + if (atomsOf(analysis, sp).has(analysis.top)) reasons.push("spread of ⊤"); + const direct = byAtom.get(s.atom) ?? []; + const ops = escapes ? [...direct, ...topOps] : direct; + const keys = new Set(s.keys ?? []); + const fieldsOf = analysis.fields.get(s.atom); + const knownKeys = + s.keys !== null ? keys : new Set([...fieldKeys(fieldsOf)].filter((k) => k !== "*")); + let freezable = false; + const seen = new Set(); + const note = (r: string): void => { + if (!seen.has(r)) { + seen.add(r); + reasons.push(r); + } + }; + for (const o of ops) { + const viaTop = !atomsOf(analysis, o.recv).has(s.atom); + const where = `${locLabel(o.node)}${viaTop ? " via ⊤" : ""}`; + switch (o.kind) { + case "delete": + case "defineProperty": + case "setPrototypeOf": + case "seal": + case "proxy": + note(`${o.kind} at ${where}`); + break; + case "assign": + note(`Object.assign target at ${where}`); + break; + case "freeze": + freezable = true; + break; + case "computedWrite": + if (!viaTop) + note(s.kind === "array" ? `index write at ${where}` : `computed write at ${where}`); + break; + case "lengthWrite": + if (s.kind === "array") note(`length write at ${where}`); + break; + case "write": + if (s.kind === "object" && !viaTop && o.name !== null && !knownKeys.has(o.name)) + note(`adds key '${o.name}' at ${where}`); + break; + case "read": + if ( + s.kind === "object" && + !underPromiseGuard(o.node) && + escapes && + o.name !== null && + !viaTop && + !knownKeys.has(o.name) && + !OBJECT_PROTOTYPE_MEMBERS.has(o.name) + ) + note(`reads absent key '${o.name}' at ${where} (escapes)`); + break; + default: + break; + } + } + let brand = false; + if (s.kind === "object" && s.keys !== null) { + const o = orders.get([...s.keys].sort().join(",")); + if (o !== undefined && o.size > 1) brand = true; + } + const writableByTop: string[] = []; + if (escapes) { + if (analysis.topComputedWrites.length > 0) writableByTop.push("*"); + else for (const k of knownKeys) if (analysis.topWriteNames.has(k)) writableByTop.push(k); + } + const verdict: SiteVerdict["verdict"] = + reasons.length > 0 ? "G" : escapes ? "P-escaping" : "P-local"; + const label = s.atom.label; + if (escapes) reasons.push(`escapes: ${escapedWhy}`); + verdicts.push({ site: s, label, verdict, reasons, writableByTop, freezable, brand }); + } + + const hot = hotFunctions(analysis); + const hotNodes = new Set([...hot].map((f) => f.node)); + + // ---- print ---- + const pkgFns = [...analysis.functions.values()].filter((f) => f.inPackage); + lines.push( + `analyzed ${analysis.files.length} files (${analysis.packageFiles} package JS), ${analysis.functions.size} functions (${pkgFns.length} in packages), ${analysis.atoms.atoms.length} atoms, ${analysis.nodes.length} value nodes, ${analysis.steps} steps${analysis.budgetExceeded ? " — BUDGET EXCEEDED, results incomplete" : ""}`, + ); + const topNames = [...analysis.topWriteNames.entries()].map( + ([n, node]) => `${n} (${locLabel(node)})`, + ); + lines.push( + `census: writes on ⊤ receivers: ${topNames.length === 0 ? "none" : topNames.slice(0, 20).join(", ")}${topNames.length > 20 ? ` +${topNames.length - 20}` : ""}`, + ); + lines.push( + `census: computed writes on ⊤ receivers: ${analysis.topComputedWrites.length === 0 ? "none" : analysis.topComputedWrites.slice(0, 8).map(locLabel).join(", ")}`, + ); + const topReflect = topOps.filter( + (o) => + o.kind !== "read" && + o.kind !== "computedRead" && + o.kind !== "write" && + o.kind !== "computedWrite", + ); + lines.push( + `census: reflection on ⊤ receivers: ${topReflect.length === 0 ? "none" : topReflect.map((o) => `${o.kind} (${locLabel(o.node)})`).join(", ")}`, + ); + const escapedPkg = [...analysis.escaped.keys()].filter( + (a) => + a.node !== undefined && + wanted(a.node, a.node.getSourceFile().fileName.includes("/node_modules/")), + ); + lines.push( + `escaped atoms: ${analysis.escaped.size} (${escapedPkg.length} shown below where relevant)`, + ); + const firstEscapes = [...analysis.escaped.entries()] + .filter(([, why]) => !why.startsWith("via ")) + .slice(0, 12); + for (const [atom, why] of firstEscapes) lines.push(` escape root: ${atom.label}: ${why}`); + + const counts = { "P-local": 0, "P-escaping": 0, G: 0 }; + const hotCounts = { "P-local": 0, "P-escaping": 0, G: 0 }; + const inHot = (n: ts.Node): boolean => { + let p: ts.Node | undefined = n.parent; + while (p !== undefined) { + if (hotNodes.has(p)) return true; + p = p.parent; + } + return false; + }; + for (const v of verdicts) { + counts[v.verdict]++; + if (inHot(v.site.node)) hotCounts[v.verdict]++; + } + lines.push( + `sites: ${verdicts.length} (P local ${counts["P-local"]}, P escaping ${counts["P-escaping"]}, G ${counts.G}); in hot functions: P local ${hotCounts["P-local"]}, P escaping ${hotCounts["P-escaping"]}, G ${hotCounts.G}`, + ); + for (const v of verdicts) { + if (!wanted(v.site.node, v.site.inPackage)) continue; + if (!verbose && !inHot(v.site.node)) continue; + const extra: string[] = []; + if (v.brand) extra.push("needs brand (key order)"); + if (v.freezable) extra.push("freezable"); + if (v.writableByTop.length > 0) extra.push(`⊤-writable: ${v.writableByTop.join(",")}`); + const fields = analysis.fields.get(v.site.atom); + const ftypes = + v.site.kind === "array" + ? `elem: ${analysis.elements.has(v.site.atom) ? describeValue(analysis, analysis.elements.get(v.site.atom)!) : "∅"}` + : fieldEntries(fields) + .filter(([k]) => k !== "*") + .map(([k, id]) => `${k}: ${describeValue(analysis, id)}`) + .join("; "); + lines.push( + `site ${v.label}${inHot(v.site.node) ? " [hot]" : ""}: ${v.verdict}${v.reasons.length > 0 ? ` — ${v.reasons.join("; ")}` : ""}${extra.length > 0 ? ` [${extra.join("; ")}]` : ""}`, + ); + if (ftypes.length > 0) lines.push(` ${ftypes}`); + } + + // Class fields. + for (const atom of analysis.atoms.atoms) { + if (atom.kind !== "instance" || atom.node === undefined) continue; + const inPackage = atom.node.getSourceFile().fileName.includes("/node_modules/"); + if (!wanted(atom.node, inPackage)) continue; + const fm = analysis.fields.get(atom); + if (fm === undefined || fm.size === 0) continue; + const esc = analysis.escaped.get(atom); + const parts = [...fm.entries()].map(([k, id]) => { + const w = + esc !== undefined && + !k.startsWith("#") && + (analysis.topComputedWrites.length > 0 || analysis.topWriteNames.has(k)) + ? " (⊤-writable)" + : ""; + return `${k}: ${describeValue(analysis, id)}${w}`; + }); + lines.push( + `class ${atom.label}${esc !== undefined ? ` (escapes: ${esc})` : ""}: ${parts.join("; ")}`, + ); + } + + // Hot functions. + const hotPkg = [...hot].filter((info) => wanted(info.node, info.inPackage)); + lines.push(`hot functions: ${hotPkg.length} (clones per receiver class counted separately)`); + for (const info of hotPkg) { + const n = info.node; + const params = info.params.map((p, i) => `p${i}=${describeValue(analysis, p)}`).join(", "); + const flags = [ + info.usesArguments ? "uses arguments" : "", + analysis.escaped.size > 0 && [...analysis.escaped.keys()].some((a) => a.node === n) + ? "escapes" + : "", + ].filter((x) => x !== ""); + lines.push( + `fn ${info.label}${flags.length > 0 ? ` [${flags.join(", ")}]` : ""}: this=${describeValue(analysis, info.thisNode)}${params.length > 0 ? `, ${params}` : ""}, ret=${describeValue(analysis, info.ret)}`, + ); + } + const why = process.env["SCRIPTC_DEBUG_SHAPES_WHY"]; + if (why !== undefined) { + for (const info of analysis.functions.values()) { + if (!info.label.startsWith(why)) continue; + for (const [what, node] of [ + ["ret", info.ret], + ...info.params.map((p, i) => [`p${i}`, p] as const), + ] as const) { + if (!analysis.nodes[node]!.atoms.has(analysis.top)) continue; + lines.push(`why ⊤ in ${info.label} ${what}:`); + let cur: number | string | undefined = node; + for (let i = 0; i < 40 && typeof cur === "number"; i++) { + lines.push(` ${analysis.nodeLabel.get(cur) ?? `node ${cur}`}`); + cur = analysis.topCause.get(cur); + } + if (typeof cur === "string") lines.push(` seed: ${cur}`); + } + } + } + return { sites: verdicts, hot, lines }; +} + +/** A read inside the true arm of a promise test (`isAsync(x)`, + * `x instanceof Promise`): flow-sensitive narrowing removes the record + * arms there. Stage S1's locals are flow-insensitive, so the report + * recognizes the guard syntactically. */ +function underPromiseGuard(node: ts.Node): boolean { + let child: ts.Node = node; + let p = node.parent; + while (p !== undefined && !ts.isFunctionLike(p)) { + let cond: ts.Expression | undefined; + if (ts.isIfStatement(p) && p.thenStatement === child) cond = p.expression; + if (ts.isConditionalExpression(p) && p.whenTrue === child) cond = p.condition; + if (cond !== undefined && isPromiseTest(cond)) return true; + child = p; + p = p.parent; + } + return false; +} + +function isPromiseTest(e: ts.Expression): boolean { + if (ts.isParenthesizedExpression(e)) return isPromiseTest(e.expression); + if (ts.isBinaryExpression(e)) { + if (e.operatorToken.kind === ts.SyntaxKind.InstanceOfKeyword) + return ts.isIdentifier(e.right) && e.right.text === "Promise"; + if (e.operatorToken.kind === ts.SyntaxKind.AmpersandAmpersandToken) + return isPromiseTest(e.left) || isPromiseTest(e.right); + return false; + } + if (ts.isCallExpression(e) && ts.isIdentifier(e.expression)) + return /^is(Async|Promise|Thenable)$/.test(e.expression.text); + return false; +} diff --git a/packages/compiler/test/shape-inference.test.ts b/packages/compiler/test/shape-inference.test.ts new file mode 100644 index 000000000..3cd6e809d --- /dev/null +++ b/packages/compiler/test/shape-inference.test.ts @@ -0,0 +1,166 @@ +import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { afterEach, beforeEach, expect, test, vi } from "vitest"; +import { compile } from "../src/index.js"; + +// A package shaped like a validation library: schema classes with a virtual +// `_parse`, per-field context and result literals, a class holding the +// context, and an output object built with computed keys. +const packageSource = ` +export class Status { + constructor() { this.value = "valid"; } + dirty() { if (this.value === "valid") this.value = "dirty"; } +} +class LazyPath { + constructor(parent, data, key) { this.parent = parent; this.data = data; this.key = key; } + get path() { return [this.key]; } +} +export class Base { + constructor(def) { this._def = def; } + ctxOf(input) { return { common: input.parent.common, data: input.data, parent: input.parent }; } + parse(data) { + const root = { common: { issues: [] }, data, parent: null }; + const result = this._parse({ data, parent: root }); + return result.value; + } +} +export class Str extends Base { + _parse(input) { + const status = new Status(); + if (typeof input.data !== "string") status.dirty(); + return { status: status.value, value: input.data }; + } +} +export class Obj extends Base { + _parse(input) { + const ctx = this.ctxOf(input); + const pairs = []; + for (const key of Object.keys(this._def.shape)) { + const field = this._def.shape[key]; + pairs.push({ key, value: field._parse(new LazyPath(ctx, ctx.data[key], key)) }); + } + const out = {}; + for (const pair of pairs) out[pair.key] = pair.value.value; + return { status: "valid", value: out }; + } +} +export const str = () => new Str({ checks: [] }); +export const obj = (shape) => new Obj({ shape }); +export function leak(value) { globalThis.leaked = value; return value; } +export function reflect() { const o = { a: 1 }; delete o.a; return o; } +`; + +const packageTypes = ` +export declare class Base { parse(data: unknown): unknown; } +export declare class Str extends Base {} +export declare class Obj extends Base {} +export declare const str: () => Str; +export declare const obj: (shape: Record) => Obj; +export declare function leak(value: T): T; +export declare function reflect(): object; +`; + +const mainSource = ` +import { leak, obj, reflect, str } from "shapes-fixture"; +const schema = obj({ a: str(), b: str() }); +const input: unknown = JSON.parse('{"a":"x","b":"y"}'); +console.log(JSON.stringify(schema.parse(input))); +console.log(JSON.stringify(leak({ kept: 1 })), JSON.stringify(reflect())); +`; + +let dir: string; +let saved: string | undefined; +beforeEach(async () => { + dir = await mkdtemp(join(tmpdir(), "scriptc-shapes-")); + const pkg = join(dir, "node_modules", "shapes-fixture"); + await mkdir(pkg, { recursive: true }); + await writeFile( + join(pkg, "package.json"), + JSON.stringify({ + name: "shapes-fixture", + version: "1.0.0", + type: "module", + main: "index.js", + types: "index.d.ts", + }), + ); + await writeFile(join(pkg, "index.js"), packageSource); + await writeFile(join(pkg, "index.d.ts"), packageTypes); + await writeFile( + join(dir, "package.json"), + JSON.stringify({ type: "module", dependencies: { "shapes-fixture": "1.0.0" } }), + ); + await writeFile(join(dir, "main.ts"), mainSource); + saved = process.env["SCRIPTC_DEBUG_SHAPES"]; +}); +afterEach(async () => { + if (saved === undefined) delete process.env["SCRIPTC_DEBUG_SHAPES"]; + else process.env["SCRIPTC_DEBUG_SHAPES"] = saved; + vi.restoreAllMocks(); + await rm(dir, { recursive: true, force: true }); +}); + +async function report(): Promise { + process.env["SCRIPTC_DEBUG_SHAPES"] = "verbose"; + const lines: string[] = []; + vi.spyOn(process.stderr, "write").mockImplementation((chunk: string | Uint8Array) => { + const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8"); + for (const l of text.split("\n")) if (l.startsWith("[shapes] ")) lines.push(l.slice(9)); + return true; + }); + const entry = join(dir, "main.ts"); + await compile(entry, { + outDir: dir, + outPath: join(dir, "main.ir.json"), + outputKind: "ir", + npmStatic: ["shapes-fixture"], + }); + return lines; +} + +function site(lines: string[], label: RegExp): string { + const line = lines.find((l) => l.startsWith("site ") && label.test(l)); + if (line === undefined) throw new Error(`no site ${label}:\n${lines.join("\n")}`); + return line; +} + +test("S1 report: per-field temporaries are provable records, dynamic objects stay G", async () => { + const lines = await report(); + // result literals of both _parse implementations, the pair literal, the + // context and the root context never escape: native records would be exact + // the leaf schema's result: in a function called from a loop (hot) + expect(site(lines, /^site \{status,value\}@shapes-fixture\/index\.js:23 \[hot\]/)).toMatch( + /: P-local/, + ); + expect(site(lines, /^site \{status,value\}@shapes-fixture\/index\.js:36/)).toMatch(/: P-local/); + expect(site(lines, /^site \{key,value\}@/)).toMatch(/: P-local/); + expect(site(lines, /^site \{common,data,parent\}@shapes-fixture\/index\.js:12/)).toMatch( + /: P-local/, + ); + expect(site(lines, /^site \[\]@shapes-fixture\/index\.js:29/)).toMatch(/: P-local/); + // the output object is built with computed keys + expect(site(lines, /^site \{\}@shapes-fixture\/index\.js:34/)).toMatch(/: G — computed write/); + // a deleted key and a value stored into the global object + expect(site(lines, /^site \{a\}@/)).toMatch(/: G — delete at/); + expect(site(lines, /^site \{kept\}@main\.ts/)).toMatch(/: P-escaping — escapes: stored into ⊤/); + // receiver-typed dispatch: the field's validators are the schema classes + expect(lines.find((l) => l.startsWith("fn Str._parse@"))).toMatch(/p0=LazyPath/); + expect(lines.find((l) => l.startsWith("class LazyPath"))).toMatch( + /parent: \{common,data,parent\}@shapes-fixture\/index\.js:12;/, + ); + expect(lines.find((l) => l.startsWith("class Str"))).toMatch(/_def: \{checks\}@/); +}); + +test("S1 report is off by default and changes nothing", async () => { + delete process.env["SCRIPTC_DEBUG_SHAPES"]; + const writes = vi.spyOn(process.stderr, "write"); + const entry = join(dir, "main.ts"); + await compile(entry, { + outDir: dir, + outPath: join(dir, "main.ir.json"), + outputKind: "ir", + npmStatic: ["shapes-fixture"], + }); + expect(writes.mock.calls.some(([c]) => String(c).includes("[shapes]"))).toBe(false); +}); From c244ddc4c53b5746b7443c6dadbd42eea1f616f8 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 13:18:19 -0500 Subject: [PATCH 120/259] Answer 'send', 'disconnect' and 'channel' in a child process from its IPC channel A child process has these members only when it was created with an IPC channel (fork, or an "ipc" stdio entry), and keeps them after the channel closes and after the child exits. The 'in' test on native handles answered true for every declared member, so a child spawned without IPC reported them and entered IPC-only branches. The three names now answer from the runtime: scr_child_ipc_present reports whether the child was created with a channel. Corpus 8290 tests a forked and a spawned child before and after disconnect and exit. --- .../compiler/src/backend/llvm/lib-process.ts | 7 +++++ .../lowering/expressions/relational.ts | 8 ++++++ .../compiler/src/ir/builtin-signatures.ts | 1 + .../8290-child-channel-members/main.ts.json | 6 ++++ packages/runtime/src/scr_child.c | 3 ++ packages/runtime/src/scr_child.h | 1 + .../corpus/8290-child-channel-members/main.ts | 28 +++++++++++++++++++ .../8290-child-channel-members/worker.ts | 1 + 8 files changed, 55 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8290-child-channel-members/main.ts.json create mode 100644 tests/corpus/8290-child-channel-members/main.ts create mode 100644 tests/corpus/8290-child-channel-members/worker.ts diff --git a/packages/compiler/src/backend/llvm/lib-process.ts b/packages/compiler/src/backend/llvm/lib-process.ts index 3e8a9bff5..c44febada 100644 --- a/packages/compiler/src/backend/llvm/lib-process.ts +++ b/packages/compiler/src/backend/llvm/lib-process.ts @@ -118,6 +118,13 @@ export function emitChildProcessLibCall(host: LlvmEmitterContext, e: LibCallExpr B.line(`call void @scr_child_on_error(ptr ${child.name}, ptr ${cb.name}, ptr @${adapter})`); return { name: "", type: e.type }; } + if (e.fn === "child.hasChannel") { + const child = host.emitExpr(e.args[0]!); + host.declare(`declare zeroext i1 @scr_child_ipc_present(ptr)`); + const out = B.tmp(); + B.line(`${out} = call i1 @scr_child_ipc_present(ptr ${child.name})`); + return { name: out, type: e.type }; + } if (e.fn === "child.connected") { const child = host.emitExpr(e.args[0]!); host.declare(`declare zeroext i1 @scr_child_ipc_connected(ptr)`); diff --git a/packages/compiler/src/frontend/lowering/expressions/relational.ts b/packages/compiler/src/frontend/lowering/expressions/relational.ts index edec5ba5f..9b74e3f10 100644 --- a/packages/compiler/src/frontend/lowering/expressions/relational.ts +++ b/packages/compiler/src/frontend/lowering/expressions/relational.ts @@ -1762,6 +1762,11 @@ export function lowerInExpression( }; } } + // A child process has `send`, `disconnect` and `channel` only when it was + // created with an IPC channel (fork, or an "ipc" stdio entry), and keeps + // them after the channel closes: the runtime answers from the child. + if (recv.type.kind === "child" && CHILD_CHANNEL_MEMBERS.has(key)) + return { kind: "libCall", fn: "child.hasChannel", args: [recv], type: BOOL, loc }; // A native Node handle (an http.Server, a socket, a child process...): // a member Node's declarations give the class is on its prototype, so // `"closeAllConnections" in server` answers true. Undeclared names can @@ -2094,6 +2099,9 @@ const NATIVE_HANDLE_KINDS: ReadonlySet = new Set([ "http2Stream", ]); +/** Child process members that exist only on a child with an IPC channel. */ +const CHILD_CHANNEL_MEMBERS: ReadonlySet = new Set(["send", "disconnect", "channel"]); + /** Whether every constituent of `t` declares a required member `key` in * a declaration file (Node's @types/node). */ function nodeDeclaredMember(lowerer: Lowerer, t: ts.Type, key: string): boolean { diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 51a0ec778..0449be07f 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -2570,6 +2570,7 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ result: CHILD_T, }, "child.connected": { argTypes: [CHILD_T], result: BOOL }, + "child.hasChannel": { argTypes: [CHILD_T], result: BOOL }, "child.send": { argTypes: [CHILD_T, STRING], result: BOOL }, "child.sendCb": { argTypes: [CHILD_T, STRING, null], result: BOOL }, "child.disconnect": { argTypes: [CHILD_T], result: VOID }, diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8290-child-channel-members/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8290-child-channel-members/main.ts.json new file mode 100644 index 000000000..3519c4e6c --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8290-child-channel-members/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8290-child-channel-members/main.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_child.c b/packages/runtime/src/scr_child.c index df7543500..234b3c115 100644 --- a/packages/runtime/src/scr_child.c +++ b/packages/runtime/src/scr_child.c @@ -6456,6 +6456,9 @@ double scr_process_fork_target(double target_count) { return target; } +/* The child was created with an IPC channel; it keeps it until it is freed. */ +bool scr_child_ipc_present(ScrChild *c) { return c->ipc != NULL; } + bool scr_child_ipc_connected(ScrChild *c) { return c->ipc != NULL && c->ipc->connected; } diff --git a/packages/runtime/src/scr_child.h b/packages/runtime/src/scr_child.h index a5853ad59..8b0d4d3f1 100644 --- a/packages/runtime/src/scr_child.h +++ b/packages/runtime/src/scr_child.h @@ -176,6 +176,7 @@ void scr_child_release_v(void *p); void scr_child_on_exit(ScrChild *c, ScrClosure *cb /*moves*/, ScrChildExitFn fn); void scr_child_on_close(ScrChild *c, ScrClosure *cb /*moves*/, ScrChildExitFn fn); void scr_child_on_error(ScrChild *c, ScrClosure *cb /*moves*/, ScrChildErrFn fn); +bool scr_child_ipc_present(ScrChild *c); bool scr_child_ipc_connected(ScrChild *c); bool scr_child_ipc_send(ScrChild *c, ScrStr *json); bool scr_child_ipc_send_cb(ScrChild *c, ScrStr *json, diff --git a/tests/corpus/8290-child-channel-members/main.ts b/tests/corpus/8290-child-channel-members/main.ts new file mode 100644 index 000000000..78ed52de1 --- /dev/null +++ b/tests/corpus/8290-child-channel-members/main.ts @@ -0,0 +1,28 @@ +import { fork, spawn } from "node:child_process"; + +// `send`, `disconnect` and `channel` exist only on a child created with an +// IPC channel, and stay after the channel closes; the other members are +// on every child. +const describe = (label: string, child: ReturnType): string => + `${label}: send ${"send" in child} disconnect ${"disconnect" in child} channel ${"channel" in child} kill ${"kill" in child} pid ${"pid" in child}`; + +const lines: string[] = []; +const plain = spawn("/bin/sh", ["-c", "exit 0"], { stdio: "ignore" }); +lines.push(describe("spawn", plain)); +const forked = fork(new URL("./worker.ts", import.meta.url), [], { + stdio: ["ignore", "ignore", "inherit", "ipc"], +}); +lines.push(describe("fork", forked)); +forked.once("message", () => { + forked.disconnect(); + lines.push(describe("fork after disconnect", forked)); +}); +forked.once("exit", () => { + lines.push(describe("fork after exit", forked)); +}); +plain.once("exit", () => { + lines.push(describe("spawn after exit", plain)); +}); +process.once("exit", () => { + console.log(lines.sort().join("\n")); +}); diff --git a/tests/corpus/8290-child-channel-members/worker.ts b/tests/corpus/8290-child-channel-members/worker.ts new file mode 100644 index 000000000..96401ea1a --- /dev/null +++ b/tests/corpus/8290-child-channel-members/worker.ts @@ -0,0 +1 @@ +process.send?.({ value: 1 }); From b78520559f11be608a6e43e77e05bc0d61a1c6da Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 13:20:02 -0500 Subject: [PATCH 121/259] Follow values through shadowed members, unknown keys on arrays, JSON callbacks and proxies - Named loads also read what was written under that name or an unknown key where an own field shadows a builtin: an instance's constructor, a function's call, apply, bind, prototype, name and length, a class's prototype and name, an array's methods. Named loads of arrays read what was written under unknown keys, which computed stores on arrays now record. - Computed stores into builtins, promises and collections escape, as named stores there do. - JSON.stringify calls toJSON on arrays, functions and classes, and on values written under unknown keys. A JSON.parse reviver's results are part of the result and of later calls' values. - Reflect.construct(Proxy, ...) and globalThis.Proxy record a proxy operation, as new Proxy does. --- .../src/frontend/shape-inference/analyze.ts | 136 ++++++++++++++---- .../compiler/test/shape-inference.test.ts | 55 +++++++ 2 files changed, 161 insertions(+), 30 deletions(-) diff --git a/packages/compiler/src/frontend/shape-inference/analyze.ts b/packages/compiler/src/frontend/shape-inference/analyze.ts index 0a7b4d6d9..9f2028b2c 100644 --- a/packages/compiler/src/frontend/shape-inference/analyze.ts +++ b/packages/compiler/src/frontend/shape-inference/analyze.ts @@ -447,9 +447,11 @@ class Analyzer { id = this.newNode(); m.set(name, id); if (this.traceTop) this.nodeLabel.set(id, `${atom.label}.${name}`); - if (name === "*") { - for (const dst of this.unknownKeyReaders.get(atom) ?? []) this.edge(id, dst); - this.unknownKeyReaders.delete(atom); + const byName = this.fieldReaders.get(atom); + const readers = byName?.get(name); + if (readers !== undefined) { + for (const dst of readers) this.edge(id, dst); + byName!.delete(name); } const reason = this.escaped.get(atom); if (reason !== undefined) { @@ -1303,6 +1305,17 @@ class Analyzer { } if (ts.isPropertyAccessExpression(e)) { this.noteSite(e); + // `globalThis.Proxy` and the like are the modeled globals. + const object = unparen(e.expression); + if ( + ts.isIdentifier(object) && + object.text === "globalThis" && + MODELED_GLOBALS.has(e.name.text) + ) { + const d = this.resolve(object); + if (d === undefined || d.getSourceFile().isDeclarationFile) + return this.globalNode(e.name.text); + } const recv = this.expr(e.expression); const name = e.name.text; const dst = this.newNode(); @@ -1696,25 +1709,35 @@ class Analyzer { return this.field(atom, "*"); } - /** Loads waiting for an atom's first write under an unknown key. */ - private readonly unknownKeyReaders = new Map(); + /** Loads waiting for an atom's first write of a field, by field name. */ + private readonly fieldReaders = new Map>(); - /** dst ⊇ the values written to `atom` under unknown keys, now and later, + /** dst ⊇ the values written to field `name` of `atom`, now and later, * without creating the field for atoms that have none. */ - unknownKeysInto(atom: Atom, dst: number): void { - const id = this.fields.get(atom)?.get("*"); + fieldInto(atom: Atom, name: string, dst: number): void { + const id = this.fields.get(atom)?.get(name); if (id !== undefined) { this.edge(id, dst); return; } - let readers = this.unknownKeyReaders.get(atom); + let byName = this.fieldReaders.get(atom); + if (byName === undefined) { + byName = new Map(); + this.fieldReaders.set(atom, byName); + } + let readers = byName.get(name); if (readers === undefined) { readers = []; - this.unknownKeyReaders.set(atom, readers); + byName.set(name, readers); } readers.push(dst); } + /** dst ⊇ the values written to `atom` under unknown keys, now and later. */ + unknownKeysInto(atom: Atom, dst: number): void { + this.fieldInto(atom, "*", dst); + } + copyFields(src: number, dstAtom: Atom, site: Node): void { this.on(src, (a) => { if (a.kind === "top") { @@ -1777,21 +1800,33 @@ class Analyzer { }); } - /** JSON.stringify's call of `value.toJSON(key)` on a value that has one - * (a class member, or an own field once it exists); the result goes to `out`. */ + /** JSON.stringify's call of `value.toJSON(key)` on an object, array or function that may + * have one (a class member, an own field, or a write under an unknown key, once it exists); + * the result goes to `out`. */ callToJSON( value: Atom, key: number, out: number, site: ts.CallExpression | ts.TaggedTemplateExpression, ): void { - if (value.kind !== "object" && value.kind !== "instance" && value.kind !== "dictionary") return; + if ( + value.kind !== "object" && + value.kind !== "instance" && + value.kind !== "dictionary" && + value.kind !== "array" && + value.kind !== "function" && + value.kind !== "class" + ) + return; let called = false; const call = (): void => { if (called) return; + const fields = this.fields.get(value); const has = - this.fields.get(value)?.has("toJSON") === true || - (value.kind === "instance" && this.lookupMember(value.node!, "toJSON", false) !== null); + fields?.has("toJSON") === true || + fields?.has("*") === true || + ((value.kind === "instance" || value.kind === "class") && + this.lookupMember(value.node!, "toJSON", value.kind === "class") !== null); if (!has) return; called = true; const fn = this.newNode(); @@ -2002,7 +2037,10 @@ class Analyzer { case "instance": { const decl = a.node!; if (name === "constructor") { + // An own `constructor` field, written by name or under an unknown key, shadows the class. this.add(dst, this.classAtoms(decl).cls); + this.fieldInto(a, name, dst); + this.unknownKeysInto(a, dst); return; } const member = this.lookupMember(decl, name, false); @@ -2027,12 +2065,10 @@ class Analyzer { } case "class": { const decl = a.node!; - if (name === "prototype") { - this.add(dst, this.top); - return; - } - if (name === "name") { - this.add(dst, this.prim("string")); + if (name === "prototype" || name === "name") { + this.add(dst, name === "prototype" ? this.top : this.prim("string")); + this.fieldInto(a, name, dst); + this.unknownKeysInto(a, dst); return; } const member = this.lookupMember(decl, name, true); @@ -2057,6 +2093,7 @@ class Analyzer { return; } case "function": + // An own field, written by name or under an unknown key, shadows a builtin member. if (name === "call" || name === "apply" || name === "bind") this.add(dst, this.builtin(`function.${name}`, a)); else if (name === "prototype") this.add(dst, this.top); @@ -2065,13 +2102,22 @@ class Analyzer { else { this.edge(this.field(a, name), dst); this.unknownKeysInto(a, dst); + return; } + this.fieldInto(a, name, dst); + this.unknownKeysInto(a, dst); return; case "array": if (name === "length") this.add(dst, this.prim("number")); else if (/^\d+$/.test(name)) this.edge(this.element(a), dst); - else if (ARRAY_METHODS.has(name)) this.add(dst, this.builtin(`array.${name}`, a)); - else this.edge(this.field(a, name), dst); + else { + // A named property, written by name or under an unknown key; an own field shadows a method. + if (ARRAY_METHODS.has(name)) { + this.add(dst, this.builtin(`array.${name}`, a)); + this.fieldInto(a, name, dst); + } else this.edge(this.field(a, name), dst); + this.unknownKeysInto(a, dst); + } return; case "object": this.edge(this.field(a, name), dst); @@ -2217,12 +2263,22 @@ class Analyzer { this.sink(value, `stored into ⊤[k] at ${locLabel(site)}`); return; case "array": + // An index, or a named property under an unknown key. this.edge(value, this.element(a)); + this.edge(value, this.anyField(a)); return; case "prim": return; - default: + case "object": + case "dictionary": + case "instance": + case "class": + case "function": this.edge(value, this.anyField(a)); + return; + default: + // As a store under a name: a builtin, promise or collection keeps it where it isn't tracked. + this.sink(value, `stored into ${a.label}[k] at ${locLabel(site)}`); } }); } @@ -2885,22 +2941,29 @@ class Analyzer { this.add(dst, out); return; } - case "JSON.parse": - // A reviver runs on every parsed value with its key, the holder as `this`. + case "JSON.parse": { + // A reviver runs on every parsed value with its key, the holder as `this`, innermost first: + // what it returns replaces the value, in its holder (which later calls receive) and in the + // result. + const revived = this.newNode(); + this.add(revived, this.top); if (args[1] !== undefined) this.on(args[1], (f) => { if (f.kind === "function") this.callFunction( this.infoOfAtom(f)!, - this.constNode(this.top), - [this.constNode(this.prim("string")), this.constNode(this.top)], + revived, + [this.constNode(this.prim("string")), revived], false, - this.newNode(), + revived, site, ); + else if (f.kind === "top") + this.sink(revived, `JSON.parse reviver at ${locLabel(site)}`); }); - this.add(dst, this.top); + this.edge(revived, dst); return; + } case "JSON.stringify": { // Every value it serializes: toJSON methods run on them, and a // replacer function with each key and value, the holder as `this`. @@ -2942,6 +3005,19 @@ class Analyzer { this.ops.push({ kind: "proxy", recv: arg(0), name: null, node: site }); escapeAll(); return; + case "Reflect.construct": { + // Reflect.construct(Proxy, [target, handler]) is `new Proxy(target, handler)`: the arguments + // are the list's elements. + const listed = this.newNode(); + if (args[1] !== undefined) this.iterateInto(args[1], listed, site); + this.on(arg(0), (c) => { + if (c.kind === "builtin" && c.path === "Proxy") + this.ops.push({ kind: "proxy", recv: listed, name: null, node: site }); + }); + this.sink(listed, `argument of ${path} at ${locLabel(site)}`); + escapeAll(); + return; + } case "String": case "encodeURIComponent": case "decodeURIComponent": diff --git a/packages/compiler/test/shape-inference.test.ts b/packages/compiler/test/shape-inference.test.ts index b4c898025..911cef79a 100644 --- a/packages/compiler/test/shape-inference.test.ts +++ b/packages/compiler/test/shape-inference.test.ts @@ -79,6 +79,29 @@ export function stringified() { export function proxied() { return new Proxy({ proxied: 1 }, {}); } export function reflectDelete() { const o = { gone: 1 }; Reflect.deleteProperty(o, "gone"); return o; } export function tagged() { return tag\`a\${{ part: 1 }}b\`; } +export function arrayComputed(k) { const l = []; l[k] = { arrayComputed: 1 }; return leak(l.meta); } +export function shadowed(k) { + const fn = function () {}; + fn[k] = { onPrototype: 1 }; + const box = new Box(); + box[k] = { onConstructor: 1 }; + return [leak(fn.prototype), leak(box.constructor)]; +} +export function jsonCallbacks(k) { + const inArray = { inArray: 1 }; + const list = []; + list.toJSON = function () { globalThis.inArray = inArray; return 1; }; + const inFunction = { inFunction: 1 }; + const fn = function () {}; + fn.toJSON = function () { globalThis.inFunction = inFunction; return 1; }; + const underKey = { underKey: 1 }; + const o = {}; + o[k] = function () { globalThis.underKey = underKey; return 1; }; + return JSON.stringify([list, { fn }, o]); +} +export function revivedResult(text) { const r = { fromReviver: 1 }; return leak(JSON.parse(text, function () { return r; })); } +export function constructedProxy() { return Reflect.construct(Proxy, [{ constructedProxy: 1 }, {}]); } +export function globalProxy() { return new globalThis.Proxy({ globalProxy: 1 }, {}); } `; const packageTypes = ` @@ -96,18 +119,30 @@ export declare function stringified(): unknown; export declare function proxied(): unknown; export declare function reflectDelete(): unknown; export declare function tagged(): unknown; +export declare function arrayComputed(k: string): unknown; +export declare function shadowed(k: string): unknown; +export declare function jsonCallbacks(k: string): unknown; +export declare function revivedResult(text: string): unknown; +export declare function constructedProxy(): unknown; +export declare function globalProxy(): unknown; `; const mainSource = ` import { + arrayComputed, arrayProp, computedField, + constructedProxy, + globalProxy, + jsonCallbacks, leak, obj, proxied, reflect, reflectDelete, revive, + revivedResult, + shadowed, str, stringified, tagged, @@ -124,6 +159,12 @@ const more = [ proxied(), reflectDelete(), tagged(), + arrayComputed("meta"), + shadowed("prototype"), + jsonCallbacks("toJSON"), + revivedResult("{}"), + constructedProxy(), + globalProxy(), ]; console.log(more.length); `; @@ -229,6 +270,20 @@ test("S1 report follows values through array properties, unknown keys, callbacks expect(site(lines, /^site \{gone\}@/)).toMatch(/: G — delete at/); // a tagged template's substitution, passed to its tag expect(site(lines, /^site \{part\}@/)).toMatch(/: P-escaping/); + // a named load of an array property written under an unknown key + expect(site(lines, /^site \{arrayComputed\}@/)).toMatch(/: P-escaping/); + // own fields written under unknown keys shadow a function's prototype and an instance's constructor + expect(site(lines, /^site \{onPrototype\}@/)).toMatch(/: P-escaping/); + expect(site(lines, /^site \{onConstructor\}@/)).toMatch(/: P-escaping/); + // toJSON on an array, on a function, and stored under an unknown key + expect(site(lines, /^site \{inArray\}@/)).toMatch(/: P-escaping/); + expect(site(lines, /^site \{inFunction\}@/)).toMatch(/: P-escaping/); + expect(site(lines, /^site \{underKey\}@/)).toMatch(/: P-escaping/); + // what a JSON.parse reviver returns is in the result + expect(site(lines, /^site \{fromReviver\}@/)).toMatch(/: P-escaping/); + // a proxy constructed through Reflect.construct and globalThis + expect(site(lines, /^site \{constructedProxy\}@/)).toMatch(/: G — proxy at/); + expect(site(lines, /^site \{globalProxy\}@/)).toMatch(/: G — proxy at/); // the existing verdicts hold expect(site(lines, /^site \{kept\}@main\.ts/)).toMatch(/: P-escaping — escapes: stored into ⊤/); }); From 587443428cfb1e2600fd642195731cd4e68814ba Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 13:22:26 -0500 Subject: [PATCH 122/259] Link Linux executables with lld when the driver finds it Linux executables linked through the clang driver with its default linker, GNU ld. lld links the same objects in about half the time. - Native and Node-hosted Linux exe links pass -fuse-ld=lld when ld.lld is beside the driver's executable (where clang looks first) or on PATH, and the default driver is in use (no SCRIPTC_LINKER, no sanitizer link). - A link with lld that fails runs again with the driver's default linker, whose error is the one reported when that fails too. --- packages/compiler/src/backend/linker.ts | 14 ++- packages/compiler/src/backend/lld.test.ts | 61 ++++++++++++ packages/compiler/src/backend/lld.ts | 49 +++++++++ packages/compiler/src/native/compiler.test.ts | 99 ++++++++++++++++++- packages/compiler/src/native/compiler.ts | 20 +++- 5 files changed, 238 insertions(+), 5 deletions(-) create mode 100644 packages/compiler/src/backend/lld.test.ts create mode 100644 packages/compiler/src/backend/lld.ts diff --git a/packages/compiler/src/backend/linker.ts b/packages/compiler/src/backend/linker.ts index af53f74df..a54956ed9 100644 --- a/packages/compiler/src/backend/linker.ts +++ b/packages/compiler/src/backend/linker.ts @@ -21,6 +21,7 @@ import { import { type NativeArtifactDependency } from "./native/contracts.js"; import { RuntimePackError, stageRuntimePackArtifacts } from "./runtime-pack.js"; import type { NativeLinkPlan } from "./link-plan.js"; +import { lldLinkerArgs } from "./lld.js"; import { createDarwinDebugSymbols, installDarwinDebugSymbols, @@ -240,8 +241,11 @@ export async function linkNativeExecutable( try { const staged = await stageRuntimePackArtifacts(plan.runtimePack); stagedRoot = staged.root; + // Linux links with lld when the default driver finds it. + const lld = explicitLinker === undefined ? lldLinkerArgs(plan.target.platform, linker) : []; const args = [ ...(explicitLinker === undefined ? plan.target.defaultLinkerArgs : []), + ...lld, ...plan.driverFlags, ...plan.inputs.map((input) => staged.replacements.get(input) ?? input), ...plan.systemLibraries.map((name) => `-l${name}`), @@ -276,7 +280,15 @@ export async function linkNativeExecutable( ...(await snapshotDependencies([...toolchain, ...additionalDependencyPaths])), ]) .catch(() => null); - await execFileAsync(linker, args); + await execFileAsync(linker, args).catch(async (error: unknown) => { + // A failed link with lld runs again with the driver's default linker, + // whose error (if any) is the one reported. + if (lld.length === 0) throw error; + await execFileAsync( + linker, + args.filter((arg) => !lld.includes(arg)), + ); + }); const output = await stat(privateOut); if (!output.isFile() || output.size === 0) throw new Error("linker produced no executable"); if (plan.darwinDebugSymbols) { diff --git a/packages/compiler/src/backend/lld.test.ts b/packages/compiler/src/backend/lld.test.ts new file mode 100644 index 000000000..b0a466cf6 --- /dev/null +++ b/packages/compiler/src/backend/lld.test.ts @@ -0,0 +1,61 @@ +import { chmodSync, mkdirSync, mkdtempSync, rmSync, symlinkSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { afterEach, expect, test } from "vitest"; +import { driverFindsLld, lldLinkerArgs } from "./lld.js"; + +const directories: string[] = []; +afterEach(() => { + for (const path of directories.splice(0)) rmSync(path, { recursive: true, force: true }); +}); + +function tool(path: string): string { + writeFileSync(path, "#!/bin/sh\n"); + chmodSync(path, 0o755); + return path; +} + +function fixture() { + const root = mkdtempSync(join(tmpdir(), "scriptc-lld-")); + directories.push(root); + const llvm = join(root, "llvm", "bin"); + const usr = join(root, "usr", "bin"); + const other = join(root, "other"); + for (const directory of [llvm, usr, other]) mkdirSync(directory, { recursive: true }); + return { root, llvm, usr, other }; +} + +test.skipIf(process.platform === "win32")( + "a driver finds ld.lld beside itself, beside its real executable, or on PATH", + () => { + const f = fixture(); + const clang = tool(join(f.llvm, "clang")); + // Without ld.lld anywhere. + expect(driverFindsLld(clang, { PATH: f.other })).toBe(false); + // Beside the driver. + tool(join(f.llvm, "ld.lld")); + expect(driverFindsLld(clang, { PATH: f.other })).toBe(true); + // A PATH entry that links to the driver: clang looks beside its real executable. + symlinkSync(clang, join(f.usr, "clang")); + expect(driverFindsLld("clang", { PATH: f.usr })).toBe(true); + // A driver elsewhere finds ld.lld on PATH, and not otherwise. + const gcc = tool(join(f.other, "gcc")); + expect(driverFindsLld(gcc, { PATH: f.other })).toBe(false); + expect(driverFindsLld(gcc, { PATH: [f.other, f.llvm].join(":") })).toBe(true); + expect(driverFindsLld("missing-driver", { PATH: f.llvm })).toBe(false); + }, +); + +test.skipIf(process.platform === "win32")( + "Linux links with the default driver use lld when the driver finds it", + () => { + const f = fixture(); + const clang = tool(join(f.llvm, "clang")); + tool(join(f.llvm, "ld.lld")); + const env = { PATH: f.other }; + expect(lldLinkerArgs("linux", clang, env)).toEqual(["-fuse-ld=lld"]); + expect(lldLinkerArgs("darwin", clang, env)).toEqual([]); + expect(lldLinkerArgs("windows", clang, env)).toEqual([]); + expect(lldLinkerArgs("linux", clang, { ...env, SCRIPTC_LINKER: clang })).toEqual([]); + }, +); diff --git a/packages/compiler/src/backend/lld.ts b/packages/compiler/src/backend/lld.ts new file mode 100644 index 000000000..790e07062 --- /dev/null +++ b/packages/compiler/src/backend/lld.ts @@ -0,0 +1,49 @@ +import { realpathSync, statSync } from "node:fs"; +import { delimiter, dirname, isAbsolute, join, resolve } from "node:path"; + +function isFile(path: string): boolean { + try { + return statSync(path).isFile(); + } catch { + return false; + } +} + +/** The executable `command` names: a path, or the first match on PATH. */ +function commandFile(command: string, env: NodeJS.ProcessEnv): string | null { + if (command.includes("/")) return isFile(command) ? resolve(command) : null; + for (const directory of (env["PATH"] ?? "/usr/bin:/bin").split(delimiter)) { + const candidate = join(directory || ".", command); + if (isFile(candidate)) return isAbsolute(candidate) ? candidate : resolve(candidate); + } + return null; +} + +/** + * Whether the compiler driver `driver` finds ld.lld for `-fuse-ld=lld`: in + * the directory of the driver's executable (where clang looks first) or on + * PATH. Linking still falls back to the driver's default linker when a link + * with lld fails. + */ +export function driverFindsLld(driver: string, env: NodeJS.ProcessEnv = process.env): boolean { + const file = commandFile(driver, env); + if (file === null) return false; + try { + for (const directory of new Set([dirname(file), dirname(realpathSync(file))])) + if (isFile(join(directory, "ld.lld"))) return true; + } catch { + return false; + } + return commandFile("ld.lld", env) !== null; +} + +/** `-fuse-ld=lld` for Linux links whose driver finds ld.lld. */ +export function lldLinkerArgs( + platform: string, + driver: string, + env: NodeJS.ProcessEnv = process.env, +): string[] { + return platform === "linux" && env["SCRIPTC_LINKER"] === undefined && driverFindsLld(driver, env) + ? ["-fuse-ld=lld"] + : []; +} diff --git a/packages/compiler/src/native/compiler.test.ts b/packages/compiler/src/native/compiler.test.ts index 7a1cee62a..a085356a0 100644 --- a/packages/compiler/src/native/compiler.test.ts +++ b/packages/compiler/src/native/compiler.test.ts @@ -1,5 +1,13 @@ import { execFileSync, spawnSync } from "node:child_process"; -import { mkdirSync, mkdtempSync, readFileSync, readdirSync, rmSync, writeFileSync } from "node:fs"; +import { + chmodSync, + mkdirSync, + mkdtempSync, + readFileSync, + readdirSync, + rmSync, + writeFileSync, +} from "node:fs"; import { join } from "node:path"; import { tmpdir } from "node:os"; import { afterEach, expect, test, vi } from "vitest"; @@ -7,7 +15,7 @@ import { NativeCompiler } from "./compiler.js"; import type { NativeToolchain } from "./toolchain.js"; import { runNativeFrontend } from "../frontend/pipeline-native.js"; import { emitNativeObject } from "../backend/native-tools.js"; -import { MACOS_ARM64_TARGET } from "../backend/targets.js"; +import { LINUX_X64_GNU_TARGET, MACOS_ARM64_TARGET } from "../backend/targets.js"; import { VOID, type IrModule } from "../ir/ir.js"; import { contentDigest, NativeCache } from "./cache.js"; import { NativeExecutableCache, openNativeExecutableCache } from "./executable-cache.js"; @@ -283,3 +291,90 @@ test.each([false, true])( expect(readdirSync(directory).sort()).toEqual(["output.o", "output.o.ll"]); }, ); + +test.skipIf(process.platform === "win32").each([false, true])( + "Linux links use lld when the driver finds it, and the default linker when lld fails (%s)", + (lldFails) => { + const directory = mkdtempSync(join("/tmp", "scriptc-native-lld-")); + directories.push(directory); + const bin = join(directory, "bin"); + mkdirSync(bin); + const clang = join(bin, "clang"); + writeFileSync(clang, "#!/bin/sh\n"); + chmodSync(clang, 0o755); + writeFileSync(join(bin, "ld.lld"), "#!/bin/sh\n"); + chmodSync(join(bin, "ld.lld"), 0o755); + const entry = join(directory, "entry.ts"); + const output = join(directory, "program"); + const module: IrModule = { + irVersion: 17, + sourceFile: entry, + entry: "%main", + functions: [ + { + name: "%main", + params: [], + locals: [], + body: [], + returnType: VOID, + loc: { file: entry, start: 0, end: 0 }, + }, + ], + }; + vi.mocked(runNativeFrontend).mockReturnValue({ + preflight: [], + entryText: () => "", + entryExports: () => new Map(), + entryContract: () => { + throw new Error("unexpected contract request"); + }, + sourceTexts: () => new Map(), + npmStatic: [], + npmImportSites: new Map(), + dispose: () => {}, + lower: () => ({ + module, + diagnostics: [], + runtimeFences: [], + stats: { statementsTotal: 0, statementsFailed: 0, functionsSkipped: 0 }, + }), + }); + vi.mocked(emitNativeObject).mockImplementation((options) => { + writeFileSync(options.outputPath, "object"); + return [options.outputPath]; + }); + vi.mocked(openNativeExecutableCache).mockReturnValue(null); + const links: string[][] = []; + vi.mocked(execFileSync).mockImplementation((_command, args) => { + const list = args as string[]; + links.push(list); + if (lldFails && list.includes("-fuse-ld=lld")) throw new Error("lld failed"); + writeFileSync(list[list.indexOf("-o") + 1]!, "executable"); + return ""; + }); + const target = LINUX_X64_GNU_TARGET; + const compiler = new NativeCompiler({ + compilerVersion: "0.0.0", + target, + helper: target.helper, + ts7Executable: "unused", + helperExecutable: "unused", + helperPackageRoot: "unused", + runtimePackRoot: "unused", + linker: clang, + linkerArgs: [], + dsymutil: "unused", + }); + const result = compiler.compile(entry, { + outDir: directory, + outPath: output, + backend: "llvm", + optimization: "release", + strip: true, + }); + expect(result).toMatchObject({ ok: true, binaryPath: output }); + expect(links[0]).toContain("-fuse-ld=lld"); + expect(links.length).toBe(lldFails ? 2 : 1); + if (lldFails) expect(links[1]).not.toContain("-fuse-ld=lld"); + }, +); diff --git a/packages/compiler/src/native/compiler.ts b/packages/compiler/src/native/compiler.ts index a4582ec49..0188dccf7 100644 --- a/packages/compiler/src/native/compiler.ts +++ b/packages/compiler/src/native/compiler.ts @@ -65,6 +65,7 @@ import { import { splitLlvmLibraryProgram } from "../backend/llvm/split.js"; import { prepareNativeExecutable, prepareNativeLibrary } from "./prepare.js"; import { buildSanitizedRuntime, sanitizerDriver, sanitizerFlags } from "./sanitizer.js"; +import { lldLinkerArgs } from "../backend/lld.js"; import { openNativeExecutableCache } from "./executable-cache.js"; import { nativeFileIdentity } from "./file-identity.js"; @@ -494,8 +495,11 @@ export class NativeCompiler { : { windowsSubsystem: options.windowsSubsystem }), ...(profile?.generate === undefined ? {} : { profileGenerate: true }), }); + // Linux links with lld when the driver finds it. + const lld = options.sanitize ? [] : lldLinkerArgs(target.platform, toolchain.linker); const linkArgs = [ ...(options.sanitize ? ["-fsanitize=address"] : toolchain.linkerArgs), + ...lld, ...plan.driverFlags, ...plan.inputs, ...plan.systemLibraries.map((name) => `-l${name}`), @@ -506,8 +510,20 @@ export class NativeCompiler { timing("link-inputs"); // A successful dependency trace already produced this executable. // Keep its verified output instead of asking the linker to repeat it. - if (!cacheable) - runNativeTool(options.sanitize ? sanitizerDriver(toolchain) : toolchain.linker, linkArgs); + if (!cacheable) { + const driver = options.sanitize ? sanitizerDriver(toolchain) : toolchain.linker; + try { + runNativeTool(driver, linkArgs); + } catch (error) { + // A failed link with lld runs again with the driver's default + // linker, whose error (if any) is the one reported. + if (lld.length === 0) throw error; + runNativeTool( + driver, + linkArgs.filter((arg) => !lld.includes(arg)), + ); + } + } timing("native-link"); requireNativeArtifact(stagedOutput); if (target.platform === "darwin" && optimization === "dev" && !options.strip) { From a8c0fa772b9c14005f55e378df588059bed0cb0a Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 13:28:53 -0500 Subject: [PATCH 123/259] Use fixed timestamps in the fs.cp preserveTimestamps test --- tests/corpus/5570-fs-cp-async.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/corpus/5570-fs-cp-async.ts b/tests/corpus/5570-fs-cp-async.ts index d83750095..23747bcb3 100644 --- a/tests/corpus/5570-fs-cp-async.ts +++ b/tests/corpus/5570-fs-cp-async.ts @@ -88,8 +88,13 @@ const stamp = new Date("2021-05-06T07:08:09.123Z"); fs.utimesSync("file.txt", stamp, stamp); await fsp.cp("file.txt", "p-stamped.txt", { preserveTimestamps: true }); console.log(new Date(fs.statSync("p-stamped.txt").mtimeMs).toISOString()); +// The source tree gets fixed times: its own times come from the clock, and +// whether a copy equals them depends on their sub-millisecond digits. +fs.utimesSync("src/a.txt", stamp, stamp); +fs.utimesSync("src", stamp, stamp); await fsp.cp("src", "p-stamped-dir", { recursive: true, preserveTimestamps: true }); -console.log(fs.statSync("p-stamped-dir").mtimeMs === fs.statSync("src").mtimeMs); +for (const path of ["p-stamped-dir", "p-stamped-dir/a.txt"]) + console.log(path, new Date(fs.statSync(path).mtimeMs).toISOString()); const rejected = await fsp.cp("missing", "x").then( () => "fulfilled", From 3f03c90e864352a95c31857baf7143fd87829827 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 13:47:17 -0500 Subject: [PATCH 124/259] Keep versioned loops' slow copies free of speculative integer copies The copy of a dense-array, byte-window, counted, callback or typed-array versioned loop that runs when its guard fails no longer gives its loops speculative integer or int32 kind copies, which emitted each loop again for a path that rarely runs. Proven integer loops, which emit one copy, are kept in it. --- .../src/backend/llvm/emit-function.ts | 1 + .../src/backend/llvm/emit-statements.ts | 26 +++- packages/compiler/src/backend/llvm/emitter.ts | 3 + .../test/speculative-loop-emission.test.ts | 44 +++++- .../7902-versioned-loop-slow-copies.ts.json | 6 + .../corpus/7902-versioned-loop-slow-copies.ts | 139 ++++++++++++++++++ 6 files changed, 211 insertions(+), 8 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7902-versioned-loop-slow-copies.ts.json create mode 100644 tests/corpus/7902-versioned-loop-slow-copies.ts diff --git a/packages/compiler/src/backend/llvm/emit-function.ts b/packages/compiler/src/backend/llvm/emit-function.ts index e015c2d72..327d2019b 100644 --- a/packages/compiler/src/backend/llvm/emit-function.ts +++ b/packages/compiler/src/backend/llvm/emit-function.ts @@ -136,6 +136,7 @@ export function emitFunction(emitter: LlEmitter, fn: IrFunction): string { emitter.integerTempsEnabled = emitter.debug === null && !fn.async && !fn.generator; beginFunctionLoops(emitter, fn, numericFn); emitter.speculativeLoopsEnabled = LOOPS.of(emitter).countedLoopsEnabled; + emitter.loopCopiesEnabled = true; emitter.speculativeFunction = fn.name; emitter.speculation = null; emitter.speculationResume = null; diff --git a/packages/compiler/src/backend/llvm/emit-statements.ts b/packages/compiler/src/backend/llvm/emit-statements.ts index d356bfa3d..794ba1798 100644 --- a/packages/compiler/src/backend/llvm/emit-statements.ts +++ b/packages/compiler/src/backend/llvm/emit-statements.ts @@ -994,7 +994,7 @@ export function emitStmtBody(emitter: LlEmitter, s: IrStmt): void { LOOPS.of(emitter).denseLoopsEnabled = false; try { B.startBlock(slow); - emitter.emitStmt(s); + emitSlowCopy(emitter, s); B.br(done); B.startBlock(fast); LOOPS.of(emitter).denseLoop = dense; @@ -1018,7 +1018,7 @@ export function emitStmtBody(emitter: LlEmitter, s: IrStmt): void { LOOPS.of(emitter).byteWindowsEnabled = false; try { B.startBlock(slow); - emitter.emitStmt(s); + emitSlowCopy(emitter, s); B.br(done); B.startBlock(fast); emitter.integerRanges = window.ranges; @@ -1072,7 +1072,7 @@ export function emitStmtBody(emitter: LlEmitter, s: IrStmt): void { B.condBr(safe, fast, slow); B.startBlock(slow); LOOPS.of(emitter).countedLoopsEnabled = false; - emitter.emitStmt(s); + emitSlowCopy(emitter, s); LOOPS.of(emitter).countedLoopsEnabled = true; B.br(countedJoin); B.startBlock(fast); @@ -2049,7 +2049,7 @@ function emitCallbackVersionedLoop( emitter.callbackVersioning.add(s); try { B.startBlock(slow); - emitter.emitStmt(s); + emitSlowCopy(emitter, s); B.br(done); B.startBlock(fast); for (const { ref } of bindings) emitter.knownCallbacks.add(ref.localId); @@ -2062,6 +2062,20 @@ function emitCallbackVersionedLoop( B.startBlock(done); } +/** The copy of a versioned loop that runs when its guard fails. Its loops + * get no speculative or int32 kind copies, which would emit each loop again + * for a path that rarely runs. Proven integer loops, which emit one copy, + * are kept. */ +function emitSlowCopy(emitter: LlEmitter, s: IrStmt): void { + const copies = emitter.loopCopiesEnabled; + emitter.loopCopiesEnabled = false; + try { + emitter.emitStmt(s); + } finally { + emitter.loopCopiesEnabled = copies; + } +} + /** Entries in a row whose fast copy bailed before a speculative loop site * stops trying it. */ const SPECULATION_BAILS = 8; @@ -2089,7 +2103,7 @@ function emitVersionedLoop( LOOPS.of(emitter).bytesLoopVersioning.add(s); try { B.startBlock(slow); - emitter.emitStmt(s); + emitSlowCopy(emitter, s); B.br(done); B.startBlock(fast); emitter.bytesBounds = new Set([...originalBounds, ...version.bounds]); @@ -2120,6 +2134,7 @@ export function emitLoopCopies( const plan = allowed && emitter.speculativeLoopsEnabled && + emitter.loopCopiesEnabled && emitter.speculation === null && emitter.speculationResume === null ? planSpeculativeLoop( @@ -2147,6 +2162,7 @@ export function emitLoopCopies( const kinds = allowed && emitter.speculativeLoopsEnabled && + emitter.loopCopiesEnabled && emitter.int32Slots.checkedInt32Arrays.size > 0 && emitter.int32Kinds === null && emitter.speculation === null && diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 6729da197..e6ec6e702 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -1461,6 +1461,9 @@ export class LlEmitter { integerTempsEnabled = false; /** Speculative integer loops (speculative-integers.ts) run in this function. */ speculativeLoopsEnabled = false; + /** False inside the copy of a versioned loop that runs when its guard + * fails: loops there get no speculative or int32 kind copies. */ + loopCopiesEnabled = true; /** The fast copy of a speculative integer loop being emitted: its * integer-computed writes and where each resumes in the ordinary copy. */ speculation: { diff --git a/packages/compiler/test/speculative-loop-emission.test.ts b/packages/compiler/test/speculative-loop-emission.test.ts index a81348102..3f6aef158 100644 --- a/packages/compiler/test/speculative-loop-emission.test.ts +++ b/packages/compiler/test/speculative-loop-emission.test.ts @@ -47,9 +47,8 @@ test("a failed check finishes its iteration outside the ordinary copy", async () const llvm = await emitLlvm(source); const fn = /^define internal double @sc_bf_scaled\([^]*?^}/m.exec(llvm)?.[0] ?? ""; const order = labels(fn); - // The loop may have several speculative sites (one in each copy of a - // dense-array loop). Each site emits its ordinary copy, its third copy - // and its fast copy in that order. + // Each speculative site emits its ordinary copy, its third copy and its + // fast copy in that order. const slows = order.flatMap((l, i) => (l.startsWith("spec.slow") ? [i] : [])); expect(slows.length).toBeGreaterThan(0); let resumes = 0; @@ -91,3 +90,42 @@ test("a loop site stops entering its fast copy after repeated bails", async () = expect(fn).toMatch(new RegExp(`call i8 @llvm\\.uadd\\.sat\\.i8\\(i8 %\\S+, i8 1\\)`)); expect(fn).toContain(`store atomic i8 0, ptr ${site} unordered, align 1`); }); + +test("the slow copy of a dense-array loop has no speculative copy", async () => { + const llvm = await emitLlvm(source); + const fn = /^define internal double @sc_bf_scaled\([^]*?^}/m.exec(llvm)?.[0] ?? ""; + const order = labels(fn); + const slow = order.findIndex((l) => l.startsWith("dense.loop.slow")); + const fast = order.findIndex((l) => l.startsWith("dense.loop.fast")); + expect(slow).toBeGreaterThanOrEqual(0); + expect(fast).toBeGreaterThan(slow); + // The slow copy runs when the guard fails; only the fast copy speculates. + expect(order.slice(slow, fast).filter((l) => l.startsWith("spec."))).toEqual([]); + expect(order.slice(fast).some((l) => l.startsWith("spec.fast"))).toBe(true); + expect(llvm.match(/^@sc_spec_bails_\d+ = /gm)).toHaveLength(1); +}); + +test("the slow copy of a typed-array version keeps its proven integer loop", async () => { + // The program can start a worker, so typed-array loops are versioned on + // thread ownership. + const llvm = await emitLlvm(` +import { Worker, isMainThread } from "node:worker_threads"; +function count(bytes: Uint8Array): number { + let lines = 0; + for (let i = 0; i < bytes.length; i++) if (bytes[i] === 10) lines++; + return lines; +} +if (isMainThread) { + if (process.argv[2] === "spawn") new Worker(new URL(import.meta.url)); + console.log(count(new Uint8Array([10, 1, 10]))); +} +`); + const fn = /^define internal double @sc_bf_\w*count\([^]*?^}/m.exec(llvm)?.[0] ?? ""; + const order = labels(fn); + const slow = order.findIndex((l) => l.startsWith("bytes.version.slow")); + const fast = order.findIndex((l) => l.startsWith("bytes.version.fast")); + expect(slow).toBeGreaterThanOrEqual(0); + expect(fast).toBeGreaterThan(slow); + expect(order.slice(slow, fast).some((l) => l.startsWith("integer.leave"))).toBe(true); + expect(order.slice(fast).some((l) => l.startsWith("integer.leave"))).toBe(true); +}); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7902-versioned-loop-slow-copies.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7902-versioned-loop-slow-copies.ts.json new file mode 100644 index 000000000..0147937af --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7902-versioned-loop-slow-copies.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7902-versioned-loop-slow-copies.ts" + ], + "diags": [] +} diff --git a/tests/corpus/7902-versioned-loop-slow-copies.ts b/tests/corpus/7902-versioned-loop-slow-copies.ts new file mode 100644 index 000000000..91b769f47 --- /dev/null +++ b/tests/corpus/7902-versioned-loop-slow-copies.ts @@ -0,0 +1,139 @@ +// Loops whose versioning guard can fail, so they run the ordinary copy: +// arrays whose holes were filled later, counted loops that read past the +// end, arrays that change length inside the loop, typed-array windows past +// the end, fractional and NaN bounds, and callbacks that are replaced. The +// loops keep integer counters and sums that would also suit integer +// speculation, with values past 2^31 and 2^53, negative zero and fractions. + +function sum(values: number[]): string { + let total = 0; + let count = 0; + let seed = 12345; + let grow = 1; + for (let i = 0; i < values.length; i++) { + total += values[i]!; + count++; + seed = (seed * 1103515245 + 12345) % 2147483648; + grow = grow * 7 + i; + } + return `${total} ${count} ${seed} ${grow}`; +} + +function product(values: number[], limit: number): string { + let p = 1; + let steps = 0; + for (let i = 0; i < limit; i++) { + p *= values[i] ?? 1; + steps += 3; + } + return `${p} ${steps}`; +} + +function shrinking(values: number[]): string { + let total = 0; + for (let i = 0; i < values.length; i++) { + total += values[i]! * i; + if (values[i]! % 3 === 0) values.pop(); + } + return `${total} ${values.length}`; +} + +function windowSum(a: Int32Array, from: number, to: number): string { + let total = 0; + let mix = 1; + for (let i = from; i < to; i++) { + total += a[i] ?? -1; + mix = (mix * 31 + 17) % 65521; + } + return `${total} ${mix}`; +} + +function bytes(a: Uint8Array, start: number, n: number): string { + let hash = 0; + let steps = 0; + for (let i = start; i < start + n; i++) { + hash = (hash * 31 + (a[i] ?? 7)) | 0; + steps++; + } + return `${hash} ${steps}`; +} + +function counted(values: Float64Array, n: number, step: number): string { + let total = 0; + let odd = 0; + for (let i = 0; i < n; i += step) { + values[i] = i * 2; + total += i; + odd = odd * 2 + 1; + } + return `${total} ${odd} ${values.join()}`; +} + +function mapped(values: number[], f: (x: number) => number): string { + let total = 0; + let k = 0; + for (let i = 0; i < values.length; i++) { + total += f(values[i]!); + k = k * 10 + 1; + } + return `${total} ${k}`; +} + +function lastNegativeZero(values: number[]): string { + let last = 0; + let zero = 0; + for (let i = 0; i < values.length; i++) { + last = values[i]! * -1; + zero = zero * -1; + } + return `${Object.is(last, -0) ? "-0" : String(last)} ${Object.is(zero, -0) ? "-0" : zero}`; +} + +/** An array written out of order: index 2 first, then the hole at 1. */ +function filledLate(): number[] { + const values: number[] = [1]; + values[2] = 3; + values[1] = 2; + return values; +} + +console.log(sum([1, 2, 3, 4, 5])); +console.log(sum(filledLate())); +console.log(sum([1, 2.5, 3])); +console.log(sum([2147483647, 2147483647, 2147483647])); +console.log(sum([9007199254740991, 2, 2])); +console.log(sum(Array.from({ length: 40 }, (_, i) => (i % 2 === 0 ? i : -i)))); + +console.log(product([1, 2, 3, 4], 4)); +console.log(product([1, 2, 3, 4], 6)); +console.log(product([65536, 65536, 65536], 3)); +console.log(product([0, -1], 2), product([-1, 0], 2)); + +console.log(shrinking([1, 2, 3, 4, 5, 6, 7, 8, 9])); +console.log(shrinking([3, 3, 3, 3])); + +const ints = new Int32Array([10, 20, 30, 40]); +console.log(windowSum(ints, 0, 4), windowSum(ints, 2, 7), windowSum(ints, -2, 2)); +console.log(windowSum(ints, 0.5, 3.5), windowSum(ints, 0, NaN)); + +const text = new Uint8Array([104, 101, 108, 108, 111]); +console.log(bytes(text, 0, 5), bytes(text, 3, 5), bytes(text, -1, 3)); + +console.log(counted(new Float64Array(12), 10, 1), counted(new Float64Array(12), 10.5, 1)); +console.log(counted(new Float64Array(12), 10, 2.5), counted(new Float64Array(4), NaN, 1)); +console.log(counted(new Float64Array(4), 8, 1), counted(new Float64Array(4), 3, 0.75)); +console.log(counted(new Float64Array(60), 60, 1).split(" ").slice(0, 2).join(" ")); + +let calls = 0; +const double = (x: number): number => { + calls++; + return x * 2; +}; +const half = (x: number): number => { + calls++; + return x / 2; +}; +console.log(mapped([1, 2, 3], double), mapped([1, 2, 3], half), calls); +console.log(mapped(filledLate(), double), mapped([1, 2.5], (x) => x * x), calls); + +console.log(lastNegativeZero([1, 2, 0]), lastNegativeZero([1, 2, 3]), lastNegativeZero([])); From 40faf6a9f1b2cf2beb2e3dee7c10abf1cc735466 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 14:16:32 -0500 Subject: [PATCH 125/259] Collect the native compiler profile on the release commit The release workflow's new cli-profile job runs scripts/refresh-cli-profile.mjs on Linux x64 and uploads the profile. Every platform's native CLI build uses it through SCRIPTC_NATIVE_PROFILE_USE, and the GitHub release attaches it as scriptc--cli.profdata.gz. When the job fails, the CLI builds use the committed profile. build-native-cli.mts accepts a gzip-compressed profile in SCRIPTC_NATIVE_PROFILE_USE when the name ends in .gz. refresh-cli-profile.mjs creates the directory of --output before it starts. --- .github/workflows/release.yml | 90 ++++++++++++++++++++++++++++++++- RELEASING.md | 2 +- scripts/build-native-cli.mts | 12 +++-- scripts/refresh-cli-profile.mjs | 19 ++++--- 4 files changed, 109 insertions(+), 14 deletions(-) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fff1931ae..799337e0a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -100,10 +100,59 @@ jobs: if (receiptRun) appendFileSync(process.env.GITHUB_OUTPUT, `receipt_run=${receiptRun}\n`); NODE - build-native-packages: - name: Build native package (${{ matrix.platform }}) + # Collects the native compiler's profile on this commit + # (scripts/refresh-cli-profile.mjs), so every platform's CLI build optimizes + # with a profile of the code it compiles. The committed profile falls behind + # main within a day or two. If this job fails, the CLI builds use the + # committed profile. + cli-profile: + name: Collect the native compiler profile needs: check-release if: needs.check-release.outputs.should_release == 'true' && needs.check-release.outputs.reuse_artifacts != 'true' + runs-on: ubuntu-24.04 + timeout-minutes: 45 + continue-on-error: true + permissions: + contents: read + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v4 + with: + version: 11.1.3 + - uses: actions/setup-node@v4 + with: + node-version: "24" + cache: pnpm + - uses: ./.github/actions/llvm-linux + - run: pnpm install --frozen-lockfile + - uses: ./.github/actions/zig + - uses: ./.github/actions/native-packages + with: + target: linux-x64-gnu + - run: pnpm --filter @scriptc/compiler --filter scriptc build + - name: Check out tsc-ts + run: | + git clone --quiet --depth 1 https://github.com/vercel-labs/tsc-ts "$RUNNER_TEMP/tsc-ts" + echo "tsc-ts $(git -C "$RUNNER_TEMP/tsc-ts" rev-parse HEAD)" + npm ci --prefix "$RUNNER_TEMP/tsc-ts" + - name: Collect the profile + run: >- + node scripts/refresh-cli-profile.mjs --tsc-ts "$RUNNER_TEMP/tsc-ts" --jobs 4 + --output "$RUNNER_TEMP/cli-profile/cli.profdata.gz" + - uses: actions/upload-artifact@v4 + with: + name: cli-profile + path: ${{ runner.temp }}/cli-profile/cli.profdata.gz + retention-days: 7 + if-no-files-found: error + + build-native-packages: + name: Build native package (${{ matrix.platform }}) + needs: [check-release, cli-profile] + # Runs when the profile job fails; the CLI builds then use the committed profile. + if: >- + !cancelled() && needs.check-release.outputs.should_release == 'true' && + needs.check-release.outputs.reuse_artifacts != 'true' strategy: fail-fast: false matrix: @@ -243,6 +292,28 @@ jobs: - name: Build host helper for cross-libc bootstrap if: matrix.seed_helper != '' run: pnpm --filter @scriptc/${{ matrix.seed_helper }} build:native + - name: Download the profile collected on this commit + id: cli-profile + if: matrix.cli != '' + continue-on-error: true + uses: actions/download-artifact@v4 + with: + name: cli-profile + path: ${{ runner.temp }}/cli-profile + # Without the artifact, SCRIPTC_NATIVE_PROFILE_USE stays unset and + # build-native-cli.mts uses the committed profile. + - name: Select the native compiler profile + if: matrix.cli != '' + shell: bash + env: + COLLECTED: ${{ steps.cli-profile.outcome == 'success' && format('{0}/cli-profile/cli.profdata.gz', runner.temp) || '' }} + run: | + if [ -n "$COLLECTED" ]; then + echo "SCRIPTC_NATIVE_PROFILE_USE=$COLLECTED" >> "$GITHUB_ENV" + echo "The native CLI builds with the profile collected on $GITHUB_SHA" + else + echo "::warning::No profile was collected on this commit; the native CLI builds with the committed profile" + fi - name: Build native CLI distribution if: matrix.cli != '' env: @@ -558,6 +629,21 @@ jobs: - name: Package standalone compilers run: node scripts/package-native-cli.mjs packages /tmp/scriptc-release-assets + # The profile the native CLIs were built with. Runs that reuse native + # builds from before the cli-profile job, or whose profile job failed, + # have none; their CLIs used the committed profile. + - name: Download the native compiler profile + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + RUN: ${{ needs.check-release.outputs.artifact_run }} + VERSION: ${{ needs.check-release.outputs.version }} + run: | + if gh run download "$RUN" --repo "$GITHUB_REPOSITORY" --name cli-profile --dir "$RUNNER_TEMP/cli-profile"; then + mv "$RUNNER_TEMP/cli-profile/cli.profdata.gz" "/tmp/scriptc-release-assets/scriptc-$VERSION-cli.profdata.gz" + else + echo "Run $RUN has no cli-profile artifact" + fi + - name: Create GitHub Release run: | VERSION="${{ needs.check-release.outputs.version }}" diff --git a/RELEASING.md b/RELEASING.md index b6c5239ee..42bfe75ad 100644 --- a/RELEASING.md +++ b/RELEASING.md @@ -16,7 +16,7 @@ CI (`.github/workflows/release.yml`) compares the version in `packages/cli/packa The release job builds each pinned LLVM helper, precompiled runtime pack, and native CLI on its matching host. The native CLI bundles its TypeScript checker, LLVM helper, runtime pack, declarations, and comptime evaluator. npm postinstall installs the matching native executable; Node is needed for npm installation but not native compilation or execution. The user's toolchain performs the final platform link. Sanitized builds also use it to instrument program LLVM and compile the C runtime. Platform packages publish ahead of `@scriptc/compiler` and `scriptc`. The GitHub release attaches standalone compiler archives, their SHA-256 checksums, and the surface manifest after npm publication succeeds. -Release builds of the native CLI optimize the compiler with the committed profile `packages/compiler/native/cli.profdata` on every platform. Code the profile does not describe, or describes from older compiler sources, is optimized as without a profile. Refresh the profile on a quiet Linux x64 host when compiler code has changed substantially since the last refresh: `node scripts/refresh-cli-profile.mjs --tsc-ts ` builds an instrumented compiler, runs it on tsc-ts, a slice of the corpus, and the runtime benchmark workloads, and writes the merged sparse profile. Commit the new profile on its own. +Release builds of the native CLI optimize the compiler with a profile collected on the release commit. The `cli-profile` job runs `node scripts/refresh-cli-profile.mjs` on Linux x64, which builds an instrumented compiler, runs it on tsc-ts, a slice of the corpus, and the runtime benchmark workloads, and writes the merged sparse profile. Every platform's CLI build uses that profile (`SCRIPTC_NATIVE_PROFILE_USE`), and the GitHub release attaches it as `scriptc--cli.profdata.gz`. Code the profile does not describe, or describes from older compiler sources, is optimized as without a profile. When the profile job fails, the CLI builds use the committed profile `packages/compiler/native/cli.profdata.gz`, which local and CI builds of the native compiler also use. Refresh the committed profile when compiler code has changed substantially since the last refresh: run `node scripts/refresh-cli-profile.mjs --tsc-ts ` on a quiet Linux x64 host and commit the new profile on its own. Publishing uses npm trusted publishing (OIDC) — there is no npm token secret. Each published package must have a GitHub Actions trusted publisher for diff --git a/scripts/build-native-cli.mts b/scripts/build-native-cli.mts index e539cea1d..0b26b0965 100644 --- a/scripts/build-native-cli.mts +++ b/scripts/build-native-cli.mts @@ -17,8 +17,9 @@ const sanitize = process.env["SCRIPTC_SAN"] === "1"; // SCRIPTC_NATIVE_PROFILE_GENERATE= builds a compiler that writes a // raw profile per run (scripts/refresh-cli-profile.mjs). Optimized builds // otherwise use the committed profile, or the indexed profile that -// SCRIPTC_NATIVE_PROFILE_USE names; an empty SCRIPTC_NATIVE_PROFILE_USE -// builds without one. +// SCRIPTC_NATIVE_PROFILE_USE names (gzip-compressed when the name ends in +// .gz, as refresh-cli-profile.mjs writes it); an empty +// SCRIPTC_NATIVE_PROFILE_USE builds without one. const profileGenerate = process.env["SCRIPTC_NATIVE_PROFILE_GENERATE"] || undefined; const committedProfile = join(root, "packages/compiler/native/cli.profdata.gz"); const requestedProfile = process.env["SCRIPTC_NATIVE_PROFILE_USE"]; @@ -45,10 +46,11 @@ const seed = join(dirname(output), ".scriptc", basename(output) + "-seed"); for (const dir of [bin, lib, seed]) mkdirSync(dir, { recursive: true }); let profileUse: string | undefined; if (useProfile) { - profileUse = requestedProfile; - if (profileUse === undefined) { + profileUse = requestedProfile ?? committedProfile; + if (profileUse.endsWith(".gz")) { + const compressed = profileUse; profileUse = join(seed, "cli.profdata"); - writeFileSync(profileUse, gunzipSync(readFileSync(committedProfile))); + writeFileSync(profileUse, gunzipSync(readFileSync(compressed))); } } const compiler = process.env["SCRIPTC_CC"] ?? target.defaultLinker; diff --git a/scripts/refresh-cli-profile.mjs b/scripts/refresh-cli-profile.mjs index e9554e911..1285b5503 100644 --- a/scripts/refresh-cli-profile.mjs +++ b/scripts/refresh-cli-profile.mjs @@ -1,6 +1,8 @@ #!/usr/bin/env node -/* Refreshes packages/compiler/native/cli.profdata.gz, the profile that release - * builds of the native compiler optimize with (scripts/build-native-cli.mts). +/* Refreshes packages/compiler/native/cli.profdata.gz, the profile that builds + * of the native compiler optimize with (scripts/build-native-cli.mts). The + * release workflow's cli-profile job runs it with --output on the release + * commit, and release builds use that profile instead of the committed one. * * Builds an instrumented native compiler for this Linux host, runs it on the * training builds below, and merges the raw profiles it writes into one @@ -26,7 +28,7 @@ import { writeFileSync, } from "node:fs"; import { cpus, tmpdir } from "node:os"; -import { join, resolve } from "node:path"; +import { dirname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; import { parseArgs } from "node:util"; import { constants, gzipSync } from "node:zlib"; @@ -55,6 +57,9 @@ const tscTsPackage = join(tscTs, "packages/tsc-ts"); if (!existsSync(join(tscTsPackage, "src/main.ts"))) throw new Error(`${tscTs} is not a tsc-ts checkout with installed dependencies`); const jobs = Number(values.jobs); +// The output's directory is created up front, before the instrumented build. +const profileOutput = resolve(values.output); +mkdirSync(dirname(profileOutput), { recursive: true }); const work = resolve(values.work ?? mkdtempSync(join(tmpdir(), "scriptc-cli-profile-"))); const raw = join(work, "raw"); const builds = join(work, "builds"); @@ -196,10 +201,12 @@ const merged = spawnSync(scriptc, ["merge-profiles", "--sparse", "-o", indexed, }); if (merged.status !== 0) throw new Error("merge-profiles failed"); // The indexed profile compresses to about an eighth of its size. -const output = resolve(values.output); -writeFileSync(output, gzipSync(readFileSync(indexed), { level: constants.Z_BEST_COMPRESSION })); +writeFileSync( + profileOutput, + gzipSync(readFileSync(indexed), { level: constants.Z_BEST_COMPRESSION }), +); console.log( - `wrote ${output} (${statSync(output).size} bytes; ${statSync(indexed).size} uncompressed)`, + `wrote ${profileOutput} (${statSync(profileOutput).size} bytes; ${statSync(indexed).size} uncompressed)`, ); // A work directory the caller named stays for inspection. if (values.work === undefined) rmSync(work, { recursive: true, force: true }); From 55740d094a6b461abb886be66f395a577fe21205 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 14:33:02 -0500 Subject: [PATCH 126/259] Resolve corpus promises 7503 and 7504 with an explicit undefined tsgo checks JavaScript calls to an untyped Promise's resolve against its one parameter, so resolve() with no argument is an error there while tsc-ts accepts it. The two programs pass undefined, which both checkers accept and which settles the promise the same way. --- tests/corpus/7503-pipeline-untyped-sources.mjs | 10 +++++----- tests/corpus/7504-pipeline-untyped-source-errors.mjs | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/tests/corpus/7503-pipeline-untyped-sources.mjs b/tests/corpus/7503-pipeline-untyped-sources.mjs index 3dbc90eee..e676fd607 100644 --- a/tests/corpus/7503-pipeline-untyped-sources.mjs +++ b/tests/corpus/7503-pipeline-untyped-sources.mjs @@ -58,7 +58,7 @@ async function run(name) { queueMicrotask(() => log.push(`${name} microtask`)); pipeline(src, sink(name, objectMode), (err) => { log.push(`${name} done ${err ? err.code ?? err.message : err}`); - resolve(); + resolve(undefined); }); log.push(`${name} after call`); }); @@ -72,7 +72,7 @@ await new Promise((resolve) => src2, new Transform({ transform(c, _e, cb) { cb(null, c.toString().toUpperCase()); } }), sink("transform"), - (err) => { log.push(`transform done ${err}`); resolve(); }, + (err) => { log.push(`transform done ${err}`); resolve(undefined); }, ), ); const src3 = new Set(["f1", "f2"]); @@ -81,7 +81,7 @@ await new Promise((resolve) => src3, async function* (source) { for await (const c of source) yield c + "!"; }, sink("fnstage"), - (err) => { log.push(`fnstage done ${err}`); resolve(); }, + (err) => { log.push(`fnstage done ${err}`); resolve(undefined); }, ), ); // promises form @@ -92,11 +92,11 @@ log.push("promises resolved"); function* bad() { yield "ok"; throw new Error("source failed"); } const src5 = bad(); await new Promise((resolve) => - pipeline(src5, sink("bad"), (err) => { log.push(`bad done ${err && err.message}`); resolve(); }), + pipeline(src5, sink("bad"), (err) => { log.push(`bad done ${err && err.message}`); resolve(undefined); }), ); // a source of non-string values into a byte-mode writable const src6 = [1, 2]; await new Promise((resolve) => - pipeline(src6, sink("numbers"), (err) => { log.push(`numbers done ${err && err.code}`); resolve(); }), + pipeline(src6, sink("numbers"), (err) => { log.push(`numbers done ${err && err.code}`); resolve(undefined); }), ); console.log(log.join("\n")); diff --git a/tests/corpus/7504-pipeline-untyped-source-errors.mjs b/tests/corpus/7504-pipeline-untyped-source-errors.mjs index fcbfa9d60..9c677c011 100644 --- a/tests/corpus/7504-pipeline-untyped-source-errors.mjs +++ b/tests/corpus/7504-pipeline-untyped-source-errors.mjs @@ -30,7 +30,7 @@ await new Promise((resolve) => { }); pipeline(pick(counted("f", 5)), dst, (err) => { console.log("fail done", err && err.message); - resolve(); + resolve(undefined); }); }); @@ -45,7 +45,7 @@ await new Promise((resolve) => { }); pipeline(pick(counted("b", 3)), dst, (err) => { console.log("slow done", err); - resolve(); + resolve(undefined); }); }); @@ -85,6 +85,6 @@ await new Promise((resolve) => { pipeline( pick(new Map([["k", 1]])), new Writable({ objectMode: true, write(c, _e, cb) { console.log("map write", JSON.stringify(c)); cb(); } }), - (err) => { console.log("map done", err); resolve(); }, + (err) => { console.log("map done", err); resolve(undefined); }, ); }); From ab341be202cfcb5d56c802f994045c0c0c45a141 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 15:19:33 -0500 Subject: [PATCH 127/259] Settle BigInt quotients from the top limbs, and vectorize limb shifts A quotient-only BigInt division with a one-limb quotient returns Knuth's estimate without a pass over the operands when the top limbs prove it: with rhat * B + u0 - qhat * d0 at least qhat, a - qhat * b stays positive whatever the lower limbs hold, since they subtract less than qhat * B^(n-2). Otherwise one pass settles the estimate as before. The add and subtract loops process eight limbs a pass, which rebuilds the carry half as often. Left and right shifts, including the operand normalization of the general division, form each limb from two source limbs in a restrict-qualified helper with no dependency between limbs, so the loops vectorize. --- packages/runtime/src/scr_bigint.c | 60 +++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 18 deletions(-) diff --git a/packages/runtime/src/scr_bigint.c b/packages/runtime/src/scr_bigint.c index 5af2eafaa..69b7009fc 100644 --- a/packages/runtime/src/scr_bigint.c +++ b/packages/runtime/src/scr_bigint.c @@ -269,11 +269,15 @@ static inline bi_limb bi_subc(bi_limb x, bi_limb y, bi_limb *borrow) { static bi_limb bi_add_n(bi_limb *r, const bi_limb *a, const bi_limb *b, size_t n) { bi_limb carry = 0; size_t i = 0; - for (; i + 4 <= n; i += 4) { + for (; i + 8 <= n; i += 8) { r[i] = bi_addc(a[i], b[i], &carry); r[i + 1] = bi_addc(a[i + 1], b[i + 1], &carry); r[i + 2] = bi_addc(a[i + 2], b[i + 2], &carry); r[i + 3] = bi_addc(a[i + 3], b[i + 3], &carry); + r[i + 4] = bi_addc(a[i + 4], b[i + 4], &carry); + r[i + 5] = bi_addc(a[i + 5], b[i + 5], &carry); + r[i + 6] = bi_addc(a[i + 6], b[i + 6], &carry); + r[i + 7] = bi_addc(a[i + 7], b[i + 7], &carry); } for (; i < n; i++) r[i] = bi_addc(a[i], b[i], &carry); return carry; @@ -283,11 +287,15 @@ static bi_limb bi_add_n(bi_limb *r, const bi_limb *a, const bi_limb *b, size_t n static bi_limb bi_sub_n(bi_limb *r, const bi_limb *a, const bi_limb *b, size_t n) { bi_limb borrow = 0; size_t i = 0; - for (; i + 4 <= n; i += 4) { + for (; i + 8 <= n; i += 8) { r[i] = bi_subc(a[i], b[i], &borrow); r[i + 1] = bi_subc(a[i + 1], b[i + 1], &borrow); r[i + 2] = bi_subc(a[i + 2], b[i + 2], &borrow); r[i + 3] = bi_subc(a[i + 3], b[i + 3], &borrow); + r[i + 4] = bi_subc(a[i + 4], b[i + 4], &borrow); + r[i + 5] = bi_subc(a[i + 5], b[i + 5], &borrow); + r[i + 6] = bi_subc(a[i + 6], b[i + 6], &borrow); + r[i + 7] = bi_subc(a[i + 7], b[i + 7], &borrow); } for (; i < n; i++) r[i] = bi_subc(a[i], b[i], &borrow); return borrow; @@ -409,6 +417,23 @@ static bi_limb bi_submul1(bi_limb *r, const bi_limb *a, size_t n, bi_limb m) { return carry; } +/* y[0..n) = the low n limbs of x << shift, for 0 < shift < BI_LIMB_BITS + * and y disjoint from x. Each limb is formed from two source limbs with no + * dependency between limbs, so the loop vectorizes. */ +static void bi_lshift(bi_limb *restrict y, const bi_limb *restrict x, size_t n, unsigned shift) { + unsigned back = BI_LIMB_BITS - shift; + y[0] = x[0] << shift; + for (size_t i = 1; i < n; i++) y[i] = (x[i] << shift) | (x[i - 1] >> back); +} + +/* y[0..n) = x[0..n) >> shift, for 0 < shift < BI_LIMB_BITS and y disjoint + * from x; like bi_lshift, each limb reads two source limbs. */ +static void bi_rshift(bi_limb *restrict y, const bi_limb *restrict x, size_t n, unsigned shift) { + unsigned back = BI_LIMB_BITS - shift; + for (size_t i = 0; i + 1 < n; i++) y[i] = (x[i] >> shift) | (x[i + 1] << back); + y[n - 1] = x[n - 1] >> shift; +} + /* Schoolbook product: r[0..an+bn) = a * b, r disjoint from a and b. */ static void bi_mul_school(bi_limb *r, const bi_limb *a, size_t an, const bi_limb *b, size_t bn) { r[an] = bi_mul1(r, a, an, b[0], 0); @@ -589,11 +614,9 @@ static void bi_divmod_knuth(bi_limb *q, bi_limb *r, const bi_limb *a, size_t an, bi_limb *un = bi_limbs(an + 1 + bn); bi_limb *vn = un + an + 1; if (s) { - for (size_t i = bn - 1; i > 0; i--) vn[i] = (b[i] << s) | (b[i - 1] >> (BI_LIMB_BITS - s)); - vn[0] = b[0] << s; + bi_lshift(vn, b, bn, s); + bi_lshift(un, a, an, s); un[an] = a[an - 1] >> (BI_LIMB_BITS - s); - for (size_t i = an - 1; i > 0; i--) un[i] = (a[i] << s) | (a[i - 1] >> (BI_LIMB_BITS - s)); - un[0] = a[0] << s; } else { memcpy(vn, b, bn * sizeof(bi_limb)); memcpy(un, a, an * sizeof(bi_limb)); @@ -631,8 +654,7 @@ static void bi_divmod_knuth(bi_limb *q, bi_limb *r, const bi_limb *a, size_t an, } if (r) { if (s) { - for (size_t i = 0; i + 1 < bn; i++) r[i] = (un[i] >> s) | (un[i + 1] << (BI_LIMB_BITS - s)); - r[bn - 1] = un[bn - 1] >> s; + bi_rshift(r, un, bn, s); } else { memcpy(r, un, bn * sizeof(bi_limb)); } @@ -674,6 +696,15 @@ static bi_limb bi_div_qlimb(bi_limb *r, const bi_limb *a, const bi_limb *b, size rhat += d1; rhat_big = rhat < d1; } + /* Without a remainder, the top limbs decide when they leave room: + * a - qhat * b >= (rhat * B + u0 - qhat * d0) * B^(n-2) - qhat * B^(n-2) + * as normalized, so a margin of at least qhat proves qhat. */ + if (!r && !rhat_big) { + bi_wide top = ((bi_wide)rhat << BI_LIMB_BITS) | u0, sub = (bi_wide)qhat * d0; + if (top - sub >= qhat) return qhat; + } else if (!r) { + return qhat; /* rhat >= B: the remainder exceeds B^(n-1) >= qhat * b's low part */ + } /* a - qhat * b: negative when the product's high limb or the borrow * reaches past a's n limbs */ bi_limb carry = 0, borrow = 0; @@ -926,13 +957,8 @@ static ScrBigInt *bi_shl_abs(const ScrBigInt *a, size_t count, int sign) { if (!shift) { memcpy(r->limb + words, a->limb, a->len * sizeof(bi_limb)); } else { - bi_limb carry = 0; - for (size_t i = 0; i < a->len; i++) { - bi_limb v = a->limb[i]; - r->limb[i + words] = (v << shift) | carry; - carry = v >> (BI_LIMB_BITS - shift); - } - if (grow) r->limb[n] = carry; + bi_lshift(r->limb + words, a->limb, a->len, shift); + if (grow) r->limb[n] = a->limb[a->len - 1] >> (BI_LIMB_BITS - shift); } r->len = n + grow; r->sign = sign; @@ -955,9 +981,7 @@ static ScrBigInt *bi_shr_abs(const ScrBigInt *a, size_t count, int sign, bool *d if (!shift) { memcpy(r->limb, a->limb + words, n * sizeof(bi_limb)); } else { - for (size_t i = 0; i + 1 < n; i++) - r->limb[i] = (a->limb[i + words] >> shift) | (a->limb[i + words + 1] << (BI_LIMB_BITS - shift)); - r->limb[n - 1] = a->limb[a->len - 1] >> shift; + bi_rshift(r->limb, a->limb + words, n, shift); } return bi_finish(r, n, sign); } From 9b6a25f57e48507b2819867c03f3efc0d557ad4f Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 15:20:53 -0500 Subject: [PATCH 128/259] Resolve each package file's module edges once when pruning npm re-exports planNpmStaticReexports visited a file again each time another of its export names was demanded. Every visit resolved the file's import and export declarations again and walked its whole syntax tree for import() and require() calls. The purity check kept only pure trees and the failing root, so once a walk reached an impure file, the next namespace re-export walked the same files again. Each file's edges are now collected once per plan; the calls come from moduleSourceCandidates, which fork and worker discovery already fill. A repeated visit re-checks only the file's namespace re-exports, the only edges whose pruning depends on the demand. Purity is decided per strongly connected component of the module graph and kept for every file, and a walk that reaches an impure file marks every file on its stack impure. The pruned re-exports and the module order are unchanged. --- .../compiler/src/frontend/npm-static-prune.ts | 266 ++++++++++-------- 1 file changed, 154 insertions(+), 112 deletions(-) diff --git a/packages/compiler/src/frontend/npm-static-prune.ts b/packages/compiler/src/frontend/npm-static-prune.ts index 84a58d561..f02a6e0f6 100644 --- a/packages/compiler/src/frontend/npm-static-prune.ts +++ b/packages/compiler/src/frontend/npm-static-prune.ts @@ -11,6 +11,7 @@ import { npmStaticPackageOfPath } from "./npm-static.js"; import { trackedReadFile } from "./input-tracker.js"; import { npmPackageNameOf } from "./workspace-registry.js"; import { typeOnlyNamedImport } from "./type-only-imports.js"; +import { moduleSourceCandidates } from "./module-source-candidates.js"; export function isPrunedNpmReexport(program: ts.Program, stmt: ts.ExportDeclaration): boolean { return program.analysis.prunedNpmReexports.has(stmt); @@ -117,6 +118,21 @@ function pureExternalPackage( type Demand = Set | null; // null requests the entire namespace +/** One module edge of a package file, resolved once per plan. */ +interface ModuleEdge { + spec: string; + dep: ts.SourceFile | null; +} + +/** A file's runtime module edges: its import declarations with the names + * they request (null: the whole module), its `export … from` declarations, + * and its `import()` and `require()` calls with one string argument. */ +interface ModuleEdges { + imports: (ModuleEdge & { names: readonly string[] | null })[]; + reexports: (ModuleEdge & { stmt: ts.ExportDeclaration })[]; + calls: ModuleEdge[]; +} + /** Package files outside the demanded module graph are absent from the * executable program. All ordinary project files retain their preflight * behavior, including files not imported by the entry. */ @@ -151,6 +167,70 @@ export function planNpmStaticReexports( } }; + // The demand walk visits a file again whenever another of its names is + // requested, and every purity check walks the files it reaches: both read + // these edges instead of resolving the file's syntax each time. + const edgeMemo = new Map(); + const edgesOf = (sf: ts.SourceFile): ModuleEdges => { + const cached = edgeMemo.get(sf); + if (cached !== undefined) return cached; + const edges: ModuleEdges = { imports: [], reexports: [], calls: [] }; + for (const stmt of sf.statements.nodes) { + if (ts.isImportDeclaration(stmt)) { + if (!ts.isStringLiteral(stmt.moduleSpecifier)) continue; + const clause = stmt.importClause; + if (clause?.phaseModifier === ts.SyntaxKind.TypeKeyword) continue; + const spec = stmt.moduleSpecifier.text; + let names: string[] | null = null; + if ( + clause !== undefined && + (clause.namedBindings === undefined || + !( + ts.isNamespaceImport(clause.namedBindings) || + (ts.isNamedImports(clause.namedBindings) && + clause.namedBindings.elements.nodes.length === 0) + )) && + // `import { type A }` still loads the module, like `import {}`. + !typeOnlyNamedImport(stmt) + ) { + names = []; + if (clause.name !== undefined) names.push("default"); + if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) { + for (const element of clause.namedBindings.elements.nodes) { + if (!element.isTypeOnly) names.push((element.propertyName ?? element.name).text); + } + } + } + edges.imports.push({ spec, dep: resolveEdge(sf, spec), names }); + } else if (ts.isExportDeclaration(stmt)) { + // `export { type A } from` still loads the module under Node's + // type stripping; only `export type … from` erases. + if ( + stmt.isTypeOnly || + stmt.moduleSpecifier === undefined || + !ts.isStringLiteral(stmt.moduleSpecifier) + ) + continue; + const spec = stmt.moduleSpecifier.text; + edges.reexports.push({ spec, dep: resolveEdge(sf, spec), stmt }); + } + } + for (const node of moduleSourceCandidates(program, sf).calls) { + if (node.arguments.nodes.length !== 1) continue; + const arg = node.arguments.nodes[0]; + if (arg === undefined || !ts.isStringLiteralLike(arg)) continue; + const kind = + node.expression.kind === ts.SyntaxKind.ImportKeyword + ? "import" + : ts.isIdentifier(node.expression) && node.expression.text === "require" + ? "require" + : null; + if (kind !== null) edges.calls.push({ spec: arg.text, dep: resolveEdge(sf, arg.text, kind) }); + } + edgeMemo.set(sf, edges); + return edges; + }; + for (const sf of files) { if (npmStaticPackageOfPath(sf.fileName) === null) request(sf, null); } @@ -178,57 +258,65 @@ export function planNpmStaticReexports( return false; } }; + // An edge this program does not resolve: the conservative + // whole-dependency promise of the external package it names. + const externalPure = (sf: ts.SourceFile, spec: string): boolean => { + const resolved = resolveBareModule(sf.fileName, spec, "js-only"); + const pkg = resolved === null ? null : npmPackageNameOf(resolved.typesFile); + const root = + pkg === null || resolved === null + ? null + : packageRootJsonPath(resolved.typesFile, pkg, packageJsons); + return root !== null && pureExternalPackage(root, packageJsons); + }; // Check the actual imported closure: metadata for one file never vouches // for its side-effectful descendants, even across a package or a cycle. - const pureModuleTree = (root: ts.SourceFile): boolean => { - const cached = pureMemo.get(root); - if (cached !== undefined) return cached; - const visited = new Set(); - const visit = (sf: ts.SourceFile): boolean => { - if (visited.has(sf)) return true; - if (pureMemo.get(sf) === false || !filePure(sf)) return false; - visited.add(sf); - const edges: { spec: string; kind?: "import" | "require" }[] = []; - for (const stmt of sf.statements.nodes) { - if ( - ts.isImportDeclaration(stmt) && - stmt.importClause?.phaseModifier !== ts.SyntaxKind.TypeKeyword && - ts.isStringLiteral(stmt.moduleSpecifier) - ) - edges.push({ spec: stmt.moduleSpecifier.text }); - else if ( - ts.isExportDeclaration(stmt) && - !stmt.isTypeOnly && - stmt.moduleSpecifier && - ts.isStringLiteral(stmt.moduleSpecifier) - ) - edges.push({ spec: stmt.moduleSpecifier.text }); + // A file is pure when every file it reaches is. The walk finds the + // strongly connected components of the module graph (Tarjan): a finished + // component is pure as a whole. On the first impure file the walk stops, + // and every file still on its stack reaches that file, so each is impure. + const order = new Map(); + const stack: ts.SourceFile[] = []; + /** The lowest order the file's walk reaches (Infinity for a finished + * component), or -1 once it reaches an impure file. */ + const visit = (sf: ts.SourceFile): number => { + const known = pureMemo.get(sf); + if (known !== undefined) return known ? Infinity : -1; + const seen = order.get(sf); + if (seen !== undefined) return seen; + if (!filePure(sf)) { + pureMemo.set(sf, false); + return -1; + } + const own = order.size; + order.set(sf, own); + stack.push(sf); + let low = own; + const edges = edgesOf(sf); + for (const list of [edges.imports, edges.reexports, edges.calls]) { + for (const edge of list) { + const reached = + edge.dep !== null ? visit(edge.dep) : externalPure(sf, edge.spec) ? low : -1; + if (reached < 0) return -1; + if (reached < low) low = reached; } - ts.walkPreorder(sf, (node) => { - if (!ts.isCallExpression(node) || node.arguments.nodes.length !== 1) return; - const arg = node.arguments.nodes[0]; - if (!arg || !ts.isStringLiteralLike(arg)) return; - if (node.expression.kind === ts.SyntaxKind.ImportKeyword) - edges.push({ spec: arg.text, kind: "import" }); - else if (ts.isIdentifier(node.expression) && node.expression.text === "require") - edges.push({ spec: arg.text, kind: "require" }); - }); - return edges.every((edge) => { - const dep = resolveEdge(sf, edge.spec, edge.kind); - if (dep !== null) return visit(dep); - const resolved = resolveBareModule(sf.fileName, edge.spec, "js-only"); - const pkg = resolved === null ? null : npmPackageNameOf(resolved.typesFile); - const root = - pkg === null || resolved === null - ? null - : packageRootJsonPath(resolved.typesFile, pkg, packageJsons); - return root !== null && pureExternalPackage(root, packageJsons); - }); - }; - const pure = visit(root); - if (pure) for (const sf of visited) pureMemo.set(sf, true); - else pureMemo.set(root, false); - return pure; + } + if (low === own) { + for (;;) { + const member = stack.pop()!; + order.delete(member); + pureMemo.set(member, true); + if (member === sf) break; + } + } + return low; + }; + const pureModuleTree = (root: ts.SourceFile): boolean => { + if (visit(root) >= 0) return true; + for (const sf of stack) pureMemo.set(sf, false); + stack.length = 0; + order.clear(); + return false; }; const canPrune = ( sf: ts.SourceFile, @@ -245,78 +333,32 @@ export function planNpmStaticReexports( return names !== undefined && names !== null && !names.has(stmt.exportClause.name.text); }; + // A file is queued again only when its demand grows. Its imports and + // calls request the same modules every time; only a namespace re-export + // the new demand names stops being prunable. + const walked = new Set(); while (queue.length > 0) { const sf = queue.shift()!; - for (const stmt of sf.statements.nodes) { - if (ts.isImportDeclaration(stmt)) { - if (!ts.isStringLiteral(stmt.moduleSpecifier)) continue; - const clause = stmt.importClause; - if (clause?.phaseModifier === ts.SyntaxKind.TypeKeyword) continue; - const dep = resolveEdge(sf, stmt.moduleSpecifier.text); - if ( - clause === undefined || - (clause.namedBindings !== undefined && - (ts.isNamespaceImport(clause.namedBindings) || - (ts.isNamedImports(clause.namedBindings) && - clause.namedBindings.elements.nodes.length === 0))) || - // `import { type A }` still loads the module, like `import {}`. - typeOnlyNamedImport(stmt) - ) { - request(dep, null); - } else { - if (clause.name !== undefined) request(dep, "default"); - if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) { - for (const element of clause.namedBindings.elements.nodes) { - if (!element.isTypeOnly) request(dep, (element.propertyName ?? element.name).text); - } - } - } - } else if (ts.isExportDeclaration(stmt)) { - // `export { type A } from` still loads the module under Node's - // type stripping; only `export type … from` erases. - if ( - stmt.isTypeOnly || - stmt.moduleSpecifier === undefined || - !ts.isStringLiteral(stmt.moduleSpecifier) - ) - continue; - const dep = resolveEdge(sf, stmt.moduleSpecifier.text); - if (canPrune(sf, stmt, dep)) continue; - request(dep, null); + const edges = edgesOf(sf); + const first = !walked.has(sf); + walked.add(sf); + if (first) { + for (const edge of edges.imports) { + if (edge.names === null) request(edge.dep, null); + else for (const name of edge.names) request(edge.dep, name); } } - ts.walkPreorder(sf, (node) => { - if (!ts.isCallExpression(node) || node.arguments.nodes.length !== 1) return undefined; - const arg = node.arguments.nodes[0]; - if (arg === undefined || !ts.isStringLiteralLike(arg)) return undefined; - if ( - node.expression.kind === ts.SyntaxKind.ImportKeyword || - (ts.isIdentifier(node.expression) && node.expression.text === "require") - ) { - request( - resolveEdge( - sf, - arg.text, - node.expression.kind === ts.SyntaxKind.ImportKeyword ? "import" : "require", - ), - null, - ); - } - return undefined; - }); + for (const edge of edges.reexports) { + if (canPrune(sf, edge.stmt, edge.dep)) continue; + request(edge.dep, null); + } + if (first) for (const edge of edges.calls) request(edge.dep, null); } const pruned = new Set(); for (const sf of demanded.keys()) { - for (const stmt of sf.statements.nodes) { - if ( - !ts.isExportDeclaration(stmt) || - stmt.moduleSpecifier === undefined || - !ts.isStringLiteral(stmt.moduleSpecifier) - ) - continue; - if (canPrune(sf, stmt, resolveEdge(sf, stmt.moduleSpecifier.text))) pruned.add(stmt); - } + for (const edge of edgesOf(sf).reexports) + if (canPrune(sf, edge.stmt, edge.dep)) pruned.add(edge.stmt); } program.analysis.prunedNpmReexports.clear(); for (const stmt of pruned) program.analysis.prunedNpmReexports.add(stmt); From e5d386add79ad909c1b5d25a06ae1f2b2eed6acb Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 15:27:31 -0500 Subject: [PATCH 129/259] List caches and open pull requests in full before pruning --- .github/workflows/prune-caches.yml | 21 +++++++++++++-------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/.github/workflows/prune-caches.yml b/.github/workflows/prune-caches.yml index 008baaa43..1509d56ce 100644 --- a/.github/workflows/prune-caches.yml +++ b/.github/workflows/prune-caches.yml @@ -24,13 +24,18 @@ jobs: GH_TOKEN: ${{ github.token }} REPO: ${{ github.repository }} run: | - open=" $(gh api --paginate "repos/$REPO/pulls?state=open&per_page=100" --jq '.[].number' | tr '\n' ' ') " - gh api --paginate "repos/$REPO/actions/caches?per_page=100" \ - --jq '.actions_caches[] | select(.ref | startswith("refs/pull/")) | "\(.id) \(.ref)"' | + set -euo pipefail + # Read both lists in full before deleting anything: deleting while the cache + # listing pages shifts later pages, and a failed request must stop the job + # instead of leaving open pull requests out of the list. + open=$(gh api --paginate "repos/$REPO/pulls?state=open&per_page=100" --jq '.[].number') + caches=$(gh api --paginate "repos/$REPO/actions/caches?per_page=100" \ + --jq '.actions_caches[] | select(.ref | startswith("refs/pull/")) | "\(.id) \(.ref)"') while read -r id ref; do + [ -n "$id" ] || continue number=$(echo "$ref" | cut -d/ -f3) - case "$open" in - *" $number "*) ;; - *) gh api --method DELETE "repos/$REPO/actions/caches/$id" >/dev/null && echo "deleted cache $id ($ref)" ;; - esac - done + if ! grep -qx "$number" <<<"$open"; then + gh api --method DELETE "repos/$REPO/actions/caches/$id" >/dev/null + echo "deleted cache $id ($ref)" + fi + done <<<"$caches" From dd57655bb14bbc36cc72790b0ca1ef572d572be1 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 15:38:16 -0500 Subject: [PATCH 130/259] Parse npm-static declaration and package files only when a rewrite can apply Loading a program with --npm-static parses package files on their own before the checker reads them: - The declaration closure of each named package was walked twice, once for class overloads and once for class properties, and the one-entry parse cache could not serve the second walk. One walk now reads both from each parse. - The nullable class field and Array.find return rewrites parsed every package JavaScript file. They now parse only files whose text contains `class` and `null` (or `find`), or a Unicode escape that could spell them. - The JSDoc namepath rewrite parsed every file containing `#` or `~`. It now parses only files with a namepath segment joined by one of them (`a#b`, `a~b`), the pattern the rewrite replaces. The rewritten sources are unchanged. --- packages/compiler/src/frontend/program.ts | 43 ++++++++-------------- packages/compiler/src/frontend/services.ts | 13 ++++++- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/packages/compiler/src/frontend/program.ts b/packages/compiler/src/frontend/program.ts index 8e582af89..5a3f3d20c 100644 --- a/packages/compiler/src/frontend/program.ts +++ b/packages/compiler/src/frontend/program.ts @@ -488,43 +488,33 @@ function visitNpmStaticDeclarationClosure( visit(entryPath); } -function npmStaticDeclarationOverloadsOf( +/** The overloads and properties of the classes a package's declaration + * closure declares, read from one parse of each declaration file. */ +function npmStaticDeclarationMetadataOf( services: FrontendServices, entryPath: string, -): NpmStaticDeclarationOverloads { - const classes = new Map>(); +): { overloads: NpmStaticDeclarationOverloads; properties: NpmStaticDeclarationProperties } { + const overloads = new Map>(); + const properties = new Map>(); visitNpmStaticDeclarationClosure(services, entryPath, (path, source) => { - for (const [className, methods] of parseNpmStaticDeclarationOverloads( - services.parse(path, source, "ts"), - )) { + const sourceFile = services.parse(path, source, "ts"); + for (const [className, methods] of parseNpmStaticDeclarationOverloads(sourceFile)) { const target = - classes.get(className) ?? new Map(); - classes.set(className, target); + overloads.get(className) ?? new Map(); + overloads.set(className, target); for (const [methodName, signatures] of methods) { if (!target.has(methodName)) target.set(methodName, signatures); } } - }); - return classes; -} - -function npmStaticDeclarationPropertiesOf( - services: FrontendServices, - entryPath: string, -): NpmStaticDeclarationProperties { - const classes = new Map>(); - visitNpmStaticDeclarationClosure(services, entryPath, (path, source) => { - for (const [className, properties] of parseNpmStaticDeclarationProperties( - services.parse(path, source, "ts"), - )) { - const target = classes.get(className) ?? new Map(); - classes.set(className, target); - for (const [propertyName, type] of properties) { + for (const [className, fields] of parseNpmStaticDeclarationProperties(sourceFile)) { + const target = properties.get(className) ?? new Map(); + properties.set(className, target); + for (const [propertyName, type] of fields) { if (!target.has(propertyName)) target.set(propertyName, type); } } }); - return classes; + return { overloads, properties }; } /** See LoadResult.startupCrash: Node's exact error message, the IR error @@ -1096,8 +1086,7 @@ export function loadProgram( ) { continue; } - const overloads = npmStaticDeclarationOverloadsOf(services, resolved.typesFile); - const properties = npmStaticDeclarationPropertiesOf(services, resolved.typesFile); + const { overloads, properties } = npmStaticDeclarationMetadataOf(services, resolved.typesFile); const classNames = new Set([...overloads.keys(), ...properties.keys()]); if (classNames.size === 0) continue; const runtime = resolveBareModule(entryPath, pkg, "js-only"); diff --git a/packages/compiler/src/frontend/services.ts b/packages/compiler/src/frontend/services.ts index 14b366bfa..a0acb5818 100644 --- a/packages/compiler/src/frontend/services.ts +++ b/packages/compiler/src/frontend/services.ts @@ -20,6 +20,12 @@ import * as syntax from "./npm-static-declaration-syntax.js"; import { normalizeCjsExportsVar } from "./npm-static-cjs-exports-var.js"; import type { SourceFile } from "./ts7/ast-types.js"; +/** Whether the source can contain `word` as a keyword or identifier: it + * holds the word itself or a Unicode escape that might spell it. */ +function spells(source: string, word: string): boolean { + return source.includes(word) || source.includes("\\u"); +} + /** Evaluate an isolated, self-contained TypeScript callback under a finite * budget. Hosts supply execution; shared lowering owns capture checks and * verifies the returned value before baking it into the program. */ @@ -150,13 +156,18 @@ export class FrontendServices { return normalizeCjsExportsVar(this.parse(path, source, "js")); } nullableClassFields(path: string, source: string): syntax.NpmStaticOverloadRewrite | null { + // Rewrites `null`-initialized fields of class declarations. + if (!spells(source, "class") || !spells(source, "null")) return null; return syntax.applyNpmStaticNullableClassFields(this.parse(path, source, "js"), source); } jsDocNamepaths(path: string, source: string): string | null { - if (!source.includes("~") && !source.includes("#")) return null; + // A namepath segment joined by `#` or `~` (applyNpmStaticJsDocNamepaths). + if (!/[$\w][#~][$A-Z_a-z]/.test(source)) return null; return syntax.applyNpmStaticJsDocNamepaths(this.parse(path, source, "js"), source); } findReturnWidening(path: string, source: string): syntax.NpmStaticOverloadRewrite | null { + // Widens `find` calls returned by methods of class declarations. + if (!spells(source, "class") || !spells(source, "find")) return null; return syntax.applyNpmStaticFindReturnWidening(this.parse(path, source, "js"), source); } declarationProperties( From d4fcd787a8f6f11b3ea4a7be786b06f7d06f799c Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 15:38:37 -0500 Subject: [PATCH 131/259] Reference the unwinder weakly from the runtime's raise scr_unwind.c is linked into every Linux executable, and its references to _Unwind_ForcedUnwind and _Unwind_GetCFA pulled the unwinder out of libgcc_eh (or Zig's libunwind) even for programs that never raise, which grew a static hello world past its size ceiling. The references are now weak: programs that raise reference the personality routine from their landing pads, and its unit links the unwinder in. --- packages/runtime/src/scr_unwind.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/runtime/src/scr_unwind.c b/packages/runtime/src/scr_unwind.c index 9bdf2dbd2..50474e82e 100644 --- a/packages/runtime/src/scr_unwind.c +++ b/packages/runtime/src/scr_unwind.c @@ -10,6 +10,13 @@ #include #include +/* Weak, so the runtime unit alone does not link the unwinder into every + * program: programs that raise reference the personality routine from + * their landing pads, and its unit references the unwinder's entry points, + * which link it in. */ +#pragma weak _Unwind_ForcedUnwind +#pragma weak _Unwind_GetCFA + #if defined(__SANITIZE_ADDRESS__) #define SCR_UNWIND_ASAN 1 #elif defined(__has_feature) @@ -69,7 +76,7 @@ void scr_unwind_raise(void) { #ifdef SCR_UNWIND_ASAN scr_unwind_low = (uintptr_t)__builtin_frame_address(0); #endif - _Unwind_ForcedUnwind(exc, scr_unwind_stop, NULL); + if (_Unwind_ForcedUnwind != NULL) _Unwind_ForcedUnwind(exc, scr_unwind_stop, NULL); fputs("scriptc: the native unwinder could not raise an exception\n", stderr); abort(); } From d837036f87a64711db49b138fc5dd009b788aebe Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 24 Oct 2026 11:27:25 -0700 Subject: [PATCH 132/259] Report constant object graphs in untyped JavaScript (static objects, stage 1) SCRIPTC_DEBUG_SHAPES=const reports the constant object graphs shape inference finds (DESIGN-constant-objects.md, stage 1): objects created by code that runs at most once (module top level, IIFEs, functions reached only through one call site from such code) whose fields are written only there, that never meet a reflective or computed write, and that never escape. Namespaces (`var ns = ns || {}; ns.util = {}`), revealing modules, `module.exports` tables, and ES5 constructors' prototype objects qualify. Each near miss names its rule: allocated repeatedly, created by an init factory (one object per call site), escapes, reflective or computed write, literal form, written after init, or lazy cache. The report counts the member reads and calls a later stage can fold. The analysis now models ES5 constructors (a function's prototype object, instances reading through it) and links CommonJS require() and export bindings to the analyzed module's exports, which it previously read as nothing. Code generation is unchanged. Co-Authored-By: Claude Opus 5.5 --- .../src/frontend/shape-inference/analyze.ts | 111 ++++- .../shape-inference/constant-graphs.ts | 421 ++++++++++++++++++ .../src/frontend/shape-inference/index.ts | 11 +- .../compiler/test/constant-graphs.test.ts | 106 +++++ 4 files changed, 642 insertions(+), 7 deletions(-) create mode 100644 packages/compiler/src/frontend/shape-inference/constant-graphs.ts create mode 100644 packages/compiler/test/constant-graphs.test.ts diff --git a/packages/compiler/src/frontend/shape-inference/analyze.ts b/packages/compiler/src/frontend/shape-inference/analyze.ts index 55e0e0107..ee07098e7 100644 --- a/packages/compiler/src/frontend/shape-inference/analyze.ts +++ b/packages/compiler/src/frontend/shape-inference/analyze.ts @@ -100,6 +100,8 @@ export interface CallEdge { readonly caller: FunctionInfo | null; readonly callee: FunctionInfo; readonly inLoop: boolean; + /** The call (or `new`, getter read, builtin callback) site. */ + readonly site: Node; } export interface ShapeAnalysis { @@ -123,6 +125,10 @@ export interface ShapeAnalysis { readonly steps: number; readonly topCause: ReadonlyMap; readonly nodeLabel: ReadonlyMap; + /** Functions unknown code may call (their atoms escaped). */ + readonly escapedFunctions: ReadonlySet; + /** ES5 constructors: each function's default prototype object. */ + readonly protoOf: ReadonlyMap; } /** Array.prototype members: other names on an array are own properties. */ @@ -298,6 +304,7 @@ class Analyzer { caller: ctx?.caller ?? null, callee, inLoop: (ctx?.inLoop ?? false) || this.forceLoop, + site, }); } @@ -340,6 +347,8 @@ class Analyzer { steps: this.steps, topCause: this.topCause, nodeLabel: this.nodeLabel, + escapedFunctions: this.escapedFunctionCalls, + protoOf: this.protoOf, }; } @@ -413,6 +422,25 @@ class Analyzer { return a; } + /** ES5 constructor functions: the function's default prototype object, + * and which function each `new F()` instance atom belongs to. */ + readonly protoOf = new Map(); + readonly fnOfInstance = new Map(); + protoAtom(fn: Atom): Atom { + let p = this.protoOf.get(fn); + if (p === undefined) { + p = this.atoms.intern(`proto:${this.nodeKey(fn.node!)}:${fn.ctx ?? ""}`, () => ({ + kind: "object", + label: `${fn.label}.prototype`, + node: fn.node, + })); + this.protoOf.set(fn, p); + this.add(this.field(p, "constructor"), fn); + if (this.escaped.has(fn)) this.escape(p, `via ${fn.label}`); + } + return p; + } + builtin(path: string, receiver?: Atom): Atom { const key = receiver === undefined ? `builtin:${path}` : `builtin:${path}@${receiver.id}`; return this.atoms.intern(key, () => ({ kind: "builtin", label: path, path, receiver })); @@ -477,6 +505,11 @@ class Analyzer { if (this.escaped.has(atom)) return; this.escaped.set(atom, reason); const via = `via ${atom.label}`; + // Unknown code reaches a constructor's prototype through the function + // and through its instances. + const ctor = atom.kind === "function" ? atom : this.fnOfInstance.get(atom); + if (ctor !== undefined && ctor.node !== undefined && (atom !== ctor || this.protoOf.has(ctor))) + this.escape(this.protoAtom(ctor), via); const fm = this.fields.get(atom); if (fm !== undefined) { for (const [name, id] of fm) { @@ -1424,6 +1457,15 @@ class Analyzer { ) return this.constNode(this.top); if (ts.isSourceFile(decl) || ts.isModuleDeclaration(decl)) return this.namespaceNode(decl); + // A CommonJS export the checker resolved an import or require binding + // to (`module.exports = { name }`, `exports.name = v`): the member of the + // module's exports. + const exported = cjsExportName(decl); + if (exported !== null && decl.getSourceFile() !== id.getSourceFile()) { + const dst = this.newNode(); + this.loadConstraint(this.namespaceNode(decl.getSourceFile()), exported, dst, id); + return dst; + } return this.narrowed(id, decl, this.binding(decl)); } @@ -1531,6 +1573,9 @@ class Analyzer { } private readonly namespaces = new Map(); + /** Module namespaces: a CommonJS module's `module.exports` value is the + * namespace's `exports` field, and member reads see its members too. */ + private readonly namespaceAtoms = new Set(); /** `import * as ns`: an object whose fields are the module's exports. */ namespaceNode(mod: Node): number { const existing = this.namespaces.get(mod); @@ -1542,6 +1587,7 @@ class Analyzer { label: `namespace ${shortFile((mod as ts.SourceFile).fileName ?? "")}`, node: mod, })); + this.namespaceAtoms.add(atom); this.add(n, atom); const sym = this.checker.getSymbolAtLocation(mod); if (sym !== undefined) { @@ -1983,8 +2029,11 @@ class Analyzer { case "function": if (name === "call" || name === "apply" || name === "bind") this.add(dst, this.builtin(`function.${name}`, a)); - else if (name === "prototype") this.add(dst, this.top); - else if (name === "name") this.add(dst, this.prim("string")); + else if (name === "prototype") { + // The default prototype object, or what the program assigns. + this.add(dst, this.protoAtom(a)); + this.edge(this.field(a, "prototype"), dst); + } else if (name === "name") this.add(dst, this.prim("string")); else if (name === "length") this.add(dst, this.prim("number")); else this.edge(this.field(a, name), dst); return; @@ -1994,12 +2043,28 @@ class Analyzer { else if (ARRAY_METHODS.has(name)) this.add(dst, this.builtin(`array.${name}`, a)); else this.edge(this.field(a, name), dst); return; - case "object": + case "object": { this.edge(this.field(a, name), dst); this.edge(this.anyField(a), dst); + if (this.namespaceAtoms.has(a) && name !== "exports") { + this.loadConstraint(this.field(a, "exports"), name, dst, site); + } + // `new F()` instances read through F's prototype objects. + const fn = this.fnOfInstance.get(a); + if (fn !== undefined) { + const protos = this.newNode(); + this.add(protos, this.protoAtom(fn)); + this.edge(this.field(fn, "prototype"), protos); + this.on(protos, (proto) => { + if (proto.kind === "object") this.edge(this.field(proto, name), dst); + else if (proto.kind === "top") this.add(dst, this.top); + }); + return; + } if (name === "constructor" || name === "hasOwnProperty" || name === "toString") this.add(dst, this.builtin(`object.${name}`, a)); return; + } case "dictionary": this.edge(this.anyField(a), dst); this.edge(this.field(a, name), dst); @@ -2190,6 +2255,27 @@ class Analyzer { for (const a of args) this.sink(a, `super(...) at ${locLabel(e)}`); return dst; } + // CommonJS `require("")` of an analyzed module: its exports (the + // module's namespace, which holds `module.exports` as its `exports` + // field and the checker's view of its exports). + if (ts.isIdentifier(callee) && callee.text === "require" && e.arguments.nodes.length === 1) { + const spec = e.arguments.nodes[0]!; + if (ts.isStringLiteral(spec)) { + let target: Node | undefined; + try { + const sym = this.checker.getSymbolAtLocation(spec); + target = sym?.valueDeclaration ?? sym?.declarations[0]; + } catch { + target = undefined; + } + if (target !== undefined && ts.isSourceFile(target) && this.files.includes(target)) { + const ns = this.namespaceNode(target); + this.edge(ns, dst); + this.on(ns, (a) => this.edge(this.field(a, "exports"), dst)); + return dst; + } + } + } if (ts.isPropertyAccessExpression(callee) || ts.isElementAccessExpression(callee)) { const recvExpr = unparen(callee.expression); const { args, spread } = this.args(e); @@ -2286,6 +2372,7 @@ class Analyzer { label: `new ${a.label}`, node: a.node, })); + this.fnOfInstance.set(inst, a); this.add(dst, inst); const info = this.infoOfAtom(a); if (info !== undefined) { @@ -2862,3 +2949,21 @@ class Analyzer { } } } + +/** The export name of a CommonJS export declaration the checker resolves + * bindings to: a member of the `module.exports` literal, or the target of + * `exports.name =` / `module.exports.name =`. */ +function cjsExportName(decl: Node): string | null { + if (ts.isShorthandPropertyAssignment(decl) || ts.isPropertyAssignment(decl)) { + const n = decl.name; + return ts.isIdentifier(n) || ts.isStringLiteral(n) ? n.text : null; + } + if (ts.isPropertyAccessExpression(decl) && ts.isIdentifier(decl.name)) return decl.name.text; + if ( + ts.isBinaryExpression(decl) && + ts.isPropertyAccessExpression(decl.left) && + ts.isIdentifier(decl.left.name) + ) + return decl.left.name.text; + return null; +} diff --git a/packages/compiler/src/frontend/shape-inference/constant-graphs.ts b/packages/compiler/src/frontend/shape-inference/constant-graphs.ts new file mode 100644 index 000000000..dffa8d17d --- /dev/null +++ b/packages/compiler/src/frontend/shape-inference/constant-graphs.ts @@ -0,0 +1,421 @@ +/* Static-object specialization, stage 1 (DESIGN-constant-objects.md): + * constant object graphs. + * + * An object literal is a SINGLETON when the code that creates it runs at + * most once: at module top level, or in a function every call path to which + * starts at module evaluation through exactly one call site outside loops + * (IIFEs, revealing modules, init helpers). A singleton's field is CONSTANT + * when every store to it runs in such once-only code, no reflective or + * computed write reaches the object, and the object never escapes to code + * the analysis cannot see. A constant object has only constant fields and a + * fixed key set; constant objects whose constant fields point at each other + * form a constant graph (`ns`, `ns.util`, `ns.util.trim`). + * + * This stage computes the graphs and reports them, with the rule that + * demoted every near miss, and the reads and calls a later stage could fold. + * Nothing reaches code generation. */ +import * as ts from "../ts7/adapter.js"; +import type { Atom } from "./domain.js"; +import type { FunctionInfo, Op, ShapeAnalysis } from "./analyze.js"; +import { npmStaticPackageOfPath } from "../npm-static.js"; + +type Node = ts.Node; + +export interface ConstantField { + readonly key: string; + /** Distinct atoms the field may hold. */ + readonly values: readonly Atom[]; + /** Stores (the literal's own member included). */ + readonly stores: number; +} + +/** An object the analysis tracks as one allocation: an object literal, a + * function object (a namespace or an ES5 constructor), or a constructor's + * default prototype object. */ +export interface Candidate { + readonly atom: Atom; + /** The syntax that creates it (the literal or the function). */ + readonly node: Node; + readonly kind: "literal" | "function" | "prototype"; + /** Keys the creating syntax itself defines. */ + readonly keys: readonly string[]; + /** Whether the creating syntax is a plain data literal. */ + readonly plain: boolean; + readonly inPackage: boolean; +} + +export interface ConstantObject { + readonly site: Candidate; + readonly fields: readonly ConstantField[]; + readonly frozen: boolean; +} + +export interface NearMiss { + readonly site: Candidate; + /** Null when the whole object was demoted. */ + readonly key: string | null; + readonly rule: + | "init-factory" + | "allocated-repeatedly" + | "escapes" + | "reflective-write" + | "computed-write" + | "literal-form" + | "written-after-init" + | "lazy-cache"; + readonly detail: string; +} + +export interface ConstantGraphs { + readonly objects: readonly ConstantObject[]; + readonly nearMisses: readonly NearMiss[]; + /** Reads `e.k` whose receiver is exactly one constant object and whose + * field is constant, and the subset that are callees. */ + readonly foldableReads: number; + readonly foldableCalls: number; + /** Reads of a constant field through a receiver that may also be other + * values. */ + readonly mixedReads: number; + readonly once: (fn: Node) => boolean; +} + +function isLoop(n: Node): boolean { + return ( + ts.isForStatement(n) || + ts.isForInStatement(n) || + ts.isForOfStatement(n) || + ts.isWhileStatement(n) || + ts.isDoStatement(n) + ); +} + +/** The function (or source file) whose body contains `n`. */ +function ownerFunction(n: Node): Node { + for (let p = n.parent; p !== undefined; p = p.parent) { + if (ts.isSourceFile(p)) return p; + if (ts.isFunctionLike(p) && (p as { body?: Node }).body !== undefined) return p; + } + return n.getSourceFile(); +} + +/** Whether `n` sits in a loop of its own function's body. */ +function inLoop(n: Node, owner: Node): boolean { + for (let p = n.parent; p !== undefined && p !== owner; p = p.parent) if (isLoop(p)) return true; + return false; +} + +function loc(n: Node): string { + const sf = n.getSourceFile(); + const file = sf.fileName.split("/node_modules/").pop() ?? sf.fileName; + return `${file.split("/").slice(-2).join("/")}:${sf.getLineAndCharacterOfPosition(ts.tokenStartOfNode(n)).line + 1}`; +} + +/** `x.k || (x.k = v)`, `x.k ??= v`, `x.k ||= v`, `if (!x.k) x.k = v`. */ +function isCacheStore(write: Node): boolean { + let assign: Node | undefined = write.parent; + while (assign !== undefined && ts.isParenthesizedExpression(assign)) assign = assign.parent; + if (assign === undefined || !ts.isBinaryExpression(assign)) return false; + const op = assign.operatorToken.kind; + if (op === ts.SyntaxKind.BarBarEqualsToken || op === ts.SyntaxKind.QuestionQuestionEqualsToken) + return true; + if (op !== ts.SyntaxKind.EqualsToken) return false; + const text = write.getText(); + let up: Node | undefined = assign.parent; + while (up !== undefined && ts.isParenthesizedExpression(up)) up = up.parent; + if ( + up !== undefined && + ts.isBinaryExpression(up) && + (up.operatorToken.kind === ts.SyntaxKind.BarBarToken || + up.operatorToken.kind === ts.SyntaxKind.QuestionQuestionToken) && + up.left.getText() === text + ) + return true; + for (let p: Node | undefined = assign.parent; p !== undefined; p = p.parent) { + if (ts.isIfStatement(p)) { + const cond = p.expression.getText().replace(/\s+/g, ""); + return cond === `!${text}` || cond === `${text}===undefined` || cond === `${text}==null`; + } + if (ts.isFunctionLike(p) || ts.isSourceFile(p)) break; + } + return false; +} + +const OBJECT_DEMOTING: ReadonlySet = new Set([ + "computedWrite", + "delete", + "defineProperty", + "setPrototypeOf", + "assign", + "proxy", +]); + +export function computeConstantGraphs(analysis: ShapeAnalysis): ConstantGraphs { + const infosByNode = new Map(); + for (const info of analysis.functions.values()) { + let l = infosByNode.get(info.node); + if (l === undefined) infosByNode.set(info.node, (l = [])); + l.push(info); + } + const edgesTo = new Map(); + for (const e of analysis.calls) { + let l = edgesTo.get(e.callee.node); + if (l === undefined) edgesTo.set(e.callee.node, (l = [])); + l.push(e); + } + const escapedNodes = new Set([...analysis.escapedFunctions].map((f) => f.node)); + + const onceMemo = new Map(); + const once = (fn: Node): boolean => { + if (ts.isSourceFile(fn)) return true; + const known = onceMemo.get(fn); + if (known !== undefined) return known; + onceMemo.set(fn, false); // a cycle is not once-only + let result = false; + const edges = edgesTo.get(fn) ?? []; + if ( + infosByNode.has(fn) && + !escapedNodes.has(fn) && + edges.length > 0 && + new Set(edges.map((e) => e.site)).size === 1 + ) { + result = edges.every( + (e) => + !e.inLoop && e.caller !== null && !inLoop(e.site, e.caller.node) && once(e.caller.node), + ); + } + onceMemo.set(fn, result); + return result; + }; + + // Whether every call of a function comes from once-only code outside + // loops, through any number of call sites: an init factory, whose + // allocations are one object per call site (schema builders called at + // module initialization). + const initOnlyMemo = new Map(); + const initOnly = (fn: Node): boolean => { + if (ts.isSourceFile(fn)) return true; + const known = initOnlyMemo.get(fn); + if (known !== undefined) return known; + initOnlyMemo.set(fn, false); + const edges = edgesTo.get(fn) ?? []; + const result = + infosByNode.has(fn) && + !escapedNodes.has(fn) && + edges.length > 0 && + edges.every( + (e) => + !e.inLoop && + e.caller !== null && + !inLoop(e.site, e.caller.node) && + (once(e.caller.node) || initOnly(e.caller.node)), + ); + initOnlyMemo.set(fn, result); + return result; + }; + + const opsByAtom = new Map(); + for (const op of analysis.ops) { + for (const a of analysis.nodes[op.recv]!.atoms) { + let l = opsByAtom.get(a); + if (l === undefined) opsByAtom.set(a, (l = [])); + l.push(op); + } + } + + const objects: ConstantObject[] = []; + const nearMisses: NearMiss[] = []; + const constantKeys = new Map>(); + const candidates: Candidate[] = []; + for (const site of analysis.sites) { + if (site.kind !== "object") continue; + candidates.push({ + atom: site.atom, + node: site.node, + kind: "literal", + keys: site.keys ?? [], + plain: !( + site.hasAccessor || + site.hasComputedKey || + site.spreads.length > 0 || + site.keys === null + ), + inPackage: site.inPackage, + }); + } + const inPackage = (n: Node): boolean => + npmStaticPackageOfPath(n.getSourceFile().fileName) !== null; + for (const atom of analysis.atoms.atoms) { + if (atom.kind !== "function" || atom.node === undefined) continue; + const hasFields = (analysis.fields.get(atom)?.size ?? 0) > 0; + const proto = analysis.protoOf.get(atom); + if (!hasFields && proto === undefined) continue; + candidates.push({ + atom, + node: atom.node, + kind: "function", + keys: [], + plain: true, + inPackage: inPackage(atom.node), + }); + if (proto !== undefined) + candidates.push({ + atom: proto, + node: atom.node, + kind: "prototype", + keys: ["constructor"], + plain: true, + inPackage: inPackage(atom.node), + }); + } + for (const site of candidates) { + // A function object is created where its expression or declaration + // runs; its prototype with it. + const owner = ownerFunction(site.node); + if (!once(owner) || inLoop(site.node, owner)) { + const factory = !inLoop(site.node, owner) && initOnly(owner); + if (site.inPackage || factory) + nearMisses.push({ + site, + key: null, + rule: factory ? "init-factory" : "allocated-repeatedly", + detail: factory + ? `one object per call of ${loc(owner)} (${new Set((edgesTo.get(owner) ?? []).map((e) => e.site)).size} call sites)` + : `created in ${owner.kind === ts.SyntaxKind.SourceFile ? "a module loop" : loc(owner)}`, + }); + continue; + } + const escaped = analysis.escaped.get(site.atom); + if (escaped !== undefined) { + nearMisses.push({ site, key: null, rule: "escapes", detail: escaped }); + continue; + } + if (!site.plain) { + nearMisses.push({ + site, + key: null, + rule: "literal-form", + detail: "accessor, computed key or spread in the literal", + }); + continue; + } + const ops = opsByAtom.get(site.atom) ?? []; + const demoting = ops.find((op) => OBJECT_DEMOTING.has(op.kind)); + if (demoting !== undefined) { + nearMisses.push({ + site, + key: null, + rule: demoting.kind === "computedWrite" ? "computed-write" : "reflective-write", + detail: `${demoting.kind} at ${loc(demoting.node)}`, + }); + continue; + } + const frozen = ops.some((op) => op.kind === "freeze"); + const stores = new Map(); + for (const k of site.keys) stores.set(k, 1); + // A function's own data fields come only from stores. + const demotedKeys = new Map(); + for (const op of ops) { + // A `length` store on an object (not an array) is an ordinary write. + if ((op.kind !== "write" && op.kind !== "lengthWrite") || op.name === null) continue; + stores.set(op.name, (stores.get(op.name) ?? 0) + 1); + const fn = ownerFunction(op.node); + if (once(fn) && !inLoop(op.node, fn)) continue; + if (demotedKeys.has(op.name)) continue; + demotedKeys.set(op.name, { + site, + key: op.name, + rule: isCacheStore(op.node) ? "lazy-cache" : "written-after-init", + detail: loc(op.node), + }); + } + for (const miss of demotedKeys.values()) nearMisses.push(miss); + const fieldMap = analysis.fields.get(site.atom) ?? new Map(); + const fields: ConstantField[] = []; + const keys = new Set(); + for (const [key, count] of stores) { + if (demotedKeys.has(key)) continue; + const id = fieldMap.get(key); + const values = id === undefined ? [] : [...analysis.nodes[id]!.atoms]; + fields.push({ key, values, stores: count }); + keys.add(key); + } + constantKeys.set(site.atom, keys); + if (demotedKeys.size === 0) objects.push({ site, fields, frozen }); + } + + let foldableReads = 0, + foldableCalls = 0, + mixedReads = 0; + for (const op of analysis.ops) { + if (op.kind !== "read" || op.name === null) continue; + const atoms = analysis.nodes[op.recv]!.atoms; + const constant = [...atoms].filter((a) => constantKeys.get(a)?.has(op.name!) === true); + if (constant.length === 0) continue; + if (atoms.size === 1) { + foldableReads++; + const p = op.node.parent; + if (p !== undefined && ts.isCallExpression(p) && p.expression === op.node) foldableCalls++; + } else mixedReads++; + } + return { objects, nearMisses, foldableReads, foldableCalls, mixedReads, once }; +} + +/** Report lines (SCRIPTC_DEBUG_SHAPES=const): per package, the constant + * graphs with their roots, the near misses by rule, and the foldable reads. */ +export function constantGraphReport(analysis: ShapeAnalysis, graphs: ConstantGraphs): string[] { + const lines: string[] = []; + const pkgOf = (site: Candidate): string => + npmStaticPackageOfPath(site.node.getSourceFile().fileName) ?? ""; + const byPkg = new Map(); + const entry = (pkg: string) => { + let e = byPkg.get(pkg); + if (e === undefined) byPkg.set(pkg, (e = { objects: [], misses: [] })); + return e; + }; + for (const o of graphs.objects) entry(pkgOf(o.site)).objects.push(o); + for (const m of graphs.nearMisses) entry(pkgOf(m.site)).misses.push(m); + const constantAtoms = new Set(graphs.objects.map((o) => o.site.atom)); + const referenced = new Set(); + for (const o of graphs.objects) + for (const f of o.fields) + if (f.values.length === 1 && constantAtoms.has(f.values[0]!)) referenced.add(f.values[0]!); + const describe = (o: ConstantObject, depth: number, seen: Set): string => { + const parts = o.fields.map((f) => { + if (f.values.length !== 1) + return `${f.key}: ${f.values.length === 0 ? "?" : f.values.map((a) => a.label).join("|")}`; + const v = f.values[0]!; + const child = graphs.objects.find((x) => x.site.atom === v); + if (child !== undefined && depth < 3 && !seen.has(v)) { + seen.add(v); + return `${f.key}: ${describe(child, depth + 1, seen)}`; + } + return `${f.key}: ${v.kind === "function" && child === undefined ? "fn" : v.label}`; + }); + const shown = parts.length > 8 ? [...parts.slice(0, 8), `… ${parts.length - 8} more`] : parts; + return `{${shown.join(", ")}}${o.frozen ? " (frozen)" : ""}`; + }; + lines.push( + `analysis ${analysis.steps} steps${analysis.budgetExceeded ? " (BUDGET EXCEEDED: facts incomplete)" : ""}, ${analysis.files.length} files`, + ); + lines.push( + `constant objects ${graphs.objects.length}, near misses ${graphs.nearMisses.length}; foldable reads ${graphs.foldableReads} (calls ${graphs.foldableCalls}), mixed-receiver reads ${graphs.mixedReads}`, + ); + for (const [pkg, e] of [...byPkg].sort((a, b) => a[0].localeCompare(b[0]))) { + const fields = e.objects.reduce((n, o) => n + o.fields.length, 0); + const rules = new Map(); + for (const m of e.misses) rules.set(m.rule, (rules.get(m.rule) ?? 0) + 1); + lines.push( + `${pkg}: ${e.objects.length} constant objects (${fields} fields); near misses ${[...rules].map(([r, n]) => `${r} ${n}`).join(", ") || "none"}`, + ); + for (const o of e.objects) { + if (referenced.has(o.site.atom)) continue; + lines.push(` graph ${loc(o.site.node)} ${describe(o, 0, new Set([o.site.atom]))}`); + } + for (const m of e.misses.filter((x) => x.rule !== "allocated-repeatedly").slice(0, 40)) { + lines.push( + ` near miss ${loc(m.site.node)}${m.key === null ? "" : ` .${m.key}`}: ${m.rule} (${m.detail})`, + ); + } + } + return lines; +} diff --git a/packages/compiler/src/frontend/shape-inference/index.ts b/packages/compiler/src/frontend/shape-inference/index.ts index 88c2100ee..402a788b1 100644 --- a/packages/compiler/src/frontend/shape-inference/index.ts +++ b/packages/compiler/src/frontend/shape-inference/index.ts @@ -3,6 +3,7 @@ import type * as ts from "../ts7/adapter.js"; import { analyzeShapes } from "./analyze.js"; import { buildShapeReport } from "./report.js"; +import { computeConstantGraphs, constantGraphReport } from "./constant-graphs.js"; export { analyzeShapes } from "./analyze.js"; export { buildShapeReport } from "./report.js"; @@ -13,9 +14,11 @@ export { buildShapeReport } from "./report.js"; export function reportShapes(program: ts.Program, filter: string): void { const start = performance.now(); const analysis = analyzeShapes(program, program.getTypeChecker()); - const report = buildShapeReport(analysis, filter); + // `const`: the constant object graphs (DESIGN-constant-objects.md, stage 1). + const lines = + filter === "const" + ? constantGraphReport(analysis, computeConstantGraphs(analysis)) + : buildShapeReport(analysis, filter).lines; const ms = (performance.now() - start).toFixed(0); - process.stderr.write( - `[shapes] ${ms} ms\n${report.lines.map((l) => `[shapes] ${l}`).join("\n")}\n`, - ); + process.stderr.write(`[shapes] ${ms} ms\n${lines.map((l) => `[shapes] ${l}`).join("\n")}\n`); } diff --git a/packages/compiler/test/constant-graphs.test.ts b/packages/compiler/test/constant-graphs.test.ts new file mode 100644 index 000000000..258c83b08 --- /dev/null +++ b/packages/compiler/test/constant-graphs.test.ts @@ -0,0 +1,106 @@ +import { mkdir, mkdtemp, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { afterEach, beforeEach, expect, test, vi } from "vitest"; +import { compile } from "../src/index.js"; + +// A library in the pre-module idiom: guarded namespace declarations, a +// revealing module, an ES5 constructor with prototype methods, and the +// cases that keep an object from being constant. +const packageSource = ` +var lib = lib || {}; +lib.math = lib.math || {}; +lib.math.TAU = 6.283185307179586; +lib.math.half = function (x) { return x / 2; }; +lib.text = (function () { + function upper(s) { return s.toUpperCase(); } + return { upper: upper }; +})(); +lib.Point = function (x, y) { this.x = x; this.y = y; }; +lib.Point.prototype.norm = function () { return Math.sqrt(this.x * this.x + this.y * this.y); }; +lib.counter = { hits: 0 }; +lib.bump = function () { lib.counter.hits++; }; +lib.cache = { table: null }; +lib.lookup = function () { return lib.cache.table || (lib.cache.table = [1, 2, 3]); }; +lib.scratch = { a: 1, b: 2 }; +delete lib.scratch.b; +lib.shared = { value: 1 }; +globalThis.sharedFromLib = lib.shared; +function option(name) { return { name: name }; } +lib.options = { first: option("a"), second: option("b") }; +module.exports = { lib }; +`; + +const mainSource = ` +const { lib } = require("ns-fixture"); +let total = 0; +for (let i = 0; i < 3; i++) { + total += lib.math.half(i) + new lib.Point(i, i).norm() + lib.lookup().length; + lib.bump(); +} +console.log(total, lib.text.upper("x"), lib.counter.hits); +`; + +let dir: string; +let saved: string | undefined; +beforeEach(async () => { + dir = await mkdtemp(join(tmpdir(), "scriptc-constant-graphs-")); + const pkg = join(dir, "node_modules", "ns-fixture"); + await mkdir(pkg, { recursive: true }); + await writeFile( + join(pkg, "package.json"), + JSON.stringify({ name: "ns-fixture", version: "1.0.0", main: "index.js", types: "index.d.ts" }), + ); + await writeFile(join(pkg, "index.js"), packageSource); + await writeFile(join(pkg, "index.d.ts"), "declare const lib: any;\nexport { lib };\n"); + await writeFile( + join(dir, "package.json"), + JSON.stringify({ dependencies: { "ns-fixture": "1.0.0" } }), + ); + await writeFile(join(dir, "main.cjs"), mainSource); + saved = process.env["SCRIPTC_DEBUG_SHAPES"]; +}); +afterEach(async () => { + if (saved === undefined) delete process.env["SCRIPTC_DEBUG_SHAPES"]; + else process.env["SCRIPTC_DEBUG_SHAPES"] = saved; + vi.restoreAllMocks(); + await rm(dir, { recursive: true, force: true }); +}); + +async function report(): Promise { + process.env["SCRIPTC_DEBUG_SHAPES"] = "const"; + const lines: string[] = []; + vi.spyOn(process.stderr, "write").mockImplementation((chunk: string | Uint8Array) => { + const text = typeof chunk === "string" ? chunk : Buffer.from(chunk).toString("utf8"); + for (const l of text.split("\n")) if (l.startsWith("[shapes] ")) lines.push(l.slice(9)); + return true; + }); + await compile(join(dir, "main.cjs"), { + outDir: dir, + outPath: join(dir, "main.ir.json"), + outputKind: "ir", + npmStatic: ["ns-fixture"], + }); + return lines; +} + +test("constant graphs: namespaces, revealing modules and prototypes, with near misses", async () => { + const lines = await report(); + const text = lines.join("\n"); + // The namespace graph: guarded declarations, the revealing module's + // table, and the constructor function. + expect(text).toMatch( + /graph ns-fixture\/index\.js:\d+ \{lib: \{math: \{TAU: number, half: fn\}, text: \{upper: fn\}/, + ); + // The constructor's prototype object, built by member stores at init. + expect(text).toMatch(/graph ns-fixture\/index\.js:\d+ \{constructor: \{\}, norm: fn\}/); + // A field written by a function called from a loop. + expect(text).toMatch(/near miss ns-fixture\/index\.js:12 \.hits: written-after-init/); + // A lazily filled cache. + expect(text).toMatch(/near miss ns-fixture\/index\.js:14 \.table: lazy-cache/); + // A deleted key, and an object stored into the global object. + expect(text).toMatch(/near miss ns-fixture\/index\.js:16: reflective-write \(delete/); + expect(text).toMatch(/near miss ns-fixture\/index\.js:18: escapes/); + // A factory called from two init sites: one object per call site. + expect(text).toMatch(/near miss ns-fixture\/index\.js:20: init-factory \(.*2 call sites\)/); +}); From 5e7338ad2c5ef69402c9133bf5f18e520e40adcb Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 15:56:52 -0500 Subject: [PATCH 133/259] Scan checker reply strings with many escapes in one pass scriptc_ts7_json_value_end searched for the next quote again after each backslash escape in a string, so a string with many escapes was scanned once per escape. The quote it found now stays the candidate end until an escape skips it, and each byte of a string is scanned once by each search. A test scans strings of 2,000,000 newline, backslash and quote escapes, alone and inside an object, and compares the ends with jsonValueEnd's; before the change it does not finish within 60 s. --- packages/compiler/native/ts7-process.c | 6 +- .../test/native-json-value-end.test.ts | 75 +++++++++++++------ 2 files changed, 58 insertions(+), 23 deletions(-) diff --git a/packages/compiler/native/ts7-process.c b/packages/compiler/native/ts7-process.c index 3333cf4e8..eb90f8bd3 100644 --- a/packages/compiler/native/ts7-process.c +++ b/packages/compiler/native/ts7-process.c @@ -418,9 +418,10 @@ int32_t scriptc_ts7_json_value_end(const uint8_t *bytes, size_t size, uint32_t s uint8_t byte = bytes[index]; if (byte == '"') { index++; + // The quote found stays the candidate end until an escape skips it, so + // every byte of the string is scanned once by each search. + const uint8_t *quote = index < size ? memchr(bytes + index, '"', size - index) : NULL; for (;;) { - if (index >= size) return -1; - const uint8_t *quote = memchr(bytes + index, '"', size - index); if (quote == NULL) return -1; const uint8_t *escape = memchr(bytes + index, '\\', (size_t)(quote - (bytes + index))); if (escape == NULL) { @@ -428,6 +429,7 @@ int32_t scriptc_ts7_json_value_end(const uint8_t *bytes, size_t size, uint32_t s break; } index = (size_t)(escape - bytes) + 2; + if (bytes + index > quote) quote = index < size ? memchr(bytes + index, '"', size - index) : NULL; } index++; if (depth == 0) return (int32_t)index; diff --git a/packages/compiler/test/native-json-value-end.test.ts b/packages/compiler/test/native-json-value-end.test.ts index 9d9cc3950..0818fbab6 100644 --- a/packages/compiler/test/native-json-value-end.test.ts +++ b/packages/compiler/test/native-json-value-end.test.ts @@ -76,31 +76,45 @@ function cases(): { bytes: Uint8Array; start: number }[] { return out; } +/** The native scanner's results for `all`, from a harness built in `dir`. */ +function nativeEnds( + dir: string, + all: { bytes: Uint8Array; start: number }[], + timeout?: number, +): number[] { + const harness = join(dir, "scan" + (process.platform === "win32" ? ".exe" : "")); + execFileSync("clang", [ + "-std=c11", + "-Wall", + "-Wextra", + "-Werror", + ...(process.env["SCRIPTC_SAN"] === "1" ? ["-fsanitize=address,undefined"] : []), + join(sources, "ts7-json.test.c"), + join(sources, "ts7-process.c"), + "-o", + harness, + ]); + const chunks: Buffer[] = []; + for (const { bytes, start } of all) { + const header = Buffer.alloc(8); + header.writeUInt32LE(bytes.length, 0); + header.writeUInt32LE(start, 4); + chunks.push(header, Buffer.from(bytes)); + } + const output = execFileSync(harness, { + input: Buffer.concat(chunks), + encoding: "utf8", + maxBuffer: 64 * 1024 * 1024, + ...(timeout === undefined ? {} : { timeout }), + }); + return output.trim().split(/\r?\n/).map(Number); +} + test("the native scanner finds the value ends jsonValueEnd finds", () => { const dir = mkdtempSync(join(tempRoot, "scriptc-ts7-json-")); try { - const harness = join(dir, "scan" + (process.platform === "win32" ? ".exe" : "")); - execFileSync("clang", [ - "-std=c11", - "-Wall", - "-Wextra", - "-Werror", - ...(process.env["SCRIPTC_SAN"] === "1" ? ["-fsanitize=address,undefined"] : []), - join(sources, "ts7-json.test.c"), - join(sources, "ts7-process.c"), - "-o", - harness, - ]); const all = cases(); - const chunks: Buffer[] = []; - for (const { bytes, start } of all) { - const header = Buffer.alloc(8); - header.writeUInt32LE(bytes.length, 0); - header.writeUInt32LE(start, 4); - chunks.push(header, Buffer.from(bytes)); - } - const output = execFileSync(harness, { input: Buffer.concat(chunks), encoding: "utf8" }); - const actual = output.trim().split(/\r?\n/).map(Number); + const actual = nativeEnds(dir, all); expect(actual.length).toBe(all.length); for (let k = 0; k < all.length; k++) { const { bytes, start } = all[k]!; @@ -116,3 +130,22 @@ test("the native scanner finds the value ends jsonValueEnd finds", () => { rmSync(dir, { recursive: true, force: true }); } }); + +test("the native scanner reads strings with many escapes in one pass", () => { + const dir = mkdtempSync(join(tempRoot, "scriptc-ts7-json-")); + try { + // Strings of 2,000,000 escapes each: newlines, backslashes and quotes, + // alone and as a member of an object. + const strings = ["\\n", "\\\\", '\\"'].map((escape) => `"${escape.repeat(2_000_000)}"`); + const all = [ + ...strings.map((text) => ({ bytes: Buffer.from(text, "utf8"), start: 0 })), + ...strings.map((text) => ({ bytes: Buffer.from(`{"value":${text}},1`, "utf8"), start: 0 })), + ]; + // A scan that searched for the closing quote again after each escape + // would take minutes here. + const actual = nativeEnds(dir, all, 60_000); + expect(actual).toEqual(all.map(({ bytes, start }) => expectedEnd(bytes, start))); + } finally { + rmSync(dir, { recursive: true, force: true }); + } +}); From ebeec4818d680f09278c51aea8ae5a9126dda032 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 15:58:14 -0500 Subject: [PATCH 134/259] Prove 32-bit products exact only below 2^53 The exactness test for a product's 32-bit form multiplied the operands' magnitude bounds in a double and accepted a result of at most 2^53. A bound of 2^53 + 1 (3 * 3002399751580331) rounds to 2^53 there, so a product the double rounds took the integer multiply's low bits: `(3 * 3002399751580331) | 0` printed 1 where Node prints 0. The test is now strict: a bound below 2^53 is exact, and no bound of 2^53 or more rounds below it. --- .../src/backend/llvm/wrapping-sums.ts | 8 +++--- .../8195-wrapping-products-near-2-53.ts.json | 6 +++++ .../8195-wrapping-products-near-2-53.ts | 25 +++++++++++++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8195-wrapping-products-near-2-53.ts.json create mode 100644 tests/corpus/8195-wrapping-products-near-2-53.ts diff --git a/packages/compiler/src/backend/llvm/wrapping-sums.ts b/packages/compiler/src/backend/llvm/wrapping-sums.ts index e93d66909..5b487d809 100644 --- a/packages/compiler/src/backend/llvm/wrapping-sums.ts +++ b/packages/compiler/src/backend/llvm/wrapping-sums.ts @@ -176,12 +176,14 @@ export function emitWrappingSum( } /** Whether every product of a value in `left` and one in `right` is an - * integer of magnitude at most 2^53, which the double product holds - * exactly. */ + * integer of magnitude below 2^53, which the double product holds exactly. + * The bound's own product is computed in a double: a bound of at least + * 2^53 never rounds below 2^53, while 2^53 + 1 (3 * 3002399751580331) + * rounds to 2^53, so the test is strict. */ function exactProduct(left: IntegerRange, right: IntegerRange): boolean { const magnitude = (range: IntegerRange): number => Math.max(Math.abs(range.min), Math.abs(range.max)); - return magnitude(left) * magnitude(right) <= 2 ** 53; + return magnitude(left) * magnitude(right) < 2 ** 53; } /** The number locals of `fn` that only hold exact integers (never -0) or NaN, with the range of diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8195-wrapping-products-near-2-53.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8195-wrapping-products-near-2-53.ts.json new file mode 100644 index 000000000..234bcebd5 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8195-wrapping-products-near-2-53.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8195-wrapping-products-near-2-53.ts" + ], + "diags": [] +} diff --git a/tests/corpus/8195-wrapping-products-near-2-53.ts b/tests/corpus/8195-wrapping-products-near-2-53.ts new file mode 100644 index 000000000..c42104290 --- /dev/null +++ b/tests/corpus/8195-wrapping-products-near-2-53.ts @@ -0,0 +1,25 @@ +// Products that reach bitwise operators with operands whose ranges are +// known, around 2^53: below it the double product is exact, and from it on +// the double product rounds, so the 32-bit result comes from the rounded +// value (3 * 3002399751580331 is 2^53 + 1, which rounds to 2^53). +const pairs: [number, number][] = [ + [3, 3002399751580331], + [-3, 3002399751580331], + [2 ** 26, 2 ** 27], + [94906265, 94906267], + [94906267, 94906267], + [7, 1286742750677284], + [65535, 137443147777], +]; +for (const [a, b] of pairs) console.log(a, b, (a * b) | 0, (a * b) >>> 0, (a * b) ^ 1, (a * b) << 3); + +// The same products with literal operands, which the compiler sees whole. +console.log((3 * 3002399751580331) | 0, (3 * 3002399751580331) >>> 0); +console.log((-3 * 3002399751580331) | 0, (2 ** 26 * 2 ** 27) | 0); +console.log((94906267 * 94906267) | 0, (94906265 * 94906267) >>> 0); + +// A counted loop whose counter multiplies a constant past 2^53. +const step = 1286742750677284; +let h = 0; +for (let k = 5; k < 9; k++) h = (h + ((k * step) | 0)) | 0; +console.log(h); From d813fdafd32dfc999ca38754585f26d40acb34ae Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:00:06 -0500 Subject: [PATCH 135/259] Compare termination signals and resolve the Node checkout path in the test/parallel runner A run that a signal ends has a null exit code, so the runner recorded a pass when Node and the executable ended by different signals, or when one ended by a signal and the other with an exit code compared as null. The verdict now compares both the exit code and the signal (verdict.mjs), and records Node's signal in nodeExit as it does for the executable. A relative --node path also made the minimal lane's fixtures symlink relative to the copied tree, where it does not resolve. The checkout path is now resolved first. tests/harness/node-parallel-runner.test.ts covers both: the termination comparison, and a relative --node path whose fixtures resolve from the minimal tree. --- tests/harness/node-parallel-runner.test.ts | 52 ++++++++++++++++++++++ tests/node-parallel/README.md | 2 +- tests/node-parallel/run.mjs | 13 +++--- tests/node-parallel/verdict.mjs | 13 ++++++ 4 files changed, 73 insertions(+), 7 deletions(-) create mode 100644 tests/harness/node-parallel-runner.test.ts create mode 100644 tests/node-parallel/verdict.mjs diff --git a/tests/harness/node-parallel-runner.test.ts b/tests/harness/node-parallel-runner.test.ts new file mode 100644 index 000000000..a829c4d78 --- /dev/null +++ b/tests/harness/node-parallel-runner.test.ts @@ -0,0 +1,52 @@ +import { spawnSync } from "node:child_process"; +import { existsSync, mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join, relative, resolve } from "node:path"; +import { afterAll, expect, test } from "vitest"; +// @ts-expect-error -- a plain ESM helper of the runner script +import { sameTermination, termination } from "../node-parallel/verdict.mjs"; + +const repo = resolve(import.meta.dirname, "../.."); +const scratch = mkdtempSync(join(tmpdir(), "scriptc-node-parallel-")); +afterAll(() => rmSync(scratch, { recursive: true, force: true })); + +test("runs that end by different signals, or by a signal and an exit, differ", () => { + expect(sameTermination({ code: 0, signal: null }, { code: 0, signal: null })).toBe(true); + expect( + sameTermination({ code: null, signal: "SIGABRT" }, { code: null, signal: "SIGABRT" }), + ).toBe(true); + expect( + sameTermination({ code: null, signal: "SIGABRT" }, { code: null, signal: "SIGSEGV" }), + ).toBe(false); + expect(sameTermination({ code: 1, signal: null }, { code: null, signal: "SIGKILL" })).toBe(false); + expect(sameTermination({ code: 0, signal: null }, { code: 1, signal: null })).toBe(false); + expect(termination({ code: null, signal: "SIGSEGV" })).toBe("SIGSEGV"); + expect(termination({ code: 0, signal: null })).toBe(0); +}); + +test("a relative --node path links the checkout's fixtures into the minimal tree", () => { + const checkout = join(scratch, "node"); + mkdirSync(join(checkout, "test", "parallel"), { recursive: true }); + mkdirSync(join(checkout, "test", "fixtures"), { recursive: true }); + mkdirSync(join(checkout, "test", "common"), { recursive: true }); + writeFileSync(join(checkout, "test", "fixtures", "marker.txt"), "fixture\n"); + writeFileSync(join(checkout, "test", "common", "fixtures.js"), "module.exports = {};\n"); + const out = join(scratch, "out"); + const result = spawnSync( + process.execPath, + [ + join(repo, "tests/node-parallel/run.mjs"), + "--node", + relative(scratch, checkout), + "--pattern", + "^no-such-test$", + "--out", + out, + ], + { cwd: scratch, encoding: "utf8" }, + ); + expect(result.status, result.stderr).toBe(0); + const linked = join(out, "tree", "test", "fixtures", "marker.txt"); + expect(existsSync(linked)).toBe(true); + expect(readFileSync(linked, "utf8")).toBe("fixture\n"); +}); diff --git a/tests/node-parallel/README.md b/tests/node-parallel/README.md index 35af64464..c8ac12134 100644 --- a/tests/node-parallel/README.md +++ b/tests/node-parallel/README.md @@ -1,6 +1,6 @@ # Node test/parallel files -`run.mjs` builds files from a Node.js checkout's `test/parallel` with scriptc, runs each executable in that directory, and compares its exit status with Node's. It records a verdict per file: `pass` (same exit status), `fail` (different exit status), or `refused` (the build failed), with the first error line. +`run.mjs` builds files from a Node.js checkout's `test/parallel` with scriptc, runs each executable in that directory, and compares its exit status with Node's. It records a verdict per file: `pass` (the same exit code, or the same terminating signal), `fail` (a different exit code or signal), or `refused` (the build failed), with the first error line. ```bash git clone --depth 1 --branch v24.22.0 https://github.com/nodejs/node /path/to/node diff --git a/tests/node-parallel/run.mjs b/tests/node-parallel/run.mjs index 4f2230c6b..e7a1e3cec 100644 --- a/tests/node-parallel/run.mjs +++ b/tests/node-parallel/run.mjs @@ -14,6 +14,7 @@ import { import { dirname, join, resolve } from "node:path"; import { fileURLToPath } from "node:url"; import { parseArgs } from "node:util"; +import { sameTermination, termination } from "./verdict.mjs"; const here = dirname(fileURLToPath(import.meta.url)); const repo = resolve(here, "../.."); @@ -33,9 +34,9 @@ if (!values.node || !values.pattern || !["minimal", "node"].includes(values.comm ); process.exit(2); } -const nodeTest = existsSync(join(values.node, "test", "parallel")) - ? join(values.node, "test") - : values.node; +// Absolute, so the minimal lane's fixtures symlink resolves from the tree. +const nodeRoot = resolve(values.node); +const nodeTest = existsSync(join(nodeRoot, "test", "parallel")) ? join(nodeRoot, "test") : nodeRoot; const pattern = new RegExp(values.pattern); const out = resolve(values.out); mkdirSync(out, { recursive: true }); @@ -96,15 +97,15 @@ async function one(file) { cwd: dir, timeout: 900_000, }); - const result = { file, flags: flags.join(" "), nodeExit: node.code }; + const result = { file, flags: flags.join(" "), nodeExit: termination(node) }; if (build.code !== 0) { result.verdict = "refused"; result.cause = firstCause(build.stdout + build.stderr); return result; } const native = await run(exe, [], { cwd: dir, timeout: 120_000 }); - result.exit = native.code ?? native.signal; - result.verdict = native.code === node.code ? "pass" : "fail"; + result.exit = termination(native); + result.verdict = sameTermination(node, native) ? "pass" : "fail"; if (result.verdict !== "pass") result.cause = firstCause(native.stderr + native.stdout); return result; } diff --git a/tests/node-parallel/verdict.mjs b/tests/node-parallel/verdict.mjs new file mode 100644 index 000000000..392238f44 --- /dev/null +++ b/tests/node-parallel/verdict.mjs @@ -0,0 +1,13 @@ +// How two runs of one test file compare (run.mjs). + +/** Whether Node and the executable ended the same way: the same exit code, + * or the same terminating signal (an exit code is null when a signal ended + * the process). */ +export function sameTermination(node, native) { + return node.code === native.code && node.signal === native.signal; +} + +/** An exit code, or the signal that ended the process. */ +export function termination(result) { + return result.code ?? result.signal; +} From 190fb8d58e75f0165e7be2b973bc32a802a3aac8 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:01:33 -0500 Subject: [PATCH 136/259] Mix weak-collection hashes in 64 bits on 32-bit targets uintptr_t is 32 bits on wasm32, where the weak-collection hashes shifted it by 33 and 56 bits. The hashes now widen keys, owners and kinds to uint64_t before mixing; 64-bit targets compute the same values as before. --- packages/runtime/src/scr_json.c | 11 +++++---- packages/runtime/test/json.test.ts | 31 ++++++++++++++++++++++++- tests/harness/wasi-differential.test.ts | 3 +++ 3 files changed, 40 insertions(+), 5 deletions(-) diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index afe3315de..7df866a4c 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -16157,16 +16157,19 @@ typedef struct { void *key; ScrWeakEntry *head; } ScrWeakKeySlot; static SCR_TL ScrWeakKeySlot *scr_weak_keys; static SCR_TL size_t scr_weak_keys_mask, scr_weak_keys_used; -static inline size_t scr_weak_mix(uintptr_t bits) { +/* Mixed in 64 bits on every target: uintptr_t is 32 bits on wasm32, where + * these shifts would exceed its width. */ +static inline size_t scr_weak_mix(uint64_t bits) { bits ^= bits >> 33; - bits *= 0xff51afd7ed558ccdull; + bits *= UINT64_C(0xff51afd7ed558ccd); bits ^= bits >> 29; return (size_t)bits; } static inline size_t scr_weak_entry_hash(const ScrWeakMap *owner, const void *key, unsigned kind) { - return scr_weak_mix((uintptr_t)key ^ ((uintptr_t)owner * 0x9E3779B97F4A7C15ull) ^ ((uintptr_t)kind << 56)); + return scr_weak_mix((uint64_t)(uintptr_t)key ^ ((uint64_t)(uintptr_t)owner * UINT64_C(0x9E3779B97F4A7C15)) ^ + ((uint64_t)kind << 56)); } -static inline size_t scr_weak_key_hash(const void *key) { return scr_weak_mix((uintptr_t)key); } +static inline size_t scr_weak_key_hash(const void *key) { return scr_weak_mix((uint64_t)(uintptr_t)key); } static void scr_weak_index_put(ScrWeakEntry *entry) { size_t j = scr_weak_entry_hash(entry->owner, entry->key, entry->kind) & scr_weak_index_mask; diff --git a/packages/runtime/test/json.test.ts b/packages/runtime/test/json.test.ts index 3315cb415..f83f5ad65 100644 --- a/packages/runtime/test/json.test.ts +++ b/packages/runtime/test/json.test.ts @@ -1,4 +1,4 @@ -import { execFile } from "node:child_process"; +import { execFile, execFileSync } from "node:child_process"; import { mkdir } from "node:fs/promises"; import { join } from "node:path"; import { promisify } from "node:util"; @@ -85,3 +85,32 @@ test("json runtime: parser, dyn, dynCheck failure path, stringify buffer", async ].join("\n"), ); }); + +function zigOnPath(): boolean { + try { + execFileSync("zig", ["version"], { stdio: "ignore" }); + return true; + } catch { + return false; + } +} + +// 32-bit uintptr_t: the weak-collection hashes mix in 64 bits, so no shift +// exceeds the width of its operand on wasm32. +test.skipIf(!zigOnPath())("json runtime builds for wasm32 without oversized shifts", async () => { + await execFileAsync("zig", [ + "cc", + "-target", + "wasm32-wasi", + "-std=c11", + "-O2", + "-D_GNU_SOURCE", + "-D_WASI_EMULATED_SIGNAL", + "-D_WASI_EMULATED_PROCESS_CLOCKS", + "-Werror=shift-count-overflow", + "-c", + "-o", + join(testDir, "build", "scr_json.wasm32.o"), + join(testDir, "../src/scr_json.c"), + ]); +}); diff --git a/tests/harness/wasi-differential.test.ts b/tests/harness/wasi-differential.test.ts index 5d814b384..66c2934f2 100644 --- a/tests/harness/wasi-differential.test.ts +++ b/tests/harness/wasi-differential.test.ts @@ -313,6 +313,9 @@ describe.skipIf(!zigOnPath())("wasm32-wasi differential", () => { // ThreadSlots blocks and pages hold 32-bit pointers. "5727-thread-slots-basics.ts", "5729-thread-slots-values.ts", + // Weak-collection hashes mix 32-bit pointers in 64 bits. + "4591-weak-keys-union-records.ts", + "7742-weak-collections-many-keys.ts", ])("the LLVM target runs %s byte-identically to Node", async (fixture) => { const entry = join(repoRoot, "tests/corpus", fixture); const outDir = await mkdtemp("/tmp/scriptc-wasi-"); From 1d579ea5a2ba93fb7073e0656720cc9fe91e12e9 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:05:19 -0500 Subject: [PATCH 137/259] Check the identity of the open file a runtime pack artifact is read from Staging stat'ed an artifact's path, read the path, and stat'ed it again. When the path was a symbolic link switched to another file of the same size during the read and back before the second stat, both identities were those of the verified file, so the bytes of the other file were staged without hashing. Staging now opens the artifact once and takes both identities from the open file with fstat, so they describe the file the bytes come from. A test switches the artifact's link to a same-sized file during the read and checks that the staged copy has the verified bytes. --- .../src/backend/runtime-pack-native.test.ts | 50 ++++++++++++++++++- .../src/backend/runtime-pack-native.ts | 20 ++++++-- 2 files changed, 65 insertions(+), 5 deletions(-) diff --git a/packages/compiler/src/backend/runtime-pack-native.test.ts b/packages/compiler/src/backend/runtime-pack-native.test.ts index 723deba39..293d814b8 100644 --- a/packages/compiler/src/backend/runtime-pack-native.test.ts +++ b/packages/compiler/src/backend/runtime-pack-native.test.ts @@ -1,5 +1,14 @@ import { createHash } from "node:crypto"; -import { mkdirSync, readFileSync, renameSync, statSync, utimesSync, writeFileSync } from "node:fs"; +import { + mkdirSync, + readFileSync, + renameSync, + statSync, + symlinkSync, + unlinkSync, + utimesSync, + writeFileSync, +} from "node:fs"; import { mkdtemp, rm } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; @@ -21,6 +30,10 @@ vi.mock("node:crypto", async (original) => { const crypto = await original(); return { ...crypto, createHash: vi.fn(crypto.createHash) }; }); +vi.mock("node:fs", async (original) => { + const fs = await original(); + return { ...fs, readFileSync: vi.fn(fs.readFileSync) }; +}); const dirs: string[] = []; afterEach(async () => @@ -192,3 +205,38 @@ test("staging does not hash an unchanged artifact again", async () => { expect(hashes() - start).toBe(firstStage - 1); expect(readFileSync(staged.runtimeObjects[0]!, "utf8")).toBe("base object"); }); + +test.skipIf(process.platform === "win32")( + "staging reads an artifact's bytes from the file whose identity it checks", + async () => { + const f = await packFixture(); + // The artifact path is a symbolic link to the verified file. + const real = f.object + ".real"; + renameSync(f.object, real); + symlinkSync(real, f.object); + const selection = f.select(); + f.stage(selection); + // During the next read the link names another file of the same size, + // and it names the verified file again before the read ends. + const other = f.object + ".other"; + writeFileSync(other, "x".repeat(statSync(real).size)); + const read = vi.mocked(readFileSync); + const original = read.getMockImplementation()!; + read.mockImplementation(((source: Parameters[0], ...rest: unknown[]) => { + if (typeof source === "string" && !source.endsWith("base.o")) + return (original as (...args: unknown[]) => unknown)(source, ...rest); + read.mockImplementation(original); + unlinkSync(f.object); + symlinkSync(other, f.object); + try { + return (original as (...args: unknown[]) => unknown)(source, ...rest); + } finally { + unlinkSync(f.object); + symlinkSync(real, f.object); + } + }) as typeof readFileSync); + const staged = f.stage(selection); + expect(read.getMockImplementation()).toBe(original); + expect(readFileSync(staged.runtimeObjects[0]!, "utf8")).toBe("base object"); + }, +); diff --git a/packages/compiler/src/backend/runtime-pack-native.ts b/packages/compiler/src/backend/runtime-pack-native.ts index f51b24221..0fff34455 100644 --- a/packages/compiler/src/backend/runtime-pack-native.ts +++ b/packages/compiler/src/backend/runtime-pack-native.ts @@ -9,11 +9,13 @@ import { closeSync, constants, existsSync, + fstatSync, mkdirSync, openSync, readFileSync, statSync, writeSync, + type Stats, } from "node:fs"; import { dirname, join } from "node:path"; import type { NativeLinkFeatures } from "./native-link-info.js"; @@ -62,7 +64,10 @@ interface FileIdentity { } function fileIdentity(path: string): FileIdentity { - const info = statSync(path); + return statsIdentity(statSync(path)); +} + +function statsIdentity(info: Stats): FileIdentity { return { dev: info.dev, ino: info.ino, @@ -256,9 +261,16 @@ function stageArtifact( let before: FileIdentity; let after: FileIdentity; try { - before = fileIdentity(source); - bytes = readFileSync(source); - after = fileIdentity(source); + // The identities are those of the open file the bytes come from, also + // when the path is a symbolic link that changes during the read. + const input = openSync(source, constants.O_RDONLY); + try { + before = statsIdentity(fstatSync(input)); + bytes = readFileSync(input); + after = statsIdentity(fstatSync(input)); + } finally { + closeSync(input); + } } catch { throw new RuntimePackError(`runtime pack artifact is missing: ${artifact.path}`, "invalid"); } From 70f565177e1823c1a67853b9fe46da50e8572fae Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:05:36 -0500 Subject: [PATCH 138/259] Count profile-annotated functions when the annotation runs The match report counted the functions with profile counts after the whole pipeline, so an annotated function that inlining or dead code elimination later removed was not counted, while the annotation's mismatch and missing-function warnings were. A pass-instrumentation callback now counts the annotated functions right after PGOInstrumentationUse runs, in the one-module and the partitioned pipelines. A new test builds helpers that reach the annotation and are then inlined into main and deleted, and checks that the report counts them. --- native/llvm-codegen/src/emit.cpp | 23 +++- packages/compiler/test/native-profile.test.ts | 100 +++++++++++++++++- 2 files changed, 114 insertions(+), 9 deletions(-) diff --git a/native/llvm-codegen/src/emit.cpp b/native/llvm-codegen/src/emit.cpp index 35d7ce4f0..14bcd1522 100644 --- a/native/llvm-codegen/src/emit.cpp +++ b/native/llvm-codegen/src/emit.cpp @@ -296,6 +296,7 @@ std::optional inspectProfile(const EmitOptions &Options) { // Owns the analysis managers a pipeline needs for one module. struct Pipeline { + PassInstrumentationCallbacks Callbacks; LoopAnalysisManager LAM; FunctionAnalysisManager FAM; CGSCCAnalysisManager CGAM; @@ -304,13 +305,26 @@ struct Pipeline { Pipeline(TargetMachine &Machine, OptimizationLevel Level, std::optional Profile = std::nullopt) - : PB(&Machine, tuningFor(Level), std::move(Profile)) { + : PB(&Machine, tuningFor(Level), std::move(Profile), &Callbacks) { PB.registerModuleAnalyses(MAM); PB.registerCGSCCAnalyses(CGAM); PB.registerFunctionAnalyses(FAM); PB.registerLoopAnalyses(LAM); PB.crossRegisterProxies(LAM, FAM, CGAM, MAM); } + + // Adds to Count the functions the profile annotation gave counts to, as + // soon as that pass has run: inlining and dead code elimination later in + // the pipeline delete annotated functions. + void countAnnotated(std::atomic &Count) { + Callbacks.registerAfterPassCallback( + [&Count](StringRef PassID, Any IR, const PreservedAnalyses &) { + if (PassID != "PGOInstrumentationUse") + return; + if (const auto *M = llvm::any_cast(&IR)) + Count += annotatedFunctions(**M); + }); + } }; std::optional verify(Module &M, StringRef Code) { @@ -499,9 +513,9 @@ emitModule(Module &M, TargetMachine &Machine, OptimizationLevel Level, M.getContext().setDiagnosticHandler( std::make_unique(Match)); Pipeline P(Machine, Level, std::move(Profile)); - P.PB.buildPerModuleDefaultPipeline(Level).run(M, P.MAM); if (Annotating) - Match.Annotated += annotatedFunctions(M); + P.countAnnotated(Match.Annotated); + P.PB.buildPerModuleDefaultPipeline(Level).run(M, P.MAM); if (std::optional Failure = verify(M, "post_optimization_verification_failed")) return Failure; @@ -716,6 +730,8 @@ compileOptimizedPartitions(const EmitOptions &Options, // Profile instrumentation or annotation happens here, before the thin // link; the post-link optimization reads the annotated weights. Pipeline P(*Machine, Level, profileOptions(Options)); + if (Annotating) + P.countAnnotated(PartitionMatch.Annotated); ModulePassManager MPM = P.PB.buildThinLTOPreLinkDefaultPipeline(Level); MPM.addPass(BitcodeWriterPass(Stream, /*ShouldPreserveUseListOrder=*/false, /*EmitSummaryIndex=*/true, @@ -723,7 +739,6 @@ compileOptimizedPartitions(const EmitOptions &Options, MPM.run(Mod, P.MAM); } if (Annotating) { - PartitionMatch.Annotated += annotatedFunctions(Mod); Match.add(PartitionMatch); // Stored before the summary, so a reused summary finds its counts. Cache.store(Key, "match", PartitionMatch.serialize()); diff --git a/packages/compiler/test/native-profile.test.ts b/packages/compiler/test/native-profile.test.ts index 53d077017..9d04739d0 100644 --- a/packages/compiler/test/native-profile.test.ts +++ b/packages/compiler/test/native-profile.test.ts @@ -110,6 +110,65 @@ function expectedExit(argc: number, edit = 0): number { return Number(total % 251n); } +const INLINED = 6; + +/** A program whose helpers are too large for the inliner that runs before the + * profile annotation and each called twice, so they reach the annotation, + * and which the profile-guided inliner then inlines into their hot call + * sites in `main` and deletes. */ +function inlinedProgram(): string { + const lines = ["; profiled program, helpers inlined after annotation"]; + for (let index = 0; index < INLINED; index++) { + lines.push( + `define internal i64 @g${index}(i64 %n) {`, + "entry:", + " %x0 = add i64 %n, " + index, + ); + for (let step = 1; step <= 40; step++) + lines.push(` %x${step} = ${step % 2 === 0 ? "xor" : "mul"} i64 %x${step - 1}, ${step + 3}`); + lines.push(" ret i64 %x40", "}"); + } + lines.push( + "define i32 @main(i32 %argc, ptr %argv) {", + "entry:", + " %wide = sext i32 %argc to i64", + " %limit = mul i64 %wide, 1000", + " br label %loop", + "loop:", + " %i = phi i64 [ 0, %entry ], [ %next, %loop ]", + " %total = phi i64 [ 0, %entry ], [ %grown, %loop ]", + ...Array.from({ length: INLINED }, (_, index) => [ + ` %a${index} = call i64 @g${index}(i64 %i)`, + ` %b${index} = call i64 @g${index}(i64 %a${index})`, + ` %t${index} = add i64 ${index === 0 ? "%total" : `%t${index - 1}`}, %b${index}`, + ]).flat(), + ` %grown = add i64 %t${INLINED - 1}, 0`, + " %next = add i64 %i, 1", + " %again = icmp ult i64 %next, %limit", + " br i1 %again, label %loop, label %exit", + "exit:", + " %low = urem i64 %grown, 251", + " %code = trunc i64 %low to i32", + " ret i32 %code", + "}", + ); + return lines.join("\n") + "\n"; +} + +function inlinedExit(argc: number): number { + const mask = (1n << 64n) - 1n; + const g = (index: number, n: bigint) => { + let x = (n + BigInt(index)) & mask; + for (let step = 1; step <= 40; step++) + x = step % 2 === 0 ? x ^ BigInt(step + 3) : (x * BigInt(step + 3)) & mask; + return x; + }; + let total = 0n; + for (let i = 0n; i < BigInt(argc * 1000); i++) + for (let index = 0; index < INLINED; index++) total = (total + g(index, g(index, i))) & mask; + return Number(total % 251n); +} + type EmitOptions = { outputs: number; name: string; @@ -119,12 +178,17 @@ type EmitOptions = { }; async function emit(dir: string, source: string, options: EmitOptions): Promise { + return (await emitReporting(dir, source, options)).outputs; +} + +/** `emit`, also returning the helper's stdout (its profile match report). */ +async function emitReporting(dir: string, source: string, options: EmitOptions) { const input = join(dir, `${options.name}.ll`); await writeFile(input, source); const outputs = Array.from({ length: options.outputs }, (_, index) => join(dir, `${options.name}.${index}.o`), ); - await execFileAsync(helper!, [ + const { stdout } = await execFileAsync(helper!, [ "emit", "--input", input, @@ -145,7 +209,7 @@ async function emit(dir: string, source: string, options: EmitOptions): Promise< ...(options.use === undefined ? [] : ["--profile-use", options.use]), ...(options.cache === undefined ? [] : ["--cache-dir", options.cache]), ]); - return outputs; + return { outputs, stdout }; } async function link(dir: string, objects: string[], name: string, instrumented = false) { @@ -181,12 +245,18 @@ async function merge(output: string, inputs: string[]) { /** An instrumented build of `source` run with 1 and 3 arguments, its raw * profiles merged into one indexed profile. */ -async function collect(dir: string, source: string, outputs: number, name: string) { +async function collect( + dir: string, + source: string, + outputs: number, + name: string, + expected: (argc: number) => number = expectedExit, +) { const raw = join(dir, `${name}-raw`); const objects = await emit(dir, source, { outputs, name, generate: join(raw, "%p.profraw") }); const executable = await link(dir, objects, name, true); - expect(await run(executable, 1)).toBe(expectedExit(1)); - expect(await run(executable, 3)).toBe(expectedExit(3)); + expect(await run(executable, 1)).toBe(expected(1)); + expect(await run(executable, 3)).toBe(expected(3)); const profiles = (await readdir(raw)).map((file) => join(raw, file)); expect(profiles).toHaveLength(2); const profile = join(dir, `${name}.profdata`); @@ -286,6 +356,26 @@ describe.runIf(helper !== null)("LLVM profile-guided optimization", () => { expect(await run(await link(dir, objects, "edited"), 2)).toBe(expectedExit(2, 7)); }); + test("the match report counts annotated functions that inlining removes", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-profile-match-")); + dirs.push(dir); + const { profile } = await collect(dir, inlinedProgram(), 1, "train", inlinedExit); + const { outputs, stdout } = await emitReporting(dir, inlinedProgram(), { + outputs: 1, + name: "guided", + use: profile, + }); + expect(await run(await link(dir, outputs, "guided"), 2)).toBe(inlinedExit(2)); + // Every g and main received counts, though optimization then + // inlined the helpers into main and deleted them. + expect(JSON.parse(stdout.trim().split("\n").at(-1)!)).toEqual({ + ok: true, + profile: { annotated: INLINED + 1, mismatched: 0, missing: 0, unknown_partitions: 0 }, + }); + const symbols = await execFileAsync("nm", [outputs[0]!]); + expect(symbols.stdout).not.toMatch(/\bg\d\b/); + }); + test("the profile keys the partition cache", async () => { const dir = await mkdtemp(join(tmpdir(), "scriptc-profile-cache-")); dirs.push(dir); From 530bd9534ffc45ca8a29db5c971b533c407d55d6 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:10:00 -0500 Subject: [PATCH 139/259] Await the values of untyped sync pipeline sources An untyped pipeline source that is a sync iterable passed each value on as it came, so a promise reached the next stage as the promise: a byte-mode destination refused it and an object-mode one received it. for await over a sync iterator, which Node's pipeline pumps it with, awaits each value. The source's generator now awaits a value that is an object (a promise included) before yielding it, and a rejection closes the source, as Node's async-from-sync iterator does. --- .../src/frontend/lowering/lower-stream.ts | 44 ++++++++++++++++++- .../7504-pipeline-untyped-source-errors.mjs | 27 +++++++++++- 2 files changed, 69 insertions(+), 2 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/lower-stream.ts b/packages/compiler/src/frontend/lowering/lower-stream.ts index 72bea5dd7..b519ce378 100644 --- a/packages/compiler/src/frontend/lowering/lower-stream.ts +++ b/packages/compiler/src/frontend/lowering/lower-stream.ts @@ -3947,11 +3947,13 @@ function lowerDynIterableSource( const syncId = frame.local("sync", BOOL, false); const nextId = frame.local("next", DYN, false); const stepId = frame.local("step", DYN, true); + const valueId = frame.local("value", DYN, true); const activeId = frame.local("active", BOOL, true); const closeId = frame.local("close", DYN, false); const it = (): IrExpr => varRef(itId, DYN, loc); const sync = (): IrExpr => varRef(syncId, BOOL, loc); const step = (): IrExpr => varRef(stepId, DYN, loc); + const value = (): IrExpr => varRef(valueId, DYN, loc); const get = (obj: IrExpr, name: string): IrExpr => ({ kind: "dynKeyGet", value: obj, @@ -4011,6 +4013,7 @@ function lowerDynIterableSource( }, { kind: "varDecl", localId: nextId, init: get(it(), "next"), loc }, { kind: "varDecl", localId: stepId, init: dynUndefinedExpr(loc), loc }, + { kind: "varDecl", localId: valueId, init: dynUndefinedExpr(loc), loc }, { kind: "varDecl", localId: activeId, init: boolLit(false, loc), loc }, { kind: "tryCatch", @@ -4055,9 +4058,48 @@ function lowerDynIterableSource( loc, }, setActive(true), + { kind: "assign", localId: valueId, value: get(step(), "value"), loc }, + // for await over a sync iterator awaits each value + // (CreateAsyncFromSyncIterator): a promise or a thenable + // passes on its result, and a rejection closes the iterator + { + kind: "if", + cond: { + kind: "logical", + op: "&&", + left: sync(), + right: { + kind: "logical", + op: "||", + left: { kind: "dynTest", test: "promise", value: value(), type: BOOL, loc }, + right: { + kind: "logical", + op: "&&", + left: { + kind: "dynTest", + test: "nullish", + negated: true, + value: value(), + type: BOOL, + loc, + }, + right: { kind: "dynTest", test: "object", value: value(), type: BOOL, loc }, + type: BOOL, + loc, + }, + type: BOOL, + loc, + }, + type: BOOL, + loc, + }, + then: [{ kind: "assign", localId: valueId, value: awaitDyn(value()), loc }], + else_: null, + loc, + }, { kind: "exprStmt", - expr: { kind: "yieldExpr", value: get(step(), "value"), type: VOID, loc }, + expr: { kind: "yieldExpr", value: value(), type: VOID, loc }, loc, }, ], diff --git a/tests/corpus/7504-pipeline-untyped-source-errors.mjs b/tests/corpus/7504-pipeline-untyped-source-errors.mjs index 9c677c011..3ee984547 100644 --- a/tests/corpus/7504-pipeline-untyped-source-errors.mjs +++ b/tests/corpus/7504-pipeline-untyped-source-errors.mjs @@ -1,6 +1,7 @@ // pipeline() over untyped iterable sources: a destination that fails closes // the source, backpressure waits for drain, an abort signal stops the pump, -// and async generator and Map sources reach object-mode destinations. +// async generator and Map sources reach object-mode destinations, and a +// sync source's promise values are awaited. import { pipeline, Writable, PassThrough } from "node:stream"; import { pipeline as pipelineP } from "node:stream/promises"; @@ -88,3 +89,27 @@ await new Promise((resolve) => { (err) => { console.log("map done", err); resolve(undefined); }, ); }); + +// sync sources whose values are promises: each value is awaited, as +// for await over a sync iterator does, and a rejection closes the source +await pipelineP( + pick([Promise.resolve("p1"), "p2", new Promise((r) => setTimeout(() => r("p3"), 1))]), + new Writable({ write(c, _e, cb) { console.log("byte write", String(c)); cb(); } }), +); +function* promised() { + try { + yield Promise.resolve({ n: 1 }); + yield Promise.reject(new Error("value rejected")); + yield "never"; + } finally { + console.log("promised finally"); + } +} +try { + await pipelineP( + pick(promised()), + new Writable({ objectMode: true, write(c, _e, cb) { console.log("object write", JSON.stringify(c)); cb(); } }), + ); +} catch (err) { + console.log("promised rejected", err.message); +} From 317162af78f367342ff8a06b46779f9c4e2b5e9d Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:13:05 -0500 Subject: [PATCH 140/259] Count repeated calls through constructors, apply and per-value callbacks The constant-graph pass treats a function whose call edges all run once at initialization as init-only. Some calls recorded no edge or a once-only one: - `new F()` of an ES5 constructor and `f.apply(thisArg, args)` bound the arguments without a call edge, so a function also called directly once was init-only even when a loop constructed or applied it. - Callbacks of Array.from, toSorted, replace and replaceAll run once per element, comparison or match, but those methods were missing from the repeating callback set. - JSON.parse revivers, JSON.stringify replacers and toJSON methods run once per value; their edges at the JSON call site now count as repeated, including toJSON calls resolved after the call's handling. Objects these functions write or allocate were reported as constant, and their reads as foldable. constant-graphs.test.ts covers each case. --- .../src/frontend/shape-inference/analyze.ts | 15 +++++++- .../compiler/test/constant-graphs.test.ts | 37 +++++++++++++++++++ 2 files changed, 51 insertions(+), 1 deletion(-) diff --git a/packages/compiler/src/frontend/shape-inference/analyze.ts b/packages/compiler/src/frontend/shape-inference/analyze.ts index 98ec87099..8b1101da2 100644 --- a/packages/compiler/src/frontend/shape-inference/analyze.ts +++ b/packages/compiler/src/frontend/shape-inference/analyze.ts @@ -252,6 +252,10 @@ const LOOP_CALLBACK_METHODS: ReadonlySet = new Set([ "reduceRight", "flatMap", "sort", + "toSorted", + "from", + "replace", + "replaceAll", ]); export function analyzeShapes(program: ts.Program, checker: ts.TypeChecker): ShapeAnalysis { @@ -298,12 +302,17 @@ class Analyzer { this.siteCtx.set(site, { caller: this.currentFn, inLoop: this.loopDepth > 0 }); } + /** Builtin calls that invoke their callbacks once per value + * (JSON.parse revivers, JSON.stringify replacers and toJSON methods), + * which may run after the call's own handling. */ + private readonly repeatingSites = new Set(); + edgeFor(site: Node, callee: FunctionInfo): void { const ctx = this.siteCtx.get(site); this.calls.push({ caller: ctx?.caller ?? null, callee, - inLoop: (ctx?.inLoop ?? false) || this.forceLoop, + inLoop: (ctx?.inLoop ?? false) || this.forceLoop || this.repeatingSites.has(site), site, }); } @@ -2547,6 +2556,7 @@ class Analyzer { this.add(info.thisNode, inst); this.bindArgs(info, args, spread); this.edge(info.ret, dst); + this.edgeFor(e, info); } return; } @@ -2894,6 +2904,7 @@ class Analyzer { for (const p of info.params) if (args[1] !== undefined) this.iterateInto(args[1], p, site); this.edge(info.ret, dst); + this.edgeFor(site, info); } return; } @@ -3034,6 +3045,7 @@ class Analyzer { // result. const revived = this.newNode(); this.add(revived, this.top); + this.repeatingSites.add(site); if (args[1] !== undefined) this.on(args[1], (f) => { if (f.kind === "function") @@ -3057,6 +3069,7 @@ class Analyzer { // Their results are serialized in turn. const serialized = this.newNode(); this.childrenInto(serialized); + this.repeatingSites.add(site); this.edge(arg(0), serialized); const key = this.constNode(this.prim("string")); this.on(serialized, (v) => this.callToJSON(v, key, serialized, site)); diff --git a/packages/compiler/test/constant-graphs.test.ts b/packages/compiler/test/constant-graphs.test.ts index 258c83b08..a89276ce7 100644 --- a/packages/compiler/test/constant-graphs.test.ts +++ b/packages/compiler/test/constant-graphs.test.ts @@ -104,3 +104,40 @@ test("constant graphs: namespaces, revealing modules and prototypes, with near m // A factory called from two init sites: one object per call site. expect(text).toMatch(/near miss ns-fixture\/index\.js:20: init-factory \(.*2 call sites\)/); }); + +// Functions that one call site runs repeatedly: an ES5 constructor and an +// apply call in a loop, and builtin callbacks that run once per element, +// match or parsed value. +const repeatedSource = ` +var lib = {}; +lib.newState = { v: 0 }; +function bumpNew() { lib.newState.v++; } +bumpNew(); +lib.applyState = { v: 0 }; +function bumpApply() { lib.applyState.v++; } +bumpApply(); +lib.repeat = function () { for (var i = 0; i < 3; i++) { new bumpNew(); bumpApply.apply(null, []); } }; +lib.seen = { match: null, pair: null, mapped: null, key: null }; +lib.replaced = "a-b".replace(/\\\\w/g, function (m) { lib.seen.match = { m: m }; return m; }); +lib.sorted = [3, 1, 2].toSorted(function (a, b) { lib.seen.pair = { a: a }; return a - b; }); +lib.mapped = Array.from([1, 2], function (x) { lib.seen.mapped = { x: x }; return x; }); +lib.revived = JSON.parse('{"a":{"b":1}}', function (k, v) { lib.seen.key = { k: k }; return v; }); +module.exports = { lib }; +`; + +test("constant graphs: constructors, apply calls and callbacks that one site runs repeatedly", async () => { + await writeFile(join(dir, "node_modules", "ns-fixture", "index.js"), repeatedSource); + await writeFile( + join(dir, "main.cjs"), + 'const { lib } = require("ns-fixture");\nlib.repeat();\nconsole.log(lib.newState.v, lib.applyState.v, lib.replaced, lib.sorted, lib.mapped, lib.revived);\n', + ); + const text = (await report()).join("\n"); + // `new bumpNew()` and `bumpApply.apply(...)` in a loop write after init. + expect(text).toMatch(/near miss ns-fixture\/index\.js:3 \.v: written-after-init/); + expect(text).toMatch(/near miss ns-fixture\/index\.js:6 \.v: written-after-init/); + // Each callback runs once per match, comparison, element or parsed value. + for (const field of ["match", "pair", "mapped", "key"]) + expect(text).toMatch( + new RegExp(`near miss ns-fixture/index\\.js:10 \\.${field}: written-after-init`), + ); +}); From 8f3c2c28d625015a93bb15acbc3cdb5fb1c20d9a Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:14:15 -0500 Subject: [PATCH 141/259] Count comparator calls in AArch64 and Mach-O assembly The string comparison emission test matched only x86-64 `call` instructions to unprefixed symbols, so on AArch64 and macOS hosts it counted no calls and failed its positive-count check. It now also matches AArch64 `bl` and Mach-O's leading underscore, and it runs for the host and for aarch64-linux-gnu and x86_64-macos assembly, so every host checks all three spellings. --- tests/harness/string-compare-emission.test.ts | 35 ++++++++++++++----- 1 file changed, 26 insertions(+), 9 deletions(-) diff --git a/tests/harness/string-compare-emission.test.ts b/tests/harness/string-compare-emission.test.ts index 2654f56ba..1a8fdddf6 100644 --- a/tests/harness/string-compare-emission.test.ts +++ b/tests/harness/string-compare-emission.test.ts @@ -11,17 +11,23 @@ import { compile } from "@scriptc/compiler"; const repoRoot = join(import.meta.dirname, "../.."); const cacheDir = join(repoRoot, "node_modules/.cache/scriptc-tests"); -async function emittedAsm(name: string, source: string): Promise { - const key = createHash("sha256").update(source).digest("hex").slice(0, 16); +async function emittedAsm(name: string, source: string, target: string): Promise { + const key = createHash("sha256").update(target).update(source).digest("hex").slice(0, 16); const outDir = join(cacheDir, `string-compare-${key}`); mkdirSync(outDir, { recursive: true }); const file = join(outDir, `${name}.ts`); writeFileSync(file, source); + const saved = process.env["SCRIPTC_TARGET"]; + if (target === "host") delete process.env["SCRIPTC_TARGET"]; + else process.env["SCRIPTC_TARGET"] = target; const result = await compile(file, { outPath: join(outDir, name), outDir, backend: "llvm", outputKind: "asm", + }).finally(() => { + if (saved === undefined) delete process.env["SCRIPTC_TARGET"]; + else process.env["SCRIPTC_TARGET"] = saved; }); if (!result.ok) throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); @@ -36,12 +42,23 @@ words.sort(order); console.log(words.join(",")); `; +// Calls to the comparison runtime: `call`/`callq` on x86-64 and `bl` on +// AArch64, with Mach-O's leading underscore on macOS. const compareCalls = (asm: string): number => - asm.match(/\bcall[a-z]*\s+(?:sc_str_cmp_u16|scr_str_cmp_u16_bytes|scr_str_cmp)\b/g)?.length ?? 0; + asm.match( + /\b(?:call[a-z]*|bl)\s+_?(?:sc_str_cmp_u16|scr_str_cmp_u16_bytes|scr_str_cmp)\b/g, + )?.length ?? 0; -test("a three-way string comparator compares its pair once", async () => { - const once = compareCalls(await emittedAsm("once", program("a < b ? -1 : 1"))); - const both = compareCalls(await emittedAsm("both", program("a < b ? -1 : a > b ? 1 : 0"))); - expect(once).toBeGreaterThan(0); - expect(both).toBe(once); -}); +// The host's assembly, and two other targets' so that every host checks the +// x86-64, AArch64 and Mach-O spellings. +test.each(["host", "aarch64-linux-gnu", "x86_64-macos"])( + "a three-way string comparator compares its pair once (%s)", + async (target) => { + const once = compareCalls(await emittedAsm("once", program("a < b ? -1 : 1"), target)); + const both = compareCalls( + await emittedAsm("both", program("a < b ? -1 : a > b ? 1 : 0"), target), + ); + expect(once).toBeGreaterThan(0); + expect(both).toBe(once); + }, +); From c98c1fe345a988113032d425cc02434ab1090f48 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:15:53 -0500 Subject: [PATCH 142/259] Test powers of two exactly before treating a product as exact The product of two exact integers was treated as exact everywhere when one of them was a constant power of two, tested with Number.isInteger(Math.log2). Math.log2 rounds to 52 for 2^52 - 1, so a product by 2^52 - 1 that passes 2^53 was compared as its integer instead of its rounded double. The test now compares 2 ** Math.round(Math.log2(value)) with the value. Corpus 7983 adds products by 2^52 - 1 compared with products by 4. --- .../compiler/src/backend/llvm/integer-values.ts | 4 +++- tests/corpus/7983-integer-compares.ts | 16 ++++++++++++++++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/compiler/src/backend/llvm/integer-values.ts b/packages/compiler/src/backend/llvm/integer-values.ts index 497eb5b0d..5b8935036 100644 --- a/packages/compiler/src/backend/llvm/integer-values.ts +++ b/packages/compiler/src/backend/llvm/integer-values.ts @@ -143,7 +143,9 @@ export function wideArithmetic( function powerOfTwo(integer: LlInteger | null): boolean { if (integer === null || integer.range.min !== integer.range.max) return false; const value = Math.abs(integer.range.min); - return value >= 1 && value <= 2 ** 52 && Number.isInteger(Math.log2(value)); + // Math.log2 can round to an integer for a value that is not a power of + // two (2^52 - 1), so the candidate power is compared with the value. + return value >= 1 && value <= 2 ** 52 && 2 ** Math.round(Math.log2(value)) === value; } /** The i64 operands of a number compare that gives the doubles' result: diff --git a/tests/corpus/7983-integer-compares.ts b/tests/corpus/7983-integer-compares.ts index 1114df8a8..2603a39a1 100644 --- a/tests/corpus/7983-integer-compares.ts +++ b/tests/corpus/7983-integer-compares.ts @@ -123,6 +123,21 @@ function scaled(i: number, end: number): string { .join(""); } +function roundedProducts(): string { + // 3 * (2^52 - 1) is 13510798882111485, which rounds to 13510798882111484 = + // 4 * 3377699720527871: the products' doubles are equal and the integers + // are not. A product by 4 never rounds. + let equal = 0; + let below = 0; + for (let i = 1; i <= 8; i++) { + for (let j = 3377699720527869; j <= 3377699720527873; j++) { + if (i * 4503599627370495 === j * 4) equal++; + if (i * 4503599627370495 < j * 4) below++; + } + } + return `${equal} ${below}`; +} + const a = new Int32Array([5, -3, 2147483647, -2147483648, 5, 0]); const b = new Uint8Array([0, 255, 7, 128, 5, 0]); const c = new Uint32Array([4294967295, 2147483648, 2147483647, 0, 1, 4294967295]); @@ -148,3 +163,4 @@ console.log(descend(3, 100), descend(0, 1), descend(5, 0)); for (const i of [0, 1, p52 / 2 - 1, p52 / 2, p52 / 1024, p52 / 2 + 1, p52, -p52]) { console.log(scaled(i, safe), scaled(i, safe - 1), scaled(i, 2 ** 51), scaled(i, 4)); } +console.log(roundedProducts()); From 7405e93e5647e7020248608d47d4934a65105429 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:16:23 -0500 Subject: [PATCH 143/259] Convert compareArray's message only when the arrays differ --- tests/harness/test262.test.ts | 16 ++++++++++++++++ tests/test262/README.md | 2 +- tests/test262/harness.ts | 11 ++++++----- 3 files changed, 23 insertions(+), 6 deletions(-) diff --git a/tests/harness/test262.test.ts b/tests/harness/test262.test.ts index fd35a08fb..678685103 100644 --- a/tests/harness/test262.test.ts +++ b/tests/harness/test262.test.ts @@ -278,6 +278,22 @@ assert.compareArray([object, fn], [object, fn]); status: "fail", source: "assert.sameValue(1, 2, false);", }, + { + name: "passing assertions do not convert their message", + status: "pass", + source: ` +const message = { toString() { throw new Error("converted"); } }; +assert(true, message); +assert.sameValue(1, 1, message); +assert.notSameValue(1, 2, message); +assert.compareArray([1, 2], [1, 2], message); +`, + }, + { + name: "array mismatch with an object message", + status: "fail", + source: 'assert.compareArray([1], [2], { toString() { return "differs"; } });', + }, ]; describe(`Test262 host assertion contract${shardSuffix()}`, () => { diff --git a/tests/test262/README.md b/tests/test262/README.md index 5474fa2c3..231e074e6 100644 --- a/tests/test262/README.md +++ b/tests/test262/README.md @@ -32,7 +32,7 @@ The current profile is `static-adapted-v6`. It adapts strict scripts to standalo The unmodified upstream assertion helper currently reaches scriptc's JavaScript function-expando refusal. Test262 explicitly permits host implementations of harness functions in its [interpretation rules](https://github.com/tc39/test262/blob/7ab7fafa0003f73fc85c1b95d88094d33f7eb8bd/INTERPRETING.md#host-defined-functions). `harness.ts` supplies `assert`, `assert.sameValue`, `assert.notSameValue`, `assert.compareArray`, `assert.throws` for selected Error constructors, `$DONE`, and `Test262Error`. Scalar SameValue and scalar array-element comparisons use the statically compiled `node:assert/strict` implementation. Contract tests compare successful and failing assertions with the original Test262 helpers under Node, including NaN, signed zero, null/undefined, differing primitive types, and premature termination. -Conversion at a native function boundary can copy references, so one object, array, or function may reach the adapter as two distinct references. A copy cannot merge two references into one. `assert.sameValue`, `assert.notSameValue`, and `assert.compareArray` elements therefore treat identical references as the same value and a reference as different from every primitive. Two distinct references terminate with a distinct harness-refusal result, which tests cannot catch and turn into a pass. Assertion messages may be any value; the adapter converts them with `String`, as the upstream helpers do. Sparse array comparisons are not yet handled faithfully across that boundary. The adapted `propertyHelper.js` admits direct `verifyProperty` calls with an inline descriptor literal or `undefined`; reference-valued comparisons follow the same identity rule, while other property helpers and descriptor expressions remain excluded. The adapted `testTypedArray.js` keeps the upstream constructor lists, argument factories and `testWith*` helpers. It omits the `TypedArray` (%TypedArray%) binding, so tests that name it are excluded. Its resizable and immutable buffer factories run only where `ArrayBuffer.prototype` provides `resize` and `transferToImmutable`, as the upstream feature checks intend. Contract tests compare its successful and failing uses with the upstream helper under Node. Assertion aliases, mutation, reflection, additional assertion methods, and other `includes` helpers remain excluded. +Conversion at a native function boundary can copy references, so one object, array, or function may reach the adapter as two distinct references. A copy cannot merge two references into one. `assert.sameValue`, `assert.notSameValue`, and `assert.compareArray` elements therefore treat identical references as the same value and a reference as different from every primitive. Two distinct references terminate with a distinct harness-refusal result, which tests cannot catch and turn into a pass. Assertion messages may be any value; the adapter converts them with `String` when an assertion fails, as the upstream `assert`, `assert.sameValue`, `assert.notSameValue` and `assert.compareArray` do. Sparse array comparisons are not yet handled faithfully across that boundary. The adapted `propertyHelper.js` admits direct `verifyProperty` calls with an inline descriptor literal or `undefined`; reference-valued comparisons follow the same identity rule, while other property helpers and descriptor expressions remain excluded. The adapted `testTypedArray.js` keeps the upstream constructor lists, argument factories and `testWith*` helpers. It omits the `TypedArray` (%TypedArray%) binding, so tests that name it are excluded. Its resizable and immutable buffer factories run only where `ArrayBuffer.prototype` provides `resize` and `transferToImmutable`, as the upstream feature checks intend. Contract tests compare its successful and failing uses with the upstream helper under Node. Assertion aliases, mutation, reflection, additional assertion methods, and other `includes` helpers remain excluded. Raw tests, module variants, agents, resolution negatives, and runtime negatives remain excluded. Parse negatives pass only when a source-matched syntax or vetted JavaScript early-error diagnostic appears; TypeScript type errors and harness-only failures never satisfy a negative expectation. `$262`, dynamic evaluation, observable script-global state, and other unsupported host requirements are excluded as well. The runtime and compiler continue to enforce their existing refusal boundaries for admitted source. diff --git a/tests/test262/harness.ts b/tests/test262/harness.ts index b478b4555..dce1be99c 100644 --- a/tests/test262/harness.ts +++ b/tests/test262/harness.ts @@ -79,18 +79,19 @@ export namespace assert { if (outcome !== "pass") throw new Test262Error(text(message, "Expected exception")); } + /** Converts `message` only when the contents differ, as the upstream helper does. */ export function compareArray(actual: unknown, expected: unknown, message?: unknown): void { - const failure = text(message, "Expected matching array contents"); if (!Array.isArray(actual) || !Array.isArray(expected)) { scalar(actual); scalar(expected); - throw new Test262Error(failure); + throw new Test262Error(text(message, "Expected matching array contents")); } - if (actual.length !== expected.length) throw new Test262Error(failure); - for (let i = 0; i < actual.length; i++) { + let matches = actual.length === expected.length; + for (let i = 0; matches && i < actual.length; i++) { const left: unknown = i in actual ? actual[i] : undefined; const right: unknown = i in expected ? expected[i] : undefined; - if (!same(left, right)) throw new Test262Error(failure); + matches = same(left, right); } + if (!matches) throw new Test262Error(text(message, "Expected matching array contents")); } } From af33be8046e3a3833d44dcf63880082cccea4257 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:16:49 -0500 Subject: [PATCH 144/259] Treat a collection exported through an export list as escaping A reference in `export { m }` resolved to the export's alias symbol, not to the local binding, so the inference did not see the export and typed the collection from its local uses. An importing module then used it as an untyped Map and failed to compile (SC9001). An unrenamed export specifier now resolves to the binding it exports, which refuses the inference as `export const` does. Corpus 7985 adds `export { listed, renamed as alias }`. --- .../src/frontend/lowering/js-collection-types.ts | 12 +++++++++++- packages/compiler/test/js-collection-types.test.ts | 2 ++ tests/corpus/7985-untyped-collection-types.mjs | 9 +++++++++ 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/packages/compiler/src/frontend/lowering/js-collection-types.ts b/packages/compiler/src/frontend/lowering/js-collection-types.ts index 8820ade4a..a4c182523 100644 --- a/packages/compiler/src/frontend/lowering/js-collection-types.ts +++ b/packages/compiler/src/frontend/lowering/js-collection-types.ts @@ -225,7 +225,17 @@ function referencedSymbol(lowerer: Lowerer, id: ts.Identifier): ts.Symbol | unde const parent = id.parent; if (parent !== undefined && ts.isShorthandPropertyAssignment(parent) && parent.name === id) return lowerer.checker.getShorthandAssignmentValueSymbol(parent); - return lowerer.checker.getSymbolAtLocation(id); + const symbol = lowerer.checker.getSymbolAtLocation(id); + // `export { m }` names the export, an alias of the local binding. + if ( + symbol !== undefined && + parent !== undefined && + ts.isExportSpecifier(parent) && + parent.propertyName === undefined && + (symbol.flags & ts.SymbolFlags.Alias) !== 0 + ) + return lowerer.checker.getAliasedSymbol(symbol); + return symbol; } /** Records a reference's use, or answers false when the reference is not diff --git a/packages/compiler/test/js-collection-types.test.ts b/packages/compiler/test/js-collection-types.test.ts index 88e2006b7..6a6f65798 100644 --- a/packages/compiler/test/js-collection-types.test.ts +++ b/packages/compiler/test/js-collection-types.test.ts @@ -54,6 +54,8 @@ test("untyped JavaScript collections take the types their uses prove, and only t "spread", "unread", "exported", + "listed", + "renamed", ]) expect(typed(types.get(untyped)!), untyped).toBe(false); } finally { diff --git a/tests/corpus/7985-untyped-collection-types.mjs b/tests/corpus/7985-untyped-collection-types.mjs index a60a2ea04..de4e581c2 100644 --- a/tests/corpus/7985-untyped-collection-types.mjs +++ b/tests/corpus/7985-untyped-collection-types.mjs @@ -114,3 +114,12 @@ console.log(unread.size, unread.get("none")); export const exported = new Map(); exported.set("e", 1); console.log(exported.get("e")); +// Exported through an export list, under its own name or another: an +// importer sees an untyped Map. +const listed = new Map(); +listed.set("l", 1); +console.log(listed.get("l")); +const renamed = new Map(); +renamed.set("r", 1); +console.log(renamed.get("r")); +export { listed, renamed as alias }; From 49d99d776493120858fef3a2971471f344deeb1e Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:20:33 -0500 Subject: [PATCH 145/259] Rewrite tests of held character locals inside other optional reads An optional read tested against a one-unit literal is replaced by a test of its code unit, built from the read's receiver and index. When that receiver or index tested a held character local, as in `src[c === "a" ? pos + 1 : pos] === "b"`, the inner test was kept as it was and still compared the local as a string|undefined union while the local's binding became a number, which failed IR validation. The same held for a held local's own initializer. The receiver, index and temps of both reads are now rewritten first. --- .../compiler/src/ir/char-unit-locals.test.ts | 26 +++++++++++++++++++ packages/compiler/src/ir/char-unit-locals.ts | 18 +++++++++++-- .../corpus/7304-string-optional-char-reads.ts | 14 ++++++++++ 3 files changed, 56 insertions(+), 2 deletions(-) diff --git a/packages/compiler/src/ir/char-unit-locals.test.ts b/packages/compiler/src/ir/char-unit-locals.test.ts index 378a7f0df..2cce2f32b 100644 --- a/packages/compiler/src/ir/char-unit-locals.test.ts +++ b/packages/compiler/src/ir/char-unit-locals.test.ts @@ -4,6 +4,7 @@ import { join } from "node:path"; import { expect, test } from "vitest"; import { compile, deserializeModule } from "../index.js"; import { holdCharLocalsAsUnits } from "./char-unit-locals.js"; +import { validateModule } from "./validate.js"; import type { IrFunction, IrModule } from "./ir.js"; import { everyStmtList } from "./traverse.js"; @@ -166,3 +167,28 @@ console.log(kept("a b", 1), kept("ab", 0), kept("", 3), longer("ab", 0), twice(" // The local's own test still reads it as a union. expect(unionTests(fn(after, "kept"))).toContain("unionEq"); }); + +test("a held local tested inside another read's index or receiver becomes its unit", async () => { + const mod = holdCharLocalsAsUnits( + await lower(` +function count(src: string, other: string): number { + let n = 0; + for (let pos = 0; pos <= src.length; pos += 1.5) { + const c = src[pos]; + if (src[c === "a" ? pos + 1 : pos] === "b") n++; + if ((c === "x" ? other : src)[pos] === "y") n += 2; + const d = src[c === "c" ? pos - 1 : pos]; + if (d === "c") n += 10; + } + return n; +} +console.log(count("abcab", "xyz"), count("cab", "yy"), count("", "")); +`), + ); + const count = fn(mod, "count"); + expect(validateModule(mod)).toEqual([]); + expect(count.locals.find((l) => l.name === "c")!.type).toEqual({ kind: "f64" }); + expect(count.locals.find((l) => l.name === "d")!.type).toEqual({ kind: "f64" }); + // No test of either local reads it as a union. + expect(unionTests(count)).not.toContain("unionEq"); +}); diff --git a/packages/compiler/src/ir/char-unit-locals.ts b/packages/compiler/src/ir/char-unit-locals.ts index d8be86f08..03636fa87 100644 --- a/packages/compiler/src/ir/char-unit-locals.ts +++ b/packages/compiler/src/ir/char-unit-locals.ts @@ -421,18 +421,32 @@ function rewriteFunction(fn: IrFunction): IrFunction { const read = optionalCharRead(operand)!; if (read.plain || !optional.twice) { changed = true; - return optional.test(() => unitRead(read, operand.loc)); + const rewritten = rewriteRead(read); + return optional.test(() => unitRead(rewritten, operand.loc)); } } return mapExprChildren(e, rewriteExpr, rewriteStmt); }; + // A read's receiver and index may test other held locals. + const rewriteRead = (read: OptionalCharRead): OptionalCharRead => { + const [str, idx] = read.temps; + return { + ...read, + temps: [ + { ...str, init: rewriteExpr(str.init!) }, + { ...idx, init: rewriteExpr(idx.init!) }, + ], + receiver: rewriteExpr(read.receiver), + index: rewriteExpr(read.index), + }; + }; const rewriteStmt = (s: IrStmt): IrStmt => { if (s.kind === "varDecl" && held.has(s.localId) && s.init) { changed = true; const source = copyOf.get(s.localId); if (source !== undefined) return { ...s, init: unitRef(source, s.init.loc) }; const read = reads.get(s.localId); - if (read) return { ...s, init: unitRead(read, s.init.loc) }; + if (read) return { ...s, init: unitRead(rewriteRead(read), s.init.loc) }; if (s.init.kind === "strIntrinsic") return { ...s, diff --git a/tests/corpus/7304-string-optional-char-reads.ts b/tests/corpus/7304-string-optional-char-reads.ts index 13222219d..6e47abb75 100644 --- a/tests/corpus/7304-string-optional-char-reads.ts +++ b/tests/corpus/7304-string-optional-char-reads.ts @@ -119,3 +119,17 @@ for (const p of programs) console.log(JSON.stringify(p), JSON.stringify(new Lexe let text = ""; for (let k = 0; k < 30; k++) text += (k % 4 === 0 ? "==" : "w" + k) + " "; console.log(new Lexer(text).tokens().length, new Lexer(text).tokens().slice(0, 6).join(",")); + +// A character local tested inside another read's index or receiver. +function nested(src: string, other: string): number { + let n = 0; + for (let pos = 0; pos <= src.length; pos += 1.5) { + const c = src[pos]; + if (src[c === "a" ? pos + 1 : pos] === "b") n++; + if ((c === "x" ? other : src)[pos] === "y") n += 2; + const d = src[c === "c" ? pos - 1 : pos]; + if (d === "c") n += 10; + } + return n; +} +console.log(nested("abcab", "xyz"), nested("cab", "yy"), nested("xyxy", "yyyy"), nested("", "")); From 0c6ed44227b893057e75e5868d4b67d4d4df27eb Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:21:32 -0500 Subject: [PATCH 146/259] Match a nested union in full after a getter runs in a trusted build A union without recursion builds its matched arm without a visit session, so its getters and proxy traps ran without marking the conversion. A nested union then took its arm from the earlier match, even when the getter returned another value. A getter or trap that runs during a trusted build outside a session now marks it as well, and the outermost trusted build clears the mark when it ends. --- packages/runtime/src/scr_json.c | 24 ++++++++++++++++------ tests/harness/dyncheck.test.ts | 36 +++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 6 deletions(-) diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 2f9c9884e..b0f4c99c4 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -10824,9 +10824,10 @@ static SCR_TL const ScrDyn *scr_dyn_visit_held; /* Set while a union's builder builds the arm it matched in full * (scr_dyn_trust_enter). */ static SCR_TL bool scr_dyn_trusted; -/* Set once a getter or proxy trap has run during this session. Their code - * can return a value the match never saw or change one it saw, so no build - * in the rest of the session trusts an earlier match. */ +/* Set once a getter or proxy trap has run during this session, or during + * a trusted build outside any session. Their code can return a value the + * match never saw or change one it saw, so no build in the rest of the + * session, or of the outermost trusted build, trusts an earlier match. */ static SCR_TL bool scr_dyn_session_ran_code; /* Tables up to this many slots stay allocated for the next session. */ @@ -10978,7 +10979,10 @@ static void scr_dyn_visit_resume(const ScrDynVisitState *saved) { /* Calls a getter for a member read, outside any visit session. */ static ScrDyn *scr_dyn_visit_call_getter(ScrDyn *getter) { - if (scr_dyn_visit_depth == 0) return scr_dyn_call(getter, NULL, 0, "getter"); + if (scr_dyn_visit_depth == 0) { + if (scr_dyn_trusted) scr_dyn_session_ran_code = true; + return scr_dyn_call(getter, NULL, 0, "getter"); + } ScrDynVisitState saved; scr_dyn_visit_suspend(&saved); ScrDyn *result = scr_dyn_call(getter, NULL, 0, "getter"); @@ -10988,7 +10992,10 @@ static ScrDyn *scr_dyn_visit_call_getter(ScrDyn *getter) { /* A proxy's get trap for a member read, outside any visit session. */ static ScrDyn *scr_dyn_visit_proxy_get(const ScrDyn *d, ScrStr *name) { - if (scr_dyn_visit_depth == 0) return scr_dyn_proxy_get(d, name); + if (scr_dyn_visit_depth == 0) { + if (scr_dyn_trusted) scr_dyn_session_ran_code = true; + return scr_dyn_proxy_get(d, name); + } ScrDynVisitState saved; scr_dyn_visit_suspend(&saved); ScrDyn *result = scr_dyn_proxy_get(d, name); @@ -11002,7 +11009,12 @@ bool scr_dyn_trust_enter(void) { return previous; } -void scr_dyn_trust_exit(bool previous) { scr_dyn_trusted = previous; } +void scr_dyn_trust_exit(bool previous) { + scr_dyn_trusted = previous; + /* The outermost trusted build outside a session ends: later conversions + * may trust their own matches again. A session clears it on its exit. */ + if (!previous && scr_dyn_visit_depth == 0) scr_dyn_session_ran_code = false; +} bool scr_dyn_trusted_build(void) { return scr_dyn_trusted && !scr_dyn_session_ran_code; } diff --git a/tests/harness/dyncheck.test.ts b/tests/harness/dyncheck.test.ts index eb0ea1a7f..f38d8237d 100644 --- a/tests/harness/dyncheck.test.ts +++ b/tests/harness/dyncheck.test.ts @@ -650,6 +650,42 @@ console.log("getter calls", calls); ]); }); + test("nested unions: a getter's value in a non-recursive union's build is matched in full", async () => { + // A union without recursion builds without a visit session. The getter + // still runs user code during the trusted build, so the nested union + // matches its second answer in full, and the failure names that union. + const r = await compileAndRun( + "flat-discriminated-getter", + `type Inner = { tag: "x"; n: number } | { tag: "y"; s: string }; +type Outer = { kind: "a"; inner: Inner } | { kind: "b"; other: number }; +const v = JSON.parse('{"kind":"a"}') as unknown; +let calls = 0; +Object.defineProperty(v, "inner", { + enumerable: true, + get() { + calls++; + return calls === 1 ? JSON.parse('{"tag":"x","n":1}') : JSON.parse('{"tag":"x","n":"bad"}'); + }, +}); +try { + const o = v as Outer; + console.log("ok", JSON.stringify(o)); +} catch (err) { + console.log((err as Error).message); +} +console.log("getter calls", calls); +const plain = JSON.parse('{"kind":"a","inner":{"tag":"y","s":"z"}}') as Outer; +console.log(JSON.stringify(plain)); +`, + ); + expect(r.exitCode).toBe(0); + expect(r.stdout.trimEnd().split("\n")).toEqual([ + "expected object | object at $.inner, got object", + "getter calls 2", + '{"kind":"a","inner":{"tag":"y","s":"z"}}', + ]); + }); + test("array where a record is expected names the mismatch at the root", async () => { const r = await compileAndRun( "root-kind", From e00d3fd9116431b8ce2ac4e52358aea7b51ccde2 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:22:03 -0500 Subject: [PATCH 147/259] Check comparison operands and walk instanceof chains as Node does - The assert comparison methods read as function values (equal, strictEqual, deepEqual, partialDeepStrictEqual and their negations) throw Node's ERR_MISSING_ARGS TypeError, `The "actual" and "expected" arguments must be specified`, when called with fewer than two arguments, where `[assert.equal][0]()` passed. - Untyped `instanceof Object` starts at the value's prototype, so Object.prototype itself, whose prototype is null, is not an Object. - Untyped `instanceof Function` follows the whole prototype chain through objects and functions: an object whose prototype is a function, or a function whose prototype was set to such an object, is a Function. --- packages/runtime/src/scr_assert.c | 11 ++++ packages/runtime/src/scr_json.c | 64 ++++++++++++++++--- .../8078-instanceof-object-function.cjs | 22 +++++++ tests/corpus/8190-assert-function-values.cjs | 15 +++++ 4 files changed, 102 insertions(+), 10 deletions(-) diff --git a/packages/runtime/src/scr_assert.c b/packages/runtime/src/scr_assert.c index 738a7729c..bf5d1c875 100644 --- a/packages/runtime/src/scr_assert.c +++ b/packages/runtime/src/scr_assert.c @@ -3066,8 +3066,18 @@ static ScrDyn *scr_av_fail(ScrClosure *c, ScrDyn *const *args, size_t argc) { return scr_av_done(msg); } +/* The comparison methods take both operands: Node's ERR_MISSING_ARGS + * TypeError otherwise. False with it pending. */ +static bool scr_av_operands(size_t argc) { + if (argc >= 2) return true; + static const char text[] = "The \"actual\" and \"expected\" arguments must be specified"; + scr_throw_error_msg_code(SCR_ERR_TYPE, text, sizeof text - 1, "ERR_MISSING_ARGS"); + return false; +} + /* equal / notEqual: Node's loose comparison, NaN equal to NaN. */ static ScrDyn *scr_av_loose(ScrDyn *const *args, size_t argc, bool negated) { + if (!scr_av_operands(argc)) return NULL; const ScrDyn *a = scr_av_arg(args, argc, 0), *b = scr_av_arg(args, argc, 1); bool nan = a->kind == SCR_DYN_NUM && b->kind == SCR_DYN_NUM && isnan(a->v.num) && isnan(b->v.num); bool equal = nan || scr_dyn_abstract_eq(a, b); @@ -3097,6 +3107,7 @@ static ScrDyn *scr_av_not_equal(ScrClosure *c, ScrDyn *const *a, size_t n) { enum { SCR_AV_STRICT, SCR_AV_DEEP_STRICT, SCR_AV_DEEP, SCR_AV_PARTIAL }; static ScrDyn *scr_av_compare(ScrDyn *const *args, size_t argc, int form, bool negated) { + if (!scr_av_operands(argc)) return NULL; ScrDyn *a = (ScrDyn *)scr_av_arg(args, argc, 0), *b = (ScrDyn *)scr_av_arg(args, argc, 1); ScrStr *msg; bool has; diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index ecc49e8cf..5414611b8 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -4684,12 +4684,18 @@ static bool scr_dyn_instanceof_object(const ScrDyn *value) { default: break; } + /* Object.prototype is on the chain from the value's own prototype on: + * Object.prototype itself has a null prototype, so it is not an Object. */ ScrDyn *current = scr_dyn_retain((ScrDyn *)value); - for (;;) { - if (current == scr_builtin_object_prototype) { + for (bool first = true;; first = false) { + if (!first && current == scr_builtin_object_prototype) { scr_dyn_release(current); return true; } + if (current == scr_builtin_object_prototype) { + scr_dyn_release(current); + return false; + } ScrDyn *next = NULL; if (current->kind == SCR_DYN_FUNC) { /* A function's prototype is Function.prototype, whose own is @@ -4719,15 +4725,53 @@ static bool scr_dyn_instanceof_object(const ScrDyn *value) { } } -/* `value instanceof Function`: every function, unless the program set its - * prototype to null or to a non-function. */ +/* `value instanceof Function`: whether a function is on the value's + * prototype chain. A function's own prototype is Function.prototype unless + * the program set it, so the walk ends true at the first function that + * kept its prototype; it follows set prototypes through functions and + * objects alike (`Object.create(function () {})` is a Function instance), + * and ends false at null or at a value without a chain the runtime walks. + * False with the exception pending when a prototype read throws. */ static bool scr_dyn_instanceof_function(const ScrDyn *value) { - if (value->kind != SCR_DYN_FUNC) return false; - if (!scr_closure_identity(value->v.fn.clo)->props) return true; - ScrDyn *table = scr_dyn_fn_properties((ScrDyn *)value); - bool result = table->prototype ? scr_dyn_instanceof_function(table->prototype) : !table->null_proto; - scr_dyn_release(table); - return result; + ScrDyn *current = NULL; + if (value->kind == SCR_DYN_FUNC) { + if (!scr_closure_identity(value->v.fn.clo)->props) return true; + ScrDyn *table = scr_dyn_fn_properties((ScrDyn *)value); + current = table->prototype ? scr_dyn_retain(table->prototype) : NULL; + bool unset = !table->prototype && !table->null_proto; + scr_dyn_release(table); + if (unset) return true; + } else if (value->kind == SCR_DYN_OBJ || value->kind == SCR_DYN_ARR) { + current = scr_dyn_get_prototype((ScrDyn *)value); + if (!current) return false; /* the read threw: pending */ + } + while (current && current->kind != SCR_DYN_NULL) { + ScrDyn *next = NULL; + if (current->kind == SCR_DYN_FUNC) { + if (!scr_closure_identity(current->v.fn.clo)->props) { + scr_dyn_release(current); + return true; + } + ScrDyn *table = scr_dyn_fn_properties(current); + bool unset = !table->prototype && !table->null_proto; + next = table->prototype ? scr_dyn_retain(table->prototype) : NULL; + scr_dyn_release(table); + if (unset) { + scr_dyn_release(current); + return true; + } + } else if (current->kind == SCR_DYN_OBJ || current->kind == SCR_DYN_ARR) { + next = scr_dyn_get_prototype(current); + if (!next) { + scr_dyn_release(current); + return false; /* the read threw: pending */ + } + } + scr_dyn_release(current); + current = next; + } + if (current) scr_dyn_release(current); + return false; } bool scr_bytes_instanceof_at(const ScrDyn *value, const ScrDyn *callee, const ScrStr *refusal) { diff --git a/tests/corpus/8078-instanceof-object-function.cjs b/tests/corpus/8078-instanceof-object-function.cjs index 9a72de00f..22f212269 100644 --- a/tests/corpus/8078-instanceof-object-function.cjs +++ b/tests/corpus/8078-instanceof-object-function.cjs @@ -53,3 +53,25 @@ function describe(value) { return value instanceof Function ? 'function' : 'object'; } console.log([nullProto, {}, describe, 0].map(describe).join(', ')); + +// Prototype chains through functions and objects, and Object.prototype +// itself, whose own prototype is null. +const base = function base() {}; +const fromFunction = {}; +Object.setPrototypeOf(fromFunction, base); +const throughObject = {}; +Object.setPrototypeOf(throughObject, fromFunction); +const nullRooted = function nullRooted() {}; +Object.setPrototypeOf(nullRooted, null); +const reparented = function reparented() {}; +Object.setPrototypeOf(reparented, fromFunction); +const chains = { + objectPrototype: Object.getPrototypeOf({}), + fromFunction, + throughObject, + nullRooted, + reparented, +}; +for (const [label, value] of Object.entries(chains)) { + console.log(`${label}: Object ${value instanceof Object}, Function ${value instanceof Function}`); +} diff --git a/tests/corpus/8190-assert-function-values.cjs b/tests/corpus/8190-assert-function-values.cjs index b91434899..f27bf22dc 100644 --- a/tests/corpus/8190-assert-function-values.cjs +++ b/tests/corpus/8190-assert-function-values.cjs @@ -28,3 +28,18 @@ const checks = [assert.ok, assert.fail, assert.strictEqual]; checks.forEach((check, i) => console.log(i, typeof check, check === checks[i], check.name)); [1, 'x', true].forEach((value) => assert.ok(value)); console.log('done'); + +// The comparison methods need both operands, as Node's ERR_MISSING_ARGS +// TypeError says, also through function values. +const comparisons = [assert.equal, assert.notEqual, assert.strictEqual, assert.notStrictEqual, + assert.deepEqual, assert.notDeepEqual, assert.deepStrictEqual, assert.notDeepStrictEqual]; +for (const compare of comparisons) { + for (const args of [[], [1]]) { + try { + compare(...args); + console.log(compare.name, args.length, 'passed'); + } catch (e) { + console.log(compare.name, args.length, e.name, e.code, e.message); + } + } +} From e7c7a458106c6bf5fb9f538eba159c0822dd510d Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:24:50 -0500 Subject: [PATCH 148/259] Convert a read length once in fs.read and fs.readSync fs.read and fs.readSync with arguments the compiler could not type validated the length with `length |= 0` and then converted it again for the read. A length with a valueOf method ran valueOf twice, and the read used the second result. Node converts the length once. scr_fs_read_validate now returns the converted length, and both reads use it. --- packages/runtime/src/scr_bytes_io.c | 23 ++++++++++++------- .../8273-fs-read-write-argument-checks.cjs | 17 +++++++++++--- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/packages/runtime/src/scr_bytes_io.c b/packages/runtime/src/scr_bytes_io.c index bebc2a479..daeb47c60 100644 --- a/packages/runtime/src/scr_bytes_io.c +++ b/packages/runtime/src/scr_bytes_io.c @@ -635,7 +635,8 @@ void scr_fs_cb_schedule(const ScrDyn *callback, ScrDyn *result, const ScrDyn *bu #endif } -static bool scr_fs_read_validate(const ScrDyn *, const ScrDyn *, const ScrDyn *, const ScrDyn *, const ScrDyn *); +static bool scr_fs_read_validate(const ScrDyn *, const ScrDyn *, const ScrDyn *, const ScrDyn *, const ScrDyn *, + double *); static bool scr_fs_encoding_chk(const ScrDyn *); static bool scr_fs_int_range_chk(const ScrDyn *, const char *, double, double, const char *); static bool scr_fs_length_int32(const ScrDyn *, double *); @@ -904,7 +905,12 @@ static ScrDyn *scr_fs_cb_invoke(ScrStr *member, ScrDyn *const *args, size_t argc } if (!scr_fs_cb_chk(callback, "cb")) return NULL; } - if (!strcmp(op, "read") && count >= 4 && !scr_fs_read_validate(ARG(0), ARG(1), ARG(2), ARG(3), ARG(4))) return NULL; + /* The read length after `length |= 0`, converted once (a valueOf call + * runs once, as in Node). */ + double readLength = 0; + if (!strcmp(op, "read") && count >= 4 && + !scr_fs_read_validate(ARG(0), ARG(1), ARG(2), ARG(3), ARG(4), &readLength)) + return NULL; /* write checks its fd first, then the buffer form's callback, offset and * length (validateOffsetLengthWrite), or the string form's data and * callback. */ @@ -1121,7 +1127,7 @@ static ScrDyn *scr_fs_cb_invoke(ScrStr *member, ScrDyn *const *args, size_t argc double offset = ownedBuffer ? scr_fs_cb_option_number(options, "offset", 0) : scr_fs_cb_number(ARG(2), "offset", 0); double length = bytes->len - offset; if (ownedBuffer) length = scr_fs_cb_option_number(options, "length", length); - else if (readOp && count >= 4) scr_fs_length_int32(ARG(3), &length); + else if (readOp && count >= 4) length = readLength; else length = scr_fs_cb_number(ARG(3), "length", length); double position = ownedBuffer ? scr_fs_cb_option_number(options, "position", -1) : scr_fs_cb_number(ARG(4), "position", -1); if (!scr_exc_pending()) result = scr_dyn_new_num(readOp ? scr_fs_read_sync(fd, bytes, offset, length, position) : scr_fs_write_sync(fd, bytes, offset, length, position)); @@ -1973,9 +1979,10 @@ static bool scr_fs_bigint_position_chk(ScrBigInt *position, double length) { * Node's order: the fd, the buffer, the offset (an integer >= 0), the * length as `length |= 0`, the position (validatePosition, against that * length), then for a non-empty read the empty-buffer and - * validateOffsetLengthRead checks. */ + * validateOffsetLengthRead checks. The converted length goes to + * *length_out when it is not NULL, so the read does not convert again. */ static bool scr_fs_read_validate(const ScrDyn *fd, const ScrDyn *buffer, const ScrDyn *offset, - const ScrDyn *length, const ScrDyn *position) { + const ScrDyn *length, const ScrDyn *position, double *length_out) { if (fd->kind != SCR_DYN_NUM) { scr_dyn_arg_type_fail("fd", "of type number", fd); return false; @@ -1995,6 +2002,7 @@ static bool scr_fs_read_validate(const ScrDyn *fd, const ScrDyn *buffer, const S } double count = 0; if (!scr_fs_length_int32(length, &count)) return false; + if (length_out) *length_out = count; if (!scr_fs_dyn_absent(position)) { if (position->kind == SCR_DYN_BIGINT) { if (!scr_fs_bigint_position_chk(position->v.bigint, count)) return false; @@ -2034,7 +2042,7 @@ static bool scr_fs_read_validate(const ScrDyn *fd, const ScrDyn *buffer, const S void scr_fs_read_chk(const ScrDyn *fd, const ScrDyn *buffer, const ScrDyn *offset, const ScrDyn *length, const ScrDyn *position, const ScrStr *fence) { - if (scr_fs_read_validate(fd, buffer, offset, length, position)) scr_throw_lowering_fence(fence); + if (scr_fs_read_validate(fd, buffer, offset, length, position, NULL)) scr_throw_lowering_fence(fence); } /* createReadStream/createWriteStream(path, options?): getOptions' @@ -2090,9 +2098,8 @@ double scr_fs_read_sync_dyn(const ScrDyn *fd, const ScrDyn *buffer, const ScrDyn scr_dyn_arg_type_fail("buffer", "an instance of Buffer, TypedArray, or DataView", buffer); return 0; } - if (!scr_fs_read_validate(fd, buffer, offset, length, position)) return 0; double count = 0; - if (!scr_fs_length_int32(length, &count)) return 0; + if (!scr_fs_read_validate(fd, buffer, offset, length, position, &count)) return 0; if (count == 0) return 0; double at = scr_fs_dyn_absent(position) ? -1 : position->kind == SCR_DYN_BIGINT ? scr_bigint_to_f64(position->v.bigint) diff --git a/tests/corpus/8273-fs-read-write-argument-checks.cjs b/tests/corpus/8273-fs-read-write-argument-checks.cjs index 623d5286f..b27564837 100644 --- a/tests/corpus/8273-fs-read-write-argument-checks.cjs +++ b/tests/corpus/8273-fs-read-write-argument-checks.cjs @@ -1,7 +1,8 @@ 'use strict'; // fs.read, fs.readSync and fs.write check their arguments in Node's order // and with Node's errors: the fd, the buffer, the offset, `length |= 0`, -// number and bigint positions, and the buffer window. +// number and bigint positions, and the buffer window. A length with a +// valueOf method is converted once. const fs = require('fs'); const path = require('path'); const os = require('os'); @@ -48,6 +49,11 @@ attempt('readSync offset 4', () => fs.readSync(fd, Buffer.alloc(3), 4, 1, 0)); attempt('readSync buffer number', () => fs.readSync(fd, 3, 0, 1, 0)); attempt('readSync fd null', () => fs.readSync(null, Buffer.alloc(3), 0, 1, 0)); console.log(fs.readSync(fd, Buffer.alloc(3), 0, 0.5, 0), fs.readSync(fd, Buffer.alloc(3), 0, 2.5, 0)); +let syncCalls = 0; +const syncLength = { valueOf: () => (++syncCalls === 1 ? 2 : 3) }; +const syncTarget = Buffer.alloc(3); +const syncCount = fs.readSync(fd, syncTarget, 0, syncLength, 0); +console.log('readSync valueOf', syncCount, syncCalls, syncTarget.toString('utf8', 0, syncCount)); attempt('write fd null', () => fs.write(null, Buffer.alloc(1), 0, 1, noop)); attempt('write fd "1"', () => fs.write('1', 'x', noop)); @@ -63,7 +69,12 @@ fs.read(fd, Buffer.alloc(2), 0, 2, 2n, (error, count, buffer) => { console.log('read 2n', error, count, buffer.toString()); fs.write(fd, Buffer.from('XY'), 0, 2, 0, (error2, written) => { console.log('wrote', error2, written, fs.readFileSync(file, 'utf8')); - fs.closeSync(fd); - fs.rmSync(dir, { recursive: true }); + let calls = 0; + const length = { valueOf: () => (++calls === 1 ? 1 : 3) }; + fs.read(fd, Buffer.alloc(3), 0, length, 0, (error3, count3, buffer3) => { + console.log('read valueOf', error3, count3, calls, buffer3.toString('utf8', 0, count3)); + fs.closeSync(fd); + fs.rmSync(dir, { recursive: true }); + }); }); }); From bffd887145a81541b05cd6a1361c074c88f0f57c Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:26:20 -0500 Subject: [PATCH 149/259] Keep the native receiver for private accessors and private method values A JavaScript prototype method value runs over the call-site receiver when its private members are fields (brand-checked reads and writes) or private methods it calls. A private accessor, or a private method read as a value, would read a public property of the same name, so such a method keeps its native receiver, as before. A super method call with spread arguments over the call-site receiver now spreads them into the dynamic call instead of rejecting them. --- .../frontend/lowering/class-method-values.ts | 34 ++++++++++++- .../src/frontend/lowering/lower-classes.ts | 11 ++++- .../7621-class-methods-foreign-receivers.mjs | 49 +++++++++++++++++++ 3 files changed, 91 insertions(+), 3 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/class-method-values.ts b/packages/compiler/src/frontend/lowering/class-method-values.ts index af2ef51d5..ab9101cf7 100644 --- a/packages/compiler/src/frontend/lowering/class-method-values.ts +++ b/packages/compiler/src/frontend/lowering/class-method-values.ts @@ -383,12 +383,29 @@ function reflectedMethodValue( // base has a prototype object. Other uses of `super` keep the native // receiver. const superCalls = !staticMethod && info.base !== null && prototypeChainViewable(info.base); + // Over a dynamic receiver, private fields are brand-checked and read, and private methods + // brand-checked and called; a private accessor, or a private method read as a value, would become a + // lookup of its name. + const privateAccessors = new Set(); + const privateMethods = new Set(); + for (const other of declaration.members.nodes) + if (other.name !== undefined && ts.isPrivateIdentifier(other.name)) { + if (ts.isAccessor(other)) privateAccessors.add(other.name.text); + else if (ts.isMethodDeclaration(other)) privateMethods.add(other.name.text); + } ts.walkPreorder(member, (node) => { if (node.kind === ts.SyntaxKind.SuperKeyword && !(superCalls && isSuperMethodCallee(node))) needsNativeReceiver = true; + if (!ts.isPrivateIdentifier(node)) return; // Private members on a static method's receiver (the class value) keep - // the native receiver; prototype methods brand-check theirs. - if (staticMethod && ts.isPrivateIdentifier(node)) needsNativeReceiver = true; + // the native receiver; prototype methods brand-check theirs, except + // private accessors and private methods used other than by a call. + if ( + staticMethod || + privateAccessors.has(node.text) || + (privateMethods.has(node.text) && !isPrivateMethodCallee(node)) + ) + needsNativeReceiver = true; }); if (needsNativeReceiver) return null; // The method reads itself as a value inside its own body: it is the @@ -477,6 +494,19 @@ function prototypeChainViewable(base: ClassInfo): boolean { } /** `super` as the receiver of a called member: `super.m(...)`. */ +/** Whether `node`, a private name, is the method a call calls (`x.#m(...)`). */ +function isPrivateMethodCallee(node: ts.Node): boolean { + const access = node.parent; + return ( + access !== undefined && + ts.isPropertyAccessExpression(access) && + access.name === node && + access.parent !== undefined && + ts.isCallExpression(access.parent) && + access.parent.expression === access + ); +} + function isSuperMethodCallee(node: ts.Node): boolean { const access = node.parent; return ( diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index db8f35f95..2abbe81ca 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -9402,12 +9402,21 @@ export function lowerSuperMethodCall( type: DYN, loc, }; + // Spread arguments are spread into the dynamic call, as in a dynamic method call. + const spreads: { arg: number; what: string }[] = []; + const args = call.arguments.nodes.map((arg, index) => { + if (!ts.isSpreadElement(arg)) return lowerer.lowerExprExpecting(arg, DYN); + const spelling = ts.getTextOfNode(arg.expression); + spreads.push({ arg: index, what: spelling }); + return checkedIterableSpread(lowerer, lowerer.lowerExpr(arg.expression), spelling, loc); + }); const value: IrExpr = { kind: "dynCall", callee, receiver: lowerer.coerceToExpected(thisRef, DYN), calleeName: ts.getTextOfNode(access), - args: call.arguments.nodes.map((arg) => lowerer.lowerExprExpecting(arg, DYN)), + args, + ...(spreads.length > 0 ? { spreads } : {}), type: DYN, loc, }; diff --git a/tests/corpus/7621-class-methods-foreign-receivers.mjs b/tests/corpus/7621-class-methods-foreign-receivers.mjs index 8e4feedbd..70826a192 100644 --- a/tests/corpus/7621-class-methods-foreign-receivers.mjs +++ b/tests/corpus/7621-class-methods-foreign-receivers.mjs @@ -167,3 +167,52 @@ console.log( JSON.stringify(meshClone.geometry), typeof copyValue, ); + +// Methods that use a private accessor or return a private method keep their own receiver, as values too. +class Vault { + #v = 1; + get #value() { + return this.#v * 10; + } + set #value(x) { + this.#v = x; + } + #hidden() { + return "hidden " + this.#v; + } + read() { + return this.#value; + } + bump() { + this.#value = this.#v + 1; + return this.#v; + } + hiddenValue() { + return this.#hidden; + } +} +const vault = new Vault(); +const readVault = Vault.prototype.read; +const bumpVault = Vault.prototype.bump; +const hiddenOf = Vault.prototype.hiddenValue; +console.log(readVault.call(vault), bumpVault.call(vault), readVault.call(vault), typeof hiddenOf.call(vault)); +console.log(hiddenOf.call(vault).call(vault)); +try { + readVault.call({}); +} catch (error) { + console.log(error.constructor.name); +} + +// A method value whose body calls super with spread arguments. +class Summer { + add(...xs) { + return xs.reduce((sum, x) => sum + x, 0); + } +} +class Doubler extends Summer { + add(...xs) { + return super.add(...xs) * 2; + } +} +const addValue = Doubler.prototype.add; +console.log(addValue.call(new Doubler(), 1, 2, 3), addValue.apply(new Doubler(), [4, 5])); From 49964dc9970f39538c2d471783936f5a25dc5b57 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:26:38 -0500 Subject: [PATCH 150/259] Read prototype methods stored under computed keys on ES5 instances A member read on a `new F()` instance looked up the name only among the fields of F's prototype objects. A method stored under a computed key (`F.prototype[name] = fn`) is kept in the prototype's unknown-key field, so the read found nothing: the method's body was never visited, and the objects it writes stayed constant in the report. The read now also takes the prototype's unknown-key field, as reads of the object's own fields do. --- .../src/frontend/shape-inference/analyze.ts | 8 +++++-- .../compiler/test/constant-graphs.test.ts | 21 +++++++++++++++++++ 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/packages/compiler/src/frontend/shape-inference/analyze.ts b/packages/compiler/src/frontend/shape-inference/analyze.ts index 8b1101da2..19d3cac22 100644 --- a/packages/compiler/src/frontend/shape-inference/analyze.ts +++ b/packages/compiler/src/frontend/shape-inference/analyze.ts @@ -2190,8 +2190,12 @@ class Analyzer { this.add(protos, this.protoAtom(fn)); this.edge(this.field(fn, "prototype"), protos); this.on(protos, (proto) => { - if (proto.kind === "object") this.edge(this.field(proto, name), dst); - else if (proto.kind === "top") this.add(dst, this.top); + if (proto.kind === "object") { + // A method stored under a computed key (`F.prototype[k] = fn`) + // may be any name. + this.edge(this.field(proto, name), dst); + this.edge(this.anyField(proto), dst); + } else if (proto.kind === "top") this.add(dst, this.top); }); return; } diff --git a/packages/compiler/test/constant-graphs.test.ts b/packages/compiler/test/constant-graphs.test.ts index a89276ce7..a7cbe6118 100644 --- a/packages/compiler/test/constant-graphs.test.ts +++ b/packages/compiler/test/constant-graphs.test.ts @@ -141,3 +141,24 @@ test("constant graphs: constructors, apply calls and callbacks that one site run new RegExp(`near miss ns-fixture/index\\.js:10 \\.${field}: written-after-init`), ); }); + +// A prototype method stored under a computed key and called on instances. +const computedMethodSource = ` +var lib = {}; +lib.touched = { count: 0 }; +lib.Widget = function () {}; +var methodName = ["to", "uch"].join(""); +lib.Widget.prototype[methodName] = function () { lib.touched.count++; }; +lib.useWidget = function () { new lib.Widget().touch(); }; +module.exports = { lib }; +`; + +test("constant graphs: prototype methods stored under computed keys run on their instances", async () => { + await writeFile(join(dir, "node_modules", "ns-fixture", "index.js"), computedMethodSource); + await writeFile( + join(dir, "main.cjs"), + 'const { lib } = require("ns-fixture");\nfor (let i = 0; i < 3; i++) lib.useWidget();\nconsole.log(lib.touched.count);\n', + ); + const text = (await report()).join("\n"); + expect(text).toMatch(/near miss ns-fixture\/index\.js:3 \.count: written-after-init/); +}); From f645e8e7022e8710631cbf641b99e00d4b55f0a3 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:27:15 -0500 Subject: [PATCH 151/259] Run a prototype's constructor getter on the instance An instance's `constructor` read that reaches a class prototype's own property now reads it with the instance as the receiver (Reflect.get), so an accessor's getter sees the instance as `this`, as in Node, instead of the prototype. --- .../lowering/class-dynamic-dispatch.ts | 24 +++++++++++++++---- tests/corpus/8260-class-prototype-views.mjs | 23 ++++++++++++++++++ 2 files changed, 43 insertions(+), 4 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts index fd6b8c941..db1ed1c8c 100644 --- a/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts +++ b/packages/compiler/src/frontend/lowering/class-dynamic-dispatch.ts @@ -4235,25 +4235,35 @@ export class ClassDynamicDispatch { * (prototypeReflectedFlag, set when the view initializes): then the * program deleted the property, and the read continues to the base * class's prototype and past the last one to Object.prototype, as in - * Node. */ + * Node. A prototype's own `constructor` is read with the instance + * `receiver` as `this`, so an accessor's getter runs on the instance. */ private inheritedConstructor( lowerer: Lowerer, info: ClassInfo, key: IrExpr, + receiver: IrExpr, loc: SrcLoc, ): IrExpr { const cls = lowerer.coerceToExpected(classValueRef(lowerer, info, info.decl!), DYN); const prototype = hasClassPrototypeData(info) ? classPrototypeData(lowerer, info, loc) : null; if (!prototype) return cls; const base = info.base; + const read = (): IrExpr => ({ + kind: "libCall", + fn: "dyn.reflectGet", + args: [prototype, lowerer.coerceToExpected(key, DYN), receiver], + type: DYN, + loc, + }); + // Past the last class prototype, the read continues to Object.prototype's data property. const next: IrExpr = base && !base.builtinError && base.decl && !base.generic && !base.localClass - ? this.inheritedConstructor(lowerer, base, key, loc) + ? this.inheritedConstructor(lowerer, base, key, receiver, loc) : { kind: "dynKeyGet", value: prototype, key, type: DYN, loc }; return { kind: "ternary", cond: { kind: "libCall", fn: "dyn.hasOwn", args: [prototype, key], type: BOOL, loc }, - then: { kind: "dynKeyGet", value: prototype, key, type: DYN, loc }, + then: read(), else_: { kind: "ternary", cond: varRef(prototypeReflectedFlag(lowerer, info), BOOL, loc), @@ -6045,7 +6055,13 @@ export class ClassDynamicDispatch { type: DYN, loc, }, - else_: this.inheritedConstructor(lowerer, info, key, loc), + else_: this.inheritedConstructor( + lowerer, + info, + key, + lowerer.coerceToExpected(receiver, DYN), + loc, + ), type: DYN, loc, }, diff --git a/tests/corpus/8260-class-prototype-views.mjs b/tests/corpus/8260-class-prototype-views.mjs index 35e55f5f4..0f7b080bf 100644 --- a/tests/corpus/8260-class-prototype-views.mjs +++ b/tests/corpus/8260-class-prototype-views.mjs @@ -153,3 +153,26 @@ delete Object.getPrototypeOf(new Root()).constructor; console.log(constructorNames(), new Middle().constructor === Object); Middle.prototype.constructor = function Named() {}; console.log(constructorNames()); + +// A reflected prototype whose constructor is an accessor: an instance's read runs the getter with the +// instance as `this`, also where the instance's class inherits it. +class Facet { + constructor(tag) { + this.tag = tag; + } +} +class Tile extends Facet {} +class Brick extends Tile {} +const facets = [new Tile("s"), new Brick("c"), new Facet("p")]; +const facetTags = () => + facets.map((facet) => (typeof facet.constructor === "string" ? facet.constructor : facet.constructor.name)).join(","); +Object.defineProperty(Tile.prototype, "constructor", { + get() { + return "on " + this.tag; + }, + configurable: true, +}); +delete Object.getPrototypeOf(new Brick("x")).constructor; +console.log(facetTags()); +delete Object.getPrototypeOf(new Tile("x")).constructor; +console.log(facetTags()); From e22cdf358bcd2a67909e3e905e68312370e7928b Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:28:43 -0500 Subject: [PATCH 152/259] Decode an untyped stream unshift's string chunk with its encoding `s.unshift("e9", "hex")` on a native stream held as an untyped value dropped the encoding argument and put the string's UTF-8 bytes at the front. A byte-mode stream now takes a string chunk with an encoding as the bytes Buffer.from(chunk, encoding) holds, as Node's readableAddChunkUnshift converts it, and an unknown encoding throws ERR_UNKNOWN_ENCODING. Object-mode streams keep the string as the entry. --- packages/runtime/src/scr_stream.c | 25 ++++++++++++++++---- tests/corpus/8232-native-streams-untyped.cjs | 24 +++++++++++++++++++ 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/packages/runtime/src/scr_stream.c b/packages/runtime/src/scr_stream.c index 33382363b..552fef146 100644 --- a/packages/runtime/src/scr_stream.c +++ b/packages/runtime/src/scr_stream.c @@ -8101,10 +8101,25 @@ static ScrDyn *scr_stream_dyn_push(ScrStream *stream, ScrDyn *const *args, size_ return scr_exc_pending() ? NULL : scr_dyn_new_bool(more); } -/* unshift(chunk): whether the stream takes more data afterwards, Node's - * canPushMore. */ -static ScrDyn *scr_stream_dyn_unshift(ScrStream *stream, const ScrDyn *chunk) { - scr_stream_unshift_dyn(stream, chunk); +/* unshift(chunk[, encoding]): a byte-mode stream takes a string chunk with + * an encoding as the bytes Buffer.from(chunk, encoding) holds, as Node's + * readableAddChunkUnshift converts it; an unknown encoding throws + * ERR_UNKNOWN_ENCODING. Answers whether the stream takes more data + * afterwards, Node's canPushMore. */ +static ScrDyn *scr_stream_dyn_unshift(ScrStream *stream, ScrDyn *const *args, size_t argc) { + ScrDyn *chunk = argc ? args[0] : scr_dyn_undefined(); + ScrDyn *encoding = argc > 1 ? args[1] : scr_dyn_undefined(); + if (chunk->kind == SCR_DYN_STR && encoding->kind == SCR_DYN_STR && + !(stream->st->has_r && stream->st->r.object_entries)) { + ScrStr *canonical = scr_bytes_normalize_encoding(encoding->v.str); + if (!canonical) return NULL; + ScrBytes *b = scr_stream_buffer(scr_bytes_from_str(chunk->v.str, canonical)); + scr_str_release(canonical); + scr_stream_unshift(stream, b); + scr_bytes_release(b); + } else { + scr_stream_unshift_dyn(stream, chunk); + } if (scr_exc_pending()) return NULL; ScrStreamState *st = stream->st; bool more = chunk->kind != SCR_DYN_NULL && st->has_r && !st->destroyed && !st->errored && @@ -8169,7 +8184,7 @@ static ScrDyn *scr_stream_dyn_call(ScrStream *stream, ScrDyn *self, const char * } } else if (!strcmp(method, "eventNames")) result = scr_stream_dyn_event_names(stream); else if (!strcmp(method, "push")) result = scr_stream_dyn_push(stream, args, argc); - else if (!strcmp(method, "unshift")) result = scr_stream_dyn_unshift(stream, first); + else if (!strcmp(method, "unshift")) result = scr_stream_dyn_unshift(stream, args, argc); else if (!strcmp(method, "setDefaultEncoding")) { ScrStream *returned = scr_stream_set_default_encoding(stream, first); if (returned) scr_stream_release(returned); diff --git a/tests/corpus/8232-native-streams-untyped.cjs b/tests/corpus/8232-native-streams-untyped.cjs index b70017b5a..fb1c1f0c1 100644 --- a/tests/corpus/8232-native-streams-untyped.cjs +++ b/tests/corpus/8232-native-streams-untyped.cjs @@ -54,3 +54,27 @@ const w = new Writable({ }); w.on("finish", () => console.log("finish")); drain(w); + +// unshift(string, encoding) puts the decoded bytes at the front; an +// unknown encoding throws. +const bytes = new Readable({ read() {} }); +const parts = []; +bytes.on("data", (c) => parts.push(c.toString("hex"))); +bytes.on("end", () => console.log("unshift bytes", parts.join("|"))); +(function (s) { + console.log(s.unshift("e9", "hex"), s.unshift("aGk=", "base64"), s.unshift("é", "latin1"), s.unshift("x", "utf8")); + try { + s.unshift("x", "bogus"); + } catch (e) { + console.log(e.code, e.message); + } + s.push(null); +})(bytes); +const text = new Readable({ read() {} }); +text.setEncoding("utf8"); +text.on("data", (c) => console.log("unshift text", JSON.stringify(c))); +(function (s) { + s.unshift("c3a9", "hex"); + s.unshift("41", "hex"); + s.push(null); +})(text); From d9fdd81ee92ed8b60dbceb6a311843e119207059 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:32:40 -0500 Subject: [PATCH 153/259] Construct X509Certificate bound through a require() member `const X = require("crypto").X509Certificate; new X(data)` now resolves to the builtin class, so the standard-library constructor fence reported SC2020 for it before the X509Certificate lowering ran. That lowering now runs ahead of the fence. Corpus 8231 constructs a certificate through the binding. --- .../src/frontend/lowering/lower-classes.ts | 189 +++++++++--------- .../8231-builtin-member-binding-new.cjs | 27 ++- 2 files changed, 122 insertions(+), 94 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index 8bd5e57d7..fc89dc6b1 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -10122,6 +10122,102 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { const agent = lowerHttpAgentNew(lowerer, expr); if (agent) return agent; } + // `new crypto.X509Certificate(data)` — the Dirent-style data record: + // the certificate's lowered members (fingerprint — the SHA-1 of the + // DER, uppercase colon-separated — plus the validFrom/validTo + // validity window in Node's ASN1_TIME_print shape) compute AT + // CONSTRUCTION, when Node parses too, so unparseable input throws + // Node's exact PEM error here (ERR_OSSL_PEM_NO_START_LINE) and the + // handle never exists. Both import forms (`crypto.X509Certificate` + // through the namespace, named `X509Certificate`); Buffer input only + // — the readFileSync idiom. mapType interns the matching record, so + // locals and the composed member reads all flow. The data argument + // feeds THREE field computations, so construction goes through an + // interned helper whose parameter evaluates it exactly once. + // It runs before the standard-library constructor fence below, which + // also sees `const X = require("crypto").X509Certificate` as the + // builtin class. + { + const callee = expr.expression; + const isX509 = + (ts.isPropertyAccessExpression(callee) && + callee.name.text === "X509Certificate" && + lowerer.builtinNamespaceModuleOf(callee.expression) === "crypto") || + (ts.isIdentifier(callee) && + (() => { + const bi = lowerer.builtinImportOf(callee); + return bi?.module === "crypto" && bi.member === "X509Certificate"; + })()); + if (isX509) { + const args: readonly ts.Expression[] = expr.arguments?.nodes ?? []; + if (args.length !== 1) { + lowerer.noLowering( + "X509Certificate with this argument shape", + expr, + "the supported form is new X509Certificate(readFileSync(path))", + ); + } + const data = lowerer.lowerExpr(args[0]!); + const isBytes = data.type.kind === "bytes" && data.type.elem === "u8"; + if (!isBytes && data.type.kind !== "string") { + lowerer.noLowering( + `X509Certificate over '${lowerer.fmt(data.type)}' data`, + args[0]!, + "pass the certificate Buffer or PEM string (an fs.readFileSync result)", + ); + } + const t = lowerer.mapTypeOf(lowerer.typeOf(expr)); + if (t?.kind !== "record") lowerer.badType(expr, lowerer.typeOf(expr)); + const key = `x509.record:${isBytes ? "bytes" : "str"}`; + let helper = lowerer.valueHelpers.get(key); + if (!helper) { + helper = keyedHelperName(lowerer, "%x509.record", key); + lowerer.valueHelpers.set(key, helper); + const dataT = data.type; + const dRef: IrExpr = { kind: "varRef", localId: "d.0", type: dataT, loc }; + const field = ( + name: string, + fn: + | "crypto.x509Fingerprint" + | "crypto.x509FingerprintStr" + | "crypto.x509ValidFrom" + | "crypto.x509ValidFromStr" + | "crypto.x509ValidTo" + | "crypto.x509ValidToStr", + ): { name: string; value: IrExpr } => ({ + name, + value: { kind: "libCall", fn, args: [dRef], type: STRING, loc }, + }); + lowerer.liftedFns.push({ + name: helper, + params: [{ localId: "d.0", name: "d", type: dataT }], + returnType: t, + locals: [{ id: "d.0", name: "d", type: dataT, mutable: false }], + body: [ + { + kind: "return", + value: { + kind: "recordLit", + fields: [ + field( + "fingerprint", + isBytes ? "crypto.x509Fingerprint" : "crypto.x509FingerprintStr", + ), + field("validFrom", isBytes ? "crypto.x509ValidFrom" : "crypto.x509ValidFromStr"), + field("validTo", isBytes ? "crypto.x509ValidTo" : "crypto.x509ValidToStr"), + ], + type: t, + loc, + }, + loc, + }, + ], + loc, + }); + } + return { kind: "call", callee: helper, args: [data], type: t, loc }; + } + } if ( ts.isIdentifier(expr.expression) || (ts.isPropertyAccessExpression(expr.expression) && @@ -10907,99 +11003,6 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { ); } } - // `new crypto.X509Certificate(data)` — the Dirent-style data record: - // the certificate's lowered members (fingerprint — the SHA-1 of the - // DER, uppercase colon-separated — plus the validFrom/validTo - // validity window in Node's ASN1_TIME_print shape) compute AT - // CONSTRUCTION, when Node parses too, so unparseable input throws - // Node's exact PEM error here (ERR_OSSL_PEM_NO_START_LINE) and the - // handle never exists. Both import forms (`crypto.X509Certificate` - // through the namespace, named `X509Certificate`); Buffer input only - // — the readFileSync idiom. mapType interns the matching record, so - // locals and the composed member reads all flow. The data argument - // feeds THREE field computations, so construction goes through an - // interned helper whose parameter evaluates it exactly once. - { - const callee = expr.expression; - const isX509 = - (ts.isPropertyAccessExpression(callee) && - callee.name.text === "X509Certificate" && - lowerer.builtinNamespaceModuleOf(callee.expression) === "crypto") || - (ts.isIdentifier(callee) && - (() => { - const bi = lowerer.builtinImportOf(callee); - return bi?.module === "crypto" && bi.member === "X509Certificate"; - })()); - if (isX509) { - const args: readonly ts.Expression[] = expr.arguments?.nodes ?? []; - if (args.length !== 1) { - lowerer.noLowering( - "X509Certificate with this argument shape", - expr, - "the supported form is new X509Certificate(readFileSync(path))", - ); - } - const data = lowerer.lowerExpr(args[0]!); - const isBytes = data.type.kind === "bytes" && data.type.elem === "u8"; - if (!isBytes && data.type.kind !== "string") { - lowerer.noLowering( - `X509Certificate over '${lowerer.fmt(data.type)}' data`, - args[0]!, - "pass the certificate Buffer or PEM string (an fs.readFileSync result)", - ); - } - const t = lowerer.mapTypeOf(lowerer.typeOf(expr)); - if (t?.kind !== "record") lowerer.badType(expr, lowerer.typeOf(expr)); - const key = `x509.record:${isBytes ? "bytes" : "str"}`; - let helper = lowerer.valueHelpers.get(key); - if (!helper) { - helper = keyedHelperName(lowerer, "%x509.record", key); - lowerer.valueHelpers.set(key, helper); - const dataT = data.type; - const dRef: IrExpr = { kind: "varRef", localId: "d.0", type: dataT, loc }; - const field = ( - name: string, - fn: - | "crypto.x509Fingerprint" - | "crypto.x509FingerprintStr" - | "crypto.x509ValidFrom" - | "crypto.x509ValidFromStr" - | "crypto.x509ValidTo" - | "crypto.x509ValidToStr", - ): { name: string; value: IrExpr } => ({ - name, - value: { kind: "libCall", fn, args: [dRef], type: STRING, loc }, - }); - lowerer.liftedFns.push({ - name: helper, - params: [{ localId: "d.0", name: "d", type: dataT }], - returnType: t, - locals: [{ id: "d.0", name: "d", type: dataT, mutable: false }], - body: [ - { - kind: "return", - value: { - kind: "recordLit", - fields: [ - field( - "fingerprint", - isBytes ? "crypto.x509Fingerprint" : "crypto.x509FingerprintStr", - ), - field("validFrom", isBytes ? "crypto.x509ValidFrom" : "crypto.x509ValidFromStr"), - field("validTo", isBytes ? "crypto.x509ValidTo" : "crypto.x509ValidToStr"), - ], - type: t, - loc, - }, - loc, - }, - ], - loc, - }); - } - return { kind: "call", callee: helper, args: [data], type: t, loc }; - } - } // `new X(...)` through a class VALUE (a classval-typed binding, array // element, map read, param): the newValue dispatch through the class // object's construct thunk. Arguments complete against the STATIC diff --git a/tests/corpus/8231-builtin-member-binding-new.cjs b/tests/corpus/8231-builtin-member-binding-new.cjs index 1549425f7..df1b2ebb3 100644 --- a/tests/corpus/8231-builtin-member-binding-new.cjs +++ b/tests/corpus/8231-builtin-member-binding-new.cjs @@ -1,12 +1,14 @@ // `new` of a builtin class bound through a member of a require() result // (`const SD = require("string_decoder").StringDecoder`, the spelling of // Node's own tests): the binding resolves to the class, as the -// destructured `const { StringDecoder } = require(...)` does. +// destructured `const { StringDecoder } = require(...)` does, also for the +// X509Certificate record. "use strict"; const SD = require("string_decoder").StringDecoder; const Readable = require("stream").Readable; const PassThrough = require("stream").PassThrough; const Transform = require("stream").Transform; +const X509 = require("crypto").X509Certificate; const decoder = new SD("utf8"); console.log(decoder.encoding); @@ -33,3 +35,26 @@ const upper = new Transform({ }); upper.on("data", (chunk) => console.log("transform", String(chunk))); upper.end("shout"); + +// The X509Certificate record constructs through the same binding. +const PEM = `-----BEGIN CERTIFICATE----- +MIIDEzCCAfugAwIBAgIUMsBCFtPck8TATMJzfikgW963q3AwDQYJKoZIhvcNAQEL +BQAwGDEWMBQGA1UEAwwNdHNuYXRpdmUtdGVzdDAgFw0yNjA3MTcxNzUyMTFaGA8y +MTI2MDYyMzE3NTIxMVowGDEWMBQGA1UEAwwNdHNuYXRpdmUtdGVzdDCCASIwDQYJ +KoZIhvcNAQEBBQADggEPADCCAQoCggEBALRspe2XjtKvNU7Ws5JfqzmTCPmWtfw0 +1Uha271hNp/30VstOxWLbpqPrXDvIwJMN4o8CRp92Y1hcmS36m9QS5qfXJFw+n+S +SWGpFdMNvp6hro0OoNBA+anuKWoTsMyHSwe8ND0fyobQbgAXJ0+snmuK0E2ii+CM +IoUqYbK57nHeyHfISLupgrRoNGXjDHv4v+RSr3MJDag6BLA+/yVjkBOBOT6kaE4K +oyNXYYsfFxGnB/4pDSanV/UsfJ4wHXkVn18ndZHIzTsZMUkV4BecF8UaMrP+u8NI +c5wce0uWLFFEneK4q15iVvk9TaY0g1Uj69ryRT3L58W7RYYuHu7cVB0CAwEAAaNT +MFEwHQYDVR0OBBYEFLT2GqaTmxDhntPxMWaUZvA3s9V5MB8GA1UdIwQYMBaAFLT2 +GqaTmxDhntPxMWaUZvA3s9V5MA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL +BQADggEBAFcTLVJIyhbIKHfOnGM5T+Kzu5IoDlqzr+Rdx/0IKFLVDqEA9ihEme07 +K/d246pOW5LBceVDY2eMikDpIOjYPEoe9C+Ftv5zrCaDw1wtXrq8a7/eS5B+3TzL +k8c1SVVDPIbmViAZNRmnkwCPBsIF9xIfMFhxz4BTJrm/Lt2Hv1GcRBQx/yRK89sj +JiGnsTna//4mPGRGYw+dRCq4tbyr8HbBKdJmbzOCb4CPKfwAMKUpd4e0Ao7jh/BU +EML7B3BEzv5Jw/BT7B39wAfDyhq32PnRnZefF+7pAmpkklHbckBtZtWn02zwQazv +5z62tszZee2i4BouJiyFnb30F6Pebs4= +-----END CERTIFICATE-----`; +const cert = new X509(PEM); +console.log(cert.fingerprint, cert.validFrom, cert.validTo); From 54f12d73dccf1b2cb62bb36ac920e7b8c4e0f5d0 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:37:07 -0500 Subject: [PATCH 154/259] Use built-in typed-array species, copy slices after species creation, and read element descriptors - A built-in typed-array constructor set as a view's `constructor` is its own species, as the getter it inherits from %TypedArray% returns it: `u8.constructor = Float64Array; u8.map(f)` makes a Float64Array. An own Symbol.species on the constructor still wins. - TypedArray.prototype.slice with a species constructor creates the result first and then copies the source's current elements, up to its current length: a constructor that changes the source is seen. - Object.defineProperty on a typed-array element reads the descriptor as ToPropertyDescriptor does, through its getters and in its order, and throws a TypeError for a primitive descriptor or an accessor with a value. The generic object path shares the same reader. --- packages/runtime/src/scr_json.c | 176 ++++++++++++------ .../7753-typed-array-named-properties.js | 23 +++ 2 files changed, 140 insertions(+), 59 deletions(-) diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index be63e1436..f28160d42 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -5024,6 +5024,29 @@ static double *dyn_bytes_values(const ScrBytes *b, size_t n) { return values; } +static ScrDyn *scr_dyn_symbol_receiver(const ScrDyn *value); +static ScrDynEntry *scr_dyn_symbol_entry(const ScrDyn *receiver, const ScrDyn *key, bool own); + +/* Whether a typed-array constructor has a Symbol.species of its own, + * shadowing the one it inherits from %TypedArray%. */ +static bool scr_bytes_ctor_own_species(const ScrDyn *constructor) { + ScrDyn *table = scr_dyn_symbol_receiver(constructor); + bool own = table && scr_dyn_symbol_entry(table, scr_species_symbol, true); + scr_dyn_release(table); + return own; +} + +/* A relative index (ToIntegerOrInfinity, negatives from the end), clamped + * to [0, len], as scr_bytes_slice computes it. */ +static size_t scr_bytes_rel_index_of(double i, size_t len) { + if (i != i) return 0; + double t = trunc(i); + if (t < 0) t += (double)len; + if (t < 0) return 0; + if (t > (double)len) return len; + return (size_t)t; +} + /* SpeciesConstructor of a typed array: NULL (and no exception) for the * default constructor of its kind, else the species constructor (+1). * Only a `constructor` the program set on the view can differ. */ @@ -5044,6 +5067,13 @@ static ScrDyn *scr_bytes_species(ScrDyn *recv, bool *failed) { return NULL; } ScrDyn *species = scr_species_symbol ? scr_dyn_symbol_key_get(constructor, scr_species_symbol, true) : NULL; + if (species && species->kind == SCR_DYN_UNDEF && scr_bytes_ctor_elem(constructor) >= 0 && + !scr_bytes_ctor_own_species(constructor)) { + /* A built-in typed-array constructor inherits %TypedArray%'s species + * getter, which returns the constructor itself. */ + scr_dyn_release(species); + species = scr_dyn_retain(constructor); + } scr_dyn_release(constructor); if (scr_exc_pending()) { scr_dyn_release(species); *failed = true; return NULL; } if (!species || species->kind == SCR_DYN_UNDEF || species->kind == SCR_DYN_NULL || @@ -5096,33 +5126,40 @@ ScrDyn *scr_dyn_bytes_method(ScrDyn *recv, const char *method, ScrDyn *const *ar bool failed; ScrDyn *species = recv->buffer ? NULL : scr_bytes_species(recv, &failed); if (!recv->buffer && failed) return NULL; + if (species && !subarray) { + /* TypedArraySpeciesCreate runs first: the constructor can change the + * source, and the copy reads its elements as they are afterwards, + * up to its current length. */ + size_t from = scr_bytes_rel_index_of(startD, blen), to = scr_bytes_rel_index_of(endD, blen); + size_t count = to > from ? to - from : 0; + ScrDyn *result = scr_bytes_static_create(species, count); + scr_dyn_release(species); + if (!result) return NULL; + size_t end = to < bytes->len ? to : bytes->len; + for (size_t k = from, n = 0; k < end; k++, n++) + scr_bytes_set(result->v.bytes, (double)n, scr_bytes_get(bytes, (double)k)); + return result; + } ScrBytes *out = subarray ? scr_bytes_subarray(bytes, startD, endD) : scr_bytes_slice(bytes, startD, endD); if (!species) { ScrDyn *d = recv->buffer ? scr_dyn_new_buffer(out) : scr_dyn_new_bytes(out); scr_bytes_release(out); return d; } - ScrDyn *result; - if (subarray) { - /* The species constructor views the same buffer. */ - ScrDyn *ctor_args = scr_dyn_new_arr(); - scr_dyn_arr_push(ctor_args, scr_array_buffer_from_bytes(bytes)); - scr_dyn_arr_push(ctor_args, scr_dyn_new_num(scr_bytes_byte_offset(out))); - scr_dyn_arr_push(ctor_args, scr_dyn_new_num((double)out->len)); - ScrStr *what = scr_str_new("TypedArray species", 18); - result = scr_dyn_construct(species, ctor_args, what); - scr_str_release(what); - scr_dyn_release(ctor_args); - if (result && (result->kind != SCR_DYN_BYTES || result->v.bytes->is_data_view)) { - scr_dyn_release(result); - result = NULL; - static const char message[] = "this is not a typed array."; - scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); - } - } else { - result = scr_bytes_static_create(species, out->len); - for (size_t i = 0; result && i < out->len; i++) - scr_bytes_set(result->v.bytes, (double)i, scr_bytes_get(out, (double)i)); + /* A subarray's species constructor views the same buffer. */ + ScrDyn *ctor_args = scr_dyn_new_arr(); + scr_dyn_arr_push(ctor_args, scr_array_buffer_from_bytes(bytes)); + scr_dyn_arr_push(ctor_args, scr_dyn_new_num(scr_bytes_byte_offset(out))); + scr_dyn_arr_push(ctor_args, scr_dyn_new_num((double)out->len)); + ScrStr *what = scr_str_new("TypedArray species", 18); + ScrDyn *result = scr_dyn_construct(species, ctor_args, what); + scr_str_release(what); + scr_dyn_release(ctor_args); + if (result && (result->kind != SCR_DYN_BYTES || result->v.bytes->is_data_view)) { + scr_dyn_release(result); + result = NULL; + static const char message[] = "this is not a typed array."; + scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); } scr_dyn_release(species); scr_bytes_release(out); @@ -6382,6 +6419,45 @@ bool scr_dyn_same_value(const ScrDyn *left, const ScrDyn *right) { static void scr_dyn_descriptor_fields_drop(ScrDyn **fields) { for (size_t i = 0; i < 6; i++) scr_dyn_release(fields[i]); } + +/* ToPropertyDescriptor: the present fields of `descriptor` (enumerable, + * configurable, value, writable, get, set; +1 each, NULL when absent), + * read in that order through any getters. False with a TypeError pending + * for a primitive descriptor, a getter's exception, or an invalid + * combination; every field is then released. */ +static bool scr_dyn_descriptor_fields_read(const ScrDyn *descriptor, ScrDyn **fields) { + for (size_t i = 0; i < 6; i++) fields[i] = NULL; + if (descriptor->kind != SCR_DYN_OBJ) { + static const char msg[] = "Property description must be an object"; + scr_throw_error_msg(SCR_ERR_TYPE, msg, sizeof msg - 1); + return false; + } + static const char *const names[] = {"enumerable", "configurable", "value", "writable", "get", "set"}; + static const size_t lengths[] = {10, 12, 5, 8, 3, 3}; + for (size_t i = 0; i < 6; i++) { + if (!scr_dyn_obj_get(descriptor, names[i], lengths[i])) continue; + fields[i] = scr_dyn_obj_read(descriptor, names[i], lengths[i]); + if (!fields[i]) { + scr_dyn_descriptor_fields_drop(fields); + return false; + } + } + ScrDyn *get = fields[4], *set = fields[5]; + if ((get || set) && (fields[2] || fields[3])) { + scr_dyn_descriptor_fields_drop(fields); + static const char msg[] = "Invalid property descriptor. Cannot both specify accessors and a value or writable attribute"; + scr_throw_error_msg(SCR_ERR_TYPE, msg, sizeof msg - 1); + return false; + } + if ((get && get->kind != SCR_DYN_UNDEF && get->kind != SCR_DYN_FUNC) || + (set && set->kind != SCR_DYN_UNDEF && set->kind != SCR_DYN_FUNC)) { + scr_dyn_descriptor_fields_drop(fields); + static const char msg[] = "Getter and setter must be functions"; + scr_throw_error_msg(SCR_ERR_TYPE, msg, sizeof msg - 1); + return false; + } + return true; +} static void scr_error_sync_cause(ScrDyn *view, const ScrStr *key); static void scr_error_sync_slots(const ScrDyn *view, ScrDyn *obj, const ScrStr *key); @@ -8374,12 +8450,19 @@ ScrDyn *scr_dyn_define_property(ScrDyn *target, ScrDyn *key, ScrDyn *descriptor) if (numeric) { /* [[DefineOwnProperty]] of an element: a valid index and a data * descriptor that keeps it writable, enumerable and configurable. */ + /* The descriptor is read first (ToPropertyDescriptor), through its + * getters, and must be an object. */ + ScrDyn *fields[6]; + if (!scr_dyn_descriptor_fields_read(descriptor, fields)) { + scr_str_release(name); + return NULL; + } + const ScrDyn *enumerable = fields[0], *configurable = fields[1], *value = fields[2]; + const ScrDyn *writable = fields[3]; + bool accessor = fields[4] || fields[5]; bool valid = !signbit(index) && trunc(index) == index && index < (double)target->v.bytes->len; - const ScrDyn *configurable = scr_dyn_obj_get(descriptor, "configurable", 12); - const ScrDyn *enumerable = scr_dyn_obj_get(descriptor, "enumerable", 10); - const ScrDyn *writable = scr_dyn_obj_get(descriptor, "writable", 8); - bool accessor = scr_dyn_obj_get(descriptor, "get", 3) || scr_dyn_obj_get(descriptor, "set", 3); if (!valid) { + scr_dyn_descriptor_fields_drop(fields); scr_str_release(name); static const char message[] = "Invalid typed array index"; scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); @@ -8387,6 +8470,7 @@ ScrDyn *scr_dyn_define_property(ScrDyn *target, ScrDyn *key, ScrDyn *descriptor) } if (accessor || (configurable && !scr_dyn_truthy(configurable)) || (enumerable && !scr_dyn_truthy(enumerable)) || (writable && !scr_dyn_truthy(writable))) { + scr_dyn_descriptor_fields_drop(fields); ScrJsonBuf message; scr_jb_init(&message); scr_jb_puts(&message, "Cannot redefine property: "); @@ -8396,13 +8480,15 @@ ScrDyn *scr_dyn_define_property(ScrDyn *target, ScrDyn *key, ScrDyn *descriptor) return NULL; } scr_str_release(name); - const ScrDyn *value = scr_dyn_obj_get(descriptor, "value", 5); double number; + bool stored = true; if (value) { - if (!scr_dyn_number_coerce_js(value, &number)) return NULL; - scr_bytes_set(target->v.bytes, index, number); + stored = scr_dyn_number_coerce_js(value, &number); + /* The conversion can run user code; the index is checked again. */ + if (stored && index < (double)target->v.bytes->len) scr_bytes_set(target->v.bytes, index, number); } - return scr_dyn_retain(target); + scr_dyn_descriptor_fields_drop(fields); + return stored ? scr_dyn_retain(target) : NULL; } bool fenced = scr_bytes_protocol_name(name) && !scr_bytes_has_named(target, name); if (fenced) scr_bytes_protocol_fence(name->data, name->len); @@ -8420,44 +8506,16 @@ ScrDyn *scr_dyn_define_property(ScrDyn *target, ScrDyn *key, ScrDyn *descriptor) } ScrStr *name = scr_dyn_property_key(key); if (!name) return NULL; - if (descriptor->kind != SCR_DYN_OBJ) { + ScrDyn *fields[6]; + if (!scr_dyn_descriptor_fields_read(descriptor, fields)) { scr_str_release(name); - static const char msg[] = "Property description must be an object"; - scr_throw_error_msg(SCR_ERR_TYPE, msg, sizeof msg - 1); return NULL; } - static const char *const names[] = {"enumerable", "configurable", "value", "writable", "get", "set"}; - static const size_t lengths[] = {10, 12, 5, 8, 3, 3}; - ScrDyn *fields[6] = {NULL}; - for (size_t i = 0; i < 6; i++) { - if (!scr_dyn_obj_get(descriptor, names[i], lengths[i])) continue; - fields[i] = scr_dyn_obj_read(descriptor, names[i], lengths[i]); - if (!fields[i]) { - scr_dyn_descriptor_fields_drop(fields); - scr_str_release(name); - return NULL; - } - } ScrDyn *e = fields[0], *c = fields[1], *value = fields[2]; ScrDyn *w = fields[3], *get = fields[4], *set = fields[5]; ScrDynEntry *prior = scr_dyn_entry(target, name); bool accessor_descriptor = get || set; bool data_descriptor = value || w; - if (accessor_descriptor && data_descriptor) { - scr_dyn_descriptor_fields_drop(fields); - scr_str_release(name); - static const char msg[] = "Invalid property descriptor. Cannot both specify accessors and a value or writable attribute"; - scr_throw_error_msg(SCR_ERR_TYPE, msg, sizeof msg - 1); - return NULL; - } - if ((get && get->kind != SCR_DYN_UNDEF && get->kind != SCR_DYN_FUNC) || - (set && set->kind != SCR_DYN_UNDEF && set->kind != SCR_DYN_FUNC)) { - scr_dyn_descriptor_fields_drop(fields); - scr_str_release(name); - static const char msg[] = "Getter and setter must be functions"; - scr_throw_error_msg(SCR_ERR_TYPE, msg, sizeof msg - 1); - return NULL; - } bool accessor = accessor_descriptor || (!data_descriptor && prior && prior->accessor); bool writable = w ? scr_dyn_truthy(w) : prior && !prior->accessor && !accessor ? prior->writable : false; bool enumerable = e ? scr_dyn_truthy(e) : prior ? prior->enumerable : false; diff --git a/tests/corpus/7753-typed-array-named-properties.js b/tests/corpus/7753-typed-array-named-properties.js index b49f100b5..449e78ac7 100644 --- a/tests/corpus/7753-typed-array-named-properties.js +++ b/tests/corpus/7753-typed-array-named-properties.js @@ -23,6 +23,17 @@ function expandos(TA) { try { Object.defineProperty(a, "7", { value: 1 }); } catch (e) { console.log(e.constructor.name, e.message); } try { Object.defineProperty(a, "-0", { value: 1 }); } catch (e) { console.log(e.constructor.name, e.message); } try { Object.defineProperty(a, "0", { get() { return 1; } }); } catch (e) { console.log(e.constructor.name, e.message); } + // An element's descriptor is read through its getters, and must be an object. + const got = []; + Object.defineProperty(a, "1", { get value() { got.push("value"); return 6; }, get enumerable() { got.push("enumerable"); return true; } }); + console.log(a[1], got); + for (const bad of [5, "x", undefined]) { + try { Object.defineProperty(a, "0", bad); } catch (e) { console.log(e.constructor.name); } + } + try { Object.defineProperty(a, "9", 5); } catch (e) { console.log(e.constructor.name); } + try { Object.defineProperty(a, "0", { get configurable() { throw new RangeError("read"); } }); } catch (e) { console.log(e.constructor.name, e.message); } + try { Object.defineProperty(a, "0", { value: 1, get: undefined }); } catch (e) { console.log(e.constructor.name); } + console.log(a[0], a[1]); let reads = 0; Object.defineProperty(a, "g", { get() { reads++; return this.length; }, enumerable: true }); console.log(a.g, reads, new TA(0)); @@ -56,6 +67,18 @@ function species(TA, Other) { const u = new TA([1, 2, 3]); u.constructor = { [Symbol.species]: Uint16Array }; console.log(u.filter(() => true), u.subarray(1), u.subarray(1).constructor === Uint16Array); + // A built-in constructor set as `constructor` is its own species. + const w = new TA([1, 2, 3]); + w.constructor = Float64Array; + const wm = w.map((v) => v / 2), ws = w.slice(1); + console.log(wm, wm.constructor === Float64Array, ws, ws.constructor === Float64Array, w.filter((v) => v > 1)); + w.constructor = TA; + console.log(w.map((v) => v / 2).constructor === TA); + // slice copies the source after the species constructor ran. + const x = new TA([1, 2, 3, 4]); + x.constructor = {}; + x.constructor[Symbol.species] = function (n) { x[1] = 40; x[2] = 30; return new Other(n); }; + console.log(x.slice(1, 3), x.slice(-1), x.slice(2, 1)); } function reflection(TA) { From 9b64c7388d7b675a645ae09099e955feea03fb55 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:38:12 -0500 Subject: [PATCH 155/259] Resume hoisted-call writes reached from earlier bails, and shift only by exact powers of two - A speculated write with hoisted calls resumes over its stored call results only when its own check failed. Reached in the resume copy from an earlier write's failed check, its calls never ran on that iteration, so it now runs as written: the calls happen once and the arithmetic reads their fresh results. - A literal divisor is a power of two only when it is exactly 2^k with k in [0, 52]. Math.log2 rounds 2^52 + 1 to 52, so `Math.floor(v / (2^52 + 1))` was emitted as a shift by 52. - A helper expands only when every call in its body is of another helper that expands, so an expansion never moves a call with effects ahead of an argument read. Hoisting already refused such writes; the classification now says so itself. --- packages/compiler/src/backend/llvm/emitter.ts | 37 ++++++++++----- .../backend/llvm/speculative-integers.test.ts | 30 ++++++++++++ .../src/backend/llvm/speculative-integers.ts | 29 ++++++++---- tests/corpus/7757-speculative-key-chains.ts | 47 +++++++++++++++++++ 4 files changed, 124 insertions(+), 19 deletions(-) diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 4080084de..eb1fa4157 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -1457,14 +1457,20 @@ export class LlEmitter { /** What speculative loop planning may assume here (SpeculationContext). */ speculationContext(): SpeculationContext { + const inlinable = (callee: string): InlinableFunction | undefined => { + if (!this.inlinableFunctions.has(callee)) { + // Unset while its body is checked: a recursive helper is not inlinable. + this.inlinableFunctions.set(callee, undefined); + const fn = this.fnByName.get(callee); + this.inlinableFunctions.set( + callee, + fn ? inlinableNumberFunction(fn, inlinable) : undefined, + ); + } + return this.inlinableFunctions.get(callee); + }; return { - inlinable: (callee) => { - if (!this.inlinableFunctions.has(callee)) { - const fn = this.fnByName.get(callee); - this.inlinableFunctions.set(callee, fn ? inlinableNumberFunction(fn) : undefined); - } - return this.inlinableFunctions.get(callee); - }, + inlinable, unaliased: (id) => { const local = this.currentLocals.get(id); return ( @@ -5626,15 +5632,24 @@ export class LlEmitter { if (resume && !resume.placed && !this.B.isTerminated()) { // The fast copy's failed checks re-execute this statement here. resume.placed = true; - this.B.br(resume.label); - this.B.startBlock(resume.label); - // A write with hoisted leaves re-executes its arithmetic over the - // leaves' stored doubles: each leaf ran once, in the fast copy. + // A write with hoisted leaves resumed from its own failed check + // re-executes its arithmetic over the leaves' stored doubles: each + // leaf ran once, in the fast copy. Reached from an earlier statement + // of this copy (a failed check before it), its leaves never ran, so + // it runs as written. const rewritten = this.speculationResumeValues?.get(s); if (rewritten !== undefined && rewritten.leaves.length > 0) { + const join = this.B.newLabel("spec.resume.join"); + this.emitStmt(s); + if (!this.B.isTerminated()) this.B.br(join); + this.B.startBlock(resume.label); this.emitStmt(withSpeculativeValue(s, rewritten.value)); + if (!this.B.isTerminated()) this.B.br(join); + this.B.startBlock(join); return; } + this.B.br(resume.label); + this.B.startBlock(resume.label); } if (this.speculation?.writes.has(s)) { this.emitSpeculativeWrite(s, this.speculation.resume.get(s)); diff --git a/packages/compiler/src/backend/llvm/speculative-integers.test.ts b/packages/compiler/src/backend/llvm/speculative-integers.test.ts index 86055b1b6..151fab7c4 100644 --- a/packages/compiler/src/backend/llvm/speculative-integers.test.ts +++ b/packages/compiler/src/backend/llvm/speculative-integers.test.ts @@ -339,6 +339,36 @@ test("Math.floor needs a power-of-two divisor, and expansion pure arguments", () body: [{ kind: "exprStmt", expr: call("log", []), loc }], }; expect(inlinableNumberFunction(effectful as never)).toBeUndefined(); + // A divisor next to a power of two is not one, though Math.log2 rounds it to 52. + const near = (d: number): IrExpr => libCall("math.floor", [bin("/", ref("a"), num(d))]); + expect(rewriteSpeculable(near(2 ** 52), {})).not.toBeNull(); + expect(rewriteSpeculable(near(2 ** 52 + 1), {})).toBeNull(); + expect(rewriteSpeculable(near(2 ** 53), {})).toBeNull(); + expect(rewriteSpeculable(near(0.5), {})).toBeNull(); +}); + +test("a helper's own calls must be of helpers that expand too", () => { + // `function outer(v, n) { return trim(v, n) + other(v); }` + const outer = { + ...(trim as object), + name: "outer", + body: [ + { + kind: "return", + value: bin("+", call("trim", [ref("v"), ref("n")]), call("other", [ref("v")])), + loc, + }, + ], + }; + const helpers = (callee: string) => + callee === "trim" ? inlinableNumberFunction(trim) : undefined; + expect(inlinableNumberFunction(outer as never)).toBeUndefined(); + expect(inlinableNumberFunction(outer as never, helpers)).toBeUndefined(); + const pure = { + ...(outer as object), + body: [{ kind: "return", value: bin("*", call("trim", [ref("v"), ref("n")]), num(2)), loc }], + }; + expect(inlinableNumberFunction(pure as never, helpers)).toBeDefined(); }); test("other leaves are hoisted only when no call can change the write's locals", () => { diff --git a/packages/compiler/src/backend/llvm/speculative-integers.ts b/packages/compiler/src/backend/llvm/speculative-integers.ts index 69066a5b4..1d33a71ce 100644 --- a/packages/compiler/src/backend/llvm/speculative-integers.ts +++ b/packages/compiler/src/backend/llvm/speculative-integers.ts @@ -86,8 +86,12 @@ const MAX_INLINE_NODES = 64; /** A function that only returns arithmetic over its number parameters: * `function trim(v, n) { return v - Math.floor(v / Math.pow(2, n)) * Math.pow(2, n); }`. * Its call evaluates nothing but its arguments, so a speculated write may - * expand it in place. */ -export function inlinableNumberFunction(fn: IrFunction): InlinableFunction | undefined { + * expand it in place. A call in its body must be of another such function + * (`resolve`): any other call could change what the expansion reads. */ +export function inlinableNumberFunction( + fn: IrFunction, + resolve?: (callee: string) => InlinableFunction | undefined, +): InlinableFunction | undefined { if ( fn.async || fn.generator || @@ -126,7 +130,7 @@ export function inlinableNumberFunction(fn: IrFunction): InlinableFunction | und case "libCall": return (e.fn === "math.floor" || e.fn === "math.pow") && e.args.every(pure); case "call": - return e.args.every(pure); + return resolve?.(e.callee) !== undefined && e.args.every(pure); default: return false; } @@ -175,13 +179,18 @@ function substitute(e: IrExpr, args: ReadonlyMap): IrExpr { } } +/** k when `value` is exactly 2^k with k in [0, 52], else null. + * Math.log2 rounds: 2^52 + 1 gives 52, so the power is compared back. */ +function exactPowerOfTwo(value: number): number | null { + if (!(value >= 1)) return null; + const k = Math.round(Math.log2(value)); + return k >= 0 && k <= 52 && 2 ** k === value ? k : null; +} + /** Whether `e` is a power of two speculation can shift by: * `Math.pow(2, n)` or a literal 2^k with k in [0, 52]. */ function powerOfTwo(e: IrExpr): boolean { - if (e.kind === "numLit") { - const k = Math.log2(e.value); - return Number.isInteger(k) && k >= 0 && k <= 52; - } + if (e.kind === "numLit") return exactPowerOfTwo(e.value) !== null; return ( e.kind === "libCall" && e.fn === "math.pow" && @@ -1022,7 +1031,11 @@ function exponentOf( reads: ReadonlyMap, integral: boolean, ): string { - if (e.kind === "numLit") return String(Math.log2(e.value)); + if (e.kind === "numLit") { + const k = exactPowerOfTwo(e.value); + if (k === null) throw new InternalCompilerError("llvm emitter bug: speculative power of two"); + return String(k); + } if (e.kind !== "libCall") throw new InternalCompilerError("llvm emitter bug: speculative power of two"); const n = emitSpeculativeInteger(host, e.args[1]!, bail, reads, integral); diff --git a/tests/corpus/7757-speculative-key-chains.ts b/tests/corpus/7757-speculative-key-chains.ts index bdbd12e1e..206b53827 100644 --- a/tests/corpus/7757-speculative-key-chains.ts +++ b/tests/corpus/7757-speculative-key-chains.ts @@ -54,6 +54,49 @@ function hoisted(n: number): number { return acc; } +// A check that fails before a write with a hoisted call: that write still +// makes its call on the iteration that bails. +function tally(x: number): number { + calls++; + return x * 2 + 1; +} +function chained(n: number): number { + let a = 1; + let b = 1; + for (let i = 0; i < n; i++) { + a = a * 3 + i; + b = (b * 7 + tally(i) + (a % 11)) % 1000003; + } + return b; +} + +// A divisor next to a power of two is not one: 2^52 + 1 divides as itself. +function nearPowers(start: number, steps: number): number[] { + const out: number[] = []; + let v = start; + for (let i = 0; i < steps; i++) { + v = Math.floor(v / 4503599627370497) * 4 + Math.floor(v / 4503599627370496) + i; + out.push(v); + } + return out; +} + +// A helper that calls a function with effects is not expanded: its +// argument is read before the call runs. +let level = 0; +function raise(): number { + level += 100; + return 1; +} +function lifted(x: number): number { + return raise() + x; +} +function effectfulHelper(n: number): number { + let acc = 0; + for (let i = 0; i < n; i++) acc = (acc * 3 + lifted(level)) % 1000003; + return acc; +} + const codes = new Uint8Array(5000); let seed = 7; for (let i = 0; i < codes.length; i++) { @@ -65,3 +108,7 @@ console.log(shifts(1000, 3, 6), shifts(-1000, 2, 6), shifts(5, 53, 3), shifts(7. console.log(hoisted(20), calls); const short = codes.subarray(0, 3); console.log(chain(short, 2), chain(new Uint8Array(0), 2)); +calls = 0; +console.log(chained(34), chained(60), calls); +console.log(nearPowers(4503599627370496, 3), nearPowers(9007199254740991, 2)); +console.log(effectfulHelper(10), level); From 02ec0e86f607ce56a9a2241bb13aab08e25f23e6 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 16:54:24 -0500 Subject: [PATCH 156/259] Address review findings in the npm and CommonJS interop batch - Intl.Segmenter accepts an options object literal made only of `granularity` entries again, including the empty `{}` main accepted; with none the segmenter is a grapheme segmenter, and a repeated key takes its last value, as in JavaScript. - Namespace reads of a CommonJS module refuse a name that any module it re-exports assigns inside a function, not only the module itself: Node's namespace keeps the values from the end of evaluation. - The named-import link check treats `module.exports` as an export every CommonJS module provides, as Node 24 does, instead of throwing its missing-export SyntaxError. - The npm cases cjs-esm-named and cjs-lexer-aligned, which the batch no longer refuses at build time, are listed with the run-time SC1090 their CommonJS exports-object reads report. --- .../src/frontend/lowering/lower-classes.ts | 29 ++++++++++++------- .../compiler/src/frontend/lowering/lowerer.ts | 14 ++++++++- packages/compiler/src/frontend/program.ts | 27 +++++++++++++++-- .../main.ts | 10 ++++--- .../node_modules/text-width/index.d.ts | 1 + .../node_modules/text-width/index.js | 5 ++++ .../cjs-namespace-reexports/impl.cjs | 6 ++++ .../cjs-namespace-reexports/main.mjs | 7 +++++ .../cjs-namespace-reexports/package.json | 1 + .../cjs-namespace-reexports/wrapper.cjs | 2 ++ tests/harness/coverage.test.ts | 16 ++++++++++ tests/harness/npm.test.ts | 4 +-- 12 files changed, 101 insertions(+), 21 deletions(-) create mode 100644 tests/coverage-fixtures/cjs-namespace-reexports/impl.cjs create mode 100644 tests/coverage-fixtures/cjs-namespace-reexports/main.mjs create mode 100644 tests/coverage-fixtures/cjs-namespace-reexports/package.json create mode 100644 tests/coverage-fixtures/cjs-namespace-reexports/wrapper.cjs diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index e50466114..80ad97090 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -9950,23 +9950,30 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { const options = args[1]; let granularity = "grapheme"; if (options && !undefinedArg(options)) { - const properties = ts.isObjectLiteralExpression(options) ? options.properties.nodes : null; - const property = properties?.length === 1 ? properties[0] : undefined; - if ( - property === undefined || - !ts.isPropertyAssignment(property) || - !(ts.isIdentifier(property.name) || ts.isStringLiteral(property.name)) || - property.name.text !== "granularity" || - !ts.isStringLiteral(property.initializer) || - !granularities.includes(property.initializer.text) - ) { + // An object literal of `granularity` entries (none: the default; a + // repeated key: the last one, as in JavaScript). + if (!ts.isObjectLiteralExpression(options)) lowerer.noLowering( "Intl.Segmenter options", options, 'the native segmenter supports default options and { granularity: "grapheme" }; word and sentence segmentation remain unsupported', ); + for (const property of options.properties.nodes) { + if ( + !ts.isPropertyAssignment(property) || + !(ts.isIdentifier(property.name) || ts.isStringLiteral(property.name)) || + property.name.text !== "granularity" || + !ts.isStringLiteral(property.initializer) || + !granularities.includes(property.initializer.text) + ) { + lowerer.noLowering( + "Intl.Segmenter options", + options, + 'the native segmenter supports default options and { granularity: "grapheme" }; word and sentence segmentation remain unsupported', + ); + } + granularity = property.initializer.text; } - granularity = property.initializer.text; } // Explicit undefined expressions can carry effects; retain argument order. const stmts: IrStmt[] = args.map((arg) => { diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 59dda3d08..b62c024f0 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -270,6 +270,7 @@ import { cjsExportAssignmentOf, cjsExportDiscardReason, cjsExportsAssignedInFunctions, + cjsReexportedModules, cjsNamespaceExportNames, fallbackDtsPath, isCheckedJsSourceFile, @@ -4016,9 +4017,20 @@ export class Lowerer { } { let namespace = this.cjsNamespaces.get(dep); if (namespace === undefined) { + // A re-exported name reads the module that assigns it, so the writes + // after evaluation of every re-exported module count too. + let assignedLater: Set | "all" = new Set(); + for (const mod of cjsReexportedModules(this.program, dep)) { + const later = cjsExportsAssignedInFunctions(mod); + if (later === "all") { + assignedLater = "all"; + break; + } + for (const name of later) assignedLater.add(name); + } namespace = { names: cjsNamespaceExportNames(this.program, dep), - assignedLater: cjsExportsAssignedInFunctions(dep), + assignedLater, }; this.cjsNamespaces.set(dep, namespace); } diff --git a/packages/compiler/src/frontend/program.ts b/packages/compiler/src/frontend/program.ts index ce5f3c2bc..755eff830 100644 --- a/packages/compiler/src/frontend/program.ts +++ b/packages/compiler/src/frontend/program.ts @@ -6403,6 +6403,25 @@ function lexWithAccessorNames(sf: ts.SourceFile): ReturnType([dep]); + const order = [dep]; + for (let i = 0; i < order.length; i++) { + const mod = order[i]!; + for (const spec of lexWithAccessorNames(mod).reexports) { + const next = resolveDep(mod, spec); + if (next !== null && !seen.has(next)) { + seen.add(next); + order.push(next); + } + } + } + return order; +} + export function cjsNamespaceExportNames(program: ts.Program, dep: ts.SourceFile): Set { const names = cjsVisibleNames(dep, lexWithAccessorNames, cjsReexportDep7(program), new Map()); return new Set([...names, "default", "module.exports"]); @@ -6504,10 +6523,12 @@ function cjsNamedImportLinkCheck( }; const resolveCjsDep = cjsReexportDep7(program); const visible = (dep: ts.SourceFile, name: string): boolean => - // `default` is the module.exports binding itself — always provided. - // The program already owns native source ASTs; reuse them without - // starting another syntax session or reparsing their source text. + // `default` and `module.exports` are the module.exports binding itself + // — always provided. The program already owns native source ASTs; + // reuse them without starting another syntax session or reparsing + // their source text. name === "default" || + name === "module.exports" || cjsVisibleNames(dep, lexWithAccessorNames, resolveCjsDep, lexMemo).has(name); /** The statement's resolved LOCAL CommonJS dependency, when it is an diff --git a/tests/corpus/8217-intl-segmenter-word-construct/main.ts b/tests/corpus/8217-intl-segmenter-word-construct/main.ts index 5a2a42e08..d0c2247e7 100644 --- a/tests/corpus/8217-intl-segmenter-word-construct/main.ts +++ b/tests/corpus/8217-intl-segmenter-word-construct/main.ts @@ -1,8 +1,10 @@ // A package builds its segmenters at module load (pi-tui, grok-mermaid): -// a grapheme segmenter with a locale tag, and a word segmenter that only -// some paths use. Grapheme segmentation matches Node; the word segmenter -// constructs, and this program never segments with it. -import { columns, describe } from "text-width"; +// a grapheme segmenter with a locale tag, one with empty options, and a +// word segmenter that only some paths use. Grapheme segmentation matches +// Node; the word segmenter constructs, and this program never segments +// with it. +import { columns, describe, plainColumns } from "text-width"; console.log(describe()); console.log(columns("éa👍🏽🇫🇷"), columns("abc")); +console.log(plainColumns("a\u0301b\u{1F44D}\u{1F3FD}")); diff --git a/tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/index.d.ts b/tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/index.d.ts index 471b4fd0a..89b16ddc0 100644 --- a/tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/index.d.ts +++ b/tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/index.d.ts @@ -1,2 +1,3 @@ export declare function columns(text: string): string; export declare function describe(): string; +export declare function plainColumns(text: string): number; diff --git a/tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/index.js b/tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/index.js index d58b4ccbb..c7619bd81 100644 --- a/tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/index.js +++ b/tests/corpus/8217-intl-segmenter-word-construct/node_modules/text-width/index.js @@ -1,11 +1,16 @@ const graphemes = new Intl.Segmenter("en", { granularity: "grapheme" }); const words = new Intl.Segmenter(undefined, { granularity: "word" }); const sentences = new Intl.Segmenter(undefined, { granularity: "sentence" }); +const plain = new Intl.Segmenter(undefined, {}); export function columns(text) { return [...graphemes.segment(text)].map((part) => part.segment).join("|"); } +export function plainColumns(text) { + return [...plain.segment(text)].length; +} + export function describe() { return `${typeof words} ${typeof sentences}`; } diff --git a/tests/coverage-fixtures/cjs-namespace-reexports/impl.cjs b/tests/coverage-fixtures/cjs-namespace-reexports/impl.cjs new file mode 100644 index 000000000..3172d6685 --- /dev/null +++ b/tests/coverage-fixtures/cjs-namespace-reexports/impl.cjs @@ -0,0 +1,6 @@ +"use strict"; +exports.version = 1; +exports.current = null; +exports.set = (value) => { + exports.current = value; +}; diff --git a/tests/coverage-fixtures/cjs-namespace-reexports/main.mjs b/tests/coverage-fixtures/cjs-namespace-reexports/main.mjs new file mode 100644 index 000000000..2ce528d48 --- /dev/null +++ b/tests/coverage-fixtures/cjs-namespace-reexports/main.mjs @@ -0,0 +1,7 @@ +// A namespace import of a CommonJS wrapper that re-exports another module: +// Node's namespace keeps impl.cjs's values from the end of its evaluation, +// so `ns.current` reads null after `ns.set(5)`. +import * as ns from "./wrapper.cjs"; + +ns.set(5); +console.log(ns.current, ns.version); diff --git a/tests/coverage-fixtures/cjs-namespace-reexports/package.json b/tests/coverage-fixtures/cjs-namespace-reexports/package.json new file mode 100644 index 000000000..a3c15a7a6 --- /dev/null +++ b/tests/coverage-fixtures/cjs-namespace-reexports/package.json @@ -0,0 +1 @@ +{ "type": "commonjs" } diff --git a/tests/coverage-fixtures/cjs-namespace-reexports/wrapper.cjs b/tests/coverage-fixtures/cjs-namespace-reexports/wrapper.cjs new file mode 100644 index 000000000..ab637bab5 --- /dev/null +++ b/tests/coverage-fixtures/cjs-namespace-reexports/wrapper.cjs @@ -0,0 +1,2 @@ +"use strict"; +module.exports = require("./impl.cjs"); diff --git a/tests/harness/coverage.test.ts b/tests/harness/coverage.test.ts index 5b541cc54..ffb30b1ce 100644 --- a/tests/harness/coverage.test.ts +++ b/tests/harness/coverage.test.ts @@ -553,6 +553,22 @@ test("CommonJS var and let exports that can change after the export keep their r expect(refused).toEqual(["counter", "tab", "twice"]); }); +test("CommonJS namespace reads of exports a re-exported module assigns later keep their refusal", () => { + // wrapper.cjs re-exports impl.cjs, whose set() assigns `current` after + // evaluation; `version` never changes. + const { coverage } = analyze(fixture("cjs-namespace-reexports/main.mjs")); + const refused = [...coverage.diagnostics, ...(coverage.runtimeFences ?? [])] + .map( + (d) => + /reads of '(\w+)' through namespace imports of CommonJS modules whose functions assign exports/.exec( + d.message, + )?.[1], + ) + .filter((name) => name !== undefined) + .sort(); + expect(refused).toEqual(["current"]); +}); + test("inferred JavaScript compiles natively", async () => { // The js-gap fixture turns noImplicitAny off. Its inferred parameter // uses checked native values alongside the JSDoc-typed neighbor. diff --git a/tests/harness/npm.test.ts b/tests/harness/npm.test.ts index 27b27b8e3..d1bdcf190 100644 --- a/tests/harness/npm.test.ts +++ b/tests/harness/npm.test.ts @@ -38,8 +38,8 @@ const KNOWN: Record = { "assert-shims": { run: "SC1043" }, "buffer-shims": { run: "SC2020" }, "bytes-exit": { build: "SC2004" }, - "cjs-esm-named": { build: "SC2013" }, - "cjs-lexer-aligned": { build: "SC2013" }, + "cjs-esm-named": { run: "SC1090" }, + "cjs-lexer-aligned": { run: "SC1090" }, "commander-calc": { run: "SC1090", argvs: [["--help"]] }, "commander-calc-async": { run: "SC1090", argvs: [["--help"]] }, "create-require": { run: "SC1090" }, From 3d4aeddb82d94f78692c4fe125bee413c0dec9e3 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 17:03:27 -0500 Subject: [PATCH 157/259] Keep the reply scanner in a constant object A native build of a program that installs the C scanner but decodes no reply, such as the self-hosted source parser and CommonJS checks, failed at startup with "Cannot access 'valueEnd' before initialization": the build left the module variable uninitialized because its only other use was the assignment in useNativeJsonValueEnd, which checks it first. The scanner is now a property of a constant object that the decoders and useNativeJsonValueEnd read, so it is initialized in every program. --- .../compiler/src/frontend/ts7/semantic-json.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/packages/compiler/src/frontend/ts7/semantic-json.ts b/packages/compiler/src/frontend/ts7/semantic-json.ts index 1a4d93bd6..8913007d3 100644 --- a/packages/compiler/src/frontend/ts7/semantic-json.ts +++ b/packages/compiler/src/frontend/ts7/semantic-json.ts @@ -104,15 +104,20 @@ export function jsonValueEnd(bytes: Uint8Array, start: number): number { } /** The scanner the decoders find value ends with: jsonValueEnd, or the - * native compiler's scanner (useNativeJsonValueEnd). */ -let valueEnd: (bytes: Uint8Array, start: number) => number = jsonValueEnd; + * native compiler's scanner (useNativeJsonValueEnd). It is a property of a + * constant object: a program that installs the scanner but decodes no + * reply must still initialize it, and an assigned module variable with no + * other reader would be left uninitialized by a native build. */ +const scanner: { valueEnd: (bytes: Uint8Array, start: number) => number } = { + valueEnd: jsonValueEnd, +}; /** Has the decoders find value ends with `scan`, which returns what * jsonValueEnd returns, or -1 where jsonValueEnd throws. The native compiler * installs its C scanner (native/ts7-process.c), which skips the strings that * make up most reply bytes with memchr. */ export function useNativeJsonValueEnd(scan: (bytes: Uint8Array, start: number) => number): void { - valueEnd = (bytes, start) => { + scanner.valueEnd = (bytes, start) => { const end = scan(bytes, start); if (end < 0) malformedReply(); return end; @@ -174,7 +179,7 @@ export function decodeSemanticObject( ): R | null { const start = skipJsonSpace(bytes, 0); if (start === bytes.length) return null; - const end = valueEnd(bytes, start); + const end = scanner.valueEnd(bytes, start); if (skipJsonSpace(bytes, end) !== bytes.length) malformedReply(); return replyElement(bytes, start, end, cached, build); } @@ -190,7 +195,7 @@ export function decodeSemanticObjects( let index = skipJsonSpace(bytes, 0); if (index === bytes.length) return null; if (bytes[index] !== OPEN_BRACKET) { - const end = valueEnd(bytes, index); + const end = scanner.valueEnd(bytes, index); if ( skipJsonSpace(bytes, end) !== bytes.length || parseJsonSlice(bytes, index, end) !== null @@ -205,7 +210,7 @@ export function decodeSemanticObjects( return result; } for (;;) { - const end = valueEnd(bytes, index); + const end = scanner.valueEnd(bytes, index); if (end === index) malformedReply(); result.push(replyElement(bytes, index, end, cached, build)); index = skipJsonSpace(bytes, end); From 9406ba5b892b16b1675ba55fbfbcd5c1a762e514 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 17:04:14 -0500 Subject: [PATCH 158/259] Run row sums two rows per pass A loop nest that sums one term per row, for (let i = start; i < end; i++) { let t = 0; for (let j = from; j < to; j++) t += term; out[i] = t; } where the term only reads numbers, the counters and typed-array elements, now runs two rows per pass when both row bounds are int32, the start is at most the end, and the stored array shares no byte with any array the term reads. Each row keeps its order of additions, so each sum has the bits of the loop as written; an odd row count runs its last row as written, and any other case runs the nest as written. Element reads that do not depend on the row are read once per column for both rows. With two independent sums in the inner loop, neither waits on the other's addition, and LLVM computes both rows' terms in one vector. bytes.disjoint compares two typed arrays' element ranges in memory. --- packages/compiler/src/backend/llvm/emitter.ts | 19 +- .../compiler/src/backend/llvm/lib-dispatch.ts | 34 +- .../compiler/src/ir/builtin-signatures.ts | 3 + packages/compiler/src/ir/row-pairs.test.ts | 147 ++++++ packages/compiler/src/ir/row-pairs.ts | 438 ++++++++++++++++++ .../tests/corpus/8194-row-pair-sums.ts.json | 6 + tests/corpus/8194-row-pair-sums.ts | 72 +++ 7 files changed, 710 insertions(+), 9 deletions(-) create mode 100644 packages/compiler/src/ir/row-pairs.test.ts create mode 100644 packages/compiler/src/ir/row-pairs.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8194-row-pair-sums.ts.json create mode 100644 tests/corpus/8194-row-pair-sums.ts diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index f6f9ea313..0009d5229 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -81,6 +81,7 @@ import { import { specializeNumericCalls } from "../../ir/numeric-call-specialization.js"; import { versionLoopBoundParameters } from "../../ir/parameter-versions.js"; import { inlineExpressionFunctions } from "../../ir/expression-inlining.js"; +import { pairRowSums } from "../../ir/row-pairs.js"; import { allocatedLiteral, fillAllocationLength, @@ -565,14 +566,16 @@ function moduleEmitter(input: IrModule, options: LlvmTargetOptions): LlEmitter { scalarizeNumericRecords( specializeCallbackCalls( specializeNumericCalls( - inlineExpressionFunctions( - foldConstantGlobals( - copyStableCaptures( - resolveSelfCaptures( - hoistFinalFieldReads( - freezeInitOnlyGlobals( - holdCharLocalsAsUnits( - dropUnwrittenPropertyBags(runPairedWhileLoopsAsFor(mod)), + pairRowSums( + inlineExpressionFunctions( + foldConstantGlobals( + copyStableCaptures( + resolveSelfCaptures( + hoistFinalFieldReads( + freezeInitOnlyGlobals( + holdCharLocalsAsUnits( + dropUnwrittenPropertyBags(runPairedWhileLoopsAsFor(mod)), + ), ), ), ), diff --git a/packages/compiler/src/backend/llvm/lib-dispatch.ts b/packages/compiler/src/backend/llvm/lib-dispatch.ts index d8ca5add8..f4ce9e405 100644 --- a/packages/compiler/src/backend/llvm/lib-dispatch.ts +++ b/packages/compiler/src/backend/llvm/lib-dispatch.ts @@ -10,7 +10,7 @@ import { FN_ATTRS, arrNewCall, traceArg, vAdapters } from "./shapes.js"; import { InternalCompilerError } from "../../errors.js"; import { MAY_THROW_LIB_FNS } from "../../ir/builtin-effects.js"; -import { F64, type IrExpr, type IrType } from "../../ir/ir.js"; +import { BYTES_ELEMENT_SIZE, F64, type IrExpr, type IrType } from "../../ir/ir.js"; import { LlvmUnsupportedError } from "./unsupported.js"; import { emitJsLibCall } from "./jsval.js"; import type { LlvmEmitterContext, LibCallExpr, LibCallPrefix, LlValue } from "./expr-context.js"; @@ -936,6 +936,38 @@ export function emitLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlValue { return { name: t, type: e.type }; } if (e.fn === "bytes.absent") return host.own({ name: "null", type: e.type }); + if (e.fn === "bytes.disjoint") { + // [data, data + len * size) of each view, compared as addresses. + const B = host.B; + const range = (arg: IrExpr): { start: string; end: string } => { + const value = host.emitReadReceiver(arg); + const size = arg.type.kind === "bytes" ? BYTES_ELEMENT_SIZE[arg.type.elem] : 1; + const dataSlot = B.tmp(), + data = B.tmp(), + lenSlot = B.tmp(), + len = B.tmp(), + bytes = B.tmp(), + start = B.tmp(), + end = B.tmp(); + B.line(`${dataSlot} = getelementptr inbounds %ScrBytes, ptr ${value.name}, i64 0, i32 3`); + B.line(`${data} = load ptr, ptr ${dataSlot}`); + B.line(`${lenSlot} = getelementptr inbounds %ScrBytes, ptr ${value.name}, i64 0, i32 1`); + B.line(`${len} = load ${host.sizeType}, ptr ${lenSlot}`); + B.line(`${bytes} = mul ${host.sizeType} ${len}, ${size}`); + B.line(`${start} = ptrtoint ptr ${data} to ${host.sizeType}`); + B.line(`${end} = add ${host.sizeType} ${start}, ${bytes}`); + return { start, end }; + }; + const left = range(e.args[0]!), + right = range(e.args[1]!); + const before = B.tmp(), + after = B.tmp(), + t = B.tmp(); + B.line(`${before} = icmp ule ${host.sizeType} ${left.end}, ${right.start}`); + B.line(`${after} = icmp ule ${host.sizeType} ${right.end}, ${left.start}`); + B.line(`${t} = or i1 ${before}, ${after}`); + return { name: t, type: e.type }; + } if (e.fn === "record.isFrozen") { // The frozen bit of the record's rc word (scr_rc.h SCR_RC_FROZEN) is // its second-highest bit; an immortal word sets the highest one too. diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index 1109f7f95..ef75b1b6d 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -4930,6 +4930,9 @@ export const LIB_FN_SIGS = defineLibFnSignatures({ * and crypto callback adapters pass NULL after an error. Borrowed arg; * never throws. */ "bytes.isAbsent": { argTypes: [BYTES_U8], result: BOOL }, + /** Whether two typed arrays share no byte: their element ranges in + * memory do not overlap. Borrowed args of any element kind; never throws. */ + "bytes.disjoint": { argTypes: [null, null], result: BOOL }, /** The absent Buffer result itself (NULL), where an error-path callback * body passes its undefined result on into a Buffer slot. Owned (+1); * never throws. */ diff --git a/packages/compiler/src/ir/row-pairs.test.ts b/packages/compiler/src/ir/row-pairs.test.ts new file mode 100644 index 000000000..f9db5b89d --- /dev/null +++ b/packages/compiler/src/ir/row-pairs.test.ts @@ -0,0 +1,147 @@ +import { expect, test } from "vitest"; +import { BOOL, F64, VOID, type IrExpr, type IrFunction, type IrModule, type IrStmt } from "./ir.js"; +import { pairRowSums } from "./row-pairs.js"; + +const loc = { file: "row-pairs.ts", start: 0, end: 0 }; +const BYTES = { kind: "bytes", elem: "f64" } as const; +const num = (value: number): IrExpr => ({ loc, kind: "numLit", value, type: F64 }); +const ref = (localId: string): IrExpr => ({ loc, kind: "varRef", localId, type: F64 }); +const bytes = (localId: string): IrExpr & { kind: "varRef" } => ({ + loc, + kind: "varRef", + localId, + type: BYTES, +}); +const bin = (op: "+" | "/" | "<", left: IrExpr, right: IrExpr): IrExpr => ({ + loc, + kind: "bin", + op, + left, + right, + type: op === "<" ? BOOL : F64, +}); +const step = (id: string): IrStmt => ({ + loc, + kind: "assign", + localId: id, + value: bin("+", ref(id), num(1)), +}); +const counted = ( + id: string, + start: IrExpr, + end: IrExpr, + body: IrStmt[], +): IrStmt & { kind: "for" } => ({ + loc, + kind: "for", + init: { loc, kind: "varDecl", localId: id, init: start }, + cond: bin("<", ref(id), end), + update: step(id), + body, +}); +const get = (array: string, index: IrExpr): IrExpr => ({ + loc, + kind: "bytesIntrinsic", + method: "get", + receiver: bytes(array), + args: [index], + type: F64, + invalidNaN: true, +}); + +/** for (i = start; i < end; i++) { t = 0; for (j = 0; j < n; j++) t += u[j] / (i + j + 1); v[i] = t } */ +function rowSum( + term: IrExpr = bin("/", get("u", ref("j")), bin("+", bin("+", ref("i"), ref("j")), num(1))), +) { + return counted("i", ref("start"), ref("end"), [ + { loc, kind: "varDecl", localId: "t", init: num(0) }, + counted("j", num(0), ref("n"), [ + { loc, kind: "assign", localId: "t", value: bin("+", ref("t"), term) }, + ]), + { loc, kind: "bytesSet", arr: bytes("v"), index: ref("i"), value: ref("t") }, + ]); +} + +const local = (id: string, type: IrExpr["type"] = F64) => ({ id, name: id, type, mutable: true }); +function mod(body: IrStmt[]): IrModule { + const fn: IrFunction = { + loc, + name: "rows", + params: [], + locals: [ + ...["i", "j", "t", "start", "end", "n"].map((id) => local(id)), + local("u", BYTES), + local("v", BYTES), + ], + returnType: VOID, + body, + }; + return { irVersion: 17, sourceFile: "row-pairs.ts", entry: "rows", functions: [fn] }; +} + +test("a row-sum nest runs two rows per pass behind its bounds and overlap test", () => { + const result = pairRowSums(mod([rowSum()])); + const top = result.functions[0]!.body[0] as IrStmt & { kind: "block" }; + expect(top.kind).toBe("block"); + const [go, from, branch, rest] = top.body as [ + IrStmt & { kind: "varDecl" }, + IrStmt & { kind: "varDecl" }, + IrStmt & { kind: "if" }, + IrStmt & { kind: "for" }, + ]; + // The test: int32 bounds, start <= end, and the stored array disjoint + // from the array the term reads. + expect(JSON.stringify(go.init)).toContain('"fn":"bytes.disjoint"'); + expect(branch.else_).toBeNull(); + const pairs = branch.then[0] as IrStmt & { kind: "for" }; + expect(pairs.body.filter((s) => s.kind === "bytesSet")).toHaveLength(2); + const inner = pairs.body[2] as IrStmt & { kind: "for" }; + // One read of u[j] for both rows, then the two sums. + expect(inner.body).toHaveLength(3); + expect(inner.body[0]).toMatchObject({ kind: "varDecl", init: { kind: "bytesIntrinsic" } }); + // The second row's term reads `row + 1`. + const row = pairs.init?.kind === "varDecl" ? pairs.init.localId : ""; + expect((inner.body[2] as IrStmt & { kind: "assign" }).value).toMatchObject({ + op: "+", + right: { + op: "/", + left: { kind: "varRef" }, + right: { + op: "+", + left: { + op: "+", + left: { op: "+", left: { kind: "varRef", localId: row }, right: { value: 1 } }, + }, + }, + }, + }); + // The loop as written runs from `end - ((end - start) & 1)` after the + // pairs, or from the start when the test failed: the nest's one other copy. + expect(from.init).toMatchObject({ + kind: "ternary", + then: { op: "-" }, + else_: { localId: "start" }, + }); + expect(rest.init).toMatchObject({ + kind: "varDecl", + localId: "i", + init: { localId: from.localId }, + }); + expect(top.body).toHaveLength(4); + expect( + result.functions[0]!.locals.map((l) => l.id).filter((id) => id.startsWith("%pair.")), + ).toHaveLength(7); +}); + +test("nests whose term calls, writes or reads the sum keep their loops", () => { + const calls: IrExpr = { loc, kind: "call", callee: "f", args: [ref("j")], type: F64 }; + const readsSum = bin("+", ref("t"), get("u", ref("j"))); + for (const term of [calls, readsSum]) { + const m = mod([rowSum(term)]); + expect(pairRowSums(m)).toBe(m); + } + const stored = rowSum(); + stored.body[2] = { loc, kind: "bytesSet", arr: bytes("v"), index: ref("j"), value: ref("t") }; + const m = mod([stored]); + expect(pairRowSums(m)).toBe(m); +}); diff --git a/packages/compiler/src/ir/row-pairs.ts b/packages/compiler/src/ir/row-pairs.ts new file mode 100644 index 000000000..ed71166a8 --- /dev/null +++ b/packages/compiler/src/ir/row-pairs.ts @@ -0,0 +1,438 @@ +import { + BOOL, + F64, + type IrExpr, + type IrFunction, + type IrLocal, + type IrModule, + type IrStmt, +} from "./ir.js"; +import { everyExpr, everyExprChild, mapExprChildren, transformStmtList } from "./traverse.js"; + +/** Inner-loop expressions above this many nodes keep the loop as written. */ +const MAX_TERM_NODES = 64; + +/** The number operators a term may use: they run no other code and cannot + * throw. */ +const PURE_BINARY = new Set([ + "+", + "-", + "*", + "/", + "%", + "**", + "&", + "|", + "^", + "<<", + ">>", + ">>>", +]); + +/** A loop nest that sums one term per row: + * + * for (let i = start; i < end; i++) { + * let t = ; + * for (let j = from; j < to; j++) t = t + ; + * out[i] = t; + * } + */ +interface RowSum { + row: string; + start: IrExpr; + end: IrExpr; + sum: string; + init: IrExpr & { kind: "numLit" }; + inner: IrStmt & { kind: "for" }; + column: string; + term: IrExpr; + out: IrExpr & { kind: "varRef" }; + /** The typed arrays the term reads. */ + reads: (IrExpr & { kind: "varRef" })[]; +} + +function isRef(e: IrExpr | null | undefined, id: string): boolean { + return e?.kind === "varRef" && e.localId === id; +} + +/** `id = id + 1`, or `id++` as a statement. */ +function unitStep(update: IrStmt | null, id: string): boolean { + if (update?.kind === "exprStmt") + return update.expr.kind === "incDec" && update.expr.localId === id && update.expr.op === "+"; + return ( + update?.kind === "assign" && + update.localId === id && + update.value.kind === "bin" && + update.value.op === "+" && + isRef(update.value.left, id) && + update.value.right.kind === "numLit" && + update.value.right.value === 1 + ); +} + +/** A plain number local: unboxed and outside the temporal dead zone. */ +function plainNumber(locals: ReadonlyMap, id: string): boolean { + const local = locals.get(id); + return local !== undefined && local.type.kind === "f64" && !local.boxed && !local.tdz; +} + +function readsLocal(e: IrExpr, id: string): boolean { + return !everyExpr(e, { stmt: () => true, expr: (x) => !isRef(x, id) }); +} + +/** The row-sum shape of a `for` statement, or null. Bounds and receivers + * must be literals or locals the nest never writes. */ +function matchRowSum( + s: IrStmt & { kind: "for" }, + locals: ReadonlyMap, +): RowSum | null { + if (s.labels?.length || s.init?.kind !== "varDecl" || !s.init.init) return null; + const row = s.init.localId; + if (!plainNumber(locals, row) || !unitStep(s.update, row)) return null; + const cond = s.cond; + if (cond?.kind !== "bin" || cond.op !== "<" || !isRef(cond.left, row)) return null; + const start = s.init.init, + end = cond.right; + if (s.body.length !== 3) return null; + const [decl, inner, store] = s.body as [IrStmt, IrStmt, IrStmt]; + if (decl.kind !== "varDecl" || decl.init?.kind !== "numLit") return null; + const sum = decl.localId; + if (!plainNumber(locals, sum)) return null; + if (inner.kind !== "for" || inner.labels?.length) return null; + if (inner.init?.kind !== "varDecl" || !inner.init.init) return null; + const column = inner.init.localId; + if (!plainNumber(locals, column) || !unitStep(inner.update, column)) return null; + const innerCond = inner.cond; + if (innerCond?.kind !== "bin" || innerCond.op !== "<" || !isRef(innerCond.left, column)) + return null; + if (inner.body.length !== 1) return null; + const add = inner.body[0]!; + if ( + add.kind !== "assign" || + add.localId !== sum || + add.value.kind !== "bin" || + add.value.op !== "+" || + !isRef(add.value.left, sum) + ) + return null; + const term = add.value.right; + if ( + store.kind !== "bytesSet" || + store.arr.kind !== "varRef" || + store.arr.type.kind !== "bytes" || + !isRef(store.index, row) || + !isRef(store.value, sum) + ) + return null; + const out = store.arr; + // Values the nest reads but never writes: the row counter, the column + // counter and the sum are its only writes. + const written = new Set([row, sum, column]); + // A typed array's length is fixed, so a stable receiver's length is + // stable too. + const stable = (e: IrExpr): boolean => + e.kind === "numLit" || + (e.kind === "varRef" && + !written.has(e.localId) && + locals.get(e.localId) !== undefined && + !locals.get(e.localId)!.boxed && + !locals.get(e.localId)!.tdz) || + (e.kind === "bytesIntrinsic" && + e.method === "length" && + e.args.length === 0 && + e.receiver.kind === "varRef" && + e.receiver.type.kind === "bytes" && + stable(e.receiver)); + if (!stable(start) || !stable(end) || !stable(out)) return null; + if (!stable(inner.init.init) || !stable(innerCond.right)) return null; + const reads: (IrExpr & { kind: "varRef" })[] = []; + let nodes = 0; + const pure = (e: IrExpr): boolean => { + if (++nodes > MAX_TERM_NODES) return false; + switch (e.kind) { + case "numLit": + return e.type.kind === "f64"; + case "varRef": + return e.type.kind === "f64" && (e.localId === row || e.localId === column || stable(e)); + case "bin": + return e.type.kind === "f64" && PURE_BINARY.has(e.op) && pure(e.left) && pure(e.right); + case "unary": + return e.type.kind === "f64" && (e.op === "-" || e.op === "~") && pure(e.operand); + case "bytesIntrinsic": + if (stable(e)) return true; + if ( + e.method !== "get" || + e.args.length !== 1 || + e.receiver.kind !== "varRef" || + e.receiver.type.kind !== "bytes" || + !stable(e.receiver) + ) + return false; + reads.push(e.receiver); + return pure(e.args[0]!); + default: + return false; + } + }; + if (!pure(term) || readsLocal(term, sum)) return null; + return { row, start, end, sum, init: decl.init, inner, column, term, out, reads }; +} + +/** A fresh copy of `e` with `substitute` applied to its local reads and + * `replace` to the nodes it answers for. */ +function copy( + e: IrExpr, + substitute: (ref: IrExpr & { kind: "varRef" }) => IrExpr, + replace: (node: IrExpr) => IrExpr | null = () => null, +): IrExpr { + const replaced = replace(e); + if (replaced !== null) return replaced; + if (e.kind === "varRef") return substitute(e); + return mapExprChildren( + { ...e }, + (child) => copy(child, substitute, replace), + (stmt) => stmt, + ); +} + +const bin = ( + op: "+" | "-" | "&" | "|", + left: IrExpr, + right: IrExpr, + loc: IrExpr["loc"], +): IrExpr => ({ + kind: "bin", + op, + left, + right, + type: F64, + loc, +}); + +/** Runs the row sums of `match` two rows per pass when the test holds and + * as written otherwise. */ +function pairRows( + s: IrStmt & { kind: "for" }, + match: RowSum, + fresh: (name: string) => string, + done: Set, +): IrStmt { + const loc = s.loc; + const ref = (id: string): IrExpr => ({ kind: "varRef", localId: id, type: F64, loc }); + const num = (value: number): IrExpr => ({ kind: "numLit", value, type: F64, loc }); + const again = (e: IrExpr): IrExpr => copy(e, (r) => ({ ...r })); + const row = fresh("row"), + sum = fresh("sum"), + next = fresh("next"), + column = fresh("column"); + const atColumn = (r: IrExpr & { kind: "varRef" }): IrExpr => + r.localId === match.column ? { ...r, localId: column } : { ...r }; + // Element reads that do not depend on the row are read once per column + // and shared by both rows. + const shared = new Map(); + const elements: IrStmt[] = []; + const collect = (e: IrExpr): boolean => { + if (e.kind === "bytesIntrinsic" && e.method === "get" && !readsLocal(e, match.row)) { + const id = fresh("element"); + shared.set(e, id); + elements.push({ kind: "varDecl", localId: id, init: copy(e, atColumn), loc }); + return true; + } + return everyExprChild(e, collect, () => true); + }; + collect(match.term); + // The second row's term reads `row + 1`, so its counter sums stay visible + // to the counted-loop analysis. + const termAt = (rowExpr: () => IrExpr): IrExpr => + copy( + match.term, + (r) => (r.localId === match.row ? rowExpr() : atColumn(r)), + (node) => { + const id = shared.get(node); + return id === undefined ? null : { kind: "varRef", localId: id, type: node.type, loc }; + }, + ); + const innerCond = match.inner.cond as IrExpr & { kind: "bin" }; + const pairs: IrStmt = { + kind: "for", + init: { kind: "varDecl", localId: row, init: again(match.start), loc }, + cond: { + kind: "bin", + op: "<", + left: ref(row), + right: bin("-", again(match.end), num(1), loc), + type: BOOL, + loc, + }, + update: { kind: "assign", localId: row, value: bin("+", ref(row), num(2), loc), loc }, + body: [ + { kind: "varDecl", localId: sum, init: { ...match.init }, loc }, + { kind: "varDecl", localId: next, init: { ...match.init }, loc }, + { + kind: "for", + init: { + kind: "varDecl", + localId: column, + init: again((match.inner.init as IrStmt & { kind: "varDecl" }).init!), + loc, + }, + cond: { ...innerCond, left: ref(column), right: again(innerCond.right) }, + update: { kind: "assign", localId: column, value: bin("+", ref(column), num(1), loc), loc }, + body: [ + ...elements, + { + kind: "assign", + localId: sum, + value: bin( + "+", + ref(sum), + termAt(() => ref(row)), + loc, + ), + loc, + }, + { + kind: "assign", + localId: next, + value: bin( + "+", + ref(next), + termAt(() => bin("+", ref(row), num(1), loc)), + loc, + ), + loc, + }, + ], + loc, + }, + { kind: "bytesSet", arr: { ...match.out }, index: ref(row), value: ref(sum), loc }, + { + kind: "bytesSet", + arr: { ...match.out }, + index: bin("+", ref(row), num(1), loc), + value: ref(next), + loc, + }, + ], + loc, + }; + // Both bounds are int32, so `row < end - 1` is `row + 1 < end`, and the + // start is at most the end. Rows are independent when the written array + // shares no byte with an array the term reads. + const int32 = (e: IrExpr): IrExpr => ({ + kind: "bin", + op: "===", + left: bin("|", again(e), num(0), loc), + right: again(e), + type: BOOL, + loc, + }); + const tests: IrExpr[] = [ + int32(match.start), + int32(match.end), + { kind: "bin", op: "<=", left: again(match.start), right: again(match.end), type: BOOL, loc }, + ...match.reads.map((read): IrExpr => ({ + kind: "libCall", + fn: "bytes.disjoint", + args: [{ ...match.out }, { ...read }], + type: BOOL, + loc, + })), + ]; + const test = tests.reduce((left, right) => ({ + kind: "logical", + op: "&&", + left, + right, + type: BOOL, + loc, + })); + // The loop as written then runs the rows the pairs left: the last one when + // the count is odd (from `end - ((end - start) & 1)`), or all of them when + // the test failed. It is the nest's only other copy. + const go = fresh("go"), + from = fresh("from"); + const paired: IrExpr = { kind: "bin", op: "===", left: ref(go), right: num(1), type: BOOL, loc }; + const rest: IrStmt = { + ...s, + init: { kind: "varDecl", localId: match.row, init: ref(from), loc }, + }; + done.add(rest); + return { + kind: "block", + body: [ + { + kind: "varDecl", + localId: go, + init: { kind: "ternary", cond: test, then: num(1), else_: num(0), type: F64, loc }, + loc, + }, + { + kind: "varDecl", + localId: from, + init: { + kind: "ternary", + cond: paired, + then: bin( + "-", + again(match.end), + bin("&", bin("-", again(match.end), again(match.start), loc), num(1), loc), + loc, + ), + else_: again(match.start), + type: F64, + loc, + }, + loc, + }, + { kind: "if", cond: { ...paired }, then: [pairs], else_: null, loc }, + rest, + ], + loc, + }; +} + +/** Runs loop nests that sum one term per row (spectral-norm's `au`) two rows + * per pass. + * + * Each row's sum keeps its order of additions, so every sum has the bits + * the nest computes as written: the second row's term is the same + * expression of `row + 1`. The term only reads numbers, the counters and + * typed-array elements, so it runs no other code and cannot throw. The + * nest runs paired when both row bounds are int32 (so `row < end - 1` is + * `row + 1 < end`), the start is at most the end, and the array the rows + * store into shares no byte with any array the term reads, so no row reads + * another row's result. An odd row count runs its last row as written. + * Otherwise the nest runs as written. Two independent sums take turns in + * the inner loop, so neither waits on the other's addition. */ +export function pairRowSums(mod: IrModule): IrModule { + let changed = false; + const functions = mod.functions.map((fn): IrFunction => { + if (fn.async || fn.generator) return fn; + const locals = new Map(fn.locals.map((local) => [local.id, local])); + const added: IrLocal[] = []; + const ids = new Set(fn.locals.map((local) => local.id)); + const fresh = (name: string): string => { + let id = `%pair.${name}.${ids.size}`; + while (ids.has(id)) id += "_"; + ids.add(id); + added.push({ id, name: `%pair.${name}`, type: F64, mutable: true }); + return id; + }; + const paired = new Set(); + const body = transformStmtList(fn.body, { + expr: (e) => e, + stmt: (s) => { + if (s.kind !== "for" || paired.has(s)) return s; + const match = matchRowSum(s, locals); + if (match === null) return s; + paired.add(s); + return pairRows(s, match, fresh, paired); + }, + }); + if (added.length === 0) return fn; + changed = true; + return { ...fn, locals: [...fn.locals, ...added], body }; + }); + return changed ? { ...mod, functions } : mod; +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8194-row-pair-sums.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8194-row-pair-sums.ts.json new file mode 100644 index 000000000..afb53a915 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8194-row-pair-sums.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8194-row-pair-sums.ts" + ], + "diags": [] +} diff --git a/tests/corpus/8194-row-pair-sums.ts b/tests/corpus/8194-row-pair-sums.ts new file mode 100644 index 000000000..9aa22b9bd --- /dev/null +++ b/tests/corpus/8194-row-pair-sums.ts @@ -0,0 +1,72 @@ +// Row sums (`for i { t = 0; for j t += term; out[i] = t }`) over typed +// arrays, run with even and odd row counts, an empty range, fractional, +// negative-zero and out-of-int32 bounds, and output arrays that are the +// input array or overlap it in one buffer, so a row may read an earlier +// row's result. +function rows(u: Float64Array, v: Float64Array, start: number, end: number, n: number): void { + for (let i = start; i < end; i++) { + let t = 0; + for (let j = 0; j < n; j++) t += u[j]! / ((((i + j) * (i + j + 1)) >>> 1) + i + 1); + v[i] = t; + } +} + +function weighted(u: Float32Array, w: Int32Array, v: Float64Array, start: number, end: number): void { + for (let i = start; i < end; i++) { + let t = 0.5; + for (let j = 0; j < u.length; j++) t += u[j]! * w[(i + j) % w.length]! - i * 0.25; + v[i] = t; + } +} + +const show = (label: string, v: Float64Array): void => { + const parts: string[] = []; + for (const x of v) parts.push(Object.is(x, -0) ? "-0" : x.toPrecision(17)); + console.log(label, parts.join(" ")); +}; + +const n = Number(process.argv[2] ?? 7); +const u = new Float64Array(n).map((_, k) => k + 1); +for (const [start, end] of [ + [0, n], + [0, n - 1], + [1, n], + [2, 2], + [3, 1], + [-0, 3], + [0.5, 4], + [0, 4.5], + [2 ** 31 - 3, 2 ** 31 + 1], + [NaN, 3], +]) { + const v = new Float64Array(n + 2); + rows(u, v, start!, end!, n); + show(`rows ${start} ${end}`, v); +} + +// The output is the input: each row reads the rows stored before it. +const same = new Float64Array(n).map((_, k) => k + 1); +rows(same, same, 0, n, n); +show("same", same); + +// Overlapping views of one buffer, offset by one element. +const buffer = new ArrayBuffer(8 * (n + 1)); +const lo = new Float64Array(buffer, 0, n).map((_, k) => k + 1); +const hi = new Float64Array(buffer, 8, n); +rows(lo, hi, 0, n, n); +show("overlap", new Float64Array(buffer)); + +// Disjoint views of one buffer. +const shared = new ArrayBuffer(16 * n); +const a = new Float64Array(shared, 0, n).map((_, k) => n - k); +const b = new Float64Array(shared, 8 * n, n); +rows(a, b, 0, n, n); +show("disjoint", b); + +const f = new Float32Array(n).map((_, k) => k / 3); +const w = new Int32Array([3, -1, 4, 1, -5]); +const out = new Float64Array(n); +weighted(f, w, out, 0, n); +show("weighted", out); +weighted(f, w, out, 1, n - 1); +show("weighted inner", out); From 01e6d55fc56e00e9ba91b55f29e021029d3289f3 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 17:05:18 -0500 Subject: [PATCH 159/259] Keep optional-element arrays through nested conversions, union arms, rest packing and receiver reassignment - Checked conversions from dynamic values key their builders and matchers by the type with `?` after every `(T | undefined)[]`, at any depth. `number[][]` and `(number | undefined)[][]` share a typeKey, so the second conversion reused the first one's builder and rejected undefined elements. - The dynamic matcher of a `(T | undefined)[]` takes undefined elements, so a union with such an arm matches arrays that hold undefined. - An optional-element rest parameter packs tuple-spread values and plain arguments together as present undefined elements, each evaluated once in argument order, instead of converting each value to T. - The element-state scan counts an argument in a rest position that may be undefined, and a spread tuple with undefined elements, as undefined elements of the rest array, so reads in the callee check element states. - A union index read keeps the receiver in a temporary when the key can assign it, so `a[(a = other, 0)]` reads the array `a` held before the key. --- packages/compiler/src/backend/llvm/dyn.ts | 34 +++++++++++-- .../src/frontend/lowering/call-arguments.ts | 26 +++++++++- .../lowering/expressions/element-access.ts | 15 ++++-- .../compiler/src/frontend/lowering/lowerer.ts | 24 ++++++++- .../lowering/runtime-optional-elements.ts | 19 ++++++- .../8004-optional-element-conversions.ts.json | 6 +++ .../8004-optional-element-conversions.ts | 49 +++++++++++++++++++ .../8004-optional-element-conversions.ts.json | 1 + 8 files changed, 162 insertions(+), 12 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8004-optional-element-conversions.ts.json create mode 100644 tests/corpus/8004-optional-element-conversions.ts create mode 100644 tests/harness/corpus-costs/8004-optional-element-conversions.ts.json diff --git a/packages/compiler/src/backend/llvm/dyn.ts b/packages/compiler/src/backend/llvm/dyn.ts index 57c8b5177..4ec710b28 100644 --- a/packages/compiler/src/backend/llvm/dyn.ts +++ b/packages/compiler/src/backend/llvm/dyn.ts @@ -66,6 +66,25 @@ import { recordMayKeepSource, recordSourceFieldOrder } from "./record-sources.js import type { WalkerHost } from "./walkers.js"; import type { LlStreamTypedRefAdapter } from "./expr-context.js"; +/** typeKey with `?` after every `(T | undefined)[]` (optionalElements), + * at any depth of arrays, Maps, Sets and promises: checked conversions to + * `number[][]` and `(number | undefined)[][]` need separate helpers, though + * the two types share a typeKey. */ +function checkedConversionKey(t: IrType): string { + switch (t.kind) { + case "array": + return `array<${checkedConversionKey(t.elem)}>${t.optionalElements ? "?" : ""}`; + case "map": + return `map<${checkedConversionKey(t.key)},${checkedConversionKey(t.value)}>`; + case "set": + return `set<${checkedConversionKey(t.elem)}>`; + case "promise": + return `promise<${checkedConversionKey(t.inner)}>`; + default: + return typeKey(t); + } +} + /** Whether to-dyn of a record shape keeps the record itself: an empty shape * and an event-listener record (a `handleEvent` function field) box their * identity. Every other shape, tuples included, copies its fields into a @@ -1060,7 +1079,7 @@ export class LlDyn { /** `sc_dm_(ptr d) -> i1` — does this dyn fit T? Never throws. */ dynMatchHelper(t: IrType, preserveRefs = false): string { - const key = typeKey(t); + const key = checkedConversionKey(t); const matcherKey = preserveRefs ? `identity:${key}` : key; const existing = this.dynMatchers.get(matcherKey); if (existing) return existing; @@ -1375,7 +1394,7 @@ export class LlDyn { B.startBlock(l0); const n = this.lenOf(B, "%d"); const items = this.itemsOf(B, "%d"); - this.i64Loop(B, "dm.el", n, (i, brNext) => { + this.i64Loop(B, "dm.el", n, (i, brNext, next) => { this.host.declare(`declare zeroext i1 @scr_dyn_arr_has_index(ptr, ${this.S})`); const present = B.tmp(); B.line(`${present} = call zeroext i1 @scr_dyn_arr_has_index(ptr %d, ${this.S} ${i})`); @@ -1386,6 +1405,15 @@ export class LlDyn { brNext(); B.startBlock(valueLabel); const e = this.itemAt(B, items, i); + if (t.optionalElements) { + // A `(T | undefined)[]` stored as T elements takes undefined + // elements as well. + const undef = B.tmp(); + const checkLabel = B.newLabel("dm.check"); + B.line(`${undef} = icmp eq i32 ${this.kindOf(B, e)}, ${DYN_KIND.UNDEF}`); + B.condBr(undef, next, checkLabel); + B.startBlock(checkLabel); + } const ok = B.tmp(); B.line(`${ok} = call zeroext i1 @${m}(ptr ${e})`); const lOk = B.newLabel("dm.eo"); @@ -1798,7 +1826,7 @@ export class LlDyn { * TypeError and return a dummy with the pending flag set. */ dynCheckHelper(t: IrType, preserveRefs = false): string { // A `(T | undefined)[]` stored as T elements also takes undefined ones. - const key = t.kind === "array" && t.optionalElements ? `${typeKey(t)}?` : typeKey(t); + const key = checkedConversionKey(t); const builderKey = preserveRefs ? `identity:${key}` : key; const existing = this.dynBuilders.get(builderKey); if (existing) return existing; diff --git a/packages/compiler/src/frontend/lowering/call-arguments.ts b/packages/compiler/src/frontend/lowering/call-arguments.ts index 6da0cb337..b02d0b85c 100644 --- a/packages/compiler/src/frontend/lowering/call-arguments.ts +++ b/packages/compiler/src/frontend/lowering/call-arguments.ts @@ -28,7 +28,7 @@ import { checkedIterableSpread } from "./checked-iterable-spread.js"; import { type ParamShape } from "./call-signatures.js"; import { arrayValueRead, arrayValueType } from "./array-values.js"; import { buildArrayConversion } from "./coercions/builders.js"; -import { lowerArraySpreadItems } from "./containers/array-construction.js"; +import { lowerArraySpreadItems, lowerArrayValueItems } from "./containers/array-construction.js"; import { restTupleElementTypes, typeKey } from "../type-mapper.js"; function fixedTupleSpreadInfo( @@ -413,6 +413,30 @@ export function completeArgs( ); return out; } + // Tuple-spread values (pre-lowered) and plain arguments pack the same + // way. Each value evaluates once, in argument order. + if ( + restType.optionalElements === true && + !restNodes.some((a) => !isIr(a) && ts.isSpreadElement(a)) + ) { + const stmts: IrStmt[] = []; + const values = restNodes.map((a): IrExpr => { + if (isIr(a)) { + if (a.ir.kind !== "seqExpr") return a.ir; + stmts.push(...a.ir.stmts); + return a.ir.result; + } + const value = lowerer.lowerExpr(a as ts.Expression); + const saved = lowerer.declareHiddenLocal("%callArg", value.type); + stmts.push({ kind: "varDecl", localId: saved.id, init: value, loc: value.loc }); + return { kind: "varRef", localId: saved.id, type: value.type, loc: value.loc }; + }); + const items = lowerArrayValueItems(lowerer, values, restType.elem, restType, loc); + out.push( + stmts.length === 0 ? items : { kind: "seqExpr", stmts, result: items, type: restType, loc }, + ); + return out; + } // The rest pack is a fresh array per call; surplus SPREADS copy // their elements in (JS-exact — `f(a, ...xs, b, ...ys)` packs in // order, sources untouched). diff --git a/packages/compiler/src/frontend/lowering/expressions/element-access.ts b/packages/compiler/src/frontend/lowering/expressions/element-access.ts index 70909ca7b..a2f2ebdb6 100644 --- a/packages/compiler/src/frontend/lowering/expressions/element-access.ts +++ b/packages/compiler/src/frontend/lowering/expressions/element-access.ts @@ -2471,14 +2471,21 @@ function optionalArmIndexRead( return null; if (unionArrayValueRead(lowerer, value, key, loc) === null) return null; const stmts: IrStmt[] = []; - const stable = (e: IrExpr, name: string): IrExpr => { - if (e.kind === "varRef" || e.kind === "numLit") return e; + const stable = (e: IrExpr, name: string, keep: boolean): IrExpr => { + if (keep) return e; const local = lowerer.declareHiddenLocal(name, e.type); stmts.push({ kind: "varDecl", localId: local.id, init: e, loc }); return varRef(local.id, e.type, loc); }; - const receiver = stable(value, "%indexReceiver"); - const index = stable(key, "%indexKey"); + // A receiver local stays a direct read only when the key cannot assign + // it (`a[(a = other, 0)]` reads the array `a` held before the key). + const plainKey = key.kind === "varRef" || key.kind === "numLit"; + const receiver = stable( + value, + "%indexReceiver", + value.kind === "numLit" || (value.kind === "varRef" && plainKey), + ); + const index = stable(key, "%indexKey", plainKey); const read = unionArrayValueRead(lowerer, receiver, index, loc)!; return stmts.length === 0 ? read : { kind: "seqExpr", stmts, result: read, type: read.type, loc }; } diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 87825d030..28288a5f1 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -6546,8 +6546,20 @@ export class Lowerer { }, iterationMayYieldUndefined: (node) => { const type = typeOrNull(node); - if (type === null || this.checker.isArrayType(type) || this.checker.isTupleType(type)) - return false; + if (type === null || this.checker.isArrayType(type)) return false; + // A tuple yields its elements, in order. + if (this.checker.isTupleType(type)) + return panicSafe( + () => + this.checker + .getTypeArguments(type as ts.TypeReference) + .some((element) => + (element.isUnionType() ? ts.constituentTypes(element) : [element]).some( + (part) => (part.flags & (ts.TypeFlags.Undefined | ts.TypeFlags.Void)) !== 0, + ), + ), + true, + ); // The first type argument of Set, Map and Set iterators, // generators and iterables is the value they yield. const element = @@ -6601,6 +6613,14 @@ export class Lowerer { const rest = sig.params.find((shape) => shape.mode === "rest"); return rest?.type.kind === "array" ? [typeKey(rest.type.elem)] : []; }, + restStart: (call) => { + const callee = peel(call.expression); + if (!ts.isIdentifier(callee) && !ts.isPropertyAccessExpression(callee)) return null; + const symbol = callableSymbolOf(callee); + const sig = symbol ? signatureBySymbol.get(symbol) : undefined; + const at = sig ? sig.params.findIndex((shape) => shape.mode === "rest") : -1; + return at >= 0 ? at : null; + }, markIterationBinding: (node, known) => { const symbol = symbolOf(node); if (!symbol) return false; diff --git a/packages/compiler/src/frontend/lowering/runtime-optional-elements.ts b/packages/compiler/src/frontend/lowering/runtime-optional-elements.ts index fffe79a51..7561f4a65 100644 --- a/packages/compiler/src/frontend/lowering/runtime-optional-elements.ts +++ b/packages/compiler/src/frontend/lowering/runtime-optional-elements.ts @@ -31,6 +31,9 @@ export interface ElementStateHost { /** Element keys of the rest parameter that the spread arguments of * `call` fill: `[]` when the callee has none, null when it is unknown. */ restKeys(call: ts.CallExpression | ts.NewExpression): readonly string[] | null; + /** The argument index where the callee's rest parameter starts, or null + * when the callee has none or is unknown. */ + restStart?(call: ts.CallExpression | ts.NewExpression): number | null; /** Record that iterating `node`'s binding can observe `undefined`; * `known` when the iterated array's own facts (not only those shared by * its element ABI) say so. Returns true when the binding's record grew. */ @@ -518,14 +521,26 @@ export class ArrayElementStates { private scanCall(node: ts.CallExpression | ts.NewExpression): boolean { let changed = false; const args = node.arguments?.nodes ?? []; - // Spreading a sparse array into a rest parameter fills the holes. + // Spreading a sparse array, or a tuple with undefined elements, into a + // rest parameter fills the holes. if (args.some((arg) => ts.isSpreadElement(arg))) { for (const arg of args) { - if (!ts.isSpreadElement(arg) || !this.mayYieldUndefined(arg.expression)) continue; + if (!ts.isSpreadElement(arg) || !this.valueMayBeUndefined(arg)) continue; const rest = this.host.restKeys(node) ?? this.host.arrayKeys(arg.expression); if (this.addUndefined(rest)) changed = true; } } + // An argument in a rest position that may be undefined is a present + // undefined element of the rest array. + const restStart = this.host.restStart?.(node) ?? null; + if (restStart !== null) + for (const arg of args.slice(restStart)) + if ( + !ts.isSpreadElement(arg) && + this.host.mayBeUndefined(arg) && + this.addUndefined(this.host.restKeys(node)) + ) + changed = true; if (this.record(node)) changed = true; const callee = peel(node.expression); if (!ts.isPropertyAccessExpression(callee)) return changed; diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8004-optional-element-conversions.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8004-optional-element-conversions.ts.json new file mode 100644 index 000000000..2a1bc7c66 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8004-optional-element-conversions.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8004-optional-element-conversions.ts" + ], + "diags": [] +} diff --git a/tests/corpus/8004-optional-element-conversions.ts b/tests/corpus/8004-optional-element-conversions.ts new file mode 100644 index 000000000..2a394c331 --- /dev/null +++ b/tests/corpus/8004-optional-element-conversions.ts @@ -0,0 +1,49 @@ +// `(T | undefined)[]` values built by checked conversions, rest parameters +// and union index reads: nested arrays converted beside their non-optional +// form, a union arm that is an optional-element array, undefined arguments +// and tuple spreads packed into a rest parameter, and an index expression +// that reassigns the receiver. + +const plainRows = JSON.parse("[[1, 2], [3]]") as number[][]; +console.log(plainRows); +const optionalSource: unknown = (JSON.parse("[[1, null], [null, 4]]") as unknown[][]).map((row) => + row.map((v) => (v === null ? undefined : v)), +); +const optionalRows = optionalSource as (number | undefined)[][]; +console.log(optionalRows, optionalRows[0]![1], optionalRows[1]!.length); + +const armSource: unknown = [1, undefined, 3]; +const arm = armSource as (number | undefined)[] | string; +console.log(typeof arm === "string" ? arm : arm.length, arm); +const stringArm = ["a", undefined] as unknown as (string | undefined)[] | number; +console.log(stringArm); +const textArm = "text" as unknown as (string | undefined)[] | string; +console.log(textArm); + +function flags(...values: (boolean | undefined)[]): string { + let text = ""; + for (const value of values) text += value === undefined ? "u" : value ? "t" : "f"; + return `${values.length}:${text}:${String(values[1])}`; +} +console.log(flags(true, undefined)); +const flagPair: [boolean, boolean | undefined] = [false, undefined]; +console.log(flags(...flagPair), flags(true, ...flagPair), flags(...flagPair, true)); +function label(first: string, ...rest: (string | undefined)[]): string { + return `${first}/${rest.length}/${rest.map((v) => v ?? "-").join("")}`; +} +const words: [string, string | undefined, string | undefined] = ["a", undefined, "c"]; +console.log(label(...words), label("b", undefined)); + +function pick(start: (number | undefined)[] | string[], other: (number | undefined)[] | string[]): string { + let a = start; + const read = a[((a = other), 0)]; + return `${String(read)} ${String(a[0])}`; +} +console.log(pick([1, undefined, 3], ["x", "y"]), pick([undefined, 2], ["z"])); +function counted(start: (number | undefined)[] | string[]): string { + let b = start; + let i = 1; + const read = b[((b = ["q"]), i--)]; + return `${String(read)} ${b.length} ${i}`; +} +console.log(counted([4, undefined]), counted(["s", "t"])); diff --git a/tests/harness/corpus-costs/8004-optional-element-conversions.ts.json b/tests/harness/corpus-costs/8004-optional-element-conversions.ts.json new file mode 100644 index 000000000..9f8eb9e05 --- /dev/null +++ b/tests/harness/corpus-costs/8004-optional-element-conversions.ts.json @@ -0,0 +1 @@ +{ "plain": 4882, "san": 6379 } From 40adc2d1619c6598bc8600d79c93fb5455cbdef4 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 17:06:14 -0500 Subject: [PATCH 160/259] Hoist a call only when its arguments write no binding A hoisted call runs before the rest of its write. An argument such as `i++` in `acc = acc * 3 + i + tally(i++)` would then move that write ahead of the write's earlier read of `i`, so such a call stays where it is and the write is not speculated. --- .../src/backend/llvm/speculative-integers.test.ts | 5 +++++ .../src/backend/llvm/speculative-integers.ts | 15 ++++++++++++++- tests/corpus/7757-speculative-key-chains.ts | 10 ++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/packages/compiler/src/backend/llvm/speculative-integers.test.ts b/packages/compiler/src/backend/llvm/speculative-integers.test.ts index 151fab7c4..1b82768d5 100644 --- a/packages/compiler/src/backend/llvm/speculative-integers.test.ts +++ b/packages/compiler/src/backend/llvm/speculative-integers.test.ts @@ -382,6 +382,11 @@ test("other leaves are hoisted only when no call can change the write's locals", const hoisted = rewriteSpeculable(value, { unaliased: () => true, leafId })!; expect(hoisted.leaves.map((leaf) => leaf.expr)).toEqual([call("noisy", [ref("i")])]); expect(rewriteSpeculable(value, { unaliased: (id) => id !== "acc", leafId })).toBeNull(); + // A call whose argument writes a local stays where it is. + const bump: IrExpr = { kind: "incDec", localId: "i", op: "+", prefix: false, type: F64, loc }; + expect( + rewriteSpeculable(bin("+", ref("i"), call("noisy", [bump])), { unaliased: () => true, leafId }), + ).toBeNull(); // Without leaf ids nothing is hoisted. expect(rewriteSpeculable(value, { unaliased: () => true })).toBeNull(); const write = assign("acc", value); diff --git a/packages/compiler/src/backend/llvm/speculative-integers.ts b/packages/compiler/src/backend/llvm/speculative-integers.ts index 1d33a71ce..07e5e3721 100644 --- a/packages/compiler/src/backend/llvm/speculative-integers.ts +++ b/packages/compiler/src/backend/llvm/speculative-integers.ts @@ -1,5 +1,5 @@ import type { IrExpr, IrFunction, IrStmt } from "../../ir/ir.js"; -import { everyExprChild, everyStmtChild } from "../../ir/traverse.js"; +import { everyExpr, everyExprChild, everyStmtChild } from "../../ir/traverse.js"; import { InternalCompilerError } from "../../errors.js"; import { f64Lit } from "./common.js"; import type { LlValue, LlvmEmitterContext } from "./expr-context.js"; @@ -219,6 +219,15 @@ function isSpeculativeByteRead(e: IrExpr): boolean { ); } +/** Whether evaluating `e` assigns no binding: no `++`/`--`, no assignment + * expression, and no statement inside it. */ +function writesNoLocal(e: IrExpr): boolean { + return everyExpr(e, { + expr: (node) => node.kind !== "incDec" && node.kind !== "assignExpr", + stmt: () => false, + }); +} + /** Rewrite a write's value that isSpeculableValue refuses into one it can * speculate (SpeculativeValue), or null. Expansion and the new operations * (`Math.pow(2, n)`, `Math.floor(a / 2^n)`, byte reads) evaluate nothing @@ -295,6 +304,10 @@ export function rewriteSpeculable( // length, a Map read) are cheap where they stand, and would turn every // loop that adds one into a second copy. if (context.leafId === undefined || e.kind !== "call") return null; + // Hoisting runs the arguments before the rest of the write: one that + // assigns a local would move that write ahead of the write's earlier + // reads of it. + if (!e.args.every(writesNoLocal)) return null; const ref: IrExpr = { kind: "varRef", localId: context.leafId(), type: e.type, loc: e.loc }; leaves.push({ localId: (ref as { localId: string }).localId, expr: e, ref }); return ref; diff --git a/tests/corpus/7757-speculative-key-chains.ts b/tests/corpus/7757-speculative-key-chains.ts index 206b53827..1ef08a942 100644 --- a/tests/corpus/7757-speculative-key-chains.ts +++ b/tests/corpus/7757-speculative-key-chains.ts @@ -97,6 +97,15 @@ function effectfulHelper(n: number): number { return acc; } +// A call whose argument assigns a local the write also reads stays where it +// is: `i` is read before `i++` runs. +function stepped(n: number): number { + let acc = 1; + let i = 0; + while (i < n) acc = (acc * 3 + i + tally(i++)) % 1000003; + return acc; +} + const codes = new Uint8Array(5000); let seed = 7; for (let i = 0; i < codes.length; i++) { @@ -112,3 +121,4 @@ calls = 0; console.log(chained(34), chained(60), calls); console.log(nearPowers(4503599627370496, 3), nearPowers(9007199254740991, 2)); console.log(effectfulHelper(10), level); +console.log(stepped(40)); From 34ada100c47f24865125092cfaeb9bab7142a12b Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 17:07:05 -0500 Subject: [PATCH 161/259] Format the string comparison emission test --- tests/harness/string-compare-emission.test.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/harness/string-compare-emission.test.ts b/tests/harness/string-compare-emission.test.ts index 1a8fdddf6..b4219853e 100644 --- a/tests/harness/string-compare-emission.test.ts +++ b/tests/harness/string-compare-emission.test.ts @@ -45,9 +45,8 @@ console.log(words.join(",")); // Calls to the comparison runtime: `call`/`callq` on x86-64 and `bl` on // AArch64, with Mach-O's leading underscore on macOS. const compareCalls = (asm: string): number => - asm.match( - /\b(?:call[a-z]*|bl)\s+_?(?:sc_str_cmp_u16|scr_str_cmp_u16_bytes|scr_str_cmp)\b/g, - )?.length ?? 0; + asm.match(/\b(?:call[a-z]*|bl)\s+_?(?:sc_str_cmp_u16|scr_str_cmp_u16_bytes|scr_str_cmp)\b/g) + ?.length ?? 0; // The host's assembly, and two other targets' so that every host checks the // x86-64, AArch64 and Mach-O spellings. From 055c9ffa257d0f9ef63af5673d088c4804c997f4 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 17:07:44 -0500 Subject: [PATCH 162/259] Evaluate the arguments of deferred require.resolve calls before they throw Preflight admits a createRequire loader's require.resolve call with a computed request inside a try block, but lowering refused the call, so in JavaScript source the whole statement became a runtime fence. The fence threw before the request expression ran, and before anything else in the statement: `try { where = load.resolve(candidate(name)); }` skipped candidate()'s side effects, so the catch clause saw a different state than in Node. Such calls (a computed request, another argument shape, or runtime-computed options, on require.resolve and require.resolve.paths) now evaluate their arguments in order and then throw the fence, as a computed require call does. The addon-probe fixture checks that a computed candidate path runs before each failed lookup. --- docs/content/limitations/native-addons.mdx | 5 +- .../lowering/builtins/module-resolution.ts | 81 ++++++++++++++----- tests/fixtures/npm-static/addon-probe-cli.ts | 3 +- .../node_modules/addon-probe/index.d.ts | 1 + .../node_modules/addon-probe/index.js | 24 ++++++ tests/harness/npm-static.test.ts | 6 +- 6 files changed, 95 insertions(+), 25 deletions(-) diff --git a/docs/content/limitations/native-addons.mdx b/docs/content/limitations/native-addons.mdx index 5fff3d7e8..8fa7f94bf 100644 --- a/docs/content/limitations/native-addons.mdx +++ b/docs/content/limitations/native-addons.mdx @@ -3,8 +3,9 @@ Direct `createRequire` calls to local addons are rejected at compile time. A package that requires an addon needs a JavaScript implementation that compiles, or a replacement through native FFI. A package that looks for an optional addon at run time compiles with `--npm-static` when the lookup is inside a `try` block. -There, a `createRequire` require call with a computed specifier throws an error where it runs, and its `require.resolve` read as a value is a function that throws when called. -Coverage lists both as deferred to runtime. +There, a `createRequire` require call with a computed specifier, and a `require.resolve` or `require.resolve.paths` call with a computed request, evaluate their arguments and then throw an error. +Its `require.resolve` read as a value is a function that throws when called. +Coverage lists these as deferred to runtime. The package's `catch` clause then runs as it does in Node.js when the addon is missing. Outside a `try` block, the same uses keep the package refused. diff --git a/packages/compiler/src/frontend/lowering/builtins/module-resolution.ts b/packages/compiler/src/frontend/lowering/builtins/module-resolution.ts index 42ecfdd50..107e1f793 100644 --- a/packages/compiler/src/frontend/lowering/builtins/module-resolution.ts +++ b/packages/compiler/src/frontend/lowering/builtins/module-resolution.ts @@ -193,6 +193,39 @@ export function createRequireResolveFenceValue( }; } +/** A createRequire use deferred to run time in JavaScript source: as in + * Node, the call's arguments are evaluated in order, then the call throws + * (here, the fence). Code before the call in the same statement runs, and + * the expression diverges, so nothing after it does. */ +function deferredCreateRequireThrow( + lowerer: Lowerer, + call: ts.CallExpression, + surface: string, + hint: string, + loc: SrcLoc, +): IrExpr { + const stmts: IrStmt[] = call.arguments.nodes.map((arg) => ({ + kind: "exprStmt", + expr: lowerer.lowerExpr(arg), + loc: locOf(arg), + })); + const type = lowerer.irTypeOf(call); + const slot = lowerer.declareHiddenLocal("%never", type); + slot.mutable = true; + stmts.push( + { kind: "varDecl", localId: slot.id, init: null, loc }, + createRequireFence(lowerer, surface, call, hint), + ); + return { + kind: "seqExpr", + stmts, + result: varRef(slot.id, type, loc), + diverges: true, + type, + loc, + }; +} + export function lowerCreateRequireCall( lowerer: Lowerer, call: ts.CallExpression, @@ -205,27 +238,7 @@ export function lowerCreateRequireCall( const hint = 'the compiled module graph is fixed at build time — the one lowered form is require(""); native addons are not loaded'; if (!isJsSourceFile(ts.getSourceFileOfNode(call))) lowerer.noLowering(surface, call, hint); - // Node evaluates the arguments, then the require throws. - const stmts: IrStmt[] = call.arguments.nodes.map((arg) => ({ - kind: "exprStmt", - expr: lowerer.lowerExpr(arg), - loc: locOf(arg), - })); - const type = lowerer.irTypeOf(call); - const slot = lowerer.declareHiddenLocal("%never", type); - slot.mutable = true; - stmts.push( - { kind: "varDecl", localId: slot.id, init: null, loc }, - createRequireFence(lowerer, surface, call, hint), - ); - return { - kind: "seqExpr", - stmts, - result: varRef(slot.id, type, loc), - diverges: true, - type, - loc, - }; + return deferredCreateRequireThrow(lowerer, call, surface, hint, loc); } const spec = cr.spec; if (spec === "node:ffi") { @@ -446,11 +459,30 @@ export function lowerRequireResolveCall(lowerer: Lowerer, call: ts.CallExpressio } const baseFile = requireResolverBaseFile(lowerer, receiver); if (baseFile === null) return null; + const surface = pathsCall ? "require.resolve.paths" : "require.resolve"; + // A createRequire loader's query that resolves only at run time, in + // JavaScript source: preflight admits it inside a try block + // (createRequireUse7 in program.ts). Its arguments run, then it throws. + const deferred = (what: string, hint: string): IrExpr | null => + call.questionDotToken === undefined && + createRequireCalleeFileOf(lowerer, receiver) !== null && + isJsSourceFile(ts.getSourceFileOfNode(call)) + ? deferredCreateRequireThrow( + lowerer, + call, + `createRequire's ${surface} ${what}`, + hint, + locOf(call), + ) + : null; + const resolveHint = `call it with a string literal (${surface}("")), which resolves at build time`; if ( call.questionDotToken !== undefined || call.arguments.nodes.length < 1 || call.arguments.nodes.length > (pathsCall ? 1 : 2) ) { + const fenced = deferred("with this argument shape", resolveHint); + if (fenced) return fenced; lowerer.noLowering( pathsCall ? "require.resolve.paths with this argument shape" @@ -460,6 +492,8 @@ export function lowerRequireResolveCall(lowerer: Lowerer, call: ts.CallExpressio } const specifier = staticString(call.arguments.nodes[0]); if (specifier === null) { + const fenced = deferred("with a computed request", resolveHint); + if (fenced) return fenced; lowerer.noLowering( `${pathsCall ? "require.resolve.paths" : "require.resolve"} with a runtime-computed request`, call.arguments.nodes[0]!, @@ -495,6 +529,11 @@ export function lowerRequireResolveCall(lowerer: Lowerer, call: ts.CallExpressio } const paths = staticResolveOptionPaths(call.arguments.nodes[1]); if (paths === null) { + const fenced = deferred( + "with runtime-computed options", + 'omit options or pass { paths: ["", ...] }', + ); + if (fenced) return fenced; lowerer.noLowering( "require.resolve with runtime-computed options", call.arguments.nodes[1]!, diff --git a/tests/fixtures/npm-static/addon-probe-cli.ts b/tests/fixtures/npm-static/addon-probe-cli.ts index 4515fb5bf..aa21df05d 100644 --- a/tests/fixtures/npm-static/addon-probe-cli.ts +++ b/tests/fixtures/npm-static/addon-probe-cli.ts @@ -1,5 +1,6 @@ -import { probe, resolveHelper } from "addon-probe"; +import { locate, probe, resolveHelper } from "addon-probe"; import { join } from "node:path"; console.log(join("a", "b"), [probe("clipboard"), probe("keys"), resolveHelper("addon-probe-helper")].join(",")); console.log(resolveHelper("other", (id) => `custom:${id}`)); +console.log(locate("helper")); diff --git a/tests/fixtures/npm-static/node_modules/addon-probe/index.d.ts b/tests/fixtures/npm-static/node_modules/addon-probe/index.d.ts index cfacc4764..a9987d787 100644 --- a/tests/fixtures/npm-static/node_modules/addon-probe/index.d.ts +++ b/tests/fixtures/npm-static/node_modules/addon-probe/index.d.ts @@ -1,2 +1,3 @@ export declare function probe(name: string): string; export declare function resolveHelper(name: string, resolvePackage?: (id: string) => string): string; +export declare function locate(name: string): string; diff --git a/tests/fixtures/npm-static/node_modules/addon-probe/index.js b/tests/fixtures/npm-static/node_modules/addon-probe/index.js index e65b1ad0e..2cc423359 100644 --- a/tests/fixtures/npm-static/node_modules/addon-probe/index.js +++ b/tests/fixtures/npm-static/node_modules/addon-probe/index.js @@ -26,3 +26,27 @@ export function resolveHelper(name, resolvePackage) { return "unresolved"; } } + +let probes = 0; +function candidate(name) { + probes++; + return `./${name}-${probes}.node`; +} + +// Resolves computed candidate paths: the arguments run before the lookup +// fails, as an assignment and as a statement of their own. +export function locate(name) { + let where = "none"; + try { + where = load.resolve(candidate(name)); + } catch { + where = `missing after ${probes}`; + } + try { + load.resolve(candidate(name)); + where += ",found"; + } catch { + where += `,missing after ${probes}`; + } + return where; +} diff --git a/tests/harness/npm-static.test.ts b/tests/harness/npm-static.test.ts index 026da8f4e..4ddb6fe15 100644 --- a/tests/harness/npm-static.test.ts +++ b/tests/harness/npm-static.test.ts @@ -435,6 +435,8 @@ describe(`npm-static pilots${sanitize ? " (sanitized)" : ""}`, () => { ).toEqual([ expect.stringContaining("'createRequire's require with a computed specifier"), expect.stringContaining("'createRequire's require.resolve as a value'"), + expect.stringContaining("'createRequire's require.resolve with a computed request'"), + expect.stringContaining("'createRequire's require.resolve with a computed request'"), ]); const outDir = join(cacheDir, "addon-probe", sanitize ? "san" : "plain", backend); const result = await compile(entry, { @@ -450,7 +452,9 @@ describe(`npm-static pilots${sanitize ? " (sanitized)" : ""}`, () => { runBinary(process.execPath, [entry]), runBinary(result.binaryPath, []), ]); - expect(nativeRes.stdout.toString()).toBe("a/b absent,absent,unresolved\ncustom:other\n"); + expect(nativeRes.stdout.toString()).toBe( + "a/b absent,absent,unresolved\ncustom:other\nmissing after 1,missing after 2\n", + ); expect(nativeRes.stdout).toEqual(nodeRes.stdout); expect(comparableStderr(nativeRes.stderr)).toEqual(nodeRes.stderr); expect(nativeRes.exitCode).toBe(nodeRes.exitCode); From adbd9cd1e9b85fbe6b997e6ba2170b2f1d5a1858 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 17:18:30 -0500 Subject: [PATCH 163/259] Lower each closure argument of an implicit-any call once To key an implicit-any function's instance, storedImplicitArgumentType lowers a JavaScript arrow or function-expression argument to read its function type, then discards the value; the call's argument list then lowers the closure again. Every such closure was lowered twice, and a closure nested in another one four times, and each lowering lifted its own copy of the body. The first lowering now keeps its value (Lowerer.speculatedClosures), and the argument's own lowering in the same function and with the same type bindings takes it instead of lowering the closure again. A lowering that reported diagnostics is not kept. --- .../frontend/lowering/generic-functions.ts | 17 ++++++++++-- .../compiler/src/frontend/lowering/lowerer.ts | 26 +++++++++++++++++++ 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/generic-functions.ts b/packages/compiler/src/frontend/lowering/generic-functions.ts index 7896da578..0f9e41723 100644 --- a/packages/compiler/src/frontend/lowering/generic-functions.ts +++ b/packages/compiler/src/frontend/lowering/generic-functions.ts @@ -2082,6 +2082,10 @@ function storedImplicitArgumentType(lowerer: Lowerer, arg: ts.Expression): IrTyp isJsSourceFile(ts.getSourceFileOfNode(arg)) && (ts.isArrowFunction(arg) || ts.isFunctionExpression(arg)) ) { + // A closure lowered here before (another call site's instance key, or + // a repeated demand) keeps its value for the argument's own lowering. + const known = lowerer.speculatedClosure(arg); + if (known !== null) return known.type; const saved = lowerer.diagSink; const diagnostics: typeof lowerer.diags = []; lowerer.diagSink = diagnostics; @@ -2092,8 +2096,17 @@ function storedImplicitArgumentType(lowerer: Lowerer, arg: ts.Expression): IrTyp lowerer.diagSink = saved; } // Direct inferred helpers can receive native callbacks even when their - // result is an opaque handle that cannot cross checked storage. - if (diagnostics.length === 0 && value?.type.kind === "func") return value.type; + // result is an opaque handle that cannot cross checked storage. The + // argument's own lowering then takes this value instead of lowering + // the closure a second time. + if (diagnostics.length === 0 && value?.type.kind === "func") { + lowerer.speculatedClosures.set(arg, { + ctx: lowerer.ctx, + bindings: lowerer.typeParamBindings, + value, + }); + return value.type; + } } if (arg.kind === ts.SyntaxKind.ThisKeyword) return lowerer.resolveThis()?.type ?? null; if (ts.isAwaitExpression(arg)) { diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 6fd6d863a..dd07d0075 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -3174,6 +3174,14 @@ export class Lowerer { * (builtins/fs-paths.ts): each lowers to the hidden local that holds its * value, which is null until the path's lowering has saved it. */ readonly stagedArguments = new Map(); + /** Closure arguments an implicit-any call already lowered to learn their + * type (storedImplicitArgumentType), by node: the argument's own lowering + * in the same function and with the same type bindings takes that value + * once instead of lowering the closure again. */ + readonly speculatedClosures = new Map< + ts.Expression, + { ctx: FnCtx; bindings: Map | null; value: IrExpr } + >(); /** What each fs path argument of a URL-path call lowers to (the plans * of builtins/fs-paths.ts). */ readonly fsPathPlans = new Map(); @@ -12938,12 +12946,30 @@ export class Lowerer { /* ── expressions ──────────────────────────────────────────────────── */ lowerExpr(expr: ts.Expression): IrExpr { + if (this.speculatedClosures.size > 0) { + const speculated = this.speculatedClosure(expr); + if (speculated !== null) { + this.speculatedClosures.delete(expr); + return speculated; + } + } const streamValue = this.valueStreamReceivers.get(expr); if (streamValue) return valueStreamOf(varRef(streamValue.localId, streamValue.type, locOf(expr))); return this.stagedArgument(expr) ?? lowerExpr(this, expr); } + /** The value storedImplicitArgumentType lowered for `expr` in the active + * function and type bindings (speculatedClosures), or null. */ + speculatedClosure(expr: ts.Expression): IrExpr | null { + const entry = this.speculatedClosures.get(expr); + return entry !== undefined && + entry.ctx === this.ctx && + entry.bindings === this.typeParamBindings + ? entry.value + : null; + } + /** The saved value of a staged fs argument (stagedArguments, keyed * without type-only wrappers), or null for every other expression. */ private stagedArgument(node: ts.Expression): IrExpr | null { From cc6b1144681da6c0d29649d44ee203703e9db25d Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 17:23:08 -0500 Subject: [PATCH 164/259] Take the argument count before parameters bind A function that reads arguments.length and is called through a value reads the count its adapter stored, then clears the slot. That read ran after the parameter prologue, so a parameter binding that threw would leave the slot set for the next direct call. The count is now taken, and the slot cleared, before any parameter binds. --- .../src/frontend/lowering/lower-functions.ts | 7 ++++++- ...3-argument-count-destructured-parameter.ts.json | 6 ++++++ .../8223-argument-count-destructured-parameter.ts | 14 ++++++++++++++ ...3-argument-count-destructured-parameter.ts.json | 1 + 4 files changed, 27 insertions(+), 1 deletion(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8223-argument-count-destructured-parameter.ts.json create mode 100644 tests/corpus/8223-argument-count-destructured-parameter.ts create mode 100644 tests/harness/corpus-costs/8223-argument-count-destructured-parameter.ts.json diff --git a/packages/compiler/src/frontend/lowering/lower-functions.ts b/packages/compiler/src/frontend/lowering/lower-functions.ts index c1682f7c8..bd9b5f55d 100644 --- a/packages/compiler/src/frontend/lowering/lower-functions.ts +++ b/packages/compiler/src/frontend/lowering/lower-functions.ts @@ -535,12 +535,18 @@ export function lowerFunction(lowerer: Lowerer, decl: ts.FunctionDeclaration): I const diagsBefore = lowerer.diags.length; lowerer.fnStack.push(ctx); try { + // The count a call through a value stored is taken (and its slot + // cleared) before the parameters bind: a destructuring default that + // throws must not leave the slot set for the next direct call. + const argumentCount: IrStmt[] = []; + declareArgumentCount(lowerer, decl, argumentCount); const receiver = decl.parameters.nodes.some(isThisParameter) || isJsSourceFile(ts.getSourceFileOfNode(decl)) ? declareCallReceiver(lowerer, decl, sig.generator !== undefined) : null; const { params, prologue } = lowerer.declareParams(decl.parameters.nodes, sig.params); if (receiver) prologue.unshift(receiver); + prologue.unshift(...argumentCount); declareFunctionArguments( lowerer, decl, @@ -552,7 +558,6 @@ export function lowerFunction(lowerer: Lowerer, decl: ts.FunctionDeclaration): I (sig.params[sig.params.length - 1]!.mode === "dynRest" || sig.params[sig.params.length - 1]!.mode === "arguments"), ); - declareArgumentCount(lowerer, decl, prologue); const bodyBlock = blockBodyOf(decl); if (!bodyBlock) { lowerer.unsupported( diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8223-argument-count-destructured-parameter.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8223-argument-count-destructured-parameter.ts.json new file mode 100644 index 000000000..6cae202d3 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8223-argument-count-destructured-parameter.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8223-argument-count-destructured-parameter.ts" + ], + "diags": [] +} diff --git a/tests/corpus/8223-argument-count-destructured-parameter.ts b/tests/corpus/8223-argument-count-destructured-parameter.ts new file mode 100644 index 000000000..def8c5ba8 --- /dev/null +++ b/tests/corpus/8223-argument-count-destructured-parameter.ts @@ -0,0 +1,14 @@ +// A function with a destructured parameter that reads arguments.length, +// called through a value (map passes three arguments) and directly. The +// count is taken before the parameters bind, so each call sees its own. + +function probe({ v, w }: { v: number; w: string }): string { + return `${arguments.length}:${v}${w}`; +} + +console.log([{ v: 1, w: "a" }, { v: 2, w: "b" }].map(probe)); +console.log(probe({ v: 3, w: "c" })); +const call = (f: (item: { v: number; w: string }, index: number) => string): string => + f({ v: 4, w: "d" }, 0); +console.log(call(probe)); +console.log(probe({ v: 5, w: "e" })); diff --git a/tests/harness/corpus-costs/8223-argument-count-destructured-parameter.ts.json b/tests/harness/corpus-costs/8223-argument-count-destructured-parameter.ts.json new file mode 100644 index 000000000..664b49416 --- /dev/null +++ b/tests/harness/corpus-costs/8223-argument-count-destructured-parameter.ts.json @@ -0,0 +1 @@ +{ "plain": 4700, "san": 4200 } From 7fb950deaf04b0eb48943694c213a7b652f5903b Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 17:29:34 -0500 Subject: [PATCH 165/259] Keep rejectUnauthorized on unless false, and certificates independent of raw A server with requestCert read a runtime rejectUnauthorized through JavaScript truthiness, so null, 0 or "" let clients without a valid certificate through, and tls.connect read it the same way. Both now treat only false as off, as Node's options.rejectUnauthorized !== false does; a standalone TLSSocket keeps Node's truthiness test. An X509Certificate's methods read the record's raw Buffer, so writing into the Buffer that certificate.raw answers changed later checks, the PEM and the public key. The record now keeps a hidden copy of the DER that the methods read, and raw stays the same Buffer at every read, as in Node. --- .../src/frontend/lowering/builtins/x509.ts | 17 +++--- .../src/frontend/lowering/lower-classes.ts | 3 + packages/compiler/src/frontend/type-mapper.ts | 9 ++- ...79-tls-reject-unauthorized-values.mjs.json | 6 ++ .../tests/corpus/8181-x509-raw-writes.ts.json | 6 ++ packages/runtime/src/scr_tls.c | 14 +++-- .../8179-tls-reject-unauthorized-values.mjs | 55 +++++++++++++++++++ tests/corpus/8181-x509-raw-writes.ts | 20 +++++++ ...79-tls-reject-unauthorized-values.mjs.json | 1 + .../corpus-costs/8181-x509-raw-writes.ts.json | 1 + 10 files changed, 119 insertions(+), 13 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8179-tls-reject-unauthorized-values.mjs.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8181-x509-raw-writes.ts.json create mode 100644 tests/corpus/8179-tls-reject-unauthorized-values.mjs create mode 100644 tests/corpus/8181-x509-raw-writes.ts create mode 100644 tests/harness/corpus-costs/8179-tls-reject-unauthorized-values.mjs.json create mode 100644 tests/harness/corpus-costs/8181-x509-raw-writes.ts.json diff --git a/packages/compiler/src/frontend/lowering/builtins/x509.ts b/packages/compiler/src/frontend/lowering/builtins/x509.ts index bc0092369..5d81070eb 100644 --- a/packages/compiler/src/frontend/lowering/builtins/x509.ts +++ b/packages/compiler/src/frontend/lowering/builtins/x509.ts @@ -16,13 +16,14 @@ import { } from "../../../ir/ir.js"; import { everyStmtList } from "../../../ir/traverse.js"; import { unsupportedDiag } from "../../../diagnostics/diagnostic.js"; -import { X509_PUBLIC_KEY_FIELD } from "../../type-mapper.js"; +import { X509_DER_FIELD, X509_PUBLIC_KEY_FIELD } from "../../type-mapper.js"; import { keyedHelperName } from "../stable-names.js"; import { x509RecordCall } from "../lower-classes.js"; /* node:crypto's X509Certificate members beyond its fields: the methods * and the publicKey getter. A certificate is the Dirent-style record - * (type-mapper.ts), and each member reads its raw DER. checkHost, + * (type-mapper.ts), and each member reads the record's hidden copy of its + * DER, which writes into the `raw` Buffer leave alone, as in Node. checkHost, * checkEmail, checkIP, checkIssued, toLegacyObject and the PEM of * toString/toJSON run in scr_x509.c; * publicKey, verify and checkPrivateKey read keys in scr_pki.c. The first @@ -110,7 +111,7 @@ export function refuseX509DynValues(lowerer: Lowerer, functions: readonly IrFunc /** String(x509), `${x509}` and x509 + "": the certificate's toString(), * its PEM. */ export function x509ToString(record: IrExpr, loc: SrcLoc): IrExpr { - return { kind: "libCall", fn: "crypto.x509Pem", args: [rawOf(record, loc)], type: STRING, loc }; + return { kind: "libCall", fn: "crypto.x509Pem", args: [derOf(record, loc)], type: STRING, loc }; } /** Node keeps a certificate's fields as prototype getters, so own-key @@ -131,13 +132,13 @@ export function fenceX509KeyWalk( ); } -function rawOf(record: IrExpr, loc: SrcLoc): IrExpr { +function derOf(record: IrExpr, loc: SrcLoc): IrExpr { if (record.type.kind !== "record") return record; return { kind: "recordGet", obj: record, shapeId: record.type.shapeId, - field: "raw", + field: X509_DER_FIELD, type: BYTES_U8, loc, }; @@ -254,7 +255,7 @@ export function lowerX509PublicKey( value: { kind: "libCall", fn: "crypto.x509PublicKey", - args: [rawOf(c, loc)], + args: [derOf(c, loc)], type: DYN, loc, }, @@ -310,7 +311,7 @@ export function lowerX509Call(lowerer: Lowerer, call: ts.CallExpression): IrExpr `the supported form is ${method.form}`, ); } - const raw = rawOf(lowerer.lowerExpr(access.expression), loc); + const raw = derOf(lowerer.lowerExpr(access.expression), loc); if (method.fn === "crypto.x509LegacyObject") { return { kind: "libCall", fn: method.fn, args: [raw], type: DYN, loc }; } @@ -337,7 +338,7 @@ export function lowerX509Call(lowerer: Lowerer, call: ts.CallExpression): IrExpr loc, }; } - const other = rawOf(lowerer.lowerExpr(args[0]!), loc); + const other = derOf(lowerer.lowerExpr(args[0]!), loc); return { kind: "libCall", fn: method.fn, args: [raw, other], type: BOOL, loc }; } const first = lowerer.lowerExprExpecting(args[0]!, DYN); diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index 9035869d9..23dac58a2 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -100,6 +100,7 @@ import { jsOpenObjectType, typeKey, withUnitArm, + X509_DER_FIELD, X509_PUBLIC_KEY_FIELD, } from "../type-mapper.js"; import { @@ -11313,6 +11314,8 @@ function x509RecordHelper( type: DYN, loc, }), + // A copy: writes into `raw` must not reach the methods. + [X509_DER_FIELD]: () => call("crypto.x509RawDer", BYTES_U8), }; /** A string | undefined field: the runtime's text, or undefined for "". */ function optionalText(local: string, fn: IrLibFn, type: IrType): IrExpr { diff --git a/packages/compiler/src/frontend/type-mapper.ts b/packages/compiler/src/frontend/type-mapper.ts index f51efd5f1..9a8ae46ba 100644 --- a/packages/compiler/src/frontend/type-mapper.ts +++ b/packages/compiler/src/frontend/type-mapper.ts @@ -6715,8 +6715,14 @@ function boundVoidReturnType(p: ts.Type, resolveTypeParam?: TypeParamResolver): * filled on the first read (builtins/x509.ts). */ export const X509_PUBLIC_KEY_FIELD = "%publicKey"; +/** The X509Certificate record's hidden copy of its DER, which its methods + * read: a program can write into the Buffer `raw` answers, and in Node + * that changes neither the certificate's checks nor its PEM. */ +export const X509_DER_FIELD = "%der"; + /** The X509Certificate record's fields in @types/node's declaration order - * ("string?" is string | undefined), then the hidden publicKey slot. */ + * ("string?" is string | undefined), then the hidden publicKey and DER + * slots. */ export const X509_FIELDS: readonly (readonly [string, IrType | "string?"])[] = [ ["ca", BOOL], ["fingerprint", STRING], @@ -6735,6 +6741,7 @@ export const X509_FIELDS: readonly (readonly [string, IrType | "string?"])[] = [ ["validTo", STRING], ["validToDate", DATE_T], [X509_PUBLIC_KEY_FIELD, DYN], + [X509_DER_FIELD, { kind: "bytes", elem: "u8" }], ]; export function withUndefinedArm(t: IrType, unions: UnionRegistry): IrType | null { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8179-tls-reject-unauthorized-values.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8179-tls-reject-unauthorized-values.mjs.json new file mode 100644 index 000000000..ef98570e2 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8179-tls-reject-unauthorized-values.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8179-tls-reject-unauthorized-values.mjs" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8181-x509-raw-writes.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8181-x509-raw-writes.ts.json new file mode 100644 index 000000000..d92d8f8fd --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8181-x509-raw-writes.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8181-x509-raw-writes.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_tls.c b/packages/runtime/src/scr_tls.c index e764926b2..547fef27a 100644 --- a/packages/runtime/src/scr_tls.c +++ b/packages/runtime/src/scr_tls.c @@ -2232,8 +2232,8 @@ static void scr_tls_opt_fence(const char *api, const char *key, const char *hint scr_throw_error(SCR_ERR_ERROR, scr_jb_finish(&b)); } -/* JS truthiness over the dyn kinds — Node reads requestCert / - * rejectUnauthorized through `if (options.x)`. */ +/* JS truthiness over the dyn kinds — Node reads requestCert (and a + * standalone TLSSocket's rejectUnauthorized) through `if (options.x)`. */ static bool scr_tls_dyn_truthy(const ScrDyn *v) { switch (v->kind) { case SCR_DYN_UNDEF: @@ -2245,6 +2245,12 @@ static bool scr_tls_dyn_truthy(const ScrDyn *v) { } } +/* tls.Server and tls.connect read rejectUnauthorized as + * `options.rejectUnauthorized !== false`: null, 0 and "" keep it on. */ +static bool scr_tls_dyn_not_false(const ScrDyn *v) { + return v->kind != SCR_DYN_BOOL || v->v.b; +} + /* PEM material from a runtime option value: a string, a Buffer/Uint8Array, * or an array of those. `concat` (the client `ca` bundle) joins array * entries; cert/key arrays accept exactly one entry (one identity per @@ -2630,7 +2636,7 @@ static bool scr_tls_srv_opts_walk_ex(const ScrDyn *opts, const char *api, ScrByt continue; } if (strcmp(e->key, "rejectUnauthorized") == 0) { - if (auth != NULL) auth->reject = scr_tls_dyn_truthy(v); + if (auth != NULL) auth->reject = scr_tls_dyn_not_false(v); continue; /* without client certificates it has no effect */ } if (server_ok && (strcmp(e->key, "ALPNProtocols") == 0 || strcmp(e->key, "minVersion") == 0 || @@ -3300,7 +3306,7 @@ static ScrNetSocket *scr_tls_connect_plain(double port, ScrStr *host /*borrowed, continue; } if (strcmp(e->key, "rejectUnauthorized") == 0) { - reject = scr_tls_dyn_truthy(v); + reject = scr_tls_dyn_not_false(v); continue; } if (strcmp(e->key, "ca") == 0) { diff --git a/tests/corpus/8179-tls-reject-unauthorized-values.mjs b/tests/corpus/8179-tls-reject-unauthorized-values.mjs new file mode 100644 index 000000000..d0275ab4a --- /dev/null +++ b/tests/corpus/8179-tls-reject-unauthorized-values.mjs @@ -0,0 +1,55 @@ +// rejectUnauthorized is off only when it is false, as in Node: on a server +// with requestCert, null, 0, "" and undefined keep rejecting clients that +// send no certificate, and in tls.connect they keep rejecting a server +// certificate that does not verify. +import { readFileSync } from "node:fs"; +import * as tls from "node:tls"; + +const D = "tests/fixtures/server/certs"; +const r = (f) => readFileSync(`${D}/${f}`); +const ca = r("ca.pem"), cert = r("localhost.pem"), key = r("localhost-key.pem"); +const self = r("selfsigned.pem"), selfKey = r("selfsigned-key.pem"); + +const values = [ + ["false", false], + ["true", true], + ["null", null], + ["0", 0], + ['""', ""], + ["undefined", undefined], +]; + +for (const [label, value] of values) { + const events = []; + const server = tls.createServer({ cert, key, requestCert: true, rejectUnauthorized: value }, (s) => { + events.push(`server authorized=${s.authorized} error=${s.authorizationError}`); + s.end("ok"); + }); + const port = await new Promise((res) => server.listen(0, () => res(server.address().port))); + await new Promise((done) => { + const c = tls.connect({ port, ca, servername: "localhost" }); + c.on("secureConnect", () => events.push("client secureConnect")); + c.on("data", (d) => events.push(`client data ${d}`)); + c.on("error", (e) => events.push(`client error ${e.code}`)); + c.on("close", () => setTimeout(done, 50)); + }); + console.log("rejectUnauthorized", label, "|", events.join(" ; ")); + await new Promise((res) => server.close(() => res())); +} + +{ + const server = tls.createServer({ cert: self, key: selfKey }, (s) => s.end("ok")); + const port = await new Promise((res) => server.listen(0, () => res(server.address().port))); + for (const [label, value] of values) { + const events = []; + await new Promise((done) => { + const c = tls.connect({ port, servername: "localhost", rejectUnauthorized: value }); + c.on("secureConnect", () => events.push(`secureConnect authorized=${c.authorized} error=${c.authorizationError}`)); + c.on("data", (d) => events.push(`data ${d}`)); + c.on("error", (e) => events.push(`error ${e.code}`)); + c.on("close", () => done()); + }); + console.log("tls.connect rejectUnauthorized", label, "|", events.join(" ; ")); + } + server.close(); +} diff --git a/tests/corpus/8181-x509-raw-writes.ts b/tests/corpus/8181-x509-raw-writes.ts new file mode 100644 index 000000000..17704096d --- /dev/null +++ b/tests/corpus/8181-x509-raw-writes.ts @@ -0,0 +1,20 @@ +// A certificate's raw Buffer is the same object at every read, and writing +// into it changes neither the certificate's fields, checks and PEM nor its +// public key, as in Node: the methods read the certificate itself. +import { X509Certificate } from "node:crypto"; +import { readFileSync } from "node:fs"; + +const cert = new X509Certificate(readFileSync("tests/fixtures/server/certs/localhost.pem")); +const ca = new X509Certificate(readFileSync("tests/fixtures/server/certs/ca.pem")); +const raw = cert.raw; +console.log("same Buffer", raw === cert.raw); +const report = (): string => + `${cert.fingerprint256}\n${cert.subject}\n${cert.checkHost("localhost")}\n` + + `${cert.checkIssued(ca)} ${ca.checkIssued(cert)} ${cert.verify(ca.publicKey)}\n` + + `${cert.toString()}\n${cert.publicKey.export({ format: "pem", type: "spki" })}`; +const before = report(); +raw.fill(0); +console.log("unchanged", report() === before); +console.log("raw now", cert.raw.every((b) => b === 0), cert.raw.length); +const other = new X509Certificate(readFileSync("tests/fixtures/server/certs/localhost.pem")); +console.log("fresh certificate raw", other.raw[0], other.raw.equals(cert.raw)); diff --git a/tests/harness/corpus-costs/8179-tls-reject-unauthorized-values.mjs.json b/tests/harness/corpus-costs/8179-tls-reject-unauthorized-values.mjs.json new file mode 100644 index 000000000..ef441a0df --- /dev/null +++ b/tests/harness/corpus-costs/8179-tls-reject-unauthorized-values.mjs.json @@ -0,0 +1 @@ +{ "plain": 5582, "san": 65742 } diff --git a/tests/harness/corpus-costs/8181-x509-raw-writes.ts.json b/tests/harness/corpus-costs/8181-x509-raw-writes.ts.json new file mode 100644 index 000000000..df264cf6e --- /dev/null +++ b/tests/harness/corpus-costs/8181-x509-raw-writes.ts.json @@ -0,0 +1 @@ +{ "plain": 3996, "san": 8383 } From 2edebe7e2ff7df84903a9236aa147472950b3002 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 17:30:32 -0500 Subject: [PATCH 166/259] Read spread tuple fields before later rest arguments run The packing path for `(T | undefined)[]` rest parameters saved plain arguments to temporaries but read tuple fields only when it built the pack, after every later argument had run. A later argument that wrote the tuple changed values already spread into the call. Each tuple field is now saved where its spread appears, in argument order. --- .../src/frontend/lowering/call-arguments.ts | 14 +++++++++----- .../corpus/8004-optional-element-conversions.ts | 16 ++++++++++++++++ 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/call-arguments.ts b/packages/compiler/src/frontend/lowering/call-arguments.ts index b02d0b85c..a139bfc64 100644 --- a/packages/compiler/src/frontend/lowering/call-arguments.ts +++ b/packages/compiler/src/frontend/lowering/call-arguments.ts @@ -421,12 +421,16 @@ export function completeArgs( ) { const stmts: IrStmt[] = []; const values = restNodes.map((a): IrExpr => { + // A tuple field is read where its spread appears: a later + // argument may write the tuple. + let value: IrExpr; if (isIr(a)) { - if (a.ir.kind !== "seqExpr") return a.ir; - stmts.push(...a.ir.stmts); - return a.ir.result; - } - const value = lowerer.lowerExpr(a as ts.Expression); + value = a.ir; + if (value.kind === "seqExpr") { + stmts.push(...value.stmts); + value = value.result; + } + } else value = lowerer.lowerExpr(a as ts.Expression); const saved = lowerer.declareHiddenLocal("%callArg", value.type); stmts.push({ kind: "varDecl", localId: saved.id, init: value, loc: value.loc }); return { kind: "varRef", localId: saved.id, type: value.type, loc: value.loc }; diff --git a/tests/corpus/8004-optional-element-conversions.ts b/tests/corpus/8004-optional-element-conversions.ts index 2a394c331..07178e9b0 100644 --- a/tests/corpus/8004-optional-element-conversions.ts +++ b/tests/corpus/8004-optional-element-conversions.ts @@ -33,6 +33,22 @@ function label(first: string, ...rest: (string | undefined)[]): string { } const words: [string, string | undefined, string | undefined] = ["a", undefined, "c"]; console.log(label(...words), label("b", undefined)); +// Spread tuple fields are read before later arguments run. +const changing: [boolean, boolean | undefined] = [true, undefined]; +function flip(pair: [boolean, boolean | undefined], second: boolean | undefined): boolean { + pair[0] = !pair[0]; + pair[1] = second; + return pair[0]; +} +console.log(flags(...changing, flip(changing, true))); +console.log(flags(...changing, flip(changing, undefined), ...changing)); +const swapped: [string, string | undefined] = ["x", "y"]; +function swap(pair: [string, string | undefined]): string { + pair[0] = "w"; + pair[1] = undefined; + return "v"; +} +console.log(label("z", ...swapped, swap(swapped), ...swapped)); function pick(start: (number | undefined)[] | string[], other: (number | undefined)[] | string[]): string { let a = start; From 51557931556f79b49f4b8a00fe80c6a59aeaaf05 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 17:33:30 -0500 Subject: [PATCH 167/259] Decode passphrases with the key's encoding, and refuse RSA-PSS keys restricted to other digests createPrivateKey decoded a string passphrase as UTF-8 whatever the options' encoding, so a correct passphrase given in that encoding failed to decrypt, and an encrypted export read its passphrase the same way. Both now decode it with the encoding, as Node does. An RSA-PSS key whose parameters name a digest the runtime does not sign with, such as sha512-224 or sha512-256, was imported without its digest, MGF1 and salt restrictions, so it allowed operations the key forbids. It now throws a coded SC2020 error that names the digest. Parameters that are malformed still leave the key unrestricted, as OpenSSL reads them. --- .../8183-key-passphrase-encoding.cjs.json | 6 ++ packages/runtime/src/scr_pki.c | 78 +++++++++++++++---- tests/corpus/8183-key-passphrase-encoding.cjs | 28 +++++++ .../8183-key-passphrase-encoding.cjs.json | 1 + tests/harness/errors.test.ts | 32 ++++++++ 5 files changed, 128 insertions(+), 17 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8183-key-passphrase-encoding.cjs.json create mode 100644 tests/corpus/8183-key-passphrase-encoding.cjs create mode 100644 tests/harness/corpus-costs/8183-key-passphrase-encoding.cjs.json diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8183-key-passphrase-encoding.cjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8183-key-passphrase-encoding.cjs.json new file mode 100644 index 000000000..ee89a2add --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8183-key-passphrase-encoding.cjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8183-key-passphrase-encoding.cjs" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_pki.c b/packages/runtime/src/scr_pki.c index 908129243..9877ac6c9 100644 --- a/packages/runtime/src/scr_pki.c +++ b/packages/runtime/src/scr_pki.c @@ -1635,48 +1635,79 @@ static SpKey *sp_ed_from_der(const unsigned char *der, size_t len, bool private_ return k; } -/* RSASSA-PSS-params at *p (RFC 4055): true with the restrictions set on - * `k`, false when they are malformed or unsupported, which leaves the key - * without restrictions, as OpenSSL reads a negative or oversized salt. */ -static bool sp_pss_params_read(unsigned char **p, const unsigned char *end, SpKey *k) { +/* The name of a digest OID that RSASSA-PSS-params can hold and this + * runtime does not sign with, for its refusal. */ +static const char *sp_pss_other_digest(const mbedtls_asn1_buf *oid) { + /* 2.16.840.1.101.3.4.2.x, the NIST hash arc */ + static const unsigned char nist[] = {0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02}; + if (oid->len == sizeof nist + 1 && memcmp(oid->p, nist, sizeof nist) == 0) { + switch (oid->p[sizeof nist]) { + case 0x05: return "sha512-224"; + case 0x06: return "sha512-256"; + case 0x07: return "sha3-224"; + case 0x08: return "sha3-256"; + case 0x09: return "sha3-384"; + case 0x0a: return "sha3-512"; + } + } + mbedtls_md_type_t md; + if (mbedtls_oid_get_md_alg(oid, &md) == 0) { + if (md == MBEDTLS_MD_MD5) return "md5"; + if (md == MBEDTLS_MD_RIPEMD160) return "ripemd160"; + } + return "this digest"; +} + +/* RSASSA-PSS-params at *p (RFC 4055): 1 with the restrictions set on `k`; + * 0 when they are malformed, which leaves the key without restrictions, as + * OpenSSL reads a negative or oversized salt; -1 with *digest named when a + * hash or MGF1 digest is one this runtime does not sign with, so that the + * key is refused rather than imported without the restrictions it carries. */ +static int sp_pss_params_read(unsigned char **p, const unsigned char *end, SpKey *k, const char **digest) { size_t n; - if (mbedtls_asn1_get_tag(p, end, &n, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) return false; + if (mbedtls_asn1_get_tag(p, end, &n, MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE) != 0) return 0; const unsigned char *params_end = *p + n; mbedtls_md_type_t md = MBEDTLS_MD_SHA1, mgf1 = MBEDTLS_MD_SHA1; int salt = 20; if (*p < params_end && **p == (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0)) { mbedtls_asn1_buf oid, params; if (mbedtls_asn1_get_tag(p, params_end, &n, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 0) != 0 || - mbedtls_asn1_get_alg(p, *p + n, &oid, ¶ms) != 0 || mbedtls_oid_get_md_alg(&oid, &md) != 0 || - !sp_pss_md_name(md)) - return false; + mbedtls_asn1_get_alg(p, *p + n, &oid, ¶ms) != 0) + return 0; + if (mbedtls_oid_get_md_alg(&oid, &md) != 0 || !sp_pss_md_name(md)) { + *digest = sp_pss_other_digest(&oid); + return -1; + } } if (*p < params_end && **p == (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1)) { mbedtls_asn1_buf oid, params; if (mbedtls_asn1_get_tag(p, params_end, &n, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 1) != 0 || mbedtls_asn1_get_alg(p, *p + n, &oid, ¶ms) != 0 || oid.len != MBEDTLS_OID_SIZE(MBEDTLS_OID_MGF1) || memcmp(oid.p, MBEDTLS_OID_MGF1, oid.len) != 0) - return false; + return 0; /* MGF1's parameters are the hash's AlgorithmIdentifier, whose * content starts with the hash's OID. */ - if (params.tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) return false; + if (params.tag != (MBEDTLS_ASN1_CONSTRUCTED | MBEDTLS_ASN1_SEQUENCE)) return 0; unsigned char *alg = params.p; mbedtls_asn1_buf hash_oid = {.tag = MBEDTLS_ASN1_OID}; - if (mbedtls_asn1_get_tag(&alg, params.p + params.len, &hash_oid.len, MBEDTLS_ASN1_OID) != 0) return false; + if (mbedtls_asn1_get_tag(&alg, params.p + params.len, &hash_oid.len, MBEDTLS_ASN1_OID) != 0) return 0; hash_oid.p = alg; - if (mbedtls_oid_get_md_alg(&hash_oid, &mgf1) != 0 || !sp_pss_md_name(mgf1)) return false; + if (mbedtls_oid_get_md_alg(&hash_oid, &mgf1) != 0 || !sp_pss_md_name(mgf1)) { + *digest = sp_pss_other_digest(&hash_oid); + return -1; + } } if (*p < params_end && **p == (MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 2)) { if (mbedtls_asn1_get_tag(p, params_end, &n, MBEDTLS_ASN1_CONTEXT_SPECIFIC | MBEDTLS_ASN1_CONSTRUCTED | 2) != 0 || mbedtls_asn1_get_int(p, *p + n, &salt) != 0 || salt < 0) - return false; + return 0; } *p = (unsigned char *)params_end; k->pss_params = true; k->pss_md = md; k->pss_mgf1 = mgf1; k->pss_salt = salt; - return true; + return 1; } /* An RSA-PSS key from PKCS#8 or SubjectPublicKeyInfo DER whose algorithm @@ -1706,7 +1737,19 @@ static SpKey *sp_pss_from_der(const unsigned char *der, size_t len, bool private p += oid_len; SpKey *k = sp_key_alloc(pkcs8); k->rsa_pss = true; - if (p < alg_end && !sp_pss_params_read(&p, alg_end, k)) k->pss_params = false; + const char *digest = NULL; + if (p < alg_end) { + int read = sp_pss_params_read(&p, alg_end, k, &digest); + if (read < 0) { + sp_key_release(k); + *failed = true; + char what[96]; + snprintf(what, sizeof what, "RSA-PSS keys restricted to %s", digest); + sp_not_supported(what); + return NULL; + } + if (read == 0) k->pss_params = false; + } p = (unsigned char *)alg_end; int r; if (pkcs8) { @@ -1967,7 +2010,8 @@ static ScrDyn *sp_create_key(ScrDyn *input, bool private_key) { } ScrBytes *pass = NULL; if (passphrase && !sp_absent(passphrase)) { - pass = sp_source_bytes(passphrase, NULL); + /* Node decodes a string passphrase with the key's encoding. */ + pass = sp_source_bytes(passphrase, encoding); if (!pass) { scr_bytes_release(bytes); return NULL; @@ -2292,7 +2336,7 @@ static ScrDyn *sp_export_plain(SpKey *k, const ScrDyn *options) { /* OpenSSL's error, raised once the key is encoded. */ } else if (ci) { const unsigned char *start = der + SP_DER_MAX - n; - ScrBytes *pass = sp_source_bytes(passphrase, NULL); + ScrBytes *pass = sp_source_bytes(passphrase, sp_opt(options, "encoding")); const unsigned char *pass_data = pass ? pass->data : (const unsigned char *)""; size_t pass_len = pass ? (size_t)scr_bytes_byte_len(pass) : 0; if (pkcs8) { diff --git a/tests/corpus/8183-key-passphrase-encoding.cjs b/tests/corpus/8183-key-passphrase-encoding.cjs new file mode 100644 index 000000000..e52fa6c1c --- /dev/null +++ b/tests/corpus/8183-key-passphrase-encoding.cjs @@ -0,0 +1,28 @@ +// A string passphrase is decoded with the key's encoding, as in Node: +// createPrivateKey's { encoding } and the encoding option of an encrypted +// export both apply to it. +const c = require("node:crypto"); + +const { privateKey } = c.generateKeyPairSync("ec", { namedCurve: "P-256" }); +const pass = "pässwörd"; +const hex = Buffer.from(pass).toString("hex"); +const pem = privateKey.export({ format: "pem", type: "pkcs8", cipher: "aes-256-cbc", passphrase: hex, encoding: "hex" }); +const der = privateKey.export({ format: "der", type: "pkcs8", cipher: "aes-128-cbc", passphrase: pass }); + +function attempt(label, options) { + try { + const key = c.createPrivateKey(options); + console.log(label, key.asymmetricKeyType, key.equals(privateKey)); + } catch (e) { + console.log(label, "throws", e.code); + } +} + +attempt("utf8 passphrase", { key: pem, passphrase: pass }); +attempt("hex passphrase, encoding hex", { key: Buffer.from(pem), passphrase: hex, encoding: "hex" }); +attempt("base64 passphrase, encoding base64", { key: Buffer.from(pem), passphrase: Buffer.from(pass).toString("base64"), encoding: "base64" }); +attempt("latin1 passphrase, encoding latin1", { key: Buffer.from(pem), passphrase: Buffer.from(pass).toString("latin1"), encoding: "latin1" }); +attempt("hex passphrase, no encoding", { key: pem, passphrase: hex }); +attempt("Buffer passphrase, encoding hex", { key: Buffer.from(pem), passphrase: Buffer.from(pass), encoding: "hex" }); +attempt("der, hex passphrase, encoding hex", { key: der, format: "der", type: "pkcs8", passphrase: hex, encoding: "hex" }); +attempt("hex key string, encoding hex", { key: Buffer.from(pem).toString("hex"), passphrase: hex, encoding: "hex" }); diff --git a/tests/harness/corpus-costs/8183-key-passphrase-encoding.cjs.json b/tests/harness/corpus-costs/8183-key-passphrase-encoding.cjs.json new file mode 100644 index 000000000..0d507484f --- /dev/null +++ b/tests/harness/corpus-costs/8183-key-passphrase-encoding.cjs.json @@ -0,0 +1 @@ +{ "plain": 3665, "san": 67315 } diff --git a/tests/harness/errors.test.ts b/tests/harness/errors.test.ts index c8849a10f..663806942 100644 --- a/tests/harness/errors.test.ts +++ b/tests/harness/errors.test.ts @@ -870,6 +870,38 @@ console.log(\`\${register(7)}\`); }); }); +// An RSA-PSS key whose parameters restrict it to a digest the runtime does +// not sign with (sha512-224 and sha512-256, which OpenSSL reads) throws a +// coded SC2020 error naming the digest, instead of importing the key +// without the restrictions it carries. +describe("RSA-PSS keys restricted to unimplemented digests", () => { + test("importing one throws SC2020 naming the digest", async () => { + const r = await compileAndRun( + "pss-restricted-digest", + `import { createPublicKey } from "node:crypto"; +const keys = [ + "-----BEGIN PUBLIC KEY-----\\nMIGQMEEGCSqGSIb3DQEBCjA0oA8wDQYJYIZIAWUDBAIFBQChHDAaBgkqhkiG9w0B\\nAQgwDQYJYIZIAWUDBAIFBQCiAwIBCANLADBIAkEArMDQESqjeWDLqFa1E5SzsMl4\\n6tyUsEqcDKSwRUvPilv1AUudf/w6qaXlPnAxBmFjZYihdQSZlk0czRLOX3o7gwID\\nAQAB\\n-----END PUBLIC KEY-----\\n", + "-----BEGIN PUBLIC KEY-----\\nMIGQMEEGCSqGSIb3DQEBCjA0oA8wDQYJYIZIAWUDBAIBBQChHDAaBgkqhkiG9w0B\\nAQgwDQYJYIZIAWUDBAIGBQCiAwIBCANLADBIAkEAuOa9NkzXzMDelHCIEkf0mnKe\\nnQdalNUm9vZtIMwpDJcn5U0Vbhhd6MTfRPhSo5nW71Oh5eU7v5M3PMYOHS7cMQID\\nAQAB\\n-----END PUBLIC KEY-----\\n", +]; +for (const key of keys) { + try { + console.log(createPublicKey(key).asymmetricKeyType); + } catch (error) { + const e = error as Error & { code?: string }; + console.log(e.name, e.code, e.message); + } +} +`, + ); + expect(r.exitCode).toBe(0); + expect(r.stdout).toBe( + "Error SC2020 'RSA-PSS keys restricted to sha512-224' is part of the standard library types but has no scriptc lowering yet\n" + + "Error SC2020 'RSA-PSS keys restricted to sha512-256' is part of the standard library types but has no scriptc lowering yet\n", + ); + expect(r.stderr).toBe(""); + }); +}); + // A cipher name Node lists in crypto.getCiphers() but the runtime does not // implement throws a coded SC2020 error naming the cipher when the name is // computed; literal names are refused at compile time (node-types-fenced). From 6e4bfb3c913bf82bd9119243495f9074bced4ea0 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 17:34:40 -0500 Subject: [PATCH 168/259] Await the final value of an untyped sync pipeline source for await over a sync iterator awaits the value of the result that ends it too, so a sync iterator that returns a rejected promise rejects the pump. The source's generator skipped that value and reported success. It now awaits a final value that is an object (a promise included) before it stops, without closing the finished iterator. --- .../src/frontend/lowering/lower-stream.ts | 80 +++++++++++-------- .../7504-pipeline-untyped-source-errors.mjs | 24 +++++- 2 files changed, 70 insertions(+), 34 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/lower-stream.ts b/packages/compiler/src/frontend/lowering/lower-stream.ts index b519ce378..d3883427a 100644 --- a/packages/compiler/src/frontend/lowering/lower-stream.ts +++ b/packages/compiler/src/frontend/lowering/lower-stream.ts @@ -3954,6 +3954,38 @@ function lowerDynIterableSource( const sync = (): IrExpr => varRef(syncId, BOOL, loc); const step = (): IrExpr => varRef(stepId, DYN, loc); const value = (): IrExpr => varRef(valueId, DYN, loc); + // for await over a sync iterator awaits each value, the final one + // included (CreateAsyncFromSyncIterator): an object (a promise or a + // thenable) passes on its result + const awaitsValue = (): IrExpr => ({ + kind: "logical", + op: "&&", + left: sync(), + right: { + kind: "logical", + op: "||", + left: { kind: "dynTest", test: "promise", value: value(), type: BOOL, loc }, + right: { + kind: "logical", + op: "&&", + left: { + kind: "dynTest", + test: "nullish", + negated: true, + value: value(), + type: BOOL, + loc, + }, + right: { kind: "dynTest", test: "object", value: value(), type: BOOL, loc }, + type: BOOL, + loc, + }, + type: BOOL, + loc, + }, + type: BOOL, + loc, + }); const get = (obj: IrExpr, name: string): IrExpr => ({ kind: "dynKeyGet", value: obj, @@ -4053,46 +4085,28 @@ function lowerDynIterableSource( type: BOOL, loc, }, - then: [{ kind: "break", loc }], + // the final value is awaited too: a rejection rejects the + // pump, and the finished iterator is not closed + then: [ + { kind: "assign", localId: valueId, value: get(step(), "value"), loc }, + { + kind: "if", + cond: awaitsValue(), + then: [{ kind: "exprStmt", expr: awaitDyn(value()), loc }], + else_: null, + loc, + }, + { kind: "break", loc }, + ], else_: null, loc, }, setActive(true), { kind: "assign", localId: valueId, value: get(step(), "value"), loc }, - // for await over a sync iterator awaits each value - // (CreateAsyncFromSyncIterator): a promise or a thenable - // passes on its result, and a rejection closes the iterator + // a rejection here closes the iterator { kind: "if", - cond: { - kind: "logical", - op: "&&", - left: sync(), - right: { - kind: "logical", - op: "||", - left: { kind: "dynTest", test: "promise", value: value(), type: BOOL, loc }, - right: { - kind: "logical", - op: "&&", - left: { - kind: "dynTest", - test: "nullish", - negated: true, - value: value(), - type: BOOL, - loc, - }, - right: { kind: "dynTest", test: "object", value: value(), type: BOOL, loc }, - type: BOOL, - loc, - }, - type: BOOL, - loc, - }, - type: BOOL, - loc, - }, + cond: awaitsValue(), then: [{ kind: "assign", localId: valueId, value: awaitDyn(value()), loc }], else_: null, loc, diff --git a/tests/corpus/7504-pipeline-untyped-source-errors.mjs b/tests/corpus/7504-pipeline-untyped-source-errors.mjs index 3ee984547..5d6faded1 100644 --- a/tests/corpus/7504-pipeline-untyped-source-errors.mjs +++ b/tests/corpus/7504-pipeline-untyped-source-errors.mjs @@ -1,7 +1,7 @@ // pipeline() over untyped iterable sources: a destination that fails closes // the source, backpressure waits for drain, an abort signal stops the pump, // async generator and Map sources reach object-mode destinations, and a -// sync source's promise values are awaited. +// sync source's promise values, its final value included, are awaited. import { pipeline, Writable, PassThrough } from "node:stream"; import { pipeline as pipelineP } from "node:stream/promises"; @@ -113,3 +113,25 @@ try { } catch (err) { console.log("promised rejected", err.message); } + +// a sync source's final value is awaited too: a rejected one rejects the +// pipeline, and a resolved one is not written +function* finalRejects() { + yield "f1"; + return Promise.reject(new Error("final value rejected")); +} +function* finalResolves() { + yield "r1"; + return Promise.resolve("not written"); +} +for (const [label, source] of [["finalRejects", finalRejects], ["finalResolves", finalResolves]]) { + try { + await pipelineP( + pick(source()), + new Writable({ objectMode: true, write(c, _e, cb) { console.log(label, "write", c); cb(); } }), + ); + console.log(label, "resolved"); + } catch (err) { + console.log(label, "rejected", err.message); + } +} From 43ff8a11222f131b8eaed0bcb40e1e945f49982f Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 17:35:25 -0500 Subject: [PATCH 169/259] Inline destructured literal results and read ASCII slice ranges inline - A function whose whole body is `return [a, b]` or `return { a, b }`, with number, boolean or string fields, is now inlined where its result is only destructured (`const [head, tail] = split(text, at)`). The parameters are declared from the arguments, then each field straight into its destructured binding, in the literal's order; an unread field still evaluates into a binding of its own. No record is built, and a slice field read only through its length or char codes becomes a scalar slice that copies nothing. Arguments may own their value, but as for numeric records nothing inside an argument may hold a temporary of its own. - A scalar slice of a proven-ASCII string computes its range inline: the bounds clamp over the byte length exactly as scr_str_slice_range does, and no boundary can split a surrogate pair. Other strings keep the runtime call, which gains the same ASCII fast path. - value-records' tuples section, `[head, tail] = split(...)` read only through lengths, goes from two heap slices per step to none. --- packages/compiler/src/backend/llvm/emitter.ts | 28 +- .../src/backend/llvm/stack-objects.test.ts | 5 +- .../src/backend/llvm/string-slices.ts | 100 +++++- .../compiler/src/ir/scalar-records.test.ts | 160 ++++++++- packages/compiler/src/ir/scalar-records.ts | 321 ++++++++++++++++++ .../corpus/8241-literal-result-slices.ts.json | 6 + packages/runtime/src/scr_string.c | 11 + tests/corpus/8241-literal-result-slices.ts | 81 +++++ .../8241-literal-result-slices.ts.json | 1 + 9 files changed, 696 insertions(+), 17 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8241-literal-result-slices.ts.json create mode 100644 tests/corpus/8241-literal-result-slices.ts create mode 100644 tests/harness/corpus-costs/8241-literal-result-slices.ts.json diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 0243763f1..7c4a8aed1 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -68,7 +68,7 @@ import { type StoredSplitSnapshot, type StringSplit, } from "./split-loops.js"; -import { scalarizeNumericRecords } from "../../ir/scalar-records.js"; +import { scalarizeLiteralResults, scalarizeNumericRecords } from "../../ir/scalar-records.js"; import { addRecordResultEntries, resultEntryName } from "./record-results.js"; import { specializeCallbackCalls } from "../../ir/callback-specialization.js"; import { @@ -578,27 +578,29 @@ function moduleEmitter(input: IrModule, options: LlvmTargetOptions): LlEmitter { ? selectInt32Arrays( versionParameters( addRecordResultEntries( - scalarizeNumericRecords( - specializeCallbackCalls( - specializeNumericCalls( - inlineExpressionFunctions( - foldConstantGlobals( - copyStableCaptures( - resolveSelfCaptures( - hoistFinalFieldReads( - freezeInitOnlyGlobals( - holdCharLocalsAsUnits( - dropUnwrittenPropertyBags(runPairedWhileLoopsAsFor(mod)), + scalarizeLiteralResults( + scalarizeNumericRecords( + specializeCallbackCalls( + specializeNumericCalls( + inlineExpressionFunctions( + foldConstantGlobals( + copyStableCaptures( + resolveSelfCaptures( + hoistFinalFieldReads( + freezeInitOnlyGlobals( + holdCharLocalsAsUnits( + dropUnwrittenPropertyBags(runPairedWhileLoopsAsFor(mod)), + ), ), ), ), ), ), ), + mangleFunction, ), mangleFunction, ), - mangleFunction, ), ), ), diff --git a/packages/compiler/src/backend/llvm/stack-objects.test.ts b/packages/compiler/src/backend/llvm/stack-objects.test.ts index a74878080..c4f2bedc4 100644 --- a/packages/compiler/src/backend/llvm/stack-objects.test.ts +++ b/packages/compiler/src/backend/llvm/stack-objects.test.ts @@ -286,8 +286,9 @@ function bump(s: State): State { return { ...s, count: s.count + 1 }; } export function tokens(n: number, w: string): number { const t = { kind: "id", text: w, pos: n }; const u = make("num", w, n); - const [q, r] = divmod(n, 7); - return t.pos + width(u) + width({ kind: w, text: w, pos: 0 }) + q + r; + // Read by index: a destructured literal result is inlined instead. + const qr = divmod(n, 7); + return t.pos + width(u) + width({ kind: w, text: w, pos: 0 }) + qr[0] + qr[1]; } export function states(n: number, w: string): number { let s: State = { name: w, count: 0 }; diff --git a/packages/compiler/src/backend/llvm/string-slices.ts b/packages/compiler/src/backend/llvm/string-slices.ts index d00c681d6..35abaec14 100644 --- a/packages/compiler/src/backend/llvm/string-slices.ts +++ b/packages/compiler/src/backend/llvm/string-slices.ts @@ -8,6 +8,7 @@ import { everyExprChild, everyStmtChild, everyStmtList } from "../../ir/traverse import { F64_INF, f64Lit, sizeToDouble } from "./common.js"; import type { CallLifetimes } from "./call-lifetimes.js"; import type { LlValue, LlvmEmitterContext } from "./expr-context.js"; +import { emitStringAsciiFlag, emitStringByteLength } from "./string-reads.js"; type Slice = IrExpr & { kind: "strIntrinsic" }; @@ -66,6 +67,58 @@ export function findScalarStringSlices( return slices; } +/** scr_slice_unit: a slice()/substring() bound `v` over `length` units. A + * non-negative bound clamps to the length; a negative one counts from the + * end for slice (truncated toward zero) and is 0 for substring, as is NaN. */ +function emitSliceUnit( + host: LlvmEmitterContext, + v: string, + length: string, + substring: boolean, +): string { + const B = host.B; + const size = host.sizeType; + const lengthNumber = B.tmp(), + nonNegative = B.tmp(), + past = B.tmp(), + whole = B.tmp(), + clamped = B.tmp(), + result = B.tmp(); + B.line(`${lengthNumber} = ${sizeToDouble(size)} ${size} ${length} to double`); + B.line(`${nonNegative} = fcmp oge double ${v}, 0.0`); + B.line(`${past} = fcmp oge double ${v}, ${lengthNumber}`); + // Frozen: the conversion is only used where the bound is in range. + const raw = B.tmp(); + B.line(`${raw} = fptosi double ${v} to i64`); + B.line(`${whole} = freeze i64 ${raw}`); + let unit = whole; + if (size !== "i64") { + unit = B.tmp(); + B.line(`${unit} = trunc i64 ${whole} to ${size}`); + } + B.line(`${clamped} = select i1 ${past}, ${size} ${length}, ${size} ${unit}`); + if (substring) { + B.line(`${result} = select i1 ${nonNegative}, ${size} ${clamped}, ${size} 0`); + return result; + } + // Negative: (-length, -1] counts back from the end; (-1, 0) truncates to + // 0, and at or below -length, and NaN, give 0. + const negLength = B.tmp(), + inside = B.tmp(), + zero = B.tmp(), + back = B.tmp(), + counted = B.tmp(), + negative = B.tmp(); + B.line(`${negLength} = fneg double ${lengthNumber}`); + B.line(`${inside} = fcmp ogt double ${v}, ${negLength}`); + B.line(`${zero} = icmp eq ${size} ${unit}, 0`); + B.line(`${back} = add ${size} ${length}, ${unit}`); + B.line(`${counted} = select i1 ${zero}, ${size} 0, ${size} ${back}`); + B.line(`${negative} = select i1 ${inside}, ${size} ${counted}, ${size} 0`); + B.line(`${result} = select i1 ${nonNegative}, ${size} ${clamped}, ${size} ${negative}`); + return result; +} + export interface StringSliceSnapshot { source: string; range: string; @@ -87,10 +140,55 @@ export function emitStringSliceSnapshot( `${range} = alloca { ${host.sizeType}, ${host.sizeType}, i32 }`, ); B.line(`store ptr ${source.name}, ptr ${sourceSlot}`); + const start = args[0]?.name ?? f64Lit(0), + end = args[1]?.name ?? F64_INF; + const substring = slice.method === "substring"; + // A proven-ASCII receiver's units are its bytes, so the range is the + // runtime's clamped bounds over its byte length, and no boundary splits a + // surrogate pair (scr_str_slice_range); other strings ask the runtime. + const ascii = B.newLabel("slice.range.ascii"), + runtime = B.newLabel("slice.range.runtime"), + done = B.newLabel("slice.range.done"); + B.condBr(emitStringAsciiFlag(host, source.name), ascii, runtime); + B.startBlock(ascii); + const size = host.sizeType; + const length = emitStringByteLength(host, source.name); + let from = emitSliceUnit(host, start, length, substring), + to = emitSliceUnit(host, end, length, substring); + if (substring) { + const swap = B.tmp(), + low = B.tmp(), + high = B.tmp(); + B.line(`${swap} = icmp ugt ${size} ${from}, ${to}`); + B.line(`${low} = select i1 ${swap}, ${size} ${to}, ${size} ${from}`); + B.line(`${high} = select i1 ${swap}, ${size} ${from}, ${size} ${to}`); + from = low; + to = high; + } + const nonEmpty = B.tmp(), + difference = B.tmp(), + units = B.tmp(), + startPtr = B.tmp(), + lengthPtr = B.tmp(), + splitPtr = B.tmp(); + B.line(`${nonEmpty} = icmp ugt ${size} ${to}, ${from}`); + B.line(`${difference} = sub ${size} ${to}, ${from}`); + B.line(`${units} = select i1 ${nonEmpty}, ${size} ${difference}, ${size} 0`); + const rangeType = `{ ${size}, ${size}, i32 }`; + B.line(`${startPtr} = getelementptr inbounds ${rangeType}, ptr ${range}, i32 0, i32 0`); + B.line(`store ${size} ${from}, ptr ${startPtr}`); + B.line(`${lengthPtr} = getelementptr inbounds ${rangeType}, ptr ${range}, i32 0, i32 1`); + B.line(`store ${size} ${units}, ptr ${lengthPtr}`); + B.line(`${splitPtr} = getelementptr inbounds ${rangeType}, ptr ${range}, i32 0, i32 2`); + B.line(`store i32 0, ptr ${splitPtr}`); + B.br(done); + B.startBlock(runtime); host.declare("declare void @scr_str_slice_range(ptr, double, double, i1 zeroext, ptr)"); B.line( - `call void @scr_str_slice_range(ptr ${source.name}, double ${args[0]?.name ?? f64Lit(0)}, double ${args[1]?.name ?? F64_INF}, i1 ${slice.method === "substring" ? "true" : "false"}, ptr ${range})`, + `call void @scr_str_slice_range(ptr ${source.name}, double ${start}, double ${end}, i1 ${substring ? "true" : "false"}, ptr ${range})`, ); + B.br(done); + B.startBlock(done); host.toFrame(source); return { source: sourceSlot, range }; } diff --git a/packages/compiler/src/ir/scalar-records.test.ts b/packages/compiler/src/ir/scalar-records.test.ts index e3132088d..7b355ee26 100644 --- a/packages/compiler/src/ir/scalar-records.test.ts +++ b/packages/compiler/src/ir/scalar-records.test.ts @@ -10,7 +10,7 @@ import { type IrStmt, type IrType, } from "./ir.js"; -import { scalarizeNumericRecords } from "./scalar-records.js"; +import { scalarizeLiteralResults, scalarizeNumericRecords } from "./scalar-records.js"; import { validateModule } from "./validate.js"; const loc = { file: "scalar-records.ts", start: 0, end: 0 }; @@ -284,3 +284,161 @@ test("bounds expansion in callers with many eligible calls", () => { expect(remaining).toBeGreaterThan(0); expect(remaining).toBeLessThan(300); }); + +const tuple: IrType = { kind: "record", shapeId: "t0" }; +const strRef = (localId: string): IrExpr => ref(localId, STRING); +const element = (localId: string, field: string, type: IrType): IrStmt => ({ + kind: "varDecl", + localId, + init: { kind: "recordGet", obj: ref("result", tuple), shapeId: "t0", field, type, loc }, + loc, +}); + +/** `split(text, at)` returning `[text.slice(0, at), text.slice(at), at > 0]`, + * and a `main` destructuring it. */ +function literalFixture(after: IrStmt[]): IrModule { + const slice = (args: IrExpr[]): IrExpr => ({ + kind: "strIntrinsic", + method: "slice", + receiver: strRef("text"), + args, + type: STRING, + loc, + }); + return { + irVersion: 17, + sourceFile: loc.file, + entry: "main", + records: [ + { + id: "t0", + fields: [ + { name: "0", type: STRING }, + { name: "1", type: STRING }, + { name: "2", type: BOOL }, + ], + tuple: true, + }, + ], + functions: [ + { + name: "split", + params: [ + { localId: "text", name: "text", type: STRING }, + { localId: "at", name: "at", type: F64 }, + ], + returnType: tuple, + locals: [ + { id: "text", name: "text", type: STRING, mutable: false }, + { id: "at", name: "at", type: F64, mutable: false }, + ], + body: [ + { + kind: "return", + value: { + kind: "recordLit", + type: tuple, + fields: [ + { name: "0", value: slice([num(0), ref("at")]) }, + { name: "1", value: slice([ref("at")]) }, + { + name: "2", + value: { kind: "bin", op: ">", left: ref("at"), right: num(0), type: BOOL, loc }, + }, + ], + loc, + }, + loc, + }, + ], + loc, + }, + { + name: "main", + params: [{ localId: "source", name: "source", type: STRING }], + returnType: VOID, + locals: [ + { id: "source", name: "source", type: STRING, mutable: false }, + { id: "result", name: "result", type: tuple, mutable: false }, + { id: "head", name: "head", type: STRING, mutable: false }, + { id: "tail", name: "tail", type: STRING, mutable: true }, + ], + body: [ + { + kind: "varDecl", + localId: "result", + init: call("split", [strRef("source"), call("effect", [num(1)])], tuple), + loc, + }, + ...after, + ], + loc, + }, + { + name: "effect", + params: [{ localId: "x", name: "x", type: F64 }], + returnType: F64, + locals: [{ id: "x", name: "x", type: F64, mutable: true }], + body: [{ kind: "return", value: ref("x"), loc }], + loc, + }, + ], + }; +} + +function literalTransformed(mod: IrModule): IrModule { + expect(validateModule(mod)).toEqual([]); + const out = scalarizeLiteralResults(mod); + expect(validateModule(out)).toEqual([]); + return out; +} + +test("declares destructured elements from a literal producer's fields in evaluation order", () => { + const mod = literalFixture([element("head", "0", STRING), element("tail", "1", STRING)]); + const snapshot = structuredClone(mod); + const out = literalTransformed(mod); + expect(mod).toEqual(snapshot); + const caller = main(out); + expect(nodes(caller.body, "recordGet")).toEqual([]); + expect(nodes(caller.body, "call").map((c) => c["callee"])).toEqual(["effect"]); + const declared = caller.body.map((s) => (s.kind === "varDecl" ? s.localId : s.kind)); + // Parameters, then every field in the literal's order: the unread third + // field still evaluates, into a binding of its own. + expect(declared.slice(2)).toEqual(["head", "tail", declared[4]]); + expect(caller.locals.find((l) => l.id === declared[4])?.type).toEqual(BOOL); + expect(caller.locals.some((l) => l.id === "result")).toBe(false); + // Slices stay slices of the renamed parameter. + expect(nodes(caller.body, "strIntrinsic").map((n) => (n["receiver"] as IrExpr).kind)).toEqual([ + "varRef", + "varRef", + ]); +}); + +test("keeps the call when the result is read other than by adjacent element declarations", () => { + const escaped = literalFixture([ + element("head", "0", STRING), + { kind: "exprStmt", expr: ref("result", tuple), loc }, + ]); + expect(literalTransformed(escaped)).toBe(escaped); + const apart = literalFixture([ + element("head", "0", STRING), + { kind: "exprStmt", expr: num(0), loc }, + element("tail", "1", STRING), + ]); + expect(literalTransformed(apart)).toBe(apart); +}); + +test("keeps the call when an argument holds a counted temporary of its own", () => { + const mod = literalFixture([element("head", "0", STRING)]); + const decl = main(mod).body[0] as IrStmt & { kind: "varDecl" }; + const length: IrExpr = { + kind: "strIntrinsic", + method: "length", + receiver: { kind: "strLit", value: "abc", type: STRING, loc }, + args: [], + type: F64, + loc, + }; + (decl.init as IrExpr & { kind: "call" }).args[1] = length; + expect(literalTransformed(mod)).toBe(mod); +}); diff --git a/packages/compiler/src/ir/scalar-records.ts b/packages/compiler/src/ir/scalar-records.ts index 0a5b0c80f..f75e522bf 100644 --- a/packages/compiler/src/ir/scalar-records.ts +++ b/packages/compiler/src/ir/scalar-records.ts @@ -10,6 +10,7 @@ import { } from "./ir.js"; import { everyExpr, + transformExpr, everyExprChild, everyStmtChild, everyStmtList, @@ -362,3 +363,323 @@ export function scalarizeNumericRecords(mod: IrModule): IrModule { }); return changed ? { ...mod, functions } : mod; } + +/** A producer whose whole body is `return `, with number, boolean + * or string fields, inlined where its result is destructured. */ +interface LiteralProducer { + fn: IrFunction; + shape: IrRecordShape; + literal: IrExpr & { kind: "recordLit" }; + size: number; +} + +/** Whether `value` holds no counted temporary of its own: every counted + * node in it only views a binding, so evaluating it in its own statement + * shortens no lifetime. A message argument of a throw counts as nothing: it + * lives until the throw, which ends the evaluation anyway. */ +function viewsOnly(value: IrExpr): boolean { + if (!isRefCounted(value.type)) return everyExprChild(value, viewsOnly, () => false); + switch (value.kind) { + case "varRef": + return true; + case "unionNarrow": + return viewsOnly(value.value); + case "ternary": + return viewsOnly(value.cond) && viewsOnly(value.then) && viewsOnly(value.else_); + case "libCall": + return value.fn === "error.nodeThrow"; + default: + return false; + } +} + +/** The node's own value may be counted (it moves into the binding that + * takes it); everything under it must hold no temporary (viewsOnly), as + * scalarTemporaries requires for the numeric pass. */ +function ownedTemporaries(value: IrExpr): boolean { + return everyExprChild(value, viewsOnly, () => false); +} + +const LITERAL_FIELD_KINDS: ReadonlySet = new Set(["f64", "bool", "string"]); + +function literalProducer( + fn: IrFunction, + shapes: ReadonlyMap, +): LiteralProducer | null { + if ( + fn.async || + fn.generator || + fn.captures?.length || + fn.classCaptures?.length || + fn.returnType.kind !== "record" || + fn.body.length !== 1 + ) + return null; + const shape = shapes.get(fn.returnType.shapeId); + if ( + !shape || + shape.indexValue || + shape.fields.length === 0 || + shape.fields.length > MAX_FIELDS || + shape.fields.some((f) => !LITERAL_FIELD_KINDS.has(f.type.kind)) + ) + return null; + // Every local is a parameter: the body declares nothing. + const params = new Set(fn.params.map((p) => p.localId)); + if (fn.locals.some((l) => l.boxed || l.tdz || !params.has(l.id))) return null; + const ret = fn.body[0]!; + const literal = ret.kind === "return" ? ret.value : null; + if ( + literal?.kind !== "recordLit" || + literal.type.kind !== "record" || + literal.type.shapeId !== shape.id || + literal.fields.length !== shape.fields.length || + !literal.fields.every( + (f) => + !f.overflow && + shape.fields.some((sf) => sf.name === f.name && sf.type.kind === f.value.type.kind) && + ownedTemporaries(f.value), + ) + ) + return null; + let size = 0; + const small = everyExpr(literal, { + expr: (node) => + ++size <= MAX_CALLEE_NODES && + node.kind !== "closure" && + node.kind !== "selfRef" && + node.kind !== "awaitExpr" && + node.kind !== "awaitUnionExpr" && + node.kind !== "yieldExpr", + stmt: () => false, + }); + return small ? { fn, shape, literal, size } : null; +} + +/** Rewrite every statement list under `body`, innermost first. */ +function mapStatementLists(body: IrStmt[], f: (list: IrStmt[]) => IrStmt[]): IrStmt[] { + const lists = (s: IrStmt): IrStmt => { + switch (s.kind) { + case "if": + return { + ...s, + then: mapStatementLists(s.then, f), + else_: s.else_ === null ? null : mapStatementLists(s.else_, f), + }; + case "block": + case "while": + case "doWhile": + case "for": + case "forOf": + return { ...s, body: mapStatementLists(s.body, f) }; + case "switch": + return { + ...s, + cases: s.cases.map((c) => ({ + ...c, + body: mapStatementLists(c.body, f), + })), + }; + case "tryCatch": + return { + ...s, + tryBody: mapStatementLists(s.tryBody, f), + catchBody: s.catchBody === null ? null : mapStatementLists(s.catchBody, f), + finallyBody: s.finallyBody === null ? null : mapStatementLists(s.finallyBody, f), + }; + default: + return s; + } + }; + return f(body.map(lists)); +} + +/** How often each local is read, anywhere in `fn`. */ +function localReads(fn: IrFunction): Map { + const reads = new Map(); + const count = (id: string): void => { + reads.set(id, (reads.get(id) ?? 0) + 1); + }; + everyStmtList(fn.body, { + expr: (node) => { + switch (node.kind) { + case "varRef": + case "incDec": + case "assignExpr": + count(node.localId); + break; + case "closure": + case "classRef": + for (const id of node.captures ?? []) count(id); + break; + } + return true; + }, + stmt: (node) => { + if (node.kind === "assign" || node.kind === "forOf" || node.kind === "rethrow") + count(node.localId); + return true; + }, + }); + return reads; +} + +/** Inline small literal producers where the result is only destructured. + * + * `const [head, tail] = split(text, at)`, where `split` is + * `return [text.slice(0, at), text.slice(at)]`, lowers to a result binding + * and one declaration per element read from it, right after the call. Each + * such declaration now takes its field's value directly: the parameters are + * declared from the arguments in order, then the fields in the literal's + * order (unread fields go to fresh bindings), then the destructured + * bindings, so evaluation order is unchanged and no record is built. A + * slice element read only through its length then needs no copy at all + * (findScalarStringSlices). The declarations stay in the caller's own + * statement list, so every binding keeps its scope; parameters live to the + * end of it, which only lengthens the arguments' lifetimes. Every other use + * of the result binding keeps the call. */ +export function scalarizeLiteralResults(mod: IrModule): IrModule { + const shapes = new Map((mod.records ?? []).map((s) => [s.id, s])); + const producers = new Map(); + for (const fn of mod.functions) { + const p = literalProducer(fn, shapes); + if (p) producers.set(fn.name, p); + } + if (producers.size === 0) return mod; + let changed = false; + const functions = mod.functions.map((fn): IrFunction => { + if (fn.async || fn.generator) return fn; + const locals = new Map(fn.locals.map((l) => [l.id, l])); + const used = new Set([...locals.keys(), ...(mod.globals ?? []).map((g) => g.id)]); + collectLabels(fn.body, used); + let next = 0; + const fresh = (): string => { + let id: string; + do { + id = `%literal.${next++}`; + } while (used.has(id)); + used.add(id); + return id; + }; + let reads: Map | null = null; + const added: IrLocal[] = []; + const removed = new Set(); + let budget = MAX_INLINE_NODES; + const rewrite = (list: IrStmt[]): IrStmt[] => { + const out: IrStmt[] = []; + for (let i = 0; i < list.length; i++) { + const decl = list[i]!; + const call = decl.kind === "varDecl" ? decl.init : null; + const p = call?.kind === "call" ? producers.get(call.callee) : undefined; + const local = decl.kind === "varDecl" ? locals.get(decl.localId) : undefined; + if ( + decl.kind !== "varDecl" || + call?.kind !== "call" || + !p || + !local || + p.fn.name === fn.name || + p.size > budget || + local.mutable || + local.boxed || + local.tdz || + local.type.kind !== "record" || + local.type.shapeId !== p.shape.id || + call.args.length !== p.fn.params.length || + !call.args.every(ownedTemporaries) + ) { + out.push(decl); + continue; + } + // The element declarations right after the call, one per field. + const elements = new Map(); + let j = i + 1; + for (; j < list.length; j++) { + const element = list[j]!; + const get = element.kind === "varDecl" ? element.init : null; + const target = element.kind === "varDecl" ? locals.get(element.localId) : undefined; + if ( + element.kind !== "varDecl" || + get?.kind !== "recordGet" || + get.obj.kind !== "varRef" || + get.obj.localId !== local.id || + get.shapeId !== p.shape.id || + elements.has(get.field) || + !target || + target.boxed || + target.tdz || + target.type.kind !== get.type.kind + ) + break; + elements.set(get.field, element); + } + reads ??= localReads(fn); + if (elements.size === 0 || reads.get(local.id) !== elements.size) { + out.push(decl); + continue; + } + budget -= p.size; + changed = true; + removed.add(local.id); + const renamed = new Map(p.fn.params.map((param) => [param.localId, fresh()])); + for (const l of p.fn.locals) { + // Copied field by field: the native compiler does not spread a + // record whose type has a union. + const copy: IrLocal = { + id: renamed.get(l.id)!, + name: l.name, + type: l.type, + mutable: false, + }; + if (l.source !== undefined) copy.source = l.source; + added.push(copy); + } + p.fn.params.forEach((param, index) => { + out.push({ + kind: "varDecl", + localId: renamed.get(param.localId)!, + init: call.args[index]!, + loc: decl.loc, + }); + }); + const rename = (value: IrExpr): IrExpr => + transformExpr(value, { + expr: (node) => + node.kind === "varRef" && renamed.has(node.localId) + ? { ...node, localId: renamed.get(node.localId)! } + : node, + stmt: (node) => node, + }); + for (const field of p.literal.fields) { + const element = elements.get(field.name); + let id = element?.localId; + if (id === undefined) { + id = fresh(); + const type = p.shape.fields.find((f) => f.name === field.name)!.type; + added.push({ + id, + name: `${local.name}.${field.name}`, + type, + mutable: false, + }); + } + out.push({ + kind: "varDecl", + localId: id, + init: rename(field.value), + loc: element?.loc ?? decl.loc, + }); + } + i = j - 1; + } + return out; + }; + const body = mapStatementLists(fn.body, rewrite); + if (!changed || removed.size === 0) return fn; + return { + ...fn, + locals: [...fn.locals.filter((l) => !removed.has(l.id)), ...added], + body, + }; + }); + return changed ? { ...mod, functions } : mod; +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8241-literal-result-slices.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8241-literal-result-slices.ts.json new file mode 100644 index 000000000..9cd832dca --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8241-literal-result-slices.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8241-literal-result-slices.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_string.c b/packages/runtime/src/scr_string.c index 37b92e48c..2d7f46d85 100644 --- a/packages/runtime/src/scr_string.c +++ b/packages/runtime/src/scr_string.c @@ -2210,6 +2210,17 @@ static void scr_str_slice_bounds(ScrStr *s, ScrSidx *e, double start, double end void scr_str_slice_range(ScrStr *s, double start, double end, bool substring, ScrStringSlice *out) { + if (__builtin_expect(s->ascii, 1)) { + /* Units are bytes: no index entry, and no boundary splits a pair. */ + size_t length = s->len; + size_t from = scr_slice_unit(start, length, substring); + size_t to = scr_slice_unit(end, length, substring); + if (substring && from > to) { size_t swap = from; from = to; to = swap; } + out->start = from; + out->length = to > from ? to - from : 0; + out->split = 0; + return; + } ScrSidx *e = scr_sidx_for(s); size_t from, to; scr_str_slice_bounds(s, e, start, end, substring, &from, &to); diff --git a/tests/corpus/8241-literal-result-slices.ts b/tests/corpus/8241-literal-result-slices.ts new file mode 100644 index 000000000..11de82819 --- /dev/null +++ b/tests/corpus/8241-literal-result-slices.ts @@ -0,0 +1,81 @@ +// Destructured results of small literal producers: string slices, numbers +// and booleans, with evaluation order, unread fields, throws and every +// slice() and substring() bound kind. +let trace = ""; +function mark(tag: string, value: T): T { + trace += tag; + return value; +} + +function split(text: string, at: number): [string, string] { + return [text.slice(0, at), text.slice(at)]; +} +function cut(text: string, from: number, to: number): [string, number, boolean] { + return [text.substring(from, to), text.length, from > to]; +} +function divmod(a: number, b: number): [number, number] { + return [Math.floor(a / b), a % b]; +} +function pair(text: string): { head: string; size: number } { + return { size: mark("s", text.length), head: mark("h", text.slice(1, -1)) }; +} + +const bounds = [0, 1, 2, 3, -1, -2, -3, -10, 10, 0.5, -0.5, 1.9, -1.9, -0, NaN, Infinity, -Infinity]; +const texts = ["", "a", "ab", "abcdef", "héllo", "東京ok", "a\u{1F600}b"]; +let lengths = 0; +let units = 0; +for (const text of texts) { + for (const at of bounds) { + const [head, tail] = split(text, at); + lengths = lengths * 7 + head.length * 3 + tail.length; + lengths %= 1000000007; + if (head.length > 0) units += head.charCodeAt(head.length - 1); + if (tail.length > 0) units += tail.charCodeAt(0); + for (const to of bounds) { + const [part, size, swapped] = cut(text, at, to); + lengths = (lengths * 5 + part.length + size + (swapped ? 1 : 0)) % 1000000007; + } + } +} +console.log("lengths", lengths, "units", units); + +// The pieces themselves, as strings. +const [left, right] = split("scriptc", 3); +console.log(left, right, `${left}|${right}`); + +// Arguments, then fields in the literal's order, then the bindings. +trace = ""; +const { head, size } = pair(mark("a", "[inner]")); +console.log("order", trace, head.length, size); + +// Unread fields still run. +trace = ""; +const [onlyHead] = split(mark("x", "unread"), mark("y", 2)); +const { size: onlySize } = pair("<>"); +console.log("unread", trace, onlyHead, onlySize); + +// A mutable destructured binding. +let [first, rest] = split("mutable", 1); +first += "!"; +console.log("let", first, rest.length); + +// Numbers and a throw from an argument. +let sum = 0; +for (let i = 0; i < 50; i++) { + const [q, r] = divmod(i * 31, 17); + sum += q * 3 + r; +} +console.log("divmod", sum); +const list: (string | undefined)[] = ["xy", undefined]; +for (const item of list) { + try { + const [a, b] = split(item!, 1); + console.log("ok", a.length, b.length); + } catch (error) { + console.log("threw", error instanceof TypeError); + } +} + +// The producer keeps working for every other caller. +const whole = split("kept", 2); +console.log("kept", whole[0], whole[1], whole.length); diff --git a/tests/harness/corpus-costs/8241-literal-result-slices.ts.json b/tests/harness/corpus-costs/8241-literal-result-slices.ts.json new file mode 100644 index 000000000..be69de5f7 --- /dev/null +++ b/tests/harness/corpus-costs/8241-literal-result-slices.ts.json @@ -0,0 +1 @@ +{ "plain": 2200, "san": 2900 } From a711d74ecf3171189109b576fec9378bc5f49709 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 17:35:51 -0500 Subject: [PATCH 170/259] Keep copied array callbacks exact with local classes, switches and contracts - A binding that a local class captures counts as written: the class's methods may assign it while the loop runs, so the call keeps its helper. - Copied bodies rename the labels of switch and for-of statements and the binding of for-of loops. - The known-union and record-temporary cleanups rewrite switch cases and for-of bodies, where they left declarations of removed locals. - Copied locals keep their source bindings. In programs that write contract types, a parameter with a source binding keeps its own local, so an Int32 parameter is checked against the elements the loop passes. --- .../lowering/containers/array-pipelines.ts | 104 +++++++++++++++--- .../test/array-pipeline-fusion.test.ts | 59 ++++++++++ tests/diagnostics/contract-int32.ts | 4 +- .../__snapshots__/contract-int32.ts.txt | 13 ++- 4 files changed, 164 insertions(+), 16 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts b/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts index c83a9c447..7c2e07b1c 100644 --- a/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts +++ b/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts @@ -1,3 +1,5 @@ +import * as ts from "../../ts7/adapter.js"; +import { CONTRACT_TYPES_MODULE } from "../../contract-types.js"; import { keyedHelperName } from "../stable-names.js"; import { writtenLocals } from "../../../ir/callback-specialization.js"; import { AmbientReceiverReaders } from "../../../ir/receiver-readers.js"; @@ -6,6 +8,7 @@ import { BOOL, F64, VOID, + type IrBindingSource, type IrExpr, type IrFunction, type IrGlobal, @@ -667,6 +670,10 @@ class PipelineFusion { /** Bindings each function, or a closure it creates, writes after their * declaration. */ private readonly written: Map>; + /** classCaptured's answers by function name. */ + private readonly classCaptures = new Map>(); + /** Whether a module imports or re-exports the contract types. */ + private readonly contractTypes: boolean; /** Bindings of the function being fused that inlined callbacks captured. */ private inlinedCaptures = new Set(); /** The helper calls each callback with an undefined receiver; a copied @@ -680,6 +687,15 @@ class PipelineFusion { this.effects = new CallbackEffects(functions, lowerer.globalsList); this.written = writtenLocals({ functions }); this.receivers = new AmbientReceiverReaders(new Map(functions.map((fn) => [fn.name, fn]))); + this.contractTypes = lowerer.moduleOrder.some((sf) => + sf.statements.nodes.some( + (st) => + (ts.isImportDeclaration(st) || ts.isExportDeclaration(st)) && + st.moduleSpecifier !== undefined && + ts.isStringLiteral(st.moduleSpecifier) && + st.moduleSpecifier.text === CONTRACT_TYPES_MODULE, + ), + ); } run(fn: IrFunction): void { @@ -933,19 +949,22 @@ class PipelineFusion { /** inlineTarget for a callback created in `fn` whose captured bindings * nothing assigns after their declaration: `fn`'s own locals and * parameters, written neither by `fn` nor by any closure that shares - * them, and not by the callback body. The callback must not observe the - * ambient receiver (AmbientReceiverReaders). */ + * them, and not by the callback body. A binding a local class captures + * counts as written, since its methods may assign it. The callback must + * not observe the ambient receiver (AmbientReceiverReaders). */ private stableTarget(fn: IrFunction): InlineTarget { const locals = new Map(fn.locals.map((l) => [l.id, l])); const inherited = new Set((fn.captures ?? []).map((c) => c.localId)); const written = this.written.get(fn.name); + const classCaptured = this.classCaptured(fn); return (arg) => { const target = this.closureTarget(arg); if (!target || !written || arg.kind !== "closure") return null; if (!this.receivers.ignores(target)) return null; for (const id of arg.captures) { const local = locals.get(id); - if (!local || local.tdz || inherited.has(id) || written.has(id)) return null; + if (!local || local.tdz || inherited.has(id) || written.has(id) || classCaptured.has(id)) + return null; } const captures = new Set((target.captures ?? []).map((c) => c.localId)); const assigns = !everyStmtList(target.body, { @@ -957,6 +976,22 @@ class PipelineFusion { }; } + /** The bindings of `fn` that a local class it creates captures. */ + private classCaptured(fn: IrFunction): ReadonlySet { + const known = this.classCaptures.get(fn.name); + if (known) return known; + const ids = new Set(); + everyStmtList(fn.body, { + expr: (e) => { + if (e.kind === "classRef") for (const id of e.captures ?? []) ids.add(id); + return true; + }, + stmt: () => true, + }); + this.classCaptures.set(fn.name, ids); + return ids; + } + /** The function behind a closure-literal callback the loop can inline. */ private closureTarget(arg: IrExpr): IrFunction | null { if (arg.kind !== "closure" || arg.adapts) return null; @@ -967,7 +1002,12 @@ class PipelineFusion { } private emit(plan: Plan): IrExpr | null { - const built = new FusedLoop(this.lowerer, plan.chain, plan.inline ?? this.inlineTarget).build(); + const built = new FusedLoop( + this.lowerer, + plan.chain, + plan.inline ?? this.inlineTarget, + this.contractTypes, + ).build(); if (!built) return null; for (const id of built.inlinedCaptures) this.inlinedCaptures.add(id); let name = this.helpers.get(built.key); @@ -1153,10 +1193,13 @@ class FusedLoop { private next = 0; private failed = false; + /** `contractTypes`: the program writes contract types, which the + * contract checker binds to source bindings. */ constructor( private readonly lowerer: Lowerer, private readonly chain: Chain, private readonly inlineTarget: InlineTarget, + private readonly contractTypes: boolean, ) { this.loc = chain.loc; } @@ -1165,9 +1208,9 @@ class FusedLoop { return `${name}.${this.next++}`; } - private local(name: string, type: IrType, mutable = false): string { + private local(name: string, type: IrType, mutable = false, source?: IrBindingSource): string { const id = this.fresh(name); - this.locals.push({ id, name, type, mutable }); + this.locals.push(source ? { id, name, type, mutable, source } : { id, name, type, mutable }); return id; } @@ -1234,17 +1277,27 @@ class FusedLoop { return true; }, }); + // Copies keep their source bindings, so contract types written on + // them are checked against what the loop stores. In a program that + // writes contract types, a parameter with a source binding keeps its + // own local for the same reason. + const sources = new Map(fn.locals.map((l) => [l.id, l.source])); const aliased = new Set(); fn.params.forEach((p, index) => { const arg = args[index]!; - if (arg.kind === "varRef" && !assigned.has(p.localId) && typeEquals(arg.type, p.type)) { + if ( + arg.kind === "varRef" && + !assigned.has(p.localId) && + typeEquals(arg.type, p.type) && + !(this.contractTypes && sources.get(p.localId) !== undefined) + ) { renamed.set(p.localId, arg.localId); aliased.add(p.localId); } }); for (const l of fn.locals) { if (renamed.has(l.id)) continue; - const id = this.local(l.name, l.type, true); + const id = this.local(l.name, l.type, true, l.source); renamed.set(l.id, id); } const rename = (id: string): string => renamed.get(id) ?? id; @@ -1258,11 +1311,15 @@ class FusedLoop { return e; } }; - const bind: IrStmt[] = fn.params.flatMap((p, index): IrStmt[] => - aliased.has(p.localId) - ? [] - : [{ kind: "varDecl", localId: rename(p.localId), init: args[index]!, loc }], - ); + // A bound parameter's value is an element or index with no source text + // of its own; it is located at the parameter, without a span. + const bind: IrStmt[] = fn.params.flatMap((p, index): IrStmt[] => { + if (aliased.has(p.localId)) return []; + const source = sources.get(p.localId); + const arg = args[index]!; + const init = source ? { ...arg, loc: { ...source.loc, end: source.loc.start } } : arg; + return [{ kind: "varDecl", localId: rename(p.localId), init, loc }]; + }); const labels = new Map(); const label = (name: string): string => { let id = labels.get(name); @@ -1281,9 +1338,14 @@ class FusedLoop { case "break": case "continue": return st.label ? { ...st, label: label(st.label) } : st; + case "forOf": { + const renamedFor = { ...st, localId: rename(st.localId) }; + return st.labels ? { ...renamedFor, labels: st.labels.map(label) } : renamedFor; + } case "while": case "doWhile": case "for": + case "switch": case "block": return st.labels ? { ...st, labels: st.labels.map(label) } : st; default: @@ -1946,8 +2008,11 @@ function foldKnownUnions(fn: Omit): void { case "for": case "while": case "doWhile": + case "forOf": case "block": return { ...s, body: prune(s.body) }; + case "switch": + return { ...s, cases: s.cases.map((c) => ({ ...c, body: prune(c.body) })) }; default: return s; } @@ -2135,6 +2200,19 @@ function scalarizeRecordTemporaries(lowerer: Lowerer, fn: Omit ({ + test: c.test === null ? null : rewriteExpr(c.test), + body: rewriteList(c.body), + })), + }, + ]; case "block": return [{ ...s, body: rewriteList(s.body) }]; default: { diff --git a/packages/compiler/test/array-pipeline-fusion.test.ts b/packages/compiler/test/array-pipeline-fusion.test.ts index 0ff456a2c..ba814105f 100644 --- a/packages/compiler/test/array-pipeline-fusion.test.ts +++ b/packages/compiler/test/array-pipeline-fusion.test.ts @@ -154,3 +154,62 @@ console.log(a.length, b.length, limit); ${postlude}`); expect(helperCalls(init(mod))).toEqual(["%arr.filter", "%arr.map"]); }); + +test("a lone call keeps its helper when a local class's method can assign a capture", async () => { + const mod = await lowerSource(`${prelude} +let k = 1; +class Bump { + go(): void { k = 10; } +} +const b = new Bump(); +const out = rows.map((r) => { if (r.id === 2) b.go(); return r.id * k; }); +console.log(out.join(",")); +${postlude}`); + expect(helperCalls(init(mod))).toEqual(["%arr.map"]); +}); + +test("a copied callback keeps its switch and for-of labels and bindings", async () => { + const mod = await lowerSource(`${prelude} +const out = rows.map((r) => { + let n = 0; + outer: switch (r.id % 3) { + case 0: + n = 10; + break outer; + case 1: + inner: for (const v of [1, 2, 3]) { + n += v; + if (v === 2) break outer; + if (v === 3) continue inner; + } + break; + default: + n = r.value; + } + return n; +}); +console.log(out.join(",")); +${postlude}`); + expect(helperCalls(init(mod))).toEqual(["%arr.loop"]); +}); + +test("a copied callback's switch-local records and known unions are rewritten in its cases", async () => { + const mod = await lowerSource(`${prelude} +type Shape = { kind: "sq"; side: number } | { kind: "rect"; w: number; h: number }; +const out = rows.map((r) => { + switch (r.id % 3) { + case 0: + const p = { a: r.id, b: 2 }; + return p.a + p.b; + case 1: + const sq = { kind: "sq" as const, side: r.value }; + const s: Shape = sq; + return s.kind === "sq" ? s.side * 10 : 0; + default: + return r.value; + } +}); +console.log(out.join(",")); +${postlude}`); + expect(helperCalls(init(mod))).toEqual(["%arr.loop"]); +}); diff --git a/tests/diagnostics/contract-int32.ts b/tests/diagnostics/contract-int32.ts index f6e900626..20231c535 100644 --- a/tests/diagnostics/contract-int32.ts +++ b/tests/diagnostics/contract-int32.ts @@ -29,8 +29,10 @@ function bump(): void { const sizes = [1, 2, 3]; const len: Int32 = sizes.length; +const weights = [1.5, 2]; +const shifted = weights.map((w: Int32) => w + 1); const span = new Span(1.5); span.advance(); bump(); -console.log(width(span), half(7), count, len); +console.log(width(span), half(7), count, len, shifted); diff --git a/tests/harness/__snapshots__/contract-int32.ts.txt b/tests/harness/__snapshots__/contract-int32.ts.txt index 2f3a65c1d..90f046973 100644 --- a/tests/harness/__snapshots__/contract-int32.ts.txt +++ b/tests/harness/__snapshots__/contract-int32.ts.txt @@ -48,6 +48,15 @@ contract-int32.ts:31:20 - error SC7002: the value stored into 'len' (Int32) is n 30 | const sizes = [1, 2, 3]; 31 | const len: Int32 = sizes.length; | ^~~~~~~~~~~~ - 32 | + 32 | const weights = [1.5, 2]; - hint: make the int32 conversion explicit, for example 'sizes.length | 0', so Node computes the same value \ No newline at end of file + hint: make the int32 conversion explicit, for example 'sizes.length | 0', so Node computes the same value + +contract-int32.ts:33:30 - error SC7002: the value stored into 'w' (Int32) is not provably an int32 + + 32 | const weights = [1.5, 2]; + 33 | const shifted = weights.map((w: Int32) => w + 1); + | ^ + 34 | + + hint: make the int32 conversion explicit with '| 0', so Node computes the same value \ No newline at end of file From 01f5a3455a215634771f94ab4e813803013253f9 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 17:38:44 -0500 Subject: [PATCH 171/259] Test row-pair overlaps only for nests of two or more rows The paired copy's test read the stored and read arrays' headers whatever the row range, so a nest whose arrays the program assigns only for a nonempty range dereferenced their NULL headers on an empty range, where the loop as written never reads them. The overlap tests now run only when the nest has at least two rows, and an array that is not there answers that it is not disjoint, so the loop runs as written. --- .../compiler/src/backend/llvm/lib-dispatch.ts | 35 ++++++++++++++----- packages/compiler/src/ir/row-pairs.ts | 17 ++++++--- tests/corpus/8194-row-pair-sums.ts | 18 ++++++++++ 3 files changed, 58 insertions(+), 12 deletions(-) diff --git a/packages/compiler/src/backend/llvm/lib-dispatch.ts b/packages/compiler/src/backend/llvm/lib-dispatch.ts index f4ce9e405..95cee3860 100644 --- a/packages/compiler/src/backend/llvm/lib-dispatch.ts +++ b/packages/compiler/src/backend/llvm/lib-dispatch.ts @@ -937,10 +937,24 @@ export function emitLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlValue { } if (e.fn === "bytes.absent") return host.own({ name: "null", type: e.type }); if (e.fn === "bytes.disjoint") { - // [data, data + len * size) of each view, compared as addresses. + // [data, data + len * size) of each view, compared as addresses. A view + // that is not there (a binding the nest never assigned, NULL) answers + // false without reading its header, so the caller keeps its loop. const B = host.B; - const range = (arg: IrExpr): { start: string; end: string } => { - const value = host.emitReadReceiver(arg); + const values = e.args.map((arg) => ({ arg, value: host.emitReadReceiver(arg) })); + const present = values.map(({ value }) => { + const t = B.tmp(); + B.line(`${t} = icmp ne ptr ${value.name}, null`); + return t; + }); + const both = B.tmp(); + B.line(`${both} = and i1 ${present[0]}, ${present[1]}`); + const compare = B.newLabel("disjoint.compare"), + done = B.newLabel("disjoint.done"); + const from = B.currentLabel(); + B.condBr(both, compare, done); + B.startBlock(compare); + const range = (arg: IrExpr, pointer: string): { start: string; end: string } => { const size = arg.type.kind === "bytes" ? BYTES_ELEMENT_SIZE[arg.type.elem] : 1; const dataSlot = B.tmp(), data = B.tmp(), @@ -949,23 +963,28 @@ export function emitLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlValue { bytes = B.tmp(), start = B.tmp(), end = B.tmp(); - B.line(`${dataSlot} = getelementptr inbounds %ScrBytes, ptr ${value.name}, i64 0, i32 3`); + B.line(`${dataSlot} = getelementptr inbounds %ScrBytes, ptr ${pointer}, i64 0, i32 3`); B.line(`${data} = load ptr, ptr ${dataSlot}`); - B.line(`${lenSlot} = getelementptr inbounds %ScrBytes, ptr ${value.name}, i64 0, i32 1`); + B.line(`${lenSlot} = getelementptr inbounds %ScrBytes, ptr ${pointer}, i64 0, i32 1`); B.line(`${len} = load ${host.sizeType}, ptr ${lenSlot}`); B.line(`${bytes} = mul ${host.sizeType} ${len}, ${size}`); B.line(`${start} = ptrtoint ptr ${data} to ${host.sizeType}`); B.line(`${end} = add ${host.sizeType} ${start}, ${bytes}`); return { start, end }; }; - const left = range(e.args[0]!), - right = range(e.args[1]!); + const left = range(values[0]!.arg, values[0]!.value.name), + right = range(values[1]!.arg, values[1]!.value.name); const before = B.tmp(), after = B.tmp(), + apart = B.tmp(), t = B.tmp(); B.line(`${before} = icmp ule ${host.sizeType} ${left.end}, ${right.start}`); B.line(`${after} = icmp ule ${host.sizeType} ${right.end}, ${left.start}`); - B.line(`${t} = or i1 ${before}, ${after}`); + B.line(`${apart} = or i1 ${before}, ${after}`); + const compared = B.currentLabel(); + B.br(done); + B.startBlock(done); + B.line(`${t} = phi i1 [ false, %${from} ], [ ${apart}, %${compared} ]`); return { name: t, type: e.type }; } if (e.fn === "record.isFrozen") { diff --git a/packages/compiler/src/ir/row-pairs.ts b/packages/compiler/src/ir/row-pairs.ts index ed71166a8..2e189f42e 100644 --- a/packages/compiler/src/ir/row-pairs.ts +++ b/packages/compiler/src/ir/row-pairs.ts @@ -317,8 +317,10 @@ function pairRows( loc, }; // Both bounds are int32, so `row < end - 1` is `row + 1 < end`, and the - // start is at most the end. Rows are independent when the written array - // shares no byte with an array the term reads. + // nest has at least two rows. The overlap tests run only then, so they never + // read an array the program assigns only when there are rows. Rows are + // independent when the written array shares no byte with an array the + // term reads; an array that is not there answers false. const int32 = (e: IrExpr): IrExpr => ({ kind: "bin", op: "===", @@ -330,7 +332,14 @@ function pairRows( const tests: IrExpr[] = [ int32(match.start), int32(match.end), - { kind: "bin", op: "<=", left: again(match.start), right: again(match.end), type: BOOL, loc }, + { + kind: "bin", + op: "<", + left: bin("+", again(match.start), num(1), loc), + right: again(match.end), + type: BOOL, + loc, + }, ...match.reads.map((read): IrExpr => ({ kind: "libCall", fn: "bytes.disjoint", @@ -400,7 +409,7 @@ function pairRows( * expression of `row + 1`. The term only reads numbers, the counters and * typed-array elements, so it runs no other code and cannot throw. The * nest runs paired when both row bounds are int32 (so `row < end - 1` is - * `row + 1 < end`), the start is at most the end, and the array the rows + * `row + 1 < end`), there are at least two rows, and the array the rows * store into shares no byte with any array the term reads, so no row reads * another row's result. An odd row count runs its last row as written. * Otherwise the nest runs as written. Two independent sums take turns in diff --git a/tests/corpus/8194-row-pair-sums.ts b/tests/corpus/8194-row-pair-sums.ts index 9aa22b9bd..f28242ff5 100644 --- a/tests/corpus/8194-row-pair-sums.ts +++ b/tests/corpus/8194-row-pair-sums.ts @@ -70,3 +70,21 @@ weighted(f, w, out, 0, n); show("weighted", out); weighted(f, w, out, 1, n - 1); show("weighted inner", out); + +// Arrays a program assigns only when the row range is nonempty: an empty or +// one-row range never reads them, and the paired copy does not either. +function lazyRows(n: number, start: number, end: number): number { + let u!: Float64Array; + let v!: Float64Array; + if (end > start) { + u = new Float64Array(n).fill(1); + v = new Float64Array(end); + } + for (let i = start; i < end; i++) { + let t = 0; + for (let j = 0; j < n; j++) t += u[j]! / (i + j + 1); + v[i] = t; + } + return end > start ? v[end - 1]! : -1; +} +console.log("lazy", lazyRows(4, 3, 3), lazyRows(4, 2, 3), lazyRows(4, 0, 5), lazyRows(0, 5, 5)); From e25d871a3444c28124d9581768fba2b02040d5ba Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 17:45:59 -0500 Subject: [PATCH 172/259] Allocate stream ticks from the small-block allocator, and emit stream events by immortal names Each deferred stream step (afterWrite, emitReadable, resume and the others) queued a ScrStreamTick and a process.nextTick entry, both from libc calloc and free. They now come from the runtime's small-block allocator, as do the nextTick entries scheduled through scr_next_tick and scr_process_write_callback. The stream unit emitted each event with a newly allocated name string. The names it emits ("data", "end", "drain", "finish" and the others) are now immortal static strings, so an emit allocates no name. --- packages/runtime/src/scr_async.c | 12 +++---- packages/runtime/src/scr_stream.c | 54 +++++++++++++++++++++++++++---- 2 files changed, 54 insertions(+), 12 deletions(-) diff --git a/packages/runtime/src/scr_async.c b/packages/runtime/src/scr_async.c index 0ae774df7..f9c6944c2 100644 --- a/packages/runtime/src/scr_async.c +++ b/packages/runtime/src/scr_async.c @@ -1275,7 +1275,7 @@ static ScrClosure *scr_als_bind(ScrClosure *cb /*moves*/); /* A tick runs with the AsyncLocalStorage context active when it was * queued, as Node's process.nextTick does. */ void scr_next_tick(ScrClosure *cb /*moves*/) { - ScrNtick *t = calloc(1, sizeof *t); + ScrNtick *t = scr_mem_calloc(sizeof *t); if (!t) scr_oom(); t->cb = scr_als_bind(cb); if (scr_nt_tail) scr_nt_tail->next = t; @@ -1288,7 +1288,7 @@ void scr_next_tick(ScrClosure *cb /*moves*/) { * adapter ABI also used by fs.rename: emitted adapters construct the * program's Error | null union, and NULL selects its null arm. */ void scr_process_write_callback(ScrClosure *cb /*moves*/, ScrFsRenameFn fn) { - ScrNtick *t = calloc(1, sizeof *t); + ScrNtick *t = scr_mem_calloc(sizeof *t); if (!t) scr_oom(); t->cb = cb; t->error_cb = fn; @@ -1303,7 +1303,7 @@ void scr_process_write_callback(ScrClosure *cb /*moves*/, ScrFsRenameFn fn) { * endReadableNT, ...). The hook dispatches exactly one stream tick; * teardown just drops markers (the stream queue owns its entries). */ void scr_next_tick_raw(void (*fn)(void)) { - ScrNtick *t = calloc(1, sizeof *t); + ScrNtick *t = scr_mem_calloc(sizeof *t); if (!t) scr_oom(); t->raw = fn; if (scr_nt_tail) scr_nt_tail->next = t; @@ -1314,7 +1314,7 @@ void scr_next_tick_raw(void (*fn)(void)) { /* A raw tick at the front of the queue: it runs before the ticks already * queued. */ static void scr_next_tick_raw_first(void (*fn)(void)) { - ScrNtick *t = calloc(1, sizeof *t); + ScrNtick *t = scr_mem_calloc(sizeof *t); if (!t) scr_oom(); t->raw = fn; t->next = scr_nt_head; @@ -1327,7 +1327,7 @@ void scr_nticks_teardown(void) { ScrNtick *t = scr_nt_head; scr_nt_head = t->next; if (t->cb) scr_closure_release(t->cb); - free(t); + scr_mem_free(t); } scr_nt_tail = NULL; } @@ -4435,7 +4435,7 @@ static bool scr_loop_run_ticks(void) { ScrClosure *cb = t->cb; ScrFsRenameFn error_cb = t->error_cb; void (*raw)(void) = t->raw; - free(t); + scr_mem_free(t); if (cb) { if (error_cb) error_cb(cb, NULL); else ((void (*)(ScrClosure *))cb->fn)(cb); diff --git a/packages/runtime/src/scr_stream.c b/packages/runtime/src/scr_stream.c index 552fef146..406821961 100644 --- a/packages/runtime/src/scr_stream.c +++ b/packages/runtime/src/scr_stream.c @@ -557,7 +557,7 @@ static void scr_stream_dispatch_one(void); static void scr_st_tick(ScrStream *s, ScrStreamTickOp op, ScrError *err /*moves*/, ScrClosure *cb /*moves*/) { - ScrStreamTick *t = calloc(1, sizeof *t); + ScrStreamTick *t = scr_mem_calloc(sizeof *t); if (!t) scr_stream_oom(); t->s = scr_stream_retain(s); t->op = op; @@ -580,15 +580,57 @@ static bool scr_stream_ticks_pending(void) { return scr_st_head != NULL; } /* ── emit helpers ─────────────────────────────────────────────────────── */ +/* The event names the stream unit emits, as immortal strings (the layout + * of an emitted string literal), so an emit allocates no name. */ +#define SCR_STREAM_EVENT_NAME(name) \ + static const struct { \ + size_t rc; \ + size_t len; \ + size_t cap; \ + char data[sizeof #name]; \ + } scr_stream_lit_##name = {SIZE_MAX, sizeof #name - 1, \ + SCR_STR_CAP_WORD(sizeof #name - 1, 0, 1), #name} +SCR_STREAM_EVENT_NAME(data); +SCR_STREAM_EVENT_NAME(error); +SCR_STREAM_EVENT_NAME(close); +SCR_STREAM_EVENT_NAME(drain); +SCR_STREAM_EVENT_NAME(end); +SCR_STREAM_EVENT_NAME(finish); +SCR_STREAM_EVENT_NAME(pause); +SCR_STREAM_EVENT_NAME(prefinish); +SCR_STREAM_EVENT_NAME(readable); +SCR_STREAM_EVENT_NAME(resume); +SCR_STREAM_EVENT_NAME(pipe); +SCR_STREAM_EVENT_NAME(unpipe); +#undef SCR_STREAM_EVENT_NAME + +static ScrStr *const scr_stream_event_names[] = { + (ScrStr *)&scr_stream_lit_data, (ScrStr *)&scr_stream_lit_error, + (ScrStr *)&scr_stream_lit_close, (ScrStr *)&scr_stream_lit_drain, + (ScrStr *)&scr_stream_lit_end, (ScrStr *)&scr_stream_lit_finish, + (ScrStr *)&scr_stream_lit_pause, (ScrStr *)&scr_stream_lit_prefinish, + (ScrStr *)&scr_stream_lit_readable, (ScrStr *)&scr_stream_lit_resume, + (ScrStr *)&scr_stream_lit_pipe, (ScrStr *)&scr_stream_lit_unpipe, +}; + +/* The event name as a string: an immortal one for the names above, else a + * new string (+1 either way; releasing an immortal string does nothing). */ +static ScrStr *scr_stream_event_name(const char *name) { + for (size_t i = 0; i < sizeof scr_stream_event_names / sizeof *scr_stream_event_names; i++) { + if (strcmp(scr_stream_event_names[i]->data, name) == 0) return scr_stream_event_names[i]; + } + return scr_str_new(name, strlen(name)); +} + static bool scr_stream_emit0(ScrStream *s, const char *name) { - ScrStr *n = scr_str_new(name, strlen(name)); + ScrStr *n = scr_stream_event_name(name); bool had = scr_emitter_emit((ScrEmitter *)s, n); scr_str_release(n); return had; } static void scr_stream_emit_stream(ScrStream *s, const char *name, ScrStream *payload) { - ScrStr *n = scr_str_new(name, strlen(name)); + ScrStr *n = scr_stream_event_name(name); scr_emitter_emit((ScrEmitter *)s, n, payload); scr_str_release(n); } @@ -596,7 +638,7 @@ static void scr_stream_emit_stream(ScrStream *s, const char *name, ScrStream *pa /* 'error': unhandled throws the payload (Node's crash), via the emitter's * error contract. Borrows err. */ static void scr_stream_emit_error(ScrStream *s, ScrError *err) { - ScrStr *n = scr_str_new("error", 5); + ScrStr *n = (ScrStr *)&scr_stream_lit_error; scr_emitter_emit_error((ScrEmitter *)s, n, err); scr_str_release(n); } @@ -765,7 +807,7 @@ static void scr_stream_emit_data(ScrStream *s, void *chunk, ScrEntryKind kind) { } else { b = chunk; } - ScrStr *n = scr_str_new("data", 4); + ScrStr *n = (ScrStr *)&scr_stream_lit_data; scr_emitter_emit((ScrEmitter *)s, n, b, str, value); scr_str_release(n); if (scr_exc_pending()) return; @@ -7858,7 +7900,7 @@ static void scr_stream_tick_free(ScrStreamTick *t) { if (t->err) scr_error_release(t->err); if (t->cb) scr_closure_release(t->cb); scr_als_ctx_release(t->ctx); - free(t); + scr_mem_free(t); } /* One tick-marker's dispatch: the queue's FIFO head (markers and entries From c0a4496900d41522c1011d29999afa4cf86f9793 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 17:50:45 -0500 Subject: [PATCH 173/259] Check with a tsc-ts server shared by later builds (opt-in) With SCRIPTC_CHECKER_SERVER=1 on Linux and macOS, the native compiler's checker connections go to a shared `tsc-ts --api --listen` server, which keeps the files it parsed for the next build. When the variable is unset, nothing changes. checkerServerName names the server by a digest of the tsc-ts executable's identity, the working directory, the file system callbacks, the timing flag and the TSC_TS_* environment. scriptc_ts7_attach takes the server's lock file with a non-blocking flock, connects to its socket in this user's private server directory ($XDG_RUNTIME_DIR/scriptc or /tmp/scriptc-), and starts the server when none answers: in its own process group, with its standard streams on /dev/null and no other descriptor of the build, with --idle-exit 300 and TSC_TS_LISTEN_MEMORY=2048 unless the environment sets it. A build that finds the server in use, cannot start or reach it, or gets no answer to a ping checks with its own tsc-ts process, as without the variable; so does a tsc-ts without --listen, which exits as it starts. The syntax-only source parser, which reads no libraries, always uses its own process and leaves the server to the program's checker. --- docs/content/docs/cli.mdx | 3 + .../compiler/native/ts7-process-child.test.c | 52 ++++- packages/compiler/native/ts7-process.c | 190 +++++++++++++++++- packages/compiler/native/ts7-process.ffi.json | 1 + packages/compiler/native/ts7-process.h | 13 ++ packages/compiler/native/ts7-process.test.c | 88 ++++++++ packages/compiler/src/frontend/services.ts | 4 +- .../src/frontend/ts7/checker-server.test.ts | 47 +++++ .../src/frontend/ts7/checker-server.ts | 50 +++++ .../compiler/src/frontend/ts7/native-api.ts | 21 +- .../src/frontend/ts7/native-process.ts | 39 +++- .../compiler/src/frontend/ts7/program-host.ts | 3 + .../self-hosting/ts7-native-process.ts | 37 +++- .../harness/self-hosting-ts7-process.test.ts | 30 ++- 14 files changed, 569 insertions(+), 9 deletions(-) create mode 100644 packages/compiler/src/frontend/ts7/checker-server.test.ts create mode 100644 packages/compiler/src/frontend/ts7/checker-server.ts diff --git a/docs/content/docs/cli.mdx b/docs/content/docs/cli.mdx index 9fa5e9447..050d076e3 100644 --- a/docs/content/docs/cli.mdx +++ b/docs/content/docs/cli.mdx @@ -210,6 +210,9 @@ With `--sparse`, the profile leaves out the functions the runs never reached. Th

    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

    ```console diff --git a/packages/compiler/native/ts7-process-child.test.c b/packages/compiler/native/ts7-process-child.test.c index 7202cab51..386a0a7c3 100644 --- a/packages/compiler/native/ts7-process-child.test.c +++ b/packages/compiler/native/ts7-process-child.test.c @@ -12,7 +12,49 @@ #include #include #else +#include +#include +#include #include + +/* `--listen PATH --idle-exit SECONDS`: a stand-in for a shared server. In + * mode "listen-exit" it exits as an executable without --listen does. In + * mode "listen" it answers each client, in order, with its client number, + * its listen arguments and TSC_TS_LISTEN_MEMORY, then echoes until the + * client closes, and exits after SECONDS (at most 5) without a client. */ +static int listen_main(const char *mode, char **argv) { + if (strcmp(mode, "listen-exit") == 0) return 2; + if (strcmp(mode, "listen") != 0) return 73; + struct sockaddr_un address; + memset(&address, 0, sizeof(address)); + address.sun_family = AF_UNIX; + if (strlen(argv[0]) >= sizeof(address.sun_path)) return 77; + strcpy(address.sun_path, argv[0]); + int listener = socket(AF_UNIX, SOCK_STREAM, 0); + if (listener < 0 || bind(listener, (struct sockaddr *)&address, sizeof(address)) != 0 || + listen(listener, 4) != 0) + return 78; + const char *memory = getenv("TSC_TS_LISTEN_MEMORY"); + int idle = atoi(argv[2]); + if (idle > 5) idle = 5; + for (int client = 1;; client++) { + struct pollfd entry = {listener, POLLIN, 0}; + if (poll(&entry, 1, idle * 1000) <= 0) break; + int fd = accept(listener, NULL, NULL); + if (fd < 0) return 79; + char line[512]; + int size = snprintf(line, sizeof(line), "client %d\n%s %s\n%s\n", client, argv[0], argv[2], + memory == NULL ? "unset" : memory); + if (size <= 0 || write(fd, line, (size_t)size) != size) return 80; + uint8_t bytes[17]; + ssize_t count; + while ((count = read(fd, bytes, sizeof(bytes))) > 0) + if (write(fd, bytes, (size_t)count) != count) break; + close(fd); + } + unlink(argv[0]); + return 0; +} #endif static int child_main(int argc, char **argv) { @@ -20,9 +62,15 @@ static int child_main(int argc, char **argv) { _setmode(_fileno(stdin), _O_BINARY); _setmode(_fileno(stdout), _O_BINARY); #endif - if (argc < 5 || argc > 6 || strcmp(argv[1], "--api") != 0 || strcmp(argv[2], "--cwd") != 0 || - strncmp(argv[4], "--callbacks=", 12) != 0 || (argc == 6 && strcmp(argv[5], "--timing") != 0)) return 71; + int listening = argc >= 9 && strcmp(argv[5], "--listen") == 0 && strcmp(argv[7], "--idle-exit") == 0; + int fixed = listening ? 9 : 5; + if (argc < fixed || argc > fixed + 1 || strcmp(argv[1], "--api") != 0 || strcmp(argv[2], "--cwd") != 0 || + strncmp(argv[4], "--callbacks=", 12) != 0 || (argc == fixed + 1 && strcmp(argv[fixed], "--timing") != 0)) + return 71; const char *mode = argv[3]; +#ifndef _WIN32 + if (listening) return listen_main(mode, argv + 6); +#endif if (strncmp(mode, "argv:", 5) == 0) { fwrite(mode + 5, 1, strlen(mode + 5), stdout); fputc('\n', stdout); diff --git a/packages/compiler/native/ts7-process.c b/packages/compiler/native/ts7-process.c index ea451345d..dda3bac46 100644 --- a/packages/compiler/native/ts7-process.c +++ b/packages/compiler/native/ts7-process.c @@ -1,5 +1,8 @@ #ifndef _WIN32 #define _POSIX_C_SOURCE 200809L +/* flock(2), for the checker server's lock file, and syscall(2). */ +#define _DEFAULT_SOURCE +#define _DARWIN_C_SOURCE #endif #include "ts7-process.h" #include @@ -16,7 +19,13 @@ #include #include #include +#include #include +#include +#ifdef __linux__ +#include +#endif +#include #include #include #include @@ -38,6 +47,9 @@ typedef struct Ts7Process { HANDLE output; #else int socket; + /* The checker server's lock file, held while connected to the server + * (scriptc_ts7_attach); -1 for a server this process started. */ + int lock; #endif } Ts7Process; @@ -283,7 +295,7 @@ static int start_process(Ts7Process *p, char **args, size_t argc) { if (error == 0) error = posix_spawn(&pid, args[0], &actions, NULL, args, environment); posix_spawn_file_actions_destroy(&actions); if (error == 0) { - p->socket = sockets[0]; p->pid = (uint32_t)pid; + p->socket = sockets[0]; p->pid = (uint32_t)pid; p->lock = -1; } done: close(sockets[1]); @@ -293,6 +305,9 @@ done: static void stop_process(Ts7Process *p) { close(p->socket); + // A shared checker server keeps running; closing the connection ends this + // build's session, and closing the lock file lets another build connect. + if (p->lock >= 0) { close(p->lock); return; } int status; pid_t pid = (pid_t)p->pid; for (int attempt = 0; attempt < 5; attempt++) { @@ -338,6 +353,179 @@ uint32_t scriptc_ts7_open(const uint8_t *executable, size_t executable_size, return p->id; } +#ifdef _WIN32 +uint32_t scriptc_ts7_attach(const uint8_t *name, size_t name_size, + const uint8_t *executable, size_t executable_size, + const uint8_t *cwd, size_t cwd_size, + const uint8_t *callbacks, size_t callbacks_size, + uint8_t timing, uint32_t idle_exit, uint32_t memory) { + (void)name; (void)name_size; (void)executable; (void)executable_size; (void)cwd; (void)cwd_size; + (void)callbacks; (void)callbacks_size; (void)timing; (void)idle_exit; (void)memory; + error_text("a shared checker server needs Unix sockets"); + return 0; +} +#else +/* This user's checker server directory: $XDG_RUNTIME_DIR/scriptc, or + * /tmp/scriptc-. It must be a directory this user owns with no access + * for others; one that exists otherwise is not used. */ +static int server_directory(char *path, size_t size) { + const char *runtime = getenv("XDG_RUNTIME_DIR"); + int count = runtime != NULL && runtime[0] == '/' + ? snprintf(path, size, "%s/scriptc", runtime) + : snprintf(path, size, "/tmp/scriptc-%lu", (unsigned long)geteuid()); + if (count < 0 || (size_t)count >= size) { error_text("checker server directory path is too long"); return 0; } + if (mkdir(path, 0700) != 0 && errno != EEXIST) { system_error(errno); return 0; } + struct stat info; + if (lstat(path, &info) != 0) { system_error(errno); return 0; } + if (!S_ISDIR(info.st_mode) || info.st_uid != geteuid() || (info.st_mode & 077) != 0) { + error_text("checker server directory is not private to this user"); + return 0; + } + return 1; +} + +/* A connection to the server listening at `path`, or -1. */ +static int connect_server(const char *path) { + struct sockaddr_un address; + memset(&address, 0, sizeof(address)); + address.sun_family = AF_UNIX; + memcpy(address.sun_path, path, strlen(path) + 1); + int fd = socket(AF_UNIX, SOCK_STREAM, 0); + if (fd < 0) return -1; + if (fcntl(fd, F_SETFD, FD_CLOEXEC) < 0) { close(fd); return -1; } +#ifdef SO_NOSIGPIPE + int no_sigpipe = 1; + if (setsockopt(fd, SOL_SOCKET, SO_NOSIGPIPE, &no_sigpipe, sizeof(no_sigpipe)) != 0) { close(fd); return -1; } +#endif + int status; + do { status = connect(fd, (const struct sockaddr *)&address, sizeof(address)); } while (status != 0 && errno == EINTR); + if (status != 0) { close(fd); return -1; } + return fd; +} + +/* Starts the server in its own process group, so that a terminal's signals + * to the build do not reach it, with its standard streams on /dev/null and + * no other descriptor of this process, so that it holds no pipe a caller of + * the build waits on. `limit` (TSC_TS_LISTEN_MEMORY=...) is added to the + * environment unless it sets TSC_TS_LISTEN_MEMORY. */ +static pid_t start_server(char **args, char *limit) { +#ifdef __APPLE__ + char **inherited = *_NSGetEnviron(); +#else + char **inherited = environ; +#endif + size_t count = 0; + int has_limit = 0; + for (; inherited[count] != NULL; count++) + if (strncmp(inherited[count], "TSC_TS_LISTEN_MEMORY=", 21) == 0) has_limit = 1; + char **environment = malloc((count + 2) * sizeof(char *)); + if (environment == NULL) { error_text("out of memory"); return -1; } + memcpy(environment, inherited, count * sizeof(char *)); + environment[count] = has_limit ? NULL : limit; + environment[count + 1] = NULL; + long descriptors = sysconf(_SC_OPEN_MAX); + if (descriptors < 0 || descriptors > 65536) descriptors = 65536; + sigset_t signals; + sigemptyset(&signals); + pid_t pid = fork(); + if (pid == 0) { + // Only async-signal-safe calls until exec. + int null = open("/dev/null", O_RDWR); + if (setpgid(0, 0) != 0 || null < 0 || dup2(null, STDIN_FILENO) < 0 || dup2(null, STDOUT_FILENO) < 0 || + dup2(null, STDERR_FILENO) < 0) + _exit(127); +#if defined(__linux__) && defined(SYS_close_range) + if (syscall(SYS_close_range, 3U, ~0U, 0U) != 0) +#endif + for (long fd = 3; fd < descriptors; fd++) close((int)fd); + sigprocmask(SIG_SETMASK, &signals, NULL); + execve(args[0], args, environment); + _exit(127); + } + int error = errno; + free(environment); + if (pid < 0) { system_error(error); return -1; } + return pid; +} + +uint32_t scriptc_ts7_attach(const uint8_t *name, size_t name_size, + const uint8_t *executable, size_t executable_size, + const uint8_t *cwd, size_t cwd_size, + const uint8_t *callbacks, size_t callbacks_size, + uint8_t timing, uint32_t idle_exit, uint32_t memory) { + if (next_id == 0) { error_text("server handle IDs are exhausted"); return 0; } + char *server = copy_argument(name, name_size, ""); + if (server == NULL) return 0; + char directory[256], socket_path[sizeof(((struct sockaddr_un *)0)->sun_path)], lock_path[512]; + int named = strchr(server, '/') == NULL; + if (!named) error_text("checker server names cannot contain '/'"); + if (named) named = server_directory(directory, sizeof(directory)); + if (named) { + int count = snprintf(socket_path, sizeof(socket_path), "%s/%s.sock", directory, server); + named = count > 0 && (size_t)count < sizeof(socket_path); + if (!named) error_text("checker server socket path is too long"); + else (void)snprintf(lock_path, sizeof(lock_path), "%s.lock", socket_path); + } + free(server); + if (!named) return 0; + // One build at a time uses the server; a build that finds it in use + // starts its own server instead of waiting. + int lock = open(lock_path, O_RDWR | O_CREAT | O_CLOEXEC | O_NOFOLLOW, 0600); + if (lock < 0) { system_error(errno); return 0; } + if (flock(lock, LOCK_EX | LOCK_NB) != 0) { + if (errno == EWOULDBLOCK) error_text("the checker server is in use"); + else system_error(errno); + close(lock); + return 0; + } + int fd = connect_server(socket_path); + if (fd < 0) { + char *exe = copy_argument(executable, executable_size, ""); + char *dir = exe == NULL ? NULL : copy_argument(cwd, cwd_size, ""); + char *callback_flag = dir == NULL ? NULL : copy_argument(callbacks, callbacks_size, "--callbacks="); + char idle[16], limit[48]; + (void)snprintf(idle, sizeof(idle), "%lu", (unsigned long)idle_exit); + (void)snprintf(limit, sizeof(limit), "TSC_TS_LISTEN_MEMORY=%lu", (unsigned long)memory); + pid_t pid = -1; + if (callback_flag != NULL) { + char *args[] = {exe, "--api", "--cwd", dir, callback_flag, "--listen", socket_path, "--idle-exit", idle, + timing ? "--timing" : NULL, NULL}; + pid = start_server(args, limit); + } + free(exe); free(dir); free(callback_flag); + // The server listens as it starts. One that exits first, such as a + // tsc-ts without --listen, or one that is not listening within 2 s, + // leaves this build to start its own server. + for (int attempt = 0; pid > 0; attempt++) { + fd = connect_server(socket_path); + if (fd >= 0) break; + int status; + pid_t result; + do { result = waitpid(pid, &status, WNOHANG); } while (result < 0 && errno == EINTR); + if (result != 0) { error_text("the checker server exited as it started"); break; } + if (attempt == 1000) { error_text("the checker server did not start listening"); break; } + struct timespec delay = {0, 2000000}; + while (nanosleep(&delay, &delay) != 0 && errno == EINTR) {} + } + } + if (fd < 0) { close(lock); return 0; } + Ts7Process *p = calloc(1, sizeof(*p)); + if (p == NULL) { error_text("out of memory"); close(fd); close(lock); return 0; } + if (!exit_registered) { + if (atexit(scriptc_ts7_close_all) != 0) { + error_text("could not register server cleanup"); free(p); close(fd); close(lock); return 0; + } + exit_registered = 1; + } + p->socket = fd; + p->lock = lock; + p->id = next_id++; + p->next = processes; + processes = p; + return p->id; +} +#endif + uint32_t scriptc_ts7_pid(uint32_t handle) { Ts7Process *p = find_process(handle); return p != NULL ? p->pid : 0; diff --git a/packages/compiler/native/ts7-process.ffi.json b/packages/compiler/native/ts7-process.ffi.json index 86f3cb4d2..5e3bcbc5e 100644 --- a/packages/compiler/native/ts7-process.ffi.json +++ b/packages/compiler/native/ts7-process.ffi.json @@ -2,6 +2,7 @@ "ffi_format": 6, "functions": [ { "name": "ts7NativeOpen", "symbol": "scriptc_ts7_open", "params": ["string", "string", "string", "bool"], "returns": "u32" }, + { "name": "ts7NativeAttach", "symbol": "scriptc_ts7_attach", "params": ["string", "string", "string", "string", "bool", "u32", "u32"], "returns": "u32" }, { "name": "ts7NativeRead", "symbol": "scriptc_ts7_read", "params": ["u32", "mutable-bytes", "u32", "u32"], "returns": "i32" }, { "name": "ts7NativeWrite", "symbol": "scriptc_ts7_write", "params": ["u32", "bytes", "u32", "u32"], "returns": "i32" }, { "name": "ts7NativePid", "symbol": "scriptc_ts7_pid", "params": ["u32"], "returns": "u32" }, diff --git a/packages/compiler/native/ts7-process.h b/packages/compiler/native/ts7-process.h index 3d2a0ba05..cb5c72097 100644 --- a/packages/compiler/native/ts7-process.h +++ b/packages/compiler/native/ts7-process.h @@ -13,6 +13,19 @@ uint32_t scriptc_ts7_open(const uint8_t *executable, size_t executable_size, const uint8_t *cwd, size_t cwd_size, const uint8_t *callbacks, size_t callbacks_size, uint8_t timing); +/* Connects to the shared checker server `name` (`--api --listen`) in this + * user's private server directory, starting it in its own process group + * with `--idle-exit idle_exit` and a limit of `memory` megabytes + * (TSC_TS_LISTEN_MEMORY, unless the environment sets it) when none answers. Returns 0 with the error + * text when another build is connected to it, it cannot be started or + * reached, or the platform has no Unix sockets; the caller then starts its + * own server with scriptc_ts7_open. Closing the handle ends the connection + * and leaves the server running. */ +uint32_t scriptc_ts7_attach(const uint8_t *name, size_t name_size, + const uint8_t *executable, size_t executable_size, + const uint8_t *cwd, size_t cwd_size, + const uint8_t *callbacks, size_t callbacks_size, + uint8_t timing, uint32_t idle_exit, uint32_t memory); int32_t scriptc_ts7_read(uint32_t handle, uint8_t *bytes, size_t size, uint32_t offset, uint32_t length); int32_t scriptc_ts7_write(uint32_t handle, const uint8_t *bytes, size_t size, diff --git a/packages/compiler/native/ts7-process.test.c b/packages/compiler/native/ts7-process.test.c index e17c367c7..dc0c67ced 100644 --- a/packages/compiler/native/ts7-process.test.c +++ b/packages/compiler/native/ts7-process.test.c @@ -11,7 +11,9 @@ #include #else #include +#include #include +#include #include #include #endif @@ -171,6 +173,89 @@ static void failure_cases(void) { scriptc_ts7_close(UINT32_MAX); } +#ifndef _WIN32 +static uint32_t attach(const char *name, const char *mode, uint32_t memory) { + return scriptc_ts7_attach((const uint8_t *)name, strlen(name), (const uint8_t *)executable, strlen(executable), + (const uint8_t *)mode, strlen(mode), (const uint8_t *)callbacks, strlen(callbacks), + 0, 1, memory); +} + +static void expect_line(uint32_t id, const char *expected) { + char line[512]; + size_t at = 0; + do { + assert(at + 1 < sizeof(line)); + read_exact(id, (uint8_t *)line + at, 1); + } while (line[at++] != '\n'); + line[at] = '\0'; + assert(strcmp(line, expected) == 0); +} + +static void attach_cases(void) { + char runtime[] = "/tmp/scriptc-ts7-attach-XXXXXX"; + assert(mkdtemp(runtime) != NULL); + assert(setenv("XDG_RUNTIME_DIR", runtime, 1) == 0); + assert(unsetenv("TSC_TS_LISTEN_MEMORY") == 0); + char directory[256], socket_path[512], expected[600]; + uint8_t bytes[4]; + snprintf(directory, sizeof(directory), "%s/scriptc", runtime); + snprintf(socket_path, sizeof(socket_path), "%s/server.sock", directory); + // The first build starts the server with its idle time and memory limit. + // The server holds none of the build's descriptors, such as an output + // pipe its caller reads to the end. + int output[2]; + assert(pipe(output) == 0); + uint32_t first = attach("server", "listen", 123); + assert(first != 0 && scriptc_ts7_pid(first) == 0); + close(output[1]); + struct pollfd ended = {output[0], POLLIN, 0}; + assert(poll(&ended, 1, 5000) == 1); + assert(read(output[0], bytes, 1) == 0); + close(output[0]); + expect_line(first, "client 1\n"); + snprintf(expected, sizeof(expected), "%s 1\n", socket_path); + expect_line(first, expected); + expect_line(first, "123\n"); + write_exact(first, (const uint8_t *)"ping", 4, 0, 4); + read_exact(first, bytes, 4); + assert(memcmp(bytes, "ping", 4) == 0); + // A build that finds the server in use gets no handle. + for (int i = 0; i < 3; i++) { assert(attach("server", "listen", 123) == 0); fail_message(); } + scriptc_ts7_close(first); + scriptc_ts7_close(first); + // A later build connects to the same server. + uint32_t second = attach("server", "listen", 123); + assert(second != 0); + expect_line(second, "client 2\n"); + scriptc_ts7_close(second); + // An executable without --listen exits as it starts. + assert(attach("old", "listen-exit", 0) == 0); + fail_message(); + // A server directory others can access is not used. + assert(chmod(directory, 0755) == 0); + assert(attach("server", "listen", 123) == 0); + fail_message(); + assert(chmod(directory, 0700) == 0); + // A name that would leave the directory, or make the path too long. + assert(attach("../server", "listen", 123) == 0); + fail_message(); + char long_name[200]; + memset(long_name, 'x', sizeof(long_name) - 1); + long_name[sizeof(long_name) - 1] = '\0'; + assert(attach(long_name, "listen", 123) == 0); + fail_message(); + // The server exits after its idle second and removes its socket. + unlink(socket_path); + snprintf(expected, sizeof(expected), "%s.lock", socket_path); + unlink(expected); + snprintf(expected, sizeof(expected), "%s/old.sock.lock", directory); + unlink(expected); + rmdir(directory); + rmdir(runtime); + assert(unsetenv("XDG_RUNTIME_DIR") == 0); +} +#endif + static int process_main(int argc, char **argv) { assert(argc >= 2); executable = argv[1]; @@ -196,6 +281,9 @@ static int process_main(int argc, char **argv) { argument_cases(); exchange_cases(); failure_cases(); +#ifndef _WIN32 + attach_cases(); +#endif assert(resource_count() == before); #ifndef _WIN32 if (saved_input >= 0) { assert(dup2(saved_input, STDIN_FILENO) >= 0); close(saved_input); } diff --git a/packages/compiler/src/frontend/services.ts b/packages/compiler/src/frontend/services.ts index a0acb5818..182611526 100644 --- a/packages/compiler/src/frontend/services.ts +++ b/packages/compiler/src/frontend/services.ts @@ -61,7 +61,9 @@ export class FrontendServices { // Called as a plain function: the instance is not its receiver. const createApi = this.createApi; return (this.parser ??= new Ts7SourceParser( - (options) => createApi({ ...options, collectTiming: false }), + // The parser reads no libraries, so it gains nothing from the shared + // checker server, and leaves it to the program's checker. + (options) => createApi({ ...options, collectTiming: false, shared: false }), this.cwd, )); } diff --git a/packages/compiler/src/frontend/ts7/checker-server.test.ts b/packages/compiler/src/frontend/ts7/checker-server.test.ts new file mode 100644 index 000000000..9a0371fe6 --- /dev/null +++ b/packages/compiler/src/frontend/ts7/checker-server.test.ts @@ -0,0 +1,47 @@ +import { mkdtempSync, rmSync, utimesSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { afterAll, expect, test } from "vitest"; +import { checkerServerName } from "./checker-server.js"; + +const dir = mkdtempSync(join(tmpdir(), "scriptc-checker-server-")); +const executable = join(dir, "tsc-ts"); +writeFileSync(executable, "server"); +const enabled = { SCRIPTC_CHECKER_SERVER: "1" }; +const posix = process.platform === "linux" || process.platform === "darwin"; + +afterAll(() => rmSync(dir, { recursive: true, force: true })); + +test("builds use the shared checker server only when they opt in, on Linux and macOS, with tsc-ts", () => { + expect(checkerServerName(executable, dir, false, {})).toBeNull(); + expect(checkerServerName(executable, dir, false, { SCRIPTC_CHECKER_SERVER: "0" })).toBeNull(); + expect( + checkerServerName(executable, dir, false, { ...enabled, SCRIPTC_CHECKER: "tsgo" }), + ).toBeNull(); + const name = checkerServerName(executable, dir, false, enabled); + if (!posix) expect(name).toBeNull(); + else expect(name).toMatch(/^[0-9a-f]{32}$/); +}); + +test.skipIf(!posix)( + "the server's name changes with what its answers depend on, and with nothing else", + () => { + const name = checkerServerName(executable, dir, false, enabled); + expect( + checkerServerName(executable, dir, false, { ...enabled, SCRIPTC_CHECKER: "tsc-ts" }), + ).toBe(name); + expect(checkerServerName(executable, dir, false, { ...enabled, PATH: "/elsewhere" })).toBe( + name, + ); + const others = [ + checkerServerName(executable, join(dir, "other"), false, enabled), + checkerServerName(executable, dir, true, enabled), + checkerServerName(executable, dir, false, { ...enabled, TSC_TS_LIB_DIR: dir }), + checkerServerName(executable, dir, false, { ...enabled, TSC_TS_LISTEN_MEMORY: "512" }), + ]; + for (const other of others) expect(other).not.toBe(name); + // An updated tsc-ts executable gets its own server. + utimesSync(executable, new Date(0), new Date(0)); + expect(checkerServerName(executable, dir, false, enabled)).not.toBe(name); + }, +); diff --git a/packages/compiler/src/frontend/ts7/checker-server.ts b/packages/compiler/src/frontend/ts7/checker-server.ts new file mode 100644 index 000000000..6d80e2599 --- /dev/null +++ b/packages/compiler/src/frontend/ts7/checker-server.ts @@ -0,0 +1,50 @@ +import { createHash } from "node:crypto"; +import { checkerBackend } from "./checker-backend.js"; +import { checkerExecutableIdentity } from "./lib-diagnostics.js"; +import { TS7_FILE_SYSTEM_CALLBACKS } from "./rpc-filesystem.js"; + +/** How long a shared checker server waits for the next build before it + * exits, in seconds. */ +export const CHECKER_SERVER_IDLE_EXIT = 300; + +/** The resident memory, in megabytes, above which a shared checker server + * exits after a build. tsc-ts never frees a program's syntax trees, types and + * symbols, so its memory grows with each build it serves. */ +export const CHECKER_SERVER_MEMORY = 2048; + +/** + * With `SCRIPTC_CHECKER_SERVER=1` on Linux and macOS, the native compiler + * checks with a tsc-ts server shared by the builds that follow + * (`tsc-ts --api --listen`): a build connects to it, starting it when none + * answers, and the server keeps the files it parsed for the next build. + * Returns the server's name, a digest of everything a server's answers + * depend on besides the files it reads through the build: the tsc-ts + * executable, the working directory, the file system callbacks, timing, and + * the `TSC_TS_*` environment. Returns null when the shared server is not used. + */ +export function checkerServerName( + executable: string, + cwd: string, + timing: boolean, + env: NodeJS.ProcessEnv = process.env, +): string | null { + if (env["SCRIPTC_CHECKER_SERVER"] !== "1") return null; + if (process.platform !== "linux" && process.platform !== "darwin") return null; + if (checkerBackend(env) !== "tsc-ts") return null; + const tscTsEnv = Object.keys(env) + .filter((name) => name.startsWith("TSC_TS_")) + .sort() + .map((name) => [name, env[name] ?? ""]); + return createHash("sha256") + .update( + JSON.stringify([ + checkerExecutableIdentity(executable), + cwd, + TS7_FILE_SYSTEM_CALLBACKS, + timing, + tscTsEnv, + ]), + ) + .digest("hex") + .slice(0, 32); +} diff --git a/packages/compiler/src/frontend/ts7/native-api.ts b/packages/compiler/src/frontend/ts7/native-api.ts index 259529541..f8e10efc5 100644 --- a/packages/compiler/src/frontend/ts7/native-api.ts +++ b/packages/compiler/src/frontend/ts7/native-api.ts @@ -1,7 +1,9 @@ import { Ts7Api } from "./api.js"; -import { spawnNativeTs7Wire } from "./native-process.js"; +import { checkerServerName } from "./checker-server.js"; +import { attachNativeTs7Process, spawnNativeTs7Wire } from "./native-process.js"; import { Ts7RpcClient } from "./rpc-client.js"; import type { Ts7FileSystem } from "./rpc-filesystem.js"; +import { Ts7Wire } from "./rpc-wire.js"; /** The native driver supplies its installed TypeScript executable path. * Package discovery is separate from starting and owning a server. */ @@ -10,8 +12,25 @@ export function createNativeTs7Api(options: { cwd: string; fs: Ts7FileSystem; collectTiming?: boolean; + shared?: boolean; }): Ts7Api { const timing = options.collectTiming ?? false; + const server = + options.shared === false ? null : checkerServerName(options.executable, options.cwd, timing); + const shared = + server === null + ? null + : attachNativeTs7Process(server, options.executable, options.cwd, timing); + if (shared !== null) { + const rpc = new Ts7RpcClient(new Ts7Wire(shared)); + try { + // A server that ended the connection leaves this build to start its own. + rpc.requestText("ping", "null"); + return new Ts7Api(rpc, options.fs, timing); + } catch { + rpc.close(); + } + } return new Ts7Api( new Ts7RpcClient(spawnNativeTs7Wire(options.executable, options.cwd, timing)), options.fs, diff --git a/packages/compiler/src/frontend/ts7/native-process.ts b/packages/compiler/src/frontend/ts7/native-process.ts index 7bb523d74..aa38cf4b4 100644 --- a/packages/compiler/src/frontend/ts7/native-process.ts +++ b/packages/compiler/src/frontend/ts7/native-process.ts @@ -1,5 +1,6 @@ import { Ts7Wire, type Ts7WireIo } from "./rpc-wire.js"; import { TS7_FILE_SYSTEM_CALLBACKS } from "./rpc-filesystem.js"; +import { CHECKER_SERVER_IDLE_EXIT, CHECKER_SERVER_MEMORY } from "./checker-server.js"; // Bound by native/ts7-process.ffi.json. This module is a native entry point; // the Node host continues to use rpc-process.ts's public spawn boundary. @@ -9,6 +10,15 @@ declare function ts7NativeOpen( callbacks: string, timing: boolean, ): number; +declare function ts7NativeAttach( + name: string, + executable: string, + cwd: string, + callbacks: string, + timing: boolean, + idleExit: number, + memory: number, +): number; declare function ts7NativeRead( handle: number, bytes: Uint8Array, @@ -47,8 +57,12 @@ export class NativeTs7Process implements Ts7WireIo { private handle: number; readonly pid: number; - constructor(executable: string, cwd: string, collectTiming = false) { - this.handle = ts7NativeOpen(executable, cwd, TS7_FILE_SYSTEM_CALLBACKS, collectTiming); + /** With `handle`, a connection to a shared checker server (attachNativeTs7Process). */ + constructor(executable: string, cwd: string, collectTiming = false, handle = 0) { + this.handle = + handle !== 0 + ? handle + : ts7NativeOpen(executable, cwd, TS7_FILE_SYSTEM_CALLBACKS, collectTiming); if (this.handle === 0) throw nativeError("startup"); this.pid = ts7NativePid(this.handle); } @@ -97,6 +111,27 @@ export class NativeTs7Process implements Ts7WireIo { }; } +/** A connection to the shared checker server `name`, started when none + * answers (`checkerServerName`), or null when this build cannot use it, such + * as while another build is connected to it. */ +export function attachNativeTs7Process( + name: string, + executable: string, + cwd: string, + collectTiming = false, +): NativeTs7Process | null { + const handle = ts7NativeAttach( + name, + executable, + cwd, + TS7_FILE_SYSTEM_CALLBACKS, + collectTiming, + CHECKER_SERVER_IDLE_EXIT, + CHECKER_SERVER_MEMORY, + ); + return handle === 0 ? null : new NativeTs7Process(executable, cwd, collectTiming, handle); +} + export function spawnNativeTs7Wire( executable: string, cwd: string, diff --git a/packages/compiler/src/frontend/ts7/program-host.ts b/packages/compiler/src/frontend/ts7/program-host.ts index ec143e401..e66d598d9 100644 --- a/packages/compiler/src/frontend/ts7/program-host.ts +++ b/packages/compiler/src/frontend/ts7/program-host.ts @@ -122,6 +122,9 @@ export interface Ts7ApiOptions { cwd: string; fs: Ts7FileSystem; collectTiming: boolean; + /** False for a connection that should not use the shared checker server + * (`SCRIPTC_CHECKER_SERVER`), such as the syntax-only source parser's. */ + shared?: boolean; } export type Ts7ApiFactory = (options: Ts7ApiOptions) => Ts7Api; diff --git a/tests/fixtures/self-hosting/ts7-native-process.ts b/tests/fixtures/self-hosting/ts7-native-process.ts index 2fdbb9e79..3b04a784c 100644 --- a/tests/fixtures/self-hosting/ts7-native-process.ts +++ b/tests/fixtures/self-hosting/ts7-native-process.ts @@ -1,6 +1,9 @@ import { writeFileSync } from "node:fs"; import { join } from "node:path"; -import { NativeTs7Process } from "../../../packages/compiler/src/frontend/ts7/native-process.js"; +import { + attachNativeTs7Process, + NativeTs7Process, +} from "../../../packages/compiler/src/frontend/ts7/native-process.js"; import { createNativeTs7Api } from "../../../packages/compiler/src/frontend/ts7/native-api.js"; import { Ts7RpcClient } from "../../../packages/compiler/src/frontend/ts7/rpc-client.js"; import { Ts7Wire } from "../../../packages/compiler/src/frontend/ts7/rpc-wire.js"; @@ -95,12 +98,44 @@ function checkTransport(executable: string): void { console.log("native transport passed"); } +function readLine(connection: NativeTs7Process): string { + const byte = new Uint8Array(1); + let line = ""; + for (;;) { + check(connection.read(byte, 0, 1) === 1, "shared server line"); + if (byte[0] === 10) return line; + line += String.fromCharCode(byte[0]!); + } +} + +// The stand-in server (ts7-process-child.test.c, mode "listen") answers each +// client with its number, its socket and idle time, and its memory limit. +function checkShared(executable: string): void { + const first = attachNativeTs7Process("server", executable, "listen"); + check(first !== null, "shared server started"); + check(readLine(first!) === "client 1", "first client"); + check(readLine(first!).endsWith("/scriptc/server.sock 300"), "listen arguments"); + check(readLine(first!) === "2048", "memory limit"); + check(attachNativeTs7Process("server", executable, "listen") === null, "shared server in use"); + first!.close(); + first!.close(); + const second = attachNativeTs7Process("server", executable, "listen"); + check(second !== null && readLine(second) === "client 2", "shared server reused"); + second!.close(); + check(attachNativeTs7Process("old", executable, "listen-exit") === null, "server without --listen"); + console.log("native shared server passed"); +} + const executable = process.argv[2]!; const directory = process.argv[3]!; const report = process.argv[4]!; const mode = process.argv[5] ?? "client"; if (mode === "transport") { checkTransport(executable); +} else if (mode === "shared") { + checkShared(executable); +} else if (mode === "api") { + checkApi(executable, directory); } else if (mode === "exit" || mode === "normal-exit") { const child = new NativeTs7Process(executable, "stall"); const byte = new Uint8Array(1); diff --git a/tests/harness/self-hosting-ts7-process.test.ts b/tests/harness/self-hosting-ts7-process.test.ts index d49a5c092..150a8860d 100644 --- a/tests/harness/self-hosting-ts7-process.test.ts +++ b/tests/harness/self-hosting-ts7-process.test.ts @@ -1,5 +1,5 @@ import { execFileSync, spawnSync } from "node:child_process"; -import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { mkdirSync, mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { analyze, compile } from "@scriptc/compiler"; @@ -72,6 +72,20 @@ for (const backend of ["llvm"] as const) { expect(transport.status, transport.stderr).toBe(0); expect(transport.stdout).toBe("native transport passed\n"); expect(transport.stderr).toBe(""); + if (process.platform !== "win32") { + // A shared server in a private server directory, which the stand-in + // leaves after its idle time. + const runtime = join(dir, "run"); + mkdirSync(runtime, { mode: 0o700 }); + const shared = spawnSync(built.binaryPath, [child, dir, "unused", "shared"], { + encoding: "utf8", + timeout: 15_000, + env: { ...process.env, XDG_RUNTIME_DIR: runtime, TSC_TS_LISTEN_MEMORY: undefined }, + }); + expect(shared.status, shared.stderr).toBe(0); + expect(shared.stdout).toBe("native shared server passed\n"); + expect(shared.stderr).toBe(""); + } for (const mode of ["normal-exit", "exit"]) { const pidFile = join(dir, mode + ".pid"); const run = spawnSync(built.binaryPath, [child, dir, pidFile, mode], { @@ -94,6 +108,20 @@ for (const backend of ["llvm"] as const) { dir, join(dir, "oracle.json"), ); + if (process.platform !== "win32") { + // With the shared server requested, a checker without --listen exits + // as it starts and the build checks with its own process. + const runtime = join(dir, "api-run"); + mkdirSync(runtime, { mode: 0o700 }); + const api = spawnSync(built.binaryPath, [tsgoExecutable(), dir, "unused", "api"], { + encoding: "utf8", + timeout: 45_000, + env: { ...process.env, XDG_RUNTIME_DIR: runtime, SCRIPTC_CHECKER_SERVER: "1" }, + }); + expect(api.status, api.stderr).toBe(0); + expect(api.stdout).toBe(""); + expect(api.stderr).toBe(""); + } const report = join(dir, "native.json"); // Only ordinary stdio is inherited. The native executable starts the // actual tsgo process; the test runner never creates its RPC pipes. As in From 05bc5299b0846c4c4d6c0296498cff45696fb3e3 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 17:54:15 -0500 Subject: [PATCH 174/259] Reap the checker process within a millisecond of closing it Closing a checker process checked for its exit once and then slept 10 ms before checking again, although the process exits a fraction of a millisecond after its input closes. The checks now start 0.1 ms apart and double, so the process is reaped as soon as it exits. The total wait before the kill stays at about 50 ms (51.1 ms). --- packages/compiler/native/ts7-process.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/packages/compiler/native/ts7-process.c b/packages/compiler/native/ts7-process.c index ea451345d..b2b7c5062 100644 --- a/packages/compiler/native/ts7-process.c +++ b/packages/compiler/native/ts7-process.c @@ -295,13 +295,16 @@ static void stop_process(Ts7Process *p) { close(p->socket); int status; pid_t pid = (pid_t)p->pid; - for (int attempt = 0; attempt < 5; attempt++) { + // A server exits within a fraction of a millisecond of reading EOF, so the + // checks start 0.1 ms apart and double: 51.1 ms in all before the kill. + for (int attempt = 0; attempt < 10; attempt++) { pid_t result; do { result = waitpid(pid, &status, WNOHANG); } while (result < 0 && errno == EINTR); // ECHILD also means the PID no longer belongs to us. Never signal a // potentially recycled PID after somebody else has reaped the child. if (result == pid || (result < 0 && errno == ECHILD)) return; - struct timespec delay = {0, 10000000}; + if (attempt == 9) break; + struct timespec delay = {0, 100000L << attempt}; while (nanosleep(&delay, &delay) != 0 && errno == EINTR) {} } (void)kill(pid, SIGKILL); From fcc81c034cbef0e3fbcea1835a131d43359e8692 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 17:59:56 -0500 Subject: [PATCH 175/259] Read the final result's value only for sync pipeline sources for await reads the value of a done result only through the async-from-sync wrapper; an async iterator's done result is not read. The source's generator read it for both, so an async iterator whose done result has a throwing value getter rejected the pipeline. It now reads and awaits the final value only when the iterator is sync. --- .../src/frontend/lowering/lower-stream.ts | 19 ++++++++--- .../7504-pipeline-untyped-source-errors.mjs | 34 +++++++++++++++++++ 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/lower-stream.ts b/packages/compiler/src/frontend/lowering/lower-stream.ts index d3883427a..d67cf257e 100644 --- a/packages/compiler/src/frontend/lowering/lower-stream.ts +++ b/packages/compiler/src/frontend/lowering/lower-stream.ts @@ -4085,14 +4085,23 @@ function lowerDynIterableSource( type: BOOL, loc, }, - // the final value is awaited too: a rejection rejects the - // pump, and the finished iterator is not closed + // a sync iterator's final value is awaited too: a rejection + // rejects the pump, and the finished iterator is not closed. + // An async iterator's final value is not read. then: [ - { kind: "assign", localId: valueId, value: get(step(), "value"), loc }, { kind: "if", - cond: awaitsValue(), - then: [{ kind: "exprStmt", expr: awaitDyn(value()), loc }], + cond: sync(), + then: [ + { kind: "assign", localId: valueId, value: get(step(), "value"), loc }, + { + kind: "if", + cond: awaitsValue(), + then: [{ kind: "exprStmt", expr: awaitDyn(value()), loc }], + else_: null, + loc, + }, + ], else_: null, loc, }, diff --git a/tests/corpus/7504-pipeline-untyped-source-errors.mjs b/tests/corpus/7504-pipeline-untyped-source-errors.mjs index 5d6faded1..9dd671606 100644 --- a/tests/corpus/7504-pipeline-untyped-source-errors.mjs +++ b/tests/corpus/7504-pipeline-untyped-source-errors.mjs @@ -135,3 +135,37 @@ for (const [label, source] of [["finalRejects", finalRejects], ["finalResolves", console.log(label, "rejected", err.message); } } + +// the final result's value is read for a sync iterator only: an async +// iterator's done result is not read, so a throwing value getter there is +// never called +function finalResult(label, i) { + if (i === 1) return { value: `${label}1`, done: false }; + return { + done: true, + get value() { + throw new Error(`${label} final value read`); + }, + }; +} +function asyncFinal() { + let i = 0; + return { [Symbol.asyncIterator]() { return { async next() { i++; return finalResult("async", i); } }; } }; +} +function syncFinal() { + let i = 0; + return { [Symbol.iterator]() { return { next() { i++; return finalResult("sync", i); } }; } }; +} +async function runFinal(label, source) { + try { + await pipelineP( + pick(source), + new Writable({ objectMode: true, write(c, _e, cb) { console.log(label, "write", c); cb(); } }), + ); + console.log(label, "resolved"); + } catch (err) { + console.log(label, "rejected", err.message); + } +} +await runFinal("async final", asyncFinal()); +await runFinal("sync final", syncFinal()); From 8da01d3ab3778c8c1073a9624fb0aa7f2faf6240 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 18:02:25 -0500 Subject: [PATCH 176/259] State that SCRIPTC_CHECKER_SERVER needs a tsc-ts that serves --listen The tsc-ts 0.0.9 that scriptc includes rejects --listen, so with it every build that sets SCRIPTC_CHECKER_SERVER=1 checks with its own tsc-ts process. The variable's description now says so. --- docs/content/docs/cli.mdx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/content/docs/cli.mdx b/docs/content/docs/cli.mdx index 050d076e3..4c1b7e7c6 100644 --- a/docs/content/docs/cli.mdx +++ b/docs/content/docs/cli.mdx @@ -212,7 +212,7 @@ With `--sparse`, the profile leaves out the functions the runs never reached. Th
    The TypeScript 7 API server that checks the program: tsc-ts (the default), which scriptc includes, or tsgo, from the typescript package scriptc also includes. Both give the same diagnostics and generated code.
    SCRIPTC_CHECKER_SERVER
    -
    Set to 1 on Linux and macOS to check with a tsc-ts server that later builds share. A build connects to the server for its working directory, starting it when none answers, and the server keeps the files it parsed, so the next build of the same program loads it faster. A build that finds the server in use by another build, or cannot start or reach it, checks with its own tsc-ts process. The server exits after 5 minutes without a build, or after a build when its resident memory is above 2048 MB (TSC_TS_LISTEN_MEMORY sets another limit in megabytes). Diagnostics and generated code are the same with and without it. It applies to the default checker, tsc-ts.
    +
    Set to 1 on Linux and macOS to check with a tsc-ts server that later builds share. It takes effect with a tsc-ts release that serves tsc-ts --api --listen. The tsc-ts 0.0.9 that this version of scriptc includes does not, so each build checks with its own tsc-ts process, as without the variable. A build connects to the server for its working directory, starting it when none answers, and the server keeps the files it parsed, so the next build of the same program loads it faster. A build that finds the server in use by another build, or cannot start or reach it, checks with its own tsc-ts process. The server exits after 5 minutes without a build, or after a build when its resident memory is above 2048 MB (TSC_TS_LISTEN_MEMORY sets another limit in megabytes). Diagnostics and generated code are the same with and without it. It applies to the default checker, tsc-ts.
    ```console From 5dc3a051b73383f10f0b824fa8a2e3250f3fb872 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 18:06:45 -0500 Subject: [PATCH 177/259] Prove typed array reads in while loops bounded by the length in bounds findBytesBounds proved element reads only inside for loops, and only for `counter + c` indexes. A while loop such as while (i < len) { c = line[right - i]!; // right = len - 1 i++; if (c === 10) { if (i === len) break; c = line[right - i]!; i++; } ... } kept a bounds check on every read. The out-of-bounds path also produced a NaN that LLVM threaded into a following switch, which then stayed an indirect jump instead of becoming a lookup table. - A while condition that compares an integer counter with a typed array's length (`i < len`, `i <= right`, `len > i`) starts a bound. The body may write the counter only by statements that add a positive literal, and may not write the receiver. Calls in the body are allowed: they cannot write either binding (both are uncaptured locals), and a typed array's length is fixed at construction. - The body is followed in order. An increment raises the bound and the counter's minimum by its step. An if condition that compares the counter with the length narrows the bound in its branches (`if (i === len) break` restores `i < len` after an increment). Branches join to the weaker bound, and a statement that advances the counter inside a nested loop or labeled block leaves the counter unbounded after it. - Indexes of the form `L + d - counter` (`len - 1 - i`, `right - i`) are proven for both for and while bounds, from the counter's upper bound and its minimum. --- .../compiler/src/backend/llvm/bytes-bounds.ts | 199 +++++++++++++++++- .../8003-while-reversed-byte-reads.ts.json | 6 + .../test/while-bytes-bounds-emission.test.ts | 136 ++++++++++++ .../corpus/8003-while-reversed-byte-reads.ts | 168 +++++++++++++++ .../8003-while-reversed-byte-reads.ts.json | 1 + 5 files changed, 508 insertions(+), 2 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8003-while-reversed-byte-reads.ts.json create mode 100644 packages/compiler/test/while-bytes-bounds-emission.test.ts create mode 100644 tests/corpus/8003-while-reversed-byte-reads.ts create mode 100644 tests/harness/corpus-costs/8003-while-reversed-byte-reads.ts.json diff --git a/packages/compiler/src/backend/llvm/bytes-bounds.ts b/packages/compiler/src/backend/llvm/bytes-bounds.ts index 86a1d7ac8..b35a949ff 100644 --- a/packages/compiler/src/backend/llvm/bytes-bounds.ts +++ b/packages/compiler/src/backend/llvm/bytes-bounds.ts @@ -14,11 +14,25 @@ interface Bound extends Extent { minimum: number; } type Node = IrExpr | IrStmt; +const FLIPPED: Readonly> = { + "<": ">", + "<=": ">=", + ">": "<", + ">=": "<=", + "===": "===", + "==": "==", + "!==": "!==", + "!=": "!=", +}; /** Relational proofs for fixed typed-array lengths. Cached lengths retain * their receiver identity only when that binding is never reassigned. * Loops may use offsets in either direction, but both index integrality - * and receiver stability are established separately from the relation. */ + * and receiver stability are established separately from the relation. + * For loops hold one bound over the body. While loops start from the + * condition's bound and follow the body in order: increments raise it and + * comparisons with the length in if conditions narrow it. Indexes are + * `counter + c` or `L + d - counter`, where L is the receiver's length. */ export function findBytesBounds(fn: IrFunction, ranges: IntegerRanges): ReadonlySet { const proved = new Map(); if (fn.async || fn.generator || !fn.locals.some((local) => local.type.kind === "bytes")) @@ -96,6 +110,20 @@ export function findBytesBounds(fn: IrFunction, ranges: IntegerRanges): Readonly const result = left + (e.op === "+" ? e.right.value : -e.right.value); return Number.isSafeInteger(result) ? result : null; } + /** For an index of the form `L + d - counter` (`len - 1 - i`, `right - i` + * with `right = len - 1`), where L is the receiver's length: d. */ + function reversed(e: IrExpr, bound: Bound): number | null { + if (e.kind !== "bin" || (e.op !== "+" && e.op !== "-")) return null; + if (e.op === "-" && e.right.kind === "varRef" && e.right.localId === bound.counter) { + const length = extent(e.left, false); + return length && length.receiver === bound.receiver ? length.offset : null; + } + if (e.right.kind !== "numLit" || !Number.isSafeInteger(e.right.value)) return null; + const left = reversed(e.left, bound); + if (left === null) return null; + const result = left + (e.op === "+" ? e.right.value : -e.right.value); + return Number.isSafeInteger(result) ? result : null; + } function affineRange(e: IrExpr, bound: Bound): IntegerRange | null { if (e.kind === "varRef" && e.localId === bound.counter) { const max = Number.MAX_SAFE_INTEGER + bound.offset - 1; @@ -159,7 +187,7 @@ export function findBytesBounds(fn: IrFunction, ranges: IntegerRanges): Readonly if (s.cond.left.kind !== "varRef" || s.cond.left.localId !== counter) { if (right.kind !== "varRef" || right.localId !== counter) return null; right = s.cond.left; - op = ({ "<": ">", "<=": ">=", ">": "<", ">=": "<=" } as Record)[op] ?? ""; + op = FLIPPED[op] ?? ""; } const update = s.update; let step = 0; @@ -212,6 +240,90 @@ export function findBytesBounds(fn: IrFunction, ranges: IntegerRanges): Readonly } return result && stable(s.body, result.receiver, counter) ? result : null; } + /** A comparison of the counter with the receiver's length: the operator + * with the counter on the left, and the length's offset. */ + function lengthComparison(e: IrExpr, bound: Bound): { op: string; offset: number } | null { + if (e.kind !== "bin") return null; + let other = e.right, + op: string = e.op; + if (e.left.kind !== "varRef" || e.left.localId !== bound.counter) { + if (other.kind !== "varRef" || other.localId !== bound.counter) return null; + other = e.left; + op = FLIPPED[op] ?? op; + } + const length = extent(other, false); + return length && length.receiver === bound.receiver ? { op, offset: length.offset } : null; + } + /** The step of `counter = counter + c` with a positive literal c, or null. */ + function increment(s: IrStmt, counter: string): number | null { + return s.kind === "assign" && + s.localId === counter && + s.value.kind === "bin" && + s.value.op === "+" && + s.value.left.kind === "varRef" && + s.value.left.localId === counter && + s.value.right.kind === "numLit" && + Number.isSafeInteger(s.value.right.value) && + s.value.right.value > 0 + ? s.value.right.value + : null; + } + function writes(s: IrStmt, id: string): boolean { + return !everyStmtList([s], { + expr: (e) => (e.kind !== "assignExpr" && e.kind !== "incDec") || e.localId !== id, + stmt: (child) => + !( + ((child.kind === "assign" || child.kind === "forOf" || child.kind === "varDecl") && + child.localId === id) || + (child.kind === "tryCatch" && child.catchLocalId === id) + ), + }); + } + /** A while loop whose condition bounds an integer counter by a typed + * array's length. The body may write the counter only by statements + * that add a positive literal, and may not write the receiver. Calls + * cannot write either binding (both are uncaptured locals), and a typed + * array's length is fixed at construction, so the body may hold calls. */ + function whileBound(s: IrStmt & { kind: "while" }): Bound | null { + const cond = s.cond; + if (cond.kind !== "bin") return null; + const counterRef = [cond.left, cond.right].find( + (side, i) => + side.kind === "varRef" && + eligible(side.localId) && + extent(i === 0 ? cond.right : cond.left, false) !== null, + ); + const minimum = counterRef ? ranges.get(counterRef)?.min : undefined; + if (counterRef?.kind !== "varRef" || minimum === undefined) return null; + const counter = counterRef.localId; + const length = extent(counterRef === cond.left ? cond.right : cond.left, false)!; + const receiver = length.receiver; + const comparison = lengthComparison(cond, { receiver, counter, offset: 0, minimum }); + if (comparison?.op !== "<" && comparison?.op !== "<=") return null; + const writesOk = everyStmtList(s.body, { + expr: (e) => + (e.kind !== "assignExpr" && e.kind !== "incDec") || + (e.localId !== counter && e.localId !== receiver), + stmt: (child) => { + if (child.kind === "assign" && child.localId === counter) + return increment(child, counter) !== null; + if (child.kind === "assign" || child.kind === "forOf" || child.kind === "varDecl") + return child.localId !== counter && child.localId !== receiver; + return ( + child.kind !== "tryCatch" || + (child.catchLocalId !== counter && child.catchLocalId !== receiver) + ); + }, + }); + return writesOk + ? { + receiver, + counter, + offset: comparison.offset + (comparison.op === "<=" ? 1 : 0), + minimum, + } + : null; + } function access(node: Node, array: IrExpr, index: IrExpr, active: Bound[], width: number): void { const integer = ranges.get(index); let safe = false; @@ -228,6 +340,13 @@ export function findBytesBounds(fn: IrFunction, ranges: IntegerRanges): Readonly safe = true; break; } + // counter < L + bound.offset and counter >= bound.minimum put + // L + d - counter in [0, L - width]. + const d = integer ? reversed(index, bound) : null; + if (d !== null && bound.offset <= d + 1 && bound.minimum >= d + width) { + safe = true; + break; + } } } proved.set(node, (proved.get(node) ?? true) && safe); @@ -244,8 +363,84 @@ export function findBytesBounds(fn: IrFunction, ranges: IntegerRanges): Readonly (child) => stmt(child, active), ); } + /** The bounds where `cond` is true and where it is false, from the + * bound before it. */ + function narrow(cond: IrExpr, bound: Bound): [Bound, Bound] { + const comparison = lengthComparison(cond, bound); + if (!comparison) return [bound, bound]; + const j = comparison.offset, + offset = bound.offset; + // counter < L + j, counter <= L + j, and counter !== L + j. + const below = { ...bound, offset: Math.min(offset, j) }, + atMost = { ...bound, offset: Math.min(offset, j + 1) }, + unequal = offset === j + 1 ? { ...bound, offset: j } : bound; + switch (comparison.op) { + case "<": + return [below, bound]; + case "<=": + return [atMost, bound]; + case ">": + return [bound, atMost]; + case ">=": + return [bound, below]; + case "===": + case "==": + return [atMost, unequal]; + case "!==": + case "!=": + return [unequal, atMost]; + default: + return [bound, bound]; + } + } + /** Visits a while body in order, from the bound that holds on entry. + * Returns the bound at the end of the list. Its offset is -Infinity (and + * its minimum Infinity) when the end is unreachable, and Infinity when + * nothing bounds the counter there. Every write of the counter adds a + * positive literal (whileBound), so the minimum survives any write. */ + function flow(list: IrStmt[], active: Bound[], bound: Bound): Bound { + for (const s of list) { + const current = Number.isFinite(bound.offset) ? [...active, bound] : active; + const step = increment(s, bound.counter); + if (step !== null) { + bound = { ...bound, offset: bound.offset + step, minimum: bound.minimum + step }; + } else if (s.kind === "if") { + expr(s.cond, current); + const [then, else_] = narrow(s.cond, bound); + const left = flow(s.then, active, then), + right = s.else_ ? flow(s.else_, active, else_) : else_; + bound = { + ...bound, + offset: Math.max(left.offset, right.offset), + minimum: Math.min(left.minimum, right.minimum), + }; + } else if (s.kind === "block" && !s.labels?.length) { + bound = flow(s.body, active, bound); + } else if (writes(s, bound.counter)) { + stmt(s, active); + bound = { ...bound, offset: Infinity }; + } else { + stmt(s, current); + if ( + s.kind === "break" || + s.kind === "continue" || + s.kind === "return" || + s.kind === "throw" + ) + bound = { ...bound, offset: -Infinity, minimum: Infinity }; + } + } + return bound; + } function stmt(s: IrStmt, active: Bound[]): boolean { if (s.kind === "bytesSet") access(s, s.arr, s.index, active, 1); + if (s.kind === "while") { + expr(s.cond, active); + const bound = whileBound(s); + if (!bound) return s.body.every((child) => stmt(child, active)); + flow(s.body, active, bound); + return true; + } if (s.kind === "for") { if (s.init) stmt(s.init, active); if (s.cond) expr(s.cond, active); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8003-while-reversed-byte-reads.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8003-while-reversed-byte-reads.ts.json new file mode 100644 index 000000000..26031ac1f --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8003-while-reversed-byte-reads.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8003-while-reversed-byte-reads.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/while-bytes-bounds-emission.test.ts b/packages/compiler/test/while-bytes-bounds-emission.test.ts new file mode 100644 index 000000000..2b6dc1d3c --- /dev/null +++ b/packages/compiler/test/while-bytes-bounds-emission.test.ts @@ -0,0 +1,136 @@ +import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile } from "../src/index.js"; + +async function emitLlvm(source: string): Promise { + const dir = await mkdtemp(join(tmpdir(), "scriptc-while-bounds-")); + try { + const entry = join(dir, "main.ts"); + const outPath = join(dir, "main.ll"); + await writeFile(entry, source); + const result = await compile(entry, { + outDir: dir, + outPath, + outputKind: "llvm", + }); + expect(result.ok, JSON.stringify(result.diagnostics)).toBe(true); + return await readFile(outPath, "utf8"); + } finally { + await rm(dir, { recursive: true, force: true }); + } +} + +/** The number of bounds-checked element reads and writes in a function's + * statement body (the borrowed-argument body when there is one). */ +function checks(ll: string, name: string): number { + const definition = (prefix: string): number => + ll.search(new RegExp(`define [^\\n]*@${prefix}_${name}\\(`)); + const start = definition("sc_bf") >= 0 ? definition("sc_bf") : definition("sc_f"); + expect(start).toBeGreaterThanOrEqual(0); + const fn = ll.slice(start, ll.indexOf("\n}\n", start)); + return fn.split("label %bytes.index.valid").length - 1; +} + +test("reads from the end of a typed array in a while loop are proven in bounds", async () => { + const ll = await emitLlvm(` +function code(c: number): number { + switch (c) { + case 65: return 84; + case 84: return 65; + } + return 0; +} +function reversed(line: Uint8Array): number { + const len = line.length; + const right = len - 1; + let i = 0; + let total = 0; + while (i < len) { + let c = line[right - i]!; + i++; + if (c === 10) { + if (i === len) break; + c = line[right - i]!; + i++; + } + total += code(c); + } + return total; +} +function pairs(values: Uint16Array): number { + let i = 0; + let total = 0; + while (values.length > i) { + i += 2; + total += values[i - 2]!; + if (i < values.length) total += values[values.length - 1 - i]!; + } + return total; +} +console.log(reversed(new Uint8Array([65, 10, 84])), pairs(new Uint16Array([1, 2, 3]))); +`); + expect(checks(ll, "reversed")).toBe(0); + expect(checks(ll, "pairs")).toBe(0); +}); + +test("reads a while loop does not keep in bounds keep their checks", async () => { + const ll = await emitLlvm(` +function inclusive(line: Uint8Array): number { + const len = line.length; + let i = 0; + let total = 0; + while (i <= len) { + total += line[len - i]!; + i++; + } + return total; +} +function unguarded(line: Uint8Array): number { + const right = line.length - 1; + let i = 0; + let total = 0; + while (i < line.length) { + total += line[right - i]!; + i++; + total += line[right - i]!; + } + return total; +} +function ahead(values: Uint16Array): number { + let i = 0; + let total = 0; + while (i < values.length) { + i += 2; + total += values[i - 1]!; + } + return total; +} +function nested(line: Uint8Array): number { + const len = line.length; + let i = 0; + let total = 0; + while (i < len) { + const c = line[len - 1 - i]!; + i++; + while (i < len && line[len - 1 - i]! === c) i++; + total += line[len - 1 - i]!; + } + return total; +} +console.log( + inclusive(new Uint8Array(2)), + unguarded(new Uint8Array(2)), + ahead(new Uint16Array(3)), + nested(new Uint8Array(3)), +); +`); + expect(checks(ll, "inclusive")).toBe(1); + // The read before the increment is in bounds; the one after it is not. + expect(checks(ll, "unguarded")).toBe(1); + expect(checks(ll, "ahead")).toBe(1); + // The read before the nested loop is in bounds. The nested loop's + // condition is not a bound, and the read after the loop can be at -1. + expect(checks(ll, "nested")).toBe(2); +}); diff --git a/tests/corpus/8003-while-reversed-byte-reads.ts b/tests/corpus/8003-while-reversed-byte-reads.ts new file mode 100644 index 000000000..9b2efd4f0 --- /dev/null +++ b/tests/corpus/8003-while-reversed-byte-reads.ts @@ -0,0 +1,168 @@ +// While loops that read a typed array or Buffer backwards from its length +// (`line[len - 1 - i]`, `line[right - i]`), with increments, guards that +// exit at the length, calls in the body, reads at or past either end, and +// counters advanced by nested loops. + +function complement(code: number): number { + switch (code) { + case 65: + return 84; + case 67: + return 71; + case 71: + return 67; + case 84: + return 65; + } + return 63; +} + +function reverseComplement(line: Uint8Array, target: Uint8Array): string { + const len = line.length; + const right = len - 1; + let ileft = 0; + let iright = 0; + let c: number; + while (iright < len) { + c = line[right - iright]!; + iright++; + if (c === 10) { + if (iright === len) break; + c = line[right - iright]!; + iright++; + } + target[ileft] = complement(c); + ileft++; + } + return Buffer.from(target.subarray(0, ileft)).toString("latin1"); +} + +const out = new Uint8Array(32); +console.log(reverseComplement(Buffer.from("ACGT\nTTGA\n"), out)); +console.log(reverseComplement(Buffer.from("\nGATTACA"), out)); +console.log(reverseComplement(Buffer.from("\n"), out)); +console.log(reverseComplement(Buffer.from("A\n\nC"), out)); +console.log(JSON.stringify(reverseComplement(new Uint8Array(0), out))); + +// Reads one past the end: the first pass reads line[len], which is undefined. +function inclusive(line: Uint8Array): string { + const len = line.length; + let i = 0; + const seen: (number | undefined)[] = []; + while (i <= len) { + seen.push(line[len - i]); + i++; + } + return JSON.stringify(seen.map((v) => (v === undefined ? "u" : v))); +} +console.log(inclusive(new Uint8Array([1, 2, 3])), inclusive(new Uint8Array(0))); + +// A read after an increment with no guard reads line[-1] on the last pass. +function unguarded(line: Uint8Array): string { + const right = line.length - 1; + let i = 0; + let total = 0; + let missing = 0; + while (i < line.length) { + total += line[right - i]!; + i++; + const next = line[right - i]; + if (next === undefined) missing++; + else total += next * 100; + } + return `${total} ${missing}`; +} +console.log(unguarded(new Uint8Array([1, 2, 3])), unguarded(new Uint8Array([9]))); + +// Guards in other forms: >=, !==, and a guard in an else branch. +function guards(line: Uint16Array): number[] { + const len = line.length; + const result: number[] = []; + let i = 0; + while (i < len) { + i += 1; + if (i >= len) { + result.push(-1); + break; + } + result.push(line[len - 1 - i]!); + } + let j = 0; + while (len > j) { + j++; + if (j !== len) result.push(line[len - 1 - j]! * 10); + else result.push(-2); + } + let k = 0; + while (k < len) { + k++; + if (line[0] === 0) { + result.push(-3); + } else if (k === len) { + break; + } else { + result.push(line[len - k - 1]! * 100); + } + } + return result; +} +console.log(guards(new Uint16Array([5, 6, 7]))); +console.log(guards(new Uint16Array([0, 1]))); +console.log(guards(new Uint16Array(0))); + +// A nested loop advances the counter, so the read after it can fall +// outside the array. +function skipRuns(line: Uint8Array): string { + const len = line.length; + let i = 0; + const parts: string[] = []; + while (i < len) { + const c = line[len - 1 - i]!; + i++; + while (i < len && line[len - 1 - i] === c) i++; + const after = line[len - 1 - i]; + parts.push(`${c}:${after === undefined ? "end" : after}`); + } + return parts.join(" "); +} +console.log(skipRuns(Buffer.from("aabbbc")), skipRuns(Buffer.from("zz"))); + +// A condition with <= against the last index, a labeled block, and +// counters that start past zero or past the end. +function labeled(line: Int8Array, start: number): number[] { + const len = line.length; + const right = len - 1; + const result: number[] = []; + let i = start; + while (i <= right) { + found: { + if (line[len - 1 - i]! < 0) break found; + result.push(line[len - 1 - i]!); + } + i += 2; + } + result.push(i); + return result; +} +console.log(labeled(new Int8Array([1, -2, 3, -4, 5]), 0)); +console.log(labeled(new Int8Array([1, -2, 3, -4, 5]), 1)); +console.log(labeled(new Int8Array([1, -2, 3]), 5)); + +// An exception thrown from a call in the body. +function throwing(line: Uint8Array): string { + const len = line.length; + let i = 0; + let total = 0; + try { + while (i < len) { + const c = line[len - 1 - i]!; + i++; + if (c === 0) throw new Error(`zero after ${total}`); + total += c; + } + } catch (error) { + return (error as Error).message; + } + return String(total); +} +console.log(throwing(new Uint8Array([4, 0, 2, 3])), throwing(new Uint8Array([1, 2]))); diff --git a/tests/harness/corpus-costs/8003-while-reversed-byte-reads.ts.json b/tests/harness/corpus-costs/8003-while-reversed-byte-reads.ts.json new file mode 100644 index 000000000..6c521804e --- /dev/null +++ b/tests/harness/corpus-costs/8003-while-reversed-byte-reads.ts.json @@ -0,0 +1 @@ +{ "plain": 2359, "san": 4025 } From c8ee28de80b24f5b35f7f99eb811d6ba9525e1e1 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 18:23:17 -0500 Subject: [PATCH 178/259] Write slices stored in records that are only read into stack buffers A slice whose every reader only borrows it is written into a stack buffer instead of a heap allocation. A slice stored in a record field counted as kept, so a tokenizer's `const text = source.slice(start, i); const t = token(kind, text, start); sum += weight(t);` allocated and freed a string per token even though `t` is read only for `t.text.length`. A slice local stored directly in a field of a stable record local, built by a record literal or by a factory that only returns a record literal of its parameters, is now lent when the record is only projected: its field reads are lending reads, and it is passed only to record parameters whose bodies read that field only in lending positions (a fixpoint, like the one for lent string parameters). A record that is returned, stored, captured or passed anywhere else keeps the slice on the heap. includes, indexOf and lastIndexOf on string arrays now lend their search argument. --- .../src/backend/llvm/emit-function.ts | 2 +- packages/compiler/src/backend/llvm/emitter.ts | 19 +- .../src/backend/llvm/string-slices.test.ts | 184 ++++++++++- .../src/backend/llvm/string-slices.ts | 288 +++++++++++++++++- .../corpus/8114-record-field-slices.ts.json | 6 + tests/corpus/8114-record-field-slices.ts | 122 ++++++++ 6 files changed, 597 insertions(+), 24 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8114-record-field-slices.ts.json create mode 100644 tests/corpus/8114-record-field-slices.ts diff --git a/packages/compiler/src/backend/llvm/emit-function.ts b/packages/compiler/src/backend/llvm/emit-function.ts index a3ebbe0e8..ca45a6624 100644 --- a/packages/compiler/src/backend/llvm/emit-function.ts +++ b/packages/compiler/src/backend/llvm/emit-function.ts @@ -191,7 +191,7 @@ export function emitFunction(emitter: LlEmitter, fn: IrFunction): string { fn, emitter.callLifetimes, emitter.scalarStringSlices, - emitter.lentStringParameters, + emitter.lendingFacts, ) : new Set(); emitter.mapReadLifetimes = findMapReadLifetimes( diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 586517356..ce698be55 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -200,8 +200,10 @@ import { StackCallbacks } from "./stack-callbacks.js"; import { findAppendedArrayLiterals } from "./appended-array-literals.js"; import { AmbientReceiverReaders, findConstantCallbacks } from "./constant-callbacks.js"; import { + findLentRecordFields, findLentStringParameters, - type LentStringParameters, + findRecordFieldProducers, + type LendingFacts, type StringSliceSnapshot, } from "./string-slices.js"; import { LazyCaptures } from "./lazy-captures.js"; @@ -792,8 +794,9 @@ export class LlEmitter { readonly stringSlices = new Map(); /** Slices written into stack buffers (findScratchStringSlices). */ scratchStringSlices: ReadonlySet = new Set(); - /** String parameters a caller may lend scratch slices to. */ - lentStringParameters: LentStringParameters = new Map(); + /** String parameters, record fields and record producers a caller may + * lend scratch slices to. */ + lendingFacts: LendingFacts = { strings: new Map(), records: new Map(), producers: new Map() }; localStackUnions = new Map(); localStackObjects = new Map(); reassignedStackObjects = new Set(); @@ -1893,8 +1896,14 @@ export class LlEmitter { }, (wrap) => this.borrowableNullableWrap(wrap) === "ref", ); - this.lentStringParameters = - this.debug === null ? findLentStringParameters(this.fnByName, this.callLifetimes) : new Map(); + if (this.debug === null) { + const strings = findLentStringParameters(this.fnByName, this.callLifetimes); + this.lendingFacts = { + strings, + records: findLentRecordFields(this.fnByName, this.callLifetimes, strings), + producers: findRecordFieldProducers(this.fnByName), + }; + } this.constantCallbacks = findConstantCallbacks(mod, this.callLifetimes, this.nodeIndex); // Integer clones signal a stack overflow through their result, which // needs the single-threaded guard; worker programs also poll for diff --git a/packages/compiler/src/backend/llvm/string-slices.test.ts b/packages/compiler/src/backend/llvm/string-slices.test.ts index b2656e560..43bec955a 100644 --- a/packages/compiler/src/backend/llvm/string-slices.test.ts +++ b/packages/compiler/src/backend/llvm/string-slices.test.ts @@ -1,8 +1,19 @@ import { expect, test } from "vitest"; -import { BOOL, F64, STRING, VOID, type IrExpr, type IrFunction, type IrStmt } from "../../ir/ir.js"; +import { + BOOL, + F64, + STRING, + VOID, + type IrExpr, + type IrFunction, + type IrStmt, + type IrType, +} from "../../ir/ir.js"; import { analyzeCallLifetimes } from "./call-lifetimes.js"; import { + findLentRecordFields, findLentStringParameters, + findRecordFieldProducers, findScalarStringSlices, findScratchStringSlices, } from "./string-slices.js"; @@ -142,12 +153,12 @@ function lending(body: IrStmt[]): IrFunction { function scratch(fn: IrFunction, extra: IrFunction[] = []): Set { const functions = new Map([fn, ...extra].map((f) => [f.name, f])); const lifetimes = analyzeCallLifetimes(functions); - return findScratchStringSlices( - fn, - lifetimes, - findScalarStringSlices(fn, lifetimes), - findLentStringParameters(functions, lifetimes), - ); + const strings = findLentStringParameters(functions, lifetimes); + return findScratchStringSlices(fn, lifetimes, findScalarStringSlices(fn, lifetimes), { + strings, + records: findLentRecordFields(functions, lifetimes, strings), + producers: findRecordFieldProducers(functions), + }); } test("slices read only by lending consumers use a stack buffer", () => { const inline = slice("source", 0, 3); @@ -242,3 +253,162 @@ test("helper parameters read only by lending consumers accept stack slices", () const all = new Map([fn, ...functions].map((f) => [f.name, f])); expect([...findLentStringParameters(all, analyzeCallLifetimes(all)).keys()]).toEqual(["isGet"]); }); + +const TOKEN: IrType = { kind: "record", shapeId: "token" }; +const record = (id: string): IrExpr => ({ kind: "varRef", localId: id, type: TOKEN, loc }); +const textOf = (obj: IrExpr): IrExpr => ({ + kind: "recordGet", + obj, + shapeId: "token", + field: "text", + type: STRING, + loc, +}); +const lengthOf = (receiver: IrExpr): IrExpr => ({ + kind: "strIntrinsic", + method: "length", + receiver, + args: [], + type: F64, + loc, +}); +const tokenLit = (text: IrExpr): IrExpr => ({ + kind: "recordLit", + fields: [ + { name: "text", value: text }, + { name: "pos", value: { kind: "numLit", value: 1, type: F64, loc } }, + ], + type: TOKEN, + loc, +}); +const keepIn = (value: IrExpr): IrStmt => ({ + kind: "exprStmt", + expr: { kind: "arrayLit", elems: [value], type: { kind: "array", elem: STRING }, loc }, + loc, +}); +/** A function of one record parameter `t`. */ +function recordHelper(name: string, body: IrStmt[]): IrFunction { + return { + name, + params: [{ localId: "t", name: "t", type: TOKEN }], + locals: [{ id: "t", name: "t", type: TOKEN, mutable: false }], + returnType: F64, + loc, + body, + }; +} +/** `make(text)` returns `{ text, pos: 1 }`; `twice` also reads its parameter elsewhere. */ +function producerHelper(name: string, extra: IrStmt[] = []): IrFunction { + return { + name, + params: [{ localId: "text", name: "text", type: STRING }], + locals: [{ id: "text", name: "text", type: STRING, mutable: false }], + returnType: TOKEN, + loc, + body: [...extra, { kind: "return", value: tokenLit(ref("text")), loc }], + }; +} +function containing(init: IrExpr, declare: IrExpr, uses: IrStmt[]): IrFunction { + const fn = lending([ + { kind: "varDecl", localId: "word", init, loc }, + { kind: "varDecl", localId: "tok", init: declare, loc }, + ...uses, + ]); + fn.locals.push({ id: "tok", name: "tok", type: TOKEN, mutable: false }); + return fn; +} +const reads = recordHelper("reads", [ + { kind: "return", value: lengthOf(textOf(record("t"))), loc }, +]); +const keepsText = recordHelper("keepsText", [ + keepIn(textOf(record("t"))), + { kind: "return", value: { kind: "numLit", value: 0, type: F64, loc }, loc }, +]); +const escapes = recordHelper("escapes", [ + { + kind: "exprStmt", + expr: { kind: "arrayLit", elems: [record("t")], type: { kind: "array", elem: TOKEN }, loc }, + loc, + }, + { kind: "return", value: { kind: "numLit", value: 0, type: F64, loc }, loc }, +]); +const passCall = (callee: string, arg: IrExpr): IrStmt => ({ + kind: "exprStmt", + expr: { kind: "call", callee, args: [arg], type: F64, loc }, + loc, +}); + +test("a slice stored in a record that is only projected uses a stack buffer", () => { + const helpers = [reads, keepsText, escapes, producerHelper("make")]; + for (const declare of [tokenLit(ref("word")), callOf("make", ref("word"))]) { + if (declare.kind === "call") declare.type = TOKEN; + const init = slice("source", 1, 5); + const fn = containing(init, declare, [ + { kind: "exprStmt", expr: equals(textOf(record("tok"))), loc }, + passCall("reads", record("tok")), + ]); + expect(scratch(fn, helpers).has(init)).toBe(true); + } + const all = new Map(helpers.map((f) => [f.name, f])); + const lifetimes = analyzeCallLifetimes(all); + const lent = findLentRecordFields(all, lifetimes, findLentStringParameters(all, lifetimes)); + expect(lent.get("reads")?.get(0)).toEqual(new Set()); + expect(lent.get("keepsText")?.get(0)).toEqual(new Set(["text"])); + expect(lent.has("escapes")).toBe(false); + expect(findRecordFieldProducers(all).get("make")).toEqual(new Map([[0, "text"]])); +}); + +test.each([ + "kept-field", + "returned", + "kept-by-callee", + "escapes-callee", + "captured", + "producer-reuse", +])("a slice stored in a record that may be kept (%s) stays owned", (reason) => { + const helpers = [ + reads, + keepsText, + escapes, + producerHelper("make"), + producerHelper("twice", [keepIn(ref("text"))]), + ]; + const init = slice("source", 1, 5); + const declare = + reason === "producer-reuse" ? callOf("twice", ref("word")) : tokenLit(ref("word")); + if (declare.kind === "call") declare.type = TOKEN; + const uses: IrStmt[] = [{ kind: "exprStmt", expr: equals(textOf(record("tok"))), loc }]; + if (reason === "kept-field") uses.push(keepIn(textOf(record("tok")))); + if (reason === "returned") uses.push({ kind: "return", value: record("tok"), loc }); + if (reason === "kept-by-callee") uses.push(passCall("keepsText", record("tok"))); + if (reason === "escapes-callee") uses.push(passCall("escapes", record("tok"))); + const fn = containing(init, declare, uses); + if (reason === "captured") fn.locals.find((l) => l.id === "tok")!.boxed = true; + expect(scratch(fn, helpers).has(init)).toBe(false); +}); + +test("searches of string arrays lend their needle", () => { + const keywords: IrExpr = { + kind: "varRef", + localId: "keywords", + type: { kind: "array", elem: STRING }, + loc, + }; + const classify = helper("classify", [ + { + kind: "return", + value: { + kind: "arrIntrinsic", + method: "includes", + receiver: keywords, + args: [ref("text")], + type: BOOL, + loc, + }, + loc, + }, + ]); + const init = slice("source", 0, 3); + const fn = lending([{ kind: "exprStmt", expr: callOf("classify", init), loc }]); + expect(scratch(fn, [classify]).has(init)).toBe(true); +}); diff --git a/packages/compiler/src/backend/llvm/string-slices.ts b/packages/compiler/src/backend/llvm/string-slices.ts index d00c681d6..81a4a5a3e 100644 --- a/packages/compiler/src/backend/llvm/string-slices.ts +++ b/packages/compiler/src/backend/llvm/string-slices.ts @@ -145,6 +145,10 @@ const LENDING_LIB_FNS: ReadonlySet = new Set([ "num.parseFloat", ]); +/** Searches of string arrays compare the needle with the elements during + * the call. */ +const LENDING_ARRAY_SEARCHES: ReadonlySet = new Set(["includes", "indexOf", "lastIndexOf"]); + /** Typed string-keyed collection operations: reads probe with the key, and * an insertion stores scr_str_scratch_keep's copy (scr_map_append). */ const LENDING_KEY_METHODS: ReadonlySet = new Set(["get", "has", "set", "add", "delete"]); @@ -176,6 +180,12 @@ function lentOperands(value: IrExpr, parameters: LentStringParameters): readonly return LENDING_KEY_METHODS.has(value.method) && stringKeyed(value) ? value.args.slice(0, 1) : []; + case "arrIntrinsic": + return LENDING_ARRAY_SEARCHES.has(value.method) && + value.receiver.type.kind === "array" && + value.receiver.type.elem.kind === "string" + ? value.args.slice(0, 1) + : []; case "call": { const lent = parameters.get(value.callee); return lent ? value.args.filter((_, index) => lent.has(index)) : []; @@ -185,41 +195,123 @@ function lentOperands(value: IrExpr, parameters: LentStringParameters): readonly } } +/** Record parameters, by function and index, that the body only projects: + * it reads their fields and passes them only to such parameters. The set + * lists the string fields some read keeps (reads outside a lending + * position); every other string field is lent (findLentRecordFields). */ +export type LentRecordFields = ReadonlyMap>>; + +/** Functions whose body only returns a record literal that stores some + * parameters, each read once, directly as fields: by function, parameter + * index to field (findRecordFieldProducers). A call stores those arguments + * in the fields of its result and keeps them nowhere else. */ +export type RecordFieldProducers = ReadonlyMap>; + +/** What lends a string: lent string parameters, lent record fields and + * record field producers. */ +export interface LendingFacts { + strings: LentStringParameters; + records: LentRecordFields; + producers: RecordFieldProducers; +} + +const NO_LENDING_FACTS: LendingFacts = { + strings: new Map(), + records: new Map(), + producers: new Map(), +}; + interface LendingScan { /** Slice operands of lending consumers, excluding any node also reached * in an owning position. */ scratch: Set; /** Candidates read anywhere other than a lending position. */ invalid: Set; - /** Direct callees, for the parameter fixpoint. */ + /** Record candidates read other than by a field read or a lent record + * argument. */ + invalidRecords: Set; + /** String fields of record candidates read outside a lending position. */ + keptFields: Map>; + /** Direct callees, for the parameter fixpoints. */ callees: Set; } /** One pass over `fn`: which candidate bindings only lending consumers read * (a slice initializer of a candidate local is not itself a read), and * which slice operands those consumers lend. A switch discriminant is only - * compared with the case tests. */ + * compared with the case tests. Record candidates (`records`) may only be + * projected: their field reads are checked as reads of the field, and they + * may be passed to lent record parameters. A record `container` + * declaration stores candidates in fields of a record candidate; those + * stores are not reads. */ function scanLending( fn: IrFunction, candidates: ReadonlySet, initializers: ReadonlyMap, - parameters: LentStringParameters, + facts: LendingFacts, + records: ReadonlySet = new Set(), + containers: ReadonlyMap = new Map(), ): LendingScan { - const scan: LendingScan = { scratch: new Set(), invalid: new Set(), callees: new Set() }; + const scan: LendingScan = { + scratch: new Set(), + invalid: new Set(), + invalidRecords: new Set(), + keptFields: new Map(), + callees: new Set(), + }; const owned = new Set(); + const keep = (record: string, field: string): void => { + let fields = scan.keptFields.get(record); + if (!fields) scan.keptFields.set(record, (fields = new Set())); + fields.add(field); + }; + const projected = (value: IrExpr): value is IrExpr & { kind: "recordGet" } => + value.kind === "recordGet" && value.obj.kind === "varRef" && records.has(value.obj.localId); function lent(value: IrExpr): boolean { if (value.kind === "varRef" && candidates.has(value.localId)) return true; + if (projected(value)) return true; if (!isSlice(value)) return expr(value); scan.scratch.add(value); return everyExprChild(value, expr, stmt); } + /** A call's arguments: lent string parameters lend, lent record + * parameters project their record, and `stored` arguments (a producer's + * fields in a container declaration) are not reads. */ + function callArgs(value: IrExpr & { kind: "call" }, stored: ReadonlySet | null): void { + scan.callees.add(value.callee); + const strings = facts.strings.get(value.callee); + const recordParams = facts.records.get(value.callee); + value.args.forEach((arg, index) => { + if (stored !== null && stored.has(index)) return; + const kept = recordParams?.get(index); + if (kept && arg.kind === "varRef" && records.has(arg.localId)) { + for (const field of kept) keep(arg.localId, field); + return; + } + if (strings?.has(index)) lent(arg); + else expr(arg); + }); + } function expr(value: IrExpr): boolean { if (isSlice(value)) owned.add(value); + if (projected(value)) { + if (value.type.kind === "string") + keep((value.obj as { localId: string }).localId, value.field); + return true; + } if (value.kind === "varRef" && candidates.has(value.localId)) scan.invalid.add(value.localId); + if (value.kind === "varRef" && records.has(value.localId)) + scan.invalidRecords.add(value.localId); if (value.kind === "closure" || value.kind === "classRef") - for (const id of value.captures ?? []) scan.invalid.add(id); - if (value.kind === "call") scan.callees.add(value.callee); - const operands = lentOperands(value, parameters); + for (const id of value.captures ?? []) { + scan.invalid.add(id); + scan.invalidRecords.add(id); + } + if (value.kind === "call") { + callArgs(value, null); + return true; + } + const operands = lentOperands(value, facts.strings); if (operands.length === 0) return everyExprChild(value, expr, stmt); return everyExprChild( value, @@ -231,6 +323,20 @@ function scanLending( // A candidate's single declaration initializes it with its slice. if (value.kind === "varDecl" && value.init !== null && initializers.has(value.localId)) return everyExprChild(value.init, expr, stmt); + const container = value.kind === "varDecl" ? containers.get(value.localId) : undefined; + if (container && value.kind === "varDecl" && value.init !== null) { + const init = value.init; + if (init.kind === "recordLit") + for (const field of init.fields) { + if (!container.stored.has(field.value)) expr(field.value); + } + else if (init.kind === "call") + callArgs( + init, + new Set(init.args.flatMap((arg, i) => (container.stored.has(arg) ? [i] : []))), + ); + return true; + } if (value.kind === "switch" && value.disc.type.kind === "string") { lent(value.disc); for (const entry of value.cases) { @@ -276,7 +382,7 @@ export function findLentStringParameters( const fn = functions.get(name); if (!indexes || !fn) continue; const ids = new Set([...indexes].map((index) => fn.params[index]!.localId)); - const scan = scanLending(fn, ids, new Map(), lent); + const scan = scanLending(fn, ids, new Map(), { ...NO_LENDING_FACTS, strings: lent }); for (const callee of scan.callees) { let set = callers.get(callee); if (!set) callers.set(callee, (set = new Set())); @@ -296,6 +402,148 @@ export function findLentStringParameters( return lent; } +/** Functions whose whole body is `return { ... }`, a record literal storing + * some parameters, each read nowhere else, directly as fields (a factory + * such as `token(kind, text, pos)`). A synchronous body only: the result + * then holds those arguments, and nothing else does. */ +export function findRecordFieldProducers( + functions: ReadonlyMap, +): Map> { + const producers = new Map>(); + for (const fn of functions.values()) { + if (fn.async || fn.generator || fn.body.length !== 1) continue; + const only = fn.body[0]!; + if (only.kind !== "return" || only.value?.kind !== "recordLit") continue; + const literal = only.value; + const reads = new Map(); + everyStmtList(fn.body, { + expr: (value) => { + if (value.kind === "varRef") reads.set(value.localId, (reads.get(value.localId) ?? 0) + 1); + return true; + }, + stmt: () => true, + }); + const fields = new Map(); + fn.params.forEach((param, index) => { + if (param.type.kind !== "string" || reads.get(param.localId) !== 1) return; + const field = literal.fields.find( + (entry) => + !entry.overflow && entry.value.kind === "varRef" && entry.value.localId === param.localId, + ); + if (field) fields.set(index, field.name); + }); + if (fields.size > 0) producers.set(fn.name, fields); + } + return producers; +} + +/** Record parameters that every body only projects (LentRecordFields), with + * the string fields some read keeps. Start from every borrowed record + * parameter of a synchronous function, keeping no field, and grow the kept + * fields and drop escaping parameters until nothing changes; a record passed + * to another lent record parameter keeps what that parameter keeps. */ +export function findLentRecordFields( + functions: ReadonlyMap, + lifetimes: CallLifetimes, + strings: LentStringParameters, +): Map>> { + const lent = new Map>>(); + for (const fn of functions.values()) { + if (fn.async || fn.generator) continue; + const stable = lifetimes.borrowed.get(fn.name); + const indexes = new Map>(); + fn.params.forEach((param, index) => { + if (param.type.kind === "record" && stable?.has(index)) indexes.set(index, new Set()); + }); + if (indexes.size > 0) lent.set(fn.name, indexes); + } + const callers = new Map>(); + const pending = new Set(lent.keys()); + while (pending.size > 0) { + const name = pending.values().next().value as string; + pending.delete(name); + const indexes = lent.get(name); + const fn = functions.get(name); + if (!indexes || !fn) continue; + const ids = new Set([...indexes.keys()].map((index) => fn.params[index]!.localId)); + const scan = scanLending( + fn, + new Set(), + new Map(), + { strings, records: lent, producers: new Map() }, + ids, + ); + for (const callee of scan.callees) { + let set = callers.get(callee); + if (!set) callers.set(callee, (set = new Set())); + set.add(name); + } + let changed = false; + for (const [index, kept] of [...indexes]) { + const id = fn.params[index]!.localId; + if (scan.invalidRecords.has(id)) { + indexes.delete(index); + changed = true; + continue; + } + const fields = scan.keptFields.get(id); + if (fields) + for (const field of fields) { + if (kept.has(field)) continue; + kept.add(field); + changed = true; + } + } + if (!changed) continue; + if (indexes.size === 0) lent.delete(name); + const affected = callers.get(name); + if (affected) for (const caller of affected) if (lent.has(caller)) pending.add(caller); + } + return lent; +} + +/** A record local whose declaration stores slice locals directly in some of + * its fields: a record literal, or a call to a record field producer. */ +interface RecordContainer { + /** The stored candidate reads of the declaration, by field. */ + stored: Map; +} + +/** Record locals declared with slice locals in their fields. */ +function findRecordContainers( + fn: IrFunction, + bindings: ReadonlySet | undefined, + slices: ReadonlySet, + producers: RecordFieldProducers, +): Map { + const containers = new Map(); + everyStmtList(fn.body, { + expr: () => true, + stmt: (stmt) => { + if (stmt.kind !== "varDecl" || stmt.init === null || !bindings?.has(stmt.localId)) + return true; + if (stmt.init.type.kind !== "record") return true; + const stored = new Map(); + const init = stmt.init; + if (init.kind === "recordLit") { + for (const field of init.fields) + if (!field.overflow && field.value.kind === "varRef" && slices.has(field.value.localId)) + stored.set(field.value, { field: field.name, slice: field.value.localId }); + } else if (init.kind === "call") { + const fields = producers.get(init.callee); + init.args.forEach((arg, index) => { + const field = fields?.get(index); + if (field !== undefined && arg.kind === "varRef" && slices.has(arg.localId)) + stored.set(arg, { field, slice: arg.localId }); + }); + } + if (stored.size > 0) containers.set(stmt.localId, { stored }); + return true; + }, + }); + return containers; +} + /** Slices whose every reader borrows them are written into a stack buffer * instead of a heap allocation (scr_str_slice_scratch): a slice operand of * a lending consumer, and the initializer of a stable local read only by @@ -304,12 +552,18 @@ export function findLentStringParameters( * non-ASCII results keep the ordinary owned string. Each site owns its * buffer: a site runs again only after its previous value is dead, since * nothing can keep it. Coroutine frames do not keep stack buffers across a - * suspension, so they are left alone. */ + * suspension, so they are left alone. + * + * A slice local may also be stored in a field of a stable record local + * declared with it (a record literal, or a record field producer's result): + * the record is then only projected, and every read of that field lends. + * The record is declared after the slice in its scope and is never kept, so + * it is dead before the slice's site runs again. */ export function findScratchStringSlices( fn: IrFunction, lifetimes: CallLifetimes, scalar: ReadonlyMap, - parameters: LentStringParameters = new Map(), + facts: LendingFacts = NO_LENDING_FACTS, ): Set { if (fn.async || fn.generator) return new Set(); const bindings = lifetimes.bindings.get(fn.name); @@ -328,7 +582,19 @@ export function findScratchStringSlices( return true; }, }); - const scan = scanLending(fn, new Set(locals.keys()), locals, parameters); + const containers = findRecordContainers(fn, bindings, new Set(locals.keys()), facts.producers); + const scan = scanLending( + fn, + new Set(locals.keys()), + locals, + facts, + new Set(containers.keys()), + containers, + ); + for (const [record, container] of containers) + for (const { field, slice } of container.stored.values()) + if (scan.invalidRecords.has(record) || scan.keptFields.get(record)?.has(field)) + scan.invalid.add(slice); for (const [id, init] of locals) if (!scan.invalid.has(id)) scan.scratch.add(init); return scan.scratch; } diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8114-record-field-slices.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8114-record-field-slices.ts.json new file mode 100644 index 000000000..58ce71d85 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8114-record-field-slices.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8114-record-field-slices.ts" + ], + "diags": [] +} diff --git a/tests/corpus/8114-record-field-slices.ts b/tests/corpus/8114-record-field-slices.ts new file mode 100644 index 000000000..69d41a1c8 --- /dev/null +++ b/tests/corpus/8114-record-field-slices.ts @@ -0,0 +1,122 @@ +// Slices stored in record fields: records built from a literal or a factory +// whose fields are only read for their length, comparisons and keyword +// searches, next to records that are kept after the iteration that built +// them (pushed into an array, held in an outer binding, captured by a +// closure, read into a kept array, returned from a helper). Slices of +// non-ASCII text and slices longer than a short token are included. +interface Token { + kind: string; + text: string; + pos: number; +} + +const KEYWORDS = ["let", "const", "if", "else", "return"]; + +function token(kind: string, text: string, pos: number): Token { + return { kind, text, pos }; +} + +function classify(text: string): string { + return KEYWORDS.includes(text) ? "keyword" : "ident"; +} + +function weight(t: Token): number { + return t.kind === "keyword" ? t.text.length * 3 : t.text.length + (t.pos & 7); +} + +function isReturn(t: Token): boolean { + return t.text === "return"; +} + +function textOf(t: Token): string { + return t.text; +} + +/** Calls `visit` with the start and end of every run of word characters. */ +function words(source: string, visit: (start: number, end: number) => void): void { + let start = -1; + for (let i = 0; i <= source.length; i++) { + const c = i < source.length ? source.charCodeAt(i) : 32; + const word = c > 32 && c !== 44 && c !== 59; + if (word) { + if (start < 0) start = i; + } else if (start >= 0) { + visit(start, i); + start = -1; + } + } +} + +function lentTokens(source: string): string { + let sum = 0; + let returns = 0; + let longest = 0; + for (let i = 0, start = -1; i <= source.length; i++) { + const c = i < source.length ? source.charCodeAt(i) : 32; + if (c > 32 && c !== 44 && c !== 59) { + if (start < 0) start = i; + continue; + } + if (start < 0) continue; + const text = source.slice(start, i); + const t = token(classify(text), text, start); + sum += weight(t); + if (isReturn(t)) returns++; + const literal = { text, pos: start }; + if (literal.text.length > longest) longest = literal.text.length; + start = -1; + } + return `lent ${sum} ${returns} ${longest}`; +} + +function keptTokens(source: string): string { + const kept: Token[] = []; + const texts: string[] = []; + const later: (() => string)[] = []; + const returned: string[] = []; + let last: Token | null = null; + for (let i = 0, start = -1; i <= source.length; i++) { + const c = i < source.length ? source.charCodeAt(i) : 32; + if (c > 32 && c !== 44 && c !== 59) { + if (start < 0) start = i; + continue; + } + if (start < 0) continue; + const text = source.slice(start, i); + const pushed = token(classify(text), text, start); + kept.push(pushed); + const held = { kind: "held", text, pos: start }; + last = held; + const read = token("read", source.slice(start, i), start); + texts.push(read.text); + const captured = { kind: "captured", text: source.slice(start, i), pos: start }; + later.push(() => captured.text); + const viaHelper = token("helper", source.slice(start, i), start); + returned.push(textOf(viaHelper)); + start = -1; + } + return [ + `kept ${kept.map((t) => `${t.kind}:${t.text}`).join(" ")}`, + `last ${last === null ? "none" : last.text}`, + `texts ${texts.join("|")}`, + `later ${later.map((f) => f()).join("|")}`, + `returned ${returned.join("|")}`, + ].join("\n"); +} + +const ascii = "let total = count; if (total) return total; else return 0;"; +const mixed = "lét naïve = café; return 東京, x"; +const long = `const ${"identifier".repeat(12)} = ${"v".repeat(150)};`; + +for (const source of [ascii, mixed, long]) { + console.log(lentTokens(source)); + console.log(keptTokens(source)); +} + +let count = 0; +words(ascii, (start, end) => { + const text = ascii.slice(start, end); + const t = token(classify(text), text, start); + count += weight(t); +}); +console.log("callback", count); From 61c32fbc4803a91cf3769c42603fdbfca200c47b Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 18:24:13 -0500 Subject: [PATCH 179/259] Keep Map.get results owned when a copy or a temporary map can outlive the entry A borrowed Map.get local holds the entry's own reference, so every use must run before anything that can release the entry. Two cases escaped that proof: - A local declared from the borrowed local (`const copy = held`) is a stable alias of it, with no reference of its own. Its reads after a write to the map were not counted as uses. Reference locals declared from the local, at any depth of the statement that declares them, now count as its uses. - A read from a map that no local holds (`fresh().get(k)`) borrowed an entry of a map released at the end of the declaration. The map must now be a local or a field chain rooted at one, whose changes the proof sees as edge changes. Both keep the owned read. Corpus 8181 covers the two cases, and the emission test checks that their reads retain the value. --- .../src/backend/llvm/map-read-lifetimes.ts | 57 +++++++++++++++---- .../test/map-get-borrow-emission.test.ts | 26 ++++++++- tests/corpus/8181-map-get-borrows.ts | 27 ++++++++- 3 files changed, 96 insertions(+), 14 deletions(-) diff --git a/packages/compiler/src/backend/llvm/map-read-lifetimes.ts b/packages/compiler/src/backend/llvm/map-read-lifetimes.ts index 0f22f9e05..3371a7f70 100644 --- a/packages/compiler/src/backend/llvm/map-read-lifetimes.ts +++ b/packages/compiler/src/backend/llvm/map-read-lifetimes.ts @@ -166,6 +166,17 @@ export function findMapReadLifetimes( return result; } +/** Whether a map read's receiver keeps the map past its own statement: a + * local or a field of one. Changing either is an edge change the borrow + * proof sees. A temporary map (a call's result, `new Map()`) is released at + * the end of the declaration, and its entries with it. */ +function heldReceiver(expr: IrExpr): boolean { + if (expr.kind === "varRef") return true; + if (expr.kind === "fieldGet" || expr.kind === "recordGet") return heldReceiver(expr.obj); + if (expr.kind === "unionNarrow" || expr.kind === "downcast") return heldReceiver(expr.value); + return false; +} + /** The locals, declared by statements `candidate` accepts, that can hold a * map entry's own reference instead of a +1 copy. The statements after the * declaration run in order, and every one that names the local must @@ -174,7 +185,9 @@ export function findMapReadLifetimes( * while the local is read. An `if` passes its condition's state to both * branches and joins them; any other statement that names the local is * judged whole. A later pass of an enclosing loop declares the local again, - * so only the rest of its own statement list matters. An update such as + * so only the rest of its own statement list matters. The map must be held + * by a local or a field (heldReceiver), and locals declared from the local + * count as its uses. An update such as * `const c = m.get(k); if (c === undefined) m.set(k, v); else c.n++` keeps * the borrow: the write runs only on the branch that does not read `c`. */ export function findMapReadBorrows( @@ -184,12 +197,14 @@ export function findMapReadBorrows( ): Set { const result = new Set(); if (fn.async || fn.generator) return result; - const names = (node: IrStmt | IrExpr, id: string, isStmt: boolean): boolean => { + // `ids` holds the local and the locals declared from it: a stable alias + // (`const d = c`) reads the same entry without a reference of its own. + const names = (node: IrStmt | IrExpr, ids: ReadonlySet, isStmt: boolean): boolean => { let found = false; const visitor = { stmt: () => !found, expr: (expr: IrExpr) => { - if (expr.kind === "varRef" && expr.localId === id) found = true; + if (expr.kind === "varRef" && ids.has(expr.localId)) found = true; return !found; }, }; @@ -197,28 +212,48 @@ export function findMapReadBorrows( else everyExpr(node as IrExpr, visitor); return found; }; + // Adds the reference locals that `stmt` declares from one in `ids`, at any + // depth: a `var` inside a loop or a try stays in scope after it. + const alias = (stmt: IrStmt, ids: Set): void => { + everyStmt(stmt, { + stmt: (node) => { + if ( + node.kind === "varDecl" && + node.init !== null && + isRefCounted(node.init.type) && + names(node.init, ids, false) + ) + ids.add(node.localId); + return true; + }, + expr: () => true, + }); + }; // Whether an edge may have changed after `list`, or null when a statement // names the local after such a change (or changes edges itself). - const walk = (list: readonly IrStmt[], id: string, changed: boolean): boolean | null => { + const walk = (list: readonly IrStmt[], ids: Set, changed: boolean): boolean | null => { for (const stmt of list) { if (stmt.kind === "if") { const preserving = effects.preserves(stmt.cond); - if (names(stmt.cond, id, false) && (changed || !preserving)) return null; + if (names(stmt.cond, ids, false) && (changed || !preserving)) return null; const condition = changed || !preserving; - const then = walk(stmt.then, id, condition); - const otherwise = stmt.else_ === null ? condition : walk(stmt.else_, id, condition); + const then = walk(stmt.then, ids, condition); + const otherwise = stmt.else_ === null ? condition : walk(stmt.else_, ids, condition); if (then === null || otherwise === null) return null; changed = then || otherwise; continue; } if (stmt.kind === "block") { - const inner = walk(stmt.body, id, changed); + const inner = walk(stmt.body, ids, changed); if (inner === null) return null; changed = inner; continue; } const preserving = effects.preservesScope([stmt]); - if (names(stmt, id, true) && (changed || !preserving)) return null; + if (names(stmt, ids, true)) { + if (changed || !preserving) return null; + alias(stmt, ids); + } changed ||= !preserving; } return changed; @@ -227,8 +262,10 @@ export function findMapReadBorrows( list.forEach((stmt, index) => { if ( stmt.kind === "varDecl" && + stmt.init?.kind === "mapIntrinsic" && + heldReceiver(stmt.init.receiver) && candidate(stmt) && - walk(list.slice(index + 1), stmt.localId, false) !== null + walk(list.slice(index + 1), new Set([stmt.localId]), false) !== null ) result.add(stmt.localId); for (const nested of nestedStmtLists(stmt)) visit(nested); diff --git a/packages/compiler/test/map-get-borrow-emission.test.ts b/packages/compiler/test/map-get-borrow-emission.test.ts index 950fe35c2..eba430453 100644 --- a/packages/compiler/test/map-get-borrow-emission.test.ts +++ b/packages/compiler/test/map-get-borrow-emission.test.ts @@ -32,9 +32,26 @@ function replaced(m: Map): number { m.set(1, new Counter()); return old === undefined ? 0 : old.num; } +function aliased(m: Map): number { + const held = m.get(1); + const copy = held; + m.set(1, new Counter()); + return copy === undefined ? 0 : copy.num; +} +function fresh(): Map { + return new Map([[1, new Counter()]]); +} +function temporary(keys: number[]): number { + let total = 0; + for (const key of keys) { + const held = fresh().get(key); + if (held !== undefined) total += held.num; + } + return total; +} const numbers = new Map(); count(numbers, [1, 2, 1]); -console.log(named(new Map([["a", new Counter()]]), "a"), replaced(numbers)); +console.log(named(new Map([["a", new Counter()]]), "a"), replaced(numbers), aliased(numbers), temporary([1, 2])); `, ); const result = await compile(entry, { outDir: dir, outPath, outputKind: "ir" }); @@ -50,8 +67,11 @@ console.log(named(new Map([["a", new Counter()]]), "a"), replaced(numbers)); expect(fn(name)).not.toContain("@sc_retain_Counter"); expect(fn(name)).not.toContain("@sc_release_Counter"); } - // A write between the read and its use keeps the read's own reference. - expect(fn("replaced")).toContain("@sc_retain_Counter"); + // A write between the read and its use keeps the read's own reference, + // also when the use goes through a local declared from the read, and so + // does a read from a map that is released after the declaration. + for (const name of ["replaced", "aliased", "temporary"]) + expect(fn(name)).toContain("@sc_retain_Counter"); } finally { await rm(dir, { recursive: true, force: true }); } diff --git a/tests/corpus/8181-map-get-borrows.ts b/tests/corpus/8181-map-get-borrows.ts index be546cf73..5df7ad226 100644 --- a/tests/corpus/8181-map-get-borrows.ts +++ b/tests/corpus/8181-map-get-borrows.ts @@ -1,7 +1,8 @@ // Map.get results held in locals across the operations that can and cannot // release the entry's value: an update on the absent branch, a write, delete // or clear before a later read, a call that may change the map, loops, -// string keys, and values that are stored, returned or compared. +// string keys, values that are stored, returned or compared, a local declared +// from the read, and a read from a temporary map. class Counter { num: number; label: string; @@ -128,3 +129,27 @@ function loopWrites(m: Map): number { return total; } console.log("loop", loopWrites(new Map([[0, new Counter(1, "a")], [1, new Counter(2, "b")]]))); + +// A local declared from the read is read after a write that replaces the +// entry; it reads the value the map held when the local was declared. +function aliasThenWrite(m: Map): string { + const held = m.get(1); + const copy = held; + m.set(1, new Counter(10, "ten")); + m.delete(1); + const filler = [new Counter(11, "filler"), new Counter(12, "filler")]; + return copy === undefined ? "none" : `${copy.num}:${copy.label}:${filler.length}`; +} +console.log("alias", aliasThenWrite(new Map([[1, new Counter(1, "one")]]))); + +// A read from a map that no local holds: the map is released after the +// declaration, and the value stays readable. +function freshMap(): Map { + return new Map([[1, new Counter(5, "five")]]); +} +function fromTemporary(): string { + const held = freshMap().get(1); + const filler = [new Counter(6, "filler"), new Counter(7, "filler")]; + return held === undefined ? "none" : `${held.num}:${held.label}:${filler.length}`; +} +console.log("temporary", fromTemporary()); From ecd103d1fb904cdb5f8fe298261aacda03aee265 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 18:32:42 -0500 Subject: [PATCH 180/259] Keep the while-loop bound off counters written inside expressions flow follows a while body's statements and applies each increment it meets as a statement. An increment inside an expression, such as an if condition's comma expression `if ((i++, i > 0))`, lowers to a statement nested in the expression; whileBound accepted it as an increment, but flow never applied it, so a read after it kept the pre-increment bound and lost its bounds check. whileBound now gives no bound when any expression in the body holds a write of the counter. --- .../compiler/src/backend/llvm/bytes-bounds.ts | 12 ++++++++++-- .../test/while-bytes-bounds-emission.test.ts | 14 ++++++++++++++ tests/corpus/8003-while-reversed-byte-reads.ts | 15 +++++++++++++++ 3 files changed, 39 insertions(+), 2 deletions(-) diff --git a/packages/compiler/src/backend/llvm/bytes-bounds.ts b/packages/compiler/src/backend/llvm/bytes-bounds.ts index b35a949ff..29b1c8e15 100644 --- a/packages/compiler/src/backend/llvm/bytes-bounds.ts +++ b/packages/compiler/src/backend/llvm/bytes-bounds.ts @@ -300,10 +300,18 @@ export function findBytesBounds(fn: IrFunction, ranges: IntegerRanges): Readonly const receiver = length.receiver; const comparison = lengthComparison(cond, { receiver, counter, offset: 0, minimum }); if (comparison?.op !== "<" && comparison?.op !== "<=") return null; + // An increment is a statement of the body: one inside an expression + // (a comma expression's statements) would run where flow does not + // follow it. const writesOk = everyStmtList(s.body, { expr: (e) => - (e.kind !== "assignExpr" && e.kind !== "incDec") || - (e.localId !== counter && e.localId !== receiver), + ((e.kind !== "assignExpr" && e.kind !== "incDec") || + (e.localId !== counter && e.localId !== receiver)) && + everyExprChild( + e, + () => true, + (child) => !writes(child, counter), + ), stmt: (child) => { if (child.kind === "assign" && child.localId === counter) return increment(child, counter) !== null; diff --git a/packages/compiler/test/while-bytes-bounds-emission.test.ts b/packages/compiler/test/while-bytes-bounds-emission.test.ts index 2b6dc1d3c..a2604eed1 100644 --- a/packages/compiler/test/while-bytes-bounds-emission.test.ts +++ b/packages/compiler/test/while-bytes-bounds-emission.test.ts @@ -119,13 +119,27 @@ function nested(line: Uint8Array): number { } return total; } +function comma(line: Uint8Array): number { + const len = line.length; + let i = 0; + let total = 0; + while (i < len) { + if ((i++, i > 0)) total += line[len - 1 - i]!; + total += line[len - 1 - i]!; + } + return total; +} console.log( + comma(new Uint8Array(2)), inclusive(new Uint8Array(2)), unguarded(new Uint8Array(2)), ahead(new Uint16Array(3)), nested(new Uint8Array(3)), ); `); + // The increment in the comma expression is not a statement of the + // body, so the loop has no bound and both reads keep their checks. + expect(checks(ll, "comma")).toBe(2); expect(checks(ll, "inclusive")).toBe(1); // The read before the increment is in bounds; the one after it is not. expect(checks(ll, "unguarded")).toBe(1); diff --git a/tests/corpus/8003-while-reversed-byte-reads.ts b/tests/corpus/8003-while-reversed-byte-reads.ts index 9b2efd4f0..1407b9324 100644 --- a/tests/corpus/8003-while-reversed-byte-reads.ts +++ b/tests/corpus/8003-while-reversed-byte-reads.ts @@ -166,3 +166,18 @@ function throwing(line: Uint8Array): string { return String(total); } console.log(throwing(new Uint8Array([4, 0, 2, 3])), throwing(new Uint8Array([1, 2]))); + +// An increment inside an if condition's comma expression: both reads are +// at index -1 on the last pass. +function commaIncrement(line: Uint8Array): string { + const len = line.length; + let i = 0; + const out: (number | undefined)[] = []; + while (i < len) { + if ((i++, i > 0)) out.push(line[len - 1 - i]); + const v = line[len - 1 - i]!; + out.push(v); + } + return JSON.stringify(out); +} +console.log(commaIncrement(new Uint8Array([1, 2, 3])), commaIncrement(new Uint8Array(0))); From 383b69cf2df230e4d9f8c529337612163a569bd0 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 18:39:02 -0500 Subject: [PATCH 181/259] Represent record-only unions used as Map keys and Set elements as record pointers --- benchmarks/runtime/README.md | 1 + .../runtime/workloads/union-node-sets.json | 6 + .../runtime/workloads/union-node-sets.ts | 141 +++++++++++++++++ packages/compiler/native/cli.profdata.gz | Bin 1751358 -> 1806722 bytes .../compiler/src/backend/llvm/emit-module.ts | 6 +- .../src/backend/llvm/expr-containers.ts | 4 +- .../compiler/src/backend/llvm/expr-control.ts | 86 ++++++++++ .../src/backend/llvm/nullable-unions.test.ts | 32 +++- .../src/backend/llvm/nullable-unions.ts | 31 +++- .../backend/llvm/record-union-keys.test.ts | 148 ++++++++++++++++++ packages/compiler/src/backend/llvm/shapes.ts | 98 ++++++++---- .../src/backend/llvm/test-boxed-unions.ts | 33 ++-- 12 files changed, 540 insertions(+), 46 deletions(-) create mode 100644 benchmarks/runtime/workloads/union-node-sets.json create mode 100644 benchmarks/runtime/workloads/union-node-sets.ts create mode 100644 packages/compiler/src/backend/llvm/record-union-keys.test.ts diff --git a/benchmarks/runtime/README.md b/benchmarks/runtime/README.md index c69ec43d9..83cfcb831 100644 --- a/benchmarks/runtime/README.md +++ b/benchmarks/runtime/README.md @@ -36,6 +36,7 @@ Application-shaped workloads for measuring the speed of compiled executables. Ea | `typed-array-kernels` | cpu | element-wise loops that run to one typed array's length and index others at the same position: `Float64Array` axpy, `Float32Array` blend, `Uint8Array` mask, wrapping `Int32Array` add, `Uint8ClampedArray` brighten, RGBA to gray, a row-major `Float32Array` matrix-vector product, and `reduce`/`some`/`map` callbacks | | `typed-array-scan`, `typed-array-scan-workers` | cpu | element-by-element scan loops over `Uint8Array`, `Uint16Array`, `Int32Array` and `Float64Array`; the second entry is a worker-enabled executable (it can start a worker), so each access also checks for shared storage | | `unicode-lexer` | cpu | a hand-written lexer over a 2.7M-unit bundled module whose comments and strings are in several languages: `charCodeAt` scans, line starts | +| `union-node-sets` | cpu | syntax-tree passes over a discriminated union of object literals: a `Set` of visited nodes, a `Map` from node to value, conversions to a sub-union of leaves | | `validate-errors` | cpu | throw/catch on a fraction of inputs, small call chains | | `value-objects` | cpu | small immutable records and class instances: vector helpers, method chains, particle updates | | `value-records` | cpu | records that hold strings, spread state updates and destructured tuples: token helpers, an immutable reducer, tuple returns | diff --git a/benchmarks/runtime/workloads/union-node-sets.json b/benchmarks/runtime/workloads/union-node-sets.json new file mode 100644 index 000000000..98e9fe2e5 --- /dev/null +++ b/benchmarks/runtime/workloads/union-node-sets.json @@ -0,0 +1,6 @@ +{ + "entry": "workloads/union-node-sets.ts", + "args": [ + "1" + ] +} diff --git a/benchmarks/runtime/workloads/union-node-sets.ts b/benchmarks/runtime/workloads/union-node-sets.ts new file mode 100644 index 000000000..16d6f4dfe --- /dev/null +++ b/benchmarks/runtime/workloads/union-node-sets.ts @@ -0,0 +1,141 @@ +// Syntax-tree passes over a discriminated union of object literals, the way +// compilers walk their IR: a DAG of shared subexpressions, a `Set` of +// visited nodes, a `Map` from node to its value, and conversions between +// the whole union and the sub-unions passes narrow it to. +type Num = { kind: "num"; value: number }; +type Var = { kind: "var"; slot: number }; +type Neg = { kind: "neg"; operand: Node }; +type Add = { kind: "add"; left: Node; right: Node }; +type Mul = { kind: "mul"; left: Node; right: Node }; +type Pick = { kind: "pick"; cond: Node; then: Node; else_: Node }; +type Leaf = Num | Var; +type Node = Leaf | Neg | Add | Mul | Pick; + +function children(node: Node, visit: (child: Node) => void): void { + switch (node.kind) { + case "num": + case "var": + return; + case "neg": + visit(node.operand); + return; + case "add": + case "mul": + visit(node.left); + visit(node.right); + return; + case "pick": + visit(node.cond); + visit(node.then); + visit(node.else_); + return; + } +} + +function leafValue(leaf: Leaf, env: number[]): number { + return leaf.kind === "num" ? leaf.value : env[leaf.slot]!; +} + +function evaluate(node: Node, env: number[], memo: Map): number { + const cached = memo.get(node); + if (cached !== undefined) return cached; + let result: number; + switch (node.kind) { + case "num": + case "var": + result = leafValue(node, env); + break; + case "neg": + result = -evaluate(node.operand, env, memo); + break; + case "add": + result = (evaluate(node.left, env, memo) + evaluate(node.right, env, memo)) % 1000003; + break; + case "mul": + result = (evaluate(node.left, env, memo) * evaluate(node.right, env, memo)) % 1000003; + break; + case "pick": + result = + evaluate(node.cond, env, memo) % 2 === 0 + ? evaluate(node.then, env, memo) + : evaluate(node.else_, env, memo); + break; + } + memo.set(node, result); + return result; +} + +function reachable(root: Node): number { + const seen = new Set(); + const stack: Node[] = [root]; + while (stack.length > 0) { + const node = stack.pop()!; + if (seen.has(node)) continue; + seen.add(node); + children(node, (child) => { + if (!seen.has(child)) stack.push(child); + }); + } + return seen.size; +} + +function leaves(root: Node): Leaf[] { + const out: Leaf[] = []; + const seen = new Set(); + const walk = (node: Node): void => { + if (seen.has(node)) return; + seen.add(node); + if (node.kind === "num" || node.kind === "var") out.push(node); + else children(node, walk); + }; + walk(root); + return out; +} + +let seed = 2463534242; +function next(): number { + seed ^= seed << 13; + seed ^= seed >>> 17; + seed ^= seed << 5; + return seed >>> 0; +} + +function build(size: number): Node { + const pool: Node[] = []; + for (let i = 0; i < 64; i++) + pool.push(i % 2 === 0 ? { kind: "num", value: i * 7 + 1 } : { kind: "var", slot: i % 16 }); + // Operands come from the most recent nodes, so most of the DAG is + // reachable from the root and many nodes are shared. + const recent = (): Node => pool[pool.length - 1 - (next() % 48)]!; + for (let i = 0; i < size; i++) { + const a = recent(); + const b = recent(); + const r = next() % 10; + let node: Node; + if (r < 1) node = { kind: "neg", operand: a }; + else if (r < 5) node = { kind: "add", left: a, right: b }; + else if (r < 8) node = { kind: "mul", left: a, right: b }; + else node = { kind: "pick", cond: a, then: b, else_: recent() }; + pool.push(node); + } + return pool[pool.length - 1]!; +} + +const scale = Number(process.argv[2] ?? "1"); +const rounds = Math.max(1, Math.round(40 * scale)); +let checksum = 0; +let nodes = 0; +let leafCount = 0; +for (let round = 0; round < rounds; round++) { + const root = build(20_000); + nodes += reachable(root); + const found = leaves(root); + leafCount += found.length; + for (let pass = 0; pass < 4; pass++) { + const env: number[] = []; + for (let i = 0; i < 16; i++) env.push((round * 31 + pass * 7 + i) % 97); + checksum = (checksum + evaluate(root, env, new Map())) % 1000003; + for (const leaf of found) checksum = (checksum + leafValue(leaf, env)) % 1000003; + } +} +console.log("rounds", rounds, "nodes", nodes, "leaves", leafCount, "checksum", checksum); diff --git a/packages/compiler/native/cli.profdata.gz b/packages/compiler/native/cli.profdata.gz index 31423fa043e0a12aba496a4ae1604d79da4773ef..aa9398b5febacdfdc156d2c385c07312e12909f3 100644 GIT binary patch literal 1806722 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≠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

    m*OE7LK= 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%0A{?@7M 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

  • w_bYHksWL?#OZ@ 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Ξ!-T!N7k_2P+D{C3lJ-ubx;yT_iq9Z>?6P|8SLovMfs8;6i@SbA>E#VTi z2-lAGG9QcdN1GK6=8vt+LoY}?YYliI`jyQtJ^Ab0;ApkMI%3(n5mr5+kH)K}j=m?EISURix< z^f4Ny_xfoM?SJ1_^@4b+;2VokFv36g(@gG1t&2hrCYK;k)!%T+__H(2nMH=mCS#dG zbrgKpTrm)YzZbsblCPB@Rso$n6EO}^`!7YAIAI_1`jG{wdLcP3mq%jl7pVR0Lj#}? ziz*z9Q6KkNz23U9xzTRBQM};&I0xmz5XD3pmMW?ms6mUGOK2Xsr0q^L`}NK^u=!;@ zB0x6E#^3l<4!j+5UMv1cO|;b1^#M_wdFBRU;K{hlp)8*yix;R1X{biFySiOCdi*|{ z@Zyd1a}@|-FgfSTozlOXw$=OEsrblDmcOQJmV&}%T)nu-3L466c&b#(8C{>q9?
    4K(A&w;e%wG)z4g4TMzVj*UnuFqL^s^48R!%vM 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]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%0ATB!i@_r|K@81IwN@I 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%0D(sOE}2aB<<*K2Q_Vx-C9 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%0DZN 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�xu_KTjY>W6e}@uB*}uaE`7)Wg}KideN+X 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 literal 1751358 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 z%0D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 FZb9Q_mW0nQa`|zjX^=^02Ug?S~ME+oD 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

    OaGw0X0$FmR5F_ACy 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≫={Tk{t(BZD7H!-XU6b4sPhqL$hdLS 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

    oV{Ezg6C?D0&7e{@no9S+X1r++~X_7tF)g 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 T#+&My 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%0Dpv=6^sL;#aedv%=`Sz5;aoy8)F1fLkt61I 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

  • K7I{Rt0Ez+YPt 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%0A=z%r)FY!#;I7012uh!8fi}Z@m};c#wAb0 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
    uNBT8?bFx0Z7{W<3l}8j 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

    9C(vwyz$$*DzRy#7SAv(4y4p zF4Wqbt1v8LAkSg#Hay;G$X~S)+qfPL&_hVe`pUMijIH>$ptgkbnoRUYfu2}@2r7L; zbp))+3Py`y6TwZHePyB`kxgyEGgrnh7!K1&o_Rbkj&kKHlwvDpeS7eyGvu5 z^2gH@8)#~3O7ydoI;6@DARQ8nNb`5PfozYtSmg==0b48c zpLiMRd%wo$Ge<5P++woWBX_tEbKP#-^lv0{o(gxU zPn699EN6qzqxIv@@1dFECL z&IM|kwt{@medkICe>WyD{JBQJ3{bU(<9z8PeTG2G35Y0wP|FA-B)qfZ79sm@m9Ldu zHsk146ld7|=BOiJ6);ad_zSDP$-gD9`a9GnBy*gmGo4WxcizopTP%O>dro;3XK#o+ zs$BLu|JTM8j%f1}%El-K*57}3&t$jOrdtW_Pr%CS!|O4Kp+CqVl;jylFUjo`gl@qi z4?IehUI`~J#nrZ5{Qz<9ajUH?rc^UOPNruvNQN0?1g%_S3RGaunz(xmiU=B8p|^EQ z9p~y@p>Ppz9A5Q3 zfTA*|x^bwM<~F+=Z^^fVY!dsb;m4n=npGVoZowlcpDr!E?LNlgl(Q zP2rC|QD1dKR~{OrHgWXh+r#ib_9+>lPo76Gi`x*W zY4MZ0@B?y=!*fp0kh8Fp2d-*Ojw51h-U>Ko0_(e+SelwP-IW$@bi?3J{%FbV;XxJO zwrEj}RCi6|M{%@*hlVY-u{BI&Q?RTsJJVr}WvV@K1owOwbC;%2k4{Y%1I2ELLUGh1 zk0eufl@E=gv_nqT-WE+yK+v;ZB9rvMva#rbtKG}OD16+Q^VA30J>{(p%Fm5+Y!7 zco5`=qwrg3cKLF8qNj(=GvK;_6v#OYBqvL(!gHc=$gH8#jbiFM@8EtoMy+iH@++wU zFgOwG8pf3W34Tilj<4>G69>Exs88=YV6#)oBQY{vf_i3bCI5BaJrh2`>H5^hfz0o6 zcZ84`pMYhJUWxlsF=|pV={LKlA|!?y4B~F)ksSJ3x7da;>O6TrmHBcj=dh_p@C#WP zY3k~0(uv1^;w_Low)3 z3s|77n9oPw04SU*;5imH%xS*~d(DO_-k^@eP@wld5vNO(RwW##$CTK3)%!>~zi6JA z5&6s;`Y7z1WuF2!BR483l(q4*RvrX&k=);V--JP{6ypQ;5mHsKftrx?i=aiakbs4o z*FWt}{0;xY{c`di|EA8MF>65jZY$tGC?u)J?9)9Zg>@{%sJE6D@BmwetZtT~7FuwHRWMvi{ymHefbo754QI|b8`X^{v7j+B$x8zLW2fhG9*Qr@bK= zgPd#*xO-j)c+)IykAFQWh74`fRMqL>*E$#8Oe?pa2IY?qP|{9*hI#eQ!eG^8dznvJ zVof}`Uv2+*LXuz{?x{fQh}a#m*sQbfHF+iCDURJPeKn?eUNV4OW`2 z$i_bt6j9s@Ccg?_zr`b_s;~a^T57$lj_Js&{d!j**c$;Vi%%AvWAs+>Cow_pto5!E z);|;QXnYBXK|E{3_25YNhC!NyYXn&mZM053ALQNI(NRw`DqYeL>}g#_+w-lvdEXwT zA>}i3D$p9@rQmP*++z&k!8yJG49Q00~nr=D}QFJ52 z4C_1SuG}hVZ}3KGf@n{z4QI!h=mrQN5IRq?oHLSTlAXM`<$Z7Fn&#odaTCYG;tWo_ zbTn=WScp>Gj54F_THBbod~>?jhd)f_d(Y0I<{i?2!a#Uw=UYFDQ<3H=4OV!uU!lA%41&8FE^R;u4JvlF@ruI zlRq|j;|4`A8UA&Z6tp<<)q!nbZMbU_aL-}4KCOReh%C-|@~~>XwAp{2di~5R_SMl##+!=e@^8+{3SV$B zs2+7&O{POFpHELz3VLAqAC`lg!3`HayNURg>g-;MydW83c28aAuPDuT6;(Y92H$g^ zDnjq)*ol#^9l`bSgv=efh1j7qUZEyl=i5&z98uDOQwr=u2~^d$8|*usHR{w7-B1aT z*+k6Y%ZhAP+lNWs+LrZB%$iT`aRwiYu{8NU2^R_dUy-+v;1f%%B31aVDm1!3J)|0y zq{Mf-1G@=h^dtb!S2x5Uahz`%NMbwJdhUUBN>E<+dTH50I7D$8f5`&YT0=m>AJs~A zD$P=g+t!&zR)|(sYUkZ|%;OD1^2YvK$-`YAw*j?%&m<9Ne;C8e#f1sI|J*o(R-nZ; zA<~8!{$R&fpA-0xQ#vnOFi_^bKNA_^xwU+lPh&!L32{6l+;Q)jmdzE7M8W`^VC18c zBc#J#R6L+x?d%AjYVJ203(S$a2ne(#d6$2C4hfH}(2VcgLAB~T1ExT0V$-&*0zQb! zG7t_mYX=!0cksX0Y^-5pWgMFzq72VcfTSy;zl#%_YMv@+ ze_%KJYC}NdJ)?$Q_8 zW}~Q8(f758rg1w4(HLJ(GLZ%TZt(}7v}r_xYZlyhMjD&YYZc7H*-h}$j-!zbmu7}_p!quk^MIE)%}{8lahX7 zC-GzM`R3vsyKc^qO*ty_+M zS=s6d{_ zTgNu*4x*=WmB?QmM%VzUEetE#e2Uv{W*y30k6^Z_zo$Os3XM31!tk0wYL&A;WmrRG zp>&k7b?&QQ>kTd_z^nP-rw)6Ro$sA9$L(`A(eH#ygTy#X#rln{YijpjRsN&*$i7>f-n` zi((!m3wP8`xWepn$>;;hDF$d5@#z$Mnxl8@y@fdB$ul3LVkRm)n>YUS1^bX2<2$_= z)(yHKA9%&)^QCM96k&HCH1CA2pMHaX7!kNh8y~CC2v(~D(Il$-45C*nOJI4D{O>#O z-rD@Yt93~!Mb=@(l0g`ffkj%VIaP+aa~)(WZ4r5X0``I(`I^99zA_9dwklbUrhzeR zBX*vp)3@CQlyX+f+YzqHzc%N_TYtaw)g3>Gcd_+G=#IF z{T?{(#~!32%S`?7o!QfUfah?L$>jx+i5#xT2uos(DA(Zgx%gv{kLqH11kuXl5RnY4 zj1(u-(eJc>`Ee*99mDsp93ea)r`qxH4)r*BoS}+z6ubYjB6E#Jpw)gnY)J)gjJ+3z zLbj50{h4R0Q5D?&+=}5wamOE8rSn58pO$jmi88XnjXS4zvUpGUA~PoZ%Xvt)y;x@8 zbKs%GN%*WmxQk;;<|&NWB(%DhOzDu)-#LE6of@pelSC)Yd8q;OKN3U5QAmS}9DU{w z-bBm5-@}a7{s7!R`nUv`wRO%WF)W#iz^mN{rX&i91=$lR>9G~! z1p$R{adhfH&HP2@zSg%6YlnR~yE{XBR(Q~;W6{RWHB@UQi6dmIL}1vSyA-vsXU%+7 z^V^hV&vue7CZf6!u4_cgNt*H9@)wsv42rqg7 zAfiNFXO=VJknU?IB}_0(H_%Ut?H>He&I?l)LN~Ort=O|PtvxH4H?HvB(JhtL* zADLRmS1xA^hlzdBzymbOG`rGW;g%o zvUUaq44f1iHNXKy!&I#$*F<|*fYv()$s%DCm881ax7;+zR8?~3;pPZc8s)zfZm+eq zuXi`z4$^jTGM7Mlq{O~*sMT0SgtjVl8ful%{icStakXqOAj&DL0Bq<5U^T=zWlxl}gzs*gZe|#v7EB z;N_1#fB*cx@t~EZe&rEi%V+W~19uJ|W>(oFOze5CYCU=Z`}x@)Mf#y?uXRRC-bwv6 zX?WqGTUdnkX1%Yhlcj-@E(u5rNc{QtWzl4NM8#p>&~dwEE5N5|yXi-?9P0%mnAOzU^r_a|;{59UnJ@CJU=;)Th|E^X;5K;O9 zs@6a7o8qq4y)za`jvkoa*a^~BseEhQ>Bbf44_=f>Al`_2_xg9Ay8)4n>qSuu(>N%Y ztZ%XRGSaXP;V9N<_PH9;haLwE*(@|^mjX5jN4iqMC&g#so-dBgeVqe}7Xp*<9+=+FTEFJ}gAgjGy^kf+KSLpYTNmtK(SEcM( zQM=TVcZv73yq_LuuCEwQH@P%0;*?gYN7k9-6uwpNOIfa{SY(Ce0hu>pPJbM}Nh-K8 z^vaUBw+;ainP#$~Xi+*9J28^%f{Ooq+;h-y->m?vdF35Br_r&8U8-oMAAQrSeCC8R zE%d})0_J?c7yi!%o_6g4`&w4a0u=F3@{#!cbY~VeaJnjRG+Pw^2eUv-zc>~YmfUX& zcxci=NCo2}OV(q9vb24~)PBHa_WX)eXo7{qE@9E4|CiTp9I91@jaGSd356$Ud2f+iyMK^_G6yWbKj>Xld zwLdkv>4uh9x6^;QA+oEo7?H4NNnT|_@J_WXDU*gtZYisuJ3BYWGgK2l+k0QoPX}rw zf#Tx#RR{mU{vX}fHWl9d-WD11qo~UXz-bDph=fWK{F>y{Pp_}KHt`Al(?80Yb8!Xi zAOxc!B^Hz8l@y?#1{y=S7KCeltK+M53@wo03Bb$Mjq`!+t6RqX2d6`2%Q{(50Si%$sp)O+~EXnJIHc)Lm`nyHF%tV!u^A#i=N9Vt1**?>66xQY(c)W#K;Hz z4$TjJjyfed6(@tV7W4i88sIz{y?A0~i$~wz)Hbo;8S8)NWcz_1y#ZI0LwMOqun%%x zFF7Xxx5qwNa*oP-rorZ{u1`;@gj*eMMbb0i>a17i6Kj0m;lAIB`L1hXc)CZNGD%15 zY!v<0hc@l4U8^ZVfQB(jXiX#)O<;LaX6}FL;QEEzHm2YLXvC75N@@~U*7?QC2k-c= zi~qguIZ3a6AH~-kL$f3)k}OTL9M7Wrj=Gg%@yc%g%z5;RGoRpt)bJ$Bh#X1qEX~m* zg%@c zW|OFXS}8{0HHlO;E;2ymCb$(w>b((5K>hqbFHQ2^F&8obgRoZmE{zxLy`&s(t{e1q zW>2wuyprq$L*0(?4%fC0zjf)zs#Rd5t5#{@7==4@Jj!CcCU(<@qHaR?)^Ql}{xHn@ z7G#eA0a}l@NeWMwo$NBef5R7>KRmMr=Df~elS%QUeTv)R1)f{vg}*;bt+my_&;^=K z!#po<>uOwhC97qK|G9Q|o;bU?d6Z2x9}JHflGBFfcpX`e+ofO#wqIJ-s}?xCq#&}_ z!$<*WaMOn|of4_18tUKZ-#Iz~9}I|MSYD(khNpOuVMGySifKB1*f5d1hWe@5uJP=4 ztfN5=P=YMTBo7D{=V&lqqOw_r`ICqA700rk|n^<%mr=HxxZUKHZvIdFs&BF z+edl$QI0H!YrLUo5B(`sE@DFUgq|5AsP@;O&P|c_*g2G8a;544^oAh7#9}8z*2@<|N7T0>_Cw&2d5`3vCob)UjGL|D>s_`j614$P$q4 z7th!SIboFV;10isC(oty1Fn(4>vaMZEjvBtGCkg(`pP@UdVr`B93Ui$krb9Cfs9IU zb+IuWC-~d;TDCiVEu5r;VVqEvVt7dq0Vfdbqg|>#v1i*4iBQ0vi)a|SV>EZ@Mg)zj z-3}QF$aqx!!?)qFi~itRjK;GAqJe~+wJ0$>pV4~%!{eJV80K0MCQ`KR6a1Us;9goJ z!#>X`96VLA^Aua}+rNJa)Qs=}c`Alxr=(J!%`(ydVwKVBe`o{8{D949%qfu(1W^)c z1t<%bxBc1n(%Hl@7g;+})^_hVUgq^LEj+lh0Z&4Uchu)q}`e| zynM}iapqxp17zEi{M**IoqlFjbG!;8Y_G*o3eOXQN^A129+p?4#R57RxBZgSzhMCR zLH#*!F~T1B7{nHkv(>!ee?9)t;-{Nbfs5KtGwOtu^l46=%X-qoo^tw+PriNdrV$-t z?aWAlu=jPiBxhd-aH<}=lI`+%-MNZ4+dcp55kj}u(rj=~mST&wC(HHUJ@R^WXD2u{ zg!uP^gQc7yV9NFz>%LYr_)1=!&9z#l`u&gH^yWLm;ZCVqvVlm!Q5VYUndb#Va08PqiJepzl-6b8j zc>5&*(~el_%wpEdip+~xV2h!UZ*qn21x>g#d;fMZ=3%T;v>Q<6G(t$|sbKXO`4#Se z@AU6|WX;^X+4UlKy+!muq{4`z00fq17CxPn1C7^;Oku|Vo{m=hp&MnOb>~Dcr9b}QDV9%0V2Z%KlH)?;#N_Qa&CXo* zR8_c!{usB`;35CnoH6b0PKIk~HN&-(AqasNfK1VhbjOq&8<7W+;aYGfk~dev^&Yp= zTKc}elSf9aIr1Fl_vpHCa%zC&2m7_ScSG>zG!Oghr*ISR&up##vdv)RXo0hP-I6k? zms9e1E~uJ%xxoe7rioLot$J?fj?`F&d}pnf3(I-L-+uoesl$e6Mv}5Ss2g>->~2}0 zNR?$sLQ>R&=SR(CD}9gwhp-L?qa{7!-*6HbMUMCoDRTz@u37!%NMfyw0ekgdX z4vi51HzI@|zB+o_R_T3zu1>rY>oNb1KgKm_djgW_oaoA8f#eyE;RH$%>AU~E@%`^J z_g5)z|Iw9V4&*%ljoa4_-SQHo>~%>-9n7hKVkMrCSWSZg!LPqy8``Sl@fOz&O?E)MD1K-O-$S=N8xh%xS#Y4=rD+gYKtQW@2LPqAz3COPW`LctQY#{)t)LmlK?L- z&oEMMh=kpp>+(9XE|{ffyCmnJY(;Vo)n2^i$PTT`WT%1P_>4W)^qQDL`o#FX zPYEkuqm=LCW$~x|TNfWW{qBdbmy4XyyMyvKu)8HiA_-nrI7N_Idd}hf{tX3^XU$|| z97`!_wLI^id(SmJPM(Ca=nYpHiAoyFvJ@w<3Qtnc+_8UEtFOPejJJh1q=BBUhRhl$ zMP02A{c>gzaP|KSPb?B!3L z>t*Tc4LBKR>K!&+*J)PKk3NpQ7~UU!ti~JbN%}uEtC;j<(w9kJCViERzRYno`9^v0 z3#VSuoAmcj>*=-nxJ{l|G3trZ1A1No>7u0b1Er^U=LwGP(D}0fqj*ol&?TH-IQm5A zT`YP<=Ov_Hbbg}r4CgCK*Kq!#^bO}TO6TbOenzL48|sGBA*4G@ z>&oRucd_b+wx_u5EA9JGj%{#vXaq-n5c;5hC!68#+jV+?&u8oT!RP4vjQ-v-oie-K zWeNNJ%*^oj>+8o|cjzjB_4>HHIn!eJJ^Zepp3ikD;orf07+tYbAF+jf1r($4{psw%hq!9!UB#w{- zji2-4>pve~R;w~x@?WuqV+c#Fv1siz|ITNw{-Rk&sBn&S%S;js%@7<#ktD^S)>UJ5 zGn9iEUknMB*ZmLl$U1oF$LRLhfMx|!6eU$5X!PiV!1$DY-4E;&pT9F38lDs}t8%Jt zJ1LMsKf=K6kerU&!M@u2YM-k7ZGoGvz8Eq|v*1d5cHp$VyECHt1*2t|7F32235`Vk zg4MJ|l0)>dS?>SyxVPr`RZ$O(NLeN&isNNURneaNdqNT>>lOY{+l2?jM@9UogielF zfwT{Bd1|C@QtK^ljX#yUaJ@`& zNzT06!QgB)*9k6EVWczL>-m^|X4$&c_ohQ}y-6wA?JECY16wqELXFzVyhx}tK?}5~ zMBI`;jkV0r_doJ)`u zT}dQ;5^*fP3P~?P(i)N;j-(qR>FP-OIAT0H2T6}a(%q4C7bI;%(q|CUzg@dGSAmmrwg0YJTYmiMsVHs*d7fqkL7+&EBWW5HSUSXT=epXz>D^{6#UG-IV!X^K z63I}6CbFm~)=bwkb(pKK!TS0?^Q!Q4f=#8ZzhO8Twa#}Pj<7w8gjK0GO*6aNDeNg|)YsW*;(;zU%h4t4B6yTT) z+(R{M^&~1iuqY7@O4&OnUGH!1{HIyU5xlctO5jD2XE}l+SdJ%A0`99jRJ{u8qHu%% z-obAj%6SFr8Iw{Ng;qG0U=;@Sj9I{v65?&q2mVdF$eLQl+p9vhz1i%mZ&_G<0x4b z2$=?oT=!+}V9;h1O0n;>3K91Yx`+dR??qoK4eH1Kk6vE(^`gv1(UdhJEr_b5392M; zhTefI#lVr}e(Il9`_AX{R>4JOjrxhc?SdUglsi+#Eg9k(gU?h$#<{1 z$jeH)#e|Z8Rd-x`-)*`E&K3S#_Z4n=D#o~`mvG!;iI=6l5(dAoXjcudiZfl>-%W_M z?0@b5=q7D;|Hq)#$-t*k;Uy`B5lCKDSxr%tksfe$!r^lnDRGi=MvQb}m45c`8QH;c z)gI{V?NMtK&Oh4i9O;$34kgI;YyW)s<~lty6QEE3yYCCf-|DtbJ$r;>2_;Ri_Xoembp()959+u=ORr>zBd7Im{tuI0oRZ1G z#;i1qw!mtfEJ`fL@}%@#(?)wcCL|}0xX1$_#Q9!%9a&y(lKC*C-zxvdb{K^;{)hkP z?8B!rU#O2?y0S=$vrln&CpcUeEL0ACHTZ?16KdCMp?UG;xDXzDs|{1wpZ@E6U6(Gr zRp36!W+3xK-r^qZ0YkM-cOGnd^obj6y^yASrZe~c3qyE-E&TUq^_IEyh)J;4ujmZt zLnJ?V<^V0r;df8f57%KrfWOBJ>-4zsbM>B{k32ttST@c@=60)cp2}AqiT~q2x5s_( z-cOrEF7FWvG9XBdLdXiM(&Xyv?&!Srsd)t_&WLs;B3)caDW{f~m30%|x#uZ=t91`E z^=n2sa}GKrBQ;UtNm<|o<^A46-l;r*x4}`FoE#sHca%^0t5kjX^!I0>L^dpnHL*r3 zvLthwsxpfv{yNlGdtqXW80!QsUDoRnnl5emqspj$qoR;TxNnEk{_OjC*T&(|w?dQ% z085CRtZGc}buVnMQ)DZ26N2#*`;33x`)mH$yu6+zyeg<)JXIzL8Zd;aJvugPRNFb5 zOC7!F0ll(MW5^ULUOfrn@7F>!ukg7C+5X*}5RT_0lzi%jhZH{R@7{k~_FPX4OJ$J< zKoDh$W(ib4|9W5z!|^!lzj|}CRZlE{SI@df=4=#J!6|vXqdj17_GIAc;S6d!)KN)i zjubs^>8EeZX6d(yfQ|*MQEE~kH+}V?50Bw3sAyi~1cu^Ch9g*tL${1a6JilxYT#U# zf2!2k4D~lljr2FHV3%@ofJ^P;^1AavR=%Ex-aWlLkaABVw0`{?hRG|TUM5~I+m%bW zDTwv_?_wU%!1w=7C|!HY3h>OVQs8}c$@k%$!#x` z;(I35u!w4b*T0z7qV@S0Iu?!QS%G6UO_k8fKUfXdDb)ka`;_&LV{n(TGR=UiQA|iH z-N)_DcK6M7DZy=8P&2*Y<=Yp1R^^!_%5?T-f(a&EreGehhG4=A@x3=ix2wBuO4*dV z{JFAi2h0yAIg(S%u{Pnq1BLQl&A(s~f4VDZJMpNgM+Nji+dqxo1T3(xS@$ z$}u))g+*ls68k6;@2!tl8fK9+VRwTZ$?X9ny;G0+i2BLIiyN0@)d4l7MHTRz3tHQ1P0O-#| z#~;NV)}m41lX(YDo;nBjp4$qqe}sIb>dF*~w-0ho&gu>1-0=fkT6U}NW(7`E7cvTL zRjtu6gawI(yWim8W@d(82&@ugpvyX4=_04oN|{bA=d{`XX8->e``>1167WCW{q|E| zMDyN35F*QRBFB&ds!pjJ<1%cMz( z%i*=N1dj&mj%AKmI2l_7-u$`tdG$bxNWK$pY3aH!qIO1LXhu*ZMgj`TgdQ215Tmq? zfvZP9-s9<7Fc>yIj9FpK`0O0umRxGkWlSeWWE`_uM{$L94s`v#=iTl9#-EQ-WRRT- z6h#xkh(~C9u4@=7q_PdiwaLK2J=RIN*Vc(_k6Q^wVY9ngp3w+~5g3t)FasQLqp=YY z8OUh7@ul|dqF&&VSs>7iAjqn~8eZUP6$3~17#moaQf+$wkFY()5G>1aEJKP6$CD(F z_SjV`LhDdR>>V*Ku$XMy>Z4X^kv*nn*-4T_`zRB;Wb%R56RWKFYz^LGmZK<lgkHI^z^jt+N&VgAAX&pC01iu8E^!{?tk;#jV=1JiOrCTUvr7L z%QcwvH6^TH(-PLBX`Jhh)zUSfOnPap@CLkBAQbKjRmDycj9t!F^Cr#h{m$~eXOrOd z@3-|#Tr$k4RVHRf4{7>NVUyR!|h6z zJ|EtV|AS)754w!^Zut9aVnieYuZ5?}DyVwJ9j#u02XFH&zJ5LwhISjMR4J0TgDi*l zI?n(lbai-px1Ya0yK_e>l+4~o@a5VcHcRh7?!c+nj!ec2X|!;`^nw>Tp5@pGze8Kn zqAMeM2aZ2{xWj|5!^>BX;S(fa-Yw*)YQ`_FjJMi z83Uu6YBDs%ij+V|62)cD7&N2ktu-z6wMDziHdB3!qO^>RJtcT%F90-Y%HCh!E z5~wG7WV}9PWz~4iO_Pg>Eyeu3xX(+nOHT}w3$6>C@3!dQ53g^I=TJo_j3Tg%OlX|I za#D+S{r3KP*WQfM#^SS8FgA5vVBCO{|4e@=>JF9@8G@n-mf{)Sa0k2379B@U!9js1 ze!BlKxgKwqCQvjc+5xDrMNZftYv_v*{yadtwA6eTJ$$I1$QY``_PHz(au6>eDn#Yk}HV@P)J zyMHf|h1(fx`Q(Flb}}lk{y4MKo&)=QLKwGX#nCU^{K5?b4p`B>Lq~l`*cf-{(C28n zaI8lMcAXvmSLdMyius~f2?UN4If>^0OI_9Kw?|IhQm+bJGit@?m0EG{yT=6fep>&x zEhD45fZ=70XDE#%xd<=S&(**+^Txoz-49iH^ErcgSu|@_&=i^`WKx~~^$4NcYiTw( zZV540Uwa^R&3*fieiij1H%*fqNih`3(wgB#?hFK@kP)*Ua-d7zu;$;Ng0pZAUTq`` zG*3yA#7Km&u@|}O)R3)Jp=$KTGMZdBmhyS5?`|w+z6~zX%G4lErMu0d1k#!Wyqg~E zh*yb2vjo;Y0%*VuTnY%qnYU{W;8X{KJd}QSgXnal1l$eU46bxdS|lG(6+6#zAKzT% zx1hIl+_BNwVlvS}(NPT?d0<_3MvHj;$EgfO@fxEL3i;lf_YE!TKkn8iQ!A7hq6P+C z)2?UrJ<a{Y5sQRr-Gf8;l(skW(ASuMVjFWen-N92k-s6O7jwqYH4*EWgP|n;_YH5 z1%~$AJK@V;qx!NINS>2e0Z<|r;mi6&LO8ZqjMI@ty8_ZLW9Sx7m+>Jmi5>!9DyS%0 zf4s1o9q9PaY0pF_{v4BJIi6!kp5z6JW+HYR-*gD!npj8ElLNP({;>JrVQ|NBz+xz~ zXbzWZ7gWI0JR=YSsnq^+Ld|8n=f(7{J+zpeF|?T9l{Ej@GV#>FjK2mxu)Qs|^GTi} z37(-yiVGf#Mrhl5^C8?T5!d;*2gXr-x9nON$F*)P=n7xpC4uEYtZUtC21QSo72wJ# zZTY9lXjgd38t+)&5g7E(kO^bfL^=K@XptiXo+2oUrXvgnJ~|h|?_np}odN0Y1CO+* z8Rg8H5m=EWSutpx5J6218-=o-lY}eb?!cC2KcqeMNkhECGm9Z;yXx?G9WLd9jfDsG z)YT{Mm1%b1?;mZ=GNxkf)@X_jwnk)WQ6wX-AU~zAr7~7Jy*IFN=$%ztr9z=0fMHG9 z?mm(-!Olu5tB^D;079+5ZyI5rv@@YPx)ms)wk+0nPg{%k97l=w2FNyl_08xEn>@oH z4h_Rnq5Fv=y>1|74RZ(0WW0Gxt9-M0g_M^7ovSxRc0X`?L1C&`2f@%*q$PrzA@9MB zKN6lK!qKt~leS@2^brV&5nY5RC*wk$bE=4Hv*&VeA0U+}Qgt98rpnB;6i9I(M;$`wLsXR|yW zXgF)({<9sU#0Dd2Lf`~J6bXT3BAlU~*ATxUjH>`wO zy2tCXv9wzza|W1T1Xm*%1$gE*SjS$3ZgIArs44oxIv$OoORIs*U@>s=oQA0<%(p(~ zyDFIPDkJ&A_T3z#zaYTiyzrbPF-ARc{hNW=UZKYn(7k4BOutpV$n=w9P9YPbK(g5d z<+6Q6`5R#kkAYkn)A{!yX$48MNE+o!=`r|fA}0OB=Fdj#$!s1G(cKy&%_HgdG1h}b zj9TU=HF?vk%R4VCTyGWz{Jkf527UNLxf*GR307laoQD#&%|8)PE4d!gO z#yS*Sy(_-oVH)>-S}Car_dWigXmOyyuWyj+n@4v}sPP)m7*dodmWBM~ab@{IG8Dw*|Ysej$)^&xYLN7N}2KSy)6-uPdZr?==A^lYqOg zq(~}2ovsY8934ZLY6*9`Vzb$zE*_O)EH3dre<3h(&o}kE=f>j_U1m6*76DK-ie3GX zkUFkN5bn-8Cx5YwxK`(K3QhE2V%dC$SHvy}X#GYt>AfjRIH!=AfHUaym=;-45P+s} zGV#vSJMtU+>CEU5r^2DE6cHCop@9=ntZ}|qUiH8`cX%oA*m~EJsV}HdU^rCRzlA1SBqasy zs3{=vN}+w=15dVDSE=zI1+G`LRI4Gz0s4G_HJk`gf%MmH;pr)efY297??7hNO-T9; zq4wEjrz7d480o|qvlu<8`w>ZRC?JgIiAN=ee zm|I(XgkSpm+Zr$GuLL%)ZI|5jLr85!!W9>ZV#dfEuW}?qXjCD!?caCK^~J{~ zhQT-;PJINU&@67TYH48MQvT!BU87n#%A`bdJi%&`q@q@iOKuK{#;I%w57EsPoa-!M z=}4(-S>R;#?ithuX!CubZUi^XqQwG}i(r((zQC(Y=#`z7Be`_X(7)~ed|IcMo23i- zd^wd@zKhP3x~2>2;=t&|W*?Yf!j%SdpELWw1QSd!;bOq3F43Payus{;iU>U$T-x$+ zRvabGC)V%Q7|+W~IcV<6OfbO&6HG9{1QSd!;qrw-%bC{$sW05r1oVN2=0=yRr5w8l z0M#zZEJrGg#0Ws!^TsQy9XEMW;6dsVgj;KzAKY*!(hD%{PXY6rx?5A8*9cx=I3TDB>ee(N zZmM`A(2_h#kN6UvEiZ^HtEhh{RTNo)RtSdTr21V(CqM8sl@9M4EWmhssVawt;&I(j zI9;cbL`*HAB`nTM5&V5G_HNdjf$pnUuK8gSY!nf_QM}4?fY3;e1PtmbNwvme8*c^b zE&4{zL_(EUQ%@NI}E*GjYeYTpc(+<(Uq*zeskJObCYhg)j_1kc#je)+VZoYNS%VcWwlv?e^y+5FIL)Wc`q>i z{o9Ux&>riVD(I4m7D$$%S&E8`rqrTRtVyvxFtyRBue+u~8@p`=y9q^_&ppvALq8iYS|Fz*?!V!{&&2~a+2W% zkr7#nB}JNu2)cEjJ_&EY_WWmoj*ek79R&VPiAa(h#|ff95{8j!ePS@&Kdw~T1HFpc{?-u0)X>sD;?`64j)=%BYY_Jtdn zbw*1KrD+T;XdI`?TA}4HF?GS>aZfc$h02E}F>rCANu0k6NaIl93U`grYS|fh?UomI zH@*fE_EH0uLXxa~idPeQ=6Qj~`svxd3qRdoxjLq5aDnWJq)|+L6aHP#Vs=eW%y)%L z_nyG~gBusO`aK?16Gf0Rr4l^H3lXX&bPIeI;}T_0;MjY&?76GJ>D)G3)D1DAu_7y| z8U+Y7eP*-0f$_~!#z11N6T1HkZPnjDW9kr1xP0`yR?F9cBPV(!KKf46XrhWB*g;l~ zH*ZMLm)jtR7q}&7)6Cz$sMBdvghO0s5>D=_m~v}jSL_Qkd!zcgzFS-3y8^lf9^g{J zRJ$N+ysC;Sr}50V`Qok_d#vd=X{}QUtJkTV^TRK<-v)*VJ<~cDgh(yImOc7%+bLIN zXhxA_P6aBsXGHQ+w$cX~kRLZjdbkdD1vn7+@VeADHvQZ%%Hl?mwA~Fu5Ddze)J02r zJ-)erd+Y+Yub7ua;rshac)1i8zV$#LbJ8uJeR?B_U*7cPo41byS(3}^Q1si#!RX{8 zy>5qV{HVMffQCM<6E|fa4E%7{r+H&f)iuxw6i7}yFKP^_$P_0j+vYzfPQ1yJ0=wdr zJ{JPI8>7E;d%(|9a77*t)MQ^8{(OGDNWDN2MKG;MnkJCEEUL8hZl5i$-SS!0;wotH z6#Przulbqn>h!Gk3pgp znxjZsRX7>F|F&gSGG?~?8F;K(<0-FeQ6fJHq`(C4%?m6e&;q*0$(G$0@Ywfi8y4|r z;K0uhPi>S9$8M?3XzUbLp$J+PRZ&sqE87zW95|LT9O;h(NdG~?3+QyytaAuob5*!< z_+H&z-9wLs@JG5sgdcU<7j!lT%~IcF!wZ64Hv=J_=cmYKamxWm#=0X8+1 z-he1!zC_$fP0;I|r@sKNqb4Rs-{e3qGiW4YI3A;5{d9~Tj&$!9u2h7Kb6kwY^;f-K z-|FX{DH}t$#@G-h_4_5zD_?@uIKP#;3Is+#?Vz{6`oIw0S}Q#NUqGk_9?lM>-#HP= z35En6syF;*{rkreW_nyNIFMkxxu_QRy!;H)As(^9&cZ_ zlm*c1m+?Adjx7I7U{K0)KV|KW5~`h}34tXAf);3!kMO+SSocUY6kEi(z~Y^st^e-X zsH}%47@Fr4mS6#ovYy7+v&8d(^Zw^&AKZXdF3X%mNq}VpNmJ2N`kI&%Abe*ftnM;< z-O-*##d*Ba_)fWkBy*%nQ9xC|_z6!=d#qAc8Z7R?%y4Y67^e#vYvSr=RXqHy2cn1W zA_jIDW#DulFi4Hj84kC~@_{?`BV1v=0`r*eK#8;CR3alEP9HKl|;Ezyq~v z+d5f_Csad7i1YVa2)1C-I4CDS9~B1hGDgzs!A&&G1jNJr@)o$W;t=}kboh(O#jdl$Gyk^>GAK@<@b3#e4( z6I6-~0U^n$GzCG5B8m+~L5hN6K@f!R7jEb7GRb6f4G!J+&tx{cQ{TLK^X3&=1gxMD zDn&EIl{=nIeZOt-bA!nRVZ4^qh%B{OLg$TqJG3$L*CcPVBzf{$-LRi7a6c3}23Nk5 zVM+m-NXfDaBnl;;-H;T;#3YZs@@V_QGmtOc5i$-J%QB1%1cs$WsZqzgdhe@`+n^V} zY(0fXeA*VsXQ3N-r|OY?*Q1QTFYR~m`8xf@PBjDb@c&4kTP&gf?{U?HGnGB(ce%Gs zSQ0kOF2w_dpC`HFE%F@8|Gx_$ovsJ@I z84_4d;6<9Gd5RA@sLs1Dze5Xe2wg=3&;BMG{`qTFLxe91<=Kf9X+=~-o);0%$onwxxmRu`#dyGVJT7c#%~84M^sdyJTHRD9N6nU%BC$% zJaID?r^LV3K6oM#i6&Pd(H!8+8Uqx!UCGLHxt%$RJIjeqZ4R{x`bs3Sp+Okvorx7ygcH)A8H>;N=AfzICL#3 zSPdy!E6<*#Km76d2{BBx82_mjtR!iyHQ~Z-?TTfIfyJpcdVJ}k| z8URIRDNWXbE>njf@^A|#Usz>3kCc+LW77GEBJHWXsHqI8$&4zXk@k`h540B&OE)S> z<>S%TvNNh|zQa3sZtvN06FKwPx8cpoIGLdchGQs2*3ihY(Gg;d%|d!AjhuAH%)2?r zz{X(sWm@3uUDG9(t6OfSl;KdiIb7M2TS>FaQtAL_mOIOxn++aaJMP;VUuMRyxlUx~ zX2g?!=lI$FqwT70P;YE8=hId}$2Ylx&Tn!BU$2nvlb-Yg!>n(&Ob$Nbsu^~Hy&|^g zeCqJTvgdmEXEHF5;hK)_G&FG`` z!aVM|5&TiYt8MftA6sY)O%(Se_?Ekz>iADmu;0PwQZfKL&U<-}dR3^UgrNCxjty21`+Pm!yI8 z+$(v40kljBw5$NXCnEx9*;~I=1bu-YjIi}Af>m|sObPCCnFq}pUlF0BZC5*Uv z!K9+bX!X&y81h_$JT1l6#K|3z1X&hTQW7PGp(RrG^trG7-bHf@f-JibRU4*S=@8IW zt$YxBw5@Eu!!MA*o=0Am-^kbyCIC1sFf=J}f=Dm|5u_jfmTsQlz)spwPxR?-FHp2>eI@<-VE26Pxoy7A+hZ$2PssgIp%oqXzml(dbesP7 zlF3yt9KPN2(S*Ba5wn|F0vB6I^%7PQfl5oH#9dk3^rMTu-@G7mcFYe&W(!6~TP_mq=|J-{;j|I5w znqR|yaC(;8uVugb$#rX*d*Tyd=`SS&rf=x2KC6%LHf!-(YqLn6S?`~nJKoy_zg-o* zPh$v;V@O7kIGL}#t!}qvtGC3%)9MDK@)5;sjO2Ogv)w&!IuO?0L6B8eAyko+c?CT; zr#H4@dMSJA$4pE9<7oIZIj69sppld$XhCHk!!%mri(fdM~DD#vo(2B+h zGQo_x`OX7Mz3H(KJ+_yTKf7M-L+2xXjw>fp7-kDhOWUvQ*T~ObB+OMzz_tuLPgF@A z_wL}Z!Kq1(R5?yjHAU1=?+B7!?f^Z7y2Q|8v?_M>YM%P-w>E$5&Dz0oEvJ9MIx_7} zk{|%3X^JSz{P&lJOe^Yg=!KZjDO!`}ncb>IO4sF3*7t1WIdWE~wI%T0g3SiK+$e254J85HSvTjp?I z*@^mr3>i3GX^!lPTdLl({7S>M(uTemeNg41Ii~8w^DP~8lma!h^ z>#vGjr0@9j>%1hA=}j9qv0dXPsUz$%pSxgskVUS%G!HJXa$S z3kJCI({ql%bc&Xr@@nX`*QoG)+IO8vLkj00!?UUyU3+B`RItx(5n>KlGGCb9RZ35n zC1q@9XX+KUtp1%um*a5>-$z@n3%J%QvCo=fuL=d%8g1v8Q()4K3QVuAcX+mf(%oot zYAPf=Y0@JTZ%r`wadX|6V1gmc`j7PU-=@46FVLcA_7{1B0}xb3ef zcpF>Bd@GN6URt?GS<6$5_M_+s-g1p_esK zA2ksPkAgaEK=42Rndoc4Sh5x;ixd#(?g6!o?8raM1J+%{s~S?8xt@EzSop*1BG#rtU;xX| z3ZQvXL~SazM<~H7l=RK>?3wKABOMGACWa-h#Cc|Tl4OIu2e3N#u>j*eV4f$pMeE~@ zMmNAun3|huSNzs9c11TBum|nKRj~v1oTqog_Xc#!4P&EI)D%-uIGP5M$nk>s$>L=b z2c2k@oPc3u%5J61_e?!JtJ}0~;n7xR6j7CEMpgig4nPdH>;;|)4PT0`^lR97vYbY+ zf<}@WMa%QP93*sHm0*KYIJ>e@^A~%5|7!PR-+vf(`=b?A(ioN(DK#k8?@v2yA&ZW( zEb%FiH zRokGkmJ)I;#r>|NGOE~!xt&)$_KyZmTKq{fJRQrR2*RH37!UI8-|uv)z&RMC1I3;B zu5+wESQSditYuEgR(ckk5sv5H2VGs<8!Ae#DiZ`psX&kv4LTo~|KqWGuP(G%A+fn& zjV$emepiV;M2c4d_I9Lp4mkS_#`#-eTp*m-ZW;H}Z08-EtD{ z6;ng*6}%>ryvisvFEG(V`h2~~Gb0%yCyXpy5MvRkdnS_aqSH;d*gEJ~xD$DfXAIx+ z{4is`^QTJK!xzt!jKHxpOA`KIkSJf++<a6hgN68`3(RZ$7(>41y-a`zX2(jG`OaX zo@NQhg-v@~gg6BR97Slt-ou%d=>~pLPj-%bh*MI=0w;RVawxU{VmSF8TS($qIRAN` z#mu4+)lY@@{VCIgCQv-dh_uitdPUC$MMAcY*UQefh9B2FPtEL?9=h2EIluv-PLV7_ zFd8M1JV|m_;s#eg(uDTgu)|e2;0bF$iUNGTdO2>)-}MYXec#L~ha!y?DXXd?h`dNp z5*jNK2jvyWy08~c9$Gc!P@`%bN~ zdz04hwj%`&f>u-wOf3e_%dcl2be&UpBwQC}(^1DxI<{@wwr$%sI<{?_9orqVV>=Z) zmB}~r{Fif6_f;2l&e`v~*YfN{s5AK7&vpxeRt{ug4>qL&bqqA0?+4(RfG+M1jl0J; z?1z^iH~-r+b1FO(I@3z3>LR`CB0}jB@U1*5JOo{UuFfth2axz}!d$E}wa3n&2uAeO z6Mb2nojG(4TeOqieBR|nU*TUbRX4A?_bAO;MD#PI?OoEhA42-KIB!+badX|O_a(qM z^TaYmgjX=z9F#9^2YgMF7=HLl^P#>H zcbVg-0gqLQe+jPt{8Rx-Pv1{LYglx%lLNcXsV?4>QE1G+>d?{naKs^U;GeyLGxm;) zz)>Ty(7+_gw0X?9l9UAE!M-@iGRpoFi}-N6|h z!_E;>D}J`JJO7M<(UQqlV7?!j%svRPyHlSMnssUQ_o}Z~b$r&B#EXLYg?B#8lj|;? z=9P*mfL!JXSk~!CRX??T z?h@pZQ?#;VPJkH4qS$2!{6c@@!%ghdycC2q@S5@Pwdx0WDV}#yaWZxYT;f+s7lCqS z6$OEp^?kf~C@&$EOcU6Jk#XD`yRwV)hRBKIoeC6`JFU)f==q zrd@T4CyvN-adG^`R3`8L_DBDV1bSrXwVt;x_e*TbkElqKubX(jMb;%o*z(kEf12&J zFHNDz==VO+tOI=4=EFFsr6`JU4{ykksLx91G!2%tvZgqA32Bn_2@VaP?vlhiw_fy~ zl8&LZY!;$V$u!S0k9=4kCq!ThbY3xO=68d*XQCm_BoEQW-r-g^0>j8#`aP91$bhHt zU9{k^gNzIBL0zb9V{hj13HY)BPmxA3jFy}Lf!czam;bYy{Y<#$ZTwBh)y`AM5L&93 zjPTtgf~|+f@2wl-SvA=^ZaeU{o7wlgN}dlK5>o~np@71peUaFY{a4q3=%qL=@HwF#z+ zE0Jw!j6OGL6O$qZ_#A+IA14)~kU~0?V*gRxz2vP}BD$I>MHuPH0+Ks?YRL%w3>dQx zoALL17$~-0f2<5cF=7{jXeCkgbL{ZgPC8WEpk-jX$wFbwh1Fl@oSZ((u(!U`=d6&< zM&i!CqK|SxE@$OvE@Lpm*PV5r%(ozHoBpuA37ey$s~V6o z93li-4Sdy3da|tuDi=RbR`DM!d(1DM*4rgJ@PJ_5yAZ9Zg&%*WQDG%@>DZeCWH}@u zV0pvC4n8i1^KPfYhI|vu2 zQl&WS__lG}PFu5Wmv6~8(ZrZYWsr!4pg?g-?0c883?>9)gk8G7ci|$sTK##!d*n27 z-IEGGP^kS#Af8lrdjmSU@7jsUbNepH`UI2(^3Ppu_3m$IcqWq$`D8C&iq9f%elm(3 zYeglSg(IUqfS9us;7e^U4O{nw4*U(K;zr?BLAv}TYd7INrKYm#&m-a*yY@4F+jB|n zrJF++(2ylkPVyK7YfV3_vvC;ylMviv1N_kt@m*7Cu;2-T+?3Y-qDAk(Ua5JNQz|3l z<5!-{+_!s9Jvmr;0qJWQXDkt9h9hafod6fxsx8b`nH~}EuiMw_tXprql^87ICu(XD zccCVs5jxJ6T3cDYqgKJ-ET=O1lw|CdP0A5O!WAlP8ztkT(V=te{wzP<+EEL~>{f*q zf|Q~b$k0f~l>?g@u%Eb6tP53d=Kb)$8|@uSVj)pA86t&J@un=GIzpLwCuINA#ZOF#T9wkN<9D^no0ES7;t! zI>Z%2n?cdJOf&sIK+`iHDv-u8nhTsfG zh1m<-IQ**ElS~be>KoOO{T7bfy7#Y zX}hi=)0JpMPSa89o)YukzSNm{)Sx63Wq;GLeC=Lu*p@gX=8c!wR^fd4d2!nX|t6UeF=u)U8evIC{ z9Hu00e`h~Y=XVokz2<0wGN-A0z^bqODu9ESe>riE~U;wMSEK3A09!RRPQX~5iINaUuuAR$$$+pMoEoek5NSXwe*!t|2z44wsxv;3+pDm}%#{<`BUrEo8~S z^5ut}k@rR41-OD&;)`fb4RwhiO%ACfz;)-3_0o09ejN*MR{LFV>$Z!ns1VfF-T>b+ z^A+|GB})A`^MoP?tH9^*w-Y2822K(FT>NXSwKTPT^*Yudt`EM=)OsALUl1aclsQMx zadUn;)~A;%3ICTBIIpgV(l1c!l+sO zlAr}_xIp$cb!sJ8+q9K!pNs2{i<4Hywa0HzU}_0hm&zH$LUT|vj^cvebN$xbI$No9 z3;ywXla9me)f;)wQE~ry#L;oNTsS0ufRXU-ml;GPX4BF?oK?HA(R6}fpSzxkfm}1o zfxNUM$3H(Ga(Paeo+awtY~YYIm2o@n`Z+cndb$?mFr^KYJmOB7-|8xs`Y{@q zH@p>ewIAokclPjI<}jq4iEdMBnutYUnVWXd>*qCw_m4Aox*hO1@$GQnw7 zr5g{Br_E1Iy-B}BA>{E3XRmcNcfvm&RysZ&E^7;?del6ge82{amsgHF1k~3ih`MuE zySMFvKpmi>HZx1A<$1<7SV%b>xl3HfNDUPruFIBsy@q@OEW$WQn-j2tUSGZk&a&m2 zA_2cPSr^_Tdg8vtLblq8JSgcK(4*^E!N!_VrqDvWP*G&IRJ9SVG|oKAD)~ntYt)ng z>e;=&@AUmP8JBZ72H`1o8d#acoUz4b>iTAxOMnA`<^yd)2!)POT5fFtdWQ#mgyU4E zDK3V=Y@F(_#}%HfH=u;`oTn^CeumHX%Kie-mXvf-5Yv|S$DD5;% zLKs{M#YgN_`$<#W*gCx#U;j(BG)nYR39<6{=VQ__jdyQP622YcUEMMp*g*CSFlpl~k$fhb0v}c= zxWLY|1-e~99fEyUsHY&yChHbcELSg>NOf6qV%lk^TtbY9VH(t(@PTWLe$= zkK(aZGxV7s+qn9`8SAscQ*V?e7VCHH2Ib5YkM1=wJS}?n>=Mtvuf=6Uh6{ub_?+VdCp(=5A0?^;s3mJ}%(#i^0`xyVje}`il}1Z12dmPfWih9FY>~?BZ#! zhVDvJpNE$2Y;OR5XqQL5q6Ca`k!Kp3X)wB%D)N^xlNn1G&NYZbba;9ahb>(7FM64z zBBs!Blt9GFU-}2W!r$|lYcC@nNbdm6_n~l|nFDxGOX!M}lFDu**6sA#k*g;{hf<5G znu(q+`-a12N)I_G6sksASW>UEYo;OHo*XGl3GcXZ1w0RkW5ji7ZnBUbK5o3a`9_G$}laQn+`qwUW@R)Z%+MU|{`RXXDeY;!a57Sn?fZUxS6vRvK=?Kz z<8gM!BskXCBFrQc4fcF)L-kx&9P8o+8Hs+x1lQ zvkf{Du~@Nr3Sm`8H2Id!*_{Xz;&lz`bS`?M<$+}sDtbRuH`@CxAL6op4<*FPgRE{z z(S&UM(M3J}hm}63ctSEM1XN2u4RZ){u)tWD{CpO356kuDM6Euuz9(gKpsJUeni)cF zfu5WRWAV`g{}n%*a|INI01yAt;rG*xF^4t*4!V=BZna@OWVVD9!^Kai_rnwGYJ)-I zWqZ_^{ufTTUQ>$mpZ&a5iP2lgkh=}_hAaNM;Fclv!6)5%ThpAQ9f&VCcVG-ZNU@u@ zBgvhB>U8wb-143FPjS=U&d8tSDPU-Klm|VH+1dWRXVnd|q+~Lr3@oJO&O)+>x6(n% zYc5KKrA=XK@(*qPX&GE^mQzT{?VGYxLxrv`9Zh8IN#QX2=jQ_8 zcs%^=((zIWs)1g-I1DQ8O;DxYZ_KsQ7C{MajWa_qg;GF(Ffb z=d?qXVaS~N8l|dqdr<$YFo#727F(lI}hPXSO-?P|QT}MgQ9n7qVIxJ?KjkUNV z0tn9fKi_fOnzz6y+!B-grX@-Mr780GKs>cp=QTgJO^fI`vG4JF;%FBNa(2JDF=Zq@ zYR5iHDz@rhU(aM>dUkw1qJX5>)kRLj2%G;H+CF3O5Fqfv1wIp!Pyk;0-W4IZ$HgIldw6@S!nKL%3b3k59s z0b1b%FxA3E4QM3EXhc@5Rl*C9$we8=vpkL~m%sL(S>d)VqOKFGQm)$WYowuQkucMY z6!TYN6IeU)e&O_Vl-x#+eUw z=^ymxZ5QE}FC)H#geSKK@ZNZSi9Qhs#9QPU8trS&5P;KtI1R-DCeBDIiRyzUruvky zL$23>K-Ysxv7tErU5R|bX_`42QFIPD3bWYn@9@l(k*?9(Sv6FqCjs7no97G5{O>{e z;Ds1d6DVfX3agS}7&%xtN8|m$qWN#5Papp^U$%!TIOm%ICtz zA=I=sXD|ws@V;lDYxmfOx@Qd#fyCd*w8~u{B&({C72ee9T;s*_@7l4nR9eRWt3lp?rX>)wKxO^STU(;9EL*9yL+8(T=(+f2VW5LjMCC7F z8~pq2!0xWH^=%Y&3UwdpdTbnH$$BltqkI3WJNkkFS|*e;4(Z!vBO0f!MBJiX5B4v) zb@6_=QLXplv-F_w=v`+8ZnTv~|MV1u!IjdOu6ry>t52uG0#Gk=-lY7%d2i z3ba5ksQiSpg&2X7i8i*8Ddu-n8FRATPi?B{{eK*72w^WyJ$ zpU{IM&JH`SP;jpRv&?;>@w!U$+U&EADoI~9Gh+b`5YX#xKD;_3OD>gNZ3MnF?{PKS ziGKeVd=;e~K2x~Zr3RwqM)z#b{JcZ4X^C)gV`Po+B6|a)U`e8sfsu3BOku(!Fzv(4 z(*z3<=NL=7le7n^FG;!f!?pOc%42caEAN3@A20m|$_l~R$03<{NGbGZAJIx>$3f>~ z)6m%&*Exz+nl6KPJ92;@aA`D8(%VhpE2@@CPNr>S7QXN4{4bg3lb>GE+U&dL676%h zdGcA%e6WgmZz#ha9^+j2=68uiEOU#7c^led`a0x-^3%k<&;za{i2(CbUwlW4@v*16 zoG0PVL)XM=uB2KuUa4m0iyH0vcfQxy2;9rX12rY>`ge`P)Uzwgp_F6zM~;WojI4zD z`KMQTdJA`oZY8&JnbI2^dBEel|C~<>_8&$wJxxR>?6E}9%G;X$N+P~twMv2vNU68S zlM0EaL3iIhKfnEVuTKE%MQLz3ggB8@KQc@-vl?w%^p0n#9|tOQY&HoE;VuX{($hl? zbpQG?G${ur_~;R5PC<1_p8kENUF~IMy||m;BtUnJHQ~b{Ap+1-EwTCKmhb0DCzE6% z8f69%WG?tjz(?eMFf@4o;#H zEh>>9hNh>3m4NGD+Ub8LIH@?Ys&Dx~;8Y2bY^a(C9O z_ehHPSQ;MU!Fj4VbRIcZV!5R}9J34IW51A3g9hnIPlWs5%*{?jbxLs;aIz>`iaFj9 zCn2_vg6IeQ>WJz+2f&3>Z@`MrU^G0N@*ZX)Ifxv%n4DH%Y?kxHy9i#H-xy*Rcr<*J zZu)!@Z4}&YP(M1iu_%>6i19wOe45jQkMXG9bl4xGktSXRNo=Y)P-s$BTAWIW@j>Lc zJGyM1uUIW9WZhI$>;y~s1GFe5CygTk-Qo~tZHDQCJe+|+9GMk_2cB=qR*b{bzE(hs zCnVr16BRt}L^BD+GaNZsmuYpxRwv8_=fdalD2F;9xB{*)%7U5II>i;|+M1uT^<8V) z%1I(=mN@QI*kA2qFLJO2Gu>;YT&Q=P15GaSS$^DChX3_CX&w2j_m;BWe#AnZkw)U| zBj57;$a3GGIlF}DUVVn}hrqGitkT~fc!2Dtj$ZmG&_!~DTK&$>-*^Dvzz%=boRtP0 znnJ6emzMMzUa#m!`_JC)zI4;GU}sa$lO;CD0U}rpK4nEaph&sn2wOH5JV3i;eB)=e z7hbJOza3Xr=5QHTyLpOJ1)&lPG81I1gbuqI=COCV{Pbw>vF*pRVMK)@h6E=9L;RP8 zcUD^%CR8v@$GtWo{M|jY>@?<0XZa=yYP>I~l z{)v+{1fS!caOQse-7I8=%+p>gsK}kYm$}2b3t#E?b!2<=vsir&u$vz9RF5{%iaVxE zGm#2M3oe0h7{h!lNd%ND=;w0nx>a0sFo088NPUKGBASl(uNzE)cvus}<}7wB>(Lcs zm7H!IjYFc21#yVnQ6KZ6yKq*=;d-Maib%!?bs5us+4r*`$oaW3?A$JWuq2-9{s;z* zB6ju{a1-LzSm|fQJj;5;{?s-z&+YNV2qT6NHw4e4kc_gBM5{+U6H{5E{`cyfr`s|A z1Y(+vt&T|aij38l7Lv50Fo_RN`p8u#Bisx)5tE}MuaE4FWAXl2)^JzBw4OlXu5Q>A z)P1x!Cagz`wrn}5d5VICg#+%yS5hcjZD@2Bn3d6M$gH^WO8lKvXl5dXKrv2ng`dM& z7{yqt1NhG>l%EG@;T5qN=I!}hJpg*!!|NPEf9Th?eK!$Df{u=K{jHXFWV{u0R*FI; zr=qI~5A46wm`|oX?}#L6Iq5C{ubR*k9;IL4bF4Dgl?3c$#V7Pp=+95!kte<#y&G!X zfnQhA^?_TW3wVh`{MlIy)S0?QD8gfO0{tTm8Q!Ty(Lc4I!D_$B=P7Bs*=dg<9q?OH zF%@1RW?G@bL8S_sl+enMJG-Nc&&6iul(An*vXn)<1<r$cRG>j-Sb^KAIc<=4_@gH7)efpVG2439;To-mX!0e{Ny?`5 z<35=5NPya29DC`E6g~KV&eyQ?T#~i+fh;y~ikt2fnCW1;*Yt6+6PY}n7IDW}%4D79 zSR^xX)@IFaV;HDPwP|s^LUQIS@3zismWwf>NYu5?IkHNY3E3v!jNFoP#pGjr8AJY# z^9?^W?5lH)lV9CYG-NlRVo|IVO}JAkBddt#hd6p?wqP``2H<==K95nFa4`&6c5>4_IM3}t&Hxg!Ptx`@+hMf`BCZ`vtnQLZwH2e;YReLt3w9iJK*BBi)q>1PcvDnpU7~^)Ri6L)Pe3}`L;mT@$IhIDP4sYk=B;idt7HB z2(;50MvKq{2Ho~&+E`!)DT)S}Xo_X*+zT!jVH-wfK$2mzaxx7*OT%bX>vltGI^EW>S$7>tg3He97CA9T?6aB%2WP|P3!_C8c6yDV&6J1{i7uXj7NVrx_j}<+>tFL z5!YHvek`ms%4tZo1wuYb>eWGB4wQ0D_{rJ|r05t6DK-|TtX#juI~sIUL}`VLh_{)m z_wuO}45ai$Vd+RQK^1C6F)^|Z?fR)Z1_t;TiOgo$@qanEMkY=9i+cC^LMcWwv z$$(3Ge!sdrmUQa~p}$GvkD>A?0SsmU@~8Yje11V&29au}9cs#3_Ij+P?5M9&c0~IM zF%X0c+nB7ucg1&H+`gBa2@9hSB1;4U^aveUccp~TD$~XDJb~@RtKz&(=GCISX-NQj zg^O6k0PyzCQlfTl;dx7}aZ*JntG&Cr0D7(&F%6;fP-igKU{u$OMmYrrVrSSFTxxpU z#_%*3(O$o)-T-;=Sp_*8q-$LHb0Yi z+cXg!I*U{?kC-aBMDyX?ej_=EmS0;e3vky|d;!G8TS@(qfC+*oW9(wAskP_@;=W|8-i=0v#LQ> zd__@)+!JPTz@X`P0w0b$1 z+d7kfalqs)33r>RMI}NDlVKJKHvYs@A-UkS87_)+>Xk`z*+{cm`>UbE7OZR;XD9}$ z2Cn@q=-;`4an^hC@R`#2m^aVmc(jcpjUw#ATv`QAXc@Jw@i?-~)cV~n$NAkQGqcj+ z_gIdQHRo^Ikq|3b!lu7qDu>F+YH9*U4qs;#<*=)Rg8%^F^7luBs>&t(5StK+YYbRf zWrw@?@R9vKjV2>}Evm_8@PYi>mw9B+afPD6g<8QR!Dvo1y@~nkvcqb(4GdEY882_! zH+xxPal~G+rK)PF#PF-Qm8PTW#%X5Z^|7_-?Qxn7geD`)FY6~Q?xz+Zblh(w-0OO=b0g=NfkKZ<+vdRf*2 zfx;!MTaRcxtT2*e#<R`un*8Qy72`nd%)MlA`U8TUAPXm4kjztO)hq9KMg%)y2KsMW^b(o7OkcM;5I|uZV}8zf1Lz$59M_wbDzqc!#p9iOD1~Z^ z1w3`jSuGwx7Zab&N73U0ML>Ukx@;DdbFqPK#J(MPA|l%e<+>w#IW)5I77kr~If}5{ zxfB_5b0eAcGp@3#JtE{R9(_4By3TFz!IMCSE(^cYESZCy-vO4UykzQ69Kc$$tI((a zY_C9Fkxag~J-gd@`U(XxzX)Iy`X%7H_S+J6e0|Z}gM`g0ir&YvecVg#SvLO^1*# zuo1&mW-XTI|mSb__HV(L@{rTCJ@d>eVpGTH}zY~PTLE$_%$}|p!^acw7ulC^1 zX9C}M9kcR_wjSrs7giZxTV6-UFzfdv*jB=m15-auMjIWu&~FBk4_XHCZE#d-6n<^G z*|$zMYtSeCz~}Az=$uTLlG#vN=9uZLNm$k`@4RfBUSrAxC4fN#)5G)O&=ZTk5C%u6;DW81Ppy`MH zp$>3^Cf!G?;TIJ#(aUTPFA^GlkL2t37HfI^piaVxU-9pMdg}Z!Zt)CBq$G}T1JT42 zKXoMdE5>4c53c6ecmeNRdb#VRZWo5O-@xu8sD*6}4npXkAdpryN ztxrQ%>q-z6PaCIg!c9S6EQYWXKfCz)@lGc%RMS~_O{k&*5a~lsZIjo*u!b0i+PNm7Gf6UF;alaO60O1{IV!ELnnJ;!{NZ2=%K7&Z~NgLFzc zqo^_C%`kv77lZen=;KkL$6oaDl6uM`{@$XT7Z649ojtoc{X4q%Qn^+m0U@XL1!4GW z;$NR|yIMk^MY72h7B%%tj!&nY6@_aYgXC&W5XxnGrMOMU87C!lANPol-iyRFKm8CF z8bnL-h>lvqP}=rm>yaPmj^8c&Xkd0j%IY3+C$^e(wGl^}Z%(H4tX1p3iPA!$G|N zz&z9;c};_aZ6p#W51v$}!$fvr3)vdP-MPcsN$thA(2kRGz?BMxRU;#dBsPmvVr3l^ zlR68nP1!M^$;_wQ?{QD9cRJDNyK-W!fs7lME}{lg1`Up}-t~>uZN_7AMY^v7sLbNr z4)wtn>Z=Yz^BECbjCZ4WGO}I$Dd`L_hzS~Y#6E^Y(_PH&%?x0BcQ+~2GqHS_$2|ki zp`jF4Q5&l1D-Ij<_4dtPiDaf=WN@e9HirE@FdV;l1w0;4TI^@z@P6CQfEpS0DXKU> z=@8pR#I;u5&IOo1+9Kn_A`PXJG~htF^3c`|(bu~k7zBnw33V=fsE$KO(xE@dYABt% zC7D_%nR)Sip?xL^31_u;_|m^4xP1oCy(KDY%zCZh){tARvje=$N{#N5he>IT^xl^H zh#wXRWW`LvF~;E~ZYyN9n5~Tr$nF@u9I#%9e~W_>tc@o{jN z_?$%MD|`-S>EfweiRlGC+A*m;(HnRFKp|V|7wH?yXJ>z5*XwnVjlJK)V_payO^)hk z%ql5rK{%gw!3;}=?*(kX8bw`=aSwp$YX%8Q2N%r;5>omv^TZ)u+pjOG;|*!86CcLd zt|Fa)J`R7gntVFO%GeP1l2H(vP${3F5teh!e?fomBdeiF(Tyh_G~aRpM=o%lwS39$ z99g<)IYQ7Weca<{uB7A4q*9Ni;`Y?Mzk;p4y~1t7f{oX?Z|<&I_0MPSg+9Ffj4Nm6 zJ39co7xTfy-x@eXH!;KW!Nj+r^VT7&(JWC^(OS_1G4y09X9YWZ$VSl)r*w#BZCoh& z`}B^1WI?0Mv9CvqkUsR#0tH{ zB0pd9BCPB6Q&7UVVD>NGhCQBdcajj%!;ukDzpv{cLyb*PrsjJY`2gRp<6z4iw&gC! z*CtTiZ|OsyH&$!C_i&13U%gqm2LDS9G%s0z#Xx=%dY&p;_>rYB%Er#ik@2 z`UTLKp>`AI@E6razS$9-Qa$WTnX1gbC2Vy=BIY1LW;F8br2a>^XYm5pr$rN_Q;&`*@wfQJ_@_r1+!e4Z|ReA<=Q&_q5f` zxi@C_zNa@oYWPeo78~Z3cmt3GpHeyR!0W;=JKDr&!KCuWIyQv3Wd{307gqIVkvIN@ zgbnf)HBgTKX!oOo2{`*9v<6#h;r+||jGC^fj=57PfAQJP3LmXgn8c!D{gqOgfmUN4 z2Qobj)rDbiWh7twtA2-qwI0or z9=kArLwlBB`CBoxhX2#W;I9IX#7`JxV1(|>fWAn`g~{(1=k)D*kpKw(e0ylz9q^KF zuNC1pB$(c66s$=JErfS-+q^l;Rk03>Pit7Bru{p4VXivitKLeBr%v0Cn6OnZnY zXih#mZH^lmysaO*Ao9X`#Q*59%PG}*M_)I5c1`%fycM#Qgwt_JC~$(k3r?SK=Ko&E zAaBpv$ou1tEb=z!jMdLOOKf_U;4xP3Fi~LLrx|E!O-U@_;{IR5s>>#eL=P_|KxA$; z5n5NTyu7cY=Ba^nT(M*W)FWP@Cg^qY?aNQ*PXoVDuYd*oHy*uN75XML2z#Z_OO*wD z*(HuWL9*brcID+?5LfsMFpU5gja9f+Gz(7)6I<+ekp4V&hV(+xjh zf1yHip=fx&?(<ok>tNUwl{cN{Vyqs65KO+?liiAj+mo|x7Fu7zG4WEthBZ-`4-y)`D zqbRAE&@kLX+3bU#Bg}sFOJ2_ z(TQE7E`QagN5;!~1o0L3`DndZZ(TZEUL6}T!dBLh`Qj^g!>`Og^dA)Qd%PqI#h<_X zB(=$fxV=O0T-$Jz>!%;Y-6UoVKx<7?DYb3aQ-sz^)|6ZJH1sevE#H~@aD6}e8Ws~G z%HZwO6OA1eb9rl%rgLirWR7Y<`1c3g$=$aB_?(4b)+_@PK|q*i?{pPyS!v1+1YYUe zH4R>+;L|o4sZ}R%CmKOZZ?VZJQ=R2En71_v*g7*LrZuP0v=aHTAi!|6#VJ|j9iYOL z+=kaZajZVm*jTBHoeAaD7vDF~SP;bnAzeksz@pB(P6Iy5s*QzpiV)sh3>Aq~k*XuH zzNn$dMLM)+R&V*C{GYd4uOrzPjvMk^!DAIQu@gw;AiNe{MW0Rm6b(dTwIPn@#cZ2% z9_db-seq$HiY5Unl(BwEZ9KX?YTpy|4wo+T(sHnotMSQhu){dziA4jqSoz^Uks|00 z7R0ak$o>{oCjeUXOP->Xo!CVRU&JJd4K;zmCyZwt-SA&`k9yvYjiMS@*NKdUZy?vFbuI^JiYE zS6TtIHkzoKC{{bi=swK1ceu^o&0M{G)v~n&+<@iyE%t8-e$3Z@Ot@S*Ms`VF%8?|82#^Z%< zhjnbYFf)mz{e9S$!toETR%WHuY|p>e-+Z5c^xi=icF&FP^DbYpSll>p2lNX&C!DhS z=TH=sVt8HFtH);0pq=r`arjr~MYeKQ<{|&Z=EsfLtwnmBkn=wsGkSE4XXS{ifQm_% zh%;H5{?+3M{qC2c+~>WuUN}(fgb9s>|0IeeS=?)5Ijl$gaP&&H5N9^czrzm8tJzO7 zuO=e{3@z0}nB+SCK#Saf;LEGZAyj6jfyxqR6X5kb0H}pcB1N;G%Xey@w%tayg5~Q( zJ=9nt(c=te;%JTS-KopOc2lwNpEc0`zz%bRx!_G8g9uB~QeMWidkXUzjZ`pbU zwl>T(OyD9>RV78CttjSnOA|UAAFVz0ydd*?x=?qcC`DVj$Bu69e{d@^{dsnP%8;CY z`53K_{?=27JXbQ3o57Q|rZ5`J7bJKuO5G%f?|TNPaR&X| z?s=}eCdk(DI#aXv?ONOK323M4t42yNMEE8+{GcSQ<2d4b>?;*m%0=XJ?Zz?|F&5pv zc6?0Ul>WEt8Ugwdmtmpy_8?U|^pYXDjAcJM9!lgJ`GIJbT02=&{&-KVwS87oHh}u~ z4-(}5>-=}vT#cr|jq_*6P$IufqHN_OEfTY#s5DwCp+WD?R_I1l*5NW{ zxBFG4&kgVjI;a?2_)sdyf-+7JPwZ(4!ULLJ7rpk*|D3tOEY|Pl`es|P+&nXpEr<|G z2*nh0wE8;qZ*;|~`Y&Cx_OA`>1nq>AG~yxDb84JH0;QWib}uTUz=D0MUS zW7U38^hcR&+}pD6%EiO6pMxp=a2%`HE$Cmz(0(XVxo9}K`>FVNX6~NOy=qx-5RM5KwGwIJ?naz~~?s1T|*`kR!bVQM=`&p3`7)f}Ng3Bph=kBcBv>k(Wz*SJ(YGHHvMYy)N* zP0V`s7IFJC&iwj-tz(^P*~(CBCC2&0(nY2k>>TV2QJyMRRlc*n1e?*ZyaLC zo~x>SKAz*hF<(CV?!qq@G(oCR;$$GR;Dzb%IuBP~;55B$w#>SnVz>%bQMpA>UEkC* z`kLF})Nh75453b8RHgWdiL8kWFSHah`{{ zx>Ft+&Yv11rp8|?%+-`K>D^sje5+q}GHYE{u@r2|mwp!j z9ko+NC-V%XpD_gqP2$qb)pi%sy>7i<+h~~L09`C6c=4l@7W{8kv(M)J)T*Si+dB4o zP@Rl^-=Ck?UyroxpllNja178ewa}p0L2o&|8h~o_v+WhO`o~VOK6fkF*}%f3Tg$9A zg@lE%rws9Jemlcs`xN2_(M81h&&OykgnIFdb41mpVG7GZ;a>k zx1+}Yt3Pb{*Eu9ZQW3L|Pytn5B4$uw-^HSxbi~1ZF||=BYwDDpf5f32uTOEtokp_Z zymiG7WAMx(Gi40Q@KxQq(A}|atukeN7#L#liK|oSlf){LSf{^Clh8OESSS&`M<}C=u(S>| z+PgF+AE+)%Iff-KK#eh++uPFzFUqvg+HmG&=zHL3N^oOEQvT>*?pu#D4Lttu&>%XL zeb$2lm%fUU_JXgS%2rdi{vYo*@QQ+@c(NoV*zb(A5mHvfc#_fg9PC_nv&Un1Y!2;ugD^dab^FJ-z1Yj5^OXUw*b~|pngr7mX_Y@jWTCQ zn$fJT8I%@O1Cgc5&o=Qhxcr*7g^p~#EnY1*=8C|iLMY&|M6gkS=K=*2BVv+Z!EsbY zt*6pa5Fq$*#UEHzb&kYIn=B^*nT6=*xm2vw4 z$DHaXxpeM_*wR9mas+iE9WMImPqPF3HqVKK%BKO+llW>K0U%-2=WYEOA#b+M3pGP3 z6L{62ru)JhuU^_53^!>5KM^Z23Yl~~k0^8)8Scp#bI6{9D#u+1beWyRb>HGLJpZr2 z&Ja>%DbVh>)3Wg^d)-m*Ww+jNY|Ll0lI3}c=7p-Df}#2N_~rW1aM;V{K=zj-i#TGa zsALtjq^;8~r^S*@suKz$GMIi`y69=+Re3$GjRJbdBm^4>y4%1CaDNg?v;PTX$trLd zx?`VF!_G!qaR*iR*}~_0<}32%hlbW|~sf@DQe1x*o61x-Ogu}4}+`6s-AFc`WZqz`1RFVw&%e6y2l z>IGRVI9?5Ce}B`&^;p*X?r1Xo>8Oj_%Mfa%IMLX~Fso;4BqOQa?D~3ZTQJrNX_g%8jbp`?hGFhpeE89NUcw;|>cP_IKurXrmk22&w45M#81-AOMrPU@ zv}6cMT=&b43- zwSm`*A=Bo2FtOphnC$`%8_X@RwwMUEY|r>dzo0Ok2RD7w0E%^+auim=m%ZG1yV zeR}D#A@^C3*b!VZmTZ*KCR97$yJ$PAnao&XV)EVX3CS-zq_^k6IMVE=X>v!G0_3(J z-{}4w@c7r|&Evg^04$#*;5SRhqKG1JlK zcpSY{a;JH>4{MJ=FAcNocyz+K5Y~%SPV&z)_2V1;R;;VDU>A}RmNSOqgJ)z`udByv zW5M+gA4xk%3zz#Jb8JZ{x0mj%omnM}4n5E_YmGp}diwed3lJ(?BqmCH25>nY6StaS z1n4*HDdzbWX6N!qzYNAUALZ^=$BifaEYOYhOpgD-{jUn5XeFxUWU2N8TM8pi)aT?;qvXj%`|WoS{5r?0|*nDcTkp39koM~8X-unk=JQTQ(kna6lxCm zQ?#AWdG81|eop>E>J9BEiA@lgqdki^2bdb;NuK6zyu@g5$$@?ZML^63!D}MBrxyB> zm3!rb%J|w&g1d7uGf?#7=;<5UEH|p|P`!T^?n>&q} zk7}w+Y6H`R!pA@t${wpqo9#rtnWJB>z<7vp*!AQR@`K7c7sL)BKcI;qzt*`rC!$Vq z?c(bEqt*C(7MR@V!%zoqCaSAXEHm8iNc&CoAFD{Zr$5i>=iSH<&q1u>d#Ze$7{@Lz zc}Huyox5dR6ZWcytYHPJM3xN`UP}$O*`TpcU^MEtZR->T+V_&lIx=-WM$>s~265Hu zQ64&Fl4>hvY{Tv`ql^CJ1OHOov@X5v9hSjTj|&pZX`oln{#U>T)Yo8OT|8megUfqPO+jcYOu&N(@}3hB6`dF8R0H$S+X4TRG? zZFu3O-p={nl*3C?u}nAjokscX3moJcPBik2%`V51fL795&+C&9mp2*xA>sHJu;5l8 zmkLMqqw$0QG~&(qwEmRAFXM>=$RUHt=(zzOcOa3yLx!6?W0ItuZj9iRZ}5baiqtZ+|0^1rywd4G=)KTVl6OWo_k~R?ntSF%-y& zt=5q|aQ7<~l|#*uMo#Eqq^N-HpMPE0Y$R zog8G6JWW`9enkENXetgb$x3NLuhei=h2lDPXSANjP*o?yB-Aa?a?9)5^IX4`5$X~X z?kha=r5Qxx8rDE@2Y|O84=-;NZ79Jn!{+r|lSnI*^w-f6?sgP**|NTI1fxPb;@WAX zW-L^j6QB4vKO;k6^^3}z+Y^zqL%3iw{Yvqa+M9Q3LC=pnLh+IrM zx2J#&cV4bg>n!V#WQ&JO2H7>}7cx^FOse(deK13xG=@u9qt~&FZ{~U!cawNb#AvA=Hc_IO=+U)LC%hqM3RF zDGPz%cg_U;+!U@QjIFGn2J3%CeY%wafIwRt$M`IOZb8%%k<-P+{q-@!iQ&-SeAw~g zw)CDq9*NnrboRwPP)(H%xIgM~818@P65S{~J0({QydtDpGMu?FneE`qh4cL|7X1i)HP^s)fY|LJ=?|SbwOz@+6r-B2jln!IxfmxqWA%y$5RP+nu@_HV-R>Q=dgf7% zmm*HH^ls($ou`<)mLX#f^L2Eh!+lozUM#3?O$gelU6qjO>EgBo^9iztFv35O-8Dw4P>BCCubocaDI3Q3!G=yVSk4R305wnqN( z#es3&f8$nula-=hC7wf&VA*Zm?1hfw_#2bCc z`mou<^xjJW))keJ6kDbZjGZJ@sQ1AQzjl?p^gr#t(=U0_(BCBJARj020Hsx1xm)Ud z{ziC)AATcJ@iVp{XbgU#;s)!lj5+e*f7vcr57}qXjl~lTW9fGY9D!$v(&}H3i)bYJ z$ME!~YE9@>u;v^`2IpU}g1_ZsVAL$RO0e_5wNW)|oTar|_%n6=!;=X?9LSmVcF-l( z-Ek6RW9^H)u7oWxf)>k>2#L9()<~E>6BGT+{)HSF6Jvy1Wm@7-KaANZt2~%K@bKNyptp1op<47n=)j#^+(^U= zNAG~Pd`vXgsp!W0+0MdZ+Z3C7G@>T3v_9W;t)D$l-cCU56zF!r6LOR(*t0oRS%7RT z+P^iESot%f_kEs5^2+L($=; z4hZ9}qTGR2BWkp$I|Dpe7FZIM$;nn5`b^d&+K|$o%A!?nbDdi)7l9 z@TZMU5Mo3b4V&Sqm&*4W?$TJSz{_AwW$km&HR+BE8}N=oFKib2sIPB**Yi4B%1#n7 zO$!$&ffPr9`z0AHQ%~xzcw#}682EeAsrBS{nbSqtRex=BvWnk!!J?=vAPA1KKfiRl&5f)HBc4Y~b6LmQ*(;W?2Gqw9+9- zOGo)UZ54nCJy%utisrf*-MB5yIP4I&R^E{N zkCiQYoGamXdQTutC?Mthe36)4@9LqxfzB6Irgd%OSVz>0a}|&4s}k-r^{=b?#r7W^ zgmXDC0>04M$FuNidw!DGUR0n@l@CzW`2GbW{}OOIVvUymqnW()Rm4zbr`k^nR(PVf zc;->1fGV-@B5ZMvzEE{Z-38MQ3Tv+&2_$1oH5-Zh6YOfd6(e1^@12gY>!sk|wHZ(I znsBT5!^`;tw#kWJehsJEF)MXxSfY*T<~f9DFVBTbFcc?+%O^J+Aqo8FFF zpXxFj3nG1g>Hyvh@P!tFRsWsha{J%<|9_Xh#2+HLowAo4Tl~pycVj`nUg-lteQpMN zgL*&3Bz9Hh<{%{#Ag_+;`dS9XTSXRfj1+l|!I8Lc?XNwIBLjqj^*(ShLBLcG#%RMY z5uBcJ_Daz-EKXIdfJz|SHshtIr2c$9m(NN5j)!Lxg@Lnt`&g6N>omHASWGmC*dh%B zHhO91Xa1)~f9;@A20fAGoh#v%BMm>)(C-aZ0TeNKrC;qA`F`+jWZCP+>SV?9a(Flr z50cq@WQbzYIB|H<5%8q+wZQ5eV&FgCuJO(FKNOKx{)Q5{4o8BEVN&HT{Ke(P>E zes2TthH*=C_+bt$HtBG{?hG_Yc57DX^H7DXl2!?gAutp78&7BN!3P1l+eNrcgVW4H z(w*!TsKNS+*v_6oe4AKg(IdJka|4)r%eu5wPCq%#iknQ_cWlvhLAsXAzXTG62>HhO zODT>Dza@SC5q>JO-Kb!gMg(N5|=h9K~4I(PsF?JyCzPMt8> zRcN-}YL5DeBg*82!uA8+e*+s7yHw?|x(ccX2=2OrQ&2{A9I%I*CjRukzi# zLqO$&hw5#0V}W|)c0p!1gRbL>ohXQ~>~82PrS6Z^WdGAr_=ny<=Zc-r>U3rV7C&b^ z0}XLS6HZA3l_{NN$$Cz3J8W7v;H_93}Z<{YRW5-2nj zAcC96rh3-jMEhLEbXO%MSFRPS;`e9zNcw@aK*I}EuT34k7znqo?(VqUV@mVYN}Y;C zr?rwp>GI>}!`z5k^~$xN1E)WcM3MoeUXDbT_?Kb`md>urw#ry;i4WLw z9!q3fxObUU@^juTt(khC^G=p4;N~W>_2b(BHL~5?~rajcpBH-nx?w zE}J4K41pnyajGIjlYKb^>Xzj+Y5RIvs8{Wol+m(GHN|FC_S}XZ$s7_a)}yfzYOmIF zrgyi#*SFK&c9sW{96=8Ys><+TOuUg7s&9DY-G^H(8`BxR7$^STdL3M+ze)PF<$>1h zRlC;RU=Wv;i!{0tR$zW+DJ8!h!ei%q;K{4BjU&+pmM1JV(4Y<>(~c;?SQIfgd=s#g z;$!K1dirCn^ZLnw)aSYkII-Q zt^Bc7lvoupMH9IL5tXT6?f{Lk68~A(cz}Ll0bx3#|DUEB--0yLUy^T z{8b5BwUH&J@MGJf+ZKb_eoggxY}oy!;U&x&C6>tA@!gfXD@IImn6Vdo*^CW+vIaOw z&Ok^}CP?`ie}P&^)Ldwbc#Lv2-hc3)=llT~YZOWkXjR;W5<^?VtIl;a@_#l~<5@?J zM-{y|39jdR{)i}5f>D)HCI-%31!R51Xxn<7T|h^Xw3-MKmXOJp;N*vg=L!A@W|jnN zPrAPa=p@g``6v=r-%aFk^k!Wq=s@sX!S*Z;Urt@|9BBk(cU9X2cuZ$B*n2h0VHIHQ z`!LyCA|2~}#FTmQJ}(B%BH6mZDv&`@Dw4GxY?7KSYt@z*31xsQ3VunQ?NfOA>!r*t zX!B@-P6*@kc%-oil6m2meS~R^ob%264bL|Dsh^YGXT{4~sw-(p&FZ&NNq4=S zx5w+()E_&B+V2%Ae|SrV1g3zu^((+-Q7!g~Nz$-$lKZW>hd71WG#?=9)ReX75gbxBNpT;!_+n$8(fvcX z@md1(1@7Q3NK}eE(s0bZ;r}XE({W`y9~E%$s-os2Lhd|SSvM5rD&ZBb@tm6ii)i$Z z{uY+={Auc5{V;n=zqI?mH~MY&5})3LUfJ#!zgmh*5|CSqb1c`c{>npUW%Z=u&%M1k z@>J0S=UeYTigB8>bh(Yw+*zjrrN6OGP_&SJdlG#s?dY^_FE7voDVW)`)4*z_$^I9L zs8EzEAX@eOw9QZU5cOt7g2z*Es4BEfa6updPu5#UHtY!QL9qm1?z#LAB5NI1&L!ln zPpHk+JAKcd)5|3|Up&U$$~0NX>WTj^u0@8T|K#4a-PT)K{S&hrN+U0o5fWOP@iz`Z zWQiOYIM$Qn+iYgK9|c{70I)w9fRLu9u-$XUU(QtZHk7WGCRmJs&D-BC-7!u(*2p9w=+-q`OZwj-S8Cy zpJ5q9X|{v}YVKSPI_}OF+`6lHbU!^pznf#jm$$Xh$-edA&00$ck>vI65ZZDDxgs#= zce(W9eE8^EyYYg;XQ$$sy4giupLAuqH_`L6722#a-Xnek)FxSTChRPtY;`#PX&2bJ z&~n1i9jLF9Z~%63!%1>X^iYJ7Sodz97WKTlu`*Li0b|6*)U0B0IS;3N%t#R)t<*+a z`YQ|_&)UuyTX13UqwcFVO}a?nrUmB20)2 zsSlwSA3Utp^V()>J8)l4Kxiu4!8|&W_r^baH%2<7lfXypzn^-usdP0WO|-`DCa0Mm z2Y0v)NA!E(*W~>!rSf-}VG(P~AtC_0DQ?=#V_UqmG2TAfo=~J6*$3NR+~$eQR0zd} zQ{01Uci+3;E-PRv#kT2*^F7{Bm}Zhs+kS`Pqna- z&}*S$9^AeN04N>L%&ZOdh{$#K4u(DQ<)Ws=)`PjKHK9HWm`__UoSp5&#pL}?^&gXc z_$6n5vHryaDsO_6h93w@Z=#OT!%DYc9il8O{kV0d+g@yDwHc5Lj*@@@jzo0y*(2yS zzDRnGunLd_-wYjbyS{-o8>w3E3roxzaQY?FDoRkM<4UmUctT2iO?1Je9g{w%vP0(f zhXn{&sO!=+(FE66L!>YF)yR&CvI`<{QGmQ1l7Bwq#;QFjkdKlUdGNY(_dlBK@c;oE z=XNyr>28iVI`K#vdEtUA(h>3j7_K>R)*{X{hnbmJG7s*WeLqB_pD6(!mC^d`r*#2eM-7(spuJ-GA@S$h zFLhcDAAkytsiGme90^qv5qd@<^H$1-;in~Cro;uJ`IT6IDvh*25{wuHE5QWMt4Dn` z#zP4fP0cP=XQ?(4Ofs$8`xE9vU(^y}LF0L(L&pro)TaO9ZRqEn7N7~o1sp(=g@GMh zz?p;!8;49vkD^+Ynrz5jk!RiYsj(=F56zDxc^|3p*OHza*2G^0sz;H!o7_-kJn@t& zOj1*GzI=g0LI0n z%qX8aJD`odFIGE52JAjshO5Z!cx)>uoL>V1W``MnKr_YweQ>OHqj)$G3Ss4pOB z<|$P`)DM)&>YO3UK5(Mk#P2CJ1DE`>=(X!d+zkLKY_ec7@4|g=K`g13Z-1lE=r`Ma zJ?;mDTtEAD+#7QRpQ6*6DNo`|Uuo2Dc2NFjz&gdgHgF*5!&!Omv1+^7rZ}lhr zkQ`8scdAc0G00>9C~lk|7j-0ZXpH+GHt zO4WSLRay%sS54WoQdO>ghJPM`P1!*^hon_kBQ}Q$n7D;un23J2S|W5B`Q-aLklmp~ z6+=$&&7$l-`)PBD95^@4*3;Gg;TS z{T2k4Dy=PAO;2|n*aPPqXNg{En>;(TsJlye)3?{~a+$~VNKBSi=qDCmfVK-=1Mkw& zbp?9whW_qjKO#`5A%QJpUpEE=C#*QPQAiW>Piy3@&NeR=pqA;^8&|M>{i*TRDi^V3 zi8opWw-Pq8UcWKc5(_WHIJ$fcZtaj~ZVJm3vX}m~lON`%Il-^gRrMu4=k znQhK1)x1}4`by;y1*{zl3Tor5mYb#T3#ZxbeUDcC2@Z(s%m0?Qv* z;2!bA*280Y$Us(nG}EPa6^-L|v)uEcD*%Yo+%rHqj{MyNuogmkj)x@Af)1dpY`)b09O%cm0%#BT!lUukqdF1_ycspyLMAVw#?HzDn_0= zG`^zn|M0w6t9EMYE6O$`B4J|5Hcwt2Kb-s?jx-d3b@mOlydA`G?!(584rf>bD5UDdw6-UI@yD`e@9Jca9Ue`K z*d#h}AoOMpS~~*iU)6&67Uw%#1=N%_8&&9|c80B~&PZG_&MCF0V&pO;!5Z$CrJ!)&qt0|5GH;0fyV#L zF^*xyQx7F>N@f997S#4S)OUC5czwY;(J@4!H$fYOd*qYTy=pOVa27oENdHwpxw=yR zIXOL{#+dQYVCE^yUW~b_%DGpqWblx^T z&|S7rRV$th&g-SB=Aw}y`jBRsft`ir>2sM(LF4E?3gB~m9>Z%D(Z+B<6}7-28Ba;Q zNAVOb%qFws`ED*g?UAeh0o4-xouF7EsZJi@hP}G$9Q^B~Ud|I=)ADBwK_$7m_?QA~ zd9vCm64zO?MtJf1&y4WvKV5$1ZK4zFIi1dbPFf)}oLa={9)_&2Ci;iVH*sUTpg67& z(tE4y<%dV}#11%_B@pn4#Ax~Ql@Pxzc-~#2THZOcho=)??qvG1=>);9Aj^&+&~K@i z(I^Aq>j3^m63)%R15U@p9PFmYf^sxkr5K)^BmjW?<~wcG{%yM&Rdtx{tPtxnDBU)) z4qp3jpplN8r)gyg&$?G#S2s|s6$UTA-1ZC7xx3}@{pKKxEd8M;ZqlYl_q)!h#-(pQ zdwu9%`s7+|$-<{}X*Z1kAHCd!vmhQaw$6{VXY-B(eoPpOnAkHngH zh*#i7uJkN(nF}@Oy~_K}o^BIr@K4O4A+*uNnyg(3p)`l#k>Ra-56%Z3I2r>E3mgFC zy{TsX5^L|1T8+BA{VAdkEp~pNa=YsVk5A!xa_$vP&%7CP06jj7hn+Jsd!khC&`CtQ zc<4WXwF!0VJk+6%i*3HGXBe_ElZiA28ZtOjY)<)i?+Af+)SPhReC;UQJ7m<|9aE_M zx^0{vERPPEw1^dKBngHUET3r`6-|0da6i4d^vQnCt$@tfA6i9gNjnT1`Tbc4QzUy^ zu^;qS7>#cB{b9xuCSE$CmuL34mOlJwIJ^<>7U|P=eoyf(ZHLv-Pzymco+FJM9r#^V z`(fqj?(0NoH8kTnl%@$7(s0N%M_nh!mE?bQ#jmc<`G{A5;O*~`3o5j1KYIKdpTLC4 z;t)VSZLw2N!#w+*WMxH-h|@~cf5 zN-y@?uW+E)Hv;FfSd9Ztr@l{>ZZLNK7N)d*7(D~3pm_f>JU-zB9+s zFo@GIXf*M}@NlrIaqmHziarngDMuFFk#^{k)Em@aZVgX6#@23es4O2_!s|WyoBe&J ztVg@^q=eTgUPWEQSQheIG6rPG$($<2*K=cpEKz=quOKhU+sN+O{eW@1PCkBthTWY7 z7BN(lq+>}n{3I~BVE^`Bo}slq2TAO%$=l@au`Q6eY4tEPOkrSbHEJBGhJTR=4lg@~ z-c`m@IF1MHVw%cth@Kv40$8ZEu zSbhN!{C*@+uT*?Kxc)0#DlkkpoStO8j~|_p8L15vv##L!7X%IA`Y0!@?HreYZYo>q zR2i`9QwWb;c%OMm@}ND$x>RL~k5WscS53S=r*F4dUK1NuNeD1wlK zzcOKrQK#_JF zLTmS&{o^Dv{#kK;r|D6DS@BJ!sa&VmR{Rh9h)%T_+*GG*Hv7nJ5I9-O^ zAoykJF8BgM`FAVT?_(yfIt5c`Qk>m<4oCWop;ho59`{@GsC+>I7Ljot{-!E&iIA#b zCTQCccBJLc>!Lb~H<{}E*U!VcI2ZqZmN`RXp##C|#D0V4DnL5#Zse}T$exIc|4aWi z$@==9gcq#n+uc0CrWVjc&^lbjE!P)6t^2(r(DYL3M97pOxj%Whoad9g+H!SgHyk_G zLBF)O3l1mG-Czpj`P$5hF1spJ7AOYaK!F+=O0E4-kFzf!MF(!3Jf*^Y$uxr-qy`m7 z-9f!FETN}jH*kWp{1USd`IO|ReXa|5n-j13K`7#P2$fX`n`Gcd+!w=y(5Zl_9F_z& zwp){dzSs7LQaX?lLQM@jHPU&Vammlb0f`p%>s4sH?ELac?j4t; zrc+2WTS;{5>Nj=IMTz@JGs=no=xF*H)iAwY(|(Si5A3<26;-O}nf*fZ_V4lWo*S;< zlVZE=y=QNK1sec~ME#B>!wopYcUL7)%$?Kk^lgU7MtVB>tND|>vi+`FW7*-QQahytMs!_-XlKnJ`@{)T>!KCidG4*AK`zn8TD8|(#aPXhmiKa6pxY#G3 z-+)*AMa1fJGpawUI&1%;?T@YG1zBesjzk+`-2PLcO5V5cw3j&(8UQUuZhy*RmTO_o zBco-NZsA!Z^Rl(h(on_W(y@*cobs8`CW*Ts%Gk6`^YXMi6ksVBSjfRW(vGsO!7}^p zJ(i?m4g~zKXG=2i+B|kM^-KV^tMfuA2B%=a%CQ0WyZEPt7BWki5>(f2oPIF6%U!gP zR@h;lHbmAMB6zi#2x}~{iB=)DqM0ul7S0Gus2}O+Bce^J=ell8bqT67Ji`o`csX;w zWtm3f%jl;X+O6fgLZqRKI62;>k6+uet7hY?+zPQ%zH2CnWw=0H;1_j!?ZM{t#(DA9 z{S1Pzp}imp3o7x1u*LmuID7fy2ip#pFk+4r4J~O6izM=1v=nyv(UyZc&i#gy+9yQa zEYfb0%yxX{j1y0edJ|V4z&Zc*-#1A_o81@hoTr7Tu-%v9Gwb^hj}PeSgWa$4B0>)I zXx?`ha2WK$@+q=CPxPB<$u&&6@07PRqV;V!DEXX#ciT33B=Uz{dmQ#NXa2M^!^>WT zD5+%y1-PD~h#1v!p6nWbkkKq2RW52fY4Ql{)=|Q9mYp1xo(}-sVToekg)fbvOCB03 z_)-}#nt1DMI9m;;)G;!TxhF%tmchVoBjgwJqx7C*FZ)OKZ z6Bj8sLuT>x*LWgx9T%#p+qIRe8?^k?cL=hW1Sqebd2~v-QPLMYTTHE1HVrAIokHSC zbNKi??GMIWni0G~6cl{qb5lrqYtEXFA%4L60xm&Bf`WT(b|-;B%6UgyUa>wefl`Kq@xtL@d!Qo~(48*qGxi9ojJDbG&AK$VRZL@GJ?#b>v7b z$tV+Tf4)@-T^r6>EaI}wl)!PTD_!w2jt!@GS!NN5m!4ttU54NGdPZyRH0($#0V~?P z@XZcoq9Mz7N+fxL1+&RfGvs(2b3)hOK(S6@0lM4f*QQQA=Y7;F0a{Q)!c zMjEHa-UusAzfrrzlIK1IN}uUaY9DJJ!7#FErUWt9^k%2YivbqgHM4j|JpzhE;8V!l zSaHlEN7NfWbd*+tt$yyyF8(hw=!z#D*SV^`6&C3+QEIPS<9VGLyE7c6R~-#AbZjyKI|4a9ZZS@s>V5<#fA0S1(~A>u zupsbwtX&`cx8Nq-Mpw&N!qY5z{CEWXysl|)c0=P?Gw4m{y?&p zQ`-!KNZpYu(93Y7!|a3VJb1TPBU6o}Z+lmQNWL!NbbWzjm<57Y z%=GXQsMIpT9K;T)S5G>o>1y#g7GSVemRcJ&TnHZTSg8NI$9pG$>5wC;fSWYrrRF13 zdKF}IyigwhEAJAI>xT&V)f${N88`8zuiSKi1P*Jo9Lqc=`JcuKgaw}02LwBe48M5$ z$XGHMPyW&4lyBcXU%&{O!8`QcAV*IX$O%Uhbn^X@v)>2nj02Pu`9=0^t4&hAjI&pL zHuW2*8h47BhsRw#`dQ?nU+TEtPmyqvQ5az+?HBtBDtIYb zL39<-Ln>9_Md$3|9gU}p9_J_Ce~Rl;v#duXL{wrJCP|7j6*1kBDForsj$M9fRBr07!_#$KXb^7!cH4Lw%24@ z6kIKybl|+$T2)JZU1kq-$NNSW?dWMn#|+o4YU@!C*@&{ysrt-ue8p}W*Zn*K8b9%!VSI;KBXws-sG7P?Iu*U^>J~ z(?}F~sJ;11mca?&o1!JJ!g_YsLGEtH+;~~?11Ld>{xFg^1m!EV@DThw`sU-t5$j@e zll)0!qcgn+P@hd|o7 zA@0%#s#ymU^6VdYTg&ao_21Hp=py%gvx;EV79lm~55E7p^1OSA1EM!gPH-IFrIPbZ z(q27Xb8kG|9KAi6Izr<(r8ZLp{*wtv~c!PM_x*|D31wB10-xT_x z!%uxZ$z;JvFKU-VaF10mk!*t#B)hVthoR9@34%ul`8zGHXeHNkXQI}%eQlxdI6Ici zZEjJUJVKPZjW_xA#nXdJWyN>$z%1mx?Eb^+RZY2;k6>O_0L|Y&5RQvZ4pW#CcZogY zA@c-V_`E+zr$YrGAj#)|!CRQ_M&?`oz_ZDI`SY%P^37lO^SbtxZ(0V+wWZ$WGGV_& zV!m6X?YoPr`Gp6c_*oUsYDhYm3Z#12TqNu(y7P|O^He+d%Qy^m=*fhAm7-N}CO>rF z)NGAZG_z13=}hW!Z-hjytKn91U&M%Z!=}?Yv!YzGW#VCFjnRb2Ij}qBlLC7w3n9nT zeE+NmQr-S_d*z`%JN-SWkOnCcR0O;C0bNyYe?3A>;{oL(mx)p(=^Q!k)tb{UI)yY0 zu?(rj3aX3qLd`Oc>K(N-1e+A%>-8Nj3}MM^)v5o`pcHZtet(oHve0RgFWvhyx(wN7 zV_Cwhxa~Ww(~>9=xG9B)=;ewOuTM9zL)4@FD-$_V|MxbmO?liu(`EL2J5SiGU2-59 zr6lpJrJK3?mxbmDJaMU7SLYJLBCT=FA}FUM_KCGw{E|lY3Q@pii}mG)Ys{|?E;eq& z+gCUAfD>>}2s7*eM5tz7#!L+3wF2^89A>POSD)s_q@|iV@yhQu2}w{&h3L_WzLDK8 z2)i;$98Ci+Ub(DZQVZd=h4fZj{W6#|e;RFI|LS6wJRarGny3FYr27Sx7*A>|Pi|~} z+th=Zm>z?p4J(BpHpJ2(pdTu}u(&&!v}K zxz`^c|+6so=)~Ds0DrJ>R)C8u^yDa0bR$y?@kwDq5*D3+g{Nu+@uPQ~B!7eE# zl5Ytkj1}KS$Ny)(=-Gs9GMIDgoD1=D8Ey8OVDS?g0y9R}&T41%M}gJa=a5>mEopw5 zER46E4t2(qn`&>DS zx47O;wL)Dgz-=3SPogOYksr~%IQ=Z9+=-ykISCWLb9 z_aERfH}Zy$q^z;U}E zU|idM0Gs|6!#%$1Z1E%K44FXqBOCK#5{;`X$tpnivBXTLz(4-Z+ppTE45$m*FJXTq zPeb<=u+JN~4rYJM1?guXeQ62)j(7+it#xl9#dp=Zu6_FLMQ(E63W{bjD7>1Fws&RQ z>%&SM`Vo^YX*YZ&w-qLC8)?lrwZyOkc7G@!K~DiZc;2H{V`(rQf90F4S_W5@(zP>{ zF8QJ@beJg=+ebp&yH~K_p@u+&fZWfwUe0eEnz5oV$z=;!RRuDs1^&rre2-!qm-pk+ zW$)T(f#ds&Ese?}Udtot0N!6)BA%AdMfi>)yjR?_f-Pj`^z(tQL86?N2AD^EgLlRE zm&OMF1Jgp=NoRj4|E}s zv6S@p`X<^FcY3I`1QlSL|NBk9o(GF zAL&P``SlA=J&Yl!c;JczM&79Ybe!29FZ7pm$*JS%{Vf27ht(*s@p~WF+I=H2j{knv zLl?O+>$9h$yErA%UOppo#_EOj8XfR~xb9by+$)*|bl1#f35$dY>M_P_<_BMV`&_OF zr?FZh6Gcs+r3n=JX|c3y$bBP2baK{0?#!Pd+YeW3H#im17vgG?vC-lq=N`$BNuobT zPxS7(<1#Fs?d6RJGR?-62rm}ZBBK;4Anl86l8g}D)7kO+knd>U?Wc%~h(}IGhE3g} zf>S^cCo7(iLaN2yxZuV&_lBU0Sff9N=nHd2Dh9>)^aFRXR3Y<3tfi3K)=}_g>o#6( z8}p*c0&2^U!d^8YxMk|Vw4KLW|%J=_x=g=KVsZ1_5E4*$z!7cFQef5+pzsb6x!xzrq{ao#P zqb#)}2(A?&oVk%Pv2$yD41lH3fnz*w=iHX1Y*(mCxD(Es)cjb2ew5ISdw4|l-a18v zyRFb zRL0FCcPE;<&3_W^R3B|qRTB`s|5x)lQ!l5Iy$K`P+#+$v{VgEz41Z?^+xYNH8szDk zTidltXOPRB&NZJmiSz-EOYr9&0;}fS69Ox=oyWd9Mjb&dM`hOz;9ws=j=w-j0!RS< zYj3NS*C@VbqVD}Uj+HV77|Yydy~mRS$ly|M+#cdrTsX^QW^f8A5lU;G%qSQbY&P*|QZ&FyBX`OUrdJY;5v@=i z-{?XOZM(mkZ4GRyOsMU?B7-~IA;Z5~A-)gq5~Jk$GQl9;PjJDeyB6l0d*LrX%PCG* zh$a@YD9vDLg@s;+IaSB}(xlS>@jJ_maY-<@`FIo(`;-9$l7 zEG2Bvd^O}^-Z9R696IdaI)K( zT%@8zlWG^*Dm)iH1XsF>=8McU5dE&mxdsL+ac$n#!@HTQ>3K@QQy5UPB0OHP8Mgh? z{Id@`^t<+G*;qBIeaXxcXG52}d~}v+wmoUzGyV`)IxN7&{wxs+2~p0#u361FQ3}Nf^D$fJ;Sw zjV?J8{qZ2#2P~YQBs(yo)-&EquYE_o$FGOG$eDY_j&%Og-Z%q` zU&ypqKcu65nGpIm|7#vr@{&nXH=e%#f}-#2#!BDQm)s~K+=|%s;tRlvyyG(tx1G2< zrpA)fg;uL_Z#V;kD1a;YD`Qs;gHc^f7)9hQpPqazP*bhpG9rHeNpyYDXB15TCbR*( z{Wi-?WRs`HtBTHPDC#pUynMXC#}hPl96|CC%lMjD;#^(Lz&;dZ{a8o}A7Ap1i|#Fz z&1B=xcv1@D%Venyr(Mq4dPwyznoyXhW=NwJr)Vo`XykFVXR+mE|; zB|)2~#_=kjiLyd>lOc^FnY*vYjuxD_at*wDp9NfDRp!0UZDu^h;jnh+Y~WVOp3q*9 z`S28bA@Z4@%X4B;w9NV6GC(2npJYCx0F{wQcMVETs;nQE8)YunCir3977GnyZ4=oB zPXFBr_2WP*PhpP}Oq8SNiOf|c-6T6mcOU@+srw!UiT@?2DRT9N#X#6}=;nZPgGR@rI5+EX70J z+k+ekVhEafr>_4F$0D@_`D%PnF2XE-9;VZ=JE+6b(RRw7!JnD;-N}}s^8wpIHl6}G zn@!Gc`3RJs86cHT+>F3|hW*;Qrx83iqeT6`;Ap)mAf$j7-AQ|n{%3^Y>RPPy2n*H& zyT8w;GAPY7uIF81W`b@b{Jc7ze|Xe0EdHGDK1J1!r6r+%ABe$&b7J`Qq1-Ihjew^6jN-x021;Z638$GPOINOyR2|`T z0Ym0Px8GHym5G_{PQFe;$*4N8L;K4)R}CxWe(*g6Nv-qy<{pDi`KO!DunOOm&{1e~ zh)Ju6UKC$+p9jSF+e~x0_MT@ytTMwTG(NpDn zt#tWzXq8P7U%qqFSC&%m*|oe+fAZ?jaQA7YR`IPTKW9ImuT8UfFg4#MXc02oLj(;HQiFEuy)^;kms*@o(k3YZsDVnuQMQ<@OPK4CL- zKCvmfWY(=ADZ{mD7M_xGf>o zGVv-oT%Z?A2I=!6uLfADW~QUvHs4Ot_4}U-564nXXO!ZSSn!Jdt&K;*@NJs97J241 zk%+4KGx9q3P5cX#lgwFP&7`Bzc@R;4Kj~1L;U)o%)PaY1>BZo=Y z#t)asVn|f9-+q{B`(D(8H#c&~Or6Cw%#gS3^h5$g!z)!NU!T}YTp}oJP-VC!=Ex}H zTA^gPMdqwbkJywq!!`q^SSV@ z1mYzqF`pD3LJ^lAWdKfF5|#oMGW%}o)`e-(P`VTtg85kKOXM#UN^DX_;I8x9TkuV> za!my`sHcHk-0G#^dZ+GT^};@y=}S06^8eOrkp2Pucf5yJzJ>(!O2{zaxiISH`PG6p zRq@U6IZ&LWWOsllafT-x4?hHtuFUg%7l+;VifeRgu1~3wydy*J2wz{7h(G^j7Q82GK{!6$M>_ zAz*vG$=6FBY)3|F$+UDDpU(MhDAF-rD(sWSM%t?0G|m0EYqH*J>G38W8J3>E#jo@v z!oevcxK{1?-#3l?f1di(U!P+f-jGt4%p-6>M`AbX)990G$Kv2U!_nTo8($S~WNi(F z_a}w$il$f)Rsd-bty8x48vrct3&M}%fl0c4>8szB z+sD!onFQ6h4@K8$FDA_C+Qo}NI016HBy)?bbDod(%udEhIok0GQzl&f--nnmx%@nj zqEiLoTQPh|M5m&2w5$zGw8@a=&d7wV?GhThI2}KR&->`#Q$Jexa|!9cR_J)jmPG!? zb6g0&`Rm)gGj;97u3Ww$ZWcl;%Uj8B9_qc7H5X# zey0DM*mcC!tE~?=!QKLcez%yUNm)6Ayp*_P13PdPZARP#B%(M)oH^xYpeq|Y6~RE` z1{a0gKHOR%J}1?~3cIi6@LBzgA%j>LcH6vmDo;|HbrS&w6*#B$zS0p?bkUUJ5k+*- z7(7jifZN$?rZjQS%Xg{FTq7YohdsA0syS@dXo|@q%8z65&w3FXe`nWZ6*O*{A4o5B z#rJCFNvik|(qY3Z8e4Zh>&fS~xj(aURjM?p{&XEK_x~r#==f7!hEZ}L$M_1mb?x0> zu`=AjM%9=;k4h%G5Fwh1lC$TId;jgz4!ltJo@d;>`N4T`F^pxbBUz#yO@kl2<&8_N zti}5F3mPfnvp=TOiknD>HjDiy?Rhl+$o}b}W-y+{SHLekaN8{`cW+Zo|M8RuMY*U6 za}F|gxFxoR>F8%zZ#76yMKFJonCV*g1PL}Gg{=8Gw8B2396q%W@Q33Ew>if?`@lEE z%ZK&nHdlFgSf$pfO(D_=1BuiU>{JzV83;Nr2h~B_HKycHwGK{IA-$M=TWnS~Vrtb8 zx;akDf`KvxU3bLf(CPPUxt)Q=0t`!9GYkngo`64QTHdO=77}W_I^J7nQCB-=R=?xS zhzACdN&~W?y#!LwX*YJpDHhuntkgoflgV0GX^FNy>UCnJmjlQd*XWy;9q@wR^3>7 z_OU(GMDmYOvTz$7{($IiFl=z}SBcURpwcz%=;;}pE{P`S6I%^t%cW_9EcB>B3 zMpj3pH{Y=gJj1_04j}=@v7mLUekP{lZuRc8or{WZ&K_(^f817hS#t}oe-i_=F z@*kbvi8=3gCyGr))vOzv1B=X~RkZVhp59E7%Sa6(o56;;ssi25qisuNexa%+$qXYZUDz%uT%_~lXt2T=Rh*y?`Qp(Wq%_+Q49-lTcqX0<-EkrGvq|LJ zYeDPy6D`+U9wD#3`p{Hke;&a(D1UaF^>oNHFc|R;M#5j{@mYzRRW`*7JY;hkb1kf8yx?!Nnd6-jmg^mOB+zC)e3?0qWc~KG=J)=|pz`vHtWKd-=O|*&qeSddNFyeH?@XbX zx<@F(D5uO#HTft-N876D{nSapN7;+8{(cpigHd$_VU;Q(rD~I}2%E6y%bTBFjkY?* z)TK5L@ItRo>D}MwQVETF#7Xpa7ceEXJn`V}7vQ;dec=85!+vYL(#Md2DRX3P3FdYQ zrq>8~bJeaeTPWuQVTuDt09ZDY=^d6-a zc_N{TUlvC=n`bz+^(LD8n9WwH__tLl?KZ97mYw@H(HJ(g;8<~OS@_FUp}+h{g(v@b zcgW32q(GGo6$shYlCVcCJ1<_`a0qWYBxEGR3E$VwGXse7`+F~E64^Q_GB_H?0HY)8 z&ay)So&~b+r5Nc(0v&!*j4(uxGC(Ro=1~Tyb$})UIhcO)0k1qh^JjC^;oXbC?u2xu zR+tYjE#K_Jz{pp>;w1m^*#|O$mqf5acX#EfTD(r61IT z%Xh^IW^M6mD*uo~Kpx`)@w)47V`WacRBnH5R|<*jJq=XlC-PX6;-C^iWT&N+CuxoQnjmgjD16#sAmNC9^xN}Z!9)K0T+F;5 zBKtF3GnA4#tA)`qed!!JKqL)W;0@48k(_Mk(6AS|bXeLV!4CcfBJo+ltq}?$Xrz+O z5PiRt_I|#X>fh&n)bAem!coAm=R|ifQ9XF*%T73d)XGZejhA#55aA%6#Gs%CVw5pY zT#OAQvuUyPpskL?Jaqr7%FN3%|Ar3`uzT1y=NHKrkh?Qv!I8H;Eci8KMe5f*FdL3= zoblX&PRzR1!-#(d7m{nFe+xRcS@tZ1j^F3W!_!GJ)}bjfuz%KNFykhQ3|YL`<1jMc z(sIZ`hmPNo$;0K1E?2=U{+Jvn|3-xhLv;3)ki?s7)hA)l6HCkb5oZ(~c}BQ@Bo>h8*IpOIWN1V`qf8a;of zqb>R}WHkq#Mlqws{~z$ETnm{s5fepPM$P7Sh7uzCfvoSBYOSx5KYrv&S;dv>=mGRh zWh}?qSzsoC;sek8MvTtI+&$w4m1E}f^p*p+e{aDy?Bh_)UiprNQf-G8UhU38u zR;iwEU-xCy!aw=t#}jkVSh1SF8~d7Qjrj2WsVh#Blc>v?sz(N7i&TLW&ik2(wY@Ut!7gx405!m%L}~(Ov42R%S{_aFomQ- zXYF{4Qc?BSj1Gp}BS=lLGfpf?dV2E2hI;4Y0YJbOC+5&x&&`)#MBHs?Go7k+ghBt) zJAhqzm0tkI84@_TXfb$_cN-_T`FJ)PwA%lsDSP{dJ2YM*j+rB?VmsvFA-Uj`3iRe? z+6J(D&9kcZSf0hr9jCiD(z9F%QJd|)WqX25<*e=Nl*ZP|jtupo$2TYTi+`~=YK>B6 zO~+hlXPG!tOJkZ6hwL_s8-%Hj^F;+c!k+a-#@Y`(AJrS@duup39fDF@gd ze%t=lA;0Y9K)U%}Lw)Auzrg6&6?7LxPl9`-h=EA<7MWcQ4C$W0FNlT8y8u%B`g3uK znwNvZ=hq!S%Oc|$(syw$WQ(Ta=Z5)L(8k#CnB57*NYZi93vmoV;=F>8C|}S6G~P#R zTue}*-AET-f7sRqg!OIrH|D%7(ACVDm&h)i8XnoyUAh?f@~$3wa5R%E9c>OBy+e5~ z`XPtHiYHq%CF!F(py#Q`)mDnHOLT`=*CdD)3!ChiM6Bo@-ZVu2h^=0^Im|H8UHy_t z*UAP+H&7Pq?3}4&iauig+q+w$;k1iT^IDzq;`B#t?hu1^^`(s#676zXqW~fSt|IfZ zH5Jl|>+Mdl|hd4X&w%pr3UR)arn9jz*d);h62HFK|h9G8%{tIFChOidOFm=I`oWp53&8ACF2BqtSi zOEpfA_jJY7M?;X=*f(Mkn;&q|{p?4%Ghq~NGq^;(K4(@P@i)(O>#6py zyjDBNOK%d#&oaLQo`B6-8fLpro41_n#74pD-3WLi(eB5M2$BZ}F4Bo2K90r$y&5Q3 z3B>mOIjV9m*H#%+qyI4$1)#Rdx!$`l0_R`;9Z5J06k=Zqux$GY)=P=60622J9i53%Q2IOP8GVw(PblT|HIM~YA=s4K* z#!xs4t_+^vRWM*Af^ea2ib4wBg|OLuk=r0@(u{jWzE|yJsM!T(YT;{F`dA{XKbh_$^7M=R!Sb z7?9A=lPEylF4D5G3v)3`KK(T^*WiSW`I_d076jWf2Xh zL`%!_k=zcD>Q^}68=P)+pO1h=BcD+LA4oXy^RMpkgM5!;e;9(=1wS{$o#S}xUfx}{ zVFm^zE)J_TRiU*&>1D+v`9Mfx@=On!P`2|>UfJv?nZ!KFQaZO-Cp=>|$SXZGn<#9< zG}BPV$f=pFM~m+k|49<z6Ln5pq*?>T9DHeGyW#u? ziy8evXU|8y1nS5aq7`AHc70KpCL&Y7y1R?R#wG&a^S11(av8di!sA9qYh<}u6RYnZ zfFdJMFmq9_(*Ol?^MziWky}xx^_Q$v-Yjy6f~H;?)UNYM;?0&n-py(4dl_u|(*MdaPkb5vZ^jx}8=7SkW#aDcJ%!_l`f2o&>7 z7;HIf*+JvJhw`v8x-GC4^|p|Efs@A8sF7a7>NXx0txSxFk3t>*cGMA2?yMKsb_RXa z;YwR32=^RMYVUT~0@+rz{Ix;gXv_l=0UZ%dJi3G~*muBh0ocnIsEjq9WZ{9P$aMH} zbzrpew1c*VdflC#;;`XkGjX}CZd$IIcum}}VUd%7LK=78a=m#w2}i0F3U%^DCnJc~ zOrS}0PMgCju~u%n_7{m?vA7v>JCOuUXwMmilJYuMGO7S!3Vt%%-%iE#aKX8jw zBxlsca4k9olDJA4w4@{O*)YzS<4?m4DcWSG&f4R6&$!pnx|RC2Do+)qy(zyAFg52s z({t&|QU)uOj zBd_lSzZ373{n@H=Z!7}Y&YCc2TP$Fgxifyc3dx6V5iM$mz^0k ze={rRkU4>JhR$gCQxw$GlTjaqK*+1AQs6-x6H)A11oTd`G_IqR3c` z(mB8foyL6dxkBZtvdGNHp@T92n=wUT{!U0#~!EH;c}TpN+oN3+^nkkIS~OxTiQ zscA_@VOH}}195jWsO-~ZdLlU9+SaLa_l+Z>zEWUnXo*W1kV$WnsfKuHXrOY zN2q6;$u-b^?^}TS0$ZED*r=G@Lj*6ur{Z7(_f;P7aAcVA332IP zNH^zS*W%Q^uKANDYjc#U`q8B=$o_8`kMeU5 z?PC3?dHjxgTt2Q1jvRj?)g^nS=h%2CvC~{M(%LPDmEqu&Ko_876A-yN`lroa&NkpR z?~KK}wzN3UQ*6ZjYQi3|&68IwBZ{r_?X@y*8b)?nd@Ig2(pi#&B-O7hcBJ$E6uyowyr(zaui=r@~XPf1; zdco(>*%TQvkBVf-i9?^XWs_PYuF12V@qE=xCNE?Cg8;W`msqIkGikH7ZpZPxAstBLh)T6l%imXBPaA{v9Lhg!X?UEEck9N$)IA-h9`JIw8BI3Tc$9{ z;;I5T6*tprX)JU?+35D3O|Ok!Px0A1F_M1dERm!vQymo?i9hHJ9jmApW<&CQ$30Em z%zW?nD27XA+Ml@u(E^?)NWYA0ynRnH`hH}zbI4JQ8_GjF(*p72( z(f2l2VX3Eq8!ArO(*~#ZSGwtuoSaT=bVK@L!(iv)rj{lw*BQl|_ejiR+8V)z%e4`pQ31;Y1alyCg54#eQ zs>c~ZN3n8;9KRgqiMFg~IfCTg29$NUiT1`++ixcQ;u5?0bV!ymlwe|zqQ})>h?#S^ z4(T^n;quuW*HQP zo-wRC3OV$G0l>0b&du^ai{wV&!HeplzKib%mO_82SAq%VQC9629X0hlO>@I;2lwk| z;Lgi*B;x#lFiu%H(0S)Y6m+)qtT65bL+L58jaD}Ibm(% z`mSDG^Z7LEJ4WOKVQC_?h+S;OwQa_OZVnN3_xN$H^5Vm`U)#g(q?ak+_b;qn(&3l@ zr2NOnRE=7R?s{d-Pi&fXCZ@DH!Xy{|tP15CXEoqT$Y`XwBPa}i03cVO5upm7I?MA< z-W6*x!ll>AFrh}N_a5~%8uM%7#!BS{Y@hW#bnV!W6kgfl(`G^s6PTb<{)DEpYunj3+N9lB2tv9rQCCFP!}5hyZh(sca|Ktt zw!Zf1rX4%w+`eHmrs#+)4bb6*pwQ?=)6;sl$@lB+6UZ-OP7nRfi%K*o?y|21{#=ys zfpic4Jr_QJNE9k84ddB0>;Rn)sZdyyF9=Dr_WO|q{043z5k(Ujfu9be7|sgyni!f- z!WmvxpFvcs`3H63lZRx+P|1B^6W$64q)S#`NihXSf`PQmGH88^J_qumbQcm0idm+= z|9Wc&-wjzv_WdY0ilo2?**CqwY*{Hbb=AFd1|c{;NjdTN;AX?AXT=-r!Fuc;{H zjbfMTbUcx%a0=33^@mOsxabF-)ruu&t|{F#Z$}09`N--Wns!?^*DfyaPLt}vNjZsw zBtufvxf8pM+s>Mm;LHU5!2&PG+(CH;b3<260M58x)PyHR!_*Fc)-|dwRBFczSZpaM z)lwVTPPcOoVKT<;vkpj%QPNluJiNCsr^?-^<~0Ex6$Y9{Q4BK#d4)I{VrKcJslEb^m(BNpw3fHpqx+30t}o;q?w8JG zq9@QBg_64l3Q@PP-^SYnrv72l;?+p6IjKswPd_?p)YxeD5(IMOVL@l%5g2aKXHgC4 z^Q{scbTB4Ua^Gb*2zbDmM+|EKr^yn_TZ0PUCzIo?5>(j5?tz& z(c3B0@nWN(Ph4kb#;WfBLU=?a2l6onRRvQFEbcXp{`#brrJ6r-nTr>8o?gvOKV!CZ zb9Tk!3tkg2&Xs(p!#1{dInJBy$5ATB(IBTk;Pjtr&78ieIfg_T?-kd@wPvAPiA^RE zJ7aP1?zuU0Fi`-x8TPp9`eMZfAZ^%GhQ11MOg%V*iyhDFl1RTFO}R{|GPeB8d&t#U zuz2f9%iN}HA1$K0L@a<&U4#dUFh`purbx&VVjc3d=yE-g-v1MNJFRo{?)+6BHJii9 zZsf8o$h&JX!nt*y(@i&XI;GX!Zc=EVR-gag0L~(7;%Me<6TJ7wEc>oXRnil$kM{$K z)_JwttV+vMe{|=60@<9I_6GQ(-B=j5SdY&%Wf(@T>lqLilY=kC;qoGu+!>U=i zqdH#2>G^r>Omin zPJ4o}9JM`+AbYL_relyNl{sbDAh8ajA=&;`v;}P5b_*E4UUVA$n4%LkC(45RqJZiB zrw*|&i2Yh@t9=ABM>)7x2{IJRNo3?wLYg@VYSZE8w(6~seXE4@a zvna5~={@o%rD^QyK?W#ck#z%Ez#|WIa=V+npyt?RvP8zb8#ovGR&~G++}WGajG6Wt z3PlTieVI_n{qbcQp`q*-MWRg(7W&0zaabDw_@nkX;l7-70|jtOznuj@QPt)=yz!Fc^t!E5g`4{`3n0TtJk7x{hGjDK z&240>;eGJov=g-Xylp(%NTGkXWiHM>dU5X47bE*TPFh=jUY%QY3m=ajCjJqJPg zK3nS`rUvgS;qOQ{G%?@_3PJt7+FFZLdSpbg?yHpaPv`vFc4@^Ay{qy1Pj+W-9hc5V zYa0Flz8`{QTjX@9`i#2b@Lu*04DG*hb4M*?Jl|VhhFh$E&)oP$WLIFgL9@m|D6Z@` zR}J6si+pq9ygcYM=ra)%CBy0p8p#I3-mQ_P$x0e`c1zhXukZ&1HOjpiS0`Vx!dI!E{Dh2S=na@*cr~fUH_Q24|#gjHLgP`=jXkwzQ!B=(D0Ng!M zxGiV1xlC=lxNE&o=#)f1J+pvHX=wsA?P#zY`Nca)vT1ZAAgU{>7~1`}4n5@Za@yeB z3LYErBQPE}1yiyA)K^{)@r(O!clsS>@cj%LjQWuIq%Ae6@ z@9XjQ&}xAZTkY?ok{TuVb{hcTi~LFUR=}dGz3?)vPf{@bJpY z)hO}m*On|tI>>Z|v%;+{rLoO43UG86IO8>SdwU)AD;;cBOWfRjOS5zCLZAtmvqe+1 zut`i`yU*-j7(rkHIFR5X+385pm()arTxbE-;y|X-Zn`QnW@y3O3BW;oT?CcDOLsnmm#d-?iNanVuX2#y_aKP-bmXlj6!NPlic)uA`mZ79ZTNa`p~u}f$qm22@*&Cq;(XA*)*UT=C@RJ z9J_mA*fi<=d7$U!X&3Hc508W$veI>z^t=l=CYw!#pp6e^#3TNNY1ay%(^YB1Q_R>C z7+IwKtM<$}Hg#j=IORK*JyV0uedK9=aMZ?I zCg_<@UU=4JeUIWWlP*c$-2f(5no)r9gv|5oUiAUhh)Pt<5@j#rzWbYK*vK<~G@-}% z(!hQ|Z`0H6c`|LlM`Iu-bE5H}05WeKw(B&%j9je77=h%gk-^UkLqGg9TbDWgW?JepE6Q4YEoe&(0 zv5UWMRN$O8yFbE6(E`6V?MS=p7b%l0Rf0ZR3B%_U5`TtD`bt1af9{*%(0y4%i<9(| zzPI9%6jFytq7+v=2%emWK4ZI!9mT`P!Qx4X(rM4AC0Y9w!A&F{H2(_^y>Arh^%8hK z7w1X)9aw36A=AUJKU*%Ia*dq?OZ@Ay>pPwus6r3D=~r=!M@oFD0$w(zeIVS`4oY`p z@n8)OUA&343UUM)$^%o5`JTe=p2)}j`y}}JF&Q<=nsA4Q0u#6~&+Uy`)H(vSZs>QR zWA$UZov_Vpv}ef8FRw`y>JM(Q&c`=xkSb-afk>sPOShi>HjQu(BcuNn-7$YbbZo^~ z^;C@d_0-QB4sHQ`qA5_W%bFGDo7`yUiV^z`{Bj9A=MZLC#TV7@P+Wp!<)PwT(;Bxg zmxAk`TGvapw%|32E=!>cP?WRtzjMDsC)_4pSvd&(a?SQf$!uB8xu!@9ULV2m*jyKt-RkmsBNa0Pr?PhvruJ1MPOH8m zCjylSMs1@?ZM)=GkV2e(z7?h^{c7`TtKu@iV-n7JauB+1>72!(P7aELTJ{SeE09=; z{UoJyC*7^LVR0~5Kp}QsGujVLLPx1&b?2;1_uZuP_e%$fBQXmd9)}z|9VeRe-Q84| zn0J$$48hY?PdI%A3G3;vbKyCYv!YPNw#Rc%@w!@Quz~AZ?tQ_K+vm$3wBn|EkRs4= z(2!L&XSTBwK3T1lO1@1&BE{tvoyqoOx6bB;#5#31x|jT^0kfHW3cvpmga3d1Xj3-H z%V&2Hip_>@9NRrXa}zRJuFIp{y%c3;y@Mpt8avbpP!O`}AAI5u`uk+p5{ckO{QvO} z;u3|Ad`+Z-1phd^k8u1%M z`vpq3A!;`=vBzM8sdZIp;m69q@Hef+hzGBauS z(eW|px}#r@UdsyG!e9qeEKVIp0k&G!E_ScZuZw$0*T8Q!mSk)`Nfs1o^D2kl0eiqp z6j5VQQm1e(Q#f6yI1q_WNPhPUbzs#5?OT6*tGZar?~m5L=1n)3UbiY3*F;p7)5_LM z``P-V89NXw0Y4?ZW;}cVVQ&6rp^m({{Q860)lbLlFAV81cwABffPD$A&c=rZ1xeP?v>H+k6qHeh0mqO7L+T_%Q;DmTt)NVE z#?sdrDz@Z_i#xHgw*b{b9W+-?axIWzv<>2?2vTC&2kGpAJ>;Ieh$LAY_Q+ZT77_=s zE*7ks^%Yb>6(ly?dw8L(*O_kx{4%ud3!$c6c?3@}v1seJROLhGO* zsfEFjwW6QD-m#@zm`=KJqh<|m4UhfD^bvOo$KCdB&bXVNgJ}uR?fhj0imLUmO?5vb zH+>epdsa%cPg$k%nt`@oA1d^FsYA>e^FEr#0g(0; z{tI-j+352*n%oFCXEg-D1QtPQGi>us`R{zMqd(piJEYCwL6nnoKuRxIXS8eIn}~he zC)61&Pae%m0;pcYwrO97*!~j=cS@?Euao)(@;Pc{^Kx%859{sM-3v3AGT2JW2}>w7 z>DJNM_`ot5!!7M3YWrqZqBZd9+i~LEc}Kf*NK0lYV^MZcQ11rJ2bUd=;~A4>4532Q z4^{VQ2x#+|idi=uG<}S)kMK_Y-}(6e*m5S@42&c87A4}hyt6F6(6)etF3Nz!We61G z+GdDE#~)|aLG)aZI~3} z>>rlcc_|(mG^wS2l1N$txtiwl??$fGc~)=5pqF}M898l9L)8*?bKFrTR%Ptcsue#n zCl@{2yx&C@H{Kf6(TG&DY{Q^rc~}){Iy?Ss2#F~LPN`=Af=Ts(KjZlc)8muZaS&Wk zK>O81%B9Dj#1$VKWan{~T7&a!sDCzpm@S~d%Q`;BVM3N^YGWR^_o$N^`vpC%=kKLY zGMSWWvx0-Sh?Omqa~mI}bzfcF(jC2-i|bagr=`V6-f}%_@!F^XOPRD)o12cU0#&_G zJbGNVO|3q0DhSR!t&W-*JtW1D8*fmHWdYZiP=LiQX9aD~PU`X;+WIgSAS4=oo@su| zI-C6=nGZclqCK2Ov=z zW6M@?MVId%J?n(4s1+IqZsK=iBJZ1Mg}h;s4n?^bgd~UQ6z+OqjwGRu;WNw_gm>qo z(O-p^q>g;Q9j$&l(uI$^*k7UpLPb6)abcdFxBek~woh`$&ok!C+NUe9{kwI#_7QOX zA_ExCG9Bh+eo4V0!1L}zzFG1L@-925O=ND7hbOvvV)3hybA_tSVYUg8K2BkAhOT-~ z;@H_2Veuoxrr^(ZZAHMMF4G*wQV=Gh7pdATFfAM|Y^M%R%4xuBJ8u{Wgo3Zsa-*SB zf;qEAUgXmYXKp&wqMA2dxICM=;9w`Ph5)IUtD=ZcTak1j`YfjZZwp zdrXKJfM0?}Hv7x){)I#X^%$6Z?gwW$yS5PC6(WUP$h5H+Ff>wl4HvC*si1Ljwz5om zk99u;TS;Da6me@Ne_0Xlzy47x7Bl@FY<$P-BxinWic#=BNUD-IW!L;;0wDRkFNv<jaLjF2Ec*AN7^5o#)&?wx1NYTB?eJvrZQUiixaL#Dod;k)l_3rNYXN zq{l_HvjB=}M)t|+14`4A;1fkBqD}Qe$oSLh`H;aQ;$J^06fk4sxz_q;>t!eI9ui-2 zSRNtQZm4Jzi$-IJ>E|d$BF^{R710z1;I#63mq5u4U9DR&TRtHcF!8uP5xYO@DBc0E zmpp&9_MXrbZCsn2z!d`el>t@C)PS~%lwcD7f6W+PC(2G)wo!t`J$vj z|FOFT1zFfWI?v=_(iU`sW&bFk)*6l3yslPH^X;Bjgp2*ap|h!*&jhF9z#V0uBIdPU z`BDvC%xxacgNfP=A5s)u0wv-YY=0Aev$w8)H&o$j(*~EPW(99o$tjfGdxdW zYKUQ5gyX3j7{h$Y%NAhYZ_VzlN!5{o9XiP))SQTWU;KD|HCxM4@uBX!rjknP7>+XO zx?YRtQSprjwL9J)265VBvNU27G1=s4af<$fHkk2ZGN4w>J(3Bwv-B&jO{bDn99X%T zd?!Jo5omnDs@4`s=A^%-n&yBM!89=)>a$#og8i=DKlxrIndlYNOCf3p1E4TOo{e%f zM_bj+)V{gU|JZOsuHK-7>t$e1A-`lAOXgI#+4i8N7aJYEzxy2+Fdn2uvx&YS&1}o} zb*_l%OUNL>FD0|y9mgO)P&8R>TQ!!Ub}*5_oHm;9;zd(ugB({@MBt*No#nr;pQS9j zT0{q%E#TR-$0w3?&e?Mo1)zr^l|^_7uSA|-{=;Os7i-^hg+)4Dxz__Nh5J;g;2 zF95BVplPnx!KsQ*X>kIP+c3p_a!~^Ii>A4Gxa6A*S=3totxNCQ<0SZXri?nUKUa{K z@z94_2ZEvsiLg)A)pM%B>NzdL@=2OdXfp3INRX#gQq`+17I8a5lU89KxUmo8sFm-} zOynK+`=PA%yjlK+seXL8$|I>sWcFRcI+_APEFBPshoF(7EBo}|eM$s=(2-p+yjldQ zPJ!EJk_fh6-O-gEe}(KW30|sxQdt&cG|=5;wEz&Q1ylIUFSP(y!YQT2m&{-0|!x-hzYGiS&J8D2+&k4trG! zlFgxF14h6pj<`I{-L#o}xMq3Z@zUw-G;adr(N}=Lj~S!42A}nZF_s}2S>lLdE%2jj zvUdr`whyxWdR8rJ|L0IH$ywgtzskXdSaYr)>;upeExU+`Q$jKB>LFs(6ZhV`(@5NsO+4@X9{HW(c{oWmjg@_=W>ZV0Q_aOysNg*Y zr^kG&w6ZL2xls!L@1aNhS5ipHLT&;AmIef!U(XTQom;us8s2xcgKKA{Y9N0IAA)%% z1SGk-=kLT4aQ27E4tyhEB76uhs`mVz@NhV>Mc42e6li4`;mr1oVH2T+kZFql3BA9K za_?c*B+z^9H00$A+)iq`WGB|``OHD3<%MbM^jtUz?#1(|^@O>7VQj zO#Hq`uW78)ES7*)<7cuO*Q}C0G3Q98&Q+b7f;MF^W4UrtdvgRiGQize&&Ix^Z7iXA z2uOpf?Dru4W<7rdm1|ohHT}VkSP?o?KfJ5?p=|iH&;$u&0~rHi?1GDj6r`2HbXt#8C0tuJM=UV3;?oI<56pk9Nwp_(DnBEb$L~nBvbO z3I-}d5lBMotYHV_>z9|jqG=}G@CTlK{D=aH2y&ae9c|3R_e%szy8-aWh2`4A64Q_2 zdm!n4gj~Dcf_sRnO}w!Lq{mk$Q~Ug48y+dYHIU8C8L=~zP>6ILbVTvztP2`=Fr(zd zTF-V$$wfTxKLWaIzO}kO*~*o$4l&coIuy^_CJ>?fonE$ZT@!SR{dCtOVE(m=(zhxZ zTEe=LFm^+HbEai!Ha#dG$kz}((&S@1Vqg0xUV`>EvAP$ZlNGaXlTzaf{iUb|$Y;BS zyQ4oDtuTLJA-*k#Vf z_f*SefKxmbd=pDFyRwHNDW8Ck(a29T%);T#VO#z~w{6;$x+p`Z!B>1s`NvzAmP^+0M+|z~uqR=wt-hB@IPw-umx0 zDim%1*0gW~hrj*x)nB)Xe68*7IZAf8;Ch76YfzRrgpbEXkk}n4;#`ayyNrJvAr0y` zYQ)`CCP&AXQ3;Vw!j?)DP`n$$aT)wz@MaNo1~3&UUZFGP1yokMAeSmfOEQoFw7b-$`a4%SZ;aR$bUU2a`NDXiCg4gKDu;ePf0nP%0<<0kb|ML zaEd>y+5ZjttM??SYeT&|zj*DrPxcgjE2oUQp7UZg!=Vx0#AjfS07&b44$ZQ*pB zh}w9PupMk;QL~!={s(N-)g4HYhQ(GQ?FKn?O(CMnG?ac%TtDeL_c68<(CC^bB|KIb z-Bo>x-G_k~nzyGtuDAP~lN{J`0KSM9SmgYQ)j@&SRWx25lBEX*XcNX_)l*xpJ$NMeU&quK068iuZElwS*mE#BD zS!=6Y7=Wa%d`489rAGCS{QD)Lv(wqx6;vk=q)G-)hXeT5l1ipT9~|feJJ05Mb;tCV zhhE>Ut0H`V!6fX4G;yl9Nx11px5H_oXJfW#7Nnm%CdV2@giqt&B@@*uyO5U^0;Y^PEs(&6~eZ|mw?2crzoz|nZEhy zAr}Y$jJTJfxTF^eHhB!eIK>ssL?WQ*%rst^)&u=(2rCj|?e4_OS_Fn2A#~b58|kjY zkqCU_ _-1eSL6-axn_zNs-G&9Hpv_u?Kn%~FXz1>2Kpj!)`U$&75;O`&HBrHpPO)I%Sdz=kCD7Vt?P@; zS^G){Uvl~}q-zU_OJ)I{>FihB*|d*9TN$>Y^E0vr7AE06Y=Opm=nywluCJ)H83R!R zZf>=RIjDn1i!KB21taw5lsz|0x*JXhwWLp4SAld{^(sQ2eWZN6$iQ?5JmU|1WUkXE5_5FE zP2$=BZVW{j^$WWmvKhe`b=i-XKnz7R17$Rr3-4QIov*Wf9M|sI)KY=2+rfa*i=Cq& zaKt8wfz=R7YW?#9EP4Ry(3dS2Rd>vF4nX67(sO`E(_ZiIT0;ZXa-o}p04593l6=MU zsJn-Pk)j056*GEt85VdXxq~V~xwz@H0k8fEV<8=#0R{YH-9CJlg%0l%{`ek6S4m{y z=AH?r?VVKl%mNGETdOJ`X5NS3I6Kuit*hJ&SNte%c7Pj^XVe~mDFzKRAO z?J41v95BI)nmH#)Ih=uF72jA3CQmi zjXli5w8wzWg1^(TE!BGF-pJe-{4l9o)yBE{#<(RY-UKQ3J-ylWBA#!U( zD;Yx(T$I>Iq+frJ#B$8Y z5L|{~#A`8=U@o+T6;+@ni}fb2I!peiBPXVzY#3Q;M^z{ruog1-^6MY1qMzqZ@5fr# zaC^2whd_M>rDC9fNDI~8RyrI@h60OYxrD!kRQ1B)7Uo8(5UEB|u5*^6272SqBEyhS zKrH^%NBaXvi6VZK{#%}i;GD5tZk486R<4Gx$wD4B>U=#T4&jsz5ffy;Y{g-#Q9pYE zj+@s%v2K$^iztqoeQKpYYuF^FEu>L-Zi$8vGO-#9jjc)(?&T0&)ejy=6)QIbj)%&? zVo^Z@5L}G$mrTUm?=|y^zs2g`hp%_SxUU?0$6c8-ps9rjLFT04Buhit%iUx z0_DMed--)M3t9c;e?B2eNd9M9viA>Bvm)UrtTM*GZ{`!N%pi5B<|IoClYH>%pk5nn z9G~L~j)x>PkllJl0i__Ic%!9QAT=$KrT*u&Yx^dpHAI(@o5-Xx$7KTMY2?h!pRN~L z{Kl8#C1J*^1p&DGqgZp{le_Tica(U~h9bY};*i(#=8Gj7dfvU?I+qo2IYv!L-zD&K=OI!LU=W_79r_+&901>tftg0`Oe2tFl+b*JsY~U5j7o|{l1e-?qdD*?TNv4g^|BIB% ziLKoh$`;94%n@+;DyK87PSf^heI>SyBYY^dyOQy#b*NLTq93PjbCScuE6w2NIO}OE z_NZ$~+~*?K!W<-e>DMNubUOpRbT`X7BL)`1Q|gU&ngOwupT-yTKqu(RkA{j~N@uI3 zg1~}@V&LZ81cDpirv7N^3Vin^r-m$L2Vc2e6$`_0O3U?wXfwm6v(g2EbRXn3}8?HxaZeSOV+oZ3(ytw+!nnSraj(+)Z9GGd_h-Aq<%kRW4tqTewF&ha?WRC~<-^m`bVQp(nNlQ1WYfSgslRPJqMhDz z_a_66RK(9yggNuL&7Mbp)FRCopx&)YrXjjU0UELOD1TGlb>dn*>|~5xG(D~T!4o!- zGiP%uKGwZJZxuw0=tIsDRT8-y9-{!0kGoD&$w=WiaXBY8?*xll@8D`u)0YBFX&5Eh@`UrRnxmT{?WPd2&ka%|d$_*lA{ z5e0D?{KRoE0E4Dcqp{PB#{Iw8MJi z`|g_f=)bb`%QA4P6zq|ToRX!*QiU%`h%N+O++DprJJ_Ye7e;Qiv}D*cJoC8Qd0=m) zYY#m^s?K;W8+3U(V6Ry?P_3CcW;_7Y1-JBG9?#c6QEl;_Z4cW_XH#ekttzNP^QLav z3aG)y%#-!}weT;YwYlFyYZ|!s@ksIm%Z$a7ip2d5RW5Q%Lx3G~=Ay)x_ClFh&Y~b{ zvhL$@mD@g%HVS&k=C4M^HZh#iOGE`&K7p~-)Z6&2ZI*x%+obW zUtSN~TbI?VVqAnNo)syKKPH;cym3&W#7@jv)6s9qj(l=fs7(!i)<*2PLj;Lj3yWHO zCWib?ux6q)=8}Pcta-6YNpp38GPLlxaPtRh#OigHK#Zzc!`|8%5gBInk6xBPC^B_0 z`Bxk0Jf=Emx?`MjUPGEq7Dn~7i0AzGJ8!G_|9sO)#&#-7?nvdFe&saE$^h4Y-lK+? zWjA3Fxb!{ec;)AAkKGi-J;Vg-HSrhPmj*lmnt4>!U$liAW`-yNJIthDCyyp8>b%c( zd(PzuN;ZhFtLlZ+X}B#U=S)I`;}$JGIm907g_6pp9 zj$m?K{cBqXzo)5ru6MZXH@Hv8&@;z@!A04`CcpOJHNExp&(na_=QS>Hc0UIE|DYD; z_NqX)z^UbfxNOe^K#s3_simy-MRP{T)$kyzt2Q6W=|FKHCOfZ}ku0MxjQR_d^GL8% z;JC~^p-gO9!`};8uFjm^uUK#z7U{{4Uo(EOY3h!)We{_KbK!-OGB_ z>dE5l?wX$H2%f22ao&wbuyl98mZ@pnov2PZwi}EMS7(odE$h{~er`rzPe=t;%2G&y z%LN|%Dq7Q7>D;h&U&_%Afm}B-JMeG1XnV7JH*uOZtnUoyZ^MY`69au{`?|3c1a(QW z2+WIs%@NT!n$ds+SuV||stwmde?EDk`@Jq!JLph0Q3DEREV?*D*Irfl*|z8}xcPLb z#|GDT1jDf(hb-Q`MbBcI2c}}2iwUDKPmjeqn zRMvF63*rVI^A=MG+SCn39R*`*hvCkG#rV9)+O9#^U+}DOW#};yD|F-=Kl#;i^{~w$ z@bnZ0*p@3kZ#I7>KG(F`ng72)6p=)uM0fF#{|i+irVi&V&W3-UVtlVhGLS=y4Xl_W zEq9_F-t9ZcsvXi=AL?2CkU3%N+|~&E^?fFp#=V`q6t1p{iFkT0KJ9xkEPOGR!jrRV zB6huQC%Ni7g)sj{W}0|c7sCgHMM4xRN6{PeN>jdeQiN` zo2tDJdZFAvJa>A=(S`9?^8aCJ%7iXuOZ2%ug!&UPU!LsJfBP&hdt^-sqmoO4-7N^e zJf~W4aB)0WuOJ+GG>A$s{Lms9F2vqW^ z`WtiJ>092dIFsn{J6H=V-aL*LS?V$~4uhOWNF)-G3Bw;>ECUz8DHm?An=-&G0X#E{-MFWLI8~$%O85h)L>{nABT~lhs;xh~}@CC4$NF z=gtU-qK&n{urjd_6sKyRg_jp=eXH)X>QrCi`R5=;#TaV$4qN-qfqFnMbVZK>n%Hb$ z<)ewwn@&4Fo}}jAsE8{IQZuYprrA2GYhW?=;X^ml>S_^MvOKY4{@6^Jbr6v31 zRj0O^wl~P&Q-*OZ%%bH*`uC3zrl4tFi+z@-otdL6=CuCcn_Xw3%XV(2@jIfuCr!wY zW|+r6Q=GYjE58L{F84~9$!Cn&_%LT*b*^gn&MsY*Jf%c=WfGyf-IT`o?nlm1eQa( zE^gAAf4ha*ZvUu*>ap9`D9zsZOX0bg!Q{eleXiannel5@iIw>mR`v=uRVho6ar(hz zPjsr@M!f@m#?`bI@s#Vv=be@?(5T-YVEl) zj`OaJ2I&01grs7Z@Z0z#XZrue^ofCKtg)M1r*~exPtX0Vr_@f@tYx7s%(z;PxQk3_ zj8DBJgVq7N%fJ%Glm(uqhr&lkRC<^6UJ47+!T+ zu7d8pjCu4NqJ0^{H68ep{V3seBsF9M21N?oUtG3*w_I=@T)8=YAkpD`|1*qn;cTuS zKhAqykV*rKcRN@HP2Ksgm&3xA*FD87TQW*d!bS28O(Z4vGd7VbE?06i>b-69N6YKT zzt@`(@_{)w@D!&V#;%84Gt6BbR3Q24-pJ-2?;Gq=riOHJpp!~~VdRD$6tv--q><7g z*sGp0TLOsJrjwcDBG0sK$sEoA6AMW+h$JKIXyFJy$XJhm#C(W6>uAF;nEa@uWAr1QNoy9`aYrWGSM)xeW{yZ$AvVv(%= zL;i*OGU3*V8(;25twFa2W@NY3Q5Frow#%y}B1MlRlBr-3rIb1$M!vrI#?NLHc{8Lf zEUO=xl|GqlpAKPuxHTeht+T z{iEduwaWH7uIw_Z?`w4&^+wM*<&h~ZAP%{C!`-X}W~gz4I)zxbieh0e^7Sei$I5^v z?MtxkiT%=IlA6QxZ&)c7vmrJpydzfCB!tl@mWVe+`@QKT#h2mrJQcYBo5W&|@Fu$b zZ9xKO@BRm?DKClDlLIkP$>b+bN$7+FLyF+mak;MXpc(b6#>%KYfpmZVmJwaR_sUOs zB;0+|^o4rHw%;#=Kx++T>(0LUPdsFM2P@lm$on8(SA7*S&E9_(C-V@yD4!&u-mJ zl9%ThIIHed?7DElqy8bWW<2Z+#WWT6_d1T6ogNG~QcJaw&m7BHymit)Dd5)AONMs0t`;9h7`=g& zPz*0ZE!cP1pW?Ki)bYfzb8B%SuJhZOyLR+N;8{C9yvM_~k8yV2?^OB5z%1YqoKsDW zHNoh7+KuMRM(Y}-sMNM@HNjBEUUY@H?kefU*sah?2QhBfdw( zZW>2?Ll78?6G56|F5M;%~uo35)sQ4{Xc2auR)eT z@>^P%=L0bQYOOgvljD?;bI2#|*C+MqM0AxzhNMw+o_nqQpBx)&Q#lkOD8>+y-#FNQ zMj>SmWN{(oE%Db%xE4J{8hHFRtt<8kGRZ}#2JGsP|Sd`+|7E?rR}-!S-e?kaI|MSao%Z7SELOyEbjQSO;p>eRJ*(g$(k~ripz<&?ws!l)EG%eDhi%C zS%8)o3^=y27f;&x+qkxaH(B$YHqaNm-$6a1f&q2ozeqZ9U%2mGwPM~s3iQhqela%(P+xT_zzW;I780p>ptnq(PUH=KH|qTHe0(swP^*4?@I3qHWLqU z(5t1)D?EB0)}m55S{|@Mh>lh~v^Pz54Y|?RcZuINBW!rP|H&`Cz`X#6AU64m07iMN zXGe4@+CGX9m3xb1!>OT22;U@hvSLN~*@g&^l8u>(oFb$V$ zVUnv6`2e}p-SN;eNLk!2s2Ba-SvDmh!=|{vK=Cv6t7Xed|5=py@JStdfb&Wb>@Rsz zU51+it}xtCUla0+C-tqiQi1PYBSDW7Vm%`qP=pan`1 z0ScoRHfS*NppIqmYvIuCT7zL1RMd*f?5EwqA~kjo^&lcwC8Mryj9Xvj$mxy^^`fK7`ko2ELO7GOrjG$cja<(DU$@gPTO^rf7{ z=Ta4N9sRUU<3-Ok^h|HX%^`9;EVU9ndXRC|4&WXZp&L!bz~*A^rhS zq@Q`LB{~~rJJ7~to}e!)bNS7d-ZuadsW(B+8Igsa zFfHY<3c@~^O3;Qkq3p=rK$Xwuuj`+nF3C0gzlOh-Sf-Kze1KlGS4C1nz^od>=W%?$ z{h+OdTb4mpBJyv4d2v}46Z{2jHbETML+4e?dVXnT!lhIhd7^*uK0b?2LQIMnTW<>W z0v=z}T9;a2lL9RLSDv#vD5a;Y{Z{aTWedA!NFKa)va-ja`!IHM>Dm;^MDg&iQv0p* zBU@X23+Tn_nM3a%_wJh<&ug`(=ozICL$f;5M%DJj5{lazN&6Q5`tIQjAH2#Ba8)m- zSyM3lVx4S>hT{Gt=)tooHD~I788y~u5nzKipSyL&zXPX^05a*0!2my7P&{>dR5kW7H4zb^O&;TaM_&dciqER#70gJ5U#WcvY_ zrA-mbnk28>QvxU~iI=*P7Mr#JL5MB48^`(jaCzN_VsQdc8hM3(S)Z@|5+~NgO}A#KW(+n{Y1fz~lQ6vl5ZhT-Xb%>XDhc;lc*JG0p=fCN!Jk>p2Oq zL(qhpg^!1zb)a(Rkze5zv-yAGH17Gv%xn$iY>6HtK!0EfRSO=gKt~M?`Xc8h59M45 zAA2I>M3q}L`93uH@)mTO68k<8vkDwDF&%$Gdt(db-x!?@%PXK5%^bsSv_&>7&b8ze z`%c3>s0zwW>CW2jL9~rgQOneMRf=t`IA73svdlydE7$hJYvLC;bnn@FLo6P>a*A@M zlhyZhy%`I6Ob?BqA?bFX{~o7~T@Rq0@gq^u1vh;AxMTm)RV#rI>sw<|l!DQ~#sFwb zqoN8A&oS=1C)i^Bsj7Nnfs5~wJg%!(P|g&?z|v4*OH($+TXg43k5MX4!|15ZmAEt2 zR&8m}5NbbE!HdNiw}O>2J)-q2vV(DFp$pbEX=G&>DSKP0v8%S!?z;}Z@1j-=pdQ2N zwP*hC(z&L*(<=*=BaRlHjZzK$i^5inXMR)qkW!g|JaP50!G$W=o6H5Qsn?6=9+x}g z_@ruN)ks|d>s%HTzy%X4_6kPR-+%tnJAdkp<8ww#);|Q9+wkyT;kVM^?rkuRaDO8rl=QY+gPZHA7}yvJrwvUp^9)!%*F0JDmgjxf;I&1{~= zRRNgXfsNt+a%KF`^rKWgrQrq`nYglFdz}7{FC&(Pt729ZD78*Qp)%7lg;;t*BhNJn zM_?nHR8+w81K=;bZ2ZpPqzB3R01c@mQ3Q*tkMom@j(ODi+mM2#0FjM<>8vr&WxqyK z46f%21{KRI;26O(3R#U$fu)(ux_#5;WF~>Ls$X0grxZcPya8gtNCOOR(EJzhCHvLn zTE#!+_ifsy(1@nch${eh7C>wYl%2X3>_;!KK4~+Ye7f$js}{e=`JbMx6u#JHB-rwL zWAVPsF$~l9|7lRb+N#~Aa~|8K;=nDu1WW~?BC%kIMmVdH`%r3epUIadM`STT)sv6Ox)2h6h?2 zS|->Es}ytJg(*gMhg{~9(cqu|Lf|H1*Qv|pamGP@K!5%Z<_RPQo<TGW_?`z zK8%Li$=C$&6*p?oOZ*t7E}9z?F2ecr6kaf- ztUKWjW6m6gn8;bY^oH^7M{3$hIb_a2E2+YPPODE}(Vamu43vrjDhP>%#6>| z{ryBRP2ghTevXC?%I{27G=*FXRk1-d%B<}HwDdwb!Sc$lnTKbW9UPT7<(|LsPZiE{ z91Pv^(%1<1UNPq>J{xI&dx;W^!?dM45Y~!&J{Lo{&JG)4lZhjec{PnS5*Ji-m&22M zmD4(K*POs$nSC=GzXmcVZ|F|{le1KL)>uWVJ%Uo$yU#v)9sffmqSBo53z!DT`P?ni zRpyPT!%s?WeivL=V;2G2*yj&FLipbQPCyMIT`48Z;)-kHPocZ7V5>9!u1w%{VpCpL zTO&qbN<5+>bYiBW-ao2_jp6S+^D`+Zr2&d?v%tDG{+LSjhhS)0_Za5*Bz}r65GP3k zBL?BrRCQL-c)srSRYYW$T}3|f$O?wOKIY0(i@Y~6BCQD2tc%+WO3~KsHJ2y}@S`3d zk6N%T;9rJqET$m3dJw%mGcI@{87ie(I)1!O!fJOTMMNEay~d2ULjf|ChA~a{IAK9W z!e<4(5iZSKna7l7N6*yo+2KOCO^iCrf;~DB7==G^kc0EYylFWa8_@vx=cAlMZu)Dm z0BgZ3S$>CRZE0&p&+cQTHc5gIQ-ANs@lUnURw{mj3rg&h{U^K8heEVrjcu&J#a#Cy z`G}}A%kVGrVZxGV+v%>WiKKCUv(#K!OGgnc^=mU_<47Mk7ehUg@l5;B^`|Md4v( z^KeQ`_c;NxtJ@O%lYWznFr5S=$D}|5zZ;-47?$I9h&mwby{?#K6-f}0n zFV)U$c_|7-jmFmJ%h@5MfuO^t@TEDgimZ}Z?b*b2fI$ca!0p8M*+`st{4ZcS6kGqX;-S_E*K-;+}A(T_WnKNinTwwt^%gh}cUv@NY$2VoQg$U#qO;!DWJWapc zLhFoGW}YoemMPHx0Fj=XDamvwAfpi3?p-Vv(s3WAM3eJb17&;d70M4z1KuxfzO=sp zj~(fG@o6Kd0J%HOw~Ia7UtPHdv+f+6dpW2ch7*ad+P!_9D-6ay@Eg8T;0u3dDcr)p zk2OK@fIYh=$*z`fbkieXT#s)xwJ3%jgdTNIVxVM<&7oj(sEEeUw1n9_oiBSEW~7;k z4_eT?RwD$PrE{NVIZOLL~`(iQQD+bp#5 zG9kch8UNOHlK+zjAAk+_gFr_YtjR@7bdf-=@iXj~6BL0MpcfT<_u1LpBulr}bxh_) z9C@!#O@3;c`hG4a?7?%X!v|_3N1n{%ou@0s*wK`HG07b@T@wFA1u;0^WoYd8mB(15 zp~GYuNa*HZlMhs`N_;fwxmIYgY3*cxIbYt&L7oTa8ng?>nRlm4C>$E=w;41yl=lia z!N#kdq?cmQcc0{DpG^k7Hs|K1b!%%Dgu_dJeDa-#Z}ln1JN1O#={|p8*}wAEcedJ{ z8*J_BEWT<9hI~Fu_D)JMXHYN^D_aL{`suPnjShRrd>b z|2e@bxLkhdZyeNp9vFzx+?rvGmm>9FWc8mj*Ffc5AVaw?2rbGblcC-p%6QqTSHTH# ztO6`rkZ7zX(X{%{(;xgZ`;i`>oNk45v;8+*fjSB8ubNwj?_Ms+rOi)G=@PXmZQoK! zU0WZ-Yl2+bRetT`I_ge!IWt@{5!k6dimlJi6{K!9==?s~CHit^xzWG@CQ^wDjr#^p ziw+uedRJ*jdrRh^VX1IuOb^JfMBbw-Mp?*+hLkoV$)uVnXV4rdiqw=&H=!tMUkna9 zg#NOd@cV$idMNSRiyi6jo3q?)WbSLwu{2!kE`?_7^5kH}HpKRC{dvx=vb5K4CXR*Y zc)qS5i{oX2)S3#stF0X6HBMVU@g7YDIa-THXM+55!+DYR{kr0XCqe%BadXQ(FhETs zc|E83sy$5^KMbCN@qS3#T{L<0it-04?;KQIqp5cgr79)pQm(brHDea4O~8EdD^C-Q zB7ON*m)(?#xt}=I!++}O_8yQCg4`%)=#)6_vFR!8CCCA>zq+*vNqU>9$<%4gHw%-L zI;pLEb&lQ9?Y=X7aOHuHIw03{Bt5?-icXrJlsPYbB|u~IZrd=^Eb#(g%_H(7ReNer zS+jLVF_D9Q*;~7;*Q-@|h`Te=*Ke88yt`%Ov+0@G6Sw#W)DHjN$lV{?O<+{f2* zCs*rA`*XpvI3^o}wPJak+%Uo@ADUK&J{4>g{%C6GZ&;96`4miLgPspTQ z8^`R>H7JZ*(k`cjM=!T&+Lki*(Y2{_2CxmX>DCF(yBo>=#b*LhSK+OJ+B)leL;iQm1-Z|W%zjAt(t;i3s`wp zA#heg#mDHa<)bb4(i-@Dc^=NY9*7{R$F9X9e1y)rNd%TRtYC(`sU4qP0O`Te+hilu zxuxC=i&;})!y{~j%#Fbq#ynUM$0ovCavgCE%Z5Pc%cMkAT?t;K7GZi z`85JRn*|P`L++ixSaa(Sc^kB8%QEWgx}g!huG?MUo0}RFLuofl3%#O_c32Er)iyu2 z#~<)yHsaelAgtdtcksSHbuRhZ27G#RNzK}(e^k{g!R8-G(O6IkCRzz-@JYrJs3?s# zsJOC4dr?}tipQPWLPPIkad#6=+mSf-K|6eJUi%-#I@r`)h1%PYQ@x7x_LVIMnXl#C za%GBO^8mUr1-j}P1u`4&Jo~4KJ)`WdW+GkEQ8M?jLvTbY%*X`tHrsLes!`wFOlM`3 z9ao6zZ36Xxlj5y$QHy$-@Wbc=%om(GXRp8311H(E=kCIXZ(?TbaOks=6_0E|Xv!)o z{v%+=s2GV0MMbIo7&pcSi;LgI+;^N=x*vjb%z~5v;Tq6W4E!*srO9FM%9u9AS@l$*8n zqk|Z5`sVUx->tc6gm8e8-WJ2x@UQ5$6I4b=tTevRDoAKP0Xa{DIpuv`)Z4Egk=mhu zbWPp~g0d94mU)+W(*?OU^55w}Y6Yo-5kc_;i!-vtCB7fGHY@+_2lz*hB~D*{z`-zd zmWu3_mUKCso+WF|;o11|4Fp&{LSWVlE&#BAx2ww}ZFtuMoElotB zOu(_Cf{Atc+_gLF0QMtduWdNX&MIV!qW35f&;DWHf@-oT87`ae@nL95OEXaNPn$2H zw;Aa_VB7Q0o`bq0uHavH?Q8T*eBGXnDa8F)) zs!{7mQ5LemPuK_epn%A&iN2_eTwu2Q`<}e^$*iBbML+Z^o!8y11Xs3;oKuIXNyI0M!csD?sx-brT@mnI zV*2naDDEfq(UD+erhC*W6s!;_kV>I;l-vZGDjB0>64}%sN;YGBwyKv+6WD~Rv0EYH z(%b;#s1qm^;un`1$FK9%%m&A)WR0XOV3yU6N7O%6ws<)E@%ySXQQ(Yal-=Tt_oMsi z8joykGgo!L&Xbwb^gd81?&$Kpw!dnVLb`mL0;gum^#R#TT{x!MD#i6^% z5!Db2!hrXO;&itqpDljljM(56z>=V8Zpm!x6*8FUM$Ke|xGv6T4t8eK;d$a^U!q z3Nn8?)d~n_A_Z=lLU=gRAJH~fEOZx>{^E)$I+n7QBd3i-RM4(ybGa+UL}zw)Z=RYg z#=}#N2VAsw28|ATK6z~yH^|E*r&$@fDVHvGIy`4QVz6UBNnN%5&0#lim*D%{#$siF zgcu%4(r)hfXmk2RRmOR-}i46lS-_bx^8UC`)H2?(PJx}?<&xI6)X9L#=HGzQuX2f=f1DowF9hs6|sc{h^zdy#7_MS z9#mC31uw0CENhgaI7ZS?H|2ZI$_da+&k8@-4r9JW2${MNnwrRww4>2j>4?F$o-Kcr z;G|@p%PBzw_2XvmvoGxTE!L@Y|4b`B7LTOSx9B};9|E$o*Nh!o=FtvL&#>M3wK`Q0 z+$fEB_L_|oT1xebjU`!ns@Dt zGNzK}{Y-tZV2obS%M`R_!j1R)&fZR6Is3cUMoVoRF$4&3Upb6S9r$;q|Enkk4ew8X z5DDI!XLct@{L7w!kZ*0EIhd^3=F52e23s@#0^Ep#9*+gV+RdcFq2O!rHBgdQdXGE7 zvCegF9#Wx8Z``kW7Y*6Qs6tIkx>LTr@RaFLYx)Png)F)5l@6sjuE8yMHinlTXX4jW zHoEJcD4{=@h@iejv=LP>T zQ$?QZ0^w8aW$8(0Lh!_S|7DE6_v}5<92p?g)6_*^lF{3xs3LMw9L;!a5lo(JjU>?WDipVfa2!$z5UcW*f4Y z;5UvHdCVgpEdjf_iAR&cPjgU2FaV9i9Czp*VB{{j&lMnckW%^j`KWb{cwXEm+qmiZ zRSGHpNr0mv28<=92?LdK0Nv8J=_Xhr(20wlk`lk%Gh8r8k?BVBVJg;NV=oqLvFJgq z8$!;TU^@2sM6ee2rLo@NHkzDw6=12e0Kui!C$Si+zE!BJK4aF8*|O)J_k&pkD#DrG z)QW68^TSRfV)+v2(Ctn#1tpQD9&idJs@xx{BXnNu$?VL_XU>N8@waOhMrq{%ykx-Z z%IZ4CXhgi_`gNx(H?tt$j7|geU1D~D7yJsxy6&_Va%L^UK5QLHf@qkXx3^{wTfWqA zWh66JDVV31C_ehr=zK1m-!nnxS@6{EU9Ou1x%^rvwE_;VEh+ArbmWZ5DyI?pNwno0%%oQ$tdU(CDeJmh7f zzdru8qPt8$cBb>;nBYUVjm8hihx+-fqoISr8ufR%alsFQIO+3GaE;!8`yZ93Y)ymV zQAa5SYGOfKqD?WiC)1H$s`oGT^pS(Fut=kLKt|pdoKfH2af??xN<~j;L@t!Gwpes@ zMRm}%4AseWxcg_A?hKU2>tBCD01e*m{sPiZz?7I(B&dgE!ha?1(g$U1$=$d|+nGd=`;vaUE*m1 zgH0rA z0f6|2_J0*DJaG6Gt}4w&zx&SR0s3W=qqQAE%ymPf@pGs73e6w2ZL+2)KrJ(-f)-l2 zt24`G%RAkHq!Iv;B-$v8A0qamAOwc=5*sha#Tee&jgH&qlbgsqpXM!Yl0xJdva{vc zBlZ{kX9*6^gvW?N(+5zaI|if4nOW?id)Bk%y@~)+%lox4^pclVuj9m-Zo2vED8^=n z!1uUcft8GrR1_A_3qypP`^)&Jjcj#VAW?c-R&i0}i%PkIbxjBd1+i$_u1Op^Ws;6b z8k6}|*t@dwMCS~YtxEntc~ae`%6Mznv**tTo|SBG4J#|%etB8+8sZzt`u*7RT_T zCL&X&u2J^f7tvv07k_(8Vbr`@kJ48bC9SaJb*BjF8~%pH>)PzE+<*EkOE4_V(+$(A zam9PaCfF%`7Z*5%iqJJYc1o4L+B=)u{~4?dB6`xHr*H8y9X=tE>%GfllV_Q^R%N=! zhIxgI+pU&Zl`NK20KQ@ynWOJ1JeP0jMH^11%m z8UvWdM;EkR7CuvN{U8mR`7zF@<&o62`95tmWq@fNpJ$O(?DmZaNp6>@Gn6&mdpQg( zSmO~yX`%LY^ZxLQ^CQM>Wve}VF-|A>BB0sssvitnvQencuH@y9;lEai`II4lXfZ&Q_O=#4)7}fcZXuD?ZXu=r^v!ti8Z#wS)G@3Q-^VqFjonE%} z8o0J+gvjFEW(({rovxR-HV2v+WEVgIro|TZ!}KM9%I;Bct+%1+5M*StSsZITNxF9W z#!eoI`xZgll%i-SrAe5dRjKP+u!Dbs#GTXzQU`aZNi^h8585$tFa=x@uXON!sk2V6 zINlb49@!I?a=AcZfv>N)Tgp*Un9XGKV(9TF$l+y$O2&UjGQY&toymr_kmNRX+OALq zeNg1HVv%uCV%4Eg@AyHI*;7#OzUs^|om}&}>5DveZEXk2yD+Ik+v2z_q`02MG=>+C z0fhM(OL8f8l4Qke5xgbM2gEyaH&sZspJccRS{jFBtI?61PfG4l-K`miTL)df(&see z$yt$yo)#|wWJ3;vJ0{+?B6gTG-l+`N9Tg=HzchbECT%j0wRXbzBp!!=lOB_Uz=%)m zNg<&eJ^WXKL$B6z(_IAeWfJ@$d)?vSxyDDr(JR$q04V-WW5_@>l+mM)M7mar8&4;= z`qiYU@@4b(U%kwbwhCUcPQW{236P0oRICAmH3&!2`k=E3nA8^+i~wfUwU#uLkywl&FLcB2*hOmMrJJSTs62p(7xWD zC{a{LS)28m|1kf)@Cz=L>w;ksY&18#m$~}-(d{CvMhnusl4)C9@FV^25sWCIIy!R3 z(413@PrZ+4?fg;(!p^*X6dY*^AO2C}C4KvvpdOQdSCk}Z4l2qd6ETE&F#lDI=UES! zO*BWUhINc8!`MP#Zxnpf8T!}q@?Q_jk2Vjkf6xP@!fzL>T>gj9!A16hO5Q2{jOmbW zmtQxNc+Ky#vc4!o0-KliN4Z6}euWxos-mg|qzlSjS_$(#);Py6mm%y`7f!_BL1fqg z`x0pe5^*L%JT-Pp8!j7xbcT@>P9t|GV>$|4KekQ6$bQhlC6MP-Qislo^jYGZrFu_e z7FU0QrHMC$>C2GRFn{;wM9XPkqT9dvlx$p0*aSVmAV~Da0(+lKg2KlzIl_iLg00qF zSV*C58I)8c>sP(Eon6AQH=gJ8Ico_B7vM4>;x4aSm{ZG{D!Rks3?TSGRT*&cI!!3r@l&ql&Z!Z8F?Nx4)nvGOZ(NTt-0z~ zkg$VcIFsYlMErq)iC8(~o*N4!{P0$aEoXgF;hkOOa zf=L$NQCBtP)UYEdwBBn{Ic6T=SA;A1u7sc!MaD_nPxbLLyV9Y#R3-&No#Mz&y7f-~!W;9|U&C zHqq~Z4}vGYsj8YH!IxHrq4sb8DIR7+*F)P#9<`t&u`pABzzo1L_aVCH3@r z|Fb#&h@1X4!tB8GGX5eyRo>~)vP2qpGQV{4tZG-(4whu#e80v5X!dClT;cE^*N3Y9nG9` zZ_fGa_j39#1?DViH_#ecH6H0DbL^TKd8KXZA@$0D3yLee&3bdfb`FuLUk}%Xt2k}E z9o4$DJMb-ag zV}FnPo;_sdXLG{0_z5EbBTNn{ax}FXUy=oduA6^$7y*ktZsDL4N~M$!;pN^sRY0Y@ zepVGFEFUR*ny007_dj_)w19j|HGcS2-L=i7e$WZ{wXZ$v_u3#h9v+9S8P#X%{}&Gu zC^KAVhUw=IlpA&ADN)O87;oJ^#IPwApNNc3O0)3SZx+&|fu*_8LFGiGwYQ zjwQ%}t}E;OdG=-N0Ns5z{6G-k>teF&%_qc4Z3ZKj9;`vvqiq4yKrIPys zA6nuq=vS0vDI9YK*zItZv0xRJb3WF)xSn2zNvA+FsLoxB-<1Tzw$M`Q5%PieYkm9r z4`vdYq1T3FTem2%!4+x1*U~iL6P3JG)bK;rF>#~+A8rt$EdSCs`e;kLoLrqxWI%vV z1*QbH&L`jCO?4h{w1WiDE5Wp7hRv>ef%n`Jej+2a@ZP^uupqK6p^87ieXz zBK|;e>k)tPCw7o=BE_;rHUEhAjy4_J#Fu?$gS;{DTZ6K*N#XtjHYP^zEimsVhT@K4-Cd%k0yTAykab*xq#bU1 zI%z3pQtnpVfK543o<+~fR?M2l@~RicYcA}08K~r}_Tp;)glr+I7{22zee?PLv0A&b zokLLY5t9-03onttG`Jgwc9=B63La(n&*j*?^pR;$)Zhl++ydh#ZYwzRuBumLP2X2z zpnN#wyMXQMR9e_%zP#HMrY7>ssx)=NEAw0`Pz;t&0rXx(8cV}5>)pG37CPo|`h1kQ z`226C*dsMa@+EhM6mUvQ!3abVC`9c~E_vxzL^c*}SXrs_w!tlX^%Q9m<<{K_Ip;jM zccy_kw%NuJ***>&h#iwbSNf3Ca1lYpr-LOY9x}Bg%?V#Yr5kKU!GPAp~>BIQgM)uU61*$fCQbx4Sle#X# zlag-18)N*&f2#qnrG!waIEzri5HPh+cKd;vp%@iv3tIdX^EFdxSeDLn%D8pBwO7PC zQ9iia`XZBdmF<6pdMs0Jiy#G0Nv_b6K^&qWj4J(b?ZGOUc`v~2xNU48GU4B8F|IF`&X@guR|)uE~G77R_*<13pWO@ek(8d{L4*muX@T(}~ACXZckH@XzmjjE;Pm#~G_JdoPvGW%@}#&W>cIVd=M! z1TbLQ+?R8Vp$9hR2RYpY*M_{Zuqs2v9ffxpy>#0UB)1->?s`h-{QM7LjlcDO32P6% z$^^aesq*yv->pI>xdC6!U9vtkg4mMTrc8#i?2fob?e}`JSx3@4mQ#Ui_-m zTI!m{7IgXFHcx#Y9!08cM9KK?gxGVIeMlU(_g8Fa20Z;8ruX(BwV_~>uqb62%Fu#8 z+=t#^3se9E_=m(vO(cg#CnaL%RwEM&@~c-<@*E_;aPb3;oII>r(q+ZM0MvzhBeZJ) zoR}UdSvsGSI(0fNOWU(E^Px9_Nb1f?=3Ri?tO?{q>c@2XiV$yw_nW;e99}5Ixn$y@ z-BKDwqK!SCQO@^6A}2h&=Z2}o#JL6>XaRP%S6ZN5586s1-2{H(5lR*BO& zVSZ+iD4mUBe{>BRe8M42tOa}&ZcLI3_I){S6$Y=Kt5o-)ugA&3bp>*C^-J! z4CI%%emN}GnE4&o(Uly1+Abigh$8Y;B7`5x>>0)~3_;1avLkrQi3_Pt2w_ad8Ur5q zO08{=a1g2VO%Bo)YmH#}a@KKG)(2M@EH;-ExgKFh-q2Ex)D6}_paDJH8{(9^EfOj! zl;0`w*YF`*zwp8(|GLs0EXW5>H)T>Exz9B4@YAwn>bEBvEw-<%St#7VIqCWo~jpgB;$IEO- zf~8S9Yt(xQ`CbqB*W6g*UCDYVlJ$vLFPSmtB7h^MO6sRB)aVH*70{> zpTyK*viL`yCjOCI`t$#i;^xu)3P|JP_YNf$ppMr>D^N)9c$D;w5=~4Pq)!+QyxnQ( zzQk5_7Zn1o^sSVFrI2w5V@2&@K?3G6Kd}{_RP(8k$~1eA(^*HCcxAsv)99{kSh|mX zAlw@tN^o6c;ArJhPWi#a*L#VgtoMaQJMT3&1^5B7TK6e)Hooh#CNb;UcfB< zhnGNE{JvFA2bl+%n(E@(q*Ce16r5#J$0l)t&gqRyJIZ(gea2S3Pm&T6`qN2XDK-zC z-cr?n=yjwdle3Je@z)78&n@8Mmv{D#r%p$l?9(+O!|JBHTU7WD(={~5Csc!vT+r14 z5^u_7r+U3YVwx+lKh;RUEQp8v33AHYk?s03s-u;i&Ku(Bvk}6P4PY^h>Einh!Nzxc z;hNmwWeZz%Oy3R>y$MgR2n(Gqt`fa6iTmlX+)M+00nNaUu_;E_Iw7tkfNBl24dTjf zZh9Zfdk>k@sASEt2mtLV3>~s~8!UO?jm3d}#L8rSj(D&D0shQB)Ogb6voZg45 z#OptGXN0q+DErbz&Bsr^5Y+e30Jdr|bRuWpm%!U(PV2=~zs%&{OVrCCMnq+U{d;0# z!P|7&8t1dhRy&ugEh495NW26sy;uyG$N)2?OI*@tPc@Di6TcSPq$h@V0H=R{M*(N_ zuD6iTbW#MJ3zyt15q{JDX}yEu)sXteO1{HpdmbeU57K5j^o0*zBrRQn7PLH-ee28c zXWJPkw>5+4&aa-P#?2q$=%ASH5eVfZEj=_U4>jRv?l=Am-|F{e9Dwp)f{!sF@mUIm zs@&2-ufkJ^L1_dyn^S z_VUpWprYP}*KUJDeR$d8Kul{WuU9S%O1m&F(m3d6w)%{!jj@PJX9X%8VxtPgj5f&e z^20OFJ2juh#$@D#8iHu28p3E@gw#S9+?K_{KzI56H?@4SBrm;ZBbFrkj^X-2io^M1 zcGbH2bT7hZ1#Etuc$Ys)%fe~2JuHv<!$X#k^Seo{Q=c=g$>LKO%n-1HDft$zO z&pDC)xPZ*4F&#U+j`Pyc?uT}Mp^tX)6M*jNy>r|*t44l4QC-0Ngtsj}8(8aTf<3XM zZuCT68I&Oz$Wr}cSZyk|D5$orfH&)jM!Nef3dm+XTj~Jnys4ouVo-g?uT3rpk=jeZ zUp5h#X9P5lAM{k;*F?UXgi1l@211`y=_TuE>1pYzeN%B$mO1rpEFGh2Fs&-)Q63~| zhtD4SiXlG1P*ya`yzY6bsQjbtkL5M#TG5f{!H_=%YC4uq0Q5J^G^Gr~LMrWfw96UR zKR|AG>Fgp$BEQ5xG(zp>^BrnUZH?p=o^e6tfS<@U+pNTV^C3?_5czrfG zzRZ`@$jnPkq!uHyy8agPjn-1?R9s%9(tyNJ^@SMia}BuzE>z7;TjUCQJ#|M7yhUHP zOPs|+=`x?-1WBiTCG&IG!B-S~pzA6R^7CuYCy^wWoi}~IB&qPMXd-OM$UtSO-0_nZ zBpE8{#$RDm_E-E$VP7u&Y*c$kHs$Rvebe1#__+5c=)EwP_TSpW%{>+N!b}Cylcn7x zv!f`D3B}!}iEHQgCKUH~qh>TKlzBGc9WL&~JkO~8gv z$ANaea%TlUy`BmDauF5;Nvg@M7SaW#F#7cpW`()5m^N3%f+iMOMT1yiYQ8@>5Xi-1 z^Ji1Y>Px1_E8$?>W*=&~QfuC~yqa&C z+m^Gte21I9B}RIy9lQnk(T;pYk{QiInOWqhyfZQR3sU-+pSJ6c8YXUx(S^ZOHD5mo z$~v9^95~?lDSVzp*6!)_E{CpI_fX%|70)h6k#4(D{^ezqKDfS%aW6H>7Jq<{V-3fD z2ERkHJL3tScN)zzxz73Z?CbV@z0J0OR_fUZlBNFA7b6N0Gbtoi6ZKP_I9Hp1E6@iW ztT?MtyfLBSw0EWriQ#f8E>GX5Pz%V!)#L($1$SKpAP(V8WaLcff7Hi*-RTq*p5y)x z&TJk*&t2piCUThoZ4^C@Xbh0%P=J<$C5n*c{c(3vsJ zuggVp zU!yd?u2c(i!sWoMexyD^q_MWMWU%vGgNG&Tc`&5isN57k>5EWB?ikqnZ|!wR0;ZPv zD@r7IFF*-Ghg28U(06XRg!AZG!^*=1YI-tXzL)J{x^kn77fb7Av@;o;_*vsTXC(f~ zxp@W@*M0IFok8x*4_B^L@PJU`lZ@r5-dQppyr2m^Vj%@~Len>_D<<`S4Z)85eJV1BWiSo~?h*3I#|I z=EQ1G;e!m_kPs)6BL3=N(Hk8?(phZ&P#c!lx-|AUDcScxy4oV^*PlkC2E#VGbpX9KchruJvo%jmgsW@99 zDy1Je(vyJ<^tGv&3EkFA$j2JNY|fltY<+4P*X@b+5SBtN1-$M69aTG z&OpUzjEcmK0h$o%fIHHS9J~nn05{Z|G&HGmNTT?S8obC9fe^_yE+7?Ui(mL^>e|c3 z!m#VxDWYszD^pSS&fQF~ppn|H4&L?25vkRtRcJd74N zuFAm*vSXqTdvpq}e?8uqi-N~Qd1U{K&VWWOM-Cq*Hq=mVc8}9dEVv20YU$gR{Do7$ z4y{kgCtgaIU+Bo-(vj!8;CL1a)tcD4+0B4FL1)A+P+DKM$h-@s`g6Kh&=@~QsA~+O&ff99qQ#RyT5UFq;S-{n> z!V#@Rs)(%2d%6~_vR?|#$RBXF_wM;TH$}kQXk$brQ%zJ+nN49|Cqm$9VEXn$)6!9y zo38#Rs79lr&VghA?$z2i0h1qb79*6T7P&v^v+=#lPiJb|y5NbDXu8OZHoR~mLJ?9+ zo$jtIym@P*(^VOVp|+OJ3Y@L9*$q_%Fgd+pSWYKYa>J5{4eM766JsZb*kxazPQmc= zS?6)+w(Mv6BSwngSa#sCX6W0|KQf>8ErmmdK4g!lYz1uplAhtyG0Mce7`x!@^EkU+ zW9fP7VGmOpE_~$TK?WI1sT&3nQqgYozE)F`WsOsx=E+zS-`J57xMg} zPg5GuhvRH~1t174Sc|_B)V+{i(BHU)z#t&whCmBhpmSQo%%j~tuKh)EPC5oZ6zu~L zmm=DUu9vDVAz1o}X#I-4D}48J%OD54gMQ-Q4PXH%}DB9zKYf(($NWf`Zs0= zY(oJTs8MLUToO~!AdQm)dU)}geZ6IQha57}`Q>?~^{{Dcl+c+PhiW%1c^7)13;s)5srpd$UkpbPKYXFTt=b4(Dn}Ss(|rw30TR z2(*vU6!8gjK$KxD{YFCst_i40mW-TX%C1uE#uDuF3NOXmzSC@yTVcY z{fEvyM;znA1v6Lk8{QaofD>(LfIh<9`15)|dy^=I!XbZhiU9Wh+&M=J5D5c)bAcSF zA$uYnn|FsED3H1FUB0Oxw_cbw9?iWz-h2?!wkcN2?Wdzs8DkLhq?u#Uq%NiR2X9m@ z{o)sCl1|UCg{5m6n@5VCk@PrMD|VRg&N9Oe++h{! zg=u~Ir|SB^*8`+l;W9Gq8LnN94}rDML!grPnUkJS?Cw2OE-6~TFD1;L%OG&Tas|r8 zCpH_JVU>}A&-1s~G?`j=(w^%_9Zi>aP+d-gj>s?ru~f1dLKM!7!bfcg193$ggZ+r} z>8?VfKOy$xTA#J={p^vLAJfhGisOgTh-6MN2BOS_&@jTp<(1KV>23WYm89oev#};2 zR2NK__u;Ril3?2Z42OMV*g0Mz@c39%gx8F#tvqVzOSmH5Q z6VTSkblEwN5ZY6wojohx1FuW07IGrbmK2UC>RdS}5fCZSzswB(AI;X_^0WwkZnom? z?dbGC$&ano^#{)4Y>7@A&byBucoDb(8}cU)Xwn}$lt?)6STagK>v{X<1WjrooIH-9 zdo;{F;F{&KU>aS#1u#G*P>y3TR9A;~8|&Ud-obrVHUh1(;(P-b*mPswR^lPZjS#8x`ga3znyk zFWKG&^0fOMYp!<8g79lqgM5UG!T&UlBtxwS7QkCG*l%mIaa*yc#R@jT8S`@V^$FSw ziq2hc4mH*R;eAwpF{$WdkQ7qF#MsC~$3&J{J9%28Dtdoy&6u$AdEIZo7ELUsh^Ru# zm0?RQ>4v^sOgfw|qW(d{totXt;D4DW2wnwZe7HdssZ)ukij~M|jx;nGgKceG%Aew2 zn6CRH-JNxWeJHKeOX0;2z6}4ibsfr)UPdh$rp~##`S4sxnp^K1aH5A+E`?8~kqR@1 zW~ZVu>J(9AX4+NwGvp8Mj>PZ#sm6w&tqud@k~YCXkszm;v4d&%Uzt8G0+X6@zhJix zn=qV^OB=uO9qPvTc!Z=nLq#kXX_H;|$0;MF*EsRkCF;~`mLtB}&#CchMfdK0M5=g( z3|KQcIIP8s93Iq(D~TZzGZ&=M6pZ07VIskOzaMvx9whd`t%F9I_56HN5TM}kxbDfW zfk4yI(CH_9`f;LZH!c-43IWPg3o5qeQ>SZ?MtR2vfAn!KH04bMT?&#^Oc>rEzw_*| zo9FkRS3s0)eTUUd!@uMflCY{`j;>_8M>W98T$#G99#s#w^!qmtae2Nkvt3T9z5#6NA3ge074fIX~@-{P+JzcuQ!TNU5V$Byw721+RMtKYC~+ zl7kfgXrLxHc3fZ*r*!orM9C}D*NjpD774`GPSxj${nV)|Iesdn$4tCy_ zi)vqT?&T=em-4jGn_t$L7*D3Qa&uOKie0yYTDZ$2HOccjxYU#3IFh7KDjDRuYR11Y z9W)i$3j5?T?Evs4S!|K3gE-DcC0G-ah|*sb)pPHnpZmEfTGO5l@hwCx$@ha4=qGvc zXO;BGjrR#IKiZqC+y;^Ui>!P(mWI+g(8n~=Dw^$y+t=Ajiow9!_MBB$-dFEQJEuiq zh(*<0wiQR{?E6E;Zj2BE4aGD-=)(nLHMMPV6AX7C%#~NcikFl0&b1+PK=#_>7xR`8 z_8FO*;1;yAFE9uxmufvpN~Gw>E{k9EvHs0)S2>Eqs%5KEOLl#hU4t)a7b|S`5MH=9@Au2*H2wg4Jex%oNi_E2}7j7^7`kF zt6qfUX(wnoRbOq05IAxkFIM$G-K6)+ljOORHG?(WGWHQXF?)Ol^_z!Hf;3*=N{Ga!;0@RfMIXgz_xR`mk>Syd+bf)g`&$w?Ek>4EHXq9@Wtp6kj z*76TPQ+}JEUaK$vQKZx_CFz{`wa2&;=+nsW)6*j|5!vLGc0M(%T)>?4pl-w)PsFC9 z+3^S1ehNbX{?x*dJS;v?6s?q7z17>n0M^UXb5XKK?1&ir{aL-}eq-zIZHnyvqa_>_ zFVny~Os%Kh!(Z>u-RkgaC**TX$Z0QjVCEn1cF-(g%`)3^WNO}-?=qSqO6LQOp0+_xDTjEpwEx3NF^hloE@Z-)n^TAq4kIXB_+#dF~M0dh7@fcM$@Yff$-$pPKFf9qE zWBD~K#YWNFzJiD#JzkTvg#Yw3ioQ|+I~7!lj-LG^`lv0=Qa>G_W9ggU^>;79Pk?vj z0Gx3sCY5_G`qU6IE0R`TA`z+p0{!`~Th7ixYX5-2Nt?XLMmFwxVXgdk8-+5;`5gF_ z!WSq@S6L_WUfq7Sm*V64`r-h?kz;A)3D!5Z`UjDfs{7DnS_|d{WUz%emgF(q)`sJUQSn>v>-vVSk22lf z)cIzgWS6YEC4B}ed#_VvG>&b&tHJNN*T)f)k3a7orR14dKd5~4cCo~zqlG33M39NY znYSSNM2u7;*5Zl1lHpM`IO-zY2*O|mE^Lc(Yu z#IYsC=ORLGvGZX+wdlB=weqa_A@N9EcA20E@AK&Ez(8(_v^?HC*3W?528J-v^2D5SzvB?Y zolj$<`;%VudZb@w}1P`quhWS@_I?PEC-bwLYNpD)@X_F+Mwx_mw(S> zudtudk}Xjs=NCGnY51061j5&CziF9CobtgfE=mDQ1N>{OtjSZwr%!&WcSvyKZ8k@M z%wn&w40*8Dg4&6~E?W<8M@?{)dqb4R5Z5UUFo3P?2gZTDy8){K7s4-v3iaF=T|64u6Lj5>T;G!CRFzE5Px0NKdR%S&AAOxS z!JH=TP`L*SgUW7&OqmdY|TDnUE-l_Zg`#hiAy87q5(`h}$2*6)ezsw^_rp=i{l z#MLn^C-A5d}95zP1b5A}Z*ZBDyHI%OUMpWuR;JR|~_oykB+LS=21XyB4~DD>9S6>?!eC zFX(J-tyga?Jm!pHd=Yp5aM6#glp}YGTUCX8T3hcz?FclfgD+Z;jY5+$KG2Qbks!*# z;i6-(5Lxb5Z6C$gCh?`s zJMp`&hnL(O1UojC-0T;|CPY-P<>W1R%X-_4-+n?v4SC!CzPF2CjXn}ifO6*ep;(sb zT4hOD*%CBMBP}m6?ZaKHinqgkYD1)ZMaFJv0?M=Mvv#YVi;9RlU^xF2Na5ujOC%sk9CsZv9wa=IVsT9JhkENY@#eDvR! zX}c4H-;-WdF%|>1(NlhJnt89|Wy~maSZ)6&LE?M{tV7wvLiO=Fsj)S~PdJS5bBK)_ z3^@^d0x94S_cl)op@_Vk#tBC%!^F9e34k@&kEDifqOlUP39BCh7cz>=RcDRZYW)ietW!G3iWF^f%OcH@l4AhX+b9 zGp_tzzW=2O-exAKs=O9fyjhh^e%9*pomhm7BF-7dCwdvsNv@*MOaw&YtyBJ`FPINQ ztGLEf6s4A0?X%)WmgV^50Mc<^(o(MRSfk{6J-r$Hl~?T0)iQ)h|Am!&wrO!OtA(_# zy5GCc4%_v!8PZqv0w*6^US57h6)8BGz9FfZ<7MFJNhSLezjmor+%l%5poem-HCLrH zEd&5~Yj5KX4IgWk2Gf~2La6!r?VIRY@{M~w9KAtRcQW)+Da%$ZOOo$%gqwZ64D90n zl}wRA;6kANVEF{@8HC07+nNX-(s@bg>!jVj9t}l&J@~xXgH+w>ldm+u)gQ{cdu*VS zSSPu&=m%&sLZ*&Ojec2N(ZydCUot1VYzJ4)C|S#glpYK1=gQC^Rhm*}Op1_tCGD_U zTDm_}K!M#=M`^~yrkS-|k(I(TqbW1)j~Qv-bG}GsWbjKtX1A3BrUf6{{a7*EuzG$j z!`}<(%f{Y7!kIR*DAn#4!wVD zH@{c!X?FyJJhwo9nkFj^tRI>+!!~? zIh0P0n5GDkQOK2?b;OgWdt#fM5^2aEfY_n6CJ7cby8gA4h+XEPBfPZjZ_=*P)fuE# z7wlU?cUk4Fc*ZDoYSvSDh8YWsN-{k3+INp8*lGQu_15MmEO7FhIwROHjm2KI^!G=x z|J>K>^Stt4>+HIkSMpJU>Xojxk3k6mWc~*O(wn=HK=@Oxx$P1(r#1-{!jo&~mD}|N zdD$7%l{1+&$_KC7g#~{g*KishoT#NviYs39RBM6fs&#>rjPG`NahUNEt5m>!CVwTd zwdKs-XeHl#~Q*)5wDMvpq-sZeZaKq7IYHs;;Julo?;5w{gB z-T-8PH!iGTe0VI(9KoS@diMjbC;ikek&#|uDY>qpd`Hc^s0LucAS*6tJiQ-p1|51Qet>5#cKkl9V=n`-mbFlw z8mfbNJCttxlZ;K4M!`@DPXV*nv!LLC#r-q90twr=*$#BW>V)^W!d~vDD2KqmB4GPc zi`k@X*iTv{V2=?Rj5T1w(O)2aV+H>~7Pg(Z(~KT~7zPr%nSq}vv3`aR!a3c3 zhwml)WN!Efki58?dV?a;GUInF(1l=tfuRRr`Y?a=H*9E=@Eun2r)KzszX9Cjf}$EE zVS=+j)PYe7A5mx-=W!2l7m@+~IFZ%w)%#t+r$t>eQ*q{;@<~lo7z9Znbh|tyeI{hn ztp9UpcNFP)OKgfa;IlBZdZ$rO> zhg{>1kFnQmY9Z1ydz24Sm=Z8!0ZPpeKwc{Qd-PCpkMGZx@>obp`ZR_T|94NhKiv&? zb-y=SINZ(B(ATBD?Q8ugmXm^KAFQ+cmvkgDSIGK^X-iF{EjnsrY$))=I`_f9) z)~=1~@pEyUAAqO+C9MGy+%&H9?Y`m-`P)j7smHfBkg?W)Tft&X1Sx9WSZw-yCC5#X z{en+0^Bm3kof+AXVas_MJB@XwcGkQ&(12(WHGchDA8v)h2-b@qx^22Cw-yb)-0}u# z-_zcYl_}MAH@cDl4S4S?1%jk1QlB%lZbC_dgzOXQ57td^i?dCuQy)MCeNIwSLo*UC zTatl+a9NUTtx=MiN#-W+#pQNf2i6Qgte0;orANjug)!$oTGGi-q_;?<{Gil)L3n(! z$mD^J$|j6sr%ooNo@9kXqF8kPS%g&|!_w<%;yh!>{YU&HMTerZk%1Nwkx_$*oaDoO z{+pYB#guk>E?hRF?>nTgslKXk*Gs-{qtQaID9-C5Tl6|!5>?F?X*52q+4@Pd6tMz< zs!wnA&@x?tcS{;eUmfiAwbZ1-*kgWJ+=ByI zHM%0F34rb{hy)U-uSYP^$GWZCn2S(nIte$iudY~Eh(xH!a-7F zXv7$c=i%5xkkjQ5y^npK9p-2AM?RYpNkJjnmQos;*|hu~cF%m+yc|%05)QqOH|xZd zTUM%aeH}Suc0x5pdZZ(kpQT9;d8CT=fimu;X5z#uzbOyz)c z4L#r*K8+d*1hBA@&%G|mY<$reya`7Or`q8e~}`J2@Foz88aOPR)s3?Za^ z5!UY7>ZM0&V8l_Gh1qI7@JbHw?*Pgt*qK5c4N2uTS5`f4EXoJwd#NC*{4h5AD(`V@ zBGcBcP6SH`wX!Gv?VBWikt_jOK zRKl0JVyD{Qp}tx9k1Ur!nXpF2`^sVk!r%ktw_ZLiIj z?JP%~sHPk;PAL6Gpf^xM`rl?hH@p9B1cBBElXk*%6Kq9!2sX2-J%>eUcEI*sSp(>` zN`k9il|I2rPhVXw6eqgp;dDh%Ab$FLL~_c6pOZZ8{fZOiAvrLHHH zurZ6d{mCKoTw!H1jEnZ9PRg&5U;ZR;iK}B}dUE&*$fcrtT7XGv%>V=ouh%Ol&X?WI9*S*R zQ`>AxUt?-$YRmIm8fk@#M@Ln!z%~g+FE5+~{#mg!stj_iu!EadM^2h}&+I}#ymmqg z*!n4Bxj{7Y7xGF7Xz*{LscjDCpF6kmkgbKg`&_3?uJ=%q9Pf``2&_{94k*eBU$?c< z2xD4%w~Y^Ivw`U0e=#_+PA7GH4?etlviEtzL$g_p_qer=upz!2m4c>SD>zY0X-5Ba zM%KG|zea7`d9_l1rU@gl)Fi8I{pb_YLECuTMYKn`fw>c;0KtXcHZ_#T)%sQ zGRGwtZNtA@<8aGJ&qOE^`Scn)8>tD9_&Nutt);=h2jNP`&(4W;gtrYv>Wys6avCkG z!h{cDHKi8Giq;KmLFt~n`d_DPI5`g>?)Z+*y3oB_qgrnf|Ga$*MJ#qBqYJ{_&UP2i#pyaD2 zmiea>10*E)S4m@?zkf0~M$IP>ug<;~G2AlN9yoC})fRs9yH+-eOg9%u2QjR zhgSpUv&eJueYYXst57;owAK zqgfl%eNEw`*P~900#MT~y}=HB^1f`!9{e{fiEnova}v#;*b?^df9)>LuVG%%HxT!9 z2^d($=@GLI78TRKy_Pw)<3Wa?IjFiEN(@IdR$6{z8aa7w?l7j+27t+iwS#o3XzYIJ z4%MHh>&b$f)^5jRZUwFjHZ~-QW~@mxp`mAF6Z1sh$FS=kxDHAy`2(YfMRqB;{K=nz zoMwD25y4JNWq23pmkcIDXNz41PGKW}#OU;ypN0rf+URm*c38|`kBtym*F=SKa*|Sz z=slt4(Xas0FF2d8)8B4jVSgg51=9~3TDAg!0|Dg6hjfYqy2&Y)kvIrHAo(;J7r*{h zR%iFIr$5(Ozy)D2cA((2oD z-*`CqG?s+!`^exeeUVvp14Q$kF!Q^Y4^`HAdVzT-NRgq_6&?-3G#>abU>0p>i0%h( zI}-z2N86rZ{_(Tk)ylp!;ISd8L`ka$Fj2l8Fs@QJ+|$33lKM8W=H5RS^^_D)xEDJX zf;S-f05X3r>y)8e`%LP$g7&t#_;iV%(h9lsKf5JfpF7J=wGIlTCB)tHoS*mI5ieL% zi_UFb`X%*uz6-y5Y4(&0mKt`=PhL%AZpiaoMctApzLk3RGOm1Zxk8iPmh&jNbL~*8 zTZuj8tS!xdB02jX>wTS8JVWPlxnjSST5GPp=X`?{&%h3yr*oY9*fp`VS!6+p z6xbqSuIf4Tuf0_OJaS2CPoqJWV06~9>)vDZ z6dWGjDRfcDz*P6Uy8K7%$eU(j-}CuKubqoCEc1rV=TI~-X>e#fUq0PSj<3+tdWGYo z#oFD%v^F!kd!=RyPzzn45p=fYa@HtZ^Uk_5HU0N~L^p1obDbFn@t)Z_;%1pZW}9E+ zqmRXxjKIFn*);#}Xwo4lr_ImK!`iF~nob@EA_>8+|4DQNE;|zY>o<0iyYfXgBh|5q z*vn7z!^u4jJ4yA2jo7>r#UH7!z4@vqlr_XcuirDrRxr7uj<}7fpnsq+A}IB6d{U7j z!BkMZ?pya|@t13YHB!^6YslT-mG9pEH|?(P6a2x%Gqa;?qA^Oir9=8-Oj$18N=tkX zUJSwYw_Q_~$b%L)xS;14#iiOu;1F>oq=baHR2I{im5icCR#=SQ-p4oc=Yg9|3KR+< zS!GBp8AB`#1om)PtU5HhW=d{xNHG@7#fb{K8dhnb$=G_=Bu!4{#vwuPvkj;3wPW6Y zAK&AV%mRpwog%ha++1tsXXRCD!HV&E1r&&=@dWxSqVx91Qi0F=_(h3wprMZJ00`qPO3En;^X4S$=^0M0FbiR zbth8p+XYHH@}SGl{S@y_wHcvd>rBzyx7Ab#P(R71B^3Z_B|=87@cp7(vJ z+_C@qngiEh#dRSvqT)NGs5N$%C3X|+y{H%g@N_Hm9bnG-O zF{EBsB=2uE4Ic^GHO+jXsZ1)VcuGy*V{-dc-_7aO*IyQ9f(ey4iMG+7=OKnHN~cn^ zAHkVjYE@9iK{NTuX%N7qj`@xgfZ#Qd7_Hst>yuK}&yo&4D_5n~LsZX0{*i;P#ow=< zA4a^R`7m~UIjvO_E9IT}ZV4nEgVvu$nGg?VIpa3A>L4ee-p;%V7#TmJ?6I&s9rHkAAJsGP&tQ_vvbB;ex5s z1=LUqVrGB6*UIkD2R1CcWL(RYucVUYlrn> z!bct`9)pF*5O2RO`tJpo{D7M0ts2A&1x0+6+m)xrp79V@uz*@bK-^U~y((vbV&eob z&~s23LceY()B`$o^^)`DEian;ipw<$B7G##|6*wsTti=zZbc}#D*Ggm4`^=iXl`0)1R4=4_ zNl?}M4GrG{)ERQ4X3gpG??ziZXGGCZ3vcfgf%; zN{wHdI7uzIi7$Ne>)P^BF@p7jH@uU5sZfGyZ1F(N#%rdpJ+Q)8qd#&UyX?Zk@~271 zuXCM5Qle#sX&hMOaZ{2_1-nF}`tGYJUdY|=xsDkKi<=E8O_pj^A zf=C%fj=~A5WQSGFg52u+-qFCL9H$Te&n25T7I!Z${o{-247}VLbk3Ke!l#3wjFe74 z0)~@!kEw+rD+v~?DgR6j2mj~{PtR%t=`Nv)`uNge-Sp9^roL`CvPXzrrEy!*}~pU;X-8C zH#HwY^NRhq7^PE;!X*|9y@XmjFL<%&i2uEGj(|Z*I5x5BA5TYgrf(%a~FUeNmaP`guS5kaN#pw zp7VaDEb_|l_9O0PCLGeOavex4ab>pHO9Y$y6s=^w^M85AUM#Xx&WVPEiFFkU(lZo| z)|t+5O0oyCDE^>z^UOSFY`O|cK^IT_MJrma^BAYWNOCU^J^cgjM;z)AArJXHKJEO6B%OFc_5cPNA>o|-#qjaD@!s$I z-b}0%J>hvY7FRHfkCsZ8i-<}$c^1Lk5(E@n%U+`s4Xvru5R(?&+ya}1sy-`*5_>0a z!*eC9j2+B`7kM}lR5D#vxgO>p`$8g20BPRV8f|2-k{oGE@|T>7_5qF1n>bc-P|noPST=&8ZFEw;(H#mXum(cx$A_dsuI5Z_}kj{ORIslc!+^~ zTHEuR(A7FZmQ9lGSpLwc7j)~<&zYYIknS3HxO3UC+u#N=kso zy+kxZ9>|m9;faG&GUAkQ35J+jBkf!pB}lA3+uTR;_fgcd$aM_Gj*#`cl^=cq~-B#o=qDDvg1?-*2; zPQ>)j=IXQId2=DYea1|2H_8ch+eWgLcynT$ZqOrNc zUf_T|W&}gMj{KGjl4wc^BQ-!7IJ2<8G|W16LE^8@_OQyn#zg8$g|2C?mu3P=z@{>- zTSOZmi2a( z!o7rNLT?&C1s~HK9C7&EAj}>J@X}XC+2lxB8|zwXWh-{SUKzZ={IRxADISz2C0|FM z%ufZZC*WB41Ym`uhbdRraN@zv$VBU3@W4i#b=SQLDEGnXw$Ot!UD?j;+`S@g`LPc2 zhHx!CWsj0#vo`D39YQz<6`bB8QpKC>gj{iScJcnY64*oYOW&~8k|gy6q0|aH9vzKi z|HPEajHi-lf_L9`nj(DZds0oOh}F=tS}@!DjKgtZO#%7d-JKpeMhgmgUW$=sTUfKH zP6*HcBJDdhY~>TuaYIVm;_*!UGF<;^77?YNP9L?o{>XYqj)V6qBCKuTCQ9XBr{@q) z@^GkO_ln}2{!i_QfOrEl-;(y0`bX8WiWd%8X^ zbQjOa7c5p{Cj&_Es-pN6+V7=)z;RI@}A@eBX@Kaex3R6=zo?s8d7mk z5PM(^3j#`tX&&~4Uza0QTJ0GeeOVqsD#uR4x*T9JyjZ)&V9A$=BQ@!=F!Y73M&bHc zBgHf>8NY--3Ek9xSjM1!KBqqDq@&^p6(cA&(YUzrX8o0F*wRnpRlmvY@6vGEpZdrN zPIYJA8pd*ik;k*q_O6MN-pUEzfbmSO5t+=mmk*8baozBV&X1Ki6~XJ8l_TW(ak&wA z=CX?Aj2pp~uL8{cd0$)j6fmvve=70+Ta*9q5t&zjNn^6c%y!43mKisJL{UL2FhUu4 zI{X@V^n%aHgtZu|#2R|2m6=uzDYyN2yNARVIT-5Z-H-bniWP!gf>VsCYa11h3xE8f zXKr@X`S6k`%dHEMyeGR{XR~g;UqhOhr2S!fD7>+jH6Wh9tSCC+H#{|d?I%NJc7>f} z)67ARf~&XCHb_nFS#4?iRJ-<6yLaNu*(!eqg-`K`1D+MS9Vl6^1wI4k0^|5Mzd;fbtD$>r(CIiJw;saVu>pUI1-3WRfvs zit;O|^^I0oE36wF$Nk|NOrC9YnFsX9QKabPvak(m)Y9n-GWe#yyd|_g@!#eN0$BON zQc(?CFeS7{4tci3vav-Hnf1G#Ud{gus`TSFP%lQ~0X_34h)B$GMWH*s{Mh?EV}Wq7 z`*iG-v)ycpBW@HGAq4z8wq5Q0k2{=jwxZG`dsPF9>|{E4(BTZdj6zrm_mB#$F;lTd z%im9hI%ABU1jG#!0}`4jZ`#BY_3X^`jTZiGq+!%naR!%|y9Vzr8p6i0a6q#NXwB9! zg;0O+Db_NEZ}-9sfC3x{LUc&qs9{Nv_9)1FAVVI5uLSX*IPpDLV0-ZgyoI^p_B2F1 zG+=wt2lz1KhAC%+1hlt)#SL$ODX1K0Gnx{j zqBxLG@a*M1w@NYfBAc9EUaN&$3p|NdIYCRt?5r8@{T5i;q#z%{%kXW^6HW;sf+tt2 z%-;X%q}qbM05`Q*E4CCi`%nt{axr;35V5uOg+_M9NS{a@cf{yz?h@C;IZf^l7Z8?uS6|I9F1eYz^Wg8od7mvnBKzFk5?3M^KW ze!F;SYFMIK_I2vY_r}O63x!CJ3$WuYs^2xGPL5&5DAd*97+=kuPTBO&Co$yl${6RW zQG5P>X+64LNiw(xBs(0>rZZ<}r`Dt^4B*88!v|iB*RArID z-u@ImJIWPUvu0mq?9&fD>Ttr_sSN%bQyhD*M@(!~IxDTuybZ5d#sK`;cZ`1Q(3>;- zF>7EN_$S+kQC|^3#u^{DvW>s`o@-lit|dSlwbnPLJ#pkd%u2K@&J>>+q5R*A11s`x zw&{Z*_W52vzkD&zcjus=DIDixls27mo*uZV<&qI0HSrfvK2$_P;3gf5#vz zd7(JTXMM8dWq`$>*ueyR-aM0LlT*Z!Fx*i*H9=hz!(O(M>|2-?2(5jDVv|U4%PKcW zIMZ{kw)b6h&87$H7(`P78q8m*bA8_~g~0MjvV<+Gz(xo-FX8Z?gKyIzW_eCfUArRK znMrdB-kQO(Wk+9nmbpo0>vUGFkmZYP?VGmP3xf_z2)Lpc2Ol!cj3vEn` zkQID7=hdA|#V8UqQ3ZI@rA~9D;miD}ke~xbp}+n7iF=M8gFFBKr-Zig3r|e9C?)S? zeVSZA&+5{UebppjcZXv;#X-3x$~1*Lj<%n*+d3dzw<_3rY7G)&($K1D}Y z2Yj@~Q?dNL&VP1qlEnVX3@BPvp&!0bRr$$;;(@7GvfsUgQA>UL`!>z$Jys63*xVat zo=$1I>K3tjm6@?%e1jjUr`_#!mVejP+r)$Grd_m0yg(cu$SToS{UpiMlPp-?ScZ*k zx+y&vOfD$ohNXedT0jg9+D(-wF0->y%z28-g8V7Z;_3zpZ5VE|9Z)}kJxJNJ6 z2l5e|XKdNga3wUr3X=RUGXmbJFr-$tZO_l?JlA_miaLzvd~wq13MoA*fNLu-32CO- zbqksM#<#%4d(4%KiGjPwkbCswYVfJIlWQ$OQ=JCwtL2QV=p196aW2PES6GjGl>yHq|@oydrk%uag$*HYj&R*^e5%qavVy%6K038ssIH&qTgE zAdsu@v2{P5?1}a)r}#6(;SCx&A^<*KQ8ejRAY5Hx^5guNI$@j&E;||Pw=o?0PWK(& zN2+wqFU3Pq*WBL~`!&{9ti;-f;4?1}8ks_R#ccBE6MKMRnPk*~76P)e)%V=@F>j8C zY3N@aBbbTqfrF{QI&RZe*5R*sSg9|ea1w6s`|2W~VXN?N?q$1J)Tm(_O6h*)7i9v= z1Aor`KD z0r9_{f?l~VI`9P{%8PfK3c+mJYNh7emQeuRO{DT9I5Ck6RM2oxa4k{6q`gJ*?&MSQ^UB z^QV5GO7bfl@)$Lo-I`kOpyR~Y*NX*gWvj9SBxD@fVmaf%&Mw5ac-9n#JMP#-JFYH0 zqSaz)Jo zX?W@72M(-QuOXd-An>G1q{vtl#aB_|6J~lhV^Ai0G6zJ=Z^X?RN zpWTtHtP*0=D9EV8V>sp}McA`M=jds7Zs8;hP<0fyqq`=~D zKaz;Ai+3L+*I3O%tg-GAJCEJ1kFZw}kXQ9N1S02Ggb|yy3bF znd{3&{_!>a9zDyo_agDFvCyF`B!x}bg-fJzWI(|fmersRlM@@gWSU8W$fc<9KupGT zI_y`WjJsx(b;OM_!S&g9G+7WvNG&NUKd_y7V0zc)l{*pp71olfi55?7DdbHiZw|;-(+FR6Ba0zO~A=XOCYe2xAtQ5S%e0Rn>4|! zrX>uQCL3+F@0g6J;_@c;d-@2?qPwfd5a&RYRD_h>LzE2t(fRRME9}K_bN8$_^Nx_I zpQ2xDRK7g-FTPAC8&?iC{ijj3uyR?=U;VGdh*D!Flcw*KR6lLAfGrO*ZoKMXs=^HG z;S~X}@U4H_zdwSNam@U~XO(kn(;Ku|_6yqj=)N+`is4gMUir6Y_=PZsJBg}!OXe1% zh_tt?tLga-PE_U9_Wt}=mMR$PLJI>>J2KZhk4E;Y__syf%~AmYcJLWlXs~7cGyGHv zMC-}d9oEXC|BCJVsl@i0z{zQ|C0kzTC)&MJmwEo`Qm$=*SLW04@AbOvGK;0vSF!63 z0_6np3>~*}&0~4qgJt=|ms23JKDDcBQd8hmY3|AbsgY`aO&0894tGW}CJor-gDt}# zv+bo$Q{Q%HGQsYrp;XrrIleO9+I8dEiq8zxz&v@s-hr%s&(J#PR#C*S?&_Yp4KO{@ z$!m%A`K?OInmOXwYlH_uFql(|A!uIIf8YtMuR5za2lvScsXt=4mpGEi`r3%}=sge&R{ykU-d&L#&61Gdkutr<{N^L8SHx>k zp)umqM}~%60;cG$p<{Wd(VKlyc{+7<AH&)+=mbaH7~$Fe9Hc^g)O5sSdpU5d13y`I0TV?O zu>=Jpf>fXi@u7@jD8EQ=jpO^z6W7|&#}))DPmUSZ&!cN(8Jl4E{hw{b_*31em)$|P zf!-SORJ+srC0jW6W`hdak2MgpxC6YMPA@cit2tjBV%h%2EVk;TZN@{|J~ zlu`?~qlmI*>VeeH{jx)THxsj$yy2fWc{L;Xm|!qGz5$QjxZqs)v7TmfIh+N-Fq<+4 zD#~PZD?!d}!*R9FK=gT;Yn`Jqo4FRiC*(6yp=$L`n@^~IwpOFqao9&^eVFu?(cLi-WHSHBh- z*d<=vWOJj>zjV_I$`!}yXXTGo0mQt%0}{y|-IsfarRWYXm>XNKQng(L1p8hkLnn`Q zvke*5vpNm70c$)})$=9?GnFcaj^pY&H$L#P8zH}a}UXGpP|bkVm{WwRHewt&uErYDcx7{Hmo*_*WttSclFjYq5SVnmwCBxPYT^@>C)3V)oT^8T1 z51`s$+^?pHYkn#9&;e*p8}s&(=p9!U3Nk?KO*eGJ2b2SYG4&vrC^(`7KZ#35wB!an zaa@C_U-SW>JS{P~{_x<$kCy53Tvj!~yrp(X}2_QkkWm*Zkk8t$se~xCC z$OSrloE0XQNs4RLy0VP}br2K2yi`Bua!H5Jis96gR+!C&hC47~afV(Gnb!UOR6VGv z@=a{8ggHH^n9eCEV=V+D?-eu!QPD~DE3a&9WpdnIX9b3xYd3{OABszVxrpS`?q8h& zX<7)RXmpk2sO8bY73fXgM^fsE56E47>gG8Yvb^O~7FrucM)SUhxcD#+zoO(yj>($_ z2oXjJ(VK_>iQLZxecW@**wk%$M#hbUl&=Kea^MoaM$5xaq(ud}k9U;>+n%1%n8`9m z4U~$}eFwOS$|!0HmfX6`eM+C!B3dXOGk8Tss!0Vs?lZL$rEl}lw%G%Tn4<}Vvd)-; z`&a#|Xtbf>Ej{jvXWb+Z1_Wf^@uf{DNB0STqv4MBLp7-&W%82Gpk#Th2y`)YFKqrb zbK_=CO8oo#BPsX9gcES@bfy8&Nk_TSUEy{iPvW*5YuqM}vg-~0NLcsYX zwCyE#fl}4^uJsv@AT!rgz&7q4J^joszZeHQ6D_V!a{RNWg9w!*98)&}&Llw=H#(t8 z$Zv~kZbnSWc=!U^>>u?GxMvnP7m4f}-ovlfM}F%F$?YSUH9yC!uqZ{yOf&n_BE2WY zVn1^EJHk+Wl%QJC7?$i#FUOav7B|<>Lv5F(?D;x#jz5qBtP&p?9zQ!UOX~oB-0c-2{GDxsp#ci?r z27FfD%Wq$hp%M7tD@y;7Wkcg^&>Z}PG=O10y&2@1)1$*_BI;E{`+Hk;1c+544mX+- zj6~1-pRv0sr9J{Po*?ErXFH{cRu$CuP8T}O7h!Y#OV%~E*}0pc+l9xA%p^sEIVlw? zC6_U7_xqj~T@_H?8k#6=#p4a`Hv1$9^urDMEjQW~`!Zwouq4&8Xv%Q(DuZp^xb`OY zWX~qD>_DjG5|KgVRQAuks$VRTL@dgoP9==13i(NCyWX%a}O?)+E79nrvQ<* zyvB0YOhzAhA6YHU~s4Wdc zlmAO9ndFOrk zAn(wKskHqdaQi{tZXTf8M)wdGP@k%EV}q=PPsP1egK&^KGunHH-dKQ~?+%WqY=N zu}}=xa#{HF9=~h*UYrQ59gCl8&@KI{>UYAeoaPg!U}EWerqoCTvxsDm!AeB4teW?5 z!c!so*oY@I6C?PSJ!_HQ9sH5wF!k6;ZUf;&m)P8faC>BitvB9ue-h#(-(L@w6D7`XKwc^!M^VJQ|2 zbrT(OWE{Lgj7or?c0JWFaYma-XkePShBUae*0c-=hX?wY&en^_x(WQ7uqQ9&wfX7pD|YFr(Bii zF`@#S%JpwKJTjZQBVJhyZ9TNU@Mi*l^H$wog@mzO0ok=`VK)rz=O1u%NNIY^Mv-sh z9b^Lw8cSTUEGF;ML+!rTVQN-h1clpuUm{e~sxKEB8wtsF?;l$@;E`|wispxo^h%3Y z`qwL5B*e!M6*VS%chLaT49ixn(YBn1cs_oGL`nKB8_MgX_XOx{|~H(a4ODU4Cosbvq7Xbe**WlMd~`_ zuMTe=^c}}QF*o@0aezdVepNMmjBoDT)-D@))Dt9YR{q7NtK_#^py=E_`Ob;=kmNm+ zklDfqI`X|c#G0sIGZe?wwfeb4ruKNkXmlNgBz6m*jok0IQ<3KXVq!Z8$WIXvh1#JP zBx-i+$a5dXaS_eq-KF0tXB8tm)G38~0ADjjqY5gd(=VWl{4Ut!(_1^nN>Rs#4`AaC zEzl8t>PT5MtxG%gTUp+)Kf@H!r{b9>KVG|NIC*#s|6EU7pdPE~X%Mh~X=y=9{AjHg zxn6Dz9})gFTCUIV=M)umTpT!r3f!JA2)N*GMfxnv)tyvjno(F-xPNa)7l`eE~=?Wf|Nwa`+2vzys>X}_KXs!7rX3+PwnRL0`q8k!~*xgwyP5~JO^wL zb%&Dw?2nocI1kGtghwLGroy~o*_@hII^EVBjrj? zz#CsvuzFRyVx9rYUJltCrs}&VsvzM&xX4p8>NeZ}pRk7>tU}OLZ-LewO~@zwo`T4e z6Rbbt0FLkz5&g$d0h7w5=Dkv0=&*^&J+hJRN=7TV?^fhhl4?D|<(^+0V#p6v#)+}S zpFRS03Ikd1&dME@fA378=*Qopm7t-xM(8{|v~K@t$(PaZdbjyBjl!&LsC)?t=Ga{f zAu>likVo;tiX6kjphg0%R#-$MW*XcrnU|htL#StOw4G*wT+U6}JfWo)%JE`9X_FF8 zrwBnh=91nWlfToONf8LeOoC{4!L#ojek}8B8&T--jrbz4Gh?+4GV?I;+l^suHY`xD z+H#mqV6OSDgd!ThmU^=bL!(q~36b{ zLD%&6jWY_88V*gM;aBe~qSIH4+xN1_rlHUDqOG&3>&x{z0ks)% z)6N}G>L%J71}|hT`7YFZ*SLLJ%p|0kl2l)eRS6%$VqR+4_Fu6_c7Y(U4OT3J+Ico} z0(VNE~qR@+y-1%W=W@B{xzho@+_cox83I1|XjXQyT_S1WI(KT=CbB27nhIqzD^7Fg9j%2m^QKwZ6$9XIG zdKxpSLpC+M%Kjn&Vk$X~e{^~#_OZ69kIuf4bV%3p_@ zU^2fA-!qD>UJSWp9ZuIPl8ev7#~hH8mFaiBY%-8|EAJH+!mnUS8F^H_A&Jpw4u1p%WuQuhFOTAZi{!vjqMF3se!SmlPQ2 za+5BMJhO@37bh0%r*L4%ulFvfV%p=p^fFn6!Pre4uzsYv(TewUBF!MCSq>x z7n7ozw!vbQPDxIY>}Y?_e~q`d%Mk zc)bq0z%Fy}Nb?VL)H>8OK+YAd0Z{b5@7d^2^}h_jKGg-xKycSote?>2r`@!Cn)E?C zXPPV?LCEUBe$12)f*mv|_ww8KziOsuy}77D+R3<+K%>F_vD09qk-j*LI7kN{-o>7w zt6K!z*-zx91IcFJiQl{T#tHPgx#c92DBnn6?)`+ZWSkvScFKLutyNfept_M^H2D$X z)~X9Pr@!@Nfme$ezFXCl-iv(7A?cfg<@G)yG#ju7KjUdWLKnj_330Makc+MGM-lR{S(uMyNF{r>&gyusqs_(#8=txHa>C z21@SKKq%YCvPCa47!y{aCX&NLA{6U;a3C@QKYlb}e)Li_;e|mp(i8;RLkNUVdGB!) zF(MIeBXZ66?M*rQ#!NYyMSJK$+5x&Qea9WWr}HcgI}O&8`36kNle~UH&Nee?f!Qvsv50-YhMr90=!xFyUL3PLyE@4Qly#k;H-px5wesIb1j! ze=2-V!f1)$lasr*Cvv@5KZB!$wd$&hZN31(g{uDmLAwjHRiC|s4mwvx-LISPe`kFeTt0DW zm?&=Fak`*hOLWvebV`|{(*K8l!8gNmbz0>}^nFR@TXnGgeReV;fU%=X@5m;JUU zgd*#H{9FpqMdw%SaW(s(5qONR&|_5S#aV9o!X-NfHj8>4K#x7E#lwAb>kVaazonp& zE}Mfjk%mrxk0&tcw;KgEkNgG-br4-kQzVL$41V)e=V|q!Da_7UT=WeAamPE^ z$23wqg>~P$(Lcj5IhB=2eXDhCIX9!cWlV8|j9pQDIFmZ})m{Zwkhu_8Km2>DX zA}NXQ9Dth>ci_N1Bk0q=&h82GL;m*ZN3hLH>F7hx@*{0}aVb=tQ-!~cN0kE#=1Gl0 zv_9a)VpZy1x^~mj1833Sy(QwpmuMfs8eQh_WD*sxRXSp`a|Bmw+7|bqKvpK(QL{mY zo+ejQo?iq4X43ce{!#Do_0Zqw%xMrbOLEnGK!z%aJK#MWG1yA@gzJbsfCn4iJ>TcZ z4+lF+Mkv^GSsLgbdc};ojWxOnt-B`+;O@ckzth>27cS}8)cmS z&AP<>!g6`ui3PDgnSJX||6q~59vFN5DP;XAtogdiSGJ(w>rY5{Ef^h|IRa_u?RkmFX)VO?cWv*Ma&LLjUq8x!j?0&^wJ-5p$>a|HLgY}zp*`~?ilT!d> z*hM8Nh1X}#FjQ=gLvKlb@flPB|h*+zJlM8Y%q^S)rA@CleYW#>+DRUgCF$D+I$ zUl}flS5Rz0C#UO#gh^_>yw(GVjdD%vg&(d*y=gjRed_%FBbPH-_IwR~UOBWq{3mKq zJ}u@HJ>ePA+e4Vm1W|KGWuD$9j^6CK#SR0*kTy#7V{z-Y@e0bpq=9;B@K^RG^_e~LAVisad9fizDZ7d`NCPL$$@U%7PN$k!X!mm=4sN%KB_fW@OA|P4Yan;s6Y!Zr|qd809v~YIjjqNwCL^LB@NgdBbDz?<{FOSk8%_zQOJ(oisSqgmG zzbhdo?S%4UU+5(+*;N|mAqa_Y{(42d)jZ&!&rzuq8nWhSrlT>8TM>m#S7Ok9yML5& zG`vVhQWF_2yAAV-Ob7cmd*0P)k96(5^3Mj%*R+0L$3YfNpdEK$;XodBw0k1A_H_f{ zT_=PY>kB=^&a!q1G;F2&u7yu_IIiME?A>ng2MWSeQ%89cwEeSE8F(p=){XAKEulmn z!;wBTxDnp}w@Sf-V6&m@)(fsmqMAcgN0`lHm-Sctd3?@y$B4lrY{J5>w_k&nvfJLI zp5i>NB!4JErFLHro#3VZ;9tyHfoiyC z{AZcl{HaB`gp|JGwo18hgRd8HN700xvQNOn^zbj1=^w*r`8Ff|`fK2AG%A>6SK!~p zdwThw<%`LsQS9CmHv9G8h&J6SMcmxPjycSGlfJ(Z!Jr5HGsV@*>zMlTTxNZ3+Wcr} zHXKI{Pc*Lw{!TledLb-NdAcHJhts@1Dt|P^;(P~VXSgULhOAa~@4VPhuTnoOer)bV zwjs_;LGR$Y-{BpU@?hx@!fVEPUw9n|W};4#i4JY*6XZOsgQ^wv`a*0c%4 zD6G^tsmr+$JYyAn{tNA*NRzlv7hS{_Ns5b&04KigDAN~n$C;}X;psBX=PD26^*5z> zuXMm1K_|S_m`DO(C=Wb*MYl2UWj_ua-gknY7;l>8viB_{hUlP*>RyOq4Ro{A8NSip z&yREaMu#Ejzn;9J3ync-3lBaMQR5ybVpsK^JB<1Hiv`0&mbo0E+`$NK_c9@U2iP0P zCxX3P*f7VEtc29LgJ8Tkl7zq}W=N*~wVHhLH6J(_%7K3tJ~ z#<2rRIE;^uq1|d1+GjkU0~9KodgRETFVQKebYX@TB85aNL_+>ES}pSAfX$I~>7A3# z`^)1PgS6Qx3e8kXt+4&CZ0CAZpivA!!!QYySy0=pqv`|2@6*R5f_}4wEn-Y1V@MY{ zf~P6{s{FVMD5l(b)gf7Ao$rdqCG6^$6A>ttKbmA&%avE5k0i7|9!DdA;t z)mSHqm&wPHQH;z%(JUS`$Zya({B6H%Pk&`xdz|At=IM=vrTG(qolRvZee`-`rW#bZ0phDGjv7&(LRKy-w~kT$SARZIfZ(aZK&GM0%gRWd`aN4tX%Fv zv8?w?JP3_ex33yq_pt?9bwv8$JOB7w1fe{f${X_8uM8t@5AOE#49PH1iaLW}P9u7g zNf%FaQ^YNHFW0!y_waLGLE4M;-&`aW0#FI}7*=|zRv!ARiRjq_pBjs=X|K1D<1E{s z_R?%8r~s_9XXO`S1zsRz)cNJC`1josa*dYRph5?Ar2^Q*mkGa#n&09{Q%I;(lU{(1 zOl~w#vuq?2$>P@onFdHINSL86^-JOI#_}4>lbsu)QfEGVa0c>>9>P95K_ty{evUEG zxqi9zeM>~f$p5m+ZQW|}T9-4LLJYi1;`YnRhBM&X~^Bq6gv*@?4N75x?#MH~MSkmMs^p`Y5ew(H0$RVU#Z|`DFg&#VLZpDFZ|lRzrd0y; z?{ued_2kJ@HT?=Uncpo7!f|HVGU_$Pv@FPI*++2OHZ;Sla@^scM@JSHKcwYmcK`j z1IJo%Lf8Y;*?~~*-Gv@s0AMU*VA>Q_MVnMwJh2L~7WPT!rfKN410W6dQE6G=bKBUp z(~4>AjdCye_E|A@REhIMJYD7pb=_V@O+b&8E82v@6zkaI?v^KYq;E$!9`_a%rg~C$ z6>XYn$P&-A+=a*LE+eMQ0g|=;Txh+xglx3%w@Rm=j_h<90xVzRn>9XQoIgk?ym^#f zOnQFVf&TG5Ju)8olT~#3pUkCqZlmPuBN;^o#tzo~XvX4XkI%ES@m1pyEGz9AN%YWY z*r>phn8Fkq2r1HTe11bvdvdLD;mNs4V-Jz@MU>qWf_drsPk-VPfpVhp_`jx!|Fc9u zT0GYH`e2Zpcb7Vn)yXrto(K`)k)Q~^e8NY@K*WB$K26(Q@Pl$kA|}=-kV3nsrDhM7@V2qHy`wt_wFqy`%HP-%({6 z?8=8ztjY)e_t2+R$4#GI3lErX=PU)Z@4f$Uy_{JHX-Ksr3K^E26>+^R1v+NqR$gONRK6qSShf}G8%4SG} zf8Q)dcRq@i+^Ev*o}(@etj!lPBN&V`8B--Z;{#p*zGcBOT93lWiA$Hzq&D6)Za`1g zwJUw=m^w0i=*Mu#234QgA2hCDdymFU{t%Z)wm?t9LOJrAlkDGmz-C*op!O?7nP>!2)q z$SXdNIcUN-s>m2zPl#Nrf}v);Gm5rlb$>lv;sW(5GZEaNor2$5cyp3Px;2udLJQ$+PtAqMr zyVTG$J;?HW@l#v_?N>I}ASATnxiqD+zigZjq*KlR&GND5hO2(VWkaVP1nlT{Ev&UO z_Z6FE46@OQA9F9uaAd3PrScno>}?w?h#8NjVi7Bv#^#Y(KAUmA&*JJQ)1EzdwI`Oo zL+XVVi9wy?mp+Hpyy!jwJ4*{>J^$cEjU^fmOREoP3R0Z4{>kF%v4?Ke;}zziCX=D> zg#`>gPIiyK&qT-k#fK8F8|RkRfeM6odu8of+Mj&Xy zeiC)fN6;Q3??8mIFnYMls<@DSuz~{yW!MKbt8JvVN9Prh(l4xy2tRL2t1rl9xoY^! zHbf&Rr6<$_F`?GKm{cI3UwxhL7KZD(o*5w5s3M!^7hv;ZBgbn-5=jsgvOJY4MSAcS zqRJS!N@%zC@8o8ASg?e`ik1G48v&-2h{bCPY$ptrom~5hxz6)R{rW+G+n{xX43b3} zQKEH#5G1|>Kb!MMX{WCHvYZ8MWt{Rr*~SuZ<&SFyq^*#*@RQ-afVN)HS)~pddl?x|3A=6Mj&0lS*fu+M(y`gGoiDbXbZpzUJGSw~#?623IpPFj3HT4aqxlFjK&_C35%4+32%g=xD1B_zVM;fG#-E-vFe= z-ZzV#6{{T$>mB|^hwRUa;7_dQB7}~fHZ#p9rDFVpk!jejy_XL8C{d3~ky*Ls>yvvma{{zV+zSyyA@CE+umL1-8&R zc-dO=;og0a>CjA)!A1(bS<;;Qsj=6aW(?^nggyc^#_2K)G7H@}7G;zng7GcR=qioB zmLUw&424&4pNPq^>YsHfNIkIv6#A#KguW*;V;#6*u|P)|+3kz0`6@(4#>7 zLlXVS4p+n&d|#M5wS7v2c9Q<}lC*APhj7?6<2E$u;MmU6=!0#v{X^&Em}siMGC_#I z?4fB0rB*yjCD+{`Lr;u%$J{;)we2yQbo`AwXnEFc%9mu;*;5!v`{BHW<~bg_jrC>J zRGy?FcK?OvA_#3EM5am#V~BDax(Ee7!+`T!L5Yfyaf*d#W?qgp!9VpQeM+vPQMzuo zt#_Ym<0=0zb;ib)ta^)dyTlD{Ol?Cc;S>k$yrkkE4Nu2K9HY!(IKiX07uMaPBhxKh zA07uV^2QJ|$gOI7X>o~(+-0Rc3+LTSGd4Wkk83nJSo@AK+d$b%D-+ z3%l8i$dq-?%|uXWZ$P`PevO@y@I}&}h&lHAKL(e91ICkyWWxu@QW=TdQM-`ks&X-8 zlHV%N)6G;X&}Nr4>@2Wwjy;6;>=f91F}(UMx3jfsD$Yr303}k7j(QY27XX7oxBvK? z_nNP=U4wA)doR4VUF~aGh_H(zR4`5(IAGvuzY{X1Atu23%f_`Q(4eTYUWg`YkOkk` z^T^nDOpDA0?Pr0VO(OYsfHYhEeAFUi^*`n(vqu_h5 zjv8DcQ@i|qis26Rw*x#gollny1H_1wZqtf$za-$9^&O!V%(w1`BF%wx1SklV8OH^c z0b|!8_Uh+;g45d`6q*!$-xtrC;5MJ(9jyJ&~2-)v} z6}`dMiy5wYQ`N?Y!30pd~F)EB1_gVWjl6Tmg~3mrwgv>XMVFqYH4|{=J}+5 zxzLV-yp`agRCOp9K5$CB=xgQcP#i{bz&ww;x$hWX!nOo5P6HN)P#F^-Vty7yE&MtE zya5~*ZjG@sxI3zU572I>E8R821o%NjHmK#}cSKzc!AD~quZ3lv4ma`*hMi$YxSw72 z?9FX+X)5tSB*vA=&GV$wtYDBMpeuX6(xdf$*PEWs{d!DYp`C<5``GeMT+w$?f>896 zn06Lu)UPE9rKmA4t>8JA*}hh2<$3hQ1iSRUcUn3*18SW}IrrdAX8(q##%jUC^gh5& zje^k;KLzoNlYBLQF26H%_fOkoPqQ)8j>0TJ08AJ-!srYzHwQxcZM0|{# z2*?{De0@IK*FhL*DR=|_*911uonqCoGIZ*J6wQ7TNK0L%!g~R@H+=V-eLKz!_Cva& z%JT;SVw66=S-mD|&&2<|=6V+ZK~}`9#)=DW!42#QyYnHs`B10!_>Fzh9XkG=c5?&JWX;{;|N>sdF@3 z7b^yDCo>Bxyo*Y83xUPaYFQwGt9@l4@ID%D9aBBeH9umiA4i^oMb1NxTn&@_gtP4i zq`%^-g~J|TzNrdW`a%vPpQ(ke??r}>QK6qv)F1cbKKEwq7}=+0v8% z+rn<**a-wSbtA>x*jZzng%jMm^eD1b$jt{Ds+nBT&3nGr^(NXlo^!iKx!b$Xu znYsQgdRHRFurip~5JDPo+n?iRiqv^k8xeZTCQ9S)`UCuHw!BO`XRY2(ZF6>nc2yZK zNV*8xv5iU$yn@45LSkn~**q{eS7pjHrM!L-M8JJvIS9%3OWgSSjo9S_>d(_31$NRm zJ$bLvB?Yzf8};+i2X+coB7G~wHHh>`%B|Z?4YwKbZPI>jLSvf1U7Q4x+Bh9CJ$A;b z^vJbOGv7@oy#XbTy_J<;?v_3blft+0Y+0Hv_Sq{$e7B&;DFfJ$WwM|HI-xI@e@se- z803<}VANNyaM@GN7HDl7aa@K4AA;b7nublJXxbeyyI$AbGDOtibNEPuSQ3O9U`LDv zZp#j3eGM|wg8#8dz-b?)6K^LKXccFt-?VZE}kc5{QJl&<*Z+DbPvgABomoo)7)?*?@j|cKnq$NnmdM4yCBs z+_RZIM%Rzo(Pup~(7B=2zvTg+ZaVvd2jYep9nE&FYEjL%=#=~L z(qs4g_AOT|Z!Edo`BBX-wPi*>nm!boZa4GuM?<%I=oAz#5^$l;)hg)dnQ_u|2T*oH%!MC`0FtQ9WGlO@?LLIjvm$FG|sgC5+xK+ z6~EmvNamaN`xrTq3ClnbI-V^$L0NveZO+*#BA262|1D{ND!or{Mu8pGZ_eP_^EUq( zh7gVX!U;s3#P+quOIP-P+66Y|c}4YQ?LN(w_{m3}Y5t;*%mr!3rf)QV*Vq=%NwJKG zGp+dZf7MTapc;s2xI*5xEG+b0MD5<97z`vCgZ9LtOiU7XBjV0~ChCXtbxVj&6nyiR z%c7V4p|Pw*CX}j1xVPq4a;Ow8bqpJ1>lauzkETzVbm0ENPoP2eD8EoGK5VA)H;qB_ z-A~#Q)>`4VFg_DshSY%BQ_}=|*}w4CW@M=}@rEG}TQmCu``q&I31-ZIUapv(8)jdjnToLZKgf)X>lj^J@A;-!pP-`p+B%ixk=YRDhveD?mU6Jl zXjny|ilSw2;{^z@2f+0vEUpUf0K+wpY0$tlVrtNb{!^%E$X`eIWFEq8^-6 z>jj_$-^5Ds2k2rTqX*;Ud%Aj5lm}o3AYVcxQzU-VyOS+L)_Z1f?aaPs-H(lIat0@W$}Q&!Zq_WIyM5$H{nD-_ERQ2e&b;%k#?;u z27{kji22w=f~_Noe3`bMJSdV2ZTSM#buQFtRs9#ET2iAc+8+|$y+uK}gK^Xt8WuK%QSzyIct}ax81*NmUnanUKc@y%*e$_r zO*-QS__1(ldp!n<_1S{0r>RdeZJXG40$zk==Nj=duB|sI<08 z^|u8WGPT;=xMTPBK?65$}J<5_Uo$QE|lk}=fGQ6C< z__^6JkUI8bI=weQVowCo+vc1dTBll-g~Aww(^| zWfB=Njn-j`yM{XndgWB~(!@F)X_EE@R=~sX)6RM*Pfjvwfg|OR#m~VmbR|i4JX;TnAR=w zcR(4(FV{Vbj_W4vwo>sju8E3rDQKtDfPo8po zkUD6~AKc{~6r!_+;J=PIY-e7c0#E2fa(W>H(Hx@4E#1Z4tNVO2cMU?DfOJ5}er1Rf zRU^)AX%B@|-P;w6o^7tSK}k&H1g6$9A1RA0cXYwGiACe)1>1o?a1=5bqumT0R~c+Q z1->K;dDGo|I!k^pOJOzqO9tjhY6oJW7~FsZ9Ctrw|7wl0^iR4OqWSA#w6-}m5k3l5 zK2d45*t!l4zEK0MUCchOyxG9;RP)n&gL&`ik0@+47;zQS85;Tl8CVo$n5GR(e)t*A z?d=c6rn@4n7l#yx`YI{8LRgcMGgUsaZ2j%@W9-;EK#>wYqpUf=<#`*%ZMxH25jOA4 z5KU)L$$sgd(Er?P&VFV_ykQsl!jG57qwC%oTqq%gM z`r0_QldB8d+QKsIhE!p;fK~+^lIc=`b{JF9pD2#ET|P!?HU(PrAW(5| zZ%1?WVpF8tuQLuGuyw4Ug32gO^pr$ytpqI*b!DE|)w29u+~-GCi^mKw449*V{k*5$ z#AhvNf`}#7k+0p(gFsud-th1pWV8$G_!vj$Fj~7X#hcfR&BybgmAM)AK=Z=X#u+Rt z5;$k|%NO@S!Z3go5@Z~r6c#?Iw&s)<^f%VK1pQyfv`=L2y4V=B(et0z3qlGkT484Avo-pqJh({f2WvyLqW%w zp6E3zT05cgO;ad4;-_WMwlQoaFHyfWT zWOGk2w;1wJ#VHtzr}25RPV>mM_e=ufOk=25wFIsgLnmlm7YSIrax`}Zeb#NOTwAON zrsu|W;*AIrcAO#t+0K6(9kt*ATfdY(Ya1m@MZ8S%rVq}tm!kbnHut{{oQ|dtEBdk? zB+j8lV+HoNg~svHsJJ$Lw)DAgLf2!9Uh_ni9b5K% z86#|}{YDNW)DXRqRvMvgo@Kva=#m+5eH^t$N6ql!*Z!yDl{>#jmglY1J!e=Xk;ce? zGVO8|peZdn=nZKsh0u0BT3+C?>&l%+hSw(;WOkANab2%I8>-FgQyS81o`d#Ec)y?> zWW9DK5~lsv_?=|BVaWrgAX4)VJW#9>al=c*aWOrb&Sl=xqKqiqZNrTd*d$Hu-T+e& zSXSWDP|=2OSYg_VsjzZXlgP6_R;sDAiTOvXDM~>)e(_8O!K91uHR635kD_u~fyvYTlzts5_?Dc}}!=_fLisBUT+F=su7^Uepza z&7NUa#6bf}^9MLmckP>M+?GNqpEYfp!0$Zd)(%Lj;}q+|R&2)>v6L9T#lD^QO|*=b zs&L0Sv~jFIsiY^VuHm1Hcj<;nerw1NW%OTDr6o=VGJ*4B3d}_E0j~>UOCWz5QA5}o z#^lmUo$iIAcq+2THIMX{6VTXV@zRgv8HKnd$Q=;oU3 z@?aDH+s7bwurh`HQ;|0s`q8_EZZmU@*3ok-uY=jL5I5md zXYE49`Mr^*YxOvN8H=v!hTy-P{iqoV<%sfq`3r>H5U2e{o&F0U>jX(e_e`xTm|0nt zM$_0ZXl}h+3bE9GEAM)!iBh%>N-gc5f7h^G&Nbd z+#t+5btolJpd*?&DAb|KX=ZwU7hPAmi>!2Sp~+cUl_}Am($;{GYUgiPim)=U5ERu2 z1DP~9-y?A~Aj?;=hwRZ~57}7+Nmhwwh@obBzRB~Tl3+Biyc{d7DBsobUkvxn7ErY9 z@W&m9Bjjv54?|(!d|8^C7A~cRmIwW(>yZV&e;IlbC>~1C*CpyNMO@|uBOenTU9IOU zb$O zCR6XeEJ3~37!d9A0TQ#=Wro#2M6 z0yU5q1JDbapASbjR3Dkch}J#FK_|zs+{qY_$;Q&+N;}RW;P77jUc-K`9V3iwK$clU zxB^b>5#`QF)^h5d`9h#vIxq08YE+r05nyUnVH){`&7Zg52`9X(u~vYYLy41qWU7^C zX~mFQ>Dx^m$41!~l4+|TKp7<^?)KU8`L@Q*+h9jA?SB(tP%sT!0#}8j0FOVDeB$X?8MJF!VTJ*4=5O6DP$0fx$ z`>XMpe>w!Gwog9!eKJDL^Bz(cF7LUaF@s`71178$$+DNa4h8Ey=F7q!t*IL6of%4# z$%nY6-6gPhFm;FYOIGqR+lo<7%{uq)+R%ZKD^*;_J%;=DP(1sL{JV*>9iLRy-mWi% zShrmG!m_Z!0Q#D7Y;XK(Wlx*cReInHQ0u;@=H0JRgi~wGNL#@a21)~6ArDb5-TSrU zU`e{n)H0ZKIeO=6R@gvu8RU=GjNf()OO2n0-r_)WmQeCFnl7d^Veb=mp zskuEyy$5gVfdw1!1dLoN?7${rmJDe9{W{ z-XS3WXP>C-DK%fF__xpHK5Hw$>1g=HtMVm1JZ6JdrltFzbNc&YaKs=P9?MKpMW)-E zWIL8X_X}g~F*oPNnEnvIq6E5lNG%4%~B99u%kO9PWC1j<`|zHqJ?Y^!qA zUq%Iw?w;1N!o-_UQN(3ZJOFtt@c~t0fom~v6(MfcGiufre4V_HFC*Q}yEW^cg*8U~ z)P(z*xP=ZG18KGV4f;6wM(&tzA6-1I&lff6hG`PaPgPuU7~h;ms6t1HLj$j)BbGDB zhD3Iv?e<~(CB^C7mjzBf50fo8l=kZW5Jj-zTRz1da*`@@buf<283ShQ{-GG@NpdTGu5A~rCd`dciZ@{oi2b6Z(Jw*| z2x1t%Skr`%6xgZ@9v*0T9~S(594hY_MLdUyNp_2)n>d&5SzB?kiJ>t+;aK^p{wXZ6b zFEqff9Bo@;8EgCH>#cQr+PPY2dlv8wyZpkQf}^!LVw0#C77JptZNb0m__3AU69XZl z`E(+ZM%&QYPfah024=&=1s^}g@->5(W9vDVP-+gY8h|RL-)9;FC)-+vk$fE>dC>FZ zjYVRVdf`|r7O`S6w2!VkU4bE)vlD_Q(1^f(<@-paMAh@jiuW*$91`aaFrg4JCELdN z#Z2dkodab06cw~n%xz$7SEikyt(02;n=xjN#DPJ$Z?kcMt<_R^#WUw~^FX419TSPj zM+cx;$`nvPn;2nP-}5QF07Oji_QOH&n7| zy4qetO!i={;$ht%41-1~m&R;VfCy47#g5_q{UF6gn=>ZIQJZc~2lsWiFIpUn-Qo-aPgZGo(pUnNlRw z1A2aA%?YwOSPK>Jf>vKp%O>p1C(5$%(SpbwrxM4Q)((Tl4zlxWQeR@A7`rT_ml5vJ z1&2~64iP)N_ur0(&H+$pRHSD?slUY%redv`w^ap_`Qz<;zHi*aP?|GO71o=z=b-`*i_pMp`O8OLq_B__a2;Eq#`V|4}mJ^nl_qoJ{b^~Qp< zi&~>FQ#Bc_=((Ja*hBg^uy#=JUr#p@0`XU^W~ne~P~j+@n{J*Bn5hJ)=1 z$y*&~N_8LkWkI*drN@n9IA%Vp!b%K@YtT`5pLXAyFfE2st{;#Ifj}czL0qv%W8CFf zNVd-_zj#N|`xLG#zYdi0j;L`z7R#ccUq%Y@mc#`1`7--E<2@HAL%#;dmb`gzLOYRu z8n347LxLgO%&IfEfqcv_-VJNXEclmvTthT{8f2T zd-G{YL2Mb;|*i-IZffy8~H!IlP1udC(2ML?SuiQAE>9 z`8;1cS@7OQZ$M)=)s-*tT7vzYCE(WsHT!1IKqNeWt)(blt7YmxX~ z#_=f2UNYbS@ARIAux}~<;hqRAz89T zw|uB!LfevM0Tf8=ga^;eit61^(STE7s<~!$-K)#eSV{SLvWhg3h(C~W+!R@N`v^vc zQ=bE>d0v~$*FMss$8i?EDy&Od?WgaN+Jbu;{1B)f6;&Fc+~S41g_;qA9!lMoMkzJB*McLoBPrF$&2f?|df8I6rXDz!I4H}(PtDNMO2L^QXqO_}eIaFVe+$%9 zoETTDoKdizS@Kt}h&bG1{=3Nm?|LF+6QYqPPS5kev)OgpHzvXvNlZ|1bsRd;G z74#KD^}uFR?Y`CUJh z{c7*&wOT(4Um`%PIPW&vBBV}?I08u0&b!+qR`sShn2kh`gcPKbx_(<_o!9BF5qbVz zd*xvq=^F~0irr#QL$u-K2fxt|;(FWfM>qa(9M$GrUP7?Bd5|QY{zTrVKh`Y;@oEGM zbT;rgry*(|&Lh}zQ*$u{u{+i@3WGisVF><6y-qpVFBV655~Wo|a-fi^Z?an=(|6B* z?!oQaEE)>f&J=rL%FMJZTVb}+UoTC#D~)JpKq8nfBNXs!ZnCa4Y(#!^o9&EQBFahi z?_pX1rm}FK*bISD=S0QL94|ZZI9ctY>l{4z{;5H0IjuzNiAdZ&e+b%oy&?#DIjI6- zru~SlK>sEH>R7qH<4j@Bg7ew;J1O|2It%+4eQipF$=3HhP^acSSeS;fQ2*dcot1+F z$|^|~JQmVc^zg4guQaR)blX?b3Y%;f5sK5W&!M&o7>dmur1 z+rgh01Dfu6ikGW>Nste#F7Lr=1lNW3tyN@=KlIcNgM^pwZV=Aj&LdYru%A?1PLM(k zRS6Ymxq@Ga{zf8dcvhpez?!8-))0F#xrvs`4xQt z;rAm}Hf>A&d@?foQcb02JZ55;eNph5tCOR|>b9)va|deq#>d)uy~{PKBcq`3Ou(Kk zuvG6uV{-+3(X}UqnV;M$SH+$XNN6r0P9RT+j_`2~9mGjXc zxLQ0?3Y5BkH=M?zG+;CO-}dkSfAfG<`^C%eS7Mlpvt=*w;wGIW_+4h{z%osTtyZ?W z0udw@sDZ2WRp29bOxRq%DIBOF`JTNf!bS?8AxhSFjV#prX_QUHgn8b9!RMz@E%ibJ zIw&L{7PZR(CEK>uur-HPH=lOmG=Na``v<{E79tPxbq{1 zOAF)W%al8OMc$l`m~j;9ImIi-%GFLg_!CBK!}DySztAUEaUZgnEzUG>dTEEMJqErA zvRYYZ$}aJUWq+y#xIR-div)kxQ`_pO*llr=X5 zx_fOH4w09trGApU=zIyNIrl0HA@IJfix`qEL8!xAYXk%=VW55R8B84HP}oV*Pdeek z3Ov#nPhWY0-GY@9c$kV}pS;WVftt^*ZjWc``_^P`M5GF*G$BBJ@8~Tsdzc~n=1CR- zM5}43-waAJZ)u*zVasP_yZbpq0XZNH-cya#F`m*iVi$4*zmMIzlWF^D+wbe6k<(Ze zDzC94wD6XTYW6*Ks^QW03}3&vURWwF$v8%m8b1qo|AIavRkBjjilNw0Ey&}$y4YD6 zSdFa}wKUI8tnd30@enpkAG$*mGfWdo>H#2eNE_0%Tbd})*?GYLzTfD~#LQaMC<*rM zJ5o1bDAom$VgEYh4)|s9kg^oE-D&@{URD*?Daa=FK}e^xO>t&Ho~3~J`>{@Y8t#70 zxyn|}pf|Te(vHVoxO*>8E1{Sr=C^~g_mbO~p5NoOd9&o?u!Ih^*74hTzrOsbx{Z;J z)Q8s(p6%4-IevKQFY@R){7_@`A!qc7YvvDwiImW7O|k_)U~k0$f6Si`r$Q&>(0%eK z5||KTqhUwBp-^m1&EE6w(^#e%(O5meFm}uUO(>NkE)p8j?QybM{a|QTHCA|Z$j96PbA`Y5G`Ur+d z(IM~?|5;Z2%FZP%g_9V^{q6itkud|r8zBZ^rZeedFU#2Q8?FAuCki1QhcO~I#Myg@ z-U;CA<}#pn__+LdPUqBbr$JM7etye;Le9Rxq%-~t=7;%8#dsb}DVMX$l4a-)AZEcu zGM@BeOKlS7rG?|DePbsvK8GUP2qET%+2>X^6$d?HyvfnB(H#Ru|20@TEohBg>W5UH zdfA>U#OsA`CeG?rZ2>oTNcqhYTFm7%4|?1UiIvp|CVi(a)juUJ)txNPt#%IsoqKHi zWo^M0Gm6UASBF1jjE^&{=4pCjI>#BO%em}GBfuC=?` z*jBWS_(hgLjFVx;j5~mn5nz2E!V#Q7+;D=0y)Nu~LWc=o%*1e#AKbtfkXRqi!nfKn z)n~pk-Bp>t_24=qYE;=%$jq+bly0RN+{QKgoPAHgAP9^)s>8tHBN-12hRGr>*PLFj zf~wkVPoJ^6nk4e1YnbWcaF_^^!$M*(YCQlw}xR`zT`f?8xs9 z`WD2NQg27+_3HA!NL7DPq4Vj}{mketHcZUaa_M5Oht zpoLgki6@ez0H}^P;ol{9E}D3a=+h4>gZwJs8O|eoqTy1i8zr52b zjSfj0eP}2r$L^E_nBh7jyCN5HLI}@CXAh0)cYD?VC^{yTO6E#>4F)@(2iPl(K-1n-* zumDb#WZwL*nT!GwFo*-#=Su1I2&J&l{6(E7JHV)}iun_)%VZnL%~cw%CO!*DTzA=a zJD(+Affpci|H?%1JI$w!AU+8DdSl1tX8Wh%Uk@JcGr55q(kT^IahA$7?%mK5q>a__ z+sen&#AvxQ&hL^QvBpKF!(g?uTx84t`H4=?*CDCvUY_6&*I61@IoV5D?^jefpMzuJ zmM_Zv;A3zpZREa|5duHL1=S8w5)~F(4fwsW;LdoDq$mwobXNzqrGdI zi)<2u9PEf=OpztLu_oz7(vjC!Qm6rGY&RBEj^}+Q7Sk64fFGl;j%|P$fA|I+%S9C-_mG=6nKc~__vTDi!Rk5~n^o|v(qR9xBR?$mg=a_R#^K<#Nbp0Q_a9NsA z1z5D~HOFHMZhnxcaL=mf{;t+E!bQj2AL%1=?ov!+hn!<(z_2tF6*sJ1Ejo3ubFB^l z{Pv;6tzH*v6D0c3L)=hH8j~4=Lr9bx9mE6uhb!OB_Jd`vzwM#XV=X?d9bIB&kqmrf z8GJq_!Sm;Jzg`WeDk`50Q+)<}E5!bNTzqtK*ggWDPxCr1Z!%8XNZ&BaJ0;&kWi&ID>$ZFZA_@!pT`83_acgyV-ZsK zVJgME>*meJk~H0&U>->cOtd+>b}f4zc2Vz(Z!`w$f5}_pzB5D+jE8=*92xIjNcbil zDwj^QXM$;L@$;AyAp8vqBUSi88Z-x6eTy#7T4J;R$+h*F!3s1v7RgtZ3rMl4jext* zKy!72)$t1g+QZs-06$^wO2FFq0y8TCPHpAiC*&GzpkeQSmTxdW$-_3u3{s0m22!91 zeNOkkAbX&!0!11#{Lz>JloZK(CZCQI-+0Tre%hK|$y7O>7Sz6$V+!wF=(9A`5-i6= zy-+0hTlTqGLAKxxgv0{=*e?E9y?2@^n~$>PKd3q>easWii`m9E%7B0|5~#nu4Oz5x zY(pg%>CL5szi_3H|BEIFAII}e=YZ_7ttsV7jfgzj4=>^W$X;|G=oPu0_2Z`wwC z;jbePowErW(SKu!Lv`>te|AX4TB->C2jP|b0F2}x z@cQhd3y;&qe}4epuNpJ74iis!88-Q*%HGwFzsKq^C*5N(2%w$;xQAk?{`*5{O1@Mi zfnza0H|4qK))96Z`yQt`p79yK#&{^-CTXzCSZn!^NeMSq`$S?M}{Un3U|OK!xiMG0=!cLd15yZsdOAwOJ^` zaro_I0G z6iJ#ZlCegA#CQT-qMp(RUwsSjpSwj#x^m>`{HJ0Ap2fppRb(Xw4>v^vViMh;a=I?? zFUOJ`D69pf9g6Y9(EzYBS-z8Qp2?t$D{N;uJy$p*#cp&94&r8^#1P$>hPJK^*vSMp z{rVGLb-FMw4m*9o>Kv0Egbhz*4>!HI5Ru%VWXEa~10pmC{N{CTOC*Hdtcw&$upb6F z_tu}hCv^ClxFwbVW5+1cw(HDmffdhFelb%*m`(%lk+r0Lix%ixKH)uB$#A}j{?AvY z+0x@ub~gAKDszy{?t!=yuNQK%a#Hy{`Vf@by=A~f%%1?Ci#a!b*nbkM1Uar_3c=bt zIP_8;h~kD8`p6D}DQ$O>)PhW0hErm5PFUH;dV59163N~~wqmUU%rEDc+eVy{+Z2i9 zpe0=TzbUk}7XXCbo-<kV|SsmaZrGSlxZq(cr@LlsMV>0pLYk`kBdO|*(?>qo}OWNI!ne)lQt%`1uW zlqicIAG}`=0Du zN#MriSi0jQDB8ZWs+8s0Rh4}kejJ)1Fi&(ZK(4@pl|0nx|s;kBmre%n*U z%+6+qX%M~lff%B`JnFdU964RST*|dJOPsick8MhD-!n5Tu{od$flsCuwdbA?QqtcO zzdSwz!RYgKq<0*BiY<^Gr0_tUU>u|Jc*sqi-m9gqimsNTfsfxJ$n>27Kl_3}Bk^PN zE+CgG=F<6X3wp9G@J;SlKQ{a^MgWSD?7+a(L%lo6^>zR1Q?57oA}vE88FH2}zPO#% zjk^ydMd&ZP+=gDC?5d}SgK@kn4WW9V3Uqn_);&IZVqdhV2r1ij+}alIN5@;<4+D`y zx%uvy#hjY3doEHdlJK3UJkaexO8*htd{Q4qa#!N&gWAp_vT?j@^VZrBMe1QOEpjbd zU55^I<(NVx$!^FwTI<*iMayt+kap4(^*YkIw?pPDHocv}VCif!!EHBN8u1_1@&K;S zbJ#PUuBy(*i(6}}`P7Jp^c=Y~7mZBApRJ5i=o#vcZPsuXFx3V=g2uONYf9YI_QIC$ zy7Io+KE}VqUNDAnt9Jc$;SLP&8mnz#qW9UGPxjwG<)xJmLF*H|i<0}E68{XVH4lA5 ztYNnw(F_4kDbp5z9?lI1{f&e2J+0D7SOA5Zfk(v}`aM;(=dzZjPZd$x8n^%?5$iqq zd^y9nh2~PzRn(J*$*#A@9!M7|6uW^jbLcS1w(`+aWhhw2l_7If44Ph%{lYx}5n_FmaWxj5EB+BBZd{k;j`hntF- z{iUqBxkQ+sx%EHjJTHo#b35iuM3%qys+*uCky|R8gqoky+S4nXVDc+b*G8I-E%75J zYQ+{ABj}IyOwE^RtnadP#A$-q!`me#L%4NIT zUqgokeR44>7IMyOqkLf`fad?6i8}Rt*izQ5-R;6_9^avaGSGm8fJlz8DQJ4IW zUEeWEW)Gqj@D#>@qqA0NOEXmA%$;|SP>Af$r54ln%9oMY!f_M;495U}=ZsFNLIW1I zVCOZww2$69x~*4eWa)kAP$#ZPUOs>(t-QOB?<3;j)%xXSBh&msK^XJ=AH?i@Um_lM zwhQRM318%ANfVwPVAEw#L7Jy1zVf-oU$! zXn;(zfOf2JsUSIOmIy7|4`9ggs**Gj^v(p7iHl97z>LnGD8dMK1{Dp|$bii;D+wqq zU!)>^BqUloq#7^8q!NBuIH#)C%6#=>ayM#{j%a9$UefQVU~HdSoK9xy zS5VqDd1Fas`@JvXy%n?)5_4yeG6$N|#E?k4Lw7rtvt?xl6tt5C;7qMQbS^It&OfM{ zyhG?&IdBNyyh`v4C9oehSHZgK#70f3HHkS}7Pwj_$fuPejS6cvtkQ4)c>ihN<#X!N z_$H9mM_n-JK@?kuk9O2;uUs*Ud^ENFW0>RYk8)3^E6QLjs|QG`c+6i-krc@3-S03e zZqL<(AOLJAO~#{_L1|q%9rf8QBK~qzPwUqPO$YyZd24?LjMl{v_MP0qa>WgL|Fk69$dF1L?fOE z2!CxWy897u+-YtE-7tx>jzaB$_%G$^CQ<5E|AdRkUt85opq` z$)*84z+&Fg4AJowz51LvuQhmXVab0*@;Tiz_kMli()AbLZJTPE>Y1p+xKbP2bMG%D zLAyal1(>6HgnU-&&xKDgX^ z$S_ICL=+f3^AG5+DMWup=^VTVrvt_f1<9yXj27qH65KAarl&NhnfapV%IG<6Dh&O7 z#-pX-U)xIC{n~d+!*>srhDY;5-yc}X^1&`@=B?EDsYV~)YFdAg|0hMI`ABE4lEaF&nH&#Nd{03fO8=>4d)M>m%e=(72pc#p4^!XG#^NKOIVc-r~w}h|yL2 z-smbS4+`<_x{ffXZWCt_f^mLVQM;HNGVXp2+|NEaVCyUAX-^_})zK7bB59Zv6fpWsqpCG`uPTZV)H7uPtPX(U1v+tP49*DYk z!wD3nk}@ufq!MxOrh`rx-n0J%e%iUD^P@e1HSE*j?guMc!?Gkz;RMTxI4?V-AAcY0 z+nhEIA|LY%tclu$a$^54aND=y?a4m^tF@dXVZ?sM*XEf`s!4)pkRrJj9Qn8D#t-{6 zIMk+Y)!G^(i%S#>T&h;Ce5mI})3rnpu@Z?V4K|eC;&KeM`wXhrNlX6`ga>{A(i$oj z%}xrzr&DY zClY<2iAP;-9)J0X_aqoC&@w5I9-uY0;@C#GL2i~FJQ z7p(%Fp?bsCx^00cR3LA3FvfowsDu7NyjNZModeB39omP=y$@SL!+7Ncz29NJ{d$aa zfU1Ylane`k`43w7p|&m4)F5N?0C`6%-?!RC{X8^2UeN^B%b@WJaGAYo(u=j-9gtwq z*%~^JPHz`kjvt#~d9tqHYAC*2=XtDH4e`%kA^xQYRR6^bKpwAZ1kkf#V&)x7obwJ0 zFz-}1pS4ty|2=H*y_#xgxLnmekH?Fjw6MA6dM%J3fz>FVOSC>b-h4rK7RE?70Dq)L z&mYjuTeW-wu*SH4sct@^H~uRtN13P^dV)Row1Vj4fgL?juPI|+} zMd!CQB?lzBf6g|*?e`+0{T|e5ze{Ub`?WAQ9;$mj1^V}{kp3M7n2(iR9E;aT+acB_XHirI<$u9043+t)O=%feO6uk#%@r)scCUGQS)|H%^TJj z^#HJ)*A_$tM<<2y9T;n@q5W6e`Fv&j(dhVzb>9?x-T|@xF%h}lYx+i=nzE+=`kzFP z-@o9p|y<~gH!09cPw5a&eYh;x3aZR_T` zy52wAklys{u76eOcT9OM^7sT{s?Ph3YKfkps=qh7Zj6=RKU`1f#$HRt*`@@^OEao@ zezWTEttaE$HzI0yey{6x1(gM?x7>huZ>CNtz@ z!;)IgUt-n6WEhlZ`{~SQM#m4l@6i!auFG}yJswCf!PfLRP1HEHSF@fVUchwlVkP&# zmeg?n)pfpMsiX96!ko_&feT?d8qt8mbokNTXIaD7ReRdnhGFCC*LnygPnqMaYLF=X z*EMQl(@kqyJ@Zo1S=#UQO+RBjOX~4@6_4Y1vDBo?8pZgtwBD2BWZ>!5JdUk(jNYq@ zpR9%AOU!w&M&}!NIIT*M{>eGDcFa>I%=K?|@{`)WKTzFh0?jX3G0rzx*4o9-hu89X zcU2u-=a6yU(|k@Xt*_C2s}c3=+?KhXOU!tvZR`E|ipsWY6SIHfLfe$8O}{S`N9`Z< zu}9~>%WDb$)sr(#zF#-_dQGis>@n5{J}(XA`2O{D9y9rQY}lD>j&~DioG`~Iy8SzE{NW<;21q^8s_dI8^q`(ZDv>-^Ie8k%yWF}z*J z`5ahhov@gQXZ;4t14hvz#`l*%p;5Xp^$;~HKkS+k8lJ6qB|+)5(CII@z2R`1rE>l8 zYUAqRKQKQ5eu8$5iEUo3>hgB%99k}bd$bNZQbqZCxzO-=OK6xV+@OU!>-hKu^xoVW z8rFBdv<-^qjg2oIxZMC?w^lD}<88~7%FQpetzWt!%ELkNXSMpLSxi&~^0bC!py%(8 ziA?V>TI$ea&oQC&M?t^O>rxsv8x|U$1rfp>TDTqx0gmXz^^l|U`@;4$(?4)Kz_`|c-gV{u@E$aGNIc>;`I0HglwLI19=B>jPUU2o8EZI|ZA6{r(IxF#d9 z^gwGN>R7~h1Yd{G8+CyAugy|B%LB$e;QJoL zd^Q%bAYWI_@(5_RSod*uWkr_@a}fPR8B8DS&&GPb39iRl#Cv-FpkXqzM z+69F+TIkZ~`C^^t04L+TKTMA=Jyc1%jh(rX*9Gu+YYWLyFn#Os6VRU-8vptm`hBp$ z@euENDN#sGP=4|5XX)9c>(RB|at*%c2JV-K6WkB*^X3NU(V20U<2!@rV0UFzj!x!7 z6-$Y+eNgm~WRM>{tdssHEu)tQ^uuhObh>KcBt$xQKp%kR?Pbt-a%*9>7G~D+@@&q;0`AjaPggY&fBJXBe~da?SK9IcfbxB+_E61iL`!0l`^IF7)529?!I80F{Z zBEIXL7GJv6We56vCFi5+f*xI4p!U`qf1v%pw8uA(>irJmH->e{C-(pvxj1y6m7sm)9Zaatf6H z7>F)oR1;ffXbdws#&HVI`|In1<*3kTi$2kw%b>2hG zw^=%IqjE&7<*hDEspLN6h_u+~QV(1u>w}u_(jmG_H2)q{&HY?k&mkD~!`Gya)F;;d z(7Qj}TF>adwzWTs-?T|htXyAH;}n)dZnc=G%zUGVc<&vImA-0=Uej){UhQkC9G0l@ zW}f>`%=*+)P3!3T)?c zB$S`r4p1D{QyD#XQ&a1wSjVZgmexbBoUP7sdao~XQ&rJdGE}b0$}h1Zr;f;lHQoMo z9ZBYTtw#Bo+0G_vGhM_>=Sfv8*VPyKp{~(ORok=G*82u)+kTQcZ zDv1mys3QIOGyhCIX9%6tsh)Odds||@LpQuV*#5aKuRPYVIn;#}8a|&Q9Zv5Mr%PFJ za2$8h#lgVnTbug(qK{2hH$~kp*)UkK%E-O2RSXm5SsW zrTFp+aO%V(U3RADgqOkNQG9~a?eLJCpa_B_ z6C_O>{&&LlbjDj*Ag9-?k;Cwu(u4Ou)%AAAlfZ6#Sa@w!w?mR>T4hCykQuRA*B}4e z)F3Sh>@>&fK%+eGjNpuR&(HtpdoV`t2p>VdqC%H)W(-jj#qk(R;g~4Clzcqdx_e{h zIWcB!i!lyAw^h^gsxk_mQeiBmo%y@;U%c&8Uf!&rYxa>#a*jqLSejrJStJCK;Tf1< z&qstX(PRZbzJ5>3pDyfJp+@ETxD>&wI6OQi3If5iJcY>)S@HTj1;tG}UV8MS&0SJq zszp(6mf?AzQ80VK2S492Ave58F4^N?aYw%3Q#?+=<-A&P%v5}xKeA?TJ-RL(m>9gN zT{ZDhTI3MmtJLTN%4TU2Jm6i}E_F{UH0x5`4pCrORgo!4QfZo8e4rwW(r(o%+YWAu z$g4^4+gBHjePJ%hX?Mh&C`_URmY`^r=YQK9{NLNlAI{8%QiKgw?9g*Pf4O=N4l8R| zn1gT@Z?!ZHe%A4k+gH8_X7c_K<{_MB9D-|(Q0yH%SCD+e-9BZe;`w6phz|Yk zT#@uof>_GgZeL`=go)aN%K9DG`##m+G!w4~mtv65>Xp-0$NI;dAF2oCB1H4xXTP=E z{aHE?`EnxbFVq6hU_r`r2ox>LG{x~WOLXt+zv7u$^BTcMvl9_k$?)@unblL-bxo=! z9kfi?BDm_6=Pv8;N$+r(5G+qhg);`j9HRxFbG9;gt|Arr1kt4o6r?=G;dK?vIeOWW zgDp3$ZUh9xQ`YEVc<;6hHs0cX?AgY-;Yt#(&!b%BpfC(4cpfJ?l4UuZvo-2DVbIjC zGC+OaX;PZ@!RDwea)Q=1E2LY>2M~V`z(zL9!>lAqL#|7Wn;nTnq5!c{N z{4lKT%~N6B(XdTvdi`@FcZc25 zHu&+KZx8>t6EX*uCK!stF@~oIE4ZO~t4Q>WK-`bo@ z3;{ZL*RYlp3lPP$*^t@^HP{9O?v=E)3 zOk~*~d(aCn3%-^G#Qb~V%b>OH9Xd7icd(3^q3r<=?Hl=d=e~)mTc2R>?EHeu+5icr zyFFY+q6pq0%n_VE@4!5#OP-LYxJy2wSByCDo$Yj9*U;LLL)a%P6&MO7wQT&9^72gl_xm!~9yHQmoc zL-T^;!=SvucWaw`;Ow*b0v3ovzjpm_=bSEErh)j4+ovoX`fkn!5bqbftnU~7hjwos zK`3)8a~vK*#ROR-F$H7suDd49|7BD220$LV5U~(NQ(XVxt1mBFn{ot64kUr&B+v0Y z#$!B(g^|O*n#gnrNpTkkx4p}XZ_Gz$!7wCOLTW6=Fce0?SE7 zX9+iNWH7WCjK@kJ?R3&@q|-l*pkZo(;(F+0r+CIG z-XfQ8uuI9$p7VZ@KX;@x1rn;7##v{pWqj~z-=}xBSIg+aA8&t6CfI4W zCL0SamdNq$kVpvYfU?UdVM>twXZN+YZj2!JmzP)JRhA|d924*|<3hMeu3Z+nNu~q~ zw|<-d{P|H;Zj8dPGNWRIAjxpT&5=ENS@8X<+T1U_3KRpo5h^#Z87I;Tjj=Q#)8zRh zl%E$Iu!dRYRW<(YUb*+tTDfV#8=WZ!?o9)Y@epEb+a>r$355=kR7iqTNJ*mjM<4j} zv+D-?!VFLs*U*K#j6HH3^&G~|I1MYtS>j9Ybd33d_jejrxn3S@+3xwPmS57*68baL zxyo$CQ|zD=T#;#t#2J~oW%c1V@7w)$s?jSV5+x!us$!9&k>T~X5L}k@{GQYIMz;?Z z7+k?QiJ>uEgpV*Rg7Wer7?KeD-wXZjeLDG^@JTgvr`0WZJOy(c6hjL#j&lktgl$YG z=}u>AaQ#Eaih4;=`6?%in20N~AQ3psSJxqvo*8WY!0Bd3kL5;C1eDDQtjh6^Aq!q7DUUodn18980qt#*qX@<1lGBG&ZFo8q*zo>)mgMcfTkqVbGFHaT2Cb zEE%@Pbvv?`3WHf|j=z<%wOzPaS7F;u;7EnRC6-tCGr~>wH=W5lru}12fkZfzCt8Rl6dv@wHoyhu_Q%?m0J z$OgUfNXH@n+>#11TxSgpVQ|(^5{0{CEJCe@il-zvo~#p3N^sn+6E8pb;|;c%X}jpz zP7(%3Z9cE+HZZ}?3SGp*ZLT|9q z=U3iVw5v0E^;pqlNoH_X6ey0C2t4QQR)f}V+MWi8>4}b^-F(#(#$?)Zp63hpnBVKv zC5-{k%ZtSG2vuS*Md4KmS0gUyc!Qw@5l4%LMZxp&e+E2Tw$$DjPK@~!%{hd^Ld7i) zDs~I`PHA|4VS&dtsz5GsDc&9p7k#@m^~NM%zj?5h+EIgY{b3J{C%U|UTaEn=zxQ{7 z#tm9_m=k>B*o$8*{2dI82nScS9S53pjGH@F@OTxEqp&3Cu($a5$p&APZE&G{G23+p z#GK$!{MiLBy%*ik0OwherzwVGSoWnqy0!Xv=fWglXppQ?>R4zSYaSE=Ea?%sL>(-# zJ=fQY%?+~I``gUk(M5amJz5AI?v|Cg4wc1t6~`Hh;*`wGCV#bW`J~L2i0RQtuU7>c z$N3(LInNC?ZhWN6+GnCJ4roE7d6rd3nIYlD!LJ&L!5hWsjpO3r(+xU(^;u^0^$5ue zqCm2;po(yoNd`rL@+_|p&b~eCkrPEmk!2>gcw-yK8Jt*-5UKn3qsD-11i7p(X%AzBtPlbe}w_x5P~4$tcv4= z$TBG35Epci(nX)Oxg+@6n8Sbn{vu#24@I1QC5FQVj+96Nm&dg}`at*Z3+$jx zW@`xpTmEk#>1mV}F4YRveY-Vc87FH4_I$trf~D_?4N9Z%$%?O9pm^=_VE^_jhU6%% z(0a3y6Z||TtCUEq3@yMa5nz1M3(3##4t{dv=+MLcqiX>f7869Az*SOYQ}#?-l(T7d zBf$6ceAkrcb#E}U|Es+oOG4W@(KLZk1V=DD$zlWnSLZ9u5M;$UC|>37}^ z4x?eV2zyx=>zLzl`jiRET;Ev1w7}K_t1%VN2rMbIzw@I(6@);t##t?wo9%~yd@NG zp%ZVe6VKL(H#0bNtd>>5+n>DW(Nq0_G;lJKn86dG%rZRBC_-d4NN0l~sy{YDvIjgV zHGtw7IyywX6YSPF<5tT9!C@=JX?v#wDKRI4(Rzuq5>;_a$~fh!BE{<)?soc0{b`+k zY-V!O1A^@eOWlH=PSuj&-;KVPWHC{ffL>!f99)!p*>ig@1|z?)oDa#8gQak~)fayp z+nOCV^xw5cAL_B9T;6*m*rf4+=AFw-Xugb~DhQYC>`1x^$Q>Gw|Kmd^P5r3Ua|J#97G z6ORS=1ozQ}+w~m#VJuH$j3hBavtN6UuBa9T_#rv6fPl_>bMT&v+8sJ}X%wlSzzCcp zF_xeSj$>e{|Lfw?@WvEW7S9CVU31Pf{L!d-FhRm)nd22vBotT=X4Lmzd6v%x{dWv2 z{85a)Hlry?CTW~zNST72Pad-B{7@1dWFoK<+&iS=n5k#kSz|^n3&$X9u)KFdyeIhg9J9`aDIFufQ|VC3wB_>BbjS^y0eV8%;ZQur$26VdNbB!3`T) zKhb<(A9Q}2sK_}cc-ira*Xt~BkM$JH^a%MSC+CN{3Piy*$SKTp7kGV6$qU;lS`D_i z)e;C=-n=tqMAzs>-#AZT9M32OL!*qoCv-q%u`~FtZp)Dl5C?|S%>HV$;)CqvUm+iT!#g`W-50njr-N7sOP@7M`*A3lMU=343 zn3J6zrQ)DSS|1os3>(*|0iqx%YY9F4ts^(?4rY$K@F&~*Wui+;bkRk|2wY`3l2b%! zUh(qRuYW%4owJ+;@6Ir%ArrkZ zm5j_{Z?NI6T~wQUz~QWoNyzD$a*T8hDt0^a6|YyAdBzS&@eEU3g^K5yo-Z^=dGK9Z zaWyp&ENG>~`8?KqU~_&D!m1*@u1yPDFNB7ujSizSxCK!jl!cm66_2fk`qxCwVh41~ ziOp^+x#gsc9Kd*bkty(9yJ5v>xZjcy{pyf?#OTeU{lP73 z%jxOkV8gGzpL%FIV5t$U4pfH5X_2H<0b^12Y_B&74K0?)aXp)ZU!k(6Kymm`+ZHIk z7K%Tp6Tb_JFNWf<*Up=u`1MfS1I6>9xD3TbC_WvE!+X+`q4*dmJ{pP-f#L(9_=RPC z@k!8r{gTK3dlB@={tBd^xpVUHB+g>2z%UA~z)qZ=D-I1kP|rPA92+GB&I^tI0CDsC zA*yc%#j~LJUr>2YKyi5M1U7`a28z#x;zdxr5Q^tPaS@6;p!ftR&Oq_=p?F&;o(sjB z>BN64>x=!t@xT6lU*rAlqG)Ico^m+7<9)KrDUMR|Ma7fdcEa||+fOzGyN@%K$kSD- z&McN%L$h4@fyV>EpVxjmdeTO)0E@82Ty{Jb!&zG3Ws0UGs>N@4*_-y?rK>Z$FgGokCJ9kAM`r8`PH^#lleAv71bwQ_fWRsg_PcVq4S?OJ?YYG}Q#)23l?dTNQ5 z?|w+&GW(%+^uttWtlgo79r4oelY2_TZ#C9-kO-{@?C}TGhe@lR^dHySrxj#9oOh0~ z-yZ^mxUe+A7c>Ic-oYC39K`zyq2V{$e#6DxLem?h(ShFY05@ucSq$Cl^0Zcrt+vX& zZ(NsjDClc;r0b#`*E-S-#TP>9 zor`!6t1^Au=fURLo^?NwI>$T&o}qC`z&MhfnRjo)R)3vNhVQgO-Emc}5c)DW+Hv#C zzwd}{wj|>MEvpPKNnvJ7=cj}=7h{Xu9U#jugKN$U2A^Po5qesrLmxcla4TM)B9Hgw z`$jswKJUZRp1J*!W*alWy6S7qXr9pM>m`kY2@v&wbtCW#F~%BNyi?jAoo%7(wxQ5_ zJ2fNxp;}W~rvBRF%=OZ)!ZsyeA#<=X1Q!50^H{V2&E)iVsMh?GLfGOvQv#f+}L!n544NCp3GZlji_rLG(R*x9a;)Z zFNjZ9J44g#IFpU()M4m-ceVq4it|YD=nL!r*giAbExIJ`aC*lnt~2+gjW1Lrr|MKZ z*S)mw?TU6!%lB!j8!eowg;!5Njnwah*V%vXL==HpWPgObaf)(CC4=;g8_YAl4sQ8; z@vLXhpOp$uC=m}wuRN{&?$M?d6*@-zR=?2q;P0xBD;^7GtUW2Vx*Es~QzFU?6e}?* zrm_OY3d9cUQzfUGV5ND}rM8#}Bh(VPR)2S~>kyQP7G%k}rk9-V*qHa)XZf{#+v z7Z_!Hwo3k9+v;0e{ZLsG^qp1bd0nB$_)jxd&vT>nR8{`bOu@y3iTWU5|1Zeg{FU#c zXPbr#*k%4fojwQ75c@ZC=jBuosKH@Fq0MiuEZ84WLxi7# zh6!@C->{k-_TOlY97jDz#S>i)G`ai{9NBkfTYH(e^tq9E4oOKk!DA{XkxKJ_roC_^ zd36#n(Db)Y+<6>Zg}CSuS>u5`0o#se$uTw;B{xr$hgt&-pAjoOA)tjnov`B2!I92&l(4e;h^q0f!t zxHYs~aQSSA`l9Mlc4w#d#}F;#weSaPWV#z=4GmHGYTgFRYy^LUe%}Yt<#20g{E-;@ zZz&W98rD(J^CenHLk-ePC;b`L$m4iA@Zt~T_W!f@-0@Kr&tFL+3B83DIs#H&FCa)S z5{iHnQJ=3S2ba5ecL9Qmh>9R6qS&w@h$x_hNJy)Cn|voo`^v*z%^H2^DuplZd~o&@N$B<^Yq2Tr6jToE6Vn*c zPE;Otwy9grd}@?@tvK`1ZbM3rvR+2J&Bz*M-8l;7TZgfn#e@GkQS`y|a^}PZ z8aAGHnym|W@TJ7yG#Zq&;mocS=WqFmdn3AuQVd6Oq)6imEyMd+DDNYS>D;bY)<0KE z>lD$vsL={fixe(%q8Qe^*dR&@*L!Z)&)vry+T02c?NIOtk_;(~Pzy%86xB7#=~3N6 zuIkBgDn-{)kJjLhGRY_$p5HaRSBvYX-rEE+p9Oi@;f$a$RF=(?x@_A!i5X*3QV_&g zR-w71Jy!33OA77Bf6IWxfg;3vM4Ll!ahQs!I3bFJB!7Eu{GFwvoSmx|J`JrY+550X z>!VC-i|%<~*TkmG9PJVq3>OKJAuy4WK7MR`-$}#2HixXFTyR=;B-HXAdoF3)&_$8M z!*UuYW1>t`8qWy+Uflv$SAse8Q9^uHqmsJodoj~E_mGLmNVtSXk*vn@7$=gQ{1axE z-o$;SbFgutPn7DcriR{HFFf)~hb8FkF`gz^jwcD4V|favU{;leSeHQ+4ZYSk@E@u*dhZ?j%Dj6X0!zf4 z$g#*Y4I?E{)ihS5=KTJS>YDRnGT2A(#CcK{obv*=eAd(bYE#p~uV*a8OX@>Q(uzU4 zy%w@N4uI<251k8y;mIgC|Ll>-_CpIqxBv=u#`C6Le*ekAzf*eJ9HNEi5OTmq2p?H` zx>M(0`f)?kAgDiJQ~0CWvDtS4XmN%wgtw>l!!xFpdjH0!#a2!hBzI-SXwU18cn<8_ z4xIrcLWq4`Z{K}7ew{JWH5iWb*F}Es4Z{#;fB|KO5}CY_7Z)C9_vA&q)LX+jjm9vB z79}?9rQT+9a2m3d>d&7=w4;%?Z_}^(_IwO1q5lhWfQ+Je!R8)R;27-ixC+LIHkW&R zL7uwl@5%o+JnJ^=I7C;|Dj0QXRXkK_l~hhzCAA~1oOx3je^09>;}xxbwA*T9FXqes zwM}t2!I|NvBBqfF$x95wVHAjc1xG&O`?m;6VSt}=kYEc7(sdz8eQj~`n|hZ`eQ)k= z94H!-!Wj!hoTDU+rzle5ZaMnp?uR#DTL-AloA(6^AhB*N!VILTcf?tx*I!2?S}hbp zR55~QB#C8UW&U<6N_Wffu3xaP%MHH)nQvHV^pjkg#szo2}QArwXitAT=Qi4QZPJ=V*797}j`Gw-e6Y1!Kk_$N+ z`<-q$Xp4+t(A>LrfA)mGT7s>#`DkB$7GqeI!f;W-E1e?}U3FYrJ@OME!{;DNa^2mQgSQ<}~{m z7Ev_eW&c@s-#uS<4Al`!GXh1-^9a1Ak&?tqBuQ(6EjQ1;^x)VW=7yx=09~#71g{5h z9(D0eyM_J!G*4XkY;Gc8fQ(n#*J+M(c?1T?FeE`@G>*{>MY8Y!PS%6v&1@JRsf>5@ z+(G06ha(&y%cU?Ta7BPK+hLofD&w3k&j_`^-MHsVO9pJeHK9k0RB5jwrc*c0_opD9 z*Fv09ORwTf8Y!ImLemwuo%yA1V-}|$I%!E(@K+9i_$aw!`Cp# zn>66A>&~@}yjYU7tWlhd@jNEOi{+ZAQ+%+u*O7a!yS`pzCjg06NP=Vul7pQ9^4f(@ zL$Ni~d+#fEZg_VJ5?d63Qx_0LFgVGE9L~HerD&?S5eLSGdQ+SI`Qd9HM?P~+V3>x< zD#<9k1aqscDX6wz&&ER~%hAzQrRl(ufhP9w9aIyT|KW|Yv z<(6=hEU)Fvjq1y1B5@N+!&zR_Btld|xXIRi;nUEX#(2Aa_~3IlObiogvt+VM62tK- z&Eo{iH0<=NP}+YcvunJa8|!`M$d{?jdVx)`$3vHHScin%sd`MvMu znn@S`yY14X_cUY5UleecQNOGx{;+7IF$R?ZKkDhd`!cIlyDFRSR@AzAslelgTbltD z06$!0HPvm{K`%>rE7tYvi;L90nyN?CRDH#e7b{0jG~n`r>ZTVM@>0zPu)!vJr&wOe zJ-!$0<;@53Tj`xiMq?FDp*50}6mSepQ2P9S;|~)@4JdZpY6GPvL>>k3dnoTd_ZteVc zGMH`qezXLoFaVE;GtgC%q`rMRBTDbz(YG@XKN0*KU7mrAdr$wY7C~a zDn&1N^4kxdDBPCZ9MM=1w79D|^6&8i>bo5kWH{InW1M}f$?k2iO@4J?L$u=`!%_ss zQv^# z=OP~ee9F(88Wo?(cwKK|J!|DKQM>p1HDmAYGNgGZ6D@reF~KMz&d@X=leUJ>9?jac zB^h|y&4Eh3K~MFYx=pR1w4z#WHsyMMS@+L#P2U6)U{bgRKxQb0#zlfsF%oqSIoBMV z!jKyyVOdO0@3l)7JpIzANW!8CmY`^g=P{lmd1O2zRHvQZKL#ePD(D``n+@khO5rq8 zVl)NzX1jH1aOzu(LaxjE)utb;JN^U_W5R_7qe#J_iZ0dd8Sa=a+HJ}hQJyAdtJk=l zjxnMqXZsmqc5!2u4&X0#j&J;;&{VJ=pa~?c%dbXUaHnSKXeGP9@*2 z25umQuQgd>jSY_$(_P-{>t_#ME2e}l9EvP31l|0rzke#VJOH@1eXs|wzjnop>|NgN z@7+0Q#j!AGFIgP|H->2>$8f5m!CrFdQ7W*S?)LT^^7fo-mVg!L@vtipjbSV&;gZNO zMB8=d!PhKXlnDBGRjc3>0Iz#RJ^_hZ>E$GQ6#Kv1d#w9l+q_fA;CYNlb0nwXJf%o~ zwHv$e=F^+g;2YikjgeOF_8$Cg**{WMIMQ`%6i09bAGr0G3q4t4iCV=x?}|Aa`;TZDIjAVh@iIv&1g4UF7T%`!2b<^B zPJ%R=gfjE7`QE3eK4I;spu5R49LC`|MbRXO(LCJExAd7g5Gl4V^zPoBIEH>F@}Urs zBP0@M2|}SlF5-Iwc|XxZUUh)`&EYgyt8&6gL<%Wl8jq=xf~h4c@qLeVem~$zoQxPR zO9f35i)pF%^VvIws{;B!8%Yx^hSLm1aXd+duyR}%Esr9GajAFl;?3qy`T)P%^{Y(4! zr%J;5F8AJi*wV@;M~nk5(hP-RIK#@g95xO(9VHE=*%jU%-B;IZ@?Rt^U&Am~6&XzA zG#1wKS6jlTp*5}a9?R_Cx{0|%s4xN_d1rW1!*NDaD4x4;dS>WVNT$LjnW@DW28(l3QH==$SbD!Pqe zlc4T5y`Rp@ymf!~HV`30yEJZRt}1Xe&Tu%1u>>Q}p4xXVePB{*4)6;rA z@EyA57%3lyjtKMH^*YAi(D!|hK+gT4 zr?)`u0LS6M{_qIs_YsCFTrEJU;&MwS^atMVv%l;)>%It_iy;F%gd9L@6#$1;3~@w2x+vovHC+r77c`0}7@uZp6&ZL&jDqJi8&a!Mu@>V zhQ?`G#I0vyyQVv6mBS;yjedD3uVLBU+sDFGlod*U~Pw0ZYxWVtefAy@K>2F22 zi%=Ma z83VW7ILCQJkD9AGJg^irz>yS`hF0>qcYglk-)}tuB$aw$w`e$Aq$EYeM3Kk;woh4h z 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

    ?@cb#d=SP$whOLZR~aTb;Ya%6ZOUE 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�AB~4Eg1-OKvnr9Y;Q&bum%*bh5 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 z zrzY3`iwFQ-{D*UT73=(_dD<`Qu-Z24GyD~ea?{sL6zYD+Bf^E$4eYCu5ZN6Dy(HAj z1>K(2#)?v6rKepS=Id5G_Rv6!(xXgs8T`WwqNAOy zgHyq3?AVR)Jq;-F&Lg7>DP>zHdD&{JE$ZBp48PR=hZh1$&fL1C71Tmn>gg50JdX{* zHvd#VfuS8-%ddO6IPWR++AJse;W>1u;=-)*jk*dvWc+m&Wa$zF^%A=%eWRBcPF@C* zu-UeUY!}D(%=*igQDUU1L`Xv1#LGvMRIM!yf#FmAg2-(^##!aH(vTquz{89j>$`95 z=W{9H?r+=?UuRB|QGx}i?19eqip@m!u_4DPbG$33*ec{6UsU(q?g@vqiSxASdiSsf z<+z#UX>rHc+dL3hf41wN^nn_03cMF#9;{Y8EwFkC@7(QmQV5F`yKF z7h*+R(jnmPEB?y-nlBD^S>3P;7y?eDlf3^ur`i2nxD3fewA10sN7z=pX~9xO7Pp`5 z65vt^ni^63S56TI{_r~=+Y`F}l3bxK)o6Jk5tA?nlTJU6A94Bv5XJZQg4+G+2<8&f zxk)eiWZ1g`3G754NBcZ<>~==iLEKrt7CJE07|50749=8-bZ@joJ5T#Dw<0Mqx(mtA zzn>Wx@4dzvQ65!l)XkZjLxp)TY;5aOX@mkGOnx#ukJs|m=}-L0_hgC*cqQ-vmL9Wn zZ7p#c({4YcqeY^D3NWxOCuWaf$0C*1@PR`rXOA;%G@S?i{y zWbys6{)d@7wQ6?&H#<%|Vb8(TQqUQFdEenhT?w$Ay}&70dC4Py-0G-VYvJJEG^D9Rs{@QR-irVQ&km*7XJ>pm5 zxK(@a#`IYy*(G1^k2ck(fI4?Bb24`my5F<>0)xm?#oK3L-cz)doa;jiFtbsmjg{;l z^oQPFxv3Y459->MJu0k##LBJfWND>K4{mr<;uRIT5w279WnJ`^z7E9Ey?0Q?8?n1= zjYBB)(#&(Agc7*@FNZTSHdH%G^ys{7<6_=D!bSB}xIbu#WFJsw1hlyFw0ba)3~|-@ zmB@Xg*Hi>#%8I8ESe2auM7%rkx@nKY+E(!gi{VU;v{xy42*IZyqv$otVW zo+bt5a`7qS*^hcCy${s*>xu2Qea{jZr(TmDzFkneq_!ex3o*~L(3FJ_?}N4scd;5T zmIkL4iT@?Xp=jj?nulQFpJLRz4gd7ne46mGZTJ{^4=PGFa9 z{nX~LwyWU8E$$c`8}vCYuP(L>c=#=AtgPvNi;iUcjYYi%q+^B6*DCdnKPOs8Ctxq) z1@AY~T@paZ^U>_!X+(>0Dfzt3 zuhc6~zWF+Y`>V|}ZqHoiBidtLjuX>c&8*!gCX!h6ykn-r7vatpASijtaK3y!pa0ah zo!u|S6L)c*+DfBzKc*ExYq!TgjYpxcJ>e$~zU7Se=kqV_1_bV9I@GqeNS?T&t{lUX zt{2p+6m4Y9O>>rT)1r?R!_DdFpneUh0ch--lcApSsP*G z)m?^RJ7h4c5ML~NqdUhvp`f^cN{kI&XPxrgQGk-a#J&&CXru>)s3avBqAHR&?q9RqNYg+jSK=JmT8 zA03+XvnP~Pz5<8|(hVA`&R(lcdKHN}0h&0Nf9nYd^0<9rmyc`M?GDmIw}LTpmuRE} ziQPJl(E0Q()>b+DIb_d(i(S;GLDRxylJmdq5%~z(fk(ksQ=FKs;|${fu9F!P*7(cs zruU@mu0cP(Hqe68f4U

    *P@Y`qcO~;T+SwX8 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 TUH4=%HTny2dXYb>e(C%lSAWI3 diff --git a/packages/compiler/src/backend/llvm/emit-module.ts b/packages/compiler/src/backend/llvm/emit-module.ts index 554e6a5a1..6adf76079 100644 --- a/packages/compiler/src/backend/llvm/emit-module.ts +++ b/packages/compiler/src/backend/llvm/emit-module.ts @@ -1014,7 +1014,7 @@ export function emitModuleParts(emitter: LlEmitter): string[] { // LIBRARY mode: no @main — the profile-declared external // symbols specified by the library IR instead. for (const line of emitter.emitLibDefs(globals, globalReleaseLines, stamps)) out.push(line); - out.push(...emitter.inlineRcTail(flushedDecls)); + for (const line of emitter.inlineRcTail(flushedDecls)) out.push(line); out.push(...functionAttributes(emitter, hasNoInlineRecordClone)); out.push(``); out.push(...emitter.fieldAliasMetadata()); @@ -1160,7 +1160,9 @@ export function emitModuleParts(emitter: LlEmitter): string[] { : [` %native_exit = call i32 @scr_exit_code_hint_get()`, ` ret i32 %native_exit`]), `}`, ``, - ...emitter.inlineRcTail(flushedDecls), + ); + for (const line of emitter.inlineRcTail(flushedDecls)) out.push(line); + out.push( // sanitize_address is inert under the plain pipeline; the sanitized // lane's -fsanitize=address link activates instrumentation over the // emitted functions too (the runtime TUs get theirs from clang). diff --git a/packages/compiler/src/backend/llvm/expr-containers.ts b/packages/compiler/src/backend/llvm/expr-containers.ts index 31643bdfa..59ef43d7d 100644 --- a/packages/compiler/src/backend/llvm/expr-containers.ts +++ b/packages/compiler/src/backend/llvm/expr-containers.ts @@ -1219,7 +1219,9 @@ function collectionOps(host: LlvmEmitterContext, key: IrType, value: IrType): st function newCollection(host: LlvmEmitterContext, key: IrType, value: IrType): string { const B = host.B; const arms = key.kind === "union" ? host.unionsById.get(key.unionId)?.arms : undefined; - const kind = mapKeyKindNum(key, arms); + // SCR_MAP_KEY_REF (2): shape-union keys are record pointers. + const kind = + key.kind === "union" && host.nullableUnions.shapes(key.unionId) ? 2 : mapKeyKindNum(key, arms); const m = B.tmp(); host.declare(`declare ptr @scr_map_new(i32, i32, ptr)`); // SCR_MAP_VAL_CREF (3): string keys and compact values (compactMapValues). diff --git a/packages/compiler/src/backend/llvm/expr-control.ts b/packages/compiler/src/backend/llvm/expr-control.ts index 242f9997c..2f7c31813 100644 --- a/packages/compiler/src/backend/llvm/expr-control.ts +++ b/packages/compiler/src/backend/llvm/expr-control.ts @@ -7,6 +7,8 @@ import { DYN_KIND } from "./dyn.js"; import { LlvmUnsupportedError } from "./unsupported.js"; import type { LlvmEmitterContext, ExprOf, LlValue } from "./expr-context.js"; import { f64Lit } from "./common.js"; +import { NULLABLE_NULL, SHAPE_WORD_INDEX, shapeWordHeader } from "./nullable-unions.js"; +import { emitUnionTag } from "./union-repr.js"; export function emitControlExpr( host: LlvmEmitterContext, @@ -52,6 +54,8 @@ export function emitControlExpr( case "toBool": return { name: host.truthy(host.emitUnionProjection(e.operand)), type: e.type }; case "logical": { + const tagSet = e.op === "||" ? unionTagSet(e) : null; + if (tagSet) return { name: emitUnionTagSet(host, tagSet), type: e.type }; // JS value semantics: the result is the deciding operand itself. // Left evaluates once, ownership moves into the result slot; when // the branch takes the right operand the stale left releases first @@ -614,3 +618,85 @@ function literalChoice(e: IrExpr): boolean { if (e.kind === "strLit") return true; return e.kind === "ternary" && literalChoice(e.then) && literalChoice(e.else_); } + +type TagSet = { unionId: string; value: IrExpr; tags: Set }; + +/** An `||` chain of two or more tag tests of one local (`isTag(u, 1) || + * isTag(u, 4) || ...`, the shape of a union conversion's identity test). */ +function unionTagSet(e: IrExpr & { kind: "logical" }): TagSet | null { + const leaves: IrExpr[] = []; + const collect = (x: IrExpr): void => { + if (x.kind === "logical" && x.op === "||") { + collect(x.left); + collect(x.right); + } else leaves.push(x); + }; + collect(e); + const first = leaves[0]!; + if (first.kind !== "unionIsTag" || first.value.kind !== "varRef") return null; + const localId = first.value.localId; + const tags = new Set(); + for (const leaf of leaves) { + if ( + leaf.kind !== "unionIsTag" || + leaf.negated || + leaf.unionId !== first.unionId || + leaf.value.kind !== "varRef" || + leaf.value.localId !== localId + ) + return null; + tags.add(leaf.tag); + } + return { unionId: first.unionId, value: first.value, tags }; +} + +/** i1: the union value holds one of the tags. One read of the tag and one + * switch over the set; a shape union switches on the record's shape word + * after its unit encodings. */ +function emitUnionTagSet(host: LlvmEmitterContext, set: TagSet): string { + const B = host.B; + const u = host.emitUnionProjection(set.value).name; + const nullable = host.nullableUnions.get(set.unionId); + const yes = B.newLabel("tags.y"); + const no = B.newLabel("tags.n"); + const join = B.newLabel("tags.j"); + const target = (tag: number): string => (set.tags.has(tag) ? yes : no); + if (nullable?.repr === "shapes") { + if (nullable.unitTag >= 0) { + const isNull = B.tmp(); + const next = B.newLabel("tags.r"); + B.line(`${isNull} = icmp eq ptr ${u}, null`); + B.condBr(isNull, target(nullable.unitTag), next); + B.startBlock(next); + } + if (nullable.nullTag >= 0) { + const isNullArm = B.tmp(); + const next = B.newLabel("tags.r"); + B.line(`${isNullArm} = icmp eq ptr ${u}, ${NULLABLE_NULL}`); + B.condBr(isNullArm, target(nullable.nullTag), next); + B.startBlock(next); + } + const wp = B.tmp(); + const w = B.tmp(); + B.line( + `${wp} = getelementptr inbounds ${shapeWordHeader(host.sizeType)}, ptr ${u}, i32 0, i32 ${SHAPE_WORD_INDEX}`, + ); + B.line(`${w} = load i32, ptr ${wp}`); + const cases = nullable.arms + .filter((arm) => set.tags.has(arm.tag)) + .map((arm) => `i32 ${host.nullableUnions.shapeNumber(arm.shapeId)}, label %${yes}`); + B.terminate(`switch i32 ${w}, label %${no} [ ${cases.join(" ")} ]`); + } else { + const tag = nullable ? emitUnionTag(B, nullable, u) : host.unionTag(u, set.unionId); + const cases = [...set.tags].map((t) => `i32 ${t}, label %${yes}`); + B.terminate(`switch i32 ${tag}, label %${no} [ ${cases.join(" ")} ]`); + } + B.startBlock(yes); + B.br(join); + B.startBlock(no); + B.br(join); + B.startBlock(join); + const t = B.tmp(); + B.line(`${t} = phi i1 [ true, %${yes} ], [ false, %${no} ]`); + return t; +} diff --git a/packages/compiler/src/backend/llvm/nullable-unions.test.ts b/packages/compiler/src/backend/llvm/nullable-unions.test.ts index 47278453e..bf0941652 100644 --- a/packages/compiler/src/backend/llvm/nullable-unions.test.ts +++ b/packages/compiler/src/backend/llvm/nullable-unions.test.ts @@ -56,10 +56,11 @@ test("unions of two or more records become shape unions", () => { }); test("records of runtime-inspected unions keep every union over them boxed", () => { - const set: IrType = { kind: "set", elem: { kind: "union", unionId: "ab" } }; + const set: IrType = { kind: "set", elem: { kind: "union", unionId: "abf" } }; const unions = new NullableUnions( module( [ + { id: "abf", arms: [a, b, F64] }, { id: "ab", arms: [a, b] }, { id: "abu", arms: [a, b, UNDEFINED_T] }, { id: "bc", arms: [b, c] }, @@ -68,6 +69,7 @@ test("records of runtime-inspected unions keep every union over them boxed", () { globals: [{ id: "%g.s", name: "s", type: set, mutable: false }] }, ), ); + expect(unions.get("abf")).toBeNull(); expect(unions.get("ab")).toBeNull(); expect(unions.get("abu")).toBeNull(); expect(unions.get("bc")).toBeNull(); @@ -75,6 +77,34 @@ test("records of runtime-inspected unions keep every union over them boxed", () expect(unions.shapeNumber("c")).toBe(0); }); +test("unions of records alone stay shape unions as Map keys and Set elements", () => { + const set: IrType = { kind: "set", elem: { kind: "union", unionId: "ab" } }; + const map: IrType = { kind: "map", key: { kind: "union", unionId: "abc" }, value: F64 }; + const unions = new NullableUnions( + module( + [ + { id: "ab", arms: [a, b] }, + { id: "abc", arms: [a, b, c] }, + { id: "ba", arms: [b, a] }, + { id: "abu", arms: [a, b, UNDEFINED_T] }, + ], + { + globals: [ + { id: "%g.s", name: "s", type: set, mutable: false }, + { id: "%g.m", name: "m", type: map, mutable: false }, + ], + }, + ), + ); + expect(unions.shapes("ab")).not.toBeNull(); + expect(unions.shapes("abc")).not.toBeNull(); + expect(unions.shapes("abu")).not.toBeNull(); + // Unions over the same records share one release and trace helper. + expect(unions.helperOwner("ba")).toBe("ab"); + expect(unions.helperOwner("abu")).toBe("ab"); + expect(unions.helperOwner("abc")).toBe("abc"); +}); + test("library, lifetime-region and debug builds keep record unions boxed", () => { const unions = [{ id: "ab", arms: [a, b] }]; expect(new NullableUnions(module(unions), false).get("ab")).toBeNull(); diff --git a/packages/compiler/src/backend/llvm/nullable-unions.ts b/packages/compiler/src/backend/llvm/nullable-unions.ts index d9b9cdfcf..c51f3b5f6 100644 --- a/packages/compiler/src/backend/llvm/nullable-unions.ts +++ b/packages/compiler/src/backend/llvm/nullable-unions.ts @@ -118,6 +118,9 @@ export class NullableUnions { readonly retainWrappers = new Map(); /** Some nullable union encodes `null` with NULLABLE_NULL. */ readonly usesNullSentinel: boolean = false; + /** The shape union whose release and trace helpers each shape union + * uses: the first one over the same record arms. */ + private readonly helperOwners = new Map(); /** `shapes`: allow shape unions (debug builds keep boxes, whose * debug-info layouts describe every arm). */ @@ -151,6 +154,24 @@ export class NullableUnions { if (!this.shapeNumbers.has(arm.shapeId)) this.shapeNumbers.set(arm.shapeId, this.shapeNumbers.size + 2); } + // Release and trace dispatch on the shape word, which names a record + // shape module-wide, so unions over the same records share them. + const owners = new Map(); + for (const nullable of this.byId.values()) { + if (nullable.repr !== "shapes") continue; + const key = nullable.arms + .map((arm) => arm.shapeId) + .sort() + .join(" "); + const owner = owners.get(key) ?? nullable.unionId; + owners.set(key, owner); + this.helperOwners.set(nullable.unionId, owner); + } + } + + /** The shape union whose release and trace helpers this one uses. */ + helperOwner(unionId: string): string { + return this.helperOwners.get(unionId) ?? unionId; } get(unionId: string): PointerUnion | null { @@ -277,13 +298,19 @@ function shapeUnion( /** Unions the runtime itself inspects as tagged boxes keep that * representation: Map keys and Set elements hash and compare union keys by - * tag and payload inside the C map. */ + * tag and payload inside the C map. A union of records alone is the + * exception: its keys compare by record identity, which a shape union's + * record pointer carries as well (the map keys it by reference). */ function boxedUnionIds(mod: IrModule, nodes?: IrNodeIndex): Set { const boxed = new Set(); // Only the module's union definitions consult the result. if (!mod.unions?.length) return boxed; + const recordsOnly = new Set(); + for (const def of mod.unions) + if (def.arms.length >= 2 && def.arms.every((arm) => arm.kind === "record")) + recordsOnly.add(def.id); const mark = (t: IrType): void => { - if (t.kind === "union") boxed.add(t.unionId); + if (t.kind === "union" && !recordsOnly.has(t.unionId)) boxed.add(t.unionId); }; if (nodes !== undefined) { for (const t of nodes.types) { diff --git a/packages/compiler/src/backend/llvm/record-union-keys.test.ts b/packages/compiler/src/backend/llvm/record-union-keys.test.ts new file mode 100644 index 000000000..8c3a89b96 --- /dev/null +++ b/packages/compiler/src/backend/llvm/record-union-keys.test.ts @@ -0,0 +1,148 @@ +import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile, deserializeModule } from "../../index.js"; +import { BOOL, F64, VOID, type IrExpr, type IrModule, type IrType } from "../../ir/ir.js"; +import { validateModule } from "../../ir/validate.js"; +import { emitLlvmModule } from "./emitter.js"; + +const loc = { file: "record-union-keys.ts", start: 0, end: 0 }; + +async function llvmFor(source: string): Promise { + const dir = await mkdtemp(join(tmpdir(), "scriptc-record-union-keys-")); + try { + const entry = join(dir, "main.ts"), + output = join(dir, "main.ir.json"); + await writeFile(entry, source); + const result = await compile(entry, { + outDir: dir, + outPath: output, + outputKind: "ir", + }); + if (!result.ok) + throw new Error(result.diagnostics.map((item) => `${item.code}: ${item.message}`).join("\n")); + const module = deserializeModule(await readFile(output, "utf8")); + expect(validateModule(module)).toEqual([]); + return emitLlvmModule(module); + } finally { + await rm(dir, { recursive: true, force: true }); + } +} + +function body(ir: string, name: string): string { + const found = new RegExp(`^define internal [^\\n]*@${name}(?:\\.i32)?\\([^]*?^}`, "m").exec(ir); + expect(found, name).not.toBeNull(); + return found![0]; +} + +test("Sets and Maps of record unions key the record pointer", async () => { + const ir = await llvmFor(` +type Num = { kind: "num"; value: number }; +type Neg = { kind: "neg"; operand: Node }; +type Add = { kind: "add"; left: Node; right: Node }; +type Node = Num | Neg | Add; +const one: Node = { kind: "num", value: 1 }; +const nodes: Node[] = [one, { kind: "neg", operand: one }, { kind: "add", left: one, right: one }]; +const seen = new Set(); +const depth = new Map(); +for (const node of nodes) { + seen.add(node); + depth.set(node, node.kind === "num" ? 0 : 1); +} +console.log(seen.size, depth.get(nodes[1]!), seen.has({ kind: "num", value: 1 })); +`); + // SCR_MAP_KEY_REF (2), never SCR_MAP_KEY_UNION_REF (3), and no union box. + expect(ir).toMatch(/call ptr @scr_map_new\(i32 2,/); + expect(ir).not.toMatch(/call ptr @scr_map_new\(i32 3,/); + expect(ir).not.toMatch(/call ptr @scr_union_new_ref/); +}); + +const recordType = (shapeId: string): IrType => ({ kind: "record", shapeId }); +const wide: IrType = { kind: "union", unionId: "wide" }; + +/** `pick(u)` answers whether `u` holds arm 0, 2 or 3 of a five-record union + * through an `||` chain of tag tests; `same` is a second union over the same + * records in another order. */ +function tagChainModule(): IrModule { + const u: IrExpr = { kind: "varRef", localId: "u", type: wide, loc }; + const isTag = (tag: number): IrExpr => ({ + kind: "unionIsTag", + unionId: "wide", + tag, + negated: false, + value: u, + type: BOOL, + loc, + }); + const or = (left: IrExpr, right: IrExpr): IrExpr => ({ + kind: "logical", + op: "||", + left, + right, + type: BOOL, + loc, + }); + const shapes = ["a", "b", "c", "d", "e"]; + return { + irVersion: 17, + sourceFile: loc.file, + entry: "main", + records: shapes.map((id) => ({ id, fields: [{ name: id, type: F64 }] })), + unions: [ + { id: "wide", arms: shapes.map(recordType) }, + { id: "same", arms: [...shapes].reverse().map(recordType) }, + ], + functions: [ + { + name: "main", + params: [], + returnType: VOID, + locals: [], + body: [], + loc, + }, + { + name: "pick", + params: [{ localId: "u", name: "u", type: wide }], + returnType: BOOL, + locals: [{ id: "u", name: "u", type: wide, mutable: false }], + body: [{ kind: "return", value: or(or(isTag(0), isTag(2)), isTag(3)), loc }], + loc, + }, + { + name: "keep", + params: [{ localId: "s", name: "s", type: { kind: "union", unionId: "same" } }], + returnType: VOID, + locals: [ + { + id: "s", + name: "s", + type: { kind: "union", unionId: "same" }, + mutable: false, + }, + ], + body: [], + loc, + }, + ], + }; +} + +test("an || chain of tag tests is one switch on the shape word", () => { + const mod = tagChainModule(); + expect(validateModule(mod)).toEqual([]); + const ir = emitLlvmModule(mod, { pointerBits: 64 }); + const pick = body(ir, "sc_bf_pick"); + const switches = pick.match(/switch i32 [^\n]*/g) ?? []; + expect(switches).toHaveLength(1); + expect(switches[0]!.match(/label %tags\.y/g)).toHaveLength(3); + expect(pick).not.toMatch(/@sc_stag\./); +}); + +test("unions over the same records share one release", () => { + const ir = emitLlvmModule(tagChainModule(), { pointerBits: 64 }); + expect(ir.match(/^define internal void @sc_srelease\.[^\n]*noinline/gm)).toHaveLength(1); + expect(ir).toMatch(/^define internal void @sc_srelease\.wide\(/m); + expect(ir).not.toMatch(/^define internal void @sc_srelease\.same\(/m); +}); diff --git a/packages/compiler/src/backend/llvm/shapes.ts b/packages/compiler/src/backend/llvm/shapes.ts index a966ff305..d5a77c76d 100644 --- a/packages/compiler/src/backend/llvm/shapes.ts +++ b/packages/compiler/src/backend/llvm/shapes.ts @@ -233,7 +233,7 @@ export { computeTraced } from "../cycle-analysis.js"; * `_v`-shaped. */ export function vAdapters(host: ShapeHost, t: IrType): { retain: string; release: string } { const nullable = host.nullableUnions.of(t); - if (nullable?.repr === "shapes") return shapeUnionRc(nullable); + if (nullable?.repr === "shapes") return shapeUnionRc(host, nullable); if (nullable) { const arm = vAdapters(host, nullable.arm); return { retain: nullableRetainSym(host, nullable.arm), release: arm.release }; @@ -290,7 +290,7 @@ export function vAdapters(host: ShapeHost, t: IrType): { retain: string; release export function retainSym(host: ShapeHost, t: IrType): string { if (t.kind === "jsval") return jsvalRcSym(host, "retain"); const nullable = host.nullableUnions.of(t); - if (nullable?.repr === "shapes") return shapeUnionRc(nullable).retain; + if (nullable?.repr === "shapes") return shapeUnionRc(host, nullable).retain; if (nullable) return nullableRetainSym(host, nullable.arm); const stem = runtimeRcStem(t); if (host.rcHelpers !== null && stem !== null && inlineRcFamily(host, stem, "retain") !== null) { @@ -305,10 +305,10 @@ export function retainSym(host: ShapeHost, t: IrType): string { /** A shape union's RC entry points: every record retain is the same * NULL- and immortal-skipping increment (the null sentinel is immortal), * so the first arm's serves; release dispatches on the arm. */ -function shapeUnionRc(union: ShapeUnion): { retain: string; release: string } { +function shapeUnionRc(host: ShapeHost, union: ShapeUnion): { retain: string; release: string } { return { retain: `@${mangleRecordRetain(union.arms[0]!.shapeId)}`, - release: shapeReleaseFn(union.unionId), + release: shapeReleaseFn(host.nullableUnions.helperOwner(union.unionId)), }; } @@ -352,38 +352,72 @@ export function emitShapeUnionHelpers(host: ShapeHost): string[] { `}`, ``, ); - // release: unit encodings are NULL or immortal; each arm releases - // through its own (NULL- and immortal-tolerant) helper. - out.push( - `define internal void ${shapeReleaseFn(union.unionId)}(ptr %u) ${FN_ATTRS} { ; shape union release`, - `entry:`, - ` %t = call i32 ${tagFn}(ptr %u)`, - ` switch i32 %t, label %done [ ${union.arms.map((arm) => `i32 ${arm.tag}, label %a${arm.tag}`).join(" ")} ]`, - ...union.arms.flatMap((arm) => [ - `a${arm.tag}:`, - ` call void @${mangleRecordRelease(arm.shapeId)}(ptr %u)`, - ` br label %done`, - ]), + // Release and trace: one definition for the unions over the same + // record arms (helperOwner). Unit encodings are NULL or the immortal + // null sentinel; the shape word picks the arm. + if (host.nullableUnions.helperOwner(union.unionId) !== union.unionId) continue; + const units = [ + ` %isnull = icmp eq ptr %o, null`, + ` br i1 %isnull, label %done, label %${host.nullableUnions.usesNullSentinel ? "notnull" : "rec"}`, + ...(host.nullableUnions.usesNullSentinel + ? [ + `notnull:`, + ` %isnullarm = icmp eq ptr %o, ${NULLABLE_NULL}`, + ` br i1 %isnullarm, label %done, label %rec`, + ] + : []), + `rec:`, + ]; + const armSwitch = (call: (shapeId: string) => string): string[] => [ + ` %wp = getelementptr inbounds ${header}, ptr %o, i32 0, i32 ${SHAPE_WORD_INDEX}`, + ` %w = load i32, ptr %wp`, + ` switch i32 %w, label %done [ ${union.arms.map((arm) => `i32 ${host.nullableUnions.shapeNumber(arm.shapeId)}, label %a${arm.tag}`).join(" ")} ]`, + ...union.arms.flatMap((arm) => [`a${arm.tag}:`, call(arm.shapeId), ` br label %done`]), `done:`, ` ret void`, `}`, ``, - ); + ]; + // Every record arm shares the release fast path (the count at the same + // offset, one collector header choice for the whole union), so only a + // release that may free dispatches on the arm. The release stays a call: + // inlined at every release site, it grows code more than it saves. + const traced = union.arms.map((arm) => host.tracedShapes.has(`record:${arm.shapeId}`)); + const release = shapeReleaseFn(union.unionId); + if (traced.every((t) => t === traced[0])) + out.push( + `define internal void ${release}(ptr %o) noinline ${FN_ATTRS} { ; shape union release`, + `entry:`, + ...units, + ` %rc = load ${S}, ptr %o`, + ` %rcm2 = sub ${S} %rc, 2`, + ` %shared = icmp ult ${S} %rcm2, -3`, + ` br i1 %shared, label %dec, label %slow`, + `dec:`, + ` %n = sub ${S} %rc, 1`, + ` store ${S} %n, ptr %o`, + ...(traced[0] ? cycleRootLines(host, "done") : [` br label %done`]), + `slow:`, + ` %imm = icmp eq ${S} %rc, -1`, + ` br i1 %imm, label %done, label %free`, + `free:`, + ...armSwitch((shapeId) => ` call void @${mangleRecordRelease(shapeId)}_slow(ptr %o)`), + ); + else + out.push( + `define internal void ${release}(ptr %o) ${FN_ATTRS} { ; shape union release`, + `entry:`, + ...units, + ...armSwitch((shapeId) => ` call void @${mangleRecordRelease(shapeId)}(ptr %o)`), + ); if (shapeUnionTraced(host, union)) out.push( - `define internal void ${shapeTraceFn(union.unionId)}(ptr %u, ptr %visit, ptr %ctx) ${FN_ATTRS} { ; shape union trace`, + `define internal void ${shapeTraceFn(union.unionId)}(ptr %o, ptr %visit, ptr %ctx) ${FN_ATTRS} { ; shape union trace`, `entry:`, - ` %t = call i32 ${tagFn}(ptr %u)`, - ` switch i32 %t, label %done [ ${union.arms.map((arm) => `i32 ${arm.tag}, label %a${arm.tag}`).join(" ")} ]`, - ...union.arms.flatMap((arm) => [ - `a${arm.tag}:`, - ` call void @${mangleRecordTrace(arm.shapeId)}(ptr %u, ptr %visit, ptr %ctx)`, - ` br label %done`, - ]), - `done:`, - ` ret void`, - `}`, - ``, + ...units, + ...armSwitch( + (shapeId) => ` call void @${mangleRecordTrace(shapeId)}(ptr %o, ptr %visit, ptr %ctx)`, + ), ); } return out; @@ -435,7 +469,7 @@ export function emitNullableRetainWrappers(host: ShapeHost): string[] { export function releaseSym(host: ShapeHost, t: IrType): string { if (t.kind === "jsval") return jsvalRcSym(host, "release"); const nullable = host.nullableUnions.of(t); - if (nullable?.repr === "shapes") return shapeUnionRc(nullable).release; + if (nullable?.repr === "shapes") return shapeUnionRc(host, nullable).release; if (nullable) return releaseSym(host, nullable.arm); const stem = runtimeRcStem(t); if (host.rcHelpers !== null && stem !== null && inlineRcFamily(host, stem, "release") !== null) { @@ -985,7 +1019,9 @@ export function traceAdapter(host: ShapeHost, t: IrType): string | null { case "union": { const nullable = host.nullableUnions.get(t.unionId); if (nullable?.repr === "shapes") - return shapeUnionTraced(host, nullable) ? shapeTraceFn(nullable.unionId) : null; + return shapeUnionTraced(host, nullable) + ? shapeTraceFn(host.nullableUnions.helperOwner(nullable.unionId)) + : null; if (nullable) return traceAdapter(host, nullable.arm); if (!host.tracedUnions.has(t.unionId)) return null; host.declare(`declare void @scr_union_trace_v(ptr, ptr, ptr)`); diff --git a/packages/compiler/src/backend/llvm/test-boxed-unions.ts b/packages/compiler/src/backend/llvm/test-boxed-unions.ts index 15cf5aee9..8847d53a3 100644 --- a/packages/compiler/src/backend/llvm/test-boxed-unions.ts +++ b/packages/compiler/src/backend/llvm/test-boxed-unions.ts @@ -1,14 +1,29 @@ -import type { IrModule, IrType } from "../../ir/ir.js"; +import { F64, type IrModule, type IrType, type IrUnionDef } from "../../ir/ir.js"; /** Test helper: a Set of each union keeps it a tagged `%ScrUnion` box (Set * elements are runtime-inspected boxes), so stack-box tests exercise the - * paths that nullable-pointer unions (nullable-unions.ts) bypass. */ + * paths that nullable-pointer unions (nullable-unions.ts) bypass. A union of + * records alone is a Set element by record identity, so for those the Set + * holds a companion union with a number arm, which keeps the records out of + * every shape union. */ export function keepUnionsBoxed(mod: IrModule): IrModule { - const keep = (mod.unions ?? []).map((union) => ({ - id: `%g.keep.${union.id}`, - name: `keep_${union.id}`, - type: { kind: "set", elem: { kind: "union", unionId: union.id } } as IrType, - mutable: false, - })); - return { ...mod, globals: [...(mod.globals ?? []), ...keep] }; + const companions: IrUnionDef[] = []; + const keep = (mod.unions ?? []).map((union) => { + let elem = union.id; + if (union.arms.every((arm) => arm.kind === "record")) { + elem = `%keep.${union.id}`; + companions.push({ id: elem, arms: [...union.arms, F64] }); + } + return { + id: `%g.keep.${union.id}`, + name: `keep_${union.id}`, + type: { kind: "set", elem: { kind: "union", unionId: elem } } as IrType, + mutable: false, + }; + }); + return { + ...mod, + unions: [...(mod.unions ?? []), ...companions], + globals: [...(mod.globals ?? []), ...keep], + }; } From 53bddc6ed7b62eb3f9e9bbb81296ae7b64792f39 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 18:46:36 -0500 Subject: [PATCH 182/259] Give the module namespace handle its own tag --- packages/runtime/src/scr_dyn.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index 04bb9bb22..a3264b5d0 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -186,7 +186,7 @@ typedef enum { X(MATCH_SOURCE, 55) /* a match result's pending metadata (scr_regex.c) */ \ X(MESSAGE_EVENT, 50) /* ScrEvent with data — BroadcastChannel's 'message' */ \ X(MESSAGE_PORT, 36) \ - X(MODULE_NAMESPACE, 78) /* module namespace object read through its exports (scr_module_namespace.c) */ \ + X(MODULE_NAMESPACE, 79) /* module namespace object read through its exports (scr_module_namespace.c) */ \ X(NET_BLOCK_LIST, 48) /* net.BlockList (scr_net.c) */ \ X(NET_SERVER, 3) /* ScrNetServer — net.Server (http.Server rides the same handle) */ \ X(NET_SOCKET, 2) /* ScrNetSocket — net.Socket */ \ From b7491676bbd23afbe423b406133321886c68637c Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 19:01:18 -0500 Subject: [PATCH 183/259] Read the runtime ABI in the runtime pack test fixture from the compiler --- packages/compiler/src/backend/runtime-pack-native.test.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/compiler/src/backend/runtime-pack-native.test.ts b/packages/compiler/src/backend/runtime-pack-native.test.ts index 293d814b8..7a8a2e6c4 100644 --- a/packages/compiler/src/backend/runtime-pack-native.test.ts +++ b/packages/compiler/src/backend/runtime-pack-native.test.ts @@ -16,6 +16,7 @@ import { afterEach, expect, test, vi } from "vitest"; import { nativeCodegenDiag } from "../diagnostics/diagnostic.js"; import { compilerReleaseVersion } from "../library/sidecar.js"; import type { NativeLinkFeatures } from "./native-link-info.js"; +import { RUNTIME_ABI_MARKER, RUNTIME_ABI_VERSION } from "./runtime-abi.js"; import { RuntimePackError, type RuntimePackManifest } from "./runtime-pack-core.js"; import { runtimePackManifest, @@ -114,7 +115,7 @@ async function packFixture() { object_format: target.objectFormat, minimum_os: target.minimumOs, }, - runtime_abi: { version: 37, marker: "scr_runtime_abi_v37" }, + runtime_abi: { version: RUNTIME_ABI_VERSION, marker: RUNTIME_ABI_MARKER }, compiler: { command: "clang", identity: "fixture clang", target: target.llvmTriple }, macros: { executable: [], From 7464f12e6b4649b2aa67489b812c2c5a0e58d652 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 20:01:49 -0500 Subject: [PATCH 184/259] Emit unwinding code for textual LLVM and assembly output on Linux --- packages/compiler/src/index.ts | 3 +++ packages/compiler/src/native/prepare.ts | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/compiler/src/index.ts b/packages/compiler/src/index.ts index 51230703c..345e7565e 100644 --- a/packages/compiler/src/index.ts +++ b/packages/compiler/src/index.ts @@ -809,6 +809,9 @@ async function prepareExecutableInput( pointerBits: buildPlatform === "wasi" ? 32 : 64, wasi: buildPlatform === "wasi", runtimeAbiMarker: outputKind === "obj", + // Textual output shows the code an executable gets; objects keep + // the pending flag, since their link may not add an unwinder. + unwindAbi: buildPlatform === "linux" && outputKind !== "obj", objectAudit: opts.sanitize === true, lowRegion: lowRegionTarget(buildPlatform, opts.sanitize === true), ...(opts.sanitize === true ? { wasmBoundsChecks: true } : {}), diff --git a/packages/compiler/src/native/prepare.ts b/packages/compiler/src/native/prepare.ts index c15bfbf9b..13d32fd3b 100644 --- a/packages/compiler/src/native/prepare.ts +++ b/packages/compiler/src/native/prepare.ts @@ -408,7 +408,11 @@ export function prepareNativeExecutable( pointerBits: toolchain.target.pointerBits, wasi: toolchain.target.platform === "wasi", runtimeAbiMarker: outputKind === "obj" || outputKind === "exe", - unwindAbi: outputKind === "exe" && toolchain.target.platform === "linux", + // As for the Node-hosted build: executables and their textual + // LLVM and assembly, not objects. + unwindAbi: + (outputKind === "exe" || outputKind === "llvm" || outputKind === "asm") && + toolchain.target.platform === "linux", objectAudit: options.sanitize === true, lowRegion: lowRegionTarget(toolchain.target.platform, options.sanitize === true), functionWorkers: emitWorkers(), From e2db1ef344d3e09c8db683b4f32fddff8751de6f Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 20:07:36 -0500 Subject: [PATCH 185/259] Hold Reflect.ownKeys's function value in the Reflect namespace object Reading `ownKeys` from Reflect read as a value (`const r = Reflect; r.ownKeys`) gave the member function that throws SC1090 when called, although the spelled `Reflect.ownKeys` read already has a function value. The namespace object now holds that function value, so calls through the alias run and `r.ownKeys === Reflect.ownKeys` is true, as in Node. The spelled read and the namespace member share one lowering (reflectMemberValue). --- .../frontend/lowering/builtin-namespaces.ts | 3 ++- .../frontend/lowering/builtins/reflection.ts | 19 ++++++++++++++++++- .../lowering/expressions/property-access.ts | 16 +++------------- tests/corpus/7186-namespace-object-values.js | 5 +++++ 4 files changed, 28 insertions(+), 15 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/builtin-namespaces.ts b/packages/compiler/src/frontend/lowering/builtin-namespaces.ts index bfe3c5e39..c1e40d2e6 100644 --- a/packages/compiler/src/frontend/lowering/builtin-namespaces.ts +++ b/packages/compiler/src/frontend/lowering/builtin-namespaces.ts @@ -24,6 +24,7 @@ import type { Lowerer } from "./lowerer.js"; import { InternalCompilerError } from "../../errors.js"; import { mathMemberValue } from "./lower-stdlib.js"; import { jsonMemberValue } from "./builtins/json.js"; +import { reflectMemberValue } from "./builtins/reflection.js"; /** A function member with its `length`, or a constant (`length` -1). */ interface NamespaceMember { @@ -244,7 +245,7 @@ function functionValue(lowerer: Lowerer, canonical: string, key: string, loc: Sr ? mathMemberValue(lowerer, key, loc) : canonical === "JSON" ? jsonMemberValue(lowerer, key, loc) - : null; + : reflectMemberValue(lowerer, key, loc); if (value !== null) return value.type.kind === "dyn" ? value diff --git a/packages/compiler/src/frontend/lowering/builtins/reflection.ts b/packages/compiler/src/frontend/lowering/builtins/reflection.ts index 8e1e6fd94..5171ebfdb 100644 --- a/packages/compiler/src/frontend/lowering/builtins/reflection.ts +++ b/packages/compiler/src/frontend/lowering/builtins/reflection.ts @@ -3,7 +3,24 @@ import * as ts from "../../ts7/adapter.js"; import { type Lowerer } from "../lowerer.js"; import { locOf } from "../../program.js"; import { builtinModuleFnOf } from "../surfaces.js"; -import { BOOL, DYN, type IrExpr, STRING, arrayOf } from "../../../ir/ir.js"; +import { BOOL, DYN, type IrExpr, STRING, type SrcLoc, arrayOf } from "../../../ir/ir.js"; + +/** The function value of the Reflect member `member` (ownKeys, on native + * computed-key reflection), or null for members without one. */ +export function reflectMemberValue(lowerer: Lowerer, member: string, loc: SrcLoc): IrExpr | null { + if (member !== "ownKeys") return null; + const value = lowerer.lowerNativeCallableValue( + { + fn: "dyn.ownKeys", + params: [DYN], + result: DYN, + valueParams: [{ mode: "required", type: DYN }], + }, + "Reflect.ownKeys", + loc, + )!; + return { kind: "dynFrom", value, fnName: "ownKeys", type: DYN, loc }; +} /** Reflect.ownKeys uses native computed-key reflection. Reflect.apply(target, * thisArg, argsList) where the TARGET is a builtin diff --git a/packages/compiler/src/frontend/lowering/expressions/property-access.ts b/packages/compiler/src/frontend/lowering/expressions/property-access.ts index 536ef93c9..7c931aae6 100644 --- a/packages/compiler/src/frontend/lowering/expressions/property-access.ts +++ b/packages/compiler/src/frontend/lowering/expressions/property-access.ts @@ -161,6 +161,7 @@ import { lowerNetAddressStaticRead } from "../builtins/net-address.js"; import { STATS_TYPE_TESTS } from "../builtins/filesystem.js"; import { arrayValueRead, arrayValueType } from "../array-values.js"; import { lowerClassMethodValue } from "../class-method-values.js"; +import { reflectMemberValue } from "../builtins/reflection.js"; import { objLitGenericFnInfoOf, objLitGenericFnNodeOf, @@ -1691,19 +1692,8 @@ export function lowerIntrinsicProperty( ); } } - if (lowerer.stdlibGlobalMember(expr, "Reflect") === "ownKeys") { - const value = lowerer.lowerNativeCallableValue( - { - fn: "dyn.ownKeys", - params: [DYN], - result: DYN, - valueParams: [{ mode: "required", type: DYN }], - }, - "Reflect.ownKeys", - locOf(expr), - )!; - return { kind: "dynFrom", value, fnName: "ownKeys", type: DYN, loc: locOf(expr) }; - } + if (lowerer.stdlibGlobalMember(expr, "Reflect") === "ownKeys") + return reflectMemberValue(lowerer, "ownKeys", locOf(expr)); if (lowerer.chainBlocked(expr)) return null; // Object.prototype.constructor: the Object constructor value. if ( diff --git a/tests/corpus/7186-namespace-object-values.js b/tests/corpus/7186-namespace-object-values.js index c61d96e11..33c30e12f 100644 --- a/tests/corpus/7186-namespace-object-values.js +++ b/tests/corpus/7186-namespace-object-values.js @@ -20,3 +20,8 @@ console.log(parse("[1,2]").length, JSON.stringify({ a: [1] })); console.log(typeof Math === "object" && typeof Reflect === "object"); console.log(Math.max.length, Math.min.length, Math.hypot.length, Math.abs.length); + +const r = Reflect; +const ownKeys = r.ownKeys; +console.log(ownKeys === Reflect.ownKeys, r.ownKeys === Reflect.ownKeys, typeof ownKeys); +console.log(r.ownKeys({ a: 1, b: 2 }).length, ownKeys({ c: 3 })[0], ownKeys.name, ownKeys.length); From 8032e6c6c67211e4e8d5187a9a74d6444af49b3c Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 20:08:30 -0500 Subject: [PATCH 186/259] Free frozen records when a shape union drops their last reference A frozen record's rc word carries SCR_RC_FROZEN beside its count. The shared shape-union release compared the whole word, so the last reference to a frozen record took the shared-reference branch: it decremented the count and never freed the record or its fields. When an arm is freezable, the release now compares the count without the frozen bit, as the record's own release does. --- .../backend/llvm/record-union-keys.test.ts | 21 ++++++ packages/compiler/src/backend/llvm/shapes.ts | 13 +++- .../8291-frozen-record-union-keys.ts.json | 6 ++ tests/corpus/8291-frozen-record-union-keys.ts | 65 +++++++++++++++++++ .../8291-frozen-record-union-keys.ts.json | 1 + 5 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8291-frozen-record-union-keys.ts.json create mode 100644 tests/corpus/8291-frozen-record-union-keys.ts create mode 100644 tests/harness/corpus-costs/8291-frozen-record-union-keys.ts.json diff --git a/packages/compiler/src/backend/llvm/record-union-keys.test.ts b/packages/compiler/src/backend/llvm/record-union-keys.test.ts index 8c3a89b96..3c961cabb 100644 --- a/packages/compiler/src/backend/llvm/record-union-keys.test.ts +++ b/packages/compiler/src/backend/llvm/record-union-keys.test.ts @@ -146,3 +146,24 @@ test("unions over the same records share one release", () => { expect(ir).toMatch(/^define internal void @sc_srelease\.wide\(/m); expect(ir).not.toMatch(/^define internal void @sc_srelease\.same\(/m); }); + +test("a union with a freezable arm compares its count without the frozen bit", async () => { + const ir = await llvmFor(` +type Name = { kind: "name"; text: string }; +type Count = { kind: "count"; value: number }; +type Key = Name | Count; +function name(text: string): Key { + const built: Name = { kind: "name", text }; + return Object.freeze(built); +} +const seen = new Set(); +seen.add(name("a")); +seen.add({ kind: "count", value: 1 }); +console.log(seen.size); +`); + const release = /^define internal void @sc_srelease\.[^\n]*\n[^]*?^}/m.exec(ir); + expect(release).not.toBeNull(); + // SCR_RC_FROZEN is bit 62: a frozen record's last reference has count 1. + expect(release![0]).toContain("and i64 %rc, -4611686018427387905"); + expect(release![0]).toContain("icmp ult i64 %rcm2, -4611686018427387907"); +}); diff --git a/packages/compiler/src/backend/llvm/shapes.ts b/packages/compiler/src/backend/llvm/shapes.ts index d5a77c76d..ab623f934 100644 --- a/packages/compiler/src/backend/llvm/shapes.ts +++ b/packages/compiler/src/backend/llvm/shapes.ts @@ -383,6 +383,10 @@ export function emitShapeUnionHelpers(host: ShapeHost): string[] { // release that may free dispatches on the arm. The release stays a call: // inlined at every release site, it grows code more than it saves. const traced = union.arms.map((arm) => host.tracedShapes.has(`record:${arm.shapeId}`)); + // A freezable arm's count is the word without its frozen bit, as in + // releaseFastPath: a frozen record's last reference takes the slow path. + const frozen = union.arms.some((arm) => host.recordsById.get(arm.shapeId)?.freezable === true); + const notFrozen = ~recordFrozenBit(S); const release = shapeReleaseFn(union.unionId); if (traced.every((t) => t === traced[0])) out.push( @@ -390,8 +394,13 @@ export function emitShapeUnionHelpers(host: ShapeHost): string[] { `entry:`, ...units, ` %rc = load ${S}, ptr %o`, - ` %rcm2 = sub ${S} %rc, 2`, - ` %shared = icmp ult ${S} %rcm2, -3`, + ...(frozen + ? [ + ` %refs = and ${S} %rc, ${sizeLiteral(S, notFrozen)}`, + ` %rcm2 = sub ${S} %refs, 2`, + ` %shared = icmp ult ${S} %rcm2, ${sizeLiteral(S, notFrozen - 2n)}`, + ] + : [` %rcm2 = sub ${S} %rc, 2`, ` %shared = icmp ult ${S} %rcm2, -3`]), ` br i1 %shared, label %dec, label %slow`, `dec:`, ` %n = sub ${S} %rc, 1`, diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8291-frozen-record-union-keys.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8291-frozen-record-union-keys.ts.json new file mode 100644 index 000000000..3dcadeb0a --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8291-frozen-record-union-keys.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8291-frozen-record-union-keys.ts" + ], + "diags": [] +} diff --git a/tests/corpus/8291-frozen-record-union-keys.ts b/tests/corpus/8291-frozen-record-union-keys.ts new file mode 100644 index 000000000..b6173ef4e --- /dev/null +++ b/tests/corpus/8291-frozen-record-union-keys.ts @@ -0,0 +1,65 @@ +// Frozen records in record-only unions used as Set elements and Map keys: +// the union's release frees a frozen record when it drops the last +// reference, for unions the cycle collector traces and ones it does not. +type Leaf = { kind: "leaf"; label: string }; +type Pair = { kind: "pair"; left: Node; right: Node }; +type Node = Leaf | Pair; + +type Name = { kind: "name"; text: string }; +type Count = { kind: "count"; value: number; unit: string }; +type Key = Name | Count; + +function leaf(label: string): Node { + const built: Leaf = { kind: "leaf", label }; + return Object.freeze(built); +} + +function pair(left: Node, right: Node): Node { + const built: Pair = { kind: "pair", left, right }; + return Object.freeze(built); +} + +function key(i: number): Key { + if (i % 2 === 0) { + const name: Name = { kind: "name", text: "n" + i }; + return Object.freeze(name); + } + const count: Count = { kind: "count", value: i, unit: "u" + i }; + return Object.freeze(count); +} + +function nodes(n: number): number { + const seen = new Set(); + const weight = new Map(); + let last = leaf("start"); + for (let i = 0; i < n; i++) { + const next = i % 3 === 0 ? leaf("l" + i) : pair(last, leaf("r" + i)); + seen.add(next); + weight.set(next, i); + last = next; + } + let total = 0; + for (const node of seen) total += (weight.get(node) ?? 0) + (node.kind === "pair" ? 1 : 0); + seen.clear(); + weight.clear(); + return total + (last.kind === "pair" ? 1 : 0); +} + +function keys(n: number): number { + const seen = new Set(); + const size = new Map(); + for (let i = 0; i < n; i++) { + const k = key(i); + seen.add(k); + size.set(k, k.kind === "name" ? k.text.length : k.value); + } + let total = 0; + for (const k of seen) total += size.get(k) ?? 0; + seen.clear(); + size.clear(); + return total; +} + +let sum = 0; +for (let r = 0; r < 50; r++) sum += nodes(40) + keys(40); +console.log(sum); diff --git a/tests/harness/corpus-costs/8291-frozen-record-union-keys.ts.json b/tests/harness/corpus-costs/8291-frozen-record-union-keys.ts.json new file mode 100644 index 000000000..77d20b756 --- /dev/null +++ b/tests/harness/corpus-costs/8291-frozen-record-union-keys.ts.json @@ -0,0 +1 @@ +{ "plain": 2500, "san": 5000 } From c091adc0e4ff0a333d163318bb7d288254439e91 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 20:09:28 -0500 Subject: [PATCH 187/259] Build symbol-keyed fields into frozen class views whatever their attributes A JavaScript class whose instances track which fields they have copies the instance's property bag into its view first, attributes included, and then wrote each symbol-keyed field with an ordinary assignment. Once the instance was frozen, its symbol entry was read-only and the copy non-extensible, so any later reflection that rebuilt the view (Object.isFrozen, a property read) threw "Cannot assign to a read only symbol property". String-keyed fields already use scr_dyn_obj_set_field, which replaces a field's value whatever the attributes copied into the view. The new scr_dyn_symbol_field_set does the same for symbol-keyed fields, and the view uses it when it copies the bag or carries integrity attributes. --- .../src/backend/llvm/expr-stream-bridges.ts | 10 ++++-- ...7408-frozen-js-class-symbol-fields.js.json | 6 ++++ packages/runtime/src/scr_dyn.h | 4 +++ packages/runtime/src/scr_json.c | 31 ++++++++++++++++++ .../7408-frozen-js-class-symbol-fields.js | 32 +++++++++++++++++++ 5 files changed, 81 insertions(+), 2 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7408-frozen-js-class-symbol-fields.js.json create mode 100644 tests/corpus/7408-frozen-js-class-symbol-fields.js diff --git a/packages/compiler/src/backend/llvm/expr-stream-bridges.ts b/packages/compiler/src/backend/llvm/expr-stream-bridges.ts index 1f66324ad..0a502eea7 100644 --- a/packages/compiler/src/backend/llvm/expr-stream-bridges.ts +++ b/packages/compiler/src/backend/llvm/expr-stream-bridges.ts @@ -1004,9 +1004,15 @@ export function streamTypedRefMaterializeAdapter( host.declare(`declare void @scr_union_release(ptr)`); B.line(`call void @scr_union_release(ptr ${fieldValue})`); } - host.declare(`declare void @scr_dyn_symbol_key_set(ptr, ptr, ptr)`); + // As for string-keyed fields, attributes copied from the bag (a frozen + // instance's) do not stop the view taking the value. + const symbolSetter = + meta.def.tracksOwnFields || withAttributes + ? "scr_dyn_symbol_field_set" + : "scr_dyn_symbol_key_set"; + host.declare(`declare void @${symbolSetter}(ptr, ptr, ptr)`); host.declare(`declare void @scr_dyn_release_v(ptr)`); - B.line(`call void @scr_dyn_symbol_key_set(ptr ${out}, ptr ${key}, ptr ${value})`); + B.line(`call void @${symbolSetter}(ptr ${out}, ptr ${key}, ptr ${value})`); B.line(`call void @scr_dyn_release_v(ptr ${value})`); if (afterSymbol) { B.terminate(`br label %${afterSymbol}`); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7408-frozen-js-class-symbol-fields.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7408-frozen-js-class-symbol-fields.js.json new file mode 100644 index 000000000..a57d1c73b --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7408-frozen-js-class-symbol-fields.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7408-frozen-js-class-symbol-fields.js" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index 3e5cdd4a5..691453783 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -870,6 +870,10 @@ bool scr_disposable_stack_use(const ScrDyn *stack, const ScrDyn *value); bool scr_disposable_stack_use_callback(const ScrDyn *stack, const ScrDyn *value, const ScrDyn *dispose); bool scr_disposable_stack_adopt(const ScrDyn *stack, const ScrDyn *value, const ScrDyn *on_dispose); void scr_dyn_symbol_key_set(ScrDyn *value, ScrDyn *key, ScrDyn *stored); +/* scr_dyn_obj_set_field for a symbol-keyed field of a class instance's + * view: replaces the value whatever the attributes copied into the view. + * Does not consume stored. */ +void scr_dyn_symbol_field_set(ScrDyn *value, ScrDyn *key, ScrDyn *stored); void scr_dyn_symbol_key_placeholder(ScrDyn *value, ScrDyn *key); bool scr_dyn_has_key_computed(const ScrDyn *value, const ScrDyn *key); bool scr_dyn_has_own_computed(const ScrDyn *value, const ScrDyn *key); diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index e3f27cf61..a32958e51 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -7989,6 +7989,37 @@ void scr_dyn_symbol_key_set(ScrDyn *value, ScrDyn *key, ScrDyn *stored) { scr_dyn_release(receiver); } +/* scr_dyn_obj_set_field for a symbol-keyed field of a class instance's + * view: the view takes the native value whatever the attributes copied into + * it from the instance's property bag (a frozen instance's view is built the + * same way as any other). An accessor entry takes the ordinary assignment. + * Does not consume value. */ +void scr_dyn_symbol_field_set(ScrDyn *obj, ScrDyn *key, ScrDyn *value) { + ScrDynEntry *entry = obj->kind == SCR_DYN_OBJ && obj->symbol_properties + ? scr_dyn_symbol_entry(obj, key, true) + : NULL; + if (entry && !entry->accessor) { + scr_dyn_region_store(obj->symbol_properties, value); + ScrDyn *old = entry->value; + entry->value = scr_dyn_retain(value); + scr_dyn_release(old); + return; + } + if (entry || obj->kind != SCR_DYN_OBJ) { + scr_dyn_symbol_key_set(obj, key, value); + return; + } + bool non_extensible = obj->non_extensible; + ScrDyn *table = obj->symbol_properties; + bool table_non_extensible = table && table->non_extensible; + obj->non_extensible = false; + if (table) table->non_extensible = false; + scr_dyn_symbol_key_set(obj, key, value); + obj->non_extensible = non_extensible; + if (obj->symbol_properties) + obj->symbol_properties->non_extensible = table ? table_non_extensible : non_extensible; +} + static ScrDyn *scr_dyn_define_symbol(ScrDyn *target, ScrDyn *key, ScrDyn *descriptor) { ScrDyn *receiver = scr_dyn_symbol_receiver(target); if (!receiver) { diff --git a/tests/corpus/7408-frozen-js-class-symbol-fields.js b/tests/corpus/7408-frozen-js-class-symbol-fields.js new file mode 100644 index 000000000..9ce5a1c53 --- /dev/null +++ b/tests/corpus/7408-frozen-js-class-symbol-fields.js @@ -0,0 +1,32 @@ +// A JavaScript class whose instances track which fields they have (one +// field is created by a method) and carry a symbol-keyed field. Freezing +// or sealing such an instance makes its symbol entry read-only; later +// reflection rebuilds the instance's view and takes the field's value. +const tag = Symbol("tag"); +class Box { + constructor(v) { + this.v = v; + this[tag] = v; + } + later() { + this.w = 3; + } +} + +const frozen = new Box(1); +frozen.extra = 2; +Object.freeze(frozen); +console.log(Object.isFrozen(frozen)); +console.log(Object.isFrozen(frozen), Object.isSealed(frozen), Object.isExtensible(frozen)); +console.log(frozen[tag], frozen.v, frozen.extra, frozen.w); +console.log(JSON.stringify(Object.getOwnPropertyDescriptor(frozen, tag))); + +const sealed = new Box(2); +sealed.later(); +Object.seal(sealed); +console.log(Object.isSealed(sealed), Object.isFrozen(sealed), sealed[tag], sealed.w); +console.log(JSON.stringify(Object.getOwnPropertyDescriptor(sealed, tag))); + +const closed = new Box(4); +Object.preventExtensions(closed); +console.log(Object.isExtensible(closed), Object.isSealed(closed), closed[tag]); From 1547fd47cd31249b0417a5237f5c79d8fbb0d518 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 20:10:29 -0500 Subject: [PATCH 188/259] Keep record factory parameters that a closure in the record captures findRecordFieldProducers counted only direct reads of a parameter, so a factory such as `(text) => ({ text, upper: () => text.toUpperCase() })` counted as storing `text` only in its field. A caller's slice passed to it was written into a stack buffer, and the closure kept by the caller then read whatever the next iteration wrote there. Captures by closures and classes now count as reads, so such a factory is not a producer. --- .../src/backend/llvm/string-slices.test.ts | 17 ++++++++++++++- .../src/backend/llvm/string-slices.ts | 3 +++ tests/corpus/8114-record-field-slices.ts | 21 +++++++++++++++++-- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/packages/compiler/src/backend/llvm/string-slices.test.ts b/packages/compiler/src/backend/llvm/string-slices.test.ts index 43bec955a..e53bf38c6 100644 --- a/packages/compiler/src/backend/llvm/string-slices.test.ts +++ b/packages/compiler/src/backend/llvm/string-slices.test.ts @@ -365,17 +365,32 @@ test.each([ "escapes-callee", "captured", "producer-reuse", + "producer-capture", ])("a slice stored in a record that may be kept (%s) stays owned", (reason) => { + // The factory also stores a closure over its text parameter. + const capturing = producerHelper("capturing"); + const literal = (capturing.body[0] as IrStmt & { kind: "return" }).value as IrExpr & { + kind: "recordLit"; + }; + literal.fields.push({ + name: "get", + value: { kind: "closure", fnName: "get", captures: ["text"], type: F64, loc }, + }); const helpers = [ reads, keepsText, escapes, producerHelper("make"), producerHelper("twice", [keepIn(ref("text"))]), + capturing, ]; const init = slice("source", 1, 5); const declare = - reason === "producer-reuse" ? callOf("twice", ref("word")) : tokenLit(ref("word")); + reason === "producer-reuse" + ? callOf("twice", ref("word")) + : reason === "producer-capture" + ? callOf("capturing", ref("word")) + : tokenLit(ref("word")); if (declare.kind === "call") declare.type = TOKEN; const uses: IrStmt[] = [{ kind: "exprStmt", expr: equals(textOf(record("tok"))), loc }]; if (reason === "kept-field") uses.push(keepIn(textOf(record("tok")))); diff --git a/packages/compiler/src/backend/llvm/string-slices.ts b/packages/compiler/src/backend/llvm/string-slices.ts index 81a4a5a3e..d1bb197ee 100644 --- a/packages/compiler/src/backend/llvm/string-slices.ts +++ b/packages/compiler/src/backend/llvm/string-slices.ts @@ -419,6 +419,9 @@ export function findRecordFieldProducers( everyStmtList(fn.body, { expr: (value) => { if (value.kind === "varRef") reads.set(value.localId, (reads.get(value.localId) ?? 0) + 1); + // A closure or class that captures a parameter keeps it too. + if (value.kind === "closure" || value.kind === "classRef") + for (const id of value.captures ?? []) reads.set(id, (reads.get(id) ?? 0) + 1); return true; }, stmt: () => true, diff --git a/tests/corpus/8114-record-field-slices.ts b/tests/corpus/8114-record-field-slices.ts index 69d41a1c8..110cd3acb 100644 --- a/tests/corpus/8114-record-field-slices.ts +++ b/tests/corpus/8114-record-field-slices.ts @@ -2,8 +2,9 @@ // whose fields are only read for their length, comparisons and keyword // searches, next to records that are kept after the iteration that built // them (pushed into an array, held in an outer binding, captured by a -// closure, read into a kept array, returned from a helper). Slices of -// non-ASCII text and slices longer than a short token are included. +// closure, read into a kept array, returned from a helper, captured by a +// closure the factory stores beside it). Slices of non-ASCII text and slices +// longer than a short token are included. interface Token { kind: string; text: string; @@ -16,6 +17,15 @@ function token(kind: string, text: string, pos: number): Token { return { kind, text, pos }; } +interface LazyToken { + text: string; + upper: () => string; +} + +function lazyToken(text: string): LazyToken { + return { text, upper: () => text.toUpperCase() }; +} + function classify(text: string): string { return KEYWORDS.includes(text) ? "keyword" : "ident"; } @@ -74,6 +84,8 @@ function keptTokens(source: string): string { const texts: string[] = []; const later: (() => string)[] = []; const returned: string[] = []; + const uppers: (() => string)[] = []; + let lazyLength = 0; let last: Token | null = null; for (let i = 0, start = -1; i <= source.length; i++) { const c = i < source.length ? source.charCodeAt(i) : 32; @@ -93,6 +105,10 @@ function keptTokens(source: string): string { later.push(() => captured.text); const viaHelper = token("helper", source.slice(start, i), start); returned.push(textOf(viaHelper)); + const lazyText = source.slice(start, i); + const lazy = lazyToken(lazyText); + lazyLength += lazy.text.length; + uppers.push(lazy.upper); start = -1; } return [ @@ -101,6 +117,7 @@ function keptTokens(source: string): string { `texts ${texts.join("|")}`, `later ${later.map((f) => f()).join("|")}`, `returned ${returned.join("|")}`, + `upper ${lazyLength} ${uppers.map((f) => f()).join("|")}`, ].join("\n"); } From d64f18d2a8e17539afef33f4d3019c0c0cb7c584 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 20:11:25 -0500 Subject: [PATCH 189/259] Evaluate constructor arguments before the class-value check `new kinds[i](args)` over an array of class values read the element and narrowed it to the class value before the arguments ran, so an index past the end threw "is not a constructor" without evaluating them. JavaScript evaluates the arguments first: the construction is now a call of a lifted helper (checkedElementConstruction) that takes the element read and the arguments, in that order, then runs the check and constructs. Keeping the arguments in one call also keeps a spread's argument pack alive until every argument has read it. A checked class-value boundary accepted every subclass's class value into a base class's slot, so construction through the slot could call a subclass constructor that takes different arguments with the base constructor's. It now accepts only the subclasses whose class-value constructor takes the same arguments (classValueAbiEquals, the rule the classval upcast validator already applied); any other subclass fails the check with a TypeError. --- packages/compiler/src/backend/llvm/dyn.ts | 10 +- packages/compiler/src/backend/llvm/emitter.ts | 26 ++-- .../src/frontend/lowering/lower-classes.ts | 113 +++++++++++++++--- packages/compiler/src/ir/ir.ts | 22 ++++ packages/compiler/src/ir/validate.ts | 21 ++-- tests/corpus/6937-class-value-arrays.mjs | 23 ++++ tests/corpus/6938-class-value-arrays.ts | 20 ++++ 7 files changed, 198 insertions(+), 37 deletions(-) diff --git a/packages/compiler/src/backend/llvm/dyn.ts b/packages/compiler/src/backend/llvm/dyn.ts index 1d2a14964..24db045c8 100644 --- a/packages/compiler/src/backend/llvm/dyn.ts +++ b/packages/compiler/src/backend/llvm/dyn.ts @@ -174,6 +174,10 @@ export interface DynHost extends WalkerHost { dynPromiseAdapter(t: IrType): string; isErrorClass(className: string): boolean; classSubtypes(className: string): readonly string[]; + /** The strict subclasses whose class-value constructor takes the same + * arguments as `className`'s (classValueAbiEquals): the class values a + * checked `classval` slot accepts besides its own class. */ + classValueSubtypes(className: string): readonly string[]; /** emitter.ts's pendingTestLines: the inline pending-exception test. */ pendingTestLines(dest: string): string[]; } @@ -1808,8 +1812,10 @@ export class LlDyn { const B = new BlockBuilder(); if (t.kind === "classval") { host.declare(`declare ptr @scr_dyn_class_check(ptr, ptr, ptr)`); - // A subclass's class value checks into the base class's slot. - const subclasses = host.classSubtypes(t.className).filter((name) => name !== t.className); + // A subclass's class value checks into the base class's slot when + // construction through the slot can call its thunk with the base + // constructor's arguments; any other subclass fails the check. + const subclasses = host.classValueSubtypes(t.className); if (subclasses.length > 0) { host.declare(`declare zeroext i1 @scr_dyn_class_is(ptr, ptr)`); for (const className of subclasses) { diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index 6760f3b74..26641c667 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -55,6 +55,7 @@ import { typeKey, VOID, classJsName, + classValueAbiEquals, } from "../../ir/ir.js"; import { moduleRuntimeFeatures, type RuntimeFeatures } from "../../ir/runtime-features.js"; import { captureFreeFunctions, observesStacks } from "../stack-observations.js"; @@ -1895,14 +1896,14 @@ export class LlEmitter { const meta = this.classMeta.get(t.className); return meta !== undefined && programLifetimeClass(this.shapeHost, meta); }, - classSubtypes: (name) => { - const target = this.classMetaOf(name); - const intervals = classMembershipIntervals(this.classMeta, target.def.name); - return [...this.classMeta.values()] - .filter((meta) => - intervals.some((range) => range.pre <= meta.pre && meta.pre <= range.post), - ) - .map((meta) => meta.def.name); + classSubtypes: (name) => this.classSubtypes(name), + classValueSubtypes: (name) => { + const target = this.classMetaOf(name).def; + return this.classSubtypes(name).filter( + (sub) => + sub !== target.name && + classValueAbiEquals(this.classMetaOf(sub).def, target, this.fnByName), + ); }, pendingTestLines: (dest) => this.pendingTestLines(dest), virtualEntry: (implFn) => this.virtualEntry(implFn), @@ -3965,6 +3966,15 @@ export class LlEmitter { // ── class plumbing ────────────────────────────────────────────────────── + /** `name` and every class whose membership interval falls in its own. */ + private classSubtypes(name: string): string[] { + const target = this.classMetaOf(name); + const intervals = classMembershipIntervals(this.classMeta, target.def.name); + return [...this.classMeta.values()] + .filter((meta) => intervals.some((range) => range.pre <= meta.pre && meta.pre <= range.post)) + .map((meta) => meta.def.name); + } + classMetaOf(className: string): LlClassMeta { const meta = this.classMeta.get(className); if (!meta) throw new InternalCompilerError(`llvm emitter bug: unknown class ${className}`); diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index a91b3c30a..e1b4e890e 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -9782,6 +9782,75 @@ function assignedThisFieldType(lowerer: Lowerer, expr: ts.NewExpression): IrType return lowerer.currentClass?.fields.get(parent.left.name.text) ?? null; } +/** An array element read that construction narrows to a class value with a + * check (`%new.callee`, which throws "is not a constructor"). */ +interface NarrowedConstructorRead { + read: IrExpr; + check: string; + unionT: IrType & { kind: "union" }; + calleeT: IrType & { kind: "classval" }; + message: IrExpr; +} + +/** `new arr[i](args)` through a narrowed element read: an interned lifted + * function takes the read and the completed arguments, which evaluate in + * that order as call arguments, then runs the check and constructs. JS + * evaluates the arguments before it checks that the callee constructs, and + * the arguments stay in the one call, where a spread's argument pack lives + * until every argument has read it. */ +function checkedElementConstruction( + lowerer: Lowerer, + info: ClassInfo, + narrowed: NarrowedConstructorRead, + args: IrExpr[], + loc: SrcLoc, +): IrExpr { + const type: IrType = { kind: "object", className: info.def.name }; + const key = `newChecked:${narrowed.check}:${info.def.name}:${args.map((a) => typeKey(a.type)).join(",")}`; + let name = lowerer.valueHelpers.get(key); + if (!name) { + name = keyedHelperName(lowerer, "%new.checked", key); + lowerer.valueHelpers.set(key, name); + const params: IrParam[] = [ + { localId: "value", name: "value", type: narrowed.unionT }, + { localId: "message", name: "message", type: STRING }, + ...args.map((arg, i) => ({ localId: `arg.${i}`, name: `arg${i}`, type: arg.type })), + ]; + lowerer.liftedFns.push({ + name, + params, + returnType: type, + locals: params.map((p) => ({ id: p.localId, name: p.name, type: p.type, mutable: false })), + body: [ + { + kind: "return", + value: { + kind: "newValue", + callee: { + kind: "call", + callee: narrowed.check, + args: [varRef("value", narrowed.unionT, loc), varRef("message", STRING, loc)], + type: narrowed.calleeT, + loc, + }, + args: params.slice(2).map((p) => varRef(p.localId, p.type, loc)), + type, + loc, + }, + loc, + }, + ], + loc, + }); + } + return { + kind: "call", + callee: name, + args: [narrowed.read, narrowed.message, ...args], + type, + loc, + }; +} /** Map, Set and the error classes construct in lowerNew's identifier * branch, which a module member alias of one (`new mod.M()`) also takes. */ function isCollectionOrErrorClass(ref: BuiltinClassRef | null): boolean { @@ -11045,6 +11114,9 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { } let callee = lowerer.lowerExpr(expr.expression); if (callee.type.kind === "dyn") return lowerCheckedConstructor(lowerer, expr, callee); + /** The union-typed element read a narrowing check guards, and the + * check (`%new.callee`) that yields the class value or throws. */ + let narrowedCallee: NarrowedConstructorRead | null = null; // An array element read (`new T[0]()` over `[Dog, Animal]`, whose // checker type is the common base) keeps the undefined an index past // the end reads: the class value is narrowed out with a check, which @@ -11118,18 +11190,25 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { loc, }); } + // JavaScript evaluates the arguments before it checks that the + // callee constructs, so the check runs at the construction + // (checkedElementConstruction). + narrowedCallee = { + read: callee, + check: name, + unionT, + calleeT, + message: { + kind: "strLit", + value: `${expr.expression.getText()} is not a constructor`, + type: STRING, + loc, + }, + }; callee = { kind: "call", callee: name, - args: [ - callee, - { - kind: "strLit", - value: `${expr.expression.getText()} is not a constructor`, - type: STRING, - loc, - }, - ], + args: [callee, narrowedCallee.message], type: calleeT, loc, }; @@ -11175,13 +11254,15 @@ export function lowerNew(lowerer: Lowerer, expr: ts.NewExpression): IrExpr { const built = constructedFromValue( lowerer, info, - { - kind: "newValue", - callee, - args, - type: { kind: "object", className: info.def.name }, - loc, - }, + narrowedCallee !== null + ? checkedElementConstruction(lowerer, info, narrowedCallee, args, loc) + : { + kind: "newValue", + callee, + args, + type: { kind: "object", className: info.def.name }, + loc, + }, expr, ); // A runtime class slot widened from a union (`[Readable, Writable]`'s diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index 3818433f8..b936e265e 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -1630,6 +1630,28 @@ export function classValueConstructor(def: { name: string; runtime?: true }): { : { fn: `%${def.name}.constructor`, firstArg: 1 }; } +/** Whether construction through a class value typed as `sup` may call + * `sub`'s construct thunk: both class-value constructors exist and take the + * same argument types after the receiver. The classval upcast rule and the + * checked class-value boundary both rest on it. */ +export function classValueAbiEquals( + sub: { name: string; runtime?: true }, + sup: { name: string; runtime?: true }, + functions: ReadonlyMap, +): boolean { + const subValueCtor = classValueConstructor(sub); + const supValueCtor = classValueConstructor(sup); + const subCtor = functions.get(subValueCtor.fn); + const supCtor = functions.get(supValueCtor.fn); + if (!subCtor || !supCtor) return false; + const subArgs = subCtor.params.slice(subValueCtor.firstArg); + const supArgs = supCtor.params.slice(supValueCtor.firstArg); + return ( + subArgs.length === supArgs.length && + subArgs.every((p, i) => typeEquals(p.type, supArgs[i]!.type)) + ); +} + /** The JavaScript `.name` of a class: its jsName, or the runtime-provided * class's own name (`%TypeError` is TypeError). */ export function classJsName(def: { name: string; runtime?: true; jsName?: string }): string { diff --git a/packages/compiler/src/ir/validate.ts b/packages/compiler/src/ir/validate.ts index 5bae241b1..928b1647b 100644 --- a/packages/compiler/src/ir/validate.ts +++ b/packages/compiler/src/ir/validate.ts @@ -58,7 +58,12 @@ import { unionContainerArmsOk, VOID, } from "./ir.js"; -import { DYN_CLASS_PROPERTIES, callSiteReturnType, classValueConstructor } from "./ir.js"; +import { + DYN_CLASS_PROPERTIES, + callSiteReturnType, + classValueAbiEquals, + classValueConstructor, +} from "./ir.js"; import { unionWideningTags } from "./analysis.js"; import { alwaysReturns } from "./control-flow.js"; import { dynamicOperationOf, functionTier } from "./tiers.js"; @@ -2997,19 +3002,13 @@ function validateFunction( } const subClass = classes.get(sub); const supClass = classes.get(sup); - const subValueCtor = subClass ? classValueConstructor(subClass) : null; - const supValueCtor = supClass ? classValueConstructor(supClass) : null; - const subCtor = subValueCtor ? functions.get(subValueCtor.fn) : undefined; - const supCtor = supValueCtor ? functions.get(supValueCtor.fn) : undefined; - if (!subCtor || !supCtor || !subValueCtor || !supValueCtor) { + const subCtor = subClass ? functions.get(classValueConstructor(subClass).fn) : undefined; + const supCtor = supClass ? functions.get(classValueConstructor(supClass).fn) : undefined; + if (!subClass || !supClass || !subCtor || !supCtor) { err(`classval upcast: "${sub}"/"${sup}" lack constructor functions`, e.loc); break; } - const subArgs = subCtor.params.slice(subValueCtor.firstArg); - const supArgs = supCtor.params.slice(supValueCtor.firstArg); - const abiEqual = - subArgs.length === supArgs.length && - subArgs.every((p, i) => typeEquals(p.type, supArgs[i]!.type)); + const abiEqual = classValueAbiEquals(subClass, supClass, functions); if (!abiEqual) { err(`classval upcast: "${sub}" and "${sup}" constructor ABIs differ`, e.loc); } diff --git a/tests/corpus/6937-class-value-arrays.mjs b/tests/corpus/6937-class-value-arrays.mjs index a563d7514..8fcfcb815 100644 --- a/tests/corpus/6937-class-value-arrays.mjs +++ b/tests/corpus/6937-class-value-arrays.mjs @@ -28,3 +28,26 @@ try { } const byName = { dog: Dog, cat: Cat }; console.log(new byName.dog().speak(), new byName["cat"]().speak()); +// The arguments are evaluated before the missing element throws. +class Point { + constructor(x, y) { + this.sum = x + y; + } +} +class Point3 extends Point {} +const points = [Point3, Point]; +const evaluated = []; +const arg = (v) => (evaluated.push(v), v); +console.log(new points[0](arg(1), arg(2)).sum, evaluated.join()); +try { + new points[2](arg(3), arg(4)); +} catch (e) { + console.log(e.name, e.message, evaluated.join()); +} +// Spread arguments too, through a valid index and past the end. +console.log(new points[1](...[5, 6]).sum); +try { + new points[3](...[arg(7), arg(8)]); +} catch (e) { + console.log(e.name, e.message, evaluated.join()); +} diff --git a/tests/corpus/6938-class-value-arrays.ts b/tests/corpus/6938-class-value-arrays.ts index 672700cbf..db695bc0a 100644 --- a/tests/corpus/6938-class-value-arrays.ts +++ b/tests/corpus/6938-class-value-arrays.ts @@ -26,3 +26,23 @@ try { } catch (e) { console.log((e as Error).name, (e as Error).message); } +// A class value checked into a `typeof Shape` slot: a subclass whose +// constructor takes the same arguments constructs, and one whose constructor +// takes an argument the slot does not pass throws a TypeError (Node's from +// reading the missing argument, the compiled program's from the check). +class Sized extends Shape { + label: string; + constructor(side: number) { + super(); + this.label = side.toFixed(1); + } +} +const values: any[] = [Square, Sized, Shape]; +for (const value of values) { + try { + const S: typeof Shape = value; + console.log(new S().area()); + } catch (e) { + console.log((e as Error).name); + } +} From 120c65bfbbd3c3298dc0232aacc5a3b2e85c8e08 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 20:24:11 -0500 Subject: [PATCH 190/259] Read an iterator's next once, and await return()'s value in for await JavaScript reads an iterator's `next` when the iterator opens and keeps calling that function, so a `next` the iterator assigns while it runs is not called. The for-of loop and the spread drain over an object-literal iterator read the field on every step; they now read it once after the open (classIteratorNextRead) and call the function they read. The checked-dynamic spread drain (%iterator.pack.checked) does the same, using the stepping the for-of and Array.from drains already use. `for await` over a synchronous iterator closes it on an early exit the way the async-from-sync iterator does: return()'s result is read for done and value, and the value is awaited, so a pending promise settles before the loop continues and a rejected one rejects the loop (after a throw from the body, the body's error still wins). --- .../lowering/expressions/array-literals.ts | 123 ++++++++++++++---- .../src/frontend/lowering/lower-classes.ts | 45 ++++++- .../src/frontend/lowering/lower-stmts.ts | 41 +++++- .../src/frontend/lowering/lower-stream.ts | 2 +- .../compiler/src/frontend/lowering/lowerer.ts | 14 +- tests/corpus/6928-class-iterator-protocol.ts | 19 +++ tests/corpus/6929-class-iterator-protocol.mjs | 19 +++ .../6935-class-async-iterator-protocol.ts | 40 ++++++ .../6936-class-async-iterator-protocol.mjs | 39 ++++++ 9 files changed, 306 insertions(+), 36 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/expressions/array-literals.ts b/packages/compiler/src/frontend/lowering/expressions/array-literals.ts index 6153b87f2..09f3e1a2c 100644 --- a/packages/compiler/src/frontend/lowering/expressions/array-literals.ts +++ b/packages/compiler/src/frontend/lowering/expressions/array-literals.ts @@ -29,9 +29,10 @@ import { lowerCollectionSpread } from "../containers/collection-methods.js"; import { strCharsCall } from "../containers/array-construction.js"; import { generatorDrain } from "../iterator-adapters.js"; import { isSearchParamsIterable } from "../builtins/url.js"; -import { varRef } from "../../../ir/build.js"; +import { dynUndefinedExpr, varRef } from "../../../ir/build.js"; import { arrayValueStore } from "../array-values.js"; import { classGeneratorIterable } from "../class-iterables.js"; +import { iteratorCanStep } from "../iterator-consumption.js"; /** JavaScript: whether `expr` is or holds an existing checked-dynamic * object — a binding stored as a dyn value whose checker type is an @@ -717,13 +718,17 @@ function lowerTupleSpreadLiteral( return { kind: "seqExpr", stmts, result: { kind: "recordLit", fields, type, loc }, type, loc }; } -/** Drain using checked dispatch so native class and generator iterators keep their methods. - * `spell` is the TypeError message for a source that is not iterable - * (notIterableSpelling). */ +/** Drain a checked-dynamic iterable: `next` is read once when the iterator + * opens, as JS keeps it in the iterator record, so a `next` the iterator + * assigns while it runs is not called. Runtime iterators step natively, and + * other iterators call the `next` read (class methods keep their emitted + * dispatch). `spell` is the TypeError message for a source that is not + * iterable (notIterableSpelling). */ function checkedIteratorPack(lowerer: Lowerer, source: IrExpr, spell: string, loc: SrcLoc): IrExpr { const name = "%iterator.pack.checked"; if (!lowerer.liftedFns.some((fn) => fn.name === name)) { const ref = (id: string): IrExpr => ({ kind: "varRef", localId: id, type: DYN, loc }); + const flag = (id: string): IrExpr => ({ kind: "varRef", localId: id, type: BOOL, loc }); const property = (key: string): IrExpr => ({ kind: "dynKeyGet", value: ref("step"), @@ -731,6 +736,7 @@ function checkedIteratorPack(lowerer: Lowerer, source: IrExpr, spell: string, lo type: DYN, loc, }); + const finished: IrStmt = { kind: "return", value: ref("result"), loc }; lowerer.liftedFns.push({ name, params: [ @@ -739,12 +745,13 @@ function checkedIteratorPack(lowerer: Lowerer, source: IrExpr, spell: string, lo ], returnType: DYN, locals: [ - ...["source", "iterator", "step", "result"].map((id) => ({ + ...["source", "iterator", "next", "step", "value", "result"].map((id) => ({ id, name: id, type: DYN, mutable: id !== "source", })), + { id: "fast", name: "fast", type: BOOL, mutable: false }, { id: "spell", name: "spell", type: STRING, mutable: false }, ], body: [ @@ -760,6 +767,24 @@ function checkedIteratorPack(lowerer: Lowerer, source: IrExpr, spell: string, lo }, loc, }, + { + kind: "varDecl", + localId: "next", + init: { + kind: "dynKeyGet", + value: ref("iterator"), + key: { kind: "strLit", value: "next", type: STRING, loc }, + type: DYN, + loc, + }, + loc, + }, + { + kind: "varDecl", + localId: "fast", + init: iteratorCanStep(ref("iterator"), ref("next"), loc), + loc, + }, { kind: "varDecl", localId: "result", @@ -770,25 +795,77 @@ function checkedIteratorPack(lowerer: Lowerer, source: IrExpr, spell: string, lo kind: "while", cond: { kind: "boolLit", value: true, type: BOOL, loc }, body: [ - { - kind: "varDecl", - localId: "step", - init: { - kind: "dynInvoke", - recv: ref("iterator"), - method: "next", - calleeName: "iterator.next", - args: [], - type: DYN, - loc, - }, - loc, - }, + // Declared before the branches, which each assign it: a local + // declared in a branch is released when the branch ends. + { kind: "varDecl", localId: "value", init: dynUndefinedExpr(loc), loc }, { kind: "if", - cond: { kind: "dynTest", test: "truthy", value: property("done"), type: BOOL, loc }, - then: [{ kind: "return", value: ref("result"), loc }], - else_: null, + cond: flag("fast"), + then: [ + { + kind: "assign", + localId: "value", + value: { + kind: "libCall", + fn: "dyn.iteratorStep", + args: [ref("iterator")], + type: DYN, + loc, + }, + loc, + }, + { + kind: "if", + cond: { + kind: "libCall", + fn: "dyn.iteratorStepDone", + args: [ref("iterator")], + type: BOOL, + loc, + }, + then: [finished], + else_: null, + loc, + }, + ], + else_: [ + { + kind: "varDecl", + localId: "step", + init: { + kind: "libCall", + fn: "dyn.iteratorResult", + args: [ + { + kind: "dynCall", + callee: ref("next"), + receiver: ref("iterator"), + calleeName: "iterator.next", + args: [], + type: DYN, + loc, + }, + ], + type: DYN, + loc, + }, + loc, + }, + { + kind: "if", + cond: { + kind: "dynTest", + test: "truthy", + value: property("done"), + type: BOOL, + loc, + }, + then: [finished], + else_: null, + loc, + }, + { kind: "assign", localId: "value", value: property("value"), loc }, + ], loc, }, { @@ -796,7 +873,7 @@ function checkedIteratorPack(lowerer: Lowerer, source: IrExpr, spell: string, lo expr: { kind: "libCall", fn: "dyn.packPush", - args: [ref("result"), property("value")], + args: [ref("result"), ref("value")], type: VOID, loc, }, diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index 9d994b76b..2e077bfcf 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -8016,15 +8016,42 @@ export function classIteratorOf( }; } -/** The `it.next()` step of a class iterator as an ordinary (possibly - * virtual) method call. */ -export function classIteratorNextCall( +/** The `next` an object-literal iterator's protocol calls, read once when + * the iterator opens: JS keeps the `next` it reads then in the iterator + * record, so a `next` the iterator assigns while it runs is not called. + * Null for an iterator class, whose `next` is a method. */ +export function classIteratorNextRead( lowerer: Lowerer, cit: ClassIteratorInfo, itRef: IrExpr, loc: SrcLoc, +): (IrExpr & { type: IrType & { kind: "func" } }) | null { + const iterT = cit.iterT; + if (iterT.kind === "object") return null; + const field = lowerer.shapes.get(iterT.shapeId)!.fields.find((f) => f.name === "next")!; + return { + kind: "recordGet", + obj: itRef, + shapeId: iterT.shapeId, + field: "next", + type: field.type as IrType & { kind: "func" }, + loc, + }; +} + +/** The `it.next()` step of a class iterator: an ordinary (possibly + * virtual) method call, or the call of `next`, the object-literal + * iterator's `next` that classIteratorNextRead read when it opened. */ +export function classIteratorNextCall( + lowerer: Lowerer, + cit: ClassIteratorInfo, + itRef: IrExpr, + next: IrExpr | null, + loc: SrcLoc, ): IrExpr { - return classIteratorMethodCall(lowerer, cit, "next", itRef, loc); + if (next === null || next.type.kind !== "func") + return classIteratorMethodCall(lowerer, cit, "next", itRef, loc); + return { kind: "callValue", callee: next, args: [], type: next.type.ret, loc }; } /** `it.next()` or `it.return()` of a class iterator: a (possibly virtual) @@ -8108,6 +8135,8 @@ export function classIteratorDrainCall( const recvT: IrType = { kind: "object", className: cit.className }; const recvRef: IrExpr = { kind: "varRef", localId: "r.0", type: recvT, loc }; const itRef: IrExpr = { kind: "varRef", localId: "it.0", type: cit.iterT, loc }; + const nextRead = classIteratorNextRead(lowerer, cit, itRef, loc); + const nextRef: IrExpr | null = nextRead ? varRef("next.0", nextRead.type, loc) : null; const outRef: IrExpr = { kind: "varRef", localId: "out.0", type: outT, loc }; const resRef: IrExpr = { kind: "varRef", localId: "res.0", type: cit.resultT, loc }; const valueRead: IrExpr = { @@ -8122,7 +8151,7 @@ export function classIteratorDrainCall( { kind: "varDecl", localId: "res.0", - init: classIteratorNextCall(lowerer, cit, itRef, loc), + init: classIteratorNextCall(lowerer, cit, itRef, nextRef, loc), loc, }, ...(cit.hasDone @@ -8163,6 +8192,7 @@ export function classIteratorDrainCall( locals: [ { id: "r.0", name: "r", type: recvT, mutable: false }, { id: "it.0", name: "it", type: cit.iterT, mutable: false }, + ...(nextRead ? [{ id: "next.0", name: "next", type: nextRead.type, mutable: false }] : []), { id: "out.0", name: "out", type: outT, mutable: false }, { id: "res.0", name: "res", type: cit.resultT, mutable: true }, ], @@ -8179,6 +8209,9 @@ export function classIteratorDrainCall( init: classIteratorOpenCall(lowerer, cit, recvRef, loc), loc, }, + ...(nextRead + ? [{ kind: "varDecl", localId: "next.0", init: nextRead, loc } satisfies IrStmt] + : []), { kind: "while", cond: { kind: "boolLit", value: true, type: BOOL, loc }, @@ -8226,7 +8259,7 @@ export function classIteratorRestDrainCall( { kind: "varDecl", localId: "res.0", - init: classIteratorNextCall(lowerer, cit, itRef, loc), + init: classIteratorNextCall(lowerer, cit, itRef, null, loc), loc, }, ...(cit.hasDone diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index bee887e0f..b942a538b 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -2578,7 +2578,7 @@ export function lowerBindingPattern( const itRef = (): IrExpr => ({ kind: "varRef", localId: it.id, type: citPat.iterT, loc }); for (const el of pattern.elements.nodes) { const stepLoc = locOf(el); - const step = lowerer.classIteratorNextCall(citPat, itRef(), stepLoc); + const step = lowerer.classIteratorNextCall(citPat, itRef(), null, stepLoc); if (ts.isOmittedExpression(el) || el.name === undefined) { out.push({ kind: "exprStmt", expr: step, loc: stepLoc }); continue; @@ -10726,6 +10726,8 @@ function lowerForOfClassIterator( const r = lowerer.declareHiddenLocal("%cir", cit.resultT); const recvRef: IrExpr = { kind: "varRef", localId: recv.id, type: iterable.type, loc }; const itRef = (): IrExpr => ({ kind: "varRef", localId: it.id, type: cit.iterT, loc }); + const nextRead = lowerer.classIteratorNextRead(cit, itRef(), loc); + const next = nextRead ? lowerer.declareHiddenLocal("%cin", nextRead.type) : null; const rRef = (): IrExpr => ({ kind: "varRef", localId: r.id, type: cit.resultT, loc }); const done = cit.hasReturn ? lowerer.declareHiddenLocal("%cid", BOOL) : null; if (done) done.mutable = true; @@ -10756,7 +10758,12 @@ function lowerForOfClassIterator( { kind: "varDecl", localId: r.id, - init: lowerer.classIteratorNextCall(cit, itRef(), loc), + init: lowerer.classIteratorNextCall( + cit, + itRef(), + next ? varRef(next.id, next.type, loc) : null, + loc, + ), loc, }, ...(cit.hasDone @@ -10820,6 +10827,9 @@ function lowerForOfClassIterator( init: lowerer.classIteratorOpenCall(cit, recvRef, loc), loc, }, + ...(next && nextRead + ? [{ kind: "varDecl", localId: next.id, init: nextRead, loc } satisfies IrStmt] + : []), ...(done ? [ { @@ -10887,6 +10897,7 @@ function lowerForOfDyn( done.mutable = true; const value = lowerer.declareHiddenLocal("%dofValue", DYN); const returned = lowerer.declareHiddenLocal("%dofReturn", DYN); + const closed = lowerer.declareHiddenLocal("%dofClosed", DYN); const needsClose = lowerer.declareHiddenLocal("%dofNeedsClose", BOOL); needsClose.mutable = true; const error = lowerer.declareHiddenLocal("%dofError", CAUGHT); @@ -10952,9 +10963,10 @@ function lowerForOfDyn( }, then: [ { - kind: "exprStmt", + kind: "varDecl", + localId: closed.id, // return()'s (awaited) result must be an object, as for next(). - expr: asyncLoop + init: asyncLoop ? check( awaitDyn({ kind: "dynCall", @@ -10969,6 +10981,27 @@ function lowerForOfDyn( : call(varRef(returned.id, DYN, loc)), loc, }, + // A synchronous iterator's return() result is read as the + // async-from-sync iterator reads it: done, then the value, which is + // awaited, so a rejected promise there rejects the loop. + ...(syncIterator + ? [ + { + kind: "if", + cond: varRef(syncIterator.id, BOOL, loc), + then: [ + { kind: "exprStmt", expr: get(varRef(closed.id, DYN, loc), "done"), loc }, + { + kind: "exprStmt", + expr: awaitDyn(get(varRef(closed.id, DYN, loc), "value")), + loc, + }, + ], + else_: null, + loc, + } satisfies IrStmt, + ] + : []), ], else_: null, loc, diff --git a/packages/compiler/src/frontend/lowering/lower-stream.ts b/packages/compiler/src/frontend/lowering/lower-stream.ts index 90bdf917e..e17dee274 100644 --- a/packages/compiler/src/frontend/lowering/lower-stream.ts +++ b/packages/compiler/src/frontend/lowering/lower-stream.ts @@ -1982,7 +1982,7 @@ function classIteratorObject( { kind: "varDecl", localId: r.id, - init: classIteratorNextCall(lowerer, cit, varRef(it.id, cit.iterT, loc), loc), + init: classIteratorNextCall(lowerer, cit, varRef(it.id, cit.iterT, loc), null, loc), loc, }, { diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index ea503e1f1..76c4e5c0d 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -362,6 +362,7 @@ import { classIteratorDrainCall, classIteratorMethodCall, classIteratorNextCall, + classIteratorNextRead, classIteratorOf, classIteratorOpenCall, classIteratorRestDrainCall, @@ -13063,8 +13064,17 @@ export class Lowerer { return classIteratorOpenCall(this, cit, recv, loc); } - classIteratorNextCall(cit: ClassIteratorInfo, itRef: IrExpr, loc: SrcLoc): IrExpr { - return classIteratorNextCall(this, cit, itRef, loc); + classIteratorNextRead(cit: ClassIteratorInfo, itRef: IrExpr, loc: SrcLoc): IrExpr | null { + return classIteratorNextRead(this, cit, itRef, loc); + } + + classIteratorNextCall( + cit: ClassIteratorInfo, + itRef: IrExpr, + next: IrExpr | null, + loc: SrcLoc, + ): IrExpr { + return classIteratorNextCall(this, cit, itRef, next, loc); } classIteratorDrainCall(src: IrExpr, loc: SrcLoc, elemT?: IrType): IrExpr | null { diff --git a/tests/corpus/6928-class-iterator-protocol.ts b/tests/corpus/6928-class-iterator-protocol.ts index f097368de..2c2eecccc 100644 --- a/tests/corpus/6928-class-iterator-protocol.ts +++ b/tests/corpus/6928-class-iterator-protocol.ts @@ -91,3 +91,22 @@ class Range { let total = 0; for (const v of new Range(4)) total += v; console.log(total, [...new Range(3)].join()); + +// An object-literal iterator that replaces its next() while it runs: the +// loop and the spread keep calling the next() they read when it opened. +class Swapping { + [Symbol.iterator]() { + let i = 0; + const it = { + next(): { value: number; done: boolean } { + i++; + if (i === 2) it.next = () => ({ value: -1, done: true }); + return { value: i, done: i > 4 }; + }, + }; + return it; + } +} +const swapped: number[] = []; +for (const v of new Swapping()) swapped.push(v); +console.log(swapped.join(), [...new Swapping()].join()); diff --git a/tests/corpus/6929-class-iterator-protocol.mjs b/tests/corpus/6929-class-iterator-protocol.mjs index b5255ba35..6a7827f15 100644 --- a/tests/corpus/6929-class-iterator-protocol.mjs +++ b/tests/corpus/6929-class-iterator-protocol.mjs @@ -76,3 +76,22 @@ try { } catch (e) { console.log("throw:", e.message); } + +// An object-literal iterator that replaces its next() while it runs: the +// loop and the spread keep calling the next() they read when it opened. +class Swapping { + [Symbol.iterator]() { + let i = 0; + const it = { + next() { + i++; + if (i === 2) it.next = () => ({ value: -1, done: true }); + return { value: i, done: i > 4 }; + }, + }; + return it; + } +} +const swapped = []; +for (const v of new Swapping()) swapped.push(v); +console.log(swapped.join(), [...new Swapping()].join()); diff --git a/tests/corpus/6935-class-async-iterator-protocol.ts b/tests/corpus/6935-class-async-iterator-protocol.ts index 9ec5a61a5..25626a773 100644 --- a/tests/corpus/6935-class-async-iterator-protocol.ts +++ b/tests/corpus/6935-class-async-iterator-protocol.ts @@ -56,5 +56,45 @@ async function main(): Promise { console.log("found", await find()); for await (const p of new Pages()) console.log(p); for await (const l of new Letters()) console.log("letter", l); + // return()'s value is awaited when the loop leaves early: a pending + // promise settles first, and a rejection rejects the loop after a break + // (after a throw from the body, the body's error wins). + for await (const v of new Closing((resolve) => setTimeout(() => resolve(1), 5))) + if (v === 1) break; + console.log("after break"); + try { + for await (const v of new Closing((_, reject) => reject(new Error("closing failed")))) + if (v === 1) break; + } catch (e) { + console.log("break:", (e as Error).message); + } + try { + for await (const v of new Closing((_, reject) => reject(new Error("closing failed")))) + if (v === 1) throw new Error("body failed"); + } catch (e) { + console.log("throw:", (e as Error).message); + } +} +class Closing { + readonly settle: (resolve: (v: number) => void, reject: (e: Error) => void) => void; + constructor(settle: (resolve: (v: number) => void, reject: (e: Error) => void) => void) { + this.settle = settle; + } + [Symbol.iterator]() { + let i = 0; + const settle = this.settle; + return { + next(): IteratorResult { + return { value: i++, done: false }; + }, + return(): IteratorResult { + console.log("return called"); + const value = new Promise((resolve, reject) => + settle((v) => (console.log("value settled"), resolve(v)), reject), + ); + return { value: value as unknown as number, done: true }; + }, + }; + } } main(); diff --git a/tests/corpus/6936-class-async-iterator-protocol.mjs b/tests/corpus/6936-class-async-iterator-protocol.mjs index cb7b1e68a..4cc67b0d1 100644 --- a/tests/corpus/6936-class-async-iterator-protocol.mjs +++ b/tests/corpus/6936-class-async-iterator-protocol.mjs @@ -56,5 +56,44 @@ async function main() { console.log("found", await find()); for await (const p of new Pages()) console.log(p); for await (const l of new Letters()) console.log("letter", l); + // return()'s value is awaited when the loop leaves early: a pending + // promise settles first, and a rejection rejects the loop after a break + // (after a throw from the body, the body's error wins). + for await (const v of new Closing((resolve) => setTimeout(() => resolve(1), 5))) + if (v === 1) break; + console.log("after break"); + try { + for await (const v of new Closing((_, reject) => reject(new Error("closing failed")))) + if (v === 1) break; + } catch (e) { + console.log("break:", e.message); + } + try { + for await (const v of new Closing((_, reject) => reject(new Error("closing failed")))) + if (v === 1) throw new Error("body failed"); + } catch (e) { + console.log("throw:", e.message); + } +} +class Closing { + constructor(settle) { + this.settle = settle; + } + [Symbol.iterator]() { + let i = 0; + const settle = this.settle; + return { + next() { + return { value: i++, done: false }; + }, + return() { + console.log("return called"); + const value = new Promise((resolve, reject) => + settle((v) => (console.log("value settled"), resolve(v)), reject), + ); + return { value, done: true }; + }, + }; + } } main(); From e73dbe0bb3842e18d793600a449a9b3ae62c8d40 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 20:41:45 -0500 Subject: [PATCH 191/259] Run the three.js nodes fixture unsanitized in the sanitized lane The sanitized nodes build compiles one 1.14 GB LLVM module, and its clang compile peaks at about 16 GB, more than the CI runners have, so the fixture failed in every san shard that ran it. It now builds without the sanitizer there, as in the plain lane; every other three.js fixture keeps it. The fixture goes back under the sanitizer once sanitized dev builds compile large programs in shards. --- tests/harness/three.test.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tests/harness/three.test.ts b/tests/harness/three.test.ts index 27fb86d1f..967c8654a 100644 --- a/tests/harness/three.test.ts +++ b/tests/harness/three.test.ts @@ -72,7 +72,11 @@ test.for(cases)( const previousTarget = process.env["SCRIPTC_TARGET"]; const previousCc = process.env["SCRIPTC_CC"]; const wasm = target === "wasm32-wasi"; - const sanitize = !wasm && process.env["SCRIPTC_SAN"] === "1"; + // The sanitized nodes program is one 1.14 GB LLVM module, whose clang + // compile needs about 16 GB, more than the CI runners have. It runs + // unsanitized until sanitized dev builds compile large programs in + // shards; every other fixture keeps the sanitizer. + const sanitize = !wasm && fixture !== "nodes" && process.env["SCRIPTC_SAN"] === "1"; try { if (wasm) { process.env["SCRIPTC_TARGET"] = target; From 0eb7cc12e5e74822145c4a50430bf999c3b302a6 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 20:51:37 -0500 Subject: [PATCH 192/259] Reuse symbol storage keys and checked-dynamic symbol boxes Every read or write of a symbol-keyed property on a checked-dynamic value formatted the symbol's address into a new string to find its storage key, and every conversion of a symbol to a checked value allocated a new box. Programs that key hot properties by symbols, such as Effect's type ids checked on each combinator, spent a large share of their time there. The storage key is a function of the address, so a 256-entry per-thread cache by address now returns the existing string, released at exit. A symbol also keeps a weak pointer to its live box: conversions share it, and the box clears the pointer when it is freed. --- .../corpus/symbol-property-key-reuse.mjs.json | 6 ++ packages/runtime/src/scr_json.c | 39 ++++++++++- packages/runtime/src/scr_symbol.c | 16 ++++- tests/corpus/symbol-property-key-reuse.mjs | 69 +++++++++++++++++++ .../symbol-property-key-reuse.mjs.json | 1 + 5 files changed, 127 insertions(+), 4 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/symbol-property-key-reuse.mjs.json create mode 100644 tests/corpus/symbol-property-key-reuse.mjs create mode 100644 tests/harness/corpus-costs/symbol-property-key-reuse.mjs.json diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/symbol-property-key-reuse.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/symbol-property-key-reuse.mjs.json new file mode 100644 index 000000000..e8fb5f353 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/symbol-property-key-reuse.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/symbol-property-key-reuse.mjs" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 9b7c13483..8da68a5a5 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -6615,11 +6615,44 @@ ScrDyn *scr_dyn_construct(const ScrDyn *callee, const ScrDyn *args, const ScrStr /* Symbol descriptors use the ordinary descriptor implementation in an * inaccessible table. Keep a retained key list so identities cannot be - * recycled while properties exist, and reflection returns real symbols. */ + * recycled while properties exist, and reflection returns real symbols. + * + * The storage key is the symbol's address in text, which depends on the + * address alone, so a small cache by address answers repeated defines and + * lookups without formatting a new string each time. A recycled address + * names the same key text, so entries never go stale. */ +#define SCR_SYMBOL_KEY_CACHE 256 +static SCR_TL struct { + const void *symbol; + ScrStr *key; +} scr_symbol_key_cache[SCR_SYMBOL_KEY_CACHE]; +static SCR_TL bool scr_symbol_key_cache_registered; + +static void scr_symbol_key_cache_cleanup(void) { + for (size_t i = 0; i < SCR_SYMBOL_KEY_CACHE; i++) { + scr_str_release(scr_symbol_key_cache[i].key); + scr_symbol_key_cache[i].key = NULL; + scr_symbol_key_cache[i].symbol = NULL; + } + scr_symbol_key_cache_registered = false; +} + static ScrStr *scr_dyn_symbol_storage_key(const ScrDyn *key) { + const void *symbol = key->v.symbol.value; + size_t slot = ((uintptr_t)symbol >> 4) & (SCR_SYMBOL_KEY_CACHE - 1); + if (scr_symbol_key_cache[slot].key && scr_symbol_key_cache[slot].symbol == symbol) + return scr_str_retain(scr_symbol_key_cache[slot].key); char buffer[2 * sizeof(void *) + 4]; - int length = snprintf(buffer, sizeof buffer, "%p", (void *)key->v.symbol.value); - return scr_str_new(buffer, (size_t)length); + int length = snprintf(buffer, sizeof buffer, "%p", (void *)symbol); + ScrStr *name = scr_str_new(buffer, (size_t)length); + if (!scr_symbol_key_cache_registered) { + scr_symbol_key_cache_registered = true; + scr_atexit(scr_symbol_key_cache_cleanup); + } + scr_str_release(scr_symbol_key_cache[slot].key); + scr_symbol_key_cache[slot].symbol = symbol; + scr_symbol_key_cache[slot].key = scr_str_retain(name); + return name; } static ScrDyn *scr_dyn_symbol_receiver(const ScrDyn *value) { diff --git a/packages/runtime/src/scr_symbol.c b/packages/runtime/src/scr_symbol.c index 727e008b5..3169d6b13 100644 --- a/packages/runtime/src/scr_symbol.c +++ b/packages/runtime/src/scr_symbol.c @@ -22,6 +22,10 @@ struct ScrSym { ScrStr *desc; /* owned; NULL = no description (Symbol()) */ ScrStr *reg_key; /* owned; non-NULL exactly for Symbol.for symbols */ struct ScrSym *reg_next; /* the registry's intrusive chain */ + /* The symbol's checked-dynamic box while one is alive (not retained: the + * box retains the symbol and clears this when it is freed), shared by + * every conversion of the symbol to a checked value. */ + ScrDyn *box; }; ScrSym *scr_sym_retain(ScrSym *s) { @@ -50,6 +54,7 @@ ScrSym *scr_sym_new(ScrStr *desc) { s->desc = desc ? scr_str_retain(desc) : NULL; s->reg_key = NULL; s->reg_next = NULL; + s->box = NULL; return s; } @@ -142,8 +147,17 @@ ScrStr *scr_sym_desc(ScrSym *s) { return s->desc ? scr_str_retain(s->desc) : NUL ScrStr *scr_sym_key_for(ScrSym *s) { return s->reg_key ? scr_str_retain(s->reg_key) : NULL; } +/* The release of a symbol's shared box: the box is going away. */ +static void scr_sym_release_box(ScrSym *s) { + s->box = NULL; + scr_sym_release(s); +} + ScrDyn *scr_dyn_new_symbol(ScrSym *value) { - return scr_dyn_symbol_ref(scr_sym_retain(value), scr_sym_release, scr_sym_to_string, scr_sym_desc); + if (value->box) return scr_dyn_retain(value->box); + ScrDyn *box = scr_dyn_symbol_ref(scr_sym_retain(value), scr_sym_release_box, scr_sym_to_string, scr_sym_desc); + value->box = box; + return box; } ScrStr *scr_sym_to_string(ScrSym *s) { diff --git a/tests/corpus/symbol-property-key-reuse.mjs b/tests/corpus/symbol-property-key-reuse.mjs new file mode 100644 index 000000000..f4fc2a0c4 --- /dev/null +++ b/tests/corpus/symbol-property-key-reuse.mjs @@ -0,0 +1,69 @@ +// Symbol-keyed properties read and written many times: on plain objects, on +// prototypes and class instances, with Symbol.for symbols, and with symbols +// created in a loop (each a distinct key, even after earlier ones are +// unreachable), plus the same symbol converted to a checked value repeatedly. +const tag = Symbol("tag"); +const shared = Symbol.for("shared"); +const proto = { [tag]: "from proto" }; +const child = Object.create(proto); +child[shared] = 0; +for (let i = 0; i < 1000; i++) child[shared] += i; +console.log(child[tag], child[shared], Object.getOwnPropertySymbols(child).length); + +const count = Symbol("count"); +class Counter { + constructor() { + this[count] = 0; + } + bump() { + this[count]++; + return this; + } + get count() { + return this[count]; + } +} +const c = new Counter(); +for (let i = 0; i < 500; i++) c.bump(); +console.log(c.count, c[count], count.toString()); + +const keys = []; +const holder = {}; +for (let i = 0; i < 300; i++) { + const key = Symbol(`k${i}`); + holder[key] = i; + if (i % 100 === 0) keys.push(key); +} +let sum = 0; +for (const key of Object.getOwnPropertySymbols(holder)) sum += holder[key]; +console.log(sum, keys.map((k) => holder[k]).join(), keys[1].description); + +// Symbols that become unreachable between rounds: a new symbol never reads +// a property stored under an earlier one. +const scratch = {}; +let stale = 0; +for (let round = 0; round < 200; round++) { + const key = Symbol("round"); + if (scratch[key] !== undefined) stale++; + scratch[key] = round; +} +console.log(stale, Object.getOwnPropertySymbols(scratch).length); + +// A symbol stored, deleted and dropped each round, so its storage can be +// reused by the next round's symbol: the new symbol still reads nothing. +const persist = {}; +let reused = 0; +for (let round = 0; round < 200; round++) { + const key = Symbol("dropped"); + if (key in persist) reused++; + persist[key] = round; + delete persist[key]; +} +console.log(reused, Object.getOwnPropertySymbols(persist).length); + +const viaFor = {}; +for (let i = 0; i < 10; i++) viaFor[Symbol.for("same")] = i; +console.log(viaFor[Symbol.for("same")], Object.getOwnPropertySymbols(viaFor).length); +console.log(Symbol.for("same") === Symbol.for("same"), Symbol("x") === Symbol("x"), tag === tag); +const boxes = [tag, tag, shared]; +console.log(boxes[0] === boxes[1], boxes.indexOf(shared), new Set(boxes).size); diff --git a/tests/harness/corpus-costs/symbol-property-key-reuse.mjs.json b/tests/harness/corpus-costs/symbol-property-key-reuse.mjs.json new file mode 100644 index 000000000..ddd7f7805 --- /dev/null +++ b/tests/harness/corpus-costs/symbol-property-key-reuse.mjs.json @@ -0,0 +1 @@ +{ "plain": 5174, "san": 9089 } From ab93f728edbeea66d4c2777515603e70d36e4786 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 20:53:18 -0500 Subject: [PATCH 193/259] Initialize a deferred module binding that a reached body assigns A module binding whose initializer only allocates data (a function, an arrow function, a literal or a registry object) is initialized only when a reached body uses the binding. Only reads and updates counted as uses, so a binding that reached code only assigned was never initialized, and the assignment, which checks that the binding is initialized and releases its value, threw "Cannot access '' before initialization" where Node runs. Assignments now count as uses. Corpus 8320 assigns two such bindings, one through an assignment expression, without reading them. --- .../deferred-module-initializers.test.ts | 30 +++++++++++++++---- .../lowering/deferred-module-initializers.ts | 24 ++++++++++----- .../main.ts.json | 7 +++++ .../8320-assign-only-deferred-binding/main.ts | 8 +++++ .../scanner.ts | 21 +++++++++++++ .../main.ts.json | 1 + 6 files changed, 77 insertions(+), 14 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8320-assign-only-deferred-binding/main.ts.json create mode 100644 tests/corpus/8320-assign-only-deferred-binding/main.ts create mode 100644 tests/corpus/8320-assign-only-deferred-binding/scanner.ts create mode 100644 tests/harness/corpus-costs/8320-assign-only-deferred-binding/main.ts.json diff --git a/packages/compiler/src/frontend/lowering/deferred-module-initializers.test.ts b/packages/compiler/src/frontend/lowering/deferred-module-initializers.test.ts index 4696659bc..4786585d9 100644 --- a/packages/compiler/src/frontend/lowering/deferred-module-initializers.test.ts +++ b/packages/compiler/src/frontend/lowering/deferred-module-initializers.test.ts @@ -168,17 +168,19 @@ test("reports the functions whose placeholders it fills", () => { expect(filled).toEqual([functions[0]]); }); -test("an update of the binding demands its initializer", () => { +test("an update or an assignment of the binding demands its initializer", () => { const { initializers, pending, lowerer } = fixture(); const updated = block(loc), - written = block({ ...loc, start: 2, end: 3 }); + written = block({ ...loc, start: 2, end: 3 }), + assigned = block({ ...loc, start: 4, end: 5 }), + unused = block({ ...loc, start: 6, end: 7 }); const update = (id: string, prefix: boolean): IrStmt => ({ kind: "exprStmt", expr: { kind: "incDec", op: "+", prefix, localId: id, type: F64, loc }, loc, }); const functions = [ - fn("init", [updated, written]), + fn("init", [updated, written, assigned, unused]), fn("use", [ update("updated", false), { @@ -187,13 +189,29 @@ test("an update of the binding demands its initializer", () => { value: { kind: "numLit", value: 1, type: F64, loc }, loc, }, + { + kind: "exprStmt", + expr: { + kind: "assignExpr", + localId: "assigned", + value: { kind: "numLit", value: 2, type: F64, loc }, + type: F64, + loc, + }, + loc, + }, ]), ]; pending.set("updated", [{ loc, lower: () => [value(2)] }]); pending.set("written", [{ loc: written.loc, lower: () => [value(3)] }]); + pending.set("assigned", [{ loc: assigned.loc, lower: () => [value(4)] }]); + pending.set("unused", [{ loc: unused.loc, lower: () => [value(5)] }]); expect(initializers.process(lowerer, functions)).toBe(true); expect(updated.body).toEqual([value(2)]); - // A plain write never observes the initial value. - expect(written.body).toEqual([]); - expect(pending.has("written")).toBe(true); + // An assignment checks that the binding is initialized and releases its + // value, so the declaration must have run. + expect(written.body).toEqual([value(3)]); + expect(assigned.body).toEqual([value(4)]); + expect(unused.body).toEqual([]); + expect(pending.has("unused")).toBe(true); }); diff --git a/packages/compiler/src/frontend/lowering/deferred-module-initializers.ts b/packages/compiler/src/frontend/lowering/deferred-module-initializers.ts index a44df8f75..3af054dd6 100644 --- a/packages/compiler/src/frontend/lowering/deferred-module-initializers.ts +++ b/packages/compiler/src/frontend/lowering/deferred-module-initializers.ts @@ -387,18 +387,22 @@ function scanStatements( const placeholders: PlaceholderBlock[] = []; const typeEvents = lowerer ? typeScanner(lowerer, body) : null; const reads = new Set(); + const observe = (id: string): void => { + if (deferred!.has(id) && !reads.has(id)) { + reads.add(id); + body.push({ kind: "read", id }); + } + }; everyStmtList(statements, { stmt: (statement) => { if (statement.kind === "block" && statement.body.length === 0) placeholders.push(statement); + if (typeEvents !== null && statement.kind === "assign") observe(statement.localId); return true; }, expr: (expr) => { if (typeEvents === null) return true; typeEvents(expr.type); - if (readsBinding(expr) && deferred!.has(expr.localId) && !reads.has(expr.localId)) { - reads.add(expr.localId); - body.push({ kind: "read", id: expr.localId }); - } + if (observesBinding(expr)) observe(expr.localId); // Every call, as the helpers are visited from a stack in call order. if ( expr.kind === "call" && @@ -411,10 +415,14 @@ function scanStatements( return { body, placeholders }; } -/** A read of a binding's current value: a plain read, or an update - * (`n++`, `--n`) that reads before it writes. */ -function readsBinding(expr: IrExpr): expr is IrExpr & { kind: "varRef" | "incDec" } { - return expr.kind === "varRef" || expr.kind === "incDec"; +/** A use that needs the binding initialized: a plain read, an update + * (`n++`, `--n`) that reads before it writes, or an assignment, which + * checks that the binding is initialized and releases its current value. + * Assignment statements count the same way (scanStatements). */ +function observesBinding( + expr: IrExpr, +): expr is IrExpr & { kind: "varRef" | "incDec" | "assignExpr" } { + return expr.kind === "varRef" || expr.kind === "incDec" || expr.kind === "assignExpr"; } function registryInitializer( diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8320-assign-only-deferred-binding/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8320-assign-only-deferred-binding/main.ts.json new file mode 100644 index 000000000..399baa239 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8320-assign-only-deferred-binding/main.ts.json @@ -0,0 +1,7 @@ +{ + "order": [ + "/tests/corpus/8320-assign-only-deferred-binding/scanner.ts", + "/tests/corpus/8320-assign-only-deferred-binding/main.ts" + ], + "diags": [] +} diff --git a/tests/corpus/8320-assign-only-deferred-binding/main.ts b/tests/corpus/8320-assign-only-deferred-binding/main.ts new file mode 100644 index 000000000..d35a863ae --- /dev/null +++ b/tests/corpus/8320-assign-only-deferred-binding/main.ts @@ -0,0 +1,8 @@ +import { installCount, useFormat, useScanner } from "./scanner.ts"; + +useScanner((bytes, start) => start + bytes.length * 2); +console.log("scanner installed"); +const formatter = useFormat((value) => `[${value}]`); +console.log(formatter(7)); +useScanner((bytes, start) => start); +console.log("installs", installCount()); diff --git a/tests/corpus/8320-assign-only-deferred-binding/scanner.ts b/tests/corpus/8320-assign-only-deferred-binding/scanner.ts new file mode 100644 index 000000000..601df60ba --- /dev/null +++ b/tests/corpus/8320-assign-only-deferred-binding/scanner.ts @@ -0,0 +1,21 @@ +// Module bindings that only assignments use after their declarations. +export function defaultEnd(bytes: Uint8Array, start: number): number { + return start + bytes.length; +} + +let valueEnd: (bytes: Uint8Array, start: number) => number = defaultEnd; +let format: (value: number) => string = (value) => `#${value}`; +let installs = 0; + +export function useScanner(scan: (bytes: Uint8Array, start: number) => number): void { + valueEnd = (bytes, start) => scan(bytes, start) + 1; + installs++; +} + +export function useFormat(next: (value: number) => string): (value: number) => string { + return (format = next); +} + +export function installCount(): number { + return installs; +} diff --git a/tests/harness/corpus-costs/8320-assign-only-deferred-binding/main.ts.json b/tests/harness/corpus-costs/8320-assign-only-deferred-binding/main.ts.json new file mode 100644 index 000000000..0606e0393 --- /dev/null +++ b/tests/harness/corpus-costs/8320-assign-only-deferred-binding/main.ts.json @@ -0,0 +1 @@ +{ "plain": 4500, "san": 48000 } From 4e9a4311b00c2c2983ae1a7c140663f0e64d492e Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 21:15:01 -0500 Subject: [PATCH 194/259] Prove a typed-array loop's views disjoint and give each its own alias scope A loop that reads one typed array and writes another kept every element in memory: separate views can share a buffer, so LLVM had to assume a store to one could change the other's elements. A loop of eight lanes held in Float64Arrays (zr[k], zi[k], tr[k], ti[k]) ran as scalar loads and stores of each lane on every step. When a typed-array loop version covers at least two views and writes at least one of them, its guard now also requires every pair of the views' byte ranges to be disjoint: one ends at or before the other starts. In the fast copy, each view's element reads and writes carry an alias scope of their own and no-alias with the others' scopes, so LLVM keeps the elements in registers and vectorizes across lanes. Views that share bytes, or one array passed twice, take the checked copy as before. The scopes are string-named, written inline, and named after the function and the version, so every copy of a loop has its own. Worker programs scope only views the guard proves thread-owned. Corpus 8182 runs such loops over disjoint, adjacent, overlapping and identical views, views of different element types over one buffer, and empty views. --- .../compiler/src/backend/llvm/bytes-alias.ts | 4 +- .../src/backend/llvm/bytes-loop-versions.ts | 81 ++++++++++++++++- .../src/backend/llvm/emit-function.ts | 1 + .../src/backend/llvm/emit-statements.ts | 38 +++++++- packages/compiler/src/backend/llvm/emitter.ts | 25 +++++- .../compiler/src/backend/llvm/expr-bytes.ts | 42 +++++++++ .../8182-typed-array-alias-scopes.ts.json | 6 ++ .../typed-array-alias-scope-emission.test.ts | 57 ++++++++++++ tests/corpus/8182-typed-array-alias-scopes.ts | 89 +++++++++++++++++++ .../8182-typed-array-alias-scopes.ts.json | 1 + 10 files changed, 336 insertions(+), 8 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8182-typed-array-alias-scopes.ts.json create mode 100644 packages/compiler/test/typed-array-alias-scope-emission.test.ts create mode 100644 tests/corpus/8182-typed-array-alias-scopes.ts create mode 100644 tests/harness/corpus-costs/8182-typed-array-alias-scopes.ts.json diff --git a/packages/compiler/src/backend/llvm/bytes-alias.ts b/packages/compiler/src/backend/llvm/bytes-alias.ts index d43620fd9..b7a672754 100644 --- a/packages/compiler/src/backend/llvm/bytes-alias.ts +++ b/packages/compiler/src/backend/llvm/bytes-alias.ts @@ -18,8 +18,10 @@ export function bytesHeaderAlias(host: LlvmEmitterContext): string { return tag === "" ? "" : `${tag}, !invariant.load !{}`; } +/** Element storage's tag, and the alias scope of the access being emitted + * in a loop version's fast copy (bytesAccessScope). */ export function bytesElementAlias(host: LlvmEmitterContext): string { - return host.memoryAliasAttachment("bytes:elements"); + return host.memoryAliasAttachment("bytes:elements") + host.bytesAccessScope; } /** A module global's slot is its own category for whole-slot loads of a diff --git a/packages/compiler/src/backend/llvm/bytes-loop-versions.ts b/packages/compiler/src/backend/llvm/bytes-loop-versions.ts index 301f65de2..ac280df00 100644 --- a/packages/compiler/src/backend/llvm/bytes-loop-versions.ts +++ b/packages/compiler/src/backend/llvm/bytes-loop-versions.ts @@ -1,4 +1,11 @@ -import { F64, type IrExpr, type IrLocal, type IrStmt } from "../../ir/ir.js"; +import { + BYTES_ELEMENT_SIZE, + F64, + type IrExpr, + type IrLocal, + type IrStmt, + type IrType, +} from "../../ir/ir.js"; import type { IntegerRange, IntegerRanges } from "../../ir/integer-ranges.js"; import type { IntegerCountedForLoop, IntegerPairedForLoop } from "../../ir/integer-loops.js"; import type { LlvmEmitterContext } from "./expr-context.js"; @@ -10,7 +17,7 @@ import { emitCountedLoopSafety, emitExactIntegerTest, } from "./counted-loops.js"; -import { emitBytesHeaderLength, emitBytesSharedStorage } from "./expr-bytes.js"; +import { emitBytesData, emitBytesHeaderLength, emitBytesSharedStorage } from "./expr-bytes.js"; import { f64Lit } from "./common.js"; import { emitStringAsciiFlag, @@ -106,6 +113,12 @@ export interface BytesLoopVersion { /** Integer ranges of affine index operands that hold in the unchecked * loop (where the guard bounds the counter). */ ranges: ReadonlyMap; + /** Typed-array receivers whose element ranges the guard proves disjoint, + * and the receiver of each of their element reads and writes. The fast + * copy gives each receiver its own alias scope, so a store to one view + * leaves the elements of the others in registers. Null when the loop + * writes no element, or reads and writes a single view. */ + scopes: { receivers: number[]; nodes: ReadonlyMap } | null; } export interface BytesLoopFacts { @@ -136,6 +149,8 @@ export interface BytesLoopFacts { const MAX_COST = 400; const MAX_FIXED_END = 2 ** 31; const MAX_CHECKS = 8; +/** Alias-scoped views per loop: the guard tests every pair's ranges. */ +const MAX_SCOPED_RECEIVERS = 6; const MAX_OFFSET = 2 ** 31; const SAFE = Number.MAX_SAFE_INTEGER; /** The range the guard requires of an invariant index term without a @@ -547,11 +562,24 @@ export function matchBytesLoopVersion( group.nodes.push(node); } else fixed.set(receiver, { check: { receiver, end }, nodes: [node] }); }; + // Element reads and writes of each typed-array receiver, for alias scopes. + const scoped = new Map(); + const writtenViews = new Set(); + const scope = (node: Node, array: IrExpr, write: boolean): void => { + const ref = root(array); + if (!ref || ref.type.kind !== "bytes") return; + const receiver = receiverOf(ref); + scoped.set(node, receiver); + if (write) writtenViews.add(receiver); + }; const visitExpr = (e: IrExpr): boolean => { if (e.kind === "bytesIntrinsic") { const numeric = byteNumberAccess(e); if (numeric) access(e, e.receiver, e.args[numeric.offsetArg]!, numeric.width); - else if (e.method === "get" && e.args[0]) access(e, e.receiver, e.args[0], 1); + else if (e.method === "get" && e.args[0]) { + access(e, e.receiver, e.args[0], 1); + scope(e, e.receiver, false); + } } else if ( e.kind === "strIntrinsic" && (e.method === "charCodeAt" || e.method === "charAt") && @@ -561,7 +589,10 @@ export function matchBytesLoopVersion( return everyExprChild(e, visitExpr, visitStmt); }; const visitStmt = (s: IrStmt): boolean => { - if (s.kind === "bytesSet") access(s, s.arr, s.index, 1); + if (s.kind === "bytesSet") { + access(s, s.arr, s.index, 1); + scope(s, s.arr, true); + } return everyStmtChild(s, visitExpr, visitStmt); }; loop.body.every(visitStmt); @@ -684,6 +715,17 @@ export function matchBytesLoopVersion( : [], }); } + // Alias scopes: at least two views, one of them written, each read only + // through plain loads (in a worker program, a view the guard proves + // thread-owned). + const scopedReceivers = [...new Set(scoped.values())].sort((a, b) => a - b); + const ownedSet = new Set(ownedKept.map(([receiver]) => receiver)); + const scoping = + scopedReceivers.length >= 2 && + scopedReceivers.length <= MAX_SCOPED_RECEIVERS && + scopedReceivers.some((receiver) => writtenViews.has(receiver)) && + (!facts.workers || scopedReceivers.every((receiver) => ownedSet.has(receiver))); + if (scoping) for (const receiver of scopedReceivers) used.add(receiver); // Renumber the receivers the kept checks use. const order = [...used].sort((a, b) => a - b); const renumber = new Map(order.map((old, index) => [old, index])); @@ -737,6 +779,12 @@ export function matchBytesLoopVersion( : null, counterBound: needsBound ? bound : null, ranges, + scopes: scoping + ? { + receivers: scopedReceivers.map((receiver) => renumber.get(receiver)!), + nodes: new Map([...scoped].map(([node, receiver]) => [node, renumber.get(receiver)!])), + } + : null, }; } @@ -1126,6 +1174,31 @@ export function emitBytesLoopVersionGuard( B.line(`${ok} = icmp ugt i64 ${lengths[check.receiver]}, ${check.end}`); conditions.push(ok); } + if (version.scopes) { + // Every pair of scoped views covers disjoint bytes: one ends at or + // before the other starts. An empty view covers none. + const spans = version.scopes.receivers.map((index) => { + const type = version.receivers[index]!.ref.type as IrType & { kind: "bytes" }; + const start = B.tmp(), + size = B.tmp(), + end = B.tmp(); + B.line(`${start} = ptrtoint ptr ${emitBytesData(host, receivers[index]!)} to i64`); + B.line(`${size} = mul nuw i64 ${lengths[index]}, ${BYTES_ELEMENT_SIZE[type.elem]}`); + B.line(`${end} = add nuw i64 ${start}, ${size}`); + return { start, end }; + }); + spans.forEach((a, i) => { + for (const b of spans.slice(i + 1)) { + const before = B.tmp(), + after = B.tmp(), + apart = B.tmp(); + B.line(`${before} = icmp ule i64 ${a.end}, ${b.start}`); + B.line(`${after} = icmp ule i64 ${b.end}, ${a.start}`); + B.line(`${apart} = or i1 ${before}, ${after}`); + conditions.push(apart); + } + }); + } for (const counter of version.counters) { const value = host.emitExpr(counter.ref); // A counter held as an integer (an int32 slot) is exact already and diff --git a/packages/compiler/src/backend/llvm/emit-function.ts b/packages/compiler/src/backend/llvm/emit-function.ts index ca45a6624..b79e2406d 100644 --- a/packages/compiler/src/backend/llvm/emit-function.ts +++ b/packages/compiler/src/backend/llvm/emit-function.ts @@ -64,6 +64,7 @@ export function emitFunction(emitter: LlEmitter, fn: IrFunction): string { emitter.currentFunctionName = fn.name; emitter.currentUnwindAbi = emitter.unwindAbi.has(fn.name); emitter.usesLandingPads = false; + emitter.aliasScopedVersions = 0; emitter.findInt32Allocations(fn); emitter.currentTier = fn.tier; // Fiber switches restore the active exception cell before control diff --git a/packages/compiler/src/backend/llvm/emit-statements.ts b/packages/compiler/src/backend/llvm/emit-statements.ts index 3d3aa6781..36c28bf97 100644 --- a/packages/compiler/src/backend/llvm/emit-statements.ts +++ b/packages/compiler/src/backend/llvm/emit-statements.ts @@ -570,6 +570,7 @@ export function emitStmtBody(emitter: LlEmitter, s: IrStmt): void { s.value, emitter.bytesBounds.has(s), emitter.bytesOwned.has(s), + emitter.bytesAliasScopes.get(s), ); break; } @@ -2080,6 +2081,32 @@ function emitSlowCopy(emitter: LlEmitter, s: IrStmt): void { * stops trying it. */ const SPECULATION_BAILS = 8; +/** The attachment of each scoped access in a version's fast copy: the + * scope of its own view, and no alias with the scopes of the other views, + * whose bytes the guard proved disjoint. The scopes are named after the + * function and the version, so every copy of a loop has its own, and + * written inline (string-named scopes need no numbered metadata). */ +function bytesAliasScopes( + emitter: LlEmitter, + scopes: NonNullable, +): Map { + const version = emitter.aliasScopedVersions++; + const name = emitter.currentFunctionName.replace(/[^A-Za-z0-9_.$%]/g, "_"); + const domain = '!{!"scriptc typed-array views"}'; + const scope = (receiver: number): string => `!{!"${name}.${version}.${receiver}", ${domain}}`; + const attachments = new Map(); + for (const receiver of scopes.receivers) { + const others = scopes.receivers.filter((other) => other !== receiver).map(scope); + attachments.set( + receiver, + `, !alias.scope !{${scope(receiver)}}, !noalias !{${others.join(", ")}}`, + ); + } + const result = new Map(); + for (const [node, receiver] of scopes.nodes) result.set(node, attachments.get(receiver)!); + return result; +} + /** Emit a loop's condition, body and update through `emitCopy`, twice * when speculative-integers.ts plans a fast integer copy. Both copies * share the loop's setup and exit; the ordinary copy comes first so the @@ -2104,7 +2131,8 @@ function emitVersionedLoop( originalOwned = emitter.bytesOwned, originalRanges = emitter.integerRanges, originalUnitReads = emitter.stringUnitReads, - originalLengthReads = emitter.stringLengthReads; + originalLengthReads = emitter.stringLengthReads, + originalScopes = emitter.bytesAliasScopes; LOOPS.of(emitter).bytesLoopVersioning.add(s); try { B.startBlock(slow); @@ -2113,6 +2141,13 @@ function emitVersionedLoop( if (version.owned.size > 0) emitter.bytesOwned = new Set([...originalOwned, ...version.owned]); if (version.ranges.size > 0) emitter.integerRanges = new Map([...originalRanges, ...version.ranges]); + // Both fast copies run under the guard's span test, so they share the + // version's scopes. + if (version.scopes && emitter.debug === null) + emitter.bytesAliasScopes = new Map([ + ...originalScopes, + ...bytesAliasScopes(emitter, version.scopes), + ]); if (version.counted?.guarded || version.paired?.loop.guarded) LOOPS.of(emitter).provenCountedGuards.add(s); B.startBlock(fast); @@ -2146,6 +2181,7 @@ function emitVersionedLoop( emitter.integerRanges = originalRanges; emitter.stringUnitReads = originalUnitReads; emitter.stringLengthReads = originalLengthReads; + emitter.bytesAliasScopes = originalScopes; LOOPS.of(emitter).provenCountedGuards.delete(s); LOOPS.of(emitter).bytesLoopVersioning.delete(s); } diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index bcb8a5ba2..d5964f1ba 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -1624,6 +1624,14 @@ export class LlEmitter { /** Worker programs: typed-array accesses whose views an enclosing version * guard proved thread-owned. */ bytesOwned: ReadonlySet = new Set(); + /** The alias-scope attachment of each typed-array element read and write + * in the current loop version's fast copy (emitVersionedLoop), and the + * one the element access being emitted carries (bytesElementAlias). */ + bytesAliasScopes: ReadonlyMap = new Map(); + bytesAccessScope = ""; + /** Loop versions with alias scopes in the current function; it names + * their scopes. */ + aliasScopedVersions = 0; integerViews = new Map(); /** Module globals the current function owns outright (initializer * bindings): their function-local slot, which stands in for the global. */ @@ -7275,8 +7283,9 @@ export class LlEmitter { inBounds = false, invalidNaN = false, owned = false, + scope = "", ): LlValue { - return emitBytesGet(this, elem, receiver, index, expr, inBounds, invalidNaN, owned); + return emitBytesGet(this, elem, receiver, index, expr, inBounds, invalidNaN, owned, scope); } emitToUint32(value: string, expr?: IrExpr, uint32?: string): string { @@ -7340,8 +7349,20 @@ export class LlEmitter { expr?: IrExpr, inBounds = false, owned = false, + scope = "", ): void { - return emitBytesSet(this, elem, receiver, index, value, indexExpr, expr, inBounds, owned); + return emitBytesSet( + this, + elem, + receiver, + index, + value, + indexExpr, + expr, + inBounds, + owned, + scope, + ); } emitBytesIntrinsic(e: IrExpr & { kind: "bytesIntrinsic" }): LlValue { diff --git a/packages/compiler/src/backend/llvm/expr-bytes.ts b/packages/compiler/src/backend/llvm/expr-bytes.ts index 23025d00c..a50464cd6 100644 --- a/packages/compiler/src/backend/llvm/expr-bytes.ts +++ b/packages/compiler/src/backend/llvm/expr-bytes.ts @@ -235,6 +235,26 @@ export function emitBytesGet( inBounds = false, invalidNaN = false, owned = false, + scope = "", +): LlValue { + const outer = host.bytesAccessScope; + host.bytesAccessScope = scope; + try { + return emitScopedBytesGet(host, elem, receiver, index, expr, inBounds, invalidNaN, owned); + } finally { + host.bytesAccessScope = outer; + } +} + +function emitScopedBytesGet( + host: LlvmEmitterContext, + elem: IrBytesElem, + receiver: string, + index: LlValue, + expr: IrExpr | undefined, + inBounds: boolean, + invalidNaN: boolean, + owned: boolean, ): LlValue { const B = host.B; // Any invalid index traps (the array runtime's discipline). @@ -547,6 +567,27 @@ export function emitBytesSet( expr?: IrExpr, inBounds = false, owned = false, + scope = "", +): void { + const outer = host.bytesAccessScope; + host.bytesAccessScope = scope; + try { + emitScopedBytesSet(host, elem, receiver, index, value, indexExpr, expr, inBounds, owned); + } finally { + host.bytesAccessScope = outer; + } +} + +function emitScopedBytesSet( + host: LlvmEmitterContext, + elem: IrBytesElem, + receiver: string, + index: LlValue, + value: LlValue, + indexExpr: IrExpr | undefined, + expr: IrExpr | undefined, + inBounds: boolean, + owned: boolean, ): void { const B = host.B; // Invalid integer-indexed writes are ignored after evaluating the RHS. @@ -768,6 +809,7 @@ export function emitBytesIntrinsic( host.bytesBounds.has(e), e.invalidNaN === true, host.bytesOwned.has(e), + host.bytesAliasScopes.get(e), ); case "slice": return call( diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8182-typed-array-alias-scopes.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8182-typed-array-alias-scopes.ts.json new file mode 100644 index 000000000..c941e8b5d --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8182-typed-array-alias-scopes.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8182-typed-array-alias-scopes.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/typed-array-alias-scope-emission.test.ts b/packages/compiler/test/typed-array-alias-scope-emission.test.ts new file mode 100644 index 000000000..a32df03e7 --- /dev/null +++ b/packages/compiler/test/typed-array-alias-scope-emission.test.ts @@ -0,0 +1,57 @@ +import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile, deserializeModule } from "../src/index.js"; +import { emitLlvmModule } from "../src/backend/llvm/emitter.js"; + +test("a typed-array loop version proves its views disjoint and scopes their accesses", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-alias-scopes-")); + try { + const entry = join(dir, "main.ts"); + const outPath = join(dir, "main.ir.json"); + await writeFile( + entry, + ` +function copy(dst: Float64Array, src: Float64Array, n: number): void { + for (let i = 0; i < n; i++) dst[i] = src[i]! + 1; +} +function scale(xs: Float64Array, n: number): void { + for (let i = 0; i < n; i++) xs[i] = xs[i]! * 2; +} +function dot(a: Float64Array, b: Float64Array, n: number): number { + let sum = 0; + for (let i = 0; i < n; i++) sum += a[i]! * b[i]!; + return sum; +} +const a = new Float64Array(8), b = new Float64Array(8); +copy(a, b, 8); +scale(a, 8); +console.log(dot(a, b, 8)); +`, + ); + const result = await compile(entry, { outDir: dir, outPath, outputKind: "ir" }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + const mod = deserializeModule(await readFile(outPath, "utf8")); + const ll = emitLlvmModule(mod); + const fn = (name: string): string => + new RegExp(`^define internal [^\\n]*@sc_bf_${name}(?:\\.i32)?\\([^]*?^}`, "m").exec(ll)![0]; + // Two views, one written: the guard compares their byte ranges, and + // each view's accesses in the fast copy carry its own scope. + const copy = fn("copy"); + expect(copy).toMatch(/ptrtoint ptr %\w+ to i64/); + expect(copy).toMatch(/icmp ule i64 %\w+, %\w+/); + expect(copy).toMatch( + /load double, ptr %\w+, align 1[^\n]*!alias\.scope !\{!\{!"copy\.0\.\d", !\{!"scriptc typed-array views"\}\}\}, !noalias/, + ); + expect(copy).toMatch(/store double %\w+, ptr %\w+, align 1[^\n]*!alias\.scope/); + // One view, or views that are only read, need no scopes. + for (const name of ["scale", "dot"]) { + expect(fn(name)).not.toContain("!alias.scope"); + expect(fn(name)).not.toContain("ptrtoint"); + } + } finally { + await rm(dir, { recursive: true, force: true }); + } +}); diff --git a/tests/corpus/8182-typed-array-alias-scopes.ts b/tests/corpus/8182-typed-array-alias-scopes.ts new file mode 100644 index 000000000..4dbf52e47 --- /dev/null +++ b/tests/corpus/8182-typed-array-alias-scopes.ts @@ -0,0 +1,89 @@ +// Loops that read one typed array and write another, where the two views +// may share bytes: overlapping and disjoint views of one buffer, the same +// array passed twice, views of different element types over one buffer, +// and empty views. A loop over views that overlap must see its own writes. +function shiftAdd(dst: Float64Array, src: Float64Array, n: number): void { + for (let i = 0; i < n; i++) dst[i] = src[i]! + 1; +} + +function mixed(bytes: Uint8Array, words: Float64Array, n: number): number { + let sum = 0; + for (let i = 0; i < n; i++) { + words[i] = i * 0.5 + 1; + sum += bytes[i]!; + } + return sum; +} + +function lanes(zr: Float64Array, zi: Float64Array, tr: Float64Array, ti: Float64Array): number { + for (let step = 0; step < 6; step++) + for (let k = 0; k < 4; k++) { + const r = zr[k]!; + const i = zi[k]!; + zi[k] = 2 * r * i + 0.25; + zr[k] = tr[k]! - ti[k]! - 0.5; + tr[k] = zr[k]! * zr[k]!; + ti[k] = zi[k]! * zi[k]!; + } + let sum = 0; + for (let k = 0; k < 4; k++) sum += zr[k]! + zi[k]! + tr[k]! + ti[k]!; + return sum; +} + +function show(a: Float64Array): string { + const parts: string[] = []; + for (let i = 0; i < a.length; i++) parts.push(a[i]!.toFixed(3)); + return parts.join(","); +} + +// Disjoint arrays. +const a = new Float64Array([1, 2, 3, 4]); +const b = new Float64Array(4); +shiftAdd(b, a, 4); +console.log("disjoint", show(b)); + +// One array as both views: each element reads its own old value. +const same = new Float64Array([1, 2, 3, 4]); +shiftAdd(same, same, 4); +console.log("same", show(same)); + +// Overlapping views of one buffer: the destination starts one element +// after the source, so every read sees the previous iteration's write. +const buffer = new ArrayBuffer(8 * 8); +const whole = new Float64Array(buffer); +whole.fill(1); +shiftAdd(new Float64Array(buffer, 8, 6), new Float64Array(buffer, 0, 6), 6); +console.log("overlap forward", show(whole)); +whole.fill(1); +shiftAdd(new Float64Array(buffer, 0, 6), new Float64Array(buffer, 8, 6), 6); +console.log("overlap backward", show(whole)); + +// Adjacent views of one buffer share no bytes. +whole.set([1, 2, 3, 4, 5, 6, 7, 8]); +shiftAdd(new Float64Array(buffer, 32, 4), new Float64Array(buffer, 0, 4), 4); +console.log("adjacent", show(whole)); + +// A byte view over the doubles it writes. +const shared = new ArrayBuffer(64); +console.log("mixed", mixed(new Uint8Array(shared), new Float64Array(shared), 8), show(new Float64Array(shared))); +console.log("mixed disjoint", mixed(new Uint8Array(new ArrayBuffer(64)), new Float64Array(8), 8)); + +// Empty views. +shiftAdd(new Float64Array(0), new Float64Array(0), 0); +console.log("empty", new Float64Array(0).length); + +// Four lanes in separate arrays, and the same arrays aliased. +const lane = (): Float64Array => new Float64Array([0.1, -0.2, 0.3, -0.4]); +console.log("lanes", lanes(lane(), lane(), lane(), lane()).toFixed(6)); +const one = lane(); +console.log("lanes aliased", lanes(one, one, lane(), lane()).toFixed(6)); +const pool = new Float64Array(16); +pool.set([0.1, -0.2, 0.3, -0.4, 0.1, -0.2, 0.3, -0.4, 0.1, -0.2, 0.3, -0.4, 0.1, -0.2, 0.3, -0.4]); +console.log( + "lanes subarrays", + lanes(pool.subarray(0, 4), pool.subarray(4, 8), pool.subarray(8, 12), pool.subarray(12, 16)).toFixed(6), +); +console.log( + "lanes overlapping", + lanes(pool.subarray(0, 4), pool.subarray(2, 6), pool.subarray(8, 12), pool.subarray(9, 13)).toFixed(6), +); diff --git a/tests/harness/corpus-costs/8182-typed-array-alias-scopes.ts.json b/tests/harness/corpus-costs/8182-typed-array-alias-scopes.ts.json new file mode 100644 index 000000000..974b44e1e --- /dev/null +++ b/tests/harness/corpus-costs/8182-typed-array-alias-scopes.ts.json @@ -0,0 +1 @@ +{ "plain": 2600, "san": 3800 } From 5f602ff3b85989be80e44c6f82d01bbce84c9e61 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 21:16:59 -0500 Subject: [PATCH 195/259] Decode asserted optional typed arrays other than Uint8Array `decoder.decode(view!)` on a `Uint16Array | undefined` (or another typed array that may be undefined) was refused with SC2020: the assertion keeps the undefined arm for decode, and the decode input only read the undefined arm of `Uint8Array | undefined`. The undefined arm of any typed array that may be undefined now reads as an empty array of the same type, so a defined input decodes its bytes and an undefined one decodes no bytes, as in Node. --- .../frontend/lowering/builtins/text-codecs.ts | 30 ++++++++++++------- tests/corpus/text-decoder-undefined-input.ts | 7 +++++ 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/builtins/text-codecs.ts b/packages/compiler/src/frontend/lowering/builtins/text-codecs.ts index 34cc7aa14..39156940e 100644 --- a/packages/compiler/src/frontend/lowering/builtins/text-codecs.ts +++ b/packages/compiler/src/frontend/lowering/builtins/text-codecs.ts @@ -16,7 +16,6 @@ import { type IrType, STRING, type SrcLoc, - typeEquals, } from "../../../ir/ir.js"; import { lowerBuiltinValuePreservingUndefined, @@ -27,21 +26,30 @@ import { type BuiltinModuleFn } from "../surfaces.js"; /** The input of `decoder.decode(input)`. An undefined input decodes no bytes, * as `decode()` does in Node: a statically undefined argument (after its - * effects) and the undefined arm of `Uint8Array | undefined` read as an - * empty Uint8Array. */ + * effects) reads as an empty Uint8Array, and the undefined arm of a typed + * array or view that may be undefined (`Uint8Array | undefined`, + * `Uint16Array | undefined`) as an empty view of the same type. */ function lowerDecodeInput(lowerer: Lowerer, node: ts.Expression, loc: SrcLoc): IrExpr { - const empty: IrExpr = { kind: "bytesNew", source: null, type: BYTES_U8, loc }; const undefinedArg = lowerStaticallyUndefinedArgument(lowerer, node); - if (undefinedArg) return defaultAfterUndefined(undefinedArg, empty); + if (undefinedArg) + return defaultAfterUndefined(undefinedArg, { + kind: "bytesNew", + source: null, + type: BYTES_U8, + loc, + }); const value = lowerer.lowerExpr(node); if (value.type.kind === "union") { const def = lowerer.unions.get(value.type.unionId); - if ( - def?.arms.length === 2 && - def.arms.some((arm) => arm.kind === "undefinedT") && - def.arms.some((arm) => typeEquals(arm, BYTES_U8)) - ) - return { kind: "nullish", left: value, right: empty, type: BYTES_U8, loc }; + const view = def?.arms.find((arm) => arm.kind === "bytes"); + if (def?.arms.length === 2 && view && def.arms.some((arm) => arm.kind === "undefinedT")) + return { + kind: "nullish", + left: value, + right: { kind: "bytesNew", source: null, type: view, loc }, + type: view, + loc, + }; } return value; } diff --git a/tests/corpus/text-decoder-undefined-input.ts b/tests/corpus/text-decoder-undefined-input.ts index 6a3be354c..32bca7f3a 100644 --- a/tests/corpus/text-decoder-undefined-input.ts +++ b/tests/corpus/text-decoder-undefined-input.ts @@ -29,3 +29,10 @@ const streaming = new TextDecoder(); let text = ""; for (const chunk of chunks) text += streaming.decode(chunk.value, { stream: !chunk.done }); console.log(JSON.stringify(text), text.length); + +// Other typed arrays decode their bytes, with or without the assertion. +const wide = new Map([["present", new Uint16Array([0x6968])]]); +const asserted = wide.get("present")!; +console.log(JSON.stringify(decoder.decode(asserted)), JSON.stringify(decoder.decode(wide.get("present")!))); +console.log(JSON.stringify(decoder.decode(wide.get("present"))), JSON.stringify(decoder.decode(wide.get("absent")))); +console.log(JSON.stringify(new TextDecoder("utf-8").decode(wide.get("absent")!))); From 031c6172f905f45e9838961d350f88deaf73ea62 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 21:20:10 -0500 Subject: [PATCH 196/259] Emit serialized IR with the unwinding ABI in the serialized IR emission test compile() emits textual LLVM on Linux with the unwinding ABI since #2163, so the test's emission from serialized IR passes the same option. --- .../compiler/src/backend/llvm/serialized-ir-emission.test.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/compiler/src/backend/llvm/serialized-ir-emission.test.ts b/packages/compiler/src/backend/llvm/serialized-ir-emission.test.ts index cdbba146c..6d2457c57 100644 --- a/packages/compiler/src/backend/llvm/serialized-ir-emission.test.ts +++ b/packages/compiler/src/backend/llvm/serialized-ir-emission.test.ts @@ -41,6 +41,8 @@ test("sort-heavy programs emit equal LLVM from memory and from serialized IR", a pointerBits: 64, wasi: false, runtimeAbiMarker: false, + // compile() emits Linux textual LLVM with the unwinding ABI. + unwindAbi: process.platform === "linux", objectAudit: sanitize, ...inlineRcOption(options.optimization, sanitize), }); From 492d1558be1a4884dd3c22c4b796361614791b91 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 21:22:54 -0500 Subject: [PATCH 197/259] Complete consecutive synchronous writes in one afterWrite step Node's onwrite queues one afterWrite nextTick for a synchronous write completion and lets later synchronous completions with the same callback join it (afterWriteTickInfo.count); writes without a callback share one. The step then checks 'drain' once, calls the callback once per write and runs finishMaybe once. The runtime queued a stream tick and a nextTick entry per write, which ran the callbacks of later writes after nextTicks queued between them. The queued afterWrite tick now counts the writes that join it, as Node's does. --- .../7514-stream-after-write-order.ts.json | 6 ++ packages/runtime/src/scr_stream.c | 42 ++++++++-- tests/corpus/7514-stream-after-write-order.ts | 76 +++++++++++++++++++ .../7514-stream-after-write-order.ts.json | 1 + 4 files changed, 117 insertions(+), 8 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7514-stream-after-write-order.ts.json create mode 100644 tests/corpus/7514-stream-after-write-order.ts create mode 100644 tests/harness/corpus-costs/7514-stream-after-write-order.ts.json diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7514-stream-after-write-order.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7514-stream-after-write-order.ts.json new file mode 100644 index 000000000..a6c705cd7 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7514-stream-after-write-order.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7514-stream-after-write-order.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_stream.c b/packages/runtime/src/scr_stream.c index 1214ce5fd..cc0b277f3 100644 --- a/packages/runtime/src/scr_stream.c +++ b/packages/runtime/src/scr_stream.c @@ -176,6 +176,9 @@ struct ScrStreamState { size_t n, cap, head; int corked; bool writing, wsync, need_drain, after_scheduled; + /* the queued SCR_ST_AFTER_WRITE tick later synchronous writes with + * the same callback join (Node's afterWriteTickInfo), or NULL */ + struct ScrStreamTick *after_tick; /* Deferred afterWrites Node also defers (a user callback, a 'drain' * or a destroyed stream): its pendingcb, which holds the finish until * they ran — afterWrite's finishMaybe then puts 'finish' on a tick @@ -543,6 +546,9 @@ typedef struct ScrStreamTick { ScrError *err; /* owned or NULL (SCR_ST_ERROR) */ ScrClosure *cb; /* owned or NULL (SCR_ST_AFTER_WRITE / SCR_ST_WCB_ERR / SCR_ST_WRITE_ERR) */ bool hold; /* SCR_ST_AFTER_WRITE: counted in w.after_holds */ + /* SCR_ST_AFTER_WRITE: the synchronous writes it completes, which share + * cb (Node's afterWriteTickInfo.count) */ + size_t count; /* The AsyncLocalStorage context active when the tick was scheduled (+1, * NULL outside a store): Node schedules these steps with * process.nextTick, so their events and callbacks run in it. */ @@ -2117,7 +2123,7 @@ static void scr_stream_error_buffer(ScrStream *s) { * empty), THEN the user's write(chunk, cb) callback, then finishMaybe. * The buffered queue was already restarted by write_done (Node's onwrite * calls clearBuffer before afterWrite). cb moves. */ -static void scr_stream_after_write(ScrStream *s, ScrClosure *cb) { +static void scr_stream_after_write(ScrStream *s, ScrClosure *cb, size_t count) { ScrStreamState *st = s->st; if (st->w.length == 0 && st->w.need_drain && !st->w.ending && !st->destroyed) { st->w.need_drain = false; @@ -2137,7 +2143,11 @@ static void scr_stream_after_write(ScrStream *s, ScrClosure *cb) { } } if (cb) { - ((void (*)(ScrClosure *))cb->fn)(cb); + /* afterWrite: the callback once per write the tick completes */ + for (size_t i = 0; i < count; i++) { + ((void (*)(ScrClosure *))cb->fn)(cb); + if (scr_exc_pending()) break; + } scr_closure_release(cb); if (scr_exc_pending()) return; } @@ -7170,13 +7180,24 @@ void scr_stream_write_done(ScrStream *s, ScrError *err /*moves*/) { } if (was_sync) { bool hold = ucb != NULL || (st->w.need_drain && st->w.length == 0) || st->destroyed; - scr_st_tick(s, SCR_ST_AFTER_WRITE, NULL, ucb); - if (hold) { - scr_st_tail->hold = true; + ScrStreamTick *pending = st->w.after_tick; + if (pending && pending->cb == ucb) { + /* Node's onwrite: a synchronous write with the callback of the + * afterWrite tick already queued joins it (count++) */ + pending->count++; + if (ucb) scr_closure_release(ucb); + } else { + scr_st_tick(s, SCR_ST_AFTER_WRITE, NULL, ucb); + pending = scr_st_tail; + pending->count = 1; + st->w.after_tick = pending; + } + if (hold && !pending->hold) { + pending->hold = true; st->w.after_holds++; } } else { - scr_stream_after_write(s, ucb); + scr_stream_after_write(s, ucb, 1); } } @@ -7722,13 +7743,17 @@ static void scr_stream_run_tick(ScrStreamTick *t) { case SCR_ST_AFTER_WRITE: { st->w.after_scheduled = false; if (t->hold) st->w.after_holds--; + if (st->w.after_tick == t) st->w.after_tick = NULL; ScrClosure *cb = t->cb; t->cb = NULL; if (!st->destroyed) { - scr_stream_after_write(s, cb); + scr_stream_after_write(s, cb, t->count); } else { if (cb) { - ((void (*)(ScrClosure *))cb->fn)(cb); + for (size_t i = 0; i < t->count; i++) { + ((void (*)(ScrClosure *))cb->fn)(cb); + if (scr_exc_pending()) break; + } scr_closure_release(cb); if (scr_exc_pending()) break; } @@ -7898,6 +7923,7 @@ static void scr_stream_run_tick_in_context(ScrStreamTick *t) { } static void scr_stream_tick_free(ScrStreamTick *t) { + if (t->s->st && t->s->st->w.after_tick == t) t->s->st->w.after_tick = NULL; scr_stream_release(t->s); if (t->err) scr_error_release(t->err); if (t->cb) scr_closure_release(t->cb); diff --git a/tests/corpus/7514-stream-after-write-order.ts b/tests/corpus/7514-stream-after-write-order.ts new file mode 100644 index 000000000..5647f5bc8 --- /dev/null +++ b/tests/corpus/7514-stream-after-write-order.ts @@ -0,0 +1,76 @@ +// Write callbacks of synchronous writes run in Node's order: consecutive +// writes with the same callback complete in one afterWrite step, ahead of +// a process.nextTick queued between them, and a write with another +// callback (or none) starts the next step; end's callback and 'finish' +// follow. A PassThrough read by 'data' runs each write's own callback. +import { PassThrough, Writable } from "node:stream"; + +const log: string[] = []; + +function run(): Promise { + return new Promise((resolve) => { + const w = new Writable({ + highWaterMark: 4, + write(chunk: Buffer, _enc, cb) { + log.push(`write ${String(chunk)}`); + cb(); + }, + }); + const shared = (): void => { + log.push("shared callback"); + }; + w.on("finish", () => { + log.push("finish"); + resolve(); + }); + w.write("a", shared); + w.write("b", shared); + process.nextTick(() => log.push("tick between")); + w.write("c", shared); + w.write("d", () => log.push("own callback d")); + w.write("e"); + w.write("f"); + queueMicrotask(() => log.push("microtask")); + w.write("g", shared); + w.write("h", shared); + process.nextTick(() => log.push("tick after")); + w.end(() => log.push("end callback")); + }); +} + +function passThrough(): Promise { + return new Promise((resolve) => { + const pt = new PassThrough({ highWaterMark: 8 }); + let bytes = 0; + pt.on("data", (chunk: Buffer) => { + bytes += chunk.length; + }); + pt.on("end", () => { + log.push(`passthrough end ${bytes}`); + resolve(); + }); + let i = 0; + const more = (): void => { + while (i < 40) { + i++; + const n = i; + if (!pt.write(`chunk${n}`, () => { + if (n % 10 === 0) log.push(`callback ${n}`); + })) { + pt.once("drain", more); + return; + } + } + pt.end(); + }; + more(); + }); +} + +async function main(): Promise { + await run(); + await passThrough(); + console.log(log.join("\n")); +} + +main(); diff --git a/tests/harness/corpus-costs/7514-stream-after-write-order.ts.json b/tests/harness/corpus-costs/7514-stream-after-write-order.ts.json new file mode 100644 index 000000000..56aa0985f --- /dev/null +++ b/tests/harness/corpus-costs/7514-stream-after-write-order.ts.json @@ -0,0 +1 @@ +{ "plain": 2600, "san": 3600 } From dd2e53f00cad23959425d645324dc6ef2f5de365 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 21:40:50 -0500 Subject: [PATCH 198/259] Look up a number Map key on its integer view A Map or Set operation on a number key that the emitter knows is an integer (exactInteger: an integer view, a range proof or a literal) now looks the key up through sc_map_entry_f64_int, which tests the map's direct index with an unsigned compare of that integer. Before, the lookup converted the double back to an integer and compared it with the original to prove it integral. The hashed probe still takes the double, so hashing and SameValueZero are unchanged. --- .../src/backend/llvm/emit-function.ts | 1 + .../compiler/src/backend/llvm/emit-module.ts | 36 +++++++++++ packages/compiler/src/backend/llvm/emitter.ts | 5 +- .../src/backend/llvm/expr-containers.ts | 8 ++- .../backend/llvm/local-union-storage.test.ts | 3 +- .../backend/llvm/map-number-lookup.test.ts | 28 ++++++++- .../src/backend/llvm/map-number-lookup.ts | 24 ++++++- .../src/backend/llvm/map-read-lifetimes.ts | 2 + .../6308-number-map-integer-keys.ts.json | 6 ++ tests/corpus/6308-number-map-integer-keys.ts | 62 +++++++++++++++++++ .../6308-number-map-integer-keys.ts.json | 1 + 11 files changed, 168 insertions(+), 8 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6308-number-map-integer-keys.ts.json create mode 100644 tests/corpus/6308-number-map-integer-keys.ts create mode 100644 tests/harness/corpus-costs/6308-number-map-integer-keys.ts.json diff --git a/packages/compiler/src/backend/llvm/emit-function.ts b/packages/compiler/src/backend/llvm/emit-function.ts index ca45a6624..d7c5696cf 100644 --- a/packages/compiler/src/backend/llvm/emit-function.ts +++ b/packages/compiler/src/backend/llvm/emit-function.ts @@ -200,6 +200,7 @@ export function emitFunction(emitter: LlEmitter, fn: IrFunction): string { emitter.callLifetimes, ); emitter.readNumberMapWrites = findReadNumberMapWrites(fn); + emitter.numberMapKeyIntegers = new Map(); emitter.mapEntryFusion = emitter.debug === null ? findMapEntryFusions(fn) : null; emitter.localStackUnions = findLocalStackUnions( fn, diff --git a/packages/compiler/src/backend/llvm/emit-module.ts b/packages/compiler/src/backend/llvm/emit-module.ts index 6adf76079..c6d3dbff4 100644 --- a/packages/compiler/src/backend/llvm/emit-module.ts +++ b/packages/compiler/src/backend/llvm/emit-module.ts @@ -1301,6 +1301,42 @@ export function helperDefs(emitter: LlEmitter): string[] { ` ret ptr %hashed`, `}`, ``, + // The same lookup for a key the emitter knows is an integer (`%ki`, + // the double `%k`'s exact value): the direct index tests the integer + // itself, so the double is converted only by the hashed probe. A + // negative key is not below the index's size as an unsigned value. + `define internal ptr @sc_map_entry_f64_int(ptr %m, i64 %ki, double %k) ${FN_ATTRS} {`, + `entry:`, + ` %ndp = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32 16`, + ` %nd32 = load i32, ptr %ndp`, + ` %nd = zext i32 %nd32 to i64`, + ` %inside = icmp ult i64 %ki, %nd`, + ` br i1 %inside, label %slot, label %outside`, + `slot:`, + sz === "i64" ? ` %i = add i64 %ki, 0` : ` %i = trunc i64 %ki to ${sz}`, + ` %dp = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32 15`, + ` %dense = load ptr, ptr %dp`, + ` %sp = getelementptr inbounds i32, ptr %dense, ${sz} %i`, + ` %s = load i32, ptr %sp`, + ` %empty = icmp eq i32 %s, 0`, + ` br i1 %empty, label %miss, label %hit`, + `hit:`, + ` %e32 = sub i32 %s, 1`, + sz === "i32" ? ` %e = add i32 %e32, 0` : ` %e = zext i32 %e32 to ${sz}`, + ` %ep = getelementptr inbounds %ScrMapIx, ptr %m, i32 0, i32 11`, + ` %entries = load ptr, ptr %ep`, + ` %found = getelementptr inbounds %ScrMapNumEntry, ptr %entries, ${sz} %e`, + ` ret ptr %found`, + `miss:`, + ` ret ptr null`, + `outside:`, + ` %dense.any = icmp ne i64 %nd, 0`, + ` br i1 %dense.any, label %miss, label %slow`, + `slow:`, + ` %hashed = call ptr @sc_map_entry_f64_hashed(ptr %m, double %k)`, + ` ret ptr %hashed`, + `}`, + ``, // Hashing (scr_map_find_f64): the SameValueZero key word, its // scr_key_mix hash (zero remapped to one) and the absent-key filter. `define internal ptr @sc_map_entry_f64_hashed(ptr %m, double %k) noinline ${FN_ATTRS} {`, diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index bcb8a5ba2..0dae48868 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -123,7 +123,7 @@ import { } from "./int32-abi.js"; import { type Int32Local } from "./int32-locals.js"; import { findIntegerClones, NO_INTEGER_CLONES, type IntegerClones } from "./integer-clones.js"; -import { exactInteger, narrowInteger, widenInteger } from "./integer-values.js"; +import { exactInteger, narrowInteger, widenInteger, type LlInteger } from "./integer-values.js"; import { findInitializerBindings } from "../../ir/initializer-bindings.js"; import { findConstantNumericTables, type ConstantNumericTable } from "../../ir/constant-tables.js"; import { @@ -1241,6 +1241,9 @@ export class LlEmitter { callArrayReads = new Map(); mapReadLifetimes: MapReadLifetimes = { locals: new Map(), arguments: new Map() }; readNumberMapWrites: ReadonlySet = new Set(); + /** The integer views of the current function's number Map/Set keys, by + * the key's double operand (noteNumberMapKey, map-number-lookup.ts). */ + numberMapKeyIntegers = new Map(); /** The current function's fused string-key Map get-then-set pairs (map-entry-fusion.ts). */ mapEntryFusion: MapEntryFusion | null = null; readonly callLifetimes: CallLifetimes; diff --git a/packages/compiler/src/backend/llvm/expr-containers.ts b/packages/compiler/src/backend/llvm/expr-containers.ts index 59ef43d7d..98389b2e5 100644 --- a/packages/compiler/src/backend/llvm/expr-containers.ts +++ b/packages/compiler/src/backend/llvm/expr-containers.ts @@ -42,6 +42,7 @@ import { emitStringMapGetRef, emitStringMapGetScalar, emitStringMapHas, + noteNumberMapKey, } from "./map-number-lookup.js"; import { emitBorrowedInput } from "./borrowed-inputs.js"; import { emitFusedMapSet, rememberMapEntry } from "./map-entry-fusion.js"; @@ -1548,6 +1549,7 @@ export function emitMapLikeIntrinsic( // Key borrowed (the runtime retains stored string keys); the // value MOVES in (replacement releases the old value inside). const k = emitBorrowedInput(host, e.args[0]!); + if (kAcc === "f64") noteNumberMapKey(host, k, e.args[0]!); const v = host.emitExpr(e.args[1]!); const vAcc = elemAccess(receiverType.value); if (vAcc === "ref") host.toHeap(v); @@ -1574,6 +1576,7 @@ export function emitMapLikeIntrinsic( // Element borrowed (the runtime retains stored strings); the unit // value is 0. Re-adding overwrites in place, preserving insertion. const k = emitBorrowedInput(host, e.args[0]!); + if (kAcc === "f64") noteNumberMapKey(host, k, e.args[0]!); if (kAcc === "f64" && host.readNumberMapWrites.has(e)) emitNumberMapSetScalar(host, r.name, k.name, null, () => host.mapSet(r.name, kAcc, "f64", k.name, f64Lit(0)), @@ -1583,7 +1586,10 @@ export function emitMapLikeIntrinsic( } case "has": { const k = borrowInputs ? host.emitReadReceiver(e.args[0]!) : host.emitExpr(e.args[0]!); - if (kAcc === "f64") return { name: emitNumberMapHas(host, r.name, k.name), type: e.type }; + if (kAcc === "f64") { + noteNumberMapKey(host, k, e.args[0]!); + return { name: emitNumberMapHas(host, r.name, k.name), type: e.type }; + } if (kAcc === "str") return { name: emitStringMapHas(host, r.name, k.name, compact), type: e.type }; host.declare(`declare zeroext i1 @scr_map_has_${kAcc}(ptr, ${kTy})`); diff --git a/packages/compiler/src/backend/llvm/local-union-storage.test.ts b/packages/compiler/src/backend/llvm/local-union-storage.test.ts index b8f44408d..81019cadc 100644 --- a/packages/compiler/src/backend/llvm/local-union-storage.test.ts +++ b/packages/compiler/src/backend/llvm/local-union-storage.test.ts @@ -113,7 +113,8 @@ test("conditional and reassigned locals own payload snapshots without heap wrapp expect(facts(mod).get("item")?.ownerType).toEqual(STRING); for (const bits of [32, 64] as const) { const ir = body(mod, bits); - expect(ir).toContain("call ptr @sc_map_entry_f64("); // inline number-key read + // The inline number-key read, on the integer view of the literal key. + expect(ir).toMatch(/call ptr @sc_map_entry_f64_int\(ptr %\S+, i64 \d+, double /); expect(ir).toContain("@scr_str_release"); expect(ir).not.toMatch(/@scr_union_(?:new|retain|release)/); expect(ir).toContain("store i64 0"); diff --git a/packages/compiler/src/backend/llvm/map-number-lookup.test.ts b/packages/compiler/src/backend/llvm/map-number-lookup.test.ts index 989b8b3b0..28b6a0552 100644 --- a/packages/compiler/src/backend/llvm/map-number-lookup.test.ts +++ b/packages/compiler/src/backend/llvm/map-number-lookup.test.ts @@ -118,7 +118,7 @@ test("string keys and reference values are retained inline, boolean slots compar }); /** work(map, k): map.has(k) on a number-keyed map. */ -function lookupFixture(): IrModule { +function lookupFixture(key: IrExpr = ref("k", F64)): IrModule { const map: IrType = { kind: "map", key: F64, value: F64 }; const params = [ { localId: "map", name: "map", type: map }, @@ -128,7 +128,7 @@ function lookupFixture(): IrModule { kind: "mapIntrinsic", method: "has", receiver: ref("map", map), - args: [ref("k", F64)], + args: [key], type: BOOL, loc, }; @@ -182,6 +182,30 @@ test("hashed number-key lookups probe inline and call the runtime only for wide } }); +test("a key with an integer view tests the direct index on the integer", () => { + for (const bits of [32, 64] as const) { + const sz = bits === 64 ? "i64" : "i32"; + const integral = emitted(lookupFixture({ kind: "numLit", value: 12, type: F64, loc }), bits); + expect(integral.work).toMatch(/call ptr @sc_map_entry_f64_int\(ptr %\S+, i64 12, double /); + const helper = + /^define internal ptr @sc_map_entry_f64_int\(ptr %m, i64 %ki, double %k\)[^]*?^}/m.exec( + integral.module, + )![0]; + // An unsigned compare also rejects negative keys; the hashed probe takes + // the double. + expect(helper).toContain("icmp ult i64 %ki, %nd"); + expect(helper).toContain(`getelementptr inbounds i32, ptr %dense, ${sz} %i`); + expect(helper).toContain("call ptr @sc_map_entry_f64_hashed(ptr %m, double %k)"); + expect(helper).not.toContain("fptosi"); + // A fractional key and a key without a proof keep the double lookup. + for (const key of [{ kind: "numLit", value: 0.5, type: F64, loc } as IrExpr, ref("k", F64)]) { + const { work } = emitted(lookupFixture(key), bits); + expect(work).toContain("call ptr @sc_map_entry_f64("); + expect(work).not.toContain("@sc_map_entry_f64_int("); + } + } +}); + /** work(map): map.size, and keep(map): map returned as an owned value. */ function sizeFixture(): IrModule { const map: IrType = { kind: "map", key: F64, value: F64 }; diff --git a/packages/compiler/src/backend/llvm/map-number-lookup.ts b/packages/compiler/src/backend/llvm/map-number-lookup.ts index 6d219b50a..6cb7f1ea3 100644 --- a/packages/compiler/src/backend/llvm/map-number-lookup.ts +++ b/packages/compiler/src/backend/llvm/map-number-lookup.ts @@ -28,16 +28,34 @@ * guard excludes. for-of starts at scr_map_iter_start, past a deleted * prefix. */ -import type { IrType } from "../../ir/ir.js"; -import type { LlvmEmitterContext } from "./expr-context.js"; +import type { IrExpr, IrType } from "../../ir/ir.js"; +import type { LlValue, LlvmEmitterContext } from "./expr-context.js"; +import { exactInteger, widenInteger } from "./integer-values.js"; import { mapKeyAccess } from "./shapes.js"; export const NUMBER_MAP_ENTRY_DECL = "declare ptr @scr_map_entry_f64(ptr, double)"; +/** Record the integer view of a number Map/Set key operand, when the + * emitter has one (exactInteger), for the entry lookups of that key. */ +export function noteNumberMapKey(host: LlvmEmitterContext, key: LlValue, expr: IrExpr): void { + if (key.type.kind !== "f64" || host.numberMapKeyIntegers.has(key.name)) return; + const integer = exactInteger(host, key, expr); + if (integer) host.numberMapKeyIntegers.set(key.name, integer); +} -/** The entry for `key`, or null when absent. Valid until the next mutation. */ +/** The entry for `key`, or null when absent. Valid until the next mutation. + * A key with an integer view (noteNumberMapKey) tests the direct index on + * that integer instead of converting the double back. */ export function emitNumberMapEntry(host: LlvmEmitterContext, map: string, key: string): string { host.declare(NUMBER_MAP_ENTRY_DECL); const entry = host.B.tmp(); + const integer = host.numberMapKeyIntegers.get(key); + if (integer) { + const wide = widenInteger(host, integer); + host.B.line( + `${entry} = call ptr @sc_map_entry_f64_int(ptr ${map}, i64 ${wide}, double ${key})`, + ); + return entry; + } host.B.line(`${entry} = call ptr @sc_map_entry_f64(ptr ${map}, double ${key})`); return entry; } diff --git a/packages/compiler/src/backend/llvm/map-read-lifetimes.ts b/packages/compiler/src/backend/llvm/map-read-lifetimes.ts index 6053d70eb..c44e28cb2 100644 --- a/packages/compiler/src/backend/llvm/map-read-lifetimes.ts +++ b/packages/compiler/src/backend/llvm/map-read-lifetimes.ts @@ -16,6 +16,7 @@ import { emitStringMapGetScalar, emitStringMapGetRef, compactMapValues, + noteNumberMapKey, } from "./map-number-lookup.js"; import { mapKeyAccess, mapKeyParamType } from "./shapes.js"; import { rememberMapEntry } from "./map-entry-fusion.js"; @@ -265,6 +266,7 @@ export function emitMapLookupKey( const value = borrow ? host.emitReadReceiver(key) : host.emitExpr(key); const access = mapKeyAccess(key.type); const type = mapKeyParamType(access); + if (access === "f64") noteNumberMapKey(host, value, key); return { access, types: type, args: `${type} ${value.name}`, value: value.name }; } diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6308-number-map-integer-keys.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6308-number-map-integer-keys.ts.json new file mode 100644 index 000000000..b58240a3e --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6308-number-map-integer-keys.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6308-number-map-integer-keys.ts" + ], + "diags": [] +} diff --git a/tests/corpus/6308-number-map-integer-keys.ts b/tests/corpus/6308-number-map-integer-keys.ts new file mode 100644 index 000000000..16110f80a --- /dev/null +++ b/tests/corpus/6308-number-map-integer-keys.ts @@ -0,0 +1,62 @@ +// Number-keyed Map and Set operations whose keys the compiler knows are +// integers (loop counters, `| 0` results, typed-array bytes, integer +// arithmetic) test the map's direct index on the integer. Results must +// match Node while the index covers the keys, after a key outside it moves +// the map to hashing, for negative keys and for keys past the index, and +// when a double key and an integer key name the same entry. + +const counts = new Map(); +for (let i = 0; i < 200; i++) { + const key = (i * 7) % 13; + counts.set(key, (counts.get(key) ?? 0) + 1); +} +const dense: string[] = []; +for (let k = -2; k < 16; k++) dense.push(`${k}:${counts.has(k) ? counts.get(k) : "-"}`); +console.log(dense.join(" ")); + +// A key past the direct index moves the map to hashing; integer reads still +// find every key. +counts.set(1_000_000, 5); +let found = 0; +for (let k = -2; k < 16; k++) if (counts.has(k)) found += counts.get(k)!; +console.log(found, counts.get(1_000_000), counts.has(999_999), counts.size); + +// Negative keys, and keys built with `| 0` and shifts. +const signed = new Map(); +for (let i = -5; i <= 5; i++) signed.set((i * 3) | 0, `v${i}`); +const reads: string[] = []; +for (let i = -16; i <= 16; i += 4) reads.push(`${i}:${signed.get(i) ?? "-"}`); +console.log(reads.join(" "), signed.get(-0), signed.get(0)); + +// Bytes of a typed array as keys, in a Set. +const bytes = new Uint8Array([3, 250, 3, 0, 17, 250, 255, 0]); +const seen = new Set(); +let repeats = 0; +for (let i = 0; i < bytes.length; i++) { + if (seen.has(bytes[i]!)) repeats++; + seen.add(bytes[i]!); +} +console.log([...seen].join(","), repeats); + +// A double key and an integer key name the same entry. +const mixed = new Map(); +mixed.set(2.0, 1); +mixed.set(0.5, 2); +for (let i = 0; i < 4; i++) mixed.set(i, (mixed.get(i) ?? 0) + 10); +console.log([...mixed.entries()].map(([k, v]) => `${k}=${v}`).join(" "), mixed.get(0.5)); + +// Deletion through integer keys, then reinsertion order. +const order = new Map(); +for (let i = 0; i < 10; i++) order.set(i, i * i); +for (let i = 0; i < 10; i += 3) order.delete(i); +for (let i = 9; i >= 0; i -= 2) order.set(i, -i); +console.log([...order.entries()].map(([k, v]) => `${k}=${v}`).join(" ")); + +// Large integer keys near 2^53, from integer arithmetic. +const wide = new Map(); +let key = 2 ** 52; +for (let i = 0; i < 5; i++) { + wide.set(key, i); + key = key * 2 - 1; +} +console.log([...wide.keys()].join(" "), wide.get(2 ** 52), wide.get(2 ** 53 - 1)); diff --git a/tests/harness/corpus-costs/6308-number-map-integer-keys.ts.json b/tests/harness/corpus-costs/6308-number-map-integer-keys.ts.json new file mode 100644 index 000000000..a6e4996ff --- /dev/null +++ b/tests/harness/corpus-costs/6308-number-map-integer-keys.ts.json @@ -0,0 +1 @@ +{ "plain": 2800, "san": 3500 } From f025b5243345daa0b2855173f93806be557e6b3c Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 21:50:36 -0500 Subject: [PATCH 199/259] Declare a typed-array loop version's alias scopes where its fast copy starts The guard proves the views disjoint for one entry of the loop. An enclosing loop may pass other views on its next pass, such as two buffers swapped after every pass, so one pass's write and the next pass's read can be the same bytes under different scopes. Without a declaration, a scope holds across the whole function, and LLVM could apply one entry's no-alias facts to another's accesses once it unrolled the enclosing loop. Each fast copy now begins with llvm.experimental.noalias.scope.decl for each of its scopes. A declared scope holds from its declaration, and LLVM gives each copy of the declaration its own scopes when it unrolls or duplicates the code around it. Corpus 8182 adds ping-pong passes over swapped Float64Array and Int32Array views; the emission test checks the declarations. --- .../src/backend/llvm/emit-statements.ts | 32 +++++++++---- .../typed-array-alias-scope-emission.test.ts | 7 +++ tests/corpus/8182-typed-array-alias-scopes.ts | 47 ++++++++++++++++++- 3 files changed, 76 insertions(+), 10 deletions(-) diff --git a/packages/compiler/src/backend/llvm/emit-statements.ts b/packages/compiler/src/backend/llvm/emit-statements.ts index 36c28bf97..9b7ed9d8f 100644 --- a/packages/compiler/src/backend/llvm/emit-statements.ts +++ b/packages/compiler/src/backend/llvm/emit-statements.ts @@ -2085,11 +2085,12 @@ const SPECULATION_BAILS = 8; * scope of its own view, and no alias with the scopes of the other views, * whose bytes the guard proved disjoint. The scopes are named after the * function and the version, so every copy of a loop has its own, and - * written inline (string-named scopes need no numbered metadata). */ + * written inline (string-named scopes need no numbered metadata). Also + * the scopes, which each fast copy declares on entry (declareAliasScopes). */ function bytesAliasScopes( emitter: LlEmitter, scopes: NonNullable, -): Map { +): { attachments: Map; scopes: string[] } { const version = emitter.aliasScopedVersions++; const name = emitter.currentFunctionName.replace(/[^A-Za-z0-9_.$%]/g, "_"); const domain = '!{!"scriptc typed-array views"}'; @@ -2104,7 +2105,20 @@ function bytesAliasScopes( } const result = new Map(); for (const [node, receiver] of scopes.nodes) result.set(node, attachments.get(receiver)!); - return result; + return { attachments: result, scopes: scopes.receivers.map(scope) }; +} + +/** Declares a version's scopes where a fast copy starts. The guard proves + * the views disjoint for this entry only: an enclosing loop may pass other + * views on its next pass (`[cur, next] = [next, cur]`). A declared scope + * holds from its declaration, and LLVM gives each copy of the declaration + * its own scopes when it unrolls or duplicates the enclosing code, so the + * no-alias facts of one entry never apply to the accesses of another. */ +function declareAliasScopes(emitter: LlEmitter, scopes: readonly string[]): void { + if (scopes.length === 0) return; + emitter.declare("declare void @llvm.experimental.noalias.scope.decl(metadata)"); + for (const scope of scopes) + emitter.B.line(`call void @llvm.experimental.noalias.scope.decl(metadata !{${scope}})`); } /** Emit a loop's condition, body and update through `emitCopy`, twice @@ -2142,15 +2156,14 @@ function emitVersionedLoop( if (version.ranges.size > 0) emitter.integerRanges = new Map([...originalRanges, ...version.ranges]); // Both fast copies run under the guard's span test, so they share the - // version's scopes. - if (version.scopes && emitter.debug === null) - emitter.bytesAliasScopes = new Map([ - ...originalScopes, - ...bytesAliasScopes(emitter, version.scopes), - ]); + // version's scopes, and each declares them on entry. + const scoped = + version.scopes && emitter.debug === null ? bytesAliasScopes(emitter, version.scopes) : null; + if (scoped) emitter.bytesAliasScopes = new Map([...originalScopes, ...scoped.attachments]); if (version.counted?.guarded || version.paired?.loop.guarded) LOOPS.of(emitter).provenCountedGuards.add(s); B.startBlock(fast); + declareAliasScopes(emitter, scoped?.scopes ?? []); emitter.bytesBounds = new Set([...originalBounds, ...version.bounds]); // Both fast copies read the string's length the guard took. const length = guard?.length; @@ -2164,6 +2177,7 @@ function emitVersionedLoop( if (unitsFast !== undefined && units !== null) { // The string reads take the receiver's UTF-16 units. B.startBlock(unitsFast); + declareAliasScopes(emitter, scoped?.scopes ?? []); emitter.bytesBounds = new Set([ ...originalBounds, ...[...version.bounds].filter((node) => !version.stringReads.has(node)), diff --git a/packages/compiler/test/typed-array-alias-scope-emission.test.ts b/packages/compiler/test/typed-array-alias-scope-emission.test.ts index a32df03e7..c94b58d59 100644 --- a/packages/compiler/test/typed-array-alias-scope-emission.test.ts +++ b/packages/compiler/test/typed-array-alias-scope-emission.test.ts @@ -46,6 +46,13 @@ console.log(dot(a, b, 8)); /load double, ptr %\w+, align 1[^\n]*!alias\.scope !\{!\{!"copy\.0\.\d", !\{!"scriptc typed-array views"\}\}\}, !noalias/, ); expect(copy).toMatch(/store double %\w+, ptr %\w+, align 1[^\n]*!alias\.scope/); + // The fast copy declares both scopes where it starts, so they hold for + // this entry only, and declares nothing else. + for (const receiver of [0, 1]) + expect(copy).toContain( + `call void @llvm.experimental.noalias.scope.decl(metadata !{!{!"copy.0.${receiver}", !{!"scriptc typed-array views"}}})`, + ); + expect(copy.match(/noalias\.scope\.decl/g)).toHaveLength(2); // One view, or views that are only read, need no scopes. for (const name of ["scale", "dot"]) { expect(fn(name)).not.toContain("!alias.scope"); diff --git a/tests/corpus/8182-typed-array-alias-scopes.ts b/tests/corpus/8182-typed-array-alias-scopes.ts index 4dbf52e47..f56face07 100644 --- a/tests/corpus/8182-typed-array-alias-scopes.ts +++ b/tests/corpus/8182-typed-array-alias-scopes.ts @@ -1,7 +1,9 @@ // Loops that read one typed array and write another, where the two views // may share bytes: overlapping and disjoint views of one buffer, the same // array passed twice, views of different element types over one buffer, -// and empty views. A loop over views that overlap must see its own writes. +// and empty views, and passes whose views an enclosing loop swaps. A loop +// over views that overlap must see its own writes, and each pass the +// previous pass's writes. function shiftAdd(dst: Float64Array, src: Float64Array, n: number): void { for (let i = 0; i < n; i++) dst[i] = src[i]! + 1; } @@ -87,3 +89,46 @@ console.log( "lanes overlapping", lanes(pool.subarray(0, 4), pool.subarray(2, 6), pool.subarray(8, 12), pool.subarray(9, 13)).toFixed(6), ); + +// Ping-pong passes: an enclosing loop swaps the two views after every pass, +// so each pass reads what the previous one wrote. +function pingPongPairs(a: Float64Array, b: Float64Array, steps: number): string { + let cur = a; + let next = b; + for (let s = 0; s < steps; s++) { + for (let i = 0; i < 2; i++) next[i] = cur[i]! + cur[1 - i]! * 2 + s; + const t = cur; + cur = next; + next = t; + } + return Array.from(cur).join(","); +} +function pingPongWords(a: Int32Array, b: Int32Array): string { + let cur = a; + let next = b; + for (let s = 0; s < 4; s++) { + for (let i = 0; i < 4; i++) next[i] = (cur[i]! * 3 + cur[(i + 1) & 3]! + 1) | 0; + const t = cur; + cur = next; + next = t; + } + return Array.from(cur).join(","); +} +function pingPongRows(a: Float64Array, b: Float64Array, steps: number): number { + let cur = a; + let next = b; + for (let s = 0; s < steps; s++) { + for (let i = 0; i < cur.length; i++) next[i] = cur[i]! * 0.5 + 1; + const t = cur; + cur = next; + next = t; + } + let sum = 0; + for (let i = 0; i < cur.length; i++) sum += cur[i]!; + return sum; +} +for (let k = 0; k < 3; k++) { + console.log("ping-pong pairs", pingPongPairs(new Float64Array([1, 2]), new Float64Array(2), 3 + k)); + console.log("ping-pong words", pingPongWords(new Int32Array([1, 2, 3, 4]), new Int32Array(4))); +} +console.log("ping-pong rows", pingPongRows(new Float64Array(37).fill(8), new Float64Array(37), 9)); From d6c8b0f260e3d18829f67ce0c0808a68bf66a549 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 21:52:18 -0500 Subject: [PATCH 200/259] Close the afterWrite batch whenever an afterWrite tick runs Node's afterWriteTick sets afterWriteTickInfo to null before it runs the callbacks, whichever tick it is. The runtime cleared the queued batch only when the running tick was that batch, so a write made from an earlier tick's callback joined a later queued tick with the same callback and completed ahead of nextTicks queued between them. Any afterWrite tick now closes the batch, and such a write queues its own. --- packages/runtime/src/scr_stream.c | 4 ++- tests/corpus/7514-stream-after-write-order.ts | 28 ++++++++++++++++++- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/packages/runtime/src/scr_stream.c b/packages/runtime/src/scr_stream.c index cc0b277f3..406d91599 100644 --- a/packages/runtime/src/scr_stream.c +++ b/packages/runtime/src/scr_stream.c @@ -7743,7 +7743,9 @@ static void scr_stream_run_tick(ScrStreamTick *t) { case SCR_ST_AFTER_WRITE: { st->w.after_scheduled = false; if (t->hold) st->w.after_holds--; - if (st->w.after_tick == t) st->w.after_tick = NULL; + /* afterWriteTick: the batch closes when any afterWrite tick runs, so + * a write its callback makes queues a new tick */ + st->w.after_tick = NULL; ScrClosure *cb = t->cb; t->cb = NULL; if (!st->destroyed) { diff --git a/tests/corpus/7514-stream-after-write-order.ts b/tests/corpus/7514-stream-after-write-order.ts index 5647f5bc8..1c14de6eb 100644 --- a/tests/corpus/7514-stream-after-write-order.ts +++ b/tests/corpus/7514-stream-after-write-order.ts @@ -2,7 +2,9 @@ // writes with the same callback complete in one afterWrite step, ahead of // a process.nextTick queued between them, and a write with another // callback (or none) starts the next step; end's callback and 'finish' -// follow. A PassThrough read by 'data' runs each write's own callback. +// follow. A write made from a write callback starts a new afterWrite step +// even when its callback matches a later queued one. A PassThrough read by +// 'data' runs each write's own callback. import { PassThrough, Writable } from "node:stream"; const log: string[] = []; @@ -38,6 +40,29 @@ function run(): Promise { }); } +function nested(): Promise { + return new Promise((resolve) => { + const w = new Writable({ + write(chunk: Buffer, _enc, cb) { + log.push(`nested write ${String(chunk)}`); + cb(); + }, + }); + let laterCalls = 0; + const later = (): void => { + log.push("later callback"); + if (++laterCalls === 2) resolve(); + }; + w.write("a", () => { + log.push("first callback"); + w.write("from first", later); + }); + process.nextTick(() => log.push("nested tick 1")); + w.write("b", later); + process.nextTick(() => log.push("nested tick 2")); + }); +} + function passThrough(): Promise { return new Promise((resolve) => { const pt = new PassThrough({ highWaterMark: 8 }); @@ -69,6 +94,7 @@ function passThrough(): Promise { async function main(): Promise { await run(); + await nested(); await passThrough(); console.log(log.join("\n")); } From 4241ca533f86e2c9bb7df0854f610fbd2f4dc1d6 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 21:59:28 -0500 Subject: [PATCH 201/259] Read elements of native arrays passed to untyped code by index A typed array such as a number[] reaches untyped code as a capsule of the native array. A keyed read `xs[i]` there missed the inline cache, which answers only dyn arrays, and went to the member helper, which converted the index to a string; the capsule's key lookup then parsed the string back into a number for every element. Keyed sites now read an element of a native number[] capsule in place when the index is an integer below the array's hole-free prefix, and `length` sites read the native array's length. Other capsule elements (holes, out-of-range and fractional indices, arrays of other element types) are answered by the keyed probe through scr_dyn_index_get without forming the key, or by the helper as before. --- packages/compiler/src/backend/llvm/js-ic.ts | 128 ++++++++++++++++-- packages/compiler/test/js-ic-emission.test.ts | 41 ++++++ .../main.ts.json | 7 + packages/runtime/src/scr_dyn.h | 4 +- packages/runtime/src/scr_js_object.c | 3 + .../8300-native-array-capsule-reads/lib.cjs | 36 +++++ .../8300-native-array-capsule-reads/main.ts | 59 ++++++++ .../package.json | 1 + .../main.ts.json | 1 + 9 files changed, 268 insertions(+), 12 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8300-native-array-capsule-reads/main.ts.json create mode 100644 tests/corpus/8300-native-array-capsule-reads/lib.cjs create mode 100644 tests/corpus/8300-native-array-capsule-reads/main.ts create mode 100644 tests/corpus/8300-native-array-capsule-reads/package.json create mode 100644 tests/harness/corpus-costs/8300-native-array-capsule-reads/main.ts.json diff --git a/packages/compiler/src/backend/llvm/js-ic.ts b/packages/compiler/src/backend/llvm/js-ic.ts index 7516673cd..b8be1ecb1 100644 --- a/packages/compiler/src/backend/llvm/js-ic.ts +++ b/packages/compiler/src/backend/llvm/js-ic.ts @@ -384,6 +384,15 @@ function emitGet(host: Host, e: ExprOf<"call">, callee: IrFunction, key: string) incoming.push(`[ ${numberResult(host, count, e)}, %${B.currentLabel()} ]`); B.br(join); B.startBlock(other); + // So is the length of a native array passed in from typed code. + const rest = B.newLabel("icg.rest"); + const arr = nativeArray(host, receiver.name, rest); + const native = load(host, "i32", arr, 8); + const nativeCount = B.tmp(); + B.line(`${nativeCount} = uitofp i32 ${native} to double`); + incoming.push(`[ ${numberResult(host, nativeCount, e)}, %${B.currentLabel()} ]`); + B.br(join); + B.startBlock(rest); } // Inline hits (borrowed values) and probe hits (owned ones) share one // conversion to the result type. @@ -623,6 +632,98 @@ function numberKey(host: Host, key: IrExpr): NumberKey | null { }; } +/** Branches to `yes` when `d` is a capsule of a native array passed in + * from typed code (a TYPED_REF bound to live array ops, not a record or + * class instance), with the ScrArr in `yes`; else to `no`. */ +function nativeArray(host: Host, d: string, no: string): string { + const B = host.B; + const capsule = B.newLabel("ica.cap"); + const bound = B.newLabel("ica.ops"); + const yes = B.newLabel("ica.arr"); + kindIs(host, d, DYN_KIND.TYPED_REF, capsule, no); + B.startBlock(capsule); + // The flag word after `casts`: record, klass and bag_class are its top + // three bits; any of them means `array` holds other ops. + const flags = load(host, "i32", d, 88); + const kinds = B.tmp(); + const plain = B.tmp(); + B.line(`${kinds} = lshr i32 ${flags}, 29`); + B.line(`${plain} = icmp eq i32 ${kinds}, 0`); + B.condBr(plain, bound, no); + B.startBlock(bound); + const ops = load(host, "ptr", d, 64); + const live = B.tmp(); + B.line(`${live} = icmp ne ptr ${ops}, null`); + B.condBr(live, yes, no); + B.startBlock(yes); + return load(host, "ptr", d, 16); +} + +/** `xs[i]` on a native number[] passed in from typed code: an integral + * index below the array's hole-free prefix reads the element in place. + * The other cases branch to `miss`, whose probe and helper answer them as + * before. The result joins `incoming` at `join`. */ +function emitNativeNumberElement( + host: Host, + receiver: string, + e: IrExpr, + indexIn: (next: string) => string, + miss: string, + join: string, + incoming: string[], +): void { + const B = host.B; + const arr = nativeArray(host, receiver, miss); + const numbers = B.newLabel("ica.f64"); + const elem = load(host, "i8", arr, 16); + const f64 = B.tmp(); + B.line(`${f64} = icmp eq i8 ${elem}, 0 ; SCR_ELEM_F64`); + B.condBr(f64, numbers, miss); + B.startBlock(numbers); + const index = indexIn(B.newLabel("ica.idx")); + const filled = load(host, "i32", arr, 20); + const filledD = B.tmp(); + const nonNegative = B.tmp(); + const below = B.tmp(); + const ok = B.tmp(); + B.line(`${filledD} = uitofp i32 ${filled} to double`); + B.line(`${nonNegative} = fcmp oge double ${index}, 0.0`); + B.line(`${below} = fcmp olt double ${index}, ${filledD}`); + B.line(`${ok} = and i1 ${nonNegative}, ${below}`); + const ranged = B.newLabel("ica.rng"); + B.condBr(ok, ranged, miss); + B.startBlock(ranged); + const i = B.tmp(); + const back = B.tmp(); + const integral = B.tmp(); + B.line(`${i} = fptoui double ${index} to i64`); + B.line(`${back} = uitofp i64 ${i} to double`); + B.line(`${integral} = fcmp oeq double ${back}, ${index}`); + const hit = B.newLabel("ica.hit"); + B.condBr(integral, hit, miss); + B.startBlock(hit); + const data = load(host, "ptr", arr, 24); + const slot = B.tmp(); + const value = B.tmp(); + B.line(`${slot} = getelementptr inbounds double, ptr ${data}, i64 ${i}`); + B.line(`${value} = load double, ptr ${slot}`); + let out: string; + if (e.type.kind === "jsval") { + const raw = B.tmp(); + const nan = B.tmp(); + const bits = B.tmp(); + out = B.tmp(); + B.line(`${raw} = bitcast double ${value} to i64`); + B.line(`${nan} = fcmp uno double ${value}, ${value}`); + B.line(`${bits} = select i1 ${nan}, i64 ${JS_BITS.canonicalNan}, i64 ${raw}`); + B.line(`${out} = inttoptr i64 ${bits} to ptr`); + } else { + out = numberResult(host, value, e); + } + incoming.push(`[ ${out}, %${B.currentLabel()} ]`); + B.br(join); +} + function emitKeyed(host: Host, e: ExprOf<"call">, callee: IrFunction): LlValue { const B = host.B; const receiver = emitBorrowedInput(host, e.args[0]!); @@ -645,18 +746,23 @@ function emitKeyed(host: Host, e: ExprOf<"call">, callee: IrFunction): LlValue { B.line(`store ptr null, ptr ${keySlot}`); host.ownSlot(keySlot, DYN); } - kindIs(host, receiver.name, DYN_KIND.ARR, array, probe); + /** The key as a double in block `next`; other keys go to the probe. */ + const indexIn = (next: string): string => { + if (numeric === null) { + kindIs(host, key!.name, DYN_KIND.NUM, next, probe); + B.startBlock(next); + return load(host, "double", key!.name, 16); + } + B.condBr(numeric.present, next, probe); + B.startBlock(next); + return numeric.value; + }; + const other = B.newLabel("ick.other"); + kindIs(host, receiver.name, DYN_KIND.ARR, array, other); + B.startBlock(other); + emitNativeNumberElement(host, receiver.name, e, indexIn, probe, join, incoming); B.startBlock(array); - let index: string; - if (numeric === null) { - kindIs(host, key!.name, DYN_KIND.NUM, number, probe); - B.startBlock(number); - index = load(host, "double", key!.name, 16); - } else { - B.condBr(numeric.present, number, probe); - B.startBlock(number); - index = numeric.value; - } + const index = indexIn(number); const len = load(host, "i64", receiver.name, 16); const i = B.tmp(); const back = B.tmp(); diff --git a/packages/compiler/test/js-ic-emission.test.ts b/packages/compiler/test/js-ic-emission.test.ts index 54ea13d26..7a1d44f34 100644 --- a/packages/compiler/test/js-ic-emission.test.ts +++ b/packages/compiler/test/js-ic-emission.test.ts @@ -134,3 +134,44 @@ console.log(len2({ x: 3, y: 4 }), typeof parsed); await rm(dir, { recursive: true, force: true }); } }); + +test("keyed and length sites read native number arrays in place", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-js-ic-native-")); + try { + const entry = join(dir, "main.ts"); + const outPath = join(dir, "main.ir.json"); + await writeFile(join(dir, "package.json"), `{ "type": "module" }`); + await writeFile( + join(dir, "lib.cjs"), + `exports.total = function (xs) { + let s = 0; + for (let i = 0; i < xs.length; i++) s += xs[i]; + return s; +}; +`, + ); + await writeFile( + entry, + `import { createRequire } from "node:module"; +const require = createRequire(import.meta.url); +const lib: { total(xs: number[]): number } = require("./lib.cjs"); +console.log(lib.total([1, 2, 3])); +`, + ); + const result = await compile(entry, { outDir: dir, outPath, outputKind: "ir" }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + const llvm = emitLlvmModule(deserializeModule(await readFile(outPath, "utf8"))); + const fn = llvm.split("\ndefine ").find((f) => f.includes("ica.f64")) ?? ""; + // The keyed read tests the capsule's element kind and loads the double + // in place; other receivers keep the probe. + expect(fn).toMatch(/icmp eq i8 %t\d+, 0 ; SCR_ELEM_F64/); + expect(fn).toMatch(/load double, ptr %t\d+/); + expect(fn).toContain("@scr_js_keyed_probe("); + // The length read answers from the native array's length. + expect(fn).toContain("icg.rest"); + expect(fn).toContain("@scr_js_load_probe("); + } finally { + await rm(dir, { recursive: true, force: true }); + } +}); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8300-native-array-capsule-reads/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8300-native-array-capsule-reads/main.ts.json new file mode 100644 index 000000000..fb6e3a0bf --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8300-native-array-capsule-reads/main.ts.json @@ -0,0 +1,7 @@ +{ + "order": [ + "/tests/corpus/8300-native-array-capsule-reads/lib.cjs", + "/tests/corpus/8300-native-array-capsule-reads/main.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index 6270c8cdc..2f9d7eb82 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -523,7 +523,9 @@ struct ScrDyn { * identity while the source reference remains observable. */ ScrDyn *materialized; ScrDynTypedCast *casts; - /* One word keeps this, the largest payload, at its previous size. */ + /* One word keeps this, the largest payload, at its previous size. + * Dynamic-tier inline caches read record, klass and bag_class as + * the word's top three bits (backend/llvm/js-ic.ts nativeArray). */ uint32_t type_key_len : 27; uint32_t traced : 1; /* native referent has a cycle header */ uint32_t observed : 1; /* native release reports this identity's disposal */ diff --git a/packages/runtime/src/scr_js_object.c b/packages/runtime/src/scr_js_object.c index 4b6e3141e..e09226fd1 100644 --- a/packages/runtime/src/scr_js_object.c +++ b/packages/runtime/src/scr_js_object.c @@ -355,6 +355,9 @@ bool scr_js_store_probe(ScrDyn *receiver, const ScrStr *key, ScrDyn *value, ScrJ /* ── keyed loads ──────────────────────────────────────────────────────── */ ScrDyn *scr_js_index_probe(ScrDyn *receiver, double index) { + /* A native array passed in from typed code answers its elements in + * place, without forming the index's key string. */ + if (receiver->kind == SCR_DYN_TYPED_REF) return scr_dyn_index_get(receiver, index); if (receiver->kind != SCR_DYN_ARR || !(index >= 0) || index >= (double)receiver->v.arr.len) return NULL; size_t i = (size_t)index; diff --git a/tests/corpus/8300-native-array-capsule-reads/lib.cjs b/tests/corpus/8300-native-array-capsule-reads/lib.cjs new file mode 100644 index 000000000..6f386216b --- /dev/null +++ b/tests/corpus/8300-native-array-capsule-reads/lib.cjs @@ -0,0 +1,36 @@ +"use strict"; +// Reads and writes the arrays the typed program passes in. +exports.total = function (xs) { + let s = 0; + for (let i = 0; i < xs.length; i++) s += xs[i]; + return s; +}; +exports.at = function (xs, i) { + return xs[i]; +}; +exports.describe = function (xs, keys) { + const out = []; + for (const k of keys) { + const v = xs[k]; + out.push(typeof v === "number" && Object.is(v, -0) ? "-0" : String(v)); + } + return out.join(" "); +}; +exports.has = function (xs, i) { + return i in xs; +}; +exports.write = function (xs, i, v) { + xs[i] = v; + return xs[i]; +}; +exports.grow = function (xs, v) { + xs.push(v); + return xs.length; +}; +exports.cut = function (xs, n) { + xs.length = n; + return xs.length; +}; +exports.lengthOf = function (xs) { + return xs.length; +}; diff --git a/tests/corpus/8300-native-array-capsule-reads/main.ts b/tests/corpus/8300-native-array-capsule-reads/main.ts new file mode 100644 index 000000000..5b1513ee4 --- /dev/null +++ b/tests/corpus/8300-native-array-capsule-reads/main.ts @@ -0,0 +1,59 @@ +// A typed program passes its arrays to untyped CommonJS functions, which +// read their elements and lengths, write them and resize them. Element reads +// cover integral, negative, fractional, non-finite and out-of-range indexes, +// string keys, holes, frozen arrays and arrays of other element types. +import { createRequire } from "node:module"; + +interface Lib { + total(xs: readonly unknown[]): number; + at(xs: readonly unknown[], i: unknown): unknown; + describe(xs: readonly unknown[], keys: unknown[]): string; + has(xs: readonly unknown[], i: number): boolean; + write(xs: unknown[], i: number, v: unknown): unknown; + grow(xs: unknown[], v: unknown): number; + cut(xs: unknown[], n: number): number; + lengthOf(xs: readonly unknown[]): number; +} +const require = createRequire(import.meta.url); +const lib: Lib = require("./lib.cjs"); + +// Element reads of a number[] at integral, negative, fractional, +// non-finite and out-of-range indexes, and through string keys. +const nums: number[] = [1, 2.5, -0, NaN, Infinity, -7]; +console.log(lib.total([1, 2, 3, 4]), lib.total(nums), lib.total([])); +console.log(lib.describe(nums, [0, 1, 2, 3, 4, 5, 6, -1, 1.5, -0, NaN, Infinity, 2 ** 32, "1", "01", "length"])); +console.log(lib.at(nums, 5), lib.at(nums, 6), typeof lib.at(nums, 2), Object.is(lib.at(nums, 2), -0)); + +// Holes: below and past the hole-free prefix, and an array cut longer. +const holey: number[] = [1, 2]; +holey[4] = 5; +console.log(lib.describe(holey, [0, 1, 2, 3, 4, 5]), lib.has(holey, 3), lib.has(holey, 4), lib.lengthOf(holey)); +const longer: number[] = [3, 4, 5]; +longer.length = 6; +console.log(lib.describe(longer, [0, 2, 3, 5]), lib.lengthOf(longer)); + +// Writes from the package and from the program are seen by both. +const live: number[] = [10, 20, 30]; +console.log(lib.write(live, 0, 11), lib.write(live, 3, 40), lib.grow(live, 50), live.join(",")); +live.push(60); +live[1] = 21; +console.log(lib.total(live), lib.lengthOf(live), lib.at(live, 5)); +console.log(lib.cut(live, 2), lib.total(live), live.length, lib.at(live, 2)); + +// Frozen and empty arrays. +const frozen: readonly number[] = Object.freeze([4, 5, 6]); +console.log(lib.total(frozen), lib.at(frozen, 1), lib.at([], 0), lib.lengthOf([])); + +// Arrays of other element types read through the same sites. +const words: string[] = ["a", "b", "c"]; +const flags: boolean[] = [true, false]; +const points: { x: number }[] = [{ x: 1 }, { x: 2 }]; +console.log(lib.describe(words, [0, 2, 3]), lib.describe(flags, [0, 1, 2]), (lib.at(points, 1) as { x: number }).x); +console.log(lib.at(words, 1.5), lib.has(words, 2), lib.lengthOf(points)); + +// A loop over a larger array. +const big: number[] = []; +for (let i = 0; i < 1000; i++) big.push(i % 7); +let sum = 0; +for (let round = 0; round < 50; round++) sum += lib.total(big); +console.log(sum); diff --git a/tests/corpus/8300-native-array-capsule-reads/package.json b/tests/corpus/8300-native-array-capsule-reads/package.json new file mode 100644 index 000000000..5ffd9800b --- /dev/null +++ b/tests/corpus/8300-native-array-capsule-reads/package.json @@ -0,0 +1 @@ +{ "type": "module" } diff --git a/tests/harness/corpus-costs/8300-native-array-capsule-reads/main.ts.json b/tests/harness/corpus-costs/8300-native-array-capsule-reads/main.ts.json new file mode 100644 index 000000000..a37fc12d7 --- /dev/null +++ b/tests/harness/corpus-costs/8300-native-array-capsule-reads/main.ts.json @@ -0,0 +1 @@ +{ "plain": 4860, "san": 7734 } From d1432eeb187e2cf269cd06ddddb9374813724aaa Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 24 Oct 2026 13:14:39 -0700 Subject: [PATCH 202/259] Compile namespace-style npm packages: guarded declarations and var exports Two refusals kept pre-module JavaScript packages from compiling: - `var ns = ns || {}` (and `?? {}`): the read in the variable's own initializer made the checker type the namespace `any`, and requirers then failed to reach the binding (SC1030). In a module, the read sees the hoisted `undefined` whenever nothing else writes the variable, so a new package-source normalization respells the declaration as its default (`var ns = ({})`) when no other declaration, assignment, update, function, class, parameter or local of that name exists in the file and no earlier top-level statement mentions it. - `module.exports = { ns }` with a `var` binding was refused as exporting a mutable binding by reference. A `var` (or `let`) whose initialized declaration precedes the export statement at top level and that nothing reassigns exports exactly the value Node copies, so it now aliases like a const. The namespace benchmark (results/design-shape-inference/nsbench) now compiles and matches Node; the new npm case legacy-namespaces pins a namespace library with guarded declarations, constructor functions with prototype methods, enums, a revealing module and a handler registry. Co-Authored-By: Claude Opus 5.5 --- .../src/frontend/lowering/lower-stmts.ts | 20 ++- .../npm-static-namespace-defaults.test.ts | 63 ++++++++ .../frontend/npm-static-namespace-defaults.ts | 138 ++++++++++++++++++ packages/compiler/src/frontend/npm-static.ts | 5 + packages/compiler/src/frontend/services.ts | 11 ++ .../npm/cases/legacy-namespaces/main.ts.json | 6 + .../npm/cases/legacy-namespaces/main.ts | 26 ++++ .../node_modules/legacy-ns/index.d.ts | 2 + .../node_modules/legacy-ns/index.js | 97 ++++++++++++ .../node_modules/legacy-ns/package.json | 1 + .../npm/cases/legacy-namespaces/package.json | 1 + 11 files changed, 368 insertions(+), 2 deletions(-) create mode 100644 packages/compiler/src/frontend/npm-static-namespace-defaults.test.ts create mode 100644 packages/compiler/src/frontend/npm-static-namespace-defaults.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/legacy-namespaces/main.ts.json create mode 100644 tests/fixtures/npm/cases/legacy-namespaces/main.ts create mode 100644 tests/fixtures/npm/cases/legacy-namespaces/node_modules/legacy-ns/index.d.ts create mode 100644 tests/fixtures/npm/cases/legacy-namespaces/node_modules/legacy-ns/index.js create mode 100644 tests/fixtures/npm/cases/legacy-namespaces/node_modules/legacy-ns/package.json create mode 100644 tests/fixtures/npm/cases/legacy-namespaces/package.json diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index c50676863..851cae4c9 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -7445,7 +7445,7 @@ function lowerCjsExportStatement( const fenceMutable = (nameNode: ts.Identifier): void => { const sym = lowerer.resolveValueSymbol(nameNode); const g = sym ? lowerer.globalsBySymbol.get(sym) : undefined; - if (g?.mutable) { + if (g?.mutable && !(sym && settledBeforeExport(lowerer, sym, cjs.expr))) { lowerer.unsupported( "SC1090", nameNode, @@ -7605,7 +7605,7 @@ function lowerCjsSingleValueExport( } const g = lowerer.globalsBySymbol.get(sym); if (g) { - if (g.mutable) { + if (g.mutable && !settledBeforeExport(lowerer, sym, rhs)) { lowerer.unsupported( "SC1090", rhs, @@ -12707,3 +12707,19 @@ function isAssertionInitializer(node: ts.Expression): boolean { while (ts.isParenthesizedExpression(e)) e = e.expression; return ts.isAsExpression(e) || ts.isTypeAssertion(e); } + +/** A `var` (or `let`) whose initialized declaration precedes the export + * statement in the module's top-level statements and that nothing ever + * reassigns: exporting it by reference reads the value Node copies. The + * legacy `var ns = ns || {}; …; module.exports = { ns }` shape. */ +function settledBeforeExport(lowerer: Lowerer, sym: ts.Symbol, exportNode: ts.Node): boolean { + const decl = sym.valueDeclaration; + if (!decl || !ts.isVariableDeclaration(decl) || decl.initializer === undefined) return false; + const stmt = decl.parent?.parent; + if (!stmt || !ts.isVariableStatement(stmt) || !ts.isSourceFile(stmt.parent)) return false; + let exportStmt: ts.Node = exportNode; + while (exportStmt.parent !== undefined && !ts.isSourceFile(exportStmt.parent)) + exportStmt = exportStmt.parent; + if (exportStmt.parent !== stmt.parent || stmt.end > exportStmt.pos) return false; + return bindingNeverReassigned(lowerer, sym, decl); +} diff --git a/packages/compiler/src/frontend/npm-static-namespace-defaults.test.ts b/packages/compiler/src/frontend/npm-static-namespace-defaults.test.ts new file mode 100644 index 000000000..93a776f7e --- /dev/null +++ b/packages/compiler/src/frontend/npm-static-namespace-defaults.test.ts @@ -0,0 +1,63 @@ +import { spawnSync } from "node:child_process"; +import { mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { afterAll, expect, test } from "vitest"; +import { nodeFrontendServices } from "./services-node.js"; + +const dirs: string[] = []; +afterAll(() => { + for (const dir of dirs) rmSync(dir, { recursive: true, force: true }); +}); + +function rewrite(source: string): string | null { + return nodeFrontendServices().namespaceDefaults(source, "/pkg/index.js"); +} + +/** Node prints the same for the original and the rewritten module. */ +function expectSameOutput(source: string): void { + const result = rewrite(source); + expect(typeof result).toBe("string"); + const dir = mkdtempSync(join(tmpdir(), "scriptc-namespace-defaults-")); + dirs.push(dir); + const outputs = [source, result!].map((text, i) => { + const file = join(dir, `m${i}.cjs`); + writeFileSync(file, text); + const r = spawnSync(process.execPath, [file], { encoding: "utf8" }); + expect(r.status).toBe(0); + return r.stdout; + }); + expect(outputs[1]).toBe(outputs[0]); +} + +test("a guarded namespace declaration becomes its default", () => { + const source = `var app = app || {}; +app.util = app.util || {}; +app.util.twice = function (x) { return 2 * x; }; +var cfg = cfg ?? { depth: 1 }; +console.log(app.util.twice(3), cfg.depth, Object.keys(app).join(",")); +`; + expect(rewrite(source)).toBe(`var app = {}; +app.util = app.util || {}; +app.util.twice = function (x) { return 2 * x; }; +var cfg = { depth: 1 }; +console.log(app.util.twice(3), cfg.depth, Object.keys(app).join(",")); +`); + expectSameOutput(source); +}); + +test("any other write, declaration or earlier mention keeps the text", () => { + // Redeclared: the second declaration reads the first one's object. + expect(rewrite("var ns = ns || {};\nvar ns = ns || {};\n")).toBeNull(); + // Assigned elsewhere, updated, or declared as a function. + expect(rewrite("var ns = ns || {};\nfunction reset() { ns = {}; }\n")).toBeNull(); + expect(rewrite("var n = n || 0;\nn++;\n")).toBeNull(); + // A local of the same name somewhere in the file. + expect(rewrite("var ns = ns || {};\nfunction f(ns) { return ns; }\n")).toBeNull(); + // Mentioned by an earlier statement. + expect(rewrite("console.log(typeof ns);\nvar ns = ns || {};\n")).toBeNull(); + // let and const read their own binding in its temporal dead zone. + expect(rewrite("let ns = ns || {};\n")).toBeNull(); + // Not the declared name on the left. + expect(rewrite("var ns = other || {};\n")).toBeNull(); +}); diff --git a/packages/compiler/src/frontend/npm-static-namespace-defaults.ts b/packages/compiler/src/frontend/npm-static-namespace-defaults.ts new file mode 100644 index 000000000..2e4bf046c --- /dev/null +++ b/packages/compiler/src/frontend/npm-static-namespace-defaults.ts @@ -0,0 +1,138 @@ +/* The guarded namespace declaration of pre-module JavaScript: + * + * var ns = ns || {}; + * + * In a module (CommonJS or ES), `var` is module-local and hoisted, so the + * read in its own initializer sees `undefined` unless something writes the + * variable first. When nothing else in the file ever writes it (no other + * declaration, assignment or update of that name anywhere, no function or + * class of that name) and no earlier top-level statement mentions it, the + * initializer is its right operand: `var ns = {};`. Inference then types + * the namespace from that literal and the members later statements add, + * instead of `any` (the self-reference makes the checker give up). `??` + * is the same. Anything else keeps the original text. */ +import * as ts from "./ts7/syntax.js"; +import { tokenStartOfNode } from "./ts7/node-functions.js"; +import { applyEdits, unparen, type Edit } from "./npm-static-bundled-chunks.js"; + +/** A cheap probe: some `var X = X ||` or `?? ` may be present. */ +export function mayHoldNamespaceDefault(source: string): boolean { + return /\bvar\s+([A-Za-z_$][\w$]*)\s*=\s*\(?\s*\1\s*(\|\||\?\?)/.test(source); +} + +/** The module text with each guarded namespace declaration respelled as a + * plain one, or null when there is none. */ +export function rewriteNamespaceDefaults(sf: ts.SourceFile): string | null { + const stmts = sf.statements.nodes; + const edits: Edit[] = []; + for (let i = 0; i < stmts.length; i++) { + const stmt = stmts[i]!; + if (!ts.isVariableStatement(stmt)) continue; + const list = stmt.declarationList; + if ((list.flags & (ts.NodeFlags.Let | ts.NodeFlags.Const)) !== 0) continue; + for (const decl of list.declarations.nodes) { + if (!ts.isIdentifier(decl.name) || decl.initializer === undefined) continue; + const name = decl.name.text; + const init = unparen(decl.initializer); + if ( + !ts.isBinaryExpression(init) || + (init.operatorToken.kind !== ts.SyntaxKind.BarBarToken && + init.operatorToken.kind !== ts.SyntaxKind.QuestionQuestionToken) + ) + continue; + const left = unparen(init.left); + if (!ts.isIdentifier(left) || left.text !== name) continue; + if (mentionedBefore(stmts, i, name) || writtenElsewhere(sf, name, decl)) continue; + const right = init.right; + edits.push({ + start: tokenStartOfNode(decl.initializer), + end: decl.initializer.end, + // A literal stays bare: inference types `var ns = {}` from the + // members later statements add (a parenthesized one it does not). + text: + ts.isObjectLiteralExpression(unparen(right)) || + ts.isArrayLiteralExpression(unparen(right)) + ? sf.text.slice(tokenStartOfNode(right), right.end) + : `(${sf.text.slice(tokenStartOfNode(right), right.end)})`, + }); + } + } + if (edits.length === 0) return null; + return applyEdits(sf.text, 0, sf.text.length, edits); +} + +/** Whether a top-level statement before index `at` mentions `name`. */ +function mentionedBefore(stmts: readonly ts.Statement[], at: number, name: string): boolean { + for (let i = 0; i < at; i++) { + let found = false; + ts.walkPreorder(stmts[i]!, (n) => { + if (found) return "stop"; + if (ts.isIdentifier(n) && n.text === name) found = true; + return undefined; + }); + if (found) return true; + } + return false; +} + +/** Whether anything other than `decl` declares or writes `name`. */ +function writtenElsewhere(sf: ts.SourceFile, name: string, decl: ts.VariableDeclaration): boolean { + let written = false; + ts.walkPreorder(sf, (n) => { + if (written) return "stop"; + if (n === decl.name) return undefined; + if (ts.isBinaryExpression(n) && isAssignmentOperator(n.operatorToken.kind)) { + if (isName(n.left, name)) written = true; + } else if ( + (ts.isPrefixUnaryExpression(n) || ts.isPostfixUnaryExpression(n)) && + (n.operator === ts.SyntaxKind.PlusPlusToken || + n.operator === ts.SyntaxKind.MinusMinusToken) && + isName(n.operand, name) + ) { + written = true; + } else if ( + (ts.isFunctionDeclaration(n) || ts.isClassDeclaration(n)) && + n.name !== undefined && + n.name.text === name + ) { + written = true; + } else if ( + (ts.isVariableDeclaration(n) || ts.isParameter(n) || ts.isBindingElement(n)) && + n !== decl && + n.name !== undefined && + bindsName(n.name, name) + ) { + // Another declaration of the name (a redeclaration, or a local that + // shadows it) — keep the original text rather than reason about it. + written = true; + } else if ( + (ts.isForInStatement(n) || ts.isForOfStatement(n)) && + !ts.isVariableDeclarationList(n.initializer) && + isName(n.initializer, name) + ) { + written = true; + } + return undefined; + }); + return written; +} + +function bindsName(binding: ts.Node, name: string): boolean { + if (ts.isIdentifier(binding)) return binding.text === name; + let found = false; + ts.walkPreorder(binding, (n) => { + if (found) return "stop"; + if (ts.isIdentifier(n) && n.text === name) found = true; + return undefined; + }); + return found; +} + +function isName(node: ts.Node, name: string): boolean { + const n = unparen(node as ts.Expression); + return ts.isIdentifier(n) && n.text === name; +} + +function isAssignmentOperator(kind: ts.SyntaxKind): boolean { + return kind >= ts.SyntaxKind.FirstAssignment && kind <= ts.SyntaxKind.LastAssignment; +} diff --git a/packages/compiler/src/frontend/npm-static.ts b/packages/compiler/src/frontend/npm-static.ts index b00e14aa0..f51c6bbe2 100644 --- a/packages/compiler/src/frontend/npm-static.ts +++ b/packages/compiler/src/frontend/npm-static.ts @@ -505,6 +505,10 @@ export function npmStaticFsShadow(services: FrontendServices): NpmStaticFsShadow // literals they build. const enums = original === null ? null : services.enumIifes(original, path); if (enums !== null) original = enums; + // Guarded namespace declarations (`var ns = ns || {}`) read the + // hoisted `undefined`: the declaration is its default. + const namespaces = original === null ? null : services.namespaceDefaults(original, path); + if (namespaces !== null) original = namespaces; // A module that names its export object through a variable reaches // its members through `exports`. const exportsVar = original === null ? null : services.cjsExportsVar(original, path); @@ -517,6 +521,7 @@ export function npmStaticFsShadow(services: FrontendServices): NpmStaticFsShadow aliased !== null || fnExports !== null || enums !== null || + namespaces !== null || exportsVar !== null; if (original !== null) { const namepaths = services.jsDocNamepaths(path, original); diff --git a/packages/compiler/src/frontend/services.ts b/packages/compiler/src/frontend/services.ts index 14b366bfa..11fa0de72 100644 --- a/packages/compiler/src/frontend/services.ts +++ b/packages/compiler/src/frontend/services.ts @@ -14,6 +14,10 @@ import { } from "./npm-static-builtin-aliases.js"; import { mayHoldUmdWrapper, unwrapUmdFactory } from "./npm-static-umd.js"; import { mayHoldEnumIife, rewriteEnumIifes } from "./npm-static-enum-iife.js"; +import { + mayHoldNamespaceDefault, + rewriteNamespaceDefaults, +} from "./npm-static-namespace-defaults.js"; import { mayHoldTscBuiltinImport, unwrapTscBuiltinImports } from "./npm-static-tsc-helpers.js"; import { builtinPackageAliasFor } from "./package-shims.js"; import * as syntax from "./npm-static-declaration-syntax.js"; @@ -132,6 +136,13 @@ export class FrontendServices { if (!mayHoldEnumIife(source)) return null; return rewriteEnumIifes(this.parse(path, source, "js")); } + /** A package module with its guarded namespace declarations + * (`var ns = ns || {}`) respelled as plain ones (null: none). */ + namespaceDefaults(source: string, path: string): string | null { + this.ensureOpen(); + if (!mayHoldNamespaceDefault(source)) return null; + return rewriteNamespaceDefaults(this.parse(path, source, "js")); + } /** A package module with its requires of builtin-aliased polyfill * packages respelled as the builtins (null: none). */ builtinAliasRequires(source: string, path: string): string | null { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/legacy-namespaces/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/legacy-namespaces/main.ts.json new file mode 100644 index 000000000..7f50545d6 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/legacy-namespaces/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/npm/cases/legacy-namespaces/main.ts" + ], + "diags": [] +} diff --git a/tests/fixtures/npm/cases/legacy-namespaces/main.ts b/tests/fixtures/npm/cases/legacy-namespaces/main.ts new file mode 100644 index 000000000..2f9483ba9 --- /dev/null +++ b/tests/fixtures/npm/cases/legacy-namespaces/main.ts @@ -0,0 +1,26 @@ +// A namespace-style library in the pre-module idiom (guarded namespace +// declarations, constructor functions with prototype methods, enums as +// objects, a revealing module, a handler registry, exported through +// `module.exports = { app }`), used from TypeScript. +import { app } from "legacy-ns"; + +const v = new app.geom.Vec(3, 4); +console.log(v.length(), v.add(new app.geom.Vec(1, 1)).scale(2).x, v instanceof app.geom.Vec); +console.log(Object.keys(app).join(","), Object.keys(app.math).join(","), Object.keys(app.geom.Kind).join(",")); +console.log(app.math.clamp(12, 0, 10), app.math.lerp(0, 10, 0.25), app.text.pad(7, 3), app.text.label(1, 42)); + +const shapes = []; +for (let i = 0; i < 12; i++) { + const center = new app.geom.Vec(app.math.lerp(-5, 5, (i % 4) / 3), app.math.lerp(-5, 5, Math.floor(i / 4) / 2)); + shapes.push(new app.geom.Shape(i % 3, center, 1 + (i % 4))); +} +let area = 0; +let hits = 0; +for (let step = 0; step < 200; step++) { + const probe = new app.geom.Vec(app.math.clamp(Math.sin(step) * 7, -5, 5), app.math.clamp(Math.cos(step * 0.7) * 7, -5, 5)); + for (const s of shapes) { + area += app.registry.run("area", s, probe); + hits += app.registry.run("hits", s, probe); + } +} +console.log(Math.round(area), hits, shapes[4].contains(shapes[4].center), shapes[0].area()); diff --git a/tests/fixtures/npm/cases/legacy-namespaces/node_modules/legacy-ns/index.d.ts b/tests/fixtures/npm/cases/legacy-namespaces/node_modules/legacy-ns/index.d.ts new file mode 100644 index 000000000..16c9fa62a --- /dev/null +++ b/tests/fixtures/npm/cases/legacy-namespaces/node_modules/legacy-ns/index.d.ts @@ -0,0 +1,2 @@ +declare const app: any; +export { app }; diff --git a/tests/fixtures/npm/cases/legacy-namespaces/node_modules/legacy-ns/index.js b/tests/fixtures/npm/cases/legacy-namespaces/node_modules/legacy-ns/index.js new file mode 100644 index 000000000..2efa926f5 --- /dev/null +++ b/tests/fixtures/npm/cases/legacy-namespaces/node_modules/legacy-ns/index.js @@ -0,0 +1,97 @@ +// A namespace-style geometry and text library in the pre-module idiom: +// guarded namespace declarations, constructor functions with prototype +// methods, enums as objects, a revealing module, and a static registry. +var app = app || {}; +app.math = app.math || {}; +app.geom = app.geom || {}; + +app.math.EPSILON = 1e-9; + +app.math.clamp = function (value, lo, hi) { + return value < lo ? lo : value > hi ? hi : value; +}; + +app.math.lerp = function (a, b, t) { + return a + (b - a) * t; +}; + +app.math.hypot = function (x, y) { + return Math.sqrt(x * x + y * y); +}; + +app.geom.Kind = { POINT: 0, CIRCLE: 1, RECT: 2 }; + +/** @constructor */ +app.geom.Vec = function (x, y) { + this.x = x; + this.y = y; +}; + +app.geom.Vec.prototype.add = function (other) { + return new app.geom.Vec(this.x + other.x, this.y + other.y); +}; + +app.geom.Vec.prototype.scale = function (k) { + return new app.geom.Vec(this.x * k, this.y * k); +}; + +app.geom.Vec.prototype.length = function () { + return app.math.hypot(this.x, this.y); +}; + +/** @constructor */ +app.geom.Shape = function (kind, center, size) { + this.kind = kind; + this.center = center; + this.size = size; +}; + +app.geom.Shape.prototype.area = function () { + switch (this.kind) { + case app.geom.Kind.CIRCLE: + return Math.PI * this.size * this.size; + case app.geom.Kind.RECT: + return this.size * this.size; + default: + return 0; + } +}; + +app.geom.Shape.prototype.contains = function (p) { + var d = p.add(this.center.scale(-1)).length(); + return d <= this.size + app.math.EPSILON; +}; + +app.text = (function () { + var digits = "0123456789"; + function pad(n, width) { + var s = ""; + var v = n; + do { + s = digits.charAt(v % 10) + s; + v = Math.floor(v / 10); + } while (v > 0); + while (s.length < width) s = "0" + s; + return s; + } + function label(kind, n) { + return (kind === app.geom.Kind.CIRCLE ? "c" : kind === app.geom.Kind.RECT ? "r" : "p") + pad(n, 4); + } + return { pad: pad, label: label }; +})(); + +app.registry = { + handlers: { + area: function (shape) { + return shape.area(); + }, + hits: function (shape, probe) { + return shape.contains(probe) ? 1 : 0; + }, + }, + run: function (name, shape, probe) { + return app.registry.handlers[name](shape, probe); + }, +}; + +module.exports = { app }; diff --git a/tests/fixtures/npm/cases/legacy-namespaces/node_modules/legacy-ns/package.json b/tests/fixtures/npm/cases/legacy-namespaces/node_modules/legacy-ns/package.json new file mode 100644 index 000000000..cde18c613 --- /dev/null +++ b/tests/fixtures/npm/cases/legacy-namespaces/node_modules/legacy-ns/package.json @@ -0,0 +1 @@ +{ "name": "legacy-ns", "version": "1.0.0", "main": "index.js", "types": "index.d.ts" } diff --git a/tests/fixtures/npm/cases/legacy-namespaces/package.json b/tests/fixtures/npm/cases/legacy-namespaces/package.json new file mode 100644 index 000000000..140c08a1c --- /dev/null +++ b/tests/fixtures/npm/cases/legacy-namespaces/package.json @@ -0,0 +1 @@ +{ "name": "legacy-namespaces-case", "private": true, "type": "module" } From fe8ba8900f45c0d12615142f210feec282ce4a5f Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 22:16:05 -0500 Subject: [PATCH 203/259] Start integer loops from the integers their starts carry --- .../backend/llvm/bytes-loop-versions.test.ts | 3 +- .../src/backend/llvm/bytes-loop-versions.ts | 5 +- .../src/backend/llvm/counted-loops.ts | 55 ++++++++++++++++++- .../src/backend/llvm/dense-array-loops.ts | 4 +- .../src/backend/llvm/emit-statements.ts | 13 ++--- .../8196-counted-loops-integer-starts.ts.json | 6 ++ .../8196-counted-loops-integer-starts.ts | 50 +++++++++++++++++ 7 files changed, 121 insertions(+), 15 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8196-counted-loops-integer-starts.ts.json create mode 100644 tests/corpus/8196-counted-loops-integer-starts.ts diff --git a/packages/compiler/src/backend/llvm/bytes-loop-versions.test.ts b/packages/compiler/src/backend/llvm/bytes-loop-versions.test.ts index 0c0f1aaa0..096712c97 100644 --- a/packages/compiler/src/backend/llvm/bytes-loop-versions.test.ts +++ b/packages/compiler/src/backend/llvm/bytes-loop-versions.test.ts @@ -701,7 +701,8 @@ test("a two-counter loop versions the typed arrays it indexes at either counter" }; const body = /^define internal [^\n]*@sc_bf_kernel[^]*?^}/m.exec(emitLlvmModule(mod))![0]; const guard = body.slice(0, body.search(/^bytes\.version\.(fast|slow)\d+:$/m)); - expect(guard).toMatch(/icmp sge i64 %\S+, 0/); + // `i` starts at the literal 0, so its test compares the integer itself. + expect(guard).toMatch(/icmp sge i64 0, 0/); expect(guard).toMatch(/icmp slt i64 %\S+, %\S+/); const fast = /^bytes\.version\.fast\d+:$[^]*?^bytes\.version\.done\d+:$/m.exec(body)![0]; // The fast copy keeps only the `src[i + 1]` check, and no second guard. diff --git a/packages/compiler/src/backend/llvm/bytes-loop-versions.ts b/packages/compiler/src/backend/llvm/bytes-loop-versions.ts index 301f65de2..faec650a4 100644 --- a/packages/compiler/src/backend/llvm/bytes-loop-versions.ts +++ b/packages/compiler/src/backend/llvm/bytes-loop-versions.ts @@ -9,6 +9,7 @@ import { emitCountedLoopLimit, emitCountedLoopSafety, emitExactIntegerTest, + emitStartIntegerTest, } from "./counted-loops.js"; import { emitBytesHeaderLength, emitBytesSharedStorage } from "./expr-bytes.js"; import { f64Lit } from "./common.js"; @@ -1251,8 +1252,8 @@ export function emitBytesLoopVersionGuard( // access at either one is in bounds when `lo >= 0` and `hi < length`. const { loop } = version.paired; const [low, high] = [loop.low.start, loop.high.start].map((expr) => { - const tested = emitExactIntegerTest(host, host.emitExpr(expr).name, -SAFE, SAFE); - conditions.push(tested.ok); + const tested = emitStartIntegerTest(host, expr, -SAFE, SAFE); + if (tested.ok !== "true") conditions.push(tested.ok); return tested.integer; }); const nonNegative = B.tmp(); diff --git a/packages/compiler/src/backend/llvm/counted-loops.ts b/packages/compiler/src/backend/llvm/counted-loops.ts index bb402d5b8..39f97717b 100644 --- a/packages/compiler/src/backend/llvm/counted-loops.ts +++ b/packages/compiler/src/backend/llvm/counted-loops.ts @@ -7,6 +7,7 @@ import { FOLLOWER_GUARD_LIMIT } from "../../ir/integer-loops.js"; import type { IrExpr } from "../../ir/ir.js"; import type { LlvmEmitterContext } from "./expr-context.js"; import { f64Lit } from "./common.js"; +import { exactInteger, widenInteger } from "./integer-values.js"; /** The caller has proved or guarded the direction's finite endpoint. Clamp * the opposite infinity before integer conversion. Fractional limits become @@ -121,6 +122,7 @@ export function emitPairedLoopSafety(host: LlvmEmitterContext, loop: IntegerPair } function andSafe(host: LlvmEmitterContext, safe: string, ok: string): string { + if (ok === "true") return safe; if (safe === "true") return ok; const both = host.B.tmp(); host.B.line(`${both} = and i1 ${safe}, ${ok}`); @@ -129,10 +131,25 @@ function andSafe(host: LlvmEmitterContext, safe: string, ok: string): string { /** An exact integer of at most 2^53 - 1 in magnitude, and not -0 (the bit * patterns of the value and its round trip agree). NaN and infinities fail - * the ordered range tests. */ + * the ordered range tests. A start with an integer form (an int32 local, + * `p0 - 1` of one) is an exact integer already: its range answers the test, + * or two integer compares do. */ function emitExactStart(host: LlvmEmitterContext, expr: IrExpr): string { const B = host.B; const start = host.emitExpr(expr); + const integer = exactInteger(host, start, expr); + if (integer) { + const limit = Number.MAX_SAFE_INTEGER; + if (integer.range.min >= -limit && integer.range.max <= limit) return "true"; + const wide = widenInteger(host, integer), + low = B.tmp(), + high = B.tmp(), + ok = B.tmp(); + B.line(`${low} = icmp sge i64 ${wide}, ${-limit}`); + B.line(`${high} = icmp sle i64 ${wide}, ${limit}`); + B.line(`${ok} = and i1 ${low}, ${high}`); + return ok; + } const low = B.tmp(), high = B.tmp(), raw = B.tmp(), @@ -188,3 +205,39 @@ export function emitExactIntegerTest( B.line(`${ok} = and i1 ${inRange}, ${exact}`); return { ok, integer }; } + +/** The i64 start of an integer counter: the integer form the start value + * carries (an int32 local, `p0 - 1` of one), or the double's conversion, + * which the loop's guard or proof makes exact. */ +export function emitCountedStart(host: LlvmEmitterContext, expr: IrExpr): string { + const value = host.emitExpr(expr); + const integer = exactInteger(host, value, expr); + if (integer) return widenInteger(host, integer); + const start = host.B.tmp(); + host.B.line(`${start} = fptosi double ${value.name} to i64`); + return start; +} + +/** emitExactIntegerTest of a start expression: when the value carries an + * integer form (an exact integer, never -0), its range answers the test or + * two integer compares do, and the integer is the form's. */ +export function emitStartIntegerTest( + host: LlvmEmitterContext, + expr: IrExpr, + min: number, + max: number, +): { ok: string; integer: string } { + const value = host.emitExpr(expr); + const integer = exactInteger(host, value, expr); + if (!integer) return emitExactIntegerTest(host, value.name, min, max); + const wide = widenInteger(host, integer); + if (integer.range.min >= min && integer.range.max <= max) return { ok: "true", integer: wide }; + const B = host.B; + const low = B.tmp(), + high = B.tmp(), + ok = B.tmp(); + B.line(`${low} = icmp sge i64 ${wide}, ${min}`); + B.line(`${high} = icmp sle i64 ${wide}, ${max}`); + B.line(`${ok} = and i1 ${low}, ${high}`); + return { ok, integer: wide }; +} diff --git a/packages/compiler/src/backend/llvm/dense-array-loops.ts b/packages/compiler/src/backend/llvm/dense-array-loops.ts index b806939b5..020ea582a 100644 --- a/packages/compiler/src/backend/llvm/dense-array-loops.ts +++ b/packages/compiler/src/backend/llvm/dense-array-loops.ts @@ -36,7 +36,7 @@ import { everyExprChild, everyStmtChild } from "../../ir/traverse.js"; import type { IntegerCountedForLoop, IntegerPairedForLoop } from "../../ir/integer-loops.js"; import type { LlvmEmitterContext } from "./expr-context.js"; import { loadArrCount, SCR_ARR_FIELD } from "./common.js"; -import { emitCountedLoopLimit, emitExactIntegerTest } from "./counted-loops.js"; +import { emitCountedLoopLimit, emitStartIntegerTest } from "./counted-loops.js"; export const INT32_MAX = 2147483647; @@ -453,7 +453,7 @@ function emitPairedDenseGuard( ): string { const B = host.B; const start = (expr: IrExpr, min: number, max: number) => - emitExactIntegerTest(host, host.emitExpr(expr).name, min, max); + emitStartIntegerTest(host, expr, min, max); const low = start(pair.lowStart, 0, INT32_MAX - 1); const high = start(pair.highStart, -1, INT32_MAX - 1); let valid = B.tmp(); diff --git a/packages/compiler/src/backend/llvm/emit-statements.ts b/packages/compiler/src/backend/llvm/emit-statements.ts index 3d3aa6781..89e36a203 100644 --- a/packages/compiler/src/backend/llvm/emit-statements.ts +++ b/packages/compiler/src/backend/llvm/emit-statements.ts @@ -61,6 +61,7 @@ import { import { emitCountedLoopLimit, emitCountedLoopSafety, + emitCountedStart, emitPairedLoopSafety, } from "./counted-loops.js"; import { emitBytesLoopVersionGuard, type BytesLoopVersion } from "./bytes-loop-versions.js"; @@ -1112,9 +1113,7 @@ export function emitStmtBody(emitter: LlEmitter, s: IrStmt): void { B.entryAllocas.push( `${integerSlot} = alloca i64 ; integer induction ${emitter.currentLocals.get(countedLoop.localId)!.name}`, ); - const startNumber = emitter.emitExpr(countedLoop.start); - const start = B.tmp(); - B.line(`${start} = fptosi double ${startNumber.name} to i64`); + const start = emitCountedStart(emitter, countedLoop.start); B.line(`store i64 ${start}, ptr ${integerSlot}`); emitter.integerLoopBindings.set(countedLoop.localId, { slot: integerSlot, @@ -1130,9 +1129,7 @@ export function emitStmtBody(emitter: LlEmitter, s: IrStmt): void { B.entryAllocas.push( `${slot} = alloca i64 ; integer induction ${emitter.currentLocals.get(follower.localId)!.name}`, ); - const value = emitter.emitExpr(follower.start); - const followerStart = B.tmp(); - B.line(`${followerStart} = fptosi double ${value.name} to i64`); + const followerStart = emitCountedStart(emitter, follower.start); B.line(`store i64 ${followerStart}, ptr ${slot}`); followerSlots.push(slot); emitter.integerLoopBindings.set(follower.localId, { @@ -1149,9 +1146,7 @@ export function emitStmtBody(emitter: LlEmitter, s: IrStmt): void { B.entryAllocas.push( `${slot} = alloca i64 ; integer induction ${emitter.currentLocals.get(counter.localId)!.name}`, ); - const value = emitter.emitExpr(counter.start); - const start = B.tmp(); - B.line(`${start} = fptosi double ${value.name} to i64`); + const start = emitCountedStart(emitter, counter.start); B.line(`store i64 ${start}, ptr ${slot}`); pairedSlots.push(slot); const dense = LOOPS.of(emitter).denseLoop; diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8196-counted-loops-integer-starts.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8196-counted-loops-integer-starts.ts.json new file mode 100644 index 000000000..6569a8326 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8196-counted-loops-integer-starts.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8196-counted-loops-integer-starts.ts" + ], + "diags": [] +} diff --git a/tests/corpus/8196-counted-loops-integer-starts.ts b/tests/corpus/8196-counted-loops-integer-starts.ts new file mode 100644 index 000000000..d608bc4b5 --- /dev/null +++ b/tests/corpus/8196-counted-loops-integer-starts.ts @@ -0,0 +1,50 @@ +// Counted, paired and dense array loops whose start is an int32 value +// (an int32 array element, `p0 | 0` or one minus either): starts at -1, 0, +// inside the array, at its end, and at the int32 extremes, where the loop +// must not run or must stop at the array's end as Node does. Number arrays +// and an Int32Array both run their paired loops. +function reverse(pp: number[], p0: number): number { + let swaps = 0; + for (let i = 1, j = (p0 | 0) - 1; i < j; i++, j--) { + const t = pp[i]!; + pp[i] = pp[j]!; + pp[j] = t; + swaps++; + } + return swaps; +} + +function reverseBytes(values: Int32Array, p0: number): number { + let swaps = 0; + for (let i = 0, j = (p0 | 0) - 1; i < j; i++, j--) { + const t = values[i]!; + values[i] = values[j]!; + values[j] = t; + swaps++; + } + return swaps; +} + +function sumFrom(values: number[], start: number): number { + let total = 0; + for (let k = start - 1; k < values.length; k++) total += values[k] ?? 100; + return total; +} + +function countdown(values: Int32Array, from: number): number { + let total = 0; + for (let k = from; k >= 0; k--) total += values[k] ?? 1000; + return total; +} + +const starts: number[] = [0, 1, 2, 5, 9, 10, 11, 2147483647, -2147483648]; +const ints = new Int32Array(starts); +for (let s = 0; s < ints.length; s++) { + const p0 = ints[s]!; + const pp = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; + const swaps = p0 <= 11 ? reverse(pp, p0) : 0; + const bytes = new Int32Array(pp); + const byteSwaps = p0 <= 11 ? reverseBytes(bytes, p0) : 0; + console.log(p0, swaps, pp.join(""), p0 <= 11 && p0 >= -1 ? sumFrom(pp, p0) : "-", p0 <= 11 ? countdown(ints, p0) : "-"); + console.log(" bytes", byteSwaps, bytes.join("")); +} From 33f63655a0ddd712253790c260657f6d51aba080 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 22:34:45 -0500 Subject: [PATCH 204/259] Infer untyped JavaScript collection types once, without re-entering The inference reads types while it runs: resolving a candidate's constructor through a destructured require (const { TextDecoder } = util) asks for the namespace's type, which asked for the inferred collection types again and restarted the inference until the stack overflowed. The lowerer now stores an empty table before inferring, so reads during the inference see no inferred types, and stores the result after. --- .../frontend/lowering/js-collection-types.ts | 10 +++++-- .../compiler/test/js-collection-types.test.ts | 29 ++++++++++++++++++- 2 files changed, 36 insertions(+), 3 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/js-collection-types.ts b/packages/compiler/src/frontend/lowering/js-collection-types.ts index a4c182523..2be4e0dbd 100644 --- a/packages/compiler/src/frontend/lowering/js-collection-types.ts +++ b/packages/compiler/src/frontend/lowering/js-collection-types.ts @@ -75,9 +75,15 @@ export function initializedCollectionType( /** The inferred collection type of an identifier that names a proven * binding, or null. Computed for every JavaScript file of the program on - * first use. */ + * first use. The inference itself reads types (a candidate's constructor + * through a destructured require, for example); while it runs, those reads + * see no inferred types rather than starting it again. */ export function inferredCollectionType(lowerer: Lowerer, node: ts.Identifier): ts.Type | null { - const types = (lowerer.inferredCollectionTypes ??= inferProgram(lowerer)); + if (lowerer.inferredCollectionTypes === undefined) { + lowerer.inferredCollectionTypes = new Map(); + lowerer.inferredCollectionTypes = inferProgram(lowerer); + } + const types = lowerer.inferredCollectionTypes; return types.size === 0 ? null : (types.get(node) ?? null); } diff --git a/packages/compiler/test/js-collection-types.test.ts b/packages/compiler/test/js-collection-types.test.ts index 6a6f65798..7a5ef967a 100644 --- a/packages/compiler/test/js-collection-types.test.ts +++ b/packages/compiler/test/js-collection-types.test.ts @@ -1,4 +1,4 @@ -import { mkdtempSync, readFileSync, rmSync } from "node:fs"; +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { expect, test } from "vitest"; @@ -62,3 +62,30 @@ test("untyped JavaScript collections take the types their uses prove, and only t rmSync(dir, { recursive: true, force: true }); } }); + +// Resolving a candidate's constructor through a destructured require reads +// types while the inference runs; those reads must not start it again. +test("the inference runs once when a candidate's values come from a destructured require", async () => { + const dir = mkdtempSync(join(tmpdir(), "scriptc-js-collection-reentry-")); + try { + const entry = join(dir, "main.cjs"); + writeFileSync( + entry, + [ + 'const util = require("node:util");', + "const { TextDecoder } = util;", + "const decoder = new TextDecoder();", + 'const decoders = new Map([["utf-8", decoder]]);', + "const seen = new Set([decoder]);", + "console.log(decoders.size, seen.size);", + "", + ].join("\n"), + ); + const output = join(dir, "main.ir.json"); + const lowered = await compile(entry, { outputKind: "ir", outDir: dir, outPath: output }); + if (!lowered.ok) throw new Error(JSON.stringify(lowered.diagnostics)); + expect(validateModule(deserializeModule(readFileSync(output, "utf8")))).toEqual([]); + } finally { + rmSync(dir, { recursive: true, force: true }); + } +}); From f4eda0fb6c9fcc475e5b7f3eb4392d7af02063c2 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 22:43:27 -0500 Subject: [PATCH 205/259] Number hoisted speculative leaves per function --- .../src/backend/llvm/emit-function.ts | 1 + packages/compiler/src/backend/llvm/emitter.ts | 7 ++- tests/harness/atomics-emission.test.ts | 2 +- tests/harness/interface-dispatch.test.ts | 4 +- .../speculative-leaves-emission.test.ts | 63 +++++++++++++++++++ 5 files changed, 72 insertions(+), 5 deletions(-) create mode 100644 tests/harness/speculative-leaves-emission.test.ts diff --git a/packages/compiler/src/backend/llvm/emit-function.ts b/packages/compiler/src/backend/llvm/emit-function.ts index b79e2406d..802a0c384 100644 --- a/packages/compiler/src/backend/llvm/emit-function.ts +++ b/packages/compiler/src/backend/llvm/emit-function.ts @@ -66,6 +66,7 @@ export function emitFunction(emitter: LlEmitter, fn: IrFunction): string { emitter.usesLandingPads = false; emitter.aliasScopedVersions = 0; emitter.findInt32Allocations(fn); + emitter.speculativeLeaves = 0; emitter.currentTier = fn.tier; // Fiber switches restore the active exception cell before control // returns to a synchronous frame (emitPendingCheck). diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index d5964f1ba..7a49e2884 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -1546,8 +1546,11 @@ export class LlEmitter { speculationResume: Map | null = null; /** The rewritten values of the writes `speculationResume` resumes at. */ speculationResumeValues: ReadonlyMap | null = null; - /** Hoisted speculative leaves numbered so far in the module. */ - private speculativeLeaves = 0; + /** Hoisted speculative leaves numbered so far in the function being + * emitted (emitFunction resets it): a function's local names must not + * depend on which functions the same emitter emitted before it, since + * function workers each emit a share of the module. */ + speculativeLeaves = 0; private readonly inlinableFunctions = new Map(); /** What speculative loop planning may assume here (SpeculationContext). */ diff --git a/tests/harness/atomics-emission.test.ts b/tests/harness/atomics-emission.test.ts index 2d708e382..9068ad59e 100644 --- a/tests/harness/atomics-emission.test.ts +++ b/tests/harness/atomics-emission.test.ts @@ -59,7 +59,7 @@ console.log(work(new Int32Array(buffer), new Uint8Array(buffer), new Int16Array( // Every runtime call is the cold path for an index out of range. const calls = work.match(/call double @scr_atomics_op\([^\n]*/g) ?? []; expect(calls).toHaveLength(9); - for (const call of calls) expect(call).toMatch(/\) cold$/); + for (const call of calls) expect(call).toMatch(/\)(?: nounwind)? cold$/); }); test("an unchanged local array is borrowed across Atomics operations", async () => { diff --git a/tests/harness/interface-dispatch.test.ts b/tests/harness/interface-dispatch.test.ts index 21e455e70..bf70ecafb 100644 --- a/tests/harness/interface-dispatch.test.ts +++ b/tests/harness/interface-dispatch.test.ts @@ -71,7 +71,7 @@ describe("interface method dispatch", () => { test("calls through an interface reach the implementing methods with typed values", async () => { const llvm = await emittedLlvm("direct", shapes("")); const run = bodies(llvm, "sc_bf_run"); - expect(run).toMatch(/call double @sc_bf__x25_dyn_class_protocol_\d+/); + expect(run).toMatch(/(?:call|invoke) double @sc_bf__x25_dyn_class_protocol_\d+/); expect(run).not.toContain("@scr_dyn_call"); expect(run).not.toContain("@sc_bf__x25_dyn_class_property_"); const dispatch = llvm.slice(llvm.indexOf("; %dyn.class.protocol.0")); @@ -90,7 +90,7 @@ describe("interface method dispatch", () => { console.log(sum([circle, new Rect(1)]));`), ); const sum = bodies(llvm, "sc_bf_sum"); - expect(sum).toMatch(/call double @sc_bf__x25_dyn_class_protocol_\d+/); + expect(sum).toMatch(/(?:call|invoke) double @sc_bf__x25_dyn_class_protocol_\d+/); expect(sum).not.toContain("@scr_dyn_iterator"); expect(sum).not.toContain("@sc_bf__x25_dyn_class_computed_"); }); diff --git a/tests/harness/speculative-leaves-emission.test.ts b/tests/harness/speculative-leaves-emission.test.ts new file mode 100644 index 000000000..16fd298d4 --- /dev/null +++ b/tests/harness/speculative-leaves-emission.test.ts @@ -0,0 +1,63 @@ +/* Speculative integer loops (behavior is in the differential corpus, 7757): + * the locals that hold hoisted calls are numbered per function, so a + * function's text does not depend on the functions emitted before it (the + * native compiler's function workers each emit a share of the module). */ +import { createHash } from "node:crypto"; +import { mkdirSync, readFileSync, writeFileSync } from "node:fs"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile } from "@scriptc/compiler"; + +const repoRoot = join(import.meta.dirname, "../.."); +const cacheDir = join(repoRoot, "node_modules/.cache/scriptc-tests"); + +async function emittedLlvm(name: string, source: string): Promise { + const key = createHash("sha256").update(source).digest("hex").slice(0, 16); + const outDir = join(cacheDir, `spec-leaves-${key}`); + mkdirSync(outDir, { recursive: true }); + const file = join(outDir, `${name}.ts`); + writeFileSync(file, source); + const result = await compile(file, { + outPath: join(outDir, name), + outDir, + backend: "llvm", + outputKind: "llvm", + }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + return readFileSync(result.artifact.path, "utf8"); +} + +function body(llvm: string, name: string): string { + const start = llvm.search(new RegExp(`^define internal [^\\n]*@${name}[.(]`, "m")); + expect(start).toBeGreaterThanOrEqual(0); + return llvm.slice(start, llvm.indexOf("\n}\n", start)); +} + +test("hoisted speculative leaves are numbered per function", async () => { + const llvm = await emittedLlvm( + "leaves", + `let calls = 0; +function noisy(x: number): number { + calls++; + return x % 5 === 0 ? x / 2 : x * 2; +} +function first(n: number): number { + let acc = 1; + for (let i = 0; i < n; i++) acc = (acc * 7 + noisy(i)) % 1000003; + return acc; +} +function second(n: number): number { + let acc = 3; + for (let i = 0; i < n; i++) acc = (acc * 5 + noisy(i)) % 1000003; + return acc; +} +console.log(first(20), second(20), calls); +`, + ); + for (const name of ["sc_f_first", "sc_f_second"]) { + const leaves = body(llvm, name).match(/%\w*spec_leaf_\d+ = alloca double/g) ?? []; + expect(leaves).toHaveLength(1); + expect(leaves[0]).toMatch(/_spec_leaf_0 = /); + } +}); From add5f4869b12444003785a3f5da2045b8523722e Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 22:53:15 -0500 Subject: [PATCH 206/259] Convert a loop's string receiver to UTF-16 at once, and publish it only when the scan holds another string --- .../src/backend/llvm/bytes-loop-versions.ts | 31 +++-- .../compiler/src/backend/llvm/string-reads.ts | 4 + .../test/string-scan-emission.test.ts | 4 +- .../test/string-unit-loop-emission.test.ts | 64 ++++++++++- .../corpus/8242-string-scan-republish.ts.json | 6 + packages/runtime/src/scr_string.c | 15 +++ packages/runtime/src/scr_string_methods.h | 5 + packages/runtime/test/test_string.c | 25 ++++ tests/corpus/8242-string-scan-republish.ts | 108 ++++++++++++++++++ 9 files changed, 249 insertions(+), 13 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8242-string-scan-republish.ts.json create mode 100644 tests/corpus/8242-string-scan-republish.ts diff --git a/packages/compiler/src/backend/llvm/bytes-loop-versions.ts b/packages/compiler/src/backend/llvm/bytes-loop-versions.ts index 0fffacb25..de704ad42 100644 --- a/packages/compiler/src/backend/llvm/bytes-loop-versions.ts +++ b/packages/compiler/src/backend/llvm/bytes-loop-versions.ts @@ -23,7 +23,7 @@ import { f64Lit } from "./common.js"; import { emitStringAsciiFlag, emitStringByteLength, - STRING_CHAR_CODE_AT_DECL, + STRING_SCAN_UNITS_DECL, stringScanType, } from "./string-reads.js"; import { unitSafeLoop } from "./string-unit-versions.js"; @@ -1360,10 +1360,11 @@ export function emitBytesLoopVersionGuard( } /** The length of a version's units receiver `s` in UTF-16 units: its byte - * length when it is ASCII; otherwise, after one runtime read publishes it - * as the scan receiver, the published unit count (0 when the runtime does - * not hold its units). Also the units pointer, whether the loop is to - * read it, and whether the published receiver is `s`. */ + * length when it is ASCII; otherwise, once it is the scan receiver, the + * published unit count (0 when the runtime does not hold its units). When + * `s` is not already the scan receiver, the runtime converts it to units + * and publishes it (scr_str_scan_units). Also the units pointer, whether + * the loop is to read it, and whether the published receiver is `s`. */ function emitUnitsLength( host: LlvmEmitterContext, s: string, @@ -1378,16 +1379,28 @@ function emitUnitsLength( join = B.newLabel("bytes.version.length"); B.condBr(ascii, join, publish); B.startBlock(publish); - host.declare(STRING_CHAR_CODE_AT_DECL); - const read = B.tmp(), - receiver = B.tmp(), + // When `s` is already the scan receiver (an earlier loop over it published + // it), its units stay published until the runtime clears the scan: skip + // the call. + const held = B.tmp(), + holds = B.tmp(); + B.line(`${held} = load ptr, ptr @scr_str_scan`); + B.line(`${holds} = icmp eq ptr ${held}, ${s}`); + const call = B.newLabel("bytes.version.publish.units"), + load = B.newLabel("bytes.version.publish.load"); + B.condBr(holds, load, call); + B.startBlock(call); + host.declare(STRING_SCAN_UNITS_DECL); + const receiver = B.tmp(), same = B.tmp(), pointerSlot = B.tmp(), pointer = B.tmp(), countSlot = B.tmp(), count = B.tmp(), published = B.tmp(); - B.line(`${read} = call double @scr_str_char_code_at(ptr ${s}, double 0.0)`); + B.line(`call void @scr_str_scan_units(ptr ${s})`); + B.br(load); + B.startBlock(load); B.line(`${receiver} = load ptr, ptr @scr_str_scan`); B.line(`${same} = icmp eq ptr ${receiver}, ${s}`); B.line(`${pointerSlot} = getelementptr inbounds ${type}, ptr @scr_str_scan, i32 0, i32 1`); diff --git a/packages/compiler/src/backend/llvm/string-reads.ts b/packages/compiler/src/backend/llvm/string-reads.ts index 08df79cf2..9fd2fa78c 100644 --- a/packages/compiler/src/backend/llvm/string-reads.ts +++ b/packages/compiler/src/backend/llvm/string-reads.ts @@ -24,6 +24,10 @@ import { literalCapWord, literalCapWord32 } from "./string-key-hash.js"; export const STRING_UTF16_LEN_DECL = "declare double @scr_str_utf16_len(ptr)"; export const STRING_CHAR_CODE_AT_DECL = "declare double @scr_str_char_code_at(ptr, double)"; +/** Converts a string to UTF-16 units and publishes it as the scan receiver + * (bytes-loop-versions.ts). Like the fallbacks below, it can evict an + * index entry, so it carries no memory restriction. */ +export const STRING_SCAN_UNITS_DECL = "declare void @scr_str_scan_units(ptr)"; /** The runtime fallbacks are cold: both common cases read inline. They * carry no * memory restriction: a fallback can evict an index entry, which resets diff --git a/packages/compiler/test/string-scan-emission.test.ts b/packages/compiler/test/string-scan-emission.test.ts index 427e2d543..76242e3d4 100644 --- a/packages/compiler/test/string-scan-emission.test.ts +++ b/packages/compiler/test/string-scan-emission.test.ts @@ -37,7 +37,9 @@ console.log(scan("é-é", "ü-ü", "ö-ö"), at("é", 0.5)); expect(llvm).toContain("@scr_str_scan = external global"); const fallbacks = llvm .split("\n") - .filter((line) => /call double @scr_str_(utf16_len|char_code_at)\(/.test(line)); + .filter((line) => + /call (double|void) @scr_str_(utf16_len|char_code_at|scan_units)\(/.test(line), + ); expect(fallbacks.length).toBeGreaterThanOrEqual(3); for (const line of fallbacks) expect(line).not.toMatch(/\bmemory\(/); } finally { diff --git a/packages/compiler/test/string-unit-loop-emission.test.ts b/packages/compiler/test/string-unit-loop-emission.test.ts index 32ee8411b..fa11af007 100644 --- a/packages/compiler/test/string-unit-loop-emission.test.ts +++ b/packages/compiler/test/string-unit-loop-emission.test.ts @@ -50,9 +50,9 @@ console.log(total, spaces("plain ascii text"), spaces("")); )![0]; const spaces = body("spaces"); - // A string that is not ASCII is published as the scan receiver once, - // before the loop, and its copy loads units. - expect(spaces).toMatch(/call double @scr_str_char_code_at\(ptr %\S+, double 0\.0\)/); + // A string that is not ASCII is converted to units and published as the + // scan receiver once, before the loop, and its copy loads units. + expect(spaces).toMatch(/call void @scr_str_scan_units\(ptr %\S+\)/); // The copies follow the checked one: bytes, then units. const bytesAt = spaces.search(/^bytes\.version\.fast\d+:/m); const unitsAt = spaces.search(/^bytes\.version\.fast\.units\d+:/m); @@ -92,3 +92,61 @@ console.log(total, spaces("plain ascii text"), spaces("")); await rm(dir, { recursive: true, force: true }); } }); + +test("loops that start at each token publish the scan receiver only when it changed", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-unit-republish-")); + try { + const entry = join(dir, "main.ts"); + await writeFile( + entry, + ` +function words(s: string): number { + let n = 0, + pos = 0; + while (pos < s.length) { + while (pos < s.length && s.charCodeAt(pos) !== 32) pos++; + while (pos < s.length && s.charCodeAt(pos) === 32) pos++; + n++; + } + return n; +} +let text = ""; +for (let k = 0; k < 400; k++) text += k % 3 === 0 ? "café " : "naïve façade "; +console.log(words(text), words(text.replace(/a/g, "ä")), words("plain ascii")); +`, + ); + const outPath = join(dir, "main.ir.json"); + const lowered = await compile(entry, { outDir: dir, outPath, outputKind: "ir" }); + if (!lowered.ok) + throw new Error(lowered.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + const ll = emitLlvmModule(deserializeModule(await readFile(outPath, "utf8"))); + const words = ll.match( + /define internal [^\n]+ @sc_bf_words(?:\.i32)?\([^\n]*\) #0 \{[\s\S]*?\n\}/, + )![0]; + // Each inner loop's entry compares the scan receiver with `s` and calls + // the runtime to publish `s` only when they differ. + const guards = [ + ...words.matchAll( + /^bytes\.version\.publish\d+:[^\n]*\n\s+(%\S+) = load ptr, ptr @scr_str_scan\n\s+(%\S+) = icmp eq ptr \1, (%\S+)\n\s+br i1 \2, label %(bytes\.version\.publish\.load\d+), label %(bytes\.version\.publish\.units\d+)\n/gm, + ), + ]; + expect(guards.length).toBeGreaterThanOrEqual(2); + for (const [, , , s, load, convert] of guards) { + const block = words.slice(words.search(new RegExp(`^${convert}:`, "m"))); + expect(block).toMatch( + new RegExp( + `^${convert}:[^\\n]*\\n\\s+call void @scr_str_scan_units\\(ptr ${s}\\)\\n\\s+br label %${load}\\n`, + ), + ); + } + const calls = words.match(/call void @scr_str_scan_units\(ptr %\S+\)/g)!; + expect(calls.length).toBe(guards.length); + + const exe = join(dir, "main"); + const built = await compile(entry, { outputKind: "exe", outDir: dir, outPath: exe }); + if (!built.ok) throw new Error(JSON.stringify(built.diagnostics)); + expect(execFileSync(exe, { encoding: "utf8" })).toBe("666 666 2\n"); + } finally { + await rm(dir, { recursive: true, force: true }); + } +}); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8242-string-scan-republish.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8242-string-scan-republish.ts.json new file mode 100644 index 000000000..78a4f52e6 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8242-string-scan-republish.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8242-string-scan-republish.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_string.c b/packages/runtime/src/scr_string.c index 2d7f46d85..d2d397e25 100644 --- a/packages/runtime/src/scr_string.c +++ b/packages/runtime/src/scr_string.c @@ -1889,6 +1889,21 @@ static bool scr_sidx_units(const ScrStr *s, ScrSidx *e) { return true; } +/* A loop about to read every unit of s (bytes-loop-versions.ts) converts it + * at once instead of after the threshold's reads, and publishes it as the + * scan's receiver. ASCII receivers and receivers past SCR_SIDX_UNITS_MAX + * publish nothing; the caller compares scr_str_scan.s with s. */ +void scr_str_scan_units(ScrStr *s) { + if (s->ascii || s->len > SCR_SIDX_UNITS_MAX) return; + ScrSidx *e = scr_sidx(s); + if (!e->units) e->units = scr_str_units(s, &e->nunits); + if (scr_str_scan.s != s) { + scr_str_scan.s = s; + scr_str_scan.units = e->units; + scr_str_scan.n = e->nunits; + } +} + typedef enum { SCR_UNIT_FIRST, SCR_UNIT_LAST, SCR_UNIT_AT } ScrUnitSearch; /* The UTF-16 index of needle in s: the first match at or after `from`, diff --git a/packages/runtime/src/scr_string_methods.h b/packages/runtime/src/scr_string_methods.h index 1f25b8766..820b1c9e6 100644 --- a/packages/runtime/src/scr_string_methods.h +++ b/packages/runtime/src/scr_string_methods.h @@ -42,6 +42,11 @@ extern SCR_TL ScrStrScan scr_str_scan; * [0, length) — note charCodeAt(1.5) is index 1, matching Node. */ double scr_str_char_code_at(ScrStr *s, double i); +/* Converts a non-ASCII s up to the units cap to UTF-16 at once and + * publishes it in scr_str_scan, for a loop about to read all of it. Leaves + * scr_str_scan unchanged for any other s. */ +void scr_str_scan_units(ScrStr *s); + /* indexOf(needle, fromIndex): UTF-16 index of the first occurrence at or * after fromIndex (clamped to [0, length]), or -1. Empty needle returns the * clamped fromIndex per spec. */ diff --git a/packages/runtime/test/test_string.c b/packages/runtime/test/test_string.c index e49d8eb8b..3e14a5958 100644 --- a/packages/runtime/test/test_string.c +++ b/packages/runtime/test/test_string.c @@ -522,6 +522,30 @@ static void short_string_asserts(void) { scr_str_release(source); } +/* A loop's publish converts a non-ASCII receiver before any read, while a + * lone read still walks bytes. ASCII receivers publish nothing. */ +static void scan_units_asserts(void) { + ScrStr *s = scr_str_new("a\xC3\xA9\xF0\x9F\x98\x80" "b", 8); /* a é 😀 b */ + static const double codes[] = {97, 233, 0xD83D, 0xDE00, 98}; + if (scr_str_char_code_at(s, 0) != 97 || scr_str_scan.s == s) failed++; + scr_str_scan_units(s); + if (scr_str_scan.s != s || scr_str_scan.n != 5) failed++; + for (size_t i = 0; i < 5; i++) + if (scr_str_scan.n == 5 && (scr_str_scan.units[i] != codes[i] || + scr_str_char_code_at(s, (double)i) != codes[i])) failed++; + if (!isnan(scr_str_char_code_at(s, 5))) failed++; + scr_str_scan_units(s); /* republishing keeps the same units */ + const uint16_t *units = scr_str_scan.units; + scr_str_scan_units(s); + if (scr_str_scan.s != s || scr_str_scan.units != units) failed++; + ScrStr *ascii = scr_str_new("plain", 5); + scr_str_scan_units(ascii); + if (scr_str_scan.s != s) failed++; + scr_str_release(ascii); + scr_str_release(s); + if (scr_str_scan.s != NULL) failed++; + total++; +} #ifdef SCR_SIDX_TEST static void sidx_fail(const char *what) { failed++; @@ -1153,6 +1177,7 @@ int main(int argc, char **argv) { split_scratch_asserts(); accumulation_asserts(); short_string_asserts(); + scan_units_asserts(); #ifdef SCR_SIDX_TEST sparse_index_asserts(); sparse_ascii_prefix_asserts(); diff --git a/tests/corpus/8242-string-scan-republish.ts b/tests/corpus/8242-string-scan-republish.ts new file mode 100644 index 000000000..9800bb099 --- /dev/null +++ b/tests/corpus/8242-string-scan-republish.ts @@ -0,0 +1,108 @@ +// Token scans that alternate between two non-ASCII strings: each inner loop +// starts at a token and runs while the class holds, so every token enters a +// loop over one of the strings again. Also a string extended in place +// between scans, strings rebuilt with the same length and new content, and +// slices of a scanned string. + +function isWord(c: number): boolean { + return (c >= 97 && c <= 122) || (c >= 65 && c <= 90) || c >= 0xc0; +} + +function isDigit(c: number): boolean { + return c >= 48 && c <= 57; +} + +// The kinds and lengths of s's tokens, hashed. +function lex(s: string): number { + let h = 0, + tokens = 0, + pos = 0; + const end = s.length; + while (pos < end) { + const c = s.charCodeAt(pos); + let start = pos; + if (isWord(c)) { + while (pos < end && isWord(s.charCodeAt(pos))) pos++; + h = (h * 31 + 1) | 0; + } else if (isDigit(c)) { + while (pos < end && isDigit(s.charCodeAt(pos))) pos++; + h = (h * 31 + 2) | 0; + } else if (c === 32) { + while (pos < end && s.charCodeAt(pos) === 32) pos++; + start = pos; + } else { + pos++; + h = (h * 31 + c) | 0; + } + h = (h * 31 + (pos - start)) | 0; + tokens++; + } + return h ^ tokens; +} + +// Two strings lexed token by token in turn: each token's loop runs over a +// different receiver than the one before it. +function interleave(a: string, b: string): number { + let i = 0, + j = 0, + h = 0; + while (i < a.length || j < b.length) { + const fromA = i < a.length; + while (i < a.length && a.charCodeAt(i) !== 32) { + h = (h * 31 + a.charCodeAt(i)) | 0; + i++; + } + i++; + while (j < b.length && b.charCodeAt(j) !== 32) { + h = (h * 37 + b.charCodeAt(j)) | 0; + j++; + } + j++; + if (fromA) h = (h + 1) | 0; + } + return h; +} + +// The sum of every unit of s. +function units(s: string): number { + let sum = 0; + for (let i = 0; i < s.length; i++) sum += s.charCodeAt(i); + return sum; +} + +function text(seed: number, words: number): string { + const parts = ["café", "naïve", "façade", "x", "😀", "Ωmega", "über", "ab"]; + let s = ""; + for (let k = 0; k < words; k++) { + s += parts[(seed + k * 7) % parts.length]!; + s += k % 5 === 0 ? " " + ((seed * k) % 1000) + " " : k % 3 === 0 ? "; " : " "; + } + return s; +} + +const first = text(1, 300), + second = text(4, 280); +for (let pass = 0; pass < 3; pass++) { + console.log(lex(first), lex(second), lex(first), units(second), units(first)); + console.log(interleave(first, second), interleave(second, first)); +} + +// Extended in place between scans: the second scan reads the new units. +let grown = text(2, 120); +console.log(lex(grown), units(grown), grown.length); +for (let round = 0; round < 4; round++) { + grown += round % 2 === 0 ? " é1 ü22 " : " 😀 tail "; + console.log(lex(grown), units(grown), grown.length, interleave(grown, first)); +} + +// Same length, different content, built after the previous one is dropped. +for (let round = 0; round < 6; round++) { + const s = round % 2 === 0 ? "é".repeat(200) + " a" : "ü".repeat(200) + " b"; + console.log(lex(s), units(s), units(s.slice(0, 100)), lex(second)); +} + +// Slices of a scanned string, scanned between scans of the whole. +for (const at of [0, 7, 101, first.length - 9]) { + const part = first.slice(at, at + 64); + console.log(lex(part), units(part), lex(first), units(part.slice(3))); +} From faa54f6443d35873d37b29ea9e4385707553744f Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 22:58:41 -0500 Subject: [PATCH 207/259] Cache only number-key integer views that need no conversion A Map/Set lookup's integer key view was cached for the function by the key operand's name. When the view was a conversion emitted at a lookup in a branch, a later lookup of the same operand (a wide integer constant) reused it from a block the conversion does not dominate, and LLVM rejected the module. Only the value's own integer or uint32 view and integral literals are cached now. --- .../backend/llvm/map-number-lookup.test.ts | 49 +++++++++++++++++++ .../src/backend/llvm/map-number-lookup.ts | 16 ++++-- tests/corpus/6308-number-map-integer-keys.ts | 15 ++++++ 3 files changed, 77 insertions(+), 3 deletions(-) diff --git a/packages/compiler/src/backend/llvm/map-number-lookup.test.ts b/packages/compiler/src/backend/llvm/map-number-lookup.test.ts index 28b6a0552..7457db42d 100644 --- a/packages/compiler/src/backend/llvm/map-number-lookup.test.ts +++ b/packages/compiler/src/backend/llvm/map-number-lookup.test.ts @@ -206,6 +206,55 @@ test("a key with an integer view tests the direct index on the integer", () => { } }); +test("a key view converted in a branch is not reused by a later lookup of the same constant", () => { + // work(map, k, taken): if (taken) return map.has((k = 2 ** 40)); return map.has(2 ** 40). + const wide = 2 ** 40; + const mod = lookupFixture(); + const work = mod.functions[1]!; + const map = work.params[0]!.type; + const has = (key: IrExpr): IrExpr => ({ + kind: "mapIntrinsic", + method: "has", + receiver: ref("map", map), + args: [key], + type: BOOL, + loc, + }); + const literal: IrExpr = { kind: "numLit", value: wide, type: F64, loc }; + const taken = { localId: "taken", name: "taken", type: BOOL }; + work.params.push(taken); + work.locals.push({ id: "taken", name: "taken", type: BOOL, mutable: true }); + work.body = [ + { + kind: "if", + cond: ref("taken", BOOL), + then: [ + { + kind: "return", + value: has({ + kind: "assignExpr", + localId: "k", + value: literal, + type: F64, + loc, + }), + loc, + }, + ], + else_: null, + loc, + }, + { kind: "return", value: has(literal), loc }, + ]; + for (const bits of [32, 64] as const) { + const { work: text } = emitted(mod, bits); + // The lookup after the branch takes the literal, not a conversion made + // inside the branch. + expect(text).toMatch(/call ptr @sc_map_entry_f64_int\(ptr %\S+, i64 1099511627776, double /); + expect(text).not.toMatch(/@sc_map_entry_f64_int\(ptr %\S+, i64 %/); + } +}); + /** work(map): map.size, and keep(map): map returned as an owned value. */ function sizeFixture(): IrModule { const map: IrType = { kind: "map", key: F64, value: F64 }; diff --git a/packages/compiler/src/backend/llvm/map-number-lookup.ts b/packages/compiler/src/backend/llvm/map-number-lookup.ts index 6cb7f1ea3..0038cbb96 100644 --- a/packages/compiler/src/backend/llvm/map-number-lookup.ts +++ b/packages/compiler/src/backend/llvm/map-number-lookup.ts @@ -34,12 +34,22 @@ import { exactInteger, widenInteger } from "./integer-values.js"; import { mapKeyAccess } from "./shapes.js"; export const NUMBER_MAP_ENTRY_DECL = "declare ptr @scr_map_entry_f64(ptr, double)"; -/** Record the integer view of a number Map/Set key operand, when the - * emitter has one (exactInteger), for the entry lookups of that key. */ +/** Record the integer view of a number Map/Set key operand for the entry + * lookups of that key, when the view needs no instruction of its own: the + * value's integer or uint32 view, defined with the value, or an integral + * literal. A view exactInteger converts at this lookup is not recorded: the + * key cache spans the function, and a later lookup of the same operand (a + * constant, say) can be in a block the conversion does not dominate. */ export function noteNumberMapKey(host: LlvmEmitterContext, key: LlValue, expr: IrExpr): void { if (key.type.kind !== "f64" || host.numberMapKeyIntegers.has(key.name)) return; + if (!key.integer && key.uint32 === undefined && expr.kind !== "numLit") return; const integer = exactInteger(host, key, expr); - if (integer) host.numberMapKeyIntegers.set(key.name, integer); + if (!integer) return; + const defined = + integer.name === key.integer?.name || + integer.name === key.uint32 || + /^-?\d+$/.test(integer.name); + if (defined) host.numberMapKeyIntegers.set(key.name, integer); } /** The entry for `key`, or null when absent. Valid until the next mutation. diff --git a/tests/corpus/6308-number-map-integer-keys.ts b/tests/corpus/6308-number-map-integer-keys.ts index 16110f80a..75efb3a72 100644 --- a/tests/corpus/6308-number-map-integer-keys.ts +++ b/tests/corpus/6308-number-map-integer-keys.ts @@ -60,3 +60,18 @@ for (let i = 0; i < 5; i++) { key = key * 2 - 1; } console.log([...wide.keys()].join(" "), wide.get(2 ** 52), wide.get(2 ** 53 - 1)); + +// A lookup whose key is an assignment of a wide integer constant, in a +// branch, then a lookup of the same constant after the branch. +const far = new Map(); +far.set(1099511627776, 7); +function probeFar(taken: boolean): number { + let k = 0; + let hits = 0; + if (taken) { + if (far.has((k = 1099511627776))) hits += 1; + } + hits += far.get(1099511627776) ?? -1; + return hits + k; +} +console.log(probeFar(true), probeFar(false)); From 6a299479988ccc7ee188e458786cdbcbf1259b47 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 22:59:02 -0500 Subject: [PATCH 208/259] Run the native compiler's nursery passes every 1024 candidates The native compiler now starts with the cycle collector's nursery trigger at 1024 new candidates instead of 256. scr_cyc_set_nursery_threshold sets the trigger that SCR_CYCLE_THRESHOLD sets, on the pattern of scr_cyc_set_growth_cap; the environment variable still takes precedence. The compiler sets it from a constructor in its host object, before its modules initialize. Set from main, the trigger leaves the build's collection work where it was: the cost depends on the collector's first passes. Programs keep the default trigger. A cold tsc-ts build takes 4% less wall time (12 paired runs) and its peak RSS goes from 1.41 GB to 1.31 GB. The program's IR is unchanged. --- packages/compiler/native/host.c | 11 +++++++++++ packages/runtime/src/scr_cycle.c | 19 +++++++++++++++---- packages/runtime/src/scr_rc.h | 6 ++++++ packages/runtime/test/test_cycle.c | 19 +++++++++++++++++++ 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/packages/compiler/native/host.c b/packages/compiler/native/host.c index f54bdaa3f..4e1a0b754 100644 --- a/packages/compiler/native/host.c +++ b/packages/compiler/native/host.c @@ -135,3 +135,14 @@ void scr_cyc_set_growth_cap(long cap); void scriptc_native_bound_cycle_growth(void) { scr_cyc_set_growth_cap(2); } + +/* The runtime's nursery trigger (scr_rc.h). */ +void scr_cyc_set_nursery_threshold(long threshold); + +/* Runs nursery passes every 1024 new candidates instead of every 256. It + * has to be in place before the compiler's modules initialize: set from + * main it leaves the build's collection work as it is. SCR_CYCLE_THRESHOLD + * still overrides it. */ +__attribute__((constructor)) static void scriptc_native_widen_cycle_nursery(void) { + scr_cyc_set_nursery_threshold(1024); +} diff --git a/packages/runtime/src/scr_cycle.c b/packages/runtime/src/scr_cycle.c index dbd636306..d08f54a21 100644 --- a/packages/runtime/src/scr_cycle.c +++ b/packages/runtime/src/scr_cycle.c @@ -637,14 +637,25 @@ static SCR_TL bool scr_cyc_idle_points = false; static SCR_TL size_t scr_cyc_death_due_live = 0; #endif +/* The nursery trigger a program sets for itself + * (scr_cyc_set_nursery_threshold), 0 for the default; SCR_CYCLE_THRESHOLD + * takes precedence over it. */ +static long scr_cyc_nursery_threshold_set = 0; +static SCR_TL size_t scr_cyc_nursery_threshold_cached = 0; + static size_t scr_cyc_nursery_threshold(void) { - static SCR_TL size_t cached = 0; - if (cached == 0) { + if (scr_cyc_nursery_threshold_cached == 0) { const char *env = scr_getenv("SCR_CYCLE_THRESHOLD"); long v = env ? strtol(env, NULL, 10) : 0; - cached = v > 0 ? (size_t)v : SCR_CYC_NURSERY_CANDIDATES; + if (v <= 0) v = scr_cyc_nursery_threshold_set; + scr_cyc_nursery_threshold_cached = v > 0 ? (size_t)v : SCR_CYC_NURSERY_CANDIDATES; } - return cached; + return scr_cyc_nursery_threshold_cached; +} + +void scr_cyc_set_nursery_threshold(long threshold) { + scr_cyc_nursery_threshold_set = threshold; + scr_cyc_nursery_threshold_cached = 0; } /* The number of buffered candidates (across every generation) at which the diff --git a/packages/runtime/src/scr_rc.h b/packages/runtime/src/scr_rc.h index 4d8e059a9..de9f21f44 100644 --- a/packages/runtime/src/scr_rc.h +++ b/packages/runtime/src/scr_rc.h @@ -700,6 +700,12 @@ void scr_collect_cycles_phase(void); * that knows its own memory profile; the environment variable takes * precedence. Call it before the program allocates much. */ void scr_cyc_set_growth_cap(long cap); +/* Sets the nursery trigger SCR_CYCLE_THRESHOLD sets (scr_cycle.c): the + * number of new candidates at which the release path runs a pass, for a + * program that knows its own collection profile. The environment variable + * takes precedence; 0 restores the default. The trigger re-arms with it at + * the end of the next pass. Call it before the program allocates much. */ +void scr_cyc_set_nursery_threshold(long threshold); void scr_cyc_context_cleanup(void); /* One pass on the normal generational schedule, for callers that reach a diff --git a/packages/runtime/test/test_cycle.c b/packages/runtime/test/test_cycle.c index 160083d6b..0ab827e47 100644 --- a/packages/runtime/test/test_cycle.c +++ b/packages/runtime/test/test_cycle.c @@ -557,6 +557,24 @@ static void check_program_growth_cap(void) { scr_cyc_set_growth_cap(0); } +/* scr_cyc_set_nursery_threshold sets the trigger SCR_CYCLE_THRESHOLD sets, + * from the end of the next pass: with a trigger of 1024, dead rings released + * after a full pass wait until the 1024th, which collects them all. 0 + * restores the default. */ +static void check_program_nursery_threshold(void) { + enum { THRESHOLD = 1024 }; + if (getenv("SCR_CYCLE_THRESHOLD") != NULL) return; /* it takes precedence */ + scr_cyc_set_nursery_threshold(THRESHOLD); + scr_collect_cycles(); /* re-arm with the new trigger */ + size_t before = freed; + for (size_t i = 0; i < THRESHOLD - 1; i++) release_live(make_ring(1)); + check(freed == before, "a program's nursery trigger did not hold the pass back"); + release_live(make_ring(1)); + check(freed - before == THRESHOLD, "a program's nursery trigger did not run the pass"); + scr_cyc_set_nursery_threshold(0); + scr_collect_cycles(); +} + /* The phase sweep (scr_collect_cycles_phase) is for a caller that knows a * phase's data has just died: it sweeps, and the growth schedule starts * over. After passes that find nothing have widened the old level's @@ -1522,6 +1540,7 @@ int main(void) { check_unjudged_backlog_follows_growth(); check_acyclic_objects(); check_program_growth_cap(); + check_program_nursery_threshold(); printf("cycle collection checks passed: threshold=%zu growth_cap=%zu\n", configured_nursery_threshold(), configured_growth_cap()); return 0; From 20041b4262e9be646fa30215f5efb3300925bdea Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 23:27:15 -0500 Subject: [PATCH 209/259] Keep speculative copies in typed-array loops over shared storage In a program that can start a worker, a typed-array loop version's guard requires thread-owned storage, so every view of a SharedArrayBuffer runs the version's checked copy. That copy gave its loops no speculative or int32 kind copies, on the assumption that it rarely runs, so loops over shared views, such as k-nucleotide's frequency count in every worker, ran only the double copy. A version whose guard requires thread-owned storage now keeps those copies in its checked copy. --- .../src/backend/llvm/emit-statements.ts | 9 ++++-- .../test/speculative-loop-emission.test.ts | 30 +++++++++++++++++++ 2 files changed, 37 insertions(+), 2 deletions(-) diff --git a/packages/compiler/src/backend/llvm/emit-statements.ts b/packages/compiler/src/backend/llvm/emit-statements.ts index 378c82bee..63bae226e 100644 --- a/packages/compiler/src/backend/llvm/emit-statements.ts +++ b/packages/compiler/src/backend/llvm/emit-statements.ts @@ -2061,7 +2061,8 @@ function emitCallbackVersionedLoop( /** The copy of a versioned loop that runs when its guard fails. Its loops * get no speculative or int32 kind copies, which would emit each loop again * for a path that rarely runs. Proven integer loops, which emit one copy, - * are kept. */ + * are kept. A typed-array version whose guard requires thread-owned + * storage does not use it (emitVersionedLoop). */ function emitSlowCopy(emitter: LlEmitter, s: IrStmt): void { const copies = emitter.loopCopiesEnabled; emitter.loopCopiesEnabled = false; @@ -2145,7 +2146,11 @@ function emitVersionedLoop( LOOPS.of(emitter).bytesLoopVersioning.add(s); try { B.startBlock(slow); - emitSlowCopy(emitter, s); + // A guard that requires thread-owned storage fails for every view of + // shared memory, which worker programs pass routinely: that checked + // copy keeps its loops' speculative and int32 kind copies. + if (version.ownedReceivers.length > 0) emitter.emitStmt(s); + else emitSlowCopy(emitter, s); B.br(done); if (version.owned.size > 0) emitter.bytesOwned = new Set([...originalOwned, ...version.owned]); if (version.ranges.size > 0) diff --git a/packages/compiler/test/speculative-loop-emission.test.ts b/packages/compiler/test/speculative-loop-emission.test.ts index 3f6aef158..748fd50c5 100644 --- a/packages/compiler/test/speculative-loop-emission.test.ts +++ b/packages/compiler/test/speculative-loop-emission.test.ts @@ -129,3 +129,33 @@ if (isMainThread) { expect(order.slice(slow, fast).some((l) => l.startsWith("integer.leave"))).toBe(true); expect(order.slice(fast).some((l) => l.startsWith("integer.leave"))).toBe(true); }); + +test("the shared-storage copy of a typed-array version keeps its speculative copy", async () => { + // In a program that can start a worker, the guard requires thread-owned + // storage, so every view of a SharedArrayBuffer runs the checked copy. + const llvm = await emitLlvm(` +import { Worker, isMainThread } from "node:worker_threads"; +function trim(value: number, bits: number): number { + return value - Math.floor(value / Math.pow(2, bits)) * Math.pow(2, bits); +} +function key(bytes: Uint8Array, bits: number): number { + let k = 0; + for (let i = 0; i < bytes.length; i++) k = trim(k, bits) * 4 + bytes[i]!; + return k; +} +if (isMainThread) { + if (process.argv[2] === "spawn") new Worker(new URL(import.meta.url)); + const shared = new Uint8Array(new SharedArrayBuffer(4)); + shared.set([1, 2, 3, 0]); + console.log(key(shared, 6), key(new Uint8Array([3, 2, 1, 0]), 6)); +} +`); + const fn = /^define internal double @sc_bf_\w*key[\w.]*\([^]*?^}/m.exec(llvm)?.[0] ?? ""; + const order = labels(fn); + const slow = order.findIndex((l) => l.startsWith("bytes.version.slow")); + const fast = order.findIndex((l) => l.startsWith("bytes.version.fast")); + expect(slow).toBeGreaterThanOrEqual(0); + expect(fast).toBeGreaterThan(slow); + expect(order.slice(slow, fast).some((l) => l.startsWith("spec.fast"))).toBe(true); + expect(order.slice(fast).some((l) => l.startsWith("spec.fast"))).toBe(true); +}); From f06f47aca1fbd4d2af6a354ce206750f324569e7 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 23:27:46 -0500 Subject: [PATCH 210/259] Resolve promises with an argument in the rejectUnauthorized corpus program 8179-tls-reject-unauthorized-values.mjs called the resolve function of an untyped new Promise() with no argument. tsgo types that function as taking one argument and reported SC0001 for each call, while tsc-ts accepted them, so the checker-identity comparison failed. The calls now pass undefined. --- tests/corpus/8179-tls-reject-unauthorized-values.mjs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/corpus/8179-tls-reject-unauthorized-values.mjs b/tests/corpus/8179-tls-reject-unauthorized-values.mjs index d0275ab4a..4e87099d4 100644 --- a/tests/corpus/8179-tls-reject-unauthorized-values.mjs +++ b/tests/corpus/8179-tls-reject-unauthorized-values.mjs @@ -31,10 +31,10 @@ for (const [label, value] of values) { c.on("secureConnect", () => events.push("client secureConnect")); c.on("data", (d) => events.push(`client data ${d}`)); c.on("error", (e) => events.push(`client error ${e.code}`)); - c.on("close", () => setTimeout(done, 50)); + c.on("close", () => setTimeout(() => done(undefined), 50)); }); console.log("rejectUnauthorized", label, "|", events.join(" ; ")); - await new Promise((res) => server.close(() => res())); + await new Promise((res) => server.close(() => res(undefined))); } { @@ -47,7 +47,7 @@ for (const [label, value] of values) { c.on("secureConnect", () => events.push(`secureConnect authorized=${c.authorized} error=${c.authorizationError}`)); c.on("data", (d) => events.push(`data ${d}`)); c.on("error", (e) => events.push(`error ${e.code}`)); - c.on("close", () => done()); + c.on("close", () => done(undefined)); }); console.log("tls.connect rejectUnauthorized", label, "|", events.join(" ; ")); } From 182a108270f0884f856335e6d58c0e256e11131e Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 23:41:28 -0500 Subject: [PATCH 211/259] Correct the native compiler's nursery trigger comment --- packages/compiler/native/host.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/compiler/native/host.c b/packages/compiler/native/host.c index 4e1a0b754..24d330cc0 100644 --- a/packages/compiler/native/host.c +++ b/packages/compiler/native/host.c @@ -139,10 +139,12 @@ void scriptc_native_bound_cycle_growth(void) { /* The runtime's nursery trigger (scr_rc.h). */ void scr_cyc_set_nursery_threshold(long threshold); -/* Runs nursery passes every 1024 new candidates instead of every 256. It - * has to be in place before the compiler's modules initialize: set from - * main it leaves the build's collection work as it is. SCR_CYCLE_THRESHOLD - * still overrides it. */ +/* Runs nursery passes every 1024 new candidates instead of every 256. Much + * of a build's cyclic garbage outlives 256 releases: in the shorter window + * it survives a nursery pass, is promoted, and only full passes over the + * whole live heap find it. A constructor sets it before the compiler's + * modules initialize, so every pass of a build uses it. + * SCR_CYCLE_THRESHOLD still overrides it. */ __attribute__((constructor)) static void scriptc_native_widen_cycle_nursery(void) { scr_cyc_set_nursery_threshold(1024); } From 3e115ce08c8aff475cf6f125e34f2282c4c52e3a Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sat, 24 Oct 2026 23:47:41 -0500 Subject: [PATCH 212/259] Cache absent properties in the dynamic tier's property caches A read site's cache only remembered properties it found on the receiver or its first prototype. Reads of properties an object lacks, which validation libraries make constantly (zod reads ctx.skipChecks, payload.memo, x.aborted and _zod.optin on every check), walked the whole shape chain and then repeated the lookup on the generic path every time: 7.9 million such reads in one zod benchmark run. - Read sites call a new probe, scr_js_get_probe, that answers undefined for a key the receiver and its chain of plain shaped objects (at most one prototype, ending in the default prototype) lack, and caches that answer. The entry holds while the receiver's shape, its prototype link, and that prototype's shape are unchanged. Its tag and placeholder holder make the inline entry-0 test in compiled code miss, so the answer always comes from the probe. Method reads keep scr_js_load_probe, so a missing method still reaches the slow path and its "is not a function" error. Names of Object.prototype members are never cached as absent. - Receivers of one shape with different prototypes (zod's internals objects) each keep an entry instead of replacing one another. - A site whose four-way record is full consults a per-thread table keyed by shape and key before walking shapes, and fills it. --- packages/compiler/src/backend/llvm/js-ic.ts | 8 +- packages/compiler/test/js-ic-emission.test.ts | 4 +- .../corpus/absent-property-reads.mjs.json | 6 + packages/runtime/src/scr_js.h | 4 + packages/runtime/src/scr_js_object.c | 145 +++++++++++++++++- packages/runtime/src/scr_js_object.test.c | 120 +++++++++++++++ packages/runtime/src/scr_js_object.test.ts | 12 +- tests/corpus/absent-property-reads.mjs | 87 +++++++++++ .../absent-property-reads.mjs.json | 1 + 9 files changed, 370 insertions(+), 17 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/absent-property-reads.mjs.json create mode 100644 tests/corpus/absent-property-reads.mjs create mode 100644 tests/harness/corpus-costs/absent-property-reads.mjs.json diff --git a/packages/compiler/src/backend/llvm/js-ic.ts b/packages/compiler/src/backend/llvm/js-ic.ts index b8be1ecb1..b69d3199d 100644 --- a/packages/compiler/src/backend/llvm/js-ic.ts +++ b/packages/compiler/src/backend/llvm/js-ic.ts @@ -6,7 +6,8 @@ * * load ordinary object whose shape is entry 0's own-property shape: * read entry `slot` inline unless it is an accessor; otherwise - * scr_js_load_probe (polymorphic, prototype hits, misses) + * scr_js_get_probe (polymorphic, prototype hits, absent keys, + * misses) * store ordinary object whose shape is entry 0's replace shape, outside * an intact parse region, writable data entry: replace inline; * otherwise scr_js_store_probe (adds, polymorphic, misses) @@ -402,9 +403,10 @@ function emitGet(host: Host, e: ExprOf<"call">, callee: IrFunction, key: string) B.startBlock(object); inlineLoad(host, receiver.name, ic, INLINE_WAYS, INLINE_PROTO, (cell) => cell, hits, hit, probe); B.startBlock(probe); - host.declare(`declare ptr @scr_js_load_probe(ptr, ptr, ptr)`); + // The read's probe also answers keys the receiver's plain chain lacks. + host.declare(`declare ptr @scr_js_get_probe(ptr, ptr, ptr)`); const probed = B.tmp(); - B.line(`${probed} = call ptr @scr_js_load_probe(ptr ${receiver.name}, ptr ${name}, ptr ${ic})`); + B.line(`${probed} = call ptr @scr_js_get_probe(ptr ${receiver.name}, ptr ${name}, ptr ${ic})`); const found = B.tmp(); B.line(`${found} = icmp ne ptr ${probed}, null`); const probeEnd = B.currentLabel(); diff --git a/packages/compiler/test/js-ic-emission.test.ts b/packages/compiler/test/js-ic-emission.test.ts index 7a1d44f34..437ac34e4 100644 --- a/packages/compiler/test/js-ic-emission.test.ts +++ b/packages/compiler/test/js-ic-emission.test.ts @@ -48,7 +48,7 @@ console.log(read(o), at(dyn([5, 6]), 1), call(o), o.n); expect(llvm).toMatch( /@sc_js_ic_0 = internal (thread_local )?global \[21 x i64\] zeroinitializer/, ); - expect(body(llvm, "read")).toContain("@scr_js_load_probe("); + expect(body(llvm, "read")).toContain("@scr_js_get_probe("); expect(body(llvm, "write")).toContain("@scr_js_store_probe("); expect(body(llvm, "at")).toContain("@scr_js_keyed_probe("); expect(body(llvm, "call")).toContain("@scr_js_load_probe("); @@ -100,7 +100,7 @@ console.log(read(o), read(p), read(t), at(dyn([5, 6]), 1), at(p, "x"), at(t, "ta const mod = deserializeModule(await readFile(outPath, "utf8")); expect(validateModule(mod)).toEqual([]); const llvm = emitLlvmModule(mod); - expect(body(llvm, "read")).toContain("@scr_js_load_probe("); + expect(body(llvm, "read")).toContain("@scr_js_get_probe("); expect(body(llvm, "write")).toContain("@scr_js_store_probe("); expect(body(llvm, "at")).toContain("@scr_js_keyed_probe("); } finally { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/absent-property-reads.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/absent-property-reads.mjs.json new file mode 100644 index 000000000..3c0646fa9 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/absent-property-reads.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/absent-property-reads.mjs" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_js.h b/packages/runtime/src/scr_js.h index 1d874b31e..3ff9becd3 100644 --- a/packages/runtime/src/scr_js.h +++ b/packages/runtime/src/scr_js.h @@ -231,6 +231,10 @@ typedef struct ScrJsIc { /* `receiver.key` for a plain data property: +1 value, or NULL. */ ScrDyn *scr_js_load_probe(ScrDyn *receiver, const ScrStr *key, ScrJsIc *ic); +/* The same for a property read site, which also answers (+1) undefined for + * a key that the receiver and its plain prototype chain lack, and caches + * that answer. A method read uses scr_js_load_probe. */ +ScrDyn *scr_js_get_probe(ScrDyn *receiver, const ScrStr *key, ScrJsIc *ic); /* `receiver.key = value` (value borrowed) when it replaces a writable own * data property or adds one the prototype chain lacks: true when done. */ bool scr_js_store_probe(ScrDyn *receiver, const ScrStr *key, ScrDyn *value, ScrJsIc *ic); diff --git a/packages/runtime/src/scr_js_object.c b/packages/runtime/src/scr_js_object.c index e09226fd1..e97651557 100644 --- a/packages/runtime/src/scr_js_object.c +++ b/packages/runtime/src/scr_js_object.c @@ -76,9 +76,21 @@ static SCR_TL size_t scr_js_filled_capacity; * which answer with a miss until the key set changes. */ static ScrJsShape scr_js_unshaped; +/* The second-level cache of load sites whose own record is full: one entry + * per (receiver shape, key bytes) slot, filled by the probe and checked like + * a site entry. It names shapes, so the shape reset clears it. */ +#define SCR_JS_SHARED_LOADS 2048 +typedef struct ScrJsSharedLoad { + const char *key; + ScrJsIcEntry entry; +} ScrJsSharedLoad; +static SCR_TL ScrJsSharedLoad *scr_js_shared_loads; + static void scr_js_shapes_reset(void) { for (size_t i = 0; i < scr_js_filled_count; i++) memset(scr_js_filled_ics[i], 0, sizeof *scr_js_filled_ics[i]); + free(scr_js_shared_loads); + scr_js_shared_loads = NULL; free(scr_js_filled_ics); scr_js_filled_ics = NULL; scr_js_filled_count = 0; @@ -244,38 +256,155 @@ static ScrDyn *scr_js_load_hit(ScrDyn *receiver, const ScrJsIcEntry *entry) { return found->accessor ? NULL : scr_dyn_retain(found->value); } -ScrDyn *scr_js_load_probe(ScrDyn *receiver, const ScrStr *key, ScrJsIc *ic) { +/* An absent entry: its target is this tag and its holder is a placeholder + * that is never a prototype, so the inline test of entry 0 in compiled code + * (a prototype hit needs the receiver's prototype to be the holder) always + * sends such a receiver to the probe. Its holder_shape and slot name the one + * prototype the read walked past (shape and object), or NULL and 0 when the + * receiver had no prototype. */ +static const ScrJsShape scr_js_absent; +static const ScrDyn scr_js_absent_holder; + +/* Keys whose read on a plain object is not just its [[Get]]: the members of + * Object.prototype, which reads of an absent own property answer through + * the inherited-member path, and the error constructor read. */ +static bool scr_js_absent_cacheable(const ScrStr *key) { +#define SCR_JS_INHERITED(name) {name, sizeof name - 1} + static const struct { + const char *name; + size_t len; + } inherited[] = { + SCR_JS_INHERITED("constructor"), SCR_JS_INHERITED("__proto__"), + SCR_JS_INHERITED("toString"), SCR_JS_INHERITED("toLocaleString"), + SCR_JS_INHERITED("valueOf"), SCR_JS_INHERITED("hasOwnProperty"), + SCR_JS_INHERITED("isPrototypeOf"), SCR_JS_INHERITED("propertyIsEnumerable"), + SCR_JS_INHERITED("__defineGetter__"), SCR_JS_INHERITED("__defineSetter__"), + SCR_JS_INHERITED("__lookupGetter__"), SCR_JS_INHERITED("__lookupSetter__"), + }; +#undef SCR_JS_INHERITED + for (size_t i = 0; i < sizeof inherited / sizeof inherited[0]; i++) + if (key->len == inherited[i].len && memcmp(key->data, inherited[i].name, key->len) == 0) + return false; + return true; +} + +static ScrJsSharedLoad *scr_js_shared_load(const ScrJsShape *shape, const ScrStr *key) { + if (!scr_js_shared_loads) { + scr_js_shared_loads = calloc(SCR_JS_SHARED_LOADS, sizeof *scr_js_shared_loads); + if (!scr_js_shared_loads) scr_trap("scriptc: out of memory\n"); + } + uint64_t mixed = scr_key_mix((uint64_t)(uintptr_t)shape ^ ((uint64_t)(uintptr_t)key->data << 1)); + return &scr_js_shared_loads[mixed & (SCR_JS_SHARED_LOADS - 1)]; +} + +/* Whether an absent entry still holds for `receiver`, whose shape matched: + * its own keys lack the key, so the walked prototype (if any) must be the + * same object with the same shape, and the chain must end there. */ +static bool scr_js_absent_hit(const ScrDyn *receiver, const ScrJsIcEntry *entry) { + const ScrDyn *prototype = receiver->prototype; + const ScrDyn *walked = (const ScrDyn *)entry->slot; + if (!walked) return prototype == NULL; + return prototype == walked && walked->kind == SCR_DYN_OBJ && + walked->v.obj.shape == entry->holder_shape && walked->prototype == NULL; +} + +/* A load site's probe. With `absent`, a read of a key that the receiver and + * its chain of plain shaped objects (ending in the default prototype) lack + * answers undefined and caches that answer. Method reads leave absent + * methods to the slow path, which names the missing function. */ +/* The answer of a matching entry for `receiver`, or NULL when the entry no + * longer holds. */ +static ScrDyn *scr_js_entry_answer(ScrDyn *receiver, const ScrJsIcEntry *entry) { + if (entry->target == &scr_js_absent) + return scr_js_absent_hit(receiver, entry) ? scr_dyn_retain(scr_dyn_undefined()) : NULL; + return scr_js_load_hit(receiver, entry); +} + +/* The object an entry's answer depends on besides the receiver: the + * prototype it read from or walked past, or NULL for an own property. */ +static const ScrDyn *scr_js_entry_prototype(const ScrJsIcEntry *entry) { + if (entry->target == &scr_js_absent) return (const ScrDyn *)entry->slot; + return entry->target ? entry->holder : NULL; +} + +/* Records `entry` in the site and, when the site's record is full, in the + * shared slot. A matching entry whose answer failed is replaced when it + * depends on the same prototype (that prototype changed); one that names + * another prototype stays, so receivers of one shape with different + * prototypes each keep an entry. */ +static void scr_js_load_fill(ScrJsIc *ic, uint32_t stale, ScrJsSharedLoad *shared, + const ScrStr *key, ScrJsIcEntry entry) { + if (stale < ic->count && + scr_js_entry_prototype(&ic->entry[stale]) != scr_js_entry_prototype(&entry)) + stale = UINT32_MAX; + if (shared) *shared = (ScrJsSharedLoad){key->data, entry}; + scr_js_ic_add(ic, stale, entry); +} + +/* A load site's probe. With `absent`, a read of a key that the receiver and + * its chain of plain shaped objects (ending in the default prototype) lack + * answers undefined and caches that answer. Method reads leave absent + * methods to the slow path, which names the missing function. */ +static ScrDyn *scr_js_probe_load(ScrDyn *receiver, const ScrStr *key, ScrJsIc *ic, bool absent) { const ScrJsShape *shape = scr_js_shape_of(receiver); if (!shape) return NULL; uint32_t stale = UINT32_MAX; for (uint32_t i = 0; i < ic->count; i++) { if (ic->entry[i].shape != shape) continue; - ScrDyn *value = scr_js_load_hit(receiver, &ic->entry[i]); + ScrDyn *value = scr_js_entry_answer(receiver, &ic->entry[i]); if (value) return value; - stale = i; - break; + if (stale == UINT32_MAX) stale = i; + } + ScrJsSharedLoad *shared = NULL; + if (ic->count == SCR_JS_IC_WAYS) { + shared = scr_js_shared_load(shape, key); + if (shared->key == key->data && shared->entry.shape == shape && + (absent || shared->entry.target != &scr_js_absent)) { + ScrDyn *value = scr_js_entry_answer(receiver, &shared->entry); + if (value) return value; + } } size_t slot = scr_js_shape_find(shape, key->data, key->len); if (slot != SIZE_MAX) { const ScrDynEntry *found = &receiver->v.obj.entries[slot]; if (found->accessor) return NULL; - scr_js_ic_add(ic, stale, (ScrJsIcEntry){shape, NULL, NULL, NULL, slot}); + scr_js_load_fill(ic, stale, shared, key, (ScrJsIcEntry){shape, NULL, NULL, NULL, slot}); return scr_dyn_retain(found->value); } + absent = absent && scr_js_absent_cacheable(key); /* One prototype link: an ordinary object other than the builtin * Object.prototype (whose reads the generic path fences). */ ScrDyn *holder = receiver->prototype; - if (!holder) return NULL; + if (!holder) { + if (!absent) return NULL; + scr_js_load_fill(ic, stale, shared, key, + (ScrJsIcEntry){shape, &scr_js_absent, &scr_js_absent_holder, NULL, 0}); + return scr_dyn_retain(scr_dyn_undefined()); + } const ScrJsShape *holder_shape = scr_js_shape_of(holder); if (!holder_shape) return NULL; slot = scr_js_shape_find(holder_shape, key->data, key->len); - if (slot == SIZE_MAX) return NULL; + if (slot == SIZE_MAX) { + if (!absent || holder->prototype != NULL) return NULL; + scr_js_load_fill(ic, stale, shared, key, + (ScrJsIcEntry){shape, &scr_js_absent, &scr_js_absent_holder, holder_shape, + (size_t)holder}); + return scr_dyn_retain(scr_dyn_undefined()); + } const ScrDynEntry *found = &holder->v.obj.entries[slot]; if (found->accessor) return NULL; - scr_js_ic_add(ic, stale, (ScrJsIcEntry){shape, holder_shape, holder, NULL, slot}); + scr_js_load_fill(ic, stale, shared, key, (ScrJsIcEntry){shape, holder_shape, holder, NULL, slot}); return scr_dyn_retain(found->value); } +ScrDyn *scr_js_load_probe(ScrDyn *receiver, const ScrStr *key, ScrJsIc *ic) { + return scr_js_probe_load(receiver, key, ic, false); +} + +ScrDyn *scr_js_get_probe(ScrDyn *receiver, const ScrStr *key, ScrJsIc *ic) { + return scr_js_probe_load(receiver, key, ic, true); +} + /* ── stores ───────────────────────────────────────────────────────────── */ /* The generic store keeps a native Error's fields in sync with these keys diff --git a/packages/runtime/src/scr_js_object.test.c b/packages/runtime/src/scr_js_object.test.c index 6b6934dea..06b804759 100644 --- a/packages/runtime/src/scr_js_object.test.c +++ b/packages/runtime/src/scr_js_object.test.c @@ -103,8 +103,128 @@ static void immortal_objects_stay_unshaped(void) { scr_str_release(key); } +/* A read site's probe answers a key that the receiver and its plain + * prototype chain lack with undefined, and caches that answer until the + * receiver's keys, its prototype, or the prototype's keys change. */ +static ScrJsIc get_ic; +static ScrJsIc other_ic; + +/* Each site reads one key, so each key below has its own record. */ +static bool get_reads_undefined_at(ScrJsIc *ic, ScrDyn *object, const ScrStr *key) { + ScrDyn *value = scr_js_get_probe(object, key, ic); + if (!value) return false; + assert(value->kind == SCR_DYN_UNDEF); + scr_dyn_release(value); + return true; +} + +static bool get_reads_undefined(ScrDyn *object, const ScrStr *key) { + ScrDyn *value = scr_js_get_probe(object, key, &get_ic); + if (!value) return false; + assert(value->kind == SCR_DYN_UNDEF); + scr_dyn_release(value); + return true; +} + +static bool get_reads(ScrDyn *object, const ScrStr *key, double n) { + ScrDyn *value = scr_js_get_probe(object, key, &get_ic); + if (!value) return false; + assert(value->kind == SCR_DYN_NUM && value->v.num == n); + scr_dyn_release(value); + return true; +} + +static void absent_reads(void) { + ScrStr *own = scr_str_new("own", 3); + ScrStr *missing = scr_str_new("missing", 7); + ScrStr *inherited = scr_str_new("toString", 8); + + /* No prototype: undefined, from the cache the second time. */ + ScrDyn *object = object_with(own, 1); + memset(&get_ic, 0, sizeof get_ic); + assert(get_reads_undefined(object, missing)); + assert(get_ic.count == 1); + assert(get_reads_undefined(object, missing)); + assert(get_ic.count == 1); + /* Method reads and Object.prototype member names keep the slow path. */ + memset(&load_ic, 0, sizeof load_ic); + assert(!scr_js_load_probe(object, missing, &load_ic)); + memset(&other_ic, 0, sizeof other_ic); + assert(!get_reads_undefined_at(&other_ic, object, inherited)); + /* The key added: the same record answers its value. */ + scr_dyn_obj_set(object, missing->data, missing->len, scr_dyn_new_num(2)); + assert(get_reads(object, missing, 2)); + + /* One plain prototype that lacks the key, then gains it. */ + ScrDyn *prototype = object_with(own, 5); + ScrDyn *child = object_with(own, 6); + child->prototype = scr_dyn_retain(prototype); + memset(&get_ic, 0, sizeof get_ic); + assert(get_reads_undefined(child, missing)); + assert(get_reads_undefined(child, missing)); + scr_dyn_obj_set(prototype, missing->data, missing->len, scr_dyn_new_num(3)); + assert(get_reads(child, missing, 3)); + + /* A receiver of the same shape with another prototype that lacks the + * key: both answers stay cached. */ + ScrDyn *other_prototype = object_with(own, 7); + ScrDyn *sibling = object_with(own, 8); + sibling->prototype = scr_dyn_retain(other_prototype); + assert(get_reads_undefined(sibling, missing)); + assert(get_reads(child, missing, 3)); + assert(get_reads_undefined(sibling, missing)); + + /* A longer chain is left to the generic read, even for a receiver whose + * absent answer was cached. */ + ScrDyn *grandparent = object_with(own, 9); + other_prototype->prototype = scr_dyn_retain(grandparent); + assert(!get_reads_undefined(sibling, missing)); + + /* A prototype swapped on a cached receiver: the entry no longer holds. */ + ScrDyn *plain = object_with(own, 10); + memset(&get_ic, 0, sizeof get_ic); + assert(get_reads_undefined(plain, missing)); + plain->prototype = scr_dyn_retain(prototype); + assert(get_reads(plain, missing, 3)); + + /* More shapes than the record holds: the shared cache answers the reads + * that the full record misses, absent keys included. */ + memset(&get_ic, 0, sizeof get_ic); + memset(&other_ic, 0, sizeof other_ic); + ScrDyn *shapes[SCR_JS_IC_WAYS + 3]; + char name[16]; + for (size_t i = 0; i < sizeof shapes / sizeof shapes[0]; i++) { + int n = snprintf(name, sizeof name, "k%zu", i); + shapes[i] = object_with(own, (double)i); + scr_dyn_obj_set(shapes[i], name, (size_t)n, scr_dyn_new_num((double)i)); + } + for (int round = 0; round < 3; round++) + for (size_t i = 0; i < sizeof shapes / sizeof shapes[0]; i++) { + assert(get_reads(shapes[i], own, (double)i)); + assert(get_reads_undefined_at(&other_ic, shapes[i], missing)); + } + for (size_t i = 0; i < sizeof shapes / sizeof shapes[0]; i++) scr_dyn_release(shapes[i]); + + scr_dyn_release(plain); + scr_dyn_release(sibling); + scr_dyn_release(other_prototype); + scr_dyn_release(grandparent); + scr_dyn_release(child); + scr_dyn_release(prototype); + scr_dyn_release(object); + scr_str_release(inherited); + scr_str_release(missing); + scr_str_release(own); +} + int main(int argc, char **argv) { scr_init(); + /* Shapes count against the budget, so these checks run on their own. */ + if (argc > 1 && strcmp(argv[1], "absent") == 0) { + absent_reads(); + puts("absent read checks passed"); + return 0; + } immortal_objects_stay_unshaped(); if (argc > 1 && strcmp(argv[1], "key-bytes") == 0) { /* 64 KiB keys spend the key-byte budget after 64 shapes. */ diff --git a/packages/runtime/src/scr_js_object.test.ts b/packages/runtime/src/scr_js_object.test.ts index 0a5aa1d5b..1fb90cdaa 100644 --- a/packages/runtime/src/scr_js_object.test.ts +++ b/packages/runtime/src/scr_js_object.test.ts @@ -7,7 +7,7 @@ import { expect, test } from "vitest"; const exec = promisify(execFile); -test("dynamic-tier shapes stay within the shape and key-byte budgets", async () => { +test("dynamic-tier shapes stay within the shape and key-byte budgets, and absent reads are cached", async () => { const scratch = await mkdtemp(join(tmpdir(), "scriptc-js-object-")); const src = import.meta.dirname; const binary = join(scratch, "js-object"); @@ -50,15 +50,19 @@ test("dynamic-tier shapes stay within the shape and key-byte budgets", async () ].map((file) => join(src, file)), ...(process.platform === "linux" ? ["-D_GNU_SOURCE", "-lm"] : []), ]); - for (const args of [[], ["key-bytes"]]) { - const result = await exec(binary, args, { + for (const [args, stdout] of [ + [[], "shape budget checks passed\n"], + [["key-bytes"], "shape budget checks passed\n"], + [["absent"], "absent read checks passed\n"], + ] as const) { + const result = await exec(binary, [...args], { env: { ...process.env, ASAN_OPTIONS: "detect_leaks=0:halt_on_error=1", UBSAN_OPTIONS: "halt_on_error=1", }, }); - expect(result.stdout).toBe("shape budget checks passed\n"); + expect(result.stdout).toBe(stdout); expect(result.stderr).toBe(""); } } finally { diff --git a/tests/corpus/absent-property-reads.mjs b/tests/corpus/absent-property-reads.mjs new file mode 100644 index 000000000..cd568b11c --- /dev/null +++ b/tests/corpus/absent-property-reads.mjs @@ -0,0 +1,87 @@ +// Reads of properties an object lacks, from the same untyped sites many +// times: they answer undefined until the object, its prototype, or the +// prototype link changes, and Object.prototype members still answer. +function read(object) { + return object.flag; +} +function readName(object) { + return object.name; +} +function describe(object) { + return [object.toString === Object.prototype.toString, typeof object.constructor, typeof object.hasOwnProperty].join(); +} +function callIt(object) { + try { + return object.run(); + } catch (e) { + return `${e.name}: ${e.message}`; + } +} + +const seen = []; +const plain = { name: "plain" }; +for (let i = 0; i < 3; i++) seen.push(read(plain)); +plain.flag = "added"; +seen.push(read(plain)); +delete plain.flag; +seen.push(read(plain)); +console.log(seen.join()); + +// A prototype that gains, changes and loses the key. +const base = { kind: "base" }; +const child = Object.create(base); +child.name = "child"; +const fromProto = []; +for (let i = 0; i < 3; i++) fromProto.push(read(child)); +base.flag = "inherited"; +fromProto.push(read(child)); +base.flag = "changed"; +fromProto.push(read(child)); +delete base.flag; +fromProto.push(read(child)); +console.log(fromProto.join()); + +// Objects of one shape with different prototypes, read from one site. +const left = Object.create({ flag: "left" }); +const right = Object.create({ other: 1 }); +left.name = "l"; +right.name = "r"; +const mixed = []; +for (let i = 0; i < 3; i++) mixed.push(read(left), read(right)); +console.log(mixed.join()); + +// Changing the prototype link of an object whose absent read was cached. +const moved = { name: "moved" }; +for (let i = 0; i < 3; i++) read(moved); +Object.setPrototypeOf(moved, { flag: "after setPrototypeOf" }); +console.log(read(moved)); +Object.setPrototypeOf(moved, null); +console.log(read(moved), readName(moved)); + +// A longer prototype chain. +const grand = { flag: "grand" }; +const parent = Object.create(grand); +const deep = Object.create(parent); +console.log(read(deep), read(Object.create(Object.create({})))); + +// Object.prototype members and missing methods still answer as in Node. +const bare = { name: "bare" }; +for (let i = 0; i < 3; i++) describe(bare); +console.log(describe(bare), describe({ other: 2 })); +for (let i = 0; i < 3; i++) callIt(bare); +console.log(callIt(bare)); +bare.run = () => "ran"; +console.log(callIt(bare)); + +// Many shapes through one site. +const shapes = []; +for (let i = 0; i < 12; i++) { + const object = { name: `s${i}` }; + object[`k${i}`] = i; + if (i % 3 === 0) object.flag = i; + shapes.push(object); +} +let total = 0; +for (let round = 0; round < 4; round++) + for (const object of shapes) total += read(object) === undefined ? 1 : 100; +console.log(total, shapes.map(readName).join()); diff --git a/tests/harness/corpus-costs/absent-property-reads.mjs.json b/tests/harness/corpus-costs/absent-property-reads.mjs.json new file mode 100644 index 000000000..a9e46230d --- /dev/null +++ b/tests/harness/corpus-costs/absent-property-reads.mjs.json @@ -0,0 +1 @@ +{ "plain": 8432, "san": 13661 } From 944cae84a8b4cc4c2f7b0af2af0dcf8793e72591 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 00:06:13 -0500 Subject: [PATCH 213/259] Keep an unchanged executable without selecting the runtime pack An unchanged rebuild that kept its output still selected the runtime pack's artifacts first, reading the stored selection, and computed the identity of every selected artifact to open the executable cache. - The executable cache key names the pack by its package.json text, the manifest's identity (its text on darwin), and the link features and flavor. Together they fix which artifacts the selection names. - The cache selects the artifacts only when it needs their identities, in restore() and trace(). keep() checks the recorded entry, which lists them. - A build that does not keep or restore its executable selects the pack before code generation, as before. --- packages/compiler/src/native/compiler.ts | 46 ++++++------- .../src/native/executable-cache-open.test.ts | 21 ++++-- .../src/native/executable-cache.test.ts | 31 +++++++++ .../compiler/src/native/executable-cache.ts | 67 ++++++++++++++++--- 4 files changed, 125 insertions(+), 40 deletions(-) diff --git a/packages/compiler/src/native/compiler.ts b/packages/compiler/src/native/compiler.ts index e919090a9..64964d94f 100644 --- a/packages/compiler/src/native/compiler.ts +++ b/packages/compiler/src/native/compiler.ts @@ -30,6 +30,7 @@ import { verifyNativeHelper, } from "../backend/native-tools.js"; import { + type NativeRuntimeSelection, selectNativeRuntimePack, runtimePackManifest, stageNativeRuntimeSelection, @@ -400,34 +401,33 @@ export class NativeCompiler { outputKind === "exe" ? join(inputDirectory, "program" + target.outputSuffixes.obj) : stagedOutput; - const executablePack = - outputKind === "exe" - ? selectNativeRuntimePack( - toolchain.runtimePackRoot, - target, - toolchain.compilerVersion, - features, - optimization, - "executable", - this.runtimePackStore(), - ) - : null; + let executablePack: NativeRuntimeSelection | null = null; + const selectPack = (): NativeRuntimeSelection => + (executablePack ??= selectNativeRuntimePack( + toolchain.runtimePackRoot, + target, + toolchain.compilerVersion, + features, + optimization, + "executable", + this.runtimePackStore(), + )); const executableCache = - executablePack === null - ? null - : openNativeExecutableCache( - this.cache, - toolchain, - digestLlvm, - options, - ffi, - executablePack, - ); + outputKind === "exe" + ? openNativeExecutableCache(this.cache, toolchain, digestLlvm, options, ffi, { + root: toolchain.runtimePackRoot, + features, + flavor: optimization, + select: selectPack, + }) + : null; // An unchanged rebuild keeps the executable the last build left. const kept = executableCache?.keep(output) ?? false; const restored = kept || (executableCache?.restore(stagedOutput) ?? false); timing(restored ? "executable-cache-hit" : "executable-cache-miss"); if (!restored) { + // A missing or invalid runtime pack fails before code generation. + if (outputKind === "exe") selectPack(); let programObjects = [object]; if (options.sanitize) { runNativeTool(sanitizerDriver(toolchain), [ @@ -496,7 +496,7 @@ export class NativeCompiler { }, }; } - const pack = executablePack!; + const pack = selectPack(); const runtime = options.sanitize ? buildSanitizedRuntime(toolchain, pack, join(stage, "runtime"), "executable", this.cache) : stageNativeRuntimeSelection(pack, join(stage, "runtime"), this.runtimePackStore()); diff --git a/packages/compiler/src/native/executable-cache-open.test.ts b/packages/compiler/src/native/executable-cache-open.test.ts index 09a8b9cc9..0c3b2832f 100644 --- a/packages/compiler/src/native/executable-cache-open.test.ts +++ b/packages/compiler/src/native/executable-cache-open.test.ts @@ -2,9 +2,10 @@ import { chmodSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:f import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterEach, beforeEach, expect, test } from "vitest"; +import type { NativeLinkFeatures } from "../backend/native-link-info.js"; import type { NativeRuntimeSelection } from "../backend/runtime-pack-native.js"; import { NativeCache } from "./cache.js"; -import { openNativeExecutableCache } from "./executable-cache.js"; +import { type ExecutableRuntimePack, openNativeExecutableCache } from "./executable-cache.js"; import type { NativeToolchain } from "./toolchain.js"; const directories: string[] = []; @@ -50,14 +51,20 @@ function fixture(platform: string, driver: string) { linkerArgs: [], dsymutil: "dsymutil", } as unknown as NativeToolchain; - const pack = { + const pack: ExecutableRuntimePack = { root: runtime, - licenses: [], - packageText: "{}", - manifestText: "{}", - selected: { runtime: [], archives: [] }, + features: {} as NativeLinkFeatures, flavor: "release", - } as unknown as NativeRuntimeSelection; + select: () => + ({ + root: runtime, + licenses: [], + packageText: "{}", + manifestText: "{}", + selected: { runtime: [], archives: [] }, + flavor: "release", + }) as unknown as NativeRuntimeSelection, + }; const open = () => openNativeExecutableCache( new NativeCache(join(root, "cache")), diff --git a/packages/compiler/src/native/executable-cache.test.ts b/packages/compiler/src/native/executable-cache.test.ts index 97f9a3571..8bec9916e 100644 --- a/packages/compiler/src/native/executable-cache.test.ts +++ b/packages/compiler/src/native/executable-cache.test.ts @@ -300,3 +300,34 @@ test("a Linux build whose output changed links again, and then stores the execut expect(open().restore(f.destination)).toBe(true); expect(readFileSync(f.destination)).toEqual(readFileSync(f.output)); }); + +test("a Linux build that keeps its output does not read the deferred inputs", () => { + const f = fixture(); + const artifact = join(f.root, "inputs", "artifact.o"); + writeFileSync(artifact, "runtime pack artifact"); + const deferred = vi.fn(() => [artifact]); + const open = () => + new NativeExecutableCache(f.cache, f.key, "clang", false, [f.runtime], true, deferred); + const first = open(); + expect(first.trace(["-o", f.output], f.stage)).toBe(true); + first.recordOutput(f.output); + expect(deferred).toHaveBeenCalledTimes(1); + const recorded = ( + JSON.parse(f.cache.read("kept", f.key)!.toString()) as { inputs: { path: string }[] } + ).inputs.map((saved) => saved.path); + expect(recorded).toContain(artifact); + // The unchanged rebuild checks the recorded identities, the artifact's + // among them, without asking for the deferred inputs. + expect(open().keep(f.output)).toBe(true); + expect(deferred).toHaveBeenCalledTimes(1); + // A replaced artifact misses. + writeFileSync(artifact, "another runtime pack artifact"); + expect(open().keep(f.output)).toBe(false); + expect(deferred).toHaveBeenCalledTimes(1); + // restore() adds the deferred inputs before it checks an entry. + const second = open(); + expect(second.trace(["-o", f.output], f.stage)).toBe(true); + second.publish(f.output); + expect(open().restore(f.destination)).toBe(true); + expect(deferred).toHaveBeenCalledTimes(3); +}); diff --git a/packages/compiler/src/native/executable-cache.ts b/packages/compiler/src/native/executable-cache.ts index 0ce638d54..bafd2c020 100644 --- a/packages/compiler/src/native/executable-cache.ts +++ b/packages/compiler/src/native/executable-cache.ts @@ -9,6 +9,8 @@ import { toolchainEnvironmentFingerprint, } from "../backend/toolchain-environment.js"; import { runNativeTool } from "../backend/native-tools.js"; +import type { NativeLinkFeatures } from "../backend/native-link-info.js"; +import type { NativeOptimization } from "../backend/optimization.js"; import type { NativeRuntimeSelection } from "../backend/runtime-pack-native.js"; import type { NativeToolchain } from "./toolchain.js"; import { contentDigest, NativeCache } from "./cache.js"; @@ -204,6 +206,7 @@ export class NativeExecutableCache { private traced = false; /** The inputs of the entry restore() used. */ private restoredInputs: InputIdentity[] | null = null; + private deferredAdded = false; constructor( private readonly cache: NativeCache, @@ -214,10 +217,25 @@ export class NativeExecutableCache { /** Linux: trace with one verbose link, keep an unchanged output, and * store the executable from a key's second link on. */ private readonly linux = false, + /** Inputs that the key determines, such as the runtime pack's selected + * artifacts. keep() does not read them, because the entry it checks + * lists them; restore() and trace() add their identities first. */ + private readonly deferredPaths: () => string[] = () => [], ) { this.inputs = [...new Set(paths)].sort().map(identity); } + private addDeferredInputs(): void { + if (this.deferredAdded) return; + this.deferredAdded = true; + const listed = new Set(this.inputs.map((input) => input.path)); + for (const path of this.deferredPaths()) + if (!listed.has(path)) { + listed.add(path); + this.inputs.push(identity(path)); + } + } + /** Whether `recorded`, the inputs of an entry, still match and cover this * build's inputs. */ private covers(recorded: InputIdentity[]): boolean { @@ -249,6 +267,7 @@ export class NativeExecutableCache { try { const metadata = this.cache.read("executable", this.key); if (metadata === null) return false; + this.addDeferredInputs(); const entry: unknown = JSON.parse(metadata.toString("utf8")); if (!validEntry(entry) || !this.covers(entry.inputs)) return false; if (this.debug !== (entry.symbols !== null)) return false; @@ -275,6 +294,7 @@ export class NativeExecutableCache { trace(args: string[], stage: string): boolean { this.traced = false; try { + this.addDeferredInputs(); const roots = [resolve(stage), realpathSync(stage)]; let driverInputs = this.linux ? [] @@ -342,13 +362,24 @@ export class NativeExecutableCache { } } +/** The runtime pack an executable links: its directory, and the link features + * and flavor that select its artifacts. `select` reads and validates the + * manifest; the cache calls it only when it needs the artifacts' identities, + * so an unchanged rebuild that keeps its output never reads the manifest. */ +export interface ExecutableRuntimePack { + root: string; + features: NativeLinkFeatures; + flavor: NativeOptimization; + select: () => NativeRuntimeSelection; +} + export function openNativeExecutableCache( cache: NativeCache | null, toolchain: NativeToolchain, llvmDigest: () => string, options: CompileRequestOptions, ffi: FfiProfile | null, - pack: NativeRuntimeSelection, + pack: ExecutableRuntimePack, ): NativeExecutableCache | null { // Match the established complete-cache contract: the default Apple driver // or a Linux clang driver, known runtime inputs, and no wrapper or @@ -394,11 +425,19 @@ export function openNativeExecutableCache( join(toolchain.helperPackageRoot, "package.json"), join(toolchain.runtimePackRoot, "package.json"), join(toolchain.runtimePackRoot, "runtime-pack.json"), - ...[...pack.selected.runtime, ...pack.selected.archives, ...pack.licenses].map((artifact) => - join(pack.root, artifact.path), - ), ]; - if (platform === "linux") paths.push(join(pack.root, "runtime-pack.json")); + const manifest = join(pack.root, "runtime-pack.json"); + if (platform === "linux") paths.push(manifest); + // The manifest's identity, the features and the flavor in the key fix + // which artifacts the selection names. + const artifacts = (): string[] => { + const selection = pack.select(); + return [ + ...selection.selected.runtime, + ...selection.selected.archives, + ...selection.licenses, + ].map((artifact) => join(selection.root, artifact.path)); + }; if (debug) { const dsymutil = commandPath(toolchain.dsymutil); if (realpathSync(dsymutil) !== "/usr/bin/dsymutil") return null; @@ -410,13 +449,13 @@ export function openNativeExecutableCache( llvm: llvmDigest(), options, toolchain, - runtimeIdentity: pack.packageText, + runtimeIdentity: readFileSync(join(pack.root, "package.json"), "utf8"), // On Linux the manifest's identity names it: restore checks that // identity again, as it does every other input. runtimeManifest: - platform === "darwin" - ? pack.manifestText - : identity(join(pack.root, "runtime-pack.json")), + platform === "darwin" ? readFileSync(manifest, "utf8") : identity(manifest), + runtimeFeatures: pack.features, + runtimeFlavor: pack.flavor, linker: identity(linker), effective: identity(effective), environment: toolchainEnvironmentFingerprint(), @@ -424,7 +463,15 @@ export function openNativeExecutableCache( path: process.env["PATH"] ?? null, }), ); - return new NativeExecutableCache(cache, key, linker, debug, paths, platform === "linux"); + return new NativeExecutableCache( + cache, + key, + linker, + debug, + paths, + platform === "linux", + artifacts, + ); } catch { return null; } From be7fb3723568a2631d8788f2cbef9dd9dda171d7 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 00:16:42 -0500 Subject: [PATCH 214/259] Expect the get probe at the native-array length site in the emission test The length read in the keyed and length emission test is a get site, which now calls scr_js_get_probe. --- packages/compiler/test/js-ic-emission.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/compiler/test/js-ic-emission.test.ts b/packages/compiler/test/js-ic-emission.test.ts index 437ac34e4..15e8e92bc 100644 --- a/packages/compiler/test/js-ic-emission.test.ts +++ b/packages/compiler/test/js-ic-emission.test.ts @@ -170,7 +170,7 @@ console.log(lib.total([1, 2, 3])); expect(fn).toContain("@scr_js_keyed_probe("); // The length read answers from the native array's length. expect(fn).toContain("icg.rest"); - expect(fn).toContain("@scr_js_load_probe("); + expect(fn).toContain("@scr_js_get_probe("); } finally { await rm(dir, { recursive: true, force: true }); } From 478feb15cd860605215de22605ec4ee299bef182 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 00:26:55 -0500 Subject: [PATCH 215/259] Call the declared base method for super calls in JavaScript method values Since 76735a8d9 (#1975), a `super.m()` call in a JavaScript class method whose `this` is the call-site receiver reflected the base class's whole prototype and read `m` from it. An instance's member lookup first tests its property bag, which inherits from its class's prototype data, so once the base's prototype was reflected, `child[k]` for a method the subclass overrides found the base's method there: `value[name](arg)` on a subclass instance called the base method. While no code reads a prototype method by name, `super.m()` now calls the declaring class's receiver-independent method value with the receiver, as the method's [[HomeObject]] lookup answers, without reflecting the base prototype. Programs that read prototype methods by name keep the reflected lookup. --- .../src/frontend/lowering/lower-classes.ts | 37 +++++++++++++------ .../main.ts.json | 7 ++++ .../8302-class-super-method-values/lib.cjs | 33 +++++++++++++++++ .../8302-class-super-method-values/main.ts | 26 +++++++++++++ .../package.json | 1 + .../main.ts.json | 1 + 6 files changed, 94 insertions(+), 11 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8302-class-super-method-values/main.ts.json create mode 100644 tests/corpus/8302-class-super-method-values/lib.cjs create mode 100644 tests/corpus/8302-class-super-method-values/main.ts create mode 100644 tests/corpus/8302-class-super-method-values/package.json create mode 100644 tests/harness/corpus-costs/8302-class-super-method-values/main.ts.json diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index 333e11ff8..b125734f7 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -194,7 +194,10 @@ import { classPrototypeData, reflectClassPrototype } from "./class-prototypes.js import { constructionEscape } from "./construction-escapes.js"; import { checkedClassConstruction, checkedClassConstructionPacked } from "./class-construction.js"; import { initializeRuntimeStatics, hasRuntimeStatics } from "./class-runtime-statics.js"; -import { reflectedClassStaticMethodValue } from "./class-method-values.js"; +import { + reflectedClassMethodValue, + reflectedClassStaticMethodValue, +} from "./class-method-values.js"; import { identifierReadSymbol } from "./surfaces.js"; export function returnsOnlyThis(member: ts.MethodDeclaration): boolean { @@ -9560,19 +9563,31 @@ export function lowerSuperMethodCall( // method up on the base class's complete prototype, as `super` reads // [[HomeObject]].[[Prototype]], and calls it with that receiver. const dynamicThis = thisRef.type.kind === "dyn"; + // While no code reads a prototype method by name (which could replace it), + // that method is the declaring class's own: its receiver-independent value + // is called directly. Reflecting the base's whole prototype instead would + // put its members on the prototype chain of every subclass instance's + // property bag, ahead of the subclasses' own compiled overrides. + const declared = + dynamicThis && !lowerer.prototypeMethodAccesses.has(access.name.text) + ? reflectedClassMethodValue(lowerer, found.declarer, access.name.text) + : null; if (dynamicThis || lowerer.prototypeMethodAccesses.has(access.name.text)) { - const prototype = - dynamicThis && cls.base.decl + const prototype = declared + ? null + : dynamicThis && cls.base.decl ? reflectClassPrototype(lowerer, cls.base, loc, classValueRef(lowerer, cls.base, access)) : classPrototypeData(lowerer, cls.base, loc); - if (prototype) { - const callee: IrExpr = { - kind: "dynKeyGet", - value: prototype, - key: { kind: "strLit", value: access.name.text, type: STRING, loc }, - type: DYN, - loc, - }; + if (declared || prototype) { + const callee: IrExpr = declared + ? lowerer.coerceToExpected(declared, DYN) + : { + kind: "dynKeyGet", + value: prototype!, + key: { kind: "strLit", value: access.name.text, type: STRING, loc }, + type: DYN, + loc, + }; // Spread arguments are spread into the dynamic call, as in a dynamic method call. const spreads: { arg: number; what: string }[] = []; const args = call.arguments.nodes.map((arg, index) => { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8302-class-super-method-values/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8302-class-super-method-values/main.ts.json new file mode 100644 index 000000000..24fe2decc --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8302-class-super-method-values/main.ts.json @@ -0,0 +1,7 @@ +{ + "order": [ + "/tests/corpus/8302-class-super-method-values/lib.cjs", + "/tests/corpus/8302-class-super-method-values/main.ts" + ], + "diags": [] +} diff --git a/tests/corpus/8302-class-super-method-values/lib.cjs b/tests/corpus/8302-class-super-method-values/lib.cjs new file mode 100644 index 000000000..4a8b1640a --- /dev/null +++ b/tests/corpus/8302-class-super-method-values/lib.cjs @@ -0,0 +1,33 @@ +"use strict"; +// Subclasses whose methods call super, read and called through computed and +// literal keys, as values called with call(), and directly. +class Base { + constructor(n) { this.n = n; } + scale(k) { return this.n * k; } + label() { return "base:" + this.n; } + plain(k) { return k; } +} +class Child extends Base { + scale(k) { return super.scale(k) * 10; } + label() { return "child(" + super.label() + ")"; } + plain(k) { return k * 100; } +} +class Grandchild extends Child { + scale(k) { return super.scale(k) + 1; } +} +class Sibling extends Base { + scale(k) { return -k; } + plain(k) { return super.plain(k) + 0.5; } +} +exports.make = function (i) { + switch (i % 4) { + case 0: return new Base(i); + case 1: return new Child(i); + case 2: return new Grandchild(i); + default: return new Sibling(i); + } +}; +exports.computed = function (value, name, arg) { return value[name](arg); }; +exports.viaCall = function (value, name, arg) { const f = value[name]; return f.call(value, arg); }; +exports.literal = function (value, arg) { return [value["scale"](arg), value["plain"](arg), value["label"]()].join(" "); }; +exports.direct = function (value, arg) { return [value.scale(arg), value.plain(arg), value.label()].join(" "); }; diff --git a/tests/corpus/8302-class-super-method-values/main.ts b/tests/corpus/8302-class-super-method-values/main.ts new file mode 100644 index 000000000..1a7edbb49 --- /dev/null +++ b/tests/corpus/8302-class-super-method-values/main.ts @@ -0,0 +1,26 @@ +// Methods of JavaScript subclasses that call super, read from instances +// through computed keys, literal keys and as values, and called directly. +import { createRequire } from "node:module"; + +interface Lib { + make(i: number): unknown; + computed(value: unknown, name: string, arg: number): unknown; + viaCall(value: unknown, name: string, arg: number): unknown; + literal(value: unknown, arg: number): string; + direct(value: unknown, arg: number): string; +} +const require = createRequire(import.meta.url); +const lib: Lib = require("./lib.cjs"); + +for (let i = 0; i < 8; i++) { + const value = lib.make(i); + console.log( + i, + lib.computed(value, "scale", 3), + lib.computed(value, "plain", 3), + lib.computed(value, "label", 0), + lib.viaCall(value, "scale", 2), + lib.viaCall(value, "label", 0), + ); + console.log(i, lib.literal(value, 5), "|", lib.direct(value, 5)); +} diff --git a/tests/corpus/8302-class-super-method-values/package.json b/tests/corpus/8302-class-super-method-values/package.json new file mode 100644 index 000000000..5ffd9800b --- /dev/null +++ b/tests/corpus/8302-class-super-method-values/package.json @@ -0,0 +1 @@ +{ "type": "module" } diff --git a/tests/harness/corpus-costs/8302-class-super-method-values/main.ts.json b/tests/harness/corpus-costs/8302-class-super-method-values/main.ts.json new file mode 100644 index 000000000..30437efb4 --- /dev/null +++ b/tests/harness/corpus-costs/8302-class-super-method-values/main.ts.json @@ -0,0 +1 @@ +{ "plain": 4797 } From e5ba0734680922fe58128355f71582515d12467f Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 00:44:25 -0500 Subject: [PATCH 216/259] Parse JSON into discriminated unions in one pass `JSON.parse(text) as T` for a discriminated union of records took the checked-dynamic route: it parsed the text into a dynamic tree, matched and copied that tree into records, then freed it. The one-pass schema parser now builds these unions directly, as record members, array elements and whole documents. For an object, a shallow scan of its members finds the discriminant's value, which selects the one record arm that holds that literal, and the object is parsed with that arm's schema. An object with a missing, non-string or unknown discriminant, or any member the arm rejects, declines, and the checked route then gives the result or the error as before. The compiler admits unions whose record arms each name their string literals, every literal naming one arm, plus null and undefined arms. --- packages/compiler/src/backend/llvm/dyn.ts | 86 ++++++++++-- .../test/json-schema-parse-emission.test.ts | 58 +++++++- ...43-json-parse-discriminated-unions.ts.json | 6 + packages/runtime/src/scr_json.c | 129 ++++++++++++++++-- packages/runtime/src/scr_json.h | 32 ++++- .../8243-json-parse-discriminated-unions.ts | 119 ++++++++++++++++ 6 files changed, 396 insertions(+), 34 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8243-json-parse-discriminated-unions.ts.json create mode 100644 tests/corpus/8243-json-parse-discriminated-unions.ts diff --git a/packages/compiler/src/backend/llvm/dyn.ts b/packages/compiler/src/backend/llvm/dyn.ts index 9a91db0ca..54ce1bece 100644 --- a/packages/compiler/src/backend/llvm/dyn.ts +++ b/packages/compiler/src/backend/llvm/dyn.ts @@ -1480,8 +1480,9 @@ export class LlDyn { * fields, and at least one unless an index signature collects the * members), record members typed as unions of those leaves, records and * arrays, null and undefined (optional and nullable members; see - * jsonUnionSupported), and index signatures whose value type is not a - * union. Everything else keeps the checked-dynamic route alone. */ + * jsonUnionSupported), discriminated unions of records anywhere (see + * jsonDiscriminatedSupported), and index signatures whose value type is + * not a union. Everything else keeps the checked-dynamic route alone. */ private jsonSchemaSupported(t: IrType, visiting: Set, member = false): boolean { switch (t.kind) { case "f64": @@ -1508,13 +1509,42 @@ export class LlDyn { (!index || this.jsonSchemaSupported(index, visiting)) ); } - case "union": + case "union": { + const def = this.host.unionsById.get(t.unionId); + if (def?.discriminant) return this.jsonDiscriminatedSupported(def, visiting); return member && this.jsonUnionSupported(t, visiting); + } default: return false; } } + /** A discriminated union the one-pass parser writes directly, as a record + * member, an array element or the whole document: record arms that each + * name the string literals their discriminant member holds, every + * literal naming one arm, plus null and undefined arms. An object then + * selects the one arm whose literal its discriminant member holds, the + * only arm the checked route's literal tests leave to match + * (unionArmsByDiscriminant); an object holding no such literal declines. */ + private jsonDiscriminatedSupported(def: IrUnionDef, visiting: Set): boolean { + const discriminant = def.discriminant!; + const literals = new Set(); + let records = 0; + const supported = def.arms.every((arm, tag) => { + if (arm.kind === "nullT" || arm.kind === "undefinedT") return true; + if (arm.kind !== "record") return false; + records++; + const guard = discriminant.cases.find((candidate) => candidate.tag === tag); + if (!guard || guard.values.length === 0) return false; + for (const value of guard.values) { + if (typeof value !== "string" || literals.has(value)) return false; + literals.add(value); + } + return this.jsonSchemaSupported(arm, visiting); + }); + return supported && records >= 2; + } + /** A union record member the one-pass parser writes directly: every arm * a number, boolean, string, null, undefined, or a supported record or * array, with at most one record and one array arm and no discriminant. @@ -1619,9 +1649,15 @@ export class LlDyn { body = `${S} 3, ${S} ${entries.length}, ptr ${fields}, ptr ${overflow.elem}, ptr @${mangleRecordNew(t.shapeId)}, ptr null, ptr ${vAdapters(host, t).release}, ptr null, ${S} ${overflow.offset}`; break; } - case "union": - body = `${S} 5, ${S} 0, ptr null, ptr null, ptr null, ptr null, ptr null, ptr @${this.jsonUnionSchema(t, name)}, ${S} 0`; + case "union": { + // A discriminated union can be a whole document, whose value the + // parser releases when text follows it. + const release = host.unionsById.get(t.unionId)?.discriminant + ? vAdapters(host, t).release + : "null"; + body = `${S} 5, ${S} 0, ptr null, ptr null, ptr null, ptr null, ptr ${release}, ptr @${this.jsonUnionSchema(t, name)}, ${S} 0`; break; + } default: throw new InternalCompilerError(`llvm emitter bug: JSON schema of ${t.kind}`); } @@ -1636,7 +1672,11 @@ export class LlDyn { /** The ScrJsonUnion descriptor of a union member (scr_json.h layout): * its slot representation, the arm each JSON value kind selects, and the * values the runtime stores for null and for a missing member. Boxed - * unions build their boxes through `_box`. */ + * unions build their boxes through `_box`. A discriminated union + * also lists its object arms by discriminant literal (`_cases`), + * and, because it can be an array element or a whole document, whose + * values are boxes unless the union is a pointer union, it keeps its null + * value and box whatever its field representation. */ private jsonUnionSchema(t: IrType & { kind: "union" }, name: string): string { const host = this.host; const S = host.sizeType; @@ -1655,10 +1695,11 @@ export class LlDyn { ); const nullTag = tags[0]!; const absentTag = tags[6]!; - const nullValue = !inline && nullTag >= 0 ? host.unitInstanceRef(t.unionId, nullTag) : "null"; - const absentValue = !inline && absentTag >= 0 ? host.absentInstanceRef(t.unionId) : "null"; + const values = !inline || def.discriminant !== undefined; + const nullValue = values && nullTag >= 0 ? host.unitInstanceRef(t.unionId, nullTag) : "null"; + const absentValue = values && absentTag >= 0 ? host.absentInstanceRef(t.unionId) : "null"; let box = "null"; - if (repr === 2) { + if (repr === 2 || (def.discriminant && !nullable)) { box = `@${name}_box`; const lines = [`define internal ptr ${box}(i32 %tag, i64 %bits) ${FN_ATTRS} {`, `entry:`]; const cases: string[] = []; @@ -1699,9 +1740,27 @@ export class LlDyn { ``, ); } + let cases = "null"; + if (def.discriminant) { + const discriminant = def.discriminant; + const caseTy = `{ ptr, ${S}, ${S}, ptr }`; + const entries = discriminant.cases.flatMap((guard) => + guard.values.map( + (value) => + `${caseTy} { ptr ${host.cstr(String(value))}, ${S} ${Buffer.byteLength(String(value), "utf8")}, ${S} ${guard.tag}, ptr @${this.jsonSchema(def.arms[guard.tag]!)} }`, + ), + ); + const table = `@${name}_case_table`; + cases = `@${name}_cases`; + this.defs.push( + `${table} = internal constant [${entries.length} x ${caseTy}] [${entries.join(", ")}]`, + `${cases} = internal constant { ptr, ${S}, ${S}, ptr } { ptr ${host.cstr(discriminant.field)}, ${S} ${Buffer.byteLength(discriminant.field, "utf8")}, ${S} ${entries.length}, ptr ${table} }`, + ``, + ); + } const descriptor = `${name}_union`; this.defs.push( - `@${descriptor} = internal constant { ${S}, [7 x ${S}], [7 x ptr], ptr, ptr, ptr } { ${S} ${repr}, [7 x ${S}] [${tags.map((tag) => `${S} ${tag}`).join(", ")}], [7 x ptr] [${arms.join(", ")}], ptr ${nullValue}, ptr ${absentValue}, ptr ${box} }`, + `@${descriptor} = internal constant { ${S}, [7 x ${S}], [7 x ptr], ptr, ptr, ptr, ptr } { ${S} ${repr}, [7 x ${S}] [${tags.map((tag) => `${S} ${tag}`).join(", ")}], [7 x ptr] [${arms.join(", ")}], ptr ${nullValue}, ptr ${absentValue}, ptr ${box}, ptr ${cases} }`, ``, ); return descriptor; @@ -1751,7 +1810,12 @@ export class LlDyn { * dynCheck builder — which reports the exact error. Returns +1, or null * with the pending flag set. */ jsonParseHelper(t: IrType): string | null { - if (t.kind !== "record" && t.kind !== "array") return null; + if ( + t.kind !== "record" && + t.kind !== "array" && + !(t.kind === "union" && this.host.unionsById.get(t.unionId)?.discriminant) + ) + return null; const key = typeKey(t); const existing = this.jsonParsers.get(key); if (existing) return existing; diff --git a/packages/compiler/test/json-schema-parse-emission.test.ts b/packages/compiler/test/json-schema-parse-emission.test.ts index b96c9a032..dd6bf52ae 100644 --- a/packages/compiler/test/json-schema-parse-emission.test.ts +++ b/packages/compiler/test/json-schema-parse-emission.test.ts @@ -58,13 +58,13 @@ console.log(orders.length, typed.sku, loose.name, mixed.length, pair[0], either. // record pointer (0), the inline scalar pair (1), and a tagged box built // through the schema's box function (2), with arm tags by JSON kind. expect(llvm).toMatch( - /@sc_jsch_\d+_union = internal constant \{ i64, \[7 x i64\], \[7 x ptr\], ptr, ptr, ptr \} \{ i64 0, /, + /@sc_jsch_\d+_union = internal constant \{ i64, \[7 x i64\], \[7 x ptr\], ptr, ptr, ptr, ptr \} \{ i64 0, /, ); expect(llvm).toMatch( - /@sc_jsch_\d+_union = internal constant \{ i64, \[7 x i64\], \[7 x ptr\], ptr, ptr, ptr \} \{ i64 1, /, + /@sc_jsch_\d+_union = internal constant \{ i64, \[7 x i64\], \[7 x ptr\], ptr, ptr, ptr, ptr \} \{ i64 1, /, ); expect(llvm).toMatch( - /@sc_jsch_\d+_union = internal constant \{ i64, \[7 x i64\], \[7 x ptr\], ptr, ptr, ptr \} \{ i64 2, .*ptr @sc_jsch_\d+_box \}/, + /@sc_jsch_\d+_union = internal constant \{ i64, \[7 x i64\], \[7 x ptr\], ptr, ptr, ptr, ptr \} \{ i64 2, .*ptr @sc_jsch_\d+_box, ptr null \}/, ); expect(llvm).toMatch(/^define internal ptr @sc_jsch_\d+_box\(i32 %tag, i64 %bits\)/m); // A pure dictionary has no declared fields: its index value schema and @@ -78,9 +78,59 @@ console.log(orders.length, typed.sku, loose.name, mixed.length, pair[0], either. const wasm = emitLlvmModule(mod, { pointerBits: 32, wasi: true }); expect(wasm).toContain("= internal constant { i32, i32, ptr, ptr, ptr, ptr, ptr, ptr, i32 }"); - expect(wasm).toContain("= internal constant { i32, [7 x i32], [7 x ptr], ptr, ptr, ptr }"); + expect(wasm).toContain("= internal constant { i32, [7 x i32], [7 x ptr], ptr, ptr, ptr, ptr }"); expect(wasm).toMatch(/\{ ptr, i32, i32, ptr \} \{ ptr @sc_cs_\d+, i32 3, i32 ptrtoint/); } finally { await rm(dir, { recursive: true, force: true }); } }); + +test("JSON.parse casts to discriminated unions fuse into the schema parser", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-json-schema-union-")); + try { + const entry = join(dir, "main.ts"); + const outPath = join(dir, "main.ir.json"); + await writeFile( + entry, + ` +type Event = + | { kind: "click"; x: number; y: number } + | { kind: "focus" | "blur"; target: string } + | { kind: "load"; ms: number; next: Event | null }; +type Expr = { kind: "num"; value: number } | { kind: "add"; items: Expr[] }; +type Loose = { kind: string; a: number } | { kind: string; b: string }; +const text = process.argv[2] ?? "[]"; +const events = JSON.parse(text) as Event[]; +const tree = JSON.parse(text) as Expr; +const loose = JSON.parse(text) as Loose[]; +console.log(events.length, tree.kind, loose.length); +`, + ); + const result = await compile(entry, { outDir: dir, outPath, outputKind: "ir" }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + const llvm = emitLlvmModule(deserializeModule(await readFile(outPath, "utf8"))); + // Event[] and the whole-document Expr take the fused path; a union + // without literal discriminants keeps the checked-dynamic route alone. + expect(llvm.match(/^define internal ptr @sc_jp_\d+(?:\.i32)?\(ptr %text\)/gm)).toHaveLength(2); + expect(llvm.match(/call ptr @scr_json_parse\(ptr /g)).toHaveLength(3); + // Each literal names its arm's tag and record schema; an arm with two + // literals is listed under both. Event, `Event | null` and Expr each + // have a table. + const cases = [...llvm.matchAll(/^@sc_jsch_\d+_case_table = internal constant \[(\d+) x /gm)]; + expect(cases.map((m) => Number(m[1])).sort()).toEqual([2, 4, 4]); + expect(llvm).toMatch( + /^@sc_jsch_\d+_cases = internal constant \{ ptr, i64, i64, ptr \} \{ ptr @sc_cs_\d+, i64 4, i64 4, ptr @sc_jsch_\d+_case_table \}/m, + ); + // The union descriptors point at their cases, and a union schema that + // can be a whole document carries its release. + expect(llvm).toMatch( + /@sc_jsch_\d+_union = internal constant \{ i64, \[7 x i64\], \[7 x ptr\], ptr, ptr, ptr, ptr \} \{ .*, ptr @sc_jsch_\d+_cases \}/, + ); + expect(llvm).toMatch( + /= internal constant \{ i64, i64, ptr, ptr, ptr, ptr, ptr, ptr, i64 \} \{ i64 5, i64 0, ptr null, ptr null, ptr null, ptr null, ptr @\S+, ptr @sc_jsch_\d+_union, i64 0 \}/, + ); + } finally { + await rm(dir, { recursive: true, force: true }); + } +}); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8243-json-parse-discriminated-unions.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8243-json-parse-discriminated-unions.ts.json new file mode 100644 index 000000000..96ef2084c --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8243-json-parse-discriminated-unions.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8243-json-parse-discriminated-unions.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index cfe3e8389..7539b3a1b 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -12304,7 +12304,8 @@ static bool scr_jschema_read(ScrJsonP *p, const ScrJsonSchema *s, ScrJsonSlot *o static void scr_jschema_drop(const ScrJsonSchema *s, ScrJsonSlot *v) { if (s->kind == SCR_JSCHEMA_STR) scr_str_release(v->ptr); - else if (s->kind == SCR_JSCHEMA_REC || s->kind == SCR_JSCHEMA_ARR) s->release(v->ptr); + else if (s->kind == SCR_JSCHEMA_REC || s->kind == SCR_JSCHEMA_ARR || s->kind == SCR_JSCHEMA_UNION) + s->release(v->ptr); } static bool scr_jschema_string_skip(ScrJsonP *p) { @@ -12418,14 +12419,79 @@ static void scr_jschema_inline_store(char *slot, size_t tag, uint64_t bits) { memcpy(slot, &pair, sizeof pair); } -/* A union member value written into its field slot. Each JSON value kind - * selects at most one arm (the compiler admits no two arms one kind could - * both match), so the checked route's first full match is that arm, and - * any other value declines. */ -static __attribute__((noinline)) bool scr_jschema_union(ScrJsonP *p, const ScrJsonUnion *u, - char *slot) { - scr_json_ws(p); - if (p->pos >= p->len) return false; +/* The string at p->pos (a quote), as a span into the text or, when it + * holds escapes, decoded into *decoded (released by the caller). */ +static bool scr_jschema_string_at(ScrJsonP *p, const char **span, size_t *span_len, + ScrStr **decoded) { + *decoded = NULL; + int r = scr_json_string_span(p, span, span_len); + if (r > 0) return true; + if (r < 0) return false; + *decoded = scr_json_string_slow(p, *span_len); + if (!*decoded) return false; + *span = (*decoded)->data; + *span_len = (*decoded)->len; + return true; +} + +/* The case of discriminated union `d` that the object at p->pos (its + * opening brace) selects: the one whose literal the object's discriminant + * member holds. A shallow scan of the members up to that one finds it and + * restores p->pos. NULL when the member is missing or not a string, when + * no case has its value, or when the text before it is malformed: the + * checked route then decides. A repeated discriminant member selects by + * its first value; the arm's record then declines the repeat. */ +static __attribute__((noinline)) const ScrJsonCase *scr_jschema_case(ScrJsonP *p, + const ScrJsonDiscriminant *d) { + const size_t start = p->pos, depth = p->depth; + const ScrJsonCase *found = NULL; + if (++p->depth > SCR_JSON_MAX_DEPTH) goto done; + p->pos++; /* '{' */ + for (;;) { + scr_json_ws(p); + if (p->pos >= p->len || p->s[p->pos] != '"') goto done; + const char *key; + size_t key_len; + ScrStr *decoded; + if (!scr_jschema_string_at(p, &key, &key_len, &decoded)) goto done; + bool discriminant = key_len == d->field_len && scr_key_equal(key, d->field, key_len); + scr_str_release(decoded); + scr_json_ws(p); + if (p->pos >= p->len || p->s[p->pos] != ':') goto done; + p->pos++; + if (discriminant) { + scr_json_ws(p); + if (p->pos >= p->len || p->s[p->pos] != '"') goto done; + const char *value; + size_t value_len; + if (!scr_jschema_string_at(p, &value, &value_len, &decoded)) goto done; + for (size_t i = 0; i < d->ncases; i++) { + const ScrJsonCase *c = &d->cases[i]; + if (c->value_len == value_len && memcmp(c->value, value, value_len) == 0) { + found = c; + break; + } + } + scr_str_release(decoded); + goto done; + } + if (!scr_jschema_skip(p)) goto done; + scr_json_ws(p); + if (p->pos >= p->len || p->s[p->pos] != ',') goto done; + p->pos++; + } +done: + p->pos = start; + p->depth = depth; + return found; +} + +/* A union value's arm tag and payload at p->pos (whitespace skipped): the + * arm its JSON value kind selects or, for an object of a discriminated + * union, its case's record. A null value reads no payload (*arm_out is + * SCR_JARM_NULL). False when the value declines. */ +static bool scr_jschema_union_payload(ScrJsonP *p, const ScrJsonUnion *u, size_t *tag, + size_t *arm_out, ScrJsonSlot *v) { char c = p->s[p->pos]; size_t arm; if (c == 'n') arm = SCR_JARM_NULL; @@ -12435,16 +12501,36 @@ static __attribute__((noinline)) bool scr_jschema_union(ScrJsonP *p, const ScrJs else if (c == 't' || c == 'f') arm = SCR_JARM_BOOL; else if (c == '-' || (c >= '0' && c <= '9')) arm = SCR_JARM_NUM; else return false; - size_t tag = u->tags[arm]; - if (tag == SCR_JSCHEMA_NO_ARM) return false; + *arm_out = arm; + if (arm == SCR_JARM_OBJ && u->disc) { + const ScrJsonCase *selected = scr_jschema_case(p, u->disc); + if (!selected) return false; + *tag = selected->tag; + return scr_jschema_read(p, selected->record, v); + } + *tag = u->tags[arm]; + if (*tag == SCR_JSCHEMA_NO_ARM) return false; + if (arm == SCR_JARM_NULL) return scr_json_lit(p, "null", 4); + return scr_jschema_read(p, u->arms[arm], v); +} + +/* A union member value written into its field slot. Each JSON value kind + * selects at most one arm, and an object of a discriminated union selects + * its case's arm (the compiler admits no two arms one value could both + * match), so the checked route's first full match is that arm, and any + * other value declines. */ +static __attribute__((noinline)) bool scr_jschema_union(ScrJsonP *p, const ScrJsonUnion *u, + char *slot) { + scr_json_ws(p); + if (p->pos >= p->len) return false; + size_t tag, arm; + ScrJsonSlot v; + if (!scr_jschema_union_payload(p, u, &tag, &arm, &v)) return false; if (arm == SCR_JARM_NULL) { - if (!scr_json_lit(p, "null", 4)) return false; if (u->repr == SCR_JUNION_INLINE) scr_jschema_inline_store(slot, tag, 0); else memcpy(slot, &u->null_value, sizeof u->null_value); /* immortal */ return true; } - ScrJsonSlot v; - if (!scr_jschema_read(p, u->arms[arm], &v)) return false; uint64_t bits = 0; if (arm == SCR_JARM_NUM) memcpy(&bits, &v.f, sizeof bits); else if (arm == SCR_JARM_BOOL) bits = v.b ? 1 : 0; @@ -12460,6 +12546,19 @@ static __attribute__((noinline)) bool scr_jschema_union(ScrJsonP *p, const ScrJs return true; } +/* A discriminated union value outside a record field: an array element or + * the whole document. A pointer union's value is the case's record itself; + * any other union's is a box. */ +static bool scr_jschema_union_value(ScrJsonP *p, const ScrJsonUnion *u, ScrJsonSlot *out) { + size_t tag, arm; + ScrJsonSlot v; + if (!scr_jschema_union_payload(p, u, &tag, &arm, &v)) return false; + if (arm == SCR_JARM_NULL) out->ptr = u->null_value; /* immortal */ + else if (u->repr == SCR_JUNION_NULLABLE) out->ptr = v.ptr; + else out->ptr = u->box((uint32_t)tag, (uint64_t)(uintptr_t)v.ptr); /* the record moves in */ + return true; +} + /* A declared member value written into its (zeroed) slot of `rec`. */ static inline __attribute__((always_inline)) bool scr_jschema_field(ScrJsonP *p, const ScrJsonSchemaField *f, @@ -12805,6 +12904,8 @@ static bool scr_jschema_read(ScrJsonP *p, const ScrJsonSchema *s, ScrJsonSlot *o p->depth--; return ok; } + case SCR_JSCHEMA_UNION: + return scr_jschema_union_value(p, s->uni, out); } return false; } diff --git a/packages/runtime/src/scr_json.h b/packages/runtime/src/scr_json.h index 8a4ecc62d..a8a59b60c 100644 --- a/packages/runtime/src/scr_json.h +++ b/packages/runtime/src/scr_json.h @@ -13,11 +13,14 @@ ScrDyn *scr_json_parse(ScrStr *text); /* Compiler-emitted description of a statically known JSON.parse target * (`JSON.parse(text) as T`). Constant data in the program image; the LLVM * backend mirrors this layout ({size, size, ptr, ptr, ptr, ptr, ptr, ptr, size}, - * {ptr, size, size, ptr} and {size, [7 x size], [7 x ptr], ptr, ptr, ptr}). - * Records list their declared fields (at most 64), each with its byte - * offset in the record struct; bool fields are one byte, f64 fields - * doubles, inline union fields a {uint32 tag, uint64 bits} pair, every - * other kind a +1 pointer. Unions appear only as record field types. A + * {ptr, size, size, ptr}, {size, [7 x size], [7 x ptr], ptr, ptr, ptr, ptr}, + * and for discriminated unions {ptr, size, size, ptr} with {ptr, size, size, + * ptr} cases). Records list their declared fields (at most 64), each with + * its byte offset in the record struct; bool fields are one byte, f64 + * fields doubles, inline union fields a {uint32 tag, uint64 bits} pair, + * every other kind a +1 pointer. Unions appear as record field types; + * discriminated unions also as array elements and whole documents, whose + * values are the union's box (or its pointer, for a pointer union). A * record with an index signature names its index value type in `elem` and * its overflow map's offset in `ovf_offset`. */ enum { @@ -57,6 +60,22 @@ typedef struct { size_t offset; const ScrJsonSchema *type; } ScrJsonSchemaField; +/* One string literal of a discriminated union's discriminant member and + * the record arm (canonical tag and schema) that holds it. */ +typedef struct { + const char *value; + size_t value_len; + size_t tag; + const ScrJsonSchema *record; +} ScrJsonCase; +/* A discriminated union's object arms by discriminant literal: every + * literal names one arm. */ +typedef struct { + const char *field; + size_t field_len; + size_t ncases; + const ScrJsonCase *cases; +} ScrJsonDiscriminant; typedef struct { size_t repr; size_t tags[SCR_JARM_COUNT]; /* canonical arm tag, or SCR_JSCHEMA_NO_ARM */ @@ -66,6 +85,9 @@ typedef struct { /* boxed: a +1 box of the value arm `tag`; bits hold its double, its * bool, or its +1 payload pointer (moved in). */ void *(*box)(uint32_t tag, uint64_t bits); + /* discriminated unions: the object arms; NULL for other unions, whose + * object arm is arms[SCR_JARM_OBJ] */ + const ScrJsonDiscriminant *disc; } ScrJsonUnion; struct ScrJsonSchema { size_t kind; diff --git a/tests/corpus/8243-json-parse-discriminated-unions.ts b/tests/corpus/8243-json-parse-discriminated-unions.ts new file mode 100644 index 000000000..df3fd6dd8 --- /dev/null +++ b/tests/corpus/8243-json-parse-discriminated-unions.ts @@ -0,0 +1,119 @@ +// JSON.parse cast to discriminated unions of records: arrays of them, +// whole documents, members (with null and optional arms) and recursive +// trees. The discriminant appears first, last or between other members, +// escaped, repeated, and beside undeclared members; values hold escapes +// and non-ASCII text. + +type Event = + | { kind: "click"; x: number; y: number } + | { kind: "focus" | "blur"; target: string } + | { key: string; kind: "key"; repeat: boolean } + | { kind: "load"; ms: number; next: Event | null; note?: string }; + +type Expr = + | { kind: "num"; value: number } + | { kind: "neg"; operand: Expr } + | { items: Expr[]; kind: "max" } + | { body: Expr; kind: "let"; name: string; value: Expr }; + +function describe(e: Event): string { + switch (e.kind) { + case "click": + return `click ${e.x},${e.y}`; + case "focus": + case "blur": + return `${e.kind} ${e.target}`; + case "key": + return `key ${e.key}${e.repeat ? " (repeat)" : ""}`; + case "load": + return `load ${e.ms}${e.note === undefined ? "" : ` "${e.note}"`}${e.next === null ? "" : ` then ${describe(e.next)}`}`; + } +} + +function evaluate(e: Expr, env: Map): number { + switch (e.kind) { + case "num": + return e.value; + case "neg": + return -evaluate(e.operand, env); + case "max": { + let best = -Infinity; + for (const item of e.items) best = Math.max(best, evaluate(item, env)); + return best; + } + case "let": { + const inner = new Map(env); + inner.set(e.name, evaluate(e.value, env)); + return evaluate(e.body, inner) + (inner.get(e.name) ?? 0); + } + } +} + +const events = JSON.parse(`[ + {"kind":"click","x":1,"y":2}, + {"x":3,"y":4,"kind":"click"}, + {"y":6,"kind":"click","x":5}, + {"kind":"focus","target":"input"}, + {"target":"button","kind":"blur"}, + {"key":"Enter","kind":"key","repeat":false}, + {"repeat":true,"key":"\\u00e9","kind":"key"}, + {"kind":"load","ms":12,"next":null}, + {"kind":"load","ms":7,"note":"caf\\u00e9 \\ud83d\\ude00","next":{"kind":"blur","target":"tab"}}, + {"next":{"kind":"load","ms":1,"next":{"kind":"click","x":0,"y":-1}},"ms":30,"kind":"load"}, + {"k\\u0069nd":"focus","target":"escaped key"}, + {"kind":"bl\\u0075r","target":"escaped value"}, + {"kind":"click","kind":"focus","target":"repeated"}, + {"kind":"click","x":8,"y":9,"extra":{"kind":"not an event","list":[1,[2]]}}, + { "kind" : "key" , "key" : "space" , "repeat" : true } +]`) as Event[]; +console.log(events.length); +for (const e of events) console.log(describe(e)); +console.log(JSON.stringify(events[12]), JSON.stringify(events[13])); + +const empty = JSON.parse("[]") as Event[]; +console.log(empty.length); + +const single = JSON.parse('{"target":"whole document","kind":"focus"}') as Event; +console.log(describe(single)); + +const tree = JSON.parse(`{ + "body": {"items": [{"kind":"num","value":4}, {"kind":"neg","operand":{"kind":"num","value":-9}}, {"items":[],"kind":"max"}], "kind": "max"}, + "kind": "let", + "name": "x", + "value": {"kind":"neg","operand":{"kind":"neg","operand":{"kind":"num","value":2.5}}} +}`) as Expr; +console.log(evaluate(tree, new Map())); + +const forest = JSON.parse( + `[${Array.from({ length: 50 }, (_, i) => + i % 3 === 0 + ? `{"kind":"num","value":${i}}` + : i % 3 === 1 + ? `{"operand":{"kind":"num","value":${i}},"kind":"neg"}` + : `{"items":[{"kind":"num","value":${i}},{"kind":"num","value":${50 - i}}],"kind":"max"}`, + ).join(",")}]`, +) as Expr[]; +let total = 0; +for (const t of forest) total += evaluate(t, new Map()); +console.log(forest.length, total); + +// Parsing the same text again builds separate values. +const again = JSON.parse('[{"kind":"num","value":1},{"kind":"num","value":2}]') as Expr[]; +const twice = JSON.parse('[{"kind":"num","value":1},{"kind":"num","value":2}]') as Expr[]; +console.log(again.length + twice.length, again[0] === twice[0]); + +// Malformed text throws Node's SyntaxError, including text that ends +// inside the members before the discriminant or inside its value. +for (const text of [ + '[{"kind":"click","x":1,"y":2},', + '[{"x":1,"kind"', + '[{"x":[1,2,"kind":"click"}]', + '[{"kind":"cl', + '[{"target":"a" "kind":"focus"}]', +]) { + try { + console.log((JSON.parse(text) as Event[]).length); + } catch (error) { + console.log(error instanceof SyntaxError, (error as Error).message); + } +} From a54e0811d0c22d6fb019b8aa776b15922bf37e3c Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 01:04:31 -0500 Subject: [PATCH 217/259] Journal the Promise.all tuple and AsyncLocalStorage callback thunks --- .../compiler/src/backend/llvm/lib-dispatch.ts | 52 ++++++++++++------- .../compiler/src/backend/llvm/lib-process.ts | 7 +++ .../compiler/test/chunked-emission.test.ts | 35 ++++++++++++- 3 files changed, 73 insertions(+), 21 deletions(-) diff --git a/packages/compiler/src/backend/llvm/lib-dispatch.ts b/packages/compiler/src/backend/llvm/lib-dispatch.ts index e1f038093..8a98fb154 100644 --- a/packages/compiler/src/backend/llvm/lib-dispatch.ts +++ b/packages/compiler/src/backend/llvm/lib-dispatch.ts @@ -25,6 +25,7 @@ import { DYN_KIND } from "./dyn.js"; import { caBytes } from "./lib-abi.js"; import { emitInlineAtomicsOp } from "./expr-bytes.js"; import { regexLiteralCaptures } from "./regex-matchers.js"; +import { registerReplay } from "./emit-journal.js"; /** ScrDyn.v.typed_ref.type_key_len: the low 27 bits of its bit-field word. */ const TYPE_KEY_LEN_MASK = (1 << 27) - 1; @@ -1130,6 +1131,36 @@ export function emitLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlValue { } } +/** The settlement adapter of Promise.all's tuple form for the builder + * `fnName`, which fulfills the result with the builder's tuple. */ +function allTupleAdapterFor(host: LlvmEmitterContext, fnName: string, tuple: IrType): string { + const key = `allTuple:${fnName}`; + let adapter = host.resolveThunks.get(key); + if (adapter !== undefined) return adapter; + adapter = `sc_all_tuple_${host.resolveThunks.size}`; + host.resolveThunks.set(key, adapter); + host.journal?.allocated(adapter, "allTupleAdapterFor", [fnName, tuple]); + const rc = vAdapters(host.shapeHost, tuple); + host.declare(`declare ptr @scr_promise_payload_ref(ptr)`); + host.declare(`declare void @scr_promise_fulfill_ref(ptr, ptr, ptr, ptr, ptr)`); + host.resolveThunkDefs.push( + `define internal void @${adapter}(ptr %dst, ptr %src) ${FN_ATTRS} { ; Promise.all tuple`, + `entry:`, + ` %entries = call ptr @scr_promise_payload_ref(ptr %src) ; +1, moves into the builder`, + ` %tuple = call ptr @${host.callTarget(fnName)}(ptr %entries)`, + ` call void @scr_promise_fulfill_ref(ptr %dst, ptr %tuple, ptr ${rc.retain}, ptr ${rc.release}, ptr ${traceArg(host.shapeHost, tuple)})`, + ` ret void`, + `}`, + ``, + ); + host.journal?.built(); + return adapter; +} + +registerReplay("allTupleAdapterFor", (host, args) => + allTupleAdapterFor(host, args[0] as string, args[1] as IrType), +); + /** Promise.all's tuple form (promise.allTuple): the combinator over the * entries stores each fulfilled entry promise, and a settlement adapter on * the combinator calls the builder with them and fulfills the result with @@ -1142,26 +1173,7 @@ function emitPromiseAllTuple(host: LlvmEmitterContext, e: LibCallExpr): LlValue throw new InternalCompilerError("llvm emitter bug: promise.allTuple shape"); const entriesT = e.args[0]!.type; const entries = host.emitExpr(e.args[0]!); - const tuple = e.type.inner; - const key = `allTuple:${build.fnName}`; - let adapter = host.resolveThunks.get(key); - if (adapter === undefined) { - adapter = `sc_all_tuple_${host.resolveThunks.size}`; - host.resolveThunks.set(key, adapter); - const rc = vAdapters(host.shapeHost, tuple); - host.declare(`declare ptr @scr_promise_payload_ref(ptr)`); - host.declare(`declare void @scr_promise_fulfill_ref(ptr, ptr, ptr, ptr, ptr)`); - host.resolveThunkDefs.push( - `define internal void @${adapter}(ptr %dst, ptr %src) ${FN_ATTRS} { ; Promise.all tuple`, - `entry:`, - ` %entries = call ptr @scr_promise_payload_ref(ptr %src) ; +1, moves into the builder`, - ` %tuple = call ptr @${host.callTarget(build.fnName)}(ptr %entries)`, - ` call void @scr_promise_fulfill_ref(ptr %dst, ptr %tuple, ptr ${rc.retain}, ptr ${rc.release}, ptr ${traceArg(host.shapeHost, tuple)})`, - ` ret void`, - `}`, - ``, - ); - } + const adapter = allTupleAdapterFor(host, build.fnName, e.type.inner); host.declare(`declare ptr @scr_promise_all(ptr, ptr, ptr)`); host.declare(`declare void @scr_promise_all_store_promise(ptr, double, ptr)`); host.declare(`declare ptr @scr_promise_new()`); diff --git a/packages/compiler/src/backend/llvm/lib-process.ts b/packages/compiler/src/backend/llvm/lib-process.ts index 74ab34971..75d8038fc 100644 --- a/packages/compiler/src/backend/llvm/lib-process.ts +++ b/packages/compiler/src/backend/llvm/lib-process.ts @@ -6,6 +6,7 @@ import type { LlvmEmitterContext, LibCallExpr, LlValue } from "./expr-context.js import { f64Lit } from "./common.js"; import { mockTimerSym } from "./lib-shared.js"; import { FN_ATTRS } from "./shapes.js"; +import { registerReplay } from "./emit-journal.js"; export function emitChildProcessLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlValue { const B = host.B; @@ -498,6 +499,7 @@ function boundCallbackThunk(host: LlvmEmitterContext, cbT: IrType & { kind: "fun if (sym) return sym; sym = `sc_alsbound_${host.resolveThunks.size}`; host.resolveThunks.set(key, sym); + host.journal?.allocated(sym, "boundCallbackThunk", [cbT]); host.declare("declare ptr @scr_als_bound_target(ptr)"); host.declare("declare ptr @scr_als_bound_enter(ptr)"); host.declare("declare void @scr_als_bound_leave(ptr, ptr)"); @@ -517,9 +519,14 @@ function boundCallbackThunk(host: LlvmEmitterContext, cbT: IrType & { kind: "fun `}`, ``, ); + host.journal?.built(); return sym; } +registerReplay("boundCallbackThunk", (host, args) => + boundCallbackThunk(host, args[0] as IrType & { kind: "func" }), +); + export function emitProcessLibCall(host: LlvmEmitterContext, e: LibCallExpr): LlValue { const B = host.B; if (e.fn === "process.forkTarget") { diff --git a/packages/compiler/test/chunked-emission.test.ts b/packages/compiler/test/chunked-emission.test.ts index 2aec1e49b..f4977f035 100644 --- a/packages/compiler/test/chunked-emission.test.ts +++ b/packages/compiler/test/chunked-emission.test.ts @@ -1,4 +1,4 @@ -import { mkdtemp, readFile, rm } from "node:fs/promises"; +import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { expect, test } from "vitest"; @@ -25,6 +25,7 @@ const PROGRAMS = [ "6305-json-discriminant-dispatch.ts", "7321-speculative-loop-bail-sites.ts", "7360-worker-typed-records.ts", + "7110-als-completion-callbacks.ts", "node24-text-utilities-coercion.js", ]; @@ -70,6 +71,38 @@ test("function bodies emitted in chunks merge into the text one emitter gives", } }, 600_000); +// Thunks a range creates are journaled, so the merging emitter defines +// them: here Promise.all's tuple adapter, requested by a function that is +// not async (async functions are emitted again when the merging emitter +// selects stackless bodies). +test("a Promise.all tuple adapter requested in a range is defined", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-chunked-tuple-")); + try { + const entry = join(dir, "main.ts"); + await writeFile( + entry, + [ + "function both(a: Promise, b: Promise): Promise<[number, string]> {", + " return Promise.all([a, b]);", + "}", + 'both(Promise.resolve(1), Promise.resolve("x")).then((v) => console.log(v[0], v[1]));', + "", + ].join("\n"), + ); + const outPath = join(dir, "main.ir.json"); + const result = await compile(entry, { outDir: dir, outPath, outputKind: "ir" }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + const ir = await readFile(outPath, "utf8"); + const serial = text(emitLlvmModuleSource(deserializeModule(ir), {})); + expect(serial).toContain("define internal void @sc_all_tuple_0("); + const chunked = text(emitLlvmModuleSource(deserializeModule(ir), { functionChunks: 2 })); + expect(chunked === serial).toBe(true); + } finally { + await rm(dir, { recursive: true, force: true }); + } +}, 60_000); + // Debug metadata is numbered per emitter (debug-info.ts) and not journaled: // a debug build emits its function bodies in one emitter. test("debug builds emit function bodies serially, with every metadata reference defined", async () => { From 9d7f0182e5d670bb603e80cf23720b5c78d742a3 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 01:04:55 -0500 Subject: [PATCH 218/259] Keep CommonJS wrapper names and redeclared exports out of namespace rewrites - A guarded declaration of a name the CommonJS wrapper defines (`var exports = exports || {}`, and `module`, `require`, `__filename`, `__dirname`, `arguments`) reads the wrapper's value, not undefined, so it keeps its text instead of becoming a fresh object. - The write scan counts destructuring assignments, and destructuring for-in/for-of targets, as writes, so a hoisted function that sets the namespace before its guarded declaration keeps the declaration as it is. - An exported `var` that a later declaration of the same name sets again is not settled at the export: importers would read the redeclared value, where Node copies the first one into module.exports. It stays refused (SC1090), as before. The npm case var-export-redeclared pins it. --- .../src/frontend/lowering/lower-stmts.ts | 8 +++-- .../npm-static-namespace-defaults.test.ts | 17 ++++++++++ .../frontend/npm-static-namespace-defaults.ts | 31 ++++++++++++++++--- .../cases/var-export-redeclared/main.ts.json | 6 ++++ .../npm/cases/var-export-redeclared/main.ts | 3 ++ .../node_modules/redeclared-ns/index.d.ts | 1 + .../node_modules/redeclared-ns/index.js | 5 +++ .../node_modules/redeclared-ns/package.json | 1 + .../cases/var-export-redeclared/package.json | 1 + tests/harness/npm.test.ts | 2 ++ 10 files changed, 68 insertions(+), 7 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/var-export-redeclared/main.ts.json create mode 100644 tests/fixtures/npm/cases/var-export-redeclared/main.ts create mode 100644 tests/fixtures/npm/cases/var-export-redeclared/node_modules/redeclared-ns/index.d.ts create mode 100644 tests/fixtures/npm/cases/var-export-redeclared/node_modules/redeclared-ns/index.js create mode 100644 tests/fixtures/npm/cases/var-export-redeclared/node_modules/redeclared-ns/package.json create mode 100644 tests/fixtures/npm/cases/var-export-redeclared/package.json diff --git a/packages/compiler/src/frontend/lowering/lower-stmts.ts b/packages/compiler/src/frontend/lowering/lower-stmts.ts index 851cae4c9..4366a04b0 100644 --- a/packages/compiler/src/frontend/lowering/lower-stmts.ts +++ b/packages/compiler/src/frontend/lowering/lower-stmts.ts @@ -12708,13 +12708,15 @@ function isAssertionInitializer(node: ts.Expression): boolean { return ts.isAsExpression(e) || ts.isTypeAssertion(e); } -/** A `var` (or `let`) whose initialized declaration precedes the export - * statement in the module's top-level statements and that nothing ever - * reassigns: exporting it by reference reads the value Node copies. The +/** A `var` (or `let`) whose one initialized declaration precedes the + * export statement in the module's top-level statements and that nothing + * ever reassigns or redeclares: exporting it by reference reads the value Node copies. The * legacy `var ns = ns || {}; …; module.exports = { ns }` shape. */ function settledBeforeExport(lowerer: Lowerer, sym: ts.Symbol, exportNode: ts.Node): boolean { const decl = sym.valueDeclaration; if (!decl || !ts.isVariableDeclaration(decl) || decl.initializer === undefined) return false; + // A redeclaration (`var ns = other` after the export) writes it too. + if (sym.declarations.some((d) => d !== decl)) return false; const stmt = decl.parent?.parent; if (!stmt || !ts.isVariableStatement(stmt) || !ts.isSourceFile(stmt.parent)) return false; let exportStmt: ts.Node = exportNode; diff --git a/packages/compiler/src/frontend/npm-static-namespace-defaults.test.ts b/packages/compiler/src/frontend/npm-static-namespace-defaults.test.ts index 93a776f7e..0fe7dc9a1 100644 --- a/packages/compiler/src/frontend/npm-static-namespace-defaults.test.ts +++ b/packages/compiler/src/frontend/npm-static-namespace-defaults.test.ts @@ -60,4 +60,21 @@ test("any other write, declaration or earlier mention keeps the text", () => { expect(rewrite("let ns = ns || {};\n")).toBeNull(); // Not the declared name on the left. expect(rewrite("var ns = other || {};\n")).toBeNull(); + // Written through a destructuring assignment, here by a hoisted function + // that runs before the declaration. + expect( + rewrite("init();\nvar ns = ns || {};\nfunction init() { [ns] = [{ a: 1 }]; }\n"), + ).toBeNull(); + expect( + rewrite("init();\nvar ns = ns || {};\nfunction init() { ({ ns } = { ns: { a: 1 } }); }\n"), + ).toBeNull(); + expect(rewrite("var ns = ns || {};\nfor ([ns] of [[{}]]);\n")).toBeNull(); +}); + +test("a name the CommonJS wrapper defines keeps the text", () => { + // `exports` is the module's export object here, not undefined. + const source = "var exports = exports || {};\nexports.answer = 42;\n"; + expect(rewrite(source)).toBeNull(); + expect(rewrite("var module = module || {};\n")).toBeNull(); + expect(rewrite("var require = require || null;\n")).toBeNull(); }); diff --git a/packages/compiler/src/frontend/npm-static-namespace-defaults.ts b/packages/compiler/src/frontend/npm-static-namespace-defaults.ts index 2e4bf046c..26a8e4cd0 100644 --- a/packages/compiler/src/frontend/npm-static-namespace-defaults.ts +++ b/packages/compiler/src/frontend/npm-static-namespace-defaults.ts @@ -6,8 +6,9 @@ * read in its own initializer sees `undefined` unless something writes the * variable first. When nothing else in the file ever writes it (no other * declaration, assignment or update of that name anywhere, no function or - * class of that name) and no earlier top-level statement mentions it, the - * initializer is its right operand: `var ns = {};`. Inference then types + * class of that name), no earlier top-level statement mentions it, and it + * is not a name a CommonJS module's wrapper defines (`exports`, `module`, + * ...), the initializer is its right operand: `var ns = {};`. Inference then types * the namespace from that literal and the members later statements add, * instead of `any` (the self-reference makes the checker give up). `??` * is the same. Anything else keeps the original text. */ @@ -15,6 +16,18 @@ import * as ts from "./ts7/syntax.js"; import { tokenStartOfNode } from "./ts7/node-functions.js"; import { applyEdits, unparen, type Edit } from "./npm-static-bundled-chunks.js"; +/** Names a CommonJS module's wrapper function defines before its first + * statement: its parameters and its arguments object. `var exports = + * exports || {}` keeps the module's export object, not a fresh one. */ +const COMMONJS_WRAPPER_NAMES = new Set([ + "exports", + "require", + "module", + "__filename", + "__dirname", + "arguments", +]); + /** A cheap probe: some `var X = X ||` or `?? ` may be present. */ export function mayHoldNamespaceDefault(source: string): boolean { return /\bvar\s+([A-Za-z_$][\w$]*)\s*=\s*\(?\s*\1\s*(\|\||\?\?)/.test(source); @@ -42,6 +55,7 @@ export function rewriteNamespaceDefaults(sf: ts.SourceFile): string | null { continue; const left = unparen(init.left); if (!ts.isIdentifier(left) || left.text !== name) continue; + if (COMMONJS_WRAPPER_NAMES.has(name)) continue; if (mentionedBefore(stmts, i, name) || writtenElsewhere(sf, name, decl)) continue; const right = init.right; edits.push({ @@ -82,7 +96,7 @@ function writtenElsewhere(sf: ts.SourceFile, name: string, decl: ts.VariableDecl if (written) return "stop"; if (n === decl.name) return undefined; if (ts.isBinaryExpression(n) && isAssignmentOperator(n.operatorToken.kind)) { - if (isName(n.left, name)) written = true; + if (assignsName(n.left, name)) written = true; } else if ( (ts.isPrefixUnaryExpression(n) || ts.isPostfixUnaryExpression(n)) && (n.operator === ts.SyntaxKind.PlusPlusToken || @@ -108,7 +122,7 @@ function writtenElsewhere(sf: ts.SourceFile, name: string, decl: ts.VariableDecl } else if ( (ts.isForInStatement(n) || ts.isForOfStatement(n)) && !ts.isVariableDeclarationList(n.initializer) && - isName(n.initializer, name) + assignsName(n.initializer, name) ) { written = true; } @@ -128,6 +142,15 @@ function bindsName(binding: ts.Node, name: string): boolean { return found; } +/** Whether an assignment target may write `name`: the name itself, or a + * destructuring pattern that mentions it anywhere (over-approximated: a + * property key of that name counts too). */ +function assignsName(target: ts.Node, name: string): boolean { + const t = unparen(target as ts.Expression); + if (ts.isArrayLiteralExpression(t) || ts.isObjectLiteralExpression(t)) return bindsName(t, name); + return isName(t, name); +} + function isName(node: ts.Node, name: string): boolean { const n = unparen(node as ts.Expression); return ts.isIdentifier(n) && n.text === name; diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/var-export-redeclared/main.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/var-export-redeclared/main.ts.json new file mode 100644 index 000000000..ccc1a3653 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/fixtures/npm/cases/var-export-redeclared/main.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/fixtures/npm/cases/var-export-redeclared/main.ts" + ], + "diags": [] +} diff --git a/tests/fixtures/npm/cases/var-export-redeclared/main.ts b/tests/fixtures/npm/cases/var-export-redeclared/main.ts new file mode 100644 index 000000000..23f014d29 --- /dev/null +++ b/tests/fixtures/npm/cases/var-export-redeclared/main.ts @@ -0,0 +1,3 @@ +// An importer sees the value module.exports holds, not the redeclared binding. +import { ns } from "redeclared-ns"; +console.log(ns.version); diff --git a/tests/fixtures/npm/cases/var-export-redeclared/node_modules/redeclared-ns/index.d.ts b/tests/fixtures/npm/cases/var-export-redeclared/node_modules/redeclared-ns/index.d.ts new file mode 100644 index 000000000..1db3d1444 --- /dev/null +++ b/tests/fixtures/npm/cases/var-export-redeclared/node_modules/redeclared-ns/index.d.ts @@ -0,0 +1 @@ +export declare const ns: { version: number }; diff --git a/tests/fixtures/npm/cases/var-export-redeclared/node_modules/redeclared-ns/index.js b/tests/fixtures/npm/cases/var-export-redeclared/node_modules/redeclared-ns/index.js new file mode 100644 index 000000000..45f29a690 --- /dev/null +++ b/tests/fixtures/npm/cases/var-export-redeclared/node_modules/redeclared-ns/index.js @@ -0,0 +1,5 @@ +// A namespace exported by reference, then redeclared with a new value: +// Node copies the first object into module.exports. +var ns = { version: 1 }; +module.exports = { ns }; +var ns = { version: 2 }; diff --git a/tests/fixtures/npm/cases/var-export-redeclared/node_modules/redeclared-ns/package.json b/tests/fixtures/npm/cases/var-export-redeclared/node_modules/redeclared-ns/package.json new file mode 100644 index 000000000..c18908fd8 --- /dev/null +++ b/tests/fixtures/npm/cases/var-export-redeclared/node_modules/redeclared-ns/package.json @@ -0,0 +1 @@ +{ "name": "redeclared-ns", "version": "1.0.0", "main": "index.js", "types": "index.d.ts" } diff --git a/tests/fixtures/npm/cases/var-export-redeclared/package.json b/tests/fixtures/npm/cases/var-export-redeclared/package.json new file mode 100644 index 000000000..023d0b3d9 --- /dev/null +++ b/tests/fixtures/npm/cases/var-export-redeclared/package.json @@ -0,0 +1 @@ +{ "name": "var-export-redeclared-case", "private": true, "type": "module" } diff --git a/tests/harness/npm.test.ts b/tests/harness/npm.test.ts index 27b27b8e3..203e75a41 100644 --- a/tests/harness/npm.test.ts +++ b/tests/harness/npm.test.ts @@ -104,6 +104,8 @@ const KNOWN: Record = { "self-name": { build: "SC2013" }, "stream-shims": { run: "SC2020" }, "util-shims": { run: "SC2020" }, + // The package redeclares the var it exported: Node copies the first value. + "var-export-redeclared": { run: "SC1090" }, "web-streams": { run: "SC1090" }, "workspace-copied": { build: "SC2013" }, "workspace-unclean": { build: "SC2013" }, From 6b27ffbf08660c5b4cc1b8b69bea657664b9a436 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 01:25:03 -0500 Subject: [PATCH 219/259] Fetch only the syntax trees lowering reads --- .../compiler/src/frontend/lowering/argument-counts.ts | 3 +-- .../compiler/src/frontend/lowering/js-collection-types.ts | 4 ++-- packages/compiler/src/frontend/lowering/lower-classes.ts | 4 ++-- packages/compiler/src/frontend/lowering/lower-server.ts | 8 ++++---- packages/compiler/src/frontend/lowering/lowerer.ts | 4 +--- packages/compiler/src/frontend/lowering/symbol-fields.ts | 4 ++-- packages/compiler/src/frontend/program.ts | 5 ++--- packages/compiler/src/frontend/shape-inference/analyze.ts | 3 +-- 8 files changed, 15 insertions(+), 20 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/argument-counts.ts b/packages/compiler/src/frontend/lowering/argument-counts.ts index ec1753160..d79e7b43f 100644 --- a/packages/compiler/src/frontend/lowering/argument-counts.ts +++ b/packages/compiler/src/frontend/lowering/argument-counts.ts @@ -193,8 +193,7 @@ export function usedAsValue( const symbol = symbolAt(name); if (!symbol) return false; let found = false; - for (const sf of lowerer.program.getSourceFiles()) { - if (sf.isDeclarationFile) continue; + for (const sf of lowerer.program.getImplementationSourceFiles()) { ts.walkPreorder(sf, (n) => { if (found) return "stop"; if (ts.isTypeNode(n)) return "skip"; diff --git a/packages/compiler/src/frontend/lowering/js-collection-types.ts b/packages/compiler/src/frontend/lowering/js-collection-types.ts index 2be4e0dbd..1e3219276 100644 --- a/packages/compiler/src/frontend/lowering/js-collection-types.ts +++ b/packages/compiler/src/frontend/lowering/js-collection-types.ts @@ -91,8 +91,8 @@ function inferProgram(lowerer: Lowerer): Map { const out = new Map(); const carriers = carrierTypes(lowerer); if (carriers === null) return out; - for (const file of lowerer.program.getSourceFiles()) { - if (file.isDeclarationFile || !isJsSourceFile(file)) continue; + for (const file of lowerer.program.getImplementationSourceFiles()) { + if (!isJsSourceFile(file)) continue; for (const candidate of inferFile(lowerer, file)) { const name = candidate.kind === "map" diff --git a/packages/compiler/src/frontend/lowering/lower-classes.ts b/packages/compiler/src/frontend/lowering/lower-classes.ts index bb1f1714f..5f1f6a03d 100644 --- a/packages/compiler/src/frontend/lowering/lower-classes.ts +++ b/packages/compiler/src/frontend/lowering/lower-classes.ts @@ -7019,8 +7019,8 @@ function capturesEnclosingScope( * reflection: the member a runtime lookup finds can then differ. */ function memberAssigned(lowerer: Lowerer, member: ts.MethodDeclaration, name: string): boolean { let found = false; - for (const sf of lowerer.program.getSourceFiles()) { - if (sf.isDeclarationFile || found) continue; + for (const sf of lowerer.program.getImplementationSourceFiles()) { + if (found) continue; if (!sf.text.includes(name)) continue; ts.walkPreorder(sf, (node) => { if (found) return "skip"; diff --git a/packages/compiler/src/frontend/lowering/lower-server.ts b/packages/compiler/src/frontend/lowering/lower-server.ts index 4121d13b4..7359b56a8 100644 --- a/packages/compiler/src/frontend/lowering/lower-server.ts +++ b/packages/compiler/src/frontend/lowering/lower-server.ts @@ -2317,8 +2317,8 @@ function lowerNetServerMethodCall( function socketEncodingReachable(lowerer: Lowerer): boolean { if (lowerer.socketEncodingReachable !== null) return lowerer.socketEncodingReachable; let reachable = false; - for (const file of lowerer.program.getSourceFiles()) { - if (file.isDeclarationFile || !file.text.includes("setEncoding")) continue; + for (const file of lowerer.program.getImplementationSourceFiles()) { + if (!file.text.includes("setEncoding")) continue; ts.walkPreorder(file, (node) => { if (reachable) return "skip"; if (!ts.isCallExpression(node)) return undefined; @@ -2349,8 +2349,8 @@ function socketEncodingReachable(lowerer: Lowerer): boolean { function unixListenReachable(lowerer: Lowerer): boolean { if (lowerer.unixListenReachable !== null) return lowerer.unixListenReachable; let reachable = false; - for (const file of lowerer.program.getSourceFiles()) { - if (file.isDeclarationFile || !file.text.includes("listen")) continue; + for (const file of lowerer.program.getImplementationSourceFiles()) { + if (!file.text.includes("listen")) continue; ts.walkPreorder(file, (node) => { if (reachable) return "skip"; if (!ts.isCallExpression(node) || node.arguments.nodes.length === 0) return undefined; diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 15c0ef993..6b54b17bf 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -3743,9 +3743,7 @@ export class Lowerer { * that comes back through a boundary cast keeps its identity. */ private declBoundaryMemo: boolean | null = null; get declBoundary(): boolean { - this.declBoundaryMemo ??= this.program - .getSourceFiles() - .some((sf) => isDeclBoundaryFile(sf.fileName)); + this.declBoundaryMemo ??= this.program.getSourceFileNames().some(isDeclBoundaryFile); return this.declBoundaryMemo; } /** Tracked classes' bag initializers over a typed `this` diff --git a/packages/compiler/src/frontend/lowering/symbol-fields.ts b/packages/compiler/src/frontend/lowering/symbol-fields.ts index cdfb9e1b8..958af5963 100644 --- a/packages/compiler/src/frontend/lowering/symbol-fields.ts +++ b/packages/compiler/src/frontend/lowering/symbol-fields.ts @@ -394,9 +394,9 @@ function tablePropertyWritten( } return false; }; - for (const sf of lowerer.program.getSourceFiles()) { + for (const sf of lowerer.program.getImplementationSourceFiles()) { if (written) break; - if (sf.isDeclarationFile || !sf.text.includes(name)) continue; + if (!sf.text.includes(name)) continue; ts.walkPreorder(sf, (node) => { if (written) return "stop"; let target: ts.Node | undefined; diff --git a/packages/compiler/src/frontend/program.ts b/packages/compiler/src/frontend/program.ts index aa6ddbfa7..00afcd696 100644 --- a/packages/compiler/src/frontend/program.ts +++ b/packages/compiler/src/frontend/program.ts @@ -1291,10 +1291,9 @@ export function loadProgram( * packages whose declarations the boundary projects from. */ function declBoundaryUserFiles(program: ts.Program, packages: readonly string[]): string[] { const out: string[] = []; - for (const sf of program.getSourceFiles()) { + for (const sf of program.getImplementationSourceFiles()) { const name = sf.fileName.split("\\").join("/"); - if (sf.isDeclarationFile || name.includes("/node_modules/") || !/\.[mc]?tsx?$/.test(name)) - continue; + if (name.includes("/node_modules/") || !/\.[mc]?tsx?$/.test(name)) continue; if (name.endsWith(".tsx")) continue; // JSX files: not projected yet const text = sf.text; if ( diff --git a/packages/compiler/src/frontend/shape-inference/analyze.ts b/packages/compiler/src/frontend/shape-inference/analyze.ts index 19d3cac22..c403c6ba8 100644 --- a/packages/compiler/src/frontend/shape-inference/analyze.ts +++ b/packages/compiler/src/frontend/shape-inference/analyze.ts @@ -325,8 +325,7 @@ class Analyzer { } run(): ShapeAnalysis { - for (const sf of this.program.getSourceFiles()) { - if (sf.isDeclarationFile) continue; + for (const sf of this.program.getImplementationSourceFiles()) { const name = sf.fileName.split("\\").join("/"); const inPackage = isPackageJsFile(sf); if (!inPackage && name.includes("/node_modules/")) continue; From db2cb5c99e767d1f3f3841965649f16a73a7efd8 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 01:35:28 -0500 Subject: [PATCH 220/259] Split readline input in one scan and copy ASCII strings into buffers whole readline split redirected input byte by byte, twice per chunk (once to find whether the chunk ends a line, once to split it). Before splitting it copied each chunk out of its Buffer and into a scratch buffer, decoded it into a new string, and copied the unfinished line and the whole chunk into a joined buffer. Now: - one scan per chunk: memchr for a CR once, then LF to LF with memchr when the chunk has none, and the LF, CR and CRLF split otherwise; - the unfinished line joins only the first line of the chunk; - an ASCII chunk with no partial UTF-8 sequence held from the previous one is split where it is, and a chunk that is not shared memory is read from its own storage. Lines are still copied into their strings before the first is delivered. Buffer.from(string, 'latin1' | 'ascii') encoded character by character; an ASCII prefix, all of an ASCII string, is now copied with memcpy. Line events, their order and the CRLF delay are unchanged. Corpus 8344 covers lines joined across chunks, a line longer than a chunk, empty lines, mixed line endings and UTF-8 split across chunks. The new line-reader workload reads a 67 MB log through readline over a file stream. --- benchmarks/runtime/README.md | 1 + benchmarks/runtime/workloads/line-reader.json | 7 ++ benchmarks/runtime/workloads/line-reader.ts | 34 +++++++++ .../8344-readline-chunk-splitting.ts.json | 6 ++ packages/runtime/src/scr_bytes.c | 4 +- packages/runtime/src/scr_readline.c | 71 +++++++++++-------- scripts/bench-runtime.mjs | 10 +++ tests/corpus/8344-readline-chunk-splitting.ts | 41 +++++++++++ 8 files changed, 145 insertions(+), 29 deletions(-) create mode 100644 benchmarks/runtime/workloads/line-reader.json create mode 100644 benchmarks/runtime/workloads/line-reader.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8344-readline-chunk-splitting.ts.json create mode 100644 tests/corpus/8344-readline-chunk-splitting.ts diff --git a/benchmarks/runtime/README.md b/benchmarks/runtime/README.md index 83cfcb831..520964cf3 100644 --- a/benchmarks/runtime/README.md +++ b/benchmarks/runtime/README.md @@ -20,6 +20,7 @@ Application-shaped workloads for measuring the speed of compiled executables. Ea | `json-records` | cpu | `JSON.stringify`, typed `JSON.parse`, Map aggregation | | `json-unions` | cpu | `JSON.parse` into discriminated unions: an event log with eight kinds and nested expression trees with nine, evaluated after the cast | | `keyed-option-writes` | cpu | class methods whose names are also keys of option records written through element accesses: `enabled[name] = true` over a union of literal names and `totals["count"] = n` | +| `line-reader` | cpu | `readline` over a file stream: 'line' events for a 67 MB access log (every 50th line not ASCII), with a status count, a path tally and byte totals | | `log-lines` | cpu | 200k immediate `console.log`/`process.stdout.write` lines into the runner's pipe | | `log-summary`, `inventory-report` | cpu | the multi-module applications from `benchmarks/builds`, on 300k-line inputs | | `number-maps` | cpu | number-keyed Map/Set: a dense-id table, sparse ids in many small maps, get/has/set mixes | diff --git a/benchmarks/runtime/workloads/line-reader.json b/benchmarks/runtime/workloads/line-reader.json new file mode 100644 index 000000000..85194f70c --- /dev/null +++ b/benchmarks/runtime/workloads/line-reader.json @@ -0,0 +1,7 @@ +{ + "entry": "workloads/line-reader.ts", + "input": "line-reader", + "args": [ + "{input}" + ] +} diff --git a/benchmarks/runtime/workloads/line-reader.ts b/benchmarks/runtime/workloads/line-reader.ts new file mode 100644 index 000000000..cbdf384bb --- /dev/null +++ b/benchmarks/runtime/workloads/line-reader.ts @@ -0,0 +1,34 @@ +// Line-by-line processing of a log file with readline over a file stream: +// 'line' events for about 67 MB of access-log lines, with light work per +// line (a status count, a path tally, byte totals). +import { createReadStream } from "node:fs"; +import { createInterface } from "node:readline"; + +const path = process.argv[2]!; +const statuses = new Map(); +const paths = new Map(); +let lines = 0; +let chars = 0; +let bytes = 0; +let longest = 0; + +const input = createInterface({ input: createReadStream(path), crlfDelay: Infinity }); +input.on("line", (line: string) => { + lines++; + chars += line.length; + if (line.length > longest) longest = line.length; + const quote = line.indexOf('"'); + const space = line.indexOf(" ", quote); + const path = line.slice(space + 1, line.indexOf("/", line.indexOf("/", space) + 1)); + paths.set(path, (paths.get(path) ?? 0) + 1); + const close = line.indexOf('"', space); + const status = line.slice(close + 2, close + 5); + statuses.set(status, (statuses.get(status) ?? 0) + 1); + bytes += Number(line.slice(close + 6, line.indexOf(" ", close + 6))); +}); +input.on("close", () => { + console.log(`${lines} lines, ${chars} characters, longest ${longest}`); + console.log(`bytes ${bytes}`); + for (const status of [...statuses.keys()].sort()) console.log(`status ${status}: ${statuses.get(status)}`); + for (const prefix of [...paths.keys()].sort()) console.log(`path ${prefix}: ${paths.get(prefix)}`); +}); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8344-readline-chunk-splitting.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8344-readline-chunk-splitting.ts.json new file mode 100644 index 000000000..8c01e6b47 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8344-readline-chunk-splitting.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8344-readline-chunk-splitting.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_bytes.c b/packages/runtime/src/scr_bytes.c index e6df837c8..6b8594c08 100644 --- a/packages/runtime/src/scr_bytes.c +++ b/packages/runtime/src/scr_bytes.c @@ -2722,7 +2722,9 @@ static ScrBytes *scr_bytes_encode_str(ScrBytesSink *sink, const ScrStr *s, const /* Node writes charCodeAt(i) & 0xFF for BOTH spellings — an astral * code point contributes its two surrogates' low bytes. */ ScrBytes *b = scr_bytes_conversion_storage_in(sink, n); - size_t o = 0, i = 0; + /* An ASCII prefix (all of an ASCII string) is its own encoding. */ + size_t o = s->ascii ? n : scr_bytes_ascii_prefix(in, n), i = o; + memcpy(b->data, in, o); while (i < n) { uint32_t cp = scr_bytes_next_cp(in, &i); if (cp > 0xffff) { diff --git a/packages/runtime/src/scr_readline.c b/packages/runtime/src/scr_readline.c index 1bc48bbe7..178d620c6 100644 --- a/packages/runtime/src/scr_readline.c +++ b/packages/runtime/src/scr_readline.c @@ -283,7 +283,23 @@ static void scr_rl_buf_append(ScrRl *rl, const char *p, size_t n) { rl->line_len += n; } -/* kNormalWrite over decoded UTF-8 text. */ +/* The end of the line starting at `i` in text without a CR: the next LF, + * or n when the text ends first. */ +static size_t scr_rl_next_lf(const char *p, size_t i, size_t n) { + const char *lf = memchr(p + i, '\n', n - i); + return lf ? (size_t)(lf - p) : n; +} + +/* The end of the line starting at `i`: the next LF or CR, or n. */ +static size_t scr_rl_next_break(const char *p, size_t i, size_t n) { + while (i < n && p[i] != '\n' && p[i] != '\r') i++; + return i; +} + +/* kNormalWrite over decoded UTF-8 text. The text is scanned once: LF-only + * text (no CR anywhere in it) moves from LF to LF with memchr, other text + * splits at LF, CR and CRLF. The unfinished line before the text only + * joins the first line, so the rest of the text is never copied whole. */ static void scr_rl_feed_text(ScrRl *rl, const char *p, size_t n) { if (rl->tty) { scr_rl_tty_ops->feed(rl, p, n); @@ -296,43 +312,31 @@ static void scr_rl_feed_text(ScrRl *rl, const char *p, size_t n) { } rl->saw_return_at = 0; } - bool ending = false; - for (size_t i = 0; i < n && !ending; i++) ending = p[i] == '\n' || p[i] == '\r'; - if (!ending) { + bool cr = n > 0 && memchr(p, '\r', n) != NULL; + size_t end = n == 0 ? 0 : cr ? scr_rl_next_break(p, 0, n) : scr_rl_next_lf(p, 0, n); + if (end == n) { if (n > 0) scr_rl_buf_append(rl, p, n); return; } - /* The unfinished line joins the new text; the scan runs over both. */ - char *text = p ? (char *)p : (char *)""; - size_t len = n; - char *joined = NULL; - if (rl->line_len > 0) { - joined = malloc(rl->line_len + n); - if (!joined) scr_rl_oom(); - memcpy(joined, rl->line_buf, rl->line_len); - memcpy(joined + rl->line_len, p, n); - text = joined; - len = rl->line_len + n; - } - rl->line_len = 0; - rl->saw_return_at = len > 0 && text[len - 1] == '\r' ? scr_now_ms() : 0; + rl->saw_return_at = p[n - 1] == '\r' ? scr_now_ms() : 0; /* Split first (the remainder becomes the new unfinished line before any * line is delivered, as in Node), then deliver in order. */ size_t n_lines = 0, cap_lines = 0; ScrStr **lines = NULL; size_t start = 0; - for (size_t i = 0; i < len; i++) { - size_t adv; - if (text[i] == '\n') adv = 1; - else if (text[i] == '\r') adv = i + 1 < len && text[i + 1] == '\n' ? 2 : 1; - else continue; + while (end < n) { lines = scr_rl_grow(lines, &cap_lines, n_lines + 1, sizeof *lines); - lines[n_lines++] = scr_str_new(text + start, i - start); - i += adv - 1; - start = i + 1; + if (n_lines == 0 && rl->line_len > 0) { + scr_rl_buf_append(rl, p, end); + lines[n_lines++] = scr_str_new(rl->line_buf, rl->line_len); + } else { + lines[n_lines++] = scr_str_new(p + start, end - start); + } + start = end + (p[end] == '\r' && end + 1 < n && p[end + 1] == '\n' ? 2 : 1); + end = start >= n ? n : cr ? scr_rl_next_break(p, start, n) : scr_rl_next_lf(p, start, n); } - if (start < len) scr_rl_buf_append(rl, text + start, len - start); - free(joined); + rl->line_len = 0; + if (start < n) scr_rl_buf_append(rl, p + start, n - start); for (size_t i = 0; i < n_lines; i++) { if (rl->closed || scr_exc_pending()) { scr_str_release(lines[i]); @@ -366,6 +370,11 @@ static void scr_rl_feed_bytes(ScrRl *rl, const char *p, size_t n) { rl->parked_len += n; return; } + /* ASCII with no held bytes decodes to itself: split it in place. */ + if (rl->n_held == 0 && scr_bytes_ascii_span(p, n) == n) { + scr_rl_feed_text(rl, p, n); + return; + } size_t total = rl->n_held + n; unsigned char *all = malloc(total ? total : 1); if (!all) scr_rl_oom(); @@ -401,6 +410,12 @@ static void scr_rl_feed_end(ScrRl *rl) { void scr_rl_input_bytes(double id, ScrBytes *chunk) { ScrRl *rl = scr_rl_find(id); if (!rl || rl->closed) return; + /* The splitter copies every line it keeps before it delivers one, so it + * can read a chunk's own storage; shared memory is copied out first. */ + if (!chunk->shared) { + scr_rl_feed_bytes(rl, (const char *)chunk->data, chunk->len); + return; + } char *p = malloc(chunk->len ? chunk->len : 1); if (!p) scr_rl_oom(); scr_bytes_read(chunk, 0, p, chunk->len); diff --git a/scripts/bench-runtime.mjs b/scripts/bench-runtime.mjs index b45e3ebdf..d89a4e759 100644 --- a/scripts/bench-runtime.mjs +++ b/scripts/bench-runtime.mjs @@ -180,6 +180,16 @@ function generateInput(kind) { ["sku-" + i, "category-" + (i % 17), "product " + i, i % 40, 199 + (i % 5000)].join("\t"), ).join("\n") + "\n", ); + } else if (kind === "line-reader") { + // About 67 MB of access-log lines; every 50th path is not ASCII. + writeFileSync( + path, + Array.from( + { length: 600_000 }, + (_, i) => + `10.${i % 251}.${i % 7}.${i % 13} - - [24/Oct/2026:${String(i % 24).padStart(2, "0")}:${String(i % 60).padStart(2, "0")}:00 +0000] "${i % 9 === 0 ? "POST" : "GET"} /${i % 50 === 0 ? "caf\u00e9" : "api"}/items/${i % 997}?page=${i % 31} HTTP/1.1" ${i % 23 === 0 ? 404 : 200} ${(i * 7919) % 50000} "scriptc-bench/1.0"`, + ).join("\n") + "\n", + ); } else if (kind === "cli-config") { writeFileSync(path, JSON.stringify(deployManifest(), null, 2) + "\n"); } else throw new Error(`unknown input kind ${kind}`); diff --git a/tests/corpus/8344-readline-chunk-splitting.ts b/tests/corpus/8344-readline-chunk-splitting.ts new file mode 100644 index 000000000..85eff8cdc --- /dev/null +++ b/tests/corpus/8344-readline-chunk-splitting.ts @@ -0,0 +1,41 @@ +// Line splitting over stream chunks: an unfinished line joined across many +// chunks, a line longer than a chunk, empty lines, LF-only +// chunks next to chunks with CR and CRLF, an ASCII chunk after a chunk that +// ends inside a UTF-8 sequence, and text written with rl.write(). Each line +// event shows the line's length and its first and last characters. +import { createInterface } from "node:readline"; +import { Readable } from "node:stream"; + +function show(tag: string, line: string): void { + console.log(tag, line.length, JSON.stringify(line.slice(0, 12)), JSON.stringify(line.slice(-6))); +} + +function feed(tag: string, chunks: (string | Buffer)[]): Promise { + return new Promise((resolve) => { + const src = new Readable({ read() {} }); + const rl = createInterface({ input: src, crlfDelay: Infinity }); + rl.on("line", (line: string) => show(tag, line)); + rl.on("close", () => { + console.log(tag, "closed"); + resolve(); + }); + for (const chunk of chunks) src.push(typeof chunk === "string" ? Buffer.from(chunk, "utf8") : chunk); + src.push(null); + }); +} + +const long = "x".repeat(70000) + "y"; +await feed("joined", ["par", "tial ", "line", " continues", "\nnext\n", "tail"]); +await feed("long", [long.slice(0, 30000), long.slice(30000, 65536), long.slice(65536) + "\nshort\n"]); +await feed("empty", ["\n\n", "a\n\n", "\n", "b"]); +await feed("mixed", ["lf only\nstill lf\n", "cr\rcrlf\r\nlf\n", "end\r", "\nafter\r", "\r\n", "done"]); +const euro = Buffer.from("€uro\n", "utf8"); +await feed("utf8", [euro.subarray(0, 2), Buffer.concat([euro.subarray(2), Buffer.from("plain ascii\nmore")])]); +await feed("utf8-lines", ["café one\nnaïve two\n", "ascii three\n", "中文 four"]); + +const writer = createInterface({ input: new Readable({ read() {} }), crlfDelay: Infinity }); +writer.on("line", (line: string) => show("write", line)); +writer.write("first part "); +writer.write("second part\nthird\r\nfourth\rfifth"); +writer.write("\n"); +writer.close(); From 3ef34770bd7a652169db35bc0d21b8934c43feef Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 01:41:31 -0500 Subject: [PATCH 221/259] Read optional elements of bindings that hold undefined as undefined `a?.[i]` on a binding whose type admits undefined, such as a `string[] | undefined` parameter, threw "undefined is not representable in the target union" when the binding held undefined. Element access replaced an identifier receiver whose storage has an undefined arm with a checked narrow to its present arm before the optional chain ran, so the chain saw a receiver that is never nullish and lowered `?.[` as a plain element read. Element access now leaves the receiver to the optional chain when the access carries `?.`; the chain tests the undefined arm and lowers the access again inside its guard. This applies to arrays, tuples and record keys. Property access (`a?.length`, `a?.at(0)`) already lowered through the chain. Corpus 8330 matches Node's output. --- .../compiler/src/frontend/lowering/lowerer.ts | 4 + ...tional-element-undefined-receivers.ts.json | 6 ++ ...30-optional-element-undefined-receivers.ts | 75 +++++++++++++++++++ ...tional-element-undefined-receivers.ts.json | 1 + 4 files changed, 86 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8330-optional-element-undefined-receivers.ts.json create mode 100644 tests/corpus/8330-optional-element-undefined-receivers.ts create mode 100644 tests/harness/corpus-costs/8330-optional-element-undefined-receivers.ts.json diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index 15c0ef993..9065e691e 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -13145,6 +13145,10 @@ export class Lowerer { ) { return lowerElementAccess(this, expr); } + // `a?.[i]`: the optional chain tests the receiver's undefined arm and + // lowers this access again inside its guard. + if (expr.questionDotToken && !this.chainHandled.has(expr)) + return lowerElementAccess(this, expr); const receiver = this.runtimeOptionalIdentifierValue(expr.expression); const receiverValue: IrExpr | null = receiver && (receiver.present.kind === "array" || receiver.present.kind === "record") diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8330-optional-element-undefined-receivers.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8330-optional-element-undefined-receivers.ts.json new file mode 100644 index 000000000..ef78d4391 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8330-optional-element-undefined-receivers.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8330-optional-element-undefined-receivers.ts" + ], + "diags": [] +} diff --git a/tests/corpus/8330-optional-element-undefined-receivers.ts b/tests/corpus/8330-optional-element-undefined-receivers.ts new file mode 100644 index 000000000..b9433e66c --- /dev/null +++ b/tests/corpus/8330-optional-element-undefined-receivers.ts @@ -0,0 +1,75 @@ +// Optional element access on bindings whose type admits undefined: an +// undefined receiver short-circuits to undefined without evaluating the +// key, and a present receiver reads the element as a plain access does. + +function first(kinds: string[] | undefined, i: number): string { + const kind = kinds?.[i]; + return kind === undefined ? "none" : String(kind); +} +console.log(first(undefined, 0)); +console.log(first(["a", "b"], 1)); +console.log(first(["a"], 5)); + +function orDefault(values: number[] | undefined, i: number): number { + return values?.[i] ?? -1; +} +console.log(orDefault(undefined, 0), orDefault([4, 5], 1), orDefault([4], 3)); + +function isMissing(flags: boolean[] | undefined, i: number): boolean { + return flags?.[i] === undefined; +} +console.log(isMissing(undefined, 0), isMissing([true], 0), isMissing([false], 2)); + +function head(pair: [string, number] | undefined): string { + return pair?.[0] ?? "empty"; +} +console.log(head(undefined), head(["x", 1])); + +function lookup(table: Record | undefined, key: string): number | undefined { + return table?.[key]; +} +console.log(lookup(undefined, "a"), lookup({ a: 1 }, "a"), lookup({ a: 1 }, "b")); + +function width(words: string[] | undefined, i: number): number { + return words?.[i]?.length ?? 0; +} +console.log(width(undefined, 0), width(["abc"], 0), width(["abc"], 1)); + +// The key is not evaluated when the receiver is undefined. +let keys = 0; +function nextKey(): number { + keys++; + return 0; +} +function counted(items: string[] | undefined): string | undefined { + return items?.[nextKey()]; +} +console.log(counted(undefined), keys); +console.log(counted(["k"]), keys); + +// Local bindings, including one reassigned between reads. +function maybe(present: boolean): number[] | undefined { + return present ? [7, 8] : undefined; +} +let current = maybe(false); +console.log(current?.[0]); +current = maybe(true); +console.log(current?.[1]); +current = maybe(false); +console.log(current?.[1]); + +function local(present: boolean): string { + const items: string[] | undefined = present ? ["p", "q"] : undefined; + const second = items?.[1]; + return second ?? "absent"; +} +console.log(local(true), local(false)); + +// A sparse array reads its holes as undefined. +const sparse: number[] = [1]; +sparse[3] = 4; +function at(values: number[] | undefined, i: number): string { + const value = values?.[i]; + return value === undefined ? "hole" : String(value); +} +console.log(at(sparse, 1), at(sparse, 3), at(undefined, 3)); diff --git a/tests/harness/corpus-costs/8330-optional-element-undefined-receivers.ts.json b/tests/harness/corpus-costs/8330-optional-element-undefined-receivers.ts.json new file mode 100644 index 000000000..662eb397f --- /dev/null +++ b/tests/harness/corpus-costs/8330-optional-element-undefined-receivers.ts.json @@ -0,0 +1 @@ +{ "plain": 2108 } From 8b0921243f87dd17f096eb030c52648b35a49c96 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 01:59:32 -0500 Subject: [PATCH 222/259] Compile large sanitized dev programs in shards --- packages/compiler/src/backend/library-pack.ts | 2 +- .../compiler/src/backend/llvm/split.test.ts | 132 ++++++- packages/compiler/src/backend/llvm/split.ts | 335 ++++++++++++++---- .../src/backend/native-toolchain.test.ts | 22 +- .../compiler/src/backend/native/contracts.ts | 4 +- .../compiler/src/backend/native/executable.ts | 18 +- .../compiler/src/backend/native/library.ts | 4 +- .../src/backend/native/program-shards.ts | 6 +- packages/compiler/src/index.ts | 11 +- packages/compiler/src/native/compiler.ts | 2 +- tests/harness/three.test.ts | 6 +- 11 files changed, 431 insertions(+), 111 deletions(-) diff --git a/packages/compiler/src/backend/library-pack.ts b/packages/compiler/src/backend/library-pack.ts index e7fa7a782..521f1d53e 100644 --- a/packages/compiler/src/backend/library-pack.ts +++ b/packages/compiler/src/backend/library-pack.ts @@ -153,7 +153,7 @@ export async function compilePackedLibrary( ...(await Promise.all( shards .slice(start, start + 4) - .map((shard, offset) => emit(shard.source, `shard-${start + offset}.o`)), + .map((shard, offset) => emit(shard.source(), `shard-${start + offset}.o`)), )), ); } diff --git a/packages/compiler/src/backend/llvm/split.test.ts b/packages/compiler/src/backend/llvm/split.test.ts index a49a11545..2e0cfa5a5 100644 --- a/packages/compiler/src/backend/llvm/split.test.ts +++ b/packages/compiler/src/backend/llvm/split.test.ts @@ -3,7 +3,7 @@ import { mkdtemp, readFile, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { afterAll, expect, test } from "vitest"; -import { splitLlvmLibraryProgram, splitLlvmProgram } from "./split.js"; +import { splitLlvmLibraryProgram, splitLlvmProgram, splitLlvmProgramFile } from "./split.js"; import { LlvmDebugInfo } from "./debug-info.js"; import { VOID } from "../../ir/ir.js"; @@ -61,17 +61,17 @@ test("splits generated LLVM functions and promotes only private cross-shard defi expect(actual!.promotedSymbols).not.toContain("public_entry"); expect(actual!.publicSymbols).toEqual(["public_value", "public_entry"]); expect(actual!.shards[0]!.name).toBe("program-globals.ll"); - expect(actual!.shards[0]!.source).toContain("@hidden_value = hidden global i64 7"); + expect(actual!.shards[0]!.source()).toContain("@hidden_value = hidden global i64 7"); expect( actual!.shards .slice(1) - .every((shard) => shard.source.includes("@hidden_value = external hidden global i64")), + .every((shard) => shard.source().includes("@hidden_value = external hidden global i64")), ).toBe(true); expect( actual!.shards.some( (shard) => - !shard.source.includes("define hidden i64 @right() #0") && - shard.source.includes("declare hidden i64 @right() #0"), + !shard.source().includes("define hidden i64 @right() #0") && + shard.source().includes("declare hidden i64 @right() #0"), ), ).toBe(true); }); @@ -82,9 +82,115 @@ test("thread-local definitions and declarations preserve their storage model acr "@hidden_value = internal thread_local global i64 7", ); const split = splitLlvmProgram(tls, { minimumBytes: 0, targetBytes: 64 * 1024 })!; - expect(split.shards[0]!.source).toContain("@hidden_value = hidden thread_local global i64 7"); + expect(split.shards[0]!.source()).toContain("@hidden_value = hidden thread_local global i64 7"); for (const shard of split.shards.slice(1)) { - expect(shard.source).toContain("@hidden_value = external hidden thread_local global i64"); + expect(shard.source()).toContain("@hidden_value = external hidden thread_local global i64"); + } +}); + +const PADDING = Array.from( + { length: 80 }, + (_, i) => + `define internal i64 @pad_${i}() #0 {\nentry:\n ; ${"x".repeat(2048)}\n ret i64 ${i}\n}\n`, +).join("\n"); + +/** SAMPLE with more globals after @public_value and enough functions to + * split into several shards. */ +function withGlobals(globals: string, tail = ""): string { + return `${SAMPLE.replace( + "@public_value = constant i64 11", + `@public_value = constant i64 11\n${globals}`, + ).replace("define i64 @public_entry", `${PADDING}\ndefine i64 @public_entry`)}${tail}`; +} + +/** Writes each shard and compiles it with clang. */ +async function compileShards( + shards: readonly { name: string; source: () => string }[], +): Promise { + const dir = await mkdtemp(join(tmpdir(), "scriptc-llvm-split-shards-")); + scratch.push(dir); + for (const shard of shards) { + const source = join(dir, shard.name); + await writeFile(source, shard.source()); + execFileSync("clang", ["-Wno-override-module", "-c", source, "-o", `${source}.o`]); + } +} + +test("private unnamed_addr lookup tables are promoted like internal globals", async () => { + const split = splitLlvmProgram( + withGlobals('@table = private unnamed_addr constant [2 x i8] c"\\01\\02"'), + { minimumBytes: 0, targetBytes: 64 * 1024 }, + )!; + expect(split).not.toBeNull(); + const [globals, ...functions] = split.shards; + expect(globals!.source()).toContain('@table = hidden unnamed_addr constant [2 x i8] c"\\01\\02"'); + for (const shard of functions) + expect(shard.source()).toContain("@table = external hidden constant [2 x i8]"); + expect(split.promotedSymbols).toContain("table"); + await compileShards(split.shards); +}); + +test("aggregate initializers over several lines stay whole in the globals shard", async () => { + // The regex global's comment holds unbalanced brackets. + const split = splitLlvmProgram( + withGlobals(`@regex = internal global { ptr, i64 } { ptr @left, i64 0 } ; /(a|[b/ +@vt = internal constant [2 x { i64, ptr }] [ + { i64, ptr } { i64 1, ptr @left }, + { i64, ptr } { i64 2, ptr @right } +]`), + { minimumBytes: 0, targetBytes: 64 * 1024 }, + )!; + expect(split).not.toBeNull(); + const [globals, ...functions] = split.shards; + expect(globals!.source()).toContain( + "@vt = hidden constant [2 x { i64, ptr }] [\n { i64, ptr } { i64 1, ptr @left },\n { i64, ptr } { i64 2, ptr @right }\n]", + ); + for (const shard of functions) { + expect(shard.source()).toContain("@vt = external hidden constant [2 x { i64, ptr }]"); + expect(shard.source()).not.toContain("{ i64, ptr } { i64 1"); + } + expect(split.promotedSymbols).toEqual(expect.arrayContaining(["regex", "vt"])); + await compileShards(split.shards); +}); + +test("globals after the attributes and metadata join the globals shard", async () => { + const split = splitLlvmProgram(withGlobals("", "@flag = internal constant i1 true\n"), { + minimumBytes: 0, + targetBytes: 64 * 1024, + })!; + expect(split).not.toBeNull(); + const [globals, ...functions] = split.shards; + expect(globals!.source()).toContain("@flag = hidden constant i1 true"); + for (const shard of functions) + expect(shard.source()).toContain("@flag = external hidden constant i1"); + await compileShards(split.shards); +}); + +test("a module split from its file has the shards of the same module split in memory", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-llvm-split-file-")); + scratch.push(dir); + const options = { minimumBytes: 0, targetBytes: 64 * 1024 }; + const storage = withGlobals( + `@table = private unnamed_addr constant [2 x i8] c"\\01\\02" +@vt = internal constant [2 x { i64, ptr }] [ + { i64, ptr } { i64 1, ptr @left }, + { i64, ptr } { i64 2, ptr @right } +]`, + "@flag = internal constant i1 true\n", + ); + for (const [name, source] of [ + ["sample.ll", withGlobals("")], + ["storage.ll", storage], + ] as const) { + const path = join(dir, name); + await writeFile(path, source); + const fromFile = splitLlvmProgramFile(path, options)!; + expect(fromFile).not.toBeNull(); + const materialize = (split: NonNullable) => ({ + ...split, + shards: split.shards.map((shard) => ({ name: shard.name, source: shard.source() })), + }); + expect(materialize(fromFile)).toEqual(materialize(splitLlvmProgram(source, options)!)); } }); @@ -127,7 +233,7 @@ entry: for (const shard of split.shards) { const path = join(dir, shard.name); const object = `${path}.o`; - await writeFile(path, shard.source); + await writeFile(path, shard.source()); execFileSync("clang", ["-Wno-override-module", "-O2", "-c", path, "-o", object]); objects.push(object); } @@ -169,10 +275,10 @@ test("shared metadata bounds shard growth while preserving every definition", () expect(split).not.toBeNull(); expect(split!.shards.length).toBeGreaterThan(1); expect( - split!.shards.reduce((bytes, shard) => bytes + Buffer.byteLength(shard.source), 0), + split!.shards.reduce((bytes, shard) => bytes + Buffer.byteLength(shard.source()), 0), ).toBeLessThanOrEqual(2 * Buffer.byteLength(source)); const definitions = split!.shards.flatMap((shard) => - [...shard.source.matchAll(/^define (?:hidden )?i64 @(\w+)\(/gm)].map((match) => match[1]), + [...shard.source().matchAll(/^define (?:hidden )?i64 @(\w+)\(/gm)].map((match) => match[1]), ); expect(definitions.sort()).toEqual([...names, "left", "right", "public_entry"].sort()); expect(split!.publicSymbols).toEqual(["public_value", "public_entry"]); @@ -207,9 +313,9 @@ test("debug metadata stays on definitions when splitting LLVM modules", async () const dir = await mkdtemp(join(tmpdir(), "scriptc-debug-split-")); scratch.push(dir); for (const shard of split!.shards) { - expect(shard.source).not.toMatch(/^declare.*!dbg/m); + expect(shard.source()).not.toMatch(/^declare.*!dbg/m); const path = join(dir, shard.name); - await writeFile(path, shard.source); + await writeFile(path, shard.source()); const result = spawnSync("clang", ["-Wno-override-module", "-c", path, "-o", `${path}.o`], { encoding: "utf8", }); @@ -250,7 +356,7 @@ test("every shard compiles and its merged object exposes only canonical public d for (const shard of split.shards) { const source = join(dir, shard.name); const object = `${source}.o`; - await writeFile(source, shard.source); + await writeFile(source, shard.source()); execFileSync("clang", ["-Wno-override-module", "-c", source, "-o", object]); objects.push(object); } diff --git a/packages/compiler/src/backend/llvm/split.ts b/packages/compiler/src/backend/llvm/split.ts index 3fb41ce6b..aecef8df8 100644 --- a/packages/compiler/src/backend/llvm/split.ts +++ b/packages/compiler/src/backend/llvm/split.ts @@ -19,10 +19,15 @@ * canonical TU normally — cache optimization must never become correctness. */ +import { closeSync, openSync, readSync, statSync } from "node:fs"; + export interface LlvmProgramShard { /** Stable source identity used in object cache keys and diagnostics. */ name: string; - source: string; + /** Assembles the shard's LLVM text. A module split from a file reads its + * function bodies back from there on each call, so only the shards being + * written are in memory. */ + source: () => string; } export interface LlvmProgramSplit { @@ -54,12 +59,20 @@ const LIBRARY_TARGET_BYTES = 768 * 1024; const LIBRARY_MINIMUM_BYTES = 2 * 1024 * 1024; interface FunctionDef { - source: string; + /** UTF-8 length of the definition's text. */ + bytes: number; + /** The definition's text: its header (promoted to hidden linkage when + * internal), body and closing brace. A definition left in a file reads + * its body through `read`. */ + text: (read: RangeReader) => string; declaration: string; symbol: string; promoted: boolean; } +/** Reads the text between two byte offsets of the module file. */ +type RangeReader = (start: number, end: number) => string; + interface GlobalDef { line: string; declaration: string | null; @@ -72,50 +85,68 @@ function symbolOf(spelling: string): string | null { return match?.[1] ?? null; } -function functionDefAt( - lines: readonly string[], - start: number, -): { def: FunctionDef; end: number } | null { - const header = lines[start]!; +/** A definition's header line: the line its shard compiles, the + * declaration every other shard carries, and its linkage. */ +function functionHeader( + header: string, +): { line: string; declaration: string; symbol: string; promoted: boolean } | null { const match = /^define\s+(internal\s+)?(.+?)\s+(@[-$._A-Za-z][-$.\w]*)\((.*)\)(.*)\{(?:\s*;.*)?$/.exec( header, ); if (!match) return null; - let end = start + 1; - while (end < lines.length && lines[end] !== "}") end++; - if (end >= lines.length) return null; const symbol = symbolOf(match[3]!); if (symbol === null) return null; const promoted = match[1] !== undefined; const linkage = promoted ? "hidden " : ""; - const definitionHeader = promoted - ? header.replace(/^define internal /, "define hidden ") - : header; - const source = [definitionHeader, ...lines.slice(start + 1, end + 1)].join("\n"); + const line = promoted ? header.replace(/^define internal /, "define hidden ") : header; // Parameter names are legal on declarations. Preserve the emitted text so // attributes, zeroext, and varargs stay byte-exact. // A definition's DISubprogram cannot be attached to a declaration in a // different shard. Its owning definition retains the original metadata. const attrs = match[5]!.replace(/\s+!dbg !\d+/g, ""); const declaration = `declare ${linkage}${match[2]} ${match[3]}(${match[4]})${attrs}`.trimEnd(); - return { def: { source, declaration, symbol, promoted }, end }; + return { line, declaration, symbol, promoted }; +} + +function functionDefAt( + lines: readonly string[], + start: number, +): { def: FunctionDef; end: number } | null { + const header = functionHeader(lines[start]!); + if (header === null) return null; + let end = start + 1; + while (end < lines.length && lines[end] !== "}") end++; + if (end >= lines.length) return null; + const source = [header.line, ...lines.slice(start + 1, end + 1)].join("\n"); + return { + def: { + bytes: Buffer.byteLength(source), + text: () => source, + declaration: header.declaration, + symbol: header.symbol, + promoted: header.promoted, + }, + end, + }; } function globalDef(line: string): GlobalDef | null { const match = - /^(@[-$._A-Za-z][-$.\w]*)\s+=\s+(internal\s+)?(thread_local(?:\([^)]*\))?\s+)?(global|constant)\s+(.+)$/.exec( + /^(@[-$._A-Za-z][-$.\w]*)\s+=\s+((?:internal|private)\s+)?(thread_local(?:\([^)]*\))?\s+)?((?:local_)?unnamed_addr\s+)?(global|constant)\s+([\s\S]+)$/.exec( line, ); if (!match) return null; const symbol = symbolOf(match[1]!); if (symbol === null) return null; + // Internal and private definitions (such as private unnamed_addr lookup + // tables) are local to their module: shards reach them as hidden ones. const promoted = match[2] !== undefined; const threadLocal = match[3] === undefined ? "" : `${match[3].trim()} `; // The declaration needs only the complete type. Emitted initializers begin // after it; the generated LLVM subset uses first-class scalars/pointers or // balanced aggregate types, so one small scanner is sufficient. - const rest = match[5]!; + const rest = match[6]!; let depth = 0; let quote = false; let typeEnd = -1; @@ -133,13 +164,30 @@ function globalDef(line: string): GlobalDef | null { if (typeEnd < 0) return null; const type = rest.slice(0, typeEnd); return { - line: promoted ? line.replace(`${match[1]} = internal `, `${match[1]} = hidden `) : line, - declaration: `${match[1]} = external ${promoted ? "hidden " : ""}${threadLocal}${match[4]} ${type}`, + line: promoted ? line.replace(`${match[1]} = ${match[2]}`, `${match[1]} = hidden `) : line, + declaration: `${match[1]} = external ${promoted ? "hidden " : ""}${threadLocal}${match[5]} ${type}`, symbol, promoted, }; } +/** The change in aggregate nesting depth over one line of LLVM text, + * outside string constants and comments (a regex global's comment spells + * its source). */ +function bracketDepth(line: string): number { + let depth = 0; + let quote = false; + for (let i = 0; i < line.length; i++) { + const ch = line[i]!; + if (ch === '"') quote = !quote; + if (quote) continue; + if (ch === ";") break; + if (ch === "{" || ch === "[" || ch === "<" || ch === "(") depth++; + else if (ch === "}" || ch === "]" || ch === ">" || ch === ")") depth--; + } + return depth; +} + function stableBucket(symbol: string, count: number): number { let hash = 0x811c9dc5; for (let i = 0; i < symbol.length; i++) { @@ -154,7 +202,7 @@ function chunksOf( targetBytes: number, maximumBuckets: number, ): { bucket: number; functions: FunctionDef[] }[] { - const totalBytes = functions.reduce((sum, fn) => sum + Buffer.byteLength(fn.source) + 2, 0); + const totalBytes = functions.reduce((sum, fn) => sum + fn.bytes + 2, 0); // A power-of-two bucket count changes only when the program crosses a wide // size band. Ordinary edits therefore keep every function in the same // symbol-hash bucket; ceil(total/target) would reshuffle the whole program @@ -168,6 +216,74 @@ function chunksOf( ); } +/** A module's top-level forms, as the splitter classifies them. */ +interface ModuleParts { + preamble: string[]; + globals: GlobalDef[]; + functions: FunctionDef[]; + trailer: string[]; +} + +/** Classifies a module one line at a time. `define` lines go to + * `onFunction`, which takes the following lines through the definition's + * closing brace; every other line is offered to `line`. */ +class ModuleReader { + readonly parts: ModuleParts = { preamble: [], globals: [], functions: [], trailer: [] }; + private sawDefinition = false; + private inTrailer = false; + /** A global definition whose aggregate initializer continues over the + * following lines (vtable arrays list one element per line). */ + private pendingGlobal: { text: string; depth: number } | null = null; + failed = false; + + /** Whether a definition may start here (none may follow the trailer). */ + startFunction(): boolean { + if (this.inTrailer || this.pendingGlobal !== null) this.failed = true; + this.sawDefinition = true; + return !this.failed; + } + + line(line: string): void { + if (this.pendingGlobal !== null) { + this.pendingGlobal.text += "\n" + line; + this.pendingGlobal.depth += bracketDepth(line); + if (this.pendingGlobal.depth <= 0) { + const { text } = this.pendingGlobal; + this.pendingGlobal = null; + this.global(text); + } + return; + } + if (line.startsWith("@") && line.includes(" = ")) { + const depth = bracketDepth(line); + if (depth > 0) this.pendingGlobal = { text: line, depth }; + else this.global(line); + return; + } + if (line.startsWith("attributes ") || line.startsWith("!")) this.inTrailer = true; + if (this.inTrailer) this.parts.trailer.push(line); + else if (!this.sawDefinition || line.trim() !== "") this.parts.preamble.push(line); + } + + /** Globals may follow the attributes and metadata (the feature flags the + * link-features step appends); they are module storage like any other. */ + private global(definition: string): void { + const parsed = globalDef(definition); + if (parsed === null) { + // External declarations are already valid in every shard. + if (/^@.+\s+=\s+external\s+/.test(definition)) this.parts.preamble.push(definition); + else this.failed = true; + } else { + this.parts.globals.push(parsed); + this.sawDefinition = true; + } + } + + finish(): ModuleParts | null { + return this.failed || this.pendingGlobal !== null ? null : this.parts; + } +} + export function splitLlvmProgram( source: string, options: LlvmProgramSplitOptions = {}, @@ -175,42 +291,129 @@ export function splitLlvmProgram( const minimumBytes = options.minimumBytes ?? DEFAULT_MINIMUM_BYTES; const sourceBytes = Buffer.byteLength(source); if (sourceBytes < minimumBytes) return null; - const targetBytes = Math.max(64 * 1024, options.targetBytes ?? DEFAULT_TARGET_BYTES); const lines = source.split("\n"); - const preamble: string[] = []; - const globals: GlobalDef[] = []; - const functions: FunctionDef[] = []; - const trailer: string[] = []; - let sawDefinition = false; - let inTrailer = false; - for (let i = 0; i < lines.length; i++) { + const reader = new ModuleReader(); + for (let i = 0; i < lines.length && !reader.failed; i++) { const line = lines[i]!; if (line.startsWith("define ")) { - if (inTrailer) return null; + if (!reader.startFunction()) break; const parsed = functionDefAt(lines, i); if (parsed === null) return null; - functions.push(parsed.def); - sawDefinition = true; + reader.parts.functions.push(parsed.def); i = parsed.end; - continue; - } - if (line.startsWith("@") && line.includes(" = ")) { - if (inTrailer) return null; - const parsed = globalDef(line); - if (parsed === null) { - // External declarations are already valid in every shard. - if (/^@.+\s+=\s+external\s+/.test(line)) preamble.push(line); - else return null; - } else { - globals.push(parsed); - sawDefinition = true; - } - continue; - } - if (line.startsWith("attributes ") || line.startsWith("!")) inTrailer = true; - if (inTrailer) trailer.push(line); - else if (!sawDefinition || line.trim() !== "") preamble.push(line); + } else reader.line(line); } + const parts = reader.finish(); + return parts === null ? null : shardModule(parts, sourceBytes, options, null); +} + +/** The read size of splitLlvmProgramFile's scan. */ +const FILE_CHUNK_BYTES = 16 * 1024 * 1024; + +/** splitLlvmProgram over LLVM text already written to `path`, for modules + * too large to hold in memory more than once (or past the longest string the + * engine allows). Function bodies stay in the file: each shard's source + * reads its bodies when it is read, so only the shards being written at a + * time are in memory. */ +export function splitLlvmProgramFile( + path: string, + options: LlvmProgramSplitOptions = {}, +): LlvmProgramSplit | null { + const minimumBytes = options.minimumBytes ?? DEFAULT_MINIMUM_BYTES; + const sourceBytes = statSync(path).size; + if (sourceBytes < minimumBytes) return null; + const reader = new ModuleReader(); + // The definition being read: its header and where its body starts. + let current: { header: NonNullable>; body: number } | null = + null; + const onLine = (bytes: Buffer, start: number, end: number, offset: number): void => { + if (current !== null) { + // Only the closing brace ends a definition; its body is not decoded. + if (end - start === 1 && bytes[start] === 0x7d) { + const { header, body } = current; + const bodyEnd = offset + 1; + reader.parts.functions.push({ + bytes: Buffer.byteLength(header.line) + 1 + (bodyEnd - body), + text: (read) => `${header.line}\n${read(body, bodyEnd)}`, + declaration: header.declaration, + symbol: header.symbol, + promoted: header.promoted, + }); + current = null; + } + return; + } + const line = bytes.toString("utf8", start, end); + if (line.startsWith("define ")) { + const header = functionHeader(line); + if (header === null || !reader.startFunction()) reader.failed = true; + else current = { header, body: offset + (end - start) + 1 }; + } else reader.line(line); + }; + const fd = openSync(path, "r"); + try { + let carry: Buffer = Buffer.alloc(0); + let carryOffset = 0; + for (let position = 0; position < sourceBytes && !reader.failed;) { + const chunk = Buffer.allocUnsafe(Math.min(FILE_CHUNK_BYTES, sourceBytes - position)); + const read = readSync(fd, chunk, 0, chunk.length, position); + if (read === 0) break; + const data = + carry.length === 0 + ? chunk.subarray(0, read) + : Buffer.concat([carry, chunk.subarray(0, read)]); + const dataOffset = carry.length === 0 ? position : carryOffset; + position += read; + let lineStart = 0; + for (let newline = data.indexOf(10); newline >= 0; newline = data.indexOf(10, lineStart)) { + onLine(data, lineStart, newline, dataOffset + lineStart); + lineStart = newline + 1; + } + carry = Buffer.from(data.subarray(lineStart)); + carryOffset = dataOffset + lineStart; + } + // The text after the last newline is a line too (empty when the file + // ends with one), as String.prototype.split answers it. + if (!reader.failed) onLine(carry, 0, carry.length, carryOffset); + } finally { + closeSync(fd); + } + if (current !== null) return null; + const parts = reader.finish(); + return parts === null ? null : shardModule(parts, sourceBytes, options, path); +} + +/** Runs `use` with a reader of `path`'s byte ranges (or of nothing, for a + * module held in memory). */ +function withRangeReader(path: string | null, use: (read: RangeReader) => T): T { + if (path === null) + return use(() => { + throw new Error("an in-memory LLVM module has no file to read"); + }); + const fd = openSync(path, "r"); + try { + return use((start, end) => { + const bytes = Buffer.allocUnsafe(end - start); + for (let done = 0; done < bytes.length;) { + const read = readSync(fd, bytes, done, bytes.length - done, start + done); + if (read === 0) throw new Error(`${path} ended before byte ${end}`); + done += read; + } + return bytes.toString("utf8"); + }); + } finally { + closeSync(fd); + } +} + +function shardModule( + parts: ModuleParts, + sourceBytes: number, + options: LlvmProgramSplitOptions, + path: string | null, +): LlvmProgramSplit | null { + const { preamble, globals, functions, trailer } = parts; + const targetBytes = Math.max(64 * 1024, options.targetBytes ?? DEFAULT_TARGET_BYTES); if (functions.length < 2) return null; const globalDecls = globals.flatMap((global) => global.declaration === null ? [] : [global.declaration], @@ -230,16 +433,22 @@ export function splitLlvmProgram( const chunks = chunksOf(functions, targetBytes, 2 ** Math.floor(Math.log2(bucketLimit))); if (chunks.length < 2) return null; const tail = trailer.length === 0 ? "" : `\n${trailer.join("\n")}`; - const functionShards = chunks.map(({ bucket, functions: chunk }) => { + // A shard's source is assembled when it is read; a module split from a + // file reads its function bodies from there each time. + const functionShards = chunks.map(({ bucket, functions: chunk }): LlvmProgramShard => { const owned = new Set(chunk); - const declarations = functions.filter((fn) => !owned.has(fn)).map((fn) => fn.declaration); return { name: `program-f${bucket.toString().padStart(3, "0")}.ll`, - source: [ - [...preamble, ...globalDecls, ...declarations, ""].join("\n"), - ...chunk.map((fn) => fn.source), - tail, - ].join("\n"), + source: () => { + const declarations = functions.filter((fn) => !owned.has(fn)).map((fn) => fn.declaration); + return withRangeReader(path, (read) => + [ + [...preamble, ...globalDecls, ...declarations, ""].join("\n"), + ...chunk.map((fn) => fn.text(read)), + tail, + ].join("\n"), + ); + }, }; }); // Global initializer changes are common (literal text, generated tables) @@ -247,15 +456,15 @@ export function splitLlvmProgram( // all module storage in one dedicated shard that declares every function. const globalShard: LlvmProgramShard = { name: "program-globals.ll", - source: [ - [...preamble, ...functions.map((fn) => fn.declaration), ""].join("\n"), - ...globals.map((global) => global.line), - tail, - ].join("\n"), + source: () => + [ + [...preamble, ...functions.map((fn) => fn.declaration), ""].join("\n"), + ...globals.map((global) => global.line), + tail, + ].join("\n"), }; - const shards = [globalShard, ...functionShards]; return { - shards, + shards: [globalShard, ...functionShards], promotedSymbols: [ ...globals.filter((global) => global.promoted).map((global) => global.symbol), ...functions.filter((fn) => fn.promoted).map((fn) => fn.symbol), diff --git a/packages/compiler/src/backend/native-toolchain.test.ts b/packages/compiler/src/backend/native-toolchain.test.ts index fd7a5325f..f1bcde404 100644 --- a/packages/compiler/src/backend/native-toolchain.test.ts +++ b/packages/compiler/src/backend/native-toolchain.test.ts @@ -3983,12 +3983,12 @@ test.skipIf( programShards: [ { name: "program-f000.ll", - source: + source: () => "define i32 @main() {\nentry:\n ret i32 7\n}\ndeclare hidden i64 @other_value()\n", }, { name: "program-f001.ll", - source: + source: () => "declare i32 @main()\ndefine hidden i64 @other_value() {\nentry:\n ret i64 9\n}\n", }, ], @@ -4038,11 +4038,11 @@ test.skipIf(!nativeShardMergeAvailable)( const programShards = [ { name: "program-f000.ll", - source: "define i64 @foo() {\nentry:\n ret i64 1\n}\ndeclare i64 @bar()\n", + source: () => "define i64 @foo() {\nentry:\n ret i64 1\n}\ndeclare i64 @bar()\n", }, { name: "program-f001.ll", - source: "declare i64 @foo()\ndefine i64 @bar() {\nentry:\n ret i64 2\n}\n", + source: () => "declare i64 @foo()\ndefine i64 @bar() {\nentry:\n ret i64 2\n}\n", }, ]; try { @@ -4082,7 +4082,7 @@ test.skipIf(!nativeShardMergeAvailable)( // The canonical TU and ABI stay fixed, but the exact shard projection // changes. The merged-object tier must not reuse the previous layout. await build("bar", join(dir, "bar-commented.lib.a"), [ - { ...programShards[0]!, source: `; projection edit\n${programShards[0]!.source}` }, + { ...programShards[0]!, source: () => `; projection edit\n${programShards[0]!.source()}` }, programShards[1]!, ]); expect(await completeArtifacts(cacheRoot, "lib")).toHaveLength(3); @@ -4131,11 +4131,11 @@ test.skipIf( const programShards = [ { name: "program-f000.ll", - source: "define i64 @foo() {\nentry:\n ret i64 1\n}\ndeclare i64 @bar()\n", + source: () => "define i64 @foo() {\nentry:\n ret i64 1\n}\ndeclare i64 @bar()\n", }, { name: "program-f001.ll", - source: "declare i64 @foo()\ndefine i64 @bar() {\nentry:\n ret i64 2\n}\n", + source: () => "declare i64 @foo()\ndefine i64 @bar() {\nentry:\n ret i64 2\n}\n", }, ]; const ldWrapper = (generation: string): string => `#!/bin/sh @@ -4227,8 +4227,8 @@ test.skipIf( // If compilation reaches either shard, this build fails. Missing ld // (and objcopy on Linux) must select the valid canonical TU instead. programShards: [ - { name: "program-f000.ll", source: "not valid LLVM IR\n" }, - { name: "program-f001.ll", source: "also not valid LLVM IR\n" }, + { name: "program-f000.ll", source: () => "not valid LLVM IR\n" }, + { name: "program-f001.ll", source: () => "also not valid LLVM IR\n" }, ], programPublicSymbols: ["public_value"], outPath, @@ -4293,12 +4293,12 @@ test.skipIf( programShards: [ { name: "program-f000.ll", - source: + source: () => "define i64 @public_value() {\nentry:\n ret i64 7\n}\ndeclare i64 @other_value()\n", }, { name: "program-f001.ll", - source: + source: () => "declare i64 @public_value()\ndefine i64 @other_value() {\nentry:\n ret i64 9\n}\n", }, ], diff --git a/packages/compiler/src/backend/native/contracts.ts b/packages/compiler/src/backend/native/contracts.ts index ff1c7a3f6..e3f97710f 100644 --- a/packages/compiler/src/backend/native/contracts.ts +++ b/packages/compiler/src/backend/native/contracts.ts @@ -29,7 +29,7 @@ export interface CcOptions { windowsSubsystem?: WindowsSubsystem; /** Optional equivalent LLVM modules for dev compilation. Unsupported * targets or merge failures fall back to the canonical cPath TU. */ - programShards?: readonly { name: string; source: string }[]; + programShards?: readonly { name: string; source: () => string }[]; /** Canonical externally visible definitions retained while shard merging * demotes generated cross-shard linkage back to local symbols. */ programPublicSymbols?: readonly string[]; @@ -306,7 +306,7 @@ export interface LibArchiveOptions { * `programSource` remains the canonical TU/cache identity; these stable * shards compile independently and are relocatably merged into one program * object before archive assembly. */ - programShards?: readonly { name: string; source: string }[]; + programShards?: readonly { name: string; source: () => string }[]; /** Canonical externally visible definitions retained while the shard merge * demotes generated cross-shard linkage back to local symbols. */ programPublicSymbols?: readonly string[]; diff --git a/packages/compiler/src/backend/native/executable.ts b/packages/compiler/src/backend/native/executable.ts index 71bec40e8..7f989a5e4 100644 --- a/packages/compiler/src/backend/native/executable.ts +++ b/packages/compiler/src/backend/native/executable.ts @@ -436,7 +436,7 @@ export async function compileCInternal( ? ["-gline-tables-only", ...(opts.cPath.endsWith(".ll") ? [] : ["-gno-column-info"])] : []; const { programShards, programPublicSymbols, programShardMergeIdentity } = - await selectProgramShards(driver, opts, optimization === "dev" && !sanitize); + await selectProgramShards(driver, opts, optimization === "dev"); // Mobile triples produce library archives, never standalone executables: // the executable-lane runtime (event loop, sockets, child processes) is // not verified on those device classes. compile() reports the SC3002 @@ -890,9 +890,15 @@ export async function compileCInternal( }; const buildExecutable = async ( runtimeInput: (path: string) => string, - build: { programPath?: string; outPath?: string; compilerVisibleSource?: string } = {}, + build: { + programPath?: string; + outPath?: string; + compilerVisibleSource?: string; + /** programPath is an object already (the merged program shards). */ + programObject?: boolean; + } = {}, ): Promise => { - if (!separateSanitizedProgram) { + if (!separateSanitizedProgram || build.programObject === true) { await runClang(buildArgs(runtimeInput, build)); return; } @@ -1471,7 +1477,7 @@ export async function compileCInternal( .update("\0") .update(shard.name) .update("\0") - .update(shard.source) + .update(shard.source()) .digest("hex"); return { ...shard, @@ -1485,7 +1491,7 @@ export async function compileCInternal( for (let i = 0; i < entries.length; i += shardWidth) { await Promise.all( entries.slice(i, i + shardWidth).map(async (entry) => { - await writeFile(entry.sourcePath, entry.source); + await writeFile(entry.sourcePath, entry.source()); if (await copyValidCachedFile(entry.cachePath, entry.staged)) return; entry.missed = true; await runClang([ @@ -1572,7 +1578,7 @@ export async function compileCInternal( (p) => objects?.get(p) ?? p, shardedProgramObject === null ? { programPath, outPath: privateOut, compilerVisibleSource: opts.cPath } - : { programPath: shardedProgramObject, outPath: privateOut }, + : { programPath: shardedProgramObject, outPath: privateOut, programObject: true }, ); if (darwinDebugSymbols) { // clang invokes dsymutil when compiling a source TU while linking. diff --git a/packages/compiler/src/backend/native/library.ts b/packages/compiler/src/backend/native/library.ts index cca706896..f0577f3ca 100644 --- a/packages/compiler/src/backend/native/library.ts +++ b/packages/compiler/src/backend/native/library.ts @@ -485,7 +485,7 @@ export async function compileLibArchive(opts: LibArchiveOptions): Promise .update("\0") .update(shard.name) .update("\0") - .update(shard.source) + .update(shard.source()) .digest("hex"); cachePath = join(persistentCache.root, "program-shard", key); } @@ -495,7 +495,7 @@ export async function compileLibArchive(opts: LibArchiveOptions): Promise for (let i = 0; i < shardEntries.length; i += shardWidth) { await Promise.all( shardEntries.slice(i, i + shardWidth).map(async (entry) => { - await writeFile(entry.sourcePath, entry.source); + await writeFile(entry.sourcePath, entry.source()); if ( entry.cachePath !== null && (await copyValidCachedFile(entry.cachePath, entry.staged)) diff --git a/packages/compiler/src/backend/native/program-shards.ts b/packages/compiler/src/backend/native/program-shards.ts index 978be3a97..1afd87f7b 100644 --- a/packages/compiler/src/backend/native/program-shards.ts +++ b/packages/compiler/src/backend/native/program-shards.ts @@ -7,7 +7,7 @@ import { rememberFingerprintDependencies } from "./dependency-files.js"; export function updateProgramShardCacheIdentity( hash: ReturnType, - shards: readonly { name: string; source: string }[] | undefined, + shards: readonly { name: string; source: () => string }[] | undefined, publicSymbols: readonly string[] | undefined, mergeIdentity: string | undefined, ): void { @@ -17,7 +17,7 @@ export function updateProgramShardCacheIdentity( } else { hash.update("\0"); for (const shard of shards) { - hash.update(shard.name).update("\0").update(shard.source).update("\0"); + hash.update(shard.name).update("\0").update(shard.source()).update("\0"); } } hash.update("\0program-public-symbols\0"); @@ -78,7 +78,7 @@ export async function resolveProgramShardMergeIdentity(driver: CcDriver): Promis } /** Library builds admit shards in both optimization modes; executable builds - * only admit unsanitized dev LLVM. Both use the same validated names, required + * admit dev LLVM, sanitized or not. Both use the same validated names, required * public-symbol projection, target support, and canonical-TU fallback. */ export async function selectProgramShards( driver: CcDriver, diff --git a/packages/compiler/src/index.ts b/packages/compiler/src/index.ts index 74a61d892..17087d542 100644 --- a/packages/compiler/src/index.ts +++ b/packages/compiler/src/index.ts @@ -103,7 +103,11 @@ import { platformLinkerSupportsPersistentCache, resolvePlatformLinker, } from "./backend/linker.js"; -import { splitLlvmLibraryProgram, splitLlvmProgram } from "./backend/llvm/split.js"; +import { + splitLlvmLibraryProgram, + splitLlvmProgram, + splitLlvmProgramFile, +} from "./backend/llvm/split.js"; import { emitLibraryIdentityLines, replaceLibraryIdentity, @@ -566,8 +570,8 @@ async function compileExecutableNative( } const effectiveProgramSplit = programSplit ?? - (!programIsObject && features.optimization === "dev" && features.backend === "llvm" && !sanitize - ? splitLlvmProgram(await readFile(llvmPath, "utf8")) + (!programIsObject && features.optimization === "dev" && features.backend === "llvm" + ? splitLlvmProgramFile(llvmPath) : null); if (programIsObject) throw new InternalCompilerError("program objects must link against a precompiled runtime pack"); @@ -912,7 +916,6 @@ async function prepareExecutableInput( !useRuntimePack && backend === "llvm" && (opts.optimization ?? "release") === "dev" && - !(opts.sanitize ?? false) && typeof llvmSource === "string" ? splitLlvmProgram(llvmSource) : null; diff --git a/packages/compiler/src/native/compiler.ts b/packages/compiler/src/native/compiler.ts index 64964d94f..8710d31b6 100644 --- a/packages/compiler/src/native/compiler.ts +++ b/packages/compiler/src/native/compiler.ts @@ -295,7 +295,7 @@ export class NativeCompiler { for (const [index, shard] of split.shards.entries()) { const shardInput = join(stage, `shard-${index}.ll`); const shardOutput = join(stage, `shard-${index}` + this.toolchain.target.outputSuffixes.obj); - writeFileSync(shardInput, shard.source); + writeFileSync(shardInput, shard.source()); this.emitObject(shardInput, shardOutput, source + "." + shard.name, optimization, "obj"); objects.push(shardOutput); } diff --git a/tests/harness/three.test.ts b/tests/harness/three.test.ts index 967c8654a..27fb86d1f 100644 --- a/tests/harness/three.test.ts +++ b/tests/harness/three.test.ts @@ -72,11 +72,7 @@ test.for(cases)( const previousTarget = process.env["SCRIPTC_TARGET"]; const previousCc = process.env["SCRIPTC_CC"]; const wasm = target === "wasm32-wasi"; - // The sanitized nodes program is one 1.14 GB LLVM module, whose clang - // compile needs about 16 GB, more than the CI runners have. It runs - // unsanitized until sanitized dev builds compile large programs in - // shards; every other fixture keeps the sanitizer. - const sanitize = !wasm && fixture !== "nodes" && process.env["SCRIPTC_SAN"] === "1"; + const sanitize = !wasm && process.env["SCRIPTC_SAN"] === "1"; try { if (wasm) { process.env["SCRIPTC_TARGET"] = target; From 0af32aff5a22a364b694bc6440edbf687ed6e1df Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 02:15:04 -0500 Subject: [PATCH 223/259] Compute dev builds' int32 slot analysis on a forked process --- .../compiler/src/backend/llvm/emit-module.ts | 8 +- packages/compiler/src/backend/llvm/emitter.ts | 73 ++++++++++++--- .../src/backend/llvm/forked-analysis.ts | 45 ++++++++++ packages/compiler/src/ir/int32-slots.ts | 76 ++++++++++++++++ packages/compiler/src/ir/node-index.ts | 30 +++++++ .../compiler/test/chunked-emission.test.ts | 6 +- .../test/int32-slots-transfer.test.ts | 88 +++++++++++++++++++ 7 files changed, 306 insertions(+), 20 deletions(-) create mode 100644 packages/compiler/src/backend/llvm/forked-analysis.ts create mode 100644 packages/compiler/test/int32-slots-transfer.test.ts diff --git a/packages/compiler/src/backend/llvm/emit-module.ts b/packages/compiler/src/backend/llvm/emit-module.ts index c6d3dbff4..dfdd95451 100644 --- a/packages/compiler/src/backend/llvm/emit-module.ts +++ b/packages/compiler/src/backend/llvm/emit-module.ts @@ -102,10 +102,10 @@ function emitFunctionsInChunks(emitter: LlEmitter, chunks: number): string[] { return fnDefs; } -/** Modules with fewer functions emit in one process: forking and merging - * would cost more than the workers save (SCRIPTC_EMIT_WORKER_FUNCTIONS - * lowers it, for tests). */ -function workerMinFunctions(): number { +/** Modules with fewer functions emit in one process, and compute their + * analyses in it: forking and merging would cost more than the workers save + * (SCRIPTC_EMIT_WORKER_FUNCTIONS lowers it, for tests). */ +export function workerMinFunctions(): number { const value = Number(process.env["SCRIPTC_EMIT_WORKER_FUNCTIONS"] ?? "2000"); return Number.isFinite(value) && value > 0 ? value : 2000; } diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index a8c5d2c39..8049f8624 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -104,7 +104,7 @@ import { analyzeInt32Slots, dynamicFieldStores, type DynamicFieldStores, - type Int32Slots, + Int32Slots, } from "../../ir/int32-slots.js"; import { analyzeFinalFields, type FinalFields } from "../../ir/final-fields.js"; import { foldConstantGlobals } from "../../ir/constant-globals.js"; @@ -373,7 +373,9 @@ import { emitModuleParts, emitParts, helperDefs, + workerMinFunctions, } from "./emit-module.js"; +import { forkedAnalysis } from "./forked-analysis.js"; import { emitLoopCopies, emitSpeculativeWrite, @@ -1483,7 +1485,13 @@ export class LlEmitter { streamingSplitsEnabled = false; readonly initializerBindings: ReturnType; /** Whole-program int32 storage and parameter/result facts. */ - readonly int32Slots: Int32Slots; + get int32Slots(): Int32Slots { + return (this.int32SlotsValue ??= this.joinInt32Slots()); + } + private int32SlotsValue: Int32Slots | undefined; + /** The join of the int32 slot analysis a forked process computes + * (startInt32Slots). */ + private int32SlotsJoin: (() => Int32Slots) | undefined; /** The program has no runtime store into a checked-dynamic value * (dynamicFieldStores), so live views of classes and records never * commit back into their objects. Library builds keep their commits: @@ -1736,6 +1744,15 @@ export class LlEmitter { // One walk of every body, which the analyses below read instead of // walking the bodies themselves. this.nodeIndex = int32Analysis?.nodeIndex ?? new IrNodeIndex(mod); + this.initializerBindings = + int32Analysis?.initializerBindings ?? findInitializerBindings(mod, this.nodeIndex); + // One walk finds the dynamic field stores every analysis below consults. + const dynamicStores = + int32Analysis?.dynamicStores ?? dynamicFieldStores(mod, undefined, undefined, this.nodeIndex); + // Started before the other analyses, which may run while a forked + // process computes it (startInt32Slots). + if (int32Analysis !== null) this.int32SlotsValue = int32Analysis.slots; + else this.startInt32Slots(dynamicStores); this.stackTraces = observesStacks(mod, this.nodeIndex); this.nullableUnions = new NullableUnions( mod, @@ -1754,18 +1771,6 @@ export class LlEmitter { this.nullableUnions.armTypes(), ); this.constantNumericTables = findConstantNumericTables(mod); - this.initializerBindings = - int32Analysis?.initializerBindings ?? findInitializerBindings(mod, this.nodeIndex); - // One walk finds the dynamic field stores every analysis below consults. - const dynamicStores = - int32Analysis?.dynamicStores ?? dynamicFieldStores(mod, undefined, undefined, this.nodeIndex); - this.int32Slots = - int32Analysis?.slots ?? - analyzeInt32Slots(mod, { - dynamicStores, - initializerBindings: this.initializerBindings, - nodes: this.nodeIndex, - }); this.untypedIntegrity = mod.untypedIntegrity === true; this.liveViewsReadOnly = mod.lib === undefined && @@ -2211,6 +2216,46 @@ export class LlEmitter { ); // After the vtable slots: borrowing slots exclude their implementations. if (this.debug === null) this.analyzeBorrowedReturns(); + this.int32SlotsValue ??= this.joinInt32Slots(); + } + + /** Computes the int32 slot analysis, or starts it on a forked process. + * Dev builds read its result only near the end of the constructor + * (int32Abis is empty with debug info), so for a large module the + * process computes it while the constructor runs the other analyses. */ + private startInt32Slots(dynamicStores: DynamicFieldStores): void { + const mod = this.mod; + const nodes = this.nodeIndex; + const analyze = (): Int32Slots => + analyzeInt32Slots(mod, { + dynamicStores, + initializerBindings: this.initializerBindings, + nodes, + }); + const fork = this.targetOptions.forkPrimitives; + if ( + fork === undefined || + this.targetOptions.debugSources === undefined || + (this.targetOptions.functionWorkers ?? 1) < 2 || + mod.functions.length < workerMinFunctions() + ) { + this.int32SlotsValue = analyze(); + return; + } + this.int32SlotsJoin = forkedAnalysis( + fork, + analyze, + (slots) => slots.encode(nodes), + (text) => Int32Slots.decode(text, mod, nodes), + ); + } + + private joinInt32Slots(): Int32Slots { + const join = this.int32SlotsJoin; + if (join === undefined) + throw new InternalCompilerError("llvm emitter bug: int32 slots read before analysis"); + this.int32SlotsJoin = undefined; + return join(); } /** The borrowed parameters of a hierarchy's vtable slot (empty: owned). */ diff --git a/packages/compiler/src/backend/llvm/forked-analysis.ts b/packages/compiler/src/backend/llvm/forked-analysis.ts new file mode 100644 index 000000000..80ba35fac --- /dev/null +++ b/packages/compiler/src/backend/llvm/forked-analysis.ts @@ -0,0 +1,45 @@ +import { mkdtempSync, readFileSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import type { ForkPrimitives } from "./emitter.js"; + +/** Starts `compute` on a forked child process, which inherits this process + * as it is at the fork, and returns the join that answers its result. The + * child writes `encode`'s text to a file and exits; the join waits for it + * and decodes the text. When the fork fails, the child fails, or `encode` + * answers null, the join runs `compute` here instead, so the result does + * not depend on the child. Join once. */ +export function forkedAnalysis( + fork: ForkPrimitives, + compute: () => T, + encode: (value: T) => string | null, + decode: (text: string) => T, +): () => T { + const dir = mkdtempSync(join(tmpdir(), "scriptc-analysis-")); + const file = join(dir, "result.json"); + const pid = fork.fork(); + if (pid === 0) { + let code = 1; + try { + const text = encode(compute()); + if (text !== null) { + writeFileSync(file, text); + code = 0; + } + } catch { + // The parent computes the result itself. + } + fork.exit(code); + } + return () => { + let text: string | null = null; + try { + if (pid > 0 && fork.wait(pid) === 0) text = readFileSync(file, "utf8"); + } catch { + // The result is computed here. + } finally { + rmSync(dir, { recursive: true, force: true }); + } + return text === null ? compute() : decode(text); + }; +} diff --git a/packages/compiler/src/ir/int32-slots.ts b/packages/compiler/src/ir/int32-slots.ts index 1616a2a77..35207f79b 100644 --- a/packages/compiler/src/ir/int32-slots.ts +++ b/packages/compiler/src/ir/int32-slots.ts @@ -352,6 +352,82 @@ export class Int32Slots { for (const params of this.paramFacts.values()) count += params.size; return count; } + + /** The analysis as JSON, for a process that shares this module and its + * node index (a forked one). Proven writes are numbered by their position + * in `nodes`. Null when a proven write is not in the index. */ + encode(nodes: IrNodeIndex): string | null { + const proven = nodes.expressionPositions(this.provenWrites); + if (proven === null) return null; + const data: Int32SlotsData = { + fields: [...this.fields], + familyOf: [...this.familyOf], + paramFacts: [...this.paramFacts].map(([fn, params]) => [fn, [...params]]), + returns: [...this.returns], + returnRanges: [...this.returnRanges], + boxes: [...this.boxes], + boxGroupOf: [...this.boxGroupOf], + provenWrites: proven, + called: [...this.called], + reasons: [...this.reasons], + pinned: [...this.pinned], + int32Locals: [...this.int32Locals], + int32Elements: [...this.int32Elements], + pinViolations: this.pinViolations, + nonNegative: [...this.nonNegative], + narrowedReads: this.narrowedReads, + int32Arrays: [...this.int32Arrays], + checkedInt32Arrays: [...this.checkedInt32Arrays], + }; + return JSON.stringify(data); + } + + /** The analysis `encode` wrote for `mod`, whose node index is `nodes`. */ + static decode(text: string, mod: IrModule, nodes: IrNodeIndex): Int32Slots { + const data = JSON.parse(text) as Int32SlotsData; + const slots = new Int32Slots(new Map((mod.classes ?? []).map((c) => [c.name, c]))); + for (const family of data.fields) slots.fields.add(family); + for (const [key, family] of data.familyOf) slots.familyOf.set(key, family); + for (const [fn, params] of data.paramFacts) slots.paramFacts.set(fn, new Map(params)); + for (const fn of data.returns) slots.returns.add(fn); + for (const [fn, range] of data.returnRanges) slots.returnRanges.set(fn, range); + for (const group of data.boxes) slots.boxes.add(group); + for (const [member, group] of data.boxGroupOf) slots.boxGroupOf.set(member, group); + for (const node of nodes.expressionsAt(data.provenWrites)) slots.provenWrites.add(node); + for (const fn of data.called) slots.called.add(fn); + for (const [key, why] of data.reasons) slots.reasons.set(key, why); + for (const key of data.pinned) slots.pinned.add(key); + for (const key of data.int32Locals) slots.int32Locals.add(key); + for (const key of data.int32Elements) slots.int32Elements.add(key); + slots.pinViolations.push(...data.pinViolations); + for (const key of data.nonNegative) slots.nonNegative.add(key); + slots.narrowedReads = data.narrowedReads; + for (const key of data.int32Arrays) slots.int32Arrays.add(key); + for (const key of data.checkedInt32Arrays) slots.checkedInt32Arrays.add(key); + return slots; + } +} + +/** Int32Slots as plain data (Int32Slots.encode). */ +interface Int32SlotsData { + fields: string[]; + familyOf: [string, string | null][]; + paramFacts: [string, [string, IntegerRange][]][]; + returns: string[]; + returnRanges: [string, IntegerRange][]; + boxes: string[]; + boxGroupOf: [string, string][]; + provenWrites: number[]; + called: string[]; + reasons: [string, string][]; + pinned: string[]; + int32Locals: string[]; + int32Elements: string[]; + pinViolations: string[]; + nonNegative: string[]; + narrowedReads: boolean; + int32Arrays: string[]; + checkedInt32Arrays: string[]; } const DYN_KINDS = new Set(["dyn", "jsval", "caught"]); diff --git a/packages/compiler/src/ir/node-index.ts b/packages/compiler/src/ir/node-index.ts index 2aac7df92..be1fa506a 100644 --- a/packages/compiler/src/ir/node-index.ts +++ b/packages/compiler/src/ir/node-index.ts @@ -122,6 +122,36 @@ export class IrNodeIndex { if (statementKinds.has(kind)) this.statements[code] = 1; } + /** The positions of the expressions `wanted` in the index, which an + * index of the same module in another process resolves with + * expressionsAt. Null when an expression is not recorded, or is recorded + * more than once. */ + expressionPositions(wanted: ReadonlySet): number[] | null { + const positions: number[] = []; + if (wanted.size === 0) return positions; + const found = new Set(); + const { nodes, codes, statements } = this; + for (let i = 0; i < nodes.length; i++) { + if (statements[codes[i]!] !== 0) continue; + const node = nodes[i]! as IrExpr; + if (!wanted.has(node)) continue; + if (found.has(node)) return null; + found.add(node); + positions.push(i); + } + return found.size === wanted.size ? positions : null; + } + + /** The expressions at `positions` (expressionPositions). */ + expressionsAt(positions: readonly number[]): IrExpr[] { + return positions.map((position) => { + const code = this.codes[position]; + if (code === undefined || this.statements[code] !== 0) + throw new InternalCompilerError(`no IR expression at index position ${position}`); + return this.nodes[position]! as IrExpr; + }); + } + /** A scan for the nodes of `kinds`, for eachNodeOfKinds. Pass a * constant list: scans are kept by the list's identity. */ scan(kinds: readonly IrNodeKind[]): IrKindScan { diff --git a/packages/compiler/test/chunked-emission.test.ts b/packages/compiler/test/chunked-emission.test.ts index f4977f035..6d2b2e06a 100644 --- a/packages/compiler/test/chunked-emission.test.ts +++ b/packages/compiler/test/chunked-emission.test.ts @@ -104,7 +104,9 @@ test("a Promise.all tuple adapter requested in a range is defined", async () => }, 60_000); // Debug metadata is numbered per emitter (debug-info.ts) and not journaled: -// a debug build emits its function bodies in one emitter. +// a debug build emits its function bodies in one emitter. Its one fork +// computes the int32 slot analysis; when the fork fails, the emitter +// computes it itself. test("debug builds emit function bodies serially, with every metadata reference defined", async () => { const dir = await mkdtemp(join(tmpdir(), "scriptc-chunked-debug-")); const minFunctions = process.env["SCRIPTC_EMIT_WORKER_FUNCTIONS"]; @@ -148,7 +150,7 @@ test("debug builds emit function bodies serially, with every metadata reference const referenced = new Set([...emitted.matchAll(/(![0-9]+)\b/g)].map((m) => m[1])); expect([...referenced].filter((id) => !defined.has(id))).toEqual([]); } - expect(forks).toBe(0); + expect(forks).toBe(1); } finally { if (minFunctions === undefined) delete process.env["SCRIPTC_EMIT_WORKER_FUNCTIONS"]; else process.env["SCRIPTC_EMIT_WORKER_FUNCTIONS"] = minFunctions; diff --git a/packages/compiler/test/int32-slots-transfer.test.ts b/packages/compiler/test/int32-slots-transfer.test.ts new file mode 100644 index 000000000..3ea4f6a6a --- /dev/null +++ b/packages/compiler/test/int32-slots-transfer.test.ts @@ -0,0 +1,88 @@ +import { mkdtemp, readFile, rm } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile, deserializeModule } from "../src/index.js"; +import { findInitializerBindings } from "../src/ir/initializer-bindings.js"; +import { analyzeInt32Slots, dynamicFieldStores, Int32Slots } from "../src/ir/int32-slots.js"; +import type { IrExpr, IrModule } from "../src/ir/ir.js"; +import { IrNodeIndex } from "../src/ir/node-index.js"; +import { unshareNodes } from "../src/ir/unshare.js"; + +// Programs with int32 fields, parameters, results, captured boxes, contract +// pins, int32 arrays and disqualified candidates. +const PROGRAMS = [ + "4451-int32-field-storage.ts", + "4452-int32-field-dynamic-writes.ts", + "4453-int32-closed-locals.ts", + "4630-contract-int32.ts", + "4970-int32-call-abi.ts", + "5323-int32-nonnegative-slot-facts.ts", + "5332-int32-narrowed-slot-facts.ts", + "5930-contract-int32-arrays.ts", + "7326-int32-element-arrays.ts", + "7580-int32-arrays-across-calls.ts", +]; + +async function lower(program: string, dir: string): Promise { + const entry = join(import.meta.dirname, "../../../tests/corpus", program); + const outPath = join(dir, `${program}.ir.json`); + const result = await compile(entry, { outDir: dir, outPath, outputKind: "ir" }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + return readFile(outPath, "utf8"); +} + +/** The analysis LlEmitter makes of `mod`, with its node index. */ +function analyze(mod: IrModule): { nodes: IrNodeIndex; slots: Int32Slots } { + const nodes = new IrNodeIndex(mod); + const slots = analyzeInt32Slots(mod, { + nodes, + dynamicStores: dynamicFieldStores(mod, undefined, undefined, nodes), + initializerBindings: findInitializerBindings(mod, nodes), + }); + return { nodes, slots }; +} + +// A forked process holds its own copy of the module: the encoded analysis +// names nodes by index position, which resolve in any copy of the module. +test("the int32 slot analysis decodes against another copy of its module", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-int32-transfer-")); + try { + let provenWrites = 0; + for (const program of PROGRAMS) { + const ir = await lower(program, dir); + const first = analyze(unshareNodes(deserializeModule(ir))); + const copy = unshareNodes(deserializeModule(ir)); + const second = analyze(copy); + const text = first.slots.encode(first.nodes); + expect(text, program).not.toBeNull(); + const decoded = Int32Slots.decode(text!, copy, second.nodes); + expect(decoded, program).toEqual(second.slots); + for (const node of decoded.provenWrites) + expect(second.slots.provenWrites.has(node), program).toBe(true); + provenWrites += decoded.provenWrites.size; + } + expect(provenWrites).toBeGreaterThan(0); + } finally { + await rm(dir, { recursive: true, force: true }); + } +}, 120_000); + +test("an analysis whose proven writes the index does not record does not encode", () => { + const loc = { file: "test.ts", start: 0, end: 0 }; + const mod: IrModule = { + irVersion: 17, + sourceFile: "test.ts", + entry: "%main", + functions: [ + { loc, name: "%main", params: [], locals: [], returnType: { kind: "void" }, body: [] }, + ], + }; + const { nodes, slots } = analyze(mod); + expect(slots.encode(nodes)).not.toBeNull(); + const elsewhere: IrExpr = { loc, kind: "numLit", value: 1, type: { kind: "f64" } }; + slots.provenWrites.add(elsewhere); + expect(nodes.expressionPositions(slots.provenWrites)).toBeNull(); + expect(slots.encode(nodes)).toBeNull(); +}); From ad26bed418b3e976d4b6168cc75049e278bea26b Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 02:29:47 -0500 Subject: [PATCH 224/259] List line-reader among the benchmark workloads that link the dynamic tier The workload reads its file through readline over fs.createReadStream. The stream and readline runtime units define dynamic-tier symbols on their own: a program that only reads a file with createReadStream links the same 32, as log-summary and inventory-report do. --- scripts/zero-cost-compare.mjs | 1 + 1 file changed, 1 insertion(+) diff --git a/scripts/zero-cost-compare.mjs b/scripts/zero-cost-compare.mjs index b23f61a0a..7ae33d64a 100644 --- a/scripts/zero-cost-compare.mjs +++ b/scripts/zero-cost-compare.mjs @@ -418,6 +418,7 @@ export const DYNAMIC_WORKLOADS = new Set([ "bench/typed-array-scan-workers", "bench/log-summary", "bench/inventory-report", + "bench/line-reader", "bench/json-unions", "bench/throw-chains", ]); From f176e868bf3f27b0056191d703ed2ee9f7e007d6 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 02:32:44 -0500 Subject: [PATCH 225/259] Prove int32 array candidates in one analysis that revises dropped ones selectInt32Arrays proposed int32 array candidates, analyzed the marked module, and when a candidate dropped, marked the module again without it and analyzed the result from scratch, until a round kept every candidate it marked. On tsc-ts the first analysis drops 6 of 8 candidates, and a second full analysis confirms the other 2. The analysis now revises the module as candidates drop: a candidate whose element stores fail (and that keeps no checked stores) has its functions replaced by the module's functions marked without it, which call the element readers again, and the fixpoint goes on over the revised functions. The selection takes the module of the functions the analysis ended with when marking the module for the candidates it kept proposes exactly those candidates, in those functions, and the emitter takes over the analysis with that module's node index, initializer bindings and dynamic stores. A revision that changes anything else in a function, such as a call of a function no other call reaches, ends the analysis, and selection falls back to rounds. SCRIPTC_INT32_VERIFY=1 also runs the rounds and throws unless the selected module and every fact of its analysis are the same. --- packages/compiler/src/backend/llvm/emitter.ts | 236 ++++++++++++++---- packages/compiler/src/ir/int32-arrays.ts | 169 +++++++++++-- packages/compiler/src/ir/int32-slots.ts | 196 ++++++++++++++- .../test/int32-element-array-emission.test.ts | 58 ++++- 4 files changed, 581 insertions(+), 78 deletions(-) diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index a8c5d2c39..329ec4771 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -17,6 +17,7 @@ import { import { youngNurseryRequested } from "../young-nursery.js"; import { llvmBytes as llBytes, wtf8Bytes } from "../literals.js"; import { InternalCompilerError } from "../../errors.js"; +import { serializeModuleParts } from "../../ir/serialize.js"; import { createHash } from "node:crypto"; import { endsWithJump, @@ -88,6 +89,8 @@ import { fillAllocationLength, int32ArrayKey, selectInt32Arrays, + type Int32ArrayProof, + type Int32ArrayRevision, } from "../../ir/int32-arrays.js"; import { everyExpr, everyExprChild, everyStmtChild, everyStmtList } from "../../ir/traverse.js"; import { @@ -103,6 +106,7 @@ import { resolveSelfCaptures } from "../../ir/self-captures.js"; import { analyzeInt32Slots, dynamicFieldStores, + Int32RevisionConflict, type DynamicFieldStores, type Int32Slots, } from "../../ir/int32-slots.js"; @@ -552,15 +556,60 @@ export interface Int32SlotAnalysis { readonly slots: Int32Slots; } -/** The int32 slot analysis of `mod`, with the inputs LlEmitter gives it. */ -function analyzeModuleInt32Slots(mod: IrModule): Int32SlotAnalysis { +/** The int32 slot analysis of `mod`, with the inputs LlEmitter gives it. + * With `revise`, the analysis revises the functions of candidates that drop + * (Int32SlotInputs.revise), and `mod` is the module it started from. */ +function analyzeModuleInt32Slots( + mod: IrModule, + revise?: (fnName: string, dropped: ReadonlySet) => IrFunction, +): Int32SlotAnalysis { const nodeIndex = new IrNodeIndex(mod); const initializerBindings = findInitializerBindings(mod, nodeIndex); const dynamicStores = dynamicFieldStores(mod, undefined, undefined, nodeIndex); - const slots = analyzeInt32Slots(mod, { dynamicStores, initializerBindings, nodes: nodeIndex }); + const slots = analyzeInt32Slots(mod, { + dynamicStores, + initializerBindings, + nodes: nodeIndex, + ...(revise === undefined ? {} : { revise }), + }); return { mod, nodeIndex, initializerBindings, dynamicStores, slots }; } +/** The candidates an analysis keeps: int32 arrays and checked ones. */ +function keptInt32Arrays(analysis: Int32SlotAnalysis): ReadonlySet { + return new Set([...analysis.slots.int32Arrays, ...analysis.slots.checkedInt32Arrays]); +} + +/** An analysis that revised functions (analyzeModuleInt32Slots' `revise`) + * as the analysis of `mod`, the module of the functions it ended with: the + * node index of `mod`, and its initializer bindings and dynamic stores, + * which must be the ones the analysis read. Null when they differ. */ +function revisedAnalysis(analysis: Int32SlotAnalysis, mod: IrModule): Int32SlotAnalysis | null { + const nodeIndex = new IrNodeIndex(mod); + const initializerBindings = findInitializerBindings(mod, nodeIndex); + const dynamicStores = dynamicFieldStores(mod, undefined, undefined, nodeIndex); + const read = analysis.initializerBindings; + if (initializerBindings.size !== read.size) return null; + for (const [name, globals] of initializerBindings) { + const other = read.get(name); + if (other?.length !== globals.length || globals.some((g, i) => other[i] !== g)) return null; + } + const stores = analysis.dynamicStores; + if ( + dynamicStores.all !== stores.all || + dynamicStores.names.size !== stores.names.size || + [...dynamicStores.names].some((name) => !stores.names.has(name)) + ) + return null; + return { + mod, + nodeIndex, + initializerBindings, + dynamicStores, + slots: analysis.slots, + }; +} + /** The functions whose calls the backend may emit as calls of their * result-slot entries (record-results.ts). */ function resultEntryTargets(mod: IrModule): ReadonlySet { @@ -575,57 +624,127 @@ function moduleEmitter(input: IrModule, options: LlvmTargetOptions): LlEmitter { // Facts are keyed by node identity: emit the same module whether it was // lowered in memory or read back from its serialized form. const mod = unshareNodes(input); - // Each round of selectInt32Arrays analyzes the module it marks; the - // emitter of the module it returns reuses that round's analysis. - const rounds: { last: Int32SlotAnalysis | null } = { last: null }; - const proven = (marked: IrModule): ReadonlySet => { - const analysis = analyzeModuleInt32Slots(marked); - rounds.last = analysis; - return new Set([...analysis.slots.int32Arrays, ...analysis.slots.checkedInt32Arrays]); + // Each proof selectInt32Arrays asks for analyzes a marked module; the + // emitter of the module it returns reuses the last one. A proof that + // revised functions analyzed the module of the functions it ended with. + const rounds: { + last: Int32SlotAnalysis | null; + functions: readonly IrFunction[] | null; + revising: boolean; + } = { last: null, functions: null, revising: true }; + const proven = (marked: IrModule, revise: Int32ArrayRevision | null): Int32ArrayProof | null => { + rounds.functions = null; + if (revise === null || !rounds.revising) { + rounds.last = analyzeModuleInt32Slots(marked); + return { kept: keptInt32Arrays(rounds.last), functions: null }; + } + const latest = new Map(); + try { + rounds.last = analyzeModuleInt32Slots(marked, (fnName, dropped) => { + const fn = revise(fnName, dropped); + latest.set(fnName, fn); + return fn; + }); + } catch (error) { + if (!(error instanceof Int32RevisionConflict)) throw error; + rounds.last = null; + return null; + } + if (latest.size === 0) return { kept: keptInt32Arrays(rounds.last), functions: null }; + rounds.functions = marked.functions.map((fn) => latest.get(fn.name) ?? fn); + return { kept: keptInt32Arrays(rounds.last), functions: rounds.functions }; }; // Keep source storage intact for debugger inspection in dev builds. - const emitted = - options.debugSources === undefined - ? selectInt32Arrays( - versionParameters( - addRecordResultEntries( - scalarizeLiteralResults( - scalarizeNumericRecords( - specializeCallbackCalls( - specializeNumericCalls( - pairRowSums( - inlineExpressionFunctions( - foldConstantGlobals( - copyStableCaptures( - resolveSelfCaptures( - hoistFinalFieldReads( - freezeInitOnlyGlobals( - holdCharLocalsAsUnits( - dropUnwrittenPropertyBags(runPairedWhileLoopsAsFor(mod)), - ), - ), - ), - ), + if (options.debugSources !== undefined) return new LlEmitter(mod, options, null, null); + const passed = versionParameters( + addRecordResultEntries( + scalarizeLiteralResults( + scalarizeNumericRecords( + specializeCallbackCalls( + specializeNumericCalls( + pairRowSums( + inlineExpressionFunctions( + foldConstantGlobals( + copyStableCaptures( + resolveSelfCaptures( + hoistFinalFieldReads( + freezeInitOnlyGlobals( + holdCharLocalsAsUnits( + dropUnwrittenPropertyBags(runPairedWhileLoopsAsFor(mod)), ), ), ), ), - mangleFunction, ), - mangleFunction, ), ), ), + mangleFunction, ), + mangleFunction, ), - proven, - resultEntryTargets, - ) - : mod; - const prepared = rounds.last; + ), + ), + ), + ); + let emitted = selectInt32Arrays(passed, proven, resultEntryTargets); + let prepared = rounds.last; + // A proof that revised functions analyzed the module of the functions it + // ended with, which is the selected module unless selection fell back to + // rounds: then the selected module was proved by its own round. + if (prepared !== null && rounds.functions !== null && prepared.mod !== emitted) { + const functions = rounds.functions; + prepared = + emitted !== passed && + emitted.functions.length === functions.length && + emitted.functions.every((fn, i) => fn === functions[i]) + ? revisedAnalysis(prepared, emitted) + : null; + if (prepared === null && emitted !== passed) { + rounds.revising = false; + emitted = selectInt32Arrays(passed, proven, resultEntryTargets); + prepared = rounds.last; + } + } + if (process.env["SCRIPTC_INT32_VERIFY"] === "1") + verifyInt32Selection(passed, emitted, prepared?.mod === emitted ? prepared : null); return new LlEmitter(emitted, options, null, prepared?.mod === emitted ? prepared : null); } +/** SCRIPTC_INT32_VERIFY=1: throws unless the selection with revisions + * (`emitted`, and the analysis the emitter takes over) is the one rounds + * without revisions give: the same module, and the same facts. */ +function verifyInt32Selection( + passed: IrModule, + emitted: IrModule, + analysis: Int32SlotAnalysis | null, +): void { + let last: Int32SlotAnalysis | null = null; + const reference = selectInt32Arrays( + passed, + (marked) => { + last = analyzeModuleInt32Slots(marked); + return { kept: keptInt32Arrays(last), functions: null }; + }, + resultEntryTargets, + ); + const text = (mod: IrModule): string => serializeModuleParts(mod).join(""); + if (text(reference) !== text(emitted)) + throw new InternalCompilerError("int32 selection: the revised module differs from the rounds'"); + const facts = (mod: IrModule, prepared: Int32SlotAnalysis | null): string => + (prepared?.mod === mod ? prepared : analyzeModuleInt32Slots(mod)).slots.summary(mod); + const expected = facts(reference, last); + const actual = facts(emitted, analysis); + if (expected !== actual) { + const want = expected.split("\n"); + const got = actual.split("\n"); + const line = want.findIndex((entry, i) => entry !== got[i]); + throw new InternalCompilerError( + `int32 selection: the revised analysis differs from the rounds': ${want[line]?.slice(0, 400)} != ${got[line]?.slice(0, 400)}`, + ); + } +} + /** Emits the module's parts, emitting it again with the functions an * UnwindAbiViolation names on the pending-flag ABI. */ function emitModuleText(input: IrModule, options: LlvmTargetOptions): string[] { @@ -1438,7 +1557,12 @@ export class LlEmitter { /** Preorder intervals of the runtime error classes under THIS module's * class-forest numbering (main() stamps scr_error_vts with them, exactly * like the runtime ABI’s errorVtStampLines). */ - readonly errorIntervals: { kind: number; pre: number; post: number; lib: string }[] = []; + readonly errorIntervals: { + kind: number; + pre: number; + post: number; + lib: string; + }[] = []; /** The runtime emitter vtable's preorder interval, when the program * touches node:events (the class def rides the module exactly then) — * main() stamps scr_emitter_vt with it (emitterVtStampLines, ported). */ @@ -1447,7 +1571,12 @@ export class LlEmitter { * ported): the defs ride every emitter-touching module (the frontend * collects the whole emitter-rooted tree), and scr_stream.c links on * the same predicate, so the stamps always have their globals. */ - readonly streamIntervals: { vt: string; pre: number; post: number; lib: string }[] = []; + readonly streamIntervals: { + vt: string; + pre: number; + post: number; + lib: string; + }[] = []; // ── per-function state (reset in emitFunction) ───────────────────────── B = new BlockBuilder(); @@ -1514,7 +1643,12 @@ export class LlEmitter { /** Active induction bindings retain their width independently of size_t. */ integerLoopBindings = new Map< string, - { slot: string; type: "i32" | "i64"; signed?: boolean; range?: { min: number; max: number } } + { + slot: string; + type: "i32" | "i64"; + signed?: boolean; + range?: { min: number; max: number }; + } >(); /** Constant number locals whose latest emitted declaration stored an * exact integer beside the double, such as `const j = i * 4` in a @@ -1597,7 +1731,11 @@ export class LlEmitter { * (the fast copy) or as double arrays (an ordinary copy entered only * after they widened), as `function\0local` keys, and where each of the * fast copy's writes resumes in the third copy. */ - int32Kinds: { int32: Set; wide: Set; resume: Map } | null = null; + int32Kinds: { + int32: Set; + wide: Set; + resume: Map; + } | null = null; /** The resume label of the fast-copy write being emitted. */ int32KindResume: string | null = null; /** The function being emitted, for speculative globals. */ @@ -1671,7 +1809,12 @@ export class LlEmitter { * releases frames/scopes down to the recorded depths and branches to * `label` (the catch, or the exception-path finally) instead of * returning out of the function. Entering a try emits no code. */ - tryStack: { label: string; used: boolean; frameDepth: number; scopeDepth: number }[] = []; + tryStack: { + label: string; + used: boolean; + frameDepth: number; + scopeDepth: number; + }[] = []; /** Return type of the function being emitted — the unwind path returns * a dummy of this type (never read: callers check the flag first). */ currentReturnType: IrType = VOID; @@ -7150,7 +7293,10 @@ export class LlEmitter { return childDataDynThunkFor(this, chunk); } - emitterFixedAdapter(cbT: IrType & { kind: "func" }): { fn: string; shim: string } { + emitterFixedAdapter(cbT: IrType & { kind: "func" }): { + fn: string; + shim: string; + } { return emitterFixedAdapter(this, cbT); } diff --git a/packages/compiler/src/ir/int32-arrays.ts b/packages/compiler/src/ir/int32-arrays.ts index 353755c05..0677b2ad1 100644 --- a/packages/compiler/src/ir/int32-arrays.ts +++ b/packages/compiler/src/ir/int32-arrays.ts @@ -805,6 +805,41 @@ function rewriteCandidates( return { ...fn, body, locals: locals.filter((local) => !popLocals.has(local.id)) }; } +/** A module marked for its int32 array candidates: the candidates of + * each function (int32ArrayCandidates) and the element readers the marking + * inlines. */ +interface Int32ArrayMarking { + readonly mod: IrModule; + readonly readers: ReadonlyMap; + readonly candidates: ReadonlyMap>; +} + +/** markInt32ArrayCandidates with the candidates it marked; null when it + * marks none. */ +function markCandidates( + mod: IrModule, + keep: ReadonlySet | null, + redirected: ReadonlySet, +): Int32ArrayMarking | null { + if (mod.lib !== undefined) return null; + const readers = new Map(); + for (const fn of mod.functions) if (isElementReader(fn)) readers.set(fn.name, fn); + const all = moduleInt32ArrayCandidates(mod, new Set(readers.keys()), keep, redirected); + if (all.size === 0) return null; + const keys = new Set(); + const functions = mod.functions.map((fn) => { + const candidates = all.get(fn.name); + if (!candidates) return fn; + for (const id of candidates) keys.add(int32ArrayKey(fn.name, id)); + return rewriteCandidates(fn, candidates, readers); + }); + return { + mod: { ...mod, functions, int32ArrayCandidates: [...keys] }, + readers, + candidates: all, + }; +} + /** Propose the module's int32 array candidates (int32ArrayKey keys in * `int32ArrayCandidates`), only those in `keep` when given, and rewrite * their functions. */ @@ -813,42 +848,126 @@ export function markInt32ArrayCandidates( keep: ReadonlySet | null = null, redirected: ReadonlySet = new Set(), ): IrModule { - if (mod.lib !== undefined) return mod; - const readers = new Map(); - for (const fn of mod.functions) if (isElementReader(fn)) readers.set(fn.name, fn); - const all = moduleInt32ArrayCandidates(mod, new Set(readers.keys()), keep, redirected); - if (all.size === 0) return mod; - const keys = new Set(); - const functions = mod.functions.map((fn) => { - const candidates = all.get(fn.name); - if (!candidates) return fn; - for (const id of candidates) keys.add(int32ArrayKey(fn.name, id)); - return rewriteCandidates(fn, candidates, readers); - }); - return { ...mod, functions, int32ArrayCandidates: [...keys] }; + return markCandidates(mod, keep, redirected)?.mod ?? mod; +} + +/** Revises a function of a module marked for int32 array candidates when + * some of them drop: the function marked for its candidates outside + * `dropped` (int32ArrayKey keys), which is the unmarked function when none + * is left. */ +export type Int32ArrayRevision = (fnName: string, dropped: ReadonlySet) => IrFunction; + +/** What a proof of a marked module (selectInt32Arrays' `prove`) keeps. */ +export interface Int32ArrayProof { + /** The candidates it keeps. */ + readonly kept: ReadonlySet; + /** The functions of the module it proved, in module order, when it + * revised some through the Int32ArrayRevision it was given; otherwise + * null, for the marked module's own. */ + readonly functions: readonly IrFunction[] | null; } /** The module the backend emits: rewritten for exactly the candidates the - * int32 slot analysis (`prove`, returning its int32Arrays) keeps, so a - * module without int32 arrays is `mod` itself. A dropped candidate's - * rewrite is undone by marking again without it, until every candidate - * marked is kept. `redirected` names the functions some of whose calls the + * int32 slot analysis (`prove`) keeps, so a module without int32 arrays is + * `mod` itself. `redirected` names the functions some of whose calls the * backend emits as calls of another function (a result-slot entry): their - * parameters keep doubles. */ + * parameters keep doubles. + * + * The proof of the marked module gets an Int32ArrayRevision: as candidates + * drop, it revises their functions and goes on proving the revised module, + * so one analysis ends with the module marked for the candidates it keeps. + * That module is the answer when marking for those candidates again proposes + * exactly them, in the functions the proof revised. A proof that cannot + * follow a revision answers null; then each round marks the module, proves + * it without revisions, and marks again without the dropped candidates, + * until a round keeps every candidate it marks (four rounds at most). */ export function selectInt32Arrays( mod: IrModule, - prove: (marked: IrModule) => ReadonlySet, + prove: (marked: IrModule, revise: Int32ArrayRevision | null) => Int32ArrayProof | null, redirected: (mod: IrModule) => ReadonlySet = () => new Set(), ): IrModule { - let keep: ReadonlySet | null = null; const others = redirected(mod); - for (let round = 0; round < 4; round++) { + const marking = markCandidates(mod, null, others); + if (marking === null) return mod; + const original = new Map(mod.functions.map((fn) => [fn.name, fn])); + const markedFunctions = new Map(marking.mod.functions.map((fn) => [fn.name, fn])); + // Each function's latest revision and the candidates it is marked for. + const revisions = new Map }>(); + const revise: Int32ArrayRevision = (fnName, dropped) => { + const candidates = marking.candidates.get(fnName) ?? new Set(); + const ids = new Set(); + for (const id of candidates) if (!dropped.has(int32ArrayKey(fnName, id))) ids.add(id); + const latest = revisions.get(fnName); + if (latest !== undefined && latest.ids.size === ids.size) return latest.fn; + if (latest === undefined && ids.size === candidates.size) return markedFunctions.get(fnName)!; + const fn = + ids.size === 0 + ? original.get(fnName)! + : rewriteCandidates(original.get(fnName)!, ids, marking.readers); + revisions.set(fnName, { fn, ids }); + return fn; + }; + const proof = prove(marking.mod, revise); + const proposed = marking.mod.int32ArrayCandidates ?? []; + let keep: ReadonlySet | null = null; + let round = 0; + if (proof !== null && proof.functions === null) { + // The marked module itself was proved: the first round. + if (proposed.every((key) => proof.kept.has(key))) return marking.mod; + keep = new Set(proposed.filter((key) => proof.kept.has(key))); + round = 1; + } else if (proof !== null) { + const settled = settleRevisions(mod, marking, proof, revisions, others); + if (settled !== null) return settled; + } + for (; round < 4; round++) { const marked = markInt32ArrayCandidates(mod, keep, others); if (marked === mod) return mod; - const kept = prove(marked); - const proposed = marked.int32ArrayCandidates ?? []; - if (proposed.every((key) => kept.has(key))) return marked; - keep = new Set(proposed.filter((key) => kept.has(key))); + const kept = prove(marked, null)!.kept; + const roundProposed = marked.int32ArrayCandidates ?? []; + if (roundProposed.every((key) => kept.has(key))) return marked; + keep = new Set(roundProposed.filter((key) => kept.has(key))); } return mod; } + +/** The module marked for the candidates a revising proof kept, built from + * the functions it proved: null unless marking `mod` for those candidates + * proposes, in each function, exactly the candidates its proved function is + * marked for. `mod` itself when it proposes none. */ +function settleRevisions( + mod: IrModule, + marking: Int32ArrayMarking, + proof: Int32ArrayProof, + revisions: ReadonlyMap }>, + redirected: ReadonlySet, +): IrModule | null { + const kept = proof.kept; + const functions = proof.functions!; + if (functions.length !== mod.functions.length) return null; + const all = moduleInt32ArrayCandidates( + mod, + new Set(marking.readers.keys()), + new Set([...(marking.mod.int32ArrayCandidates ?? [])].filter((key) => kept.has(key))), + redirected, + ); + const keys = new Set(); + for (let i = 0; i < mod.functions.length; i++) { + const fn = mod.functions[i]!; + const proved = functions[i]!; + const candidates = all.get(fn.name); + const revision = revisions.get(fn.name); + const marked = revision?.ids ?? marking.candidates.get(fn.name) ?? new Set(); + if ((candidates?.size ?? 0) !== marked.size) return null; + if (candidates !== undefined) + for (const id of candidates) { + if (!marked.has(id)) return null; + keys.add(int32ArrayKey(fn.name, id)); + } + const expected = + revision?.fn ?? (marking.candidates.has(fn.name) ? marking.mod.functions[i]! : fn); + if (proved !== expected) return null; + } + if (all.size === 0) return mod; + return { ...mod, functions: [...functions], int32ArrayCandidates: [...keys] }; +} diff --git a/packages/compiler/src/ir/int32-slots.ts b/packages/compiler/src/ir/int32-slots.ts index 1616a2a77..af1ba36ac 100644 --- a/packages/compiler/src/ir/int32-slots.ts +++ b/packages/compiler/src/ir/int32-slots.ts @@ -27,7 +27,7 @@ import { int32ArraySlot, int32ArrayStores, } from "./int32-arrays.js"; -import { everyExprChild, everyStmtChild, everyTypeChild } from "./traverse.js"; +import { everyExprChild, everyStmtChild, everyStmtList, everyTypeChild } from "./traverse.js"; /** The storage slot an array-valued expression reads, as an * IrContracts.int32Elements key: a local or parameter @@ -352,6 +352,47 @@ export class Int32Slots { for (const params of this.paramFacts.values()) count += params.size; return count; } + + /** Every fact, in a canonical order, with each proven write as its + * position in `mod` (function index, then walk order): two analyses of + * equal modules hold the same facts when their summaries are equal. */ + summary(mod: IrModule): string { + const sorted = (values: Iterable): string => [...values].sort().join(","); + const lines = [ + `fields ${sorted(this.fields)}`, + `params ${sorted([...this.paramFacts].flatMap(([fn, params]) => [...params].map(([id, r]) => `${fn}\0${id}=${r.min}:${r.max}`)))}`, + `returns ${sorted(this.returns)}`, + `returnRanges ${sorted([...this.returnRanges].map(([fn, r]) => `${fn}=${r.min}:${r.max}`))}`, + `boxes ${sorted(this.boxes)}`, + `boxGroups ${sorted([...this.boxGroupOf].map(([member, group]) => `${member}=${group}`))}`, + `called ${sorted(this.called)}`, + `pinned ${sorted(this.pinned)}`, + `int32Locals ${sorted(this.int32Locals)}`, + `int32Elements ${sorted(this.int32Elements)}`, + `nonNegative ${sorted(this.nonNegative)}`, + `pinViolations ${sorted(this.pinViolations)}`, + `narrowedReads ${this.narrowedReads}`, + `int32Arrays ${sorted(this.int32Arrays)}`, + `checkedInt32Arrays ${sorted(this.checkedInt32Arrays)}`, + ]; + const positions: string[] = []; + mod.functions.forEach((fn, f) => { + let at = 0; + everyStmtList(fn.body, { + expr: (e) => { + if (this.provenWrites.has(e)) positions.push(`${f}:${at}`); + at++; + return true; + }, + stmt: () => { + at++; + return true; + }, + }); + }); + lines.push(`provenWrites ${this.provenWrites.size} ${positions.join(",")}`); + return lines.join("\n"); + } } const DYN_KINDS = new Set(["dyn", "jsval", "caught"]); @@ -833,6 +874,95 @@ export interface Int32SlotInputs { initializerBindings?: ReadonlyMap; /** The module's node index, read instead of walking the bodies. */ nodes?: IrNodeIndex; + /** Revises a function of a module marked for int32 array candidates when + * candidates drop (int32-arrays.ts Int32ArrayRevision): the function + * marked without the `dropped` candidates. With it, a candidate that drops + * (and keeps no checked stores) takes its sites back to the element-reader + * calls the marking inlined, and the fixpoint goes on over the revised + * functions, so its result is the analysis of the module marked for the + * candidates it keeps. A revision that changes more of a function than + * those sites throws Int32RevisionConflict. */ + revise?: (fnName: string, dropped: ReadonlySet) => IrFunction; +} + +/** A revision (Int32SlotInputs.revise) changed a function in a way the + * fixpoint cannot follow: a call of a function no other call reaches, or + * any change besides element-reader calls taking the place of their + * inlined reads. The module needs an analysis of its own. */ +export class Int32RevisionConflict extends Error {} + +/** What the analysis's setup reads from a function body, besides direct + * calls: a revision must leave all of it unchanged. */ +function revisionStructure(fn: IrFunction): { + calls: { callee: string; args: number }[]; + rest: string; +} { + const calls: { callee: string; args: number }[] = []; + const rest: string[] = []; + const boxed = new Set(fn.locals.filter((local) => local.boxed).map((local) => local.id)); + const expr = (e: IrExpr): boolean => { + const referenced = exprFunctionReference(e); + if (referenced !== undefined) rest.push(`ref:${referenced}`); + switch (e.kind) { + case "call": + calls.push({ callee: e.callee, args: e.args.length }); + break; + case "new": + rest.push(`new:${e.className}:${e.args.length}`); + break; + case "varRef": + if (boxed.has(e.localId)) rest.push(`read:${e.localId}`); + break; + case "assignExpr": + case "incDec": + rest.push(`${e.kind}:${e.localId}`); + break; + case "fieldGet": + case "fieldIncDec": + rest.push(`${e.kind}:${e.className}\0${e.field}`); + break; + case "closure": + rest.push(`closure:${e.fnName}:${e.captures.join(",")}`); + break; + case "classRef": + rest.push(`classRef:${e.className}:${(e.captures ?? []).join(",")}`); + break; + case "virtualCall": + rest.push(`virtualCall:${e.className}.${e.method}`); + break; + case "instanceOfValue": + rest.push(`instanceOf:${e.classValue.kind}`); + break; + } + if (BOUNDARY_KINDS.has(e.kind)) rest.push(`boundary:${e.kind}`); + return everyExprChild(e, expr, stmt); + }; + const stmt = (s: IrStmt): boolean => { + switch (s.kind) { + case "forOf": + rest.push(`forOf:${s.localId}`); + break; + case "tryCatch": + if (s.catchLocalId) rest.push(`catch:${s.catchLocalId}`); + break; + case "assign": + case "varDecl": + if (boxed.has(s.localId)) rest.push(`${s.kind}:${s.localId}`); + break; + case "throw": + rest.push("throw"); + break; + } + return everyStmtChild(s, expr, stmt); + }; + for (const s of fn.body) stmt(s); + rest.sort(); + for (const local of fn.locals) + if (local.boxed || local.tdz) + rest.push(`local:${local.id}:${local.boxed === true}:${local.tdz === true}`); + for (const capture of fn.captures ?? []) rest.push(`capture:${capture.localId}`); + for (const capture of fn.classCaptures ?? []) rest.push(`classCapture:${capture.localId}`); + return { calls, rest: rest.join("\n") }; } export function analyzeInt32Slots(mod: IrModule, inputs: Int32SlotInputs = {}): Int32Slots { @@ -1204,6 +1334,36 @@ export function analyzeInt32Slots(mod: IrModule, inputs: Int32SlotInputs = {}): }); return found; }; + // Candidates dropped without checked stores, and the revision of the + // functions that hold them (Int32SlotInputs.revise). + const dropped = new Set(); + const revise = (names: ReadonlySet): void => { + for (const name of names) { + const previous = functions.get(name)!; + const next = inputs.revise!(name, dropped); + if (next === previous) continue; + const before = revisionStructure(previous); + const after = revisionStructure(next); + if (before.rest !== after.rest) throw new Int32RevisionConflict(name); + // The revision adds the element-reader calls back: each must be of a + // function other calls already reach, with its arity. + const counts = new Map(); + for (const { callee } of before.calls) counts.set(callee, (counts.get(callee) ?? 0) + 1); + for (const { callee, args } of after.calls) { + const left = counts.get(callee) ?? 0; + if (left > 0) { + counts.set(callee, left - 1); + continue; + } + const target = functions.get(callee); + if (!called.has(callee) || target === undefined || target.params.length !== args) + throw new Int32RevisionConflict(name); + reads(`ret:${callee}`, name); + } + for (const left of counts.values()) if (left > 0) throw new Int32RevisionConflict(name); + functions.set(name, next); + } + }; const provenByFunction = new Map(); // Each function's parameter and result writes under its latest analysis: // at the fixpoint, the ranges of every write under the final facts. @@ -1248,6 +1408,8 @@ export function analyzeInt32Slots(mod: IrModule, inputs: Int32SlotInputs = {}): for (const id of globalArrays) both.add(id); arrays = both; } + // Functions whose candidates this visit drops, revised after it. + const revised = new Set(); if (arrays && arrayGroups) { const requeue = (name: string): void => { if (queued.has(name)) return; @@ -1282,9 +1444,39 @@ export function analyzeInt32Slots(mod: IrModule, inputs: Int32SlotInputs = {}): checkableInt32Allocations(fn, id) ) slots.checkedInt32Arrays.add(key); - else for (const member of group) reason(`array:${member}`, "an element store is not int32"); + else { + for (const member of group) reason(`array:${member}`, "an element store is not int32"); + if (inputs.revise !== undefined) { + // The revised module no longer marks the group: its functions + // leave the candidate sets the visits below consult. + for (const member of group) { + dropped.add(member); + if (member.startsWith("\0")) { + globalArrays.delete(member.slice(1)); + const names = arrayGroups.globalReaders.get(member); + if (names) for (const name of names) revised.add(name); + } else { + const cut = member.indexOf("\0"); + const owner = member.slice(0, cut); + const ids = arrayCandidates.get(owner); + ids?.delete(member.slice(cut + 1)); + if (ids?.size === 0) arrayCandidates.delete(owner); + revised.add(owner); + } + } + globalArrayFunctions.clear(); + for (const [member, names] of arrayGroups.globalReaders) + if (!dropped.has(member)) for (const name of names) globalArrayFunctions.add(name); + } + } } } + if (revised.size > 0) { + revise(revised); + // A revised body is analyzed again (it was queued with its readers); + // the writes of the body it replaces no longer count. + if (functions.get(fn.name) !== fn) continue; + } // An int32 written into a slot still assumed non-negative: widen the // assumption when the value may be negative, and reanalyze its readers. const settle = (slot: string, e: IrExpr): void => { diff --git a/packages/compiler/test/int32-element-array-emission.test.ts b/packages/compiler/test/int32-element-array-emission.test.ts index 605f64e04..fccf06973 100644 --- a/packages/compiler/test/int32-element-array-emission.test.ts +++ b/packages/compiler/test/int32-element-array-emission.test.ts @@ -3,8 +3,10 @@ import { tmpdir } from "node:os"; import { join } from "node:path"; import { expect, test } from "vitest"; import { compile, deserializeModule } from "../src/index.js"; -import type { IrModule } from "../src/ir/ir.js"; +import type { IrFunction, IrModule } from "../src/ir/ir.js"; import { markInt32ArrayCandidates, selectInt32Arrays } from "../src/ir/int32-arrays.js"; +import { analyzeInt32Slots, type Int32Slots } from "../src/ir/int32-slots.js"; +import { serializeModule } from "../src/ir/serialize.js"; async function emitLlvm(source: string): Promise { const dir = await mkdtemp(join(tmpdir(), "scriptc-int32-elements-")); @@ -210,12 +212,12 @@ test("only the candidates the proof keeps are rewritten", async () => { // An array that reaches `join` is never proposed. expect(proposed.some((key) => key.startsWith("joined\0"))).toBe(false); // Without a kept candidate, the module is the input itself. - expect(selectInt32Arrays(mod, () => new Set())).toBe(mod); + expect(selectInt32Arrays(mod, () => ({ kept: new Set(), functions: null }))).toBe(mod); const kept = new Set(["compose\0p.0", "compose\0q.0"]); - const selected = selectInt32Arrays( - mod, - (marked) => new Set((marked.int32ArrayCandidates ?? []).filter((key) => kept.has(key))), - ); + const selected = selectInt32Arrays(mod, (marked) => ({ + kept: new Set((marked.int32ArrayCandidates ?? []).filter((key) => kept.has(key))), + functions: null, + })); expect(selected.int32ArrayCandidates).toEqual([...kept]); for (const fn of selected.functions) if (fn.name !== "compose") expect(fn).toBe(mod.functions.find((f) => f.name === fn.name)); @@ -259,3 +261,47 @@ test("arrays passed to helpers and held in module globals get 4-byte slots", asy expect(functions(llvm, "mean")).not.toMatch(/getelementptr inbounds i32, ptr/); expect(llvm).toMatch(/@scr_arr_new(_small)?\(i32 7/); }); + +/** The module selectInt32Arrays selects, the analysis of its last proof, + * and how many proofs it asked for: with `revising`, each proof revises + * the functions of candidates that drop. */ +function selection( + mod: IrModule, + revising: boolean, +): { selected: IrModule; slots: Int32Slots; proofs: number } { + let slots: Int32Slots | null = null; + let proofs = 0; + const selected = selectInt32Arrays(mod, (marked, revise) => { + proofs++; + const latest = new Map(); + slots = analyzeInt32Slots( + marked, + revising && revise !== null + ? { + revise: (fnName, dropped) => { + const fn = revise(fnName, dropped); + latest.set(fnName, fn); + return fn; + }, + } + : {}, + ); + const kept = new Set([...slots.int32Arrays, ...slots.checkedInt32Arrays]); + if (latest.size === 0) return { kept, functions: null }; + return { kept, functions: marked.functions.map((fn) => latest.get(fn.name) ?? fn) }; + }); + return { selected, slots: slots!, proofs }; +} + +test("one proof that revises dropped candidates selects what rounds of proofs select", async () => { + for (const program of [source, sharedSource]) { + const mod = await lowerIr(program); + const rounds = selection(mod, false); + const revised = selection(mod, true); + // The rounds drop a candidate and prove the module again. + expect(rounds.proofs).toBeGreaterThan(1); + expect(revised.proofs).toBe(1); + expect(serializeModule(revised.selected, true)).toBe(serializeModule(rounds.selected, true)); + expect(revised.slots.summary(revised.selected)).toBe(rounds.slots.summary(rounds.selected)); + } +}); From 975270cef5a59ffe33821c8abe2be257dc141b24 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 03:02:53 -0500 Subject: [PATCH 226/259] Decode base64 eight characters at a time Buffer.from(text, "base64" | "base64url") decoded each four-character group with four lookups and a sign test, then stored its three bytes one at a time. The decoder now first takes complete groups two at a time: each character's value comes from a table that holds it already shifted into place within its group's 24 bits, a single bit test covers all eight characters, and each group's three bytes go out in one four-byte store whose last byte the next store overwrites. A group with any other character (padding, whitespace, an invalid character) takes the previous path, and the two-group step resumes after it, so line-wrapped text keeps most of the gain. The destination already holds two spare bytes, which cover the extra store byte. --- .../corpus/8006-buffer-base64-decode.ts.json | 6 ++ packages/runtime/src/scr_bytes.c | 66 ++++++++++++++++--- tests/corpus/8006-buffer-base64-decode.ts | 66 +++++++++++++++++++ .../8006-buffer-base64-decode.ts.json | 1 + 4 files changed, 129 insertions(+), 10 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8006-buffer-base64-decode.ts.json create mode 100644 tests/corpus/8006-buffer-base64-decode.ts create mode 100644 tests/harness/corpus-costs/8006-buffer-base64-decode.ts.json diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8006-buffer-base64-decode.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8006-buffer-base64-decode.ts.json new file mode 100644 index 000000000..135fe4af6 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8006-buffer-base64-decode.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8006-buffer-base64-decode.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_bytes.c b/packages/runtime/src/scr_bytes.c index 6b8594c08..31716604e 100644 --- a/packages/runtime/src/scr_bytes.c +++ b/packages/runtime/src/scr_bytes.c @@ -2672,20 +2672,66 @@ static ScrBytes *scr_bytes_conversion_storage(size_t capacity) { return scr_bytes_conversion_storage_in(NULL, capacity); } +/* scr_b64_values, each value shifted into its place in a four-character + * group's 24 bits; a character outside both alphabets sets bit 24. */ +#define SCR_B64_VALUE(c) \ + ((c) >= 'A' && (c) <= 'Z' ? (c) - 'A' \ + : (c) >= 'a' && (c) <= 'z' ? (c) - 'a' + 26 \ + : (c) >= '0' && (c) <= '9' ? (c) - '0' + 52 \ + : (c) == '+' || (c) == '-' ? 62 \ + : (c) == '/' || (c) == '_' ? 63 \ + : -1) +#define SCR_B64_AT(c, shift) \ + (SCR_B64_VALUE(c) < 0 ? UINT32_C(0x1000000) : (uint32_t)SCR_B64_VALUE(c) << (shift)) +#define SCR_B64_4(c, s) SCR_B64_AT(c, s), SCR_B64_AT(c + 1, s), SCR_B64_AT(c + 2, s), SCR_B64_AT(c + 3, s) +#define SCR_B64_16(c, s) SCR_B64_4(c, s), SCR_B64_4(c + 4, s), SCR_B64_4(c + 8, s), SCR_B64_4(c + 12, s) +#define SCR_B64_64(c, s) SCR_B64_16(c, s), SCR_B64_16(c + 16, s), SCR_B64_16(c + 32, s), SCR_B64_16(c + 48, s) +#define SCR_B64_256(s) SCR_B64_64(0, s), SCR_B64_64(64, s), SCR_B64_64(128, s), SCR_B64_64(192, s) +static const uint32_t scr_b64_shifted[4][256] = { + {SCR_B64_256(18)}, {SCR_B64_256(12)}, {SCR_B64_256(6)}, {SCR_B64_256(0)}}; + +/* One group's 24 bits as three bytes, in a four-byte store whose last byte + * the next store overwrites (the destination holds two spare bytes). */ +static inline void scr_b64_put_group(uint8_t *out, uint32_t bits) { +#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + uint32_t word = __builtin_bswap32(bits << 8); +#else + uint32_t word = bits << 8; +#endif + memcpy(out, &word, 4); +} + static ScrBytes *scr_bytes_decode_b64(ScrBytesSink *sink, const uint8_t *in, size_t n) { ScrBytes *b = scr_bytes_conversion_storage_in(sink, n / 4 * 3 + 2); + /* A local copy: a byte store could otherwise change b->data. */ + uint8_t *out = b->data; + const uint32_t(*t)[256] = scr_b64_shifted; size_t i = 0, o = 0; unsigned acc = 0, have = 0; while (i < n) { + /* Complete groups, two per step: each character's shifted value comes + * from a table and one bit test covers all eight. The second store + * ends at o + 6, within the destination while eight characters remain. */ + if (have == 0) { + while (n - i >= 8) { + uint32_t first = t[0][in[i]] | t[1][in[i + 1]] | t[2][in[i + 2]] | t[3][in[i + 3]]; + uint32_t second = t[0][in[i + 4]] | t[1][in[i + 5]] | t[2][in[i + 6]] | t[3][in[i + 7]]; + if ((first | second) & UINT32_C(0x1000000)) break; + scr_b64_put_group(out + o, first); + scr_b64_put_group(out + o + 3, second); + o += 6; + i += 8; + } + } /* Common complete groups need neither per-character branches nor state. */ if (have == 0 && n - i >= 4) { int a = scr_b64_values[in[i]], c = scr_b64_values[in[i + 1]]; int d = scr_b64_values[in[i + 2]], e = scr_b64_values[in[i + 3]]; if ((a | c | d | e) >= 0) { unsigned v = ((unsigned)a << 18) | ((unsigned)c << 12) | ((unsigned)d << 6) | (unsigned)e; - b->data[o++] = (uint8_t)(v >> 16); - b->data[o++] = (uint8_t)(v >> 8); - b->data[o++] = (uint8_t)v; + out[o++] = (uint8_t)(v >> 16); + out[o++] = (uint8_t)(v >> 8); + out[o++] = (uint8_t)v; i += 4; continue; } @@ -2696,17 +2742,17 @@ static ScrBytes *scr_bytes_decode_b64(ScrBytesSink *sink, const uint8_t *in, siz if (v < 0) continue; acc = (acc << 6) | (unsigned)v; if (++have == 4) { - b->data[o++] = (uint8_t)(acc >> 16); - b->data[o++] = (uint8_t)(acc >> 8); - b->data[o++] = (uint8_t)acc; + out[o++] = (uint8_t)(acc >> 16); + out[o++] = (uint8_t)(acc >> 8); + out[o++] = (uint8_t)acc; acc = 0; have = 0; } } - if (have == 2) b->data[o++] = (uint8_t)(acc >> 4); + if (have == 2) out[o++] = (uint8_t)(acc >> 4); else if (have == 3) { - b->data[o++] = (uint8_t)(acc >> 10); - b->data[o++] = (uint8_t)(acc >> 2); + out[o++] = (uint8_t)(acc >> 10); + out[o++] = (uint8_t)(acc >> 2); } b->len = o; return b; @@ -2764,7 +2810,7 @@ static ScrBytes *scr_bytes_encode_str(ScrBytesSink *sink, const ScrStr *s, const /* Node interprets encoded text as the low byte of each UTF-16 unit. * ASCII can borrow storage; non-ASCII must preserve that truncation. */ ScrBytes *narrowed = NULL; - if (scr_bytes_ascii_prefix(in, n) != n) { + if (!scr_str_known_ascii(s) && scr_bytes_ascii_prefix(in, n) != n) { ScrStr *latin1 = scr_str_new("latin1", 6); narrowed = scr_bytes_encode_str(NULL, s, latin1); scr_str_release(latin1); diff --git a/tests/corpus/8006-buffer-base64-decode.ts b/tests/corpus/8006-buffer-base64-decode.ts new file mode 100644 index 000000000..3d7b20303 --- /dev/null +++ b/tests/corpus/8006-buffer-base64-decode.ts @@ -0,0 +1,66 @@ +// Buffer.from(text, "base64" | "base64url") over complete eight-character +// blocks and the text around them: every length from 0 to 40, an invalid +// character at each position of a block, padding and text after it, both +// alphabets, line breaks every 76 characters, sizes around the pool +// threshold, and characters past U+00FF. + +let seed = 7; +function next(): number { + seed = (seed * 1103515245 + 12345) & 0x7fffffff; + return seed >>> 8; +} +function bytes(size: number): Buffer { + const buf = Buffer.alloc(size); + for (let i = 0; i < size; i++) buf[i] = next() & 255; + return buf; +} + +const rows: string[] = []; +for (let size = 0; size <= 30; size++) { + const buf = bytes(size); + const text = buf.toString("base64"); + const url = buf.toString("base64url"); + rows.push( + `${size}:${text.length}:${Buffer.from(text, "base64").equals(buf)}:${Buffer.from(url, "base64url").equals(buf)}:${Buffer.from(url, "base64").equals(buf)}`, + ); +} +console.log(rows.join(" ")); + +const block = Buffer.from("0123456789abcdefghijklmnopqrstuv").toString("base64"); +for (let at = 0; at < 16; at++) { + for (const bad of [" ", "\n", "*", "=", "é", "中"]) { + const text = block.slice(0, at) + bad + block.slice(at); + console.log(at, JSON.stringify(bad), Buffer.from(text, "base64").toString("hex")); + } +} + +for (const text of [ + "QUJDREVGR0g=", + "QUJDREVGR0", + "QUJDREVGR0g=QUJD", + "QUJD=REVGR0hJ", + "QUJDREVGR0hJSktM", + "QUJDREVGR0hJSktMTQ", + "QUJDREVGR0hJSktMTQ==", + "--__--__", + "++//++//", + "+-/_+-/_+-/_", + "Q U J D R E V G R 0 h J", + "QUJD\tREVG\r\nR0hJ", + "=QUJDREVGR0hJ", + "", +]) { + console.log(JSON.stringify(text), Buffer.from(text, "base64").toString("hex"), Buffer.from(text, "base64url").length); +} + +for (const size of [4095, 4096, 4097, 6144, 6145, 70000]) { + const buf = bytes(size); + const text = buf.toString("base64"); + const wrapped = text.replace(/.{76}/g, "$&\n"); + const decoded = Buffer.from(text, "base64"); + const unwrapped = Buffer.from(wrapped, "base64"); + console.log(size, decoded.length, decoded.equals(buf), unwrapped.equals(buf), Buffer.byteLength(text, "base64")); +} + +const wide = "QUJDREVGR0hJİSktM"; +console.log(Buffer.from(wide, "base64").toString("hex"), Buffer.from("ŁłQUJD", "base64").toString("hex")); diff --git a/tests/harness/corpus-costs/8006-buffer-base64-decode.ts.json b/tests/harness/corpus-costs/8006-buffer-base64-decode.ts.json new file mode 100644 index 000000000..88f85d0aa --- /dev/null +++ b/tests/harness/corpus-costs/8006-buffer-base64-decode.ts.json @@ -0,0 +1 @@ +{ "plain": 3995, "san": 2236 } From 493785a12166c34e1a85343de0cd6804ed4d7788 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 03:20:44 -0500 Subject: [PATCH 227/259] Test switch labels in copied callbacks that return early A lone array callback whose body has an early return is copied into an exit block, and its statements are renamed by a separate path from the single-return case. The new test covers labeled switches, a nested labeled switch and breaks to both labels in map and some callbacks that return early. Both calls run as loops, and the IR validator accepts every renamed break. --- .../test/array-pipeline-fusion.test.ts | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/packages/compiler/test/array-pipeline-fusion.test.ts b/packages/compiler/test/array-pipeline-fusion.test.ts index ba814105f..e41e378a3 100644 --- a/packages/compiler/test/array-pipeline-fusion.test.ts +++ b/packages/compiler/test/array-pipeline-fusion.test.ts @@ -213,3 +213,39 @@ console.log(out.join(",")); ${postlude}`); expect(helperCalls(init(mod))).toEqual(["%arr.loop"]); }); + +test("a copied callback with early returns keeps its switch labels", async () => { + const mod = await lowerSource(`${prelude} +const out = rows.map((r) => { + let n = 0; + outer: switch (r.id % 4) { + case 0: + return -1; + case 1: + n = 10; + break outer; + default: + inner: switch (r.value % 2) { + case 0: + n = r.value; + break outer; + default: + break inner; + } + n = 1; + } + return n; +}); +const hit = rows.some((r) => { + pick: switch (r.id) { + case 3: + break pick; + default: + return false; + } + return true; +}); +console.log(out.join(","), hit); +${postlude}`); + expect(helperCalls(init(mod))).toEqual(["%arr.loop", "%arr.loop"]); +}); From 2b11f14a041c49b64e304db16abdd9e1d830f7d8 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 03:21:25 -0500 Subject: [PATCH 228/259] Test that typed-array element descriptors are read through their getters Object.defineProperty on a typed-array index reads its descriptor with ToPropertyDescriptor (scr_dyn_descriptor_fields_read): every field once, in specification order, through its getter, and a primitive descriptor throws a TypeError. 7753 now also checks that the stored value is the value getter's result, read once; that a getter-produced writable: false is refused after the fields are read in order; and that null, booleans, BigInts and symbols are refused as descriptors. --- .../corpus/7753-typed-array-named-properties.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/tests/corpus/7753-typed-array-named-properties.js b/tests/corpus/7753-typed-array-named-properties.js index 449e78ac7..e37181a5e 100644 --- a/tests/corpus/7753-typed-array-named-properties.js +++ b/tests/corpus/7753-typed-array-named-properties.js @@ -27,6 +27,23 @@ function expandos(TA) { const got = []; Object.defineProperty(a, "1", { get value() { got.push("value"); return 6; }, get enumerable() { got.push("enumerable"); return true; } }); console.log(a[1], got); + // Each field is read once, through its getter; the stored value is the + // getter's result, and a getter-produced `writable: false` is refused. + let valueReads = 0; + Object.defineProperty(a, "1", { get value() { valueReads++; return 40 + valueReads; } }); + console.log(a[1], valueReads); + const order = []; + try { + Object.defineProperty(a, "1", { + get writable() { order.push("writable"); return false; }, + get value() { order.push("value"); return 2; }, + get configurable() { order.push("configurable"); return true; }, + }); + } catch (e) { console.log(e.constructor.name, e.message); } + console.log(a[1], order); + for (const bad of [null, true, 1n, Symbol("d")]) { + try { Object.defineProperty(a, "1", bad); } catch (e) { console.log(e.constructor.name); } + } for (const bad of [5, "x", undefined]) { try { Object.defineProperty(a, "0", bad); } catch (e) { console.log(e.constructor.name); } } From 342b770cf20a8b1ae124c5053b174ab18281177f Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 03:25:37 -0500 Subject: [PATCH 229/259] Keep a Map.get result owned when its key can replace the map's holder The receiver of a borrowed Map.get is read before its key. When the key's evaluation replaces the field or local that holds the map (`this.m.get(this.key())` where key() assigns this.m), the read runs on the old map, which only the statement still holds, and the borrowed value outlives it. A borrow now also requires the read itself, receiver and key included, to preserve reference edges; otherwise the read keeps its own reference. Corpus 8181 and the emission test cover a key method that replaces the field. --- .../src/backend/llvm/map-read-lifetimes.ts | 7 +++++-- .../test/map-get-borrow-emission.test.ts | 17 ++++++++++++++++- tests/corpus/8181-map-get-borrows.ts | 19 ++++++++++++++++++- 3 files changed, 39 insertions(+), 4 deletions(-) diff --git a/packages/compiler/src/backend/llvm/map-read-lifetimes.ts b/packages/compiler/src/backend/llvm/map-read-lifetimes.ts index 3371a7f70..d5d286674 100644 --- a/packages/compiler/src/backend/llvm/map-read-lifetimes.ts +++ b/packages/compiler/src/backend/llvm/map-read-lifetimes.ts @@ -186,8 +186,10 @@ function heldReceiver(expr: IrExpr): boolean { * branches and joins them; any other statement that names the local is * judged whole. A later pass of an enclosing loop declares the local again, * so only the rest of its own statement list matters. The map must be held - * by a local or a field (heldReceiver), and locals declared from the local - * count as its uses. An update such as + * by a local or a field (heldReceiver), the read itself must preserve + * reference edges (a key whose evaluation replaces the receiver's field + * leaves the read on a map the statement releases), and locals declared + * from the local count as its uses. An update such as * `const c = m.get(k); if (c === undefined) m.set(k, v); else c.n++` keeps * the borrow: the write runs only on the branch that does not read `c`. */ export function findMapReadBorrows( @@ -264,6 +266,7 @@ export function findMapReadBorrows( stmt.kind === "varDecl" && stmt.init?.kind === "mapIntrinsic" && heldReceiver(stmt.init.receiver) && + effects.preserves(stmt.init) && candidate(stmt) && walk(list.slice(index + 1), new Set([stmt.localId]), false) !== null ) diff --git a/packages/compiler/test/map-get-borrow-emission.test.ts b/packages/compiler/test/map-get-borrow-emission.test.ts index eba430453..4e3c91766 100644 --- a/packages/compiler/test/map-get-borrow-emission.test.ts +++ b/packages/compiler/test/map-get-borrow-emission.test.ts @@ -49,9 +49,20 @@ function temporary(keys: number[]): number { } return total; } +class Holder { + m = new Map([[1, new Counter()]]); + key(): number { + this.m = new Map(); + return 1; + } + read(): number { + const held = this.m.get(this.key()); + return held === undefined ? 0 : held.num; + } +} const numbers = new Map(); count(numbers, [1, 2, 1]); -console.log(named(new Map([["a", new Counter()]]), "a"), replaced(numbers), aliased(numbers), temporary([1, 2])); +console.log(named(new Map([["a", new Counter()]]), "a"), replaced(numbers), aliased(numbers), temporary([1, 2]), new Holder().read()); `, ); const result = await compile(entry, { outDir: dir, outPath, outputKind: "ir" }); @@ -72,6 +83,10 @@ console.log(named(new Map([["a", new Counter()]]), "a"), replaced(numbers), alia // does a read from a map that is released after the declaration. for (const name of ["replaced", "aliased", "temporary"]) expect(fn(name)).toContain("@sc_retain_Counter"); + // A key whose evaluation replaces the receiver's field leaves the read + // on the old map, which the statement releases: the read keeps its own + // reference. + expect(fn("_x25_Holder_read")).toContain("@sc_retain_Counter"); } finally { await rm(dir, { recursive: true, force: true }); } diff --git a/tests/corpus/8181-map-get-borrows.ts b/tests/corpus/8181-map-get-borrows.ts index 5df7ad226..1a6c71667 100644 --- a/tests/corpus/8181-map-get-borrows.ts +++ b/tests/corpus/8181-map-get-borrows.ts @@ -2,7 +2,8 @@ // release the entry's value: an update on the absent branch, a write, delete // or clear before a later read, a call that may change the map, loops, // string keys, values that are stored, returned or compared, a local declared -// from the read, and a read from a temporary map. +// from the read, a read from a temporary map, and a key that replaces the +// field holding the map. class Counter { num: number; label: string; @@ -153,3 +154,19 @@ function fromTemporary(): string { return held === undefined ? "none" : `${held.num}:${held.label}:${filler.length}`; } console.log("temporary", fromTemporary()); + +// A key whose evaluation replaces the field that holds the map: the read +// uses the old map, which only the statement still holds. +class Holder { + m = new Map([[1, new Counter(9, "nine")]]); + key(): number { + this.m = new Map(); + return 1; + } + read(): string { + const held = this.m.get(this.key()); + const filler = [new Counter(10, "filler"), new Counter(11, "filler")]; + return held === undefined ? "none" : `${held.num}:${held.label}:${filler.length}:${this.m.size}`; + } +} +console.log("replaced by key", new Holder().read()); From 9cb9750f92c6bd3daeb4d1c97ff888367073d9d9 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 03:34:33 -0500 Subject: [PATCH 230/259] Set a trusted build aside while a getter runs outside a visit session A getter or proxy trap that runs during a trusted build outside any visit session now runs with the build's state set aside, as inside a session. A conversion the getter starts, such as a recursive union that opens and ends its own session, no longer clears the mark that keeps the rest of the outer build from trusting its earlier match. --- packages/runtime/src/scr_json.c | 22 ++++++++---------- tests/harness/dyncheck.test.ts | 40 +++++++++++++++++++++++++++++++++ 2 files changed, 49 insertions(+), 13 deletions(-) diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index b0f4c99c4..9f10368cc 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -10932,9 +10932,9 @@ static void scr_dyn_visit_exit(void) { } /* Getters and proxy traps run user code, which may start conversions of - * its own and catch their failures. It runs with the session set aside, - * so its conversions use their own tables and leave the session's - * entries alone. */ + * its own and catch their failures. It runs with the session and any + * trusted build set aside, so its conversions use their own tables and + * leave the session's entries and the trusted build's state alone. */ typedef struct { size_t depth; ScrDynVisitSet matching, built, viewed; @@ -10977,12 +10977,10 @@ static void scr_dyn_visit_resume(const ScrDynVisitState *saved) { scr_dyn_session_ran_code = true; } -/* Calls a getter for a member read, outside any visit session. */ +/* Calls a getter for a member read, outside any visit session or trusted + * build. */ static ScrDyn *scr_dyn_visit_call_getter(ScrDyn *getter) { - if (scr_dyn_visit_depth == 0) { - if (scr_dyn_trusted) scr_dyn_session_ran_code = true; - return scr_dyn_call(getter, NULL, 0, "getter"); - } + if (scr_dyn_visit_depth == 0 && !scr_dyn_trusted) return scr_dyn_call(getter, NULL, 0, "getter"); ScrDynVisitState saved; scr_dyn_visit_suspend(&saved); ScrDyn *result = scr_dyn_call(getter, NULL, 0, "getter"); @@ -10990,12 +10988,10 @@ static ScrDyn *scr_dyn_visit_call_getter(ScrDyn *getter) { return result; } -/* A proxy's get trap for a member read, outside any visit session. */ +/* A proxy's get trap for a member read, outside any visit session or + * trusted build. */ static ScrDyn *scr_dyn_visit_proxy_get(const ScrDyn *d, ScrStr *name) { - if (scr_dyn_visit_depth == 0) { - if (scr_dyn_trusted) scr_dyn_session_ran_code = true; - return scr_dyn_proxy_get(d, name); - } + if (scr_dyn_visit_depth == 0 && !scr_dyn_trusted) return scr_dyn_proxy_get(d, name); ScrDynVisitState saved; scr_dyn_visit_suspend(&saved); ScrDyn *result = scr_dyn_proxy_get(d, name); diff --git a/tests/harness/dyncheck.test.ts b/tests/harness/dyncheck.test.ts index f38d8237d..8dde55167 100644 --- a/tests/harness/dyncheck.test.ts +++ b/tests/harness/dyncheck.test.ts @@ -686,6 +686,46 @@ console.log(JSON.stringify(plain)); ]); }); + test("nested unions: a getter that converts a recursive union keeps a non-recursive build untrusted", async () => { + // The getter converts a recursive union, which opens and ends a visit + // session of its own, before it answers. The outer build still matches + // the getter's second answer in full, and the failure names that union. + const r = await compileAndRun( + "flat-discriminated-getter-session", + `type Tree = { kind: "leaf"; n: number } | { kind: "node"; left: Tree; right: Tree }; +type Inner = { tag: "x"; n: number } | { tag: "y"; s: string }; +type Outer = { kind: "a"; inner: Inner } | { kind: "b"; other: number }; +const v = JSON.parse('{"kind":"a"}') as unknown; +let calls = 0; +let leaves = 0; +Object.defineProperty(v, "inner", { + enumerable: true, + get() { + calls++; + const t = JSON.parse('{"kind":"node","left":{"kind":"leaf","n":1},"right":{"kind":"leaf","n":2}}') as Tree; + if (t.kind === "node") leaves += 2; + return calls === 1 ? JSON.parse('{"tag":"x","n":1}') : JSON.parse('{"tag":"x","n":"bad"}'); + }, +}); +try { + const o = v as Outer; + console.log("ok", JSON.stringify(o)); +} catch (err) { + console.log((err as Error).message); +} +console.log("getter calls", calls, "leaves", leaves); +const plain = JSON.parse('{"kind":"a","inner":{"tag":"y","s":"z"}}') as Outer; +console.log(JSON.stringify(plain)); +`, + ); + expect(r.exitCode).toBe(0); + expect(r.stdout.trimEnd().split("\n")).toEqual([ + "expected object | object at $.inner, got object", + "getter calls 2 leaves 4", + '{"kind":"a","inner":{"tag":"y","s":"z"}}', + ]); + }); + test("array where a record is expected names the mismatch at the root", async () => { const r = await compileAndRun( "root-kind", From e38f7c329d4119ef3629e5eed802cbe6f8176d57 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 03:56:48 -0500 Subject: [PATCH 231/259] Speculate floor-mods and products by powers of two as masks and shifts In a speculative integer loop, `v - Math.floor(v / 2^n) * 2^n` computed the floor division as an arithmetic shift, multiplied it back by 2^n with overflow and -0 checks, and subtracted with range checks. For a safe integer v and n in [0, 52] the result is the floor-mod, which is v's low n bits: the fast copy now computes it as `v & (2^n - 1)`, which lies in [0, 2^n) and needs no check. A product with a power of two (a literal or `Math.pow(2, n)`) becomes a shift, with one test that the other factor's magnitude is at most (2^53 - 1) >> n; its zero result is +0. --- .../src/backend/llvm/speculative-integers.ts | 62 +++++++++++++ .../test/speculative-loop-emission.test.ts | 24 +++++ .../8244-speculative-floor-mod-powers.ts.json | 6 ++ .../8244-speculative-floor-mod-powers.ts | 88 +++++++++++++++++++ 4 files changed, 180 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8244-speculative-floor-mod-powers.ts.json create mode 100644 tests/corpus/8244-speculative-floor-mod-powers.ts diff --git a/packages/compiler/src/backend/llvm/speculative-integers.ts b/packages/compiler/src/backend/llvm/speculative-integers.ts index 07e5e3721..971bd00cb 100644 --- a/packages/compiler/src/backend/llvm/speculative-integers.ts +++ b/packages/compiler/src/backend/llvm/speculative-integers.ts @@ -187,6 +187,37 @@ function exactPowerOfTwo(value: number): number | null { return k >= 0 && k <= 52 && 2 ** k === value ? k : null; } +/** The same speculated operand written twice: a local, a literal, or a + * power of two of the same exponent. */ +function sameOperand(a: IrExpr, b: IrExpr): boolean { + if (a.kind === "varRef") return b.kind === "varRef" && a.localId === b.localId; + if (a.kind === "numLit") return b.kind === "numLit" && Object.is(a.value, b.value); + return ( + a.kind === "libCall" && + b.kind === "libCall" && + a.fn === "math.pow" && + b.fn === "math.pow" && + powerOfTwo(a) && + powerOfTwo(b) && + sameOperand(a.args[1]!, b.args[1]!) + ); +} + +/** `a - Math.floor(a / p) * p` (either factor order) with p a power of two + * and `a` a local or literal: the floor-mod of `a` by p. */ +function floorModPowerOfTwo(e: IrExpr): { value: IrExpr; power: IrExpr } | null { + if (e.kind !== "bin" || e.op !== "-" || e.right.kind !== "bin" || e.right.op !== "*") return null; + const { left, right } = e.right; + const [floor, power] = + left.kind === "libCall" && left.fn === "math.floor" ? [left, right] : [right, left]; + if (floor.kind !== "libCall" || floor.fn !== "math.floor" || floor.args.length !== 1) return null; + const quotient = floor.args[0]!; + if (quotient.kind !== "bin" || quotient.op !== "/") return null; + if (!powerOfTwo(power) || !sameOperand(quotient.right, power)) return null; + if (e.left.kind !== "varRef" && e.left.kind !== "numLit") return null; + return sameOperand(quotient.left, e.left) ? { value: e.left, power } : null; +} + /** Whether `e` is a power of two speculation can shift by: * `Math.pow(2, n)` or a literal 2^k with k in [0, 52]. */ function powerOfTwo(e: IrExpr): boolean { @@ -950,6 +981,37 @@ export function emitSpeculativeInteger( } case "bin": { if (e.op !== "+" && e.op !== "-" && e.op !== "*" && e.op !== "%") break; + // The floor-mod of a safe integer by 2^n (n in [0, 52]) is its low n + // bits, also for a negative value: in [0, 2^n), and never -0. + const mod = floorModPowerOfTwo(e); + if (mod) { + const value = emitSpeculativeInteger(host, mod.value, bail, reads, integral); + const n = exponentOf(host, mod.power, bail, reads, integral); + const mask = B.tmp(), + low = B.tmp(); + B.line(`${mask} = sub i64 ${shiftOne(host, n)}, 1`); + B.line(`${low} = and i64 ${value}, ${mask}`); + return low; + } + // A product with 2^n shifts: it is safe iff the other factor's + // magnitude is at most (2^53 - 1) >> n, and a zero product of a safe + // integer and a positive power is +0. + if (e.op === "*" && (powerOfTwo(e.right) || powerOfTwo(e.left))) { + const [factor, power] = powerOfTwo(e.right) ? [e.left, e.right] : [e.right, e.left]; + const value = emitSpeculativeInteger(host, factor, bail, reads, integral); + const n = exponentOf(host, power, bail, reads, integral); + const limit = B.tmp(), + magnitude = B.tmp(), + outside = B.tmp(), + product = B.tmp(); + B.line(`${limit} = ashr i64 ${SAFE}, ${n}`); + host.declare("declare i64 @llvm.abs.i64(i64, i1)"); + B.line(`${magnitude} = call i64 @llvm.abs.i64(i64 ${value}, i1 true)`); + B.line(`${outside} = icmp ugt i64 ${magnitude}, ${limit}`); + bail(outside); + B.line(`${product} = shl nsw i64 ${value}, ${n}`); + return product; + } const a = emitSpeculativeInteger(host, e.left, bail, reads, integral); const b = emitSpeculativeInteger(host, e.right, bail, reads, integral); const result = B.tmp(); diff --git a/packages/compiler/test/speculative-loop-emission.test.ts b/packages/compiler/test/speculative-loop-emission.test.ts index 748fd50c5..d26a0c96c 100644 --- a/packages/compiler/test/speculative-loop-emission.test.ts +++ b/packages/compiler/test/speculative-loop-emission.test.ts @@ -159,3 +159,27 @@ if (isMainThread) { expect(order.slice(slow, fast).some((l) => l.startsWith("spec.fast"))).toBe(true); expect(order.slice(fast).some((l) => l.startsWith("spec.fast"))).toBe(true); }); + +test("a floor-mod by a power of two speculates as a mask and a product by one as a shift", async () => { + const llvm = await emitLlvm(` +function trim(value: number, bits: number): number { + return value - Math.floor(value / Math.pow(2, bits)) * Math.pow(2, bits); +} +function key(bytes: Uint8Array, bits: number): number { + let k = 0; + for (let i = 0; i < bytes.length; i++) k = trim(k, bits) * 4 + bytes[i]!; + return k; +} +console.log(key(new Uint8Array([1, 2, 3, 0]), 6)); +`); + const fn = /^define internal double @sc_bf_\w*key[\w.]*\([^]*?^}/m.exec(llvm)?.[0] ?? ""; + const fast = fn.slice(fn.search(/^spec\.fast\d+:/m)); + expect(fast.length).toBeLessThan(fn.length); + // trim(k, bits): the low `bits` bits; * 4: a shift by two. + expect(fast).toMatch(/= sub i64 %\S+, 1\n\s+%\S+ = and i64 %\S+, %\S+\n/); + expect(fast).toMatch(/= shl nsw i64 %\S+, 2\n/); + // No floor division of k (an arithmetic shift of it) and no checked + // multiply remain. + expect(fast).not.toMatch(/ashr i64 %/); + expect(fast).not.toContain("@llvm.smul.with.overflow.i64"); +}); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8244-speculative-floor-mod-powers.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8244-speculative-floor-mod-powers.ts.json new file mode 100644 index 000000000..65e7ccb38 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8244-speculative-floor-mod-powers.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8244-speculative-floor-mod-powers.ts" + ], + "diags": [] +} diff --git a/tests/corpus/8244-speculative-floor-mod-powers.ts b/tests/corpus/8244-speculative-floor-mod-powers.ts new file mode 100644 index 000000000..db28dcde0 --- /dev/null +++ b/tests/corpus/8244-speculative-floor-mod-powers.ts @@ -0,0 +1,88 @@ +// Integer loops whose writes take a floor-mod by a power of two +// (`v - Math.floor(v / 2^n) * 2^n`) or multiply by one: negative and zero +// values, exponents 0, 52 and above, literal powers, both factor orders, +// fractional values and results past 2^53, which leave the integer copy. + +function trim(value: number, bits: number): number { + return value - Math.floor(value / Math.pow(2, bits)) * Math.pow(2, bits); +} + +function low3(value: number): number { + return value - Math.floor(value / 8) * 8; +} + +function rolling(bytes: Uint8Array, bits: number): number { + let key = 0; + let sum = 0; + for (let i = 0; i < bytes.length; i++) { + key = trim(key, bits) * 4 + bytes[i]!; + sum = (sum + key) % 1000003; + } + return key * 7 + sum; +} + +function stepped(start: number, step: number, bits: number, count: number): number { + let v = start; + let h = 0; + for (let i = 0; i < count; i++) { + v = trim(v, bits) * 3 - step; + h = (h * 31 + v) % 999983; + } + return h * 1000 + v; +} + +function literal(start: number, count: number): number { + let v = start; + let h = 0; + for (let i = 0; i < count; i++) { + v = low3(v) * 16 - i; + h = (h * 17 + v) % 65521; + } + return h * 100 + v; +} + +function scaled(start: number, bits: number, count: number): number { + let v = start; + let h = 0; + for (let i = 0; i < count; i++) { + v = Math.pow(2, bits) * v + 1; + h = (h * 7 + v) % 10007; + } + return h + v; +} + +function shifted(start: number, count: number): number { + let v = start; + let h = 0; + for (let i = 0; i < count; i++) { + v = v * 1024 - i; + h = (h * 3 + v) % 101; + } + return h + v; +} + +const bytes = new Uint8Array(4000); +for (let i = 0; i < bytes.length; i++) bytes[i] = (i * 7 + (i >> 3)) & 3; + +for (const bits of [0, 1, 2, 10, 22, 34, 50, 52, 53, 60]) console.log("rolling", bits, rolling(bytes, bits)); +for (const [start, step, bits] of [ + [0, 1, 3], + [-5, 3, 2], + [-1, -1, 0], + [123456789, 7, 20], + [-9007199254740991, 1, 52], + [2.5, 1, 4], + [7, 0.5, 3], +] as const) + console.log("stepped", start, step, bits, stepped(start, step, bits, 50)); +for (const start of [0, 13, -13, 4096, -7.25]) console.log("literal", start, literal(start, 40)); +for (const [start, bits] of [ + [1, 3], + [-2, 5], + [0, 52], + [3, 20], + [-1, 0], +] as const) + console.log("scaled", start, bits, scaled(start, bits, 6)); +for (const start of [0, 1, -1, 3, 1e6]) console.log("shifted", start, shifted(start, 7)); +console.log(Object.is(stepped(0, 0, 3, 5), 0), Object.is(scaled(0, 2, 3), 21 + 1)); From 45171ea02cb01c5d8b2683a7195623464d8d8bcc Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 03:59:10 -0500 Subject: [PATCH 232/259] Use a built-in typed-array constructor as its own species before the species symbol exists A typed array whose constructor property is set to another built-in typed-array constructor now creates that kind from map, filter, slice and subarray when the program has not evaluated Symbol.species. --- packages/runtime/src/scr_json.c | 7 ++++-- .../8321-typed-array-constructor-kind.js | 23 +++++++++++++++++++ 2 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 tests/corpus/8321-typed-array-constructor-kind.js diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index f06080ef6..6e0ca43c0 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -5345,9 +5345,12 @@ static ScrDyn *scr_bytes_species(ScrDyn *recv, bool *failed) { *failed = true; return NULL; } - ScrDyn *species = scr_species_symbol ? scr_dyn_symbol_key_get(constructor, scr_species_symbol, true) : NULL; + /* Before the program creates the species symbol, no constructor can have + * a Symbol.species property of its own. */ + ScrDyn *species = scr_species_symbol ? scr_dyn_symbol_key_get(constructor, scr_species_symbol, true) + : scr_dyn_retain(scr_dyn_undefined()); if (species && species->kind == SCR_DYN_UNDEF && scr_bytes_ctor_elem(constructor) >= 0 && - !scr_bytes_ctor_own_species(constructor)) { + (!scr_species_symbol || !scr_bytes_ctor_own_species(constructor))) { /* A built-in typed-array constructor inherits %TypedArray%'s species * getter, which returns the constructor itself. */ scr_dyn_release(species); diff --git a/tests/corpus/8321-typed-array-constructor-kind.js b/tests/corpus/8321-typed-array-constructor-kind.js new file mode 100644 index 000000000..277128a93 --- /dev/null +++ b/tests/corpus/8321-typed-array-constructor-kind.js @@ -0,0 +1,23 @@ +// A built-in typed-array constructor set as a view's `constructor` is the +// species of map, filter, slice and subarray when the program never names +// the species symbol. +function kinds(TA, Other) { + const a = new TA([1, 2, 3, 4]); + a.constructor = Other; + const m = a.map((v) => v * 1.5), f = a.filter((v) => v > 1), s = a.slice(1, 3); + console.log(m, f, s, m.constructor === Other, f.constructor === Other, s.constructor === Other); + try { + const sub = a.subarray(0, 2); + console.log(sub, sub.constructor === Other); + } catch (err) { + console.log(err.constructor.name); + } + a.constructor = TA; + console.log(a.map((v) => v / 2).constructor === TA); + a.constructor = {}; + console.log(a.slice().constructor === TA); +} +kinds(Uint8Array, Float64Array); +kinds(Int16Array, Uint8Array); +kinds(Float32Array, Int32Array); +kinds(Float64Array, Uint8ClampedArray); From 0d4df6ff6202ae01094be725890c38c3493ee8d6 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 04:14:58 -0500 Subject: [PATCH 233/259] Skip fork discovery in programs that never name node:child_process forkTargetPaths asked the checker for the symbol of every identifier callee in every implementation file, on each root-discovery pass and twice more in preflight, to find calls of child_process.fork. A call is a fork only through a binding whose import or alias chain names the module in a module specifier, or through a '#' specifier a package.json "imports" field maps. namesChildProcess reads every program file once per program, outside Node's type declarations and scriptc's own declaration files, which declare the module and alias it only as node:child_process. Implementation files are read from their syntax trees, which discovery fetches anyway; other files as the host serves them to the server (the new Ts7Program.getSourceText), without fetching their syntax trees. When no file holds "child_process" in its text, an escape or line continuation that spells it, or an "imports" entry that names it, forkTargetPaths answers no targets without querying the checker. The discovered fork targets are unchanged. --- .../compiler/src/frontend/fork-target.test.ts | 53 +++++++++++++ packages/compiler/src/frontend/fork-target.ts | 77 ++++++++++++++++++- .../compiler/src/frontend/program-analysis.ts | 3 + packages/compiler/src/frontend/resolve.ts | 6 ++ .../compiler/src/frontend/ts7/program-host.ts | 52 ++++++++----- 5 files changed, 172 insertions(+), 19 deletions(-) diff --git a/packages/compiler/src/frontend/fork-target.test.ts b/packages/compiler/src/frontend/fork-target.test.ts index 5e56cea5d..ffe01ee47 100644 --- a/packages/compiler/src/frontend/fork-target.test.ts +++ b/packages/compiler/src/frontend/fork-target.test.ts @@ -65,3 +65,56 @@ test("fork discovery batches only candidate bindings and preserves aliases and s rmSync(directory, { recursive: true, force: true }); } }); + +/** forkTargetPaths over the entry of a program made of `files`, and + * whether it asked the checker for any binding. */ +function discover(files: Record): { targets: string[]; queried: boolean } { + const directory = mkdtempSync(join(tmpdir(), "scriptc-fork-gate-")); + for (const [name, text] of Object.entries(files)) writeFileSync(join(directory, name), text); + const entry = join(directory, "main.ts"); + const host = new Ts7Host((options) => new Ts7Api(options), { cwd: directory }); + const program = host.createProgram([entry, fallbackDtsPath()], { + noLib: true, + types: [], + module: ModuleKind.ESNext, + moduleResolution: ModuleResolutionKind.Bundler, + }); + const batch = vi.spyOn(program.getTypeChecker(), "prefetchSymbolNodesExact"); + try { + const targets = forkTargetPaths(program, [program.getSourceFile(entry)!]).map((path) => + path.slice(directory.length + 1), + ); + return { targets, queried: batch.mock.calls.length > 0 }; + } finally { + batch.mockRestore(); + program.dispose(); + host.close(); + rmSync(directory, { recursive: true, force: true }); + } +} + +test("fork discovery asks the checker nothing when no file names node:child_process", () => { + expect( + discover({ + "main.ts": + 'function fork(url: URL) { return url; }\nfork(new URL("./child.ts", import.meta.url));\n', + }), + ).toEqual({ targets: [], queried: false }); +}); + +test("fork discovery reads a module specifier spelled with escapes", () => { + expect( + discover({ + "main.ts": + 'import { fork } from "node:child\\u005fprocess";\nfork(new URL("./child.ts", import.meta.url));\n', + }), + ).toEqual({ targets: ["child.ts"], queried: true }); +}); + +test("fork discovery reads a package imports entry that maps node:child_process", () => { + const result = discover({ + "package.json": JSON.stringify({ type: "module", imports: { "#cp": "node:child_process" } }), + "main.ts": 'import { fork } from "#cp";\nfork(new URL("./child.ts", import.meta.url));\n', + }); + expect(result.queried).toBe(true); +}); diff --git a/packages/compiler/src/frontend/fork-target.ts b/packages/compiler/src/frontend/fork-target.ts index 38c8f5f07..93fc7c244 100644 --- a/packages/compiler/src/frontend/fork-target.ts +++ b/packages/compiler/src/frontend/fork-target.ts @@ -1,7 +1,14 @@ import { resolve } from "node:path"; import { fileURLToPath, pathToFileURL } from "node:url"; import * as ts from "./ts7/adapter.js"; -import { fallbackDtsPath, isNodeTypesPath, tsgoPath } from "./dts-paths.js"; +import { + ambientDtsPath, + fallbackDtsPath, + isNodeTypesPath, + overridesDtsPath, + tsgoPath, +} from "./dts-paths.js"; +import { nearestPackageImports } from "./resolve.js"; import { canonicalBuiltinModule } from "./builtin-modules.js"; import { moduleSourceCandidates } from "./module-source-candidates.js"; @@ -292,9 +299,77 @@ export function forkCallModulePath(program: ts.Program, call: ts.CallExpression) return staticForkModulePath(program, call.arguments.nodes[0]); } +/** The ways a string or template literal can spell one character of a + * module name: the character, \xHH, \uHHHH, \u{H…}, a legacy octal escape, + * or the character after a backslash where that is not another escape. */ +function spelledCharacter(ch: string): string { + const code = ch.charCodeAt(0); + const hex = code.toString(16); + const forms = [ + ch, + "\\\\x" + hex.padStart(2, "0"), + "\\\\u" + hex.padStart(4, "0"), + "\\\\u\\{0*" + hex + "\\}", + "\\\\" + code.toString(8), + ]; + if (!"bfnrtvux0123456789".includes(ch)) forms.push("\\\\" + ch); + return "(?:" + forms.join("|") + ")"; +} + +/** "child_process" with escapes and line continuations in any of its + * characters (case-insensitive, a superset). */ +const SPELLED_CHILD_PROCESS = new RegExp( + [..."child_process"].map(spelledCharacter).join("(?:\\\\(?:\\r\\n|[\\n\\r\\u2028\\u2029]))*"), + "i", +); + +/** Whether a call in the program can reach node:child_process's fork. A + * fork binding is an import or alias whose chain names the module in a + * module specifier (a string), or a '#' specifier the nearest package.json + * "imports" field maps. Node's type declarations and scriptc's own declare + * the module, and alias it only as node:child_process, so they are not + * read; any other file that names the module in a string holds + * "child_process" in its text, or an escape that spells it. */ +function namesChildProcess(program: ts.Program): boolean { + const known = program.analysis.namesChildProcess; + if (known !== null) return known; + const own = new Set([ambientDtsPath(), overridesDtsPath(), fallbackDtsPath()]); + // Implementation files are already fetched; any other file is read as + // the host serves it, without fetching its syntax tree. + const texts = new Map(); + for (const sourceFile of program.getImplementationSourceFiles()) + texts.set(tsgoPath(sourceFile.fileName), sourceFile.text); + const scopes = new Set(); + let names = false; + for (const fileName of program.getSourceFileNames()) { + const path = tsgoPath(fileName); + if (isNodeTypesPath(fileName) || own.has(path)) continue; + const text = texts.get(path) ?? program.getSourceText(fileName) ?? ""; + if ( + text.includes("child_process") || + (text.includes("\\") && SPELLED_CHILD_PROCESS.test(text)) + ) { + names = true; + break; + } + const imports = nearestPackageImports(fileName); + if (imports === undefined || scopes.has(imports)) continue; + scopes.add(imports); + if (JSON.stringify(imports).includes("child_process")) { + names = true; + break; + } + } + program.analysis.namesChildProcess = names; + return names; +} + /** Source-order static fork targets in the supplied files, deduplicated by * resolved path. */ export function forkTargetPaths(program: ts.Program, files: readonly ts.SourceFile[]): string[] { + // Without a binding of node:child_process no call is a fork, and the + // checker queries below are skipped. + if (!namesChildProcess(program)) return []; const targets: string[] = []; const seen = new Set(); for (const sourceFile of files) { diff --git a/packages/compiler/src/frontend/program-analysis.ts b/packages/compiler/src/frontend/program-analysis.ts index d4ec9fa98..475942908 100644 --- a/packages/compiler/src/frontend/program-analysis.ts +++ b/packages/compiler/src/frontend/program-analysis.ts @@ -25,6 +25,8 @@ export class ProgramAnalysis { /** The modules of every import cycle the exact initialization rule admitted. */ readonly exactCycleMembers = new Set(); cycleEarlyBindings: EarlyBindingsMemo | null = null; + /** Whether some program file can name node:child_process (namesChildProcess). */ + namesChildProcess: boolean | null = null; moduleEarlyBindings: EarlyBindingsMemo | null = null; /** Top-level require declarations: the first reference to their bindings * that code running before the require can reach (requireEarlyReference). */ @@ -46,6 +48,7 @@ export class ProgramAnalysis { this.moduleSourceCandidates.clear(); this.exactCycleMembers.clear(); this.cycleEarlyBindings = null; + this.namesChildProcess = null; this.moduleEarlyBindings = null; this.requireEarlyReferences.clear(); this.requireFirstRunnable.clear(); diff --git a/packages/compiler/src/frontend/resolve.ts b/packages/compiler/src/frontend/resolve.ts index 3b32dad3a..5b035b6cb 100644 --- a/packages/compiler/src/frontend/resolve.ts +++ b/packages/compiler/src/frontend/resolve.ts @@ -562,6 +562,12 @@ export function nearestPkgJsonPath(fromFile: string): string | null { return dir === null ? null : join(dir, "package.json"); } +/** The nearest package scope's "imports" field (undefined without one). */ +export function nearestPackageImports(fromFile: string): unknown { + const dir = nearestPkgDir(dirname(resolve(fromFile))); + return dir === null ? undefined : pkgJsonOf(dir)?.imports; +} + /** The target the nearest package scope's "imports" field maps a '#' * specifier to under Node's ESM runtime conditions: a './' path inside the * package or another package's specifier. Null when no entry maps it. */ diff --git a/packages/compiler/src/frontend/ts7/program-host.ts b/packages/compiler/src/frontend/ts7/program-host.ts index e66d598d9..84cbe2474 100644 --- a/packages/compiler/src/frontend/ts7/program-host.ts +++ b/packages/compiler/src/frontend/ts7/program-host.ts @@ -152,33 +152,37 @@ export class Ts7Host { private readonly virtualChanges = new Map(); private readonly closingProjects = new Set(); private readonly api: Ts7Api; + /** The text the server reads for a file (its readFile hook). */ + private readonly readSource: (fileName: string) => string | null; private closed = false; constructor(createApi: Ts7ApiFactory, options?: Ts7HostOptions) { const virtualFiles = this.virtualFiles; const shadow = options?.fsShadow ?? null; + // A virtual file, a shadow's replacement, a package shim's declaration + // entry or the file on disk; null when shadowed out of existence or + // missing. + this.readSource = (fileName) => { + const virtual = virtualFiles.get(tsgoPath(fileName)); + if (virtual !== undefined) return stripSourceBom(virtual); + if (shadow !== null) { + if (shadow.hideFile(fileName)) return null; + const replacement = shadow.readFile(fileName); + if (replacement !== undefined) return stripSourceBom(replacement); + } + // A package scriptc implements itself (package-shims.ts): its + // installed declaration entry re-exports the shim module, in every + // program the host creates. + const shim = packageShimDeclarationText(fileName); + if (shim !== undefined) return shim; + const source = trackedReadFile(fileName); + return source === null ? null : stripSourceBom(source); + }; this.api = createApi({ cwd: options?.cwd ?? process.cwd(), collectTiming: options?.collectTiming ?? false, fs: { - // string => virtual (or shadowed) hit; null => shadowed out of - // existence; undefined => real-FS fallthrough. - readFile: (fileName) => { - const virtual = virtualFiles.get(tsgoPath(fileName)); - if (virtual !== undefined) return stripSourceBom(virtual); - if (shadow !== null) { - if (shadow.hideFile(fileName)) return null; - const replacement = shadow.readFile(fileName); - if (replacement !== undefined) return stripSourceBom(replacement); - } - // A package scriptc implements itself (package-shims.ts): its - // installed declaration entry re-exports the shim module, in every - // program the host creates. - const shim = packageShimDeclarationText(fileName); - if (shim !== undefined) return shim; - const source = trackedReadFile(fileName); - return source === null ? null : stripSourceBom(source); - }, + readFile: this.readSource, fileExists: (fileName) => { if (virtualFiles.has(tsgoPath(fileName))) return true; if (shadow !== null && shadow.hideFile(fileName)) return false; @@ -193,6 +197,12 @@ export class Ts7Host { }); } + /** The text this host serves for a file (null when it serves none), + * without asking the server for its syntax tree. */ + sourceText(fileName: string): string | null { + return this.readSource(fileName); + } + /** Registers an in-memory file served to tsgo by the virtual-FS hooks. */ addVirtualFile(path: string, content: string): void { this.ensureOpen(); @@ -315,6 +325,12 @@ export class Ts7Program { return this.project.program.getSourceFile(resolve(fileName)); } + /** A file's text as the host serves it, without fetching its syntax + * tree (Ts7Host.sourceText). */ + getSourceText(fileName: string): string | null { + return this.host.sourceText(fileName); + } + getSourceFileNames(): readonly string[] { this.snapshot.ensureActive(); return (this.sourceFileNamesCache ??= this.project.program.getSourceFileNames()); From 080fe5e5e0f3e2660c58a8dd6b64a3ede63827d6 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 04:16:32 -0500 Subject: [PATCH 234/259] Record the TypeScript order baseline for the typed-array constructor kind fixture --- .../tests/corpus/8321-typed-array-constructor-kind.js.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8321-typed-array-constructor-kind.js.json diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8321-typed-array-constructor-kind.js.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8321-typed-array-constructor-kind.js.json new file mode 100644 index 000000000..6da151987 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8321-typed-array-constructor-kind.js.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8321-typed-array-constructor-kind.js" + ], + "diags": [] +} From 534c08dd2f30fa2ce5611fdbfcce20598a8f8f77 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 04:34:24 -0500 Subject: [PATCH 235/259] Pack spread tuple fields together with other spreads into optional-element rests A call that spread a fixed tuple and also an array, a Set or another iterable into a `(T | undefined)[]` rest parameter took the general rest path, which converts every value to T, so an undefined tuple field threw ("undefined is not representable in the target union"). Such calls now pack every item in argument order through lowerArraySpreadItems, which takes values already lowered (the tuple's fields) beside argument nodes and keeps undefined values as present undefined elements. A tuple element typed only `undefined`, as in `...["b", undefined]`, has a `null | undefined` field. Stored into an array that keeps undefined elements it is now evaluated and stored as undefined, where it was an internal compiler error; the checker admits it there only as undefined. --- .../src/frontend/lowering/call-arguments.ts | 16 ++++-- .../lowering/containers/array-construction.ts | 53 +++++++++++++++++-- .../8004-optional-element-conversions.ts | 9 ++++ 3 files changed, 70 insertions(+), 8 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/call-arguments.ts b/packages/compiler/src/frontend/lowering/call-arguments.ts index a139bfc64..79e891d4f 100644 --- a/packages/compiler/src/frontend/lowering/call-arguments.ts +++ b/packages/compiler/src/frontend/lowering/call-arguments.ts @@ -407,10 +407,18 @@ export function completeArgs( // A `(T | undefined)[]` rest (stored as T elements) packs undefined // arguments as present undefined elements. const restNodes = sources.slice(restAt); - if (restType.optionalElements === true && !restNodes.some(isIr)) { - out.push( - lowerArraySpreadItems(lowerer, restNodes as ts.Expression[], restType.elem, restType, loc), - ); + // Plain arguments and spreads, also together with spread tuple fields + // (pre-lowered): each item, in argument order. + if ( + restType.optionalElements === true && + (!restNodes.some(isIr) || restNodes.some((a) => !isIr(a) && ts.isSpreadElement(a))) + ) { + const items: (ts.Expression | IrExpr)[] = []; + for (const a of restNodes) { + if (isIr(a)) items.push(a.ir); + else items.push(a); + } + out.push(lowerArraySpreadItems(lowerer, items, restType.elem, restType, loc)); return out; } // Tuple-spread values (pre-lowered) and plain arguments pack the same diff --git a/packages/compiler/src/frontend/lowering/containers/array-construction.ts b/packages/compiler/src/frontend/lowering/containers/array-construction.ts index 25a98c8a6..63e2e6e07 100644 --- a/packages/compiler/src/frontend/lowering/containers/array-construction.ts +++ b/packages/compiler/src/frontend/lowering/containers/array-construction.ts @@ -4,6 +4,7 @@ import { generatorDrain } from "../iterator-adapters.js"; import { identityPreservingWidening } from "../coercions/identity.js"; import { liftedFreshSpread } from "../coercions/fresh-spread.js"; import { checkedIterableSpread } from "../checked-iterable-spread.js"; +import { AstNode } from "../../ts7/ast-node.js"; import { InternalCompilerError } from "../../../errors.js"; import { dynUndefinedExpr, @@ -27,7 +28,9 @@ import { type IrType, STRING, type SrcLoc, + UNDEFINED_T, arrayOf, + isUnitType, canConvertToDyn, funcOf, isRefCounted, @@ -57,6 +60,34 @@ import { } from "./callback-arguments.js"; import { classGeneratorIterable } from "../class-iterables.js"; +/** A value whose type admits only null and undefined, stored into an array + * that keeps undefined elements: the checker admits it there only when its + * type is `undefined` (a tuple element typed `undefined` maps to such a + * union), so it is evaluated and stored as undefined. */ +function undefinedForNullish( + lowerer: Lowerer, + value: IrExpr, + arrType: IrType & { kind: "array" }, +): IrExpr { + if (arrType.optionalElements !== true || value.type.kind !== "union") return value; + const arms = lowerer.unions.get(value.type.unionId)?.arms ?? []; + if (arms.length === 0 || !arms.every(isUnitType)) return value; + const loc = value.loc; + const optional: IrType = { + kind: "union", + unionId: lowerer.unions.intern([arrType.elem, UNDEFINED_T]), + }; + const missing = lowerer.wrappedUndefined(optional, loc); + if (!missing) return value; + return { + kind: "seqExpr", + stmts: [{ kind: "exprStmt", expr: value, loc }], + result: missing, + type: optional, + loc, + }; +} + /** Build the argument array for a mutating/copying operation while keeping * the receiver's scalar payload ABI. A missing read is represented as the * present UNDEFINED state in this temporary, so push/unshift and toSpliced @@ -92,7 +123,8 @@ export function lowerArrayValueItems( loc, }, ]; - for (const value of values) { + for (const item of values) { + const value = undefinedForNullish(lowerer, item, arrType); const stored = lowerer.runtimeOptionalWidening(value.type, elem) !== null || optionalElementValue(lowerer, value, elem) @@ -103,16 +135,21 @@ export function lowerArrayValueItems( return { kind: "seqExpr", stmts: body, result: outRef, type: arrType, loc }; } +/** The items of an array built from argument nodes (a spread copies its + * elements in) and values already lowered (a spread tuple's fields), in + * order. Each value is stored when its turn comes. */ export function lowerArraySpreadItems( lowerer: Lowerer, - nodes: readonly ts.Expression[], + nodes: readonly (ts.Expression | IrExpr)[], elem: IrType, arrType: IrType & { kind: "array" }, loc: SrcLoc, ): IrExpr { const out = lowerer.declareHiddenLocal("%arrayItems", arrType); const outRef = varRef(out.id, arrType, loc); - const plainItems = nodes.filter((node) => !ts.isSpreadElement(node)).length; + const plainItems = nodes.filter( + (node) => !(node instanceof AstNode) || !ts.isSpreadElement(node), + ).length; const length = (): IrExpr => ({ kind: "arrIntrinsic", method: "length", @@ -136,7 +173,15 @@ export function lowerArraySpreadItems( }, ]; for (const node of nodes) { - if (ts.isSpreadElement(node)) { + if (!(node instanceof AstNode)) { + const value = undefinedForNullish(lowerer, node, arrType); + const stored = + lowerer.runtimeOptionalWidening(value.type, elem) !== null || + optionalElementValue(lowerer, value, elem) + ? value + : lowerer.coerceToExpected(value, elem); + body.push(arrayValueStore(lowerer, outRef, length(), stored, elem, loc)); + } else if (ts.isSpreadElement(node)) { let source = lowerer.lowerExpr(node.expression); if ( source.type.kind === "set" && diff --git a/tests/corpus/8004-optional-element-conversions.ts b/tests/corpus/8004-optional-element-conversions.ts index 07178e9b0..9a4ac55ac 100644 --- a/tests/corpus/8004-optional-element-conversions.ts +++ b/tests/corpus/8004-optional-element-conversions.ts @@ -49,6 +49,15 @@ function swap(pair: [string, string | undefined]): string { return "v"; } console.log(label("z", ...swapped, swap(swapped), ...swapped)); +// Tuple spreads together with array and Set spreads keep undefined +// elements, and every item is read in argument order. +const mixedPair: [boolean, boolean | undefined] = [true, undefined]; +const mixedMore: (boolean | undefined)[] = [false, undefined]; +console.log(flags(...mixedPair, ...mixedMore), flags(...mixedMore, ...mixedPair), flags(true, ...mixedPair, ...mixedMore, undefined)); +const mixedChanging: [boolean, boolean | undefined] = [true, undefined]; +console.log(flags(...mixedChanging, ...mixedMore, flip(mixedChanging, true), ...mixedChanging)); +const mixedWords: [string, string | undefined] = ["a", undefined]; +console.log(label("z", ...["b", undefined, "c"], ...mixedWords), label("y", ...mixedWords, ...new Set(["s", undefined]))); function pick(start: (number | undefined)[] | string[], other: (number | undefined)[] | string[]): string { let a = start; From 256fbdba20804c8a478f7cb0f77090d6df6dd5a8 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 04:54:28 -0500 Subject: [PATCH 236/259] Keep the helper for callbacks that read a local class's captures A lone array callback in a local class's method could read a binding the method reaches through its class's captures. Those bindings are shared by every method of the class, so another method can assign one while the loop runs, but the copied loop read the value once when the call started. stableTarget now counts a method's class captures as inherited, so such a callback keeps its helper and reads the current value on every call. --- .../lowering/containers/array-pipelines.ts | 7 +++++-- .../compiler/test/array-pipeline-fusion.test.ts | 17 +++++++++++++++++ 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts b/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts index 7c2e07b1c..197af2a9e 100644 --- a/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts +++ b/packages/compiler/src/frontend/lowering/containers/array-pipelines.ts @@ -950,11 +950,14 @@ class PipelineFusion { * nothing assigns after their declaration: `fn`'s own locals and * parameters, written neither by `fn` nor by any closure that shares * them, and not by the callback body. A binding a local class captures - * counts as written, since its methods may assign it. The callback must + * counts as written, since its methods may assign it; so does a binding + * a method reads through its class's captures. The callback must * not observe the ambient receiver (AmbientReceiverReaders). */ private stableTarget(fn: IrFunction): InlineTarget { const locals = new Map(fn.locals.map((l) => [l.id, l])); - const inherited = new Set((fn.captures ?? []).map((c) => c.localId)); + const inherited = new Set( + [...(fn.captures ?? []), ...(fn.classCaptures ?? [])].map((c) => c.localId), + ); const written = this.written.get(fn.name); const classCaptured = this.classCaptured(fn); return (arg) => { diff --git a/packages/compiler/test/array-pipeline-fusion.test.ts b/packages/compiler/test/array-pipeline-fusion.test.ts index e41e378a3..2c0c138ce 100644 --- a/packages/compiler/test/array-pipeline-fusion.test.ts +++ b/packages/compiler/test/array-pipeline-fusion.test.ts @@ -249,3 +249,20 @@ console.log(out.join(","), hit); ${postlude}`); expect(helperCalls(init(mod))).toEqual(["%arr.loop", "%arr.loop"]); }); + +test("a lone call in a local class's method keeps its helper for the class's captures", async () => { + const mod = await lowerSource(`${prelude} +let k = 1; +class Box { + set(v: number): void { k = v; } + go(): number[] { + const b = new Box(); + return rows.map((r) => { b.set(r.id); return r.value + k; }); + } +} +console.log(new Box().go().join(",")); +${postlude}`); + const go = mod.functions.find((f) => f.name.endsWith(".Box.go")); + expect(go).toBeDefined(); + expect(helperCalls(go!)).toEqual(["%arr.map"]); +}); From f8b1f9ffc36ade3f470c4e6d98d7625f5124caff Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 05:02:40 -0500 Subject: [PATCH 237/259] Keep a spread tuple alive until all its fields are packed into the rest A spread tuple's first field carries the statements that evaluate the tuple into a hidden local, and its later fields read that local. When lowerArraySpreadItems stored the first field as one item's expression, the local's frame ended with that store, so a tuple returned by a call was released before its later fields were read (a use-after-free under SCRIPTC_SAN=1). The field's statements now join the packing sequence at the item's position, whose frame lasts until every item is stored. --- .../frontend/lowering/containers/array-construction.ts | 10 +++++++++- tests/corpus/8004-optional-element-conversions.ts | 8 ++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/packages/compiler/src/frontend/lowering/containers/array-construction.ts b/packages/compiler/src/frontend/lowering/containers/array-construction.ts index 63e2e6e07..5029abc36 100644 --- a/packages/compiler/src/frontend/lowering/containers/array-construction.ts +++ b/packages/compiler/src/frontend/lowering/containers/array-construction.ts @@ -174,7 +174,15 @@ export function lowerArraySpreadItems( ]; for (const node of nodes) { if (!(node instanceof AstNode)) { - const value = undefinedForNullish(lowerer, node, arrType); + // A spread tuple's first field declares the tuple's storage, which + // the later fields read: its statements join this sequence, whose + // frame lasts until every item is stored. + let item = node; + if (item.kind === "seqExpr") { + body.push(...item.stmts); + item = item.result; + } + const value = undefinedForNullish(lowerer, item, arrType); const stored = lowerer.runtimeOptionalWidening(value.type, elem) !== null || optionalElementValue(lowerer, value, elem) diff --git a/tests/corpus/8004-optional-element-conversions.ts b/tests/corpus/8004-optional-element-conversions.ts index 9a4ac55ac..a592a4f32 100644 --- a/tests/corpus/8004-optional-element-conversions.ts +++ b/tests/corpus/8004-optional-element-conversions.ts @@ -58,6 +58,14 @@ const mixedChanging: [boolean, boolean | undefined] = [true, undefined]; console.log(flags(...mixedChanging, ...mixedMore, flip(mixedChanging, true), ...mixedChanging)); const mixedWords: [string, string | undefined] = ["a", undefined]; console.log(label("z", ...["b", undefined, "c"], ...mixedWords), label("y", ...mixedWords, ...new Set(["s", undefined]))); +// A tuple returned by a call keeps its string fields alive until every +// field is packed beside the other spreads. +function makeTuple(n: number): [string, string | undefined, string] { + return ["p" + n.toString(16).repeat(4), n % 2 ? undefined : "q" + n, "r".repeat((n % 7) + 3) + n]; +} +for (let i = 0; i < 3; i++) { + console.log(label("z", ...["m", undefined], ...makeTuple(i), ...mixedWords), label("y", ...makeTuple(i + 10), ...new Set(["s" + i]))); +} function pick(start: (number | undefined)[] | string[], other: (number | undefined)[] | string[]): string { let a = start; From cbc062a35f84e7a7099419e4d5b8a852e37c2e90 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 05:03:04 -0500 Subject: [PATCH 238/259] Skip NULL children and key-cache walks when disposing dynamic values Disposing a checked-dynamic node released each entry's getter and setter and the node's prototype and symbol tables through scr_dyn_release, though almost all of them are NULL: in a zod validation loop, over half of all dyn releases. Dispose now tests each child first. A pooled object also walked all its slots again on reuse, to take the key bytes it kept back from the pool's key budget. It now records that total when it is pooled, and reuse subtracts it. --- packages/runtime/src/scr_dyn.h | 7 ++++- packages/runtime/src/scr_json.c | 51 +++++++++++++++++++-------------- 2 files changed, 36 insertions(+), 22 deletions(-) diff --git a/packages/runtime/src/scr_dyn.h b/packages/runtime/src/scr_dyn.h index d6b05be71..f90fa1838 100644 --- a/packages/runtime/src/scr_dyn.h +++ b/packages/runtime/src/scr_dyn.h @@ -480,7 +480,12 @@ struct ScrDyn { * exits, and those clear it before release; reuse of a freed object * resets it (scr_dyn_alloc). */ const char *class_name; - struct ScrDynRegion *region; /* see ScrDynRegion */ + union { + struct ScrDynRegion *region; /* see ScrDynRegion */ + /* While the node is pooled: the key bytes it keeps for reuse, + * counted in the pool's key budget (scr_dyn_obj_drop_keys). */ + size_t cached_key_bytes; + }; /* The dynamic tier's hidden class (scr_js_object.c): the transition * tree node naming this object's key sequence, or NULL while it has * none. Only programs with dynamic-tier code read or maintain it: diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 1738ba848..bfc63270f 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -846,15 +846,21 @@ static SCR_TL size_t scr_dyn_cached_key_bytes; #define SCR_DYN_KEY_CACHE_LENGTH 64 #endif -static void scr_dyn_obj_drop_keys(ScrDyn *d, bool cache) { +/* Returns the key bytes it kept for reuse, which it added to the budget; + * the pooled node records them (v.obj.cached_key_bytes) so its reuse takes + * them back without walking its slots. */ +static size_t scr_dyn_obj_drop_keys(ScrDyn *d, bool cache) { + size_t kept = 0; for (size_t i = 0; i < d->v.obj.cap; i++) { ScrDynEntry *entry = &d->v.obj.entries[i]; if (!entry->key) continue; #ifndef SCR_RC_AUDIT + size_t bytes = sizeof(ScrDynKey) + entry->key_len + 1; if (cache && d->v.obj.cap <= SCR_DYN_KEY_CACHE_SLOTS && entry->key_len <= SCR_DYN_KEY_CACHE_LENGTH && - sizeof(ScrDynKey) + entry->key_len + 1 <= SCR_DYN_KEY_CACHE_MAX - scr_dyn_cached_key_bytes) { - scr_dyn_cached_key_bytes += sizeof(ScrDynKey) + entry->key_len + 1; + bytes <= SCR_DYN_KEY_CACHE_MAX - scr_dyn_cached_key_bytes) { + scr_dyn_cached_key_bytes += bytes; + kept += bytes; continue; } #else @@ -864,6 +870,7 @@ static void scr_dyn_obj_drop_keys(ScrDyn *d, bool cache) { entry->key = NULL; entry->key_len = 0; } + return kept; } /* Primitive kinds cannot acquire properties or change kind while live, so @@ -1054,15 +1061,11 @@ static ScrDyn *scr_dyn_alloc(ScrDynKind kind) { d->v.arr.region = NULL; } else if (kind == SCR_DYN_OBJ) { d->v.obj.len = 0; /* cap/entries preserved */ + /* The kept keys leave the pool's budget with the node. */ + scr_dyn_cached_key_bytes -= d->v.obj.cached_key_bytes; d->v.obj.region = NULL; d->v.obj.class_name = NULL; /* a released class prototype's name */ SCR_JS_SHAPE_RESET(d); - if (d->v.obj.cap <= SCR_DYN_KEY_CACHE_SLOTS) { - for (size_t i = 0; i < d->v.obj.cap; i++) { - ScrDynEntry *entry = &d->v.obj.entries[i]; - if (entry->key) scr_dyn_cached_key_bytes -= sizeof(ScrDynKey) + entry->key_len + 1; - } - } d->v.obj.source_identity = NULL; d->v.obj.source_access = NULL; } else if (kind != SCR_DYN_NUM && kind != SCR_DYN_STR) { @@ -1128,6 +1131,12 @@ static inline void scr_dyn_weak_dispose(ScrDyn *d) { if (scr_weak_observing) scr_weak_disposed(d); } +/* A disposed node's child: most getters, setters, prototypes and symbol + * tables are NULL, and the test costs less than the call. */ +static inline void scr_dyn_release_child(ScrDyn *child) { + if (child) scr_dyn_release(child); +} + static void scr_dyn_dispose(ScrDyn *d, bool collected) { #ifndef SCR_RC_AUDIT /* A capsule with nothing but its referent and adapters: the common end @@ -1149,9 +1158,9 @@ static void scr_dyn_dispose(ScrDyn *d, bool collected) { d->v.obj.index = NULL; } if (d->kind == SCR_DYN_ARR || d->kind == SCR_DYN_OBJ) scr_dyn_region_leave(d); - if (!collected) scr_dyn_release(d->prototype); - if (!collected) scr_dyn_release(d->symbol_properties); - if (!collected) scr_dyn_release(d->symbol_keys); + if (!collected) scr_dyn_release_child(d->prototype); + if (!collected) scr_dyn_release_child(d->symbol_properties); + if (!collected) scr_dyn_release_child(d->symbol_keys); /* Pooled nodes keep all three NULL (scr_dyn_leaf_alloc relies on it). */ d->prototype = d->symbol_properties = d->symbol_keys = NULL; switch (d->kind) { @@ -1171,17 +1180,17 @@ static void scr_dyn_dispose(ScrDyn *d, bool collected) { free(d->v.arr.presence); d->v.arr.presence = NULL; if (!collected) { - for (size_t i = 0; i < d->v.arr.len; i++) scr_dyn_release(d->v.arr.items[i]); - scr_dyn_release(d->v.arr.properties); + for (size_t i = 0; i < d->v.arr.len; i++) scr_dyn_release_child(d->v.arr.items[i]); + scr_dyn_release_child(d->v.arr.properties); } break; case SCR_DYN_OBJ: for (size_t i = 0; i < d->v.obj.len; i++) { ScrDyn *value = d->v.obj.entries[i].value; - if (!collected || !d->v.obj.entries[i].value_traced) scr_dyn_release(value); + if (!collected || !d->v.obj.entries[i].value_traced) scr_dyn_release_child(value); if (!collected) { - scr_dyn_release(d->v.obj.entries[i].getter); - scr_dyn_release(d->v.obj.entries[i].setter); + scr_dyn_release_child(d->v.obj.entries[i].getter); + scr_dyn_release_child(d->v.obj.entries[i].setter); } d->v.obj.entries[i].value = NULL; d->v.obj.entries[i].getter = NULL; @@ -1207,7 +1216,7 @@ static void scr_dyn_dispose(ScrDyn *d, bool collected) { case SCR_DYN_TYPED_REF: scr_typed_ref_forget(d); - if (!collected) scr_dyn_release(d->v.typed_ref.materialized); + if (!collected) scr_dyn_release_child(d->v.typed_ref.materialized); while (d->v.typed_ref.casts) { ScrDynTypedCast *cast = d->v.typed_ref.casts; d->v.typed_ref.casts = cast->next; @@ -1218,8 +1227,8 @@ static void scr_dyn_dispose(ScrDyn *d, bool collected) { break; case SCR_DYN_PROXY: if (!collected) { - scr_dyn_release(d->v.proxy.target); - scr_dyn_release(d->v.proxy.handler); + scr_dyn_release_child(d->v.proxy.target); + scr_dyn_release_child(d->v.proxy.handler); } break; default: @@ -1230,7 +1239,7 @@ static void scr_dyn_dispose(ScrDyn *d, bool collected) { #endif #ifndef SCR_RC_AUDIT if (!collected && scr_dyn_free_count < SCR_DYN_FREE_MAX) { - if (d->kind == SCR_DYN_OBJ) scr_dyn_obj_drop_keys(d, true); + if (d->kind == SCR_DYN_OBJ) d->v.obj.cached_key_bytes = scr_dyn_obj_drop_keys(d, true); /* Pooled blocks retain their headers and count toward the bounded * allocated heap, but never remain in a candidate buffer. */ scr_dyn_weak_dispose(d); From 9abf35f6a2e999944ee503c545000f9033cf632a Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 05:23:35 -0500 Subject: [PATCH 239/259] Build the large compiler tables on first use The native compiler ran four large module initializers at every startup: the builtin call signatures (LIB_FN_SIGS), the Node 24 fetch compatibility profile, and the builtin module function and ambient surface tables. Together their init functions are about 1.3 MB of code, and --version and warm cache-hit builds paged them in and built the tables without reading them. Each table is now built by a function on its first call and kept in a module variable: - libFnSignatures() replaces LIB_FN_SIGS - node24FetchCompatProfile() and staticFetchMembers() replace NODE24_FETCH_COMPAT_PROFILE and the STATIC_* member sets - builtinModuleFns() and ambientSurfaceFns() replace BUILTIN_MODULE_FNS and AMBIENT_SURFACE_FNS The @scriptc/compiler entry point keeps LIB_FN_SIGS and NODE24_FETCH_COMPAT_PROFILE as deprecated constants built from the new functions when the entry module loads. The native compiler does not load that module. The surface manifest's coverage notes read the fetch target through the profile function, so building the manifest module no longer builds the profile. The table contents are unchanged. --- packages/compiler/src/compat/fetch-profile.ts | 1511 +-- .../compiler/src/coverage/surface-manifest.ts | 53 +- .../src/frontend/lowering/lib-boundary.ts | 4 +- .../frontend/lowering/lower-builtin-values.ts | 6 +- .../src/frontend/lowering/lower-stdlib.ts | 40 +- .../src/frontend/lowering/surfaces.ts | 3116 ++--- packages/compiler/src/index.ts | 12 +- .../compiler/src/ir/builtin-signatures.ts | 10139 ++++++++-------- packages/compiler/src/ir/ir.ts | 2 +- packages/compiler/src/ir/validate.ts | 4 +- packages/compiler/src/library/fence-eval.ts | 12 +- packages/compiler/test/compat-exports.test.ts | 12 + packages/compiler/test/node-pin.test.ts | 4 +- tests/harness/README.md | 2 +- tests/harness/code-quality.test.ts | 2 +- tests/harness/fetch-conformance-program.ts | 2 +- tests/harness/fetch-conformance.test.ts | 4 +- tests/harness/surface-manifest.test.ts | 6 +- 18 files changed, 7525 insertions(+), 7406 deletions(-) create mode 100644 packages/compiler/test/compat-exports.test.ts diff --git a/packages/compiler/src/compat/fetch-profile.ts b/packages/compiler/src/compat/fetch-profile.ts index ff7cedb22..03d261aff 100644 --- a/packages/compiler/src/compat/fetch-profile.ts +++ b/packages/compiler/src/compat/fetch-profile.ts @@ -155,494 +155,104 @@ const typedInterfaceUnsupported = "typed source has no compiler bridge for this const metadataExclusion = "WebIDL brand metadata is observable reflection, not an executable compatibility operation"; -export const NODE24_FETCH_COMPAT_PROFILE = { - schemaVersion: 1, - target: { - node: "24.22.0", - undici: "7.29.1", - }, - requestInit: [ - { - id: "stdlib.fetch.request-init.method", - name: "RequestInit.method", - conversion: "WebIDL ByteString after all call arguments evaluate", - evidence: [fixture("static-coercion")], +function buildFetchCompatProfile() { + return { + schemaVersion: 1, + target: { + node: "24.22.0", + undici: "7.29.1", }, - { - id: "stdlib.fetch.request-init.headers", - name: "RequestInit.headers", - conversion: "Headers, record, or sequence-of-pairs snapshot", - evidence: [fixture("static"), fixture("static-coercion")], - }, - { - id: "stdlib.fetch.request-init.body", - name: "RequestInit.body", - conversion: "string, Uint8Array, ReadableStream, or null", - evidence: [fixture("static"), fixture("static-stream"), fixture("static-coercion")], - }, - { - id: "stdlib.fetch.request-init.duplex", - name: "RequestInit.duplex", - conversion: "WebIDL enum; 'half' required for streaming bodies", - evidence: [fixture("static-stream"), fixture("static-coercion")], - }, - { - id: "stdlib.fetch.request-init.redirect", - name: "RequestInit.redirect", - conversion: "WebIDL enum: follow, error, or manual", - evidence: [fixture("static"), fixture("static-coercion")], - }, - { - id: "stdlib.fetch.request-init.signal", - name: "RequestInit.signal", - conversion: "native AbortSignal handle or absent", - evidence: [fixture("static"), fixture("static-abort-throw")], - }, - ], - responseInit: [ - { - id: "stdlib.response-init.headers", - name: "ResponseInit.headers", - conversion: "Headers, record, or sequence-of-pairs snapshot", - evidence: [fixture("static")], - }, - { - id: "stdlib.response-init.status", - name: "ResponseInit.status", - conversion: "WebIDL unsigned-short conversion followed by the 200–599 range check", - evidence: [fixture("static")], - }, - { - id: "stdlib.response-init.statusText", - name: "ResponseInit.statusText", - conversion: "WebIDL ByteString with HTTP reason-phrase validation", - evidence: [fixture("static")], - }, - ], - members: { - responseReads: [ - "ok", - "status", - "statusText", - "url", - "redirected", - "headers", - "body", - "bodyUsed", - ], - responseCalls: ["json", "text", "bytes"], - readableStreamReads: ["locked"], - readableStreamCalls: ["cancel", "getReader"], - }, - operations: [ - { - id: "stdlib.headers.constructor", - name: "Headers constructor", - kind: "constructor", - facets: ["webidl-conversion", "mutation", "identity"], - scope: "Record and iterable header pairs, including copying native Headers", - evidence: [fixture("static-request")], - }, - { - id: "stdlib.request.constructor", - name: "Request constructor", - kind: "constructor", - facets: ["webidl-conversion", "body-consumption", "error-shape"], - scope: - "Absolute URLs with method, headers, body, duplex, redirect, and signal; other RequestInit members retain explicit fences", - evidence: [fixture("static-request")], - }, - ...[ - "method", - "url", - "headers", - "destination", - "referrer", - "referrerPolicy", - "mode", - "credentials", - "cache", - "redirect", - "integrity", - "keepalive", - "isReloadNavigation", - "isHistoryNavigation", - "signal", - "body", - "bodyUsed", - "duplex", - ].map((member): FetchCompatOperation => ({ - id: `stdlib.request.${member}`, - name: `Request.${member}`, - kind: "property", - facets: ["property-read", "state-machine"], - scope: "Reads on native Requests within the constructor's supported RequestInit subset", - evidence: [fixture("static-request")], - })), - ...["arrayBuffer", "text", "json", "bytes"].map((member): FetchCompatOperation => ({ - id: `stdlib.request.${member}`, - name: `Request.${member}`, - kind: "method", - facets: ["body-consumption", "promise-settlement", "state-machine", "error-shape"], - evidence: [fixture("static-request")], - })), - { - id: "stdlib.response.constructor", - name: "Response constructor", - kind: "constructor", - facets: ["webidl-conversion", "body-consumption", "state-machine", "error-shape"], - scope: - "BodyInit is string, Uint8Array/Buffer, ReadableStream, null/undefined, or a checked-dynamic value that follows the supported WebIDL string conversion; ResponseInit is headers/status/statusText", - evidence: [fixture("static")], - }, - { - id: "stdlib.fetch", - name: "fetch", - kind: "function", - facets: [ - "argument-evaluation", - "webidl-conversion", - "surplus-arguments", - "promise-settlement", - "transport", - "error-shape", - ], - evidence: [fixture("static"), fixture("static-coercion"), fixture("static-network-error")], - }, - { - id: "stdlib.abort-controller.constructor", - name: "AbortController constructor", - kind: "constructor", - facets: ["argument-evaluation", "identity", "state-machine", "surplus-arguments"], - evidence: [fixture("static-controller")], - }, - { - id: "stdlib.abort-controller.signal", - name: "AbortController.signal", - kind: "property", - facets: ["identity", "property-read", "state-machine"], - evidence: [fixture("static-controller")], - }, - { - id: "stdlib.abort-controller.abort", - name: "AbortController.abort", - kind: "method", - facets: ["callback-order", "identity", "liveness", "state-machine", "surplus-arguments"], - evidence: [fixture("static-controller")], - }, - { - id: "stdlib.abort-signal.abort", - name: "AbortSignal.abort", - kind: "static-method", - facets: ["identity", "liveness", "surplus-arguments", "property-read"], - evidence: [generated("webidl-operations"), fixture("static-stream-this")], - }, - { - id: "stdlib.abort-signal.any", - name: "AbortSignal.any", - kind: "static-method", - facets: ["webidl-conversion", "missing-arguments", "surplus-arguments", "property-read"], - evidence: [generated("webidl-operations"), fixture("static-stream-this")], - }, - { - id: "stdlib.abort-signal.timeout", - name: "AbortSignal.timeout", - kind: "static-method", - facets: ["webidl-conversion", "missing-arguments", "surplus-arguments", "error-shape"], - evidence: [generated("webidl-operations"), fixture("static-stream-this")], - }, - { - id: "stdlib.abort-signal.aborted", - name: "AbortSignal.aborted", - kind: "property", - facets: ["property-read"], - evidence: [generated("webidl-operations")], - }, - { - id: "stdlib.abort-signal.reason", - name: "AbortSignal.reason", - kind: "property", - facets: ["identity", "liveness", "property-read"], - evidence: [generated("webidl-operations"), fixture("static-stream-this")], - }, - { - id: "stdlib.abort-signal.onabort", - name: "AbortSignal.onabort", - kind: "property", - facets: ["callback-order", "callback-this", "mutation", "property-read"], - evidence: [generated("abort-events"), fixture("static-listener-this")], - }, - { - id: "stdlib.abort-signal.throw-if-aborted", - name: "AbortSignal.throwIfAborted", - kind: "method", - facets: ["identity", "error-shape"], - evidence: [generated("webidl-operations"), fixture("static-abort-throw")], - }, - { - id: "stdlib.abort-signal.add-event-listener", - name: "AbortSignal.addEventListener", - kind: "method", - facets: ["webidl-conversion", "identity", "callback-order", "callback-this"], - evidence: [ - generated("abort-events"), - fixture("static-listener-this"), - fixture("static-listener-noncallable"), - ], - }, - { - id: "stdlib.abort-signal.remove-event-listener", - name: "AbortSignal.removeEventListener", - kind: "method", - facets: ["webidl-conversion", "identity", "callback-order"], - evidence: [generated("abort-events"), fixture("static-stream-this")], - }, - { - id: "stdlib.abort-signal.dispatch-event", - name: "AbortSignal.dispatchEvent", - kind: "method", - facets: ["callback-order", "callback-this", "error-shape"], - evidence: [fixture("static-dispatch-throw")], - }, - { - id: "stdlib.readable-stream.constructor", - name: "ReadableStream constructor", - kind: "constructor", - facets: ["webidl-conversion", "callback-this", "callback-order", "state-machine"], - evidence: [generated("stream-traces"), fixture("static-stream-this")], - }, - { - id: "stdlib.readable-stream.from", - name: "ReadableStream.from", - kind: "static-method", - facets: ["webidl-conversion", "missing-arguments", "surplus-arguments", "liveness"], - evidence: [generated("webidl-operations"), generated("stream-traces")], - }, - { - id: "stdlib.readable-stream.locked", - name: "ReadableStream.locked", - kind: "property", - facets: ["property-read", "state-machine"], - evidence: [generated("stream-traces")], - }, - { - id: "stdlib.readable-stream.cancel", - name: "ReadableStream.cancel", - kind: "method", - facets: ["identity", "promise-settlement", "state-machine"], - evidence: [generated("stream-traces"), fixture("static-stream")], - }, - { - id: "stdlib.readable-stream.get-reader", - name: "ReadableStream.getReader", - kind: "method", - facets: ["webidl-conversion", "identity", "state-machine", "error-shape"], - evidence: [generated("stream-traces"), fixture("static-stream")], - }, - { - id: "stdlib.readable-stream-default-reader.closed", - name: "ReadableStreamDefaultReader.closed", - kind: "property", - facets: ["promise-settlement", "property-read", "state-machine"], - evidence: [generated("stream-traces"), fixture("static-stream")], - }, - { - id: "stdlib.readable-stream-default-reader.read", - name: "ReadableStreamDefaultReader.read", - kind: "method", - facets: ["identity", "promise-settlement", "state-machine"], - evidence: [generated("stream-traces"), fixture("static-stream")], - }, - { - id: "stdlib.readable-stream-default-reader.cancel", - name: "ReadableStreamDefaultReader.cancel", - kind: "method", - facets: ["identity", "promise-settlement", "state-machine"], - evidence: [generated("stream-traces"), fixture("static-stream")], - }, - { - id: "stdlib.readable-stream-default-reader.release-lock", - name: "ReadableStreamDefaultReader.releaseLock", - kind: "method", - facets: ["promise-settlement", "state-machine", "error-shape"], - evidence: [generated("stream-traces"), fixture("static-stream")], - }, - { - id: "stdlib.readable-stream-default-controller.desired-size", - name: "ReadableStreamDefaultController.desiredSize", - kind: "property", - facets: ["property-read", "state-machine"], - evidence: [generated("stream-traces")], - }, - { - id: "stdlib.readable-stream-default-controller.enqueue", - name: "ReadableStreamDefaultController.enqueue", - kind: "method", - facets: ["identity", "liveness", "state-machine", "error-shape"], - evidence: [generated("stream-traces"), fixture("static-stream")], - }, - { - id: "stdlib.readable-stream-default-controller.close", - name: "ReadableStreamDefaultController.close", - kind: "method", - facets: ["state-machine", "error-shape"], - evidence: [generated("stream-traces"), fixture("static-stream")], - }, - { - id: "stdlib.readable-stream-default-controller.error", - name: "ReadableStreamDefaultController.error", - kind: "method", - facets: ["identity", "promise-settlement", "state-machine"], - evidence: [generated("stream-traces"), fixture("static-stream")], - }, - ...["append", "delete", "get", "getSetCookie", "has", "set", "forEach"].map( - (member): FetchCompatOperation => ({ - id: `stdlib.headers.${member}`, - name: `Headers.${member}`, - kind: "method", - facets: - member === "forEach" - ? ["callback-order", "callback-this", "mutation"] - : member === "get" || member === "has" - ? ["webidl-conversion", "missing-arguments", "property-read"] - : ["webidl-conversion", "mutation", "error-shape"], + requestInit: [ + { + id: "stdlib.fetch.request-init.method", + name: "RequestInit.method", + conversion: "WebIDL ByteString after all call arguments evaluate", + evidence: [fixture("static-coercion")], + }, + { + id: "stdlib.fetch.request-init.headers", + name: "RequestInit.headers", + conversion: "Headers, record, or sequence-of-pairs snapshot", evidence: [fixture("static"), fixture("static-coercion")], - }), - ), - ...["ok", "status", "statusText", "url", "redirected", "headers", "body", "bodyUsed"].map( - (member): FetchCompatOperation => ({ - id: `stdlib.response.${member}`, - name: `Response.${member}`, - kind: "property", - facets: ["property-read"], - evidence: [fixture("static")], - }), - ), - { - id: "stdlib.response.static.json", - name: "Response.json", - kind: "static-method", - facets: ["webidl-conversion", "error-shape"], - scope: - "data that crosses the checked-dynamic boundary, serialized with JSON.stringify (toJSON hooks included); ResponseInit as for the constructor", - evidence: [fixture("static-response-json")], - }, - ...["json", "text", "bytes", "arrayBuffer"].map((member): FetchCompatOperation => ({ - id: `stdlib.response.${member}`, - name: `Response.${member}`, - kind: "method", - facets: ["body-consumption", "promise-settlement", "state-machine", "error-shape"], - evidence: - member === "arrayBuffer" - ? [fixture("static")] - : [fixture("static"), fixture("static-stream")], - })), - ], - inventory: { - interfaces: [ - "AbortController", - "AbortSignal", - "Headers", - "Request", - "Response", - "ReadableStream", - "ReadableStreamDefaultReader", - "ReadableStreamDefaultController", + }, + { + id: "stdlib.fetch.request-init.body", + name: "RequestInit.body", + conversion: "string, Uint8Array, ReadableStream, or null", + evidence: [fixture("static"), fixture("static-stream"), fixture("static-coercion")], + }, + { + id: "stdlib.fetch.request-init.duplex", + name: "RequestInit.duplex", + conversion: "WebIDL enum; 'half' required for streaming bodies", + evidence: [fixture("static-stream"), fixture("static-coercion")], + }, + { + id: "stdlib.fetch.request-init.redirect", + name: "RequestInit.redirect", + conversion: "WebIDL enum: follow, error, or manual", + evidence: [fixture("static"), fixture("static-coercion")], + }, + { + id: "stdlib.fetch.request-init.signal", + name: "RequestInit.signal", + conversion: "native AbortSignal handle or absent", + evidence: [fixture("static"), fixture("static-abort-throw")], + }, ], - entries: [ - staticEntry("stdlib.fetch", "globalThis", "fetch", "global"), - - staticEntry( - "stdlib.abort-controller.constructor", - "AbortController", - "constructor", - "constructor", - ), - staticEntry("stdlib.abort-controller.signal", "AbortController", "signal", "prototype"), - staticEntry("stdlib.abort-controller.abort", "AbortController", "abort", "prototype"), - outOfScopeEntry( - "stdlib.abort-controller.symbol.toStringTag", - "AbortController", - "[Symbol.toStringTag]", - "prototype-symbol", - metadataExclusion, - ), - - unsupportedEntry( - "stdlib.abort-signal.constructor", - "AbortSignal", - "constructor", - "constructor", - "Node exposes the interface object but constructing it throws; the compiler does not preserve that constructor behavior", - ), - staticEntry("stdlib.abort-signal.abort", "AbortSignal", "abort", "static"), - staticEntry("stdlib.abort-signal.timeout", "AbortSignal", "timeout", "static"), - staticEntry("stdlib.abort-signal.any", "AbortSignal", "any", "static"), - staticEntry("stdlib.abort-signal.aborted", "AbortSignal", "aborted", "prototype"), - staticEntry("stdlib.abort-signal.reason", "AbortSignal", "reason", "prototype"), - staticEntry( - "stdlib.abort-signal.throw-if-aborted", - "AbortSignal", - "throwIfAborted", - "prototype", - ), - staticEntry("stdlib.abort-signal.onabort", "AbortSignal", "onabort", "prototype"), - staticEntry( - "stdlib.abort-signal.add-event-listener", - "AbortSignal", - "addEventListener", - "prototype-inherited", - ), - staticEntry( - "stdlib.abort-signal.remove-event-listener", - "AbortSignal", - "removeEventListener", - "prototype-inherited", - ), - staticEntry( - "stdlib.abort-signal.dispatch-event", - "AbortSignal", - "dispatchEvent", - "prototype-inherited", - ), - outOfScopeEntry( - "stdlib.abort-signal.symbol.toStringTag", - "AbortSignal", - "[Symbol.toStringTag]", - "prototype-symbol", - metadataExclusion, - ), - - staticEntry("stdlib.headers.constructor", "Headers", "constructor", "constructor"), - ...["append", "delete", "get", "has", "set", "getSetCookie"].map((member) => - staticEntry(`stdlib.headers.${member}`, "Headers", member, "prototype"), - ), - ...["keys", "values", "entries"].map((member) => - unsupportedEntry( - `stdlib.headers.${member}`, - "Headers", - member, - "prototype", - "native Headers iteration does not yet expose a static iterator handle", - ), - ), - staticEntry("stdlib.headers.forEach", "Headers", "forEach", "prototype"), - unsupportedEntry( - "stdlib.headers.symbol.iterator", - "Headers", - "[Symbol.iterator]", - "prototype-symbol", - "native Headers iteration does not expose an engine-free iterator handle", - ), - outOfScopeEntry( - "stdlib.headers.symbol.toStringTag", - "Headers", - "[Symbol.toStringTag]", - "prototype-symbol", - metadataExclusion, - ), - - staticEntry("stdlib.request.constructor", "Request", "constructor", "constructor"), + responseInit: [ + { + id: "stdlib.response-init.headers", + name: "ResponseInit.headers", + conversion: "Headers, record, or sequence-of-pairs snapshot", + evidence: [fixture("static")], + }, + { + id: "stdlib.response-init.status", + name: "ResponseInit.status", + conversion: "WebIDL unsigned-short conversion followed by the 200–599 range check", + evidence: [fixture("static")], + }, + { + id: "stdlib.response-init.statusText", + name: "ResponseInit.statusText", + conversion: "WebIDL ByteString with HTTP reason-phrase validation", + evidence: [fixture("static")], + }, + ], + members: { + responseReads: [ + "ok", + "status", + "statusText", + "url", + "redirected", + "headers", + "body", + "bodyUsed", + ], + responseCalls: ["json", "text", "bytes"], + readableStreamReads: ["locked"], + readableStreamCalls: ["cancel", "getReader"], + }, + operations: [ + { + id: "stdlib.headers.constructor", + name: "Headers constructor", + kind: "constructor", + facets: ["webidl-conversion", "mutation", "identity"], + scope: "Record and iterable header pairs, including copying native Headers", + evidence: [fixture("static-request")], + }, + { + id: "stdlib.request.constructor", + name: "Request constructor", + kind: "constructor", + facets: ["webidl-conversion", "body-consumption", "error-shape"], + scope: + "Absolute URLs with method, headers, body, duplex, redirect, and signal; other RequestInit members retain explicit fences", + evidence: [fixture("static-request")], + }, ...[ "method", "url", @@ -662,276 +272,695 @@ export const NODE24_FETCH_COMPAT_PROFILE = { "body", "bodyUsed", "duplex", - "clone", - "blob", - "arrayBuffer", - "text", - "json", - "formData", - "bytes", - "attribute", - ].map((member) => - ["clone", "blob", "formData", "attribute"].includes(member) - ? unsupportedEntry( - `stdlib.request.${member}`, - "Request", - member, - "prototype", - typedInterfaceUnsupported, - ) - : staticEntry(`stdlib.request.${member}`, "Request", member, "prototype"), + ].map((member): FetchCompatOperation => ({ + id: `stdlib.request.${member}`, + name: `Request.${member}`, + kind: "property", + facets: ["property-read", "state-machine"], + scope: "Reads on native Requests within the constructor's supported RequestInit subset", + evidence: [fixture("static-request")], + })), + ...["arrayBuffer", "text", "json", "bytes"].map((member): FetchCompatOperation => ({ + id: `stdlib.request.${member}`, + name: `Request.${member}`, + kind: "method", + facets: ["body-consumption", "promise-settlement", "state-machine", "error-shape"], + evidence: [fixture("static-request")], + })), + { + id: "stdlib.response.constructor", + name: "Response constructor", + kind: "constructor", + facets: ["webidl-conversion", "body-consumption", "state-machine", "error-shape"], + scope: + "BodyInit is string, Uint8Array/Buffer, ReadableStream, null/undefined, or a checked-dynamic value that follows the supported WebIDL string conversion; ResponseInit is headers/status/statusText", + evidence: [fixture("static")], + }, + { + id: "stdlib.fetch", + name: "fetch", + kind: "function", + facets: [ + "argument-evaluation", + "webidl-conversion", + "surplus-arguments", + "promise-settlement", + "transport", + "error-shape", + ], + evidence: [fixture("static"), fixture("static-coercion"), fixture("static-network-error")], + }, + { + id: "stdlib.abort-controller.constructor", + name: "AbortController constructor", + kind: "constructor", + facets: ["argument-evaluation", "identity", "state-machine", "surplus-arguments"], + evidence: [fixture("static-controller")], + }, + { + id: "stdlib.abort-controller.signal", + name: "AbortController.signal", + kind: "property", + facets: ["identity", "property-read", "state-machine"], + evidence: [fixture("static-controller")], + }, + { + id: "stdlib.abort-controller.abort", + name: "AbortController.abort", + kind: "method", + facets: ["callback-order", "identity", "liveness", "state-machine", "surplus-arguments"], + evidence: [fixture("static-controller")], + }, + { + id: "stdlib.abort-signal.abort", + name: "AbortSignal.abort", + kind: "static-method", + facets: ["identity", "liveness", "surplus-arguments", "property-read"], + evidence: [generated("webidl-operations"), fixture("static-stream-this")], + }, + { + id: "stdlib.abort-signal.any", + name: "AbortSignal.any", + kind: "static-method", + facets: ["webidl-conversion", "missing-arguments", "surplus-arguments", "property-read"], + evidence: [generated("webidl-operations"), fixture("static-stream-this")], + }, + { + id: "stdlib.abort-signal.timeout", + name: "AbortSignal.timeout", + kind: "static-method", + facets: ["webidl-conversion", "missing-arguments", "surplus-arguments", "error-shape"], + evidence: [generated("webidl-operations"), fixture("static-stream-this")], + }, + { + id: "stdlib.abort-signal.aborted", + name: "AbortSignal.aborted", + kind: "property", + facets: ["property-read"], + evidence: [generated("webidl-operations")], + }, + { + id: "stdlib.abort-signal.reason", + name: "AbortSignal.reason", + kind: "property", + facets: ["identity", "liveness", "property-read"], + evidence: [generated("webidl-operations"), fixture("static-stream-this")], + }, + { + id: "stdlib.abort-signal.onabort", + name: "AbortSignal.onabort", + kind: "property", + facets: ["callback-order", "callback-this", "mutation", "property-read"], + evidence: [generated("abort-events"), fixture("static-listener-this")], + }, + { + id: "stdlib.abort-signal.throw-if-aborted", + name: "AbortSignal.throwIfAborted", + kind: "method", + facets: ["identity", "error-shape"], + evidence: [generated("webidl-operations"), fixture("static-abort-throw")], + }, + { + id: "stdlib.abort-signal.add-event-listener", + name: "AbortSignal.addEventListener", + kind: "method", + facets: ["webidl-conversion", "identity", "callback-order", "callback-this"], + evidence: [ + generated("abort-events"), + fixture("static-listener-this"), + fixture("static-listener-noncallable"), + ], + }, + { + id: "stdlib.abort-signal.remove-event-listener", + name: "AbortSignal.removeEventListener", + kind: "method", + facets: ["webidl-conversion", "identity", "callback-order"], + evidence: [generated("abort-events"), fixture("static-stream-this")], + }, + { + id: "stdlib.abort-signal.dispatch-event", + name: "AbortSignal.dispatchEvent", + kind: "method", + facets: ["callback-order", "callback-this", "error-shape"], + evidence: [fixture("static-dispatch-throw")], + }, + { + id: "stdlib.readable-stream.constructor", + name: "ReadableStream constructor", + kind: "constructor", + facets: ["webidl-conversion", "callback-this", "callback-order", "state-machine"], + evidence: [generated("stream-traces"), fixture("static-stream-this")], + }, + { + id: "stdlib.readable-stream.from", + name: "ReadableStream.from", + kind: "static-method", + facets: ["webidl-conversion", "missing-arguments", "surplus-arguments", "liveness"], + evidence: [generated("webidl-operations"), generated("stream-traces")], + }, + { + id: "stdlib.readable-stream.locked", + name: "ReadableStream.locked", + kind: "property", + facets: ["property-read", "state-machine"], + evidence: [generated("stream-traces")], + }, + { + id: "stdlib.readable-stream.cancel", + name: "ReadableStream.cancel", + kind: "method", + facets: ["identity", "promise-settlement", "state-machine"], + evidence: [generated("stream-traces"), fixture("static-stream")], + }, + { + id: "stdlib.readable-stream.get-reader", + name: "ReadableStream.getReader", + kind: "method", + facets: ["webidl-conversion", "identity", "state-machine", "error-shape"], + evidence: [generated("stream-traces"), fixture("static-stream")], + }, + { + id: "stdlib.readable-stream-default-reader.closed", + name: "ReadableStreamDefaultReader.closed", + kind: "property", + facets: ["promise-settlement", "property-read", "state-machine"], + evidence: [generated("stream-traces"), fixture("static-stream")], + }, + { + id: "stdlib.readable-stream-default-reader.read", + name: "ReadableStreamDefaultReader.read", + kind: "method", + facets: ["identity", "promise-settlement", "state-machine"], + evidence: [generated("stream-traces"), fixture("static-stream")], + }, + { + id: "stdlib.readable-stream-default-reader.cancel", + name: "ReadableStreamDefaultReader.cancel", + kind: "method", + facets: ["identity", "promise-settlement", "state-machine"], + evidence: [generated("stream-traces"), fixture("static-stream")], + }, + { + id: "stdlib.readable-stream-default-reader.release-lock", + name: "ReadableStreamDefaultReader.releaseLock", + kind: "method", + facets: ["promise-settlement", "state-machine", "error-shape"], + evidence: [generated("stream-traces"), fixture("static-stream")], + }, + { + id: "stdlib.readable-stream-default-controller.desired-size", + name: "ReadableStreamDefaultController.desiredSize", + kind: "property", + facets: ["property-read", "state-machine"], + evidence: [generated("stream-traces")], + }, + { + id: "stdlib.readable-stream-default-controller.enqueue", + name: "ReadableStreamDefaultController.enqueue", + kind: "method", + facets: ["identity", "liveness", "state-machine", "error-shape"], + evidence: [generated("stream-traces"), fixture("static-stream")], + }, + { + id: "stdlib.readable-stream-default-controller.close", + name: "ReadableStreamDefaultController.close", + kind: "method", + facets: ["state-machine", "error-shape"], + evidence: [generated("stream-traces"), fixture("static-stream")], + }, + { + id: "stdlib.readable-stream-default-controller.error", + name: "ReadableStreamDefaultController.error", + kind: "method", + facets: ["identity", "promise-settlement", "state-machine"], + evidence: [generated("stream-traces"), fixture("static-stream")], + }, + ...["append", "delete", "get", "getSetCookie", "has", "set", "forEach"].map( + (member): FetchCompatOperation => ({ + id: `stdlib.headers.${member}`, + name: `Headers.${member}`, + kind: "method", + facets: + member === "forEach" + ? ["callback-order", "callback-this", "mutation"] + : member === "get" || member === "has" + ? ["webidl-conversion", "missing-arguments", "property-read"] + : ["webidl-conversion", "mutation", "error-shape"], + evidence: [fixture("static"), fixture("static-coercion")], + }), ), - outOfScopeEntry( - "stdlib.request.symbol.toStringTag", + ...["ok", "status", "statusText", "url", "redirected", "headers", "body", "bodyUsed"].map( + (member): FetchCompatOperation => ({ + id: `stdlib.response.${member}`, + name: `Response.${member}`, + kind: "property", + facets: ["property-read"], + evidence: [fixture("static")], + }), + ), + { + id: "stdlib.response.static.json", + name: "Response.json", + kind: "static-method", + facets: ["webidl-conversion", "error-shape"], + scope: + "data that crosses the checked-dynamic boundary, serialized with JSON.stringify (toJSON hooks included); ResponseInit as for the constructor", + evidence: [fixture("static-response-json")], + }, + ...["json", "text", "bytes", "arrayBuffer"].map((member): FetchCompatOperation => ({ + id: `stdlib.response.${member}`, + name: `Response.${member}`, + kind: "method", + facets: ["body-consumption", "promise-settlement", "state-machine", "error-shape"], + evidence: + member === "arrayBuffer" + ? [fixture("static")] + : [fixture("static"), fixture("static-stream")], + })), + ], + inventory: { + interfaces: [ + "AbortController", + "AbortSignal", + "Headers", "Request", - "[Symbol.toStringTag]", - "prototype-symbol", - metadataExclusion, - ), - - staticEntry("stdlib.response.constructor", "Response", "constructor", "constructor"), - staticEntry("stdlib.response.static.json", "Response", "json", "static"), - ...["error", "redirect"].map((member) => - unsupportedEntry( - `stdlib.response.static.${member}`, - "Response", - member, - "static", - "Response static constructor-object operations have no compiler lowering", - ), - ), - unsupportedEntry("stdlib.response.type", "Response", "type", "prototype", widerMemberFence), - ...["url", "redirected", "status", "ok", "statusText", "headers", "body", "bodyUsed"].map( - (member) => staticEntry(`stdlib.response.${member}`, "Response", member, "prototype"), - ), - staticEntry("stdlib.response.arrayBuffer", "Response", "arrayBuffer", "prototype"), - ...["clone", "blob", "formData"].map((member) => - unsupportedEntry( - `stdlib.response.${member}`, - "Response", - member, - "prototype", - "the native fetch runtime does not implement this Response operation", - ), - ), - ...["text", "json"].map((member) => - staticEntry(`stdlib.response.${member}`, "Response", member, "prototype"), - ), - staticEntry("stdlib.response.bytes", "Response", "bytes", "prototype"), - outOfScopeEntry( - "stdlib.response.symbol.toStringTag", "Response", - "[Symbol.toStringTag]", - "prototype-symbol", - metadataExclusion, - ), - - staticEntry( - "stdlib.readable-stream.constructor", "ReadableStream", - "constructor", - "constructor", - ), - staticEntry("stdlib.readable-stream.from", "ReadableStream", "from", "static"), - staticEntry("stdlib.readable-stream.locked", "ReadableStream", "locked", "prototype"), - staticEntry("stdlib.readable-stream.cancel", "ReadableStream", "cancel", "prototype"), - staticEntry("stdlib.readable-stream.get-reader", "ReadableStream", "getReader", "prototype"), - ...["pipeThrough", "values"].map((member) => - unsupportedEntry( - `stdlib.readable-stream.${member}`, - "ReadableStream", - member, - "prototype", - member === "values" - ? "direct for-await consumption compiles statically; storing or driving the first-class iterator handle is unsupported" - : "the wider Web Streams graph is outside the native readable-stream slice", + "ReadableStreamDefaultReader", + "ReadableStreamDefaultController", + ], + entries: [ + staticEntry("stdlib.fetch", "globalThis", "fetch", "global"), + + staticEntry( + "stdlib.abort-controller.constructor", + "AbortController", + "constructor", + "constructor", ), - ), - ...["pipeTo", "tee"].map((member) => - unsupportedEntry( - `stdlib.readable-stream.${member}`, - "ReadableStream", - member, - "prototype", - "this operation is outside the native readable-stream implementation", + staticEntry("stdlib.abort-controller.signal", "AbortController", "signal", "prototype"), + staticEntry("stdlib.abort-controller.abort", "AbortController", "abort", "prototype"), + outOfScopeEntry( + "stdlib.abort-controller.symbol.toStringTag", + "AbortController", + "[Symbol.toStringTag]", + "prototype-symbol", + metadataExclusion, ), - ), - unsupportedEntry( - "stdlib.readable-stream.symbol.asyncIterator", - "ReadableStream", - "[Symbol.asyncIterator]", - "prototype-symbol", - "direct for-await consumption compiles statically; explicit symbol access and stored iterator handles have no compiler lowering", - ), - outOfScopeEntry( - "stdlib.readable-stream.symbol.toStringTag", - "ReadableStream", - "[Symbol.toStringTag]", - "prototype-symbol", - metadataExclusion, - ), - unsupportedEntry( - "stdlib.readable-stream-default-reader.constructor", - "ReadableStreamDefaultReader", - "constructor", - "constructor", - "reader handles come from ReadableStream.getReader(); the constructor object is unsupported", - ), - staticEntry( - "stdlib.readable-stream-default-reader.read", - "ReadableStreamDefaultReader", - "read", - "prototype", - ), - staticEntry( - "stdlib.readable-stream-default-reader.release-lock", - "ReadableStreamDefaultReader", - "releaseLock", - "prototype", - ), - staticEntry( - "stdlib.readable-stream-default-reader.closed", - "ReadableStreamDefaultReader", - "closed", - "prototype", - ), - staticEntry( - "stdlib.readable-stream-default-reader.cancel", - "ReadableStreamDefaultReader", - "cancel", - "prototype", - ), - outOfScopeEntry( - "stdlib.readable-stream-default-reader.symbol.toStringTag", - "ReadableStreamDefaultReader", - "[Symbol.toStringTag]", - "prototype-symbol", - metadataExclusion, - ), + unsupportedEntry( + "stdlib.abort-signal.constructor", + "AbortSignal", + "constructor", + "constructor", + "Node exposes the interface object but constructing it throws; the compiler does not preserve that constructor behavior", + ), + staticEntry("stdlib.abort-signal.abort", "AbortSignal", "abort", "static"), + staticEntry("stdlib.abort-signal.timeout", "AbortSignal", "timeout", "static"), + staticEntry("stdlib.abort-signal.any", "AbortSignal", "any", "static"), + staticEntry("stdlib.abort-signal.aborted", "AbortSignal", "aborted", "prototype"), + staticEntry("stdlib.abort-signal.reason", "AbortSignal", "reason", "prototype"), + staticEntry( + "stdlib.abort-signal.throw-if-aborted", + "AbortSignal", + "throwIfAborted", + "prototype", + ), + staticEntry("stdlib.abort-signal.onabort", "AbortSignal", "onabort", "prototype"), + staticEntry( + "stdlib.abort-signal.add-event-listener", + "AbortSignal", + "addEventListener", + "prototype-inherited", + ), + staticEntry( + "stdlib.abort-signal.remove-event-listener", + "AbortSignal", + "removeEventListener", + "prototype-inherited", + ), + staticEntry( + "stdlib.abort-signal.dispatch-event", + "AbortSignal", + "dispatchEvent", + "prototype-inherited", + ), + outOfScopeEntry( + "stdlib.abort-signal.symbol.toStringTag", + "AbortSignal", + "[Symbol.toStringTag]", + "prototype-symbol", + metadataExclusion, + ), - unsupportedEntry( - "stdlib.readable-stream-default-controller.constructor", - "ReadableStreamDefaultController", - "constructor", - "constructor", - "controller handles come from underlying-source callbacks; the constructor object is unsupported", - ), - staticEntry( - "stdlib.readable-stream-default-controller.desired-size", - "ReadableStreamDefaultController", - "desiredSize", - "prototype", - ), - staticEntry( - "stdlib.readable-stream-default-controller.close", - "ReadableStreamDefaultController", - "close", - "prototype", - ), - staticEntry( - "stdlib.readable-stream-default-controller.enqueue", - "ReadableStreamDefaultController", - "enqueue", - "prototype", - ), - staticEntry( - "stdlib.readable-stream-default-controller.error", - "ReadableStreamDefaultController", - "error", - "prototype", - ), - outOfScopeEntry( - "stdlib.readable-stream-default-controller.symbol.toStringTag", - "ReadableStreamDefaultController", - "[Symbol.toStringTag]", - "prototype-symbol", - metadataExclusion, - ), + staticEntry("stdlib.headers.constructor", "Headers", "constructor", "constructor"), + ...["append", "delete", "get", "has", "set", "getSetCookie"].map((member) => + staticEntry(`stdlib.headers.${member}`, "Headers", member, "prototype"), + ), + ...["keys", "values", "entries"].map((member) => + unsupportedEntry( + `stdlib.headers.${member}`, + "Headers", + member, + "prototype", + "native Headers iteration does not yet expose a static iterator handle", + ), + ), + staticEntry("stdlib.headers.forEach", "Headers", "forEach", "prototype"), + unsupportedEntry( + "stdlib.headers.symbol.iterator", + "Headers", + "[Symbol.iterator]", + "prototype-symbol", + "native Headers iteration does not expose an engine-free iterator handle", + ), + outOfScopeEntry( + "stdlib.headers.symbol.toStringTag", + "Headers", + "[Symbol.toStringTag]", + "prototype-symbol", + metadataExclusion, + ), - ...[ - "body", - "cache", - "credentials", - "dispatcher", - "duplex", - "headers", - "integrity", - "keepalive", - "method", - "mode", - "priority", - "redirect", - "referrer", - "referrerPolicy", - "signal", - "window", - ].map((member) => { - const id = `stdlib.fetch.request-init.${member}`; - const supported = new Set(["body", "duplex", "headers", "method", "redirect", "signal"]); - return supported.has(member) - ? staticEntry(id, "RequestInit", member, "dictionary") - : member === "dispatcher" + staticEntry("stdlib.request.constructor", "Request", "constructor", "constructor"), + ...[ + "method", + "url", + "headers", + "destination", + "referrer", + "referrerPolicy", + "mode", + "credentials", + "cache", + "redirect", + "integrity", + "keepalive", + "isReloadNavigation", + "isHistoryNavigation", + "signal", + "body", + "bodyUsed", + "duplex", + "clone", + "blob", + "arrayBuffer", + "text", + "json", + "formData", + "bytes", + "attribute", + ].map((member) => + ["clone", "blob", "formData", "attribute"].includes(member) ? unsupportedEntry( - id, - "RequestInit", + `stdlib.request.${member}`, + "Request", member, - "dictionary", - "custom dispatchers are unsupported; native environment-proxy routing uses NODE_USE_ENV_PROXY", + "prototype", + typedInterfaceUnsupported, ) - : unsupportedEntry( - id, - "RequestInit", - member, - "dictionary", - "the compiler does not preserve this RequestInit member's conversion or transport behavior", - ); - }), - ...["headers", "status", "statusText"].map((member) => - staticEntry(`stdlib.response-init.${member}`, "ResponseInit", member, "dictionary"), - ), - ], - excludedInterfaces: [ - { - name: "Blob/File/FormData bodies", - reason: - "fetch request and response bodies do not accept or produce Blob, File, or FormData values", - }, - { - name: "WritableStream/TransformStream", - reason: - "native support covers readable fetch bodies and the identity `new TransformStream()`; the WritableStream constructor, transformers, and general Web Streams graphs are unsupported", - }, - { - name: "Readable byte/BYOB streams", - reason: - "the native stream projection currently supports default readers and controllers only", - }, - { - name: "EventSource/WebSocket", - reason: "these are separate protocol clients, not fetch request/response compatibility", - }, - ], - }, -} satisfies FetchCompatProfile; + : staticEntry(`stdlib.request.${member}`, "Request", member, "prototype"), + ), + outOfScopeEntry( + "stdlib.request.symbol.toStringTag", + "Request", + "[Symbol.toStringTag]", + "prototype-symbol", + metadataExclusion, + ), -export const STATIC_RESPONSE_READS = new Set(NODE24_FETCH_COMPAT_PROFILE.members.responseReads); + staticEntry("stdlib.response.constructor", "Response", "constructor", "constructor"), + staticEntry("stdlib.response.static.json", "Response", "json", "static"), + ...["error", "redirect"].map((member) => + unsupportedEntry( + `stdlib.response.static.${member}`, + "Response", + member, + "static", + "Response static constructor-object operations have no compiler lowering", + ), + ), + unsupportedEntry("stdlib.response.type", "Response", "type", "prototype", widerMemberFence), + ...["url", "redirected", "status", "ok", "statusText", "headers", "body", "bodyUsed"].map( + (member) => staticEntry(`stdlib.response.${member}`, "Response", member, "prototype"), + ), + staticEntry("stdlib.response.arrayBuffer", "Response", "arrayBuffer", "prototype"), + ...["clone", "blob", "formData"].map((member) => + unsupportedEntry( + `stdlib.response.${member}`, + "Response", + member, + "prototype", + "the native fetch runtime does not implement this Response operation", + ), + ), + ...["text", "json"].map((member) => + staticEntry(`stdlib.response.${member}`, "Response", member, "prototype"), + ), + staticEntry("stdlib.response.bytes", "Response", "bytes", "prototype"), + outOfScopeEntry( + "stdlib.response.symbol.toStringTag", + "Response", + "[Symbol.toStringTag]", + "prototype-symbol", + metadataExclusion, + ), -export const STATIC_RESPONSE_CALLS = new Set(NODE24_FETCH_COMPAT_PROFILE.members.responseCalls); + staticEntry( + "stdlib.readable-stream.constructor", + "ReadableStream", + "constructor", + "constructor", + ), + staticEntry("stdlib.readable-stream.from", "ReadableStream", "from", "static"), + staticEntry("stdlib.readable-stream.locked", "ReadableStream", "locked", "prototype"), + staticEntry("stdlib.readable-stream.cancel", "ReadableStream", "cancel", "prototype"), + staticEntry( + "stdlib.readable-stream.get-reader", + "ReadableStream", + "getReader", + "prototype", + ), + ...["pipeThrough", "values"].map((member) => + unsupportedEntry( + `stdlib.readable-stream.${member}`, + "ReadableStream", + member, + "prototype", + member === "values" + ? "direct for-await consumption compiles statically; storing or driving the first-class iterator handle is unsupported" + : "the wider Web Streams graph is outside the native readable-stream slice", + ), + ), + ...["pipeTo", "tee"].map((member) => + unsupportedEntry( + `stdlib.readable-stream.${member}`, + "ReadableStream", + member, + "prototype", + "this operation is outside the native readable-stream implementation", + ), + ), + unsupportedEntry( + "stdlib.readable-stream.symbol.asyncIterator", + "ReadableStream", + "[Symbol.asyncIterator]", + "prototype-symbol", + "direct for-await consumption compiles statically; explicit symbol access and stored iterator handles have no compiler lowering", + ), + outOfScopeEntry( + "stdlib.readable-stream.symbol.toStringTag", + "ReadableStream", + "[Symbol.toStringTag]", + "prototype-symbol", + metadataExclusion, + ), -export const STATIC_HEADERS_CALLS = new Set( - NODE24_FETCH_COMPAT_PROFILE.inventory.entries - .filter( - (entry) => - entry.owner === "Headers" && entry.placement === "prototype" && entry.status === "static", - ) - .map((entry) => entry.member), -); + unsupportedEntry( + "stdlib.readable-stream-default-reader.constructor", + "ReadableStreamDefaultReader", + "constructor", + "constructor", + "reader handles come from ReadableStream.getReader(); the constructor object is unsupported", + ), + staticEntry( + "stdlib.readable-stream-default-reader.read", + "ReadableStreamDefaultReader", + "read", + "prototype", + ), + staticEntry( + "stdlib.readable-stream-default-reader.release-lock", + "ReadableStreamDefaultReader", + "releaseLock", + "prototype", + ), + staticEntry( + "stdlib.readable-stream-default-reader.closed", + "ReadableStreamDefaultReader", + "closed", + "prototype", + ), + staticEntry( + "stdlib.readable-stream-default-reader.cancel", + "ReadableStreamDefaultReader", + "cancel", + "prototype", + ), + outOfScopeEntry( + "stdlib.readable-stream-default-reader.symbol.toStringTag", + "ReadableStreamDefaultReader", + "[Symbol.toStringTag]", + "prototype-symbol", + metadataExclusion, + ), -export const STATIC_READABLE_STREAM_READS = new Set( - NODE24_FETCH_COMPAT_PROFILE.members.readableStreamReads, -); + unsupportedEntry( + "stdlib.readable-stream-default-controller.constructor", + "ReadableStreamDefaultController", + "constructor", + "constructor", + "controller handles come from underlying-source callbacks; the constructor object is unsupported", + ), + staticEntry( + "stdlib.readable-stream-default-controller.desired-size", + "ReadableStreamDefaultController", + "desiredSize", + "prototype", + ), + staticEntry( + "stdlib.readable-stream-default-controller.close", + "ReadableStreamDefaultController", + "close", + "prototype", + ), + staticEntry( + "stdlib.readable-stream-default-controller.enqueue", + "ReadableStreamDefaultController", + "enqueue", + "prototype", + ), + staticEntry( + "stdlib.readable-stream-default-controller.error", + "ReadableStreamDefaultController", + "error", + "prototype", + ), + outOfScopeEntry( + "stdlib.readable-stream-default-controller.symbol.toStringTag", + "ReadableStreamDefaultController", + "[Symbol.toStringTag]", + "prototype-symbol", + metadataExclusion, + ), -export const STATIC_READABLE_STREAM_CALLS = new Set( - NODE24_FETCH_COMPAT_PROFILE.members.readableStreamCalls, -); + ...[ + "body", + "cache", + "credentials", + "dispatcher", + "duplex", + "headers", + "integrity", + "keepalive", + "method", + "mode", + "priority", + "redirect", + "referrer", + "referrerPolicy", + "signal", + "window", + ].map((member) => { + const id = `stdlib.fetch.request-init.${member}`; + const supported = new Set(["body", "duplex", "headers", "method", "redirect", "signal"]); + return supported.has(member) + ? staticEntry(id, "RequestInit", member, "dictionary") + : member === "dispatcher" + ? unsupportedEntry( + id, + "RequestInit", + member, + "dictionary", + "custom dispatchers are unsupported; native environment-proxy routing uses NODE_USE_ENV_PROXY", + ) + : unsupportedEntry( + id, + "RequestInit", + member, + "dictionary", + "the compiler does not preserve this RequestInit member's conversion or transport behavior", + ); + }), + ...["headers", "status", "statusText"].map((member) => + staticEntry(`stdlib.response-init.${member}`, "ResponseInit", member, "dictionary"), + ), + ], + excludedInterfaces: [ + { + name: "Blob/File/FormData bodies", + reason: + "fetch request and response bodies do not accept or produce Blob, File, or FormData values", + }, + { + name: "WritableStream/TransformStream", + reason: + "native support covers readable fetch bodies and the identity `new TransformStream()`; the WritableStream constructor, transformers, and general Web Streams graphs are unsupported", + }, + { + name: "Readable byte/BYOB streams", + reason: + "the native stream projection currently supports default readers and controllers only", + }, + { + name: "EventSource/WebSocket", + reason: "these are separate protocol clients, not fetch request/response compatibility", + }, + ], + }, + } satisfies FetchCompatProfile; +} + +let fetchCompatProfile: ReturnType | undefined; + +/** The Node 24 fetch compatibility profile. It is built on the first call, + * so runs that do not lower a module do not construct it. */ +export function node24FetchCompatProfile(): ReturnType { + fetchCompatProfile ??= buildFetchCompatProfile(); + return fetchCompatProfile; +} + +/** The members the native static fetch handles project. */ +export interface StaticFetchMembers { + responseReads: ReadonlySet; + responseCalls: ReadonlySet; + headersCalls: ReadonlySet; + readableStreamReads: ReadonlySet; + readableStreamCalls: ReadonlySet; +} + +let staticFetchMemberSets: StaticFetchMembers | undefined; + +/** The profile's static members as sets, built on the first call. */ +export function staticFetchMembers(): StaticFetchMembers { + if (staticFetchMemberSets !== undefined) return staticFetchMemberSets; + const profile = node24FetchCompatProfile(); + staticFetchMemberSets = { + responseReads: new Set(profile.members.responseReads), + responseCalls: new Set(profile.members.responseCalls), + headersCalls: new Set( + profile.inventory.entries + .filter( + (entry) => + entry.owner === "Headers" && + entry.placement === "prototype" && + entry.status === "static", + ) + .map((entry) => entry.member), + ), + readableStreamReads: new Set(profile.members.readableStreamReads), + readableStreamCalls: new Set(profile.members.readableStreamCalls), + }; + return staticFetchMemberSets; +} diff --git a/packages/compiler/src/coverage/surface-manifest.ts b/packages/compiler/src/coverage/surface-manifest.ts index 9867a5617..b87a8065d 100644 --- a/packages/compiler/src/coverage/surface-manifest.ts +++ b/packages/compiler/src/coverage/surface-manifest.ts @@ -39,14 +39,14 @@ import { InternalCompilerError } from "../errors.js"; * byte-deterministic: entries sort by id, keys are emitted in one fixed * order, and the output carries no timestamps or absolute paths. */ import { FENCE_CODES, UNSUPPORTED, webAssemblyDiag } from "../diagnostics/diagnostic.js"; -import { NODE24_FETCH_COMPAT_PROFILE } from "../compat/fetch-profile.js"; +import { node24FetchCompatProfile } from "../compat/fetch-profile.js"; import { SUPPORTED_BUILTIN_MODULES, SUPPORTED_NODE_MODULES } from "../frontend/builtin-modules.js"; import { - AMBIENT_SURFACE_FNS, + ambientSurfaceFns, ARRAY_METHODS, BUILTIN_MODULE_CONSTS, BUILTIN_MODULE_FENCE_HINTS, - BUILTIN_MODULE_FNS, + builtinModuleFns, COLLECTION_ITERATOR_METHODS, COMPOUND_ASSIGN_OPS, STDLIB_SURFACE, @@ -88,18 +88,21 @@ export const MANIFEST_SCHEMA_VERSION = 2; /** The manifest's own scope statement: what the projection covers and — * just as load-bearing — what it deliberately leaves out, so absence is * never read as a support claim in either direction. */ -const COVERAGE_NOTES: string[] = [ - "Entries are projected mechanically from the compiler's own decision tables: the diagnostics registry, the unsupported-syntax dispatch tables, the stdlib and node-builtin lowering tables, and the supported-builtin-module list. Nothing is hand-maintained; the manifest regenerates byte-identically from the source tree at this version.", - "Absence from this manifest means 'not projected', never 'unsupported'. Surfaces lowered through dedicated code paths rather than tables are not yet projected: console, JSON, Promise/async and the timer surface, the net/http/tls/https/dgram/dns/assert/test/stream/readline module member surfaces, template literals, the regex slice, global functions (parseInt, parseFloat, isNaN, isFinite), and the process surface outside its ambient slice.", - "The ambient-nondeterminism and ambient-authority surfaces the library sidecar's determinism attestation scans ARE projected even where they lower through dedicated code paths — the Date compositions (stdlib.date.*), perf_hooks' performance.now, and the process global's ambient reads and authority calls (node-builtin.process.*) — so a determinism fence can name every surface the attestation demotes on.", - "stdlib and node-builtin member entries name surface whose LOWERED call forms are constrained (arity, argument shapes); declared call forms outside the lowered set are refused per site, with code SC2020 for standard-library and node-builtin surface.", - "Entries with status 'unsupported' describe where the named code is raised: forms of the construct outside the supported subset are refused with that code — not that every form of the named feature is refused. Supported forms appear as their own static entries where a table projects them.", - `The engine-free fetch projection targets Node ${NODE24_FETCH_COMPAT_PROFILE.target.node} with bundled Undici ${NODE24_FETCH_COMPAT_PROFILE.target.undici}. Each projected row names the differential evidence that guards it; changing the pinned Node or Undici version is an explicit profile update.`, - "The fetch profile also contains a runtime-reflected census of the selected fetch, abort, Headers, and readable-stream interfaces plus RequestInit/ResponseInit dictionary reads. Static and unsupported census rows are projected here; its explicitly out-of-scope metadata rows and adjacent-interface exclusions remain in the profile so absence is deliberate rather than ambiguous.", - "Process-level diagnostic codes are not surface entries: SC0001-SC0004 are preflight gates, SC1110 is a comptime evaluation failure, SC3001/SC3002 are backend/target tier refusals, SC9001/SC9002 are internal errors.", - "Entry statuses are projected for the desktop targets. The mobile targets (aarch64-apple-ios, aarch64-apple-ios-simulator, aarch64-linux-android) compile library-mode archives only: the library-admissible surface (what SC4005's async_free requirement and the library link set admit) is supported there, the executable lane refuses those triples with SC3002, and no entry outside the library-admissible surface carries a mobile support claim. iOS archives build for iOS 15.0 on darwin hosts; Android archives build against NDK API level 26.", - "No scheduling metadata is published; entry ids are the stable diff keys across releases.", -]; +function coverageNotes(): string[] { + const fetchTarget = node24FetchCompatProfile().target; + return [ + "Entries are projected mechanically from the compiler's own decision tables: the diagnostics registry, the unsupported-syntax dispatch tables, the stdlib and node-builtin lowering tables, and the supported-builtin-module list. Nothing is hand-maintained; the manifest regenerates byte-identically from the source tree at this version.", + "Absence from this manifest means 'not projected', never 'unsupported'. Surfaces lowered through dedicated code paths rather than tables are not yet projected: console, JSON, Promise/async and the timer surface, the net/http/tls/https/dgram/dns/assert/test/stream/readline module member surfaces, template literals, the regex slice, global functions (parseInt, parseFloat, isNaN, isFinite), and the process surface outside its ambient slice.", + "The ambient-nondeterminism and ambient-authority surfaces the library sidecar's determinism attestation scans ARE projected even where they lower through dedicated code paths — the Date compositions (stdlib.date.*), perf_hooks' performance.now, and the process global's ambient reads and authority calls (node-builtin.process.*) — so a determinism fence can name every surface the attestation demotes on.", + "stdlib and node-builtin member entries name surface whose LOWERED call forms are constrained (arity, argument shapes); declared call forms outside the lowered set are refused per site, with code SC2020 for standard-library and node-builtin surface.", + "Entries with status 'unsupported' describe where the named code is raised: forms of the construct outside the supported subset are refused with that code — not that every form of the named feature is refused. Supported forms appear as their own static entries where a table projects them.", + `The engine-free fetch projection targets Node ${fetchTarget.node} with bundled Undici ${fetchTarget.undici}. Each projected row names the differential evidence that guards it; changing the pinned Node or Undici version is an explicit profile update.`, + "The fetch profile also contains a runtime-reflected census of the selected fetch, abort, Headers, and readable-stream interfaces plus RequestInit/ResponseInit dictionary reads. Static and unsupported census rows are projected here; its explicitly out-of-scope metadata rows and adjacent-interface exclusions remain in the profile so absence is deliberate rather than ambiguous.", + "Process-level diagnostic codes are not surface entries: SC0001-SC0004 are preflight gates, SC1110 is a comptime evaluation failure, SC3001/SC3002 are backend/target tier refusals, SC9001/SC9002 are internal errors.", + "Entry statuses are projected for the desktop targets. The mobile targets (aarch64-apple-ios, aarch64-apple-ios-simulator, aarch64-linux-android) compile library-mode archives only: the library-admissible surface (what SC4005's async_free requirement and the library link set admit) is supported there, the executable lane refuses those triples with SC3002, and no entry outside the library-admissible surface carries a mobile support claim. iOS archives build for iOS 15.0 on darwin hosts; Android archives build against NDK API level 26.", + "No scheduling metadata is published; entry ids are the stable diff keys across releases.", + ]; +} /** Stable kebab id segment from prose: quotes dropped, the parenthetical * tail dropped, non-alphanumeric runs collapsed to one dash. */ @@ -410,7 +413,7 @@ export function generateSurfaceManifest(compilerVersion: string): SurfaceManifes : "recognized module (bare and node:-prefixed specifiers)", }); } - for (const [mod, members] of Object.entries(BUILTIN_MODULE_FNS)) { + for (const [mod, members] of Object.entries(builtinModuleFns())) { for (const member of Object.keys(members!)) { add({ id: `${moduleId(mod)}.${member}`, @@ -459,10 +462,9 @@ export function generateSurfaceManifest(compilerVersion: string): SurfaceManifes } // ── fetch/Web platform: one explicit, versioned compatibility profile ─ - const fetchTarget = - `Node ${NODE24_FETCH_COMPAT_PROFILE.target.node} / ` + - `Undici ${NODE24_FETCH_COMPAT_PROFILE.target.undici}`; - for (const operation of NODE24_FETCH_COMPAT_PROFILE.operations) { + const fetchProfile = node24FetchCompatProfile(); + const fetchTarget = `Node ${fetchProfile.target.node} / Undici ${fetchProfile.target.undici}`; + for (const operation of fetchProfile.operations) { const evidence = operation.evidence.map((item) => item.generated !== undefined ? `generated:${item.generated}` : `fixture:${item.fixture!}`, ); @@ -478,10 +480,7 @@ export function generateSurfaceManifest(compilerVersion: string): SurfaceManifes `differential evidence: ${evidence.join(", ")}`, }); } - for (const options of [ - NODE24_FETCH_COMPAT_PROFILE.requestInit, - NODE24_FETCH_COMPAT_PROFILE.responseInit, - ]) { + for (const options of [fetchProfile.requestInit, fetchProfile.responseInit]) { for (const option of options) { const evidence = option.evidence.map((item) => item.generated !== undefined ? `generated:${item.generated}` : `fixture:${item.fixture!}`, @@ -497,7 +496,7 @@ export function generateSurfaceManifest(compilerVersion: string): SurfaceManifes }); } } - for (const row of NODE24_FETCH_COMPAT_PROFILE.inventory.entries) { + for (const row of fetchProfile.inventory.entries) { if (row.status !== "unsupported") continue; if (row.code === undefined || row.reason === undefined) { throw new InternalCompilerError(`non-static fetch inventory row '${row.id}' is incomplete`); @@ -524,7 +523,7 @@ export function generateSurfaceManifest(compilerVersion: string): SurfaceManifes // Date/perf_hooks/process rows from the one ambient table — each entry // is fenceable by construction (its row carries the reach-witnessing // libCall spellings the fence detector uses). - for (const row of AMBIENT_SURFACE_FNS) { + for (const row of ambientSurfaceFns()) { add({ id: row.id, kind: row.kind, @@ -578,7 +577,7 @@ export function generateSurfaceManifest(compilerVersion: string): SurfaceManifes return { schemaVersion: MANIFEST_SCHEMA_VERSION, compilerVersion, - coverage: COVERAGE_NOTES, + coverage: coverageNotes(), entries, }; } diff --git a/packages/compiler/src/frontend/lowering/lib-boundary.ts b/packages/compiler/src/frontend/lowering/lib-boundary.ts index 5be10e997..8a264d346 100644 --- a/packages/compiler/src/frontend/lowering/lib-boundary.ts +++ b/packages/compiler/src/frontend/lowering/lib-boundary.ts @@ -57,7 +57,7 @@ import { isUnitType, typeEquals, } from "../../ir/ir.js"; -import { LIB_FN_SIGS } from "../../ir/builtin-signatures.js"; +import { libFnSignatures } from "../../ir/builtin-signatures.js"; import { REGEX_INTRINSIC_SIGS, STR_INTRINSIC_SIGS } from "../../ir/intrinsic-signatures.js"; import { unionMismatchDiag, unsupportedDiag } from "../../diagnostics/diagnostic.js"; @@ -162,7 +162,7 @@ function enforceExprBoundary(lowerer: Lowerer, node: IrExpr): void { const kind = node.kind; if (kind === "libCall") { const e = node; - const sig = LIB_FN_SIGS[e.fn]; + const sig = libFnSignatures()[e.fn]; if (!sig) return; e.args.forEach((a, i) => { const want = sig.argTypes[i]; diff --git a/packages/compiler/src/frontend/lowering/lower-builtin-values.ts b/packages/compiler/src/frontend/lowering/lower-builtin-values.ts index e5ebc6d8e..d59b234d3 100644 --- a/packages/compiler/src/frontend/lowering/lower-builtin-values.ts +++ b/packages/compiler/src/frontend/lowering/lower-builtin-values.ts @@ -16,7 +16,7 @@ import { strLit, varRef } from "../../ir/build.js"; import type { Lowerer } from "./lowerer.js"; import { BUILTIN_MODULE_CONSTS, - BUILTIN_MODULE_FNS, + builtinModuleFns, OBJECT_CALLABLE_VALUES, builtinConstLit, builtinModuleConstOf, @@ -430,7 +430,7 @@ export function pathModuleValue(lowerer: Lowerer, module: string, loc: SrcLoc): const add = (member: string, value: IrExpr): void => { fields.push({ key: strLit(member, loc), value: box(value) }); }; - for (const member of Object.keys(BUILTIN_MODULE_FNS[module] ?? {})) { + for (const member of Object.keys(builtinModuleFns()[module] ?? {})) { const value = lowerer.lowerBuiltinCallableValue({ module, member }, loc); if (value) add(member, value); } @@ -512,7 +512,7 @@ function moduleValue(lowerer: Lowerer, module: string, loc: SrcLoc): IrExpr { loc, }); }; - for (const member of Object.keys(BUILTIN_MODULE_FNS[module] ?? {})) { + for (const member of Object.keys(builtinModuleFns()[module] ?? {})) { const callable = lowerer.lowerBuiltinCallableValue({ module, member }, loc); if (callable) add(member, callable); } diff --git a/packages/compiler/src/frontend/lowering/lower-stdlib.ts b/packages/compiler/src/frontend/lowering/lower-stdlib.ts index fc0fd338f..fe748bb93 100644 --- a/packages/compiler/src/frontend/lowering/lower-stdlib.ts +++ b/packages/compiler/src/frontend/lowering/lower-stdlib.ts @@ -35,14 +35,7 @@ import { esmNamedImportLinkCrash, isCjsJsFile, locOf, npmPackageNameOf } from ". import { foldedStringKeyOf, lowerDynObjectLiteral } from "./expressions/object-literals.js"; import { noteEventListeners } from "./lower-event-target.js"; import { PoisonError, newFnCtx, own } from "./lowerer.js"; -import { - NODE24_FETCH_COMPAT_PROFILE, - STATIC_HEADERS_CALLS, - STATIC_READABLE_STREAM_CALLS, - STATIC_READABLE_STREAM_READS, - STATIC_RESPONSE_CALLS, - STATIC_RESPONSE_READS, -} from "../../compat/fetch-profile.js"; +import { node24FetchCompatProfile, staticFetchMembers } from "../../compat/fetch-profile.js"; import { classGeneratorIterable } from "./class-iterables.js"; import { generatorDrain } from "./iterator-adapters.js"; @@ -434,7 +427,7 @@ function fenceRequestInitObject( : contextual ? [contextual] : []; - const rows = NODE24_FETCH_COMPAT_PROFILE.inventory.entries.filter( + const rows = node24FetchCompatProfile().inventory.entries.filter( (entry) => entry.owner === "RequestInit" && entry.placement === "dictionary", ); const shadowed = new Set(); @@ -837,7 +830,7 @@ function fetchInventoryStatus( placement: "static" | "prototype" | "prototype-symbol", ): "static" | "unsupported" | "out-of-scope" | null { return ( - NODE24_FETCH_COMPAT_PROFILE.inventory.entries.find( + node24FetchCompatProfile().inventory.entries.find( (entry) => entry.owner === owner && entry.member === member && entry.placement === placement, )?.status ?? null ); @@ -848,7 +841,7 @@ function fetchInventoryReason( member: string, placement: "static" | "prototype" | "prototype-symbol", ): string | undefined { - return NODE24_FETCH_COMPAT_PROFILE.inventory.entries.find( + return node24FetchCompatProfile().inventory.entries.find( (entry) => entry.owner === owner && entry.member === member && entry.placement === placement, )?.reason; } @@ -951,8 +944,9 @@ export function fenceStaticResponseMember( member.startsWith("[Symbol.") ? "prototype-symbol" : "prototype", ); + const projected = staticFetchMembers(); const supported = (member: string) => - use === "call" ? STATIC_RESPONSE_CALLS.has(member) : STATIC_RESPONSE_READS.has(member); + use === "call" ? projected.responseCalls.has(member) : projected.responseReads.has(member); if (members.every(supported)) return null; const member = members.find((candidate) => !supported(candidate))!; if (status(member) === "unsupported") { @@ -993,12 +987,9 @@ export function fenceStaticHeadersMember( member.startsWith("[Symbol.") ? "prototype-symbol" : "prototype", ); - if (use === "call" && members.every((member) => STATIC_HEADERS_CALLS.has(member))) { - return null; - } - const member = members.find( - (candidate) => use !== "call" || !STATIC_HEADERS_CALLS.has(candidate), - )!; + const headersCalls = staticFetchMembers().headersCalls; + if (use === "call" && members.every((member) => headersCalls.has(member))) return null; + const member = members.find((candidate) => use !== "call" || !headersCalls.has(candidate))!; if (status(member) === "unsupported") { lowerer.noLowering( `Headers.${member}`, @@ -1108,7 +1099,7 @@ function fetchInterfaceInventoryOwner( const symbol = [type.getSymbol(), type.getAliasSymbol()].find( (candidate) => candidate !== undefined && - NODE24_FETCH_COMPAT_PROFILE.inventory.interfaces.includes(ts.symbolName(candidate)) && + node24FetchCompatProfile().inventory.interfaces.includes(ts.symbolName(candidate)) && lowerer.isStdlibSymbol(candidate), ); return symbol ? { owner: ts.symbolName(symbol), symbol } : null; @@ -1123,7 +1114,7 @@ function fenceFetchObjectMembers( if (!resolved) return; const { owner, symbol } = resolved; for (const { member, node } of members) { - const row = NODE24_FETCH_COMPAT_PROFILE.inventory.entries.find( + const row = node24FetchCompatProfile().inventory.entries.find( (entry) => entry.owner === owner && entry.member === member && @@ -1136,7 +1127,7 @@ function fenceFetchObjectMembers( // Static data properties retain the ordinary checked-dynamic keyed-read // lowering. Only a method extraction loses the receiver that its direct // call bridge would preserve; non-static rows keep their inventory fence. - const operation = NODE24_FETCH_COMPAT_PROFILE.operations.find( + const operation = node24FetchCompatProfile().operations.find( (candidate) => candidate.id === row.id, ); if (row.status === "static" && operation?.kind === "property") { @@ -1235,7 +1226,7 @@ export function lowerFetchElementMethodCall( return null; } const rows = members.map((member) => - NODE24_FETCH_COMPAT_PROFILE.inventory.entries.find( + node24FetchCompatProfile().inventory.entries.find( (entry) => entry.owner === resolved.owner && entry.member === member && @@ -1397,10 +1388,11 @@ export function fenceStaticReadableStreamMember( member.startsWith("[Symbol.") ? "prototype-symbol" : "prototype", ); + const projected = staticFetchMembers(); const supported = (member: string) => use === "call" - ? STATIC_READABLE_STREAM_CALLS.has(member) - : STATIC_READABLE_STREAM_READS.has(member); + ? projected.readableStreamCalls.has(member) + : projected.readableStreamReads.has(member); if (members.every(supported)) return null; const member = members.find((candidate) => !supported(candidate))!; if (status(member) === "unsupported") { diff --git a/packages/compiler/src/frontend/lowering/surfaces.ts b/packages/compiler/src/frontend/lowering/surfaces.ts index 0303d34d7..b5051d79d 100644 --- a/packages/compiler/src/frontend/lowering/surfaces.ts +++ b/packages/compiler/src/frontend/lowering/surfaces.ts @@ -1129,921 +1129,940 @@ export const UTIL_TYPES_KEYS: readonly string[] = [ "isCryptoKey", ]; -export const BUILTIN_MODULE_FNS: Record< - string, - Record | undefined -> = { - fs: { - readFileSync: { fn: "fs.readFileSync", params: [STRING, STRING], result: STRING }, - // The exact-API subset is first-class. A fixed native ABI is not enough: - // rows whose Node function has behavior-bearing trailing options remain - // call-only, or function-width adaptation could discard those options - // without a diagnostic before entering the fixed runtime call. - writeFileSync: { fn: "fs.writeFileSync", params: [STRING, STRING], result: VOID }, - appendFileSync: { fn: "fs.appendFileSync", params: [STRING, STRING], result: VOID }, - existsSync: { - fn: "fs.existsSync", - params: [STRING], - result: BOOL, - valueParams: exactValueParams(STRING), - }, - mkdirSync: { fn: "fs.mkdirSync", params: [STRING], result: VOID }, - rmSync: { fn: "fs.rmSync", params: [STRING], result: VOID }, - rmdirSync: { fn: "fs.rmdirSync", params: [STRING], result: VOID }, - readdirSync: { fn: "fs.readdirSync", params: [STRING], result: arrayOf(STRING) }, - // Pattern and options are checked by the runtime (lowerFsGlobSyncCall). - globSync: { fn: "fs.globSync", params: [DYN, DYN], result: arrayOf(STRING) }, - statSync: { fn: "fs.statSync", params: [STRING], result: STATS_T }, - mkdtempSync: { fn: "fs.mkdtempSync", params: [STRING], result: STRING }, - // accessSync's omitted mode completes to 0 (F_OK) in the special case - // in lowerBuiltinModuleCall — string `defaults` can't spell a number. - accessSync: { fn: "fs.accessSync", params: [STRING, F64], result: VOID }, - unlinkSync: { - fn: "fs.unlinkSync", - params: [STRING], - result: VOID, - valueParams: exactValueParams(STRING), - }, - chmodSync: { - fn: "fs.chmodSync", - params: [STRING, F64], - result: VOID, - valueParams: exactValueParams(STRING, F64), - }, - chownSync: { - fn: "fs.chownSync", - params: [STRING, F64, F64], - result: VOID, - valueParams: exactValueParams(STRING, F64, F64), - }, - lchownSync: { - fn: "fs.lchownSync", - params: [STRING, F64, F64], - result: VOID, - valueParams: exactValueParams(STRING, F64, F64), - }, - fchownSync: { - fn: "fs.fchownSync", - params: [F64, F64, F64], - result: VOID, - valueParams: exactValueParams(F64, F64, F64), - }, - // truncateSync's omitted len completes to 0 in lowerBuiltinModuleCall, - // like accessSync's mode. - truncateSync: { fn: "fs.truncateSync", params: [STRING, F64], result: VOID }, - // The 2-argument form only: Node's mode flags (COPYFILE_EXCL, ...) - // land on the arity fence. - copyFileSync: { fn: "fs.copyFileSync", params: [STRING, STRING], result: VOID }, - // The callback form is special-cased in lowerBuiltinModuleCall: its - // Error | null parameter is program-shaped and needs an emitted - // adapter. The row still projects the static surface and routes the - // dispatch. - rename: { fn: "fs.renameCb", params: [], result: VOID }, - renameSync: { - fn: "fs.renameSync", - params: [STRING, STRING], - result: VOID, - valueParams: exactValueParams(STRING, STRING), - }, - // statSync's no-follow sibling; stats.isSymbolicLink answers what the - // follow-free snapshot saw. - // opendirSync's options (a literal { bufferSize, encoding: "utf8" }) - // lower in lowerBuiltinModuleCall; the row routes the dispatch. - opendirSync: { fn: "fs.opendirSync", params: [STRING, F64], result: DIR_T }, - // createReadStream/createWriteStream lower in lowerBuiltinModuleCall - // (path and options cross as dyn values); the rows route the dispatch. - createReadStream: { - fn: "fs.createReadStream", - params: [DYN, DYN], - result: { kind: "object", className: "%Readable" }, - }, - createWriteStream: { - fn: "fs.createWriteStream", - params: [DYN, DYN], - result: { kind: "object", className: "%Writable" }, - }, - lstatSync: { fn: "fs.lstatSync", params: [STRING], result: STATS_T }, - fstatSync: { - fn: "fs.fstatSync", - params: [F64], - result: STATS_T, - valueParams: exactValueParams(F64), - }, - fchmodSync: { - fn: "fs.fchmodSync", - params: [F64, F64], - result: VOID, - valueParams: exactValueParams(F64, F64), - }, - fsyncSync: { - fn: "fs.fsyncSync", - params: [F64], - result: VOID, - valueParams: exactValueParams(F64), - }, - fdatasyncSync: { - fn: "fs.fdatasyncSync", - params: [F64], - result: VOID, - valueParams: exactValueParams(F64), - }, - ftruncateSync: { fn: "fs.ftruncateSync", params: [F64, F64], result: VOID }, - utimesSync: { fn: "fs.utimesSync", params: [DYN, DYN, DYN], result: VOID }, - futimesSync: { fn: "fs.futimesSync", params: [DYN, DYN, DYN], result: VOID }, - lutimesSync: { fn: "fs.lutimesSync", params: [DYN, DYN, DYN], result: VOID }, - readvSync: { fn: "fs.readvSync", params: [F64, arrayOf(BYTES_U8), F64], result: F64 }, - writevSync: { fn: "fs.writevSync", params: [F64, arrayOf(BYTES_U8), F64], result: F64 }, - linkSync: { - fn: "fs.linkSync", - params: [DYN, DYN], - result: VOID, - valueParams: exactValueParams(DYN, DYN), - }, - // Options and paths are checked by the runtime (scr_fs_cp_begin). - cpSync: { - fn: "fs.cpSync", - params: [DYN, DYN, DYN], - result: VOID, - valueParams: [ - ...exactValueParams(DYN, DYN), - { mode: "optional", type: DYN, defaultValue: undefined }, - ], - }, - symlinkSync: { - fn: "fs.symlinkSync", - params: [DYN, DYN, DYN], - result: VOID, - valueParams: [ - ...exactValueParams(DYN, DYN), - { mode: "optional", type: DYN, defaultValue: undefined }, - ], - }, - readlinkSync: { - fn: "fs.readlinkSync", - params: [DYN, DYN], - result: DYN, - valueParams: [ - ...exactValueParams(DYN), - { mode: "optional", type: DYN, defaultValue: undefined }, - ], - }, - statfsSync: { - fn: "fs.statfsSync", - params: [DYN, DYN], - result: DYN, - valueParams: [ - ...exactValueParams(DYN), - { mode: "optional", type: DYN, defaultValue: undefined }, - ], - }, - // realpath(3) — Node's realpathSync (failures spell syscall "lstat", - // Node's own message shape). - realpathSync: { fn: "fs.realpathSync", params: [STRING], result: STRING }, - "realpathSync.native": { fn: "fs.realpathNativeSync", params: [STRING], result: STRING }, - // The fd pair behind spawn's fd-stdio form (the daemon-log idiom: - // openSync(logPath, "a") → spawn stdio ["ignore", fd, fd] → - // closeSync). String flags use the established two-argument path; - // inline numeric O_* expressions route through openNumericSync, with - // an optional creation mode as the third argument. - openSync: { fn: "fs.openSync", params: [STRING, STRING], result: F64 }, - // The buffer forms (fd, buffer, offset, length[, position]). The - // lowering completes an omitted or literal-null position to -1 (the - // runtime's current-offset sentinel); numeric positions read without - // advancing the fd. The options-object and bigint forms still fence. - readSync: { fn: "fs.readSync", params: [F64, BYTES_U8, F64, F64, F64], result: F64 }, - // Entirely special-cased: the classic Buffer window and utf8 string - // overloads lower to separate fixed-width runtime ABIs. As with - // readSync, -1 is the current-offset sentinel. - writeSync: { fn: "fs.writeSync", params: [F64, BYTES_U8, F64, F64, F64], result: F64 }, - closeSync: { - fn: "fs.closeSync", - params: [F64], - result: VOID, - valueParams: exactValueParams(F64), - }, - // Entirely special-cased (lowerFsWatchCall — the callback needs an - // adapter per listener shape); this entry only routes the dispatch. - watch: { fn: "fs.watch", params: [], result: VOID }, - }, - "fs/promises": { - // The sync operations behind already-settled promises: failures - // REJECT (catchable at the await) instead of throwing. readFile is - // utf8-fenced exactly like readFileSync (same special case below). - readFile: { - fn: "fsp.readFile", - params: [STRING, STRING], - result: { kind: "promise", inner: STRING }, - }, - writeFile: { - fn: "fsp.writeFile", - params: [STRING, STRING], - result: { kind: "promise", inner: VOID }, - }, - mkdir: { fn: "fsp.mkdir", params: [STRING], result: { kind: "promise", inner: VOID } }, - readdir: { - fn: "fsp.readdir", - params: [STRING], - result: { kind: "promise", inner: arrayOf(STRING) }, - }, - rm: { fn: "fsp.rm", params: [STRING], result: { kind: "promise", inner: VOID } }, - // The async iterator lowers only as a for await head (lowerFspGlobCall). - glob: { fn: "fsp.globStrings", params: [DYN, DYN], result: arrayOf(STRING) }, - stat: { fn: "fsp.stat", params: [STRING], result: { kind: "promise", inner: STATS_T } }, - realpath: { fn: "fsp.realpath", params: [STRING], result: { kind: "promise", inner: STRING } }, - lstat: { fn: "fsp.lstat", params: [STRING], result: { kind: "promise", inner: STATS_T } }, - opendir: { - fn: "fsp.opendir", - params: [STRING, F64], - result: { kind: "promise", inner: DIR_T }, - }, - unlink: { - fn: "fsp.unlink", - params: [STRING], - result: { kind: "promise", inner: VOID }, - valueParams: exactValueParams(STRING), - }, - chmod: { - fn: "fsp.chmod", - params: [STRING, F64], - result: { kind: "promise", inner: VOID }, - valueParams: exactValueParams(STRING, F64), - }, - chown: { - fn: "fsp.chown", - params: [STRING, F64, F64], - result: { kind: "promise", inner: VOID }, - valueParams: exactValueParams(STRING, F64, F64), - }, - lchown: { - fn: "fsp.lchown", - params: [STRING, F64, F64], - result: { kind: "promise", inner: VOID }, - valueParams: exactValueParams(STRING, F64, F64), - }, - // access' omitted mode and truncate's omitted len complete to 0 in - // lowerBuiltinModuleCall, like their sync spellings. - access: { fn: "fsp.access", params: [STRING, F64], result: { kind: "promise", inner: VOID } }, - truncate: { - fn: "fsp.truncate", - params: [STRING, F64], - result: { kind: "promise", inner: VOID }, - }, - // String data; Uint8Array/Buffer data routes to fsp.appendFileBytes in - // lowerBuiltinModuleCall. - appendFile: { - fn: "fsp.appendFile", - params: [STRING, STRING], - result: { kind: "promise", inner: VOID }, - }, - // The 2-argument form only, like copyFileSync. - copyFile: { - fn: "fsp.copyFile", - params: [STRING, STRING], - result: { kind: "promise", inner: VOID }, - }, - mkdtemp: { fn: "fsp.mkdtemp", params: [STRING], result: { kind: "promise", inner: STRING } }, - rmdir: { fn: "fsp.rmdir", params: [STRING], result: { kind: "promise", inner: VOID } }, - link: { - fn: "fsp.link", - params: [DYN, DYN], - result: { kind: "promise", inner: VOID }, - valueParams: exactValueParams(DYN, DYN), - }, - cp: { - fn: "fsp.cp", - params: [DYN, DYN, DYN], - result: { kind: "promise", inner: VOID }, - valueParams: [ - ...exactValueParams(DYN, DYN), - { mode: "optional", type: DYN, defaultValue: undefined }, - ], - }, - symlink: { - fn: "fsp.symlink", - params: [DYN, DYN, DYN], - result: { kind: "promise", inner: VOID }, - valueParams: [ - ...exactValueParams(DYN, DYN), - { mode: "optional", type: DYN, defaultValue: undefined }, - ], - }, - readlink: { - fn: "fsp.readlink", - params: [DYN, DYN], - result: { kind: "promise", inner: DYN }, - valueParams: [ - ...exactValueParams(DYN), - { mode: "optional", type: DYN, defaultValue: undefined }, - ], - }, - statfs: { - fn: "fsp.statfs", - params: [DYN, DYN], - result: { kind: "promise", inner: DYN }, - valueParams: [ - ...exactValueParams(DYN), - { mode: "optional", type: DYN, defaultValue: undefined }, - ], - }, - utimes: { fn: "fsp.utimes", params: [DYN, DYN, DYN], result: { kind: "promise", inner: VOID } }, - lutimes: { - fn: "fsp.lutimes", - params: [DYN, DYN, DYN], - result: { kind: "promise", inner: VOID }, - }, - rename: { - fn: "fsp.rename", - params: [STRING, STRING], - result: { kind: "promise", inner: VOID }, - valueParams: exactValueParams(STRING, STRING), - }, - // open's optional flags/mode completion is special-cased in - // lowerBuiltinModuleCall; this row routes all import spellings and - // gives coverage the static member. - open: { - fn: "fsp.open", - params: [STRING, STRING, F64], - result: { kind: "promise", inner: FILEHANDLE_T }, - valueParams: [ - { mode: "required", type: STRING }, - { mode: "optional", type: STRING, defaultValue: "r" }, - { mode: "optional", type: F64, defaultValue: 0o666 }, - ], - }, - }, - // The bare module's POSIX-target binding; a win32 target rebinds it to - // the win32 table (builtinModuleFnsOf — Node on Windows IS path.win32). - path: PATH_MODULE_FNS, - // Real Node modules ("node:path/posix" resolves), and the receivers of - // `path.posix.` / `path.win32.` through the namespace - // chain (builtinNamespaceModuleOf composes "path" + ".posix" to these - // keys). Both namespaces carry the FULL surface on every platform, - // Node's own rule: each answers its own platform's semantics anywhere. - "path/posix": PATH_MODULE_FNS, - "path/win32": PATH_WIN32_MODULE_FNS, - os: { - // One platform implementation: os.platform() === process.platform. - platform: { fn: "process.platform", params: [], result: STRING, valueParams: [] }, - homedir: { fn: "os.homedir", params: [], result: STRING, valueParams: [] }, - tmpdir: { fn: "os.tmpdir", params: [], result: STRING, valueParams: [] }, - // uname(2)'s release field — Node's own implementation. - release: { fn: "os.release", params: [], result: STRING, valueParams: [] }, - // uname(2)'s sysname field ("Darwin", "Linux", "Windows_NT") — the - // libFn/runtime pair predates this entry (the portless surface used - // them); this row makes the MODULE call reach them (test/common's - // isAIX/isIBMi getters are the canonical callers). - type: { fn: "os.type", params: [], result: STRING, valueParams: [] }, - // Total physical memory in bytes — same predating-pair story. - totalmem: { fn: "os.totalmem", params: [], result: F64, valueParams: [] }, - // uv_available_parallelism: the CPUs this process may use (affinity, - // then cgroup quota on Linux), at least 1. - availableParallelism: { - fn: "os.availableParallelism", - params: [], - result: F64, - valueParams: [], - }, - // os.arch() IS process.arch, like platform(). - arch: { fn: "process.arch", params: [], result: STRING, valueParams: [] }, - hostname: { fn: "os.hostname", params: [], result: STRING, valueParams: [] }, - // uv_os_uname's machine and version fields, read once at module load - // in Node (they never change while a process runs). - machine: { fn: "os.machine", params: [], result: STRING, valueParams: [] }, - version: { fn: "os.version", params: [], result: STRING, valueParams: [] }, - endianness: { fn: "os.endianness", params: [], result: STRING, valueParams: [] }, - freemem: { fn: "os.freemem", params: [], result: F64, valueParams: [] }, - uptime: { fn: "os.uptime", params: [], result: F64, valueParams: [] }, - loadavg: { fn: "os.loadavg", params: [], result: arrayOf(F64), valueParams: [] }, - // An omitted (or undefined) pid is 0, the current process - // (lowerOsGetPriorityCall completes it). - getPriority: { - fn: "os.getPriority", - params: [F64], - result: F64, - valueParams: [{ mode: "optional", type: F64, defaultValue: 0 }], - }, - // A one-argument call is setPriority(0, priority) - // (lowerOsSetPriorityCall completes it). - setPriority: { fn: "os.setPriority", params: [F64, F64], result: VOID }, - // Special-cased (lowerOsCpusCall): the call site's CpuInfo[] assembles - // from one uv_cpu_info snapshot. - cpus: { fn: "os.cpusTake", params: [], result: VOID }, - // Entirely special-cased (lowerOsNetworkInterfacesCall): the result is - // the call site's mapped Dict shape, verified - // structurally there — this entry only routes the dispatch. - networkInterfaces: { fn: "os.networkInterfaces", params: [], result: VOID }, - // Special-cased too (lowerOsUserInfoCall): the call site's mapped - // UserInfo record assembles field-by-field from scalar libCalls. - userInfo: { fn: "os.userName", params: [], result: VOID }, - }, - crypto: { - randomUUID: { - fn: "crypto.randomUUID", - params: [], - result: STRING, - // As a value (uuid's `export default { randomUUID }`), the optional - // options argument goes through the validating entry point. - valueFn: "crypto.randomUUIDOpts", - valueParams: [{ mode: "optional", type: DYN, defaultValue: undefined }], - }, - // A real Buffer result. The composed randomBytes(n).toString(enc) - // form KEEPS its one-libCall lowering (lowerCryptoComposedCall runs - // first and the Buffer never materializes there); this entry covers - // the bare calls and non-composed uses. - randomBytes: { - fn: "crypto.randomBytes", - params: [F64], - result: BYTES_U8, - valueParams: exactValueParams(F64), - }, - // The crypto utility surface is special-cased for overloads and - // string/Buffer splits in lowerCryptoModuleCall. These rows carry the - // canonical signatures for manifest projection and fallback dispatch. - createHash: { fn: "crypto.hashNew", params: [STRING], result: CRYPTOHASH_T }, - createHmac: { fn: "crypto.hmacNewStr", params: [STRING, STRING], result: CRYPTOHMAC_T }, - hash: { fn: "crypto.hashDigestStr", params: [STRING, STRING, STRING], result: STRING }, - timingSafeEqual: { fn: "crypto.timingSafeEqual", params: [BYTES_U8, BYTES_U8], result: BOOL }, - randomFillSync: { fn: "crypto.randomFill", params: [BYTES_U8, F64, F64], result: BYTES_U8 }, - getRandomValues: { fn: "crypto.getRandomValues", params: [BYTES_U8], result: BYTES_U8 }, - randomInt: { fn: "crypto.randomInt", params: [F64, F64], result: F64 }, - randomFill: { fn: "crypto.randomFillCb", params: [], result: VOID }, - randomUUIDv7: { - fn: "crypto.randomUUIDv7", - params: [DYN], - result: STRING, - valueParams: [{ mode: "optional", type: DYN, defaultValue: undefined }], - }, - createSecretKey: { fn: "crypto.createSecretKey", params: [DYN, DYN], result: DYN }, - generateKeySync: { fn: "crypto.generateKeySync", params: [DYN, DYN], result: DYN }, - generateKey: { fn: "crypto.generateKeyCb", params: [], result: VOID }, - // Asymmetric keys and signatures (lowerPkiCall): checked-dynamic - // arguments, results converted to the call site's type. - createPrivateKey: { fn: "crypto.createPrivateKey", params: [DYN], result: DYN }, - createPublicKey: { fn: "crypto.createPublicKey", params: [DYN], result: DYN }, - createSign: { fn: "crypto.createSign", params: [DYN], result: DYN }, - createVerify: { fn: "crypto.createVerify", params: [DYN], result: DYN }, - generateKeyPairSync: { fn: "crypto.generateKeyPairSync", params: [], result: DYN }, - generateKeyPair: { fn: "crypto.generateKeyPairCb", params: [], result: VOID }, - sign: { fn: "crypto.signOneshot", params: [], result: DYN }, - verify: { fn: "crypto.verifyOneshot", params: [], result: DYN }, - diffieHellman: { fn: "crypto.diffieHellman", params: [], result: DYN }, - pbkdf2Sync: { - fn: "crypto.pbkdf2", - params: [BYTES_U8, BYTES_U8, F64, F64, STRING], - result: BYTES_U8, - }, - pbkdf2: { fn: "crypto.pbkdf2Cb", params: [], result: VOID }, - hkdfSync: { - fn: "crypto.hkdf", - params: [STRING, BYTES_U8, BYTES_U8, BYTES_U8, F64], - result: DYN, - }, - hkdf: { fn: "crypto.hkdfCb", params: [], result: VOID }, - scryptSync: { fn: "crypto.scrypt", params: [BYTES_U8, BYTES_U8, F64, DYN], result: BYTES_U8 }, - scrypt: { fn: "crypto.scryptCb", params: [], result: VOID }, - // Checked-dynamic arguments; the result is a native Cipheriv or - // Decipheriv handle (lowerCryptoModuleCall). - createCipheriv: { fn: "crypto.cipherNew", params: [BOOL, DYN, DYN, DYN, DYN], result: DYN }, - createDecipheriv: { fn: "crypto.cipherNew", params: [BOOL, DYN, DYN, DYN, DYN], result: DYN }, - // A checked-dynamic curve name; the result is a native ECDH handle - // (lowerCreateEcdh). - createECDH: { fn: "crypto.ecdhNew", params: [DYN], result: DYN }, - // Checked-dynamic arguments; the result is a native DiffieHellman or - // DiffieHellmanGroup handle (lowerCreateDiffieHellman and - // lowerGetDiffieHellman). - createDiffieHellman: { fn: "crypto.dhNew", params: [DYN, DYN, DYN, DYN], result: DYN }, - getDiffieHellman: { fn: "crypto.dhGroupNew", params: [DYN], result: DYN }, - createDiffieHellmanGroup: { fn: "crypto.dhGroupNew", params: [DYN], result: DYN }, - // Prime checks and generation (lowerPrimeCall): checked-dynamic - // arguments, results converted to the call site's type. - checkPrimeSync: { fn: "crypto.checkPrimeSync", params: [], result: DYN }, - // Checked-dynamic arguments, the result converted to the call site's - // type (lowerPrimeCall). - getCipherInfo: { fn: "crypto.getCipherInfo", params: [], result: DYN }, - checkPrime: { fn: "crypto.checkPrimeCb", params: [], result: VOID }, - generatePrimeSync: { fn: "crypto.generatePrimeSync", params: [], result: DYN }, - generatePrime: { fn: "crypto.generatePrimeCb", params: [], result: VOID }, - }, - zlib: { - // The default-options convenience family is special-cased in - // lowerBuiltinModuleCall: string inputs UTF-8 encode, callback forms - // carry program-shaped closures, and explicit options fence per site. - // native-toolchain.ts links libz only when these appear on the IR. - deflate: { fn: "zlib.deflateCb", params: [], result: VOID }, - deflateSync: { fn: "zlib.deflateSync", params: [BYTES_U8], result: BYTES_U8 }, - inflate: { fn: "zlib.inflateCb", params: [], result: VOID }, - inflateSync: { fn: "zlib.inflateSync", params: [BYTES_U8], result: BYTES_U8 }, - deflateRaw: { fn: "zlib.deflateRawCb", params: [], result: VOID }, - deflateRawSync: { fn: "zlib.deflateRawSync", params: [BYTES_U8], result: BYTES_U8 }, - inflateRaw: { fn: "zlib.inflateRawCb", params: [], result: VOID }, - inflateRawSync: { fn: "zlib.inflateRawSync", params: [BYTES_U8], result: BYTES_U8 }, - gzip: { fn: "zlib.gzipCb", params: [], result: VOID }, - gzipSync: { fn: "zlib.gzipSync", params: [BYTES_U8], result: BYTES_U8 }, - gunzip: { fn: "zlib.gunzipCb", params: [], result: VOID }, - gunzipSync: { fn: "zlib.gunzipSync", params: [BYTES_U8], result: BYTES_U8 }, - unzip: { fn: "zlib.unzipCb", params: [], result: VOID }, - unzipSync: { fn: "zlib.unzipSync", params: [BYTES_U8], result: BYTES_U8 }, - crc32: { fn: "zlib.crc32", params: [], result: F64 }, - // Brotli (special-cased in lowerZlibModuleCall): every form takes the - // options entries with Node's BROTLI_ENCODE or BROTLI_DECODE mode. - brotliCompress: { fn: "zlib.cbOpts", params: [], result: VOID }, - brotliCompressSync: { fn: "zlib.syncOpts", params: [], result: BYTES_U8 }, - brotliDecompress: { fn: "zlib.cbOpts", params: [], result: VOID }, - brotliDecompressSync: { fn: "zlib.syncOpts", params: [], result: BYTES_U8 }, - // The stream factories (special-cased in lowerZlibModuleCall): each - // answers a runtime Transform stream over the zlib engine. - createDeflate: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, - createInflate: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, - createGzip: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, - createGunzip: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, - createDeflateRaw: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, - createInflateRaw: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, - createUnzip: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, - createBrotliCompress: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, - createBrotliDecompress: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, - }, - url: { - fileURLToPath: { - fn: "url.fileURLToPathOptions", - params: [DYN, DYN], - result: STRING, - valueParams: [ - { mode: "required", type: DYN }, - { mode: "optional", type: DYN, defaultValue: undefined }, - ], - }, - fileURLToPathBuffer: { - fn: "url.fileURLToPathBuffer", - params: [DYN, DYN], - result: BYTES_U8, - valueParams: [ - { mode: "required", type: DYN }, - { mode: "optional", type: DYN, defaultValue: undefined }, - ], - }, - pathToFileURL: { - fn: "url.pathToFileURLChecked", - params: [DYN, DYN], - result: URL_T, - valueParams: [ - { mode: "required", type: DYN }, - { mode: "optional", type: DYN, defaultValue: undefined }, - ], - }, - // The legacy API and the domain pair (lowerLegacyUrlCall): arguments - // cross as dyn values for Node's own validators; url.parse() answers - // the checked-dynamic Url instance. - parse: { fn: "url.legacyParse", params: [DYN, DYN, DYN], result: DYN }, - format: { fn: "url.legacyFormat", params: [DYN, DYN], result: STRING }, - resolve: { fn: "url.legacyResolve", params: [DYN, DYN], result: STRING }, - domainToASCII: { fn: "url.domainToASCII", params: [DYN], result: STRING }, - domainToUnicode: { fn: "url.domainToUnicode", params: [DYN], result: STRING }, - urlToHttpOptions: { fn: "url.toHttpOptions", params: [DYN], result: DYN }, - }, - child_process: { - // spawnSync's and spawn's call completions are entirely special-cased - // (an omitted args list completes to an empty string[]; spawnSync - // accepts its documented literal options, while spawn supports the - // stdio/detached/env/cwd/windowsHide/shell subset — see - // lowerBuiltinModuleCall); the - // entries carry the canonical shapes. - spawnSync: { fn: "cp.spawnSync", params: [STRING, arrayOf(STRING)], result: SPAWNRES_T }, - spawn: { fn: "cp.spawn", params: [STRING, arrayOf(STRING)], result: CHILD_T }, - fork: { fn: "cp.fork", params: [STRING, arrayOf(STRING)], result: CHILD_T }, - // execFileSync(file, args?, options?) and execSync(command, options?) - // share the cp.execSync runtime entry (execSync sets the shell flag); - // both call completions are special-cased in lowerBuiltinModuleCall. - // The entries carry canonical shapes for the coverage/fence machinery. - execFileSync: { fn: "cp.execSync", params: [STRING, arrayOf(STRING)], result: STRING }, - execSync: { fn: "cp.execSync", params: [STRING], result: STRING }, - }, - // node:util lowers through dedicated paths: promisify - // only in the const-binding-over-execFile shape — recognized in - // lowerVarDecl / collectGlobals BEFORE any call lowering runs — and - // inspect/format/formatWithOptions plus parseArgs through the util spoke - // (lower-inspect.ts: per-type synthesized traversal helpers, - // compile-time format strings, checked-dynamic config/result for - // parseArgs), which both dispatch paths try before the generic table. - // parseArgs is tabled as well so the generated surface manifest records - // the dedicated static member; the spoke owns its optional arity and - // call-site-specific result type before this canonical signature is used. - util: { - styleText: { - fn: "util.styleText", - params: [DYN, DYN, DYN], - result: STRING, - valueParams: [ - { mode: "required", type: DYN }, - { mode: "required", type: DYN }, - { mode: "optional", type: DYN, defaultValue: undefined }, - ], - }, - isDeepStrictEqual: { - fn: "util.isDeepStrictEqual", - params: [DYN, DYN, DYN], - result: BOOL, - valueParams: [ - { mode: "required", type: DYN }, - { mode: "required", type: DYN }, - { mode: "optional", type: DYN, defaultValue: undefined }, - ], - }, - parseArgs: { fn: "util.parseArgs", params: [DYN], result: DYN }, - parseEnv: { fn: "util.parseEnv", params: [DYN], result: DYN }, - getSystemErrorName: { - fn: "util.getSystemErrorName", - params: [DYN], - result: STRING, - valueParams: exactValueParams(DYN), - }, - getSystemErrorMessage: { - fn: "util.getSystemErrorMessage", - params: [DYN], - result: STRING, - valueParams: exactValueParams(DYN), - }, - getSystemErrorMap: { fn: "util.systemErrorEntries", params: [], result: DYN }, - stripVTControlCharacters: { - fn: "util.stripVTControlCharacters", - params: [DYN], - result: STRING, - valueParams: exactValueParams(DYN), - }, - toUSVString: { - fn: "util.toUSVString", - params: [DYN], - result: STRING, - valueParams: exactValueParams(DYN), - }, - // The function helpers take checked-dynamic arguments and answer native - // dyn functions, which a static function slot checks when it receives - // one (lowerUtilCallableCall in the util spoke). - inherits: { - fn: "util.inherits", - params: [DYN, DYN], - result: VOID, - valueParams: [ - { mode: "required", type: DYN }, - { mode: "required", type: DYN }, - ], - }, - deprecate: { - fn: "util.deprecate", - params: [DYN, DYN, DYN, DYN], - result: DYN, - valueParams: [ - { mode: "required", type: DYN }, - { mode: "required", type: DYN }, - { mode: "optional", type: DYN, defaultValue: undefined }, - { mode: "optional", type: DYN, defaultValue: undefined }, - ], - }, - callbackify: { - fn: "util.callbackify", - params: [DYN], - result: DYN, - valueParams: [{ mode: "required", type: DYN }], - }, - debuglog: { - fn: "util.debuglog", - params: [DYN, DYN], - result: DYN, - valueParams: [ - { mode: "required", type: DYN }, - { mode: "optional", type: DYN, defaultValue: undefined }, - ], - }, - debug: { - fn: "util.debuglog", - params: [DYN, DYN], - result: DYN, - valueParams: [ - { mode: "required", type: DYN }, - { mode: "optional", type: DYN, defaultValue: undefined }, - ], - }, - }, - // The util/types spoke supplies the probe name to the shared brand check. - "util/types": { - isAnyArrayBuffer: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isArrayBuffer: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isArrayBufferView: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isDataView: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isTypedArray: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isUint8Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isUint8ClampedArray: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isUint16Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isUint32Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isInt8Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isInt16Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isInt32Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isFloat32Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isFloat64Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isMap: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isSet: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isWeakMap: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isWeakSet: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isRegExp: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isNativeError: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isPromise: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isProxy: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isAsyncFunction: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isGeneratorFunction: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isGeneratorObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isDate: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isSharedArrayBuffer: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isMapIterator: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isSetIterator: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isKeyObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isNumberObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isStringObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isBooleanObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isBigIntObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isSymbolObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isBoxedPrimitive: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isBigInt64Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isBigUint64Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isFloat16Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isCryptoKey: { fn: "util.typeIs", params: [DYN], result: BOOL }, - isExternal: { fn: "util.typeIs", params: [DYN], result: BOOL }, - }, - buffer: { - isAscii: { fn: "buffer.isAscii", params: [DYN], result: BOOL }, - isUtf8: { fn: "buffer.isUtf8", params: [DYN], result: BOOL }, - transcode: { fn: "buffer.transcode", params: [DYN, DYN, DYN], result: BYTES_U8 }, - }, - tty: { - isatty: { fn: "process.isTTY", params: [F64], result: BOOL }, - }, - process: { - loadEnvFile: { fn: "process.loadEnvFile", params: [DYN], result: VOID }, - }, - // node:string_decoder's surface is the StringDecoder CLASS — new/write/ - // end are special-cased (lowerNew + lowerStringDecoderMethodCall); no - // function members exist to table. - string_decoder: {}, - // node:querystring — the legacy query-string codec (NOT URLSearchParams; - // the escaping and '+' rules differ). escape/unescape ride the table - // path directly; parse and stringify are special-cased in - // lowerBuiltinModuleCall (parse's result is the call site's mapped - // ParsedUrlQuery dictionary — the networkInterfaces verification stance - // — and its sep/eq/options complete there; stringify's object argument - // crosses as a dyn value). decode/encode are Node's own aliases of - // parse/stringify (`const decode = parse` in lib/querystring.js) and - // route to the same special cases; the entries carry canonical shapes. - querystring: { - parse: { fn: "qs.parse", params: [STRING], result: VOID }, - decode: { fn: "qs.parse", params: [STRING], result: VOID }, - stringify: { fn: "qs.stringify", params: [DYN], result: STRING }, - encode: { fn: "qs.stringify", params: [DYN], result: STRING }, - escape: { - fn: "qs.escape", - params: [STRING], - result: STRING, - valueParams: [{ mode: "required", type: STRING }], - }, - unescape: { - fn: "qs.unescape", - params: [STRING], - result: STRING, - valueParams: [{ mode: "required", type: STRING }], - }, - }, - // node:punycode (deprecated): punycode.js 2.1.0's conversions over - // strings (scr_url.c). ucs2.decode/encode are members of the module's - // ucs2 object, dispatched as module members (builtinMemberOf). The - // DEP0040 report rides the module's load sites (punycodeLoadWarning). - punycode: { - decode: { fn: "punycode.decode", params: [STRING], result: STRING }, - encode: { fn: "punycode.encode", params: [STRING], result: STRING }, - toASCII: { fn: "punycode.toASCII", params: [STRING], result: STRING }, - toUnicode: { fn: "punycode.toUnicode", params: [STRING], result: STRING }, - "ucs2.decode": { fn: "punycode.ucs2Decode", params: [STRING], result: arrayOf(F64) }, - "ucs2.encode": { fn: "punycode.ucs2Encode", params: [arrayOf(F64)], result: STRING }, - }, - // node:constants (deprecated) is one frozen object (Object.assign of - // os.constants' groups, fs.constants and crypto.constants): bindings of - // the module read it as a checked-dynamic value (builtinConstantsObject). - constants: {}, - // node:readline: createInterface's options are entirely special-cased - // (exactly { input: process.stdin, output?: process.stdout } — see - // lowerBuiltinModuleCall); the entry carries the canonical shape. The - // interface's question/close/on lower through - // lowerReadlineMethodCall. - readline: { - createInterface: { fn: "rl.create", params: [], result: F64 }, - }, - // node:readline/promises: the same Interface with the promise question - // (lowerReadlineMethodCall tells the forms apart by the call's result). - "readline/promises": { - createInterface: { fn: "rl.create", params: [], result: F64 }, - }, - // node:net and node:http lower ENTIRELY through the server spoke - // (lower-server.ts — every call shape is special-cased: closures, the - // optional connect host, writeHead's literal headers); the member list - // is the lower-server dispatch there. The modules still need keys here so future - // table entries have a home, and so the "recognized module, unlowered - // member" fence wording applies. - net: { - // The process-wide happy-eyeballs attempt budget: one runtime double - // in the core unit (never links scr_net.c by itself), default 250ms - // like Node's. - getDefaultAutoSelectFamilyAttemptTimeout: { - fn: "net.getAutoSelTimeout", - params: [], - result: F64, - }, - setDefaultAutoSelectFamilyAttemptTimeout: { - fn: "net.setAutoSelTimeout", - params: [F64], - result: VOID, - }, - // Node's IPv4Reg / IPv6Reg tests over String(input). - isIP: { fn: "net.isIP", params: [DYN], result: F64 }, - isIPv4: { fn: "net.isIPv4", params: [DYN], result: BOOL }, - isIPv6: { fn: "net.isIPv6", params: [DYN], result: BOOL }, - }, - http: {}, - // node:tls and node:https ride the same spoke (tls.createServer's - // options + secureConnection handler, https.createServer, and the - // https client's rejectUnauthorized/ca options are all special-cased - // in lower-server.ts). - tls: {}, - https: {}, - // node:dgram and node:dns lower ENTIRELY through the dgram spoke - // (lower-dgram.ts — createSocket's option literal, dns.lookup's - // options + callback, and the Socket method surface are all - // special-cased); the keys exist for the same reason net/http's do. - dgram: {}, - dns: {}, - // node:dns/promises rides the same spoke (lookup's promise form). - "dns/promises": {}, - // node:v8: getHeapStatistics answers allocator-derived figures in - // Node's shape (builtins/v8.ts — the entry carries the canonical - // shape); every other member fences with the by-design reason - // (builtinFenceHintOf). - v8: { - getHeapStatistics: { fn: "process.memoryUsageTake", params: [], result: VOID }, - }, - // node:stream/web re-exports the web stream globals (the same objects); - // its members lower through the globals' own paths. - "stream/web": {}, - // node:assert lowers ENTIRELY through the assert spoke (lower-assert.ts - // — every call shape is special-cased: optional messages complete, the - // comparisons pick per-type libCalls, deep equality synthesizes - // helpers); the keys exist so unlowered members fence module-qualified - // with the hints below. - assert: {}, - "assert/strict": {}, - // node:test lowers ENTIRELY through the test spoke (lower-test.ts — - // registrations, suites, hooks, the TestContext surface); the key - // exists so unlowered members fence module-qualified. - test: {}, - // node:stream/promises lowers through the stream spoke too - // (lower-stream.ts — finished/pipeline's promise forms special-case - // their stream arguments exactly like the callback forms); the key - // exists so unlowered members fence module-qualified. - "stream/promises": {}, - // node:stream/consumers rides the stream spoke as well (text/json/ - // buffer/arrayBuffer special-case their stream argument); blob fences - // module-qualified with the pointed hint below. - "stream/consumers": {}, - // node:timers/promises — the delay-only setTimeout and bare setImmediate - // (void promises the shared timer heap settles), and scheduler.wait / - // scheduler.yield, which Node defines as setTimeout(delay, undefined, - // options) and setImmediate(). The arity completion (omitted delay = - // Node's 1ms) and the value/options fences are special-cased in - // lowerBuiltinModuleCall; these entries carry the canonical shapes and - // route the dispatch. - "timers/promises": { - setTimeout: { fn: "tp.setTimeout", params: [F64], result: { kind: "promise", inner: VOID } }, - setImmediate: { fn: "tp.setImmediate", params: [], result: { kind: "promise", inner: VOID } }, - "scheduler.wait": { - fn: "tp.setTimeout", - params: [F64], - result: { kind: "promise", inner: VOID }, - }, - "scheduler.yield": { - fn: "tp.setImmediate", - params: [], - result: { kind: "promise", inner: VOID }, - }, - }, - // node:diagnostics_channel — the pub/sub core. channel() answers an f64 - // handle (type-mapper.ts maps Channel to F64); the subscriber arguments box - // into the checked-dynamic tree (special-cased in lowerBuiltinModuleCall — the entries - // carry canonical shapes and route the dispatch). The Channel method - // surface lowers through lowerDiagnosticsChannelMethodCall/lowerDiagnosticsChannelProperty. - diagnostics_channel: { - channel: { fn: "dc.channel", params: [STRING], result: F64 }, - subscribe: { fn: "dc.subscribe", params: [STRING, DYN], result: VOID }, - unsubscribe: { fn: "dc.unsubscribe", params: [STRING, DYN], result: BOOL }, - hasSubscribers: { fn: "dc.hasSubscribers", params: [STRING], result: BOOL }, - // The string form's canonical shape; the collection form (an object - // literal of five Channels) is special-cased in lowerBuiltinModuleCall. - tracingChannel: { fn: "dc.tracingChannel", params: [STRING], result: F64 }, - }, -}; +type BuiltinModuleFnTable = Record | undefined>; + +let builtinModuleFnTable: BuiltinModuleFnTable | undefined; + +/** Every builtin module's lowered function members, keyed by module and + * member. The table is built on the first call, so runs that do not lower + * a module do not construct it. */ +export function builtinModuleFns(): BuiltinModuleFnTable { + builtinModuleFnTable ??= buildBuiltinModuleFns(); + return builtinModuleFnTable; +} + +function buildBuiltinModuleFns(): BuiltinModuleFnTable { + return { + fs: { + readFileSync: { fn: "fs.readFileSync", params: [STRING, STRING], result: STRING }, + // The exact-API subset is first-class. A fixed native ABI is not enough: + // rows whose Node function has behavior-bearing trailing options remain + // call-only, or function-width adaptation could discard those options + // without a diagnostic before entering the fixed runtime call. + writeFileSync: { fn: "fs.writeFileSync", params: [STRING, STRING], result: VOID }, + appendFileSync: { fn: "fs.appendFileSync", params: [STRING, STRING], result: VOID }, + existsSync: { + fn: "fs.existsSync", + params: [STRING], + result: BOOL, + valueParams: exactValueParams(STRING), + }, + mkdirSync: { fn: "fs.mkdirSync", params: [STRING], result: VOID }, + rmSync: { fn: "fs.rmSync", params: [STRING], result: VOID }, + rmdirSync: { fn: "fs.rmdirSync", params: [STRING], result: VOID }, + readdirSync: { fn: "fs.readdirSync", params: [STRING], result: arrayOf(STRING) }, + // Pattern and options are checked by the runtime (lowerFsGlobSyncCall). + globSync: { fn: "fs.globSync", params: [DYN, DYN], result: arrayOf(STRING) }, + statSync: { fn: "fs.statSync", params: [STRING], result: STATS_T }, + mkdtempSync: { fn: "fs.mkdtempSync", params: [STRING], result: STRING }, + // accessSync's omitted mode completes to 0 (F_OK) in the special case + // in lowerBuiltinModuleCall — string `defaults` can't spell a number. + accessSync: { fn: "fs.accessSync", params: [STRING, F64], result: VOID }, + unlinkSync: { + fn: "fs.unlinkSync", + params: [STRING], + result: VOID, + valueParams: exactValueParams(STRING), + }, + chmodSync: { + fn: "fs.chmodSync", + params: [STRING, F64], + result: VOID, + valueParams: exactValueParams(STRING, F64), + }, + chownSync: { + fn: "fs.chownSync", + params: [STRING, F64, F64], + result: VOID, + valueParams: exactValueParams(STRING, F64, F64), + }, + lchownSync: { + fn: "fs.lchownSync", + params: [STRING, F64, F64], + result: VOID, + valueParams: exactValueParams(STRING, F64, F64), + }, + fchownSync: { + fn: "fs.fchownSync", + params: [F64, F64, F64], + result: VOID, + valueParams: exactValueParams(F64, F64, F64), + }, + // truncateSync's omitted len completes to 0 in lowerBuiltinModuleCall, + // like accessSync's mode. + truncateSync: { fn: "fs.truncateSync", params: [STRING, F64], result: VOID }, + // The 2-argument form only: Node's mode flags (COPYFILE_EXCL, ...) + // land on the arity fence. + copyFileSync: { fn: "fs.copyFileSync", params: [STRING, STRING], result: VOID }, + // The callback form is special-cased in lowerBuiltinModuleCall: its + // Error | null parameter is program-shaped and needs an emitted + // adapter. The row still projects the static surface and routes the + // dispatch. + rename: { fn: "fs.renameCb", params: [], result: VOID }, + renameSync: { + fn: "fs.renameSync", + params: [STRING, STRING], + result: VOID, + valueParams: exactValueParams(STRING, STRING), + }, + // statSync's no-follow sibling; stats.isSymbolicLink answers what the + // follow-free snapshot saw. + // opendirSync's options (a literal { bufferSize, encoding: "utf8" }) + // lower in lowerBuiltinModuleCall; the row routes the dispatch. + opendirSync: { fn: "fs.opendirSync", params: [STRING, F64], result: DIR_T }, + // createReadStream/createWriteStream lower in lowerBuiltinModuleCall + // (path and options cross as dyn values); the rows route the dispatch. + createReadStream: { + fn: "fs.createReadStream", + params: [DYN, DYN], + result: { kind: "object", className: "%Readable" }, + }, + createWriteStream: { + fn: "fs.createWriteStream", + params: [DYN, DYN], + result: { kind: "object", className: "%Writable" }, + }, + lstatSync: { fn: "fs.lstatSync", params: [STRING], result: STATS_T }, + fstatSync: { + fn: "fs.fstatSync", + params: [F64], + result: STATS_T, + valueParams: exactValueParams(F64), + }, + fchmodSync: { + fn: "fs.fchmodSync", + params: [F64, F64], + result: VOID, + valueParams: exactValueParams(F64, F64), + }, + fsyncSync: { + fn: "fs.fsyncSync", + params: [F64], + result: VOID, + valueParams: exactValueParams(F64), + }, + fdatasyncSync: { + fn: "fs.fdatasyncSync", + params: [F64], + result: VOID, + valueParams: exactValueParams(F64), + }, + ftruncateSync: { fn: "fs.ftruncateSync", params: [F64, F64], result: VOID }, + utimesSync: { fn: "fs.utimesSync", params: [DYN, DYN, DYN], result: VOID }, + futimesSync: { fn: "fs.futimesSync", params: [DYN, DYN, DYN], result: VOID }, + lutimesSync: { fn: "fs.lutimesSync", params: [DYN, DYN, DYN], result: VOID }, + readvSync: { fn: "fs.readvSync", params: [F64, arrayOf(BYTES_U8), F64], result: F64 }, + writevSync: { fn: "fs.writevSync", params: [F64, arrayOf(BYTES_U8), F64], result: F64 }, + linkSync: { + fn: "fs.linkSync", + params: [DYN, DYN], + result: VOID, + valueParams: exactValueParams(DYN, DYN), + }, + // Options and paths are checked by the runtime (scr_fs_cp_begin). + cpSync: { + fn: "fs.cpSync", + params: [DYN, DYN, DYN], + result: VOID, + valueParams: [ + ...exactValueParams(DYN, DYN), + { mode: "optional", type: DYN, defaultValue: undefined }, + ], + }, + symlinkSync: { + fn: "fs.symlinkSync", + params: [DYN, DYN, DYN], + result: VOID, + valueParams: [ + ...exactValueParams(DYN, DYN), + { mode: "optional", type: DYN, defaultValue: undefined }, + ], + }, + readlinkSync: { + fn: "fs.readlinkSync", + params: [DYN, DYN], + result: DYN, + valueParams: [ + ...exactValueParams(DYN), + { mode: "optional", type: DYN, defaultValue: undefined }, + ], + }, + statfsSync: { + fn: "fs.statfsSync", + params: [DYN, DYN], + result: DYN, + valueParams: [ + ...exactValueParams(DYN), + { mode: "optional", type: DYN, defaultValue: undefined }, + ], + }, + // realpath(3) — Node's realpathSync (failures spell syscall "lstat", + // Node's own message shape). + realpathSync: { fn: "fs.realpathSync", params: [STRING], result: STRING }, + "realpathSync.native": { fn: "fs.realpathNativeSync", params: [STRING], result: STRING }, + // The fd pair behind spawn's fd-stdio form (the daemon-log idiom: + // openSync(logPath, "a") → spawn stdio ["ignore", fd, fd] → + // closeSync). String flags use the established two-argument path; + // inline numeric O_* expressions route through openNumericSync, with + // an optional creation mode as the third argument. + openSync: { fn: "fs.openSync", params: [STRING, STRING], result: F64 }, + // The buffer forms (fd, buffer, offset, length[, position]). The + // lowering completes an omitted or literal-null position to -1 (the + // runtime's current-offset sentinel); numeric positions read without + // advancing the fd. The options-object and bigint forms still fence. + readSync: { fn: "fs.readSync", params: [F64, BYTES_U8, F64, F64, F64], result: F64 }, + // Entirely special-cased: the classic Buffer window and utf8 string + // overloads lower to separate fixed-width runtime ABIs. As with + // readSync, -1 is the current-offset sentinel. + writeSync: { fn: "fs.writeSync", params: [F64, BYTES_U8, F64, F64, F64], result: F64 }, + closeSync: { + fn: "fs.closeSync", + params: [F64], + result: VOID, + valueParams: exactValueParams(F64), + }, + // Entirely special-cased (lowerFsWatchCall — the callback needs an + // adapter per listener shape); this entry only routes the dispatch. + watch: { fn: "fs.watch", params: [], result: VOID }, + }, + "fs/promises": { + // The sync operations behind already-settled promises: failures + // REJECT (catchable at the await) instead of throwing. readFile is + // utf8-fenced exactly like readFileSync (same special case below). + readFile: { + fn: "fsp.readFile", + params: [STRING, STRING], + result: { kind: "promise", inner: STRING }, + }, + writeFile: { + fn: "fsp.writeFile", + params: [STRING, STRING], + result: { kind: "promise", inner: VOID }, + }, + mkdir: { fn: "fsp.mkdir", params: [STRING], result: { kind: "promise", inner: VOID } }, + readdir: { + fn: "fsp.readdir", + params: [STRING], + result: { kind: "promise", inner: arrayOf(STRING) }, + }, + rm: { fn: "fsp.rm", params: [STRING], result: { kind: "promise", inner: VOID } }, + // The async iterator lowers only as a for await head (lowerFspGlobCall). + glob: { fn: "fsp.globStrings", params: [DYN, DYN], result: arrayOf(STRING) }, + stat: { fn: "fsp.stat", params: [STRING], result: { kind: "promise", inner: STATS_T } }, + realpath: { + fn: "fsp.realpath", + params: [STRING], + result: { kind: "promise", inner: STRING }, + }, + lstat: { fn: "fsp.lstat", params: [STRING], result: { kind: "promise", inner: STATS_T } }, + opendir: { + fn: "fsp.opendir", + params: [STRING, F64], + result: { kind: "promise", inner: DIR_T }, + }, + unlink: { + fn: "fsp.unlink", + params: [STRING], + result: { kind: "promise", inner: VOID }, + valueParams: exactValueParams(STRING), + }, + chmod: { + fn: "fsp.chmod", + params: [STRING, F64], + result: { kind: "promise", inner: VOID }, + valueParams: exactValueParams(STRING, F64), + }, + chown: { + fn: "fsp.chown", + params: [STRING, F64, F64], + result: { kind: "promise", inner: VOID }, + valueParams: exactValueParams(STRING, F64, F64), + }, + lchown: { + fn: "fsp.lchown", + params: [STRING, F64, F64], + result: { kind: "promise", inner: VOID }, + valueParams: exactValueParams(STRING, F64, F64), + }, + // access' omitted mode and truncate's omitted len complete to 0 in + // lowerBuiltinModuleCall, like their sync spellings. + access: { fn: "fsp.access", params: [STRING, F64], result: { kind: "promise", inner: VOID } }, + truncate: { + fn: "fsp.truncate", + params: [STRING, F64], + result: { kind: "promise", inner: VOID }, + }, + // String data; Uint8Array/Buffer data routes to fsp.appendFileBytes in + // lowerBuiltinModuleCall. + appendFile: { + fn: "fsp.appendFile", + params: [STRING, STRING], + result: { kind: "promise", inner: VOID }, + }, + // The 2-argument form only, like copyFileSync. + copyFile: { + fn: "fsp.copyFile", + params: [STRING, STRING], + result: { kind: "promise", inner: VOID }, + }, + mkdtemp: { fn: "fsp.mkdtemp", params: [STRING], result: { kind: "promise", inner: STRING } }, + rmdir: { fn: "fsp.rmdir", params: [STRING], result: { kind: "promise", inner: VOID } }, + link: { + fn: "fsp.link", + params: [DYN, DYN], + result: { kind: "promise", inner: VOID }, + valueParams: exactValueParams(DYN, DYN), + }, + cp: { + fn: "fsp.cp", + params: [DYN, DYN, DYN], + result: { kind: "promise", inner: VOID }, + valueParams: [ + ...exactValueParams(DYN, DYN), + { mode: "optional", type: DYN, defaultValue: undefined }, + ], + }, + symlink: { + fn: "fsp.symlink", + params: [DYN, DYN, DYN], + result: { kind: "promise", inner: VOID }, + valueParams: [ + ...exactValueParams(DYN, DYN), + { mode: "optional", type: DYN, defaultValue: undefined }, + ], + }, + readlink: { + fn: "fsp.readlink", + params: [DYN, DYN], + result: { kind: "promise", inner: DYN }, + valueParams: [ + ...exactValueParams(DYN), + { mode: "optional", type: DYN, defaultValue: undefined }, + ], + }, + statfs: { + fn: "fsp.statfs", + params: [DYN, DYN], + result: { kind: "promise", inner: DYN }, + valueParams: [ + ...exactValueParams(DYN), + { mode: "optional", type: DYN, defaultValue: undefined }, + ], + }, + utimes: { + fn: "fsp.utimes", + params: [DYN, DYN, DYN], + result: { kind: "promise", inner: VOID }, + }, + lutimes: { + fn: "fsp.lutimes", + params: [DYN, DYN, DYN], + result: { kind: "promise", inner: VOID }, + }, + rename: { + fn: "fsp.rename", + params: [STRING, STRING], + result: { kind: "promise", inner: VOID }, + valueParams: exactValueParams(STRING, STRING), + }, + // open's optional flags/mode completion is special-cased in + // lowerBuiltinModuleCall; this row routes all import spellings and + // gives coverage the static member. + open: { + fn: "fsp.open", + params: [STRING, STRING, F64], + result: { kind: "promise", inner: FILEHANDLE_T }, + valueParams: [ + { mode: "required", type: STRING }, + { mode: "optional", type: STRING, defaultValue: "r" }, + { mode: "optional", type: F64, defaultValue: 0o666 }, + ], + }, + }, + // The bare module's POSIX-target binding; a win32 target rebinds it to + // the win32 table (builtinModuleFnsOf — Node on Windows IS path.win32). + path: PATH_MODULE_FNS, + // Real Node modules ("node:path/posix" resolves), and the receivers of + // `path.posix.` / `path.win32.` through the namespace + // chain (builtinNamespaceModuleOf composes "path" + ".posix" to these + // keys). Both namespaces carry the FULL surface on every platform, + // Node's own rule: each answers its own platform's semantics anywhere. + "path/posix": PATH_MODULE_FNS, + "path/win32": PATH_WIN32_MODULE_FNS, + os: { + // One platform implementation: os.platform() === process.platform. + platform: { fn: "process.platform", params: [], result: STRING, valueParams: [] }, + homedir: { fn: "os.homedir", params: [], result: STRING, valueParams: [] }, + tmpdir: { fn: "os.tmpdir", params: [], result: STRING, valueParams: [] }, + // uname(2)'s release field — Node's own implementation. + release: { fn: "os.release", params: [], result: STRING, valueParams: [] }, + // uname(2)'s sysname field ("Darwin", "Linux", "Windows_NT") — the + // libFn/runtime pair predates this entry (the portless surface used + // them); this row makes the MODULE call reach them (test/common's + // isAIX/isIBMi getters are the canonical callers). + type: { fn: "os.type", params: [], result: STRING, valueParams: [] }, + // Total physical memory in bytes — same predating-pair story. + totalmem: { fn: "os.totalmem", params: [], result: F64, valueParams: [] }, + // uv_available_parallelism: the CPUs this process may use (affinity, + // then cgroup quota on Linux), at least 1. + availableParallelism: { + fn: "os.availableParallelism", + params: [], + result: F64, + valueParams: [], + }, + // os.arch() IS process.arch, like platform(). + arch: { fn: "process.arch", params: [], result: STRING, valueParams: [] }, + hostname: { fn: "os.hostname", params: [], result: STRING, valueParams: [] }, + // uv_os_uname's machine and version fields, read once at module load + // in Node (they never change while a process runs). + machine: { fn: "os.machine", params: [], result: STRING, valueParams: [] }, + version: { fn: "os.version", params: [], result: STRING, valueParams: [] }, + endianness: { fn: "os.endianness", params: [], result: STRING, valueParams: [] }, + freemem: { fn: "os.freemem", params: [], result: F64, valueParams: [] }, + uptime: { fn: "os.uptime", params: [], result: F64, valueParams: [] }, + loadavg: { fn: "os.loadavg", params: [], result: arrayOf(F64), valueParams: [] }, + // An omitted (or undefined) pid is 0, the current process + // (lowerOsGetPriorityCall completes it). + getPriority: { + fn: "os.getPriority", + params: [F64], + result: F64, + valueParams: [{ mode: "optional", type: F64, defaultValue: 0 }], + }, + // A one-argument call is setPriority(0, priority) + // (lowerOsSetPriorityCall completes it). + setPriority: { fn: "os.setPriority", params: [F64, F64], result: VOID }, + // Special-cased (lowerOsCpusCall): the call site's CpuInfo[] assembles + // from one uv_cpu_info snapshot. + cpus: { fn: "os.cpusTake", params: [], result: VOID }, + // Entirely special-cased (lowerOsNetworkInterfacesCall): the result is + // the call site's mapped Dict shape, verified + // structurally there — this entry only routes the dispatch. + networkInterfaces: { fn: "os.networkInterfaces", params: [], result: VOID }, + // Special-cased too (lowerOsUserInfoCall): the call site's mapped + // UserInfo record assembles field-by-field from scalar libCalls. + userInfo: { fn: "os.userName", params: [], result: VOID }, + }, + crypto: { + randomUUID: { + fn: "crypto.randomUUID", + params: [], + result: STRING, + // As a value (uuid's `export default { randomUUID }`), the optional + // options argument goes through the validating entry point. + valueFn: "crypto.randomUUIDOpts", + valueParams: [{ mode: "optional", type: DYN, defaultValue: undefined }], + }, + // A real Buffer result. The composed randomBytes(n).toString(enc) + // form KEEPS its one-libCall lowering (lowerCryptoComposedCall runs + // first and the Buffer never materializes there); this entry covers + // the bare calls and non-composed uses. + randomBytes: { + fn: "crypto.randomBytes", + params: [F64], + result: BYTES_U8, + valueParams: exactValueParams(F64), + }, + // The crypto utility surface is special-cased for overloads and + // string/Buffer splits in lowerCryptoModuleCall. These rows carry the + // canonical signatures for manifest projection and fallback dispatch. + createHash: { fn: "crypto.hashNew", params: [STRING], result: CRYPTOHASH_T }, + createHmac: { fn: "crypto.hmacNewStr", params: [STRING, STRING], result: CRYPTOHMAC_T }, + hash: { fn: "crypto.hashDigestStr", params: [STRING, STRING, STRING], result: STRING }, + timingSafeEqual: { fn: "crypto.timingSafeEqual", params: [BYTES_U8, BYTES_U8], result: BOOL }, + randomFillSync: { fn: "crypto.randomFill", params: [BYTES_U8, F64, F64], result: BYTES_U8 }, + getRandomValues: { fn: "crypto.getRandomValues", params: [BYTES_U8], result: BYTES_U8 }, + randomInt: { fn: "crypto.randomInt", params: [F64, F64], result: F64 }, + randomFill: { fn: "crypto.randomFillCb", params: [], result: VOID }, + randomUUIDv7: { + fn: "crypto.randomUUIDv7", + params: [DYN], + result: STRING, + valueParams: [{ mode: "optional", type: DYN, defaultValue: undefined }], + }, + createSecretKey: { fn: "crypto.createSecretKey", params: [DYN, DYN], result: DYN }, + generateKeySync: { fn: "crypto.generateKeySync", params: [DYN, DYN], result: DYN }, + generateKey: { fn: "crypto.generateKeyCb", params: [], result: VOID }, + // Asymmetric keys and signatures (lowerPkiCall): checked-dynamic + // arguments, results converted to the call site's type. + createPrivateKey: { fn: "crypto.createPrivateKey", params: [DYN], result: DYN }, + createPublicKey: { fn: "crypto.createPublicKey", params: [DYN], result: DYN }, + createSign: { fn: "crypto.createSign", params: [DYN], result: DYN }, + createVerify: { fn: "crypto.createVerify", params: [DYN], result: DYN }, + generateKeyPairSync: { fn: "crypto.generateKeyPairSync", params: [], result: DYN }, + generateKeyPair: { fn: "crypto.generateKeyPairCb", params: [], result: VOID }, + sign: { fn: "crypto.signOneshot", params: [], result: DYN }, + verify: { fn: "crypto.verifyOneshot", params: [], result: DYN }, + diffieHellman: { fn: "crypto.diffieHellman", params: [], result: DYN }, + pbkdf2Sync: { + fn: "crypto.pbkdf2", + params: [BYTES_U8, BYTES_U8, F64, F64, STRING], + result: BYTES_U8, + }, + pbkdf2: { fn: "crypto.pbkdf2Cb", params: [], result: VOID }, + hkdfSync: { + fn: "crypto.hkdf", + params: [STRING, BYTES_U8, BYTES_U8, BYTES_U8, F64], + result: DYN, + }, + hkdf: { fn: "crypto.hkdfCb", params: [], result: VOID }, + scryptSync: { fn: "crypto.scrypt", params: [BYTES_U8, BYTES_U8, F64, DYN], result: BYTES_U8 }, + scrypt: { fn: "crypto.scryptCb", params: [], result: VOID }, + // Checked-dynamic arguments; the result is a native Cipheriv or + // Decipheriv handle (lowerCryptoModuleCall). + createCipheriv: { fn: "crypto.cipherNew", params: [BOOL, DYN, DYN, DYN, DYN], result: DYN }, + createDecipheriv: { fn: "crypto.cipherNew", params: [BOOL, DYN, DYN, DYN, DYN], result: DYN }, + // A checked-dynamic curve name; the result is a native ECDH handle + // (lowerCreateEcdh). + createECDH: { fn: "crypto.ecdhNew", params: [DYN], result: DYN }, + // Checked-dynamic arguments; the result is a native DiffieHellman or + // DiffieHellmanGroup handle (lowerCreateDiffieHellman and + // lowerGetDiffieHellman). + createDiffieHellman: { fn: "crypto.dhNew", params: [DYN, DYN, DYN, DYN], result: DYN }, + getDiffieHellman: { fn: "crypto.dhGroupNew", params: [DYN], result: DYN }, + createDiffieHellmanGroup: { fn: "crypto.dhGroupNew", params: [DYN], result: DYN }, + // Prime checks and generation (lowerPrimeCall): checked-dynamic + // arguments, results converted to the call site's type. + checkPrimeSync: { fn: "crypto.checkPrimeSync", params: [], result: DYN }, + // Checked-dynamic arguments, the result converted to the call site's + // type (lowerPrimeCall). + getCipherInfo: { fn: "crypto.getCipherInfo", params: [], result: DYN }, + checkPrime: { fn: "crypto.checkPrimeCb", params: [], result: VOID }, + generatePrimeSync: { fn: "crypto.generatePrimeSync", params: [], result: DYN }, + generatePrime: { fn: "crypto.generatePrimeCb", params: [], result: VOID }, + }, + zlib: { + // The default-options convenience family is special-cased in + // lowerBuiltinModuleCall: string inputs UTF-8 encode, callback forms + // carry program-shaped closures, and explicit options fence per site. + // native-toolchain.ts links libz only when these appear on the IR. + deflate: { fn: "zlib.deflateCb", params: [], result: VOID }, + deflateSync: { fn: "zlib.deflateSync", params: [BYTES_U8], result: BYTES_U8 }, + inflate: { fn: "zlib.inflateCb", params: [], result: VOID }, + inflateSync: { fn: "zlib.inflateSync", params: [BYTES_U8], result: BYTES_U8 }, + deflateRaw: { fn: "zlib.deflateRawCb", params: [], result: VOID }, + deflateRawSync: { fn: "zlib.deflateRawSync", params: [BYTES_U8], result: BYTES_U8 }, + inflateRaw: { fn: "zlib.inflateRawCb", params: [], result: VOID }, + inflateRawSync: { fn: "zlib.inflateRawSync", params: [BYTES_U8], result: BYTES_U8 }, + gzip: { fn: "zlib.gzipCb", params: [], result: VOID }, + gzipSync: { fn: "zlib.gzipSync", params: [BYTES_U8], result: BYTES_U8 }, + gunzip: { fn: "zlib.gunzipCb", params: [], result: VOID }, + gunzipSync: { fn: "zlib.gunzipSync", params: [BYTES_U8], result: BYTES_U8 }, + unzip: { fn: "zlib.unzipCb", params: [], result: VOID }, + unzipSync: { fn: "zlib.unzipSync", params: [BYTES_U8], result: BYTES_U8 }, + crc32: { fn: "zlib.crc32", params: [], result: F64 }, + // Brotli (special-cased in lowerZlibModuleCall): every form takes the + // options entries with Node's BROTLI_ENCODE or BROTLI_DECODE mode. + brotliCompress: { fn: "zlib.cbOpts", params: [], result: VOID }, + brotliCompressSync: { fn: "zlib.syncOpts", params: [], result: BYTES_U8 }, + brotliDecompress: { fn: "zlib.cbOpts", params: [], result: VOID }, + brotliDecompressSync: { fn: "zlib.syncOpts", params: [], result: BYTES_U8 }, + // The stream factories (special-cased in lowerZlibModuleCall): each + // answers a runtime Transform stream over the zlib engine. + createDeflate: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, + createInflate: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, + createGzip: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, + createGunzip: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, + createDeflateRaw: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, + createInflateRaw: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, + createUnzip: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, + createBrotliCompress: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, + createBrotliDecompress: { fn: "zlib.streamNew", params: [], result: ZLIB_STREAM }, + }, + url: { + fileURLToPath: { + fn: "url.fileURLToPathOptions", + params: [DYN, DYN], + result: STRING, + valueParams: [ + { mode: "required", type: DYN }, + { mode: "optional", type: DYN, defaultValue: undefined }, + ], + }, + fileURLToPathBuffer: { + fn: "url.fileURLToPathBuffer", + params: [DYN, DYN], + result: BYTES_U8, + valueParams: [ + { mode: "required", type: DYN }, + { mode: "optional", type: DYN, defaultValue: undefined }, + ], + }, + pathToFileURL: { + fn: "url.pathToFileURLChecked", + params: [DYN, DYN], + result: URL_T, + valueParams: [ + { mode: "required", type: DYN }, + { mode: "optional", type: DYN, defaultValue: undefined }, + ], + }, + // The legacy API and the domain pair (lowerLegacyUrlCall): arguments + // cross as dyn values for Node's own validators; url.parse() answers + // the checked-dynamic Url instance. + parse: { fn: "url.legacyParse", params: [DYN, DYN, DYN], result: DYN }, + format: { fn: "url.legacyFormat", params: [DYN, DYN], result: STRING }, + resolve: { fn: "url.legacyResolve", params: [DYN, DYN], result: STRING }, + domainToASCII: { fn: "url.domainToASCII", params: [DYN], result: STRING }, + domainToUnicode: { fn: "url.domainToUnicode", params: [DYN], result: STRING }, + urlToHttpOptions: { fn: "url.toHttpOptions", params: [DYN], result: DYN }, + }, + child_process: { + // spawnSync's and spawn's call completions are entirely special-cased + // (an omitted args list completes to an empty string[]; spawnSync + // accepts its documented literal options, while spawn supports the + // stdio/detached/env/cwd/windowsHide/shell subset — see + // lowerBuiltinModuleCall); the + // entries carry the canonical shapes. + spawnSync: { fn: "cp.spawnSync", params: [STRING, arrayOf(STRING)], result: SPAWNRES_T }, + spawn: { fn: "cp.spawn", params: [STRING, arrayOf(STRING)], result: CHILD_T }, + fork: { fn: "cp.fork", params: [STRING, arrayOf(STRING)], result: CHILD_T }, + // execFileSync(file, args?, options?) and execSync(command, options?) + // share the cp.execSync runtime entry (execSync sets the shell flag); + // both call completions are special-cased in lowerBuiltinModuleCall. + // The entries carry canonical shapes for the coverage/fence machinery. + execFileSync: { fn: "cp.execSync", params: [STRING, arrayOf(STRING)], result: STRING }, + execSync: { fn: "cp.execSync", params: [STRING], result: STRING }, + }, + // node:util lowers through dedicated paths: promisify + // only in the const-binding-over-execFile shape — recognized in + // lowerVarDecl / collectGlobals BEFORE any call lowering runs — and + // inspect/format/formatWithOptions plus parseArgs through the util spoke + // (lower-inspect.ts: per-type synthesized traversal helpers, + // compile-time format strings, checked-dynamic config/result for + // parseArgs), which both dispatch paths try before the generic table. + // parseArgs is tabled as well so the generated surface manifest records + // the dedicated static member; the spoke owns its optional arity and + // call-site-specific result type before this canonical signature is used. + util: { + styleText: { + fn: "util.styleText", + params: [DYN, DYN, DYN], + result: STRING, + valueParams: [ + { mode: "required", type: DYN }, + { mode: "required", type: DYN }, + { mode: "optional", type: DYN, defaultValue: undefined }, + ], + }, + isDeepStrictEqual: { + fn: "util.isDeepStrictEqual", + params: [DYN, DYN, DYN], + result: BOOL, + valueParams: [ + { mode: "required", type: DYN }, + { mode: "required", type: DYN }, + { mode: "optional", type: DYN, defaultValue: undefined }, + ], + }, + parseArgs: { fn: "util.parseArgs", params: [DYN], result: DYN }, + parseEnv: { fn: "util.parseEnv", params: [DYN], result: DYN }, + getSystemErrorName: { + fn: "util.getSystemErrorName", + params: [DYN], + result: STRING, + valueParams: exactValueParams(DYN), + }, + getSystemErrorMessage: { + fn: "util.getSystemErrorMessage", + params: [DYN], + result: STRING, + valueParams: exactValueParams(DYN), + }, + getSystemErrorMap: { fn: "util.systemErrorEntries", params: [], result: DYN }, + stripVTControlCharacters: { + fn: "util.stripVTControlCharacters", + params: [DYN], + result: STRING, + valueParams: exactValueParams(DYN), + }, + toUSVString: { + fn: "util.toUSVString", + params: [DYN], + result: STRING, + valueParams: exactValueParams(DYN), + }, + // The function helpers take checked-dynamic arguments and answer native + // dyn functions, which a static function slot checks when it receives + // one (lowerUtilCallableCall in the util spoke). + inherits: { + fn: "util.inherits", + params: [DYN, DYN], + result: VOID, + valueParams: [ + { mode: "required", type: DYN }, + { mode: "required", type: DYN }, + ], + }, + deprecate: { + fn: "util.deprecate", + params: [DYN, DYN, DYN, DYN], + result: DYN, + valueParams: [ + { mode: "required", type: DYN }, + { mode: "required", type: DYN }, + { mode: "optional", type: DYN, defaultValue: undefined }, + { mode: "optional", type: DYN, defaultValue: undefined }, + ], + }, + callbackify: { + fn: "util.callbackify", + params: [DYN], + result: DYN, + valueParams: [{ mode: "required", type: DYN }], + }, + debuglog: { + fn: "util.debuglog", + params: [DYN, DYN], + result: DYN, + valueParams: [ + { mode: "required", type: DYN }, + { mode: "optional", type: DYN, defaultValue: undefined }, + ], + }, + debug: { + fn: "util.debuglog", + params: [DYN, DYN], + result: DYN, + valueParams: [ + { mode: "required", type: DYN }, + { mode: "optional", type: DYN, defaultValue: undefined }, + ], + }, + }, + // The util/types spoke supplies the probe name to the shared brand check. + "util/types": { + isAnyArrayBuffer: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isArrayBuffer: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isArrayBufferView: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isDataView: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isTypedArray: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isUint8Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isUint8ClampedArray: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isUint16Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isUint32Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isInt8Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isInt16Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isInt32Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isFloat32Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isFloat64Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isMap: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isSet: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isWeakMap: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isWeakSet: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isRegExp: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isNativeError: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isPromise: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isProxy: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isAsyncFunction: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isGeneratorFunction: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isGeneratorObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isDate: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isSharedArrayBuffer: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isMapIterator: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isSetIterator: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isKeyObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isNumberObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isStringObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isBooleanObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isBigIntObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isSymbolObject: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isBoxedPrimitive: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isBigInt64Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isBigUint64Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isFloat16Array: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isCryptoKey: { fn: "util.typeIs", params: [DYN], result: BOOL }, + isExternal: { fn: "util.typeIs", params: [DYN], result: BOOL }, + }, + buffer: { + isAscii: { fn: "buffer.isAscii", params: [DYN], result: BOOL }, + isUtf8: { fn: "buffer.isUtf8", params: [DYN], result: BOOL }, + transcode: { fn: "buffer.transcode", params: [DYN, DYN, DYN], result: BYTES_U8 }, + }, + tty: { + isatty: { fn: "process.isTTY", params: [F64], result: BOOL }, + }, + process: { + loadEnvFile: { fn: "process.loadEnvFile", params: [DYN], result: VOID }, + }, + // node:string_decoder's surface is the StringDecoder CLASS — new/write/ + // end are special-cased (lowerNew + lowerStringDecoderMethodCall); no + // function members exist to table. + string_decoder: {}, + // node:querystring — the legacy query-string codec (NOT URLSearchParams; + // the escaping and '+' rules differ). escape/unescape ride the table + // path directly; parse and stringify are special-cased in + // lowerBuiltinModuleCall (parse's result is the call site's mapped + // ParsedUrlQuery dictionary — the networkInterfaces verification stance + // — and its sep/eq/options complete there; stringify's object argument + // crosses as a dyn value). decode/encode are Node's own aliases of + // parse/stringify (`const decode = parse` in lib/querystring.js) and + // route to the same special cases; the entries carry canonical shapes. + querystring: { + parse: { fn: "qs.parse", params: [STRING], result: VOID }, + decode: { fn: "qs.parse", params: [STRING], result: VOID }, + stringify: { fn: "qs.stringify", params: [DYN], result: STRING }, + encode: { fn: "qs.stringify", params: [DYN], result: STRING }, + escape: { + fn: "qs.escape", + params: [STRING], + result: STRING, + valueParams: [{ mode: "required", type: STRING }], + }, + unescape: { + fn: "qs.unescape", + params: [STRING], + result: STRING, + valueParams: [{ mode: "required", type: STRING }], + }, + }, + // node:punycode (deprecated): punycode.js 2.1.0's conversions over + // strings (scr_url.c). ucs2.decode/encode are members of the module's + // ucs2 object, dispatched as module members (builtinMemberOf). The + // DEP0040 report rides the module's load sites (punycodeLoadWarning). + punycode: { + decode: { fn: "punycode.decode", params: [STRING], result: STRING }, + encode: { fn: "punycode.encode", params: [STRING], result: STRING }, + toASCII: { fn: "punycode.toASCII", params: [STRING], result: STRING }, + toUnicode: { fn: "punycode.toUnicode", params: [STRING], result: STRING }, + "ucs2.decode": { fn: "punycode.ucs2Decode", params: [STRING], result: arrayOf(F64) }, + "ucs2.encode": { fn: "punycode.ucs2Encode", params: [arrayOf(F64)], result: STRING }, + }, + // node:constants (deprecated) is one frozen object (Object.assign of + // os.constants' groups, fs.constants and crypto.constants): bindings of + // the module read it as a checked-dynamic value (builtinConstantsObject). + constants: {}, + // node:readline: createInterface's options are entirely special-cased + // (exactly { input: process.stdin, output?: process.stdout } — see + // lowerBuiltinModuleCall); the entry carries the canonical shape. The + // interface's question/close/on lower through + // lowerReadlineMethodCall. + readline: { + createInterface: { fn: "rl.create", params: [], result: F64 }, + }, + // node:readline/promises: the same Interface with the promise question + // (lowerReadlineMethodCall tells the forms apart by the call's result). + "readline/promises": { + createInterface: { fn: "rl.create", params: [], result: F64 }, + }, + // node:net and node:http lower ENTIRELY through the server spoke + // (lower-server.ts — every call shape is special-cased: closures, the + // optional connect host, writeHead's literal headers); the member list + // is the lower-server dispatch there. The modules still need keys here so future + // table entries have a home, and so the "recognized module, unlowered + // member" fence wording applies. + net: { + // The process-wide happy-eyeballs attempt budget: one runtime double + // in the core unit (never links scr_net.c by itself), default 250ms + // like Node's. + getDefaultAutoSelectFamilyAttemptTimeout: { + fn: "net.getAutoSelTimeout", + params: [], + result: F64, + }, + setDefaultAutoSelectFamilyAttemptTimeout: { + fn: "net.setAutoSelTimeout", + params: [F64], + result: VOID, + }, + // Node's IPv4Reg / IPv6Reg tests over String(input). + isIP: { fn: "net.isIP", params: [DYN], result: F64 }, + isIPv4: { fn: "net.isIPv4", params: [DYN], result: BOOL }, + isIPv6: { fn: "net.isIPv6", params: [DYN], result: BOOL }, + }, + http: {}, + // node:tls and node:https ride the same spoke (tls.createServer's + // options + secureConnection handler, https.createServer, and the + // https client's rejectUnauthorized/ca options are all special-cased + // in lower-server.ts). + tls: {}, + https: {}, + // node:dgram and node:dns lower ENTIRELY through the dgram spoke + // (lower-dgram.ts — createSocket's option literal, dns.lookup's + // options + callback, and the Socket method surface are all + // special-cased); the keys exist for the same reason net/http's do. + dgram: {}, + dns: {}, + // node:dns/promises rides the same spoke (lookup's promise form). + "dns/promises": {}, + // node:v8: getHeapStatistics answers allocator-derived figures in + // Node's shape (builtins/v8.ts — the entry carries the canonical + // shape); every other member fences with the by-design reason + // (builtinFenceHintOf). + v8: { + getHeapStatistics: { fn: "process.memoryUsageTake", params: [], result: VOID }, + }, + // node:stream/web re-exports the web stream globals (the same objects); + // its members lower through the globals' own paths. + "stream/web": {}, + // node:assert lowers ENTIRELY through the assert spoke (lower-assert.ts + // — every call shape is special-cased: optional messages complete, the + // comparisons pick per-type libCalls, deep equality synthesizes + // helpers); the keys exist so unlowered members fence module-qualified + // with the hints below. + assert: {}, + "assert/strict": {}, + // node:test lowers ENTIRELY through the test spoke (lower-test.ts — + // registrations, suites, hooks, the TestContext surface); the key + // exists so unlowered members fence module-qualified. + test: {}, + // node:stream/promises lowers through the stream spoke too + // (lower-stream.ts — finished/pipeline's promise forms special-case + // their stream arguments exactly like the callback forms); the key + // exists so unlowered members fence module-qualified. + "stream/promises": {}, + // node:stream/consumers rides the stream spoke as well (text/json/ + // buffer/arrayBuffer special-case their stream argument); blob fences + // module-qualified with the pointed hint below. + "stream/consumers": {}, + // node:timers/promises — the delay-only setTimeout and bare setImmediate + // (void promises the shared timer heap settles), and scheduler.wait / + // scheduler.yield, which Node defines as setTimeout(delay, undefined, + // options) and setImmediate(). The arity completion (omitted delay = + // Node's 1ms) and the value/options fences are special-cased in + // lowerBuiltinModuleCall; these entries carry the canonical shapes and + // route the dispatch. + "timers/promises": { + setTimeout: { fn: "tp.setTimeout", params: [F64], result: { kind: "promise", inner: VOID } }, + setImmediate: { fn: "tp.setImmediate", params: [], result: { kind: "promise", inner: VOID } }, + "scheduler.wait": { + fn: "tp.setTimeout", + params: [F64], + result: { kind: "promise", inner: VOID }, + }, + "scheduler.yield": { + fn: "tp.setImmediate", + params: [], + result: { kind: "promise", inner: VOID }, + }, + }, + // node:diagnostics_channel — the pub/sub core. channel() answers an f64 + // handle (type-mapper.ts maps Channel to F64); the subscriber arguments box + // into the checked-dynamic tree (special-cased in lowerBuiltinModuleCall — the entries + // carry canonical shapes and route the dispatch). The Channel method + // surface lowers through lowerDiagnosticsChannelMethodCall/lowerDiagnosticsChannelProperty. + diagnostics_channel: { + channel: { fn: "dc.channel", params: [STRING], result: F64 }, + subscribe: { fn: "dc.subscribe", params: [STRING, DYN], result: VOID }, + unsubscribe: { fn: "dc.unsubscribe", params: [STRING, DYN], result: BOOL }, + hasSubscribers: { fn: "dc.hasSubscribers", params: [STRING], result: BOOL }, + // The string form's canonical shape; the collection form (an object + // literal of five Channels) is special-cased in lowerBuiltinModuleCall. + tracingChannel: { fn: "dc.tracingChannel", params: [STRING], result: F64 }, + }, + }; +} /** Builtin-module CONSTANTS (value reads of named imports): each lowers to * a literal of its value's kind. The bare-module values are the TARGET @@ -2080,7 +2099,7 @@ export const BUILTIN_MODULE_CONSTS: Record< * the sidecar's determinism attestation demotes on them by prefix, so the * member's fence detector must witness them too (fencing one spelling * fences the operation, the trimLeft/trimStart rule). Keyed like - * BUILTIN_MODULE_FNS; consumed by the fence taxonomy + * builtinModuleFns(); consumed by the fence taxonomy * (library/fence-eval.ts) and the attestation-parity test. */ export const BUILTIN_MODULE_FN_ALIASES: Record< string, @@ -2232,628 +2251,643 @@ export interface AmbientSurfaceRow { note?: string; } -export const AMBIENT_SURFACE_FNS: readonly AmbientSurfaceRow[] = [ - { - id: "node-builtin.worker_threads.Worker", - kind: "node-builtin", - name: "worker_threads.Worker", - fns: ["worker.new"], - note: "native threads with statically compiled entry points, workerData, argv and message events", - }, - { - id: "node-builtin.worker_threads.metadata", - kind: "node-builtin", - name: "worker_threads metadata", - fns: [ - "worker.isMainThread", - "worker.threadId", - "worker.data", - "worker.parentPort", - "worker.resourceLimits", - "worker.threadName", - ], - note: "current-thread metadata and the worker's parent message port", - }, - { - id: "stdlib.sharedArrayBuffer", - kind: "stdlib", - name: "SharedArrayBuffer", - fns: ["sharedArrayBuffer.new"], - note: "fixed shared storage with context-local typed-array and DataView wrappers", - }, - { - id: "stdlib.blob", - kind: "stdlib", - name: "Blob", - fns: ["blob.new", "blob.slice", "blob.text", "blob.bytes", "blob.arrayBuffer", "blob.is"], - note: "immutable bytes with size, type, slice(), text(), bytes(), arrayBuffer() and structured cloning", - }, - { - id: "stdlib.file", - kind: "stdlib", - name: "File", - fns: ["blob.fileNew"], - note: "a Blob with name and lastModified (Date.now() when absent)", - }, - { - id: "stdlib.webcrypto.subtle", - kind: "stdlib", - name: "globalThis.crypto.subtle", - fns: [ - "webcrypto.generateKey", - "webcrypto.importKey", - "webcrypto.exportKey", - "webcrypto.encrypt", - "webcrypto.decrypt", - "webcrypto.wrapKey", - "webcrypto.unwrapKey", - "webcrypto.deriveBits", - "webcrypto.deriveKey", - "webcrypto.sign", - "webcrypto.verify", - "webcrypto.digest", - ], - note: "importKey, generateKey and exportKey (raw and jwk) for HMAC and AES keys, importKey for PBKDF2 and HKDF keys, AES-GCM, AES-CBC and AES-CTR encrypt and decrypt, wrapKey and unwrapKey of secret keys with AES-KW or those ciphers, PBKDF2 and HKDF deriveBits and deriveKey, HMAC sign and verify, generateKey, importKey, exportKey, sign and verify for ECDSA, Ed25519, RSASSA-PKCS1-v1_5 and RSA-PSS, and SHA-1/SHA-2 digest; other methods, algorithms and key formats are refused", - }, - { - id: "stdlib.webcrypto.CryptoKey", - kind: "stdlib", - name: "CryptoKey", - fns: ["webcrypto.isCryptoKey"], - note: "secret HMAC, AES, PBKDF2 and HKDF keys with type, extractable, algorithm and usages, and instanceof CryptoKey", - }, - { - id: "stdlib.atomics", - kind: "stdlib", - name: "Atomics", - fns: ["atomics.op", "atomics.wait", "atomics.notify"], - note: "8-, 16- and 32-bit integer operations, plus Int32Array wait and notify", - }, - { - id: "node-builtin.fs.callbacks", - kind: "node-builtin", - name: "fs error-first callbacks", - fns: ["fs.callbackValue", "fs.callbackCall", "fs.callbackGlob"], - note: "native filesystem callbacks, including stored platform adapter functions", - }, - // ── the Date slice (lowerDateCall/lowerNew): statics, construction, - // stored read-only values, calendar getters, and ISO formatting. - { - id: "stdlib.date.now", - kind: "stdlib", - name: "Date.now", - fns: ["date.now"], - note: "the live clock", - }, - { - id: "stdlib.date.parse", - kind: "stdlib", - name: "Date.parse", - fns: ["date.parse"], - note: "one date string, using V8's date parser shared with new Date(dateString)", - }, - { - id: "stdlib.date.constructor", - kind: "stdlib", - name: "Date constructor", - fns: [ - "date.newNow", - "date.newMs", - "date.newString", - "date.nativeNew", - "date.newLocal", - "date.nativeNewFields", - "date.nativeNewValue", - "date.argumentsTime", - "date.classOperation", - ], - note: "zero arguments, one milliseconds/date-string argument, or local-time year/month fields; values are the read-only TimeClip scalar slice", - }, - { - id: "stdlib.date.setters", - kind: "stdlib", - name: "Date.prototype setters", - fns: ["date.setFields", "date.timeClip", "date.store"], - note: "setTime and the local and UTC field setters, with their optional arguments", - }, - { - id: "stdlib.date.UTC", - kind: "stdlib", - name: "Date.UTC", - fns: ["date.utc"], - note: "the lowered call form takes 1 to 7 number arguments", - }, - { - id: "stdlib.date.getTime", - kind: "stdlib", - name: "Date.prototype.getTime", - fns: ["date.getTime", "date.parseGetTime"], - note: "the millisecond value of a stored Date", - }, - { - id: "stdlib.date.valueOf", - kind: "stdlib", - name: "Date.prototype.valueOf", - fns: ["date.valueOf"], - note: "the same millisecond read as getTime()", - }, - { - id: "stdlib.date.toISOString", - kind: "stdlib", - name: "Date.prototype.toISOString", - fns: ["date.toISOString", "date.toISOStringValue"], - note: "UTC ISO formatting over constructed and stored Date values", - }, - { - id: "stdlib.date.toUTCString", - kind: "stdlib", - name: "Date.prototype.toUTCString", - fns: ["date.toUTCString"], - note: "RFC 7231 IMF-fixdate formatting over stored Date values", - }, - { - id: "stdlib.date.getFullYear", - kind: "stdlib", - name: "Date.prototype.getFullYear", - fns: ["date.getFullYear"], - }, - { - id: "stdlib.date.getUTCFullYear", - kind: "stdlib", - name: "Date.prototype.getUTCFullYear", - fns: ["date.getUTCFullYear"], - }, - { - id: "stdlib.date.getMonth", - kind: "stdlib", - name: "Date.prototype.getMonth", - fns: ["date.getMonth"], - }, - { - id: "stdlib.date.getUTCMonth", - kind: "stdlib", - name: "Date.prototype.getUTCMonth", - fns: ["date.getUTCMonth"], - }, - { - id: "stdlib.date.getDate", - kind: "stdlib", - name: "Date.prototype.getDate", - fns: ["date.getDate"], - }, - { - id: "stdlib.date.getUTCDate", - kind: "stdlib", - name: "Date.prototype.getUTCDate", - fns: ["date.getUTCDate"], - }, - { id: "stdlib.date.getDay", kind: "stdlib", name: "Date.prototype.getDay", fns: ["date.getDay"] }, - { - id: "stdlib.date.getUTCDay", - kind: "stdlib", - name: "Date.prototype.getUTCDay", - fns: ["date.getUTCDay"], - }, - { - id: "stdlib.date.getHours", - kind: "stdlib", - name: "Date.prototype.getHours", - fns: ["date.getHours"], - }, - { - id: "stdlib.date.getUTCHours", - kind: "stdlib", - name: "Date.prototype.getUTCHours", - fns: ["date.getUTCHours"], - }, - { - id: "stdlib.date.getMinutes", - kind: "stdlib", - name: "Date.prototype.getMinutes", - fns: ["date.getMinutes"], - }, - { - id: "stdlib.date.getUTCMinutes", - kind: "stdlib", - name: "Date.prototype.getUTCMinutes", - fns: ["date.getUTCMinutes"], - }, - { - id: "stdlib.date.getSeconds", - kind: "stdlib", - name: "Date.prototype.getSeconds", - fns: ["date.getSeconds"], - }, - { - id: "stdlib.date.getUTCSeconds", - kind: "stdlib", - name: "Date.prototype.getUTCSeconds", - fns: ["date.getUTCSeconds"], - }, - { - id: "stdlib.date.getMilliseconds", - kind: "stdlib", - name: "Date.prototype.getMilliseconds", - fns: ["date.getMilliseconds"], - }, - { - id: "stdlib.date.getUTCMilliseconds", - kind: "stdlib", - name: "Date.prototype.getUTCMilliseconds", - fns: ["date.getUTCMilliseconds"], - }, - { - id: "stdlib.date.getTimezoneOffset", - kind: "stdlib", - name: "Date.prototype.getTimezoneOffset", - fns: ["date.getTimezoneOffset"], - }, - { - id: "stdlib.date.toString", - kind: "stdlib", - name: "Date.prototype.toString", - fns: ["date.toString"], - note: "local time with the host zone's long English name; String(date) and template literals use it", - }, - { - id: "stdlib.date.toDateString", - kind: "stdlib", - name: "Date.prototype.toDateString", - fns: ["date.toDateString"], - }, - { - id: "stdlib.date.toTimeString", - kind: "stdlib", - name: "Date.prototype.toTimeString", - fns: ["date.toTimeString"], - }, - // ── perf_hooks (lowerPerfHooksCall): the monotonic clock. - { - id: "node-builtin.perf_hooks.performance.now", - kind: "node-builtin", - name: "perf_hooks.performance.now", - fns: ["perf.now"], - note: "the global performance object and the performance.now.bind(performance) function value reach the same clock", - }, - { - id: "node-builtin.perf_hooks.performance.mark", - kind: "node-builtin", - name: "perf_hooks.performance.mark", - fns: [ - "perf.mark", - "perf.entryName", - "perf.entryType", - "perf.entryStart", - "perf.entryDuration", - "perf.entryDetail", - "perf.entryKeep", - "perf.entryRef", - ], - note: "records a mark in the thread's performance timeline at the live clock or the given startTime", - }, - { - id: "node-builtin.perf_hooks.performance.measure", - kind: "node-builtin", - name: "perf_hooks.performance.measure", - fns: ["perf.measure"], - note: "the mark-name, timestamp, and options forms are one surface", - }, - { - id: "node-builtin.perf_hooks.performance.getEntries", - kind: "node-builtin", - name: "perf_hooks.performance.getEntries", - fns: ["perf.entries"], - note: "getEntries, getEntriesByName, and getEntriesByType read the same timeline", - }, - { - id: "node-builtin.perf_hooks.performance.clearMarks", - kind: "node-builtin", - name: "perf_hooks.performance.clearMarks", - fns: ["perf.clearMarks"], - }, - { - id: "node-builtin.perf_hooks.performance.clearMeasures", - kind: "node-builtin", - name: "perf_hooks.performance.clearMeasures", - fns: ["perf.clearMeasures"], - }, - { - id: "node-builtin.perf_hooks.performance.eventLoopUtilization", - kind: "node-builtin", - name: "perf_hooks.performance.eventLoopUtilization", - fns: ["perf.loopStart", "perf.idleTime"], - note: "active time is the main thread's CPU time since the loop started; the one- and two-argument difference forms are supported", - }, - { - id: "node-builtin.perf_hooks.monitorEventLoopDelay", - kind: "node-builtin", - name: "perf_hooks.monitorEventLoopDelay", - fns: [ - "perf.eldNew", - "perf.eldEnable", - "perf.eldDisable", - "perf.eldReset", - "perf.eldPercentile", - "perf.eldStat", - ], - note: "an unref'd sampling interval records the delay histogram; enable, disable, reset, percentile and the min, max, mean, stddev, count and exceeds readings are supported", - }, - // ── the process global's ambient reads and authority calls - // (lowerProcessProperty/lowerProcessMethodCall — process is a - // provenance-checked global here, not an importable module). - { - id: "node-builtin.process.env", - kind: "node-builtin", - name: "process.env", - fns: ["process.envGet", "process.envSet", "process.envUnset", "process.envPairs"], - note: "reads, writes, deletes, and enumeration of the process environment (the process global)", - }, - { - id: "node-builtin.process.argv", - kind: "node-builtin", - name: "process.argv", - fns: ["process.argv"], - }, - { - id: "node-builtin.process.hrtime", - kind: "node-builtin", - name: "process.hrtime", - fns: ["process.hrtimeValue"], - note: "native monotonic tuple clock and bigint member; direct calls and stored JavaScript callable values", - }, - { - id: "node-builtin.process.getBuiltinModule", - kind: "node-builtin", - name: "process.getBuiltinModule", - fns: ["process.builtinId", "process.builtinModule", "process.builtinUnsupported"], - note: "native path and os export subsets plus current-thread worker_threads metadata; other modules and exports throw SC2020", - }, - { - id: "node-builtin.process.versions", - kind: "node-builtin", - name: "process.versions", - fns: ["process.versions"], - note: "shared version dictionary containing node and openssl; other components are absent unless defined by the program", - }, - { - id: "node-builtin.process.release", - kind: "node-builtin", - name: "process.release", - fns: ["process.release"], - note: "the compatibility target's release metadata as one stable read-only object", - }, - { - id: "node-builtin.process.cwd", - kind: "node-builtin", - name: "process.cwd", - fns: ["process.cwd"], - }, - { - id: "node-builtin.process.chdir", - kind: "node-builtin", - name: "process.chdir", - fns: ["process.chdir"], - }, - { - id: "node-builtin.process.pid", - kind: "node-builtin", - name: "process.pid", - fns: ["process.pid"], - }, - { - id: "node-builtin.process.getuid", - kind: "node-builtin", - name: "process.getuid", - fns: ["process.getuid"], - }, - { - id: "node-builtin.process.getgid", - kind: "node-builtin", - name: "process.getgid", - fns: ["process.getgid"], - }, - { - id: "node-builtin.process.geteuid", - kind: "node-builtin", - name: "process.geteuid", - fns: ["process.geteuid"], - }, - { - id: "node-builtin.process.getegid", - kind: "node-builtin", - name: "process.getegid", - fns: ["process.getegid"], - }, - { - id: "node-builtin.process.getgroups", - kind: "node-builtin", - name: "process.getgroups", - fns: ["process.getgroups"], - }, - { - id: "node-builtin.process.ppid", - kind: "node-builtin", - name: "process.ppid", - fns: ["process.ppid"], - }, - { - id: "node-builtin.process.title", - kind: "node-builtin", - name: "process.title", - fns: ["process.title", "process.setTitle"], - note: "reads and writes of the process title are one surface", - }, - { - id: "node-builtin.process.argv0", - kind: "node-builtin", - name: "process.argv0", - fns: ["process.argv0"], - }, - { - id: "node-builtin.process.execArgv", - kind: "node-builtin", - name: "process.execArgv", - fns: ["process.execArgv"], - }, - { - id: "node-builtin.process.execPath", - kind: "node-builtin", - name: "process.execPath", - fns: ["process.execPath"], - }, - { - id: "node-builtin.process.uptime", - kind: "node-builtin", - name: "process.uptime", - fns: ["process.uptime"], - }, - { - id: "node-builtin.process.availableMemory", - kind: "node-builtin", - name: "process.availableMemory", - fns: ["process.availableMemory"], - }, - { - id: "node-builtin.process.constrainedMemory", - kind: "node-builtin", - name: "process.constrainedMemory", - fns: ["process.constrainedMemory"], - }, - { - id: "node-builtin.process.memoryUsage", - kind: "node-builtin", - name: "process.memoryUsage", - fns: ["process.memoryUsageTake", "process.memoryUsageField", "process.rss"], - note: "the record and memoryUsage.rss() read live memory state; external and arrayBuffers are 0", - }, - { - id: "node-builtin.process.resourceUsage", - kind: "node-builtin", - name: "process.resourceUsage", - fns: ["process.rusage"], - note: "getrusage's 16 fields — every field read samples live machine state", - }, - { - id: "node-builtin.process.cpuUsage", - kind: "node-builtin", - name: "process.cpuUsage", - fns: [ - "process.cpuUser", - "process.cpuSystem", - "process.cpuUserDiff", - "process.cpuSystemDiff", - "process.cpuPrevValidate", - ], - note: "the plain-sample and previous-value diff forms are one surface", - }, - { - id: "node-builtin.process.threadCpuUsage", - kind: "node-builtin", - name: "process.threadCpuUsage", - fns: [ - "process.threadCpuUser", - "process.threadCpuSystem", - "process.threadCpuUserDiff", - "process.threadCpuSystemDiff", - ], - note: "the plain-sample and previous-value diff forms are one surface", - }, - { - id: "node-builtin.process.isTTY", - kind: "node-builtin", - name: "process.isTTY", - fns: ["process.isTTY"], - note: "the isTTY read on process.stdin/stdout/stderr — one surface across the three streams", - }, - { - id: "node-builtin.process.columns", - kind: "node-builtin", - name: "process.columns", - fns: ["process.columns"], - note: "the columns read on the process stdio streams (terminal geometry)", - }, - { - id: "node-builtin.process.rows", - kind: "node-builtin", - name: "process.rows", - fns: ["process.rows"], - note: "the rows read on process.stdout/stderr (terminal geometry)", - }, - { - id: "node-builtin.process.kill", - kind: "node-builtin", - name: "process.kill", - fns: ["process.kill", "process.killNum"], - note: "the signal-name and signal-number forms are one surface", - }, - { - id: "node-builtin.process.umask", - kind: "node-builtin", - name: "process.umask", - fns: ["process.umask"], - }, - { - id: "node-builtin.process.exit", - kind: "node-builtin", - name: "process.exit", - fns: ["process.exit", "process.exiting"], - note: "process.exit and the process._exiting flag read are one surface", - }, - { - id: "node-builtin.process.exitCode", - kind: "node-builtin", - name: "process.exitCode", - fns: ["process.setExitCode", "process.setExitCodeTracked", "process.hasExitCode"], - note: "numeric writes in statement position set the implicit exit status; reads answer the assigned code or undefined; process.exit() reads it", - }, - // ── the tls CA store (lowerTlsCaCall / lowerTlsRootCertificates): the - // host's trust anchors, read and replaced. Dedicated paths, and - // rootCertificates is a VALUE read with no call form at all, so none of - // the three can hang off a lowering-table row. Split three ways rather - // than folded into one "CA store" surface: a library author who denies - // REPLACING the trust anchors is making a different decision from one - // who denies reading them, and each Node spelling is the name they will - // reach for when writing the fence. - { - id: "node-builtin.tls.getCACertificates", - kind: "node-builtin", - name: "tls.getCACertificates", - fns: ["tlsca.get"], - note: "the per-type cached PEM bundle: 'default' and 'extra' additionally read NODE_EXTRA_CA_CERTS, 'system' the platform store", - }, - { - id: "node-builtin.tls.rootCertificates", - kind: "node-builtin", - name: "tls.rootCertificates", - fns: ["tlsca.root"], - note: "the value read; answers the same bundled array as getCACertificates('bundled'), but fenced under its own id — the spelling an author writes", - }, - { - id: "node-builtin.tls.setDefaultCACertificates", - kind: "node-builtin", - name: "tls.setDefaultCACertificates", - fns: ["tlsca.set"], - note: "replaces the default set and the client trust anchors for the rest of the process", - }, - // os.constants is a VALUE read (lowerNamespaceBuiltinProperty and the - // named-import path): the platform's null-prototype constants object. - { - id: "node-builtin.os.constants", - kind: "node-builtin", - name: "os.constants", - fns: ["os.constants"], - note: "the platform's dlopen, errno, signals and priority groups; members a platform lacks read as undefined", - }, - // fs.constants as a value, and its members beyond the baked access-mode - // bits: the target libc's null-prototype constants object. - { - id: "node-builtin.fs.constants", - kind: "node-builtin", - name: "fs.constants", - fns: ["fs.constants"], - note: "node_constants.cc's fs group under the target libc's macros; members a platform lacks read as undefined", - }, -]; +let ambientSurfaceRows: readonly AmbientSurfaceRow[] | undefined; + +/** The ambient surface rows, built on the first call. */ +export function ambientSurfaceFns(): readonly AmbientSurfaceRow[] { + ambientSurfaceRows ??= buildAmbientSurfaceFns(); + return ambientSurfaceRows; +} + +function buildAmbientSurfaceFns(): readonly AmbientSurfaceRow[] { + return [ + { + id: "node-builtin.worker_threads.Worker", + kind: "node-builtin", + name: "worker_threads.Worker", + fns: ["worker.new"], + note: "native threads with statically compiled entry points, workerData, argv and message events", + }, + { + id: "node-builtin.worker_threads.metadata", + kind: "node-builtin", + name: "worker_threads metadata", + fns: [ + "worker.isMainThread", + "worker.threadId", + "worker.data", + "worker.parentPort", + "worker.resourceLimits", + "worker.threadName", + ], + note: "current-thread metadata and the worker's parent message port", + }, + { + id: "stdlib.sharedArrayBuffer", + kind: "stdlib", + name: "SharedArrayBuffer", + fns: ["sharedArrayBuffer.new"], + note: "fixed shared storage with context-local typed-array and DataView wrappers", + }, + { + id: "stdlib.blob", + kind: "stdlib", + name: "Blob", + fns: ["blob.new", "blob.slice", "blob.text", "blob.bytes", "blob.arrayBuffer", "blob.is"], + note: "immutable bytes with size, type, slice(), text(), bytes(), arrayBuffer() and structured cloning", + }, + { + id: "stdlib.file", + kind: "stdlib", + name: "File", + fns: ["blob.fileNew"], + note: "a Blob with name and lastModified (Date.now() when absent)", + }, + { + id: "stdlib.webcrypto.subtle", + kind: "stdlib", + name: "globalThis.crypto.subtle", + fns: [ + "webcrypto.generateKey", + "webcrypto.importKey", + "webcrypto.exportKey", + "webcrypto.encrypt", + "webcrypto.decrypt", + "webcrypto.wrapKey", + "webcrypto.unwrapKey", + "webcrypto.deriveBits", + "webcrypto.deriveKey", + "webcrypto.sign", + "webcrypto.verify", + "webcrypto.digest", + ], + note: "importKey, generateKey and exportKey (raw and jwk) for HMAC and AES keys, importKey for PBKDF2 and HKDF keys, AES-GCM, AES-CBC and AES-CTR encrypt and decrypt, wrapKey and unwrapKey of secret keys with AES-KW or those ciphers, PBKDF2 and HKDF deriveBits and deriveKey, HMAC sign and verify, generateKey, importKey, exportKey, sign and verify for ECDSA, Ed25519, RSASSA-PKCS1-v1_5 and RSA-PSS, and SHA-1/SHA-2 digest; other methods, algorithms and key formats are refused", + }, + { + id: "stdlib.webcrypto.CryptoKey", + kind: "stdlib", + name: "CryptoKey", + fns: ["webcrypto.isCryptoKey"], + note: "secret HMAC, AES, PBKDF2 and HKDF keys with type, extractable, algorithm and usages, and instanceof CryptoKey", + }, + { + id: "stdlib.atomics", + kind: "stdlib", + name: "Atomics", + fns: ["atomics.op", "atomics.wait", "atomics.notify"], + note: "8-, 16- and 32-bit integer operations, plus Int32Array wait and notify", + }, + { + id: "node-builtin.fs.callbacks", + kind: "node-builtin", + name: "fs error-first callbacks", + fns: ["fs.callbackValue", "fs.callbackCall", "fs.callbackGlob"], + note: "native filesystem callbacks, including stored platform adapter functions", + }, + // ── the Date slice (lowerDateCall/lowerNew): statics, construction, + // stored read-only values, calendar getters, and ISO formatting. + { + id: "stdlib.date.now", + kind: "stdlib", + name: "Date.now", + fns: ["date.now"], + note: "the live clock", + }, + { + id: "stdlib.date.parse", + kind: "stdlib", + name: "Date.parse", + fns: ["date.parse"], + note: "one date string, using V8's date parser shared with new Date(dateString)", + }, + { + id: "stdlib.date.constructor", + kind: "stdlib", + name: "Date constructor", + fns: [ + "date.newNow", + "date.newMs", + "date.newString", + "date.nativeNew", + "date.newLocal", + "date.nativeNewFields", + "date.nativeNewValue", + "date.argumentsTime", + "date.classOperation", + ], + note: "zero arguments, one milliseconds/date-string argument, or local-time year/month fields; values are the read-only TimeClip scalar slice", + }, + { + id: "stdlib.date.setters", + kind: "stdlib", + name: "Date.prototype setters", + fns: ["date.setFields", "date.timeClip", "date.store"], + note: "setTime and the local and UTC field setters, with their optional arguments", + }, + { + id: "stdlib.date.UTC", + kind: "stdlib", + name: "Date.UTC", + fns: ["date.utc"], + note: "the lowered call form takes 1 to 7 number arguments", + }, + { + id: "stdlib.date.getTime", + kind: "stdlib", + name: "Date.prototype.getTime", + fns: ["date.getTime", "date.parseGetTime"], + note: "the millisecond value of a stored Date", + }, + { + id: "stdlib.date.valueOf", + kind: "stdlib", + name: "Date.prototype.valueOf", + fns: ["date.valueOf"], + note: "the same millisecond read as getTime()", + }, + { + id: "stdlib.date.toISOString", + kind: "stdlib", + name: "Date.prototype.toISOString", + fns: ["date.toISOString", "date.toISOStringValue"], + note: "UTC ISO formatting over constructed and stored Date values", + }, + { + id: "stdlib.date.toUTCString", + kind: "stdlib", + name: "Date.prototype.toUTCString", + fns: ["date.toUTCString"], + note: "RFC 7231 IMF-fixdate formatting over stored Date values", + }, + { + id: "stdlib.date.getFullYear", + kind: "stdlib", + name: "Date.prototype.getFullYear", + fns: ["date.getFullYear"], + }, + { + id: "stdlib.date.getUTCFullYear", + kind: "stdlib", + name: "Date.prototype.getUTCFullYear", + fns: ["date.getUTCFullYear"], + }, + { + id: "stdlib.date.getMonth", + kind: "stdlib", + name: "Date.prototype.getMonth", + fns: ["date.getMonth"], + }, + { + id: "stdlib.date.getUTCMonth", + kind: "stdlib", + name: "Date.prototype.getUTCMonth", + fns: ["date.getUTCMonth"], + }, + { + id: "stdlib.date.getDate", + kind: "stdlib", + name: "Date.prototype.getDate", + fns: ["date.getDate"], + }, + { + id: "stdlib.date.getUTCDate", + kind: "stdlib", + name: "Date.prototype.getUTCDate", + fns: ["date.getUTCDate"], + }, + { + id: "stdlib.date.getDay", + kind: "stdlib", + name: "Date.prototype.getDay", + fns: ["date.getDay"], + }, + { + id: "stdlib.date.getUTCDay", + kind: "stdlib", + name: "Date.prototype.getUTCDay", + fns: ["date.getUTCDay"], + }, + { + id: "stdlib.date.getHours", + kind: "stdlib", + name: "Date.prototype.getHours", + fns: ["date.getHours"], + }, + { + id: "stdlib.date.getUTCHours", + kind: "stdlib", + name: "Date.prototype.getUTCHours", + fns: ["date.getUTCHours"], + }, + { + id: "stdlib.date.getMinutes", + kind: "stdlib", + name: "Date.prototype.getMinutes", + fns: ["date.getMinutes"], + }, + { + id: "stdlib.date.getUTCMinutes", + kind: "stdlib", + name: "Date.prototype.getUTCMinutes", + fns: ["date.getUTCMinutes"], + }, + { + id: "stdlib.date.getSeconds", + kind: "stdlib", + name: "Date.prototype.getSeconds", + fns: ["date.getSeconds"], + }, + { + id: "stdlib.date.getUTCSeconds", + kind: "stdlib", + name: "Date.prototype.getUTCSeconds", + fns: ["date.getUTCSeconds"], + }, + { + id: "stdlib.date.getMilliseconds", + kind: "stdlib", + name: "Date.prototype.getMilliseconds", + fns: ["date.getMilliseconds"], + }, + { + id: "stdlib.date.getUTCMilliseconds", + kind: "stdlib", + name: "Date.prototype.getUTCMilliseconds", + fns: ["date.getUTCMilliseconds"], + }, + { + id: "stdlib.date.getTimezoneOffset", + kind: "stdlib", + name: "Date.prototype.getTimezoneOffset", + fns: ["date.getTimezoneOffset"], + }, + { + id: "stdlib.date.toString", + kind: "stdlib", + name: "Date.prototype.toString", + fns: ["date.toString"], + note: "local time with the host zone's long English name; String(date) and template literals use it", + }, + { + id: "stdlib.date.toDateString", + kind: "stdlib", + name: "Date.prototype.toDateString", + fns: ["date.toDateString"], + }, + { + id: "stdlib.date.toTimeString", + kind: "stdlib", + name: "Date.prototype.toTimeString", + fns: ["date.toTimeString"], + }, + // ── perf_hooks (lowerPerfHooksCall): the monotonic clock. + { + id: "node-builtin.perf_hooks.performance.now", + kind: "node-builtin", + name: "perf_hooks.performance.now", + fns: ["perf.now"], + note: "the global performance object and the performance.now.bind(performance) function value reach the same clock", + }, + { + id: "node-builtin.perf_hooks.performance.mark", + kind: "node-builtin", + name: "perf_hooks.performance.mark", + fns: [ + "perf.mark", + "perf.entryName", + "perf.entryType", + "perf.entryStart", + "perf.entryDuration", + "perf.entryDetail", + "perf.entryKeep", + "perf.entryRef", + ], + note: "records a mark in the thread's performance timeline at the live clock or the given startTime", + }, + { + id: "node-builtin.perf_hooks.performance.measure", + kind: "node-builtin", + name: "perf_hooks.performance.measure", + fns: ["perf.measure"], + note: "the mark-name, timestamp, and options forms are one surface", + }, + { + id: "node-builtin.perf_hooks.performance.getEntries", + kind: "node-builtin", + name: "perf_hooks.performance.getEntries", + fns: ["perf.entries"], + note: "getEntries, getEntriesByName, and getEntriesByType read the same timeline", + }, + { + id: "node-builtin.perf_hooks.performance.clearMarks", + kind: "node-builtin", + name: "perf_hooks.performance.clearMarks", + fns: ["perf.clearMarks"], + }, + { + id: "node-builtin.perf_hooks.performance.clearMeasures", + kind: "node-builtin", + name: "perf_hooks.performance.clearMeasures", + fns: ["perf.clearMeasures"], + }, + { + id: "node-builtin.perf_hooks.performance.eventLoopUtilization", + kind: "node-builtin", + name: "perf_hooks.performance.eventLoopUtilization", + fns: ["perf.loopStart", "perf.idleTime"], + note: "active time is the main thread's CPU time since the loop started; the one- and two-argument difference forms are supported", + }, + { + id: "node-builtin.perf_hooks.monitorEventLoopDelay", + kind: "node-builtin", + name: "perf_hooks.monitorEventLoopDelay", + fns: [ + "perf.eldNew", + "perf.eldEnable", + "perf.eldDisable", + "perf.eldReset", + "perf.eldPercentile", + "perf.eldStat", + ], + note: "an unref'd sampling interval records the delay histogram; enable, disable, reset, percentile and the min, max, mean, stddev, count and exceeds readings are supported", + }, + // ── the process global's ambient reads and authority calls + // (lowerProcessProperty/lowerProcessMethodCall — process is a + // provenance-checked global here, not an importable module). + { + id: "node-builtin.process.env", + kind: "node-builtin", + name: "process.env", + fns: ["process.envGet", "process.envSet", "process.envUnset", "process.envPairs"], + note: "reads, writes, deletes, and enumeration of the process environment (the process global)", + }, + { + id: "node-builtin.process.argv", + kind: "node-builtin", + name: "process.argv", + fns: ["process.argv"], + }, + { + id: "node-builtin.process.hrtime", + kind: "node-builtin", + name: "process.hrtime", + fns: ["process.hrtimeValue"], + note: "native monotonic tuple clock and bigint member; direct calls and stored JavaScript callable values", + }, + { + id: "node-builtin.process.getBuiltinModule", + kind: "node-builtin", + name: "process.getBuiltinModule", + fns: ["process.builtinId", "process.builtinModule", "process.builtinUnsupported"], + note: "native path and os export subsets plus current-thread worker_threads metadata; other modules and exports throw SC2020", + }, + { + id: "node-builtin.process.versions", + kind: "node-builtin", + name: "process.versions", + fns: ["process.versions"], + note: "shared version dictionary containing node and openssl; other components are absent unless defined by the program", + }, + { + id: "node-builtin.process.release", + kind: "node-builtin", + name: "process.release", + fns: ["process.release"], + note: "the compatibility target's release metadata as one stable read-only object", + }, + { + id: "node-builtin.process.cwd", + kind: "node-builtin", + name: "process.cwd", + fns: ["process.cwd"], + }, + { + id: "node-builtin.process.chdir", + kind: "node-builtin", + name: "process.chdir", + fns: ["process.chdir"], + }, + { + id: "node-builtin.process.pid", + kind: "node-builtin", + name: "process.pid", + fns: ["process.pid"], + }, + { + id: "node-builtin.process.getuid", + kind: "node-builtin", + name: "process.getuid", + fns: ["process.getuid"], + }, + { + id: "node-builtin.process.getgid", + kind: "node-builtin", + name: "process.getgid", + fns: ["process.getgid"], + }, + { + id: "node-builtin.process.geteuid", + kind: "node-builtin", + name: "process.geteuid", + fns: ["process.geteuid"], + }, + { + id: "node-builtin.process.getegid", + kind: "node-builtin", + name: "process.getegid", + fns: ["process.getegid"], + }, + { + id: "node-builtin.process.getgroups", + kind: "node-builtin", + name: "process.getgroups", + fns: ["process.getgroups"], + }, + { + id: "node-builtin.process.ppid", + kind: "node-builtin", + name: "process.ppid", + fns: ["process.ppid"], + }, + { + id: "node-builtin.process.title", + kind: "node-builtin", + name: "process.title", + fns: ["process.title", "process.setTitle"], + note: "reads and writes of the process title are one surface", + }, + { + id: "node-builtin.process.argv0", + kind: "node-builtin", + name: "process.argv0", + fns: ["process.argv0"], + }, + { + id: "node-builtin.process.execArgv", + kind: "node-builtin", + name: "process.execArgv", + fns: ["process.execArgv"], + }, + { + id: "node-builtin.process.execPath", + kind: "node-builtin", + name: "process.execPath", + fns: ["process.execPath"], + }, + { + id: "node-builtin.process.uptime", + kind: "node-builtin", + name: "process.uptime", + fns: ["process.uptime"], + }, + { + id: "node-builtin.process.availableMemory", + kind: "node-builtin", + name: "process.availableMemory", + fns: ["process.availableMemory"], + }, + { + id: "node-builtin.process.constrainedMemory", + kind: "node-builtin", + name: "process.constrainedMemory", + fns: ["process.constrainedMemory"], + }, + { + id: "node-builtin.process.memoryUsage", + kind: "node-builtin", + name: "process.memoryUsage", + fns: ["process.memoryUsageTake", "process.memoryUsageField", "process.rss"], + note: "the record and memoryUsage.rss() read live memory state; external and arrayBuffers are 0", + }, + { + id: "node-builtin.process.resourceUsage", + kind: "node-builtin", + name: "process.resourceUsage", + fns: ["process.rusage"], + note: "getrusage's 16 fields — every field read samples live machine state", + }, + { + id: "node-builtin.process.cpuUsage", + kind: "node-builtin", + name: "process.cpuUsage", + fns: [ + "process.cpuUser", + "process.cpuSystem", + "process.cpuUserDiff", + "process.cpuSystemDiff", + "process.cpuPrevValidate", + ], + note: "the plain-sample and previous-value diff forms are one surface", + }, + { + id: "node-builtin.process.threadCpuUsage", + kind: "node-builtin", + name: "process.threadCpuUsage", + fns: [ + "process.threadCpuUser", + "process.threadCpuSystem", + "process.threadCpuUserDiff", + "process.threadCpuSystemDiff", + ], + note: "the plain-sample and previous-value diff forms are one surface", + }, + { + id: "node-builtin.process.isTTY", + kind: "node-builtin", + name: "process.isTTY", + fns: ["process.isTTY"], + note: "the isTTY read on process.stdin/stdout/stderr — one surface across the three streams", + }, + { + id: "node-builtin.process.columns", + kind: "node-builtin", + name: "process.columns", + fns: ["process.columns"], + note: "the columns read on the process stdio streams (terminal geometry)", + }, + { + id: "node-builtin.process.rows", + kind: "node-builtin", + name: "process.rows", + fns: ["process.rows"], + note: "the rows read on process.stdout/stderr (terminal geometry)", + }, + { + id: "node-builtin.process.kill", + kind: "node-builtin", + name: "process.kill", + fns: ["process.kill", "process.killNum"], + note: "the signal-name and signal-number forms are one surface", + }, + { + id: "node-builtin.process.umask", + kind: "node-builtin", + name: "process.umask", + fns: ["process.umask"], + }, + { + id: "node-builtin.process.exit", + kind: "node-builtin", + name: "process.exit", + fns: ["process.exit", "process.exiting"], + note: "process.exit and the process._exiting flag read are one surface", + }, + { + id: "node-builtin.process.exitCode", + kind: "node-builtin", + name: "process.exitCode", + fns: ["process.setExitCode", "process.setExitCodeTracked", "process.hasExitCode"], + note: "numeric writes in statement position set the implicit exit status; reads answer the assigned code or undefined; process.exit() reads it", + }, + // ── the tls CA store (lowerTlsCaCall / lowerTlsRootCertificates): the + // host's trust anchors, read and replaced. Dedicated paths, and + // rootCertificates is a VALUE read with no call form at all, so none of + // the three can hang off a lowering-table row. Split three ways rather + // than folded into one "CA store" surface: a library author who denies + // REPLACING the trust anchors is making a different decision from one + // who denies reading them, and each Node spelling is the name they will + // reach for when writing the fence. + { + id: "node-builtin.tls.getCACertificates", + kind: "node-builtin", + name: "tls.getCACertificates", + fns: ["tlsca.get"], + note: "the per-type cached PEM bundle: 'default' and 'extra' additionally read NODE_EXTRA_CA_CERTS, 'system' the platform store", + }, + { + id: "node-builtin.tls.rootCertificates", + kind: "node-builtin", + name: "tls.rootCertificates", + fns: ["tlsca.root"], + note: "the value read; answers the same bundled array as getCACertificates('bundled'), but fenced under its own id — the spelling an author writes", + }, + { + id: "node-builtin.tls.setDefaultCACertificates", + kind: "node-builtin", + name: "tls.setDefaultCACertificates", + fns: ["tlsca.set"], + note: "replaces the default set and the client trust anchors for the rest of the process", + }, + // os.constants is a VALUE read (lowerNamespaceBuiltinProperty and the + // named-import path): the platform's null-prototype constants object. + { + id: "node-builtin.os.constants", + kind: "node-builtin", + name: "os.constants", + fns: ["os.constants"], + note: "the platform's dlopen, errno, signals and priority groups; members a platform lacks read as undefined", + }, + // fs.constants as a value, and its members beyond the baked access-mode + // bits: the target libc's null-prototype constants object. + { + id: "node-builtin.fs.constants", + kind: "node-builtin", + name: "fs.constants", + fns: ["fs.constants"], + note: "node_constants.cc's fs group under the target libc's macros; members a platform lacks read as undefined", + }, + ]; +} /** The win32-target overrides of the bare modules' constants: path's * constants ARE the path/win32 namespace's, and os.EOL is CRLF (Node's @@ -2866,7 +2900,7 @@ const WIN32_TARGET_CONSTS: Record< os: { EOL: "\r\n", devNull: "\\\\.\\nul" }, }; -/** BUILTIN_MODULE_FNS with the platform-conditional modules bound per +/** builtinModuleFns() with the platform-conditional modules bound per * TARGET: a win32 triple compiles Node-on-Windows semantics — `path` is * path.win32 and url's bridge selects the Windows runtime behavior. Fence wording is * unaffected — callers keep naming the module the source spelled. */ @@ -2875,9 +2909,9 @@ function builtinModuleFnsOf( module: string, ): Record | undefined { if (lowerer.targetPlatform === "win32") { - if (module === "path") return BUILTIN_MODULE_FNS["path/win32"]; + if (module === "path") return builtinModuleFns()["path/win32"]; } - return ownEntry(BUILTIN_MODULE_FNS, module); + return ownEntry(builtinModuleFns(), module); } /** Own-property lookup — lowerer.ts's own(), duplicated locally because diff --git a/packages/compiler/src/index.ts b/packages/compiler/src/index.ts index 44b5f63ec..3e4871084 100644 --- a/packages/compiler/src/index.ts +++ b/packages/compiler/src/index.ts @@ -46,6 +46,8 @@ export type { AnalyzeResult, } from "./compile-types.js"; import { compilePackedLibrary } from "./backend/library-pack.js"; +import { node24FetchCompatProfile } from "./compat/fetch-profile.js"; +import { libFnSignatures } from "./ir/builtin-signatures.js"; import { InternalCompilerError } from "./errors.js"; import { frontendProcessExecArgv } from "./frontend-process-args.js"; import { type ChildProcess, spawn } from "node:child_process"; @@ -249,7 +251,7 @@ export { type SurfaceManifestEntry, } from "./coverage/surface-manifest.js"; export { - NODE24_FETCH_COMPAT_PROFILE, + node24FetchCompatProfile, type FetchCompatEvidence, type FetchCompatFacet, type FetchCompatInventory, @@ -261,7 +263,13 @@ export { type FetchCompatOption, type FetchCompatProfile, } from "./compat/fetch-profile.js"; -export { LIB_FN_SIGS } from "./ir/builtin-signatures.js"; +export { libFnSignatures } from "./ir/builtin-signatures.js"; +/** @deprecated Use `libFnSignatures()`. Built when this module loads; the + * native compiler does not load this module. */ +export const LIB_FN_SIGS = libFnSignatures(); +/** @deprecated Use `node24FetchCompatProfile()`. Built when this module + * loads; the native compiler does not load this module. */ +export const NODE24_FETCH_COMPAT_PROFILE = node24FetchCompatProfile(); export { validateModule } from "./ir/validate.js"; export { assignLegacyTiers, diff --git a/packages/compiler/src/ir/builtin-signatures.ts b/packages/compiler/src/ir/builtin-signatures.ts index e768f257f..916c64583 100644 --- a/packages/compiler/src/ir/builtin-signatures.ts +++ b/packages/compiler/src/ir/builtin-signatures.ts @@ -58,5058 +58,5103 @@ function defineLibFnSignatures( * together here; frontend coercion and IR validation consume the same table. * All arguments are required. Lowering supplies optional-source defaults * before this boundary and preserves their evaluation order. */ -export const LIB_FN_SIGS = defineLibFnSignatures({ - /** Native static fetch and its Web-platform companions. fetch.start - * answers once the response head arrives; the response body readers - * consume the native body stream. AbortSignal and ReadableStream values - * are opaque checked-dynamic handles. */ - "fetch.start": { argTypes: [STRING, DYN], result: { kind: "promise", inner: DYN } }, - "fetch.responseNew": { argTypes: [DYN, DYN], result: DYN }, - "fetch.responseJsonStatic": { argTypes: [DYN, DYN], result: DYN }, - "fetch.responseLight": { argTypes: [DYN], result: arrayOf(STRING) }, - "fetch.input": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, - "abort.controllerNew": { argTypes: [], result: DYN }, - /** EventTarget / Event / CustomEvent construction (scr_event_target.c): - * the Event constructors take the argument vector as one dyn array and - * throw Node's validation errors; `event.is` is `v instanceof Event` - * (kind 0), `CustomEvent` (1), `EventTarget` (2). addAbortListener - * answers the disposer (the Disposable's [Symbol.dispose]). */ - "event.targetNew": { argTypes: [], result: DYN }, - "event.new": { argTypes: [DYN], result: DYN }, - "event.customNew": { argTypes: [DYN], result: DYN }, - "event.is": { argTypes: [DYN, F64], result: BOOL }, - /** Compiled EventTarget and Event subclasses: the receiver is the - * instance (an object rooted at %EventTarget / %Event). targetInit and - * init are super() (init takes the argument vector as one dyn array - * and throws the constructor's validation errors; initType is the - * super(type) form with a string); targetCall runs an EventTarget method - * with the instance's own capsule as `self` (targetDispatch is its - * dispatchEvent(event) form, answering the bool); call, get and set - * reach the Event members. */ - "event.targetInit": { argTypes: [null], result: VOID }, - "event.init": { argTypes: [null, DYN], result: VOID }, - "event.initType": { argTypes: [null, STRING], result: VOID }, - /** %main hands the engine the compiled `listener.handleEvent` reader - * (lower-event-target.ts noteEventListeners). */ - "event.handleEventReader": { argTypes: [DYN], result: VOID }, - "event.targetDispatch": { argTypes: [null, DYN, DYN], result: BOOL }, - "event.targetCall": { argTypes: [null, DYN, STRING, DYN], result: DYN }, - "event.call": { argTypes: [null, STRING, DYN], result: DYN }, - "event.get": { argTypes: [null, STRING], result: DYN }, - "event.set": { argTypes: [null, STRING, DYN], result: VOID }, - "events.addAbortListener": { argTypes: [DYN, DYN], result: DYN }, - /** Blob / File (scr_blob.c): the constructors and slice() take their - * argument vector as one dyn array and throw Node's validation errors; - * the readers settle on Node's microtask turn for the Blob's parts. - * `blob.is` is `v instanceof Blob` (kind 0) or `File` (1). */ - "blob.new": { argTypes: [DYN], result: DYN }, - "blob.fileNew": { argTypes: [DYN], result: DYN }, - "blob.slice": { argTypes: [DYN, DYN], result: DYN }, - "blob.text": { argTypes: [DYN], result: { kind: "promise", inner: STRING } }, - "blob.bytes": { argTypes: [DYN], result: { kind: "promise", inner: BYTES_U8 } }, - "blob.arrayBuffer": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, - "blob.is": { argTypes: [DYN, F64], result: BOOL }, - /** WebAssembly (scr_wasm.c): modules translated at build time - * (wasm/translate.ts), found at run time by the SHA-256 of their bytes. - * compile and instantiate over bytes settle on a later loop turn; - * instantiate over a Module settles now, as in Node. `wasm.is` answers - * instanceof for Module, Instance, Memory, Table and Global (kinds 0-4) - * and CompileError, LinkError and RuntimeError (5-7); `wasm.errorNew` - * constructs one of the error classes (kind 5-7, message, options). */ - "wasm.compile": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, - "wasm.validate": { argTypes: [DYN], result: BOOL }, - "wasm.instantiate": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, - "wasm.moduleNew": { argTypes: [DYN], result: DYN }, - "wasm.instanceNew": { argTypes: [DYN, DYN], result: DYN }, - "wasm.is": { argTypes: [DYN, F64], result: BOOL }, - "wasm.errorNew": { argTypes: [F64, DYN, DYN], result: DYN }, - /** new WebAssembly.Memory(descriptor), Table(descriptor, value) and - * Global(descriptor, value) (an undefined value is the type's default); - * `wasm.withoutNew` throws the TypeError for Module, Instance, Memory, - * Table or Global (kinds 0-4) called without new, after its arguments - * evaluate. */ - "wasm.memoryNew": { argTypes: [DYN], result: DYN }, - "wasm.tableNew": { argTypes: [DYN, DYN], result: DYN }, - "wasm.globalNew": { argTypes: [DYN, DYN], result: DYN }, - "wasm.withoutNew": { argTypes: [F64, DYN, DYN], result: DYN }, - /** WebAssembly.Module.imports(module), exports(module) and - * customSections(module, name): checked-dynamic arrays of descriptor - * objects and ArrayBuffers. */ - "wasm.moduleImports": { argTypes: [DYN], result: DYN }, - "wasm.moduleExports": { argTypes: [DYN], result: DYN }, - "wasm.moduleCustomSections": { argTypes: [DYN, DYN], result: DYN }, - /** `v.valueOf()` on a WebAssembly-typed receiver: a Global's value, - * dyn.valueOf's answer for anything else. */ - "wasm.valueOf": { argTypes: [DYN], result: DYN }, - /** WebAssembly.compile (0), instantiate (1) and validate (2) as function - * values, and the namespace object holding them. */ - "wasm.function": { argTypes: [F64], result: DYN }, - "wasm.namespace": { argTypes: [], result: DYN }, - /** The global object viewed through a cast to a type with a WebAssembly - * member: an object holding the namespace. */ - "wasm.globalView": { argTypes: [], result: DYN }, - "abort.timeout": { argTypes: [DYN], result: DYN }, - "abort.now": { argTypes: [DYN], result: DYN }, - "abort.any": { argTypes: [DYN], result: DYN }, - "fetch.function": { argTypes: [], result: DYN }, - "fetch.requestNew": { argTypes: [DYN, DYN], result: DYN }, - "fetch.headersNew": { argTypes: [DYN], result: DYN }, - "fetch.responseArrayBuffer": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, - "fetch.responseJson": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, - "fetch.responseText": { argTypes: [DYN], result: { kind: "promise", inner: STRING } }, - "fetch.responseBytes": { argTypes: [DYN], result: { kind: "promise", inner: BYTES_U8 } }, - "fetch.abortControllerNew": { argTypes: [], result: DYN }, - "fetch.abortTimeout": { argTypes: [DYN], result: DYN }, - "fetch.abortNow": { argTypes: [DYN], result: DYN }, - "fetch.abortAny": { argTypes: [DYN], result: DYN }, - "fetch.streamNew": { argTypes: [DYN], result: DYN }, - "fetch.transformNew": { argTypes: [], result: DYN }, - // Program-dependent iterable: typed arrays/bytes/string stay intact so - // the native stream can pull lazily; checked-dynamic values are the - // fallback. The libCall validator in validate.ts checks the closed set. - "fetch.webIs": { argTypes: [DYN, STRING], result: BOOL }, - "fetch.streamIs": { argTypes: [DYN], result: BOOL }, - "fetch.streamFrom": { argTypes: [null], result: DYN }, - // The chunk/result record depends on ReadableStream; validated by validate.ts. - "fetch.readerRead": { argTypes: [DYN], result: VOID }, - /** Readable.fromWeb (scr_stream_from_web.c): the stream, objectMode, - * highWaterMark (< 0: the mode's default) and encoding ("": none). */ - "fetch.readableFromWeb": { argTypes: [DYN, BOOL, F64, STRING], result: VOID }, - "json.parse": { argTypes: [STRING], result: DYN }, - "json.parseReviver": { argTypes: [STRING, DYN], result: DYN }, - "json.stringifyReplacer": { argTypes: [DYN, DYN, STRING], result: DYN }, - "json.stringifyValue": { argTypes: [DYN, DYN, DYN], result: DYN }, - /** Keyed WRITE on a dyn value — `h.onDone = cb` / `h["k"] = v` on a - * checked-dynamic object (args: receiver, key string, value — all - * borrowed; the runtime copies the key and retains the value in). An - * OBJ receiver sets the member (later writes win, insertion order - * preserved — JS exactly); undefined/null throws Node's catchable - * "Cannot set properties of undefined (setting 'k')"; every other kind - * throws Node's STRICT-mode "Cannot create property 'k' on " — - * primitives quoting their rendering, V8's "on number '5'" - * (sloppy mode would ignore the write — suite tests are 'use strict'; - * SEMANTICS.md notes the sloppy divergence: the write throws). Void - * result; in the may-throw seed set. */ - "dyn.keySet": { argTypes: [DYN, STRING, DYN], result: VOID }, - "dyn.keySetComputed": { argTypes: [DYN, DYN, DYN], result: VOID }, - /** Delete an ordinary checked-native object's own key. Borrows both - * arguments; other receiver representations retain a runtime refusal. */ - "dyn.keyDelete": { argTypes: [DYN, STRING, BOOL], result: VOID }, - "dyn.keyDeleteComputed": { argTypes: [DYN, DYN, BOOL], result: VOID }, - "dyn.reflectDeleteProperty": { argTypes: [DYN, DYN], result: BOOL }, - "dyn.hasKeyComputed": { argTypes: [DYN, DYN], result: BOOL }, - "dyn.hasOwnComputed": { argTypes: [DYN, DYN], result: BOOL }, - "dyn.propertyIsEnumerableComputed": { argTypes: [DYN, DYN], result: BOOL }, - /** Native own properties on globalThis keyed by symbol identity. */ - "dyn.globalSymbolGet": { argTypes: [SYMBOL_T], result: DYN }, - "dyn.globalSymbolSet": { argTypes: [SYMBOL_T, DYN], result: VOID }, - "dyn.globalSymbolHas": { argTypes: [SYMBOL_T], result: BOOL }, - "dyn.globalSymbolDelete": { argTypes: [SYMBOL_T], result: VOID }, - /** Exact native class capsule identity, without materializing its fields. */ - "dyn.typedRefIs": { argTypes: [DYN, STRING], result: BOOL }, - /** A capsule boxed by this program from exactly this class: one key - * pointer test, false for equal keys boxed elsewhere. Guards fast paths - * whose fallback handles every other value. The key is a literal. */ - "dyn.typedRefKeyIs": { argTypes: [DYN, STRING], result: BOOL }, - "dyn.classIs": { argTypes: [DYN, STRING], result: BOOL }, - /** Destructuring pack over a dyn source — `const [a, b] = d`, a - * destructured dyn callback param (args: the source and the STATIC - * TypeError spelling, "" when the source has none — both borrowed; - * result: a fresh dyn array, +1). Iterable kinds collect like spread - * (arrays element-by-element, strings by code point, bytes by byte); - * every other kind throws V8's destructuring TypeError — the spelling - * verbatim when non-empty, else the runtime kind wording ("number 5 is - * not iterable (cannot read property Symbol(Symbol.iterator))"). In the - * may-throw seed set. */ - "dyn.iterPack": { argTypes: [DYN, STRING], result: DYN }, - "dyn.mathFold": { argTypes: [DYN, BOOL, STRING], result: F64 }, - "dyn.destructureRest": { argTypes: [DYN, STRING], result: DYN }, - "dyn.arrayFromIterator": { argTypes: [DYN], result: DYN }, - "dyn.iterator": { argTypes: [DYN, STRING], result: DYN }, - /** for await over a checked-dynamic value: the loop's iterator (a - * compiled async generator, Symbol.asyncIterator's result, or the sync - * iterator), and whether that iterator is synchronous. */ - "dyn.asyncIteratorOpen": { argTypes: [DYN, STRING], result: DYN }, - "dyn.asyncIteratorWasSync": { argTypes: [], result: BOOL }, - "dyn.iteratorResult": { argTypes: [DYN], result: DYN }, - "dyn.iteratorCanStep": { argTypes: [DYN, DYN], result: BOOL }, - "dyn.iteratorStep": { argTypes: [DYN], result: DYN }, - "dyn.iteratorStepDone": { argTypes: [DYN], result: BOOL }, - "dyn.setGeneratorMembers": { argTypes: [DYN, DYN], result: VOID }, - "dyn.iteratorHelperMethod": { argTypes: [STRING], result: DYN }, - "dyn.collectionIteratorIndex": { argTypes: [DYN], result: F64 }, - "dyn.mapSeedEntries": { argTypes: [DYN], result: DYN }, - "dyn.mapSeedEntry": { argTypes: [DYN], result: DYN }, - /** The for-of-over-dyn pack accessors — the emitted index loop drives - * them over a dyn.iterPack result (ARR by construction). arrLen: the - * ARR length as f64 (0 for non-ARR kinds; arg borrowed). arrAt: the - * element at index (+1; the undefined singleton past the end). Neither - * throws. */ - "dyn.arrLen": { argTypes: [DYN], result: F64 }, - "dyn.arrAt": { argTypes: [DYN, F64], result: DYN }, - /** `key in v` with a RUNTIME (string) key on a checked-dynamic - * receiver (args: value dyn, key string; result bool): OBJ answers - * own-member presence, ARR answers 'length'/a valid index — exactly - * the literal-key dynHasKey path. Proxy has traps may throw. */ - "dyn.hasKey": { argTypes: [DYN, STRING], result: BOOL }, - /** The `in` operator with a runtime string key: dyn.hasKey plus the - * members inherited from builtin and compiled class prototypes. */ - "dyn.in": { argTypes: [DYN, STRING], result: BOOL }, - "dyn.freeze": { argTypes: [DYN], result: DYN }, - "dyn.isFrozen": { argTypes: [DYN], result: BOOL }, - /** Object.defineProperty on a declared class field (scr_json.c): the - * field's current value (borrowed), its FIELD_* attribute word, the - * instance's CLASS_* integrity word, the field name and the descriptor. - * Validates as Node does (TypeError "Cannot redefine property: f") and - * answers a one-property holder of the defined value and attributes (+1), - * read back with class.definedBits and class.definedValue. */ - "class.defineField": { argTypes: [DYN, F64, F64, STRING, DYN], result: DYN }, - "class.definedBits": { argTypes: [DYN, STRING], result: F64 }, - "class.definedValue": { argTypes: [DYN, STRING], result: DYN }, - /** Whether a property descriptor has a `value` member. */ - "class.descriptorHasValue": { argTypes: [DYN], result: BOOL }, - /** Throws Node's TypeError for a write to a read-only class field: the - * field name and the instance's class name. */ - "class.throwReadOnly": { argTypes: [STRING, STRING], result: VOID }, - /** Throws Node's TypeError for a class field initializer on a - * non-extensible instance: the field name. */ - "class.throwNotExtensible": { argTypes: [STRING], result: VOID }, - /** Object.freeze of a record whose shape is freezable (frozen-records.ts): - * sets the frozen bit in its rc word (scr_record_freeze). The receiver is - * any record type. */ - "record.freeze": { argTypes: [null], result: VOID }, - /** Whether a record is frozen: its rc word's frozen bit, set by - * record.freeze and dyn.freeze of a capsule. Emitted inline. The receiver - * is any record type. */ - "record.isFrozen": { argTypes: [null], result: BOOL }, - /** Throws Node's TypeError for a write to a frozen record: the key, the - * object's text in the message ("#") and the operation (0 assign, - * 1 add, 2 delete). */ - "record.throwFrozen": { argTypes: [STRING, STRING, F64], result: VOID }, - /** Object.freeze of an array (scr_arr_freeze): sets its frozen bit, which - * the write guards of IrModule.freezableArrays test, and isFrozen reads. - * The receiver is any array type. */ - "array.freeze": { argTypes: [null], result: VOID }, - "array.isFrozen": { argTypes: [null], result: BOOL }, - /** Object.freeze, seal or preventExtensions of a Map or Set - * (scr_map_prevent_extensions), which only makes it not extensible: its - * entries stay writable. The receiver is any map or set type. */ - "collection.preventExtensions": { argTypes: [null], result: VOID }, - "collection.isExtensible": { argTypes: [null], result: BOOL }, - "dyn.nativeSetNew": { argTypes: [DYN], result: DYN }, - "dyn.nativeSetIs": { argTypes: [DYN], result: BOOL }, - "dyn.nativeMapIs": { argTypes: [DYN], result: BOOL }, - "dyn.nativeUrlIs": { argTypes: [DYN], result: BOOL }, - "dyn.nativeDateIs": { argTypes: [DYN], result: BOOL }, - "dyn.nativeDateHandleIs": { argTypes: [DYN], result: BOOL }, - /** A builtin constructor (`Object`, `Date`, `RegExp`, `Map`, `Set`, - * `Promise`, `WeakMap`, `WeakSet`) read as a JavaScript value: one - * interned function per name, the same one dynamic values answer for - * `.constructor`. The name is a compiler-chosen literal. */ - "dyn.globalConstructor": { argTypes: [STRING], result: DYN }, - /** A builtin global function (setTimeout, setInterval, setImmediate, - * the clear functions, queueMicrotask, process.nextTick) read as a - * JavaScript value: one interned function per name whose calls run the - * timer APIs (it pulls in the event loop). The name is a compiler-chosen - * literal. */ - "dyn.builtinFunction": { argTypes: [STRING], result: DYN }, - "dyn.namespaceNew": { argTypes: [STRING, DYN], result: DYN }, - "dyn.namespaceDefine": { argTypes: [DYN, STRING, DYN, F64, F64], result: VOID }, - "date.nativeNew": { argTypes: [DYN], result: DYN }, - /** `new Date(year, monthIndex, ...)` in JavaScript: the argument array's - * first seven values pass through ToNumber in order (later ones are - * evaluated, never converted), then the local-time field constructor. */ - "date.nativeNewFields": { argTypes: [DYN], result: DYN }, - /** `new Date(value)` in JavaScript: a string argument parses with V8's - * full date parser; every other value constructs as date.nativeNew. */ - "date.nativeNewValue": { argTypes: [DYN], result: DYN }, - "date.argumentsTime": { argTypes: [DYN], result: DATE_T }, - "date.classOperation": { argTypes: [DYN, DYN], result: VOID }, - "date.checkedValue": { argTypes: [DYN], result: DATE_T }, - "dyn.nativeRegexIs": { argTypes: [DYN], result: BOOL }, - /** toString() on a checked-dynamic receiver: runtime kind dispatch - * (bytes decode per the literal encoding — utf8 default; strings, - * numbers, booleans, arrays, objects answer JS-exactly; undefined and - * null throw the catchable TypeError). */ - "dyn.toString": { argTypes: [DYN, DYN, STRING], result: STRING }, - "dyn.valueOf": { argTypes: [DYN, STRING], result: DYN }, - /** Object.defineProperties over dyn values (args: target, descriptors — - * both borrowed dyn; result: the target, +1 — JS's return value). - * Value descriptors become own properties on OBJ and FUNC targets; - * OBJ targets preserve data attributes. get/set - * descriptors and non-object targets/descriptors throw catchably - * (Node's TypeError texts; accessors the "not supported yet" Error). In - * the may-throw seed set. */ - "dyn.defineProps": { argTypes: [DYN, DYN], result: DYN }, - "dyn.defineProperty": { argTypes: [DYN, DYN, DYN], result: DYN }, - "dyn.getOwnPropertyDescriptor": { argTypes: [DYN, DYN], result: DYN }, - "dyn.arrayProtoCall": { argTypes: [DYN, STRING, DYN], result: DYN }, - /** Promise.all / Promise.allSettled / Promise.any over a spread - * checked-dynamic array: the values, the settled-record array, or the - * first fulfillment (AggregateError once every entry rejects). - * Thenable elements adopt; the second argument reads a program class - * instance's `then` (the compiled property dispatch). */ - "dyn.promiseAll": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, - "dyn.promiseAllSettled": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, - "dyn.promiseAny": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, - /** PromiseResolve over one checked-dynamic value: the promise it holds, - * a promise that adopts a thenable's settlement, or a promise fulfilled - * with the value. The second argument reads `then` as above. */ - "dyn.promiseResolve": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, - /** Bare `typeof v` on a dyn value AS A STRING (arg: the dyn value, - * borrowed; result: an owned string) — the dyn kind's JS answer: - * undefined→"undefined", null/object/array/bytes→"object" (JS's oldest - * wart preserved), boolean/number/string by kind, function→"function". - * Never throws. */ - "dyn.typeof": { argTypes: [DYN], result: STRING }, - /** Object.prototype.toString.call on a checked-dynamic value. */ - "dyn.objectTag": { argTypes: [DYN], result: STRING }, - /** Engine-free CommonJS module graph. Module values are scalar f64 - * handles; generated startup defines the registry, init wrappers update - * loading/cache state, and the read surface answers Node's live metadata. */ - "module.registryInit": { argTypes: [F64], result: VOID }, - "module.define": { argTypes: [F64, STRING, STRING, STRING, arrayOf(STRING), BOOL], result: VOID }, - "module.enter": { argTypes: [F64], result: VOID }, - "module.link": { argTypes: [F64, F64], result: VOID }, - "module.finish": { argTypes: [F64], result: VOID }, - "module.fail": { argTypes: [F64], result: VOID }, - "module.filename": { argTypes: [F64], result: STRING }, - "module.id": { argTypes: [F64], result: STRING }, - "module.path": { argTypes: [F64], result: STRING }, - "module.paths": { argTypes: [F64], result: arrayOf(STRING) }, - "module.children": { argTypes: [F64], result: arrayOf(F64) }, - "module.parent": { argTypes: [F64], result: F64 }, - "module.loaded": { argTypes: [F64], result: BOOL }, - "module.cacheGet": { argTypes: [STRING], result: F64 }, - "module.cacheHas": { argTypes: [STRING], result: BOOL }, - "module.cacheKeys": { argTypes: [], result: arrayOf(STRING) }, - "timers.setTimeout": { argTypes: [{ kind: "func", params: [], ret: VOID }, F64], result: VOID }, - /** The repeating timer pair. setInterval takes (callback, ms) like - * setTimeout and RETURNS the f64 handle the fallback declarations - * promise (ids start at 1, so truthiness narrowing works); the loop - * owns the callback until clearInterval removes the entry (eagerly — a - * live interval keeps the loop alive, a cleared one releases it, like - * Node). Neither throws; a throw ESCAPING an interval callback ends the - * program like a setTimeout throw. */ - "timers.setInterval": { argTypes: [{ kind: "func", params: [], ret: VOID }, F64], result: F64 }, - "timers.clearInterval": { argTypes: [F64], result: VOID }, - /** setTimeout WITH a clear handle (the f64 id) — the clearable/unref-able - * one-shot; clearTimeout cancels it, .unref() drops it from loop - * liveness. The plain timers.setTimeout stays the handle-less - * fire-and-forget. */ - "timers.setTimeoutHandle": { - argTypes: [{ kind: "func", params: [], ret: VOID }, F64], - result: F64, - }, - "timers.clearTimeout": { argTypes: [F64], result: VOID }, - /** Timeout.unref()/ref()/hasRef() — loop-liveness bookkeeping over the - * handle id. unref/ref RETURN the handle (f64) for chaining; hasRef - * returns bool. */ - "timers.unref": { argTypes: [F64], result: F64 }, - "timers.ref": { argTypes: [F64], result: F64 }, - "timers.hasRef": { argTypes: [F64], result: BOOL }, - /** Timeout.refresh() — re-arm to now + the original delay (from the - * heap or from inside the firing callback; a one-shot that fired on an - * earlier turn is gone and no-ops — documented divergence). Returns - * the handle for chaining like unref/ref. */ - "timers.refresh": { argTypes: [F64], result: F64 }, - /** setImmediate/clearImmediate — Node's check phase: callbacks run - * once per loop turn AFTER due timers, FIFO, and immediates queued - * mid-phase wait for the next turn. setImmediate returns the f64 - * handle (its own id space — clearTimeout of an Immediate no-ops, - * like Node); the Immediate ref trio mirrors the Timeout one (an - * unref'd pending immediate neither keeps the loop alive nor fires - * once nothing reffed remains). */ - "timers.setImmediate": { argTypes: [{ kind: "func", params: [], ret: VOID }], result: F64 }, - /** queueMicrotask (scr_async.c): the callback enters the SAME FIFO - * promise continuations ride — one microtask order, like V8's queue — - * and a throw is an UNCAUGHT exception (never a rejection). - * timers.queueMicrotask takes an owned zero-param closure and never - * throws; the Dyn form (checked-dynamic arguments — the mustCall - * wrapper, the suite's invalid-input probes) throws Node's - * ERR_INVALID_ARG_TYPE synchronously on a non-function value and calls - * the function with zero arguments at drain. */ - "timers.queueMicrotask": { argTypes: [{ kind: "func", params: [], ret: VOID }], result: VOID }, - "timers.queueMicrotaskDyn": { argTypes: [DYN], result: VOID }, - "timers.clearImmediate": { argTypes: [F64], result: VOID }, - /** process.nextTick(cb, ...args) — the user tick queue. args: [cb - * (() => void; trailing call arguments ride the timer surface's - * interned dyn thunk)]. Ticks drain BEFORE promise jobs at every loop - * checkpoint, to joint exhaustion with them (Node's tick-then- - * microtask order); ticks enqueued by station listeners run at the - * NEXT checkpoint (the stream-tick station divergence, SEMANTICS.md). - * Pending ticks are always-ready work — the loop neither sleeps nor - * exits while any exist; ticks scheduled from 'exit' listeners never - * run (Node). The enqueue itself never throws. */ - "process.nextTick": { argTypes: [{ kind: "func", params: [], ret: VOID }], result: VOID }, - /** The process introspection statics. uptime: seconds since the - * binary's own start (fractional — a load-time monotonic anchor). - * availableMemory/constrainedMemory: libuv's numbers (free-ish bytes; - * the cgroup cap or 0). cpuUser/cpuSystem (+ threadCpu twins): the - * process/thread CPU clocks in microseconds — the frontend composes - * the {user, system} records. The *Diff forms answer current − prev - * for one field; cpuPrevValidate throws Node's ERR_INVALID_ARG_VALUE - * RangeError for negative/non-finite prev fields (user first, then - * system — Node's order; MAY THROW). rusage(idx): one - * process.resourceUsage() field by canonical index (Node's units). - * activeResources: the loop's own bookkeeping — 'Timeout' per armed - * (or firing, uncleared) timer, 'Immediate' per queued unfired - * immediate; unmodeled resource kinds are absent (SEMANTICS.md). */ - "process.uptime": { argTypes: [], result: F64 }, - /** perf_hooks performance.now(): fractional ms since process start. */ - "perf.now": { argTypes: [], result: F64 }, - /** perf_hooks user timing over the thread's performance timeline. The - * producing calls take the call's whole argument vector as one dyn - * array (Node's validation and errors run in the runtime, MAY THROW): - * mark/measure answer 1, entries(args, which) the entry count of - * getEntries (0), getEntriesByName (1) or getEntriesByType (2). The - * entryName/Type/Start/Duration/Detail accessors read entry i of that - * answer; the frontend builds a new entry's record from them and hands - * it to entryKeep (a typed reference capsule), and the getters read the - * kept records back through entryRef, so entries keep their identity. */ - "perf.mark": { argTypes: [DYN], result: F64 }, - "perf.measure": { argTypes: [DYN], result: F64 }, - "perf.entries": { argTypes: [DYN, F64], result: F64 }, - "perf.clearMarks": { argTypes: [DYN], result: VOID }, - "perf.clearMeasures": { argTypes: [DYN], result: VOID }, - "perf.entryName": { argTypes: [F64], result: STRING }, - "perf.entryType": { argTypes: [F64], result: STRING }, - "perf.entryStart": { argTypes: [F64], result: F64 }, - "perf.entryDuration": { argTypes: [F64], result: F64 }, - "perf.entryDetail": { argTypes: [F64], result: DYN }, - "perf.entryKeep": { argTypes: [DYN], result: VOID }, - "perf.entryRef": { argTypes: [F64], result: DYN }, - /** perf_hooks event-loop metrics (scr_perf_loop.c): loopStart is the - * loop's start in performance.now() ms (0 before it), idleTime the idle - * ms since. eldNew(resolution ms) creates a monitorEventLoopDelay - * histogram handle (MAY THROW Node's resolution RangeError); enable/disable answer whether the state changed; - * eldPercentile expects Node's validated range; eldStat(which) reads - * 0 min, 1 max, 2 mean, 3 stddev, 4 count, 5 exceeds. */ - "perf.loopStart": { argTypes: [], result: F64 }, - "perf.idleTime": { argTypes: [], result: F64 }, - "perf.eldNew": { argTypes: [F64], result: F64 }, - "perf.eldEnable": { argTypes: [F64], result: BOOL }, - "perf.eldDisable": { argTypes: [F64], result: BOOL }, - "perf.eldReset": { argTypes: [F64], result: VOID }, - "perf.eldPercentile": { argTypes: [F64, F64], result: F64 }, - "perf.eldStat": { argTypes: [F64, F64], result: F64 }, - /** process.memoryUsage(): memoryUsageTake samples the resident set and - * the runtime heap once (MAY THROW Node's uv_resident_set_memory error) - * and memoryUsageField(k) reads that sample (0 rss, 1 heapTotal, 2 - * heapUsed, 3 external, 4 arrayBuffers). rss is memoryUsage.rss(). */ - "process.memoryUsageTake": { argTypes: [], result: VOID }, - "process.memoryUsageField": { argTypes: [F64], result: F64 }, - "process.rss": { argTypes: [], result: F64 }, - "process.availableMemory": { argTypes: [], result: F64 }, - "process.constrainedMemory": { argTypes: [], result: F64 }, - "process.cpuUser": { argTypes: [], result: F64 }, - "process.cpuSystem": { argTypes: [], result: F64 }, - "process.cpuUserDiff": { argTypes: [F64], result: F64 }, - "process.cpuSystemDiff": { argTypes: [F64], result: F64 }, - "process.threadCpuUser": { argTypes: [], result: F64 }, - "process.threadCpuSystem": { argTypes: [], result: F64 }, - "process.threadCpuUserDiff": { argTypes: [F64], result: F64 }, - "process.threadCpuSystemDiff": { argTypes: [F64], result: F64 }, - "process.cpuPrevValidate": { argTypes: [F64, F64], result: VOID }, - "process.rusage": { argTypes: [F64], result: F64 }, - "process.activeResources": { argTypes: [], result: arrayOf(STRING) }, - "timers.immediateUnref": { argTypes: [F64], result: F64 }, - "timers.immediateRef": { argTypes: [F64], result: F64 }, - "timers.immediateHasRef": { argTypes: [F64], result: BOOL }, - /** The tolerated non-handle clear (`clearTimeout(null)`, - * `clearInterval({})`, zero-argument forms): Node ignores anything - * that is not a live handle without an error — a VOID no-op the emitter drops - * (only syntactically side-effect-free arguments take this path). */ - "timers.clearNoop": { argTypes: [], result: VOID }, - // Signal listeners are zero-param (the ambient shape); exit/stdin - // callbacks carry program-dependent one-param shapes — null slots, the - // libCall case checks them (child.onExit precedent). - /** Named process signal events: [name string, callback dyn, once bool] - * or [name, callback] for removal. The runtime resolves platform signal - * numbers and delivers (name, number). Listeners do not keep the loop - * alive. Invalid callbacks and uncatchable signals throw. */ - "process.onSignal": { argTypes: [STRING, DYN, BOOL], result: VOID }, - "process.offSignal": { argTypes: [STRING, DYN], result: VOID }, - /** The process 'exit' event — process.on/once/off("exit"). args: [cb, - * once bool] / [cb]. Listeners run SYNCHRONOUSLY at termination - * (normal exit, process.exit(), the uncaught/unhandled exit-1 paths) - * with the exit code; anything they schedule never runs, like Node. - * Callback shapes: () => void or (code: number) => void — the emitter - * picks the runtime adapter. Never throw. */ - "process.onExit": { argTypes: [null, BOOL], result: VOID }, - "process.offExit": { argTypes: [null], result: VOID }, - /** process.stdin listener registration — stdin.on/once("data" | "end" | - * "error", cb). args: [cb, once bool]. data callbacks: () => void or - * (chunk: Uint8Array) => void; end: () => void; error: () => void or - * (err: Error) => void (the child error adapters are reused). While a - * data listener (or a parked for-await chunk promise) exists, stdin - * keeps the loop alive — Node's flowing-stdin keep-alive. Never - * throw. */ - "stdin.onData": { argTypes: [null, BOOL], result: VOID }, - "stdin.onEnd": { argTypes: [{ kind: "func", params: [], ret: VOID }, BOOL], result: VOID }, - "stdin.onError": { argTypes: [null, BOOL], result: VOID }, - /** process.stdin.on/once('keypress', cb) (scr_readline_tty.c): cb is the - * listener as a checked-dynamic function, called with (str, key). */ - "stdin.onKeypress": { argTypes: [DYN, BOOL], result: VOID }, - /** The for-await chunk source over process.stdin: no args, result - * Promise (+1). Fulfills with the next arrived chunk; the - * EMPTY bytes value is the done sentinel (POSIX reads never deliver - * empty data chunks), which the for-await desugar turns into loop - * exit. Never throws itself; awaiting it re-throws nothing (stdin - * errors surface through 'error' listeners, not the iterator). */ - "stdin.nextChunk": { argTypes: [], result: { kind: "promise", inner: BYTES_U8 } }, - "fs.readFileSync": { argTypes: [STRING, STRING], result: STRING }, - "fs.readFileEncoded": { argTypes: [STRING, STRING], result: STRING }, - "fs.readFdEncoded": { argTypes: [F64, STRING], result: STRING }, - /** readFileSync(path) — the Buffer read (+1 bytes); throws catchably - * like the utf8 form. */ - "fs.readFileSyncBuf": { argTypes: [STRING], result: BYTES_U8 }, - /** readFileSync(path, enc) with a RUNTIME encoding (an untyped JS - * parameter): undefined/null answer Buffers, utf8 a string, other real - * encodings throw the "not supported yet" Error, unknown names throw - * ERR_UNKNOWN_ENCODING. */ - "fs.readFileSyncDyn": { argTypes: [STRING, DYN], result: DYN }, - "fs.writeFileSync": { argTypes: [STRING, STRING], result: VOID }, - "fs.appendFileSync": { argTypes: [STRING, STRING], result: VOID }, - "fs.existsSync": { argTypes: [STRING], result: BOOL }, - "fs.mkdirSync": { argTypes: [STRING], result: VOID }, - "fs.rmSync": { argTypes: [STRING], result: VOID }, - "fs.rmdirSync": { argTypes: [STRING], result: VOID }, - "fs.readdirSync": { argTypes: [STRING], result: arrayOf(STRING) }, - // Result is the call site's Dirent record array (VOID is the - // structure-checked sentinel, the os.networkInterfaces pattern). - /** `fs.readdirSync(path, { withFileTypes: true })` — Dirent rows over - * one readdir pass (scr_lib.c's scandir snapshot; DT_UNKNOWN falls back - * to lstat, Node's getDirents rule). The result type is the call site's - * interned Dirent record array (name, parentPath, hidden %dtype in - * libuv's UV_DIRENT encoding) — verified by the frontend; the emitter - * assembles the rows from the snapshot. Byte order on POSIX (libuv - * sorts), the directory's order on Windows; no "."/"..". Throws - * Node's scandir errno error (may-throw seed set); fresh +1 array. */ - "fs.readdirTypesSync": { argTypes: [STRING], result: VOID }, - /** fs.globSync / fs.glob / fs/promises glob (scr_glob.c, Node's - * lib/internal/fs/glob.js walk): pattern and options are dyn values the - * runtime validates in Node's order. The string forms answer string[]; - * the Dirent forms answer the call site's Dirent record array (validated - * in validate.ts) assembled from the snapshot; fs.callbackGlob takes the - * argument vector and calls back with string[]. */ - "fs.globSync": { argTypes: [DYN, DYN], result: arrayOf(STRING) }, - "fs.globTypesSync": { argTypes: [DYN, DYN], result: VOID }, - "fs.callbackGlob": { argTypes: [DYN], result: VOID }, - "fsp.globStrings": { argTypes: [DYN, DYN], result: arrayOf(STRING) }, - "fsp.globTypes": { argTypes: [DYN, DYN], result: VOID }, - /** The error an fs/promises glob walk ended with (undefined when none), - * read once right after fsp.globStrings / fsp.globTypes. */ - "fsp.globError": { argTypes: [], result: DYN }, - /** fs.Dir (scr_lib.c): opendirSync(path, bufferSize) throws Node's - * opendir error (or the options.bufferSize RangeError); dir.readSync - * answers the call site's `Dirent | null` (VOID here — the emitter builds - * the row like readdirTypesSync) and dir.read is its promise twin; - * readSync and closeSync throw ERR_DIR_CLOSED on a closed Dir, read and - * close reject with it. */ - "fs.opendirSync": { argTypes: [STRING, F64], result: DIR_T }, - "fsp.opendir": { argTypes: [STRING, F64], result: { kind: "promise", inner: DIR_T } }, - "dir.path": { argTypes: [DIR_T], result: STRING }, - "dir.readSync": { argTypes: [DIR_T], result: VOID }, - "dir.read": { argTypes: [DIR_T], result: { kind: "promise", inner: VOID } }, - "dir.closeSync": { argTypes: [DIR_T], result: VOID }, - "dir.close": { argTypes: [DIR_T], result: { kind: "promise", inner: VOID } }, - /** node:path (scr_path.c ports BOTH of Node's implementations - * function-by-function): the `path.*` family is posix, the - * `path.win32*` family is Node v24's path.win32 ported exactly — the - * frontend binds the bare module to the TARGET platform's family - * (Node on Windows IS path.win32) and the path.posix / path.win32 - * namespaces to their own family everywhere. join and resolve take ONE - * string[] arg — the frontend packs the variadic call's arguments into - * an array literal. basename always receives its suffix (the frontend - * completes an omitted one with "", a Node no-op). toNamespacedPath is - * the posix identity and the win32 \\?\-prefixer. None of these throw; - * the resolves consult the process cwd like Node's. */ - "path.join": { argTypes: [arrayOf(STRING)], result: STRING }, - "path.resolve": { argTypes: [arrayOf(STRING)], result: STRING }, - "path.normalize": { argTypes: [STRING], result: STRING }, - "path.dirname": { argTypes: [STRING], result: STRING }, - "path.basename": { argTypes: [STRING, STRING], result: STRING }, - "path.extname": { argTypes: [STRING], result: STRING }, - "path.isAbsolute": { argTypes: [STRING], result: BOOL }, - "path.relative": { argTypes: [STRING, STRING], result: STRING }, - "path.toNamespacedPath": { argTypes: [STRING], result: STRING }, - "path.win32Join": { argTypes: [arrayOf(STRING)], result: STRING }, - "path.win32Resolve": { argTypes: [arrayOf(STRING)], result: STRING }, - "path.win32Normalize": { argTypes: [STRING], result: STRING }, - "path.win32Dirname": { argTypes: [STRING], result: STRING }, - "path.win32Basename": { argTypes: [STRING, STRING], result: STRING }, - "path.win32Extname": { argTypes: [STRING], result: STRING }, - "path.win32IsAbsolute": { argTypes: [STRING], result: BOOL }, - "path.win32Relative": { argTypes: [STRING, STRING], result: STRING }, - "path.win32ToNamespacedPath": { argTypes: [STRING], result: STRING }, - /** path.parse: [root, dir, base, ext, name] as a fresh string[] (the - * frontend builds the ParsedPath record); path.format: the pathObject's - * root, dir, base, name and ext with undefined spelled "". */ - "path.parse": { argTypes: [STRING], result: arrayOf(STRING) }, - "path.win32Parse": { argTypes: [STRING], result: arrayOf(STRING) }, - "path.format": { argTypes: [STRING, STRING, STRING, STRING, STRING], result: STRING }, - "path.win32Format": { argTypes: [STRING, STRING, STRING, STRING, STRING], result: STRING }, - /** path.matchesGlob(path, pattern): Node's matchGlobPattern over its - * bundled minimatch (scr_glob.c). Both families match case-insensitively - * on macOS and Windows hosts like Node's; win32 also accepts either - * separator. Throws TypeError for a pattern over 64 Ki code units, - * RangeError for a brace sequence too long to expand, and SyntaxError - * when a segment's regex is invalid under the u flag. */ - "path.matchesGlob": { argTypes: [STRING, STRING], result: BOOL }, - "path.win32MatchesGlob": { argTypes: [STRING, STRING], result: BOOL }, - /** node:os: homedir is $HOME else getpwuid(3); tmpdir is Node's env - * cascade ($TMPDIR/$TMP/$TEMP else /tmp, one trailing slash trimmed). - * os.platform() lowers to process.platform — one implementation. */ - "os.homedir": { argTypes: [], result: STRING }, - /** os.release(): uname(2)'s release field — Node's own implementation - * (the kernel version string, e.g. "24.6.0" on macOS 15). Interned; +1 - * per read. Never throws. */ - "os.release": { argTypes: [], result: STRING }, - /** os.type(): uname(2)'s sysname ("Darwin", "Linux"; "Windows_NT" on - * win32) — Node's uv_os_uname answer. Interned per call; never throws. */ - "os.type": { argTypes: [], result: STRING }, - /** os.totalmem(): total physical memory in bytes. Never throws. */ - "os.totalmem": { argTypes: [], result: F64 }, - /** os.availableParallelism(): CPUs the process may use (libuv's answer), >= 1. Never throws. */ - "os.availableParallelism": { argTypes: [], result: F64 }, - /** os.hostname/machine/version/endianness, freemem, uptime and loadavg: - * libuv's answers (uname's machine and version fields, gethostname, - * "LE"/"BE", free memory in bytes, uptime in seconds, the three load - * averages). Fresh results; never throw. */ - "os.hostname": { argTypes: [], result: STRING }, - "os.machine": { argTypes: [], result: STRING }, - "os.version": { argTypes: [], result: STRING }, - "os.endianness": { argTypes: [], result: STRING }, - "os.freemem": { argTypes: [], result: F64 }, - "os.uptime": { argTypes: [], result: F64 }, - "os.loadavg": { argTypes: [], result: arrayOf(F64) }, - /** os.getPriority(pid): validateInt32 (RangeError ERR_OUT_OF_RANGE), - * then the priority; a failure throws Node's SystemError. */ - "os.getPriority": { argTypes: [F64], result: F64 }, - /** os.setPriority(pid, priority): validateInt32 for both (priority in - * -20..19, RangeError ERR_OUT_OF_RANGE), then the priority; a failure - * throws Node's SystemError. */ - "os.setPriority": { argTypes: [F64, F64], result: VOID }, - /** os.cpus(): cpusTake snapshots every CPU and answers the count; - * cpusModel(i) and cpusField(i, k) (k: 0 speed, 1 user, 2 nice, 3 sys, - * 4 idle, 5 irq) read the snapshot. Never throw. */ - "os.cpusTake": { argTypes: [], result: F64 }, - "os.cpusModel": { argTypes: [F64], result: STRING }, - "os.cpusField": { argTypes: [F64, F64], result: F64 }, - /** os.constants: the per-thread null-prototype constants object (dlopen, - * errno, signals, priority, UV_UDP_REUSEADDR). Never throws. */ - "os.constants": { argTypes: [], result: DYN }, - /** fs.constants: the target's cached null-prototype constants object. */ - "fs.constants": { argTypes: [], result: DYN }, - /** The deprecated node:constants object (scr_os.c): the os groups and - * fs.constants merged with the borrowed baked crypto.constants table, - * frozen, one per thread. */ - "constants.object": { argTypes: [DYN], result: DYN }, - /** umask(2): arg < 0 reads without setting (umask has no read-only form - * — set 0, restore); otherwise sets and answers the PREVIOUS mask. - * Never throws. */ - "process.umask": { argTypes: [F64], result: F64 }, - /** chdir(2) — throws Node's fs-shaped error (ENOENT/EACCES/ENOTDIR, - * syscall "chdir") on failure. */ - "process.chdir": { argTypes: [STRING], result: VOID }, - "process.loadEnvFile": { argTypes: [DYN], result: VOID }, - /** process._exiting: true once the exit sequence began (exit listeners - * running) — the runtime flag scr_run_exit_listeners/process.exit set. - * Never throws. */ - "process.exiting": { argTypes: [], result: BOOL }, - /** net's process-wide happy-eyeballs attempt budget (Node's default - * 250ms): one runtime double in the core unit, so reading/writing it - * never forces the net unit into the link. Never throw. */ - "net.getAutoSelTimeout": { argTypes: [], result: F64 }, - "net.setAutoSelTimeout": { argTypes: [F64], result: VOID }, - /** realpath(3) with Node's error shape (syscall "lstat" in the message, - * Node's own spelling for realpathSync failures). +1 fresh string. */ - "fs.realpathSync": { argTypes: [STRING], result: STRING }, - /** fs.realpathSync (or its .native when the flag is true) as a function - * value: path and options arrive unchecked; the result is a string or a - * Buffer by the options' encoding. */ - "fs.realpathValue": { argTypes: [DYN, DYN, BOOL], result: DYN }, - /** Native realpath with syscall "realpath" on failure. +1 fresh string. */ - "fs.realpathNativeSync": { argTypes: [STRING], result: STRING }, - /** The os.userInfo() field trio (uv_os_get_passwd's slices): pw_name, - * pw_shell, pw_dir — the PASSWD homedir, not os.homedir's $HOME-first - * cascade (Node's own split). The frontend assembles the UserInfo - * record from these plus getuid/getgid. +1 fresh strings; a passwd - * lookup failure aborts (Node throws a system error there — no - * compiled program path reaches it for the running uid). */ - "os.userName": { argTypes: [], result: STRING }, - "os.userShell": { argTypes: [], result: STRING }, - "os.userHomedir": { argTypes: [], result: STRING }, - "os.tmpdir": { argTypes: [], result: STRING }, - // Result is the call site's Dict record (VOID is - // the dgram.address sentinel — the libCall case checks the structure). - /** os.networkInterfaces(): getifaddrs(3) → the Dict - * record, built inline by the emitter from a runtime snapshot (scr_lib.c). - * The result type is the CALL SITE's mapped @types/node shape — a pure - * index-signature record whose value is `Info[] | undefined`, Info a - * two-record union (IPv4: scopeid `number | undefined` holding undefined; - * IPv6: scopeid number) — verified structurally by the frontend. Rows - * match libuv's filter (IFF_UP && IFF_RUNNING, AF_INET/AF_INET6; loopback - * = internal; MACs from the interface's link-level sibling entry, zeros - * when absent; cidr from the netmask's contiguous prefix, the null arm - * when it is missing or non-contiguous). Key/row order follows the OS's - * getifaddrs enumeration — Node itself does not guarantee an order. - * Fresh +1 record; never throws (a getifaddrs failure yields {}). */ - "os.networkInterfaces": { argTypes: [], result: VOID }, - /** `Math.max(...xs)` / `Math.min(...xs)` over one spread number[] - * (scr_number.c): the JS fold exactly — any NaN element poisons the - * result, ±0 order by the JS comparison (max prefers +0, min prefers - * -0), and the empty array yields -Infinity / +Infinity like the - * zero-argument calls. Borrows the array; never throws. */ - "math.maxArr": { argTypes: [arrayOf(F64)], result: F64 }, - "math.minArr": { argTypes: [arrayOf(F64)], result: F64 }, - "math.hypotArr": { argTypes: [arrayOf(F64)], result: F64 }, - /** `Math.floor(x)` — C floor() IS the JS operation (NaN/±0/±Infinity - * pass through bit-exactly). Never throws. */ - "math.floor": { argTypes: [F64], result: F64 }, - /** Math.abs (C fabs — IS the JS operation) and Math.round (scr_lib.c: - * ECMA half-toward-+Infinity with the exact-fraction comparison — C - * round() is half-away-from-zero and floor(x+0.5) drifts at the - * epsilon boundary). Borrow nothing; never throw. */ - "math.abs": { argTypes: [F64], result: F64 }, - "math.round": { argTypes: [F64], result: F64 }, +function buildLibFnSignatures() { + return defineLibFnSignatures({ + /** Native static fetch and its Web-platform companions. fetch.start + * answers once the response head arrives; the response body readers + * consume the native body stream. AbortSignal and ReadableStream values + * are opaque checked-dynamic handles. */ + "fetch.start": { argTypes: [STRING, DYN], result: { kind: "promise", inner: DYN } }, + "fetch.responseNew": { argTypes: [DYN, DYN], result: DYN }, + "fetch.responseJsonStatic": { argTypes: [DYN, DYN], result: DYN }, + "fetch.responseLight": { argTypes: [DYN], result: arrayOf(STRING) }, + "fetch.input": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, + "abort.controllerNew": { argTypes: [], result: DYN }, + /** EventTarget / Event / CustomEvent construction (scr_event_target.c): + * the Event constructors take the argument vector as one dyn array and + * throw Node's validation errors; `event.is` is `v instanceof Event` + * (kind 0), `CustomEvent` (1), `EventTarget` (2). addAbortListener + * answers the disposer (the Disposable's [Symbol.dispose]). */ + "event.targetNew": { argTypes: [], result: DYN }, + "event.new": { argTypes: [DYN], result: DYN }, + "event.customNew": { argTypes: [DYN], result: DYN }, + "event.is": { argTypes: [DYN, F64], result: BOOL }, + /** Compiled EventTarget and Event subclasses: the receiver is the + * instance (an object rooted at %EventTarget / %Event). targetInit and + * init are super() (init takes the argument vector as one dyn array + * and throws the constructor's validation errors; initType is the + * super(type) form with a string); targetCall runs an EventTarget method + * with the instance's own capsule as `self` (targetDispatch is its + * dispatchEvent(event) form, answering the bool); call, get and set + * reach the Event members. */ + "event.targetInit": { argTypes: [null], result: VOID }, + "event.init": { argTypes: [null, DYN], result: VOID }, + "event.initType": { argTypes: [null, STRING], result: VOID }, + /** %main hands the engine the compiled `listener.handleEvent` reader + * (lower-event-target.ts noteEventListeners). */ + "event.handleEventReader": { argTypes: [DYN], result: VOID }, + "event.targetDispatch": { argTypes: [null, DYN, DYN], result: BOOL }, + "event.targetCall": { argTypes: [null, DYN, STRING, DYN], result: DYN }, + "event.call": { argTypes: [null, STRING, DYN], result: DYN }, + "event.get": { argTypes: [null, STRING], result: DYN }, + "event.set": { argTypes: [null, STRING, DYN], result: VOID }, + "events.addAbortListener": { argTypes: [DYN, DYN], result: DYN }, + /** Blob / File (scr_blob.c): the constructors and slice() take their + * argument vector as one dyn array and throw Node's validation errors; + * the readers settle on Node's microtask turn for the Blob's parts. + * `blob.is` is `v instanceof Blob` (kind 0) or `File` (1). */ + "blob.new": { argTypes: [DYN], result: DYN }, + "blob.fileNew": { argTypes: [DYN], result: DYN }, + "blob.slice": { argTypes: [DYN, DYN], result: DYN }, + "blob.text": { argTypes: [DYN], result: { kind: "promise", inner: STRING } }, + "blob.bytes": { argTypes: [DYN], result: { kind: "promise", inner: BYTES_U8 } }, + "blob.arrayBuffer": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, + "blob.is": { argTypes: [DYN, F64], result: BOOL }, + /** WebAssembly (scr_wasm.c): modules translated at build time + * (wasm/translate.ts), found at run time by the SHA-256 of their bytes. + * compile and instantiate over bytes settle on a later loop turn; + * instantiate over a Module settles now, as in Node. `wasm.is` answers + * instanceof for Module, Instance, Memory, Table and Global (kinds 0-4) + * and CompileError, LinkError and RuntimeError (5-7); `wasm.errorNew` + * constructs one of the error classes (kind 5-7, message, options). */ + "wasm.compile": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, + "wasm.validate": { argTypes: [DYN], result: BOOL }, + "wasm.instantiate": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, + "wasm.moduleNew": { argTypes: [DYN], result: DYN }, + "wasm.instanceNew": { argTypes: [DYN, DYN], result: DYN }, + "wasm.is": { argTypes: [DYN, F64], result: BOOL }, + "wasm.errorNew": { argTypes: [F64, DYN, DYN], result: DYN }, + /** new WebAssembly.Memory(descriptor), Table(descriptor, value) and + * Global(descriptor, value) (an undefined value is the type's default); + * `wasm.withoutNew` throws the TypeError for Module, Instance, Memory, + * Table or Global (kinds 0-4) called without new, after its arguments + * evaluate. */ + "wasm.memoryNew": { argTypes: [DYN], result: DYN }, + "wasm.tableNew": { argTypes: [DYN, DYN], result: DYN }, + "wasm.globalNew": { argTypes: [DYN, DYN], result: DYN }, + "wasm.withoutNew": { argTypes: [F64, DYN, DYN], result: DYN }, + /** WebAssembly.Module.imports(module), exports(module) and + * customSections(module, name): checked-dynamic arrays of descriptor + * objects and ArrayBuffers. */ + "wasm.moduleImports": { argTypes: [DYN], result: DYN }, + "wasm.moduleExports": { argTypes: [DYN], result: DYN }, + "wasm.moduleCustomSections": { argTypes: [DYN, DYN], result: DYN }, + /** `v.valueOf()` on a WebAssembly-typed receiver: a Global's value, + * dyn.valueOf's answer for anything else. */ + "wasm.valueOf": { argTypes: [DYN], result: DYN }, + /** WebAssembly.compile (0), instantiate (1) and validate (2) as function + * values, and the namespace object holding them. */ + "wasm.function": { argTypes: [F64], result: DYN }, + "wasm.namespace": { argTypes: [], result: DYN }, + /** The global object viewed through a cast to a type with a WebAssembly + * member: an object holding the namespace. */ + "wasm.globalView": { argTypes: [], result: DYN }, + "abort.timeout": { argTypes: [DYN], result: DYN }, + "abort.now": { argTypes: [DYN], result: DYN }, + "abort.any": { argTypes: [DYN], result: DYN }, + "fetch.function": { argTypes: [], result: DYN }, + "fetch.requestNew": { argTypes: [DYN, DYN], result: DYN }, + "fetch.headersNew": { argTypes: [DYN], result: DYN }, + "fetch.responseArrayBuffer": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, + "fetch.responseJson": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, + "fetch.responseText": { argTypes: [DYN], result: { kind: "promise", inner: STRING } }, + "fetch.responseBytes": { argTypes: [DYN], result: { kind: "promise", inner: BYTES_U8 } }, + "fetch.abortControllerNew": { argTypes: [], result: DYN }, + "fetch.abortTimeout": { argTypes: [DYN], result: DYN }, + "fetch.abortNow": { argTypes: [DYN], result: DYN }, + "fetch.abortAny": { argTypes: [DYN], result: DYN }, + "fetch.streamNew": { argTypes: [DYN], result: DYN }, + "fetch.transformNew": { argTypes: [], result: DYN }, + // Program-dependent iterable: typed arrays/bytes/string stay intact so + // the native stream can pull lazily; checked-dynamic values are the + // fallback. The libCall validator in validate.ts checks the closed set. + "fetch.webIs": { argTypes: [DYN, STRING], result: BOOL }, + "fetch.streamIs": { argTypes: [DYN], result: BOOL }, + "fetch.streamFrom": { argTypes: [null], result: DYN }, + // The chunk/result record depends on ReadableStream; validated by validate.ts. + "fetch.readerRead": { argTypes: [DYN], result: VOID }, + /** Readable.fromWeb (scr_stream_from_web.c): the stream, objectMode, + * highWaterMark (< 0: the mode's default) and encoding ("": none). */ + "fetch.readableFromWeb": { argTypes: [DYN, BOOL, F64, STRING], result: VOID }, + "json.parse": { argTypes: [STRING], result: DYN }, + "json.parseReviver": { argTypes: [STRING, DYN], result: DYN }, + "json.stringifyReplacer": { argTypes: [DYN, DYN, STRING], result: DYN }, + "json.stringifyValue": { argTypes: [DYN, DYN, DYN], result: DYN }, + /** Keyed WRITE on a dyn value — `h.onDone = cb` / `h["k"] = v` on a + * checked-dynamic object (args: receiver, key string, value — all + * borrowed; the runtime copies the key and retains the value in). An + * OBJ receiver sets the member (later writes win, insertion order + * preserved — JS exactly); undefined/null throws Node's catchable + * "Cannot set properties of undefined (setting 'k')"; every other kind + * throws Node's STRICT-mode "Cannot create property 'k' on " — + * primitives quoting their rendering, V8's "on number '5'" + * (sloppy mode would ignore the write — suite tests are 'use strict'; + * SEMANTICS.md notes the sloppy divergence: the write throws). Void + * result; in the may-throw seed set. */ + "dyn.keySet": { argTypes: [DYN, STRING, DYN], result: VOID }, + "dyn.keySetComputed": { argTypes: [DYN, DYN, DYN], result: VOID }, + /** Delete an ordinary checked-native object's own key. Borrows both + * arguments; other receiver representations retain a runtime refusal. */ + "dyn.keyDelete": { argTypes: [DYN, STRING, BOOL], result: VOID }, + "dyn.keyDeleteComputed": { argTypes: [DYN, DYN, BOOL], result: VOID }, + "dyn.reflectDeleteProperty": { argTypes: [DYN, DYN], result: BOOL }, + "dyn.hasKeyComputed": { argTypes: [DYN, DYN], result: BOOL }, + "dyn.hasOwnComputed": { argTypes: [DYN, DYN], result: BOOL }, + "dyn.propertyIsEnumerableComputed": { argTypes: [DYN, DYN], result: BOOL }, + /** Native own properties on globalThis keyed by symbol identity. */ + "dyn.globalSymbolGet": { argTypes: [SYMBOL_T], result: DYN }, + "dyn.globalSymbolSet": { argTypes: [SYMBOL_T, DYN], result: VOID }, + "dyn.globalSymbolHas": { argTypes: [SYMBOL_T], result: BOOL }, + "dyn.globalSymbolDelete": { argTypes: [SYMBOL_T], result: VOID }, + /** Exact native class capsule identity, without materializing its fields. */ + "dyn.typedRefIs": { argTypes: [DYN, STRING], result: BOOL }, + /** A capsule boxed by this program from exactly this class: one key + * pointer test, false for equal keys boxed elsewhere. Guards fast paths + * whose fallback handles every other value. The key is a literal. */ + "dyn.typedRefKeyIs": { argTypes: [DYN, STRING], result: BOOL }, + "dyn.classIs": { argTypes: [DYN, STRING], result: BOOL }, + /** Destructuring pack over a dyn source — `const [a, b] = d`, a + * destructured dyn callback param (args: the source and the STATIC + * TypeError spelling, "" when the source has none — both borrowed; + * result: a fresh dyn array, +1). Iterable kinds collect like spread + * (arrays element-by-element, strings by code point, bytes by byte); + * every other kind throws V8's destructuring TypeError — the spelling + * verbatim when non-empty, else the runtime kind wording ("number 5 is + * not iterable (cannot read property Symbol(Symbol.iterator))"). In the + * may-throw seed set. */ + "dyn.iterPack": { argTypes: [DYN, STRING], result: DYN }, + "dyn.mathFold": { argTypes: [DYN, BOOL, STRING], result: F64 }, + "dyn.destructureRest": { argTypes: [DYN, STRING], result: DYN }, + "dyn.arrayFromIterator": { argTypes: [DYN], result: DYN }, + "dyn.iterator": { argTypes: [DYN, STRING], result: DYN }, + /** for await over a checked-dynamic value: the loop's iterator (a + * compiled async generator, Symbol.asyncIterator's result, or the sync + * iterator), and whether that iterator is synchronous. */ + "dyn.asyncIteratorOpen": { argTypes: [DYN, STRING], result: DYN }, + "dyn.asyncIteratorWasSync": { argTypes: [], result: BOOL }, + "dyn.iteratorResult": { argTypes: [DYN], result: DYN }, + "dyn.iteratorCanStep": { argTypes: [DYN, DYN], result: BOOL }, + "dyn.iteratorStep": { argTypes: [DYN], result: DYN }, + "dyn.iteratorStepDone": { argTypes: [DYN], result: BOOL }, + "dyn.setGeneratorMembers": { argTypes: [DYN, DYN], result: VOID }, + "dyn.iteratorHelperMethod": { argTypes: [STRING], result: DYN }, + "dyn.collectionIteratorIndex": { argTypes: [DYN], result: F64 }, + "dyn.mapSeedEntries": { argTypes: [DYN], result: DYN }, + "dyn.mapSeedEntry": { argTypes: [DYN], result: DYN }, + /** The for-of-over-dyn pack accessors — the emitted index loop drives + * them over a dyn.iterPack result (ARR by construction). arrLen: the + * ARR length as f64 (0 for non-ARR kinds; arg borrowed). arrAt: the + * element at index (+1; the undefined singleton past the end). Neither + * throws. */ + "dyn.arrLen": { argTypes: [DYN], result: F64 }, + "dyn.arrAt": { argTypes: [DYN, F64], result: DYN }, + /** `key in v` with a RUNTIME (string) key on a checked-dynamic + * receiver (args: value dyn, key string; result bool): OBJ answers + * own-member presence, ARR answers 'length'/a valid index — exactly + * the literal-key dynHasKey path. Proxy has traps may throw. */ + "dyn.hasKey": { argTypes: [DYN, STRING], result: BOOL }, + /** The `in` operator with a runtime string key: dyn.hasKey plus the + * members inherited from builtin and compiled class prototypes. */ + "dyn.in": { argTypes: [DYN, STRING], result: BOOL }, + "dyn.freeze": { argTypes: [DYN], result: DYN }, + "dyn.isFrozen": { argTypes: [DYN], result: BOOL }, + /** Object.defineProperty on a declared class field (scr_json.c): the + * field's current value (borrowed), its FIELD_* attribute word, the + * instance's CLASS_* integrity word, the field name and the descriptor. + * Validates as Node does (TypeError "Cannot redefine property: f") and + * answers a one-property holder of the defined value and attributes (+1), + * read back with class.definedBits and class.definedValue. */ + "class.defineField": { argTypes: [DYN, F64, F64, STRING, DYN], result: DYN }, + "class.definedBits": { argTypes: [DYN, STRING], result: F64 }, + "class.definedValue": { argTypes: [DYN, STRING], result: DYN }, + /** Whether a property descriptor has a `value` member. */ + "class.descriptorHasValue": { argTypes: [DYN], result: BOOL }, + /** Throws Node's TypeError for a write to a read-only class field: the + * field name and the instance's class name. */ + "class.throwReadOnly": { argTypes: [STRING, STRING], result: VOID }, + /** Throws Node's TypeError for a class field initializer on a + * non-extensible instance: the field name. */ + "class.throwNotExtensible": { argTypes: [STRING], result: VOID }, + /** Object.freeze of a record whose shape is freezable (frozen-records.ts): + * sets the frozen bit in its rc word (scr_record_freeze). The receiver is + * any record type. */ + "record.freeze": { argTypes: [null], result: VOID }, + /** Whether a record is frozen: its rc word's frozen bit, set by + * record.freeze and dyn.freeze of a capsule. Emitted inline. The receiver + * is any record type. */ + "record.isFrozen": { argTypes: [null], result: BOOL }, + /** Throws Node's TypeError for a write to a frozen record: the key, the + * object's text in the message ("#") and the operation (0 assign, + * 1 add, 2 delete). */ + "record.throwFrozen": { argTypes: [STRING, STRING, F64], result: VOID }, + /** Object.freeze of an array (scr_arr_freeze): sets its frozen bit, which + * the write guards of IrModule.freezableArrays test, and isFrozen reads. + * The receiver is any array type. */ + "array.freeze": { argTypes: [null], result: VOID }, + "array.isFrozen": { argTypes: [null], result: BOOL }, + /** Object.freeze, seal or preventExtensions of a Map or Set + * (scr_map_prevent_extensions), which only makes it not extensible: its + * entries stay writable. The receiver is any map or set type. */ + "collection.preventExtensions": { argTypes: [null], result: VOID }, + "collection.isExtensible": { argTypes: [null], result: BOOL }, + "dyn.nativeSetNew": { argTypes: [DYN], result: DYN }, + "dyn.nativeSetIs": { argTypes: [DYN], result: BOOL }, + "dyn.nativeMapIs": { argTypes: [DYN], result: BOOL }, + "dyn.nativeUrlIs": { argTypes: [DYN], result: BOOL }, + "dyn.nativeDateIs": { argTypes: [DYN], result: BOOL }, + "dyn.nativeDateHandleIs": { argTypes: [DYN], result: BOOL }, + /** A builtin constructor (`Object`, `Date`, `RegExp`, `Map`, `Set`, + * `Promise`, `WeakMap`, `WeakSet`) read as a JavaScript value: one + * interned function per name, the same one dynamic values answer for + * `.constructor`. The name is a compiler-chosen literal. */ + "dyn.globalConstructor": { argTypes: [STRING], result: DYN }, + /** A builtin global function (setTimeout, setInterval, setImmediate, + * the clear functions, queueMicrotask, process.nextTick) read as a + * JavaScript value: one interned function per name whose calls run the + * timer APIs (it pulls in the event loop). The name is a compiler-chosen + * literal. */ + "dyn.builtinFunction": { argTypes: [STRING], result: DYN }, + "dyn.namespaceNew": { argTypes: [STRING, DYN], result: DYN }, + "dyn.namespaceDefine": { argTypes: [DYN, STRING, DYN, F64, F64], result: VOID }, + "date.nativeNew": { argTypes: [DYN], result: DYN }, + /** `new Date(year, monthIndex, ...)` in JavaScript: the argument array's + * first seven values pass through ToNumber in order (later ones are + * evaluated, never converted), then the local-time field constructor. */ + "date.nativeNewFields": { argTypes: [DYN], result: DYN }, + /** `new Date(value)` in JavaScript: a string argument parses with V8's + * full date parser; every other value constructs as date.nativeNew. */ + "date.nativeNewValue": { argTypes: [DYN], result: DYN }, + "date.argumentsTime": { argTypes: [DYN], result: DATE_T }, + "date.classOperation": { argTypes: [DYN, DYN], result: VOID }, + "date.checkedValue": { argTypes: [DYN], result: DATE_T }, + "dyn.nativeRegexIs": { argTypes: [DYN], result: BOOL }, + /** toString() on a checked-dynamic receiver: runtime kind dispatch + * (bytes decode per the literal encoding — utf8 default; strings, + * numbers, booleans, arrays, objects answer JS-exactly; undefined and + * null throw the catchable TypeError). */ + "dyn.toString": { argTypes: [DYN, DYN, STRING], result: STRING }, + "dyn.valueOf": { argTypes: [DYN, STRING], result: DYN }, + /** Object.defineProperties over dyn values (args: target, descriptors — + * both borrowed dyn; result: the target, +1 — JS's return value). + * Value descriptors become own properties on OBJ and FUNC targets; + * OBJ targets preserve data attributes. get/set + * descriptors and non-object targets/descriptors throw catchably + * (Node's TypeError texts; accessors the "not supported yet" Error). In + * the may-throw seed set. */ + "dyn.defineProps": { argTypes: [DYN, DYN], result: DYN }, + "dyn.defineProperty": { argTypes: [DYN, DYN, DYN], result: DYN }, + "dyn.getOwnPropertyDescriptor": { argTypes: [DYN, DYN], result: DYN }, + "dyn.arrayProtoCall": { argTypes: [DYN, STRING, DYN], result: DYN }, + /** Promise.all / Promise.allSettled / Promise.any over a spread + * checked-dynamic array: the values, the settled-record array, or the + * first fulfillment (AggregateError once every entry rejects). + * Thenable elements adopt; the second argument reads a program class + * instance's `then` (the compiled property dispatch). */ + "dyn.promiseAll": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, + "dyn.promiseAllSettled": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, + "dyn.promiseAny": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, + /** PromiseResolve over one checked-dynamic value: the promise it holds, + * a promise that adopts a thenable's settlement, or a promise fulfilled + * with the value. The second argument reads `then` as above. */ + "dyn.promiseResolve": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, + /** Bare `typeof v` on a dyn value AS A STRING (arg: the dyn value, + * borrowed; result: an owned string) — the dyn kind's JS answer: + * undefined→"undefined", null/object/array/bytes→"object" (JS's oldest + * wart preserved), boolean/number/string by kind, function→"function". + * Never throws. */ + "dyn.typeof": { argTypes: [DYN], result: STRING }, + /** Object.prototype.toString.call on a checked-dynamic value. */ + "dyn.objectTag": { argTypes: [DYN], result: STRING }, + /** Engine-free CommonJS module graph. Module values are scalar f64 + * handles; generated startup defines the registry, init wrappers update + * loading/cache state, and the read surface answers Node's live metadata. */ + "module.registryInit": { argTypes: [F64], result: VOID }, + "module.define": { + argTypes: [F64, STRING, STRING, STRING, arrayOf(STRING), BOOL], + result: VOID, + }, + "module.enter": { argTypes: [F64], result: VOID }, + "module.link": { argTypes: [F64, F64], result: VOID }, + "module.finish": { argTypes: [F64], result: VOID }, + "module.fail": { argTypes: [F64], result: VOID }, + "module.filename": { argTypes: [F64], result: STRING }, + "module.id": { argTypes: [F64], result: STRING }, + "module.path": { argTypes: [F64], result: STRING }, + "module.paths": { argTypes: [F64], result: arrayOf(STRING) }, + "module.children": { argTypes: [F64], result: arrayOf(F64) }, + "module.parent": { argTypes: [F64], result: F64 }, + "module.loaded": { argTypes: [F64], result: BOOL }, + "module.cacheGet": { argTypes: [STRING], result: F64 }, + "module.cacheHas": { argTypes: [STRING], result: BOOL }, + "module.cacheKeys": { argTypes: [], result: arrayOf(STRING) }, + "timers.setTimeout": { argTypes: [{ kind: "func", params: [], ret: VOID }, F64], result: VOID }, + /** The repeating timer pair. setInterval takes (callback, ms) like + * setTimeout and RETURNS the f64 handle the fallback declarations + * promise (ids start at 1, so truthiness narrowing works); the loop + * owns the callback until clearInterval removes the entry (eagerly — a + * live interval keeps the loop alive, a cleared one releases it, like + * Node). Neither throws; a throw ESCAPING an interval callback ends the + * program like a setTimeout throw. */ + "timers.setInterval": { argTypes: [{ kind: "func", params: [], ret: VOID }, F64], result: F64 }, + "timers.clearInterval": { argTypes: [F64], result: VOID }, + /** setTimeout WITH a clear handle (the f64 id) — the clearable/unref-able + * one-shot; clearTimeout cancels it, .unref() drops it from loop + * liveness. The plain timers.setTimeout stays the handle-less + * fire-and-forget. */ + "timers.setTimeoutHandle": { + argTypes: [{ kind: "func", params: [], ret: VOID }, F64], + result: F64, + }, + "timers.clearTimeout": { argTypes: [F64], result: VOID }, + /** Timeout.unref()/ref()/hasRef() — loop-liveness bookkeeping over the + * handle id. unref/ref RETURN the handle (f64) for chaining; hasRef + * returns bool. */ + "timers.unref": { argTypes: [F64], result: F64 }, + "timers.ref": { argTypes: [F64], result: F64 }, + "timers.hasRef": { argTypes: [F64], result: BOOL }, + /** Timeout.refresh() — re-arm to now + the original delay (from the + * heap or from inside the firing callback; a one-shot that fired on an + * earlier turn is gone and no-ops — documented divergence). Returns + * the handle for chaining like unref/ref. */ + "timers.refresh": { argTypes: [F64], result: F64 }, + /** setImmediate/clearImmediate — Node's check phase: callbacks run + * once per loop turn AFTER due timers, FIFO, and immediates queued + * mid-phase wait for the next turn. setImmediate returns the f64 + * handle (its own id space — clearTimeout of an Immediate no-ops, + * like Node); the Immediate ref trio mirrors the Timeout one (an + * unref'd pending immediate neither keeps the loop alive nor fires + * once nothing reffed remains). */ + "timers.setImmediate": { argTypes: [{ kind: "func", params: [], ret: VOID }], result: F64 }, + /** queueMicrotask (scr_async.c): the callback enters the SAME FIFO + * promise continuations ride — one microtask order, like V8's queue — + * and a throw is an UNCAUGHT exception (never a rejection). + * timers.queueMicrotask takes an owned zero-param closure and never + * throws; the Dyn form (checked-dynamic arguments — the mustCall + * wrapper, the suite's invalid-input probes) throws Node's + * ERR_INVALID_ARG_TYPE synchronously on a non-function value and calls + * the function with zero arguments at drain. */ + "timers.queueMicrotask": { argTypes: [{ kind: "func", params: [], ret: VOID }], result: VOID }, + "timers.queueMicrotaskDyn": { argTypes: [DYN], result: VOID }, + "timers.clearImmediate": { argTypes: [F64], result: VOID }, + /** process.nextTick(cb, ...args) — the user tick queue. args: [cb + * (() => void; trailing call arguments ride the timer surface's + * interned dyn thunk)]. Ticks drain BEFORE promise jobs at every loop + * checkpoint, to joint exhaustion with them (Node's tick-then- + * microtask order); ticks enqueued by station listeners run at the + * NEXT checkpoint (the stream-tick station divergence, SEMANTICS.md). + * Pending ticks are always-ready work — the loop neither sleeps nor + * exits while any exist; ticks scheduled from 'exit' listeners never + * run (Node). The enqueue itself never throws. */ + "process.nextTick": { argTypes: [{ kind: "func", params: [], ret: VOID }], result: VOID }, + /** The process introspection statics. uptime: seconds since the + * binary's own start (fractional — a load-time monotonic anchor). + * availableMemory/constrainedMemory: libuv's numbers (free-ish bytes; + * the cgroup cap or 0). cpuUser/cpuSystem (+ threadCpu twins): the + * process/thread CPU clocks in microseconds — the frontend composes + * the {user, system} records. The *Diff forms answer current − prev + * for one field; cpuPrevValidate throws Node's ERR_INVALID_ARG_VALUE + * RangeError for negative/non-finite prev fields (user first, then + * system — Node's order; MAY THROW). rusage(idx): one + * process.resourceUsage() field by canonical index (Node's units). + * activeResources: the loop's own bookkeeping — 'Timeout' per armed + * (or firing, uncleared) timer, 'Immediate' per queued unfired + * immediate; unmodeled resource kinds are absent (SEMANTICS.md). */ + "process.uptime": { argTypes: [], result: F64 }, + /** perf_hooks performance.now(): fractional ms since process start. */ + "perf.now": { argTypes: [], result: F64 }, + /** perf_hooks user timing over the thread's performance timeline. The + * producing calls take the call's whole argument vector as one dyn + * array (Node's validation and errors run in the runtime, MAY THROW): + * mark/measure answer 1, entries(args, which) the entry count of + * getEntries (0), getEntriesByName (1) or getEntriesByType (2). The + * entryName/Type/Start/Duration/Detail accessors read entry i of that + * answer; the frontend builds a new entry's record from them and hands + * it to entryKeep (a typed reference capsule), and the getters read the + * kept records back through entryRef, so entries keep their identity. */ + "perf.mark": { argTypes: [DYN], result: F64 }, + "perf.measure": { argTypes: [DYN], result: F64 }, + "perf.entries": { argTypes: [DYN, F64], result: F64 }, + "perf.clearMarks": { argTypes: [DYN], result: VOID }, + "perf.clearMeasures": { argTypes: [DYN], result: VOID }, + "perf.entryName": { argTypes: [F64], result: STRING }, + "perf.entryType": { argTypes: [F64], result: STRING }, + "perf.entryStart": { argTypes: [F64], result: F64 }, + "perf.entryDuration": { argTypes: [F64], result: F64 }, + "perf.entryDetail": { argTypes: [F64], result: DYN }, + "perf.entryKeep": { argTypes: [DYN], result: VOID }, + "perf.entryRef": { argTypes: [F64], result: DYN }, + /** perf_hooks event-loop metrics (scr_perf_loop.c): loopStart is the + * loop's start in performance.now() ms (0 before it), idleTime the idle + * ms since. eldNew(resolution ms) creates a monitorEventLoopDelay + * histogram handle (MAY THROW Node's resolution RangeError); enable/disable answer whether the state changed; + * eldPercentile expects Node's validated range; eldStat(which) reads + * 0 min, 1 max, 2 mean, 3 stddev, 4 count, 5 exceeds. */ + "perf.loopStart": { argTypes: [], result: F64 }, + "perf.idleTime": { argTypes: [], result: F64 }, + "perf.eldNew": { argTypes: [F64], result: F64 }, + "perf.eldEnable": { argTypes: [F64], result: BOOL }, + "perf.eldDisable": { argTypes: [F64], result: BOOL }, + "perf.eldReset": { argTypes: [F64], result: VOID }, + "perf.eldPercentile": { argTypes: [F64, F64], result: F64 }, + "perf.eldStat": { argTypes: [F64, F64], result: F64 }, + /** process.memoryUsage(): memoryUsageTake samples the resident set and + * the runtime heap once (MAY THROW Node's uv_resident_set_memory error) + * and memoryUsageField(k) reads that sample (0 rss, 1 heapTotal, 2 + * heapUsed, 3 external, 4 arrayBuffers). rss is memoryUsage.rss(). */ + "process.memoryUsageTake": { argTypes: [], result: VOID }, + "process.memoryUsageField": { argTypes: [F64], result: F64 }, + "process.rss": { argTypes: [], result: F64 }, + "process.availableMemory": { argTypes: [], result: F64 }, + "process.constrainedMemory": { argTypes: [], result: F64 }, + "process.cpuUser": { argTypes: [], result: F64 }, + "process.cpuSystem": { argTypes: [], result: F64 }, + "process.cpuUserDiff": { argTypes: [F64], result: F64 }, + "process.cpuSystemDiff": { argTypes: [F64], result: F64 }, + "process.threadCpuUser": { argTypes: [], result: F64 }, + "process.threadCpuSystem": { argTypes: [], result: F64 }, + "process.threadCpuUserDiff": { argTypes: [F64], result: F64 }, + "process.threadCpuSystemDiff": { argTypes: [F64], result: F64 }, + "process.cpuPrevValidate": { argTypes: [F64, F64], result: VOID }, + "process.rusage": { argTypes: [F64], result: F64 }, + "process.activeResources": { argTypes: [], result: arrayOf(STRING) }, + "timers.immediateUnref": { argTypes: [F64], result: F64 }, + "timers.immediateRef": { argTypes: [F64], result: F64 }, + "timers.immediateHasRef": { argTypes: [F64], result: BOOL }, + /** The tolerated non-handle clear (`clearTimeout(null)`, + * `clearInterval({})`, zero-argument forms): Node ignores anything + * that is not a live handle without an error — a VOID no-op the emitter drops + * (only syntactically side-effect-free arguments take this path). */ + "timers.clearNoop": { argTypes: [], result: VOID }, + // Signal listeners are zero-param (the ambient shape); exit/stdin + // callbacks carry program-dependent one-param shapes — null slots, the + // libCall case checks them (child.onExit precedent). + /** Named process signal events: [name string, callback dyn, once bool] + * or [name, callback] for removal. The runtime resolves platform signal + * numbers and delivers (name, number). Listeners do not keep the loop + * alive. Invalid callbacks and uncatchable signals throw. */ + "process.onSignal": { argTypes: [STRING, DYN, BOOL], result: VOID }, + "process.offSignal": { argTypes: [STRING, DYN], result: VOID }, + /** The process 'exit' event — process.on/once/off("exit"). args: [cb, + * once bool] / [cb]. Listeners run SYNCHRONOUSLY at termination + * (normal exit, process.exit(), the uncaught/unhandled exit-1 paths) + * with the exit code; anything they schedule never runs, like Node. + * Callback shapes: () => void or (code: number) => void — the emitter + * picks the runtime adapter. Never throw. */ + "process.onExit": { argTypes: [null, BOOL], result: VOID }, + "process.offExit": { argTypes: [null], result: VOID }, + /** process.stdin listener registration — stdin.on/once("data" | "end" | + * "error", cb). args: [cb, once bool]. data callbacks: () => void or + * (chunk: Uint8Array) => void; end: () => void; error: () => void or + * (err: Error) => void (the child error adapters are reused). While a + * data listener (or a parked for-await chunk promise) exists, stdin + * keeps the loop alive — Node's flowing-stdin keep-alive. Never + * throw. */ + "stdin.onData": { argTypes: [null, BOOL], result: VOID }, + "stdin.onEnd": { argTypes: [{ kind: "func", params: [], ret: VOID }, BOOL], result: VOID }, + "stdin.onError": { argTypes: [null, BOOL], result: VOID }, + /** process.stdin.on/once('keypress', cb) (scr_readline_tty.c): cb is the + * listener as a checked-dynamic function, called with (str, key). */ + "stdin.onKeypress": { argTypes: [DYN, BOOL], result: VOID }, + /** The for-await chunk source over process.stdin: no args, result + * Promise (+1). Fulfills with the next arrived chunk; the + * EMPTY bytes value is the done sentinel (POSIX reads never deliver + * empty data chunks), which the for-await desugar turns into loop + * exit. Never throws itself; awaiting it re-throws nothing (stdin + * errors surface through 'error' listeners, not the iterator). */ + "stdin.nextChunk": { argTypes: [], result: { kind: "promise", inner: BYTES_U8 } }, + "fs.readFileSync": { argTypes: [STRING, STRING], result: STRING }, + "fs.readFileEncoded": { argTypes: [STRING, STRING], result: STRING }, + "fs.readFdEncoded": { argTypes: [F64, STRING], result: STRING }, + /** readFileSync(path) — the Buffer read (+1 bytes); throws catchably + * like the utf8 form. */ + "fs.readFileSyncBuf": { argTypes: [STRING], result: BYTES_U8 }, + /** readFileSync(path, enc) with a RUNTIME encoding (an untyped JS + * parameter): undefined/null answer Buffers, utf8 a string, other real + * encodings throw the "not supported yet" Error, unknown names throw + * ERR_UNKNOWN_ENCODING. */ + "fs.readFileSyncDyn": { argTypes: [STRING, DYN], result: DYN }, + "fs.writeFileSync": { argTypes: [STRING, STRING], result: VOID }, + "fs.appendFileSync": { argTypes: [STRING, STRING], result: VOID }, + "fs.existsSync": { argTypes: [STRING], result: BOOL }, + "fs.mkdirSync": { argTypes: [STRING], result: VOID }, + "fs.rmSync": { argTypes: [STRING], result: VOID }, + "fs.rmdirSync": { argTypes: [STRING], result: VOID }, + "fs.readdirSync": { argTypes: [STRING], result: arrayOf(STRING) }, + // Result is the call site's Dirent record array (VOID is the + // structure-checked sentinel, the os.networkInterfaces pattern). + /** `fs.readdirSync(path, { withFileTypes: true })` — Dirent rows over + * one readdir pass (scr_lib.c's scandir snapshot; DT_UNKNOWN falls back + * to lstat, Node's getDirents rule). The result type is the call site's + * interned Dirent record array (name, parentPath, hidden %dtype in + * libuv's UV_DIRENT encoding) — verified by the frontend; the emitter + * assembles the rows from the snapshot. Byte order on POSIX (libuv + * sorts), the directory's order on Windows; no "."/"..". Throws + * Node's scandir errno error (may-throw seed set); fresh +1 array. */ + "fs.readdirTypesSync": { argTypes: [STRING], result: VOID }, + /** fs.globSync / fs.glob / fs/promises glob (scr_glob.c, Node's + * lib/internal/fs/glob.js walk): pattern and options are dyn values the + * runtime validates in Node's order. The string forms answer string[]; + * the Dirent forms answer the call site's Dirent record array (validated + * in validate.ts) assembled from the snapshot; fs.callbackGlob takes the + * argument vector and calls back with string[]. */ + "fs.globSync": { argTypes: [DYN, DYN], result: arrayOf(STRING) }, + "fs.globTypesSync": { argTypes: [DYN, DYN], result: VOID }, + "fs.callbackGlob": { argTypes: [DYN], result: VOID }, + "fsp.globStrings": { argTypes: [DYN, DYN], result: arrayOf(STRING) }, + "fsp.globTypes": { argTypes: [DYN, DYN], result: VOID }, + /** The error an fs/promises glob walk ended with (undefined when none), + * read once right after fsp.globStrings / fsp.globTypes. */ + "fsp.globError": { argTypes: [], result: DYN }, + /** fs.Dir (scr_lib.c): opendirSync(path, bufferSize) throws Node's + * opendir error (or the options.bufferSize RangeError); dir.readSync + * answers the call site's `Dirent | null` (VOID here — the emitter builds + * the row like readdirTypesSync) and dir.read is its promise twin; + * readSync and closeSync throw ERR_DIR_CLOSED on a closed Dir, read and + * close reject with it. */ + "fs.opendirSync": { argTypes: [STRING, F64], result: DIR_T }, + "fsp.opendir": { argTypes: [STRING, F64], result: { kind: "promise", inner: DIR_T } }, + "dir.path": { argTypes: [DIR_T], result: STRING }, + "dir.readSync": { argTypes: [DIR_T], result: VOID }, + "dir.read": { argTypes: [DIR_T], result: { kind: "promise", inner: VOID } }, + "dir.closeSync": { argTypes: [DIR_T], result: VOID }, + "dir.close": { argTypes: [DIR_T], result: { kind: "promise", inner: VOID } }, + /** node:path (scr_path.c ports BOTH of Node's implementations + * function-by-function): the `path.*` family is posix, the + * `path.win32*` family is Node v24's path.win32 ported exactly — the + * frontend binds the bare module to the TARGET platform's family + * (Node on Windows IS path.win32) and the path.posix / path.win32 + * namespaces to their own family everywhere. join and resolve take ONE + * string[] arg — the frontend packs the variadic call's arguments into + * an array literal. basename always receives its suffix (the frontend + * completes an omitted one with "", a Node no-op). toNamespacedPath is + * the posix identity and the win32 \\?\-prefixer. None of these throw; + * the resolves consult the process cwd like Node's. */ + "path.join": { argTypes: [arrayOf(STRING)], result: STRING }, + "path.resolve": { argTypes: [arrayOf(STRING)], result: STRING }, + "path.normalize": { argTypes: [STRING], result: STRING }, + "path.dirname": { argTypes: [STRING], result: STRING }, + "path.basename": { argTypes: [STRING, STRING], result: STRING }, + "path.extname": { argTypes: [STRING], result: STRING }, + "path.isAbsolute": { argTypes: [STRING], result: BOOL }, + "path.relative": { argTypes: [STRING, STRING], result: STRING }, + "path.toNamespacedPath": { argTypes: [STRING], result: STRING }, + "path.win32Join": { argTypes: [arrayOf(STRING)], result: STRING }, + "path.win32Resolve": { argTypes: [arrayOf(STRING)], result: STRING }, + "path.win32Normalize": { argTypes: [STRING], result: STRING }, + "path.win32Dirname": { argTypes: [STRING], result: STRING }, + "path.win32Basename": { argTypes: [STRING, STRING], result: STRING }, + "path.win32Extname": { argTypes: [STRING], result: STRING }, + "path.win32IsAbsolute": { argTypes: [STRING], result: BOOL }, + "path.win32Relative": { argTypes: [STRING, STRING], result: STRING }, + "path.win32ToNamespacedPath": { argTypes: [STRING], result: STRING }, + /** path.parse: [root, dir, base, ext, name] as a fresh string[] (the + * frontend builds the ParsedPath record); path.format: the pathObject's + * root, dir, base, name and ext with undefined spelled "". */ + "path.parse": { argTypes: [STRING], result: arrayOf(STRING) }, + "path.win32Parse": { argTypes: [STRING], result: arrayOf(STRING) }, + "path.format": { argTypes: [STRING, STRING, STRING, STRING, STRING], result: STRING }, + "path.win32Format": { argTypes: [STRING, STRING, STRING, STRING, STRING], result: STRING }, + /** path.matchesGlob(path, pattern): Node's matchGlobPattern over its + * bundled minimatch (scr_glob.c). Both families match case-insensitively + * on macOS and Windows hosts like Node's; win32 also accepts either + * separator. Throws TypeError for a pattern over 64 Ki code units, + * RangeError for a brace sequence too long to expand, and SyntaxError + * when a segment's regex is invalid under the u flag. */ + "path.matchesGlob": { argTypes: [STRING, STRING], result: BOOL }, + "path.win32MatchesGlob": { argTypes: [STRING, STRING], result: BOOL }, + /** node:os: homedir is $HOME else getpwuid(3); tmpdir is Node's env + * cascade ($TMPDIR/$TMP/$TEMP else /tmp, one trailing slash trimmed). + * os.platform() lowers to process.platform — one implementation. */ + "os.homedir": { argTypes: [], result: STRING }, + /** os.release(): uname(2)'s release field — Node's own implementation + * (the kernel version string, e.g. "24.6.0" on macOS 15). Interned; +1 + * per read. Never throws. */ + "os.release": { argTypes: [], result: STRING }, + /** os.type(): uname(2)'s sysname ("Darwin", "Linux"; "Windows_NT" on + * win32) — Node's uv_os_uname answer. Interned per call; never throws. */ + "os.type": { argTypes: [], result: STRING }, + /** os.totalmem(): total physical memory in bytes. Never throws. */ + "os.totalmem": { argTypes: [], result: F64 }, + /** os.availableParallelism(): CPUs the process may use (libuv's answer), >= 1. Never throws. */ + "os.availableParallelism": { argTypes: [], result: F64 }, + /** os.hostname/machine/version/endianness, freemem, uptime and loadavg: + * libuv's answers (uname's machine and version fields, gethostname, + * "LE"/"BE", free memory in bytes, uptime in seconds, the three load + * averages). Fresh results; never throw. */ + "os.hostname": { argTypes: [], result: STRING }, + "os.machine": { argTypes: [], result: STRING }, + "os.version": { argTypes: [], result: STRING }, + "os.endianness": { argTypes: [], result: STRING }, + "os.freemem": { argTypes: [], result: F64 }, + "os.uptime": { argTypes: [], result: F64 }, + "os.loadavg": { argTypes: [], result: arrayOf(F64) }, + /** os.getPriority(pid): validateInt32 (RangeError ERR_OUT_OF_RANGE), + * then the priority; a failure throws Node's SystemError. */ + "os.getPriority": { argTypes: [F64], result: F64 }, + /** os.setPriority(pid, priority): validateInt32 for both (priority in + * -20..19, RangeError ERR_OUT_OF_RANGE), then the priority; a failure + * throws Node's SystemError. */ + "os.setPriority": { argTypes: [F64, F64], result: VOID }, + /** os.cpus(): cpusTake snapshots every CPU and answers the count; + * cpusModel(i) and cpusField(i, k) (k: 0 speed, 1 user, 2 nice, 3 sys, + * 4 idle, 5 irq) read the snapshot. Never throw. */ + "os.cpusTake": { argTypes: [], result: F64 }, + "os.cpusModel": { argTypes: [F64], result: STRING }, + "os.cpusField": { argTypes: [F64, F64], result: F64 }, + /** os.constants: the per-thread null-prototype constants object (dlopen, + * errno, signals, priority, UV_UDP_REUSEADDR). Never throws. */ + "os.constants": { argTypes: [], result: DYN }, + /** fs.constants: the target's cached null-prototype constants object. */ + "fs.constants": { argTypes: [], result: DYN }, + /** The deprecated node:constants object (scr_os.c): the os groups and + * fs.constants merged with the borrowed baked crypto.constants table, + * frozen, one per thread. */ + "constants.object": { argTypes: [DYN], result: DYN }, + /** umask(2): arg < 0 reads without setting (umask has no read-only form + * — set 0, restore); otherwise sets and answers the PREVIOUS mask. + * Never throws. */ + "process.umask": { argTypes: [F64], result: F64 }, + /** chdir(2) — throws Node's fs-shaped error (ENOENT/EACCES/ENOTDIR, + * syscall "chdir") on failure. */ + "process.chdir": { argTypes: [STRING], result: VOID }, + "process.loadEnvFile": { argTypes: [DYN], result: VOID }, + /** process._exiting: true once the exit sequence began (exit listeners + * running) — the runtime flag scr_run_exit_listeners/process.exit set. + * Never throws. */ + "process.exiting": { argTypes: [], result: BOOL }, + /** net's process-wide happy-eyeballs attempt budget (Node's default + * 250ms): one runtime double in the core unit, so reading/writing it + * never forces the net unit into the link. Never throw. */ + "net.getAutoSelTimeout": { argTypes: [], result: F64 }, + "net.setAutoSelTimeout": { argTypes: [F64], result: VOID }, + /** realpath(3) with Node's error shape (syscall "lstat" in the message, + * Node's own spelling for realpathSync failures). +1 fresh string. */ + "fs.realpathSync": { argTypes: [STRING], result: STRING }, + /** fs.realpathSync (or its .native when the flag is true) as a function + * value: path and options arrive unchecked; the result is a string or a + * Buffer by the options' encoding. */ + "fs.realpathValue": { argTypes: [DYN, DYN, BOOL], result: DYN }, + /** Native realpath with syscall "realpath" on failure. +1 fresh string. */ + "fs.realpathNativeSync": { argTypes: [STRING], result: STRING }, + /** The os.userInfo() field trio (uv_os_get_passwd's slices): pw_name, + * pw_shell, pw_dir — the PASSWD homedir, not os.homedir's $HOME-first + * cascade (Node's own split). The frontend assembles the UserInfo + * record from these plus getuid/getgid. +1 fresh strings; a passwd + * lookup failure aborts (Node throws a system error there — no + * compiled program path reaches it for the running uid). */ + "os.userName": { argTypes: [], result: STRING }, + "os.userShell": { argTypes: [], result: STRING }, + "os.userHomedir": { argTypes: [], result: STRING }, + "os.tmpdir": { argTypes: [], result: STRING }, + // Result is the call site's Dict record (VOID is + // the dgram.address sentinel — the libCall case checks the structure). + /** os.networkInterfaces(): getifaddrs(3) → the Dict + * record, built inline by the emitter from a runtime snapshot (scr_lib.c). + * The result type is the CALL SITE's mapped @types/node shape — a pure + * index-signature record whose value is `Info[] | undefined`, Info a + * two-record union (IPv4: scopeid `number | undefined` holding undefined; + * IPv6: scopeid number) — verified structurally by the frontend. Rows + * match libuv's filter (IFF_UP && IFF_RUNNING, AF_INET/AF_INET6; loopback + * = internal; MACs from the interface's link-level sibling entry, zeros + * when absent; cidr from the netmask's contiguous prefix, the null arm + * when it is missing or non-contiguous). Key/row order follows the OS's + * getifaddrs enumeration — Node itself does not guarantee an order. + * Fresh +1 record; never throws (a getifaddrs failure yields {}). */ + "os.networkInterfaces": { argTypes: [], result: VOID }, + /** `Math.max(...xs)` / `Math.min(...xs)` over one spread number[] + * (scr_number.c): the JS fold exactly — any NaN element poisons the + * result, ±0 order by the JS comparison (max prefers +0, min prefers + * -0), and the empty array yields -Infinity / +Infinity like the + * zero-argument calls. Borrows the array; never throws. */ + "math.maxArr": { argTypes: [arrayOf(F64)], result: F64 }, + "math.minArr": { argTypes: [arrayOf(F64)], result: F64 }, + "math.hypotArr": { argTypes: [arrayOf(F64)], result: F64 }, + /** `Math.floor(x)` — C floor() IS the JS operation (NaN/±0/±Infinity + * pass through bit-exactly). Never throws. */ + "math.floor": { argTypes: [F64], result: F64 }, + /** Math.abs (C fabs — IS the JS operation) and Math.round (scr_lib.c: + * ECMA half-toward-+Infinity with the exact-fraction comparison — C + * round() is half-away-from-zero and floor(x+0.5) drifts at the + * epsilon boundary). Borrow nothing; never throw. */ + "math.abs": { argTypes: [F64], result: F64 }, + "math.round": { argTypes: [F64], result: F64 }, - "math.trunc": { argTypes: [F64], result: F64 }, - "math.ceil": { argTypes: [F64], result: F64 }, - "math.sin": { argTypes: [F64], result: F64 }, - "math.sinh": { argTypes: [F64], result: F64 }, - "math.cos": { argTypes: [F64], result: F64 }, - "math.cosh": { argTypes: [F64], result: F64 }, - "math.tan": { argTypes: [F64], result: F64 }, - "math.tanh": { argTypes: [F64], result: F64 }, - "math.asin": { argTypes: [F64], result: F64 }, - "math.asinh": { argTypes: [F64], result: F64 }, - "math.acos": { argTypes: [F64], result: F64 }, - "math.acosh": { argTypes: [F64], result: F64 }, - "math.atan": { argTypes: [F64], result: F64 }, - "math.atanh": { argTypes: [F64], result: F64 }, - "math.cbrt": { argTypes: [F64], result: F64 }, - "math.clz32": { argTypes: [F64], result: F64 }, - /** Return -1, +1, or the original NaN/zero. In particular, -0 remains -0. */ - "math.sign": { argTypes: [F64], result: F64 }, - "math.exp": { argTypes: [F64], result: F64 }, - "math.expm1": { argTypes: [F64], result: F64 }, - "math.f16round": { argTypes: [F64], result: F64 }, - "math.fround": { argTypes: [F64], result: F64 }, - "math.sqrt": { argTypes: [F64], result: F64 }, - "math.log": { argTypes: [F64], result: F64 }, - "math.log1p": { argTypes: [F64], result: F64 }, - "math.log2": { argTypes: [F64], result: F64 }, - "math.log10": { argTypes: [F64], result: F64 }, - "math.atan2": { argTypes: [F64, F64], result: F64 }, - "math.pow": { argTypes: [F64, F64], result: F64 }, - "math.imul": { argTypes: [F64, F64], result: F64 }, - /** `Math.min(a, b)` / `Math.max(a, b)` — the two-argument scalar forms - * (scr_lib.c), JS-exact like the Arr folds: NaN poisons, max prefers +0 - * over -0 (min the reverse). C fmin/fmax are NOT these (they drop NaN). - * Never throw. */ - "math.min": { argTypes: [F64, F64], result: F64 }, - "math.max": { argTypes: [F64, F64], result: F64 }, - /** `Math.random()` — a uniform double in [0,1) with the spec's 53-bit - * granularity, drawn from arc4random_buf (the CSPRNG behind the crypto - * lowerings). Same distribution as Node, NECESSARILY different sequence - * (SEMANTICS.md 62 — no seeded sequence exists to match). Never throws. */ - "math.random": { argTypes: [], result: F64 }, - /** The static global parsers/tests (scr_string.c). num.parseInt is - * ECMA-262 19.2.5 exactly — JS whitespace, sign, ToInt32 radix (the - * frontend completes an omitted radix to 0 = the spec's "undefined": - * base 10 with the 0x hex escape), longest digit prefix, and the exact - * mathematical value correctly rounded (u64 fast path, bignum beyond — - * overflow is ±Infinity). num.isNaN is the NaN self-test on an - * already-number argument (tsc pins the argument to number, so no - * ToNumber coercion exists to model). Borrow; never throw. */ - "num.parseInt": { argTypes: [STRING, F64], result: F64 }, - /** ES parseFloat (scr_string.c): the longest StrDecimalLiteral prefix - * of the trimmed input (no hex, "Infinity" exact-case), NaN when none — - * ECMA-262 19.2.4 over a string argument (non-string arguments keep the - * fence: Node would ToNumber-coerce). Borrows; never throws. */ - "num.parseFloat": { argTypes: [STRING], result: F64 }, - /** `a.localeCompare(b)`: -1/0/1 in Node's root-locale collation for - * Latin-script text (scr_str_locale_compare). Never throws. */ - "str.localeCompare": { argTypes: [STRING, STRING], result: F64 }, - /** Annex B substr(start, length) with start ToNumber'd and length's - * presence; never throws. */ - "str.substr": { argTypes: [STRING, F64, F64, BOOL], result: STRING }, - /** toLocaleLowerCase/toLocaleUpperCase (scr_regex.c): the locales value - * as written, upper=true for toLocaleUpperCase. Throws for null and for - * locale forms with no native rules. */ - "str.localeCase": { argTypes: [STRING, DYN, BOOL], result: STRING }, - "str.replaceLiteral": { argTypes: [STRING, STRING, STRING, BOOL], result: STRING }, - // (subject, characters, NUL-separated replacement texts): the fused - // chain of global one-character replacements. - "str.replaceChars": { argTypes: [STRING, STRING, STRING], result: STRING }, - /* ToNumber(string) — ECMA-262 7.1.4.1 StringToNumber (scr_string.c): - * trim the JS StrWhiteSpace set, empty/whitespace-only → +0, then the - * whole span must be one StrNumericLiteral — signed decimal (Infinity - * included, strtod-over-validated-span correct rounding) or unsigned - * 0x/0o/0b (exact value, nearest-even; signed forms are NaN) — with - * any trailing garbage answering NaN. Number(aString), unary + on - * strings, and util.format %d over strings lower here. Borrows; never - * throws. */ - "num.fromString": { argTypes: [STRING], result: F64 }, - "num.isNaN": { argTypes: [F64], result: BOOL }, - /** The static URI component codecs (scr_string.c), ECMA-262 Encode/ - * Decode with the component sets over the runtime's UTF-8 strings. - * str.encodeUriComponent percent-encodes every byte outside the - * unreserved component set (ALPHA/DIGIT/- _ . ! ~ * ' ( )) as uppercase - * %XX — the spec's per-code-point UTF-8 encoding IS a byte scan here — - * and THROWS the spec's URIError ("URI malformed") on a lone surrogate. - * str.decodeUriComponent - * decodes %XX escapes bytewise (raw non-escape bytes copy through) and - * requires the escaped bytes to form strictly valid UTF-8 (overlong - * forms, surrogate code points, and >U+10FFFF refused, per UTF8-decode - * without replacement); bad hex or an invalid sequence THROWS the - * spec's URIError ("URI malformed"), catchable. Borrow; results +1. */ - "str.encodeUriComponent": { argTypes: [STRING], result: STRING }, - // The base64 globals: the argument is a dyn value (WebIDL ToString - // runs in the runtime); the zero-argument form always throws. - /** The WHATWG base64 globals (scr_string.c), Node-global since v16. - * Arguments are borrowed dyn values — WebIDL ToString runs in the - * runtime over the dyn kind (String(null) is "null": the html spec's - * coercion, which Node's atob(null) exercises). str.atob decodes - * forgiving-base64 (ASCII whitespace stripped, %4==0 strips up to two - * '=', %4==1 refuses, leftover bits discarded) into the latin1 code - * points as a string; a malformed input THROWS the catchable - * DOMException InvalidCharacterError ("The string to be decoded is not - * correctly encoded."). str.btoa encodes the string's code points as - * base64; any code point over U+00FF THROWS InvalidCharacterError - * ("Invalid character"). str.b64Missing is the zero-argument call of - * either: always throws Node's TypeError [ERR_MISSING_ARGS] "The - * \"input\" argument must be specified". Results +1. */ - "str.atob": { argTypes: [DYN], result: STRING }, - "str.btoa": { argTypes: [DYN], result: STRING }, - "str.b64Missing": { argTypes: [], result: STRING }, - "str.decodeUriComponent": { argTypes: [STRING], result: STRING }, - "str.decodeUri": { argTypes: [STRING], result: STRING }, - /** encodeURI: the same Encode() keeping the reserved set and '#' - * unescaped — throwing like the component encoder. Borrow; result +1. */ - "str.encodeUri": { argTypes: [STRING], result: STRING }, - /** RegExp.escape (ES2025): per-code-point EncodeForRegExpEscape — - * leading ASCII alphanumeric hex-escapes, syntax characters and '/' - * take a backslash, other punctuators/whitespace/line terminators - * hex-escape, the rest passes through. Total; borrows; result +1. */ - "regexp.escape": { argTypes: [STRING], result: STRING }, - /** Number.prototype formatters (scr_lib.c), JS-exact: - * num.toExponential is toExponential() with the spec's "as many digits - * as necessary"; num.toFixed0 is the non-throwing omitted-argument - * toFixed() fast path; num.toFixed implements an explicit fractionDigits - * with exact binary-value rounding and THROWS RangeError outside 0..100. - * Successful results +1. */ - "num.toExponential": { argTypes: [F64], result: STRING }, - "num.toFixed0": { argTypes: [F64], result: STRING }, - "num.toFixed": { argTypes: [F64, F64], result: STRING }, - /** toPrecision(precision) with the argument ToNumber'd and its presence - * (undefined answers ToString); toExponential with a DEFINED - * fractionDigits. Both throw V8's RangeError for out-of-range digits. */ - "num.toPrecision": { argTypes: [F64, F64, BOOL], result: STRING }, - "num.toExponentialDigits": { argTypes: [F64, F64], result: STRING }, - "num.toStringRadix": { argTypes: [F64, DYN], result: STRING }, - /** toString(radix) with a number radix (scr_lib.c): truncates it as - * ToIntegerOrInfinity does, THROWS RangeError outside 2..36. */ - "num.toStringRadixF64": { argTypes: [F64, F64], result: STRING }, - /** Object.is over two numbers — the spec's SameValue on doubles: NaN - * equals NaN, +0 differs from -0, everything else is `===`. Plain bool - * result; never throws. (Union-armed operands take unionEq's sameValue - * flag instead — this is the both-f64 fast path.) */ - "num.sameValue": { argTypes: [F64, F64], result: BOOL }, - /** `new Intl.NumberFormat("en-US").format(x)` and - * `x.toLocaleString("en-US")` with DEFAULT options — the one locale - * whose data the runtime embeds (Node's default-build locale): decimal - * notation, 0–3 fraction digits rounded half-up on the SHORTEST - * round-tripping decimal (ICU's rounding input, probed vs Node — - * format(1.0005) is "1.001" though toFixed(3) answers "1.000"), "," - * grouping every three integer digits, "∞"/"NaN" texts, and "-0" for - * negative inputs rounding to zero. Result +1; never throws. */ - "intl.numFormatEnUs": { argTypes: [F64], result: STRING }, - /** ES Symbol values (scr_symbol.c — link-gated by moduleUsesSymbol). - * sym.new: `Symbol(desc)` — a fresh runtime-unique identity (+1) whose - * one arg is the description string (borrowed); sym.newAnon is the - * description-less `Symbol()` form. sym.for: the Symbol.for global - * registry — one interned symbol per key (borrowed), +1 on every call. - * sym.toString: "Symbol(desc)" (+1 string; "Symbol()" when absent). - * sym.desc / sym.keyFor answer the interned `string | undefined` union - * (the runtime returns +1-or-NULL; the backend builds the union arms — - * the child.stdout pattern). None of these throw. */ - "sym.new": { argTypes: [STRING], result: SYMBOL_T }, - "sym.newAnon": { argTypes: [], result: SYMBOL_T }, - "sym.for": { argTypes: [STRING], result: SYMBOL_T }, - "sym.wellKnown": { argTypes: [STRING], result: SYMBOL_T }, - // Result is the interned `string | undefined` union — the libCall case - // checks the arms (the spawnRes.error pattern). - "sym.keyFor": { argTypes: [SYMBOL_T], result: VOID }, - "sym.desc": { argTypes: [SYMBOL_T], result: VOID }, - "sym.toString": { argTypes: [SYMBOL_T], result: STRING }, - /** Engine-free arbitrary-precision bigint operations (scr_bigint.c). - * parse accepts the ECMAScript BigInt string grammar; fromF64 accepts - * finite integral Numbers. Arithmetic returns fresh immutable values. - * cmp returns -1/0/1 as f64; toString accepts a numeric radix. */ - "bigint.parse": { argTypes: [STRING], result: BIGINT_T }, - "bigint.fromF64": { argTypes: [F64], result: BIGINT_T }, - "bigint.neg": { argTypes: [BIGINT_T], result: BIGINT_T }, - "bigint.not": { argTypes: [BIGINT_T], result: BIGINT_T }, - "bigint.add": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, - "bigint.sub": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, - "bigint.mul": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, - "bigint.div": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, - "bigint.mod": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, - "bigint.pow": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, - "bigint.and": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, - "bigint.or": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, - "bigint.xor": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, - "bigint.shl": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, - "bigint.shr": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, - "bigint.eq": { argTypes: [BIGINT_T, BIGINT_T], result: BOOL }, - "bigint.eqString": { argTypes: [BIGINT_T, STRING], result: BOOL }, - "bigint.cmp": { argTypes: [BIGINT_T, BIGINT_T], result: F64 }, - "bigint.cmpNumber": { argTypes: [BIGINT_T, F64], result: F64 }, - "bigint.truthy": { argTypes: [BIGINT_T], result: BOOL }, - "bigint.toString": { argTypes: [BIGINT_T, F64], result: STRING }, - "bigint.inspect": { argTypes: [BIGINT_T], result: STRING }, - "bigint.toF64": { argTypes: [BIGINT_T], result: F64 }, - "bigint.asUintN": { argTypes: [F64, BIGINT_T], result: BIGINT_T }, - "bigint.asIntN": { argTypes: [F64, BIGINT_T], result: BIGINT_T }, - "bigint.bufferRead": { argTypes: [BYTES_U8, F64, BOOL, BOOL], result: BIGINT_T }, - "bigint.bufferWrite": { argTypes: [BYTES_U8, BIGINT_T, F64, BOOL, BOOL], result: F64 }, - "bigint.dataViewGet": { argTypes: [BYTES_U8, F64, BOOL, BOOL], result: BIGINT_T }, - "bigint.dataViewSet": { argTypes: [BYTES_U8, F64, BIGINT_T, BOOL], result: VOID }, - /** node:url + the URL class (scr_url.c). url.new parses one absolute - * URL string into a mutable URL value (+1) — invalid input THROWS a - * catchable TypeError ("Invalid URL"), like Node's constructor. The - * getters (borrowed receiver, +1 string) never throw; url.href doubles - * as toString(). fileURLToPath has one libFn per receiver form (URL - * value / string) — both THROW Node's TypeErrors on non-file schemes, - * encoded slashes, and non-empty hosts. url.pathToFileURL resolves the - * path (getcwd) and never throws. */ - "url.new": { argTypes: [STRING], result: URL_T }, - "url.newBase": { argTypes: [STRING, STRING], result: URL_T }, - /** Factories consume already-converted input/base strings. canParse - * answers a boolean; parse returns a checked native URL or null (+1). - * Parser failures are suppressed; conversion occurs before these calls. */ - "url.canParse": { argTypes: [STRING], result: BOOL }, - "url.canParseBase": { argTypes: [STRING, STRING], result: BOOL }, - "url.parse": { argTypes: [STRING], result: DYN }, - "url.parseBase": { argTypes: [STRING, STRING], result: DYN }, - "url.protocol": { argTypes: [URL_T], result: STRING }, - "url.origin": { argTypes: [URL_T], result: STRING }, - "url.username": { argTypes: [URL_T], result: STRING }, - "url.password": { argTypes: [URL_T], result: STRING }, - "url.host": { argTypes: [URL_T], result: STRING }, - "url.hostname": { argTypes: [URL_T], result: STRING }, - "url.port": { argTypes: [URL_T], result: STRING }, - "url.pathname": { argTypes: [URL_T], result: STRING }, - "url.href": { argTypes: [URL_T], result: STRING }, - /** Selected component writes borrow the receiver and converted string. - * href replaces its parsed fields while retaining cached params identity. */ - "url.set": { argTypes: [URL_T, STRING, STRING], result: VOID }, - "url.setChecked": { argTypes: [URL_T, STRING, DYN], result: VOID }, - "url.fileURLToPathUrl": { argTypes: [URL_T], result: STRING }, - /** fileURLToPathUrl as a value: the path string, or the error it would - * throw (fs.existsSync and fs.promises URL paths). Never throws. */ - "url.fileURLToPathValue": { argTypes: [URL_T], result: DYN }, - /** getValidatedPath's null-byte check on a string path, and - * readFileSync's encoding check: what Node validates before it converts - * a later URL path. (path, argument name) and (encoding). */ - "fs.checkPath": { argTypes: [STRING, STRING], result: VOID }, - "fs.checkReadEncoding": { argTypes: [STRING], result: VOID }, - "url.fileURLToPathChecked": { argTypes: [DYN], result: STRING }, - "url.fileURLToPathOptions": { argTypes: [DYN, DYN], result: STRING }, - /** node:url's legacy API (scr_url_legacy.c): parse(url, parseQueryString, - * slashesDenoteHost) answers the checked-dynamic Url instance; format - * takes the urlObject (a Url-shaped object, a string, or a URL) and the - * URL form's options; resolve takes (from, to). The trailing bool says - * whether the call site emits DEP0169. domainToASCII/domainToUnicode - * take the domain and whether it was omitted. Node's validation errors - * throw catchably. */ - "url.legacyParse": { argTypes: [DYN, DYN, DYN, BOOL], result: DYN }, - "url.legacyFormat": { argTypes: [DYN, DYN, BOOL], result: STRING }, - "url.legacyResolve": { argTypes: [DYN, DYN, BOOL], result: STRING }, - "url.domainToASCII": { argTypes: [DYN, BOOL], result: STRING }, - "url.domainToUnicode": { argTypes: [DYN, BOOL], result: STRING }, - /** url.urlToHttpOptions over a checked-dynamic argument: a URL answers - * Node's null-prototype options object; a primitive or null throws - * ERR_INVALID_ARG_TYPE. */ - "url.toHttpOptions": { argTypes: [DYN], result: DYN }, - /** node:punycode (scr_url.c): punycode.js 2.1.0's string conversions; - * decode/toUnicode (and, past 32-bit deltas, encode/toASCII) throw the - * module's RangeErrors, ucs2Encode String.fromCodePoint's. warn marks the - * module's first load (scr_async_dyn.c) and reports DEP0040 then unless - * the second argument is false: at once for a static ES import, on the - * next tick for a require() call. */ - "punycode.decode": { argTypes: [STRING], result: STRING }, - "punycode.encode": { argTypes: [STRING], result: STRING }, - "punycode.toASCII": { argTypes: [STRING], result: STRING }, - "punycode.toUnicode": { argTypes: [STRING], result: STRING }, - "punycode.ucs2Decode": { argTypes: [STRING], result: arrayOf(F64) }, - "punycode.ucs2Encode": { argTypes: [arrayOf(F64)], result: STRING }, - "punycode.warn": { argTypes: [BOOL, BOOL], result: VOID }, - "url.fileURLToPathBuffer": { argTypes: [DYN, DYN], result: BYTES_U8 }, - "url.pathToFileURLChecked": { argTypes: [DYN, DYN], result: URL_T }, - "url.fileURLToPathStr": { argTypes: [STRING], result: STRING }, - "url.pathToFileURL": { argTypes: [STRING], result: URL_T }, - /** Explicit path syntax from the options.windows argument, independent - * of the executable's host platform. Windows UNC input can throw. */ - "url.pathToFileURLPlatform": { argTypes: [STRING, BOOL], result: URL_T }, - /** pathToFileURL under a win32 TARGET: the same scr_url_from_path call - * (the runtime selects the win32 arm by _WIN32), but a distinct IR name - * because that arm THROWS for malformed UNC inputs — may-throw seeds on - * it while posix pathToFileURL emission stays byte-identical. */ - "url.pathToFileURLWin32": { argTypes: [STRING], result: URL_T }, - /** URLSearchParams (scr_url.c — always linked with the url unit). - * Construction: sp.new (empty), sp.parse (one borrowed init string — - * a single leading '?' strips, Node's constructor), sp.copy (snapshot - * of another list), sp.fromPairs (a string[][] value — THROWS Node's - * ERR_INVALID_TUPLE TypeError on a non-[name, value] row; the one - * throwing entry in the family), sp.with (the record-literal init - * desugar: append one pair, answer the same list +1 — chains fold - * `new URLSearchParams({...})` into nested calls). url.searchParams - * answers the URL's LIVE cached view (+1, one identity per URL); - * url.search is the WHATWG search getter ("" for no/empty query). - * Methods mirror the WHATWG surface: sp.get answers +1-or-NULL (the - * sym.desc union pattern, null arm), sp.getAll a fresh string[]; - * sp.append/sp.set/sp.delete/sp.deleteValue/sp.sort mutate and - * re-serialize a live view's URL query; sp.has/sp.hasValue answer - * bools; sp.size/sp.toString are pure reads. sp.keyAt/sp.valAt are - * the for-of/forEach desugar's index reads (live — the loop re-reads - * sp.size each pass). */ - "sp.new": { argTypes: [], result: SEARCH_PARAMS_T }, - "sp.newChecked": { argTypes: [DYN], result: SEARCH_PARAMS_T }, - "sp.parse": { argTypes: [STRING], result: SEARCH_PARAMS_T }, - "sp.copy": { argTypes: [SEARCH_PARAMS_T], result: SEARCH_PARAMS_T }, - // The pairs argument is string[][] — checked structurally in validate.ts (the - // generic array-of slot has no named constant here). - "sp.fromPairs": { argTypes: [null], result: SEARCH_PARAMS_T }, - "sp.with": { argTypes: [SEARCH_PARAMS_T, STRING, STRING], result: SEARCH_PARAMS_T }, - "url.searchParams": { argTypes: [URL_T], result: SEARCH_PARAMS_T }, - "url.search": { argTypes: [URL_T], result: STRING }, - "url.hash": { argTypes: [URL_T], result: STRING }, - // Result is the interned `string | null` union — the libCall case - // checks the arms (the spawnRes.signal pattern). - "sp.get": { argTypes: [SEARCH_PARAMS_T, STRING], result: VOID }, - "sp.getAll": { argTypes: [SEARCH_PARAMS_T, STRING], result: arrayOf(STRING) }, - "sp.append": { argTypes: [SEARCH_PARAMS_T, STRING, STRING], result: VOID }, - "sp.set": { argTypes: [SEARCH_PARAMS_T, STRING, STRING], result: VOID }, - "sp.delete": { argTypes: [SEARCH_PARAMS_T, STRING], result: VOID }, - "sp.deleteValue": { argTypes: [SEARCH_PARAMS_T, STRING, STRING], result: VOID }, - "sp.has": { argTypes: [SEARCH_PARAMS_T, STRING], result: BOOL }, - "sp.hasValue": { argTypes: [SEARCH_PARAMS_T, STRING, STRING], result: BOOL }, - "sp.sort": { argTypes: [SEARCH_PARAMS_T], result: VOID }, - "sp.size": { argTypes: [SEARCH_PARAMS_T], result: F64 }, - "sp.toString": { argTypes: [SEARCH_PARAMS_T], result: STRING }, - "sp.keyAt": { argTypes: [SEARCH_PARAMS_T, F64], result: STRING }, - "sp.valAt": { argTypes: [SEARCH_PARAMS_T, F64], result: STRING }, - // node:querystring. qs.parse's result is the call site's ParsedUrlQuery - // dictionary record (VOID is the networkInterfaces sentinel — the - // libCall case checks the structure); qs.stringify's object argument - // is a dyn value (the frontend dynFroms typed records). - /** node:querystring (scr_qs.c — link-gated by moduleUsesQs; NOT - * URLSearchParams: the legacy codec's escaping and '+' rules differ). - * qs.escape is Node's qsEscape, which encodes exactly the component - * unreserved set — it emits the always-linked scr_qs_escape, so - * escape-only programs never pull the unit. qs.unescape is Node's qsUnescape: strict decodeURIComponent - * first, the lenient legacy unescapeBuffer fallback on failure (never - * throws). qs.parse takes (str, sep, eq, maxKeys) — the frontend - * completes omitted/null sep/eq to "&"/"=" and the omitted maxKeys - * option to Node's 1000 (0 and negatives mean unlimited, Node's rule) — - * and its result type is the CALL SITE's mapped ParsedUrlQuery shape (a - * pure index-signature record over `string | string[]`, an undefined - * arm tolerated — @types/node's Dict), verified structurally by the - * frontend (lowerQuerystringParseCall); the emitters construct the - * record and hand its overflow map to scr_qs_parse_into with the two - * union tags. qs.stringify takes (obj, sep, eq) with obj a dyn value - * (the frontend dynFroms the typed record; JS-world dyn values pass - * through) — Node's encodeStringified rules run in the runtime, so - * arrays expand to repeated keys and null/undefined/nested objects are - * empty values. Custom encoder/decoder options fence at compile time. - * All borrow; string results +1; escape and stringify throw URIError - * [ERR_INVALID_URI] on a lone surrogate. */ - "qs.parse": { argTypes: [STRING, STRING, STRING, F64], result: VOID }, - "qs.stringify": { argTypes: [DYN, STRING, STRING], result: STRING }, - "qs.escape": { argTypes: [STRING], result: STRING }, - "qs.unescape": { argTypes: [STRING], result: STRING }, - /** node:util.parseArgs: one checked-dynamic config object in, one - * checked-dynamic ParsedResults tree out. Statically typed member reads - * validate their values when leaving that tree. The native parser may - * throw Node's coded validation/grammar TypeErrors. */ - "util.parseArgs": { argTypes: [DYN], result: DYN }, - "util.parseEnv": { argTypes: [DYN], result: DYN }, - "util.getSystemErrorName": { argTypes: [DYN], result: STRING }, - "util.getSystemErrorMessage": { argTypes: [DYN], result: STRING }, - "util.systemErrorEntries": { argTypes: [], result: DYN }, - "util.stripVTControlCharacters": { argTypes: [DYN], result: STRING }, - "util.toUSVString": { argTypes: [DYN], result: STRING }, - "util.isDeepStrictEqual": { argTypes: [DYN, DYN, DYN], result: BOOL }, - "util.styleText": { argTypes: [DYN, DYN, DYN], result: STRING }, - /** util.inherits/deprecate/callbackify/debuglog over checked-dynamic - * arguments (scr_util_callable.c). The function results are native dyn - * wrappers; call sites with a static function type check them back. */ - "util.inherits": { argTypes: [DYN, DYN], result: VOID }, - "util.inheritsPrototype": { argTypes: [DYN, DYN, DYN], result: VOID }, - "util.deprecate": { argTypes: [DYN, DYN, DYN, DYN], result: DYN }, - "util.callbackify": { argTypes: [DYN], result: DYN }, - /** util.promisify over an untyped function value: a native dyn function - * whose calls answer a dyn promise the appended callback settles. */ - "util.promisifyDyn": { argTypes: [DYN], result: DYN }, - "util.debuglog": { argTypes: [DYN, DYN], result: DYN }, - "util.typeIs": { argTypes: [DYN, STRING], result: BOOL }, - "util.typeValue": { argTypes: [DYN, STRING], result: DYN }, - /** fs.statSync → a Stats value (may throw, like the other sync fs - * calls); the stats.* getters are pure reads on it. */ - "fs.statSync": { argTypes: [STRING], result: STATS_T }, - "fs.lstatSync": { argTypes: [STRING], result: STATS_T }, - // statSync / lstatSync(path, { throwIfNoEntry }): arg 1 is the flag. - // Result is the interned `Stats | undefined` union (the runtime answers - // +1-or-NULL; the backend builds the arms). - "fs.statProbeSync": { argTypes: [STRING, BOOL], result: VOID }, - "fs.lstatProbeSync": { argTypes: [STRING, BOOL], result: VOID }, - "fs.fstatSync": { argTypes: [F64], result: STATS_T }, - "fs.fchmodSync": { argTypes: [F64, F64], result: VOID }, - "fs.fsyncSync": { argTypes: [F64], result: VOID }, - "fs.fdatasyncSync": { argTypes: [F64], result: VOID }, - "fs.ftruncateSync": { argTypes: [F64, F64], result: VOID }, - "fs.utimesSync": { argTypes: [DYN, DYN, DYN], result: VOID }, - "fs.futimesSync": { argTypes: [DYN, DYN, DYN], result: VOID }, - "fs.lutimesSync": { argTypes: [DYN, DYN, DYN], result: VOID }, - "fs.readvSync": { argTypes: [F64, arrayOf(BYTES_U8), F64], result: F64 }, - "fs.writevSync": { argTypes: [F64, arrayOf(BYTES_U8), F64], result: F64 }, - "fs.linkSync": { argTypes: [DYN, DYN], result: VOID }, - "fs.symlinkSync": { argTypes: [DYN, DYN, DYN], result: VOID }, - /** fs.cpSync / fs/promises cp (scr_fs_cp.c): src, dest and options are - * dyn values the runtime validates in Node's order. */ - "fs.cpSync": { argTypes: [DYN, DYN, DYN], result: VOID }, - "fs.readlinkSync": { argTypes: [DYN, DYN], result: DYN }, - "fs.statfsSync": { argTypes: [DYN, DYN], result: DYN }, - "fs.readlinkSyncStr": { argTypes: [DYN, DYN], result: STRING }, - "fs.readlinkSyncBuffer": { argTypes: [DYN, DYN], result: BYTES_U8 }, - /** fs.openSync(path, flags) → the raw fd as f64; fs.readSync/fs.writeSync - * over Buffer windows perform sequential I/O when position is -1 and - * offset-preserving positioned I/O otherwise; fs.writeStrSync is the - * utf8 string twin; and fs.closeSync(fd) closes the descriptor. This is - * the fd slice behind spawn/log-processing forms. - * flags is Node's string - * grammar ("r", "w", "a" and the +/x variants; unknown flags throw - * Node's ERR_INVALID_ARG_VALUE TypeError text). All throw Node-shaped - * fs errors (openSync ENOENT/EACCES..., readSync EBADF/range errors, - * closeSync EBADF). */ - "fs.openSync": { argTypes: [STRING, STRING], result: F64 }, - "fs.openNumericSync": { argTypes: [STRING, F64, F64], result: F64 }, - "fs.readSync": { argTypes: [F64, BYTES_U8, F64, F64, F64], result: F64 }, - "fs.readSyncDyn": { argTypes: [DYN, DYN, DYN, DYN, DYN], result: F64 }, - "fs.writeSync": { argTypes: [F64, BYTES_U8, F64, F64, F64], result: F64 }, - "fs.writeStrSync": { argTypes: [F64, STRING, F64, STRING], result: F64 }, - // fs.watch's callback func type is program-dependent (zero params, or - // the eventType string) — the slot pins arity and the path/receiver. - /** fs.watch(path, listener?) → an FSWatcher handle (scr_watch.c — - * linked, and scr_watch_install() emitted, only when these appear on - * the IR; moduleUsesFsWatch is the switch). The path opens NOW — - * failure throws Node's fs error synchronously ("ENOENT: ..., watch - * 'x'", the polling-fallback catch shape) — and the unit's kqueue - * (EVFILT_VNODE) delivers "rename"/"change" through the loop's watch - * hook. The callback (nullable) MOVES in with an adapter per listener - * shape (zero-param, or the (eventType: string) form — runtime- - * provided); an open watcher keeps the loop alive until watcher.close() - * (idempotent, receiver borrowed, statement position only). */ - "fs.watch": { argTypes: [STRING], result: FSWATCHER_T }, - "fs.watchCb": { argTypes: [STRING, null], result: FSWATCHER_T }, - "watcher.close": { argTypes: [FSWATCHER_T], result: VOID }, - /** The composed `new crypto.X509Certificate(data).fingerprint` read - * (scr_lib.c — no certificate handle exists): the SHA-1 of the DER, - * uppercase colon-separated, over PEM or raw-DER Buffer input; other - * inputs throw Node's ERR_OSSL_PEM_NO_START_LINE Error (may-throw). */ - "crypto.x509Fingerprint": { argTypes: [BYTES_U8], result: STRING }, - "crypto.x509FingerprintStr": { argTypes: [STRING], result: STRING }, - /** The certificate's Validity window (validFrom / validTo reads — - * scr_lib.c's minimal ASN.1 walk to the TBSCertificate validity - * SEQUENCE): UTCTime and GeneralizedTime render in Node's exact - * ASN1_TIME_print shape ("Jul 1 00:00:00 2026 GMT" — %2d space-padded - * day). Same input contract and PEM error as the fingerprint pair - * (may-throw). */ - "crypto.x509ValidFrom": { argTypes: [BYTES_U8], result: STRING }, - "crypto.x509ValidFromStr": { argTypes: [STRING], result: STRING }, - "crypto.x509ValidTo": { argTypes: [BYTES_U8], result: STRING }, - "crypto.x509ValidToStr": { argTypes: [STRING], result: STRING }, - /** The certificate's DER as a fresh Buffer (the raw field), decoded - * once from the constructor's input; the same PEM error (may-throw). */ - "crypto.x509Raw": { argTypes: [BYTES_U8], result: BYTES_U8 }, - "crypto.x509RawDer": { argTypes: [BYTES_U8], result: BYTES_U8 }, - "crypto.x509RawStr": { argTypes: [STRING], result: BYTES_U8 }, - /** The remaining X509Certificate fields over that DER, in Node's - * renderings (scr_lib.c). subjectAltName, infoAccess and - * signatureAlgorithm answer "" where Node answers undefined. Borrowed; - * never throw. */ - "crypto.x509Subject": { argTypes: [BYTES_U8], result: STRING }, - "crypto.x509Issuer": { argTypes: [BYTES_U8], result: STRING }, - "crypto.x509SubjectAltName": { argTypes: [BYTES_U8], result: STRING }, - "crypto.x509InfoAccess": { argTypes: [BYTES_U8], result: STRING }, - "crypto.x509SerialNumber": { argTypes: [BYTES_U8], result: STRING }, - "crypto.x509Fingerprint256": { argTypes: [BYTES_U8], result: STRING }, - "crypto.x509Fingerprint512": { argTypes: [BYTES_U8], result: STRING }, - "crypto.x509Ca": { argTypes: [BYTES_U8], result: BOOL }, - "crypto.x509SignatureAlgorithm": { argTypes: [BYTES_U8], result: STRING }, - "crypto.x509SignatureAlgorithmOid": { argTypes: [BYTES_U8], result: STRING }, - /** X509Certificate methods over its raw DER. checkHost/checkEmail/checkIP - * answer the matching name or "" (undefined), checkIssued compares two - * certificates, x509Pem is toString's PEM (scr_x509.c); publicKey, - * verify and checkPrivateKey read keys (scr_pki.c). */ - "crypto.x509CheckHost": { argTypes: [BYTES_U8, DYN, DYN], result: STRING }, - "crypto.x509CheckEmail": { argTypes: [BYTES_U8, DYN, DYN], result: STRING }, - "crypto.x509CheckIP": { argTypes: [BYTES_U8, DYN, DYN], result: STRING }, - "crypto.x509CheckIssued": { argTypes: [BYTES_U8, BYTES_U8], result: BOOL }, - "crypto.x509LegacyObject": { argTypes: [BYTES_U8], result: DYN }, - "crypto.x509Pem": { argTypes: [BYTES_U8], result: STRING }, - "crypto.x509PublicKey": { argTypes: [BYTES_U8], result: DYN }, - "crypto.x509Verify": { argTypes: [BYTES_U8, DYN], result: BOOL }, - "crypto.x509CheckPrivateKey": { argTypes: [BYTES_U8, DYN], result: BOOL }, - "fs.closeSync": { argTypes: [F64], result: VOID }, - "stats.isFile": { argTypes: [STATS_T], result: BOOL }, - "stats.isDirectory": { argTypes: [STATS_T], result: BOOL }, - "stats.isSymbolicLink": { argTypes: [STATS_T], result: BOOL }, - "stats.size": { argTypes: [STATS_T], result: F64 }, - "stats.dev": { argTypes: [STATS_T], result: F64 }, - "stats.ino": { argTypes: [STATS_T], result: F64 }, - "stats.blocks": { argTypes: [STATS_T], result: F64 }, - "stats.nlink": { argTypes: [STATS_T], result: F64 }, - "stats.atimeMs": { argTypes: [STATS_T], result: F64 }, - "stats.mtimeMs": { argTypes: [STATS_T], result: F64 }, - "stats.ctimeMs": { argTypes: [STATS_T], result: F64 }, - "stats.birthtimeMs": { argTypes: [STATS_T], result: F64 }, - "stats.mode": { argTypes: [STATS_T], result: F64 }, - "stats.uid": { argTypes: [STATS_T], result: F64 }, - "stats.gid": { argTypes: [STATS_T], result: F64 }, - "stats.rdev": { argTypes: [STATS_T], result: F64 }, - "stats.blksize": { argTypes: [STATS_T], result: F64 }, - "stats.isBlockDevice": { argTypes: [STATS_T], result: BOOL }, - "stats.isCharacterDevice": { argTypes: [STATS_T], result: BOOL }, - "stats.isFIFO": { argTypes: [STATS_T], result: BOOL }, - "stats.isSocket": { argTypes: [STATS_T], result: BOOL }, - /** The Date fields: the *Ms value rounded (Node's dateFromMs). */ - "stats.atime": { argTypes: [STATS_T], result: DATE_T }, - "stats.mtime": { argTypes: [STATS_T], result: DATE_T }, - "stats.ctime": { argTypes: [STATS_T], result: DATE_T }, - "stats.birthtime": { argTypes: [STATS_T], result: DATE_T }, - // The wider sync fs slice (unlink/chmod/chown/copyfile and the - // mode-carrying write/mkdir forms). - /** The wider sync fs slice (scr_lib.c), all throwing catchably with - * Node's errno message shapes and `.code` stamped like the rest of - * sync fs. unlink/chmod/chown wrap the syscalls 1:1 (Node reports the - * syscall's own name). copyFileSync copies contents into a fresh (or - * truncated) destination carrying the SOURCE's mode (libuv's - * uv_fs_copyfile behavior); its errors carry BOTH paths — Node's - * "copyfile 'src' -> 'dest'". lstatSync is statSync without following - * a trailing symlink (Node reports lstat); stats.isSymbolicLink / - * stats.dev / ino / blocks / nlink / atimeMs / mtimeMs / ctimeMs are pure reads on the widened - * snapshot (blocks is allocated 512-byte units; the times are milliseconds - * with their sub-second fractions, Node's arithmetic). - * writeFileModeSync is writeFileSync(path, data, { mode }): the mode - * applies at CREATION only (open(2) with O_CREAT, umask applying), - * exactly Node — an existing file keeps its permissions. mkdirModeSync - * / mkdirRecursiveModeSync are the mkdirSync option forms with an - * explicit mode (the recursive walk passes it to every directory it - * creates, like Node's). */ - "fs.unlinkSync": { argTypes: [STRING], result: VOID }, - "fs.chmodSync": { argTypes: [STRING, F64], result: VOID }, - "fs.chownSync": { argTypes: [STRING, F64, F64], result: VOID }, - "fs.lchownSync": { argTypes: [STRING, F64, F64], result: VOID }, - "fs.fchownSync": { argTypes: [F64, F64, F64], result: VOID }, - /** truncateSync opens the path with 'r+', then truncates (len checked and - * clamped like ftruncateSync's) and closes it. */ - "fs.truncateSync": { argTypes: [STRING, F64], result: VOID }, - "fs.copyFileSync": { argTypes: [STRING, STRING], result: VOID }, - /** renameSync is the direct two-path syscall wrapper. renameCb defers - * the operation to the loop and fires a program-shaped Error | null - * callback through a backend-emitted adapter. */ - "fs.renameSync": { argTypes: [STRING, STRING], result: VOID }, - // Callback type is program-dependent (zero params or Error | null). - "fs.renameCb": { argTypes: [STRING, STRING, null], result: VOID }, - "fs.writeFileModeSync": { argTypes: [STRING, STRING, F64], result: VOID }, - "fs.mkdirModeSync": { argTypes: [STRING, F64], result: VOID }, - "fs.mkdirRecursiveModeSync": { argTypes: [STRING, F64], result: VOID }, - "atomics.wait": { argTypes: [bytesOf("i32"), F64, F64, F64], result: STRING }, - "atomics.notify": { argTypes: [bytesOf("i32"), F64, F64], result: F64 }, - "atomics.op": { argTypes: [null, F64, F64, F64, F64], result: F64 }, - "atomics.opDyn": { argTypes: [DYN, F64, F64, F64, F64], result: F64 }, - "atomics.waitDyn": { argTypes: [DYN, F64, F64, F64], result: STRING }, - "atomics.notifyDyn": { argTypes: [DYN, F64, F64], result: F64 }, - "worker.new": { argTypes: [F64, STRING, DYN], result: DYN }, - "worker.isMainThread": { argTypes: [], result: BOOL }, - "worker.threadId": { argTypes: [], result: F64 }, - "worker.root": { argTypes: [], result: F64 }, - "worker.data": { argTypes: [], result: DYN }, - "worker.parentPort": { argTypes: [], result: DYN }, - /** worker_threads.resourceLimits: {} in the main thread; a refusal in a - * worker (scr_worker_events.c). */ - "worker.resourceLimits": { argTypes: [], result: DYN }, - /** worker_threads.threadName: the Worker's name in a worker, "" in the - * main thread (scr_worker.c). */ - "worker.threadName": { argTypes: [], result: DYN }, - /** new MessageChannel() ({ port1, port2 }) and receiveMessageOnPort(port) - * (scr_worker_events.c; the latter may throw). */ - "worker.channel": { argTypes: [], result: DYN }, - "worker.receiveMessageOnPort": { argTypes: [DYN], result: DYN }, - /** setEnvironmentData(key, value) and getEnvironmentData(key) - * (scr_worker_events.c; arguments borrowed). */ - "worker.setEnvironmentData": { argTypes: [DYN, DYN], result: VOID }, - "worker.getEnvironmentData": { argTypes: [DYN], result: DYN }, - /** markAsUntransferable(value) and isMarkedAsUntransferable(value) - * (scr_worker_events.c; the value borrowed). */ - "worker.markUntransferable": { argTypes: [DYN], result: VOID }, - "worker.isMarkedUntransferable": { argTypes: [DYN], result: BOOL }, - /** markAsUncloneable(value) (scr_json.c; the value borrowed). */ - "dyn.markUncloneable": { argTypes: [DYN], result: VOID }, - /** before new Worker() with the stdout or stderr option: links the stream - * unit that worker.stdout and worker.stderr read through (scr_stream.c). */ - "stream.workerStdio": { argTypes: [], result: VOID }, - /** new BroadcastChannel(...args) (scr_worker_events.c; may throw), after - * event.broadcastInstall, which installs its EventTarget side. */ - "worker.broadcastChannel": { argTypes: [DYN], result: DYN }, - "event.broadcastInstall": { argTypes: [], result: VOID }, - /** child_process.spawnSync (scr_child.c): posix_spawn + waitpid + piped - * utf8 capture — cmd borrowed, args one borrowed string[] (the frontend - * completes an omitted list to an empty literal), result an owned (+1) - * spawnRes. NEVER throws: spawn failure (nonexistent binary, EACCES) is - * data, like Node's error property — status null and empty outputs - * (SEMANTICS.md documents the divergence from Node's null stdout). - * The getters are pure reads: status is the interned `number | null` - * union (null = spawn failure or signal death, type-directed - * construction in the backend like process.envGet); stdout/stderr are - * +1 strings. */ - "cp.spawnSync": { argTypes: [STRING, arrayOf(STRING)], result: SPAWNRES_T }, - // spawnSync's options form: timeout, killSignal name ("" = SIGTERM), - // and the three stdio modes. - /** spawnSync with options (scr_child.c): the cp.spawnSync core plus the - * option slice portless-class CLIs pass — timeout (killSignal fires at - * the deadline and the result carries error: ETIMEDOUT + the signal, - * Node's shape), killSignal (a signal NAME; "" = the SIGTERM default), - * and per-fd stdio modes (in: 0 /dev/null, 1 ignore, 2 inherit; out/ - * err: 0 capture, 1 ignore → "", 2 inherit → ""). NEVER throws — spawn - * failure and timeout are data on the result, like Node's error - * property. spawnRes.signal is the result's termination signal as the - * call site's `Signals | null` union (null = exited normally or spawn - * failure), constructed type-directedly like spawnRes.status. */ - "cp.spawnSyncOpts": { - argTypes: [STRING, arrayOf(STRING), F64, STRING, F64, F64, F64], - result: SPAWNRES_T, - }, - /** cp.spawnSyncOpts with the `env` option: the trailing [k,v,...] - * pairs replace the child's environment (recordToEnvPairs). */ - "cp.spawnSyncEnv": { - argTypes: [STRING, arrayOf(STRING), F64, STRING, F64, F64, F64, arrayOf(STRING)], - result: SPAWNRES_T, - }, - /** cp.spawnSyncOpts with the stdio carried as a RUNTIME string — - * "pipe" | "ignore" | "inherit", proven by the call site's TYPE (the - * defaultRunner idiom `stdio: options?.stdio ?? "pipe"`); the runtime - * maps the value to the three modes. Args (cmd, argv, timeout, - * killSignal, stdio). Never throws, like the other spawnSync forms. */ - "cp.spawnSyncStdioStr": { - argTypes: [STRING, arrayOf(STRING), F64, STRING, STRING], - result: SPAWNRES_T, - }, - // node:net (scr_net.c). Listener slots are program-dependent closures — - // null slots, checked in the libCall case (the child.onExit precedent); - // the zero-param callbacks pin the exact func type here. The trailing - // BOOL on registrations is the once flag. - /** node:net (scr_net.c — linked, and scr_net_install() emitted, only - * when one of these appears on the IR; moduleUsesNet is the switch). - * Receivers are borrowed; CALLBACKS MOVE into the handle's listener - * registry and are released at settlement (the child.onExit story). - * All listener registrations carry a trailing BOOL once-flag (`on` vs - * `once`) and are void — chaining is fenced. None of these throw: - * listen/connect failures are the async 'error' event, like Node. - * - * net.createServer's optional connection handler and the - * serverOnConnection listeners take the runtime-provided adapters - * (zero-param, or the one-param socket shape); sockOnData's adapters - * are the stdin pair's shapes (zero-param / bytes chunk); the error - * events reuse the child %Error adapters. net.listen/net.listenCb bind - * NOW and defer 'listening' to the next loop turn (Node's next-tick - * emit); net.serverPort is the composed `server.address().port` read. - * net.connect's host argument is a string ("localhost" pins to - * 127.0.0.1 — SEMANTICS.md); the connect callback is once('connect'). */ - "net.createServer": { argTypes: [], result: NETSERVER_T }, - "net.createServerCb": { argTypes: [null], result: NETSERVER_T }, - "net.listen": { argTypes: [NETSERVER_T, F64], result: VOID }, - /** listen(path[, cb]): a Unix-socket server; the socket file is removed - * when the server closes. Failures are the async 'error'. */ - "net.listenPath": { argTypes: [NETSERVER_T, STRING], result: VOID }, - "net.listenPathCb": { - argTypes: [NETSERVER_T, STRING, { kind: "func", params: [], ret: VOID }], - result: VOID, - }, - "net.listenCb": { - argTypes: [NETSERVER_T, F64, { kind: "func", params: [], ret: VOID }], - result: VOID, - }, - /** listen({ port, host, ipv6Only }[, cb]) — the explicit-interface bind - * (portless's listenOnProxyInterface): args [server, port, host, - * ipv6Only]. host is an IP literal string ("" = the host-less - * dual-stack any default); ipv6Only sets IPV6_V6ONLY before the bind. - * These are the old-shaped calls, retained for omitted reusePort so - * serialized IR remains compatible. Failures are the async 'error', - * message in Node's listen shape with the requested host. Never throws. */ - "net.listenOpts": { argTypes: [NETSERVER_T, F64, STRING, BOOL], result: VOID }, - // The callback slot is a zero-param void closure OR its - // `(() => void) | undefined` optional-binding union (checked specially). - "net.listenOptsCb": { argTypes: [NETSERVER_T, F64, STRING, BOOL, null], result: VOID }, - /** Additive ABI for listen({ ..., reusePort }) — args - * [server, port, host, ipv6Only, reusePort], with the callback following - * those values in the callback form. The final BOOL is the requested - * kernel connection-distribution option; old spellings remain - * four/five-argument calls so serialized IR stays compatible. */ - "net.listenOptsReusePort": { argTypes: [NETSERVER_T, F64, STRING, BOOL, BOOL], result: VOID }, - // The callback is a zero-param void closure OR its optional-binding union; - // the callback follows the reusePort BOOL in this additive ABI. - "net.listenOptsReusePortCb": { - argTypes: [NETSERVER_T, F64, STRING, BOOL, BOOL, null], - result: VOID, - }, - "net.serverPort": { argTypes: [NETSERVER_T], result: F64 }, - "net.serverListening": { argTypes: [NETSERVER_T], result: BOOL }, - /** socket.ref()/unref() and server.ref()/unref(): whether the handle - * keeps the event loop alive. */ - "net.sockSetRef": { argTypes: [NETSOCKET_T, BOOL], result: VOID }, - "net.serverSetRef": { argTypes: [NETSERVER_T, BOOL], result: VOID }, - // net.serverAddress's record result is shape-checked in the libCall case - // (the dgram.address sentinel pattern). - /** server.address() as the full AddressInfo record (the dgram.address - * materialization pattern: the emitter builds the record from the three - * runtime reads; the frontend pinned the shape). Never throws — before - * listen it answers the any-form defaults with port 0 where Node - * answers null (the serverPort stance). */ - "net.serverAddress": { argTypes: [NETSERVER_T], result: VOID }, - "net.serverClose": { argTypes: [NETSERVER_T], result: VOID }, - /** server.close((err) => ...): the callback (a dyn function) gets - * undefined once the server closes, or Node's ERR_SERVER_NOT_RUNNING - * when it was not listening. */ - "net.serverCloseDyn": { argTypes: [NETSERVER_T, DYN], result: VOID }, - /** server.address() in programs that may listen on a Unix socket: the - * path a listening server answers ("" for a TCP server), and the check - * a record-typed address() makes first (throws for a Unix server). */ - "net.serverUnixPath": { argTypes: [NETSERVER_T], result: STRING }, - "net.serverAddressCheck": { argTypes: [NETSERVER_T], result: VOID }, - "net.serverCloseCb": { - argTypes: [NETSERVER_T, { kind: "func", params: [], ret: VOID }], - result: VOID, - }, - "net.serverOnError": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, - "net.serverOnClose": { - argTypes: [NETSERVER_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - "net.serverOnConnection": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, - /** 'secureConnection' — the TLS server's deferred 'connection' list - * (handshake-completion timing); on a server without deferred - * connections (a plain net server) the registration never fires, - * exactly Node's split. */ - "net.serverOnSecureConnection": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, - "net.connect": { argTypes: [F64, STRING], result: NETSOCKET_T }, - /** connect with a validated autoSelectFamilyAttemptTimeout option (the - * budget runs Node's validateInt32-from-1 ladder and is then inert — - * the single dial has nothing to time). May-throw. */ - "net.connectAttempt": { argTypes: [F64, STRING, DYN], result: NETSOCKET_T }, - /** net.connect/createConnection over a RUNTIME option bag (computed - * keys — the invalid-input probes): Node-order validation (the - * objectMode trio's ERR_INVALID_ARG_VALUE, validatePort, host string, - * autoSelectFamily boolean, the attempt budget), then the trailing - * compiler-rendered fence — ALWAYS THROWS (the error.nodeThrow - * polymorphic-result carve-out). May-throw seed. */ - "net.connectOptsChk": { argTypes: [DYN, STRING], result: VOID }, - "net.connectCb": { - argTypes: [F64, STRING, { kind: "func", params: [], ret: VOID }], - result: NETSOCKET_T, - }, - // The lookup's exact func shape is program data (its answer callback's - // union/record types) — checked specially in the libCall case. - /** connect({ port, host, autoSelectFamily: true, lookup }) — the - * caller-resolver dial (portless's createLoopbackConnection): args - * [port, host, lookup]. The runtime creates the (connecting) socket - * handle, invokes the lookup as Node does — lookup(hostname, options, - * callback), options crossing as the dyn undefined — and the answer - * closure (an emitter-synthesized per-shape thunk over a boxed socket, - * the SNI-answer pattern) dials the answered addresses IN ORDER: each - * connect failure tries the next, the LAST failure's message is the - * socket's 'error' (Node's autoSelectFamily aggregate is a documented - * divergence), and a lookup error surfaces as the deferred socket - * 'error'. A synchronous throw INSIDE the lookup propagates out of the - * connect call (may-throw seed). */ - "net.connectLookup": { argTypes: [F64, STRING, null], result: NETSOCKET_T }, - /** connect({ host, port, lookup }) with a lookup of Node's own type, as - * a checked-dynamic function: the runtime calls it with { hints, all: - * true } and a callback taking an address string or list, then dials - * the answers in order. MAY THROW (host validation, a lookup throw). */ - "net.connectLookupDyn": { argTypes: [F64, STRING, DYN], result: NETSOCKET_T }, - "net.sockWrite": { argTypes: [NETSOCKET_T, STRING], result: VOID }, - "net.sockWriteBytes": { argTypes: [NETSOCKET_T, BYTES_U8], result: VOID }, - "net.sockEnd": { argTypes: [NETSOCKET_T], result: VOID }, - "net.sockEndStr": { argTypes: [NETSOCKET_T, STRING], result: VOID }, - "net.sockEndBytes": { argTypes: [NETSOCKET_T, BYTES_U8], result: VOID }, - /** write/end with a CHECKED-DYNAMIC chunk (an untyped JS payload into a - * typed socket): the runtime dispatches STR/BYTES and throws Node's - * ERR_INVALID_ARG_TYPE chunk TypeError on any other kind. */ - "net.sockWriteDyn": { argTypes: [NETSOCKET_T, DYN], result: VOID }, - "net.sockEndDyn": { argTypes: [NETSOCKET_T, DYN], result: VOID }, - "net.sockDestroy": { argTypes: [NETSOCKET_T], result: VOID }, - "net.sockPipe": { argTypes: [NETSOCKET_T, NETSOCKET_T], result: VOID }, - /** socket.pipe(res) — raw socket chunks into a ServerResponse body - * (the extended-CONNECT bridge leg): each chunk is a body write (the - * response's own framing applies); source EOF end()s the response, - * pipe's default. Borrows both. Never throws. */ - "net.sockPipeRes": { argTypes: [NETSOCKET_T, HTTPRES_T], result: VOID }, - "net.sockOnData": { argTypes: [NETSOCKET_T, null, BOOL], result: VOID }, - "net.sockOnEnd": { - argTypes: [NETSOCKET_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - "net.sockOnClose": { - argTypes: [NETSOCKET_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - "net.sockOnError": { argTypes: [NETSOCKET_T, null, BOOL], result: VOID }, - "net.sockOnConnect": { - argTypes: [NETSOCKET_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - // node:dgram + node:dns (scr_dgram.c). The message/error listeners and - // dns.lookup's callback are program-dependent closures (null slots, - // checked in the libCall case); dgram.address's record result is - // program-dependent too (VOID here is the envGet sentinel — the libCall - // case checks the {address, family, port} shape). - /** node:dgram + node:dns (scr_dgram.c — linked, and - * scr_dgram_install() emitted, only when one of these appears on the - * IR; moduleUsesDgram is the switch — dns.lookup rides the same unit). - * The net listener discipline verbatim: receivers borrowed, CALLBACKS - * MOVE into the handle's registry and release at settlement, `on` vs - * `once` is the trailing bool, registrations are void. bind/connect - * bind NOW and defer 'listening'/'connect' to the next loop turn (the - * net.listen story); their optional-host completions are "" - * (bind → 0.0.0.0) and "127.0.0.1" (connect — udp4's Node default). - * bind/connect/send/close/address THROW Node's state errors ("Socket - * is already bound", "Already connected", "Not running") — may-throw - * seeded. dgram.address returns the AddressInfo RECORD (the frontend - * pins the {address, family, port} shape; the emitter builds it from - * runtime parts). onMessage adapters are emitted per rinfo record - * shape (the child.onExit precedent); onError reuses the child %Error - * adapters. dns.lookup resolves via getaddrinfo AT CALL TIME and - * defers the callback to the next turn (SEMANTICS.md documents the - * blocking divergence); its per-union adapter builds the - * `Error | null` first argument. */ - "dgram.createSocket": { argTypes: [BOOL], result: DGRAMSOCK_T }, - "dgram.bind": { argTypes: [DGRAMSOCK_T, F64, STRING], result: VOID }, - "dgram.bindCb": { - argTypes: [DGRAMSOCK_T, F64, STRING, { kind: "func", params: [], ret: VOID }], - result: VOID, - }, - "dgram.connect": { argTypes: [DGRAMSOCK_T, F64, STRING], result: VOID }, - "dgram.connectCb": { - argTypes: [DGRAMSOCK_T, F64, STRING, { kind: "func", params: [], ret: VOID }], - result: VOID, - }, - "dgram.sendStr": { argTypes: [DGRAMSOCK_T, STRING, F64, STRING], result: VOID }, - "dgram.sendBytes": { argTypes: [DGRAMSOCK_T, BYTES_U8, F64, STRING], result: VOID }, - /** Connected AF_UNIX datagram sockets for the hot-shots package shim - * (the unix-dgram addon's surface): fd or result >= 0, -errno on - * failure; send answers 1 when the socket would block. */ - "dgram.unixSocket": { argTypes: [], result: F64 }, - "dgram.unixConnect": { argTypes: [F64, STRING], result: F64 }, - "dgram.unixSend": { argTypes: [F64, BYTES_U8], result: F64 }, - "dgram.unixClose": { argTypes: [F64], result: F64 }, - /** The send argument-validation ladder over dyn arguments (Node's - * signature shuffle: slice bounds, list/type contracts, port/address - * validation, connected-state errors), then the send: lists, connected - * sends and completion callbacks included. Up to six arguments, the - * missing ones undefined. May-throw. */ - "dgram.sendChk": { argTypes: [DGRAMSOCK_T, DYN, DYN, DYN, DYN, DYN, DYN], result: VOID }, - "dgram.address": { argTypes: [DGRAMSOCK_T], result: VOID }, - "dgram.close": { argTypes: [DGRAMSOCK_T], result: VOID }, - "dgram.closeCb": { - argTypes: [DGRAMSOCK_T, { kind: "func", params: [], ret: VOID }], - result: VOID, - }, - "dgram.unref": { argTypes: [DGRAMSOCK_T], result: VOID }, - "dgram.ref": { argTypes: [DGRAMSOCK_T], result: VOID }, - /** The socket options (scr_dgram.c): the membership calls take the - * interface and whether it was given. May-throw. */ - "dgram.setBroadcast": { argTypes: [DGRAMSOCK_T, BOOL], result: VOID }, - "dgram.setTTL": { argTypes: [DGRAMSOCK_T, F64], result: F64 }, - "dgram.setMulticastTTL": { argTypes: [DGRAMSOCK_T, F64], result: F64 }, - "dgram.setMulticastLoopback": { argTypes: [DGRAMSOCK_T, BOOL], result: BOOL }, - "dgram.setMulticastInterface": { argTypes: [DGRAMSOCK_T, STRING], result: VOID }, - "dgram.addMembership": { argTypes: [DGRAMSOCK_T, STRING, STRING, BOOL], result: VOID }, - "dgram.dropMembership": { argTypes: [DGRAMSOCK_T, STRING, STRING, BOOL], result: VOID }, - "dgram.getRecvBufferSize": { argTypes: [DGRAMSOCK_T], result: F64 }, - "dgram.getSendBufferSize": { argTypes: [DGRAMSOCK_T], result: F64 }, - "dgram.setRecvBufferSize": { argTypes: [DGRAMSOCK_T, F64], result: VOID }, - "dgram.setSendBufferSize": { argTypes: [DGRAMSOCK_T, F64], result: VOID }, - "dgram.getSendQueueSize": { argTypes: [DGRAMSOCK_T], result: F64 }, - "dgram.getSendQueueCount": { argTypes: [DGRAMSOCK_T], result: F64 }, - "dgram.disconnect": { argTypes: [DGRAMSOCK_T], result: VOID }, - "dgram.onMessage": { argTypes: [DGRAMSOCK_T, null, BOOL], result: VOID }, - "dgram.onError": { argTypes: [DGRAMSOCK_T, null, BOOL], result: VOID }, - "dgram.onListening": { - argTypes: [DGRAMSOCK_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - "dgram.onClose": { - argTypes: [DGRAMSOCK_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - "dgram.onConnect": { - argTypes: [DGRAMSOCK_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - "dns.lookup": { argTypes: [STRING, F64, null], result: VOID }, - /** Node's argument forms with dyn callbacks: lookup(hostname, options, - * callback) and lookupService(address, port, callback). */ - "dns.lookupDyn": { argTypes: [DYN, DYN, DYN, BOOL], result: VOID }, - "dns.lookupService": { argTypes: [DYN, DYN, DYN, BOOL], result: VOID }, - /** node:dns/promises: lookup(hostname, options) and lookupService(address, - * port) over the callback forms; the promise fulfills with the dyn - * { address, family } (array for all: true) / { hostname, service }. - * Argument errors throw synchronously (may-throw), unlike the - * util.promisify forms below. */ - "dns.promisesLookup": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, - "dns.promisesLookupService": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, - "dns.getServers": { argTypes: [], result: DYN }, - "dns.getDefaultResultOrder": { argTypes: [], result: STRING }, - "dns.setDefaultResultOrder": { argTypes: [DYN], result: VOID }, - // node:test (scr_test.c). Bodies are program-dependent closures (0 or - // 1 testCtx param, void or Promise result — the spoke pinned the - // shape): null slots. sub's result is the settled Promise the - // await consumes. - /** node:test (scr_test.c — linked only when one of these appears on - * the IR; moduleUsesNodeTest is the switch, and the main epilogue asks - * scr_test_exit_code() for the process's exit status). Strings are - * BORROWED, callbacks MOVE. register/suite/hook attach to the runner - * tree (register: name, mode 0|1|2 run/skip/todo, directive message "" - * = none, cb or absent via registerEmpty, flags 1 async | 2 takes-ctx - * | 4 only, "file:line:col"); suite runs its body AT registration - * (Node's collection phase). sub is t.test — runs the subtest INLINE - * on the runner fiber and returns the settled promise the await - * consumes. ctxSkip/ctxTodo mark the running test; ctxDiagnostic - * queues an ℹ line; ctxName reads t.name. Every registration keeps - * the loop-run emitted (usesTimers) so the runner fiber drains. */ - // The trailing three are the { plan, timeout, concurrency } options (plan - // -1 without one; timeout read under flag 8; concurrency read under flag - // 16, -1 for true). An out-of-range timeout or concurrency throws. - "test.register": { - argTypes: [STRING, F64, STRING, null, F64, STRING, F64, F64, F64], - result: VOID, - }, - "test.registerEmpty": { - argTypes: [STRING, F64, STRING, F64, STRING, F64, F64, F64], - result: VOID, - }, - // The suite body takes no parameters or its SuiteContext (flag 2). - "test.suite": { argTypes: [STRING, F64, STRING, null, STRING, F64, F64], result: VOID }, - // The trailing string is the hook call's "file:line:col". - "test.hook": { argTypes: [F64, null, F64, STRING], result: VOID }, - "test.sub": { - argTypes: [TESTCTX_T, STRING, F64, STRING, null, F64, STRING, F64, F64, F64], - result: { kind: "promise", inner: VOID }, - }, - "test.subEmpty": { - argTypes: [TESTCTX_T, STRING, F64, STRING, F64, STRING, F64, F64, F64], - result: VOID, - }, - "test.ctxSkip": { argTypes: [TESTCTX_T, STRING], result: VOID }, - "test.ctxTodo": { argTypes: [TESTCTX_T, STRING], result: VOID }, - "test.ctxDiagnostic": { argTypes: [TESTCTX_T, STRING], result: VOID }, - "test.ctxName": { argTypes: [TESTCTX_T], result: STRING }, - "test.ctxFullName": { argTypes: [TESTCTX_T], result: STRING }, - // t.passed, and t.workerId's Number(NODE_TEST_WORKER_ID) with 0 for - // undefined. - "test.ctxPassed": { argTypes: [TESTCTX_T], result: BOOL }, - "test.workerId": { argTypes: [], result: F64 }, - // getTestContext(): whether a test, suite or hook is running in the - // current async context, and that context. - "test.hasContext": { argTypes: [], result: BOOL }, - "test.context": { argTypes: [], result: TESTCTX_T }, - // t.before/t.after/t.beforeEach/t.afterEach (which: 0 before, 1 after, - // 2 beforeEach, 3 afterEach); a throwing t.before is captured on the test. - "test.ctxHook": { argTypes: [TESTCTX_T, F64, null, F64], result: VOID }, - // t.plan(count), and the count of one t.assert call. - "test.ctxPlan": { argTypes: [TESTCTX_T, F64], result: VOID }, - "test.ctxCount": { argTypes: [TESTCTX_T], result: VOID }, - // The mock trackers: the module's `mock` and t.mock keep each mock's - // restore closure (moved) for restoreAll and reset. - "test.mockTrack": { argTypes: [{ kind: "func", params: [], ret: VOID }], result: VOID }, - "test.mockRestoreAll": { argTypes: [], result: VOID }, - "test.mockReset": { argTypes: [], result: VOID }, - "test.ctxMockTrack": { - argTypes: [TESTCTX_T, { kind: "func", params: [], ret: VOID }], - result: VOID, - }, - "test.ctxMockRestoreAll": { argTypes: [TESTCTX_T], result: VOID }, - "test.ctxMockReset": { argTypes: [TESTCTX_T], result: VOID }, - // mock.timers on the module's `mock` and on t.mock. enable takes one - // code per listed API ('T' setTimeout, 'I' setInterval), the `now` - // value and its flags (1 given, 2 from a Date). enable, tick, runAll and - // setTime throw Node's errors; tick and runAll run timer callbacks. - // t.assert.snapshot and fileSnapshot: the escaped, wrapped serialized - // value, and the stored value it is compared with (snapshot: the test, - // the value, the snapshot file; fileSnapshot: the value, the path). - // Both read or, in update mode, record; missing and unreadable - // snapshots throw Node's ERR_INVALID_STATE. - "test.snapshotValue": { argTypes: [STRING], result: STRING }, - "test.ctxSnapshot": { argTypes: [TESTCTX_T, STRING, STRING], result: STRING }, - "test.fileSnapshot": { argTypes: [STRING, STRING], result: STRING }, - // Node's serializeValue over a dyn array of serializers (undefined for - // the default JSON.stringify(value, null, 2)); a throw becomes Node's - // "The provided serializers did not generate a string." ERR_INVALID_STATE. - "test.snapshotSerialize": { argTypes: [DYN, DYN], result: DYN }, - "test.mockTimersEnable": { argTypes: [STRING, F64, F64], result: VOID }, - "test.mockTimersTick": { argTypes: [F64], result: VOID }, - "test.mockTimersRunAll": { argTypes: [], result: VOID }, - "test.mockTimersReset": { argTypes: [], result: VOID }, - "test.mockTimersSetTime": { argTypes: [F64], result: VOID }, - "test.ctxMockTimersEnable": { argTypes: [TESTCTX_T, STRING, F64, F64], result: VOID }, - "test.ctxMockTimersTick": { argTypes: [TESTCTX_T, F64], result: VOID }, - "test.ctxMockTimersRunAll": { argTypes: [TESTCTX_T], result: VOID }, - "test.ctxMockTimersReset": { argTypes: [TESTCTX_T], result: VOID }, - "test.ctxMockTimersSetTime": { argTypes: [TESTCTX_T, F64], result: VOID }, - // node:http (scr_http.c over scr_net.c). The handler and the data - // listeners are program-dependent closures (null slots, checked in the - // libCall case); reqHeader's result is the interned string|undefined - // union, checked like process.envGet. - /** node:http, the server slice (scr_http.c over scr_net.c — linked - * only when these appear on the IR; moduleUsesHttpServer is the - * switch, and any http.* libCall also counts as net use so scr_net.c - * links and installs). http.createServer's handler MOVES in and takes - * the runtime adapters for its (req, res) / (req) / () shapes; req - * body listeners follow the net.sockOnData story (bytes chunks, once - * flags); reqHeader answers the interned `string | undefined` union - * exactly like process.envGet; the res writers are borrowed-argument - * voids with Node's framing decided in the runtime (Content-Length - * for end-before-head, chunked after an explicit writeHead/write). */ - "http.createServer": { argTypes: [null], result: NETSERVER_T }, - /** http.createServer() / http.Server() with no handler — the - * on("request") route; option helpers set parser behavior on a fresh - * server before the constructor/factory result is returned. */ - "http.createServerEmpty": { argTypes: [], result: NETSERVER_T }, - "http.validateHeaderName": { argTypes: [STRING, STRING], result: VOID }, - "http.validateHeaderValue": { argTypes: [STRING, DYN], result: VOID }, - "http.serverJoinDupHeaders": { argTypes: [NETSERVER_T], result: VOID }, - "http.serverAllowMissingHostHeader": { argTypes: [NETSERVER_T], result: VOID }, - /** The five writable numeric http.Server timeout fields use one - * selector ABI: 0 timeout, 1 keepAliveTimeout, 2 headersTimeout, - * 3 requestTimeout, 4 keepAliveTimeoutBuffer. These calls store/read - * the property values; timer enforcement remains outside this surface. - * The constructor-option setter takes dyn so explicit undefined remains - * distinguishable from a numeric value until its Node validation ladder. */ - "http.serverTimeoutGet": { argTypes: [NETSERVER_T, F64], result: F64 }, - "http.serverSetTimeout": { argTypes: [NETSERVER_T, F64], result: VOID }, - "http.serverSetTimeoutCb": { argTypes: [NETSERVER_T, F64, null], result: VOID }, - "http.serverOnTimeout": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, - "http.serverCloseAllConnections": { argTypes: [NETSERVER_T], result: VOID }, - "http.serverCloseIdleConnections": { argTypes: [NETSERVER_T], result: VOID }, - "http.serverTimeoutSet": { argTypes: [NETSERVER_T, F64, F64], result: VOID }, - "http.serverTimeoutOptionSet": { argTypes: [NETSERVER_T, F64, DYN], result: VOID }, - /** server.on("listening", cb) — the deferred listen-callback list. */ - "net.serverOnListening": { - argTypes: [NETSERVER_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - /** The ServerResponse member surface: statusCode/statusMessage reads - * and assignments (Node's writable properties), the header CRUD trio - * (getHeader answers `string | undefined` like reqHeader), and - * end(cb)'s callback slot (resOnEndCallback registers, the end call - * follows — the callback fires deferred, just before Node's 'finish' - * emit; resOnFinish is the 'finish' listener slot). writeHead's - * statusMessage forms compose in interned helpers: resStatusMsgSet - * then the ordinary writeHead entry. */ - "http.resStatusGet": { argTypes: [HTTPRES_T], result: F64 }, - "http.resStatusSet": { argTypes: [HTTPRES_T, F64], result: VOID }, - "http.resStatusMsgGet": { argTypes: [HTTPRES_T], result: VOID }, - "http.resStatusMsgSet": { argTypes: [HTTPRES_T, STRING], result: VOID }, - "http.resRequest": { argTypes: [HTTPRES_T], result: HTTPREQ_T }, - "http.resSocket": { argTypes: [HTTPRES_T], result: VOID }, - "http.resWritableFinished": { argTypes: [HTTPRES_T], result: BOOL }, - "http.resSendDateGet": { argTypes: [HTTPRES_T], result: BOOL }, - "http.resSendDateSet": { argTypes: [HTTPRES_T, BOOL], result: VOID }, - "http.resStrictContentLengthGet": { argTypes: [HTTPRES_T], result: BOOL }, - "http.resStrictContentLengthSet": { argTypes: [HTTPRES_T, BOOL], result: VOID }, - "http.resSetTimeout": { argTypes: [HTTPRES_T, F64], result: VOID }, - "http.resSetTimeoutCb": { - argTypes: [HTTPRES_T, F64, { kind: "func", params: [], ret: VOID }], - result: VOID, - }, - // resGetHeader answers the interned `string | undefined` union — the - // reqHeader/envGet sentinel pattern (VOID here, checked specially). - "http.resGetHeader": { argTypes: [HTTPRES_T, STRING], result: VOID }, - /** getHeader as Node answers it: the number, string or string[] that was - * set, or undefined, as a checked-dynamic value. */ - "http.resGetHeaderDyn": { argTypes: [HTTPRES_T, STRING], result: DYN }, - "http.resGetHeaderNames": { argTypes: [HTTPRES_T], result: arrayOf(STRING) }, - "http.resGetRawHeaderNames": { argTypes: [HTTPRES_T], result: arrayOf(STRING) }, - "http.resGetHeaders": { argTypes: [HTTPRES_T], result: DYN }, - "http.resHasHeader": { argTypes: [HTTPRES_T, STRING], result: BOOL }, - "http.resRemoveHeader": { argTypes: [HTTPRES_T, STRING], result: VOID }, - "http.resOnFinish": { - argTypes: [HTTPRES_T, { kind: "func", params: [], ret: VOID }], - result: VOID, - }, - "http.resOnEndCallback": { - argTypes: [HTTPRES_T, { kind: "func", params: [], ret: VOID }], - result: VOID, - }, - "http.reqUrl": { argTypes: [HTTPREQ_T], result: STRING }, - "http.reqMethod": { argTypes: [HTTPREQ_T], result: STRING }, - "http.reqHeader": { argTypes: [HTTPREQ_T, STRING], result: VOID }, - "http.reqTrailer": { argTypes: [HTTPREQ_T, STRING], result: VOID }, - "http.reqHeaderValues": { argTypes: [HTTPREQ_T, STRING], result: VOID }, - "http.reqTrailerValues": { argTypes: [HTTPREQ_T, STRING], result: VOID }, - "http.reqOnData": { argTypes: [HTTPREQ_T, null, BOOL], result: VOID }, - "http.reqOnEnd": { - argTypes: [HTTPREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - "http.resSetHeader": { argTypes: [HTTPRES_T, STRING, STRING], result: VOID }, - /** setHeader / appendHeader with a number, string or array value; the - * stored value keeps its type for getHeader/getHeaders. MAY THROW. */ - "http.resSetHeaderDyn": { argTypes: [HTTPRES_T, STRING, DYN], result: VOID }, - "http.resAppendHeader": { argTypes: [HTTPRES_T, STRING, DYN], result: VOID }, - "http.resWriteHead": { argTypes: [HTTPRES_T, F64], result: VOID }, - "http.resWriteHeadN": { - argTypes: [HTTPRES_T, F64, arrayOf(STRING), arrayOf(STRING)], - result: VOID, - }, - /** HTTP/1.1 informational heads; early hints takes flat string pairs, - * with a lowercase `link` key required to send anything. */ - "http.resWriteContinue": { argTypes: [HTTPRES_T], result: VOID }, - "http.resWriteProcessing": { argTypes: [HTTPRES_T], result: VOID }, - "http.resWriteEarlyHints": { argTypes: [HTTPRES_T, arrayOf(STRING)], result: VOID }, - "http.resWrite": { argTypes: [HTTPRES_T, STRING], result: VOID }, - "http.resWriteBytes": { argTypes: [HTTPRES_T, BYTES_U8], result: VOID }, - "http.resEnd": { argTypes: [HTTPRES_T], result: VOID }, - "http.resEndStr": { argTypes: [HTTPRES_T, STRING], result: VOID }, - "http.resEndBytes": { argTypes: [HTTPRES_T, BYTES_U8], result: VOID }, - /** The checked-dynamic chunk twins (the net.sockWriteDyn story). */ - "http.resWriteDyn": { argTypes: [HTTPRES_T, DYN], result: VOID }, - "http.resEndDyn": { argTypes: [HTTPRES_T, DYN], result: VOID }, - "http.resHeadersSent": { argTypes: [HTTPRES_T], result: BOOL }, - "http.resWritableEnded": { argTypes: [HTTPRES_T], result: BOOL }, - "http.resFlushHeaders": { argTypes: [HTTPRES_T], result: VOID }, - "http.resAddTrailers": { argTypes: [HTTPRES_T, arrayOf(STRING)], result: VOID }, - "http.resCork": { argTypes: [HTTPRES_T], result: VOID }, - "http.resUncork": { argTypes: [HTTPRES_T], result: VOID }, - "http.resWritableCorked": { argTypes: [HTTPRES_T], result: F64 }, - // The member follow-ups: reqStatusCode's `number | undefined` and - // sockRemoteAddress's `string | undefined` results are shape-checked in - // the special cases in validate.ts (like reqHeader/columns). - /** The server-surface member follow-ups: reqStatusCode answers the - * interned `number | undefined` union (negative = the undefined arm — - * a SERVER request, where Node's statusCode is undefined; every client - * response carries a real status); reqSocket is the underlying - * connection (+1, the same handle net.connect would give); - * sockRemoteAddress answers `string | undefined` (NULL after the fd - * closed, Node's destroyed-socket undefined; a dual-stack accept of an - * IPv4 peer reads "::ffff:a.b.c.d" like Node). reqResume/reqPause/reqDestroy and - * the req error/close listener slots complete the IncomingMessage - * surface portless's client responses use; resDestroy/resOnClose and - * resWriteHeadPairs ([k0,v0,k1,v1,...] — the env.pairs helper's flat - * shape) complete ServerResponse. sockSetTimeout arms the idle - * EVFILT_TIMER ('timeout' fires after ms of inactivity, once per idle - * period, never destroying the socket — Node's semantics). */ - "http.reqStatusCode": { argTypes: [HTTPREQ_T], result: VOID }, - // reqStatusMessage's `string | undefined` is program-interned like - // reqHeader's (the VOID here is the envGet sentinel). - "http.reqStatusMessage": { argTypes: [HTTPREQ_T], result: VOID }, - /** req.rawHeaders — [name, value, name, value, ...] in arrival order, - * names in their ORIGINAL case (Node's shape); a fresh string[] per - * read. reqStatusMessage answers the interned `string | undefined` - * union — the reason phrase on client responses ("" when the status - * line carried none), the undefined arm on server requests (the - * statusCode split). sockDestroyed is socket.destroyed — true once the - * fd is gone (destroy() or full close). */ - "http.reqRawHeaders": { argTypes: [HTTPREQ_T], result: arrayOf(STRING) }, - /** The `{ ...req.headers }` snapshot feed: [lowercased name, value, - * ...] pairs in arrival order — the interned %headers.snapshot helper - * builds the record over it, exactly the process.envPairs pattern. */ - "http.reqHeaderPairs": { argTypes: [HTTPREQ_T], result: arrayOf(STRING) }, - /** Every value of one header in arrival order (empty when absent): the - * set-cookie array of a `{ ...req.headers }` snapshot. */ - "http.reqHeaderList": { argTypes: [HTTPREQ_T, STRING], result: arrayOf(STRING) }, - "http.reqRawTrailers": { argTypes: [HTTPREQ_T], result: arrayOf(STRING) }, - "http.reqTrailerPairs": { argTypes: [HTTPREQ_T], result: arrayOf(STRING) }, - "net.sockDestroyed": { argTypes: [NETSOCKET_T], result: BOOL }, - /** socket.writable — the write half is open: no end() yet, no FIN sent, - * fd alive (connecting sockets answer true; writes queue). Node's - * stream flag. Borrows; never throws. */ - "net.sockWritable": { argTypes: [NETSOCKET_T], result: BOOL }, - // The 'upgrade' registrations: the callback shapes are program-typed - // ((req, socket, head) and shorter prefixes — the libCall case checks). - /** The 'upgrade' events, both sides (SEMANTICS.md — the WebSocket - * proxying surface): serverOnUpgrade registers (req, socket, head) - * listeners fired INSTEAD of 'request' for Connection: upgrade - * requests (the parser steps aside; the socket is raw; `head` carries - * bytes past the request head; no listener = the socket destroys, - * Node's default). clientOnUpgrade is the client twin: a 101 response - * fires (res, socket, head) INSTEAD of 'response'. */ - "http.serverOnUpgrade": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, - /** server.on("connect", ...) — HTTP CONNECT tunneling, the 'upgrade' - * machinery's twin: (req, socket, head) fired INSTEAD of 'request' for - * CONNECT-method requests (no listener = the socket destroys, Node's - * default). The h2 compat server's 'connect' (portless's RFC 8441 - * handler) only ever sees the HTTP/1.1 arm under the allowHTTP1 - * lowering, so a listener whose second parameter is a UNION with a - * netSocket arm takes the socket wrapped at that arm (an emitted - * per-shape adapter — the tags are program data). */ - "http.serverOnConnect": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, - "http.clientOnUpgrade": { argTypes: [HTTPCLIENTREQ_T, null, BOOL], result: VOID }, - "http.reqSocket": { argTypes: [HTTPREQ_T], result: NETSOCKET_T }, - // reqH2Stream's program-interned Http2Stream | undefined result is - // checked in the special libCall cases in validate.ts. - "http.reqH2Stream": { argTypes: [HTTPREQ_T], result: VOID }, - "http.reqH2StreamOrThrow": { argTypes: [HTTPREQ_T, STRING], result: HTTP2STREAM_T }, - /** req.pipe(dest) — the IncomingMessage body streaming into a - * ServerResponse (the proxy's response leg), a ClientRequest (the - * request-body forward), or a raw socket (the upgrade-rejection leg); - * chunk-for-chunk, natural end ends the destination (Node's pipe - * default; no backpressure — divergence 54's stream model). */ - "http.reqPipeRes": { argTypes: [HTTPREQ_T, HTTPRES_T], result: VOID }, - "http.reqPipeClient": { argTypes: [HTTPREQ_T, HTTPCLIENTREQ_T], result: VOID }, - "http.reqPipeSock": { argTypes: [HTTPREQ_T, NETSOCKET_T], result: VOID }, - "http.reqResume": { argTypes: [HTTPREQ_T], result: VOID }, - "http.reqPause": { argTypes: [HTTPREQ_T], result: VOID }, - "http.reqDestroy": { argTypes: [HTTPREQ_T], result: VOID }, - "http.reqOnError": { argTypes: [HTTPREQ_T, null, BOOL], result: VOID }, - "http.reqOnClose": { - argTypes: [HTTPREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - "http.reqOnAborted": { - argTypes: [HTTPREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - "http.reqHttpVersion": { argTypes: [HTTPREQ_T], result: STRING }, - "http.reqHttpVersionMajor": { argTypes: [HTTPREQ_T], result: F64 }, - "http.reqHttpVersionMinor": { argTypes: [HTTPREQ_T], result: F64 }, - "http.reqAborted": { argTypes: [HTTPREQ_T], result: BOOL }, - "http.reqComplete": { argTypes: [HTTPREQ_T], result: BOOL }, - "http.resDestroy": { argTypes: [HTTPRES_T], result: VOID }, - "http.resOnClose": { - argTypes: [HTTPRES_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - "http.resWriteHeadPairs": { argTypes: [HTTPRES_T, F64, arrayOf(STRING)], result: VOID }, - /** writeHead(status, headers) with a checked-dynamic headers value — - * the runtime OBJ walk (string/number values; other values throw - * Node's invalid-argument TypeError; may throw). */ - "http.resWriteHeadDyn": { argTypes: [HTTPRES_T, F64, DYN], result: VOID }, - "net.sockSetTimeout": { argTypes: [NETSOCKET_T, F64], result: VOID }, - /** setEncoding('utf8') — 'data' delivers strings inside the chunk-encoding window; other real encodings throw the "not supported yet" Error, unknown names throw ERR_UNKNOWN_ENCODING (may throw). */ - "net.sockSetEncoding": { argTypes: [NETSOCKET_T, STRING], result: VOID }, - "http.reqSetEncoding": { argTypes: [HTTPREQ_T, STRING], result: VOID }, - "net.sockOnTimeout": { - argTypes: [NETSOCKET_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - "net.sockRemoteAddress": { argTypes: [NETSOCKET_T], result: VOID }, - /** socket.encrypted — `boolean | undefined`: the true arm iff the - * socket carries a TLS transport (Node types `encrypted: true` on - * TLSSocket; plain sockets answer undefined — the proxy.ts isEncrypted - * idiom reads it through a cast). */ - "net.sockEncrypted": { argTypes: [NETSOCKET_T], result: VOID }, - // node:http, the client slice. The response callback shapes are - // program-dependent (checked by validate.ts); header pairs arrive flat. - /** node:http, the CLIENT slice (http.request/http.get over the net - * client machinery): request/requestCb take (host, port, path, method, - * timeoutMs, headerPairs, autoEnd[, responseCb]) — headerPairs is the - * flat [k0,v0,...] array (empty for none), autoEnd true is http.get's - * eager end(). The handle owns one dialed connection (NO pooling — the - * wire still carries Node's exact head: user headers, then Host, - * Connection: keep-alive, and the framing header; the socket closes - * when the response completes). The response delivered to responseCb / - * 'response' listeners IS an httpReq (IncomingMessage), status and - * headers parsed from the wire, body via reqOnData/reqOnEnd. Errors are - * Node-shaped ('connect ECONNREFUSED ip:port', 'socket hang up') and - * fire 'error' then 'close'; an unhandled 'error' exits 1 like every - * net handle. clientWrite before end commits to chunked framing unless - * the caller set content-length; clientEnd(data) before any write sends - * Content-Length exactly like Node. */ - "http.request": { - argTypes: [STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL], - result: HTTPCLIENTREQ_T, - }, - "http.requestCb": { - argTypes: [STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL, null], - result: HTTPCLIENTREQ_T, - }, - /** new http.Agent(opts) / new https.Agent(opts): (secure, keepAlive, - * keepAliveMsecs, maxSockets, maxFreeSockets, timeoutMs, port) — the - * numeric options arrive < 0 for "unset" (Infinity/256/none; port - * seeds the settable defaultPort, Node's option merge). Returns the - * Agent as a checked-dynamic HANDLE (getName/destroy and the - * sockets/requests/freeSockets counters dispatch through the dyn - * handle ops). keepAlive: true THROWS the named construction fence — - * socket POOLING is not modeled (one dial per request); maxSockets - * accounting is real: over-limit requests defer their dial and queue. - * MAY THROW. */ - "http.agentNew": { argTypes: [BOOL, BOOL, F64, F64, F64, F64, F64, DYN], result: DYN }, - /** http.globalAgent / https.globalAgent (true): Node's keepAlive global - * agent, the one requests without an agent option use. */ - "http.globalAgent": { argTypes: [BOOL], result: DYN }, - /** http.request's `signal` option over the fresh request: an aborted - * signal destroys it with Node's AbortError now, a later abort event - * does the same. A falsy value is ignored; a non-signal throws - * ERR_INVALID_ARG_TYPE. */ - "http.clientSignal": { argTypes: [HTTPCLIENTREQ_T, DYN], result: VOID }, - /** options.signal checked before the request is built (ERR_INVALID_ARG_TYPE). */ - "http.clientSignalCheck": { argTypes: [DYN], result: VOID }, - /** https.request's servername option, stored for the construction call - * that follows: the TLS name sent and verified, and part of the pooled - * socket key. The "https." prefix keeps the TLS unit linked. */ - "https.nextServername": { argTypes: [STRING], result: VOID }, - /** The maxHeaderSize option of createServer / http.request: Node's - * validateInteger (ERR_OUT_OF_RANGE) then the header size bound. - * MAY THROW. */ - "http.serverMaxHeaderSize": { argTypes: [NETSERVER_T, F64], result: VOID }, - "http.clientMaxHeaderSize": { argTypes: [HTTPCLIENTREQ_T, F64], result: VOID }, - /** req.destroy(err): err becomes the request's 'error'. */ - "http.clientDestroyError": { - argTypes: [HTTPCLIENTREQ_T, { kind: "object", className: "%Error" }], - result: VOID, - }, - /** The agent-threaded request rows: the http.request/https.request - * shape with a trailing `agent` dyn argument (an Agent handle, false — - * the one-shot Connection: close dial — or null/undefined for the - * default path). port < 0 means "no port option": the agent's settable - * defaultPort, then the scheme's. MAY THROW (a non-Agent value is - * Node's ERR_INVALID_ARG_TYPE). */ - "http.requestAgent": { - argTypes: [STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL, DYN], - result: HTTPCLIENTREQ_T, - }, - "http.requestAgentCb": { - argTypes: [STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL, DYN, null], - result: HTTPCLIENTREQ_T, - }, - /** request/get with a URL-STRING first argument: the runtime parses it - * (WHATWG) and dials — throws catchably on an unparsable input or a - * non-http scheme. */ - "http.requestUrl": { argTypes: [STRING, STRING, BOOL], result: HTTPCLIENTREQ_T }, - "http.requestUrlCb": { argTypes: [STRING, STRING, BOOL, null], result: HTTPCLIENTREQ_T }, - /** request/get with a runtime options record: a RequestOptions - * variable, or a literal that spreads one or sets socketPath. Args - * (options, autoEnd[, cb]). The runtime reads the record in the - * ClientRequest constructor's order (host/port or socketPath, path, - * method, headers, timeout, agent, signal, maxHeaderSize) with Node's - * errors, and documented options it does not implement throw the - * runtime fence. The "https." pair adds the TLS options. MAY THROW. */ - "http.requestDyn": { argTypes: [DYN, BOOL], result: HTTPCLIENTREQ_T }, - "http.requestDynCb": { argTypes: [DYN, BOOL, null], result: HTTPCLIENTREQ_T }, - "https.requestDyn": { argTypes: [DYN, BOOL], result: HTTPCLIENTREQ_T }, - "https.requestDynCb": { argTypes: [DYN, BOOL, null], result: HTTPCLIENTREQ_T }, - /** The paused-mode demux surface (portless's first-byte TLS peek: - * once('readable') + read(1) + unshift + emit('connection')). - * sockOnReadable registers a zero-param listener (a consumer: arrived - * bytes buffer instead of flowing, and EOF announces too); sockRead - * answers `Buffer | null` (exactly n buffered bytes, or null — Node's - * less-than-n answer; n <= 0 drains everything); sockUnshift returns - * bytes to the front of the stream; serverEmitConnection routes a - * socket into another server's protocol layer (a TLS target's - * 'connection' waits for its handshake). */ - "net.sockOnReadable": { argTypes: [NETSOCKET_T, null, BOOL], result: VOID }, - // sockRead's result is the interned `Buffer | null` union — checked - // specially in validate.ts (the reqHeader/envGet pattern; VOID here is a - // placeholder the special case overrides). - "net.sockRead": { argTypes: [NETSOCKET_T, F64], result: VOID }, - "net.sockUnshift": { argTypes: [NETSOCKET_T, BYTES_U8], result: VOID }, - /** Socket flow control and the compat surface: pause/resume (reads - * gate off/on — kernel backpressure holds paused bytes; resume flows - * and discards sans listeners) and setNoDelay answer the SOCKET (+1, - * Node's chaining); destroySoon ends now and destroys once the FIN - * flushed; bytesWritten counts accepted bytes; readable is true until - * the read half ends. */ - "net.sockPause": { argTypes: [NETSOCKET_T], result: NETSOCKET_T }, - "net.sockResume": { argTypes: [NETSOCKET_T], result: NETSOCKET_T }, - "net.sockSetNoDelay": { argTypes: [NETSOCKET_T, BOOL], result: NETSOCKET_T }, - "net.sockDestroySoon": { argTypes: [NETSOCKET_T], result: VOID }, - /** RST close, answers the socket; throws ERR_INVALID_HANDLE_TYPE on TLS. */ - "net.sockResetAndDestroy": { argTypes: [NETSOCKET_T], result: NETSOCKET_T }, - /** socket.address(): { address, family, port } or {} as a dyn. */ - "net.sockAddress": { argTypes: [NETSOCKET_T], result: DYN }, - "net.sockBytesWritten": { argTypes: [NETSOCKET_T], result: F64 }, - /** remotePort (0), remoteFamily (1), localAddress (2), localPort (3), - * localFamily (4): dyn values, undefined when unknown. */ - "net.sockAddrField": { argTypes: [NETSOCKET_T, F64], result: DYN }, - "net.sockBytesRead": { argTypes: [NETSOCKET_T], result: F64 }, - "net.sockConnecting": { argTypes: [NETSOCKET_T], result: BOOL }, - "net.sockPending": { argTypes: [NETSOCKET_T], result: BOOL }, - "net.sockReadyState": { argTypes: [NETSOCKET_T], result: STRING }, - "net.sockSetKeepAlive": { argTypes: [NETSOCKET_T, BOOL, F64], result: NETSOCKET_T }, - "net.sockOnReady": { - argTypes: [NETSOCKET_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - /** Listeners with a parameter, as dyn functions: close(hadError), - * write's cb(err) and end's cb. */ - "net.sockOnCloseDyn": { argTypes: [NETSOCKET_T, DYN, BOOL], result: VOID }, - /** socket.on/once('lookup', listener): the listener (a dyn function) - * gets (err, address, family, host) once per resolved address, or once - * with the lookup error, before the connect. */ - "net.sockOnLookup": { argTypes: [NETSOCKET_T, DYN, BOOL], result: VOID }, - "net.sockOnWriteFlush": { - argTypes: [NETSOCKET_T, { kind: "func", params: [], ret: VOID }], - result: VOID, - }, - "net.sockOnWriteFlushDyn": { argTypes: [NETSOCKET_T, DYN], result: VOID }, - "net.sockOnFinishDyn": { argTypes: [NETSOCKET_T, DYN], result: VOID }, - "net.sockSetTimeoutCb": { - argTypes: [NETSOCKET_T, F64, { kind: "func", params: [], ret: VOID }], - result: VOID, - }, - "net.isIP": { argTypes: [DYN], result: F64 }, - "net.isIPv4": { argTypes: [DYN], result: BOOL }, - "net.isIPv6": { argTypes: [DYN], result: BOOL }, - "net.serverMaxConnectionsGet": { argTypes: [NETSERVER_T], result: DYN }, - "net.serverMaxConnectionsSet": { argTypes: [NETSERVER_T, DYN], result: VOID }, - "net.serverDropMaxConnectionGet": { argTypes: [NETSERVER_T], result: DYN }, - "net.serverDropMaxConnectionSet": { argTypes: [NETSERVER_T, DYN], result: VOID }, - /** net.SocketAddress and net.BlockList (scr_net.c): the constructors - * take the argument array; the handles are dyn values. */ - "net.socketAddressNew": { argTypes: [DYN], result: DYN }, - "net.socketAddressParse": { argTypes: [DYN], result: DYN }, - "net.isSocketAddress": { argTypes: [DYN], result: BOOL }, - "net.blockListNew": { argTypes: [DYN], result: DYN }, - "net.isBlockList": { argTypes: [DYN], result: BOOL }, - "net.blockListPrivateRanges": { argTypes: [], result: DYN }, - "net.serverOnDrop": { argTypes: [NETSERVER_T, DYN, BOOL], result: VOID }, - "net.serverGetConnections": { argTypes: [NETSERVER_T, DYN], result: VOID }, - "net.sockReadable": { argTypes: [NETSOCKET_T], result: BOOL }, - /** socket.on('finish', cb) / end(cb): fires once when the FIN goes out - * (sweep-deferred, never the registering stack). */ - "net.sockOnFinish": { - argTypes: [NETSOCKET_T, { kind: "func", params: [], ret: VOID }], - result: VOID, - }, - "net.serverEmitConnection": { argTypes: [NETSERVER_T, NETSOCKET_T], result: VOID }, - // tls/https: cert/key/ca PEM arguments are strings OR Buffers (null = - // both accepted; the emitter passes data+len either way). - /** node:tls + node:https (scr_tls.c over scr_net.c/scr_http.c, with - * the vendored mbedTLS archive — linked only when one of these appears - * on the IR; moduleUsesTls is the switch, and every tls/https libCall - * also counts as net AND http use so both units link and install). - * tls.createServer takes (cert, key[, handler]) — cert/key are PEM - * strings or Buffers (the emitter passes data+len for either); the - * handler is Node's 'secureConnection' (fires post-handshake with a - * socket that behaves exactly like a net socket, the same adapters as - * net.createServer). https.createServer is (cert, key, handler) with - * the http request-handler adapters. https.request/requestCb extend - * the http client row with (…, rejectUnauthorized: bool, ca: PEM - * string/Buffer — "" for none) and default port 443; everything else - * (write/end/destroy/events, the response surface) IS the http client - * surface — the handles are the same kinds. */ - "tls.createServer": { argTypes: [null, null], result: NETSERVER_T }, - "tls.createServerCb": { argTypes: [null, null, null], result: NETSERVER_T }, - /** The SNICallback forms: (cert, key, SNICallback[, handler]). The - * callback is http2.createSecureServerSni's shape, a function or a - * function | undefined union. */ - "tls.createServerSni": { argTypes: [null, null, null], result: NETSERVER_T }, - "tls.createServerSniCb": { argTypes: [null, null, null, null], result: NETSERVER_T }, - // The runtime options records (divergence 66's stance): a dyn options - // value whose members read at runtime; pemDyn extracts a runtime-valued - // cert/key member (arg 1 is the precomposed fence label). - /** RUNTIME options records (the divergence-66 stance): the *Dyn - * creators take a checked-dynamic (dyn) options value whose members - * read at runtime — cert/key extract like the literal path, members - * whose literal forms fence THROW the catchable fence at runtime, and - * undocumented keys drop like Node drops them. tls.pemDyn is the - * literal walk's runtime-valued cert/key extraction: (value, whatLit) - * → PEM bytes (strings/Buffers/one-element arrays of those) or the - * thrown fence. All of them may throw. */ - "tls.pemDyn": { argTypes: [DYN, STRING], result: BYTES_U8 }, - "tls.createServerDyn": { argTypes: [DYN], result: NETSERVER_T }, - "tls.createServerDynCb": { argTypes: [DYN, null], result: NETSERVER_T }, - "https.createServerDyn": { argTypes: [DYN], result: NETSERVER_T }, - "https.createServerDynCb": { argTypes: [DYN, null], result: NETSERVER_T }, - /** createSecureServer(options, handler) — the eager COMPAT handler as - * the first 'request' listener (Node's exact route), on both literal - * flavors: Req is the dual ALPN allowHTTP1 server, H2Req the ALPN=h2-only - * server (both use compat handles over h2 streams). Args are - * (cert, key, cb, enableConnectProtocol). */ - "http2.createSecureServerReq": { argTypes: [null, null, null, BOOL], result: NETSERVER_T }, - "http2.createSecureServerH2Req": { argTypes: [null, null, null, BOOL], result: NETSERVER_T }, - /** createSecureServer with a RUNTIME options record (the divergence-66 - * stance): allowHTTP1/cert/key read at runtime — allowHTTP1 picks the - * flavor, the TLS server walk fences its out-of-bounds members with - * the catchable runtime fence, and h2 session-tuning keys drop exactly - * like the literal walk ignores them. May throw. The Cb form carries - * the eager compat handler. */ - "http2.createSecureServerDyn": { argTypes: [DYN], result: NETSERVER_T }, - "http2.createSecureServerDynCb": { argTypes: [DYN, null], result: NETSERVER_T }, - // tls.connect(port, host, opts[, cb]) — port -1 / host "" read the - // options record; the callback fires post-handshake (secureConnect). - /** tls.connect — the TLS client socket: (port, host, opts[, cb]) where - * port -1 reads options.port, host "" reads options.host, and opts is - * the runtime (dyn) options record (rejectUnauthorized/ca/servername - * implemented; other documented members throw the runtime fence). The - * callback fires post-handshake — Node's secureConnect timing. */ - "tls.connect": { argTypes: [F64, STRING, DYN], result: NETSOCKET_T }, - "tls.connectCb": { argTypes: [F64, STRING, DYN, null], result: NETSOCKET_T }, - // The TLSSocket member surface (authError's `string | null` union is - // shape-checked in the special cases in validate.ts — the reqHeader pattern). - /** The TLSSocket member surface on the socket kind: authorized (bool — - * Node's verify verdict), authorizationError (the verify-failure CODE - * STRING or null), the 'secureConnect' registration (a TLS socket's - * conn list fires at establishment; plain sockets never fire it), and - * the 'session' registration (fires once with the serialized session — - * a Buffer; the received-ticket event). */ - "tls.sockAuthorized": { argTypes: [NETSOCKET_T], result: BOOL }, - /** getProtocol() (string | null), getCipher() (CipherNameAndProtocol, - * undefined before the handshake, null after close) and alpnProtocol - * (string | false | null), as dyn values. */ - "tls.sockGetProtocol": { argTypes: [NETSOCKET_T], result: DYN }, - "tls.sockGetCipher": { argTypes: [NETSOCKET_T], result: DYN }, - "tls.sockAlpnProtocol": { argTypes: [NETSOCKET_T], result: DYN }, - /** getPeerCertificate(detailed) and getCertificate() (the legacy object, - * {} or null; scr_tls_x509.c), and the DER behind getPeerX509Certificate() - * and getX509Certificate() (a Buffer, empty without a certificate). */ - "tls.sockGetPeerCertificate": { argTypes: [NETSOCKET_T, DYN], result: DYN }, - "tls.sockGetCertificate": { argTypes: [NETSOCKET_T], result: DYN }, - "tls.sockPeerCertDer": { argTypes: [NETSOCKET_T], result: BYTES_U8 }, - "tls.sockOwnCertDer": { argTypes: [NETSOCKET_T], result: BYTES_U8 }, - "tls.sockAuthError": { argTypes: [NETSOCKET_T], result: VOID }, - "tls.sockOnSecureConnect": { - argTypes: [NETSOCKET_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - "tls.sockOnSession": { argTypes: [NETSOCKET_T, null, BOOL], result: VOID }, - /** The 'secure' event: the handshake completed (after secureConnect on - * a client). Plain sockets never fire it. */ - "tls.sockOnSecure": { - argTypes: [NETSOCKET_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - /** new tls.TLSSocket(socket, options) in server mode: a new TLS socket - * takes over the socket's connection (wrapSocketCtx passes a literal's - * secureContext member apart from the runtime options record). The - * record reads at runtime: isServer, cert, key, ALPNProtocols, - * minVersion and maxVersion are implemented, the client mode and other - * documented members throw the runtime fence. MAY THROW. */ - "tls.wrapSocket": { argTypes: [NETSOCKET_T, DYN], result: NETSOCKET_T }, - "tls.wrapSocketCtx": { argTypes: [NETSOCKET_T, DYN, SECURECTX_T], result: NETSOCKET_T }, - // createSecureContext({ cert, key }) mints the opaque SNI-answer handle. - /** tls.createSecureContext({ cert, key }) — parses the PEM pair into an - * opaque SecureContext handle (secureCtx kind) for SNI callbacks to - * answer with; cert/key are PEM strings or Buffers like createServer's. */ - "tls.createSecureContext": { argTypes: [null, null], result: SECURECTX_T }, - /** createSecureContext over a RUNTIME options record (the checked- - * dynamic lane): Node's typed option validations first (the ciphers/ - * passphrase/engine/version/timeout/ticketKeys ladders), then the pem - * walk — a validated { cert, key } bag builds the real context. - * May-throw. */ - "tls.createSecureContextDyn": { argTypes: [DYN], result: SECURECTX_T }, - /** server.addContext(servername, options | SecureContext), - * server.setSecureContext(options) and the 'tlsClientError' listener of - * a tls or https server (scr_tls.c). */ - "tls.serverAddContext": { argTypes: [NETSERVER_T, DYN, DYN], result: VOID }, - "tls.serverAddContextCtx": { argTypes: [NETSERVER_T, DYN, SECURECTX_T], result: VOID }, - "tls.serverSetSecureContext": { argTypes: [NETSERVER_T, DYN], result: VOID }, - "tls.serverOnClientError": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, - /** tls.getCACertificates(type): validateString + the documented name - * set, then the trailing compiler-rendered fence — ALWAYS THROWS (the - * error.nodeThrow polymorphic-result carve-out). May-throw seed. */ - "tls.caCertsChk": { argTypes: [DYN, STRING], result: VOID }, - // The CA-store introspection unit (scr_tls_ca.c): per-type cached PEM - // string arrays and the default-set replacement. - /** The CA-store introspection surface (scr_tls_ca.c — its own unit and - * link gate, "tlsca." NOT "tls.", so a getCACertificates-only binary - * never pulls mbedTLS): tlsca.get is tls.getCACertificates(type) — the - * cached per-type string[] of PEM blocks (identity-stable across calls, - * Node's caching; an unknown type throws Node's ERR_INVALID_ARG_VALUE - * TypeError); tlsca.root is the tls.rootCertificates value read; - * tlsca.set is tls.setDefaultCACertificates(certs) — replaces the - * default set (deduped) and the anchors the TLS client verifies - * against, throwing Node's ERR_CRYPTO_OPERATION_FAILED when no entry - * carries a certificate block. */ - "tlsca.get": { argTypes: [STRING], result: arrayOf(STRING) }, - "tlsca.root": { argTypes: [], result: arrayOf(STRING) }, - "tlsca.set": { argTypes: [arrayOf(STRING)], result: VOID }, - "https.createServer": { argTypes: [null, null, null], result: NETSERVER_T }, - // http2's allowHTTP1 compatibility server (divergence 57): cert/key - // like tls.createServer; the 'request' handler arrives separately via - // http.serverOnRequest (shape checked in the libCall case, like - // http.createServer's). sessionError callback shape is checked by validate.ts. - /** node:http2 allowHTTP1: one TLS server advertises h2 + http/1.1 and - * dispatches to the matching parser after ALPN. Request listeners mirror - * into both compatibility lists; the remaining session/req.stream rows - * below retain their explicitly limited behavior. */ - "http2.createSecureServer": { argTypes: [null, null, BOOL], result: NETSERVER_T }, - // The SNI-callback form: arg 2 is the JS SNICallback closure — a - // `(servername, cb) => void` func, or its `| undefined` union from the - // conditional-spread spelling (the libCall case checks the shape). - /** createSecureServer with an SNI callback: args are (cert, key, sniCb) - * where sniCb is the JS SNICallback — a `(servername, cb) => void` - * closure, or the `SNICallback | undefined` union from the conditional- - * spread spelling (`...(x ? { SNICallback: x } : {})`; the emitter - * unwraps the union — the undefined arm means "no callback", exactly - * the no-SNI server). The runtime parses each connection's ClientHello - * for the server_name extension BEFORE the TLS handshake begins, calls - * the callback with (servername, answer-closure), and resumes the - * handshake when the answer arrives — cb(err) tears the socket down - * without an error event (Node's 'tlsClientError' default), cb(null, ctx) serves - * ctx's cert/key, cb(null, undefined) serves the default pair. */ - "http2.createSecureServerSni": { argTypes: [null, null, null, BOOL], result: NETSERVER_T }, - // The ALPN=h2 server (createSecureServer without allowHTTP1): the real - // h2 session machinery behind the TLS handshake. - /** The REAL h2-over-TLS server (createSecureServer WITHOUT allowHTTP1): - * scr_http2_create_secure_server — the h2c session machinery behind an - * mbedTLS handshake whose ALPN advertises h2 alone (an http/1.1-only - * client fails the handshake with no_application_protocol, Node's - * h2-only split). args are (cert, key) — PEM strings or Buffers. */ - "http2.createSecureServerH2": { argTypes: [null, null, BOOL], result: NETSERVER_T }, - "http.serverOnRequest": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, - /** server.on('checkContinue' | 'checkExpectation', (req, res)): the - * 'request' listener shape; the last argument picks checkExpectation. */ - "http.serverOnCheck": { argTypes: [NETSERVER_T, null, BOOL, BOOL], result: VOID }, - "http2.serverOnSessionError": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, - /** The guarded absent-session compatibility call remains a no-op. */ - "http2.streamNoop": { argTypes: [], result: VOID }, - /** The UNGUARDED h2-only stream call (`req.stream.on(...)`): stream is - * undefined on every connection the allowHTTP1 lowering accepts — and - * on every HTTP/1.1 connection of Node's own allowHTTP1 server — so the - * call IS Node's member read on undefined: throws the exact catchable - * TypeError ("Cannot read properties of undefined (reading 'on')"). - * One arg: the read member's name (a string literal). Never returns. */ - "http2.streamUndefCall": { argTypes: [STRING], result: VOID }, - // The REAL h2c surface (scr_http2.c). Callback slots are null (the - // emitter picks the thunk); pairs slots are string arrays; the - // endStream tri-state and event flags ride as f64. - /** node:http2, the REAL h2c surface (scr_http2.c — frame codec + HPACK - * over the net loop; the design note atop that file has the story). - * Sessions and streams are first-class handle kinds; 'stream'/'response' - * payloads cross as flat [name, value, ...] pairs arrays and an EMITTED - * adapter closure builds the program-side headers record (the response - * :status rides separately as a number). */ - "http2.createServer": { argTypes: [], result: NETSERVER_T }, - "http2.createServerReq": { argTypes: [null], result: NETSERVER_T }, - "http2.serverOnStream": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, - "http2.serverOnSession": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, - // connect(authority, reject, ca[, cb]): the TLS client knobs an https - // authority reads (inert on http ones, exactly Node); ca is a PEM - // string/Buffer ("" = the system anchors). - /** connect(authority[, listener]) — h2c prior knowledge; the listener - * closure (if any) is the 'connect' once-listener. */ - "http2.connect": { argTypes: [STRING, BOOL, null], result: HTTP2SESSION_T }, - "http2.connectCb": { argTypes: [STRING, BOOL, null, null], result: HTTP2SESSION_T }, - /** session.request(pairs?, endStream) — endStream is a tri-state f64: - * -1 the method's payload-meaningless default, 0/1 explicit. */ - "http2.sessionRequest": { - argTypes: [HTTP2SESSION_T, arrayOf(STRING), F64], - result: HTTP2STREAM_T, - }, - "http2.sessionClose": { argTypes: [HTTP2SESSION_T], result: VOID }, - "http2.sessionCloseCb": { argTypes: [HTTP2SESSION_T, null], result: VOID }, - "http2.sessionDestroy": { argTypes: [HTTP2SESSION_T], result: VOID }, - "http2.sessionOnClose": { argTypes: [HTTP2SESSION_T, null, BOOL], result: VOID }, - "http2.sessionOnError": { argTypes: [HTTP2SESSION_T, null, BOOL], result: VOID }, - "http2.sessionOnConnect": { argTypes: [HTTP2SESSION_T, null, BOOL], result: VOID }, - "http2.sessionOnStream": { argTypes: [HTTP2SESSION_T, null, BOOL], result: VOID }, - "http2.sessionOnGoaway": { argTypes: [HTTP2SESSION_T, null, BOOL], result: VOID }, - "http2.sessionClosed": { argTypes: [HTTP2SESSION_T], result: BOOL }, - "http2.sessionDestroyed": { argTypes: [HTTP2SESSION_T], result: BOOL }, - "http2.sessionEncrypted": { argTypes: [HTTP2SESSION_T], result: BOOL }, - "http2.sessionType": { argTypes: [HTTP2SESSION_T], result: F64 }, - "http2.sessionAlpn": { argTypes: [HTTP2SESSION_T], result: STRING }, - "http2.sessionSocket": { argTypes: [HTTP2SESSION_T], result: NETSOCKET_T }, - /** stream.respond(pairs?, endStream) — the server answer. */ - "http2.streamRespond": { argTypes: [HTTP2STREAM_T, arrayOf(STRING), BOOL], result: VOID }, - "http2.streamWrite": { argTypes: [HTTP2STREAM_T, STRING], result: VOID }, - "http2.streamWriteBytes": { argTypes: [HTTP2STREAM_T, BYTES_U8], result: VOID }, - "http2.streamEnd": { argTypes: [HTTP2STREAM_T], result: VOID }, - "http2.streamEndStr": { argTypes: [HTTP2STREAM_T, STRING], result: VOID }, - "http2.streamEndBytes": { argTypes: [HTTP2STREAM_T, BYTES_U8], result: VOID }, - "http2.streamClose": { argTypes: [HTTP2STREAM_T, F64], result: VOID }, - "http2.streamCloseCb": { argTypes: [HTTP2STREAM_T, F64, null], result: VOID }, - "http2.streamDestroy": { argTypes: [HTTP2STREAM_T], result: VOID }, - "http2.sessionSettings0": { argTypes: [HTTP2SESSION_T], result: VOID }, - "http2.sessionSettings": { argTypes: [HTTP2SESSION_T, DYN], result: VOID }, - "http2.sessionSettingsDynCb": { argTypes: [HTTP2SESSION_T, DYN, DYN], result: VOID }, - "http2.sessionSettingsCb0": { - argTypes: [HTTP2SESSION_T, DYN, { kind: "func", params: [], ret: VOID }], - result: VOID, - }, - "http2.sessionOnSettingsDyn": { argTypes: [HTTP2SESSION_T, DYN, BOOL, BOOL], result: VOID }, - "http2.sessionOnSettings0": { - argTypes: [HTTP2SESSION_T, { kind: "func", params: [], ret: VOID }, BOOL, BOOL], - result: VOID, - }, - "http2.sessionSettingsGet": { argTypes: [HTTP2SESSION_T, BOOL], result: DYN }, - "http2.sessionPendingSettingsAck": { argTypes: [HTTP2SESSION_T], result: BOOL }, - "http2.getDefaultSettings": { argTypes: [], result: DYN }, - "http2.streamSetEncoding": { argTypes: [HTTP2STREAM_T, STRING], result: VOID }, - "http2.streamSetEncodingRet": { argTypes: [HTTP2STREAM_T, STRING], result: HTTP2STREAM_T }, - "http2.streamResume": { argTypes: [HTTP2STREAM_T], result: VOID }, - "http2.streamPause": { argTypes: [HTTP2STREAM_T], result: VOID }, - "http2.streamOnData": { argTypes: [HTTP2STREAM_T, null, BOOL], result: VOID }, - "http2.streamOnEnd": { argTypes: [HTTP2STREAM_T, null, BOOL], result: VOID }, - "http2.streamOnClose": { argTypes: [HTTP2STREAM_T, null, BOOL], result: VOID }, - "http2.streamOnAborted": { argTypes: [HTTP2STREAM_T, null, BOOL], result: VOID }, - "http2.streamOnError": { argTypes: [HTTP2STREAM_T, null, BOOL], result: VOID }, - "http2.streamOnResponse": { argTypes: [HTTP2STREAM_T, null, BOOL], result: VOID }, - "http2.streamId": { argTypes: [HTTP2STREAM_T], result: F64 }, - "http2.streamRstCode": { argTypes: [HTTP2STREAM_T], result: F64 }, - "http2.streamDestroyed": { argTypes: [HTTP2STREAM_T], result: BOOL }, - "http2.streamClosed": { argTypes: [HTTP2STREAM_T], result: BOOL }, - "http2.streamAborted": { argTypes: [HTTP2STREAM_T], result: BOOL }, - "http2.streamPending": { argTypes: [HTTP2STREAM_T], result: BOOL }, - "http2.streamSession": { argTypes: [HTTP2STREAM_T], result: HTTP2SESSION_T }, - // The createConnection forms: arg 0 is the dialer closure (() => - // Socket — the libCall case checks), then path/method/timeout/headers/ - // autoEnd like http.request. - /** The createConnection form (the proxy's own dialer): args are - * (connCb, path, method, timeout, headers, autoEnd[, cb]) — connCb is - * a `() => net.Socket` closure the runtime invokes ONCE, synchronously - * (Node's onSocket timing); everything else matches http.request. The - * Host header defaults to "localhost" — a headers.host entry wins - * verbatim, the proxy shape. */ - "http.requestConn": { - argTypes: [null, STRING, STRING, F64, arrayOf(STRING), BOOL], - result: HTTPCLIENTREQ_T, - }, - "http.requestConnCb": { - argTypes: [null, STRING, STRING, F64, arrayOf(STRING), BOOL, null], - result: HTTPCLIENTREQ_T, - }, - "https.request": { - argTypes: [STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL, BOOL, null], - result: HTTPCLIENTREQ_T, - }, - "https.requestCb": { - argTypes: [STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL, BOOL, null, null], - result: HTTPCLIENTREQ_T, - }, - /** The URL-string first argument, the http.requestUrl row over TLS: - * no options means Node's defaults (verification on, default trust - * anchors), and a non-https scheme is ERR_INVALID_PROTOCOL. */ - "https.requestUrl": { argTypes: [STRING, STRING, BOOL], result: HTTPCLIENTREQ_T }, - "https.requestUrlCb": { argTypes: [STRING, STRING, BOOL, null], result: HTTPCLIENTREQ_T }, - "https.requestAgent": { - argTypes: [STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL, BOOL, null, DYN], - result: HTTPCLIENTREQ_T, - }, - "https.requestAgentCb": { - argTypes: [STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL, BOOL, null, DYN, null], - result: HTTPCLIENTREQ_T, - }, - // The requestFn binding's runtime-secure rows: https.request's shape - // with the leading `secure` bool. - /** A call through a `const requestFn = tls ? https.request : - * http.request` binding — the module-function-as-value ternary between - * the two known clients: the https.request row with a leading `secure` - * bool that picks the dial at RUNTIME (true = the TLS client, exactly - * https.request; false = the plain client, exactly http.request — - * rejectUnauthorized/ca ignored there like Node ignores TLS options on - * http.request). The "https." prefix keeps the TLS unit linked. */ - "https.requestFn": { - argTypes: [BOOL, STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL, BOOL, null], - result: HTTPCLIENTREQ_T, - }, - "https.requestFnCb": { - argTypes: [BOOL, STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL, BOOL, null, null], - result: HTTPCLIENTREQ_T, - }, - "http.clientWrite": { argTypes: [HTTPCLIENTREQ_T, STRING], result: VOID }, - "http.clientSetHeader": { argTypes: [HTTPCLIENTREQ_T, STRING, STRING], result: VOID }, - "http.clientGetHeader": { argTypes: [HTTPCLIENTREQ_T, STRING], result: VOID }, - "http.clientHasHeader": { argTypes: [HTTPCLIENTREQ_T, STRING], result: BOOL }, - "http.clientRemoveHeader": { argTypes: [HTTPCLIENTREQ_T, STRING], result: VOID }, - "http.clientGetHeaderNames": { argTypes: [HTTPCLIENTREQ_T], result: arrayOf(STRING) }, - "http.clientGetRawHeaderNames": { argTypes: [HTTPCLIENTREQ_T], result: arrayOf(STRING) }, - "http.clientGetHeaders": { argTypes: [HTTPCLIENTREQ_T], result: DYN }, - "http.clientWriteBytes": { argTypes: [HTTPCLIENTREQ_T, BYTES_U8], result: VOID }, - "http.clientEnd": { argTypes: [HTTPCLIENTREQ_T], result: VOID }, - "http.clientEndStr": { argTypes: [HTTPCLIENTREQ_T, STRING], result: VOID }, - "http.clientEndBytes": { argTypes: [HTTPCLIENTREQ_T, BYTES_U8], result: VOID }, - /** The checked-dynamic chunk twins (the net.sockWriteDyn story). */ - "http.clientWriteDyn": { argTypes: [HTTPCLIENTREQ_T, DYN], result: VOID }, - "http.clientEndDyn": { argTypes: [HTTPCLIENTREQ_T, DYN], result: VOID }, - "http.clientFlushHeaders": { argTypes: [HTTPCLIENTREQ_T], result: VOID }, - "http.clientAddTrailers": { argTypes: [HTTPCLIENTREQ_T, arrayOf(STRING)], result: VOID }, - "http.clientCork": { argTypes: [HTTPCLIENTREQ_T], result: VOID }, - "http.clientUncork": { argTypes: [HTTPCLIENTREQ_T], result: VOID }, - "http.clientWritableCorked": { argTypes: [HTTPCLIENTREQ_T], result: F64 }, - "http.clientMethod": { argTypes: [HTTPCLIENTREQ_T], result: STRING }, - "http.clientPath": { argTypes: [HTTPCLIENTREQ_T], result: STRING }, - "http.clientHost": { argTypes: [HTTPCLIENTREQ_T], result: STRING }, - "http.clientProtocol": { argTypes: [HTTPCLIENTREQ_T], result: STRING }, - "http.clientHeadersSent": { argTypes: [HTTPCLIENTREQ_T], result: BOOL }, - "http.clientWritableEnded": { argTypes: [HTTPCLIENTREQ_T], result: BOOL }, - "http.clientWritableFinished": { argTypes: [HTTPCLIENTREQ_T], result: BOOL }, - "http.clientSocket": { argTypes: [HTTPCLIENTREQ_T], result: NETSOCKET_T }, - "http.clientReusedSocket": { argTypes: [HTTPCLIENTREQ_T], result: BOOL }, - "http.clientSetNoDelay": { argTypes: [HTTPCLIENTREQ_T, BOOL], result: VOID }, - "http.clientSetSocketKeepAlive": { argTypes: [HTTPCLIENTREQ_T, BOOL, F64], result: VOID }, - "http.clientSetTimeout": { argTypes: [HTTPCLIENTREQ_T, F64], result: VOID }, - "http.clientSetTimeoutCb": { - argTypes: [HTTPCLIENTREQ_T, F64, { kind: "func", params: [], ret: VOID }], - result: VOID, - }, - "http.statusCodes": { argTypes: [], result: DYN }, - "http.methods": { argTypes: [], result: arrayOf(STRING) }, - "http.reqSetTimeout": { argTypes: [HTTPREQ_T, F64], result: VOID }, - "http.reqSetTimeoutCb": { - argTypes: [HTTPREQ_T, F64, { kind: "func", params: [], ret: VOID }], - result: VOID, - }, - "http.clientDestroy": { argTypes: [HTTPCLIENTREQ_T], result: VOID }, - "http.clientAbort": { argTypes: [HTTPCLIENTREQ_T], result: VOID }, - "http.clientAborted": { argTypes: [HTTPCLIENTREQ_T], result: BOOL }, - "http.clientDestroyed": { argTypes: [HTTPCLIENTREQ_T], result: BOOL }, - "http.clientOnResponse": { argTypes: [HTTPCLIENTREQ_T, null, BOOL], result: VOID }, - "http.clientOnSocket": { argTypes: [HTTPCLIENTREQ_T, null, BOOL], result: VOID }, - "http.clientOnFinish": { - argTypes: [HTTPCLIENTREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - "http.clientOnError": { argTypes: [HTTPCLIENTREQ_T, null, BOOL], result: VOID }, - "http.clientOnTimeout": { - argTypes: [HTTPCLIENTREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - "http.clientOnClose": { - argTypes: [HTTPCLIENTREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - "http.clientOnAbort": { - argTypes: [HTTPCLIENTREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - "http.clientOnContinue": { - argTypes: [HTTPCLIENTREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], - result: VOID, - }, - /** execFileSync/execSync as ONE entry (args: cmd, argv, shell, input, - * cwd, hasEnv, envPairs, timeoutMs, stdoutMode, stderrMode, buffers — - * see scr_child.h). Throws Node's exact errors: "Command failed: " - * (+ captured stderr) on non-zero exit or signal death, "spawnSync - * ENOENT" on spawn failure, "spawnSync ETIMEDOUT" after - * the SIGTERM timeout, with Node's status, signal, output, pid, stdout - * and stderr properties (Buffer outputs when buffers is set: no - * encoding option). Result is the captured utf8 stdout (+1). */ - "cp.execSync": { - argTypes: [ - STRING, - arrayOf(STRING), - BOOL, - STRING, - BOOL, - STRING, - BOOL, - arrayOf(STRING), - F64, - F64, - F64, - BOOL, - ], - result: STRING, - }, - /** The promisified-execFile/exec capture (args: cmd, argv, shell, cwd, - * hasEnv, envPairs, timeoutMs; shell marks exec's /bin/sh -c argv, as - * for execSync, so failures display the command string): the same exec - * core in the async shape — both streams captured, no echo, Node's ASYNC messages on the throw paths - * ("Command failed: \n" with the unconditional newline, - * "spawn ENOENT" with .code, timeouts reporting as ordinary - * SIGTERM command failures — never ETIMEDOUT). Result reuses the - * ScrSpawnRes container (+1; stdout/stderr strings, status unused). - * Called only from the frontend's interned %execFileAsync and - * %execAsync ASYNC helpers, whose fiber turns the throw into the - * rejection. */ - "cp.execCapture": { - argTypes: [STRING, arrayOf(STRING), BOOL, STRING, BOOL, arrayOf(STRING), F64], - result: SPAWNRES_T, - }, - /** child_process.spawn (scr_child.c + the scr_async.c loop): posix_spawnp - * with per-slot ignore/inherit/pipe modes (and number output fds), the - * all-piped Node default, and the child registered with the event loop, - * which polls waitpid(WNOHANG) at quiescence like timers. - * NEVER throws: spawn failure defers to the "error" event, Node-exact - * (the error message is Node's "spawn "; an "error" - * event with no listener prints it and exits 1 like an EventEmitter). - * cmd/args borrowed; result an owned (+1) child handle. The loop will - * not exhaust while any spawned child is unreaped — Node's keep-alive. - * - * child.onExit / child.onClose / child.onError — terminal listener - * registration through child.on/once. Close uses the exit adapter shape - * but fires only after every piped stdio handle reaches EOF. The - * receiver is borrowed, the CALLBACK MOVES into the child's listener - * registry (released after the terminal event fires, or at reap for - * the event that never fires). Both are void (chaining is fenced). - * onExit's third emitted ingredient is an ADAPTER the backend interns - * per callback shape: the runtime invokes adapter(cb, has_code, code) - * and the adapter builds the `number | null` union (tags are program- - * dependent) or ignores the code for a zero-param callback. onError's - * adapters are runtime-provided (zero-param, or the %Error one-param - * shape — scr_error_new needs no program types). "exit" fires once - * with the code (f64 arm) or null (signal death); "error" fires only - * for spawn failure, exactly Node's split. */ - "cp.spawn": { argTypes: [STRING, arrayOf(STRING)], result: CHILD_T }, - /** Static-native fork startup and IPC. process.forkTarget initializes a - * re-executed child's inherited channel and returns its embedded target id - * (-1 in the parent). The remaining entries mirror Node's JSON channel. */ - "process.forkTarget": { argTypes: [F64], result: F64 }, - "cp.fork": { - argTypes: [F64, arrayOf(STRING), F64, F64, F64, BOOL, arrayOf(STRING), STRING], - result: CHILD_T, - }, - "child.connected": { argTypes: [CHILD_T], result: BOOL }, - "child.hasChannel": { argTypes: [CHILD_T], result: BOOL }, - "child.send": { argTypes: [CHILD_T, STRING], result: BOOL }, - "child.sendCb": { argTypes: [CHILD_T, STRING, null], result: BOOL }, - "child.disconnect": { argTypes: [CHILD_T], result: VOID }, - "child.onMessage": { argTypes: [CHILD_T, null, BOOL], result: VOID }, - "child.onDisconnect": { argTypes: [CHILD_T, null, BOOL], result: VOID }, - "child.onSpawn": { argTypes: [CHILD_T, null], result: VOID }, - /** Rest listeners use the checked function bridge to pack event arguments. */ - "child.onDyn": { argTypes: [CHILD_T, STRING, DYN], result: VOID }, - // Own properties JavaScript adds to children (handle-properties.ts). - "child.propsInstall": { argTypes: [], result: VOID }, - "child.propsDefine": { argTypes: [DYN, DYN, DYN], result: DYN }, - "child.propsDescriptor": { argTypes: [DYN, DYN], result: DYN }, - "child.propsResolve": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, - "child.propsOnDyn": { argTypes: [CHILD_T, STRING, DYN], result: VOID }, - "process.connected": { argTypes: [], result: BOOL }, - /** Whether this fork child opened its channel; part of process.send's - * presence in programs with fork targets. Never throws. */ - "process.ipcOpen": { argTypes: [], result: BOOL }, - "process.send": { argTypes: [STRING], result: BOOL }, - "process.sendCb": { argTypes: [STRING, null], result: BOOL }, - "process.disconnect": { argTypes: [], result: VOID }, - "process.onMessage": { argTypes: [null, BOOL], result: VOID }, - "process.onDisconnect": { argTypes: [null, BOOL], result: VOID }, - /** child_process.execFile's callback slice: starts an all-piped child, - * captures stdout/stderr, and moves the error-first callback into the - * child registry. The callback shape is program-dependent and checked - * by the validator/backends. The last argument is exec's shell flag: - * the argv is ["-c", command] and failure messages show the command. */ - "cp.execFile": { argTypes: [STRING, arrayOf(STRING), null, BOOL], result: CHILD_T }, - // spawn's options form: per-slot stdio modes (0 ignore / 1 inherit / - // 2 fd) with the out/err fds for mode 2, detached, env replacement - // pairs, cwd ("" = inherit). - /** spawn with options (scr_child.c): the cp.spawn core plus PER-SLOT - * stdio — args are (cmd, argv, inMode, outMode, errMode, outFd, errFd, - * detached, hasEnv, envPairs, cwd); modes 0 ignore (/dev/null), 1 - * inherit, 2 fd (out/err only — the fd dup2s into the child's slot, - * Node's stdio fd form; the daemon-log idiom ["ignore", logFd, logFd]). - * detached is POSIX_SPAWN_SETSID (the child gets its own session and - * process group, Node's semantics), env is a REPLACEMENT ([k,v,...] - * pairs like cp.execSync's), cwd ""=inherit. Same event/loop story as - * cp.spawn. */ - "cp.spawnOpts": { - argTypes: [ - STRING, - arrayOf(STRING), - F64, - F64, - F64, - F64, - F64, - BOOL, - BOOL, - BOOL, - arrayOf(STRING), - STRING, - ], - result: CHILD_T, - }, - /** Runtime options normalized into the native spawn core; unsupported - * process features retain explicit refusals. (command, args, options). */ - "cp.spawnDynamic": { argTypes: [STRING, arrayOf(STRING), DYN], result: CHILD_T }, - // The callback's func type is program-dependent (zero params, or the - // `number | null` union / the %Error class) — the libCall case checks - // the shape; the slot here only pins arity and the child receiver. - "child.onExit": { argTypes: [CHILD_T, null], result: VOID }, - "child.onClose": { argTypes: [CHILD_T, null], result: VOID }, - "child.onError": { argTypes: [CHILD_T, null], result: VOID }, - // Like process.envGet, spawnRes.status's result type is program-dependent - // (the interned `number | null` union) — the libCall case checks the arms. - "spawnRes.status": { argTypes: [SPAWNRES_T], result: VOID }, - // spawnRes.error's result is the interned `Error | undefined` union — - // the libCall case checks the arms, the spawnRes.status pattern. - /** Node's spawn-failure carrier `error?: Error`: a fresh +1 %Error - * ("spawnSync ENOENT", `code` stamped) when the spawn itself - * failed, the interned undefined arm otherwise — the result type is the - * call site's `Error | undefined` union, constructed type-directedly in - * the backend (the envGet convention). Never throws. */ - "spawnRes.error": { argTypes: [SPAWNRES_T], result: VOID }, - // spawnRes.signal's result is the interned `string | null` union — - // same pattern. - "spawnRes.signal": { argTypes: [SPAWNRES_T], result: VOID }, - // The ChildProcess lifecycle members: pid/exitCode are program-dependent - // unions (`number | undefined` / `number | null` — the libCall case - // checks the arms, the spawnRes.status pattern). - /** The ChildProcess lifecycle members (scr_child.c), Node's shapes - * exactly (SEMANTICS.md has the pinned matrix). child.pid is the - * checker's `number | undefined` (undefined = spawn failure) and - * child.exitCode its `number | null` (null while running and after a - * signal death; -errno once a spawn failure settled) — both unions are - * type-directed constructions in the backend over a has/get runtime - * pair, the spawnRes.status pattern. child.killed is Node's - * sent-a-signal flag. child.kill sends while the child is un-reaped - * (false after — Node's null-handle answer) and THROWS the - * Unknown-signal TypeError on bad names (may-throw); killNum passes - * numbers through (0 probes; never throws). child.unref drops the - * child from the loop's keep-alive set — it is still reaped while the - * loop runs for other reasons, and one the loop never reaps is left to - * the OS at exit. All receivers borrowed. */ - "child.pid": { argTypes: [CHILD_T], result: VOID }, - "child.exitCode": { argTypes: [CHILD_T], result: VOID }, - // The close-override pair: the bound close's result func type and the - // override's func argument are program-dependent (the callback union's - // tags) — the slots pin the server receiver; the libCall case checks - // the bound value's shape. - /** The close-override pair (the portless close-proxy idiom). - * serverCloseBind is `wrapper.close.bind(wrapper)` as a VALUE: a - * compiler-emitted closure over the server whose invocation runs the - * REAL close (scr_net_server_close_direct — never the override), so - * the override body's `origClose(cb)` cannot recurse; its callback - * argument (the `((err?: Error) => void) | undefined` union) registers - * as a once-'close' listener, a one-param callback wrapped by an - * emitted zero-arg trampoline firing the undefined arm (a clean close - * carries no error). serverSetCloseOverride is `wrapper.close = fn`: - * the override MOVES in behind an emitted zero-arg wrapper (it invokes - * the user function with the undefined-arm callback — tags are program - * data), and server.close() consults it before closing. */ - "net.serverCloseBind": { argTypes: [NETSERVER_T], result: VOID }, - "net.serverSetCloseOverride": { argTypes: [NETSERVER_T, null], result: VOID }, - // The piped-output stream reads: `Readable | null` unions (the libCall - // case checks the arms — the child.pid pattern with a ref arm). - /** The piped-output streams (stdio mode 3 — scr_child.c's stream - * slice). child.stdout/child.stderr answer the checker's - * `Readable | null` union (type-directed construction in the backend - * over the +1-or-NULL runtime pair — the child.pid pattern with a ref - * arm). stream.onData/onEnd register 'data'/'end' listeners (receiver - * borrowed, CALLBACK MOVES, trailing once-flag, void — chaining - * fenced): 'data' fires one Buffer chunk per read (zero-param and - * Buffer/string adapters are runtime-provided; setEncoding threads - * split multibyte sequences through the shared StringDecoder core. A - * union-param listener — - * ngrok's `Buffer | string` — gets a compiler-emitted adapter wrapping - * the chunk at its Buffer arm), 'end' fires once at EOF, always BEFORE - * the child's 'exit' (the pinned ordering). A flowing stream keeps the - * loop alive: usesTimers. */ - "child.stdout": { argTypes: [CHILD_T], result: VOID }, - "child.stderr": { argTypes: [CHILD_T], result: VOID }, - /** The piped-input writer (stdio mode 3 on fd 0). child.stdin answers - * `Writable | null`; writes copy borrowed data into the nonblocking - * queue, end/destroy settle it, writable is a pure state read, and - * listener callbacks move into the writer registry. */ - "child.stdin": { argTypes: [CHILD_T], result: VOID }, - /** Under the general stream representation (general-streams.ts), a - * stdio read (slot 0, 1 or 2) answers the child's bridged runtime stream - * — `Writable | null` for stdin, `Readable | null` otherwise; the bridge - * throws when the program lacks the stream unit's boxing helpers. */ - "child.stdioStream": { argTypes: [CHILD_T, F64], result: VOID }, - // Listener registrations: callback func shapes are program-dependent - // (zero-param / Buffer / string / unknown / Buffer-armed union) — the slots pin arity, - // the stream receiver, and the once-flag. - "stream.onData": { argTypes: [CHILDSTREAM_T, null, BOOL], result: VOID }, - "stream.onDataStr": { argTypes: [CHILDSTREAM_T, null, BOOL], result: VOID }, - "stream.onEnd": { argTypes: [CHILDSTREAM_T, null, BOOL], result: VOID }, - "stream.childSetEncoding": { argTypes: [CHILDSTREAM_T, STRING], result: CHILDSTREAM_T }, - "writer.writeString": { argTypes: [CHILDWRITER_T, STRING], result: BOOL }, - "writer.writeBytes": { argTypes: [CHILDWRITER_T, BYTES_U8], result: BOOL }, - "writer.end": { argTypes: [CHILDWRITER_T], result: VOID }, - "writer.destroy": { argTypes: [CHILDWRITER_T], result: VOID }, - "writer.writable": { argTypes: [CHILDWRITER_T], result: BOOL }, - "writer.onDrain": { argTypes: [CHILDWRITER_T, null, BOOL], result: VOID }, - "writer.onFinish": { argTypes: [CHILDWRITER_T, null, BOOL], result: VOID }, - "writer.onError": { argTypes: [CHILDWRITER_T, null, BOOL], result: VOID }, - /** The first-class WritableStream write (`output.write(line)` — the - * prefixStream idiom): the receiver IS the fd scalar (process.stdout/ - * stderr reads mint 1/2), dispatched onto the exact stdoutWrite/ - * stderrWrite paths so buffering and ordering stay identical. Data - * borrowed; the bool is Node's always-true backpressure signal. */ - "procStream.write": { argTypes: [PROCSTREAM_T, STRING], result: BOOL }, - /** process.stdout/stderr flowing into a runtime Writable slot under the - * general stream representation: an fd-backed Writable (+1) whose - * writes take process.stdout.write's synchronous path. */ - /** A pipeline() stage that is a checked-dynamic value: a boxed native - * stream unwraps by identity (+1); anything else throws the given - * not-supported message. Typed as a Duplex so every stage position - * accepts it; the runtime pipeline checks the stream's real sides. */ - "stream.unboxDyn": { - argTypes: [DYN, STRING], - result: { kind: "object", className: "%Duplex" }, - }, - /** Whether pipeline() pumps a checked-dynamic first stage as an - * iterable (a string, or a value with an iterator method that is not a - * stream with pipe() and on()) instead of piping it as a stream. */ - "stream.dynIterableSource": { argTypes: [DYN], result: BOOL }, - /** The Transform a Cipheriv or Decipheriv reads and writes as a stream - * (+1, created on first use and owned by the cipher). */ - "stream.handleStream": { - argTypes: [DYN], - result: { kind: "object", className: "%Transform" }, - }, - /** Checked-dynamic stream slots (dyn-streams.ts): the native stream a - * checked-dynamic value boxes (+1) — a runtime stream with the readable - * (1) or writable (2) side — or null for any other value. Never throws; - * the result union is `%Readable | null` or `%Writable | null`. */ - "stream.dynNative": { argTypes: [DYN, F64], result: VOID }, - /** stream.dynNative for a pipe or unpipe destination: also a - * constructor-function stream's runtime stream, in programs that link - * that unit, unless it overrides write() or end(). */ - "stream.dynNativePipe": { argTypes: [DYN, F64], result: VOID }, - /** readable.pipe(destination, end) into a checked-dynamic destination - * that is not a native stream: [source, the source boxed, destination, - * end]. Node's pipe listener protocol over the destination's members - * (scr_stream_dyn.c); throws what those members throw. */ - "stream.pipeDyn": { argTypes: [null, DYN, DYN, BOOL], result: VOID }, - /** readable.unpipe(destination) for a checked-dynamic destination that - * is not a native stream: [source, destination]. Unpipes the pipe - * stream.pipeDyn registered into it, if any (scr_stream_dyn.c). */ - "stream.unpipeDyn": { argTypes: [null, DYN], result: VOID }, - "stream.stdioWritable": { - argTypes: [PROCSTREAM_T], - result: { kind: "object", className: "%Writable" }, - }, - "child.killed": { argTypes: [CHILD_T], result: BOOL }, - "child.kill": { argTypes: [CHILD_T, STRING], result: BOOL }, - "child.killNum": { argTypes: [CHILD_T, F64], result: BOOL }, - "child.unref": { argTypes: [CHILD_T], result: VOID }, - "child.ref": { argTypes: [CHILD_T], result: VOID }, - "spawnRes.stdout": { argTypes: [SPAWNRES_T], result: STRING }, - "spawnRes.stderr": { argTypes: [SPAWNRES_T], result: STRING }, - /** fs/promises (scr_lib.c over scr_async.c's settled minting): the SAME - * sync syscalls, wrapped in an ALREADY-SETTLED promise — failure - * REJECTS (catchable at the await) instead of throwing, so none of - * these are in the may-throw seed. readFile is utf8-fenced like - * readFileSync. The non-interleaving divergence is documented in - * SEMANTICS.md. */ - /** node:crypto randomness: randomUUID plus randomBytes as either a real - * Buffer or the fused randomBytes(n).toString("hex"|"base64") path. - * The size-taking forms throw Node's RangeError on invalid values. */ - "crypto.randomUUID": { argTypes: [], result: STRING }, - "crypto.randomBytesToString": { argTypes: [F64, STRING], result: STRING }, - /** crypto.randomBytes(n) → a real u8 Buffer (+1). THROWS Node's - * RangeError on out-of-range sizes, exactly like the composed - * randomBytesToString (which keeps its one-libCall lowering — the two - * coexist: the composed form never materializes the Buffer). */ - "crypto.randomBytes": { argTypes: [F64], result: BYTES_U8 }, - /** The fused createHash(alg).update(data).digest(enc) fast path and the - * one-shot crypto.hash implementation. First-class Hash/Hmac handles use - * the entries below; all paths share the incremental runtime core. */ - "crypto.hashDigestStr": { argTypes: [STRING, STRING, STRING], result: STRING }, - "crypto.hashDigestBytes": { argTypes: [STRING, BYTES_U8, STRING], result: STRING }, - /** First-class static Hash/Hmac handles. Constructors validate the - * runtime algorithm string (every digest Node 24 lists); update returns the same - * handle by retained identity, copy snapshots Hash state, and digest - * finalizes the handle and returns either a Buffer or encoded string. */ - "crypto.native": { argTypes: [], result: DYN }, - "crypto.hashNew": { argTypes: [STRING], result: CRYPTOHASH_T }, - /** The Transform a Hash or Hmac reads and writes as a stream (+1, - * created on first use and owned by the value; scr_stream.c). The Piped - * form, for pipe destinations and pipeline stages, also keeps the value - * alive until the stream flushes or is destroyed. */ - "crypto.hashStream": { argTypes: [null], result: { kind: "object", className: "%Transform" } }, - "crypto.hashStreamPiped": { - argTypes: [null], - result: { kind: "object", className: "%Transform" }, - }, - /** createCipheriv (false) / createDecipheriv (true) over checked-dynamic - * cipher, key, iv and options arguments (scr_cipher.c): a native - * Cipheriv/Decipheriv handle whose methods dispatch through dynInvoke. */ - "crypto.cipherNew": { argTypes: [BOOL, DYN, DYN, DYN, DYN], result: DYN }, - /** createECDH(curveName) over a checked-dynamic curve (scr_ecdh.c): a - * native ECDH handle whose methods dispatch through dynInvoke. */ - "crypto.ecdhNew": { argTypes: [DYN], result: DYN }, - /** ECDH.convertKey(key, curve, inputEncoding, outputEncoding, format): - * the converted point as a Buffer or string. */ - "crypto.ecdhConvertKey": { argTypes: [DYN, DYN, DYN, DYN, DYN], result: DYN }, - /** createDiffieHellman(sizeOrKey, keyEncoding, generator, - * generatorEncoding) over checked-dynamic arguments (scr_dh.c): a native - * DiffieHellman handle whose methods dispatch through dynInvoke. */ - "crypto.dhNew": { argTypes: [DYN, DYN, DYN, DYN], result: DYN }, - /** getDiffieHellman(groupName) and createDiffieHellmanGroup(name): a - * native DiffieHellmanGroup handle. */ - "crypto.dhGroupNew": { argTypes: [DYN], result: DYN }, - /** checkPrimeSync(candidate, options) and generatePrimeSync(size, - * options) over checked-dynamic arguments (scr_dh.c): a boolean, and an - * ArrayBuffer or bigint, as checked-dynamic results. The Cb forms take - * the callback and whether its error parameter takes null for Node's - * undefined, and call it in a later macrotask; Node's argument errors - * throw (may-throw). */ - "crypto.checkPrimeSync": { argTypes: [DYN, DYN], result: DYN }, - /** getCipherInfo(nameOrNid, options) over checked-dynamic arguments - * (scr_cipher_info.c): the info object or undefined. */ - "crypto.getCipherInfo": { argTypes: [DYN, DYN], result: DYN }, - "crypto.checkPrimeCb": { argTypes: [DYN, DYN, DYN, BOOL], result: VOID }, - "crypto.generatePrimeSync": { argTypes: [DYN, DYN], result: DYN }, - "crypto.generatePrimeCb": { argTypes: [DYN, DYN, DYN, BOOL], result: VOID }, - "crypto.hmacNewStr": { argTypes: [STRING, STRING], result: CRYPTOHMAC_T }, - "crypto.hmacNewBytes": { argTypes: [STRING, BYTES_U8], result: CRYPTOHMAC_T }, - "crypto.hashUpdateStr": { argTypes: [CRYPTOHASH_T, STRING], result: CRYPTOHASH_T }, - "crypto.hashUpdateBytes": { argTypes: [CRYPTOHASH_T, BYTES_U8], result: CRYPTOHASH_T }, - "crypto.hmacUpdateStr": { argTypes: [CRYPTOHMAC_T, STRING], result: CRYPTOHMAC_T }, - "crypto.hmacUpdateBytes": { argTypes: [CRYPTOHMAC_T, BYTES_U8], result: CRYPTOHMAC_T }, - "crypto.hashCopy": { argTypes: [CRYPTOHASH_T], result: CRYPTOHASH_T }, - "crypto.hashDigestString": { argTypes: [CRYPTOHASH_T, STRING], result: STRING }, - "crypto.hashDigestBuffer": { argTypes: [CRYPTOHASH_T], result: BYTES_U8 }, - "crypto.hmacDigestString": { argTypes: [CRYPTOHMAC_T, STRING], result: STRING }, - "crypto.hmacDigestBuffer": { argTypes: [CRYPTOHMAC_T], result: BYTES_U8 }, - /** The option and any-value forms, with Node's checks at run time. The - * Dyn digests return a string or a Buffer, and crypto.hash's Dyn form - * either one by its outputEncoding. */ - "crypto.hashNewOpts": { argTypes: [STRING, DYN], result: CRYPTOHASH_T }, - "crypto.hmacNewDyn": { argTypes: [STRING, DYN, DYN], result: CRYPTOHMAC_T }, - "crypto.hashCopyOpts": { argTypes: [CRYPTOHASH_T, DYN], result: CRYPTOHASH_T }, - "crypto.hashUpdateEnc": { argTypes: [CRYPTOHASH_T, STRING, STRING], result: CRYPTOHASH_T }, - "crypto.hmacUpdateEnc": { argTypes: [CRYPTOHMAC_T, STRING, STRING], result: CRYPTOHMAC_T }, - "crypto.hashUpdateDyn": { argTypes: [CRYPTOHASH_T, DYN, DYN], result: CRYPTOHASH_T }, - "crypto.hmacUpdateDyn": { argTypes: [CRYPTOHMAC_T, DYN, DYN], result: CRYPTOHMAC_T }, - "crypto.hashDigestDyn": { argTypes: [CRYPTOHASH_T, DYN], result: DYN }, - "crypto.hmacDigestDyn": { argTypes: [CRYPTOHMAC_T, DYN], result: DYN }, - "crypto.hashOneshot": { argTypes: [STRING, DYN, DYN], result: DYN }, - /** Views of any element kind (the validator checks both are views). */ - "crypto.timingSafeEqual": { argTypes: [null, null], result: BOOL }, - "crypto.timingSafeEqualDyn": { argTypes: [DYN, DYN], result: BOOL }, - "crypto.randomFill": { argTypes: [BYTES_U8, F64, F64], result: BYTES_U8 }, - "crypto.randomFillRest": { argTypes: [BYTES_U8, F64], result: BYTES_U8 }, - "crypto.randomInt": { argTypes: [F64, F64], result: F64 }, - "crypto.randomIntMax": { argTypes: [F64], result: F64 }, - /** randomFillSync over any view returns that view at its own type (the - * validator checks the result against the first argument). The Dyn form - * takes ArrayBuffers and other values. The callback forms carry - * randomFill's argument count before the callback; randomIntCb carries - * whether min was given. */ - "crypto.randomFillView": { argTypes: [null, F64, F64], result: BYTES_U8 }, - "crypto.randomFillViewRest": { argTypes: [null, F64], result: BYTES_U8 }, - /** crypto.getRandomValues: a view returns itself at its own type (the - * float/size DOMExceptions are thrown at run time); any other value - * takes the checked form. */ - "crypto.getRandomValues": { argTypes: [null], result: BYTES_U8 }, - "crypto.getRandomValuesDyn": { argTypes: [DYN], result: DYN }, - "crypto.randomFillSyncDyn": { argTypes: [DYN, DYN, DYN], result: DYN }, - "crypto.randomFillCb": { argTypes: [null, F64, F64, F64, null], result: VOID }, - "crypto.randomFillCbDyn": { argTypes: [DYN, DYN, DYN, F64, null], result: VOID }, - "crypto.randomIntCb": { argTypes: [F64, F64, F64, null], result: VOID }, - "crypto.randomUUIDOpts": { argTypes: [DYN], result: STRING }, - /** Secret KeyObjects: native handles whose getters and methods dispatch - * through the handle. keyObjectInput reads a key's bytes for hkdf. */ - "crypto.createSecretKey": { argTypes: [DYN, DYN], result: DYN }, - "crypto.generateKeySync": { argTypes: [DYN, DYN], result: DYN }, - "crypto.generateKeyCb": { argTypes: [DYN, DYN, null], result: VOID }, - "crypto.keyObjectInput": { argTypes: [DYN], result: BYTES_U8 }, - "crypto.isKeyObject": { argTypes: [DYN], result: BOOL }, - /** WebCrypto (scr_webcrypto.c): each method takes its argument vector as - * one dyn array and answers a promise that argument and validation - * failures reject. CryptoKey values are native handles. */ - "webcrypto.generateKey": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, - "webcrypto.importKey": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, - "webcrypto.exportKey": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, - "webcrypto.encrypt": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, - "webcrypto.decrypt": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, - "webcrypto.wrapKey": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, - "webcrypto.unwrapKey": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, - "webcrypto.deriveBits": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, - "webcrypto.deriveKey": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, - "webcrypto.sign": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, - "webcrypto.verify": { argTypes: [DYN], result: { kind: "promise", inner: BOOL } }, - "webcrypto.digest": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, - "webcrypto.isCryptoKey": { argTypes: [DYN], result: BOOL }, - "webcrypto.object": { argTypes: [], result: DYN }, - "crypto.randomUUIDv7": { argTypes: [DYN], result: STRING }, - "crypto.pbkdf2": { argTypes: [BYTES_U8, BYTES_U8, F64, F64, STRING], result: BYTES_U8 }, - "crypto.randomBytesCb": { argTypes: [F64, null], result: VOID }, - "crypto.pbkdf2Cb": { argTypes: [BYTES_U8, BYTES_U8, F64, F64, STRING, null], result: VOID }, - "crypto.hkdf": { argTypes: [STRING, BYTES_U8, BYTES_U8, BYTES_U8, F64], result: DYN }, - "crypto.hkdfCb": { argTypes: [STRING, BYTES_U8, BYTES_U8, BYTES_U8, F64, null], result: VOID }, - "crypto.scrypt": { argTypes: [BYTES_U8, BYTES_U8, F64, DYN], result: BYTES_U8 }, - "crypto.scryptCb": { argTypes: [BYTES_U8, BYTES_U8, F64, DYN, null], result: VOID }, - /** util.promisify over the callback forms: the callback form's - * arguments without the callback → a promise the callback form settles, - * or rejected with an argument error; never throws. The result's value - * type is the declared one (a Buffer, the filled view, a number, or a - * checked-dynamic value); the validator checks it. */ - "crypto.randomBytesPromise": { argTypes: [F64], result: VOID }, - "crypto.pbkdf2Promise": { argTypes: [BYTES_U8, BYTES_U8, F64, F64, STRING], result: VOID }, - "crypto.scryptPromise": { argTypes: [BYTES_U8, BYTES_U8, F64, DYN], result: VOID }, - "crypto.hkdfPromise": { argTypes: [STRING, BYTES_U8, BYTES_U8, BYTES_U8, F64], result: VOID }, - "crypto.randomFillPromise": { argTypes: [null, F64, F64, F64], result: VOID }, - "crypto.randomFillPromiseDyn": { argTypes: [DYN, DYN, DYN, F64], result: VOID }, - "crypto.randomIntPromise": { argTypes: [F64, F64, F64], result: VOID }, - "crypto.generateKeyPromise": { argTypes: [DYN, DYN], result: VOID }, - /** util.promisify(dns.lookup) and util.promisify(dns.lookupService): - * [hostname, options] and [address, port] → a promise of the - * checked-dynamic result object (the address array with options.all), - * or rejected with the error; never throws. */ - "dns.lookupPromise": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, - "dns.lookupServicePromise": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, - // The Buffer statics and the fs/zlib Buffer forms: fixed always-u8 - // signatures (Buffer IS a Uint8Array — one bytes kind). - /** The Buffer statics with fixed (always-u8) signatures. fromStr is - * `Buffer.from(string, enc)` — the frontend completes an omitted - * encoding to "utf8" and fences non-literal/unsupported ones; hex and - * base64 decode Node-leniently, so it never throws. concat takes ONE - * bytes[] arg (the list) and returns a fresh copy. `Buffer.from(u8)` - * and `Buffer.alloc(n)` need no libFn — they lower to bytesNew. */ - "buffer.fromStr": { argTypes: [STRING, STRING], result: BYTES_U8 }, - "buffer.fromStrChecked": { argTypes: [STRING, STRING], result: BYTES_U8 }, - "buffer.brand": { argTypes: [BYTES_U8], result: BYTES_U8 }, - /** Buffer.isBuffer over a typed view: whether the view carries the - * Buffer brand (any element kind; only Buffers do). Never throws. */ - "buffer.isBranded": { argTypes: [null], result: BOOL }, - /** Buffer.from on checked-native strings, bytes, arrays and data-only - * array-like/Buffer-JSON objects. The encoding is a normalized literal; - * non-string inputs ignore it. Copies the input and may throw during - * element coercion or argument validation. Custom object valueOf and - * opaque reference inputs retain explicit runtime refusals. */ - "buffer.fromDyn": { argTypes: [DYN, STRING], result: BYTES_U8 }, - "buffer.concat": { argTypes: [arrayOf(BYTES_U8)], result: BYTES_U8 }, - "buffer.concatDyn": { argTypes: [DYN], result: BYTES_U8 }, - /** The pooled Buffer factories (Node's allocate/fromStringFast/ - * fromArrayLike): allocUnsafe, Buffer.from of strings, Uint8Arrays, - * number[] and checked values, and concat return views into the - * per-thread pool slab below Buffer.poolSize >>> 1 bytes. alloc and - * allocUnsafeSlow never pool. The size forms validate like Node - * (ERR_OUT_OF_RANGE). poolSize reads and writes Buffer.poolSize. */ - "buffer.alloc": { argTypes: [F64], result: BYTES_U8 }, - /** Buffer.alloc as a function value: the size, fill and encoding arrive - * unchecked, and the runtime fills as Node's alloc does. */ - "buffer.allocValue": { argTypes: [DYN, DYN, DYN], result: BYTES_U8 }, - "buffer.allocUnsafe": { argTypes: [F64], result: BYTES_U8 }, - "buffer.allocUnsafeSlow": { argTypes: [F64], result: BYTES_U8 }, - "buffer.poolFromStr": { argTypes: [STRING, STRING], result: BYTES_U8 }, - "buffer.poolFromStrChecked": { argTypes: [STRING, STRING], result: BYTES_U8 }, - "buffer.poolFromBytes": { argTypes: [BYTES_U8], result: BYTES_U8 }, - "buffer.poolFromArray": { argTypes: [arrayOf(F64)], result: BYTES_U8 }, - "buffer.poolFromDyn": { argTypes: [DYN, STRING], result: BYTES_U8 }, - /** poolFromDyn that also copies an array crossing by reference. */ - "buffer.poolFromDynRef": { argTypes: [DYN, STRING], result: BYTES_U8 }, - "buffer.poolFromDynOffset": { argTypes: [DYN, DYN], result: BYTES_U8 }, - /** Buffer.from(value, byteOffset, length): an ArrayBuffer's range with - * Node's fromArrayBuffer checks; other values as poolFromDynOffset. */ - "buffer.poolFromDynRange": { argTypes: [DYN, DYN, DYN], result: BYTES_U8 }, - "buffer.poolSize": { argTypes: [], result: F64 }, - "buffer.setPoolSize": { argTypes: [F64], result: VOID }, - /** Buffer.byteLength(string, enc) — enc a NORMALIZED literal like - * fromStr's — and Buffer.isEncoding(name) over a runtime string - * (case-insensitive against Node's alias set). Pure; never throw. */ - "buffer.byteLenDyn": { argTypes: [DYN, STRING], result: F64 }, - /** Buffer.byteLength as a function value: the encoding arrives at run time. */ - "buffer.byteLenValue": { argTypes: [DYN, DYN], result: F64 }, - "buffer.byteLenStr": { argTypes: [STRING, STRING], result: F64 }, - "buffer.isEncoding": { argTypes: [STRING], result: BOOL }, - /** Buffer.concat(list, totalLength): the concatenation truncated or - * zero-padded to the total. THROWS Node's 'length' RangeError on a - * negative/non-integer total (may-throw seed). */ - "buffer.concatLen": { argTypes: [arrayOf(BYTES_U8), F64], result: BYTES_U8 }, - "buffer.concatLenDyn": { argTypes: [DYN, F64], result: BYTES_U8 }, - // The checked-dynamic compare/equals validators (Node's argument - // ladders over dyn-boxed invalid-input probes). - /** The checked-dynamic compare/equals validators (scr_bytes_io.c) — - * the lowered form when an argument is NOT statically bytes (the - * invalid-input probes; a dyn from an untyped JS helper): Node's own - * argument ladders run at runtime — ERR_INVALID_ARG_TYPE with the - * API's argument name ("buf1"/"buf2", "otherBuffer", "target"; offsets - * "of type number"), validateOffset's ERR_OUT_OF_RANGE for bad - * numbers, undefined offsets taking their Node defaults — and a - * well-typed value still computes the real answer. All args borrowed - * dyn; compareChk's four offset slots pass the undefined dyn when - * syntactically absent. May-throw seeds. */ - "buffer.compareChk": { argTypes: [DYN, DYN], result: F64 }, - "bytes.equalsChk": { argTypes: [BYTES_U8, DYN], result: BOOL }, - "bytes.compareChk": { argTypes: [BYTES_U8, DYN, DYN, DYN, DYN, DYN], result: F64 }, - /** The deprecated `new Buffer(number, 'enc')` string-arm rejection: - * always throws Node's ERR_INVALID_ARG_TYPE ("The \"string\" argument - * must be of type string. Received ..."). Borrowed dyn; may-throw. */ - "buffer.newStringFail": { argTypes: [DYN], result: BYTES_U8 }, - "buffer.deprecation": { argTypes: [], result: VOID }, - "buffer.deprecationCount": { argTypes: [], result: VOID }, - "buffer.constructor": { argTypes: [], result: DYN }, - "buffer.installValue": { argTypes: [], result: VOID }, - "buffer.staticValue": { argTypes: [STRING], result: DYN }, - "buffer.prototypeMember": { argTypes: [DYN], result: DYN }, - /** fs._toUnixTimestamp(time) over a dyn value: numeric strings and - * finite numbers coerce (negatives answer now/1000, Node's shape); - * everything else throws Node's ERR_INVALID_ARG_TYPE. May-throw. */ - "fs.toUnixTimestamp": { argTypes: [DYN], result: F64 }, - /** The fs argument-validation ladders (checked-dynamic lane): each Chk - * replicates its API's Node-order validation over dyn values (Node's - * exact typed errors — ERR_INVALID_ARG_TYPE/VALUE, ERR_OUT_OF_RANGE), - * and a full pass meets the trailing compiler-rendered SC2020 fence - * string — so the ALWAYS-THROW forms take the error.nodeThrow - * polymorphic-result carve-out. mkdtempSyncChk and the lchmod sync/ - * promise pair run the REAL operation on a validated pass instead - * (macOS lchmod(2); non-APPLE answers Node's not-a-function / - * ERR_METHOD_NOT_IMPLEMENTED shapes). May-throw seeds, all of them. */ - "fs.existsChk": { argTypes: [DYN, DYN], result: DYN }, - "fs.mkdtempChk": { argTypes: [DYN, DYN, STRING], result: VOID }, - "fs.mkdtempSyncChk": { argTypes: [DYN, DYN, STRING], result: STRING }, - "fs.readFileChk": { argTypes: [DYN, DYN, DYN, STRING], result: VOID }, - "fs.opendirChk": { argTypes: [DYN, DYN, STRING], result: VOID }, - "fs.watchFileChk": { argTypes: [DYN, DYN, STRING], result: VOID }, - "fs.lchmodChk": { argTypes: [DYN, DYN, DYN, STRING], result: VOID }, - "fs.lchmodSyncChk": { argTypes: [DYN, DYN], result: DYN }, - "fsp.lchmodChk": { argTypes: [DYN, DYN], result: { kind: "promise", inner: VOID } }, - "fs.readChk": { argTypes: [DYN, DYN, DYN, DYN, DYN, STRING], result: VOID }, - "fs.streamOptsChk": { argTypes: [DYN, DYN, STRING], result: VOID }, - /** fs.ReadStream / fs.WriteStream (scr_fs_stream.c): the constructors - * take the path and options as dyn values and throw Node's option - * errors; the members read bytesRead/bytesWritten, pending and the path - * value, and close() / close(cb) (a `() => void` callback). */ - "fs.createReadStream": { - argTypes: [DYN, DYN], - result: { kind: "object", className: "%Readable" }, - }, - "fs.createWriteStream": { - argTypes: [DYN, DYN], - result: { kind: "object", className: "%Writable" }, - }, - "fs.fsStreamBytes": { argTypes: [null], result: F64 }, - "fs.fsStreamPending": { argTypes: [null], result: BOOL }, - "fs.fsStreamPath": { argTypes: [null], result: DYN }, - "fs.fsStreamPropDyn": { argTypes: [null, STRING], result: DYN }, - "fileHandle.createReadStream": { - argTypes: [FILEHANDLE_T, DYN], - result: { kind: "object", className: "%Readable" }, - }, - "fileHandle.createWriteStream": { - argTypes: [FILEHANDLE_T, DYN], - result: { kind: "object", className: "%Writable" }, - }, - "fs.fsStreamClose": { argTypes: [null], result: VOID }, - "fs.fsStreamCloseCb": { argTypes: [null, funcOf([], VOID)], result: VOID }, - /** The compiler-resolved ERR_INVALID_ARG_TYPE throw with a RUNTIME- - * rendered Received tail: args [argname, "of type ..." clause, the - * offending dyn value]. ALWAYS THROWS; polymorphic result (the - * error.nodeThrow pattern). May-throw seed. */ - "error.argTypeThrow": { argTypes: [STRING, STRING, DYN], result: VOID }, - /** The property flavor of argTypeThrow ("The \"options.x\" property - * must be ..."): the option-bag ladders' provably-invalid arms. ALWAYS - * THROWS; polymorphic result. May-throw seed. */ - "error.propTypeThrow": { argTypes: [STRING, STRING, DYN], result: VOID }, - /** The checked-dynamic max-listeners ladders: setMaxChk is the - * instance form over a dyn n (non-numbers ERR_INVALID_ARG_TYPE, - * negatives/NaN ERR_OUT_OF_RANGE; +1 receiver back — chaining); - * setDefaultMaxChk is the static/property form, its second argument - * naming the message slot ("setMaxListeners" for the static call, - * "defaultMaxListeners" for the module-property assignment). */ - "emitter.setMaxChk": { argTypes: [null, DYN], result: VOID }, - "emitter.setDefaultMaxChk": { argTypes: [DYN, STRING], result: VOID }, - /** The Buffer forms of fs: readFileSync(path) with NO - * encoding → bytes (+1), writeFileSync/appendFileSync(path, bytes), and the - * fs/promises readFile(path) no-encoding form (an already-settled - * promise, rejecting on failure like the other fsp members). The sync - * forms THROW catchably on failure exactly like the utf8 forms. */ - "fs.readFileSyncBytes": { argTypes: [STRING], result: BYTES_U8 }, - "fs.writeFileSyncBytes": { argTypes: [STRING, BYTES_U8], result: VOID }, - "fs.appendFileSyncBytes": { argTypes: [STRING, BYTES_U8], result: VOID }, - "fsp.readFileBytes": { argTypes: [STRING], result: { kind: "promise", inner: BYTES_U8 } }, - /** node:zlib (scr_zlib.c — native-toolchain.ts compiles/links it ONLY when these - * appear on the IR, the regex/libcurl gating precedent): one-shot zlib, - * raw-DEFLATE, gzip, and auto-detect codecs over u8 bytes with Node's - * default options, or a validated literal compression level from -1 to 9. - * Compression never throws (OOM aborts); decompression - * of corrupt input THROWS Node's error catchably. */ - "zlib.deflateSync": { argTypes: [BYTES_U8], result: BYTES_U8 }, - "zlib.inflateSync": { argTypes: [BYTES_U8], result: BYTES_U8 }, - "zlib.deflateRawSync": { argTypes: [BYTES_U8], result: BYTES_U8 }, - /** bytes, mode (0 zlib / 1 raw / 2 gzip), validated compression level. */ - "zlib.deflateLevelSync": { argTypes: [BYTES_U8, F64, F64], result: BYTES_U8 }, - "zlib.inflateRawSync": { argTypes: [BYTES_U8], result: BYTES_U8 }, - "zlib.gzipSync": { argTypes: [BYTES_U8], result: BYTES_U8 }, - "zlib.gunzipSync": { argTypes: [BYTES_U8], result: BYTES_U8 }, - "zlib.unzipSync": { argTypes: [BYTES_U8], result: BYTES_U8 }, - /** The default-options callback twins run on the executable's shared - * native work pool and deliver (Error | null, Buffer) on a later loop - * turn. crc32 validates its optional uint32 seed synchronously. */ - "zlib.deflateCb": { argTypes: [BYTES_U8, null], result: VOID }, - "zlib.inflateCb": { argTypes: [BYTES_U8, null], result: VOID }, - "zlib.deflateRawCb": { argTypes: [BYTES_U8, null], result: VOID }, - "zlib.inflateRawCb": { argTypes: [BYTES_U8, null], result: VOID }, - "zlib.gzipCb": { argTypes: [BYTES_U8, null], result: VOID }, - "zlib.gunzipCb": { argTypes: [BYTES_U8, null], result: VOID }, - "zlib.unzipCb": { argTypes: [BYTES_U8, null], result: VOID }, - "zlib.crc32": { argTypes: [BYTES_U8, F64], result: F64 }, - /** The one-shot forms with an options value: node_zlib_mode, the input, - * the options (validated at runtime with Node's ladder). The Cb form - * takes the program-shaped (Error | null, Buffer) callback, which moves. */ - "zlib.syncOpts": { argTypes: [F64, BYTES_U8, DYN], result: BYTES_U8 }, - "zlib.cbOpts": { argTypes: [F64, BYTES_U8, DYN, null], result: VOID }, - /** The checked-dynamic input twins (the JS lane's untyped data). */ - "zlib.syncOptsDyn": { argTypes: [F64, DYN, DYN], result: BYTES_U8 }, - "zlib.cbOptsDyn": { argTypes: [F64, DYN, DYN, null], result: VOID }, - /** util.promisify over the callback one-shots: [mode, data, options] - * like zlib.cbOpts → a promise the worker-pool run settles with the - * Buffer or the callback form's Error. An options or input error rejects - * it; never throws. The Dyn twin takes the JS lane's untyped data. */ - "zlib.promise": { argTypes: [F64, BYTES_U8, DYN], result: { kind: "promise", inner: BYTES_U8 } }, - "zlib.promiseDyn": { argTypes: [F64, DYN, DYN], result: { kind: "promise", inner: BYTES_U8 } }, - /** The stream classes (scr_zlib_stream.c, linked with the stream unit): - * streamNew takes Node's node_zlib_mode number and the options value - * (undefined when absent), validates it with Node's ladder, and answers - * the +1 %Transform stream. flush takes the kind value, params the level - * and strategy values; the Cb forms move their () => void callback. The - * receivers are borrowed. */ - /** Connects scr_brotli.c to the zlib engine (%main, before any module). */ - "zlib.brotliInstall": { argTypes: [], result: VOID }, - "zlib.streamNew": { argTypes: [F64, DYN], result: VOID }, - "zlib.streamBytesWritten": { argTypes: [null], result: F64 }, - /** `stream instanceof zlib.Gzip`: the borrowed stream and the class's - * node_zlib_mode; true when the stream is a zlib stream of that mode. */ - "zlib.streamIs": { argTypes: [null, F64], result: BOOL }, - "zlib.streamFlush": { argTypes: [null, DYN], result: VOID }, - "zlib.streamFlushCb": { argTypes: [null, DYN, null], result: VOID }, - "zlib.streamParams": { argTypes: [null, DYN, DYN], result: VOID }, - "zlib.streamParamsCb": { argTypes: [null, DYN, DYN, null], result: VOID }, - "zlib.streamClose": { argTypes: [null], result: VOID }, - "zlib.streamCloseCb": { argTypes: [null, null], result: VOID }, - "zlib.streamReset": { argTypes: [null], result: VOID }, - /** The Buffer overloads of the raw stream writes — same promptly - * submitted streams as process.stdoutWrite/stderrWrite, constantly true. - * The encoding arg is evaluated but ignored for bytes, like Node. The Cb - * forms move their program-shaped completion callback to the tick queue. */ - "process.stdoutWriteBytes": { argTypes: [BYTES_U8, STRING], result: BOOL }, - "process.stderrWriteBytes": { argTypes: [BYTES_U8, STRING], result: BOOL }, - // Completion callback is program-dependent: zero params, checked-dynamic, - // or an optional Error | null slot (same success shape as fs.rename). - "process.stdoutWriteBytesCb": { argTypes: [BYTES_U8, STRING, null], result: BOOL }, - "process.stderrWriteBytesCb": { argTypes: [BYTES_U8, STRING, null], result: BOOL }, - /** The value of a FULFILLED promise, read without a microtask turn (+1 - * for references): the tuple form of Promise.all reads its entries this - * way once the combinator fulfills, each entry widened to Promise - * and read at the type it was built with (program-dependent). */ - "promise.fulfilledValue": { argTypes: [null], result: VOID }, - /** Promise.all's tuple form as a value: the entries (each widened to - * Promise) join the runtime combinator, and when it fulfills the - * function reads the fulfilled entries into the tuple inside that - * settlement, so the result settles on the combinator's turn; a - * rejection settles it the same way. The result is the tuple's promise - * (program-dependent). */ - "promise.allTuple": { argTypes: [null, null], result: VOID }, - "fsp.readFile": { argTypes: [STRING, STRING], result: { kind: "promise", inner: STRING } }, - "fsp.writeFile": { argTypes: [STRING, STRING], result: { kind: "promise", inner: VOID } }, - /** fs.promises.writeFile(path, data, { mode }): the settled-promise - * twin of fs.writeFileModeSync. */ - "fsp.writeFileMode": { - argTypes: [STRING, STRING, F64], - result: { kind: "promise", inner: VOID }, - }, - "fsp.mkdir": { argTypes: [STRING], result: { kind: "promise", inner: VOID } }, - /** The fs/promises option/member tail the certs pipeline uses: mkdir's - * literal { recursive?, mode? } options (the mkdirSync matrix behind - * settled promises), unlink, chmod. Failures REJECT (catchable at the - * await), like the rest of the fsp family. */ - "fsp.mkdirMode": { argTypes: [STRING, F64], result: { kind: "promise", inner: VOID } }, - "fsp.mkdirRecursive": { argTypes: [STRING], result: { kind: "promise", inner: VOID } }, - "fsp.mkdirRecursiveMode": { argTypes: [STRING, F64], result: { kind: "promise", inner: VOID } }, - "fsp.unlink": { argTypes: [STRING], result: { kind: "promise", inner: VOID } }, - "fsp.chmod": { argTypes: [STRING, F64], result: { kind: "promise", inner: VOID } }, - "fsp.chown": { argTypes: [STRING, F64, F64], result: { kind: "promise", inner: VOID } }, - "fsp.lchown": { argTypes: [STRING, F64, F64], result: { kind: "promise", inner: VOID } }, - "fsp.access": { argTypes: [STRING, F64], result: { kind: "promise", inner: VOID } }, - "fsp.truncate": { argTypes: [STRING, F64], result: { kind: "promise", inner: VOID } }, - "fsp.appendFile": { argTypes: [STRING, STRING], result: { kind: "promise", inner: VOID } }, - "fsp.appendFileBytes": { argTypes: [STRING, BYTES_U8], result: { kind: "promise", inner: VOID } }, - "fsp.copyFile": { argTypes: [STRING, STRING], result: { kind: "promise", inner: VOID } }, - "fsp.mkdtemp": { argTypes: [STRING], result: { kind: "promise", inner: STRING } }, - /** readFile(path, encoding | { encoding }) for any runtime encoding name. */ - "fsp.readFileEncoded": { argTypes: [STRING, STRING], result: { kind: "promise", inner: STRING } }, - "fsp.rmdir": { argTypes: [STRING], result: { kind: "promise", inner: VOID } }, - "fsp.link": { argTypes: [DYN, DYN], result: { kind: "promise", inner: VOID } }, - "fsp.symlink": { argTypes: [DYN, DYN, DYN], result: { kind: "promise", inner: VOID } }, - "fsp.cp": { argTypes: [DYN, DYN, DYN], result: { kind: "promise", inner: VOID } }, - "fsp.readlink": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, - "fsp.statfs": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, - "fsp.readlinkStr": { argTypes: [DYN, DYN], result: { kind: "promise", inner: STRING } }, - "fsp.readlinkBuffer": { argTypes: [DYN, DYN], result: { kind: "promise", inner: BYTES_U8 } }, - "fsp.utimes": { argTypes: [DYN, DYN, DYN], result: { kind: "promise", inner: VOID } }, - "fsp.lutimes": { argTypes: [DYN, DYN, DYN], result: { kind: "promise", inner: VOID } }, - "fsp.rename": { argTypes: [STRING, STRING], result: { kind: "promise", inner: VOID } }, - "fsp.readdir": { argTypes: [STRING], result: { kind: "promise", inner: arrayOf(STRING) } }, - // Result is promise; the libCall case - // validates the program-dependent record shape in validate.ts. - /** `fs.promises.readdir(path, { withFileTypes: true })` — the settled- - * promise twin of fs.readdirTypesSync. The backends assemble the same - * call-site-shaped Dirent rows, then move the array into a promise; - * scandir failure becomes its rejection. */ - "fsp.readdirTypes": { argTypes: [STRING], result: { kind: "promise", inner: VOID } }, - "fsp.rm": { argTypes: [STRING], result: { kind: "promise", inner: VOID } }, - /** `fs.promises.rm(path, options)`: fs.rmOptsSync and fs.rmRetrySync - * behind a settled promise; their errors become its rejection. */ - "fsp.rmOpts": { argTypes: [STRING, BOOL, BOOL], result: { kind: "promise", inner: VOID } }, - "fsp.rmRetry": { - argTypes: [STRING, BOOL, BOOL, F64, F64], - result: { kind: "promise", inner: VOID }, - }, - "fsp.stat": { argTypes: [STRING], result: { kind: "promise", inner: STATS_T } }, - "fsp.realpath": { argTypes: [STRING], result: { kind: "promise", inner: STRING } }, - "fsp.lstat": { argTypes: [STRING], result: { kind: "promise", inner: STATS_T } }, - /** fs/promises.open and the statically represented FileHandle surface. - * Every operation returns an already-settled promise; syscall failures - * become rejections rather than escaping synchronously. read/write - * results are call-site record shapes ({ bytesRead/bytesWritten, - * buffer }) assembled by the backends around the fixed runtime ABI. */ - "fsp.open": { argTypes: [STRING, STRING, F64], result: { kind: "promise", inner: FILEHANDLE_T } }, - "fileHandle.fd": { argTypes: [FILEHANDLE_T], result: F64 }, - "fileHandle.close": { argTypes: [FILEHANDLE_T], result: { kind: "promise", inner: VOID } }, - "fileHandle.sync": { argTypes: [FILEHANDLE_T], result: { kind: "promise", inner: VOID } }, - "fileHandle.datasync": { argTypes: [FILEHANDLE_T], result: { kind: "promise", inner: VOID } }, - "fileHandle.truncate": { - argTypes: [FILEHANDLE_T, F64], - result: { kind: "promise", inner: VOID }, - }, - "fileHandle.chmod": { argTypes: [FILEHANDLE_T, F64], result: { kind: "promise", inner: VOID } }, - "fileHandle.utimes": { - argTypes: [FILEHANDLE_T, DYN, DYN], - result: { kind: "promise", inner: VOID }, - }, - "fileHandle.readv": { - argTypes: [FILEHANDLE_T, arrayOf(BYTES_U8), F64], - result: { kind: "promise", inner: VOID }, - }, - "fileHandle.writev": { - argTypes: [FILEHANDLE_T, arrayOf(BYTES_U8), F64], - result: { kind: "promise", inner: VOID }, - }, - // read/write carry call-site result record shapes; the validator checks - // those in validate.ts, so promise is only a table sentinel. - "fileHandle.read": { - argTypes: [FILEHANDLE_T, BYTES_U8, F64, F64, F64, BOOL], - result: { kind: "promise", inner: VOID }, - }, - "fileHandle.writeBytes": { - argTypes: [FILEHANDLE_T, BYTES_U8, F64, F64, F64, BOOL], - result: { kind: "promise", inner: VOID }, - }, - "fileHandle.writeStr": { - argTypes: [FILEHANDLE_T, STRING, F64, STRING], - result: { kind: "promise", inner: VOID }, - }, - "fileHandle.readFile": { - argTypes: [FILEHANDLE_T, STRING], - result: { kind: "promise", inner: STRING }, - }, - "fileHandle.readFileBytes": { - argTypes: [FILEHANDLE_T, STRING], - result: { kind: "promise", inner: BYTES_U8 }, - }, - "fileHandle.writeFile": { - argTypes: [FILEHANDLE_T, STRING, STRING], - result: { kind: "promise", inner: VOID }, - }, - "fileHandle.writeFileBytes": { - argTypes: [FILEHANDLE_T, BYTES_U8, STRING], - result: { kind: "promise", inner: VOID }, - }, - "fileHandle.stat": { argTypes: [FILEHANDLE_T], result: { kind: "promise", inner: STATS_T } }, - "process.argv": { argTypes: [], result: arrayOf(STRING) }, - // The Node runtime flag a node:test binary took out of process.argv - // (--test-update-snapshots), or [] — a fresh array per read. - "process.execArgv": { argTypes: [], result: arrayOf(STRING) }, - "process.platform": { argTypes: [], result: STRING }, - // The one libCall whose result type is program-dependent (union ids are - // per-module): the `result` here is a placeholder — the libCall case - // checks the union's ARMS ([string, undefinedT] in canonical order) - // against the module's registry instead. - /** getenv(3): one string key arg → the interned `string | undefined` - * union (present: +1 string wrapped into the string arm; absent: the - * interned undefined-arm instance). BOTH source forms — `process.env.FOO` - * and `process.env[expr]` — lower here. Purely static; never throws. */ - "process.envGet": { argTypes: [STRING], result: VOID }, - /** setenv(3): (name, value) string args → void. Later envGet reads and - * spawned children observe the write, like Node (values are strings — - * the frontend fences non-string RHS). Never throws. */ - "process.envSet": { argTypes: [STRING, STRING], result: VOID }, - /** `delete process.env[NAME]` — unsetenv(3): the mutation is visible to - * every later read (process.envGet asks getenv fresh) and inherited by - * spawned children, exactly Node. Statement position only (JS's boolean - * result is constant true there). Borrows the name; never throws. */ - "process.envUnset": { argTypes: [STRING], result: VOID }, - /** The whole environment as alternating [k0, v0, k1, v1, ...] strings in - * environ order — the raw material of the process.env SNAPSHOT record - * (the frontend's interned %env.snapshot helper keyed-writes the pairs - * into a fresh `{ [k: string]: string | undefined }` record). Fresh +1 - * array; never throws. */ - "process.envPairs": { argTypes: [], result: arrayOf(STRING) }, - "process.exit": { argTypes: [F64], result: VOID }, - /** Numeric process.exitCode write (integer validation, implicit exit status). */ - "process.setExitCode": { argTypes: [F64], result: VOID }, - /** The process.exitCode write of a program that also reads the - * property: the same validation, and the code counts as assigned. */ - "process.setExitCodeTracked": { argTypes: [F64], result: VOID }, - /** The code for process.exit() with no argument, or zero when unset. */ - "process.currentExitCode": { argTypes: [], result: F64 }, - /** Whether process.exitCode reads a code rather than undefined. Never throws. */ - "process.hasExitCode": { argTypes: [], result: BOOL }, - "process.cwd": { argTypes: [], result: STRING }, - /** getpid(2) / getuid(2): zero args → f64. POSIX-only target, so both - * always answer (the checker's `getuid?` optionality covers Windows — - * `process.getuid?.()` lowers as the plain call). Never throw. */ - "process.pid": { argTypes: [], result: F64 }, - "dyn.this": { argTypes: [], result: DYN }, - "dyn.generatorThis": { argTypes: [], result: DYN }, - "process.getuid": { argTypes: [], result: F64 }, - "process.getgid": { argTypes: [], result: F64 }, - /** geteuid(2) / getegid(2) / getgroups(2) (the effective gid appended - * when the list lacks it, like Node). Windows has no such members: the - * calls throw the TypeError a missing member does (MAY THROW). */ - "process.geteuid": { argTypes: [], result: F64 }, - "process.getegid": { argTypes: [], result: F64 }, - "process.getgroups": { argTypes: [], result: arrayOf(F64) }, - /** process.ppid: the parent's pid at the read. Never throws. */ - "process.ppid": { argTypes: [], result: F64 }, - /** process.title: libuv's process title (argv[0] until set); setTitle - * writes it (truncated to the original argument area on POSIX, the - * console title on Windows). Never throw. */ - "process.title": { argTypes: [], result: STRING }, - "process.setTitle": { argTypes: [STRING], result: VOID }, - /** process.argv0: the original argv[0]. Never throws. */ - "process.argv0": { argTypes: [], result: STRING }, - /** process.release: the compatibility target's stable release object - * (name, lts, sourceUrl, headersUrl, and libUrl on Windows). +1. */ - "process.release": { argTypes: [], result: DYN }, - /** process.execPath: the compiled binary's own resolved absolute path - * (one interned string, +1 per read) — the honest answer where Node's - * is the node executable's (SEMANTICS.md divergence 12). Never throws. */ - "process.execPath": { argTypes: [], result: STRING }, - /** process.arch: the compiled binary's OWN architecture ("arm64", - * "x64") — Node's answer for its own build on the same machine. - * Interned; +1 per read. Never throws. */ - "process.arch": { argTypes: [], result: STRING }, - /** Stable native version dictionary. node/openssl identify compatibility - * targets; components absent from the native runtime are omitted. */ - "process.versions": { argTypes: [], result: DYN }, - "process.builtinId": { argTypes: [DYN, arrayOf(STRING)], result: STRING }, - "process.builtinModule": { argTypes: [STRING, DYN], result: DYN }, - "process.builtinUnsupported": { argTypes: [STRING, STRING], result: DYN }, - /** A module namespace object as a checked-dynamic value - * (scr_module_namespace_value): the module id, its sorted export names - * and the compiled getter. One object per module. Never throws. */ - "module.namespaceValue": { argTypes: [STRING, arrayOf(STRING), DYN], result: DYN }, - "fs.callbackValue": { argTypes: [STRING], result: DYN }, - "fs.callbackCall": { argTypes: [STRING, DYN], result: DYN }, - "process.hrtimeValue": { argTypes: [], result: DYN }, - /** process.versions.node: the runtime's Node COMPATIBILITY TARGET — - * there is no Node under the binary, so this reports the version whose - * semantics the runtime implements (SEMANTICS.md divergence 60, the - * execPath stance). Interned; +1 per read. Never throws. */ - "process.versionsNode": { argTypes: [], result: STRING }, - "process.versionsOpenssl": { argTypes: [], result: STRING }, - /** kill(2) with Node's exact semantics and error shapes: the pid must be - * an int32 (else the ERR_INVALID_ARG_TYPE TypeError text), the named - * form resolves Node's signal-name table (unknown names throw the - * ERR_UNKNOWN_SIGNAL TypeError), an omitted signal completes to - * "SIGTERM" in the frontend, signal 0 probes, and a kill(2) failure - * throws Node's `kill ESRCH`/`kill EPERM` Error. Result is Node's - * constant true. */ - "process.kill": { argTypes: [F64, STRING], result: BOOL }, - "process.killNum": { argTypes: [F64, F64], result: BOOL }, - /** The raw byte writes: one borrowed string arg → bool (constantly true - * — this synchronous runtime never queues backpressure). stdoutWrite - * shares console.log's stream, each call is submitted promptly, and - * interleaved output keeps source order. No newline, no formatting, - * never throws. */ - "process.stdoutWrite": { argTypes: [STRING], result: BOOL }, - "process.stdio": { argTypes: [F64], result: DYN }, - "process.stderrWrite": { argTypes: [STRING], result: BOOL }, - // error.new's result and the receiver slots are builtin-error classes — - // program-dependent object types, checked in the libCall case. - /** The runtime-provided Error hierarchy's entry points (scr_error.c). - * error.new: one borrowed string arg (the message), result an owned (+1) - * builtin error instance — the result TYPE names which builtin class - * (backends derive the runtime kind from it). error.ctor: the - * super(message) call of an `extends Error` constructor — borrowed - * receiver (already allocated by the derived class's new) + borrowed - * message, void; the receiver's type names the builtin class whose name - * field to stamp. error.toString: borrowed `%Error`-typed receiver, +1 - * string in Node's "name: message" shape. Formatting can invoke a user - * message accessor, which can throw. */ - "error.new": { argTypes: [STRING], result: VOID }, - /** ECMAScript constructors with raw checked-dynamic message/options. - * Options retain cause presence; constructor calls borrow their args. - * Message coercion may throw before the cause is installed. */ - "error.newOptions": { argTypes: [DYN, DYN], result: VOID }, - "error.ctorOptions": { argTypes: [null, DYN, DYN], result: VOID }, - /** Borrowed Error receiver. cause returns an owned dyn value (undefined - * when absent); hasCause distinguishes absence from present undefined. */ - "error.cause": { argTypes: [null], result: DYN }, - "error.hasCause": { argTypes: [null], result: BOOL }, - /** Assignment borrows both operands and retains the new cause. */ - "error.setCause": { argTypes: [null, DYN], result: VOID }, - /** `err.code = s` on an error-hierarchy receiver: the code slot that - * error.code reads and coded throws stamp. Borrows both; never throws. */ - "error.setCode": { argTypes: [null, STRING], result: VOID }, - /** `err.code = v` with a value that is not statically a string: strings - * take the code slot, anything else clears it and sets the dynamic own - * property. Borrows both; never throws. */ - "error.setCodeDyn": { argTypes: [null, DYN], result: VOID }, - /** `Object.assign(err, ...sources)` onto an error-hierarchy receiver - * (args: the error, a dyn array of the sources): the own-member copy - * onto its checked-dynamic node, then the typed slots (name, message, - * stack, cause, code) re-read from it. Throws what the copy throws. */ - "error.assign": { argTypes: [null, DYN], result: VOID }, - /** `key in err` for a key no compiled class of the receiver declares - * (args: the error, the key): a runtime-set own property (Object.assign, - * throw-site fields, dynamic writes) or an Object.prototype member. */ - "error.hasKey": { argTypes: [null, STRING], result: BOOL }, - "error.hasCode": { argTypes: [null], result: BOOL }, - /** Whether the error's own `name` or `message` (the key) is an accessor - * a reflective definition installed. Borrows both; never throws. */ - "error.ownAccessor": { argTypes: [null, STRING], result: BOOL }, - /** That accessor's getter called on the error (owned result), and its - * setter called with the value (V8's TypeError without one). Borrow - * their arguments; throw what the accessor throws. */ - "error.accessorGet": { argTypes: [null, STRING], result: DYN }, - "error.accessorSet": { argTypes: [null, STRING, DYN], result: VOID }, - "error.defineCause": { argTypes: [null, DYN], result: VOID }, - "error.deleteCause": { argTypes: [null], result: VOID }, - /** The compiler-resolved Node-parity throw for always-throwing lowered - * arms (ERR_INVALID_THIS receivers, ERR_MISSING_ARGS arity ladders, - * the symbol-to-string TypeError): args are [error-kind f64 (the - * SCR_ERR_* index: 0 Error, 1 TypeError, 2 RangeError), code (empty = - * no code slot), message]. ALWAYS THROWS catchably; the result type is - * the replaced expression's own (never materialized — the - * global.undefRead pattern). May-throw seed. */ - "error.nodeThrow": { argTypes: [F64, STRING, STRING], result: VOID }, - /** JS ToString over a dyn value WITH the object protocol (a user - * toString/valueOf member is CALLED and its throw propagates; - * exhaustion throws "Cannot convert object to primitive value"; units - * render "null"/"undefined") — the WHATWG USVString conversions - * (URLSearchParams names/values). Borrowed dyn; +1 string. May-throw. */ - "dyn.toStringCoerce": { argTypes: [DYN], result: STRING }, - "dyn.stringConstructor": { argTypes: [DYN], result: STRING }, - "dyn.propertyKey": { argTypes: [DYN], result: DYN }, - "dyn.toNumeric": { argTypes: [DYN], result: DYN }, - "dyn.increment": { argTypes: [DYN, BOOL], result: DYN }, - /** JS ToNumber over a dyn value WITH the object protocol (number-hint - * valueOf/toString ordering; user throws propagate). Borrowed dyn; - * f64 result, or a throw. Used by statically lowered numeric coercions - * whose checker type remained any. */ - "dyn.numberConstructor": { argTypes: [DYN], result: F64 }, - "dyn.bigintConstructor": { argTypes: [DYN], result: BIGINT_T }, - "dyn.toNumberCoerce": { argTypes: [DYN], result: F64 }, - "dyn.add": { argTypes: [DYN, DYN], result: DYN }, - "dyn.arithmetic": { argTypes: [DYN, DYN, STRING], result: DYN }, - "dyn.compare": { argTypes: [DYN, DYN, STRING], result: BOOL }, - "dyn.bitwise": { argTypes: [DYN, DYN, STRING], result: DYN }, - "dyn.proxyNew": { argTypes: [DYN, DYN], result: DYN }, - /* Dynamic-tier values (jsval; two-tier design stage S3). The jsval pass - * (ir/jsval.ts) introduces these in dynamic-tier functions only; the - * runtime is scr_js_value.c. Arguments are borrowed and results owned, - * like every libCall. Boundary conversions: js.fromDyn (a cell keeps its - * identity), js.toDyn (an immediate is boxed), js.fromF64/fromBool/ - * fromStr/fromBigInt (the design's toJs: immediates, and strings and - * BigInts under a tag without a copy) and js.toF64 (fromJs to number: dynCheck's - * number check and TypeError). The operators are the dyn.* operators - * over jsvals, with identical JS semantics. */ - "js.fromDyn": { argTypes: [DYN], result: JSVAL }, - "js.toDyn": { argTypes: [JSVAL], result: DYN }, - "js.fromF64": { argTypes: [F64], result: JSVAL }, - "js.fromBool": { argTypes: [BOOL], result: JSVAL }, - "js.fromStr": { argTypes: [STRING], result: JSVAL }, - "js.fromBigInt": { argTypes: [BIGINT_T], result: JSVAL }, - "js.toF64": { argTypes: [JSVAL], result: F64 }, - "js.add": { argTypes: [JSVAL, JSVAL], result: JSVAL }, - "js.arithmetic": { argTypes: [JSVAL, JSVAL, STRING], result: JSVAL }, - "js.bitwise": { argTypes: [JSVAL, JSVAL, STRING], result: JSVAL }, - "js.compare": { argTypes: [JSVAL, JSVAL, STRING], result: BOOL }, - "js.toNumeric": { argTypes: [JSVAL], result: JSVAL }, - "js.increment": { argTypes: [JSVAL, BOOL], result: JSVAL }, - "js.toNumberCoerce": { argTypes: [JSVAL], result: F64 }, - // Always throws; the result is the READ's declared type (a typed dummy - // the unwind abandons) — the libCall case skips the result check. - /** A read of a `declare`d const NOTHING defines (the bundler-define - * pattern — __VERSION__): always throws the catchable ReferenceError - * Node raises at the access (" is not defined"). args[0] is the - * name; the result type is the read's declared type (a typed dummy the - * unwind abandons — the value never exists). */ - "global.undefRead": { argTypes: [STRING], result: VOID }, - "console.native": { argTypes: [], result: DYN }, - /** node:console Console instances (scr_console_native.c): new mints the - * handle over the stdout/stderr fds (1/2; 0 = a stream binds next) and - * the ignoreErrors flag; bind attaches a borrowed writable stream to - * target 0 (stdout) or 1 (stderr); write prints `text\n` to the - * selected target of an instance or the global console handle. */ - "console.new": { argTypes: [F64, F64, BOOL], result: DYN }, - "console.bind": { argTypes: [DYN, F64, null], result: VOID }, - "console.write": { argTypes: [DYN, STRING, BOOL], result: VOID }, - /** The global console's remaining members (scr_console_native.c; the - * group indentation itself lives with the writers in scr_console.c). - * Arguments are borrowed; string results are owned. noop is the - * emitter-dropped tail of a lowering whose effects sit in statements. - * label is `${label}` over a defaulted label (undefined -> "default"; - * a Symbol throws Node's TypeError). count prints "label: n". - * countReset answers the warning text for an unknown (or non-string) - * label, "" otherwise. time answers the duplicate-label warning text - * or ""; timeEnd/timeLog answer Node's formatted elapsed time, or "" - * for an unknown label (timeEnd drops the timer). group adds (+1) or - * removes (-1) one two-space indentation step. clear writes the - * cursor-home and erase-down sequences when stdout is a terminal. - * table renders and prints Node's table for a dyn value (undefined - * properties = all). dirDyn is console.dir's inspect of a dyn value - * (custom inspection off: a Buffer anywhere inside throws the fence). */ - "console.noop": { argTypes: [], result: VOID }, - "console.label": { argTypes: [DYN], result: STRING }, - "console.count": { argTypes: [STRING], result: VOID }, - "console.countReset": { argTypes: [DYN], result: STRING }, - "console.time": { argTypes: [STRING], result: STRING }, - "console.timeEnd": { argTypes: [STRING], result: STRING }, - "console.timeLog": { argTypes: [STRING], result: STRING }, - "console.group": { argTypes: [F64], result: VOID }, - "console.clear": { argTypes: [], result: VOID }, - "console.table": { argTypes: [DYN, DYN], result: VOID }, - "console.dirDyn": { argTypes: [DYN, F64], result: STRING }, - /** A native reference to the global object; known names retain value fences. */ - "global.native": { argTypes: [arrayOf(STRING)], result: DYN }, - // `X.name` through a class value: the arg is a program-dependent - // classval (a null slot; the libCall case checks the kind). - /** `X.name` through a class VALUE (scr_object.c): args[0] is a borrowed - * classval; the result is the class object's stored .name string, - * retained (+1 — the string is an interned immortal, so the retain is a - * no-op, kept for ownership uniformity). Never throws. A direct - * `C.name` on the class name itself folds to a strLit instead. */ - "class.name": { argTypes: [null], result: STRING }, - "error.ctor": { argTypes: [null, STRING], result: VOID }, - "error.toString": { argTypes: [null], result: STRING }, - /** SameValue over checked values, including NaN, signed zero and reference identity. */ - "dyn.sameValue": { argTypes: [DYN, DYN], result: BOOL }, - "error.stack": { argTypes: [null], result: STRING }, - "error.setStack": { argTypes: [null, STRING], result: VOID }, - "error.stackLimitGet": { argTypes: [], result: F64 }, - "error.stackLimitSet": { argTypes: [F64], result: VOID }, - // Receiver (any error-hierarchy object) and the program-dependent - // `string | undefined` result are checked in the libCall case. - /** NodeJS.ErrnoException's `.code` read: borrowed error-hierarchy - * receiver → the interned `string | undefined` union (type-directed - * construction in the backend, the process.envGet pattern) — the errno - * name where a throw site stamped one (fs, exec spawn/timeout, - * process.kill, the spawn 'error' event), the undefined arm everywhere - * else. Never throws. */ - "error.code": { argTypes: [null], result: VOID }, - // DOMException: construction takes the two dyn args (WebIDL's - // resolution runs in the runtime); the %DOMException result is a - // program-dependent object type, checked in the libCall case. The - // read surface takes the %DOMException receiver (a null slot — the - // libCall case checks the class name). - /** `new DOMException(message?, nameOrOptions?)` (scr_error.c): both args - * are borrowed dyn values (the lowering passes the dyn undefined for an - * absent argument, so WebIDL's optionality lives in one place). The - * runtime ToStrings the message ("" for absent/undefined), resolves the - * name — absent/undefined → "Error", a non-null object → ToString of its - * `name` member plus the `cause` own-property record, anything else → - * ToString — and stamps the legacy code from the WebIDL name table (0 - * off-table). Result is an owned (+1) %DOMException. Never throws (dyn - * ToString is total). */ - "error.newDom": { argTypes: [DYN, DYN], result: VOID }, - /** DOMException's own read surface (scr_error.c; %DOMException receivers - * only — borrowed). domCode: the legacy numeric code. domHasCause: the - * options form's own-property record (`'cause' in e`). domCause: the - * cause value, +1 (the dyn undefined when absent — matching Node's - * undefined read). None throws. */ - "error.domCode": { argTypes: [null], result: F64 }, - "error.domHasCause": { argTypes: [null], result: BOOL }, - "error.domCause": { argTypes: [null], result: DYN }, - /** structuredClone of a %DOMException receiver (scr_error.c): WebIDL - * serialization — name/message copy, the legacy code re-derives, cause - * does not serialize. args are the borrowed receiver and the borrowed - * options dyn value (the dyn undefined when absent — the shared - * validation throws Node's exact option errors; any non-empty transfer - * list throws DataCloneError, nothing static is transferable). Result - * +1 %DOMException. */ - "error.domClone": { argTypes: [null, DYN], result: VOID }, - /** `new AggregateError(errors, message?, options?)` (scr_json.c), in - * spec order: newAggregate installs the message and cause (both dyn, - * borrowed — the message conversion can throw) and returns an owned - * %AggregateError; aggregateSetErrors then stores the iterated list - * (borrowed receiver, the dyn array borrowed and retained). - * aggregateErrors reads the list (+1, the same array every read). */ - "error.newAggregate": { - argTypes: [DYN, DYN], - result: { kind: "object", className: "%AggregateError" }, - }, - "error.aggregateSetErrors": { argTypes: [null, DYN], result: VOID }, - "error.aggregateErrors": { argTypes: [null], result: DYN }, - /** `new SuppressedError(error, suppressed, message?)` (scr_json.c): all - * three dyn and borrowed; the message conversion can throw. Returns an - * owned %SuppressedError. */ - "error.newSuppressed": { - argTypes: [DYN, DYN, DYN], - result: { kind: "object", className: "%SuppressedError" }, - }, - /** `d instanceof TypeError` (and the other BUILTIN error classes) on a - * checked-dynamic value (scr_json.c): the from_error cache holds the - * dyn↔error identity edge, so the test resolves the runtime error and - * asks its vtable's stamped preorder interval — exact for every error - * that crossed the boundary. A dyn object that never came from an - * error (a hand-built {%error} literal) answers false: subclass - * identity is unknowable there (the root keeps dynTest's marker - * answer). args are the borrowed dyn and the SCR_ERR_* kind literal. - * Never throws. */ - "dyn.errInstanceof": { argTypes: [DYN, F64], result: BOOL }, - "weakMap.is": { argTypes: [DYN], result: BOOL }, - "weakSet.is": { argTypes: [DYN], result: BOOL }, - "weakMap.new": { argTypes: [DYN], result: DYN }, - "weakSet.new": { argTypes: [DYN], result: DYN }, - "finalizationRegistry.new": { argTypes: [DYN], result: DYN }, - "finalizationRegistry.is": { argTypes: [DYN], result: BOOL }, - "dyn.fromEntries": { argTypes: [DYN], result: DYN }, - "bytes.constructor": { argTypes: [STRING], result: DYN }, - "bytes.instanceOf": { argTypes: [DYN, DYN, STRING], result: BOOL }, - "bytes.construct": { argTypes: [DYN, DYN, STRING], result: DYN }, - /** The ambient receiver — JS `this` in a plain (non-method) function - * body: the innermost binding the current firing/dispatch window - * pushed (Node's listener receiver, a dyn OBJ method's object, an - * apply/call thisArg), or the undefined dyn singleton with none bound - * (the strict-mode plain-call answer, the old constant). Zero args → - * dyn (+1). Never throws. */ - "dyn.dataViewIs": { argTypes: [DYN], result: BOOL }, - "dyn.construct": { argTypes: [DYN, DYN, STRING], result: DYN }, - "arrayBuffer.constructor": { argTypes: [], result: DYN }, - "sharedArrayBuffer.new": { argTypes: [DYN], result: DYN }, - "sharedArrayBuffer.is": { argTypes: [DYN], result: BOOL }, - "arrayBuffer.new": { argTypes: [DYN], result: DYN }, - "ffi.argument": { argTypes: [DYN, STRING], result: DYN }, - "ffi.memoryModule": { argTypes: [DYN], result: DYN }, - "intl.segmenterNew": { argTypes: [], result: DYN }, - "intl.segmenterRefusing": { argTypes: [STRING], result: DYN }, - "arrayBuffer.is": { argTypes: [DYN], result: BOOL }, - "arrayBuffer.isView": { argTypes: [DYN], result: BOOL }, - "arrayBuffer.byteLengthGetter": { argTypes: [], result: F64 }, - "arrayBuffer.byteLengthDescriptor": { argTypes: [DYN], result: DYN }, - "arrayBuffer.viewU8C": { argTypes: [DYN, DYN, DYN], result: bytesOf("u8c") }, - "arrayBuffer.viewI8": { argTypes: [DYN, DYN, DYN], result: bytesOf("i8") }, - "arrayBuffer.viewU16": { argTypes: [DYN, DYN, DYN], result: bytesOf("u16") }, - "arrayBuffer.viewI16": { argTypes: [DYN, DYN, DYN], result: bytesOf("i16") }, - "arrayBuffer.viewU8": { argTypes: [DYN, DYN, DYN], result: BYTES_U8 }, - "arrayBuffer.viewU32": { argTypes: [DYN, DYN, DYN], result: bytesOf("u32") }, - "arrayBuffer.viewI32": { argTypes: [DYN, DYN, DYN], result: bytesOf("i32") }, - "arrayBuffer.viewF16": { argTypes: [DYN, DYN, DYN], result: bytesOf("f16") }, - "arrayBuffer.viewF32": { argTypes: [DYN, DYN, DYN], result: bytesOf("f32") }, - "arrayBuffer.viewF64": { argTypes: [DYN, DYN, DYN], result: bytesOf("f64") }, - "arrayBuffer.viewDV": { argTypes: [DYN, DYN, DYN], result: BYTES_U8 }, - /** Object.keys/values/entries over a CHECKED-DYNAMIC receiver - * (scr_json.c): the runtime walks the dyn node's own members in JS - * own-key order (array-index keys ascending first, then insertion - * order) and answers a dyn array (entries: an array of [key, value] - * pairs; values RETAIN the member nodes — reference semantics, like - * JS). Strings/arrays/bytes answer their index keys; other scalars an - * empty array; null/undefined throw Node's catchable TypeError - * ("Cannot convert undefined or null to object"). */ - "dyn.objKeys": { argTypes: [DYN], result: DYN }, - "dyn.forInKeys": { argTypes: [DYN], result: DYN }, - "dyn.forInKeyStrings": { argTypes: [DYN], result: arrayOf(STRING) }, - "dyn.forInStable": { argTypes: [DYN], result: BOOL }, - "dyn.objKeyStrings": { argTypes: [DYN], result: arrayOf(STRING) }, - /** Object.entries as a native [string, any][] (VOID: the tuple row's - * shape is program-dependent; the validator checks it). */ - "dyn.objEntryPairs": { argTypes: [DYN], result: VOID }, - "dyn.hasOwn": { argTypes: [DYN, STRING], result: BOOL }, - "dyn.propertyIsEnumerable": { argTypes: [DYN, STRING], result: BOOL }, - "dyn.assign": { argTypes: [DYN, DYN], result: DYN }, - "dyn.copyDataProperties": { argTypes: [DYN, DYN], result: DYN }, - "dyn.objectRest": { argTypes: [DYN, DYN], result: DYN }, - /** Variadic Object.assign over CHECKED-DYNAMIC targets (`Object.assign( - * {}, ...arr.map(f), tail)` — the option-table merge): the lowering - * builds one fresh dyn pack of sources (packPush retains a plain source - * in; packPushSpread flattens a spread source through the spread-call - * walk — V8's exact TypeError texts, the string arg spelling the spread - * expression for the nullish form), so every source evaluates and - * flattens BEFORE any copying (JS's ArgumentListEvaluation), then - * assignAll copies each pack element's own enumerable keys onto the - * target left to right and answers the TARGET (+1) — identity, like JS. - * assignAll throws Node's ToObject TypeError on a nullish target. */ - "dyn.packPush": { argTypes: [DYN, DYN], result: VOID }, - "dyn.packPushSpread": { argTypes: [DYN, DYN, STRING], result: VOID }, - /** The iterated-path spread twin: V8 spells the optimized apply-path - * texts (packPushSpread's — the expression named for nullish sources) - * only for the SINGLE LAST argument's spread; any other spread position - * drives the real iterator protocol, whose failure describes the VALUE - * ("object null is not iterable (cannot read property - * Symbol(Symbol.iterator))"). The frontend picks by position. */ - "dyn.packPushSpreadIter": { argTypes: [DYN, DYN], result: VOID }, - "dyn.reflectApply": { argTypes: [DYN, DYN, DYN], result: DYN }, - "dyn.reflectGet": { argTypes: [DYN, DYN, DYN], result: DYN }, - /** `using` / `await using` with a dyn value (scr_json.c): usingMethod - * runs the declaration's checks and answers what usingDispose calls at - * scope exit (undefined for a null or undefined value). The bool selects - * `await using`. Both throw Node's TypeErrors or the method's error. */ - "dyn.usingMethod": { argTypes: [DYN, BOOL], result: DYN }, - "dyn.usingDispose": { argTypes: [DYN, DYN], result: DYN }, - /** DisposableStack (scr_symbol.c): a new stack handle; whether a value is - * one; and `stack.use(value)` for a class instance, registering the - * compiler's disposal function for it. The last throws Node's - * ReferenceError on a disposed stack. */ - "disposable.stackNew": { argTypes: [], result: DYN }, - "disposable.stackIs": { argTypes: [DYN], result: BOOL }, - "disposable.stackUseCallback": { argTypes: [DYN, DYN, DYN], result: BOOL }, - "dyn.reflectSet": { argTypes: [DYN, DYN, DYN, DYN], result: BOOL }, - "dyn.reflectDefine": { argTypes: [DYN, DYN, DYN], result: BOOL }, - "dyn.abstractEq": { argTypes: [DYN, DYN], result: BOOL }, - "dyn.assignAll": { argTypes: [DYN, DYN], result: DYN }, + "math.trunc": { argTypes: [F64], result: F64 }, + "math.ceil": { argTypes: [F64], result: F64 }, + "math.sin": { argTypes: [F64], result: F64 }, + "math.sinh": { argTypes: [F64], result: F64 }, + "math.cos": { argTypes: [F64], result: F64 }, + "math.cosh": { argTypes: [F64], result: F64 }, + "math.tan": { argTypes: [F64], result: F64 }, + "math.tanh": { argTypes: [F64], result: F64 }, + "math.asin": { argTypes: [F64], result: F64 }, + "math.asinh": { argTypes: [F64], result: F64 }, + "math.acos": { argTypes: [F64], result: F64 }, + "math.acosh": { argTypes: [F64], result: F64 }, + "math.atan": { argTypes: [F64], result: F64 }, + "math.atanh": { argTypes: [F64], result: F64 }, + "math.cbrt": { argTypes: [F64], result: F64 }, + "math.clz32": { argTypes: [F64], result: F64 }, + /** Return -1, +1, or the original NaN/zero. In particular, -0 remains -0. */ + "math.sign": { argTypes: [F64], result: F64 }, + "math.exp": { argTypes: [F64], result: F64 }, + "math.expm1": { argTypes: [F64], result: F64 }, + "math.f16round": { argTypes: [F64], result: F64 }, + "math.fround": { argTypes: [F64], result: F64 }, + "math.sqrt": { argTypes: [F64], result: F64 }, + "math.log": { argTypes: [F64], result: F64 }, + "math.log1p": { argTypes: [F64], result: F64 }, + "math.log2": { argTypes: [F64], result: F64 }, + "math.log10": { argTypes: [F64], result: F64 }, + "math.atan2": { argTypes: [F64, F64], result: F64 }, + "math.pow": { argTypes: [F64, F64], result: F64 }, + "math.imul": { argTypes: [F64, F64], result: F64 }, + /** `Math.min(a, b)` / `Math.max(a, b)` — the two-argument scalar forms + * (scr_lib.c), JS-exact like the Arr folds: NaN poisons, max prefers +0 + * over -0 (min the reverse). C fmin/fmax are NOT these (they drop NaN). + * Never throw. */ + "math.min": { argTypes: [F64, F64], result: F64 }, + "math.max": { argTypes: [F64, F64], result: F64 }, + /** `Math.random()` — a uniform double in [0,1) with the spec's 53-bit + * granularity, drawn from arc4random_buf (the CSPRNG behind the crypto + * lowerings). Same distribution as Node, NECESSARILY different sequence + * (SEMANTICS.md 62 — no seeded sequence exists to match). Never throws. */ + "math.random": { argTypes: [], result: F64 }, + /** The static global parsers/tests (scr_string.c). num.parseInt is + * ECMA-262 19.2.5 exactly — JS whitespace, sign, ToInt32 radix (the + * frontend completes an omitted radix to 0 = the spec's "undefined": + * base 10 with the 0x hex escape), longest digit prefix, and the exact + * mathematical value correctly rounded (u64 fast path, bignum beyond — + * overflow is ±Infinity). num.isNaN is the NaN self-test on an + * already-number argument (tsc pins the argument to number, so no + * ToNumber coercion exists to model). Borrow; never throw. */ + "num.parseInt": { argTypes: [STRING, F64], result: F64 }, + /** ES parseFloat (scr_string.c): the longest StrDecimalLiteral prefix + * of the trimmed input (no hex, "Infinity" exact-case), NaN when none — + * ECMA-262 19.2.4 over a string argument (non-string arguments keep the + * fence: Node would ToNumber-coerce). Borrows; never throws. */ + "num.parseFloat": { argTypes: [STRING], result: F64 }, + /** `a.localeCompare(b)`: -1/0/1 in Node's root-locale collation for + * Latin-script text (scr_str_locale_compare). Never throws. */ + "str.localeCompare": { argTypes: [STRING, STRING], result: F64 }, + /** Annex B substr(start, length) with start ToNumber'd and length's + * presence; never throws. */ + "str.substr": { argTypes: [STRING, F64, F64, BOOL], result: STRING }, + /** toLocaleLowerCase/toLocaleUpperCase (scr_regex.c): the locales value + * as written, upper=true for toLocaleUpperCase. Throws for null and for + * locale forms with no native rules. */ + "str.localeCase": { argTypes: [STRING, DYN, BOOL], result: STRING }, + "str.replaceLiteral": { argTypes: [STRING, STRING, STRING, BOOL], result: STRING }, + // (subject, characters, NUL-separated replacement texts): the fused + // chain of global one-character replacements. + "str.replaceChars": { argTypes: [STRING, STRING, STRING], result: STRING }, + /* ToNumber(string) — ECMA-262 7.1.4.1 StringToNumber (scr_string.c): + * trim the JS StrWhiteSpace set, empty/whitespace-only → +0, then the + * whole span must be one StrNumericLiteral — signed decimal (Infinity + * included, strtod-over-validated-span correct rounding) or unsigned + * 0x/0o/0b (exact value, nearest-even; signed forms are NaN) — with + * any trailing garbage answering NaN. Number(aString), unary + on + * strings, and util.format %d over strings lower here. Borrows; never + * throws. */ + "num.fromString": { argTypes: [STRING], result: F64 }, + "num.isNaN": { argTypes: [F64], result: BOOL }, + /** The static URI component codecs (scr_string.c), ECMA-262 Encode/ + * Decode with the component sets over the runtime's UTF-8 strings. + * str.encodeUriComponent percent-encodes every byte outside the + * unreserved component set (ALPHA/DIGIT/- _ . ! ~ * ' ( )) as uppercase + * %XX — the spec's per-code-point UTF-8 encoding IS a byte scan here — + * and THROWS the spec's URIError ("URI malformed") on a lone surrogate. + * str.decodeUriComponent + * decodes %XX escapes bytewise (raw non-escape bytes copy through) and + * requires the escaped bytes to form strictly valid UTF-8 (overlong + * forms, surrogate code points, and >U+10FFFF refused, per UTF8-decode + * without replacement); bad hex or an invalid sequence THROWS the + * spec's URIError ("URI malformed"), catchable. Borrow; results +1. */ + "str.encodeUriComponent": { argTypes: [STRING], result: STRING }, + // The base64 globals: the argument is a dyn value (WebIDL ToString + // runs in the runtime); the zero-argument form always throws. + /** The WHATWG base64 globals (scr_string.c), Node-global since v16. + * Arguments are borrowed dyn values — WebIDL ToString runs in the + * runtime over the dyn kind (String(null) is "null": the html spec's + * coercion, which Node's atob(null) exercises). str.atob decodes + * forgiving-base64 (ASCII whitespace stripped, %4==0 strips up to two + * '=', %4==1 refuses, leftover bits discarded) into the latin1 code + * points as a string; a malformed input THROWS the catchable + * DOMException InvalidCharacterError ("The string to be decoded is not + * correctly encoded."). str.btoa encodes the string's code points as + * base64; any code point over U+00FF THROWS InvalidCharacterError + * ("Invalid character"). str.b64Missing is the zero-argument call of + * either: always throws Node's TypeError [ERR_MISSING_ARGS] "The + * \"input\" argument must be specified". Results +1. */ + "str.atob": { argTypes: [DYN], result: STRING }, + "str.btoa": { argTypes: [DYN], result: STRING }, + "str.b64Missing": { argTypes: [], result: STRING }, + "str.decodeUriComponent": { argTypes: [STRING], result: STRING }, + "str.decodeUri": { argTypes: [STRING], result: STRING }, + /** encodeURI: the same Encode() keeping the reserved set and '#' + * unescaped — throwing like the component encoder. Borrow; result +1. */ + "str.encodeUri": { argTypes: [STRING], result: STRING }, + /** RegExp.escape (ES2025): per-code-point EncodeForRegExpEscape — + * leading ASCII alphanumeric hex-escapes, syntax characters and '/' + * take a backslash, other punctuators/whitespace/line terminators + * hex-escape, the rest passes through. Total; borrows; result +1. */ + "regexp.escape": { argTypes: [STRING], result: STRING }, + /** Number.prototype formatters (scr_lib.c), JS-exact: + * num.toExponential is toExponential() with the spec's "as many digits + * as necessary"; num.toFixed0 is the non-throwing omitted-argument + * toFixed() fast path; num.toFixed implements an explicit fractionDigits + * with exact binary-value rounding and THROWS RangeError outside 0..100. + * Successful results +1. */ + "num.toExponential": { argTypes: [F64], result: STRING }, + "num.toFixed0": { argTypes: [F64], result: STRING }, + "num.toFixed": { argTypes: [F64, F64], result: STRING }, + /** toPrecision(precision) with the argument ToNumber'd and its presence + * (undefined answers ToString); toExponential with a DEFINED + * fractionDigits. Both throw V8's RangeError for out-of-range digits. */ + "num.toPrecision": { argTypes: [F64, F64, BOOL], result: STRING }, + "num.toExponentialDigits": { argTypes: [F64, F64], result: STRING }, + "num.toStringRadix": { argTypes: [F64, DYN], result: STRING }, + /** toString(radix) with a number radix (scr_lib.c): truncates it as + * ToIntegerOrInfinity does, THROWS RangeError outside 2..36. */ + "num.toStringRadixF64": { argTypes: [F64, F64], result: STRING }, + /** Object.is over two numbers — the spec's SameValue on doubles: NaN + * equals NaN, +0 differs from -0, everything else is `===`. Plain bool + * result; never throws. (Union-armed operands take unionEq's sameValue + * flag instead — this is the both-f64 fast path.) */ + "num.sameValue": { argTypes: [F64, F64], result: BOOL }, + /** `new Intl.NumberFormat("en-US").format(x)` and + * `x.toLocaleString("en-US")` with DEFAULT options — the one locale + * whose data the runtime embeds (Node's default-build locale): decimal + * notation, 0–3 fraction digits rounded half-up on the SHORTEST + * round-tripping decimal (ICU's rounding input, probed vs Node — + * format(1.0005) is "1.001" though toFixed(3) answers "1.000"), "," + * grouping every three integer digits, "∞"/"NaN" texts, and "-0" for + * negative inputs rounding to zero. Result +1; never throws. */ + "intl.numFormatEnUs": { argTypes: [F64], result: STRING }, + /** ES Symbol values (scr_symbol.c — link-gated by moduleUsesSymbol). + * sym.new: `Symbol(desc)` — a fresh runtime-unique identity (+1) whose + * one arg is the description string (borrowed); sym.newAnon is the + * description-less `Symbol()` form. sym.for: the Symbol.for global + * registry — one interned symbol per key (borrowed), +1 on every call. + * sym.toString: "Symbol(desc)" (+1 string; "Symbol()" when absent). + * sym.desc / sym.keyFor answer the interned `string | undefined` union + * (the runtime returns +1-or-NULL; the backend builds the union arms — + * the child.stdout pattern). None of these throw. */ + "sym.new": { argTypes: [STRING], result: SYMBOL_T }, + "sym.newAnon": { argTypes: [], result: SYMBOL_T }, + "sym.for": { argTypes: [STRING], result: SYMBOL_T }, + "sym.wellKnown": { argTypes: [STRING], result: SYMBOL_T }, + // Result is the interned `string | undefined` union — the libCall case + // checks the arms (the spawnRes.error pattern). + "sym.keyFor": { argTypes: [SYMBOL_T], result: VOID }, + "sym.desc": { argTypes: [SYMBOL_T], result: VOID }, + "sym.toString": { argTypes: [SYMBOL_T], result: STRING }, + /** Engine-free arbitrary-precision bigint operations (scr_bigint.c). + * parse accepts the ECMAScript BigInt string grammar; fromF64 accepts + * finite integral Numbers. Arithmetic returns fresh immutable values. + * cmp returns -1/0/1 as f64; toString accepts a numeric radix. */ + "bigint.parse": { argTypes: [STRING], result: BIGINT_T }, + "bigint.fromF64": { argTypes: [F64], result: BIGINT_T }, + "bigint.neg": { argTypes: [BIGINT_T], result: BIGINT_T }, + "bigint.not": { argTypes: [BIGINT_T], result: BIGINT_T }, + "bigint.add": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, + "bigint.sub": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, + "bigint.mul": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, + "bigint.div": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, + "bigint.mod": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, + "bigint.pow": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, + "bigint.and": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, + "bigint.or": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, + "bigint.xor": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, + "bigint.shl": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, + "bigint.shr": { argTypes: [BIGINT_T, BIGINT_T], result: BIGINT_T }, + "bigint.eq": { argTypes: [BIGINT_T, BIGINT_T], result: BOOL }, + "bigint.eqString": { argTypes: [BIGINT_T, STRING], result: BOOL }, + "bigint.cmp": { argTypes: [BIGINT_T, BIGINT_T], result: F64 }, + "bigint.cmpNumber": { argTypes: [BIGINT_T, F64], result: F64 }, + "bigint.truthy": { argTypes: [BIGINT_T], result: BOOL }, + "bigint.toString": { argTypes: [BIGINT_T, F64], result: STRING }, + "bigint.inspect": { argTypes: [BIGINT_T], result: STRING }, + "bigint.toF64": { argTypes: [BIGINT_T], result: F64 }, + "bigint.asUintN": { argTypes: [F64, BIGINT_T], result: BIGINT_T }, + "bigint.asIntN": { argTypes: [F64, BIGINT_T], result: BIGINT_T }, + "bigint.bufferRead": { argTypes: [BYTES_U8, F64, BOOL, BOOL], result: BIGINT_T }, + "bigint.bufferWrite": { argTypes: [BYTES_U8, BIGINT_T, F64, BOOL, BOOL], result: F64 }, + "bigint.dataViewGet": { argTypes: [BYTES_U8, F64, BOOL, BOOL], result: BIGINT_T }, + "bigint.dataViewSet": { argTypes: [BYTES_U8, F64, BIGINT_T, BOOL], result: VOID }, + /** node:url + the URL class (scr_url.c). url.new parses one absolute + * URL string into a mutable URL value (+1) — invalid input THROWS a + * catchable TypeError ("Invalid URL"), like Node's constructor. The + * getters (borrowed receiver, +1 string) never throw; url.href doubles + * as toString(). fileURLToPath has one libFn per receiver form (URL + * value / string) — both THROW Node's TypeErrors on non-file schemes, + * encoded slashes, and non-empty hosts. url.pathToFileURL resolves the + * path (getcwd) and never throws. */ + "url.new": { argTypes: [STRING], result: URL_T }, + "url.newBase": { argTypes: [STRING, STRING], result: URL_T }, + /** Factories consume already-converted input/base strings. canParse + * answers a boolean; parse returns a checked native URL or null (+1). + * Parser failures are suppressed; conversion occurs before these calls. */ + "url.canParse": { argTypes: [STRING], result: BOOL }, + "url.canParseBase": { argTypes: [STRING, STRING], result: BOOL }, + "url.parse": { argTypes: [STRING], result: DYN }, + "url.parseBase": { argTypes: [STRING, STRING], result: DYN }, + "url.protocol": { argTypes: [URL_T], result: STRING }, + "url.origin": { argTypes: [URL_T], result: STRING }, + "url.username": { argTypes: [URL_T], result: STRING }, + "url.password": { argTypes: [URL_T], result: STRING }, + "url.host": { argTypes: [URL_T], result: STRING }, + "url.hostname": { argTypes: [URL_T], result: STRING }, + "url.port": { argTypes: [URL_T], result: STRING }, + "url.pathname": { argTypes: [URL_T], result: STRING }, + "url.href": { argTypes: [URL_T], result: STRING }, + /** Selected component writes borrow the receiver and converted string. + * href replaces its parsed fields while retaining cached params identity. */ + "url.set": { argTypes: [URL_T, STRING, STRING], result: VOID }, + "url.setChecked": { argTypes: [URL_T, STRING, DYN], result: VOID }, + "url.fileURLToPathUrl": { argTypes: [URL_T], result: STRING }, + /** fileURLToPathUrl as a value: the path string, or the error it would + * throw (fs.existsSync and fs.promises URL paths). Never throws. */ + "url.fileURLToPathValue": { argTypes: [URL_T], result: DYN }, + /** getValidatedPath's null-byte check on a string path, and + * readFileSync's encoding check: what Node validates before it converts + * a later URL path. (path, argument name) and (encoding). */ + "fs.checkPath": { argTypes: [STRING, STRING], result: VOID }, + "fs.checkReadEncoding": { argTypes: [STRING], result: VOID }, + "url.fileURLToPathChecked": { argTypes: [DYN], result: STRING }, + "url.fileURLToPathOptions": { argTypes: [DYN, DYN], result: STRING }, + /** node:url's legacy API (scr_url_legacy.c): parse(url, parseQueryString, + * slashesDenoteHost) answers the checked-dynamic Url instance; format + * takes the urlObject (a Url-shaped object, a string, or a URL) and the + * URL form's options; resolve takes (from, to). The trailing bool says + * whether the call site emits DEP0169. domainToASCII/domainToUnicode + * take the domain and whether it was omitted. Node's validation errors + * throw catchably. */ + "url.legacyParse": { argTypes: [DYN, DYN, DYN, BOOL], result: DYN }, + "url.legacyFormat": { argTypes: [DYN, DYN, BOOL], result: STRING }, + "url.legacyResolve": { argTypes: [DYN, DYN, BOOL], result: STRING }, + "url.domainToASCII": { argTypes: [DYN, BOOL], result: STRING }, + "url.domainToUnicode": { argTypes: [DYN, BOOL], result: STRING }, + /** url.urlToHttpOptions over a checked-dynamic argument: a URL answers + * Node's null-prototype options object; a primitive or null throws + * ERR_INVALID_ARG_TYPE. */ + "url.toHttpOptions": { argTypes: [DYN], result: DYN }, + /** node:punycode (scr_url.c): punycode.js 2.1.0's string conversions; + * decode/toUnicode (and, past 32-bit deltas, encode/toASCII) throw the + * module's RangeErrors, ucs2Encode String.fromCodePoint's. warn marks the + * module's first load (scr_async_dyn.c) and reports DEP0040 then unless + * the second argument is false: at once for a static ES import, on the + * next tick for a require() call. */ + "punycode.decode": { argTypes: [STRING], result: STRING }, + "punycode.encode": { argTypes: [STRING], result: STRING }, + "punycode.toASCII": { argTypes: [STRING], result: STRING }, + "punycode.toUnicode": { argTypes: [STRING], result: STRING }, + "punycode.ucs2Decode": { argTypes: [STRING], result: arrayOf(F64) }, + "punycode.ucs2Encode": { argTypes: [arrayOf(F64)], result: STRING }, + "punycode.warn": { argTypes: [BOOL, BOOL], result: VOID }, + "url.fileURLToPathBuffer": { argTypes: [DYN, DYN], result: BYTES_U8 }, + "url.pathToFileURLChecked": { argTypes: [DYN, DYN], result: URL_T }, + "url.fileURLToPathStr": { argTypes: [STRING], result: STRING }, + "url.pathToFileURL": { argTypes: [STRING], result: URL_T }, + /** Explicit path syntax from the options.windows argument, independent + * of the executable's host platform. Windows UNC input can throw. */ + "url.pathToFileURLPlatform": { argTypes: [STRING, BOOL], result: URL_T }, + /** pathToFileURL under a win32 TARGET: the same scr_url_from_path call + * (the runtime selects the win32 arm by _WIN32), but a distinct IR name + * because that arm THROWS for malformed UNC inputs — may-throw seeds on + * it while posix pathToFileURL emission stays byte-identical. */ + "url.pathToFileURLWin32": { argTypes: [STRING], result: URL_T }, + /** URLSearchParams (scr_url.c — always linked with the url unit). + * Construction: sp.new (empty), sp.parse (one borrowed init string — + * a single leading '?' strips, Node's constructor), sp.copy (snapshot + * of another list), sp.fromPairs (a string[][] value — THROWS Node's + * ERR_INVALID_TUPLE TypeError on a non-[name, value] row; the one + * throwing entry in the family), sp.with (the record-literal init + * desugar: append one pair, answer the same list +1 — chains fold + * `new URLSearchParams({...})` into nested calls). url.searchParams + * answers the URL's LIVE cached view (+1, one identity per URL); + * url.search is the WHATWG search getter ("" for no/empty query). + * Methods mirror the WHATWG surface: sp.get answers +1-or-NULL (the + * sym.desc union pattern, null arm), sp.getAll a fresh string[]; + * sp.append/sp.set/sp.delete/sp.deleteValue/sp.sort mutate and + * re-serialize a live view's URL query; sp.has/sp.hasValue answer + * bools; sp.size/sp.toString are pure reads. sp.keyAt/sp.valAt are + * the for-of/forEach desugar's index reads (live — the loop re-reads + * sp.size each pass). */ + "sp.new": { argTypes: [], result: SEARCH_PARAMS_T }, + "sp.newChecked": { argTypes: [DYN], result: SEARCH_PARAMS_T }, + "sp.parse": { argTypes: [STRING], result: SEARCH_PARAMS_T }, + "sp.copy": { argTypes: [SEARCH_PARAMS_T], result: SEARCH_PARAMS_T }, + // The pairs argument is string[][] — checked structurally in validate.ts (the + // generic array-of slot has no named constant here). + "sp.fromPairs": { argTypes: [null], result: SEARCH_PARAMS_T }, + "sp.with": { argTypes: [SEARCH_PARAMS_T, STRING, STRING], result: SEARCH_PARAMS_T }, + "url.searchParams": { argTypes: [URL_T], result: SEARCH_PARAMS_T }, + "url.search": { argTypes: [URL_T], result: STRING }, + "url.hash": { argTypes: [URL_T], result: STRING }, + // Result is the interned `string | null` union — the libCall case + // checks the arms (the spawnRes.signal pattern). + "sp.get": { argTypes: [SEARCH_PARAMS_T, STRING], result: VOID }, + "sp.getAll": { argTypes: [SEARCH_PARAMS_T, STRING], result: arrayOf(STRING) }, + "sp.append": { argTypes: [SEARCH_PARAMS_T, STRING, STRING], result: VOID }, + "sp.set": { argTypes: [SEARCH_PARAMS_T, STRING, STRING], result: VOID }, + "sp.delete": { argTypes: [SEARCH_PARAMS_T, STRING], result: VOID }, + "sp.deleteValue": { argTypes: [SEARCH_PARAMS_T, STRING, STRING], result: VOID }, + "sp.has": { argTypes: [SEARCH_PARAMS_T, STRING], result: BOOL }, + "sp.hasValue": { argTypes: [SEARCH_PARAMS_T, STRING, STRING], result: BOOL }, + "sp.sort": { argTypes: [SEARCH_PARAMS_T], result: VOID }, + "sp.size": { argTypes: [SEARCH_PARAMS_T], result: F64 }, + "sp.toString": { argTypes: [SEARCH_PARAMS_T], result: STRING }, + "sp.keyAt": { argTypes: [SEARCH_PARAMS_T, F64], result: STRING }, + "sp.valAt": { argTypes: [SEARCH_PARAMS_T, F64], result: STRING }, + // node:querystring. qs.parse's result is the call site's ParsedUrlQuery + // dictionary record (VOID is the networkInterfaces sentinel — the + // libCall case checks the structure); qs.stringify's object argument + // is a dyn value (the frontend dynFroms typed records). + /** node:querystring (scr_qs.c — link-gated by moduleUsesQs; NOT + * URLSearchParams: the legacy codec's escaping and '+' rules differ). + * qs.escape is Node's qsEscape, which encodes exactly the component + * unreserved set — it emits the always-linked scr_qs_escape, so + * escape-only programs never pull the unit. qs.unescape is Node's qsUnescape: strict decodeURIComponent + * first, the lenient legacy unescapeBuffer fallback on failure (never + * throws). qs.parse takes (str, sep, eq, maxKeys) — the frontend + * completes omitted/null sep/eq to "&"/"=" and the omitted maxKeys + * option to Node's 1000 (0 and negatives mean unlimited, Node's rule) — + * and its result type is the CALL SITE's mapped ParsedUrlQuery shape (a + * pure index-signature record over `string | string[]`, an undefined + * arm tolerated — @types/node's Dict), verified structurally by the + * frontend (lowerQuerystringParseCall); the emitters construct the + * record and hand its overflow map to scr_qs_parse_into with the two + * union tags. qs.stringify takes (obj, sep, eq) with obj a dyn value + * (the frontend dynFroms the typed record; JS-world dyn values pass + * through) — Node's encodeStringified rules run in the runtime, so + * arrays expand to repeated keys and null/undefined/nested objects are + * empty values. Custom encoder/decoder options fence at compile time. + * All borrow; string results +1; escape and stringify throw URIError + * [ERR_INVALID_URI] on a lone surrogate. */ + "qs.parse": { argTypes: [STRING, STRING, STRING, F64], result: VOID }, + "qs.stringify": { argTypes: [DYN, STRING, STRING], result: STRING }, + "qs.escape": { argTypes: [STRING], result: STRING }, + "qs.unescape": { argTypes: [STRING], result: STRING }, + /** node:util.parseArgs: one checked-dynamic config object in, one + * checked-dynamic ParsedResults tree out. Statically typed member reads + * validate their values when leaving that tree. The native parser may + * throw Node's coded validation/grammar TypeErrors. */ + "util.parseArgs": { argTypes: [DYN], result: DYN }, + "util.parseEnv": { argTypes: [DYN], result: DYN }, + "util.getSystemErrorName": { argTypes: [DYN], result: STRING }, + "util.getSystemErrorMessage": { argTypes: [DYN], result: STRING }, + "util.systemErrorEntries": { argTypes: [], result: DYN }, + "util.stripVTControlCharacters": { argTypes: [DYN], result: STRING }, + "util.toUSVString": { argTypes: [DYN], result: STRING }, + "util.isDeepStrictEqual": { argTypes: [DYN, DYN, DYN], result: BOOL }, + "util.styleText": { argTypes: [DYN, DYN, DYN], result: STRING }, + /** util.inherits/deprecate/callbackify/debuglog over checked-dynamic + * arguments (scr_util_callable.c). The function results are native dyn + * wrappers; call sites with a static function type check them back. */ + "util.inherits": { argTypes: [DYN, DYN], result: VOID }, + "util.inheritsPrototype": { argTypes: [DYN, DYN, DYN], result: VOID }, + "util.deprecate": { argTypes: [DYN, DYN, DYN, DYN], result: DYN }, + "util.callbackify": { argTypes: [DYN], result: DYN }, + /** util.promisify over an untyped function value: a native dyn function + * whose calls answer a dyn promise the appended callback settles. */ + "util.promisifyDyn": { argTypes: [DYN], result: DYN }, + "util.debuglog": { argTypes: [DYN, DYN], result: DYN }, + "util.typeIs": { argTypes: [DYN, STRING], result: BOOL }, + "util.typeValue": { argTypes: [DYN, STRING], result: DYN }, + /** fs.statSync → a Stats value (may throw, like the other sync fs + * calls); the stats.* getters are pure reads on it. */ + "fs.statSync": { argTypes: [STRING], result: STATS_T }, + "fs.lstatSync": { argTypes: [STRING], result: STATS_T }, + // statSync / lstatSync(path, { throwIfNoEntry }): arg 1 is the flag. + // Result is the interned `Stats | undefined` union (the runtime answers + // +1-or-NULL; the backend builds the arms). + "fs.statProbeSync": { argTypes: [STRING, BOOL], result: VOID }, + "fs.lstatProbeSync": { argTypes: [STRING, BOOL], result: VOID }, + "fs.fstatSync": { argTypes: [F64], result: STATS_T }, + "fs.fchmodSync": { argTypes: [F64, F64], result: VOID }, + "fs.fsyncSync": { argTypes: [F64], result: VOID }, + "fs.fdatasyncSync": { argTypes: [F64], result: VOID }, + "fs.ftruncateSync": { argTypes: [F64, F64], result: VOID }, + "fs.utimesSync": { argTypes: [DYN, DYN, DYN], result: VOID }, + "fs.futimesSync": { argTypes: [DYN, DYN, DYN], result: VOID }, + "fs.lutimesSync": { argTypes: [DYN, DYN, DYN], result: VOID }, + "fs.readvSync": { argTypes: [F64, arrayOf(BYTES_U8), F64], result: F64 }, + "fs.writevSync": { argTypes: [F64, arrayOf(BYTES_U8), F64], result: F64 }, + "fs.linkSync": { argTypes: [DYN, DYN], result: VOID }, + "fs.symlinkSync": { argTypes: [DYN, DYN, DYN], result: VOID }, + /** fs.cpSync / fs/promises cp (scr_fs_cp.c): src, dest and options are + * dyn values the runtime validates in Node's order. */ + "fs.cpSync": { argTypes: [DYN, DYN, DYN], result: VOID }, + "fs.readlinkSync": { argTypes: [DYN, DYN], result: DYN }, + "fs.statfsSync": { argTypes: [DYN, DYN], result: DYN }, + "fs.readlinkSyncStr": { argTypes: [DYN, DYN], result: STRING }, + "fs.readlinkSyncBuffer": { argTypes: [DYN, DYN], result: BYTES_U8 }, + /** fs.openSync(path, flags) → the raw fd as f64; fs.readSync/fs.writeSync + * over Buffer windows perform sequential I/O when position is -1 and + * offset-preserving positioned I/O otherwise; fs.writeStrSync is the + * utf8 string twin; and fs.closeSync(fd) closes the descriptor. This is + * the fd slice behind spawn/log-processing forms. + * flags is Node's string + * grammar ("r", "w", "a" and the +/x variants; unknown flags throw + * Node's ERR_INVALID_ARG_VALUE TypeError text). All throw Node-shaped + * fs errors (openSync ENOENT/EACCES..., readSync EBADF/range errors, + * closeSync EBADF). */ + "fs.openSync": { argTypes: [STRING, STRING], result: F64 }, + "fs.openNumericSync": { argTypes: [STRING, F64, F64], result: F64 }, + "fs.readSync": { argTypes: [F64, BYTES_U8, F64, F64, F64], result: F64 }, + "fs.readSyncDyn": { argTypes: [DYN, DYN, DYN, DYN, DYN], result: F64 }, + "fs.writeSync": { argTypes: [F64, BYTES_U8, F64, F64, F64], result: F64 }, + "fs.writeStrSync": { argTypes: [F64, STRING, F64, STRING], result: F64 }, + // fs.watch's callback func type is program-dependent (zero params, or + // the eventType string) — the slot pins arity and the path/receiver. + /** fs.watch(path, listener?) → an FSWatcher handle (scr_watch.c — + * linked, and scr_watch_install() emitted, only when these appear on + * the IR; moduleUsesFsWatch is the switch). The path opens NOW — + * failure throws Node's fs error synchronously ("ENOENT: ..., watch + * 'x'", the polling-fallback catch shape) — and the unit's kqueue + * (EVFILT_VNODE) delivers "rename"/"change" through the loop's watch + * hook. The callback (nullable) MOVES in with an adapter per listener + * shape (zero-param, or the (eventType: string) form — runtime- + * provided); an open watcher keeps the loop alive until watcher.close() + * (idempotent, receiver borrowed, statement position only). */ + "fs.watch": { argTypes: [STRING], result: FSWATCHER_T }, + "fs.watchCb": { argTypes: [STRING, null], result: FSWATCHER_T }, + "watcher.close": { argTypes: [FSWATCHER_T], result: VOID }, + /** The composed `new crypto.X509Certificate(data).fingerprint` read + * (scr_lib.c — no certificate handle exists): the SHA-1 of the DER, + * uppercase colon-separated, over PEM or raw-DER Buffer input; other + * inputs throw Node's ERR_OSSL_PEM_NO_START_LINE Error (may-throw). */ + "crypto.x509Fingerprint": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509FingerprintStr": { argTypes: [STRING], result: STRING }, + /** The certificate's Validity window (validFrom / validTo reads — + * scr_lib.c's minimal ASN.1 walk to the TBSCertificate validity + * SEQUENCE): UTCTime and GeneralizedTime render in Node's exact + * ASN1_TIME_print shape ("Jul 1 00:00:00 2026 GMT" — %2d space-padded + * day). Same input contract and PEM error as the fingerprint pair + * (may-throw). */ + "crypto.x509ValidFrom": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509ValidFromStr": { argTypes: [STRING], result: STRING }, + "crypto.x509ValidTo": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509ValidToStr": { argTypes: [STRING], result: STRING }, + /** The certificate's DER as a fresh Buffer (the raw field), decoded + * once from the constructor's input; the same PEM error (may-throw). */ + "crypto.x509Raw": { argTypes: [BYTES_U8], result: BYTES_U8 }, + "crypto.x509RawDer": { argTypes: [BYTES_U8], result: BYTES_U8 }, + "crypto.x509RawStr": { argTypes: [STRING], result: BYTES_U8 }, + /** The remaining X509Certificate fields over that DER, in Node's + * renderings (scr_lib.c). subjectAltName, infoAccess and + * signatureAlgorithm answer "" where Node answers undefined. Borrowed; + * never throw. */ + "crypto.x509Subject": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509Issuer": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509SubjectAltName": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509InfoAccess": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509SerialNumber": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509Fingerprint256": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509Fingerprint512": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509Ca": { argTypes: [BYTES_U8], result: BOOL }, + "crypto.x509SignatureAlgorithm": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509SignatureAlgorithmOid": { argTypes: [BYTES_U8], result: STRING }, + /** X509Certificate methods over its raw DER. checkHost/checkEmail/checkIP + * answer the matching name or "" (undefined), checkIssued compares two + * certificates, x509Pem is toString's PEM (scr_x509.c); publicKey, + * verify and checkPrivateKey read keys (scr_pki.c). */ + "crypto.x509CheckHost": { argTypes: [BYTES_U8, DYN, DYN], result: STRING }, + "crypto.x509CheckEmail": { argTypes: [BYTES_U8, DYN, DYN], result: STRING }, + "crypto.x509CheckIP": { argTypes: [BYTES_U8, DYN, DYN], result: STRING }, + "crypto.x509CheckIssued": { argTypes: [BYTES_U8, BYTES_U8], result: BOOL }, + "crypto.x509LegacyObject": { argTypes: [BYTES_U8], result: DYN }, + "crypto.x509Pem": { argTypes: [BYTES_U8], result: STRING }, + "crypto.x509PublicKey": { argTypes: [BYTES_U8], result: DYN }, + "crypto.x509Verify": { argTypes: [BYTES_U8, DYN], result: BOOL }, + "crypto.x509CheckPrivateKey": { argTypes: [BYTES_U8, DYN], result: BOOL }, + "fs.closeSync": { argTypes: [F64], result: VOID }, + "stats.isFile": { argTypes: [STATS_T], result: BOOL }, + "stats.isDirectory": { argTypes: [STATS_T], result: BOOL }, + "stats.isSymbolicLink": { argTypes: [STATS_T], result: BOOL }, + "stats.size": { argTypes: [STATS_T], result: F64 }, + "stats.dev": { argTypes: [STATS_T], result: F64 }, + "stats.ino": { argTypes: [STATS_T], result: F64 }, + "stats.blocks": { argTypes: [STATS_T], result: F64 }, + "stats.nlink": { argTypes: [STATS_T], result: F64 }, + "stats.atimeMs": { argTypes: [STATS_T], result: F64 }, + "stats.mtimeMs": { argTypes: [STATS_T], result: F64 }, + "stats.ctimeMs": { argTypes: [STATS_T], result: F64 }, + "stats.birthtimeMs": { argTypes: [STATS_T], result: F64 }, + "stats.mode": { argTypes: [STATS_T], result: F64 }, + "stats.uid": { argTypes: [STATS_T], result: F64 }, + "stats.gid": { argTypes: [STATS_T], result: F64 }, + "stats.rdev": { argTypes: [STATS_T], result: F64 }, + "stats.blksize": { argTypes: [STATS_T], result: F64 }, + "stats.isBlockDevice": { argTypes: [STATS_T], result: BOOL }, + "stats.isCharacterDevice": { argTypes: [STATS_T], result: BOOL }, + "stats.isFIFO": { argTypes: [STATS_T], result: BOOL }, + "stats.isSocket": { argTypes: [STATS_T], result: BOOL }, + /** The Date fields: the *Ms value rounded (Node's dateFromMs). */ + "stats.atime": { argTypes: [STATS_T], result: DATE_T }, + "stats.mtime": { argTypes: [STATS_T], result: DATE_T }, + "stats.ctime": { argTypes: [STATS_T], result: DATE_T }, + "stats.birthtime": { argTypes: [STATS_T], result: DATE_T }, + // The wider sync fs slice (unlink/chmod/chown/copyfile and the + // mode-carrying write/mkdir forms). + /** The wider sync fs slice (scr_lib.c), all throwing catchably with + * Node's errno message shapes and `.code` stamped like the rest of + * sync fs. unlink/chmod/chown wrap the syscalls 1:1 (Node reports the + * syscall's own name). copyFileSync copies contents into a fresh (or + * truncated) destination carrying the SOURCE's mode (libuv's + * uv_fs_copyfile behavior); its errors carry BOTH paths — Node's + * "copyfile 'src' -> 'dest'". lstatSync is statSync without following + * a trailing symlink (Node reports lstat); stats.isSymbolicLink / + * stats.dev / ino / blocks / nlink / atimeMs / mtimeMs / ctimeMs are pure reads on the widened + * snapshot (blocks is allocated 512-byte units; the times are milliseconds + * with their sub-second fractions, Node's arithmetic). + * writeFileModeSync is writeFileSync(path, data, { mode }): the mode + * applies at CREATION only (open(2) with O_CREAT, umask applying), + * exactly Node — an existing file keeps its permissions. mkdirModeSync + * / mkdirRecursiveModeSync are the mkdirSync option forms with an + * explicit mode (the recursive walk passes it to every directory it + * creates, like Node's). */ + "fs.unlinkSync": { argTypes: [STRING], result: VOID }, + "fs.chmodSync": { argTypes: [STRING, F64], result: VOID }, + "fs.chownSync": { argTypes: [STRING, F64, F64], result: VOID }, + "fs.lchownSync": { argTypes: [STRING, F64, F64], result: VOID }, + "fs.fchownSync": { argTypes: [F64, F64, F64], result: VOID }, + /** truncateSync opens the path with 'r+', then truncates (len checked and + * clamped like ftruncateSync's) and closes it. */ + "fs.truncateSync": { argTypes: [STRING, F64], result: VOID }, + "fs.copyFileSync": { argTypes: [STRING, STRING], result: VOID }, + /** renameSync is the direct two-path syscall wrapper. renameCb defers + * the operation to the loop and fires a program-shaped Error | null + * callback through a backend-emitted adapter. */ + "fs.renameSync": { argTypes: [STRING, STRING], result: VOID }, + // Callback type is program-dependent (zero params or Error | null). + "fs.renameCb": { argTypes: [STRING, STRING, null], result: VOID }, + "fs.writeFileModeSync": { argTypes: [STRING, STRING, F64], result: VOID }, + "fs.mkdirModeSync": { argTypes: [STRING, F64], result: VOID }, + "fs.mkdirRecursiveModeSync": { argTypes: [STRING, F64], result: VOID }, + "atomics.wait": { argTypes: [bytesOf("i32"), F64, F64, F64], result: STRING }, + "atomics.notify": { argTypes: [bytesOf("i32"), F64, F64], result: F64 }, + "atomics.op": { argTypes: [null, F64, F64, F64, F64], result: F64 }, + "atomics.opDyn": { argTypes: [DYN, F64, F64, F64, F64], result: F64 }, + "atomics.waitDyn": { argTypes: [DYN, F64, F64, F64], result: STRING }, + "atomics.notifyDyn": { argTypes: [DYN, F64, F64], result: F64 }, + "worker.new": { argTypes: [F64, STRING, DYN], result: DYN }, + "worker.isMainThread": { argTypes: [], result: BOOL }, + "worker.threadId": { argTypes: [], result: F64 }, + "worker.root": { argTypes: [], result: F64 }, + "worker.data": { argTypes: [], result: DYN }, + "worker.parentPort": { argTypes: [], result: DYN }, + /** worker_threads.resourceLimits: {} in the main thread; a refusal in a + * worker (scr_worker_events.c). */ + "worker.resourceLimits": { argTypes: [], result: DYN }, + /** worker_threads.threadName: the Worker's name in a worker, "" in the + * main thread (scr_worker.c). */ + "worker.threadName": { argTypes: [], result: DYN }, + /** new MessageChannel() ({ port1, port2 }) and receiveMessageOnPort(port) + * (scr_worker_events.c; the latter may throw). */ + "worker.channel": { argTypes: [], result: DYN }, + "worker.receiveMessageOnPort": { argTypes: [DYN], result: DYN }, + /** setEnvironmentData(key, value) and getEnvironmentData(key) + * (scr_worker_events.c; arguments borrowed). */ + "worker.setEnvironmentData": { argTypes: [DYN, DYN], result: VOID }, + "worker.getEnvironmentData": { argTypes: [DYN], result: DYN }, + /** markAsUntransferable(value) and isMarkedAsUntransferable(value) + * (scr_worker_events.c; the value borrowed). */ + "worker.markUntransferable": { argTypes: [DYN], result: VOID }, + "worker.isMarkedUntransferable": { argTypes: [DYN], result: BOOL }, + /** markAsUncloneable(value) (scr_json.c; the value borrowed). */ + "dyn.markUncloneable": { argTypes: [DYN], result: VOID }, + /** before new Worker() with the stdout or stderr option: links the stream + * unit that worker.stdout and worker.stderr read through (scr_stream.c). */ + "stream.workerStdio": { argTypes: [], result: VOID }, + /** new BroadcastChannel(...args) (scr_worker_events.c; may throw), after + * event.broadcastInstall, which installs its EventTarget side. */ + "worker.broadcastChannel": { argTypes: [DYN], result: DYN }, + "event.broadcastInstall": { argTypes: [], result: VOID }, + /** child_process.spawnSync (scr_child.c): posix_spawn + waitpid + piped + * utf8 capture — cmd borrowed, args one borrowed string[] (the frontend + * completes an omitted list to an empty literal), result an owned (+1) + * spawnRes. NEVER throws: spawn failure (nonexistent binary, EACCES) is + * data, like Node's error property — status null and empty outputs + * (SEMANTICS.md documents the divergence from Node's null stdout). + * The getters are pure reads: status is the interned `number | null` + * union (null = spawn failure or signal death, type-directed + * construction in the backend like process.envGet); stdout/stderr are + * +1 strings. */ + "cp.spawnSync": { argTypes: [STRING, arrayOf(STRING)], result: SPAWNRES_T }, + // spawnSync's options form: timeout, killSignal name ("" = SIGTERM), + // and the three stdio modes. + /** spawnSync with options (scr_child.c): the cp.spawnSync core plus the + * option slice portless-class CLIs pass — timeout (killSignal fires at + * the deadline and the result carries error: ETIMEDOUT + the signal, + * Node's shape), killSignal (a signal NAME; "" = the SIGTERM default), + * and per-fd stdio modes (in: 0 /dev/null, 1 ignore, 2 inherit; out/ + * err: 0 capture, 1 ignore → "", 2 inherit → ""). NEVER throws — spawn + * failure and timeout are data on the result, like Node's error + * property. spawnRes.signal is the result's termination signal as the + * call site's `Signals | null` union (null = exited normally or spawn + * failure), constructed type-directedly like spawnRes.status. */ + "cp.spawnSyncOpts": { + argTypes: [STRING, arrayOf(STRING), F64, STRING, F64, F64, F64], + result: SPAWNRES_T, + }, + /** cp.spawnSyncOpts with the `env` option: the trailing [k,v,...] + * pairs replace the child's environment (recordToEnvPairs). */ + "cp.spawnSyncEnv": { + argTypes: [STRING, arrayOf(STRING), F64, STRING, F64, F64, F64, arrayOf(STRING)], + result: SPAWNRES_T, + }, + /** cp.spawnSyncOpts with the stdio carried as a RUNTIME string — + * "pipe" | "ignore" | "inherit", proven by the call site's TYPE (the + * defaultRunner idiom `stdio: options?.stdio ?? "pipe"`); the runtime + * maps the value to the three modes. Args (cmd, argv, timeout, + * killSignal, stdio). Never throws, like the other spawnSync forms. */ + "cp.spawnSyncStdioStr": { + argTypes: [STRING, arrayOf(STRING), F64, STRING, STRING], + result: SPAWNRES_T, + }, + // node:net (scr_net.c). Listener slots are program-dependent closures — + // null slots, checked in the libCall case (the child.onExit precedent); + // the zero-param callbacks pin the exact func type here. The trailing + // BOOL on registrations is the once flag. + /** node:net (scr_net.c — linked, and scr_net_install() emitted, only + * when one of these appears on the IR; moduleUsesNet is the switch). + * Receivers are borrowed; CALLBACKS MOVE into the handle's listener + * registry and are released at settlement (the child.onExit story). + * All listener registrations carry a trailing BOOL once-flag (`on` vs + * `once`) and are void — chaining is fenced. None of these throw: + * listen/connect failures are the async 'error' event, like Node. + * + * net.createServer's optional connection handler and the + * serverOnConnection listeners take the runtime-provided adapters + * (zero-param, or the one-param socket shape); sockOnData's adapters + * are the stdin pair's shapes (zero-param / bytes chunk); the error + * events reuse the child %Error adapters. net.listen/net.listenCb bind + * NOW and defer 'listening' to the next loop turn (Node's next-tick + * emit); net.serverPort is the composed `server.address().port` read. + * net.connect's host argument is a string ("localhost" pins to + * 127.0.0.1 — SEMANTICS.md); the connect callback is once('connect'). */ + "net.createServer": { argTypes: [], result: NETSERVER_T }, + "net.createServerCb": { argTypes: [null], result: NETSERVER_T }, + "net.listen": { argTypes: [NETSERVER_T, F64], result: VOID }, + /** listen(path[, cb]): a Unix-socket server; the socket file is removed + * when the server closes. Failures are the async 'error'. */ + "net.listenPath": { argTypes: [NETSERVER_T, STRING], result: VOID }, + "net.listenPathCb": { + argTypes: [NETSERVER_T, STRING, { kind: "func", params: [], ret: VOID }], + result: VOID, + }, + "net.listenCb": { + argTypes: [NETSERVER_T, F64, { kind: "func", params: [], ret: VOID }], + result: VOID, + }, + /** listen({ port, host, ipv6Only }[, cb]) — the explicit-interface bind + * (portless's listenOnProxyInterface): args [server, port, host, + * ipv6Only]. host is an IP literal string ("" = the host-less + * dual-stack any default); ipv6Only sets IPV6_V6ONLY before the bind. + * These are the old-shaped calls, retained for omitted reusePort so + * serialized IR remains compatible. Failures are the async 'error', + * message in Node's listen shape with the requested host. Never throws. */ + "net.listenOpts": { argTypes: [NETSERVER_T, F64, STRING, BOOL], result: VOID }, + // The callback slot is a zero-param void closure OR its + // `(() => void) | undefined` optional-binding union (checked specially). + "net.listenOptsCb": { argTypes: [NETSERVER_T, F64, STRING, BOOL, null], result: VOID }, + /** Additive ABI for listen({ ..., reusePort }) — args + * [server, port, host, ipv6Only, reusePort], with the callback following + * those values in the callback form. The final BOOL is the requested + * kernel connection-distribution option; old spellings remain + * four/five-argument calls so serialized IR stays compatible. */ + "net.listenOptsReusePort": { argTypes: [NETSERVER_T, F64, STRING, BOOL, BOOL], result: VOID }, + // The callback is a zero-param void closure OR its optional-binding union; + // the callback follows the reusePort BOOL in this additive ABI. + "net.listenOptsReusePortCb": { + argTypes: [NETSERVER_T, F64, STRING, BOOL, BOOL, null], + result: VOID, + }, + "net.serverPort": { argTypes: [NETSERVER_T], result: F64 }, + "net.serverListening": { argTypes: [NETSERVER_T], result: BOOL }, + /** socket.ref()/unref() and server.ref()/unref(): whether the handle + * keeps the event loop alive. */ + "net.sockSetRef": { argTypes: [NETSOCKET_T, BOOL], result: VOID }, + "net.serverSetRef": { argTypes: [NETSERVER_T, BOOL], result: VOID }, + // net.serverAddress's record result is shape-checked in the libCall case + // (the dgram.address sentinel pattern). + /** server.address() as the full AddressInfo record (the dgram.address + * materialization pattern: the emitter builds the record from the three + * runtime reads; the frontend pinned the shape). Never throws — before + * listen it answers the any-form defaults with port 0 where Node + * answers null (the serverPort stance). */ + "net.serverAddress": { argTypes: [NETSERVER_T], result: VOID }, + "net.serverClose": { argTypes: [NETSERVER_T], result: VOID }, + /** server.close((err) => ...): the callback (a dyn function) gets + * undefined once the server closes, or Node's ERR_SERVER_NOT_RUNNING + * when it was not listening. */ + "net.serverCloseDyn": { argTypes: [NETSERVER_T, DYN], result: VOID }, + /** server.address() in programs that may listen on a Unix socket: the + * path a listening server answers ("" for a TCP server), and the check + * a record-typed address() makes first (throws for a Unix server). */ + "net.serverUnixPath": { argTypes: [NETSERVER_T], result: STRING }, + "net.serverAddressCheck": { argTypes: [NETSERVER_T], result: VOID }, + "net.serverCloseCb": { + argTypes: [NETSERVER_T, { kind: "func", params: [], ret: VOID }], + result: VOID, + }, + "net.serverOnError": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, + "net.serverOnClose": { + argTypes: [NETSERVER_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + "net.serverOnConnection": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, + /** 'secureConnection' — the TLS server's deferred 'connection' list + * (handshake-completion timing); on a server without deferred + * connections (a plain net server) the registration never fires, + * exactly Node's split. */ + "net.serverOnSecureConnection": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, + "net.connect": { argTypes: [F64, STRING], result: NETSOCKET_T }, + /** connect with a validated autoSelectFamilyAttemptTimeout option (the + * budget runs Node's validateInt32-from-1 ladder and is then inert — + * the single dial has nothing to time). May-throw. */ + "net.connectAttempt": { argTypes: [F64, STRING, DYN], result: NETSOCKET_T }, + /** net.connect/createConnection over a RUNTIME option bag (computed + * keys — the invalid-input probes): Node-order validation (the + * objectMode trio's ERR_INVALID_ARG_VALUE, validatePort, host string, + * autoSelectFamily boolean, the attempt budget), then the trailing + * compiler-rendered fence — ALWAYS THROWS (the error.nodeThrow + * polymorphic-result carve-out). May-throw seed. */ + "net.connectOptsChk": { argTypes: [DYN, STRING], result: VOID }, + "net.connectCb": { + argTypes: [F64, STRING, { kind: "func", params: [], ret: VOID }], + result: NETSOCKET_T, + }, + // The lookup's exact func shape is program data (its answer callback's + // union/record types) — checked specially in the libCall case. + /** connect({ port, host, autoSelectFamily: true, lookup }) — the + * caller-resolver dial (portless's createLoopbackConnection): args + * [port, host, lookup]. The runtime creates the (connecting) socket + * handle, invokes the lookup as Node does — lookup(hostname, options, + * callback), options crossing as the dyn undefined — and the answer + * closure (an emitter-synthesized per-shape thunk over a boxed socket, + * the SNI-answer pattern) dials the answered addresses IN ORDER: each + * connect failure tries the next, the LAST failure's message is the + * socket's 'error' (Node's autoSelectFamily aggregate is a documented + * divergence), and a lookup error surfaces as the deferred socket + * 'error'. A synchronous throw INSIDE the lookup propagates out of the + * connect call (may-throw seed). */ + "net.connectLookup": { argTypes: [F64, STRING, null], result: NETSOCKET_T }, + /** connect({ host, port, lookup }) with a lookup of Node's own type, as + * a checked-dynamic function: the runtime calls it with { hints, all: + * true } and a callback taking an address string or list, then dials + * the answers in order. MAY THROW (host validation, a lookup throw). */ + "net.connectLookupDyn": { argTypes: [F64, STRING, DYN], result: NETSOCKET_T }, + "net.sockWrite": { argTypes: [NETSOCKET_T, STRING], result: VOID }, + "net.sockWriteBytes": { argTypes: [NETSOCKET_T, BYTES_U8], result: VOID }, + "net.sockEnd": { argTypes: [NETSOCKET_T], result: VOID }, + "net.sockEndStr": { argTypes: [NETSOCKET_T, STRING], result: VOID }, + "net.sockEndBytes": { argTypes: [NETSOCKET_T, BYTES_U8], result: VOID }, + /** write/end with a CHECKED-DYNAMIC chunk (an untyped JS payload into a + * typed socket): the runtime dispatches STR/BYTES and throws Node's + * ERR_INVALID_ARG_TYPE chunk TypeError on any other kind. */ + "net.sockWriteDyn": { argTypes: [NETSOCKET_T, DYN], result: VOID }, + "net.sockEndDyn": { argTypes: [NETSOCKET_T, DYN], result: VOID }, + "net.sockDestroy": { argTypes: [NETSOCKET_T], result: VOID }, + "net.sockPipe": { argTypes: [NETSOCKET_T, NETSOCKET_T], result: VOID }, + /** socket.pipe(res) — raw socket chunks into a ServerResponse body + * (the extended-CONNECT bridge leg): each chunk is a body write (the + * response's own framing applies); source EOF end()s the response, + * pipe's default. Borrows both. Never throws. */ + "net.sockPipeRes": { argTypes: [NETSOCKET_T, HTTPRES_T], result: VOID }, + "net.sockOnData": { argTypes: [NETSOCKET_T, null, BOOL], result: VOID }, + "net.sockOnEnd": { + argTypes: [NETSOCKET_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + "net.sockOnClose": { + argTypes: [NETSOCKET_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + "net.sockOnError": { argTypes: [NETSOCKET_T, null, BOOL], result: VOID }, + "net.sockOnConnect": { + argTypes: [NETSOCKET_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + // node:dgram + node:dns (scr_dgram.c). The message/error listeners and + // dns.lookup's callback are program-dependent closures (null slots, + // checked in the libCall case); dgram.address's record result is + // program-dependent too (VOID here is the envGet sentinel — the libCall + // case checks the {address, family, port} shape). + /** node:dgram + node:dns (scr_dgram.c — linked, and + * scr_dgram_install() emitted, only when one of these appears on the + * IR; moduleUsesDgram is the switch — dns.lookup rides the same unit). + * The net listener discipline verbatim: receivers borrowed, CALLBACKS + * MOVE into the handle's registry and release at settlement, `on` vs + * `once` is the trailing bool, registrations are void. bind/connect + * bind NOW and defer 'listening'/'connect' to the next loop turn (the + * net.listen story); their optional-host completions are "" + * (bind → 0.0.0.0) and "127.0.0.1" (connect — udp4's Node default). + * bind/connect/send/close/address THROW Node's state errors ("Socket + * is already bound", "Already connected", "Not running") — may-throw + * seeded. dgram.address returns the AddressInfo RECORD (the frontend + * pins the {address, family, port} shape; the emitter builds it from + * runtime parts). onMessage adapters are emitted per rinfo record + * shape (the child.onExit precedent); onError reuses the child %Error + * adapters. dns.lookup resolves via getaddrinfo AT CALL TIME and + * defers the callback to the next turn (SEMANTICS.md documents the + * blocking divergence); its per-union adapter builds the + * `Error | null` first argument. */ + "dgram.createSocket": { argTypes: [BOOL], result: DGRAMSOCK_T }, + "dgram.bind": { argTypes: [DGRAMSOCK_T, F64, STRING], result: VOID }, + "dgram.bindCb": { + argTypes: [DGRAMSOCK_T, F64, STRING, { kind: "func", params: [], ret: VOID }], + result: VOID, + }, + "dgram.connect": { argTypes: [DGRAMSOCK_T, F64, STRING], result: VOID }, + "dgram.connectCb": { + argTypes: [DGRAMSOCK_T, F64, STRING, { kind: "func", params: [], ret: VOID }], + result: VOID, + }, + "dgram.sendStr": { argTypes: [DGRAMSOCK_T, STRING, F64, STRING], result: VOID }, + "dgram.sendBytes": { argTypes: [DGRAMSOCK_T, BYTES_U8, F64, STRING], result: VOID }, + /** Connected AF_UNIX datagram sockets for the hot-shots package shim + * (the unix-dgram addon's surface): fd or result >= 0, -errno on + * failure; send answers 1 when the socket would block. */ + "dgram.unixSocket": { argTypes: [], result: F64 }, + "dgram.unixConnect": { argTypes: [F64, STRING], result: F64 }, + "dgram.unixSend": { argTypes: [F64, BYTES_U8], result: F64 }, + "dgram.unixClose": { argTypes: [F64], result: F64 }, + /** The send argument-validation ladder over dyn arguments (Node's + * signature shuffle: slice bounds, list/type contracts, port/address + * validation, connected-state errors), then the send: lists, connected + * sends and completion callbacks included. Up to six arguments, the + * missing ones undefined. May-throw. */ + "dgram.sendChk": { argTypes: [DGRAMSOCK_T, DYN, DYN, DYN, DYN, DYN, DYN], result: VOID }, + "dgram.address": { argTypes: [DGRAMSOCK_T], result: VOID }, + "dgram.close": { argTypes: [DGRAMSOCK_T], result: VOID }, + "dgram.closeCb": { + argTypes: [DGRAMSOCK_T, { kind: "func", params: [], ret: VOID }], + result: VOID, + }, + "dgram.unref": { argTypes: [DGRAMSOCK_T], result: VOID }, + "dgram.ref": { argTypes: [DGRAMSOCK_T], result: VOID }, + /** The socket options (scr_dgram.c): the membership calls take the + * interface and whether it was given. May-throw. */ + "dgram.setBroadcast": { argTypes: [DGRAMSOCK_T, BOOL], result: VOID }, + "dgram.setTTL": { argTypes: [DGRAMSOCK_T, F64], result: F64 }, + "dgram.setMulticastTTL": { argTypes: [DGRAMSOCK_T, F64], result: F64 }, + "dgram.setMulticastLoopback": { argTypes: [DGRAMSOCK_T, BOOL], result: BOOL }, + "dgram.setMulticastInterface": { argTypes: [DGRAMSOCK_T, STRING], result: VOID }, + "dgram.addMembership": { argTypes: [DGRAMSOCK_T, STRING, STRING, BOOL], result: VOID }, + "dgram.dropMembership": { argTypes: [DGRAMSOCK_T, STRING, STRING, BOOL], result: VOID }, + "dgram.getRecvBufferSize": { argTypes: [DGRAMSOCK_T], result: F64 }, + "dgram.getSendBufferSize": { argTypes: [DGRAMSOCK_T], result: F64 }, + "dgram.setRecvBufferSize": { argTypes: [DGRAMSOCK_T, F64], result: VOID }, + "dgram.setSendBufferSize": { argTypes: [DGRAMSOCK_T, F64], result: VOID }, + "dgram.getSendQueueSize": { argTypes: [DGRAMSOCK_T], result: F64 }, + "dgram.getSendQueueCount": { argTypes: [DGRAMSOCK_T], result: F64 }, + "dgram.disconnect": { argTypes: [DGRAMSOCK_T], result: VOID }, + "dgram.onMessage": { argTypes: [DGRAMSOCK_T, null, BOOL], result: VOID }, + "dgram.onError": { argTypes: [DGRAMSOCK_T, null, BOOL], result: VOID }, + "dgram.onListening": { + argTypes: [DGRAMSOCK_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + "dgram.onClose": { + argTypes: [DGRAMSOCK_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + "dgram.onConnect": { + argTypes: [DGRAMSOCK_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + "dns.lookup": { argTypes: [STRING, F64, null], result: VOID }, + /** Node's argument forms with dyn callbacks: lookup(hostname, options, + * callback) and lookupService(address, port, callback). */ + "dns.lookupDyn": { argTypes: [DYN, DYN, DYN, BOOL], result: VOID }, + "dns.lookupService": { argTypes: [DYN, DYN, DYN, BOOL], result: VOID }, + /** node:dns/promises: lookup(hostname, options) and lookupService(address, + * port) over the callback forms; the promise fulfills with the dyn + * { address, family } (array for all: true) / { hostname, service }. + * Argument errors throw synchronously (may-throw), unlike the + * util.promisify forms below. */ + "dns.promisesLookup": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, + "dns.promisesLookupService": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, + "dns.getServers": { argTypes: [], result: DYN }, + "dns.getDefaultResultOrder": { argTypes: [], result: STRING }, + "dns.setDefaultResultOrder": { argTypes: [DYN], result: VOID }, + // node:test (scr_test.c). Bodies are program-dependent closures (0 or + // 1 testCtx param, void or Promise result — the spoke pinned the + // shape): null slots. sub's result is the settled Promise the + // await consumes. + /** node:test (scr_test.c — linked only when one of these appears on + * the IR; moduleUsesNodeTest is the switch, and the main epilogue asks + * scr_test_exit_code() for the process's exit status). Strings are + * BORROWED, callbacks MOVE. register/suite/hook attach to the runner + * tree (register: name, mode 0|1|2 run/skip/todo, directive message "" + * = none, cb or absent via registerEmpty, flags 1 async | 2 takes-ctx + * | 4 only, "file:line:col"); suite runs its body AT registration + * (Node's collection phase). sub is t.test — runs the subtest INLINE + * on the runner fiber and returns the settled promise the await + * consumes. ctxSkip/ctxTodo mark the running test; ctxDiagnostic + * queues an ℹ line; ctxName reads t.name. Every registration keeps + * the loop-run emitted (usesTimers) so the runner fiber drains. */ + // The trailing three are the { plan, timeout, concurrency } options (plan + // -1 without one; timeout read under flag 8; concurrency read under flag + // 16, -1 for true). An out-of-range timeout or concurrency throws. + "test.register": { + argTypes: [STRING, F64, STRING, null, F64, STRING, F64, F64, F64], + result: VOID, + }, + "test.registerEmpty": { + argTypes: [STRING, F64, STRING, F64, STRING, F64, F64, F64], + result: VOID, + }, + // The suite body takes no parameters or its SuiteContext (flag 2). + "test.suite": { argTypes: [STRING, F64, STRING, null, STRING, F64, F64], result: VOID }, + // The trailing string is the hook call's "file:line:col". + "test.hook": { argTypes: [F64, null, F64, STRING], result: VOID }, + "test.sub": { + argTypes: [TESTCTX_T, STRING, F64, STRING, null, F64, STRING, F64, F64, F64], + result: { kind: "promise", inner: VOID }, + }, + "test.subEmpty": { + argTypes: [TESTCTX_T, STRING, F64, STRING, F64, STRING, F64, F64, F64], + result: VOID, + }, + "test.ctxSkip": { argTypes: [TESTCTX_T, STRING], result: VOID }, + "test.ctxTodo": { argTypes: [TESTCTX_T, STRING], result: VOID }, + "test.ctxDiagnostic": { argTypes: [TESTCTX_T, STRING], result: VOID }, + "test.ctxName": { argTypes: [TESTCTX_T], result: STRING }, + "test.ctxFullName": { argTypes: [TESTCTX_T], result: STRING }, + // t.passed, and t.workerId's Number(NODE_TEST_WORKER_ID) with 0 for + // undefined. + "test.ctxPassed": { argTypes: [TESTCTX_T], result: BOOL }, + "test.workerId": { argTypes: [], result: F64 }, + // getTestContext(): whether a test, suite or hook is running in the + // current async context, and that context. + "test.hasContext": { argTypes: [], result: BOOL }, + "test.context": { argTypes: [], result: TESTCTX_T }, + // t.before/t.after/t.beforeEach/t.afterEach (which: 0 before, 1 after, + // 2 beforeEach, 3 afterEach); a throwing t.before is captured on the test. + "test.ctxHook": { argTypes: [TESTCTX_T, F64, null, F64], result: VOID }, + // t.plan(count), and the count of one t.assert call. + "test.ctxPlan": { argTypes: [TESTCTX_T, F64], result: VOID }, + "test.ctxCount": { argTypes: [TESTCTX_T], result: VOID }, + // The mock trackers: the module's `mock` and t.mock keep each mock's + // restore closure (moved) for restoreAll and reset. + "test.mockTrack": { argTypes: [{ kind: "func", params: [], ret: VOID }], result: VOID }, + "test.mockRestoreAll": { argTypes: [], result: VOID }, + "test.mockReset": { argTypes: [], result: VOID }, + "test.ctxMockTrack": { + argTypes: [TESTCTX_T, { kind: "func", params: [], ret: VOID }], + result: VOID, + }, + "test.ctxMockRestoreAll": { argTypes: [TESTCTX_T], result: VOID }, + "test.ctxMockReset": { argTypes: [TESTCTX_T], result: VOID }, + // mock.timers on the module's `mock` and on t.mock. enable takes one + // code per listed API ('T' setTimeout, 'I' setInterval), the `now` + // value and its flags (1 given, 2 from a Date). enable, tick, runAll and + // setTime throw Node's errors; tick and runAll run timer callbacks. + // t.assert.snapshot and fileSnapshot: the escaped, wrapped serialized + // value, and the stored value it is compared with (snapshot: the test, + // the value, the snapshot file; fileSnapshot: the value, the path). + // Both read or, in update mode, record; missing and unreadable + // snapshots throw Node's ERR_INVALID_STATE. + "test.snapshotValue": { argTypes: [STRING], result: STRING }, + "test.ctxSnapshot": { argTypes: [TESTCTX_T, STRING, STRING], result: STRING }, + "test.fileSnapshot": { argTypes: [STRING, STRING], result: STRING }, + // Node's serializeValue over a dyn array of serializers (undefined for + // the default JSON.stringify(value, null, 2)); a throw becomes Node's + // "The provided serializers did not generate a string." ERR_INVALID_STATE. + "test.snapshotSerialize": { argTypes: [DYN, DYN], result: DYN }, + "test.mockTimersEnable": { argTypes: [STRING, F64, F64], result: VOID }, + "test.mockTimersTick": { argTypes: [F64], result: VOID }, + "test.mockTimersRunAll": { argTypes: [], result: VOID }, + "test.mockTimersReset": { argTypes: [], result: VOID }, + "test.mockTimersSetTime": { argTypes: [F64], result: VOID }, + "test.ctxMockTimersEnable": { argTypes: [TESTCTX_T, STRING, F64, F64], result: VOID }, + "test.ctxMockTimersTick": { argTypes: [TESTCTX_T, F64], result: VOID }, + "test.ctxMockTimersRunAll": { argTypes: [TESTCTX_T], result: VOID }, + "test.ctxMockTimersReset": { argTypes: [TESTCTX_T], result: VOID }, + "test.ctxMockTimersSetTime": { argTypes: [TESTCTX_T, F64], result: VOID }, + // node:http (scr_http.c over scr_net.c). The handler and the data + // listeners are program-dependent closures (null slots, checked in the + // libCall case); reqHeader's result is the interned string|undefined + // union, checked like process.envGet. + /** node:http, the server slice (scr_http.c over scr_net.c — linked + * only when these appear on the IR; moduleUsesHttpServer is the + * switch, and any http.* libCall also counts as net use so scr_net.c + * links and installs). http.createServer's handler MOVES in and takes + * the runtime adapters for its (req, res) / (req) / () shapes; req + * body listeners follow the net.sockOnData story (bytes chunks, once + * flags); reqHeader answers the interned `string | undefined` union + * exactly like process.envGet; the res writers are borrowed-argument + * voids with Node's framing decided in the runtime (Content-Length + * for end-before-head, chunked after an explicit writeHead/write). */ + "http.createServer": { argTypes: [null], result: NETSERVER_T }, + /** http.createServer() / http.Server() with no handler — the + * on("request") route; option helpers set parser behavior on a fresh + * server before the constructor/factory result is returned. */ + "http.createServerEmpty": { argTypes: [], result: NETSERVER_T }, + "http.validateHeaderName": { argTypes: [STRING, STRING], result: VOID }, + "http.validateHeaderValue": { argTypes: [STRING, DYN], result: VOID }, + "http.serverJoinDupHeaders": { argTypes: [NETSERVER_T], result: VOID }, + "http.serverAllowMissingHostHeader": { argTypes: [NETSERVER_T], result: VOID }, + /** The five writable numeric http.Server timeout fields use one + * selector ABI: 0 timeout, 1 keepAliveTimeout, 2 headersTimeout, + * 3 requestTimeout, 4 keepAliveTimeoutBuffer. These calls store/read + * the property values; timer enforcement remains outside this surface. + * The constructor-option setter takes dyn so explicit undefined remains + * distinguishable from a numeric value until its Node validation ladder. */ + "http.serverTimeoutGet": { argTypes: [NETSERVER_T, F64], result: F64 }, + "http.serverSetTimeout": { argTypes: [NETSERVER_T, F64], result: VOID }, + "http.serverSetTimeoutCb": { argTypes: [NETSERVER_T, F64, null], result: VOID }, + "http.serverOnTimeout": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, + "http.serverCloseAllConnections": { argTypes: [NETSERVER_T], result: VOID }, + "http.serverCloseIdleConnections": { argTypes: [NETSERVER_T], result: VOID }, + "http.serverTimeoutSet": { argTypes: [NETSERVER_T, F64, F64], result: VOID }, + "http.serverTimeoutOptionSet": { argTypes: [NETSERVER_T, F64, DYN], result: VOID }, + /** server.on("listening", cb) — the deferred listen-callback list. */ + "net.serverOnListening": { + argTypes: [NETSERVER_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + /** The ServerResponse member surface: statusCode/statusMessage reads + * and assignments (Node's writable properties), the header CRUD trio + * (getHeader answers `string | undefined` like reqHeader), and + * end(cb)'s callback slot (resOnEndCallback registers, the end call + * follows — the callback fires deferred, just before Node's 'finish' + * emit; resOnFinish is the 'finish' listener slot). writeHead's + * statusMessage forms compose in interned helpers: resStatusMsgSet + * then the ordinary writeHead entry. */ + "http.resStatusGet": { argTypes: [HTTPRES_T], result: F64 }, + "http.resStatusSet": { argTypes: [HTTPRES_T, F64], result: VOID }, + "http.resStatusMsgGet": { argTypes: [HTTPRES_T], result: VOID }, + "http.resStatusMsgSet": { argTypes: [HTTPRES_T, STRING], result: VOID }, + "http.resRequest": { argTypes: [HTTPRES_T], result: HTTPREQ_T }, + "http.resSocket": { argTypes: [HTTPRES_T], result: VOID }, + "http.resWritableFinished": { argTypes: [HTTPRES_T], result: BOOL }, + "http.resSendDateGet": { argTypes: [HTTPRES_T], result: BOOL }, + "http.resSendDateSet": { argTypes: [HTTPRES_T, BOOL], result: VOID }, + "http.resStrictContentLengthGet": { argTypes: [HTTPRES_T], result: BOOL }, + "http.resStrictContentLengthSet": { argTypes: [HTTPRES_T, BOOL], result: VOID }, + "http.resSetTimeout": { argTypes: [HTTPRES_T, F64], result: VOID }, + "http.resSetTimeoutCb": { + argTypes: [HTTPRES_T, F64, { kind: "func", params: [], ret: VOID }], + result: VOID, + }, + // resGetHeader answers the interned `string | undefined` union — the + // reqHeader/envGet sentinel pattern (VOID here, checked specially). + "http.resGetHeader": { argTypes: [HTTPRES_T, STRING], result: VOID }, + /** getHeader as Node answers it: the number, string or string[] that was + * set, or undefined, as a checked-dynamic value. */ + "http.resGetHeaderDyn": { argTypes: [HTTPRES_T, STRING], result: DYN }, + "http.resGetHeaderNames": { argTypes: [HTTPRES_T], result: arrayOf(STRING) }, + "http.resGetRawHeaderNames": { argTypes: [HTTPRES_T], result: arrayOf(STRING) }, + "http.resGetHeaders": { argTypes: [HTTPRES_T], result: DYN }, + "http.resHasHeader": { argTypes: [HTTPRES_T, STRING], result: BOOL }, + "http.resRemoveHeader": { argTypes: [HTTPRES_T, STRING], result: VOID }, + "http.resOnFinish": { + argTypes: [HTTPRES_T, { kind: "func", params: [], ret: VOID }], + result: VOID, + }, + "http.resOnEndCallback": { + argTypes: [HTTPRES_T, { kind: "func", params: [], ret: VOID }], + result: VOID, + }, + "http.reqUrl": { argTypes: [HTTPREQ_T], result: STRING }, + "http.reqMethod": { argTypes: [HTTPREQ_T], result: STRING }, + "http.reqHeader": { argTypes: [HTTPREQ_T, STRING], result: VOID }, + "http.reqTrailer": { argTypes: [HTTPREQ_T, STRING], result: VOID }, + "http.reqHeaderValues": { argTypes: [HTTPREQ_T, STRING], result: VOID }, + "http.reqTrailerValues": { argTypes: [HTTPREQ_T, STRING], result: VOID }, + "http.reqOnData": { argTypes: [HTTPREQ_T, null, BOOL], result: VOID }, + "http.reqOnEnd": { + argTypes: [HTTPREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + "http.resSetHeader": { argTypes: [HTTPRES_T, STRING, STRING], result: VOID }, + /** setHeader / appendHeader with a number, string or array value; the + * stored value keeps its type for getHeader/getHeaders. MAY THROW. */ + "http.resSetHeaderDyn": { argTypes: [HTTPRES_T, STRING, DYN], result: VOID }, + "http.resAppendHeader": { argTypes: [HTTPRES_T, STRING, DYN], result: VOID }, + "http.resWriteHead": { argTypes: [HTTPRES_T, F64], result: VOID }, + "http.resWriteHeadN": { + argTypes: [HTTPRES_T, F64, arrayOf(STRING), arrayOf(STRING)], + result: VOID, + }, + /** HTTP/1.1 informational heads; early hints takes flat string pairs, + * with a lowercase `link` key required to send anything. */ + "http.resWriteContinue": { argTypes: [HTTPRES_T], result: VOID }, + "http.resWriteProcessing": { argTypes: [HTTPRES_T], result: VOID }, + "http.resWriteEarlyHints": { argTypes: [HTTPRES_T, arrayOf(STRING)], result: VOID }, + "http.resWrite": { argTypes: [HTTPRES_T, STRING], result: VOID }, + "http.resWriteBytes": { argTypes: [HTTPRES_T, BYTES_U8], result: VOID }, + "http.resEnd": { argTypes: [HTTPRES_T], result: VOID }, + "http.resEndStr": { argTypes: [HTTPRES_T, STRING], result: VOID }, + "http.resEndBytes": { argTypes: [HTTPRES_T, BYTES_U8], result: VOID }, + /** The checked-dynamic chunk twins (the net.sockWriteDyn story). */ + "http.resWriteDyn": { argTypes: [HTTPRES_T, DYN], result: VOID }, + "http.resEndDyn": { argTypes: [HTTPRES_T, DYN], result: VOID }, + "http.resHeadersSent": { argTypes: [HTTPRES_T], result: BOOL }, + "http.resWritableEnded": { argTypes: [HTTPRES_T], result: BOOL }, + "http.resFlushHeaders": { argTypes: [HTTPRES_T], result: VOID }, + "http.resAddTrailers": { argTypes: [HTTPRES_T, arrayOf(STRING)], result: VOID }, + "http.resCork": { argTypes: [HTTPRES_T], result: VOID }, + "http.resUncork": { argTypes: [HTTPRES_T], result: VOID }, + "http.resWritableCorked": { argTypes: [HTTPRES_T], result: F64 }, + // The member follow-ups: reqStatusCode's `number | undefined` and + // sockRemoteAddress's `string | undefined` results are shape-checked in + // the special cases in validate.ts (like reqHeader/columns). + /** The server-surface member follow-ups: reqStatusCode answers the + * interned `number | undefined` union (negative = the undefined arm — + * a SERVER request, where Node's statusCode is undefined; every client + * response carries a real status); reqSocket is the underlying + * connection (+1, the same handle net.connect would give); + * sockRemoteAddress answers `string | undefined` (NULL after the fd + * closed, Node's destroyed-socket undefined; a dual-stack accept of an + * IPv4 peer reads "::ffff:a.b.c.d" like Node). reqResume/reqPause/reqDestroy and + * the req error/close listener slots complete the IncomingMessage + * surface portless's client responses use; resDestroy/resOnClose and + * resWriteHeadPairs ([k0,v0,k1,v1,...] — the env.pairs helper's flat + * shape) complete ServerResponse. sockSetTimeout arms the idle + * EVFILT_TIMER ('timeout' fires after ms of inactivity, once per idle + * period, never destroying the socket — Node's semantics). */ + "http.reqStatusCode": { argTypes: [HTTPREQ_T], result: VOID }, + // reqStatusMessage's `string | undefined` is program-interned like + // reqHeader's (the VOID here is the envGet sentinel). + "http.reqStatusMessage": { argTypes: [HTTPREQ_T], result: VOID }, + /** req.rawHeaders — [name, value, name, value, ...] in arrival order, + * names in their ORIGINAL case (Node's shape); a fresh string[] per + * read. reqStatusMessage answers the interned `string | undefined` + * union — the reason phrase on client responses ("" when the status + * line carried none), the undefined arm on server requests (the + * statusCode split). sockDestroyed is socket.destroyed — true once the + * fd is gone (destroy() or full close). */ + "http.reqRawHeaders": { argTypes: [HTTPREQ_T], result: arrayOf(STRING) }, + /** The `{ ...req.headers }` snapshot feed: [lowercased name, value, + * ...] pairs in arrival order — the interned %headers.snapshot helper + * builds the record over it, exactly the process.envPairs pattern. */ + "http.reqHeaderPairs": { argTypes: [HTTPREQ_T], result: arrayOf(STRING) }, + /** Every value of one header in arrival order (empty when absent): the + * set-cookie array of a `{ ...req.headers }` snapshot. */ + "http.reqHeaderList": { argTypes: [HTTPREQ_T, STRING], result: arrayOf(STRING) }, + "http.reqRawTrailers": { argTypes: [HTTPREQ_T], result: arrayOf(STRING) }, + "http.reqTrailerPairs": { argTypes: [HTTPREQ_T], result: arrayOf(STRING) }, + "net.sockDestroyed": { argTypes: [NETSOCKET_T], result: BOOL }, + /** socket.writable — the write half is open: no end() yet, no FIN sent, + * fd alive (connecting sockets answer true; writes queue). Node's + * stream flag. Borrows; never throws. */ + "net.sockWritable": { argTypes: [NETSOCKET_T], result: BOOL }, + // The 'upgrade' registrations: the callback shapes are program-typed + // ((req, socket, head) and shorter prefixes — the libCall case checks). + /** The 'upgrade' events, both sides (SEMANTICS.md — the WebSocket + * proxying surface): serverOnUpgrade registers (req, socket, head) + * listeners fired INSTEAD of 'request' for Connection: upgrade + * requests (the parser steps aside; the socket is raw; `head` carries + * bytes past the request head; no listener = the socket destroys, + * Node's default). clientOnUpgrade is the client twin: a 101 response + * fires (res, socket, head) INSTEAD of 'response'. */ + "http.serverOnUpgrade": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, + /** server.on("connect", ...) — HTTP CONNECT tunneling, the 'upgrade' + * machinery's twin: (req, socket, head) fired INSTEAD of 'request' for + * CONNECT-method requests (no listener = the socket destroys, Node's + * default). The h2 compat server's 'connect' (portless's RFC 8441 + * handler) only ever sees the HTTP/1.1 arm under the allowHTTP1 + * lowering, so a listener whose second parameter is a UNION with a + * netSocket arm takes the socket wrapped at that arm (an emitted + * per-shape adapter — the tags are program data). */ + "http.serverOnConnect": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, + "http.clientOnUpgrade": { argTypes: [HTTPCLIENTREQ_T, null, BOOL], result: VOID }, + "http.reqSocket": { argTypes: [HTTPREQ_T], result: NETSOCKET_T }, + // reqH2Stream's program-interned Http2Stream | undefined result is + // checked in the special libCall cases in validate.ts. + "http.reqH2Stream": { argTypes: [HTTPREQ_T], result: VOID }, + "http.reqH2StreamOrThrow": { argTypes: [HTTPREQ_T, STRING], result: HTTP2STREAM_T }, + /** req.pipe(dest) — the IncomingMessage body streaming into a + * ServerResponse (the proxy's response leg), a ClientRequest (the + * request-body forward), or a raw socket (the upgrade-rejection leg); + * chunk-for-chunk, natural end ends the destination (Node's pipe + * default; no backpressure — divergence 54's stream model). */ + "http.reqPipeRes": { argTypes: [HTTPREQ_T, HTTPRES_T], result: VOID }, + "http.reqPipeClient": { argTypes: [HTTPREQ_T, HTTPCLIENTREQ_T], result: VOID }, + "http.reqPipeSock": { argTypes: [HTTPREQ_T, NETSOCKET_T], result: VOID }, + "http.reqResume": { argTypes: [HTTPREQ_T], result: VOID }, + "http.reqPause": { argTypes: [HTTPREQ_T], result: VOID }, + "http.reqDestroy": { argTypes: [HTTPREQ_T], result: VOID }, + "http.reqOnError": { argTypes: [HTTPREQ_T, null, BOOL], result: VOID }, + "http.reqOnClose": { + argTypes: [HTTPREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + "http.reqOnAborted": { + argTypes: [HTTPREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + "http.reqHttpVersion": { argTypes: [HTTPREQ_T], result: STRING }, + "http.reqHttpVersionMajor": { argTypes: [HTTPREQ_T], result: F64 }, + "http.reqHttpVersionMinor": { argTypes: [HTTPREQ_T], result: F64 }, + "http.reqAborted": { argTypes: [HTTPREQ_T], result: BOOL }, + "http.reqComplete": { argTypes: [HTTPREQ_T], result: BOOL }, + "http.resDestroy": { argTypes: [HTTPRES_T], result: VOID }, + "http.resOnClose": { + argTypes: [HTTPRES_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + "http.resWriteHeadPairs": { argTypes: [HTTPRES_T, F64, arrayOf(STRING)], result: VOID }, + /** writeHead(status, headers) with a checked-dynamic headers value — + * the runtime OBJ walk (string/number values; other values throw + * Node's invalid-argument TypeError; may throw). */ + "http.resWriteHeadDyn": { argTypes: [HTTPRES_T, F64, DYN], result: VOID }, + "net.sockSetTimeout": { argTypes: [NETSOCKET_T, F64], result: VOID }, + /** setEncoding('utf8') — 'data' delivers strings inside the chunk-encoding window; other real encodings throw the "not supported yet" Error, unknown names throw ERR_UNKNOWN_ENCODING (may throw). */ + "net.sockSetEncoding": { argTypes: [NETSOCKET_T, STRING], result: VOID }, + "http.reqSetEncoding": { argTypes: [HTTPREQ_T, STRING], result: VOID }, + "net.sockOnTimeout": { + argTypes: [NETSOCKET_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + "net.sockRemoteAddress": { argTypes: [NETSOCKET_T], result: VOID }, + /** socket.encrypted — `boolean | undefined`: the true arm iff the + * socket carries a TLS transport (Node types `encrypted: true` on + * TLSSocket; plain sockets answer undefined — the proxy.ts isEncrypted + * idiom reads it through a cast). */ + "net.sockEncrypted": { argTypes: [NETSOCKET_T], result: VOID }, + // node:http, the client slice. The response callback shapes are + // program-dependent (checked by validate.ts); header pairs arrive flat. + /** node:http, the CLIENT slice (http.request/http.get over the net + * client machinery): request/requestCb take (host, port, path, method, + * timeoutMs, headerPairs, autoEnd[, responseCb]) — headerPairs is the + * flat [k0,v0,...] array (empty for none), autoEnd true is http.get's + * eager end(). The handle owns one dialed connection (NO pooling — the + * wire still carries Node's exact head: user headers, then Host, + * Connection: keep-alive, and the framing header; the socket closes + * when the response completes). The response delivered to responseCb / + * 'response' listeners IS an httpReq (IncomingMessage), status and + * headers parsed from the wire, body via reqOnData/reqOnEnd. Errors are + * Node-shaped ('connect ECONNREFUSED ip:port', 'socket hang up') and + * fire 'error' then 'close'; an unhandled 'error' exits 1 like every + * net handle. clientWrite before end commits to chunked framing unless + * the caller set content-length; clientEnd(data) before any write sends + * Content-Length exactly like Node. */ + "http.request": { + argTypes: [STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL], + result: HTTPCLIENTREQ_T, + }, + "http.requestCb": { + argTypes: [STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL, null], + result: HTTPCLIENTREQ_T, + }, + /** new http.Agent(opts) / new https.Agent(opts): (secure, keepAlive, + * keepAliveMsecs, maxSockets, maxFreeSockets, timeoutMs, port) — the + * numeric options arrive < 0 for "unset" (Infinity/256/none; port + * seeds the settable defaultPort, Node's option merge). Returns the + * Agent as a checked-dynamic HANDLE (getName/destroy and the + * sockets/requests/freeSockets counters dispatch through the dyn + * handle ops). keepAlive: true THROWS the named construction fence — + * socket POOLING is not modeled (one dial per request); maxSockets + * accounting is real: over-limit requests defer their dial and queue. + * MAY THROW. */ + "http.agentNew": { argTypes: [BOOL, BOOL, F64, F64, F64, F64, F64, DYN], result: DYN }, + /** http.globalAgent / https.globalAgent (true): Node's keepAlive global + * agent, the one requests without an agent option use. */ + "http.globalAgent": { argTypes: [BOOL], result: DYN }, + /** http.request's `signal` option over the fresh request: an aborted + * signal destroys it with Node's AbortError now, a later abort event + * does the same. A falsy value is ignored; a non-signal throws + * ERR_INVALID_ARG_TYPE. */ + "http.clientSignal": { argTypes: [HTTPCLIENTREQ_T, DYN], result: VOID }, + /** options.signal checked before the request is built (ERR_INVALID_ARG_TYPE). */ + "http.clientSignalCheck": { argTypes: [DYN], result: VOID }, + /** https.request's servername option, stored for the construction call + * that follows: the TLS name sent and verified, and part of the pooled + * socket key. The "https." prefix keeps the TLS unit linked. */ + "https.nextServername": { argTypes: [STRING], result: VOID }, + /** The maxHeaderSize option of createServer / http.request: Node's + * validateInteger (ERR_OUT_OF_RANGE) then the header size bound. + * MAY THROW. */ + "http.serverMaxHeaderSize": { argTypes: [NETSERVER_T, F64], result: VOID }, + "http.clientMaxHeaderSize": { argTypes: [HTTPCLIENTREQ_T, F64], result: VOID }, + /** req.destroy(err): err becomes the request's 'error'. */ + "http.clientDestroyError": { + argTypes: [HTTPCLIENTREQ_T, { kind: "object", className: "%Error" }], + result: VOID, + }, + /** The agent-threaded request rows: the http.request/https.request + * shape with a trailing `agent` dyn argument (an Agent handle, false — + * the one-shot Connection: close dial — or null/undefined for the + * default path). port < 0 means "no port option": the agent's settable + * defaultPort, then the scheme's. MAY THROW (a non-Agent value is + * Node's ERR_INVALID_ARG_TYPE). */ + "http.requestAgent": { + argTypes: [STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL, DYN], + result: HTTPCLIENTREQ_T, + }, + "http.requestAgentCb": { + argTypes: [STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL, DYN, null], + result: HTTPCLIENTREQ_T, + }, + /** request/get with a URL-STRING first argument: the runtime parses it + * (WHATWG) and dials — throws catchably on an unparsable input or a + * non-http scheme. */ + "http.requestUrl": { argTypes: [STRING, STRING, BOOL], result: HTTPCLIENTREQ_T }, + "http.requestUrlCb": { argTypes: [STRING, STRING, BOOL, null], result: HTTPCLIENTREQ_T }, + /** request/get with a runtime options record: a RequestOptions + * variable, or a literal that spreads one or sets socketPath. Args + * (options, autoEnd[, cb]). The runtime reads the record in the + * ClientRequest constructor's order (host/port or socketPath, path, + * method, headers, timeout, agent, signal, maxHeaderSize) with Node's + * errors, and documented options it does not implement throw the + * runtime fence. The "https." pair adds the TLS options. MAY THROW. */ + "http.requestDyn": { argTypes: [DYN, BOOL], result: HTTPCLIENTREQ_T }, + "http.requestDynCb": { argTypes: [DYN, BOOL, null], result: HTTPCLIENTREQ_T }, + "https.requestDyn": { argTypes: [DYN, BOOL], result: HTTPCLIENTREQ_T }, + "https.requestDynCb": { argTypes: [DYN, BOOL, null], result: HTTPCLIENTREQ_T }, + /** The paused-mode demux surface (portless's first-byte TLS peek: + * once('readable') + read(1) + unshift + emit('connection')). + * sockOnReadable registers a zero-param listener (a consumer: arrived + * bytes buffer instead of flowing, and EOF announces too); sockRead + * answers `Buffer | null` (exactly n buffered bytes, or null — Node's + * less-than-n answer; n <= 0 drains everything); sockUnshift returns + * bytes to the front of the stream; serverEmitConnection routes a + * socket into another server's protocol layer (a TLS target's + * 'connection' waits for its handshake). */ + "net.sockOnReadable": { argTypes: [NETSOCKET_T, null, BOOL], result: VOID }, + // sockRead's result is the interned `Buffer | null` union — checked + // specially in validate.ts (the reqHeader/envGet pattern; VOID here is a + // placeholder the special case overrides). + "net.sockRead": { argTypes: [NETSOCKET_T, F64], result: VOID }, + "net.sockUnshift": { argTypes: [NETSOCKET_T, BYTES_U8], result: VOID }, + /** Socket flow control and the compat surface: pause/resume (reads + * gate off/on — kernel backpressure holds paused bytes; resume flows + * and discards sans listeners) and setNoDelay answer the SOCKET (+1, + * Node's chaining); destroySoon ends now and destroys once the FIN + * flushed; bytesWritten counts accepted bytes; readable is true until + * the read half ends. */ + "net.sockPause": { argTypes: [NETSOCKET_T], result: NETSOCKET_T }, + "net.sockResume": { argTypes: [NETSOCKET_T], result: NETSOCKET_T }, + "net.sockSetNoDelay": { argTypes: [NETSOCKET_T, BOOL], result: NETSOCKET_T }, + "net.sockDestroySoon": { argTypes: [NETSOCKET_T], result: VOID }, + /** RST close, answers the socket; throws ERR_INVALID_HANDLE_TYPE on TLS. */ + "net.sockResetAndDestroy": { argTypes: [NETSOCKET_T], result: NETSOCKET_T }, + /** socket.address(): { address, family, port } or {} as a dyn. */ + "net.sockAddress": { argTypes: [NETSOCKET_T], result: DYN }, + "net.sockBytesWritten": { argTypes: [NETSOCKET_T], result: F64 }, + /** remotePort (0), remoteFamily (1), localAddress (2), localPort (3), + * localFamily (4): dyn values, undefined when unknown. */ + "net.sockAddrField": { argTypes: [NETSOCKET_T, F64], result: DYN }, + "net.sockBytesRead": { argTypes: [NETSOCKET_T], result: F64 }, + "net.sockConnecting": { argTypes: [NETSOCKET_T], result: BOOL }, + "net.sockPending": { argTypes: [NETSOCKET_T], result: BOOL }, + "net.sockReadyState": { argTypes: [NETSOCKET_T], result: STRING }, + "net.sockSetKeepAlive": { argTypes: [NETSOCKET_T, BOOL, F64], result: NETSOCKET_T }, + "net.sockOnReady": { + argTypes: [NETSOCKET_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + /** Listeners with a parameter, as dyn functions: close(hadError), + * write's cb(err) and end's cb. */ + "net.sockOnCloseDyn": { argTypes: [NETSOCKET_T, DYN, BOOL], result: VOID }, + /** socket.on/once('lookup', listener): the listener (a dyn function) + * gets (err, address, family, host) once per resolved address, or once + * with the lookup error, before the connect. */ + "net.sockOnLookup": { argTypes: [NETSOCKET_T, DYN, BOOL], result: VOID }, + "net.sockOnWriteFlush": { + argTypes: [NETSOCKET_T, { kind: "func", params: [], ret: VOID }], + result: VOID, + }, + "net.sockOnWriteFlushDyn": { argTypes: [NETSOCKET_T, DYN], result: VOID }, + "net.sockOnFinishDyn": { argTypes: [NETSOCKET_T, DYN], result: VOID }, + "net.sockSetTimeoutCb": { + argTypes: [NETSOCKET_T, F64, { kind: "func", params: [], ret: VOID }], + result: VOID, + }, + "net.isIP": { argTypes: [DYN], result: F64 }, + "net.isIPv4": { argTypes: [DYN], result: BOOL }, + "net.isIPv6": { argTypes: [DYN], result: BOOL }, + "net.serverMaxConnectionsGet": { argTypes: [NETSERVER_T], result: DYN }, + "net.serverMaxConnectionsSet": { argTypes: [NETSERVER_T, DYN], result: VOID }, + "net.serverDropMaxConnectionGet": { argTypes: [NETSERVER_T], result: DYN }, + "net.serverDropMaxConnectionSet": { argTypes: [NETSERVER_T, DYN], result: VOID }, + /** net.SocketAddress and net.BlockList (scr_net.c): the constructors + * take the argument array; the handles are dyn values. */ + "net.socketAddressNew": { argTypes: [DYN], result: DYN }, + "net.socketAddressParse": { argTypes: [DYN], result: DYN }, + "net.isSocketAddress": { argTypes: [DYN], result: BOOL }, + "net.blockListNew": { argTypes: [DYN], result: DYN }, + "net.isBlockList": { argTypes: [DYN], result: BOOL }, + "net.blockListPrivateRanges": { argTypes: [], result: DYN }, + "net.serverOnDrop": { argTypes: [NETSERVER_T, DYN, BOOL], result: VOID }, + "net.serverGetConnections": { argTypes: [NETSERVER_T, DYN], result: VOID }, + "net.sockReadable": { argTypes: [NETSOCKET_T], result: BOOL }, + /** socket.on('finish', cb) / end(cb): fires once when the FIN goes out + * (sweep-deferred, never the registering stack). */ + "net.sockOnFinish": { + argTypes: [NETSOCKET_T, { kind: "func", params: [], ret: VOID }], + result: VOID, + }, + "net.serverEmitConnection": { argTypes: [NETSERVER_T, NETSOCKET_T], result: VOID }, + // tls/https: cert/key/ca PEM arguments are strings OR Buffers (null = + // both accepted; the emitter passes data+len either way). + /** node:tls + node:https (scr_tls.c over scr_net.c/scr_http.c, with + * the vendored mbedTLS archive — linked only when one of these appears + * on the IR; moduleUsesTls is the switch, and every tls/https libCall + * also counts as net AND http use so both units link and install). + * tls.createServer takes (cert, key[, handler]) — cert/key are PEM + * strings or Buffers (the emitter passes data+len for either); the + * handler is Node's 'secureConnection' (fires post-handshake with a + * socket that behaves exactly like a net socket, the same adapters as + * net.createServer). https.createServer is (cert, key, handler) with + * the http request-handler adapters. https.request/requestCb extend + * the http client row with (…, rejectUnauthorized: bool, ca: PEM + * string/Buffer — "" for none) and default port 443; everything else + * (write/end/destroy/events, the response surface) IS the http client + * surface — the handles are the same kinds. */ + "tls.createServer": { argTypes: [null, null], result: NETSERVER_T }, + "tls.createServerCb": { argTypes: [null, null, null], result: NETSERVER_T }, + /** The SNICallback forms: (cert, key, SNICallback[, handler]). The + * callback is http2.createSecureServerSni's shape, a function or a + * function | undefined union. */ + "tls.createServerSni": { argTypes: [null, null, null], result: NETSERVER_T }, + "tls.createServerSniCb": { argTypes: [null, null, null, null], result: NETSERVER_T }, + // The runtime options records (divergence 66's stance): a dyn options + // value whose members read at runtime; pemDyn extracts a runtime-valued + // cert/key member (arg 1 is the precomposed fence label). + /** RUNTIME options records (the divergence-66 stance): the *Dyn + * creators take a checked-dynamic (dyn) options value whose members + * read at runtime — cert/key extract like the literal path, members + * whose literal forms fence THROW the catchable fence at runtime, and + * undocumented keys drop like Node drops them. tls.pemDyn is the + * literal walk's runtime-valued cert/key extraction: (value, whatLit) + * → PEM bytes (strings/Buffers/one-element arrays of those) or the + * thrown fence. All of them may throw. */ + "tls.pemDyn": { argTypes: [DYN, STRING], result: BYTES_U8 }, + "tls.createServerDyn": { argTypes: [DYN], result: NETSERVER_T }, + "tls.createServerDynCb": { argTypes: [DYN, null], result: NETSERVER_T }, + "https.createServerDyn": { argTypes: [DYN], result: NETSERVER_T }, + "https.createServerDynCb": { argTypes: [DYN, null], result: NETSERVER_T }, + /** createSecureServer(options, handler) — the eager COMPAT handler as + * the first 'request' listener (Node's exact route), on both literal + * flavors: Req is the dual ALPN allowHTTP1 server, H2Req the ALPN=h2-only + * server (both use compat handles over h2 streams). Args are + * (cert, key, cb, enableConnectProtocol). */ + "http2.createSecureServerReq": { argTypes: [null, null, null, BOOL], result: NETSERVER_T }, + "http2.createSecureServerH2Req": { argTypes: [null, null, null, BOOL], result: NETSERVER_T }, + /** createSecureServer with a RUNTIME options record (the divergence-66 + * stance): allowHTTP1/cert/key read at runtime — allowHTTP1 picks the + * flavor, the TLS server walk fences its out-of-bounds members with + * the catchable runtime fence, and h2 session-tuning keys drop exactly + * like the literal walk ignores them. May throw. The Cb form carries + * the eager compat handler. */ + "http2.createSecureServerDyn": { argTypes: [DYN], result: NETSERVER_T }, + "http2.createSecureServerDynCb": { argTypes: [DYN, null], result: NETSERVER_T }, + // tls.connect(port, host, opts[, cb]) — port -1 / host "" read the + // options record; the callback fires post-handshake (secureConnect). + /** tls.connect — the TLS client socket: (port, host, opts[, cb]) where + * port -1 reads options.port, host "" reads options.host, and opts is + * the runtime (dyn) options record (rejectUnauthorized/ca/servername + * implemented; other documented members throw the runtime fence). The + * callback fires post-handshake — Node's secureConnect timing. */ + "tls.connect": { argTypes: [F64, STRING, DYN], result: NETSOCKET_T }, + "tls.connectCb": { argTypes: [F64, STRING, DYN, null], result: NETSOCKET_T }, + // The TLSSocket member surface (authError's `string | null` union is + // shape-checked in the special cases in validate.ts — the reqHeader pattern). + /** The TLSSocket member surface on the socket kind: authorized (bool — + * Node's verify verdict), authorizationError (the verify-failure CODE + * STRING or null), the 'secureConnect' registration (a TLS socket's + * conn list fires at establishment; plain sockets never fire it), and + * the 'session' registration (fires once with the serialized session — + * a Buffer; the received-ticket event). */ + "tls.sockAuthorized": { argTypes: [NETSOCKET_T], result: BOOL }, + /** getProtocol() (string | null), getCipher() (CipherNameAndProtocol, + * undefined before the handshake, null after close) and alpnProtocol + * (string | false | null), as dyn values. */ + "tls.sockGetProtocol": { argTypes: [NETSOCKET_T], result: DYN }, + "tls.sockGetCipher": { argTypes: [NETSOCKET_T], result: DYN }, + "tls.sockAlpnProtocol": { argTypes: [NETSOCKET_T], result: DYN }, + /** getPeerCertificate(detailed) and getCertificate() (the legacy object, + * {} or null; scr_tls_x509.c), and the DER behind getPeerX509Certificate() + * and getX509Certificate() (a Buffer, empty without a certificate). */ + "tls.sockGetPeerCertificate": { argTypes: [NETSOCKET_T, DYN], result: DYN }, + "tls.sockGetCertificate": { argTypes: [NETSOCKET_T], result: DYN }, + "tls.sockPeerCertDer": { argTypes: [NETSOCKET_T], result: BYTES_U8 }, + "tls.sockOwnCertDer": { argTypes: [NETSOCKET_T], result: BYTES_U8 }, + "tls.sockAuthError": { argTypes: [NETSOCKET_T], result: VOID }, + "tls.sockOnSecureConnect": { + argTypes: [NETSOCKET_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + "tls.sockOnSession": { argTypes: [NETSOCKET_T, null, BOOL], result: VOID }, + /** The 'secure' event: the handshake completed (after secureConnect on + * a client). Plain sockets never fire it. */ + "tls.sockOnSecure": { + argTypes: [NETSOCKET_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + /** new tls.TLSSocket(socket, options) in server mode: a new TLS socket + * takes over the socket's connection (wrapSocketCtx passes a literal's + * secureContext member apart from the runtime options record). The + * record reads at runtime: isServer, cert, key, ALPNProtocols, + * minVersion and maxVersion are implemented, the client mode and other + * documented members throw the runtime fence. MAY THROW. */ + "tls.wrapSocket": { argTypes: [NETSOCKET_T, DYN], result: NETSOCKET_T }, + "tls.wrapSocketCtx": { argTypes: [NETSOCKET_T, DYN, SECURECTX_T], result: NETSOCKET_T }, + // createSecureContext({ cert, key }) mints the opaque SNI-answer handle. + /** tls.createSecureContext({ cert, key }) — parses the PEM pair into an + * opaque SecureContext handle (secureCtx kind) for SNI callbacks to + * answer with; cert/key are PEM strings or Buffers like createServer's. */ + "tls.createSecureContext": { argTypes: [null, null], result: SECURECTX_T }, + /** createSecureContext over a RUNTIME options record (the checked- + * dynamic lane): Node's typed option validations first (the ciphers/ + * passphrase/engine/version/timeout/ticketKeys ladders), then the pem + * walk — a validated { cert, key } bag builds the real context. + * May-throw. */ + "tls.createSecureContextDyn": { argTypes: [DYN], result: SECURECTX_T }, + /** server.addContext(servername, options | SecureContext), + * server.setSecureContext(options) and the 'tlsClientError' listener of + * a tls or https server (scr_tls.c). */ + "tls.serverAddContext": { argTypes: [NETSERVER_T, DYN, DYN], result: VOID }, + "tls.serverAddContextCtx": { argTypes: [NETSERVER_T, DYN, SECURECTX_T], result: VOID }, + "tls.serverSetSecureContext": { argTypes: [NETSERVER_T, DYN], result: VOID }, + "tls.serverOnClientError": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, + /** tls.getCACertificates(type): validateString + the documented name + * set, then the trailing compiler-rendered fence — ALWAYS THROWS (the + * error.nodeThrow polymorphic-result carve-out). May-throw seed. */ + "tls.caCertsChk": { argTypes: [DYN, STRING], result: VOID }, + // The CA-store introspection unit (scr_tls_ca.c): per-type cached PEM + // string arrays and the default-set replacement. + /** The CA-store introspection surface (scr_tls_ca.c — its own unit and + * link gate, "tlsca." NOT "tls.", so a getCACertificates-only binary + * never pulls mbedTLS): tlsca.get is tls.getCACertificates(type) — the + * cached per-type string[] of PEM blocks (identity-stable across calls, + * Node's caching; an unknown type throws Node's ERR_INVALID_ARG_VALUE + * TypeError); tlsca.root is the tls.rootCertificates value read; + * tlsca.set is tls.setDefaultCACertificates(certs) — replaces the + * default set (deduped) and the anchors the TLS client verifies + * against, throwing Node's ERR_CRYPTO_OPERATION_FAILED when no entry + * carries a certificate block. */ + "tlsca.get": { argTypes: [STRING], result: arrayOf(STRING) }, + "tlsca.root": { argTypes: [], result: arrayOf(STRING) }, + "tlsca.set": { argTypes: [arrayOf(STRING)], result: VOID }, + "https.createServer": { argTypes: [null, null, null], result: NETSERVER_T }, + // http2's allowHTTP1 compatibility server (divergence 57): cert/key + // like tls.createServer; the 'request' handler arrives separately via + // http.serverOnRequest (shape checked in the libCall case, like + // http.createServer's). sessionError callback shape is checked by validate.ts. + /** node:http2 allowHTTP1: one TLS server advertises h2 + http/1.1 and + * dispatches to the matching parser after ALPN. Request listeners mirror + * into both compatibility lists; the remaining session/req.stream rows + * below retain their explicitly limited behavior. */ + "http2.createSecureServer": { argTypes: [null, null, BOOL], result: NETSERVER_T }, + // The SNI-callback form: arg 2 is the JS SNICallback closure — a + // `(servername, cb) => void` func, or its `| undefined` union from the + // conditional-spread spelling (the libCall case checks the shape). + /** createSecureServer with an SNI callback: args are (cert, key, sniCb) + * where sniCb is the JS SNICallback — a `(servername, cb) => void` + * closure, or the `SNICallback | undefined` union from the conditional- + * spread spelling (`...(x ? { SNICallback: x } : {})`; the emitter + * unwraps the union — the undefined arm means "no callback", exactly + * the no-SNI server). The runtime parses each connection's ClientHello + * for the server_name extension BEFORE the TLS handshake begins, calls + * the callback with (servername, answer-closure), and resumes the + * handshake when the answer arrives — cb(err) tears the socket down + * without an error event (Node's 'tlsClientError' default), cb(null, ctx) serves + * ctx's cert/key, cb(null, undefined) serves the default pair. */ + "http2.createSecureServerSni": { argTypes: [null, null, null, BOOL], result: NETSERVER_T }, + // The ALPN=h2 server (createSecureServer without allowHTTP1): the real + // h2 session machinery behind the TLS handshake. + /** The REAL h2-over-TLS server (createSecureServer WITHOUT allowHTTP1): + * scr_http2_create_secure_server — the h2c session machinery behind an + * mbedTLS handshake whose ALPN advertises h2 alone (an http/1.1-only + * client fails the handshake with no_application_protocol, Node's + * h2-only split). args are (cert, key) — PEM strings or Buffers. */ + "http2.createSecureServerH2": { argTypes: [null, null, BOOL], result: NETSERVER_T }, + "http.serverOnRequest": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, + /** server.on('checkContinue' | 'checkExpectation', (req, res)): the + * 'request' listener shape; the last argument picks checkExpectation. */ + "http.serverOnCheck": { argTypes: [NETSERVER_T, null, BOOL, BOOL], result: VOID }, + "http2.serverOnSessionError": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, + /** The guarded absent-session compatibility call remains a no-op. */ + "http2.streamNoop": { argTypes: [], result: VOID }, + /** The UNGUARDED h2-only stream call (`req.stream.on(...)`): stream is + * undefined on every connection the allowHTTP1 lowering accepts — and + * on every HTTP/1.1 connection of Node's own allowHTTP1 server — so the + * call IS Node's member read on undefined: throws the exact catchable + * TypeError ("Cannot read properties of undefined (reading 'on')"). + * One arg: the read member's name (a string literal). Never returns. */ + "http2.streamUndefCall": { argTypes: [STRING], result: VOID }, + // The REAL h2c surface (scr_http2.c). Callback slots are null (the + // emitter picks the thunk); pairs slots are string arrays; the + // endStream tri-state and event flags ride as f64. + /** node:http2, the REAL h2c surface (scr_http2.c — frame codec + HPACK + * over the net loop; the design note atop that file has the story). + * Sessions and streams are first-class handle kinds; 'stream'/'response' + * payloads cross as flat [name, value, ...] pairs arrays and an EMITTED + * adapter closure builds the program-side headers record (the response + * :status rides separately as a number). */ + "http2.createServer": { argTypes: [], result: NETSERVER_T }, + "http2.createServerReq": { argTypes: [null], result: NETSERVER_T }, + "http2.serverOnStream": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, + "http2.serverOnSession": { argTypes: [NETSERVER_T, null, BOOL], result: VOID }, + // connect(authority, reject, ca[, cb]): the TLS client knobs an https + // authority reads (inert on http ones, exactly Node); ca is a PEM + // string/Buffer ("" = the system anchors). + /** connect(authority[, listener]) — h2c prior knowledge; the listener + * closure (if any) is the 'connect' once-listener. */ + "http2.connect": { argTypes: [STRING, BOOL, null], result: HTTP2SESSION_T }, + "http2.connectCb": { argTypes: [STRING, BOOL, null, null], result: HTTP2SESSION_T }, + /** session.request(pairs?, endStream) — endStream is a tri-state f64: + * -1 the method's payload-meaningless default, 0/1 explicit. */ + "http2.sessionRequest": { + argTypes: [HTTP2SESSION_T, arrayOf(STRING), F64], + result: HTTP2STREAM_T, + }, + "http2.sessionClose": { argTypes: [HTTP2SESSION_T], result: VOID }, + "http2.sessionCloseCb": { argTypes: [HTTP2SESSION_T, null], result: VOID }, + "http2.sessionDestroy": { argTypes: [HTTP2SESSION_T], result: VOID }, + "http2.sessionOnClose": { argTypes: [HTTP2SESSION_T, null, BOOL], result: VOID }, + "http2.sessionOnError": { argTypes: [HTTP2SESSION_T, null, BOOL], result: VOID }, + "http2.sessionOnConnect": { argTypes: [HTTP2SESSION_T, null, BOOL], result: VOID }, + "http2.sessionOnStream": { argTypes: [HTTP2SESSION_T, null, BOOL], result: VOID }, + "http2.sessionOnGoaway": { argTypes: [HTTP2SESSION_T, null, BOOL], result: VOID }, + "http2.sessionClosed": { argTypes: [HTTP2SESSION_T], result: BOOL }, + "http2.sessionDestroyed": { argTypes: [HTTP2SESSION_T], result: BOOL }, + "http2.sessionEncrypted": { argTypes: [HTTP2SESSION_T], result: BOOL }, + "http2.sessionType": { argTypes: [HTTP2SESSION_T], result: F64 }, + "http2.sessionAlpn": { argTypes: [HTTP2SESSION_T], result: STRING }, + "http2.sessionSocket": { argTypes: [HTTP2SESSION_T], result: NETSOCKET_T }, + /** stream.respond(pairs?, endStream) — the server answer. */ + "http2.streamRespond": { argTypes: [HTTP2STREAM_T, arrayOf(STRING), BOOL], result: VOID }, + "http2.streamWrite": { argTypes: [HTTP2STREAM_T, STRING], result: VOID }, + "http2.streamWriteBytes": { argTypes: [HTTP2STREAM_T, BYTES_U8], result: VOID }, + "http2.streamEnd": { argTypes: [HTTP2STREAM_T], result: VOID }, + "http2.streamEndStr": { argTypes: [HTTP2STREAM_T, STRING], result: VOID }, + "http2.streamEndBytes": { argTypes: [HTTP2STREAM_T, BYTES_U8], result: VOID }, + "http2.streamClose": { argTypes: [HTTP2STREAM_T, F64], result: VOID }, + "http2.streamCloseCb": { argTypes: [HTTP2STREAM_T, F64, null], result: VOID }, + "http2.streamDestroy": { argTypes: [HTTP2STREAM_T], result: VOID }, + "http2.sessionSettings0": { argTypes: [HTTP2SESSION_T], result: VOID }, + "http2.sessionSettings": { argTypes: [HTTP2SESSION_T, DYN], result: VOID }, + "http2.sessionSettingsDynCb": { argTypes: [HTTP2SESSION_T, DYN, DYN], result: VOID }, + "http2.sessionSettingsCb0": { + argTypes: [HTTP2SESSION_T, DYN, { kind: "func", params: [], ret: VOID }], + result: VOID, + }, + "http2.sessionOnSettingsDyn": { argTypes: [HTTP2SESSION_T, DYN, BOOL, BOOL], result: VOID }, + "http2.sessionOnSettings0": { + argTypes: [HTTP2SESSION_T, { kind: "func", params: [], ret: VOID }, BOOL, BOOL], + result: VOID, + }, + "http2.sessionSettingsGet": { argTypes: [HTTP2SESSION_T, BOOL], result: DYN }, + "http2.sessionPendingSettingsAck": { argTypes: [HTTP2SESSION_T], result: BOOL }, + "http2.getDefaultSettings": { argTypes: [], result: DYN }, + "http2.streamSetEncoding": { argTypes: [HTTP2STREAM_T, STRING], result: VOID }, + "http2.streamSetEncodingRet": { argTypes: [HTTP2STREAM_T, STRING], result: HTTP2STREAM_T }, + "http2.streamResume": { argTypes: [HTTP2STREAM_T], result: VOID }, + "http2.streamPause": { argTypes: [HTTP2STREAM_T], result: VOID }, + "http2.streamOnData": { argTypes: [HTTP2STREAM_T, null, BOOL], result: VOID }, + "http2.streamOnEnd": { argTypes: [HTTP2STREAM_T, null, BOOL], result: VOID }, + "http2.streamOnClose": { argTypes: [HTTP2STREAM_T, null, BOOL], result: VOID }, + "http2.streamOnAborted": { argTypes: [HTTP2STREAM_T, null, BOOL], result: VOID }, + "http2.streamOnError": { argTypes: [HTTP2STREAM_T, null, BOOL], result: VOID }, + "http2.streamOnResponse": { argTypes: [HTTP2STREAM_T, null, BOOL], result: VOID }, + "http2.streamId": { argTypes: [HTTP2STREAM_T], result: F64 }, + "http2.streamRstCode": { argTypes: [HTTP2STREAM_T], result: F64 }, + "http2.streamDestroyed": { argTypes: [HTTP2STREAM_T], result: BOOL }, + "http2.streamClosed": { argTypes: [HTTP2STREAM_T], result: BOOL }, + "http2.streamAborted": { argTypes: [HTTP2STREAM_T], result: BOOL }, + "http2.streamPending": { argTypes: [HTTP2STREAM_T], result: BOOL }, + "http2.streamSession": { argTypes: [HTTP2STREAM_T], result: HTTP2SESSION_T }, + // The createConnection forms: arg 0 is the dialer closure (() => + // Socket — the libCall case checks), then path/method/timeout/headers/ + // autoEnd like http.request. + /** The createConnection form (the proxy's own dialer): args are + * (connCb, path, method, timeout, headers, autoEnd[, cb]) — connCb is + * a `() => net.Socket` closure the runtime invokes ONCE, synchronously + * (Node's onSocket timing); everything else matches http.request. The + * Host header defaults to "localhost" — a headers.host entry wins + * verbatim, the proxy shape. */ + "http.requestConn": { + argTypes: [null, STRING, STRING, F64, arrayOf(STRING), BOOL], + result: HTTPCLIENTREQ_T, + }, + "http.requestConnCb": { + argTypes: [null, STRING, STRING, F64, arrayOf(STRING), BOOL, null], + result: HTTPCLIENTREQ_T, + }, + "https.request": { + argTypes: [STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL, BOOL, null], + result: HTTPCLIENTREQ_T, + }, + "https.requestCb": { + argTypes: [STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL, BOOL, null, null], + result: HTTPCLIENTREQ_T, + }, + /** The URL-string first argument, the http.requestUrl row over TLS: + * no options means Node's defaults (verification on, default trust + * anchors), and a non-https scheme is ERR_INVALID_PROTOCOL. */ + "https.requestUrl": { argTypes: [STRING, STRING, BOOL], result: HTTPCLIENTREQ_T }, + "https.requestUrlCb": { argTypes: [STRING, STRING, BOOL, null], result: HTTPCLIENTREQ_T }, + "https.requestAgent": { + argTypes: [STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL, BOOL, null, DYN], + result: HTTPCLIENTREQ_T, + }, + "https.requestAgentCb": { + argTypes: [STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL, BOOL, null, DYN, null], + result: HTTPCLIENTREQ_T, + }, + // The requestFn binding's runtime-secure rows: https.request's shape + // with the leading `secure` bool. + /** A call through a `const requestFn = tls ? https.request : + * http.request` binding — the module-function-as-value ternary between + * the two known clients: the https.request row with a leading `secure` + * bool that picks the dial at RUNTIME (true = the TLS client, exactly + * https.request; false = the plain client, exactly http.request — + * rejectUnauthorized/ca ignored there like Node ignores TLS options on + * http.request). The "https." prefix keeps the TLS unit linked. */ + "https.requestFn": { + argTypes: [BOOL, STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL, BOOL, null], + result: HTTPCLIENTREQ_T, + }, + "https.requestFnCb": { + argTypes: [BOOL, STRING, F64, STRING, STRING, F64, arrayOf(STRING), BOOL, BOOL, null, null], + result: HTTPCLIENTREQ_T, + }, + "http.clientWrite": { argTypes: [HTTPCLIENTREQ_T, STRING], result: VOID }, + "http.clientSetHeader": { argTypes: [HTTPCLIENTREQ_T, STRING, STRING], result: VOID }, + "http.clientGetHeader": { argTypes: [HTTPCLIENTREQ_T, STRING], result: VOID }, + "http.clientHasHeader": { argTypes: [HTTPCLIENTREQ_T, STRING], result: BOOL }, + "http.clientRemoveHeader": { argTypes: [HTTPCLIENTREQ_T, STRING], result: VOID }, + "http.clientGetHeaderNames": { argTypes: [HTTPCLIENTREQ_T], result: arrayOf(STRING) }, + "http.clientGetRawHeaderNames": { argTypes: [HTTPCLIENTREQ_T], result: arrayOf(STRING) }, + "http.clientGetHeaders": { argTypes: [HTTPCLIENTREQ_T], result: DYN }, + "http.clientWriteBytes": { argTypes: [HTTPCLIENTREQ_T, BYTES_U8], result: VOID }, + "http.clientEnd": { argTypes: [HTTPCLIENTREQ_T], result: VOID }, + "http.clientEndStr": { argTypes: [HTTPCLIENTREQ_T, STRING], result: VOID }, + "http.clientEndBytes": { argTypes: [HTTPCLIENTREQ_T, BYTES_U8], result: VOID }, + /** The checked-dynamic chunk twins (the net.sockWriteDyn story). */ + "http.clientWriteDyn": { argTypes: [HTTPCLIENTREQ_T, DYN], result: VOID }, + "http.clientEndDyn": { argTypes: [HTTPCLIENTREQ_T, DYN], result: VOID }, + "http.clientFlushHeaders": { argTypes: [HTTPCLIENTREQ_T], result: VOID }, + "http.clientAddTrailers": { argTypes: [HTTPCLIENTREQ_T, arrayOf(STRING)], result: VOID }, + "http.clientCork": { argTypes: [HTTPCLIENTREQ_T], result: VOID }, + "http.clientUncork": { argTypes: [HTTPCLIENTREQ_T], result: VOID }, + "http.clientWritableCorked": { argTypes: [HTTPCLIENTREQ_T], result: F64 }, + "http.clientMethod": { argTypes: [HTTPCLIENTREQ_T], result: STRING }, + "http.clientPath": { argTypes: [HTTPCLIENTREQ_T], result: STRING }, + "http.clientHost": { argTypes: [HTTPCLIENTREQ_T], result: STRING }, + "http.clientProtocol": { argTypes: [HTTPCLIENTREQ_T], result: STRING }, + "http.clientHeadersSent": { argTypes: [HTTPCLIENTREQ_T], result: BOOL }, + "http.clientWritableEnded": { argTypes: [HTTPCLIENTREQ_T], result: BOOL }, + "http.clientWritableFinished": { argTypes: [HTTPCLIENTREQ_T], result: BOOL }, + "http.clientSocket": { argTypes: [HTTPCLIENTREQ_T], result: NETSOCKET_T }, + "http.clientReusedSocket": { argTypes: [HTTPCLIENTREQ_T], result: BOOL }, + "http.clientSetNoDelay": { argTypes: [HTTPCLIENTREQ_T, BOOL], result: VOID }, + "http.clientSetSocketKeepAlive": { argTypes: [HTTPCLIENTREQ_T, BOOL, F64], result: VOID }, + "http.clientSetTimeout": { argTypes: [HTTPCLIENTREQ_T, F64], result: VOID }, + "http.clientSetTimeoutCb": { + argTypes: [HTTPCLIENTREQ_T, F64, { kind: "func", params: [], ret: VOID }], + result: VOID, + }, + "http.statusCodes": { argTypes: [], result: DYN }, + "http.methods": { argTypes: [], result: arrayOf(STRING) }, + "http.reqSetTimeout": { argTypes: [HTTPREQ_T, F64], result: VOID }, + "http.reqSetTimeoutCb": { + argTypes: [HTTPREQ_T, F64, { kind: "func", params: [], ret: VOID }], + result: VOID, + }, + "http.clientDestroy": { argTypes: [HTTPCLIENTREQ_T], result: VOID }, + "http.clientAbort": { argTypes: [HTTPCLIENTREQ_T], result: VOID }, + "http.clientAborted": { argTypes: [HTTPCLIENTREQ_T], result: BOOL }, + "http.clientDestroyed": { argTypes: [HTTPCLIENTREQ_T], result: BOOL }, + "http.clientOnResponse": { argTypes: [HTTPCLIENTREQ_T, null, BOOL], result: VOID }, + "http.clientOnSocket": { argTypes: [HTTPCLIENTREQ_T, null, BOOL], result: VOID }, + "http.clientOnFinish": { + argTypes: [HTTPCLIENTREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + "http.clientOnError": { argTypes: [HTTPCLIENTREQ_T, null, BOOL], result: VOID }, + "http.clientOnTimeout": { + argTypes: [HTTPCLIENTREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + "http.clientOnClose": { + argTypes: [HTTPCLIENTREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + "http.clientOnAbort": { + argTypes: [HTTPCLIENTREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + "http.clientOnContinue": { + argTypes: [HTTPCLIENTREQ_T, { kind: "func", params: [], ret: VOID }, BOOL], + result: VOID, + }, + /** execFileSync/execSync as ONE entry (args: cmd, argv, shell, input, + * cwd, hasEnv, envPairs, timeoutMs, stdoutMode, stderrMode, buffers — + * see scr_child.h). Throws Node's exact errors: "Command failed: " + * (+ captured stderr) on non-zero exit or signal death, "spawnSync + * ENOENT" on spawn failure, "spawnSync ETIMEDOUT" after + * the SIGTERM timeout, with Node's status, signal, output, pid, stdout + * and stderr properties (Buffer outputs when buffers is set: no + * encoding option). Result is the captured utf8 stdout (+1). */ + "cp.execSync": { + argTypes: [ + STRING, + arrayOf(STRING), + BOOL, + STRING, + BOOL, + STRING, + BOOL, + arrayOf(STRING), + F64, + F64, + F64, + BOOL, + ], + result: STRING, + }, + /** The promisified-execFile/exec capture (args: cmd, argv, shell, cwd, + * hasEnv, envPairs, timeoutMs; shell marks exec's /bin/sh -c argv, as + * for execSync, so failures display the command string): the same exec + * core in the async shape — both streams captured, no echo, Node's ASYNC messages on the throw paths + * ("Command failed: \n" with the unconditional newline, + * "spawn ENOENT" with .code, timeouts reporting as ordinary + * SIGTERM command failures — never ETIMEDOUT). Result reuses the + * ScrSpawnRes container (+1; stdout/stderr strings, status unused). + * Called only from the frontend's interned %execFileAsync and + * %execAsync ASYNC helpers, whose fiber turns the throw into the + * rejection. */ + "cp.execCapture": { + argTypes: [STRING, arrayOf(STRING), BOOL, STRING, BOOL, arrayOf(STRING), F64], + result: SPAWNRES_T, + }, + /** child_process.spawn (scr_child.c + the scr_async.c loop): posix_spawnp + * with per-slot ignore/inherit/pipe modes (and number output fds), the + * all-piped Node default, and the child registered with the event loop, + * which polls waitpid(WNOHANG) at quiescence like timers. + * NEVER throws: spawn failure defers to the "error" event, Node-exact + * (the error message is Node's "spawn "; an "error" + * event with no listener prints it and exits 1 like an EventEmitter). + * cmd/args borrowed; result an owned (+1) child handle. The loop will + * not exhaust while any spawned child is unreaped — Node's keep-alive. + * + * child.onExit / child.onClose / child.onError — terminal listener + * registration through child.on/once. Close uses the exit adapter shape + * but fires only after every piped stdio handle reaches EOF. The + * receiver is borrowed, the CALLBACK MOVES into the child's listener + * registry (released after the terminal event fires, or at reap for + * the event that never fires). Both are void (chaining is fenced). + * onExit's third emitted ingredient is an ADAPTER the backend interns + * per callback shape: the runtime invokes adapter(cb, has_code, code) + * and the adapter builds the `number | null` union (tags are program- + * dependent) or ignores the code for a zero-param callback. onError's + * adapters are runtime-provided (zero-param, or the %Error one-param + * shape — scr_error_new needs no program types). "exit" fires once + * with the code (f64 arm) or null (signal death); "error" fires only + * for spawn failure, exactly Node's split. */ + "cp.spawn": { argTypes: [STRING, arrayOf(STRING)], result: CHILD_T }, + /** Static-native fork startup and IPC. process.forkTarget initializes a + * re-executed child's inherited channel and returns its embedded target id + * (-1 in the parent). The remaining entries mirror Node's JSON channel. */ + "process.forkTarget": { argTypes: [F64], result: F64 }, + "cp.fork": { + argTypes: [F64, arrayOf(STRING), F64, F64, F64, BOOL, arrayOf(STRING), STRING], + result: CHILD_T, + }, + "child.connected": { argTypes: [CHILD_T], result: BOOL }, + "child.hasChannel": { argTypes: [CHILD_T], result: BOOL }, + "child.send": { argTypes: [CHILD_T, STRING], result: BOOL }, + "child.sendCb": { argTypes: [CHILD_T, STRING, null], result: BOOL }, + "child.disconnect": { argTypes: [CHILD_T], result: VOID }, + "child.onMessage": { argTypes: [CHILD_T, null, BOOL], result: VOID }, + "child.onDisconnect": { argTypes: [CHILD_T, null, BOOL], result: VOID }, + "child.onSpawn": { argTypes: [CHILD_T, null], result: VOID }, + /** Rest listeners use the checked function bridge to pack event arguments. */ + "child.onDyn": { argTypes: [CHILD_T, STRING, DYN], result: VOID }, + // Own properties JavaScript adds to children (handle-properties.ts). + "child.propsInstall": { argTypes: [], result: VOID }, + "child.propsDefine": { argTypes: [DYN, DYN, DYN], result: DYN }, + "child.propsDescriptor": { argTypes: [DYN, DYN], result: DYN }, + "child.propsResolve": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, + "child.propsOnDyn": { argTypes: [CHILD_T, STRING, DYN], result: VOID }, + "process.connected": { argTypes: [], result: BOOL }, + /** Whether this fork child opened its channel; part of process.send's + * presence in programs with fork targets. Never throws. */ + "process.ipcOpen": { argTypes: [], result: BOOL }, + "process.send": { argTypes: [STRING], result: BOOL }, + "process.sendCb": { argTypes: [STRING, null], result: BOOL }, + "process.disconnect": { argTypes: [], result: VOID }, + "process.onMessage": { argTypes: [null, BOOL], result: VOID }, + "process.onDisconnect": { argTypes: [null, BOOL], result: VOID }, + /** child_process.execFile's callback slice: starts an all-piped child, + * captures stdout/stderr, and moves the error-first callback into the + * child registry. The callback shape is program-dependent and checked + * by the validator/backends. The last argument is exec's shell flag: + * the argv is ["-c", command] and failure messages show the command. */ + "cp.execFile": { argTypes: [STRING, arrayOf(STRING), null, BOOL], result: CHILD_T }, + // spawn's options form: per-slot stdio modes (0 ignore / 1 inherit / + // 2 fd) with the out/err fds for mode 2, detached, env replacement + // pairs, cwd ("" = inherit). + /** spawn with options (scr_child.c): the cp.spawn core plus PER-SLOT + * stdio — args are (cmd, argv, inMode, outMode, errMode, outFd, errFd, + * detached, hasEnv, envPairs, cwd); modes 0 ignore (/dev/null), 1 + * inherit, 2 fd (out/err only — the fd dup2s into the child's slot, + * Node's stdio fd form; the daemon-log idiom ["ignore", logFd, logFd]). + * detached is POSIX_SPAWN_SETSID (the child gets its own session and + * process group, Node's semantics), env is a REPLACEMENT ([k,v,...] + * pairs like cp.execSync's), cwd ""=inherit. Same event/loop story as + * cp.spawn. */ + "cp.spawnOpts": { + argTypes: [ + STRING, + arrayOf(STRING), + F64, + F64, + F64, + F64, + F64, + BOOL, + BOOL, + BOOL, + arrayOf(STRING), + STRING, + ], + result: CHILD_T, + }, + /** Runtime options normalized into the native spawn core; unsupported + * process features retain explicit refusals. (command, args, options). */ + "cp.spawnDynamic": { argTypes: [STRING, arrayOf(STRING), DYN], result: CHILD_T }, + // The callback's func type is program-dependent (zero params, or the + // `number | null` union / the %Error class) — the libCall case checks + // the shape; the slot here only pins arity and the child receiver. + "child.onExit": { argTypes: [CHILD_T, null], result: VOID }, + "child.onClose": { argTypes: [CHILD_T, null], result: VOID }, + "child.onError": { argTypes: [CHILD_T, null], result: VOID }, + // Like process.envGet, spawnRes.status's result type is program-dependent + // (the interned `number | null` union) — the libCall case checks the arms. + "spawnRes.status": { argTypes: [SPAWNRES_T], result: VOID }, + // spawnRes.error's result is the interned `Error | undefined` union — + // the libCall case checks the arms, the spawnRes.status pattern. + /** Node's spawn-failure carrier `error?: Error`: a fresh +1 %Error + * ("spawnSync ENOENT", `code` stamped) when the spawn itself + * failed, the interned undefined arm otherwise — the result type is the + * call site's `Error | undefined` union, constructed type-directedly in + * the backend (the envGet convention). Never throws. */ + "spawnRes.error": { argTypes: [SPAWNRES_T], result: VOID }, + // spawnRes.signal's result is the interned `string | null` union — + // same pattern. + "spawnRes.signal": { argTypes: [SPAWNRES_T], result: VOID }, + // The ChildProcess lifecycle members: pid/exitCode are program-dependent + // unions (`number | undefined` / `number | null` — the libCall case + // checks the arms, the spawnRes.status pattern). + /** The ChildProcess lifecycle members (scr_child.c), Node's shapes + * exactly (SEMANTICS.md has the pinned matrix). child.pid is the + * checker's `number | undefined` (undefined = spawn failure) and + * child.exitCode its `number | null` (null while running and after a + * signal death; -errno once a spawn failure settled) — both unions are + * type-directed constructions in the backend over a has/get runtime + * pair, the spawnRes.status pattern. child.killed is Node's + * sent-a-signal flag. child.kill sends while the child is un-reaped + * (false after — Node's null-handle answer) and THROWS the + * Unknown-signal TypeError on bad names (may-throw); killNum passes + * numbers through (0 probes; never throws). child.unref drops the + * child from the loop's keep-alive set — it is still reaped while the + * loop runs for other reasons, and one the loop never reaps is left to + * the OS at exit. All receivers borrowed. */ + "child.pid": { argTypes: [CHILD_T], result: VOID }, + "child.exitCode": { argTypes: [CHILD_T], result: VOID }, + // The close-override pair: the bound close's result func type and the + // override's func argument are program-dependent (the callback union's + // tags) — the slots pin the server receiver; the libCall case checks + // the bound value's shape. + /** The close-override pair (the portless close-proxy idiom). + * serverCloseBind is `wrapper.close.bind(wrapper)` as a VALUE: a + * compiler-emitted closure over the server whose invocation runs the + * REAL close (scr_net_server_close_direct — never the override), so + * the override body's `origClose(cb)` cannot recurse; its callback + * argument (the `((err?: Error) => void) | undefined` union) registers + * as a once-'close' listener, a one-param callback wrapped by an + * emitted zero-arg trampoline firing the undefined arm (a clean close + * carries no error). serverSetCloseOverride is `wrapper.close = fn`: + * the override MOVES in behind an emitted zero-arg wrapper (it invokes + * the user function with the undefined-arm callback — tags are program + * data), and server.close() consults it before closing. */ + "net.serverCloseBind": { argTypes: [NETSERVER_T], result: VOID }, + "net.serverSetCloseOverride": { argTypes: [NETSERVER_T, null], result: VOID }, + // The piped-output stream reads: `Readable | null` unions (the libCall + // case checks the arms — the child.pid pattern with a ref arm). + /** The piped-output streams (stdio mode 3 — scr_child.c's stream + * slice). child.stdout/child.stderr answer the checker's + * `Readable | null` union (type-directed construction in the backend + * over the +1-or-NULL runtime pair — the child.pid pattern with a ref + * arm). stream.onData/onEnd register 'data'/'end' listeners (receiver + * borrowed, CALLBACK MOVES, trailing once-flag, void — chaining + * fenced): 'data' fires one Buffer chunk per read (zero-param and + * Buffer/string adapters are runtime-provided; setEncoding threads + * split multibyte sequences through the shared StringDecoder core. A + * union-param listener — + * ngrok's `Buffer | string` — gets a compiler-emitted adapter wrapping + * the chunk at its Buffer arm), 'end' fires once at EOF, always BEFORE + * the child's 'exit' (the pinned ordering). A flowing stream keeps the + * loop alive: usesTimers. */ + "child.stdout": { argTypes: [CHILD_T], result: VOID }, + "child.stderr": { argTypes: [CHILD_T], result: VOID }, + /** The piped-input writer (stdio mode 3 on fd 0). child.stdin answers + * `Writable | null`; writes copy borrowed data into the nonblocking + * queue, end/destroy settle it, writable is a pure state read, and + * listener callbacks move into the writer registry. */ + "child.stdin": { argTypes: [CHILD_T], result: VOID }, + /** Under the general stream representation (general-streams.ts), a + * stdio read (slot 0, 1 or 2) answers the child's bridged runtime stream + * — `Writable | null` for stdin, `Readable | null` otherwise; the bridge + * throws when the program lacks the stream unit's boxing helpers. */ + "child.stdioStream": { argTypes: [CHILD_T, F64], result: VOID }, + // Listener registrations: callback func shapes are program-dependent + // (zero-param / Buffer / string / unknown / Buffer-armed union) — the slots pin arity, + // the stream receiver, and the once-flag. + "stream.onData": { argTypes: [CHILDSTREAM_T, null, BOOL], result: VOID }, + "stream.onDataStr": { argTypes: [CHILDSTREAM_T, null, BOOL], result: VOID }, + "stream.onEnd": { argTypes: [CHILDSTREAM_T, null, BOOL], result: VOID }, + "stream.childSetEncoding": { argTypes: [CHILDSTREAM_T, STRING], result: CHILDSTREAM_T }, + "writer.writeString": { argTypes: [CHILDWRITER_T, STRING], result: BOOL }, + "writer.writeBytes": { argTypes: [CHILDWRITER_T, BYTES_U8], result: BOOL }, + "writer.end": { argTypes: [CHILDWRITER_T], result: VOID }, + "writer.destroy": { argTypes: [CHILDWRITER_T], result: VOID }, + "writer.writable": { argTypes: [CHILDWRITER_T], result: BOOL }, + "writer.onDrain": { argTypes: [CHILDWRITER_T, null, BOOL], result: VOID }, + "writer.onFinish": { argTypes: [CHILDWRITER_T, null, BOOL], result: VOID }, + "writer.onError": { argTypes: [CHILDWRITER_T, null, BOOL], result: VOID }, + /** The first-class WritableStream write (`output.write(line)` — the + * prefixStream idiom): the receiver IS the fd scalar (process.stdout/ + * stderr reads mint 1/2), dispatched onto the exact stdoutWrite/ + * stderrWrite paths so buffering and ordering stay identical. Data + * borrowed; the bool is Node's always-true backpressure signal. */ + "procStream.write": { argTypes: [PROCSTREAM_T, STRING], result: BOOL }, + /** process.stdout/stderr flowing into a runtime Writable slot under the + * general stream representation: an fd-backed Writable (+1) whose + * writes take process.stdout.write's synchronous path. */ + /** A pipeline() stage that is a checked-dynamic value: a boxed native + * stream unwraps by identity (+1); anything else throws the given + * not-supported message. Typed as a Duplex so every stage position + * accepts it; the runtime pipeline checks the stream's real sides. */ + "stream.unboxDyn": { + argTypes: [DYN, STRING], + result: { kind: "object", className: "%Duplex" }, + }, + /** Whether pipeline() pumps a checked-dynamic first stage as an + * iterable (a string, or a value with an iterator method that is not a + * stream with pipe() and on()) instead of piping it as a stream. */ + "stream.dynIterableSource": { argTypes: [DYN], result: BOOL }, + /** The Transform a Cipheriv or Decipheriv reads and writes as a stream + * (+1, created on first use and owned by the cipher). */ + "stream.handleStream": { + argTypes: [DYN], + result: { kind: "object", className: "%Transform" }, + }, + /** Checked-dynamic stream slots (dyn-streams.ts): the native stream a + * checked-dynamic value boxes (+1) — a runtime stream with the readable + * (1) or writable (2) side — or null for any other value. Never throws; + * the result union is `%Readable | null` or `%Writable | null`. */ + "stream.dynNative": { argTypes: [DYN, F64], result: VOID }, + /** stream.dynNative for a pipe or unpipe destination: also a + * constructor-function stream's runtime stream, in programs that link + * that unit, unless it overrides write() or end(). */ + "stream.dynNativePipe": { argTypes: [DYN, F64], result: VOID }, + /** readable.pipe(destination, end) into a checked-dynamic destination + * that is not a native stream: [source, the source boxed, destination, + * end]. Node's pipe listener protocol over the destination's members + * (scr_stream_dyn.c); throws what those members throw. */ + "stream.pipeDyn": { argTypes: [null, DYN, DYN, BOOL], result: VOID }, + /** readable.unpipe(destination) for a checked-dynamic destination that + * is not a native stream: [source, destination]. Unpipes the pipe + * stream.pipeDyn registered into it, if any (scr_stream_dyn.c). */ + "stream.unpipeDyn": { argTypes: [null, DYN], result: VOID }, + "stream.stdioWritable": { + argTypes: [PROCSTREAM_T], + result: { kind: "object", className: "%Writable" }, + }, + "child.killed": { argTypes: [CHILD_T], result: BOOL }, + "child.kill": { argTypes: [CHILD_T, STRING], result: BOOL }, + "child.killNum": { argTypes: [CHILD_T, F64], result: BOOL }, + "child.unref": { argTypes: [CHILD_T], result: VOID }, + "child.ref": { argTypes: [CHILD_T], result: VOID }, + "spawnRes.stdout": { argTypes: [SPAWNRES_T], result: STRING }, + "spawnRes.stderr": { argTypes: [SPAWNRES_T], result: STRING }, + /** fs/promises (scr_lib.c over scr_async.c's settled minting): the SAME + * sync syscalls, wrapped in an ALREADY-SETTLED promise — failure + * REJECTS (catchable at the await) instead of throwing, so none of + * these are in the may-throw seed. readFile is utf8-fenced like + * readFileSync. The non-interleaving divergence is documented in + * SEMANTICS.md. */ + /** node:crypto randomness: randomUUID plus randomBytes as either a real + * Buffer or the fused randomBytes(n).toString("hex"|"base64") path. + * The size-taking forms throw Node's RangeError on invalid values. */ + "crypto.randomUUID": { argTypes: [], result: STRING }, + "crypto.randomBytesToString": { argTypes: [F64, STRING], result: STRING }, + /** crypto.randomBytes(n) → a real u8 Buffer (+1). THROWS Node's + * RangeError on out-of-range sizes, exactly like the composed + * randomBytesToString (which keeps its one-libCall lowering — the two + * coexist: the composed form never materializes the Buffer). */ + "crypto.randomBytes": { argTypes: [F64], result: BYTES_U8 }, + /** The fused createHash(alg).update(data).digest(enc) fast path and the + * one-shot crypto.hash implementation. First-class Hash/Hmac handles use + * the entries below; all paths share the incremental runtime core. */ + "crypto.hashDigestStr": { argTypes: [STRING, STRING, STRING], result: STRING }, + "crypto.hashDigestBytes": { argTypes: [STRING, BYTES_U8, STRING], result: STRING }, + /** First-class static Hash/Hmac handles. Constructors validate the + * runtime algorithm string (every digest Node 24 lists); update returns the same + * handle by retained identity, copy snapshots Hash state, and digest + * finalizes the handle and returns either a Buffer or encoded string. */ + "crypto.native": { argTypes: [], result: DYN }, + "crypto.hashNew": { argTypes: [STRING], result: CRYPTOHASH_T }, + /** The Transform a Hash or Hmac reads and writes as a stream (+1, + * created on first use and owned by the value; scr_stream.c). The Piped + * form, for pipe destinations and pipeline stages, also keeps the value + * alive until the stream flushes or is destroyed. */ + "crypto.hashStream": { argTypes: [null], result: { kind: "object", className: "%Transform" } }, + "crypto.hashStreamPiped": { + argTypes: [null], + result: { kind: "object", className: "%Transform" }, + }, + /** createCipheriv (false) / createDecipheriv (true) over checked-dynamic + * cipher, key, iv and options arguments (scr_cipher.c): a native + * Cipheriv/Decipheriv handle whose methods dispatch through dynInvoke. */ + "crypto.cipherNew": { argTypes: [BOOL, DYN, DYN, DYN, DYN], result: DYN }, + /** createECDH(curveName) over a checked-dynamic curve (scr_ecdh.c): a + * native ECDH handle whose methods dispatch through dynInvoke. */ + "crypto.ecdhNew": { argTypes: [DYN], result: DYN }, + /** ECDH.convertKey(key, curve, inputEncoding, outputEncoding, format): + * the converted point as a Buffer or string. */ + "crypto.ecdhConvertKey": { argTypes: [DYN, DYN, DYN, DYN, DYN], result: DYN }, + /** createDiffieHellman(sizeOrKey, keyEncoding, generator, + * generatorEncoding) over checked-dynamic arguments (scr_dh.c): a native + * DiffieHellman handle whose methods dispatch through dynInvoke. */ + "crypto.dhNew": { argTypes: [DYN, DYN, DYN, DYN], result: DYN }, + /** getDiffieHellman(groupName) and createDiffieHellmanGroup(name): a + * native DiffieHellmanGroup handle. */ + "crypto.dhGroupNew": { argTypes: [DYN], result: DYN }, + /** checkPrimeSync(candidate, options) and generatePrimeSync(size, + * options) over checked-dynamic arguments (scr_dh.c): a boolean, and an + * ArrayBuffer or bigint, as checked-dynamic results. The Cb forms take + * the callback and whether its error parameter takes null for Node's + * undefined, and call it in a later macrotask; Node's argument errors + * throw (may-throw). */ + "crypto.checkPrimeSync": { argTypes: [DYN, DYN], result: DYN }, + /** getCipherInfo(nameOrNid, options) over checked-dynamic arguments + * (scr_cipher_info.c): the info object or undefined. */ + "crypto.getCipherInfo": { argTypes: [DYN, DYN], result: DYN }, + "crypto.checkPrimeCb": { argTypes: [DYN, DYN, DYN, BOOL], result: VOID }, + "crypto.generatePrimeSync": { argTypes: [DYN, DYN], result: DYN }, + "crypto.generatePrimeCb": { argTypes: [DYN, DYN, DYN, BOOL], result: VOID }, + "crypto.hmacNewStr": { argTypes: [STRING, STRING], result: CRYPTOHMAC_T }, + "crypto.hmacNewBytes": { argTypes: [STRING, BYTES_U8], result: CRYPTOHMAC_T }, + "crypto.hashUpdateStr": { argTypes: [CRYPTOHASH_T, STRING], result: CRYPTOHASH_T }, + "crypto.hashUpdateBytes": { argTypes: [CRYPTOHASH_T, BYTES_U8], result: CRYPTOHASH_T }, + "crypto.hmacUpdateStr": { argTypes: [CRYPTOHMAC_T, STRING], result: CRYPTOHMAC_T }, + "crypto.hmacUpdateBytes": { argTypes: [CRYPTOHMAC_T, BYTES_U8], result: CRYPTOHMAC_T }, + "crypto.hashCopy": { argTypes: [CRYPTOHASH_T], result: CRYPTOHASH_T }, + "crypto.hashDigestString": { argTypes: [CRYPTOHASH_T, STRING], result: STRING }, + "crypto.hashDigestBuffer": { argTypes: [CRYPTOHASH_T], result: BYTES_U8 }, + "crypto.hmacDigestString": { argTypes: [CRYPTOHMAC_T, STRING], result: STRING }, + "crypto.hmacDigestBuffer": { argTypes: [CRYPTOHMAC_T], result: BYTES_U8 }, + /** The option and any-value forms, with Node's checks at run time. The + * Dyn digests return a string or a Buffer, and crypto.hash's Dyn form + * either one by its outputEncoding. */ + "crypto.hashNewOpts": { argTypes: [STRING, DYN], result: CRYPTOHASH_T }, + "crypto.hmacNewDyn": { argTypes: [STRING, DYN, DYN], result: CRYPTOHMAC_T }, + "crypto.hashCopyOpts": { argTypes: [CRYPTOHASH_T, DYN], result: CRYPTOHASH_T }, + "crypto.hashUpdateEnc": { argTypes: [CRYPTOHASH_T, STRING, STRING], result: CRYPTOHASH_T }, + "crypto.hmacUpdateEnc": { argTypes: [CRYPTOHMAC_T, STRING, STRING], result: CRYPTOHMAC_T }, + "crypto.hashUpdateDyn": { argTypes: [CRYPTOHASH_T, DYN, DYN], result: CRYPTOHASH_T }, + "crypto.hmacUpdateDyn": { argTypes: [CRYPTOHMAC_T, DYN, DYN], result: CRYPTOHMAC_T }, + "crypto.hashDigestDyn": { argTypes: [CRYPTOHASH_T, DYN], result: DYN }, + "crypto.hmacDigestDyn": { argTypes: [CRYPTOHMAC_T, DYN], result: DYN }, + "crypto.hashOneshot": { argTypes: [STRING, DYN, DYN], result: DYN }, + /** Views of any element kind (the validator checks both are views). */ + "crypto.timingSafeEqual": { argTypes: [null, null], result: BOOL }, + "crypto.timingSafeEqualDyn": { argTypes: [DYN, DYN], result: BOOL }, + "crypto.randomFill": { argTypes: [BYTES_U8, F64, F64], result: BYTES_U8 }, + "crypto.randomFillRest": { argTypes: [BYTES_U8, F64], result: BYTES_U8 }, + "crypto.randomInt": { argTypes: [F64, F64], result: F64 }, + "crypto.randomIntMax": { argTypes: [F64], result: F64 }, + /** randomFillSync over any view returns that view at its own type (the + * validator checks the result against the first argument). The Dyn form + * takes ArrayBuffers and other values. The callback forms carry + * randomFill's argument count before the callback; randomIntCb carries + * whether min was given. */ + "crypto.randomFillView": { argTypes: [null, F64, F64], result: BYTES_U8 }, + "crypto.randomFillViewRest": { argTypes: [null, F64], result: BYTES_U8 }, + /** crypto.getRandomValues: a view returns itself at its own type (the + * float/size DOMExceptions are thrown at run time); any other value + * takes the checked form. */ + "crypto.getRandomValues": { argTypes: [null], result: BYTES_U8 }, + "crypto.getRandomValuesDyn": { argTypes: [DYN], result: DYN }, + "crypto.randomFillSyncDyn": { argTypes: [DYN, DYN, DYN], result: DYN }, + "crypto.randomFillCb": { argTypes: [null, F64, F64, F64, null], result: VOID }, + "crypto.randomFillCbDyn": { argTypes: [DYN, DYN, DYN, F64, null], result: VOID }, + "crypto.randomIntCb": { argTypes: [F64, F64, F64, null], result: VOID }, + "crypto.randomUUIDOpts": { argTypes: [DYN], result: STRING }, + /** Secret KeyObjects: native handles whose getters and methods dispatch + * through the handle. keyObjectInput reads a key's bytes for hkdf. */ + "crypto.createSecretKey": { argTypes: [DYN, DYN], result: DYN }, + "crypto.generateKeySync": { argTypes: [DYN, DYN], result: DYN }, + "crypto.generateKeyCb": { argTypes: [DYN, DYN, null], result: VOID }, + "crypto.keyObjectInput": { argTypes: [DYN], result: BYTES_U8 }, + "crypto.isKeyObject": { argTypes: [DYN], result: BOOL }, + /** WebCrypto (scr_webcrypto.c): each method takes its argument vector as + * one dyn array and answers a promise that argument and validation + * failures reject. CryptoKey values are native handles. */ + "webcrypto.generateKey": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, + "webcrypto.importKey": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, + "webcrypto.exportKey": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, + "webcrypto.encrypt": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, + "webcrypto.decrypt": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, + "webcrypto.wrapKey": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, + "webcrypto.unwrapKey": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, + "webcrypto.deriveBits": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, + "webcrypto.deriveKey": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, + "webcrypto.sign": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, + "webcrypto.verify": { argTypes: [DYN], result: { kind: "promise", inner: BOOL } }, + "webcrypto.digest": { argTypes: [DYN], result: { kind: "promise", inner: DYN } }, + "webcrypto.isCryptoKey": { argTypes: [DYN], result: BOOL }, + "webcrypto.object": { argTypes: [], result: DYN }, + "crypto.randomUUIDv7": { argTypes: [DYN], result: STRING }, + "crypto.pbkdf2": { argTypes: [BYTES_U8, BYTES_U8, F64, F64, STRING], result: BYTES_U8 }, + "crypto.randomBytesCb": { argTypes: [F64, null], result: VOID }, + "crypto.pbkdf2Cb": { argTypes: [BYTES_U8, BYTES_U8, F64, F64, STRING, null], result: VOID }, + "crypto.hkdf": { argTypes: [STRING, BYTES_U8, BYTES_U8, BYTES_U8, F64], result: DYN }, + "crypto.hkdfCb": { argTypes: [STRING, BYTES_U8, BYTES_U8, BYTES_U8, F64, null], result: VOID }, + "crypto.scrypt": { argTypes: [BYTES_U8, BYTES_U8, F64, DYN], result: BYTES_U8 }, + "crypto.scryptCb": { argTypes: [BYTES_U8, BYTES_U8, F64, DYN, null], result: VOID }, + /** util.promisify over the callback forms: the callback form's + * arguments without the callback → a promise the callback form settles, + * or rejected with an argument error; never throws. The result's value + * type is the declared one (a Buffer, the filled view, a number, or a + * checked-dynamic value); the validator checks it. */ + "crypto.randomBytesPromise": { argTypes: [F64], result: VOID }, + "crypto.pbkdf2Promise": { argTypes: [BYTES_U8, BYTES_U8, F64, F64, STRING], result: VOID }, + "crypto.scryptPromise": { argTypes: [BYTES_U8, BYTES_U8, F64, DYN], result: VOID }, + "crypto.hkdfPromise": { argTypes: [STRING, BYTES_U8, BYTES_U8, BYTES_U8, F64], result: VOID }, + "crypto.randomFillPromise": { argTypes: [null, F64, F64, F64], result: VOID }, + "crypto.randomFillPromiseDyn": { argTypes: [DYN, DYN, DYN, F64], result: VOID }, + "crypto.randomIntPromise": { argTypes: [F64, F64, F64], result: VOID }, + "crypto.generateKeyPromise": { argTypes: [DYN, DYN], result: VOID }, + /** util.promisify(dns.lookup) and util.promisify(dns.lookupService): + * [hostname, options] and [address, port] → a promise of the + * checked-dynamic result object (the address array with options.all), + * or rejected with the error; never throws. */ + "dns.lookupPromise": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, + "dns.lookupServicePromise": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, + // The Buffer statics and the fs/zlib Buffer forms: fixed always-u8 + // signatures (Buffer IS a Uint8Array — one bytes kind). + /** The Buffer statics with fixed (always-u8) signatures. fromStr is + * `Buffer.from(string, enc)` — the frontend completes an omitted + * encoding to "utf8" and fences non-literal/unsupported ones; hex and + * base64 decode Node-leniently, so it never throws. concat takes ONE + * bytes[] arg (the list) and returns a fresh copy. `Buffer.from(u8)` + * and `Buffer.alloc(n)` need no libFn — they lower to bytesNew. */ + "buffer.fromStr": { argTypes: [STRING, STRING], result: BYTES_U8 }, + "buffer.fromStrChecked": { argTypes: [STRING, STRING], result: BYTES_U8 }, + "buffer.brand": { argTypes: [BYTES_U8], result: BYTES_U8 }, + /** Buffer.isBuffer over a typed view: whether the view carries the + * Buffer brand (any element kind; only Buffers do). Never throws. */ + "buffer.isBranded": { argTypes: [null], result: BOOL }, + /** Buffer.from on checked-native strings, bytes, arrays and data-only + * array-like/Buffer-JSON objects. The encoding is a normalized literal; + * non-string inputs ignore it. Copies the input and may throw during + * element coercion or argument validation. Custom object valueOf and + * opaque reference inputs retain explicit runtime refusals. */ + "buffer.fromDyn": { argTypes: [DYN, STRING], result: BYTES_U8 }, + "buffer.concat": { argTypes: [arrayOf(BYTES_U8)], result: BYTES_U8 }, + "buffer.concatDyn": { argTypes: [DYN], result: BYTES_U8 }, + /** The pooled Buffer factories (Node's allocate/fromStringFast/ + * fromArrayLike): allocUnsafe, Buffer.from of strings, Uint8Arrays, + * number[] and checked values, and concat return views into the + * per-thread pool slab below Buffer.poolSize >>> 1 bytes. alloc and + * allocUnsafeSlow never pool. The size forms validate like Node + * (ERR_OUT_OF_RANGE). poolSize reads and writes Buffer.poolSize. */ + "buffer.alloc": { argTypes: [F64], result: BYTES_U8 }, + /** Buffer.alloc as a function value: the size, fill and encoding arrive + * unchecked, and the runtime fills as Node's alloc does. */ + "buffer.allocValue": { argTypes: [DYN, DYN, DYN], result: BYTES_U8 }, + "buffer.allocUnsafe": { argTypes: [F64], result: BYTES_U8 }, + "buffer.allocUnsafeSlow": { argTypes: [F64], result: BYTES_U8 }, + "buffer.poolFromStr": { argTypes: [STRING, STRING], result: BYTES_U8 }, + "buffer.poolFromStrChecked": { argTypes: [STRING, STRING], result: BYTES_U8 }, + "buffer.poolFromBytes": { argTypes: [BYTES_U8], result: BYTES_U8 }, + "buffer.poolFromArray": { argTypes: [arrayOf(F64)], result: BYTES_U8 }, + "buffer.poolFromDyn": { argTypes: [DYN, STRING], result: BYTES_U8 }, + /** poolFromDyn that also copies an array crossing by reference. */ + "buffer.poolFromDynRef": { argTypes: [DYN, STRING], result: BYTES_U8 }, + "buffer.poolFromDynOffset": { argTypes: [DYN, DYN], result: BYTES_U8 }, + /** Buffer.from(value, byteOffset, length): an ArrayBuffer's range with + * Node's fromArrayBuffer checks; other values as poolFromDynOffset. */ + "buffer.poolFromDynRange": { argTypes: [DYN, DYN, DYN], result: BYTES_U8 }, + "buffer.poolSize": { argTypes: [], result: F64 }, + "buffer.setPoolSize": { argTypes: [F64], result: VOID }, + /** Buffer.byteLength(string, enc) — enc a NORMALIZED literal like + * fromStr's — and Buffer.isEncoding(name) over a runtime string + * (case-insensitive against Node's alias set). Pure; never throw. */ + "buffer.byteLenDyn": { argTypes: [DYN, STRING], result: F64 }, + /** Buffer.byteLength as a function value: the encoding arrives at run time. */ + "buffer.byteLenValue": { argTypes: [DYN, DYN], result: F64 }, + "buffer.byteLenStr": { argTypes: [STRING, STRING], result: F64 }, + "buffer.isEncoding": { argTypes: [STRING], result: BOOL }, + /** Buffer.concat(list, totalLength): the concatenation truncated or + * zero-padded to the total. THROWS Node's 'length' RangeError on a + * negative/non-integer total (may-throw seed). */ + "buffer.concatLen": { argTypes: [arrayOf(BYTES_U8), F64], result: BYTES_U8 }, + "buffer.concatLenDyn": { argTypes: [DYN, F64], result: BYTES_U8 }, + // The checked-dynamic compare/equals validators (Node's argument + // ladders over dyn-boxed invalid-input probes). + /** The checked-dynamic compare/equals validators (scr_bytes_io.c) — + * the lowered form when an argument is NOT statically bytes (the + * invalid-input probes; a dyn from an untyped JS helper): Node's own + * argument ladders run at runtime — ERR_INVALID_ARG_TYPE with the + * API's argument name ("buf1"/"buf2", "otherBuffer", "target"; offsets + * "of type number"), validateOffset's ERR_OUT_OF_RANGE for bad + * numbers, undefined offsets taking their Node defaults — and a + * well-typed value still computes the real answer. All args borrowed + * dyn; compareChk's four offset slots pass the undefined dyn when + * syntactically absent. May-throw seeds. */ + "buffer.compareChk": { argTypes: [DYN, DYN], result: F64 }, + "bytes.equalsChk": { argTypes: [BYTES_U8, DYN], result: BOOL }, + "bytes.compareChk": { argTypes: [BYTES_U8, DYN, DYN, DYN, DYN, DYN], result: F64 }, + /** The deprecated `new Buffer(number, 'enc')` string-arm rejection: + * always throws Node's ERR_INVALID_ARG_TYPE ("The \"string\" argument + * must be of type string. Received ..."). Borrowed dyn; may-throw. */ + "buffer.newStringFail": { argTypes: [DYN], result: BYTES_U8 }, + "buffer.deprecation": { argTypes: [], result: VOID }, + "buffer.deprecationCount": { argTypes: [], result: VOID }, + "buffer.constructor": { argTypes: [], result: DYN }, + "buffer.installValue": { argTypes: [], result: VOID }, + "buffer.staticValue": { argTypes: [STRING], result: DYN }, + "buffer.prototypeMember": { argTypes: [DYN], result: DYN }, + /** fs._toUnixTimestamp(time) over a dyn value: numeric strings and + * finite numbers coerce (negatives answer now/1000, Node's shape); + * everything else throws Node's ERR_INVALID_ARG_TYPE. May-throw. */ + "fs.toUnixTimestamp": { argTypes: [DYN], result: F64 }, + /** The fs argument-validation ladders (checked-dynamic lane): each Chk + * replicates its API's Node-order validation over dyn values (Node's + * exact typed errors — ERR_INVALID_ARG_TYPE/VALUE, ERR_OUT_OF_RANGE), + * and a full pass meets the trailing compiler-rendered SC2020 fence + * string — so the ALWAYS-THROW forms take the error.nodeThrow + * polymorphic-result carve-out. mkdtempSyncChk and the lchmod sync/ + * promise pair run the REAL operation on a validated pass instead + * (macOS lchmod(2); non-APPLE answers Node's not-a-function / + * ERR_METHOD_NOT_IMPLEMENTED shapes). May-throw seeds, all of them. */ + "fs.existsChk": { argTypes: [DYN, DYN], result: DYN }, + "fs.mkdtempChk": { argTypes: [DYN, DYN, STRING], result: VOID }, + "fs.mkdtempSyncChk": { argTypes: [DYN, DYN, STRING], result: STRING }, + "fs.readFileChk": { argTypes: [DYN, DYN, DYN, STRING], result: VOID }, + "fs.opendirChk": { argTypes: [DYN, DYN, STRING], result: VOID }, + "fs.watchFileChk": { argTypes: [DYN, DYN, STRING], result: VOID }, + "fs.lchmodChk": { argTypes: [DYN, DYN, DYN, STRING], result: VOID }, + "fs.lchmodSyncChk": { argTypes: [DYN, DYN], result: DYN }, + "fsp.lchmodChk": { argTypes: [DYN, DYN], result: { kind: "promise", inner: VOID } }, + "fs.readChk": { argTypes: [DYN, DYN, DYN, DYN, DYN, STRING], result: VOID }, + "fs.streamOptsChk": { argTypes: [DYN, DYN, STRING], result: VOID }, + /** fs.ReadStream / fs.WriteStream (scr_fs_stream.c): the constructors + * take the path and options as dyn values and throw Node's option + * errors; the members read bytesRead/bytesWritten, pending and the path + * value, and close() / close(cb) (a `() => void` callback). */ + "fs.createReadStream": { + argTypes: [DYN, DYN], + result: { kind: "object", className: "%Readable" }, + }, + "fs.createWriteStream": { + argTypes: [DYN, DYN], + result: { kind: "object", className: "%Writable" }, + }, + "fs.fsStreamBytes": { argTypes: [null], result: F64 }, + "fs.fsStreamPending": { argTypes: [null], result: BOOL }, + "fs.fsStreamPath": { argTypes: [null], result: DYN }, + "fs.fsStreamPropDyn": { argTypes: [null, STRING], result: DYN }, + "fileHandle.createReadStream": { + argTypes: [FILEHANDLE_T, DYN], + result: { kind: "object", className: "%Readable" }, + }, + "fileHandle.createWriteStream": { + argTypes: [FILEHANDLE_T, DYN], + result: { kind: "object", className: "%Writable" }, + }, + "fs.fsStreamClose": { argTypes: [null], result: VOID }, + "fs.fsStreamCloseCb": { argTypes: [null, funcOf([], VOID)], result: VOID }, + /** The compiler-resolved ERR_INVALID_ARG_TYPE throw with a RUNTIME- + * rendered Received tail: args [argname, "of type ..." clause, the + * offending dyn value]. ALWAYS THROWS; polymorphic result (the + * error.nodeThrow pattern). May-throw seed. */ + "error.argTypeThrow": { argTypes: [STRING, STRING, DYN], result: VOID }, + /** The property flavor of argTypeThrow ("The \"options.x\" property + * must be ..."): the option-bag ladders' provably-invalid arms. ALWAYS + * THROWS; polymorphic result. May-throw seed. */ + "error.propTypeThrow": { argTypes: [STRING, STRING, DYN], result: VOID }, + /** The checked-dynamic max-listeners ladders: setMaxChk is the + * instance form over a dyn n (non-numbers ERR_INVALID_ARG_TYPE, + * negatives/NaN ERR_OUT_OF_RANGE; +1 receiver back — chaining); + * setDefaultMaxChk is the static/property form, its second argument + * naming the message slot ("setMaxListeners" for the static call, + * "defaultMaxListeners" for the module-property assignment). */ + "emitter.setMaxChk": { argTypes: [null, DYN], result: VOID }, + "emitter.setDefaultMaxChk": { argTypes: [DYN, STRING], result: VOID }, + /** The Buffer forms of fs: readFileSync(path) with NO + * encoding → bytes (+1), writeFileSync/appendFileSync(path, bytes), and the + * fs/promises readFile(path) no-encoding form (an already-settled + * promise, rejecting on failure like the other fsp members). The sync + * forms THROW catchably on failure exactly like the utf8 forms. */ + "fs.readFileSyncBytes": { argTypes: [STRING], result: BYTES_U8 }, + "fs.writeFileSyncBytes": { argTypes: [STRING, BYTES_U8], result: VOID }, + "fs.appendFileSyncBytes": { argTypes: [STRING, BYTES_U8], result: VOID }, + "fsp.readFileBytes": { argTypes: [STRING], result: { kind: "promise", inner: BYTES_U8 } }, + /** node:zlib (scr_zlib.c — native-toolchain.ts compiles/links it ONLY when these + * appear on the IR, the regex/libcurl gating precedent): one-shot zlib, + * raw-DEFLATE, gzip, and auto-detect codecs over u8 bytes with Node's + * default options, or a validated literal compression level from -1 to 9. + * Compression never throws (OOM aborts); decompression + * of corrupt input THROWS Node's error catchably. */ + "zlib.deflateSync": { argTypes: [BYTES_U8], result: BYTES_U8 }, + "zlib.inflateSync": { argTypes: [BYTES_U8], result: BYTES_U8 }, + "zlib.deflateRawSync": { argTypes: [BYTES_U8], result: BYTES_U8 }, + /** bytes, mode (0 zlib / 1 raw / 2 gzip), validated compression level. */ + "zlib.deflateLevelSync": { argTypes: [BYTES_U8, F64, F64], result: BYTES_U8 }, + "zlib.inflateRawSync": { argTypes: [BYTES_U8], result: BYTES_U8 }, + "zlib.gzipSync": { argTypes: [BYTES_U8], result: BYTES_U8 }, + "zlib.gunzipSync": { argTypes: [BYTES_U8], result: BYTES_U8 }, + "zlib.unzipSync": { argTypes: [BYTES_U8], result: BYTES_U8 }, + /** The default-options callback twins run on the executable's shared + * native work pool and deliver (Error | null, Buffer) on a later loop + * turn. crc32 validates its optional uint32 seed synchronously. */ + "zlib.deflateCb": { argTypes: [BYTES_U8, null], result: VOID }, + "zlib.inflateCb": { argTypes: [BYTES_U8, null], result: VOID }, + "zlib.deflateRawCb": { argTypes: [BYTES_U8, null], result: VOID }, + "zlib.inflateRawCb": { argTypes: [BYTES_U8, null], result: VOID }, + "zlib.gzipCb": { argTypes: [BYTES_U8, null], result: VOID }, + "zlib.gunzipCb": { argTypes: [BYTES_U8, null], result: VOID }, + "zlib.unzipCb": { argTypes: [BYTES_U8, null], result: VOID }, + "zlib.crc32": { argTypes: [BYTES_U8, F64], result: F64 }, + /** The one-shot forms with an options value: node_zlib_mode, the input, + * the options (validated at runtime with Node's ladder). The Cb form + * takes the program-shaped (Error | null, Buffer) callback, which moves. */ + "zlib.syncOpts": { argTypes: [F64, BYTES_U8, DYN], result: BYTES_U8 }, + "zlib.cbOpts": { argTypes: [F64, BYTES_U8, DYN, null], result: VOID }, + /** The checked-dynamic input twins (the JS lane's untyped data). */ + "zlib.syncOptsDyn": { argTypes: [F64, DYN, DYN], result: BYTES_U8 }, + "zlib.cbOptsDyn": { argTypes: [F64, DYN, DYN, null], result: VOID }, + /** util.promisify over the callback one-shots: [mode, data, options] + * like zlib.cbOpts → a promise the worker-pool run settles with the + * Buffer or the callback form's Error. An options or input error rejects + * it; never throws. The Dyn twin takes the JS lane's untyped data. */ + "zlib.promise": { + argTypes: [F64, BYTES_U8, DYN], + result: { kind: "promise", inner: BYTES_U8 }, + }, + "zlib.promiseDyn": { argTypes: [F64, DYN, DYN], result: { kind: "promise", inner: BYTES_U8 } }, + /** The stream classes (scr_zlib_stream.c, linked with the stream unit): + * streamNew takes Node's node_zlib_mode number and the options value + * (undefined when absent), validates it with Node's ladder, and answers + * the +1 %Transform stream. flush takes the kind value, params the level + * and strategy values; the Cb forms move their () => void callback. The + * receivers are borrowed. */ + /** Connects scr_brotli.c to the zlib engine (%main, before any module). */ + "zlib.brotliInstall": { argTypes: [], result: VOID }, + "zlib.streamNew": { argTypes: [F64, DYN], result: VOID }, + "zlib.streamBytesWritten": { argTypes: [null], result: F64 }, + /** `stream instanceof zlib.Gzip`: the borrowed stream and the class's + * node_zlib_mode; true when the stream is a zlib stream of that mode. */ + "zlib.streamIs": { argTypes: [null, F64], result: BOOL }, + "zlib.streamFlush": { argTypes: [null, DYN], result: VOID }, + "zlib.streamFlushCb": { argTypes: [null, DYN, null], result: VOID }, + "zlib.streamParams": { argTypes: [null, DYN, DYN], result: VOID }, + "zlib.streamParamsCb": { argTypes: [null, DYN, DYN, null], result: VOID }, + "zlib.streamClose": { argTypes: [null], result: VOID }, + "zlib.streamCloseCb": { argTypes: [null, null], result: VOID }, + "zlib.streamReset": { argTypes: [null], result: VOID }, + /** The Buffer overloads of the raw stream writes — same promptly + * submitted streams as process.stdoutWrite/stderrWrite, constantly true. + * The encoding arg is evaluated but ignored for bytes, like Node. The Cb + * forms move their program-shaped completion callback to the tick queue. */ + "process.stdoutWriteBytes": { argTypes: [BYTES_U8, STRING], result: BOOL }, + "process.stderrWriteBytes": { argTypes: [BYTES_U8, STRING], result: BOOL }, + // Completion callback is program-dependent: zero params, checked-dynamic, + // or an optional Error | null slot (same success shape as fs.rename). + "process.stdoutWriteBytesCb": { argTypes: [BYTES_U8, STRING, null], result: BOOL }, + "process.stderrWriteBytesCb": { argTypes: [BYTES_U8, STRING, null], result: BOOL }, + /** The value of a FULFILLED promise, read without a microtask turn (+1 + * for references): the tuple form of Promise.all reads its entries this + * way once the combinator fulfills, each entry widened to Promise + * and read at the type it was built with (program-dependent). */ + "promise.fulfilledValue": { argTypes: [null], result: VOID }, + /** Promise.all's tuple form as a value: the entries (each widened to + * Promise) join the runtime combinator, and when it fulfills the + * function reads the fulfilled entries into the tuple inside that + * settlement, so the result settles on the combinator's turn; a + * rejection settles it the same way. The result is the tuple's promise + * (program-dependent). */ + "promise.allTuple": { argTypes: [null, null], result: VOID }, + "fsp.readFile": { argTypes: [STRING, STRING], result: { kind: "promise", inner: STRING } }, + "fsp.writeFile": { argTypes: [STRING, STRING], result: { kind: "promise", inner: VOID } }, + /** fs.promises.writeFile(path, data, { mode }): the settled-promise + * twin of fs.writeFileModeSync. */ + "fsp.writeFileMode": { + argTypes: [STRING, STRING, F64], + result: { kind: "promise", inner: VOID }, + }, + "fsp.mkdir": { argTypes: [STRING], result: { kind: "promise", inner: VOID } }, + /** The fs/promises option/member tail the certs pipeline uses: mkdir's + * literal { recursive?, mode? } options (the mkdirSync matrix behind + * settled promises), unlink, chmod. Failures REJECT (catchable at the + * await), like the rest of the fsp family. */ + "fsp.mkdirMode": { argTypes: [STRING, F64], result: { kind: "promise", inner: VOID } }, + "fsp.mkdirRecursive": { argTypes: [STRING], result: { kind: "promise", inner: VOID } }, + "fsp.mkdirRecursiveMode": { argTypes: [STRING, F64], result: { kind: "promise", inner: VOID } }, + "fsp.unlink": { argTypes: [STRING], result: { kind: "promise", inner: VOID } }, + "fsp.chmod": { argTypes: [STRING, F64], result: { kind: "promise", inner: VOID } }, + "fsp.chown": { argTypes: [STRING, F64, F64], result: { kind: "promise", inner: VOID } }, + "fsp.lchown": { argTypes: [STRING, F64, F64], result: { kind: "promise", inner: VOID } }, + "fsp.access": { argTypes: [STRING, F64], result: { kind: "promise", inner: VOID } }, + "fsp.truncate": { argTypes: [STRING, F64], result: { kind: "promise", inner: VOID } }, + "fsp.appendFile": { argTypes: [STRING, STRING], result: { kind: "promise", inner: VOID } }, + "fsp.appendFileBytes": { + argTypes: [STRING, BYTES_U8], + result: { kind: "promise", inner: VOID }, + }, + "fsp.copyFile": { argTypes: [STRING, STRING], result: { kind: "promise", inner: VOID } }, + "fsp.mkdtemp": { argTypes: [STRING], result: { kind: "promise", inner: STRING } }, + /** readFile(path, encoding | { encoding }) for any runtime encoding name. */ + "fsp.readFileEncoded": { + argTypes: [STRING, STRING], + result: { kind: "promise", inner: STRING }, + }, + "fsp.rmdir": { argTypes: [STRING], result: { kind: "promise", inner: VOID } }, + "fsp.link": { argTypes: [DYN, DYN], result: { kind: "promise", inner: VOID } }, + "fsp.symlink": { argTypes: [DYN, DYN, DYN], result: { kind: "promise", inner: VOID } }, + "fsp.cp": { argTypes: [DYN, DYN, DYN], result: { kind: "promise", inner: VOID } }, + "fsp.readlink": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, + "fsp.statfs": { argTypes: [DYN, DYN], result: { kind: "promise", inner: DYN } }, + "fsp.readlinkStr": { argTypes: [DYN, DYN], result: { kind: "promise", inner: STRING } }, + "fsp.readlinkBuffer": { argTypes: [DYN, DYN], result: { kind: "promise", inner: BYTES_U8 } }, + "fsp.utimes": { argTypes: [DYN, DYN, DYN], result: { kind: "promise", inner: VOID } }, + "fsp.lutimes": { argTypes: [DYN, DYN, DYN], result: { kind: "promise", inner: VOID } }, + "fsp.rename": { argTypes: [STRING, STRING], result: { kind: "promise", inner: VOID } }, + "fsp.readdir": { argTypes: [STRING], result: { kind: "promise", inner: arrayOf(STRING) } }, + // Result is promise; the libCall case + // validates the program-dependent record shape in validate.ts. + /** `fs.promises.readdir(path, { withFileTypes: true })` — the settled- + * promise twin of fs.readdirTypesSync. The backends assemble the same + * call-site-shaped Dirent rows, then move the array into a promise; + * scandir failure becomes its rejection. */ + "fsp.readdirTypes": { argTypes: [STRING], result: { kind: "promise", inner: VOID } }, + "fsp.rm": { argTypes: [STRING], result: { kind: "promise", inner: VOID } }, + /** `fs.promises.rm(path, options)`: fs.rmOptsSync and fs.rmRetrySync + * behind a settled promise; their errors become its rejection. */ + "fsp.rmOpts": { argTypes: [STRING, BOOL, BOOL], result: { kind: "promise", inner: VOID } }, + "fsp.rmRetry": { + argTypes: [STRING, BOOL, BOOL, F64, F64], + result: { kind: "promise", inner: VOID }, + }, + "fsp.stat": { argTypes: [STRING], result: { kind: "promise", inner: STATS_T } }, + "fsp.realpath": { argTypes: [STRING], result: { kind: "promise", inner: STRING } }, + "fsp.lstat": { argTypes: [STRING], result: { kind: "promise", inner: STATS_T } }, + /** fs/promises.open and the statically represented FileHandle surface. + * Every operation returns an already-settled promise; syscall failures + * become rejections rather than escaping synchronously. read/write + * results are call-site record shapes ({ bytesRead/bytesWritten, + * buffer }) assembled by the backends around the fixed runtime ABI. */ + "fsp.open": { + argTypes: [STRING, STRING, F64], + result: { kind: "promise", inner: FILEHANDLE_T }, + }, + "fileHandle.fd": { argTypes: [FILEHANDLE_T], result: F64 }, + "fileHandle.close": { argTypes: [FILEHANDLE_T], result: { kind: "promise", inner: VOID } }, + "fileHandle.sync": { argTypes: [FILEHANDLE_T], result: { kind: "promise", inner: VOID } }, + "fileHandle.datasync": { argTypes: [FILEHANDLE_T], result: { kind: "promise", inner: VOID } }, + "fileHandle.truncate": { + argTypes: [FILEHANDLE_T, F64], + result: { kind: "promise", inner: VOID }, + }, + "fileHandle.chmod": { argTypes: [FILEHANDLE_T, F64], result: { kind: "promise", inner: VOID } }, + "fileHandle.utimes": { + argTypes: [FILEHANDLE_T, DYN, DYN], + result: { kind: "promise", inner: VOID }, + }, + "fileHandle.readv": { + argTypes: [FILEHANDLE_T, arrayOf(BYTES_U8), F64], + result: { kind: "promise", inner: VOID }, + }, + "fileHandle.writev": { + argTypes: [FILEHANDLE_T, arrayOf(BYTES_U8), F64], + result: { kind: "promise", inner: VOID }, + }, + // read/write carry call-site result record shapes; the validator checks + // those in validate.ts, so promise is only a table sentinel. + "fileHandle.read": { + argTypes: [FILEHANDLE_T, BYTES_U8, F64, F64, F64, BOOL], + result: { kind: "promise", inner: VOID }, + }, + "fileHandle.writeBytes": { + argTypes: [FILEHANDLE_T, BYTES_U8, F64, F64, F64, BOOL], + result: { kind: "promise", inner: VOID }, + }, + "fileHandle.writeStr": { + argTypes: [FILEHANDLE_T, STRING, F64, STRING], + result: { kind: "promise", inner: VOID }, + }, + "fileHandle.readFile": { + argTypes: [FILEHANDLE_T, STRING], + result: { kind: "promise", inner: STRING }, + }, + "fileHandle.readFileBytes": { + argTypes: [FILEHANDLE_T, STRING], + result: { kind: "promise", inner: BYTES_U8 }, + }, + "fileHandle.writeFile": { + argTypes: [FILEHANDLE_T, STRING, STRING], + result: { kind: "promise", inner: VOID }, + }, + "fileHandle.writeFileBytes": { + argTypes: [FILEHANDLE_T, BYTES_U8, STRING], + result: { kind: "promise", inner: VOID }, + }, + "fileHandle.stat": { argTypes: [FILEHANDLE_T], result: { kind: "promise", inner: STATS_T } }, + "process.argv": { argTypes: [], result: arrayOf(STRING) }, + // The Node runtime flag a node:test binary took out of process.argv + // (--test-update-snapshots), or [] — a fresh array per read. + "process.execArgv": { argTypes: [], result: arrayOf(STRING) }, + "process.platform": { argTypes: [], result: STRING }, + // The one libCall whose result type is program-dependent (union ids are + // per-module): the `result` here is a placeholder — the libCall case + // checks the union's ARMS ([string, undefinedT] in canonical order) + // against the module's registry instead. + /** getenv(3): one string key arg → the interned `string | undefined` + * union (present: +1 string wrapped into the string arm; absent: the + * interned undefined-arm instance). BOTH source forms — `process.env.FOO` + * and `process.env[expr]` — lower here. Purely static; never throws. */ + "process.envGet": { argTypes: [STRING], result: VOID }, + /** setenv(3): (name, value) string args → void. Later envGet reads and + * spawned children observe the write, like Node (values are strings — + * the frontend fences non-string RHS). Never throws. */ + "process.envSet": { argTypes: [STRING, STRING], result: VOID }, + /** `delete process.env[NAME]` — unsetenv(3): the mutation is visible to + * every later read (process.envGet asks getenv fresh) and inherited by + * spawned children, exactly Node. Statement position only (JS's boolean + * result is constant true there). Borrows the name; never throws. */ + "process.envUnset": { argTypes: [STRING], result: VOID }, + /** The whole environment as alternating [k0, v0, k1, v1, ...] strings in + * environ order — the raw material of the process.env SNAPSHOT record + * (the frontend's interned %env.snapshot helper keyed-writes the pairs + * into a fresh `{ [k: string]: string | undefined }` record). Fresh +1 + * array; never throws. */ + "process.envPairs": { argTypes: [], result: arrayOf(STRING) }, + "process.exit": { argTypes: [F64], result: VOID }, + /** Numeric process.exitCode write (integer validation, implicit exit status). */ + "process.setExitCode": { argTypes: [F64], result: VOID }, + /** The process.exitCode write of a program that also reads the + * property: the same validation, and the code counts as assigned. */ + "process.setExitCodeTracked": { argTypes: [F64], result: VOID }, + /** The code for process.exit() with no argument, or zero when unset. */ + "process.currentExitCode": { argTypes: [], result: F64 }, + /** Whether process.exitCode reads a code rather than undefined. Never throws. */ + "process.hasExitCode": { argTypes: [], result: BOOL }, + "process.cwd": { argTypes: [], result: STRING }, + /** getpid(2) / getuid(2): zero args → f64. POSIX-only target, so both + * always answer (the checker's `getuid?` optionality covers Windows — + * `process.getuid?.()` lowers as the plain call). Never throw. */ + "process.pid": { argTypes: [], result: F64 }, + "dyn.this": { argTypes: [], result: DYN }, + "dyn.generatorThis": { argTypes: [], result: DYN }, + "process.getuid": { argTypes: [], result: F64 }, + "process.getgid": { argTypes: [], result: F64 }, + /** geteuid(2) / getegid(2) / getgroups(2) (the effective gid appended + * when the list lacks it, like Node). Windows has no such members: the + * calls throw the TypeError a missing member does (MAY THROW). */ + "process.geteuid": { argTypes: [], result: F64 }, + "process.getegid": { argTypes: [], result: F64 }, + "process.getgroups": { argTypes: [], result: arrayOf(F64) }, + /** process.ppid: the parent's pid at the read. Never throws. */ + "process.ppid": { argTypes: [], result: F64 }, + /** process.title: libuv's process title (argv[0] until set); setTitle + * writes it (truncated to the original argument area on POSIX, the + * console title on Windows). Never throw. */ + "process.title": { argTypes: [], result: STRING }, + "process.setTitle": { argTypes: [STRING], result: VOID }, + /** process.argv0: the original argv[0]. Never throws. */ + "process.argv0": { argTypes: [], result: STRING }, + /** process.release: the compatibility target's stable release object + * (name, lts, sourceUrl, headersUrl, and libUrl on Windows). +1. */ + "process.release": { argTypes: [], result: DYN }, + /** process.execPath: the compiled binary's own resolved absolute path + * (one interned string, +1 per read) — the honest answer where Node's + * is the node executable's (SEMANTICS.md divergence 12). Never throws. */ + "process.execPath": { argTypes: [], result: STRING }, + /** process.arch: the compiled binary's OWN architecture ("arm64", + * "x64") — Node's answer for its own build on the same machine. + * Interned; +1 per read. Never throws. */ + "process.arch": { argTypes: [], result: STRING }, + /** Stable native version dictionary. node/openssl identify compatibility + * targets; components absent from the native runtime are omitted. */ + "process.versions": { argTypes: [], result: DYN }, + "process.builtinId": { argTypes: [DYN, arrayOf(STRING)], result: STRING }, + "process.builtinModule": { argTypes: [STRING, DYN], result: DYN }, + "process.builtinUnsupported": { argTypes: [STRING, STRING], result: DYN }, + /** A module namespace object as a checked-dynamic value + * (scr_module_namespace_value): the module id, its sorted export names + * and the compiled getter. One object per module. Never throws. */ + "module.namespaceValue": { argTypes: [STRING, arrayOf(STRING), DYN], result: DYN }, + "fs.callbackValue": { argTypes: [STRING], result: DYN }, + "fs.callbackCall": { argTypes: [STRING, DYN], result: DYN }, + "process.hrtimeValue": { argTypes: [], result: DYN }, + /** process.versions.node: the runtime's Node COMPATIBILITY TARGET — + * there is no Node under the binary, so this reports the version whose + * semantics the runtime implements (SEMANTICS.md divergence 60, the + * execPath stance). Interned; +1 per read. Never throws. */ + "process.versionsNode": { argTypes: [], result: STRING }, + "process.versionsOpenssl": { argTypes: [], result: STRING }, + /** kill(2) with Node's exact semantics and error shapes: the pid must be + * an int32 (else the ERR_INVALID_ARG_TYPE TypeError text), the named + * form resolves Node's signal-name table (unknown names throw the + * ERR_UNKNOWN_SIGNAL TypeError), an omitted signal completes to + * "SIGTERM" in the frontend, signal 0 probes, and a kill(2) failure + * throws Node's `kill ESRCH`/`kill EPERM` Error. Result is Node's + * constant true. */ + "process.kill": { argTypes: [F64, STRING], result: BOOL }, + "process.killNum": { argTypes: [F64, F64], result: BOOL }, + /** The raw byte writes: one borrowed string arg → bool (constantly true + * — this synchronous runtime never queues backpressure). stdoutWrite + * shares console.log's stream, each call is submitted promptly, and + * interleaved output keeps source order. No newline, no formatting, + * never throws. */ + "process.stdoutWrite": { argTypes: [STRING], result: BOOL }, + "process.stdio": { argTypes: [F64], result: DYN }, + "process.stderrWrite": { argTypes: [STRING], result: BOOL }, + // error.new's result and the receiver slots are builtin-error classes — + // program-dependent object types, checked in the libCall case. + /** The runtime-provided Error hierarchy's entry points (scr_error.c). + * error.new: one borrowed string arg (the message), result an owned (+1) + * builtin error instance — the result TYPE names which builtin class + * (backends derive the runtime kind from it). error.ctor: the + * super(message) call of an `extends Error` constructor — borrowed + * receiver (already allocated by the derived class's new) + borrowed + * message, void; the receiver's type names the builtin class whose name + * field to stamp. error.toString: borrowed `%Error`-typed receiver, +1 + * string in Node's "name: message" shape. Formatting can invoke a user + * message accessor, which can throw. */ + "error.new": { argTypes: [STRING], result: VOID }, + /** ECMAScript constructors with raw checked-dynamic message/options. + * Options retain cause presence; constructor calls borrow their args. + * Message coercion may throw before the cause is installed. */ + "error.newOptions": { argTypes: [DYN, DYN], result: VOID }, + "error.ctorOptions": { argTypes: [null, DYN, DYN], result: VOID }, + /** Borrowed Error receiver. cause returns an owned dyn value (undefined + * when absent); hasCause distinguishes absence from present undefined. */ + "error.cause": { argTypes: [null], result: DYN }, + "error.hasCause": { argTypes: [null], result: BOOL }, + /** Assignment borrows both operands and retains the new cause. */ + "error.setCause": { argTypes: [null, DYN], result: VOID }, + /** `err.code = s` on an error-hierarchy receiver: the code slot that + * error.code reads and coded throws stamp. Borrows both; never throws. */ + "error.setCode": { argTypes: [null, STRING], result: VOID }, + /** `err.code = v` with a value that is not statically a string: strings + * take the code slot, anything else clears it and sets the dynamic own + * property. Borrows both; never throws. */ + "error.setCodeDyn": { argTypes: [null, DYN], result: VOID }, + /** `Object.assign(err, ...sources)` onto an error-hierarchy receiver + * (args: the error, a dyn array of the sources): the own-member copy + * onto its checked-dynamic node, then the typed slots (name, message, + * stack, cause, code) re-read from it. Throws what the copy throws. */ + "error.assign": { argTypes: [null, DYN], result: VOID }, + /** `key in err` for a key no compiled class of the receiver declares + * (args: the error, the key): a runtime-set own property (Object.assign, + * throw-site fields, dynamic writes) or an Object.prototype member. */ + "error.hasKey": { argTypes: [null, STRING], result: BOOL }, + "error.hasCode": { argTypes: [null], result: BOOL }, + /** Whether the error's own `name` or `message` (the key) is an accessor + * a reflective definition installed. Borrows both; never throws. */ + "error.ownAccessor": { argTypes: [null, STRING], result: BOOL }, + /** That accessor's getter called on the error (owned result), and its + * setter called with the value (V8's TypeError without one). Borrow + * their arguments; throw what the accessor throws. */ + "error.accessorGet": { argTypes: [null, STRING], result: DYN }, + "error.accessorSet": { argTypes: [null, STRING, DYN], result: VOID }, + "error.defineCause": { argTypes: [null, DYN], result: VOID }, + "error.deleteCause": { argTypes: [null], result: VOID }, + /** The compiler-resolved Node-parity throw for always-throwing lowered + * arms (ERR_INVALID_THIS receivers, ERR_MISSING_ARGS arity ladders, + * the symbol-to-string TypeError): args are [error-kind f64 (the + * SCR_ERR_* index: 0 Error, 1 TypeError, 2 RangeError), code (empty = + * no code slot), message]. ALWAYS THROWS catchably; the result type is + * the replaced expression's own (never materialized — the + * global.undefRead pattern). May-throw seed. */ + "error.nodeThrow": { argTypes: [F64, STRING, STRING], result: VOID }, + /** JS ToString over a dyn value WITH the object protocol (a user + * toString/valueOf member is CALLED and its throw propagates; + * exhaustion throws "Cannot convert object to primitive value"; units + * render "null"/"undefined") — the WHATWG USVString conversions + * (URLSearchParams names/values). Borrowed dyn; +1 string. May-throw. */ + "dyn.toStringCoerce": { argTypes: [DYN], result: STRING }, + "dyn.stringConstructor": { argTypes: [DYN], result: STRING }, + "dyn.propertyKey": { argTypes: [DYN], result: DYN }, + "dyn.toNumeric": { argTypes: [DYN], result: DYN }, + "dyn.increment": { argTypes: [DYN, BOOL], result: DYN }, + /** JS ToNumber over a dyn value WITH the object protocol (number-hint + * valueOf/toString ordering; user throws propagate). Borrowed dyn; + * f64 result, or a throw. Used by statically lowered numeric coercions + * whose checker type remained any. */ + "dyn.numberConstructor": { argTypes: [DYN], result: F64 }, + "dyn.bigintConstructor": { argTypes: [DYN], result: BIGINT_T }, + "dyn.toNumberCoerce": { argTypes: [DYN], result: F64 }, + "dyn.add": { argTypes: [DYN, DYN], result: DYN }, + "dyn.arithmetic": { argTypes: [DYN, DYN, STRING], result: DYN }, + "dyn.compare": { argTypes: [DYN, DYN, STRING], result: BOOL }, + "dyn.bitwise": { argTypes: [DYN, DYN, STRING], result: DYN }, + "dyn.proxyNew": { argTypes: [DYN, DYN], result: DYN }, + /* Dynamic-tier values (jsval; two-tier design stage S3). The jsval pass + * (ir/jsval.ts) introduces these in dynamic-tier functions only; the + * runtime is scr_js_value.c. Arguments are borrowed and results owned, + * like every libCall. Boundary conversions: js.fromDyn (a cell keeps its + * identity), js.toDyn (an immediate is boxed), js.fromF64/fromBool/ + * fromStr/fromBigInt (the design's toJs: immediates, and strings and + * BigInts under a tag without a copy) and js.toF64 (fromJs to number: dynCheck's + * number check and TypeError). The operators are the dyn.* operators + * over jsvals, with identical JS semantics. */ + "js.fromDyn": { argTypes: [DYN], result: JSVAL }, + "js.toDyn": { argTypes: [JSVAL], result: DYN }, + "js.fromF64": { argTypes: [F64], result: JSVAL }, + "js.fromBool": { argTypes: [BOOL], result: JSVAL }, + "js.fromStr": { argTypes: [STRING], result: JSVAL }, + "js.fromBigInt": { argTypes: [BIGINT_T], result: JSVAL }, + "js.toF64": { argTypes: [JSVAL], result: F64 }, + "js.add": { argTypes: [JSVAL, JSVAL], result: JSVAL }, + "js.arithmetic": { argTypes: [JSVAL, JSVAL, STRING], result: JSVAL }, + "js.bitwise": { argTypes: [JSVAL, JSVAL, STRING], result: JSVAL }, + "js.compare": { argTypes: [JSVAL, JSVAL, STRING], result: BOOL }, + "js.toNumeric": { argTypes: [JSVAL], result: JSVAL }, + "js.increment": { argTypes: [JSVAL, BOOL], result: JSVAL }, + "js.toNumberCoerce": { argTypes: [JSVAL], result: F64 }, + // Always throws; the result is the READ's declared type (a typed dummy + // the unwind abandons) — the libCall case skips the result check. + /** A read of a `declare`d const NOTHING defines (the bundler-define + * pattern — __VERSION__): always throws the catchable ReferenceError + * Node raises at the access (" is not defined"). args[0] is the + * name; the result type is the read's declared type (a typed dummy the + * unwind abandons — the value never exists). */ + "global.undefRead": { argTypes: [STRING], result: VOID }, + "console.native": { argTypes: [], result: DYN }, + /** node:console Console instances (scr_console_native.c): new mints the + * handle over the stdout/stderr fds (1/2; 0 = a stream binds next) and + * the ignoreErrors flag; bind attaches a borrowed writable stream to + * target 0 (stdout) or 1 (stderr); write prints `text\n` to the + * selected target of an instance or the global console handle. */ + "console.new": { argTypes: [F64, F64, BOOL], result: DYN }, + "console.bind": { argTypes: [DYN, F64, null], result: VOID }, + "console.write": { argTypes: [DYN, STRING, BOOL], result: VOID }, + /** The global console's remaining members (scr_console_native.c; the + * group indentation itself lives with the writers in scr_console.c). + * Arguments are borrowed; string results are owned. noop is the + * emitter-dropped tail of a lowering whose effects sit in statements. + * label is `${label}` over a defaulted label (undefined -> "default"; + * a Symbol throws Node's TypeError). count prints "label: n". + * countReset answers the warning text for an unknown (or non-string) + * label, "" otherwise. time answers the duplicate-label warning text + * or ""; timeEnd/timeLog answer Node's formatted elapsed time, or "" + * for an unknown label (timeEnd drops the timer). group adds (+1) or + * removes (-1) one two-space indentation step. clear writes the + * cursor-home and erase-down sequences when stdout is a terminal. + * table renders and prints Node's table for a dyn value (undefined + * properties = all). dirDyn is console.dir's inspect of a dyn value + * (custom inspection off: a Buffer anywhere inside throws the fence). */ + "console.noop": { argTypes: [], result: VOID }, + "console.label": { argTypes: [DYN], result: STRING }, + "console.count": { argTypes: [STRING], result: VOID }, + "console.countReset": { argTypes: [DYN], result: STRING }, + "console.time": { argTypes: [STRING], result: STRING }, + "console.timeEnd": { argTypes: [STRING], result: STRING }, + "console.timeLog": { argTypes: [STRING], result: STRING }, + "console.group": { argTypes: [F64], result: VOID }, + "console.clear": { argTypes: [], result: VOID }, + "console.table": { argTypes: [DYN, DYN], result: VOID }, + "console.dirDyn": { argTypes: [DYN, F64], result: STRING }, + /** A native reference to the global object; known names retain value fences. */ + "global.native": { argTypes: [arrayOf(STRING)], result: DYN }, + // `X.name` through a class value: the arg is a program-dependent + // classval (a null slot; the libCall case checks the kind). + /** `X.name` through a class VALUE (scr_object.c): args[0] is a borrowed + * classval; the result is the class object's stored .name string, + * retained (+1 — the string is an interned immortal, so the retain is a + * no-op, kept for ownership uniformity). Never throws. A direct + * `C.name` on the class name itself folds to a strLit instead. */ + "class.name": { argTypes: [null], result: STRING }, + "error.ctor": { argTypes: [null, STRING], result: VOID }, + "error.toString": { argTypes: [null], result: STRING }, + /** SameValue over checked values, including NaN, signed zero and reference identity. */ + "dyn.sameValue": { argTypes: [DYN, DYN], result: BOOL }, + "error.stack": { argTypes: [null], result: STRING }, + "error.setStack": { argTypes: [null, STRING], result: VOID }, + "error.stackLimitGet": { argTypes: [], result: F64 }, + "error.stackLimitSet": { argTypes: [F64], result: VOID }, + // Receiver (any error-hierarchy object) and the program-dependent + // `string | undefined` result are checked in the libCall case. + /** NodeJS.ErrnoException's `.code` read: borrowed error-hierarchy + * receiver → the interned `string | undefined` union (type-directed + * construction in the backend, the process.envGet pattern) — the errno + * name where a throw site stamped one (fs, exec spawn/timeout, + * process.kill, the spawn 'error' event), the undefined arm everywhere + * else. Never throws. */ + "error.code": { argTypes: [null], result: VOID }, + // DOMException: construction takes the two dyn args (WebIDL's + // resolution runs in the runtime); the %DOMException result is a + // program-dependent object type, checked in the libCall case. The + // read surface takes the %DOMException receiver (a null slot — the + // libCall case checks the class name). + /** `new DOMException(message?, nameOrOptions?)` (scr_error.c): both args + * are borrowed dyn values (the lowering passes the dyn undefined for an + * absent argument, so WebIDL's optionality lives in one place). The + * runtime ToStrings the message ("" for absent/undefined), resolves the + * name — absent/undefined → "Error", a non-null object → ToString of its + * `name` member plus the `cause` own-property record, anything else → + * ToString — and stamps the legacy code from the WebIDL name table (0 + * off-table). Result is an owned (+1) %DOMException. Never throws (dyn + * ToString is total). */ + "error.newDom": { argTypes: [DYN, DYN], result: VOID }, + /** DOMException's own read surface (scr_error.c; %DOMException receivers + * only — borrowed). domCode: the legacy numeric code. domHasCause: the + * options form's own-property record (`'cause' in e`). domCause: the + * cause value, +1 (the dyn undefined when absent — matching Node's + * undefined read). None throws. */ + "error.domCode": { argTypes: [null], result: F64 }, + "error.domHasCause": { argTypes: [null], result: BOOL }, + "error.domCause": { argTypes: [null], result: DYN }, + /** structuredClone of a %DOMException receiver (scr_error.c): WebIDL + * serialization — name/message copy, the legacy code re-derives, cause + * does not serialize. args are the borrowed receiver and the borrowed + * options dyn value (the dyn undefined when absent — the shared + * validation throws Node's exact option errors; any non-empty transfer + * list throws DataCloneError, nothing static is transferable). Result + * +1 %DOMException. */ + "error.domClone": { argTypes: [null, DYN], result: VOID }, + /** `new AggregateError(errors, message?, options?)` (scr_json.c), in + * spec order: newAggregate installs the message and cause (both dyn, + * borrowed — the message conversion can throw) and returns an owned + * %AggregateError; aggregateSetErrors then stores the iterated list + * (borrowed receiver, the dyn array borrowed and retained). + * aggregateErrors reads the list (+1, the same array every read). */ + "error.newAggregate": { + argTypes: [DYN, DYN], + result: { kind: "object", className: "%AggregateError" }, + }, + "error.aggregateSetErrors": { argTypes: [null, DYN], result: VOID }, + "error.aggregateErrors": { argTypes: [null], result: DYN }, + /** `new SuppressedError(error, suppressed, message?)` (scr_json.c): all + * three dyn and borrowed; the message conversion can throw. Returns an + * owned %SuppressedError. */ + "error.newSuppressed": { + argTypes: [DYN, DYN, DYN], + result: { kind: "object", className: "%SuppressedError" }, + }, + /** `d instanceof TypeError` (and the other BUILTIN error classes) on a + * checked-dynamic value (scr_json.c): the from_error cache holds the + * dyn↔error identity edge, so the test resolves the runtime error and + * asks its vtable's stamped preorder interval — exact for every error + * that crossed the boundary. A dyn object that never came from an + * error (a hand-built {%error} literal) answers false: subclass + * identity is unknowable there (the root keeps dynTest's marker + * answer). args are the borrowed dyn and the SCR_ERR_* kind literal. + * Never throws. */ + "dyn.errInstanceof": { argTypes: [DYN, F64], result: BOOL }, + "weakMap.is": { argTypes: [DYN], result: BOOL }, + "weakSet.is": { argTypes: [DYN], result: BOOL }, + "weakMap.new": { argTypes: [DYN], result: DYN }, + "weakSet.new": { argTypes: [DYN], result: DYN }, + "finalizationRegistry.new": { argTypes: [DYN], result: DYN }, + "finalizationRegistry.is": { argTypes: [DYN], result: BOOL }, + "dyn.fromEntries": { argTypes: [DYN], result: DYN }, + "bytes.constructor": { argTypes: [STRING], result: DYN }, + "bytes.instanceOf": { argTypes: [DYN, DYN, STRING], result: BOOL }, + "bytes.construct": { argTypes: [DYN, DYN, STRING], result: DYN }, + /** The ambient receiver — JS `this` in a plain (non-method) function + * body: the innermost binding the current firing/dispatch window + * pushed (Node's listener receiver, a dyn OBJ method's object, an + * apply/call thisArg), or the undefined dyn singleton with none bound + * (the strict-mode plain-call answer, the old constant). Zero args → + * dyn (+1). Never throws. */ + "dyn.dataViewIs": { argTypes: [DYN], result: BOOL }, + "dyn.construct": { argTypes: [DYN, DYN, STRING], result: DYN }, + "arrayBuffer.constructor": { argTypes: [], result: DYN }, + "sharedArrayBuffer.new": { argTypes: [DYN], result: DYN }, + "sharedArrayBuffer.is": { argTypes: [DYN], result: BOOL }, + "arrayBuffer.new": { argTypes: [DYN], result: DYN }, + "ffi.argument": { argTypes: [DYN, STRING], result: DYN }, + "ffi.memoryModule": { argTypes: [DYN], result: DYN }, + "intl.segmenterNew": { argTypes: [], result: DYN }, + "intl.segmenterRefusing": { argTypes: [STRING], result: DYN }, + "arrayBuffer.is": { argTypes: [DYN], result: BOOL }, + "arrayBuffer.isView": { argTypes: [DYN], result: BOOL }, + "arrayBuffer.byteLengthGetter": { argTypes: [], result: F64 }, + "arrayBuffer.byteLengthDescriptor": { argTypes: [DYN], result: DYN }, + "arrayBuffer.viewU8C": { argTypes: [DYN, DYN, DYN], result: bytesOf("u8c") }, + "arrayBuffer.viewI8": { argTypes: [DYN, DYN, DYN], result: bytesOf("i8") }, + "arrayBuffer.viewU16": { argTypes: [DYN, DYN, DYN], result: bytesOf("u16") }, + "arrayBuffer.viewI16": { argTypes: [DYN, DYN, DYN], result: bytesOf("i16") }, + "arrayBuffer.viewU8": { argTypes: [DYN, DYN, DYN], result: BYTES_U8 }, + "arrayBuffer.viewU32": { argTypes: [DYN, DYN, DYN], result: bytesOf("u32") }, + "arrayBuffer.viewI32": { argTypes: [DYN, DYN, DYN], result: bytesOf("i32") }, + "arrayBuffer.viewF16": { argTypes: [DYN, DYN, DYN], result: bytesOf("f16") }, + "arrayBuffer.viewF32": { argTypes: [DYN, DYN, DYN], result: bytesOf("f32") }, + "arrayBuffer.viewF64": { argTypes: [DYN, DYN, DYN], result: bytesOf("f64") }, + "arrayBuffer.viewDV": { argTypes: [DYN, DYN, DYN], result: BYTES_U8 }, + /** Object.keys/values/entries over a CHECKED-DYNAMIC receiver + * (scr_json.c): the runtime walks the dyn node's own members in JS + * own-key order (array-index keys ascending first, then insertion + * order) and answers a dyn array (entries: an array of [key, value] + * pairs; values RETAIN the member nodes — reference semantics, like + * JS). Strings/arrays/bytes answer their index keys; other scalars an + * empty array; null/undefined throw Node's catchable TypeError + * ("Cannot convert undefined or null to object"). */ + "dyn.objKeys": { argTypes: [DYN], result: DYN }, + "dyn.forInKeys": { argTypes: [DYN], result: DYN }, + "dyn.forInKeyStrings": { argTypes: [DYN], result: arrayOf(STRING) }, + "dyn.forInStable": { argTypes: [DYN], result: BOOL }, + "dyn.objKeyStrings": { argTypes: [DYN], result: arrayOf(STRING) }, + /** Object.entries as a native [string, any][] (VOID: the tuple row's + * shape is program-dependent; the validator checks it). */ + "dyn.objEntryPairs": { argTypes: [DYN], result: VOID }, + "dyn.hasOwn": { argTypes: [DYN, STRING], result: BOOL }, + "dyn.propertyIsEnumerable": { argTypes: [DYN, STRING], result: BOOL }, + "dyn.assign": { argTypes: [DYN, DYN], result: DYN }, + "dyn.copyDataProperties": { argTypes: [DYN, DYN], result: DYN }, + "dyn.objectRest": { argTypes: [DYN, DYN], result: DYN }, + /** Variadic Object.assign over CHECKED-DYNAMIC targets (`Object.assign( + * {}, ...arr.map(f), tail)` — the option-table merge): the lowering + * builds one fresh dyn pack of sources (packPush retains a plain source + * in; packPushSpread flattens a spread source through the spread-call + * walk — V8's exact TypeError texts, the string arg spelling the spread + * expression for the nullish form), so every source evaluates and + * flattens BEFORE any copying (JS's ArgumentListEvaluation), then + * assignAll copies each pack element's own enumerable keys onto the + * target left to right and answers the TARGET (+1) — identity, like JS. + * assignAll throws Node's ToObject TypeError on a nullish target. */ + "dyn.packPush": { argTypes: [DYN, DYN], result: VOID }, + "dyn.packPushSpread": { argTypes: [DYN, DYN, STRING], result: VOID }, + /** The iterated-path spread twin: V8 spells the optimized apply-path + * texts (packPushSpread's — the expression named for nullish sources) + * only for the SINGLE LAST argument's spread; any other spread position + * drives the real iterator protocol, whose failure describes the VALUE + * ("object null is not iterable (cannot read property + * Symbol(Symbol.iterator))"). The frontend picks by position. */ + "dyn.packPushSpreadIter": { argTypes: [DYN, DYN], result: VOID }, + "dyn.reflectApply": { argTypes: [DYN, DYN, DYN], result: DYN }, + "dyn.reflectGet": { argTypes: [DYN, DYN, DYN], result: DYN }, + /** `using` / `await using` with a dyn value (scr_json.c): usingMethod + * runs the declaration's checks and answers what usingDispose calls at + * scope exit (undefined for a null or undefined value). The bool selects + * `await using`. Both throw Node's TypeErrors or the method's error. */ + "dyn.usingMethod": { argTypes: [DYN, BOOL], result: DYN }, + "dyn.usingDispose": { argTypes: [DYN, DYN], result: DYN }, + /** DisposableStack (scr_symbol.c): a new stack handle; whether a value is + * one; and `stack.use(value)` for a class instance, registering the + * compiler's disposal function for it. The last throws Node's + * ReferenceError on a disposed stack. */ + "disposable.stackNew": { argTypes: [], result: DYN }, + "disposable.stackIs": { argTypes: [DYN], result: BOOL }, + "disposable.stackUseCallback": { argTypes: [DYN, DYN, DYN], result: BOOL }, + "dyn.reflectSet": { argTypes: [DYN, DYN, DYN, DYN], result: BOOL }, + "dyn.reflectDefine": { argTypes: [DYN, DYN, DYN], result: BOOL }, + "dyn.abstractEq": { argTypes: [DYN, DYN], result: BOOL }, + "dyn.assignAll": { argTypes: [DYN, DYN], result: DYN }, - "dyn.objCreateNullProto": { argTypes: [], result: DYN }, - "dyn.arrayPrototype": { argTypes: [], result: DYN }, - "dyn.arrayConstructor": { argTypes: [], result: DYN }, - "dyn.objectPrototype": { argTypes: [], result: DYN }, - "dyn.errorPrototype": { argTypes: [], result: DYN }, - "dyn.inheritsErrorPrototype": { argTypes: [DYN], result: BOOL }, - "dyn.errorCaptureStackTrace": { argTypes: [DYN], result: DYN }, - "dyn.errorCaptureStackTraceFunction": { argTypes: [], result: DYN }, - "dyn.functionApply": { argTypes: [], result: DYN }, - "dyn.builtinMethod": { argTypes: [STRING, STRING], result: DYN }, - "dyn.classPrototype": { argTypes: [DYN, DYN], result: DYN }, - "dyn.classBasePrototype": { argTypes: [DYN], result: DYN }, - "dyn.classInherit": { argTypes: [DYN, DYN], result: DYN }, - /** EventEmitter (0), Stream (1), Readable (2), Writable (3), Duplex (4), - * Transform (5) and PassThrough (6) as untyped constructor values, one - * per thread (scr_dyn_builtin_class.c). */ - "dyn.builtinClass": { argTypes: [F64], result: DYN }, - /** The stream classes (2-6 above) with their stream half: constructor - * functions over them get native stream state - * (scr_dyn_builtin_stream.c). */ - "dyn.builtinStreamClass": { argTypes: [F64], result: DYN }, - /** `value instanceof C` for those constructors, over the value's - * prototype chain. */ - "dyn.builtinInstanceOf": { argTypes: [DYN, F64], result: BOOL }, - /** `value instanceof f` for an untyped constructor function: the - * prototype chain against f.prototype. */ - "dyn.functionInstanceOf": { argTypes: [DYN, DYN], result: BOOL }, - "dyn.classSuper": { argTypes: [DYN, DYN, DYN], result: VOID }, - "dyn.assignPrototype": { argTypes: [DYN, DYN, DYN], result: DYN }, - "dyn.definePrototypeProps": { argTypes: [DYN, DYN, DYN], result: DYN }, - "dyn.bagGet": { argTypes: [DYN, STRING, DYN], result: DYN }, - /** A class field's creation in its instance's property bag: adds the - * string key as a default data property when absent, answering false - * (nothing changed) when the bag needs the general defineProperty path. */ - "dyn.bagCreateField": { argTypes: [DYN, STRING], result: BOOL }, - "dyn.bagSet": { argTypes: [DYN, STRING, DYN, DYN], result: VOID }, - "dyn.objCreate": { argTypes: [DYN], result: DYN }, - // Names a compiled class's prototype object (args[0]) after the class - // (args[1]) for util.inspect. - "dyn.nameClassPrototype": { argTypes: [DYN, STRING], result: VOID }, - "dyn.objCreateWithProperties": { argTypes: [DYN, DYN], result: DYN }, - "dyn.getPrototype": { argTypes: [DYN], result: DYN }, - // dyn.getPrototype for walks that compare each prototype with a program - // class's prototype: native builtin values end the walk (null). - "dyn.getPrototypeForIdentity": { argTypes: [DYN], result: DYN }, - "dyn.setPrototype": { argTypes: [DYN, DYN], result: DYN }, - "dyn.getOwnPropertyNames": { argTypes: [DYN], result: DYN }, - "dyn.ownKeys": { argTypes: [DYN], result: DYN }, - "dyn.getOwnPropertySymbols": { argTypes: [DYN], result: DYN }, - "dyn.getOwnPropertyDescriptors": { argTypes: [DYN], result: DYN }, - "dyn.preventExtensions": { argTypes: [DYN], result: DYN }, - "dyn.isExtensible": { argTypes: [DYN], result: BOOL }, - "dyn.seal": { argTypes: [DYN], result: DYN }, - "dyn.isSealed": { argTypes: [DYN], result: BOOL }, - "dyn.objValues": { argTypes: [DYN], result: DYN }, - /** Object.values as a native vector of checked values, for results the - * program consumes directly (for-of, index reads, read-only methods). */ - "dyn.objValueList": { argTypes: [DYN], result: arrayOf(DYN) }, - "dyn.objEntries": { argTypes: [DYN], result: DYN }, - /** structuredClone over the checked-dynamic tree (scr_json.c): the JSON-safe subset plus - * bytes (a fresh copy — a Buffer clones as a plain Uint8Array, like - * Node), deep. Functions and handle kinds throw the spec's catchable - * DataCloneError; CYCLES throw the scriptc fence (the checked-dynamic tree cannot - * represent them — Node clones cycles; documented divergence). The - * options dyn value validates with Node's exact errors (dictionary - * conversion, the transfer-sequence member; any non-empty transfer - * list throws DataCloneError). dyn.cloneMissing is the zero-argument - * call: always throws Node's TypeError [ERR_MISSING_ARGS] with Node's - * own (verbatim, doubly-wrapped) message. */ - "dyn.structuredClone": { argTypes: [DYN, DYN], result: DYN }, - /** The declaration-typed boundary's adoption (decl-projection.ts): - * `source` is the dynamic value a boundary cast just converted, and - * `capsule` a live capsule of the native value built from it. Every - * object or array of `source` that something else still references - * becomes, in place, a live capsule of the native value built from it. - * Throws the path TypeError, changing nothing, when a converted object - * is not plain data (a prototype, accessors, symbols, frozen state). */ - "dyn.declAdopt": { argTypes: [DYN, DYN], result: VOID }, - "dyn.cloneMissing": { argTypes: [], result: DYN }, - /** structuredClone with a NON-EMPTY transfer array of static values: - * nothing static is transferable, so the call always throws Node's - * catchable DataCloneError ("Found invalid value in transferList.") — - * lowered directly (the list's values need no dyn representation to - * fail). */ - "dyn.cloneTransferFail": { argTypes: [], result: DYN }, - /** The same refusal given the transfer list's first member, an - * ArrayBuffer: a Buffer pool slab gets Node's untransferable message. */ - "dyn.cloneTransferFailWith": { argTypes: [DYN], result: DYN }, - /** `new RegExp(pattern, flags?)` (scr_regex.c): a heap regex over the - * same libregexp engine the literals use. The pattern compiles EAGERLY - * so an invalid pattern (or an unknown flag letter) throws Node's - * catchable SyntaxError at construction — Node's message shape with - * libregexp's detail text (approximate fidelity; e.name exact). An - * empty pattern stores the spec's "(?:)" source. Both args borrowed - * strings (the lowering completes an absent flags to ""); result +1. - * The result TYPE is the regex kind, so the link switch pulls the - * engine exactly like a literal. */ - "regex.new": { argTypes: [STRING, STRING], result: REGEX }, - "regex.resetLastIndex": { argTypes: [REGEX, F64], result: VOID }, - "regex.newChecked": { argTypes: [DYN, DYN], result: REGEX }, - "regex.replaceCallback": { argTypes: [STRING, REGEX, DYN, BOOL], result: STRING }, - // Reads of capture args[1] of an execSpans/matchGroups result: - // `capture === args[2]`, Number(capture) and parseInt(capture, - // args[2]). Borrowed; never throw. - "regex.groupEquals": { argTypes: [arrayOf(STRING), F64, STRING], result: BOOL }, - "regex.groupNumber": { argTypes: [arrayOf(STRING), F64], result: F64 }, - "regex.groupParseInt": { argTypes: [arrayOf(STRING), F64, F64], result: F64 }, - // `.index` / `.input` (args[1]) of a match result. Borrowed; never throws. - "regex.resultProp": { argTypes: [arrayOf(STRING), STRING], result: DYN }, - // The string keys `for...in` visits on an array (args[0], any element - // type) after its indices. Borrowed; never throws. - "array.namedKeys": { argTypes: [null], result: arrayOf(STRING) }, - // Whether the array (args[0]) still has the key (args[1]) from its - // namedKeys list. Borrowed; never throws. - "array.hasNamedKey": { argTypes: [null, STRING], result: BOOL }, - // Whether an array (args[0], any element type) has properties besides its - // elements: noncanonical numeric keys, match metadata or named - // properties. Borrowed; never throws. - "array.hasProperties": { argTypes: [null], result: BOOL }, - // The key of an element access whose index is undefined (the property - // named "undefined"; frontend/lowering/undefined-index.ts). - "array.undefinedKey": { argTypes: [], result: F64 }, - // node:events EventEmitter: receivers are emitter-hierarchy objects and - // the chaining forms (on/off/removeAll/setMax) return the receiver's - // own class — program-dependent object types, checked in the libCall - // case. emitter.emit is the one VARIADIC libCall: args beyond - // (recv, name) are the event's frontend-unified tuple, any borrowable - // kind — the count check admits a longer list for it alone. - /** node:events EventEmitter (scr_events_emitter.c, link-gated by - * moduleUsesEmitter). The receiver of every instance form is a borrowed - * emitter-hierarchy object (`%EventEmitter` or a user subclass — the - * backend reinterprets to ScrEmitter*, the identical prefix); event - * names are borrowed strings (compile-time literals — the frontend - * fences non-literals and unifies each event's argument tuple program- - * wide). The chaining forms (on/off/removeAll/setMax) return the - * receiver +1 typed as its static class, Node's `return this`. - * - * emitter.new: `new EventEmitter()` → a +1 bare emitter. emitter.ctor: - * super() into the prefix of an emitted subclass (borrowed receiver, - * void — allocation already initialized the prefix). emitter.on: - * (recv, name, cb /moves/, once, prepend) — the backend synthesizes the - * per-signature va_list invoke adapter from the cb's func type. - * emitter.emit: (recv, name, ...tuple) — VARIADIC, the one libCall - * whose arg count exceeds its signature; args are borrowed, result is - * the had-listeners bool. emitter.emitError: emit('error', err) — - * throws err when unhandled. count/countFn/names/listeners/getMax/ - * setMax/setDefaultMax/getDefaultMax are the introspection surface. */ - "emitter.new": { argTypes: [], result: VOID }, - /** `x.constructor.name` of an emitter or stream (a borrowed object of - * EventEmitter's hierarchy): the +1 class name the instance records. */ - "emitter.className": { argTypes: [null], result: STRING }, - "emitter.ctor": { argTypes: [null], result: VOID }, - "emitter.on": { argTypes: [null, STRING, null, BOOL, BOOL], result: VOID }, - "emitter.off": { argTypes: [null, STRING, null], result: VOID }, - // The dyn-adapted registration family (JS-lane checked-dynamic - // listeners): checkListener has NO receiver (it validates the listener - // argument alone); onDyn carries (recv, name, cb dyn, adapter func, - // once, prepend), offDyn (recv, name, cb dyn). - "emitter.checkListener": { argTypes: [DYN], result: VOID }, - "emitter.onDyn": { argTypes: [null, STRING, DYN, null, BOOL, BOOL], result: VOID }, - "emitter.onFlex": { argTypes: [null, STRING, DYN, BOOL, BOOL], result: VOID }, - /** on/once/prepend* and emit through an untyped value (the class - * dispatch of compiled emitters): onFlex/emitFlex plus runtime typed - * adapters under 'error' and the meta events, and Node's unhandled-'error' - * contract. emitAny is VARIADIC like emitFlex. */ - "emitter.onAny": { argTypes: [null, STRING, DYN, BOOL, BOOL], result: VOID }, - "emitter.offDyn": { argTypes: [null, STRING, DYN], result: VOID }, - "emitter.removeAll": { argTypes: [null, STRING, BOOL], result: VOID }, - "emitter.emit": { argTypes: [null, STRING], result: BOOL }, - "emitter.emitFlex": { argTypes: [null, STRING], result: BOOL }, - "emitter.emitAny": { argTypes: [null, STRING], result: BOOL }, - /** An untyped emit of an event with a fixed tuple: (recv, name, k, then - * k checked-dynamic arguments as given, then the event's converted - * tuple) — VARIADIC like emitter.emit. hasTyped answers whether a - * listener of the name needs the converted tuple. */ - "emitter.emitMixed": { argTypes: [null, STRING, F64], result: BOOL }, - "emitter.hasTyped": { argTypes: [null, STRING], result: BOOL }, - "emitter.emitError": { argTypes: [null, STRING, null], result: BOOL }, - "emitter.count": { argTypes: [null, STRING], result: F64 }, - "emitter.countFn": { argTypes: [null, STRING, null], result: F64 }, - "emitter.countDyn": { argTypes: [null, STRING, DYN], result: F64 }, - "emitter.names": { argTypes: [null], result: VOID }, - "emitter.listeners": { argTypes: [null, STRING], result: VOID }, - /** listeners()/rawListeners() through an untyped value: a checked- - * dynamic array (throws when a listener has typed parameters). */ - "emitter.listenersDyn": { argTypes: [null, STRING], result: DYN }, - /** Stream-'data' registration twins of emitter.on/onDyn (same args): - * chosen at registration sites whose receiver is stream-rooted, so the - * backend emits DATA thunks — the runtime's 'data' emission carries - * BOTH payload slots (bytes, string; exactly one non-NULL — encoded - * streams deliver strings), and the thunk unwraps the listener's - * declared side (typed) or boxes by tag (dyn). emitter.emitData is the - * user-emit form: (recv, name, chunk) with a bytes OR string chunk. */ - "emitter.onData": { argTypes: [null, STRING, null, BOOL, BOOL], result: VOID }, - "emitter.onDataDyn": { argTypes: [null, STRING, DYN, null, BOOL, BOOL], result: VOID }, - "emitter.emitData": { argTypes: [null, STRING, null], result: BOOL }, - "emitter.setMax": { argTypes: [null, F64], result: VOID }, - "emitter.getMax": { argTypes: [null], result: F64 }, - "emitter.setDefaultMax": { argTypes: [F64], result: VOID }, - "emitter.getDefaultMax": { argTypes: [], result: F64 }, - // The ES module namespace's copy of defaultMaxListeners, and - // module.syncBuiltinESMExports() refreshing it. - "emitter.esmDefaultMax": { argTypes: [], result: F64 }, - "emitter.esmSync": { argTypes: [], result: VOID }, - /** The events.errorMonitor event key: an immortal string the runtime - * registry matches by identity, so no string event name reaches it. */ - "emitter.errorMonitor": { argTypes: [], result: STRING }, - // node:stream: receivers are stream-hierarchy objects and several - // results are program-dependent (the receiver's class, unions) — the - // libCall case owns those checks. The constructors and a few methods - // are VARIADIC (trailing option callbacks / the optional chunk+cb tail): - // argTypes here is the fixed prefix, VARIADIC_LIB_FNS admits the rest. - /** node:stream (scr_stream.c, link-gated by moduleUsesStream — which - * implies the emitter unit: stream events dispatch through the embedded - * ScrEmitter registry). Receivers are borrowed stream-class objects - * (`%Readable`/`%Writable`/`%Duplex`/`%Transform`/`%PassThrough` — one - * runtime layout, reinterpreted by side). - * - * Constructors (`readable.new` et al): args are [hwmR, hwmW, flags] - * followed by the PRESENT user callbacks in canonical order (read, - * write, final, destroy, transform, flush — the flags f64 is a bitmask - * naming which follow; absent ones emit NULL). Every callback closure - * MOVES and carries a leading `this` param (the stream), invoked - * through compiler-emitted adapters. Results are +1. - * - * readable.push / readable.pushStr / readable.pushNull: Node's push — - * buffers or delivers (bytes chunk borrowed; string converted utf8); - * returns the below-hwm answer. readable.read: (recv, size — -1 for - * absent) → Buffer|null union. pause/resume return recv +1 (`this`); - * isPaused answers the flag. readable.pipe: (recv, dst, end) → dst +1, - * fires 'pipe' on dst; readable.pipeGeneral: the same, with `end` off - * when dst is the converted process.stdout / process.stderr; - * readable.unpipe (recv[, dst]) → recv +1. - * writable.write/writeStr: (recv, chunk[, cb]) → below-hwm bool (cb - * MOVES when present, called after the user write completes). - * writable.writeEnc: (recv, flags, chunk[, encoding][, cb]) — flags 1 - * an encoding argument, 2 a callback (the encoding is then null, as - * Node's write shifts it). - * writable.end: (recv, flags[, chunk][, encoding][, cb]) → recv +1; - * flags 16: an encoding argument follows the dyn chunk. cork/uncork are - * void. stream.destroy/destroyErr: (recv[, err]) → recv +1. - * stream.prop: (recv, name-literal) → the flag/number the name asks - * for; stream.errored → Error|null union; readable.flowing → - * bool|null union. All may leave a listener's exception pending - * (dispatch runs user code synchronously, like emit). */ - "readable.new": { argTypes: [F64, BOOL, BOOL, F64], result: VOID }, - "writable.new": { argTypes: [F64, BOOL, BOOL, F64], result: VOID }, - "duplex.new": { argTypes: [F64, F64, BOOL, BOOL, BOOL, BOOL, BOOL, F64], result: VOID }, - "transform.new": { argTypes: [F64, F64, BOOL, BOOL, BOOL, BOOL, BOOL, F64], result: VOID }, - "passthrough.new": { argTypes: [F64, F64, BOOL, BOOL, BOOL, BOOL, BOOL, F64], result: VOID }, - // The subclass-initialization twins: the borrowed receiver leads, then - // the .new tail (variadic callbacks likewise). - // The dyn-options twins: newDyn takes the record, initDyn the borrowed - // receiver + record + fallback flags (trailing wrapper closures ride - // the variadic tail like the static forms). - /** The underscore-method assignment surface (`r._read = fn` after - * construction — Node's own-property shadow of the prototype method): - * args [stream receiver (borrowed), callback closure (+1 moves)]. The - * runtime slot the matching option callback fills swaps its closure - * and invoke thunk; the next dispatch uses it (Node's timing). The - * setters themselves never throw. */ - "stream.setRead": { argTypes: [null, null], result: VOID }, - "stream.setWrite": { argTypes: [null, null], result: VOID }, - "stream.setFinal": { argTypes: [null, null], result: VOID }, - "stream.setDestroy": { argTypes: [null, null], result: VOID }, - "stream.setTransform": { argTypes: [null, null], result: VOID }, - "stream.setFlush": { argTypes: [null, null], result: VOID }, - "stream.setConstruct": { argTypes: [null, null], result: VOID }, - "stream.replaceConstruct": { argTypes: [null, null], result: VOID }, - "stream.setWritev": { argTypes: [null, null], result: VOID }, - "stream.setWritevDefault": { argTypes: [null, null], result: VOID }, - /** The dyn-options twins (a checked-dynamic options record — the JS - * lane's `super(options)` forwarding and `new Readable(dynVar)`): the - * option walk runs at RUNTIME with Node's reading rules. newDyn: - * (optsDyn) → the fresh stream; initDyn: (recv, optsDyn, flags, - * ...fallback wrapper closures in canonical order — the flags literal - * names which ride, exactly the .init callback ABI). MAY THROW (a - * consumed-but-unlowered option is the compile fence's runtime twin). */ - /** stream.finished(s, cb) — the callback form: the watcher fires once - * at the terminal point with the finish status; the result is the +1 - * cleanup closure. stream.pipeline(count, s1..sn, cb): chains pipes, - * propagates the first error by destroying the rest, calls cb after the - * last 'close'; answers the destination +1. The Dyn twins take the - * callback as a checked-dynamic VALUE (mustCall wrappers). */ - /** stream.addAbortSignal: [stream, signal] — the constructors' signal - * option, chained over the fresh stream (falsy signals are ignored); - * stream.addAbortSignalFn: [signal, stream] — addAbortSignal(signal, - * stream). Both answer the stream (+1) and throw ERR_INVALID_ARG_TYPE - * for a value that is not an AbortSignal; they link the event-target - * unit (addAbortListener). */ - "stream.addAbortSignal": { argTypes: [null, DYN], result: VOID }, - "stream.addAbortSignalFn": { argTypes: [DYN, null], result: VOID }, - "stream.finished": { argTypes: [null, null], result: VOID }, - "stream.finishedDyn": { argTypes: [null, DYN], result: VOID }, - "stream.pipeline": { argTypes: [F64], result: VOID }, - "stream.pipelineDyn": { argTypes: [F64], result: VOID }, - "stream.pipelineStages": { argTypes: [F64, F64, F64, F64, F64], result: VOID }, - "stream.composeStages": { argTypes: [F64, F64, F64, F64, F64], result: VOID }, - "stream.pipelineStagesDyn": { argTypes: [F64, F64, F64, F64, F64], result: VOID }, - /** stream.compose(count, s1..sn): the Duplex over a pipeline of the - * streams (+1). MAY THROW (ERR_INVALID_ARG_VALUE for a stream that is - * no longer readable or writable). */ - "stream.compose": { argTypes: [F64], result: VOID }, - /** node:stream/promises — the promise forms over the same machinery: - * sp.finished: (s) → a pending void promise the terminal watcher - * settles; sp.pipeline: (count, s1..sn) → the callback pipeline's - * chaining/destroyer semantics settling a void promise (fulfilled on a - * clean finish, rejected with the finish status otherwise). */ - "sp.finished": { argTypes: [null], result: { kind: "promise", inner: VOID } }, - /** The options forms: finished(s, { readable, writable, error, cleanup, - * signal }) as [s, readable, writable, error, cleanup, signal?] — - * readable/writable -1 (absent), 0 or 1 — and pipeline(...streams, - * { signal, end }) as [count, s1..sn, end, signal?]. The Signal forms - * link the event-target unit (addAbortListener). The callback form - * stream.finishedOpts: [s, readable, writable, error, signal?, cb] → - * the cleanup closure. */ - "sp.finishedOpts": { - argTypes: [null, F64, F64, BOOL, BOOL], - result: { kind: "promise", inner: VOID }, - }, - "sp.finishedOptsSignal": { - argTypes: [null, F64, F64, BOOL, BOOL, DYN], - result: { kind: "promise", inner: VOID }, - }, - "sp.pipelineOpts": { argTypes: [F64], result: { kind: "promise", inner: VOID } }, - "sp.pipelineOptsSignal": { argTypes: [F64], result: { kind: "promise", inner: VOID } }, - "stream.finishedOpts": { argTypes: [null, F64, F64, BOOL, null], result: VOID }, - "stream.finishedOptsSignal": { argTypes: [null, F64, F64, BOOL, DYN, null], result: VOID }, - "sp.pipeline": { argTypes: [F64], result: { kind: "promise", inner: VOID } }, - /** pipeline with function stages: [n, k, positions, flags, mask, - * s1..sn, stage1..stagek, helpers..., box?, (signal, abort)?] (+ the - * callback for the stream.* forms): the user's stage functions at the - * positions the bitmask names, the frontend's (next, read, return) - * helpers for each pumped generator (pipelinePumpedRuns) and a promise - * destination's box, and the pipeline's AbortSignal with its abort - * closure; flags bits 1-2 give the destination kind and bit 5 the - * signal group (scr_stream_pipeline_stages). A promise destination's - * promise type is sp.pipelineStages' result. */ - "sp.pipelineStages": { - argTypes: [F64, F64, F64, F64, F64], - result: { kind: "promise", inner: VOID }, - }, - /** sp.pipelineStages with the options argument: the same head, then - * end (a bool) and, with flags bit 6, the options' signal (dyn). */ - "sp.pipelineStagesOpts": { - argTypes: [F64, F64, F64, F64, F64], - result: { kind: "promise", inner: VOID }, - }, - /** node:stream/consumers — the promise consumers over the readable - * machinery: (s) → a pending promise settled at the terminal point - * with the accumulated result (sc.text: the utf8 decode, sc.json: the - * parsed dyn — malformed input rejects with the parse's SyntaxError, - * sc.buffer: the concatenated bytes, sc.arrayBuffer: an ArrayBuffer - * dyn over them) or rejected with the stream's - * error / ERR_STREAM_PREMATURE_CLOSE. */ - "sc.text": { argTypes: [null], result: { kind: "promise", inner: STRING } }, - "sc.json": { argTypes: [null], result: { kind: "promise", inner: DYN } }, - "sc.buffer": { argTypes: [null], result: { kind: "promise", inner: BYTES_U8 } }, - "sc.arrayBuffer": { argTypes: [null], result: { kind: "promise", inner: DYN } }, - "readable.newDyn": { argTypes: [DYN], result: VOID }, - "writable.newDyn": { argTypes: [DYN], result: VOID }, - "duplex.newDyn": { argTypes: [DYN], result: VOID }, - "transform.newDyn": { argTypes: [DYN], result: VOID }, - "passthrough.newDyn": { argTypes: [DYN], result: VOID }, - "readable.initDyn": { argTypes: [null, DYN, F64], result: VOID }, - "writable.initDyn": { argTypes: [null, DYN, F64], result: VOID }, - "duplex.initDyn": { argTypes: [null, DYN, F64], result: VOID }, - "transform.initDyn": { argTypes: [null, DYN, F64], result: VOID }, - "passthrough.initDyn": { argTypes: [null, DYN, F64], result: VOID }, - /** Subclass initialization (`super(options?)` in a user `extends - * Readable` constructor): same tail as the `.new` forms, prefixed with - * the BORROWED receiver (the emitted subclass allocation — vtable and - * display name stamped, state NULL until here). Overridden underscore - * methods arrive as synthesized wrapper closures dispatching through - * the vtable. Void result. */ - "readable.init": { argTypes: [null, F64, BOOL, BOOL, F64], result: VOID }, - "writable.init": { argTypes: [null, F64, BOOL, BOOL, F64], result: VOID }, - "duplex.init": { argTypes: [null, F64, F64, BOOL, BOOL, BOOL, BOOL, BOOL, F64], result: VOID }, - "transform.init": { argTypes: [null, F64, F64, BOOL, BOOL, BOOL, BOOL, BOOL, F64], result: VOID }, - "passthrough.init": { - argTypes: [null, F64, F64, BOOL, BOOL, BOOL, BOOL, BOOL, F64], - result: VOID, - }, - "readable.push": { argTypes: [null, BYTES_U8], result: BOOL }, - "readable.pushStr": { argTypes: [null, STRING], result: BOOL }, - "readable.pushNull": { argTypes: [null], result: BOOL }, - "readable.pushU": { argTypes: [null, null], result: BOOL }, - "readable.pushDyn": { argTypes: [null, DYN], result: BOOL }, - "readable.unshift": { argTypes: [null, BYTES_U8], result: VOID }, - "readable.unshiftDyn": { argTypes: [null, DYN], result: VOID }, - "readable.unshiftStr": { argTypes: [null, STRING], result: VOID }, - "stream.onDyn": { argTypes: [null, STRING, DYN, BOOL, BOOL], result: VOID }, - "readable.readDyn": { argTypes: [null, DYN], result: DYN }, - "readable.read": { argTypes: [null, F64], result: VOID }, - "readable.pause": { argTypes: [null], result: VOID }, - "readable.setEncoding": { argTypes: [null, STRING], result: VOID }, - /** push(chunk, enc) with a literal non-utf8 encoding, and the - * defaultEncoding option's push side (how push(string) decodes — - * Buffer.from(chunk, enc)); both carry the CANONICAL literal. */ - "readable.pushStrEnc": { argTypes: [null, STRING, STRING], result: BOOL }, - "readable.pushEncoding": { argTypes: [null, STRING], result: VOID }, - /** The objectMode option's sides (readable, writable), applied right - * after construction; answers the receiver (+1, the chaining shape). */ - "stream.objectMode": { argTypes: [null, BOOL, BOOL], result: VOID }, - "stream.decodeStrings": { argTypes: [null, BOOL], result: VOID }, - /** Runtime decodeStrings and defaultEncoding option values, applied - * after construction (answers the receiver +1); the encoding was - * validated by stream.checkEncodingOption before construction. */ - "stream.optionValues": { argTypes: [null, DYN, DYN], result: VOID }, - "stream.checkEncodingOption": { argTypes: [DYN], result: VOID }, - "stream.duplexFromGen": { argTypes: [null, null, null, null, null, null], result: VOID }, - "stream.duplexFromDyn": { argTypes: [DYN], result: VOID }, - /** Duplex.from over a lone Readable or Writable, or a { readable, - * writable } pair of streams (duplexify.js's _duplexify). */ - "stream.duplexifyReadable": { argTypes: [null], result: VOID }, - "stream.duplexifyWritable": { argTypes: [null], result: VOID }, - "stream.duplexifyPair": { argTypes: [null, null], result: VOID }, - /** Duplex.from(promise): the promise and its box helper. */ - "stream.duplexFromPromise": { argTypes: [null, null], result: VOID }, - /** Duplex.from(asyncFunction): the stage, its source helper and the - * promise's box helper. */ - "stream.duplexFromAsyncFn": { argTypes: [null, null, null], result: VOID }, - /** The same for a body that declares the options argument: then the - * AbortController's abort() and its signal. */ - "stream.duplexFromGenSignal": { - argTypes: [null, null, null, null, null, null, null, DYN], - result: VOID, - }, - "stream.duplexFromAsyncFnSignal": { argTypes: [null, null, null, null, DYN], result: VOID }, - "writable.writeEncoding": { argTypes: [null, STRING], result: VOID }, - "writable.setDefaultEncoding": { argTypes: [null, DYN], result: VOID }, - /** Whether a readable.nextChunkDyn step answered the end (the done - * marker; an object-mode stream can yield undefined). */ - "stream.chunkDone": { argTypes: [DYN], result: BOOL }, - /** for-await over a readable (the desugared loop's per-pass promise): - * +1 promise of the next chunk — buffered content, the EOF sentinel - * (empty Buffer / dyn undefined), or a rejection with the stream's - * error. The Dyn twin boxes chunks by runtime tag (the JS lane). - * readable.fromArr is Readable.from over a typed array, string or - * Buffer: [array, SCR_FROM_* flags, highWaterMark]. readable.fromDyn is - * Readable.from over a checked-dynamic source: [source, options]. - * readable.fromIter is Readable.from over a class iterator, already - * opened: [checked-dynamic { next } object, flags, highWaterMark]; - * readable.fromAsyncIter is the async class iterator's twin. */ - "readable.nextChunk": { argTypes: [null], result: VOID }, - "readable.nextChunkDyn": { argTypes: [null], result: VOID }, - "readable.fromArr": { argTypes: [null, F64, F64], result: VOID }, - "readable.fromDyn": { argTypes: [DYN, DYN], result: VOID }, - "readable.fromIter": { argTypes: [DYN, F64, F64], result: VOID }, - "readable.fromAsyncIter": { argTypes: [DYN, F64, F64], result: VOID }, - /** Readable.from over a compiled generator: [generator, next, return, - * throw, flags, highWaterMark] (sync) or [generator, next, read, - * return, throw, flags, highWaterMark] (async), the helpers being the - * frontend's interned closures. readable.fromDone is the done marker - * the helpers answer. */ - "readable.fromGen": { argTypes: [null, null, null, null, F64, F64], result: VOID }, - "readable.fromAsyncGen": { argTypes: [null, null, null, null, null, F64, F64], result: VOID }, - "readable.fromDone": { argTypes: [], result: DYN }, - /** The Readable operators (scr_stream_ops.c): [stream, ...] with every - * other argument a checked-dynamic value (the callback, the count, the - * options). map/filter/flatMap/drop/take answer the object-mode output - * stream (validated as a stream class; THROW Node's validation errors); - * toArray settles a dyn array, find a dyn value, some/every a boolean, - * forEach nothing; reduce: [stream, fn, init, hasInit, options, kind] - * with the payload kind (0 dyn, 1 number, 2 boolean, 3 string). The - * promise-returning ones reject instead of throwing. */ - "readable.opMap": { argTypes: [null, DYN, DYN, DYN], result: VOID }, - "readable.opFilter": { argTypes: [null, DYN, DYN, DYN], result: VOID }, - "readable.opFlatMap": { argTypes: [null, DYN, DYN, DYN], result: VOID }, - /** flatMap whose callback returns a compiled generator: the helpers - * over its type follow (async: next, read, return, throw; sync: next, - * return, throw). */ - "readable.opFlatMapAsyncGen": { - argTypes: [null, DYN, DYN, DYN, null, null, null, null], - result: VOID, - }, - "readable.opFlatMapSyncGen": { argTypes: [null, DYN, DYN, DYN, null, null, null], result: VOID }, - "readable.opDrop": { argTypes: [null, DYN, DYN], result: VOID }, - "readable.opTake": { argTypes: [null, DYN, DYN], result: VOID }, - "readable.opToArray": { argTypes: [null, DYN], result: { kind: "promise", inner: DYN } }, - "readable.opForEach": { - argTypes: [null, DYN, DYN, DYN], - result: { kind: "promise", inner: VOID }, - }, - "readable.opSome": { argTypes: [null, DYN, DYN, DYN], result: { kind: "promise", inner: BOOL } }, - "readable.opEvery": { argTypes: [null, DYN, DYN, DYN], result: { kind: "promise", inner: BOOL } }, - "readable.opFind": { argTypes: [null, DYN, DYN, DYN], result: { kind: "promise", inner: DYN } }, - /** The map family's last argument is the callback's { signal } (or - * undefined). reduceSignal adds ac.abort() (a closure) and - * { signal: ac.signal } for a reducer that reads them. */ - "readable.opReduce": { argTypes: [null, DYN, DYN, BOOL, DYN, F64], result: VOID }, - "readable.opReduceSignal": { - argTypes: [null, DYN, DYN, BOOL, DYN, F64, null, DYN], - result: VOID, - }, - "readable.opSignalList": { argTypes: [DYN], result: DYN }, - "readable.opSignalOpts": { argTypes: [DYN], result: DYN }, - "readable.opSignalOf": { argTypes: [DYN], result: DYN }, - "readable.opOnceOptions": { argTypes: [], result: DYN }, - "readable.resume": { argTypes: [null], result: VOID }, - "readable.isPaused": { argTypes: [null], result: BOOL }, - "readable.pipe": { argTypes: [null, null, BOOL], result: VOID }, - "readable.pipeGeneral": { argTypes: [null, null, BOOL], result: VOID }, - "readable.unpipe": { argTypes: [null], result: VOID }, - "readable.flowing": { argTypes: [null], result: VOID }, - "writable.write": { argTypes: [null, BYTES_U8], result: BOOL }, - "writable.writeStr": { argTypes: [null, STRING], result: BOOL }, - "writable.writeU": { argTypes: [null, null], result: BOOL }, - "writable.writeDyn": { argTypes: [null, DYN], result: BOOL }, - "writable.writeEnc": { argTypes: [null, F64, DYN], result: BOOL }, - "writable.end": { argTypes: [null, F64], result: VOID }, - "writable.cork": { argTypes: [null], result: VOID }, - "writable.uncork": { argTypes: [null], result: VOID }, - "stream.destroy": { argTypes: [null], result: VOID }, - "stream.destroyErr": { argTypes: [null, null], result: VOID }, - /** AsyncIteratorClose for Readable[Symbol.asyncIterator](): destroy with - * Node's AbortError/ABORT_ERR payload while the iterator's internal error - * consumer prevents an unhandled-error crash. */ - "stream.iteratorClose": { argTypes: [null], result: VOID }, - "stream.prop": { argTypes: [null, STRING], result: VOID }, - "stream.errored": { argTypes: [null], result: VOID }, - // node:assert: pass/negated/deep/hasMsg are frontend-computed bools; the - // message slot always carries a string ("" when hasMsg is false). - /** node:assert (scr_assert.c; assert.match in scr_regex.c — every call - * site carries a regex value, so the regex link switch is already on). - * Failures throw a catchable AssertionError — a runtime %Error whose - * name is "AssertionError" and whose code slot is "ERR_ASSERTION" — so - * `instanceof Error`, `.name`, `.message`, and `.code` all answer like - * Node's. Generated messages are Node's assertion_error.js scalar forms - * byte-exactly (the short `a !== b` form, the stacked `+ actual - * - expected` diff with the string `^` indicator, the inline-vs-block - * not-equal split); composite deep failures carry the header line - * without the rendered inspect diff (documented divergence). - * - * assert.ok: (pass, message) — the frontend computed the truthiness AND - * the full message (the user's, or the compile-time source-text form — - * assert.fail lowers here too with pass=false). assert.eqF64/eqBigInt/ - * eqStr/eqBool: (a, b, negated, deep, msg, hasMsg) — Object.is comparison, - * covering strictEqual/notStrictEqual and the scalar deepStrictEqual - * pair; msg is a typed dummy ("" literal) when hasMsg is false (Node - * distinguishes an omitted message from an empty one per operator). - * assert.deepResult: (equal, negated, msg, hasMsg) — the verdict of a - * frontend-synthesized structural comparison, turned into Node's throw. - * assert.sameValue: Object.is over doubles (the deep-equal helpers' - * number leaf; never throws). assert.match: (s, regex, negated, msg, - * hasMsg) — a fresh exec from index 0. assert.throwsNone: (rejection, - * ename, hasEname, msg, hasMsg) — the "Missing expected - * exception|rejection" throw of assert.throws/rejects whose callback - * returned (fulfilled) normally, with Node's ` (${expected.name})` - * detail when the expected class or shape carries a name. - * assert.throwsMismatch: (expectedName, error) — the wrong-class throw - * of the assert.throws(fn, ErrorClass) form. assert.eqSym: - * (a, b, negated, deep, msg, hasMsg) — strict equality over symbol - * values, pointer identity with v24's "Symbol(desc)" stacked-diff - * messages (scr_symbol.c, the assert.match pattern — symbol-typed - * slots already flip the symbol link switch). assert.eqDyn: - * (a, b, negated, deep, msg, hasMsg) — the whole quartet over - * checked-dynamic operands (both slots dyn; the frontend boxes a - * static side with dynFrom first): SameValue for the strict pair over - * the dyn kinds (boxed-closure identity for functions), the structural - * dyn walk for the deep pair, with assertion_error.js's messages — - * scalar forms byte-exact, composites rendered compact:false/sorted - * through the checked-dynamic tree and diffed with the real myers line printer. - * - * The assert.throws(fn, {name/code/message}) shape check - * (expectedException over the static error surface): shapeBegin - * stashes the caught error, shapeStr/shapeRe add one expected key each - * (key ids 0 code / 1 message / 2 name; shapeRe lives in scr_regex.c — - * its regex argument flips the regex link switch — and tests eagerly - * so scr_assert.c stays libregexp-free), then shapeEnd throws Node's - * deep-equal Comparison diff BYTE-EXACTLY (the bounded key set makes - * the rendering enumerable) or the custom message. - * assert.throwsRegex: (regex, error, msg, hasMsg) — the - * assert.throws(fn, /re/) check over String(error), Node's - * regex-mismatch message. assert.regexErrTest: doesNotReject's - * regex predicate over String(error) (never throws). - * assert.unwantedRejection: (error, msg, hasMsg) — doesNotReject's - * "Got unwanted rejection" throw. - * assert.ifErrorErr/F64/Str/Bool: assert.ifError's per-type throws - * ("ifError got unwanted exception: " + the error's message/name or - * the value's inspection) — the frontend routes null/undefined to a - * no-op and everything else here (Node throws for falsy values too). - * All arguments are borrowed. */ - "assert.ok": { argTypes: [BOOL, STRING, BOOL], result: VOID }, - /** The next AssertionError's actual, expected and operator, recorded on - * a failure branch. */ - "assert.record": { argTypes: [DYN, DYN, STRING], result: VOID }, - "assert.errorNew": { argTypes: [DYN], result: { kind: "object", className: "%AssertionError" } }, - "assert.eqF64": { argTypes: [F64, F64, BOOL, BOOL, STRING, BOOL], result: VOID }, - "assert.eqBigInt": { argTypes: [BIGINT_T, BIGINT_T, BOOL, BOOL, STRING, BOOL], result: VOID }, - "assert.eqStr": { argTypes: [STRING, STRING, BOOL, BOOL, STRING, BOOL], result: VOID }, - "assert.eqBool": { argTypes: [BOOL, BOOL, BOOL, BOOL, STRING, BOOL], result: VOID }, - "assert.deepResult": { argTypes: [BOOL, BOOL, STRING, BOOL], result: VOID }, - "assert.looseDeepResult": { argTypes: [BOOL, BOOL, STRING, BOOL], result: VOID }, - "assert.looseDeepDyn": { argTypes: [DYN, DYN, BOOL, STRING, BOOL], result: VOID }, - "assert.partialDeepDyn": { argTypes: [DYN, DYN, STRING, BOOL], result: VOID }, - "assert.partialDeepResult": { argTypes: [BOOL, BOOL, STRING, BOOL], result: VOID }, - "assert.partialEqDyn": { argTypes: [DYN, DYN], result: BOOL }, - "assert.looseF64Eq": { argTypes: [F64, F64], result: BOOL }, - "assert.sameValue": { argTypes: [F64, F64], result: BOOL }, - // The deep-equality pair memo: both slots are program-dependent - // (any cycle-capable record/array/map type). - /* deepStrictEqual's pair memo over cycle-capable types: enter answers - * true for a pair already being compared (Node's memo — equal cyclic - * structures compare true); leave pops. */ - "assert.deqEnter": { argTypes: [null, null], result: BOOL }, - "assert.deqLeave": { argTypes: [], result: VOID }, - "assert.match": { argTypes: [STRING, REGEX, BOOL, STRING, BOOL], result: VOID }, - "assert.throwsNone": { argTypes: [BOOL, STRING, BOOL, STRING, BOOL], result: VOID }, - "assert.throwsMismatch": { - argTypes: [STRING, { kind: "object", className: "%Error" }, STRING, BOOL, BOOL], - result: VOID, - }, - "assert.throwsRegex": { - argTypes: [REGEX, { kind: "object", className: "%Error" }, STRING, BOOL, BOOL], - result: VOID, - }, - // Symbol strict equality (pointer identity; scr_symbol.c). - "assert.eqSym": { - argTypes: [{ kind: "symbol" }, { kind: "symbol" }, BOOL, BOOL, STRING, BOOL], - result: VOID, - }, - // The equality quartet over checked-dynamic operands (the frontend - // boxes a static side into the checked-dynamic tree first). - "assert.eqDyn": { argTypes: [DYN, DYN, BOOL, BOOL, STRING, BOOL], result: VOID }, - /** A message argument that is not a string, registered for the next - * failing assertion (scr_assert_message_value). */ - "assert.messageValue": { argTypes: [DYN, BOOL], result: VOID }, - /** An assert method as a function value, by canonical name. */ - "assert.methodValue": { argTypes: [STRING], result: DYN }, - "assert.messageClear": { argTypes: [], result: VOID }, - "assert.looseResult": { argTypes: [BOOL, BOOL, STRING, STRING, STRING, BOOL], result: VOID }, - // The throws(fn, {shape}) accumulator: begin/slot calls never throw; - // shapeEnd throws the Comparison diff. The error slot is the - // %Error-narrowed caught value. - "assert.shapeBegin": { argTypes: [{ kind: "object", className: "%Error" }], result: VOID }, - "assert.shapeStr": { argTypes: [F64, STRING], result: VOID }, - "assert.shapeRe": { argTypes: [F64, REGEX], result: VOID }, - "assert.shapeEnd": { argTypes: [STRING, BOOL, BOOL], result: VOID }, - "assert.regexErrTest": { - argTypes: [REGEX, { kind: "object", className: "%Error" }], - result: BOOL, - }, - "assert.unwantedRejection": { - argTypes: [{ kind: "object", className: "%Error" }, STRING, BOOL], - result: VOID, - }, - "assert.unwantedError": { argTypes: [STRING, BOOL, STRING, BOOL], result: VOID }, - "assert.noErrorPredicate": { argTypes: [DYN, DYN], result: BOOL }, - "assert.regexDynTest": { argTypes: [REGEX, DYN], result: BOOL }, - /** Node's expectsError over an error-INSTANCE expected (assert.throws/ - * rejects second argument): walk the expected dyn error's keys (name, - * message, code — the %error marker skipped) and deep-compare each - * against the caught value's; a mismatch throws the deep-equal - * AssertionError (scr_assert.c). MAY THROW by design. */ - "assert.expectsErrDyn": { argTypes: [DYN, DYN, STRING, BOOL], result: VOID }, - /** A validation function against the caught value (Node's expectedException). */ - "assert.throwsValidate": { argTypes: [DYN, DYN, STRING, STRING, BOOL], result: VOID }, - // assert.ifError's typed entries (always throw; unit args never - // lower). The error slot is program-dependent — any %Error-hierarchy - // class, root or subclass (the insp.error precedent, null slot). - "assert.ifErrorErr": { argTypes: [null], result: VOID }, - "assert.ifErrorF64": { argTypes: [F64], result: VOID }, - "assert.ifErrorStr": { argTypes: [STRING], result: VOID }, - "assert.ifErrorBool": { argTypes: [BOOL], result: VOID }, - "assert.ifErrorDyn": { argTypes: [DYN], result: VOID }, - // Bytes equality: the two value slots are any bytes kind (the frontend - // gates both sides to ONE static bytes type; the libCall case checks - // the kind and the pair below). - "assert.refEqBytes": { argTypes: [null, null, BOOL, BOOL, STRING, BOOL], result: VOID }, - "assert.refEqFn": { argTypes: [null, null, BOOL, STRING, BOOL], result: VOID }, - "assert.bytesDeepEq": { argTypes: [null, null, BOOL], result: BOOL }, - "assert.looseBytesEq": { argTypes: [null, null], result: BOOL }, - // util.inspect: the error receiver is program-dependent (a builtin or - // user error class — the error.toString precedent, null slot). + "dyn.objCreateNullProto": { argTypes: [], result: DYN }, + "dyn.arrayPrototype": { argTypes: [], result: DYN }, + "dyn.arrayConstructor": { argTypes: [], result: DYN }, + "dyn.objectPrototype": { argTypes: [], result: DYN }, + "dyn.errorPrototype": { argTypes: [], result: DYN }, + "dyn.inheritsErrorPrototype": { argTypes: [DYN], result: BOOL }, + "dyn.errorCaptureStackTrace": { argTypes: [DYN], result: DYN }, + "dyn.errorCaptureStackTraceFunction": { argTypes: [], result: DYN }, + "dyn.functionApply": { argTypes: [], result: DYN }, + "dyn.builtinMethod": { argTypes: [STRING, STRING], result: DYN }, + "dyn.classPrototype": { argTypes: [DYN, DYN], result: DYN }, + "dyn.classBasePrototype": { argTypes: [DYN], result: DYN }, + "dyn.classInherit": { argTypes: [DYN, DYN], result: DYN }, + /** EventEmitter (0), Stream (1), Readable (2), Writable (3), Duplex (4), + * Transform (5) and PassThrough (6) as untyped constructor values, one + * per thread (scr_dyn_builtin_class.c). */ + "dyn.builtinClass": { argTypes: [F64], result: DYN }, + /** The stream classes (2-6 above) with their stream half: constructor + * functions over them get native stream state + * (scr_dyn_builtin_stream.c). */ + "dyn.builtinStreamClass": { argTypes: [F64], result: DYN }, + /** `value instanceof C` for those constructors, over the value's + * prototype chain. */ + "dyn.builtinInstanceOf": { argTypes: [DYN, F64], result: BOOL }, + /** `value instanceof f` for an untyped constructor function: the + * prototype chain against f.prototype. */ + "dyn.functionInstanceOf": { argTypes: [DYN, DYN], result: BOOL }, + "dyn.classSuper": { argTypes: [DYN, DYN, DYN], result: VOID }, + "dyn.assignPrototype": { argTypes: [DYN, DYN, DYN], result: DYN }, + "dyn.definePrototypeProps": { argTypes: [DYN, DYN, DYN], result: DYN }, + "dyn.bagGet": { argTypes: [DYN, STRING, DYN], result: DYN }, + /** A class field's creation in its instance's property bag: adds the + * string key as a default data property when absent, answering false + * (nothing changed) when the bag needs the general defineProperty path. */ + "dyn.bagCreateField": { argTypes: [DYN, STRING], result: BOOL }, + "dyn.bagSet": { argTypes: [DYN, STRING, DYN, DYN], result: VOID }, + "dyn.objCreate": { argTypes: [DYN], result: DYN }, + // Names a compiled class's prototype object (args[0]) after the class + // (args[1]) for util.inspect. + "dyn.nameClassPrototype": { argTypes: [DYN, STRING], result: VOID }, + "dyn.objCreateWithProperties": { argTypes: [DYN, DYN], result: DYN }, + "dyn.getPrototype": { argTypes: [DYN], result: DYN }, + // dyn.getPrototype for walks that compare each prototype with a program + // class's prototype: native builtin values end the walk (null). + "dyn.getPrototypeForIdentity": { argTypes: [DYN], result: DYN }, + "dyn.setPrototype": { argTypes: [DYN, DYN], result: DYN }, + "dyn.getOwnPropertyNames": { argTypes: [DYN], result: DYN }, + "dyn.ownKeys": { argTypes: [DYN], result: DYN }, + "dyn.getOwnPropertySymbols": { argTypes: [DYN], result: DYN }, + "dyn.getOwnPropertyDescriptors": { argTypes: [DYN], result: DYN }, + "dyn.preventExtensions": { argTypes: [DYN], result: DYN }, + "dyn.isExtensible": { argTypes: [DYN], result: BOOL }, + "dyn.seal": { argTypes: [DYN], result: DYN }, + "dyn.isSealed": { argTypes: [DYN], result: BOOL }, + "dyn.objValues": { argTypes: [DYN], result: DYN }, + /** Object.values as a native vector of checked values, for results the + * program consumes directly (for-of, index reads, read-only methods). */ + "dyn.objValueList": { argTypes: [DYN], result: arrayOf(DYN) }, + "dyn.objEntries": { argTypes: [DYN], result: DYN }, + /** structuredClone over the checked-dynamic tree (scr_json.c): the JSON-safe subset plus + * bytes (a fresh copy — a Buffer clones as a plain Uint8Array, like + * Node), deep. Functions and handle kinds throw the spec's catchable + * DataCloneError; CYCLES throw the scriptc fence (the checked-dynamic tree cannot + * represent them — Node clones cycles; documented divergence). The + * options dyn value validates with Node's exact errors (dictionary + * conversion, the transfer-sequence member; any non-empty transfer + * list throws DataCloneError). dyn.cloneMissing is the zero-argument + * call: always throws Node's TypeError [ERR_MISSING_ARGS] with Node's + * own (verbatim, doubly-wrapped) message. */ + "dyn.structuredClone": { argTypes: [DYN, DYN], result: DYN }, + /** The declaration-typed boundary's adoption (decl-projection.ts): + * `source` is the dynamic value a boundary cast just converted, and + * `capsule` a live capsule of the native value built from it. Every + * object or array of `source` that something else still references + * becomes, in place, a live capsule of the native value built from it. + * Throws the path TypeError, changing nothing, when a converted object + * is not plain data (a prototype, accessors, symbols, frozen state). */ + "dyn.declAdopt": { argTypes: [DYN, DYN], result: VOID }, + "dyn.cloneMissing": { argTypes: [], result: DYN }, + /** structuredClone with a NON-EMPTY transfer array of static values: + * nothing static is transferable, so the call always throws Node's + * catchable DataCloneError ("Found invalid value in transferList.") — + * lowered directly (the list's values need no dyn representation to + * fail). */ + "dyn.cloneTransferFail": { argTypes: [], result: DYN }, + /** The same refusal given the transfer list's first member, an + * ArrayBuffer: a Buffer pool slab gets Node's untransferable message. */ + "dyn.cloneTransferFailWith": { argTypes: [DYN], result: DYN }, + /** `new RegExp(pattern, flags?)` (scr_regex.c): a heap regex over the + * same libregexp engine the literals use. The pattern compiles EAGERLY + * so an invalid pattern (or an unknown flag letter) throws Node's + * catchable SyntaxError at construction — Node's message shape with + * libregexp's detail text (approximate fidelity; e.name exact). An + * empty pattern stores the spec's "(?:)" source. Both args borrowed + * strings (the lowering completes an absent flags to ""); result +1. + * The result TYPE is the regex kind, so the link switch pulls the + * engine exactly like a literal. */ + "regex.new": { argTypes: [STRING, STRING], result: REGEX }, + "regex.resetLastIndex": { argTypes: [REGEX, F64], result: VOID }, + "regex.newChecked": { argTypes: [DYN, DYN], result: REGEX }, + "regex.replaceCallback": { argTypes: [STRING, REGEX, DYN, BOOL], result: STRING }, + // Reads of capture args[1] of an execSpans/matchGroups result: + // `capture === args[2]`, Number(capture) and parseInt(capture, + // args[2]). Borrowed; never throw. + "regex.groupEquals": { argTypes: [arrayOf(STRING), F64, STRING], result: BOOL }, + "regex.groupNumber": { argTypes: [arrayOf(STRING), F64], result: F64 }, + "regex.groupParseInt": { argTypes: [arrayOf(STRING), F64, F64], result: F64 }, + // `.index` / `.input` (args[1]) of a match result. Borrowed; never throws. + "regex.resultProp": { argTypes: [arrayOf(STRING), STRING], result: DYN }, + // The string keys `for...in` visits on an array (args[0], any element + // type) after its indices. Borrowed; never throws. + "array.namedKeys": { argTypes: [null], result: arrayOf(STRING) }, + // Whether the array (args[0]) still has the key (args[1]) from its + // namedKeys list. Borrowed; never throws. + "array.hasNamedKey": { argTypes: [null, STRING], result: BOOL }, + // Whether an array (args[0], any element type) has properties besides its + // elements: noncanonical numeric keys, match metadata or named + // properties. Borrowed; never throws. + "array.hasProperties": { argTypes: [null], result: BOOL }, + // The key of an element access whose index is undefined (the property + // named "undefined"; frontend/lowering/undefined-index.ts). + "array.undefinedKey": { argTypes: [], result: F64 }, + // node:events EventEmitter: receivers are emitter-hierarchy objects and + // the chaining forms (on/off/removeAll/setMax) return the receiver's + // own class — program-dependent object types, checked in the libCall + // case. emitter.emit is the one VARIADIC libCall: args beyond + // (recv, name) are the event's frontend-unified tuple, any borrowable + // kind — the count check admits a longer list for it alone. + /** node:events EventEmitter (scr_events_emitter.c, link-gated by + * moduleUsesEmitter). The receiver of every instance form is a borrowed + * emitter-hierarchy object (`%EventEmitter` or a user subclass — the + * backend reinterprets to ScrEmitter*, the identical prefix); event + * names are borrowed strings (compile-time literals — the frontend + * fences non-literals and unifies each event's argument tuple program- + * wide). The chaining forms (on/off/removeAll/setMax) return the + * receiver +1 typed as its static class, Node's `return this`. + * + * emitter.new: `new EventEmitter()` → a +1 bare emitter. emitter.ctor: + * super() into the prefix of an emitted subclass (borrowed receiver, + * void — allocation already initialized the prefix). emitter.on: + * (recv, name, cb /moves/, once, prepend) — the backend synthesizes the + * per-signature va_list invoke adapter from the cb's func type. + * emitter.emit: (recv, name, ...tuple) — VARIADIC, the one libCall + * whose arg count exceeds its signature; args are borrowed, result is + * the had-listeners bool. emitter.emitError: emit('error', err) — + * throws err when unhandled. count/countFn/names/listeners/getMax/ + * setMax/setDefaultMax/getDefaultMax are the introspection surface. */ + "emitter.new": { argTypes: [], result: VOID }, + /** `x.constructor.name` of an emitter or stream (a borrowed object of + * EventEmitter's hierarchy): the +1 class name the instance records. */ + "emitter.className": { argTypes: [null], result: STRING }, + "emitter.ctor": { argTypes: [null], result: VOID }, + "emitter.on": { argTypes: [null, STRING, null, BOOL, BOOL], result: VOID }, + "emitter.off": { argTypes: [null, STRING, null], result: VOID }, + // The dyn-adapted registration family (JS-lane checked-dynamic + // listeners): checkListener has NO receiver (it validates the listener + // argument alone); onDyn carries (recv, name, cb dyn, adapter func, + // once, prepend), offDyn (recv, name, cb dyn). + "emitter.checkListener": { argTypes: [DYN], result: VOID }, + "emitter.onDyn": { argTypes: [null, STRING, DYN, null, BOOL, BOOL], result: VOID }, + "emitter.onFlex": { argTypes: [null, STRING, DYN, BOOL, BOOL], result: VOID }, + /** on/once/prepend* and emit through an untyped value (the class + * dispatch of compiled emitters): onFlex/emitFlex plus runtime typed + * adapters under 'error' and the meta events, and Node's unhandled-'error' + * contract. emitAny is VARIADIC like emitFlex. */ + "emitter.onAny": { argTypes: [null, STRING, DYN, BOOL, BOOL], result: VOID }, + "emitter.offDyn": { argTypes: [null, STRING, DYN], result: VOID }, + "emitter.removeAll": { argTypes: [null, STRING, BOOL], result: VOID }, + "emitter.emit": { argTypes: [null, STRING], result: BOOL }, + "emitter.emitFlex": { argTypes: [null, STRING], result: BOOL }, + "emitter.emitAny": { argTypes: [null, STRING], result: BOOL }, + /** An untyped emit of an event with a fixed tuple: (recv, name, k, then + * k checked-dynamic arguments as given, then the event's converted + * tuple) — VARIADIC like emitter.emit. hasTyped answers whether a + * listener of the name needs the converted tuple. */ + "emitter.emitMixed": { argTypes: [null, STRING, F64], result: BOOL }, + "emitter.hasTyped": { argTypes: [null, STRING], result: BOOL }, + "emitter.emitError": { argTypes: [null, STRING, null], result: BOOL }, + "emitter.count": { argTypes: [null, STRING], result: F64 }, + "emitter.countFn": { argTypes: [null, STRING, null], result: F64 }, + "emitter.countDyn": { argTypes: [null, STRING, DYN], result: F64 }, + "emitter.names": { argTypes: [null], result: VOID }, + "emitter.listeners": { argTypes: [null, STRING], result: VOID }, + /** listeners()/rawListeners() through an untyped value: a checked- + * dynamic array (throws when a listener has typed parameters). */ + "emitter.listenersDyn": { argTypes: [null, STRING], result: DYN }, + /** Stream-'data' registration twins of emitter.on/onDyn (same args): + * chosen at registration sites whose receiver is stream-rooted, so the + * backend emits DATA thunks — the runtime's 'data' emission carries + * BOTH payload slots (bytes, string; exactly one non-NULL — encoded + * streams deliver strings), and the thunk unwraps the listener's + * declared side (typed) or boxes by tag (dyn). emitter.emitData is the + * user-emit form: (recv, name, chunk) with a bytes OR string chunk. */ + "emitter.onData": { argTypes: [null, STRING, null, BOOL, BOOL], result: VOID }, + "emitter.onDataDyn": { argTypes: [null, STRING, DYN, null, BOOL, BOOL], result: VOID }, + "emitter.emitData": { argTypes: [null, STRING, null], result: BOOL }, + "emitter.setMax": { argTypes: [null, F64], result: VOID }, + "emitter.getMax": { argTypes: [null], result: F64 }, + "emitter.setDefaultMax": { argTypes: [F64], result: VOID }, + "emitter.getDefaultMax": { argTypes: [], result: F64 }, + // The ES module namespace's copy of defaultMaxListeners, and + // module.syncBuiltinESMExports() refreshing it. + "emitter.esmDefaultMax": { argTypes: [], result: F64 }, + "emitter.esmSync": { argTypes: [], result: VOID }, + /** The events.errorMonitor event key: an immortal string the runtime + * registry matches by identity, so no string event name reaches it. */ + "emitter.errorMonitor": { argTypes: [], result: STRING }, + // node:stream: receivers are stream-hierarchy objects and several + // results are program-dependent (the receiver's class, unions) — the + // libCall case owns those checks. The constructors and a few methods + // are VARIADIC (trailing option callbacks / the optional chunk+cb tail): + // argTypes here is the fixed prefix, VARIADIC_LIB_FNS admits the rest. + /** node:stream (scr_stream.c, link-gated by moduleUsesStream — which + * implies the emitter unit: stream events dispatch through the embedded + * ScrEmitter registry). Receivers are borrowed stream-class objects + * (`%Readable`/`%Writable`/`%Duplex`/`%Transform`/`%PassThrough` — one + * runtime layout, reinterpreted by side). + * + * Constructors (`readable.new` et al): args are [hwmR, hwmW, flags] + * followed by the PRESENT user callbacks in canonical order (read, + * write, final, destroy, transform, flush — the flags f64 is a bitmask + * naming which follow; absent ones emit NULL). Every callback closure + * MOVES and carries a leading `this` param (the stream), invoked + * through compiler-emitted adapters. Results are +1. + * + * readable.push / readable.pushStr / readable.pushNull: Node's push — + * buffers or delivers (bytes chunk borrowed; string converted utf8); + * returns the below-hwm answer. readable.read: (recv, size — -1 for + * absent) → Buffer|null union. pause/resume return recv +1 (`this`); + * isPaused answers the flag. readable.pipe: (recv, dst, end) → dst +1, + * fires 'pipe' on dst; readable.pipeGeneral: the same, with `end` off + * when dst is the converted process.stdout / process.stderr; + * readable.unpipe (recv[, dst]) → recv +1. + * writable.write/writeStr: (recv, chunk[, cb]) → below-hwm bool (cb + * MOVES when present, called after the user write completes). + * writable.writeEnc: (recv, flags, chunk[, encoding][, cb]) — flags 1 + * an encoding argument, 2 a callback (the encoding is then null, as + * Node's write shifts it). + * writable.end: (recv, flags[, chunk][, encoding][, cb]) → recv +1; + * flags 16: an encoding argument follows the dyn chunk. cork/uncork are + * void. stream.destroy/destroyErr: (recv[, err]) → recv +1. + * stream.prop: (recv, name-literal) → the flag/number the name asks + * for; stream.errored → Error|null union; readable.flowing → + * bool|null union. All may leave a listener's exception pending + * (dispatch runs user code synchronously, like emit). */ + "readable.new": { argTypes: [F64, BOOL, BOOL, F64], result: VOID }, + "writable.new": { argTypes: [F64, BOOL, BOOL, F64], result: VOID }, + "duplex.new": { argTypes: [F64, F64, BOOL, BOOL, BOOL, BOOL, BOOL, F64], result: VOID }, + "transform.new": { argTypes: [F64, F64, BOOL, BOOL, BOOL, BOOL, BOOL, F64], result: VOID }, + "passthrough.new": { argTypes: [F64, F64, BOOL, BOOL, BOOL, BOOL, BOOL, F64], result: VOID }, + // The subclass-initialization twins: the borrowed receiver leads, then + // the .new tail (variadic callbacks likewise). + // The dyn-options twins: newDyn takes the record, initDyn the borrowed + // receiver + record + fallback flags (trailing wrapper closures ride + // the variadic tail like the static forms). + /** The underscore-method assignment surface (`r._read = fn` after + * construction — Node's own-property shadow of the prototype method): + * args [stream receiver (borrowed), callback closure (+1 moves)]. The + * runtime slot the matching option callback fills swaps its closure + * and invoke thunk; the next dispatch uses it (Node's timing). The + * setters themselves never throw. */ + "stream.setRead": { argTypes: [null, null], result: VOID }, + "stream.setWrite": { argTypes: [null, null], result: VOID }, + "stream.setFinal": { argTypes: [null, null], result: VOID }, + "stream.setDestroy": { argTypes: [null, null], result: VOID }, + "stream.setTransform": { argTypes: [null, null], result: VOID }, + "stream.setFlush": { argTypes: [null, null], result: VOID }, + "stream.setConstruct": { argTypes: [null, null], result: VOID }, + "stream.replaceConstruct": { argTypes: [null, null], result: VOID }, + "stream.setWritev": { argTypes: [null, null], result: VOID }, + "stream.setWritevDefault": { argTypes: [null, null], result: VOID }, + /** The dyn-options twins (a checked-dynamic options record — the JS + * lane's `super(options)` forwarding and `new Readable(dynVar)`): the + * option walk runs at RUNTIME with Node's reading rules. newDyn: + * (optsDyn) → the fresh stream; initDyn: (recv, optsDyn, flags, + * ...fallback wrapper closures in canonical order — the flags literal + * names which ride, exactly the .init callback ABI). MAY THROW (a + * consumed-but-unlowered option is the compile fence's runtime twin). */ + /** stream.finished(s, cb) — the callback form: the watcher fires once + * at the terminal point with the finish status; the result is the +1 + * cleanup closure. stream.pipeline(count, s1..sn, cb): chains pipes, + * propagates the first error by destroying the rest, calls cb after the + * last 'close'; answers the destination +1. The Dyn twins take the + * callback as a checked-dynamic VALUE (mustCall wrappers). */ + /** stream.addAbortSignal: [stream, signal] — the constructors' signal + * option, chained over the fresh stream (falsy signals are ignored); + * stream.addAbortSignalFn: [signal, stream] — addAbortSignal(signal, + * stream). Both answer the stream (+1) and throw ERR_INVALID_ARG_TYPE + * for a value that is not an AbortSignal; they link the event-target + * unit (addAbortListener). */ + "stream.addAbortSignal": { argTypes: [null, DYN], result: VOID }, + "stream.addAbortSignalFn": { argTypes: [DYN, null], result: VOID }, + "stream.finished": { argTypes: [null, null], result: VOID }, + "stream.finishedDyn": { argTypes: [null, DYN], result: VOID }, + "stream.pipeline": { argTypes: [F64], result: VOID }, + "stream.pipelineDyn": { argTypes: [F64], result: VOID }, + "stream.pipelineStages": { argTypes: [F64, F64, F64, F64, F64], result: VOID }, + "stream.composeStages": { argTypes: [F64, F64, F64, F64, F64], result: VOID }, + "stream.pipelineStagesDyn": { argTypes: [F64, F64, F64, F64, F64], result: VOID }, + /** stream.compose(count, s1..sn): the Duplex over a pipeline of the + * streams (+1). MAY THROW (ERR_INVALID_ARG_VALUE for a stream that is + * no longer readable or writable). */ + "stream.compose": { argTypes: [F64], result: VOID }, + /** node:stream/promises — the promise forms over the same machinery: + * sp.finished: (s) → a pending void promise the terminal watcher + * settles; sp.pipeline: (count, s1..sn) → the callback pipeline's + * chaining/destroyer semantics settling a void promise (fulfilled on a + * clean finish, rejected with the finish status otherwise). */ + "sp.finished": { argTypes: [null], result: { kind: "promise", inner: VOID } }, + /** The options forms: finished(s, { readable, writable, error, cleanup, + * signal }) as [s, readable, writable, error, cleanup, signal?] — + * readable/writable -1 (absent), 0 or 1 — and pipeline(...streams, + * { signal, end }) as [count, s1..sn, end, signal?]. The Signal forms + * link the event-target unit (addAbortListener). The callback form + * stream.finishedOpts: [s, readable, writable, error, signal?, cb] → + * the cleanup closure. */ + "sp.finishedOpts": { + argTypes: [null, F64, F64, BOOL, BOOL], + result: { kind: "promise", inner: VOID }, + }, + "sp.finishedOptsSignal": { + argTypes: [null, F64, F64, BOOL, BOOL, DYN], + result: { kind: "promise", inner: VOID }, + }, + "sp.pipelineOpts": { argTypes: [F64], result: { kind: "promise", inner: VOID } }, + "sp.pipelineOptsSignal": { argTypes: [F64], result: { kind: "promise", inner: VOID } }, + "stream.finishedOpts": { argTypes: [null, F64, F64, BOOL, null], result: VOID }, + "stream.finishedOptsSignal": { argTypes: [null, F64, F64, BOOL, DYN, null], result: VOID }, + "sp.pipeline": { argTypes: [F64], result: { kind: "promise", inner: VOID } }, + /** pipeline with function stages: [n, k, positions, flags, mask, + * s1..sn, stage1..stagek, helpers..., box?, (signal, abort)?] (+ the + * callback for the stream.* forms): the user's stage functions at the + * positions the bitmask names, the frontend's (next, read, return) + * helpers for each pumped generator (pipelinePumpedRuns) and a promise + * destination's box, and the pipeline's AbortSignal with its abort + * closure; flags bits 1-2 give the destination kind and bit 5 the + * signal group (scr_stream_pipeline_stages). A promise destination's + * promise type is sp.pipelineStages' result. */ + "sp.pipelineStages": { + argTypes: [F64, F64, F64, F64, F64], + result: { kind: "promise", inner: VOID }, + }, + /** sp.pipelineStages with the options argument: the same head, then + * end (a bool) and, with flags bit 6, the options' signal (dyn). */ + "sp.pipelineStagesOpts": { + argTypes: [F64, F64, F64, F64, F64], + result: { kind: "promise", inner: VOID }, + }, + /** node:stream/consumers — the promise consumers over the readable + * machinery: (s) → a pending promise settled at the terminal point + * with the accumulated result (sc.text: the utf8 decode, sc.json: the + * parsed dyn — malformed input rejects with the parse's SyntaxError, + * sc.buffer: the concatenated bytes, sc.arrayBuffer: an ArrayBuffer + * dyn over them) or rejected with the stream's + * error / ERR_STREAM_PREMATURE_CLOSE. */ + "sc.text": { argTypes: [null], result: { kind: "promise", inner: STRING } }, + "sc.json": { argTypes: [null], result: { kind: "promise", inner: DYN } }, + "sc.buffer": { argTypes: [null], result: { kind: "promise", inner: BYTES_U8 } }, + "sc.arrayBuffer": { argTypes: [null], result: { kind: "promise", inner: DYN } }, + "readable.newDyn": { argTypes: [DYN], result: VOID }, + "writable.newDyn": { argTypes: [DYN], result: VOID }, + "duplex.newDyn": { argTypes: [DYN], result: VOID }, + "transform.newDyn": { argTypes: [DYN], result: VOID }, + "passthrough.newDyn": { argTypes: [DYN], result: VOID }, + "readable.initDyn": { argTypes: [null, DYN, F64], result: VOID }, + "writable.initDyn": { argTypes: [null, DYN, F64], result: VOID }, + "duplex.initDyn": { argTypes: [null, DYN, F64], result: VOID }, + "transform.initDyn": { argTypes: [null, DYN, F64], result: VOID }, + "passthrough.initDyn": { argTypes: [null, DYN, F64], result: VOID }, + /** Subclass initialization (`super(options?)` in a user `extends + * Readable` constructor): same tail as the `.new` forms, prefixed with + * the BORROWED receiver (the emitted subclass allocation — vtable and + * display name stamped, state NULL until here). Overridden underscore + * methods arrive as synthesized wrapper closures dispatching through + * the vtable. Void result. */ + "readable.init": { argTypes: [null, F64, BOOL, BOOL, F64], result: VOID }, + "writable.init": { argTypes: [null, F64, BOOL, BOOL, F64], result: VOID }, + "duplex.init": { argTypes: [null, F64, F64, BOOL, BOOL, BOOL, BOOL, BOOL, F64], result: VOID }, + "transform.init": { + argTypes: [null, F64, F64, BOOL, BOOL, BOOL, BOOL, BOOL, F64], + result: VOID, + }, + "passthrough.init": { + argTypes: [null, F64, F64, BOOL, BOOL, BOOL, BOOL, BOOL, F64], + result: VOID, + }, + "readable.push": { argTypes: [null, BYTES_U8], result: BOOL }, + "readable.pushStr": { argTypes: [null, STRING], result: BOOL }, + "readable.pushNull": { argTypes: [null], result: BOOL }, + "readable.pushU": { argTypes: [null, null], result: BOOL }, + "readable.pushDyn": { argTypes: [null, DYN], result: BOOL }, + "readable.unshift": { argTypes: [null, BYTES_U8], result: VOID }, + "readable.unshiftDyn": { argTypes: [null, DYN], result: VOID }, + "readable.unshiftStr": { argTypes: [null, STRING], result: VOID }, + "stream.onDyn": { argTypes: [null, STRING, DYN, BOOL, BOOL], result: VOID }, + "readable.readDyn": { argTypes: [null, DYN], result: DYN }, + "readable.read": { argTypes: [null, F64], result: VOID }, + "readable.pause": { argTypes: [null], result: VOID }, + "readable.setEncoding": { argTypes: [null, STRING], result: VOID }, + /** push(chunk, enc) with a literal non-utf8 encoding, and the + * defaultEncoding option's push side (how push(string) decodes — + * Buffer.from(chunk, enc)); both carry the CANONICAL literal. */ + "readable.pushStrEnc": { argTypes: [null, STRING, STRING], result: BOOL }, + "readable.pushEncoding": { argTypes: [null, STRING], result: VOID }, + /** The objectMode option's sides (readable, writable), applied right + * after construction; answers the receiver (+1, the chaining shape). */ + "stream.objectMode": { argTypes: [null, BOOL, BOOL], result: VOID }, + "stream.decodeStrings": { argTypes: [null, BOOL], result: VOID }, + /** Runtime decodeStrings and defaultEncoding option values, applied + * after construction (answers the receiver +1); the encoding was + * validated by stream.checkEncodingOption before construction. */ + "stream.optionValues": { argTypes: [null, DYN, DYN], result: VOID }, + "stream.checkEncodingOption": { argTypes: [DYN], result: VOID }, + "stream.duplexFromGen": { argTypes: [null, null, null, null, null, null], result: VOID }, + "stream.duplexFromDyn": { argTypes: [DYN], result: VOID }, + /** Duplex.from over a lone Readable or Writable, or a { readable, + * writable } pair of streams (duplexify.js's _duplexify). */ + "stream.duplexifyReadable": { argTypes: [null], result: VOID }, + "stream.duplexifyWritable": { argTypes: [null], result: VOID }, + "stream.duplexifyPair": { argTypes: [null, null], result: VOID }, + /** Duplex.from(promise): the promise and its box helper. */ + "stream.duplexFromPromise": { argTypes: [null, null], result: VOID }, + /** Duplex.from(asyncFunction): the stage, its source helper and the + * promise's box helper. */ + "stream.duplexFromAsyncFn": { argTypes: [null, null, null], result: VOID }, + /** The same for a body that declares the options argument: then the + * AbortController's abort() and its signal. */ + "stream.duplexFromGenSignal": { + argTypes: [null, null, null, null, null, null, null, DYN], + result: VOID, + }, + "stream.duplexFromAsyncFnSignal": { argTypes: [null, null, null, null, DYN], result: VOID }, + "writable.writeEncoding": { argTypes: [null, STRING], result: VOID }, + "writable.setDefaultEncoding": { argTypes: [null, DYN], result: VOID }, + /** Whether a readable.nextChunkDyn step answered the end (the done + * marker; an object-mode stream can yield undefined). */ + "stream.chunkDone": { argTypes: [DYN], result: BOOL }, + /** for-await over a readable (the desugared loop's per-pass promise): + * +1 promise of the next chunk — buffered content, the EOF sentinel + * (empty Buffer / dyn undefined), or a rejection with the stream's + * error. The Dyn twin boxes chunks by runtime tag (the JS lane). + * readable.fromArr is Readable.from over a typed array, string or + * Buffer: [array, SCR_FROM_* flags, highWaterMark]. readable.fromDyn is + * Readable.from over a checked-dynamic source: [source, options]. + * readable.fromIter is Readable.from over a class iterator, already + * opened: [checked-dynamic { next } object, flags, highWaterMark]; + * readable.fromAsyncIter is the async class iterator's twin. */ + "readable.nextChunk": { argTypes: [null], result: VOID }, + "readable.nextChunkDyn": { argTypes: [null], result: VOID }, + "readable.fromArr": { argTypes: [null, F64, F64], result: VOID }, + "readable.fromDyn": { argTypes: [DYN, DYN], result: VOID }, + "readable.fromIter": { argTypes: [DYN, F64, F64], result: VOID }, + "readable.fromAsyncIter": { argTypes: [DYN, F64, F64], result: VOID }, + /** Readable.from over a compiled generator: [generator, next, return, + * throw, flags, highWaterMark] (sync) or [generator, next, read, + * return, throw, flags, highWaterMark] (async), the helpers being the + * frontend's interned closures. readable.fromDone is the done marker + * the helpers answer. */ + "readable.fromGen": { argTypes: [null, null, null, null, F64, F64], result: VOID }, + "readable.fromAsyncGen": { argTypes: [null, null, null, null, null, F64, F64], result: VOID }, + "readable.fromDone": { argTypes: [], result: DYN }, + /** The Readable operators (scr_stream_ops.c): [stream, ...] with every + * other argument a checked-dynamic value (the callback, the count, the + * options). map/filter/flatMap/drop/take answer the object-mode output + * stream (validated as a stream class; THROW Node's validation errors); + * toArray settles a dyn array, find a dyn value, some/every a boolean, + * forEach nothing; reduce: [stream, fn, init, hasInit, options, kind] + * with the payload kind (0 dyn, 1 number, 2 boolean, 3 string). The + * promise-returning ones reject instead of throwing. */ + "readable.opMap": { argTypes: [null, DYN, DYN, DYN], result: VOID }, + "readable.opFilter": { argTypes: [null, DYN, DYN, DYN], result: VOID }, + "readable.opFlatMap": { argTypes: [null, DYN, DYN, DYN], result: VOID }, + /** flatMap whose callback returns a compiled generator: the helpers + * over its type follow (async: next, read, return, throw; sync: next, + * return, throw). */ + "readable.opFlatMapAsyncGen": { + argTypes: [null, DYN, DYN, DYN, null, null, null, null], + result: VOID, + }, + "readable.opFlatMapSyncGen": { + argTypes: [null, DYN, DYN, DYN, null, null, null], + result: VOID, + }, + "readable.opDrop": { argTypes: [null, DYN, DYN], result: VOID }, + "readable.opTake": { argTypes: [null, DYN, DYN], result: VOID }, + "readable.opToArray": { argTypes: [null, DYN], result: { kind: "promise", inner: DYN } }, + "readable.opForEach": { + argTypes: [null, DYN, DYN, DYN], + result: { kind: "promise", inner: VOID }, + }, + "readable.opSome": { + argTypes: [null, DYN, DYN, DYN], + result: { kind: "promise", inner: BOOL }, + }, + "readable.opEvery": { + argTypes: [null, DYN, DYN, DYN], + result: { kind: "promise", inner: BOOL }, + }, + "readable.opFind": { argTypes: [null, DYN, DYN, DYN], result: { kind: "promise", inner: DYN } }, + /** The map family's last argument is the callback's { signal } (or + * undefined). reduceSignal adds ac.abort() (a closure) and + * { signal: ac.signal } for a reducer that reads them. */ + "readable.opReduce": { argTypes: [null, DYN, DYN, BOOL, DYN, F64], result: VOID }, + "readable.opReduceSignal": { + argTypes: [null, DYN, DYN, BOOL, DYN, F64, null, DYN], + result: VOID, + }, + "readable.opSignalList": { argTypes: [DYN], result: DYN }, + "readable.opSignalOpts": { argTypes: [DYN], result: DYN }, + "readable.opSignalOf": { argTypes: [DYN], result: DYN }, + "readable.opOnceOptions": { argTypes: [], result: DYN }, + "readable.resume": { argTypes: [null], result: VOID }, + "readable.isPaused": { argTypes: [null], result: BOOL }, + "readable.pipe": { argTypes: [null, null, BOOL], result: VOID }, + "readable.pipeGeneral": { argTypes: [null, null, BOOL], result: VOID }, + "readable.unpipe": { argTypes: [null], result: VOID }, + "readable.flowing": { argTypes: [null], result: VOID }, + "writable.write": { argTypes: [null, BYTES_U8], result: BOOL }, + "writable.writeStr": { argTypes: [null, STRING], result: BOOL }, + "writable.writeU": { argTypes: [null, null], result: BOOL }, + "writable.writeDyn": { argTypes: [null, DYN], result: BOOL }, + "writable.writeEnc": { argTypes: [null, F64, DYN], result: BOOL }, + "writable.end": { argTypes: [null, F64], result: VOID }, + "writable.cork": { argTypes: [null], result: VOID }, + "writable.uncork": { argTypes: [null], result: VOID }, + "stream.destroy": { argTypes: [null], result: VOID }, + "stream.destroyErr": { argTypes: [null, null], result: VOID }, + /** AsyncIteratorClose for Readable[Symbol.asyncIterator](): destroy with + * Node's AbortError/ABORT_ERR payload while the iterator's internal error + * consumer prevents an unhandled-error crash. */ + "stream.iteratorClose": { argTypes: [null], result: VOID }, + "stream.prop": { argTypes: [null, STRING], result: VOID }, + "stream.errored": { argTypes: [null], result: VOID }, + // node:assert: pass/negated/deep/hasMsg are frontend-computed bools; the + // message slot always carries a string ("" when hasMsg is false). + /** node:assert (scr_assert.c; assert.match in scr_regex.c — every call + * site carries a regex value, so the regex link switch is already on). + * Failures throw a catchable AssertionError — a runtime %Error whose + * name is "AssertionError" and whose code slot is "ERR_ASSERTION" — so + * `instanceof Error`, `.name`, `.message`, and `.code` all answer like + * Node's. Generated messages are Node's assertion_error.js scalar forms + * byte-exactly (the short `a !== b` form, the stacked `+ actual + * - expected` diff with the string `^` indicator, the inline-vs-block + * not-equal split); composite deep failures carry the header line + * without the rendered inspect diff (documented divergence). + * + * assert.ok: (pass, message) — the frontend computed the truthiness AND + * the full message (the user's, or the compile-time source-text form — + * assert.fail lowers here too with pass=false). assert.eqF64/eqBigInt/ + * eqStr/eqBool: (a, b, negated, deep, msg, hasMsg) — Object.is comparison, + * covering strictEqual/notStrictEqual and the scalar deepStrictEqual + * pair; msg is a typed dummy ("" literal) when hasMsg is false (Node + * distinguishes an omitted message from an empty one per operator). + * assert.deepResult: (equal, negated, msg, hasMsg) — the verdict of a + * frontend-synthesized structural comparison, turned into Node's throw. + * assert.sameValue: Object.is over doubles (the deep-equal helpers' + * number leaf; never throws). assert.match: (s, regex, negated, msg, + * hasMsg) — a fresh exec from index 0. assert.throwsNone: (rejection, + * ename, hasEname, msg, hasMsg) — the "Missing expected + * exception|rejection" throw of assert.throws/rejects whose callback + * returned (fulfilled) normally, with Node's ` (${expected.name})` + * detail when the expected class or shape carries a name. + * assert.throwsMismatch: (expectedName, error) — the wrong-class throw + * of the assert.throws(fn, ErrorClass) form. assert.eqSym: + * (a, b, negated, deep, msg, hasMsg) — strict equality over symbol + * values, pointer identity with v24's "Symbol(desc)" stacked-diff + * messages (scr_symbol.c, the assert.match pattern — symbol-typed + * slots already flip the symbol link switch). assert.eqDyn: + * (a, b, negated, deep, msg, hasMsg) — the whole quartet over + * checked-dynamic operands (both slots dyn; the frontend boxes a + * static side with dynFrom first): SameValue for the strict pair over + * the dyn kinds (boxed-closure identity for functions), the structural + * dyn walk for the deep pair, with assertion_error.js's messages — + * scalar forms byte-exact, composites rendered compact:false/sorted + * through the checked-dynamic tree and diffed with the real myers line printer. + * + * The assert.throws(fn, {name/code/message}) shape check + * (expectedException over the static error surface): shapeBegin + * stashes the caught error, shapeStr/shapeRe add one expected key each + * (key ids 0 code / 1 message / 2 name; shapeRe lives in scr_regex.c — + * its regex argument flips the regex link switch — and tests eagerly + * so scr_assert.c stays libregexp-free), then shapeEnd throws Node's + * deep-equal Comparison diff BYTE-EXACTLY (the bounded key set makes + * the rendering enumerable) or the custom message. + * assert.throwsRegex: (regex, error, msg, hasMsg) — the + * assert.throws(fn, /re/) check over String(error), Node's + * regex-mismatch message. assert.regexErrTest: doesNotReject's + * regex predicate over String(error) (never throws). + * assert.unwantedRejection: (error, msg, hasMsg) — doesNotReject's + * "Got unwanted rejection" throw. + * assert.ifErrorErr/F64/Str/Bool: assert.ifError's per-type throws + * ("ifError got unwanted exception: " + the error's message/name or + * the value's inspection) — the frontend routes null/undefined to a + * no-op and everything else here (Node throws for falsy values too). + * All arguments are borrowed. */ + "assert.ok": { argTypes: [BOOL, STRING, BOOL], result: VOID }, + /** The next AssertionError's actual, expected and operator, recorded on + * a failure branch. */ + "assert.record": { argTypes: [DYN, DYN, STRING], result: VOID }, + "assert.errorNew": { + argTypes: [DYN], + result: { kind: "object", className: "%AssertionError" }, + }, + "assert.eqF64": { argTypes: [F64, F64, BOOL, BOOL, STRING, BOOL], result: VOID }, + "assert.eqBigInt": { argTypes: [BIGINT_T, BIGINT_T, BOOL, BOOL, STRING, BOOL], result: VOID }, + "assert.eqStr": { argTypes: [STRING, STRING, BOOL, BOOL, STRING, BOOL], result: VOID }, + "assert.eqBool": { argTypes: [BOOL, BOOL, BOOL, BOOL, STRING, BOOL], result: VOID }, + "assert.deepResult": { argTypes: [BOOL, BOOL, STRING, BOOL], result: VOID }, + "assert.looseDeepResult": { argTypes: [BOOL, BOOL, STRING, BOOL], result: VOID }, + "assert.looseDeepDyn": { argTypes: [DYN, DYN, BOOL, STRING, BOOL], result: VOID }, + "assert.partialDeepDyn": { argTypes: [DYN, DYN, STRING, BOOL], result: VOID }, + "assert.partialDeepResult": { argTypes: [BOOL, BOOL, STRING, BOOL], result: VOID }, + "assert.partialEqDyn": { argTypes: [DYN, DYN], result: BOOL }, + "assert.looseF64Eq": { argTypes: [F64, F64], result: BOOL }, + "assert.sameValue": { argTypes: [F64, F64], result: BOOL }, + // The deep-equality pair memo: both slots are program-dependent + // (any cycle-capable record/array/map type). + /* deepStrictEqual's pair memo over cycle-capable types: enter answers + * true for a pair already being compared (Node's memo — equal cyclic + * structures compare true); leave pops. */ + "assert.deqEnter": { argTypes: [null, null], result: BOOL }, + "assert.deqLeave": { argTypes: [], result: VOID }, + "assert.match": { argTypes: [STRING, REGEX, BOOL, STRING, BOOL], result: VOID }, + "assert.throwsNone": { argTypes: [BOOL, STRING, BOOL, STRING, BOOL], result: VOID }, + "assert.throwsMismatch": { + argTypes: [STRING, { kind: "object", className: "%Error" }, STRING, BOOL, BOOL], + result: VOID, + }, + "assert.throwsRegex": { + argTypes: [REGEX, { kind: "object", className: "%Error" }, STRING, BOOL, BOOL], + result: VOID, + }, + // Symbol strict equality (pointer identity; scr_symbol.c). + "assert.eqSym": { + argTypes: [{ kind: "symbol" }, { kind: "symbol" }, BOOL, BOOL, STRING, BOOL], + result: VOID, + }, + // The equality quartet over checked-dynamic operands (the frontend + // boxes a static side into the checked-dynamic tree first). + "assert.eqDyn": { argTypes: [DYN, DYN, BOOL, BOOL, STRING, BOOL], result: VOID }, + /** A message argument that is not a string, registered for the next + * failing assertion (scr_assert_message_value). */ + "assert.messageValue": { argTypes: [DYN, BOOL], result: VOID }, + /** An assert method as a function value, by canonical name. */ + "assert.methodValue": { argTypes: [STRING], result: DYN }, + "assert.messageClear": { argTypes: [], result: VOID }, + "assert.looseResult": { argTypes: [BOOL, BOOL, STRING, STRING, STRING, BOOL], result: VOID }, + // The throws(fn, {shape}) accumulator: begin/slot calls never throw; + // shapeEnd throws the Comparison diff. The error slot is the + // %Error-narrowed caught value. + "assert.shapeBegin": { argTypes: [{ kind: "object", className: "%Error" }], result: VOID }, + "assert.shapeStr": { argTypes: [F64, STRING], result: VOID }, + "assert.shapeRe": { argTypes: [F64, REGEX], result: VOID }, + "assert.shapeEnd": { argTypes: [STRING, BOOL, BOOL], result: VOID }, + "assert.regexErrTest": { + argTypes: [REGEX, { kind: "object", className: "%Error" }], + result: BOOL, + }, + "assert.unwantedRejection": { + argTypes: [{ kind: "object", className: "%Error" }, STRING, BOOL], + result: VOID, + }, + "assert.unwantedError": { argTypes: [STRING, BOOL, STRING, BOOL], result: VOID }, + "assert.noErrorPredicate": { argTypes: [DYN, DYN], result: BOOL }, + "assert.regexDynTest": { argTypes: [REGEX, DYN], result: BOOL }, + /** Node's expectsError over an error-INSTANCE expected (assert.throws/ + * rejects second argument): walk the expected dyn error's keys (name, + * message, code — the %error marker skipped) and deep-compare each + * against the caught value's; a mismatch throws the deep-equal + * AssertionError (scr_assert.c). MAY THROW by design. */ + "assert.expectsErrDyn": { argTypes: [DYN, DYN, STRING, BOOL], result: VOID }, + /** A validation function against the caught value (Node's expectedException). */ + "assert.throwsValidate": { argTypes: [DYN, DYN, STRING, STRING, BOOL], result: VOID }, + // assert.ifError's typed entries (always throw; unit args never + // lower). The error slot is program-dependent — any %Error-hierarchy + // class, root or subclass (the insp.error precedent, null slot). + "assert.ifErrorErr": { argTypes: [null], result: VOID }, + "assert.ifErrorF64": { argTypes: [F64], result: VOID }, + "assert.ifErrorStr": { argTypes: [STRING], result: VOID }, + "assert.ifErrorBool": { argTypes: [BOOL], result: VOID }, + "assert.ifErrorDyn": { argTypes: [DYN], result: VOID }, + // Bytes equality: the two value slots are any bytes kind (the frontend + // gates both sides to ONE static bytes type; the libCall case checks + // the kind and the pair below). + "assert.refEqBytes": { argTypes: [null, null, BOOL, BOOL, STRING, BOOL], result: VOID }, + "assert.refEqFn": { argTypes: [null, null, BOOL, STRING, BOOL], result: VOID }, + "assert.bytesDeepEq": { argTypes: [null, null, BOOL], result: BOOL }, + "assert.looseBytesEq": { argTypes: [null, null], result: BOOL }, + // util.inspect: the error receiver is program-dependent (a builtin or + // user error class — the error.toString precedent, null slot). - "insp.f64": { argTypes: [F64], result: STRING }, - /** util.format %j over a checked-dynamic argument: the runtime dyn - * walk (JS-exact stringify; root undefined/function prints - * "undefined"; a handle in the tree throws the "not supported yet" - * Error). */ - "insp.jsonDyn": { argTypes: [DYN], result: STRING }, - "insp.str": { argTypes: [STRING], result: STRING }, - "insp.regex": { argTypes: [REGEX], result: STRING }, - /** A Date's inspect text: toISOString(), or "Invalid Date". */ - "insp.date": { argTypes: [DATE_T], result: STRING }, - "insp.buffer": { argTypes: [BYTES_U8], result: STRING }, - /** A numeric typed array that is not a Buffer (any element kind). */ - "insp.typedArray": { argTypes: [null, F64, F64], result: STRING }, - /** A u8 byte view in a union arm, element or field: a DataView, Buffer - * or Uint8Array by its own flags. */ - "insp.bytes": { argTypes: [null, F64, F64], result: STRING }, - "insp.error": { argTypes: [null, F64, F64], result: STRING }, - "insp.errorHasCause": { argTypes: [null], result: BOOL }, - "insp.errorBagHasProperties": { argTypes: [DYN], result: BOOL }, - "insp.errorCause": { argTypes: [null, F64, F64], result: STRING }, - "insp.dyn": { argTypes: [DYN, F64, F64], result: STRING }, - "insp.dynS": { argTypes: [DYN, F64], result: STRING }, - /** util.format's %o over a checked-dynamic value: inspect with - * showHidden. Kinds whose hidden entries have no rendering throw the - * 'not supported yet' Error. */ - "insp.dynHidden": { argTypes: [DYN, F64], result: STRING }, - "insp.begin": { argTypes: [F64], result: VOID }, - /** util.inspect's breakLength, compact (0 for false) and sorted for the - * renders that follow; the call site restores 80, 3 and false afterwards. */ - "insp.layout": { argTypes: [F64, F64, BOOL], result: VOID }, - "insp.entry": { argTypes: [STRING, BOOL], result: VOID }, - // Circular references: the receiver slot is program-dependent (any - // cycle-capable record/array/map/class type — the insp.error precedent). - /* Circular references over cycle-capable composites (recursive record/ - * class types): circCheck answers a value's circular id when it is - * already on the traversal stack (0 otherwise), seenPush/refWrap - * bracket the frame (insp.end adds Node's " " prefix to values - * the walk found circular), circular renders "[Circular *N]". */ - "insp.circCheck": { argTypes: [null], result: F64 }, - "insp.seenPush": { argTypes: [null], result: VOID }, - "insp.refWrap": { argTypes: [null, STRING], result: STRING }, - "insp.circular": { argTypes: [F64], result: STRING }, - /* Whether a closed declared-field record kept the undeclared properties - * of its checked source (scr_record_source_note): reflective surfaces - * (inspect, Object.keys/values/entries) then answer through its live - * checked view. The receiver is any such record type. Never throws. */ - "record.sourceHas": { argTypes: [null], result: BOOL }, - /** `record.sourceSpread(built, value)`: the record a literal starting - * with `...value` just built keeps the order of value's kept source - * (key-order-witness.ts ordered spreads). Both are record types. Never - * throws. */ - "record.sourceSpread": { argTypes: [null, null], result: VOID }, - "insp.key": { argTypes: [STRING], result: STRING }, - "insp.moreItems": { argTypes: [F64], result: STRING }, - "insp.end": { argTypes: [STRING, STRING, STRING, F64, BOOL, BOOL], result: STRING }, - /** A nested inspect inside a custom rendering (PerformanceEntry's - * `${name} ${inspect(toJSON)}`): nestedBegin starts a fresh inspect - * context, nestedEnd(prefix, inner) restores the caller's and answers - * `prefix inner` re-indented at the caller's level (+1). */ - "insp.nestedBegin": { argTypes: [], result: VOID }, - "insp.nestedEnd": { argTypes: [STRING, STRING], result: STRING }, - /** Around a top-level render that an inspection refusal can end: mark - * records the inspector's frame and nesting depth, unwind (in the - * render's finally) closes what the render left open above it. */ - "insp.mark": { argTypes: [], result: VOID }, - "insp.unwind": { argTypes: [], result: VOID }, - /** node:string_decoder's utf8 StringDecoder (scr_string.c): the decoder - * value is a one-field record whose f64 PACKS the pending partial - * sequence (count + up to 3 raw bytes — Node buffers at most 3 for - * every encoding); the frontend's interned %strdec helpers thread it, - * with the decoder's CANONICAL encoding name first, through these pure - * functions. write: (enc, pending, chunk) → the decoded complete - * prefix of pending+chunk (+1); next: (enc, pending, chunk) → the - * packed NEW pending; end: (enc, pending) → the buffered partial's - * flush (+1). Node-exact per encoding (oracle-pinned); none throws. */ - "strdec.write": { argTypes: [STRING, F64, BYTES_U8], result: STRING }, - "strdec.next": { argTypes: [STRING, F64, BYTES_U8], result: F64 }, - "strdec.end": { argTypes: [STRING, F64], result: STRING }, - /** A runtime encoding argument's canonical name (Node's normalizeEncoding: - * nullish and "" are utf8); an unknown name throws ERR_UNKNOWN_ENCODING. */ - "strdec.encoding": { argTypes: [DYN], result: STRING }, - // node:readline: the interface handle is f64; the callbacks' func types - // are program-dependent (the emitter picks the adapter by parameter - // count), so those slots are null like child.onExit's. - /** node:readline and node:readline/promises (scr_readline.c, linked - * under the events gate — these fns imply moduleUsesProcessEvents; a - * stream input or output adds scr_stream.c's bridge). The interface - * value is an f64 handle (the Timeout-id precedent); an open interface - * on stdin keeps the loop alive until close/EOF. - * rl.create: [mode, input?, output?, crlfDelay, prompt?] → f64, mode - * bits 1 stream input, 2 stream output, 4 stdout output, 16 prompt - * (lowerReadlineCreateCall); rl.createSignal: the same plus the - * trailing AbortSignal (mode bit 8), which links the event-target unit - * for addAbortListener. rl.question: [handle, query, cb] — the callback - * form; THROWS ERR_USE_AFTER_CLOSE on a closed interface (may-throw). - * rl.questionAsync(Signal): [handle, query, signal?] → promise, - * rejecting instead of throwing. rl.close/pause/resume/prompt: - * [handle] (pause/resume/prompt throw ERR_USE_AFTER_CLOSE when - * closed); rl.setPrompt/getPrompt; rl.write: [handle, data] (throws - * when closed). rl.on: [handle, event, cb, once] — the event number - * (0 'line', 1 'close', 2 'pause', 3 'resume', 4 'error') and the - * listener (moves). rl.iterOpen/iterNext/iterReturn: the async - * iterator — iterNext answers promise of the line or undefined. */ - "rl.create": { argTypes: [F64], result: F64 }, - "rl.createSignal": { argTypes: [F64], result: F64 }, - "rl.question": { argTypes: [F64, STRING, null], result: VOID }, - "rl.questionAsync": { argTypes: [F64, STRING], result: { kind: "promise", inner: STRING } }, - "rl.questionAsyncSignal": { - argTypes: [F64, STRING, DYN], - result: { kind: "promise", inner: STRING }, - }, - /** The question forms with a checked-dynamic query (a JavaScript value - * that need not be a string). */ - "rl.questionDyn": { argTypes: [F64, DYN, null], result: VOID }, - "rl.questionAsyncDyn": { argTypes: [F64, DYN], result: { kind: "promise", inner: STRING } }, - "rl.questionAsyncSignalDyn": { - argTypes: [F64, DYN, DYN], - result: { kind: "promise", inner: STRING }, - }, - "rl.close": { argTypes: [F64], result: VOID }, - "rl.pause": { argTypes: [F64], result: VOID }, - "rl.resume": { argTypes: [F64], result: VOID }, - "rl.prompt": { argTypes: [F64], result: VOID }, - /** prompt(preserveCursor): [handle, preserveCursor] */ - "rl.promptWith": { argTypes: [F64, BOOL], result: VOID }, - "rl.setPrompt": { argTypes: [F64, STRING], result: VOID }, - "rl.setPromptDyn": { argTypes: [F64, DYN], result: VOID }, - "rl.getPrompt": { argTypes: [F64], result: STRING }, - "rl.write": { argTypes: [F64, STRING], result: VOID }, - /** write(data, key): [handle, hasData, data, hasKey, hasName, name, - * ctrl, meta, shift] */ - "rl.writeKey": { - argTypes: [F64, BOOL, STRING, BOOL, BOOL, STRING, BOOL, BOOL, BOOL], - result: VOID, - }, - "rl.on": { argTypes: [F64, F64, null, BOOL], result: VOID }, - "rl.iterOpen": { argTypes: [F64], result: VOID }, - "rl.iterNext": { argTypes: [F64], result: { kind: "promise", inner: DYN } }, - "rl.iterReturn": { argTypes: [F64], result: VOID }, - /** createInterface's history and editing options (scr_rl_check_options: - * [flags, tabSize, escapeCodeTimeout, historySize], may throw; - * rl.setOptions: [handle, flags, historySize, removeHistoryDuplicates, - * tabSize, escapeCodeTimeout]; rl.setHistory: [handle, history]) and - * the member reads (rl.history answers the array, rl.numProp the - * numeric member by number). */ - "rl.checkOptions": { argTypes: [F64, F64, F64, F64], result: VOID }, - "rl.checkCompleter": { argTypes: [DYN], result: VOID }, - "rl.setOptions": { argTypes: [F64, F64, F64, BOOL, F64, F64], result: VOID }, - "rl.setHistory": { argTypes: [F64, arrayOf(STRING)], result: VOID }, - "rl.history": { argTypes: [F64], result: arrayOf(STRING) }, - "rl.numProp": { argTypes: [F64, F64], result: F64 }, - /** Terminal mode (scr_readline_tty.c): rl.terminal: [handle, mode (0 - * the option's value, 2 output.isTTY of process.stdout), terminal, - * completer (undefined when absent), readline/promises], emitted with - * scr_insp_dyn when there is a completer; the line, terminal and cursor - * members. */ - "rl.terminal": { argTypes: [F64, F64, BOOL, DYN, BOOL], result: VOID }, - "rl.line": { argTypes: [F64], result: STRING }, - "rl.isTerminal": { argTypes: [F64], result: BOOL }, - "rl.isPromises": { argTypes: [F64], result: BOOL }, - /** createInterface's input or output as a checked-dynamic value: - * [value, output] — the stream; refused when it is not one. */ - "rl.inputFromDyn": { argTypes: [DYN, BOOL], result: { kind: "object", className: "%Readable" } }, - "rl.outputFromDyn": { - argTypes: [DYN, BOOL], - result: { kind: "object", className: "%Writable" }, - }, - "rl.cursor": { argTypes: [F64], result: F64 }, - /** readline.cursorTo / moveCursor / clearLine / clearScreenDown: rl.seq - * [kind (0-3), the first and second numbers, whether the second is - * given] answers the data to write after the argument checks (may - * throw); rl.moves [dx, dy] says whether moveCursor writes. */ - "rl.seq": { argTypes: [F64, F64, F64, BOOL], result: STRING }, - "rl.moves": { argTypes: [F64, F64], result: BOOL }, - /** getCursorPos() (scr_readline_tty.c, linked through the regex unit - * like rl.terminal): [handle, 0 rows | 1 cols] */ - "rl.cursorPos": { argTypes: [F64, F64], result: F64 }, - /** readline.emitKeypressEvents (scr_readline_tty.c): rl.keypressStdin - * [interface (0: none), escapeCodeTimeout (NaN: the interface's or - * 500)], rl.keypressStream [stream, interface, timeout]. */ - "rl.keypressStdin": { argTypes: [F64, F64], result: VOID }, - "rl.keypressStream": { argTypes: [null, F64, F64], result: VOID }, - /** readline/promises Readline over an f64 handle: rl.uiOpen [fd (1 - * stdout, 2 stderr), autoCommit], rl.uiOpenStream [stream, autoCommit] - * (isWritable, may throw); the actions take [handle, ...numbers] (the - * checks may throw; cursorTo: [handle, x, whether y is given, y]); - * rl.uiCommit answers a promise. */ - "rl.uiOpen": { argTypes: [F64, BOOL], result: F64 }, - "rl.uiOpenStream": { argTypes: [null, BOOL], result: F64 }, - "rl.uiCursorTo": { argTypes: [F64, F64, BOOL, F64], result: VOID }, - "rl.uiMoveCursor": { argTypes: [F64, F64, F64], result: VOID }, - "rl.uiClearLine": { argTypes: [F64, F64], result: VOID }, - "rl.uiClearScreenDown": { argTypes: [F64], result: VOID }, - "rl.uiRollback": { argTypes: [F64], result: VOID }, - "rl.uiCommit": { argTypes: [F64], result: { kind: "promise", inner: VOID } }, - /** node:timers/promises — the promisified pair (scr_async.c, beside - * the timer heap they ride): tp.setTimeout: [ms] → a pending void - * promise a one-shot heap timer fulfills (the loop's timer phase, FIFO - * against equal deadlines like Node); tp.setImmediate: [] → the same - * through the immediate queue (fires before due timers of later loop - * turns, Node's check phase). Neither throws. */ - "tp.setTimeout": { argTypes: [F64], result: { kind: "promise", inner: VOID } }, - // scheduler.wait(delay): tp.setTimeout's promise. It throws Node's - // ERR_INVALID_THIS once mock.timers has restored the real scheduler.wait. - "tp.schedulerWait": { argTypes: [F64], result: { kind: "promise", inner: VOID } }, - "tp.setImmediate": { argTypes: [], result: { kind: "promise", inner: VOID } }, - /** events.once (scr_events_emitter.c): [emitter, name, boxer, - * errorBoxer, listenForError] → a pending promise of any[]; the boxers - * turn the event's and the 'error' tuple into that array. */ - "events.once": { argTypes: [null, STRING, null, null, BOOL], result: VOID }, - /** events.once(emitter, name, { signal }) (scr_events_once_signal.c): - * events.once's arguments plus the checked-dynamic signal (an - * AbortSignal or undefined). */ - "events.onceSignal": { argTypes: [null, STRING, null, null, BOOL, DYN], result: VOID }, - /** The resolve-value forms: [ms?, value, ref] → a pending promise of the - * value's type that copies the borrowed already-resolved `value` promise - * when the timer (or immediate) fires; ref false unrefs it. The result - * type follows the value promise. */ - "tp.setTimeoutValue": { argTypes: [F64, null, BOOL], result: VOID }, - "tp.setImmediateValue": { argTypes: [null, BOOL], result: VOID }, - /** The same with options.signal (a checked-dynamic AbortSignal or - * undefined) last: an abort clears the timer and rejects with an - * AbortError (scr_event_target.c). */ - "tp.setTimeoutSignal": { argTypes: [F64, null, BOOL, DYN], result: VOID }, - "tp.setImmediateSignal": { argTypes: [null, BOOL, DYN], result: VOID }, - /** scheduler.wait(delay, options): tp.setTimeoutValue's and - * tp.setTimeoutSignal's shapes, with tp.schedulerWait's throws. */ - "tp.schedulerWaitValue": { argTypes: [F64, null, BOOL], result: VOID }, - "tp.schedulerWaitSignal": { argTypes: [F64, null, BOOL, DYN], result: VOID }, - /** node:diagnostics_channel (scr_dc.c, linked when any dc.* appears — - * the zlib gating precedent): a process-global name→channel registry; - * channel values are f64 handles (type-mapper.ts maps Channel to F64, the - * readline.Interface pattern). Subscribers are dyn function values — - * identity-compared by unsubscribe, called (message, name) by publish - * over a SNAPSHOT of the list (a subscriber unsubscribing itself - * mid-publish still lets its siblings fire, Node's behavior). dc.publish - * MAY THROW: a subscriber's throw propagates out of publish (catchable - * there) where Node routes it to triggerUncaughtException — the - * documented divergence. subscribe/unsubscribe throw Node's - * ERR_INVALID_ARG_TYPE TypeError for non-function subscribers. */ - "dc.channel": { argTypes: [STRING], result: F64 }, - "dc.subscribe": { argTypes: [STRING, DYN], result: VOID }, - "dc.unsubscribe": { argTypes: [STRING, DYN], result: BOOL }, - "dc.hasSubscribers": { argTypes: [STRING], result: BOOL }, - "dc.publish": { argTypes: [F64, DYN], result: VOID }, - "dc.chanSubscribe": { argTypes: [F64, DYN], result: VOID }, - "dc.chanUnsubscribe": { argTypes: [F64, DYN], result: BOOL }, - "dc.chanHasSubscribers": { argTypes: [F64], result: BOOL }, - "dc.chanName": { argTypes: [F64], result: STRING }, - /** TracingChannel (dc.tracingChannel): a registry entry of the five - * event channels, an f64 handle like Channel (type-mapper.ts). tcSubscribe/ - * tcUnsubscribe walk a dyn handlers object's five event keys (truthy - * non-function slots throw the per-channel ERR_INVALID_ARG_TYPE); - * tcTraceSync/tcTraceCallback/tcTracePromise run Node's publish choreography in C over - * dyn values (fn, ctx, thisArg, args-array) with thisArg bound as the - * ambient receiver — the traced call's throw and any subscriber throw - * both propagate (MAY THROW). tcTraceCallback wraps args[position] in a - * native error/result + asyncStart/asyncEnd publisher and throws Node's - * TypeError when that slot is not callable. tracingChannelOf is the - * five-Channel collection form of the constructor. */ - /** setImmediate as a first-class dyn value (scr_async.c): a minted dyn - * callable scheduling args[0](args[1..]) on the immediate queue — the - * Node-suite traceCallback shape (`traceCallback(setImmediate, ...)`). - * Calling it validates the callback (the dyn call machinery); minting - * never throws. */ - "timers.setImmediateFnValue": { argTypes: [], result: DYN }, - /** `new Promise(setImmediate)` (the Node-suite early-exit shape): a - * fresh promise an immediate fulfills with the undefined dyn value — - * the executor IS setImmediate, so resolve rides the immediate queue - * (scr_async.c). Never throws. */ - "timers.immediatePromise": { argTypes: [], result: { kind: "promise", inner: DYN } }, - "dc.tracingChannel": { argTypes: [STRING], result: F64 }, - "dc.tracingChannelOf": { argTypes: [F64, F64, F64, F64, F64], result: F64 }, - "dc.tcChannel": { argTypes: [F64, F64], result: F64 }, - "dc.tcHasSubscribers": { argTypes: [F64], result: BOOL }, - "dc.tcSubscribe": { argTypes: [F64, DYN], result: VOID }, - "dc.tcUnsubscribe": { argTypes: [F64, DYN], result: BOOL }, - "dc.tcTraceSync": { argTypes: [F64, DYN, DYN, DYN, DYN], result: DYN }, - "dc.tcTraceCallback": { argTypes: [F64, DYN, F64, DYN, DYN, DYN], result: DYN }, - /** tracePromise (scr_dc.c): start publish, the traced call, a wrap of - * non-promise results, the end publish, and a REACTION FIBER that - * awaits the traced promise and publishes asyncStart/asyncEnd (error - * first on rejection) before settling the returned promise with - * the passed-through outcome. MAY THROW (the traced call and the - * synchronous publishes). */ - "dc.tcTracePromise": { - argTypes: [F64, DYN, DYN, DYN, DYN], - result: { kind: "promise", inner: DYN }, - }, - /** process.on/once('unhandledRejection', fn): registers a dyn listener - * the checkpoint report dispatches per never-observed rejection — - * (reason, promise) — instead of printing and exiting 1 (scr_async.c). - * The bool second arg is `once` (auto-removed after one delivery, - * Node's once); off/removeListener remove by closure identity, the - * offWarning stance. Throws Node's ERR_INVALID_ARG_TYPE on a - * non-function. */ - /** Uncaught exception handlers and monitors: [callback dyn, once, monitor]. */ - "process.onUncaughtException": { argTypes: [DYN, BOOL, BOOL], result: VOID }, - "process.offUncaughtException": { argTypes: [DYN, BOOL], result: VOID }, - "process.onUnhandledRejection": { argTypes: [DYN, BOOL], result: VOID }, - "process.offUnhandledRejection": { argTypes: [DYN], result: VOID }, - /** process.on/once/off('rejectionHandled', fn): the sibling registry. - * A handler attached after unhandledRejection delivery fires the event - * once. Dispatch is synchronous at the attach, with the promise, - * Node's payload. */ - "process.onRejectionHandled": { argTypes: [DYN, BOOL], result: VOID }, - "process.offRejectionHandled": { argTypes: [DYN], result: VOID }, - /** process warnings (scr_async_dyn.c): onWarning/offWarning register - * dyn listeners; emitWarning applies Node's full argument grammar over - * the call's dyn argument vector (ERR_INVALID_ARG_TYPE TypeErrors — MAY - * THROW) and emits on the next tick, like Node: Node's stderr report, - * then the listeners. */ - "process.onWarning": { argTypes: [DYN], result: VOID }, - "process.offWarning": { argTypes: [DYN], result: VOID }, - "process.emitWarning": { argTypes: [DYN], result: VOID }, - /** A Warning-typed process warning with this message (the console - * members' warnings), emitted on the next tick as Node's emitWarning - * does (so the loop runs); an empty message emits nothing. */ - "process.emitWarningText": { argTypes: [STRING], result: VOID }, - /** process.noDeprecation (0) / process.throwDeprecation (1): the stored - * value (undefined until assigned) and its assignment. util.deprecate's - * warnings and DeprecationWarning emissions read their truthiness. */ - "process.deprecationFlag": { argTypes: [F64], result: DYN }, - "process.setDeprecationFlag": { argTypes: [F64, DYN], result: VOID }, - "process.setEmitWarning": { argTypes: [DYN], result: VOID }, - /** AsyncLocalStorage (node:async_hooks — scr_async.c): stores are f64 - * handles; contexts are immutable fiber-carried snapshots (spawned - * fibers inherit the spawner's — Node's init-time capture). run/exit - * enter (or clear) the store, call the dyn function with forwarded - * arguments, and restore (the finally); getStore answers the current - * dyn value or undefined; enterWith installs with no restore point. - * run/exit MAY THROW (the callback's own throws propagate). */ - /** `await v` over a checked-dynamic VALUE (scr_async.c): a dyn promise - * adopts (rejections re-throw — MAY THROW), anything else takes JS's - * one-microtask non-thenable await and answers itself. Only emitted - * inside async bodies (the frontend's isAsync gate). */ - "async.awaitDyn": { argTypes: [DYN], result: DYN }, - /** The bare one-microtask hop (scr_await_hop): `await v` over a typed - * NON-promise value — JS awaits non-thenables through exactly one - * microtask turn and yields the value itself. Never throws. */ - "async.hop": { argTypes: [], result: VOID }, - "als.new": { argTypes: [], result: F64 }, - "als.get": { argTypes: [F64], result: DYN }, - "als.run": { argTypes: [F64, DYN, DYN, DYN], result: DYN }, - "als.exitRun": { argTypes: [F64, DYN, DYN], result: DYN }, - "als.enterWith": { argTypes: [F64, DYN], result: VOID }, - "als.disable": { argTypes: [F64], result: VOID }, - /** new AsyncLocalStorage(options) (Node's object check throws; MAY - * THROW) and the store's name option (dyn; "" without one). */ - "als.newOptions": { argTypes: [DYN], result: F64 }, - "als.name": { argTypes: [F64], result: DYN }, - /** A function bound to the active context: the completion callbacks of - * callback-style APIs (always false: an empty context leaves the - * callback unbound) and AsyncLocalStorage.bind (always true). The typed - * form answers its closure argument's type; the dyn form throws Node's - * ERR_INVALID_ARG_TYPE for a non-function when always (MAY THROW). */ - "als.bindCallback": { argTypes: [null, BOOL], result: VOID }, - "als.bindCallbackDyn": { argTypes: [DYN, BOOL], result: DYN }, - /** AsyncLocalStorage.snapshot(): a dyn function (cb, ...args) that runs - * cb in the context active at the snapshot. */ - "als.snapshot": { argTypes: [], result: DYN }, - /** Channel.bindStore/unbindStore/runStores (scr_dc.c): the - * AsyncLocalStorage integration — set-semantics bindings per store, - * runStores entering every bound store with transform(data) around the - * publish and the callback (MAY THROW: transforms, subscribers, and - * the callback all run). */ - "dc.chanBindStore": { argTypes: [F64, F64, DYN], result: VOID }, - "dc.chanUnbindStore": { argTypes: [F64, F64], result: BOOL }, - "dc.chanRunStores": { argTypes: [F64, DYN, DYN, DYN, DYN], result: DYN }, - /** The Number statics with a static C implementation (scr_lib.c): one - * f64 arg → bool, JS-exact BY CONSTRUCTION — Number.isFinite/isNaN/ - * isInteger/isSafeInteger never coerce, and the frontend routes only - * f64-typed arguments here (other static types fence). None throws. */ - "number.isFinite": { argTypes: [F64], result: BOOL }, - "number.isNaN": { argTypes: [F64], result: BOOL }, - "number.isInteger": { argTypes: [F64], result: BOOL }, - "number.isSafeInteger": { argTypes: [F64], result: BOOL }, - /** Date (scr_lib.c). Values are TimeClip'd epoch-millisecond scalars: - * construction/store/pass/getters are exact while identity and mutation - * remain fenced. date.now is Node's integer milliseconds since epoch; - * date.toISOString formats one raw f64 millisecond time value and - * date.toISOStringValue formats a stored Date, both with Node's rules (UTC, - * YYYY-MM-DDTHH:mm:ss.sssZ, expanded ±YYYYYY years outside 0–9999, - * ToInteger truncation of fractional ms) and THROWS Node's "Invalid - * time value" RangeError on NaN / out-of-range input (may-throw seed). - * Results: f64 / owned (+1) string. */ - "date.now": { argTypes: [], result: F64 }, - "date.newNow": { argTypes: [], result: DATE_T }, - "date.newMs": { argTypes: [F64], result: DATE_T }, - "date.newString": { argTypes: [STRING], result: DATE_T }, - /** Date.parse(dateString), with its own reach witness for exact fences. */ - "date.parse": { argTypes: [STRING], result: F64 }, - "date.getTime": { argTypes: [DATE_T], result: F64 }, - "date.valueOf": { argTypes: [DATE_T], result: F64 }, - "date.toISOString": { argTypes: [F64], result: STRING }, - "date.toISOStringValue": { argTypes: [DATE_T], result: STRING }, - /** Date.prototype.toUTCString over a stored Date ("Invalid Date" for - * NaN; never throws). */ - "date.toUTCString": { argTypes: [DATE_T], result: STRING }, - "date.getFullYear": { argTypes: [DATE_T], result: F64 }, - "date.getUTCFullYear": { argTypes: [DATE_T], result: F64 }, - "date.getMonth": { argTypes: [DATE_T], result: F64 }, - "date.getUTCMonth": { argTypes: [DATE_T], result: F64 }, - "date.getDate": { argTypes: [DATE_T], result: F64 }, - "date.getUTCDate": { argTypes: [DATE_T], result: F64 }, - "date.getDay": { argTypes: [DATE_T], result: F64 }, - "date.getUTCDay": { argTypes: [DATE_T], result: F64 }, - "date.getHours": { argTypes: [DATE_T], result: F64 }, - "date.getUTCHours": { argTypes: [DATE_T], result: F64 }, - "date.getMinutes": { argTypes: [DATE_T], result: F64 }, - "date.getUTCMinutes": { argTypes: [DATE_T], result: F64 }, - "date.getSeconds": { argTypes: [DATE_T], result: F64 }, - "date.getUTCSeconds": { argTypes: [DATE_T], result: F64 }, - "date.getMilliseconds": { argTypes: [DATE_T], result: F64 }, - "date.getUTCMilliseconds": { argTypes: [DATE_T], result: F64 }, - "date.getTimezoneOffset": { argTypes: [DATE_T], result: F64 }, - /** A Date object for a time value a local holds (date-values.ts): a - * lib-call argument passes the time value itself, and any other use - * creates the Date. */ - "date.fromTime": { argTypes: [F64], result: DATE_T }, - /** Date.prototype's field setters over a time value - * (scr_date_set_fields): time value, setter code, argument count and four - * arguments; answers the new time value. */ - "date.setFields": { argTypes: [F64, F64, F64, F64, F64, F64, F64], result: F64 }, - /** TimeClip of a number (setTime's argument). */ - "date.timeClip": { argTypes: [F64], result: F64 }, - /** Stores a time value into a Date object and answers it (a setter's - * write). */ - "date.store": { argTypes: [DATE_T, F64], result: F64 }, - /** Date.prototype.toString / toDateString / toTimeString and String(date): - * V8's local-time formats with the host zone's long name, "Invalid Date" - * for an invalid date. Owned (+1) string; never throws. */ - "date.toString": { argTypes: [DATE_T], result: STRING }, - "date.toDateString": { argTypes: [DATE_T], result: STRING }, - "date.toTimeString": { argTypes: [DATE_T], result: STRING }, - /** The composed `new Date(dateString).getTime()` read: one borrowed - * string, f64 milliseconds since epoch, with V8's date-string grammar - * (the ES5 format, then the legacy forms: RFC 1123/2822, Date#toString, - * "Jan 2, 2024", ...). Zone-less dates are local time; anything V8 - * rejects is NaN, Node's invalid-date getTime. Never throws. */ - "date.parseGetTime": { argTypes: [STRING], result: F64 }, - /** `Date.UTC(...)` — seven f64 arguments (the frontend completes the - * spec's defaults for omitted trailing parts: month 0, date 1, time - * parts 0), the spec's MakeDay/MakeTime/TimeClip exactly: 0–99 years - * map to 1900+year, out-of-range months/dates roll over, non-finite - * parts and out-of-range results answer NaN. Never throws. */ - "date.utc": { argTypes: [F64, F64, F64, F64, F64, F64, F64], result: F64 }, - /** `new Date(year, monthIndex[, date, hours, minutes, seconds, ms])` — - * the same seven-f64 completion as date.utc, but the fields are LOCAL - * time: V8's MakeDay/MakeTime, then UTC(t) in the host zone (DST gaps - * read with the offset before the transition, overlaps answer the - * earlier instant), then TimeClip. Never throws. */ - "date.newLocal": { argTypes: [F64, F64, F64, F64, F64, F64, F64], result: DATE_T }, - /** WHATWG TextDecoder.decode over u8 bytes (scr_bytes.c): utf-8 with - * default options — the same maximal-subpart replacement decode as - * Buffer.toString("utf8"), with the leading BOM stripped (the one - * behavioral difference; ignoreBOM defaults to false). Inline calls - * lower directly; stored decoder records dispatch by encoding id. - * TextEncoder.encode needs no libFn: its matching forms - * lower to buffer.fromStr(s, "utf8") (identical bytes — both write each - * lone surrogate as U+FFFD). Borrowed arg; owned (+1) string; never throws. */ - "text.decode": { argTypes: [BYTES_U8], result: STRING }, - "bytes.bufferSource": { argTypes: [DYN], result: BYTES_U8 }, - /** Whether an error-first callback's Buffer result is absent: the zlib - * and crypto callback adapters pass NULL after an error. Borrowed arg; - * never throws. */ - "bytes.isAbsent": { argTypes: [BYTES_U8], result: BOOL }, - /** Whether two typed arrays share no byte: their element ranges in - * memory do not overlap. Borrowed args of any element kind; never throws. */ - "bytes.disjoint": { argTypes: [null, null], result: BOOL }, - /** The absent Buffer result itself (NULL), where an error-path callback - * body passes its undefined result on into a Buffer slot. Owned (+1); - * never throws. */ - "bytes.absent": { argTypes: [], result: BYTES_U8 }, - /** node:crypto asymmetric keys and signatures (scr_pki.c): checked- - * dynamic arguments, borrowed; KeyObject, Sign and Verify handles, - * Buffers and booleans as checked-dynamic results (+1). Node's argument - * and decoder errors throw (may-throw); generateKeyPairCb's callback - * receives (null, publicKey, privateKey) in a later macrotask. */ - "crypto.createPrivateKey": { argTypes: [DYN], result: DYN }, - "crypto.createPublicKey": { argTypes: [DYN], result: DYN }, - "crypto.generateKeyPairSync": { argTypes: [DYN, DYN], result: DYN }, - "crypto.generateKeyPairCb": { argTypes: [DYN, DYN, DYN], result: VOID }, - "crypto.signOneshot": { argTypes: [DYN, DYN, DYN], result: DYN }, - "crypto.diffieHellman": { argTypes: [DYN, DYN], result: DYN }, - "crypto.verifyOneshot": { argTypes: [DYN, DYN, DYN, DYN], result: DYN }, - "crypto.createSign": { argTypes: [DYN], result: DYN }, - "crypto.createVerify": { argTypes: [DYN], result: DYN }, - /** The Buffer brand of a Uint8Array source onto a fresh Uint8Array - * result (map and filter of a Buffer return a Buffer). */ - "bytes.copyBrand": { argTypes: [BYTES_U8, BYTES_U8], result: VOID }, - "text.decodeBufferSource": { argTypes: [DYN], result: STRING }, - "text.decodeOptions": { argTypes: [BYTES_U8, BOOL, BOOL], result: STRING }, - "text.decodeStream": { argTypes: [DYN, BYTES_U8, F64, BOOL, BOOL, BOOL], result: STRING }, - "text.decodeLegacyOptions": { argTypes: [BYTES_U8, F64, BOOL, BOOL], result: STRING }, - /** TextDecoder.decode for a compile-time non-UTF-8 WHATWG label. The - * second f64 is the frontend-owned encoding id consumed by scr_bytes.c; - * label aliases/case/ASCII whitespace are canonicalized before IR. The - * mapping tables are generated from the pinned Node 24 oracle, keeping - * output portable without an ICU/iconv dependency. Borrowed args; owned - * (+1) string; never throws. */ - "text.decodeLegacy": { argTypes: [BYTES_U8, F64], result: STRING }, - "text.decoderEncoding": { argTypes: [DYN], result: F64 }, - "text.decoderName": { argTypes: [F64], result: STRING }, - "text.encodeInto": { argTypes: [DYN, DYN], result: DYN }, - /** `value instanceof TextDecoder` (true) or `TextEncoder` (false) on a - * checked-dynamic value: a codec record's handle box (scr_text_codec_dyn.c). - * Borrowed; never throws. */ - "text.codecIs": { argTypes: [DYN, BOOL], result: BOOL }, - "buffer.isAscii": { argTypes: [DYN], result: BOOL }, - "buffer.isUtf8": { argTypes: [DYN], result: BOOL }, - "buffer.transcode": { argTypes: [DYN, DYN, DYN], result: BYTES_U8 }, - /** The fs option forms and friends (scr_lib.c), all throwing catchably - * like the rest of sync fs. mkdirRecursiveSync is Node's recursive - * algorithm (try mkdir, EEXIST-dir is fine, ENOENT creates the parent - * first — errors report Node's errno at Node's path, EEXIST at a file - * target, ENOTDIR at the full path past a file); the first-created-dir - * return value has no lowering (statement position only, frontend- - * fenced). rmOptsSync is rmSync with (recursive, force) bools: force - * swallows ENOENT, recursive removes trees post-order, a directory - * without recursive throws Node's ERR_FS_EISDIR SystemError. mkdtempSync appends the six X's and returns the - * created path (+1). accessSync takes the F_OK/R_OK/W_OK/X_OK bits as - * one f64 (the frontend bakes fs.constants.* as literals and completes - * an omitted mode to 0). readFdSync/readFdSyncBytes are the - * readFileSync(fd[, "utf8"]) forms — a read(2) loop to EOF on the fd - * (the stdin path); errors carry Node's no-path message shape. */ - "fs.mkdirRecursiveSync": { argTypes: [STRING], result: VOID }, - "fs.rmOptsSync": { argTypes: [STRING, BOOL, BOOL], result: VOID }, - /** rmOptsSync's maxRetries/retryDelay form (path, recursive, force, - * maxRetries, retryDelay): Node's linear-backoff retry on - * EBUSY/EMFILE/ENFILE/ENOTEMPTY/EPERM — the tmpdir-harness shape - * rmSync(p, { maxRetries: 3, recursive: true, force: true }). Throws - * ERR_OUT_OF_RANGE for a retryDelay outside int32 >= 0 or a maxRetries - * outside uint32, before checking the path. */ - "fs.rmRetrySync": { argTypes: [STRING, BOOL, BOOL, F64, F64], result: VOID }, - "fs.mkdtempSync": { argTypes: [STRING], result: STRING }, - "fs.accessSync": { argTypes: [STRING, F64], result: VOID }, - "fs.readFdSync": { argTypes: [F64, STRING], result: STRING }, - "fs.readFdSyncBytes": { argTypes: [F64], result: BYTES_U8 }, - /** Validated isatty(3) probe. Stream property lowering maps false to - * undefined; tty.isatty exposes the boolean result directly. */ - "process.isTTY": { argTypes: [F64], result: BOOL }, - // Like process.envGet: the result is the module's interned - // `number | undefined` union — checked by arms in the libCall case. - /** Terminal width over an fd literal (1/2 — process.stdout/stderr - * .columns): ioctl(TIOCGWINSZ). The result is the module's interned - * `number | undefined` union — a non-TTY stream (or an ioctl refusal) - * yields the undefined arm, exactly Node's missing `.columns`. Never - * throws. */ - "process.columns": { argTypes: [F64], result: VOID }, - /** Terminal height, with the same fd and optional-number contract. */ - "process.rows": { argTypes: [F64], result: VOID }, - /** process.stdin.destroy(): a deliberate no-op (no stream machinery - * exists to tear down; documented in SEMANTICS.md). */ - "process.stdinDestroy": { argTypes: [], result: VOID }, - /** process.stdin.setRawMode(mode) — one borrowed bool arg, void. On a - * TTY stdin: termios raw mode on/off (libuv's UV_TTY_MODE_RAW flag set, - * the mode Node's setRawMode(true) applies; false restores the entry - * state). On a NON-TTY stdin Node's process.stdin has no such method at - * all, so the call throws Node's exact catchable TypeError - * ("process.stdin.setRawMode is not a function") — the may-throw seed - * carries it. */ - "process.stdinSetRawMode": { argTypes: [BOOL], result: VOID }, - // Arg 0 is a packed f64[] OR a bytes value (the spread-typed-array - // form) — checked in the libCall case. - /** fromCharCode takes one packed f64[] or bytes arg and builds a string - * from UTF-16 code units. Adjacent surrogate pairs combine; lone - * surrogates follow the runtime's replacement policy. */ - "string.fromCharCode": { argTypes: [null], result: STRING }, - /** Numeric code points, with catchable RangeError for non-integers or - * values outside 0..0x10ffff. Uses the same UTF-8 surrogate policy. */ - "string.fromCodePoint": { argTypes: [null], result: STRING }, - /** lastIndexOf returns the last UTF-16 start index, or -1. The two-arg - * form searches at or before its numeric position; NaN starts at the end. - * String arguments are borrowed and neither form throws. */ - "string.lastIndexOf": { argTypes: [STRING, STRING], result: F64 }, - "string.lastIndexOfFrom": { argTypes: [STRING, STRING, F64], result: F64 }, - /** String.raw(template, ...subs): the raw literals array (a string[] - * read off the template record) interleaved with the PRE-STRINGIFIED - * substitutions (the frontend applies the static ToString and packs - * them into one string[] literal) — extra substitutions drop, missing - * ones skip, the spec's loop exactly (scr_array.c). Borrowed args; - * +1 string; never throws. */ - "string.raw": { argTypes: [arrayOf(STRING), arrayOf(STRING)], result: STRING }, -}); + "insp.f64": { argTypes: [F64], result: STRING }, + /** util.format %j over a checked-dynamic argument: the runtime dyn + * walk (JS-exact stringify; root undefined/function prints + * "undefined"; a handle in the tree throws the "not supported yet" + * Error). */ + "insp.jsonDyn": { argTypes: [DYN], result: STRING }, + "insp.str": { argTypes: [STRING], result: STRING }, + "insp.regex": { argTypes: [REGEX], result: STRING }, + /** A Date's inspect text: toISOString(), or "Invalid Date". */ + "insp.date": { argTypes: [DATE_T], result: STRING }, + "insp.buffer": { argTypes: [BYTES_U8], result: STRING }, + /** A numeric typed array that is not a Buffer (any element kind). */ + "insp.typedArray": { argTypes: [null, F64, F64], result: STRING }, + /** A u8 byte view in a union arm, element or field: a DataView, Buffer + * or Uint8Array by its own flags. */ + "insp.bytes": { argTypes: [null, F64, F64], result: STRING }, + "insp.error": { argTypes: [null, F64, F64], result: STRING }, + "insp.errorHasCause": { argTypes: [null], result: BOOL }, + "insp.errorBagHasProperties": { argTypes: [DYN], result: BOOL }, + "insp.errorCause": { argTypes: [null, F64, F64], result: STRING }, + "insp.dyn": { argTypes: [DYN, F64, F64], result: STRING }, + "insp.dynS": { argTypes: [DYN, F64], result: STRING }, + /** util.format's %o over a checked-dynamic value: inspect with + * showHidden. Kinds whose hidden entries have no rendering throw the + * 'not supported yet' Error. */ + "insp.dynHidden": { argTypes: [DYN, F64], result: STRING }, + "insp.begin": { argTypes: [F64], result: VOID }, + /** util.inspect's breakLength, compact (0 for false) and sorted for the + * renders that follow; the call site restores 80, 3 and false afterwards. */ + "insp.layout": { argTypes: [F64, F64, BOOL], result: VOID }, + "insp.entry": { argTypes: [STRING, BOOL], result: VOID }, + // Circular references: the receiver slot is program-dependent (any + // cycle-capable record/array/map/class type — the insp.error precedent). + /* Circular references over cycle-capable composites (recursive record/ + * class types): circCheck answers a value's circular id when it is + * already on the traversal stack (0 otherwise), seenPush/refWrap + * bracket the frame (insp.end adds Node's " " prefix to values + * the walk found circular), circular renders "[Circular *N]". */ + "insp.circCheck": { argTypes: [null], result: F64 }, + "insp.seenPush": { argTypes: [null], result: VOID }, + "insp.refWrap": { argTypes: [null, STRING], result: STRING }, + "insp.circular": { argTypes: [F64], result: STRING }, + /* Whether a closed declared-field record kept the undeclared properties + * of its checked source (scr_record_source_note): reflective surfaces + * (inspect, Object.keys/values/entries) then answer through its live + * checked view. The receiver is any such record type. Never throws. */ + "record.sourceHas": { argTypes: [null], result: BOOL }, + /** `record.sourceSpread(built, value)`: the record a literal starting + * with `...value` just built keeps the order of value's kept source + * (key-order-witness.ts ordered spreads). Both are record types. Never + * throws. */ + "record.sourceSpread": { argTypes: [null, null], result: VOID }, + "insp.key": { argTypes: [STRING], result: STRING }, + "insp.moreItems": { argTypes: [F64], result: STRING }, + "insp.end": { argTypes: [STRING, STRING, STRING, F64, BOOL, BOOL], result: STRING }, + /** A nested inspect inside a custom rendering (PerformanceEntry's + * `${name} ${inspect(toJSON)}`): nestedBegin starts a fresh inspect + * context, nestedEnd(prefix, inner) restores the caller's and answers + * `prefix inner` re-indented at the caller's level (+1). */ + "insp.nestedBegin": { argTypes: [], result: VOID }, + "insp.nestedEnd": { argTypes: [STRING, STRING], result: STRING }, + /** Around a top-level render that an inspection refusal can end: mark + * records the inspector's frame and nesting depth, unwind (in the + * render's finally) closes what the render left open above it. */ + "insp.mark": { argTypes: [], result: VOID }, + "insp.unwind": { argTypes: [], result: VOID }, + /** node:string_decoder's utf8 StringDecoder (scr_string.c): the decoder + * value is a one-field record whose f64 PACKS the pending partial + * sequence (count + up to 3 raw bytes — Node buffers at most 3 for + * every encoding); the frontend's interned %strdec helpers thread it, + * with the decoder's CANONICAL encoding name first, through these pure + * functions. write: (enc, pending, chunk) → the decoded complete + * prefix of pending+chunk (+1); next: (enc, pending, chunk) → the + * packed NEW pending; end: (enc, pending) → the buffered partial's + * flush (+1). Node-exact per encoding (oracle-pinned); none throws. */ + "strdec.write": { argTypes: [STRING, F64, BYTES_U8], result: STRING }, + "strdec.next": { argTypes: [STRING, F64, BYTES_U8], result: F64 }, + "strdec.end": { argTypes: [STRING, F64], result: STRING }, + /** A runtime encoding argument's canonical name (Node's normalizeEncoding: + * nullish and "" are utf8); an unknown name throws ERR_UNKNOWN_ENCODING. */ + "strdec.encoding": { argTypes: [DYN], result: STRING }, + // node:readline: the interface handle is f64; the callbacks' func types + // are program-dependent (the emitter picks the adapter by parameter + // count), so those slots are null like child.onExit's. + /** node:readline and node:readline/promises (scr_readline.c, linked + * under the events gate — these fns imply moduleUsesProcessEvents; a + * stream input or output adds scr_stream.c's bridge). The interface + * value is an f64 handle (the Timeout-id precedent); an open interface + * on stdin keeps the loop alive until close/EOF. + * rl.create: [mode, input?, output?, crlfDelay, prompt?] → f64, mode + * bits 1 stream input, 2 stream output, 4 stdout output, 16 prompt + * (lowerReadlineCreateCall); rl.createSignal: the same plus the + * trailing AbortSignal (mode bit 8), which links the event-target unit + * for addAbortListener. rl.question: [handle, query, cb] — the callback + * form; THROWS ERR_USE_AFTER_CLOSE on a closed interface (may-throw). + * rl.questionAsync(Signal): [handle, query, signal?] → promise, + * rejecting instead of throwing. rl.close/pause/resume/prompt: + * [handle] (pause/resume/prompt throw ERR_USE_AFTER_CLOSE when + * closed); rl.setPrompt/getPrompt; rl.write: [handle, data] (throws + * when closed). rl.on: [handle, event, cb, once] — the event number + * (0 'line', 1 'close', 2 'pause', 3 'resume', 4 'error') and the + * listener (moves). rl.iterOpen/iterNext/iterReturn: the async + * iterator — iterNext answers promise of the line or undefined. */ + "rl.create": { argTypes: [F64], result: F64 }, + "rl.createSignal": { argTypes: [F64], result: F64 }, + "rl.question": { argTypes: [F64, STRING, null], result: VOID }, + "rl.questionAsync": { argTypes: [F64, STRING], result: { kind: "promise", inner: STRING } }, + "rl.questionAsyncSignal": { + argTypes: [F64, STRING, DYN], + result: { kind: "promise", inner: STRING }, + }, + /** The question forms with a checked-dynamic query (a JavaScript value + * that need not be a string). */ + "rl.questionDyn": { argTypes: [F64, DYN, null], result: VOID }, + "rl.questionAsyncDyn": { argTypes: [F64, DYN], result: { kind: "promise", inner: STRING } }, + "rl.questionAsyncSignalDyn": { + argTypes: [F64, DYN, DYN], + result: { kind: "promise", inner: STRING }, + }, + "rl.close": { argTypes: [F64], result: VOID }, + "rl.pause": { argTypes: [F64], result: VOID }, + "rl.resume": { argTypes: [F64], result: VOID }, + "rl.prompt": { argTypes: [F64], result: VOID }, + /** prompt(preserveCursor): [handle, preserveCursor] */ + "rl.promptWith": { argTypes: [F64, BOOL], result: VOID }, + "rl.setPrompt": { argTypes: [F64, STRING], result: VOID }, + "rl.setPromptDyn": { argTypes: [F64, DYN], result: VOID }, + "rl.getPrompt": { argTypes: [F64], result: STRING }, + "rl.write": { argTypes: [F64, STRING], result: VOID }, + /** write(data, key): [handle, hasData, data, hasKey, hasName, name, + * ctrl, meta, shift] */ + "rl.writeKey": { + argTypes: [F64, BOOL, STRING, BOOL, BOOL, STRING, BOOL, BOOL, BOOL], + result: VOID, + }, + "rl.on": { argTypes: [F64, F64, null, BOOL], result: VOID }, + "rl.iterOpen": { argTypes: [F64], result: VOID }, + "rl.iterNext": { argTypes: [F64], result: { kind: "promise", inner: DYN } }, + "rl.iterReturn": { argTypes: [F64], result: VOID }, + /** createInterface's history and editing options (scr_rl_check_options: + * [flags, tabSize, escapeCodeTimeout, historySize], may throw; + * rl.setOptions: [handle, flags, historySize, removeHistoryDuplicates, + * tabSize, escapeCodeTimeout]; rl.setHistory: [handle, history]) and + * the member reads (rl.history answers the array, rl.numProp the + * numeric member by number). */ + "rl.checkOptions": { argTypes: [F64, F64, F64, F64], result: VOID }, + "rl.checkCompleter": { argTypes: [DYN], result: VOID }, + "rl.setOptions": { argTypes: [F64, F64, F64, BOOL, F64, F64], result: VOID }, + "rl.setHistory": { argTypes: [F64, arrayOf(STRING)], result: VOID }, + "rl.history": { argTypes: [F64], result: arrayOf(STRING) }, + "rl.numProp": { argTypes: [F64, F64], result: F64 }, + /** Terminal mode (scr_readline_tty.c): rl.terminal: [handle, mode (0 + * the option's value, 2 output.isTTY of process.stdout), terminal, + * completer (undefined when absent), readline/promises], emitted with + * scr_insp_dyn when there is a completer; the line, terminal and cursor + * members. */ + "rl.terminal": { argTypes: [F64, F64, BOOL, DYN, BOOL], result: VOID }, + "rl.line": { argTypes: [F64], result: STRING }, + "rl.isTerminal": { argTypes: [F64], result: BOOL }, + "rl.isPromises": { argTypes: [F64], result: BOOL }, + /** createInterface's input or output as a checked-dynamic value: + * [value, output] — the stream; refused when it is not one. */ + "rl.inputFromDyn": { + argTypes: [DYN, BOOL], + result: { kind: "object", className: "%Readable" }, + }, + "rl.outputFromDyn": { + argTypes: [DYN, BOOL], + result: { kind: "object", className: "%Writable" }, + }, + "rl.cursor": { argTypes: [F64], result: F64 }, + /** readline.cursorTo / moveCursor / clearLine / clearScreenDown: rl.seq + * [kind (0-3), the first and second numbers, whether the second is + * given] answers the data to write after the argument checks (may + * throw); rl.moves [dx, dy] says whether moveCursor writes. */ + "rl.seq": { argTypes: [F64, F64, F64, BOOL], result: STRING }, + "rl.moves": { argTypes: [F64, F64], result: BOOL }, + /** getCursorPos() (scr_readline_tty.c, linked through the regex unit + * like rl.terminal): [handle, 0 rows | 1 cols] */ + "rl.cursorPos": { argTypes: [F64, F64], result: F64 }, + /** readline.emitKeypressEvents (scr_readline_tty.c): rl.keypressStdin + * [interface (0: none), escapeCodeTimeout (NaN: the interface's or + * 500)], rl.keypressStream [stream, interface, timeout]. */ + "rl.keypressStdin": { argTypes: [F64, F64], result: VOID }, + "rl.keypressStream": { argTypes: [null, F64, F64], result: VOID }, + /** readline/promises Readline over an f64 handle: rl.uiOpen [fd (1 + * stdout, 2 stderr), autoCommit], rl.uiOpenStream [stream, autoCommit] + * (isWritable, may throw); the actions take [handle, ...numbers] (the + * checks may throw; cursorTo: [handle, x, whether y is given, y]); + * rl.uiCommit answers a promise. */ + "rl.uiOpen": { argTypes: [F64, BOOL], result: F64 }, + "rl.uiOpenStream": { argTypes: [null, BOOL], result: F64 }, + "rl.uiCursorTo": { argTypes: [F64, F64, BOOL, F64], result: VOID }, + "rl.uiMoveCursor": { argTypes: [F64, F64, F64], result: VOID }, + "rl.uiClearLine": { argTypes: [F64, F64], result: VOID }, + "rl.uiClearScreenDown": { argTypes: [F64], result: VOID }, + "rl.uiRollback": { argTypes: [F64], result: VOID }, + "rl.uiCommit": { argTypes: [F64], result: { kind: "promise", inner: VOID } }, + /** node:timers/promises — the promisified pair (scr_async.c, beside + * the timer heap they ride): tp.setTimeout: [ms] → a pending void + * promise a one-shot heap timer fulfills (the loop's timer phase, FIFO + * against equal deadlines like Node); tp.setImmediate: [] → the same + * through the immediate queue (fires before due timers of later loop + * turns, Node's check phase). Neither throws. */ + "tp.setTimeout": { argTypes: [F64], result: { kind: "promise", inner: VOID } }, + // scheduler.wait(delay): tp.setTimeout's promise. It throws Node's + // ERR_INVALID_THIS once mock.timers has restored the real scheduler.wait. + "tp.schedulerWait": { argTypes: [F64], result: { kind: "promise", inner: VOID } }, + "tp.setImmediate": { argTypes: [], result: { kind: "promise", inner: VOID } }, + /** events.once (scr_events_emitter.c): [emitter, name, boxer, + * errorBoxer, listenForError] → a pending promise of any[]; the boxers + * turn the event's and the 'error' tuple into that array. */ + "events.once": { argTypes: [null, STRING, null, null, BOOL], result: VOID }, + /** events.once(emitter, name, { signal }) (scr_events_once_signal.c): + * events.once's arguments plus the checked-dynamic signal (an + * AbortSignal or undefined). */ + "events.onceSignal": { argTypes: [null, STRING, null, null, BOOL, DYN], result: VOID }, + /** The resolve-value forms: [ms?, value, ref] → a pending promise of the + * value's type that copies the borrowed already-resolved `value` promise + * when the timer (or immediate) fires; ref false unrefs it. The result + * type follows the value promise. */ + "tp.setTimeoutValue": { argTypes: [F64, null, BOOL], result: VOID }, + "tp.setImmediateValue": { argTypes: [null, BOOL], result: VOID }, + /** The same with options.signal (a checked-dynamic AbortSignal or + * undefined) last: an abort clears the timer and rejects with an + * AbortError (scr_event_target.c). */ + "tp.setTimeoutSignal": { argTypes: [F64, null, BOOL, DYN], result: VOID }, + "tp.setImmediateSignal": { argTypes: [null, BOOL, DYN], result: VOID }, + /** scheduler.wait(delay, options): tp.setTimeoutValue's and + * tp.setTimeoutSignal's shapes, with tp.schedulerWait's throws. */ + "tp.schedulerWaitValue": { argTypes: [F64, null, BOOL], result: VOID }, + "tp.schedulerWaitSignal": { argTypes: [F64, null, BOOL, DYN], result: VOID }, + /** node:diagnostics_channel (scr_dc.c, linked when any dc.* appears — + * the zlib gating precedent): a process-global name→channel registry; + * channel values are f64 handles (type-mapper.ts maps Channel to F64, the + * readline.Interface pattern). Subscribers are dyn function values — + * identity-compared by unsubscribe, called (message, name) by publish + * over a SNAPSHOT of the list (a subscriber unsubscribing itself + * mid-publish still lets its siblings fire, Node's behavior). dc.publish + * MAY THROW: a subscriber's throw propagates out of publish (catchable + * there) where Node routes it to triggerUncaughtException — the + * documented divergence. subscribe/unsubscribe throw Node's + * ERR_INVALID_ARG_TYPE TypeError for non-function subscribers. */ + "dc.channel": { argTypes: [STRING], result: F64 }, + "dc.subscribe": { argTypes: [STRING, DYN], result: VOID }, + "dc.unsubscribe": { argTypes: [STRING, DYN], result: BOOL }, + "dc.hasSubscribers": { argTypes: [STRING], result: BOOL }, + "dc.publish": { argTypes: [F64, DYN], result: VOID }, + "dc.chanSubscribe": { argTypes: [F64, DYN], result: VOID }, + "dc.chanUnsubscribe": { argTypes: [F64, DYN], result: BOOL }, + "dc.chanHasSubscribers": { argTypes: [F64], result: BOOL }, + "dc.chanName": { argTypes: [F64], result: STRING }, + /** TracingChannel (dc.tracingChannel): a registry entry of the five + * event channels, an f64 handle like Channel (type-mapper.ts). tcSubscribe/ + * tcUnsubscribe walk a dyn handlers object's five event keys (truthy + * non-function slots throw the per-channel ERR_INVALID_ARG_TYPE); + * tcTraceSync/tcTraceCallback/tcTracePromise run Node's publish choreography in C over + * dyn values (fn, ctx, thisArg, args-array) with thisArg bound as the + * ambient receiver — the traced call's throw and any subscriber throw + * both propagate (MAY THROW). tcTraceCallback wraps args[position] in a + * native error/result + asyncStart/asyncEnd publisher and throws Node's + * TypeError when that slot is not callable. tracingChannelOf is the + * five-Channel collection form of the constructor. */ + /** setImmediate as a first-class dyn value (scr_async.c): a minted dyn + * callable scheduling args[0](args[1..]) on the immediate queue — the + * Node-suite traceCallback shape (`traceCallback(setImmediate, ...)`). + * Calling it validates the callback (the dyn call machinery); minting + * never throws. */ + "timers.setImmediateFnValue": { argTypes: [], result: DYN }, + /** `new Promise(setImmediate)` (the Node-suite early-exit shape): a + * fresh promise an immediate fulfills with the undefined dyn value — + * the executor IS setImmediate, so resolve rides the immediate queue + * (scr_async.c). Never throws. */ + "timers.immediatePromise": { argTypes: [], result: { kind: "promise", inner: DYN } }, + "dc.tracingChannel": { argTypes: [STRING], result: F64 }, + "dc.tracingChannelOf": { argTypes: [F64, F64, F64, F64, F64], result: F64 }, + "dc.tcChannel": { argTypes: [F64, F64], result: F64 }, + "dc.tcHasSubscribers": { argTypes: [F64], result: BOOL }, + "dc.tcSubscribe": { argTypes: [F64, DYN], result: VOID }, + "dc.tcUnsubscribe": { argTypes: [F64, DYN], result: BOOL }, + "dc.tcTraceSync": { argTypes: [F64, DYN, DYN, DYN, DYN], result: DYN }, + "dc.tcTraceCallback": { argTypes: [F64, DYN, F64, DYN, DYN, DYN], result: DYN }, + /** tracePromise (scr_dc.c): start publish, the traced call, a wrap of + * non-promise results, the end publish, and a REACTION FIBER that + * awaits the traced promise and publishes asyncStart/asyncEnd (error + * first on rejection) before settling the returned promise with + * the passed-through outcome. MAY THROW (the traced call and the + * synchronous publishes). */ + "dc.tcTracePromise": { + argTypes: [F64, DYN, DYN, DYN, DYN], + result: { kind: "promise", inner: DYN }, + }, + /** process.on/once('unhandledRejection', fn): registers a dyn listener + * the checkpoint report dispatches per never-observed rejection — + * (reason, promise) — instead of printing and exiting 1 (scr_async.c). + * The bool second arg is `once` (auto-removed after one delivery, + * Node's once); off/removeListener remove by closure identity, the + * offWarning stance. Throws Node's ERR_INVALID_ARG_TYPE on a + * non-function. */ + /** Uncaught exception handlers and monitors: [callback dyn, once, monitor]. */ + "process.onUncaughtException": { argTypes: [DYN, BOOL, BOOL], result: VOID }, + "process.offUncaughtException": { argTypes: [DYN, BOOL], result: VOID }, + "process.onUnhandledRejection": { argTypes: [DYN, BOOL], result: VOID }, + "process.offUnhandledRejection": { argTypes: [DYN], result: VOID }, + /** process.on/once/off('rejectionHandled', fn): the sibling registry. + * A handler attached after unhandledRejection delivery fires the event + * once. Dispatch is synchronous at the attach, with the promise, + * Node's payload. */ + "process.onRejectionHandled": { argTypes: [DYN, BOOL], result: VOID }, + "process.offRejectionHandled": { argTypes: [DYN], result: VOID }, + /** process warnings (scr_async_dyn.c): onWarning/offWarning register + * dyn listeners; emitWarning applies Node's full argument grammar over + * the call's dyn argument vector (ERR_INVALID_ARG_TYPE TypeErrors — MAY + * THROW) and emits on the next tick, like Node: Node's stderr report, + * then the listeners. */ + "process.onWarning": { argTypes: [DYN], result: VOID }, + "process.offWarning": { argTypes: [DYN], result: VOID }, + "process.emitWarning": { argTypes: [DYN], result: VOID }, + /** A Warning-typed process warning with this message (the console + * members' warnings), emitted on the next tick as Node's emitWarning + * does (so the loop runs); an empty message emits nothing. */ + "process.emitWarningText": { argTypes: [STRING], result: VOID }, + /** process.noDeprecation (0) / process.throwDeprecation (1): the stored + * value (undefined until assigned) and its assignment. util.deprecate's + * warnings and DeprecationWarning emissions read their truthiness. */ + "process.deprecationFlag": { argTypes: [F64], result: DYN }, + "process.setDeprecationFlag": { argTypes: [F64, DYN], result: VOID }, + "process.setEmitWarning": { argTypes: [DYN], result: VOID }, + /** AsyncLocalStorage (node:async_hooks — scr_async.c): stores are f64 + * handles; contexts are immutable fiber-carried snapshots (spawned + * fibers inherit the spawner's — Node's init-time capture). run/exit + * enter (or clear) the store, call the dyn function with forwarded + * arguments, and restore (the finally); getStore answers the current + * dyn value or undefined; enterWith installs with no restore point. + * run/exit MAY THROW (the callback's own throws propagate). */ + /** `await v` over a checked-dynamic VALUE (scr_async.c): a dyn promise + * adopts (rejections re-throw — MAY THROW), anything else takes JS's + * one-microtask non-thenable await and answers itself. Only emitted + * inside async bodies (the frontend's isAsync gate). */ + "async.awaitDyn": { argTypes: [DYN], result: DYN }, + /** The bare one-microtask hop (scr_await_hop): `await v` over a typed + * NON-promise value — JS awaits non-thenables through exactly one + * microtask turn and yields the value itself. Never throws. */ + "async.hop": { argTypes: [], result: VOID }, + "als.new": { argTypes: [], result: F64 }, + "als.get": { argTypes: [F64], result: DYN }, + "als.run": { argTypes: [F64, DYN, DYN, DYN], result: DYN }, + "als.exitRun": { argTypes: [F64, DYN, DYN], result: DYN }, + "als.enterWith": { argTypes: [F64, DYN], result: VOID }, + "als.disable": { argTypes: [F64], result: VOID }, + /** new AsyncLocalStorage(options) (Node's object check throws; MAY + * THROW) and the store's name option (dyn; "" without one). */ + "als.newOptions": { argTypes: [DYN], result: F64 }, + "als.name": { argTypes: [F64], result: DYN }, + /** A function bound to the active context: the completion callbacks of + * callback-style APIs (always false: an empty context leaves the + * callback unbound) and AsyncLocalStorage.bind (always true). The typed + * form answers its closure argument's type; the dyn form throws Node's + * ERR_INVALID_ARG_TYPE for a non-function when always (MAY THROW). */ + "als.bindCallback": { argTypes: [null, BOOL], result: VOID }, + "als.bindCallbackDyn": { argTypes: [DYN, BOOL], result: DYN }, + /** AsyncLocalStorage.snapshot(): a dyn function (cb, ...args) that runs + * cb in the context active at the snapshot. */ + "als.snapshot": { argTypes: [], result: DYN }, + /** Channel.bindStore/unbindStore/runStores (scr_dc.c): the + * AsyncLocalStorage integration — set-semantics bindings per store, + * runStores entering every bound store with transform(data) around the + * publish and the callback (MAY THROW: transforms, subscribers, and + * the callback all run). */ + "dc.chanBindStore": { argTypes: [F64, F64, DYN], result: VOID }, + "dc.chanUnbindStore": { argTypes: [F64, F64], result: BOOL }, + "dc.chanRunStores": { argTypes: [F64, DYN, DYN, DYN, DYN], result: DYN }, + /** The Number statics with a static C implementation (scr_lib.c): one + * f64 arg → bool, JS-exact BY CONSTRUCTION — Number.isFinite/isNaN/ + * isInteger/isSafeInteger never coerce, and the frontend routes only + * f64-typed arguments here (other static types fence). None throws. */ + "number.isFinite": { argTypes: [F64], result: BOOL }, + "number.isNaN": { argTypes: [F64], result: BOOL }, + "number.isInteger": { argTypes: [F64], result: BOOL }, + "number.isSafeInteger": { argTypes: [F64], result: BOOL }, + /** Date (scr_lib.c). Values are TimeClip'd epoch-millisecond scalars: + * construction/store/pass/getters are exact while identity and mutation + * remain fenced. date.now is Node's integer milliseconds since epoch; + * date.toISOString formats one raw f64 millisecond time value and + * date.toISOStringValue formats a stored Date, both with Node's rules (UTC, + * YYYY-MM-DDTHH:mm:ss.sssZ, expanded ±YYYYYY years outside 0–9999, + * ToInteger truncation of fractional ms) and THROWS Node's "Invalid + * time value" RangeError on NaN / out-of-range input (may-throw seed). + * Results: f64 / owned (+1) string. */ + "date.now": { argTypes: [], result: F64 }, + "date.newNow": { argTypes: [], result: DATE_T }, + "date.newMs": { argTypes: [F64], result: DATE_T }, + "date.newString": { argTypes: [STRING], result: DATE_T }, + /** Date.parse(dateString), with its own reach witness for exact fences. */ + "date.parse": { argTypes: [STRING], result: F64 }, + "date.getTime": { argTypes: [DATE_T], result: F64 }, + "date.valueOf": { argTypes: [DATE_T], result: F64 }, + "date.toISOString": { argTypes: [F64], result: STRING }, + "date.toISOStringValue": { argTypes: [DATE_T], result: STRING }, + /** Date.prototype.toUTCString over a stored Date ("Invalid Date" for + * NaN; never throws). */ + "date.toUTCString": { argTypes: [DATE_T], result: STRING }, + "date.getFullYear": { argTypes: [DATE_T], result: F64 }, + "date.getUTCFullYear": { argTypes: [DATE_T], result: F64 }, + "date.getMonth": { argTypes: [DATE_T], result: F64 }, + "date.getUTCMonth": { argTypes: [DATE_T], result: F64 }, + "date.getDate": { argTypes: [DATE_T], result: F64 }, + "date.getUTCDate": { argTypes: [DATE_T], result: F64 }, + "date.getDay": { argTypes: [DATE_T], result: F64 }, + "date.getUTCDay": { argTypes: [DATE_T], result: F64 }, + "date.getHours": { argTypes: [DATE_T], result: F64 }, + "date.getUTCHours": { argTypes: [DATE_T], result: F64 }, + "date.getMinutes": { argTypes: [DATE_T], result: F64 }, + "date.getUTCMinutes": { argTypes: [DATE_T], result: F64 }, + "date.getSeconds": { argTypes: [DATE_T], result: F64 }, + "date.getUTCSeconds": { argTypes: [DATE_T], result: F64 }, + "date.getMilliseconds": { argTypes: [DATE_T], result: F64 }, + "date.getUTCMilliseconds": { argTypes: [DATE_T], result: F64 }, + "date.getTimezoneOffset": { argTypes: [DATE_T], result: F64 }, + /** A Date object for a time value a local holds (date-values.ts): a + * lib-call argument passes the time value itself, and any other use + * creates the Date. */ + "date.fromTime": { argTypes: [F64], result: DATE_T }, + /** Date.prototype's field setters over a time value + * (scr_date_set_fields): time value, setter code, argument count and four + * arguments; answers the new time value. */ + "date.setFields": { argTypes: [F64, F64, F64, F64, F64, F64, F64], result: F64 }, + /** TimeClip of a number (setTime's argument). */ + "date.timeClip": { argTypes: [F64], result: F64 }, + /** Stores a time value into a Date object and answers it (a setter's + * write). */ + "date.store": { argTypes: [DATE_T, F64], result: F64 }, + /** Date.prototype.toString / toDateString / toTimeString and String(date): + * V8's local-time formats with the host zone's long name, "Invalid Date" + * for an invalid date. Owned (+1) string; never throws. */ + "date.toString": { argTypes: [DATE_T], result: STRING }, + "date.toDateString": { argTypes: [DATE_T], result: STRING }, + "date.toTimeString": { argTypes: [DATE_T], result: STRING }, + /** The composed `new Date(dateString).getTime()` read: one borrowed + * string, f64 milliseconds since epoch, with V8's date-string grammar + * (the ES5 format, then the legacy forms: RFC 1123/2822, Date#toString, + * "Jan 2, 2024", ...). Zone-less dates are local time; anything V8 + * rejects is NaN, Node's invalid-date getTime. Never throws. */ + "date.parseGetTime": { argTypes: [STRING], result: F64 }, + /** `Date.UTC(...)` — seven f64 arguments (the frontend completes the + * spec's defaults for omitted trailing parts: month 0, date 1, time + * parts 0), the spec's MakeDay/MakeTime/TimeClip exactly: 0–99 years + * map to 1900+year, out-of-range months/dates roll over, non-finite + * parts and out-of-range results answer NaN. Never throws. */ + "date.utc": { argTypes: [F64, F64, F64, F64, F64, F64, F64], result: F64 }, + /** `new Date(year, monthIndex[, date, hours, minutes, seconds, ms])` — + * the same seven-f64 completion as date.utc, but the fields are LOCAL + * time: V8's MakeDay/MakeTime, then UTC(t) in the host zone (DST gaps + * read with the offset before the transition, overlaps answer the + * earlier instant), then TimeClip. Never throws. */ + "date.newLocal": { argTypes: [F64, F64, F64, F64, F64, F64, F64], result: DATE_T }, + /** WHATWG TextDecoder.decode over u8 bytes (scr_bytes.c): utf-8 with + * default options — the same maximal-subpart replacement decode as + * Buffer.toString("utf8"), with the leading BOM stripped (the one + * behavioral difference; ignoreBOM defaults to false). Inline calls + * lower directly; stored decoder records dispatch by encoding id. + * TextEncoder.encode needs no libFn: its matching forms + * lower to buffer.fromStr(s, "utf8") (identical bytes — both write each + * lone surrogate as U+FFFD). Borrowed arg; owned (+1) string; never throws. */ + "text.decode": { argTypes: [BYTES_U8], result: STRING }, + "bytes.bufferSource": { argTypes: [DYN], result: BYTES_U8 }, + /** Whether an error-first callback's Buffer result is absent: the zlib + * and crypto callback adapters pass NULL after an error. Borrowed arg; + * never throws. */ + "bytes.isAbsent": { argTypes: [BYTES_U8], result: BOOL }, + /** Whether two typed arrays share no byte: their element ranges in + * memory do not overlap. Borrowed args of any element kind; never throws. */ + "bytes.disjoint": { argTypes: [null, null], result: BOOL }, + /** The absent Buffer result itself (NULL), where an error-path callback + * body passes its undefined result on into a Buffer slot. Owned (+1); + * never throws. */ + "bytes.absent": { argTypes: [], result: BYTES_U8 }, + /** node:crypto asymmetric keys and signatures (scr_pki.c): checked- + * dynamic arguments, borrowed; KeyObject, Sign and Verify handles, + * Buffers and booleans as checked-dynamic results (+1). Node's argument + * and decoder errors throw (may-throw); generateKeyPairCb's callback + * receives (null, publicKey, privateKey) in a later macrotask. */ + "crypto.createPrivateKey": { argTypes: [DYN], result: DYN }, + "crypto.createPublicKey": { argTypes: [DYN], result: DYN }, + "crypto.generateKeyPairSync": { argTypes: [DYN, DYN], result: DYN }, + "crypto.generateKeyPairCb": { argTypes: [DYN, DYN, DYN], result: VOID }, + "crypto.signOneshot": { argTypes: [DYN, DYN, DYN], result: DYN }, + "crypto.diffieHellman": { argTypes: [DYN, DYN], result: DYN }, + "crypto.verifyOneshot": { argTypes: [DYN, DYN, DYN, DYN], result: DYN }, + "crypto.createSign": { argTypes: [DYN], result: DYN }, + "crypto.createVerify": { argTypes: [DYN], result: DYN }, + /** The Buffer brand of a Uint8Array source onto a fresh Uint8Array + * result (map and filter of a Buffer return a Buffer). */ + "bytes.copyBrand": { argTypes: [BYTES_U8, BYTES_U8], result: VOID }, + "text.decodeBufferSource": { argTypes: [DYN], result: STRING }, + "text.decodeOptions": { argTypes: [BYTES_U8, BOOL, BOOL], result: STRING }, + "text.decodeStream": { argTypes: [DYN, BYTES_U8, F64, BOOL, BOOL, BOOL], result: STRING }, + "text.decodeLegacyOptions": { argTypes: [BYTES_U8, F64, BOOL, BOOL], result: STRING }, + /** TextDecoder.decode for a compile-time non-UTF-8 WHATWG label. The + * second f64 is the frontend-owned encoding id consumed by scr_bytes.c; + * label aliases/case/ASCII whitespace are canonicalized before IR. The + * mapping tables are generated from the pinned Node 24 oracle, keeping + * output portable without an ICU/iconv dependency. Borrowed args; owned + * (+1) string; never throws. */ + "text.decodeLegacy": { argTypes: [BYTES_U8, F64], result: STRING }, + "text.decoderEncoding": { argTypes: [DYN], result: F64 }, + "text.decoderName": { argTypes: [F64], result: STRING }, + "text.encodeInto": { argTypes: [DYN, DYN], result: DYN }, + /** `value instanceof TextDecoder` (true) or `TextEncoder` (false) on a + * checked-dynamic value: a codec record's handle box (scr_text_codec_dyn.c). + * Borrowed; never throws. */ + "text.codecIs": { argTypes: [DYN, BOOL], result: BOOL }, + "buffer.isAscii": { argTypes: [DYN], result: BOOL }, + "buffer.isUtf8": { argTypes: [DYN], result: BOOL }, + "buffer.transcode": { argTypes: [DYN, DYN, DYN], result: BYTES_U8 }, + /** The fs option forms and friends (scr_lib.c), all throwing catchably + * like the rest of sync fs. mkdirRecursiveSync is Node's recursive + * algorithm (try mkdir, EEXIST-dir is fine, ENOENT creates the parent + * first — errors report Node's errno at Node's path, EEXIST at a file + * target, ENOTDIR at the full path past a file); the first-created-dir + * return value has no lowering (statement position only, frontend- + * fenced). rmOptsSync is rmSync with (recursive, force) bools: force + * swallows ENOENT, recursive removes trees post-order, a directory + * without recursive throws Node's ERR_FS_EISDIR SystemError. mkdtempSync appends the six X's and returns the + * created path (+1). accessSync takes the F_OK/R_OK/W_OK/X_OK bits as + * one f64 (the frontend bakes fs.constants.* as literals and completes + * an omitted mode to 0). readFdSync/readFdSyncBytes are the + * readFileSync(fd[, "utf8"]) forms — a read(2) loop to EOF on the fd + * (the stdin path); errors carry Node's no-path message shape. */ + "fs.mkdirRecursiveSync": { argTypes: [STRING], result: VOID }, + "fs.rmOptsSync": { argTypes: [STRING, BOOL, BOOL], result: VOID }, + /** rmOptsSync's maxRetries/retryDelay form (path, recursive, force, + * maxRetries, retryDelay): Node's linear-backoff retry on + * EBUSY/EMFILE/ENFILE/ENOTEMPTY/EPERM — the tmpdir-harness shape + * rmSync(p, { maxRetries: 3, recursive: true, force: true }). Throws + * ERR_OUT_OF_RANGE for a retryDelay outside int32 >= 0 or a maxRetries + * outside uint32, before checking the path. */ + "fs.rmRetrySync": { argTypes: [STRING, BOOL, BOOL, F64, F64], result: VOID }, + "fs.mkdtempSync": { argTypes: [STRING], result: STRING }, + "fs.accessSync": { argTypes: [STRING, F64], result: VOID }, + "fs.readFdSync": { argTypes: [F64, STRING], result: STRING }, + "fs.readFdSyncBytes": { argTypes: [F64], result: BYTES_U8 }, + /** Validated isatty(3) probe. Stream property lowering maps false to + * undefined; tty.isatty exposes the boolean result directly. */ + "process.isTTY": { argTypes: [F64], result: BOOL }, + // Like process.envGet: the result is the module's interned + // `number | undefined` union — checked by arms in the libCall case. + /** Terminal width over an fd literal (1/2 — process.stdout/stderr + * .columns): ioctl(TIOCGWINSZ). The result is the module's interned + * `number | undefined` union — a non-TTY stream (or an ioctl refusal) + * yields the undefined arm, exactly Node's missing `.columns`. Never + * throws. */ + "process.columns": { argTypes: [F64], result: VOID }, + /** Terminal height, with the same fd and optional-number contract. */ + "process.rows": { argTypes: [F64], result: VOID }, + /** process.stdin.destroy(): a deliberate no-op (no stream machinery + * exists to tear down; documented in SEMANTICS.md). */ + "process.stdinDestroy": { argTypes: [], result: VOID }, + /** process.stdin.setRawMode(mode) — one borrowed bool arg, void. On a + * TTY stdin: termios raw mode on/off (libuv's UV_TTY_MODE_RAW flag set, + * the mode Node's setRawMode(true) applies; false restores the entry + * state). On a NON-TTY stdin Node's process.stdin has no such method at + * all, so the call throws Node's exact catchable TypeError + * ("process.stdin.setRawMode is not a function") — the may-throw seed + * carries it. */ + "process.stdinSetRawMode": { argTypes: [BOOL], result: VOID }, + // Arg 0 is a packed f64[] OR a bytes value (the spread-typed-array + // form) — checked in the libCall case. + /** fromCharCode takes one packed f64[] or bytes arg and builds a string + * from UTF-16 code units. Adjacent surrogate pairs combine; lone + * surrogates follow the runtime's replacement policy. */ + "string.fromCharCode": { argTypes: [null], result: STRING }, + /** Numeric code points, with catchable RangeError for non-integers or + * values outside 0..0x10ffff. Uses the same UTF-8 surrogate policy. */ + "string.fromCodePoint": { argTypes: [null], result: STRING }, + /** lastIndexOf returns the last UTF-16 start index, or -1. The two-arg + * form searches at or before its numeric position; NaN starts at the end. + * String arguments are borrowed and neither form throws. */ + "string.lastIndexOf": { argTypes: [STRING, STRING], result: F64 }, + "string.lastIndexOfFrom": { argTypes: [STRING, STRING, F64], result: F64 }, + /** String.raw(template, ...subs): the raw literals array (a string[] + * read off the template record) interleaved with the PRE-STRINGIFIED + * substitutions (the frontend applies the static ToString and packs + * them into one string[] literal) — extra substitutions drop, missing + * ones skip, the spec's loop exactly (scr_array.c). Borrowed args; + * +1 string; never throws. */ + "string.raw": { argTypes: [arrayOf(STRING), arrayOf(STRING)], result: STRING }, + }); +} + +let libFnSignatureTable: ReturnType | undefined; + +/** The runtime call slots of every native builtin, keyed by name. The table + * is built on the first call, so runs that neither lower nor validate a + * module do not construct it. */ +export function libFnSignatures(): ReturnType { + libFnSignatureTable ??= buildLibFnSignatures(); + return libFnSignatureTable; +} /** A builtin name exists exactly when its runtime signature exists. */ -export type IrLibFn = keyof typeof LIB_FN_SIGS; +export type IrLibFn = keyof ReturnType; /** The function-stage runs of a pipeline of `total` stages that a stream * follows (positions bit j: stage j is a function), and an async diff --git a/packages/compiler/src/ir/ir.ts b/packages/compiler/src/ir/ir.ts index 251d14904..655288945 100644 --- a/packages/compiler/src/ir/ir.ts +++ b/packages/compiler/src/ir/ir.ts @@ -3940,7 +3940,7 @@ export type IrExpr = } /** Standard-library call (`process` members, node:fs functions). `fn` is a * closed union; arg/result types are fixed per member (validated against - * LIB_FN_SIGS). Property READS (`process.argv`, `process.platform`) are + * libFnSignatures()). Property READS (`process.argv`, `process.platform`) are * zero-arg libCalls. Args are BORROWED by the operation (frame temps * release at statement end); refcounted results come back owned (+1) — * `process.argv` returns +1 on ONE interned array (JS identity: diff --git a/packages/compiler/src/ir/validate.ts b/packages/compiler/src/ir/validate.ts index eba319f85..f27d11f5b 100644 --- a/packages/compiler/src/ir/validate.ts +++ b/packages/compiler/src/ir/validate.ts @@ -66,7 +66,7 @@ import { import { unionWideningTags } from "./analysis.js"; import { alwaysReturns } from "./control-flow.js"; import { dynamicOperationOf, functionTier } from "./tiers.js"; -import { LIB_FN_SIGS, pipelinePumpedRuns } from "./builtin-signatures.js"; +import { libFnSignatures, pipelinePumpedRuns } from "./builtin-signatures.js"; import { ALWAYS_THROW_LIB_FNS } from "./builtin-effects.js"; /** The promisified crypto calls' value kinds besides checked-dynamic. */ @@ -4104,7 +4104,7 @@ function validateFunction( } if (e.fn === "worker.new" && !workers) errors.push({ message: "Worker construction requires worker execution mode", loc: e.loc }); - const sig = LIB_FN_SIGS[e.fn]; + const sig = libFnSignatures()[e.fn]; if (!sig) { err(`libCall of unknown library function "${e.fn as string}"`, e.loc); return; diff --git a/packages/compiler/src/library/fence-eval.ts b/packages/compiler/src/library/fence-eval.ts index 8b0450857..a950b3990 100644 --- a/packages/compiler/src/library/fence-eval.ts +++ b/packages/compiler/src/library/fence-eval.ts @@ -56,9 +56,9 @@ import { } from "../coverage/surface-manifest.js"; import { libFenceDiag, type ScrDiagnostic } from "../diagnostics/diagnostic.js"; import { - AMBIENT_SURFACE_FNS, + ambientSurfaceFns, BUILTIN_MODULE_CONSTS, - BUILTIN_MODULE_FNS, + builtinModuleFns, BUILTIN_MODULE_FN_ALIASES, STATIC_MATH_FNS, STATIC_MATH_PROPS, @@ -125,7 +125,7 @@ interface FenceTaxonomy { /** node-builtin constant ids: reads fold to literals at compile time. */ foldedIds: Set; /** Ambient dedicated-path surfaces (Date/perf_hooks/process): manifest - * id → the libCall spellings witnessing reach (AMBIENT_SURFACE_FNS — + * id → the libCall spellings witnessing reach (ambientSurfaceFns() — * the same rows the manifest projects the entries from). */ ambientFns: Map; } @@ -148,7 +148,7 @@ function fenceTaxonomy(): FenceTaxonomy { const builtinFns = new Map(); const builtinRoots = new Map(); const foldedIds = new Set(); - for (const [mod, members] of Object.entries(BUILTIN_MODULE_FNS)) { + for (const [mod, members] of Object.entries(builtinModuleFns())) { const root = new Set(); for (const [member, entry] of Object.entries(members!)) { if (entry === undefined) continue; @@ -156,7 +156,7 @@ function fenceTaxonomy(): FenceTaxonomy { // The bare-path and url tables rebind per TARGET platform // (builtinModuleFnsOf): a fence on the bare id covers both flavors. if (mod === "path") { - const w = BUILTIN_MODULE_FNS["path/win32"]?.[member]; + const w = builtinModuleFns()["path/win32"]?.[member]; if (w !== undefined) fns.add(w.fn); } if (mod === "url" && member === "pathToFileURL") fns.add("url.pathToFileURLWin32"); @@ -173,7 +173,7 @@ function fenceTaxonomy(): FenceTaxonomy { } for (const member of Object.keys(STATIC_MATH_PROPS)) foldedIds.add(`stdlib.math.${member}`); const ambientFns = new Map( - AMBIENT_SURFACE_FNS.map((row) => [row.id, row.fns as readonly string[]]), + ambientSurfaceFns().map((row) => [row.id, row.fns as readonly string[]]), ); taxonomy = { byId, diff --git a/packages/compiler/test/compat-exports.test.ts b/packages/compiler/test/compat-exports.test.ts new file mode 100644 index 000000000..57ee41339 --- /dev/null +++ b/packages/compiler/test/compat-exports.test.ts @@ -0,0 +1,12 @@ +import { expect, test } from "vitest"; +import { + LIB_FN_SIGS, + libFnSignatures, + NODE24_FETCH_COMPAT_PROFILE, + node24FetchCompatProfile, +} from "../src/index.js"; + +test("the table constants name the tables their functions build", () => { + expect(LIB_FN_SIGS).toBe(libFnSignatures()); + expect(NODE24_FETCH_COMPAT_PROFILE).toBe(node24FetchCompatProfile()); +}); diff --git a/packages/compiler/test/node-pin.test.ts b/packages/compiler/test/node-pin.test.ts index 7f032c69e..4d4c4a7e8 100644 --- a/packages/compiler/test/node-pin.test.ts +++ b/packages/compiler/test/node-pin.test.ts @@ -5,7 +5,7 @@ import { readFileSync } from "node:fs"; import { join } from "node:path"; import { expect, test } from "vitest"; -import { NODE24_FETCH_COMPAT_PROFILE } from "../src/compat/fetch-profile.js"; +import { node24FetchCompatProfile } from "../src/compat/fetch-profile.js"; import { NODE_COMPAT_VERSION } from "../src/frontend/lowering/builtins/process.js"; import { CRYPTO_CONSTANTS } from "../src/frontend/lowering/crypto-tables.js"; import { ZLIB_CONSTANTS } from "../src/frontend/lowering/zlib-constants.js"; @@ -23,7 +23,7 @@ test("the Node pins agree", () => { expect(compat.tag).toBe(`v${pinned}`); expect(read("Dockerfile.sandbox")).toMatch(new RegExp(`^ARG NODE_VERSION=${pinned}$`, "m")); expect(NODE_COMPAT_VERSION).toBe(pinned); - expect(NODE24_FETCH_COMPAT_PROFILE.target.node).toBe(pinned); + expect(node24FetchCompatProfile().target.node).toBe(pinned); expect(read("packages/runtime/src/scr_lib.c")).toContain( `#define SCR_NODE_COMPAT_VERSION "${pinned}"`, ); diff --git a/tests/harness/README.md b/tests/harness/README.md index 3922c72cc..66a528f4e 100644 --- a/tests/harness/README.md +++ b/tests/harness/README.md @@ -52,7 +52,7 @@ that may be newer than the installed declarations). Every item is classified: The selected adjacent interface families excluded from the census carry reasons too. A Node upgrade that adds/removes a public member or dictionary key fails the focused suite until that member is classified. The static and unsupported rows project into the shipped surface manifest; -filter `NODE24_FETCH_COMPAT_PROFILE.inventory.entries` by `status`/`owner` for +filter `node24FetchCompatProfile().inventory.entries` by `status`/`owner` for the next cohesive implementation queue. When Node changes, update `.node-version` and the profile's Node/Undici tuple diff --git a/tests/harness/code-quality.test.ts b/tests/harness/code-quality.test.ts index deff9afe0..9a683e50a 100644 --- a/tests/harness/code-quality.test.ts +++ b/tests/harness/code-quality.test.ts @@ -93,7 +93,7 @@ test("IR imports and the explicit parser islands remain usable", () => { source( work, "packages/compiler/src/frontend/lowering/probe.ts", - 'export { LIB_FN_SIGS } from "../../ir/builtin-signatures.js";\nexport { STR_INTRINSIC_SIGS } from "../../ir/intrinsic-signatures.js";\n', + 'export { libFnSignatures } from "../../ir/builtin-signatures.js";\nexport { STR_INTRINSIC_SIGS } from "../../ir/intrinsic-signatures.js";\n', ); source( work, diff --git a/tests/harness/fetch-conformance-program.ts b/tests/harness/fetch-conformance-program.ts index 0858f5bfe..322443e73 100644 --- a/tests/harness/fetch-conformance-program.ts +++ b/tests/harness/fetch-conformance-program.ts @@ -429,7 +429,7 @@ export function generateFetchConformanceProgram( const traceCount = options.traceCount ?? 12; const scenarios = generatedScenarioIds(profile); const sections: string[] = [ - `// Generated from NODE24_FETCH_COMPAT_PROFILE. Seed: 0x${seed.toString(16)}.`, + `// Generated from node24FetchCompatProfile(). Seed: 0x${seed.toString(16)}.`, ]; for (const scenario of scenarios) { if (!Object.hasOwn(SCENARIO_GENERATORS, scenario)) { diff --git a/tests/harness/fetch-conformance.test.ts b/tests/harness/fetch-conformance.test.ts index 5b6d62f08..abeac58ae 100644 --- a/tests/harness/fetch-conformance.test.ts +++ b/tests/harness/fetch-conformance.test.ts @@ -17,7 +17,7 @@ import { promisify } from "node:util"; import { beforeAll, describe, expect, test } from "vitest"; import { compile, - NODE24_FETCH_COMPAT_PROFILE, + node24FetchCompatProfile, renderDiagnostics, type FetchCompatEvidence, } from "@scriptc/compiler"; @@ -32,7 +32,7 @@ const execFileAsync = promisify(execFile); const repoRoot = join(import.meta.dirname, "../.."); const fixturesRoot = join(repoRoot, "tests/fixtures/fetch"); const sanitize = process.env["SCRIPTC_SAN"] === "1"; -const profile = NODE24_FETCH_COMPAT_PROFILE; +const profile = node24FetchCompatProfile(); function configuredInteger(name: string, fallback: number, maximum: number): number { const raw = process.env[name]; if (raw === undefined || raw === "") return fallback; diff --git a/tests/harness/surface-manifest.test.ts b/tests/harness/surface-manifest.test.ts index 58958c102..8a838aac6 100644 --- a/tests/harness/surface-manifest.test.ts +++ b/tests/harness/surface-manifest.test.ts @@ -6,7 +6,7 @@ import { analyze, generateSurfaceManifest, ir, - LIB_FN_SIGS, + libFnSignatures, renderSurfaceManifest, resolveLibraryFences, type SurfaceManifest, @@ -563,7 +563,7 @@ describe("determinism attestation ↔ fence parity", () => { // initializer is the Date expression the fences witness. "date.fromTime", ]); - const missing = Object.keys(LIB_FN_SIGS).filter( + const missing = Object.keys(libFnSignatures()).filter( (fn) => ir.LIB_NONDETERMINISTIC_PREFIXES.some(([prefix]) => fn.startsWith(prefix)) && !covered.has(fn) && @@ -571,7 +571,7 @@ describe("determinism attestation ↔ fence parity", () => { ); expect( missing, - "attestation-demoting spellings no declarable fence can deny — add a manifest projection (AMBIENT_SURFACE_FNS) or a member alias (BUILTIN_MODULE_FN_ALIASES)", + "attestation-demoting spellings no declarable fence can deny — add a manifest projection (ambientSurfaceFns()) or a member alias (BUILTIN_MODULE_FN_ALIASES)", ).toEqual([]); // The excuse list stays honest in the other direction too: an excused // spelling that gains detector coverage must leave the list. From 0e92be2bf79e9e244e32ffd3aef52d05cb9e5a93 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 05:41:44 -0500 Subject: [PATCH 240/259] Poll worker cancellation between blocks of typed-array loop iterations In a worker program, every loop without a pending test on each iteration decremented a cancellation budget in its body and polled the exception flag every 64 iterations. The poll's early return made each loop an early-exit loop, which LLVM's loop vectorizer does not vectorize. A counted for loop (integer counter, invariant limit), or a loop to a typed array's length, whose body reads or writes a typed-array element outside nested loops and closures, now runs as blocks of at most 64 iterations: the outer header tests the counter against the limit, the inner loop runs to the nearer of the limit and 64 steps on, and the poll follows each block. A typed array's length is fixed, so each block takes it as its limit. The loop polls as often as the budget did, and the inner loop's only exit besides break and return is its bound. The block bound lives in one slot shared by the loop's speculative copies, which resume iterations in each other's bodies. Other loops keep the budget, which costs less in loops of a few iterations. An elementwise Float64Array loop in a worker-enabled program vectorizes again: 949 ms to 691 ms. A byte-classifying loop over a 100M-byte Uint8Array takes 13 ms instead of 141 ms. New corpus program: native-worker-terminate-counted-loops.ts. --- .../src/backend/llvm/emit-statements.ts | 157 +++++++++++++++++- packages/compiler/src/backend/llvm/emitter.ts | 27 ++- packages/compiler/src/backend/loop-polls.ts | 31 ++++ .../test/counted-loop-emission.test.ts | 80 ++++++++- ...ive-worker-terminate-counted-loops.ts.json | 6 + .../native-worker-terminate-counted-loops.ts | 66 ++++++++ ...ive-worker-terminate-counted-loops.ts.json | 1 + 7 files changed, 358 insertions(+), 10 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-terminate-counted-loops.ts.json create mode 100644 tests/corpus/native-worker-terminate-counted-loops.ts create mode 100644 tests/harness/corpus-costs/native-worker-terminate-counted-loops.ts.json diff --git a/packages/compiler/src/backend/llvm/emit-statements.ts b/packages/compiler/src/backend/llvm/emit-statements.ts index cbdeb0558..2efe2cf3a 100644 --- a/packages/compiler/src/backend/llvm/emit-statements.ts +++ b/packages/compiler/src/backend/llvm/emit-statements.ts @@ -91,6 +91,7 @@ import { } from "./string-construction.js"; import { emitStringInputs } from "./string-lifetimes.js"; import { LOOPS } from "./loop-state.js"; +import { loopAccessesTypedArrays } from "../loop-polls.js"; /** A callback loop version copies the loop; keep the copies small. */ const MAX_CALLBACK_VERSION_COST = 400; @@ -1211,9 +1212,67 @@ export function emitStmtBody(emitter: LlEmitter, s: IrStmt): void { B.line(`store ptr ${fresh}, ptr ${slot}`); } }; - const workerBudget = emitter.workerLoopBudget(s); + // A counted loop over typed arrays, or a loop to a typed array's + // length, polls between blocks of WORKER_POLL_BLOCK iterations instead + // of counting a budget in its body: the inner loop over a block then + // has no exit besides its own bound, which LLVM can vectorize. A typed + // array's length is fixed, so each block can take it as its limit. + const stripMined = + capturedLets.length === 0 && + integerSlot !== null && + ((countedLoop !== null && + countedLimit !== null && + Math.abs(countedLoop.step) * WORKER_POLL_BLOCK <= 2 ** 52) || + (integerLoop !== null && integerArrayLoop === null)) && + emitter.workerLoopPolls(s) && + loopAccessesTypedArrays(s); + const workerBudget = stripMined ? null : emitter.workerLoopBudget(s); + // One slot for every copy of the loop: a speculative copy resumes an + // iteration in another copy's body, which then reads this bound. + let blockBound: string | null = null; + if (stripMined) { + blockBound = B.slot(); + B.entryAllocas.push( + `${blockBound} = alloca ${countedLoop ? "i64" : emitter.sizeType} ; cancellation poll block bound`, + ); + } freshenBindings(); emitter.emitLoopCopies(s, capturedLets.length === 0, le, (exit) => { + if (stripMined) { + const counter: StripMinedCounter = countedLoop + ? { + slot: integerSlot!, + type: "i64", + signed: true, + step: countedLoop.step, + followers: countedLoop.followers.map((f, i) => ({ + slot: followerSlots[i]!, + step: f.step, + })), + limit: () => countedLimit!, + } + : { + slot: integerSlot!, + type: emitter.sizeType, + signed: false, + step: 1, + followers: [], + limit: () => { + const receiver = emitter.emitStableReceiver(integerLoop!.limitReceiver, []); + const lenPtr = B.tmp(); + const len = B.tmp(); + B.line( + `${lenPtr} = getelementptr inbounds %ScrBytes, ptr ${receiver.name}, i64 0, i32 1`, + ); + B.line( + `${len} = load ${emitter.sizeType}, ptr ${lenPtr}${bytesHeaderAlias(emitter)}`, + ); + return len; + }, + }; + emitStripMinedCountedLoop(emitter, s, counter, blockBound!, exit); + return; + } const lc = B.newLabel("loop.c"); const lb = B.newLabel("loop.b"); const lu = @@ -2549,6 +2608,102 @@ function emitInt32KindLoop( /** At the top of a loop copy's header: lets a speculative loop find its * ordinary copy's header, and keeps its third copy out of the loop. */ +/** Iterations between cancellation polls of a strip-mined counted loop. */ +const WORKER_POLL_BLOCK = 64; + +/** The counter of a strip-mined loop: its slot, the LLVM integer type and + * signedness of its values, its step, the counters stepped beside it, and + * the limit, emitted in the outer header before each block. */ +interface StripMinedCounter { + slot: string; + type: string; + signed: boolean; + step: number; + followers: { slot: string; step: number }[]; + limit: () => string; +} + +/** A counted `for` loop of a worker program as blocks of WORKER_POLL_BLOCK + * iterations, with the cancellation poll between blocks: the outer header + * tests the counter against the loop's limit, each block runs the body up + * to the nearer of the limit and WORKER_POLL_BLOCK steps on, and the poll + * follows the block. It polls as often as the budget it replaces, and the + * inner loop's only exit besides `break` and `return` is its bound. */ +function emitStripMinedCountedLoop( + emitter: LlEmitter, + s: Extract, + counter: StripMinedCounter, + boundSlot: string, + exit: string, +): void { + const B = emitter.B; + const { slot, type, signed, step } = counter; + const ascending = step > 0; + const compare = !signed ? "ult" : ascending ? "slt" : "sgt"; + const saturating = `llvm.${signed ? "sadd" : "uadd"}.sat.${type}`; + const nearer = `llvm.${!signed ? "umin" : ascending ? "smin" : "smax"}.${type}`; + const wrap = signed ? "nsw" : "nuw"; + const lc = B.newLabel("loop.c"); + const block = B.newLabel("loop.block"); + const bc = B.newLabel("loop.bc"); + const lb = B.newLabel("loop.b"); + const lu = B.newLabel("loop.u"); + const poll = B.newLabel("loop.poll"); + emitter.declare(`declare ${type} @${saturating}(${type}, ${type})`); + emitter.declare(`declare ${type} @${nearer}(${type}, ${type})`); + B.br(lc); + B.startBlock(lc); + enterLoopHeader(emitter, lc); + const start = B.tmp(); + const open = B.tmp(); + B.line(`${start} = load ${type}, ptr ${slot}`); + const limit = counter.limit(); + B.line(`${open} = icmp ${compare} ${type} ${start}, ${limit}`); + B.condBr(open, block, exit); + B.startBlock(block); + const stepped = B.tmp(); + const bound = B.tmp(); + B.line( + `${stepped} = call ${type} @${saturating}(${type} ${start}, ${type} ${step * WORKER_POLL_BLOCK})`, + ); + B.line(`${bound} = call ${type} @${nearer}(${type} ${stepped}, ${type} ${limit})`); + B.line(`store ${type} ${bound}, ptr ${boundSlot}`); + B.br(bc); + B.startBlock(bc); + const index = B.tmp(); + const end = B.tmp(); + const inBlock = B.tmp(); + B.line(`${index} = load ${type}, ptr ${slot}`); + B.line(`${end} = load ${type}, ptr ${boundSlot}`); + B.line(`${inBlock} = icmp ${compare} ${type} ${index}, ${end}`); + B.condBr(inBlock, lb, poll); + B.startBlock(lb); + emitter.jumpTargets.push({ + kind: "loop", + brkLabel: exit, + contLabel: lu, + labels: s.labels, + frameDepth: emitter.frames.length, + scopeDepth: emitter.scopes.length, + finallyDepth: emitter.finallyStack.length, + }); + emitter.emitBlock(s.body); + emitter.jumpTargets.pop(); + B.br(lu); + B.startBlock(lu); + for (const { slot: stepSlot, step: by } of [{ slot, step }, ...counter.followers]) { + const old = B.tmp(); + const next = B.tmp(); + B.line(`${old} = load ${type}, ptr ${stepSlot}`); + B.line(`${next} = add ${wrap} ${type} ${old}, ${by}`); + B.line(`store ${type} ${next}, ptr ${stepSlot}`); + } + B.br(bc); + B.startBlock(poll); + emitter.emitWorkerPoll(); + B.br(lc); +} + function enterLoopHeader(emitter: LlEmitter, header: string): void { const dispatch = emitter.speculationHeader; emitter.speculationHeader = null; diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index d1f4ebcca..c1ea7bf35 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -3932,13 +3932,19 @@ export class LlEmitter { } } + /** Whether `loop` needs a cancellation poll: in a worker program, unless + * the loop already runs a pending test on every iteration, which observes + * a terminate request itself (a separate poll would only add work). */ + workerLoopPolls(loop: Extract): boolean { + return ( + this.mod.workers === true && !loopTestsEveryIteration(loop, (e) => this.callTestsPending(e)) + ); + } + workerLoopBudget( loop: Extract, ): string | null { - if (!this.mod.workers) return null; - // A loop that runs a pending test on every iteration observes a - // terminate request through it; a separate poll would only add work. - if (loopTestsEveryIteration(loop, (e) => this.callTestsPending(e))) return null; + if (!this.workerLoopPolls(loop)) return null; const slot = this.B.slot(); this.B.entryAllocas.push(`${slot} = alloca i32 ; worker cancellation budget`); this.B.line(`store i32 0, ptr ${slot}`); @@ -4056,14 +4062,19 @@ export class LlEmitter { B.condBr(due, poll, next); B.startBlock(poll); B.line(`store i32 63, ptr ${slot}`); - // Calls and throwing operations retain their own checks. Amortize the - // extra cancellation poll across bounded loop batches so scalar work - // does not cross the runtime ABI on every iteration. - this.emitPendingCheck(undefined, true); + this.emitWorkerPoll(); B.br(next); B.startBlock(next); } + /** The cancellation poll itself. Calls and throwing operations retain + * their own checks. Loops amortize this extra poll across bounded + * batches of iterations so scalar work does not cross the runtime ABI on + * every iteration. */ + emitWorkerPoll(): void { + this.emitPendingCheck(undefined, true); + } + /** Moves an already-evaluated value into the runtime's exception cell — * the `throw` statement's kind dispatch (stmts.ts's), shared with * every synthetic thrower. Ownership of a refcounted payload must have diff --git a/packages/compiler/src/backend/loop-polls.ts b/packages/compiler/src/backend/loop-polls.ts index 14c2b049c..c582a4974 100644 --- a/packages/compiler/src/backend/loop-polls.ts +++ b/packages/compiler/src/backend/loop-polls.ts @@ -106,3 +106,34 @@ export function loopTestsEveryIteration(loop: Loop, tested: (call: IrExpr) => bo } return false; } + +/** True when the body of `loop`, outside its nested loops and closures, + * reads or writes a typed-array element: the loops whose cancellation poll + * the emitter moves between blocks of iterations, so that LLVM can + * vectorize them. Other loops keep the budget in their body, which costs + * less in a loop of a few iterations. */ +export function loopAccessesTypedArrays(loop: Loop): boolean { + const inExpr = (e: IrExpr): boolean => { + if (e.kind === "bytesIntrinsic" && e.method === "get") return true; + let found = false; + everyExprChild( + e, + (child) => !(found = inExpr(child)), + (child) => !(found = inStmt(child)), + ); + return found; + }; + const inStmt = (s: IrStmt): boolean => { + if (s.kind === "bytesSet") return true; + if (s.kind === "while" || s.kind === "doWhile" || s.kind === "for" || s.kind === "forOf") + return false; + let found = false; + everyStmtChild( + s, + (child) => !(found = inExpr(child)), + (child) => !(found = inStmt(child)), + ); + return found; + }; + return loop.body.some(inStmt); +} diff --git a/packages/compiler/test/counted-loop-emission.test.ts b/packages/compiler/test/counted-loop-emission.test.ts index 7a3fc1f44..206a3c57e 100644 --- a/packages/compiler/test/counted-loop-emission.test.ts +++ b/packages/compiler/test/counted-loop-emission.test.ts @@ -1,4 +1,4 @@ -import { mkdtemp, readFile, rm } from "node:fs/promises"; +import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; import { tmpdir } from "node:os"; import { join } from "node:path"; import { expect, test } from "vitest"; @@ -45,3 +45,81 @@ test("counted loops guard exact induction and preserve wide remainders on both p await rm(dir, { recursive: true, force: true }); } }); + +test("worker programs poll counted loops over typed arrays between blocks of iterations", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-counted-poll-")); + try { + const source = (workers: boolean): string => + [ + workers ? 'import { isMainThread, Worker } from "node:worker_threads";' : "", + "export function scale(a: Float64Array, b: Float64Array, n: number): void {", + " for (let i = 0; i < n; i++) b[i] = a[i]! * 2;", + "}", + "export function codes(a: Uint8Array): void {", + " for (let i = 0; i < a.length; ++i) a[i] = a[i] === 97 ? 0 : 3;", + "}", + "export function mix(n: number): number {", + " let t = 0;", + " for (let i = 0; i < n; i++) t = (t * 31 + i) % 1000003;", + " return t;", + "}", + "const a = new Float64Array(8).fill(1);", + "const b = new Float64Array(8);", + "scale(a, b, 8);", + "const c = new Uint8Array(8).fill(97);", + "codes(c);", + "console.log(b[7], mix(8), c[0]);", + workers ? "if (!isMainThread) new Worker(new URL(import.meta.url));" : "", + ].join("\n"); + const emit = async (workers: boolean): Promise => { + const entry = join(dir, `${workers ? "worker" : "plain"}.ts`); + await writeFile(entry, source(workers)); + const outPath = join(dir, `${workers ? "worker" : "plain"}.ir.json`); + const result = await compile(entry, { outPath, outDir: dir, outputKind: "ir" }); + if (!result.ok) throw new Error(result.diagnostics.map((d) => d.message).join("\n")); + return emitLlvmModule(deserializeModule(await readFile(outPath, "utf8"))); + }; + // Every emitted version of a function (the number and int32 entries). + const bodies = (ll: string, name: string): string => + [ + ...ll.matchAll( + new RegExp( + `define internal [^\\n]+ @sc_b?f_${name}(?:\\.i32)?\\([^\\n]*\\n([\\s\\S]*?)\\n\\}`, + "g", + ), + ), + ] + .map((match) => match[1]!) + .join("\n"); + const workerModule = await emit(true); + const worker = bodies(workerModule, "scale"); + const blocks = worker.split(/\n(?=[\w.]+:)/); + // No budget in the body: the inner loop's latch only steps the counter, + // the poll runs after each block, and the block's bound is the nearer of + // the limit and 64 steps on. + expect(worker).not.toContain("worker cancellation budget"); + expect(worker).toContain("@llvm.sadd.sat.i64(i64 %"); + expect(worker).toMatch(/@llvm\.smin\.i64\(i64 %\w+, i64 %\w+\)/); + for (const latch of blocks.filter((block) => block.startsWith("loop.u"))) + expect(latch).not.toContain("scr_exc_flag"); + const polls = blocks.filter((block) => block.startsWith("loop.poll")); + expect(polls.length).toBeGreaterThan(0); + for (const poll of polls) expect(poll).toContain("@scr_exc_flag"); + // A counted loop without typed-array accesses keeps the budget. + // A loop to a typed array's length is strip-mined the same way, with the + // length as each block's limit. + const codes = bodies(workerModule, "codes"); + expect(codes).not.toContain("worker cancellation budget"); + expect(codes).toMatch(/@llvm\.uadd\.sat\.i64\(i64 %\w+, i64 64\)/); + expect(codes).toMatch(/@llvm\.umin\.i64\(i64 %\w+, i64 %\w+\)/); + expect(codes).toMatch(/^loop\.poll\d+:$/m); + const mix = bodies(workerModule, "mix"); + expect(mix).toContain("worker cancellation budget"); + expect(mix).not.toContain("loop.poll"); + const plain = bodies(await emit(false), "scale"); + expect(plain).not.toContain("loop.poll"); + expect(plain).not.toContain("@scr_exc_flag"); + } finally { + await rm(dir, { recursive: true, force: true }); + } +}); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-terminate-counted-loops.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-terminate-counted-loops.ts.json new file mode 100644 index 000000000..5f7c54075 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-terminate-counted-loops.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/native-worker-terminate-counted-loops.ts" + ], + "diags": [] +} diff --git a/tests/corpus/native-worker-terminate-counted-loops.ts b/tests/corpus/native-worker-terminate-counted-loops.ts new file mode 100644 index 000000000..55972c4f6 --- /dev/null +++ b/tests/corpus/native-worker-terminate-counted-loops.ts @@ -0,0 +1,66 @@ +// worker.terminate() stops a worker in counted loops over a typed array +// with long bounds: ascending and descending counters, a step above one, a +// second counter that steps with the first, and loops to a typed array's +// length run again and again. +import { Worker, isMainThread, parentPort, workerData } from "node:worker_threads"; + +function ascending(values: Float64Array, limit: number): number { + let acc = 0; + for (let i = 0; i < limit; i++) { + acc = (acc + values[i & 1023]!) % 1000003; + if (i === 5000) parentPort!.postMessage("ready"); + } + return acc; +} + +function descending(values: Float64Array, limit: number): number { + let acc = 0; + for (let i = limit; i > 0; i -= 3) { + acc = (acc * 31 + i + values[i & 1023]!) % 1000003; + if (i === limit - 15000) parentPort!.postMessage("ready"); + } + return acc; +} + +function paired(values: Float64Array, limit: number): number { + let acc = 0; + for (let i = 0, j = 7; i < limit; i++, j += 2) { + acc = (acc + i * j + values[j & 1023]!) % 1000003; + if (i === 5000) parentPort!.postMessage("ready"); + } + return acc; +} + +function lengths(bytes: Uint8Array): number { + let acc = 0; + for (let round = 0; ; round++) { + for (let i = 0; i < bytes.length; ++i) bytes[i] = bytes[i] === 97 ? 0 : (bytes[i]! + round) & 127; + for (let i = 0; i < bytes.length; i++) acc = (acc + bytes[i]!) % 1000003; + if (round === 50) parentPort!.postMessage("ready"); + } + return acc; +} + +if (isMainThread) { + for (const kind of ["ascending", "descending", "paired", "lengths"]) { + await new Promise((resolve) => { + const worker = new Worker(new URL(import.meta.url), { workerData: kind }); + worker.once("message", () => { + void worker.terminate().then((code: number) => console.log(kind, "terminate", code)); + }); + worker.once("exit", (code: number) => { + console.log(kind, "exit", code); + resolve(); + }); + }); + } +} else { + const values = new Float64Array(1024).map((_, i) => i); + const limit = 1e15; + let result = 0; + if (workerData === "ascending") result = ascending(values, limit); + else if (workerData === "descending") result = descending(values, limit); + else if (workerData === "paired") result = paired(values, limit); + else result = lengths(new Uint8Array(1 << 16).fill(97)); + console.log("unexpected result", result); +} diff --git a/tests/harness/corpus-costs/native-worker-terminate-counted-loops.ts.json b/tests/harness/corpus-costs/native-worker-terminate-counted-loops.ts.json new file mode 100644 index 000000000..66a146275 --- /dev/null +++ b/tests/harness/corpus-costs/native-worker-terminate-counted-loops.ts.json @@ -0,0 +1 @@ +{ "plain": 3594, "san": 23593 } From b3c98139e40d5b2c4bd57ec2dd9b06768baaf6d8 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 05:48:40 -0500 Subject: [PATCH 241/259] Move small number-key maps to the direct index from the second key A number-keyed Map or Set with keys the direct index allows now moves to it at its second entry rather than its fifth, so a map over a few small integer keys (a histogram over 0..3) reads through the inline direct index instead of the out-of-line linear scan. --- ...6310-small-number-map-direct-index.ts.json | 6 ++ packages/runtime/src/scr_map.c | 8 +- packages/runtime/src/scr_map.test.c | 8 +- packages/runtime/test/test_map.c | 23 +++--- .../6310-small-number-map-direct-index.ts | 77 +++++++++++++++++++ 5 files changed, 106 insertions(+), 16 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6310-small-number-map-direct-index.ts.json create mode 100644 tests/corpus/6310-small-number-map-direct-index.ts diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6310-small-number-map-direct-index.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6310-small-number-map-direct-index.ts.json new file mode 100644 index 000000000..72472aa95 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/6310-small-number-map-direct-index.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/6310-small-number-map-direct-index.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_map.c b/packages/runtime/src/scr_map.c index 1cb77b0f6..ccfd4b907 100644 --- a/packages/runtime/src/scr_map.c +++ b/packages/runtime/src/scr_map.c @@ -1205,9 +1205,11 @@ static __attribute__((noinline)) void scr_map_set_num(ScrMap *m, uint64_t hash, } /* A number-key map with at least this many entries moves to the direct - * index when its keys allow it, so small integer keys are indexed before - * the linear scan ends. */ -#define SCR_MAP_DENSE_AFTER 4 + * index when its keys allow it: from its second key, so a map of a few + * small integer keys (a histogram over 0..3) reads through the inline + * direct index rather than the out-of-line linear scan. A map with one + * key keeps its linear storage. */ +#define SCR_MAP_DENSE_AFTER 1 /* Whether appending one more entry would grow the lookup index rather than * reuse tombstones: scr_map_reserve_append compacts a linear map with a diff --git a/packages/runtime/src/scr_map.test.c b/packages/runtime/src/scr_map.test.c index 9916c7406..e04e0dac9 100644 --- a/packages/runtime/src/scr_map.test.c +++ b/packages/runtime/src/scr_map.test.c @@ -184,9 +184,11 @@ static void iterate_while_mutating(void) { static void modes(void) { ScrMap *map = scr_map_new(SCR_MAP_KEY_F64, SCR_MAP_VAL_F64, NULL); - for (int i = 1; i <= 4; i++) scr_map_set_f64_f64(map, i, i); - assert(!map->ndense && !map->nbuckets); /* still a linear scan */ - scr_map_set_f64_f64(map, 5, 5); + scr_map_set_f64_f64(map, 1, 1); + assert(!map->ndense && !map->nbuckets); /* one key: still a linear scan */ + scr_map_set_f64_f64(map, 2, 2); + assert(map->ndense >= 16 && !map->nbuckets); /* from the second small integer key */ + for (int i = 3; i <= 5; i++) scr_map_set_f64_f64(map, i, i); assert(map->ndense >= 16 && !map->nbuckets); for (int i = 6; i < 1000; i++) scr_map_set_f64_f64(map, i, i); assert(map->ndense >= 1000 && map->ndense <= 1000 + 1000 / 4 + 64); /* near the largest key */ diff --git a/packages/runtime/test/test_map.c b/packages/runtime/test/test_map.c index 46805da1e..e23618f77 100644 --- a/packages/runtime/test/test_map.c +++ b/packages/runtime/test/test_map.c @@ -422,12 +422,14 @@ static void test_live_iteration_indices(void) { /* A small (linear) map that must grow its lookup index while an iteration * is active may not compact: entry indices, tombstones and the append * position stay put. Integer keys in a compact range move to the direct - * index (dense) from the fifth entry, any other number keys to the bucket + * index (dense) from the second entry, any other number keys to the bucket * table from the ninth; both transitions are covered by running the same - * script with `offset` 0 and 0.5. */ + * script with `offset` 0 and 0.5. The walk deletes `victim`, an existing + * key, then appends the key that makes the index grow. */ static void run_small_storage_transitions(double offset) { bool dense = offset == 0; - int n = dense ? 4 : 8; /* entries a linear map holds before its index grows */ + int n = dense ? 1 : 8; /* entries a linear map holds before its index grows */ + int victim = dense ? 0 : 1; ScrMap *m = scr_map_new(SCR_MAP_KEY_F64, SCR_MAP_VAL_F64, NULL); for (int i = 0; i < n; i++) scr_map_set_f64_f64(m, i + offset, i + 10); check(m->nbuckets == 0 && m->buckets == NULL && m->ndense == 0, @@ -441,22 +443,23 @@ static void run_small_storage_transitions(double offset) { ScrMap *copy = scr_map_clone(m, false, NULL); check(copy->nbuckets == 0 && copy->ndense == 0, "small clone preserves compact storage"); scr_map_iter_enter(m); - scr_map_delete_f64(m, 1 + offset); + scr_map_delete_f64(m, victim + offset); scr_map_set_f64_f64(m, n + offset, 14); check(dense ? m->ndense > 0 && m->nbuckets == 0 : m->nbuckets > 0 && m->ndense == 0, "live iteration promotes without moving entry indices"); - check(m->nentries == (uint32_t)n + 1 && !scr_map_iter_live(m, 1) && + check(m->nentries == (uint32_t)n + 1 && !scr_map_iter_live(m, victim) && scr_map_iter_key_f64(m, n) == n + offset, "promotion preserves tombstones and append position"); for (int i = n + 1; i < 64; i++) scr_map_set_f64_f64(m, i + offset, i + 10); - check(m->nentries == 64 && !scr_map_iter_live(m, 1) && scr_map_iter_key_f64(m, 63) == 63 + offset, + check(m->nentries == 64 && !scr_map_iter_live(m, victim) && scr_map_iter_key_f64(m, 63) == 63 + offset, "growth during iteration keeps entry indices"); double out = 0; - check(scr_map_get_f64_f64(m, offset, &out) && out == 10, - "original key survives promotion and growth"); - check(!scr_map_has_f64(m, 1 + offset), "deleted small key stays absent after rehash"); + check(dense ? scr_map_get_f64_f64(m, n + offset, &out) && out == 14 + : scr_map_get_f64_f64(m, offset, &out) && out == 10, + "keys written before the promotion survive it and the growth"); + check(!scr_map_has_f64(m, victim + offset), "deleted small key stays absent after rehash"); scr_map_iter_exit(m); - check(scr_map_has_f64(copy, 1 + offset) && !scr_map_has_f64(copy, n + offset), + check(scr_map_has_f64(copy, victim + offset) && !scr_map_has_f64(copy, n + offset), "small clone remains independent"); scr_map_clear(copy); scr_map_iter_enter(copy); diff --git a/tests/corpus/6310-small-number-map-direct-index.ts b/tests/corpus/6310-small-number-map-direct-index.ts new file mode 100644 index 000000000..5614a56a1 --- /dev/null +++ b/tests/corpus/6310-small-number-map-direct-index.ts @@ -0,0 +1,77 @@ +// Number-keyed Maps and Sets with two to four small integer keys use the +// direct index. Results must match Node through overwrites, deletes and +// re-adds, a fractional, negative or large key that moves the map to +// hashing, clear, and mutation during a for-of or forEach walk. + +const hist = new Map(); +const codes = [0, 3, 1, 3, 2, 0, 3, 3, 1]; +for (const c of codes) hist.set(c, (hist.get(c) ?? 0) + 1); +console.log([...hist].map(([k, v]) => `${k}:${v}`).join(" "), hist.size, hist.has(4), hist.get(-0)); + +// Delete and re-add: the re-added key moves to the end. +hist.delete(3); +hist.set(3, 9); +hist.delete(0); +console.log([...hist.keys()].join(","), hist.get(3), hist.has(0)); + +// A key the direct index cannot hold moves the map to hashing. +for (const odd of [0.5, -1, 2 ** 40]) { + const m = new Map([ + [1, "a"], + [2, "b"], + ]); + m.set(odd, "c"); + m.set(1, "A"); + console.log([...m].map(([k, v]) => `${k}=${v}`).join(" "), m.get(2), m.get(odd), m.size); +} + +// Two keys, then clear, then reuse. +const pair = new Map(); +pair.set(5, 50); +pair.set(7, 70); +pair.clear(); +pair.set(7, 1); +pair.set(1, 2); +console.log([...pair].map(([k, v]) => `${k}=${v}`).join(" "), pair.size); + +// A walk that deletes ahead and adds keys. +const walk = new Map([ + [0, 0], + [1, 10], + [2, 20], +]); +const seen: number[] = []; +for (const [k, v] of walk) { + seen.push(v); + if (k === 0) { + walk.delete(2); + walk.set(3, 30); + } + if (k === 3) walk.set(0, -1); +} +console.log(seen.join(","), [...walk].map(([k, v]) => `${k}=${v}`).join(" ")); + +// Sets of small integers, forEach with deletion and addition. +const set = new Set([2, 0]); +set.add(1); +set.add(2); +const order: number[] = []; +set.forEach((v) => { + order.push(v); + if (v === 2) { + set.delete(1); + set.add(3); + } +}); +console.log(order.join(","), [...set].join(","), set.has(1), set.size); + +// Many small maps, each with a few keys. +let total = 0; +for (let i = 0; i < 1000; i++) { + const m = new Map(); + m.set(i % 3, i); + m.set((i + 1) % 3, 1); + if (i % 5 === 0) m.delete(i % 3); + total += (m.get(i % 3) ?? 100) + (m.get((i + 1) % 3) ?? 0) + m.size; +} +console.log(total); From cac5a19fc07a7cb13a8085645723a37d1a110d52 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 05:58:42 -0500 Subject: [PATCH 242/259] Fill Buffers with multi-byte values, swap byte order and decode utf16le a word at a time - fill with a string or Buffer value longer than one byte: writes the value once, then doubles the filled prefix with memcpy, as Node does. The value is copied with memmove, so a value that is a view of the buffer being filled gives Node's result; the previous per-byte loop read such a view while overwriting it. The loop also computed a division per byte. - swap16, swap32 and swap64: one load, byte swap and store per group, through a local data pointer. - toString("utf16le" | "ucs2"): four units below 0x80 copy as four bytes, and other units outside the surrogate range are written inline (a three-byte sequence as one four-byte store). Surrogates keep the previous path. The result records its UTF-16 length (one unit per input unit), or is marked ASCII, so `.length` does not walk it. --- .../8007-buffer-fill-swap-utf16le.ts.json | 6 + packages/runtime/src/scr_bytes.c | 85 ++++++++++++-- packages/runtime/src/scr_string.c | 13 +++ packages/runtime/src/scr_string.h | 3 + tests/corpus/8007-buffer-fill-swap-utf16le.ts | 110 ++++++++++++++++++ .../8007-buffer-fill-swap-utf16le.ts.json | 1 + 6 files changed, 210 insertions(+), 8 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8007-buffer-fill-swap-utf16le.ts.json create mode 100644 tests/corpus/8007-buffer-fill-swap-utf16le.ts create mode 100644 tests/harness/corpus-costs/8007-buffer-fill-swap-utf16le.ts.json diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8007-buffer-fill-swap-utf16le.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8007-buffer-fill-swap-utf16le.ts.json new file mode 100644 index 000000000..f629dac24 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8007-buffer-fill-swap-utf16le.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8007-buffer-fill-swap-utf16le.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_bytes.c b/packages/runtime/src/scr_bytes.c index 398e6eb86..df64b2ab2 100644 --- a/packages/runtime/src/scr_bytes.c +++ b/packages/runtime/src/scr_bytes.c @@ -2495,14 +2495,57 @@ static uint32_t scr_bytes_utf16le_cp(const uint8_t *in, size_t units, size_t *u) return cu; } +/* Four units below 0x80 copy as four bytes (one word holds them), and + * other units outside the surrogate range are written inline; surrogates + * take scr_bytes_utf16le_cp. The string has one UTF-16 unit per input + * unit, which is recorded so its length needs no walk. */ static ScrStr *scr_bytes_decode_utf16le(const uint8_t *in, size_t n) { size_t units = n / 2; if (units > SIZE_MAX / 3) scr_bytes_oom(); ScrStr *s = scr_str_alloc_raw(0, units * 3); - size_t o = 0; - for (size_t u = 0; u < units;) o = scr_bytes_put_cp(s->data, o, scr_bytes_utf16le_cp(in, units, &u)); + uint8_t *out = (uint8_t *)s->data; + size_t o = 0, u = 0; + while (u < units) { +#if defined(__BYTE_ORDER__) && __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + if (units - u >= 4) { + uint64_t w; + memcpy(&w, in + u * 2, 8); + if (!(w & UINT64_C(0xff80ff80ff80ff80))) { + out[o] = (uint8_t)w; + out[o + 1] = (uint8_t)(w >> 16); + out[o + 2] = (uint8_t)(w >> 32); + out[o + 3] = (uint8_t)(w >> 48); + o += 4; + u += 4; + continue; + } + } +#endif + uint32_t cu = (uint32_t)in[u * 2] | ((uint32_t)in[u * 2 + 1] << 8); + if (cu >= 0x800 && (cu < 0xd800 || cu > 0xdfff)) { + /* Three bytes in one four-byte store; the next write (or the + * terminator) replaces the fourth. */ + uint8_t seq[4] = {(uint8_t)(0xe0 | (cu >> 12)), (uint8_t)(0x80 | ((cu >> 6) & 0x3f)), + (uint8_t)(0x80 | (cu & 0x3f)), 0}; + memcpy(out + o, seq, 4); + o += 3; + u++; + } else if (cu < 0x80) { + out[o++] = (uint8_t)cu; + u++; + } else if (cu < 0x800) { + out[o] = (uint8_t)(0xc0 | (cu >> 6)); + out[o + 1] = (uint8_t)(0x80 | (cu & 0x3f)); + o += 2; + u++; + } else { + o = scr_bytes_put_cp(s->data, o, scr_bytes_utf16le_cp(in, units, &u)); + } + } s->len = o; s->data[o] = '\0'; + if (o == units) scr_str_note_ascii(s); + else scr_str_note_utf16_len(s, units); return s; } @@ -3479,7 +3522,15 @@ static ScrBytes *scr_bytes_fill_core(ScrBytes *b, const uint8_t *pat, size_t pat } else if (patn == 1) { memset(dst, pat[0], e - o); } else { - for (size_t i = o; i < e; i++) dst[i - o] = pat[(i - o) % patn]; + /* Node's fill: the pattern's first bytes (memmove: the pattern may + * be a view of this buffer), then the filled prefix doubled. */ + size_t len = e - o, done = patn < len ? patn : len; + memmove(dst, pat, done); + while (done < len) { + size_t step = done < len - done ? done : len - done; + memcpy(dst + done, dst, step); + done += step; + } } if (b->shared) { scr_shared_store(b->data + o, dst, e - o); @@ -3558,11 +3609,29 @@ ScrBytes *scr_bytes_swap(ScrBytes *b, double width) { scr_throw_error_msg_code(SCR_ERR_RANGE, msg, (size_t)mlen, "ERR_INVALID_BUFFER_SIZE"); return NULL; } - for (size_t g = 0; g < b->len; g += w) { - for (size_t i = 0; i < w / 2; i++) { - uint8_t t = b->data[g + i]; - b->data[g + i] = b->data[g + w - 1 - i]; - b->data[g + w - 1 - i] = t; + /* One load, byte swap and store per group. */ + uint8_t *p = b->data; + size_t len = b->len; + if (w == 2) { + for (size_t g = 0; g < len; g += 2) { + uint16_t v; + memcpy(&v, p + g, 2); + v = __builtin_bswap16(v); + memcpy(p + g, &v, 2); + } + } else if (w == 4) { + for (size_t g = 0; g < len; g += 4) { + uint32_t v; + memcpy(&v, p + g, 4); + v = __builtin_bswap32(v); + memcpy(p + g, &v, 4); + } + } else { + for (size_t g = 0; g < len; g += 8) { + uint64_t v; + memcpy(&v, p + g, 8); + v = __builtin_bswap64(v); + memcpy(p + g, &v, 8); } } return scr_bytes_retain(b); diff --git a/packages/runtime/src/scr_string.c b/packages/runtime/src/scr_string.c index d2d397e25..dfd0d23f8 100644 --- a/packages/runtime/src/scr_string.c +++ b/packages/runtime/src/scr_string.c @@ -2006,6 +2006,19 @@ double scr_str_utf16_len(ScrStr *s) { return (double)(int64_t)units; } +/* Records the UTF-16 length of a string whose producer counted it (latin1 + * text has one unit per byte), so scr_str_utf16_len does not walk it. Only + * strings that scr_str_utf16_len would otherwise record are kept. */ +void scr_str_note_utf16_len(ScrStr *s, size_t units) { + if (s->ascii || s->len <= 64 || s->rc == SIZE_MAX) return; + if (!scr_u16len_tab) { + scr_u16len_tab = calloc(SCR_U16LEN_N, sizeof *scr_u16len_tab); + if (!scr_u16len_tab) return; + scr_sidx_register_cleanup(); + } + *scr_u16len_slot(s) = (ScrU16Len){s, units}; +} + double scr_str_char_code_at(ScrStr *s, double i) { /* A sequential scan of a non-ASCII receiver stays inside the bounded * ASCII span cached at its last resolved position. Its unit offset is an diff --git a/packages/runtime/src/scr_string.h b/packages/runtime/src/scr_string.h index fc2f15562..e269498b1 100644 --- a/packages/runtime/src/scr_string.h +++ b/packages/runtime/src/scr_string.h @@ -83,6 +83,9 @@ static inline void scr_str_hash_forget(ScrStr *s) { /* True only when every byte is proven below 0x80 (see above). */ static inline bool scr_str_known_ascii(const ScrStr *s) { return s->ascii; } +/* Record the UTF-16 length a string's producer counted (scr_string.c). */ +void scr_str_note_utf16_len(ScrStr *s, size_t units); + /* Record a proven-ASCII fact. Immortal strings may live in read-only * memory and are shared across threads, so they are never written. */ static inline void scr_str_note_ascii(ScrStr *s) { diff --git a/tests/corpus/8007-buffer-fill-swap-utf16le.ts b/tests/corpus/8007-buffer-fill-swap-utf16le.ts new file mode 100644 index 000000000..850c5b964 --- /dev/null +++ b/tests/corpus/8007-buffer-fill-swap-utf16le.ts @@ -0,0 +1,110 @@ +// Buffer fill with values of more than one byte, swap16/32/64, and +// toString("utf16le"): pattern lengths that do and do not divide the +// filled range, offsets and ends, patterns that are views of the buffer +// being filled, string encodings, sizes around word and pool boundaries, +// and utf16le text with ASCII runs, other BMP characters, surrogate pairs, +// lone surrogates and an odd last byte. + +function show(buf: Uint8Array): string { + return Buffer.from(buf).toString("hex"); +} + +const fills: string[] = []; +for (const size of [0, 1, 2, 3, 7, 8, 9, 31, 32, 33]) { + const buf = Buffer.alloc(size); + buf.fill("ab"); + fills.push(buf.toString("latin1")); + buf.fill(Buffer.from([1, 2, 3])); + fills.push(show(buf)); +} +console.log(fills.join(" ")); + +const ranged = Buffer.alloc(20); +ranged.fill("xyz", 3, 17); +console.log(ranged.toString("latin1").replace(/\0/g, ".")); +ranged.fill(Buffer.from("0123456789"), 5); +console.log(ranged.toString("latin1").replace(/\0/g, ".")); +ranged.fill("long pattern longer than the range", 2, 6); +console.log(ranged.toString("latin1").replace(/\0/g, ".")); +ranged.fill("é中", 0, 11); +console.log(show(ranged)); +ranged.fill("6869", 0, 7, "hex"); +ranged.fill("aGk=", 10, 15, "base64"); +console.log(show(ranged)); +ranged.fill("éa", 0, 20, "latin1"); +console.log(show(ranged)); +ranged.fill("ab", 0, 9, "utf16le"); +console.log(show(ranged)); + +// Patterns that are views of the buffer being filled. +const self = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); +self.fill(self.subarray(1, 3)); +console.log(show(self)); +const later = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); +later.fill(later.subarray(6, 9), 2); +console.log(show(later)); +const whole = Buffer.from([9, 8, 7, 6]); +whole.fill(whole); +console.log(show(whole)); +const typed = new Uint8Array(12); +typed.set([5, 6, 7], 0); +Buffer.from(typed.buffer).fill(typed.subarray(0, 3), 3); +console.log(show(typed)); + +const big = Buffer.alloc(70001); +big.fill("0123456"); +console.log(big.length, big.toString("latin1", 0, 10), big.toString("latin1", 69990), big.toString("latin1", 35000, 35010)); +try { + Buffer.alloc(4).fill(Buffer.alloc(0)); +} catch (error) { + console.log((error as NodeJS.ErrnoException).code); +} +console.log(show(Buffer.alloc(5).fill(""))); + +// swap16/32/64. +for (const size of [0, 8, 16, 24, 64, 1000]) { + const buf = Buffer.alloc(size); + for (let i = 0; i < size; i++) buf[i] = (i * 37 + 11) & 255; + const a = Buffer.from(buf).swap16(); + const b = Buffer.from(buf).swap32(); + const c = Buffer.from(buf).swap64(); + console.log(size, show(a.subarray(0, 8)), show(b.subarray(0, 8)), show(c.subarray(0, 8)), show(c.subarray(c.length - 8)), a.swap16().equals(buf)); +} +for (const [size, width] of [[3, 16], [6, 32], [12, 64]] as const) { + try { + const buf = Buffer.alloc(size); + if (width === 16) buf.swap16(); + else if (width === 32) buf.swap32(); + else buf.swap64(); + } catch (error) { + console.log((error as NodeJS.ErrnoException).code, (error as Error).message); + } +} +const view = Buffer.from([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]).subarray(1, 9); +view.swap32(); +console.log(show(view)); + +// toString("utf16le"). +const texts = [ + "plain ascii text", + "abcéÿĀ߿ࠀ中￿", + "ascii run then 中文 and more ascii after it", + "\u{1F600}\u{10FFFF}a\u{10000}", + "lone \ud800 high and \udc00 low and \ud83d", + "x".repeat(4097) + "é" + "y".repeat(3), +]; +for (const text of texts) { + const bytes = Buffer.from(text, "utf16le"); + const back = bytes.toString("utf16le"); + console.log(back === text, back.length, bytes.length, JSON.stringify(back.slice(0, 24)), back.charCodeAt(back.length - 1)); +} +const odd = Buffer.from([0x61, 0, 0x62, 0, 0x63]); +console.log(JSON.stringify(odd.toString("utf16le")), odd.toString("utf16le").length); +const pairSplit = Buffer.from([0x3d, 0xd8, 0x00, 0xde, 0x3d, 0xd8]); +const split = pairSplit.toString("utf16le"); +console.log(split.length, split.codePointAt(0), split.charCodeAt(2)); +const units = Buffer.alloc(40); +for (let i = 0; i < 40; i++) units[i] = (i * 53 + 7) & 255; +const decoded = units.toString("utf16le"); +console.log(decoded.length, [...decoded].map((c) => c.codePointAt(0)).join(",")); +console.log(units.toString("utf16le", 3, 21).length, units.toString("ucs2", 0, 8) === units.toString("utf16le", 0, 8)); diff --git a/tests/harness/corpus-costs/8007-buffer-fill-swap-utf16le.ts.json b/tests/harness/corpus-costs/8007-buffer-fill-swap-utf16le.ts.json new file mode 100644 index 000000000..2c773a1b8 --- /dev/null +++ b/tests/harness/corpus-costs/8007-buffer-fill-swap-utf16le.ts.json @@ -0,0 +1 @@ +{ "plain": 4406, "san": 2190 } From 872c12e247952524485022a9e1af90c89ce05c3e Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 05:59:55 -0500 Subject: [PATCH 243/259] Emit dev builds' function bodies on the emit workers --- .../compiler/src/backend/llvm/debug-info.ts | 104 ++++++++++++++++- .../compiler/src/backend/llvm/emit-journal.ts | 44 ++++++- .../compiler/src/backend/llvm/emit-module.ts | 8 +- packages/compiler/src/backend/llvm/emitter.ts | 32 ++++-- .../compiler/test/chunked-emission.test.ts | 108 +++++++++++------- 5 files changed, 232 insertions(+), 64 deletions(-) diff --git a/packages/compiler/src/backend/llvm/debug-info.ts b/packages/compiler/src/backend/llvm/debug-info.ts index 3a75c6263..aaa35d666 100644 --- a/packages/compiler/src/backend/llvm/debug-info.ts +++ b/packages/compiler/src/backend/llvm/debug-info.ts @@ -13,9 +13,37 @@ import { import { SourceLocations } from "../source-locations.js"; import { mangleFunction } from "../mangle.js"; -/** DWARF describes source bindings at their actual native storage locations. */ +/** A request a range emitter made of its debug info that added nodes + * (LlvmDebugInfo.record), with the ids it answered. */ +export type DebugRequest = + | { readonly op: "function"; readonly fn: string; readonly result: string } + | { + readonly op: "local"; + readonly local: IrLocal; + readonly fn: string; + readonly arg: number; + readonly captured: boolean; + readonly result: { variable: string; location: string }; + } + | { + readonly op: "location"; + readonly loc: SrcLoc; + readonly fn: string; + readonly result: string; + }; + +/** DWARF describes source bindings at their actual native storage locations. + * + * Nodes are numbered in request order. A range emitter (emit-module.ts) + * records the requests that added nodes; the emitter that merges the range + * replays them in order, so every node gets the number serial emission + * gives it, and renames the range's text from the ids the range answered to + * its own. A request that added no node answered an id that existed before + * the range started or that an earlier recorded request created. */ export class LlvmDebugInfo { private readonly nodes: string[] = []; + /** The requests that added nodes, while recording (record). */ + private requests: DebugRequest[] | null = null; private readonly files = new Map(); private readonly locations = new Map(); private readonly scopes = new Map(); @@ -73,7 +101,53 @@ export class LlvmDebugInfo { return unit; } + /** Records the requests that add nodes from here on. */ + record(): void { + this.requests = []; + } + + /** The requests recorded since record. */ + recorded(): readonly DebugRequest[] { + return this.requests ?? []; + } + + /** Replays a range's recorded requests in order and adds to `ids` the + * rename from the ids the range answered to this debug info's. */ + replay( + requests: readonly DebugRequest[], + functionNamed: (name: string) => IrFunction, + ids: Map, + ): void { + const own = (id: string, to: string | null | undefined): void => { + if (to === null || to === undefined) + throw new Error(`llvm emitter bug: debug request for ${id} added no node on replay`); + if (to !== id) ids.set(id, to); + }; + for (const request of requests) { + if (request.op === "function") { + own(request.result, this.function(functionNamed(request.fn))); + continue; + } + const fn = ids.get(request.fn) ?? request.fn; + if (request.op === "location") { + own(request.result, this.location(request.loc, fn)); + continue; + } + const local = this.local(request.local, fn, request.arg, request.captured); + own(request.result.variable, local?.variable); + own(request.result.location, local?.location); + } + } + function(fn: IrFunction): string | null { + const before = this.nodes.length; + const id = this.functionNode(fn); + if (this.requests !== null && id !== null && this.nodes.length > before) + this.requests.push({ op: "function", fn: fn.name, result: id }); + return id; + } + + private functionNode(fn: IrFunction): string | null { const pos = this.source.position(fn.loc); if (pos === null) return null; const file = this.file(pos.file); @@ -230,6 +304,26 @@ export class LlvmDebugInfo { fn: string | null, arg = 0, captured = false, + ): { variable: string; expression: string; location: string } | null { + const before = this.nodes.length; + const result = this.localNodes(local, fn, arg, captured); + if (this.requests !== null && fn !== null && result !== null && this.nodes.length > before) + this.requests.push({ + op: "local", + local, + fn, + arg, + captured, + result: { variable: result.variable, location: result.location }, + }); + return result; + } + + private localNodes( + local: IrLocal, + fn: string | null, + arg: number, + captured: boolean, ): { variable: string; expression: string; location: string } | null { if (fn === null || local.source === undefined) return null; const pos = this.source.position(local.source.loc); @@ -279,6 +373,14 @@ export class LlvmDebugInfo { } location(loc: SrcLoc, fn: string | null): string | null { + const before = this.nodes.length; + const id = this.locationNode(loc, fn); + if (this.requests !== null && fn !== null && id !== null && this.nodes.length > before) + this.requests.push({ op: "location", loc, fn, result: id }); + return id; + } + + private locationNode(loc: SrcLoc, fn: string | null): string | null { if (fn === null) return null; const pos = this.source.position(loc); if (pos === null) return null; diff --git a/packages/compiler/src/backend/llvm/emit-journal.ts b/packages/compiler/src/backend/llvm/emit-journal.ts index ad89d2671..d6fed03a6 100644 --- a/packages/compiler/src/backend/llvm/emit-journal.ts +++ b/packages/compiler/src/backend/llvm/emit-journal.ts @@ -5,6 +5,7 @@ * replay calls the same entry point with the same arguments, so every * helper gets the number and the definition the serial emission gives it, * and the range's text is renamed to those numbers. */ +import type { DebugRequest } from "./debug-info.js"; import type { LlEmitter } from "./emitter.js"; /** One event of a range's emission, in order. */ @@ -97,6 +98,8 @@ export class EmitJournal { * worker process can write it. */ export interface ChunkResult { readonly entries: readonly JournalEntry[]; + /** The requests that added debug metadata nodes (LlvmDebugInfo.record). */ + readonly debugRequests: readonly DebugRequest[]; readonly flags: { readonly usesCoroutines: boolean; readonly usesTimers: boolean; @@ -152,23 +155,56 @@ export function replayJournal( } /** The rename of a range's text: numbered names (`names`, without the - * sigil) and field alias tags (`tags`). One scan for each kind of name: - * a numbered name starts `sc_` after a character that cannot be part of a - * name, and ends at the last digit after its counter prefix. */ + * sigil), field alias tags (`tags`) and debug metadata ids (`debugIds`, + * `!N`). One scan for each kind of name: a numbered name starts `sc_` + * after a character that cannot be part of a name, and ends at the last + * digit after its counter prefix. */ export function renameChunk( names: ReadonlyMap, tags: ReadonlyMap, + debugIds: ReadonlyMap = new Map(), ): (text: string) => string { const prefixes = new Set(); for (const name of names.keys()) prefixes.add(name.replace(/\d+$/, "")); - if (prefixes.size === 0 && tags.size === 0) return (text) => text; + if (prefixes.size === 0 && tags.size === 0 && debugIds.size === 0) return (text) => text; return (text) => { let out = prefixes.size === 0 ? text : renameNames(text, names, prefixes); if (tags.size > 0) out = renameTags(out, tags); + if (debugIds.size > 0) out = renameDebugIds(out, debugIds); return out; }; } +/** Renames metadata references `!N` outside string literals. Debug builds + * attach no alias tags, so every such reference in a function's text is a + * debug metadata id. */ +function renameDebugIds(text: string, ids: ReadonlyMap): string { + const parts: string[] = []; + let copied = 0; + // The next quote at or after the scan, and whether the scan is inside a + // string literal. + let quote = text.indexOf('"'); + let quoted = false; + for (let at = text.indexOf("!"); at >= 0; at = text.indexOf("!", at + 1)) { + while (quote >= 0 && quote < at) { + quoted = !quoted; + quote = text.indexOf('"', quote + 1); + } + if (quoted) continue; + if (at > 0 && isNameChar(text.charCodeAt(at - 1))) continue; + let end = at + 1; + while (end < text.length && isDigit(text.charCodeAt(end))) end++; + if (end === at + 1 || (end < text.length && isNameChar(text.charCodeAt(end)))) continue; + const own = ids.get(text.slice(at, end)); + if (own === undefined) continue; + parts.push(text.slice(copied, at), own); + copied = end; + } + if (copied === 0) return text; + parts.push(text.slice(copied)); + return parts.join(""); +} + function renameNames( text: string, names: ReadonlyMap, diff --git a/packages/compiler/src/backend/llvm/emit-module.ts b/packages/compiler/src/backend/llvm/emit-module.ts index dfdd95451..6a33924c3 100644 --- a/packages/compiler/src/backend/llvm/emit-module.ts +++ b/packages/compiler/src/backend/llvm/emit-module.ts @@ -134,6 +134,7 @@ function emitFunctionsOnWorkers(emitter: LlEmitter, workers: number): string[] | let code = 1; try { emitter.journal = new EmitJournal(); + emitter.debug?.record(); const texts: string[] = []; for (const fn of functions.slice(range * size, (range + 1) * size)) { texts.push(emitter.emitFunction(fn)); @@ -230,13 +231,10 @@ const PARTITION_GROUP_END = "; scriptc-group"; export function emitModuleParts(emitter: LlEmitter): string[] { // Function bodies first (the literal/unit/fn-value tables fill as they // emit), then the file assembles around them — the runtime ABI’s order. - // Debug metadata is numbered per emitter and not journaled, so a debug - // build emits every body here. - const ranges = emitter.debug === null; const chunks = emitter.targetOptions.functionChunks ?? 1; const fnDefs = - (ranges && chunks > 1 ? emitFunctionsInChunks(emitter, chunks) : null) ?? - (ranges ? emitFunctionsOnWorkers(emitter, emitter.targetOptions.functionWorkers ?? 1) : null) ?? + (chunks > 1 ? emitFunctionsInChunks(emitter, chunks) : null) ?? + emitFunctionsOnWorkers(emitter, emitter.targetOptions.functionWorkers ?? 1) ?? []; if (fnDefs.length === 0) for (const fn of emitter.mod.functions) { diff --git a/packages/compiler/src/backend/llvm/emitter.ts b/packages/compiler/src/backend/llvm/emitter.ts index d1f4ebcca..8dc1f912a 100644 --- a/packages/compiler/src/backend/llvm/emitter.ts +++ b/packages/compiler/src/backend/llvm/emitter.ts @@ -476,14 +476,13 @@ export interface LlvmTargetOptions { * earlier emission found breaking its rules (UnwindAbiViolation). */ unwindExcluded?: ReadonlySet; /** Emit the function bodies in this many contiguous ranges, each by its - * own emitter, and merge them in function order (emit-journal.ts). The - * output is the same as one emitter's. Debug builds (`debugSources`) - * emit in one emitter. */ + * own emitter, and merge them in function order (emit-journal.ts, and + * debug-info.ts for debug metadata). The output is the same as one + * emitter's. */ functionChunks?: number; /** Emit the function bodies of a large module on this many forked worker * processes at a time (emit-module.ts), forked with `forkPrimitives`. The - * output is the same as one emitter's. Debug builds (`debugSources`) - * emit in one emitter. */ + * output is the same as one emitter's. */ functionWorkers?: number; /** The host's process primitives, where it can fork (the native * compiler's). */ @@ -1889,9 +1888,7 @@ export class LlEmitter { this.journal = journal; this.journaled = journal !== null || - ((options.functionWorkers ?? 1) > 1 && - options.forkPrimitives !== undefined && - options.debugSources === undefined); + ((options.functionWorkers ?? 1) > 1 && options.forkPrimitives !== undefined); // One walk of every body, which the analyses below read instead of // walking the bodies themselves. this.nodeIndex = int32Analysis?.nodeIndex ?? new IrNodeIndex(mod); @@ -5264,6 +5261,7 @@ export class LlEmitter { chunkResult(): ChunkResult { return { entries: this.journal!.entries, + debugRequests: this.debug?.recorded() ?? [], flags: { usesCoroutines: this.usesCoroutines, usesTimers: this.usesTimers, @@ -5299,6 +5297,8 @@ export class LlEmitter { // emission left them (a helper set guards the declarations its first // request adds). replayJournal(this, chunk.entries, names, tags); + const debugIds = new Map(); + this.debug?.replay(chunk.debugRequests, (name) => this.functionNamed(name), debugIds); const flags = chunk.flags; this.usesCoroutines ||= flags.usesCoroutines; this.usesTimers ||= flags.usesTimers; @@ -5319,7 +5319,13 @@ export class LlEmitter { for (const name of chunk.adoptCallees) this.adoptCallees.add(name); for (const name of chunk.directAwaitCallees) this.directAwaitCallees.add(name); for (const name of chunk.inlineAwaitCallees) this.inlineAwaitCallees.add(name); - return renameChunk(names, tags); + return renameChunk(names, tags, debugIds); + } + + private functionNamed(name: string): IrFunction { + const fn = this.fnByName.get(name); + if (fn === undefined) throw new InternalCompilerError(`llvm emitter bug: no function ${name}`); + return fn; } /** Adds a content-named constant a chunk interned. Its symbol is this @@ -5447,7 +5453,13 @@ export class LlEmitter { /** An emitter for a range of this module's functions: the same facts, * empty module-level tables, and a journal of what the range adds. */ chunkEmitter(): LlEmitter { - return new LlEmitter(this.mod, { ...this.targetOptions, functionChunks: 1 }, new EmitJournal()); + const chunk = new LlEmitter( + this.mod, + { ...this.targetOptions, functionChunks: 1 }, + new EmitJournal(), + ); + chunk.debug?.record(); + return chunk; } /** The double-ABI entry of a function with an i32 entry: every caller diff --git a/packages/compiler/test/chunked-emission.test.ts b/packages/compiler/test/chunked-emission.test.ts index 6d2b2e06a..567a082ef 100644 --- a/packages/compiler/test/chunked-emission.test.ts +++ b/packages/compiler/test/chunked-emission.test.ts @@ -103,57 +103,77 @@ test("a Promise.all tuple adapter requested in a range is defined", async () => } }, 60_000); -// Debug metadata is numbered per emitter (debug-info.ts) and not journaled: -// a debug build emits its function bodies in one emitter. Its one fork -// computes the int32 slot analysis; when the fork fails, the emitter -// computes it itself. -test("debug builds emit function bodies serially, with every metadata reference defined", async () => { +// Debug builds journal their metadata requests (debug-info.ts): ranges +// merged in function order number every node as one emitter does. +const DEBUG_PROGRAMS: { entry: string; sources: string[] }[] = [ + { + entry: "3066-source-debugging/main.ts", + sources: ["3066-source-debugging/main.ts", "3066-source-debugging/helper.ts"], + }, + ...[ + "1020-async-basics.ts", + "7103-fiberless-plain-calls.ts", + "7110-als-completion-callbacks.ts", + "1301-errors-subclass.ts", + "1529-class-with-statics.ts", + "1591-js-closures.js", + "2010-generators-basics.ts", + "2013-generators-sent-values.ts", + "4451-int32-field-storage.ts", + ].map((program) => ({ entry: program, sources: [program] })), +]; + +test("debug builds emitted in ranges merge into the text one emitter gives", async () => { const dir = await mkdtemp(join(tmpdir(), "scriptc-chunked-debug-")); const minFunctions = process.env["SCRIPTC_EMIT_WORKER_FUNCTIONS"]; try { - const corpus = join(import.meta.dirname, "../../../tests/corpus/3066-source-debugging"); - const entry = join(corpus, "main.ts"); - const outPath = join(dir, "main.ir.json"); - const result = await compile(entry, { - outDir: dir, - outPath, - outputKind: "ir", - optimization: "dev", - }); - if (!result.ok) - throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); - const ir = await readFile(outPath, "utf8"); - const debugSources = new Map(); - for (const name of ["main.ts", "helper.ts"]) - debugSources.set(join(corpus, name), await readFile(join(corpus, name), "utf8")); - const options: LlvmTargetOptions = { debugSources }; - const serial = text(emitLlvmModuleSource(deserializeModule(ir), options)); - expect(serial).toContain("!DILocation"); + const corpus = join(import.meta.dirname, "../../../tests/corpus"); + for (const program of DEBUG_PROGRAMS) { + const outPath = join(dir, "main.ir.json"); + const result = await compile(join(corpus, program.entry), { + outDir: dir, + outPath, + outputKind: "ir", + optimization: "dev", + }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + const ir = await readFile(outPath, "utf8"); + const debugSources = new Map(); + for (const name of program.sources) + debugSources.set(join(corpus, name), await readFile(join(corpus, name), "utf8")); + const options: LlvmTargetOptions = { debugSources }; + const serial = text(emitLlvmModuleSource(deserializeModule(ir), options)); + expect(serial, program.entry).toContain("!DILocation"); - let forks = 0; - process.env["SCRIPTC_EMIT_WORKER_FUNCTIONS"] = "1"; - const forkPrimitives = { - fork: (): number => { - forks++; - return -1; - }, - exit: (): void => {}, - wait: (): number => -1, - }; - for (const variant of [ - { functionChunks: 3 }, - { functionWorkers: 4, forkPrimitives }, - ] satisfies LlvmTargetOptions[]) { - const emitted = text(emitLlvmModuleSource(deserializeModule(ir), { ...options, ...variant })); - expect(emitted === serial, JSON.stringify(Object.keys(variant))).toBe(true); - const defined = new Set([...emitted.matchAll(/^(![0-9]+) = /gm)].map((m) => m[1])); - const referenced = new Set([...emitted.matchAll(/(![0-9]+)\b/g)].map((m) => m[1])); - expect([...referenced].filter((id) => !defined.has(id))).toEqual([]); + // A fork that fails leaves every range to the merging emitter. + process.env["SCRIPTC_EMIT_WORKER_FUNCTIONS"] = "1"; + const forkPrimitives = { + fork: (): number => -1, + exit: (): void => {}, + wait: (): number => -1, + }; + for (const variant of [ + { functionChunks: 2 }, + { functionChunks: 5 }, + { functionWorkers: 4, forkPrimitives }, + ] satisfies LlvmTargetOptions[]) { + const emitted = text( + emitLlvmModuleSource(deserializeModule(ir), { ...options, ...variant }), + ); + expect(emitted === serial, `${program.entry} ${JSON.stringify(Object.keys(variant))}`).toBe( + true, + ); + const defined = new Set([...emitted.matchAll(/^(![0-9]+) = /gm)].map((m) => m[1])); + const referenced = new Set([...emitted.matchAll(/(![0-9]+)\b/g)].map((m) => m[1])); + expect([...referenced].filter((id) => !defined.has(id))).toEqual([]); + } + if (minFunctions === undefined) delete process.env["SCRIPTC_EMIT_WORKER_FUNCTIONS"]; + else process.env["SCRIPTC_EMIT_WORKER_FUNCTIONS"] = minFunctions; } - expect(forks).toBe(1); } finally { if (minFunctions === undefined) delete process.env["SCRIPTC_EMIT_WORKER_FUNCTIONS"]; else process.env["SCRIPTC_EMIT_WORKER_FUNCTIONS"] = minFunctions; await rm(dir, { recursive: true, force: true }); } -}, 120_000); +}, 300_000); From 627ebd86a51546f2fd6d40a82caab8191ceee667 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 06:16:32 -0500 Subject: [PATCH 244/259] Call replace callbacks with unannotated parameters directly TypeScript types the parameters of an inline replace callback after the match `any`. An unannotated parameter that is never reassigned, whose every read means the same for a string or number as for `any`, and that receives a capture every match sets, the offset or the subject now takes that value's type. String-search callbacks get the same treatment for the offset and the subject. scr_regex_replace_fn calls the closure directly in more cases: - checked-dynamic parameters, which receive the boxed value Node passes at their position (a capture or undefined, the offset, the subject, the groups object, then undefined); - `string | undefined` capture parameters, which receive NULL when the match leaves the capture unset; - a checked-dynamic result, converted with ToString; - up to six parameters. Callbacks of the earlier typed form compile to the same call, with a kinds argument of 0, and run the same per-match work. --- benchmarks/runtime/README.md | 1 + .../runtime/workloads/regex-replacers.json | 6 + .../runtime/workloads/regex-replacers.ts | 60 ++++ .../compiler/src/backend/llvm/lib-dispatch.ts | 77 +++-- .../containers/replacer-params.test.ts | 63 ++++ .../lowering/containers/replacer-params.ts | 292 ++++++++++++++++++ .../lowering/containers/string-and-regexp.ts | 7 +- .../lowering/containers/string-replacement.ts | 14 +- .../compiler/test/replacer-params.test.ts | 84 +++++ .../tests/corpus/8118-replacer-params.ts.json | 6 + ...45-replace-callback-untyped-params.ts.json | 6 + ...6-replace-callback-untyped-params.mjs.json | 6 + packages/runtime/src/scr_regex.c | 203 +++++++++--- packages/runtime/src/scr_regex.h | 26 +- tests/corpus/8118-replacer-params.ts | 43 +++ .../8345-replace-callback-untyped-params.ts | 85 +++++ .../8346-replace-callback-untyped-params.mjs | 32 ++ .../corpus-costs/8118-replacer-params.ts.json | 1 + ...45-replace-callback-untyped-params.ts.json | 1 + ...6-replace-callback-untyped-params.mjs.json | 1 + 20 files changed, 941 insertions(+), 73 deletions(-) create mode 100644 benchmarks/runtime/workloads/regex-replacers.json create mode 100644 benchmarks/runtime/workloads/regex-replacers.ts create mode 100644 packages/compiler/src/frontend/lowering/containers/replacer-params.test.ts create mode 100644 packages/compiler/src/frontend/lowering/containers/replacer-params.ts create mode 100644 packages/compiler/test/replacer-params.test.ts create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8118-replacer-params.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8345-replace-callback-untyped-params.ts.json create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8346-replace-callback-untyped-params.mjs.json create mode 100644 tests/corpus/8118-replacer-params.ts create mode 100644 tests/corpus/8345-replace-callback-untyped-params.ts create mode 100644 tests/corpus/8346-replace-callback-untyped-params.mjs create mode 100644 tests/harness/corpus-costs/8118-replacer-params.ts.json create mode 100644 tests/harness/corpus-costs/8345-replace-callback-untyped-params.ts.json create mode 100644 tests/harness/corpus-costs/8346-replace-callback-untyped-params.mjs.json diff --git a/benchmarks/runtime/README.md b/benchmarks/runtime/README.md index 520964cf3..af3d3d239 100644 --- a/benchmarks/runtime/README.md +++ b/benchmarks/runtime/README.md @@ -30,6 +30,7 @@ Application-shaped workloads for measuring the speed of compiled executables. Ea | `record-boundaries` | cpu | records built from unchecked array reads passed to and returned from annotated functions | | `records-sort` | cpu | comparator sorts, group-by, `reduce`/`filter` | | `regex-logs` | cpu | regex `exec` with groups, `test`, global `replace` | +| `regex-replacers` | cpu | regex `replace`/`replaceAll` with inline callbacks whose parameters have no annotations: dictionary placeholders, snake_case to camelCase, date reordering, optional captures, capitalization, and a string search that reads the offset | | `region-builds` | cpu | a watch-mode build loop over `LifetimeRegion`: each build binds a program in a new region and releases the previous one, which a cache keeps referenced for two builds | | `template-render` | cpu | template literals, escaping, `map`/`join` | | `throw-chains` | cpu | exceptions caught 2, 5 and 20 recursive calls above the throw, through direct calls and through a callback, and a backtracking parser that throws on a failed alternative | diff --git a/benchmarks/runtime/workloads/regex-replacers.json b/benchmarks/runtime/workloads/regex-replacers.json new file mode 100644 index 000000000..c01c6c272 --- /dev/null +++ b/benchmarks/runtime/workloads/regex-replacers.json @@ -0,0 +1,6 @@ +{ + "entry": "workloads/regex-replacers.ts", + "args": [ + "1" + ] +} diff --git a/benchmarks/runtime/workloads/regex-replacers.ts b/benchmarks/runtime/workloads/regex-replacers.ts new file mode 100644 index 000000000..be3820b89 --- /dev/null +++ b/benchmarks/runtime/workloads/regex-replacers.ts @@ -0,0 +1,60 @@ +// Regex replace and replaceAll with inline callbacks, written as they +// usually are, without parameter annotations: template placeholders looked +// up in a dictionary, snake_case to camelCase, date reordering, optional +// version parts, capitalization and a string search with its offset. +let seed = 7; +function random(): number { + seed = (Math.imul(seed, 1103515245) + 12345) >>> 0; + return seed / 4294967296; +} +function pick(items: readonly T[]): T { + return items[Math.floor(random() * items.length)]!; +} + +const words = ["user", "order", "item", "cart", "price", "total", "status", "created", "updated", "id"]; +const names = ["Ada", "Grace", "Linus", "Barbara", "Ken", "Margaret"]; +const vars: Record = { + name: "world", + city: "Lisbon", + day: "Tuesday", + plan: "pro", + count: "12", +}; +const keys = [...Object.keys(vars), "missing"]; + +const scale = Number(process.argv[2] ?? "1"); +const count = Math.floor(20000 * scale); +const templates: string[] = []; +const identifiers: string[] = []; +const dates: string[] = []; +const versions: string[] = []; +const sentences: string[] = []; +for (let i = 0; i < count; i++) { + templates.push(`Hello {${pick(keys)}}, your {${pick(keys)}} plan renews on {${pick(keys)}} in {${pick(keys)}}.`); + identifiers.push(`${pick(words)}_${pick(words)}_${pick(words)}${random() < 0.5 ? "_" + pick(words) : ""}`); + const year = 1990 + Math.floor(random() * 40); + const month = String(1 + Math.floor(random() * 12)).padStart(2, "0"); + const day = String(1 + Math.floor(random() * 28)).padStart(2, "0"); + dates.push(`from ${year}-${month}-${day} to ${year + 1}-${month}-${day} (${pick(names)})`); + versions.push(`v${i % 9}.${i % 13}${random() < 0.5 ? "." + (i % 7) : ""} and v${i % 5}.${i % 3}`); + sentences.push(`${pick(names)} said the ${pick(words)} and the ${pick(words)} were ready for ${pick(names)}`); +} + +let length = 0; +let checksum = 0; +for (let round = 0; round < 4; round++) { + for (let i = 0; i < count; i++) { + const filled = templates[i]!.replace(/\{(\w+)\}/g, (_m, key) => vars[key] ?? `<${key}>`); + const camel = identifiers[i]!.replace(/_([a-z])/g, (_m, c) => c.toUpperCase()); + const reordered = dates[i]!.replace(/(\d{4})-(\d{2})-(\d{2})/g, (_m, y, m, d) => `${d}/${m}/${y}`); + const padded = versions[i]!.replace(/v(\d+)\.(\d+)(?:\.(\d+))?/g, (_m, major, minor, patch) => `v${major}.${minor}.${patch ?? "0"}`); + const titled = sentences[i]!.replace(/\b[a-z]/g, (c) => c.toUpperCase()); + const marked = sentences[i]!.replaceAll("the", (m, at) => (at % 2 === 0 ? m.toUpperCase() : m)); + length += filled.length + camel.length + reordered.length + padded.length + titled.length + marked.length; + checksum = (checksum * 31 + camel.charCodeAt(camel.length - 1) + padded.charCodeAt(padded.length - 1)) >>> 0; + } +} +console.log(templates[0]!.replace(/\{(\w+)\}/g, (_m, key) => vars[key] ?? `<${key}>`)); +console.log(identifiers[1]!.replace(/_([a-z])/g, (_m, c) => c.toUpperCase())); +console.log(versions[2]!.replace(/v(\d+)\.(\d+)(?:\.(\d+))?/g, (_m, major, minor, patch) => `v${major}.${minor}.${patch ?? "0"}`)); +console.log("length", length, "checksum", checksum); diff --git a/packages/compiler/src/backend/llvm/lib-dispatch.ts b/packages/compiler/src/backend/llvm/lib-dispatch.ts index 8a98fb154..4af8182a7 100644 --- a/packages/compiler/src/backend/llvm/lib-dispatch.ts +++ b/packages/compiler/src/backend/llvm/lib-dispatch.ts @@ -843,35 +843,68 @@ function emitAssertFailing( * `a.name.localeCompare(b.name)` reads both fields without retaining). */ const READ_ONLY_STRING_LIB_FNS: ReadonlySet = new Set(["str.localeCompare"]); -/** The parameter count of a replace callback the runtime can call through - * the closure ABI (scr_regex_replace_fn), or null when it needs the dyn - * box. Each declared parameter must receive a value of its declared kind - * in every match: the match string at 0; with more than one parameter the +/** The most parameters scr_regex_replace_fn calls a replacer with + * (SCR_REPLACER_MAX_ARITY), the first bit of its string-or-undefined + * parameters (SCR_REPLACER_OPTIONAL), and its flag for a checked-dynamic + * result (SCR_REPLACER_BOXED_RESULT). */ +const REPLACER_MAX_ARITY = 6; +const REPLACER_OPTIONAL = 2 ** 8; +const REPLACER_BOXED_RESULT = 2 ** 31; + +/** `string | undefined` held as the string pointer, NULL for undefined. */ +function optionalStringType(host: LlvmEmitterContext, type: IrType): boolean { + if (type.kind !== "union") return false; + const nullable = host.nullableUnions.get(type.unionId); + if (nullable?.repr !== "single" || nullable.arm.kind !== "string" || nullable.nullTag >= 0) + return false; + return host.unionsById.get(type.unionId)?.arms[nullable.unitTag]?.kind === "undefinedT"; +} + +/** The parameter count and kinds (scr_regex_replace_fn's `kinds`) of a + * replace callback the runtime can call through the closure ABI, or null + * when it needs the dyn box. A checked-dynamic parameter receives whatever + * Node passes at its position. Each typed parameter must receive a value of + * its declared kind in every match: the match string at 0; past 0 the * pattern must be a literal whose captures are known, so position i is a - * capture that every match sets (a string), the offset (a number) right - * after the captures, or the subject (a string) after that. */ -function typedReplacerArity(callback: IrType, pattern: IrExpr): number | null { + * capture (a string when every match sets it, otherwise `string | + * undefined`), the offset (a number) right after the captures, or the + * subject (a string) after that. The result is a string or a + * checked-dynamic value. */ +function typedReplacerShape( + host: LlvmEmitterContext, + callback: IrType, + pattern: IrExpr, +): { arity: number; kinds: number } | null { if (callback.kind !== "func" || callback.rest || callback.argumentsAll) return null; - if (callback.ret.kind !== "string") return null; + if (callback.ret.kind !== "string" && callback.ret.kind !== "dyn") return null; const params = callback.params; - if (params.length > 4) return null; - if (params.length === 0) return 0; - if (params[0]!.kind !== "string") return null; - if (params.length === 1) return 1; - if (pattern.kind !== "regexLit") return null; - const captures = regexLiteralCaptures(pattern.pattern, pattern.flags); - if (!captures) return null; - for (let i = 1; i < params.length; i++) { + if (params.length > REPLACER_MAX_ARITY) return null; + let kinds = callback.ret.kind === "dyn" ? REPLACER_BOXED_RESULT : 0; + let captures: { count: number; always: boolean[] } | null | undefined; + for (let i = 0; i < params.length; i++) { const kind = params[i]!.kind; + if (kind === "dyn") { + kinds += 2 ** i; + continue; + } + const optional = optionalStringType(host, params[i]!); + if (i === 0) { + if (kind !== "string") return null; + continue; + } + if (pattern.kind !== "regexLit") return null; + captures ??= regexLiteralCaptures(pattern.pattern, pattern.flags); + if (!captures) return null; const ok = i < captures.count - ? kind === "string" && captures.always[i] === true + ? (kind === "string" && captures.always[i] === true) || optional : i === captures.count ? kind === "f64" : i === captures.count + 1 && kind === "string"; if (!ok) return null; + if (optional) kinds += REPLACER_OPTIONAL * 2 ** i; } - return params.length; + return { arity: params.length, kinds }; } /** `s.replace(re, fn)` / `replaceAll` with a typed callback the runtime can @@ -881,16 +914,16 @@ function typedReplacerArity(callback: IrType, pattern: IrExpr): number | null { function emitTypedRegexReplace(host: LlvmEmitterContext, e: LibCallExpr): LlValue | null { const [subject, pattern, callback, all] = e.args; if (!subject || !pattern || callback?.kind !== "dynFrom" || all?.kind !== "boolLit") return null; - const arity = typedReplacerArity(callback.value.type, pattern); - if (arity === null) return null; + const shape = typedReplacerShape(host, callback.value.type, pattern); + if (shape === null) return null; const B = host.B; const s = host.emitExpr(subject); const re = host.emitExpr(pattern); const fn = host.emitExpr(callback.value); - host.declare(`declare ptr @scr_regex_replace_fn(ptr, ptr, ptr, i32, i1 zeroext)`); + host.declare(`declare ptr @scr_regex_replace_fn(ptr, ptr, ptr, i32, i32, i1 zeroext)`); const result = B.tmp(); B.line( - `${result} = call ptr @scr_regex_replace_fn(ptr ${s.name}, ptr ${re.name}, ptr ${fn.name}, i32 ${arity}, i1 zeroext ${all.value})`, + `${result} = call ptr @scr_regex_replace_fn(ptr ${s.name}, ptr ${re.name}, ptr ${fn.name}, i32 ${shape.arity}, i32 ${shape.kinds | 0}, i1 zeroext ${all.value})`, ); const output = host.own({ name: result, type: e.type }); host.emitPendingCheck(); diff --git a/packages/compiler/src/frontend/lowering/containers/replacer-params.test.ts b/packages/compiler/src/frontend/lowering/containers/replacer-params.test.ts new file mode 100644 index 000000000..1d5d376e9 --- /dev/null +++ b/packages/compiler/src/frontend/lowering/containers/replacer-params.test.ts @@ -0,0 +1,63 @@ +import { describe, expect, test } from "vitest"; +import { regexCaptureParticipation } from "./replacer-params.js"; + +describe("regex capture participation", () => { + test("counts captures and marks the ones every match sets", () => { + expect(regexCaptureParticipation("\\{(\\w+)\\}", "g")).toEqual({ + count: 2, + always: [true, true], + }); + expect(regexCaptureParticipation("(\\d{4})-(\\d{2})(?:-(\\d{2}))?", "g")).toEqual({ + count: 4, + always: [true, true, true, false], + }); + expect(regexCaptureParticipation("(a)|(b)", "")).toEqual({ + count: 3, + always: [true, false, false], + }); + expect(regexCaptureParticipation("((a)|b)", "")).toEqual({ + count: 3, + always: [true, true, false], + }); + expect(regexCaptureParticipation("(?:(a)|b)(c)", "")).toEqual({ + count: 3, + always: [true, false, true], + }); + expect(regexCaptureParticipation("(a)*(b)+(c){0,2}(d){1,3}(e){00}", "")).toEqual({ + count: 6, + always: [true, false, true, false, true, false], + }); + expect(regexCaptureParticipation("(?=(a))(?!(b))(?<=(c))(?e)", "")).toEqual({ + count: 6, + always: [true, false, false, false, false, true], + }); + }); + + test("skips escapes, classes and non-capturing groups", () => { + expect(regexCaptureParticipation("\\((a)\\)[(|)\\]](?:b)(?i:c)", "")).toEqual({ + count: 2, + always: [true, true], + }); + expect(regexCaptureParticipation("[](a)", "")).toEqual({ count: 2, always: [true, true] }); + expect(regexCaptureParticipation("(a)[", "")).toBeNull(); + expect(regexCaptureParticipation("(a", "")).toBeNull(); + expect(regexCaptureParticipation("a)", "")).toBeNull(); + expect(regexCaptureParticipation("(a)", "v")).toBeNull(); + }); + test("marks captures in alternations, optional groups and lookarounds", () => { + const always = (pattern: string): boolean[] | null => + regexCaptureParticipation(pattern, "")?.always ?? null; + expect(always("tag(\\d+)")).toEqual([true, true]); + expect(always("((a)b)+c")).toEqual([true, true, true]); + expect(always("(?\\d)(x)")).toEqual([true, true, true]); + expect(always("(a){2,3}")).toEqual([true, true]); + expect(always("(?:x|y)(a)")).toEqual([true, true]); + expect(always("(?:(a)|b)c")).toEqual([true, false]); + expect(always("(x)?(\\d)")).toEqual([true, false, true]); + expect(always("(?:(t)a)*g")).toEqual([true, false]); + expect(always("((a)?)")).toEqual([true, true, false]); + expect(always("(?<=(-))(\\w)")).toEqual([true, false, true]); + expect(always("[\\]|(](b)")).toEqual([true, true]); + expect(always("[^)](c)\\|")).toEqual([true, true]); + }); +}); diff --git a/packages/compiler/src/frontend/lowering/containers/replacer-params.ts b/packages/compiler/src/frontend/lowering/containers/replacer-params.ts new file mode 100644 index 000000000..e84ca1461 --- /dev/null +++ b/packages/compiler/src/frontend/lowering/containers/replacer-params.ts @@ -0,0 +1,292 @@ +import * as ts from "../../ts7/adapter.js"; +import { F64, STRING, type IrExpr, type IrType } from "../../../ir/ir.js"; +import type { Lowerer } from "../lowerer.js"; +import { bindingNeverReassigned } from "../binding-analysis.js"; + +/** The captures of a regex literal's pattern (the whole match included) + * and, per capture, whether every successful match sets it. A capture may + * be unset when an enclosing group has alternatives, when an enclosing + * group or the capture itself is quantified with a minimum of zero, or + * when it sits inside a lookaround. Null for the `v` flag (nested + * classes) and for a pattern the scan does not finish. */ +export function regexCaptureParticipation( + pattern: string, + flags: string, +): { count: number; always: boolean[] } | null { + if (flags.includes("v")) return null; + const always: boolean[] = [true]; + /** Open groups: the group's own capture (-1 when it does not capture), + * the captures nested in it, whether it has alternatives, and whether it + * is a lookaround. */ + const frames: { own: number; nested: number[]; alternatives: boolean; lookaround: boolean }[] = [ + { own: -1, nested: [], alternatives: false, lookaround: false }, + ]; + let i = 0; + while (i < pattern.length) { + const c = pattern[i]!; + if (c === "\\") { + i += 2; + continue; + } + if (c === "[") { + // The first unescaped `]` ends the class (`[]` is an empty class). + i++; + while (i < pattern.length && pattern[i] !== "]") i += pattern[i] === "\\" ? 2 : 1; + if (i >= pattern.length) return null; + i++; + continue; + } + if (c === "|") { + frames[frames.length - 1]!.alternatives = true; + i++; + continue; + } + if (c === "(") { + let capture = false; + let lookaround = false; + if (pattern[i + 1] !== "?") { + capture = true; + i++; + } else if (pattern[i + 2] === "<" && pattern[i + 3] !== "=" && pattern[i + 3] !== "!") { + const gt = pattern.indexOf(">", i + 3); + if (gt < 0) return null; + capture = true; + i = gt + 1; + } else { + const kind = pattern[i + 2] === "<" ? pattern[i + 3] : pattern[i + 2]; + lookaround = kind === "=" || kind === "!"; + i += 2; + } + frames.push({ + own: capture ? always.length : -1, + nested: [], + alternatives: false, + lookaround, + }); + if (capture) always.push(true); + continue; + } + if (c === ")") { + if (frames.length === 1) return null; + const frame = frames.pop()!; + i++; + const next = pattern[i]; + const optional = + next === "?" || next === "*" || (next === "{" && /^\{0+[,}]/.test(pattern.slice(i))); + const parent = frames[frames.length - 1]!; + // Alternatives inside the group leave its nested captures unset, but + // not the group's own capture. + for (const index of frame.nested) { + if (optional || frame.lookaround || frame.alternatives) always[index] = false; + parent.nested.push(index); + } + if (frame.own >= 0) { + if (optional || frame.lookaround) always[frame.own] = false; + parent.nested.push(frame.own); + } + continue; + } + i++; + } + if (frames.length !== 1) return null; + if (frames[0]!.alternatives) for (const index of frames[0]!.nested) always[index] = false; + return { count: always.length, always }; +} + +/** String members a refined parameter may use: these lower from the + * receiver's type whatever the checker resolved for an `any` receiver. */ +const STRING_MEMBERS: ReadonlySet = new Set([ + "length", + "toUpperCase", + "toLowerCase", + "trim", + "charCodeAt", + "codePointAt", + "slice", + "substring", + "repeat", + "padStart", + "padEnd", + "includes", + "startsWith", + "endsWith", + "indexOf", +]); + +/** Whether every read of `symbol` in `body` is one that means the same + * for an `any` value and for a `kind` value, and lowers for both: a + * template span, a Number/String/parseInt/parseFloat argument, a listed + * string member, `+`, strict equality, arithmetic and comparisons of + * numbers, a returned value, and a string key of an element access on a + * string-indexed record or an `any` value. Anything else keeps the + * parameter `any`. */ +function readsFit( + lowerer: Lowerer, + body: ts.Node, + symbol: ts.Symbol, + kind: "string" | "f64", +): boolean { + const name = ts.symbolName(symbol); + const primitive = (e: ts.Expression): boolean => { + const flags = lowerer.checker.getTypeAtLocation(e).flags; + return (flags & (ts.TypeFlags.NumberLike | ts.TypeFlags.StringLike)) !== 0; + }; + const fits = (id: ts.Identifier): boolean => { + let node: ts.Node = id; + while (ts.isParenthesizedExpression(node.parent)) node = node.parent; + const parent = node.parent; + if (ts.isTemplateSpan(parent) || ts.isReturnStatement(parent)) return true; + if (ts.isElementAccessExpression(parent)) { + if (kind !== "string" || parent.argumentExpression !== node) return false; + const receiver = lowerer.mapTypeOf(lowerer.checker.getTypeAtLocation(parent.expression)); + if (receiver?.kind === "dyn") return true; + const shape = receiver?.kind === "record" ? lowerer.shapes.get(receiver.shapeId) : undefined; + return shape?.indexValue !== undefined && !shape.tuple; + } + if (ts.isArrowFunction(parent)) return parent.body === node; + if (ts.isCallExpression(parent)) + return ( + parent.expression !== node && + ["Number", "String", "parseInt", "parseFloat"].some((global) => + lowerer.isStdlibGlobal(parent.expression, global), + ) + ); + if (ts.isPropertyAccessExpression(parent)) { + const member = parent.name.text; + if (kind !== "string" || parent.expression !== node || !STRING_MEMBERS.has(member)) + return false; + return ( + member === "length" || + (ts.isCallExpression(parent.parent) && parent.parent.expression === parent) + ); + } + if (ts.isBinaryExpression(parent)) { + const op = parent.operatorToken.kind; + if ( + op === ts.SyntaxKind.EqualsEqualsEqualsToken || + op === ts.SyntaxKind.ExclamationEqualsEqualsToken + ) + return true; + const other = parent.left === node ? parent.right : parent.left; + if (op === ts.SyntaxKind.PlusToken) return kind === "string" || primitive(other); + return ( + kind === "f64" && + (op === ts.SyntaxKind.MinusToken || + op === ts.SyntaxKind.AsteriskToken || + op === ts.SyntaxKind.SlashToken || + op === ts.SyntaxKind.PercentToken || + op === ts.SyntaxKind.LessThanToken || + op === ts.SyntaxKind.GreaterThanToken || + op === ts.SyntaxKind.LessThanEqualsToken || + op === ts.SyntaxKind.GreaterThanEqualsToken) && + (lowerer.checker.getTypeAtLocation(other).flags & ts.TypeFlags.NumberLike) !== 0 + ); + } + return false; + }; + let ok = true; + const visit = (n: ts.Node): void => { + if (!ok) return; + if (ts.isIdentifier(n) && n.text === name && lowerer.resolveValueSymbol(n) === symbol) { + if (!fits(n)) ok = false; + return; + } + ts.forEachChild(n, visit); + }; + visit(body); + return ok; +} + +/** The capture layout of a string search: the match, then the offset and + * the subject. */ +export const PLAIN_SEARCH_CAPTURES: { count: number; always: boolean[] } = { + count: 1, + always: [true], +}; + +/** The captures of a regex literal argument (regexCaptureParticipation), + * or null for any other pattern expression. */ +export function regexLiteralCapturesOf( + pattern: ts.Expression, +): { count: number; always: boolean[] } | null { + let regex = pattern; + while (ts.isParenthesizedExpression(regex)) regex = regex.expression; + if (!ts.isRegularExpressionLiteral(regex)) return null; + const text = regex.text; + const slash = text.lastIndexOf("/"); + return regexCaptureParticipation(text.slice(1, slash), text.slice(slash + 1)); +} + +/** Lowers an inline replace callback. JavaScript passes it the match, the + * captures, the match offset and the subject (`captures` gives their + * layout; null lowers the callback as written). TypeScript types the + * parameters after the match `any`, so an unannotated parameter that is + * never reassigned, whose every read fits its value (readsFit), and that + * receives a capture every match sets, the offset or the subject takes + * that value's type: a string or a number. The closure can then be called + * directly (typed replacers in lib-dispatch.ts) with fewer boxed values. */ +export function lowerReplacerCallback( + lowerer: Lowerer, + callback: ts.Expression, + captures: { count: number; always: boolean[] } | null, +): IrExpr { + let node = callback; + while (ts.isParenthesizedExpression(node)) node = node.expression; + // A named function expression can call itself with other arguments. + const literal = + ts.isArrowFunction(node) || (ts.isFunctionExpression(node) && !node.name) ? node : null; + if (!literal || !captures) return lowerer.lowerExpr(callback); + const bound: { symbol: ts.Symbol; previous: IrType | undefined }[] = []; + const previousImplicit = lowerer.implicitParamTypes; + let implicit: Map | null = null; + const params = literal.parameters.nodes; + // A declared `this` parameter takes no argument position. + const first = + params[0] && ts.isIdentifier(params[0].name) && params[0].name.text === "this" ? 1 : 0; + params.slice(first).forEach((param, i) => { + const type = + i === 0 || i > captures.count + 1 + ? null + : i < captures.count + ? captures.always[i] === true + ? STRING + : null + : i === captures.count + ? F64 + : STRING; + if ( + type === null || + !ts.isIdentifier(param.name) || + param.type || + param.initializer || + param.dotDotDotToken || + param.questionToken + ) + return; + if ((lowerer.checker.getTypeAtLocation(param.name).flags & ts.TypeFlags.Any) === 0) return; + const symbol = lowerer.checker.getSymbolAtLocation(param.name); + if ( + !symbol || + !bindingNeverReassigned(lowerer, symbol, param) || + !readsFit(lowerer, literal.body, symbol, type === STRING ? "string" : "f64") + ) + return; + bound.push({ symbol, previous: lowerer.runtimeOptionalBindingTypes.get(symbol) }); + lowerer.runtimeOptionalBindingTypes.set(symbol, type); + implicit ??= new Map(previousImplicit ?? []); + implicit.set( + symbol, + type === STRING ? lowerer.checker.getStringType() : lowerer.checker.getNumberType(), + ); + }); + if (implicit !== null) lowerer.implicitParamTypes = implicit; + try { + return lowerer.lowerExpr(callback); + } finally { + for (const { symbol, previous } of bound) { + if (previous === undefined) lowerer.runtimeOptionalBindingTypes.delete(symbol); + else lowerer.runtimeOptionalBindingTypes.set(symbol, previous); + } + lowerer.implicitParamTypes = previousImplicit; + } +} diff --git a/packages/compiler/src/frontend/lowering/containers/string-and-regexp.ts b/packages/compiler/src/frontend/lowering/containers/string-and-regexp.ts index d55f71ff0..12885418b 100644 --- a/packages/compiler/src/frontend/lowering/containers/string-and-regexp.ts +++ b/packages/compiler/src/frontend/lowering/containers/string-and-regexp.ts @@ -33,6 +33,7 @@ import { isSafeToDiscard } from "../expressions/evaluation-safety.js"; import { STRING_INDEX_METHODS, STRING_REPLACE_METHODS, STR_METHODS } from "../surfaces.js"; import { execResultCaptureMask } from "./exec-result-uses.js"; import { lowerStringReplacement } from "./string-replacement.js"; +import { lowerReplacerCallback, regexLiteralCapturesOf } from "./replacer-params.js"; import { coerceStringSearchValue, defaultAfterUndefined, @@ -1025,7 +1026,11 @@ export function lowerRegexMethodCall( : [ lowerer.lowerExprExpecting(arg0, { kind: "regex" }), call.arguments.nodes[1] - ? lowerer.lowerExpr(call.arguments.nodes[1]) + ? lowerReplacerCallback( + lowerer, + call.arguments.nodes[1], + regexLiteralCapturesOf(arg0), + ) : dynUndefinedExpr(loc), ]; if (name !== "split") { diff --git a/packages/compiler/src/frontend/lowering/containers/string-replacement.ts b/packages/compiler/src/frontend/lowering/containers/string-replacement.ts index 156f74869..c21808464 100644 --- a/packages/compiler/src/frontend/lowering/containers/string-replacement.ts +++ b/packages/compiler/src/frontend/lowering/containers/string-replacement.ts @@ -18,6 +18,7 @@ import { import { dynUndefinedExpr, numLit, strLit, varRef } from "../../../ir/build.js"; import { InternalCompilerError } from "../../../errors.js"; import { locOf } from "../../program.js"; +import { PLAIN_SEARCH_CAPTURES, lowerReplacerCallback } from "./replacer-params.js"; import type { Lowerer } from "../lowerer.js"; import { coerceStringSearchValue, @@ -48,11 +49,18 @@ export function lowerStringReplacement( type.kind === "bool" || type.kind === "bigint" || isUnitType(type); - const argument = (node: ts.Expression | undefined, callback: boolean): IrExpr => { + const argument = ( + node: ts.Expression | undefined, + callback: boolean, + plainSearch = false, + ): IrExpr => { if (!node) return strLit("undefined", loc); const absent = lowerStaticallyUndefinedArgument(lowerer, node); if (absent) return defaultAfterUndefined(absent, strLit("undefined", loc)); - const value = lowerer.lowerExpr(node); + // A plain search passes (match, offset, subject). + const value = plainSearch + ? lowerReplacerCallback(lowerer, node, PLAIN_SEARCH_CAPTURES) + : lowerer.lowerExpr(node); if (value.type.kind === "dyn" || (callback && value.type.kind === "func")) return value; if (!primitive(value.type)) { lowerer.noLowering( @@ -64,7 +72,7 @@ export function lowerStringReplacement( return coerceStringSearchValue(lowerer, value, node, loc); }; const search = argument(args[0], false); - const replacement = argument(args[1], true); + const replacement = argument(args[1], true, search.type.kind !== "dyn"); if (search.type.kind === "dyn" || replacement.type.kind === "dyn") { // Evaluate all inputs once before choosing the search protocol. Regexes // retain their native pattern; plain values use the string-search helper. diff --git a/packages/compiler/test/replacer-params.test.ts b/packages/compiler/test/replacer-params.test.ts new file mode 100644 index 000000000..bb5549a86 --- /dev/null +++ b/packages/compiler/test/replacer-params.test.ts @@ -0,0 +1,84 @@ +import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { afterEach, describe, expect, test } from "vitest"; +import { compile } from "../src/index.js"; +import { regexLiteralCaptures } from "../src/backend/llvm/regex-matchers.js"; +import { regexCaptureParticipation } from "../src/frontend/lowering/containers/replacer-params.js"; + +// The frontend binds a replace callback parameter as a string only for a +// capture every match sets; the backend then calls the callback directly +// only when its own parse agrees. +describe("replace callback captures", () => { + test("never claims a capture the backend's parse can leave unset", () => { + const patterns = [ + "(\\w+)=(\\d)+", + "(?a)(b)?|(c)", + "x(?:(a)|(b))y(c)*(d){0,2}(e){1,3}", + "((a)(b)?)+", + "(a(b|c))d", + "(?:a|(b))(c)", + ]; + for (const pattern of patterns) { + const frontend = regexCaptureParticipation(pattern, ""); + const backend = regexLiteralCaptures(pattern, ""); + expect(frontend?.count).toBe(backend?.count); + frontend!.always.forEach((always, index) => { + if (always) expect(backend!.always[index]).toBe(true); + }); + } + }); +}); + +const directories: string[] = []; +afterEach(async () => { + await Promise.all(directories.splice(0).map((dir) => rm(dir, { recursive: true, force: true }))); +}); + +async function emit(source: string): Promise { + const outDir = await mkdtemp(join(tmpdir(), "scriptc-replacer-")); + directories.push(outDir); + const entry = join(outDir, "main.ts"); + await writeFile(entry, source); + const outPath = join(outDir, "program.ll"); + const result = await compile(entry, { entry, outDir, outPath, outputKind: "llvm" }); + expect(result.ok, JSON.stringify(result)).toBe(true); + return readFile(outPath, "utf8"); +} + +/** The (arity, kinds) arguments of each direct replacer call, and the + * number of calls through the boxed argument array. */ +function replacerCalls(llvm: string): { direct: string[]; boxed: number } { + const lines = llvm.split("\n").filter((line) => line.includes("call ")); + return { + direct: lines + .filter((line) => line.includes("@scr_regex_replace_fn(")) + .map((line) => /i32 (-?\d+), i32 (-?\d+), i1/.exec(line)!.slice(1, 3).join(":")), + boxed: lines.filter((line) => line.includes("@scr_regex_replace_callback(")).length, + }; +} + +describe("replace callback calls", () => { + test("unannotated parameters take the kinds the replace passes", async () => { + const llvm = await emit(` +const vars: Record = { a: "1" }; +const text = String(Date.now() > 0 ? "{a} {b}" : ""); +console.log(text.replace(/\\{(\\w+)\\}/g, (_m, key) => vars[key] ?? "")); +console.log(text.replace(/\\{(\\w)/g, (_m, c) => c.toUpperCase())); +console.log(text.replace(/(a)|(b)/g, (m, a, b) => \`\${m}\${a}\${b}\`)); +console.log(text.replace(/(a)(b)?/g, (m: string, a: string, b: string | undefined, at: number) => m + a + (b ?? "") + at)); +const half = (n: number): number => n / 2; +console.log(text.replace(/b/g, (m, at) => String(half(at)))); +console.log(text.replace(/(a)(b)(c)/g, (m, a, b, c, at, all, extra) => m + a + b + c + at + all + extra)); +`); + expect(replacerCalls(llvm)).toEqual({ + // Typed parameters and result (0); a checked-dynamic result (bit 31); + // two captures a match can leave unset (bits 1 and 2); + // \`string | undefined\` at capture 2 (bit 8 + 2); an offset passed to a + // number parameter keeps its checked-dynamic box (bit 1). + direct: ["2:0", "2:-2147483648", "3:6", "4:1024", "2:2"], + // Seven parameters exceed the direct calls' limit. + boxed: 1, + }); + }); +}); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8118-replacer-params.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8118-replacer-params.ts.json new file mode 100644 index 000000000..4de6ead6b --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8118-replacer-params.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8118-replacer-params.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8345-replace-callback-untyped-params.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8345-replace-callback-untyped-params.ts.json new file mode 100644 index 000000000..9a4c2b510 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8345-replace-callback-untyped-params.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8345-replace-callback-untyped-params.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8346-replace-callback-untyped-params.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8346-replace-callback-untyped-params.mjs.json new file mode 100644 index 000000000..301203783 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8346-replace-callback-untyped-params.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8346-replace-callback-untyped-params.mjs" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_regex.c b/packages/runtime/src/scr_regex.c index 158697a14..ab323c288 100644 --- a/packages/runtime/src/scr_regex.c +++ b/packages/runtime/src/scr_regex.c @@ -1529,49 +1529,101 @@ ScrStr *scr_regex_replace_callback(ScrStr *s, ScrRegex *re, ScrDyn *callback, bo return scr_jb_finish(&output); } -/* One call of a typed replacer (scr_regex_replace_fn's contract): string - * arguments are passed +1 (the closure ABI's owned parameters), the offset - * as a number, and the result is the closure's +1 string. */ -static ScrStr *scr_regex_call_replacer(ScrClosure *f, uint32_t arity, int ncap, - ScrStr *const *caps, double offset, ScrStr *subject) { - void *p[4] = { NULL, NULL, NULL, NULL }; - for (uint32_t i = 0; i < arity && i < 4; i++) { - if ((int)i < ncap) { - if (!caps[i]) scr_trap("scriptc: internal error: typed replacer capture is unset\n"); - p[i] = scr_str_retain(caps[i]); - } else if ((int)i == ncap + 1) { - p[i] = scr_str_retain(subject); - } - } +/* The closure signature scr_regex_replace_fn calls: `arity` pointer + * parameters, except a number at `number_at` (-1 when there is none). A + * string and a checked-dynamic value are both pointers, and so are both + * results. */ +#define SCR_REPLACER_CALL(...) return ((void *(*)(ScrClosure *, __VA_ARGS__))fn) +static inline __attribute__((always_inline)) void *scr_regex_call_replacer( + ScrClosure *f, uint32_t arity, int number_at, void *const *p, double offset) { void *fn = f->fn; - typedef ScrStr *R; - switch (arity) { - case 0: return ((R (*)(ScrClosure *))fn)(f); - case 1: return ((R (*)(ScrClosure *, void *))fn)(f, p[0]); - case 2: - if (ncap == 1) return ((R (*)(ScrClosure *, void *, double))fn)(f, p[0], offset); - return ((R (*)(ScrClosure *, void *, void *))fn)(f, p[0], p[1]); - case 3: - if (ncap == 1) return ((R (*)(ScrClosure *, void *, double, void *))fn)(f, p[0], offset, p[2]); - if (ncap == 2) return ((R (*)(ScrClosure *, void *, void *, double))fn)(f, p[0], p[1], offset); - return ((R (*)(ScrClosure *, void *, void *, void *))fn)(f, p[0], p[1], p[2]); - case 4: - if (ncap == 2) - return ((R (*)(ScrClosure *, void *, void *, double, void *))fn)(f, p[0], p[1], offset, p[3]); - if (ncap == 3) - return ((R (*)(ScrClosure *, void *, void *, void *, double))fn)(f, p[0], p[1], p[2], offset); - if (ncap >= 4) - return ((R (*)(ScrClosure *, void *, void *, void *, void *))fn)(f, p[0], p[1], p[2], p[3]); - break; + typedef void *P; + typedef double D; + switch (arity * 8 + (uint32_t)(number_at < 0 ? 7 : number_at)) { + case 0 * 8 + 7: return ((void *(*)(ScrClosure *))fn)(f); + case 1 * 8 + 7: SCR_REPLACER_CALL(P)(f, p[0]); + case 2 * 8 + 7: SCR_REPLACER_CALL(P, P)(f, p[0], p[1]); + case 2 * 8 + 1: SCR_REPLACER_CALL(P, D)(f, p[0], offset); + case 3 * 8 + 7: SCR_REPLACER_CALL(P, P, P)(f, p[0], p[1], p[2]); + case 3 * 8 + 1: SCR_REPLACER_CALL(P, D, P)(f, p[0], offset, p[2]); + case 3 * 8 + 2: SCR_REPLACER_CALL(P, P, D)(f, p[0], p[1], offset); + case 4 * 8 + 7: SCR_REPLACER_CALL(P, P, P, P)(f, p[0], p[1], p[2], p[3]); + case 4 * 8 + 1: SCR_REPLACER_CALL(P, D, P, P)(f, p[0], offset, p[2], p[3]); + case 4 * 8 + 2: SCR_REPLACER_CALL(P, P, D, P)(f, p[0], p[1], offset, p[3]); + case 4 * 8 + 3: SCR_REPLACER_CALL(P, P, P, D)(f, p[0], p[1], p[2], offset); + case 5 * 8 + 7: SCR_REPLACER_CALL(P, P, P, P, P)(f, p[0], p[1], p[2], p[3], p[4]); + case 5 * 8 + 1: SCR_REPLACER_CALL(P, D, P, P, P)(f, p[0], offset, p[2], p[3], p[4]); + case 5 * 8 + 2: SCR_REPLACER_CALL(P, P, D, P, P)(f, p[0], p[1], offset, p[3], p[4]); + case 5 * 8 + 3: SCR_REPLACER_CALL(P, P, P, D, P)(f, p[0], p[1], p[2], offset, p[4]); + case 5 * 8 + 4: SCR_REPLACER_CALL(P, P, P, P, D)(f, p[0], p[1], p[2], p[3], offset); + case 6 * 8 + 7: SCR_REPLACER_CALL(P, P, P, P, P, P)(f, p[0], p[1], p[2], p[3], p[4], p[5]); + case 6 * 8 + 1: SCR_REPLACER_CALL(P, D, P, P, P, P)(f, p[0], offset, p[2], p[3], p[4], p[5]); + case 6 * 8 + 2: SCR_REPLACER_CALL(P, P, D, P, P, P)(f, p[0], p[1], offset, p[3], p[4], p[5]); + case 6 * 8 + 3: SCR_REPLACER_CALL(P, P, P, D, P, P)(f, p[0], p[1], p[2], offset, p[4], p[5]); + case 6 * 8 + 4: SCR_REPLACER_CALL(P, P, P, P, D, P)(f, p[0], p[1], p[2], p[3], offset, p[5]); + case 6 * 8 + 5: SCR_REPLACER_CALL(P, P, P, P, P, D)(f, p[0], p[1], p[2], p[3], p[4], offset); default: break; } scr_trap("scriptc: internal error: typed replacer signature\n"); } +#undef SCR_REPLACER_CALL + +/* Typed replacer argument k: a capture (NULL for an unset optional one) + * or the subject; the offset is passed separately. The compiler admits a + * typed parameter only at those positions. Inlined with each constant k. */ +static inline __attribute__((always_inline)) void scr_regex_typed_arg( + void **p, uint32_t k, uint32_t kinds, int capture_count, ScrStr *const *caps, ScrStr *subject) { + if ((int)k < capture_count) { + if (!caps[k] && !(kinds & (SCR_REPLACER_OPTIONAL << k))) + scr_trap("scriptc: internal error: typed replacer capture is unset\n"); + p[k] = caps[k] ? scr_str_retain(caps[k]) : NULL; + } else if ((int)k == capture_count + 1) { + p[k] = scr_str_retain(subject); + } +} + +/* One match's replacer arguments when some parameter is checked-dynamic + * (scr_regex_replace_fn's `kinds`): typed ones +1, the rest new boxes. + * `boxed_subject` is the subject's box; `groups` the match's groups + * object, or NULL when no parameter reads it. */ +__attribute__((noinline)) static void scr_regex_replacer_args( + void **p, uint32_t arity, uint32_t kinds, int capture_count, ScrStr *const *caps, double offset, + ScrStr *subject, ScrDyn *boxed_subject, ScrDyn *groups) { + for (uint32_t k = 0; k < arity; k++) { + int at = (int)k; + if (kinds & (1u << k)) { + if (at < capture_count) + p[k] = caps[k] ? scr_dyn_new_str(caps[k]) : scr_dyn_retain(scr_dyn_undefined()); + else if (at == capture_count) + p[k] = scr_dyn_new_num(offset); + else if (at == capture_count + 1) + p[k] = scr_dyn_retain(boxed_subject); + else if (at == capture_count + 2 && groups) + p[k] = scr_dyn_retain(groups); + else + p[k] = scr_dyn_retain(scr_dyn_undefined()); + } else if (at < capture_count) { + if (!caps[k] && !(kinds & (SCR_REPLACER_OPTIONAL << k))) + scr_trap("scriptc: internal error: typed replacer capture is unset\n"); + p[k] = caps[k] ? scr_str_retain(caps[k]) : NULL; + } else if (at == capture_count + 1) { + p[k] = scr_str_retain(subject); + } else if (at != capture_count) { + scr_trap("scriptc: internal error: typed replacer signature\n"); + } + } +} /* scr_regex_replace_callback's algorithm for a typed replacer: the matches - * are collected first, keeping only the captures the replacer reads, then - * the replacer runs once per match in order. */ -ScrStr *scr_regex_replace_fn(ScrStr *s, ScrRegex *re, ScrClosure *f, uint32_t arity, bool all) { + * are collected first, keeping only the captures and groups objects the + * replacer reads, then the replacer runs once per match in order. Typed + * parameters receive their values +1 (the closure ABI's owned + * parameters) and an unset optional capture NULL; checked-dynamic ones + * receive new boxes. Inlined into one copy for kinds 0, where the boxed + * handling folds away, and one for the other kinds. */ +static inline __attribute__((always_inline)) ScrStr * +scr_regex_replace_fn_impl(ScrStr *s, ScrRegex *re, ScrClosure *f, uint32_t arity, uint32_t kinds, + bool all) { uint8_t *bc = scr_regex_bc(re); int flags = lre_get_flags(bc); bool global = (flags & LRE_FLAG_GLOBAL) != 0; @@ -1580,15 +1632,28 @@ ScrStr *scr_regex_replace_fn(ScrStr *s, ScrRegex *re, ScrClosure *f, uint32_t ar scr_throw_error_msg(SCR_ERR_TYPE, message, sizeof message - 1); return NULL; } + if (arity > SCR_REPLACER_MAX_ARITY) scr_trap("scriptc: internal error: typed replacer arity\n"); bool sticky = (flags & LRE_FLAG_STICKY) != 0; bool unicode = (flags & (LRE_FLAG_UNICODE | LRE_FLAG_UNICODE_SETS)) != 0; int capture_count = lre_get_capture_count(bc); size_t keep = arity < (uint32_t)capture_count ? arity : (size_t)capture_count; + /* Node passes the groups object after the subject when the pattern has + * named groups; only a checked-dynamic parameter can read it, and no + * typed parameter follows the subject. */ + bool past_subject = (uint32_t)capture_count + 2 < arity; + if (past_subject && !(kinds & SCR_REPLACER_BOXED_PARAMS)) + scr_trap("scriptc: internal error: typed replacer signature\n"); + const char *groupnames = past_subject ? lre_get_groupnames(bc) : NULL; + bool groups_read = groupnames != NULL; + if (groups_read && !(kinds & (1u << (capture_count + 2)))) + scr_trap("scriptc: internal error: typed replacer groups parameter\n"); + int number_at = capture_count < (int)arity && !(kinds & (1u << capture_count)) ? capture_count : -1; ScrRegexInput input; scr_regex_input_init(&input, re, bc, s); int len = input.len; struct { int start, end; } *matches = NULL; ScrStr **caps = NULL; + ScrDyn **groups = NULL; size_t count = 0, capacity = 0; if (global) re->last_index = 0; int position = sticky ? scr_regex_start(re, len) : 0; @@ -1610,6 +1675,11 @@ ScrStr *scr_regex_replace_fn(ScrStr *s, ScrRegex *re, ScrClosure *f, uint32_t ar if (!grown) scr_regex_oom(); caps = grown; } + if (groups_read) { + grown = realloc(groups, next * sizeof(*groups)); + if (!grown) scr_regex_oom(); + groups = grown; + } capacity = next; } for (size_t group = 0; group < keep; group++) { @@ -1618,6 +1688,18 @@ ScrStr *scr_regex_replace_fn(ScrStr *s, ScrRegex *re, ScrClosure *f, uint32_t ar cs && ce ? scr_regex_span(&input, scr_capture_index(&input, cs), scr_capture_index(&input, ce)) : NULL; } + if (groups_read) { + ScrDyn *object = scr_dyn_new_obj_null_proto(); + const char *name = groupnames; + for (int group = 1; group < capture_count; group++) { + size_t length = strlen(name); + if (length && (capture[group * 2] || !scr_dyn_obj_get(object, name, length))) + scr_dyn_obj_set(object, name, length, + scr_regex_capture_value(&input, capture[group * 2], capture[group * 2 + 1])); + name += length + LRE_GROUP_NAME_TRAILER_LEN; + } + groups[count] = object; + } matches[count].start = start; matches[count].end = end; count++; @@ -1627,18 +1709,43 @@ ScrStr *scr_regex_replace_fn(ScrStr *s, ScrRegex *re, ScrClosure *f, uint32_t ar ScrJsonBuf output; scr_jb_init(&output); int next = 0; + /* One box of the subject serves every match. */ + ScrDyn *subject = NULL; + if (kinds & SCR_REPLACER_BOXED_PARAMS) subject = scr_dyn_new_str(s); scr_dyn_this_push_dyn(NULL); for (size_t i = 0; i < count; i++) { - ScrStr *replacement = scr_regex_call_replacer(f, arity, capture_count, caps + i * keep, - (double)matches[i].start, s); - if (scr_exc_pending()) break; + void *p[SCR_REPLACER_MAX_ARITY] = { NULL }; + double offset = (double)matches[i].start; + ScrStr *const *match_caps = caps + i * keep; + if (kinds & SCR_REPLACER_BOXED_PARAMS) { + scr_regex_replacer_args(p, arity, kinds, capture_count, match_caps, offset, s, subject, + groups_read ? groups[i] : NULL); + } else { + for (uint32_t k = 0; k < SCR_REPLACER_MAX_ARITY; k++) + if (k < arity) scr_regex_typed_arg(p, k, kinds, capture_count, match_caps, s); + } + void *result = scr_regex_call_replacer(f, arity, number_at, p, offset); + ScrStr *replacement = (ScrStr *)result; + if (kinds & SCR_REPLACER_BOXED_RESULT) { + replacement = scr_exc_pending() ? NULL : scr_dyn_string_coerce_js((ScrDyn *)result); + scr_dyn_release((ScrDyn *)result); + } + if (scr_exc_pending()) { + scr_str_release(replacement); + break; + } scr_regex_put_span(&output, &input, next, matches[i].start); scr_jb_put_str(&output, replacement); scr_str_release(replacement); next = matches[i].end; } scr_dyn_this_pop(); + if (subject) scr_dyn_release(subject); for (size_t i = 0; i < count * keep; i++) scr_str_release(caps[i]); + if (groups_read) { + for (size_t i = 0; i < count; i++) scr_dyn_release(groups[i]); + free(groups); + } free(caps); free(matches); if (scr_exc_pending()) { @@ -1651,6 +1758,24 @@ ScrStr *scr_regex_replace_fn(ScrStr *s, ScrRegex *re, ScrClosure *f, uint32_t ar return scr_jb_finish(&output); } +__attribute__((noinline)) static ScrStr *scr_regex_replace_typed(ScrStr *s, ScrRegex *re, + ScrClosure *f, uint32_t arity, + bool all) { + return scr_regex_replace_fn_impl(s, re, f, arity, 0, all); +} + +__attribute__((noinline)) static ScrStr *scr_regex_replace_kinds(ScrStr *s, ScrRegex *re, + ScrClosure *f, uint32_t arity, + uint32_t kinds, bool all) { + return scr_regex_replace_fn_impl(s, re, f, arity, kinds, all); +} + +ScrStr *scr_regex_replace_fn(ScrStr *s, ScrRegex *re, ScrClosure *f, uint32_t arity, + uint32_t kinds, bool all) { + if (kinds == 0) return scr_regex_replace_typed(s, re, f, arity, all); + return scr_regex_replace_kinds(s, re, f, arity, kinds, all); +} + /* The pinned Node ANSI matcher derives from ansi-regex, copyright (c) * Sindre Sorhus , used under the MIT license: * Permission is hereby granted, free of charge, to any person obtaining a diff --git a/packages/runtime/src/scr_regex.h b/packages/runtime/src/scr_regex.h index 01c545bc5..cb61e49f3 100644 --- a/packages/runtime/src/scr_regex.h +++ b/packages/runtime/src/scr_regex.h @@ -80,16 +80,26 @@ ScrStr *scr_regex_flags(ScrRegex *re); /* +1 */ ScrStr *scr_regex_to_string(ScrRegex *re); /* +1 */ /* replace: first match without /g, every match with it. */ ScrStr *scr_regex_replace(ScrStr *s, ScrRegex *re, ScrStr *rep); -/* replace/replaceAll with a typed replacer closure of `arity` (at most 4) - * parameters returning a string. Parameter i receives what Node passes at - * position i: the match and captures (strings) below the capture count n, - * the match offset (a number) at n, the subject (a string) at n + 1. The - * compiler admits a closure only when every position it declares is one of - * those with the declared kind, and every capture it reads is set in every - * match (scr_regex_replace_callback handles the rest). Borrows all. */ +/* replace/replaceAll with a replacer closure of `arity` (at most + * SCR_REPLACER_MAX_ARITY) parameters. Parameter i receives what Node passes + * at position i: the match and captures below the capture count n, the + * match offset at n, the subject at n + 1, the groups object at n + 2 when + * the pattern has named groups, and undefined after that. Bit i of + * `kinds` makes parameter i a checked-dynamic value, and bit + * SCR_REPLACER_OPTIONAL << i a capture held as a string or NULL for + * undefined; otherwise it is a string, or a number at n. + * SCR_REPLACER_BOXED_RESULT makes the result a checked-dynamic value, + * converted with ToString. The compiler admits a closure only when every + * typed position it declares is one of those with the declared kind, and + * every capture a string parameter reads is set in every match + * (scr_regex_replace_callback handles the rest). Borrows all. */ +#define SCR_REPLACER_MAX_ARITY 6 +#define SCR_REPLACER_BOXED_PARAMS 0xffu +#define SCR_REPLACER_OPTIONAL (1u << 8) +#define SCR_REPLACER_BOXED_RESULT (1u << 31) struct ScrClosure; ScrStr *scr_regex_replace_fn(ScrStr *s, ScrRegex *re, struct ScrClosure *f, uint32_t arity, - bool all); + uint32_t kinds, bool all); /* replaceAll: throws Node's TypeError when /g is missing (may-throw). */ ScrStr *scr_regex_replace_all(ScrStr *s, ScrRegex *re, ScrStr *rep); /* split: captured substrings are interleaved with the split pieces; diff --git a/tests/corpus/8118-replacer-params.ts b/tests/corpus/8118-replacer-params.ts new file mode 100644 index 000000000..14579ec84 --- /dev/null +++ b/tests/corpus/8118-replacer-params.ts @@ -0,0 +1,43 @@ +// Inline replace callbacks whose parameters after the match are left +// untyped: captures every match sets, captures that can be unset (in an +// alternation, an optional or zero-repeat group, a lookahead), the offset, +// the subject and the groups object, reassigned parameters, named groups, +// patterns with classes, escapes and lookbehind, function expressions and +// replaceAll. +const lines = ["id7,tag12;tag3", "x9 y10", "", "naïve 😀 42", "a-b-c"]; +for (const line of lines) { + console.log(line.replace(/tag(\d+)/g, (_m, d) => String(Number(d) + 1))); + console.log(line.replace(/(\w)(\d+)/g, (m, letter, digits, offset, subject) => + `[${letter}:${digits.length}@${offset}/${subject.length}]`)); + console.log(line.replace(/(a)|(\d)/g, (m, a, digit) => `<${typeof a},${typeof digit}>`)); + console.log(line.replace(/(x)?(\d)/g, (m, x, d) => `${x === undefined ? "-" : x}${d}`)); + console.log(line.replace(/(?:(t)a)*g/g, (m, t, offset) => `{${t}|${offset}}`)); + console.log(line.replace(/(?=(\d))\d/g, (m, ahead, offset) => `${ahead}${offset}`)); + console.log(line.replace(/(?\d)(\d)?/g, (m, n, rest, offset, subject, groups) => + `${n}${rest ?? "_"}${offset}${typeof subject}${JSON.stringify(groups)}`)); + console.log(line.replace(/([\(\)\[\]]|[a-c])(-)/g, (m, c, dash) => c.toUpperCase() + dash.length)); + console.log(line.replace(/(?<=-)(\w)/g, (m, c, offset) => c + offset.toFixed(1))); + console.log(line.replaceAll(/(\d)/g, function (m, d, offset) { + return `${d * 2}:${offset + 1}`; + })); + console.log(line.replace(/(\d)/g, (m, d) => { + d = d.length > 0 ? 5 : 6; + return String(d + 1); + })); + console.log(line.replace(/(\d)\1?/g, (m, d, offset, subject) => `${d}${offset}${subject === line}`)); + console.log(line.replace(/(.)/u, (m, c, offset, subject, extra) => `${c.codePointAt(0)}${offset}${extra}`)); + console.log(line.replace(/(\d){0,2}x/g, (m, d) => `${d}`)); + console.log(line.replace(/(\w)(\w)/g, (m, a, b, offset) => + [a.toUpperCase(), b.toLowerCase(), a.trim(), a.charCodeAt(0), b.codePointAt(0), a.slice(0, 1), + b.substring(0), a.repeat(2), b.padStart(3, "."), a.padEnd(2, "!"), b.includes("1"), + a.startsWith("t"), b.endsWith("g"), a.indexOf("a"), a.length, parseInt(b, 36), + parseFloat(b), Number(b), String(offset), offset - 1, offset * 2, offset % 3, offset < 4, + a === b, a !== "x", a + offset, offset + 1, `${offset}`].join(","))); + console.log(line.replace(/(\d+)/g, (m, d) => (d))); + console.log(line.replace(/(\d+)/g, function (m, d) { return d + d; })); +} +let count = 0; +console.log("tag1 tag2".replace(/tag(\d)/g, (m, d) => { + count += Number(d); + return d.repeat(2); +}), count); diff --git a/tests/corpus/8345-replace-callback-untyped-params.ts b/tests/corpus/8345-replace-callback-untyped-params.ts new file mode 100644 index 000000000..31d3a038b --- /dev/null +++ b/tests/corpus/8345-replace-callback-untyped-params.ts @@ -0,0 +1,85 @@ +// String replace/replaceAll with inline callbacks whose parameters have no +// annotations, so the lib types every parameter after the match `any`. +// Each such parameter holds what Node passes at its position: the captures, +// the offset, the subject, the groups object and then undefined. Captures a +// match can leave unset hold undefined, and a result that is not a string +// converts with ToString. +const vars: Record = { name: "world", place: "earth" }; +const template = "Hello {name}, welcome to {place}! {missing} {name}."; +console.log(template.replace(/\{(\w+)\}/g, (_m, key) => vars[key] ?? `<${key}>`)); +console.log(template.replace(/\{(\w+)\}/, (_m, key) => key.toUpperCase())); +console.log("some_snake_case_name".replace(/_([a-z])/g, (_m, c) => c.toUpperCase())); +console.log("2024-01-15 and 1999-07-04".replace(/(\d{4})-(\d{2})-(\d{2})/g, (_m, y, mo, d) => `${d}/${mo}/${y}`)); +console.log("a1b22".replace(/\d+/g, (m, offset, subject) => `[${m}@${offset}/${subject.length}]`)); +console.log("x1y2".replace(/(\d)/g, (m, digit, offset, subject) => `${m}${digit}${offset}${subject}`)); +console.log("k=v".replace(/(\w)=(\w)/, function (m, k, v, at, all) { + return `${v}=${k}:${at}:${all}:${m}`; +})); + +console.log("k=v".replace(/(\w)=(\w)/, function (this: void, m, k, v, at) { + return `${typeof this}:${v}=${k}:${at}:${m}`; +})); + +// A parameter the body assigns keeps `any`. +console.log("a1".replace(/(\d)/, (_m, d) => { + d = Number(d) + 1; + return String(d * 2); +})); + +// Captures that a match can leave unset. +console.log("ab".replace(/(a)|(b)/g, (m, a, b) => `${m}:${a}:${b};`)); +console.log("b xb".replace(/(x)?b/g, (m, x, at) => `${m}:${x}:${at}`)); +console.log("ab".replace(/((a)|b)/g, (m, outer, inner) => `${outer}:${inner};`)); +console.log("ab".replace(/(?:(a)|b)/g, (m, a, at) => `${m}:${a}:${at};`)); +console.log("aab".replace(/(a){0,2}b/, (m, a, at) => `${m}:${a}:${at}`)); +console.log("ab".replace(/(?=(a))a|b/g, (m, look, at) => `${m}:${look}:${at};`)); +console.log("ab".replace(/(?!(x))a/g, (m, x, at) => `${m}:${x}:${at};`)); +console.log("ab".replace(/(a)*b/, (m, a, at) => `${m}:${a}:${at}`)); +console.log("a(b)".replace(/\((b)\)/, (m, b, at) => `${m}:${b}:${at}`)); +console.log("a|b".replace(/[|(](b)?/, (m, b, at) => `${m}:${b}:${at}`)); + +// Annotated `string | undefined` captures hold undefined when unset. +console.log("2024-01-15 1999-07".replace(/(\d{4})-(\d{2})(-(\d{2}))?/g, (_m, y: string, mo: string, _x: string | undefined, d: string | undefined) => `${d ?? "??"}/${mo}/${y}`)); +console.log("ab".replace(/(a)|(b)/g, (m: string, a: string | undefined, b: string | undefined, at: number) => `${m}:${a ?? "-"}:${b ?? "-"}:${at};`)); +console.log("abc".replace(/(a)(b)(c)/, (m: string, a: string, b: string, c: string, at: number, all: string) => `${c}${b}${a}${m}${at}${all}`)); +console.log("abcd".replace(/(a)(b)(c)(d)/, (m, a, b, c, d, at, all) => `${d}${c}${b}${a}${m}${at}${all}`)); + +// Named groups pass the groups object after the subject; later parameters +// are undefined. +console.log("2024-01".replace(/(?\d{4})-(?\d{2})/, (m, y, mo, at, all, groups) => `${groups.m}.${groups.y}:${y}${mo}:${at}:${all}`)); +console.log("ab".replace(/(?a)|(?b)/g, (m, a, b, at, all, groups) => `${m}:${JSON.stringify(groups)};`)); +console.log("ab".replace(/b/, (m, at, all, extra, more) => `${m}:${at}:${all}:${extra}:${more}`)); +console.log("ab".replace(/(a)(b)/, (m, a, b, at, all, extra, more) => `${m}${a}${b}${at}${all}${extra}${more}`)); + +// Results that are not strings convert with ToString. +const counts: Record = { a: 1, b: true, c: null, d: undefined, e: { toString: () => "E" } }; +console.log("a b c d e".replace(/\w/g, (m) => counts[m])); +console.log("abc".replace(/(\w)/g, (m, c) => counts[c])); + +// String search patterns pass (match, offset, subject). +console.log("one two one".replaceAll("one", (m, at, subject) => `${m.length}@${at}/${subject.length}`)); +console.log("one two one".replace("two", (m, at, subject, extra) => `${m}${at}${subject.length}${extra}`)); + +// A throw stops the replacement. +try { + "a1b2c3".replace(/(\d)/g, (_m, d) => { + if (d === "2") throw new Error("stop at " + d); + return "#"; + }); +} catch (error) { + console.log((error as Error).message); +} +try { + "a1".replace(/(\d)/g, (_m, d) => counts.e.missing.field + d); +} catch (error) { + console.log(error instanceof TypeError); +} +try { + "ab".replace(/(a)|b/g, (m, a) => a.toUpperCase()); +} catch (error) { + console.log(error instanceof TypeError, (error as Error).message); +} + +let total = 0; +for (let i = 0; i < 2000; i++) total += template.replace(/\{(\w+)\}/g, (_m, key) => vars[key] ?? String(i)).length; +console.log(total); diff --git a/tests/corpus/8346-replace-callback-untyped-params.mjs b/tests/corpus/8346-replace-callback-untyped-params.mjs new file mode 100644 index 000000000..2552113f3 --- /dev/null +++ b/tests/corpus/8346-replace-callback-untyped-params.mjs @@ -0,0 +1,32 @@ +// JavaScript string replace/replaceAll with inline callbacks. Each +// parameter holds what Node passes at its position: the captures, the +// offset, the subject, the groups object and then undefined. Captures a +// match can leave unset hold undefined, and a result that is not a string +// converts with ToString. +const vars = { name: "world", place: "earth" }; +const template = "Hello {name}, welcome to {place}! {missing} {name}."; +console.log(template.replace(/\{(\w+)\}/g, (_m, key) => vars[key] ?? `<${key}>`)); +console.log("some_snake_case_name".replace(/_([a-z])/g, (_m, c) => c.toUpperCase())); +console.log("2024-01-15 and 1999-07-04".replace(/(\d{4})-(\d{2})-(\d{2})/g, (_m, y, mo, d) => `${d}/${mo}/${y}`)); +console.log("a1b22".replace(/\d+/g, (m, offset, subject) => `[${m}@${offset}/${subject.length}]`)); +console.log("k=v".replace(/(\w)=(\w)/, function (m, k, v, at, all) { + return `${this === undefined}:${v}=${k}:${at}:${all}:${m}`; +})); +console.log("ab".replace(/(a)|(b)/g, (m, a, b) => `${m}:${a}:${b};`)); +console.log("b xb".replace(/(x)?b/g, (m, x, at) => `${m}:${x}:${at}`)); +console.log("2024-01".replace(/(?\d{4})-(?\d{2})/, (m, y, mo, at, all, groups) => `${groups.m}.${groups.y}:${y}${mo}:${at}:${all}`)); +console.log("ab".replace(/b/, (m, at, all, extra, more) => `${m}:${at}:${all}:${extra}:${more}`)); +const counts = { a: 1, b: true, c: null, d: undefined, e: { toString: () => "E" } }; +console.log("a b c d e".replace(/\w/g, (m) => counts[m])); +console.log("1-2".replace(/(\d)/g, (_m, d) => Number(d) * 10)); +console.log("one two one".replaceAll("one", (m, at, subject) => `${m.length}@${at}/${subject.length}`)); +let seen = ""; +console.log("xyz".replace(/(y)/, (m, y, at, subject) => { + seen = typeof m + typeof y + typeof at + typeof subject; + return y + at; +}), seen); +try { + "ab".replace(/(a)|b/g, (m, a) => a.toUpperCase()); +} catch (error) { + console.log(error instanceof TypeError, error.message); +} diff --git a/tests/harness/corpus-costs/8118-replacer-params.ts.json b/tests/harness/corpus-costs/8118-replacer-params.ts.json new file mode 100644 index 000000000..9b0bcec50 --- /dev/null +++ b/tests/harness/corpus-costs/8118-replacer-params.ts.json @@ -0,0 +1 @@ +{ "plain": 3670, "san": 4410 } diff --git a/tests/harness/corpus-costs/8345-replace-callback-untyped-params.ts.json b/tests/harness/corpus-costs/8345-replace-callback-untyped-params.ts.json new file mode 100644 index 000000000..5d5bbcefe --- /dev/null +++ b/tests/harness/corpus-costs/8345-replace-callback-untyped-params.ts.json @@ -0,0 +1 @@ +{ "plain": 3630, "san": 4420 } diff --git a/tests/harness/corpus-costs/8346-replace-callback-untyped-params.mjs.json b/tests/harness/corpus-costs/8346-replace-callback-untyped-params.mjs.json new file mode 100644 index 000000000..cdddf6d76 --- /dev/null +++ b/tests/harness/corpus-costs/8346-replace-callback-untyped-params.mjs.json @@ -0,0 +1 @@ +{ "plain": 2880, "san": 5080 } From ceb29078dc763bb0ccad928bb563ee90963d1b8c Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 06:31:51 -0500 Subject: [PATCH 245/259] Skip comments when renaming a range's debug ids --- .../compiler/src/backend/llvm/emit-journal.ts | 47 ++++++++++++++---- .../compiler/test/chunked-emission.test.ts | 49 +++++++++++++++++++ 2 files changed, 86 insertions(+), 10 deletions(-) diff --git a/packages/compiler/src/backend/llvm/emit-journal.ts b/packages/compiler/src/backend/llvm/emit-journal.ts index d6fed03a6..b2b3fc4cc 100644 --- a/packages/compiler/src/backend/llvm/emit-journal.ts +++ b/packages/compiler/src/backend/llvm/emit-journal.ts @@ -175,22 +175,49 @@ export function renameChunk( }; } -/** Renames metadata references `!N` outside string literals. Debug builds - * attach no alias tags, so every such reference in a function's text is a - * debug metadata id. */ +/** Renames metadata references `!N` outside string literals and comments. + * Debug builds attach no alias tags, so every such reference in a + * function's text is a debug metadata id. A string literal or a comment + * (`;` outside a string literal) ends at the end of its line; a quote + * inside a string literal is escaped (`\22`). */ function renameDebugIds(text: string, ids: ReadonlyMap): string { const parts: string[] = []; let copied = 0; - // The next quote at or after the scan, and whether the scan is inside a - // string literal. - let quote = text.indexOf('"'); + // The line of the reference being looked at, and whether the reference + // is inside a string literal or a comment there. The next quote and + // semicolon positions only move forward, so each is found once. + let lineEnd = -1; let quoted = false; + let comment = false; + let quote = text.indexOf('"'); + let semicolon = text.indexOf(";"); for (let at = text.indexOf("!"); at >= 0; at = text.indexOf("!", at + 1)) { - while (quote >= 0 && quote < at) { - quoted = !quoted; - quote = text.indexOf('"', quote + 1); + if (at > lineEnd) { + lineEnd = text.indexOf("\n", at); + if (lineEnd < 0) lineEnd = text.length; + quoted = false; + comment = false; + // Quotes and semicolons of earlier lines end with them. + if ((quote >= 0 && quote < at) || (semicolon >= 0 && semicolon < at)) { + const lineStart = text.lastIndexOf("\n", at) + 1; + while (quote >= 0 && quote < lineStart) quote = text.indexOf('"', quote + 1); + while (semicolon >= 0 && semicolon < lineStart) + semicolon = text.indexOf(";", semicolon + 1); + } } - if (quoted) continue; + while (!comment) { + const nextQuote = quote >= 0 && quote < at ? quote : -1; + const nextSemicolon = semicolon >= 0 && semicolon < at ? semicolon : -1; + if (nextQuote < 0 && nextSemicolon < 0) break; + if (nextQuote >= 0 && (nextSemicolon < 0 || nextQuote < nextSemicolon)) { + quoted = !quoted; + quote = text.indexOf('"', quote + 1); + } else { + if (!quoted) comment = true; + semicolon = text.indexOf(";", semicolon + 1); + } + } + if (quoted || comment) continue; if (at > 0 && isNameChar(text.charCodeAt(at - 1))) continue; let end = at + 1; while (end < text.length && isDigit(text.charCodeAt(end))) end++; diff --git a/packages/compiler/test/chunked-emission.test.ts b/packages/compiler/test/chunked-emission.test.ts index 567a082ef..47e82cf9e 100644 --- a/packages/compiler/test/chunked-emission.test.ts +++ b/packages/compiler/test/chunked-emission.test.ts @@ -177,3 +177,52 @@ test("debug builds emitted in ranges merge into the text one emitter gives", asy await rm(dir, { recursive: true, force: true }); } }, 300_000); + +// A method name holding a double quote is written into a comment after the +// function's `!dbg` attachment; the rename of the range's debug ids reads +// comments and string literals as ending at the end of their line. +test("debug ids after a comment that holds a quote are renamed", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-chunked-debug-quote-")); + try { + const entry = join(dir, "main.ts"); + const source = [ + "class Greeter {", + " ['say \"hi'](n: number): number {", + " return n + 1;", + " }", + "}", + "const greeter = new Greeter();", + "function twice(x: number): number {", + " return x * 2;", + "}", + "function report(label: string, value: number): void {", + " console.log(label, value);", + "}", + 'report("method", greeter[\'say "hi\'](1));', + 'report("twice", twice(3));', + "", + ].join("\n"); + await writeFile(entry, source); + const outPath = join(dir, "main.ir.json"); + const result = await compile(entry, { + outDir: dir, + outPath, + outputKind: "ir", + optimization: "dev", + }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + const ir = await readFile(outPath, "utf8"); + const options: LlvmTargetOptions = { debugSources: new Map([[entry, source]]) }; + const serial = text(emitLlvmModuleSource(deserializeModule(ir), options)); + expect(serial).toMatch(/!dbg ![0-9]+ \{ ;[^\n]*"/); + for (const functionChunks of [2, 3]) { + const chunked = text( + emitLlvmModuleSource(deserializeModule(ir), { ...options, functionChunks }), + ); + expect(chunked === serial, `${functionChunks} chunks`).toBe(true); + } + } finally { + await rm(dir, { recursive: true, force: true }); + } +}, 60_000); From 24ef53ac237dd58c79aa590cff61c1775b275a86 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 06:32:18 -0500 Subject: [PATCH 246/259] Have tsc-ts read its library files from disk when it can Every file tsc-ts reads goes through scriptc's file system callbacks, including the ~80 files of tsc-ts's own default library directory: one round trip from the checker to the compiler and back for each. Those files belong to the installed tsc-ts (the build caches key on its executable's identity), and no build serves them differently. When tsc-ts takes --default-libraries-from-disk, the native compiler passes it to the checker it starts and to the shared checker server, so tsc-ts reads those files itself; every other path keeps the callbacks. Released tsc-ts versions reject the flag, so checker-features.ts asks each tsc-ts executable once (tsc-ts --api --default-libraries-from-disk with an empty input exits with 0 only when it knows the flag) and keeps the answer in the native cache, keyed by the executable's identity. With a tsc-ts that does not know the flag, builds run as before. Edit builds of small programs through the shared checker server are about 18 ms faster, and 6-9 ms faster without it. --- .../compiler/native/ts7-process-child.test.c | 10 ++-- packages/compiler/native/ts7-process.c | 27 ++++++---- packages/compiler/native/ts7-process.ffi.json | 4 +- packages/compiler/native/ts7-process.h | 5 +- packages/compiler/native/ts7-process.test.c | 24 +++++---- .../src/frontend/ts7/checker-features.test.ts | 45 ++++++++++++++++ .../src/frontend/ts7/checker-features.ts | 53 +++++++++++++++++++ .../src/frontend/ts7/checker-server.ts | 7 ++- .../compiler/src/frontend/ts7/native-api.ts | 12 +++-- .../src/frontend/ts7/native-process.ts | 27 ++++++++-- packages/compiler/src/native/cli.ts | 6 +++ 11 files changed, 185 insertions(+), 35 deletions(-) create mode 100644 packages/compiler/src/frontend/ts7/checker-features.test.ts create mode 100644 packages/compiler/src/frontend/ts7/checker-features.ts diff --git a/packages/compiler/native/ts7-process-child.test.c b/packages/compiler/native/ts7-process-child.test.c index 386a0a7c3..4d1cbc081 100644 --- a/packages/compiler/native/ts7-process-child.test.c +++ b/packages/compiler/native/ts7-process-child.test.c @@ -64,8 +64,11 @@ static int child_main(int argc, char **argv) { #endif int listening = argc >= 9 && strcmp(argv[5], "--listen") == 0 && strcmp(argv[7], "--idle-exit") == 0; int fixed = listening ? 9 : 5; - if (argc < fixed || argc > fixed + 1 || strcmp(argv[1], "--api") != 0 || strcmp(argv[2], "--cwd") != 0 || - strncmp(argv[4], "--callbacks=", 12) != 0 || (argc == fixed + 1 && strcmp(argv[fixed], "--timing") != 0)) + int at = fixed, timing = 0, libraries = 0; + if (at < argc && strcmp(argv[at], "--timing") == 0) { timing = 1; at++; } + if (at < argc && strcmp(argv[at], "--default-libraries-from-disk") == 0) { libraries = 1; at++; } + if (argc < fixed || at != argc || strcmp(argv[1], "--api") != 0 || strcmp(argv[2], "--cwd") != 0 || + strncmp(argv[4], "--callbacks=", 12) != 0) return 71; const char *mode = argv[3]; #ifndef _WIN32 @@ -76,7 +79,8 @@ static int child_main(int argc, char **argv) { fputc('\n', stdout); fputs(argv[4], stdout); fputc('\n', stdout); - fputs(argc == 6 ? "timing\n" : "plain\n", stdout); + fputs(timing ? "timing\n" : "plain\n", stdout); + if (libraries) fputs("libraries from disk\n", stdout); return ferror(stdout) ? 72 : 0; } if (strcmp(mode, "exit") == 0) return 0; diff --git a/packages/compiler/native/ts7-process.c b/packages/compiler/native/ts7-process.c index 3fd38a423..8261c341b 100644 --- a/packages/compiler/native/ts7-process.c +++ b/packages/compiler/native/ts7-process.c @@ -161,7 +161,7 @@ static wchar_t *command_line(wchar_t **arguments, size_t count) { } static int start_process(Ts7Process *p, char **args, size_t argc) { - wchar_t *wide[6] = {0}; + wchar_t *wide[7] = {0}; wchar_t *line = NULL; HANDLE child_input = NULL, child_output = NULL, child_error = NULL; LPPROC_THREAD_ATTRIBUTE_LIST attributes = NULL; @@ -330,7 +330,7 @@ static void stop_process(Ts7Process *p) { uint32_t scriptc_ts7_open(const uint8_t *executable, size_t executable_size, const uint8_t *cwd, size_t cwd_size, const uint8_t *callbacks, size_t callbacks_size, - uint8_t timing) { + uint8_t timing, uint8_t libraries_from_disk) { if (next_id == 0) { error_text("server handle IDs are exhausted"); return 0; } char *exe = copy_argument(executable, executable_size, ""); if (exe == NULL) return 0; @@ -346,8 +346,12 @@ uint32_t scriptc_ts7_open(const uint8_t *executable, size_t executable_size, } exit_registered = 1; } - char *args[] = {exe, "--api", "--cwd", directory, callback_flag, timing ? "--timing" : NULL, NULL}; - int started = start_process(p, args, timing ? 6 : 5); + char *args[8] = {exe, "--api", "--cwd", directory, callback_flag}; + size_t argc = 5; + if (timing) args[argc++] = "--timing"; + if (libraries_from_disk) args[argc++] = "--default-libraries-from-disk"; + args[argc] = NULL; + int started = start_process(p, args, argc); free(exe); free(directory); free(callback_flag); if (!started) { free(p); return 0; } p->id = next_id++; @@ -361,9 +365,10 @@ uint32_t scriptc_ts7_attach(const uint8_t *name, size_t name_size, const uint8_t *executable, size_t executable_size, const uint8_t *cwd, size_t cwd_size, const uint8_t *callbacks, size_t callbacks_size, - uint8_t timing, uint32_t idle_exit, uint32_t memory) { + uint8_t timing, uint8_t libraries_from_disk, uint32_t idle_exit, + uint32_t memory) { (void)name; (void)name_size; (void)executable; (void)executable_size; (void)cwd; (void)cwd_size; - (void)callbacks; (void)callbacks_size; (void)timing; (void)idle_exit; (void)memory; + (void)callbacks; (void)callbacks_size; (void)timing; (void)libraries_from_disk; (void)idle_exit; (void)memory; error_text("a shared checker server needs Unix sockets"); return 0; } @@ -455,7 +460,8 @@ uint32_t scriptc_ts7_attach(const uint8_t *name, size_t name_size, const uint8_t *executable, size_t executable_size, const uint8_t *cwd, size_t cwd_size, const uint8_t *callbacks, size_t callbacks_size, - uint8_t timing, uint32_t idle_exit, uint32_t memory) { + uint8_t timing, uint8_t libraries_from_disk, uint32_t idle_exit, + uint32_t memory) { if (next_id == 0) { error_text("server handle IDs are exhausted"); return 0; } char *server = copy_argument(name, name_size, ""); if (server == NULL) return 0; @@ -491,8 +497,11 @@ uint32_t scriptc_ts7_attach(const uint8_t *name, size_t name_size, (void)snprintf(limit, sizeof(limit), "TSC_TS_LISTEN_MEMORY=%lu", (unsigned long)memory); pid_t pid = -1; if (callback_flag != NULL) { - char *args[] = {exe, "--api", "--cwd", dir, callback_flag, "--listen", socket_path, "--idle-exit", idle, - timing ? "--timing" : NULL, NULL}; + char *args[12] = {exe, "--api", "--cwd", dir, callback_flag, "--listen", socket_path, "--idle-exit", idle}; + size_t argc = 9; + if (timing) args[argc++] = "--timing"; + if (libraries_from_disk) args[argc++] = "--default-libraries-from-disk"; + args[argc] = NULL; pid = start_server(args, limit); } free(exe); free(dir); free(callback_flag); diff --git a/packages/compiler/native/ts7-process.ffi.json b/packages/compiler/native/ts7-process.ffi.json index c503e3cae..963c81f15 100644 --- a/packages/compiler/native/ts7-process.ffi.json +++ b/packages/compiler/native/ts7-process.ffi.json @@ -1,8 +1,8 @@ { "ffi_format": 6, "functions": [ - { "name": "ts7NativeOpen", "symbol": "scriptc_ts7_open", "params": ["string", "string", "string", "bool"], "returns": "u32" }, - { "name": "ts7NativeAttach", "symbol": "scriptc_ts7_attach", "params": ["string", "string", "string", "string", "bool", "u32", "u32"], "returns": "u32" }, + { "name": "ts7NativeOpen", "symbol": "scriptc_ts7_open", "params": ["string", "string", "string", "bool", "bool"], "returns": "u32" }, + { "name": "ts7NativeAttach", "symbol": "scriptc_ts7_attach", "params": ["string", "string", "string", "string", "bool", "bool", "u32", "u32"], "returns": "u32" }, { "name": "ts7NativeRead", "symbol": "scriptc_ts7_read", "params": ["u32", "mutable-bytes", "u32", "u32"], "returns": "i32" }, { "name": "ts7NativeWrite", "symbol": "scriptc_ts7_write", "params": ["u32", "bytes", "u32", "u32"], "returns": "i32" }, { "name": "ts7NativePid", "symbol": "scriptc_ts7_pid", "params": ["u32"], "returns": "u32" }, diff --git a/packages/compiler/native/ts7-process.h b/packages/compiler/native/ts7-process.h index 4199e8795..d51f939a9 100644 --- a/packages/compiler/native/ts7-process.h +++ b/packages/compiler/native/ts7-process.h @@ -12,7 +12,7 @@ uint32_t scriptc_ts7_open(const uint8_t *executable, size_t executable_size, const uint8_t *cwd, size_t cwd_size, const uint8_t *callbacks, size_t callbacks_size, - uint8_t timing); + uint8_t timing, uint8_t libraries_from_disk); /* Connects to the shared checker server `name` (`--api --listen`) in this * user's private server directory, starting it in its own process group * with `--idle-exit idle_exit` and a limit of `memory` megabytes @@ -25,7 +25,8 @@ uint32_t scriptc_ts7_attach(const uint8_t *name, size_t name_size, const uint8_t *executable, size_t executable_size, const uint8_t *cwd, size_t cwd_size, const uint8_t *callbacks, size_t callbacks_size, - uint8_t timing, uint32_t idle_exit, uint32_t memory); + uint8_t timing, uint8_t libraries_from_disk, uint32_t idle_exit, + uint32_t memory); int32_t scriptc_ts7_read(uint32_t handle, uint8_t *bytes, size_t size, uint32_t offset, uint32_t length); int32_t scriptc_ts7_write(uint32_t handle, const uint8_t *bytes, size_t size, diff --git a/packages/compiler/native/ts7-process.test.c b/packages/compiler/native/ts7-process.test.c index dc0c67ced..b6d760abd 100644 --- a/packages/compiler/native/ts7-process.test.c +++ b/packages/compiler/native/ts7-process.test.c @@ -21,12 +21,14 @@ static const char *executable; static const char *callbacks = "readFile,fileExists"; -static uint32_t start(const char *mode, int timing) { +static uint32_t start_with(const char *mode, int timing, int libraries) { return scriptc_ts7_open((const uint8_t *)executable, strlen(executable), (const uint8_t *)mode, strlen(mode), - (const uint8_t *)callbacks, strlen(callbacks), (uint8_t)timing); + (const uint8_t *)callbacks, strlen(callbacks), (uint8_t)timing, (uint8_t)libraries); } +static uint32_t start(const char *mode, int timing) { return start_with(mode, timing, 0); } + static void fail_message(void) { uint8_t message[1024]; int32_t size = scriptc_ts7_error(message, sizeof(message)); @@ -83,11 +85,13 @@ static void argument_cases(void) { "", "a b", "double\"quote", "end\\", "many\\\\\"quotes\\\\", "a;&$()`'b", "h\xc3\xa9llo \xf0\x9f\x8c\x8d", }; for (size_t i = 0; i < sizeof(values) / sizeof(values[0]); i++) { - for (int timing = 0; timing <= 1; timing++) { + for (int flags = 0; flags < 4; flags++) { + int timing = flags & 1, libraries = flags >> 1; char mode[256], expected[512]; snprintf(mode, sizeof(mode), "argv:%s", values[i]); - snprintf(expected, sizeof(expected), "%s\n--callbacks=%s\n%s\n", values[i], callbacks, timing ? "timing" : "plain"); - uint32_t id = start(mode, timing); + snprintf(expected, sizeof(expected), "%s\n--callbacks=%s\n%s\n%s", values[i], callbacks, + timing ? "timing" : "plain", libraries ? "libraries from disk\n" : ""); + uint32_t id = start_with(mode, timing, libraries); assert(id != 0); uint8_t actual[512]; read_exact(id, actual, strlen(expected)); @@ -147,10 +151,10 @@ static void failure_cases(void) { executable = "/scriptc/does-not-exist/tsgo"; for (int i = 0; i < 30; i++) { assert(start("echo", 0) == 0); fail_message(); } executable = saved; - assert(scriptc_ts7_open(NULL, 0, bytes, 1, bytes, 1, 0) == 0); - assert(scriptc_ts7_open((const uint8_t *)"abc\0def", 7, bytes, 1, bytes, 1, 0) == 0); - assert(scriptc_ts7_open((const uint8_t *)executable, strlen(executable), NULL, 0, bytes, 1, 0) == 0); - assert(scriptc_ts7_open((const uint8_t *)executable, strlen(executable), bytes, 1, NULL, 0, 0) == 0); + assert(scriptc_ts7_open(NULL, 0, bytes, 1, bytes, 1, 0, 0) == 0); + assert(scriptc_ts7_open((const uint8_t *)"abc\0def", 7, bytes, 1, bytes, 1, 0, 0) == 0); + assert(scriptc_ts7_open((const uint8_t *)executable, strlen(executable), NULL, 0, bytes, 1, 0, 0) == 0); + assert(scriptc_ts7_open((const uint8_t *)executable, strlen(executable), bytes, 1, NULL, 0, 0, 0) == 0); for (int i = 0; i < 30; i++) { uint32_t id = start("exit", 0); assert(id != 0); @@ -177,7 +181,7 @@ static void failure_cases(void) { static uint32_t attach(const char *name, const char *mode, uint32_t memory) { return scriptc_ts7_attach((const uint8_t *)name, strlen(name), (const uint8_t *)executable, strlen(executable), (const uint8_t *)mode, strlen(mode), (const uint8_t *)callbacks, strlen(callbacks), - 0, 1, memory); + 0, 0, 1, memory); } static void expect_line(uint32_t id, const char *expected) { diff --git a/packages/compiler/src/frontend/ts7/checker-features.test.ts b/packages/compiler/src/frontend/ts7/checker-features.test.ts new file mode 100644 index 000000000..fcd3576cb --- /dev/null +++ b/packages/compiler/src/frontend/ts7/checker-features.test.ts @@ -0,0 +1,45 @@ +import { chmodSync, mkdtempSync, rmSync, writeFileSync } from "node:fs"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { afterAll, afterEach, expect, test } from "vitest"; +import { checkerReadsLibrariesFromDisk, setCheckerFeatureStore } from "./checker-features.js"; + +const dir = mkdtempSync(join(tmpdir(), "scriptc-checker-features-")); +afterAll(() => rmSync(dir, { recursive: true, force: true })); +afterEach(() => setCheckerFeatureStore(null)); + +/** A stand-in checker that records its arguments and exits with `status`. */ +function checker(name: string, status: number): { path: string; log: string } { + const path = join(dir, name); + const log = path + ".log"; + writeFileSync(path, `#!/bin/sh\necho "$@" >> '${log}'\nexit ${status}\n`); + chmodSync(path, 0o755); + return { path, log }; +} + +test.skipIf(process.platform === "win32")( + "the checker is asked once whether it reads its library files from the disk, and the answer is stored", + async () => { + const { readFileSync, existsSync } = await import("node:fs"); + const entries = new Map(); + setCheckerFeatureStore({ + read: (key) => entries.get(key) ?? null, + write: (key, text) => void entries.set(key, text), + }); + const current = checker("current", 0); + const released = checker("released", 2); + expect(checkerReadsLibrariesFromDisk(current.path, {})).toBe(true); + expect(checkerReadsLibrariesFromDisk(released.path, {})).toBe(false); + expect(readFileSync(current.log, "utf8")).toBe("--api --default-libraries-from-disk\n"); + expect([...entries.values()].sort()).toEqual(["0", "1"]); + // Later asks use the answers: the checkers do not run again. + expect(checkerReadsLibrariesFromDisk(current.path, {})).toBe(true); + expect(checkerReadsLibrariesFromDisk(released.path, {})).toBe(false); + expect(readFileSync(current.log, "utf8").split("\n").length).toBe(2); + expect(readFileSync(released.log, "utf8").split("\n").length).toBe(2); + // tsgo is never asked. + const tsgo = checker("tsgo", 0); + expect(checkerReadsLibrariesFromDisk(tsgo.path, { SCRIPTC_CHECKER: "tsgo" })).toBe(false); + expect(existsSync(tsgo.log)).toBe(false); + }, +); diff --git a/packages/compiler/src/frontend/ts7/checker-features.ts b/packages/compiler/src/frontend/ts7/checker-features.ts new file mode 100644 index 000000000..b80a54994 --- /dev/null +++ b/packages/compiler/src/frontend/ts7/checker-features.ts @@ -0,0 +1,53 @@ +import { spawnSync } from "node:child_process"; +import { createHash } from "node:crypto"; +import { checkerBackend } from "./checker-backend.js"; +import { checkerExecutableIdentity } from "./lib-diagnostics.js"; + +/** Text entries kept between builds (the native compiler's cache). */ +export interface CheckerFeatureStore { + read(key: string): string | null; + write(key: string, text: string): void; +} + +let featureStore: CheckerFeatureStore | null = null; +const answers = new Map(); + +/** Keeps the answers of checkerReadsLibrariesFromDisk between builds. */ +export function setCheckerFeatureStore(store: CheckerFeatureStore | null): void { + featureStore = store; +} + +/** + * Whether the tsc-ts at `executable` takes `--api --default-libraries-from-disk`, which has it read the files + * of its default library directory from the disk instead of through the file system callbacks. tsc-ts releases + * before it reject the flag, so it is asked once per executable identity: the stored answer, or else + * `tsc-ts --api --default-libraries-from-disk` with an empty input, which exits with 0 when the flag is known + * and with a usage error when it is not. tsgo is never asked. + */ +export function checkerReadsLibrariesFromDisk( + executable: string, + env: NodeJS.ProcessEnv = process.env, +): boolean { + if (checkerBackend(env) !== "tsc-ts") return false; + const key = createHash("sha256") + .update(JSON.stringify(["default-libraries-from-disk", checkerExecutableIdentity(executable)])) + .digest("hex"); + const known = answers.get(key); + if (known !== undefined) return known; + const stored = featureStore?.read(key) ?? null; + let answer: boolean; + if (stored === "1" || stored === "0") answer = stored === "1"; + else { + const probe = spawnSync(executable, ["--api", "--default-libraries-from-disk"], { + encoding: "utf8", + stdio: "pipe", + timeout: 10_000, + }); + answer = probe.error === undefined && probe.status === 0; + // A probe that could not run says nothing about the flag: ask again next time. + if (probe.error === undefined && probe.status !== null) + featureStore?.write(key, answer ? "1" : "0"); + } + answers.set(key, answer); + return answer; +} diff --git a/packages/compiler/src/frontend/ts7/checker-server.ts b/packages/compiler/src/frontend/ts7/checker-server.ts index 6d80e2599..94c80f8db 100644 --- a/packages/compiler/src/frontend/ts7/checker-server.ts +++ b/packages/compiler/src/frontend/ts7/checker-server.ts @@ -19,14 +19,16 @@ export const CHECKER_SERVER_MEMORY = 2048; * answers, and the server keeps the files it parsed for the next build. * Returns the server's name, a digest of everything a server's answers * depend on besides the files it reads through the build: the tsc-ts - * executable, the working directory, the file system callbacks, timing, and - * the `TSC_TS_*` environment. Returns null when the shared server is not used. + * executable, the working directory, the file system callbacks, timing, + * whether it reads its library files from the disk, and the `TSC_TS_*` + * environment. Returns null when the shared server is not used. */ export function checkerServerName( executable: string, cwd: string, timing: boolean, env: NodeJS.ProcessEnv = process.env, + librariesFromDisk = false, ): string | null { if (env["SCRIPTC_CHECKER_SERVER"] !== "1") return null; if (process.platform !== "linux" && process.platform !== "darwin") return null; @@ -42,6 +44,7 @@ export function checkerServerName( cwd, TS7_FILE_SYSTEM_CALLBACKS, timing, + librariesFromDisk, tscTsEnv, ]), ) diff --git a/packages/compiler/src/frontend/ts7/native-api.ts b/packages/compiler/src/frontend/ts7/native-api.ts index f8e10efc5..fa0690e69 100644 --- a/packages/compiler/src/frontend/ts7/native-api.ts +++ b/packages/compiler/src/frontend/ts7/native-api.ts @@ -1,4 +1,5 @@ import { Ts7Api } from "./api.js"; +import { checkerReadsLibrariesFromDisk } from "./checker-features.js"; import { checkerServerName } from "./checker-server.js"; import { attachNativeTs7Process, spawnNativeTs7Wire } from "./native-process.js"; import { Ts7RpcClient } from "./rpc-client.js"; @@ -15,12 +16,17 @@ export function createNativeTs7Api(options: { shared?: boolean; }): Ts7Api { const timing = options.collectTiming ?? false; + // The checker reads its own library files when it can: they are part of the + // installed tsc-ts, so no build serves them differently. + const libraries = checkerReadsLibrariesFromDisk(options.executable); const server = - options.shared === false ? null : checkerServerName(options.executable, options.cwd, timing); + options.shared === false + ? null + : checkerServerName(options.executable, options.cwd, timing, process.env, libraries); const shared = server === null ? null - : attachNativeTs7Process(server, options.executable, options.cwd, timing); + : attachNativeTs7Process(server, options.executable, options.cwd, timing, libraries); if (shared !== null) { const rpc = new Ts7RpcClient(new Ts7Wire(shared)); try { @@ -32,7 +38,7 @@ export function createNativeTs7Api(options: { } } return new Ts7Api( - new Ts7RpcClient(spawnNativeTs7Wire(options.executable, options.cwd, timing)), + new Ts7RpcClient(spawnNativeTs7Wire(options.executable, options.cwd, timing, libraries)), options.fs, timing, ); diff --git a/packages/compiler/src/frontend/ts7/native-process.ts b/packages/compiler/src/frontend/ts7/native-process.ts index 0582ae673..d59543f32 100644 --- a/packages/compiler/src/frontend/ts7/native-process.ts +++ b/packages/compiler/src/frontend/ts7/native-process.ts @@ -10,6 +10,7 @@ declare function ts7NativeOpen( cwd: string, callbacks: string, timing: boolean, + librariesFromDisk: boolean, ): number; declare function ts7NativeAttach( name: string, @@ -17,6 +18,7 @@ declare function ts7NativeAttach( cwd: string, callbacks: string, timing: boolean, + librariesFromDisk: boolean, idleExit: number, memory: number, ): number; @@ -63,12 +65,26 @@ export class NativeTs7Process implements Ts7WireIo { private handle: number; readonly pid: number; - /** With `handle`, a connection to a shared checker server (attachNativeTs7Process). */ - constructor(executable: string, cwd: string, collectTiming = false, handle = 0) { + /** With `handle`, a connection to a shared checker server (attachNativeTs7Process). With + * `librariesFromDisk`, the server reads its default library files from the disk + * (checkerReadsLibrariesFromDisk). */ + constructor( + executable: string, + cwd: string, + collectTiming = false, + handle = 0, + librariesFromDisk = false, + ) { this.handle = handle !== 0 ? handle - : ts7NativeOpen(executable, cwd, TS7_FILE_SYSTEM_CALLBACKS, collectTiming); + : ts7NativeOpen( + executable, + cwd, + TS7_FILE_SYSTEM_CALLBACKS, + collectTiming, + librariesFromDisk, + ); if (this.handle === 0) throw nativeError("startup"); this.pid = ts7NativePid(this.handle); } @@ -125,6 +141,7 @@ export function attachNativeTs7Process( executable: string, cwd: string, collectTiming = false, + librariesFromDisk = false, ): NativeTs7Process | null { const handle = ts7NativeAttach( name, @@ -132,6 +149,7 @@ export function attachNativeTs7Process( cwd, TS7_FILE_SYSTEM_CALLBACKS, collectTiming, + librariesFromDisk, CHECKER_SERVER_IDLE_EXIT, CHECKER_SERVER_MEMORY, ); @@ -142,6 +160,7 @@ export function spawnNativeTs7Wire( executable: string, cwd: string, collectTiming = false, + librariesFromDisk = false, ): Ts7Wire { - return new Ts7Wire(new NativeTs7Process(executable, cwd, collectTiming)); + return new Ts7Wire(new NativeTs7Process(executable, cwd, collectTiming, 0, librariesFromDisk)); } diff --git a/packages/compiler/src/native/cli.ts b/packages/compiler/src/native/cli.ts index b729b2557..b3de05846 100644 --- a/packages/compiler/src/native/cli.ts +++ b/packages/compiler/src/native/cli.ts @@ -21,6 +21,7 @@ import { checkerExecutableIdentity, setLibDiagnosticsStore, } from "../frontend/ts7/lib-diagnostics.js"; +import { setCheckerFeatureStore } from "../frontend/ts7/checker-features.js"; import { loadNativeToolchain } from "./toolchain.js"; import { buildSanitizedRuntime } from "./sanitizer.js"; import { runCompilerTask } from "./task.js"; @@ -67,6 +68,11 @@ async function main(): Promise { }, checkerExecutableIdentity(toolchain.ts7Executable), ); + setCheckerFeatureStore({ + read: (key) => + store.read("checker-features", key, NATIVE_STRING_BYTES)?.toString("utf8") ?? null, + write: (key, text) => store.write("checker-features", key, text), + }); } compiler = new NativeCompiler(toolchain, cache); return compiler; From d8f287486087df2931f33db768b615c42fe8535f Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 06:42:25 -0500 Subject: [PATCH 247/259] Keep replace callback parameters checked-dynamic where parseInt or parseFloat expects another type parseFloat and the text of parseInt take a string, and the radix of parseInt takes a number. An unannotated offset passed as their text, or a capture passed as the radix, is no longer bound to its value's type; it stays checked-dynamic, so the call compiles as it did before the binding. --- .../lowering/containers/replacer-params.ts | 26 +++++++++++++------ .../compiler/test/replacer-params.test.ts | 7 ++++- .../8345-replace-callback-untyped-params.ts | 5 ++++ 3 files changed, 29 insertions(+), 9 deletions(-) diff --git a/packages/compiler/src/frontend/lowering/containers/replacer-params.ts b/packages/compiler/src/frontend/lowering/containers/replacer-params.ts index e84ca1461..3a3eff1cf 100644 --- a/packages/compiler/src/frontend/lowering/containers/replacer-params.ts +++ b/packages/compiler/src/frontend/lowering/containers/replacer-params.ts @@ -115,7 +115,10 @@ const STRING_MEMBERS: ReadonlySet = new Set([ /** Whether every read of `symbol` in `body` is one that means the same * for an `any` value and for a `kind` value, and lowers for both: a - * template span, a Number/String/parseInt/parseFloat argument, a listed + * template span, the argument of Number or String, the text argument of + * parseInt or parseFloat for a string and the radix of parseInt for a + * number (each a parameter of that type, which an `any` value converts + * to), a listed * string member, `+`, strict equality, arithmetic and comparisons of * numbers, a returned value, and a string key of an element access on a * string-indexed record or an `any` value. Anything else keeps the @@ -144,13 +147,20 @@ function readsFit( return shape?.indexValue !== undefined && !shape.tuple; } if (ts.isArrowFunction(parent)) return parent.body === node; - if (ts.isCallExpression(parent)) - return ( - parent.expression !== node && - ["Number", "String", "parseInt", "parseFloat"].some((global) => - lowerer.isStdlibGlobal(parent.expression, global), - ) - ); + if (ts.isCallExpression(parent)) { + if (parent.expression === node) return false; + const position = parent.arguments.nodes.indexOf(node as ts.Expression); + if ( + lowerer.isStdlibGlobal(parent.expression, "Number") || + lowerer.isStdlibGlobal(parent.expression, "String") + ) + return position === 0; + if (lowerer.isStdlibGlobal(parent.expression, "parseFloat")) + return position === 0 && kind === "string"; + if (lowerer.isStdlibGlobal(parent.expression, "parseInt")) + return position === 0 ? kind === "string" : position === 1 && kind === "f64"; + return false; + } if (ts.isPropertyAccessExpression(parent)) { const member = parent.name.text; if (kind !== "string" || parent.expression !== node || !STRING_MEMBERS.has(member)) diff --git a/packages/compiler/test/replacer-params.test.ts b/packages/compiler/test/replacer-params.test.ts index bb5549a86..a5d22bb82 100644 --- a/packages/compiler/test/replacer-params.test.ts +++ b/packages/compiler/test/replacer-params.test.ts @@ -69,6 +69,8 @@ console.log(text.replace(/(a)|(b)/g, (m, a, b) => \`\${m}\${a}\${b}\`)); console.log(text.replace(/(a)(b)?/g, (m: string, a: string, b: string | undefined, at: number) => m + a + (b ?? "") + at)); const half = (n: number): number => n / 2; console.log(text.replace(/b/g, (m, at) => String(half(at)))); +console.log(text.replace(/b/g, (m, at) => String(parseFloat(at) + parseInt(at)))); +console.log(text.replace(/(\\d)/g, (m, d) => String(parseInt("11", d)))); console.log(text.replace(/(a)(b)(c)/g, (m, a, b, c, at, all, extra) => m + a + b + c + at + all + extra)); `); expect(replacerCalls(llvm)).toEqual({ @@ -76,7 +78,10 @@ console.log(text.replace(/(a)(b)(c)/g, (m, a, b, c, at, all, extra) => m + a + b // two captures a match can leave unset (bits 1 and 2); // \`string | undefined\` at capture 2 (bit 8 + 2); an offset passed to a // number parameter keeps its checked-dynamic box (bit 1). - direct: ["2:0", "2:-2147483648", "3:6", "4:1024", "2:2"], + // parseFloat and parseInt take text, and parseInt's radix is a + // number: the offset passed as text and the capture passed as the + // radix stay checked-dynamic (bit 1), so both calls compile. + direct: ["2:0", "2:-2147483648", "3:6", "4:1024", "2:2", "2:2", "2:2"], // Seven parameters exceed the direct calls' limit. boxed: 1, }); diff --git a/tests/corpus/8345-replace-callback-untyped-params.ts b/tests/corpus/8345-replace-callback-untyped-params.ts index 31d3a038b..18ddb3389 100644 --- a/tests/corpus/8345-replace-callback-untyped-params.ts +++ b/tests/corpus/8345-replace-callback-untyped-params.ts @@ -51,6 +51,11 @@ console.log("ab".replace(/(?a)|(?b)/g, (m, a, b, at, all, groups) => `${m} console.log("ab".replace(/b/, (m, at, all, extra, more) => `${m}:${at}:${all}:${extra}:${more}`)); console.log("ab".replace(/(a)(b)/, (m, a, b, at, all, extra, more) => `${m}${a}${b}${at}${all}${extra}${more}`)); +// An offset passed to parseFloat converts with ToString, and captures +// passed to parseInt and parseFloat are their text. +console.log("a1b22".replace(/\d+/g, (m, at) => `<${parseFloat(at) + parseInt(m, at + 10)}>`)); +console.log("1.5 2e1".replace(/(\S+)/g, (_m, d) => String(parseFloat(d) + parseInt(d) + Number(d)))); + // Results that are not strings convert with ToString. const counts: Record = { a: 1, b: true, c: null, d: undefined, e: { toString: () => "E" } }; console.log("a b c d e".replace(/\w/g, (m) => counts[m])); From c80945ec21ddbd208f7191b2547ad217d6b76987 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 06:50:19 -0500 Subject: [PATCH 248/259] Leave timing and cache placement variables out of the frontend cache key The native frontend cache key included every SCRIPTC_* variable, so turning SCRIPTC_TIMING on or off, or changing SCRIPTC_CACHE_DIR, SCRIPTC_CACHE_MAX_MB, SCRIPTC_EMIT_WORKERS or SCRIPTC_EMIT_WORKER_FUNCTIONS, reran the frontend on an unchanged program. The frontend's output does not depend on these variables, so the key now leaves them out. Every other SCRIPTC_* variable still keys the entry. --- packages/compiler/src/native/prepare.test.ts | 27 +++++++++++++++++++- packages/compiler/src/native/prepare.ts | 26 ++++++++++++++----- 2 files changed, 46 insertions(+), 7 deletions(-) diff --git a/packages/compiler/src/native/prepare.test.ts b/packages/compiler/src/native/prepare.test.ts index 5d0f9faae..07698820e 100644 --- a/packages/compiler/src/native/prepare.test.ts +++ b/packages/compiler/src/native/prepare.test.ts @@ -1,7 +1,7 @@ import { mkdirSync, mkdtempSync, readdirSync, readFileSync, rmSync, writeFileSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import { afterEach, expect, test } from "vitest"; +import { afterEach, expect, test, vi } from "vitest"; import { LINUX_ARM64_GNU_TARGET, nativeCodegenTarget, @@ -23,6 +23,7 @@ function text(input: ReturnType["prepare"]>) { const scratch: string[] = []; afterEach(() => { + vi.unstubAllEnvs(); for (const path of scratch.splice(0)) rmSync(path, { recursive: true, force: true }); }); @@ -197,6 +198,30 @@ test("structurally invalid cached features cause a rebuild even with a valid dig expect(f.loads()).toBe(2); }); +test("timing, cache placement and emission worker variables keep the frontend output", () => { + for (const name of [ + "SCRIPTC_CACHE_DIR", + "SCRIPTC_CACHE_MAX_MB", + "SCRIPTC_EMIT_WORKERS", + "SCRIPTC_EMIT_WORKER_FUNCTIONS", + "SCRIPTC_TIMING", + "SCRIPTC_TEST_FRONTEND_KEY", + ]) + vi.stubEnv(name, undefined); + const f = fixture(); + expect(f.prepare().ok).toBe(true); + vi.stubEnv("SCRIPTC_CACHE_DIR", f.cache.root); + vi.stubEnv("SCRIPTC_CACHE_MAX_MB", "8192"); + vi.stubEnv("SCRIPTC_EMIT_WORKERS", "1"); + vi.stubEnv("SCRIPTC_EMIT_WORKER_FUNCTIONS", "100"); + vi.stubEnv("SCRIPTC_TIMING", "0"); + expect(f.prepare().ok).toBe(true); + expect(f.loads()).toBe(1); + vi.stubEnv("SCRIPTC_TEST_FRONTEND_KEY", "1"); + expect(f.prepare().ok).toBe(true); + expect(f.loads()).toBe(2); +}); + test("serialized IR travels as bounded parts through the frontend cache", () => { const f = fixture(); const first = f.prepare({ emitIr: true }); diff --git a/packages/compiler/src/native/prepare.ts b/packages/compiler/src/native/prepare.ts index a10d16585..11b8f9dd1 100644 --- a/packages/compiler/src/native/prepare.ts +++ b/packages/compiler/src/native/prepare.ts @@ -211,6 +211,24 @@ function implementationIdentity(toolchain: NativeToolchain): string { ); } +/** SCRIPTC_* variables that report on a build, place its cache or set + * backend emission parallelism. The frontend's output does not depend on + * them, so they are left out of its cache key. */ +const FRONTEND_INDEPENDENT_VARIABLES = new Set([ + "SCRIPTC_CACHE_DIR", + "SCRIPTC_CACHE_MAX_MB", + "SCRIPTC_EMIT_WORKERS", + "SCRIPTC_EMIT_WORKER_FUNCTIONS", + "SCRIPTC_TIMING", +]); + +/** The SCRIPTC_* variables a frontend cache entry depends on, sorted by name. */ +function frontendEnvironment(): [string, string | undefined][] { + return Object.entries(process.env) + .filter(([name]) => name.startsWith("SCRIPTC_") && !FRONTEND_INDEPENDENT_VARIABLES.has(name)) + .sort(([a], [b]) => a.localeCompare(b)); +} + function validFeatures(value: unknown): value is NativeLinkFeatures { if (value === null || typeof value !== "object" || Array.isArray(value)) return false; const features = value as Record; @@ -363,9 +381,7 @@ export function prepareNativeExecutable( implementation: implementationIdentity(toolchain), target: toolchain.target.name, declarations: toolchain.declarationsRoot ?? null, - environment: Object.entries(process.env) - .filter(([name]) => name.startsWith("SCRIPTC_")) - .sort(([a], [b]) => a.localeCompare(b)), + environment: frontendEnvironment(), }), ); const cached = readFrontendCache(cache, key, exclusions); @@ -493,9 +509,7 @@ export function prepareNativeLibrary( implementation: implementationIdentity(toolchain), target: toolchain.target.name, declarations: toolchain.declarationsRoot ?? null, - environment: Object.entries(process.env) - .filter(([name]) => name.startsWith("SCRIPTC_")) - .sort(([a], [b]) => a.localeCompare(b)), + environment: frontendEnvironment(), }), ); const cached = readFrontendCache(cache, key, exclusions); From 5247d2dfdd6bc2d0274151aec0d3059a5191962b Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 07:28:48 -0500 Subject: [PATCH 249/259] List bench/regex-replacers among the dynamic-tier workloads Its replace callbacks receive checked-dynamic values where the lib types their parameters any: captures a match can leave unset, and results the checker types any. --- scripts/zero-cost-compare.mjs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/scripts/zero-cost-compare.mjs b/scripts/zero-cost-compare.mjs index 7ae33d64a..df407bbb7 100644 --- a/scripts/zero-cost-compare.mjs +++ b/scripts/zero-cost-compare.mjs @@ -398,7 +398,10 @@ export function dynamicTierSymbols(names) { * later too, decodes JSON.parse trees. bench/throw-chains, also added * later, tests caught values with `instanceof`, as bench/validate-errors * does. bench/dynamic-methods and - * bench/dynamic-properties are untyped JavaScript. Every other bench workload is fully typed and must link none. The gate and + * bench/dynamic-properties are untyped JavaScript. bench/regex-replacers, + * also added later, passes checked-dynamic values to replace callbacks + * whose parameters the lib types `any`: captures a match can leave unset + * and results the checker types `any`. Every other bench workload is fully typed and must link none. The gate and * tests/harness/bench-dynamic-tier.test.ts enforce that, and the test also * fails when a listed workload stops linking them, so remove a workload here * when a leak fix makes its binary clean. */ @@ -421,6 +424,7 @@ export const DYNAMIC_WORKLOADS = new Set([ "bench/line-reader", "bench/json-unions", "bench/throw-chains", + "bench/regex-replacers", ]); /** Names of the functions (text and weak symbols) in `nm` output. Mach-O From 63a99cc4d94be47f7282a6df4926e8041ac1ced1 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 07:37:50 -0500 Subject: [PATCH 250/259] Convert a loop's string receiver to UTF-16 at once only when the loop can read enough of it A versioned loop over a non-ASCII string passes the range of indexes it reads: a counted loop's start and limit, or a while loop's counter and bound. The runtime converts the string at once when that range has at least one unit per 16 bytes of it, and otherwise counts the loop as one indexed read, so a loop over a line of a long source text no longer keeps a UTF-16 copy of all of it. The publish call is weighted as unlikely, since loops re-entered over one string skip it. --- .../src/backend/llvm/bytes-loop-versions.ts | 48 +++++++-- .../compiler/src/backend/llvm/string-reads.ts | 8 +- .../test/string-unit-loop-emission.test.ts | 101 ++++++++++++++++-- packages/runtime/src/scr_string.c | 22 ++-- packages/runtime/src/scr_string_methods.h | 6 +- packages/runtime/test/test_string.c | 28 ++++- 6 files changed, 182 insertions(+), 31 deletions(-) diff --git a/packages/compiler/src/backend/llvm/bytes-loop-versions.ts b/packages/compiler/src/backend/llvm/bytes-loop-versions.ts index de704ad42..ab941e658 100644 --- a/packages/compiler/src/backend/llvm/bytes-loop-versions.ts +++ b/packages/compiler/src/backend/llvm/bytes-loop-versions.ts @@ -1146,7 +1146,7 @@ export function emitBytesLoopVersionGuard( }; const lengths = receivers.map((receiver, index) => { if (index === unitsIndex) { - const read = emitUnitsLength(host, receiver); + const read = emitUnitsLength(host, receiver, () => emitUnitsSpan(host, version, index)); units.read = read; return read.length; } @@ -1359,15 +1359,49 @@ export function emitBytesLoopVersionGuard( return { units: taken.pointer, length }; } +/** The range of indexes a version's loop reads from its units receiver, as + * two doubles: a counted loop's start and limit, or a while loop's one + * counter and the receiver's bound. Both NaN when the version gives no such + * range. The runtime converts the receiver at once only when the range is + * long enough to pay for it (scr_str_scan_units_for). */ +function emitUnitsSpan( + host: LlvmEmitterContext, + version: BytesLoopVersion, + receiver: number, +): { from: string; to: string } { + // Locals and literals only: they read no string (a `length` of the + // receiver would measure it). Anything else leaves the range unbounded. + const number = (expr: IrExpr): string | null => { + if (expr.kind !== "varRef" && expr.kind !== "numLit") return null; + const value = host.emitExpr(expr); + return value.type.kind === "f64" ? value.name : null; + }; + const unbounded = { from: "0x7FF8000000000000", to: "0x7FF8000000000000" }; + const counted = version.counted; + let from: IrExpr, to: IrExpr; + if (counted) [from, to] = [counted.start, counted.limit]; + else { + const bounded = version.bounded.filter((check) => check.receiver === receiver); + if (version.counters.length !== 1 || bounded.length !== 1 || version.paired !== null) + return unbounded; + [from, to] = [version.counters[0]!.ref, bounded[0]!.bound]; + } + const start = number(from), + limit = number(to); + return start !== null && limit !== null ? { from: start, to: limit } : unbounded; +} + /** The length of a version's units receiver `s` in UTF-16 units: its byte * length when it is ASCII; otherwise, once it is the scan receiver, the * published unit count (0 when the runtime does not hold its units). When * `s` is not already the scan receiver, the runtime converts it to units - * and publishes it (scr_str_scan_units). Also the units pointer, whether - * the loop is to read it, and whether the published receiver is `s`. */ + * and publishes it if the loop's `span` makes that pay + * (scr_str_scan_units_for). Also the units pointer, whether the loop is to + * read it, and whether the published receiver is `s`. */ function emitUnitsLength( host: LlvmEmitterContext, s: string, + span: () => { from: string; to: string }, ): { length: string; pointer: string; taken: string; published: string } { const B = host.B; const sz = host.sizeType; @@ -1381,14 +1415,15 @@ function emitUnitsLength( B.startBlock(publish); // When `s` is already the scan receiver (an earlier loop over it published // it), its units stay published until the runtime clears the scan: skip - // the call. + // the call. Loops re-entered over one string take that path; the weights + // keep the call and its reach out of the loop's code. const held = B.tmp(), holds = B.tmp(); B.line(`${held} = load ptr, ptr @scr_str_scan`); B.line(`${holds} = icmp eq ptr ${held}, ${s}`); const call = B.newLabel("bytes.version.publish.units"), load = B.newLabel("bytes.version.publish.load"); - B.condBr(holds, load, call); + B.condBr(holds, load, call, `, !prof !{!"branch_weights", i32 1000, i32 1}`); B.startBlock(call); host.declare(STRING_SCAN_UNITS_DECL); const receiver = B.tmp(), @@ -1398,7 +1433,8 @@ function emitUnitsLength( countSlot = B.tmp(), count = B.tmp(), published = B.tmp(); - B.line(`call void @scr_str_scan_units(ptr ${s})`); + const { from: first, to: bound } = span(); + B.line(`call void @scr_str_scan_units_for(ptr ${s}, double ${first}, double ${bound})`); B.br(load); B.startBlock(load); B.line(`${receiver} = load ptr, ptr @scr_str_scan`); diff --git a/packages/compiler/src/backend/llvm/string-reads.ts b/packages/compiler/src/backend/llvm/string-reads.ts index 9fd2fa78c..5b7a26c6c 100644 --- a/packages/compiler/src/backend/llvm/string-reads.ts +++ b/packages/compiler/src/backend/llvm/string-reads.ts @@ -25,9 +25,11 @@ import { literalCapWord, literalCapWord32 } from "./string-key-hash.js"; export const STRING_UTF16_LEN_DECL = "declare double @scr_str_utf16_len(ptr)"; export const STRING_CHAR_CODE_AT_DECL = "declare double @scr_str_char_code_at(ptr, double)"; /** Converts a string to UTF-16 units and publishes it as the scan receiver - * (bytes-loop-versions.ts). Like the fallbacks below, it can evict an - * index entry, so it carries no memory restriction. */ -export const STRING_SCAN_UNITS_DECL = "declare void @scr_str_scan_units(ptr)"; + * when the loop about to read it can read enough of it (the other two + * operands are the range of indexes it reads; bytes-loop-versions.ts). + * Like the fallbacks below, it can evict an index entry, so it carries no + * memory restriction. */ +export const STRING_SCAN_UNITS_DECL = "declare void @scr_str_scan_units_for(ptr, double, double)"; /** The runtime fallbacks are cold: both common cases read inline. They * carry no * memory restriction: a fallback can evict an index entry, which resets diff --git a/packages/compiler/test/string-unit-loop-emission.test.ts b/packages/compiler/test/string-unit-loop-emission.test.ts index fa11af007..f522159dc 100644 --- a/packages/compiler/test/string-unit-loop-emission.test.ts +++ b/packages/compiler/test/string-unit-loop-emission.test.ts @@ -51,8 +51,11 @@ console.log(total, spaces("plain ascii text"), spaces("")); const spaces = body("spaces"); // A string that is not ASCII is converted to units and published as the - // scan receiver once, before the loop, and its copy loads units. - expect(spaces).toMatch(/call void @scr_str_scan_units\(ptr %\S+\)/); + // scan receiver once, before the loop, and its copy loads units. The + // loop runs to the length, so it gives the runtime no range (NaN). + expect(spaces).toMatch( + /call void @scr_str_scan_units_for\(ptr %\S+, double 0x7FF8000000000000, double 0x7FF8000000000000\)/, + ); // The copies follow the checked one: bytes, then units. const bytesAt = spaces.search(/^bytes\.version\.fast\d+:/m); const unitsAt = spaces.search(/^bytes\.version\.fast\.units\d+:/m); @@ -127,19 +130,27 @@ console.log(words(text), words(text.replace(/a/g, "ä")), words("plain ascii")); // the runtime to publish `s` only when they differ. const guards = [ ...words.matchAll( - /^bytes\.version\.publish\d+:[^\n]*\n\s+(%\S+) = load ptr, ptr @scr_str_scan\n\s+(%\S+) = icmp eq ptr \1, (%\S+)\n\s+br i1 \2, label %(bytes\.version\.publish\.load\d+), label %(bytes\.version\.publish\.units\d+)\n/gm, + /^bytes\.version\.publish\d+:[^\n]*\n\s+(%\S+) = load ptr, ptr @scr_str_scan\n\s+(%\S+) = icmp eq ptr \1, (%\S+)\n\s+br i1 \2, label %(bytes\.version\.publish\.load\d+), label %(bytes\.version\.publish\.units\d+)[^\n]*\n/gm, ), ]; expect(guards.length).toBeGreaterThanOrEqual(2); for (const [, , , s, load, convert] of guards) { - const block = words.slice(words.search(new RegExp(`^${convert}:`, "m"))); - expect(block).toMatch( - new RegExp( - `^${convert}:[^\\n]*\\n\\s+call void @scr_str_scan_units\\(ptr ${s}\\)\\n\\s+br label %${load}\\n`, - ), + // The block reads the loop's range and makes no other call. + const block = words + .slice(words.search(new RegExp(`^${convert}:`, "m"))) + .match(new RegExp(`^${convert}:[^\\n]*\\n([\\s\\S]*?)\\n\\s+br label %${load}\\n`))!; + expect(block).not.toBeNull(); + const lines = block[1]!.split("\n").map((line) => line.trim()); + expect(lines.at(-1)).toMatch( + new RegExp(`^call void @scr_str_scan_units_for\\(ptr ${s}, double \\S+, double \\S+\\)$`), + ); + expect(lines.slice(0, -1).filter((line) => /\bcall\b(?! double @llvm\.)/.test(line))).toEqual( + [], ); } - const calls = words.match(/call void @scr_str_scan_units\(ptr %\S+\)/g)!; + const calls = words.match( + /call void @scr_str_scan_units_for\(ptr %\S+, double \S+, double \S+\)/g, + )!; expect(calls.length).toBe(guards.length); const exe = join(dir, "main"); @@ -150,3 +161,75 @@ console.log(words(text), words(text.replace(/a/g, "ä")), words("plain ascii")); await rm(dir, { recursive: true, force: true }); } }); + +test("loops over part of a string give the runtime the range of indexes they read", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-unit-reach-")); + try { + const entry = join(dir, "main.ts"); + await writeFile( + entry, + ` +function trim(text: string, start: number, end: number): string { + while (start < end && text.charCodeAt(start) === 32) start++; + return text.substring(start, end); +} +function hasBreak(text: string, pos: number, end: number): boolean { + for (let i = pos; i < end; i++) if (text.charCodeAt(i) === 10) return true; + return false; +} +let text = ""; +for (let k = 0; k < 2000; k++) text += k % 7 === 0 ? " café\\n" : " naïve façade"; +let kept = 0, + breaks = 0; +for (let at = 0; at + 12 < text.length; at += 12) { + kept += trim(text, at, at + 12).length; + if (hasBreak(text, at, at + 12)) breaks++; +} +console.log(kept, breaks); +`, + ); + const outPath = join(dir, "main.ir.json"); + const lowered = await compile(entry, { outDir: dir, outPath, outputKind: "ir" }); + if (!lowered.ok) + throw new Error(lowered.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + const ll = emitLlvmModule(deserializeModule(await readFile(outPath, "utf8"))); + const body = (name: string): string => + ll.match( + new RegExp( + `define internal [^\\n]+ @sc_bf_${name}(?:\\.i32)?\\([^\\n]*\\) #0 \\{[\\s\\S]*?\\n\\}`, + ), + )![0]; + // The publish block passes the loop's range with the receiver: the + // counter and the bound (a while loop), or the start and the limit (a + // counted loop), here the function's parameters. + for (const name of ["trim", "hasBreak"]) { + const block = body(name).match( + /^bytes\.version\.publish\.units\d+:[^\n]*\n([\s\S]*?)\n\s+br label %bytes\.version\.publish\.load\d+\n/m, + )!; + expect(block, name).not.toBeNull(); + const [, lines] = block; + const call = lines!.match( + /call void @scr_str_scan_units_for\(ptr %\S+, double (%\S+), double (%\S+)\)/, + )!; + expect(call, name).not.toBeNull(); + expect(call[1]).not.toBe(call[2]); + } + + const exe = join(dir, "main"); + const built = await compile(entry, { outputKind: "exe", outDir: dir, outPath: exe }); + if (!built.ok) throw new Error(JSON.stringify(built.diagnostics)); + let text = ""; + for (let k = 0; k < 2000; k++) text += k % 7 === 0 ? " café\n" : " naïve façade"; + let kept = 0, + breaks = 0; + for (let at = 0; at + 12 < text.length; at += 12) { + let start = at; + while (start < at + 12 && text.charCodeAt(start) === 32) start++; + kept += at + 12 - start; + if (text.slice(at, at + 12).includes("\n")) breaks++; + } + expect(execFileSync(exe, { encoding: "utf8" })).toBe(`${kept} ${breaks}\n`); + } finally { + await rm(dir, { recursive: true, force: true }); + } +}); diff --git a/packages/runtime/src/scr_string.c b/packages/runtime/src/scr_string.c index dfd0d23f8..1e7802fbb 100644 --- a/packages/runtime/src/scr_string.c +++ b/packages/runtime/src/scr_string.c @@ -1889,14 +1889,24 @@ static bool scr_sidx_units(const ScrStr *s, ScrSidx *e) { return true; } -/* A loop about to read every unit of s (bytes-loop-versions.ts) converts it - * at once instead of after the threshold's reads, and publishes it as the - * scan's receiver. ASCII receivers and receivers past SCR_SIDX_UNITS_MAX - * publish nothing; the caller compares scr_str_scan.s with s. */ -void scr_str_scan_units(ScrStr *s) { +/* A loop about to read s (bytes-loop-versions.ts) between the indexes + * `from` and `to` (NaN: no bound) converts it at once instead of after the + * threshold's reads, and publishes it as the scan's receiver, when that + * range has at least one unit per 16 bytes of s (the threshold's ratio). + * A shorter loop, such as one over a line of a source text, counts as one + * read, so a short loop does not keep all of a long string's units. ASCII + * receivers and receivers past SCR_SIDX_UNITS_MAX publish nothing; the + * caller compares scr_str_scan.s with s. */ +void scr_str_scan_units_for(ScrStr *s, double from, double to) { if (s->ascii || s->len > SCR_SIDX_UNITS_MAX) return; ScrSidx *e = scr_sidx(s); - if (!e->units) e->units = scr_str_units(s, &e->nunits); + if (!e->units) { + if (fabs(to - from) * 16 < (double)s->len) { + (void)scr_sidx_units(s, e); + return; + } + e->units = scr_str_units(s, &e->nunits); + } if (scr_str_scan.s != s) { scr_str_scan.s = s; scr_str_scan.units = e->units; diff --git a/packages/runtime/src/scr_string_methods.h b/packages/runtime/src/scr_string_methods.h index 820b1c9e6..01ccdd8ae 100644 --- a/packages/runtime/src/scr_string_methods.h +++ b/packages/runtime/src/scr_string_methods.h @@ -43,9 +43,11 @@ extern SCR_TL ScrStrScan scr_str_scan; double scr_str_char_code_at(ScrStr *s, double i); /* Converts a non-ASCII s up to the units cap to UTF-16 at once and - * publishes it in scr_str_scan, for a loop about to read all of it. Leaves + * publishes it in scr_str_scan, for a loop about to read it between the + * indexes `from` and `to` (NaN: no bound), when that range has at least + * one unit per 16 bytes. A shorter loop counts as one indexed read. Leaves * scr_str_scan unchanged for any other s. */ -void scr_str_scan_units(ScrStr *s); +void scr_str_scan_units_for(ScrStr *s, double from, double to); /* indexOf(needle, fromIndex): UTF-16 index of the first occurrence at or * after fromIndex (clamped to [0, length]), or -1. Empty needle returns the diff --git a/packages/runtime/test/test_string.c b/packages/runtime/test/test_string.c index 3e14a5958..f41c2de50 100644 --- a/packages/runtime/test/test_string.c +++ b/packages/runtime/test/test_string.c @@ -523,27 +523,45 @@ static void short_string_asserts(void) { } /* A loop's publish converts a non-ASCII receiver before any read, while a - * lone read still walks bytes. ASCII receivers publish nothing. */ + * lone read still walks bytes. ASCII receivers publish nothing. A loop + * that can read fewer than one unit per 16 bytes counts as one read. */ static void scan_units_asserts(void) { ScrStr *s = scr_str_new("a\xC3\xA9\xF0\x9F\x98\x80" "b", 8); /* a é 😀 b */ static const double codes[] = {97, 233, 0xD83D, 0xDE00, 98}; if (scr_str_char_code_at(s, 0) != 97 || scr_str_scan.s == s) failed++; - scr_str_scan_units(s); + scr_str_scan_units_for(s, NAN, NAN); if (scr_str_scan.s != s || scr_str_scan.n != 5) failed++; for (size_t i = 0; i < 5; i++) if (scr_str_scan.n == 5 && (scr_str_scan.units[i] != codes[i] || scr_str_char_code_at(s, (double)i) != codes[i])) failed++; if (!isnan(scr_str_char_code_at(s, 5))) failed++; - scr_str_scan_units(s); /* republishing keeps the same units */ + scr_str_scan_units_for(s, NAN, NAN); /* republishing keeps the same units */ const uint16_t *units = scr_str_scan.units; - scr_str_scan_units(s); + scr_str_scan_units_for(s, 0, 1); if (scr_str_scan.s != s || scr_str_scan.units != units) failed++; ScrStr *ascii = scr_str_new("plain", 5); - scr_str_scan_units(ascii); + scr_str_scan_units_for(ascii, NAN, NAN); if (scr_str_scan.s != s) failed++; scr_str_release(ascii); scr_str_release(s); if (scr_str_scan.s != NULL) failed++; + /* 200 units in 400 bytes: a loop over 25 indexes converts at once. */ + char text[400]; + for (size_t i = 0; i < sizeof text; i += 2) memcpy(text + i, "\xC3\xA9", 2); + ScrStr *wide = scr_str_new(text, sizeof text); + scr_str_scan_units_for(wide, 175, 200); + if (scr_str_scan.s != wide || scr_str_scan.n != 200 || scr_str_scan.units[199] != 233) failed++; + scr_str_release(wide); + /* A loop over 24 does not; each such loop counts as one read, so the + * 32nd converts (32 reads, one per 12.5 bytes). */ + ScrStr *line = scr_str_new(text, sizeof text); + scr_str_scan_units_for(line, 24, 0); + if (scr_str_scan.s == line) failed++; + for (int i = 1; i < 31; i++) scr_str_scan_units_for(line, i, i + 1); + if (scr_str_scan.s == line) failed++; + scr_str_scan_units_for(line, 31, 32); + if (scr_str_scan.s != line || scr_str_scan.n != 200) failed++; + scr_str_release(line); total++; } #ifdef SCR_SIDX_TEST From 390b404251c2894582740f1373937eb9d7d659bc Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 07:46:24 -0500 Subject: [PATCH 251/259] Keep a union loop binding in the debug-variables fixture The fixture's loop iterated `[6, 7] as (number | undefined)[]` so that its binding kept the union layout the LLDB check reads through `item->tag` and `item->slot.arm0`. Since (T | undefined)[] stores T elements, an array that never holds undefined gives a `number` binding, and the check failed with "item is not a pointer". The loop now iterates `[6, 7, undefined]`, whose binding needs the union, and the check also reads the undefined arm's tag. --- packages/compiler/test/debug-variables.test.ts | 3 +++ tests/corpus/3068-debug-variables/main.ts | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/compiler/test/debug-variables.test.ts b/packages/compiler/test/debug-variables.test.ts index ea92cc1d3..946f0f5d1 100644 --- a/packages/compiler/test/debug-variables.test.ts +++ b/packages/compiler/test/debug-variables.test.ts @@ -63,6 +63,8 @@ test.runIf(process.platform === "darwin")( "continue", "frame variable item->tag item->slot.arm0", "continue", + "frame variable item->tag", + "continue", "frame variable hoisted", "continue", "frame variable moduleValue", @@ -91,6 +93,7 @@ test.runIf(process.platform === "darwin")( "item->tag = f64", "item->slot.arm0 = 6", "item->slot.arm0 = 7", + "item->tag = undefined", "hoisted = 13", ]) { expect(debug.stdout).toContain(value); diff --git a/tests/corpus/3068-debug-variables/main.ts b/tests/corpus/3068-debug-variables/main.ts index d9399b49d..2e7cef4d6 100644 --- a/tests/corpus/3068-debug-variables/main.ts +++ b/tests/corpus/3068-debug-variables/main.ts @@ -21,7 +21,7 @@ function inspect(input: number, enabled: boolean, fallback = 9): void { for (let i = 0; i < bytes.length; i++) { console.log("loop", i, bytes[i]); // debug: loop } - for (const item of [6, 7] as (number | undefined)[]) { + for (const item of [6, 7, undefined]) { console.log("item"); // debug: item console.log(item); } From 2823840134976580d129093f6f95cbf1a534f50f Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 07:49:06 -0500 Subject: [PATCH 252/259] Miss non-object receivers early in the property probes and inline the entry check Since the probes began caching absent properties (#2186), an untyped property read that reaches the load or get probe costs more than before: - Receivers that are not ordinary objects, such as class instances, have no shape and always miss, but they set up the probe's frame first. The exported probes now return the miss for them before calling the probe body, which stays out of line. - Each matching entry was answered through an out-of-line call (scr_js_entry_answer). It is inlined into the probe again. dynamic-properties executed 3.1% more instructions than before #2186; it now executes 0.4% fewer. --- packages/runtime/src/scr_js_object.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/runtime/src/scr_js_object.c b/packages/runtime/src/scr_js_object.c index e97651557..e3d0b3a54 100644 --- a/packages/runtime/src/scr_js_object.c +++ b/packages/runtime/src/scr_js_object.c @@ -308,13 +308,10 @@ static bool scr_js_absent_hit(const ScrDyn *receiver, const ScrJsIcEntry *entry) walked->v.obj.shape == entry->holder_shape && walked->prototype == NULL; } -/* A load site's probe. With `absent`, a read of a key that the receiver and - * its chain of plain shaped objects (ending in the default prototype) lack - * answers undefined and caches that answer. Method reads leave absent - * methods to the slow path, which names the missing function. */ /* The answer of a matching entry for `receiver`, or NULL when the entry no * longer holds. */ -static ScrDyn *scr_js_entry_answer(ScrDyn *receiver, const ScrJsIcEntry *entry) { +static inline __attribute__((always_inline)) ScrDyn *scr_js_entry_answer(ScrDyn *receiver, + const ScrJsIcEntry *entry) { if (entry->target == &scr_js_absent) return scr_js_absent_hit(receiver, entry) ? scr_dyn_retain(scr_dyn_undefined()) : NULL; return scr_js_load_hit(receiver, entry); @@ -345,7 +342,8 @@ static void scr_js_load_fill(ScrJsIc *ic, uint32_t stale, ScrJsSharedLoad *share * its chain of plain shaped objects (ending in the default prototype) lack * answers undefined and caches that answer. Method reads leave absent * methods to the slow path, which names the missing function. */ -static ScrDyn *scr_js_probe_load(ScrDyn *receiver, const ScrStr *key, ScrJsIc *ic, bool absent) { +static __attribute__((noinline)) ScrDyn *scr_js_probe_load(ScrDyn *receiver, const ScrStr *key, + ScrJsIc *ic, bool absent) { const ScrJsShape *shape = scr_js_shape_of(receiver); if (!shape) return NULL; uint32_t stale = UINT32_MAX; @@ -397,11 +395,15 @@ static ScrDyn *scr_js_probe_load(ScrDyn *receiver, const ScrStr *key, ScrJsIc *i return scr_dyn_retain(found->value); } +/* Receivers other than ordinary objects have no shape: they miss before + * the probe sets up its frame. */ ScrDyn *scr_js_load_probe(ScrDyn *receiver, const ScrStr *key, ScrJsIc *ic) { + if (receiver->kind != SCR_DYN_OBJ) return NULL; return scr_js_probe_load(receiver, key, ic, false); } ScrDyn *scr_js_get_probe(ScrDyn *receiver, const ScrStr *key, ScrJsIc *ic) { + if (receiver->kind != SCR_DYN_OBJ) return NULL; return scr_js_probe_load(receiver, key, ic, true); } From b28af56ba87803d8ec352d709a9649803df3c9d1 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 07:53:02 -0500 Subject: [PATCH 253/259] Skip the weak-key table when freeing objects that were never keys Once a program creates a weak collection, every object freed afterwards called into the weak-key table to remove entries keyed by it, although almost none are keys: zod's validation freed 16.6 million objects against 23 keys. A per-thread bit filter indexed by the object's address now marks every address that entered the table (cleared when the table empties), and the free paths test it inline, so an object whose bit is clear makes no call. --- .../corpus/weak-keys-freed-reused.mjs.json | 6 ++++ packages/runtime/src/scr_json.c | 19 +++++++++-- tests/corpus/weak-keys-freed-reused.mjs | 32 +++++++++++++++++++ .../weak-keys-freed-reused.mjs.json | 1 + 4 files changed, 56 insertions(+), 2 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/weak-keys-freed-reused.mjs.json create mode 100644 tests/corpus/weak-keys-freed-reused.mjs create mode 100644 tests/harness/corpus-costs/weak-keys-freed-reused.mjs.json diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/weak-keys-freed-reused.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/weak-keys-freed-reused.mjs.json new file mode 100644 index 000000000..ab4ca8bda --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/weak-keys-freed-reused.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/weak-keys-freed-reused.mjs" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_json.c b/packages/runtime/src/scr_json.c index 43b107ae3..cd9eeecde 100644 --- a/packages/runtime/src/scr_json.c +++ b/packages/runtime/src/scr_json.c @@ -1165,8 +1165,20 @@ static bool scr_dyn_to_primitive_result_is_object(const ScrDyn *d); * are never the native records the kept-source table is keyed by. */ static SCR_TL bool scr_weak_observing; static void scr_weak_disposed(void *key); +/* One bit per key address, set when a key enters the weak-key table: a + * disposed object whose bit is clear was never a key, so its disposal makes + * no call. Bits are cleared when the table empties. */ +#define SCR_WEAK_KEY_FILTER_BITS ((size_t)1 << 16) +static SCR_TL uint64_t scr_weak_key_filter[SCR_WEAK_KEY_FILTER_BITS / 64]; +static inline size_t scr_weak_key_filter_bit(const void *key) { + return ((uintptr_t)key >> 4) & (SCR_WEAK_KEY_FILTER_BITS - 1); +} +static inline bool scr_weak_maybe_key(const void *key) { + size_t bit = scr_weak_key_filter_bit(key); + return scr_weak_observing && (scr_weak_key_filter[bit >> 6] & (UINT64_C(1) << (bit & 63))); +} static inline void scr_dyn_weak_dispose(ScrDyn *d) { - if (scr_weak_observing) scr_weak_disposed(d); + if (scr_weak_maybe_key(d)) scr_weak_disposed(d); } /* A disposed node's child: most getters, setters, prototypes and symbol @@ -3479,7 +3491,7 @@ static void scr_record_source_disposed(void *rec) { /* The single native dispose hook serves weak collections and the table * above; each observer runs only while it has entries to forget. */ static void scr_dispose_observers(void *object) { - if (scr_weak_observing) scr_weak_disposed(object); + if (scr_weak_maybe_key(object)) scr_weak_disposed(object); if (scr_record_source_count) scr_record_source_disposed(object); } @@ -17413,6 +17425,8 @@ static ScrWeakKeySlot *scr_weak_key_slot_put(void *key) { scr_weak_keys[j].key = key; scr_weak_keys[j].head = NULL; scr_weak_keys_used++; + size_t bit = scr_weak_key_filter_bit(key); + scr_weak_key_filter[bit >> 6] |= UINT64_C(1) << (bit & 63); } return &scr_weak_keys[j]; } @@ -17422,6 +17436,7 @@ static void scr_weak_key_slot_delete(ScrWeakKeySlot *slot) { if (--scr_weak_keys_used == 0) { free(scr_weak_keys); scr_weak_keys = NULL; + memset(scr_weak_key_filter, 0, sizeof scr_weak_key_filter); return; } for (size_t k = i;;) { diff --git a/tests/corpus/weak-keys-freed-reused.mjs b/tests/corpus/weak-keys-freed-reused.mjs new file mode 100644 index 000000000..b24823526 --- /dev/null +++ b/tests/corpus/weak-keys-freed-reused.mjs @@ -0,0 +1,32 @@ +// Weak collection keys that become unreachable leave the collection, and +// new objects allocated afterwards (which can reuse the freed storage) are +// not found in it: plain objects, arrays, class instances and functions, +// alongside many objects that were never keys. +class Point { + constructor(x) { + this.x = x; + } +} +const map = new WeakMap(); +const set = new WeakSet(); +const kept = []; +function fill(round) { + for (let i = 0; i < 200; i++) { + const key = i % 4 === 0 ? { i } : i % 4 === 1 ? [i] : i % 4 === 2 ? new Point(i) : () => i; + map.set(key, round * 1000 + i); + set.add(key); + if (i % 50 === 0) kept.push(key); + } +} +let stale = 0; +let found = 0; +for (let round = 0; round < 20; round++) { + fill(round); + // Objects that were never keys, freed and reallocated in between. + for (let i = 0; i < 500; i++) { + const other = i % 2 ? { other: i } : new Point(-i); + if (map.has(other) || set.has(other)) stale++; + } +} +for (const key of kept) if (map.has(key) && set.has(key)) found++; +console.log(stale, found, kept.length, map.get(kept[0]), map.get(kept[kept.length - 1])); diff --git a/tests/harness/corpus-costs/weak-keys-freed-reused.mjs.json b/tests/harness/corpus-costs/weak-keys-freed-reused.mjs.json new file mode 100644 index 000000000..738211b5e --- /dev/null +++ b/tests/harness/corpus-costs/weak-keys-freed-reused.mjs.json @@ -0,0 +1 @@ +{ "plain": 5167, "san": 10508 } From b1a68147966691e22246422c80ef03d6e0d533cf Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 08:06:24 -0500 Subject: [PATCH 254/259] Prove typed-array loop bounds in worker programs when a view has shared storage A typed-array loop version in a worker program tested its bounds and its views' ownership together: every view had to have no shared storage. A loop over views of a SharedArrayBuffer always failed that guard and ran the checked copy, testing every element's index. The guard now tests the bounds first and the ownership after. When the bounds hold and every view is unshared, the loop runs the owned copy as before. When a view is shared, it runs a new third copy whose accesses skip their bounds checks and keep the shared-or-local path, without alias scopes. Versions with a UTF-16 units copy, and programs without workers, are unchanged. Corpus 8350 runs such loops over shared, unshared and mixed views, to counts within and past the views and over subarrays, with a worker writing through shared views. The emission test checks the split guard and the shared copy's accesses. --- .../backend/llvm/bytes-loop-versions.test.ts | 10 ++- .../src/backend/llvm/bytes-loop-versions.ts | 38 +++++++- .../src/backend/llvm/emit-statements.ts | 20 ++++- .../8350-worker-shared-loop-bounds.ts.json | 6 ++ ...orker-shared-loop-version-emission.test.ts | 74 ++++++++++++++++ .../corpus/8350-worker-shared-loop-bounds.ts | 86 +++++++++++++++++++ 6 files changed, 227 insertions(+), 7 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8350-worker-shared-loop-bounds.ts.json create mode 100644 packages/compiler/test/worker-shared-loop-version-emission.test.ts create mode 100644 tests/corpus/8350-worker-shared-loop-bounds.ts diff --git a/packages/compiler/src/backend/llvm/bytes-loop-versions.test.ts b/packages/compiler/src/backend/llvm/bytes-loop-versions.test.ts index 096712c97..0fa8fea34 100644 --- a/packages/compiler/src/backend/llvm/bytes-loop-versions.test.ts +++ b/packages/compiler/src/backend/llvm/bytes-loop-versions.test.ts @@ -317,13 +317,19 @@ test("worker programs test each receiver's shared storage once in the guard", () const body = /^define internal [^\n]*@sc_bf_kernel[^]*?^}/m.exec(emitLlvmModule(mod))![0]; const guard = body.slice(0, body.search(/^bytes\.version\.(fast|slow)\d+:$/m)); expect(guard.match(/icmp eq ptr %\S+, null/g)).toHaveLength(2); - const fast = /^bytes\.version\.fast\d+:$[^]*?^bytes\.version\.done\d+:$/m.exec(body)![0]; + const fast = /^bytes\.version\.fast\d+:$[^]*?^bytes\.version\.fast\.shared\d+:$/m.exec(body)![0]; expect(fast).not.toContain("bytes.shared"); expect(fast).not.toMatch(/(load|store) atomic double/); - // The checked copy keeps the shared-memory path for each access. + // The checked copy keeps the shared-memory path for each access, and so + // does the copy for shared views whose bounds hold. const slow = body.slice(body.search(/^bytes\.version\.slow\d+:$/m), body.indexOf(fast)); expect(slow).toContain("load atomic double"); expect(slow).toContain("store atomic double"); + const shared = /^bytes\.version\.fast\.shared\d+:$[^]*?^bytes\.version\.done\d+:$/m.exec( + body, + )![0]; + expect(shared).toContain("load atomic double"); + expect(shared).toContain("store atomic double"); }); test("index temps of a version's counter are integers in the fast copy", () => { diff --git a/packages/compiler/src/backend/llvm/bytes-loop-versions.ts b/packages/compiler/src/backend/llvm/bytes-loop-versions.ts index de704ad42..472934f72 100644 --- a/packages/compiler/src/backend/llvm/bytes-loop-versions.ts +++ b/packages/compiler/src/backend/llvm/bytes-loop-versions.ts @@ -20,6 +20,7 @@ import { } from "./counted-loops.js"; import { emitBytesData, emitBytesHeaderLength, emitBytesSharedStorage } from "./expr-bytes.js"; import { f64Lit } from "./common.js"; +import { InternalCompilerError } from "../../errors.js"; import { emitStringAsciiFlag, emitStringByteLength, @@ -85,8 +86,15 @@ export interface BytesLoopVersion { /** Root receiver bindings, read once before the loop; `string` marks a * string whose `charCodeAt` and `charAt` reads the version covers. */ receivers: { ref: VarRef; global: boolean; string: boolean }[]; - /** Receivers the guard requires to have no shared storage. */ + /** Receivers the guard requires to have no shared storage for the fast + * copy. */ ownedReceivers: number[]; + /** Worker programs: when the bounds hold but a receiver in + * `ownedReceivers` has shared storage, the loop runs a second fast copy + * instead of the checked one. It skips the bounds checks of `bounds` and + * keeps shared-safe accesses (emitBytesLoopVersionGuard's `sharedFast`). Set + * when the version proves bounds as well as ownership. */ + sharedCopy: boolean; /** The string reads among `bounds`. */ stringReads: ReadonlySet; /** The version's one string receiver, when the loop may also run over @@ -752,6 +760,7 @@ export function matchBytesLoopVersion( owned: ownedNodes, receivers: order.map((index) => receivers[index]!), ownedReceivers: ownedKept.map(([receiver]) => renumber.get(receiver)!), + sharedCopy: ownedKept.length > 0 && bounds.size > 0, stringReads, unitsReceiver, unitLengths: unitLengths ?? new Set(), @@ -1102,6 +1111,10 @@ function findWhileCounterAccesses( * storage, and to `slow` otherwise (including a counted loop whose * integer form is not established, or a module receiver not yet set). * + * With `sharedFast` (a version with `sharedCopy`), the ownership tests are + * separate: when everything else holds but a view has shared storage, the + * guard branches to `sharedFast` instead of `slow`. + * * With `unitsFast`, the version's units receiver may instead be a string * that is not ASCII: the guard has the runtime publish it as the scan * receiver (one read), tests the same accesses against its UTF-16 length, @@ -1115,6 +1128,7 @@ export function emitBytesLoopVersionGuard( fast: string, slow: string, unitsFast?: string, + sharedFast?: string, ): { units: string | null; length: string | null } | null { const B = host.B; const next = (cond: string): void => { @@ -1165,10 +1179,13 @@ export function emitBytesLoopVersionGuard( if (string && index !== unitsIndex) conditions.push(emitStringAsciiFlag(host, receivers[index]!)); }); + // Without `sharedFast`, shared storage sends the loop to the checked copy + // with the other failed tests; with it, only to the shared fast copy. + const ownership: string[] = []; for (const index of version.ownedReceivers) { const owned = B.tmp(); B.line(`${owned} = icmp eq ptr ${emitBytesSharedStorage(host, receivers[index]!)}, null`); - conditions.push(owned); + (sharedFast !== undefined ? ownership : conditions).push(owned); } for (const check of version.fixed) { const ok = B.tmp(); @@ -1351,7 +1368,22 @@ export function emitBytesLoopVersionGuard( const length = version.unitsReceiver !== null ? lengths[version.unitsReceiver]! : null; const taken = units.read; const target = taken ? B.newLabel("bytes.version.units") : fast; - if (valid === "true") B.br(target); + if (sharedFast !== undefined && taken) + throw new InternalCompilerError("llvm emitter bug: a shared fast copy with a units copy"); + if (sharedFast !== undefined && ownership.length > 0) { + // The bounds hold: unshared views take the owned copy. + const split = B.newLabel("bytes.version.owned"); + let owned = ownership[0]!; + for (const cond of ownership.slice(1)) { + const all = B.tmp(); + B.line(`${all} = and i1 ${owned}, ${cond}`); + owned = all; + } + if (valid === "true") B.br(split); + else B.condBr(valid, split, slow); + B.startBlock(split); + B.condBr(owned, target, sharedFast); + } else if (valid === "true") B.br(target); else B.condBr(valid, target, slow); if (!taken) return { units: null, length }; B.startBlock(target); diff --git a/packages/compiler/src/backend/llvm/emit-statements.ts b/packages/compiler/src/backend/llvm/emit-statements.ts index cbdeb0558..dc4e5090c 100644 --- a/packages/compiler/src/backend/llvm/emit-statements.ts +++ b/packages/compiler/src/backend/llvm/emit-statements.ts @@ -2139,7 +2139,9 @@ function declareAliasScopes(emitter: LlEmitter, scopes: readonly string[]): void * fast copy is only emitted when every resume point exists. */ /** A typed-array loop version: the guard, then the checked copy, which * runs whenever the guard fails, and the copy whose accesses the guard - * proves in bounds (or thread-owned). */ + * proves in bounds (or thread-owned). In worker programs a version that + * proves both also has a copy for views with shared storage, in bounds but + * not owned. */ function emitVersionedLoop( emitter: LlEmitter, s: IrStmt & { kind: "for" | "while" }, @@ -2151,7 +2153,11 @@ function emitVersionedLoop( done = B.newLabel("bytes.version.done"); const unitsFast = version.unitsReceiver !== null ? B.newLabel("bytes.version.fast.units") : undefined; - const guard = emitBytesLoopVersionGuard(emitter, version, fast, slow, unitsFast); + const sharedFast = + version.sharedCopy && unitsFast === undefined + ? B.newLabel("bytes.version.fast.shared") + : undefined; + const guard = emitBytesLoopVersionGuard(emitter, version, fast, slow, unitsFast, sharedFast); const units = guard?.units ?? null; const originalBounds = emitter.bytesBounds, originalOwned = emitter.bytesOwned, @@ -2190,6 +2196,16 @@ function emitVersionedLoop( ]); emitter.emitStmt(s); B.br(done); + if (sharedFast !== undefined) { + // The bounds hold and a view has shared storage: the accesses skip + // their bounds checks and stay shared-safe, without alias scopes + // (which worker programs give only thread-owned views). + B.startBlock(sharedFast); + emitter.bytesOwned = originalOwned; + emitter.bytesAliasScopes = originalScopes; + emitter.emitStmt(s); + B.br(done); + } if (unitsFast !== undefined && units !== null) { // The string reads take the receiver's UTF-16 units. B.startBlock(unitsFast); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8350-worker-shared-loop-bounds.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8350-worker-shared-loop-bounds.ts.json new file mode 100644 index 000000000..db4376635 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8350-worker-shared-loop-bounds.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8350-worker-shared-loop-bounds.ts" + ], + "diags": [] +} diff --git a/packages/compiler/test/worker-shared-loop-version-emission.test.ts b/packages/compiler/test/worker-shared-loop-version-emission.test.ts new file mode 100644 index 000000000..7eebcc2e4 --- /dev/null +++ b/packages/compiler/test/worker-shared-loop-version-emission.test.ts @@ -0,0 +1,74 @@ +import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises"; +import { tmpdir } from "node:os"; +import { join } from "node:path"; +import { expect, test } from "vitest"; +import { compile, deserializeModule } from "../src/index.js"; +import { emitLlvmModule } from "../src/backend/llvm/emitter.js"; + +async function emitted(source: string): Promise { + const dir = await mkdtemp(join(tmpdir(), "scriptc-worker-shared-loop-")); + try { + const entry = join(dir, "main.ts"); + const outPath = join(dir, "main.ir.json"); + await writeFile(entry, source); + const result = await compile(entry, { outDir: dir, outPath, outputKind: "ir" }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + return emitLlvmModule(deserializeModule(await readFile(outPath, "utf8"))); + } finally { + await rm(dir, { recursive: true, force: true }); + } +} + +const kernel = ` +function sumTo(view: Float64Array, n: number): number { + let total = 0; + for (let i = 0; i < n; i++) total += view[i]!; + return total; +} +`; + +function body(ll: string, name: string): string { + return new RegExp(`^define internal [^\\n]*@sc_bf_${name}(?:\\.i32)?\\([^]*?^}`, "m").exec( + ll, + )![0]; +} + +/** The instructions of the blocks whose labels start with `prefix`. */ +function blocks(fn: string, prefix: string): string { + return fn + .split(/\n(?=[\w.$-]+:)/) + .filter((block) => block.startsWith(prefix)) + .join("\n"); +} + +test("a worker program's loop over views that may be shared keeps a bounds-proven copy", async () => { + const ll = await emitted(` +import { Worker, isMainThread } from "node:worker_threads"; +${kernel} +if (isMainThread) { + const view = new Float64Array(new SharedArrayBuffer(64)); + console.log(sumTo(view, 8)); + new Worker(new URL(import.meta.url)); +} +`); + const fn = body(ll, "sumTo"); + // The guard tests the bounds first, then whether the view is shared. + expect(fn).toMatch(/^bytes\.version\.owned\d*:/m); + expect(fn).toMatch(/^bytes\.version\.fast\.shared\d*:/m); + // The shared copy reads with no bounds test, and shared-safe: a view + // with shared storage loads atomically. + const shared = blocks(fn, "bytes.version.fast.shared"); + expect(shared).not.toMatch(/icmp (ult|uge|ugt) i64 %\w+, %\w+/); + expect(fn).toMatch(/load atomic double, ptr %\w+ monotonic/); +}); + +test("a program without workers keeps two copies of the loop", async () => { + const ll = await emitted(`${kernel} +console.log(sumTo(new Float64Array(8), 8)); +`); + const fn = body(ll, "sumTo"); + expect(fn).toMatch(/^bytes\.version\.fast\d*:/m); + expect(fn).not.toMatch(/bytes\.version\.fast\.shared/); + expect(fn).not.toMatch(/bytes\.version\.owned/); +}); diff --git a/tests/corpus/8350-worker-shared-loop-bounds.ts b/tests/corpus/8350-worker-shared-loop-bounds.ts new file mode 100644 index 000000000..e5fd1ea9e --- /dev/null +++ b/tests/corpus/8350-worker-shared-loop-bounds.ts @@ -0,0 +1,86 @@ +import { Worker, isMainThread, parentPort, workerData } from "node:worker_threads"; + +// Typed-array loops in a worker program that run to a count passed in, not +// to a view's length, over views of a SharedArrayBuffer, of a thread's own +// buffer, and both in one loop. Counts within the views, past their ends +// (reads give undefined, writes are dropped) and over subarrays at an +// offset. A worker's writes through shared views are visible to the parent. + +interface Job { + shared: SharedArrayBuffer; + n: number; +} + +function rowSums(u: Float64Array, v: Float64Array, n: number, rows: number): void { + for (let i = 0; i < rows; i++) { + let t = 0; + for (let j = 0; j < n; j++) t += u[j]! / (i + j + 1); + v[i] = t; + } +} + +function copyScaled(src: Int32Array, dst: Int32Array, n: number, k: number): number { + let sum = 0; + for (let i = 0; i < n; i++) { + dst[i] = (src[i]! * k) | 0; + sum += dst[i]!; + } + return sum; +} + +function sumTo(view: Float64Array, n: number): number { + let total = 0; + for (let i = 0; i < n; i++) total += view[i]!; + return total; +} + +function fixed(view: Float64Array, count: number): string { + const parts: string[] = []; + for (let i = 0; i < count; i++) parts.push(view[i]!.toFixed(6)); + return parts.join(" "); +} + +function run(label: string, u: Float64Array, v: Float64Array, ints: Int32Array, out: Int32Array, n: number): string { + rowSums(u, v, n, 4); + const scaled = copyScaled(ints, out, n, 3); + return `${label}: rows ${fixed(v, 4)}; scaled ${scaled}; tail ${sumTo(u, n + 3)}`; +} + +function views(buffer: ArrayBufferLike, n: number): { u: Float64Array; v: Float64Array; ints: Int32Array; out: Int32Array } { + const u = new Float64Array(buffer, 0, n); + const v = new Float64Array(buffer, 8 * n, n); + const ints = new Int32Array(buffer, 16 * n, n); + const out = new Int32Array(buffer, 20 * n, n); + for (let i = 0; i < n; i++) { + u[i] = 1 + i * 0.25; + ints[i] = i * 7 - 20; + } + return { u, v, ints, out }; +} + +if (isMainThread) { + const n = 12; + const shared = new SharedArrayBuffer(24 * n); + const own = views(new ArrayBuffer(24 * n), n); + console.log(run("own", own.u, own.v, own.ints, own.out, n)); + const sh = views(shared, n); + console.log(run("shared", sh.u, sh.v, sh.ints, sh.out, n)); + console.log(run("shared, count past the end", sh.u, sh.v, sh.ints, sh.out, n + 5)); + const mixed = new Float64Array(n); + rowSums(sh.u, mixed, n, 4); + console.log("mixed", fixed(mixed, 4)); + console.log("subarray", sumTo(sh.u.subarray(3), n - 3), sumTo(sh.u.subarray(3), n)); + const worker = new Worker(new URL(import.meta.url), { workerData: { shared, n } satisfies Job }); + worker.on("message", (line: string) => { + console.log(line); + console.log("parent sees", sh.out.subarray(0, 5).join(","), sh.v[0]!.toFixed(6)); + }); +} else { + const { shared, n } = workerData as Job; + const u = new Float64Array(shared, 0, n); + const v = new Float64Array(shared, 8 * n, n); + const ints = new Int32Array(shared, 16 * n, n); + const out = new Int32Array(shared, 20 * n, n); + for (let i = 0; i < n; i++) ints[i] = i * 5 + 1; + parentPort!.postMessage(run("worker", u, v, ints, out, n)); +} From c6679d43fbc63840755e9e2e5c0e3a3063537284 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 08:18:46 -0500 Subject: [PATCH 255/259] Add no empty chunk to a byte-mode Readable's buffer push() of an empty Buffer outside object mode put a zero-length entry into the read buffer, and the chunks pushed after it stalled behind it: a 'data' listener saw nothing more and a readline interface never closed. Node's readableAddChunk adds no empty chunk outside object mode; it clears the reading flag and may read more. The runtime now does the same, as it already did for an encoded push that decodes to nothing. --- .../corpus/7516-readable-empty-push.ts.json | 6 ++ packages/runtime/src/scr_stream.c | 8 ++- tests/corpus/7516-readable-empty-push.ts | 69 +++++++++++++++++++ .../7516-readable-empty-push.ts.json | 1 + 4 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7516-readable-empty-push.ts.json create mode 100644 tests/corpus/7516-readable-empty-push.ts create mode 100644 tests/harness/corpus-costs/7516-readable-empty-push.ts.json diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7516-readable-empty-push.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7516-readable-empty-push.ts.json new file mode 100644 index 000000000..9388c4f9a --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/7516-readable-empty-push.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/7516-readable-empty-push.ts" + ], + "diags": [] +} diff --git a/packages/runtime/src/scr_stream.c b/packages/runtime/src/scr_stream.c index 406d91599..201d6e34b 100644 --- a/packages/runtime/src/scr_stream.c +++ b/packages/runtime/src/scr_stream.c @@ -954,8 +954,14 @@ static bool scr_stream_add_chunk(ScrStream *s, ScrBytes *chunk, bool front) { } entry = dec; /* owned */ } else { - entry = scr_bytes_retain(chunk); entry_len = chunk->len; + if (entry_len == 0) { + /* Node's readableAddChunk adds no empty chunk outside object mode: + * it clears reading and may read more */ + if (!front) scr_stream_maybe_read_more(s); + return !st->r.ended && (st->r.length < st->r.hwm || st->r.length == 0); + } + entry = scr_bytes_retain(chunk); } if (entry_len > 0 && st->r.flowing == 1 && st->r.length == 0 && !st->r.in_read_sync && !front && diff --git a/tests/corpus/7516-readable-empty-push.ts b/tests/corpus/7516-readable-empty-push.ts new file mode 100644 index 000000000..27d88e3ed --- /dev/null +++ b/tests/corpus/7516-readable-empty-push.ts @@ -0,0 +1,69 @@ +// readable.push() of an empty Buffer outside object mode adds nothing, as +// in Node: the chunks pushed after it still reach 'data' listeners, +// readline and read(), and push(null) still ends the stream. In object +// mode an empty Buffer is a value like any other. +import { createInterface } from "node:readline"; +import { Readable } from "node:stream"; + +function lines(chunks: string[]): Promise { + return new Promise((resolve) => { + const src = new Readable({ read() {} }); + const rl = createInterface({ input: src, crlfDelay: Infinity }); + rl.on("line", (line: string) => console.log("line", JSON.stringify(line))); + rl.on("close", () => { + console.log("readline closed"); + resolve(); + }); + for (const chunk of chunks) src.push(Buffer.from(chunk, "utf8")); + src.push(null); + }); +} + +function data(): Promise { + return new Promise((resolve) => { + const src = new Readable({ read() {} }); + src.on("data", (chunk: Buffer) => console.log("data", JSON.stringify(String(chunk)))); + src.on("end", () => { + console.log("data end"); + resolve(); + }); + console.log("push a", src.push(Buffer.from("a"))); + console.log("push empty", src.push(Buffer.alloc(0))); + console.log("push b", src.push(Buffer.from("b"))); + src.push(null); + }); +} + +function paused(): void { + const src = new Readable({ read() {} }); + src.push(Buffer.from("x")); + src.push(Buffer.alloc(0)); + src.push(Buffer.from("y")); + console.log("readableLength", src.readableLength); + console.log("read", JSON.stringify(String(src.read()))); +} + +function objectMode(): Promise { + return new Promise((resolve) => { + const src = new Readable({ objectMode: true, read() {} }); + src.on("data", (chunk: Buffer) => console.log("object chunk length", chunk.length)); + src.on("end", () => { + console.log("object end"); + resolve(); + }); + src.push(Buffer.alloc(0)); + src.push(Buffer.from("z")); + src.push(null); + }); +} + +async function main(): Promise { + await lines(["a\nb", "", "c\n"]); + await lines(["", "", "only\n"]); + await data(); + paused(); + await objectMode(); + console.log("done"); +} + +main(); diff --git a/tests/harness/corpus-costs/7516-readable-empty-push.ts.json b/tests/harness/corpus-costs/7516-readable-empty-push.ts.json new file mode 100644 index 000000000..1cfe56769 --- /dev/null +++ b/tests/harness/corpus-costs/7516-readable-empty-push.ts.json @@ -0,0 +1 @@ +{ "plain": 2200, "san": 3200 } From 9b2b97033aae21cf659623d605442f8f988eaa85 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 08:24:12 -0500 Subject: [PATCH 256/259] Add object literal members through the store caches in untyped code Untyped functions built each member of an object literal with scr_dyn_key_set: a lookup of the key in the new object, a walk of its empty prototype chain, a second lookup before the append, and a hash of the key to share its bytes. The first cached read of the object then computed its shape from its keys, hashing each key again. A member whose key is a constant string other than __proto__ now owns a store cache site and calls scr_js_store_probe, which appends the member through the cached shape transition, takes the key bytes from the shape, and leaves the object shaped. Members the probe does not take (Error field names, members past the 64th, a site's first object of a shape) keep scr_dyn_key_set, as do computed keys and literals in module initializers. --- .../compiler/src/backend/llvm/expr-dynamic.ts | 8 ++- packages/compiler/src/backend/llvm/js-ic.ts | 23 +++++++ packages/compiler/src/ir/js-ic.test.ts | 17 +++++ packages/compiler/src/ir/js-ic.ts | 17 ++++- packages/compiler/test/js-ic-emission.test.ts | 31 +++++++++ .../corpus/object-literal-members.mjs.json | 6 ++ tests/corpus/object-literal-members.mjs | 67 +++++++++++++++++++ .../object-literal-members.mjs.json | 1 + tests/harness/library-mode.test.ts | 4 +- tests/library-mode/js-ic-sessions/work.mjs | 9 ++- 10 files changed, 175 insertions(+), 8 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/object-literal-members.mjs.json create mode 100644 tests/corpus/object-literal-members.mjs create mode 100644 tests/harness/corpus-costs/object-literal-members.mjs.json diff --git a/packages/compiler/src/backend/llvm/expr-dynamic.ts b/packages/compiler/src/backend/llvm/expr-dynamic.ts index 849715ab0..55bbb828b 100644 --- a/packages/compiler/src/backend/llvm/expr-dynamic.ts +++ b/packages/compiler/src/backend/llvm/expr-dynamic.ts @@ -31,7 +31,8 @@ import { elemAccess, vAdapters } from "./shapes.js"; import { LlvmUnsupportedError } from "./unsupported.js"; import type { LlvmEmitterContext, ExprOf, LlValue } from "./expr-context.js"; import { emitUnionWiden } from "./expr-records.js"; -import { emitJsIcMethod, jsIcMethods } from "./js-ic.js"; +import { emitJsIcLiteralMember, emitJsIcMethod, jsIcMethods } from "./js-ic.js"; +import { jsIcLiteralKey } from "../../ir/js-ic.js"; import { DYN_BUFFER_METHODS } from "../../ir/runtime-features.js"; export function emitDynamicExpr( @@ -316,9 +317,14 @@ export function emitDynamicExpr( const obj = B.tmp(); B.line(`${obj} = call ptr @scr_dyn_new_obj()`); const out = host.own({ name: obj, type: e.type }); + const cached = jsIcMethods(host); for (const f of e.fields ?? []) { const k = emitBorrowedInput(host, f.key); const v = emitBorrowedInput(host, f.value); + if (cached && jsIcLiteralKey(f.key) !== null) { + emitJsIcLiteralMember(host, obj, k.name, v.name); + continue; + } B.line( `call void @${f.key.type.kind === "dyn" ? "scr_dyn_key_set_computed" : "scr_dyn_key_set"}(ptr ${obj}, ptr ${k.name}, ptr ${v.name})`, ); diff --git a/packages/compiler/src/backend/llvm/js-ic.ts b/packages/compiler/src/backend/llvm/js-ic.ts index b69d3199d..11b894a60 100644 --- a/packages/compiler/src/backend/llvm/js-ic.ts +++ b/packages/compiler/src/backend/llvm/js-ic.ts @@ -14,6 +14,8 @@ * keyed dense array element at an integral number key: inline; * otherwise scr_js_keyed_probe (string keys of ordinary objects) * method dynInvoke's method read: scr_js_load_probe + * literal an object literal's constant-key member: scr_js_store_probe, + * else scr_dyn_key_set * * A probe that cannot answer from plain data leaves everything untouched, * and the site calls its helper (or the generic runtime entry), which @@ -838,6 +840,27 @@ function emitKeyed(host: Host, e: ExprOf<"call">, callee: IrFunction): LlValue { return host.own({ name: out, type: e.type }); } +/** One member of an object literal (ir/js-ic.ts jsIcLiteralKey) added to + * the fresh object `obj` through the site's store cache, else with + * scr_dyn_key_set. The key and value are borrowed. */ +export function emitJsIcLiteralMember(host: Host, obj: string, key: string, value: string): void { + const B = host.B; + const ic = host.jsIcSite(); + host.declare(`declare zeroext i1 @scr_js_store_probe(ptr, ptr, ptr, ptr)`); + const done = B.tmp(); + B.line( + `${done} = call zeroext i1 @scr_js_store_probe(ptr ${obj}, ptr ${key}, ptr ${value}, ptr ${ic})`, + ); + const slow = B.newLabel("icl.slow"); + const join = B.newLabel("icl.j"); + B.condBr(done, join, slow); + B.startBlock(slow); + B.line(`call void @scr_dyn_key_set(ptr ${obj}, ptr ${key}, ptr ${value})`); + host.emitPendingCheck(); + B.br(join); + B.startBlock(join); +} + /** dynInvoke's method read on an ordinary object through the site's * cache, else scr_dyn_prepare_method. Returns the owned method (or NULL, * which scr_dyn_invoke_prepared_id answers with the full dispatch). */ diff --git a/packages/compiler/src/ir/js-ic.test.ts b/packages/compiler/src/ir/js-ic.test.ts index f5391b83e..35de18085 100644 --- a/packages/compiler/src/ir/js-ic.test.ts +++ b/packages/compiler/src/ir/js-ic.test.ts @@ -311,6 +311,23 @@ test("a function holds a site when it calls a classified helper or dispatches a expect(hasJsIcSite({ ...caller, name: "%init.0" }, sites)).toBe(true); }); +test("a function holds a site when an object literal has a constant-key member", () => { + const sites = sitesOf(); + const literal = (key: IrExpr): IrFunction => + helper( + "f", + ["o"], + [ret({ kind: "dynObjLit", fields: [{ key, value: ref("o") }], type: DYN, loc })], + ); + expect(hasJsIcSite(literal(str("x")), sites)).toBe(true); + // `__proto__` sets the prototype, and a computed key has no constant + // name: both keep the generic member store. + expect(hasJsIcSite(literal(str("__proto__")), sites)).toBe(false); + expect(hasJsIcSite(literal(ref("k")), sites)).toBe(false); + // Module initializers build their literals once. + expect(hasJsIcSite({ ...literal(str("x")), name: "%init.0" }, sites)).toBe(false); +}); + test("bag helpers that exit early for values no class branch matches are still the receiver", () => { /** `if (!(v)) return `: the class tables' early exit. */ const exit = (test: "classCapsule" | "funcKind", value: IrExpr, negated = true): IrStmt => ({ diff --git a/packages/compiler/src/ir/js-ic.ts b/packages/compiler/src/ir/js-ic.ts index 48019636a..5a483c585 100644 --- a/packages/compiler/src/ir/js-ic.ts +++ b/packages/compiler/src/ir/js-ic.ts @@ -296,20 +296,33 @@ function unwrapFromDyn(e: IrExpr | null | undefined): IrExpr | null { return e; } -/** Whether a function holds a cache site: a call to a classified helper or - * a method dispatch. */ +/** Whether a function holds a cache site: a call to a classified helper, + * a method dispatch, or an object literal member with a constant key. */ export function hasJsIcSite(fn: IrFunction, sites: JsIcSites): boolean { const methods = jsIcMethodSites(fn.name); return !everyStmtList(fn.body, { expr: (e) => !( (methods && e.kind === "dynInvoke") || + (methods && + e.kind === "dynObjLit" && + (e.fields ?? []).some((f) => jsIcLiteralKey(f.key) !== null)) || (e.kind === "call" && sites.site(e.callee) !== null) ), stmt: () => true, }); } +/** The key of an object literal member that its site adds through the + * store cache: a constant string other than `__proto__`, or null. The + * literal starts as an empty object with the default prototype, so each + * such member appends one data property, and the site caches the shape + * transition and shares the key bytes the shape holds. Module + * initializers have no literal sites (jsIcMethodSites). */ +export function jsIcLiteralKey(key: IrExpr): string | null { + return key.kind === "strLit" && key.value !== "__proto__" ? key.value : null; +} + /** Whether method dispatch in a function goes through caches. Module * initializers (`%init.N`) run once, and the methods they call at top level * are overwhelmingly registrations on native handles (`worker.on(...)`, diff --git a/packages/compiler/test/js-ic-emission.test.ts b/packages/compiler/test/js-ic-emission.test.ts index 15e8e92bc..79342e99d 100644 --- a/packages/compiler/test/js-ic-emission.test.ts +++ b/packages/compiler/test/js-ic-emission.test.ts @@ -64,6 +64,37 @@ console.log(read(o), at(dyn([5, 6]), 1), call(o), o.n); } }); +test("object literal members with constant keys add through store caches", async () => { + const dir = await mkdtemp(join(tmpdir(), "scriptc-js-ic-literal-")); + try { + const entry = join(dir, "main.js"); + const outPath = join(dir, "main.ir.json"); + await writeFile( + entry, + ` +function make(v, k) { return { a: v, b: 2, [k]: 3 }; } +var top = { t: 1 }; +console.log(JSON.stringify(make(1, "c")), top.t); +`, + ); + const result = await compile(entry, { outDir: dir, outPath, outputKind: "ir" }); + if (!result.ok) + throw new Error(result.diagnostics.map((d) => `${d.code}: ${d.message}`).join("\n")); + const mod = deserializeModule(await readFile(outPath, "utf8")); + expect(moduleUsesDynTier(mod)).toBe(true); + const llvm = emitLlvmModule(mod); + const make = body(llvm, "make"); + // Each constant-key member tries its site's store cache first and + // falls back to the generic member store; the computed key keeps the + // generic store only. + expect(make.match(/@scr_js_store_probe\(/g)).toHaveLength(2); + expect(make.match(/@scr_dyn_key_set\(/g)).toHaveLength(2); + expect(make).toContain("@scr_dyn_key_set_computed("); + } finally { + await rm(dir, { recursive: true, force: true }); + } +}); + test("property sites keep their caches in programs that declare classes and subclasses", async () => { const dir = await mkdtemp(join(tmpdir(), "scriptc-js-ic-class-")); try { diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/object-literal-members.mjs.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/object-literal-members.mjs.json new file mode 100644 index 000000000..f1f9017ac --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/object-literal-members.mjs.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/object-literal-members.mjs" + ], + "diags": [] +} diff --git a/tests/corpus/object-literal-members.mjs b/tests/corpus/object-literal-members.mjs new file mode 100644 index 000000000..4bd211435 --- /dev/null +++ b/tests/corpus/object-literal-members.mjs @@ -0,0 +1,67 @@ +// Object literals built in untyped functions, many times through the same +// sites: key order (integer-like keys first), members named +// like Object.prototype members and Error fields, __proto__ members, wide +// literals, literals that differ only in a later member, and objects +// changed after they are built. +function point(x, y) { + return { x, y, label: "p" + x }; +} +function ordered(i) { + return { b: i, 2: "two", a: i + 1, 1: "one", "01": "zero-one" }; +} +function named(i) { + return { constructor: i, toString: "s" + i, message: "m" + i, name: "n" + i, code: i, stack: "st" }; +} +function withProto(proto, i) { + if (proto === null) return { __proto__: null, own: i }; + const o = { own: i }; + Object.setPrototypeOf(o, proto); + return o; +} +function wide(i) { + return { + k0: i, k1: i, k2: i, k3: i, k4: i, k5: i, k6: i, k7: i, k8: i, k9: i, + k10: i, k11: i, k12: i, k13: i, k14: i, k15: i, k16: i, k17: i, k18: i, k19: i, + k20: i, k21: i, k22: i, k23: i, k24: i, k25: i, k26: i, k27: i, k28: i, k29: i, + k30: i, k31: i, k32: i, k33: i, k34: i, k35: i, k36: i, k37: i, k38: i, k39: i, + k40: i, k41: i, k42: i, k43: i, k44: i, k45: i, k46: i, k47: i, k48: i, k49: i, + k50: i, k51: i, k52: i, k53: i, k54: i, k55: i, k56: i, k57: i, k58: i, k59: i, + k60: i, k61: i, k62: i, k63: i, k64: i, k65: i, k66: i, k67: i, k68: i, k69: i, + }; +} +function variant(i) { + const head = { kind: "v", n: i }; + return i % 2 ? { ...head, odd: true } : { ...head, even: true, n: -i }; +} + +let sum = 0; +const points = []; +for (let i = 0; i < 2000; i++) { + const p = point(i, i * 2); + sum += p.x + p.y; + if (i % 500 === 0) points.push(p); +} +points[0].z = 9; +delete points[1].label; +console.log(sum, JSON.stringify(points), Object.keys(points[2]).join()); + +const o = [ordered(1), ordered(2)]; +console.log(Object.keys(o[1]).join(), JSON.stringify(o[0]), o[1]["01"], o[1][1]); + +const n = [named(1), named(2)]; +console.log(JSON.stringify(n[1]), typeof n[0].toString, n[1].constructor, n[1] instanceof Error); + +const proto = { greet() { return "hi " + this.own; } }; +const w = [withProto(proto, 1), withProto(proto, 2), withProto(null, 3)]; +console.log(w[1].greet(), Object.getPrototypeOf(w[0]) === proto, Object.getPrototypeOf(w[2]), Object.keys(w[1]).join()); + +let wideSum = 0; +for (let i = 0; i < 50; i++) { + const big = wide(i); + wideSum += big.k0 + big.k69; +} +console.log(wideSum, Object.keys(wide(1)).length, Object.keys(wide(2))[69]); + +const v = []; +for (let i = 0; i < 6; i++) v.push(variant(i)); +console.log(JSON.stringify(v)); diff --git a/tests/harness/corpus-costs/object-literal-members.mjs.json b/tests/harness/corpus-costs/object-literal-members.mjs.json new file mode 100644 index 000000000..882d60088 --- /dev/null +++ b/tests/harness/corpus-costs/object-literal-members.mjs.json @@ -0,0 +1 @@ +{ "plain": 3565, "san": 6266 } diff --git a/tests/harness/library-mode.test.ts b/tests/harness/library-mode.test.ts index 4c1b96b37..4a3d4c390 100644 --- a/tests/harness/library-mode.test.ts +++ b/tests/harness/library-mode.test.ts @@ -386,7 +386,7 @@ globals: undefined fenced const run = runProbe(probe); expect(run.signal).toBeNull(); expect(run.status).toBe(0); - expect(run.stdout).toBe("run: 20000\n".repeat(3)); + expect(run.stdout).toBe("run: 40000\n".repeat(3)); }); /* ── K5/K6/K7: the trap channel ──────────────────────────────────────── */ @@ -614,7 +614,7 @@ survived, sink_calls=1 const run = runProbe(probe); expect(run.signal).toBeNull(); expect(run.status).toBe(0); - expect(run.stdout).toBe("run: 20000\n".repeat(3)); + expect(run.stdout).toBe("run: 40000\n".repeat(3)); }); platformTest("K10: K5/K7 under ASan", async () => { diff --git a/tests/library-mode/js-ic-sessions/work.mjs b/tests/library-mode/js-ic-sessions/work.mjs index 5c1afcd18..e6c4a2fc3 100644 --- a/tests/library-mode/js-ic-sessions/work.mjs +++ b/tests/library-mode/js-ic-sessions/work.mjs @@ -1,6 +1,6 @@ // Dynamic-tier property caches across library sessions: objects built empty -// and filled through untyped stores, read back through untyped loads, and a -// class instance at the same kind of sites. Each session must start with +// and filled through untyped stores or built by object literals, read back +// through untyped loads, and a class instance at the same kind of sites. Each session must start with // empty caches, since the shapes their entries named are freed when the // previous session ends. class Box { @@ -13,6 +13,9 @@ function fill(o, n) { o.b = n + 1; return o; } +function pair(n) { + return { a: n, b: n + 1 }; +} function sum(o) { return o.a + o.b; } @@ -21,6 +24,6 @@ function unbox(b) { } export function runAll() { let total = 0; - for (let i = 0; i < 100; i++) total += sum(fill({}, i)); + for (let i = 0; i < 100; i++) total += sum(fill({}, i)) + sum(pair(i)); return total + unbox(new Box(total)); } From 0488bef1a9ad7959de22df9ab78108e1c499f657 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 09:00:40 -0500 Subject: [PATCH 257/259] Describe RSA-PSS AUTO verification against restricted keys as Node does RSA_PSS_SALTLEN_AUTO recovers the salt length from the signature and does not enforce the key's minimum salt length, as in Node (OpenSSL). The runtime's exemption now says so, and corpus 8178's header, which said the minimum was still enforced, describes what it checks. --- packages/runtime/src/scr_pki.c | 3 +++ tests/corpus/8178-rsa-pss-auto-min-salt.cjs | 6 ++++-- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/runtime/src/scr_pki.c b/packages/runtime/src/scr_pki.c index 9877ac6c9..e41dd79c3 100644 --- a/packages/runtime/src/scr_pki.c +++ b/packages/runtime/src/scr_pki.c @@ -3255,6 +3255,9 @@ static bool sp_pss_key_rules(SpSigKey *key, mbedtls_md_type_t md, size_t hash_le return false; } key->mgf1 = k->pss_mgf1; + /* RSA_PSS_SALTLEN_AUTO (-2) is exempt from the key's minimum, as in + * OpenSSL: verification recovers the salt length from the signature and + * accepts any length (corpus 8178). */ if (!key->salt_given) { key->salt = k->pss_salt; } else if (key->salt != -2 && (key->salt == -1 ? (int)hash_len : key->salt) < k->pss_salt) { diff --git a/tests/corpus/8178-rsa-pss-auto-min-salt.cjs b/tests/corpus/8178-rsa-pss-auto-min-salt.cjs index 97b9d1c05..78e288591 100644 --- a/tests/corpus/8178-rsa-pss-auto-min-salt.cjs +++ b/tests/corpus/8178-rsa-pss-auto-min-salt.cjs @@ -1,6 +1,8 @@ // Verifying with RSA_PSS_SALTLEN_AUTO against an RSA-PSS key whose -// parameters set a minimum salt length still enforces that minimum, as in -// Node: a valid signature with a shorter salt does not verify. The keys use +// parameters set a minimum salt length recovers the salt length from the +// signature and does not enforce that minimum, as in Node: a valid +// signature with a shorter salt verifies. The default salt length (the +// key's minimum) accepts only that length. The keys use // an MGF1 digest equal to the message digest and a different one. The // stricter public key is the generated one with its minimum salt length // raised from 16 to 32 in its DER. From 21e4c3683febd387866bfd20d8cee2ea2ade4420 Mon Sep 17 00:00:00 2001 From: Chris Tate Date: Sun, 25 Oct 2026 09:13:52 -0500 Subject: [PATCH 258/259] Keep the budget in typed-array length loops that assign their array A loop to a typed array's length reads the length again on every iteration, so a body that assigns the array's binding changes the limit for the next iteration. The strip-mined form took the length once per block of 64 iterations, and after the body assigned a shorter array it ran on to the block's end, reading past the new length. The loop to a typed array's length is now strip-mined only when the array is a local of the function that the body never assigns (stableReceiver on the match); others keep the budget and test the length on every iteration. New corpus program: native-worker-length-loop-reassign.ts. --- .../src/backend/llvm/emit-statements.ts | 5 +- packages/compiler/src/ir/integer-loops.ts | 18 +++++- .../test/counted-loop-emission.test.ts | 15 ++++- ...native-worker-length-loop-reassign.ts.json | 6 ++ .../native-worker-length-loop-reassign.ts | 58 +++++++++++++++++++ ...native-worker-length-loop-reassign.ts.json | 1 + 6 files changed, 98 insertions(+), 5 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-length-loop-reassign.ts.json create mode 100644 tests/corpus/native-worker-length-loop-reassign.ts create mode 100644 tests/harness/corpus-costs/native-worker-length-loop-reassign.ts.json diff --git a/packages/compiler/src/backend/llvm/emit-statements.ts b/packages/compiler/src/backend/llvm/emit-statements.ts index 2efe2cf3a..d7fccb2d4 100644 --- a/packages/compiler/src/backend/llvm/emit-statements.ts +++ b/packages/compiler/src/backend/llvm/emit-statements.ts @@ -1216,14 +1216,15 @@ export function emitStmtBody(emitter: LlEmitter, s: IrStmt): void { // length, polls between blocks of WORKER_POLL_BLOCK iterations instead // of counting a budget in its body: the inner loop over a block then // has no exit besides its own bound, which LLVM can vectorize. A typed - // array's length is fixed, so each block can take it as its limit. + // array's length is fixed, so each block can take it as its limit when + // the loop does not assign the array's binding. const stripMined = capturedLets.length === 0 && integerSlot !== null && ((countedLoop !== null && countedLimit !== null && Math.abs(countedLoop.step) * WORKER_POLL_BLOCK <= 2 ** 52) || - (integerLoop !== null && integerArrayLoop === null)) && + (integerLoop !== null && integerArrayLoop === null && integerLoop.stableReceiver)) && emitter.workerLoopPolls(s) && loopAccessesTypedArrays(s); const workerBudget = stripMined ? null : emitter.workerLoopBudget(s); diff --git a/packages/compiler/src/ir/integer-loops.ts b/packages/compiler/src/ir/integer-loops.ts index 7cc49b7a0..ea866a134 100644 --- a/packages/compiler/src/ir/integer-loops.ts +++ b/packages/compiler/src/ir/integer-loops.ts @@ -12,6 +12,9 @@ import { preservesArrayLength } from "./array-length-stability.js"; export interface IntegerBytesForLoop { localId: string; limitReceiver: IrExpr; + /** The receiver is a local of the function that the body never assigns + * (a typed array's length is then the same on every iteration). */ + stableReceiver: boolean; } export interface IntegerCountedForLoop { @@ -682,7 +685,12 @@ export function matchIntegerBytesForLoop( if (!isUnitIncrement(stmt.update, init.localId)) return null; if (writesLocal(stmt.body, init.localId)) return null; - return { localId: init.localId, limitReceiver: cond.right.receiver }; + return { + localId: init.localId, + limitReceiver: cond.right.receiver, + stableReceiver: + receiverLocal !== undefined && !writesLocal(stmt.body, cond.right.receiver.localId), + }; } /** Array lengths are uint32, so zero-based loops and nested `j = i + 1` @@ -729,5 +737,11 @@ export function matchIntegerArrayForLoop( writesLocal(stmt.body, local.id) ) return null; - return { localId: local.id, limitReceiver: cond.right.receiver }; + return { + localId: local.id, + limitReceiver: cond.right.receiver, + stableReceiver: + locals.has(cond.right.receiver.localId) && + !writesLocal(stmt.body, cond.right.receiver.localId), + }; } diff --git a/packages/compiler/test/counted-loop-emission.test.ts b/packages/compiler/test/counted-loop-emission.test.ts index 206a3c57e..f617c6ab4 100644 --- a/packages/compiler/test/counted-loop-emission.test.ts +++ b/packages/compiler/test/counted-loop-emission.test.ts @@ -58,6 +58,14 @@ test("worker programs poll counted loops over typed arrays between blocks of ite "export function codes(a: Uint8Array): void {", " for (let i = 0; i < a.length; ++i) a[i] = a[i] === 97 ? 0 : 3;", "}", + "export function shrink(a: Uint8Array): number {", + " let t = 0;", + " for (let i = 0; i < a.length; ++i) {", + " t += a[i]!;", + " if (i === 2) a = a.subarray(0, 3);", + " }", + " return t;", + "}", "export function mix(n: number): number {", " let t = 0;", " for (let i = 0; i < n; i++) t = (t * 31 + i) % 1000003;", @@ -68,7 +76,7 @@ test("worker programs poll counted loops over typed arrays between blocks of ite "scale(a, b, 8);", "const c = new Uint8Array(8).fill(97);", "codes(c);", - "console.log(b[7], mix(8), c[0]);", + "console.log(b[7], mix(8), c[0], shrink(new Uint8Array(8).fill(1)));", workers ? "if (!isMainThread) new Worker(new URL(import.meta.url));" : "", ].join("\n"); const emit = async (workers: boolean): Promise => { @@ -113,6 +121,11 @@ test("worker programs poll counted loops over typed arrays between blocks of ite expect(codes).toMatch(/@llvm\.uadd\.sat\.i64\(i64 %\w+, i64 64\)/); expect(codes).toMatch(/@llvm\.umin\.i64\(i64 %\w+, i64 %\w+\)/); expect(codes).toMatch(/^loop\.poll\d+:$/m); + // A loop that assigns its array reads the new length on the next + // iteration: it keeps the budget. + const shrink = bodies(workerModule, "shrink"); + expect(shrink).toContain("worker cancellation budget"); + expect(shrink).not.toMatch(/^loop\.poll\d+:$/m); const mix = bodies(workerModule, "mix"); expect(mix).toContain("worker cancellation budget"); expect(mix).not.toContain("loop.poll"); diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-length-loop-reassign.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-length-loop-reassign.ts.json new file mode 100644 index 000000000..f5230bace --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/native-worker-length-loop-reassign.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/native-worker-length-loop-reassign.ts" + ], + "diags": [] +} diff --git a/tests/corpus/native-worker-length-loop-reassign.ts b/tests/corpus/native-worker-length-loop-reassign.ts new file mode 100644 index 000000000..7ec152b16 --- /dev/null +++ b/tests/corpus/native-worker-length-loop-reassign.ts @@ -0,0 +1,58 @@ +// Loops to a typed array's length in a program that starts workers, where +// the body assigns the loop's array: the condition reads the new array's +// length on the next iteration, shorter or longer. +import { Worker, isMainThread, parentPort } from "node:worker_threads"; + +function shrink(values: Float64Array): string { + let total = 0; + let steps = 0; + for (let i = 0; i < values.length; i++) { + total += values[i]!; + steps++; + if (i === 100) values = values.subarray(0, 50); + } + return `shrink ${steps} ${total}`; +} + +function grow(values: Uint8Array, longer: Uint8Array): string { + let total = 0; + let steps = 0; + for (let i = 0; i < values.length; i++) { + total += values[i]!; + steps++; + if (i === 10) values = longer; + } + return `grow ${steps} ${total}`; +} + +function swap(a: Int32Array, b: Int32Array): string { + let total = 0; + let steps = 0; + for (let i = 0; i < a.length; i++) { + total += a[i]!; + steps++; + if (i % 70 === 69) { + const t = a; + a = b; + b = t; + } + } + return `swap ${steps} ${total}`; +} + +function run(): string[] { + const values = new Float64Array(300).map((_, i) => i * 0.5); + const short = new Uint8Array(20).fill(3); + const long = new Uint8Array(200).map((_, i) => i & 7); + const a = new Int32Array(100).map((_, i) => i); + const b = new Int32Array(160).map((_, i) => -i); + return [shrink(values), grow(short, long), swap(a, b)]; +} + +if (isMainThread) { + for (const line of run()) console.log(line); + const worker = new Worker(new URL(import.meta.url)); + worker.on("message", (lines: string[]) => { + for (const line of lines) console.log("worker", line); + }); +} else parentPort!.postMessage(run()); diff --git a/tests/harness/corpus-costs/native-worker-length-loop-reassign.ts.json b/tests/harness/corpus-costs/native-worker-length-loop-reassign.ts.json new file mode 100644 index 000000000..5ee17db16 --- /dev/null +++ b/tests/harness/corpus-costs/native-worker-length-loop-reassign.ts.json @@ -0,0 +1 @@ +{ "plain": 3158, "san": 20404 } From c1c4daed82d7c52ab1016d40c317bf37fecab52b Mon Sep 17 00:00:00 2001 From: Malte Ubl Date: Sat, 24 Oct 2026 22:36:05 -0700 Subject: [PATCH 259/259] Throw Node's TypeError when an asserted callee holds no function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `f!()`, `t[k]!()` and `o.cb!()` on a value that holds undefined threw scriptc's checked-extraction message ("undefined is not representable in the target union …"). The non-null assertion is erased in JavaScript, so Node throws the call's own " is not a function". The checked extraction behind an asserted callee now carries that message, with V8's spelling of the callee: parentheses and non-null assertions dropped and call results printed as `f(...)`. Co-Authored-By: Claude Opus 5.5 --- .../src/frontend/lowering/coercions/state.ts | 5 +++- .../src/frontend/lowering/coercions/unions.ts | 27 +++++++++++++++---- .../lowering/expressions/narrowing.ts | 9 ++++++- .../src/frontend/lowering/lower-exprs.ts | 22 +++++++++++++-- .../compiler/src/frontend/lowering/lowerer.ts | 4 +-- .../frontend/lowering/union-narrow.test.ts | 19 +++++++++++++ .../src/frontend/lowering/union-narrow.ts | 8 ++++-- .../8240-asserted-callee-errors.ts.json | 6 +++++ tests/corpus/8240-asserted-callee-errors.ts | 25 +++++++++++++++++ .../8240-asserted-callee-errors.ts.json | 1 + 10 files changed, 113 insertions(+), 13 deletions(-) create mode 100644 packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8240-asserted-callee-errors.ts.json create mode 100644 tests/corpus/8240-asserted-callee-errors.ts create mode 100644 tests/harness/corpus-costs/8240-asserted-callee-errors.ts.json diff --git a/packages/compiler/src/frontend/lowering/coercions/state.ts b/packages/compiler/src/frontend/lowering/coercions/state.ts index ad1d7c6ea..db9bb53ad 100644 --- a/packages/compiler/src/frontend/lowering/coercions/state.ts +++ b/packages/compiler/src/frontend/lowering/coercions/state.ts @@ -12,7 +12,10 @@ export class CoercionState { // Provenance for checked extraction; consumers must not infer it from names. readonly checkedNarrows = new Set(); // The extracted arm of each checked (non-defaulting) extraction helper. - readonly checkedNarrowArms = new Map(); + readonly checkedNarrowArms = new Map< + string, + { unionId: string; tag: number; target: IrType; message?: string } + >(); readonly retags = new Map(); readonly narrows = new Map(); } diff --git a/packages/compiler/src/frontend/lowering/coercions/unions.ts b/packages/compiler/src/frontend/lowering/coercions/unions.ts index 434e687a5..53c87e429 100644 --- a/packages/compiler/src/frontend/lowering/coercions/unions.ts +++ b/packages/compiler/src/frontend/lowering/coercions/unions.ts @@ -394,18 +394,21 @@ export function unionRetagHelper( * the catchable TypeError — divergence 38's lying-assertion stance (an * unchecked unionNarrow would misread the payload where JS lets the * impossible value flow on). Null when the target isn't a non-unit arm - * of the union — those uses keep their erasure/fences. */ + * of the union — those uses keep their erasure/fences. `message` replaces + * the failure message (the TypeError of the operation consuming the + * value, such as a call's "f is not a function"). */ export function narrowedArmHelper( lowerer: Lowerer, fromId: string, target: IrType, loc: SrcLoc, + message?: string, ): string | null { const from = lowerer.unions.get(fromId); if (!from || isUnitType(target)) return null; const tag = lowerer.armTag(fromId, target); if (tag < 0) return null; - const key = `${fromId}:${tag}`; + const key = message === undefined ? `${fromId}:${tag}` : `${fromId}:${tag}:${message}`; const existing = lowerer.coercions.narrows.get(key); if (existing) { lowerer.coercions.checkedNarrows.add(existing); @@ -414,9 +417,22 @@ export function narrowedArmHelper( const name = keyedHelperName(lowerer, "%union.narrow", key); lowerer.coercions.narrows.set(key, name); lowerer.coercions.checkedNarrows.add(name); - const fn = buildUnionNarrow(name, from, target, loc, (type) => lowerer.fmt(type)); + const fn = buildUnionNarrow( + name, + from, + target, + loc, + (type) => lowerer.fmt(type), + null, + message ?? null, + ); if (!fn) throw new InternalCompilerError("lowerer bug: invalid checked union extraction"); - lowerer.coercions.checkedNarrowArms.set(name, { unionId: fromId, tag, target: from.arms[tag]! }); + lowerer.coercions.checkedNarrowArms.set(name, { + unionId: fromId, + tag, + target: from.arms[tag]!, + ...(message === undefined ? {} : { message }), + }); lowerer.liftedFns.push(fn); return name; } @@ -458,7 +474,8 @@ export function checkedNarrowCall( let failure: IrExpr | null = null; for (let tag = from.arms.length - 1; tag >= 0; tag--) { if (tag === arm.tag) continue; - const message = unionNarrowFailureMessage(from.arms[tag]!, (t) => lowerer.fmt(t)); + const message = + arm.message ?? unionNarrowFailureMessage(from.arms[tag]!, (t) => lowerer.fmt(t)); const thrown = nodeThrowExpr(1, "", message, type, loc); failure = failure === null diff --git a/packages/compiler/src/frontend/lowering/expressions/narrowing.ts b/packages/compiler/src/frontend/lowering/expressions/narrowing.ts index 01cab9901..9f0559672 100644 --- a/packages/compiler/src/frontend/lowering/expressions/narrowing.ts +++ b/packages/compiler/src/frontend/lowering/expressions/narrowing.ts @@ -875,8 +875,15 @@ function checkedStaleArm( /** V8's spelling of a callee in "is not a function": a string-literal * element key reads as a property name (`o["a"]` is `o.a`), other keys - * keep their brackets. */ + * keep their brackets, parentheses and non-null assertions disappear, and + * a call result reads `f(...)`. */ export function v8CalleeText(node: ts.Node): string { + // `!` is type-only syntax: the running JavaScript has no trace of it. + if (ts.isNonNullExpression(node) || ts.isParenthesizedExpression(node)) + return v8CalleeText(node.expression); + // A call result prints with its arguments elided. + if (ts.isCallExpression(node) && !node.questionDotToken) + return `${v8CalleeText(node.expression)}(...)`; if (ts.isElementAccessExpression(node)) { const key = node.argumentExpression; const object = v8CalleeText(node.expression); diff --git a/packages/compiler/src/frontend/lowering/lower-exprs.ts b/packages/compiler/src/frontend/lowering/lower-exprs.ts index 20d05f3b7..006975085 100644 --- a/packages/compiler/src/frontend/lowering/lower-exprs.ts +++ b/packages/compiler/src/frontend/lowering/lower-exprs.ts @@ -89,7 +89,7 @@ import { classSymbolKeyOf } from "./symbol-fields.js"; import { lowerTypeofExpr } from "./expressions/typeof.js"; import { lowerIdentifierExpr } from "./expressions/identifiers.js"; import { lowerFieldCompoundValue, lowerIncDec } from "./expressions/updates.js"; -import { lowerTernary } from "./expressions/narrowing.js"; +import { lowerTernary, v8CalleeText } from "./expressions/narrowing.js"; import { classFieldTarget, lowerPropertyAccessExpr, @@ -433,7 +433,12 @@ function lowerExprInner(lowerer: Lowerer, expr: ts.Expression): IrExpr { const operand = assertionOperand(lowerer, expr, inner, target ?? null, loc); if (operand) return operand; if (target && target.kind !== "union" && !typeEquals(target, inner.type)) { - const helper = lowerer.narrowedArmHelper(inner.type.unionId, target, loc); + const helper = lowerer.narrowedArmHelper( + inner.type.unionId, + target, + loc, + assertedCalleeMessage(expr, target), + ); if (helper) { return lowerer.checkedNarrowCall(helper, inner, target, loc); } @@ -1160,6 +1165,19 @@ const NUMERIC_COMPOUNDS = new Set([ ts.SyntaxKind.GreaterThanGreaterThanGreaterThanEqualsToken, ]); +/** The TypeError Node raises when an asserted callee (`t[k]!(…)`, `o.f!()`) + * holds no function: `!` is erased, so the call itself throws " is + * not a function" in V8's spelling of the callee. */ +function assertedCalleeMessage(expr: ts.NonNullExpression, target: IrType): string | undefined { + if (target.kind !== "func") return undefined; + let child: ts.Expression = expr; + while (ts.isParenthesizedExpression(child.parent)) child = child.parent; + const call = child.parent; + if (!ts.isCallExpression(call) || call.expression !== child || call.questionDotToken) + return undefined; + return `${v8CalleeText(expr.expression)} is not a function`; +} + /** Whether the use of `t[i]!` tells undefined from NaN: a converting use * that takes the value itself (see convertingUseOf), or a destination that * holds a missing element (see assertedElementKeepsUndefined) other than a diff --git a/packages/compiler/src/frontend/lowering/lowerer.ts b/packages/compiler/src/frontend/lowering/lowerer.ts index e49fde6bb..56e39ff0c 100644 --- a/packages/compiler/src/frontend/lowering/lowerer.ts +++ b/packages/compiler/src/frontend/lowering/lowerer.ts @@ -10525,8 +10525,8 @@ export class Lowerer { return unionRetagHelper(this, fromId, toId, loc, trappable); } - narrowedArmHelper(fromId: string, target: IrType, loc: SrcLoc): string | null { - return narrowedArmHelper(this, fromId, target, loc); + narrowedArmHelper(fromId: string, target: IrType, loc: SrcLoc, message?: string): string | null { + return narrowedArmHelper(this, fromId, target, loc, message); } checkedNarrowCall(helper: string, value: IrExpr, type: IrType, loc: SrcLoc): IrExpr { diff --git a/packages/compiler/src/frontend/lowering/union-narrow.test.ts b/packages/compiler/src/frontend/lowering/union-narrow.test.ts index ed60fac8d..5c2a81b5e 100644 --- a/packages/compiler/src/frontend/lowering/union-narrow.test.ts +++ b/packages/compiler/src/frontend/lowering/union-narrow.test.ts @@ -97,3 +97,22 @@ test("a deferred read requires a real undefined tag", () => { const value: IrExpr = { kind: "boolLit", value: false, type: BOOL, loc }; expect(buildUnionNarrow("bad", from, BOOL, loc, () => "", value)).toBeNull(); }); + +test("a failure message replaces every other tag's TypeError", () => { + const fn = buildUnionNarrow( + "call", + union, + STRING, + loc, + (type) => type.kind, + null, + "f is not a function", + )!; + const thrown = branches(fn).flatMap((branch) => { + const statement = branch.then[0]!; + return statement.kind === "throw" ? [statement.value] : []; + }); + expect(thrown).toHaveLength(4); + for (const value of thrown) + expect(value).toMatchObject({ kind: "libCall", args: [{ value: "f is not a function" }] }); +}); diff --git a/packages/compiler/src/frontend/lowering/union-narrow.ts b/packages/compiler/src/frontend/lowering/union-narrow.ts index 3bb09cb26..a167631fc 100644 --- a/packages/compiler/src/frontend/lowering/union-narrow.ts +++ b/packages/compiler/src/frontend/lowering/union-narrow.ts @@ -20,7 +20,10 @@ export function unionNarrowFailureMessage( * * Deferred scalar fields can supply the established undefined default: * false for booleans or NaN for numbers. No other tag receives that default, - * and reference-bearing targets always use checked extraction. */ + * and reference-bearing targets always use checked extraction. + * + * `failureMessage` replaces the TypeError message of every other tag (the + * error Node raises for the operation consuming the value). */ export function buildUnionNarrow( name: string, from: IrUnionDef, @@ -28,6 +31,7 @@ export function buildUnionNarrow( loc: SrcLoc, formatType: (type: IrType) => string, undefinedDefault: IrExpr | null = null, + failureMessage: string | null = null, ): IrFunction | null { if (isUnitType(target) || target.kind === "void") return null; const targetTag = from.arms.findIndex((arm) => typeEquals(arm, target)); @@ -66,7 +70,7 @@ export function buildUnionNarrow( args: [ { kind: "strLit", - value: unionNarrowFailureMessage(arm, formatType), + value: failureMessage ?? unionNarrowFailureMessage(arm, formatType), type: STRING, loc, }, diff --git a/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8240-asserted-callee-errors.ts.json b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8240-asserted-callee-errors.ts.json new file mode 100644 index 000000000..365bf7076 --- /dev/null +++ b/packages/compiler/test/ts7/baselines/order-parity/tests/corpus/8240-asserted-callee-errors.ts.json @@ -0,0 +1,6 @@ +{ + "order": [ + "/tests/corpus/8240-asserted-callee-errors.ts" + ], + "diags": [] +} diff --git a/tests/corpus/8240-asserted-callee-errors.ts b/tests/corpus/8240-asserted-callee-errors.ts new file mode 100644 index 000000000..91537ed70 --- /dev/null +++ b/tests/corpus/8240-asserted-callee-errors.ts @@ -0,0 +1,25 @@ +// A non-null assertion is erased in JavaScript, so calling an asserted callee +// that holds undefined throws the call's own TypeError, with V8's spelling of +// the callee: element keys, literal keys as names, parentheses and asserted +// links dropped, call results as f(...). +type F = (x: number) => number; +const table: Record = { inc: (x) => x + 1 }; +const obj: { cb?: F; inner?: { cb?: F } } = { inner: {} }; +const arr: (F | undefined)[] = [undefined]; +let maybe: F | undefined; +function get(): F | undefined { return undefined; } +const key = process.argv.length > 99 ? "inc" : "missing"; +const cases: [string, () => number][] = [ + ["computed", () => table[key]!(1)], + ["literal key", () => table["missing"]!(1)], + ["dotted", () => obj.cb!(1)], + ["nested", () => obj.inner!.cb!(1)], + ["element", () => arr[0]!(1)], + ["local", () => maybe!(1)], + ["parens", () => (table[key])!(1)], + ["call result", () => get()!(1)], + ["parens outside", () => (table[key]!)(1)], +]; +for (const [name, run] of cases) { + try { console.log(name, run()); } catch (e) { console.log(name, (e as Error).name + ": " + (e as Error).message); } +} diff --git a/tests/harness/corpus-costs/8240-asserted-callee-errors.ts.json b/tests/harness/corpus-costs/8240-asserted-callee-errors.ts.json new file mode 100644 index 000000000..8c0e66c3c --- /dev/null +++ b/tests/harness/corpus-costs/8240-asserted-callee-errors.ts.json @@ -0,0 +1 @@ +{ "plain": 3000, "san": 3600 }

  • o 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 %!!-sel)E{ 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

  • o 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